Skip to content

Commit

Permalink
Issue deleting (#3952)
Browse files Browse the repository at this point in the history
  • Loading branch information
ActiveChooN authored Dec 2, 2021
1 parent 439c6d5 commit 1d952ac
Show file tree
Hide file tree
Showing 14 changed files with 182 additions and 14 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Player option: Smooth image when zoom-in, enabled by default (<https://github.com/openvinotoolkit/cvat/pull/3933>)
- Google Cloud Storage support in UI (<https://github.com/openvinotoolkit/cvat/pull/3919>)
- Add project tasks paginations (<https://github.com/openvinotoolkit/cvat/pull/3910>)
- Add remove issue button (<https://github.com/openvinotoolkit/cvat/pull/3952>)

### Changed
- TDB
Expand Down
24 changes: 23 additions & 1 deletion cvat-core/src/issue.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 @@ -241,6 +241,21 @@ class Issue {
return result;
}

/**
* The method deletes the issue
* Deletes local or server-saved issues
* @method delete
* @memberof module:API.cvat.classes.Issue
* @readonly
* @instance
* @async
* @throws {module:API.cvat.exceptions.ServerError}
* @throws {module:API.cvat.exceptions.PluginError}
*/
async delete() {
await PluginRegistry.apiWrapper.call(this, Issue.prototype.delete);
}

serialize() {
const { comments } = this;
const data = {
Expand Down Expand Up @@ -332,4 +347,11 @@ Issue.prototype.reopen.implementation = async function () {
}
};

Issue.prototype.delete.implementation = async function () {
const { id } = this;
if (id >= 0) {
await serverProxy.issues.delete(id);
}
};

module.exports = Issue;
10 changes: 9 additions & 1 deletion cvat-core/src/review.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 @@ -250,6 +250,10 @@ class Review {
return result;
}

async deleteIssue(issueId) {
await PluginRegistry.apiWrapper.call(this, Review.prototype.deleteIssue, issueId);
}

/**
* Method submits local review to the server
* @method submit
Expand Down Expand Up @@ -394,4 +398,8 @@ Review.prototype.submit.implementation = async function () {
}
};

Review.prototype.deleteIssue.implementation = function (issueId) {
this.__internal.issue_set = this.__internal.issue_set.filter((issue) => issue.id !== issueId);
};

module.exports = Review;
11 changes: 11 additions & 0 deletions cvat-core/src/server-proxy.js
Original file line number Diff line number Diff line change
Expand Up @@ -757,6 +757,16 @@
return response.data;
}

async function deleteIssue(issueID) {
const { backendAPI } = config;

try {
await Axios.delete(`${backendAPI}/issues/${issueID}`);
} catch (errorData) {
throw generateError(errorData);
}
}

async function saveJob(id, jobData) {
const { backendAPI } = config;

Expand Down Expand Up @@ -1413,6 +1423,7 @@
issues: {
value: Object.freeze({
update: updateIssue,
delete: deleteIssue,
}),
writable: false,
},
Expand Down
4 changes: 2 additions & 2 deletions cvat-ui/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion cvat-ui/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "cvat-ui",
"version": "1.28.0",
"version": "1.28.1",
"description": "CVAT single-page application",
"main": "src/index.tsx",
"scripts": {
Expand Down
34 changes: 34 additions & 0 deletions cvat-ui/src/actions/review-actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,13 @@ export enum ReviewActionTypes {
COMMENT_ISSUE = 'COMMENT_ISSUE',
COMMENT_ISSUE_SUCCESS = 'COMMENT_ISSUE_SUCCESS',
COMMENT_ISSUE_FAILED = 'COMMENT_ISSUE_FAILED',
REMOVE_ISSUE_SUCCESS = 'REMOVE_ISSUE_SUCCESS',
REMOVE_ISSUE_FAILED = 'REMOVE_ISSUE_FAILED',
SUBMIT_REVIEW = 'SUBMIT_REVIEW',
SUBMIT_REVIEW_SUCCESS = 'SUBMIT_REVIEW_SUCCESS',
SUBMIT_REVIEW_FAILED = 'SUBMIT_REVIEW_FAILED',
SWITCH_ISSUES_HIDDEN_FLAG = 'SWITCH_ISSUES_HIDDEN_FLAG',
SWITCH_RESOLVED_ISSUES_HIDDEN_FLAG = 'SWITCH_RESOLVED_ISSUES_HIDDEN_FLAG',
}

export const reviewActions = {
Expand Down Expand Up @@ -57,7 +60,14 @@ export const reviewActions = {
submitReview: (reviewId: number) => createAction(ReviewActionTypes.SUBMIT_REVIEW, { reviewId }),
submitReviewSuccess: () => createAction(ReviewActionTypes.SUBMIT_REVIEW_SUCCESS),
submitReviewFailed: (error: any) => createAction(ReviewActionTypes.SUBMIT_REVIEW_FAILED, { error }),
removeIssueSuccess: (issueId: number, frame: number) => (
createAction(ReviewActionTypes.REMOVE_ISSUE_SUCCESS, { issueId, frame })
),
removeIssueFailed: (error: any) => createAction(ReviewActionTypes.REMOVE_ISSUE_FAILED, { error }),
switchIssuesHiddenFlag: (hidden: boolean) => createAction(ReviewActionTypes.SWITCH_ISSUES_HIDDEN_FLAG, { hidden }),
switchIssuesHiddenResolvedFlag: (hidden: boolean) => (
createAction(ReviewActionTypes.SWITCH_RESOLVED_ISSUES_HIDDEN_FLAG, { hidden })
),
};

export type ReviewActions = ActionUnion<typeof reviewActions>;
Expand Down Expand Up @@ -204,3 +214,27 @@ export const submitReviewAsync = (review: any): ThunkAction => async (dispatch,
dispatch(reviewActions.submitReviewFailed(error));
}
};

export const deleteIssueAsync = (id: number): ThunkAction => async (dispatch, getState) => {
const state = getState();
const {
review: { frameIssues, activeReview },
annotation: {
player: {
frame: { number: frameNumber },
},
},
} = state;

try {
const [issue] = frameIssues.filter((_issue: any): boolean => _issue.id === id);
await issue.delete();
if (activeReview !== null) {
await activeReview.deleteIssue(id);
await activeReview.toLocalStorage();
}
dispatch(reviewActions.removeIssueSuccess(id, frameNumber));
} catch (error) {
dispatch(reviewActions.removeIssueFailed(error));
}
};
34 changes: 32 additions & 2 deletions cvat-ui/src/components/annotation-page/review/issue-dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,15 @@
//
// SPDX-License-Identifier: MIT

import React, { useState, useEffect, useRef } from 'react';
import React, {
useState,
useEffect,
useRef,
useCallback,
} from 'react';
import ReactDOM from 'react-dom';
import { useDispatch } from 'react-redux';
import Modal from 'antd/lib/modal';
import { Row, Col } from 'antd/lib/grid';
import { CloseOutlined } from '@ant-design/icons';
import Comment from 'antd/lib/comment';
Expand All @@ -13,6 +20,7 @@ import Button from 'antd/lib/button';
import Input from 'antd/lib/input';
import moment from 'moment';
import CVATTooltip from 'components/common/cvat-tooltip';
import { deleteIssueAsync } from 'actions/review-actions';

interface Props {
id: number;
Expand All @@ -32,6 +40,7 @@ interface Props {
export default function IssueDialog(props: Props): JSX.Element {
const ref = useRef<HTMLDivElement>(null);
const [currentText, setCurrentText] = useState<string>('');
const dispatch = useDispatch();
const {
comments,
id,
Expand All @@ -55,6 +64,22 @@ export default function IssueDialog(props: Props): JSX.Element {
}
}, [resolved]);

const onDeleteIssue = useCallback((): void => {
Modal.confirm({
title: `The issue${id >= 0 ? ` #${id}` : ''} will be deleted.`,
className: 'cvat-modal-confirm-remove-issue',
onOk: () => {
collapse();
dispatch(deleteIssueAsync(id));
},
okButtonProps: {
type: 'primary',
danger: true,
},
okText: 'Delete',
});
}, []);

const lines = comments.map(
(_comment: any): JSX.Element => {
const created = _comment.createdDate ? moment(_comment.createdDate) : moment(moment.now());
Expand Down Expand Up @@ -118,7 +143,12 @@ export default function IssueDialog(props: Props): JSX.Element {
/>
</Col>
</Row>
<Row className='cvat-issue-dialog-footer' justify='end'>
<Row className='cvat-issue-dialog-footer' justify='space-between'>
<Col>
<Button type='link' danger onClick={onDeleteIssue}>
Remove
</Button>
</Col>
<Col>
{currentText.length ? (
<Button
Expand Down
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 @@ -29,14 +29,17 @@ export default function IssueAggregatorComponent(): JSX.Element | null {
const dispatch = useDispatch();
const [expandedIssue, setExpandedIssue] = useState<number | null>(null);
const frameIssues = useSelector((state: CombinedState): any[] => state.review.frameIssues);
const canvasInstance = useSelector((state: CombinedState): Canvas => state.annotation.canvas.instance);
const canvasInstance = useSelector((state: CombinedState) => state.annotation.canvas.instance);
const canvasIsReady = useSelector((state: CombinedState): boolean => state.annotation.canvas.ready);
const newIssuePosition = useSelector((state: CombinedState): number[] | null => state.review.newIssuePosition);
const issuesHidden = useSelector((state: CombinedState): any => state.review.issuesHidden);
const issuesResolvedHidden = useSelector((state: CombinedState): any => state.review.issuesResolvedHidden);
const issueFetching = useSelector((state: CombinedState): number | null => state.review.fetching.issueId);
const issueLabels: JSX.Element[] = [];
const issueDialogs: JSX.Element[] = [];

if (!(canvasInstance instanceof Canvas)) return null;

useEffect(() => {
scaleHandler(canvasInstance);
});
Expand Down Expand Up @@ -81,6 +84,7 @@ export default function IssueAggregatorComponent(): JSX.Element | null {
const { geometry } = canvasInstance;
for (const issue of frameIssues) {
if (issuesHidden) break;
if (issuesResolvedHidden && !!issue.resolvedDate) continue;
const issueResolved = !!issue.resolver;
const offset = 15;
const translated = issue.position.map((coord: number): number => coord + geometry.offset);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import {
LeftOutlined, RightOutlined, EyeInvisibleFilled, EyeOutlined,
CheckCircleFilled, CheckCircleOutlined,
} from '@ant-design/icons';
import Alert from 'antd/lib/alert';
import { Row, Col } from 'antd/lib/grid';
Expand All @@ -22,6 +23,7 @@ export default function LabelsListComponent(): JSX.Element {
const issues = useSelector((state: CombinedState): any[] => state.review.issues);
const activeReview = useSelector((state: CombinedState): any => state.review.activeReview);
const issuesHidden = useSelector((state: CombinedState): any => state.review.issuesHidden);
const issuesResolvedHidden = useSelector((state: CombinedState): any => state.review.issuesResolvedHidden);
const combinedIssues = activeReview ? issues.concat(activeReview.issues) : issues;
const frames = combinedIssues.map((issue: any): number => issue.frame).sort((a: number, b: number) => +a - +b);
const nearestLeft = frames.filter((_frame: number): boolean => _frame < frame).reverse()[0];
Expand Down Expand Up @@ -62,8 +64,8 @@ export default function LabelsListComponent(): JSX.Element {
<RightOutlined className='cvat-issues-sidebar-next-frame' {...dinamicRightProps} />
</CVATTooltip>
</Col>
<Col offset={3}>
<CVATTooltip title='Show/hide all the issues'>
<Col offset={2}>
<CVATTooltip title='Show/hide all issues'>
{issuesHidden ? (
<EyeInvisibleFilled
className='cvat-issues-sidebar-hidden-issues'
Expand All @@ -77,6 +79,22 @@ export default function LabelsListComponent(): JSX.Element {
)}
</CVATTooltip>
</Col>
<Col offset={2}>
<CVATTooltip title='Show/hide resolved issues'>
{ issuesResolvedHidden ? (
<CheckCircleFilled
className='cvat-issues-sidebar-hidden-resolved-status'
onClick={() => dispatch(reviewActions.switchIssuesHiddenResolvedFlag(false))}
/>
) : (
<CheckCircleOutlined
className='cvat-issues-sidebar-hidden-resolved-status'
onClick={() => dispatch(reviewActions.switchIssuesHiddenResolvedFlag(true))}
/>

)}
</CVATTooltip>
</Col>
</Row>
</div>
<div className='cvat-objects-sidebar-issues-list'>
Expand Down
10 changes: 7 additions & 3 deletions cvat-ui/src/containers/annotation-page/canvas/canvas-wrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -169,16 +169,20 @@ function mapStateToProps(state: CombinedState): StateToProps {
opacity, colorBy, selectedOpacity, outlined, outlineColor, showBitmap, showProjections,
},
},
review: { frameIssues, issuesHidden },
review: { frameIssues, issuesHidden, issuesResolvedHidden },
shortcuts: { keyMap },
} = state;

const issues = frameIssues.filter((issue) => (
!issuesHidden && [Workspace.REVIEW_WORKSPACE, Workspace.STANDARD].includes(workspace) &&
!(!!issue.resolvedDate && issuesResolvedHidden)
));

return {
sidebarCollapsed,
canvasInstance,
jobInstance,
frameIssues:
issuesHidden || ![Workspace.REVIEW_WORKSPACE, Workspace.STANDARD].includes(workspace) ? null : frameIssues,
frameIssues: issues,
frameData,
frameAngle: frameAngles[frame - jobInstance.startFrame],
frameFetching,
Expand Down
2 changes: 2 additions & 0 deletions cvat-ui/src/reducers/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,7 @@ export interface NotificationsState {
reopeningIssue: null | ErrorState;
commentingIssue: null | ErrorState;
submittingReview: null | ErrorState;
deletingIssue: null | ErrorState;
};
predictor: {
prediction: null | ErrorState;
Expand Down Expand Up @@ -678,6 +679,7 @@ export interface ReviewState {
activeReview: any | null;
newIssuePosition: number[] | null;
issuesHidden: boolean;
issuesResolvedHidden: boolean;
fetching: {
reviewId: number | null;
issueId: number | null;
Expand Down
Loading

0 comments on commit 1d952ac

Please sign in to comment.