Merge pull request #932 from opencv/bs/show_hidden_tasks

Ability to show hidden tasks by a user request
main
Nikita Manovich 6 years ago committed by GitHub
commit 719ad1a4e1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -30,7 +30,7 @@ export enum TasksActionTypes {
UPDATE_TASK = 'UPDATE_TASK',
UPDATE_TASK_SUCCESS = 'UPDATE_TASK_SUCCESS',
UPDATE_TASK_FAILED = 'UPDATE_TASK_FAILED',
RESET_ERROR = 'RESET_ERROR',
HIDE_EMPTY_TASKS = 'HIDE_EMPTY_TASKS',
}
function getTasks(): AnyAction {
@ -90,8 +90,7 @@ ThunkAction<Promise<void>, {}, {}, AnyAction> {
return;
}
const array = Array.from(result)
.filter((task: any) => task.jobs.length > 0);
const array = Array.from(result);
const previews = [];
const promises = array
.map((task): string => (task as any).frames.preview());
@ -513,3 +512,14 @@ ThunkAction<Promise<void>, {}, {}, AnyAction> {
}
};
}
export function hideEmptyTasks(hideEmpty: boolean): AnyAction {
const action = {
type: TasksActionTypes.HIDE_EMPTY_TASKS,
payload: {
hideEmpty,
},
};
return action;
}

@ -57,7 +57,7 @@ function HeaderContainer(props: Props): JSX.Element {
type='link'
value='tasks'
onClick={
(): void => props.history.push('/tasks')
(): void => props.history.push('/tasks?page=1')
}
>
Tasks

@ -21,6 +21,7 @@ export interface TaskItemProps {
taskInstance: any;
previewImage: string;
deleted: boolean;
hidden: boolean;
activeInference: ActiveInference | null;
}
@ -49,7 +50,8 @@ class TaskItemComponent extends React.PureComponent<TaskItemProps & RouteCompone
return (
<Col span={10}>
<Text strong>{`${id} ${name}`}</Text>
<Text strong type='secondary'>{`#${id}: `}</Text>
<Text strong className='cvat-black-color'>{name}</Text>
<br />
{ owner
&& (
@ -180,13 +182,20 @@ class TaskItemComponent extends React.PureComponent<TaskItemProps & RouteCompone
}
public render(): JSX.Element {
const { deleted } = this.props;
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()}

@ -4,8 +4,12 @@ import { withRouter } from 'react-router-dom';
import {
Spin,
Button,
message,
} from 'antd';
import Text from 'antd/lib/typography/Text';
import {
TasksQuery,
} from '../../reducers/interfaces';
@ -19,7 +23,9 @@ interface TasksPageProps {
gettingQuery: TasksQuery;
numberOfTasks: number;
numberOfVisibleTasks: number;
numberOfHiddenTasks: number;
onGetTasks: (gettingQuery: TasksQuery) => void;
hideEmptyTasks: (hideEmpty: boolean) => void;
}
function getSearchField(gettingQuery: TasksQuery): string {
@ -43,6 +49,31 @@ function getSearchField(gettingQuery: TasksQuery): string {
return searchString.slice(0, -5);
}
function updateQuery(previousQuery: TasksQuery, searchString: string): TasksQuery {
const params = new URLSearchParams(searchString);
const query = { ...previousQuery };
for (const field of Object.keys(query)) {
if (params.has(field)) {
const value = params.get(field);
if (value) {
if (field === 'id' || field === 'page') {
if (Number.isInteger(+value)) {
query[field] = +value;
}
} else {
query[field] = value;
}
}
} else if (field === 'page') {
query[field] = 1;
} else {
query[field] = null;
}
}
return query;
}
class TasksPageComponent extends React.PureComponent<TasksPageProps & RouteComponentProps> {
public componentDidMount(): void {
const {
@ -50,36 +81,52 @@ class TasksPageComponent extends React.PureComponent<TasksPageProps & RouteCompo
location,
onGetTasks,
} = this.props;
const params = new URLSearchParams(location.search);
const query = { ...gettingQuery };
for (const field of Object.keys(query)) {
if (params.has(field)) {
const value = params.get(field);
if (value) {
if (field === 'id' || field === 'page') {
if (Number.isInteger(+value)) {
query[field] = +value;
}
} else {
query[field] = value;
}
}
} else if (field === 'page') {
query[field] = 1;
} else {
query[field] = null;
}
const query = updateQuery(gettingQuery, location.search);
onGetTasks(query);
}
public componentDidUpdate(prevProps: TasksPageProps & RouteComponentProps): void {
const {
location,
gettingQuery,
onGetTasks,
numberOfHiddenTasks,
hideEmptyTasks,
} = this.props;
if (prevProps.location.search !== location.search) {
// get new tasks if any query changes
const query = updateQuery(gettingQuery, location.search);
message.destroy();
onGetTasks(query);
return;
}
this.updateURL(query);
onGetTasks(query);
if (numberOfHiddenTasks) {
message.destroy();
message.info(
<>
<Text>
Some tasks have not been showed because they do not have any data.
</Text>
<Button
type='link'
onClick={(): void => {
hideEmptyTasks(false);
message.destroy();
}}
>
Show all
</Button>
</>, 7,
);
}
}
private handleSearch = (value: string): void => {
const {
gettingQuery,
onGetTasks,
} = this.props;
const query = { ...gettingQuery };
@ -114,19 +161,19 @@ class TasksPageComponent extends React.PureComponent<TasksPageProps & RouteCompo
}
this.updateURL(query);
onGetTasks(query);
};
private handlePagination = (page: number): void => {
const {
gettingQuery,
onGetTasks,
} = this.props;
const query = { ...gettingQuery };
// modify query object
const query = { ...gettingQuery };
query.page = page;
// update url according to new query object
this.updateURL(query);
onGetTasks(query);
};
private updateURL(gettingQuery: TasksQuery): void {
@ -137,9 +184,16 @@ class TasksPageComponent extends React.PureComponent<TasksPageProps & RouteCompo
queryString += `${field}=${gettingQuery[field]}&`;
}
}
history.replace({
search: queryString.slice(0, -1),
});
const oldQueryString = history.location.search;
if (oldQueryString !== queryString) {
history.push({
search: queryString.slice(0, -1),
});
// force update if any changes
this.forceUpdate();
}
}
public render(): JSX.Element {

@ -15,6 +15,7 @@ import {
interface StateToProps {
deleted: boolean;
hidden: boolean;
previewImage: string;
taskInstance: any;
activeInference: ActiveInference | null;
@ -35,6 +36,7 @@ function mapStateToProps(state: CombinedState, own: OwnProps): StateToProps {
const id = own.taskID;
return {
hidden: state.tasks.hideEmpty && task.instance.jobs.length === 0,
deleted: deletes.byTask[id] ? deletes.byTask[id] === true : false,
previewImage: task.preview,
taskInstance: task.instance,

@ -2,23 +2,29 @@ import React from 'react';
import { connect } from 'react-redux';
import {
Task,
TasksQuery,
CombinedState,
} from '../../reducers/interfaces';
import TasksPageComponent from '../../components/tasks-page/tasks-page';
import { getTasksAsync } from '../../actions/tasks-actions';
import {
getTasksAsync,
hideEmptyTasks,
} from '../../actions/tasks-actions';
interface StateToProps {
tasksFetching: boolean;
gettingQuery: TasksQuery;
numberOfTasks: number;
numberOfVisibleTasks: number;
numberOfHiddenTasks: number;
}
interface DispatchToProps {
onGetTasks: (gettingQuery: TasksQuery) => void;
hideEmptyTasks: (hideEmpty: boolean) => void;
}
function mapStateToProps(state: CombinedState): StateToProps {
@ -29,6 +35,8 @@ function mapStateToProps(state: CombinedState): StateToProps {
gettingQuery: tasks.gettingQuery,
numberOfTasks: state.tasks.count,
numberOfVisibleTasks: state.tasks.current.length,
numberOfHiddenTasks: tasks.hideEmpty ? tasks.current
.filter((task: Task): boolean => !task.instance.jobs.length).length : 0,
};
}
@ -37,6 +45,9 @@ function mapDispatchToProps(dispatch: any): DispatchToProps {
onGetTasks: (query: TasksQuery): void => {
dispatch(getTasksAsync(query));
},
hideEmptyTasks: (hideEmpty: boolean): void => {
dispatch(hideEmptyTasks(hideEmpty));
},
};
}

@ -24,6 +24,7 @@ export interface Task {
export interface TasksState {
initialized: boolean;
fetching: boolean;
hideEmpty: boolean;
gettingQuery: TasksQuery;
count: number;
current: Task[];

@ -7,6 +7,7 @@ import { TasksState, Task } from './interfaces';
const defaultState: TasksState = {
initialized: false,
fetching: false,
hideEmpty: false,
count: 0,
current: [],
gettingQuery: {
@ -51,6 +52,10 @@ export default (state: TasksState = defaultState, action: AnyAction): TasksState
},
initialized: false,
fetching: true,
hideEmpty: true,
count: 0,
current: [],
gettingQuery: { ...action.payload.query },
};
case TasksActionTypes.GET_TASKS_SUCCESS: {
const combinedWithPreviews = action.payload.array
@ -73,9 +78,6 @@ export default (state: TasksState = defaultState, action: AnyAction): TasksState
...state,
initialized: true,
fetching: false,
count: 0,
current: [],
gettingQuery: { ...action.payload.query },
};
case TasksActionTypes.DUMP_ANNOTATIONS: {
const { task } = action.payload;
@ -405,6 +407,12 @@ export default (state: TasksState = defaultState, action: AnyAction): TasksState
}),
};
}
case TasksActionTypes.HIDE_EMPTY_TASKS: {
return {
...state,
hideEmpty: action.payload.hideEmpty,
};
}
case AuthActionTypes.LOGOUT_SUCCESS: {
return {
...defaultState,

@ -48,7 +48,7 @@
}
.cvat-black-color {
color: black;
color: #363435;
}
.cvat-feedback-button {

Loading…
Cancel
Save