) => {
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,
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 17a689a997f7..ea9db3355ca7 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/appearance-block.tsx b/cvat-ui/src/components/annotation-page/standard-workspace/objects-side-bar/appearance-block.tsx
deleted file mode 100644
index d42d7a42d891..000000000000
--- 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/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 000000000000..aca9779e2db6
--- /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 (
+
+
+
+ );
+ }
+
+ 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 000000000000..08536f877ed5
--- /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 000000000000..e7d2f3c03b8a
--- /dev/null
+++ b/cvat-ui/src/components/annotation-page/standard-workspace/objects-side-bar/object-item-buttons.tsx
@@ -0,0 +1,262 @@
+// 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;
+ outsideDisabled: boolean;
+ hiddenDisabled: boolean;
+ keyframeDisabled: boolean;
+ 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,
+ outsideDisabled,
+ hiddenDisabled,
+ keyframeDisabled,
+ switchOccludedShortcut,
+ switchOutsideShortcut,
+ switchLockShortcut,
+ switchHiddenShortcut,
+ switchKeyFrameShortcut,
+ nextKeyFrameShortcut,
+ prevKeyFrameShortcut,
+
+ navigateFirstKeyframe,
+ navigatePrevKeyframe,
+ navigateNextKeyframe,
+ navigateLastKeyframe,
+
+ setOccluded,
+ unsetOccluded,
+ setOutside,
+ unsetOutside,
+ setKeyframe,
+ unsetKeyframe,
+ lock,
+ unlock,
+ pin,
+ unpin,
+ hide,
+ 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 (
+
+
+
+
+ { navigateFirstKeyframe
+ ?
+ : }
+
+
+ { navigatePrevKeyframe
+ ? (
+
+
+
+ )
+ : }
+
+
+ { navigateNextKeyframe
+ ? (
+
+
+
+ )
+ : }
+
+
+ { navigateLastKeyframe
+ ?
+ : }
+
+
+
+
+
+ { outside
+ ? (
+
+ )
+ : }
+
+
+
+
+ { locked
+ ?
+ : }
+
+
+
+
+ { occluded
+ ?
+ : }
+
+
+
+
+ { hidden
+ ?
+ : }
+
+
+
+
+ { keyframe
+ ?
+ : }
+
+
+ {
+ shapeType !== ShapeType.POINTS && (
+
+
+ { pinned
+ ?
+ : }
+
+
+ )
+ }
+
+
+
+ );
+ }
+
+ if (objectType === ObjectType.TAG) {
+ return (
+
+
+
+
+
+ { locked
+ ?
+ : }
+
+
+
+
+
+ );
+ }
+
+ return (
+
+
+
+
+
+ { locked
+ ?
+ : }
+
+
+
+
+ { occluded
+ ?
+ : }
+
+
+
+
+ { hidden
+ ?
+ : }
+
+
+ {
+ 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 000000000000..f2e17d3bd0d2
--- /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 000000000000..23e2c664dc25
--- /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 (
+
+ );
+}
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 cd982fe02f7e..3d8010fec157 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,722 +3,15 @@
// 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 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 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';
+import ItemDetails, { attrValuesAreEqual } from './object-item-details';
+import ItemBasics from './object-item-basics';
-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 (
-
- );
-}
-
-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
- ?
- : }
-
-
-
-
- { hidden
- ?
- : }
-
-
-
-
- { keyframe
- ?
- : }
-
-
- {
- shapeType !== ShapeType.POINTS && (
-
-
- { pinned
- ?
- : }
-
-
- )
- }
-
-
-
- );
- }
-
- if (objectType === ObjectType.TAG) {
- return (
-
-
-
-
-
- { locked
- ?
- : }
-
-
-
-
-
- );
- }
-
- return (
-
-
-
-
-
- { locked
- ?
- : }
-
-
-
-
- { occluded
- ?
- : }
-
-
-
-
- { hidden
- ?
- : }
-
-
- {
- 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 (
-
-
-
- );
- }
-
- 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);
-
interface Props {
normalizedKeyMap: Record;
activated: boolean;
@@ -727,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[];
@@ -740,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;
@@ -753,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;
@@ -775,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
@@ -790,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);
}
@@ -804,12 +67,7 @@ function ObjectItemComponent(props: Props): JSX.Element {
shapeType,
clientID,
serverID,
- occluded,
- outside,
locked,
- pinned,
- hidden,
- keyframe,
attrValues,
labelID,
color,
@@ -819,10 +77,6 @@ function ObjectItemComponent(props: Props): JSX.Element {
labels,
collapsed,
normalizedKeyMap,
- navigateFirstKeyframe,
- navigatePrevKeyframe,
- navigateNextKeyframe,
- navigateLastKeyframe,
activate,
copy,
@@ -832,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,
@@ -881,7 +123,7 @@ function ObjectItemComponent(props: Props): JSX.Element {
className={className}
style={{ backgroundColor: `${color}88` }}
>
-
-
{ !!attributes.length
&& (
- ): DispatchToProps {
+ return {
+ collapseSidebar(): void {
+ dispatch(collapseSidebarAction());
+ },
+ updateTabContentHeight(): void {
+ const height = computeHeight();
+ dispatch(updateTabContentHeightAction(height));
+ },
+ };
}
-function ObjectsSideBar(props: Props): JSX.Element {
+function ObjectsSideBar(props: StateToProps & DispatchToProps): JSX.Element {
const {
sidebarCollapsed,
- appearanceCollapsed,
- colorBy,
- opacity,
- selectedOpacity,
- blackBorders,
- showBitmap,
- showProjections,
canvasInstance,
collapseSidebar,
- collapseAppearance,
- changeShapesColorBy,
- changeShapesOpacity,
- changeSelectedShapesOpacity,
- changeShapesBlackBorders,
- changeShowBitmap,
- changeShowProjections,
+ updateTabContentHeight,
} = props;
- const appearanceProps = {
- collapseAppearance,
- appearanceCollapsed,
- colorBy,
- opacity,
- selectedOpacity,
- blackBorders,
- showBitmap,
- showProjections,
-
- changeShapesColorBy,
- changeShapesOpacity,
- changeSelectedShapesOpacity,
- changeShapesBlackBorders,
- changeShowBitmap,
- changeShowProjections,
- };
+ useEffect(() => {
+ const alignTabHeight = (): void => {
+ if (!sidebarCollapsed) {
+ updateTabContentHeight();
+ }
+ };
+
+ window.addEventListener('resize', alignTabHeight);
+ alignTabHeight();
+
+ return () => {
+ window.removeEventListener('resize', alignTabHeight);
+ };
+ }, []);
useEffect(() => {
const listener = (event: Event): void => {
@@ -134,9 +136,12 @@ function ObjectsSideBar(props: Props): JSX.Element {
- { !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 b6278f1b3f1e..d57be1ec2249 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/components/global-error-boundary/global-error-boundary.tsx b/cvat-ui/src/components/global-error-boundary/global-error-boundary.tsx
index aeee46b76387..fc8ca1958266 100644
--- a/cvat-ui/src/components/global-error-boundary/global-error-boundary.tsx
+++ b/cvat-ui/src/components/global-error-boundary/global-error-boundary.tsx
@@ -5,8 +5,6 @@
import './styles.scss';
import React from 'react';
import { connect } from 'react-redux';
-import { Action } from 'redux';
-import { ThunkDispatch } from 'redux-thunk';
import Result from 'antd/lib/result';
import Text from 'antd/lib/typography/Text';
import Paragraph from 'antd/lib/typography/Paragraph';
@@ -16,6 +14,7 @@ import Tooltip from 'antd/lib/tooltip';
import copy from 'copy-to-clipboard';
import ErrorStackParser from 'error-stack-parser';
+import { ThunkDispatch } from 'utils/redux';
import { resetAfterErrorAsync } from 'actions/boundaries-actions';
import { CombinedState } from 'reducers/interfaces';
import logger, { LogType } from 'cvat-logger';
@@ -60,7 +59,7 @@ function mapStateToProps(state: CombinedState): StateToProps {
};
}
-function mapDispatchToProps(dispatch: ThunkDispatch): DispatchToProps {
+function mapDispatchToProps(dispatch: ThunkDispatch): DispatchToProps {
return {
restore(): void {
dispatch(resetAfterErrorAsync());
diff --git a/cvat-ui/src/containers/annotation-page/standard-workspace/objects-side-bar/object-buttons.tsx b/cvat-ui/src/containers/annotation-page/standard-workspace/objects-side-bar/object-buttons.tsx
new file mode 100644
index 000000000000..a14510077fe1
--- /dev/null
+++ b/cvat-ui/src/containers/annotation-page/standard-workspace/objects-side-bar/object-buttons.tsx
@@ -0,0 +1,296 @@
+// Copyright (C) 2020 Intel Corporation
+//
+// SPDX-License-Identifier: MIT
+
+import React from 'react';
+import { connect } from 'react-redux';
+
+import { LogType } from 'cvat-logger';
+import { Canvas } from 'cvat-canvas-wrapper';
+import { ThunkDispatch } from 'utils/redux';
+import { updateAnnotationsAsync, changeFrameAsync } from 'actions/annotation-actions';
+import { CombinedState } from 'reducers/interfaces';
+import ItemButtonsComponent from 'components/annotation-page/standard-workspace/objects-side-bar/object-item-buttons';
+
+interface OwnProps {
+ clientID: number;
+ outsideDisabled?: boolean;
+ hiddenDisabled?: boolean;
+ keyframeDisabled?: boolean;
+}
+
+interface StateToProps {
+ objectState: any;
+ jobInstance: any;
+ frameNumber: number;
+ normalizedKeyMap: Record;
+ canvasInstance: Canvas;
+ outsideDisabled: boolean;
+ hiddenDisabled: boolean;
+ keyframeDisabled: boolean;
+}
+
+interface DispatchToProps {
+ updateAnnotations(statesToUpdate: any[]): void;
+ changeFrame(frame: number): void;
+}
+
+function mapStateToProps(state: CombinedState, own: OwnProps): StateToProps {
+ const {
+ annotation: {
+ annotations: {
+ states,
+ },
+ job: {
+ instance: jobInstance,
+ },
+ player: {
+ frame: {
+ number: frameNumber,
+ },
+ },
+ canvas: {
+ instance: canvasInstance,
+ },
+ },
+ shortcuts: {
+ normalizedKeyMap,
+ },
+ } = state;
+
+ const {
+ clientID,
+ outsideDisabled,
+ hiddenDisabled,
+ keyframeDisabled,
+ } = own;
+ const [objectState] = states
+ .filter((_objectState): boolean => _objectState.clientID === clientID);
+
+ return {
+ objectState,
+ normalizedKeyMap,
+ frameNumber,
+ jobInstance,
+ canvasInstance,
+ outsideDisabled: typeof (outsideDisabled) === 'undefined' ? false : outsideDisabled,
+ hiddenDisabled: typeof (hiddenDisabled) === 'undefined' ? false : hiddenDisabled,
+ keyframeDisabled: typeof (keyframeDisabled) === 'undefined' ? false : keyframeDisabled,
+ };
+}
+
+function mapDispatchToProps(dispatch: ThunkDispatch): DispatchToProps {
+ return {
+ updateAnnotations(states: any[]) {
+ dispatch(updateAnnotationsAsync(states));
+ },
+ changeFrame(frame: number): void {
+ dispatch(changeFrameAsync(frame));
+ },
+ };
+}
+
+class ItemButtonsWrapper extends React.PureComponent {
+ private navigateFirstKeyframe = (): void => {
+ const { objectState, frameNumber } = this.props;
+ const { first } = objectState.keyframes;
+ if (first !== frameNumber) {
+ this.changeFrame(first);
+ }
+ };
+
+ private navigatePrevKeyframe = (): void => {
+ const { objectState, frameNumber } = this.props;
+ const { prev } = objectState.keyframes;
+ if (prev !== null && prev !== frameNumber) {
+ this.changeFrame(prev);
+ }
+ };
+
+ private navigateNextKeyframe = (): void => {
+ const { objectState, frameNumber } = this.props;
+ const { next } = objectState.keyframes;
+ if (next !== null && next !== frameNumber) {
+ this.changeFrame(next);
+ }
+ };
+
+ private navigateLastKeyframe = (): void => {
+ const { objectState, frameNumber } = this.props;
+ const { last } = objectState.keyframes;
+ if (last !== frameNumber) {
+ this.changeFrame(last);
+ }
+ };
+
+ private lock = (): void => {
+ const { objectState, jobInstance } = this.props;
+ jobInstance.logger.log(LogType.lockObject, { locked: true });
+ objectState.lock = true;
+ this.commit();
+ };
+
+ private unlock = (): void => {
+ const { objectState, jobInstance } = this.props;
+ jobInstance.logger.log(LogType.lockObject, { locked: false });
+ objectState.lock = false;
+ this.commit();
+ };
+
+ private pin = (): void => {
+ const { objectState } = this.props;
+ objectState.pinned = true;
+ this.commit();
+ };
+
+ private unpin = (): void => {
+ const { objectState } = this.props;
+ objectState.pinned = false;
+ this.commit();
+ };
+
+ private show = (): void => {
+ const { objectState } = this.props;
+ objectState.hidden = false;
+ this.commit();
+ };
+
+ private hide = (): void => {
+ const { objectState } = this.props;
+ objectState.hidden = true;
+ this.commit();
+ };
+
+ private setOccluded = (): void => {
+ const { objectState } = this.props;
+ objectState.occluded = true;
+ this.commit();
+ };
+
+ private unsetOccluded = (): void => {
+ const { objectState } = this.props;
+ objectState.occluded = false;
+ this.commit();
+ };
+
+ private setOutside = (): void => {
+ const { objectState } = this.props;
+ objectState.outside = true;
+ this.commit();
+ };
+
+ private unsetOutside = (): void => {
+ const { objectState } = this.props;
+ objectState.outside = false;
+ this.commit();
+ };
+
+ private setKeyframe = (): void => {
+ const { objectState } = this.props;
+ objectState.keyframe = true;
+ this.commit();
+ };
+
+ private unsetKeyframe = (): void => {
+ const { objectState } = this.props;
+ objectState.keyframe = false;
+ this.commit();
+ };
+
+ private commit(): void {
+ const {
+ objectState,
+ updateAnnotations,
+ } = this.props;
+
+ updateAnnotations([objectState]);
+ }
+
+ private changeFrame(frame: number): void {
+ const { changeFrame, canvasInstance } = this.props;
+ if (canvasInstance.isAbleToChangeFrame()) {
+ changeFrame(frame);
+ }
+ }
+
+ public render(): JSX.Element {
+ const {
+ objectState,
+ normalizedKeyMap,
+ frameNumber,
+ outsideDisabled,
+ hiddenDisabled,
+ keyframeDisabled,
+ } = this.props;
+
+ const {
+ first,
+ prev,
+ next,
+ last,
+ } = objectState.keyframes || {
+ first: null, // shapes don't have keyframes, so we use null
+ prev: null,
+ next: null,
+ last: null,
+ };
+
+ return (
+ = frameNumber || first === null
+ ? null : this.navigateFirstKeyframe
+ }
+ navigatePrevKeyframe={
+ prev === frameNumber || prev === null
+ ? null : this.navigatePrevKeyframe
+ }
+ navigateNextKeyframe={
+ next === frameNumber || next === null
+ ? null : this.navigateNextKeyframe
+ }
+ navigateLastKeyframe={
+ last <= frameNumber || last === null
+ ? null : this.navigateLastKeyframe
+ }
+
+ setOccluded={this.setOccluded}
+ unsetOccluded={this.unsetOccluded}
+ setOutside={this.setOutside}
+ unsetOutside={this.unsetOutside}
+ setKeyframe={this.setKeyframe}
+ unsetKeyframe={this.unsetKeyframe}
+ lock={this.lock}
+ unlock={this.unlock}
+ pin={this.pin}
+ unpin={this.unpin}
+ hide={this.hide}
+ show={this.show}
+ />
+ );
+ }
+}
+
+export default connect(
+ mapStateToProps,
+ mapDispatchToProps,
+)(ItemButtonsWrapper);
diff --git a/cvat-ui/src/containers/annotation-page/standard-workspace/objects-side-bar/object-item.tsx b/cvat-ui/src/containers/annotation-page/standard-workspace/objects-side-bar/object-item.tsx
index b2282a1c984d..34e8facf9948 100644
--- a/cvat-ui/src/containers/annotation-page/standard-workspace/objects-side-bar/object-item.tsx
+++ b/cvat-ui/src/containers/annotation-page/standard-workspace/objects-side-bar/object-item.tsx
@@ -7,7 +7,6 @@ import copy from 'copy-to-clipboard';
import { connect } from 'react-redux';
import { LogType } from 'cvat-logger';
-import { Canvas } from 'cvat-canvas-wrapper';
import {
ActiveControl,
CombinedState,
@@ -17,7 +16,6 @@ import {
import {
collapseObjectItems,
changeLabelColorAsync,
- createAnnotationsAsync,
updateAnnotationsAsync,
changeFrameAsync,
removeObjectAsync,
@@ -50,13 +48,11 @@ interface StateToProps {
minZLayer: number;
maxZLayer: number;
normalizedKeyMap: Record;
- canvasInstance: Canvas;
}
interface DispatchToProps {
changeFrame(frame: number): void;
updateState(objectState: any): void;
- createAnnotations(sessionInstance: any, frameNumber: number, state: any): void;
collapseOrExpand(objectStates: any[], collapsed: boolean): void;
activateObject: (activatedStateID: number | null) => void;
removeObject: (sessionInstance: any, objectState: any) => void;
@@ -91,7 +87,6 @@ function mapStateToProps(state: CombinedState, own: OwnProps): StateToProps {
canvas: {
ready,
activeControl,
- instance: canvasInstance,
},
colors,
},
@@ -127,7 +122,6 @@ function mapStateToProps(state: CombinedState, own: OwnProps): StateToProps {
minZLayer,
maxZLayer,
normalizedKeyMap,
- canvasInstance,
};
}
@@ -139,9 +133,6 @@ function mapDispatchToProps(dispatch: any): DispatchToProps {
updateState(state: any): void {
dispatch(updateAnnotationsAsync([state]));
},
- createAnnotations(sessionInstance: any, frameNumber: number, state: any): void {
- dispatch(createAnnotationsAsync(sessionInstance, frameNumber, state));
- },
collapseOrExpand(objectStates: any[], collapsed: boolean): void {
dispatch(collapseObjectItems(objectStates, collapsed));
},
@@ -172,38 +163,6 @@ function mapDispatchToProps(dispatch: any): DispatchToProps {
type Props = StateToProps & DispatchToProps;
class ObjectItemContainer extends React.PureComponent {
- private navigateFirstKeyframe = (): void => {
- const { objectState, frameNumber } = this.props;
- const { first } = objectState.keyframes;
- if (first !== frameNumber) {
- this.changeFrame(first);
- }
- };
-
- private navigatePrevKeyframe = (): void => {
- const { objectState, frameNumber } = this.props;
- const { prev } = objectState.keyframes;
- if (prev !== null && prev !== frameNumber) {
- this.changeFrame(prev);
- }
- };
-
- private navigateNextKeyframe = (): void => {
- const { objectState, frameNumber } = this.props;
- const { next } = objectState.keyframes;
- if (next !== null && next !== frameNumber) {
- this.changeFrame(next);
- }
- };
-
- private navigateLastKeyframe = (): void => {
- const { objectState, frameNumber } = this.props;
- const { last } = objectState.keyframes;
- if (last !== frameNumber) {
- this.changeFrame(last);
- }
- };
-
private copy = (): void => {
const { objectState, copyShape } = this.props;
copyShape(objectState);
@@ -300,80 +259,6 @@ class ObjectItemContainer extends React.PureComponent {
}
};
- private lock = (): void => {
- const { objectState, jobInstance } = this.props;
- jobInstance.logger.log(LogType.lockObject, { locked: true });
- objectState.lock = true;
- this.commit();
- };
-
- private unlock = (): void => {
- const { objectState, jobInstance } = this.props;
- jobInstance.logger.log(LogType.lockObject, { locked: false });
- objectState.lock = false;
- this.commit();
- };
-
- private pin = (): void => {
- const { objectState } = this.props;
- objectState.pinned = true;
- this.commit();
- };
-
- private unpin = (): void => {
- const { objectState } = this.props;
- objectState.pinned = false;
- this.commit();
- };
-
- private show = (): void => {
- const { objectState } = this.props;
- objectState.hidden = false;
- this.commit();
- };
-
- private hide = (): void => {
- const { objectState } = this.props;
- objectState.hidden = true;
- this.commit();
- };
-
- private setOccluded = (): void => {
- const { objectState } = this.props;
- objectState.occluded = true;
- this.commit();
- };
-
- private unsetOccluded = (): void => {
- const { objectState } = this.props;
- objectState.occluded = false;
- this.commit();
- };
-
- private setOutside = (): void => {
- const { objectState } = this.props;
- objectState.outside = true;
- this.commit();
- };
-
- private unsetOutside = (): void => {
- const { objectState } = this.props;
- objectState.outside = false;
- this.commit();
- };
-
- private setKeyframe = (): void => {
- const { objectState } = this.props;
- objectState.keyframe = true;
- this.commit();
- };
-
- private unsetKeyframe = (): void => {
- const { objectState } = this.props;
- objectState.keyframe = false;
- this.commit();
- };
-
private collapse = (): void => {
const {
collapseOrExpand,
@@ -473,13 +358,6 @@ class ObjectItemContainer extends React.PureComponent {
if (commit) this.commit();
};
- private changeFrame(frame: number): void {
- const { changeFrame, canvasInstance } = this.props;
- if (canvasInstance.isAbleToChangeFrame()) {
- changeFrame(frame);
- }
- }
-
private commit(): void {
const {
objectState,
@@ -495,25 +373,12 @@ class ObjectItemContainer extends React.PureComponent {
collapsed,
labels,
attributes,
- frameNumber,
activated,
colorBy,
colors,
normalizedKeyMap,
} = this.props;
- const {
- first,
- prev,
- next,
- last,
- } = objectState.keyframes || {
- first: null, // shapes don't have keyframes, so we use null
- prev: null,
- next: null,
- last: null,
- };
-
let stateColor = '';
if (colorBy === ColorBy.INSTANCE) {
stateColor = objectState.color;
@@ -530,12 +395,7 @@ class ObjectItemContainer extends React.PureComponent {
shapeType={objectState.shapeType}
clientID={objectState.clientID}
serverID={objectState.serverID}
- occluded={objectState.occluded}
- outside={objectState.outside}
locked={objectState.lock}
- pinned={objectState.pinned}
- hidden={objectState.hidden}
- keyframe={objectState.keyframe}
attrValues={{ ...objectState.attributes }}
labelID={objectState.label.id}
color={stateColor}
@@ -544,22 +404,6 @@ class ObjectItemContainer extends React.PureComponent {
normalizedKeyMap={normalizedKeyMap}
labels={labels}
collapsed={collapsed}
- navigateFirstKeyframe={
- first >= frameNumber || first === null
- ? null : this.navigateFirstKeyframe
- }
- navigatePrevKeyframe={
- prev === frameNumber || prev === null
- ? null : this.navigatePrevKeyframe
- }
- navigateNextKeyframe={
- next === frameNumber || next === null
- ? null : this.navigateNextKeyframe
- }
- navigateLastKeyframe={
- last <= frameNumber || last === null
- ? null : this.navigateLastKeyframe
- }
activate={this.activate}
remove={this.remove}
copy={this.copy}
@@ -568,18 +412,6 @@ class ObjectItemContainer extends React.PureComponent {
switchOrientation={this.switchOrientation}
toBackground={this.toBackground}
toForeground={this.toForeground}
- setOccluded={this.setOccluded}
- unsetOccluded={this.unsetOccluded}
- setOutside={this.setOutside}
- unsetOutside={this.unsetOutside}
- setKeyframe={this.setKeyframe}
- unsetKeyframe={this.unsetKeyframe}
- lock={this.lock}
- unlock={this.unlock}
- pin={this.pin}
- unpin={this.unpin}
- hide={this.hide}
- show={this.show}
changeColor={this.changeColor}
changeLabel={this.changeLabel}
changeAttribute={this.changeAttribute}
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 2873f0261173..000000000000
--- a/cvat-ui/src/containers/annotation-page/standard-workspace/objects-side-bar/objects-side-bar.tsx
+++ /dev/null
@@ -1,254 +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';
-
-import { Canvas } from 'cvat-canvas-wrapper';
-
-interface StateToProps {
- sidebarCollapsed: boolean;
- appearanceCollapsed: boolean;
- colorBy: ColorBy;
- opacity: number;
- selectedOpacity: number;
- blackBorders: boolean;
- showBitmap: boolean;
- showProjections: boolean;
- canvasInstance: Canvas;
-}
-
-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,
- canvas: {
- instance: canvasInstance,
- },
- },
- settings: {
- shapes: {
- colorBy,
- opacity,
- selectedOpacity,
- blackBorders,
- showBitmap,
- showProjections,
- },
- },
- } = state;
-
- return {
- sidebarCollapsed,
- appearanceCollapsed,
- colorBy,
- opacity,
- selectedOpacity,
- blackBorders,
- showBitmap,
- showProjections,
- canvasInstance,
- };
-}
-
-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,
- canvasInstance,
- collapseSidebar,
- collapseAppearance,
- } = this.props;
-
- return (
-
- );
- }
-}
-
-export default connect(
- mapStateToProps,
- mapDispatchToProps,
-)(ObjectsSideBarContainer);
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 75c15028e120..74cd406ea871 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 5fecbd07e1f0..09685de64530 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/header/header.tsx b/cvat-ui/src/containers/header/header.tsx
index ed0e55f631cb..49d5a8d051fe 100644
--- a/cvat-ui/src/containers/header/header.tsx
+++ b/cvat-ui/src/containers/header/header.tsx
@@ -3,7 +3,6 @@
// SPDX-License-Identifier: MIT
import { connect } from 'react-redux';
-import { ExtendedKeyMapOptions } from 'react-hotkeys';
import getCore from 'cvat-core-wrapper';
import HeaderComponent from 'components/header/header';
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 218ba63819c1..4855f62d16a5 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/task-page/task-page.tsx b/cvat-ui/src/containers/task-page/task-page.tsx
index 77f73f09d9c7..01b4b4ed5c69 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/tasks-page.tsx b/cvat-ui/src/containers/tasks-page/tasks-page.tsx
index 545912aaef51..071c1cc75fd0 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);
diff --git a/cvat-ui/src/utils/redux.ts b/cvat-ui/src/utils/redux.ts
index 507c7097ed10..8627d2c34586 100644
--- a/cvat-ui/src/utils/redux.ts
+++ b/cvat-ui/src/utils/redux.ts
@@ -23,5 +23,5 @@ export type ActionUnion = ReturnType
= _ThunkAction;
-export type ThunkDispatch
+export type ThunkDispatch
= _ThunkDispatch;
From 18f6b2f95d0bcd0a491ad3f7a892fabb734f7b00 Mon Sep 17 00:00:00 2001
From: Boris Sekachev <40690378+bsekachev@users.noreply.github.com>
Date: Thu, 2 Jul 2020 16:01:39 +0300
Subject: [PATCH 10/15] [CVAT-UI] Fixed displaying on canvas in some cases
(#1834)
* Fixed displaying on canvas in some cases
* Updated changelog
---
CHANGELOG.md | 2 +-
cvat-canvas/package-lock.json | 2 +-
cvat-canvas/package.json | 2 +-
cvat-canvas/src/typescript/canvasView.ts | 8 ++++----
4 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index fb7e627aeb21..09f651e5b89f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -18,7 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
-
### Fixed
--
+- Some objects aren't shown on canvas sometimes. For example after propagation on of objects is invisible ()
### Security
-
diff --git a/cvat-canvas/package-lock.json b/cvat-canvas/package-lock.json
index 65559bdb8282..c59ddb778db0 100644
--- a/cvat-canvas/package-lock.json
+++ b/cvat-canvas/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "cvat-canvas",
- "version": "1.2.1",
+ "version": "1.2.2",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/cvat-canvas/package.json b/cvat-canvas/package.json
index a27a4c575cb5..0a2dcbf9c2b7 100644
--- a/cvat-canvas/package.json
+++ b/cvat-canvas/package.json
@@ -1,6 +1,6 @@
{
"name": "cvat-canvas",
- "version": "1.2.1",
+ "version": "1.2.2",
"description": "Part of Computer Vision Annotation Tool which presents its canvas library",
"main": "src/canvas.ts",
"scripts": {
diff --git a/cvat-canvas/src/typescript/canvasView.ts b/cvat-canvas/src/typescript/canvasView.ts
index 8c3d27fc7887..e1da53d33768 100644
--- a/cvat-canvas/src/typescript/canvasView.ts
+++ b/cvat-canvas/src/typescript/canvasView.ts
@@ -99,7 +99,7 @@ export class CanvasViewImpl implements CanvasView, Listener {
if (value) {
if (shape) {
(state.shapeType === 'points' ? shape.remember('_selectHandler').nested : shape)
- .style('display', 'none');
+ .addClass('cvat_canvas_hidden');
}
if (text) {
@@ -112,7 +112,7 @@ export class CanvasViewImpl implements CanvasView, Listener {
if (!state.outside && !state.hidden) {
if (shape) {
(state.shapeType === 'points' ? shape.remember('_selectHandler').nested : shape)
- .style('display', '');
+ .removeClass('cvat_canvas_hidden');
}
if (text) {
@@ -1244,13 +1244,13 @@ export class CanvasViewImpl implements CanvasView, Listener {
if (drawnState.hidden !== state.hidden || drawnState.outside !== state.outside) {
if (isInvisible) {
(state.shapeType === 'points' ? shape.remember('_selectHandler').nested : shape)
- .style('display', 'none');
+ .addClass('cvat_canvas_hidden');
if (text) {
text.addClass('cvat_canvas_hidden');
}
} else {
(state.shapeType === 'points' ? shape.remember('_selectHandler').nested : shape)
- .style('display', '');
+ .removeClass('cvat_canvas_hidden');
if (text) {
text.removeClass('cvat_canvas_hidden');
this.updateTextPosition(
From fc2fb6156a21650cb6a505fac99f5455b1558a5a Mon Sep 17 00:00:00 2001
From: zhiltsov-max
Date: Tue, 7 Jul 2020 21:34:04 +0300
Subject: [PATCH 11/15] Don't export outside annotations (#1729)
* Add option to omit outside annotations
* update changelog
* Fix mot format and test
* Fix outside in mot
* fix repo problem
* t
* Update CHANGELOG.md
Co-authored-by: Nikita Manovich <40690625+nmanovic@users.noreply.github.com>
---
CHANGELOG.md | 1 +
cvat/apps/dataset_manager/bindings.py | 6 ++++-
cvat/apps/dataset_manager/formats/mot.py | 11 +++++---
.../dataset_manager/tests/_test_formats.py | 19 +++++++++++++-
cvat/apps/engine/tests/_test_rest_api.py | 25 +++++++++++++++++--
datumaro/datumaro/components/project.py | 22 ++++++++++------
6 files changed, 69 insertions(+), 15 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 09f651e5b89f..988a2c31ef87 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed
- Some objects aren't shown on canvas sometimes. For example after propagation on of objects is invisible ()
+- `outside` annotations should not be in exported images ()
### Security
-
diff --git a/cvat/apps/dataset_manager/bindings.py b/cvat/apps/dataset_manager/bindings.py
index d7c92ed4f724..787c7f8e5cb3 100644
--- a/cvat/apps/dataset_manager/bindings.py
+++ b/cvat/apps/dataset_manager/bindings.py
@@ -442,9 +442,10 @@ def match_frame_fuzzy(self, path):
return None
class CvatTaskDataExtractor(datumaro.SourceExtractor):
- def __init__(self, task_data, include_images=False):
+ def __init__(self, task_data, include_images=False, include_outside=False):
super().__init__()
self._categories = self._load_categories(task_data)
+ self._include_outside = include_outside
dm_items = []
@@ -541,6 +542,9 @@ def convert_attrs(label, cvat_attrs):
anno_attr['track_id'] = shape_obj.track_id
anno_attr['keyframe'] = shape_obj.keyframe
+ if not self._include_outside and shape_obj.outside:
+ continue
+
anno_points = shape_obj.points
if shape_obj.type == ShapeType.POINTS:
anno = datumaro.Points(anno_points,
diff --git a/cvat/apps/dataset_manager/formats/mot.py b/cvat/apps/dataset_manager/formats/mot.py
index 1efb9b578c6c..37fa7a7bc793 100644
--- a/cvat/apps/dataset_manager/formats/mot.py
+++ b/cvat/apps/dataset_manager/formats/mot.py
@@ -63,7 +63,7 @@ def _import(src_file, task_data):
points=ann.points,
occluded=ann.attributes.get('occluded') == True,
outside=False,
- keyframe=False,
+ keyframe=True,
z_order=ann.z_order,
frame=frame_number,
attributes=[],
@@ -78,6 +78,11 @@ def _import(src_file, task_data):
for track in tracks.values():
# MOT annotations do not require frames to be ordered
track.shapes.sort(key=lambda t: t.frame)
- # Set outside=True for the last shape in a track to finish the track
- track.shapes[-1] = track.shapes[-1]._replace(outside=True)
+ # Append a shape with outside=True to finish the track
+ last_shape = track.shapes[-1]
+ if last_shape.frame + task_data.frame_step <= \
+ int(task_data.meta['task']['stop_frame']):
+ track.shapes.append(last_shape._replace(outside=True,
+ frame=last_shape.frame + task_data.frame_step)
+ )
task_data.add_track(track)
diff --git a/cvat/apps/dataset_manager/tests/_test_formats.py b/cvat/apps/dataset_manager/tests/_test_formats.py
index c6c8ab7feb73..5dbee71c44c6 100644
--- a/cvat/apps/dataset_manager/tests/_test_formats.py
+++ b/cvat/apps/dataset_manager/tests/_test_formats.py
@@ -77,7 +77,8 @@ def _setUpModule():
_setUpModule()
from cvat.apps.dataset_manager.annotation import AnnotationIR
-from cvat.apps.dataset_manager.bindings import TaskData
+from cvat.apps.dataset_manager.bindings import TaskData, CvatTaskDataExtractor
+from cvat.apps.dataset_manager.task import TaskAnnotation
from cvat.apps.engine.models import Task
@@ -406,6 +407,22 @@ def load_dataset(src):
self.assertEqual(len(dataset), task["size"])
self._test_export(check, task, format_name, save_images=False)
+ def test_can_skip_outside(self):
+ images = self._generate_task_images(3)
+ task = self._generate_task(images)
+ self._generate_annotations(task)
+ task_ann = TaskAnnotation(task["id"])
+ task_ann.init_from_db()
+ task_data = TaskData(task_ann.ir_data, Task.objects.get(pk=task["id"]))
+
+ extractor = CvatTaskDataExtractor(task_data, include_outside=False)
+ dm_dataset = datumaro.components.project.Dataset.from_extractors(extractor)
+ self.assertEqual(4, len(dm_dataset.get("image_1").annotations))
+
+ extractor = CvatTaskDataExtractor(task_data, include_outside=True)
+ dm_dataset = datumaro.components.project.Dataset.from_extractors(extractor)
+ self.assertEqual(5, len(dm_dataset.get("image_1").annotations))
+
def test_cant_make_rel_frame_id_from_unknown(self):
images = self._generate_task_images(3)
images['frame_filter'] = 'step=2'
diff --git a/cvat/apps/engine/tests/_test_rest_api.py b/cvat/apps/engine/tests/_test_rest_api.py
index 8046efbc4b6e..44d8f32a9246 100644
--- a/cvat/apps/engine/tests/_test_rest_api.py
+++ b/cvat/apps/engine/tests/_test_rest_api.py
@@ -2965,6 +2965,19 @@ def _get_initial_annotation(annotation_format):
"points": [2.0, 2.1, 77.2, 36.22],
"type": "rectangle",
"occluded": True,
+ "outside": False,
+ "attributes": [
+ {
+ "spec_id": task["labels"][0]["attributes"][1]["id"],
+ "value": task["labels"][0]["attributes"][1]["default_value"]
+ }
+ ]
+ },
+ {
+ "frame": 2,
+ "points": [2.0, 2.1, 77.2, 36.22],
+ "type": "rectangle",
+ "occluded": True,
"outside": True,
"attributes": [
{
@@ -2976,19 +2989,27 @@ def _get_initial_annotation(annotation_format):
]
}]
rectangle_tracks_wo_attrs = [{
- "frame": 1,
+ "frame": 0,
"label_id": task["labels"][1]["id"],
"group": 0,
"attributes": [],
"shapes": [
{
- "frame": 1,
+ "frame": 0,
"attributes": [],
"points": [1.0, 2.1, 50.2, 36.6],
"type": "rectangle",
"occluded": False,
"outside": False
},
+ {
+ "frame": 1,
+ "attributes": [],
+ "points": [1.0, 2.1, 51, 36.6],
+ "type": "rectangle",
+ "occluded": False,
+ "outside": False
+ },
{
"frame": 2,
"attributes": [],
diff --git a/datumaro/datumaro/components/project.py b/datumaro/datumaro/components/project.py
index 4fe08b13f4fd..c99b514f6e38 100644
--- a/datumaro/datumaro/components/project.py
+++ b/datumaro/datumaro/components/project.py
@@ -104,7 +104,7 @@ class GitWrapper:
def __init__(self, config=None):
self.repo = None
- if config is not None and osp.isdir(config.project_dir):
+ if config is not None and config.project_dir:
self.init(config.project_dir)
@staticmethod
@@ -116,8 +116,12 @@ def spawn(cls, path):
spawn = not osp.isdir(cls._git_dir(path))
repo = git.Repo.init(path=path)
if spawn:
- author = git.Actor("Nobody", "nobody@example.com")
- repo.index.commit('Initial commit', author=author)
+ repo.config_writer().set_value("user", "name", "User") \
+ .set_value("user", "email", "user@nowhere.com") \
+ .release()
+ # gitpython does not support init, use git directly
+ repo.git.init()
+ repo.git.commit('-m', 'Initial commit', '--allow-empty')
return repo
def init(self, path):
@@ -377,9 +381,10 @@ def categories(self):
def get(self, item_id, subset=None, path=None):
if path:
raise KeyError("Requested dataset item path is not found")
- if subset is None:
- subset = ''
- return self._subsets[subset].items[item_id]
+ item_id = str(item_id)
+ subset = subset or ''
+ subset = self._subsets[subset]
+ return subset.items[item_id]
def put(self, item, item_id=None, subset=None, path=None):
if path:
@@ -567,7 +572,7 @@ def get(self, item_id, subset=None, path=None):
rest_path = path[1:]
return self._sources[source].get(
item_id=item_id, subset=subset, path=rest_path)
- return self._subsets[subset].items[item_id]
+ return super().get(item_id, subset)
def put(self, item, item_id=None, subset=None, path=None):
if path is None:
@@ -754,9 +759,10 @@ def save(self, save_dir=None):
@staticmethod
def generate(save_dir, config=None):
+ config = Config(config)
+ config.project_dir = save_dir
project = Project(config)
project.save(save_dir)
- project.config.project_dir = save_dir
return project
@staticmethod
From e6b0c667f286ebb81484faac0284b3db7492f5ee Mon Sep 17 00:00:00 2001
From: Andrey Zhavoronkov <41117609+azhavoro@users.noreply.github.com>
Date: Wed, 8 Jul 2020 21:46:29 +0300
Subject: [PATCH 12/15] specified setuptools version to fix build fail (#1866)
---
Dockerfile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Dockerfile b/Dockerfile
index e6eb2911652b..77475cdaa6b9 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -56,7 +56,7 @@ RUN apt-get update && \
curl && \
curl https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash && \
apt-get --no-install-recommends install -y git-lfs && git lfs install && \
- python3 -m pip install --no-cache-dir -U pip==20.0.1 setuptools && \
+ python3 -m pip install --no-cache-dir -U pip==20.0.1 setuptools>=49.1.0 && \
ln -fs /usr/share/zoneinfo/${TZ} /etc/localtime && \
dpkg-reconfigure -f noninteractive tzdata && \
add-apt-repository --remove ppa:mc3man/gstffmpeg-keep -y && \
From 760090cbe5050d9b74e24eed73494968998aaaec Mon Sep 17 00:00:00 2001
From: "dependabot-preview[bot]"
<27856297+dependabot-preview[bot]@users.noreply.github.com>
Date: Wed, 8 Jul 2020 21:47:59 +0300
Subject: [PATCH 13/15] Bump opencv-python from 4.2.0.34 to 4.3.0.36 in
/cvat/requirements (#1854)
Bumps [opencv-python](https://github.com/skvark/opencv-python) from 4.2.0.34 to 4.3.0.36.
- [Release notes](https://github.com/skvark/opencv-python/releases)
- [Commits](https://github.com/skvark/opencv-python/commits)
Signed-off-by: dependabot-preview[bot]
Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
---
cvat/requirements/base.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/cvat/requirements/base.txt b/cvat/requirements/base.txt
index b6fd124dae6d..a53023f51dd2 100644
--- a/cvat/requirements/base.txt
+++ b/cvat/requirements/base.txt
@@ -40,7 +40,7 @@ matplotlib==3.0.3
scikit-image==0.15.0
tensorflow==2.2.0
keras==2.4.2
-opencv-python==4.2.0.34
+opencv-python==4.3.0.36
h5py==2.10.0
imgaug==0.4.0
django-cors-headers==3.4.0
From bcdcaaf459faf6c8a4e430ee4b9356a042db692a Mon Sep 17 00:00:00 2001
From: "dependabot-preview[bot]"
<27856297+dependabot-preview[bot]@users.noreply.github.com>
Date: Wed, 8 Jul 2020 21:48:30 +0300
Subject: [PATCH 14/15] Bump django-extensions from 3.0.1 to 3.0.2 in
/cvat/requirements (#1833)
Bumps [django-extensions](https://github.com/django-extensions/django-extensions) from 3.0.1 to 3.0.2.
- [Release notes](https://github.com/django-extensions/django-extensions/releases)
- [Changelog](https://github.com/django-extensions/django-extensions/blob/master/CHANGELOG.md)
- [Commits](https://github.com/django-extensions/django-extensions/compare/3.0.1...3.0.2)
Signed-off-by: dependabot-preview[bot]
Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
---
cvat/requirements/development.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/cvat/requirements/development.txt b/cvat/requirements/development.txt
index b3f846268c33..4214fcdce8bd 100644
--- a/cvat/requirements/development.txt
+++ b/cvat/requirements/development.txt
@@ -8,6 +8,6 @@ pylint-django==2.0.15
pylint-plugin-utils==0.6
rope==0.17.0
wrapt==1.12.1
-django-extensions==3.0.1
+django-extensions==3.0.2
Werkzeug==1.0.1
snakeviz==2.1.0
From 2a5cfcc6573160d55f7dfcb2278b5dc320cb12ae Mon Sep 17 00:00:00 2001
From: Boris Sekachev <40690378+bsekachev@users.noreply.github.com>
Date: Thu, 9 Jul 2020 17:17:27 +0300
Subject: [PATCH 15/15] [CVAT-UI] Critical fixes (#1874)
* Fixed redux types
* Redesigned approach to close job. Previous variant didn't work properly with GlobalErrorBoundary
* Fixed: cannot read property shapeType of undefined
* Cannot read property 'pinned' of undefined
* Do not iterate invisible objects (zLayer) in aam
* Keep cursor on the same position when editing text
* Do not select hidden shapes when grouping
* Updated version
* Fixed host
---
CHANGELOG.md | 6 ++++++
cvat-canvas/package-lock.json | 2 +-
cvat-canvas/package.json | 2 +-
cvat-canvas/src/typescript/canvas.ts | 11 +++--------
cvat-canvas/src/typescript/canvasModel.ts | 17 ++++++-----------
cvat-canvas/src/typescript/canvasView.ts | 3 +--
cvat-canvas/src/typescript/groupHandler.ts | 4 +++-
cvat-ui/package-lock.json | 2 +-
cvat-ui/package.json | 2 +-
.../annotation-page/annotation-page.tsx | 8 ++++++++
.../attribute-annotation-sidebar.tsx | 10 +++++++++-
.../standard-workspace/canvas-wrapper.tsx | 17 +++++++----------
.../objects-side-bar/object-item-attribute.tsx | 2 +-
.../annotation-page/annotation-page.tsx | 6 +++++-
.../annotation-page/top-bar/top-bar.tsx | 7 -------
cvat-ui/src/utils/redux.ts | 2 +-
16 files changed, 54 insertions(+), 47 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 988a2c31ef87..f5a9fda1ab27 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -19,6 +19,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed
- Some objects aren't shown on canvas sometimes. For example after propagation on of objects is invisible ()
+- CVAT doesn't offer to restore state after an error ()
+- Cannot read property 'shapeType' of undefined because of zOrder related issues ()
+- Cannot read property 'pinned' of undefined because of zOrder related issues ()
+- Do not iterate over hidden objects in aam (which are invisible because of zOrder) ()
+- Cursor position is reset after changing a text field ()
+- Hidden points and cuboids can be selected to be groupped ()
- `outside` annotations should not be in exported images ()
### Security
diff --git a/cvat-canvas/package-lock.json b/cvat-canvas/package-lock.json
index c59ddb778db0..f892c11a647c 100644
--- a/cvat-canvas/package-lock.json
+++ b/cvat-canvas/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "cvat-canvas",
- "version": "1.2.2",
+ "version": "2.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/cvat-canvas/package.json b/cvat-canvas/package.json
index 0a2dcbf9c2b7..2044f33dea1d 100644
--- a/cvat-canvas/package.json
+++ b/cvat-canvas/package.json
@@ -1,6 +1,6 @@
{
"name": "cvat-canvas",
- "version": "1.2.2",
+ "version": "2.0.0",
"description": "Part of Computer Vision Annotation Tool which presents its canvas library",
"main": "src/canvas.ts",
"scripts": {
diff --git a/cvat-canvas/src/typescript/canvas.ts b/cvat-canvas/src/typescript/canvas.ts
index e0db5e5a1753..356997666f7d 100644
--- a/cvat-canvas/src/typescript/canvas.ts
+++ b/cvat-canvas/src/typescript/canvas.ts
@@ -36,8 +36,7 @@ const CanvasVersion = pjson.version;
interface Canvas {
html(): HTMLDivElement;
- setZLayer(zLayer: number | null): void;
- setup(frameData: any, objectStates: any[]): void;
+ setup(frameData: any, objectStates: any[], zLayer?: number): void;
activate(clientID: number | null, attributeID?: number): void;
rotate(rotationAngle: number): void;
focus(clientID: number, padding?: number): void;
@@ -76,12 +75,8 @@ class CanvasImpl implements Canvas {
return this.view.html();
}
- public setZLayer(zLayer: number | null): void {
- this.model.setZLayer(zLayer);
- }
-
- public setup(frameData: any, objectStates: any[]): void {
- this.model.setup(frameData, objectStates);
+ public setup(frameData: any, objectStates: any[], zLayer = 0): void {
+ this.model.setup(frameData, objectStates, zLayer);
}
public fitCanvas(): void {
diff --git a/cvat-canvas/src/typescript/canvasModel.ts b/cvat-canvas/src/typescript/canvasModel.ts
index e2069efe27c4..ec860e77bbe5 100644
--- a/cvat-canvas/src/typescript/canvasModel.ts
+++ b/cvat-canvas/src/typescript/canvasModel.ts
@@ -98,7 +98,6 @@ export enum UpdateReasons {
IMAGE_FITTED = 'image_fitted',
IMAGE_MOVED = 'image_moved',
GRID_UPDATED = 'grid_updated',
- SET_Z_LAYER = 'set_z_layer',
OBJECTS_UPDATED = 'objects_updated',
SHAPE_ACTIVATED = 'shape_activated',
@@ -148,11 +147,10 @@ export interface CanvasModel {
geometry: Geometry;
mode: Mode;
- setZLayer(zLayer: number | null): void;
zoom(x: number, y: number, direction: number): void;
move(topOffset: number, leftOffset: number): void;
- setup(frameData: any, objectStates: any[]): void;
+ setup(frameData: any, objectStates: any[], zLayer: number): void;
activate(clientID: number | null, attributeID: number | null): void;
rotate(rotationAngle: number): void;
focus(clientID: number, padding: number): void;
@@ -258,11 +256,6 @@ export class CanvasModelImpl extends MasterImpl implements CanvasModel {
};
}
- public setZLayer(zLayer: number | null): void {
- this.data.zLayer = zLayer;
- this.notify(UpdateReasons.SET_Z_LAYER);
- }
-
public zoom(x: number, y: number, direction: number): void {
const oldScale: number = this.data.scale;
const newScale: number = direction > 0 ? oldScale * 6 / 5 : oldScale * 5 / 6;
@@ -337,7 +330,7 @@ export class CanvasModelImpl extends MasterImpl implements CanvasModel {
this.notify(UpdateReasons.ZOOM_CANVAS);
}
- public setup(frameData: any, objectStates: any[]): void {
+ public setup(frameData: any, objectStates: any[], zLayer: number): void {
if (this.data.imageID !== frameData.number) {
if ([Mode.EDIT, Mode.DRAG, Mode.RESIZE].includes(this.data.mode)) {
throw Error(`Canvas is busy. Action: ${this.data.mode}`);
@@ -345,6 +338,7 @@ export class CanvasModelImpl extends MasterImpl implements CanvasModel {
}
if (frameData.number === this.data.imageID) {
+ this.data.zLayer = zLayer;
this.data.objects = objectStates;
this.notify(UpdateReasons.OBJECTS_UPDATED);
return;
@@ -369,6 +363,7 @@ export class CanvasModelImpl extends MasterImpl implements CanvasModel {
this.data.image = data;
this.notify(UpdateReasons.IMAGE_CHANGED);
+ this.data.zLayer = zLayer;
this.data.objects = objectStates;
this.notify(UpdateReasons.OBJECTS_UPDATED);
}).catch((exception: any): void => {
@@ -388,9 +383,9 @@ export class CanvasModelImpl extends MasterImpl implements CanvasModel {
}
if (typeof (clientID) === 'number') {
- const [state] = this.data.objects
+ const [state] = this.objects
.filter((_state: any): boolean => _state.clientID === clientID);
- if (!['rectangle', 'polygon', 'polyline', 'points', 'cuboid'].includes(state.shapeType)) {
+ if (!state || state.objectType === 'tag') {
return;
}
}
diff --git a/cvat-canvas/src/typescript/canvasView.ts b/cvat-canvas/src/typescript/canvasView.ts
index e1da53d33768..6a99b7b06299 100644
--- a/cvat-canvas/src/typescript/canvasView.ts
+++ b/cvat-canvas/src/typescript/canvasView.ts
@@ -991,7 +991,7 @@ export class CanvasViewImpl implements CanvasView, Listener {
}
} else if (reason === UpdateReasons.IMAGE_MOVED) {
this.moveCanvas();
- } else if ([UpdateReasons.OBJECTS_UPDATED, UpdateReasons.SET_Z_LAYER].includes(reason)) {
+ } else if ([UpdateReasons.OBJECTS_UPDATED].includes(reason)) {
if (this.mode === Mode.GROUP) {
this.groupHandler.resetSelectedObjects();
}
@@ -1128,7 +1128,6 @@ export class CanvasViewImpl implements CanvasView, Listener {
if (model.imageBitmap
&& [UpdateReasons.IMAGE_CHANGED,
UpdateReasons.OBJECTS_UPDATED,
- UpdateReasons.SET_Z_LAYER,
].includes(reason)
) {
this.redrawBitmap();
diff --git a/cvat-canvas/src/typescript/groupHandler.ts b/cvat-canvas/src/typescript/groupHandler.ts
index 0c2475ef4201..f92cdab6b3c1 100644
--- a/cvat-canvas/src/typescript/groupHandler.ts
+++ b/cvat-canvas/src/typescript/groupHandler.ts
@@ -95,7 +95,9 @@ export class GroupHandlerImpl implements GroupHandler {
this.selectionRect = null;
const box = this.getSelectionBox(event);
- const shapes = (this.canvas.select('.cvat_canvas_shape') as any).members;
+ const shapes = (this.canvas.select('.cvat_canvas_shape') as any).members.filter(
+ (shape: SVG.Shape): boolean => !shape.hasClass('cvat_canvas_hidden'),
+ );
for (const shape of shapes) {
// TODO: Doesn't work properly for groups
const bbox = shape.bbox();
diff --git a/cvat-ui/package-lock.json b/cvat-ui/package-lock.json
index ed0924cdfe7b..2ca3283040c0 100644
--- a/cvat-ui/package-lock.json
+++ b/cvat-ui/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "cvat-ui",
- "version": "1.6.0",
+ "version": "1.6.1",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/cvat-ui/package.json b/cvat-ui/package.json
index 0d4115f1b824..c9b49488645f 100644
--- a/cvat-ui/package.json
+++ b/cvat-ui/package.json
@@ -1,6 +1,6 @@
{
"name": "cvat-ui",
- "version": "1.6.0",
+ "version": "1.6.1",
"description": "CVAT single-page application",
"main": "src/index.tsx",
"scripts": {
diff --git a/cvat-ui/src/components/annotation-page/annotation-page.tsx b/cvat-ui/src/components/annotation-page/annotation-page.tsx
index 5f84511217fc..8854dd5da894 100644
--- a/cvat-ui/src/components/annotation-page/annotation-page.tsx
+++ b/cvat-ui/src/components/annotation-page/annotation-page.tsx
@@ -4,6 +4,7 @@
import './styles.scss';
import React, { useEffect } from 'react';
+import { useHistory } from 'react-router';
import Layout from 'antd/lib/layout';
import Spin from 'antd/lib/spin';
import Result from 'antd/lib/result';
@@ -20,6 +21,7 @@ interface Props {
fetching: boolean;
getJob(): void;
saveLogs(): void;
+ closeJob(): void;
workspace: Workspace;
}
@@ -28,10 +30,12 @@ export default function AnnotationPageComponent(props: Props): JSX.Element {
job,
fetching,
getJob,
+ closeJob,
saveLogs,
workspace,
} = props;
+ const history = useHistory();
useEffect(() => {
saveLogs();
const root = window.document.getElementById('root');
@@ -44,6 +48,10 @@ export default function AnnotationPageComponent(props: Props): JSX.Element {
if (root) {
root.style.minHeight = '';
}
+
+ if (!history.location.pathname.includes('/jobs')) {
+ closeJob();
+ }
};
}, []);
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 85b186ee82ee..71170227bafc 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
@@ -40,6 +40,7 @@ interface StateToProps {
normalizedKeyMap: Record;
canvasInstance: Canvas;
canvasIsReady: boolean;
+ curZLayer: number;
}
interface DispatchToProps {
@@ -59,6 +60,9 @@ function mapStateToProps(state: CombinedState): StateToProps {
activatedStateID,
activatedAttributeID,
states,
+ zLayer: {
+ cur,
+ },
},
job: {
instance: jobInstance,
@@ -85,6 +89,7 @@ function mapStateToProps(state: CombinedState): StateToProps {
normalizedKeyMap,
canvasInstance,
canvasIsReady,
+ curZLayer: cur,
};
}
@@ -116,9 +121,12 @@ function AttributeAnnotationSidebar(props: StateToProps & DispatchToProps): JSX.
normalizedKeyMap,
canvasInstance,
canvasIsReady,
+ curZLayer,
} = props;
- const filteredStates = states.filter((state) => !state.outside && !state.hidden);
+ const filteredStates = states.filter((state) => !state.outside
+ && !state.hidden
+ && state.zOrder <= curZLayer);
const [labelAttrMap, setLabelAttrMap] = useState(
labels.reduce((acc, label): LabelAttrMap => {
acc[label.id] = label.attributes.length ? label.attributes[0] : null;
diff --git a/cvat-ui/src/components/annotation-page/standard-workspace/canvas-wrapper.tsx b/cvat-ui/src/components/annotation-page/standard-workspace/canvas-wrapper.tsx
index 652338cf07da..b10cd3d6bfe8 100644
--- a/cvat-ui/src/components/annotation-page/standard-workspace/canvas-wrapper.tsx
+++ b/cvat-ui/src/components/annotation-page/standard-workspace/canvas-wrapper.tsx
@@ -102,7 +102,6 @@ export default class CanvasWrapperComponent extends React.PureComponent {
automaticBordering,
showObjectsTextAlways,
canvasInstance,
- curZLayer,
} = this.props;
// It's awful approach from the point of view React
@@ -116,7 +115,6 @@ export default class CanvasWrapperComponent extends React.PureComponent {
undefinedAttrValue: consts.UNDEFINED_ATTRIBUTE_VALUE,
displayAllText: showObjectsTextAlways,
});
- canvasInstance.setZLayer(curZLayer);
this.initialSetup();
this.updateCanvas();
@@ -217,17 +215,15 @@ export default class CanvasWrapperComponent extends React.PureComponent {
}
}
- if (prevProps.curZLayer !== curZLayer) {
- canvasInstance.setZLayer(curZLayer);
- }
-
- if (prevProps.annotations !== annotations || prevProps.frameData !== frameData) {
+ if (prevProps.annotations !== annotations
+ || prevProps.frameData !== frameData
+ || prevProps.curZLayer !== curZLayer) {
this.updateCanvas();
}
if (prevProps.frame !== frameData.number
- && ((resetZoom && workspace !== Workspace.ATTRIBUTE_ANNOTATION) ||
- workspace === Workspace.TAG_ANNOTATION)
+ && ((resetZoom && workspace !== Workspace.ATTRIBUTE_ANNOTATION)
+ || workspace === Workspace.TAG_ANNOTATION)
) {
canvasInstance.html().addEventListener('canvas.setup', () => {
canvasInstance.fit();
@@ -636,6 +632,7 @@ export default class CanvasWrapperComponent extends React.PureComponent {
private updateCanvas(): void {
const {
+ curZLayer,
annotations,
frameData,
canvasInstance,
@@ -643,7 +640,7 @@ export default class CanvasWrapperComponent extends React.PureComponent {
if (frameData !== null) {
canvasInstance.setup(frameData, annotations
- .filter((e) => e.objectType !== ObjectType.TAG));
+ .filter((e) => e.objectType !== ObjectType.TAG), curZLayer);
}
}
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 aca9779e2db6..aba501b1a727 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
@@ -164,7 +164,7 @@ function ItemAttributeComponent(props: Props): JSX.Element {
onChange={(event: React.ChangeEvent): void => {
changeAttribute(attrID, event.target.value);
}}
- value={attrValue}
+ defaultValue={attrValue}
className='cvat-object-item-text-attribute'
/>
diff --git a/cvat-ui/src/containers/annotation-page/annotation-page.tsx b/cvat-ui/src/containers/annotation-page/annotation-page.tsx
index 1a3ed678f708..2b2d7752f7de 100644
--- a/cvat-ui/src/containers/annotation-page/annotation-page.tsx
+++ b/cvat-ui/src/containers/annotation-page/annotation-page.tsx
@@ -7,7 +7,7 @@ import { withRouter } from 'react-router-dom';
import { RouteComponentProps } from 'react-router';
import AnnotationPageComponent from 'components/annotation-page/annotation-page';
-import { getJobAsync, saveLogsAsync } from 'actions/annotation-actions';
+import { getJobAsync, saveLogsAsync, closeJob as closeJobAction } from 'actions/annotation-actions';
import { CombinedState, Workspace } from 'reducers/interfaces';
@@ -25,6 +25,7 @@ interface StateToProps {
interface DispatchToProps {
getJob(): void;
saveLogs(): void;
+ closeJob(): void;
}
function mapStateToProps(state: CombinedState, own: OwnProps): StateToProps {
@@ -83,6 +84,9 @@ function mapDispatchToProps(dispatch: any, own: OwnProps): DispatchToProps {
saveLogs(): void {
dispatch(saveLogsAsync());
},
+ closeJob(): void {
+ dispatch(closeJobAction());
+ },
};
}
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 83c70521d82a..389043b5b6c3 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
@@ -22,7 +22,6 @@ import {
searchAnnotationsAsync,
changeWorkspace as changeWorkspaceAction,
activateObject,
- closeJob as closeJobAction,
} from 'actions/annotation-actions';
import { Canvas } from 'cvat-canvas-wrapper';
@@ -59,7 +58,6 @@ interface DispatchToProps {
redo(sessionInstance: any, frameNumber: any): void;
searchAnnotations(sessionInstance: any, frameFrom: any, frameTo: any): void;
changeWorkspace(workspace: Workspace): void;
- closeJob(): void;
}
function mapStateToProps(state: CombinedState): StateToProps {
@@ -155,9 +153,6 @@ function mapDispatchToProps(dispatch: any): DispatchToProps {
dispatch(activateObject(null, null));
dispatch(changeWorkspaceAction(workspace));
},
- closeJob(): void {
- dispatch(closeJobAction());
- },
};
}
@@ -246,11 +241,9 @@ class AnnotationTopBarContainer extends React.PureComponent {
}
public componentWillUnmount(): void {
- const { closeJob } = this.props;
window.clearInterval(this.autoSaveInterval);
window.removeEventListener('beforeunload', this.beforeUnloadCallback);
this.unblock();
- closeJob();
}
private undo = (): void => {
diff --git a/cvat-ui/src/utils/redux.ts b/cvat-ui/src/utils/redux.ts
index 8627d2c34586..73a36430aade 100644
--- a/cvat-ui/src/utils/redux.ts
+++ b/cvat-ui/src/utils/redux.ts
@@ -20,7 +20,7 @@ export function createAction(
export type ActionUnion = ReturnType;
-export type ThunkAction
+export type ThunkAction
= _ThunkAction;
export type ThunkDispatch