Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,832 changes: 1,104 additions & 728 deletions webapp/package-lock.json

Large diffs are not rendered by default.

57 changes: 38 additions & 19 deletions webapp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
"dependencies": {
"@apollo/client": "3.7.3",
"@floating-ui/react": "0.26.28",
"@mattermost/client": "10.9.0",
"@mattermost/client": "11.1.0-2",
"@mattermost/compass-icons": "0.1.32",
"@mattermost/types": "10.9.0",
"@mattermost/types": "11.1.0-2",
"@mdi/js": "^6.5.95",
"@mdi/react": "1.5.0",
"@tanstack/react-table": "8.10.7",
Expand All @@ -24,22 +24,23 @@
"js-trim-multiline-string": "^1.0.8",
"lodash": "4.17.21",
"luxon": "3.6.1",
"mattermost-redux": "10.9.0",
"mattermost-redux": "11.1.0-2",
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I updated mattermost-redux and the client/type packages because I forgot that mattermost-redux had a dependency on a specific major version of Redux. I cut these adhoc releases off of the latest 11.1 branch of the monorepo, and we can replace them with proper ones after 11.1.0 releases

"parse-duration": "2.1.4",
"qs": "6.10.5",
"react": "^17.0.2",
"react": "18.2.0",
"react-beautiful-dnd": "13.1.1",
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This moved from being a devDependency despite being bundled with Playbooks since it's not exposed by the web app

"react-chartjs-2": "4.3.1",
"react-custom-scrollbars": "4.2.1",
"react-dom": "^17.0.2",
"react-dom": "18.2.0",
"react-infinite-scroll-component": "^6.1.0",
"react-infinite-scroller": "1.2.6",
"react-intl": "7.1.11",
"react-redux": "7.2.6",
"react-redux": "9.2.0",
"react-router-dom": "5.3.4",
"react-router-hash-link": "2.4.3",
"react-select": "4.3.1",
"react-use": "17.3.2",
"redux": "4.1.2",
"react-use": "17.3.3",
"redux": "5.0.1",
"styled-components": "5.3.7",
"typescript": "5.6.3"
},
Expand All @@ -60,18 +61,17 @@
"@types/lodash": "4.14.178",
"@types/luxon": "3.6.2",
"@types/qs": "6.9.7",
"@types/react": "^17.0.2",
"@types/react": "18.2.64",
"@types/react-beautiful-dnd": "13.1.2",
"@types/react-bootstrap": "1.0.1",
"@types/react-bootstrap": "0.32.35",
"@types/react-custom-scrollbars": "4.0.10",
"@types/react-dom": "^17.0.2",
"@types/react-dom": "18.2.25",
"@types/react-infinite-scroller": "1.2.3",
"@types/react-redux": "7.1.21",
"@types/redux-mock-store": "1.5.0",
"@types/react-router-dom": "5.3.3",
"@types/react-router-hash-link": "2.4.5",
"@types/react-select": "3.1.2",
"@types/react-test-renderer": "17.0.1",
"@types/redux-mock-store": "1.0.3",
"@types/shallow-equals": "1.0.0",
"@types/styled-components": "5.1.26",
"@typescript-eslint/eslint-plugin": "8.32.0",
Expand Down Expand Up @@ -102,14 +102,14 @@
"jest-canvas-mock": "2.3.1",
"jest-environment-jsdom": "29.7.0",
"jest-junit": "13.0.0",
"patch-package": "8.0.1",
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is temporary until I either merge mattermost/react-bootstrap#6 or figure out a better way to modify its dependency without it

"postcss-styled-syntax": "0.7.1",
"process": "0.11.10",
"react-beautiful-dnd": "13.1.0",
"react-bootstrap": "1.6.1",
"react-bootstrap": "github:mattermost/react-bootstrap#05559f4c61c5a314783c390d2d82906ee8c7e558",
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As mentioned elsewhere, this is only used during development, but it'll now match the web app's version instead of accidentally depending on a newer version of React Bootstrap

"react-refresh": "0.11.0",
"react-test-renderer": "17.0.2",
"redux-mock-store": "1.5.4",
"redux-thunk": "2.4.1",
"react-test-renderer": "18.2.0",
"redux-thunk": "3.1.0",
"sass": "1.46.0",
"sass-loader": "12.4.0",
"style-loader": "3.3.1",
Expand All @@ -122,9 +122,25 @@
"webpack-dev-server": "4.15.1"
},
"overrides": {
"@testing-library/react-hooks": {
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't upgrade a few of these dependencies because newer versions required some further changes.

This library doesn't support React 18, but it seems to work fine for now. It needs to be replaced with @testing-library/react which has some breaking changes to renderHook

"@types/react": "$@types/react",
"react": "$react",
"react-dom": "$react-dom",
"react-test-renderer": "$react-test-renderer"
},
"@types/redux-mock-store": {
"redux": "$redux"
},
"react-custom-scrollbars": {
"react": "17.0.2",
"react-dom": "17.0.2"
"react": "$react",
"react-dom": "$react-dom"
Comment on lines +135 to +136
Copy link
Copy Markdown
Member Author

@hmhealey hmhealey Oct 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

react-custom-scrollbars doesn't support React 17 or higher, so it will need to be replaced down the line. In the web app, I replaced it with simplebar-react (mattermost/mattermost#33783)

},
"react-input-autosize": {
"react": "$react"
},
"react-select": {
"react": "$react",
"react-dom": "$react-dom"
Comment on lines +138 to +143
Copy link
Copy Markdown
Member Author

@hmhealey hmhealey Oct 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The web app uses a newer version of React Select (5.9.0) which supports React 18 and has some accessibility improvements, but upgrading requires some breaking changes.

React Select 5 also removes the dependency on react-input-autosize, so we can remove that when React Select is upgraded

}
},
"scripts": {
Expand Down Expand Up @@ -190,6 +206,9 @@
"setupFiles": [
"jest-canvas-mock"
],
"setupFilesAfterEnv": [
"<rootDir>/src/setupTests.ts"
],
"testEnvironmentOptions": {
"url": "http://localhost:8065"
}
Expand Down
2 changes: 1 addition & 1 deletion webapp/src/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ export function setToggleRHSAction(toggleRHSPluginAction: () => void): ReceivedT

export function toggleRHS() {
return (dispatch: Dispatch<AnyAction>, getState: GetStateFunc) => {
selectToggleRHS(getState())();
selectToggleRHS(getState())?.();
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {useSelector} from 'react-redux';
import ReactSelect, {ControlProps} from 'react-select';

import styled from 'styled-components';
import {ActionFuncAsync} from 'mattermost-redux/types/actions';
import {ActionResult} from 'mattermost-redux/types/actions';
import {GlobalState} from '@mattermost/types/store';
import {UserProfile} from '@mattermost/types/users';
import {getUser} from 'mattermost-redux/selectors/entities/users';
Expand All @@ -21,8 +21,8 @@ import MenuList from 'src/components/backstage/playbook_edit/automation/menu_lis
interface Props {
ownerID: string;
onAddUser: (userid: string) => void;
searchProfiles: (term: string) => ActionFuncAsync;
getProfiles: () => ActionFuncAsync;
searchProfiles: (term: string) => Promise<ActionResult<UserProfile[]>>;
getProfiles: () => Promise<ActionResult<UserProfile[]>>;
isDisabled: boolean;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@

import React from 'react';

import {ActionFuncAsync} from 'mattermost-redux/types/actions';
import {ActionResult} from 'mattermost-redux/types/actions';

import {FormattedMessage} from 'react-intl';

import {UserProfile} from '@mattermost/types/users';

import {AutomationHeader, AutomationTitle, SelectorWrapper} from 'src/components/backstage/playbook_edit/automation/styles';
import AssignOwnerSelector from 'src/components/backstage/playbook_edit/automation/assign_owner_selector';
import {Toggle} from 'src/components/backstage/playbook_edit/automation/toggle';
Expand All @@ -15,8 +17,8 @@ interface Props {
enabled: boolean;
disabled?: boolean;
onToggle: () => void;
searchProfiles: (term: string) => ActionFuncAsync;
getProfiles: () => ActionFuncAsync;
searchProfiles: (term: string) => Promise<ActionResult<UserProfile[]>>;
getProfiles: () => Promise<ActionResult<UserProfile[]>>;
ownerID: string;
onAssignOwner: (userId: string | undefined) => void;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@

import React, {useState} from 'react';

import {ActionFuncAsync} from 'mattermost-redux/types/actions';
import {ActionResult} from 'mattermost-redux/types/actions';

import {FormattedMessage, useIntl} from 'react-intl';

import {UserProfile} from '@mattermost/types/users';

import {AutomationHeader, AutomationTitle, SelectorWrapper} from 'src/components/backstage/playbook_edit/automation/styles';
import {Toggle} from 'src/components/backstage/playbook_edit/automation/toggle';
import InviteUsersSelector from 'src/components/backstage/playbook_edit/automation/invite_users_selector';
Expand All @@ -16,8 +18,8 @@ interface Props {
enabled: boolean;
disabled?: boolean;
onToggle: () => void;
searchProfiles: (term: string) => ActionFuncAsync;
getProfiles: () => ActionFuncAsync;
searchProfiles: (term: string) => Promise<ActionResult<UserProfile[]>>;
getProfiles: () => Promise<ActionResult<UserProfile[]>>;
userIds: string[];
preAssignedUserIds: string[];
onAddUser: (userId: string) => void;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {useSelector} from 'react-redux';
import ReactSelect, {ControlProps, GroupType, OptionsType} from 'react-select';

import styled from 'styled-components';
import {ActionFuncAsync} from 'mattermost-redux/types/actions';
import {ActionResult} from 'mattermost-redux/types/actions';
import {UserProfile} from '@mattermost/types/users';
import {GlobalState} from '@mattermost/types/store';
import {getUser} from 'mattermost-redux/selectors/entities/users';
Expand All @@ -22,8 +22,8 @@ interface Props {
userIds: string[];
onAddUser: (userid: string) => void;
onRemoveUser: (userid: string, username: string) => void;
searchProfiles: (term: string) => ActionFuncAsync;
getProfiles: () => ActionFuncAsync;
searchProfiles: (term: string) => Promise<ActionResult<UserProfile[]>>;
getProfiles: () => Promise<ActionResult<UserProfile[]>>;
isDisabled: boolean;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ const ThumbVertical = styled.div`
`;

const MenuList = <T extends OptionTypeBase>(props: MenuListComponentProps<T, false>) => {
const renderThumbVertical = useCallback((thumbProps) => {
const renderThumbVertical = useCallback((thumbProps: Record<string, unknown>) => {
const thumbPropsWithoutStyle = {...thumbProps};
Reflect.deleteProperty(thumbPropsWithoutStyle, 'style');
return <ThumbVertical {...thumbPropsWithoutStyle}/>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,8 @@ const PlaybookEditor = () => {

const archivedTooltip = archived && (
<Tooltip
delay={{show: 0, hide: 1000}}
delayShow={0}
delayHide={1000}
Comment on lines +92 to +93
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These might be a functional change because the API used before wouldn't have worked with the provided version of React Bootstrap as best as I can tell.

We've stopped using these components instead of Floating UI in the web app though because we suspected that OverlayTrigger had a memory leak

id={`archive-${playbook.id}`}
content={formatMessage({defaultMessage: 'This playbook is archived.'})}
>
Expand All @@ -99,7 +100,8 @@ const PlaybookEditor = () => {

const privateTooltip = !playbook.public && (
<Tooltip
delay={{show: 0, hide: 1000}}
delayShow={0}
delayHide={1000}
id={`private-${playbook.id}`}
content={formatMessage({defaultMessage: 'This playbook is private.'})}
>
Expand Down
3 changes: 2 additions & 1 deletion webapp/src/components/backstage/playbook_list_row.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,8 @@ const PlaybookListRow = (props: Props) => {
if (props.playbook.delete_at > 0) {
infos.push((
<Tooltip
delay={{show: 0, hide: 1000}}
delayShow={0}
delayHide={1000}
id={`archive-${props.playbook.id}`}
content={formatMessage({defaultMessage: 'This playbook is archived.'})}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,12 @@ import React from 'react';
import Tooltip from 'src/components/widgets/tooltip';
import {CompassIcon} from 'src/types/compass';

declare module 'react-bootstrap/esm/OverlayTrigger' {
interface OverlayTriggerProps {
shouldUpdatePosition?: boolean;
declare module 'react-bootstrap' {
// eslint-disable-next-line @typescript-eslint/no-namespace
namespace OverlayTrigger {
interface OverlayTriggerProps {
shouldUpdatePosition?: boolean;
}
}
}

Expand Down
8 changes: 4 additions & 4 deletions webapp/src/components/backstage/profile_autocomplete.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {debounce} from 'debounce';
import AsyncSelect from 'react-select/async';

import styled from 'styled-components';
import {ActionFuncAsync} from 'mattermost-redux/types/actions';
import {ActionResult} from 'mattermost-redux/types/actions';
import {UserProfile} from '@mattermost/types/users';
import {
ControlProps,
Expand Down Expand Up @@ -76,8 +76,8 @@ interface Props {
userIds: string[];
onAddUser?: (userid: string) => void; // for single select
setValues?: (values: UserProfile[]) => void; // for multi select
searchProfiles: (term: string) => ActionFuncAsync;
getProfiles?: () => ActionFuncAsync;
searchProfiles: (term: string) => Promise<ActionResult<UserProfile[]>>;
getProfiles?: () => Promise<ActionResult<UserProfile[]>>;
isDisabled?: boolean;
isMultiMode?: boolean;
customSelectStyles?: StylesConfig<OptionTypeBase, boolean>;
Expand Down Expand Up @@ -132,7 +132,7 @@ const ProfileAutocomplete = (props: Props) => {

//@ts-ignore
profiles.then(({data}) => {
callback(data);
callback(data || []);
}).catch(() => {
// eslint-disable-next-line no-console
console.error('Error searching user profiles in custom attribute settings dropdown.');
Expand Down
8 changes: 5 additions & 3 deletions webapp/src/components/backstage/select_users_below.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// See LICENSE.txt for license information.

import React from 'react';
import {ActionFuncAsync} from 'mattermost-redux/types/actions';
import {ActionResult} from 'mattermost-redux/types/actions';
import {FormattedMessage} from 'react-intl';
import styled from 'styled-components';

Expand All @@ -16,6 +16,8 @@ import {getTeammateNameDisplaySetting} from 'mattermost-redux/selectors/entities

import {displayUsername} from 'mattermost-redux/utils/user_utils';

import {UserProfile} from '@mattermost/types/users';

import Profile from 'src/components/profile/profile';

import {Playbook, PlaybookMember} from 'src/types/playbook';
Expand Down Expand Up @@ -66,8 +68,8 @@ export interface SelectUsersBelowProps {
onRemoveUser: (userid: string) => void;
onMakeAdmin: (userid: string) => void;
onMakeMember: (userid: string) => void;
searchProfiles: (term: string) => ActionFuncAsync;
getProfiles: () => ActionFuncAsync;
searchProfiles: (term: string) => Promise<ActionResult<UserProfile[]>>;
getProfiles: () => Promise<ActionResult<UserProfile[]>>;
}

function roleDisplayText(roles: string[]) {
Expand Down
2 changes: 1 addition & 1 deletion webapp/src/components/modals/update_run_status_modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ const UpdateRunStatusModal = ({
}
const followersChannelCount = run?.followers?.length ?? 0;

const OverviewLink = (...chunks: string[]): ReactNode => (
const OverviewLink = (...chunks: ReactNode[]): ReactNode => (
<Link
data-testid='run-overview-link'
to={pluginUrl(`/runs/${playbookRunId}?from=status_modal`)}
Expand Down
9 changes: 4 additions & 5 deletions webapp/src/components/profile/profile_selector.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// Copyright (c) 2020-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.

import React, {useEffect, useState} from 'react';
import {useSelector, useStore} from 'react-redux';
import React, {useEffect, useMemo, useState} from 'react';
import {useSelector} from 'react-redux';
import {useIntl} from 'react-intl';
import ReactSelect, {ActionTypes, ControlProps, StylesConfig} from 'react-select';

Expand Down Expand Up @@ -88,9 +88,8 @@ export default function ProfileSelector(props: Props) {

// props.userGroups?.subsetUserIds are not guaranteed to be in the page returned by props.getAllUsers
// but they're expected to be at redux
const getProfiles = makeGetProfilesByIdsAndUsernames();
const store = useStore();
const usersInSubset = getProfiles(store.getState(), {allUserIds: props.userGroups?.subsetUserIds || [], allUsernames: []});
const getProfiles = useMemo(() => makeGetProfilesByIdsAndUsernames(), []);
const usersInSubset = useSelector((state: GlobalState) => getProfiles(state, {allUserIds: props.userGroups?.subsetUserIds || [], allUsernames: []}));
Comment on lines +91 to +92
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did a bit extra here to fix an incorrectly memoized selector


useUpdateEffect(() => {
props.onOpenChange?.(isOpen);
Expand Down
2 changes: 1 addition & 1 deletion webapp/src/components/widgets/confirmation_modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ export default class ConfirmModal extends React.Component<Props, State> {
<StyledModal
dialogClassName={'a11y__modal GenericModal'}
show={this.props.show}
onHide={this.props.onCancel}
onHide={this.handleCancel}
onExited={this.props.onExited}
id='confirmModal'
role='dialog'
Expand Down
2 changes: 1 addition & 1 deletion webapp/src/components/widgets/generic_modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ type Props = {
enforceFocus?: boolean;
footer?: React.ReactNode;
components?: Partial<{
Header: typeof Modal.Header;
Header: ComponentType;
FooterContainer: ComponentType<{children: React.ReactNode}>;
}>;
adjustTop?: number;
Expand Down
Loading
Loading