From 85e9bb59f583029b8443edbde2bd80602ef3a864 Mon Sep 17 00:00:00 2001 From: Boris Sekachev Date: Tue, 7 Jul 2020 16:37:37 +0300 Subject: [PATCH 1/9] Fixed redux types --- cvat-ui/src/utils/redux.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cvat-ui/src/utils/redux.ts b/cvat-ui/src/utils/redux.ts index 8627d2c3458..73a36430aad 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 From 5e3466233e2bb45cb4a63160f557097ac33e2f95 Mon Sep 17 00:00:00 2001 From: Boris Sekachev Date: Tue, 7 Jul 2020 16:55:39 +0300 Subject: [PATCH 2/9] Redesigned approach to close job. Previous variant didn't work properly with GlobalErrorBoundary --- .../src/components/annotation-page/annotation-page.tsx | 8 ++++++++ .../src/containers/annotation-page/annotation-page.tsx | 6 +++++- .../src/containers/annotation-page/top-bar/top-bar.tsx | 7 ------- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/cvat-ui/src/components/annotation-page/annotation-page.tsx b/cvat-ui/src/components/annotation-page/annotation-page.tsx index 5f84511217f..8854dd5da89 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/containers/annotation-page/annotation-page.tsx b/cvat-ui/src/containers/annotation-page/annotation-page.tsx index 1a3ed678f70..2b2d7752f7d 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 83c70521d82..389043b5b6c 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 => { From 56aba565a8010dc910fb624d4a62944cd9ccbe74 Mon Sep 17 00:00:00 2001 From: Boris Sekachev Date: Thu, 9 Jul 2020 13:22:11 +0300 Subject: [PATCH 3/9] Fixed: cannot read property shapeType of undefined --- cvat-canvas/src/typescript/canvas.ts | 11 +++-------- cvat-canvas/src/typescript/canvasModel.ts | 13 ++++--------- cvat-canvas/src/typescript/canvasView.ts | 3 +-- .../standard-workspace/canvas-wrapper.tsx | 17 +++++++---------- 4 files changed, 15 insertions(+), 29 deletions(-) diff --git a/cvat-canvas/src/typescript/canvas.ts b/cvat-canvas/src/typescript/canvas.ts index e0db5e5a175..356997666f7 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 e2069efe27c..5926f621750 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 => { diff --git a/cvat-canvas/src/typescript/canvasView.ts b/cvat-canvas/src/typescript/canvasView.ts index e1da53d3376..6a99b7b0629 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-ui/src/components/annotation-page/standard-workspace/canvas-wrapper.tsx b/cvat-ui/src/components/annotation-page/standard-workspace/canvas-wrapper.tsx index 652338cf07d..b10cd3d6bfe 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); } } From 2928f5649311b76b3763bb3170569f36f6d35914 Mon Sep 17 00:00:00 2001 From: Boris Sekachev Date: Thu, 9 Jul 2020 13:30:12 +0300 Subject: [PATCH 4/9] Cannot read property 'pinned' of undefined --- cvat-canvas/src/typescript/canvasModel.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cvat-canvas/src/typescript/canvasModel.ts b/cvat-canvas/src/typescript/canvasModel.ts index 5926f621750..ec860e77bbe 100644 --- a/cvat-canvas/src/typescript/canvasModel.ts +++ b/cvat-canvas/src/typescript/canvasModel.ts @@ -383,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; } } From 5275402fce575f9b5728657d1312018ae3ce64b9 Mon Sep 17 00:00:00 2001 From: Boris Sekachev Date: Thu, 9 Jul 2020 13:33:25 +0300 Subject: [PATCH 5/9] Do not iterate invisible objects (zLayer) in aam --- .../attribute-annotation-sidebar.tsx | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) 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 85b186ee82e..71170227baf 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; From 16e66c07025748f30b44ae6f05d7f20436103da0 Mon Sep 17 00:00:00 2001 From: Boris Sekachev Date: Thu, 9 Jul 2020 13:45:56 +0300 Subject: [PATCH 6/9] Keep cursor on the same position when editing text --- .../objects-side-bar/object-item-attribute.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 aca9779e2db..aba501b1a72 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' /> From 4c151c994600aa70b8d25528aba9c13d8d03a2ac Mon Sep 17 00:00:00 2001 From: Boris Sekachev Date: Thu, 9 Jul 2020 13:57:57 +0300 Subject: [PATCH 7/9] Do not select hidden shapes when grouping --- cvat-canvas/src/typescript/groupHandler.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cvat-canvas/src/typescript/groupHandler.ts b/cvat-canvas/src/typescript/groupHandler.ts index 0c2475ef420..f92cdab6b3c 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(); From 1eedc3733ef6fd26674be9bb8cd94dad2dcc1161 Mon Sep 17 00:00:00 2001 From: Boris Sekachev Date: Thu, 9 Jul 2020 14:04:36 +0300 Subject: [PATCH 8/9] Updated version --- cvat-canvas/package-lock.json | 2 +- cvat-canvas/package.json | 2 +- cvat-ui/package-lock.json | 2 +- cvat-ui/package.json | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cvat-canvas/package-lock.json b/cvat-canvas/package-lock.json index c59ddb778db..f892c11a647 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 0a2dcbf9c2b..2044f33dea1 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-ui/package-lock.json b/cvat-ui/package-lock.json index ed0924cdfe7..2ca3283040c 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 0d4115f1b82..7bd9c91659f 100644 --- a/cvat-ui/package.json +++ b/cvat-ui/package.json @@ -1,11 +1,11 @@ { "name": "cvat-ui", - "version": "1.6.0", + "version": "1.6.1", "description": "CVAT single-page application", "main": "src/index.tsx", "scripts": { "build": "webpack --config ./webpack.config.js", - "start": "REACT_APP_API_URL=http://localhost:7000 webpack-dev-server --config ./webpack.config.js --mode=development", + "start": "REACT_APP_API_URL=http://192.168.0.12:7000 webpack-dev-server --config ./webpack.config.js --mode=development", "type-check": "tsc --noEmit", "type-check:watch": "npm run type-check -- --watch", "lint": "eslint './src/**/*.{ts,tsx}'", From f44e44d470b6ab61af3d5cdae8f5c77c9b3c95d1 Mon Sep 17 00:00:00 2001 From: Boris Sekachev Date: Thu, 9 Jul 2020 16:50:16 +0300 Subject: [PATCH 9/9] Fixed host --- CHANGELOG.md | 6 ++++++ cvat-ui/package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 09f651e5b89..b0d26e6e550 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 () ### Security - diff --git a/cvat-ui/package.json b/cvat-ui/package.json index 7bd9c91659f..c9b49488645 100644 --- a/cvat-ui/package.json +++ b/cvat-ui/package.json @@ -5,7 +5,7 @@ "main": "src/index.tsx", "scripts": { "build": "webpack --config ./webpack.config.js", - "start": "REACT_APP_API_URL=http://192.168.0.12:7000 webpack-dev-server --config ./webpack.config.js --mode=development", + "start": "REACT_APP_API_URL=http://localhost:7000 webpack-dev-server --config ./webpack.config.js --mode=development", "type-check": "tsc --noEmit", "type-check:watch": "npm run type-check -- --watch", "lint": "eslint './src/**/*.{ts,tsx}'",