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/header/header.tsx b/cvat-ui/src/components/header/header.tsx index 707d7de6..69b76e22 100644 --- a/cvat-ui/src/components/header/header.tsx +++ b/cvat-ui/src/components/header/header.tsx @@ -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 diff --git a/cvat-ui/src/components/tasks-page/task-item.tsx b/cvat-ui/src/components/tasks-page/task-item.tsx index c7322cf5..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; } @@ -49,7 +50,8 @@ class TaskItemComponent extends React.PureComponent - {`${id} ${name}`} + {`#${id}: `} + {name}
{ owner && ( @@ -180,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 a0ebf786..2f640c43 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 { @@ -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 { public componentDidMount(): void { const { @@ -50,36 +81,52 @@ class TasksPageComponent extends React.PureComponent + + Some tasks have not been showed because they do not have any data. + + + , 7, + ); + } } private handleSearch = (value: string): void => { const { gettingQuery, - onGetTasks, } = this.props; const query = { ...gettingQuery }; @@ -114,19 +161,19 @@ class TasksPageComponent extends React.PureComponent { 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 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)); + }, }; } 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, diff --git a/cvat-ui/src/stylesheet.css b/cvat-ui/src/stylesheet.css index e8772391..d553f7bd 100644 --- a/cvat-ui/src/stylesheet.css +++ b/cvat-ui/src/stylesheet.css @@ -48,7 +48,7 @@ } .cvat-black-color { - color: black; + color: #363435; } .cvat-feedback-button {