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
Этот коммит содержится в:
@@ -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;
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user