diff --git a/client/galaxy/scripts/bundleEntries.js b/client/galaxy/scripts/bundleEntries.js index 6c352c38119..6dce4ad39a6 100644 --- a/client/galaxy/scripts/bundleEntries.js +++ b/client/galaxy/scripts/bundleEntries.js @@ -93,8 +93,7 @@ export { panelManagement } from "onload/globalInits/panelManagement"; export { mountMakoTags } from "components/Tags"; export { mountJobMetrics } from "components/JobMetrics"; export { mountJobParameters } from "components/JobParameters"; -export { mountWorkflowEditor, mountWorkflowPanel } from "components/Workflow/Editor/mount"; -export { mountToolBoxWorkflow } from "components/Panels/mount"; +export { mountWorkflowEditor } from "components/Workflow/Editor/mount"; export { mountPageDisplay } from "components/PageDisplay"; // Used in common.mako diff --git a/client/galaxy/scripts/components/Panels/Common/ToolSection.test.js b/client/galaxy/scripts/components/Panels/Common/ToolSection.test.js index 60272efe23c..90ba6136894 100644 --- a/client/galaxy/scripts/components/Panels/Common/ToolSection.test.js +++ b/client/galaxy/scripts/components/Panels/Common/ToolSection.test.js @@ -65,33 +65,26 @@ describe("ToolSection", () => { } }); expect(wrapper.vm.opened).to.equal(true); - const $sectionName = wrapper.find(".name"); $sectionName.trigger("click"); await Vue.nextTick(); expect(wrapper.vm.opened).to.equal(false); - - wrapper.vm.queryFilter = ""; + wrapper.setProps({ queryFilter: "" }); await Vue.nextTick(); expect(wrapper.vm.opened).to.equal(false); - - wrapper.vm.queryFilter = "test"; + wrapper.setProps({ queryFilter: "test" }); await Vue.nextTick(); expect(wrapper.vm.opened).to.equal(true); - - wrapper.vm.disableFilter = true; + wrapper.setProps({ disableFilter: true }); await Vue.nextTick(); expect(wrapper.vm.opened).to.equal(true); - - wrapper.vm.queryFilter = ""; + wrapper.setProps({ queryFilter: "" }); await Vue.nextTick(); expect(wrapper.vm.opened).to.equal(false); - $sectionName.trigger("click"); await Vue.nextTick(); expect(wrapper.vm.opened).to.equal(true); - - wrapper.vm.queryFilter = "test"; + wrapper.setProps({ queryFilter: "test" }); await Vue.nextTick(); expect(wrapper.vm.opened).to.equal(false); }); diff --git a/client/galaxy/scripts/components/Panels/SidePanel.vue b/client/galaxy/scripts/components/Panels/SidePanel.vue index 2ce4cd15c68..4c087659ad4 100644 --- a/client/galaxy/scripts/components/Panels/SidePanel.vue +++ b/client/galaxy/scripts/components/Panels/SidePanel.vue @@ -1,6 +1,8 @@ diff --git a/client/galaxy/scripts/components/Workflow/Editor/WorkflowPanel.vue b/client/galaxy/scripts/components/Workflow/Editor/WorkflowPanel.vue deleted file mode 100644 index 32ad0d53ffd..00000000000 --- a/client/galaxy/scripts/components/Workflow/Editor/WorkflowPanel.vue +++ /dev/null @@ -1,106 +0,0 @@ - - - diff --git a/client/galaxy/scripts/components/Workflow/Editor/ZoomControl.vue b/client/galaxy/scripts/components/Workflow/Editor/ZoomControl.vue new file mode 100644 index 00000000000..43e80f7bde8 --- /dev/null +++ b/client/galaxy/scripts/components/Workflow/Editor/ZoomControl.vue @@ -0,0 +1,80 @@ + + + + + diff --git a/client/galaxy/scripts/components/Workflow/Editor/mount.js b/client/galaxy/scripts/components/Workflow/Editor/mount.js index 19eb6fb00fb..5ebdea19dd7 100644 --- a/client/galaxy/scripts/components/Workflow/Editor/mount.js +++ b/client/galaxy/scripts/components/Workflow/Editor/mount.js @@ -2,26 +2,14 @@ * Endpoint for mounting WorkflowEditor from non-Vue environment (editor.mako). */ import Vue from "vue"; -import SidePanel from "components/Panels/SidePanel"; import Index from "./Index"; import Node from "./Node"; -import WorkflowPanel from "./WorkflowPanel"; -export const mountWorkflowEditor = editorConfig => { - const propsData = { editorConfig }; +export const mountWorkflowEditor = propsData => { const component = Vue.extend(Index); - return new component({ propsData: propsData, el: "#center" }); -}; - -export const mountWorkflowPanel = propsData => { - const component = Vue.extend(SidePanel); return new component({ - propsData: { - side: "right", - currentPanel: WorkflowPanel, - currentPanelProperties: propsData - }, - el: "#right" + propsData: propsData, + el: "#columns" }); }; diff --git a/client/galaxy/scripts/components/Workflow/Editor/reportDefault.js b/client/galaxy/scripts/components/Workflow/Editor/reportDefault.js new file mode 100644 index 00000000000..044f8b611b9 --- /dev/null +++ b/client/galaxy/scripts/components/Workflow/Editor/reportDefault.js @@ -0,0 +1,18 @@ +export default ` +# Workflow Execution Report + +## Workflow Inputs +\`\`\`galaxy +invocation_inputs() +\`\`\` + +## Workflow Outputs +\`\`\`galaxy +invocation_outputs() +\`\`\` + +## Workflow +\`\`\`galaxy +workflow_display() +\`\`\` +`; diff --git a/client/galaxy/scripts/components/Workflow/Editor/reportHelp.js b/client/galaxy/scripts/components/Workflow/Editor/reportHelp.js deleted file mode 100644 index 41353dd64ce..00000000000 --- a/client/galaxy/scripts/components/Workflow/Editor/reportHelp.js +++ /dev/null @@ -1,88 +0,0 @@ -import { datasetCommandsHtml, markdownGeneralHelpHtml } from "components/Markdown/help"; - -const reportHelp = ` -
-

Overview

- -

- This document Markdown document will be used to generate a report - for invocations of this workflow. This document should be Markdown - with embedded command for extracting and displaying parts of the workflow, - its invocation metadata, its inputs and outputs, etc.. -

- -${markdownGeneralHelpHtml} - -

Workflow Commands

- -

- These commands to do not take any arguments and reference the whole workflow. For - instance, the following example would display a representation of the workflow in the - resulting report: -

- -
-\`\`\`galaxy
-workflow_display()
-\`\`\`
-
-
-
workflow_display
-
Embed a description of the workflow itself in the resulting report.
-
invocation_inputs
-
Embed the labeled workflow inputs in the resulting report.
-
invocation_outputs
-
Embed the labeled workflow outputs in the resulting report.
-
- -

Step Commands

- -

- These commands reference a workflow step label and refer to job corresponding - to that step. A current limitation is the report will break if these refer to - a collection mapping step, these must identify a single job. For instance, the - following example would show the job parameters the step labeled 'qc' was run - with: -

- -
-\`\`\`galaxy
-job_parameters(step="qc")
-\`\`\`
-
- - -
tool_stderr
-
Embed the tool standard error stream for this step in the resulting report.
-
tool_stdout
-
Embed the tool standard output stream for this step in the resulting report.
-
job_metrics
-
Embed the job metrics for this step in the resulting report (if user has permission).
-
job_parameters
-
Embed the tool parameters for this step in the resulting report.
- -

Input/Output Commands

- -

- These commands reference a workflow input or output by label. For instance, the - following example would display the dataset collection corresponding to output "Merged BAM": -

- -
-\`\`\`galaxy
-history_dataset_collection_display(output="Merged Bam")
-\`\`\`
-
- -${datasetCommandsHtml} -`; - -import $ from "jquery"; -import { hide_modal, show_modal } from "layout/modal"; - -export function showReportHelp() { - const reportHelpBody = $(reportHelp); - show_modal("Workflow Invocation Report Help", reportHelpBody, { - Ok: hide_modal - }); -} diff --git a/client/galaxy/scripts/components/Workflow/Editor/services.js b/client/galaxy/scripts/components/Workflow/Editor/services.js new file mode 100644 index 00000000000..74ff7a21a78 --- /dev/null +++ b/client/galaxy/scripts/components/Workflow/Editor/services.js @@ -0,0 +1,68 @@ +import axios from "axios"; +import { rethrowSimple } from "utils/simple-error"; +import { getAppRoot } from "onload/loadConfig"; + +/** Workflow data request helper **/ +export async function getVersions(id) { + try { + const response = await axios.get(`${getAppRoot()}api/workflows/${id}/versions`); + return response.data; + } catch (e) { + rethrowSimple(e); + } +} + +export async function getDatatypes() { + try { + const datatypesRequest = await axios.get(`${getAppRoot()}api/datatypes`); + const datatypes = datatypesRequest.data; + const mappingRequest = await axios.get(`${getAppRoot()}api/datatypes/mapping`); + const datatypes_mapping = mappingRequest.data; + return { datatypes, datatypes_mapping }; + } catch (e) { + rethrowSimple(e); + } +} + +export async function getModule(request_data) { + try { + const response = await axios.post(`${getAppRoot()}api/workflows/build_module`, request_data); + return response.data; + } catch (e) { + rethrowSimple(e); + } +} + +export async function loadWorkflow(workflow, id, version) { + try { + const versionQuery = version ? `version=${version}` : ""; + const { data } = await axios.get(`${getAppRoot()}workflow/load_workflow?_=true&id=${id}&${versionQuery}`); + workflow.remove_all(); + workflow.from_simple(data, true); + workflow.has_changes = false; + workflow.fit_canvas_to_nodes(); + workflow.scroll_to_nodes(); + workflow.canvas_manager.draw_overview(); + return data; + } catch (e) { + rethrowSimple(e); + } +} + +export async function saveWorkflow(workflow, id) { + workflow.rectify_workflow_outputs(); + if (workflow.has_changes) { + try { + const requestData = { workflow: workflow.to_simple(), from_tool_form: true }; + const { data } = await axios.put(`${getAppRoot()}api/workflows/${id}`, requestData); + workflow.name = data.name; + workflow.has_changes = false; + workflow.stored = true; + workflow.workflow_version = data.version; + return data; + } catch (e) { + rethrowSimple(e); + } + } + return {}; +} diff --git a/client/galaxy/scripts/components/Workflow/Editor/utilities.js b/client/galaxy/scripts/components/Workflow/Editor/utilities.js new file mode 100644 index 00000000000..aa966a976c1 --- /dev/null +++ b/client/galaxy/scripts/components/Workflow/Editor/utilities.js @@ -0,0 +1,210 @@ +import _ from "underscore"; +import $ from "jquery"; +import { getAppRoot } from "onload/loadConfig"; +import _l from "utils/localization"; +import Utils from "utils/utils"; +import WorkflowIcons from "components/Workflow/icons"; +import { DefaultForm, ToolForm } from "mvc/workflow/workflow-forms"; +import { loadWorkflow } from "./services"; +import { hide_modal, show_message, show_modal } from "layout/modal"; + +export function copyIntoWorkflow(workflow, id = null, stepCount = null) { + const _copy_into_workflow_ajax = () => { + // Load workflow definition + show_message("Importing workflow", "progress"); + loadWorkflow(workflow, id, null).then(data => { + workflow.from_simple(data, false); + // Determine if any parameters were 'upgraded' and provide message + var upgrade_message = ""; + $.each(data.upgrade_messages, (k, v) => { + upgrade_message += `
  • Step ${parseInt(k, 10) + 1}: ${workflow.nodes[k].name}
  • "; + }); + if (upgrade_message) { + show_modal( + "Subworkflow embedded with changes", + `Problems were encountered loading this workflow (possibly a result of tool upgrades). Please review the following parameters and then save.`, + { Continue: hide_modal } + ); + } else { + hide_modal(); + } + }); + }; + if (stepCount < 2) { + _copy_into_workflow_ajax(); + } else { + // don't ruin the workflow by adding 50 steps unprompted. + show_modal(_l("Warning"), `This will copy ${stepCount} new steps into your workflow.`, { + Cancel: hide_modal, + Copy: _copy_into_workflow_ajax + }); + } +} + +export function showWarnings(data) { + const body = $("
    ").text(data.message); + if (data.errors) { + body.addClass("warningmark"); + var errlist = $("