Removing /api/v4/users/stats network request from InviteMembersButton (#23564)
Co-authored-by: Julien Tant <julien@craftyx.fr> Co-authored-by: Mattermost Build <build@mattermost.com>
Этот коммит содержится в:
@@ -15,8 +15,6 @@ exports[`components/sidebar/invite_members_button should match snapshot 1`] = `
|
|||||||
>
|
>
|
||||||
<InviteMembersButton
|
<InviteMembersButton
|
||||||
isAdmin={false}
|
isAdmin={false}
|
||||||
onClick={[MockFunction]}
|
|
||||||
touchedInviteMembersButton={false}
|
|
||||||
>
|
>
|
||||||
<Connect(TeamPermissionGate)
|
<Connect(TeamPermissionGate)
|
||||||
permissions={
|
permissions={
|
||||||
@@ -82,7 +80,7 @@ exports[`components/sidebar/invite_members_button should match snapshot 1`] = `
|
|||||||
>
|
>
|
||||||
<li
|
<li
|
||||||
aria-label="Invite Members"
|
aria-label="Invite Members"
|
||||||
className="SidebarChannelNavigator__inviteMembersLhsButton SidebarChannelNavigator__inviteMembersLhsButton--untouched"
|
className="SidebarChannelNavigator__inviteMembersLhsButton"
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
className="icon-plus-box"
|
className="icon-plus-box"
|
||||||
|
|||||||
@@ -53,8 +53,6 @@ describe('components/sidebar/invite_members_button', () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const props = {
|
const props = {
|
||||||
onClick: jest.fn(),
|
|
||||||
touchedInviteMembersButton: false,
|
|
||||||
isAdmin: false,
|
isAdmin: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -91,59 +89,4 @@ describe('components/sidebar/invite_members_button', () => {
|
|||||||
);
|
);
|
||||||
expect(wrapper.find('i').exists()).toBeFalsy();
|
expect(wrapper.find('i').exists()).toBeFalsy();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should fire onClick prop on click', () => {
|
|
||||||
const mock = jest.fn();
|
|
||||||
const wrapper = mountWithIntl(
|
|
||||||
<Provider store={store}>
|
|
||||||
<InviteMembersButton {...{...props, onClick: mock}}/>
|
|
||||||
</Provider>,
|
|
||||||
);
|
|
||||||
expect(mock).not.toHaveBeenCalled();
|
|
||||||
wrapper.find('i').simulate('click');
|
|
||||||
expect(mock).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should not be highlighted when button has been touched/clicked', () => {
|
|
||||||
const wrapper = mountWithIntl(
|
|
||||||
<Provider store={store}>
|
|
||||||
<InviteMembersButton {...{...props, touchedInviteMembersButton: true}}/>
|
|
||||||
</Provider>,
|
|
||||||
);
|
|
||||||
expect(wrapper.find('li').prop('className')).not.toContain('untouched');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should be highlighted when component has not been touched/clicked and has less than 10 users', () => {
|
|
||||||
const lessThan10Users = {
|
|
||||||
...state.entities.users,
|
|
||||||
stats: {
|
|
||||||
total_users_count: 9,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const lessThan10UsersState = {...state, entities: {...state.entities, users: lessThan10Users}};
|
|
||||||
const store = mockStore(lessThan10UsersState);
|
|
||||||
const wrapper = mountWithIntl(
|
|
||||||
<Provider store={store}>
|
|
||||||
<InviteMembersButton {...props}/>
|
|
||||||
</Provider>,
|
|
||||||
);
|
|
||||||
expect(wrapper.find('li').prop('className')).toContain('untouched');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should not be highlighted when component has not been touched/clicked but the workspace has more than 10 users', () => {
|
|
||||||
const moreThan10Users = {
|
|
||||||
...state.entities.users,
|
|
||||||
stats: {
|
|
||||||
total_users_count: 11,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const moreThan10UsersState = {...state, entities: {...state.entities, users: moreThan10Users}};
|
|
||||||
const store = mockStore(moreThan10UsersState);
|
|
||||||
const wrapper = mountWithIntl(
|
|
||||||
<Provider store={store}>
|
|
||||||
<InviteMembersButton {...props}/>
|
|
||||||
</Provider>,
|
|
||||||
);
|
|
||||||
expect(wrapper.find('li').prop('className')).not.toContain('untouched');
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,20 +1,15 @@
|
|||||||
// 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, {useEffect} from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import {useIntl, FormattedMessage} from 'react-intl';
|
import {useIntl, FormattedMessage} from 'react-intl';
|
||||||
|
|
||||||
import {useSelector, useDispatch} from 'react-redux';
|
import {useSelector} from 'react-redux';
|
||||||
|
|
||||||
import {Permissions} from 'mattermost-redux/constants';
|
import {Permissions} from 'mattermost-redux/constants';
|
||||||
|
|
||||||
import {GlobalState} from 'types/store';
|
|
||||||
|
|
||||||
import {getCurrentTeamId} from 'mattermost-redux/selectors/entities/teams';
|
import {getCurrentTeamId} from 'mattermost-redux/selectors/entities/teams';
|
||||||
import {DispatchFunc} from 'mattermost-redux/types/actions';
|
|
||||||
|
|
||||||
import {getTotalUsersStats} from 'mattermost-redux/actions/users';
|
|
||||||
|
|
||||||
import {trackEvent} from 'actions/telemetry_actions';
|
import {trackEvent} from 'actions/telemetry_actions';
|
||||||
|
|
||||||
@@ -23,40 +18,22 @@ import InvitationModal from 'components/invitation_modal';
|
|||||||
import TeamPermissionGate from 'components/permissions_gates/team_permission_gate';
|
import TeamPermissionGate from 'components/permissions_gates/team_permission_gate';
|
||||||
import {getAnalyticsCategory} from 'components/onboarding_tasks';
|
import {getAnalyticsCategory} from 'components/onboarding_tasks';
|
||||||
|
|
||||||
import Constants, {ModalIdentifiers} from 'utils/constants';
|
import {ModalIdentifiers} from 'utils/constants';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
touchedInviteMembersButton: boolean;
|
|
||||||
className?: string;
|
className?: string;
|
||||||
onClick: () => void;
|
|
||||||
isAdmin: boolean;
|
isAdmin: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const InviteMembersButton = (props: Props): JSX.Element | null => {
|
const InviteMembersButton = (props: Props): JSX.Element | null => {
|
||||||
const dispatch = useDispatch<DispatchFunc>();
|
|
||||||
|
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const currentTeamId = useSelector(getCurrentTeamId);
|
const currentTeamId = useSelector(getCurrentTeamId);
|
||||||
const totalUserCount = useSelector((state: GlobalState) => state.entities.users.stats?.total_users_count);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!totalUserCount) {
|
|
||||||
dispatch(getTotalUsersStats());
|
|
||||||
}
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const handleButtonClick = () => {
|
const handleButtonClick = () => {
|
||||||
trackEvent(getAnalyticsCategory(props.isAdmin), 'click_sidebar_invite_members_button');
|
trackEvent(getAnalyticsCategory(props.isAdmin), 'click_sidebar_invite_members_button');
|
||||||
props.onClick();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let buttonClass = 'SidebarChannelNavigator__inviteMembersLhsButton';
|
if (!currentTeamId) {
|
||||||
|
|
||||||
if (!props.touchedInviteMembersButton && Number(totalUserCount) <= Constants.USER_LIMIT) {
|
|
||||||
buttonClass += ' SidebarChannelNavigator__inviteMembersLhsButton--untouched';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!currentTeamId || !totalUserCount) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,7 +51,7 @@ const InviteMembersButton = (props: Props): JSX.Element | null => {
|
|||||||
onClick={handleButtonClick}
|
onClick={handleButtonClick}
|
||||||
>
|
>
|
||||||
<li
|
<li
|
||||||
className={buttonClass}
|
className='SidebarChannelNavigator__inviteMembersLhsButton'
|
||||||
aria-label={intl.formatMessage({id: 'sidebar_left.sidebar_channel_navigator.inviteUsers', defaultMessage: 'Invite Members'})}
|
aria-label={intl.formatMessage({id: 'sidebar_left.sidebar_channel_navigator.inviteUsers', defaultMessage: 'Invite Members'})}
|
||||||
>
|
>
|
||||||
<i className='icon-plus-box'/>
|
<i className='icon-plus-box'/>
|
||||||
|
|||||||
@@ -262,8 +262,6 @@ exports[`components/sidebar/sidebar_category should match snapshot when sorting
|
|||||||
<InviteMembersButton
|
<InviteMembersButton
|
||||||
className="followingSibling"
|
className="followingSibling"
|
||||||
isAdmin={false}
|
isAdmin={false}
|
||||||
onClick={[Function]}
|
|
||||||
touchedInviteMembersButton={false}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
@@ -387,8 +385,6 @@ exports[`components/sidebar/sidebar_category should match snapshot when the cate
|
|||||||
<InviteMembersButton
|
<InviteMembersButton
|
||||||
className="followingSibling"
|
className="followingSibling"
|
||||||
isAdmin={false}
|
isAdmin={false}
|
||||||
onClick={[Function]}
|
|
||||||
touchedInviteMembersButton={false}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -8,10 +8,8 @@ import {setCategoryCollapsed, setCategorySorting} from 'mattermost-redux/actions
|
|||||||
import {GenericAction} from 'mattermost-redux/types/actions';
|
import {GenericAction} from 'mattermost-redux/types/actions';
|
||||||
import {savePreferences} from 'mattermost-redux/actions/preferences';
|
import {savePreferences} from 'mattermost-redux/actions/preferences';
|
||||||
import {ChannelCategory} from '@mattermost/types/channel_categories';
|
import {ChannelCategory} from '@mattermost/types/channel_categories';
|
||||||
import {getBool} from 'mattermost-redux/selectors/entities/preferences';
|
|
||||||
import {getCurrentUser, getCurrentUserId} from 'mattermost-redux/selectors/entities/users';
|
import {getCurrentUser, getCurrentUserId} from 'mattermost-redux/selectors/entities/users';
|
||||||
import {isAdmin} from 'mattermost-redux/utils/user_utils';
|
import {isAdmin} from 'mattermost-redux/utils/user_utils';
|
||||||
import {Preferences, Touched} from 'utils/constants';
|
|
||||||
|
|
||||||
import {getDraggingState, makeGetFilteredChannelIdsForCategory} from 'selectors/views/channel_sidebar';
|
import {getDraggingState, makeGetFilteredChannelIdsForCategory} from 'selectors/views/channel_sidebar';
|
||||||
import {GlobalState} from 'types/store';
|
import {GlobalState} from 'types/store';
|
||||||
@@ -29,7 +27,6 @@ function makeMapStateToProps() {
|
|||||||
return {
|
return {
|
||||||
channelIds: getChannelIdsForCategory(state, ownProps.category),
|
channelIds: getChannelIdsForCategory(state, ownProps.category),
|
||||||
draggingState: getDraggingState(state),
|
draggingState: getDraggingState(state),
|
||||||
touchedInviteMembersButton: getBool(state, Preferences.TOUCHED, Touched.INVITE_MEMBERS),
|
|
||||||
currentUserId: getCurrentUserId(state),
|
currentUserId: getCurrentUserId(state),
|
||||||
isAdmin: isAdmin(getCurrentUser(state).roles),
|
isAdmin: isAdmin(getCurrentUser(state).roles),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import {trackEvent} from 'actions/telemetry_actions';
|
|||||||
import OverlayTrigger from 'components/overlay_trigger';
|
import OverlayTrigger from 'components/overlay_trigger';
|
||||||
import Tooltip from 'components/tooltip';
|
import Tooltip from 'components/tooltip';
|
||||||
import {DraggingState} from 'types/store';
|
import {DraggingState} from 'types/store';
|
||||||
import Constants, {A11yCustomEventTypes, DraggingStateTypes, DraggingStates, Preferences, Touched} from 'utils/constants';
|
import Constants, {A11yCustomEventTypes, DraggingStateTypes, DraggingStates} from 'utils/constants';
|
||||||
import {t} from 'utils/i18n';
|
import {t} from 'utils/i18n';
|
||||||
import {isKeyPressed} from 'utils/keyboard';
|
import {isKeyPressed} from 'utils/keyboard';
|
||||||
import SidebarChannel from '../sidebar_channel';
|
import SidebarChannel from '../sidebar_channel';
|
||||||
@@ -38,7 +38,6 @@ type Props = {
|
|||||||
isNewCategory: boolean;
|
isNewCategory: boolean;
|
||||||
draggingState: DraggingState;
|
draggingState: DraggingState;
|
||||||
currentUserId: string;
|
currentUserId: string;
|
||||||
touchedInviteMembersButton: boolean;
|
|
||||||
isAdmin: boolean;
|
isAdmin: boolean;
|
||||||
actions: {
|
actions: {
|
||||||
setCategoryCollapsed: (categoryId: string, collapsed: boolean) => void;
|
setCategoryCollapsed: (categoryId: string, collapsed: boolean) => void;
|
||||||
@@ -325,21 +324,7 @@ export default class SidebarCategory extends React.PureComponent<Props, State> {
|
|||||||
inviteMembersButton = (
|
inviteMembersButton = (
|
||||||
<InviteMembersButton
|
<InviteMembersButton
|
||||||
className='followingSibling'
|
className='followingSibling'
|
||||||
touchedInviteMembersButton={this.props.touchedInviteMembersButton}
|
|
||||||
isAdmin={this.props.isAdmin}
|
isAdmin={this.props.isAdmin}
|
||||||
onClick={() => {
|
|
||||||
if (!this.props.touchedInviteMembersButton) {
|
|
||||||
this.props.actions.savePreferences(
|
|
||||||
this.props.currentUserId,
|
|
||||||
[{
|
|
||||||
category: Preferences.TOUCHED,
|
|
||||||
user_id: this.props.currentUserId,
|
|
||||||
name: Touched.INVITE_MEMBERS,
|
|
||||||
value: 'true',
|
|
||||||
}],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -156,7 +156,6 @@ export const Preferences = {
|
|||||||
|
|
||||||
// For one off things that have a special, attention-grabbing UI until you interact with them
|
// For one off things that have a special, attention-grabbing UI until you interact with them
|
||||||
export const Touched = {
|
export const Touched = {
|
||||||
INVITE_MEMBERS: 'invite_members',
|
|
||||||
ADD_CHANNELS_CTA: 'add_channels_cta',
|
ADD_CHANNELS_CTA: 'add_channels_cta',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user