diff --git a/cvat-ui/src/components/actions-menu/actions-menu.tsx b/cvat-ui/src/components/actions-menu/actions-menu.tsx index 4510bc1a..b447050a 100644 --- a/cvat-ui/src/components/actions-menu/actions-menu.tsx +++ b/cvat-ui/src/components/actions-menu/actions-menu.tsx @@ -4,8 +4,10 @@ import './styles.scss'; import React from 'react'; -import Menu, { ClickParam } from 'antd/lib/menu'; +import Menu from 'antd/lib/menu'; import Modal from 'antd/lib/modal'; +// eslint-disable-next-line import/no-extraneous-dependencies +import { MenuInfo } from 'rc-menu/lib/interface'; import DumpSubmenu from './dump-submenu'; import LoadSubmenu from './load-submenu'; @@ -22,7 +24,7 @@ interface Props { exportActivities: string[] | null; inferenceIsActive: boolean; - onClickMenu: (params: ClickParam, file?: File) => void; + onClickMenu: (params: MenuInfo, file?: File) => void; } export enum Actions { @@ -48,8 +50,8 @@ export default function ActionsMenuComponent(props: Props): JSX.Element { loadActivity, } = props; - let latestParams: ClickParam | null = null; - function onClickMenuWrapper(params: ClickParam | null, file?: File): void { + let latestParams: MenuInfo | null = null; + function onClickMenuWrapper(params: MenuInfo | null, file?: File): void { const copyParams = params || latestParams; if (!copyParams) { return; @@ -67,7 +69,7 @@ export default function ActionsMenuComponent(props: Props): JSX.Element { onClickMenu(copyParams, file); }, okButtonProps: { - type: 'danger', + danger: true, }, okText: 'Update', }); @@ -83,7 +85,7 @@ export default function ActionsMenuComponent(props: Props): JSX.Element { onClickMenu(copyParams); }, okButtonProps: { - type: 'danger', + danger: true, }, okText: 'Delete', }); diff --git a/cvat-ui/src/components/annotation-page/appearance-block.tsx b/cvat-ui/src/components/annotation-page/appearance-block.tsx index 73309cbe..90843397 100644 --- a/cvat-ui/src/components/annotation-page/appearance-block.tsx +++ b/cvat-ui/src/components/annotation-page/appearance-block.tsx @@ -7,7 +7,7 @@ import { AnyAction } from 'redux'; import { connect } from 'react-redux'; import Text from 'antd/lib/typography/Text'; import Radio, { RadioChangeEvent } from 'antd/lib/radio'; -import Slider, { SliderValue } from 'antd/lib/slider'; +import Slider from 'antd/lib/slider'; import Checkbox, { CheckboxChangeEvent } from 'antd/lib/checkbox'; import Collapse from 'antd/lib/collapse'; @@ -42,8 +42,8 @@ interface StateToProps { interface DispatchToProps { collapseAppearance(): void; changeShapesColorBy(event: RadioChangeEvent): void; - changeShapesOpacity(event: SliderValue): void; - changeSelectedShapesOpacity(event: SliderValue): void; + changeShapesOpacity(value: number): void; + changeSelectedShapesOpacity(value: number): void; changeShapesOutlinedBorders(outlined: boolean, color: string): void; changeShowBitmap(event: CheckboxChangeEvent): void; changeShowProjections(event: CheckboxChangeEvent): void; @@ -107,11 +107,11 @@ function mapDispatchToProps(dispatch: Dispatch): DispatchToProps { changeShapesColorBy(event: RadioChangeEvent): void { dispatch(changeShapesColorByAction(event.target.value)); }, - changeShapesOpacity(value: SliderValue): void { - dispatch(changeShapesOpacityAction(value as number)); + changeShapesOpacity(value: number): void { + dispatch(changeShapesOpacityAction(value)); }, - changeSelectedShapesOpacity(value: SliderValue): void { - dispatch(changeSelectedShapesOpacityAction(value as number)); + changeSelectedShapesOpacity(value: number): void { + dispatch(changeSelectedShapesOpacityAction(value)); }, changeShapesOutlinedBorders(outlined: boolean, color: string): void { dispatch(changeShapesOutlinedBordersAction(outlined, color)); diff --git a/cvat-ui/src/components/annotation-page/canvas/canvas-context-menu.tsx b/cvat-ui/src/components/annotation-page/canvas/canvas-context-menu.tsx index 9d7cc35c..c85cffd1 100644 --- a/cvat-ui/src/components/annotation-page/canvas/canvas-context-menu.tsx +++ b/cvat-ui/src/components/annotation-page/canvas/canvas-context-menu.tsx @@ -4,7 +4,9 @@ import React from 'react'; import ReactDOM from 'react-dom'; -import Menu, { ClickParam } from 'antd/lib/menu'; +import Menu from 'antd/lib/menu'; +// eslint-disable-next-line import/no-extraneous-dependencies +import { MenuInfo } from 'rc-menu/lib/interface'; import ObjectItemContainer from 'containers/annotation-page/standard-workspace/objects-side-bar/object-item'; import { Workspace } from 'reducers/interfaces'; @@ -27,7 +29,7 @@ interface ReviewContextMenuProps { top: number; left: number; latestComments: string[]; - onClick: (param: ClickParam) => void; + onClick: (param: MenuInfo) => void; } enum ReviewContextMenuKeys { @@ -95,7 +97,7 @@ export default function CanvasContextMenu(props: Props): JSX.Element | null { top={top} left={left} latestComments={latestComments} - onClick={(param: ClickParam) => { + onClick={(param: MenuInfo) => { const [state] = objectStates.filter( (_state: any): boolean => _state.clientID === contextMenuClientID, ); diff --git a/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/draw-shape-popover.tsx b/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/draw-shape-popover.tsx index 8a72c39b..bf3a74ec 100644 --- a/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/draw-shape-popover.tsx +++ b/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/draw-shape-popover.tsx @@ -129,9 +129,9 @@ function DrawShapePopoverComponent(props: Props): JSX.Element { { - if (typeof value === 'number') { - onChangePoints(Math.floor(clamp(value, minimumPoints, Number.MAX_SAFE_INTEGER))); + onChange={(value: number | undefined | string) => { + if (typeof value !== 'undefined') { + onChangePoints(Math.floor(clamp(+value, minimumPoints, Number.MAX_SAFE_INTEGER))); } else if (!value) { onChangePoints(undefined); } 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 c77b63a1..f1566ea2 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 @@ -531,10 +531,10 @@ export class ToolsControlComponent extends React.PureComponent { min={1} precision={0} max={jobInstance.stopFrame - frame} - onChange={(value: number | undefined): void => { + onChange={(value: number | undefined | string): void => { if (typeof value !== 'undefined') { this.setState({ - trackingFrames: value, + trackingFrames: +value, }); } }} diff --git a/cvat-ui/src/components/annotation-page/standard-workspace/objects-side-bar/object-item-attribute.tsx b/cvat-ui/src/components/annotation-page/standard-workspace/objects-side-bar/object-item-attribute.tsx index 78ac8634..1d4d8dc1 100644 --- a/cvat-ui/src/components/annotation-page/standard-workspace/objects-side-bar/object-item-attribute.tsx +++ b/cvat-ui/src/components/annotation-page/standard-workspace/objects-side-bar/object-item-attribute.tsx @@ -134,9 +134,9 @@ function ItemAttributeComponent(props: Props): JSX.Element { { - if (typeof value === 'number') { - changeAttribute(attrID, `${clamp(value, min, max)}`); + onChange={(value: number | undefined | string): void => { + if (typeof value !== 'undefined') { + changeAttribute(attrID, `${clamp(+value, min, max)}`); } }} value={+attrValue} diff --git a/cvat-ui/src/components/annotation-page/standard-workspace/propagate-confirm.tsx b/cvat-ui/src/components/annotation-page/standard-workspace/propagate-confirm.tsx index a671889d..1ac36d16 100644 --- a/cvat-ui/src/components/annotation-page/standard-workspace/propagate-confirm.tsx +++ b/cvat-ui/src/components/annotation-page/standard-workspace/propagate-confirm.tsx @@ -52,10 +52,10 @@ export default function PropagateConfirmComponent(props: Props): JSX.Element { size='small' min={minPropagateFrames} value={propagateFrames} - onChange={(value: number | undefined) => { - if (typeof value === 'number') { + onChange={(value: number | undefined | string) => { + if (typeof value !== 'undefined') { changePropagateFrames( - Math.floor(clamp(value, minPropagateFrames, Number.MAX_SAFE_INTEGER)), + Math.floor(clamp(+value, minPropagateFrames, Number.MAX_SAFE_INTEGER)), ); } }} @@ -67,9 +67,9 @@ export default function PropagateConfirmComponent(props: Props): JSX.Element { value={propagateUpToFrame} min={frameNumber + 1} max={stopFrame} - onChange={(value: number | undefined) => { - if (typeof value === 'number') { - changeUpToFrame(Math.floor(clamp(value, frameNumber + 1, stopFrame))); + onChange={(value: number | undefined | string) => { + if (typeof value !== 'undefined') { + changeUpToFrame(Math.floor(clamp(+value, frameNumber + 1, stopFrame))); } }} /> diff --git a/cvat-ui/src/components/annotation-page/top-bar/annotation-menu.tsx b/cvat-ui/src/components/annotation-page/top-bar/annotation-menu.tsx index 9818bbcb..82c5aa82 100644 --- a/cvat-ui/src/components/annotation-page/top-bar/annotation-menu.tsx +++ b/cvat-ui/src/components/annotation-page/top-bar/annotation-menu.tsx @@ -3,8 +3,10 @@ // SPDX-License-Identifier: MIT import React from 'react'; -import Menu, { ClickParam } from 'antd/lib/menu'; +import Menu from 'antd/lib/menu'; import Modal from 'antd/lib/modal'; +// eslint-disable-next-line import/no-extraneous-dependencies +import { MenuInfo } from 'rc-menu/lib/interface'; import DumpSubmenu from 'components/actions-menu/dump-submenu'; import LoadSubmenu from 'components/actions-menu/load-submenu'; @@ -19,7 +21,7 @@ interface Props { exportActivities: string[] | null; isReviewer: boolean; jobInstance: any; - onClickMenu(params: ClickParam, file?: File): void; + onClickMenu(params: MenuInfo, file?: File): void; setForceExitAnnotationFlag(forceExit: boolean): void; saveAnnotations(jobInstance: any, afterSave?: () => void): void; } @@ -54,15 +56,15 @@ export default function AnnotationMenuComponent(props: Props): JSX.Element { const jobStatus = jobInstance.status; const taskID = jobInstance.task.id; - let latestParams: ClickParam | null = null; - function onClickMenuWrapper(params: ClickParam | null, file?: File): void { + let latestParams: MenuInfo | null = null; + function onClickMenuWrapper(params: MenuInfo | null, file?: File): void { const copyParams = params || latestParams; if (!copyParams) { return; } latestParams = params; - function checkUnsavedChanges(_copyParams: ClickParam): void { + function checkUnsavedChanges(_copyParams: MenuInfo): void { if (jobInstance.annotations.hasUnsavedChanges()) { Modal.confirm({ title: 'The job has unsaved annotations', @@ -100,7 +102,7 @@ export default function AnnotationMenuComponent(props: Props): JSX.Element { onClickMenu(copyParams, file); }, okButtonProps: { - type: 'danger', + danger: true, }, okText: 'Update', }); @@ -118,7 +120,7 @@ export default function AnnotationMenuComponent(props: Props): JSX.Element { onClickMenu(copyParams); }, okButtonProps: { - type: 'danger', + danger: true, }, okText: 'Delete', }); diff --git a/cvat-ui/src/components/annotation-page/top-bar/player-navigation.tsx b/cvat-ui/src/components/annotation-page/top-bar/player-navigation.tsx index 513ac25f..927673e5 100644 --- a/cvat-ui/src/components/annotation-page/top-bar/player-navigation.tsx +++ b/cvat-ui/src/components/annotation-page/top-bar/player-navigation.tsx @@ -6,9 +6,10 @@ import React, { useState, useEffect } from 'react'; import { Row, Col } from 'antd/lib/grid'; import { LinkOutlined } from '@ant-design/icons'; -import Slider, { SliderValue } from 'antd/lib/slider'; +import Slider from 'antd/lib/slider'; import Tooltip from 'antd/lib/tooltip'; import InputNumber from 'antd/lib/input-number'; +import Input from 'antd/lib/input'; import Text from 'antd/lib/typography/Text'; import { clamp } from 'utils/math'; @@ -19,8 +20,8 @@ interface Props { frameNumber: number; frameFilename: string; focusFrameInputShortcut: string; - inputFrameRef: React.RefObject; - onSliderChange(value: SliderValue): void; + inputFrameRef: React.RefObject; + onSliderChange(value: number): void; onInputChange(value: number): void; onURLIconClick(): void; } @@ -76,12 +77,13 @@ function PlayerNavigation(props: Props): JSX.Element { { - if (typeof value === 'number') { - setFrameInputValue(Math.floor(clamp(value, startFrame, stopFrame))); + onChange={(value: number | undefined | string) => { + if (typeof (value) !== 'undefined') { + setFrameInputValue(Math.floor(clamp(+value, startFrame, stopFrame))); } }} onBlur={() => { @@ -90,7 +92,6 @@ function PlayerNavigation(props: Props): JSX.Element { onPressEnter={() => { onInputChange(frameInputValue); }} - ref={inputFrameRef} /> diff --git a/cvat-ui/src/components/annotation-page/top-bar/top-bar.tsx b/cvat-ui/src/components/annotation-page/top-bar/top-bar.tsx index 4bdab500..45711fe9 100644 --- a/cvat-ui/src/components/annotation-page/top-bar/top-bar.tsx +++ b/cvat-ui/src/components/annotation-page/top-bar/top-bar.tsx @@ -5,8 +5,7 @@ import React from 'react'; import { Row, Col } from 'antd/lib/grid'; -import InputNumber from 'antd/lib/input-number'; -import { SliderValue } from 'antd/lib/slider'; +import Input from 'antd/lib/input'; import { Workspace } from 'reducers/interfaces'; import LeftGroup from './left-group'; @@ -20,7 +19,7 @@ interface Props { savingStatuses: string[]; frameNumber: number; frameFilename: string; - inputFrameRef: React.RefObject; + inputFrameRef: React.RefObject; startFrame: number; stopFrame: number; undoAction?: string; @@ -49,7 +48,7 @@ interface Props { onLastFrame(): void; setPrevButtonType(type: 'regular' | 'filtered' | 'empty'): void; setNextButtonType(type: 'regular' | 'filtered' | 'empty'): void; - onSliderChange(value: SliderValue): void; + onSliderChange(value: number): void; onInputChange(value: number): void; onURLIconClick(): void; onUndoClick(): void; diff --git a/cvat-ui/src/components/change-password-modal/change-password-form.tsx b/cvat-ui/src/components/change-password-modal/change-password-form.tsx index 857eeb3c..fc5a4b1a 100644 --- a/cvat-ui/src/components/change-password-modal/change-password-form.tsx +++ b/cvat-ui/src/components/change-password-modal/change-password-form.tsx @@ -3,12 +3,12 @@ // SPDX-License-Identifier: MIT import React from 'react'; -import Form, { FormComponentProps } from '@ant-design/compatible/lib/form/Form'; +import Form from 'antd/lib/form'; import { LockOutlined } from '@ant-design/icons'; import Button from 'antd/lib/button'; import Input from 'antd/lib/input'; -import patterns from 'utils/validation-patterns'; +import { validateConfirmation, validatePassword } from 'components/register-page/register-form'; export interface ChangePasswordData { oldPassword: string; @@ -16,159 +16,79 @@ export interface ChangePasswordData { newPassword2: string; } -type ChangePasswordFormProps = { +interface Props { fetching: boolean; onSubmit(loginData: ChangePasswordData): void; -} & FormComponentProps; - -class ChangePasswordFormComponent extends React.PureComponent { - private validateConfirmation = (_: any, value: string, callback: Function): void => { - const { form } = this.props; - if (value && value !== form.getFieldValue('newPassword1')) { - callback('Two passwords that you enter is inconsistent!'); - } else { - callback(); - } - }; - - private validatePassword = (_: any, value: string, callback: Function): void => { - const { form } = this.props; - if (!patterns.validatePasswordLength.pattern.test(value)) { - callback(patterns.validatePasswordLength.message); - } - - if (!patterns.passwordContainsNumericCharacters.pattern.test(value)) { - callback(patterns.passwordContainsNumericCharacters.message); - } - - if (!patterns.passwordContainsUpperCaseCharacter.pattern.test(value)) { - callback(patterns.passwordContainsUpperCaseCharacter.message); - } - - if (!patterns.passwordContainsLowerCaseCharacter.pattern.test(value)) { - callback(patterns.passwordContainsLowerCaseCharacter.message); - } - - if (value) { - form.validateFields(['newPassword2'], { force: true }); - } - callback(); - }; - - private handleSubmit = (e: React.FormEvent): void => { - e.preventDefault(); - const { form, onSubmit } = this.props; - - form.validateFields((error, values): void => { - if (!error) { - const validatedFields = { - ...values, - confirmations: [], - }; - - onSubmit(validatedFields); - } - }); - }; - - private renderOldPasswordField(): JSX.Element { - const { form } = this.props; +} - return ( - - {form.getFieldDecorator('oldPassword', { - rules: [ - { - required: true, - message: 'Please input your current password!', - }, - ], - })( - } - placeholder='Current password' - />, - )} +function ChangePasswordFormComponent({ fetching, onSubmit }: Props): JSX.Element { + return ( +
+ + } + placeholder='Current password' + /> - ); - } - - private renderNewPasswordField(): JSX.Element { - const { form } = this.props; - return ( - - {form.getFieldDecorator('newPassword1', { - rules: [ - { - required: true, - message: 'Please input new password!', - }, - { - validator: this.validatePassword, - }, - ], - })( - } - placeholder='New password' - />, - )} + + } + placeholder='New password' + /> - ); - } - private renderNewPasswordConfirmationField(): JSX.Element { - const { form } = this.props; - - return ( - - {form.getFieldDecorator('newPassword2', { - rules: [ - { - required: true, - message: 'Please confirm your new password!', - }, - { - validator: this.validateConfirmation, - }, - ], - })( - } - placeholder='Confirm new password' - />, - )} + + } + placeholder='Confirm new password' + /> - ); - } - - public render(): JSX.Element { - const { fetching } = this.props; - return ( - - {this.renderOldPasswordField()} - {this.renderNewPasswordField()} - {this.renderNewPasswordConfirmationField()} - - - - - - ); - } + + + + + ); } -export default Form.create()(ChangePasswordFormComponent); +export default React.memo(ChangePasswordFormComponent); diff --git a/cvat-ui/src/components/file-manager/file-manager.tsx b/cvat-ui/src/components/file-manager/file-manager.tsx index 6dbf0fbc..aa7c6e2b 100644 --- a/cvat-ui/src/components/file-manager/file-manager.tsx +++ b/cvat-ui/src/components/file-manager/file-manager.tsx @@ -149,6 +149,7 @@ export default class FileManager extends React.PureComponent { className='cvat-share-tree' checkable showLine + height={256} checkStrictly={false} expandedKeys={expandedKeys} checkedKeys={files.share} diff --git a/cvat-ui/src/components/file-manager/styles.scss b/cvat-ui/src/components/file-manager/styles.scss index 7c72d764..dd280ceb 100644 --- a/cvat-ui/src/components/file-manager/styles.scss +++ b/cvat-ui/src/components/file-manager/styles.scss @@ -5,10 +5,7 @@ @import '../../base.scss'; .cvat-share-tree { - height: fit-content; - min-height: 10em; - max-height: 20em; - overflow: auto; + height: 32 * $grid-unit-size; } .cvat-empty-share-tree { diff --git a/cvat-ui/src/components/header/settings-modal/player-settings.tsx b/cvat-ui/src/components/header/settings-modal/player-settings.tsx index d832d5bc..dc341d6a 100644 --- a/cvat-ui/src/components/header/settings-modal/player-settings.tsx +++ b/cvat-ui/src/components/header/settings-modal/player-settings.tsx @@ -89,9 +89,9 @@ export default function PlayerSettingsComponent(props: Props): JSX.Element { min={minFrameStep} max={maxFrameStep} value={frameStep} - onChange={(value: number | undefined): void => { - if (typeof value === 'number') { - onChangeFrameStep(Math.floor(clamp(value, minFrameStep, maxFrameStep))); + onChange={(value: number | undefined | string): void => { + if (typeof value !== 'undefined') { + onChangeFrameStep(Math.floor(clamp(+value, minFrameStep, maxFrameStep))); } }} /> @@ -174,9 +174,9 @@ export default function PlayerSettingsComponent(props: Props): JSX.Element { max={maxGridSize} value={gridSize} disabled={!grid} - onChange={(value: number | undefined): void => { - if (typeof value === 'number') { - onChangeGridSize(Math.floor(clamp(value, minGridSize, maxGridSize))); + onChange={(value: number | undefined | string): void => { + if (typeof value !== 'undefined') { + onChangeGridSize(Math.floor(clamp(+value, minGridSize, maxGridSize))); } }} /> diff --git a/cvat-ui/src/components/header/settings-modal/workspace-settings.tsx b/cvat-ui/src/components/header/settings-modal/workspace-settings.tsx index 9ccb0ae8..8166a1ec 100644 --- a/cvat-ui/src/components/header/settings-modal/workspace-settings.tsx +++ b/cvat-ui/src/components/header/settings-modal/workspace-settings.tsx @@ -70,10 +70,10 @@ export default function WorkspaceSettingsComponent(props: Props): JSX.Element { max={maxAutoSaveInterval} step={1} value={Math.round(autoSaveInterval / (60 * 1000))} - onChange={(value: number | undefined): void => { - if (typeof value === 'number') { + onChange={(value: number | undefined | string): void => { + if (typeof value !== 'undefined') { onChangeAutoSaveInterval( - Math.floor(clamp(value, minAutoSaveInterval, maxAutoSaveInterval)) * 60 * 1000, + Math.floor(clamp(+value, minAutoSaveInterval, maxAutoSaveInterval)) * 60 * 1000, ); } }} @@ -112,7 +112,8 @@ export default function WorkspaceSettingsComponent(props: Props): JSX.Element { {' '} - Show text for an object on the canvas not only when the object is activated{' '} + Show text for an object on the canvas not only when the object is activated + {' '} @@ -131,7 +132,8 @@ export default function WorkspaceSettingsComponent(props: Props): JSX.Element { {' '} - Enable automatic bordering for polygons and polylines during drawing/editing{' '} + Enable automatic bordering for polygons and polylines during drawing/editing + {' '} @@ -142,9 +144,9 @@ export default function WorkspaceSettingsComponent(props: Props): JSX.Element { min={minAAMMargin} max={maxAAMMargin} value={aamZoomMargin} - onChange={(value: number | undefined): void => { - if (typeof value === 'number') { - onChangeAAMZoomMargin(Math.floor(clamp(value, minAAMMargin, maxAAMMargin))); + onChange={(value: number | undefined | string): void => { + if (typeof value !== 'undefined') { + onChangeAAMZoomMargin(Math.floor(clamp(+value, minAAMMargin, maxAAMMargin))); } }} /> diff --git a/cvat-ui/src/components/label-selector/label-selector.tsx b/cvat-ui/src/components/label-selector/label-selector.tsx index c5f5beaf..97899956 100644 --- a/cvat-ui/src/components/label-selector/label-selector.tsx +++ b/cvat-ui/src/components/label-selector/label-selector.tsx @@ -3,9 +3,11 @@ // SPDX-License-Identifier: MIT import React from 'react'; -import Select, { OptionProps, SelectProps } from 'antd/lib/select'; +import Select, { SelectProps } from 'antd/lib/select'; +// eslint-disable-next-line import/no-extraneous-dependencies +import { OptionData, OptionGroupData } from 'rc-select/lib/interface'; -interface Props extends SelectProps { +interface Props extends SelectProps { labels: any[]; value: any | number | null; onChange: (label: any) => void; @@ -26,10 +28,12 @@ export default function LabelSelector(props: Props): JSX.Element { {...rest} {...dinamicProps} showSearch - filterOption={(input: string, option: React.ReactElement) => { - const { children } = option.props; - if (typeof children === 'string') { - return children.toLowerCase().includes(input.toLowerCase()); + filterOption={(input: string, option?: OptionData | OptionGroupData) => { + if (option) { + const { children } = option.props; + if (typeof children === 'string') { + return children.toLowerCase().includes(input.toLowerCase()); + } } return false; diff --git a/cvat-ui/src/components/labels-editor/label-form.tsx b/cvat-ui/src/components/labels-editor/label-form.tsx index 3a36b0a3..c4319e12 100644 --- a/cvat-ui/src/components/labels-editor/label-form.tsx +++ b/cvat-ui/src/components/labels-editor/label-form.tsx @@ -467,8 +467,8 @@ class LabelForm extends React.PureComponent { - - - ); - } + + + + + ); } -export default Form.create()(LoginFormComponent); +export default React.memo(LoginFormComponent); diff --git a/cvat-ui/src/components/model-runner-modal/detector-runner.tsx b/cvat-ui/src/components/model-runner-modal/detector-runner.tsx index 21f7392b..d0c4a582 100644 --- a/cvat-ui/src/components/model-runner-modal/detector-runner.tsx +++ b/cvat-ui/src/components/model-runner-modal/detector-runner.tsx @@ -6,7 +6,7 @@ import './styles.scss'; import React, { useState } from 'react'; import { Row, Col } from 'antd/lib/grid'; import { CloseCircleOutlined, QuestionCircleOutlined } from '@ant-design/icons'; -import Select, { OptionProps } from 'antd/lib/select'; +import Select from 'antd/lib/select'; import Checkbox, { CheckboxChangeEvent } from 'antd/lib/checkbox'; import Tooltip from 'antd/lib/tooltip'; import Tag from 'antd/lib/tag'; @@ -14,9 +14,12 @@ import Text from 'antd/lib/typography/Text'; import InputNumber from 'antd/lib/input-number'; import Button from 'antd/lib/button'; import notification from 'antd/lib/notification'; +// eslint-disable-next-line import/no-extraneous-dependencies +import { OptionData, OptionGroupData } from 'rc-select/lib/interface'; import { Model, StringObject } from 'reducers/interfaces'; +import { clamp } from 'utils/math'; import consts from 'consts'; interface Props { @@ -95,10 +98,12 @@ function DetectorRunner(props: Props): JSX.Element { onChange={onChange} style={{ width: '100%' }} showSearch - filterOption={(input: string, option: React.ReactElement) => { - const { children } = option.props; - if (typeof children === 'string') { - return children.toLowerCase().includes(input.toLowerCase()); + filterOption={(input: string, option?: OptionData | OptionGroupData) => { + if (option) { + const { children } = option.props; + if (typeof children === 'string') { + return children.toLowerCase().includes(input.toLowerCase()); + } } return false; @@ -106,7 +111,7 @@ function DetectorRunner(props: Props): JSX.Element { > {labels.map( (label: string): JSX.Element => ( - {label} + {label} ), )} @@ -138,7 +143,7 @@ function DetectorRunner(props: Props): JSX.Element { > {models.map( (_model: Model): JSX.Element => ( - {_model.name} + {_model.name} ), )} @@ -176,13 +181,19 @@ function DetectorRunner(props: Props): JSX.Element { <> - {renderSelector(match.model || '', 'Model labels', modelLabels, (modelLabel: string) => - updateMatch(modelLabel, null), + {renderSelector( + match.model || '', + 'Model labels', + modelLabels, + (modelLabel: string) => updateMatch(modelLabel, null), )} - {renderSelector(match.task || '', 'Task labels', taskLabels, (taskLabel: string) => - updateMatch(null, taskLabel), + {renderSelector( + match.task || '', + 'Task labels', + taskLabels, + (taskLabel: string) => updateMatch(null, taskLabel), )} @@ -219,9 +230,9 @@ function DetectorRunner(props: Props): JSX.Element { step={0.01} max={1} value={threshold} - onChange={(value: number | undefined) => { - if (typeof value === 'number') { - setThreshold(value); + onChange={(value: number | undefined | string) => { + if (typeof value !== 'undefined') { + setThreshold(clamp(+value, 0.01, 1)); } }} /> @@ -238,9 +249,9 @@ function DetectorRunner(props: Props): JSX.Element { placeholder='Threshold' min={1} value={distance} - onChange={(value: number | undefined) => { - if (typeof value === 'number') { - setDistance(value); + onChange={(value: number | undefined | string) => { + if (typeof value !== 'undefined') { + setDistance(+value); } }} /> @@ -258,12 +269,10 @@ function DetectorRunner(props: Props): JSX.Element { runInference( task, model, - model.type === 'detector' - ? { mapping, cleanup } - : { - threshold, - max_distance: distance, - }, + model.type === 'detector' ? { mapping, cleanup } : { + threshold, + max_distance: distance, + }, ); }} > diff --git a/cvat-ui/src/components/projects-page/actions-menu.tsx b/cvat-ui/src/components/projects-page/actions-menu.tsx index 149986ca..388c52e9 100644 --- a/cvat-ui/src/components/projects-page/actions-menu.tsx +++ b/cvat-ui/src/components/projects-page/actions-menu.tsx @@ -26,7 +26,7 @@ export default function ProjectActionsMenuComponent(props: Props): JSX.Element { dispatch(deleteProjectAsync(projectInstance)); }, okButtonProps: { - type: 'danger', + danger: true, }, okText: 'Delete', }); diff --git a/cvat-ui/src/components/register-page/register-form.tsx b/cvat-ui/src/components/register-page/register-form.tsx index 336153f1..8939e21b 100644 --- a/cvat-ui/src/components/register-page/register-form.tsx +++ b/cvat-ui/src/components/register-page/register-form.tsx @@ -3,8 +3,8 @@ // SPDX-License-Identifier: MIT import React from 'react'; -import Form, { FormComponentProps } from '@ant-design/compatible/lib/form/Form'; import { UserAddOutlined, MailOutlined, LockOutlined } from '@ant-design/icons'; +import Form, { RuleRender, RuleObject } from 'antd/lib/form'; import Button from 'antd/lib/button'; import Input from 'antd/lib/input'; import Checkbox from 'antd/lib/checkbox'; @@ -29,312 +29,240 @@ export interface RegisterData { confirmations: UserConfirmation[]; } -type RegisterFormProps = { +interface Props { fetching: boolean; userAgreements: UserAgreement[]; onSubmit(registerData: RegisterData): void; -} & FormComponentProps; +} -class RegisterFormComponent extends React.PureComponent { - private validateConfirmation = (rule: any, value: any, callback: any): void => { - const { form } = this.props; - if (value && value !== form.getFieldValue('password1')) { - callback('Two passwords that you enter is inconsistent!'); - } else { - callback(); - } - }; +function validateUsername(_: RuleObject, value: string): Promise { + if (!patterns.validateUsernameLength.pattern.test(value)) { + return Promise.reject(new Error(patterns.validateUsernameLength.message)); + } + + if (!patterns.validateUsernameCharacters.pattern.test(value)) { + return Promise.reject(new Error(patterns.validateUsernameCharacters.message)); + } + + return Promise.resolve(); +} - private validatePassword = (_: any, value: any, callback: any): void => { - const { form } = this.props; +export const validatePassword: RuleRender = (): RuleObject => ({ + validator(_: RuleObject, value: string): Promise { if (!patterns.validatePasswordLength.pattern.test(value)) { - callback(patterns.validatePasswordLength.message); + return Promise.reject(new Error(patterns.validatePasswordLength.message)); } if (!patterns.passwordContainsNumericCharacters.pattern.test(value)) { - callback(patterns.passwordContainsNumericCharacters.message); + return Promise.reject(new Error(patterns.passwordContainsNumericCharacters.message)); } if (!patterns.passwordContainsUpperCaseCharacter.pattern.test(value)) { - callback(patterns.passwordContainsUpperCaseCharacter.message); + return Promise.reject(new Error(patterns.passwordContainsUpperCaseCharacter.message)); } if (!patterns.passwordContainsLowerCaseCharacter.pattern.test(value)) { - callback(patterns.passwordContainsLowerCaseCharacter.message); + return Promise.reject(new Error(patterns.passwordContainsLowerCaseCharacter.message)); } - if (value) { - form.validateFields(['password2'], { force: true }); - } - callback(); - }; - - private validateUsername = (_: any, value: any, callback: any): void => { - if (!patterns.validateUsernameLength.pattern.test(value)) { - callback(patterns.validateUsernameLength.message); - } + return Promise.resolve(); + }, +}); - if (!patterns.validateUsernameCharacters.pattern.test(value)) { - callback(patterns.validateUsernameCharacters.message); +export const validateConfirmation: ((firstFieldName: string) => RuleRender) = ( + firstFieldName: string, +): RuleRender => ({ getFieldValue }): RuleObject => ({ + validator(_: RuleObject, value: string): Promise { + if (value && value !== getFieldValue(firstFieldName)) { + return Promise.reject(new Error('Two passwords that you enter is inconsistent!')); } - callback(); - }; - - private validateAgrement = (agreement: any, value: any, callback: any): void => { - const { userAgreements } = this.props; - let isValid = true; - for (const userAgreement of userAgreements) { - if (agreement.field === userAgreement.name && userAgreement.required && !value) { - isValid = false; - callback(`You must accept the ${userAgreement.displayText} to continue!`); - break; - } + return Promise.resolve(); + }, +}); + +const validateAgreement: ((userAgreements: UserAgreement[]) => RuleRender) = ( + userAgreements: UserAgreement[], +): RuleRender => () => ({ + validator(rule: any, value: boolean): Promise { + const [, name] = rule.field.split(':'); + const [agreement] = userAgreements + .filter((userAgreement: UserAgreement): boolean => userAgreement.name === name); + if (agreement.required && !value) { + return Promise.reject(new Error(`You must accept ${agreement.displayText} to continue!`)); } - if (isValid) { - callback(); - } - }; - - private handleSubmit = (e: React.FormEvent): void => { - e.preventDefault(); - const { form, onSubmit, userAgreements } = this.props; - - form.validateFields((error, values): void => { - if (!error) { - const validatedFields = { - ...values, - confirmations: [], - }; - for (const userAgreement of userAgreements) { - validatedFields.confirmations.push({ - name: userAgreement.name, - value: validatedFields[userAgreement.name], - }); - delete validatedFields[userAgreement.name]; - } - - onSubmit(validatedFields); - } - }); - }; - - private renderFirstNameField(): JSX.Element { - const { form } = this.props; - - return ( - - {form.getFieldDecorator('firstName', { - rules: [ - { - required: true, - message: 'Please specify a first name', - pattern: patterns.validateName.pattern, - }, - ], - })( - } - placeholder='First name' - />, - )} - - ); - } - - private renderLastNameField(): JSX.Element { - const { form } = this.props; - - return ( - - {form.getFieldDecorator('lastName', { - rules: [ - { - required: true, - message: 'Please specify a last name', - pattern: patterns.validateName.pattern, - }, - ], - })( - } - placeholder='Last name' - />, - )} + return Promise.resolve(); + }, +}); + +function RegisterFormComponent(props: Props): JSX.Element { + const { fetching, userAgreements, onSubmit } = props; + return ( +
) => { + const agreements = Object.keys(values) + .filter((key: string):boolean => key.startsWith('agreement:')); + const confirmations = agreements + .map((key: string): UserConfirmation => ({ name: key.split(':')[1], value: (values[key] as boolean) })); + const rest = Object.entries(values) + .filter((entry: (string | boolean)[]) => !agreements.includes(entry[0] as string)); + + onSubmit({ + ...(Object.fromEntries(rest) as any as RegisterData), + confirmations, + }); + }} + className='register-form' + > + + + + } + placeholder='First name' + /> + + + + + } + placeholder='Last name' + /> + + + + + } + placeholder='Username' + /> - ); - } - private renderUsernameField(): JSX.Element { - const { form } = this.props; - - return ( - - {form.getFieldDecorator('username', { - rules: [ - { - required: true, - message: 'Please specify a username', - }, - { - validator: this.validateUsername, - }, - ], - })( - } - placeholder='Username' - />, - )} + + } + placeholder='Email address' + /> - ); - } - - private renderEmailField(): JSX.Element { - const { form } = this.props; - return ( - - {form.getFieldDecorator('email', { - rules: [ - { - type: 'email', - message: 'The input is not valid E-mail!', - }, - { - required: true, - message: 'Please specify an email address', - }, - ], - })( - } - placeholder='Email address' - />, - )} + + } + placeholder='Password' + /> - ); - } - - private renderPasswordField(): JSX.Element { - const { form } = this.props; - return ( - - {form.getFieldDecorator('password1', { - rules: [ - { - required: true, - message: 'Please input your password!', - }, - { - validator: this.validatePassword, - }, - ], - })( - } - placeholder='Password' - />, - )} + + } + placeholder='Confirm password' + /> - ); - } - - private renderPasswordConfirmationField(): JSX.Element { - const { form } = this.props; - return ( - - {form.getFieldDecorator('password2', { - rules: [ + {userAgreements.map((userAgreement: UserAgreement): JSX.Element => ( + } - placeholder='Confirm password' - />, - )} - - ); - } - - private renderUserAgreements(): JSX.Element[] { - const { form, userAgreements } = this.props; - const getUserAgreementsElements = (): JSX.Element[] => { - const agreementsList: JSX.Element[] = []; - for (const userAgreement of userAgreements) { - agreementsList.push( - - {form.getFieldDecorator(userAgreement.name, { - initialValue: false, - valuePropName: 'checked', - rules: [ - { - required: true, - message: 'You must accept to continue!', - }, - { - validator: this.validateAgrement, - }, - ], - })( - - I read and accept the - - {` ${userAgreement.displayText}`} - - , - )} - , - ); - } - return agreementsList; - }; - - return getUserAgreementsElements(); - } - - public render(): JSX.Element { - const { fetching } = this.props; - - return ( - - - {this.renderFirstNameField()} - {this.renderLastNameField()} - - {this.renderUsernameField()} - {this.renderEmailField()} - {this.renderPasswordField()} - {this.renderPasswordConfirmationField()} - {this.renderUserAgreements()} - - - + message: 'You must accept to continue!', + }, validateAgreement(userAgreements), + ]} + > + + I read and accept the + + {` ${userAgreement.displayText}`} + + - - ); - } + ))} + + + + + + ); } -export default Form.create()(RegisterFormComponent); +export default React.memo(RegisterFormComponent); diff --git a/cvat-ui/src/components/reset-password-confirm-page/reset-password-confirm-form.tsx b/cvat-ui/src/components/reset-password-confirm-page/reset-password-confirm-form.tsx index d2911f6f..a0cbb334 100644 --- a/cvat-ui/src/components/reset-password-confirm-page/reset-password-confirm-form.tsx +++ b/cvat-ui/src/components/reset-password-confirm-page/reset-password-confirm-form.tsx @@ -3,14 +3,13 @@ // SPDX-License-Identifier: MIT import React from 'react'; -import { withRouter, RouteComponentProps } from 'react-router-dom'; -import Form, { FormComponentProps } from '@ant-design/compatible/lib/form/Form'; +import { useLocation } from 'react-router-dom'; +import Form from 'antd/lib/form'; import Button from 'antd/lib/button'; import { LockOutlined } from '@ant-design/icons'; import Input from 'antd/lib/input'; -import patterns from 'utils/validation-patterns'; - +import { validateConfirmation, validatePassword } from 'components/register-page/register-form'; export interface ResetPasswordConfirmData { newPassword1: string; @@ -19,140 +18,73 @@ export interface ResetPasswordConfirmData { token: string; } -type ResetPasswordConfirmFormProps = { +interface Props { fetching: boolean; onSubmit(resetPasswordConfirmData: ResetPasswordConfirmData): void; -} & FormComponentProps & RouteComponentProps; - -class ResetPasswordConfirmFormComponent extends React.PureComponent { - private validateConfirmation = (_: any, value: string, callback: Function): void => { - const { form } = this.props; - if (value && value !== form.getFieldValue('newPassword1')) { - callback('Passwords do not match!'); - } else { - callback(); - } - }; - - private validatePassword = (_: any, value: string, callback: Function): void => { - const { form } = this.props; - if (!patterns.validatePasswordLength.pattern.test(value)) { - callback(patterns.validatePasswordLength.message); - } - - if (!patterns.passwordContainsNumericCharacters.pattern.test(value)) { - callback(patterns.passwordContainsNumericCharacters.message); - } - - if (!patterns.passwordContainsUpperCaseCharacter.pattern.test(value)) { - callback(patterns.passwordContainsUpperCaseCharacter.message); - } - - if (!patterns.passwordContainsLowerCaseCharacter.pattern.test(value)) { - callback(patterns.passwordContainsLowerCaseCharacter.message); - } - - if (value) { - form.validateFields(['newPassword2'], { force: true }); - } - callback(); - }; - - private handleSubmit = (e: React.FormEvent): void => { - e.preventDefault(); - const { form, onSubmit, location } = this.props; - - const params = new URLSearchParams(location.search); - const uid = params.get('uid'); - const token = params.get('token'); - - form.validateFields((error, values): void => { - if (!error) { - const validatedFields = { - ...values, - uid, - token, - }; - - onSubmit(validatedFields); - } - }); - }; - - private renderNewPasswordField(): JSX.Element { - const { form } = this.props; +} - return ( - - {form.getFieldDecorator('newPassword1', { - rules: [ - { - required: true, - message: 'Please input new password!', - }, - { - validator: this.validatePassword, - }, - ], - })( - } - placeholder='New password' - />, - )} +function ResetPasswordConfirmFormComponent({ fetching, onSubmit }: Props): JSX.Element { + const location = useLocation(); + return ( +
): void => { + const params = new URLSearchParams(location.search); + const uid = params.get('uid'); + const token = params.get('token'); + if (uid && token) { + onSubmit(({ ...values, uid, token } as ResetPasswordConfirmData)); + } + }} + className='cvat-reset-password-confirm-form' + > + + } + placeholder='New password' + /> - ); - } - private renderNewPasswordConfirmationField(): JSX.Element { - const { form } = this.props; - - return ( - - {form.getFieldDecorator('newPassword2', { - rules: [ - { - required: true, - message: 'Please confirm your new password!', - }, - { - validator: this.validateConfirmation, - }, - ], - })( - } - placeholder='Confirm new password' - />, - )} + + } + placeholder='Confirm new password' + /> - ); - } - - public render(): JSX.Element { - const { fetching } = this.props; - return ( - - {this.renderNewPasswordField()} - {this.renderNewPasswordConfirmationField()} - - - - - - ); - } + + + + + ); } -export default withRouter(Form.create()(ResetPasswordConfirmFormComponent)); +export default React.memo(ResetPasswordConfirmFormComponent); diff --git a/cvat-ui/src/components/reset-password-page/reset-password-form.tsx b/cvat-ui/src/components/reset-password-page/reset-password-form.tsx index 2107c63e..22fa53a5 100644 --- a/cvat-ui/src/components/reset-password-page/reset-password-form.tsx +++ b/cvat-ui/src/components/reset-password-page/reset-password-form.tsx @@ -3,7 +3,7 @@ // SPDX-License-Identifier: MIT import React from 'react'; -import Form, { FormComponentProps } from '@ant-design/compatible/lib/form/Form'; +import Form from 'antd/lib/form'; import Button from 'antd/lib/button'; import { MailOutlined } from '@ant-design/icons'; import Input from 'antd/lib/input'; @@ -12,70 +12,48 @@ export interface ResetPasswordData { email: string; } -type ResetPasswordFormProps = { +interface Props { fetching: boolean; onSubmit(resetPasswordData: ResetPasswordData): void; -} & FormComponentProps; - -class ResetPasswordFormComponent extends React.PureComponent { - private handleSubmit = (e: React.FormEvent): void => { - e.preventDefault(); - const { form, onSubmit } = this.props; - - form.validateFields((error, values): void => { - if (!error) { - onSubmit(values); - } - }); - }; - - private renderEmailField(): JSX.Element { - const { form } = this.props; +} - return ( - - {form.getFieldDecorator('email', { - rules: [ - { - type: 'email', - message: 'The input is not valid E-mail!', - }, - { - required: true, - message: 'Please specify an email address', - }, - ], - })( - } - placeholder='Email address' - />, - )} +function ResetPasswordFormComponent({ fetching, onSubmit }: Props): JSX.Element { + return ( +
+ + } + placeholder='Email address' + /> - ); - } - - public render(): JSX.Element { - const { fetching } = this.props; - return ( - - {this.renderEmailField()} - - - -
- ); - } + + + + + ); } -export default Form.create()(ResetPasswordFormComponent); +export default React.memo(ResetPasswordFormComponent); diff --git a/cvat-ui/src/components/tasks-page/automatic-annotation-progress.tsx b/cvat-ui/src/components/tasks-page/automatic-annotation-progress.tsx index 4a3c1a9b..e11b90b7 100644 --- a/cvat-ui/src/components/tasks-page/automatic-annotation-progress.tsx +++ b/cvat-ui/src/components/tasks-page/automatic-annotation-progress.tsx @@ -47,7 +47,9 @@ export default function AutomaticAnnotationProgress(props: Props): JSX.Element | Modal.confirm({ title: 'You are going to cancel automatic annotation?', content: 'Reached progress will be lost. Continue?', - okType: 'danger', + okButtonProps: { + danger: true, + }, onOk() { cancelAutoAnnotation(); }, diff --git a/cvat-ui/src/containers/actions-menu/actions-menu.tsx b/cvat-ui/src/containers/actions-menu/actions-menu.tsx index c17e2a31..fa022d1e 100644 --- a/cvat-ui/src/containers/actions-menu/actions-menu.tsx +++ b/cvat-ui/src/containers/actions-menu/actions-menu.tsx @@ -10,7 +10,8 @@ import { CombinedState } from 'reducers/interfaces'; import { modelsActions } from 'actions/models-actions'; import { dumpAnnotationsAsync, loadAnnotationsAsync, exportDatasetAsync, deleteTaskAsync } from 'actions/tasks-actions'; -import { ClickParam } from 'antd/lib/menu'; +// eslint-disable-next-line import/no-extraneous-dependencies +import { MenuInfo } from 'rc-menu/lib/interface'; interface OwnProps { taskInstance: any; @@ -89,7 +90,7 @@ function ActionsMenuContainer(props: OwnProps & StateToProps & DispatchToProps): openRunModelWindow, } = props; - function onClickMenu(params: ClickParam, file?: File): void { + function onClickMenu(params: MenuInfo, file?: File): void { if (params.keyPath.length > 1) { const [additionalKey, action] = params.keyPath; if (action === Actions.DUMP_TASK_ANNO) { diff --git a/cvat-ui/src/containers/annotation-page/top-bar/annotation-menu.tsx b/cvat-ui/src/containers/annotation-page/top-bar/annotation-menu.tsx index a9e88143..a52d3e11 100644 --- a/cvat-ui/src/containers/annotation-page/top-bar/annotation-menu.tsx +++ b/cvat-ui/src/containers/annotation-page/top-bar/annotation-menu.tsx @@ -5,7 +5,8 @@ import React from 'react'; import { withRouter, RouteComponentProps } from 'react-router'; import { connect } from 'react-redux'; -import { ClickParam } from 'antd/lib/menu/index'; +// eslint-disable-next-line import/no-extraneous-dependencies +import { MenuInfo } from 'rc-menu/lib/interface'; import { CombinedState, TaskStatus } from 'reducers/interfaces'; import AnnotationMenuComponent, { Actions } from 'components/annotation-page/top-bar/annotation-menu'; @@ -120,7 +121,7 @@ function AnnotationMenuContainer(props: Props): JSX.Element { updateJob, } = props; - const onClickMenu = (params: ClickParam, file?: File): void => { + const onClickMenu = (params: MenuInfo, file?: File): void => { if (params.keyPath.length > 1) { const [additionalKey, action] = params.keyPath; if (action === Actions.DUMP_TASK_ANNO) { diff --git a/cvat-ui/src/containers/annotation-page/top-bar/top-bar.tsx b/cvat-ui/src/containers/annotation-page/top-bar/top-bar.tsx index e89252cf..ec8560c2 100644 --- a/cvat-ui/src/containers/annotation-page/top-bar/top-bar.tsx +++ b/cvat-ui/src/containers/annotation-page/top-bar/top-bar.tsx @@ -8,8 +8,7 @@ import { connect } from 'react-redux'; import { withRouter } from 'react-router'; import { RouteComponentProps } from 'react-router-dom'; import { GlobalHotKeys, ExtendedKeyMapOptions } from 'react-hotkeys'; -import InputNumber from 'antd/lib/input-number'; -import { SliderValue } from 'antd/lib/slider'; +import Input from 'antd/lib/input'; import { changeFrameAsync, @@ -154,15 +153,13 @@ interface State { type Props = StateToProps & DispatchToProps & RouteComponentProps; class AnnotationTopBarContainer extends React.PureComponent { - private inputFrameRef: React.RefObject; - + private inputFrameRef: React.RefObject; private autoSaveInterval: number | undefined; - private unblock: any; constructor(props: Props) { super(props); - this.inputFrameRef = React.createRef(); + this.inputFrameRef = React.createRef(); this.state = { prevButtonType: 'regular', nextButtonType: 'regular', @@ -408,7 +405,7 @@ class AnnotationTopBarContainer extends React.PureComponent { onSaveAnnotation(jobInstance); }; - private onChangePlayerSliderValue = (value: SliderValue): void => { + private onChangePlayerSliderValue = (value: number): void => { const { playing, onSwitchPlay } = this.props; if (playing) { onSwitchPlay(false);