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

Add all csv info to displayed table on successful task creation #5491

Merged
merged 10 commits into from
Jun 1, 2021
Merged
1 change: 1 addition & 0 deletions CHANGELOG.unreleased.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ For upgrade instructions, please check the [migration guide](MIGRATIONS.released
- The visibility of meshes can now be toggled via the meshes tab. [#5346](https://github.com/scalableminds/webknossos/pull/5345)
- Added an icon to the info tab of a tracing that links to the dataset settings. It's located next to the dataset name. [#5462](https://github.com/scalableminds/webknossos/pull/5462)
- When exporting an user bounding box to tiff, the active mapping will now be applied to the exported data, as well. [#5474](https://github.com/scalableminds/webknossos/pull/5474)
- Changed the layout of the modal that informs the user about the success of task creations and changed the naming schema for the downloadable csv file containing the information about created tasks. [#5491](https://github.com/scalableminds/webknossos/pull/5491)

### Fixed
- Fixed that the row selection in the user table wasn't properly preserved when filtering the table and (un)selecting rows. [#5486](https://github.com/scalableminds/webknossos/pull/5486)
Expand Down
76 changes: 41 additions & 35 deletions frontend/javascripts/admin/task/task_create_form_view.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {
import { FormInstance } from "antd/lib/form";
import Toast from "libs/toast";
import React from "react";
import { InboxOutlined } from "@ant-design/icons";
import { InboxOutlined, WarningOutlined } from "@ant-design/icons";
import _ from "lodash";

import type { APIDataset, APITaskType, APIProject, APIScript, APITask } from "types/api_flow_types";
Expand Down Expand Up @@ -117,14 +117,13 @@ export function downloadTasksAsCSV(tasks: Array<APITask>) {
if (tasks.length < 0) {
return;
}
const maybeTaskPlural = tasks.length > 2 ? "tasks" : "task";
const maybeTaskPlural = tasks.length > 1 ? "task_ids" : "task_id";
const lastCreationTime = Math.max(...tasks.map(task => task.created));
const currentDateAsString = formatDateInLocalTimeZone(lastCreationTime);
const allTeamNames = _.uniq(tasks.map(task => task.team));
const teamName = allTeamNames.length > 1 ? "multiple_teams" : allTeamNames[0];
const currentDateAsString = formatDateInLocalTimeZone(lastCreationTime, "YYYY-MM-DD_HH-mm");
const allProjectNames = _.uniq(tasks.map(task => task.projectName)).join("_");
const allTasksAsStrings = tasks.map(task => taskToText(task)).join("\n");
const csv = [TASK_CSV_HEADER, allTasksAsStrings].join("\n");
const filename = `${teamName}-${maybeTaskPlural}-${currentDateAsString}.csv`;
const filename = `${maybeTaskPlural}_${allProjectNames}_${currentDateAsString}.csv`;
const blob = new Blob([csv], { type: "text/plain;charset=utf-8" });
saveAs(blob, filename);
}
Expand All @@ -138,14 +137,6 @@ export function handleTaskCreationResponse(response: TaskCreationResponseContain
const subHeadingStyle = { fontWeight: "bold" };
const displayResultsStyle = { maxHeight: 300, overflow: "auto" };

const warningsContent =
warnings.length > 0 ? (
<div>
<div style={subHeadingStyle}>There were warnings during task creation:</div>
<div>{warnings.join("\n")}</div>
</div>
) : null;

tasks.forEach((taskResponse: TaskCreationResponse, i: number) => {
if (taskResponse.status === 200 && taskResponse.success) {
if (!teamName) {
Expand All @@ -156,6 +147,24 @@ export function handleTaskCreationResponse(response: TaskCreationResponseContain
failedTasks.push(`Line ${i}: ${taskResponse.error} \n`);
}
});

const allProjectNames = _.uniq(successfulTasks.map(task => task.projectName));
if (allProjectNames.length > 1) {
warnings.push(
`You created tasks for multiple projects at a time: ${allProjectNames.join(", ")}.`,
);
}
const warningsContent =
warnings.length > 0 ? (
<div>
<div style={subHeadingStyle}>
<WarningOutlined style={{ color: "var(--ant-warning)" }} /> There were warnings during
task creation:
</div>
<div style={{ whiteSpace: "pre-line" }}>{warnings.join("\n")}</div>
</div>
) : null;

const failedTasksAsString = failedTasks.join("");
const successfulTasksContent =
successfulTasks.length <= maxDisplayedTasksCount ? (
Expand All @@ -165,7 +174,7 @@ export function handleTaskCreationResponse(response: TaskCreationResponseContain
{successfulTasks.map(task => taskToShortText(task)).join("\n")}
</pre>
) : (
"Too many tasks to show, please use CSV download for a full list."
"Too many tasks to show, please use CSV download above for a full list."
);
const failedTasksContent =
failedTasks.length <= maxDisplayedTasksCount ? (
Expand All @@ -184,37 +193,34 @@ export function handleTaskCreationResponse(response: TaskCreationResponseContain
{warningsContent}
{successfulTasks.length > 0 ? (
<div>
<div style={{ display: "flex", justifyContent: "center", margin: 20 }}>
<Button onClick={() => downloadTasksAsCSV(successfulTasks)} type="primary">
Download task info as CSV
</Button>
</div>
<div style={subHeadingStyle}> Successful Tasks: </div>
<div style={displayResultsStyle}>{successfulTasksContent}</div>
</div>
) : null}
{successfulTasks.length > 0 ? (
<React.Fragment>
<br />
<Button onClick={() => downloadTasksAsCSV(successfulTasks)}>
Download task info as CSV
</Button>
<br />
</React.Fragment>
) : null}
{failedTasks.length > 0 ? (
<React.Fragment>
<Divider />
<div>
<br />
<div style={{ display: "flex", justifyContent: "center", margin: 20 }}>
<Button
onClick={() => {
const blob = new Blob([failedTasksAsString], {
type: "text/plain;charset=utf-8",
});
saveAs(blob, "failed-tasks.csv");
}}
>
Download failed task info as CSV
</Button>
</div>
<div style={subHeadingStyle}> Failed Tasks:</div>
<div style={displayResultsStyle}> {failedTasksContent}</div>
<br />
<Button
onClick={() => {
const blob = new Blob([failedTasksAsString], {
type: "text/plain;charset=utf-8",
});
saveAs(blob, "failed-tasks.csv");
}}
>
Download failed task info as CSV
</Button>
<br />
</div>
</React.Fragment>
Expand Down
8 changes: 6 additions & 2 deletions frontend/javascripts/components/formatted_date.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,12 @@ const defaultTimeFormat = "YYYY-MM-DD HH:mm";
* a pure string representation. In all other cases, please prefer the
* <FormattedDate /> component below.
*/
export function formatDateInLocalTimeZone(date?: number = Date.now()): string {
return moment(date).format(defaultTimeFormat);
export function formatDateInLocalTimeZone(
date?: number = Date.now(),
format?: ?string = null,
): string {
format = format || defaultTimeFormat;
return moment(date).format(format);
}

export default function FormattedDate({
Expand Down