mirror of
https://github.com/mattermost/mattermost.git
synced 2025-02-25 18:55:24 -06:00
Various improvements to preferences code (#27710)
* Add isPostFlagged selector * Remove unused code for actions_menu preferences * Improve types of Preference and getPreference * MM-58111 Change makeGetCategory to take category name once * Use shouldShowJoinLeaveMessages everywhere * Change makeGetCategory to better memoize its result * Fix test that needs EnableJoinLeaveMessageByDefault to be set * Remove more references to action_menu preferences
This commit is contained in:
parent
28939d84da
commit
6956923b6a
@ -126,18 +126,6 @@ declare namespace Cypress {
|
|||||||
*/
|
*/
|
||||||
apiSaveCloudTrialBannerPreference(userId: string, name: string, value: string): Chainable<Response>;
|
apiSaveCloudTrialBannerPreference(userId: string, name: string, value: string): Chainable<Response>;
|
||||||
|
|
||||||
/**
|
|
||||||
* Save actions menu preference.
|
|
||||||
* See https://api.mattermost.com/#tag/preferences/paths/~1users~1{user_id}~1preferences/put
|
|
||||||
* @param {string} userId - User ID
|
|
||||||
* @param {string} value - true (default) or false
|
|
||||||
* @returns {Response} response: Cypress-chainable response which should have successful HTTP status of 200 OK to continue or pass.
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* cy.apiSaveActionsMenuPreference('user-id', true);
|
|
||||||
*/
|
|
||||||
apiSaveActionsMenuPreference(userId: string, value: boolean): Chainable<Response>;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save show trial modal.
|
* Save show trial modal.
|
||||||
* See https://api.mattermost.com/#tag/preferences/paths/~1users~1{user_id}~1preferences/put
|
* See https://api.mattermost.com/#tag/preferences/paths/~1users~1{user_id}~1preferences/put
|
||||||
|
@ -256,17 +256,6 @@ Cypress.Commands.add('apiSaveCloudTrialBannerPreference', (userId, name, value)
|
|||||||
return cy.apiSaveUserPreference([preference], userId);
|
return cy.apiSaveUserPreference([preference], userId);
|
||||||
});
|
});
|
||||||
|
|
||||||
Cypress.Commands.add('apiSaveActionsMenuPreference', (userId, value = true) => {
|
|
||||||
const preference = {
|
|
||||||
user_id: userId,
|
|
||||||
category: 'actions_menu',
|
|
||||||
name: 'actions_menu_tutorial_state',
|
|
||||||
value: JSON.stringify({actions_menu_modal_viewed: value}),
|
|
||||||
};
|
|
||||||
|
|
||||||
return cy.apiSaveUserPreference([preference], userId);
|
|
||||||
});
|
|
||||||
|
|
||||||
Cypress.Commands.add('apiSaveStartTrialModal', (userId, value = 'true') => {
|
Cypress.Commands.add('apiSaveStartTrialModal', (userId, value = 'true') => {
|
||||||
const preference = {
|
const preference = {
|
||||||
user_id: userId,
|
user_id: userId,
|
||||||
@ -402,12 +391,6 @@ Cypress.Commands.add('apiDisableTutorials', (userId) => {
|
|||||||
name: userId,
|
name: userId,
|
||||||
value: '999',
|
value: '999',
|
||||||
},
|
},
|
||||||
{
|
|
||||||
user_id: userId,
|
|
||||||
category: 'actions_menu',
|
|
||||||
name: 'actions_menu_tutorial_state',
|
|
||||||
value: '{"actions_menu_modal_viewed":true}',
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
user_id: userId,
|
user_id: userId,
|
||||||
category: 'drafts',
|
category: 'drafts',
|
||||||
|
@ -234,7 +234,6 @@ Cypress.Commands.add('apiCreateUser', ({
|
|||||||
prefix = 'user',
|
prefix = 'user',
|
||||||
createAt = 0,
|
createAt = 0,
|
||||||
bypassTutorial = true,
|
bypassTutorial = true,
|
||||||
hideActionsMenu = true,
|
|
||||||
hideOnboarding = true,
|
hideOnboarding = true,
|
||||||
bypassWhatsNewModal = true,
|
bypassWhatsNewModal = true,
|
||||||
user = null,
|
user = null,
|
||||||
@ -265,10 +264,6 @@ Cypress.Commands.add('apiCreateUser', ({
|
|||||||
cy.apiDisableTutorials(createdUser.id);
|
cy.apiDisableTutorials(createdUser.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hideActionsMenu) {
|
|
||||||
cy.apiSaveActionsMenuPreference(createdUser.id, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hideOnboarding) {
|
if (hideOnboarding) {
|
||||||
cy.apiSaveOnboardingPreference(createdUser.id, 'hide', 'true');
|
cy.apiSaveOnboardingPreference(createdUser.id, 'hide', 'true');
|
||||||
cy.apiSaveOnboardingPreference(createdUser.id, 'skip', 'true');
|
cy.apiSaveOnboardingPreference(createdUser.id, 'skip', 'true');
|
||||||
|
@ -261,7 +261,6 @@ function resetUserPreference(userId) {
|
|||||||
cy.apiSaveOnboardingTaskListPreference(userId, 'onboarding_task_list_open', 'false');
|
cy.apiSaveOnboardingTaskListPreference(userId, 'onboarding_task_list_open', 'false');
|
||||||
cy.apiSaveOnboardingTaskListPreference(userId, 'onboarding_task_list_show', 'false');
|
cy.apiSaveOnboardingTaskListPreference(userId, 'onboarding_task_list_show', 'false');
|
||||||
cy.apiSaveCloudTrialBannerPreference(userId, 'trial', 'max_days_banner');
|
cy.apiSaveCloudTrialBannerPreference(userId, 'trial', 'max_days_banner');
|
||||||
cy.apiSaveActionsMenuPreference(userId);
|
|
||||||
cy.apiSaveSkipStepsPreference(userId, 'true');
|
cy.apiSaveSkipStepsPreference(userId, 'true');
|
||||||
cy.apiSaveStartTrialModal(userId, 'true');
|
cy.apiSaveStartTrialModal(userId, 'true');
|
||||||
cy.apiSaveUnreadScrollPositionPreference(userId, 'start_from_left_off');
|
cy.apiSaveUnreadScrollPositionPreference(userId, 'start_from_left_off');
|
||||||
|
@ -81,7 +81,9 @@ describe('channel view actions', () => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
general: {
|
general: {
|
||||||
config: {},
|
config: {
|
||||||
|
EnableJoinLeaveMessageByDefault: 'true',
|
||||||
|
},
|
||||||
serverVersion: '5.12.0',
|
serverVersion: '5.12.0',
|
||||||
},
|
},
|
||||||
roles: {
|
roles: {
|
||||||
@ -589,7 +591,7 @@ describe('channel view actions', () => {
|
|||||||
|
|
||||||
describe('markChannelAsReadOnFocus', () => {
|
describe('markChannelAsReadOnFocus', () => {
|
||||||
test('should mark channel as read when channel is not manually unread', async () => {
|
test('should mark channel as read when channel is not manually unread', async () => {
|
||||||
test = mockStore(initialState);
|
store = mockStore(initialState);
|
||||||
|
|
||||||
await store.dispatch(Actions.markChannelAsReadOnFocus(channel1.id));
|
await store.dispatch(Actions.markChannelAsReadOnFocus(channel1.id));
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ const CloudTrialBanner = ({trialEndDate}: Props): JSX.Element | null => {
|
|||||||
|
|
||||||
// the banner when dismissed, will be dismissed for 10 days
|
// the banner when dismissed, will be dismissed for 10 days
|
||||||
const bannerIsStillDismissed = diffDays < 0;
|
const bannerIsStillDismissed = diffDays < 0;
|
||||||
shouldShowBanner = storedDismissedEndDate && bannerIsStillDismissed;
|
shouldShowBanner = Boolean(storedDismissedEndDate) && bannerIsStillDismissed;
|
||||||
}
|
}
|
||||||
|
|
||||||
const [showBanner, setShowBanner] = useState<boolean>(shouldShowBanner);
|
const [showBanner, setShowBanner] = useState<boolean>(shouldShowBanner);
|
||||||
|
@ -20,9 +20,9 @@ import type {GlobalState} from 'types/store';
|
|||||||
|
|
||||||
import CloudTrialAnnouncementBar from './cloud_trial_announcement_bar';
|
import CloudTrialAnnouncementBar from './cloud_trial_announcement_bar';
|
||||||
|
|
||||||
function mapStateToProps(state: GlobalState) {
|
const getCloudTrialBannerPreferences = makeGetCategory('getCloudTrialBannerPreferences', Preferences.CLOUD_TRIAL_BANNER);
|
||||||
const getCategory = makeGetCategory();
|
|
||||||
|
|
||||||
|
function mapStateToProps(state: GlobalState) {
|
||||||
const subscription = state.entities.cloud.subscription;
|
const subscription = state.entities.cloud.subscription;
|
||||||
const isCloud = getLicense(state).Cloud === 'true';
|
const isCloud = getLicense(state).Cloud === 'true';
|
||||||
let isFreeTrial = false;
|
let isFreeTrial = false;
|
||||||
@ -43,7 +43,7 @@ function mapStateToProps(state: GlobalState) {
|
|||||||
currentUser: getCurrentUser(state),
|
currentUser: getCurrentUser(state),
|
||||||
isCloud,
|
isCloud,
|
||||||
subscription,
|
subscription,
|
||||||
preferences: getCategory(state, Preferences.CLOUD_TRIAL_BANNER),
|
preferences: getCloudTrialBannerPreferences(state),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
// See LICENSE.txt for license information.
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
import React, {useMemo} from 'react';
|
import React from 'react';
|
||||||
import {FormattedMessage, defineMessages} from 'react-intl';
|
import {FormattedMessage, defineMessages} from 'react-intl';
|
||||||
import {useSelector, useDispatch} from 'react-redux';
|
import {useSelector, useDispatch} from 'react-redux';
|
||||||
|
|
||||||
@ -30,14 +30,13 @@ import type {GlobalState} from 'types/store';
|
|||||||
|
|
||||||
import AnnouncementBar from '../default_announcement_bar';
|
import AnnouncementBar from '../default_announcement_bar';
|
||||||
|
|
||||||
|
const getCloudTrialEndBannerPreferences = makeGetCategory('getCloudTrialEndBannerPreferences', Preferences.CLOUD_TRIAL_END_BANNER);
|
||||||
|
|
||||||
const CloudTrialEndAnnouncementBar: React.FC = () => {
|
const CloudTrialEndAnnouncementBar: React.FC = () => {
|
||||||
const limits = useGetLimits();
|
const limits = useGetLimits();
|
||||||
const subscription = useGetSubscription();
|
const subscription = useGetSubscription();
|
||||||
const getCategory = useMemo(makeGetCategory, []);
|
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const preferences = useSelector((state: GlobalState) =>
|
const preferences = useSelector(getCloudTrialEndBannerPreferences);
|
||||||
getCategory(state, Preferences.CLOUD_TRIAL_END_BANNER),
|
|
||||||
);
|
|
||||||
const currentUser = useSelector((state: GlobalState) =>
|
const currentUser = useSelector((state: GlobalState) =>
|
||||||
getCurrentUser(state),
|
getCurrentUser(state),
|
||||||
);
|
);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
// See LICENSE.txt for license information.
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
import React, {useMemo} from 'react';
|
import React from 'react';
|
||||||
import {FormattedMessage} from 'react-intl';
|
import {FormattedMessage} from 'react-intl';
|
||||||
import {useDispatch, useSelector} from 'react-redux';
|
import {useDispatch, useSelector} from 'react-redux';
|
||||||
|
|
||||||
@ -10,7 +10,7 @@ import type {PreferenceType} from '@mattermost/types/preferences';
|
|||||||
import {savePreferences} from 'mattermost-redux/actions/preferences';
|
import {savePreferences} from 'mattermost-redux/actions/preferences';
|
||||||
import {isCurrentLicenseCloud} from 'mattermost-redux/selectors/entities/cloud';
|
import {isCurrentLicenseCloud} from 'mattermost-redux/selectors/entities/cloud';
|
||||||
import {getLicense} from 'mattermost-redux/selectors/entities/general';
|
import {getLicense} from 'mattermost-redux/selectors/entities/general';
|
||||||
import {makeGetCategory} from 'mattermost-redux/selectors/entities/preferences';
|
import {getOverageBannerPreferences} from 'mattermost-redux/selectors/entities/preferences';
|
||||||
import {getCurrentUser, isCurrentUserSystemAdmin} from 'mattermost-redux/selectors/entities/users';
|
import {getCurrentUser, isCurrentUserSystemAdmin} from 'mattermost-redux/selectors/entities/users';
|
||||||
|
|
||||||
import AnnouncementBar from 'components/announcement_bar/default_announcement_bar';
|
import AnnouncementBar from 'components/announcement_bar/default_announcement_bar';
|
||||||
@ -46,9 +46,8 @@ const OverageUsersBanner = () => {
|
|||||||
const license = useSelector(getLicense);
|
const license = useSelector(getLicense);
|
||||||
const seatsPurchased = parseInt(license.Users, 10);
|
const seatsPurchased = parseInt(license.Users, 10);
|
||||||
const isCloud = useSelector(isCurrentLicenseCloud);
|
const isCloud = useSelector(isCurrentLicenseCloud);
|
||||||
const getPreferencesCategory = useMemo(makeGetCategory, []);
|
|
||||||
const currentUser = useSelector((state: GlobalState) => getCurrentUser(state));
|
const currentUser = useSelector((state: GlobalState) => getCurrentUser(state));
|
||||||
const overagePreferences = useSelector((state: GlobalState) => getPreferencesCategory(state, Preferences.OVERAGE_USERS_BANNER));
|
const overagePreferences = useSelector(getOverageBannerPreferences);
|
||||||
const activeUsers = ((stats || {})[StatTypes.TOTAL_USERS]) as number || 0;
|
const activeUsers = ((stats || {})[StatTypes.TOTAL_USERS]) as number || 0;
|
||||||
const {
|
const {
|
||||||
isBetween5PercerntAnd10PercentPurchasedSeats,
|
isBetween5PercerntAnd10PercentPurchasedSeats,
|
||||||
|
@ -1,14 +1,12 @@
|
|||||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
// See LICENSE.txt for license information.
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
import {useEffect, useMemo} from 'react';
|
import {useEffect} from 'react';
|
||||||
import {useSelector, useDispatch} from 'react-redux';
|
import {useSelector, useDispatch} from 'react-redux';
|
||||||
|
|
||||||
import type {PreferenceType} from '@mattermost/types/preferences';
|
|
||||||
|
|
||||||
import {savePreferences} from 'mattermost-redux/actions/preferences';
|
import {savePreferences} from 'mattermost-redux/actions/preferences';
|
||||||
import {getConfig, getLicense} from 'mattermost-redux/selectors/entities/general';
|
import {getConfig, getLicense} from 'mattermost-redux/selectors/entities/general';
|
||||||
import {makeGetCategory} from 'mattermost-redux/selectors/entities/preferences';
|
import {getBool} from 'mattermost-redux/selectors/entities/preferences';
|
||||||
import {getCurrentUser, isCurrentUserSystemAdmin} from 'mattermost-redux/selectors/entities/users';
|
import {getCurrentUser, isCurrentUserSystemAdmin} from 'mattermost-redux/selectors/entities/users';
|
||||||
|
|
||||||
import {trackEvent} from 'actions/telemetry_actions';
|
import {trackEvent} from 'actions/telemetry_actions';
|
||||||
@ -29,7 +27,6 @@ import type {GlobalState} from 'types/store';
|
|||||||
const ShowStartTrialModal = () => {
|
const ShowStartTrialModal = () => {
|
||||||
const isUserAdmin = useSelector((state: GlobalState) => isCurrentUserSystemAdmin(state));
|
const isUserAdmin = useSelector((state: GlobalState) => isCurrentUserSystemAdmin(state));
|
||||||
const openStartTrialFormModal = useOpenStartTrialFormModal();
|
const openStartTrialFormModal = useOpenStartTrialFormModal();
|
||||||
const getCategory = useMemo(makeGetCategory, []);
|
|
||||||
|
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
@ -40,7 +37,7 @@ const ShowStartTrialModal = () => {
|
|||||||
|
|
||||||
const installationDate = useSelector((state: GlobalState) => getConfig(state).InstallationDate);
|
const installationDate = useSelector((state: GlobalState) => getConfig(state).InstallationDate);
|
||||||
const currentUser = useSelector((state: GlobalState) => getCurrentUser(state));
|
const currentUser = useSelector((state: GlobalState) => getCurrentUser(state));
|
||||||
const preferences = useSelector<GlobalState, PreferenceType[]>((state) => getCategory(state, Preferences.START_TRIAL_MODAL));
|
const hadAdminDismissedModal = useSelector((state: GlobalState) => getBool(state, Preferences.START_TRIAL_MODAL, Constants.TRIAL_MODAL_AUTO_SHOWN));
|
||||||
|
|
||||||
const prevTrialLicense = useSelector((state: GlobalState) => state.entities.admin.prevTrialLicense);
|
const prevTrialLicense = useSelector((state: GlobalState) => state.entities.admin.prevTrialLicense);
|
||||||
const currentLicense = useSelector(getLicense);
|
const currentLicense = useSelector(getLicense);
|
||||||
@ -77,7 +74,6 @@ const ShowStartTrialModal = () => {
|
|||||||
const now = new Date().getTime();
|
const now = new Date().getTime();
|
||||||
const hasEnvMoreThan6Hours = now > installationDatePlus6Hours;
|
const hasEnvMoreThan6Hours = now > installationDatePlus6Hours;
|
||||||
const hasEnvMoreThan10Users = Number(totalUsers) > userThreshold;
|
const hasEnvMoreThan10Users = Number(totalUsers) > userThreshold;
|
||||||
const hadAdminDismissedModal = preferences.some((pref: PreferenceType) => pref.name === Constants.TRIAL_MODAL_AUTO_SHOWN && pref.value === TRUE);
|
|
||||||
if (isUserAdmin && !isBenefitsModalOpened && hasEnvMoreThan10Users && hasEnvMoreThan6Hours && !hadAdminDismissedModal && !isLicensedOrPreviousLicensed) {
|
if (isUserAdmin && !isBenefitsModalOpened && hasEnvMoreThan10Users && hasEnvMoreThan6Hours && !hadAdminDismissedModal && !isLicensedOrPreviousLicensed) {
|
||||||
openStartTrialFormModal({trackingLocation: 'show_start_trial_modal'}, handleOnClose);
|
openStartTrialFormModal({trackingLocation: 'show_start_trial_modal'}, handleOnClose);
|
||||||
trackEvent(
|
trackEvent(
|
||||||
|
@ -8,18 +8,16 @@ import type {PreferenceType} from '@mattermost/types/preferences';
|
|||||||
|
|
||||||
import {savePreferences} from 'mattermost-redux/actions/preferences';
|
import {savePreferences} from 'mattermost-redux/actions/preferences';
|
||||||
import {getCurrentUserId} from 'mattermost-redux/selectors/entities/common';
|
import {getCurrentUserId} from 'mattermost-redux/selectors/entities/common';
|
||||||
import {getMyPreferences} from 'mattermost-redux/selectors/entities/preferences';
|
import {get as getPreference} from 'mattermost-redux/selectors/entities/preferences';
|
||||||
import type {ActionResult} from 'mattermost-redux/types/actions';
|
import type {ActionResult} from 'mattermost-redux/types/actions';
|
||||||
import {getPreferenceKey} from 'mattermost-redux/utils/preference_utils';
|
|
||||||
|
import type {GlobalState} from 'types/store';
|
||||||
|
|
||||||
export default function usePreference(category: string, name: string): [string | undefined, (value: string) => Promise<ActionResult>] {
|
export default function usePreference(category: string, name: string): [string | undefined, (value: string) => Promise<ActionResult>] {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
const userId = useSelector(getCurrentUserId);
|
const userId = useSelector(getCurrentUserId);
|
||||||
const preferences = useSelector(getMyPreferences);
|
const preferenceValue = useSelector((state: GlobalState) => getPreference(state, category, name));
|
||||||
|
|
||||||
const key = getPreferenceKey(category, name);
|
|
||||||
const preference = preferences[key];
|
|
||||||
|
|
||||||
const setPreference = useCallback((value: string) => {
|
const setPreference = useCallback((value: string) => {
|
||||||
const preference: PreferenceType = {
|
const preference: PreferenceType = {
|
||||||
@ -31,5 +29,5 @@ export default function usePreference(category: string, name: string): [string |
|
|||||||
return dispatch(savePreferences(userId, [preference]));
|
return dispatch(savePreferences(userId, [preference]));
|
||||||
}, [category, name, userId]);
|
}, [category, name, userId]);
|
||||||
|
|
||||||
return useMemo(() => ([preference?.value, setPreference]), [preference?.value, setPreference]);
|
return useMemo(() => ([preferenceValue, setPreference]), [preferenceValue, setPreference]);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
// See LICENSE.txt for license information.
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
import React, {useMemo} from 'react';
|
import React from 'react';
|
||||||
import {FormattedMessage} from 'react-intl';
|
import {FormattedMessage} from 'react-intl';
|
||||||
import {useDispatch, useSelector} from 'react-redux';
|
import {useDispatch, useSelector} from 'react-redux';
|
||||||
|
|
||||||
@ -10,7 +10,7 @@ import type {PreferenceType} from '@mattermost/types/preferences';
|
|||||||
import {savePreferences} from 'mattermost-redux/actions/preferences';
|
import {savePreferences} from 'mattermost-redux/actions/preferences';
|
||||||
import {isCurrentLicenseCloud} from 'mattermost-redux/selectors/entities/cloud';
|
import {isCurrentLicenseCloud} from 'mattermost-redux/selectors/entities/cloud';
|
||||||
import {getLicense} from 'mattermost-redux/selectors/entities/general';
|
import {getLicense} from 'mattermost-redux/selectors/entities/general';
|
||||||
import {makeGetCategory} from 'mattermost-redux/selectors/entities/preferences';
|
import {getOverageBannerPreferences} from 'mattermost-redux/selectors/entities/preferences';
|
||||||
import {getCurrentUser, isCurrentUserSystemAdmin} from 'mattermost-redux/selectors/entities/users';
|
import {getCurrentUser, isCurrentUserSystemAdmin} from 'mattermost-redux/selectors/entities/users';
|
||||||
|
|
||||||
import AlertBanner from 'components/alert_banner';
|
import AlertBanner from 'components/alert_banner';
|
||||||
@ -42,9 +42,8 @@ const OverageUsersBannerNotice = () => {
|
|||||||
const isGovSku = getIsGovSku(license);
|
const isGovSku = getIsGovSku(license);
|
||||||
const seatsPurchased = parseInt(license.Users, 10);
|
const seatsPurchased = parseInt(license.Users, 10);
|
||||||
const isCloud = useSelector(isCurrentLicenseCloud);
|
const isCloud = useSelector(isCurrentLicenseCloud);
|
||||||
const getPreferencesCategory = useMemo(makeGetCategory, []);
|
|
||||||
const currentUser = useSelector((state: GlobalState) => getCurrentUser(state));
|
const currentUser = useSelector((state: GlobalState) => getCurrentUser(state));
|
||||||
const overagePreferences = useSelector((state: GlobalState) => getPreferencesCategory(state, Preferences.OVERAGE_USERS_BANNER));
|
const overagePreferences = useSelector(getOverageBannerPreferences);
|
||||||
const activeUsers = ((stats || {})[StatTypes.TOTAL_USERS]) as number || 0;
|
const activeUsers = ((stats || {})[StatTypes.TOTAL_USERS]) as number || 0;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
|
@ -9,7 +9,6 @@ import {matchPath, useLocation} from 'react-router-dom';
|
|||||||
import {savePreferences} from 'mattermost-redux/actions/preferences';
|
import {savePreferences} from 'mattermost-redux/actions/preferences';
|
||||||
import {getCurrentUserId} from 'mattermost-redux/selectors/entities/common';
|
import {getCurrentUserId} from 'mattermost-redux/selectors/entities/common';
|
||||||
import {getLicense} from 'mattermost-redux/selectors/entities/general';
|
import {getLicense} from 'mattermost-redux/selectors/entities/general';
|
||||||
import {makeGetCategory} from 'mattermost-redux/selectors/entities/preferences';
|
|
||||||
import {isCurrentUserGuestUser, isCurrentUserSystemAdmin, isFirstAdmin} from 'mattermost-redux/selectors/entities/users';
|
import {isCurrentUserGuestUser, isCurrentUserSystemAdmin, isFirstAdmin} from 'mattermost-redux/selectors/entities/users';
|
||||||
|
|
||||||
import {trackEvent as trackEventAction} from 'actions/telemetry_actions';
|
import {trackEvent as trackEventAction} from 'actions/telemetry_actions';
|
||||||
@ -22,6 +21,7 @@ import {
|
|||||||
} from 'actions/views/onboarding_tasks';
|
} from 'actions/views/onboarding_tasks';
|
||||||
import {setProductMenuSwitcherOpen} from 'actions/views/product_menu';
|
import {setProductMenuSwitcherOpen} from 'actions/views/product_menu';
|
||||||
import {setStatusDropdown} from 'actions/views/status_dropdown';
|
import {setStatusDropdown} from 'actions/views/status_dropdown';
|
||||||
|
import {getOnboardingTaskPreferences} from 'selectors/onboarding';
|
||||||
|
|
||||||
import Channels from 'components/common/svg_images_components/channels_svg';
|
import Channels from 'components/common/svg_images_components/channels_svg';
|
||||||
import Gears from 'components/common/svg_images_components/gears_svg';
|
import Gears from 'components/common/svg_images_components/gears_svg';
|
||||||
@ -46,8 +46,6 @@ import type {GlobalState} from 'types/store';
|
|||||||
import {OnboardingTaskCategory, OnboardingTaskList, OnboardingTasksName, TaskNameMapToSteps} from './constants';
|
import {OnboardingTaskCategory, OnboardingTaskList, OnboardingTasksName, TaskNameMapToSteps} from './constants';
|
||||||
import {generateTelemetryTag} from './utils';
|
import {generateTelemetryTag} from './utils';
|
||||||
|
|
||||||
const getCategory = makeGetCategory();
|
|
||||||
|
|
||||||
const useGetTaskDetails = () => {
|
const useGetTaskDetails = () => {
|
||||||
const {formatMessage} = useIntl();
|
const {formatMessage} = useIntl();
|
||||||
return {
|
return {
|
||||||
@ -145,7 +143,7 @@ export const useTasksList = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const useTasksListWithStatus = () => {
|
export const useTasksListWithStatus = () => {
|
||||||
const dataInDb = useSelector((state: GlobalState) => getCategory(state, OnboardingTaskCategory));
|
const dataInDb = useSelector(getOnboardingTaskPreferences);
|
||||||
const tasksList = useTasksList();
|
const tasksList = useTasksList();
|
||||||
const getTaskDetails = useGetTaskDetails();
|
const getTaskDetails = useGetTaskDetails();
|
||||||
return useMemo(() =>
|
return useMemo(() =>
|
||||||
|
@ -4,16 +4,15 @@
|
|||||||
import {connect} from 'react-redux';
|
import {connect} from 'react-redux';
|
||||||
import type {ConnectedProps} from 'react-redux';
|
import type {ConnectedProps} from 'react-redux';
|
||||||
import {bindActionCreators} from 'redux';
|
import {bindActionCreators} from 'redux';
|
||||||
import type {AnyAction, Dispatch} from 'redux';
|
import type {Dispatch} from 'redux';
|
||||||
|
|
||||||
import type {Emoji} from '@mattermost/types/emojis';
|
import type {Emoji} from '@mattermost/types/emojis';
|
||||||
import type {Post} from '@mattermost/types/posts';
|
import type {Post} from '@mattermost/types/posts';
|
||||||
|
|
||||||
import {setActionsMenuInitialisationState} from 'mattermost-redux/actions/preferences';
|
|
||||||
import {General} from 'mattermost-redux/constants';
|
import {General} from 'mattermost-redux/constants';
|
||||||
import {getDirectTeammate} from 'mattermost-redux/selectors/entities/channels';
|
import {getDirectTeammate} from 'mattermost-redux/selectors/entities/channels';
|
||||||
import {getConfig} from 'mattermost-redux/selectors/entities/general';
|
import {getConfig} from 'mattermost-redux/selectors/entities/general';
|
||||||
import {getPost, makeGetCommentCountForPost, makeIsPostCommentMention, isPostAcknowledgementsEnabled, isPostPriorityEnabled} from 'mattermost-redux/selectors/entities/posts';
|
import {getPost, makeGetCommentCountForPost, makeIsPostCommentMention, isPostAcknowledgementsEnabled, isPostPriorityEnabled, isPostFlagged} from 'mattermost-redux/selectors/entities/posts';
|
||||||
import type {UserActivityPost} from 'mattermost-redux/selectors/entities/posts';
|
import type {UserActivityPost} from 'mattermost-redux/selectors/entities/posts';
|
||||||
import {
|
import {
|
||||||
get,
|
get,
|
||||||
@ -179,7 +178,7 @@ function makeMapStateToProps() {
|
|||||||
channelIsArchived: isArchivedChannel(channel),
|
channelIsArchived: isArchivedChannel(channel),
|
||||||
isConsecutivePost: isConsecutivePost(state, ownProps),
|
isConsecutivePost: isConsecutivePost(state, ownProps),
|
||||||
previousPostIsComment,
|
previousPostIsComment,
|
||||||
isFlagged: get(state, Preferences.CATEGORY_FLAGGED_POST, post.id, null) !== null,
|
isFlagged: isPostFlagged(state, post.id),
|
||||||
compactDisplay: get(state, Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.MESSAGE_DISPLAY, Preferences.MESSAGE_DISPLAY_DEFAULT) === Preferences.MESSAGE_DISPLAY_COMPACT,
|
compactDisplay: get(state, Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.MESSAGE_DISPLAY, Preferences.MESSAGE_DISPLAY_DEFAULT) === Preferences.MESSAGE_DISPLAY_COMPACT,
|
||||||
colorizeUsernames: get(state, Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.COLORIZE_USERNAMES, Preferences.COLORIZE_USERNAMES_DEFAULT) === 'true',
|
colorizeUsernames: get(state, Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.COLORIZE_USERNAMES, Preferences.COLORIZE_USERNAMES_DEFAULT) === 'true',
|
||||||
shouldShowActionsMenu: shouldShowActionsMenu(state, post),
|
shouldShowActionsMenu: shouldShowActionsMenu(state, post),
|
||||||
@ -220,12 +219,11 @@ function makeMapStateToProps() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function mapDispatchToProps(dispatch: Dispatch<AnyAction>) {
|
function mapDispatchToProps(dispatch: Dispatch) {
|
||||||
return {
|
return {
|
||||||
actions: bindActionCreators({
|
actions: bindActionCreators({
|
||||||
markPostAsUnread,
|
markPostAsUnread,
|
||||||
emitShortcutReactToLastPostFrom,
|
emitShortcutReactToLastPostFrom,
|
||||||
setActionsMenuInitialisationState,
|
|
||||||
selectPost,
|
selectPost,
|
||||||
selectPostFromRightHandSideSearch,
|
selectPostFromRightHandSideSearch,
|
||||||
setRhsExpanded,
|
setRhsExpanded,
|
||||||
|
@ -41,7 +41,6 @@ describe('PostComponent', () => {
|
|||||||
actions: {
|
actions: {
|
||||||
markPostAsUnread: jest.fn(),
|
markPostAsUnread: jest.fn(),
|
||||||
emitShortcutReactToLastPostFrom: jest.fn(),
|
emitShortcutReactToLastPostFrom: jest.fn(),
|
||||||
setActionsMenuInitialisationState: jest.fn(),
|
|
||||||
selectPost: jest.fn(),
|
selectPost: jest.fn(),
|
||||||
selectPostFromRightHandSideSearch: jest.fn(),
|
selectPostFromRightHandSideSearch: jest.fn(),
|
||||||
removePost: jest.fn(),
|
removePost: jest.fn(),
|
||||||
|
@ -91,7 +91,6 @@ export type Props = {
|
|||||||
actions: {
|
actions: {
|
||||||
markPostAsUnread: (post: Post, location: string) => void;
|
markPostAsUnread: (post: Post, location: string) => void;
|
||||||
emitShortcutReactToLastPostFrom: (emittedFrom: 'CENTER' | 'RHS_ROOT' | 'NO_WHERE') => void;
|
emitShortcutReactToLastPostFrom: (emittedFrom: 'CENTER' | 'RHS_ROOT' | 'NO_WHERE') => void;
|
||||||
setActionsMenuInitialisationState: (viewed: Record<string, boolean>) => void;
|
|
||||||
selectPost: (post: Post) => void;
|
selectPost: (post: Post) => void;
|
||||||
selectPostFromRightHandSideSearch: (post: Post) => void;
|
selectPostFromRightHandSideSearch: (post: Post) => void;
|
||||||
removePost: (post: Post) => void;
|
removePost: (post: Post) => void;
|
||||||
|
@ -8,8 +8,7 @@ import type {Dispatch} from 'redux';
|
|||||||
import type {GlobalState} from '@mattermost/types/store';
|
import type {GlobalState} from '@mattermost/types/store';
|
||||||
|
|
||||||
import {getMissingProfilesByIds, getMissingProfilesByUsernames} from 'mattermost-redux/actions/users';
|
import {getMissingProfilesByIds, getMissingProfilesByUsernames} from 'mattermost-redux/actions/users';
|
||||||
import {Preferences} from 'mattermost-redux/constants';
|
import {shouldShowJoinLeaveMessages} from 'mattermost-redux/selectors/entities/preferences';
|
||||||
import {getBool} from 'mattermost-redux/selectors/entities/preferences';
|
|
||||||
import {getCurrentUser, makeGetProfilesByIdsAndUsernames} from 'mattermost-redux/selectors/entities/users';
|
import {getCurrentUser, makeGetProfilesByIdsAndUsernames} from 'mattermost-redux/selectors/entities/users';
|
||||||
|
|
||||||
import CombinedSystemMessage from './combined_system_message';
|
import CombinedSystemMessage from './combined_system_message';
|
||||||
@ -29,7 +28,7 @@ function makeMapStateToProps() {
|
|||||||
return {
|
return {
|
||||||
currentUserId: currentUser.id,
|
currentUserId: currentUser.id,
|
||||||
currentUsername: currentUser.username,
|
currentUsername: currentUser.username,
|
||||||
showJoinLeave: getBool(state, Preferences.CATEGORY_ADVANCED_SETTINGS, Preferences.ADVANCED_FILTER_JOIN_LEAVE, true),
|
showJoinLeave: shouldShowJoinLeaveMessages(state),
|
||||||
userProfiles: getProfilesByIdsAndUsernames(state, {allUserIds, allUsernames}),
|
userProfiles: getProfilesByIdsAndUsernames(state, {allUserIds, allUsernames}),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -25,12 +25,10 @@ import {Preferences} from 'utils/constants';
|
|||||||
|
|
||||||
import type {GlobalState} from 'types/store';
|
import type {GlobalState} from 'types/store';
|
||||||
|
|
||||||
function makeMapStateToProps() {
|
const getSystemNoticePreferences = makeGetCategory('getSystemNoticePreferences', Preferences.CATEGORY_SYSTEM_NOTICE);
|
||||||
const getCategory = makeGetCategory();
|
|
||||||
|
|
||||||
const getPreferenceNameMap = createSelector(
|
const getPreferenceNameMap = createSelector(
|
||||||
'getPreferenceNameMap',
|
'getPreferenceNameMap',
|
||||||
getCategory,
|
getSystemNoticePreferences,
|
||||||
(preferences) => {
|
(preferences) => {
|
||||||
const nameMap: {[key: string]: PreferenceType} = {};
|
const nameMap: {[key: string]: PreferenceType} = {};
|
||||||
preferences.forEach((p) => {
|
preferences.forEach((p) => {
|
||||||
@ -40,7 +38,7 @@ function makeMapStateToProps() {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
return function mapStateToProps(state: GlobalState) {
|
function mapStateToProps(state: GlobalState) {
|
||||||
const license = getLicense(state);
|
const license = getLicense(state);
|
||||||
const config = getConfig(state);
|
const config = getConfig(state);
|
||||||
const serverVersion = state.entities.general.serverVersion;
|
const serverVersion = state.entities.general.serverVersion;
|
||||||
@ -48,7 +46,7 @@ function makeMapStateToProps() {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
currentUserId: state.entities.users.currentUserId,
|
currentUserId: state.entities.users.currentUserId,
|
||||||
preferences: getPreferenceNameMap(state, Preferences.CATEGORY_SYSTEM_NOTICE),
|
preferences: getPreferenceNameMap(state),
|
||||||
dismissedNotices: state.views.notice.hasBeenDismissed,
|
dismissedNotices: state.views.notice.hasBeenDismissed,
|
||||||
isSystemAdmin: haveISystemPermission(state, {permission: Permissions.MANAGE_SYSTEM}),
|
isSystemAdmin: haveISystemPermission(state, {permission: Permissions.MANAGE_SYSTEM}),
|
||||||
notices: Notices,
|
notices: Notices,
|
||||||
@ -58,7 +56,6 @@ function makeMapStateToProps() {
|
|||||||
analytics,
|
analytics,
|
||||||
currentChannel: getCurrentChannel(state),
|
currentChannel: getCurrentChannel(state),
|
||||||
};
|
};
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function mapDispatchToProps(dispatch: Dispatch) {
|
function mapDispatchToProps(dispatch: Dispatch) {
|
||||||
@ -71,4 +68,4 @@ function mapDispatchToProps(dispatch: Dispatch) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(makeMapStateToProps, mapDispatchToProps)(SystemNotice);
|
export default connect(mapStateToProps, mapDispatchToProps)(SystemNotice);
|
||||||
|
@ -4,13 +4,12 @@
|
|||||||
import React, {memo, useCallback} from 'react';
|
import React, {memo, useCallback} from 'react';
|
||||||
import type {ReactNode} from 'react';
|
import type {ReactNode} from 'react';
|
||||||
import {useIntl} from 'react-intl';
|
import {useIntl} from 'react-intl';
|
||||||
import {useDispatch, useSelector, shallowEqual} from 'react-redux';
|
import {useDispatch, useSelector} from 'react-redux';
|
||||||
|
|
||||||
import type {UserThread} from '@mattermost/types/threads';
|
import type {UserThread} from '@mattermost/types/threads';
|
||||||
|
|
||||||
import {setThreadFollow, updateThreadRead, markLastPostInThreadAsUnread} from 'mattermost-redux/actions/threads';
|
import {setThreadFollow, updateThreadRead, markLastPostInThreadAsUnread} from 'mattermost-redux/actions/threads';
|
||||||
import {Preferences} from 'mattermost-redux/constants';
|
import {isPostFlagged} from 'mattermost-redux/selectors/entities/posts';
|
||||||
import {get} from 'mattermost-redux/selectors/entities/preferences';
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
flagPost as savePost,
|
flagPost as savePost,
|
||||||
@ -56,7 +55,7 @@ function ThreadMenu({
|
|||||||
goToInChannel,
|
goToInChannel,
|
||||||
} = useThreadRouting();
|
} = useThreadRouting();
|
||||||
|
|
||||||
const isSaved = useSelector((state: GlobalState) => get(state, Preferences.CATEGORY_FLAGGED_POST, threadId, null) != null, shallowEqual);
|
const isSaved = useSelector((state: GlobalState) => isPostFlagged(state, threadId));
|
||||||
|
|
||||||
const handleReadUnread = useCallback(() => {
|
const handleReadUnread = useCallback(() => {
|
||||||
const lastViewedAt = hasUnreads ? Date.now() : unreadTimestamp;
|
const lastViewedAt = hasUnreads ? Date.now() : unreadTimestamp;
|
||||||
|
@ -24,8 +24,10 @@ import type {GlobalState} from 'types/store';
|
|||||||
import AdvancedSettingsDisplay from './user_settings_advanced';
|
import AdvancedSettingsDisplay from './user_settings_advanced';
|
||||||
import type {OwnProps} from './user_settings_advanced';
|
import type {OwnProps} from './user_settings_advanced';
|
||||||
|
|
||||||
function makeMapStateToProps(state: GlobalState, props: OwnProps) {
|
const getAdvancedSettingsCategory = makeGetCategory('getAdvancedSettingsCategory', Preferences.CATEGORY_ADVANCED_SETTINGS);
|
||||||
const getAdvancedSettingsCategory = props.adminMode ? makeGetUserCategory(props.user.id) : makeGetCategory();
|
|
||||||
|
function makeMapStateToProps() {
|
||||||
|
const getUserAdvancedSettingsCategory = makeGetUserCategory('getAdvancedSettingsCategory', Preferences.CATEGORY_ADVANCED_SETTINGS);
|
||||||
|
|
||||||
return (state: GlobalState, props: OwnProps) => {
|
return (state: GlobalState, props: OwnProps) => {
|
||||||
const config = getConfig(state);
|
const config = getConfig(state);
|
||||||
@ -34,9 +36,10 @@ function makeMapStateToProps(state: GlobalState, props: OwnProps) {
|
|||||||
const enableJoinLeaveMessage = config.EnableJoinLeaveMessageByDefault === 'true';
|
const enableJoinLeaveMessage = config.EnableJoinLeaveMessageByDefault === 'true';
|
||||||
|
|
||||||
const userPreferences = props.adminMode && props.userPreferences ? props.userPreferences : undefined;
|
const userPreferences = props.adminMode && props.userPreferences ? props.userPreferences : undefined;
|
||||||
|
const advancedSettingsCategory = userPreferences ? getUserAdvancedSettingsCategory(state, props.user.id) : getAdvancedSettingsCategory(state);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
advancedSettingsCategory: getAdvancedSettingsCategory(state, Preferences.CATEGORY_ADVANCED_SETTINGS),
|
advancedSettingsCategory,
|
||||||
sendOnCtrlEnter: get(state, Preferences.CATEGORY_ADVANCED_SETTINGS, 'send_on_ctrl_enter', 'false', userPreferences),
|
sendOnCtrlEnter: get(state, Preferences.CATEGORY_ADVANCED_SETTINGS, 'send_on_ctrl_enter', 'false', userPreferences),
|
||||||
codeBlockOnCtrlEnter: get(state, Preferences.CATEGORY_ADVANCED_SETTINGS, 'code_block_ctrl_enter', 'true', userPreferences),
|
codeBlockOnCtrlEnter: get(state, Preferences.CATEGORY_ADVANCED_SETTINGS, 'code_block_ctrl_enter', 'true', userPreferences),
|
||||||
formatting: get(state, Preferences.CATEGORY_ADVANCED_SETTINGS, 'formatting', 'true', userPreferences),
|
formatting: get(state, Preferences.CATEGORY_ADVANCED_SETTINGS, 'formatting', 'true', userPreferences),
|
||||||
|
@ -25,7 +25,7 @@ export type OwnProps = {
|
|||||||
type Props = OwnProps & {
|
type Props = OwnProps & {
|
||||||
active: boolean;
|
active: boolean;
|
||||||
areAllSectionsInactive: boolean;
|
areAllSectionsInactive: boolean;
|
||||||
joinLeave?: string;
|
joinLeave: string;
|
||||||
onUpdateSection: (section?: string) => void;
|
onUpdateSection: (section?: string) => void;
|
||||||
renderOnOffLabel: (label: string) => ReactNode;
|
renderOnOffLabel: (label: string) => ReactNode;
|
||||||
actions: {
|
actions: {
|
||||||
@ -34,7 +34,7 @@ type Props = OwnProps & {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type State = {
|
type State = {
|
||||||
joinLeaveState?: string;
|
joinLeaveState: string;
|
||||||
isSaving?: boolean;
|
isSaving?: boolean;
|
||||||
serverError?: string;
|
serverError?: string;
|
||||||
}
|
}
|
||||||
|
@ -108,7 +108,7 @@ export default class AdvancedSettingsDisplay extends React.PureComponent<Props,
|
|||||||
user_id: userId,
|
user_id: userId,
|
||||||
category: Constants.Preferences.CATEGORY_ADVANCED_SETTINGS,
|
category: Constants.Preferences.CATEGORY_ADVANCED_SETTINGS,
|
||||||
name: setting,
|
name: setting,
|
||||||
value: this.state.settings[setting],
|
value: this.state.settings[setting]!,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -6,28 +6,22 @@ import {bindActionCreators} from 'redux';
|
|||||||
import type {Dispatch} from 'redux';
|
import type {Dispatch} from 'redux';
|
||||||
|
|
||||||
import {saveTheme, deleteTeamSpecificThemes} from 'mattermost-redux/actions/preferences';
|
import {saveTheme, deleteTeamSpecificThemes} from 'mattermost-redux/actions/preferences';
|
||||||
import {getTheme, makeGetCategory} from 'mattermost-redux/selectors/entities/preferences';
|
import {getTheme, getThemePreferences} from 'mattermost-redux/selectors/entities/preferences';
|
||||||
import {getCurrentTeamId, getMyTeamsCount} from 'mattermost-redux/selectors/entities/teams';
|
import {getCurrentTeamId, getMyTeamsCount} from 'mattermost-redux/selectors/entities/teams';
|
||||||
|
|
||||||
import {openModal} from 'actions/views/modals';
|
import {openModal} from 'actions/views/modals';
|
||||||
|
|
||||||
import {Preferences} from 'utils/constants';
|
|
||||||
|
|
||||||
import type {GlobalState} from 'types/store';
|
import type {GlobalState} from 'types/store';
|
||||||
|
|
||||||
import UserSettingsTheme from './user_settings_theme';
|
import UserSettingsTheme from './user_settings_theme';
|
||||||
|
|
||||||
function makeMapStateToProps() {
|
function mapStateToProps(state: GlobalState) {
|
||||||
const getThemeCategory = makeGetCategory();
|
|
||||||
|
|
||||||
return (state: GlobalState) => {
|
|
||||||
return {
|
return {
|
||||||
currentTeamId: getCurrentTeamId(state),
|
currentTeamId: getCurrentTeamId(state),
|
||||||
theme: getTheme(state),
|
theme: getTheme(state),
|
||||||
applyToAllTeams: getThemeCategory(state, Preferences.CATEGORY_THEME).length <= 1,
|
applyToAllTeams: getThemePreferences(state).length <= 1,
|
||||||
showAllTeamsCheckbox: getMyTeamsCount(state) > 1,
|
showAllTeamsCheckbox: getMyTeamsCount(state) > 1,
|
||||||
};
|
};
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function mapDispatchToProps(dispatch: Dispatch) {
|
function mapDispatchToProps(dispatch: Dispatch) {
|
||||||
@ -40,4 +34,4 @@ function mapDispatchToProps(dispatch: Dispatch) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(makeMapStateToProps, mapDispatchToProps)(UserSettingsTheme);
|
export default connect(mapStateToProps, mapDispatchToProps)(UserSettingsTheme);
|
||||||
|
@ -14,8 +14,8 @@ import {createCustomEmoji} from 'mattermost-redux/actions/emojis';
|
|||||||
import * as Actions from 'mattermost-redux/actions/posts';
|
import * as Actions from 'mattermost-redux/actions/posts';
|
||||||
import {loadMe} from 'mattermost-redux/actions/users';
|
import {loadMe} from 'mattermost-redux/actions/users';
|
||||||
import {Client4} from 'mattermost-redux/client';
|
import {Client4} from 'mattermost-redux/client';
|
||||||
|
import {isPostFlagged} from 'mattermost-redux/selectors/entities/posts';
|
||||||
import type {GetStateFunc} from 'mattermost-redux/types/actions';
|
import type {GetStateFunc} from 'mattermost-redux/types/actions';
|
||||||
import {getPreferenceKey} from 'mattermost-redux/utils/preference_utils';
|
|
||||||
|
|
||||||
import mockStore from 'tests/test_store';
|
import mockStore from 'tests/test_store';
|
||||||
|
|
||||||
@ -1038,10 +1038,8 @@ describe('Actions.Posts', () => {
|
|||||||
reply(200, OK_RESPONSE);
|
reply(200, OK_RESPONSE);
|
||||||
|
|
||||||
dispatch(Actions.flagPost(post1.id));
|
dispatch(Actions.flagPost(post1.id));
|
||||||
const state = getState();
|
|
||||||
const prefKey = getPreferenceKey(Preferences.CATEGORY_FLAGGED_POST, post1.id);
|
expect(isPostFlagged(getState(), post1.id)).toBe(true);
|
||||||
const preference = state.entities.preferences.myPreferences[prefKey];
|
|
||||||
expect(preference).toBeTruthy();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('unflagPost', async () => {
|
it('unflagPost', async () => {
|
||||||
@ -1069,20 +1067,15 @@ describe('Actions.Posts', () => {
|
|||||||
put(`/${TestHelper.basicUser!.id}/preferences`).
|
put(`/${TestHelper.basicUser!.id}/preferences`).
|
||||||
reply(200, OK_RESPONSE);
|
reply(200, OK_RESPONSE);
|
||||||
dispatch(Actions.flagPost(post1.id));
|
dispatch(Actions.flagPost(post1.id));
|
||||||
let state = getState();
|
|
||||||
const prefKey = getPreferenceKey(Preferences.CATEGORY_FLAGGED_POST, post1.id);
|
expect(isPostFlagged(getState(), post1.id)).toBe(true);
|
||||||
const preference = state.entities.preferences.myPreferences[prefKey];
|
|
||||||
expect(preference).toBeTruthy();
|
|
||||||
|
|
||||||
nock(Client4.getUsersRoute()).
|
nock(Client4.getUsersRoute()).
|
||||||
delete(`/${TestHelper.basicUser!.id}/preferences`).
|
delete(`/${TestHelper.basicUser!.id}/preferences`).
|
||||||
reply(200, OK_RESPONSE);
|
reply(200, OK_RESPONSE);
|
||||||
dispatch(Actions.unflagPost(post1.id));
|
dispatch(Actions.unflagPost(post1.id));
|
||||||
state = getState();
|
|
||||||
const unflagged = state.entities.preferences.myPreferences[prefKey];
|
expect(isPostFlagged(getState(), post1.id)).toBe(false);
|
||||||
if (unflagged) {
|
|
||||||
throw new Error('unexpected unflagged');
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('setUnreadPost', async () => {
|
it('setUnreadPost', async () => {
|
||||||
|
@ -1234,6 +1234,7 @@ export function unflagPost(postId: string): ActionFuncAsync {
|
|||||||
user_id: currentUserId,
|
user_id: currentUserId,
|
||||||
category: Preferences.CATEGORY_FLAGGED_POST,
|
category: Preferences.CATEGORY_FLAGGED_POST,
|
||||||
name: postId,
|
name: postId,
|
||||||
|
value: 'true',
|
||||||
};
|
};
|
||||||
|
|
||||||
Client4.trackEvent('action', 'action_posts_unflag');
|
Client4.trackEvent('action', 'action_posts_unflag');
|
||||||
|
@ -5,7 +5,7 @@ import type {PreferenceType} from '@mattermost/types/preferences';
|
|||||||
|
|
||||||
import {PreferenceTypes} from 'mattermost-redux/action_types';
|
import {PreferenceTypes} from 'mattermost-redux/action_types';
|
||||||
import {Client4} from 'mattermost-redux/client';
|
import {Client4} from 'mattermost-redux/client';
|
||||||
import {getMyPreferences as getMyPreferencesSelector, makeGetCategory} from 'mattermost-redux/selectors/entities/preferences';
|
import {getMyPreferences as getMyPreferencesSelector, getThemePreferences} from 'mattermost-redux/selectors/entities/preferences';
|
||||||
import type {Theme} from 'mattermost-redux/selectors/entities/preferences';
|
import type {Theme} from 'mattermost-redux/selectors/entities/preferences';
|
||||||
import {getCurrentUserId} from 'mattermost-redux/selectors/entities/users';
|
import {getCurrentUserId} from 'mattermost-redux/selectors/entities/users';
|
||||||
import type {ActionFuncAsync, ThunkActionFunc} from 'mattermost-redux/types/actions';
|
import type {ActionFuncAsync, ThunkActionFunc} from 'mattermost-redux/types/actions';
|
||||||
@ -56,20 +56,6 @@ export function getUserPreferences(userID: string) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setActionsMenuInitialisationState(initializationState: Record<string, boolean>): ThunkActionFunc<void> {
|
|
||||||
return async (dispatch, getState) => {
|
|
||||||
const state = getState();
|
|
||||||
const currentUserId = getCurrentUserId(state);
|
|
||||||
const preference: PreferenceType = {
|
|
||||||
user_id: currentUserId,
|
|
||||||
category: Preferences.CATEGORY_ACTIONS_MENU,
|
|
||||||
name: Preferences.NAME_ACTIONS_MENU_TUTORIAL_STATE,
|
|
||||||
value: JSON.stringify(initializationState),
|
|
||||||
};
|
|
||||||
await dispatch(savePreferences(currentUserId, [preference]));
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setCustomStatusInitialisationState(initializationState: Record<string, boolean>): ThunkActionFunc<void> {
|
export function setCustomStatusInitialisationState(initializationState: Record<string, boolean>): ThunkActionFunc<void> {
|
||||||
return async (dispatch, getState) => {
|
return async (dispatch, getState) => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
@ -130,7 +116,7 @@ export function deleteTeamSpecificThemes(): ActionFuncAsync {
|
|||||||
return async (dispatch, getState) => {
|
return async (dispatch, getState) => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
|
|
||||||
const themePreferences: PreferenceType[] = makeGetCategory()(state, Preferences.CATEGORY_THEME);
|
const themePreferences: PreferenceType[] = getThemePreferences(state);
|
||||||
const currentUserId = getCurrentUserId(state);
|
const currentUserId = getCurrentUserId(state);
|
||||||
|
|
||||||
const toDelete = themePreferences.filter((pref) => pref.name !== '');
|
const toDelete = themePreferences.filter((pref) => pref.name !== '');
|
||||||
|
@ -37,10 +37,6 @@ const Preferences = {
|
|||||||
MENTION_KEYS: 'mention_keys',
|
MENTION_KEYS: 'mention_keys',
|
||||||
USE_MILITARY_TIME: 'use_military_time',
|
USE_MILITARY_TIME: 'use_military_time',
|
||||||
|
|
||||||
CATEGORY_ACTIONS_MENU: 'actions_menu',
|
|
||||||
NAME_ACTIONS_MENU_TUTORIAL_STATE: 'actions_menu_tutorial_state',
|
|
||||||
ACTIONS_MENU_VIEWED: 'actions_menu_modal_viewed',
|
|
||||||
|
|
||||||
CATEGORY_CUSTOM_STATUS: 'custom_status',
|
CATEGORY_CUSTOM_STATUS: 'custom_status',
|
||||||
NAME_CUSTOM_STATUS_TUTORIAL_STATE: 'custom_status_tutorial_state',
|
NAME_CUSTOM_STATUS_TUTORIAL_STATE: 'custom_status_tutorial_state',
|
||||||
NAME_RECENT_CUSTOM_STATUSES: 'recent_custom_statuses',
|
NAME_RECENT_CUSTOM_STATUSES: 'recent_custom_statuses',
|
||||||
@ -82,6 +78,8 @@ const Preferences = {
|
|||||||
HIDE_BATCH_EXPORT_CONFIRM_MODAL: 'hide_batch_export_confirm_modal',
|
HIDE_BATCH_EXPORT_CONFIRM_MODAL: 'hide_batch_export_confirm_modal',
|
||||||
HIDE_MYSQL_STATS_NOTIFICATION: 'hide_mysql_stats_notifcation',
|
HIDE_MYSQL_STATS_NOTIFICATION: 'hide_mysql_stats_notifcation',
|
||||||
|
|
||||||
|
CATEGORY_OVERAGE_USERS_BANNER: 'overage_users_banner',
|
||||||
|
|
||||||
CATEGORY_THEME: 'theme',
|
CATEGORY_THEME: 'theme',
|
||||||
THEMES: {
|
THEMES: {
|
||||||
denim: {
|
denim: {
|
||||||
|
@ -253,6 +253,11 @@ describe('Selectors.Posts', () => {
|
|||||||
|
|
||||||
const testStateAny = deepFreezeAndThrowOnMutation({
|
const testStateAny = deepFreezeAndThrowOnMutation({
|
||||||
entities: {
|
entities: {
|
||||||
|
general: {
|
||||||
|
config: {
|
||||||
|
EnableJoinLeaveMessageByDefault: 'true',
|
||||||
|
},
|
||||||
|
},
|
||||||
users: {
|
users: {
|
||||||
currentUserId: userAny.id,
|
currentUserId: userAny.id,
|
||||||
profiles: profilesAny,
|
profiles: profilesAny,
|
||||||
@ -372,6 +377,11 @@ describe('Selectors.Posts', () => {
|
|||||||
|
|
||||||
const testStateRoot = deepFreezeAndThrowOnMutation({
|
const testStateRoot = deepFreezeAndThrowOnMutation({
|
||||||
entities: {
|
entities: {
|
||||||
|
general: {
|
||||||
|
config: {
|
||||||
|
EnableJoinLeaveMessageByDefault: 'true',
|
||||||
|
},
|
||||||
|
},
|
||||||
users: {
|
users: {
|
||||||
currentUserId: userRoot.id,
|
currentUserId: userRoot.id,
|
||||||
profiles: profilesRoot,
|
profiles: profilesRoot,
|
||||||
@ -485,6 +495,11 @@ describe('Selectors.Posts', () => {
|
|||||||
|
|
||||||
const testStateNever = deepFreezeAndThrowOnMutation({
|
const testStateNever = deepFreezeAndThrowOnMutation({
|
||||||
entities: {
|
entities: {
|
||||||
|
general: {
|
||||||
|
config: {
|
||||||
|
EnableJoinLeaveMessageByDefault: 'true',
|
||||||
|
},
|
||||||
|
},
|
||||||
users: {
|
users: {
|
||||||
currentUserId: userNever.id,
|
currentUserId: userNever.id,
|
||||||
profiles: profilesNever,
|
profiles: profilesNever,
|
||||||
@ -601,6 +616,11 @@ describe('Selectors.Posts', () => {
|
|||||||
|
|
||||||
const testStateAny = deepFreezeAndThrowOnMutation({
|
const testStateAny = deepFreezeAndThrowOnMutation({
|
||||||
entities: {
|
entities: {
|
||||||
|
general: {
|
||||||
|
config: {
|
||||||
|
EnableJoinLeaveMessageByDefault: 'true',
|
||||||
|
},
|
||||||
|
},
|
||||||
users: {
|
users: {
|
||||||
currentUserId: userAny.id,
|
currentUserId: userAny.id,
|
||||||
profiles: profilesAny,
|
profiles: profilesAny,
|
||||||
@ -678,6 +698,11 @@ describe('Selectors.Posts', () => {
|
|||||||
|
|
||||||
const testStateAny = deepFreezeAndThrowOnMutation({
|
const testStateAny = deepFreezeAndThrowOnMutation({
|
||||||
entities: {
|
entities: {
|
||||||
|
general: {
|
||||||
|
config: {
|
||||||
|
EnableJoinLeaveMessageByDefault: 'true',
|
||||||
|
},
|
||||||
|
},
|
||||||
users: {
|
users: {
|
||||||
currentUserId: userAny.id,
|
currentUserId: userAny.id,
|
||||||
profiles: profilesAny,
|
profiles: profilesAny,
|
||||||
@ -1823,6 +1848,11 @@ describe('Selectors.Posts', () => {
|
|||||||
};
|
};
|
||||||
const state = {
|
const state = {
|
||||||
entities: {
|
entities: {
|
||||||
|
general: {
|
||||||
|
config: {
|
||||||
|
EnableJoinLeaveMessageByDefault: 'true',
|
||||||
|
},
|
||||||
|
},
|
||||||
posts: {
|
posts: {
|
||||||
posts: testPosts,
|
posts: testPosts,
|
||||||
postsInChannel: {
|
postsInChannel: {
|
||||||
@ -1852,6 +1882,11 @@ describe('Selectors.Posts', () => {
|
|||||||
};
|
};
|
||||||
const state = {
|
const state = {
|
||||||
entities: {
|
entities: {
|
||||||
|
general: {
|
||||||
|
config: {
|
||||||
|
EnableJoinLeaveMessageByDefault: 'true',
|
||||||
|
},
|
||||||
|
},
|
||||||
posts: {
|
posts: {
|
||||||
posts: testPosts,
|
posts: testPosts,
|
||||||
postsInChannel: {
|
postsInChannel: {
|
||||||
@ -1880,6 +1915,11 @@ describe('Selectors.Posts', () => {
|
|||||||
channels: {
|
channels: {
|
||||||
currentChannelId: 'abcd',
|
currentChannelId: 'abcd',
|
||||||
},
|
},
|
||||||
|
general: {
|
||||||
|
config: {
|
||||||
|
EnableJoinLeaveMessageByDefault: 'true',
|
||||||
|
},
|
||||||
|
},
|
||||||
posts: {
|
posts: {
|
||||||
posts: {},
|
posts: {},
|
||||||
postsInChannel: [],
|
postsInChannel: [],
|
||||||
@ -1910,6 +1950,11 @@ describe('Selectors.Posts', () => {
|
|||||||
channels: {
|
channels: {
|
||||||
currentChannelId: 'abcd',
|
currentChannelId: 'abcd',
|
||||||
},
|
},
|
||||||
|
general: {
|
||||||
|
config: {
|
||||||
|
EnableJoinLeaveMessageByDefault: 'true',
|
||||||
|
},
|
||||||
|
},
|
||||||
posts: {
|
posts: {
|
||||||
posts: postsAny,
|
posts: postsAny,
|
||||||
postsInChannel: {
|
postsInChannel: {
|
||||||
@ -2147,6 +2192,11 @@ describe('getPostsInCurrentChannel', () => {
|
|||||||
channels: {
|
channels: {
|
||||||
currentChannelId: 'channel1',
|
currentChannelId: 'channel1',
|
||||||
},
|
},
|
||||||
|
general: {
|
||||||
|
config: {
|
||||||
|
EnableJoinLeaveMessageByDefault: 'true',
|
||||||
|
},
|
||||||
|
},
|
||||||
posts: {
|
posts: {
|
||||||
posts: {},
|
posts: {},
|
||||||
postsInChannel: {},
|
postsInChannel: {},
|
||||||
@ -2177,6 +2227,11 @@ describe('getPostsInCurrentChannel', () => {
|
|||||||
channels: {
|
channels: {
|
||||||
currentChannelId: 'channel1',
|
currentChannelId: 'channel1',
|
||||||
},
|
},
|
||||||
|
general: {
|
||||||
|
config: {
|
||||||
|
EnableJoinLeaveMessageByDefault: 'true',
|
||||||
|
},
|
||||||
|
},
|
||||||
posts: {
|
posts: {
|
||||||
posts: {
|
posts: {
|
||||||
post1,
|
post1,
|
||||||
@ -2214,6 +2269,11 @@ describe('getPostsInCurrentChannel', () => {
|
|||||||
channels: {
|
channels: {
|
||||||
currentChannelId: 'channel1',
|
currentChannelId: 'channel1',
|
||||||
},
|
},
|
||||||
|
general: {
|
||||||
|
config: {
|
||||||
|
EnableJoinLeaveMessageByDefault: 'true',
|
||||||
|
},
|
||||||
|
},
|
||||||
posts: {
|
posts: {
|
||||||
posts: {
|
posts: {
|
||||||
post1,
|
post1,
|
||||||
|
@ -24,11 +24,10 @@ import {createSelector} from 'mattermost-redux/selectors/create_selector';
|
|||||||
import {getChannel} from 'mattermost-redux/selectors/entities/channels';
|
import {getChannel} from 'mattermost-redux/selectors/entities/channels';
|
||||||
import {getCurrentChannelId, getCurrentUser} from 'mattermost-redux/selectors/entities/common';
|
import {getCurrentChannelId, getCurrentUser} from 'mattermost-redux/selectors/entities/common';
|
||||||
import {getConfig} from 'mattermost-redux/selectors/entities/general';
|
import {getConfig} from 'mattermost-redux/selectors/entities/general';
|
||||||
import {getMyPreferences} from 'mattermost-redux/selectors/entities/preferences';
|
import {getBool, shouldShowJoinLeaveMessages} from 'mattermost-redux/selectors/entities/preferences';
|
||||||
import {getCurrentTeamId} from 'mattermost-redux/selectors/entities/teams';
|
import {getCurrentTeamId} from 'mattermost-redux/selectors/entities/teams';
|
||||||
import {getUsers, getCurrentUserId, getUserStatuses} from 'mattermost-redux/selectors/entities/users';
|
import {getUsers, getCurrentUserId, getUserStatuses} from 'mattermost-redux/selectors/entities/users';
|
||||||
import {createIdsSelector} from 'mattermost-redux/utils/helpers';
|
import {createIdsSelector} from 'mattermost-redux/utils/helpers';
|
||||||
import {shouldShowJoinLeaveMessages} from 'mattermost-redux/utils/post_list';
|
|
||||||
import {
|
import {
|
||||||
isPostEphemeral,
|
isPostEphemeral,
|
||||||
isSystemMessage,
|
isSystemMessage,
|
||||||
@ -37,7 +36,6 @@ import {
|
|||||||
isPostPendingOrFailed,
|
isPostPendingOrFailed,
|
||||||
isPostCommentMention,
|
isPostCommentMention,
|
||||||
} from 'mattermost-redux/utils/post_utils';
|
} from 'mattermost-redux/utils/post_utils';
|
||||||
import {getPreferenceKey} from 'mattermost-redux/utils/preference_utils';
|
|
||||||
import {isGuest} from 'mattermost-redux/utils/user_utils';
|
import {isGuest} from 'mattermost-redux/utils/user_utils';
|
||||||
|
|
||||||
export function getAllPosts(state: GlobalState) {
|
export function getAllPosts(state: GlobalState) {
|
||||||
@ -53,6 +51,10 @@ export function getPost(state: GlobalState, postId: Post['id']): Post {
|
|||||||
return getAllPosts(state)[postId];
|
return getAllPosts(state)[postId];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isPostFlagged(state: GlobalState, postId: Post['id']): boolean {
|
||||||
|
return getBool(state, Preferences.CATEGORY_FLAGGED_POST, postId);
|
||||||
|
}
|
||||||
|
|
||||||
export function getPostRepliesCount(state: GlobalState, postId: Post['id']): number {
|
export function getPostRepliesCount(state: GlobalState, postId: Post['id']): number {
|
||||||
return state.entities.posts.postsReplies[postId] || 0;
|
return state.entities.posts.postsReplies[postId] || 0;
|
||||||
}
|
}
|
||||||
@ -344,18 +346,15 @@ export function makeGetPostsInChannel(): (state: GlobalState, channelId: Channel
|
|||||||
getPostsInThread,
|
getPostsInThread,
|
||||||
(state: GlobalState, channelId: Channel['id']) => getPostIdsInChannel(state, channelId),
|
(state: GlobalState, channelId: Channel['id']) => getPostIdsInChannel(state, channelId),
|
||||||
getCurrentUser,
|
getCurrentUser,
|
||||||
getMyPreferences,
|
shouldShowJoinLeaveMessages,
|
||||||
(state: GlobalState, channelId: Channel['id'], numPosts: number) => numPosts || Posts.POST_CHUNK_SIZE,
|
(state: GlobalState, channelId: Channel['id'], numPosts: number) => numPosts || Posts.POST_CHUNK_SIZE,
|
||||||
(allPosts, postsInThread, allPostIds, currentUser, myPreferences, numPosts) => {
|
(allPosts, postsInThread, allPostIds, currentUser, showJoinLeave, numPosts) => {
|
||||||
if (!allPostIds) {
|
if (!allPostIds) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const posts: PostWithFormatData[] = [];
|
const posts: PostWithFormatData[] = [];
|
||||||
|
|
||||||
const joinLeavePref = myPreferences[getPreferenceKey(Preferences.CATEGORY_ADVANCED_SETTINGS, Preferences.ADVANCED_FILTER_JOIN_LEAVE)];
|
|
||||||
const showJoinLeave = joinLeavePref ? joinLeavePref.value !== 'false' : true;
|
|
||||||
|
|
||||||
const postIds = numPosts === -1 ? allPostIds : allPostIds.slice(0, numPosts);
|
const postIds = numPosts === -1 ? allPostIds : allPostIds.slice(0, numPosts);
|
||||||
|
|
||||||
for (let i = 0; i < postIds.length; i++) {
|
for (let i = 0; i < postIds.length; i++) {
|
||||||
@ -388,15 +387,13 @@ export function makeGetPostsAroundPost(): (state: GlobalState, postId: Post['id'
|
|||||||
getPostsInThread,
|
getPostsInThread,
|
||||||
(state: GlobalState, focusedPostId) => focusedPostId,
|
(state: GlobalState, focusedPostId) => focusedPostId,
|
||||||
getCurrentUser,
|
getCurrentUser,
|
||||||
getMyPreferences,
|
shouldShowJoinLeaveMessages,
|
||||||
(postIds, allPosts, postsInThread, focusedPostId, currentUser, myPreferences) => {
|
(postIds, allPosts, postsInThread, focusedPostId, currentUser, showJoinLeave) => {
|
||||||
if (!postIds || !currentUser) {
|
if (!postIds || !currentUser) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const posts: PostWithFormatData[] = [];
|
const posts: PostWithFormatData[] = [];
|
||||||
const joinLeavePref = myPreferences[getPreferenceKey(Preferences.CATEGORY_ADVANCED_SETTINGS, Preferences.ADVANCED_FILTER_JOIN_LEAVE)];
|
|
||||||
const showJoinLeave = joinLeavePref ? joinLeavePref.value !== 'false' : true;
|
|
||||||
|
|
||||||
for (let i = 0; i < postIds.length; i++) {
|
for (let i = 0; i < postIds.length; i++) {
|
||||||
const post = allPosts[postIds[i]];
|
const post = allPosts[postIds[i]];
|
||||||
@ -565,13 +562,11 @@ export const getMostRecentPostIdInChannel: (state: GlobalState, channelId: Chann
|
|||||||
'getMostRecentPostIdInChannel',
|
'getMostRecentPostIdInChannel',
|
||||||
getAllPosts,
|
getAllPosts,
|
||||||
(state: GlobalState, channelId: string) => getPostIdsInChannel(state, channelId),
|
(state: GlobalState, channelId: string) => getPostIdsInChannel(state, channelId),
|
||||||
getMyPreferences,
|
shouldShowJoinLeaveMessages,
|
||||||
(posts, postIdsInChannel, preferences) => {
|
(posts, postIdsInChannel, allowSystemMessages) => {
|
||||||
if (!postIdsInChannel) {
|
if (!postIdsInChannel) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
const key = getPreferenceKey(Preferences.CATEGORY_ADVANCED_SETTINGS, Preferences.ADVANCED_FILTER_JOIN_LEAVE);
|
|
||||||
const allowSystemMessages = preferences[key] ? preferences[key].value === 'true' : true;
|
|
||||||
|
|
||||||
if (!allowSystemMessages) {
|
if (!allowSystemMessages) {
|
||||||
// return the most recent non-system message in the channel
|
// return the most recent non-system message in the channel
|
||||||
|
@ -135,11 +135,6 @@ describe('Selectors.Preferences', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('get preferences by category', () => {
|
|
||||||
const getCategory = Selectors.makeGetCategory();
|
|
||||||
expect(getCategory(testState, category1)).toEqual([pref1]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('get direct channel show preferences', () => {
|
it('get direct channel show preferences', () => {
|
||||||
expect(Selectors.getDirectShowPreferences(testState)).toEqual([dmPref1, dmPref2]);
|
expect(Selectors.getDirectShowPreferences(testState)).toEqual([dmPref1, dmPref2]);
|
||||||
});
|
});
|
||||||
@ -599,6 +594,233 @@ describe('Selectors.Preferences', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('makeGetCategory', () => {
|
||||||
|
const category1 = 'category1';
|
||||||
|
const category2 = 'category2';
|
||||||
|
const name1 = 'name1';
|
||||||
|
const name2 = 'name2';
|
||||||
|
|
||||||
|
function getBaseState() {
|
||||||
|
return deepFreezeAndThrowOnMutation({
|
||||||
|
entities: {
|
||||||
|
preferences: {
|
||||||
|
myPreferences: {
|
||||||
|
[getPreferenceKey(category1, name1)]: {
|
||||||
|
category: category1,
|
||||||
|
name: name1,
|
||||||
|
value: 'value1',
|
||||||
|
},
|
||||||
|
[getPreferenceKey(category2, name1)]: {
|
||||||
|
category: category2,
|
||||||
|
name: name1,
|
||||||
|
value: 'value2',
|
||||||
|
},
|
||||||
|
[getPreferenceKey(category1, name2)]: {
|
||||||
|
category: category1,
|
||||||
|
name: name2,
|
||||||
|
value: 'value3',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}) as GlobalState;
|
||||||
|
}
|
||||||
|
|
||||||
|
it('should return preferences in a category', () => {
|
||||||
|
const state = getBaseState();
|
||||||
|
|
||||||
|
const getCategory1 = Selectors.makeGetCategory('getCategory1', category1);
|
||||||
|
const getCategory2 = Selectors.makeGetCategory('getCategory2', category2);
|
||||||
|
|
||||||
|
expect(getCategory1(state)).toEqual([
|
||||||
|
{
|
||||||
|
category: category1,
|
||||||
|
name: name1,
|
||||||
|
value: 'value1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: category1,
|
||||||
|
name: name2,
|
||||||
|
value: 'value3',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
expect(getCategory2(state)).toEqual([
|
||||||
|
{
|
||||||
|
category: category2,
|
||||||
|
name: name1,
|
||||||
|
value: 'value2',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return the same preference objects unless they change', () => {
|
||||||
|
let state = getBaseState();
|
||||||
|
|
||||||
|
const preference1 = state.entities.preferences.myPreferences[getPreferenceKey(category1, name1)];
|
||||||
|
const preference2 = state.entities.preferences.myPreferences[getPreferenceKey(category1, name2)];
|
||||||
|
|
||||||
|
const getCategory1 = Selectors.makeGetCategory('getCategory1', category1);
|
||||||
|
|
||||||
|
expect(getCategory1(state)[0]).toBe(preference1);
|
||||||
|
expect(getCategory1(state)[1]).toBe(preference2);
|
||||||
|
|
||||||
|
state = mergeObjects(state, {
|
||||||
|
entities: {
|
||||||
|
preferences: {
|
||||||
|
myPreferences: {
|
||||||
|
[getPreferenceKey(category1, name1)]: {
|
||||||
|
category: category1,
|
||||||
|
name: name1,
|
||||||
|
value: 'new value',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(getCategory1(state)[0]).not.toBe(preference1);
|
||||||
|
expect(getCategory1(state)[1]).toBe(preference2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should only return a new array when one of the preferences in that category changes', () => {
|
||||||
|
let state = getBaseState();
|
||||||
|
|
||||||
|
const getCategory1 = Selectors.makeGetCategory('getCategory1', category1);
|
||||||
|
const getCategory2 = Selectors.makeGetCategory('getCategory2', category2);
|
||||||
|
|
||||||
|
const originalResult1 = getCategory1(state);
|
||||||
|
const originalResult2 = getCategory2(state);
|
||||||
|
|
||||||
|
expect(getCategory1(state)).toBe(originalResult1);
|
||||||
|
|
||||||
|
state = mergeObjects(state, {
|
||||||
|
entities: {
|
||||||
|
preferences: {
|
||||||
|
myPreferences: {
|
||||||
|
[getPreferenceKey(category2, name2)]: {
|
||||||
|
category: category2,
|
||||||
|
name: name2,
|
||||||
|
value: 'value4',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(getCategory1(state)).toBe(originalResult1);
|
||||||
|
expect(getCategory2(state)).not.toBe(originalResult2);
|
||||||
|
|
||||||
|
state = mergeObjects(state, {
|
||||||
|
entities: {
|
||||||
|
preferences: {
|
||||||
|
myPreferences: {
|
||||||
|
[getPreferenceKey(category1, name1)]: {
|
||||||
|
category: category1,
|
||||||
|
name: name1,
|
||||||
|
value: 'new value',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(getCategory1(state)).not.toBe(originalResult1);
|
||||||
|
expect(getCategory2(state)).not.toBe(originalResult2);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('shouldShowJoinLeaveMessages', () => {
|
||||||
|
it('should default to true', () => {
|
||||||
|
const state = {
|
||||||
|
entities: {
|
||||||
|
general: {
|
||||||
|
config: {
|
||||||
|
EnableJoinLeaveMessageByDefault: 'true',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
preferences: {
|
||||||
|
myPreferences: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as unknown as GlobalState;
|
||||||
|
|
||||||
|
// Defaults to show post
|
||||||
|
const show = Selectors.shouldShowJoinLeaveMessages(state);
|
||||||
|
expect(show).toEqual(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('set config to false, return false', () => {
|
||||||
|
const state = {
|
||||||
|
entities: {
|
||||||
|
general: {
|
||||||
|
config: {
|
||||||
|
EnableJoinLeaveMessageByDefault: 'false',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
preferences: {
|
||||||
|
myPreferences: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as unknown as GlobalState;
|
||||||
|
|
||||||
|
// Defaults to show post
|
||||||
|
const show = Selectors.shouldShowJoinLeaveMessages(state);
|
||||||
|
expect(show).toEqual(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('if user preference, set default wont be used', () => {
|
||||||
|
const state = {
|
||||||
|
entities: {
|
||||||
|
general: {
|
||||||
|
config: {
|
||||||
|
EnableJoinLeaveMessageByDefault: 'false',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
preferences: {
|
||||||
|
myPreferences: {
|
||||||
|
[getPreferenceKey(Preferences.CATEGORY_ADVANCED_SETTINGS, Preferences.ADVANCED_FILTER_JOIN_LEAVE)]: {
|
||||||
|
category: Preferences.CATEGORY_ADVANCED_SETTINGS,
|
||||||
|
name: Preferences.ADVANCED_FILTER_JOIN_LEAVE,
|
||||||
|
value: 'true',
|
||||||
|
},
|
||||||
|
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as unknown as GlobalState;
|
||||||
|
|
||||||
|
// Defaults to show post
|
||||||
|
const show = Selectors.shouldShowJoinLeaveMessages(state);
|
||||||
|
expect(show).toEqual(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('if user preference, set default wont be used', () => {
|
||||||
|
const state = {
|
||||||
|
entities: {
|
||||||
|
general: {
|
||||||
|
config: {
|
||||||
|
EnableJoinLeaveMessageByDefault: 'true',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
preferences: {
|
||||||
|
myPreferences: {
|
||||||
|
[getPreferenceKey(Preferences.CATEGORY_ADVANCED_SETTINGS, Preferences.ADVANCED_FILTER_JOIN_LEAVE)]: {
|
||||||
|
category: Preferences.CATEGORY_ADVANCED_SETTINGS,
|
||||||
|
name: Preferences.ADVANCED_FILTER_JOIN_LEAVE,
|
||||||
|
value: 'false',
|
||||||
|
},
|
||||||
|
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as unknown as GlobalState;
|
||||||
|
|
||||||
|
// Defaults to show post
|
||||||
|
const show = Selectors.shouldShowJoinLeaveMessages(state);
|
||||||
|
expect(show).toEqual(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('shouldShowUnreadsCategory', () => {
|
describe('shouldShowUnreadsCategory', () => {
|
||||||
test('should return value from the preference if set', () => {
|
test('should return value from the preference if set', () => {
|
||||||
const state = {
|
const state = {
|
||||||
|
@ -8,7 +8,7 @@ import type {GlobalState} from '@mattermost/types/store';
|
|||||||
import {General, Preferences} from 'mattermost-redux/constants';
|
import {General, Preferences} from 'mattermost-redux/constants';
|
||||||
import {createSelector} from 'mattermost-redux/selectors/create_selector';
|
import {createSelector} from 'mattermost-redux/selectors/create_selector';
|
||||||
import {getConfig, getFeatureFlagValue, getLicense} from 'mattermost-redux/selectors/entities/general';
|
import {getConfig, getFeatureFlagValue, getLicense} from 'mattermost-redux/selectors/entities/general';
|
||||||
import {createShallowSelector} from 'mattermost-redux/utils/helpers';
|
import {createIdsSelector, createShallowSelector} from 'mattermost-redux/utils/helpers';
|
||||||
import {getPreferenceKey} from 'mattermost-redux/utils/preference_utils';
|
import {getPreferenceKey} from 'mattermost-redux/utils/preference_utils';
|
||||||
import {setThemeDefaults} from 'mattermost-redux/utils/theme_utils';
|
import {setThemeDefaults} from 'mattermost-redux/utils/theme_utils';
|
||||||
|
|
||||||
@ -20,19 +20,18 @@ export function getUserPreferences(state: GlobalState, userID: string): Preferen
|
|||||||
return state.entities.preferences.userPreferences[userID];
|
return state.entities.preferences.userPreferences[userID];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function get(state: GlobalState, category: string, name: string, defaultValue: any = '', preferences?: PreferencesType) {
|
function getPreferenceObject(state: GlobalState, category: string, name: string): PreferenceType | undefined {
|
||||||
|
return getMyPreferences(state)[getPreferenceKey(category, name)];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function get(state: GlobalState, category: string, name: string, defaultValue = '', preferences?: PreferencesType): string {
|
||||||
if (preferences) {
|
if (preferences) {
|
||||||
return getFromPreferences(preferences, category, name, defaultValue);
|
return getFromPreferences(preferences, category, name, defaultValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
const key = getPreferenceKey(category, name);
|
const pref = getPreferenceObject(state, category, name);
|
||||||
const prefs = getMyPreferences(state);
|
|
||||||
|
|
||||||
if (!(key in prefs)) {
|
return pref ? pref.value : defaultValue;
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
return prefs[key].value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getFromPreferences(preferences: PreferencesType, category: string, name: string, defaultValue: any = '') {
|
export function getFromPreferences(preferences: PreferencesType, category: string, name: string, defaultValue: any = '') {
|
||||||
@ -51,16 +50,15 @@ export function getBool(state: GlobalState, category: string, name: string, defa
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getInt(state: GlobalState, category: string, name: string, defaultValue = 0, userPreferences?: PreferencesType): number {
|
export function getInt(state: GlobalState, category: string, name: string, defaultValue = 0, userPreferences?: PreferencesType): number {
|
||||||
const value = get(state, category, name, defaultValue, userPreferences);
|
const value = get(state, category, name, String(defaultValue), userPreferences);
|
||||||
return parseInt(value, 10);
|
return parseInt(value, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function makeGetCategory(): (state: GlobalState, category: string) => PreferenceType[] {
|
export function makeGetCategory(selectorName: string, category: string): (state: GlobalState) => PreferenceType[] {
|
||||||
return createSelector(
|
return createIdsSelector(
|
||||||
'makeGetCategory',
|
selectorName,
|
||||||
getMyPreferences,
|
getMyPreferences,
|
||||||
(state: GlobalState, category: string) => category,
|
(preferences) => {
|
||||||
(preferences, category) => {
|
|
||||||
const prefix = category + '--';
|
const prefix = category + '--';
|
||||||
const prefsInCategory: PreferenceType[] = [];
|
const prefsInCategory: PreferenceType[] = [];
|
||||||
|
|
||||||
@ -75,12 +73,11 @@ export function makeGetCategory(): (state: GlobalState, category: string) => Pre
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function makeGetUserCategory(userID: string): (state: GlobalState, category: string) => PreferenceType[] {
|
export function makeGetUserCategory(selectorName: string, category: string): (state: GlobalState, userID: string) => PreferenceType[] {
|
||||||
return createSelector(
|
return createIdsSelector(
|
||||||
'makeGetCategory',
|
selectorName,
|
||||||
(state) => getUserPreferences(state, userID),
|
(state: GlobalState, userID: string) => getUserPreferences(state, userID),
|
||||||
(state: GlobalState, category: string) => category,
|
(preferences) => {
|
||||||
(preferences, category) => {
|
|
||||||
const prefix = category + '--';
|
const prefix = category + '--';
|
||||||
const prefsInCategory: PreferenceType[] = [];
|
const prefsInCategory: PreferenceType[] = [];
|
||||||
|
|
||||||
@ -95,28 +92,18 @@ export function makeGetUserCategory(userID: string): (state: GlobalState, catego
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const getDirectShowCategory = makeGetCategory();
|
export const getDirectShowPreferences = makeGetCategory('getDirectShowPreferences', Preferences.CATEGORY_DIRECT_CHANNEL_SHOW);
|
||||||
|
export const getGroupShowPreferences = makeGetCategory('getGroupShowPreferences', Preferences.CATEGORY_GROUP_CHANNEL_SHOW);
|
||||||
export function getDirectShowPreferences(state: GlobalState) {
|
|
||||||
return getDirectShowCategory(state, Preferences.CATEGORY_DIRECT_CHANNEL_SHOW);
|
|
||||||
}
|
|
||||||
|
|
||||||
const getGroupShowCategory = makeGetCategory();
|
|
||||||
|
|
||||||
export function getGroupShowPreferences(state: GlobalState) {
|
|
||||||
return getGroupShowCategory(state, Preferences.CATEGORY_GROUP_CHANNEL_SHOW);
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getTeammateNameDisplaySetting: (state: GlobalState) => string = createSelector(
|
export const getTeammateNameDisplaySetting: (state: GlobalState) => string = createSelector(
|
||||||
'getTeammateNameDisplaySetting',
|
'getTeammateNameDisplaySetting',
|
||||||
getConfig,
|
getConfig,
|
||||||
getMyPreferences,
|
(state) => getPreferenceObject(state, Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.NAME_NAME_FORMAT),
|
||||||
getLicense,
|
getLicense,
|
||||||
(config, preferences, license) => {
|
(config, teammateNameDisplayPreference, license) => {
|
||||||
const useAdminTeammateNameDisplaySetting = (license && license.LockTeammateNameDisplay === 'true') && config.LockTeammateNameDisplay === 'true';
|
const useAdminTeammateNameDisplaySetting = (license && license.LockTeammateNameDisplay === 'true') && config.LockTeammateNameDisplay === 'true';
|
||||||
const key = getPreferenceKey(Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.NAME_NAME_FORMAT);
|
if (teammateNameDisplayPreference && !useAdminTeammateNameDisplaySetting) {
|
||||||
if (preferences[key] && !useAdminTeammateNameDisplaySetting) {
|
return teammateNameDisplayPreference.value || '';
|
||||||
return preferences[key].value || '';
|
|
||||||
} else if (config.TeammateNameDisplay) {
|
} else if (config.TeammateNameDisplay) {
|
||||||
return config.TeammateNameDisplay;
|
return config.TeammateNameDisplay;
|
||||||
}
|
}
|
||||||
@ -124,6 +111,8 @@ export const getTeammateNameDisplaySetting: (state: GlobalState) => string = cre
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const getThemePreferences = makeGetCategory('getThemePreferences', Preferences.CATEGORY_THEME);
|
||||||
|
|
||||||
const getThemePreference = createSelector(
|
const getThemePreference = createSelector(
|
||||||
'getThemePreference',
|
'getThemePreference',
|
||||||
getMyPreferences,
|
getMyPreferences,
|
||||||
@ -218,6 +207,14 @@ export function makeGetStyleFromTheme<Style>(): (state: GlobalState, getStyleFro
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function shouldShowJoinLeaveMessages(state: GlobalState) {
|
||||||
|
const config = getConfig(state);
|
||||||
|
const enableJoinLeaveMessage = config.EnableJoinLeaveMessageByDefault === 'true';
|
||||||
|
|
||||||
|
// This setting is true or not set if join/leave messages are to be displayed
|
||||||
|
return getBool(state, Preferences.CATEGORY_ADVANCED_SETTINGS, Preferences.ADVANCED_FILTER_JOIN_LEAVE, enableJoinLeaveMessage);
|
||||||
|
}
|
||||||
|
|
||||||
// shouldShowUnreadsCategory returns true if the user has unereads grouped separately with the new sidebar enabled.
|
// shouldShowUnreadsCategory returns true if the user has unereads grouped separately with the new sidebar enabled.
|
||||||
export const shouldShowUnreadsCategory: (state: GlobalState, userPreferences?: PreferencesType) => boolean = createSelector(
|
export const shouldShowUnreadsCategory: (state: GlobalState, userPreferences?: PreferencesType) => boolean = createSelector(
|
||||||
'shouldShowUnreadsCategory',
|
'shouldShowUnreadsCategory',
|
||||||
@ -336,3 +333,5 @@ export function moveThreadsEnabled(state: GlobalState): boolean {
|
|||||||
export function streamlinedMarketplaceEnabled(state: GlobalState): boolean {
|
export function streamlinedMarketplaceEnabled(state: GlobalState): boolean {
|
||||||
return getFeatureFlagValue(state, 'StreamlinedMarketplace') === 'true';
|
return getFeatureFlagValue(state, 'StreamlinedMarketplace') === 'true';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const getOverageBannerPreferences = makeGetCategory('getOverageBannerPreferences', Preferences.CATEGORY_OVERAGE_USERS_BANNER);
|
||||||
|
@ -23,7 +23,6 @@ import {
|
|||||||
makeGenerateCombinedPost,
|
makeGenerateCombinedPost,
|
||||||
extractUserActivityData,
|
extractUserActivityData,
|
||||||
START_OF_NEW_MESSAGES,
|
START_OF_NEW_MESSAGES,
|
||||||
shouldShowJoinLeaveMessages,
|
|
||||||
} from './post_list';
|
} from './post_list';
|
||||||
|
|
||||||
import TestHelper from '../../test/test_helper';
|
import TestHelper from '../../test/test_helper';
|
||||||
@ -1688,95 +1687,3 @@ describe('combineUserActivityData', () => {
|
|||||||
expect(combineUserActivitySystemPost(posts)).toEqual(expectedOutput);
|
expect(combineUserActivitySystemPost(posts)).toEqual(expectedOutput);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('shouldShowJoinLeaveMessages', () => {
|
|
||||||
it('should default to true', () => {
|
|
||||||
const state = {
|
|
||||||
entities: {
|
|
||||||
general: {
|
|
||||||
config: {
|
|
||||||
EnableJoinLeaveMessageByDefault: 'true',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
preferences: {
|
|
||||||
myPreferences: {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} as unknown as GlobalState;
|
|
||||||
|
|
||||||
// Defaults to show post
|
|
||||||
const show = shouldShowJoinLeaveMessages(state);
|
|
||||||
expect(show).toEqual(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('set config to false, return false', () => {
|
|
||||||
const state = {
|
|
||||||
entities: {
|
|
||||||
general: {
|
|
||||||
config: {
|
|
||||||
EnableJoinLeaveMessageByDefault: 'false',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
preferences: {
|
|
||||||
myPreferences: {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} as unknown as GlobalState;
|
|
||||||
|
|
||||||
// Defaults to show post
|
|
||||||
const show = shouldShowJoinLeaveMessages(state);
|
|
||||||
expect(show).toEqual(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('if user preference, set default wont be used', () => {
|
|
||||||
const state = {
|
|
||||||
entities: {
|
|
||||||
general: {
|
|
||||||
config: {
|
|
||||||
EnableJoinLeaveMessageByDefault: 'false',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
preferences: {
|
|
||||||
myPreferences: {
|
|
||||||
[getPreferenceKey(Preferences.CATEGORY_ADVANCED_SETTINGS, Preferences.ADVANCED_FILTER_JOIN_LEAVE)]: {
|
|
||||||
category: Preferences.CATEGORY_ADVANCED_SETTINGS,
|
|
||||||
name: Preferences.ADVANCED_FILTER_JOIN_LEAVE,
|
|
||||||
value: 'true',
|
|
||||||
},
|
|
||||||
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} as unknown as GlobalState;
|
|
||||||
|
|
||||||
// Defaults to show post
|
|
||||||
const show = shouldShowJoinLeaveMessages(state);
|
|
||||||
expect(show).toEqual(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('if user preference, set default wont be used', () => {
|
|
||||||
const state = {
|
|
||||||
entities: {
|
|
||||||
general: {
|
|
||||||
config: {
|
|
||||||
EnableJoinLeaveMessageByDefault: 'true',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
preferences: {
|
|
||||||
myPreferences: {
|
|
||||||
[getPreferenceKey(Preferences.CATEGORY_ADVANCED_SETTINGS, Preferences.ADVANCED_FILTER_JOIN_LEAVE)]: {
|
|
||||||
category: Preferences.CATEGORY_ADVANCED_SETTINGS,
|
|
||||||
name: Preferences.ADVANCED_FILTER_JOIN_LEAVE,
|
|
||||||
value: 'false',
|
|
||||||
},
|
|
||||||
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} as unknown as GlobalState;
|
|
||||||
|
|
||||||
// Defaults to show post
|
|
||||||
const show = shouldShowJoinLeaveMessages(state);
|
|
||||||
expect(show).toEqual(false);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
@ -6,12 +6,11 @@ import moment from 'moment-timezone';
|
|||||||
import type {ActivityEntry, Post} from '@mattermost/types/posts';
|
import type {ActivityEntry, Post} from '@mattermost/types/posts';
|
||||||
import type {GlobalState} from '@mattermost/types/store';
|
import type {GlobalState} from '@mattermost/types/store';
|
||||||
|
|
||||||
import {Posts, Preferences} from 'mattermost-redux/constants';
|
import {Posts} from 'mattermost-redux/constants';
|
||||||
import {createSelector} from 'mattermost-redux/selectors/create_selector';
|
import {createSelector} from 'mattermost-redux/selectors/create_selector';
|
||||||
import {getConfig} from 'mattermost-redux/selectors/entities/general';
|
|
||||||
import {makeGetPostsForIds} from 'mattermost-redux/selectors/entities/posts';
|
import {makeGetPostsForIds} from 'mattermost-redux/selectors/entities/posts';
|
||||||
import type {UserActivityPost} from 'mattermost-redux/selectors/entities/posts';
|
import type {UserActivityPost} from 'mattermost-redux/selectors/entities/posts';
|
||||||
import {getBool} from 'mattermost-redux/selectors/entities/preferences';
|
import {shouldShowJoinLeaveMessages} from 'mattermost-redux/selectors/entities/preferences';
|
||||||
import {getCurrentUser} from 'mattermost-redux/selectors/entities/users';
|
import {getCurrentUser} from 'mattermost-redux/selectors/entities/users';
|
||||||
import {createIdsSelector, memoizeResult} from 'mattermost-redux/utils/helpers';
|
import {createIdsSelector, memoizeResult} from 'mattermost-redux/utils/helpers';
|
||||||
import {isUserActivityPost, shouldFilterJoinLeavePost, isFromWebhook} from 'mattermost-redux/utils/post_utils';
|
import {isUserActivityPost, shouldFilterJoinLeavePost, isFromWebhook} from 'mattermost-redux/utils/post_utils';
|
||||||
@ -23,14 +22,6 @@ export const DATE_LINE = 'date-';
|
|||||||
export const START_OF_NEW_MESSAGES = 'start-of-new-messages-';
|
export const START_OF_NEW_MESSAGES = 'start-of-new-messages-';
|
||||||
export const MAX_COMBINED_SYSTEM_POSTS = 100;
|
export const MAX_COMBINED_SYSTEM_POSTS = 100;
|
||||||
|
|
||||||
export function shouldShowJoinLeaveMessages(state: GlobalState) {
|
|
||||||
const config = getConfig(state);
|
|
||||||
const enableJoinLeaveMessage = config.EnableJoinLeaveMessageByDefault === 'true';
|
|
||||||
|
|
||||||
// This setting is true or not set if join/leave messages are to be displayed
|
|
||||||
return getBool(state, Preferences.CATEGORY_ADVANCED_SETTINGS, Preferences.ADVANCED_FILTER_JOIN_LEAVE, enableJoinLeaveMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
interface PostFilterOptions {
|
interface PostFilterOptions {
|
||||||
postIds: string[];
|
postIds: string[];
|
||||||
lastViewedAt: number;
|
lastViewedAt: number;
|
||||||
|
@ -3,24 +3,14 @@
|
|||||||
|
|
||||||
import type {Channel} from '@mattermost/types/channels';
|
import type {Channel} from '@mattermost/types/channels';
|
||||||
import type {Post, PostType, PostMetadata, PostEmbed} from '@mattermost/types/posts';
|
import type {Post, PostType, PostMetadata, PostEmbed} from '@mattermost/types/posts';
|
||||||
import type {PreferenceType} from '@mattermost/types/preferences';
|
|
||||||
import type {GlobalState} from '@mattermost/types/store';
|
import type {GlobalState} from '@mattermost/types/store';
|
||||||
import type {Team} from '@mattermost/types/teams';
|
import type {Team} from '@mattermost/types/teams';
|
||||||
import type {UserProfile} from '@mattermost/types/users';
|
import type {UserProfile} from '@mattermost/types/users';
|
||||||
|
|
||||||
import {haveIChannelPermission} from 'mattermost-redux/selectors/entities/roles';
|
import {haveIChannelPermission} from 'mattermost-redux/selectors/entities/roles';
|
||||||
|
|
||||||
import {getPreferenceKey} from './preference_utils';
|
|
||||||
|
|
||||||
import {Posts, Preferences, Permissions} from '../constants';
|
import {Posts, Preferences, Permissions} from '../constants';
|
||||||
|
|
||||||
export function isPostFlagged(postId: Post['id'], myPreferences: {
|
|
||||||
[x: string]: PreferenceType;
|
|
||||||
}): boolean {
|
|
||||||
const key = getPreferenceKey(Preferences.CATEGORY_FLAGGED_POST, postId);
|
|
||||||
return myPreferences.hasOwnProperty(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isSystemMessage(post: Post): boolean {
|
export function isSystemMessage(post: Post): boolean {
|
||||||
return Boolean(post.type && post.type.startsWith(Posts.SYSTEM_MESSAGE_PREFIX));
|
return Boolean(post.type && post.type.startsWith(Posts.SYSTEM_MESSAGE_PREFIX));
|
||||||
}
|
}
|
||||||
|
@ -1,18 +0,0 @@
|
|||||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
||||||
// See LICENSE.txt for license information.
|
|
||||||
|
|
||||||
import {Preferences} from 'mattermost-redux/constants';
|
|
||||||
import {get} from 'mattermost-redux/selectors/entities/preferences';
|
|
||||||
|
|
||||||
import {getIsMobileView} from 'selectors/views/browser';
|
|
||||||
|
|
||||||
import type {GlobalState} from 'types/store';
|
|
||||||
|
|
||||||
export function showActionsDropdownPulsatingDot(state: GlobalState): boolean {
|
|
||||||
if (getIsMobileView(state)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const actionsMenuTutorialState = get(state, Preferences.CATEGORY_ACTIONS_MENU, Preferences.NAME_ACTIONS_MENU_TUTORIAL_STATE, false);
|
|
||||||
const modalAlreadyViewed = actionsMenuTutorialState && JSON.parse(actionsMenuTutorialState)[Preferences.ACTIONS_MENU_VIEWED];
|
|
||||||
return !modalAlreadyViewed;
|
|
||||||
}
|
|
@ -2,7 +2,7 @@
|
|||||||
// See LICENSE.txt for license information.
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
import {createSelector} from 'mattermost-redux/selectors/create_selector';
|
import {createSelector} from 'mattermost-redux/selectors/create_selector';
|
||||||
import {makeGetCategory, getBool} from 'mattermost-redux/selectors/entities/preferences';
|
import {get as getString, getBool, makeGetCategory} from 'mattermost-redux/selectors/entities/preferences';
|
||||||
import {getCurrentUser, isFirstAdmin} from 'mattermost-redux/selectors/entities/users';
|
import {getCurrentUser, isFirstAdmin} from 'mattermost-redux/selectors/entities/users';
|
||||||
|
|
||||||
import {getIsMobileView} from 'selectors/views/browser';
|
import {getIsMobileView} from 'selectors/views/browser';
|
||||||
@ -13,21 +13,8 @@ import {RecommendedNextStepsLegacy, Preferences} from 'utils/constants';
|
|||||||
|
|
||||||
import type {GlobalState} from 'types/store';
|
import type {GlobalState} from 'types/store';
|
||||||
|
|
||||||
const getABTestCategory = makeGetCategory();
|
|
||||||
export const getABTestPreferences = (() => {
|
|
||||||
return (state: GlobalState) => getABTestCategory(state, Preferences.AB_TEST_PREFERENCE_VALUE);
|
|
||||||
})();
|
|
||||||
|
|
||||||
const getFirstChannelNamePref = createSelector(
|
|
||||||
'getFirstChannelNamePref',
|
|
||||||
getABTestPreferences,
|
|
||||||
(preferences) => {
|
|
||||||
return preferences.find((pref) => pref.name === RecommendedNextStepsLegacy.CREATE_FIRST_CHANNEL);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
export function getFirstChannelName(state: GlobalState) {
|
export function getFirstChannelName(state: GlobalState) {
|
||||||
return getFirstChannelNamePref(state)?.value || '';
|
return getString(state, Preferences.AB_TEST_PREFERENCE_VALUE, RecommendedNextStepsLegacy.CREATE_FIRST_CHANNEL, '');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getShowLaunchingWorkspace(state: GlobalState) {
|
export function getShowLaunchingWorkspace(state: GlobalState) {
|
||||||
@ -91,13 +78,13 @@ const getSteps = createSelector(
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
const getNextStepsCategory = makeGetCategory();
|
const getNextStepsPreferences = makeGetCategory('getNextStepsPreferences', Preferences.RECOMMENDED_NEXT_STEPS);
|
||||||
const getOnboardingTaskCategory = makeGetCategory();
|
export const getOnboardingTaskPreferences = makeGetCategory('getOnboardingTaskPreferences', OnboardingTaskCategory);
|
||||||
|
|
||||||
// Loop through all Steps. For each step, check that
|
// Loop through all Steps. For each step, check that
|
||||||
export const legacyNextStepsNotFinished = createSelector(
|
export const legacyNextStepsNotFinished = createSelector(
|
||||||
'legacyNextStepsNotFinished',
|
'legacyNextStepsNotFinished',
|
||||||
(state: GlobalState) => getNextStepsCategory(state, Preferences.RECOMMENDED_NEXT_STEPS),
|
getNextStepsPreferences,
|
||||||
(state: GlobalState) => getCurrentUser(state),
|
(state: GlobalState) => getCurrentUser(state),
|
||||||
(state: GlobalState) => isFirstAdmin(state),
|
(state: GlobalState) => isFirstAdmin(state),
|
||||||
(state: GlobalState) => getSteps(state),
|
(state: GlobalState) => getSteps(state),
|
||||||
@ -111,7 +98,7 @@ export const legacyNextStepsNotFinished = createSelector(
|
|||||||
// Loop through all Steps. For each step, check that
|
// Loop through all Steps. For each step, check that
|
||||||
export const hasLegacyNextStepsPreferences = createSelector(
|
export const hasLegacyNextStepsPreferences = createSelector(
|
||||||
'hasLegacyNextStepsPreferences',
|
'hasLegacyNextStepsPreferences',
|
||||||
(state: GlobalState) => getNextStepsCategory(state, Preferences.RECOMMENDED_NEXT_STEPS),
|
getNextStepsPreferences,
|
||||||
(state: GlobalState) => getSteps(state),
|
(state: GlobalState) => getSteps(state),
|
||||||
(stepPreferences, mySteps) => {
|
(stepPreferences, mySteps) => {
|
||||||
const checkPref = (step: StepType) => stepPreferences.some((pref) => (pref.name === step.id));
|
const checkPref = (step: StepType) => stepPreferences.some((pref) => (pref.name === step.id));
|
||||||
@ -121,8 +108,8 @@ export const hasLegacyNextStepsPreferences = createSelector(
|
|||||||
|
|
||||||
export const getShowTaskListBool = createSelector(
|
export const getShowTaskListBool = createSelector(
|
||||||
'getShowTaskListBool',
|
'getShowTaskListBool',
|
||||||
(state: GlobalState) => getOnboardingTaskCategory(state, OnboardingTaskCategory),
|
getOnboardingTaskPreferences,
|
||||||
(state: GlobalState) => getNextStepsCategory(state, Preferences.RECOMMENDED_NEXT_STEPS),
|
getNextStepsPreferences,
|
||||||
getIsMobileView,
|
getIsMobileView,
|
||||||
(state: GlobalState) => getBool(state, OnboardingTaskCategory, OnboardingTaskList.ONBOARDING_TASK_LIST_SHOW),
|
(state: GlobalState) => getBool(state, OnboardingTaskCategory, OnboardingTaskList.ONBOARDING_TASK_LIST_SHOW),
|
||||||
(state: GlobalState) => hasLegacyNextStepsPreferences(state),
|
(state: GlobalState) => hasLegacyNextStepsPreferences(state),
|
||||||
|
@ -103,7 +103,6 @@ export const Preferences = {
|
|||||||
UNREAD_SCROLL_POSITION_START_FROM_LEFT: 'start_from_left_off',
|
UNREAD_SCROLL_POSITION_START_FROM_LEFT: 'start_from_left_off',
|
||||||
UNREAD_SCROLL_POSITION_START_FROM_NEWEST: 'start_from_newest',
|
UNREAD_SCROLL_POSITION_START_FROM_NEWEST: 'start_from_newest',
|
||||||
CATEGORY_THEME: 'theme',
|
CATEGORY_THEME: 'theme',
|
||||||
CATEGORY_FLAGGED_POST: 'flagged_post',
|
|
||||||
CATEGORY_NOTIFICATIONS: 'notifications',
|
CATEGORY_NOTIFICATIONS: 'notifications',
|
||||||
EMAIL_INTERVAL: 'email_interval',
|
EMAIL_INTERVAL: 'email_interval',
|
||||||
INTERVAL_IMMEDIATE: 30, // "immediate" is a 30 second interval
|
INTERVAL_IMMEDIATE: 30, // "immediate" is a 30 second interval
|
||||||
@ -147,7 +146,7 @@ export const Preferences = {
|
|||||||
DELINQUENCY_MODAL_CONFIRMED: 'delinquency_modal_confirmed',
|
DELINQUENCY_MODAL_CONFIRMED: 'delinquency_modal_confirmed',
|
||||||
CONFIGURATION_BANNERS: 'configuration_banners',
|
CONFIGURATION_BANNERS: 'configuration_banners',
|
||||||
NOTIFY_ADMIN_REVOKE_DOWNGRADED_WORKSPACE: 'admin_revoke_downgraded_instance',
|
NOTIFY_ADMIN_REVOKE_DOWNGRADED_WORKSPACE: 'admin_revoke_downgraded_instance',
|
||||||
OVERAGE_USERS_BANNER: 'overage_users_banner',
|
OVERAGE_USERS_BANNER: ReduxPreferences.CATEGORY_OVERAGE_USERS_BANNER,
|
||||||
TO_CLOUD_YEARLY_PLAN_NUDGE: 'to_cloud_yearly_plan_nudge',
|
TO_CLOUD_YEARLY_PLAN_NUDGE: 'to_cloud_yearly_plan_nudge',
|
||||||
TO_PAID_PLAN_NUDGE: 'to_paid_plan_nudge',
|
TO_PAID_PLAN_NUDGE: 'to_paid_plan_nudge',
|
||||||
CLOUD_ANNUAL_RENEWAL_BANNER: 'cloud_annual_renewal_banner',
|
CLOUD_ANNUAL_RENEWAL_BANNER: 'cloud_annual_renewal_banner',
|
||||||
|
@ -21,8 +21,8 @@ import {createSelector} from 'mattermost-redux/selectors/create_selector';
|
|||||||
import {getChannel} from 'mattermost-redux/selectors/entities/channels';
|
import {getChannel} from 'mattermost-redux/selectors/entities/channels';
|
||||||
import {getConfig} from 'mattermost-redux/selectors/entities/general';
|
import {getConfig} from 'mattermost-redux/selectors/entities/general';
|
||||||
import {getAllGroupsForReferenceByName} from 'mattermost-redux/selectors/entities/groups';
|
import {getAllGroupsForReferenceByName} from 'mattermost-redux/selectors/entities/groups';
|
||||||
import {makeGetReactionsForPost} from 'mattermost-redux/selectors/entities/posts';
|
import {isPostFlagged, makeGetReactionsForPost} from 'mattermost-redux/selectors/entities/posts';
|
||||||
import {get, getTeammateNameDisplaySetting, isCollapsedThreadsEnabled} from 'mattermost-redux/selectors/entities/preferences';
|
import {getTeammateNameDisplaySetting, isCollapsedThreadsEnabled} from 'mattermost-redux/selectors/entities/preferences';
|
||||||
import {haveIChannelPermission} from 'mattermost-redux/selectors/entities/roles';
|
import {haveIChannelPermission} from 'mattermost-redux/selectors/entities/roles';
|
||||||
import {getCurrentTeamId, getTeam} from 'mattermost-redux/selectors/entities/teams';
|
import {getCurrentTeamId, getTeam} from 'mattermost-redux/selectors/entities/teams';
|
||||||
import {makeGetDisplayName, getCurrentUserId, getUser, getUsersByUsername} from 'mattermost-redux/selectors/entities/users';
|
import {makeGetDisplayName, getCurrentUserId, getUser, getUsersByUsername} from 'mattermost-redux/selectors/entities/users';
|
||||||
@ -36,7 +36,7 @@ import {displayUsername} from 'mattermost-redux/utils/user_utils';
|
|||||||
import {getEmojiMap} from 'selectors/emojis';
|
import {getEmojiMap} from 'selectors/emojis';
|
||||||
import {getIsMobileView} from 'selectors/views/browser';
|
import {getIsMobileView} from 'selectors/views/browser';
|
||||||
|
|
||||||
import Constants, {PostListRowListIds, Preferences} from 'utils/constants';
|
import Constants, {PostListRowListIds} from 'utils/constants';
|
||||||
import * as Keyboard from 'utils/keyboard';
|
import * as Keyboard from 'utils/keyboard';
|
||||||
import {formatWithRenderer} from 'utils/markdown';
|
import {formatWithRenderer} from 'utils/markdown';
|
||||||
import MentionableRenderer from 'utils/markdown/mentionable_renderer';
|
import MentionableRenderer from 'utils/markdown/mentionable_renderer';
|
||||||
@ -471,8 +471,8 @@ export function usePostAriaLabel(post: Post | undefined) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const authorDisplayName = getDisplayName(state, post.user_id);
|
const authorDisplayName = getDisplayName(state, post.user_id);
|
||||||
const reactions = getReactionsForPost(state, post?.id);
|
const reactions = getReactionsForPost(state, post.id);
|
||||||
const isFlagged = get(state, Preferences.CATEGORY_FLAGGED_POST, post.id, null) != null;
|
const isFlagged = isPostFlagged(state, post.id);
|
||||||
const emojiMap = getEmojiMap(state);
|
const emojiMap = getEmojiMap(state);
|
||||||
const mentions = getMentionsFromMessage(state, post);
|
const mentions = getMentionsFromMessage(state, post);
|
||||||
const teammateNameDisplaySetting = getTeammateNameDisplaySetting(state);
|
const teammateNameDisplaySetting = getTeammateNameDisplaySetting(state);
|
||||||
|
@ -5,7 +5,7 @@ export type PreferenceType = {
|
|||||||
category: string;
|
category: string;
|
||||||
name: string;
|
name: string;
|
||||||
user_id: string;
|
user_id: string;
|
||||||
value?: string;
|
value: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type PreferencesType = {
|
export type PreferencesType = {
|
||||||
|
Loading…
Reference in New Issue
Block a user