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

React & Antd UI: Export dataset, refactoring & fixes #872

Merged
merged 15 commits into from
Nov 28, 2019
Merged
Prev Previous commit
Next Next commit
Export as dataset, better error showing system
  • Loading branch information
bsekachev committed Nov 27, 2019
commit c197c7baa124af106ec3f2dd6577d20cd4b2f2c0
2 changes: 1 addition & 1 deletion cvat-core/src/server-proxy.js
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@
try {
await Axios.delete(`${backendAPI}/tasks/${id}`);
} catch (errorData) {
throw generateError(errorData, 'Could not delete the task from the server');
throw generateError(errorData, `Could not delete the task ${id} from the server`);
}
}

Expand Down
16 changes: 11 additions & 5 deletions cvat-ui/src/actions/formats-actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,15 @@ export enum FormatsActionTypes {
GETTING_FORMATS_FAILED = 'GETTING_FORMATS_FAILED',
}

export function gettingFormatsSuccess(formats: any): AnyAction {
export function gettingFormatsSuccess(
annotationFormats: any[],
datasetFormats: any[],
): AnyAction {
return {
type: FormatsActionTypes.GETTING_FORMATS_SUCCESS,
payload: {
formats,
annotationFormats,
datasetFormats,
},
};
}
Expand All @@ -30,14 +34,16 @@ export function gettingFormatsFailed(error: any): AnyAction {

export function gettingFormatsAsync(): ThunkAction<Promise<void>, {}, {}, AnyAction> {
return async (dispatch: ActionCreator<Dispatch>): Promise<void> => {
let formats = null;
let annotationFormats = null;
let datasetFormats = null;
try {
formats = await cvat.server.formats();
annotationFormats = await cvat.server.formats();
datasetFormats = await cvat.server.datasetFormats();
} catch (error) {
dispatch(gettingFormatsFailed(error));
return;
}

dispatch(gettingFormatsSuccess(formats));
dispatch(gettingFormatsSuccess(annotationFormats, datasetFormats));
};
}
24 changes: 24 additions & 0 deletions cvat-ui/src/actions/notification-actions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { AnyAction } from 'redux';

export enum NotificationsActionType {
RESET_ERRORS = 'RESET_ERRORS',
RESET_MESSAGES = 'RESET_MESSAGES',
}

export function resetErrors(): AnyAction {
const action = {
type: NotificationsActionType.RESET_ERRORS,
payload: {},
};

return action;
}

export function resetMessages(): AnyAction {
const action = {
type: NotificationsActionType.RESET_MESSAGES,
payload: {},
};

return action;
}
63 changes: 62 additions & 1 deletion cvat-ui/src/actions/tasks-actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ export enum TasksActionTypes {
DUMP_ANNOTATIONS = 'DUMP_ANNOTATIONS',
DUMP_ANNOTATIONS_SUCCESS = 'DUMP_ANNOTATIONS_SUCCESS',
DUMP_ANNOTATIONS_FAILED = 'DUMP_ANNOTATIONS_FAILED',
EXPORT_DATASET = 'EXPORT_DATASET',
EXPORT_DATASET_SUCCESS = 'EXPORT_DATASET_SUCCESS',
EXPORT_DATASET_FAILED = 'EXPORT_DATASET_FAILED',
DELETE_TASK = 'DELETE_TASK',
DELETE_TASK_SUCCESS = 'DELETE_TASK_SUCCESS',
DELETE_TASK_FAILED = 'DELETE_TASK_FAILED',
Expand All @@ -26,6 +29,7 @@ export enum TasksActionTypes {
UPDATE_TASK = 'UPDATE_TASK',
UPDATE_TASK_SUCCESS = 'UPDATE_TASK_SUCCESS',
UPDATE_TASK_FAILED = 'UPDATE_TASK_FAILED',
RESET_ERROR = 'RESET_ERROR',
}

function getTasks(): AnyAction {
Expand Down Expand Up @@ -150,7 +154,9 @@ ThunkAction<Promise<void>, {}, {}, AnyAction> {
try {
dispatch(dumpAnnotation(task, dumper));
const url = await task.annotations.dump(task.name, dumper);
window.location.assign(url);
// false positive
// eslint-disable-next-line security/detect-non-literal-fs-filename
window.open(url);
} catch (error) {
dispatch(dumpAnnotationFailed(task, dumper, error));
return;
Expand Down Expand Up @@ -210,6 +216,61 @@ ThunkAction<Promise<void>, {}, {}, AnyAction> {
};
}

function exportDataset(task: any, exporter: any): AnyAction {
const action = {
type: TasksActionTypes.EXPORT_DATASET,
payload: {
task,
exporter,
},
};

return action;
}

function exportDatasetSuccess(task: any, exporter: any): AnyAction {
const action = {
type: TasksActionTypes.EXPORT_DATASET_SUCCESS,
payload: {
task,
exporter,
},
};

return action;
}

function exportDatasetFailed(task: any, exporter: any, error: any): AnyAction {
const action = {
type: TasksActionTypes.EXPORT_DATASET_FAILED,
payload: {
task,
exporter,
error,
},
};

return action;
}

export function exportDatasetAsync(task: any, exporter: any):
ThunkAction<Promise<void>, {}, {}, AnyAction> {
return async (dispatch: ActionCreator<Dispatch>): Promise<void> => {
dispatch(exportDataset(task, exporter));

try {
const url = await task.annotations.exportDataset(task.name, exporter);
// false positive
// eslint-disable-next-line security/detect-non-literal-fs-filename
window.open(url, '_blank');
} catch (error) {
dispatch(exportDatasetFailed(task, exporter, error));
}

dispatch(exportDatasetSuccess(task, exporter));
};
}

function deleteTask(taskID: number): AnyAction {
const action = {
type: TasksActionTypes.DELETE_TASK,
Expand Down
11 changes: 0 additions & 11 deletions cvat-ui/src/actions/users-actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,10 @@ import getCore from '../core';
const core = getCore();

export enum UsersActionTypes {
GET_USERS = 'GET_USERS',
GET_USERS_SUCCESS = 'GET_USERS_SUCCESS',
GET_USERS_FAILED = 'GET_USERS_FAILED',
}

function getUsers(): AnyAction {
const action = {
type: UsersActionTypes.GET_USERS,
payload: { },
};

return action;
}

function getUsersSuccess(users: any[]): AnyAction {
const action = {
type: UsersActionTypes.GET_USERS_SUCCESS,
Expand All @@ -42,7 +32,6 @@ export function getUsersAsync():
ThunkAction<Promise<void>, {}, {}, AnyAction> {
return async (dispatch: ActionCreator<Dispatch>): Promise<void> => {
try {
dispatch(getUsers());
const users = await core.users.get();
dispatch(
getUsersSuccess(
Expand Down
28 changes: 20 additions & 8 deletions cvat-ui/src/components/actions-menu/actions-menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,27 @@ import {
Modal,
} from 'antd';

import Text from 'antd/lib/typography/Text';
import { ClickParam } from 'antd/lib/menu/index';

import LoaderItemComponent from './loader-item';
import DumperItemComponent from './dumper-item';
import ExportItemComponent from './export-item';


interface ActionsMenuComponentProps {
taskInstance: any;
loaders: any[];
dumpers: any[];
exporters: any[];
loadActivity: string | null;
dumpActivities: string[] | null;
exportActivities: string[] | null;
installedTFAnnotation: boolean;
installedTFSegmentation: boolean;
installedAutoAnnotation: boolean;
onLoadAnnotation: (taskInstance: any, loader: any, file: File) => void;
onDumpAnnotation: (taskInstance: any, dumper: any) => void;
onExportDataset: (taskInstance: any, exporter: any) => void;
onDeleteTask: (taskInstance: any) => void;
onOpenRunWindow: (taskInstance: any) => void;
}
Expand Down Expand Up @@ -66,24 +69,22 @@ export default function ActionsMenuComponent(props: ActionsMenuComponentProps) {
const tracker = props.taskInstance.bugTracker;
const renderModelRunner = props.installedAutoAnnotation ||
props.installedTFAnnotation || props.installedTFSegmentation;

return (
<Menu selectable={false} className='cvat-actions-menu' onClick={
(params: ClickParam) => handleMenuClick(props, params)
}>
<Menu.SubMenu key='dump' title={<
Text>{'Dump annotations'}</Text>
}>
<Menu.SubMenu key='dump' title='Dump annotations'>
{
props.dumpers.map((dumper) => DumperItemComponent({
dumper,
taskInstance: props.taskInstance,
dumpActivities: props.dumpActivities,
dumpActivity: (props.dumpActivities || [])
.filter((_dumper: string) => _dumper === dumper.name)[0] || null,
onDumpAnnotation: props.onDumpAnnotation,
} ))}
</Menu.SubMenu>
<Menu.SubMenu key='load' title={
<Text>{'Upload annotations'}</Text>
}>
<Menu.SubMenu key='load' title='Upload annotations'>
{
props.loaders.map((loader) => LoaderItemComponent({
loader,
Expand All @@ -93,6 +94,17 @@ export default function ActionsMenuComponent(props: ActionsMenuComponentProps) {
}))
}
</Menu.SubMenu>
<Menu.SubMenu key='export' title='Export as dataset'>
{
props.exporters.map((exporter) => ExportItemComponent({
exporter,
taskInstance: props.taskInstance,
exportActivity: (props.exportActivities || [])
.filter((_exporter: string) => _exporter === exporter.name)[0] || null,
onExportDataset: props.onExportDataset,
}))
}
</Menu.SubMenu>
{tracker && <Menu.Item key='tracker'>Open bug tracker</Menu.Item>}
{renderModelRunner && <Menu.Item key='auto_annotation'>Automatic annotation</Menu.Item>}
<hr/>
Expand Down
8 changes: 2 additions & 6 deletions cvat-ui/src/components/actions-menu/dumper-item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import Text from 'antd/lib/typography/Text';
interface DumperItemComponentProps {
taskInstance: any;
dumper: any;
dumpActivities: string[] | null;
dumpActivity: string | null;
onDumpAnnotation: (task: any, dumper: any) => void;
}

Expand All @@ -24,11 +24,7 @@ export default function DumperItemComponent(props: DumperItemComponentProps) {
const task = props.taskInstance;
const { mode } = task;
const { dumper } = props;

const dumpingWithThisDumper = (props.dumpActivities || [])
.filter((_dumper: string) => _dumper === dumper.name)[0];

const pending = !!dumpingWithThisDumper;
const pending = !!props.dumpActivity;

return (
<Menu.Item className='cvat-actions-menu-dump-submenu-item' key={dumper.name}>
Expand Down
38 changes: 38 additions & 0 deletions cvat-ui/src/components/actions-menu/export-item.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import React from 'react';

import {
Menu,
Button,
Icon,
} from 'antd';

import Text from 'antd/lib/typography/Text';

interface DumperItemComponentProps {
taskInstance: any;
exporter: any;
exportActivity: string | null;
onExportDataset: (task: any, exporter: any) => void;
}

export default function DumperItemComponent(props: DumperItemComponentProps) {
const task = props.taskInstance;
const { exporter } = props;
const pending = !!props.exportActivity;

return (
<Menu.Item className='cvat-actions-menu-export-submenu-item' key={exporter.name}>
<Button block={true} type='link' disabled={pending}
onClick={() => {
props.onExportDataset(task, exporter);
}}>
<Icon type='export'/>
<Text strong={props.exporter.is_default}>
{exporter.name}
</Text>
{pending && <Icon type='loading'/>}
</Button>
</Menu.Item>
);
}

16 changes: 5 additions & 11 deletions cvat-ui/src/components/create-task-page/create-task-content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
Modal,
Button,
Collapse,
message,
notification,
} from 'antd';

import Text from 'antd/lib/typography/Text';
Expand All @@ -28,7 +28,6 @@ export interface CreateTaskData {
interface Props {
onCreate: (data: CreateTaskData) => void;
status: string;
error: string;
installedGit: boolean;
}

Expand Down Expand Up @@ -190,15 +189,10 @@ export default class CreateTaskContent extends React.PureComponent<Props, State>
}

public componentDidUpdate(prevProps: Props) {
if (this.props.error && prevProps.error !== this.props.error) {
Modal.error({
title: 'Could not create task',
content: this.props.error,
});
}

if (this.props.status === 'CREATED' && prevProps.status !== 'CREATED') {
message.success('The task has been created');
notification.info({
message: 'The task has been created',
});

this.basicConfigurationComponent.resetFields();
if (this.advancedConfigurationComponent) {
Expand All @@ -216,7 +210,7 @@ export default class CreateTaskContent extends React.PureComponent<Props, State>
public render() {
const loading = !!this.props.status
&& this.props.status !== 'CREATED'
&& !this.props.error;
&& this.props.status !== 'FAILED';

return (
<Row type='flex' justify='start' align='middle' className='cvat-create-task-content'>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import CreateTaskContent, { CreateTaskData } from './create-task-content';

interface Props {
onCreate: (data: CreateTaskData) => void;
error: string;
status: string;
installedGit: boolean;
}
Expand All @@ -23,7 +22,6 @@ export default function CreateTaskPage(props: Props) {
<Text className='cvat-title'>Create a new task</Text>
<CreateTaskContent
status={props.status}
error={props.error}
onCreate={props.onCreate}
installedGit={props.installedGit}
/>
Expand Down
Loading