UNPKG

mattermost-redux

Version:

Common code (API client, Redux stores, logic, utility functions) for building a Mattermost client

266 lines (219 loc) 9.4 kB
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. import {createSelector} from 'reselect'; import {General, Preferences} from '../../constants'; import {getConfig, getLicense} from 'selectors/entities/general'; import {getCurrentTeamId} from 'selectors/entities/teams'; import {PreferenceType, Theme} from 'types/preferences'; import {UserProfile} from 'types/users'; import {GlobalState} from 'types/store'; import {$ID} from 'types/utilities'; import {createShallowSelector} from 'utils/helpers'; import {getPreferenceKey} from 'utils/preference_utils'; export function getMyPreferences(state: GlobalState) { return state.entities.preferences.myPreferences; } export function get(state: GlobalState, category: string, name: string, defaultValue: any = '') { const key = getPreferenceKey(category, name); const prefs = getMyPreferences(state); if (!(key in prefs)) { return defaultValue; } return prefs[key].value; } export function getBool(state: GlobalState, category: string, name: string, defaultValue = false) { const value = get(state, category, name, String(defaultValue)); return value !== 'false'; } export function getInt(state: GlobalState, category: string, name: string, defaultValue = 0) { const value = get(state, category, name, defaultValue); return parseInt(value, 10); } export function makeGetCategory(): (state: GlobalState, category: string) => PreferenceType[] { return createSelector( getMyPreferences, (state: GlobalState, category: string) => category, (preferences, category) => { const prefix = category + '--'; const prefsInCategory: PreferenceType[] = []; for (const key in preferences) { if (key.startsWith(prefix)) { prefsInCategory.push(preferences[key]); } } return prefsInCategory; }, ); } const getDirectShowCategory = makeGetCategory(); 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); } const getFavoritesCategory = makeGetCategory(); export function getFavoritesPreferences(state: GlobalState) { const favorites = getFavoritesCategory(state, Preferences.CATEGORY_FAVORITE_CHANNEL); return favorites.filter((f) => f.value === 'true').map((f) => f.name); } export const getVisibleTeammate: (state: GlobalState) => Array<$ID<UserProfile>> = createSelector( getDirectShowPreferences, (direct) => { return direct.filter((dm) => dm.value === 'true' && dm.name).map((dm) => dm.name); }, ); export const getVisibleGroupIds: (state: GlobalState) => string[] = createSelector( getGroupShowPreferences, (groups) => { return groups.filter((dm) => dm.value === 'true' && dm.name).map((dm) => dm.name); }, ); export const getTeammateNameDisplaySetting: (state: GlobalState) => string | undefined = createSelector( getConfig, getMyPreferences, getLicense, (config, preferences, license) => { const useAdminTeammateNameDisplaySetting = (license && license.LockTeammateNameDisplay === 'true') && config.LockTeammateNameDisplay === 'true'; const key = getPreferenceKey(Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.NAME_NAME_FORMAT); if (preferences[key] && !useAdminTeammateNameDisplaySetting) { return preferences[key].value; } else if (config.TeammateNameDisplay) { return config.TeammateNameDisplay; } return General.TEAMMATE_NAME_DISPLAY.SHOW_USERNAME; }, ); const getThemePreference = createSelector( getMyPreferences, getCurrentTeamId, (myPreferences, currentTeamId) => { // Prefer the user's current team-specific theme over the user's current global theme let themePreference; if (currentTeamId) { themePreference = myPreferences[getPreferenceKey(Preferences.CATEGORY_THEME, currentTeamId)]; } if (!themePreference) { themePreference = myPreferences[getPreferenceKey(Preferences.CATEGORY_THEME, '')]; } return themePreference; }, ); const getDefaultTheme = createSelector(getConfig, (config): Theme => { if (config.DefaultTheme && config.DefaultTheme in Preferences.THEMES) { const theme: Theme = Preferences.THEMES[config.DefaultTheme]; if (theme) { return theme; } } // If no config.DefaultTheme or value doesn't refer to a valid theme name... return Preferences.THEMES.default; }); export const getTheme: (state: GlobalState) => Theme = createShallowSelector( getThemePreference, getDefaultTheme, (themePreference, defaultTheme): Theme => { const themeValue: Theme | string = themePreference?.value ?? defaultTheme; // A custom theme will be a JSON-serialized object stored in a preference // At this point, the theme should be a plain object const theme: Theme = typeof themeValue === 'string' ? JSON.parse(themeValue) : themeValue; // If this is a system theme, find it in case the user's theme is missing any fields if (theme.type && theme.type !== 'custom') { const match = Object.values(Preferences.THEMES).find((v) => v.type === theme.type); if (match) { if (!match.mentionBg) { match.mentionBg = match.mentionBj; } return match; } } for (const key of Object.keys(defaultTheme)) { if (theme[key]) { // Fix a case where upper case theme colours are rendered as black theme[key] = theme[key]?.toLowerCase(); } } // Backwards compatability with old name if (!theme.mentionBg) { theme.mentionBg = theme.mentionBj; } return Object.assign({}, defaultTheme, theme); }, ); export function makeGetStyleFromTheme<Style>(): (state: GlobalState, getStyleFromTheme: (theme: Theme) => Style) => Style { return createSelector( getTheme, (state: GlobalState, getStyleFromTheme: (theme: Theme) => Style) => getStyleFromTheme, (theme, getStyleFromTheme) => { return getStyleFromTheme(theme); }, ); } export type SidebarPreferences = { grouping: 'by_type' | 'none'; unreads_at_top: 'true' | 'false'; favorite_at_top: 'true' | 'false'; sorting: 'alpha' | 'recent'; } const defaultSidebarPrefs: SidebarPreferences = { grouping: 'by_type', unreads_at_top: 'true', favorite_at_top: 'true', sorting: 'alpha', }; export const getSidebarPreferences: (state: GlobalState) => SidebarPreferences = createSelector( (state: GlobalState) => { const config = getConfig(state); return config.ExperimentalGroupUnreadChannels !== General.DISABLED && getBool( state, Preferences.CATEGORY_SIDEBAR_SETTINGS, 'show_unread_section', config.ExperimentalGroupUnreadChannels === General.DEFAULT_ON, ); }, (state) => { return get( state, Preferences.CATEGORY_SIDEBAR_SETTINGS, '', null, ); }, (showUnreadSection, sidebarPreference) => { let sidebarPrefs = JSON.parse(sidebarPreference); if (sidebarPrefs === null) { // Support unread settings for old implementation sidebarPrefs = { ...defaultSidebarPrefs, unreads_at_top: showUnreadSection ? 'true' : 'false', }; } return sidebarPrefs; }, ); // shouldShowUnreadsCategory returns true if the user has unereads grouped separately with the new sidebar enabled. export const shouldShowUnreadsCategory: (state: GlobalState) => boolean = createSelector( (state: GlobalState) => get(state, Preferences.CATEGORY_SIDEBAR_SETTINGS, Preferences.SHOW_UNREAD_SECTION), (state: GlobalState) => get(state, Preferences.CATEGORY_SIDEBAR_SETTINGS, ''), (state: GlobalState) => getConfig(state).ExperimentalGroupUnreadChannels, (userPreference, oldUserPreference, serverDefault) => { // Prefer the show_unread_section user preference over the previous version if (userPreference) { return userPreference === 'true'; } if (oldUserPreference) { return JSON.parse(oldUserPreference).unreads_at_top === 'true'; } // The user setting is not set, so use the system default return serverDefault === General.DEFAULT_ON; }, ); export function shouldAutocloseDMs(state: GlobalState) { const config = getConfig(state); if (!config.CloseUnusedDirectMessages || config.CloseUnusedDirectMessages === 'false') { return false; } const preference = get(state, Preferences.CATEGORY_SIDEBAR_SETTINGS, Preferences.CHANNEL_SIDEBAR_AUTOCLOSE_DMS, Preferences.AUTOCLOSE_DMS_ENABLED); return preference === Preferences.AUTOCLOSE_DMS_ENABLED; }