Mm 52993 - expose enable user statuses to client (#25455)

* MM-52993_expose enable user statuses to client and prevent statuses fetch when disabled

* modify the logic, add selector, add unit tests

* implement PR feedback

* fix unit tests

* remove client console warnings

* remove another unnecessary call if the flag is disabled

* fix merge conflicts
Этот коммит содержится в:
Pablo Vélez
2024-02-07 15:39:19 +01:00
коммит произвёл GitHub
родитель 03f71c9c84
Коммит 2e40ede7dd
16 изменённых файлов: 176 добавлений и 24 удалений

Просмотреть файл

@@ -284,6 +284,7 @@ func GenerateLimitedClientConfig(c *model.Config, telemetryID string, license *m
props["DefaultClientLocale"] = *c.LocalizationSettings.DefaultClientLocale props["DefaultClientLocale"] = *c.LocalizationSettings.DefaultClientLocale
props["EnableCustomEmoji"] = strconv.FormatBool(*c.ServiceSettings.EnableCustomEmoji) props["EnableCustomEmoji"] = strconv.FormatBool(*c.ServiceSettings.EnableCustomEmoji)
props["EnableUserStatuses"] = strconv.FormatBool(*c.ServiceSettings.EnableUserStatuses)
props["AppDownloadLink"] = *c.NativeAppSettings.AppDownloadLink props["AppDownloadLink"] = *c.NativeAppSettings.AppDownloadLink
props["AndroidAppDownloadLink"] = *c.NativeAppSettings.AndroidAppDownloadLink props["AndroidAppDownloadLink"] = *c.NativeAppSettings.AndroidAppDownloadLink
props["IosAppDownloadLink"] = *c.NativeAppSettings.IosAppDownloadLink props["IosAppDownloadLink"] = *c.NativeAppSettings.IosAppDownloadLink

Просмотреть файл

@@ -240,6 +240,19 @@ func TestGetClientConfig(t *testing.T) {
"ExperimentalSharedChannels": "true", "ExperimentalSharedChannels": "true",
}, },
}, },
{
"disable EnableUserStatuses",
&model.Config{
ServiceSettings: model.ServiceSettings{
EnableUserStatuses: model.NewBool(false),
},
},
"",
nil,
map[string]string{
"EnableUserStatuses": "false",
},
},
{ {
"Shared channels enterprise license", "Shared channels enterprise license",
&model.Config{ &model.Config{

Просмотреть файл

@@ -44,6 +44,7 @@ describe('actions/status_actions', () => {
config: { config: {
EnableCustomEmoji: 'true', EnableCustomEmoji: 'true',
EnableCustomUserStatuses: 'true', EnableCustomUserStatuses: 'true',
EnableUserStatuses: 'true',
}, },
}, },
teams: { teams: {

Просмотреть файл

@@ -5,6 +5,7 @@ import type {UserProfile} from '@mattermost/types/users';
import {getStatusesByIds} from 'mattermost-redux/actions/users'; import {getStatusesByIds} from 'mattermost-redux/actions/users';
import {getCurrentChannelId} from 'mattermost-redux/selectors/entities/channels'; import {getCurrentChannelId} from 'mattermost-redux/selectors/entities/channels';
import {getIsUserStatusesConfigEnabled} from 'mattermost-redux/selectors/entities/common';
import {getPostsInCurrentChannel} from 'mattermost-redux/selectors/entities/posts'; import {getPostsInCurrentChannel} from 'mattermost-redux/selectors/entities/posts';
import {getDirectShowPreferences} from 'mattermost-redux/selectors/entities/preferences'; import {getDirectShowPreferences} from 'mattermost-redux/selectors/entities/preferences';
import {getCurrentUserId} from 'mattermost-redux/selectors/entities/users'; import {getCurrentUserId} from 'mattermost-redux/selectors/entities/users';
@@ -84,8 +85,11 @@ export function loadStatusesForProfilesMap(users: Record<string, UserProfile> |
} }
export function loadStatusesByIds(userIds: string[]): ActionFunc { export function loadStatusesByIds(userIds: string[]): ActionFunc {
return (dispatch) => { return (dispatch, getState) => {
if (userIds.length === 0) { const state = getState();
const enabledUserStatuses = getIsUserStatusesConfigEnabled(state);
if (userIds.length === 0 || !enabledUserStatuses) {
return {data: false}; return {data: false};
} }
@@ -98,13 +102,15 @@ export function loadStatusesByIds(userIds: string[]): ActionFunc {
export function loadProfilesMissingStatus(users: UserProfile[]): ActionFunc { export function loadProfilesMissingStatus(users: UserProfile[]): ActionFunc {
return (dispatch, getState) => { return (dispatch, getState) => {
const state = getState(); const state = getState();
const enabledUserStatuses = getIsUserStatusesConfigEnabled(state);
const statuses = state.entities.users.statuses; const statuses = state.entities.users.statuses;
const missingStatusByIds = users. const missingStatusByIds = users.
filter((user) => !statuses[user.id]). filter((user) => !statuses[user.id]).
map((user) => user.id); map((user) => user.id);
if (missingStatusByIds.length === 0) { if (missingStatusByIds.length === 0 || !enabledUserStatuses) {
return {data: false}; return {data: false};
} }

Просмотреть файл

@@ -102,7 +102,9 @@ describe('Actions.User', () => {
}, },
} as unknown as GlobalState['entities']['channels'], } as unknown as GlobalState['entities']['channels'],
general: { general: {
config: {}, config: {
EnableUserStatuses: 'true',
},
} as GlobalState['entities']['general'], } as GlobalState['entities']['general'],
preferences: { preferences: {
myPreferences: { myPreferences: {

Просмотреть файл

@@ -20,6 +20,7 @@ import {
getMyChannelMember, getMyChannelMember,
getMyChannels, getMyChannels,
} from 'mattermost-redux/selectors/entities/channels'; } from 'mattermost-redux/selectors/entities/channels';
import {getIsUserStatusesConfigEnabled} from 'mattermost-redux/selectors/entities/common';
import {getBool, isCollapsedThreadsEnabled} from 'mattermost-redux/selectors/entities/preferences'; import {getBool, isCollapsedThreadsEnabled} from 'mattermost-redux/selectors/entities/preferences';
import {getCurrentTeamId, getTeamMember} from 'mattermost-redux/selectors/entities/teams'; import {getCurrentTeamId, getTeamMember} from 'mattermost-redux/selectors/entities/teams';
import * as Selectors from 'mattermost-redux/selectors/entities/users'; import * as Selectors from 'mattermost-redux/selectors/entities/users';
@@ -423,10 +424,17 @@ export function autocompleteUsers(username: string): ThunkActionFunc<Promise<Use
export function autoResetStatus(): ActionFuncAsync<UserStatus> { export function autoResetStatus(): ActionFuncAsync<UserStatus> {
return async (doDispatch) => { return async (doDispatch) => {
const {currentUserId} = getState().entities.users; const state = getState();
const enabledUserStatuses = getIsUserStatusesConfigEnabled(state);
if (!enabledUserStatuses) {
return {data: undefined};
}
const {currentUserId} = state.entities.users;
const {data: userStatus} = await doDispatch(UserActions.getStatus(currentUserId)); const {data: userStatus} = await doDispatch(UserActions.getStatus(currentUserId));
if (userStatus!.status === UserStatuses.OUT_OF_OFFICE || !userStatus!.manual) { if (userStatus?.status === UserStatuses.OUT_OF_OFFICE || !userStatus?.manual) {
return {data: userStatus}; return {data: userStatus};
} }

Просмотреть файл

@@ -1,9 +1,20 @@
// 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 {render, act} from '@testing-library/react';
import React from 'react'; import React from 'react';
import {Provider} from 'react-redux';
import {getClassnamesForBody} from './channel_controller'; import * as actions from 'actions/status_actions';
import mockStore from 'tests/test_store';
import Constants from 'utils/constants';
import type {GlobalState} from 'types/store';
import ChannelController, {getClassnamesForBody} from './channel_controller';
let mockState: GlobalState;
jest.mock('components/reset_status_modal', () => () => <div/>); jest.mock('components/reset_status_modal', () => () => <div/>);
jest.mock('components/sidebar', () => () => <div/>); jest.mock('components/sidebar', () => () => <div/>);
@@ -13,6 +24,63 @@ jest.mock('components/unreads_status_handler', () => () => <div/>);
jest.mock('components/product_notices_modal', () => () => <div/>); jest.mock('components/product_notices_modal', () => () => <div/>);
jest.mock('plugins/pluggable', () => () => <div/>); jest.mock('plugins/pluggable', () => () => <div/>);
jest.mock('actions/status_actions', () => ({
loadStatusesForChannelAndSidebar: jest.fn().mockImplementation(() => () => {}),
}));
jest.mock('mattermost-redux/selectors/entities/general', () => ({
...jest.requireActual('mattermost-redux/selectors/entities/general') as typeof import('mattermost-redux/selectors/entities/general'),
}));
describe('ChannelController', () => {
beforeEach(() => {
mockState = {
entities: {
general: {
config: {
EnableUserStatuses: 'false',
},
},
},
} as unknown as GlobalState;
jest.useFakeTimers();
});
it('dispatches loadStatusesForChannelAndSidebar when enableUserStatuses is true', () => {
mockState.entities.general.config.EnableUserStatuses = 'true';
const store = mockStore(mockState);
render(
<Provider store={store}>
<ChannelController shouldRenderCenterChannel={true}/>
</Provider>,
);
act(() => {
jest.advanceTimersByTime(Constants.STATUS_INTERVAL);
});
expect(actions.loadStatusesForChannelAndSidebar).toHaveBeenCalled();
});
it('does not dispatch loadStatusesForChannelAndSidebar when enableUserStatuses is false', () => {
const store = mockStore(mockState);
mockState.entities.general.config.EnableUserStatuses = 'false';
render(
<Provider store={store}>
<ChannelController shouldRenderCenterChannel={true}/>
</Provider>,
);
act(() => {
jest.advanceTimersByTime(Constants.STATUS_INTERVAL);
});
expect(actions.loadStatusesForChannelAndSidebar).not.toHaveBeenCalled();
});
});
describe('components/channel_layout/ChannelController', () => { describe('components/channel_layout/ChannelController', () => {
test('Should have app__body and channel-view classes by default', () => { test('Should have app__body and channel-view classes by default', () => {
expect(getClassnamesForBody('')).toEqual(['app__body', 'channel-view']); expect(getClassnamesForBody('')).toEqual(['app__body', 'channel-view']);

Просмотреть файл

@@ -3,7 +3,9 @@
import classNames from 'classnames'; import classNames from 'classnames';
import React, {useEffect} from 'react'; import React, {useEffect} from 'react';
import {useDispatch} from 'react-redux'; import {useDispatch, useSelector} from 'react-redux';
import {getIsUserStatusesConfigEnabled} from 'mattermost-redux/selectors/entities/common';
import {loadStatusesForChannelAndSidebar} from 'actions/status_actions'; import {loadStatusesForChannelAndSidebar} from 'actions/status_actions';
@@ -25,11 +27,15 @@ type Props = {
} }
export default function ChannelController(props: Props) { export default function ChannelController(props: Props) {
const enabledUserStatuses = useSelector(getIsUserStatusesConfigEnabled);
const dispatch = useDispatch(); const dispatch = useDispatch();
useEffect(() => { useEffect(() => {
const isMsBrowser = isInternetExplorer() || isEdge(); const isMsBrowser = isInternetExplorer() || isEdge();
const platform = window.navigator.platform; const {navigator} = window;
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
const platform = navigator?.userAgentData?.platform || navigator?.platform || 'unknown';
document.body.classList.add(...getClassnamesForBody(platform, isMsBrowser)); document.body.classList.add(...getClassnamesForBody(platform, isMsBrowser));
return () => { return () => {
@@ -38,14 +44,16 @@ export default function ChannelController(props: Props) {
}, []); }, []);
useEffect(() => { useEffect(() => {
const loadStatusesIntervalId = setInterval(() => { let loadStatusesIntervalId: ReturnType<typeof setInterval>;
dispatch(loadStatusesForChannelAndSidebar()); if (enabledUserStatuses) {
}, Constants.STATUS_INTERVAL); loadStatusesIntervalId = setInterval(() => {
dispatch(loadStatusesForChannelAndSidebar());
}, Constants.STATUS_INTERVAL);
}
return () => { return () => {
clearInterval(loadStatusesIntervalId); clearInterval(loadStatusesIntervalId);
}; };
}, []); }, [dispatch, enabledUserStatuses]);
return ( return (
<> <>

Просмотреть файл

@@ -18,7 +18,9 @@ describe('handleUserTypingEvent', () => {
const initialState = { const initialState = {
entities: { entities: {
general: { general: {
config: {}, config: {
EnableUserStatuses: 'true',
},
}, },
users: { users: {
currentUserId: 'user', currentUserId: 'user',
@@ -81,6 +83,25 @@ describe('handleUserTypingEvent', () => {
expect(getStatusesByIds).toHaveBeenCalled(); expect(getStatusesByIds).toHaveBeenCalled();
}); });
test('should NOT load statuses for users if enableUserStatuses config is disabled', async () => {
const state = mergeObjects(initialState, {
entities: {
general: {
config: {
EnableUserStatuses: 'false',
},
},
},
});
const store = configureStore(state);
store.dispatch(userStartedTyping(userId, channelId, rootId, Date.now()));
// Wait for side effects to resolve
await Promise.resolve();
expect(getStatusesByIds).not.toHaveBeenCalled();
});
test('should not load statuses for users that are online', async () => { test('should not load statuses for users that are online', async () => {
const state = mergeObjects(initialState, { const state = mergeObjects(initialState, {
entities: { entities: {

Просмотреть файл

@@ -5,6 +5,7 @@ import type {GlobalState} from '@mattermost/types/store';
import {getMissingProfilesByIds, getStatusesByIds} from 'mattermost-redux/actions/users'; import {getMissingProfilesByIds, getStatusesByIds} from 'mattermost-redux/actions/users';
import {General, Preferences, WebsocketEvents} from 'mattermost-redux/constants'; import {General, Preferences, WebsocketEvents} from 'mattermost-redux/constants';
import {getIsUserStatusesConfigEnabled} from 'mattermost-redux/selectors/entities/common';
import {getConfig, isPerformanceDebuggingEnabled} from 'mattermost-redux/selectors/entities/general'; import {getConfig, isPerformanceDebuggingEnabled} from 'mattermost-redux/selectors/entities/general';
import {getBool} from 'mattermost-redux/selectors/entities/preferences'; import {getBool} from 'mattermost-redux/selectors/entities/preferences';
import {getCurrentUserId, getStatusForUserId} from 'mattermost-redux/selectors/entities/users'; import {getCurrentUserId, getStatusForUserId} from 'mattermost-redux/selectors/entities/users';
@@ -49,6 +50,7 @@ function fillInMissingInfo(userId: string): ActionFuncAsync {
return async (dispatch, getState) => { return async (dispatch, getState) => {
const state = getState(); const state = getState();
const currentUserId = getCurrentUserId(state); const currentUserId = getCurrentUserId(state);
const enabledUserStatuses = getIsUserStatusesConfigEnabled(state);
if (userId !== currentUserId) { if (userId !== currentUserId) {
const result = await dispatch(getMissingProfilesByIds([userId])); const result = await dispatch(getMissingProfilesByIds([userId]));
@@ -59,7 +61,7 @@ function fillInMissingInfo(userId: string): ActionFuncAsync {
} }
const status = getStatusForUserId(state, userId); const status = getStatusForUserId(state, userId);
if (status !== General.ONLINE) { if (status !== General.ONLINE && enabledUserStatuses) {
dispatch(getStatusesByIds([userId])); dispatch(getStatusesByIds([userId]));
} }

Просмотреть файл

@@ -174,13 +174,16 @@ export default class ResetStatusModal extends React.PureComponent<Props, State>
public componentDidMount(): void { public componentDidMount(): void {
this.props.actions.autoResetStatus().then( this.props.actions.autoResetStatus().then(
(result) => { (result) => {
if (result.data! === null) {
return;
}
const status = result.data!; const status = result.data!;
const statusIsManual = status.manual; const statusIsManual = status?.manual;
const autoResetPrefNotSet = this.props.autoResetPref === ''; const autoResetPrefNotSet = this.props.autoResetPref === '';
this.setState({ this.setState({
currentUserStatus: status, // Set in state until status refactor where we store 'manual' field in redux currentUserStatus: status, // Set in state until status refactor where we store 'manual' field in redux
show: Boolean(status.status === UserStatuses.OUT_OF_OFFICE || (statusIsManual && autoResetPrefNotSet)), show: Boolean(status?.status === UserStatuses.OUT_OF_OFFICE || (statusIsManual && autoResetPrefNotSet)),
}); });
}, },
); );
@@ -220,7 +223,7 @@ export default class ResetStatusModal extends React.PureComponent<Props, State>
}; };
public render(): JSX.Element { public render(): JSX.Element {
const userStatus = this.state.currentUserStatus.status || ''; const userStatus = this.state.currentUserStatus?.status || '';
const manualStatusTitle = messages[userStatus] ? (<FormattedMessage {...messages[userStatus].title}/>) : ''; const manualStatusTitle = messages[userStatus] ? (<FormattedMessage {...messages[userStatus].title}/>) : '';
const manualStatusMessage = this.renderModalMessage(); const manualStatusMessage = this.renderModalMessage();

Просмотреть файл

@@ -25,6 +25,7 @@ import {getProfilesByIds, getProfilesByUsernames, getStatusesByIds} from 'matter
import {Client4, DEFAULT_LIMIT_AFTER, DEFAULT_LIMIT_BEFORE} from 'mattermost-redux/client'; import {Client4, DEFAULT_LIMIT_AFTER, DEFAULT_LIMIT_BEFORE} from 'mattermost-redux/client';
import {General, Preferences, Posts} from 'mattermost-redux/constants'; import {General, Preferences, Posts} from 'mattermost-redux/constants';
import {getCurrentChannelId, getMyChannelMember as getMyChannelMemberSelector} from 'mattermost-redux/selectors/entities/channels'; import {getCurrentChannelId, getMyChannelMember as getMyChannelMemberSelector} from 'mattermost-redux/selectors/entities/channels';
import {getIsUserStatusesConfigEnabled} from 'mattermost-redux/selectors/entities/common';
import {getCustomEmojisByName as selectCustomEmojisByName} from 'mattermost-redux/selectors/entities/emojis'; import {getCustomEmojisByName as selectCustomEmojisByName} from 'mattermost-redux/selectors/entities/emojis';
import {getAllGroupsByName} from 'mattermost-redux/selectors/entities/groups'; import {getAllGroupsByName} from 'mattermost-redux/selectors/entities/groups';
import * as PostSelectors from 'mattermost-redux/selectors/entities/posts'; import * as PostSelectors from 'mattermost-redux/selectors/entities/posts';
@@ -1004,6 +1005,7 @@ export async function getMentionsAndStatusesForPosts(postsArrayOrMap: Post[]|Pos
const state = getState(); const state = getState();
const {currentUserId, profiles, statuses} = state.entities.users; const {currentUserId, profiles, statuses} = state.entities.users;
const enabledUserStatuses = getIsUserStatusesConfigEnabled(state);
// Statuses and profiles of the users who made the posts // Statuses and profiles of the users who made the posts
const userIdsToLoad = new Set<string>(); const userIdsToLoad = new Set<string>();
@@ -1053,7 +1055,7 @@ export async function getMentionsAndStatusesForPosts(postsArrayOrMap: Post[]|Pos
promises.push(dispatch(getProfilesByIds(Array.from(userIdsToLoad)))); promises.push(dispatch(getProfilesByIds(Array.from(userIdsToLoad))));
} }
if (statusesToLoad.size > 0) { if (statusesToLoad.size > 0 && enabledUserStatuses) {
promises.push(dispatch(getStatusesByIds(Array.from(statusesToLoad)))); promises.push(dispatch(getStatusesByIds(Array.from(statusesToLoad))));
} }

Просмотреть файл

@@ -16,17 +16,21 @@ import {loadRolesIfNeeded} from 'mattermost-redux/actions/roles';
import {getProfilesByIds, getStatusesByIds} from 'mattermost-redux/actions/users'; import {getProfilesByIds, getStatusesByIds} from 'mattermost-redux/actions/users';
import {Client4} from 'mattermost-redux/client'; import {Client4} from 'mattermost-redux/client';
import {General} from 'mattermost-redux/constants'; import {General} from 'mattermost-redux/constants';
import {getIsUserStatusesConfigEnabled} from 'mattermost-redux/selectors/entities/common';
import {getCurrentTeamId} from 'mattermost-redux/selectors/entities/teams'; import {getCurrentTeamId} from 'mattermost-redux/selectors/entities/teams';
import {getCurrentUserId} from 'mattermost-redux/selectors/entities/users'; import {getCurrentUserId} from 'mattermost-redux/selectors/entities/users';
import type {ActionResult, DispatchFunc, GetStateFunc, ActionFuncAsync} from 'mattermost-redux/types/actions'; import type {ActionResult, DispatchFunc, GetStateFunc, ActionFuncAsync} from 'mattermost-redux/types/actions';
import EventEmitter from 'mattermost-redux/utils/event_emitter'; import EventEmitter from 'mattermost-redux/utils/event_emitter';
async function getProfilesAndStatusesForMembers(userIds: string[], dispatch: DispatchFunc, getState: GetStateFunc) { async function getProfilesAndStatusesForMembers(userIds: string[], dispatch: DispatchFunc, getState: GetStateFunc) {
const state = getState();
const { const {
currentUserId, currentUserId,
profiles, profiles,
statuses, statuses,
} = getState().entities.users; } = state.entities.users;
const enabledUserStatuses = getIsUserStatusesConfigEnabled(state);
const profilesToLoad: string[] = []; const profilesToLoad: string[] = [];
const statusesToLoad: string[] = []; const statusesToLoad: string[] = [];
userIds.forEach((userId) => { userIds.forEach((userId) => {
@@ -44,7 +48,7 @@ async function getProfilesAndStatusesForMembers(userIds: string[], dispatch: Dis
requests.push(dispatch(getProfilesByIds(profilesToLoad))); requests.push(dispatch(getProfilesByIds(profilesToLoad)));
} }
if (statusesToLoad.length) { if (statusesToLoad.length && enabledUserStatuses) {
requests.push(dispatch(getStatusesByIds(statusesToLoad))); requests.push(dispatch(getStatusesByIds(statusesToLoad)));
} }

Просмотреть файл

@@ -18,6 +18,7 @@ import {loadRolesIfNeeded} from 'mattermost-redux/actions/roles';
import {getMyTeams, getMyTeamMembers, getMyTeamUnreads} from 'mattermost-redux/actions/teams'; import {getMyTeams, getMyTeamMembers, getMyTeamUnreads} from 'mattermost-redux/actions/teams';
import {Client4} from 'mattermost-redux/client'; import {Client4} from 'mattermost-redux/client';
import {General} from 'mattermost-redux/constants'; import {General} from 'mattermost-redux/constants';
import {getIsUserStatusesConfigEnabled} from 'mattermost-redux/selectors/entities/common';
import {getServerVersion} from 'mattermost-redux/selectors/entities/general'; import {getServerVersion} from 'mattermost-redux/selectors/entities/general';
import {isCollapsedThreadsEnabled} from 'mattermost-redux/selectors/entities/preferences'; import {isCollapsedThreadsEnabled} from 'mattermost-redux/selectors/entities/preferences';
import {getCurrentUserId, getUsers} from 'mattermost-redux/selectors/entities/users'; import {getCurrentUserId, getUsers} from 'mattermost-redux/selectors/entities/users';
@@ -153,7 +154,9 @@ export function getProfiles(page = 0, perPage: number = General.PROFILE_CHUNK_SI
export function getMissingProfilesByIds(userIds: string[]): ActionFuncAsync<UserProfile[]> { export function getMissingProfilesByIds(userIds: string[]): ActionFuncAsync<UserProfile[]> {
return async (dispatch, getState) => { return async (dispatch, getState) => {
const {profiles} = getState().entities.users; const state = getState();
const {profiles} = state.entities.users;
const enabledUserStatuses = getIsUserStatusesConfigEnabled(state);
const missingIds: string[] = []; const missingIds: string[] = [];
userIds.forEach((id) => { userIds.forEach((id) => {
if (!profiles[id]) { if (!profiles[id]) {
@@ -162,7 +165,9 @@ export function getMissingProfilesByIds(userIds: string[]): ActionFuncAsync<User
}); });
if (missingIds.length > 0) { if (missingIds.length > 0) {
dispatch(getStatusesByIds(missingIds)); if (enabledUserStatuses) {
dispatch(getStatusesByIds(missingIds));
}
return dispatch(getProfilesByIds(missingIds)); return dispatch(getProfilesByIds(missingIds));
} }

Просмотреть файл

@@ -82,3 +82,10 @@ export function getCallsConfig(state: GlobalState): CallsConfig {
// @ts-ignore // @ts-ignore
return state[CALLS_PLUGIN].callsConfig; return state[CALLS_PLUGIN].callsConfig;
} }
// Config
export const getIsUserStatusesConfigEnabled: (a: GlobalState) => boolean = createSelector(
'getIsUserStatusesConfigEnabled',
(state: GlobalState) => state.entities.general.config.EnableUserStatuses,
(EnableUserStatuses) => EnableUserStatuses === 'true',
);

Просмотреть файл

@@ -57,6 +57,7 @@ export type ClientConfig = {
EnableCustomEmoji: string; EnableCustomEmoji: string;
EnableCustomGroups: string; EnableCustomGroups: string;
EnableCustomUserStatuses: string; EnableCustomUserStatuses: string;
EnableUserStatuses: string;
EnableLastActiveTime: string; EnableLastActiveTime: string;
EnableTimedDND: string; EnableTimedDND: string;
EnableCustomTermsOfService: string; EnableCustomTermsOfService: string;