You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

211 lines
7.2 KiB
TypeScript

import React from 'react';
import { RouteComponentProps } from 'react-router';
import { withRouter } from 'react-router-dom';
import Text from 'antd/lib/typography/Text';
import {
Col,
Row,
Button,
Icon,
Progress,
Dropdown,
} from 'antd';
import moment from 'moment';
import ActionsMenuContainer from 'containers/actions-menu/actions-menu';
import { ActiveInference } from 'reducers/interfaces';
import { MenuIcon } from 'icons';
export interface TaskItemProps {
taskInstance: any;
previewImage: string;
deleted: boolean;
hidden: boolean;
activeInference: ActiveInference | null;
}
class TaskItemComponent extends React.PureComponent<TaskItemProps & RouteComponentProps> {
private renderPreview(): JSX.Element {
const { previewImage } = this.props;
return (
<Col span={4}>
<div className='cvat-task-item-preview-wrapper'>
<img alt='Preview' className='cvat-task-item-preview' src={previewImage} />
</div>
</Col>
);
}
private renderDescription(): JSX.Element {
// Task info
const { taskInstance } = this.props;
const { id } = taskInstance;
const owner = taskInstance.owner ? taskInstance.owner.username : null;
const updated = moment(taskInstance.updatedDate).fromNow();
const created = moment(taskInstance.createdDate).format('MMMM Do YYYY');
// Get and truncate a task name
const name = `${taskInstance.name.substring(0, 70)}${taskInstance.name.length > 70 ? '...' : ''}`;
return (
<Col span={10}>
<Text strong type='secondary'>{`#${id}: `}</Text>
<Text strong className='cvat-text-color'>{name}</Text>
<br />
{ owner
&& (
<>
<Text type='secondary'>
{`Created ${owner ? `by ${owner}` : ''} on ${created}`}
</Text>
<br />
</>
)
}
<Text type='secondary'>{`Last updated ${updated}`}</Text>
</Col>
);
}
private renderProgress(): JSX.Element {
const {
taskInstance,
activeInference,
} = this.props;
// Count number of jobs and performed jobs
const numOfJobs = taskInstance.jobs.length;
const numOfCompleted = taskInstance.jobs.filter(
(job: any): boolean => job.status === 'completed',
).length;
// Progress appearence depends on number of jobs
let progressColor = null;
let progressText = null;
if (numOfCompleted === numOfJobs) {
progressColor = 'cvat-task-completed-progress';
progressText = <Text strong className={progressColor}>Completed</Text>;
} else if (numOfCompleted) {
progressColor = 'cvat-task-progress-progress';
progressText = <Text strong className={progressColor}>In Progress</Text>;
} else {
progressColor = 'cvat-task-pending-progress';
progressText = <Text strong className={progressColor}>Pending</Text>;
}
return (
<Col span={6}>
<Row type='flex' justify='space-between' align='top'>
<Col>
<svg height='8' width='8' className={progressColor}>
<circle cx='4' cy='4' r='4' strokeWidth='0' />
</svg>
{ progressText }
</Col>
<Col>
<Text type='secondary'>{`${numOfCompleted} of ${numOfJobs} jobs`}</Text>
</Col>
</Row>
<Row>
<Col>
<Progress
className={`${progressColor} cvat-task-progress`}
percent={numOfCompleted * 100 / numOfJobs}
strokeColor='#1890FF'
showInfo={false}
strokeWidth={5}
size='small'
/>
</Col>
</Row>
{ activeInference
&& (
<>
<Row>
<Col>
<Text strong>Automatic annotation</Text>
</Col>
</Row>
<Row>
<Col>
<Progress
percent={Math.floor(activeInference.progress)}
strokeColor={{
from: '#108ee9',
to: '#87d068',
}}
showInfo={false}
strokeWidth={5}
size='small'
/>
</Col>
</Row>
</>
)
}
</Col>
);
}
private renderNavigation(): JSX.Element {
const {
taskInstance,
history,
} = this.props;
const { id } = taskInstance;
return (
<Col span={4}>
<Row type='flex' justify='end'>
<Col>
<Button
type='primary'
size='large'
ghost
onClick={(): void => history.push(`/tasks/${id}`)}
>
Open
</Button>
</Col>
</Row>
<Row type='flex' justify='end'>
<Col>
<Text className='cvat-text-color'>Actions</Text>
<Dropdown overlay={<ActionsMenuContainer taskInstance={taskInstance} />}>
<Icon className='cvat-menu-icon' component={MenuIcon} />
</Dropdown>
</Col>
</Row>
</Col>
);
}
public render(): JSX.Element {
const {
deleted,
hidden,
} = this.props;
const style = {};
if (deleted) {
(style as any).pointerEvents = 'none';
(style as any).opacity = 0.5;
}
if (hidden) {
(style as any).display = 'none';
}
return (
<Row className='cvat-tasks-list-item' type='flex' justify='center' align='top' style={{ ...style }}>
{this.renderPreview()}
{this.renderDescription()}
{this.renderProgress()}
{this.renderNavigation()}
</Row>
);
}
}
export default withRouter(TaskItemComponent);