diff --git a/cvat-ui/src/actions/tasks-actions.ts b/cvat-ui/src/actions/tasks-actions.ts index 1dfccf7f..015c12ff 100644 --- a/cvat-ui/src/actions/tasks-actions.ts +++ b/cvat-ui/src/actions/tasks-actions.ts @@ -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, {}, {}, 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, {}, {}, AnyAction> { } }; } + +export function hideEmptyTasks(hideEmpty: boolean): AnyAction { + const action = { + type: TasksActionTypes.HIDE_EMPTY_TASKS, + payload: { + hideEmpty, + }, + }; + + return action; +} diff --git a/cvat-ui/src/components/tasks-page/task-item.tsx b/cvat-ui/src/components/tasks-page/task-item.tsx index 915df3c3..dcf2a5c5 100644 --- a/cvat-ui/src/components/tasks-page/task-item.tsx +++ b/cvat-ui/src/components/tasks-page/task-item.tsx @@ -21,6 +21,7 @@ export interface TaskItemProps { taskInstance: any; previewImage: string; deleted: boolean; + hidden: boolean; activeInference: ActiveInference | null; } @@ -181,13 +182,20 @@ class TaskItemComponent extends React.PureComponent {this.renderPreview()} diff --git a/cvat-ui/src/components/tasks-page/tasks-page.tsx b/cvat-ui/src/components/tasks-page/tasks-page.tsx index e0633f28..f97bae65 100644 --- a/cvat-ui/src/components/tasks-page/tasks-page.tsx +++ b/cvat-ui/src/components/tasks-page/tasks-page.tsx @@ -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 { @@ -85,12 +91,35 @@ class TasksPageComponent extends React.PureComponent + + Some tasks have not been showed because they do not have any data. + + + , 7, + ); } } diff --git a/cvat-ui/src/containers/tasks-page/task-item.tsx b/cvat-ui/src/containers/tasks-page/task-item.tsx index 38e5c193..9aa96727 100644 --- a/cvat-ui/src/containers/tasks-page/task-item.tsx +++ b/cvat-ui/src/containers/tasks-page/task-item.tsx @@ -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, diff --git a/cvat-ui/src/containers/tasks-page/tasks-page.tsx b/cvat-ui/src/containers/tasks-page/tasks-page.tsx index 006e2c7d..5e1c21f5 100644 --- a/cvat-ui/src/containers/tasks-page/tasks-page.tsx +++ b/cvat-ui/src/containers/tasks-page/tasks-page.tsx @@ -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) => !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)); + }, }; } diff --git a/cvat-ui/src/reducers/interfaces.ts b/cvat-ui/src/reducers/interfaces.ts index 6a185646..138c0bce 100644 --- a/cvat-ui/src/reducers/interfaces.ts +++ b/cvat-ui/src/reducers/interfaces.ts @@ -24,6 +24,7 @@ export interface Task { export interface TasksState { initialized: boolean; fetching: boolean; + hideEmpty: boolean; gettingQuery: TasksQuery; count: number; current: Task[]; diff --git a/cvat-ui/src/reducers/tasks-reducer.ts b/cvat-ui/src/reducers/tasks-reducer.ts index cb6c975f..eed41a78 100644 --- a/cvat-ui/src/reducers/tasks-reducer.ts +++ b/cvat-ui/src/reducers/tasks-reducer.ts @@ -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,