diff --git a/CHANGELOG.md b/CHANGELOG.md index 9977814a1da..ca760515b25 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,7 +19,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - TDB ### Fixed -- TDB +- Zooming canvas when scrooling comments list in an issue () +- Issues can be created many times when initial submit () ### Security - TDB diff --git a/cvat-canvas/package.json b/cvat-canvas/package.json index f14f50bdbfc..10d3fc87530 100644 --- a/cvat-canvas/package.json +++ b/cvat-canvas/package.json @@ -1,6 +1,6 @@ { "name": "cvat-canvas", - "version": "2.17.4", + "version": "2.17.5", "description": "Part of Computer Vision Annotation Tool which presents its canvas library", "main": "src/canvas.ts", "scripts": { diff --git a/cvat-canvas/src/typescript/canvasView.ts b/cvat-canvas/src/typescript/canvasView.ts index 054697d3c70..97d5be38f40 100644 --- a/cvat-canvas/src/typescript/canvasView.ts +++ b/cvat-canvas/src/typescript/canvasView.ts @@ -1252,6 +1252,14 @@ export class CanvasViewImpl implements CanvasView, Listener { window.document.addEventListener('keydown', this.onShiftKeyDown); window.document.addEventListener('keyup', this.onShiftKeyUp); + this.attachmentBoard.addEventListener('wheel', (event) => { + event.stopPropagation(); + }); + + this.attachmentBoard.addEventListener('mousemove', (event) => { + event.stopPropagation(); + }); + this.canvas.addEventListener('wheel', (event): void => { if (event.ctrlKey) return; const { offset } = this.controller.geometry; diff --git a/cvat-ui/package.json b/cvat-ui/package.json index ae0bf54801f..d9923bfad5b 100644 --- a/cvat-ui/package.json +++ b/cvat-ui/package.json @@ -1,6 +1,6 @@ { "name": "cvat-ui", - "version": "1.55.4", + "version": "1.55.5", "description": "CVAT single-page application", "main": "src/index.tsx", "scripts": { diff --git a/cvat-ui/src/components/annotation-page/review/create-issue-dialog.tsx b/cvat-ui/src/components/annotation-page/review/create-issue-dialog.tsx index 97cacaff854..b90f610c201 100644 --- a/cvat-ui/src/components/annotation-page/review/create-issue-dialog.tsx +++ b/cvat-ui/src/components/annotation-page/review/create-issue-dialog.tsx @@ -2,29 +2,31 @@ // // SPDX-License-Identifier: MIT -import React, { ReactPortal } from 'react'; +import React, { useState, ReactPortal } from 'react'; import ReactDOM from 'react-dom'; import { useDispatch } from 'react-redux'; import Form from 'antd/lib/form'; import Input from 'antd/lib/input'; import Button from 'antd/lib/button'; import { Row, Col } from 'antd/lib/grid'; +import { Store } from 'antd/lib/form/interface'; import { reviewActions, finishIssueAsync } from 'actions/review-actions'; -import { Store } from 'antd/lib/form/interface'; +import { useIsMounted } from 'utils/hooks'; interface FormProps { top: number; left: number; angle: number; scale: number; + fetching: boolean; submit(message: string): void; cancel(): void; } function MessageForm(props: FormProps): JSX.Element { const { - top, left, angle, scale, submit, cancel, + top, left, angle, scale, fetching, submit, cancel, } = props; function handleSubmit(values: Store): void { @@ -37,17 +39,31 @@ function MessageForm(props: FormProps): JSX.Element { style={{ top, left, transform: `scale(${scale}) rotate(${angle}deg)` }} onFinish={(values: Store) => handleSubmit(values)} > - + - - @@ -64,6 +80,8 @@ interface Props { } export default function CreateIssueDialog(props: Props): ReactPortal { + const [fetching, setFetching] = useState(false); + const isMounted = useIsMounted(); const dispatch = useDispatch(); const { top, left, angle, scale, @@ -75,8 +93,14 @@ export default function CreateIssueDialog(props: Props): ReactPortal { left={left} angle={angle} scale={scale} + fetching={fetching} submit={(message: string) => { - dispatch(finishIssueAsync(message)); + setFetching(true); + dispatch(finishIssueAsync(message)).finally(() => { + if (isMounted()) { + setFetching(false); + } + }); }} cancel={() => { dispatch(reviewActions.cancelIssue()); diff --git a/cvat-ui/src/components/annotation-page/review/hidden-issue-label.tsx b/cvat-ui/src/components/annotation-page/review/hidden-issue-label.tsx index 076c531b75a..747730b66e2 100644 --- a/cvat-ui/src/components/annotation-page/review/hidden-issue-label.tsx +++ b/cvat-ui/src/components/annotation-page/review/hidden-issue-label.tsx @@ -40,6 +40,27 @@ export default function HiddenIssueLabel(props: Props): ReactPortal { } }, [resolved]); + useEffect(() => { + if (ref.current) { + const { current } = ref; + const listener = (event: WheelEvent): void => { + event.stopPropagation(); + if (event.deltaX > 0) { + current.parentElement?.appendChild(current); + } else { + current.parentElement?.prepend(current); + } + }; + + current.addEventListener('wheel', listener); + return () => { + current.removeEventListener('wheel', listener); + }; + } + + return () => {}; + }, [ref.current]); + const elementID = `cvat-hidden-issue-label-${id}`; return ReactDOM.createPortal( @@ -49,16 +70,6 @@ export default function HiddenIssueLabel(props: Props): ReactPortal { onClick={onClick} onMouseEnter={highlight} onMouseLeave={blur} - onWheel={(event: React.WheelEvent) => { - if (ref.current !== null) { - const selfElement = ref.current; - if (event.deltaX > 0) { - selfElement.parentElement?.appendChild(selfElement); - } else { - selfElement.parentElement?.prepend(selfElement); - } - } - }} style={{ top, left, transform: `scale(${scale}) rotate(${angle}deg)` }} className='cvat-hidden-issue-label' > diff --git a/cvat-ui/src/components/annotation-page/review/issue-dialog.tsx b/cvat-ui/src/components/annotation-page/review/issue-dialog.tsx index 6a32614aee4..edfb5b01a8b 100644 --- a/cvat-ui/src/components/annotation-page/review/issue-dialog.tsx +++ b/cvat-ui/src/components/annotation-page/review/issue-dialog.tsx @@ -68,13 +68,28 @@ export default function IssueDialog(props: Props): JSX.Element { } }, [resolved]); + useEffect(() => { + const listener = (event: WheelEvent): void => { + event.stopPropagation(); + }; + + if (ref.current) { + const { current } = ref; + current.addEventListener('wheel', listener); + return () => { + current.removeEventListener('wheel', listener); + }; + } + return () => {}; + }, [ref.current]); + const onDeleteIssue = useCallback((): void => { Modal.confirm({ - title: `The issue${id >= 0 ? ` #${id}` : ''} will be deleted.`, + title: `The issue${typeof id === 'number' ? ` #${id}` : ''} will be deleted.`, className: 'cvat-modal-confirm-remove-issue', onOk: () => { collapse(); - dispatch(deleteIssueAsync(id)); + dispatch(deleteIssueAsync(id as number)); }, okButtonProps: { type: 'primary', @@ -116,10 +131,14 @@ export default function IssueDialog(props: Props): JSX.Element { ); return ReactDOM.createPortal( -
+
- {id >= 0 ? `Issue #${id}` : 'Issue'} + {typeof id === 'number' ? `Issue #${id}` : 'Issue'} @@ -135,7 +154,7 @@ export default function IssueDialog(props: Props): JSX.Element { ) => { setCurrentText(event.target.value);