Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Label deleting #2881

Merged
merged 14 commits into from
Mar 18, 2021
Merged
5 changes: 3 additions & 2 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
{
"python.pythonPath": ".env/bin/python",
"eslint.enable": true,
"eslint.probe": [
"javascript",
"typescript",
Expand All @@ -19,8 +18,10 @@
"!cwd": true
}
],
"npm.exclude": "**/.env/**",
"python.linting.enabled": true,
"python.linting.pylintEnabled": true,
"python.testing.unittestEnabled": true,
"python.linting.pycodestyleEnabled": false,
"licenser.license": "Custom",
"licenser.customHeader": "Copyright (C) @YEAR@ Intel Corporation\n\nSPDX-License-Identifier: MIT",
"files.trimTrailingWhitespace": true
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- [WiderFace](http://shuoyang1213.me/WIDERFACE/) format support (<https://github.com/openvinotoolkit/cvat/pull/2864>)
- [VGGFace2](https://github.com/ox-vgg/vgg_face2) format support (<https://github.com/openvinotoolkit/cvat/pull/2865>)
- [Backup/Restore guide](cvat/apps/documentation/backup_guide.md) (<https://github.com/openvinotoolkit/cvat/pull/2964>)
- Label deletion from tasks and projects (<https://github.com/openvinotoolkit/cvat/pull/2881>)

### Changed

Expand Down
11 changes: 11 additions & 0 deletions cvat-core/src/labels.js
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@
id: undefined,
name: undefined,
color: undefined,
deleted: false,
};

for (const key in data) {
Expand Down Expand Up @@ -208,6 +209,12 @@
attributes: {
get: () => [...data.attributes],
},
deleted: {
get: () => data.deleted,
set: (value) => {
data.deleted = value;
},
},
}),
);
}
Expand All @@ -223,6 +230,10 @@
object.id = this.id;
}

if (this.deleted) {
object.deleted = this.deleted;
}

return object;
}
}
Expand Down
13 changes: 11 additions & 2 deletions cvat-core/src/project.js
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,13 @@
);
}

data.labels = [...labels];
const IDs = labels.map((_label) => _label.id);
const deletedLabels = data.labels.filter((_label) => !IDs.includes(_label.id));
deletedLabels.forEach((_label) => {
_label.deleted = true;
});

data.labels = [...deletedLabels, ...labels];
},
},
/**
Expand All @@ -211,6 +217,9 @@
subsets: {
get: () => [...data.task_subsets],
},
_internalData: {
get: () => data,
},
}),
);
}
Expand Down Expand Up @@ -257,7 +266,7 @@
name: this.name,
assignee_id: this.assignee ? this.assignee.id : null,
bug_tracker: this.bugTracker,
labels: [...this.labels.map((el) => el.toJSON())],
labels: [...this._internalData.labels.map((el) => el.toJSON())],
};

await serverProxy.projects.save(this.id, projectData);
Expand Down
27 changes: 18 additions & 9 deletions cvat-core/src/session.js
Original file line number Diff line number Diff line change
Expand Up @@ -1304,7 +1304,7 @@
* @throws {module:API.cvat.exceptions.ArgumentError}
*/
labels: {
get: () => [...data.labels],
get: () => data.labels.filter((_label) => !_label.deleted),
set: (labels) => {
if (!Array.isArray(labels)) {
throw new ArgumentError('Value must be an array of Labels');
Expand All @@ -1318,8 +1318,14 @@
}
}

const IDs = labels.map((_label) => _label.id);
const deletedLabels = data.labels.filter((_label) => !IDs.includes(_label.id));
deletedLabels.forEach((_label) => {
_label.deleted = true;
});

updatedFields.labels = true;
data.labels = [...labels];
data.labels = [...deletedLabels, ...labels];
},
},
/**
Expand Down Expand Up @@ -1485,12 +1491,6 @@
dataChunkType: {
get: () => data.data_compressed_chunk_type,
},
__updatedFields: {
get: () => updatedFields,
set: (fields) => {
updatedFields = fields;
},
},
dimension: {
/**
* @name enabled
Expand All @@ -1501,6 +1501,15 @@
*/
get: () => data.dimension,
},
_internalData: {
get: () => data,
},
__updatedFields: {
get: () => updatedFields,
set: (fields) => {
updatedFields = fields;
},
},
}),
);

Expand Down Expand Up @@ -1920,7 +1929,7 @@
taskData.subset = this.subset;
break;
case 'labels':
taskData.labels = [...this.labels.map((el) => el.toJSON())];
taskData.labels = [...this._internalData.labels.map((el) => el.toJSON())];
break;
default:
break;
Expand Down
14 changes: 11 additions & 3 deletions cvat-core/tests/mocks/server-proxy.mock.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (C) 2020 Intel Corporation
// Copyright (C) 2020-2021 Intel Corporation
//
// SPDX-License-Identifier: MIT

Expand Down Expand Up @@ -97,7 +97,11 @@ class ServerProxy {
Object.prototype.hasOwnProperty.call(projectData, prop)
&& Object.prototype.hasOwnProperty.call(object, prop)
) {
object[prop] = projectData[prop];
if (prop === 'labels') {
object[prop] = projectData[prop].filter((label) => !label.deleted);
} else {
object[prop] = projectData[prop];
}
}
}
}
Expand Down Expand Up @@ -156,7 +160,11 @@ class ServerProxy {
Object.prototype.hasOwnProperty.call(taskData, prop)
&& Object.prototype.hasOwnProperty.call(object, prop)
) {
object[prop] = taskData[prop];
if (prop === 'labels') {
object[prop] = taskData[prop].filter((label) => !label.deleted);
} else {
object[prop] = taskData[prop];
}
}
}
}
Expand Down
6 changes: 1 addition & 5 deletions cvat-ui/src/actions/annotation-actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
//
// SPDX-License-Identifier: MIT

import { MutableRefObject } from 'react';
import {
AnyAction, Dispatch, ActionCreator, Store,
} from 'redux';
Expand All @@ -26,7 +27,6 @@ import getCore from 'cvat-core-wrapper';
import logger, { LogType } from 'cvat-logger';
import { RectDrawingMethod } from 'cvat-canvas-wrapper';
import { getCVATStore } from 'cvat-store';
import { MutableRefObject } from 'react';

interface AnnotationsParameters {
filters: string[];
Expand Down Expand Up @@ -919,10 +919,6 @@ export function getJobAsync(tid: number, jid: number, initialFrame: number, init
throw new Error(`Task ${tid} doesn't contain the job ${jid}`);
}

if (!task.labels.length && task.projectId) {
throw new Error(`Project ${task.projectId} does not contain any label`);
}

const frameNumber = Math.max(Math.min(job.stopFrame, initialFrame), job.startFrame);
const frameData = await job.frames.get(frameNumber);
// call first getting of frame data before rendering interface
Expand Down
24 changes: 24 additions & 0 deletions cvat-ui/src/components/annotation-page/annotation-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ import { useHistory } from 'react-router';
import Layout from 'antd/lib/layout';
import Spin from 'antd/lib/spin';
import Result from 'antd/lib/result';
import notification from 'antd/lib/notification';

import { Workspace } from 'reducers/interfaces';
import { usePrevious } from 'utils/hooks';
import AnnotationTopBarContainer from 'containers/annotation-page/top-bar/top-bar';
import StatisticsModalContainer from 'containers/annotation-page/top-bar/statistics-modal';
import StandardWorkspaceComponent from 'components/annotation-page/standard-workspace/standard-workspace';
Expand All @@ -33,6 +35,8 @@ export default function AnnotationPageComponent(props: Props): JSX.Element {
const {
job, fetching, getJob, closeJob, saveLogs, workspace,
} = props;
const prevJob = usePrevious(job);
const prevFetching = usePrevious(fetching);

const history = useHistory();
useEffect(() => {
Expand Down Expand Up @@ -60,6 +64,26 @@ export default function AnnotationPageComponent(props: Props): JSX.Element {
}
}, [job, fetching]);

useEffect(() => {
if (prevFetching && !fetching && !prevJob && job && !job.task.labels.length) {
notification.warning({
message: 'No labels',
description: (
<span>
{`${job.task.projectId ? 'Project' : 'Task'} ${
job.task.projectId || job.task.id
} does not contain any label. `}
<a href={`/${job.task.projectId ? 'projects' : 'tasks'}/${job.task.projectId || job.task.id}/`}>
Add
</a>
{' the first one for editing annotation.'}
</span>
),
placement: 'topRight',
});
}
}, [job, fetching, prevJob, prevFetching]);

if (job === null) {
return <Spin size='large' className='cvat-spinner' />;
}
Expand Down
Loading