From 9213275a4d6a510fc3ef07cd2a27fe37b7912429 Mon Sep 17 00:00:00 2001 From: Boris Sekachev Date: Thu, 25 Jun 2020 12:23:19 +0300 Subject: [PATCH 1/9] Appearance block in AAM, React code refactoring --- .../annotation-page/appearance-block.tsx | 214 +++++++++++++++ .../attribute-annotation-sidebar.tsx | 4 + .../objects-side-bar/appearance-block.tsx | 107 -------- .../objects-side-bar/objects-side-bar.tsx | 110 ++++---- .../standard-workspace/standard-workspace.tsx | 4 +- .../objects-side-bar/objects-side-bar.tsx | 246 ------------------ 6 files changed, 276 insertions(+), 409 deletions(-) create mode 100644 cvat-ui/src/components/annotation-page/appearance-block.tsx delete mode 100644 cvat-ui/src/components/annotation-page/standard-workspace/objects-side-bar/appearance-block.tsx delete mode 100644 cvat-ui/src/containers/annotation-page/standard-workspace/objects-side-bar/objects-side-bar.tsx diff --git a/cvat-ui/src/components/annotation-page/appearance-block.tsx b/cvat-ui/src/components/annotation-page/appearance-block.tsx new file mode 100644 index 00000000000..d242c387d39 --- /dev/null +++ b/cvat-ui/src/components/annotation-page/appearance-block.tsx @@ -0,0 +1,214 @@ +// Copyright (C) 2020 Intel Corporation +// +// SPDX-License-Identifier: MIT + +import React, { Dispatch } from 'react'; +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 Checkbox, { CheckboxChangeEvent } from 'antd/lib/checkbox'; +import Collapse from 'antd/lib/collapse'; + +import { ColorBy, CombinedState } from 'reducers/interfaces'; +import { + collapseAppearance as collapseAppearanceAction, + updateTabContentHeight as updateTabContentHeightAction, +} from 'actions/annotation-actions'; +import { + changeShapesColorBy as changeShapesColorByAction, + changeShapesOpacity as changeShapesOpacityAction, + changeSelectedShapesOpacity as changeSelectedShapesOpacityAction, + changeShapesBlackBorders as changeShapesBlackBordersAction, + changeShowBitmap as changeShowBitmapAction, + changeShowProjections as changeShowProjectionsAction, +} from 'actions/settings-actions'; + +interface StateToProps { + appearanceCollapsed: boolean; + colorBy: ColorBy; + opacity: number; + selectedOpacity: number; + blackBorders: boolean; + showBitmap: boolean; + showProjections: boolean; +} + +interface DispatchToProps { + collapseAppearance(): void; + changeShapesColorBy(event: RadioChangeEvent): void; + changeShapesOpacity(event: SliderValue): void; + changeSelectedShapesOpacity(event: SliderValue): void; + changeShapesBlackBorders(event: CheckboxChangeEvent): void; + changeShowBitmap(event: CheckboxChangeEvent): void; + changeShowProjections(event: CheckboxChangeEvent): void; +} + +export function computeHeight(): number { + const [sidebar] = window.document.getElementsByClassName('cvat-objects-sidebar'); + const [appearance] = window.document.getElementsByClassName('cvat-objects-appearance-collapse'); + const [tabs] = Array.from( + window.document.querySelectorAll('.cvat-objects-sidebar-tabs > .ant-tabs-card-bar'), + ); + + if (sidebar && appearance && tabs) { + const maxHeight = sidebar ? sidebar.clientHeight : 0; + const appearanceHeight = appearance ? appearance.clientHeight : 0; + const tabsHeight = tabs ? tabs.clientHeight : 0; + return maxHeight - appearanceHeight - tabsHeight; + } + + return 0; +} + +function mapStateToProps(state: CombinedState): StateToProps { + const { + annotation: { + appearanceCollapsed, + }, + settings: { + shapes: { + colorBy, + opacity, + selectedOpacity, + blackBorders, + showBitmap, + showProjections, + }, + }, + } = state; + + return { + appearanceCollapsed, + colorBy, + opacity, + selectedOpacity, + blackBorders, + showBitmap, + showProjections, + }; +} + + +function mapDispatchToProps(dispatch: Dispatch): DispatchToProps { + return { + collapseAppearance(): void { + dispatch(collapseAppearanceAction()); + const [collapser] = window.document + .getElementsByClassName('cvat-objects-appearance-collapse'); + + if (collapser) { + const listener = (event: Event): void => { + if ((event as TransitionEvent).propertyName === 'height') { + const height = computeHeight(); + dispatch(updateTabContentHeightAction(height)); + collapser.removeEventListener('transitionend', listener); + } + }; + + collapser.addEventListener('transitionend', listener); + } + }, + changeShapesColorBy(event: RadioChangeEvent): void { + dispatch(changeShapesColorByAction(event.target.value)); + }, + changeShapesOpacity(value: SliderValue): void { + dispatch(changeShapesOpacityAction(value as number)); + }, + changeSelectedShapesOpacity(value: SliderValue): void { + dispatch(changeSelectedShapesOpacityAction(value as number)); + }, + changeShapesBlackBorders(event: CheckboxChangeEvent): void { + dispatch(changeShapesBlackBordersAction(event.target.checked)); + }, + changeShowBitmap(event: CheckboxChangeEvent): void { + dispatch(changeShowBitmapAction(event.target.checked)); + }, + changeShowProjections(event: CheckboxChangeEvent): void { + dispatch(changeShowProjectionsAction(event.target.checked)); + }, + }; +} + +type Props = StateToProps & DispatchToProps; + +function AppearanceBlock(props: Props): JSX.Element { + const { + appearanceCollapsed, + colorBy, + opacity, + selectedOpacity, + blackBorders, + showBitmap, + showProjections, + collapseAppearance, + changeShapesColorBy, + changeShapesOpacity, + changeSelectedShapesOpacity, + changeShapesBlackBorders, + changeShowBitmap, + changeShowProjections, + } = props; + + return ( + + Appearance + } + key='appearance' + > +
+ Color by + + {ColorBy.INSTANCE} + {ColorBy.GROUP} + {ColorBy.LABEL} + + Opacity + + Selected opacity + + + Black borders + + + Show bitmap + + + Show projections + +
+
+
+ ); +} + +export default connect( + mapStateToProps, + mapDispatchToProps, +)(React.memo(AppearanceBlock)); diff --git a/cvat-ui/src/components/annotation-page/attribute-annotation-workspace/attribute-annotation-sidebar/attribute-annotation-sidebar.tsx b/cvat-ui/src/components/annotation-page/attribute-annotation-workspace/attribute-annotation-sidebar/attribute-annotation-sidebar.tsx index 75ed16cb941..f86da50408d 100644 --- a/cvat-ui/src/components/annotation-page/attribute-annotation-workspace/attribute-annotation-sidebar/attribute-annotation-sidebar.tsx +++ b/cvat-ui/src/components/annotation-page/attribute-annotation-workspace/attribute-annotation-sidebar/attribute-annotation-sidebar.tsx @@ -21,6 +21,8 @@ import { } from 'actions/annotation-actions'; import { CombinedState } from 'reducers/interfaces'; import AnnotationsFiltersInput from 'components/annotation-page/annotations-filters-input'; +import AppearanceBlock from 'components/annotation-page/appearance-block'; + import ObjectSwitcher from './object-switcher'; import AttributeSwitcher from './attribute-switcher'; import ObjectBasicsEditor from './object-basics-edtior'; @@ -308,6 +310,8 @@ function AttributeAnnotationSidebar(props: StateToProps & DispatchToProps): JSX. ) } + + { !sidebarCollapsed && } ); } diff --git a/cvat-ui/src/components/annotation-page/standard-workspace/objects-side-bar/appearance-block.tsx b/cvat-ui/src/components/annotation-page/standard-workspace/objects-side-bar/appearance-block.tsx deleted file mode 100644 index d42d7a42d89..00000000000 --- a/cvat-ui/src/components/annotation-page/standard-workspace/objects-side-bar/appearance-block.tsx +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright (C) 2020 Intel Corporation -// -// SPDX-License-Identifier: MIT - -import React from 'react'; -import Text from 'antd/lib/typography/Text'; -import Radio, { RadioChangeEvent } from 'antd/lib/radio'; -import Slider, { SliderValue } from 'antd/lib/slider'; -import Checkbox, { CheckboxChangeEvent } from 'antd/lib/checkbox'; -import Collapse from 'antd/lib/collapse'; - -import { ColorBy } from 'reducers/interfaces'; - -interface Props { - appearanceCollapsed: boolean; - colorBy: ColorBy; - opacity: number; - selectedOpacity: number; - blackBorders: boolean; - showBitmap: boolean; - showProjections: boolean; - - collapseAppearance(): void; - changeShapesColorBy(event: RadioChangeEvent): void; - changeShapesOpacity(event: SliderValue): void; - changeSelectedShapesOpacity(event: SliderValue): void; - changeShapesBlackBorders(event: CheckboxChangeEvent): void; - changeShowBitmap(event: CheckboxChangeEvent): void; - changeShowProjections(event: CheckboxChangeEvent): void; -} - -function AppearanceBlock(props: Props): JSX.Element { - const { - appearanceCollapsed, - colorBy, - opacity, - selectedOpacity, - blackBorders, - showBitmap, - showProjections, - collapseAppearance, - changeShapesColorBy, - changeShapesOpacity, - changeSelectedShapesOpacity, - changeShapesBlackBorders, - changeShowBitmap, - changeShowProjections, - } = props; - - return ( - - Appearance - } - key='appearance' - > -
- Color by - - {ColorBy.INSTANCE} - {ColorBy.GROUP} - {ColorBy.LABEL} - - Opacity - - Selected opacity - - - Black borders - - - Show bitmap - - - Show projections - -
-
-
- ); -} - -export default React.memo(AppearanceBlock); diff --git a/cvat-ui/src/components/annotation-page/standard-workspace/objects-side-bar/objects-side-bar.tsx b/cvat-ui/src/components/annotation-page/standard-workspace/objects-side-bar/objects-side-bar.tsx index eb3194e3db7..744168e0095 100644 --- a/cvat-ui/src/components/annotation-page/standard-workspace/objects-side-bar/objects-side-bar.tsx +++ b/cvat-ui/src/components/annotation-page/standard-workspace/objects-side-bar/objects-side-bar.tsx @@ -3,78 +3,77 @@ // SPDX-License-Identifier: MIT import './styles.scss'; -import React from 'react'; +import React, { Dispatch, useEffect } from 'react'; +import { AnyAction } from 'redux'; +import { connect } from 'react-redux'; import Text from 'antd/lib/typography/Text'; import Icon from 'antd/lib/icon'; import Tabs from 'antd/lib/tabs'; import Layout from 'antd/lib/layout'; -import { RadioChangeEvent } from 'antd/lib/radio'; -import { SliderValue } from 'antd/lib/slider'; -import { CheckboxChangeEvent } from 'antd/lib/checkbox'; -import { ColorBy } from 'reducers/interfaces'; +import { CombinedState } from 'reducers/interfaces'; import ObjectsListContainer from 'containers/annotation-page/standard-workspace/objects-side-bar/objects-list'; import LabelsListContainer from 'containers/annotation-page/standard-workspace/objects-side-bar/labels-list'; -import AppearanceBlock from './appearance-block'; +import { + collapseSidebar as collapseSidebarAction, + updateTabContentHeight as updateTabContentHeightAction, +} from 'actions/annotation-actions'; +import AppearanceBlock, { computeHeight } from 'components/annotation-page/appearance-block'; -interface Props { +interface StateToProps { sidebarCollapsed: boolean; - appearanceCollapsed: boolean; - colorBy: ColorBy; - opacity: number; - selectedOpacity: number; - blackBorders: boolean; - showBitmap: boolean; - showProjections: boolean; +} +interface DispatchToProps { collapseSidebar(): void; - collapseAppearance(): void; + updateTabContentHeight(): void; +} + +function mapStateToProps(state: CombinedState): StateToProps { + const { + annotation: { + sidebarCollapsed, + }, + } = state; - changeShapesColorBy(event: RadioChangeEvent): void; - changeShapesOpacity(event: SliderValue): void; - changeSelectedShapesOpacity(event: SliderValue): void; - changeShapesBlackBorders(event: CheckboxChangeEvent): void; - changeShowBitmap(event: CheckboxChangeEvent): void; - changeShowProjections(event: CheckboxChangeEvent): void; + return { + sidebarCollapsed, + }; } -function ObjectsSideBar(props: Props): JSX.Element { +function mapDispatchToProps(dispatch: Dispatch): DispatchToProps { + return { + collapseSidebar(): void { + dispatch(collapseSidebarAction()); + }, + updateTabContentHeight(): void { + const height = computeHeight(); + dispatch(updateTabContentHeightAction(height)); + }, + }; +} + +function ObjectsSideBar(props: StateToProps & DispatchToProps): JSX.Element { const { sidebarCollapsed, - appearanceCollapsed, - colorBy, - opacity, - selectedOpacity, - blackBorders, - showBitmap, - showProjections, collapseSidebar, - collapseAppearance, - changeShapesColorBy, - changeShapesOpacity, - changeSelectedShapesOpacity, - changeShapesBlackBorders, - changeShowBitmap, - changeShowProjections, + updateTabContentHeight, } = props; - const appearanceProps = { - collapseAppearance, - appearanceCollapsed, - colorBy, - opacity, - selectedOpacity, - blackBorders, - showBitmap, - showProjections, + useEffect(() => { + const alignTabHeight = (): void => { + if (!sidebarCollapsed) { + updateTabContentHeight(); + } + }; - changeShapesColorBy, - changeShapesOpacity, - changeSelectedShapesOpacity, - changeShapesBlackBorders, - changeShowBitmap, - changeShowProjections, - }; + window.addEventListener('resize', alignTabHeight); + alignTabHeight(); + + return () => { + window.removeEventListener('resize', alignTabHeight); + }; + }, []); return ( - { !sidebarCollapsed && } + { !sidebarCollapsed && } ); } -export default React.memo(ObjectsSideBar); +export default connect( + mapStateToProps, + mapDispatchToProps, +)(React.memo(ObjectsSideBar)); diff --git a/cvat-ui/src/components/annotation-page/standard-workspace/standard-workspace.tsx b/cvat-ui/src/components/annotation-page/standard-workspace/standard-workspace.tsx index b6278f1b3f1..d57be1ec224 100644 --- a/cvat-ui/src/components/annotation-page/standard-workspace/standard-workspace.tsx +++ b/cvat-ui/src/components/annotation-page/standard-workspace/standard-workspace.tsx @@ -8,9 +8,9 @@ import Layout from 'antd/lib/layout'; import CanvasWrapperContainer from 'containers/annotation-page/standard-workspace/canvas-wrapper'; import ControlsSideBarContainer from 'containers/annotation-page/standard-workspace/controls-side-bar/controls-side-bar'; -import ObjectSideBarContainer from 'containers/annotation-page/standard-workspace/objects-side-bar/objects-side-bar'; import PropagateConfirmContainer from 'containers/annotation-page/standard-workspace/propagate-confirm'; import CanvasContextMenuContainer from 'containers/annotation-page/standard-workspace/canvas-context-menu'; +import ObjectSideBarComponent from 'components/annotation-page/standard-workspace/objects-side-bar/objects-side-bar'; import CanvasPointContextMenuComponent from 'components/annotation-page/standard-workspace/canvas-point-context-menu'; export default function StandardWorkspaceComponent(): JSX.Element { @@ -18,7 +18,7 @@ export default function StandardWorkspaceComponent(): JSX.Element { - + diff --git a/cvat-ui/src/containers/annotation-page/standard-workspace/objects-side-bar/objects-side-bar.tsx b/cvat-ui/src/containers/annotation-page/standard-workspace/objects-side-bar/objects-side-bar.tsx deleted file mode 100644 index 906e0fc2835..00000000000 --- a/cvat-ui/src/containers/annotation-page/standard-workspace/objects-side-bar/objects-side-bar.tsx +++ /dev/null @@ -1,246 +0,0 @@ -// Copyright (C) 2020 Intel Corporation -// -// SPDX-License-Identifier: MIT - - -import React from 'react'; -import { connect } from 'react-redux'; - -import { RadioChangeEvent } from 'antd/lib/radio'; -import { SliderValue } from 'antd/lib/slider'; -import { CheckboxChangeEvent } from 'antd/lib/checkbox'; - -import ObjectsSidebarComponent from 'components/annotation-page/standard-workspace/objects-side-bar/objects-side-bar'; -import { - CombinedState, - ColorBy, -} from 'reducers/interfaces'; - -import { - collapseSidebar as collapseSidebarAction, - collapseAppearance as collapseAppearanceAction, - updateTabContentHeight as updateTabContentHeightAction, -} from 'actions/annotation-actions'; - -import { - changeShapesColorBy as changeShapesColorByAction, - changeShapesOpacity as changeShapesOpacityAction, - changeSelectedShapesOpacity as changeSelectedShapesOpacityAction, - changeShapesBlackBorders as changeShapesBlackBordersAction, - changeShowBitmap as changeShowUnlabeledRegionsAction, - changeShowProjections as changeShowProjectionsAction, -} from 'actions/settings-actions'; - - -interface StateToProps { - sidebarCollapsed: boolean; - appearanceCollapsed: boolean; - colorBy: ColorBy; - opacity: number; - selectedOpacity: number; - blackBorders: boolean; - showBitmap: boolean; - showProjections: boolean; -} - -interface DispatchToProps { - collapseSidebar(): void; - collapseAppearance(): void; - updateTabContentHeight(): void; - changeShapesColorBy(colorBy: ColorBy): void; - changeShapesOpacity(shapesOpacity: number): void; - changeSelectedShapesOpacity(selectedShapesOpacity: number): void; - changeShapesBlackBorders(blackBorders: boolean): void; - changeShowBitmap(showBitmap: boolean): void; - changeShowProjections(showProjections: boolean): void; -} - -function mapStateToProps(state: CombinedState): StateToProps { - const { - annotation: { - sidebarCollapsed, - appearanceCollapsed, - }, - settings: { - shapes: { - colorBy, - opacity, - selectedOpacity, - blackBorders, - showBitmap, - showProjections, - }, - }, - } = state; - - return { - sidebarCollapsed, - appearanceCollapsed, - colorBy, - opacity, - selectedOpacity, - blackBorders, - showBitmap, - showProjections, - }; -} - -function computeHeight(): number { - const [sidebar] = window.document.getElementsByClassName('cvat-objects-sidebar'); - const [appearance] = window.document.getElementsByClassName('cvat-objects-appearance-collapse'); - const [tabs] = Array.from( - window.document.querySelectorAll('.cvat-objects-sidebar-tabs > .ant-tabs-card-bar'), - ); - - if (sidebar && appearance && tabs) { - const maxHeight = sidebar ? sidebar.clientHeight : 0; - const appearanceHeight = appearance ? appearance.clientHeight : 0; - const tabsHeight = tabs ? tabs.clientHeight : 0; - return maxHeight - appearanceHeight - tabsHeight; - } - - return 0; -} - -function mapDispatchToProps(dispatch: any): DispatchToProps { - return { - collapseSidebar(): void { - dispatch(collapseSidebarAction()); - }, - collapseAppearance(): void { - dispatch(collapseAppearanceAction()); - - const [collapser] = window.document - .getElementsByClassName('cvat-objects-appearance-collapse'); - - if (collapser) { - collapser.addEventListener('transitionend', () => { - dispatch( - updateTabContentHeightAction( - computeHeight(), - ), - ); - }, { once: true }); - } - }, - updateTabContentHeight(): void { - dispatch( - updateTabContentHeightAction( - computeHeight(), - ), - ); - }, - changeShapesColorBy(colorBy: ColorBy): void { - dispatch(changeShapesColorByAction(colorBy)); - }, - changeShapesOpacity(shapesOpacity: number): void { - dispatch(changeShapesOpacityAction(shapesOpacity)); - }, - changeSelectedShapesOpacity(selectedShapesOpacity: number): void { - dispatch(changeSelectedShapesOpacityAction(selectedShapesOpacity)); - }, - changeShapesBlackBorders(blackBorders: boolean): void { - dispatch(changeShapesBlackBordersAction(blackBorders)); - }, - changeShowBitmap(showBitmap: boolean) { - dispatch(changeShowUnlabeledRegionsAction(showBitmap)); - }, - changeShowProjections(showProjections: boolean) { - dispatch(changeShowProjectionsAction(showProjections)); - }, - }; -} - -type Props = StateToProps & DispatchToProps; -class ObjectsSideBarContainer extends React.PureComponent { - public componentDidMount(): void { - window.addEventListener('resize', this.alignTabHeight); - this.alignTabHeight(); - } - - public componentWillUnmount(): void { - window.removeEventListener('resize', this.alignTabHeight); - } - - private alignTabHeight = (): void => { - const { - sidebarCollapsed, - updateTabContentHeight, - } = this.props; - - if (!sidebarCollapsed) { - updateTabContentHeight(); - } - }; - - private changeShapesColorBy = (event: RadioChangeEvent): void => { - const { changeShapesColorBy } = this.props; - changeShapesColorBy(event.target.value); - }; - - private changeShapesOpacity = (value: SliderValue): void => { - const { changeShapesOpacity } = this.props; - changeShapesOpacity(value as number); - }; - - private changeSelectedShapesOpacity = (value: SliderValue): void => { - const { changeSelectedShapesOpacity } = this.props; - changeSelectedShapesOpacity(value as number); - }; - - private changeShapesBlackBorders = (event: CheckboxChangeEvent): void => { - const { changeShapesBlackBorders } = this.props; - changeShapesBlackBorders(event.target.checked); - }; - - private changeShowBitmap = (event: CheckboxChangeEvent): void => { - const { changeShowBitmap } = this.props; - changeShowBitmap(event.target.checked); - }; - - private changeShowProjections = (event: CheckboxChangeEvent): void => { - const { changeShowProjections } = this.props; - changeShowProjections(event.target.checked); - }; - - public render(): JSX.Element { - const { - sidebarCollapsed, - appearanceCollapsed, - colorBy, - opacity, - selectedOpacity, - blackBorders, - showBitmap, - showProjections, - collapseSidebar, - collapseAppearance, - } = this.props; - - return ( - - ); - } -} - -export default connect( - mapStateToProps, - mapDispatchToProps, -)(ObjectsSideBarContainer); From 700ae4c934be071fbf03cf1bb8305516f3f0f1be Mon Sep 17 00:00:00 2001 From: Boris Sekachev Date: Thu, 25 Jun 2020 12:32:17 +0300 Subject: [PATCH 2/9] Removed extra code --- .../create-model-page/create-model-page.tsx | 9 +-------- .../containers/create-task-page/create-task-page.tsx | 9 +-------- .../model-runner-dialog/model-runner-dialog.tsx | 10 +--------- .../src/containers/register-page/register-page.tsx | 3 +-- cvat-ui/src/containers/task-page/task-page.tsx | 9 +-------- cvat-ui/src/containers/tasks-page/task-item.tsx | 1 - cvat-ui/src/containers/tasks-page/tasks-page.tsx | 11 +---------- 7 files changed, 6 insertions(+), 46 deletions(-) diff --git a/cvat-ui/src/containers/create-model-page/create-model-page.tsx b/cvat-ui/src/containers/create-model-page/create-model-page.tsx index 75c15028e12..74cd406ea87 100644 --- a/cvat-ui/src/containers/create-model-page/create-model-page.tsx +++ b/cvat-ui/src/containers/create-model-page/create-model-page.tsx @@ -2,7 +2,6 @@ // // SPDX-License-Identifier: MIT -import React from 'react'; import { connect } from 'react-redux'; import CreateModelPageComponent from 'components/create-model-page/create-model-page'; @@ -38,13 +37,7 @@ function mapDispatchToProps(dispatch: any): DispatchToProps { }; } -function CreateModelPageContainer(props: StateToProps & DispatchToProps): JSX.Element { - return ( - - ); -} - export default connect( mapStateToProps, mapDispatchToProps, -)(CreateModelPageContainer); +)(CreateModelPageComponent); diff --git a/cvat-ui/src/containers/create-task-page/create-task-page.tsx b/cvat-ui/src/containers/create-task-page/create-task-page.tsx index 5fecbd07e1f..09685de6453 100644 --- a/cvat-ui/src/containers/create-task-page/create-task-page.tsx +++ b/cvat-ui/src/containers/create-task-page/create-task-page.tsx @@ -2,7 +2,6 @@ // // SPDX-License-Identifier: MIT -import React from 'react'; import { connect } from 'react-redux'; import { CombinedState } from 'reducers/interfaces'; @@ -34,13 +33,7 @@ function mapStateToProps(state: CombinedState): StateToProps { }; } -function CreateTaskPageContainer(props: StateToProps & DispatchToProps): JSX.Element { - return ( - - ); -} - export default connect( mapStateToProps, mapDispatchToProps, -)(CreateTaskPageContainer); +)(CreateTaskComponent); diff --git a/cvat-ui/src/containers/model-runner-dialog/model-runner-dialog.tsx b/cvat-ui/src/containers/model-runner-dialog/model-runner-dialog.tsx index 218ba63819c..4855f62d16a 100644 --- a/cvat-ui/src/containers/model-runner-dialog/model-runner-dialog.tsx +++ b/cvat-ui/src/containers/model-runner-dialog/model-runner-dialog.tsx @@ -2,7 +2,6 @@ // // SPDX-License-Identifier: MIT -import React from 'react'; import { connect } from 'react-redux'; import ModelRunnerModalComponent from 'components/model-runner-modal/model-runner-modal'; @@ -75,14 +74,7 @@ function mapDispatchToProps(dispatch: any): DispatchToProps { }); } - -function ModelRunnerModalContainer(props: StateToProps & DispatchToProps): JSX.Element { - return ( - - ); -} - export default connect( mapStateToProps, mapDispatchToProps, -)(ModelRunnerModalContainer); +)(ModelRunnerModalComponent); diff --git a/cvat-ui/src/containers/register-page/register-page.tsx b/cvat-ui/src/containers/register-page/register-page.tsx index 1f974fe7041..c05bd31c715 100644 --- a/cvat-ui/src/containers/register-page/register-page.tsx +++ b/cvat-ui/src/containers/register-page/register-page.tsx @@ -6,13 +6,12 @@ import React from 'react'; import { connect } from 'react-redux'; import { registerAsync } from 'actions/auth-actions'; import RegisterPageComponent from 'components/register-page/register-page'; -import { UserConfirmation } from 'components/register-page/register-form' +import { UserConfirmation } from 'components/register-page/register-form'; import { CombinedState, UserAgreement } from 'reducers/interfaces'; interface StateToProps { fetching: boolean; userAgreements: UserAgreement[]; - } interface DispatchToProps { diff --git a/cvat-ui/src/containers/task-page/task-page.tsx b/cvat-ui/src/containers/task-page/task-page.tsx index 77f73f09d9c..01b4b4ed5c6 100644 --- a/cvat-ui/src/containers/task-page/task-page.tsx +++ b/cvat-ui/src/containers/task-page/task-page.tsx @@ -2,7 +2,6 @@ // // SPDX-License-Identifier: MIT -import React from 'react'; import { connect } from 'react-redux'; import { withRouter } from 'react-router-dom'; import { RouteComponentProps } from 'react-router'; @@ -74,13 +73,7 @@ function mapDispatchToProps(dispatch: any, own: Props): DispatchToProps { }; } -function TaskPageContainer(props: StateToProps & DispatchToProps): JSX.Element { - return ( - - ); -} - export default withRouter(connect( mapStateToProps, mapDispatchToProps, -)(TaskPageContainer)); +)(TaskPageComponent)); diff --git a/cvat-ui/src/containers/tasks-page/task-item.tsx b/cvat-ui/src/containers/tasks-page/task-item.tsx index 59717a7bd32..682fc34ab7e 100644 --- a/cvat-ui/src/containers/tasks-page/task-item.tsx +++ b/cvat-ui/src/containers/tasks-page/task-item.tsx @@ -2,7 +2,6 @@ // // SPDX-License-Identifier: MIT -import React from 'react'; import { connect } from 'react-redux'; import { diff --git a/cvat-ui/src/containers/tasks-page/tasks-page.tsx b/cvat-ui/src/containers/tasks-page/tasks-page.tsx index 545912aaef5..071c1cc75fd 100644 --- a/cvat-ui/src/containers/tasks-page/tasks-page.tsx +++ b/cvat-ui/src/containers/tasks-page/tasks-page.tsx @@ -2,7 +2,6 @@ // // SPDX-License-Identifier: MIT -import React from 'react'; import { connect } from 'react-redux'; import { @@ -55,15 +54,7 @@ function mapDispatchToProps(dispatch: any): DispatchToProps { }; } -type TasksPageContainerProps = StateToProps & DispatchToProps; - -function TasksPageContainer(props: TasksPageContainerProps): JSX.Element { - return ( - - ); -} - export default connect( mapStateToProps, mapDispatchToProps, -)(TasksPageContainer); +)(TasksPageComponent); From 6c771bfa9324fba79838fbb6d303bf4fc5dfaa36 Mon Sep 17 00:00:00 2001 From: Boris Sekachev Date: Thu, 25 Jun 2020 13:28:35 +0300 Subject: [PATCH 3/9] Fixed: attribute value isn't updated for text and number in AAM when change an object --- .../attribute-annotation-sidebar.tsx | 1 + .../attribute-editor.tsx | 13 +++++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/cvat-ui/src/components/annotation-page/attribute-annotation-workspace/attribute-annotation-sidebar/attribute-annotation-sidebar.tsx b/cvat-ui/src/components/annotation-page/attribute-annotation-workspace/attribute-annotation-sidebar/attribute-annotation-sidebar.tsx index f86da50408d..14c71d82707 100644 --- a/cvat-ui/src/components/annotation-page/attribute-annotation-workspace/attribute-annotation-sidebar/attribute-annotation-sidebar.tsx +++ b/cvat-ui/src/components/annotation-page/attribute-annotation-workspace/attribute-annotation-sidebar/attribute-annotation-sidebar.tsx @@ -286,6 +286,7 @@ function AttributeAnnotationSidebar(props: StateToProps & DispatchToProps): JSX. nextAttribute={nextAttribute} /> { diff --git a/cvat-ui/src/components/annotation-page/attribute-annotation-workspace/attribute-annotation-sidebar/attribute-editor.tsx b/cvat-ui/src/components/annotation-page/attribute-annotation-workspace/attribute-annotation-sidebar/attribute-editor.tsx index 6917e42fbf2..2f0b4c005db 100644 --- a/cvat-ui/src/components/annotation-page/attribute-annotation-workspace/attribute-annotation-sidebar/attribute-editor.tsx +++ b/cvat-ui/src/components/annotation-page/attribute-annotation-workspace/attribute-annotation-sidebar/attribute-editor.tsx @@ -13,6 +13,7 @@ import Input from 'antd/lib/input'; import consts from 'consts'; interface InputElementParameters { + clientID: number; attrID: number; inputType: string; values: string[]; @@ -24,6 +25,7 @@ function renderInputElement(parameters: InputElementParameters): JSX.Element { const { inputType, attrID, + clientID, values, currentValue, onChange, @@ -103,7 +105,7 @@ function renderInputElement(parameters: InputElementParameters): JSX.Element {
) => { const { value } = event.target; @@ -257,13 +259,19 @@ function renderList(parameters: ListParameters): JSX.Element | null { } interface Props { + clientID: number; attribute: any; currentValue: string; onChange(value: string): void; } function AttributeEditor(props: Props): JSX.Element { - const { attribute, currentValue, onChange } = props; + const { + attribute, + currentValue, + onChange, + clientID, + } = props; const { inputType, values, id: attrID } = attribute; return ( @@ -271,6 +279,7 @@ function AttributeEditor(props: Props): JSX.Element { {renderList({ values, inputType, onChange })}
{renderInputElement({ + clientID, attrID, inputType, currentValue, From 68a581e6ec7a591f541f415eb5644a243efedf08 Mon Sep 17 00:00:00 2001 From: Boris Sekachev Date: Thu, 25 Jun 2020 14:22:50 +0300 Subject: [PATCH 4/9] Object item refactoring (splitted into several files) --- .../object-item-attribute.tsx | 175 +++++ .../objects-side-bar/object-item-basics.tsx | 131 ++++ .../objects-side-bar/object-item-buttons.tsx | 245 ++++++ .../objects-side-bar/object-item-details.tsx | 86 +++ .../objects-side-bar/object-item-menu.tsx | 139 ++++ .../objects-side-bar/object-item.tsx | 717 +----------------- 6 files changed, 781 insertions(+), 712 deletions(-) create mode 100644 cvat-ui/src/components/annotation-page/standard-workspace/objects-side-bar/object-item-attribute.tsx create mode 100644 cvat-ui/src/components/annotation-page/standard-workspace/objects-side-bar/object-item-basics.tsx create mode 100644 cvat-ui/src/components/annotation-page/standard-workspace/objects-side-bar/object-item-buttons.tsx create mode 100644 cvat-ui/src/components/annotation-page/standard-workspace/objects-side-bar/object-item-details.tsx create mode 100644 cvat-ui/src/components/annotation-page/standard-workspace/objects-side-bar/object-item-menu.tsx 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 new file mode 100644 index 00000000000..aca9779e2db --- /dev/null +++ b/cvat-ui/src/components/annotation-page/standard-workspace/objects-side-bar/object-item-attribute.tsx @@ -0,0 +1,175 @@ +// Copyright (C) 2020 Intel Corporation +// +// SPDX-License-Identifier: MIT + +import React from 'react'; +import { Col } from 'antd/lib/grid'; +import Select from 'antd/lib/select'; +import Radio, { RadioChangeEvent } from 'antd/lib/radio'; +import Checkbox, { CheckboxChangeEvent } from 'antd/lib/checkbox'; +import Input from 'antd/lib/input'; +import InputNumber from 'antd/lib/input-number'; +import Text from 'antd/lib/typography/Text'; + +import consts from 'consts'; +import { clamp } from 'utils/math'; + +interface Props { + attrInputType: string; + attrValues: string[]; + attrValue: string; + attrName: string; + attrID: number; + changeAttribute(attrID: number, value: string): void; +} + +function attrIsTheSame( + prevProps: Props, + nextProps: Props, +): boolean { + return nextProps.attrID === prevProps.attrID + && nextProps.attrValue === prevProps.attrValue + && nextProps.attrName === prevProps.attrName + && nextProps.attrInputType === prevProps.attrInputType + && nextProps.attrValues + .map((value: string, id: number): boolean => prevProps.attrValues[id] === value) + .every((value: boolean): boolean => value); +} + +function ItemAttributeComponent(props: Props): JSX.Element { + const { + attrInputType, + attrValues, + attrValue, + attrName, + attrID, + changeAttribute, + } = props; + + if (attrInputType === 'checkbox') { + return ( + + { + const value = event.target.checked ? 'true' : 'false'; + changeAttribute(attrID, value); + }} + > + + {attrName} + + + + ); + } + + if (attrInputType === 'radio') { + return ( + +
+ + {attrName} + + { + changeAttribute(attrID, event.target.value); + }} + > + { attrValues.map((value: string): JSX.Element => ( + + {value === consts.UNDEFINED_ATTRIBUTE_VALUE + ? consts.NO_BREAK_SPACE : value} + + )) } + +
+ + ); + } + + if (attrInputType === 'select') { + return ( + <> + + + {attrName} + + + + + + + ); + } + + if (attrInputType === 'number') { + const [min, max, step] = attrValues.map((value: string): number => +value); + + return ( + <> + + + {attrName} + + + + { + if (typeof (value) === 'number') { + changeAttribute( + attrID, `${clamp(value, min, max)}`, + ); + } + }} + value={+attrValue} + className='cvat-object-item-number-attribute' + min={min} + max={max} + step={step} + /> + + + ); + } + + return ( + <> + + + {attrName} + + + + ): void => { + changeAttribute(attrID, event.target.value); + }} + value={attrValue} + className='cvat-object-item-text-attribute' + /> + + + ); +} + +export default React.memo(ItemAttributeComponent, attrIsTheSame); diff --git a/cvat-ui/src/components/annotation-page/standard-workspace/objects-side-bar/object-item-basics.tsx b/cvat-ui/src/components/annotation-page/standard-workspace/objects-side-bar/object-item-basics.tsx new file mode 100644 index 00000000000..08536f877ed --- /dev/null +++ b/cvat-ui/src/components/annotation-page/standard-workspace/objects-side-bar/object-item-basics.tsx @@ -0,0 +1,131 @@ +// Copyright (C) 2020 Intel Corporation +// +// SPDX-License-Identifier: MIT + +import React from 'react'; +import { Row, Col } from 'antd/lib/grid'; +import Icon from 'antd/lib/icon'; +import Select, { OptionProps } from 'antd/lib/select'; +import Dropdown from 'antd/lib/dropdown'; +import Text from 'antd/lib/typography/Text'; +import Tooltip from 'antd/lib/tooltip'; + +import { ObjectType, ShapeType } from 'reducers/interfaces'; +import ItemMenu from './object-item-menu'; + +interface Props { + clientID: number; + serverID: number | undefined; + labelID: number; + labels: any[]; + shapeType: ShapeType; + objectType: ObjectType; + type: string; + locked: boolean; + copyShortcut: string; + pasteShortcut: string; + propagateShortcut: string; + toBackgroundShortcut: string; + toForegroundShortcut: string; + removeShortcut: string; + changeLabel(labelID: string): void; + copy(): void; + remove(): void; + propagate(): void; + createURL(): void; + switchOrientation(): void; + toBackground(): void; + toForeground(): void; + resetCuboidPerspective(): void; +} + +function ItemTopComponent(props: Props): JSX.Element { + const { + clientID, + serverID, + labelID, + labels, + shapeType, + objectType, + type, + locked, + copyShortcut, + pasteShortcut, + propagateShortcut, + toBackgroundShortcut, + toForegroundShortcut, + removeShortcut, + changeLabel, + copy, + remove, + propagate, + createURL, + switchOrientation, + toBackground, + toForeground, + resetCuboidPerspective, + } = props; + + return ( + + + {clientID} +
+ {type} + + + + + + + + + + + +
+ ); +} + +export default React.memo(ItemTopComponent); diff --git a/cvat-ui/src/components/annotation-page/standard-workspace/objects-side-bar/object-item-buttons.tsx b/cvat-ui/src/components/annotation-page/standard-workspace/objects-side-bar/object-item-buttons.tsx new file mode 100644 index 00000000000..5b227347060 --- /dev/null +++ b/cvat-ui/src/components/annotation-page/standard-workspace/objects-side-bar/object-item-buttons.tsx @@ -0,0 +1,245 @@ +// Copyright (C) 2020 Intel Corporation +// +// SPDX-License-Identifier: MIT + +import React from 'react'; +import { Row, Col } from 'antd/lib/grid'; +import Icon from 'antd/lib/icon'; +import Tooltip from 'antd/lib/tooltip'; + +import { + ObjectOutsideIcon, + FirstIcon, + LastIcon, + PreviousIcon, + NextIcon, +} from 'icons'; +import { ObjectType, ShapeType } from 'reducers/interfaces'; + +interface Props { + objectType: ObjectType; + shapeType: ShapeType; + occluded: boolean; + outside: boolean | undefined; + locked: boolean; + pinned: boolean; + hidden: boolean; + keyframe: boolean | undefined; + switchOccludedShortcut: string; + switchOutsideShortcut: string; + switchLockShortcut: string; + switchHiddenShortcut: string; + switchKeyFrameShortcut: string; + nextKeyFrameShortcut: string; + prevKeyFrameShortcut: string; + + navigateFirstKeyframe: null | (() => void); + navigatePrevKeyframe: null | (() => void); + navigateNextKeyframe: null | (() => void); + navigateLastKeyframe: null | (() => void); + + setOccluded(): void; + unsetOccluded(): void; + setOutside(): void; + unsetOutside(): void; + setKeyframe(): void; + unsetKeyframe(): void; + lock(): void; + unlock(): void; + pin(): void; + unpin(): void; + hide(): void; + show(): void; +} + +function ItemButtonsComponent(props: Props): JSX.Element { + const { + objectType, + shapeType, + occluded, + outside, + locked, + pinned, + hidden, + keyframe, + switchOccludedShortcut, + switchOutsideShortcut, + switchLockShortcut, + switchHiddenShortcut, + switchKeyFrameShortcut, + nextKeyFrameShortcut, + prevKeyFrameShortcut, + + navigateFirstKeyframe, + navigatePrevKeyframe, + navigateNextKeyframe, + navigateLastKeyframe, + + setOccluded, + unsetOccluded, + setOutside, + unsetOutside, + setKeyframe, + unsetKeyframe, + lock, + unlock, + pin, + unpin, + hide, + show, + } = props; + + if (objectType === ObjectType.TRACK) { + return ( + + + + + { navigateFirstKeyframe + ? + : } + + + { navigatePrevKeyframe + ? ( + + + + ) + : } + + + { navigateNextKeyframe + ? ( + + + + ) + : } + + + { navigateLastKeyframe + ? + : } + + + + + + { outside + ? + : } + + + + + { locked + ? + : } + + + + + { occluded + ? + : } + + + + + + + + { keyframe + ? + : } + + + { + shapeType !== ShapeType.POINTS && ( + + + { pinned + ? + : } + + + ) + } + + + + ); + } + + if (objectType === ObjectType.TAG) { + return ( + + + + + + { locked + ? + : } + + + + + + ); + } + + return ( + + + + + + { locked + ? + : } + + + + + { occluded + ? + : } + + + + + + { + shapeType !== ShapeType.POINTS && ( + + + { pinned + ? + : } + + + ) + } + + + + ); +} + +export default React.memo(ItemButtonsComponent); diff --git a/cvat-ui/src/components/annotation-page/standard-workspace/objects-side-bar/object-item-details.tsx b/cvat-ui/src/components/annotation-page/standard-workspace/objects-side-bar/object-item-details.tsx new file mode 100644 index 00000000000..f2e17d3bd0d --- /dev/null +++ b/cvat-ui/src/components/annotation-page/standard-workspace/objects-side-bar/object-item-details.tsx @@ -0,0 +1,86 @@ +// Copyright (C) 2020 Intel Corporation +// +// SPDX-License-Identifier: MIT + +import React from 'react'; +import { Row } from 'antd/lib/grid'; +import Collapse from 'antd/lib/collapse'; + +import ItemAttribute from './object-item-attribute'; + +interface Props { + collapsed: boolean; + attributes: any[]; + values: Record; + changeAttribute(attrID: number, value: string): void; + collapse(): void; +} + +export function attrValuesAreEqual( + next: Record, prev: Record, +): boolean { + const prevKeys = Object.keys(prev); + const nextKeys = Object.keys(next); + + return nextKeys.length === prevKeys.length + && nextKeys.map((key: string): boolean => prev[+key] === next[+key]) + .every((value: boolean) => value); +} + +function attrAreTheSame( + prevProps: Props, + nextProps: Props, +): boolean { + return nextProps.collapsed === prevProps.collapsed + && nextProps.attributes === prevProps.attributes + && attrValuesAreEqual(nextProps.values, prevProps.values); +} + +function ItemAttributesComponent(props: Props): JSX.Element { + const { + collapsed, + attributes, + values, + changeAttribute, + collapse, + } = props; + + const sorted = [...attributes] + .sort((a: any, b: any): number => a.inputType.localeCompare(b.inputType)); + + return ( + + + Details} + key='details' + > + { sorted.map((attribute: any): JSX.Element => ( + + + + ))} + + + + ); +} + +export default React.memo(ItemAttributesComponent, attrAreTheSame); diff --git a/cvat-ui/src/components/annotation-page/standard-workspace/objects-side-bar/object-item-menu.tsx b/cvat-ui/src/components/annotation-page/standard-workspace/objects-side-bar/object-item-menu.tsx new file mode 100644 index 00000000000..23e2c664dc2 --- /dev/null +++ b/cvat-ui/src/components/annotation-page/standard-workspace/objects-side-bar/object-item-menu.tsx @@ -0,0 +1,139 @@ +// Copyright (C) 2020 Intel Corporation +// +// SPDX-License-Identifier: MIT + +import React from 'react'; +import Icon from 'antd/lib/icon'; +import Menu from 'antd/lib/menu'; +import Button from 'antd/lib/button'; +import Modal from 'antd/lib/modal'; +import Tooltip from 'antd/lib/tooltip'; + +import { BackgroundIcon, ForegroundIcon, ResetPerspectiveIcon } from 'icons'; +import { ObjectType, ShapeType } from 'reducers/interfaces'; + +interface Props { + serverID: number | undefined; + locked: boolean; + shapeType: ShapeType; + objectType: ObjectType; + copyShortcut: string; + pasteShortcut: string; + propagateShortcut: string; + toBackgroundShortcut: string; + toForegroundShortcut: string; + removeShortcut: string; + copy: (() => void); + remove: (() => void); + propagate: (() => void); + createURL: (() => void); + switchOrientation: (() => void); + toBackground: (() => void); + toForeground: (() => void); + resetCuboidPerspective: (() => void); +} + +export default function ItemMenu(props: Props): JSX.Element { + const { + serverID, + locked, + shapeType, + objectType, + copyShortcut, + pasteShortcut, + propagateShortcut, + toBackgroundShortcut, + toForegroundShortcut, + removeShortcut, + copy, + remove, + propagate, + createURL, + switchOrientation, + toBackground, + toForeground, + resetCuboidPerspective, + } = props; + + return ( + + + + + + + + + + + + + + + { [ShapeType.POLYGON, ShapeType.POLYLINE, ShapeType.CUBOID].includes(shapeType) && ( + + + + )} + {shapeType === ShapeType.CUBOID && ( + + + + )} + {objectType !== ObjectType.TAG && ( + + + + + + )} + {objectType !== ObjectType.TAG && ( + + + + + + )} + + + + + + + ); +} diff --git a/cvat-ui/src/components/annotation-page/standard-workspace/objects-side-bar/object-item.tsx b/cvat-ui/src/components/annotation-page/standard-workspace/objects-side-bar/object-item.tsx index 0dfb658b945..b1246187b59 100644 --- a/cvat-ui/src/components/annotation-page/standard-workspace/objects-side-bar/object-item.tsx +++ b/cvat-ui/src/components/annotation-page/standard-workspace/objects-side-bar/object-item.tsx @@ -3,721 +3,14 @@ // SPDX-License-Identifier: MIT import React from 'react'; -import { Row, Col } from 'antd/lib/grid'; -import Icon from 'antd/lib/icon'; -import Select, { OptionProps } from 'antd/lib/select'; -import Radio, { RadioChangeEvent } from 'antd/lib/radio'; -import Checkbox, { CheckboxChangeEvent } from 'antd/lib/checkbox'; -import Input from 'antd/lib/input'; -import InputNumber from 'antd/lib/input-number'; -import Collapse from 'antd/lib/collapse'; -import Dropdown from 'antd/lib/dropdown'; -import Menu from 'antd/lib/menu'; -import Button from 'antd/lib/button'; -import Modal from 'antd/lib/modal'; import Popover from 'antd/lib/popover'; -import Text from 'antd/lib/typography/Text'; -import Tooltip from 'antd/lib/tooltip'; import ColorChanger from 'components/annotation-page/standard-workspace/objects-side-bar/color-changer'; -import consts from 'consts'; -import { - ObjectOutsideIcon, - FirstIcon, - LastIcon, - PreviousIcon, - NextIcon, - BackgroundIcon, - ForegroundIcon, - ResetPerspectiveIcon, -} from 'icons'; import { ObjectType, ShapeType } from 'reducers/interfaces'; -import { clamp } from 'utils/math'; - -function ItemMenu( - serverID: number | undefined, - locked: boolean, - shapeType: ShapeType, - objectType: ObjectType, - copyShortcut: string, - pasteShortcut: string, - propagateShortcut: string, - toBackgroundShortcut: string, - toForegroundShortcut: string, - removeShortcut: string, - copy: (() => void), - remove: (() => void), - propagate: (() => void), - createURL: (() => void), - switchOrientation: (() => void), - toBackground: (() => void), - toForeground: (() => void), - resetCuboidPerspective: (() => void), -): JSX.Element { - return ( - - - - - - - - - - - - - - - { [ShapeType.POLYGON, ShapeType.POLYLINE, ShapeType.CUBOID].includes(shapeType) && ( - - - - )} - {shapeType === ShapeType.CUBOID && ( - - - - )} - {objectType !== ObjectType.TAG && ( - - - - - - )} - {objectType !== ObjectType.TAG && ( - - - - - - )} - - - - - - - ); -} - -interface ItemTopComponentProps { - clientID: number; - serverID: number | undefined; - labelID: number; - labels: any[]; - shapeType: ShapeType; - objectType: ObjectType; - type: string; - locked: boolean; - copyShortcut: string; - pasteShortcut: string; - propagateShortcut: string; - toBackgroundShortcut: string; - toForegroundShortcut: string; - removeShortcut: string; - changeLabel(labelID: string): void; - copy(): void; - remove(): void; - propagate(): void; - createURL(): void; - switchOrientation(): void; - toBackground(): void; - toForeground(): void; - resetCuboidPerspective(): void; -} - -function ItemTopComponent(props: ItemTopComponentProps): JSX.Element { - const { - clientID, - serverID, - labelID, - labels, - shapeType, - objectType, - type, - locked, - copyShortcut, - pasteShortcut, - propagateShortcut, - toBackgroundShortcut, - toForegroundShortcut, - removeShortcut, - changeLabel, - copy, - remove, - propagate, - createURL, - switchOrientation, - toBackground, - toForeground, - resetCuboidPerspective, - } = props; - - return ( - - - {clientID} -
- {type} - - - - - - - - - - - -
- ); -} - -const ItemTop = React.memo(ItemTopComponent); - -interface ItemButtonsComponentProps { - objectType: ObjectType; - shapeType: ShapeType; - occluded: boolean; - outside: boolean | undefined; - locked: boolean; - pinned: boolean; - hidden: boolean; - keyframe: boolean | undefined; - switchOccludedShortcut: string; - switchOutsideShortcut: string; - switchLockShortcut: string; - switchHiddenShortcut: string; - switchKeyFrameShortcut: string; - nextKeyFrameShortcut: string; - prevKeyFrameShortcut: string; - - navigateFirstKeyframe: null | (() => void); - navigatePrevKeyframe: null | (() => void); - navigateNextKeyframe: null | (() => void); - navigateLastKeyframe: null | (() => void); - - setOccluded(): void; - unsetOccluded(): void; - setOutside(): void; - unsetOutside(): void; - setKeyframe(): void; - unsetKeyframe(): void; - lock(): void; - unlock(): void; - pin(): void; - unpin(): void; - hide(): void; - show(): void; -} - -function ItemButtonsComponent(props: ItemButtonsComponentProps): JSX.Element { - const { - objectType, - shapeType, - occluded, - outside, - locked, - pinned, - hidden, - keyframe, - switchOccludedShortcut, - switchOutsideShortcut, - switchLockShortcut, - switchHiddenShortcut, - switchKeyFrameShortcut, - nextKeyFrameShortcut, - prevKeyFrameShortcut, - - navigateFirstKeyframe, - navigatePrevKeyframe, - navigateNextKeyframe, - navigateLastKeyframe, - - setOccluded, - unsetOccluded, - setOutside, - unsetOutside, - setKeyframe, - unsetKeyframe, - lock, - unlock, - pin, - unpin, - hide, - show, - } = props; - - if (objectType === ObjectType.TRACK) { - return ( - - - - - { navigateFirstKeyframe - ? - : } - - - { navigatePrevKeyframe - ? ( - - - - ) - : } - - - { navigateNextKeyframe - ? ( - - - - ) - : } - - - { navigateLastKeyframe - ? - : } - - - - - - { outside - ? - : } - - - - - { locked - ? - : } - - - - - { occluded - ? - : } - - - - - - - - { keyframe - ? - : } - - - { - shapeType !== ShapeType.POINTS && ( - - - { pinned - ? - : } - - - ) - } - - - - ); - } - - if (objectType === ObjectType.TAG) { - return ( - - - - - - { locked - ? - : } - - - - - - ); - } - - return ( - - - - - - { locked - ? - : } - - - - - { occluded - ? - : } - - - - - - { - shapeType !== ShapeType.POINTS && ( - - - { pinned - ? - : } - - - ) - } - - - - ); -} - -const ItemButtons = React.memo(ItemButtonsComponent); - -interface ItemAttributeComponentProps { - attrInputType: string; - attrValues: string[]; - attrValue: string; - attrName: string; - attrID: number; - changeAttribute(attrID: number, value: string): void; -} - -function attrIsTheSame( - prevProps: ItemAttributeComponentProps, - nextProps: ItemAttributeComponentProps, -): boolean { - return nextProps.attrID === prevProps.attrID - && nextProps.attrValue === prevProps.attrValue - && nextProps.attrName === prevProps.attrName - && nextProps.attrInputType === prevProps.attrInputType - && nextProps.attrValues - .map((value: string, id: number): boolean => prevProps.attrValues[id] === value) - .every((value: boolean): boolean => value); -} - -function ItemAttributeComponent(props: ItemAttributeComponentProps): JSX.Element { - const { - attrInputType, - attrValues, - attrValue, - attrName, - attrID, - changeAttribute, - } = props; - - if (attrInputType === 'checkbox') { - return ( - - { - const value = event.target.checked ? 'true' : 'false'; - changeAttribute(attrID, value); - }} - > - - {attrName} - - - - ); - } - - if (attrInputType === 'radio') { - return ( - -
- - {attrName} - - { - changeAttribute(attrID, event.target.value); - }} - > - { attrValues.map((value: string): JSX.Element => ( - - {value === consts.UNDEFINED_ATTRIBUTE_VALUE - ? consts.NO_BREAK_SPACE : value} - - )) } - -
- - ); - } - - if (attrInputType === 'select') { - return ( - <> - - - {attrName} - - - - - - - ); - } - - if (attrInputType === 'number') { - const [min, max, step] = attrValues.map((value: string): number => +value); - - return ( - <> - - - {attrName} - - - - { - if (typeof (value) === 'number') { - changeAttribute( - attrID, `${clamp(value, min, max)}`, - ); - } - }} - value={+attrValue} - className='cvat-object-item-number-attribute' - min={min} - max={max} - step={step} - /> - - - ); - } - - return ( - <> - - - {attrName} - - - - ): void => { - changeAttribute(attrID, event.target.value); - }} - value={attrValue} - className='cvat-object-item-text-attribute' - /> - - - ); -} - -const ItemAttribute = React.memo(ItemAttributeComponent, attrIsTheSame); - - -interface ItemAttributesComponentProps { - collapsed: boolean; - attributes: any[]; - values: Record; - changeAttribute(attrID: number, value: string): void; - collapse(): void; -} - -function attrValuesAreEqual(next: Record, prev: Record): boolean { - const prevKeys = Object.keys(prev); - const nextKeys = Object.keys(next); - - return nextKeys.length === prevKeys.length - && nextKeys.map((key: string): boolean => prev[+key] === next[+key]) - .every((value: boolean) => value); -} - -function attrAreTheSame( - prevProps: ItemAttributesComponentProps, - nextProps: ItemAttributesComponentProps, -): boolean { - return nextProps.collapsed === prevProps.collapsed - && nextProps.attributes === prevProps.attributes - && attrValuesAreEqual(nextProps.values, prevProps.values); -} - -function ItemAttributesComponent(props: ItemAttributesComponentProps): JSX.Element { - const { - collapsed, - attributes, - values, - changeAttribute, - collapse, - } = props; - - const sorted = [...attributes] - .sort((a: any, b: any): number => a.inputType.localeCompare(b.inputType)); - - return ( - - - Details} - key='details' - > - { sorted.map((attribute: any): JSX.Element => ( - - - - ))} - - - - ); -} - -const ItemAttributes = React.memo(ItemAttributesComponent, attrAreTheSame); +import ItemDetails, { attrValuesAreEqual } from './object-item-details'; +import ItemBasics from './object-item-basics'; +import ItemButtons from './object-item-buttons'; interface Props { normalizedKeyMap: Record; @@ -881,7 +174,7 @@ function ObjectItemComponent(props: Props): JSX.Element { className={className} style={{ borderColor: ` ${color}` }} > - { !!attributes.length && ( - Date: Mon, 29 Jun 2020 22:33:34 +0300 Subject: [PATCH 5/9] Buttons to maintain state in AAM --- .vscode/launch.json | 14 +- cvat-ui/src/actions/annotation-actions.ts | 58 ++-- .../attribute-annotation-sidebar.tsx | 50 +-- .../object-basics-edtior.tsx | 12 +- .../objects-side-bar/object-item-buttons.tsx | 29 +- .../objects-side-bar/object-item.tsx | 89 +----- .../global-error-boundary.tsx | 5 +- .../objects-side-bar/object-buttons.tsx | 296 ++++++++++++++++++ .../objects-side-bar/object-item.tsx | 168 ---------- cvat-ui/src/containers/header/header.tsx | 1 - cvat-ui/src/utils/redux.ts | 2 +- 11 files changed, 386 insertions(+), 338 deletions(-) create mode 100644 cvat-ui/src/containers/annotation-page/standard-workspace/objects-side-bar/object-buttons.tsx diff --git a/.vscode/launch.json b/.vscode/launch.json index 1fefab7fee5..b9d4b31d650 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -27,7 +27,7 @@ "request": "launch", "stopOnEntry": false, "justMyCode": false, - "pythonPath": "${config:python.pythonPath}", + "pythonPath": "${config:python.interpreterPath}", "program": "${workspaceRoot}/manage.py", "args": [ "runserver", @@ -58,7 +58,7 @@ "request": "launch", "stopOnEntry": false, "justMyCode": false, - "pythonPath": "${config:python.pythonPath}", + "pythonPath": "${config:python.interpreterPath}", "program": "${workspaceRoot}/manage.py", "args": [ "rqworker", @@ -77,7 +77,7 @@ "request": "launch", "stopOnEntry": false, "justMyCode": false, - "pythonPath": "${config:python.pythonPath}", + "pythonPath": "${config:python.interpreterPath}", "program": "${workspaceRoot}/manage.py", "args": [ "rqscheduler", @@ -93,7 +93,7 @@ "request": "launch", "justMyCode": false, "stopOnEntry": false, - "pythonPath": "${config:python.pythonPath}", + "pythonPath": "${config:python.interpreterPath}", "program": "${workspaceRoot}/manage.py", "args": [ "rqworker", @@ -112,7 +112,7 @@ "request": "launch", "justMyCode": false, "stopOnEntry": false, - "pythonPath": "${config:python.pythonPath}", + "pythonPath": "${config:python.interpreterPath}", "program": "${workspaceRoot}/manage.py", "args": [ "update_git_states" @@ -128,7 +128,7 @@ "request": "launch", "justMyCode": false, "stopOnEntry": false, - "pythonPath": "${config:python.pythonPath}", + "pythonPath": "${config:python.interpreterPath}", "program": "${workspaceRoot}/manage.py", "args": [ "migrate" @@ -144,7 +144,7 @@ "request": "launch", "justMyCode": false, "stopOnEntry": false, - "pythonPath": "${config:python.pythonPath}", + "pythonPath": "${config:python.interpreterPath}", "program": "${workspaceRoot}/manage.py", "args": [ "test", diff --git a/cvat-ui/src/actions/annotation-actions.ts b/cvat-ui/src/actions/annotation-actions.ts index c373486a08d..c78c871b9a8 100644 --- a/cvat-ui/src/actions/annotation-actions.ts +++ b/cvat-ui/src/actions/annotation-actions.ts @@ -8,7 +8,7 @@ import { ActionCreator, Store, } from 'redux'; -import { ThunkAction } from 'redux-thunk'; +import { ThunkAction } from 'utils/redux'; import { CombinedState, @@ -191,8 +191,7 @@ export enum AnnotationActionTypes { SAVE_LOGS_FAILED = 'SAVE_LOGS_FAILED', } -export function saveLogsAsync(): -ThunkAction, {}, {}, AnyAction> { +export function saveLogsAsync(): ThunkAction { return async (dispatch: ActionCreator) => { try { await logger.save(); @@ -236,7 +235,7 @@ export function switchZLayer(cur: number): AnyAction { }; } -export function fetchAnnotationsAsync(): ThunkAction, {}, {}, AnyAction> { +export function fetchAnnotationsAsync(): ThunkAction { return async (dispatch: ActionCreator): Promise => { try { const { @@ -308,8 +307,7 @@ export function updateCanvasContextMenu( }; } -export function removeAnnotationsAsync(sessionInstance: any): -ThunkAction, {}, {}, AnyAction> { +export function removeAnnotationsAsync(sessionInstance: any): ThunkAction { return async (dispatch: ActionCreator): Promise => { try { await sessionInstance.annotations.clear(); @@ -333,8 +331,7 @@ ThunkAction, {}, {}, AnyAction> { }; } -export function uploadJobAnnotationsAsync(job: any, loader: any, file: File): -ThunkAction, {}, {}, AnyAction> { +export function uploadJobAnnotationsAsync(job: any, loader: any, file: File): ThunkAction { return async (dispatch: ActionCreator): Promise => { try { const state: CombinedState = getStore().getState(); @@ -404,8 +401,7 @@ ThunkAction, {}, {}, AnyAction> { }; } -export function changeJobStatusAsync(jobInstance: any, status: string): -ThunkAction, {}, {}, AnyAction> { +export function changeJobStatusAsync(jobInstance: any, status: string): ThunkAction { return async (dispatch: ActionCreator): Promise => { const oldStatus = jobInstance.status; try { @@ -435,8 +431,7 @@ ThunkAction, {}, {}, AnyAction> { }; } -export function collectStatisticsAsync(sessionInstance: any): -ThunkAction, {}, {}, AnyAction> { +export function collectStatisticsAsync(sessionInstance: any): ThunkAction { return async (dispatch: ActionCreator): Promise => { try { dispatch({ @@ -477,7 +472,7 @@ export function propagateObjectAsync( objectState: any, from: number, to: number, -): ThunkAction, {}, {}, AnyAction> { +): ThunkAction { return async (dispatch: ActionCreator): Promise => { try { const copy = { @@ -542,7 +537,7 @@ export function changePropagateFrames(frames: number): AnyAction { } export function removeObjectAsync(sessionInstance: any, objectState: any, force: boolean): -ThunkAction, {}, {}, AnyAction> { +ThunkAction { return async (dispatch: ActionCreator): Promise => { try { await sessionInstance.logger.log(LogType.deleteObject, { count: 1 }); @@ -659,7 +654,7 @@ export function switchPlay(playing: boolean): AnyAction { } export function changeFrameAsync(toFrame: number, fillBuffer?: boolean, frameStep?: number): -ThunkAction, {}, {}, AnyAction> { +ThunkAction { return async (dispatch: ActionCreator): Promise => { const state: CombinedState = getStore().getState(); const { instance: job } = state.annotation.job; @@ -751,7 +746,7 @@ ThunkAction, {}, {}, AnyAction> { } export function undoActionAsync(sessionInstance: any, frame: number): -ThunkAction, {}, {}, AnyAction> { +ThunkAction { return async (dispatch: ActionCreator): Promise => { try { const state = getStore().getState(); @@ -794,7 +789,7 @@ ThunkAction, {}, {}, AnyAction> { } export function redoActionAsync(sessionInstance: any, frame: number): -ThunkAction, {}, {}, AnyAction> { +ThunkAction { return async (dispatch: ActionCreator): Promise => { try { const state = getStore().getState(); @@ -906,7 +901,7 @@ export function confirmCanvasReady(): AnyAction { }; } -export function closeJob(): ThunkAction, {}, {}, AnyAction> { +export function closeJob(): ThunkAction { return async (dispatch: ActionCreator): Promise => { const { jobInstance } = receiveAnnotationsParameters(); if (jobInstance) { @@ -924,7 +919,7 @@ export function getJobAsync( jid: number, initialFrame: number, initialFilters: string[], -): ThunkAction, {}, {}, AnyAction> { +): ThunkAction { return async (dispatch: ActionCreator): Promise => { try { const state: CombinedState = getStore().getState(); @@ -1001,7 +996,7 @@ export function getJobAsync( } export function saveAnnotationsAsync(sessionInstance: any): -ThunkAction, {}, {}, AnyAction> { +ThunkAction { return async (dispatch: ActionCreator): Promise => { const { filters, frame, showAllInterpolationTracks } = receiveAnnotationsParameters(); @@ -1118,8 +1113,7 @@ export function splitTrack(enabled: boolean): AnyAction { }; } -export function updateAnnotationsAsync(statesToUpdate: any[]): -ThunkAction, {}, {}, AnyAction> { +export function updateAnnotationsAsync(statesToUpdate: any[]): ThunkAction { return async (dispatch: ActionCreator): Promise => { const { jobInstance, @@ -1164,7 +1158,7 @@ ThunkAction, {}, {}, AnyAction> { } export function createAnnotationsAsync(sessionInstance: any, frame: number, statesToCreate: any[]): -ThunkAction, {}, {}, AnyAction> { +ThunkAction { return async (dispatch: ActionCreator): Promise => { try { const { filters, showAllInterpolationTracks } = receiveAnnotationsParameters(); @@ -1192,7 +1186,7 @@ ThunkAction, {}, {}, AnyAction> { } export function mergeAnnotationsAsync(sessionInstance: any, frame: number, statesToMerge: any[]): -ThunkAction, {}, {}, AnyAction> { +ThunkAction { return async (dispatch: ActionCreator): Promise => { try { const { filters, showAllInterpolationTracks } = receiveAnnotationsParameters(); @@ -1230,7 +1224,7 @@ export function groupAnnotationsAsync( sessionInstance: any, frame: number, statesToGroup: any[], -): ThunkAction, {}, {}, AnyAction> { +): ThunkAction { return async (dispatch: ActionCreator): Promise => { try { const { filters, showAllInterpolationTracks } = receiveAnnotationsParameters(); @@ -1266,7 +1260,7 @@ export function groupAnnotationsAsync( } export function splitAnnotationsAsync(sessionInstance: any, frame: number, stateToSplit: any): -ThunkAction, {}, {}, AnyAction> { +ThunkAction { return async (dispatch: ActionCreator): Promise => { const { filters, showAllInterpolationTracks } = receiveAnnotationsParameters(); try { @@ -1296,7 +1290,7 @@ ThunkAction, {}, {}, AnyAction> { export function changeLabelColorAsync( label: any, color: string, -): ThunkAction, {}, {}, AnyAction> { +): ThunkAction { return async (dispatch: ActionCreator): Promise => { try { const { @@ -1334,7 +1328,7 @@ export function changeLabelColorAsync( export function changeGroupColorAsync( group: number, color: string, -): ThunkAction, {}, {}, AnyAction> { +): ThunkAction { return async (dispatch: ActionCreator): Promise => { const state: CombinedState = getStore().getState(); const groupStates = state.annotation.annotations.states @@ -1352,7 +1346,7 @@ export function searchAnnotationsAsync( sessionInstance: any, frameFrom: number, frameTo: number, -): ThunkAction, {}, {}, AnyAction> { +): ThunkAction { return async (dispatch: ActionCreator): Promise => { try { const { filters } = receiveAnnotationsParameters(); @@ -1371,7 +1365,7 @@ export function searchAnnotationsAsync( }; } -export function pasteShapeAsync(): ThunkAction, {}, {}, AnyAction> { +export function pasteShapeAsync(): ThunkAction { return async (dispatch: ActionCreator): Promise => { const { canvas: { @@ -1430,7 +1424,7 @@ export function pasteShapeAsync(): ThunkAction, {}, {}, AnyAction> }; } -export function repeatDrawShapeAsync(): ThunkAction, {}, {}, AnyAction> { +export function repeatDrawShapeAsync(): ThunkAction { return async (dispatch: ActionCreator): Promise => { const { canvas: { @@ -1494,7 +1488,7 @@ export function repeatDrawShapeAsync(): ThunkAction, {}, {}, AnyAc }; } -export function redrawShapeAsync(): ThunkAction, {}, {}, AnyAction> { +export function redrawShapeAsync(): ThunkAction { return async (dispatch: ActionCreator): Promise => { const { annotations: { diff --git a/cvat-ui/src/components/annotation-page/attribute-annotation-workspace/attribute-annotation-sidebar/attribute-annotation-sidebar.tsx b/cvat-ui/src/components/annotation-page/attribute-annotation-workspace/attribute-annotation-sidebar/attribute-annotation-sidebar.tsx index ba14f6223e9..3cfcd59127d 100644 --- a/cvat-ui/src/components/annotation-page/attribute-annotation-workspace/attribute-annotation-sidebar/attribute-annotation-sidebar.tsx +++ b/cvat-ui/src/components/annotation-page/attribute-annotation-workspace/attribute-annotation-sidebar/attribute-annotation-sidebar.tsx @@ -5,15 +5,13 @@ import React, { useState, useEffect } from 'react'; import { GlobalHotKeys, ExtendedKeyMapOptions } from 'react-hotkeys'; import { connect } from 'react-redux'; -import { Action } from 'redux'; -import { ThunkDispatch } from 'redux-thunk'; import Layout, { SiderProps } from 'antd/lib/layout'; import { SelectValue } from 'antd/lib/select'; -import { CheckboxChangeEvent } from 'antd/lib/checkbox'; import { Row, Col } from 'antd/lib/grid'; import Text from 'antd/lib/typography/Text'; import Icon from 'antd/lib/icon'; +import { ThunkDispatch } from 'utils/redux'; import { Canvas } from 'cvat-canvas-wrapper'; import { LogType } from 'cvat-logger'; import { @@ -23,6 +21,7 @@ import { import { CombinedState } from 'reducers/interfaces'; import AnnotationsFiltersInput from 'components/annotation-page/annotations-filters-input'; import AppearanceBlock from 'components/annotation-page/appearance-block'; +import ObjectButtonsContainer from 'containers/annotation-page/standard-workspace/objects-side-bar/object-buttons'; import ObjectSwitcher from './object-switcher'; import AttributeSwitcher from './attribute-switcher'; @@ -87,7 +86,7 @@ function mapStateToProps(state: CombinedState): StateToProps { }; } -function mapDispatchToProps(dispatch: ThunkDispatch): DispatchToProps { +function mapDispatchToProps(dispatch: ThunkDispatch): DispatchToProps { return { activateObject(clientID: number, attrID: number): void { dispatch(activateObjectAction(clientID, attrID)); @@ -113,6 +112,7 @@ function AttributeAnnotationSidebar(props: StateToProps & DispatchToProps): JSX. canvasIsReady, } = props; + const filteredStates = states.filter((state) => !state.outside && !state.hidden); const [labelAttrMap, setLabelAttrMap] = useState( labels.reduce((acc, label): LabelAttrMap => { acc[label.id] = label.attributes.length ? label.attributes[0] : null; @@ -135,10 +135,11 @@ function AttributeAnnotationSidebar(props: StateToProps & DispatchToProps): JSX. setSidebarCollapsed(!sidebarCollapsed); }; - const [activeObjectState] = activatedStateID === null - ? [null] : states.filter((objectState: any): boolean => ( - objectState.clientID === activatedStateID - )); + const indexes = filteredStates.map((state) => state.clientID); + const activatedIndex = indexes.indexOf(activatedStateID); + const activeObjectState = activatedStateID === null || activatedIndex === -1 + ? null : filteredStates[activatedIndex]; + const activeAttribute = activeObjectState ? labelAttrMap[activeObjectState.label.id] : null; @@ -149,24 +150,24 @@ function AttributeAnnotationSidebar(props: StateToProps & DispatchToProps): JSX. if (attribute && attribute.id !== activatedAttributeID) { activateObject(activatedStateID, attribute ? attribute.id : null); } - } else if (states.length) { - const attribute = labelAttrMap[states[0].label.id]; - activateObject(states[0].clientID, attribute ? attribute.id : null); + } else if (filteredStates.length) { + const attribute = labelAttrMap[filteredStates[0].label.id]; + activateObject(filteredStates[0].clientID, attribute ? attribute.id : null); } } const nextObject = (step: number): void => { - if (states.length) { - const index = states.indexOf(activeObjectState); + if (filteredStates.length) { + const index = filteredStates.indexOf(activeObjectState); let nextIndex = index + step; - if (nextIndex > states.length - 1) { + if (nextIndex > filteredStates.length - 1) { nextIndex = 0; } else if (nextIndex < 0) { - nextIndex = states.length - 1; + nextIndex = filteredStates.length - 1; } if (nextIndex !== index) { - const attribute = labelAttrMap[states[nextIndex].label.id]; - activateObject(states[nextIndex].clientID, attribute ? attribute.id : null); + const attribute = labelAttrMap[filteredStates[nextIndex].label.id]; + activateObject(filteredStates[nextIndex].clientID, attribute ? attribute.id : null); } } }; @@ -270,15 +271,14 @@ function AttributeAnnotationSidebar(props: StateToProps & DispatchToProps): JSX. currentLabel={activeObjectState.label.name} clientID={activeObjectState.clientID} occluded={activeObjectState.occluded} - objectsCount={states.length} - currentIndex={states.indexOf(activeObjectState)} + objectsCount={filteredStates.length} + currentIndex={filteredStates.indexOf(activeObjectState)} normalizedKeyMap={normalizedKeyMap} nextObject={nextObject} /> { const labelName = value as string; const [newLabel] = labels @@ -286,10 +286,12 @@ function AttributeAnnotationSidebar(props: StateToProps & DispatchToProps): JSX. activeObjectState.label = newLabel; updateAnnotations([activeObjectState]); }} - setOccluded={(event: CheckboxChangeEvent): void => { - activeObjectState.occluded = event.target.checked; - updateAnnotations([activeObjectState]); - }} + /> + { activeAttribute diff --git a/cvat-ui/src/components/annotation-page/attribute-annotation-workspace/attribute-annotation-sidebar/object-basics-edtior.tsx b/cvat-ui/src/components/annotation-page/attribute-annotation-workspace/attribute-annotation-sidebar/object-basics-edtior.tsx index 17a689a997f..ea9db3355ca 100644 --- a/cvat-ui/src/components/annotation-page/attribute-annotation-workspace/attribute-annotation-sidebar/object-basics-edtior.tsx +++ b/cvat-ui/src/components/annotation-page/attribute-annotation-workspace/attribute-annotation-sidebar/object-basics-edtior.tsx @@ -4,24 +4,15 @@ import React from 'react'; import Select, { SelectValue } from 'antd/lib/select'; -import Checkbox, { CheckboxChangeEvent } from 'antd/lib/checkbox'; interface Props { currentLabel: string; labels: any[]; - occluded: boolean; - setOccluded(event: CheckboxChangeEvent): void; changeLabel(value: SelectValue): void; } function ObjectBasicsEditor(props: Props): JSX.Element { - const { - currentLabel, - occluded, - labels, - setOccluded, - changeLabel, - } = props; + const { currentLabel, labels, changeLabel } = props; return (
@@ -35,7 +26,6 @@ function ObjectBasicsEditor(props: Props): JSX.Element { ))} - Occluded
); } diff --git a/cvat-ui/src/components/annotation-page/standard-workspace/objects-side-bar/object-item-buttons.tsx b/cvat-ui/src/components/annotation-page/standard-workspace/objects-side-bar/object-item-buttons.tsx index 76475255e4e..e7d2f3c03b8 100644 --- a/cvat-ui/src/components/annotation-page/standard-workspace/objects-side-bar/object-item-buttons.tsx +++ b/cvat-ui/src/components/annotation-page/standard-workspace/objects-side-bar/object-item-buttons.tsx @@ -25,6 +25,9 @@ interface Props { pinned: boolean; hidden: boolean; keyframe: boolean | undefined; + outsideDisabled: boolean; + hiddenDisabled: boolean; + keyframeDisabled: boolean; switchOccludedShortcut: string; switchOutsideShortcut: string; switchLockShortcut: string; @@ -62,6 +65,9 @@ function ItemButtonsComponent(props: Props): JSX.Element { pinned, hidden, keyframe, + outsideDisabled, + hiddenDisabled, + keyframeDisabled, switchOccludedShortcut, switchOutsideShortcut, switchLockShortcut, @@ -89,6 +95,11 @@ function ItemButtonsComponent(props: Props): JSX.Element { show, } = props; + const outsideStyle = outsideDisabled ? { opacity: 0.5, pointerEvents: 'none' as 'none' } : {}; + const hiddenStyle = hiddenDisabled ? { opacity: 0.5, pointerEvents: 'none' as 'none' } : {}; + const keyframeStyle = keyframeDisabled ? { opacity: 0.5, pointerEvents: 'none' as 'none' } : {}; + + if (objectType === ObjectType.TRACK) { return ( @@ -133,8 +144,14 @@ function ItemButtonsComponent(props: Props): JSX.Element { { outside - ? - : } + ? ( + + ) + : } @@ -154,15 +171,15 @@ function ItemButtonsComponent(props: Props): JSX.Element { { keyframe - ? - : } + ? + : } { diff --git a/cvat-ui/src/components/annotation-page/standard-workspace/objects-side-bar/object-item.tsx b/cvat-ui/src/components/annotation-page/standard-workspace/objects-side-bar/object-item.tsx index 6f2764df300..3d8010fec15 100644 --- a/cvat-ui/src/components/annotation-page/standard-workspace/objects-side-bar/object-item.tsx +++ b/cvat-ui/src/components/annotation-page/standard-workspace/objects-side-bar/object-item.tsx @@ -5,12 +5,12 @@ import React from 'react'; import Popover from 'antd/lib/popover'; +import ObjectButtonsContainer from 'containers/annotation-page/standard-workspace/objects-side-bar/object-buttons'; import ColorChanger from 'components/annotation-page/standard-workspace/objects-side-bar/color-changer'; import { ObjectType, ShapeType } from 'reducers/interfaces'; - import ItemDetails, { attrValuesAreEqual } from './object-item-details'; import ItemBasics from './object-item-basics'; -import ItemButtons from './object-item-buttons'; + interface Props { normalizedKeyMap: Record; @@ -20,12 +20,7 @@ interface Props { clientID: number; serverID: number | undefined; labelID: number; - occluded: boolean; - outside: boolean | undefined; locked: boolean; - pinned: boolean; - hidden: boolean; - keyframe: boolean | undefined; attrValues: Record; color: string; colors: string[]; @@ -33,10 +28,6 @@ interface Props { labels: any[]; attributes: any[]; collapsed: boolean; - navigateFirstKeyframe: null | (() => void); - navigatePrevKeyframe: null | (() => void); - navigateNextKeyframe: null | (() => void); - navigateLastKeyframe: null | (() => void); activate(): void; copy(): void; @@ -46,18 +37,6 @@ interface Props { toBackground(): void; toForeground(): void; remove(): void; - setOccluded(): void; - unsetOccluded(): void; - setOutside(): void; - unsetOutside(): void; - setKeyframe(): void; - unsetKeyframe(): void; - lock(): void; - unlock(): void; - pin(): void; - unpin(): void; - hide(): void; - show(): void; changeLabel(labelID: string): void; changeAttribute(attrID: number, value: string): void; changeColor(color: string): void; @@ -68,11 +47,6 @@ interface Props { function objectItemsAreEqual(prevProps: Props, nextProps: Props): boolean { return nextProps.activated === prevProps.activated && nextProps.locked === prevProps.locked - && nextProps.pinned === prevProps.pinned - && nextProps.occluded === prevProps.occluded - && nextProps.outside === prevProps.outside - && nextProps.hidden === prevProps.hidden - && nextProps.keyframe === prevProps.keyframe && nextProps.labelID === prevProps.labelID && nextProps.color === prevProps.color && nextProps.clientID === prevProps.clientID @@ -83,10 +57,6 @@ function objectItemsAreEqual(prevProps: Props, nextProps: Props): boolean { && nextProps.labels === prevProps.labels && nextProps.attributes === prevProps.attributes && nextProps.normalizedKeyMap === prevProps.normalizedKeyMap - && nextProps.navigateFirstKeyframe === prevProps.navigateFirstKeyframe - && nextProps.navigatePrevKeyframe === prevProps.navigatePrevKeyframe - && nextProps.navigateNextKeyframe === prevProps.navigateNextKeyframe - && nextProps.navigateLastKeyframe === prevProps.navigateLastKeyframe && attrValuesAreEqual(nextProps.attrValues, prevProps.attrValues); } @@ -97,12 +67,7 @@ function ObjectItemComponent(props: Props): JSX.Element { shapeType, clientID, serverID, - occluded, - outside, locked, - pinned, - hidden, - keyframe, attrValues, labelID, color, @@ -112,10 +77,6 @@ function ObjectItemComponent(props: Props): JSX.Element { labels, collapsed, normalizedKeyMap, - navigateFirstKeyframe, - navigatePrevKeyframe, - navigateNextKeyframe, - navigateLastKeyframe, activate, copy, @@ -125,18 +86,6 @@ function ObjectItemComponent(props: Props): JSX.Element { toBackground, toForeground, remove, - setOccluded, - unsetOccluded, - setOutside, - unsetOutside, - setKeyframe, - unsetKeyframe, - lock, - unlock, - pin, - unpin, - hide, - show, changeLabel, changeAttribute, changeColor, @@ -199,38 +148,8 @@ function ObjectItemComponent(props: Props): JSX.Element { toForeground={toForeground} resetCuboidPerspective={resetCuboidPerspective} /> -