MM-64380 Remove compass components (#33744)

* Remove Flex component

* Remove Heading component

* Remove StatusIcon component

* Migrate IconButton from Compass Components repo

* Remove unused variants of IconButton and move into GlobalHeader

We only actually used IconButton in a limited set of locations (all
currently in the global header), and if I tried to test other
variations, they seemed to often have issues (like white text on a white
background). Most of those seemed to be because the theme in the
CompassThemeProvider was missing fields and fell back to defaults that
didn't make sense, but there were also enough errors in IconButtonRoot
(like invalid transitions or other logical errors) that lead me to just
rip out everything we don't currently use.

* Remove CompassThemeProvider

* Remove remaining references to @mattermost/compass-components

* Remove prop that's no longer needed
This commit is contained in:
Harrison Healey
2025-08-20 17:16:11 -04:00
committed by GitHub
parent 99190bdcb7
commit 13a6e06093
40 changed files with 347 additions and 564 deletions
-15
View File
@@ -1061,21 +1061,6 @@ For more information on this, and how to apply and follow the GNU AGPL, see
<http://www.gnu.org/licenses/>.
---
## @mattermost/compass-components
This product contains '@mattermost/compass-components' by Mattermost.
components aligning to the compass design system
* HOMEPAGE:
* https://github.com/mattermost/compass-components#readme
* LICENSE: MIT
---
## @mattermost/compass-icons
+1 -1
View File
@@ -37,7 +37,7 @@ const config = {
['jest-junit', {outputDirectory: 'build', outputName: 'test-results.xml'}],
],
transformIgnorePatterns: [
'node_modules/(?!react-native|react-router|pdfjs-dist|p-queue|p-timeout|@mattermost/compass-components|@mattermost/compass-icons|cidr-regex|ip-regex|serialize-error)',
'node_modules/(?!react-native|react-router|pdfjs-dist|p-queue|p-timeout|@mattermost/compass-icons|cidr-regex|ip-regex|serialize-error)',
],
transform: {
'^.+\\.(js|jsx|ts|tsx|mjs)$': 'babel-jest',
-4
View File
@@ -11,7 +11,6 @@
"@giphy/react-components": "8.1.0",
"@guyplusplus/turndown-plugin-gfm": "1.0.7",
"@mattermost/client": "10.11.0",
"@mattermost/compass-components": "^0.2.12",
"@mattermost/desktop-api": "5.10.0-2",
"@mattermost/dynamic-virtualized-list": "github:mattermost/dynamic-virtualized-list#08dde0c34a12d0384740db27d55e398d139d7a51",
"@mattermost/types": "10.11.0",
@@ -172,9 +171,6 @@
"yargs": "17.7.2"
},
"overrides": {
"@mattermost/compass-components": {
"axios": "1.7.9"
},
"@mattermost/desktop-api": {
"typescript": "$typescript"
}
@@ -91,7 +91,6 @@ describe('CloudUsageModal', () => {
props = {
title: '',
onClose: jest.fn(),
needsTheme: false,
};
});
@@ -2,16 +2,12 @@
// See LICENSE.txt for license information.
import React from 'react';
import {useSelector} from 'react-redux';
import {GenericModal} from '@mattermost/components';
import type {Limits} from '@mattermost/types/cloud';
import {getTheme} from 'mattermost-redux/selectors/entities/preferences';
import useGetLimits from 'components/common/hooks/useGetLimits';
import useGetUsage from 'components/common/hooks/useGetUsage';
import CompassThemeProvider from 'components/compass_theme_provider/compass_theme_provider';
import type {Message} from 'utils/i18n';
@@ -33,17 +29,13 @@ export interface Props {
backdrop?: boolean;
backdropClassName?: string;
className?: string;
// e.g. in contexts where the CompassThemeProvider isn't already applied, like the system console
needsTheme?: boolean;
}
export default function CloudUsageModal(props: Props) {
const [limits] = useGetLimits();
const usage = useGetUsage();
const theme = useSelector(getTheme);
const modal = (
return (
<GenericModal
handleCancel={props.onClose}
compassDesign={true}
@@ -68,14 +60,4 @@ export default function CloudUsageModal(props: Props) {
</>
</GenericModal>
);
if (!props.needsTheme) {
return modal;
}
return (
<CompassThemeProvider theme={theme}>
{modal}
</CompassThemeProvider>
);
}
@@ -66,7 +66,6 @@ export default function useShowAdminLimitReached() {
onClose: () => {
dispatch(closeModal(ModalIdentifiers.CLOUD_LIMITS));
},
needsTheme: true,
};
// Only show primary action if not air-gapped
@@ -1,66 +0,0 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React, {useMemo} from 'react';
import ThemeProvider, {lightTheme} from '@mattermost/compass-components/utilities/theme'; // eslint-disable-line no-restricted-imports
import type {Theme} from 'mattermost-redux/selectors/entities/preferences';
type Props = {
theme: Theme;
children?: React.ReactNode;
}
const CompassThemeProvider = ({
theme,
children,
}: Props) => {
const compassTheme = useMemo(() => {
const base = {
...lightTheme,
noStyleReset: true,
noDefaultStyle: true,
noFontFaces: true,
};
return {
...base,
palette: {
...base.palette,
primary: {
...base.palette.primary,
main: theme.sidebarHeaderBg,
contrast: theme.sidebarHeaderTextColor,
},
alert: {
...base.palette.alert,
main: theme.dndIndicator,
},
},
action: {
...base.action,
hover: theme.sidebarHeaderTextColor,
disabled: theme.sidebarHeaderTextColor,
},
badges: {
...base.badges,
online: theme.onlineIndicator,
away: theme.awayIndicator,
dnd: theme.dndIndicator,
},
text: {
...base.text,
primary: theme.sidebarHeaderTextColor,
},
};
}, [theme]);
return (
<ThemeProvider theme={compassTheme}>
{children}
</ThemeProvider>
);
};
export default CompassThemeProvider;
@@ -9,11 +9,8 @@ import type {DayModifiers, DayPickerProps} from 'react-day-picker';
import {useIntl} from 'react-intl';
import {useSelector} from 'react-redux';
import {getTheme} from 'mattermost-redux/selectors/entities/preferences';
import {getCurrentLocale} from 'selectors/i18n';
import CompassThemeProvider from 'components/compass_theme_provider/compass_theme_provider';
import DatePicker from 'components/date_picker';
import * as Menu from 'components/menu';
import Timestamp from 'components/timestamp';
@@ -77,7 +74,6 @@ const DateTimeInputContainer: React.FC<Props> = ({
const [isTimeMenuOpen, setIsTimeMenuOpen] = useState(false);
const [menuWidth, setMenuWidth] = useState<string>('200px');
const {formatMessage} = useIntl();
const theme = useSelector(getTheme);
const timeContainerRef = useRef<HTMLDivElement>(null);
const handlePopperOpenState = useCallback((isOpen: boolean) => {
@@ -175,83 +171,81 @@ const DateTimeInputContainer: React.FC<Props> = ({
};
return (
<CompassThemeProvider theme={theme}>
<div className='dateTime'>
<div className='dateTime__date'>
<DatePicker
isPopperOpen={isPopperOpen}
handlePopperOpenState={handlePopperOpenState}
locale={locale}
datePickerProps={datePickerProps}
label={formatMessage({
id: 'datetime.date',
defaultMessage: 'Date',
})}
icon={calendarIcon}
value={formatDate(time)}
>
<></>
</DatePicker>
</div>
<div
className='dateTime__time'
ref={timeContainerRef}
<div className='dateTime'>
<div className='dateTime__date'>
<DatePicker
isPopperOpen={isPopperOpen}
handlePopperOpenState={handlePopperOpenState}
locale={locale}
datePickerProps={datePickerProps}
label={formatMessage({
id: 'datetime.date',
defaultMessage: 'Date',
})}
icon={calendarIcon}
value={formatDate(time)}
>
<Menu.Container
menuButton={{
id: 'time_button',
dataTestId: 'time_button',
'aria-label': formatMessage({
id: 'datetime.time',
defaultMessage: 'Time',
}),
class: isTimeMenuOpen ? 'date-time-input date-time-input--open' : 'date-time-input',
children: (
<>
<span className='date-time-input__label'>{formatMessage({
id: 'datetime.time',
defaultMessage: 'Time',
})}</span>
<span className='date-time-input__icon'>{clockIcon}</span>
<span className='date-time-input__value'>
<Timestamp
useRelative={false}
useDate={false}
value={time.toString()}
/>
</span>
</>
),
}}
menu={{
id: 'expiryTimeMenu',
'aria-label': formatMessage({id: 'time_dropdown.choose_time', defaultMessage: 'Choose a time'}),
onToggle: handleTimeMenuToggle,
width: menuWidth,
className: 'time-menu-scrollable',
}}
>
{timeOptions.map((option, index) => (
<Menu.Item
key={index}
id={`time_option_${index}`}
data-testid={`time_option_${index}`}
labels={
<span>
<Timestamp
useRelative={false}
useDate={false}
value={option}
/>
</span>
}
onClick={() => handleTimeChange(option)}
/>
))}
</Menu.Container>
</div>
<></>
</DatePicker>
</div>
</CompassThemeProvider>
<div
className='dateTime__time'
ref={timeContainerRef}
>
<Menu.Container
menuButton={{
id: 'time_button',
dataTestId: 'time_button',
'aria-label': formatMessage({
id: 'datetime.time',
defaultMessage: 'Time',
}),
class: isTimeMenuOpen ? 'date-time-input date-time-input--open' : 'date-time-input',
children: (
<>
<span className='date-time-input__label'>{formatMessage({
id: 'datetime.time',
defaultMessage: 'Time',
})}</span>
<span className='date-time-input__icon'>{clockIcon}</span>
<span className='date-time-input__value'>
<Timestamp
useRelative={false}
useDate={false}
value={time.toString()}
/>
</span>
</>
),
}}
menu={{
id: 'expiryTimeMenu',
'aria-label': formatMessage({id: 'time_dropdown.choose_time', defaultMessage: 'Choose a time'}),
onToggle: handleTimeMenuToggle,
width: menuWidth,
className: 'time-menu-scrollable',
}}
>
{timeOptions.map((option, index) => (
<Menu.Item
key={index}
id={`time_option_${index}`}
data-testid={`time_option_${index}`}
labels={
<span>
<Timestamp
useRelative={false}
useDate={false}
value={option}
/>
</span>
}
onClick={() => handleTimeChange(option)}
/>
))}
</Menu.Container>
</div>
</div>
);
};
@@ -8,9 +8,6 @@ import {FormattedMessage, injectIntl, type WrappedComponentProps} from 'react-in
import {GenericModal} from '@mattermost/components';
import type {UserStatus} from '@mattermost/types/users';
import type {Theme} from 'mattermost-redux/selectors/entities/preferences';
import CompassThemeProvider from 'components/compass_theme_provider/compass_theme_provider';
import DateTimeInput from 'components/datetime_input/datetime_input';
import Constants, {UserStatuses} from 'utils/constants';
@@ -26,7 +23,6 @@ type Props = {
currentDate: Date;
locale: string;
theme: Theme;
actions: {
setStatus: (status: UserStatus) => void;
};
@@ -121,31 +117,29 @@ export default injectIntl(class DndCustomTimePicker extends React.PureComponent<
const {selectedDateTime} = this.state;
return (
<CompassThemeProvider theme={this.props.theme}>
<GenericModal
compassDesign={true}
ariaLabel={localizeMessage({id: 'dnd_custom_time_picker_modal.defaultMsg', defaultMessage: 'Disable notifications until'})}
onExited={this.props.onExited}
modalHeaderText={modalHeaderText}
confirmButtonText={confirmButtonText}
handleConfirm={this.handleConfirm}
handleEnterKeyPress={this.handleConfirm}
id='dndCustomTimePickerModal'
className={'DndModal modal-overflow'}
tabIndex={-1}
keyboardEscape={true}
enforceFocus={false}
>
<div className='DndModal__content'>
<DateTimeInput
time={selectedDateTime}
handleChange={this.handleDateTimeChange}
timezone={this.props.locale}
relativeDate={true}
/>
</div>
</GenericModal>
</CompassThemeProvider>
<GenericModal
compassDesign={true}
ariaLabel={localizeMessage({id: 'dnd_custom_time_picker_modal.defaultMsg', defaultMessage: 'Disable notifications until'})}
onExited={this.props.onExited}
modalHeaderText={modalHeaderText}
confirmButtonText={confirmButtonText}
handleConfirm={this.handleConfirm}
handleEnterKeyPress={this.handleConfirm}
id='dndCustomTimePickerModal'
className={'DndModal modal-overflow'}
tabIndex={-1}
keyboardEscape={true}
enforceFocus={false}
>
<div className='DndModal__content'>
<DateTimeInput
time={selectedDateTime}
handleChange={this.handleDateTimeChange}
timezone={this.props.locale}
relativeDate={true}
/>
</div>
</GenericModal>
);
}
});
@@ -7,7 +7,6 @@ import {bindActionCreators} from 'redux';
import type {Dispatch} from 'redux';
import {setStatus} from 'mattermost-redux/actions/users';
import {getTheme} from 'mattermost-redux/selectors/entities/preferences';
import {getCurrentUserId} from 'mattermost-redux/selectors/entities/users';
import {getCurrentLocale} from 'selectors/i18n';
@@ -21,12 +20,10 @@ const DndCustomTimePicker = makeAsyncComponent('DndCustomTimePicker', React.lazy
function mapStateToProps(state: GlobalState) {
const userId = getCurrentUserId(state);
const locale = getCurrentLocale(state);
const theme = getTheme(state);
return {
userId,
locale,
theme,
};
}
@@ -0,0 +1,11 @@
.GlobalSearchNav {
display: flex;
max-width: 432px;
flex: 1;
flex-direction: row;
flex-wrap: nowrap;
align-items: center;
justify-content: initial;
padding: 0;
margin: 0;
}
@@ -4,8 +4,6 @@
import React, {useEffect} from 'react';
import {useDispatch, useSelector} from 'react-redux';
import Flex from '@mattermost/compass-components/utilities/layout/Flex'; // eslint-disable-line no-restricted-imports
import {closeRightHandSide, showMentions} from 'actions/views/rhs';
import {getRhsState} from 'selectors/rhs';
@@ -19,6 +17,8 @@ import * as Keyboard from 'utils/keyboard';
import type {GlobalState} from 'types/store';
import './global_search_nav.css';
const GlobalSearchNav = (): JSX.Element => {
const dispatch = useDispatch();
const rhsState = useSelector((state: GlobalState) => getRhsState(state));
@@ -44,14 +44,9 @@ const GlobalSearchNav = (): JSX.Element => {
}, [rhsState, dispatch]);
return (
<Flex
row={true}
width={432}
flex={1}
alignment='center'
>
<div className='GlobalSearchNav'>
<NewSearch/>
</Flex>
</div>
);
};
@@ -15,16 +15,13 @@ exports[`components/channel_header/components/UserGuideDropdown should match sna
/>
}
>
<ForwardRef
<HeaderIconButton
active={false}
aria-controls="AddChannelDropdown"
aria-expanded={false}
aria-label="Help"
compact={true}
icon="help-circle-outline"
inverted={true}
onClick={[Function]}
size="sm"
/>
</WithTooltip>
<Menu
@@ -90,16 +87,13 @@ exports[`components/channel_header/components/UserGuideDropdown should match sna
/>
}
>
<ForwardRef
<HeaderIconButton
active={false}
aria-controls="AddChannelDropdown"
aria-expanded={false}
aria-label="Help"
compact={true}
icon="help-circle-outline"
inverted={true}
onClick={[Function]}
size="sm"
/>
</WithTooltip>
<Menu
@@ -157,16 +151,13 @@ exports[`components/channel_header/components/UserGuideDropdown should match sna
/>
}
>
<ForwardRef
<HeaderIconButton
active={false}
aria-controls="AddChannelDropdown"
aria-expanded={false}
aria-label="Help"
compact={true}
icon="help-circle-outline"
inverted={true}
onClick={[Function]}
size="sm"
/>
</WithTooltip>
<Menu
@@ -5,10 +5,9 @@ import React from 'react';
import {FormattedMessage, injectIntl} from 'react-intl';
import type {WrappedComponentProps} from 'react-intl';
import IconButton from '@mattermost/compass-components/components/icon-button'; // eslint-disable-line no-restricted-imports
import {trackEvent} from 'actions/telemetry_actions';
import IconButton from 'components/global_header/header_icon_button';
import KeyboardShortcutsModal from 'components/keyboard_shortcuts/keyboard_shortcuts_modal/keyboard_shortcuts_modal';
import Menu from 'components/widgets/menu/menu';
import MenuWrapper from 'components/widgets/menu/menu_wrapper';
@@ -139,12 +138,9 @@ class UserGuideDropdown extends React.PureComponent<Props, State> {
title={tooltipText}
>
<IconButton
size={'sm'}
icon={'help-circle-outline'}
onClick={() => {}} // icon button currently requires onclick ... needs to revisit
active={this.state.buttonActive}
inverted={true}
compact={true}
aria-controls='AddChannelDropdown'
aria-expanded={this.state.buttonActive}
aria-label={intl.formatMessage({id: 'channel_header.userHelpGuide', defaultMessage: 'Help'})}
@@ -2,13 +2,8 @@
// See LICENSE.txt for license information.
import React from 'react';
import {useSelector} from 'react-redux';
import styled from 'styled-components';
import {getTheme} from 'mattermost-redux/selectors/entities/preferences';
import CompassThemeProvider from 'components/compass_theme_provider/compass_theme_provider';
import {useCurrentProductId} from 'utils/products';
import CenterControls from './center_controls/center_controls';
@@ -39,20 +34,17 @@ const GlobalHeaderContainer = styled.header`
const GlobalHeader = (): JSX.Element | null => {
const isLoggedIn = useIsLoggedIn();
const currentProductID = useCurrentProductId();
const theme = useSelector(getTheme);
if (!isLoggedIn) {
return null;
}
return (
<CompassThemeProvider theme={theme}>
<GlobalHeaderContainer id='global-header'>
<LeftControls/>
<CenterControls productId={currentProductID}/>
<RightControls productId={currentProductID}/>
</GlobalHeaderContainer>
</CompassThemeProvider>
<GlobalHeaderContainer id='global-header'>
<LeftControls/>
<CenterControls productId={currentProductID}/>
<RightControls productId={currentProductID}/>
</GlobalHeaderContainer>
);
};
@@ -0,0 +1,84 @@
/* stylelint-disable no-duplicate-selectors */
.HeaderIconButton {
display: flex;
overflow: visible;
width: auto;
align-items: center;
justify-content: center;
padding: 6px;
border: none;
border-radius: 4px;
margin: 0;
background: rgba(var(--bg-color), var(--bg-opacity));
color: rgba(var(--text-color), var(--text-opacity));
font: inherit;
outline: none;
text-align: inherit;
--bg-color: var(--sidebar-header-text-color-rgb);
--text-color: var(--sidebar-header-text-color-rgb);
&--toggled:not(:disabled) {
--text-color: var(--sidebar-header-bg-rgb);
}
&:not(:disabled) {
--bg-opacity: 0;
--text-opacity: 0.56;
&:hover {
--bg-opacity: 0.08;
--text-opacity: 0.72;
}
&.HeaderIconButton--toggled {
--bg-opacity: 1;
--text-opacity: 1;
&:hover {
--bg-opacity: 0.92;
--text-opacity: 1;
}
}
&.HeaderIconButton--active, &:active {
--bg-opacity: 0.16;
--text-opacity: 1;
}
}
&:disabled {
cursor: no-allowed;
--bg-opacity: 0;
--text-opacity: 0.32;
}
&:focus-visible {
box-shadow: inset 0 0 0 2px rgba(255, 255, 255, 0.32),
inset 0 0 0 2px var(--sidebar-header-bg);
}
& > i {
position: relative;
display: inline-flex;
width: 16px;
height: 16px;
align-items: center;
justify-content: center;
padding: 0;
color: inherit;
&::before {
margin: 0;
font-size: 18px;
letter-spacing: 18px;
line-height: 1;
}
}
}
@@ -0,0 +1,36 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import classNames from 'classnames';
import React from 'react';
import './header_icon_button.scss';
type HeaderIconButtonProps = React.HTMLAttributes<HTMLButtonElement> & {
icon: string;
active?: boolean;
toggled?: boolean;
};
const HeaderIconButton = React.forwardRef<HTMLButtonElement, HeaderIconButtonProps>(({
icon = 'mattermost',
active,
toggled,
...otherProps
}, ref) => {
return (
<button
ref={ref}
className={classNames('HeaderIconButton', {
'HeaderIconButton--toggled': toggled,
'HeaderIconButton--active': active,
})}
{...otherProps}
>
<i className={`icon-${icon}`}/>
</button>
);
});
HeaderIconButton.displayName = 'HeaderIconButton';
export default HeaderIconButton;
@@ -0,0 +1,6 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import HeaderIconButton from './header_icon_button';
export default HeaderIconButton;
@@ -6,10 +6,9 @@ import {useIntl} from 'react-intl';
import {useHistory} from 'react-router-dom';
import styled from 'styled-components';
import IconButton from '@mattermost/compass-components/components/icon-button'; // eslint-disable-line no-restricted-imports
import {trackEvent} from 'actions/telemetry_actions';
import IconButton from 'components/global_header/header_icon_button';
import KeyboardShortcutSequence, {
KEYBOARD_SHORTCUTS,
} from 'components/keyboard_shortcuts/keyboard_shortcuts_sequence';
@@ -78,9 +77,6 @@ const HistoryButtons = (): JSX.Element => {
<IconButton
icon={'arrow-left'}
onClick={goBack}
size={'sm'}
compact={true}
inverted={true}
disabled={!canGoBack}
aria-label={intl.formatMessage({id: 'sidebar_left.channel_navigator.goBackLabel', defaultMessage: 'Back'})}
/>
@@ -91,9 +87,6 @@ const HistoryButtons = (): JSX.Element => {
<IconButton
icon={'arrow-right'}
onClick={goForward}
size={'sm'}
compact={true}
inverted={true}
disabled={!canGoForward}
aria-label={intl.formatMessage({id: 'sidebar_left.channel_navigator.goForwardLabel', defaultMessage: 'Forward'})}
/>
@@ -7,14 +7,11 @@ exports[`components/ProductBranding should show correct icon glyph when we are o
<ProductBoardsIcon
size={24}
/>
<Heading
<h1
className="sr-only"
element="h1"
margin="none"
size={200}
>
Boards
</Heading>
</h1>
<ProductBrandingHeading>
Boards
</ProductBrandingHeading>
@@ -28,14 +25,11 @@ exports[`components/ProductBranding should show correct icon glyph when we are o
<ProductChannelsIcon
size={24}
/>
<Heading
<h1
className="sr-only"
element="h1"
margin="none"
size={200}
>
Channels
</Heading>
</h1>
<ProductBrandingHeading>
Channels
</ProductBrandingHeading>
@@ -49,14 +43,11 @@ exports[`components/ProductBranding should show correct icon glyph when we are o
<ProductPlaybooksIcon
size={24}
/>
<Heading
<h1
className="sr-only"
element="h1"
margin="none"
size={200}
>
Playbooks
</Heading>
</h1>
<ProductBrandingHeading>
Playbooks
</ProductBrandingHeading>
@@ -4,7 +4,6 @@
import React from 'react';
import styled from 'styled-components';
import Heading from '@mattermost/compass-components/components/heading'; // eslint-disable-line no-restricted-imports
import glyphMap, {ProductChannelsIcon} from '@mattermost/compass-icons/components';
import {useCurrentProduct} from 'utils/products';
@@ -14,8 +13,6 @@ const ProductBrandingContainer = styled.span`
align-items: center;
`;
// Every style here except for 'margin-left' and 'font-family'is from the deprecated 'Heading' element.
// https://github.com/mattermost/compass-components/blob/362e96a4eb3489efc8c1852652859ef14a51eb64/src/components/heading/Heading.mixins.ts#L9-L74
const ProductBrandingHeading = styled.span`
font-family: 'Metropolis';
font-size: 16px;
@@ -35,17 +32,9 @@ const ProductBranding = (): JSX.Element => {
return (
<ProductBrandingContainer tabIndex={-1}>
<Icon size={24}/>
{/* Heading for screen readers since an h1 shouldn't be inside a button */}
<Heading
element='h1'
size={200}
margin='none'
className='sr-only'
>
<h1 className='sr-only'>
{currentProduct ? currentProduct.switcherText : 'Channels'}
</Heading>
</h1>
<ProductBrandingHeading>
{currentProduct ? currentProduct.switcherText : 'Channels'}
</ProductBrandingHeading>
@@ -27,15 +27,12 @@ exports[`components/global/AtMentionsButton should match snapshot 1`] = `
</React.Fragment>
}
>
<ForwardRef
<HeaderIconButton
aria-controls="searchContainer"
aria-expanded={false}
aria-label="Recent mentions"
compact={true}
icon="at"
inverted={true}
onClick={[Function]}
size="sm"
toggled={false}
/>
</WithTooltip>
@@ -4,7 +4,7 @@
import {shallow} from 'enzyme';
import React from 'react';
import IconButton from '@mattermost/compass-components/components/icon-button'; // eslint-disable-line no-restricted-imports
import IconButton from 'components/global_header/header_icon_button';
import type {GlobalState} from 'types/store';
@@ -5,11 +5,10 @@ import React from 'react';
import {FormattedMessage, useIntl} from 'react-intl';
import {useDispatch, useSelector} from 'react-redux';
import IconButton from '@mattermost/compass-components/components/icon-button'; // eslint-disable-line no-restricted-imports
import {closeRightHandSide, showMentions} from 'actions/views/rhs';
import {getRhsState} from 'selectors/rhs';
import IconButton from 'components/global_header/header_icon_button';
import KeyboardShortcutSequence, {KEYBOARD_SHORTCUTS} from 'components/keyboard_shortcuts/keyboard_shortcuts_sequence';
import WithTooltip from 'components/with_tooltip';
@@ -48,12 +47,9 @@ const AtMentionsButton = (): JSX.Element => {
}
>
<IconButton
size={'sm'}
icon={'at'}
toggled={rhsState === RHSStates.MENTION}
onClick={mentionButtonClick}
inverted={true}
compact={true}
aria-expanded={rhsState === RHSStates.MENTION}
aria-controls='searchContainer' // Must be changed if the ID of the container changes
aria-label={formatMessage({id: 'channel_header.recentMentions', defaultMessage: 'Recent mentions'})}
@@ -9,15 +9,12 @@ exports[`components/global/AtMentionsButton should match snapshot 1`] = `
/>
}
>
<ForwardRef
<HeaderIconButton
aria-controls="searchContainer"
aria-expanded={false}
aria-label="Saved messages"
compact={true}
icon="bookmark-outline"
inverted={true}
onClick={[Function]}
size="sm"
toggled={false}
/>
</WithTooltip>
@@ -4,7 +4,7 @@
import {shallow} from 'enzyme';
import React from 'react';
import IconButton from '@mattermost/compass-components/components/icon-button'; // eslint-disable-line no-restricted-imports
import IconButton from 'components/global_header/header_icon_button';
import type {GlobalState} from 'types/store';
@@ -5,11 +5,10 @@ import React from 'react';
import {FormattedMessage, useIntl} from 'react-intl';
import {useDispatch, useSelector} from 'react-redux';
import IconButton from '@mattermost/compass-components/components/icon-button'; // eslint-disable-line no-restricted-imports
import {closeRightHandSide, showFlaggedPosts} from 'actions/views/rhs';
import {getRhsState} from 'selectors/rhs';
import IconButton from 'components/global_header/header_icon_button';
import WithTooltip from 'components/with_tooltip';
import {RHSStates} from 'utils/constants';
@@ -40,12 +39,9 @@ const SavedPostsButton = (): JSX.Element | null => {
}
>
<IconButton
size={'sm'}
icon={'bookmark-outline'}
toggled={rhsState === RHSStates.FLAG}
onClick={savedPostsButtonClick}
inverted={true}
compact={true}
aria-expanded={rhsState === RHSStates.FLAG}
aria-controls='searchContainer' // Must be changed if the ID of the container changes
aria-label={formatMessage({id: 'channel_header.flagged', defaultMessage: 'Saved messages'})}
@@ -4,8 +4,7 @@
import React from 'react';
import {FormattedMessage, useIntl} from 'react-intl';
import IconButton from '@mattermost/compass-components/components/icon-button'; // eslint-disable-line no-restricted-imports
import IconButton from 'components/global_header/header_icon_button';
import UserSettingsModal from 'components/user_settings/modal';
import WithTooltip from 'components/with_tooltip';
@@ -32,13 +31,10 @@ const SettingsButton = (props: Props): JSX.Element | null => {
}
>
<IconButton
size={'sm'}
icon={'settings-outline'}
onClick={(): void => {
props.actions.openModal({modalId: ModalIdentifiers.USER_SETTINGS, dialogType: UserSettingsModal, dialogProps: {isContentProductSettings: true, focusOriginElement: 'settings_button'}});
}}
inverted={true}
compact={true}
aria-haspopup='dialog'
aria-label={formatMessage({id: 'global_header.productSettings', defaultMessage: 'Settings'})}
/>
@@ -10,7 +10,7 @@ import type {Team} from '@mattermost/types/teams';
import {General} from 'mattermost-redux/constants';
import deepFreeze from 'mattermost-redux/utils/deep_freeze';
import {mountWithThemedIntl} from 'tests/helpers/themed-intl-test-helper';
import {mountWithIntl} from 'tests/helpers/intl-test-helper';
import mockStore from 'tests/test_store';
import {SelfHostedProducts} from 'utils/constants';
import {TestHelper} from 'utils/test_helper';
@@ -116,7 +116,7 @@ describe('InvitationModal', () => {
});
it('shows invite view when view state is invite', () => {
const wrapper = mountWithThemedIntl(
const wrapper = mountWithIntl(
<Provider store={store}>
<InvitationModal {...props}/>
</Provider>,
@@ -125,7 +125,7 @@ describe('InvitationModal', () => {
});
it('shows result view when view state is result', () => {
const wrapper = mountWithThemedIntl(
const wrapper = mountWithIntl(
<Provider store={store}>
<InvitationModal {...props}/>
</Provider>,
@@ -142,7 +142,7 @@ describe('InvitationModal', () => {
canAddUsers: false,
canInviteGuests: false,
};
const wrapper = mountWithThemedIntl(
const wrapper = mountWithIntl(
<Provider store={store}>
<InvitationModal {...props}/>
</Provider>,
@@ -172,7 +172,7 @@ describe('InvitationModal', () => {
invitableChannels: [regularChannel, policyEnforcedChannel],
};
const wrapper = mountWithThemedIntl(
const wrapper = mountWithIntl(
<Provider store={store}>
<InvitationModal {...props}/>
</Provider>,
@@ -9,7 +9,7 @@ import type {Team} from '@mattermost/types/teams';
import deepFreeze from 'mattermost-redux/utils/deep_freeze';
import {mountWithThemedIntl} from 'tests/helpers/themed-intl-test-helper';
import {mountWithIntl} from 'tests/helpers/intl-test-helper';
import mockStore from 'tests/test_store';
import {SelfHostedProducts} from 'utils/constants';
import {TestHelper as TH} from 'utils/test_helper';
@@ -127,7 +127,7 @@ describe('InviteView', () => {
it('shows InviteAs component when user can choose to invite guests or users', async () => {
await act(async () => {
const wrapper = mountWithThemedIntl(
const wrapper = mountWithIntl(
<Provider store={store}>
<InviteView {...props}/>
</Provider>,
@@ -143,7 +143,7 @@ describe('InviteView', () => {
};
await act(async () => {
const wrapper = mountWithThemedIntl(
const wrapper = mountWithIntl(
<Provider store={store}>
<InviteView {...props}/>
</Provider>,
@@ -159,7 +159,7 @@ describe('InviteView', () => {
};
await act(async () => {
const wrapper = mountWithThemedIntl(
const wrapper = mountWithIntl(
<Provider store={store}>
<InviteView {...props}/>
</Provider>,
@@ -5,11 +5,8 @@ import React, {lazy} from 'react';
import type {RouteComponentProps} from 'react-router-dom';
import {Route} from 'react-router-dom';
import type {Theme} from 'mattermost-redux/selectors/entities/preferences';
import {makeAsyncComponent} from 'components/async_load';
import CloudPreviewModalController from 'components/cloud_preview_modal/cloud_preview_modal_controller';
import CompassThemeProvider from 'components/compass_theme_provider/compass_theme_provider';
import LoggedIn from 'components/logged_in';
const OnBoardingTaskList = makeAsyncComponent('OnboardingTaskList', lazy(() => import('components/onboarding_tasklist')));
@@ -17,23 +14,18 @@ const OnBoardingTaskList = makeAsyncComponent('OnboardingTaskList', lazy(() => i
type Props = {
component: React.ComponentType<RouteComponentProps<any>>;
path: string | string[];
theme?: Theme; // the routes that send the theme are the ones that will actually need to show the onboarding tasklist
};
export default function LoggedInRoute(props: Props) {
const {component: Component, theme, ...rest} = props;
const {component: Component, ...rest} = props;
return (
<Route
{...rest}
render={(routeProps) => (
<LoggedIn {...routeProps}>
{theme && (
<CompassThemeProvider theme={theme}>
<OnBoardingTaskList/>
<CloudPreviewModalController/>
</CompassThemeProvider>
)}
<OnBoardingTaskList/>
<CloudPreviewModalController/>
<Component {...(routeProps)}/>
</LoggedIn>
)}
@@ -15,14 +15,12 @@ import {getConfig, getLicense} from 'mattermost-redux/selectors/entities/general
import {
getBool,
getMyPreferences as getMyPreferencesSelector,
getTheme,
} from 'mattermost-redux/selectors/entities/preferences';
import {getCurrentUserId} from 'mattermost-redux/selectors/entities/users';
import {trackEvent} from 'actions/telemetry_actions';
import {getShowTaskListBool} from 'selectors/onboarding';
import CompassThemeProvider from 'components/compass_theme_provider/compass_theme_provider';
import {useFirstAdminUser, useIsCurrentUserSystemAdmin} from 'components/global_header/hooks';
import {
useTasksListWithStatus,
@@ -157,7 +155,6 @@ const OnBoardingTaskList = (): JSX.Element | null => {
getShowTaskListBool,
(a, b) => a[0] === b[0] && a[1] === b[1],
);
const theme = useSelector(getTheme);
const startTask = (taskName: string) => {
toggleTaskList();
@@ -254,7 +251,7 @@ const OnBoardingTaskList = (): JSX.Element | null => {
}
return (
<CompassThemeProvider theme={theme}>
<>
<CompletedAnimation completed={showAnimation}/>
<Button
onClick={toggleTaskList}
@@ -315,7 +312,7 @@ const OnBoardingTaskList = (): JSX.Element | null => {
)}
</TaskItems>
</TaskListPopover>
</CompassThemeProvider>
</>
);
};
@@ -4,8 +4,6 @@
import React from 'react';
import styled from 'styled-components';
import StatusIcon from '@mattermost/compass-components/components/status-icon'; // eslint-disable-line no-restricted-imports
const Animation = styled.div`
position: absolute;
z-index: 30;
@@ -33,6 +31,23 @@ const Animation = styled.div`
right: 0;
}
.icon-check-circle {
width: 16px;
height: 16px;
color: var(--online-indicator);
position: relative;
display: inline-flex;
align-items: center;
justify-content: center;
::before {
font-size: 18px;
letter-spacing: 18px;
margin: 0;
}
}
.x1 {
opacity: 0;
animation-delay: 150ms;
@@ -64,34 +79,34 @@ const Animation = styled.div`
}
}
@keyframes moveUp {
0% {
0% {
top: 0;
}
100% {
100% {
top: -50px;
}
}
@keyframes opacity {
0% {
0% {
opacity:0;
}
50% {
50% {
opacity: 1;
}
100% {
100% {
opacity: 0;
}
}
@keyframes scale {
0% {
0% {
transform: scale(0);
}
50% {
50% {
transform: scale(2);
}
100% {
100% {
transform: scale(4);
}
}
@@ -101,22 +116,10 @@ const Animation = styled.div`
export const CompletedAnimation = (props: {completed: boolean}) => {
return (
<Animation className={props.completed ? 'completed' : ''}>
<StatusIcon
status={'online'}
className={'x1'}
/>
<StatusIcon
status={'online'}
className={'x2'}
/>
<StatusIcon
status={'online'}
className={'x3'}
/>
<StatusIcon
status={'online'}
className={'x4'}
/>
<i className='icon-check-circle x1'/>
<i className='icon-check-circle x2'/>
<i className='icon-check-circle x3'/>
<i className='icon-check-circle x4'/>
</Animation>
);
};
@@ -5,8 +5,6 @@ import {screen, fireEvent} from '@testing-library/react';
import React from 'react';
import type {ComponentProps} from 'react';
import type {Theme} from 'mattermost-redux/selectors/entities/preferences';
import {renderWithContext} from 'tests/react_testing_utils';
import {ModalIdentifiers} from 'utils/constants';
import {TestHelper} from 'utils/test_helper';
@@ -22,7 +20,6 @@ describe('components/post_edit_history/edited_post_item', () => {
message: 'post message',
}),
isCurrent: false,
theme: {} as Theme,
postCurrentVersion: TestHelper.getPostMock({
id: 'post_current_version_id',
message: 'post current version message',
@@ -10,13 +10,11 @@ import {CheckIcon} from '@mattermost/compass-icons/components';
import type {Post} from '@mattermost/types/posts';
import {getPostEditHistory, restorePostVersion} from 'mattermost-redux/actions/posts';
import type {Theme} from 'mattermost-redux/selectors/entities/preferences';
import {ensureString} from 'mattermost-redux/utils/post_utils';
import {removeDraft} from 'actions/views/drafts';
import {getConnectionId} from 'selectors/general';
import CompassThemeProvider from 'components/compass_theme_provider/compass_theme_provider';
import FileAttachmentListContainer from 'components/file_attachment_list';
import InfoToast from 'components/info_toast/info_toast';
import PostAriaLabelDiv from 'components/post_view/post_aria_label_div';
@@ -58,10 +56,9 @@ const itemMessages = defineMessages({
export type Props = PropsFromRedux & {
post: Post;
isCurrent?: boolean;
theme: Theme;
}
const EditedPostItem = ({post, isCurrent = false, postCurrentVersion, theme, actions}: Props) => {
const EditedPostItem = ({post, isCurrent = false, postCurrentVersion, actions}: Props) => {
const {formatMessage} = useIntl();
const [open, setOpen] = useState(isCurrent);
@@ -220,40 +217,38 @@ const EditedPostItem = ({post, isCurrent = false, postCurrentVersion, theme, act
const timeStampValue = post.edit_at === 0 ? post.create_at : post.edit_at;
return (
<CompassThemeProvider theme={theme}>
<div
className={postContainerClass}
onClick={togglePost}
<div
className={postContainerClass}
onClick={togglePost}
>
<PostAriaLabelDiv
className={'a11y__section post'}
id={'searchResult_' + post.id}
post={post}
>
<PostAriaLabelDiv
className={'a11y__section post'}
id={'searchResult_' + post.id}
post={post}
<div
className='edit-post-history__title__container'
>
<div
className='edit-post-history__title__container'
>
<div className='edit-post-history__date__badge__container'>
<button
aria-label='Toggle to see an old message.'
className='edit-post-history__icon__button toggleCollapseButton'
>
<i className={`icon ${open ? 'icon-chevron-down' : 'icon-chevron-right'}`}/>
</button>
<span className='edit-post-history__date'>
<Timestamp
value={timeStampValue}
ranges={DATE_RANGES}
/>
</span>
{currentVersionIndicator}
</div>
{restoreButton}
<div className='edit-post-history__date__badge__container'>
<button
aria-label='Toggle to see an old message.'
className='edit-post-history__icon__button toggleCollapseButton'
>
<i className={`icon ${open ? 'icon-chevron-down' : 'icon-chevron-right'}`}/>
</button>
<span className='edit-post-history__date'>
<Timestamp
value={timeStampValue}
ranges={DATE_RANGES}
/>
</span>
{currentVersionIndicator}
</div>
{open && messageContainer}
</PostAriaLabelDiv>
</div>
</CompassThemeProvider>
{restoreButton}
</div>
{open && messageContainer}
</PostAriaLabelDiv>
</div>
);
};
@@ -7,7 +7,6 @@ import {bindActionCreators} from 'redux';
import type {Dispatch} from 'redux';
import {getPost} from 'mattermost-redux/selectors/entities/posts';
import {getTheme} from 'mattermost-redux/selectors/entities/preferences';
import {openModal} from 'actions/views/modals';
import {editPost} from 'actions/views/posts';
@@ -20,10 +19,8 @@ import EditedPostItem from './edited_post_item';
function mapStateToProps(state: GlobalState) {
const selectedPostId = getSelectedPostId(state) || '';
const theme = getTheme(state);
return {
theme,
postCurrentVersion: getPost(state, selectedPostId),
};
}
+10 -13
View File
@@ -12,7 +12,6 @@ import {ServiceEnvironment} from '@mattermost/types/config';
import {setSystemEmojis} from 'mattermost-redux/actions/emojis';
import {setUrl} from 'mattermost-redux/actions/general';
import {Client4} from 'mattermost-redux/client';
import {Preferences} from 'mattermost-redux/constants';
import {measurePageLoadTelemetry, temporarilySetPageLoadContext, trackEvent} from 'actions/telemetry_actions.jsx';
import BrowserStore from 'stores/browser_store';
@@ -69,7 +68,6 @@ const CreateTeam = makeAsyncComponent('CreateTeam', lazy(() => import('component
const Mfa = makeAsyncComponent('Mfa', lazy(() => import('components/mfa/mfa_controller')));
const PreparingWorkspace = makeAsyncComponent('PreparingWorkspace', lazy(() => import('components/preparing_workspace')));
const LaunchingWorkspace = makeAsyncComponent('LaunchingWorkspace', lazy(() => import('components/preparing_workspace/launching_workspace')));
const CompassThemeProvider = makeAsyncComponent('CompassThemeProvider', lazy(() => import('components/compass_theme_provider/compass_theme_provider')));
const TeamController = makeAsyncComponent('TeamController', lazy(() => import('components/team_controller')));
const AnnouncementBarController = makeAsyncComponent('AnnouncementBarController', lazy(() => import('components/announcement_bar')));
const SystemNotice = makeAsyncComponent('SystemNotice', lazy(() => import('components/system_notice')));
@@ -454,7 +452,6 @@ export default class Root extends React.PureComponent<Props, State> {
>
<Switch>
<LoggedInRoute
theme={Preferences.THEMES.denim}
path={'/admin_console'}
component={AdminConsole}
/>
@@ -489,16 +486,17 @@ export default class Root extends React.PureComponent<Props, State> {
from={'/_redirect/pl/:postid'}
to={`/${this.props.permalinkRedirectTeamName}/pl/:postid`}
/>
<CompassThemeProvider theme={this.props.theme}>
<>
{(this.props.showLaunchingWorkspace && !this.props.location.pathname.includes('/preparing-workspace') &&
<LaunchingWorkspace
fullscreen={true}
zIndex={LAUNCHING_WORKSPACE_FULLSCREEN_Z_INDEX}
show={true}
onPageView={noop}
transitionDirection={Animations.Reasons.EnterFromBefore}
/>
<LaunchingWorkspace
fullscreen={true}
zIndex={LAUNCHING_WORKSPACE_FULLSCREEN_Z_INDEX}
show={true}
onPageView={noop}
transitionDirection={Animations.Reasons.EnterFromBefore}
/>
)}
<WindowSizeObserver/>
<ModalController/>
<AnnouncementBarController/>
@@ -568,7 +566,6 @@ export default class Root extends React.PureComponent<Props, State> {
/>
))}
<LoggedInRoute
theme={this.props.theme}
path={`/:team(${TEAM_NAME_PATH_PATTERN})`}
component={TeamController}
/>
@@ -579,7 +576,7 @@ export default class Root extends React.PureComponent<Props, State> {
<Pluggable pluggableName='Global'/>
<AppBar/>
<Readout/>
</CompassThemeProvider>
</>
</Switch>
</RootProvider>
);
@@ -1,50 +0,0 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import type {Theme} from 'mattermost-redux/selectors/entities/preferences';
import CompassThemeProvider from 'components/compass_theme_provider/compass_theme_provider';
import {mountWithIntl} from './intl-test-helper';
const stubValue = '#fff';
const DEFAULT_THEME: Theme = {
type: 'custom',
sidebarBg: stubValue,
sidebarText: stubValue,
sidebarUnreadText: stubValue,
sidebarTextHoverBg: stubValue,
sidebarTextActiveBorder: stubValue,
sidebarTextActiveColor: stubValue,
sidebarHeaderBg: stubValue,
sidebarTeamBarBg: stubValue,
sidebarHeaderTextColor: stubValue,
onlineIndicator: stubValue,
awayIndicator: stubValue,
dndIndicator: stubValue,
mentionBg: stubValue,
mentionBj: stubValue,
mentionColor: stubValue,
centerChannelBg: stubValue,
centerChannelColor: stubValue,
newMessageSeparator: stubValue,
linkColor: stubValue,
buttonBg: stubValue,
buttonColor: stubValue,
errorTextColor: stubValue,
mentionHighlightBg: stubValue,
mentionHighlightLink: stubValue,
codeTheme: stubValue,
};
export const mountWithThemedIntl = (children: React.ReactNode | React.ReactNodeArray, theme?: Theme) => {
return mountWithIntl(
<CompassThemeProvider
theme={theme || DEFAULT_THEME}
>
{children}
</CompassThemeProvider>,
);
};
-85
View File
@@ -65,7 +65,6 @@
"@giphy/react-components": "8.1.0",
"@guyplusplus/turndown-plugin-gfm": "1.0.7",
"@mattermost/client": "10.11.0",
"@mattermost/compass-components": "^0.2.12",
"@mattermost/desktop-api": "5.10.0-2",
"@mattermost/dynamic-virtualized-list": "github:mattermost/dynamic-virtualized-list#08dde0c34a12d0384740db27d55e398d139d7a51",
"@mattermost/types": "10.11.0",
@@ -304,40 +303,6 @@
"react-dom": ">=16.8.0"
}
},
"channels/node_modules/@mattermost/compass-components": {
"version": "0.2.12",
"resolved": "https://registry.npmjs.org/@mattermost/compass-components/-/compass-components-0.2.12.tgz",
"integrity": "sha512-45ObrULlchyH8cNwGbb18ifsBSMtKHFo/VxBIxl1tNvrhqgD+tNafvlz9pO+Xy+1yFkm/pZtYr2aqZpXGXeQ8Q==",
"dependencies": {
"@mattermost/compass-icons": "^0.1.10",
"@popperjs/core": "^2.9.2",
"axios": "^0.21.1",
"clsx": "^1.1.1",
"color-blend": "^3.0.1",
"csstype": "^3.0.8",
"lodash.kebabcase": "^4.1.1",
"lodash.random": "^3.2.0",
"lodash.upperfirst": "^4.3.1",
"react-popper": "^2.2.5",
"react-transition-group": "^4.4.2",
"styled-components": "^5.2.1"
},
"engines": {
"node": ">=14.0.0"
},
"peerDependencies": {
"react": "16.13.1 || ^17.0.1",
"react-dom": "16.13.1 || ^17.0.1"
}
},
"channels/node_modules/@mattermost/compass-components/node_modules/axios": {
"version": "0.21.4",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz",
"integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==",
"dependencies": {
"follow-redirects": "^1.14.0"
}
},
"channels/node_modules/@stylistic/stylelint-plugin": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/@stylistic/stylelint-plugin/-/stylelint-plugin-3.1.2.tgz",
@@ -10497,14 +10462,6 @@
"integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==",
"dev": true
},
"node_modules/color-blend": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/color-blend/-/color-blend-3.0.1.tgz",
"integrity": "sha512-KueDvNiKHAvVeApic0SxHZLyy4x3NELfTLzMHRpRRLi+9e2kWhpeWvtuH3Sjb92mOJYEUhRjb8z7lr4OqDv17Q==",
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/color-contrast-checker": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/color-contrast-checker/-/color-contrast-checker-2.1.0.tgz",
@@ -20559,32 +20516,17 @@
"integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==",
"dev": true
},
"node_modules/lodash.kebabcase": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz",
"integrity": "sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g=="
},
"node_modules/lodash.merge": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="
},
"node_modules/lodash.random": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/lodash.random/-/lodash.random-3.2.0.tgz",
"integrity": "sha512-A6Vn7teN0+qSnhOsE8yx2bGowCS1G7D9e5abq8VhwOP98YHS/KrGMf43yYxA05lvcvloT+W9Z2ffkSajFTcPUA=="
},
"node_modules/lodash.truncate": {
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz",
"integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==",
"dev": true
},
"node_modules/lodash.upperfirst": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/lodash.upperfirst/-/lodash.upperfirst-4.3.1.tgz",
"integrity": "sha512-sReKOYJIJf74dhJONhU4e0/shzi1trVbSWDOhKYE5XV2O+H7Sb2Dihwuc7xWxVl+DgFPyTqIN3zMfT9cq5iWDg=="
},
"node_modules/loose-envify": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
@@ -23244,11 +23186,6 @@
"react": ">=16.13.1"
}
},
"node_modules/react-fast-compare": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz",
"integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ=="
},
"node_modules/react-intl": {
"version": "6.6.2",
"resolved": "https://registry.npmjs.org/react-intl/-/react-intl-6.6.2.tgz",
@@ -23353,28 +23290,6 @@
"react-dom": ">=15.0.0"
}
},
"node_modules/react-popper": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/react-popper/-/react-popper-2.3.0.tgz",
"integrity": "sha512-e1hj8lL3uM+sgSR4Lxzn5h1GxBlpa4CQz0XLF8kx4MDrDRWY0Ena4c97PUeSX9i5W3UAfDP0z0FXCTQkoXUl3Q==",
"dependencies": {
"react-fast-compare": "^3.0.1",
"warning": "^4.0.2"
},
"peerDependencies": {
"@popperjs/core": "^2.0.0",
"react": "^16.8.0 || ^17 || ^18",
"react-dom": "^16.8.0 || ^17 || ^18"
}
},
"node_modules/react-popper/node_modules/warning": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz",
"integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==",
"dependencies": {
"loose-envify": "^1.0.0"
}
},
"node_modules/react-prop-types": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/react-prop-types/-/react-prop-types-0.4.0.tgz",
@@ -374,12 +374,6 @@
"no-restricted-imports": [
"error",
{
"patterns": [
{
"group": ["@mattermost/compass-components/*"],
"message": "compass-components is now archived."
}
],
"paths": [
{
"name": "redux",