mirror of
https://github.com/mattermost/mattermost.git
synced 2025-02-25 18:55:24 -06:00
Fix several re-renders on init (#26361)
* Fix several re-renders on init * Fix tests * Address feedback --------- Co-authored-by: Mattermost Build <build@mattermost.com>
This commit is contained in:
parent
19d59d1126
commit
e8b4892877
@ -1,7 +1,7 @@
|
|||||||
// 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 {useState, useEffect, useMemo} from 'react';
|
import {useEffect, useMemo, useRef} from 'react';
|
||||||
import {useDispatch, useSelector} from 'react-redux';
|
import {useDispatch, useSelector} from 'react-redux';
|
||||||
|
|
||||||
import type {Product} from '@mattermost/types/cloud';
|
import type {Product} from '@mattermost/types/cloud';
|
||||||
@ -19,14 +19,15 @@ export default function useGetSelfHostedProducts(): [Record<string, Product>, bo
|
|||||||
const products = useSelector(getSelfHostedProducts);
|
const products = useSelector(getSelfHostedProducts);
|
||||||
const productsReceived = useSelector(getSelfHostedProductsLoaded);
|
const productsReceived = useSelector(getSelfHostedProductsLoaded);
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const [requested, setRequested] = useState(false);
|
const requested = useRef(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isLoggedIn && !isCloud && !requested && !productsReceived) {
|
if (isLoggedIn && !isCloud && !requested.current && !productsReceived) {
|
||||||
dispatch(getSelfHostedProductsAction());
|
dispatch(getSelfHostedProductsAction());
|
||||||
setRequested(true);
|
requested.current = true;
|
||||||
}
|
}
|
||||||
}, [isLoggedIn, isCloud, requested, productsReceived]);
|
}, [isLoggedIn, isCloud, productsReceived]);
|
||||||
|
|
||||||
const result: [Record<string, Product>, boolean] = useMemo(() => {
|
const result: [Record<string, Product>, boolean] = useMemo(() => {
|
||||||
return [products, productsReceived];
|
return [products, productsReceived];
|
||||||
}, [products, productsReceived]);
|
}, [products, productsReceived]);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// 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, {useState, useEffect} from 'react';
|
import React, {useMemo} from 'react';
|
||||||
|
|
||||||
import ThemeProvider, {lightTheme} from '@mattermost/compass-components/utilities/theme'; // eslint-disable-line no-restricted-imports
|
import ThemeProvider, {lightTheme} from '@mattermost/compass-components/utilities/theme'; // eslint-disable-line no-restricted-imports
|
||||||
|
|
||||||
@ -12,45 +12,48 @@ type Props = {
|
|||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
const CompassThemeProvider = ({theme, children}: Props): JSX.Element | null => {
|
const CompassThemeProvider = ({
|
||||||
const [compassTheme, setCompassTheme] = useState({
|
theme,
|
||||||
|
children,
|
||||||
|
}: Props) => {
|
||||||
|
const compassTheme = useMemo(() => {
|
||||||
|
const base = {
|
||||||
...lightTheme,
|
...lightTheme,
|
||||||
noStyleReset: true,
|
noStyleReset: true,
|
||||||
noDefaultStyle: true,
|
noDefaultStyle: true,
|
||||||
noFontFaces: true,
|
noFontFaces: true,
|
||||||
});
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
return {
|
||||||
setCompassTheme({
|
...base,
|
||||||
...compassTheme,
|
|
||||||
palette: {
|
palette: {
|
||||||
...compassTheme.palette,
|
...base.palette,
|
||||||
primary: {
|
primary: {
|
||||||
...compassTheme.palette.primary,
|
...base.palette.primary,
|
||||||
main: theme.sidebarHeaderBg,
|
main: theme.sidebarHeaderBg,
|
||||||
contrast: theme.sidebarHeaderTextColor,
|
contrast: theme.sidebarHeaderTextColor,
|
||||||
},
|
},
|
||||||
alert: {
|
alert: {
|
||||||
...compassTheme.palette.alert,
|
...base.palette.alert,
|
||||||
main: theme.dndIndicator,
|
main: theme.dndIndicator,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
action: {
|
action: {
|
||||||
...compassTheme.action,
|
...base.action,
|
||||||
hover: theme.sidebarHeaderTextColor,
|
hover: theme.sidebarHeaderTextColor,
|
||||||
disabled: theme.sidebarHeaderTextColor,
|
disabled: theme.sidebarHeaderTextColor,
|
||||||
},
|
},
|
||||||
badges: {
|
badges: {
|
||||||
...compassTheme.badges,
|
...base.badges,
|
||||||
online: theme.onlineIndicator,
|
online: theme.onlineIndicator,
|
||||||
away: theme.awayIndicator,
|
away: theme.awayIndicator,
|
||||||
dnd: theme.dndIndicator,
|
dnd: theme.dndIndicator,
|
||||||
},
|
},
|
||||||
text: {
|
text: {
|
||||||
...compassTheme.text,
|
...base.text,
|
||||||
primary: theme.sidebarHeaderTextColor,
|
primary: theme.sidebarHeaderTextColor,
|
||||||
},
|
},
|
||||||
});
|
};
|
||||||
}, [theme]);
|
}, [theme]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -161,11 +161,11 @@ const Skeleton = styled.div`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
const OnBoardingTaskList = (): JSX.Element | null => {
|
const OnBoardingTaskList = (): JSX.Element | null => {
|
||||||
const myPreferences = useSelector((state: GlobalState) => getMyPreferencesSelector(state));
|
const hasPreferences = useSelector((state: GlobalState) => Object.keys(getMyPreferencesSelector(state)).length !== 0);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
dispatch(getPrevTrialLicense());
|
dispatch(getPrevTrialLicense());
|
||||||
if (Object.keys(myPreferences).length === 0) {
|
if (!hasPreferences) {
|
||||||
dispatch(getMyPreferences());
|
dispatch(getMyPreferences());
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
@ -182,7 +182,10 @@ const OnBoardingTaskList = (): JSX.Element | null => {
|
|||||||
const isCurrentUserSystemAdmin = useIsCurrentUserSystemAdmin();
|
const isCurrentUserSystemAdmin = useIsCurrentUserSystemAdmin();
|
||||||
const isFirstAdmin = useFirstAdminUser();
|
const isFirstAdmin = useFirstAdminUser();
|
||||||
const isEnableOnboardingFlow = useSelector((state: GlobalState) => getConfig(state).EnableOnboardingFlow === 'true');
|
const isEnableOnboardingFlow = useSelector((state: GlobalState) => getConfig(state).EnableOnboardingFlow === 'true');
|
||||||
const [showTaskList, firstTimeOnboarding] = useSelector(getShowTaskListBool);
|
const [showTaskList, firstTimeOnboarding] = useSelector(
|
||||||
|
getShowTaskListBool,
|
||||||
|
(a, b) => a[0] === b[0] && a[1] === b[1],
|
||||||
|
);
|
||||||
const theme = useSelector(getTheme);
|
const theme = useSelector(getTheme);
|
||||||
|
|
||||||
const startTask = (taskName: string) => {
|
const startTask = (taskName: string) => {
|
||||||
@ -284,7 +287,7 @@ const OnBoardingTaskList = (): JSX.Element | null => {
|
|||||||
}));
|
}));
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
if (Object.keys(myPreferences).length === 0 || !showTaskList || !isEnableOnboardingFlow) {
|
if (!hasPreferences || !showTaskList || !isEnableOnboardingFlow) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// 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, {memo, useCallback} from 'react';
|
import React, {memo, useCallback, useMemo} from 'react';
|
||||||
import {FormattedMessage, useIntl} from 'react-intl';
|
import {FormattedMessage, useIntl} from 'react-intl';
|
||||||
import {useDispatch, useSelector} from 'react-redux';
|
import {useDispatch, useSelector} from 'react-redux';
|
||||||
|
|
||||||
@ -42,13 +42,12 @@ type Props = {
|
|||||||
category: ChannelCategory;
|
category: ChannelCategory;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getUnreadsIdsForCategory = makeGetUnreadIdsForCategory();
|
|
||||||
|
|
||||||
const SidebarCategoryMenu = ({
|
const SidebarCategoryMenu = ({
|
||||||
category,
|
category,
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const showUnreadsCategory = useSelector(shouldShowUnreadsCategory);
|
const showUnreadsCategory = useSelector(shouldShowUnreadsCategory);
|
||||||
|
const getUnreadsIdsForCategory = useMemo(makeGetUnreadIdsForCategory, [category]);
|
||||||
const unreadsIds = useSelector((state: GlobalState) => getUnreadsIdsForCategory(state, category));
|
const unreadsIds = useSelector((state: GlobalState) => getUnreadsIdsForCategory(state, category));
|
||||||
|
|
||||||
const {formatMessage} = useIntl();
|
const {formatMessage} = useIntl();
|
||||||
|
@ -8,7 +8,6 @@ import type {Channel} from '@mattermost/types/channels';
|
|||||||
|
|
||||||
import {favoriteChannel, unfavoriteChannel, markMultipleChannelsAsRead} from 'mattermost-redux/actions/channels';
|
import {favoriteChannel, unfavoriteChannel, markMultipleChannelsAsRead} from 'mattermost-redux/actions/channels';
|
||||||
import Permissions from 'mattermost-redux/constants/permissions';
|
import Permissions from 'mattermost-redux/constants/permissions';
|
||||||
import {getCategoryInTeamWithChannel} from 'mattermost-redux/selectors/entities/channel_categories';
|
|
||||||
import {isFavoriteChannel} from 'mattermost-redux/selectors/entities/channels';
|
import {isFavoriteChannel} from 'mattermost-redux/selectors/entities/channels';
|
||||||
import {getMyChannelMemberships, getCurrentUserId} from 'mattermost-redux/selectors/entities/common';
|
import {getMyChannelMemberships, getCurrentUserId} from 'mattermost-redux/selectors/entities/common';
|
||||||
import {haveIChannelPermission} from 'mattermost-redux/selectors/entities/roles';
|
import {haveIChannelPermission} from 'mattermost-redux/selectors/entities/roles';
|
||||||
@ -17,9 +16,7 @@ import {isChannelMuted} from 'mattermost-redux/utils/channel_utils';
|
|||||||
|
|
||||||
import {unmuteChannel, muteChannel} from 'actions/channel_actions';
|
import {unmuteChannel, muteChannel} from 'actions/channel_actions';
|
||||||
import {markMostRecentPostInChannelAsUnread} from 'actions/post_actions';
|
import {markMostRecentPostInChannelAsUnread} from 'actions/post_actions';
|
||||||
import {addChannelsInSidebar} from 'actions/views/channel_sidebar';
|
|
||||||
import {openModal} from 'actions/views/modals';
|
import {openModal} from 'actions/views/modals';
|
||||||
import {getCategoriesForCurrentTeam, getDisplayedChannels} from 'selectors/views/channel_sidebar';
|
|
||||||
|
|
||||||
import {getSiteURL} from 'utils/url';
|
import {getSiteURL} from 'utils/url';
|
||||||
|
|
||||||
@ -41,27 +38,19 @@ function mapStateToProps(state: GlobalState, ownProps: OwnProps) {
|
|||||||
|
|
||||||
let managePublicChannelMembers = false;
|
let managePublicChannelMembers = false;
|
||||||
let managePrivateChannelMembers = false;
|
let managePrivateChannelMembers = false;
|
||||||
let categories;
|
|
||||||
let currentCategory;
|
|
||||||
|
|
||||||
if (currentTeam) {
|
if (currentTeam) {
|
||||||
managePublicChannelMembers = haveIChannelPermission(state, currentTeam.id, ownProps.channel.id, Permissions.MANAGE_PUBLIC_CHANNEL_MEMBERS);
|
managePublicChannelMembers = haveIChannelPermission(state, currentTeam.id, ownProps.channel.id, Permissions.MANAGE_PUBLIC_CHANNEL_MEMBERS);
|
||||||
managePrivateChannelMembers = haveIChannelPermission(state, currentTeam.id, ownProps.channel.id, Permissions.MANAGE_PRIVATE_CHANNEL_MEMBERS);
|
managePrivateChannelMembers = haveIChannelPermission(state, currentTeam.id, ownProps.channel.id, Permissions.MANAGE_PRIVATE_CHANNEL_MEMBERS);
|
||||||
categories = getCategoriesForCurrentTeam(state);
|
|
||||||
currentCategory = getCategoryInTeamWithChannel(state, currentTeam.id, ownProps.channel.id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
currentUserId: getCurrentUserId(state),
|
currentUserId: getCurrentUserId(state),
|
||||||
categories,
|
|
||||||
currentCategory,
|
|
||||||
isFavorite: isFavoriteChannel(state, ownProps.channel.id),
|
isFavorite: isFavoriteChannel(state, ownProps.channel.id),
|
||||||
isMuted: isChannelMuted(member),
|
isMuted: isChannelMuted(member),
|
||||||
channelLink: `${getSiteURL()}${ownProps.channelLink}`,
|
channelLink: `${getSiteURL()}${ownProps.channelLink}`,
|
||||||
managePublicChannelMembers,
|
managePublicChannelMembers,
|
||||||
managePrivateChannelMembers,
|
managePrivateChannelMembers,
|
||||||
displayedChannels: getDisplayedChannels(state),
|
|
||||||
multiSelectedChannelIds: state.views.channelSidebar.multiSelectedChannelIds,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,7 +62,6 @@ const mapDispatchToProps = {
|
|||||||
muteChannel,
|
muteChannel,
|
||||||
unmuteChannel,
|
unmuteChannel,
|
||||||
openModal,
|
openModal,
|
||||||
addChannelsInSidebar,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const connector = connect(mapStateToProps, mapDispatchToProps);
|
const connector = connect(mapStateToProps, mapDispatchToProps);
|
||||||
|
@ -29,22 +29,40 @@ import type {PropsFromRedux, OwnProps} from './index';
|
|||||||
|
|
||||||
type Props = PropsFromRedux & OwnProps;
|
type Props = PropsFromRedux & OwnProps;
|
||||||
|
|
||||||
const SidebarChannelMenu = (props: Props) => {
|
const SidebarChannelMenu = ({
|
||||||
|
channel,
|
||||||
|
channelLink,
|
||||||
|
currentUserId,
|
||||||
|
favoriteChannel,
|
||||||
|
isFavorite,
|
||||||
|
isMuted,
|
||||||
|
isUnread,
|
||||||
|
managePrivateChannelMembers,
|
||||||
|
managePublicChannelMembers,
|
||||||
|
markMultipleChannelsAsRead,
|
||||||
|
markMostRecentPostInChannelAsUnread,
|
||||||
|
muteChannel,
|
||||||
|
onMenuToggle,
|
||||||
|
openModal,
|
||||||
|
unfavoriteChannel,
|
||||||
|
unmuteChannel,
|
||||||
|
channelLeaveHandler,
|
||||||
|
}: Props) => {
|
||||||
const isLeaving = useRef(false);
|
const isLeaving = useRef(false);
|
||||||
|
|
||||||
const {formatMessage} = useIntl();
|
const {formatMessage} = useIntl();
|
||||||
|
|
||||||
let markAsReadUnreadMenuItem: JSX.Element | null = null;
|
let markAsReadUnreadMenuItem: JSX.Element | null = null;
|
||||||
if (props.isUnread) {
|
if (isUnread) {
|
||||||
function handleMarkAsRead() {
|
function handleMarkAsRead() {
|
||||||
// We use mark multiple to not update the active channel in the server
|
// We use mark multiple to not update the active channel in the server
|
||||||
props.markMultipleChannelsAsRead({[props.channel.id]: Date.now()});
|
markMultipleChannelsAsRead({[channel.id]: Date.now()});
|
||||||
trackEvent('ui', 'ui_sidebar_channel_menu_markAsRead');
|
trackEvent('ui', 'ui_sidebar_channel_menu_markAsRead');
|
||||||
}
|
}
|
||||||
|
|
||||||
markAsReadUnreadMenuItem = (
|
markAsReadUnreadMenuItem = (
|
||||||
<Menu.Item
|
<Menu.Item
|
||||||
id={`markAsRead-${props.channel.id}`}
|
id={`markAsRead-${channel.id}`}
|
||||||
onClick={handleMarkAsRead}
|
onClick={handleMarkAsRead}
|
||||||
leadingElement={<MarkAsUnreadIcon size={18}/>}
|
leadingElement={<MarkAsUnreadIcon size={18}/>}
|
||||||
labels={(
|
labels={(
|
||||||
@ -58,13 +76,13 @@ const SidebarChannelMenu = (props: Props) => {
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
function handleMarkAsUnread() {
|
function handleMarkAsUnread() {
|
||||||
props.markMostRecentPostInChannelAsUnread(props.channel.id);
|
markMostRecentPostInChannelAsUnread(channel.id);
|
||||||
trackEvent('ui', 'ui_sidebar_channel_menu_markAsUnread');
|
trackEvent('ui', 'ui_sidebar_channel_menu_markAsUnread');
|
||||||
}
|
}
|
||||||
|
|
||||||
markAsReadUnreadMenuItem = (
|
markAsReadUnreadMenuItem = (
|
||||||
<Menu.Item
|
<Menu.Item
|
||||||
id={`markAsUnread-${props.channel.id}`}
|
id={`markAsUnread-${channel.id}`}
|
||||||
onClick={handleMarkAsUnread}
|
onClick={handleMarkAsUnread}
|
||||||
leadingElement={<MarkAsUnreadIcon size={18}/>}
|
leadingElement={<MarkAsUnreadIcon size={18}/>}
|
||||||
labels={(
|
labels={(
|
||||||
@ -78,15 +96,15 @@ const SidebarChannelMenu = (props: Props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let favoriteUnfavoriteMenuItem: JSX.Element | null = null;
|
let favoriteUnfavoriteMenuItem: JSX.Element | null = null;
|
||||||
if (props.isFavorite) {
|
if (isFavorite) {
|
||||||
function handleUnfavoriteChannel() {
|
function handleUnfavoriteChannel() {
|
||||||
props.unfavoriteChannel(props.channel.id);
|
unfavoriteChannel(channel.id);
|
||||||
trackEvent('ui', 'ui_sidebar_channel_menu_unfavorite');
|
trackEvent('ui', 'ui_sidebar_channel_menu_unfavorite');
|
||||||
}
|
}
|
||||||
|
|
||||||
favoriteUnfavoriteMenuItem = (
|
favoriteUnfavoriteMenuItem = (
|
||||||
<Menu.Item
|
<Menu.Item
|
||||||
id={`unfavorite-${props.channel.id}`}
|
id={`unfavorite-${channel.id}`}
|
||||||
onClick={handleUnfavoriteChannel}
|
onClick={handleUnfavoriteChannel}
|
||||||
leadingElement={<StarIcon size={18}/>}
|
leadingElement={<StarIcon size={18}/>}
|
||||||
labels={(
|
labels={(
|
||||||
@ -99,14 +117,14 @@ const SidebarChannelMenu = (props: Props) => {
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
function handleFavoriteChannel() {
|
function handleFavoriteChannel() {
|
||||||
props.favoriteChannel(props.channel.id);
|
favoriteChannel(channel.id);
|
||||||
trackEvent('ui', 'ui_sidebar_channel_menu_favorite');
|
trackEvent('ui', 'ui_sidebar_channel_menu_favorite');
|
||||||
}
|
}
|
||||||
|
|
||||||
favoriteUnfavoriteMenuItem = (
|
favoriteUnfavoriteMenuItem = (
|
||||||
|
|
||||||
<Menu.Item
|
<Menu.Item
|
||||||
id={`favorite-${props.channel.id}`}
|
id={`favorite-${channel.id}`}
|
||||||
onClick={handleFavoriteChannel}
|
onClick={handleFavoriteChannel}
|
||||||
leadingElement={<StarOutlineIcon size={18}/>}
|
leadingElement={<StarOutlineIcon size={18}/>}
|
||||||
labels={(
|
labels={(
|
||||||
@ -120,14 +138,14 @@ const SidebarChannelMenu = (props: Props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let muteUnmuteChannelMenuItem: JSX.Element | null = null;
|
let muteUnmuteChannelMenuItem: JSX.Element | null = null;
|
||||||
if (props.isMuted) {
|
if (isMuted) {
|
||||||
let muteChannelText = (
|
let muteChannelText = (
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='sidebar_left.sidebar_channel_menu.unmuteChannel'
|
id='sidebar_left.sidebar_channel_menu.unmuteChannel'
|
||||||
defaultMessage='Unmute Channel'
|
defaultMessage='Unmute Channel'
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
if (props.channel.type === Constants.DM_CHANNEL || props.channel.type === Constants.GM_CHANNEL) {
|
if (channel.type === Constants.DM_CHANNEL || channel.type === Constants.GM_CHANNEL) {
|
||||||
muteChannelText = (
|
muteChannelText = (
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='sidebar_left.sidebar_channel_menu.unmuteConversation'
|
id='sidebar_left.sidebar_channel_menu.unmuteConversation'
|
||||||
@ -137,12 +155,12 @@ const SidebarChannelMenu = (props: Props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function handleUnmuteChannel() {
|
function handleUnmuteChannel() {
|
||||||
props.unmuteChannel(props.currentUserId, props.channel.id);
|
unmuteChannel(currentUserId, channel.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
muteUnmuteChannelMenuItem = (
|
muteUnmuteChannelMenuItem = (
|
||||||
<Menu.Item
|
<Menu.Item
|
||||||
id={`unmute-${props.channel.id}`}
|
id={`unmute-${channel.id}`}
|
||||||
onClick={handleUnmuteChannel}
|
onClick={handleUnmuteChannel}
|
||||||
leadingElement={<BellOffOutlineIcon size={18}/>}
|
leadingElement={<BellOffOutlineIcon size={18}/>}
|
||||||
labels={muteChannelText}
|
labels={muteChannelText}
|
||||||
@ -155,7 +173,7 @@ const SidebarChannelMenu = (props: Props) => {
|
|||||||
defaultMessage='Mute Channel'
|
defaultMessage='Mute Channel'
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
if (props.channel.type === Constants.DM_CHANNEL || props.channel.type === Constants.GM_CHANNEL) {
|
if (channel.type === Constants.DM_CHANNEL || channel.type === Constants.GM_CHANNEL) {
|
||||||
muteChannelText = (
|
muteChannelText = (
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='sidebar_left.sidebar_channel_menu.muteConversation'
|
id='sidebar_left.sidebar_channel_menu.muteConversation'
|
||||||
@ -165,12 +183,12 @@ const SidebarChannelMenu = (props: Props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function handleMuteChannel() {
|
function handleMuteChannel() {
|
||||||
props.muteChannel(props.currentUserId, props.channel.id);
|
muteChannel(currentUserId, channel.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
muteUnmuteChannelMenuItem = (
|
muteUnmuteChannelMenuItem = (
|
||||||
<Menu.Item
|
<Menu.Item
|
||||||
id={`mute-${props.channel.id}`}
|
id={`mute-${channel.id}`}
|
||||||
onClick={handleMuteChannel}
|
onClick={handleMuteChannel}
|
||||||
leadingElement={<BellOutlineIcon size={18}/>}
|
leadingElement={<BellOutlineIcon size={18}/>}
|
||||||
labels={muteChannelText}
|
labels={muteChannelText}
|
||||||
@ -179,14 +197,14 @@ const SidebarChannelMenu = (props: Props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let copyLinkMenuItem: JSX.Element | null = null;
|
let copyLinkMenuItem: JSX.Element | null = null;
|
||||||
if (props.channel.type === Constants.OPEN_CHANNEL || props.channel.type === Constants.PRIVATE_CHANNEL) {
|
if (channel.type === Constants.OPEN_CHANNEL || channel.type === Constants.PRIVATE_CHANNEL) {
|
||||||
function handleCopyLink() {
|
function handleCopyLink() {
|
||||||
copyToClipboard(props.channelLink);
|
copyToClipboard(channelLink);
|
||||||
}
|
}
|
||||||
|
|
||||||
copyLinkMenuItem = (
|
copyLinkMenuItem = (
|
||||||
<Menu.Item
|
<Menu.Item
|
||||||
id={`copyLink-${props.channel.id}`}
|
id={`copyLink-${channel.id}`}
|
||||||
onClick={handleCopyLink}
|
onClick={handleCopyLink}
|
||||||
leadingElement={<LinkVariantIcon size={18}/>}
|
leadingElement={<LinkVariantIcon size={18}/>}
|
||||||
labels={(
|
labels={(
|
||||||
@ -200,19 +218,19 @@ const SidebarChannelMenu = (props: Props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let addMembersMenuItem: JSX.Element | null = null;
|
let addMembersMenuItem: JSX.Element | null = null;
|
||||||
if ((props.channel.type === Constants.PRIVATE_CHANNEL && props.managePrivateChannelMembers) || (props.channel.type === Constants.OPEN_CHANNEL && props.managePublicChannelMembers)) {
|
if ((channel.type === Constants.PRIVATE_CHANNEL && managePrivateChannelMembers) || (channel.type === Constants.OPEN_CHANNEL && managePublicChannelMembers)) {
|
||||||
function handleAddMembers() {
|
function handleAddMembers() {
|
||||||
props.openModal({
|
openModal({
|
||||||
modalId: ModalIdentifiers.CHANNEL_INVITE,
|
modalId: ModalIdentifiers.CHANNEL_INVITE,
|
||||||
dialogType: ChannelInviteModal,
|
dialogType: ChannelInviteModal,
|
||||||
dialogProps: {channel: props.channel},
|
dialogProps: {channel},
|
||||||
});
|
});
|
||||||
trackEvent('ui', 'ui_sidebar_channel_menu_addMembers');
|
trackEvent('ui', 'ui_sidebar_channel_menu_addMembers');
|
||||||
}
|
}
|
||||||
|
|
||||||
addMembersMenuItem = (
|
addMembersMenuItem = (
|
||||||
<Menu.Item
|
<Menu.Item
|
||||||
id={`addMembers-${props.channel.id}`}
|
id={`addMembers-${channel.id}`}
|
||||||
onClick={handleAddMembers}
|
onClick={handleAddMembers}
|
||||||
aria-haspopup='true'
|
aria-haspopup='true'
|
||||||
leadingElement={<AccountPlusOutlineIcon size={18}/>}
|
leadingElement={<AccountPlusOutlineIcon size={18}/>}
|
||||||
@ -227,14 +245,14 @@ const SidebarChannelMenu = (props: Props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let leaveChannelMenuItem: JSX.Element | null = null;
|
let leaveChannelMenuItem: JSX.Element | null = null;
|
||||||
if (props.channel.name !== Constants.DEFAULT_CHANNEL) {
|
if (channel.name !== Constants.DEFAULT_CHANNEL) {
|
||||||
let leaveChannelText = (
|
let leaveChannelText = (
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='sidebar_left.sidebar_channel_menu.leaveChannel'
|
id='sidebar_left.sidebar_channel_menu.leaveChannel'
|
||||||
defaultMessage='Leave Channel'
|
defaultMessage='Leave Channel'
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
if (props.channel.type === Constants.DM_CHANNEL || props.channel.type === Constants.GM_CHANNEL) {
|
if (channel.type === Constants.DM_CHANNEL || channel.type === Constants.GM_CHANNEL) {
|
||||||
leaveChannelText = (
|
leaveChannelText = (
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='sidebar_left.sidebar_channel_menu.leaveConversation'
|
id='sidebar_left.sidebar_channel_menu.leaveConversation'
|
||||||
@ -244,13 +262,13 @@ const SidebarChannelMenu = (props: Props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function handleLeaveChannel() {
|
function handleLeaveChannel() {
|
||||||
if (isLeaving.current || !props.channelLeaveHandler) {
|
if (isLeaving.current || !channelLeaveHandler) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
isLeaving.current = true;
|
isLeaving.current = true;
|
||||||
|
|
||||||
props.channelLeaveHandler(() => {
|
channelLeaveHandler(() => {
|
||||||
isLeaving.current = false;
|
isLeaving.current = false;
|
||||||
});
|
});
|
||||||
trackEvent('ui', 'ui_sidebar_channel_menu_leave');
|
trackEvent('ui', 'ui_sidebar_channel_menu_leave');
|
||||||
@ -258,7 +276,7 @@ const SidebarChannelMenu = (props: Props) => {
|
|||||||
|
|
||||||
leaveChannelMenuItem = (
|
leaveChannelMenuItem = (
|
||||||
<Menu.Item
|
<Menu.Item
|
||||||
id={`leave-${props.channel.id}`}
|
id={`leave-${channel.id}`}
|
||||||
onClick={handleLeaveChannel}
|
onClick={handleLeaveChannel}
|
||||||
leadingElement={<ExitToAppIcon size={18}/>}
|
leadingElement={<ExitToAppIcon size={18}/>}
|
||||||
labels={leaveChannelText}
|
labels={leaveChannelText}
|
||||||
@ -270,30 +288,30 @@ const SidebarChannelMenu = (props: Props) => {
|
|||||||
return (
|
return (
|
||||||
<Menu.Container
|
<Menu.Container
|
||||||
menuButton={{
|
menuButton={{
|
||||||
id: `SidebarChannelMenu-Button-${props.channel.id}`,
|
id: `SidebarChannelMenu-Button-${channel.id}`,
|
||||||
class: 'SidebarMenu_menuButton',
|
class: 'SidebarMenu_menuButton',
|
||||||
'aria-label': formatMessage({
|
'aria-label': formatMessage({
|
||||||
id: 'sidebar_left.sidebar_channel_menu.editChannel.ariaLabel',
|
id: 'sidebar_left.sidebar_channel_menu.editChannel.ariaLabel',
|
||||||
defaultMessage: 'Channel options for {channelName}',
|
defaultMessage: 'Channel options for {channelName}',
|
||||||
}, {channelName: props.channel.name}),
|
}, {channelName: channel.name}),
|
||||||
children: <DotsVerticalIcon size={16}/>,
|
children: <DotsVerticalIcon size={16}/>,
|
||||||
}}
|
}}
|
||||||
menuButtonTooltip={{
|
menuButtonTooltip={{
|
||||||
id: `SidebarChannelMenu-ButtonTooltip-${props.channel.id}`,
|
id: `SidebarChannelMenu-ButtonTooltip-${channel.id}`,
|
||||||
class: 'hidden-xs',
|
class: 'hidden-xs',
|
||||||
text: formatMessage({id: 'sidebar_left.sidebar_channel_menu.editChannel', defaultMessage: 'Channel options'}),
|
text: formatMessage({id: 'sidebar_left.sidebar_channel_menu.editChannel', defaultMessage: 'Channel options'}),
|
||||||
}}
|
}}
|
||||||
menu={{
|
menu={{
|
||||||
id: `SidebarChannelMenu-MenuList-${props.channel.id}`,
|
id: `SidebarChannelMenu-MenuList-${channel.id}`,
|
||||||
'aria-label': formatMessage({id: 'sidebar_left.sidebar_channel_menu.dropdownAriaLabel', defaultMessage: 'Edit channel menu'}),
|
'aria-label': formatMessage({id: 'sidebar_left.sidebar_channel_menu.dropdownAriaLabel', defaultMessage: 'Edit channel menu'}),
|
||||||
onToggle: props.onMenuToggle,
|
onToggle: onMenuToggle,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{markAsReadUnreadMenuItem}
|
{markAsReadUnreadMenuItem}
|
||||||
{favoriteUnfavoriteMenuItem}
|
{favoriteUnfavoriteMenuItem}
|
||||||
{muteUnmuteChannelMenuItem}
|
{muteUnmuteChannelMenuItem}
|
||||||
<Menu.Separator/>
|
<Menu.Separator/>
|
||||||
<ChannelMoveToSubmenu channel={props.channel}/>
|
<ChannelMoveToSubmenu channel={channel}/>
|
||||||
{(copyLinkMenuItem || addMembersMenuItem) && <Menu.Separator/>}
|
{(copyLinkMenuItem || addMembersMenuItem) && <Menu.Separator/>}
|
||||||
{copyLinkMenuItem}
|
{copyLinkMenuItem}
|
||||||
{addMembersMenuItem}
|
{addMembersMenuItem}
|
||||||
|
@ -35,7 +35,7 @@ import SidebarCategory from '../sidebar_category';
|
|||||||
import UnreadChannelIndicator from '../unread_channel_indicator';
|
import UnreadChannelIndicator from '../unread_channel_indicator';
|
||||||
import UnreadChannels from '../unread_channels';
|
import UnreadChannels from '../unread_channels';
|
||||||
|
|
||||||
export function renderView(props: any) {
|
export function renderView(props: React.HTMLProps<HTMLDivElement>) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
{...props}
|
{...props}
|
||||||
@ -44,7 +44,7 @@ export function renderView(props: any) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function renderThumbHorizontal(props: any) {
|
export function renderThumbHorizontal(props: React.HTMLProps<HTMLDivElement>) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
{...props}
|
{...props}
|
||||||
@ -53,7 +53,7 @@ export function renderThumbHorizontal(props: any) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function renderTrackVertical(props: any) {
|
export function renderTrackVertical(props: React.HTMLProps<HTMLDivElement>) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
{...props}
|
{...props}
|
||||||
@ -62,7 +62,7 @@ export function renderTrackVertical(props: any) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function renderThumbVertical(props: any) {
|
export function renderThumbVertical(props: React.HTMLProps<HTMLDivElement>) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
{...props}
|
{...props}
|
||||||
|
@ -61,10 +61,9 @@ const GlobalThreadsLink = () => {
|
|||||||
const crtTutorialTrigger = useSelector((state: GlobalState) => getInt(state, Preferences.CRT_TUTORIAL_TRIGGERED, currentUserId, Constants.CrtTutorialTriggerSteps.START));
|
const crtTutorialTrigger = useSelector((state: GlobalState) => getInt(state, Preferences.CRT_TUTORIAL_TRIGGERED, currentUserId, Constants.CrtTutorialTriggerSteps.START));
|
||||||
const threads = useSelector(getThreadsInCurrentTeam);
|
const threads = useSelector(getThreadsInCurrentTeam);
|
||||||
const showTutorialTip = crtTutorialTrigger === CrtTutorialTriggerSteps.STARTED && tipStep === CrtTutorialSteps.WELCOME_POPOVER && threads.length >= 1;
|
const showTutorialTip = crtTutorialTrigger === CrtTutorialTriggerSteps.STARTED && tipStep === CrtTutorialSteps.WELCOME_POPOVER && threads.length >= 1;
|
||||||
const threadsCount = useSelector(getThreadCountsInCurrentTeam);
|
|
||||||
const rhsOpen = useSelector(getIsRhsOpen);
|
const rhsOpen = useSelector(getIsRhsOpen);
|
||||||
const rhsState = useSelector(getRhsState);
|
const rhsState = useSelector(getRhsState);
|
||||||
const showTutorialTrigger = isFeatureEnabled && crtTutorialTrigger === Constants.CrtTutorialTriggerSteps.START && !appHaveOpenModal && Boolean(threadsCount) && threadsCount.total >= 1;
|
const showTutorialTrigger = isFeatureEnabled && crtTutorialTrigger === Constants.CrtTutorialTriggerSteps.START && !appHaveOpenModal && Boolean(counts) && counts.total >= 1;
|
||||||
const openThreads = useCallback((e) => {
|
const openThreads = useCallback((e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
|
||||||
@ -79,7 +78,7 @@ const GlobalThreadsLink = () => {
|
|||||||
if (rhsOpen && rhsState === RHSStates.EDIT_HISTORY) {
|
if (rhsOpen && rhsState === RHSStates.EDIT_HISTORY) {
|
||||||
dispatch(closeRightHandSide());
|
dispatch(closeRightHandSide());
|
||||||
}
|
}
|
||||||
}, [showTutorialTrigger, threadsCount, threads, rhsOpen, rhsState]);
|
}, [showTutorialTrigger, counts, threads, rhsOpen, rhsState]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// load counts if necessary
|
// load counts if necessary
|
||||||
|
@ -1386,35 +1386,6 @@ describe('makeGetChannelsByCategory', () => {
|
|||||||
expect(result).toBe(previousResult);
|
expect(result).toBe(previousResult);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should return a new object when user profiles change', () => {
|
|
||||||
// This behaviour isn't ideal, but it's better than the previous version which returns a new object
|
|
||||||
// whenever anything user-related changes
|
|
||||||
const getChannelsByCategory = Selectors.makeGetChannelsByCategory();
|
|
||||||
|
|
||||||
const state = mergeObjects(baseState, {
|
|
||||||
entities: {
|
|
||||||
users: {
|
|
||||||
profiles: {
|
|
||||||
newUser: {id: 'newUser'},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const previousResult = getChannelsByCategory(baseState, 'team1');
|
|
||||||
const result = getChannelsByCategory(state, 'team1');
|
|
||||||
|
|
||||||
expect(result).not.toBe(previousResult);
|
|
||||||
expect(result).toEqual(previousResult);
|
|
||||||
|
|
||||||
// Categories not containing DMs/GMs and sorted alphabetically should still remain the same
|
|
||||||
expect(result.favoritesCategory).not.toBe(previousResult.favoritesCategory);
|
|
||||||
expect(result.favoritesCategory).toEqual(previousResult.favoritesCategory);
|
|
||||||
expect(result.channelsCategory).toBe(previousResult.channelsCategory);
|
|
||||||
expect(result.directMessagesCategory).toEqual(previousResult.directMessagesCategory);
|
|
||||||
expect(result.directMessagesCategory).toEqual(previousResult.directMessagesCategory);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should return the same object when other user state changes', () => {
|
test('should return the same object when other user state changes', () => {
|
||||||
const getChannelsByCategory = Selectors.makeGetChannelsByCategory();
|
const getChannelsByCategory = Selectors.makeGetChannelsByCategory();
|
||||||
|
|
||||||
|
@ -447,13 +447,18 @@ export function makeGetChannelsByCategory() {
|
|||||||
|
|
||||||
const channelsByCategory: RelationOneToOne<ChannelCategory, Channel[]> = {};
|
const channelsByCategory: RelationOneToOne<ChannelCategory, Channel[]> = {};
|
||||||
|
|
||||||
|
// TODO: This avoids some rendering, but there is a bigger issue underneath
|
||||||
|
// Every time myPreferences or myChannels change (which can happen for many
|
||||||
|
// unrelated reasons) the whole list of channels gets reordered and re-filtered.
|
||||||
|
let allEquals = categoryIds === lastCategoryIds;
|
||||||
for (const category of categories) {
|
for (const category of categories) {
|
||||||
const channels = getChannels[category.id](state, category.channel_ids);
|
const channels = getChannels[category.id](state, category.channel_ids);
|
||||||
channelsByCategory[category.id] = filterAndSortChannels[category.id](state, channels, category);
|
channelsByCategory[category.id] = filterAndSortChannels[category.id](state, channels, category);
|
||||||
|
allEquals = allEquals && shallowEquals(channelsByCategory[category.id], lastChannelsByCategory[category.id]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do a shallow equality check of channelsByCategory to avoid returning a new object containing the same data
|
// Do a shallow equality check of channelsByCategory to avoid returning a new object containing the same data
|
||||||
if (shallowEquals(channelsByCategory, lastChannelsByCategory)) {
|
if (allEquals) {
|
||||||
return lastChannelsByCategory;
|
return lastChannelsByCategory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1259,7 +1259,10 @@ export function getChannelModerations(state: GlobalState, channelId: string): Ch
|
|||||||
}
|
}
|
||||||
|
|
||||||
const EMPTY_OBJECT = {};
|
const EMPTY_OBJECT = {};
|
||||||
export function getChannelMemberCountsByGroup(state: GlobalState, channelId: string): ChannelMemberCountsByGroup {
|
export function getChannelMemberCountsByGroup(state: GlobalState, channelId?: string): ChannelMemberCountsByGroup {
|
||||||
|
if (!channelId) {
|
||||||
|
return EMPTY_OBJECT;
|
||||||
|
}
|
||||||
return state.entities.channels.channelMemberCountsByGroup[channelId] || EMPTY_OBJECT;
|
return state.entities.channels.channelMemberCountsByGroup[channelId] || EMPTY_OBJECT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,6 +83,56 @@ export function getGroupChannels(state: GlobalState, id: string) {
|
|||||||
return getGroupSyncables(state, id).channels;
|
return getGroupSyncables(state, id).channels;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const getAllCustomGroups: (state: GlobalState) => Group[] = createSelector(
|
||||||
|
'getAllCustomGroups',
|
||||||
|
getAllGroups,
|
||||||
|
(groups) => {
|
||||||
|
return Object.entries(groups).filter((entry) => (entry[1].allow_reference && entry[1].delete_at === 0 && entry[1].source === GroupSource.Custom)).map((entry) => entry[1]);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
export const getGroupsAssociatedToTeamForReference: (state: GlobalState, teamID: string) => Group[] = createSelector(
|
||||||
|
'getGroupsAssociatedToTeamForReference',
|
||||||
|
getAllGroups,
|
||||||
|
(state: GlobalState, teamID: string) => getTeamGroupIDSet(state, teamID),
|
||||||
|
(allGroups, teamGroupIDSet) => {
|
||||||
|
return Object.entries(allGroups).filter(([groupID]) => teamGroupIDSet.has(groupID)).filter((entry) => (entry[1].allow_reference && entry[1].delete_at === 0)).map((entry) => entry[1]);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
export const getAssociatedGroupsForReference: (state: GlobalState, teamId: string, channelId?: string) => Group[] = createSelector(
|
||||||
|
'getAssociatedGroupsForReference',
|
||||||
|
(state, teamId) => Boolean(getTeam(state, teamId)?.group_constrained),
|
||||||
|
(state, _, channelId) => Boolean(getChannel(state, channelId)?.group_constrained),
|
||||||
|
getGroupsAssociatedToTeamForReference,
|
||||||
|
(state, _, channelId) => (channelId ? getGroupsAssociatedToChannelForReference(state, channelId) : undefined),
|
||||||
|
getAllCustomGroups,
|
||||||
|
(state) => getAllAssociatedGroupsForReference(state, false),
|
||||||
|
(
|
||||||
|
teamConstrained,
|
||||||
|
channelConstrained,
|
||||||
|
groupsFromTeam,
|
||||||
|
groupsFromChannel,
|
||||||
|
customGroups,
|
||||||
|
allGroups,
|
||||||
|
) => {
|
||||||
|
if (teamConstrained && channelConstrained) {
|
||||||
|
const groupSet = new Set<Group>(groupsFromChannel);
|
||||||
|
return [...(groupsFromChannel || []), ...(groupsFromTeam.filter((item) => !groupSet.has(item))), ...customGroups];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (teamConstrained) {
|
||||||
|
return [...customGroups, ...groupsFromTeam];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (channelConstrained) {
|
||||||
|
return [...customGroups, ...(groupsFromChannel || [])];
|
||||||
|
}
|
||||||
|
|
||||||
|
return allGroups;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
export const getAssociatedGroupsByName: (state: GlobalState, teamID: string, channelId: string) => Record<string, Group> = createSelector(
|
export const getAssociatedGroupsByName: (state: GlobalState, teamID: string, channelId: string) => Record<string, Group> = createSelector(
|
||||||
'getAssociatedGroupsByName',
|
'getAssociatedGroupsByName',
|
||||||
getAssociatedGroupsForReference,
|
getAssociatedGroupsForReference,
|
||||||
@ -100,7 +150,7 @@ export const getAssociatedGroupsByName: (state: GlobalState, teamID: string, cha
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
export const getAssociatedGroupsForReferenceByMention: (state: GlobalState, teamID: string, channelId: string) => Map<string, Group> = createSelector(
|
export const getAssociatedGroupsForReferenceByMention: (state: GlobalState, teamID: string, channelId?: string) => Map<string, Group> = createSelector(
|
||||||
'getAssociatedGroupsForReferenceByMention',
|
'getAssociatedGroupsForReferenceByMention',
|
||||||
getAssociatedGroupsForReference,
|
getAssociatedGroupsForReference,
|
||||||
(groups) => {
|
(groups) => {
|
||||||
@ -117,30 +167,6 @@ export function searchAssociatedGroupsForReferenceLocal(state: GlobalState, term
|
|||||||
return filteredGroups;
|
return filteredGroups;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getAssociatedGroupsForReference(state: GlobalState, teamId: string, channelId: string): Group[] {
|
|
||||||
const team = getTeam(state, teamId);
|
|
||||||
const channel = getChannel(state, channelId);
|
|
||||||
|
|
||||||
let groupsForReference = [];
|
|
||||||
if (team && team.group_constrained && channel && channel.group_constrained) {
|
|
||||||
const groupsFromChannel = getGroupsAssociatedToChannelForReference(state, channelId);
|
|
||||||
const groupsFromTeam = getGroupsAssociatedToTeamForReference(state, teamId);
|
|
||||||
const customGroups = getAllCustomGroups(state);
|
|
||||||
groupsForReference = groupsFromChannel.concat(groupsFromTeam.filter((item) => groupsFromChannel.indexOf(item) < 0), customGroups);
|
|
||||||
} else if (team && team.group_constrained) {
|
|
||||||
const customGroups = getAllCustomGroups(state);
|
|
||||||
const groupsFromTeam = getGroupsAssociatedToTeamForReference(state, teamId);
|
|
||||||
groupsForReference = [...customGroups, ...groupsFromTeam];
|
|
||||||
} else if (channel && channel.group_constrained) {
|
|
||||||
const customGroups = getAllCustomGroups(state);
|
|
||||||
const groupsFromChannel = getGroupsAssociatedToChannelForReference(state, channelId);
|
|
||||||
groupsForReference = [...customGroups, ...groupsFromChannel];
|
|
||||||
} else {
|
|
||||||
groupsForReference = getAllAssociatedGroupsForReference(state, false);
|
|
||||||
}
|
|
||||||
return groupsForReference;
|
|
||||||
}
|
|
||||||
|
|
||||||
const teamGroupIDs = (state: GlobalState, teamID: string) => state.entities.teams.groupsAssociatedToTeam[teamID]?.ids || [];
|
const teamGroupIDs = (state: GlobalState, teamID: string) => state.entities.teams.groupsAssociatedToTeam[teamID]?.ids || [];
|
||||||
|
|
||||||
const channelGroupIDs = (state: GlobalState, channelID: string) => state.entities.channels.groupsAssociatedToChannel[channelID]?.ids || [];
|
const channelGroupIDs = (state: GlobalState, channelID: string) => state.entities.channels.groupsAssociatedToChannel[channelID]?.ids || [];
|
||||||
@ -209,15 +235,6 @@ export const getGroupsAssociatedToChannel: (state: GlobalState, channelID: strin
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
export const getGroupsAssociatedToTeamForReference: (state: GlobalState, teamID: string) => Group[] = createSelector(
|
|
||||||
'getGroupsAssociatedToTeamForReference',
|
|
||||||
getAllGroups,
|
|
||||||
(state: GlobalState, teamID: string) => getTeamGroupIDSet(state, teamID),
|
|
||||||
(allGroups, teamGroupIDSet) => {
|
|
||||||
return Object.entries(allGroups).filter(([groupID]) => teamGroupIDSet.has(groupID)).filter((entry) => (entry[1].allow_reference && entry[1].delete_at === 0)).map((entry) => entry[1]);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
export const getGroupsAssociatedToChannelForReference: (state: GlobalState, channelID: string) => Group[] = createSelector(
|
export const getGroupsAssociatedToChannelForReference: (state: GlobalState, channelID: string) => Group[] = createSelector(
|
||||||
'getGroupsAssociatedToChannelForReference',
|
'getGroupsAssociatedToChannelForReference',
|
||||||
getAllGroups,
|
getAllGroups,
|
||||||
@ -264,14 +281,6 @@ export const getAllGroupsForReferenceByName: (state: GlobalState) => Record<stri
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
export const getAllCustomGroups: (state: GlobalState) => Group[] = createSelector(
|
|
||||||
'getAllCustomGroups',
|
|
||||||
getAllGroups,
|
|
||||||
(groups) => {
|
|
||||||
return Object.entries(groups).filter((entry) => (entry[1].allow_reference && entry[1].delete_at === 0 && entry[1].source === GroupSource.Custom)).map((entry) => entry[1]);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
export const makeGetMyAllowReferencedGroups = () => {
|
export const makeGetMyAllowReferencedGroups = () => {
|
||||||
return createSelector(
|
return createSelector(
|
||||||
'makeGetMyAllowReferencedGroups',
|
'makeGetMyAllowReferencedGroups',
|
||||||
|
@ -142,7 +142,11 @@ export function makeGetChannelDraft() {
|
|||||||
const defaultDraft = Object.freeze({message: '', fileInfos: [], uploadsInProgress: [], createAt: 0, updateAt: 0, channelId: '', rootId: ''});
|
const defaultDraft = Object.freeze({message: '', fileInfos: [], uploadsInProgress: [], createAt: 0, updateAt: 0, channelId: '', rootId: ''});
|
||||||
const getDraft = makeGetGlobalItemWithDefault(defaultDraft);
|
const getDraft = makeGetGlobalItemWithDefault(defaultDraft);
|
||||||
|
|
||||||
return (state: GlobalState, channelId: string): PostDraft => {
|
return (state: GlobalState, channelId?: string): PostDraft => {
|
||||||
|
if (!channelId) {
|
||||||
|
return defaultDraft;
|
||||||
|
}
|
||||||
|
|
||||||
const draft = getDraft(state, StoragePrefixes.DRAFT + channelId);
|
const draft = getDraft(state, StoragePrefixes.DRAFT + channelId);
|
||||||
if (
|
if (
|
||||||
typeof draft.message !== 'undefined' &&
|
typeof draft.message !== 'undefined' &&
|
||||||
|
Loading…
Reference in New Issue
Block a user