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

Create new export modal #6171

Merged
merged 41 commits into from
May 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
b873153
add download modal to UI
Dagobert42 Apr 27, 2022
9572424
implement modal frontend component
Dagobert42 Apr 27, 2022
eeeaa2f
Merge branch 'master' into create-new-export-modal
Dagobert42 Apr 27, 2022
081703e
pretty
Dagobert42 Apr 27, 2022
df96f5a
Merge branch 'master' into create-new-export-modal
Dagobert42 Apr 27, 2022
a5a425d
add selection components to export page
Dagobert42 Apr 27, 2022
625f736
omit <volume> tags in NML when skipVolumeData is true in download
fm3 May 2, 2022
8470f72
improve wording
Dagobert42 May 5, 2022
f8a43f2
get rid of linter warning
Dagobert42 May 5, 2022
9a7db89
add warnings, correctly adapt ok texts, pre-fill python snippet
Dagobert42 May 5, 2022
7308e08
more wording
Dagobert42 May 5, 2022
d4e68e9
some refactoring
Dagobert42 May 6, 2022
e242334
add flag for WKW download
Dagobert42 May 11, 2022
bf0a627
rename download function
Dagobert42 May 11, 2022
39f780d
random correction
Dagobert42 May 11, 2022
c41aa93
call backend with new skipVolumeData flag
Dagobert42 May 11, 2022
ea8ac50
fix backend download call
Dagobert42 May 11, 2022
467a617
remove unneeded logs
Dagobert42 May 11, 2022
bd7a63d
Merge branch 'master' into create-new-export-modal
Dagobert42 May 12, 2022
9bf8eb8
small correction
Dagobert42 May 12, 2022
eee7390
split Select from FormItems to reuse in Download Modal
Dagobert42 May 12, 2022
7a3fd81
export functions for starting Jobs from DownloadModalView (export tab)
Dagobert42 May 12, 2022
f643903
start export jobs from modal
Dagobert42 May 12, 2022
0c7ae03
keep window open if desired
Dagobert42 May 12, 2022
aa343d6
add links, improve messages
Dagobert42 May 12, 2022
7061cde
improve warnings for export UX
Dagobert42 May 12, 2022
9eeede6
Merge branch 'master' into create-new-export-modal
Dagobert42 May 12, 2022
1016d85
improve some typing
philippotto May 13, 2022
d7c9c57
edit typos and remove comments/logs
Dagobert42 May 18, 2022
b5e0a12
sort imports
Dagobert42 May 18, 2022
626f99b
show download checkboxes according to tracing
Dagobert42 May 18, 2022
bd50912
code review change
Dagobert42 May 18, 2022
b5bb9c8
Merge branch 'master' into create-new-export-modal
Dagobert42 May 18, 2022
76e1fb1
pretty after merge commit
Dagobert42 May 18, 2022
2974754
add job description for neuron inferral
Dagobert42 May 18, 2022
1ab4cc5
inline default selection
Dagobert42 May 18, 2022
84902c3
Merge branch 'master' into create-new-export-modal
Dagobert42 May 18, 2022
634ac4e
Merge branch 'master' into create-new-export-modal
Dagobert42 May 19, 2022
bd96c8d
minor tweaks
philippotto May 19, 2022
850eec4
integrate bounding box size limits in export modal UI
philippotto May 19, 2022
a0ccafd
Merge branch 'create-new-export-modal' of github.com:scalableminds/we…
philippotto May 19, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion app/controllers/AnnotationIOController.scala
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,8 @@ Expects:
None,
organizationName,
Some(user),
taskOpt)
taskOpt,
skipVolumeData)
temporaryFile = temporaryFileCreator.create()
zipper = ZipIO.startZip(new BufferedOutputStream(new FileOutputStream(new File(temporaryFile.path.toString))))
_ <- zipper.addFileFromEnumerator(name + ".nml", nmlStream)
Expand Down
35 changes: 23 additions & 12 deletions app/models/annotation/nml/NmlWriter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ class NmlWriter @Inject()(implicit ec: ExecutionContext) extends FoxImplicits {
volumeFilename: Option[String],
organizationName: String,
annotationOwner: Option[User],
annotationTask: Option[Task]): Enumerator[Array[Byte]] = Enumerator.outputStream { os =>
annotationTask: Option[Task],
skipVolumeData: Boolean = false): Enumerator[Array[Byte]] = Enumerator.outputStream { os =>
implicit val writer: IndentingXMLStreamWriter =
new IndentingXMLStreamWriter(outputService.createXMLStreamWriter(os))

Expand All @@ -50,7 +51,8 @@ class NmlWriter @Inject()(implicit ec: ExecutionContext) extends FoxImplicits {
volumeFilename,
organizationName,
annotationOwner,
annotationTask)
annotationTask,
skipVolumeData)
_ = os.close()
} yield nml
}
Expand All @@ -61,7 +63,8 @@ class NmlWriter @Inject()(implicit ec: ExecutionContext) extends FoxImplicits {
volumeFilename: Option[String],
organizationName: String,
annotationOwner: Option[User],
annotationTask: Option[Task])(implicit writer: XMLStreamWriter): Fox[Unit] =
annotationTask: Option[Task],
skipVolumeData: Boolean)(implicit writer: XMLStreamWriter): Fox[Unit] =
for {
_ <- Xml.withinElement("things") {
for {
Expand All @@ -81,7 +84,8 @@ class NmlWriter @Inject()(implicit ec: ExecutionContext) extends FoxImplicits {
case _ => ()
}
_ = volumeLayers.zipWithIndex.foreach {
case (volumeLayer, index) => writeVolumeThings(volumeLayer, index, volumeLayers.length == 1, volumeFilename)
case (volumeLayer, index) =>
writeVolumeThings(volumeLayer, index, volumeLayers.length == 1, volumeFilename, skipVolumeData)
}
} yield ()
}
Expand Down Expand Up @@ -193,14 +197,21 @@ class NmlWriter @Inject()(implicit ec: ExecutionContext) extends FoxImplicits {
def writeVolumeThings(volumeLayer: FetchedAnnotationLayer,
index: Int,
isSingle: Boolean,
volumeFilename: Option[String])(implicit writer: XMLStreamWriter): Unit =
Xml.withinElementSync("volume") {
writer.writeAttribute("id", index.toString)
writer.writeAttribute("location", volumeFilename.getOrElse(volumeLayer.volumeDataZipName(index, isSingle)))
volumeLayer.name.foreach(n => writer.writeAttribute("name", n))
volumeLayer.tracing match {
case Right(volumeTracing) => volumeTracing.fallbackLayer.foreach(writer.writeAttribute("fallbackLayer", _))
case _ => ()
volumeFilename: Option[String],
skipVolumeData: Boolean)(implicit writer: XMLStreamWriter): Unit =
if (skipVolumeData) {
val nameLabel = volumeLayer.name.map(n => f"named $n ").getOrElse("")
writer.writeComment(
f"A volume layer $nameLabel(id = $index) was omitted here while downloading this annotation without volume data.")
} else {
Xml.withinElementSync("volume") {
writer.writeAttribute("id", index.toString)
writer.writeAttribute("location", volumeFilename.getOrElse(volumeLayer.volumeDataZipName(index, isSingle)))
volumeLayer.name.foreach(n => writer.writeAttribute("name", n))
volumeLayer.tracing match {
case Right(volumeTracing) => volumeTracing.fallbackLayer.foreach(writer.writeAttribute("fallbackLayer", _))
case _ => ()
}
}
}

Expand Down
8 changes: 6 additions & 2 deletions frontend/javascripts/admin/admin_rest_api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -874,11 +874,12 @@ export function convertToHybridTracing(
});
}

export async function downloadNml(
export async function downloadAnnotation(
annotationId: string,
annotationType: APIAnnotationType,
showVolumeFallbackDownloadWarning: boolean = false,
versions: Versions = {},
includeVolumeData: boolean = true,
) {
const possibleVersionString = Object.entries(versions)
.map(([key, val]) => `${key}Version=${val}`)
Expand All @@ -889,11 +890,14 @@ export async function downloadNml(
timeout: 12000,
});
}
const skipVolumeDataString = includeVolumeData ? "" : "skipVolumeData=true";
const maybeAmpersand = possibleVersionString === "" && !includeVolumeData ? "" : "&";

const downloadUrl = `/api/annotations/${annotationType}/${annotationId}/download?${possibleVersionString}`;
const downloadUrl = `/api/annotations/${annotationType}/${annotationId}/download?${possibleVersionString}${maybeAmpersand}${skipVolumeDataString}`;
const { buffer, headers } = await Request.receiveArraybuffer(downloadUrl, {
extractHeaders: true,
});

// Using headers to determine the name and type of the file.
const contentDispositionHeader = headers["content-disposition"];
const filenameStartingPart = 'filename="';
Expand Down
14 changes: 14 additions & 0 deletions frontend/javascripts/admin/job/job_list_view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,20 @@ class JobListView extends React.PureComponent<Props, State> {
</Link>{" "}
</span>
);
} else if (
job.type === "infer_neurons" &&
job.organizationName &&
job.datasetName &&
job.layerName
) {
return (
<span>
Neuron inferral for layer {job.layerName} of{" "}
<Link to={`/datasets/${job.organizationName}/${job.datasetName}/view`}>
{job.datasetName}
</Link>{" "}
</span>
);
philippotto marked this conversation as resolved.
Show resolved Hide resolved
} else if (
job.type === "materialize_volume_annotation" &&
job.organizationName &&
Expand Down
4 changes: 2 additions & 2 deletions frontend/javascripts/admin/project/project_list_view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import {
deleteProject,
pauseProject,
resumeProject,
downloadNml,
downloadAnnotation,
getTasks,
getTaskType,
} from "admin/admin_rest_api";
Expand Down Expand Up @@ -409,7 +409,7 @@ class ProjectListView extends React.PureComponent<PropsWithRouter, State> {
href="#"
onClick={async () => {
this.maybeShowNoFallbackDataInfo(project.id);
await downloadNml(project.id, "CompoundProject");
await downloadAnnotation(project.id, "CompoundProject");
}}
title="Download all Finished Annotations"
icon={<DownloadOutlined key="download-icon" />}
Expand Down
4 changes: 2 additions & 2 deletions frontend/javascripts/admin/task/task_annotation_view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import {
finishAnnotation,
resetAnnotation,
deleteAnnotation,
downloadNml,
downloadAnnotation,
} from "admin/admin_rest_api";
import FormattedDate from "components/formatted_date";
import Toast from "libs/toast";
Expand Down Expand Up @@ -143,7 +143,7 @@ class TaskAnnotationView extends React.PureComponent<Props, State> {
href="#"
onClick={() => {
const isVolumeIncluded = getVolumeDescriptors(annotation).length > 0;
return downloadNml(annotation.id, "Task", isVolumeIncluded);
return downloadAnnotation(annotation.id, "Task", isVolumeIncluded);
}}
icon={<DownloadOutlined />}
>
Expand Down
4 changes: 2 additions & 2 deletions frontend/javascripts/admin/task/task_list_view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import _ from "lodash";
import features from "features";
import { AsyncLink } from "components/async_clickables";
import type { APITask, APITaskType } from "types/api_flow_types";
import { deleteTask, getTasks, downloadNml } from "admin/admin_rest_api";
import { deleteTask, getTasks, downloadAnnotation } from "admin/admin_rest_api";
import { formatTuple, formatSeconds } from "libs/format_utils";
import { handleGenericError } from "libs/error_handling";
import FormattedDate from "components/formatted_date";
Expand Down Expand Up @@ -418,7 +418,7 @@ class TaskListView extends React.PureComponent<Props, State> {
href="#"
onClick={() => {
const includesVolumeData = task.type.tracingType !== "skeleton";
return downloadNml(task.id, "CompoundTask", includesVolumeData);
return downloadAnnotation(task.id, "CompoundTask", includesVolumeData);
}}
title="Download all Finished Annotations"
icon={<DownloadOutlined />}
Expand Down
8 changes: 6 additions & 2 deletions frontend/javascripts/admin/tasktype/task_type_list_view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import * as React from "react";
import _ from "lodash";
import { AsyncLink } from "components/async_clickables";
import type { APITaskType } from "types/api_flow_types";
import { getTaskTypes, deleteTaskType, downloadNml } from "admin/admin_rest_api";
import { getTaskTypes, deleteTaskType, downloadAnnotation } from "admin/admin_rest_api";
import { handleGenericError } from "libs/error_handling";
import LinkButton from "components/link_button";
import Persistence from "libs/persistence";
Expand Down Expand Up @@ -287,7 +287,11 @@ class TaskTypeListView extends React.PureComponent<Props, State> {
href="#"
onClick={() => {
const includesVolumeData = taskType.tracingType !== "skeleton";
return downloadNml(taskType.id, "CompoundTaskType", includesVolumeData);
return downloadAnnotation(
taskType.id,
"CompoundTaskType",
includesVolumeData,
);
}}
title="Download all Finished Annotations"
icon={<DownloadOutlined />}
Expand Down
4 changes: 2 additions & 2 deletions frontend/javascripts/dashboard/dashboard_task_list_view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import {
finishTask,
requestTask,
peekNextTasks,
downloadNml,
downloadAnnotation,
} from "admin/admin_rest_api";
import { enforceActiveUser } from "oxalis/model/accessors/user_accessor";
import { getSkeletonDescriptor } from "oxalis/model/accessors/skeletontracing_accessor";
Expand Down Expand Up @@ -272,7 +272,7 @@ class DashboardTaskListView extends React.PureComponent<PropsWithRouter, State>
href="#"
onClick={() => {
const isVolumeIncluded = getVolumeDescriptors(annotation).length > 0;
return downloadNml(annotation.id, "Task", isVolumeIncluded);
return downloadAnnotation(annotation.id, "Task", isVolumeIncluded);
}}
icon={<DownloadOutlined />}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import {
finishAnnotation,
reOpenAnnotation,
getCompactAnnotations,
downloadNml,
downloadAnnotation,
getCompactAnnotationsForUser,
} from "admin/admin_rest_api";
import { formatHash } from "libs/format_utils";
Expand Down Expand Up @@ -240,7 +240,7 @@ class ExplorativeAnnotationsView extends React.PureComponent<Props, State> {
<br />
<AsyncLink
href="#"
onClick={() => downloadNml(id, typ, hasVolumeTracing)}
onClick={() => downloadAnnotation(id, typ, hasVolumeTracing)}
icon={<DownloadOutlined key="download" />}
>
Download
Expand Down
9 changes: 8 additions & 1 deletion frontend/javascripts/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ Editing should be done in a single window only.

In order to restore the current window, a reload is necessary.`,
"react.rendering_error":
"Unfortunately, we encountered an error during rendering. We cannot guarantee that your work is persisted. Please reload the page and try again.",
"Unfortunately, webKnossos encountered an error during rendering. Your latest changes may not have been saved. Please reload the page to try again.",
"save.leave_page_unfinished":
"WARNING: You have unsaved progress that may be lost when hitting OK. Please click cancel, wait until the progress is saved and the save button displays a checkmark before leaving the page..",
"save.failed": "Failed to save annotation. Retrying.",
Expand Down Expand Up @@ -293,6 +293,13 @@ instead. Only enable this option if you understand its effect. All layers will n
"annotation.delete": "Do you really want to reset and cancel this annotation?",
"annotation.was_edited": "Successfully updated annotation",
"annotation.shared_teams_edited": "Successfully updated the sharing options for the annotation",
"annotation.download": "The following annotation data is available for download immediately.",
"annotation.export":
"Exporting this annotation as TIFF images will trigger a background job to prepare data for download. This may take a while depending on the size of your dataset as well as bounding box and layer selection. You can monitor the progress and start the download from the ",
"annotation.export_no_worker":
"This webKnossos instance is not configured to run TIFF export jobs on a dedicated background worker. To learn more about this feature please contact us at ",
"annotation.python_do_not_share":
"These snippets are pre-configured and contain your personal access token and annotation meta data. Do not share this information with anyone you do not trust!",
"project.delete": "Do you really want to delete this project?",
"project.increase_instances":
"Do you really want to add one additional instance to all tasks of this project?",
Expand Down
1 change: 1 addition & 0 deletions frontend/javascripts/oxalis/default_state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ const defaultState: OxalisState = {
activeTool: "MOVE",
showDropzoneModal: false,
showVersionRestore: false,
showDownloadModal: false,
showShareModal: false,
storedLayouts: {},
isImportingMesh: false,
Expand Down
15 changes: 15 additions & 0 deletions frontend/javascripts/oxalis/model/actions/ui_actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@ type SetThemeAction = {
type: "SET_THEME";
value: Theme;
};

type SetDownloadModalVisibilityAction = {
type: "SET_DOWNLOAD_MODAL_VISIBILITY";
visible: boolean;
};

type SetShareModalVisibilityAction = {
type: "SET_SHARE_MODAL_VISIBILITY";
visible: boolean;
Expand All @@ -61,6 +67,7 @@ export type UiAction =
| SetToolAction
| CycleToolAction
| SetThemeAction
| SetDownloadModalVisibilityAction
| SetShareModalVisibilityAction
| SetBusyBlockingInfoAction;
export const setDropzoneModalVisibilityAction = (
Expand Down Expand Up @@ -110,6 +117,14 @@ export const setThemeAction = (value: Theme): SetThemeAction => ({
type: "SET_THEME",
value,
});

export const setDownloadModalVisibilityAction = (
visible: boolean,
): SetDownloadModalVisibilityAction => ({
type: "SET_DOWNLOAD_MODAL_VISIBILITY",
visible,
});

export const setShareModalVisibilityAction = (visible: boolean): SetShareModalVisibilityAction => ({
type: "SET_SHARE_MODAL_VISIBILITY",
visible,
Expand Down
4 changes: 4 additions & 0 deletions frontend/javascripts/oxalis/model/reducers/ui_reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ function UiReducer(state: OxalisState, action: Action): OxalisState {
});
}

case "SET_DOWNLOAD_MODAL_VISIBILITY": {
return updateKey(state, "uiInformation", { showDownloadModal: action.visible });
}

case "SET_SHARE_MODAL_VISIBILITY": {
return updateKey(state, "uiInformation", {
showShareModal: action.visible,
Expand Down
1 change: 1 addition & 0 deletions frontend/javascripts/oxalis/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,7 @@ export type BusyBlockingInfo = {
type UiInformation = {
readonly showDropzoneModal: boolean;
readonly showVersionRestore: boolean;
readonly showDownloadModal: boolean;
readonly showShareModal: boolean;
readonly activeTool: AnnotationTool;
readonly storedLayouts: Record<string, any>;
Expand Down
Loading