Merge remote-tracking branch 'upstream/develop' into dkru/cypress-test-issue-2418

main
Kruchinin 5 years ago
commit d8f01de506

@ -13,7 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
-
- PATCH requests from cvat-core submit only changed fields (<https://github.com/openvinotoolkit/cvat/pull/2445>)
### Deprecated
@ -29,6 +29,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Saving relative paths in dummy chunks instead of absolute (<https://github.com/openvinotoolkit/cvat/pull/2424>)
- Objects with a specific label cannot be displayed if at least one tag with the label exist (<https://github.com/openvinotoolkit/cvat/pull/2435>)
- Wrong attribute can be removed in labels editor (<https://github.com/openvinotoolkit/cvat/pull/2436>)
- UI fails with the error "Cannot read property 'label' of undefined" (<https://github.com/openvinotoolkit/cvat/pull/2442>)
- Exception: "Value must be a user instance" (<https://github.com/openvinotoolkit/cvat/pull/2441>)
- Reset zoom option doesn't work in tag annotation mode (<https://github.com/openvinotoolkit/cvat/pull/2443>)
- Canvas is busy error (<https://github.com/openvinotoolkit/cvat/pull/2437>)
### Security

File diff suppressed because it is too large Load Diff

@ -1,6 +1,6 @@
{
"name": "cvat-core",
"version": "3.9.0",
"version": "3.9.1",
"description": "Part of Computer Vision Tool which presents an interface for client-side integration",
"main": "babel.config.js",
"scripts": {
@ -39,7 +39,7 @@
"detect-browser": "^5.2.0",
"error-stack-parser": "^2.0.2",
"form-data": "^2.5.0",
"jest-config": "^24.8.0",
"jest-config": "^26.0.0",
"js-cookie": "^2.2.0",
"jsonpath": "^1.0.2",
"platform": "^1.3.5",

@ -674,6 +674,11 @@
task: undefined,
};
let updatedFields = {
assignee: false,
status: false,
};
for (const property in data) {
if (Object.prototype.hasOwnProperty.call(data, property)) {
if (property in initialData) {
@ -715,6 +720,7 @@
if (assignee !== null && !(assignee instanceof User)) {
throw new ArgumentError('Value must be a user instance');
}
updatedFields.assignee = true;
data.assignee = assignee;
},
},
@ -743,6 +749,7 @@
);
}
updatedFields.status = true;
data.status = status;
},
},
@ -776,6 +783,12 @@
task: {
get: () => data.task,
},
__updatedFields: {
get: () => updatedFields,
set: (fields) => {
updatedFields = fields;
},
},
}),
);
@ -879,6 +892,13 @@
use_cache: undefined,
};
let updatedFields = {
name: false,
assignee: false,
bug_tracker: false,
labels: false,
};
for (const property in data) {
if (Object.prototype.hasOwnProperty.call(data, property) && property in initialData) {
data[property] = initialData[property];
@ -948,6 +968,7 @@
if (!value.trim().length) {
throw new ArgumentError('Value must not be empty');
}
updatedFields.name = true;
data.name = value;
},
},
@ -1006,6 +1027,7 @@
if (assignee !== null && !(assignee instanceof User)) {
throw new ArgumentError('Value must be a user instance');
}
updatedFields.assignee = true;
data.assignee = assignee;
},
},
@ -1039,6 +1061,7 @@
bugTracker: {
get: () => data.bug_tracker,
set: (tracker) => {
updatedFields.bug_tracker = true;
data.bug_tracker = tracker;
},
},
@ -1145,6 +1168,7 @@
}
}
updatedFields.labels = true;
data.labels = [...labels];
},
},
@ -1311,6 +1335,12 @@
dataChunkType: {
get: () => data.data_compressed_chunk_type,
},
__updatedFields: {
get: () => updatedFields,
set: (fields) => {
updatedFields = fields;
},
},
}),
);
@ -1443,12 +1473,30 @@
Job.prototype.save.implementation = async function () {
// TODO: Add ability to change an assignee
if (this.id) {
const jobData = {
status: this.status,
assignee_id: this.assignee ? this.assignee.id : null,
};
const jobData = {};
for (const [field, isUpdated] of Object.entries(this.__updatedFields)) {
if (isUpdated) {
switch (field) {
case 'status':
jobData.status = this.status;
break;
case 'assignee':
jobData.assignee_id = this.assignee ? this.assignee.id : null;
break;
default:
break;
}
}
}
await serverProxy.jobs.saveJob(this.id, jobData);
this.__updatedFields = {
status: false,
assignee: false,
};
return this;
}
@ -1653,14 +1701,38 @@
// TODO: Add ability to change an owner and an assignee
if (typeof this.id !== 'undefined') {
// If the task has been already created, we update it
const taskData = {
assignee_id: this.assignee ? this.assignee.id : null,
name: this.name,
bug_tracker: this.bugTracker,
labels: [...this.labels.map((el) => el.toJSON())],
};
const taskData = {};
for (const [field, isUpdated] of Object.entries(this.__updatedFields)) {
if (isUpdated) {
switch (field) {
case 'assignee':
taskData.assignee_id = this.assignee ? this.assignee.id : null;
break;
case 'name':
taskData.name = this.name;
break;
case 'bug_tracker':
taskData.bug_tracker = this.bugTracker;
break;
case 'labels':
taskData.labels = [...this.labels.map((el) => el.toJSON())];
break;
default:
break;
}
}
}
await serverProxy.tasks.saveTask(this.id, taskData);
this.updatedFields = {
assignee: false,
name: false,
bugTracker: false,
labels: false,
};
return this;
}

@ -1,6 +1,6 @@
{
"name": "cvat-ui",
"version": "1.10.2",
"version": "1.10.6",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@ -1213,9 +1213,9 @@
"dev": true
},
"@types/react": {
"version": "16.9.53",
"resolved": "https://registry.npmjs.org/@types/react/-/react-16.9.53.tgz",
"integrity": "sha512-4nW60Sd4L7+WMXH1D6jCdVftuW7j4Za6zdp6tJ33Rqv0nk1ZAmQKML9ZLD4H0dehA3FZxXR/GM8gXplf82oNGw==",
"version": "16.9.55",
"resolved": "https://registry.npmjs.org/@types/react/-/react-16.9.55.tgz",
"integrity": "sha512-6KLe6lkILeRwyyy7yG9rULKJ0sXplUsl98MGoCfpteXf9sPWFWWMknDcsvubcpaTdBuxtsLF6HDUwdApZL/xIg==",
"requires": {
"@types/prop-types": "*",
"csstype": "^3.0.2"
@ -1231,9 +1231,9 @@
}
},
"@types/react-dom": {
"version": "16.9.8",
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-16.9.8.tgz",
"integrity": "sha512-ykkPQ+5nFknnlU6lDd947WbQ6TE3NNzbQAkInC2EKY1qeYdTKp7onFusmYZb+ityzx2YviqT6BXSu+LyWWJwcA==",
"version": "16.9.9",
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-16.9.9.tgz",
"integrity": "sha512-jE16FNWO3Logq/Lf+yvEAjKzhpST/Eac8EMd1i4dgZdMczfgqC8EjpxwNgEe3SExHYLliabXDh9DEhhqnlXJhg==",
"requires": {
"@types/react": "*"
}
@ -1854,9 +1854,9 @@
}
},
"antd": {
"version": "3.26.19",
"resolved": "https://registry.npmjs.org/antd/-/antd-3.26.19.tgz",
"integrity": "sha512-NcSaI0jMLhdPBoTC7p9qqe8aF9Y+YHWNPNpORY98qYADvO2aXHwyRi0YUAZLauDCvDWNTfeiACBeQaFvUhXApQ==",
"version": "3.26.20",
"resolved": "https://registry.npmjs.org/antd/-/antd-3.26.20.tgz",
"integrity": "sha512-VIous4ofZfxFtd9K1h9MpRX2sDDpj3QcOFi3YgIc9B/uyDli/GlLb8SWKfQfJaMkaxwatIv503dag2Tog+hiEg==",
"requires": {
"@ant-design/create-react-context": "^0.2.4",
"@ant-design/icons": "~2.1.1",
@ -3956,9 +3956,9 @@
}
},
"csstype": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.4.tgz",
"integrity": "sha512-xc8DUsCLmjvCfoD7LTGE0ou2MIWLx0K9RCZwSHMOdynqRsP4MtUcLeqh1HcQ2dInwDTqn+3CE0/FZh1et+p4jA=="
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.5.tgz",
"integrity": "sha512-uVDi8LpBUKQj6sdxNaTetL6FpeCqTjOvAQuQUa/qAqq8oOd4ivkbhgnqayl0dnPal8Tb/yB1tF+gOvCBiicaiQ=="
},
"currently-unhandled": {
"version": "0.4.1",
@ -28927,15 +28927,43 @@
"integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA=="
},
"react-redux": {
"version": "7.2.1",
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.1.tgz",
"integrity": "sha512-T+VfD/bvgGTUA74iW9d2i5THrDQWbweXP0AVNI8tNd1Rk5ch1rnMiJkDD67ejw7YBKM4+REvcvqRuWJb7BLuEg==",
"version": "7.2.2",
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.2.tgz",
"integrity": "sha512-8+CQ1EvIVFkYL/vu6Olo7JFLWop1qRUeb46sGtIMDCSpgwPQq8fPLpirIB0iTqFe9XYEFPHssdX8/UwN6pAkEA==",
"requires": {
"@babel/runtime": "^7.5.5",
"hoist-non-react-statics": "^3.3.0",
"@babel/runtime": "^7.12.1",
"hoist-non-react-statics": "^3.3.2",
"loose-envify": "^1.4.0",
"prop-types": "^15.7.2",
"react-is": "^16.9.0"
"react-is": "^16.13.1"
},
"dependencies": {
"@babel/runtime": {
"version": "7.12.5",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.12.5.tgz",
"integrity": "sha512-plcc+hbExy3McchJCEQG3knOsuh3HH+Prx1P6cLIkET/0dLuQDEnrT+s27Axgc9bqfsmNUNHfscgMUdBpC9xfg==",
"requires": {
"regenerator-runtime": "^0.13.4"
}
},
"hoist-non-react-statics": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
"integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
"requires": {
"react-is": "^16.7.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=="
},
"regenerator-runtime": {
"version": "0.13.7",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz",
"integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew=="
}
}
},
"react-router": {

@ -1,6 +1,6 @@
{
"name": "cvat-ui",
"version": "1.10.2",
"version": "1.10.6",
"description": "CVAT single-page application",
"main": "src/index.tsx",
"scripts": {
@ -49,15 +49,15 @@
"dependencies": {
"@types/lodash": "^4.14.165",
"@types/platform": "^1.3.3",
"@types/react": "^16.9.53",
"@types/react": "^16.9.55",
"@types/react-color": "^3.0.4",
"@types/react-dom": "^16.9.0",
"@types/react-dom": "^16.9.9",
"@types/react-redux": "^7.1.2",
"@types/react-router": "^5.0.5",
"@types/react-router-dom": "^5.1.6",
"@types/react-share": "^3.0.3",
"@types/redux-logger": "^3.0.8",
"antd": "^3.26.19",
"antd": "^3.26.20",
"copy-to-clipboard": "^3.3.1",
"cvat-canvas": "file:../cvat-canvas",
"cvat-core": "file:../cvat-core",
@ -72,7 +72,7 @@
"react-cookie": "^4.0.3",
"react-dom": "^16.14.0",
"react-hotkeys": "^2.0.0",
"react-redux": "^7.1.1",
"react-redux": "^7.2.2",
"react-router": "^5.1.0",
"react-router-dom": "^5.1.0",
"react-share": "^3.0.1",

@ -10,7 +10,9 @@ import Icon from 'antd/lib/icon';
import Layout from 'antd/lib/layout/layout';
import Slider, { SliderValue } from 'antd/lib/slider';
import { ColorBy, GridColor, ObjectType, ContextMenuType, Workspace, ShapeType } from 'reducers/interfaces';
import {
ColorBy, GridColor, ObjectType, ContextMenuType, Workspace, ShapeType,
} from 'reducers/interfaces';
import { LogType } from 'cvat-logger';
import { Canvas } from 'cvat-canvas-wrapper';
import getCore from 'cvat-core-wrapper';
@ -217,10 +219,7 @@ export default class CanvasWrapperComponent extends React.PureComponent<Props> {
this.updateCanvas();
}
if (
prevProps.frame !== frameData.number &&
((resetZoom && workspace !== Workspace.ATTRIBUTE_ANNOTATION) || workspace === Workspace.TAG_ANNOTATION)
) {
if (prevProps.frame !== frameData.number && resetZoom && workspace !== Workspace.ATTRIBUTE_ANNOTATION) {
canvasInstance.html().addEventListener(
'canvas.setup',
() => {
@ -304,7 +303,9 @@ export default class CanvasWrapperComponent extends React.PureComponent<Props> {
}
private onCanvasShapeDrawn = (event: any): void => {
const { jobInstance, activeLabelID, activeObjectType, frame, onShapeDrawn, onCreateAnnotations } = this.props;
const {
jobInstance, activeLabelID, activeObjectType, frame, onShapeDrawn, onCreateAnnotations,
} = this.props;
if (!event.detail.continue) {
onShapeDrawn();
@ -327,7 +328,9 @@ export default class CanvasWrapperComponent extends React.PureComponent<Props> {
};
private onCanvasObjectsMerged = (event: any): void => {
const { jobInstance, frame, onMergeAnnotations, onMergeObjects } = this.props;
const {
jobInstance, frame, onMergeAnnotations, onMergeObjects,
} = this.props;
onMergeObjects(false);
@ -340,7 +343,9 @@ export default class CanvasWrapperComponent extends React.PureComponent<Props> {
};
private onCanvasObjectsGroupped = (event: any): void => {
const { jobInstance, frame, onGroupAnnotations, onGroupObjects } = this.props;
const {
jobInstance, frame, onGroupAnnotations, onGroupObjects,
} = this.props;
onGroupObjects(false);
@ -349,7 +354,9 @@ export default class CanvasWrapperComponent extends React.PureComponent<Props> {
};
private onCanvasTrackSplitted = (event: any): void => {
const { jobInstance, frame, onSplitAnnotations, onSplitTrack } = this.props;
const {
jobInstance, frame, onSplitAnnotations, onSplitTrack,
} = this.props;
onSplitTrack(false);
@ -429,7 +436,9 @@ export default class CanvasWrapperComponent extends React.PureComponent<Props> {
};
private onCanvasCursorMoved = async (event: any): Promise<void> => {
const { jobInstance, activatedStateID, workspace, onActivateObject } = this.props;
const {
jobInstance, activatedStateID, workspace, onActivateObject,
} = this.props;
if (workspace !== Workspace.STANDARD) {
return;
@ -560,7 +569,9 @@ export default class CanvasWrapperComponent extends React.PureComponent<Props> {
}
private updateShapesView(): void {
const { annotations, opacity, colorBy, outlined, outlineColor } = this.props;
const {
annotations, opacity, colorBy, outlined, outlineColor,
} = this.props;
for (const state of annotations) {
let shapeColor = '';
@ -588,7 +599,9 @@ export default class CanvasWrapperComponent extends React.PureComponent<Props> {
}
private updateCanvas(): void {
const { curZLayer, annotations, frameData, canvasInstance } = this.props;
const {
curZLayer, annotations, frameData, canvasInstance,
} = this.props;
if (frameData !== null) {
canvasInstance.setup(

@ -109,7 +109,7 @@ function PlayerButtons(props: Props): JSX.Element {
<Popover
trigger='contextMenu'
placement='bottom'
content={
content={(
<>
<Tooltip title={`${prevRegularText}`} mouseLeaveDelay={0}>
<Icon
@ -139,7 +139,7 @@ function PlayerButtons(props: Props): JSX.Element {
/>
</Tooltip>
</>
}
)}
>
<Tooltip
placement='top'
@ -163,7 +163,7 @@ function PlayerButtons(props: Props): JSX.Element {
<Popover
trigger='contextMenu'
placement='bottom'
content={
content={(
<>
<Tooltip title={`${nextRegularText}`} mouseLeaveDelay={0}>
<Icon
@ -193,7 +193,7 @@ function PlayerButtons(props: Props): JSX.Element {
/>
</Tooltip>
</>
}
)}
>
<Tooltip placement='top' mouseLeaveDelay={0} title={`${nextButtonTooltipMessage} ${nextFrameShortcut}`}>
{nextButton}

@ -83,13 +83,7 @@ export default function UserSelector(props: Props): JSX.Element {
if (value && !users.filter((user) => user.id === value.id).length) {
core.users.get({ id: value.id }).then((result: User[]) => {
const [user] = result;
setUsers([
...users,
{
id: user.id,
username: user.username,
},
]);
setUsers([...users, user]);
setSearchPhrase(user.username);
});
}

@ -24,7 +24,10 @@ function mapStateToProps(state: CombinedState): StateToProps {
annotation: {
annotations: { activatedStateID, collapsed, states: objectStates },
canvas: {
contextMenu: { visible, top, left, type },
contextMenu: {
visible, top, left, type,
},
ready,
},
},
} = state;
@ -33,7 +36,11 @@ function mapStateToProps(state: CombinedState): StateToProps {
activatedStateID,
collapsed: activatedStateID !== null ? collapsed[activatedStateID] : undefined,
objectStates,
visible,
visible:
activatedStateID !== null &&
visible &&
ready &&
objectStates.map((_state: any): number => _state.clientID).includes(activatedStateID),
left,
top,
type,
@ -166,7 +173,9 @@ class CanvasContextMenuContainer extends React.PureComponent<Props, State> {
public render(): JSX.Element {
const { left, top } = this.state;
const { visible, activatedStateID, objectStates, type } = this.props;
const {
visible, activatedStateID, objectStates, type,
} = this.props;
return (
<>

@ -7,7 +7,9 @@ import copy from 'copy-to-clipboard';
import { connect } from 'react-redux';
import { LogType } from 'cvat-logger';
import { ActiveControl, CombinedState, ColorBy, ShapeType } from 'reducers/interfaces';
import {
ActiveControl, CombinedState, ColorBy, ShapeType,
} from 'reducers/interfaces';
import {
collapseObjectItems,
updateAnnotationsAsync,
@ -83,40 +85,25 @@ function mapStateToProps(state: CombinedState, own: OwnProps): StateToProps {
const stateIDs = states.map((_state: any): number => _state.clientID);
const index = stateIDs.indexOf(clientID);
try {
const collapsedState =
typeof statesCollapsed[clientID] === 'undefined' ? initialCollapsed : statesCollapsed[clientID];
return {
objectState: states[index],
collapsed: collapsedState,
attributes: jobAttributes[states[index].label.id],
labels,
ready,
activeControl,
colorBy,
jobInstance,
frameNumber,
activated: activatedStateID === clientID,
minZLayer,
maxZLayer,
normalizedKeyMap,
aiToolsRef,
};
} catch (exception) {
// we have an exception here sometimes
// but I cannot understand when it happens and what is the root reason
// maybe this temporary hack helps us
const dataObject = {
index,
frameNumber,
clientID: own.clientID,
stateIDs,
};
throw new Error(
`${exception.toString()} in mapStateToProps of ObjectItemContainer. Data are ${JSON.stringify(dataObject)}`,
);
}
const collapsedState =
typeof statesCollapsed[clientID] === 'undefined' ? initialCollapsed : statesCollapsed[clientID];
return {
objectState: states[index],
collapsed: collapsedState,
attributes: jobAttributes[states[index].label.id],
labels,
ready,
activeControl,
colorBy,
jobInstance,
frameNumber,
activated: activatedStateID === clientID,
minZLayer,
maxZLayer,
normalizedKeyMap,
aiToolsRef,
};
}
function mapDispatchToProps(dispatch: any): DispatchToProps {
@ -219,7 +206,9 @@ class ObjectItemContainer extends React.PureComponent<Props> {
};
private activate = (): void => {
const { activateObject, objectState, ready, activeControl } = this.props;
const {
activateObject, objectState, ready, activeControl,
} = this.props;
if (ready && activeControl === ActiveControl.CURSOR) {
activateObject(objectState.clientID);
@ -324,7 +313,9 @@ class ObjectItemContainer extends React.PureComponent<Props> {
}
public render(): JSX.Element {
const { objectState, collapsed, labels, attributes, activated, colorBy, normalizedKeyMap } = this.props;
const {
objectState, collapsed, labels, attributes, activated, colorBy, normalizedKeyMap,
} = this.props;
let stateColor = '';
if (colorBy === ColorBy.INSTANCE) {

@ -231,7 +231,9 @@ class AnnotationTopBarContainer extends React.PureComponent<Props, State> {
}
private undo = (): void => {
const { undo, jobInstance, frameNumber, canvasInstance } = this.props;
const {
undo, jobInstance, frameNumber, canvasInstance,
} = this.props;
if (canvasInstance.isAbleToChangeFrame()) {
undo(jobInstance, frameNumber);
@ -239,7 +241,9 @@ class AnnotationTopBarContainer extends React.PureComponent<Props, State> {
};
private redo = (): void => {
const { redo, jobInstance, frameNumber, canvasInstance } = this.props;
const {
redo, jobInstance, frameNumber, canvasInstance,
} = this.props;
if (canvasInstance.isAbleToChangeFrame()) {
redo(jobInstance, frameNumber);
@ -253,7 +257,9 @@ class AnnotationTopBarContainer extends React.PureComponent<Props, State> {
};
private onSwitchPlay = (): void => {
const { frameNumber, jobInstance, onSwitchPlay, playing } = this.props;
const {
frameNumber, jobInstance, onSwitchPlay, playing,
} = this.props;
if (playing) {
onSwitchPlay(false);
@ -263,7 +269,9 @@ class AnnotationTopBarContainer extends React.PureComponent<Props, State> {
};
private onFirstFrame = (): void => {
const { frameNumber, jobInstance, playing, onSwitchPlay } = this.props;
const {
frameNumber, jobInstance, playing, onSwitchPlay,
} = this.props;
const newFrame = jobInstance.startFrame;
if (newFrame !== frameNumber) {
@ -275,7 +283,9 @@ class AnnotationTopBarContainer extends React.PureComponent<Props, State> {
};
private onBackward = (): void => {
const { frameNumber, frameStep, jobInstance, playing, onSwitchPlay } = this.props;
const {
frameNumber, frameStep, jobInstance, playing, onSwitchPlay,
} = this.props;
const newFrame = Math.max(jobInstance.startFrame, frameNumber - frameStep);
if (newFrame !== frameNumber) {
@ -288,7 +298,9 @@ class AnnotationTopBarContainer extends React.PureComponent<Props, State> {
private onPrevFrame = (): void => {
const { prevButtonType } = this.state;
const { frameNumber, jobInstance, playing, onSwitchPlay, searchAnnotations, searchEmptyFrame } = this.props;
const {
frameNumber, jobInstance, playing, onSwitchPlay,
} = this.props;
const { startFrame } = jobInstance;
const newFrame = Math.max(jobInstance.startFrame, frameNumber - 1);
@ -296,19 +308,22 @@ class AnnotationTopBarContainer extends React.PureComponent<Props, State> {
if (playing) {
onSwitchPlay(false);
}
if (prevButtonType === 'regular') {
this.changeFrame(newFrame);
} else if (prevButtonType === 'filtered') {
searchAnnotations(jobInstance, frameNumber - 1, startFrame);
this.searchAnnotations(frameNumber - 1, startFrame);
} else {
searchEmptyFrame(jobInstance, frameNumber - 1, startFrame);
this.searchEmptyFrame(frameNumber - 1, startFrame);
}
}
};
private onNextFrame = (): void => {
const { nextButtonType } = this.state;
const { frameNumber, jobInstance, playing, onSwitchPlay, searchAnnotations, searchEmptyFrame } = this.props;
const {
frameNumber, jobInstance, playing, onSwitchPlay,
} = this.props;
const { stopFrame } = jobInstance;
const newFrame = Math.min(jobInstance.stopFrame, frameNumber + 1);
@ -316,18 +331,21 @@ class AnnotationTopBarContainer extends React.PureComponent<Props, State> {
if (playing) {
onSwitchPlay(false);
}
if (nextButtonType === 'regular') {
this.changeFrame(newFrame);
} else if (nextButtonType === 'filtered') {
searchAnnotations(jobInstance, frameNumber + 1, stopFrame);
this.searchAnnotations(frameNumber + 1, stopFrame);
} else {
searchEmptyFrame(jobInstance, frameNumber + 1, stopFrame);
this.searchEmptyFrame(frameNumber + 1, stopFrame);
}
}
};
private onForward = (): void => {
const { frameNumber, frameStep, jobInstance, playing, onSwitchPlay } = this.props;
const {
frameNumber, frameStep, jobInstance, playing, onSwitchPlay,
} = this.props;
const newFrame = Math.min(jobInstance.stopFrame, frameNumber + frameStep);
if (newFrame !== frameNumber) {
@ -339,7 +357,9 @@ class AnnotationTopBarContainer extends React.PureComponent<Props, State> {
};
private onLastFrame = (): void => {
const { frameNumber, jobInstance, playing, onSwitchPlay } = this.props;
const {
frameNumber, jobInstance, playing, onSwitchPlay,
} = this.props;
const newFrame = jobInstance.stopFrame;
if (newFrame !== frameNumber) {
@ -418,6 +438,20 @@ class AnnotationTopBarContainer extends React.PureComponent<Props, State> {
}
}
private searchAnnotations(start: number, stop: number): void {
const { canvasInstance, jobInstance, searchAnnotations } = this.props;
if (canvasInstance.isAbleToChangeFrame()) {
searchAnnotations(jobInstance, start, stop);
}
}
private searchEmptyFrame(start: number, stop: number): void {
const { canvasInstance, jobInstance, searchAnnotations } = this.props;
if (canvasInstance.isAbleToChangeFrame()) {
searchAnnotations(jobInstance, start, stop);
}
}
public render(): JSX.Element {
const { nextButtonType, prevButtonType } = this.state;
const {

@ -0,0 +1,37 @@
# REST API design principles
## REST API scheme
Common scheme for our REST API is `<VERB> [namespace] <objects> <id> <action>`.
- `VERB` can be `POST`, `GET`, `PATCH`, `PUT`, `DELETE`.
- `namespace` should scope some specific functionality like `auth`, `lambda`.
It is optional in the scheme.
- Typical `objects` are `tasks`, `projects`, `jobs`.
- When you want to extract a specific object from a collection, just specify its `id`.
- An `action` can be used to simplify REST API or provide an endpoint for entities
without `objects` endpoint like `annotations`, `data`, `data/meta`. Note: action
should not duplicate other endpoints without a reason.
## Design principles
- Use nouns instead of verbs in endpoint paths. For example,
`POST /api/v1/tasks` instead of `POST /api/v1/tasks/create`.
- Accept and respond with JSON whenever it is possible
- Name collections with plural nouns (e.g. `/tasks`, `/projects`)
- Try to keep the API structure flat. Prefer two separate endpoints
for `/projects` and `/tasks` instead of `/projects/:id1/tasks/:id2`. Use
filters to extract necessary information like `/tasks/:id2?project=:id1`.
In some cases it is useful to get all `tasks`. If the structure is
hierarchical, it cannot be done easily. Also you have to know both `:id1`
and `:id2` to get information about the task.
_Note: for now we accept `GET /tasks/:id2/jobs` but it should be replaced
by `/jobs?task=:id2` in the future_.
- Handle errors gracefully and return standard error codes (e.g. `201`, `400`)
- Allow filtering, sorting, and pagination
- Maintain good security practices
- Cache data to improve performance
- Versioning our APIs (e.g. `/api/v1`, `/api/v2`). It should be done when you
delete an endpoint or modify its behaviors.
## Links
- [Best practices for REST API design](https://stackoverflow.blog/2020/03/02/best-practices-for-rest-api-design/)
- [Flat vs. nested resources](https://stackoverflow.com/questions/20951419/what-are-best-practices-for-rest-nested-resources)

@ -4,7 +4,7 @@
/// <reference types="cypress" />
import { taskName } from '../../support/const';
import { taskName, labelName } from '../../support/const';
context('Actions on polygon', () => {
const caseId = '10';
@ -12,7 +12,7 @@ context('Actions on polygon', () => {
const createPolygonShape = {
reDraw: false,
type: 'Shape',
switchLabel: false,
labelName: labelName,
pointsMap: [
{ x: 200, y: 200 },
{ x: 250, y: 200 },
@ -24,7 +24,7 @@ context('Actions on polygon', () => {
const createPolygonTrack = {
reDraw: false,
type: 'Track',
switchLabel: false,
labelName: labelName,
pointsMap: [
{ x: 300, y: 200 },
{ x: 350, y: 200 },
@ -36,7 +36,7 @@ context('Actions on polygon', () => {
const createPolygonShapePoints = {
reDraw: false,
type: 'Shape',
switchLabel: false,
labelName: labelName,
pointsMap: [
{ x: 400, y: 200 },
{ x: 450, y: 200 },
@ -49,7 +49,7 @@ context('Actions on polygon', () => {
const createPolygonTrackPoints = {
reDraw: false,
type: 'Track',
switchLabel: false,
labelName: labelName,
pointsMap: [
{ x: 500, y: 200 },
{ x: 550, y: 200 },
@ -62,7 +62,6 @@ context('Actions on polygon', () => {
const createPolygonShapeSwitchLabel = {
reDraw: false,
type: 'Shape',
switchLabel: true,
labelName: newLabelName,
pointsMap: [
{ x: 600, y: 200 },
@ -75,7 +74,6 @@ context('Actions on polygon', () => {
const createPolygonTrackSwitchLabel = {
reDraw: false,
type: 'Track',
switchLabel: true,
labelName: newLabelName,
pointsMap: [
{ x: 700, y: 200 },

@ -4,14 +4,14 @@
/// <reference types="cypress" />
import { taskName } from '../../support/const';
import { taskName, labelName } from '../../support/const';
context('Actions on polylines', () => {
const caseId = '11';
const newLabelName = `New label for case ${caseId}`;
const createPolylinesShape = {
type: 'Shape',
switchLabel: false,
labelName: labelName,
pointsMap: [
{ x: 200, y: 200 },
{ x: 250, y: 200 },
@ -22,7 +22,7 @@ context('Actions on polylines', () => {
};
const createPolylinesTrack = {
type: 'Track',
switchLabel: false,
labelName: labelName,
pointsMap: [
{ x: 300, y: 200 },
{ x: 350, y: 200 },
@ -33,7 +33,7 @@ context('Actions on polylines', () => {
};
const createPolylinesShapePoints = {
type: 'Shape',
switchLabel: false,
labelName: labelName,
pointsMap: [
{ x: 400, y: 200 },
{ x: 450, y: 200 },
@ -45,7 +45,7 @@ context('Actions on polylines', () => {
};
const createPolylinesTrackPoints = {
type: 'Track',
switchLabel: false,
labelName: labelName,
pointsMap: [
{ x: 500, y: 200 },
{ x: 550, y: 200 },
@ -57,7 +57,6 @@ context('Actions on polylines', () => {
};
const createPolylinesShapeSwitchLabel = {
type: 'Shape',
switchLabel: true,
labelName: newLabelName,
pointsMap: [
{ x: 600, y: 200 },
@ -69,7 +68,6 @@ context('Actions on polylines', () => {
};
const createPolylinesTrackSwitchLabel = {
type: 'Track',
switchLabel: true,
labelName: newLabelName,
pointsMap: [
{ x: 700, y: 200 },

@ -4,14 +4,14 @@
/// <reference types="cypress" />
import { taskName } from '../../support/const';
import { taskName, labelName } from '../../support/const';
context('Actions on points', () => {
const caseId = '12';
const newLabelName = `New label for case ${caseId}`;
const createPointsShape = {
type: 'Shape',
switchLabel: false,
labelName: labelName,
pointsMap: [
{ x: 200, y: 200 },
{ x: 250, y: 200 },
@ -22,7 +22,7 @@ context('Actions on points', () => {
};
const createPointsTrack = {
type: 'Track',
switchLabel: false,
labelName: labelName,
pointsMap: [
{ x: 300, y: 200 },
{ x: 350, y: 200 },
@ -33,7 +33,7 @@ context('Actions on points', () => {
};
const createPointsShapePoints = {
type: 'Shape',
switchLabel: false,
labelName: labelName,
pointsMap: [
{ x: 400, y: 200 },
{ x: 450, y: 200 },
@ -45,7 +45,7 @@ context('Actions on points', () => {
};
const createPointsTrackPoints = {
type: 'Track',
switchLabel: false,
labelName: labelName,
pointsMap: [
{ x: 500, y: 200 },
{ x: 550, y: 200 },
@ -57,7 +57,6 @@ context('Actions on points', () => {
};
const createPointsShapeSwitchLabel = {
type: 'Shape',
switchLabel: true,
labelName: newLabelName,
pointsMap: [
{ x: 600, y: 200 },
@ -69,7 +68,6 @@ context('Actions on points', () => {
};
const createPointsTrackSwitchLabel = {
type: 'Track',
switchLabel: true,
labelName: newLabelName,
pointsMap: [
{ x: 700, y: 200 },

@ -4,14 +4,14 @@
/// <reference types="cypress" />
import { taskName } from '../../support/const';
import { taskName, labelName } from '../../support/const';
context('Merge/split features', () => {
const caseId = '13';
const createRectangleShape2Points = {
points: 'By 2 Points',
type: 'Shape',
switchLabel: false,
labelName: labelName,
firstX: 250,
firstY: 350,
secondX: 350,
@ -20,7 +20,7 @@ context('Merge/split features', () => {
const createRectangleShape2PointsSecond = {
points: 'By 2 Points',
type: 'Shape',
switchLabel: false,
labelName: labelName,
firstX: createRectangleShape2Points.firstX + 300,
firstY: createRectangleShape2Points.firstY,
secondX: createRectangleShape2Points.secondX + 300,

@ -4,7 +4,7 @@
/// <reference types="cypress" />
import { taskName } from '../../support/const';
import { taskName, labelName } from '../../support/const';
context('Appearance features', () => {
const caseId = '14';
@ -15,7 +15,7 @@ context('Appearance features', () => {
const createRectangleShape2Points = {
points: 'By 2 Points',
type: 'Shape',
switchLabel: false,
labelName: labelName,
firstX: 100,
firstY: 350,
secondX: 200,
@ -24,7 +24,7 @@ context('Appearance features', () => {
const createPolygonShape = {
reDraw: false,
type: 'Shape',
switchLabel: false,
labelName: labelName,
pointsMap: [
{ x: 250, y: 350 },
{ x: 300, y: 300 },
@ -35,7 +35,7 @@ context('Appearance features', () => {
};
const createPolylinesShape = {
type: 'Shape',
switchLabel: false,
labelName: labelName,
pointsMap: [
{ x: 350, y: 350 },
{ x: 400, y: 300 },
@ -48,7 +48,7 @@ context('Appearance features', () => {
const createCuboidShape2Points = {
points: 'From rectangle',
type: 'Shape',
switchLabel: false,
labelName: labelName,
firstX: 450,
firstY: 350,
secondX: 550,
@ -56,7 +56,7 @@ context('Appearance features', () => {
};
const createPointsShape = {
type: 'Shape',
switchLabel: false,
labelName: labelName,
pointsMap: [{ x: 650, y: 350 }],
complete: true,
numberOfPoints: null,

@ -4,14 +4,14 @@
/// <reference types="cypress" />
import { taskName } from '../../support/const';
import { taskName, labelName } from '../../support/const';
context('Group features', () => {
const caseId = '15';
const createRectangleShape2Points = {
points: 'By 2 Points',
type: 'Shape',
switchLabel: false,
labelName: labelName,
firstX: 250,
firstY: 350,
secondX: 350,
@ -20,7 +20,7 @@ context('Group features', () => {
const createRectangleShape2PointsSecond = {
points: 'By 2 Points',
type: 'Shape',
switchLabel: false,
labelName: labelName,
firstX: createRectangleShape2Points.firstX + 300,
firstY: createRectangleShape2Points.firstY,
secondX: createRectangleShape2Points.secondX + 300,
@ -29,7 +29,7 @@ context('Group features', () => {
const createRectangleTrack2Points = {
points: 'By 2 Points',
type: 'Track',
switchLabel: false,
labelName: labelName,
firstX: 250,
firstY: 600,
secondX: 350,
@ -38,7 +38,7 @@ context('Group features', () => {
const createRectangleTrack2PointsSecond = {
points: 'By 2 Points',
type: 'Track',
switchLabel: false,
labelName: labelName,
firstX: createRectangleTrack2Points.firstX + 300,
firstY: createRectangleTrack2Points.firstY,
secondX: createRectangleTrack2Points.secondX + 300,

@ -4,7 +4,7 @@
/// <reference types="cypress" />
import { taskName } from '../../support/const';
import { taskName, labelName } from '../../support/const';
context('Actions on polygon', () => {
const caseId = '16';
@ -12,7 +12,7 @@ context('Actions on polygon', () => {
const createPolygonShapeFirst = {
reDraw: false,
type: 'Shape',
switchLabel: false,
labelName: labelName,
pointsMap: [
{ x: 340, y: 200 },
{ x: 590, y: 200 },
@ -24,7 +24,7 @@ context('Actions on polygon', () => {
const createPolygonShapeSecond = {
reDraw: false,
type: 'Shape',
switchLabel: false,
labelName: labelName,
pointsMap: [
{ x: 190, y: 210 },
{ x: 440, y: 210 },

@ -16,7 +16,7 @@ context('Lock/hide features.', () => {
const createPolygonShape = {
reDraw: false,
type: 'Shape',
switchLabel: false,
labelName: labelName,
pointsMap: [
{ x: 200, y: 200 },
{ x: 250, y: 200 },
@ -28,7 +28,7 @@ context('Lock/hide features.', () => {
const createRectangleTrack2Points = {
points: 'By 2 Points',
type: 'Track',
switchLabel: false,
labelName: labelName,
firstX: 260,
firstY: 200,
secondX: 360,
@ -37,7 +37,7 @@ context('Lock/hide features.', () => {
const createCuboidShape4Points = {
points: 'By 4 Points',
type: 'Shape',
switchLabel: false,
labelName: labelName,
firstX: 400,
firstY: 350,
secondX: 500,
@ -49,7 +49,6 @@ context('Lock/hide features.', () => {
};
const createPolylinesShapeSwitchLabel = {
type: 'Shape',
switchLabel: true,
labelName: newLabelName1,
pointsMap: [
{ x: 600, y: 200 },
@ -61,7 +60,6 @@ context('Lock/hide features.', () => {
};
const createPointsShapeSwitchLabel = {
type: 'Shape',
switchLabel: true,
labelName: newLabelName2,
pointsMap: [
{ x: 700, y: 200 }
@ -72,7 +70,6 @@ context('Lock/hide features.', () => {
const createRectangleShape4Points = {
points: 'By 4 Points',
type: 'Shape',
switchLabel: true,
labelName: newLabelName3,
firstX: 550,
firstY: 350,
@ -86,7 +83,6 @@ context('Lock/hide features.', () => {
const createPolygonTrack = {
reDraw: false,
type: 'Track',
switchLabel: true,
labelName: newLabelName4,
pointsMap: [
{ x: 700, y: 350 },

@ -4,7 +4,7 @@
/// <reference types="cypress" />
import { taskName } from '../../support/const';
import { taskName, labelName } from '../../support/const';
context('Actions on rectangle', () => {
const caseId = '8';
@ -12,7 +12,7 @@ context('Actions on rectangle', () => {
const createRectangleShape2Points = {
points: 'By 2 Points',
type: 'Shape',
switchLabel: false,
labelName: labelName,
firstX: 250,
firstY: 350,
secondX: 350,
@ -21,7 +21,7 @@ context('Actions on rectangle', () => {
const createRectangleShape4Points = {
points: 'By 4 Points',
type: 'Shape',
switchLabel: false,
labelName: labelName,
firstX: 400,
firstY: 350,
secondX: 500,
@ -34,7 +34,7 @@ context('Actions on rectangle', () => {
const createRectangleTrack2Points = {
points: 'By 2 Points',
type: 'Track',
switchLabel: false,
labelName: labelName,
firstX: createRectangleShape2Points.firstX,
firstY: createRectangleShape2Points.firstY - 150,
secondX: createRectangleShape2Points.secondX,
@ -43,7 +43,7 @@ context('Actions on rectangle', () => {
const createRectangleTrack4Points = {
points: 'By 4 Points',
type: 'Track',
switchLabel: false,
labelName: labelName,
firstX: createRectangleShape4Points.firstX,
firstY: createRectangleShape4Points.firstY - 150,
secondX: createRectangleShape4Points.secondX - 100,
@ -57,7 +57,6 @@ context('Actions on rectangle', () => {
labelName: newLabelName,
points: 'By 2 Points',
type: 'Shape',
switchLabel: true,
firstX: createRectangleShape2Points.firstX,
firstY: createRectangleShape2Points.firstY + 150,
secondX: createRectangleShape2Points.secondX,
@ -67,7 +66,6 @@ context('Actions on rectangle', () => {
labelName: newLabelName,
points: 'By 4 Points',
type: 'Shape',
switchLabel: true,
firstX: createRectangleShape4Points.firstX,
firstY: createRectangleShape4Points.firstY + 150,
secondX: createRectangleShape4Points.secondX,

@ -4,7 +4,7 @@
/// <reference types="cypress" />
import { taskName } from '../../support/const';
import { taskName, labelName } from '../../support/const';
context('Actions on Cuboid', () => {
const caseId = '9';
@ -12,7 +12,7 @@ context('Actions on Cuboid', () => {
const createCuboidShape2Points = {
points: 'From rectangle',
type: 'Shape',
switchLabel: false,
labelName: labelName,
firstX: 250,
firstY: 350,
secondX: 350,
@ -21,7 +21,7 @@ context('Actions on Cuboid', () => {
const createCuboidShape4Points = {
points: 'By 4 Points',
type: 'Shape',
switchLabel: false,
labelName: labelName,
firstX: 400,
firstY: 350,
secondX: 500,
@ -34,7 +34,7 @@ context('Actions on Cuboid', () => {
const createCuboidTrack2Points = {
points: 'From rectangle',
type: 'Track',
switchLabel: false,
labelName: labelName,
firstX: createCuboidShape2Points.firstX,
firstY: createCuboidShape2Points.firstY - 150,
secondX: createCuboidShape2Points.secondX,
@ -43,7 +43,7 @@ context('Actions on Cuboid', () => {
const createCuboidTrack4Points = {
points: 'By 4 Points',
type: 'Track',
switchLabel: false,
labelName: labelName,
firstX: createCuboidShape4Points.firstX,
firstY: createCuboidShape4Points.firstY - 150,
secondX: createCuboidShape4Points.secondX - 100,
@ -57,7 +57,6 @@ context('Actions on Cuboid', () => {
labelName: newLabelName,
points: 'From rectangle',
type: 'Shape',
switchLabel: true,
firstX: createCuboidShape2Points.firstX,
firstY: createCuboidShape2Points.firstY + 150,
secondX: createCuboidShape2Points.secondX,
@ -67,7 +66,6 @@ context('Actions on Cuboid', () => {
labelName: newLabelName,
points: 'By 4 Points',
type: 'Shape',
switchLabel: true,
firstX: createCuboidShape4Points.firstX,
firstY: createCuboidShape4Points.firstY + 150,
secondX: createCuboidShape4Points.secondX,

@ -4,14 +4,14 @@
/// <reference types="cypress" />
import { taskName } from '../../support/const';
import { taskName, labelName } from '../../support/const';
context('Check if UI not fails with shape dragging over sidebar', () => {
const issueId = '1216';
const createRectangleShape2Points = {
points: 'By 2 Points',
type: 'Shape',
switchLabel: false,
labelName: labelName,
firstX: 250,
firstY: 350,
secondX: 350,
@ -20,7 +20,7 @@ context('Check if UI not fails with shape dragging over sidebar', () => {
const createRectangleShape2PointsSecond = {
points: 'By 2 Points',
type: 'Shape',
switchLabel: false,
labelName: labelName,
firstX: createRectangleShape2Points.firstX,
firstY: createRectangleShape2Points.firstY - 150,
secondX: createRectangleShape2Points.secondX,

@ -4,13 +4,13 @@
/// <reference types="cypress" />
import { taskName } from '../../support/const';
import { taskName, labelName } from '../../support/const';
context('Points track it is still invisible on next frames', () => {
const issueId = '1368';
const createPointsTrack = {
type: 'Track',
switchLabel: false,
labelName: labelName,
pointsMap: [{ x: 300, y: 410 }],
complete: true,
numberOfPoints: null,

@ -4,7 +4,7 @@
/// <reference types="cypress" />
import { taskName } from '../../support/const';
import { taskName, labelName } from '../../support/const';
context('When delete a point, the required point is deleted.', () => {
const issueId = '1391';
@ -12,7 +12,7 @@ context('When delete a point, the required point is deleted.', () => {
let pointsСoordinatesAfterDeletePoint = [];
const createPolylinesShape = {
type: 'Shape',
switchLabel: false,
labelName: labelName,
pointsMap: [
{ x: 309, y: 250 },
{ x: 309, y: 350 },

@ -12,7 +12,7 @@ context('The highlighted attribute in AAM should correspond to the chosen attrib
const createRectangleShape2Points = {
points: 'By 2 Points',
type: 'Shape',
switchLabel: false,
labelName: labelName,
firstX: 250,
firstY: 350,
secondX: 350,

@ -4,16 +4,15 @@
/// <reference types="cypress" />
import { taskName } from '../../support/const';
import { taskName, labelName } from '../../support/const';
context('Check if the new label reflects in the options', () => {
const issueId = '1429';
const labelName = `Issue ${issueId}`;
const newLabelName = `New ${labelName}`;
const createRectangleShape2Points = {
points: 'By 2 Points',
type: 'Shape',
switchLabel: false,
labelName: labelName,
firstX: 250,
firstY: 350,
secondX: 350,

@ -4,14 +4,14 @@
/// <reference types="cypress" />
import { taskName } from '../../support/const';
import { taskName, labelName } from '../../support/const';
context('Check hide functionality (H)', () => {
const issueId = '1433';
const createRectangleShape2Points = {
points: 'By 2 Points',
type: 'Shape',
switchLabel: false,
labelName: labelName,
firstX: 250,
firstY: 350,
secondX: 350,

@ -4,14 +4,14 @@
/// <reference types="cypress" />
import { taskName } from '../../support/const';
import { taskName, labelName } from '../../support/const';
context('Cancel "multiple paste". UI is not locked.', () => {
const issueId = '1438';
const createRectangleShape2Points = {
points: 'By 2 Points',
type: 'Shape',
switchLabel: false,
labelName: labelName,
firstX: 250,
firstY: 350,
secondX: 350,

@ -11,7 +11,7 @@ context('Information about a blocked object disappears if hover the cursor over
const createRectangleShape2Points = {
points: 'By 2 Points',
type: 'Shape',
switchLabel: false,
labelName: labelName,
firstX: 250,
firstY: 350,
secondX: 350,
@ -20,7 +20,7 @@ context('Information about a blocked object disappears if hover the cursor over
const createRectangleShape2PointsSecond = {
points: 'By 2 Points',
type: 'Shape',
switchLabel: false,
labelName: labelName,
firstX: createRectangleShape2Points.firstX,
firstY: createRectangleShape2Points.firstY - 150,
secondX: createRectangleShape2Points.secondX,

@ -4,14 +4,14 @@
/// <reference types="cypress" />
import { taskName } from '../../support/const';
import { taskName, labelName } from '../../support/const';
context('Filter property "shape" work correctly', () => {
const issueId = '1444';
const createRectangleShape2Points = {
points: 'By 2 Points',
type: 'Shape',
switchLabel: false,
labelName: labelName,
firstX: 250,
firstY: 350,
secondX: 350,
@ -20,7 +20,7 @@ context('Filter property "shape" work correctly', () => {
const createPolygonShape = {
reDraw: false,
type: 'Shape',
switchLabel: false,
labelName: labelName,
pointsMap: [
{ x: 300, y: 100 },
{ x: 400, y: 400 },

@ -4,14 +4,14 @@
/// <reference types="cypress" />
import { taskName } from '../../support/const';
import { taskName, labelName } from '../../support/const';
context('Dump annotation if cuboid created', () => {
const issueId = '1568';
const createCuboidShape2Points = {
points: 'From rectangle',
type: 'Shape',
switchLabel: false,
labelName: labelName,
firstX: 250,
firstY: 350,
secondX: 350,

@ -11,7 +11,7 @@ context('An error occurs in AAM when switching to 2 frames, if the frames have o
const createRectangleShape2Points = {
points: 'By 2 Points',
type: 'Shape',
switchLabel: false,
labelName: labelName,
firstX: 250,
firstY: 350,
secondX: 350,
@ -20,7 +20,7 @@ context('An error occurs in AAM when switching to 2 frames, if the frames have o
const createRectangleShape2PointsSecond = {
points: 'By 2 Points',
type: 'Shape',
switchLabel: false,
labelName: labelName,
firstX: createRectangleShape2Points.firstX,
firstY: createRectangleShape2Points.firstY - 150,
secondX: createRectangleShape2Points.secondX,

@ -4,14 +4,14 @@
/// <reference types="cypress" />
import { taskName, advancedConfigurationParams } from '../../support/const';
import { taskName, advancedConfigurationParams, labelName } from '../../support/const';
context('Check propagation work from the latest frame', () => {
const issueId = '1785';
const createRectangleShape2Points = {
points: 'By 2 Points',
type: 'Shape',
switchLabel: false,
labelName: labelName,
firstX: 250,
firstY: 350,
secondX: 350,

@ -4,14 +4,14 @@
/// <reference types="cypress" />
import { taskName, advancedConfigurationParams } from '../../support/const';
import { taskName, advancedConfigurationParams, labelName } from '../../support/const';
context('First part of a splitted track is visible', () => {
const issueId = '1819';
const createRectangleTrack2Points = {
points: 'By 2 Points',
type: 'Track',
switchLabel: false,
labelName: labelName,
firstX: 250,
firstY: 350,
secondX: 350,

@ -4,7 +4,7 @@
/// <reference types="cypress" />
import { taskName } from '../../support/const';
import { taskName, labelName } from '../../support/const';
context(
"Hidden objects mustn't consider when we want to group visible objects only and use an grouping area for it.",
@ -13,21 +13,21 @@ context(
let bgcolor = '';
const createFirstPointsShape = {
type: 'Shape',
switchLabel: false,
labelName: labelName,
pointsMap: [{ x: 300, y: 410 }],
complete: true,
numberOfPoints: null,
};
const createSecondPointsShape = {
type: 'Shape',
switchLabel: false,
labelName: labelName,
pointsMap: [{ x: 350, y: 410 }],
complete: true,
numberOfPoints: null,
};
const createThridPointsShape = {
type: 'Shape',
switchLabel: false,
labelName: labelName,
pointsMap: [{ x: 400, y: 410 }],
complete: true,
numberOfPoints: null,

@ -4,7 +4,7 @@
/// <reference types="cypress" />
import { taskName, textDefaultValue, attrName } from '../../support/const';
import { taskName, textDefaultValue, attrName, labelName } from '../../support/const';
context(
"Checks that the cursor doesn't automatically jump to the end of a word when the attribute value changes",
@ -13,7 +13,7 @@ context(
const createRectangleShape2Points = {
points: 'By 2 Points',
type: 'Shape',
switchLabel: false,
labelName: labelName,
firstX: 250,
firstY: 350,
secondX: 350,

@ -4,14 +4,14 @@
/// <reference types="cypress" />
import { taskName } from '../../support/const';
import { taskName, labelName } from '../../support/const';
context("The points of the previous polygon mustn't appear while polygon's interpolation.", () => {
const issueId = '1882';
const createPolygonTrack = {
reDraw: false,
type: 'Track',
switchLabel: false,
labelName: labelName,
pointsMap: [
{ x: 309, y: 431 },
{ x: 360, y: 500 },
@ -23,7 +23,7 @@ context("The points of the previous polygon mustn't appear while polygon's inter
const reDrawPolygonTrack = {
reDraw: true,
type: 'Track',
switchLabel: false,
labelName: labelName,
pointsMap: [
{ x: 359, y: 431 },
{ x: 410, y: 500 },

@ -4,7 +4,7 @@
/// <reference types="cypress" />
import { taskName, advancedConfigurationParams } from '../../support/const';
import { taskName, advancedConfigurationParams, labelName } from '../../support/const';
context("Point coordinates are not duplicated while polygon's interpolation.", () => {
const issueId = '1886';
@ -12,7 +12,7 @@ context("Point coordinates are not duplicated while polygon's interpolation.", (
const createPolygonTrack = {
reDraw: false,
type: 'Track',
switchLabel: false,
labelName: labelName,
pointsMap: [
{ x: 300, y: 450 },
{ x: 400, y: 450 },

@ -4,7 +4,7 @@
/// <reference types="cypress" />
import { taskName, textDefaultValue, attrName } from '../../support/const';
import { taskName, textDefaultValue, attrName, labelName } from '../../support/const';
context('Check label attribute changes', () => {
const issueId = '1919';
@ -12,7 +12,7 @@ context('Check label attribute changes', () => {
const createRectangleShape2Points = {
points: 'By 2 Points',
type: 'Shape',
switchLabel: false,
labelName: labelName,
firstX: 250,
firstY: 350,
secondX: 350,

@ -0,0 +1,33 @@
// Copyright (C) 2020 Intel Corporation
//
// SPDX-License-Identifier: MIT
/// <reference types="cypress" />
import { taskName } from '../../support/const';
context('Draw a point shape, specify one point', () => {
const issueId = '2306';
const createPointsShape = {
type: 'Shape',
switchLabel: false,
pointsMap: [
{ x: 500, y: 200 },
],
numberOfPoints: 1,
};
before(() => {
cy.openTaskJob(taskName);
});
describe(`Testing case "${issueId}"`, () => {
it('Draw a point shape, specify one point. Drag cursor.', () => {
cy.createPoint(createPointsShape);
cy.get('.cvat-canvas-container').trigger('mousemove');
// Test fail before fix with error:
// The following error originated from your application code, not from Cypress.
// > Cannot read property 'each' of undefined.
});
});
});

@ -4,14 +4,14 @@
/// <reference types="cypress" />
import { taskName } from '../../support/const';
import { taskName, labelName } from '../../support/const';
context('Check if the UI fails by moving to the next frame while dragging the object', () => {
const prId = '1370';
const createRectangleShape2Points = {
points: 'By 2 Points',
type: 'Shape',
switchLabel: false,
labelName: labelName,
firstX: 250,
firstY: 350,
secondX: 350,

@ -96,9 +96,7 @@ Cypress.Commands.add('openTaskJob', (taskName, jobNumber = 0) => {
Cypress.Commands.add('createRectangle', (createRectangleParams) => {
cy.get('.cvat-draw-rectangle-control').click();
if (createRectangleParams.switchLabel) {
cy.switchLabel(createRectangleParams.labelName, 'rectangle');
}
cy.switchLabel(createRectangleParams.labelName, 'rectangle');
cy.contains('Draw new rectangle')
.parents('.cvat-draw-shape-popover-content')
.within(() => {
@ -123,7 +121,7 @@ Cypress.Commands.add('switchLabel', (labelName, objectType) => {
cy.contains(regex).parents('.cvat-draw-shape-popover-content').within(() => {
cy.get('.ant-select-selection-selected-value').click();
});
cy.get('.ant-select-dropdown-menu').last().contains(labelName).click();
cy.get('.ant-select-dropdown').not('.ant-select-dropdown-hidden').contains(new RegExp(`^${labelName}$`, 'g')).click();
});
Cypress.Commands.add('checkObjectParameters', (objectParameters, objectType) => {
@ -146,9 +144,7 @@ Cypress.Commands.add('checkObjectParameters', (objectParameters, objectType) =>
Cypress.Commands.add('createPoint', (createPointParams) => {
cy.get('.cvat-draw-points-control').click();
if (createPointParams.switchLabel) {
cy.switchLabel(createPointParams.labelName, 'points');
}
cy.switchLabel(createPointParams.labelName, 'points');
cy.contains('Draw new points')
.parents('.cvat-draw-shape-popover-content')
.within(() => {
@ -190,9 +186,7 @@ Cypress.Commands.add('shapeGrouping', (firstX, firstY, lastX, lastY) => {
Cypress.Commands.add('createPolygon', (createPolygonParams) => {
if (!createPolygonParams.reDraw) {
cy.get('.cvat-draw-polygon-control').click();
if (createPolygonParams.switchLabel) {
cy.switchLabel(createPolygonParams.labelName, 'polygon');
}
cy.switchLabel(createPolygonParams.labelName, 'polygon');
cy.contains('Draw new polygon')
.parents('.cvat-draw-shape-popover-content')
.within(() => {
@ -242,16 +236,14 @@ Cypress.Commands.add('changeLabelAAM', (labelName) => {
cy.get('.attribute-annotation-sidebar-basics-editor').within(() => {
cy.get('.ant-select-selection').click();
});
cy.get('.ant-select-dropdown-menu-item').contains(labelName).click();
cy.get('.ant-select-dropdown').not('.ant-select-dropdown-hidden').contains(new RegExp(`^${labelName}$`, 'g')).click();
}
});
});
Cypress.Commands.add('createCuboid', (createCuboidParams) => {
cy.get('.cvat-draw-cuboid-control').click();
if (createCuboidParams.switchLabel) {
cy.switchLabel(createCuboidParams.labelName, 'cuboid');
}
cy.switchLabel(createCuboidParams.labelName, 'cuboid');
cy.contains('Draw new cuboid')
.parents('.cvat-draw-shape-popover-content')
.within(() => {
@ -280,9 +272,7 @@ Cypress.Commands.add('updateAttributes', (multiAttrParams) => {
Cypress.Commands.add('createPolyline', (createPolylineParams) => {
cy.get('.cvat-draw-polyline-control').click();
if (createPolylineParams.switchLabel) {
cy.switchLabel(createPolylineParams.labelName, 'polyline');
}
cy.switchLabel(createPolylineParams.labelName, 'polyline');
cy.contains('Draw new polyline')
.parents('.cvat-draw-shape-popover-content')
.within(() => {

Loading…
Cancel
Save