Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added filters and sorting options for job list, added tooltip for tasks filters #3030

Merged
merged 5 commits into from
Mar 31, 2021
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Annotations filters UI using react-awesome-query-builder (https://github.com/openvinotoolkit/cvat/issues/1418)
- Storing settings in local storage to keep them between browser sessions (<https://github.com/openvinotoolkit/cvat/pull/3017>)
- [ICDAR](https://rrc.cvc.uab.es/?ch=2) format support (<https://github.com/openvinotoolkit/cvat/pull/2866>)
- Added switcher to maintain poylgon crop behaviour (<https://github.com/openvinotoolkit/cvat/pull/3021>)
- Added switcher to maintain poylgon crop behaviour (<https://github.com/openvinotoolkit/cvat/pull/3021>
- Filters and sorting options for job list, added tooltip for tasks filters (<https://github.com/openvinotoolkit/cvat/pull/3030>)

### Changed

Expand Down
2 changes: 1 addition & 1 deletion cvat-ui/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion cvat-ui/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "cvat-ui",
"version": "1.17.0",
"version": "1.18.0",
"description": "CVAT single-page application",
"main": "src/index.tsx",
"scripts": {
Expand Down
59 changes: 58 additions & 1 deletion cvat-ui/src/components/task-page/job-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { RouteComponentProps } from 'react-router';
import { withRouter } from 'react-router-dom';
import { Row, Col } from 'antd/lib/grid';
import { LoadingOutlined, QuestionCircleOutlined, CopyOutlined } from '@ant-design/icons';
import { ColumnFilterItem } from 'antd/lib/table/interface';
import Table from 'antd/lib/table';
import Button from 'antd/lib/button';
import Text from 'antd/lib/typography/Text';
Expand Down Expand Up @@ -101,6 +102,46 @@ function JobListComponent(props: Props & RouteComponentProps): JSX.Element {
} = props;

const { jobs, id: taskId } = taskInstance;

function sorter(path: string) {
return (obj1: any, obj2: any): number => {
let currentObj1 = obj1;
let currentObj2 = obj2;
let field1: string | null = null;
let field2: string | null = null;
for (const pathSegment of path.split('.')) {
field1 = currentObj1 && pathSegment in currentObj1 ? currentObj1[pathSegment] : null;
field2 = currentObj2 && pathSegment in currentObj2 ? currentObj2[pathSegment] : null;
currentObj1 = currentObj1 && pathSegment in currentObj1 ? currentObj1[pathSegment] : null;
currentObj2 = currentObj2 && pathSegment in currentObj2 ? currentObj2[pathSegment] : null;
}

if (field1 && field2) {
return field1.localeCompare(field2);
}

if (field1 === null) {
return 1;
}

return -1;
};
}

function collectUsers(path: string): ColumnFilterItem[] {
return Array.from<string | null>(
new Set(
jobs.map((job: any) => {
if (job[path] === null) {
return null;
}

return job[path].username;
}),
),
).map((value: string | null) => ({ text: value || 'Is Empty', value: value || false }));
}

const columns = [
{
title: 'Job',
Expand Down Expand Up @@ -152,6 +193,13 @@ function JobListComponent(props: Props & RouteComponentProps): JSX.Element {
</Text>
);
},
sorter: sorter('status.status'),
filters: [
{ text: 'annotation', value: 'annotation' },
{ text: 'validation', value: 'validation' },
{ text: 'completed', value: 'completed' },
],
onFilter: (value: string | number | boolean, record: any) => record.status.status === value,
},
{
title: 'Started on',
Expand Down Expand Up @@ -180,6 +228,10 @@ function JobListComponent(props: Props & RouteComponentProps): JSX.Element {
}}
/>
),
sorter: sorter('assignee.assignee.username'),
filters: collectUsers('assignee'),
onFilter: (value: string | number | boolean, record: any) =>
(record.assignee.assignee?.username || false) === value,
},
{
title: 'Reviewer',
Expand All @@ -196,6 +248,10 @@ function JobListComponent(props: Props & RouteComponentProps): JSX.Element {
}}
/>
),
sorter: sorter('reviewer.reviewer.username'),
filters: collectUsers('reviewer'),
onFilter: (value: string | number | boolean, record: any) =>
(record.reviewer.reviewer?.username || false) === value,
},
];

Expand All @@ -207,13 +263,14 @@ function JobListComponent(props: Props & RouteComponentProps): JSX.Element {

const created = moment(props.taskInstance.createdDate);

const now = moment(moment.now());
acc.push({
key: job.id,
job: job.id,
frames: `${job.startFrame}-${job.stopFrame}`,
status: job,
started: `${created.format('MMMM Do YYYY HH:MM')}`,
duration: `${moment.duration(moment(moment.now()).diff(created)).humanize()}`,
duration: `${moment.duration(now.diff(created)).humanize()}`,
assignee: job,
reviewer: job,
});
Expand Down
10 changes: 10 additions & 0 deletions cvat-ui/src/components/tasks-page/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,16 @@
@extend .cvat-text-color;
}

.cvat-tasks-search-tooltip {
span {
color: white;
}

strong::after {
content: ' - ';
}
}

#cvat-create-task-button {
padding: 0 30px;
}
77 changes: 69 additions & 8 deletions cvat-ui/src/components/tasks-page/top-bar.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (C) 2020 Intel Corporation
// Copyright (C) 2020-2021 Intel Corporation
//
// SPDX-License-Identifier: MIT

Expand All @@ -9,6 +9,9 @@ import { PlusOutlined } from '@ant-design/icons';
import Button from 'antd/lib/button';
import Input from 'antd/lib/input';
import Text from 'antd/lib/typography/Text';
import Paragraph from 'antd/lib/typography/Paragraph';

import CVATTooltip from 'components/common/cvat-tooltip';

interface VisibleTopBarProps {
onSearch: (value: string) => void;
Expand All @@ -25,13 +28,71 @@ export default function TopBarComponent(props: VisibleTopBarProps): JSX.Element
<Row justify='center' align='middle'>
<Col md={11} lg={9} xl={8} xxl={7}>
<Text className='cvat-title'>Tasks</Text>
<Input.Search
className='cvat-task-page-search-task'
defaultValue={searchValue}
onSearch={onSearch}
size='large'
placeholder='Search'
/>
<CVATTooltip
bsekachev marked this conversation as resolved.
Show resolved Hide resolved
overlayClassName='cvat-tasks-search-tooltip'
title={(
<>
<Paragraph>
<Text strong>owner: admin</Text>
<Text>
all tasks created by the user who has the substring
<q>admin</q>
in their username
</Text>
</Paragraph>
<Paragraph>
<Text strong>assignee: employee</Text>
<Text>
all tasks which are assigned to a user who has the substring
<q>admin</q>
in their username
</Text>
</Paragraph>
<Paragraph>
<Text strong>name: training</Text>
<Text>
all tasks with the substring
<q>training</q>
in its name
</Text>
</Paragraph>
<Paragraph>
<Text strong>mode: annotation</Text>
<Text>
annotation tasks are tasks with images, interpolation tasks are tasks with
videos
</Text>
</Paragraph>
<Paragraph>
<Text strong>status: annotation</Text>
<Text>annotation, validation, or completed</Text>
</Paragraph>
<Paragraph>
<Text strong>id: 5</Text>
<Text>the task with id 5</Text>
</Paragraph>
<Paragraph>
<Text>
Filters can be combined (to the exclusion of id) using the keyword AND. Example:
<Text type='warning'>
<q>mode: interpolation AND owner: admin</q>
</Text>
</Text>
</Paragraph>
<Paragraph>
<Text type='success'>Search within all the string fields by default</Text>
</Paragraph>
</>
)}
>
<Input.Search
className='cvat-task-page-search-task'
defaultValue={searchValue}
onSearch={onSearch}
size='large'
placeholder='Search'
/>
</CVATTooltip>
</Col>
<Col md={{ span: 11 }} lg={{ span: 9 }} xl={{ span: 8 }} xxl={{ span: 7 }}>
<Button
Expand Down