From f762f4247b776c31b861814170c4ee27c7dcba7f Mon Sep 17 00:00:00 2001 From: Kirill Lakhov Date: Thu, 18 Jul 2024 15:28:08 +0300 Subject: [PATCH 1/6] store disabled state in app state --- cvat-ui/src/actions/requests-actions.ts | 4 ++++ .../src/components/requests-page/request-card.tsx | 13 +++++++------ .../src/components/requests-page/requests-list.tsx | 11 +++++++++-- cvat-ui/src/reducers/index.ts | 2 +- cvat-ui/src/reducers/requests-reducer.ts | 9 ++++++++- 5 files changed, 29 insertions(+), 10 deletions(-) diff --git a/cvat-ui/src/actions/requests-actions.ts b/cvat-ui/src/actions/requests-actions.ts index ed3438a2225c..6a62e7cecf7c 100644 --- a/cvat-ui/src/actions/requests-actions.ts +++ b/cvat-ui/src/actions/requests-actions.ts @@ -21,6 +21,7 @@ export enum RequestsActionsTypes { CANCEL_REQUEST_FAILED = 'CANCEL_REQUEST_FAILED', DELETE_REQUEST = 'DELETE_REQUEST', DELETE_REQUEST_FAILED = 'DELETE_REQUEST_FAILED', + DISABLE_REQUEST = 'DISABLE_REQUEST', } export const requestsActions = { @@ -44,6 +45,9 @@ export const requestsActions = { cancelRequestFailed: (request: Request, error: any) => createAction( RequestsActionsTypes.CANCEL_REQUEST_FAILED, { request, error }, ), + disableRequest: (request: Request) => createAction( + RequestsActionsTypes.DISABLE_REQUEST, { request }, + ), }; export type RequestsActions = ActionUnion; diff --git a/cvat-ui/src/components/requests-page/request-card.tsx b/cvat-ui/src/components/requests-page/request-card.tsx index 6ff0ab9c20fd..69b09e89d07a 100644 --- a/cvat-ui/src/components/requests-page/request-card.tsx +++ b/cvat-ui/src/components/requests-page/request-card.tsx @@ -2,7 +2,7 @@ // // SPDX-License-Identifier: MIT -import React, { useState } from 'react'; +import React from 'react'; import { Link } from 'react-router-dom'; import { Row, Col } from 'antd/lib/grid'; @@ -20,10 +20,12 @@ import { RQStatus, Request } from 'cvat-core-wrapper'; import moment from 'moment'; import { cancelRequestAsync } from 'actions/requests-async-actions'; +import { requestsActions } from 'actions/requests-actions'; import StatusMessage from './request-status'; export interface Props { request: Request; + disabled: boolean; } function constructLink(request: Request): string | null { @@ -136,12 +138,11 @@ const dimensions = { }; function RequestCard(props: Props): JSX.Element { - const { request } = props; + const { request, disabled } = props; const { operation } = request; const { type } = operation; const dispatch = useDispatch(); - const [isActive, setIsActive] = useState(true); const linkToEntity = constructLink(request); const percent = request.status === RQStatus.FINISHED ? 100 : request.progress; @@ -152,7 +153,7 @@ function RequestCard(props: Props): JSX.Element { const percentProgress = (request.status === RQStatus.FAILED || !percent) ? '' : `${percent.toFixed(2)}%`; const style: React.CSSProperties = {}; - if (!isActive) { + if (disabled) { style.pointerEvents = 'none'; style.opacity = 0.5; } @@ -166,7 +167,7 @@ function RequestCard(props: Props): JSX.Element { const downloadAnchor = window.document.getElementById('downloadAnchor') as HTMLAnchorElement; downloadAnchor.href = request.url; downloadAnchor.click(); - setIsActive(false); + dispatch(requestsActions.disableRequest(request)); }, }); } @@ -178,7 +179,7 @@ function RequestCard(props: Props): JSX.Element { label: 'Cancel', onClick: () => { dispatch(cancelRequestAsync(request, () => { - setIsActive(false); + dispatch(requestsActions.disableRequest(request)); })); }, }); diff --git a/cvat-ui/src/components/requests-page/requests-list.tsx b/cvat-ui/src/components/requests-page/requests-list.tsx index 7c48fc2b8415..b1f2192a8c81 100644 --- a/cvat-ui/src/components/requests-page/requests-list.tsx +++ b/cvat-ui/src/components/requests-page/requests-list.tsx @@ -33,10 +33,17 @@ function RequestsList(props: Props): JSX.Element { const dispatch = useDispatch(); const { query, count } = props; const { page } = query; - const { requests } = useSelector((state: CombinedState) => state.requests); + const { requests, disabled } = useSelector((state: CombinedState) => state.requests); const requestViews = setUpRequestsList(Object.values(requests), page) - .map((request: Request): JSX.Element => ); + .map((request: Request): JSX.Element => ( + + ), + ); return ( <> diff --git a/cvat-ui/src/reducers/index.ts b/cvat-ui/src/reducers/index.ts index 6ed20a30c195..419dcf40f76c 100644 --- a/cvat-ui/src/reducers/index.ts +++ b/cvat-ui/src/reducers/index.ts @@ -953,7 +953,7 @@ export interface RequestsState { fetching: boolean; initialized: boolean; requests: Record; - urls: string[]; + disabled: string[]; query: RequestsQuery; } diff --git a/cvat-ui/src/reducers/requests-reducer.ts b/cvat-ui/src/reducers/requests-reducer.ts index fbf205b5f5d4..02cd473540fa 100644 --- a/cvat-ui/src/reducers/requests-reducer.ts +++ b/cvat-ui/src/reducers/requests-reducer.ts @@ -11,7 +11,7 @@ const defaultState: RequestsState = { initialized: false, fetching: false, requests: {}, - urls: [], + disabled: [], query: { page: 1, }, @@ -33,6 +33,13 @@ export default function ( }, }; } + case RequestsActionsTypes.DISABLE_REQUEST: { + const { request } = action.payload; + return { + ...state, + disabled: [...state.disabled, request.id], + }; + } case RequestsActionsTypes.GET_REQUESTS_SUCCESS: { return { ...state, From 8fc2f3cf2a35140a7997cf46a69b8402a304bad5 Mon Sep 17 00:00:00 2001 From: Kirill Lakhov Date: Thu, 18 Jul 2024 18:12:15 +0300 Subject: [PATCH 2/6] improved links in markdown --- .../controls-side-bar/tools-control.tsx | 14 +++---- .../src/components/common/cvat-markdown.tsx | 41 +++++++++++++++++++ cvat-ui/src/components/cvat-app.tsx | 18 ++++---- .../export-backup/export-backup-modal.tsx | 6 ++- .../export-dataset/export-dataset-modal.tsx | 6 ++- .../import-dataset/import-dataset-modal.tsx | 8 ++-- cvat-ui/src/styles.scss | 10 +++++ 7 files changed, 80 insertions(+), 23 deletions(-) create mode 100644 cvat-ui/src/components/common/cvat-markdown.tsx diff --git a/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/tools-control.tsx b/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/tools-control.tsx index cd30ab33aae1..7d04b64ef2b8 100644 --- a/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/tools-control.tsx +++ b/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/tools-control.tsx @@ -44,12 +44,12 @@ import { import DetectorRunner, { DetectorRequestBody } from 'components/model-runner-modal/detector-runner'; import LabelSelector from 'components/label-selector/label-selector'; import CVATTooltip from 'components/common/cvat-tooltip'; +import CVATMarkdown from 'components/common/cvat-markdown'; import ApproximationAccuracy, { thresholdFromAccuracy, } from 'components/annotation-page/standard-workspace/controls-side-bar/approximation-accuracy'; import { switchToolsBlockerState } from 'actions/settings-actions'; -import { ReactMarkdown } from 'react-markdown/lib/react-markdown'; import withVisibilityHandling from './handle-popover-visibility'; import ToolsTooltips from './interactor-tooltips'; @@ -440,7 +440,7 @@ export class ToolsControlComponent extends React.PureComponent { setTimeout(() => this.runInteractionRequest(interactionId)); } catch (error: any) { notification.error({ - description: {error.message}, + description: {error.message}, message: 'Interaction error occurred', duration: null, }); @@ -533,7 +533,7 @@ export class ToolsControlComponent extends React.PureComponent { fetchAnnotations(); } catch (error: any) { notification.error({ - description: {error.message}, + description: {error.message}, message: 'Tracking error occurred', duration: null, }); @@ -787,7 +787,7 @@ export class ToolsControlComponent extends React.PureComponent { } catch (error: any) { notification.error({ message: 'Tracker initialization error', - description: {error.message}, + description: {error.message}, duration: null, }); } finally { @@ -841,7 +841,7 @@ export class ToolsControlComponent extends React.PureComponent { } catch (error: any) { notification.error({ message: 'Tracking error', - description: {error.message}, + description: {error.message}, duration: null, }); } finally { @@ -900,7 +900,7 @@ export class ToolsControlComponent extends React.PureComponent { } catch (error: any) { notification.error({ message: 'Could not initialize OpenCV', - description: {error.message}, + description: {error.message}, duration: null, }); } finally { @@ -1346,7 +1346,7 @@ export class ToolsControlComponent extends React.PureComponent { onSwitchToolsBlockerState({ buttonVisible: false }); } catch (error: any) { notification.error({ - description: {error.message}, + description: {error.message}, message: 'Detection error occurred', duration: null, }); diff --git a/cvat-ui/src/components/common/cvat-markdown.tsx b/cvat-ui/src/components/common/cvat-markdown.tsx new file mode 100644 index 000000000000..0f8331cfddfc --- /dev/null +++ b/cvat-ui/src/components/common/cvat-markdown.tsx @@ -0,0 +1,41 @@ +import Button from 'antd/lib/button'; +import React from 'react'; +import ReactMarkdown from 'react-markdown'; +import { RouteComponentProps } from 'react-router-dom'; + +export type UseHistoryType = RouteComponentProps['history']; + +const RouterLinkHOC = (history?: UseHistoryType) => ( + function (props: { children: React.ReactNode, href?: string }): JSX.Element { + const { href, children } = props; + + if (href?.match(/^\//) && history) { + return ( + + ); + } + + return ({children}); + }); + +export default function CVATMarkdown(props: { history?: UseHistoryType, children: string }): JSX.Element { + const { children, history } = props; + + return ( + + {children} + + ); +} diff --git a/cvat-ui/src/components/cvat-app.tsx b/cvat-ui/src/components/cvat-app.tsx index d061a97d5324..c660366e08fd 100644 --- a/cvat-ui/src/components/cvat-app.tsx +++ b/cvat-ui/src/components/cvat-app.tsx @@ -14,7 +14,6 @@ import Spin from 'antd/lib/spin'; import { DisconnectOutlined } from '@ant-design/icons'; import Space from 'antd/lib/space'; import Text from 'antd/lib/typography/Text'; -import ReactMarkdown from 'react-markdown'; import LogoutComponent from 'components/logout-component'; import LoginPageContainer from 'containers/login-page/login-page'; @@ -77,6 +76,7 @@ import '../styles.scss'; import appConfig from 'config'; import EventRecorder from 'utils/event-recorder'; import { authQuery } from 'utils/auth-query'; +import CVATMarkdown from './common/cvat-markdown'; import EmailConfirmationPage from './email-confirmation-pages/email-confirmed'; import EmailVerificationSentPage from './email-confirmation-pages/email-verification-sent'; import IncorrectEmailConfirmationPage from './email-confirmation-pages/incorrect-email-confirmation'; @@ -358,20 +358,20 @@ class CVATApplication extends React.PureComponent{notificationState.message} + {notificationState.message} ), description: notificationState?.description && ( - {notificationState?.description} + {notificationState?.description} ), duration: notificationState.duration || null, }); } - const { notifications, resetMessages } = this.props; - let shown = false; for (const where of Object.keys(notifications.messages)) { for (const what of Object.keys((notifications as any).messages[where])) { @@ -389,6 +389,8 @@ class CVATApplication extends React.PureComponent{title} + {title} ), duration: null, - description: errorLength > 300 ? 'Open the Browser Console to get details' : {error}, + description: errorLength > 300 ? 'Open the Browser Console to get details' : {error}, }); if (shouldLog) { @@ -416,8 +418,6 @@ class CVATApplication extends React.PureComponent{description} + {description} ), className: 'cvat-notification-notice-export-backup-start', }); diff --git a/cvat-ui/src/components/export-dataset/export-dataset-modal.tsx b/cvat-ui/src/components/export-dataset/export-dataset-modal.tsx index 68ca0aaf1a05..c11df51c72b7 100644 --- a/cvat-ui/src/components/export-dataset/export-dataset-modal.tsx +++ b/cvat-ui/src/components/export-dataset/export-dataset-modal.tsx @@ -6,6 +6,7 @@ import './styles.scss'; import React, { useState, useEffect, useCallback } from 'react'; import { connect, useDispatch } from 'react-redux'; +import { useHistory } from 'react-router'; import Modal from 'antd/lib/modal'; import Notification from 'antd/lib/notification'; import { DownloadOutlined } from '@ant-design/icons'; @@ -16,12 +17,12 @@ import Form from 'antd/lib/form'; import Switch from 'antd/lib/switch'; import Space from 'antd/lib/space'; import TargetStorageField from 'components/storage/target-storage-field'; +import CVATMarkdown from 'components/common/cvat-markdown'; import { CombinedState, StorageLocation } from 'reducers'; import { exportActions, exportDatasetAsync } from 'actions/export-actions'; import { Dumper, ProjectOrTaskOrJob, Job, Project, Storage, StorageData, Task, } from 'cvat-core-wrapper'; -import ReactMarkdown from 'react-markdown'; type FormValues = { selectedFormat: string | undefined; @@ -59,6 +60,7 @@ function ExportDatasetModal(props: StateToProps): JSX.Element { const [defaultStorageCloudId, setDefaultStorageCloudId] = useState(); const [helpMessage, setHelpMessage] = useState(''); const dispatch = useDispatch(); + const history = useHistory(); useEffect(() => { if (instance instanceof Project) { @@ -121,7 +123,7 @@ function ExportDatasetModal(props: StateToProps): JSX.Element { Notification.info({ message: `${resource} export started`, description: ( - {description} + {description} ), className: `cvat-notification-notice-export-${instanceType.split(' ')[0]}-start`, }); diff --git a/cvat-ui/src/components/import-dataset/import-dataset-modal.tsx b/cvat-ui/src/components/import-dataset/import-dataset-modal.tsx index d54459bd3baf..7ebd98346368 100644 --- a/cvat-ui/src/components/import-dataset/import-dataset-modal.tsx +++ b/cvat-ui/src/components/import-dataset/import-dataset-modal.tsx @@ -6,7 +6,7 @@ import './styles.scss'; import React, { useCallback, useEffect, useReducer } from 'react'; import { connect, useDispatch } from 'react-redux'; -import ReactMarkdown from 'react-markdown'; +import { useHistory } from 'react-router'; import Modal from 'antd/lib/modal'; import Form, { RuleObject } from 'antd/lib/form'; import Text from 'antd/lib/typography/Text'; @@ -19,6 +19,7 @@ import { UploadOutlined, InboxOutlined, QuestionCircleOutlined, } from '@ant-design/icons'; import CVATTooltip from 'components/common/cvat-tooltip'; +import CVATMarkdown from 'components/common/cvat-markdown'; import { CombinedState, StorageLocation } from 'reducers'; import { importActions, importDatasetAsync } from 'actions/import-actions'; import Space from 'antd/lib/space'; @@ -278,6 +279,7 @@ function ImportDatasetModal(props: StateToProps): JSX.Element { } = props; const [form] = Form.useForm(); const appDispatch = useDispatch(); + const history = useHistory(); const [state, dispatch] = useReducer(reducer, { instanceType: '', @@ -462,11 +464,11 @@ function ImportDatasetModal(props: StateToProps): JSX.Element { )); const resToPrint = uploadParams.resource.charAt(0).toUpperCase() + uploadParams.resource.slice(1); const description = `${resToPrint} import was started for ${instanceType}.` + - ' You can check progress [here](/requests)'; + ' You can check progress [here](/requests).'; Notification.info({ message: `${resToPrint} import started`, description: ( - {description} + {description} ), className: `cvat-notification-notice-import-${uploadParams.resource}-start`, }); diff --git a/cvat-ui/src/styles.scss b/cvat-ui/src/styles.scss index 5dd32306a757..d98b0be10b82 100644 --- a/cvat-ui/src/styles.scss +++ b/cvat-ui/src/styles.scss @@ -39,6 +39,16 @@ html, body { left: 0; } +.cvat-notification-link { + padding: 0; + display: inline; + height: auto; + + span { + display: inline; + } +} + .cvat-not-found { margin: 10% 25%; } From 9a054c10242b4aec86584814af304109d4068870 Mon Sep 17 00:00:00 2001 From: Kirill Lakhov Date: Fri, 19 Jul 2024 10:17:18 +0300 Subject: [PATCH 3/6] added dots --- .../src/components/export-backup/export-backup-modal.tsx | 2 +- cvat-ui/src/reducers/notifications-reducer.ts | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cvat-ui/src/components/export-backup/export-backup-modal.tsx b/cvat-ui/src/components/export-backup/export-backup-modal.tsx index 329ee4827d0f..519de666c53e 100644 --- a/cvat-ui/src/components/export-backup/export-backup-modal.tsx +++ b/cvat-ui/src/components/export-backup/export-backup-modal.tsx @@ -102,7 +102,7 @@ function ExportBackupModal(): JSX.Element { ); closeModal(); - const description = 'Backup export was started. You can check progress [here](/requests)'; + const description = 'Backup export was started. You can check progress [here](/requests).'; Notification.info({ message: 'Backup export started', description: ( diff --git a/cvat-ui/src/reducers/notifications-reducer.ts b/cvat-ui/src/reducers/notifications-reducer.ts index 26c2a81fe590..be3f96f10c09 100644 --- a/cvat-ui/src/reducers/notifications-reducer.ts +++ b/cvat-ui/src/reducers/notifications-reducer.ts @@ -542,10 +542,10 @@ export default function (state = defaultState, action: AnyAction): Notifications } = action.payload; let description = `Export ${resource} for ${instanceType} ${instance.id} is finished. `; if (target === 'local') { - description += 'You can [download it here](/requests)'; + description += 'You can [download it here](/requests).'; } else if (target === 'cloudstorage') { description = - `Export ${resource} for ${instanceType} ${instance.id} has been uploaded to cloud storage`; + `Export ${resource} for ${instanceType} ${instance.id} has been uploaded to cloud storage.`; } return { ...state, @@ -586,10 +586,10 @@ export default function (state = defaultState, action: AnyAction): Notifications } = action.payload; let description = `Backup for the ${instanceType} ${instance.id} is finished. `; if (target === 'local') { - description += 'You can [download it here](/requests)'; + description += 'You can [download it here](/requests).'; } else if (target === 'cloudstorage') { description = - `Backup for the ${instanceType} ${instance.id} has been uploaded to cloud storage`; + `Backup for the ${instanceType} ${instance.id} has been uploaded to cloud storage.`; } return { ...state, From 44f085e3aac4fa97d236a154607a6d3a20845fb0 Mon Sep 17 00:00:00 2001 From: Kirill Lakhov Date: Fri, 19 Jul 2024 12:44:59 +0300 Subject: [PATCH 4/6] omit disabled requests on changing status --- .../src/components/requests-page/requests-list.tsx | 2 +- cvat-ui/src/reducers/index.ts | 2 +- cvat-ui/src/reducers/requests-reducer.ts | 11 ++++++++--- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/cvat-ui/src/components/requests-page/requests-list.tsx b/cvat-ui/src/components/requests-page/requests-list.tsx index b1f2192a8c81..418c38166417 100644 --- a/cvat-ui/src/components/requests-page/requests-list.tsx +++ b/cvat-ui/src/components/requests-page/requests-list.tsx @@ -40,7 +40,7 @@ function RequestsList(props: Props): JSX.Element { ), ); diff --git a/cvat-ui/src/reducers/index.ts b/cvat-ui/src/reducers/index.ts index 419dcf40f76c..853e2a735e26 100644 --- a/cvat-ui/src/reducers/index.ts +++ b/cvat-ui/src/reducers/index.ts @@ -953,7 +953,7 @@ export interface RequestsState { fetching: boolean; initialized: boolean; requests: Record; - disabled: string[]; + disabled: Record; query: RequestsQuery; } diff --git a/cvat-ui/src/reducers/requests-reducer.ts b/cvat-ui/src/reducers/requests-reducer.ts index 02cd473540fa..d73d3b6ea2b5 100644 --- a/cvat-ui/src/reducers/requests-reducer.ts +++ b/cvat-ui/src/reducers/requests-reducer.ts @@ -2,6 +2,7 @@ // // SPDX-License-Identifier: MIT +import _ from 'lodash'; import { BoundariesActions, BoundariesActionTypes } from 'actions/boundaries-actions'; import { RequestsActionsTypes, RequestsActions } from 'actions/requests-actions'; import { AuthActionTypes, AuthActions } from 'actions/auth-actions'; @@ -11,7 +12,7 @@ const defaultState: RequestsState = { initialized: false, fetching: false, requests: {}, - disabled: [], + disabled: {}, query: { page: 1, }, @@ -37,7 +38,10 @@ export default function ( const { request } = action.payload; return { ...state, - disabled: [...state.disabled, request.id], + disabled: { + ...state.disabled, + [request.id]: true, + }, }; } case RequestsActionsTypes.GET_REQUESTS_SUCCESS: { @@ -56,7 +60,7 @@ export default function ( }; } case RequestsActionsTypes.GET_REQUEST_STATUS_SUCCESS: { - const { requests } = state; + const { requests, disabled } = state; return { ...state, @@ -64,6 +68,7 @@ export default function ( ...requests, [action.payload.request.id]: action.payload.request, }, + disabled: _.omit(disabled, action.payload.request.id), }; } case BoundariesActionTypes.RESET_AFTER_ERROR: From ea5f5025c3b926b640610a2d9773feb4c5111799 Mon Sep 17 00:00:00 2001 From: Kirill Lakhov Date: Fri, 19 Jul 2024 13:30:44 +0300 Subject: [PATCH 5/6] package & changelog --- changelog.d/20240719_132628_klakhov_improved_requests.md | 8 ++++++++ cvat-ui/package.json | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 changelog.d/20240719_132628_klakhov_improved_requests.md diff --git a/changelog.d/20240719_132628_klakhov_improved_requests.md b/changelog.d/20240719_132628_klakhov_improved_requests.md new file mode 100644 index 000000000000..b6dd5538f521 --- /dev/null +++ b/changelog.d/20240719_132628_klakhov_improved_requests.md @@ -0,0 +1,8 @@ +### Fixed + +- Request card was not disabed properly after downloading + () + +### Changed +- Following the link in notification no longer reloads the page + () diff --git a/cvat-ui/package.json b/cvat-ui/package.json index 3d3c97be546a..21ef73e9ae4e 100644 --- a/cvat-ui/package.json +++ b/cvat-ui/package.json @@ -1,6 +1,6 @@ { "name": "cvat-ui", - "version": "1.64.0", + "version": "1.64.1", "description": "CVAT single-page application", "main": "src/index.tsx", "scripts": { From 14d275d0e9073464209693a5f2c85fe57f200906 Mon Sep 17 00:00:00 2001 From: Kirill Lakhov Date: Thu, 25 Jul 2024 10:02:37 +0300 Subject: [PATCH 6/6] applied comments --- cvat-ui/src/components/common/cvat-markdown.tsx | 4 ++++ cvat-ui/src/components/requests-page/requests-list.tsx | 6 ++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/cvat-ui/src/components/common/cvat-markdown.tsx b/cvat-ui/src/components/common/cvat-markdown.tsx index 0f8331cfddfc..d4bc12b48309 100644 --- a/cvat-ui/src/components/common/cvat-markdown.tsx +++ b/cvat-ui/src/components/common/cvat-markdown.tsx @@ -1,3 +1,7 @@ +// Copyright (C) 2024 CVAT.ai Corporation +// +// SPDX-License-Identifier: MIT + import Button from 'antd/lib/button'; import React from 'react'; import ReactMarkdown from 'react-markdown'; diff --git a/cvat-ui/src/components/requests-page/requests-list.tsx b/cvat-ui/src/components/requests-page/requests-list.tsx index 418c38166417..28ecafc29f50 100644 --- a/cvat-ui/src/components/requests-page/requests-list.tsx +++ b/cvat-ui/src/components/requests-page/requests-list.tsx @@ -3,7 +3,7 @@ // SPDX-License-Identifier: MIT import React from 'react'; -import { useDispatch, useSelector } from 'react-redux'; +import { shallowEqual, useDispatch, useSelector } from 'react-redux'; import { CombinedState, RequestsQuery } from 'reducers'; import { Row, Col } from 'antd/lib/grid'; @@ -33,7 +33,9 @@ function RequestsList(props: Props): JSX.Element { const dispatch = useDispatch(); const { query, count } = props; const { page } = query; - const { requests, disabled } = useSelector((state: CombinedState) => state.requests); + const { requests, disabled } = useSelector((state: CombinedState) => ({ + requests: state.requests.requests, disabled: state.requests.disabled, + }), shallowEqual); const requestViews = setUpRequestsList(Object.values(requests), page) .map((request: Request): JSX.Element => (