From 8baacd6920f376046aa4df5fb575e677f19e0577 Mon Sep 17 00:00:00 2001 From: Dmitry Kalinin Date: Mon, 17 Feb 2020 16:04:14 +0300 Subject: [PATCH 01/14] Added settings actions --- cvat-ui/src/actions/settings-actions.ts | 100 ++++++++++++++++++ .../settings-page/player-settings.tsx | 54 +++++++++- .../settings-page/workspace-settings.tsx | 27 ++++- cvat-ui/src/components/task-page/job-list.tsx | 8 +- .../settings-page/player-settings.tsx | 30 +++--- .../settings-page/workspace-settings.tsx | 25 +++-- cvat-ui/src/reducers/settings-reducer.ts | 90 ++++++++++++++++ 7 files changed, 296 insertions(+), 38 deletions(-) diff --git a/cvat-ui/src/actions/settings-actions.ts b/cvat-ui/src/actions/settings-actions.ts index e1614cdfb421..2b6b0cdacb12 100644 --- a/cvat-ui/src/actions/settings-actions.ts +++ b/cvat-ui/src/actions/settings-actions.ts @@ -14,6 +14,16 @@ export enum SettingsActionTypes { CHANGE_SELECTED_SHAPES_OPACITY = 'CHANGE_SELECTED_SHAPES_OPACITY', CHANGE_SHAPES_COLOR_BY = 'CHANGE_SHAPES_COLOR_BY', CHANGE_SHAPES_BLACK_BORDERS = 'CHANGE_SHAPES_BLACK_BORDERS', + CHANGE_FRAME_STEP = 'CHANGE_FRAME_STEP', + CHANGE_FRAME_SPEED = 'CHANGE_FRAME_SPEED', + SWITCH_RESET_ZOOM = 'SWITCH_RESET_ZOOM', + CHANGE_BRIGHTNESS_LEVEL = 'CHANGE_BRIGHTNESS_LEVEL', + CHANGE_CONTRAST_LEVEL = 'CHANGE_CONTRAST_LEVEL', + CHANGE_SATURATION_LEVEL = 'CHANGE_SATURATION_LEVEL', + SWITCH_AUTO_SAVE = 'SWITCH_AUTO_SAVE', + CHANGE_AUTO_SAVE_INTERVAL = 'CHANGE_AUTO_SAVE_INTERVAL', + CHANGE_AAM_ZOOM_MARGIN = 'CHANGE_AAM_ZOOM_MARGIN', + SWITCH_SHOWNIG_INTERPOLATED_TRACKS = 'SWITCH_SHOWNIG_INTERPOLATED_TRACKS', } export function changeShapesOpacity(opacity: number): AnyAction { @@ -96,3 +106,93 @@ export function changeGridOpacity(gridOpacity: number): AnyAction { }, }; } + +export function changeFrameStep(frameStep: number): AnyAction { + return { + type: SettingsActionTypes.CHANGE_FRAME_STEP, + payload: { + frameStep, + }, + }; +} + +export function changeFrameSpeed(frameSpeed: number): AnyAction { + return { + type: SettingsActionTypes.CHANGE_FRAME_SPEED, + payload: { + frameSpeed, + }, + }; +} + +export function switchResetZoom(resetZoom: boolean): AnyAction { + return { + type: SettingsActionTypes.SWITCH_RESET_ZOOM, + payload: { + resetZoom, + }, + }; +} + +export function changeBrightnessLevel(level: number): AnyAction { + return { + type: SettingsActionTypes.CHANGE_BRIGHTNESS_LEVEL, + payload: { + level, + }, + }; +} + +export function changeContrastLevel(level: number): AnyAction { + return { + type: SettingsActionTypes.CHANGE_CONTRAST_LEVEL, + payload: { + level, + }, + }; +} + +export function changeSaturationLevel(level: number): AnyAction { + return { + type: SettingsActionTypes.CHANGE_SATURATION_LEVEL, + payload: { + level, + }, + }; +} + +export function switchAutoSave(autoSave: boolean): AnyAction { + return { + type: SettingsActionTypes.SWITCH_AUTO_SAVE, + payload: { + autoSave, + }, + }; +} + +export function changeAutoSaveInterval(autoSaveInterval: number): AnyAction { + return { + type: SettingsActionTypes.CHANGE_AUTO_SAVE_INTERVAL, + payload: { + autoSaveInterval, + }, + }; +} + +export function changeAAMZoomMargin(aamZoomMargin: number): AnyAction { + return { + type: SettingsActionTypes.CHANGE_AAM_ZOOM_MARGIN, + payload: { + aamZoomMargin, + }, + }; +} + +export function switchShowingInterpolatedTracks(showAllInterpolationTracks: boolean): AnyAction { + return { + type: SettingsActionTypes.SWITCH_SHOWNIG_INTERPOLATED_TRACKS, + payload: { + showAllInterpolationTracks, + }, + }; +} \ No newline at end of file diff --git a/cvat-ui/src/components/settings-page/player-settings.tsx b/cvat-ui/src/components/settings-page/player-settings.tsx index 1e419679a11a..2f5e5c55fda8 100644 --- a/cvat-ui/src/components/settings-page/player-settings.tsx +++ b/cvat-ui/src/components/settings-page/player-settings.tsx @@ -61,11 +61,17 @@ export default function PlayerSettingsComponent(props: Props): JSX.Element { brightnessLevel, contrastLevel, saturationLevel, + onChangeFrameStep, + onChangeFrameSpeed, + onSwitchResetZoom, onSwitchRotateAll, onSwitchGrid, onChangeGridSize, onChangeGridColor, onChangeGridOpacity, + onChangeBrightnessLevel, + onChangeContrastLevel, + onChangeSaturationLevel, } = props; return ( @@ -73,7 +79,16 @@ export default function PlayerSettingsComponent(props: Props): JSX.Element { Player step - + { + if (value) { + onChangeFrameStep(value); + } + }} + /> @@ -87,7 +102,12 @@ export default function PlayerSettingsComponent(props: Props): JSX.Element { Player speed - { + onChangeFrameSpeed(speed); + }} + > Fastest Fast Usual @@ -160,6 +180,9 @@ export default function PlayerSettingsComponent(props: Props): JSX.Element { { + onSwitchResetZoom(event.target.checked); + }} > Reset zoom @@ -193,7 +216,14 @@ export default function PlayerSettingsComponent(props: Props): JSX.Element { Brightness - + { + onChangeBrightnessLevel(value as number); + }} + /> @@ -201,7 +231,14 @@ export default function PlayerSettingsComponent(props: Props): JSX.Element { Contrast - + { + onChangeContrastLevel(value as number); + }} + /> @@ -209,7 +246,14 @@ export default function PlayerSettingsComponent(props: Props): JSX.Element { Saturation - + { + onChangeSaturationLevel(value as number); + }} + /> diff --git a/cvat-ui/src/components/settings-page/workspace-settings.tsx b/cvat-ui/src/components/settings-page/workspace-settings.tsx index 3fd6d10be6a4..263c4ae3fd60 100644 --- a/cvat-ui/src/components/settings-page/workspace-settings.tsx +++ b/cvat-ui/src/components/settings-page/workspace-settings.tsx @@ -8,6 +8,7 @@ import { } from 'antd'; import Text from 'antd/lib/typography/Text'; +import { CheckboxChangeEvent } from 'antd/lib/checkbox'; interface Props { autoSave: boolean; @@ -26,6 +27,10 @@ export default function WorkspaceSettingsComponent(props: Props): JSX.Element { autoSaveInterval, aamZoomMargin, showAllInterpolationTracks, + onSwitchAutoSave, + onChangeAutoSaveInterval, + onChangeAAMZoomMargin, + onSwitchShowingInterpolatedTracks, } = props; return ( @@ -35,6 +40,9 @@ export default function WorkspaceSettingsComponent(props: Props): JSX.Element { { + onSwitchAutoSave(event.target.checked); + }} > Enable auto save @@ -48,6 +56,11 @@ export default function WorkspaceSettingsComponent(props: Props): JSX.Element { max={60} step={1} value={Math.round(autoSaveInterval / (60 * 1000))} + onChange={(value: number | undefined): void => { + if (value) { + onChangeAutoSaveInterval(value as number * 60 * 1000); + } + }} /> minutes @@ -57,6 +70,9 @@ export default function WorkspaceSettingsComponent(props: Props): JSX.Element { { + onSwitchShowingInterpolatedTracks(event.target.checked); + }} > Show all interpolation tracks @@ -68,7 +84,16 @@ export default function WorkspaceSettingsComponent(props: Props): JSX.Element { Attribute annotation mode (AAM) zoom margin - + { + if (value) { + onChangeAAMZoomMargin(value); + } + }} + /> diff --git a/cvat-ui/src/components/task-page/job-list.tsx b/cvat-ui/src/components/task-page/job-list.tsx index fb29cca56d77..f3d10ccc68c0 100644 --- a/cvat-ui/src/components/task-page/job-list.tsx +++ b/cvat-ui/src/components/task-page/job-list.tsx @@ -1,5 +1,7 @@ import React from 'react'; +import { Link } from 'react-router-dom'; + import { Row, Col, @@ -39,7 +41,11 @@ export default function JobListComponent(props: Props): JSX.Element { title: 'Job', dataIndex: 'job', key: 'job', - render: (id: number): JSX.Element => ({ `Job #${id}` }), + render: (id: number): JSX.Element => (
+ {`Job #${id}`} + {" | "} + Old +
), }, { title: 'Frames', dataIndex: 'frames', diff --git a/cvat-ui/src/containers/settings-page/player-settings.tsx b/cvat-ui/src/containers/settings-page/player-settings.tsx index 73193b8f4278..ee0d56f0166b 100644 --- a/cvat-ui/src/containers/settings-page/player-settings.tsx +++ b/cvat-ui/src/containers/settings-page/player-settings.tsx @@ -4,11 +4,17 @@ import { connect } from 'react-redux'; import PlayerSettingsComponent from 'components/settings-page/player-settings'; import { + changeFrameStep, + changeFrameSpeed, + switchResetZoom, switchRotateAll, switchGrid, changeGridSize, changeGridColor, changeGridOpacity, + changeBrightnessLevel, + changeContrastLevel, + changeSaturationLevel, } from 'actions/settings-actions'; import { @@ -54,20 +60,14 @@ function mapStateToProps(state: CombinedState): StateToProps { function mapDispatchToProps(dispatch: any): DispatchToProps { return { - // will be implemented - // eslint-disable-next-line onChangeFrameStep(step: number): void { - + dispatch(changeFrameStep(step)); }, - // will be implemented - // eslint-disable-next-line onChangeFrameSpeed(speed: FrameSpeed): void { - + dispatch(changeFrameSpeed(speed)); }, - // will be implemented - // eslint-disable-next-line onSwitchResetZoom(enabled: boolean): void { - + dispatch(switchResetZoom(enabled)); }, onSwitchRotateAll(rotateAll: boolean): void { dispatch(switchRotateAll(rotateAll)); @@ -84,20 +84,14 @@ function mapDispatchToProps(dispatch: any): DispatchToProps { onChangeGridOpacity(gridOpacity: number): void { dispatch(changeGridOpacity(gridOpacity)); }, - // will be implemented - // eslint-disable-next-line onChangeBrightnessLevel(level: number): void { - + dispatch(changeBrightnessLevel(level)); }, - // will be implemented - // eslint-disable-next-line onChangeContrastLevel(level: number): void { - + dispatch(changeContrastLevel(level)); }, - // will be implemented - // eslint-disable-next-line onChangeSaturationLevel(level: number): void { - + dispatch(changeSaturationLevel(level)); }, }; } diff --git a/cvat-ui/src/containers/settings-page/workspace-settings.tsx b/cvat-ui/src/containers/settings-page/workspace-settings.tsx index 0c5a597efbfe..c1253c469877 100644 --- a/cvat-ui/src/containers/settings-page/workspace-settings.tsx +++ b/cvat-ui/src/containers/settings-page/workspace-settings.tsx @@ -1,6 +1,13 @@ import React from 'react'; import { connect } from 'react-redux'; +import { + switchAutoSave, + changeAutoSaveInterval, + changeAAMZoomMargin, + switchShowingInterpolatedTracks, +} from 'actions/settings-actions'; + import { CombinedState, } from 'reducers/interfaces'; @@ -38,27 +45,19 @@ function mapStateToProps(state: CombinedState): StateToProps { }; } -function mapDispatchToProps(): DispatchToProps { +function mapDispatchToProps(dispatch: any): DispatchToProps { return { - // will be implemented - // eslint-disable-next-line onSwitchAutoSave(enabled: boolean): void { - + dispatch(switchAutoSave(enabled)); }, - // will be implemented - // eslint-disable-next-line onChangeAutoSaveInterval(interval: number): void { - + dispatch(changeAutoSaveInterval(interval)); }, - // will be implemented - // eslint-disable-next-line onChangeAAMZoomMargin(margin: number): void { - + dispatch(changeAAMZoomMargin(margin)); }, - // will be implemented - // eslint-disable-next-line onSwitchShowingInterpolatedTracks(enabled: boolean): void { - + dispatch(switchShowingInterpolatedTracks(enabled)); }, }; } diff --git a/cvat-ui/src/reducers/settings-reducer.ts b/cvat-ui/src/reducers/settings-reducer.ts index b35dd37df43d..a0274e322566 100644 --- a/cvat-ui/src/reducers/settings-reducer.ts +++ b/cvat-ui/src/reducers/settings-reducer.ts @@ -119,6 +119,96 @@ export default (state = defaultState, action: AnyAction): SettingsState => { }, }; } + case SettingsActionTypes.CHANGE_FRAME_STEP: { + return { + ...state, + player: { + ...state.player, + frameStep: action.payload.frameStep, + } + } + } + case SettingsActionTypes.CHANGE_FRAME_SPEED: { + return { + ...state, + player: { + ...state.player, + frameSpeed: action.payload.frameSpeed, + } + } + } + case SettingsActionTypes.SWITCH_RESET_ZOOM: { + return { + ...state, + player: { + ...state.player, + resetZoom: action.payload.resetZoom, + } + } + } + case SettingsActionTypes.CHANGE_BRIGHTNESS_LEVEL: { + return { + ...state, + player: { + ...state.player, + brightnessLevel: action.payload.level, + } + } + } + case SettingsActionTypes.CHANGE_CONTRAST_LEVEL: { + return { + ...state, + player: { + ...state.player, + contrastLevel: action.payload.level, + } + } + } + case SettingsActionTypes.CHANGE_SATURATION_LEVEL: { + return { + ...state, + player: { + ...state.player, + saturationLevel: action.payload.level, + } + } + } + case SettingsActionTypes.SWITCH_AUTO_SAVE: { + return { + ...state, + workspace: { + ...state.workspace, + autoSave: action.payload.autoSave, + } + } + } + case SettingsActionTypes.CHANGE_AUTO_SAVE_INTERVAL: { + return { + ...state, + workspace: { + ...state.workspace, + autoSaveInterval: action.payload.autoSaveInterval, + } + } + } + case SettingsActionTypes.CHANGE_AAM_ZOOM_MARGIN: { + return { + ...state, + workspace: { + ...state.workspace, + aamZoomMargin: action.payload.aamZoomMargin, + } + } + } + case SettingsActionTypes.SWITCH_SHOWNIG_INTERPOLATED_TRACKS: { + return { + ...state, + workspace: { + ...state.workspace, + showAllInterpolationTracks: action.payload.showAllInterpolationTracks, + } + } + } default: { return state; } From 1d5699862445eb1db4f7ef693743d0d1e493dfdc Mon Sep 17 00:00:00 2001 From: Dmitry Kalinin Date: Tue, 18 Feb 2020 14:22:07 +0300 Subject: [PATCH 02/14] Added image filters for background and autosaving --- .../standard-workspace/canvas-wrapper.tsx | 12 +++++++ .../settings-page/player-settings.tsx | 3 ++ .../standard-workspace/canvas-wrapper.tsx | 9 ++++++ .../annotation-page/top-bar/top-bar.tsx | 31 ++++++++++++++++++- 4 files changed, 54 insertions(+), 1 deletion(-) diff --git a/cvat-ui/src/components/annotation-page/standard-workspace/canvas-wrapper.tsx b/cvat-ui/src/components/annotation-page/standard-workspace/canvas-wrapper.tsx index 6c9cc997d357..590cfa5892ea 100644 --- a/cvat-ui/src/components/annotation-page/standard-workspace/canvas-wrapper.tsx +++ b/cvat-ui/src/components/annotation-page/standard-workspace/canvas-wrapper.tsx @@ -39,6 +39,9 @@ interface Props { gridOpacity: number; activeLabelID: number; activeObjectType: ObjectType; + brightnessLevel: number; + contrastLevel: number; + saturationLevel: number; onSetupCanvas: () => void; onDragCanvas: (enabled: boolean) => void; onZoomCanvas: (enabled: boolean) => void; @@ -325,6 +328,9 @@ export default class CanvasWrapperComponent extends React.PureComponent { onActivateObject, onUpdateContextMenu, onEditShape, + brightnessLevel, + contrastLevel, + saturationLevel, } = this.props; // Size @@ -343,6 +349,12 @@ export default class CanvasWrapperComponent extends React.PureComponent { } canvasInstance.grid(gridSize, gridSize); + // Filters + const backgroundElement = window.document.getElementById('cvat_canvas_background'); + if (backgroundElement) { + backgroundElement.style.filter = `brightness(${brightnessLevel/50}) contrast(${contrastLevel/50}) saturate(${saturationLevel/50})`; + } + // Events canvasInstance.html().addEventListener('mousedown', (e: MouseEvent): void => { const { diff --git a/cvat-ui/src/components/settings-page/player-settings.tsx b/cvat-ui/src/components/settings-page/player-settings.tsx index 2f5e5c55fda8..8447f10e54de 100644 --- a/cvat-ui/src/components/settings-page/player-settings.tsx +++ b/cvat-ui/src/components/settings-page/player-settings.tsx @@ -138,6 +138,7 @@ export default function PlayerSettingsComponent(props: Props): JSX.Element { max={1000} step={1} value={gridSize} + disabled={!grid} onChange={(value: number | undefined): void => { if (value) { onChangeGridSize(value); @@ -149,6 +150,7 @@ export default function PlayerSettingsComponent(props: Props): JSX.Element { Grid color { onChangeFrameSpeed(speed); @@ -220,8 +220,8 @@ export default function PlayerSettingsComponent(props: Props): JSX.Element { { onChangeBrightnessLevel(value as number); @@ -235,12 +235,12 @@ export default function PlayerSettingsComponent(props: Props): JSX.Element { { onChangeContrastLevel(value as number); - }} + }} />
@@ -251,7 +251,7 @@ export default function PlayerSettingsComponent(props: Props): JSX.Element { { onChangeSaturationLevel(value as number); diff --git a/cvat-ui/src/components/task-page/job-list.tsx b/cvat-ui/src/components/task-page/job-list.tsx index f3d10ccc68c0..ab4edfddc151 100644 --- a/cvat-ui/src/components/task-page/job-list.tsx +++ b/cvat-ui/src/components/task-page/job-list.tsx @@ -36,16 +36,18 @@ export default function JobListComponent(props: Props): JSX.Element { onJobUpdate, } = props; - const { jobs } = taskInstance; + const { jobs, id: taskId } = taskInstance; const columns = [{ title: 'Job', dataIndex: 'job', key: 'job', - render: (id: number): JSX.Element => (
- {`Job #${id}`} - {" | "} + render: (id: number): JSX.Element => ( +
+ {`Job #${id}`} + {' | '} Old -
), +
+ ), }, { title: 'Frames', dataIndex: 'frames', diff --git a/cvat-ui/src/containers/annotation-page/top-bar/top-bar.tsx b/cvat-ui/src/containers/annotation-page/top-bar/top-bar.tsx index 69f895239b17..705859b121b3 100644 --- a/cvat-ui/src/containers/annotation-page/top-bar/top-bar.tsx +++ b/cvat-ui/src/containers/annotation-page/top-bar/top-bar.tsx @@ -27,7 +27,7 @@ interface StateToProps { frameChangeTime: number | null; playing: boolean; saving: boolean; - unsaved: boolean, + unsaved: boolean; canvasInstance: Canvas; canvasIsReady: boolean; savingStatuses: string[]; @@ -82,7 +82,7 @@ function mapStateToProps(state: CombinedState): StateToProps { workspace: { autoSave, autoSaveInterval, - } + }, }, } = state; @@ -132,8 +132,29 @@ function mapDispatchToProps(dispatch: any): DispatchToProps { type Props = StateToProps & DispatchToProps; class AnnotationTopBarContainer extends React.PureComponent { + private static beforeUnloadCallback(event: BeforeUnloadEvent): any { + const confirmationMessage = 'You have unsaved changes, please confirm leaving this page.'; + // eslint-disable-next-line no-param-reassign + (event || window.event).returnValue = confirmationMessage; + return confirmationMessage; + } + private autoSaveInterval: number | undefined; + componentDidMount(): void { + const { + autoSave, + autoSaveInterval, + saving, + } = this.props; + + this.autoSaveInterval = window.setInterval((): void => { + if (autoSave && !saving) { + this.onSaveAnnotation(); + } + }, autoSaveInterval); + } + public componentDidUpdate(): void { const { jobInstance, @@ -143,12 +164,15 @@ class AnnotationTopBarContainer extends React.PureComponent { playing, canvasIsReady, onSwitchPlay, + unsaved, } = this.props; - + if (playing && canvasIsReady) { if (frameNumber < jobInstance.stopFrame) { - const delay: number = frameChangeTime ? Math.max(0,~~(1000/frameSpeed) - new Date().getTime() + frameChangeTime) : 0; + const delay: number = frameChangeTime + ? Math.max(0, Math.round(1000 / frameSpeed) + - new Date().getTime() + frameChangeTime) : 0; setTimeout(() => { const { playing: stillPlaying } = this.props; if (stillPlaying) { @@ -159,40 +183,21 @@ class AnnotationTopBarContainer extends React.PureComponent { onSwitchPlay(false); } } - } - - componentDidMount(): void { - const { - autoSave, - autoSaveInterval, - saving, - unsaved, - } = this.props; - - this.autoSaveInterval = window.setInterval((autoSave: boolean, saving: boolean): void => { - if (autoSave && !saving) { - this.onSaveAnnotation(); - } - }, autoSaveInterval, autoSave, saving); if (unsaved) { - window.addEventListener('beforeunload', this.beforeUnloadCallback); + window.addEventListener('beforeunload', AnnotationTopBarContainer.beforeUnloadCallback); + } else { + window.removeEventListener('beforeunload', AnnotationTopBarContainer.beforeUnloadCallback); } } - public componentWillUnmount() : void { + public componentWillUnmount(): void { window.clearInterval(this.autoSaveInterval); - window.removeEventListener('beforeunload', this.beforeUnloadCallback); - } - - private beforeUnloadCallback(event: BeforeUnloadEvent): any { - const confirmationMessage = 'You have unsaved changes, please confirm leaving this page.'; - (event || window.event).returnValue = confirmationMessage; - return confirmationMessage; + window.removeEventListener('beforeunload', AnnotationTopBarContainer.beforeUnloadCallback); } private onChangeFrame(newFrame: number, time: number | null = null): void { - const { + const { canvasInstance, canvasIsReady, onChangeFrame, diff --git a/cvat-ui/src/reducers/interfaces.ts b/cvat-ui/src/reducers/interfaces.ts index 21889c1a6e13..f7ba149125d8 100644 --- a/cvat-ui/src/reducers/interfaces.ts +++ b/cvat-ui/src/reducers/interfaces.ts @@ -325,7 +325,7 @@ export interface AnnotationState { uploading: boolean; statuses: string[]; }; - unsaved: boolean, + unsaved: boolean; }; propagate: { objectState: any | null; diff --git a/cvat-ui/src/reducers/settings-reducer.ts b/cvat-ui/src/reducers/settings-reducer.ts index a0274e322566..9879e2b34228 100644 --- a/cvat-ui/src/reducers/settings-reducer.ts +++ b/cvat-ui/src/reducers/settings-reducer.ts @@ -30,9 +30,9 @@ const defaultState: SettingsState = { gridSize: 100, gridColor: GridColor.White, gridOpacity: 0, - brightnessLevel: 50, - contrastLevel: 50, - saturationLevel: 50, + brightnessLevel: 100, + contrastLevel: 100, + saturationLevel: 100, }, }; @@ -125,8 +125,8 @@ export default (state = defaultState, action: AnyAction): SettingsState => { player: { ...state.player, frameStep: action.payload.frameStep, - } - } + }, + }; } case SettingsActionTypes.CHANGE_FRAME_SPEED: { return { @@ -134,8 +134,8 @@ export default (state = defaultState, action: AnyAction): SettingsState => { player: { ...state.player, frameSpeed: action.payload.frameSpeed, - } - } + }, + }; } case SettingsActionTypes.SWITCH_RESET_ZOOM: { return { @@ -143,8 +143,8 @@ export default (state = defaultState, action: AnyAction): SettingsState => { player: { ...state.player, resetZoom: action.payload.resetZoom, - } - } + }, + }; } case SettingsActionTypes.CHANGE_BRIGHTNESS_LEVEL: { return { @@ -152,8 +152,8 @@ export default (state = defaultState, action: AnyAction): SettingsState => { player: { ...state.player, brightnessLevel: action.payload.level, - } - } + }, + }; } case SettingsActionTypes.CHANGE_CONTRAST_LEVEL: { return { @@ -161,8 +161,8 @@ export default (state = defaultState, action: AnyAction): SettingsState => { player: { ...state.player, contrastLevel: action.payload.level, - } - } + }, + }; } case SettingsActionTypes.CHANGE_SATURATION_LEVEL: { return { @@ -170,8 +170,8 @@ export default (state = defaultState, action: AnyAction): SettingsState => { player: { ...state.player, saturationLevel: action.payload.level, - } - } + }, + }; } case SettingsActionTypes.SWITCH_AUTO_SAVE: { return { @@ -179,8 +179,8 @@ export default (state = defaultState, action: AnyAction): SettingsState => { workspace: { ...state.workspace, autoSave: action.payload.autoSave, - } - } + }, + }; } case SettingsActionTypes.CHANGE_AUTO_SAVE_INTERVAL: { return { @@ -188,8 +188,8 @@ export default (state = defaultState, action: AnyAction): SettingsState => { workspace: { ...state.workspace, autoSaveInterval: action.payload.autoSaveInterval, - } - } + }, + }; } case SettingsActionTypes.CHANGE_AAM_ZOOM_MARGIN: { return { @@ -197,8 +197,8 @@ export default (state = defaultState, action: AnyAction): SettingsState => { workspace: { ...state.workspace, aamZoomMargin: action.payload.aamZoomMargin, - } - } + }, + }; } case SettingsActionTypes.SWITCH_SHOWNIG_INTERPOLATED_TRACKS: { return { @@ -206,8 +206,8 @@ export default (state = defaultState, action: AnyAction): SettingsState => { workspace: { ...state.workspace, showAllInterpolationTracks: action.payload.showAllInterpolationTracks, - } - } + }, + }; } default: { return state; From 4972f0acf2a438efc669a4cb474d568abbb450d8 Mon Sep 17 00:00:00 2001 From: Dmitry Kalinin Date: Thu, 20 Feb 2020 15:15:10 +0300 Subject: [PATCH 06/14] PR fixes --- cvat-ui/src/actions/annotation-actions.ts | 14 ++++-- .../settings-page/workspace-settings.tsx | 2 +- cvat-ui/src/components/task-page/job-list.tsx | 2 +- .../annotation-page/top-bar/top-bar.tsx | 46 +++++++++---------- cvat-ui/src/reducers/annotation-reducer.ts | 9 ++-- cvat-ui/src/reducers/interfaces.ts | 1 + 6 files changed, 42 insertions(+), 32 deletions(-) diff --git a/cvat-ui/src/actions/annotation-actions.ts b/cvat-ui/src/actions/annotation-actions.ts index efd882826b2b..caa86ba31c2b 100644 --- a/cvat-ui/src/actions/annotation-actions.ts +++ b/cvat-ui/src/actions/annotation-actions.ts @@ -545,7 +545,7 @@ export function switchPlay(playing: boolean): AnyAction { }; } -export function changeFrameAsync(toFrame: number, frameChangeTime: number | null): +export function changeFrameAsync(toFrame: number): ThunkAction, {}, {}, AnyAction> { return async (dispatch: ActionCreator): Promise => { const state: CombinedState = getStore().getState(); @@ -558,13 +558,17 @@ ThunkAction, {}, {}, AnyAction> { } if (toFrame === frame) { + const currentTime = new Date().getTime(); + const delay = Math.max(0, Math.round(1000 / state.settings.player.frameSpeed) + - currentTime + (state.annotation.player.frame.changeTime as number)); dispatch({ type: AnnotationActionTypes.CHANGE_FRAME_SUCCESS, payload: { number: state.annotation.player.frame.number, data: state.annotation.player.frame.data, states: state.annotation.annotations.states, - frameChangeTime, + changeTime: currentTime + delay, + delay, }, }); @@ -579,13 +583,17 @@ ThunkAction, {}, {}, AnyAction> { const data = await job.frames.get(toFrame); const states = await job.annotations.get(toFrame, showAllInterpolationTracks, filters); + const currentTime = new Date().getTime(); + const delay = Math.max(0, Math.round(1000 / state.settings.player.frameSpeed) + - currentTime + (state.annotation.player.frame.changeTime as number)); dispatch({ type: AnnotationActionTypes.CHANGE_FRAME_SUCCESS, payload: { number: toFrame, data, states, - frameChangeTime, + changeTime: currentTime + delay, + delay, }, }); } catch (error) { diff --git a/cvat-ui/src/components/settings-page/workspace-settings.tsx b/cvat-ui/src/components/settings-page/workspace-settings.tsx index 263c4ae3fd60..c704f8fa0626 100644 --- a/cvat-ui/src/components/settings-page/workspace-settings.tsx +++ b/cvat-ui/src/components/settings-page/workspace-settings.tsx @@ -58,7 +58,7 @@ export default function WorkspaceSettingsComponent(props: Props): JSX.Element { value={Math.round(autoSaveInterval / (60 * 1000))} onChange={(value: number | undefined): void => { if (value) { - onChangeAutoSaveInterval(value as number * 60 * 1000); + onChangeAutoSaveInterval(value * 60 * 1000); } }} /> diff --git a/cvat-ui/src/components/task-page/job-list.tsx b/cvat-ui/src/components/task-page/job-list.tsx index ab4edfddc151..658ea16c7306 100644 --- a/cvat-ui/src/components/task-page/job-list.tsx +++ b/cvat-ui/src/components/task-page/job-list.tsx @@ -45,7 +45,7 @@ export default function JobListComponent(props: Props): JSX.Element {
{`Job #${id}`} {' | '} - Old + Legacy UI
), }, { diff --git a/cvat-ui/src/containers/annotation-page/top-bar/top-bar.tsx b/cvat-ui/src/containers/annotation-page/top-bar/top-bar.tsx index 705859b121b3..4b545dd7a942 100644 --- a/cvat-ui/src/containers/annotation-page/top-bar/top-bar.tsx +++ b/cvat-ui/src/containers/annotation-page/top-bar/top-bar.tsx @@ -24,7 +24,7 @@ interface StateToProps { frameNumber: number; frameStep: number; frameSpeed: FrameSpeed; - frameChangeTime: number | null; + frameDelay: number; playing: boolean; saving: boolean; unsaved: boolean; @@ -39,7 +39,7 @@ interface StateToProps { } interface DispatchToProps { - onChangeFrame(frame: number, time: number | null): void; + onChangeFrame(frame: number): void; onSwitchPlay(playing: boolean): void; onSaveAnnotation(sessionInstance: any): void; showStatistics(sessionInstance: any): void; @@ -54,7 +54,7 @@ function mapStateToProps(state: CombinedState): StateToProps { playing, frame: { number: frameNumber, - changeTime: frameChangeTime, + delay: frameDelay, }, }, annotations: { @@ -89,7 +89,7 @@ function mapStateToProps(state: CombinedState): StateToProps { return { frameStep, frameSpeed, - frameChangeTime, + frameDelay, playing, canvasInstance, canvasIsReady, @@ -108,8 +108,8 @@ function mapStateToProps(state: CombinedState): StateToProps { function mapDispatchToProps(dispatch: any): DispatchToProps { return { - onChangeFrame(frame: number, time: number | null): void { - dispatch(changeFrameAsync(frame, time)); + onChangeFrame(frame: number): void { + dispatch(changeFrameAsync(frame)); }, onSwitchPlay(playing: boolean): void { dispatch(switchPlay(playing)); @@ -159,36 +159,33 @@ class AnnotationTopBarContainer extends React.PureComponent { const { jobInstance, frameNumber, - frameChangeTime, - frameSpeed, + frameDelay, playing, canvasIsReady, onSwitchPlay, - unsaved, } = this.props; if (playing && canvasIsReady) { if (frameNumber < jobInstance.stopFrame) { - const delay: number = frameChangeTime - ? Math.max(0, Math.round(1000 / frameSpeed) - - new Date().getTime() + frameChangeTime) : 0; setTimeout(() => { const { playing: stillPlaying } = this.props; if (stillPlaying) { - this.onChangeFrame(frameNumber + 1, new Date().getTime()); + this.onChangeFrame(frameNumber + 1); } - }, delay); + }, frameDelay); } else { onSwitchPlay(false); } } - if (unsaved) { - window.addEventListener('beforeunload', AnnotationTopBarContainer.beforeUnloadCallback); - } else { - window.removeEventListener('beforeunload', AnnotationTopBarContainer.beforeUnloadCallback); - } + jobInstance.annotations.hasUnsavedChanges().then((unsaved: boolean) => { + if (unsaved) { + window.addEventListener('beforeunload', AnnotationTopBarContainer.beforeUnloadCallback); + } else { + window.removeEventListener('beforeunload', AnnotationTopBarContainer.beforeUnloadCallback); + } + }); } public componentWillUnmount(): void { @@ -196,18 +193,19 @@ class AnnotationTopBarContainer extends React.PureComponent { window.removeEventListener('beforeunload', AnnotationTopBarContainer.beforeUnloadCallback); } - private onChangeFrame(newFrame: number, time: number | null = null): void { + private onChangeFrame(newFrame: number): void { const { canvasInstance, - canvasIsReady, onChangeFrame, resetZoom, } = this.props; - onChangeFrame(newFrame, time); + onChangeFrame(newFrame); - if (canvasIsReady && resetZoom) { - canvasInstance.fit(); + if (resetZoom) { + canvasInstance.html().addEventListener('canvas.setup', () => { + canvasInstance.fit(); + }, { once: true }); } } diff --git a/cvat-ui/src/reducers/annotation-reducer.ts b/cvat-ui/src/reducers/annotation-reducer.ts index 7b42cd298005..c0bb8124612d 100644 --- a/cvat-ui/src/reducers/annotation-reducer.ts +++ b/cvat-ui/src/reducers/annotation-reducer.ts @@ -36,7 +36,8 @@ const defaultState: AnnotationState = { number: 0, data: null, fetching: false, - changeTime: null + delay: 0, + changeTime: null, }, playing: false, }, @@ -162,7 +163,8 @@ export default (state = defaultState, action: AnyAction): AnnotationState => { number, data, states, - frameChangeTime + delay, + changeTime, } = action.payload; const activatedStateID = states @@ -177,7 +179,8 @@ export default (state = defaultState, action: AnyAction): AnnotationState => { data, number, fetching: false, - changeTime: frameChangeTime, + changeTime, + delay, }, }, annotations: { diff --git a/cvat-ui/src/reducers/interfaces.ts b/cvat-ui/src/reducers/interfaces.ts index f7ba149125d8..3cf7fc73292c 100644 --- a/cvat-ui/src/reducers/interfaces.ts +++ b/cvat-ui/src/reducers/interfaces.ts @@ -300,6 +300,7 @@ export interface AnnotationState { number: number; data: any | null; fetching: boolean; + delay: number; changeTime: number | null; }; playing: boolean; From 8c2fe43459c8e79f26ed99466ed440d41da4d61c Mon Sep 17 00:00:00 2001 From: Dmitry Kalinin Date: Thu, 20 Feb 2020 15:18:34 +0300 Subject: [PATCH 07/14] Another PR fixes --- cvat-ui/src/containers/annotation-page/top-bar/top-bar.tsx | 3 --- cvat-ui/src/reducers/annotation-reducer.ts | 3 --- cvat-ui/src/reducers/interfaces.ts | 1 - 3 files changed, 7 deletions(-) diff --git a/cvat-ui/src/containers/annotation-page/top-bar/top-bar.tsx b/cvat-ui/src/containers/annotation-page/top-bar/top-bar.tsx index 4b545dd7a942..107ad868417a 100644 --- a/cvat-ui/src/containers/annotation-page/top-bar/top-bar.tsx +++ b/cvat-ui/src/containers/annotation-page/top-bar/top-bar.tsx @@ -27,7 +27,6 @@ interface StateToProps { frameDelay: number; playing: boolean; saving: boolean; - unsaved: boolean; canvasInstance: Canvas; canvasIsReady: boolean; savingStatuses: string[]; @@ -63,7 +62,6 @@ function mapStateToProps(state: CombinedState): StateToProps { statuses: savingStatuses, }, history, - unsaved, }, job: { instance: jobInstance, @@ -95,7 +93,6 @@ function mapStateToProps(state: CombinedState): StateToProps { canvasIsReady, saving, savingStatuses, - unsaved, frameNumber, jobInstance, undoAction: history.undo[history.undo.length - 1], diff --git a/cvat-ui/src/reducers/annotation-reducer.ts b/cvat-ui/src/reducers/annotation-reducer.ts index c0bb8124612d..f4a125b88d82 100644 --- a/cvat-ui/src/reducers/annotation-reducer.ts +++ b/cvat-ui/src/reducers/annotation-reducer.ts @@ -60,7 +60,6 @@ const defaultState: AnnotationState = { undo: [], redo: [], }, - unsaved: false, }, propagate: { objectState: null, @@ -224,7 +223,6 @@ export default (state = defaultState, action: AnyAction): AnnotationState => { ...state.annotations.saving, uploading: false, }, - unsaved: false, }, }; } @@ -361,7 +359,6 @@ export default (state = defaultState, action: AnyAction): AnnotationState => { annotations: { ...state.annotations, activatedStateID: null, - unsaved: true, }, canvas: { ...state.canvas, diff --git a/cvat-ui/src/reducers/interfaces.ts b/cvat-ui/src/reducers/interfaces.ts index 3cf7fc73292c..cea83459767a 100644 --- a/cvat-ui/src/reducers/interfaces.ts +++ b/cvat-ui/src/reducers/interfaces.ts @@ -326,7 +326,6 @@ export interface AnnotationState { uploading: boolean; statuses: string[]; }; - unsaved: boolean; }; propagate: { objectState: any | null; From 60f44776dc5a82fb48245f11ac87a9bdeff3a95d Mon Sep 17 00:00:00 2001 From: Dmitry Kalinin Date: Fri, 21 Feb 2020 17:44:28 +0300 Subject: [PATCH 08/14] Fixed link to new job and unsaved changes message --- cvat-ui/src/actions/annotation-actions.ts | 7 +++ .../annotation-page/top-bar/top-bar.tsx | 2 + cvat-ui/src/components/task-page/job-list.tsx | 30 ++++++++-- .../objects-side-bar/object-item.tsx | 2 +- .../annotation-page/top-bar/top-bar.tsx | 60 +++++++++++++++---- cvat-ui/src/containers/task-page/job-list.tsx | 9 +++ cvat-ui/src/reducers/annotation-reducer.ts | 9 +++ 7 files changed, 101 insertions(+), 18 deletions(-) diff --git a/cvat-ui/src/actions/annotation-actions.ts b/cvat-ui/src/actions/annotation-actions.ts index caa86ba31c2b..38efcbbe3694 100644 --- a/cvat-ui/src/actions/annotation-actions.ts +++ b/cvat-ui/src/actions/annotation-actions.ts @@ -48,6 +48,7 @@ export enum AnnotationActionTypes { GET_JOB = 'GET_JOB', GET_JOB_SUCCESS = 'GET_JOB_SUCCESS', GET_JOB_FAILED = 'GET_JOB_FAILED', + REMOVE_JOB = 'REMOVE_JOB', CHANGE_FRAME = 'CHANGE_FRAME', CHANGE_FRAME_SUCCESS = 'CHANGE_FRAME_SUCCESS', CHANGE_FRAME_FAILED = 'CHANGE_FRAME_FAILED', @@ -702,6 +703,12 @@ export function getJobAsync( }; } +export function removeJob(): AnyAction { + return { + type: AnnotationActionTypes.REMOVE_JOB, + }; +} + export function saveAnnotationsAsync(sessionInstance: any): ThunkAction, {}, {}, AnyAction> { return async (dispatch: ActionCreator): Promise => { diff --git a/cvat-ui/src/components/annotation-page/top-bar/top-bar.tsx b/cvat-ui/src/components/annotation-page/top-bar/top-bar.tsx index 06a1654171a3..eb61cde1868e 100644 --- a/cvat-ui/src/components/annotation-page/top-bar/top-bar.tsx +++ b/cvat-ui/src/components/annotation-page/top-bar/top-bar.tsx @@ -20,6 +20,7 @@ interface Props { frameNumber: number; startFrame: number; stopFrame: number; + annotations: any; undoAction?: string; redoAction?: string; showStatistics(): void; @@ -48,6 +49,7 @@ function AnnotationTopBarComponent(props: Props): JSX.Element { frameNumber, startFrame, stopFrame, + annotations, showStatistics, onSwitchPlay, onSaveAnnotation, diff --git a/cvat-ui/src/components/task-page/job-list.tsx b/cvat-ui/src/components/task-page/job-list.tsx index 658ea16c7306..1eaa527e545c 100644 --- a/cvat-ui/src/components/task-page/job-list.tsx +++ b/cvat-ui/src/components/task-page/job-list.tsx @@ -1,6 +1,7 @@ import React from 'react'; -import { Link } from 'react-router-dom'; +import { RouteComponentProps } from 'react-router'; +import { withRouter } from 'react-router-dom'; import { Row, @@ -26,14 +27,21 @@ const baseURL = core.config.backendAPI.slice(0, -7); interface Props { taskInstance: any; registeredUsers: any[]; + currentJobId: number | null; onJobUpdate(jobInstance: any): void; + onJobremove(): void; } -export default function JobListComponent(props: Props): JSX.Element { +function JobListComponent(props: Props & RouteComponentProps): JSX.Element { const { taskInstance, registeredUsers, onJobUpdate, + onJobremove, + currentJobId, + history: { + push, + }, } = props; const { jobs, id: taskId } = taskInstance; @@ -43,9 +51,19 @@ export default function JobListComponent(props: Props): JSX.Element { key: 'job', render: (id: number): JSX.Element => (
- {`Job #${id}`} - {' | '} - Legacy UI + + | +
), }, { @@ -176,3 +194,5 @@ export default function JobListComponent(props: Props): JSX.Element { ); } + +export default withRouter(JobListComponent); diff --git a/cvat-ui/src/containers/annotation-page/standard-workspace/objects-side-bar/object-item.tsx b/cvat-ui/src/containers/annotation-page/standard-workspace/objects-side-bar/object-item.tsx index 7c299d16c3b2..f4baecdbec30 100644 --- a/cvat-ui/src/containers/annotation-page/standard-workspace/objects-side-bar/object-item.tsx +++ b/cvat-ui/src/containers/annotation-page/standard-workspace/objects-side-bar/object-item.tsx @@ -99,7 +99,7 @@ function mapStateToProps(state: CombinedState, own: OwnProps): StateToProps { function mapDispatchToProps(dispatch: any): DispatchToProps { return { changeFrame(frame: number): void { - dispatch(changeFrameAsync(frame, null)); + dispatch(changeFrameAsync(frame)); }, updateState(sessionInstance: any, frameNumber: number, state: any): void { dispatch(updateAnnotationsAsync(sessionInstance, frameNumber, [state])); diff --git a/cvat-ui/src/containers/annotation-page/top-bar/top-bar.tsx b/cvat-ui/src/containers/annotation-page/top-bar/top-bar.tsx index 107ad868417a..d239461ddccc 100644 --- a/cvat-ui/src/containers/annotation-page/top-bar/top-bar.tsx +++ b/cvat-ui/src/containers/annotation-page/top-bar/top-bar.tsx @@ -2,6 +2,9 @@ import React from 'react'; import copy from 'copy-to-clipboard'; import { connect } from 'react-redux'; +import { withRouter } from 'react-router'; +import { RouteComponentProps } from 'react-router-dom'; + import { Canvas } from 'cvat-canvas'; import { SliderValue } from 'antd/lib/slider'; @@ -127,7 +130,7 @@ function mapDispatchToProps(dispatch: any): DispatchToProps { }; } -type Props = StateToProps & DispatchToProps; +type Props = StateToProps & DispatchToProps & RouteComponentProps; class AnnotationTopBarContainer extends React.PureComponent { private static beforeUnloadCallback(event: BeforeUnloadEvent): any { const confirmationMessage = 'You have unsaved changes, please confirm leaving this page.'; @@ -137,6 +140,7 @@ class AnnotationTopBarContainer extends React.PureComponent { } private autoSaveInterval: number | undefined; + private unblock: any; componentDidMount(): void { const { @@ -150,6 +154,8 @@ class AnnotationTopBarContainer extends React.PureComponent { this.onSaveAnnotation(); } }, autoSaveInterval); + + this.checkUnsavedChanges(); } public componentDidUpdate(): void { @@ -176,18 +182,16 @@ class AnnotationTopBarContainer extends React.PureComponent { } } - jobInstance.annotations.hasUnsavedChanges().then((unsaved: boolean) => { - if (unsaved) { - window.addEventListener('beforeunload', AnnotationTopBarContainer.beforeUnloadCallback); - } else { - window.removeEventListener('beforeunload', AnnotationTopBarContainer.beforeUnloadCallback); - } - }); + this.checkUnsavedChanges(); } public componentWillUnmount(): void { window.clearInterval(this.autoSaveInterval); window.removeEventListener('beforeunload', AnnotationTopBarContainer.beforeUnloadCallback); + if (typeof this.unblock === 'function') { + this.unblock(); + this.unblock = undefined; + } } private onChangeFrame(newFrame: number): void { @@ -403,6 +407,34 @@ class AnnotationTopBarContainer extends React.PureComponent { copy(url); }; + private checkUnsavedChanges(): void { + const { + jobInstance, + history, + } = this.props; + + jobInstance.annotations.hasUnsavedChanges().then((unsaved: boolean) => { + if (unsaved) { + window.addEventListener('beforeunload', AnnotationTopBarContainer.beforeUnloadCallback); + if (this.unblock === undefined) { + this.unblock = history.block((location) => { + if (location.pathname !== '/settings' && location.pathname + !== `/tasks/${jobInstance.task.id}/jobs/${jobInstance.id}`) { + return 'You have unsaved changes, please confirm leaving this page.'; + } + return undefined; + }); + } + } else { + window.removeEventListener('beforeunload', AnnotationTopBarContainer.beforeUnloadCallback); + if (typeof this.unblock === 'function') { + this.unblock(); + this.unblock = undefined; + } + } + }); + } + public render(): JSX.Element { const { playing, @@ -411,6 +443,7 @@ class AnnotationTopBarContainer extends React.PureComponent { jobInstance: { startFrame, stopFrame, + annotations, }, frameNumber, undoAction, @@ -437,6 +470,7 @@ class AnnotationTopBarContainer extends React.PureComponent { startFrame={startFrame} stopFrame={stopFrame} frameNumber={frameNumber} + annotations={annotations} undoAction={undoAction} redoAction={redoAction} onUndoClick={this.undo} @@ -446,7 +480,9 @@ class AnnotationTopBarContainer extends React.PureComponent { } } -export default connect( - mapStateToProps, - mapDispatchToProps, -)(AnnotationTopBarContainer); +export default withRouter( + connect( + mapStateToProps, + mapDispatchToProps, + )(AnnotationTopBarContainer), +); diff --git a/cvat-ui/src/containers/task-page/job-list.tsx b/cvat-ui/src/containers/task-page/job-list.tsx index 04ca7ecdc093..4734c66c8273 100644 --- a/cvat-ui/src/containers/task-page/job-list.tsx +++ b/cvat-ui/src/containers/task-page/job-list.tsx @@ -3,6 +3,7 @@ import { connect } from 'react-redux'; import JobListComponent from 'components/task-page/job-list'; import { updateJobAsync } from 'actions/tasks-actions'; +import { removeJob } from 'actions/annotation-actions'; import { Task, CombinedState, @@ -14,21 +15,25 @@ interface OwnProps { interface StateToProps { registeredUsers: any[]; + currentJobId: number | null; } interface DispatchToProps { onJobUpdate(jobInstance: any): void; + onJobRemove(): void; } function mapStateToProps(state: CombinedState): StateToProps { return { registeredUsers: state.users.users, + currentJobId: state.annotation.job.instance ? state.annotation.job.instance.id : null, }; } function mapDispatchToProps(dispatch: any): DispatchToProps { return { onJobUpdate: (jobInstance: any): void => dispatch(updateJobAsync(jobInstance)), + onJobRemove: (): void => dispatch(removeJob()), }; } @@ -37,13 +42,17 @@ function TaskPageContainer(props: StateToProps & DispatchToProps & OwnProps): JS task, registeredUsers, onJobUpdate, + currentJobId, + onJobRemove, } = props; return ( ); } diff --git a/cvat-ui/src/reducers/annotation-reducer.ts b/cvat-ui/src/reducers/annotation-reducer.ts index f4a125b88d82..47e4e2c9d880 100644 --- a/cvat-ui/src/reducers/annotation-reducer.ts +++ b/cvat-ui/src/reducers/annotation-reducer.ts @@ -141,6 +141,15 @@ export default (state = defaultState, action: AnyAction): AnnotationState => { }, }; } + case AnnotationActionTypes.REMOVE_JOB: { + return { + ...defaultState, + canvas: { + ...defaultState.canvas, + instance: new Canvas(), + }, + }; + } case AnnotationActionTypes.CHANGE_FRAME: { return { ...state, From 22b68216aaf74a5090a017a036ae47125f37eea6 Mon Sep 17 00:00:00 2001 From: Dmitry Kalinin Date: Tue, 25 Feb 2020 19:47:01 +0300 Subject: [PATCH 09/14] Fixed PR --- cvat-ui/src/actions/annotation-actions.ts | 40 +++++++----- .../annotation-page/annotation-page.tsx | 16 ++++- .../standard-workspace/canvas-wrapper.tsx | 8 +++ .../annotation-page/top-bar/top-bar.tsx | 2 - cvat-ui/src/components/task-page/job-list.tsx | 7 --- .../annotation-page/annotation-page.tsx | 2 +- .../standard-workspace/canvas-wrapper.tsx | 3 + .../annotation-page/top-bar/top-bar.tsx | 61 +++++++++---------- cvat-ui/src/containers/task-page/job-list.tsx | 9 --- cvat-ui/src/reducers/annotation-reducer.ts | 2 +- 10 files changed, 81 insertions(+), 69 deletions(-) diff --git a/cvat-ui/src/actions/annotation-actions.ts b/cvat-ui/src/actions/annotation-actions.ts index 38efcbbe3694..c17ec81c600e 100644 --- a/cvat-ui/src/actions/annotation-actions.ts +++ b/cvat-ui/src/actions/annotation-actions.ts @@ -12,6 +12,7 @@ import { ShapeType, ObjectType, Task, + FrameSpeed, } from 'reducers/interfaces'; import getCore from 'cvat-core'; @@ -48,7 +49,7 @@ export enum AnnotationActionTypes { GET_JOB = 'GET_JOB', GET_JOB_SUCCESS = 'GET_JOB_SUCCESS', GET_JOB_FAILED = 'GET_JOB_FAILED', - REMOVE_JOB = 'REMOVE_JOB', + CLOSE_JOB = 'CLOSE_JOB', CHANGE_FRAME = 'CHANGE_FRAME', CHANGE_FRAME_SUCCESS = 'CHANGE_FRAME_SUCCESS', CHANGE_FRAME_FAILED = 'CHANGE_FRAME_FAILED', @@ -112,6 +113,7 @@ export enum AnnotationActionTypes { CHANGE_ANNOTATIONS_FILTERS = 'CHANGE_ANNOTATIONS_FILTERS', FETCH_ANNOTATIONS_SUCCESS = 'FETCH_ANNOTATIONS_SUCCESS', FETCH_ANNOTATIONS_FAILED = 'FETCH_ANNOTATIONS_FAILED', + ROTATE_FRAME = 'ROTATE_FRAME', } export function fetchAnnotationsAsync(sessionInstance: any): @@ -559,17 +561,12 @@ ThunkAction, {}, {}, AnyAction> { } if (toFrame === frame) { - const currentTime = new Date().getTime(); - const delay = Math.max(0, Math.round(1000 / state.settings.player.frameSpeed) - - currentTime + (state.annotation.player.frame.changeTime as number)); dispatch({ type: AnnotationActionTypes.CHANGE_FRAME_SUCCESS, payload: { number: state.annotation.player.frame.number, data: state.annotation.player.frame.data, states: state.annotation.annotations.states, - changeTime: currentTime + delay, - delay, }, }); @@ -585,7 +582,21 @@ ThunkAction, {}, {}, AnyAction> { const data = await job.frames.get(toFrame); const states = await job.annotations.get(toFrame, showAllInterpolationTracks, filters); const currentTime = new Date().getTime(); - const delay = Math.max(0, Math.round(1000 / state.settings.player.frameSpeed) + let frameSpeed; + switch (state.settings.player.frameSpeed) { + case (FrameSpeed.Fast): { + frameSpeed = (FrameSpeed.Fast as number) / 2; + break; + } + case (FrameSpeed.Fastest): { + frameSpeed = (FrameSpeed.Fastest as number) / 3; + break; + } + default: { + frameSpeed = state.settings.player.frameSpeed as number; + } + } + const delay = Math.max(0, Math.round(1000 / frameSpeed) - currentTime + (state.annotation.player.frame.changeTime as number)); dispatch({ type: AnnotationActionTypes.CHANGE_FRAME_SUCCESS, @@ -658,7 +669,14 @@ export function getJobAsync( const filters = initialFilters; const { showAllInterpolationTracks } = state.settings.workspace; - // First check state if the task is already there + // Check if already loaded job is different from asking one + if (state.annotation.job.instance && state.annotation.job.instance.id !== jid) { + dispatch({ + type: AnnotationActionTypes.CLOSE_JOB, + }); + } + + // Check state if the task is already there let task = state.tasks.current .filter((_task: Task) => _task.instance.id === tid) .map((_task: Task) => _task.instance)[0]; @@ -703,12 +721,6 @@ export function getJobAsync( }; } -export function removeJob(): AnyAction { - return { - type: AnnotationActionTypes.REMOVE_JOB, - }; -} - export function saveAnnotationsAsync(sessionInstance: any): ThunkAction, {}, {}, AnyAction> { return async (dispatch: ActionCreator): Promise => { diff --git a/cvat-ui/src/components/annotation-page/annotation-page.tsx b/cvat-ui/src/components/annotation-page/annotation-page.tsx index 82c5bcff8353..e5788c2acb86 100644 --- a/cvat-ui/src/components/annotation-page/annotation-page.tsx +++ b/cvat-ui/src/components/annotation-page/annotation-page.tsx @@ -1,6 +1,8 @@ import './styles.scss'; import React from 'react'; +import { RouteComponentProps } from 'react-router'; + import { Layout, Spin, @@ -17,14 +19,24 @@ interface Props { getJob(): void; } -export default function AnnotationPageComponent(props: Props): JSX.Element { +type RoutePros = RouteComponentProps<{ + tid: string; + jid: string; +}>; + +export default function AnnotationPageComponent(props: Props & RoutePros): JSX.Element { const { job, fetching, getJob, + match: { + params, + }, } = props; - if (job === null) { + const jid = +params.jid; + + if (job === null || (job !== undefined && job.id !== jid)) { if (!fetching) { getJob(); } diff --git a/cvat-ui/src/components/annotation-page/standard-workspace/canvas-wrapper.tsx b/cvat-ui/src/components/annotation-page/standard-workspace/canvas-wrapper.tsx index eca33c622efe..032cbc39002d 100644 --- a/cvat-ui/src/components/annotation-page/standard-workspace/canvas-wrapper.tsx +++ b/cvat-ui/src/components/annotation-page/standard-workspace/canvas-wrapper.tsx @@ -42,6 +42,7 @@ interface Props { brightnessLevel: number; contrastLevel: number; saturationLevel: number; + resetZoom: boolean; onSetupCanvas: () => void; onDragCanvas: (enabled: boolean) => void; onZoomCanvas: (enabled: boolean) => void; @@ -92,6 +93,7 @@ export default class CanvasWrapperComponent extends React.PureComponent { canvasInstance, sidebarCollapsed, activatedStateID, + resetZoom, } = this.props; if (prevProps.sidebarCollapsed !== sidebarCollapsed) { @@ -146,6 +148,12 @@ export default class CanvasWrapperComponent extends React.PureComponent { this.updateShapesView(); } + if (prevProps.frame !== frameData.number && resetZoom) { + canvasInstance.html().addEventListener('canvas.setup', () => { + canvasInstance.fit(); + }, { once: true }); + } + this.activateOnCanvas(); } diff --git a/cvat-ui/src/components/annotation-page/top-bar/top-bar.tsx b/cvat-ui/src/components/annotation-page/top-bar/top-bar.tsx index eb61cde1868e..06a1654171a3 100644 --- a/cvat-ui/src/components/annotation-page/top-bar/top-bar.tsx +++ b/cvat-ui/src/components/annotation-page/top-bar/top-bar.tsx @@ -20,7 +20,6 @@ interface Props { frameNumber: number; startFrame: number; stopFrame: number; - annotations: any; undoAction?: string; redoAction?: string; showStatistics(): void; @@ -49,7 +48,6 @@ function AnnotationTopBarComponent(props: Props): JSX.Element { frameNumber, startFrame, stopFrame, - annotations, showStatistics, onSwitchPlay, onSaveAnnotation, diff --git a/cvat-ui/src/components/task-page/job-list.tsx b/cvat-ui/src/components/task-page/job-list.tsx index 1eaa527e545c..1388111bccb8 100644 --- a/cvat-ui/src/components/task-page/job-list.tsx +++ b/cvat-ui/src/components/task-page/job-list.tsx @@ -27,9 +27,7 @@ const baseURL = core.config.backendAPI.slice(0, -7); interface Props { taskInstance: any; registeredUsers: any[]; - currentJobId: number | null; onJobUpdate(jobInstance: any): void; - onJobremove(): void; } function JobListComponent(props: Props & RouteComponentProps): JSX.Element { @@ -37,8 +35,6 @@ function JobListComponent(props: Props & RouteComponentProps): JSX.Element { taskInstance, registeredUsers, onJobUpdate, - onJobremove, - currentJobId, history: { push, }, @@ -54,9 +50,6 @@ function JobListComponent(props: Props & RouteComponentProps): JSX.Element { + | - + + + ), }, {