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.
177 lines
7.2 KiB
�������
177 lines
7.2 KiB
�������
// Copyright (C) 2019-2021 Intel Corporation
|
|
//
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
import './styles.scss';
|
|
import React, { useEffect, useCallback } from 'react';
|
|
import { useSelector, useDispatch } from 'react-redux';
|
|
import { useHistory, useParams, useLocation } from 'react-router';
|
|
import Spin from 'antd/lib/spin';
|
|
import { Row, Col } from 'antd/lib/grid';
|
|
import Result from 'antd/lib/result';
|
|
import Button from 'antd/lib/button';
|
|
import Title from 'antd/lib/typography/Title';
|
|
import Pagination from 'antd/lib/pagination';
|
|
import { PlusOutlined } from '@ant-design/icons';
|
|
|
|
import { CombinedState, Task, TasksQuery } from 'reducers/interfaces';
|
|
import { getProjectsAsync, getProjectTasksAsync } from 'actions/projects-actions';
|
|
import { cancelInferenceAsync } from 'actions/models-actions';
|
|
import TaskItem from 'components/tasks-page/task-item';
|
|
import SearchField from 'components/search-field/search-field';
|
|
import MoveTaskModal from 'components/move-task-modal/move-task-modal';
|
|
import ModelRunnerDialog from 'components/model-runner-modal/model-runner-dialog';
|
|
import { useDidUpdateEffect } from 'utils/hooks';
|
|
import DetailsComponent from './details';
|
|
import ProjectTopBar from './top-bar';
|
|
|
|
interface ParamType {
|
|
id: string;
|
|
}
|
|
|
|
export default function ProjectPageComponent(): JSX.Element {
|
|
const id = +useParams<ParamType>().id;
|
|
const dispatch = useDispatch();
|
|
const history = useHistory();
|
|
const { search } = useLocation();
|
|
const projects = useSelector((state: CombinedState) => state.projects.current).map((project) => project.instance);
|
|
const projectsFetching = useSelector((state: CombinedState) => state.projects.fetching);
|
|
const deletes = useSelector((state: CombinedState) => state.projects.activities.deletes);
|
|
const taskDeletes = useSelector((state: CombinedState) => state.tasks.activities.deletes);
|
|
const tasksActiveInferences = useSelector((state: CombinedState) => state.models.inferences);
|
|
const tasks = useSelector((state: CombinedState) => state.tasks.current);
|
|
const tasksCount = useSelector((state: CombinedState) => state.tasks.count);
|
|
const tasksGettingQuery = useSelector((state: CombinedState) => state.projects.tasksGettingQuery);
|
|
|
|
const [project] = projects.filter((_project) => _project.id === id);
|
|
const projectSubsets: Array<string> = [];
|
|
for (const task of tasks) {
|
|
if (!projectSubsets.includes(task.instance.subset)) projectSubsets.push(task.instance.subset);
|
|
}
|
|
|
|
const deleteActivity = project && id in deletes ? deletes[id] : null;
|
|
|
|
const onPageChange = useCallback(
|
|
(p: number) => {
|
|
dispatch(getProjectTasksAsync({
|
|
projectId: id,
|
|
page: p,
|
|
}));
|
|
},
|
|
[],
|
|
);
|
|
|
|
useEffect(() => {
|
|
const searchParams: Partial<TasksQuery> = {};
|
|
for (const [param, value] of new URLSearchParams(search)) {
|
|
searchParams[param] = ['page'].includes(param) ? Number.parseInt(value, 10) : value;
|
|
}
|
|
dispatch(getProjectsAsync({ id }, searchParams));
|
|
}, []);
|
|
|
|
useDidUpdateEffect(() => {
|
|
const searchParams = new URLSearchParams();
|
|
for (const [name, value] of Object.entries(tasksGettingQuery)) {
|
|
if (value !== null && typeof value !== 'undefined' && !['projectId', 'ordering'].includes(name)) {
|
|
searchParams.append(name, value.toString());
|
|
}
|
|
}
|
|
history.push({
|
|
pathname: `/projects/${id}`,
|
|
search: `?${searchParams.toString()}`,
|
|
});
|
|
}, [tasksGettingQuery, id]);
|
|
|
|
if (deleteActivity) {
|
|
history.push('/projects');
|
|
}
|
|
|
|
if (projectsFetching) {
|
|
return <Spin size='large' className='cvat-spinner' />;
|
|
}
|
|
|
|
if (!project) {
|
|
return (
|
|
<Result
|
|
className='cvat-not-found'
|
|
status='404'
|
|
title='Sorry, but this project was not found'
|
|
subTitle='Please, be sure information you tried to get exist and you have access'
|
|
/>
|
|
);
|
|
}
|
|
|
|
const paginationDimensions = {
|
|
md: 22,
|
|
lg: 18,
|
|
xl: 16,
|
|
xxl: 16,
|
|
};
|
|
|
|
return (
|
|
<Row justify='center' align='top' className='cvat-project-page'>
|
|
<Col md={22} lg={18} xl={16} xxl={14}>
|
|
<ProjectTopBar projectInstance={project} />
|
|
<DetailsComponent project={project} />
|
|
<Row justify='space-between' align='middle' className='cvat-project-page-tasks-bar'>
|
|
<Col className='cvat-project-tasks-title-search'>
|
|
<Title level={3}>Tasks</Title>
|
|
<SearchField
|
|
query={tasksGettingQuery}
|
|
instance='task'
|
|
skipFields={['ordering', 'projectId']}
|
|
onSearch={(query: TasksQuery) => dispatch(getProjectTasksAsync(query))}
|
|
/>
|
|
</Col>
|
|
<Col>
|
|
<Button
|
|
size='large'
|
|
type='primary'
|
|
icon={<PlusOutlined />}
|
|
id='cvat-create-task-button'
|
|
onClick={() => history.push(`/tasks/create?projectId=${id}`)}
|
|
>
|
|
Create new task
|
|
</Button>
|
|
</Col>
|
|
</Row>
|
|
{projectSubsets.map((subset: string) => (
|
|
<React.Fragment key={subset}>
|
|
{subset && <Title level={4}>{subset}</Title>}
|
|
{tasks
|
|
.filter((task) => task.instance.projectId === project.id && task.instance.subset === subset)
|
|
.map((task: Task) => (
|
|
<TaskItem
|
|
key={task.instance.id}
|
|
deleted={task.instance.id in taskDeletes ? taskDeletes[task.instance.id] : false}
|
|
hidden={false}
|
|
activeInference={tasksActiveInferences[task.instance.id] || null}
|
|
cancelAutoAnnotation={() => {
|
|
dispatch(cancelInferenceAsync(task.instance.id));
|
|
}}
|
|
previewImage={task.preview}
|
|
taskInstance={task.instance}
|
|
/>
|
|
))}
|
|
</React.Fragment>
|
|
))}
|
|
<Row justify='center'>
|
|
<Col {...paginationDimensions}>
|
|
<Pagination
|
|
className='cvat-project-tasks-pagination'
|
|
onChange={onPageChange}
|
|
showSizeChanger={false}
|
|
total={tasksCount}
|
|
pageSize={10}
|
|
current={tasksGettingQuery.page}
|
|
showQuickJumper
|
|
/>
|
|
</Col>
|
|
</Row>
|
|
</Col>
|
|
<MoveTaskModal />
|
|
<ModelRunnerDialog />
|
|
</Row>
|
|
);
|
|
}
|