From f57586a03cffdc99d1f41b6f9fdf1944b7cec1f8 Mon Sep 17 00:00:00 2001 From: Boris Sekachev <40690378+bsekachev@users.noreply.github.com> Date: Thu, 19 Dec 2019 16:17:36 +0300 Subject: [PATCH] UI Enhancements (#985) * Single import of basic styles * A little bit redesigned header * Specified min resolution 1280x768 * Getting a job instance * Improved handling when task doesn't exist --- cvat-ui/src/base.scss | 24 ------ .../annotation-page/annotation-page.tsx | 35 ++++++++- .../components/annotation-page/styles.scss | 64 ++++++++------- .../annotation-page/top-bar/top-bar.tsx | 23 +++--- cvat-ui/src/components/cvat-app.tsx | 6 +- .../model-runner-modal/model-runner-modal.tsx | 2 +- .../components/models-page/models-page.tsx | 2 +- .../src/components/task-page/task-page.tsx | 36 ++++----- .../src/components/tasks-page/tasks-page.tsx | 2 +- .../annotation-page/annotation-page.tsx | 78 ++++++++++++++++++- .../src/containers/task-page/task-page.tsx | 24 ++++-- cvat-ui/src/styles.scss | 34 ++++++++ 12 files changed, 225 insertions(+), 105 deletions(-) create mode 100644 cvat-ui/src/styles.scss diff --git a/cvat-ui/src/base.scss b/cvat-ui/src/base.scss index 99fed8f8013e..17348718f067 100644 --- a/cvat-ui/src/base.scss +++ b/cvat-ui/src/base.scss @@ -15,27 +15,3 @@ $danger-icon-color: #FF4136; $info-icon-color: #0074D9; $monospaced-fonts-stack: Consolas,Monaco,Lucida Console,Liberation Mono,DejaVu Sans Mono,Bitstream Vera Sans Mono,Courier New, monospace; - -hr { - border: none; - border-top: 1px solid $border-color-1; - height: 1px; -} - -.cvat-text-color { - color: $text-color; -} - -.cvat-title { - font-weight: 400; - font-size: 21px; - color: $text-color; - padding-top: 5px; -} - -#root { - width: 100%; - height: 100%; - min-height: 100%; - display: grid; -} diff --git a/cvat-ui/src/components/annotation-page/annotation-page.tsx b/cvat-ui/src/components/annotation-page/annotation-page.tsx index 0c5d4910f01c..12d0b92833e5 100644 --- a/cvat-ui/src/components/annotation-page/annotation-page.tsx +++ b/cvat-ui/src/components/annotation-page/annotation-page.tsx @@ -3,12 +3,45 @@ import React from 'react'; import { Layout, + Spin, + Result, } from 'antd'; import AnnotationTopBarComponent from './top-bar/top-bar'; import StandardWorkspaceComponent from './standard-workspace/standard-workspace'; -export default function AnnotationPageComponent(): JSX.Element { +interface Props { + jobInstance: any | null | undefined; + fetching: boolean; + getJob(): void; +} + +export default function AnnotationPageComponent(props: Props): JSX.Element { + const { + jobInstance, + fetching, + getJob, + } = props; + + if (jobInstance === null) { + if (!fetching) { + getJob(); + } + + return ; + } + + if (typeof (jobInstance) === 'undefined') { + return ( + + ); + } + return ( diff --git a/cvat-ui/src/components/annotation-page/styles.scss b/cvat-ui/src/components/annotation-page/styles.scss index 6ac4b77fb519..deb40196044b 100644 --- a/cvat-ui/src/components/annotation-page/styles.scss +++ b/cvat-ui/src/components/annotation-page/styles.scss @@ -14,46 +14,48 @@ .cvat-annotation-header-left-group { height: 100%; - > div { - padding: 0px; - width: 54px; - height: 54px; - float: left; - text-align: center; + > div:first-child { + filter: invert(0.9); + background: $background-color-1; + border-radius: 0px; + width: 70px; + } +} - > span { - font-size: 10px; - } +.cvat-annotation-header-button { + padding: 0px; + width: 54px; + height: 54px; + float: left; + text-align: center; + user-select: none; - > i { - transform: scale(0.8); - padding: 3px; - } + > span { + font-size: 10px; + } - &:hover > i { - transform: scale(0.9); - } + > i { + transform: scale(0.8); + padding: 3px; + } - &:active > i { - transform: scale(0.8); - } + &:hover > i { + transform: scale(0.9); + } - > * { - display: block; - line-height: 0px; - } + &:active > i { + transform: scale(0.8); } - > div:first-child { - filter: invert(0.9); - background: $background-color-1; - border-radius: 0px; - width: 70px; + > * { + display: block; + line-height: 0px; } } .cvat-annotation-header-player-group > div { height: 54px; + line-height: 0px; } .cvat-annotation-header-player-buttons { @@ -96,14 +98,16 @@ } .cvat-annotation-header-filename-wrapper { - max-width: 180px; + max-width: 300px; overflow: hidden; text-overflow: ellipsis; + user-select: none; } .cvat-annotation-header-frame-selector { width: 5em; - margin-right: 0.5em; + padding-right: 5px; + margin-left: 5px; } .cvat-annotation-header-right-group { 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 c6ca29e67a61..1e1f25c485a3 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 @@ -34,25 +34,25 @@ export default function AnnotationPageComponent(): JSX.Element { -
+
Menu
-
+
Save
-
+
Undo
-
+
Redo
- + @@ -68,26 +68,25 @@ export default function AnnotationPageComponent(): JSX.Element { - + filename.png - - - of 200 - + + + -
+
Fullscreen
-
+
Info
diff --git a/cvat-ui/src/components/cvat-app.tsx b/cvat-ui/src/components/cvat-app.tsx index bab6dee9a56a..a1e76e490a42 100644 --- a/cvat-ui/src/components/cvat-app.tsx +++ b/cvat-ui/src/components/cvat-app.tsx @@ -1,5 +1,5 @@ import 'antd/dist/antd.less'; -import '../base.scss'; +import '../styles.scss'; import React from 'react'; import { BrowserRouter } from 'react-router-dom'; import { @@ -262,7 +262,7 @@ export default class CVATApplication extends React.PureComponent { - + { withModels && } { installedAutoAnnotation @@ -289,7 +289,7 @@ export default class CVATApplication extends React.PureComponent { } return ( - + ); } } diff --git a/cvat-ui/src/components/model-runner-modal/model-runner-modal.tsx b/cvat-ui/src/components/model-runner-modal/model-runner-modal.tsx index fc9abff77cc9..eda2bcba7480 100644 --- a/cvat-ui/src/components/model-runner-modal/model-runner-modal.tsx +++ b/cvat-ui/src/components/model-runner-modal/model-runner-modal.tsx @@ -407,7 +407,7 @@ export default class ModelRunnerModalComponent extends React.PureComponent {!modelsInitialized - && } + && } {modelsInitialized && this.renderContent()} ) diff --git a/cvat-ui/src/components/models-page/models-page.tsx b/cvat-ui/src/components/models-page/models-page.tsx index fd79626d8596..4e2a8c3bf062 100644 --- a/cvat-ui/src/components/models-page/models-page.tsx +++ b/cvat-ui/src/components/models-page/models-page.tsx @@ -42,7 +42,7 @@ export default function ModelsPageComponent(props: Props): JSX.Element { props.getModels(); } return ( - + ); } diff --git a/cvat-ui/src/components/task-page/task-page.tsx b/cvat-ui/src/components/task-page/task-page.tsx index f01e03366ffb..0804551cc39b 100644 --- a/cvat-ui/src/components/task-page/task-page.tsx +++ b/cvat-ui/src/components/task-page/task-page.tsx @@ -7,7 +7,7 @@ import { Col, Row, Spin, - notification, + Result, } from 'antd'; import TopBarComponent from './top-bar'; @@ -17,11 +17,11 @@ import ModelRunnerModalContainer from '../../containers/model-runner-dialog/mode import { Task } from '../../reducers/interfaces'; interface TaskPageComponentProps { - task: Task | null; + task: Task | null | undefined; fetching: boolean; deleteActivity: boolean | null; installedGit: boolean; - onFetchTask: (tid: number) => void; + getTask: () => void; } type Props = TaskPageComponentProps & RouteComponentProps<{id: string}>; @@ -38,41 +38,33 @@ class TaskPageComponent extends React.PureComponent { if (deleteActivity) { history.replace('/tasks'); } - - if (this.attempts === 2) { - notification.warning({ - message: 'Something wrong with the task. It cannot be fetched from the server', - }); - } } public render(): JSX.Element { const { - match, task, fetching, - onFetchTask, + getTask, } = this.props; - const { id } = match.params; - const fetchTask = !task; - if (fetchTask) { + if (task === null) { if (!fetching) { - if (!this.attempts) { - this.attempts++; - onFetchTask(+id); - } else { - this.attempts++; - } + getTask(); } + return ( - + ); } if (typeof (task) === 'undefined') { return ( -
+ ); } diff --git a/cvat-ui/src/components/tasks-page/tasks-page.tsx b/cvat-ui/src/components/tasks-page/tasks-page.tsx index 3a21a978f151..51232923bc4d 100644 --- a/cvat-ui/src/components/tasks-page/tasks-page.tsx +++ b/cvat-ui/src/components/tasks-page/tasks-page.tsx @@ -207,7 +207,7 @@ class TasksPageComponent extends React.PureComponent + ); } diff --git a/cvat-ui/src/containers/annotation-page/annotation-page.tsx b/cvat-ui/src/containers/annotation-page/annotation-page.tsx index 541a831884b1..44da61a73f41 100644 --- a/cvat-ui/src/containers/annotation-page/annotation-page.tsx +++ b/cvat-ui/src/containers/annotation-page/annotation-page.tsx @@ -1,9 +1,83 @@ import React from 'react'; +import { connect } from 'react-redux'; +import { withRouter } from 'react-router-dom'; +import { RouteComponentProps } from 'react-router'; import AnnotationPageComponent from '../../components/annotation-page/annotation-page'; +import { getTasksAsync } from '../../actions/tasks-actions'; -export default function AnnotationPageContainer() { +import { + CombinedState, + Task, +} from '../../reducers/interfaces'; + +type OwnProps = RouteComponentProps<{ + tid: string; + jid: string; +}>; + +interface StateToProps { + jobInstance: any | null | undefined; + fetching: boolean; +} + +interface DispatchToProps { + getJob(): void; +} + +function mapStateToProps(state: CombinedState, own: OwnProps): StateToProps { + const { tasks } = state; + const { + gettingQuery, + current, + } = tasks; + const { params } = own.match; + const taskID = +params.tid; + const jobID = +params.jid; + + const filteredTasks = current + .filter((_task: Task) => _task.instance.id === taskID); + const task = filteredTasks[0] || (gettingQuery.id === taskID || Number.isNaN(taskID) + ? undefined : null); + + const job = task ? task.instance.jobs + .filter((_job: any) => _job.id === jobID)[0] : task; + + return { + jobInstance: job, + fetching: tasks.fetching, + }; +} + +function mapDispatchToProps(dispatch: any, own: OwnProps): DispatchToProps { + const { params } = own.match; + const taskID = +params.tid; + + return { + getJob(): void { + dispatch(getTasksAsync({ + id: taskID, + page: 1, + search: null, + owner: null, + assignee: null, + name: null, + status: null, + mode: null, + })); + }, + }; +} + +function AnnotationPageContainer(props: StateToProps & DispatchToProps): JSX.Element { return ( - + ); } + +export default withRouter( + connect( + mapStateToProps, + mapDispatchToProps, + )(AnnotationPageContainer), +); diff --git a/cvat-ui/src/containers/task-page/task-page.tsx b/cvat-ui/src/containers/task-page/task-page.tsx index 1133e16620b3..da2f5aae93a6 100644 --- a/cvat-ui/src/containers/task-page/task-page.tsx +++ b/cvat-ui/src/containers/task-page/task-page.tsx @@ -14,23 +14,29 @@ import { type Props = RouteComponentProps<{id: string}>; interface StateToProps { - task: Task | null; + task: Task | null | undefined; fetching: boolean; deleteActivity: boolean | null; installedGit: boolean; } interface DispatchToProps { - onFetchTask: (tid: number) => void; + getTask: () => void; } function mapStateToProps(state: CombinedState, own: Props): StateToProps { const { plugins } = state.plugins; - const { deletes } = state.tasks.activities; + const { tasks } = state; + const { gettingQuery } = tasks; + const { deletes } = tasks.activities; + const id = +own.match.params.id; - const filtered = state.tasks.current.filter((task) => task.instance.id === id); - const task = filtered[0] || null; + const filteredTasks = state.tasks.current + .filter((task) => task.instance.id === id); + + const task = filteredTasks[0] || (gettingQuery.id === id || Number.isNaN(id) + ? undefined : null); let deleteActivity = null; if (task && id in deletes.byTask) { @@ -45,11 +51,13 @@ function mapStateToProps(state: CombinedState, own: Props): StateToProps { }; } -function mapDispatchToProps(dispatch: any): DispatchToProps { +function mapDispatchToProps(dispatch: any, own: Props): DispatchToProps { + const id = +own.match.params.id; + return { - onFetchTask: (tid: number): void => { + getTask: (): void => { dispatch(getTasksAsync({ - id: tid, + id, page: 1, search: null, owner: null, diff --git a/cvat-ui/src/styles.scss b/cvat-ui/src/styles.scss new file mode 100644 index 000000000000..d3b3c0a7711d --- /dev/null +++ b/cvat-ui/src/styles.scss @@ -0,0 +1,34 @@ +@import './base.scss'; + +hr { + border: none; + border-top: 1px solid $border-color-1; + height: 1px; +} + +.cvat-spinner { + margin: 25% 50%; +} + +.cvat-not-found { + margin: 10% 25%; +} + +.cvat-text-color { + color: $text-color; +} + +.cvat-title { + font-weight: 400; + font-size: 21px; + color: $text-color; + padding-top: 5px; +} + +#root { + width: 100%; + height: 100%; + display: grid; + min-width: 1280px; + min-height: 768px; +}