Dashboard components basic styles (#574)

* Case sensitive renaming

* Update `cvat-js` lib.

* Add `.env` file

* Add basic redux capabilities

* Remove `setTimeout` as it was fixes in `cvat-js`

* Remove redundant state field

* Add header and footer styles

* Remove `Affix`

It does not recalculete width for some reason

* Add basic styles to task cards

* Fix empty component

* Pagination fixes

* Add modal on task delete
main
Artyom Zankevich 7 years ago committed by Nikita Manovich
parent a159826bf7
commit 3ba80d2e77

@ -1,8 +1,10 @@
REACT_APP_VERSION=${npm_package_version}
REACT_APP_API_PROTOCOL=http
REACT_APP_API_HOST=localhost
REACT_APP_API_PORT=7000
REACT_APP_API_HOST_URL=${REACT_APP_API_PROTOCOL}://${REACT_APP_API_HOST}:${REACT_APP_API_PORT}
REACT_APP_API_FULL_URL=${REACT_APP_API_PROTOCOL}://${REACT_APP_API_HOST}:${REACT_APP_API_PORT}/api/v1
REACT_APP_LOGIN=admin
REACT_APP_PASSWORD=admin

@ -1,23 +1,52 @@
.dashboard-content-сard {
&__header {
}
.dashboard-content {
width: 1024px;
min-height: calc(100vh - 64px - 64px);
margin: 0 auto;
.dashboard-content-сard {
margin: 20px;
padding: 20px;
border: 1px solid #001529;
border-radius: 3px;
background: white;
&__header {
text-align: center;
h2 {
margin-bottom: 20px;
}
}
&__content {
&__content {
.card-cover {
.card-cover {
img {
max-width: 300px;
img {
max-width: 300px;
}
}
}
.card-actions {
.card-actions {
display: flex;
flex-flow: column wrap;
}
button {
min-width: 200px;
margin-bottom: 1px;
}
}
.card-jobs {
.card-jobs {
}
}
}
}
.empty {
display: flex;
flex-direction: column;
justify-content: center;
height: calc(100vh - 64px - 64px);
}

@ -1,10 +1,12 @@
import React, { Component } from 'react';
import { Layout, Empty, Button, Col, Row } from 'antd';
import { Layout, Empty, Button, Modal, Col, Row } from 'antd';
import Title from 'antd/lib/typography/Title';
import './dashboard-content.scss';
const { Content } = Layout;
const { confirm } = Modal;
interface DashboardContentAction {
id: number,
@ -25,26 +27,32 @@ class DashboardContent extends Component<any, any> {
this.apiUrl = process.env.REACT_APP_API_FULL_URL;
this.actions = [
// {
// id: 1,
// name: 'Dump annotation',
// trigger: () => {},
// },
// {
// id: 2,
// name: 'Upload annotation',
// trigger: () => {},
// },
// {
// id: 3,
// name: 'Update task',
// trigger: () => {},
// },
{
id: 1,
name: 'Dump annotation',
trigger: () => {
this.onDumpAnnotation();
},
},
{
id: 2,
name: 'Upload annotation',
trigger: () => {
this.onUploadAnnotation();
},
},
{
id: 3,
name: 'Update task',
trigger: (task: any) => {
this.onUpdateTask(task);
},
},
{
id: 4,
name: 'Delete task',
trigger: (task: any) => {
this.props.deleteTask(task);
this.onDeleteTask(task);
},
},
];
@ -58,30 +66,63 @@ class DashboardContent extends Component<any, any> {
);
}
private onDumpAnnotation() {
console.log('Dump');
}
private onUploadAnnotation() {
console.log('Upload');
}
private onUpdateTask(task: any) {
console.log('Update');
}
private onDeleteTask(task: any) {
const props = this.props;
confirm({
title: 'Do you want to delete this task?',
okText: 'Yes',
okType: 'danger',
centered: true,
onOk() {
return props.deleteTask(task);
},
cancelText: 'No',
onCancel() {
return;
},
});
}
private renderPlaceholder() {
return (
<Empty
className="empty"
description={
<span>
No tasks in this workspace yet...
No tasks found...
</span>
}
>
<Button type="primary">Create a new task</Button>
<Button type="primary">
Create a new task
</Button>
</Empty>
)
}
private renderTasks() {
return(
<Content>
<Content className="dashboard-content">
{
this.props.tasks.map(
(task: any) => (
<div className="dashboard-content-сard" key={ task.id }>
<Row className="dashboard-content-сard__header" type="flex">
<Col span={24}>
<h2>{ `${task.name}: ${task.mode}` }</h2>
<Title level={2}>{ `${task.name}: ${task.mode}` }</Title>
</Col>
</Row>
@ -90,7 +131,7 @@ class DashboardContent extends Component<any, any> {
<img alt="Task cover" src={ `${this.apiUrl}/tasks/${task.id}/frames/0` } />
</Col>
<Col className="сard-actions" span={8}>
<Col className="card-actions" span={8}>
{
this.actions.map(
(action: DashboardContentAction) => (
@ -105,7 +146,7 @@ class DashboardContent extends Component<any, any> {
</Col>
<Col className="сard-jobs" span={8}>
Jobs
<Title level={3}>Jobs</Title>
{
task.jobs.map(
(job: any) => (

@ -25,10 +25,20 @@ class Dashboard extends Component<any, DashboardState> {
render() {
return (
<Layout>
<DashboardHeader onSearch={ this.getTasks } />
<DashboardContent tasks={ this.state.tasks } deleteTask={ this.deleteTask } />
<DashboardFooter tasksCount={ (this.state.tasks as any)['count'] } onPageChange={ this.onPageChange } />
<Layout className="layout">
<DashboardHeader
onSearch={ this.getTasks }>
</DashboardHeader>
<DashboardContent
tasks={ this.state.tasks }
deleteTask={ this.deleteTask }>
</DashboardContent>
<DashboardFooter
tasksCount={ (this.state.tasks as any)['count'] }
onPageChange={ this.onPageChange }>
</DashboardFooter>
</Layout>
);
}

@ -0,0 +1,9 @@
.dashboard-footer {
display: flex;
align-items: center;
justify-content: center;
min-width: 1024px;
padding: 0 50px;
height: 64px;
background: #001529;
}

@ -1,22 +1,29 @@
import React, { Component } from 'react';
import React, { PureComponent } from 'react';
import { Layout, Pagination } from 'antd';
import { Layout, Pagination, Row, Col } from 'antd';
import './dashboard-footer.scss';
const { Footer } = Layout;
class DashboardFooter extends Component<any, any> {
constructor(props: any) {
super(props);
this.state = {};
}
class DashboardFooter extends PureComponent<any, any> {
render() {
const pagination = (
<Col span={24}>
<Pagination
className="dashboard-footer__pagination"
hideOnSinglePage
onChange={ this.props.onPageChange }
total={ this.props.tasksCount }>
</Pagination>
</Col>
);
return(
<Footer>
<Pagination onChange={ this.props.onPageChange } total={ this.props.tasksCount } />
<Footer className="dashboard-footer">
<Row type="flex" gutter={16}>
{ this.props.tasksCount ? pagination : '' }
</Row>
</Footer>
);
}

@ -0,0 +1,34 @@
.dashboard-header {
min-width: 1024px;
background: #001529;
&__logo {
height: 64px;
.logo {
color: white;
}
}
&__search {
text-align: center;
.search {
max-width: 300px;
}
}
&__actions {
text-align: right;
.action:not(:nth-child(1)) {
margin-left: 8px;
}
.action {
width: 100px;
}
}
.logo, .search, .action {
vertical-align: middle;
}
}

@ -1,6 +1,7 @@
import React, { Component } from 'react';
import { Layout, Row, Col, Button, Input } from 'antd';
import Title from 'antd/lib/typography/Title';
import './dashboard-header.scss';
@ -10,7 +11,7 @@ const { Search } = Input;
interface DashboardHeaderAction {
id: number,
name: string,
trigger: any,
trigger: Function,
}
class DashboardHeader extends Component<any, any> {
@ -25,11 +26,11 @@ class DashboardHeader extends Component<any, any> {
this.hostUrl = process.env.REACT_APP_API_HOST_URL;
this.actions = [
// {
// id: 1,
// name: 'Create task',
// trigger: this.props.onSearch,
// },
{
id: 1,
name: 'Create task',
trigger: () => {},
},
{
id: 2,
name: 'User guide',
@ -40,19 +41,28 @@ class DashboardHeader extends Component<any, any> {
render() {
return(
<Header>
<Row type="flex">
<Col span={8}>
Tasks
<Header className="dashboard-header">
<Row type="flex" gutter={16}>
<Col className="dashboard-header__logo" span={8}>
<Title className="logo">Tasks</Title>
</Col>
<Col span={8}>
<Search placeholder="Search for tasks" onSearch={ query => this.props.onSearch(query) } enterButton />
<Col className="dashboard-header__search" span={8}>
<Search
className="search"
placeholder="Search for tasks"
onSearch={ query => this.props.onSearch(query) }
enterButton>
</Search>
</Col>
<Col span={8}>
<Col className="dashboard-header__actions" span={8}>
{
this.actions.map(
(action: DashboardHeaderAction) => (
<Button type="primary" key={ action.id } onClick={ () => action.trigger() }>
<Button
className="action"
type="primary"
key={ action.id }
onClick={ () => action.trigger() }>
{ action.name }
</Button>
)

Loading…
Cancel
Save