CVAT UI: batch of fixes (#1705)

main
Dmitry Kalinin 6 years ago committed by GitHub
parent db24f93d66
commit 49a7ad59ed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Built-in search for labels when create an object or change a label (<https://github.com/opencv/cvat/pull/1683>) - Built-in search for labels when create an object or change a label (<https://github.com/opencv/cvat/pull/1683>)
- Better validation of labels and attributes in raw viewer (<https://github.com/opencv/cvat/pull/1727>) - Better validation of labels and attributes in raw viewer (<https://github.com/opencv/cvat/pull/1727>)
- ClamAV antivirus integration (<https://github.com/opencv/cvat/pull/1712>) - ClamAV antivirus integration (<https://github.com/opencv/cvat/pull/1712>)
- Added canvas background color selector (<https://github.com/opencv/cvat/pull/1705>)
- SCSS files linting with Stylelint tool (<https://github.com/opencv/cvat/pull/1766>) - SCSS files linting with Stylelint tool (<https://github.com/opencv/cvat/pull/1766>)
- Supported import and export or single boxes in MOT format (https://github.com/opencv/cvat/pull/1764) - Supported import and export or single boxes in MOT format (https://github.com/opencv/cvat/pull/1764)
- [Datumaro] Added `stats` command, which shows some dataset statistics like image mean and std (https://github.com/opencv/cvat/pull/1734) - [Datumaro] Added `stats` command, which shows some dataset statistics like image mean and std (https://github.com/opencv/cvat/pull/1734)
@ -28,6 +29,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed ### Changed
- Removed information about e-mail from the basic user information (<https://github.com/opencv/cvat/pull/1627>) - Removed information about e-mail from the basic user information (<https://github.com/opencv/cvat/pull/1627>)
- Update https install manual. Makes it easier and more robust. Includes automatic renewing of lets encrypt certificates. - Update https install manual. Makes it easier and more robust. Includes automatic renewing of lets encrypt certificates.
- Settings page move to the modal. (<https://github.com/opencv/cvat/pull/1705>)
- Implemented import and export of annotations with relative image paths (<https://github.com/opencv/cvat/pull/1463>) - Implemented import and export of annotations with relative image paths (<https://github.com/opencv/cvat/pull/1463>)
- Using only single click to start editing or remove a point (<https://github.com/opencv/cvat/pull/1571>) - Using only single click to start editing or remove a point (<https://github.com/opencv/cvat/pull/1571>)
@ -46,6 +48,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Wrong description on register view for the username field (<https://github.com/opencv/cvat/pull/1667>) - Wrong description on register view for the username field (<https://github.com/opencv/cvat/pull/1667>)
- Wrong resolution for resizing a shape (<https://github.com/opencv/cvat/pull/1667>) - Wrong resolution for resizing a shape (<https://github.com/opencv/cvat/pull/1667>)
- React warning because of not unique keys in labels viewer (<https://github.com/opencv/cvat/pull/1727>) - React warning because of not unique keys in labels viewer (<https://github.com/opencv/cvat/pull/1727>)
- Fixed issue tracker (<https://github.com/opencv/cvat/pull/1705>)
- Fixed canvas fit after sidebar open/close event (<https://github.com/opencv/cvat/pull/1705>)
- A couple of exceptions in AAM related with early object activation (<https://github.com/opencv/cvat/pull/1755>) - A couple of exceptions in AAM related with early object activation (<https://github.com/opencv/cvat/pull/1755>)
- Propagation from the latest frame (<https://github.com/opencv/cvat/pull/1800>) - Propagation from the latest frame (<https://github.com/opencv/cvat/pull/1800>)
- Number attribute value validation (didn't work well with floats) (<https://github.com/opencv/cvat/pull/1800>) - Number attribute value validation (didn't work well with floats) (<https://github.com/opencv/cvat/pull/1800>)

@ -1,6 +1,6 @@
{ {
"name": "cvat-canvas", "name": "cvat-canvas",
"version": "1.2.0", "version": "1.2.1",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {

@ -1,6 +1,6 @@
{ {
"name": "cvat-canvas", "name": "cvat-canvas",
"version": "1.2.0", "version": "1.2.1",
"description": "Part of Computer Vision Annotation Tool which presents its canvas library", "description": "Part of Computer Vision Annotation Tool which presents its canvas library",
"main": "src/canvas.ts", "main": "src/canvas.ts",
"scripts": { "scripts": {

@ -188,7 +188,7 @@ polyline.cvat_canvas_shape_splitting {
height: calc(100% - 10px); height: calc(100% - 10px);
margin: 5px; margin: 5px;
border-radius: 5px; border-radius: 5px;
background-color: white; background-color: inherit;
overflow: hidden; overflow: hidden;
position: relative; position: relative;
} }

@ -911,12 +911,32 @@ export class CanvasViewImpl implements CanvasView, Listener {
if (reason === UpdateReasons.CONFIG_UPDATED) { if (reason === UpdateReasons.CONFIG_UPDATED) {
const { activeElement } = this; const { activeElement } = this;
this.deactivate(); this.deactivate();
if (model.configuration.displayAllText && !this.configuration.displayAllText) {
for (const i in this.drawnStates) {
if (!(i in this.svgTexts)) {
this.svgTexts[i] = this.addText(this.drawnStates[i]);
this.updateTextPosition(
this.svgTexts[i],
this.svgShapes[i],
);
}
}
} else if (model.configuration.displayAllText === false
&& this.configuration.displayAllText) {
for (const i in this.drawnStates) {
if (i in this.svgTexts && Number.parseInt(i, 10) !== activeElement.clientID) {
this.svgTexts[i].remove();
delete this.svgTexts[i];
}
}
}
this.configuration = model.configuration; this.configuration = model.configuration;
this.activate(activeElement); this.activate(activeElement);
this.editHandler.configurate(this.configuration); this.editHandler.configurate(this.configuration);
this.drawHandler.configurate(this.configuration); this.drawHandler.configurate(this.configuration);
// todo: setup text, add if doesn't exist and enabled
// remove if exist and not enabled // remove if exist and not enabled
// this.setupObjects([]); // this.setupObjects([]);
// this.setupObjects(model.objects); // this.setupObjects(model.objects);
@ -1208,6 +1228,7 @@ export class CanvasViewImpl implements CanvasView, Listener {
pinned: state.pinned, pinned: state.pinned,
updated: state.updated, updated: state.updated,
frame: state.frame, frame: state.frame,
label: state.label,
}; };
} }

@ -48,6 +48,7 @@ export interface DrawnState {
pinned?: boolean; pinned?: boolean;
updated: number; updated: number;
frame: number; frame: number;
label: any;
} }
// Translate point array from the canvas coordinate system // Translate point array from the canvas coordinate system

@ -13,14 +13,19 @@
} }
}, },
"@ant-design/create-react-context": { "@ant-design/create-react-context": {
"version": "0.2.4", "version": "0.2.5",
"resolved": "https://registry.npmjs.org/@ant-design/create-react-context/-/create-react-context-0.2.4.tgz", "resolved": "https://registry.npmjs.org/@ant-design/create-react-context/-/create-react-context-0.2.5.tgz",
"integrity": "sha512-8sw+/w6r+aEbd+OJ62ojoSE4zDt/3yfQydmbWFznoftjr8v/opOswGjM+/MU0rSaREbluqzOmZ6xdecHpSaS2w==", "integrity": "sha512-1rMAa4qgP2lfl/QBH9i78+Gjxtj9FTMpMyDGZsEBW5Kih72EuUo9958mV8PgpRkh4uwPSQ7vVZWXeyNZXVAFDg==",
"requires": { "requires": {
"gud": "^1.0.0", "gud": "^1.0.0",
"warning": "^4.0.3" "warning": "^4.0.3"
} }
}, },
"@ant-design/css-animation": {
"version": "1.7.2",
"resolved": "https://registry.npmjs.org/@ant-design/css-animation/-/css-animation-1.7.2.tgz",
"integrity": "sha512-bvVOe7A+r7lws58B7r+fgnQDK90cV45AXuvGx6i5CCSX1W/M3AJnHsNggDANBxEtWdNdFWcDd5LorB+RdSIlBw=="
},
"@ant-design/icons": { "@ant-design/icons": {
"version": "2.1.1", "version": "2.1.1",
"resolved": "https://registry.npmjs.org/@ant-design/icons/-/icons-2.1.1.tgz", "resolved": "https://registry.npmjs.org/@ant-design/icons/-/icons-2.1.1.tgz",
@ -975,6 +980,11 @@
"integrity": "sha512-5a6wqoJV/xEdbRNKVo6I4hO3VjyDq//8q2f9I6PBAvMesJHFauXDorcNCsr9RzvsZnaWi5NYCcfyqP1QeFHFbw==", "integrity": "sha512-5a6wqoJV/xEdbRNKVo6I4hO3VjyDq//8q2f9I6PBAvMesJHFauXDorcNCsr9RzvsZnaWi5NYCcfyqP1QeFHFbw==",
"dev": true "dev": true
}, },
"@icons/material": {
"version": "0.2.4",
"resolved": "https://registry.npmjs.org/@icons/material/-/material-0.2.4.tgz",
"integrity": "sha512-QPcGmICAPbGLGb6F/yNf/KzKqvFx8z5qx3D1yFqVAjoFmXK35EgyW+cJ57Te3CNsmzblwtzakLGFqHPqrfb4Tw=="
},
"@types/eslint-visitor-keys": { "@types/eslint-visitor-keys": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", "resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz",
@ -1056,6 +1066,14 @@
"csstype": "^2.2.0" "csstype": "^2.2.0"
} }
}, },
"@types/react-color": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/@types/react-color/-/react-color-3.0.2.tgz",
"integrity": "sha512-FhrRy0xEYEpysl1iKL11ynJc79H6ztyYc4xD1pliZyygEChleTlHGohb/bClTYPN8XeSw6yaz45l3YW5SGYftQ==",
"requires": {
"@types/react": "*"
}
},
"@types/react-dom": { "@types/react-dom": {
"version": "16.9.3", "version": "16.9.3",
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-16.9.3.tgz", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-16.9.3.tgz",
@ -1506,9 +1524,9 @@
} }
}, },
"antd": { "antd": {
"version": "3.25.2", "version": "3.26.17",
"resolved": "https://registry.npmjs.org/antd/-/antd-3.25.2.tgz", "resolved": "https://registry.npmjs.org/antd/-/antd-3.26.17.tgz",
"integrity": "sha512-+qF1bgU7rUkPIkggIIV0fmm+9pPacl50BBd6NNUR2+kKJOFYjwrnP39ZqJRsYNy5bX9VgR454fz9KEuW7HPjog==", "integrity": "sha512-P9uSK8SZ/1AvhQCC6aaLEkVrQhjbfZyUnqNV+lDnPqtudnZD2Ycy7Og+/EhuOBsQpYQvVT2aPLMgQWFv8tdJkA==",
"requires": { "requires": {
"@ant-design/create-react-context": "^0.2.4", "@ant-design/create-react-context": "^0.2.4",
"@ant-design/icons": "~2.1.1", "@ant-design/icons": "~2.1.1",
@ -1521,18 +1539,19 @@
"css-animation": "^1.5.0", "css-animation": "^1.5.0",
"dom-closest": "^0.2.0", "dom-closest": "^0.2.0",
"enquire.js": "^2.1.6", "enquire.js": "^2.1.6",
"is-mobile": "^2.1.0",
"lodash": "^4.17.13", "lodash": "^4.17.13",
"moment": "^2.24.0", "moment": "^2.24.0",
"omit.js": "^1.0.2", "omit.js": "^1.0.2",
"prop-types": "^15.7.2", "prop-types": "^15.7.2",
"raf": "^3.4.1", "raf": "^3.4.1",
"rc-animate": "^2.10.2", "rc-animate": "^2.10.2",
"rc-calendar": "~9.15.5", "rc-calendar": "~9.15.7",
"rc-cascader": "~0.17.4", "rc-cascader": "~0.17.4",
"rc-checkbox": "~2.1.6", "rc-checkbox": "~2.1.6",
"rc-collapse": "~1.11.3", "rc-collapse": "~1.11.3",
"rc-dialog": "~7.5.2", "rc-dialog": "~7.6.0",
"rc-drawer": "~3.0.0", "rc-drawer": "~3.1.1",
"rc-dropdown": "~2.4.1", "rc-dropdown": "~2.4.1",
"rc-editor-mention": "^1.1.13", "rc-editor-mention": "^1.1.13",
"rc-form": "^2.4.10", "rc-form": "^2.4.10",
@ -1540,7 +1559,7 @@
"rc-mentions": "~0.4.0", "rc-mentions": "~0.4.0",
"rc-menu": "~7.5.1", "rc-menu": "~7.5.1",
"rc-notification": "~3.3.1", "rc-notification": "~3.3.1",
"rc-pagination": "~1.20.5", "rc-pagination": "~1.20.11",
"rc-progress": "~2.5.0", "rc-progress": "~2.5.0",
"rc-rate": "~2.5.0", "rc-rate": "~2.5.0",
"rc-resize-observer": "^0.1.0", "rc-resize-observer": "^0.1.0",
@ -1548,15 +1567,15 @@
"rc-slider": "~8.7.1", "rc-slider": "~8.7.1",
"rc-steps": "~3.5.0", "rc-steps": "~3.5.0",
"rc-switch": "~1.9.0", "rc-switch": "~1.9.0",
"rc-table": "~6.9.4", "rc-table": "~6.10.5",
"rc-tabs": "~9.6.4", "rc-tabs": "~9.7.0",
"rc-time-picker": "~3.7.1", "rc-time-picker": "~3.7.1",
"rc-tooltip": "~3.7.3", "rc-tooltip": "~3.7.3",
"rc-tree": "~2.1.0", "rc-tree": "~2.1.0",
"rc-tree-select": "~2.9.1", "rc-tree-select": "~2.9.1",
"rc-trigger": "^2.6.2", "rc-trigger": "^2.6.2",
"rc-upload": "~2.9.1", "rc-upload": "~2.9.1",
"rc-util": "^4.10.0", "rc-util": "^4.16.1",
"react-lazy-load": "^3.0.13", "react-lazy-load": "^3.0.13",
"react-lifecycles-compat": "^3.0.4", "react-lifecycles-compat": "^3.0.4",
"react-slick": "~0.25.2", "react-slick": "~0.25.2",
@ -21342,9 +21361,9 @@
} }
}, },
"dom-align": { "dom-align": {
"version": "1.10.2", "version": "1.12.0",
"resolved": "https://registry.npmjs.org/dom-align/-/dom-align-1.10.2.tgz", "resolved": "https://registry.npmjs.org/dom-align/-/dom-align-1.12.0.tgz",
"integrity": "sha512-AYZUzLepy05E9bCY4ExoqHrrIlM49PEak9oF93JEFoibqKL0F7w5DLM70/rosLOawerWZ3MlepQcl+EmHskOyw==" "integrity": "sha512-YkoezQuhp3SLFGdOlr5xkqZ640iXrnHAwVYcDg8ZKRUtO7mSzSC2BA5V0VuyAwPSJA4CLIc6EDDJh4bEsD2+zA=="
}, },
"dom-closest": { "dom-closest": {
"version": "0.2.0", "version": "0.2.0",
@ -24411,6 +24430,11 @@
"is-extglob": "^2.1.1" "is-extglob": "^2.1.1"
} }
}, },
"is-mobile": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/is-mobile/-/is-mobile-2.2.1.tgz",
"integrity": "sha512-6zELsfVFr326eq2CI53yvqq6YBanOxKBybwDT+MbMS2laBnK6Ez8m5XHSuTQQbnKRfpDzCod1CMWW5q3wZYMvA=="
},
"is-number": { "is-number": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
@ -24914,6 +24938,11 @@
"object-visit": "^1.0.0" "object-visit": "^1.0.0"
} }
}, },
"material-colors": {
"version": "1.2.6",
"resolved": "https://registry.npmjs.org/material-colors/-/material-colors-1.2.6.tgz",
"integrity": "sha512-6qE4B9deFBIa9YSpOc9O0Sgc43zTeVYbgDT5veRKSlB2+ZuHNoVVxA1L/ckMUayV9Ay9y7Z/SZCLcGteW9i7bg=="
},
"md5.js": { "md5.js": {
"version": "1.3.5", "version": "1.3.5",
"resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
@ -25312,9 +25341,9 @@
"dev": true "dev": true
}, },
"mutationobserver-shim": { "mutationobserver-shim": {
"version": "0.3.3", "version": "0.3.7",
"resolved": "https://registry.npmjs.org/mutationobserver-shim/-/mutationobserver-shim-0.3.3.tgz", "resolved": "https://registry.npmjs.org/mutationobserver-shim/-/mutationobserver-shim-0.3.7.tgz",
"integrity": "sha512-gciOLNN8Vsf7YzcqRjKzlAJ6y7e+B86u7i3KXes0xfxx/nfLmozlW1Vn+Sc9x3tPIePFgc1AeIFhtRgkqTjzDQ==" "integrity": "sha512-oRIDTyZQU96nAiz2AQyngwx1e89iApl2hN5AOYwyxLUB47UYsU3Wv9lJWqH5y/QdiYkc5HQLi23ZNB3fELdHcQ=="
}, },
"mute-stream": { "mute-stream": {
"version": "0.0.8", "version": "0.0.8",
@ -27022,9 +27051,9 @@
} }
}, },
"rc-animate": { "rc-animate": {
"version": "2.10.2", "version": "2.11.1",
"resolved": "https://registry.npmjs.org/rc-animate/-/rc-animate-2.10.2.tgz", "resolved": "https://registry.npmjs.org/rc-animate/-/rc-animate-2.11.1.tgz",
"integrity": "sha512-cE/A7piAzoWFSgUD69NmmMraqCeqVBa51UErod8NS3LUEqWfppSVagHfa0qHAlwPVPiIBg3emRONyny3eiH0Dg==", "integrity": "sha512-1NyuCGFJG/0Y+9RKh5y/i/AalUCA51opyyS/jO2seELpgymZm2u9QV3xwODwEuzkmeQ1BDPxMLmYLcTJedPlkQ==",
"requires": { "requires": {
"babel-runtime": "6.x", "babel-runtime": "6.x",
"classnames": "^2.2.6", "classnames": "^2.2.6",
@ -27036,9 +27065,9 @@
} }
}, },
"rc-calendar": { "rc-calendar": {
"version": "9.15.8", "version": "9.15.11",
"resolved": "https://registry.npmjs.org/rc-calendar/-/rc-calendar-9.15.8.tgz", "resolved": "https://registry.npmjs.org/rc-calendar/-/rc-calendar-9.15.11.tgz",
"integrity": "sha512-x3zVaZSRX7FkRNKw7nz3tutwrlIrU1aqMn5GtRUmlf84GnXLtd9fuuydxeNkFWfcHry3BPSto7+r9TK2al0h+g==", "integrity": "sha512-qv0VXfAAnysMWJigxaP6se4bJHvr17D9qsLbi8BOpdgEocsS0RkgY1IUiFaOVYKJDy/EyLC447O02sV/y5YYBg==",
"requires": { "requires": {
"babel-runtime": "6.x", "babel-runtime": "6.x",
"classnames": "2.x", "classnames": "2.x",
@ -27075,9 +27104,9 @@
} }
}, },
"rc-collapse": { "rc-collapse": {
"version": "1.11.7", "version": "1.11.8",
"resolved": "https://registry.npmjs.org/rc-collapse/-/rc-collapse-1.11.7.tgz", "resolved": "https://registry.npmjs.org/rc-collapse/-/rc-collapse-1.11.8.tgz",
"integrity": "sha512-ge3EEzIFtrDGuPX4bxXdQqwb91JnPIdj3B+FU88yNOUeOroNuA2q9kVK+UatpQ1Eft5hNo/ICTDrVFi8+685ng==", "integrity": "sha512-8EhfPyScTYljkbRuIoHniSwZagD5UPpZ3CToYgoNYWC85L2qCbPYF7+OaC713FOrIkp6NbfNqXsITNxmDAmxog==",
"requires": { "requires": {
"classnames": "2.x", "classnames": "2.x",
"css-animation": "1.x", "css-animation": "1.x",
@ -27089,23 +27118,22 @@
} }
}, },
"rc-dialog": { "rc-dialog": {
"version": "7.5.13", "version": "7.6.1",
"resolved": "https://registry.npmjs.org/rc-dialog/-/rc-dialog-7.5.13.tgz", "resolved": "https://registry.npmjs.org/rc-dialog/-/rc-dialog-7.6.1.tgz",
"integrity": "sha512-tmubIipW/qoCmRlHHV8tpepDaFhuhk+SeSFSyRhNKW4mYgflsEYQmYWilyCJHy6UzKl84bSyFvJskhc1z1Hniw==", "integrity": "sha512-KUKf+2eZ4YL+lnXMG3hR4ZtIhC9glfH27NtTVz3gcoDIPAf3uUvaXVRNoDCiSi+OGKLyIb/b6EoidFh6nQC5Wg==",
"requires": { "requires": {
"babel-runtime": "6.x", "babel-runtime": "6.x",
"rc-animate": "2.x", "rc-animate": "2.x",
"rc-util": "^4.8.1" "rc-util": "^4.16.1"
} }
}, },
"rc-drawer": { "rc-drawer": {
"version": "3.0.2", "version": "3.1.3",
"resolved": "https://registry.npmjs.org/rc-drawer/-/rc-drawer-3.0.2.tgz", "resolved": "https://registry.npmjs.org/rc-drawer/-/rc-drawer-3.1.3.tgz",
"integrity": "sha512-oPScGXB/8/ov9gEFLxPH8RBv/9jLTZboZtyF/GgrrnCAvbFwUxXdELH6n6XIowmuDKKvTGIMgZdnao0T46Yv3A==", "integrity": "sha512-2z+RdxmzXyZde/1OhVMfDR1e/GBswFeWSZ7FS3Fdd0qhgVdpV1wSzILzzxRaT481ItB5hOV+e8pZT07vdJE8kg==",
"requires": { "requires": {
"babel-runtime": "^6.26.0",
"classnames": "^2.2.6", "classnames": "^2.2.6",
"rc-util": "^4.11.2", "rc-util": "^4.16.1",
"react-lifecycles-compat": "^3.0.4" "react-lifecycles-compat": "^3.0.4"
} }
}, },
@ -27151,9 +27179,9 @@
} }
}, },
"rc-form": { "rc-form": {
"version": "2.4.10", "version": "2.4.11",
"resolved": "https://registry.npmjs.org/rc-form/-/rc-form-2.4.10.tgz", "resolved": "https://registry.npmjs.org/rc-form/-/rc-form-2.4.11.tgz",
"integrity": "sha512-h6a5Nvn6fMe3BfLpIWwL2RUkfXs1tvtifblTgGgH0UfzGgiQ5M12jiMJaAXek7TDDBUw90/c5vlZ6wFZjW0IgQ==", "integrity": "sha512-8BL+FNlFLTOY/A5X6tU35GQJLSIpsmqpwn/tFAYQTczXc4dMJ33ggtH248Cum8+LS0jLTsJKG2L4Qp+1CkY+sA==",
"requires": { "requires": {
"async-validator": "~1.11.3", "async-validator": "~1.11.3",
"babel-runtime": "6.x", "babel-runtime": "6.x",
@ -27166,9 +27194,9 @@
} }
}, },
"rc-hammerjs": { "rc-hammerjs": {
"version": "0.6.9", "version": "0.6.10",
"resolved": "https://registry.npmjs.org/rc-hammerjs/-/rc-hammerjs-0.6.9.tgz", "resolved": "https://registry.npmjs.org/rc-hammerjs/-/rc-hammerjs-0.6.10.tgz",
"integrity": "sha512-4llgWO3RgLyVbEqUdGsDfzUDqklRlQW5VEhE3x35IvhV+w//VPRG34SBavK3D2mD/UaLKaohgU41V4agiftC8g==", "integrity": "sha512-Vgh9qIudyN5CHRop4M+v+xUniQBFWXKrsJxQRVtJOi2xgRrCeI52/bkpaL5HWwUhqTK9Ayq0n7lYTItT6ld5rg==",
"requires": { "requires": {
"babel-runtime": "6.x", "babel-runtime": "6.x",
"hammerjs": "^2.0.8", "hammerjs": "^2.0.8",
@ -27176,9 +27204,9 @@
} }
}, },
"rc-input-number": { "rc-input-number": {
"version": "4.5.1", "version": "4.5.7",
"resolved": "https://registry.npmjs.org/rc-input-number/-/rc-input-number-4.5.1.tgz", "resolved": "https://registry.npmjs.org/rc-input-number/-/rc-input-number-4.5.7.tgz",
"integrity": "sha512-grO7/Lau7iv3NyHVyCajE1LuGLqGkG1tEAAZSwm9M0esYfrwXVSip4qhb5sF+8g6ACsiI20sOVLIihXuhSoifA==", "integrity": "sha512-99PrQ90sTOKyyj7eu0VzwxY17xQ+bwG1XTQd+bTwFQ+IOUkIw7L4qSAYxt58sVYL+Cw+bu/RAtT2IpT9yC2pCQ==",
"requires": { "requires": {
"babel-runtime": "6.x", "babel-runtime": "6.x",
"classnames": "^2.2.0", "classnames": "^2.2.0",
@ -27188,9 +27216,9 @@
} }
}, },
"rc-mentions": { "rc-mentions": {
"version": "0.4.1", "version": "0.4.2",
"resolved": "https://registry.npmjs.org/rc-mentions/-/rc-mentions-0.4.1.tgz", "resolved": "https://registry.npmjs.org/rc-mentions/-/rc-mentions-0.4.2.tgz",
"integrity": "sha512-XSJp6kcEPydUaM0I/gnxpXggiKgA5FjgFPKZCMQBDQJYUjXpQNyg5ogNkOJt1/4B2P7pwbYPZXgxP/30yZVahA==", "integrity": "sha512-DTZurQzacLXOfVuiHydGzqkq7cFMHXF18l2jZ9PhWUn2cqvOSY3W4osN0Pq29AOMOBpcxdZCzgc7Lb0r/bgkDw==",
"requires": { "requires": {
"@ant-design/create-react-context": "^0.2.4", "@ant-design/create-react-context": "^0.2.4",
"classnames": "^2.2.6", "classnames": "^2.2.6",
@ -27201,9 +27229,9 @@
} }
}, },
"rc-menu": { "rc-menu": {
"version": "7.5.3", "version": "7.5.5",
"resolved": "https://registry.npmjs.org/rc-menu/-/rc-menu-7.5.3.tgz", "resolved": "https://registry.npmjs.org/rc-menu/-/rc-menu-7.5.5.tgz",
"integrity": "sha512-H/jUyGbJxZI/iuVdC6Iu9KHfz7tucoqK0Vn8ahDnv+ppc1PnKb4SkBbXn5LrmUyaj7thCBiaktBxVnUXSmNE2g==", "integrity": "sha512-4YJXJgrpUGEA1rMftXN7bDhrV5rPB8oBJoHqT+GVXtIWCanfQxEnM3fmhHQhatL59JoAFMZhJaNzhJIk4FUWCQ==",
"requires": { "requires": {
"classnames": "2.x", "classnames": "2.x",
"dom-scroll-into-view": "1.x", "dom-scroll-into-view": "1.x",
@ -27229,9 +27257,9 @@
} }
}, },
"rc-pagination": { "rc-pagination": {
"version": "1.20.11", "version": "1.20.15",
"resolved": "https://registry.npmjs.org/rc-pagination/-/rc-pagination-1.20.11.tgz", "resolved": "https://registry.npmjs.org/rc-pagination/-/rc-pagination-1.20.15.tgz",
"integrity": "sha512-2wKO5kO+ELx1/zlqTY8TwGBruzofi+1BcZ7Z4xalMlLbDMTuUU4FDljbBBP/n9D2llK+NtgWA619PMBhInozZw==", "integrity": "sha512-/Xr4/3GOa1DtL8iCYl7qRUroEMrRDhZiiuHwcVFfSiwa9LYloMlUWcOJsnr8LN6A7rLPdm3/CHStUNeYd+2pKw==",
"requires": { "requires": {
"babel-runtime": "6.x", "babel-runtime": "6.x",
"classnames": "^2.2.6", "classnames": "^2.2.6",
@ -27240,18 +27268,18 @@
} }
}, },
"rc-progress": { "rc-progress": {
"version": "2.5.2", "version": "2.5.3",
"resolved": "https://registry.npmjs.org/rc-progress/-/rc-progress-2.5.2.tgz", "resolved": "https://registry.npmjs.org/rc-progress/-/rc-progress-2.5.3.tgz",
"integrity": "sha512-ajI+MJkbBz9zYDuE9GQsY5gsyqPF7HFioZEDZ9Fmc+ebNZoiSeSJsTJImPFCg0dW/5WiRGUy2F69SX1aPtSJgA==", "integrity": "sha512-K2fa4CnqGehLZoMrdmBeZ86ONSTVcdk5FlqetbwJ3R/+42XfqhwQVOjWp2MH4P7XSQOMAGcNOy1SFfCP3415sg==",
"requires": { "requires": {
"babel-runtime": "6.x", "babel-runtime": "6.x",
"prop-types": "^15.5.8" "prop-types": "^15.5.8"
} }
}, },
"rc-rate": { "rc-rate": {
"version": "2.5.0", "version": "2.5.1",
"resolved": "https://registry.npmjs.org/rc-rate/-/rc-rate-2.5.0.tgz", "resolved": "https://registry.npmjs.org/rc-rate/-/rc-rate-2.5.1.tgz",
"integrity": "sha512-aXX5klRqbVZxvLghcKnLqqo7LvLVCHswEDteWsm5Gb7NBIPa1YKTcAbvb5SZ4Z4i4EeRoZaPwygRAWsQgGtbKw==", "integrity": "sha512-3iJkNJT8xlHklPCdeZtUZmJmRVUbr6AHRlfSsztfYTXVlHrv2TcPn3XkHsH+12j812WVB7gvilS2j3+ffjUHXg==",
"requires": { "requires": {
"classnames": "^2.2.5", "classnames": "^2.2.5",
"prop-types": "^15.5.8", "prop-types": "^15.5.8",
@ -27270,9 +27298,9 @@
} }
}, },
"rc-select": { "rc-select": {
"version": "9.2.1", "version": "9.2.3",
"resolved": "https://registry.npmjs.org/rc-select/-/rc-select-9.2.1.tgz", "resolved": "https://registry.npmjs.org/rc-select/-/rc-select-9.2.3.tgz",
"integrity": "sha512-nW/Zr2OCgxN26OX8ff3xcO1wK0e1l5ixnEfyN15Rbdk7TNI/rIPJIjPCQAoihRpk9A2C/GH8pahjlvKV1Vj++g==", "integrity": "sha512-WhswxOMWiNnkXRbxyrj0kiIvyCfo/BaRPaYbsDetSIAU2yEDwKHF798blCP5u86KLOBKBvtxWLFCkSsQw1so5w==",
"requires": { "requires": {
"babel-runtime": "^6.23.0", "babel-runtime": "^6.23.0",
"classnames": "2.x", "classnames": "2.x",
@ -27325,9 +27353,9 @@
} }
}, },
"rc-table": { "rc-table": {
"version": "6.9.5", "version": "6.10.15",
"resolved": "https://registry.npmjs.org/rc-table/-/rc-table-6.9.5.tgz", "resolved": "https://registry.npmjs.org/rc-table/-/rc-table-6.10.15.tgz",
"integrity": "sha512-STL6387A/izVh6r9F1WDiIIZ0QeubCdTgIlzMeGTSl/bXhB0VqjAZEikvoijPoauTjJIkIzVuQEIDjOhAWbpkQ==", "integrity": "sha512-LAr0M/gqt+irOjvPNBLApmQ0CUHNOfKsEBhu1uIuB3OlN1ynA9z+sdoTQyNd9+8NSl0MYnQOOfhtLChAY7nU0A==",
"requires": { "requires": {
"classnames": "^2.2.5", "classnames": "^2.2.5",
"component-classes": "^1.2.6", "component-classes": "^1.2.6",
@ -27340,9 +27368,9 @@
} }
}, },
"rc-tabs": { "rc-tabs": {
"version": "9.6.7", "version": "9.7.0",
"resolved": "https://registry.npmjs.org/rc-tabs/-/rc-tabs-9.6.7.tgz", "resolved": "https://registry.npmjs.org/rc-tabs/-/rc-tabs-9.7.0.tgz",
"integrity": "sha512-OXbDOgaqv2MGK9QaDi6cdva6bNz3XGw+M9BHQpm1gTGmVQEGx5VcclDClH/3xobIzooxy8hrxg/s0rTlgDnC2w==", "integrity": "sha512-kvmgp8/MfLzFZ06hWHignqomFQ5nF7BqKr5O1FfhE4VKsGrep52YSF/1MvS5oe0NPcI9XGNS2p751C5v6cYDpQ==",
"requires": { "requires": {
"@ant-design/create-react-context": "^0.2.4", "@ant-design/create-react-context": "^0.2.4",
"babel-runtime": "6.x", "babel-runtime": "6.x",
@ -27358,9 +27386,9 @@
} }
}, },
"rc-time-picker": { "rc-time-picker": {
"version": "3.7.2", "version": "3.7.3",
"resolved": "https://registry.npmjs.org/rc-time-picker/-/rc-time-picker-3.7.2.tgz", "resolved": "https://registry.npmjs.org/rc-time-picker/-/rc-time-picker-3.7.3.tgz",
"integrity": "sha512-UVWO9HXGyZoM4I2THlJsEAFcZQz+tYwdcpoHXCEFZsRLz9L2+7vV4EMp9Wa3UrtzMFEt83qSAX/90dCJeKl9sg==", "integrity": "sha512-Lv1Mvzp9fRXhXEnRLO4nW6GLNxUkfAZ3RsiIBsWjGjXXvMNjdr4BX/ayElHAFK0DoJqOhm7c5tjmIYpEOwcUXg==",
"requires": { "requires": {
"classnames": "2.x", "classnames": "2.x",
"moment": "2.x", "moment": "2.x",
@ -27381,9 +27409,9 @@
} }
}, },
"rc-tree": { "rc-tree": {
"version": "2.1.3", "version": "2.1.4",
"resolved": "https://registry.npmjs.org/rc-tree/-/rc-tree-2.1.3.tgz", "resolved": "https://registry.npmjs.org/rc-tree/-/rc-tree-2.1.4.tgz",
"integrity": "sha512-COvV65spQ6omrHBUhHRKqKNL5+ddXjlS+qWZchaL9FFuQNvjM5pjp9RnmMWK4fJJ5kBhhpLneh6wh9Vh3kSMXQ==", "integrity": "sha512-Xey794Iavgs8YldFlXcZLOhfcIhlX5Oz/yfKufknBXf2AlZCOkc7aHqSM9uTF7fBPtTGPhPxNEfOqHfY7b7xng==",
"requires": { "requires": {
"@ant-design/create-react-context": "^0.2.4", "@ant-design/create-react-context": "^0.2.4",
"classnames": "2.x", "classnames": "2.x",
@ -27395,51 +27423,27 @@
} }
}, },
"rc-tree-select": { "rc-tree-select": {
"version": "2.9.1", "version": "2.9.4",
"resolved": "https://registry.npmjs.org/rc-tree-select/-/rc-tree-select-2.9.1.tgz", "resolved": "https://registry.npmjs.org/rc-tree-select/-/rc-tree-select-2.9.4.tgz",
"integrity": "sha512-AfJQC1ZzaeH+Onmx84TtVLUL2guBZe7exA8XSfj1RRB1doDbYGTtybzpP3CEw/tuSftSRnz+iPt+iaxRTrgXRw==", "integrity": "sha512-0HQkXAN4XbfBW20CZYh3G+V+VMrjX42XRtDCpyv6PDUm5vikC0Ob682ZBCVS97Ww2a5Hf6Ajmu0ahWEdIEpwhg==",
"requires": { "requires": {
"classnames": "^2.2.1", "classnames": "^2.2.1",
"dom-scroll-into-view": "^1.2.1", "dom-scroll-into-view": "^1.2.1",
"prop-types": "^15.5.8", "prop-types": "^15.5.8",
"raf": "^3.4.0", "raf": "^3.4.0",
"rc-animate": "^2.8.2", "rc-animate": "^2.8.2",
"rc-tree": "~2.0.0", "rc-tree": "~2.1.0",
"rc-trigger": "^3.0.0-rc.2", "rc-trigger": "^3.0.0",
"rc-util": "^4.5.0", "rc-util": "^4.5.0",
"react-lifecycles-compat": "^3.0.4", "react-lifecycles-compat": "^3.0.4",
"shallowequal": "^1.0.2", "shallowequal": "^1.0.2",
"warning": "^4.0.1" "warning": "^4.0.1"
}, },
"dependencies": { "dependencies": {
"rc-tree": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/rc-tree/-/rc-tree-2.0.0.tgz",
"integrity": "sha512-DAT/jsbnFbHqG9Df9OaVG93CAVtTsJVnJiwKX+wqsG8TChpty3s6QX3zJZ+gBgjkq4ikLbu1kuFJtX63EKhSAA==",
"requires": {
"babel-runtime": "^6.23.0",
"classnames": "2.x",
"prop-types": "^15.5.8",
"rc-animate": "^2.6.0",
"rc-util": "^4.5.1",
"react-lifecycles-compat": "^3.0.4",
"warning": "^3.0.0"
},
"dependencies": {
"warning": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/warning/-/warning-3.0.0.tgz",
"integrity": "sha1-MuU3fLVy3kqwR1O9+IIcAe1gW3w=",
"requires": {
"loose-envify": "^1.0.0"
}
}
}
},
"rc-trigger": { "rc-trigger": {
"version": "3.0.0-rc.3", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/rc-trigger/-/rc-trigger-3.0.0-rc.3.tgz", "resolved": "https://registry.npmjs.org/rc-trigger/-/rc-trigger-3.0.0.tgz",
"integrity": "sha512-4vB6cpxcUdm2qO5VtB9q1TZz0MoWm9BzFLvGknulphGrl1qI6uxUsPDCvqnmujdpDdAKGGfjxntFpA7RtAwkFQ==", "integrity": "sha512-hQxbbJpo23E2QnYczfq3Ec5J5tVl2mUDhkqxrEsQAqk16HfADQg+iKNWzEYXyERSncdxfnzYuaBgy764mNRzTA==",
"requires": { "requires": {
"babel-runtime": "6.x", "babel-runtime": "6.x",
"classnames": "^2.2.6", "classnames": "^2.2.6",
@ -27447,25 +27451,37 @@
"raf": "^3.4.0", "raf": "^3.4.0",
"rc-align": "^2.4.1", "rc-align": "^2.4.1",
"rc-animate": "^3.0.0-rc.1", "rc-animate": "^3.0.0-rc.1",
"rc-util": "^4.4.0" "rc-util": "^4.15.7"
}, },
"dependencies": { "dependencies": {
"rc-animate": { "rc-animate": {
"version": "3.0.0-rc.6", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/rc-animate/-/rc-animate-3.0.0-rc.6.tgz", "resolved": "https://registry.npmjs.org/rc-animate/-/rc-animate-3.1.0.tgz",
"integrity": "sha512-oBLPpiT6Q4t6YvD/pkLcmofBP1p01TX0Otse8Q4+Mxt8J+VSDflLZGIgf62EwkvRwsQUkLPjZVFBsldnPKLzjg==", "integrity": "sha512-8FsM+3B1H+0AyTyGggY6JyVldHTs1CyYT8CfTmG/nGHHXlecvSLeICJhcKgRLjUiQlctNnRtB1rwz79cvBVmrw==",
"requires": { "requires": {
"babel-runtime": "6.x", "@ant-design/css-animation": "^1.7.2",
"classnames": "^2.2.5", "classnames": "^2.2.6",
"component-classes": "^1.2.6",
"fbjs": "^0.8.16",
"prop-types": "15.x",
"raf": "^3.4.0", "raf": "^3.4.0",
"rc-util": "^4.5.0", "rc-util": "^5.0.1"
"react-lifecycles-compat": "^3.0.4" },
"dependencies": {
"rc-util": {
"version": "5.0.4",
"resolved": "https://registry.npmjs.org/rc-util/-/rc-util-5.0.4.tgz",
"integrity": "sha512-cd19RCrE0DJH6UcJ9+V3eaXA/5sNWyVKOKkWl8ZM2OqgNzVb8fv0obf/TkuvSN43tmTsgqY8k7OqpFYHhmef8g==",
"requires": {
"react-is": "^16.12.0",
"shallowequal": "^1.1.0"
}
}
} }
} }
} }
},
"react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
} }
} }
}, },
@ -27484,9 +27500,9 @@
} }
}, },
"rc-upload": { "rc-upload": {
"version": "2.9.2", "version": "2.9.4",
"resolved": "https://registry.npmjs.org/rc-upload/-/rc-upload-2.9.2.tgz", "resolved": "https://registry.npmjs.org/rc-upload/-/rc-upload-2.9.4.tgz",
"integrity": "sha512-USjuWpTRJl3my32G5woysTaGrAld+S4dvvZ9kW6RX/RkekfmLDjvWc5ho8Mj/+6B6/tDRJnyGyvMxMQNkW7cvw==", "integrity": "sha512-WXt0HGxXyzLrPV6iec/96Rbl/6dyrAW8pKuY6wwD7yFYwfU5bjgKjv7vC8KNMJ6wzitFrZjnoiogNL3dF9dj3Q==",
"requires": { "requires": {
"babel-runtime": "6.x", "babel-runtime": "6.x",
"classnames": "^2.2.5", "classnames": "^2.2.5",
@ -27495,15 +27511,22 @@
} }
}, },
"rc-util": { "rc-util": {
"version": "4.15.6", "version": "4.21.1",
"resolved": "https://registry.npmjs.org/rc-util/-/rc-util-4.15.6.tgz", "resolved": "https://registry.npmjs.org/rc-util/-/rc-util-4.21.1.tgz",
"integrity": "sha512-W6HB1gIn+xZLxmQfLkhMnAtaZY9RktcOH2I0Tbam4D4ZDFrkO33f3M7IolN0EPtLMpf4Mv/dEQNclY77/PtBpg==", "integrity": "sha512-Z+vlkSQVc1l8O2UjR3WQ+XdWlhj5q9BMQNLk2iOBch75CqPfrJyGtcWMcnhRlNuDu0Ndtt4kLVO8JI8BrABobg==",
"requires": { "requires": {
"add-dom-event-listener": "^1.1.0", "add-dom-event-listener": "^1.1.0",
"babel-runtime": "6.x",
"prop-types": "^15.5.10", "prop-types": "^15.5.10",
"react-is": "^16.12.0",
"react-lifecycles-compat": "^3.0.4", "react-lifecycles-compat": "^3.0.4",
"shallowequal": "^1.1.0" "shallowequal": "^1.1.0"
},
"dependencies": {
"react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
}
} }
}, },
"react": { "react": {
@ -27516,6 +27539,19 @@
"prop-types": "^15.6.2" "prop-types": "^15.6.2"
} }
}, },
"react-color": {
"version": "2.18.1",
"resolved": "https://registry.npmjs.org/react-color/-/react-color-2.18.1.tgz",
"integrity": "sha512-X5XpyJS6ncplZs74ak0JJoqPi+33Nzpv5RYWWxn17bslih+X7OlgmfpmGC1fNvdkK7/SGWYf1JJdn7D2n5gSuQ==",
"requires": {
"@icons/material": "^0.2.4",
"lodash": "^4.17.11",
"material-colors": "^1.2.1",
"prop-types": "^15.5.10",
"reactcss": "^1.2.0",
"tinycolor2": "^1.4.1"
}
},
"react-dom": { "react-dom": {
"version": "16.11.0", "version": "16.11.0",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.11.0.tgz", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.11.0.tgz",
@ -27648,6 +27684,14 @@
"react-svg-core": "^3.0.3" "react-svg-core": "^3.0.3"
} }
}, },
"reactcss": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/reactcss/-/reactcss-1.2.3.tgz",
"integrity": "sha512-KiwVUcFu1RErkI97ywr8nvx8dNOpT03rbnma0SSalTYjkrPYaEajR4a/MRt6DZ46K6arDRbWMNHF+xH7G7n/8A==",
"requires": {
"lodash": "^4.0.1"
}
},
"read-pkg": { "read-pkg": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz",
@ -28642,9 +28686,9 @@
} }
}, },
"shallow-equal": { "shallow-equal": {
"version": "1.2.0", "version": "1.2.1",
"resolved": "https://registry.npmjs.org/shallow-equal/-/shallow-equal-1.2.0.tgz", "resolved": "https://registry.npmjs.org/shallow-equal/-/shallow-equal-1.2.1.tgz",
"integrity": "sha512-Z21pVxR4cXsfwpMKMhCEIO1PCi5sp7KEp+CmOpBQ+E8GpHwKOw2sEzk7sgblM3d/j4z4gakoWEoPcjK0VJQogA==" "integrity": "sha512-S4vJDjHHMBaiZuT9NPb616CSmLf618jawtv3sufLl6ivK8WocjAo58cXwbRV1cgqxH0Qbv+iUt6m05eqEa2IRA=="
}, },
"shallowequal": { "shallowequal": {
"version": "1.1.0", "version": "1.1.0",

@ -47,22 +47,24 @@
"worker-loader": "^2.0.0" "worker-loader": "^2.0.0"
}, },
"dependencies": { "dependencies": {
"cvat-core": "file:../cvat-core",
"cvat-canvas": "file:../cvat-canvas",
"@types/react": "^16.9.2", "@types/react": "^16.9.2",
"@types/react-color": "^3.0.2",
"@types/react-dom": "^16.9.0", "@types/react-dom": "^16.9.0",
"@types/react-redux": "^7.1.2", "@types/react-redux": "^7.1.2",
"@types/react-router": "^5.0.5", "@types/react-router": "^5.0.5",
"@types/react-router-dom": "^5.1.0", "@types/react-router-dom": "^5.1.0",
"@types/react-share": "^3.0.1", "@types/react-share": "^3.0.1",
"@types/redux-logger": "^3.0.7", "@types/redux-logger": "^3.0.7",
"antd": "^3.25.2", "antd": "^3.26.17",
"copy-to-clipboard": "^3.2.0", "copy-to-clipboard": "^3.2.0",
"cvat-canvas": "file:../cvat-canvas",
"cvat-core": "file:../cvat-core",
"dotenv-webpack": "^1.7.0", "dotenv-webpack": "^1.7.0",
"error-stack-parser": "^2.0.6", "error-stack-parser": "^2.0.6",
"moment": "^2.24.0", "moment": "^2.24.0",
"prop-types": "^15.7.2", "prop-types": "^15.7.2",
"react": "^16.9.0", "react": "^16.9.0",
"react-color": "^2.18.1",
"react-dom": "^16.9.0", "react-dom": "^16.9.0",
"react-hotkeys": "^2.0.0", "react-hotkeys": "^2.0.0",
"react-redux": "^7.1.1", "react-redux": "^7.1.1",

@ -52,7 +52,8 @@ export const registerAsync = (
dispatch(authActions.register()); dispatch(authActions.register());
try { try {
await cvat.server.register(username, firstName, lastName, email, password1, password2, confirmations); await cvat.server.register(username, firstName, lastName, email, password1, password2,
confirmations);
const users = await cvat.users.get({ self: true }); const users = await cvat.users.get({ self: true });
dispatch(authActions.registerSuccess(users[0])); dispatch(authActions.registerSuccess(users[0]));

@ -32,6 +32,8 @@ export enum SettingsActionTypes {
SWITCH_AUTOMATIC_BORDERING = 'SWITCH_AUTOMATIC_BORDERING', SWITCH_AUTOMATIC_BORDERING = 'SWITCH_AUTOMATIC_BORDERING',
SWITCH_SHOWNIG_INTERPOLATED_TRACKS = 'SWITCH_SHOWNIG_INTERPOLATED_TRACKS', SWITCH_SHOWNIG_INTERPOLATED_TRACKS = 'SWITCH_SHOWNIG_INTERPOLATED_TRACKS',
SWITCH_SHOWING_OBJECTS_TEXT_ALWAYS = 'SWITCH_SHOWING_OBJECTS_TEXT_ALWAYS', SWITCH_SHOWING_OBJECTS_TEXT_ALWAYS = 'SWITCH_SHOWING_OBJECTS_TEXT_ALWAYS',
CHANGE_CANVAS_BACKGROUND_COLOR = 'CHANGE_CANVAS_BACKGROUND_COLOR',
SWITCH_SETTINGS_DIALOG = 'SWITCH_SETTINGS_DIALOG',
} }
export function changeShapesOpacity(opacity: number): AnyAction { export function changeShapesOpacity(opacity: number): AnyAction {
@ -240,3 +242,21 @@ export function switchAutomaticBordering(automaticBordering: boolean): AnyAction
}, },
}; };
} }
export function changeCanvasBackgroundColor(color: string): AnyAction {
return {
type: SettingsActionTypes.CHANGE_CANVAS_BACKGROUND_COLOR,
payload: {
color,
},
};
}
export function switchSettingsDialog(show?: boolean): AnyAction {
return {
type: SettingsActionTypes.SWITCH_SETTINGS_DIALOG,
payload: {
show,
},
};
}

@ -4,7 +4,7 @@
import { ActionUnion, createAction, ThunkAction } from 'utils/redux'; import { ActionUnion, createAction, ThunkAction } from 'utils/redux';
import getCore from 'cvat-core-wrapper'; import getCore from 'cvat-core-wrapper';
import { UserAgreement } from 'reducers/interfaces' import { UserAgreement } from 'reducers/interfaces';
const core = getCore(); const core = getCore();
@ -16,10 +16,12 @@ export enum UserAgreementsActionTypes {
const userAgreementsActions = { const userAgreementsActions = {
getUserAgreements: () => createAction(UserAgreementsActionTypes.GET_USER_AGREEMENTS), getUserAgreements: () => createAction(UserAgreementsActionTypes.GET_USER_AGREEMENTS),
getUserAgreementsSuccess: (userAgreements: UserAgreement[]) => getUserAgreementsSuccess: (userAgreements: UserAgreement[]) => (
createAction(UserAgreementsActionTypes.GET_USER_AGREEMENTS_SUCCESS, userAgreements), createAction(UserAgreementsActionTypes.GET_USER_AGREEMENTS_SUCCESS, userAgreements)
getUserAgreementsFailed: (error: any) => ),
createAction(UserAgreementsActionTypes.GET_USER_AGREEMENTS_FAILED, { error }), getUserAgreementsFailed: (error: any) => (
createAction(UserAgreementsActionTypes.GET_USER_AGREEMENTS_FAILED, { error })
),
}; };
export type UserAgreementsActions = ActionUnion<typeof userAgreementsActions>; export type UserAgreementsActions = ActionUnion<typeof userAgreementsActions>;

@ -32,23 +32,22 @@ export default function DumpSubmenu(props: Props): JSX.Element {
{ {
dumpers dumpers
.sort((a: any, b: any) => a.name.localeCompare(b.name)) .sort((a: any, b: any) => a.name.localeCompare(b.name))
.map((dumper: any): JSX.Element => .map((dumper: any): JSX.Element => {
{ const pending = (dumpActivities || []).includes(dumper.name);
const pending = (dumpActivities || []).includes(dumper.name); const disabled = !dumper.enabled || pending;
const disabled = !dumper.enabled || pending; const isDefault = isDefaultFormat(dumper.name, taskMode);
const isDefault = isDefaultFormat(dumper.name, taskMode); return (
return ( <Menu.Item
<Menu.Item key={dumper.name}
key={dumper.name} disabled={disabled}
disabled={disabled} className='cvat-menu-dump-submenu-item'
className='cvat-menu-dump-submenu-item' >
> <Icon type='download' />
<Icon type='download' /> <Text strong={isDefault} disabled={disabled}>{dumper.name}</Text>
<Text strong={isDefault} disabled={disabled}>{dumper.name}</Text> {pending && <Icon style={{ marginLeft: 10 }} type='loading' />}
{pending && <Icon style={{ marginLeft: 10 }} type='loading' />} </Menu.Item>
</Menu.Item> );
); })
})
} }
</Menu.SubMenu> </Menu.SubMenu>
); );

@ -25,22 +25,21 @@ export default function ExportSubmenu(props: Props): JSX.Element {
{ {
exporters exporters
.sort((a: any, b: any) => a.name.localeCompare(b.name)) .sort((a: any, b: any) => a.name.localeCompare(b.name))
.map((exporter: any): JSX.Element => .map((exporter: any): JSX.Element => {
{ const pending = (exportActivities || []).includes(exporter.name);
const pending = (exportActivities || []).includes(exporter.name); const disabled = !exporter.enabled || pending;
const disabled = !exporter.enabled || pending; return (
return ( <Menu.Item
<Menu.Item key={exporter.name}
key={exporter.name} disabled={disabled}
disabled={disabled} className='cvat-menu-export-submenu-item'
className='cvat-menu-export-submenu-item' >
> <Icon type='export' />
<Icon type='export' /> <Text disabled={disabled}>{exporter.name}</Text>
<Text disabled={disabled}>{exporter.name}</Text> {pending && <Icon style={{ marginLeft: 10 }} type='loading' />}
{pending && <Icon style={{ marginLeft: 10 }} type='loading' />} </Menu.Item>
</Menu.Item> );
); })
})
} }
</Menu.SubMenu> </Menu.SubMenu>
); );

@ -29,39 +29,38 @@ export default function LoadSubmenu(props: Props): JSX.Element {
{ {
loaders loaders
.sort((a: any, b: any) => a.name.localeCompare(b.name)) .sort((a: any, b: any) => a.name.localeCompare(b.name))
.map((loader: any): JSX.Element => .map((loader: any): JSX.Element => {
{ const accept = loader.format
const accept = loader.format .split(',')
.split(',') .map((x: string) => `.${x.trimStart()}`)
.map((x: string) => '.' + x.trimStart()) .join(', '); // add '.' to each extension in a list
.join(', '); // add '.' to each extension in a list const pending = loadActivity === loader.name;
const pending = loadActivity === loader.name; const disabled = !loader.enabled || !!loadActivity;
const disabled = !loader.enabled || !!loadActivity; return (
return ( <Menu.Item
<Menu.Item key={loader.name}
key={loader.name} disabled={disabled}
disabled={disabled} className='cvat-menu-load-submenu-item'
className='cvat-menu-load-submenu-item'
>
<Upload
accept={accept}
multiple={false}
showUploadList={false}
beforeUpload={(file: File): boolean => {
onFileUpload(file);
return false;
}}
> >
<Button block type='link' disabled={disabled}> <Upload
<Icon type='upload' /> accept={accept}
<Text>{loader.name}</Text> multiple={false}
{pending && <Icon style={{ marginLeft: 10 }} type='loading' />} showUploadList={false}
</Button> beforeUpload={(file: File): boolean => {
</Upload> onFileUpload(file);
return false;
}}
>
<Button block type='link' disabled={disabled}>
<Icon type='upload' />
<Text>{loader.name}</Text>
{pending && <Icon style={{ marginLeft: 10 }} type='loading' />}
</Button>
</Upload>
</Menu.Item> </Menu.Item>
); );
}) })
} }
</Menu.SubMenu> </Menu.SubMenu>
); );

@ -60,9 +60,11 @@ interface Props {
resetZoom: boolean; resetZoom: boolean;
aamZoomMargin: number; aamZoomMargin: number;
showObjectsTextAlways: boolean; showObjectsTextAlways: boolean;
showAllInterpolationTracks: boolean;
workspace: Workspace; workspace: Workspace;
automaticBordering: boolean; automaticBordering: boolean;
keyMap: Record<string, ExtendedKeyMapOptions>; keyMap: Record<string, ExtendedKeyMapOptions>;
canvasBackgroundColor: string;
switchableAutomaticBordering: boolean; switchableAutomaticBordering: boolean;
onSetupCanvas: () => void; onSetupCanvas: () => void;
onDragCanvas: (enabled: boolean) => void; onDragCanvas: (enabled: boolean) => void;
@ -91,6 +93,7 @@ interface Props {
onChangeGridColor(color: GridColor): void; onChangeGridColor(color: GridColor): void;
onSwitchGrid(enabled: boolean): void; onSwitchGrid(enabled: boolean): void;
onSwitchAutomaticBordering(enabled: boolean): void; onSwitchAutomaticBordering(enabled: boolean): void;
onFetchAnnotation(): void;
} }
export default class CanvasWrapperComponent extends React.PureComponent<Props> { export default class CanvasWrapperComponent extends React.PureComponent<Props> {
@ -135,6 +138,7 @@ export default class CanvasWrapperComponent extends React.PureComponent<Props> {
curZLayer, curZLayer,
resetZoom, resetZoom,
grid, grid,
gridSize,
gridOpacity, gridOpacity,
gridColor, gridColor,
brightnessLevel, brightnessLevel,
@ -143,8 +147,11 @@ export default class CanvasWrapperComponent extends React.PureComponent<Props> {
workspace, workspace,
frameFetching, frameFetching,
showObjectsTextAlways, showObjectsTextAlways,
showAllInterpolationTracks,
automaticBordering, automaticBordering,
showProjections, showProjections,
canvasBackgroundColor,
onFetchAnnotation,
} = this.props; } = this.props;
if (prevProps.showObjectsTextAlways !== showObjectsTextAlways if (prevProps.showObjectsTextAlways !== showObjectsTextAlways
@ -159,6 +166,10 @@ export default class CanvasWrapperComponent extends React.PureComponent<Props> {
}); });
} }
if (prevProps.showAllInterpolationTracks !== showAllInterpolationTracks) {
onFetchAnnotation();
}
if (prevProps.sidebarCollapsed !== sidebarCollapsed) { if (prevProps.sidebarCollapsed !== sidebarCollapsed) {
const [sidebar] = window.document.getElementsByClassName('cvat-objects-sidebar'); const [sidebar] = window.document.getElementsByClassName('cvat-objects-sidebar');
if (sidebar) { if (sidebar) {
@ -177,6 +188,10 @@ export default class CanvasWrapperComponent extends React.PureComponent<Props> {
} }
} }
if (gridSize !== prevProps.gridSize) {
canvasInstance.grid(gridSize, gridSize);
}
if (gridOpacity !== prevProps.gridOpacity if (gridOpacity !== prevProps.gridOpacity
|| gridColor !== prevProps.gridColor || gridColor !== prevProps.gridColor
|| grid !== prevProps.grid) { || grid !== prevProps.grid) {
@ -220,7 +235,8 @@ export default class CanvasWrapperComponent extends React.PureComponent<Props> {
} }
if (prevProps.opacity !== opacity || prevProps.blackBorders !== blackBorders if (prevProps.opacity !== opacity || prevProps.blackBorders !== blackBorders
|| prevProps.selectedOpacity !== selectedOpacity || prevProps.colorBy !== colorBy) { || prevProps.selectedOpacity !== selectedOpacity || prevProps.colorBy !== colorBy
) {
this.updateShapesView(); this.updateShapesView();
} }
@ -241,6 +257,13 @@ export default class CanvasWrapperComponent extends React.PureComponent<Props> {
} }
} }
if (prevProps.canvasBackgroundColor !== canvasBackgroundColor) {
const canvasWrapperElement = window.document.getElementsByClassName('cvat-canvas-container').item(0) as HTMLElement | null;
if (canvasWrapperElement) {
canvasWrapperElement.style.backgroundColor = canvasBackgroundColor;
}
}
this.activateOnCanvas(); this.activateOnCanvas();
} }
@ -634,6 +657,7 @@ export default class CanvasWrapperComponent extends React.PureComponent<Props> {
brightnessLevel, brightnessLevel,
contrastLevel, contrastLevel,
saturationLevel, saturationLevel,
canvasBackgroundColor,
} = this.props; } = this.props;
// Size // Size
@ -660,6 +684,11 @@ export default class CanvasWrapperComponent extends React.PureComponent<Props> {
+ `saturate(${saturationLevel / 100})`; + `saturate(${saturationLevel / 100})`;
} }
const canvasWrapperElement = window.document.getElementsByClassName('cvat-canvas-container').item(0) as HTMLElement | null;
if (canvasWrapperElement) {
canvasWrapperElement.style.backgroundColor = canvasBackgroundColor;
}
// Events // Events
canvasInstance.html().addEventListener('canvas.setup', () => { canvasInstance.html().addEventListener('canvas.setup', () => {
const { activatedStateID, activatedAttributeID } = this.props; const { activatedStateID, activatedAttributeID } = this.props;

@ -6,7 +6,7 @@ import React from 'react';
import Popover from 'antd/lib/popover'; import Popover from 'antd/lib/popover';
import Icon from 'antd/lib/icon'; import Icon from 'antd/lib/icon';
import { Canvas } from 'cvat-canvas'; import { Canvas } from 'cvat-canvas-wrapper';
import { ShapeType } from 'reducers/interfaces'; import { ShapeType } from 'reducers/interfaces';
import { CubeIcon } from 'icons'; import { CubeIcon } from 'icons';

@ -379,7 +379,7 @@ function ItemButtonsComponent(props: ItemButtonsComponentProps): JSX.Element {
<Col> <Col>
<Tooltip title={`Switch lock property ${switchLockShortcut}`}> <Tooltip title={`Switch lock property ${switchLockShortcut}`}>
{ locked { locked
? <Icon type='lock' onClick={unlock} theme='filled' /> ? <Icon type='lock' theme='filled' onClick={unlock} />
: <Icon type='unlock' onClick={lock} />} : <Icon type='unlock' onClick={lock} />}
</Tooltip> </Tooltip>
</Col> </Col>
@ -393,7 +393,7 @@ function ItemButtonsComponent(props: ItemButtonsComponentProps): JSX.Element {
<Col> <Col>
<Tooltip title={`Switch hidden property ${switchHiddenShortcut}`}> <Tooltip title={`Switch hidden property ${switchHiddenShortcut}`}>
{ hidden { hidden
? <Icon type='eye-invisible' onClick={show} /> ? <Icon type='eye-invisible' theme='filled' onClick={show} />
: <Icon type='eye' onClick={hide} />} : <Icon type='eye' onClick={hide} />}
</Tooltip> </Tooltip>
</Col> </Col>

@ -3,7 +3,7 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
import './styles.scss'; import './styles.scss';
import React from 'react'; import React, { useEffect } from 'react';
import Text from 'antd/lib/typography/Text'; import Text from 'antd/lib/typography/Text';
import Icon from 'antd/lib/icon'; import Icon from 'antd/lib/icon';
import Tabs from 'antd/lib/tabs'; import Tabs from 'antd/lib/tabs';
@ -11,12 +11,14 @@ import Layout from 'antd/lib/layout';
import { RadioChangeEvent } from 'antd/lib/radio'; import { RadioChangeEvent } from 'antd/lib/radio';
import { SliderValue } from 'antd/lib/slider'; import { SliderValue } from 'antd/lib/slider';
import { CheckboxChangeEvent } from 'antd/lib/checkbox'; import { CheckboxChangeEvent } from 'antd/lib/checkbox';
import { Canvas } from 'cvat-canvas-wrapper';
import { ColorBy } from 'reducers/interfaces'; import { ColorBy } from 'reducers/interfaces';
import ObjectsListContainer from 'containers/annotation-page/standard-workspace/objects-side-bar/objects-list'; import ObjectsListContainer from 'containers/annotation-page/standard-workspace/objects-side-bar/objects-list';
import LabelsListContainer from 'containers/annotation-page/standard-workspace/objects-side-bar/labels-list'; import LabelsListContainer from 'containers/annotation-page/standard-workspace/objects-side-bar/labels-list';
import AppearanceBlock from './appearance-block'; import AppearanceBlock from './appearance-block';
interface Props { interface Props {
sidebarCollapsed: boolean; sidebarCollapsed: boolean;
appearanceCollapsed: boolean; appearanceCollapsed: boolean;
@ -26,6 +28,7 @@ interface Props {
blackBorders: boolean; blackBorders: boolean;
showBitmap: boolean; showBitmap: boolean;
showProjections: boolean; showProjections: boolean;
canvasInstance: Canvas;
collapseSidebar(): void; collapseSidebar(): void;
collapseAppearance(): void; collapseAppearance(): void;
@ -48,6 +51,7 @@ function ObjectsSideBar(props: Props): JSX.Element {
blackBorders, blackBorders,
showBitmap, showBitmap,
showProjections, showProjections,
canvasInstance,
collapseSidebar, collapseSidebar,
collapseAppearance, collapseAppearance,
changeShapesColorBy, changeShapesColorBy,
@ -76,6 +80,23 @@ function ObjectsSideBar(props: Props): JSX.Element {
changeShowProjections, changeShowProjections,
}; };
useEffect(() => {
const listener = (event: Event): void => {
if ((event as TransitionEvent).propertyName === 'width'
&& ((event.target as any).classList as DOMTokenList).contains('ant-tabs-tab-prev')) {
canvasInstance.fit();
}
};
const [sidebar] = window.document.getElementsByClassName('cvat-objects-sidebar');
sidebar.addEventListener('transitionstart', listener);
return () => {
sidebar.removeEventListener('transitionstart', listener);
};
}, []);
return ( return (
<Layout.Sider <Layout.Sider
className='cvat-objects-sidebar' className='cvat-objects-sidebar'

@ -8,10 +8,6 @@
height: 100%; height: 100%;
} }
.cvat-canvas-container {
background-color: $background-color-1;
}
.cvat-objects-sidebar-filter-input { .cvat-objects-sidebar-filter-input {
width: calc(100% - 35px); width: calc(100% - 35px);
} }

@ -14,7 +14,6 @@ import notification from 'antd/lib/notification';
import GlobalErrorBoundary from 'components/global-error-boundary/global-error-boundary'; import GlobalErrorBoundary from 'components/global-error-boundary/global-error-boundary';
import ShorcutsDialog from 'components/shortcuts-dialog/shortcuts-dialog'; import ShorcutsDialog from 'components/shortcuts-dialog/shortcuts-dialog';
import SettingsPageContainer from 'containers/settings-page/settings-page';
import TasksPageContainer from 'containers/tasks-page/tasks-page'; import TasksPageContainer from 'containers/tasks-page/tasks-page';
import CreateTaskPageContainer from 'containers/create-task-page/create-task-page'; import CreateTaskPageContainer from 'containers/create-task-page/create-task-page';
import TaskPageContainer from 'containers/task-page/task-page'; import TaskPageContainer from 'containers/task-page/task-page';
@ -39,6 +38,7 @@ interface CVATAppProps {
resetErrors: () => void; resetErrors: () => void;
resetMessages: () => void; resetMessages: () => void;
switchShortcutsDialog: () => void; switchShortcutsDialog: () => void;
switchSettingsDialog: () => void;
keyMap: Record<string, ExtendedKeyMapOptions>; keyMap: Record<string, ExtendedKeyMapOptions>;
userInitialized: boolean; userInitialized: boolean;
userFetching: boolean; userFetching: boolean;
@ -62,7 +62,7 @@ interface CVATAppProps {
class CVATApplication extends React.PureComponent<CVATAppProps & RouteComponentProps> { class CVATApplication extends React.PureComponent<CVATAppProps & RouteComponentProps> {
public componentDidMount(): void { public componentDidMount(): void {
const core = getCore(); const core = getCore();
const { verifyAuthorized, history } = this.props; const { verifyAuthorized, history, location } = this.props;
configure({ ignoreRepeatedEventsWhenKeyHeldDown: false }); configure({ ignoreRepeatedEventsWhenKeyHeldDown: false });
// Logger configuration // Logger configuration
@ -72,9 +72,9 @@ class CVATApplication extends React.PureComponent<CVATAppProps & RouteComponentP
}); });
core.logger.configure(() => window.document.hasFocus, userActivityCallback); core.logger.configure(() => window.document.hasFocus, userActivityCallback);
customWaViewHit(history.location.pathname, history.location.search, history.location.hash); customWaViewHit(location.pathname, location.search, location.hash);
history.listen((location) => { history.listen((_location) => {
customWaViewHit(location.pathname, location.search, location.hash); customWaViewHit(_location.pathname, _location.search, _location.hash);
}); });
verifyAuthorized(); verifyAuthorized();
@ -225,8 +225,8 @@ class CVATApplication extends React.PureComponent<CVATAppProps & RouteComponentP
installedTFSegmentation, installedTFSegmentation,
installedTFAnnotation, installedTFAnnotation,
switchShortcutsDialog, switchShortcutsDialog,
switchSettingsDialog,
user, user,
history,
keyMap, keyMap,
} = this.props; } = this.props;
@ -239,27 +239,19 @@ class CVATApplication extends React.PureComponent<CVATAppProps & RouteComponentP
const subKeyMap = { const subKeyMap = {
SWITCH_SHORTCUTS: keyMap.SWITCH_SHORTCUTS, SWITCH_SHORTCUTS: keyMap.SWITCH_SHORTCUTS,
OPEN_SETTINGS: keyMap.OPEN_SETTINGS, SWITCH_SETTINGS: keyMap.SWITCH_SETTINGS,
}; };
const handlers = { const handlers = {
SWITCH_SHORTCUTS: (event: KeyboardEvent | undefined) => { SWITCH_SHORTCUTS: (event: KeyboardEvent | undefined) => {
if (event) { if (event) event.preventDefault();
event.preventDefault();
}
switchShortcutsDialog(); switchShortcutsDialog();
}, },
OPEN_SETTINGS: (event: KeyboardEvent | undefined) => { SWITCH_SETTINGS: (event: KeyboardEvent | undefined) => {
if (event) { if (event) event.preventDefault();
event.preventDefault();
}
if (history.location.pathname.endsWith('settings')) { switchSettingsDialog();
history.goBack();
} else {
history.push('/settings');
}
}, },
}; };
@ -273,7 +265,6 @@ class CVATApplication extends React.PureComponent<CVATAppProps & RouteComponentP
<ShorcutsDialog /> <ShorcutsDialog />
<GlobalHotKeys keyMap={subKeyMap} handlers={handlers}> <GlobalHotKeys keyMap={subKeyMap} handlers={handlers}>
<Switch> <Switch>
<Route exact path='/settings' component={SettingsPageContainer} />
<Route exact path='/tasks' component={TasksPageContainer} /> <Route exact path='/tasks' component={TasksPageContainer} />
<Route exact path='/tasks/create' component={CreateTaskPageContainer} /> <Route exact path='/tasks/create' component={CreateTaskPageContainer} />
<Route exact path='/tasks/:id' component={TaskPageContainer} /> <Route exact path='/tasks/:id' component={TaskPageContainer} />

@ -17,9 +17,11 @@ import Text from 'antd/lib/typography/Text';
import { CVATLogo, AccountIcon } from 'icons'; import { CVATLogo, AccountIcon } from 'icons';
import consts from 'consts'; import consts from 'consts';
import SettingsModal from './settings-modal/settings-modal';
interface HeaderContainerProps { interface HeaderContainerProps {
onLogout: () => void; onLogout: () => void;
switchSettingsDialog: (show: boolean) => void;
logoutFetching: boolean; logoutFetching: boolean;
installedAnalytics: boolean; installedAnalytics: boolean;
installedAutoAnnotation: boolean; installedAutoAnnotation: boolean;
@ -34,6 +36,7 @@ interface HeaderContainerProps {
canvasVersion: string; canvasVersion: string;
uiVersion: string; uiVersion: string;
switchSettingsShortcut: string; switchSettingsShortcut: string;
settingsDialogShown: boolean;
} }
type Props = HeaderContainerProps & RouteComponentProps; type Props = HeaderContainerProps & RouteComponentProps;
@ -54,7 +57,9 @@ function HeaderContainer(props: Props): JSX.Element {
uiVersion, uiVersion,
onLogout, onLogout,
logoutFetching, logoutFetching,
settingsDialogShown,
switchSettingsShortcut, switchSettingsShortcut,
switchSettingsDialog,
} = props; } = props;
const renderModels = installedAutoAnnotation const renderModels = installedAutoAnnotation
@ -131,7 +136,7 @@ function HeaderContainer(props: Props): JSX.Element {
<Menu.Item <Menu.Item
title={`Press ${switchSettingsShortcut} to switch`} title={`Press ${switchSettingsShortcut} to switch`}
onClick={ onClick={
(): void => props.history.push('/settings') (): void => switchSettingsDialog(true)
} }
> >
<Icon type='setting' /> <Icon type='setting' />
@ -236,6 +241,10 @@ function HeaderContainer(props: Props): JSX.Element {
</span> </span>
</Dropdown> </Dropdown>
</div> </div>
<SettingsModal
visible={settingsDialogShown}
onClose={() => switchSettingsDialog(false)}
/>
</Layout.Header> </Layout.Header>
); );
} }

@ -9,13 +9,16 @@ import Checkbox, { CheckboxChangeEvent } from 'antd/lib/checkbox';
import Button from 'antd/lib/button'; import Button from 'antd/lib/button';
import Slider from 'antd/lib/slider'; import Slider from 'antd/lib/slider';
import Select from 'antd/lib/select'; import Select from 'antd/lib/select';
import Popover from 'antd/lib/popover';
import InputNumber from 'antd/lib/input-number'; import InputNumber from 'antd/lib/input-number';
import Icon from 'antd/lib/icon'; import Icon from 'antd/lib/icon';
import Text from 'antd/lib/typography/Text'; import Text from 'antd/lib/typography/Text';
import { CompactPicker } from 'react-color';
import { clamp } from 'utils/math'; import { clamp } from 'utils/math';
import { BackJumpIcon, ForwardJumpIcon } from 'icons'; import { BackJumpIcon, ForwardJumpIcon } from 'icons';
import { FrameSpeed, GridColor } from 'reducers/interfaces'; import { FrameSpeed, GridColor } from 'reducers/interfaces';
import consts from 'consts';
interface Props { interface Props {
@ -30,6 +33,7 @@ interface Props {
brightnessLevel: number; brightnessLevel: number;
contrastLevel: number; contrastLevel: number;
saturationLevel: number; saturationLevel: number;
canvasBackgroundColor: string;
onChangeFrameStep(step: number): void; onChangeFrameStep(step: number): void;
onChangeFrameSpeed(speed: FrameSpeed): void; onChangeFrameSpeed(speed: FrameSpeed): void;
onSwitchResetZoom(enabled: boolean): void; onSwitchResetZoom(enabled: boolean): void;
@ -41,6 +45,7 @@ interface Props {
onChangeBrightnessLevel(level: number): void; onChangeBrightnessLevel(level: number): void;
onChangeContrastLevel(level: number): void; onChangeContrastLevel(level: number): void;
onChangeSaturationLevel(level: number): void; onChangeSaturationLevel(level: number): void;
onChangeCanvasBackgroundColor(color: string): void;
} }
export default function PlayerSettingsComponent(props: Props): JSX.Element { export default function PlayerSettingsComponent(props: Props): JSX.Element {
@ -56,6 +61,7 @@ export default function PlayerSettingsComponent(props: Props): JSX.Element {
brightnessLevel, brightnessLevel,
contrastLevel, contrastLevel,
saturationLevel, saturationLevel,
canvasBackgroundColor,
onChangeFrameStep, onChangeFrameStep,
onChangeFrameSpeed, onChangeFrameSpeed,
onSwitchResetZoom, onSwitchResetZoom,
@ -67,6 +73,7 @@ export default function PlayerSettingsComponent(props: Props): JSX.Element {
onChangeBrightnessLevel, onChangeBrightnessLevel,
onChangeContrastLevel, onChangeContrastLevel,
onChangeSaturationLevel, onChangeSaturationLevel,
onChangeCanvasBackgroundColor,
} = props; } = props;
const minFrameStep = 2; const minFrameStep = 2;
@ -74,7 +81,6 @@ export default function PlayerSettingsComponent(props: Props): JSX.Element {
const minGridSize = 5; const minGridSize = 5;
const maxGridSize = 1000; const maxGridSize = 1000;
return ( return (
<div className='cvat-player-settings'> <div className='cvat-player-settings'>
<Row type='flex' align='bottom' className='cvat-player-settings-step'> <Row type='flex' align='bottom' className='cvat-player-settings-step'>
@ -122,6 +128,23 @@ export default function PlayerSettingsComponent(props: Props): JSX.Element {
</Select> </Select>
</Col> </Col>
</Row> </Row>
<Row type='flex' className='cvat-player-settings-canvas-background'>
<Col>
<Popover
content={(
<CompactPicker
colors={consts.CANVAS_BACKGROUND_COLORS}
color={canvasBackgroundColor}
onChange={(e) => onChangeCanvasBackgroundColor(e.hex)}
/>
)}
overlayClassName='canvas-background-color-picker-popover'
trigger='click'
>
<Button type='default'>Select canvas background color</Button>
</Popover>
</Col>
</Row>
<Row type='flex'> <Row type='flex'>
<Col> <Col>
<Checkbox <Checkbox
@ -220,62 +243,66 @@ export default function PlayerSettingsComponent(props: Props): JSX.Element {
</Row> </Row>
</Col> </Col>
</Row> </Row>
<Row className='cvat-player-settings-brightness'> <Row>
<Col className='cvat-text-color'> <Col span={12}>
Brightness <Row className='cvat-player-settings-brightness'>
</Col> <Col className='cvat-text-color'>
<Col> Brightness
<Slider </Col>
min={50} <Col>
max={200} <Slider
value={brightnessLevel} min={50}
onChange={(value: number | [number, number]): void => { max={200}
onChangeBrightnessLevel(value as number); value={brightnessLevel}
}} onChange={(value: number | [number, number]): void => {
/> onChangeBrightnessLevel(value as number);
</Col> }}
</Row> />
<Row className='cvat-player-settings-contrast'> </Col>
<Col className='cvat-text-color'> </Row>
Contrast <Row className='cvat-player-settings-contrast'>
</Col> <Col className='cvat-text-color'>
<Col> Contrast
<Slider </Col>
min={50} <Col>
max={200} <Slider
value={contrastLevel} min={50}
onChange={(value: number | [number, number]): void => { max={200}
onChangeContrastLevel(value as number); value={contrastLevel}
}} onChange={(value: number | [number, number]): void => {
/> onChangeContrastLevel(value as number);
</Col> }}
</Row> />
<Row className='cvat-player-settings-saturation'> </Col>
<Col className='cvat-text-color'> </Row>
Saturation <Row className='cvat-player-settings-saturation'>
</Col> <Col className='cvat-text-color'>
<Col> Saturation
<Slider </Col>
min={0} <Col>
max={300} <Slider
value={saturationLevel} min={0}
onChange={(value: number | [number, number]): void => { max={300}
onChangeSaturationLevel(value as number); value={saturationLevel}
}} onChange={(value: number | [number, number]): void => {
/> onChangeSaturationLevel(value as number);
</Col> }}
</Row> />
<Row className='cvat-player-reset-color-settings'> </Col>
<Col> </Row>
<Button <Row className='cvat-player-reset-color-settings'>
onClick={() => { <Col>
onChangeBrightnessLevel(100); <Button
onChangeContrastLevel(100); onClick={() => {
onChangeSaturationLevel(100); onChangeBrightnessLevel(100);
}} onChangeContrastLevel(100);
> onChangeSaturationLevel(100);
Reset color settings }}
</Button> >
Reset color settings
</Button>
</Col>
</Row>
</Col> </Col>
</Row> </Row>
</div> </div>

@ -0,0 +1,74 @@
// Copyright (C) 2020 Intel Corporation
//
// SPDX-License-Identifier: MIT
import './styles.scss';
import React from 'react';
import Tabs from 'antd/lib/tabs';
import Icon from 'antd/lib/icon';
import Text from 'antd/lib/typography/Text';
import Modal from 'antd/lib/modal/Modal';
import WorkspaceSettingsContainer from 'containers/header/settings-modal/workspace-settings';
import PlayerSettingsContainer from 'containers/header/settings-modal/player-settings';
import Button from 'antd/lib/button';
interface SettingsModalProps {
visible: boolean;
onClose(): void;
}
const SettingsModal = (props: SettingsModalProps): JSX.Element => {
const { visible, onClose } = props;
return (
<Modal
title='Settings'
visible={visible}
onCancel={onClose}
width={800}
className='cvat-settings-modal'
footer={(
<Button type='primary' onClick={onClose}>
Close
</Button>
)}
>
<div className='cvat-settings-tabs'>
<Tabs
type='card'
tabBarStyle={{ marginBottom: '0px', marginLeft: '-1px' }}
>
<Tabs.TabPane
tab={
(
<span>
<Icon type='play-circle' />
<Text>Player</Text>
</span>
)
}
key='player'
>
<PlayerSettingsContainer />
</Tabs.TabPane>
<Tabs.TabPane
tab={
(
<span>
<Icon type='laptop' />
<Text>Workspace</Text>
</span>
)
}
key='workspace'
>
<WorkspaceSettingsContainer />
</Tabs.TabPane>
</Tabs>
</div>
</Modal>
);
};
export default SettingsModal;

@ -2,15 +2,15 @@
// //
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
@import '../../base.scss'; @import '../../../base.scss';
.cvat-settings-page { .cvat-settings-tabs {
height: 100%; height: 100%;
overflow-y: auto; overflow-y: auto;
padding-bottom: 15px; padding-bottom: 15px;
> div:nth-child(1) { > div:nth-child(1) {
margin-top: 30px; margin-top: 10px;
margin-bottom: 10px; margin-bottom: 10px;
} }
} }
@ -20,7 +20,7 @@
width: 100%; width: 100%;
height: max-content; height: max-content;
background: $background-color-1; background: $background-color-1;
padding: 50px; padding: 24px;
} }
.cvat-player-settings-grid, .cvat-player-settings-grid,
@ -42,6 +42,7 @@
.cvat-player-settings-speed, .cvat-player-settings-speed,
.cvat-player-settings-reset-zoom, .cvat-player-settings-reset-zoom,
.cvat-player-settings-rotate-all, .cvat-player-settings-rotate-all,
.cvat-player-settings-canvas-background,
.cvat-workspace-settings-aam-zoom-margin, .cvat-workspace-settings-aam-zoom-margin,
.cvat-workspace-settings-auto-save-interval { .cvat-workspace-settings-auto-save-interval {
margin-bottom: 25px; margin-bottom: 25px;
@ -96,12 +97,20 @@
} }
} }
.cvat-settings-page-back-button { .cvat-player-settings-image-preview {
width: 100px; width: 100%;
margin-top: 15px; max-height: 180px;
object-fit: cover;
}
.canvas-background-color-picker-popover .ant-popover-inner-content {
padding: 6px 12px;
:first-child:first-child {
box-shadow: unset !important;
}
} }
.cvat-settings-page-back-button-wrapper { .cvat-settings-modal .ant-modal-body{
display: flex; padding-top: 0;
justify-content: flex-end;
} }

@ -42,7 +42,7 @@ export default function WorkspaceSettingsComponent(props: Props): JSX.Element {
onSwitchAutomaticBordering, onSwitchAutomaticBordering,
} = props; } = props;
const minAutoSaveInterval = 5; const minAutoSaveInterval = 1;
const maxAutoSaveInterval = 60; const maxAutoSaveInterval = 60;
const minAAMMargin = 0; const minAAMMargin = 0;
const maxAAMMargin = 1000; const maxAAMMargin = 1000;

@ -3,12 +3,12 @@
// //
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
import React, {useState, useEffect} from 'react'; import React, { useState, useEffect } from 'react';
import Drawer from 'antd/lib/drawer'; import Drawer from 'antd/lib/drawer';
import Paragraph from 'antd/lib/typography/Paragraph'; import Paragraph from 'antd/lib/typography/Paragraph';
import Button from 'antd/lib/button/button'; import Button from 'antd/lib/button/button';
import {isPublic} from 'utils/enviroment'; import { isPublic } from 'utils/enviroment';
function CookieDrawer(): JSX.Element { function CookieDrawer(): JSX.Element {
@ -19,12 +19,12 @@ function CookieDrawer(): JSX.Element {
if (cookiePolicyAccepted === null && isPublic()) { if (cookiePolicyAccepted === null && isPublic()) {
setDrawerVisible(true); setDrawerVisible(true);
} }
}, []) }, []);
const onClose = () => { const onClose = (): void => {
localStorage.setItem('cookiePolicyAccepted', 'true'); localStorage.setItem('cookiePolicyAccepted', 'true');
setDrawerVisible(false); setDrawerVisible(false);
} };
return ( return (
<Drawer <Drawer
@ -36,9 +36,11 @@ function CookieDrawer(): JSX.Element {
destroyOnClose destroyOnClose
> >
<Paragraph> <Paragraph>
This site uses cookies for functionality, analytics, and advertising purposes as described in our Cookie and Similar Technologies Notice. This site uses cookies for functionality, analytics, and advertising purposes
To see what cookies we serve and set your preferences, please visit our <a href='https://www.intel.com/cookies'>Cookie Consent Tool</a>. as described in our Cookie and Similar Technologies Notice.
By continuing to use our website, you agree to our use of cookies. To see what cookies we serve and set your preferences, please visit our
<a href='https://www.intel.com/cookies'>Cookie Consent Tool</a>
. By continuing to use our website, you agree to our use of cookies.
</Paragraph> </Paragraph>
<Button onClick={onClose} size='large' type='primary'> <Button onClick={onClose} size='large' type='primary'>
Accept Accept

@ -10,7 +10,7 @@ import Title from 'antd/lib/typography/Title';
import Text from 'antd/lib/typography/Text'; import Text from 'antd/lib/typography/Text';
import { Row, Col } from 'antd/lib/grid'; import { Row, Col } from 'antd/lib/grid';
import { UserAgreement } from 'reducers/interfaces' import { UserAgreement } from 'reducers/interfaces';
import CookieDrawer from 'components/login-page/cookie-policy-drawer'; import CookieDrawer from 'components/login-page/cookie-policy-drawer';
import RegisterForm, { RegisterData, UserConfirmation } from './register-form'; import RegisterForm, { RegisterData, UserConfirmation } from './register-form';

@ -1,78 +0,0 @@
// Copyright (C) 2020 Intel Corporation
//
// SPDX-License-Identifier: MIT
import './styles.scss';
import React from 'react';
import { Row, Col } from 'antd/lib/grid';
import Tabs from 'antd/lib/tabs';
import Icon from 'antd/lib/icon';
import Button from 'antd/lib/button';
import Text from 'antd/lib/typography/Text';
import { RouteComponentProps } from 'react-router';
import WorkspaceSettingsContainer from 'containers/settings-page/workspace-settings';
import PlayerSettingsContainer from 'containers/settings-page/player-settings';
function SettingsPage(props: RouteComponentProps): JSX.Element {
return (
<div className='cvat-settings-page'>
<Row type='flex' justify='center'>
<Col>
<Text className='cvat-title'> Settings </Text>
</Col>
</Row>
<Row type='flex' justify='center'>
<Col md={14} lg={12} xl={10} xxl={9}>
<Tabs
type='card'
tabBarStyle={{ marginBottom: '0px', marginLeft: '-1px' }}
>
<Tabs.TabPane
tab={
(
<span>
<Icon type='play-circle' />
<Text>Player</Text>
</span>
)
}
key='player'
>
<PlayerSettingsContainer />
</Tabs.TabPane>
<Tabs.TabPane
tab={
(
<span>
<Icon type='laptop' />
<Text>Workspace</Text>
</span>
)
}
key='workspace'
>
<WorkspaceSettingsContainer />
</Tabs.TabPane>
</Tabs>
</Col>
</Row>
<Row type='flex' justify='center'>
<Col md={14} lg={12} xl={10} xxl={9} className='cvat-settings-page-back-button-wrapper'>
<Button
className='cvat-settings-page-back-button'
type='primary'
onClick={(): void => {
props.history.goBack();
}}
>
Go Back
</Button>
</Col>
</Row>
</div>
);
}
export default SettingsPage;

@ -32,6 +32,7 @@ interface Props {
interface State { interface State {
name: string; name: string;
bugTracker: string; bugTracker: string;
bugTrackerEditing: boolean;
repository: string; repository: string;
repositoryStatus: string; repositoryStatus: string;
} }
@ -52,6 +53,7 @@ export default class DetailsComponent extends React.PureComponent<Props, State>
this.state = { this.state = {
name: taskInstance.name, name: taskInstance.name,
bugTracker: taskInstance.bugTracker, bugTracker: taskInstance.bugTracker,
bugTrackerEditing: false,
repository: '', repository: '',
repositoryStatus: '', repositoryStatus: '',
}; };
@ -323,9 +325,14 @@ export default class DetailsComponent extends React.PureComponent<Props, State>
taskInstance, taskInstance,
onTaskUpdate, onTaskUpdate,
} = this.props; } = this.props;
const { bugTracker } = this.state; const { bugTracker, bugTrackerEditing } = this.state;
let shown = false; let shown = false;
const onStart = (): void => {
this.setState({
bugTrackerEditing: true,
});
};
const onChangeValue = (value: string): void => { const onChangeValue = (value: string): void => {
if (value && !patterns.validateURL.pattern.test(value)) { if (value && !patterns.validateURL.pattern.test(value)) {
if (!shown) { if (!shown) {
@ -341,6 +348,7 @@ export default class DetailsComponent extends React.PureComponent<Props, State>
} else { } else {
this.setState({ this.setState({
bugTracker: value, bugTracker: value,
bugTrackerEditing: false,
}); });
taskInstance.bugTracker = value; taskInstance.bugTracker = value;
@ -377,7 +385,15 @@ export default class DetailsComponent extends React.PureComponent<Props, State>
<Col> <Col>
<Text strong className='cvat-text-color'>Issue Tracker</Text> <Text strong className='cvat-text-color'>Issue Tracker</Text>
<br /> <br />
<Text editable={{ onChange: onChangeValue }}>Not specified</Text> <Text
editable={{
editing: bugTrackerEditing,
onStart,
onChange: onChangeValue,
}}
>
{bugTrackerEditing ? '' : 'Not specified'}
</Text>
</Col> </Col>
</Row> </Row>
); );

@ -187,7 +187,7 @@ class TaskItemComponent extends React.PureComponent<TaskItemProps & RouteCompone
href={`/tasks/${id}`} href={`/tasks/${id}`}
onClick={(e: React.MouseEvent): void => { onClick={(e: React.MouseEvent): void => {
e.preventDefault(); e.preventDefault();
history.push(`/tasks/${id}`) history.push(`/tasks/${id}`);
}} }}
> >
Open Open

@ -13,6 +13,7 @@ const GITHUB_URL = 'https://github.com/opencv/cvat';
const GITHUB_IMAGE_URL = 'https://raw.githubusercontent.com/opencv/cvat/develop/cvat/apps/documentation/static/documentation/images/cvat.jpg'; const GITHUB_IMAGE_URL = 'https://raw.githubusercontent.com/opencv/cvat/develop/cvat/apps/documentation/static/documentation/images/cvat.jpg';
const AUTO_ANNOTATION_GUIDE_URL = 'https://github.com/opencv/cvat/blob/develop/cvat/apps/auto_annotation/README.md'; const AUTO_ANNOTATION_GUIDE_URL = 'https://github.com/opencv/cvat/blob/develop/cvat/apps/auto_annotation/README.md';
const SHARE_MOUNT_GUIDE_URL = 'https://github.com/opencv/cvat/blob/master/cvat/apps/documentation/installation.md#share-path'; const SHARE_MOUNT_GUIDE_URL = 'https://github.com/opencv/cvat/blob/master/cvat/apps/documentation/installation.md#share-path';
const CANVAS_BACKGROUND_COLORS = ['#ffffff', '#f1f1f1', '#e5e5e5', '#d8d8d8', '#CCCCCC', '#B3B3B3', '#999999'];
export default { export default {
UNDEFINED_ATTRIBUTE_VALUE, UNDEFINED_ATTRIBUTE_VALUE,
@ -26,4 +27,5 @@ export default {
GITHUB_IMAGE_URL, GITHUB_IMAGE_URL,
AUTO_ANNOTATION_GUIDE_URL, AUTO_ANNOTATION_GUIDE_URL,
SHARE_MOUNT_GUIDE_URL, SHARE_MOUNT_GUIDE_URL,
CANVAS_BACKGROUND_COLORS,
}; };

@ -26,6 +26,7 @@ import {
updateCanvasContextMenu, updateCanvasContextMenu,
addZLayer, addZLayer,
switchZLayer, switchZLayer,
fetchAnnotationsAsync,
} from 'actions/annotation-actions'; } from 'actions/annotation-actions';
import { import {
switchGrid, switchGrid,
@ -78,6 +79,7 @@ interface StateToProps {
resetZoom: boolean; resetZoom: boolean;
aamZoomMargin: number; aamZoomMargin: number;
showObjectsTextAlways: boolean; showObjectsTextAlways: boolean;
showAllInterpolationTracks: boolean;
workspace: Workspace; workspace: Workspace;
minZLayer: number; minZLayer: number;
maxZLayer: number; maxZLayer: number;
@ -85,6 +87,7 @@ interface StateToProps {
automaticBordering: boolean; automaticBordering: boolean;
switchableAutomaticBordering: boolean; switchableAutomaticBordering: boolean;
keyMap: Record<string, ExtendedKeyMapOptions>; keyMap: Record<string, ExtendedKeyMapOptions>;
canvasBackgroundColor: string;
} }
interface DispatchToProps { interface DispatchToProps {
@ -115,6 +118,7 @@ interface DispatchToProps {
onChangeGridColor(color: GridColor): void; onChangeGridColor(color: GridColor): void;
onSwitchGrid(enabled: boolean): void; onSwitchGrid(enabled: boolean): void;
onSwitchAutomaticBordering(enabled: boolean): void; onSwitchAutomaticBordering(enabled: boolean): void;
onFetchAnnotation(): void;
} }
function mapStateToProps(state: CombinedState): StateToProps { function mapStateToProps(state: CombinedState): StateToProps {
@ -155,6 +159,7 @@ function mapStateToProps(state: CombinedState): StateToProps {
}, },
settings: { settings: {
player: { player: {
canvasBackgroundColor,
grid, grid,
gridSize, gridSize,
gridColor, gridColor,
@ -167,6 +172,7 @@ function mapStateToProps(state: CombinedState): StateToProps {
workspace: { workspace: {
aamZoomMargin, aamZoomMargin,
showObjectsTextAlways, showObjectsTextAlways,
showAllInterpolationTracks,
automaticBordering, automaticBordering,
}, },
shapes: { shapes: {
@ -213,12 +219,14 @@ function mapStateToProps(state: CombinedState): StateToProps {
resetZoom, resetZoom,
aamZoomMargin, aamZoomMargin,
showObjectsTextAlways, showObjectsTextAlways,
showAllInterpolationTracks,
curZLayer, curZLayer,
minZLayer, minZLayer,
maxZLayer, maxZLayer,
automaticBordering, automaticBordering,
workspace, workspace,
keyMap, keyMap,
canvasBackgroundColor,
switchableAutomaticBordering: activeControl === ActiveControl.DRAW_POLYGON switchableAutomaticBordering: activeControl === ActiveControl.DRAW_POLYGON
|| activeControl === ActiveControl.DRAW_POLYLINE || activeControl === ActiveControl.DRAW_POLYLINE
|| activeControl === ActiveControl.EDIT, || activeControl === ActiveControl.EDIT,
@ -310,6 +318,9 @@ function mapDispatchToProps(dispatch: any): DispatchToProps {
onSwitchAutomaticBordering(enabled: boolean): void { onSwitchAutomaticBordering(enabled: boolean): void {
dispatch(switchAutomaticBordering(enabled)); dispatch(switchAutomaticBordering(enabled));
}, },
onFetchAnnotation(): void {
dispatch(fetchAnnotationsAsync());
},
}; };
} }

@ -31,6 +31,7 @@ import {
changeShowProjections as changeShowProjectionsAction, changeShowProjections as changeShowProjectionsAction,
} from 'actions/settings-actions'; } from 'actions/settings-actions';
import { Canvas } from 'cvat-canvas-wrapper';
interface StateToProps { interface StateToProps {
sidebarCollapsed: boolean; sidebarCollapsed: boolean;
@ -41,6 +42,7 @@ interface StateToProps {
blackBorders: boolean; blackBorders: boolean;
showBitmap: boolean; showBitmap: boolean;
showProjections: boolean; showProjections: boolean;
canvasInstance: Canvas;
} }
interface DispatchToProps { interface DispatchToProps {
@ -60,6 +62,9 @@ function mapStateToProps(state: CombinedState): StateToProps {
annotation: { annotation: {
sidebarCollapsed, sidebarCollapsed,
appearanceCollapsed, appearanceCollapsed,
canvas: {
instance: canvasInstance,
},
}, },
settings: { settings: {
shapes: { shapes: {
@ -82,6 +87,7 @@ function mapStateToProps(state: CombinedState): StateToProps {
blackBorders, blackBorders,
showBitmap, showBitmap,
showProjections, showProjections,
canvasInstance,
}; };
} }
@ -213,6 +219,7 @@ class ObjectsSideBarContainer extends React.PureComponent<Props> {
blackBorders, blackBorders,
showBitmap, showBitmap,
showProjections, showProjections,
canvasInstance,
collapseSidebar, collapseSidebar,
collapseAppearance, collapseAppearance,
} = this.props; } = this.props;
@ -227,6 +234,7 @@ class ObjectsSideBarContainer extends React.PureComponent<Props> {
blackBorders={blackBorders} blackBorders={blackBorders}
showBitmap={showBitmap} showBitmap={showBitmap}
showProjections={showProjections} showProjections={showProjections}
canvasInstance={canvasInstance}
collapseSidebar={collapseSidebar} collapseSidebar={collapseSidebar}
collapseAppearance={collapseAppearance} collapseAppearance={collapseAppearance}
changeShapesColorBy={this.changeShapesColorBy} changeShapesColorBy={this.changeShapesColorBy}

@ -169,18 +169,12 @@ class AnnotationTopBarContainer extends React.PureComponent<Props> {
public componentDidMount(): void { public componentDidMount(): void {
const { const {
autoSave,
autoSaveInterval, autoSaveInterval,
saving,
history, history,
jobInstance, jobInstance,
} = this.props; } = this.props;
this.autoSaveInterval = window.setInterval((): void => { this.autoSaveInterval = window.setInterval(this.autoSave.bind(this), autoSaveInterval);
if (autoSave && !saving) {
this.onSaveAnnotation();
}
}, autoSaveInterval);
this.unblock = history.block((location: any) => { this.unblock = history.block((location: any) => {
if (jobInstance.annotations.hasUnsavedChanges() && location.pathname !== '/settings' if (jobInstance.annotations.hasUnsavedChanges() && location.pathname !== '/settings'
@ -193,7 +187,7 @@ class AnnotationTopBarContainer extends React.PureComponent<Props> {
window.addEventListener('beforeunload', this.beforeUnloadCallback); window.addEventListener('beforeunload', this.beforeUnloadCallback);
} }
public componentDidUpdate(): void { public componentDidUpdate(prevProps: Props): void {
const { const {
jobInstance, jobInstance,
frameSpeed, frameSpeed,
@ -204,8 +198,13 @@ class AnnotationTopBarContainer extends React.PureComponent<Props> {
canvasInstance, canvasInstance,
onSwitchPlay, onSwitchPlay,
onChangeFrame, onChangeFrame,
autoSaveInterval,
} = this.props; } = this.props;
if (autoSaveInterval !== prevProps.autoSaveInterval) {
if (this.autoSaveInterval) window.clearInterval(this.autoSaveInterval);
this.autoSaveInterval = window.setInterval(this.autoSave.bind(this), autoSaveInterval);
}
if (playing && canvasIsReady) { if (playing && canvasIsReady) {
if (frameNumber < jobInstance.stopFrame) { if (frameNumber < jobInstance.stopFrame) {
@ -444,6 +443,14 @@ class AnnotationTopBarContainer extends React.PureComponent<Props> {
copy(url); copy(url);
}; };
private autoSave(): void {
const { autoSave, saving } = this.props;
if (autoSave && !saving) {
this.onSaveAnnotation();
}
}
private changeFrame(frame: number): void { private changeFrame(frame: number): void {
const { onChangeFrame, canvasInstance } = this.props; const { onChangeFrame, canvasInstance } = this.props;
if (canvasInstance.isAbleToChangeFrame()) { if (canvasInstance.isAbleToChangeFrame()) {

@ -3,11 +3,13 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { ExtendedKeyMapOptions } from 'react-hotkeys';
import getCore from 'cvat-core-wrapper'; import getCore from 'cvat-core-wrapper';
import HeaderComponent from 'components/header/header'; import HeaderComponent from 'components/header/header';
import { SupportedPlugins, CombinedState } from 'reducers/interfaces'; import { SupportedPlugins, CombinedState } from 'reducers/interfaces';
import { logoutAsync } from 'actions/auth-actions'; import { logoutAsync } from 'actions/auth-actions';
import { switchSettingsDialog } from 'actions/settings-actions';
const core = getCore(); const core = getCore();
@ -26,10 +28,12 @@ interface StateToProps {
canvasVersion: string; canvasVersion: string;
uiVersion: string; uiVersion: string;
switchSettingsShortcut: string; switchSettingsShortcut: string;
settingsDialogShown: boolean;
} }
interface DispatchToProps { interface DispatchToProps {
onLogout: typeof logoutAsync; onLogout: typeof logoutAsync;
switchSettingsDialog: (show: boolean) => void;
} }
function mapStateToProps(state: CombinedState): StateToProps { function mapStateToProps(state: CombinedState): StateToProps {
@ -50,6 +54,9 @@ function mapStateToProps(state: CombinedState): StateToProps {
shortcuts: { shortcuts: {
normalizedKeyMap, normalizedKeyMap,
}, },
settings: {
showDialog: settingsDialogShown,
},
} = state; } = state;
return { return {
@ -67,12 +74,16 @@ function mapStateToProps(state: CombinedState): StateToProps {
canvasVersion: packageVersion.canvas, canvasVersion: packageVersion.canvas,
uiVersion: packageVersion.ui, uiVersion: packageVersion.ui,
switchSettingsShortcut: normalizedKeyMap.OPEN_SETTINGS, switchSettingsShortcut: normalizedKeyMap.OPEN_SETTINGS,
settingsDialogShown,
}; };
} }
const mapDispatchToProps: DispatchToProps = { function mapDispatchToProps(dispatch: any): DispatchToProps {
onLogout: logoutAsync, return {
}; onLogout: logoutAsync,
switchSettingsDialog: (show: boolean): void => dispatch(switchSettingsDialog(show)),
};
}
export default connect( export default connect(
mapStateToProps, mapStateToProps,

@ -5,7 +5,7 @@
import React from 'react'; import React from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import PlayerSettingsComponent from 'components/settings-page/player-settings'; import PlayerSettingsComponent from 'components/header/settings-modal/player-settings';
import { import {
changeFrameStep, changeFrameStep,
@ -19,6 +19,7 @@ import {
changeBrightnessLevel, changeBrightnessLevel,
changeContrastLevel, changeContrastLevel,
changeSaturationLevel, changeSaturationLevel,
changeCanvasBackgroundColor,
} from 'actions/settings-actions'; } from 'actions/settings-actions';
import { import {
@ -39,6 +40,7 @@ interface StateToProps {
brightnessLevel: number; brightnessLevel: number;
contrastLevel: number; contrastLevel: number;
saturationLevel: number; saturationLevel: number;
canvasBackgroundColor: string;
} }
interface DispatchToProps { interface DispatchToProps {
@ -53,13 +55,17 @@ interface DispatchToProps {
onChangeBrightnessLevel(level: number): void; onChangeBrightnessLevel(level: number): void;
onChangeContrastLevel(level: number): void; onChangeContrastLevel(level: number): void;
onChangeSaturationLevel(level: number): void; onChangeSaturationLevel(level: number): void;
onChangeCanvasBackgroundColor(color: string): void;
} }
function mapStateToProps(state: CombinedState): StateToProps { function mapStateToProps(state: CombinedState): StateToProps {
const { player } = state.settings; const {
return { settings: {
...player, player,
}; },
} = state;
return player;
} }
function mapDispatchToProps(dispatch: any): DispatchToProps { function mapDispatchToProps(dispatch: any): DispatchToProps {
@ -97,6 +103,9 @@ function mapDispatchToProps(dispatch: any): DispatchToProps {
onChangeSaturationLevel(level: number): void { onChangeSaturationLevel(level: number): void {
dispatch(changeSaturationLevel(level)); dispatch(changeSaturationLevel(level));
}, },
onChangeCanvasBackgroundColor(color: string): void {
dispatch(changeCanvasBackgroundColor(color));
},
}; };
} }

@ -16,7 +16,7 @@ import {
import { CombinedState } from 'reducers/interfaces'; import { CombinedState } from 'reducers/interfaces';
import WorkspaceSettingsComponent from 'components/settings-page/workspace-settings'; import WorkspaceSettingsComponent from 'components/header/settings-modal/workspace-settings';
interface StateToProps { interface StateToProps {
autoSave: boolean; autoSave: boolean;

@ -6,13 +6,12 @@ import React from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { registerAsync } from 'actions/auth-actions'; import { registerAsync } from 'actions/auth-actions';
import RegisterPageComponent from 'components/register-page/register-page'; import RegisterPageComponent from 'components/register-page/register-page';
import { UserConfirmation } from 'components/register-page/register-form' import { UserConfirmation } from 'components/register-page/register-form';
import { CombinedState, UserAgreement } from 'reducers/interfaces'; import { CombinedState, UserAgreement } from 'reducers/interfaces';
interface StateToProps { interface StateToProps {
fetching: boolean; fetching: boolean;
userAgreements: UserAgreement[]; userAgreements: UserAgreement[];
} }
interface DispatchToProps { interface DispatchToProps {

@ -1,83 +0,0 @@
// Copyright (C) 2020 Intel Corporation
//
// SPDX-License-Identifier: MIT
import React from 'react';
import { connect } from 'react-redux';
import { RouteComponentProps } from 'react-router';
import { withRouter } from 'react-router-dom';
import SettingsPageComponent from 'components/settings-page/settings-page';
import {
CombinedState,
} from 'reducers/interfaces';
interface StateToProps {
jobInstance: any;
}
function mapStateToProps(state: CombinedState): StateToProps {
const {
annotation: {
job: {
instance: jobInstance,
},
},
} = state;
return {
jobInstance,
};
}
type Props = StateToProps & RouteComponentProps;
class SettingsPageContainer extends React.PureComponent<Props> {
private unblock: any;
public componentDidMount(): void {
const {
history,
jobInstance,
} = this.props;
this.unblock = history.block((location: any) => {
if (jobInstance && jobInstance.annotations.hasUnsavedChanges()
&& location.pathname !== `/tasks/${jobInstance.task.id}/jobs/${jobInstance.id}`) {
return 'You have unsaved changes, please confirm leaving this page.';
}
return undefined;
});
this.beforeUnloadCallback = this.beforeUnloadCallback.bind(this);
window.addEventListener('beforeunload', this.beforeUnloadCallback);
}
public componentWillUnmount(): void {
window.removeEventListener('beforeunload', this.beforeUnloadCallback);
this.unblock();
}
private beforeUnloadCallback(event: BeforeUnloadEvent): any {
const { jobInstance } = this.props;
if (jobInstance.annotations.hasUnsavedChanges()) {
const confirmationMessage = 'You have unsaved changes, please confirm leaving this page.';
// eslint-disable-next-line no-param-reassign
event.returnValue = confirmationMessage;
return confirmationMessage;
}
return undefined;
}
public render(): JSX.Element {
return (
<SettingsPageComponent {...this.props} />
);
}
}
export default withRouter(
connect(
mapStateToProps,
)(SettingsPageContainer),
);

@ -2,7 +2,6 @@
// //
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
import React from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { import {

@ -21,6 +21,7 @@ import { getUsersAsync } from 'actions/users-actions';
import { getAboutAsync } from 'actions/about-actions'; import { getAboutAsync } from 'actions/about-actions';
import { getUserAgreementsAsync } from 'actions/useragreements-actions'; import { getUserAgreementsAsync } from 'actions/useragreements-actions';
import { shortcutsActions } from 'actions/shortcuts-actions'; import { shortcutsActions } from 'actions/shortcuts-actions';
import { switchSettingsDialog } from 'actions/settings-actions';
import { import {
resetErrors, resetErrors,
resetMessages, resetMessages,
@ -65,6 +66,7 @@ interface DispatchToProps {
resetMessages: () => void; resetMessages: () => void;
switchShortcutsDialog: () => void; switchShortcutsDialog: () => void;
loadUserAgreements: () => void; loadUserAgreements: () => void;
switchSettingsDialog: (show: boolean) => void;
} }
function mapStateToProps(state: CombinedState): StateToProps { function mapStateToProps(state: CombinedState): StateToProps {
@ -109,6 +111,7 @@ function mapDispatchToProps(dispatch: any): DispatchToProps {
resetErrors: (): void => dispatch(resetErrors()), resetErrors: (): void => dispatch(resetErrors()),
resetMessages: (): void => dispatch(resetMessages()), resetMessages: (): void => dispatch(resetMessages()),
switchShortcutsDialog: (): void => dispatch(shortcutsActions.switchShortcutsDialog()), switchShortcutsDialog: (): void => dispatch(shortcutsActions.switchShortcutsDialog()),
switchSettingsDialog: (): void => dispatch(switchSettingsDialog()),
}; };
} }

@ -429,6 +429,7 @@ export enum ColorBy {
} }
export interface PlayerSettingsState { export interface PlayerSettingsState {
canvasBackgroundColor: string;
frameStep: number; frameStep: number;
frameSpeed: FrameSpeed; frameSpeed: FrameSpeed;
resetZoom: boolean; resetZoom: boolean;
@ -464,6 +465,7 @@ export interface SettingsState {
shapes: ShapesSettingsState; shapes: ShapesSettingsState;
workspace: WorkspaceSettingsState; workspace: WorkspaceSettingsState;
player: PlayerSettingsState; player: PlayerSettingsState;
showDialog: boolean;
} }
export interface ShortcutsState { export interface ShortcutsState {

@ -14,7 +14,7 @@ import { AboutActionTypes } from 'actions/about-actions';
import { AnnotationActionTypes } from 'actions/annotation-actions'; import { AnnotationActionTypes } from 'actions/annotation-actions';
import { NotificationsActionType } from 'actions/notification-actions'; import { NotificationsActionType } from 'actions/notification-actions';
import { BoundariesActionTypes } from 'actions/boundaries-actions'; import { BoundariesActionTypes } from 'actions/boundaries-actions';
import { UserAgreementsActions, UserAgreementsActionTypes } from 'actions/useragreements-actions'; import { UserAgreementsActionTypes } from 'actions/useragreements-actions';
import { NotificationsState } from './interfaces'; import { NotificationsState } from './interfaces';

@ -34,6 +34,7 @@ const defaultState: SettingsState = {
showAllInterpolationTracks: false, showAllInterpolationTracks: false,
}, },
player: { player: {
canvasBackgroundColor: '#ffffff',
frameStep: 10, frameStep: 10,
frameSpeed: FrameSpeed.Usual, frameSpeed: FrameSpeed.Usual,
resetZoom: false, resetZoom: false,
@ -46,6 +47,7 @@ const defaultState: SettingsState = {
contrastLevel: 100, contrastLevel: 100,
saturationLevel: 100, saturationLevel: 100,
}, },
showDialog: false,
}; };
export default (state = defaultState, action: AnyAction): SettingsState => { export default (state = defaultState, action: AnyAction): SettingsState => {
@ -257,6 +259,21 @@ export default (state = defaultState, action: AnyAction): SettingsState => {
}, },
}; };
} }
case SettingsActionTypes.CHANGE_CANVAS_BACKGROUND_COLOR: {
return {
...state,
player: {
...state.player,
canvasBackgroundColor: action.payload.color,
},
};
}
case SettingsActionTypes.SWITCH_SETTINGS_DIALOG: {
return {
...state,
showDialog: typeof action.payload.show === 'undefined' ? !state.showDialog : action.payload.show,
};
}
case BoundariesActionTypes.RESET_AFTER_ERROR: case BoundariesActionTypes.RESET_AFTER_ERROR:
case AnnotationActionTypes.GET_JOB_SUCCESS: { case AnnotationActionTypes.GET_JOB_SUCCESS: {
const { job } = action.payload; const { job } = action.payload;

@ -27,9 +27,9 @@ const defaultKeyMap = {
sequences: ['f1'], sequences: ['f1'],
action: 'keydown', action: 'keydown',
}, },
OPEN_SETTINGS: { SWITCH_SETTINGS: {
name: 'Open settings', name: 'Show settings',
description: 'Go to the settings page or go back', description: 'Open/hide settings dialog',
sequences: ['f2'], sequences: ['f2'],
action: 'keydown', action: 'keydown',
}, },

@ -10,8 +10,8 @@ export function isPublic(): boolean {
return process.env.PUBLIC_INSTANCE === 'true'; return process.env.PUBLIC_INSTANCE === 'true';
} }
export function customWaViewHit(pageName?: string, queryString?: string, hashInfo?: string) { export function customWaViewHit(pageName?: string, queryString?: string, hashInfo?: string): void {
const waHitFunctionName = process.env.WA_PAGE_VIEW_HIT const waHitFunctionName = process.env.WA_PAGE_VIEW_HIT;
if (waHitFunctionName) { if (waHitFunctionName) {
const waHitFunction = new Function('pageName', 'queryString', 'hashInfo', const waHitFunction = new Function('pageName', 'queryString', 'hashInfo',
`if (typeof ${waHitFunctionName} === 'function') { `if (typeof ${waHitFunctionName} === 'function') {

@ -5,8 +5,7 @@ export function clamp(value: number, min: number, max: number): number {
export function shift<T>(array: Array<T>, k: number): Array<T> { export function shift<T>(array: Array<T>, k: number): Array<T> {
if (k % array.length !== 0) { if (k % array.length !== 0) {
return array.slice(k % array.length).concat(array.slice(0,k % array.length)); return array.slice(k % array.length).concat(array.slice(0, k % array.length));
} else {
return array;
} }
return array;
} }
Loading…
Cancel
Save