exclude file count on channel stats api call on from channel header (#22624)

Этот коммит содержится в:
Ashish Dhama
2023-03-29 10:48:32 +05:30
коммит произвёл GitHub
родитель 932790f99a
Коммит 529ab959e2
8 изменённых файлов: 90 добавлений и 24 удалений

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

@@ -65,7 +65,7 @@ export function emitChannelClickEvent(channel: Channel) {
const currentChannelId = getCurrentChannelId(state); const currentChannelId = getCurrentChannelId(state);
const previousRhsState = getPreviousRhsState(state); const previousRhsState = getPreviousRhsState(state);
dispatch(getChannelStats(chan.id)); dispatch(getChannelStats(chan.id, true));
const penultimate = LocalStorageStore.getPreviousChannelName(userId, teamId); const penultimate = LocalStorageStore.getPreviousChannelName(userId, teamId);
const penultimateType = LocalStorageStore.getPreviousViewedType(userId, teamId); const penultimateType = LocalStorageStore.getPreviousViewedType(userId, teamId);

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

@@ -3,8 +3,11 @@
import React from 'react'; import React from 'react';
import {Channel, ChannelStats} from '@mattermost/types/channels'; import {act} from '@testing-library/react';
import {renderWithIntl} from 'tests/react_testing_utils'; import {renderWithIntl} from 'tests/react_testing_utils';
import {Channel, ChannelStats} from '@mattermost/types/channels';
import {UserProfile} from '@mattermost/types/users'; import {UserProfile} from '@mattermost/types/users';
import {Team} from '@mattermost/types/teams'; import {Team} from '@mattermost/types/teams';
@@ -40,6 +43,7 @@ describe('channel_info_rhs', () => {
showChannelFiles: jest.fn(), showChannelFiles: jest.fn(),
showPinnedPosts: jest.fn(), showPinnedPosts: jest.fn(),
showChannelMembers: jest.fn(), showChannelMembers: jest.fn(),
getChannelStats: jest.fn().mockImplementation(() => Promise.resolve({data: {}})),
}, },
}; };
let props = {...OriginalProps}; let props = {...OriginalProps};
@@ -49,20 +53,24 @@ describe('channel_info_rhs', () => {
}); });
describe('about area', () => { describe('about area', () => {
test('should be editable', () => { test('should be editable', async () => {
renderWithIntl( renderWithIntl(
<ChannelInfoRHS <ChannelInfoRHS
{...props} {...props}
/>, />,
); );
await act(async () => {
props.actions.getChannelStats();
});
expect(mockAboutArea).toHaveBeenCalledWith( expect(mockAboutArea).toHaveBeenCalledWith(
expect.objectContaining({ expect.objectContaining({
canEditChannelProperties: true, canEditChannelProperties: true,
}), }),
); );
}); });
test('should not be editable in archived channel', () => { test('should not be editable in archived channel', async () => {
props.isArchived = true; props.isArchived = true;
renderWithIntl( renderWithIntl(
@@ -71,6 +79,10 @@ describe('channel_info_rhs', () => {
/>, />,
); );
await act(async () => {
props.actions.getChannelStats();
});
expect(mockAboutArea).toHaveBeenCalledWith( expect(mockAboutArea).toHaveBeenCalledWith(
expect.objectContaining({ expect.objectContaining({
canEditChannelProperties: false, canEditChannelProperties: false,

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

@@ -64,6 +64,7 @@ export interface Props {
showChannelFiles: (channelId: string) => void; showChannelFiles: (channelId: string) => void;
showPinnedPosts: (channelId: string | undefined) => void; showPinnedPosts: (channelId: string | undefined) => void;
showChannelMembers: (channelId: string) => void; showChannelMembers: (channelId: string) => void;
getChannelStats: (channelId: string) => Promise<{data: ChannelStats}>;
}; };
} }
@@ -192,6 +193,7 @@ const ChannelInfoRhs = ({
showChannelFiles: actions.showChannelFiles, showChannelFiles: actions.showChannelFiles,
showPinnedPosts: actions.showPinnedPosts, showPinnedPosts: actions.showPinnedPosts,
showChannelMembers: actions.showChannelMembers, showChannelMembers: actions.showChannelMembers,
getChannelStats: actions.getChannelStats,
}} }}
/> />
</div> </div>

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

@@ -16,7 +16,7 @@ import {Constants, ModalIdentifiers} from 'utils/constants';
import {getCurrentUser} from 'mattermost-redux/selectors/entities/common'; import {getCurrentUser} from 'mattermost-redux/selectors/entities/common';
import {getIsMobileView} from 'selectors/views/browser'; import {getIsMobileView} from 'selectors/views/browser';
import {getCurrentTeam} from 'mattermost-redux/selectors/entities/teams'; import {getCurrentTeam} from 'mattermost-redux/selectors/entities/teams';
import {unfavoriteChannel, favoriteChannel} from 'mattermost-redux/actions/channels'; import {unfavoriteChannel, favoriteChannel, getChannelStats} from 'mattermost-redux/actions/channels';
import {muteChannel, unmuteChannel} from 'actions/channel_actions'; import {muteChannel, unmuteChannel} from 'actions/channel_actions';
import {openModal} from 'actions/views/modals'; import {openModal} from 'actions/views/modals';
import {getDisplayNameByUser, getUserIdFromChannelId} from 'utils/utils'; import {getDisplayNameByUser, getUserIdFromChannelId} from 'utils/utils';
@@ -92,6 +92,7 @@ function mapDispatchToProps(dispatch: Dispatch<AnyAction>) {
showChannelFiles, showChannelFiles,
showPinnedPosts, showPinnedPosts,
showChannelMembers, showChannelMembers,
getChannelStats,
}, dispatch), }, dispatch),
}; };
} }

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

@@ -2,12 +2,13 @@
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import React from 'react'; import React from 'react';
import {fireEvent, screen} from '@testing-library/react'; import {act, fireEvent, screen} from '@testing-library/react';
import {Channel, ChannelStats} from '@mattermost/types/channels';
import {renderWithIntl} from 'tests/react_testing_utils'; import {renderWithIntl} from 'tests/react_testing_utils';
import Constants from 'utils/constants'; import Constants from 'utils/constants';
import {Channel, ChannelStats} from '@mattermost/types/channels';
import Menu from './menu'; import Menu from './menu';
describe('channel_info_rhs/menu', () => { describe('channel_info_rhs/menu', () => {
@@ -20,6 +21,7 @@ describe('channel_info_rhs/menu', () => {
showChannelFiles: jest.fn(), showChannelFiles: jest.fn(),
showPinnedPosts: jest.fn(), showPinnedPosts: jest.fn(),
showChannelMembers: jest.fn(), showChannelMembers: jest.fn(),
getChannelStats: jest.fn().mockImplementation(() => Promise.resolve({data: {files_count: 3, pinnedpost_count: 12, member_count: 32}})),
}, },
}; };
@@ -29,10 +31,11 @@ describe('channel_info_rhs/menu', () => {
showChannelFiles: jest.fn(), showChannelFiles: jest.fn(),
showPinnedPosts: jest.fn(), showPinnedPosts: jest.fn(),
showChannelMembers: jest.fn(), showChannelMembers: jest.fn(),
getChannelStats: jest.fn().mockImplementation(() => Promise.resolve({data: {files_count: 3, pinnedpost_count: 12, member_count: 32}})),
}; };
}); });
test('should display notifications preferences', () => { test('should display notifications preferences', async () => {
const props = {...defaultProps}; const props = {...defaultProps};
props.actions.openNotificationSettings = jest.fn(); props.actions.openNotificationSettings = jest.fn();
@@ -42,13 +45,17 @@ describe('channel_info_rhs/menu', () => {
/>, />,
); );
await act(async () => {
props.actions.getChannelStats();
});
expect(screen.getByText('Notification Preferences')).toBeInTheDocument(); expect(screen.getByText('Notification Preferences')).toBeInTheDocument();
fireEvent.click(screen.getByText('Notification Preferences')); fireEvent.click(screen.getByText('Notification Preferences'));
expect(props.actions.openNotificationSettings).toHaveBeenCalled(); expect(props.actions.openNotificationSettings).toHaveBeenCalled();
}); });
test('should NOT display notifications preferences in a DM', () => { test('should NOT display notifications preferences in a DM', async () => {
const props = { const props = {
...defaultProps, ...defaultProps,
channel: {type: Constants.DM_CHANNEL} as Channel, channel: {type: Constants.DM_CHANNEL} as Channel,
@@ -60,10 +67,14 @@ describe('channel_info_rhs/menu', () => {
/>, />,
); );
await act(async () => {
props.actions.getChannelStats();
});
expect(screen.queryByText('Notification Preferences')).not.toBeInTheDocument(); expect(screen.queryByText('Notification Preferences')).not.toBeInTheDocument();
}); });
test('should NOT display notifications preferences in an archived channel', () => { test('should NOT display notifications preferences in an archived channel', async () => {
const props = { const props = {
...defaultProps, ...defaultProps,
isArchived: true, isArchived: true,
@@ -75,10 +86,14 @@ describe('channel_info_rhs/menu', () => {
/>, />,
); );
await act(async () => {
props.actions.getChannelStats();
});
expect(screen.queryByText('Notification Preferences')).not.toBeInTheDocument(); expect(screen.queryByText('Notification Preferences')).not.toBeInTheDocument();
}); });
test('should display the number of files', () => { test('should display the number of files', async () => {
const props = {...defaultProps}; const props = {...defaultProps};
props.actions.showChannelFiles = jest.fn(); props.actions.showChannelFiles = jest.fn();
@@ -88,6 +103,10 @@ describe('channel_info_rhs/menu', () => {
/>, />,
); );
await act(async () => {
props.actions.getChannelStats();
});
const fileItem = screen.getByText('Files'); const fileItem = screen.getByText('Files');
expect(fileItem).toBeInTheDocument(); expect(fileItem).toBeInTheDocument();
expect(fileItem.parentElement).toHaveTextContent('3'); expect(fileItem.parentElement).toHaveTextContent('3');
@@ -96,7 +115,7 @@ describe('channel_info_rhs/menu', () => {
expect(props.actions.showChannelFiles).toHaveBeenCalled(); expect(props.actions.showChannelFiles).toHaveBeenCalled();
}); });
test('should display the pinned messages', () => { test('should display the pinned messages', async () => {
const props = {...defaultProps}; const props = {...defaultProps};
props.actions.showPinnedPosts = jest.fn(); props.actions.showPinnedPosts = jest.fn();
@@ -106,6 +125,10 @@ describe('channel_info_rhs/menu', () => {
/>, />,
); );
await act(async () => {
props.actions.getChannelStats();
});
const fileItem = screen.getByText('Pinned Messages'); const fileItem = screen.getByText('Pinned Messages');
expect(fileItem).toBeInTheDocument(); expect(fileItem).toBeInTheDocument();
expect(fileItem.parentElement).toHaveTextContent('12'); expect(fileItem.parentElement).toHaveTextContent('12');
@@ -114,7 +137,7 @@ describe('channel_info_rhs/menu', () => {
expect(props.actions.showPinnedPosts).toHaveBeenCalled(); expect(props.actions.showPinnedPosts).toHaveBeenCalled();
}); });
test('should display members', () => { test('should display members', async () => {
const props = {...defaultProps}; const props = {...defaultProps};
props.actions.showChannelMembers = jest.fn(); props.actions.showChannelMembers = jest.fn();
@@ -124,6 +147,10 @@ describe('channel_info_rhs/menu', () => {
/>, />,
); );
await act(async () => {
props.actions.getChannelStats();
});
const membersItem = screen.getByText('Members'); const membersItem = screen.getByText('Members');
expect(membersItem).toBeInTheDocument(); expect(membersItem).toBeInTheDocument();
expect(membersItem.parentElement).toHaveTextContent('32'); expect(membersItem.parentElement).toHaveTextContent('32');
@@ -132,7 +159,7 @@ describe('channel_info_rhs/menu', () => {
expect(props.actions.showChannelMembers).toHaveBeenCalled(); expect(props.actions.showChannelMembers).toHaveBeenCalled();
}); });
test('should NOT display members in DM', () => { test('should NOT display members in DM', async () => {
const props = { const props = {
...defaultProps, ...defaultProps,
channel: {type: Constants.DM_CHANNEL} as Channel, channel: {type: Constants.DM_CHANNEL} as Channel,
@@ -144,6 +171,10 @@ describe('channel_info_rhs/menu', () => {
/>, />,
); );
await act(async () => {
props.actions.getChannelStats();
});
const membersItem = screen.queryByText('Members'); const membersItem = screen.queryByText('Members');
expect(membersItem).not.toBeInTheDocument(); expect(membersItem).not.toBeInTheDocument();
}); });

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

@@ -1,12 +1,14 @@
// 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 from 'react'; import React, {useEffect, useState} from 'react';
import styled from 'styled-components'; import styled from 'styled-components';
import {useIntl} from 'react-intl'; import {useIntl} from 'react-intl';
import {Constants} from 'utils/constants'; import {Constants} from 'utils/constants';
import LoadingSpinner from 'components/widgets/loading/loading_spinner';
import {Channel, ChannelStats} from '@mattermost/types/channels'; import {Channel, ChannelStats} from '@mattermost/types/channels';
const MenuItemContainer = styled.div` const MenuItemContainer = styled.div`
@@ -32,6 +34,9 @@ const RightSide = styled.div`
const Badge = styled.div` const Badge = styled.div`
font-size: 12px; font-size: 12px;
line-height: 18px; line-height: 18px;
width: 20px;
display: flex;
place-content: center;
`; `;
interface MenuItemProps { interface MenuItemProps {
@@ -39,7 +44,7 @@ interface MenuItemProps {
icon: JSX.Element; icon: JSX.Element;
text: string; text: string;
opensSubpanel?: boolean; opensSubpanel?: boolean;
badge?: string|number; badge?: string|number|JSX.Element;
onClick: () => void; onClick: () => void;
} }
@@ -94,14 +99,26 @@ interface MenuProps {
showChannelFiles: (channelId: string) => void; showChannelFiles: (channelId: string) => void;
showPinnedPosts: (channelId: string | undefined) => void; showPinnedPosts: (channelId: string | undefined) => void;
showChannelMembers: (channelId: string) => void; showChannelMembers: (channelId: string) => void;
getChannelStats: (channelId: string) => Promise<{data: ChannelStats}>;
}; };
} }
const Menu = ({channel, channelStats, isArchived, className, actions}: MenuProps) => { const Menu = ({channel, channelStats, isArchived, className, actions}: MenuProps) => {
const {formatMessage} = useIntl(); const {formatMessage} = useIntl();
const [loadingStats, setLoadingStats] = useState(true);
const showNotificationPreferences = channel.type !== Constants.DM_CHANNEL && !isArchived; const showNotificationPreferences = channel.type !== Constants.DM_CHANNEL && !isArchived;
const showMembers = channel.type !== Constants.DM_CHANNEL; const showMembers = channel.type !== Constants.DM_CHANNEL;
const fileCount = channelStats?.files_count >= 0 ? channelStats?.files_count : 0;
useEffect(() => {
actions.getChannelStats(channel.id).then(() => {
setLoadingStats(false);
});
return () => {
setLoadingStats(true);
};
}, [channel.id]);
return ( return (
<div <div
@@ -135,7 +152,7 @@ const Menu = ({channel, channelStats, isArchived, className, actions}: MenuProps
icon={<i className='icon icon-file-text-outline'/>} icon={<i className='icon icon-file-text-outline'/>}
text={formatMessage({id: 'channel_info_rhs.menu.files', defaultMessage: 'Files'})} text={formatMessage({id: 'channel_info_rhs.menu.files', defaultMessage: 'Files'})}
opensSubpanel={true} opensSubpanel={true}
badge={channelStats?.files_count} badge={loadingStats ? <LoadingSpinner/> : fileCount}
onClick={() => actions.showChannelFiles(channel.id)} onClick={() => actions.showChannelFiles(channel.id)}
/> />
</div> </div>

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

@@ -8,7 +8,6 @@ import {ChannelTypes, PreferenceTypes, UserTypes} from 'mattermost-redux/action_
import {Client4} from 'mattermost-redux/client'; import {Client4} from 'mattermost-redux/client';
import {General, Preferences} from '../constants';
import {CategoryTypes} from 'mattermost-redux/constants/channel_categories'; import {CategoryTypes} from 'mattermost-redux/constants/channel_categories';
import {MarkUnread} from 'mattermost-redux/constants/channels'; import {MarkUnread} from 'mattermost-redux/constants/channels';
@@ -25,12 +24,15 @@ import {getCurrentTeamId} from 'mattermost-redux/selectors/entities/teams';
import {ActionFunc, ActionResult, DispatchFunc, GetStateFunc} from 'mattermost-redux/types/actions'; import {ActionFunc, ActionResult, DispatchFunc, GetStateFunc} from 'mattermost-redux/types/actions';
import {getChannelsIdForTeam, getChannelByName} from 'mattermost-redux/utils/channel_utils';
import {isMinimumServerVersion} from 'mattermost-redux/utils/helpers';
import {Channel, ChannelNotifyProps, ChannelMembership, ChannelModerationPatch, ChannelsWithTotalCount, ChannelSearchOpts} from '@mattermost/types/channels'; import {Channel, ChannelNotifyProps, ChannelMembership, ChannelModerationPatch, ChannelsWithTotalCount, ChannelSearchOpts} from '@mattermost/types/channels';
import {PreferenceType} from '@mattermost/types/preferences'; import {PreferenceType} from '@mattermost/types/preferences';
import {getChannelsIdForTeam, getChannelByName} from 'mattermost-redux/utils/channel_utils'; import {General, Preferences} from '../constants';
import {isMinimumServerVersion} from 'mattermost-redux/utils/helpers';
import {addChannelToInitialCategory, addChannelToCategory} from './channel_categories'; import {addChannelToInitialCategory, addChannelToCategory} from './channel_categories';
import {logError} from './errors'; import {logError} from './errors';
@@ -1074,11 +1076,11 @@ export function searchGroupChannels(term: string): ActionFunc {
}); });
} }
export function getChannelStats(channelId: string): ActionFunc { export function getChannelStats(channelId: string, excludeFilesCount?: boolean): ActionFunc {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => { return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
let stat; let stat;
try { try {
stat = await Client4.getChannelStats(channelId); stat = await Client4.getChannelStats(channelId, excludeFilesCount);
} catch (error) { } catch (error) {
forceLogoutIfNecessary(error, dispatch, getState); forceLogoutIfNecessary(error, dispatch, getState);
dispatch(logError(error)); dispatch(logError(error));

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

@@ -1782,9 +1782,10 @@ export default class Client4 {
); );
}; };
getChannelStats = (channelId: string) => { getChannelStats = (channelId: string, excludeFilesCount = false) => {
const param = excludeFilesCount ? `?exclude_files_count=${excludeFilesCount}` : '';
return this.doFetch<ChannelStats>( return this.doFetch<ChannelStats>(
`${this.getChannelRoute(channelId)}/stats`, `${this.getChannelRoute(channelId)}/stats${param}`,
{method: 'get'}, {method: 'get'},
); );
}; };