From b37e3c720f0de194fb84a8d9afb807f4a3bdef98 Mon Sep 17 00:00:00 2001 From: guerler Date: Fri, 7 Feb 2020 00:12:22 -0500 Subject: [PATCH 01/62] Remove backbone dependency from terminal views --- .../mvc/workflow/workflow-view-terminals.js | 228 ++++++++++-------- 1 file changed, 130 insertions(+), 98 deletions(-) diff --git a/client/galaxy/scripts/mvc/workflow/workflow-view-terminals.js b/client/galaxy/scripts/mvc/workflow/workflow-view-terminals.js index 7614dfa71c1..242c76c9b0f 100644 --- a/client/galaxy/scripts/mvc/workflow/workflow-view-terminals.js +++ b/client/galaxy/scripts/mvc/workflow/workflow-view-terminals.js @@ -1,6 +1,5 @@ import $ from "jquery"; import _ from "underscore"; -import Backbone from "backbone"; import Terminals from "mvc/workflow/workflow-terminals"; import Connector from "mvc/workflow/workflow-connector"; import ariaAlert from "utils/ariaAlert"; @@ -8,49 +7,52 @@ import ariaAlert from "utils/ariaAlert"; // TODO; tie into Galaxy state? window.workflow_globals = window.workflow_globals || {}; -var TerminalMappingView = Backbone.View.extend({ - tagName: "div", - className: "fa-icon-button fa fa-folder-o", - initialize: function(options) { +class TerminalMappingView { + constructor(options = {}) { + this.$el = $("
"); var mapText = "Run tool in parallel over collection"; this.$el.tooltip({ delay: 500, title: mapText }); + this.model = options.model; this.model.bind("change", _.bind(this.render, this)); - }, - render: function() { - if (this.model.mapOver.isCollection) { + } + render() { + if (this.model.mapOver && this.model.mapOver.isCollection) { this.$el.show(); } else { this.$el.hide(); } } -}); +} -var InputTerminalMappingView = TerminalMappingView.extend({ - events: { - click: "onClick", - mouseenter: "onMouseEnter", - mouseleave: "onMouseLeave" - }, - onMouseEnter: function(e) { +export class InputTerminalMappingView extends TerminalMappingView { + constructor(options = {}) { + super(options); + const self = this; + this.$el.on("click", () => self.onClick()); + this.$el.on("mouseenter", () => self.onMouseEnter()); + this.$el.on("mouseleave", () => self.onMouseLeave()); + } + onMouseEnter() { var model = this.model; if (!model.terminal.connected() && model.mapOver.isCollection) { this.$el.css("color", "red"); } - }, - onMouseLeave: function(e) { + } + onMouseLeave() { this.$el.css("color", "black"); - }, - onClick: function(e) { + } + onClick() { var model = this.model; if (!model.terminal.connected() && model.mapOver.isCollection) { // TODO: Consider prompting... model.terminal.resetMapping(); } } -}); +} -var TerminalView = Backbone.View.extend({ - setupMappingView: function(terminal) { +class TerminalView { + setupMappingView(terminal) { + console.log(this.terminalMappingClass); var terminalMapping = new this.terminalMappingClass({ terminal: terminal }); @@ -60,19 +62,24 @@ var TerminalView = Backbone.View.extend({ terminalMappingView.render(); terminal.terminalMappingView = terminalMappingView; this.terminalMappingView = terminalMappingView; - }, - terminalElements: function() { + } + terminalElements() { if (this.terminalMappingView) { return [this.terminalMappingView.el, this.el]; } else { return [this.el]; } } -}); +} -var BaseInputTerminalView = TerminalView.extend({ - className: "terminal input-terminal", - initialize: function(options) { +class BaseInputTerminalView extends TerminalView { + constructor(options = {}, classes = {}) { + super(); + this.terminalMappingViewClass = classes.terminalMappingViewClass; + this.terminalMappingClass = classes.terminalMappingClass; + this.el = document.createElement("div"); + this.el.className = "terminal input-terminal"; + this.$el = $(this.el); const node = options.node; const input = options.input; const name = input.name; @@ -89,15 +96,15 @@ var BaseInputTerminalView = TerminalView.extend({ terminal.name = name; terminal.label = input.label; node.input_terminals[name] = terminal; - }, - events: { - dropinit: "onDropInit", - dropstart: "onDropStart", - dropend: "onDropEnd", - drop: "onDrop", - hover: "onHover" - }, - onDropInit: function(e, d) { + + const self = this; + this.$el.on("dropinit", (e, d) => self.onDropInit(e, d)); + this.$el.on("dropstart", (e, d) => self.onDropStart(e, d)); + this.$el.on("dropend", (e, d) => self.onDropEnd(e, d)); + this.$el.on("drop", (e, d) => self.onDrop(e, d)); + this.$el.on("hover", () => self.onHover()); + } + onDropInit(e, d = {}) { var terminal = this.el.terminal; // Accept a dragable if it is an output terminal and has a // compatible type @@ -113,8 +120,8 @@ var BaseInputTerminalView = TerminalView.extend({ } return true; - }, - onDropStart: function(e, d) { + } + onDropStart(e, d = {}) { if (d.proxy.terminal) { if (this.$el.hasClass("can-accept")) { d.proxy.terminal.connectors[0].inner_color = "#BBFFBB"; @@ -129,21 +136,21 @@ var BaseInputTerminalView = TerminalView.extend({ } } } - }, - onDropEnd: function(e, d) { + } + onDropEnd(e, d = {}) { d.proxy.dropTooltip = ""; if (d.proxy.terminal) { d.proxy.terminal.connectors[0].inner_color = "#FFFFFF"; } - }, - onDrop: function(e, d) { + } + onDrop(e, d = {}) { d.proxy.dropTooltip = ""; if (this.$el.hasClass("can-accept")) { const terminal = this.el.terminal; new Connector(d.drag.terminal, terminal).redraw(); } - }, - onHover: function() { + } + onHover() { const element = this.el; const terminal = element.terminal; // If connected, create a popup to allow disconnection @@ -166,44 +173,61 @@ var BaseInputTerminalView = TerminalView.extend({ .append(t); } } -}); +} -var InputTerminalView = BaseInputTerminalView.extend({ - terminalMappingClass: Terminals.TerminalMapping, - terminalMappingViewClass: InputTerminalMappingView, - terminalForInput: function(input) { +export class InputTerminalView extends BaseInputTerminalView { + constructor(options = {}) { + super(options, { + terminalMappingViewClass: InputTerminalMappingView, + terminalMappingClass: Terminals.TerminalMapping + }); + } + terminalForInput(input) { return new Terminals.InputTerminal({ element: this.el, input: input }); } -}); +} -var InputParameterTerminalView = BaseInputTerminalView.extend({ - terminalMappingClass: Terminals.TerminalMapping, - terminalMappingViewClass: InputTerminalMappingView, - terminalForInput: function(input) { +export class InputParameterTerminalView extends BaseInputTerminalView { + constructor(options = {}) { + super(options, { + terminalMappingViewClass: InputTerminalMappingView, + terminalMappingClass: Terminals.TerminalMapping + }); + } + terminalForInput(input) { return new Terminals.InputParameterTerminal({ element: this.el, input: input }); } -}); +} -var InputCollectionTerminalView = BaseInputTerminalView.extend({ - terminalMappingClass: Terminals.TerminalMapping, - terminalMappingViewClass: InputTerminalMappingView, - terminalForInput: function(input) { +export class InputCollectionTerminalView extends BaseInputTerminalView { + constructor(options = {}) { + super(options, { + terminalMappingViewClass: InputTerminalMappingView, + terminalMappingClass: Terminals.TerminalMapping + }); + } + terminalForInput(input = {}) { return new Terminals.InputCollectionTerminal({ element: this.el, input: input }); } -}); +} -var BaseOutputTerminalView = TerminalView.extend({ - className: "terminal output-terminal", - initialize: function(options) { +export class BaseOutputTerminalView extends TerminalView { + constructor(options, classes = {}) { + super(); + this.terminalMappingViewClass = classes.terminalMappingViewClass; + this.terminalMappingClass = classes.terminalMappingClass; + this.el = document.createElement("div"); + this.el.className = "terminal output-terminal"; + this.$el = $(this.el); const node = options.node; const output = options.output; const name = output.name; @@ -224,35 +248,31 @@ var BaseOutputTerminalView = TerminalView.extend({ terminal.name = name; terminal.label = output.label; node.output_terminals[name] = terminal; - }, - events: { - drag: "onDrag", - dragstart: "onDragStart", - dragend: "onDragEnd", - keydown: "screenReaderSelectOutputNode" - }, - screenReaderSelectOutputNode: function(e) { + const self = this; + this.$el.on("drag", (d, e) => self.onDrag(d, e)); + this.$el.on("dragstart", (d, e) => self.onDragStart(d, e)); + this.$el.on("dragend", (d, e) => self.onDragEnd(d, e)); + this.$el.on("keydown", e => self.screenReaderSelectOutputNode(e)); + } + screenReaderSelectOutputNode(e) { const inputChoiceKeyDown = e => { e.stopPropagation(); const currentItem = e.currentTarget; const previousItem = currentItem.previousSibling; const nextItem = currentItem.nextSibling; const inputTerminal = currentItem.input.context.terminal; - const switchActiveItem = (currentActive, newActive) => { newActive.classList.add("active"); newActive.focus(); currentActive.classList.remove("active"); }; - const removeMenu = () => { $(currentItem.parentNode).remove(); this.$el.removeAttr("aria-owns"); this.$el.attr("aria-grabbed", "false"); this.$el.focus(); }; - switch (e.keyCode) { case 40: // Down arrow if (nextItem) { @@ -341,8 +361,8 @@ var BaseOutputTerminalView = TerminalView.extend({ ariaAlert("Node selected"); buildInputChoicesMenu(); } - }, - onDrag: function(e, d) { + } + onDrag(e, d = {}) { var onmove = () => { // FIXME: global var canvasZoom = window.workflow_globals.canvas_manager.canvasZoom; @@ -361,8 +381,8 @@ var BaseOutputTerminalView = TerminalView.extend({ $("#canvas-container") .get(0) .scroll_panel.test(e, onmove); - }, - onDragStart: function(e, d) { + } + onDragStart(e, d = {}) { $(d.available).addClass("input-terminal-active"); // Save PJAs in the case of change datatype actions. window.workflow_globals.workflow.check_changes_in_active_form(); @@ -384,8 +404,8 @@ var BaseOutputTerminalView = TerminalView.extend({ c.dragging = true; c.connect(this.el.terminal, h.terminal); return h; - }, - onDragEnd: function(e, d) { + } + onDragEnd(e, d = {}) { var connector = d.proxy.terminal.connectors[0]; // check_changes_in_active_form may change the state and cause a // the connection to have already been destroyed. There must be better @@ -401,12 +421,16 @@ var BaseOutputTerminalView = TerminalView.extend({ .get(0) .scroll_panel.stop(); } -}); +} -var OutputTerminalView = BaseOutputTerminalView.extend({ - terminalMappingClass: Terminals.TerminalMapping, - terminalMappingViewClass: TerminalMappingView, - terminalForOutput: function(output) { +export class OutputTerminalView extends BaseOutputTerminalView { + constructor(options = {}) { + super(options, { + terminalMappingViewClass: TerminalMappingView, + terminalMappingClass: Terminals.TerminalMapping + }); + } + terminalForOutput(output) { var type = output.extensions; return new Terminals.OutputTerminal({ element: this.el, @@ -415,12 +439,16 @@ var OutputTerminalView = BaseOutputTerminalView.extend({ optional: output.optional }); } -}); +} -var OutputCollectionTerminalView = BaseOutputTerminalView.extend({ - terminalMappingClass: Terminals.TerminalMapping, - terminalMappingViewClass: TerminalMappingView, - terminalForOutput: function(output) { +export class OutputCollectionTerminalView extends BaseOutputTerminalView { + constructor(options = {}) { + super(options, { + terminalMappingViewClass: TerminalMappingView, + terminalMappingClass: Terminals.TerminalMapping + }); + } + terminalForOutput(output) { var collection_type = output.collection_type; var collection_type_source = output.collection_type_source; return new Terminals.OutputCollectionTerminal({ @@ -432,19 +460,23 @@ var OutputCollectionTerminalView = BaseOutputTerminalView.extend({ optional: output.optional }); } -}); +} -var OutputParameterTerminalView = BaseOutputTerminalView.extend({ - terminalMappingClass: Terminals.TerminalMapping, - terminalMappingViewClass: TerminalMappingView, - terminalForOutput: function(output) { +export class OutputParameterTerminalView extends BaseOutputTerminalView { + constructor(options = {}) { + super(options, { + terminalMappingViewClass: TerminalMappingView, + terminalMappingClass: Terminals.TerminalMapping + }); + } + terminalForOutput(output) { return new Terminals.OutputParameterTerminal({ element: this.el, type: output.type, optional: output.optional }); } -}); +} export default { InputTerminalView: InputTerminalView, From 63ba70261fb2d56f5d646ea3e4ab5e64521789c3 Mon Sep 17 00:00:00 2001 From: guerler Date: Sun, 9 Feb 2020 13:30:14 -0500 Subject: [PATCH 02/62] Move prebuild helper from workflow view to workflow manager --- .../scripts/mvc/workflow/workflow-manager.js | 73 ++++++++++++++++++- .../scripts/mvc/workflow/workflow-node.js | 14 ++-- .../scripts/mvc/workflow/workflow-view.js | 70 ------------------ .../qunit/tests/workflow_editor_tests.js | 11 ++- 4 files changed, 85 insertions(+), 83 deletions(-) diff --git a/client/galaxy/scripts/mvc/workflow/workflow-manager.js b/client/galaxy/scripts/mvc/workflow/workflow-manager.js index e4669722671..419c4ff9104 100644 --- a/client/galaxy/scripts/mvc/workflow/workflow-manager.js +++ b/client/galaxy/scripts/mvc/workflow/workflow-manager.js @@ -1,6 +1,8 @@ import $ from "jquery"; import Connector from "mvc/workflow/workflow-connector"; import { Toast } from "ui/toast"; +import { Node } from "mvc/workflow/workflow-node"; +import { mountWorkflowNode } from "components/Workflow/Editor/mount"; class Workflow { constructor(app, canvas_container) { @@ -59,7 +61,7 @@ class Workflow { return true; } create_node(type, title_text, content_id) { - var node = this.app.prebuildNode(type, title_text, content_id); + var node = this.prebuildNode(type, title_text, content_id); this.add_node(node); this.fit_canvas_to_nodes(); this.app.canvas_manager.draw_overview(); @@ -75,6 +77,73 @@ class Workflow { this.has_changes = true; node.workflow = this; } + prebuildNode(type, title_text, content_id) { + var self = this; + + // Create node wrapper + const container = document.createElement("div"); + container.className = "toolForm toolFormInCanvas"; + document.getElementById("canvas-container").appendChild(container); + var $f = $(container); + + // Create backbone model and view + var node = new Node(this, { element: $f }); + node.type = type; + node.content_id = content_id; + + // Mount node component as child dom to node wrapper + const child = document.createElement("div"); + container.appendChild(child); + mountWorkflowNode(child, { + id: content_id, + type: type, + title: title_text, + node: node + }); + + // Set initial scroll position + $f.css("left", $(window).scrollLeft() + 20); + $f.css("top", $(window).scrollTop() + 20); + + // Position in container + var o = $("#canvas-container").position(); + var p = $("#canvas-container").parent(); + var width = $f.outerWidth() + 50; + var height = $f.height(); + $f.css({ + left: -o.left + p.width() / 2 - width / 2, + top: -o.top + p.height() / 2 - height / 2 + }); + $f.css("width", width); + $f.bind("dragstart", () => { + self.workflow.activate_node(node); + }) + .bind("dragend", function() { + self.workflow.node_changed(this); + self.workflow.fit_canvas_to_nodes(); + self.canvas_manager.draw_overview(); + }) + .bind("dragclickonly", () => { + self.workflow.activate_node(node); + }) + .bind("drag", function(e, d) { + // Move + var po = $(this) + .offsetParent() + .offset(); + // Find relative offset and scale by zoom + var x = (d.offsetX - po.left) / self.canvas_manager.canvasZoom; + var y = (d.offsetY - po.top) / self.canvas_manager.canvasZoom; + $(this).css({ left: x, top: y }); + // Redraw + $(this) + .find(".terminal") + .each(function() { + this.terminal.redraw(); + }); + }); + return node; + } remove_node(node) { if (this.active_node == node) { this.clear_active_node(); @@ -220,7 +289,7 @@ class Workflow { wf.workflow_version = data.version; wf.report = data.report || {}; $.each(data.steps, (id, step) => { - var node = wf.app.prebuildNode(step.type, step.name, step.content_id); + var node = wf.prebuildNode(step.type, step.name, step.content_id); // If workflow being copied into another, wipe UUID and let // Galaxy assign new ones. if (!initialImport) { diff --git a/client/galaxy/scripts/mvc/workflow/workflow-node.js b/client/galaxy/scripts/mvc/workflow/workflow-node.js index 60144d4077d..c7cc3ca407b 100644 --- a/client/galaxy/scripts/mvc/workflow/workflow-node.js +++ b/client/galaxy/scripts/mvc/workflow/workflow-node.js @@ -54,7 +54,7 @@ export class Node { changed = this.addWorkflowOutput(outputName, label); } if (changed) { - this.app.workflow.updateOutputLabel(oldLabel, label); + this.app.updateOutputLabel(oldLabel, label); this.markChanged(); this.nodeView.redrawWorkflowOutputs(); } @@ -163,7 +163,7 @@ export class Node { annotation: this.annotation, post_job_actions: this.post_job_actions }; - var node = this.app.workflow.create_node(this.type, this.name, this.content_id); + var node = this.app.create_node(this.type, this.name, this.content_id); Utils.request({ type: "POST", @@ -177,7 +177,7 @@ export class Node { var newData = Object.assign({}, data, copiedData); node.init_field_data(newData); node.update_field_data(newData); - this.app.workflow.activate_node(node); + this.app.activate_node(node); } }); } @@ -188,7 +188,7 @@ export class Node { $.each(this.output_terminals, (k, t) => { t.destroy(); }); - this.app.workflow.remove_node(this); + this.app.remove_node(this); $(this.element).remove(); } make_active() { @@ -244,7 +244,7 @@ export class Node { nodeView.addDataOutput(output); }); nodeView.render(); - this.app.workflow.node_changed(this, true); + this.app.node_changed(this, true); } update_field_data(data) { var node = this; @@ -347,9 +347,9 @@ export class Node { var tmp = `
${text}
`; this.config_form = tmp; b.html(tmp); - this.app.workflow.node_changed(this); + this.app.node_changed(this); } markChanged() { - this.app.workflow.node_changed(this); + this.app.node_changed(this); } } diff --git a/client/galaxy/scripts/mvc/workflow/workflow-view.js b/client/galaxy/scripts/mvc/workflow/workflow-view.js index 9fb45f8e8e5..faa10b4263f 100644 --- a/client/galaxy/scripts/mvc/workflow/workflow-view.js +++ b/client/galaxy/scripts/mvc/workflow/workflow-view.js @@ -6,10 +6,8 @@ import _l from "utils/localization"; import Utils from "utils/utils"; import Workflow from "mvc/workflow/workflow-manager"; import WorkflowCanvas from "mvc/workflow/workflow-canvas"; -import { Node } from "mvc/workflow/workflow-node"; import WorkflowIcons from "mvc/workflow/workflow-icons"; import FormWrappers from "mvc/workflow/workflow-forms"; -import { mountWorkflowNode } from "components/Workflow/Editor/mount"; import "ui/editable-text"; import { hide_modal, show_message, show_modal } from "layout/modal"; @@ -545,72 +543,4 @@ export class WorkflowView { this.scroll_to_nodes(); this.canvas_manager.draw_overview(); } - - prebuildNode(type, title_text, content_id) { - var self = this; - - // Create node wrapper - const container = document.createElement("div"); - container.className = "toolForm toolFormInCanvas"; - document.getElementById("canvas-container").appendChild(container); - var $f = $(container); - - // Create backbone model and view - var node = new Node(this, { element: $f }); - node.type = type; - node.content_id = content_id; - - // Mount node component as child dom to node wrapper - const child = document.createElement("div"); - container.appendChild(child); - mountWorkflowNode(child, { - id: content_id, - type: type, - title: title_text, - node: node - }); - - // Set initial scroll position - $f.css("left", $(window).scrollLeft() + 20); - $f.css("top", $(window).scrollTop() + 20); - - // Position in container - var o = $("#canvas-container").position(); - var p = $("#canvas-container").parent(); - var width = $f.outerWidth() + 50; - var height = $f.height(); - $f.css({ - left: -o.left + p.width() / 2 - width / 2, - top: -o.top + p.height() / 2 - height / 2 - }); - $f.css("width", width); - $f.bind("dragstart", () => { - self.workflow.activate_node(node); - }) - .bind("dragend", function() { - self.workflow.node_changed(this); - self.workflow.fit_canvas_to_nodes(); - self.canvas_manager.draw_overview(); - }) - .bind("dragclickonly", () => { - self.workflow.activate_node(node); - }) - .bind("drag", function(e, d) { - // Move - var po = $(this) - .offsetParent() - .offset(); - // Find relative offset and scale by zoom - var x = (d.offsetX - po.left) / self.canvas_manager.canvasZoom; - var y = (d.offsetY - po.top) / self.canvas_manager.canvasZoom; - $(this).css({ left: x, top: y }); - // Redraw - $(this) - .find(".terminal") - .each(function() { - this.terminal.redraw(); - }); - }); - return node; - } } diff --git a/client/galaxy/scripts/qunit/tests/workflow_editor_tests.js b/client/galaxy/scripts/qunit/tests/workflow_editor_tests.js index 174927e008c..a404ff85339 100644 --- a/client/galaxy/scripts/qunit/tests/workflow_editor_tests.js +++ b/client/galaxy/scripts/qunit/tests/workflow_editor_tests.js @@ -38,7 +38,8 @@ var create_app = function() { QUnit.module("Input terminal model test", { beforeEach: function() { testApp.create(); - this.node = new Node(create_app(), {}); + var app = create_app(); + this.node = new Node(app.workflow, {}); this.input = { extensions: ["txt"], multiple: false, optional: false }; this.input_terminal = new Terminals.InputTerminal({ input: this.input }); this.input_terminal.node = this.node; @@ -286,7 +287,8 @@ QUnit.test("initial redraw", function(assert) { QUnit.module("Input collection terminal model test", { beforeEach: function() { testApp.create(); - this.node = new Node(create_app(), {}); + var app = create_app(); + this.node = new Node(app.workflow, {}); this.input = { extensions: ["txt"], collection_types: ["list"] }; this.input_terminal = new Terminals.InputCollectionTerminal({ input: this.input }); this.input_terminal.node = this.node; @@ -336,7 +338,7 @@ QUnit.module("Node unit test", { this.input_terminal = { destroy: sinon.spy(), redraw: sinon.spy() }; this.output_terminal = { destroy: sinon.spy(), redraw: sinon.spy() }; this.app = create_app(); - this.node = this.app.prebuildNode("tool", "newnode"); + this.node = this.app.workflow.prebuildNode("tool", "newnode"); this.element = this.node.element; this.node.input_terminals.i1 = this.input_terminal; this.node.output_terminals.o1 = this.output_terminal; @@ -924,7 +926,8 @@ QUnit.module("terminal mapping logic", { }, newNode: function() { var nodeEl = $("
")[0]; - return new Node(create_app(), { element: nodeEl }); + var app = create_app(); + return new Node(app.workflow, { element: nodeEl }); }, _addExistingOutput: function(terminal, output, connected) { var self = this; From 5f88ae6526a98d9fcd0ad518043d73337aaef79a Mon Sep 17 00:00:00 2001 From: guerler Date: Sun, 9 Feb 2020 13:46:45 -0500 Subject: [PATCH 03/62] Remove unused function from workflow view --- client/galaxy/scripts/mvc/workflow/workflow-view.js | 9 --------- 1 file changed, 9 deletions(-) diff --git a/client/galaxy/scripts/mvc/workflow/workflow-view.js b/client/galaxy/scripts/mvc/workflow/workflow-view.js index faa10b4263f..13de440b12b 100644 --- a/client/galaxy/scripts/mvc/workflow/workflow-view.js +++ b/client/galaxy/scripts/mvc/workflow/workflow-view.js @@ -348,15 +348,6 @@ export class WorkflowView { this._moduleInitAjax(node, { type: type, _: "true" }); } - display_file_list(node) { - var addlist = ""; - return addlist; - } - showWorkflowParameters() { var parameter_re = /\$\{.+?\}/g; var workflow_parameters = []; From e9bc82cbc16fc8280824aa72d468d2ee48a2f0a0 Mon Sep 17 00:00:00 2001 From: guerler Date: Sun, 9 Feb 2020 14:11:35 -0500 Subject: [PATCH 04/62] Reduce dependency of canvas manager from workflow view to workflow manager --- .../scripts/mvc/workflow/workflow-canvas.js | 12 +++--- .../scripts/mvc/workflow/workflow-manager.js | 43 ++++++++++++++++--- .../mvc/workflow/workflow-view-terminals.js | 10 ++--- .../scripts/mvc/workflow/workflow-view.js | 35 ++------------- 4 files changed, 51 insertions(+), 49 deletions(-) diff --git a/client/galaxy/scripts/mvc/workflow/workflow-canvas.js b/client/galaxy/scripts/mvc/workflow/workflow-canvas.js index 23d2366ca43..ab86d0fb36b 100644 --- a/client/galaxy/scripts/mvc/workflow/workflow-canvas.js +++ b/client/galaxy/scripts/mvc/workflow/workflow-canvas.js @@ -106,7 +106,7 @@ class CanvasManager { this.cv.css("width", `${100 / this.canvasZoom}%`); this.cv.css("height", `${100 / this.canvasZoom}%`); // Update canvas size - this.app.workflow.fit_canvas_to_nodes(); + this.app.fit_canvas_to_nodes(); } initZoomControls() { var zoomControl = $('
').css({ @@ -233,11 +233,11 @@ class CanvasManager { // If it appears that the user is trying to copy/paste text, we // pass that through. if (window.getSelection().toString() === "") { - if (this.app.workflow.active_node && this.app.workflow.active_node.type !== "subworkflow") { + if (this.app.active_node && this.app.active_node.type !== "subworkflow") { e.clipboardData.setData( "application/json", JSON.stringify({ - nodeId: this.app.workflow.active_node.id + nodeId: this.app.active_node.id }) ); } @@ -259,8 +259,8 @@ class CanvasManager { } catch (error) { console.debug(error); } - if (nodeId && Object.prototype.hasOwnProperty.call(this.app.workflow.nodes, nodeId)) { - this.app.workflow.nodes[nodeId].clone(); + if (nodeId && Object.prototype.hasOwnProperty.call(this.app.nodes, nodeId)) { + this.app.nodes[nodeId].clone(); } e.preventDefault(); } @@ -329,7 +329,7 @@ class CanvasManager { canvas_el.attr("width", o_w); canvas_el.attr("height", o_h); // Draw overview - $.each(this.app.workflow.nodes, (id, node) => { + $.each(this.app.nodes, (id, node) => { c.fillStyle = "gray"; var node_element = $(node.element); var position = node_element.position(); diff --git a/client/galaxy/scripts/mvc/workflow/workflow-manager.js b/client/galaxy/scripts/mvc/workflow/workflow-manager.js index 419c4ff9104..85f32b066f3 100644 --- a/client/galaxy/scripts/mvc/workflow/workflow-manager.js +++ b/client/galaxy/scripts/mvc/workflow/workflow-manager.js @@ -3,6 +3,7 @@ import Connector from "mvc/workflow/workflow-connector"; import { Toast } from "ui/toast"; import { Node } from "mvc/workflow/workflow-node"; import { mountWorkflowNode } from "components/Workflow/Editor/mount"; +import WorkflowCanvas from "mvc/workflow/workflow-canvas"; class Workflow { constructor(app, canvas_container) { @@ -15,6 +16,13 @@ class Workflow { this.active_form_has_changes = false; this.workflowOutputLabels = {}; this.workflow_version = 0; + + // Canvas overview management + this.canvas_manager = window.workflow_globals.canvas_manager = new WorkflowCanvas( + this, + $("#canvas-viewport"), + $("#overview") + ); } canLabelOutputWith(label) { if (label) { @@ -64,7 +72,7 @@ class Workflow { var node = this.prebuildNode(type, title_text, content_id); this.add_node(node); this.fit_canvas_to_nodes(); - this.app.canvas_manager.draw_overview(); + this.canvas_manager.draw_overview(); this.activate_node(node); return node; } @@ -116,15 +124,15 @@ class Workflow { }); $f.css("width", width); $f.bind("dragstart", () => { - self.workflow.activate_node(node); + self.activate_node(node); }) .bind("dragend", function() { - self.workflow.node_changed(this); - self.workflow.fit_canvas_to_nodes(); + self.node_changed(this); + self.fit_canvas_to_nodes(); self.canvas_manager.draw_overview(); }) .bind("dragclickonly", () => { - self.workflow.activate_node(node); + self.activate_node(node); }) .bind("drag", function(e, d) { // Move @@ -397,6 +405,29 @@ class Workflow { } this.app.showWorkflowParameters(); } + scroll_to_nodes() { + var cv = $("#canvas-viewport"); + var cc = $("#canvas-container"); + var top; + var left; + if (cc.width() < cv.width()) { + left = (cv.width() - cc.width()) / 2; + } else { + left = 0; + } + if (cc.height() < cv.height()) { + top = (cv.height() - cc.height()) / 2; + } else { + top = 0; + } + cc.css({ left: left, top: top }); + } + layout_auto() { + this.layout(); + this.fit_canvas_to_nodes(); + this.scroll_to_nodes(); + this.canvas_manager.draw_overview(); + } layout() { this.check_changes_in_active_form(); this.has_changes = true; @@ -508,7 +539,7 @@ class Workflow { return 0; } // Span of all elements - var canvasZoom = this.app.canvas_manager.canvasZoom; + var canvasZoom = this.canvas_manager.canvasZoom; var bounds = this.bounds_for_all_nodes(); var position = this.canvas_container.position(); var parent = this.canvas_container.parent(); diff --git a/client/galaxy/scripts/mvc/workflow/workflow-view-terminals.js b/client/galaxy/scripts/mvc/workflow/workflow-view-terminals.js index 242c76c9b0f..d740d4e1c42 100644 --- a/client/galaxy/scripts/mvc/workflow/workflow-view-terminals.js +++ b/client/galaxy/scripts/mvc/workflow/workflow-view-terminals.js @@ -195,7 +195,7 @@ export class InputParameterTerminalView extends BaseInputTerminalView { super(options, { terminalMappingViewClass: InputTerminalMappingView, terminalMappingClass: Terminals.TerminalMapping - }); + }); } terminalForInput(input) { return new Terminals.InputParameterTerminal({ @@ -210,7 +210,7 @@ export class InputCollectionTerminalView extends BaseInputTerminalView { super(options, { terminalMappingViewClass: InputTerminalMappingView, terminalMappingClass: Terminals.TerminalMapping - }); + }); } terminalForInput(input = {}) { return new Terminals.InputCollectionTerminal({ @@ -428,7 +428,7 @@ export class OutputTerminalView extends BaseOutputTerminalView { super(options, { terminalMappingViewClass: TerminalMappingView, terminalMappingClass: Terminals.TerminalMapping - }); + }); } terminalForOutput(output) { var type = output.extensions; @@ -446,7 +446,7 @@ export class OutputCollectionTerminalView extends BaseOutputTerminalView { super(options, { terminalMappingViewClass: TerminalMappingView, terminalMappingClass: Terminals.TerminalMapping - }); + }); } terminalForOutput(output) { var collection_type = output.collection_type; @@ -467,7 +467,7 @@ export class OutputParameterTerminalView extends BaseOutputTerminalView { super(options, { terminalMappingViewClass: TerminalMappingView, terminalMappingClass: Terminals.TerminalMapping - }); + }); } terminalForOutput(output) { return new Terminals.OutputParameterTerminal({ diff --git a/client/galaxy/scripts/mvc/workflow/workflow-view.js b/client/galaxy/scripts/mvc/workflow/workflow-view.js index 13de440b12b..083761ca2c0 100644 --- a/client/galaxy/scripts/mvc/workflow/workflow-view.js +++ b/client/galaxy/scripts/mvc/workflow/workflow-view.js @@ -5,7 +5,6 @@ import { getGalaxyInstance } from "app"; import _l from "utils/localization"; import Utils from "utils/utils"; import Workflow from "mvc/workflow/workflow-manager"; -import WorkflowCanvas from "mvc/workflow/workflow-canvas"; import WorkflowIcons from "mvc/workflow/workflow-icons"; import FormWrappers from "mvc/workflow/workflow-forms"; import "ui/editable-text"; @@ -40,13 +39,6 @@ export class WorkflowView { this.options = options; this.reportsEditor = reportsEditor; - // Canvas overview management - this.canvas_manager = window.workflow_globals.canvas_manager = new WorkflowCanvas( - this, - $("#canvas-viewport"), - $("#overview") - ); - // Initialize workflow state this.reset(); @@ -134,8 +126,8 @@ export class WorkflowView { self.reportsEditor.input = markdown; self.workflow.has_changes = false; self.workflow.fit_canvas_to_nodes(); - self.scroll_to_nodes(); - self.canvas_manager.draw_overview(); + self.workflow.scroll_to_nodes(); + self.workflow.canvas_manager.draw_overview(); self.build_version_select(); // Determine if any parameters were 'upgraded' and provide message @@ -269,24 +261,6 @@ export class WorkflowView { this.workflow = window.workflow_globals.workflow = new Workflow(this, $("#canvas-container")); } - scroll_to_nodes() { - var cv = $("#canvas-viewport"); - var cc = $("#canvas-container"); - var top; - var left; - if (cc.width() < cv.width()) { - left = (cv.width() - cc.width()) / 2; - } else { - left = 0; - } - if (cc.height() < cv.height()) { - top = (cv.height() - cc.height()) / 2; - } else { - top = 0; - } - cc.css({ left: left, top: top }); - } - _workflowLoadAjax(workflowId, version, options) { $.ajax( Utils.merge(options, { @@ -529,9 +503,6 @@ export class WorkflowView { } layout_editor() { - this.workflow.layout(); - this.workflow.fit_canvas_to_nodes(); - this.scroll_to_nodes(); - this.canvas_manager.draw_overview(); + this.workflow.layout_auto(); } } From 428fc639555163e8c6936c4d4350ef3509d000e8 Mon Sep 17 00:00:00 2001 From: guerler Date: Sun, 9 Feb 2020 14:44:02 -0500 Subject: [PATCH 05/62] Remove workflow globals from terminal view --- .../scripts/mvc/workflow/workflow-node.js | 2 +- .../mvc/workflow/workflow-view-node.js | 5 ++-- .../mvc/workflow/workflow-view-terminals.js | 28 ++++++++----------- .../qunit/tests/workflow_editor_tests.js | 4 +-- 4 files changed, 18 insertions(+), 21 deletions(-) diff --git a/client/galaxy/scripts/mvc/workflow/workflow-node.js b/client/galaxy/scripts/mvc/workflow/workflow-node.js index c7cc3ca407b..7ef6bd89360 100644 --- a/client/galaxy/scripts/mvc/workflow/workflow-node.js +++ b/client/galaxy/scripts/mvc/workflow/workflow-node.js @@ -228,7 +228,7 @@ export class Node { this.uuid = data.uuid; this.workflow_outputs = data.workflow_outputs ? data.workflow_outputs : []; var node = this; - var nodeView = new NodeView({ + var nodeView = new NodeView(this.app, { $el: this.element, node: node }); diff --git a/client/galaxy/scripts/mvc/workflow/workflow-view-node.js b/client/galaxy/scripts/mvc/workflow/workflow-view-node.js index b6a62eaee5a..f08feb30def 100644 --- a/client/galaxy/scripts/mvc/workflow/workflow-view-node.js +++ b/client/galaxy/scripts/mvc/workflow/workflow-view-node.js @@ -4,7 +4,8 @@ import TerminalViews from "mvc/workflow/workflow-view-terminals"; import { DataInputView, DataOutputView, ParameterOutputView } from "mvc/workflow/workflow-view-data"; export class NodeView { - constructor(options) { + constructor(app, options) { + this.app = app; this.$el = options.$el; this.node = options.node; this.output_width = Math.max(150, this.$el.width()); @@ -91,7 +92,7 @@ export class NodeView { } else if (output.parameter) { terminalViewClass = TerminalViews.OutputParameterTerminalView; } - return new terminalViewClass({ + return new terminalViewClass(this.app, { node: this.node, output: output }); diff --git a/client/galaxy/scripts/mvc/workflow/workflow-view-terminals.js b/client/galaxy/scripts/mvc/workflow/workflow-view-terminals.js index d740d4e1c42..5b5b70c04e9 100644 --- a/client/galaxy/scripts/mvc/workflow/workflow-view-terminals.js +++ b/client/galaxy/scripts/mvc/workflow/workflow-view-terminals.js @@ -4,9 +4,6 @@ import Terminals from "mvc/workflow/workflow-terminals"; import Connector from "mvc/workflow/workflow-connector"; import ariaAlert from "utils/ariaAlert"; -// TODO; tie into Galaxy state? -window.workflow_globals = window.workflow_globals || {}; - class TerminalMappingView { constructor(options = {}) { this.$el = $("
"); @@ -221,8 +218,9 @@ export class InputCollectionTerminalView extends BaseInputTerminalView { } export class BaseOutputTerminalView extends TerminalView { - constructor(options, classes = {}) { + constructor(app, options, classes = {}) { super(); + this.app = app; this.terminalMappingViewClass = classes.terminalMappingViewClass; this.terminalMappingClass = classes.terminalMappingClass; this.el = document.createElement("div"); @@ -364,8 +362,7 @@ export class BaseOutputTerminalView extends TerminalView { } onDrag(e, d = {}) { var onmove = () => { - // FIXME: global - var canvasZoom = window.workflow_globals.canvas_manager.canvasZoom; + var canvasZoom = this.app.canvas_manager.canvasZoom; var po = $(d.proxy) .offsetParent() .offset(); @@ -374,8 +371,7 @@ export class BaseOutputTerminalView extends TerminalView { var y = d.offsetY - po.top; $(d.proxy).css({ left: x / canvasZoom, top: y / canvasZoom }); d.proxy.terminal.redraw(); - // FIXME: global - window.workflow_globals.canvas_manager.update_viewport_overlay(); + this.app.canvas_manager.update_viewport_overlay(); }; onmove(); $("#canvas-container") @@ -385,7 +381,7 @@ export class BaseOutputTerminalView extends TerminalView { onDragStart(e, d = {}) { $(d.available).addClass("input-terminal-active"); // Save PJAs in the case of change datatype actions. - window.workflow_globals.workflow.check_changes_in_active_form(); + this.app.check_changes_in_active_form(); // Drag proxy div var h = $("
") .appendTo("#canvas-container") @@ -424,8 +420,8 @@ export class BaseOutputTerminalView extends TerminalView { } export class OutputTerminalView extends BaseOutputTerminalView { - constructor(options = {}) { - super(options, { + constructor(app, options = {}) { + super(app, options, { terminalMappingViewClass: TerminalMappingView, terminalMappingClass: Terminals.TerminalMapping }); @@ -442,8 +438,8 @@ export class OutputTerminalView extends BaseOutputTerminalView { } export class OutputCollectionTerminalView extends BaseOutputTerminalView { - constructor(options = {}) { - super(options, { + constructor(app, options = {}) { + super(app, options, { terminalMappingViewClass: TerminalMappingView, terminalMappingClass: Terminals.TerminalMapping }); @@ -463,8 +459,8 @@ export class OutputCollectionTerminalView extends BaseOutputTerminalView { } export class OutputParameterTerminalView extends BaseOutputTerminalView { - constructor(options = {}) { - super(options, { + constructor(app, options = {}) { + super(app, options, { terminalMappingViewClass: TerminalMappingView, terminalMappingClass: Terminals.TerminalMapping }); @@ -481,8 +477,8 @@ export class OutputParameterTerminalView extends BaseOutputTerminalView { export default { InputTerminalView: InputTerminalView, InputParameterTerminalView: InputParameterTerminalView, + InputCollectionTerminalView: InputCollectionTerminalView, OutputTerminalView: OutputTerminalView, OutputParameterTerminalView: OutputParameterTerminalView, - InputCollectionTerminalView: InputCollectionTerminalView, OutputCollectionTerminalView: OutputCollectionTerminalView }; diff --git a/client/galaxy/scripts/qunit/tests/workflow_editor_tests.js b/client/galaxy/scripts/qunit/tests/workflow_editor_tests.js index a404ff85339..12e63e32491 100644 --- a/client/galaxy/scripts/qunit/tests/workflow_editor_tests.js +++ b/client/galaxy/scripts/qunit/tests/workflow_editor_tests.js @@ -552,7 +552,7 @@ QUnit.module("Node view ", { }, set_for_node: function(node) { var element = $("
"); - this.view = new NodeView({ node: node, $el: element }); + this.view = new NodeView({}, { node: node, $el: element }); }, connectAttachedTerminal: function(inputType, outputType) { this.view.addDataInput({ name: "TestName", extensions: [inputType] }); @@ -726,7 +726,7 @@ QUnit.module("Output terminal view", { beforeEach: function() { this.node = { output_terminals: [] }; this.output = { name: "o1", extensions: "txt" }; - this.view = new TerminalsView.OutputTerminalView({ + this.view = new TerminalsView.OutputTerminalView({}, { node: this.node, output: this.output }); From 2395979226d5e14e77907e83134ff92d8e056adc Mon Sep 17 00:00:00 2001 From: guerler Date: Sun, 9 Feb 2020 15:03:28 -0500 Subject: [PATCH 06/62] Remove global workflow object dependency from data input view handlers --- .../galaxy/scripts/mvc/workflow/workflow-canvas.js | 6 +++--- .../scripts/mvc/workflow/workflow-view-data.js | 14 +++++++------- .../scripts/mvc/workflow/workflow-view-node.js | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/client/galaxy/scripts/mvc/workflow/workflow-canvas.js b/client/galaxy/scripts/mvc/workflow/workflow-canvas.js index ab86d0fb36b..ac1e81bcf5a 100644 --- a/client/galaxy/scripts/mvc/workflow/workflow-canvas.js +++ b/client/galaxy/scripts/mvc/workflow/workflow-canvas.js @@ -179,7 +179,7 @@ class CanvasManager { move((d.offsetX + x_adjust) / this.canvasZoom, (d.offsetY + y_adjust) / this.canvasZoom); }) .bind("dragend", () => { - self.app.workflow.fit_canvas_to_nodes(); + self.app.fit_canvas_to_nodes(); self.draw_overview(); }); this.overview.click(e => { @@ -193,7 +193,7 @@ class CanvasManager { var new_x_offset = e.pageX - self.oc.offset().left - self.ov.width() / 2; var new_y_offset = e.pageY - self.oc.offset().top - self.ov.height() / 2; move(-((new_x_offset / o_w) * in_w), -((new_y_offset / o_h) * in_h)); - self.app.workflow.fit_canvas_to_nodes(); + self.app.fit_canvas_to_nodes(); self.draw_overview(); } }); @@ -210,7 +210,7 @@ class CanvasManager { }) .bind("dragend", () => { self.overview.addClass("blockaclick"); - self.app.workflow.fit_canvas_to_nodes(); + self.app.fit_canvas_to_nodes(); self.draw_overview(); }); // Dragging for overview border (resize) diff --git a/client/galaxy/scripts/mvc/workflow/workflow-view-data.js b/client/galaxy/scripts/mvc/workflow/workflow-view-data.js index bf2931d46e5..6b52a335ac6 100644 --- a/client/galaxy/scripts/mvc/workflow/workflow-view-data.js +++ b/client/galaxy/scripts/mvc/workflow/workflow-view-data.js @@ -31,7 +31,7 @@ export class DataInputView { } export class DataOutputView { - constructor(options = {}) { + constructor(app, options = {}) { this.$el = $("
"); this.output = options.output; this.terminalElement = options.terminalElement; @@ -46,7 +46,7 @@ export class DataOutputView { this.$el.html(label); this.calloutView = null; if (["tool", "subworkflow"].indexOf(node.type) >= 0) { - const calloutView = new OutputCalloutView({ + const calloutView = new OutputCalloutView(app, { label: label, output: output, node: node @@ -79,7 +79,7 @@ export class DataOutputView { } export class ParameterOutputView { - constructor(options = {}) { + constructor(app, options = {}) { this.$el = $("
"); this.output = options.output; this.terminalElement = options.terminalElement; @@ -90,7 +90,7 @@ export class ParameterOutputView { this.$el.html(label); this.calloutView = null; if (["tool", "subworkflow"].indexOf(node.type) >= 0) { - const calloutView = new OutputCalloutView({ + const calloutView = new OutputCalloutView(app, { label: label, output: output, node: node @@ -123,7 +123,7 @@ export class ParameterOutputView { } export class OutputCalloutView { - constructor(options = {}) { + constructor(app, options = {}) { this.$el = $("
"); this.label = options.label; this.node = options.node; @@ -143,8 +143,8 @@ export class OutputCalloutView { node.addWorkflowOutput(outputName); view.$("icon").addClass("mark-terminal-active"); } - window.workflow_globals.workflow.has_changes = true; - window.workflow_globals.canvas_manager.draw_overview(); + app.has_changes = true; + app.canvas_manager.draw_overview(); }) ) .tooltip({ diff --git a/client/galaxy/scripts/mvc/workflow/workflow-view-node.js b/client/galaxy/scripts/mvc/workflow/workflow-view-node.js index f08feb30def..94f743bdea6 100644 --- a/client/galaxy/scripts/mvc/workflow/workflow-view-node.js +++ b/client/galaxy/scripts/mvc/workflow/workflow-view-node.js @@ -100,7 +100,7 @@ export class NodeView { outputViewforOutput(output, terminalView) { const outputViewClass = output.parameter ? ParameterOutputView : DataOutputView; - return new outputViewClass({ + return new outputViewClass(this.app, { output: output, terminalElement: terminalView.el, nodeView: this From 8e2849b71bf00a4b3b6449230373e75a2cbf13dd Mon Sep 17 00:00:00 2001 From: guerler Date: Sun, 9 Feb 2020 15:26:46 -0500 Subject: [PATCH 07/62] Remove global use in connector, parse canvas manager instead --- .../mvc/workflow/workflow-connector.js | 5 +- .../scripts/mvc/workflow/workflow-manager.js | 2 +- .../mvc/workflow/workflow-view-node.js | 2 +- .../mvc/workflow/workflow-view-terminals.js | 21 ++++---- .../qunit/tests/workflow_editor_tests.js | 48 +++++++++++-------- 5 files changed, 43 insertions(+), 35 deletions(-) diff --git a/client/galaxy/scripts/mvc/workflow/workflow-connector.js b/client/galaxy/scripts/mvc/workflow/workflow-connector.js index f3cd1628d2f..ce27a81d186 100644 --- a/client/galaxy/scripts/mvc/workflow/workflow-connector.js +++ b/client/galaxy/scripts/mvc/workflow/workflow-connector.js @@ -2,7 +2,8 @@ import $ from "jquery"; import { Toast } from "ui/toast"; -function Connector(handle1, handle2) { +function Connector(manager, handle1, handle2) { + this.manager = manager; this.canvas = null; this.dragging = false; this.inner_color = "#FFFFFF"; @@ -47,7 +48,7 @@ $.extend(Connector.prototype, { const canvasClass = `${startRibbon ? "start-ribbon" : ""} ${endRibbon ? "end-ribbon" : ""}`; var canvas_container = $("#canvas-container"); // FIXME: global - var canvasZoom = window.workflow_globals.canvas_manager.canvasZoom; + var canvasZoom = this.manager.canvasZoom; if (!this.canvas) { this.canvas = document.createElement("canvas"); canvas_container.append($(this.canvas)); diff --git a/client/galaxy/scripts/mvc/workflow/workflow-manager.js b/client/galaxy/scripts/mvc/workflow/workflow-manager.js index 85f32b066f3..5bb40026764 100644 --- a/client/galaxy/scripts/mvc/workflow/workflow-manager.js +++ b/client/galaxy/scripts/mvc/workflow/workflow-manager.js @@ -343,7 +343,7 @@ class Workflow { } $.each(v, (l, x) => { var other_node = wf.nodes[parseInt(x.id) + offset]; - var c = new Connector(); + var c = new Connector(this.canvas_manager); c.connect(other_node.output_terminals[x.output_name], node.input_terminals[k]); c.redraw(); }); diff --git a/client/galaxy/scripts/mvc/workflow/workflow-view-node.js b/client/galaxy/scripts/mvc/workflow/workflow-view-node.js index 94f743bdea6..f876ce1278c 100644 --- a/client/galaxy/scripts/mvc/workflow/workflow-view-node.js +++ b/client/galaxy/scripts/mvc/workflow/workflow-view-node.js @@ -63,7 +63,7 @@ export class NodeView { terminalView = null; } if (!terminalView) { - terminalView = new terminalViewClass({ + terminalView = new terminalViewClass(this.app, { node: this.node, input: input }); diff --git a/client/galaxy/scripts/mvc/workflow/workflow-view-terminals.js b/client/galaxy/scripts/mvc/workflow/workflow-view-terminals.js index a3e0f8b6eb3..d7308770b29 100644 --- a/client/galaxy/scripts/mvc/workflow/workflow-view-terminals.js +++ b/client/galaxy/scripts/mvc/workflow/workflow-view-terminals.js @@ -72,8 +72,9 @@ class TerminalView { } class BaseInputTerminalView extends TerminalView { - constructor(options = {}, classes = {}) { + constructor(app, options = {}, classes = {}) { super(); + this.app = app; this.terminalMappingViewClass = classes.terminalMappingViewClass; this.terminalMappingClass = classes.terminalMappingClass; this.el = document.createElement("div"); @@ -147,7 +148,7 @@ class BaseInputTerminalView extends TerminalView { d.proxy.dropTooltip = ""; if (this.$el.hasClass("can-accept")) { const terminal = this.el.terminal; - new Connector(d.drag.terminal, terminal).redraw(); + new Connector(this.app.canvas_manager, d.drag.terminal, terminal).redraw(); } } onHover() { @@ -176,8 +177,8 @@ class BaseInputTerminalView extends TerminalView { } export class InputTerminalView extends BaseInputTerminalView { - constructor(options = {}) { - super(options, { + constructor(app, options = {}) { + super(app, options, { terminalMappingViewClass: InputTerminalMappingView, terminalMappingClass: Terminals.TerminalMapping }); @@ -191,8 +192,8 @@ export class InputTerminalView extends BaseInputTerminalView { } export class InputParameterTerminalView extends BaseInputTerminalView { - constructor(options = {}) { - super(options, { + constructor(app, options = {}) { + super(app, options, { terminalMappingViewClass: InputTerminalMappingView, terminalMappingClass: Terminals.TerminalMapping }); @@ -206,8 +207,8 @@ export class InputParameterTerminalView extends BaseInputTerminalView { } export class InputCollectionTerminalView extends BaseInputTerminalView { - constructor(options = {}) { - super(options, { + constructor(app, options = {}) { + super(app, options, { terminalMappingViewClass: InputTerminalMappingView, terminalMappingClass: Terminals.TerminalMapping }); @@ -292,7 +293,7 @@ export class BaseOutputTerminalView extends TerminalView { break; case 32: // Space removeMenu(); - new Connector(this.el.terminal, inputTerminal).redraw(); + new Connector(this.app.canvas_manager, this.el.terminal, inputTerminal).redraw(); ariaAlert("Node connected"); if (inputTerminal.connectors.length > 0) { @@ -400,7 +401,7 @@ export class BaseOutputTerminalView extends TerminalView { } }); h.terminal = new Terminals.OutputTerminal({ element: h }); - var c = new Connector(); + var c = new Connector(this.app.canvas_manager); c.dragging = true; c.connect(this.el.terminal, h.terminal); return h; diff --git a/client/galaxy/scripts/qunit/tests/workflow_editor_tests.js b/client/galaxy/scripts/qunit/tests/workflow_editor_tests.js index 12e63e32491..ac0a17769f7 100644 --- a/client/galaxy/scripts/qunit/tests/workflow_editor_tests.js +++ b/client/galaxy/scripts/qunit/tests/workflow_editor_tests.js @@ -55,7 +55,7 @@ QUnit.module("Input terminal model test", { test_connector: function() { var outputTerminal = new Terminals.OutputTerminal({ datatypes: ["input"] }); var inputTerminal = this.input_terminal; - return new Connector(outputTerminal, inputTerminal); + return new Connector({}, outputTerminal, inputTerminal); }, with_test_connector: function(f) { this.test_connector(); @@ -231,12 +231,12 @@ QUnit.module("Connector test", {}); QUnit.test("connects only if both valid handles", function(assert) { const input = { connect: sinon.spy() }; const output = { connect: sinon.spy() }; - new Connector(input, null); - new Connector(null, output); + new Connector({}, input, null); + new Connector({}, null, output); // Not attempts to connect... assert.ok(!input.connect.called); assert.ok(!output.connect.called); - new Connector(input, output); + new Connector({}, input, output); assert.ok(input.connect.called); assert.ok(output.connect.called); }); @@ -244,7 +244,7 @@ QUnit.test("connects only if both valid handles", function(assert) { QUnit.test("default attributes", function(assert) { const input = { connect: sinon.spy() }; const output = { connect: sinon.spy() }; - const connector = new Connector(input, output); + const connector = new Connector({}, input, output); assert.equal(connector.dragging, false); assert.equal(connector.canvas, null); assert.equal(connector.inner_color, "#FFFFFF"); @@ -254,7 +254,7 @@ QUnit.test("default attributes", function(assert) { QUnit.test("destroy", function(assert) { const input = { connect: sinon.spy(), disconnect: sinon.spy() }; const output = { connect: sinon.spy(), disconnect: sinon.spy() }; - const connector = new Connector(input, output); + const connector = new Connector({}, input, output); connector.destroy(); assert.ok(input.disconnect.called); assert.ok(output.disconnect.called); @@ -275,7 +275,7 @@ QUnit.test("initial redraw", function(assert) { return false; } }; - const connector = new Connector(input, output); + const connector = new Connector({}, input, output); const n = $("#canvas-container").find("canvas").length; connector.redraw(); // Ensure canvas gets set @@ -484,7 +484,7 @@ QUnit.test("update_field_data preserves connectors", function(assert) { // Call init with one input and output. this.init_field_data_simple(); - var connector = new Connector(); + var connector = new Connector({}); var old_input_terminal = node.input_terminals.input1; old_input_terminal.connectors.push(connector); @@ -573,7 +573,7 @@ QUnit.module("Node view ", { disableMapOver: function() {}, mapOver: Terminals.NULL_COLLECTION_TYPE_DESCRIPTION }; - return new Connector(outputTerminal, terminal); + return new Connector({}, outputTerminal, terminal); }, connectAttachedMultiInputTerminal: function(inputType, outputType) { this.view.addDataInput({ name: "TestName", extensions: [inputType], multiple: true }); @@ -594,7 +594,7 @@ QUnit.module("Node view ", { disableMapOver: function() {}, mapOver: new Terminals.CollectionTypeDescription("list") }; - return new Connector(outputTerminal, terminal); + return new Connector({}, outputTerminal, terminal); }, connectAttachedMappedOutput: function() { this.view.addDataInput({ name: "TestName", extensions: ["txt"], input_type: "dataset_collection" }); @@ -615,7 +615,7 @@ QUnit.module("Node view ", { disableMapOver: function() {}, mapOver: new Terminals.CollectionTypeDescription("list") }; - return new Connector(outputTerminal, terminal); + return new Connector({}, outputTerminal, terminal); } }); @@ -703,10 +703,13 @@ QUnit.module("Input terminal view", { beforeEach: function() { this.node = { input_terminals: [] }; this.input = { name: "i1", extensions: "txt", multiple: false }; - this.view = new TerminalsView.InputTerminalView({ - node: this.node, - input: this.input - }); + this.view = new TerminalsView.InputTerminalView( + {}, + { + node: this.node, + input: this.input + } + ); } }); @@ -726,10 +729,13 @@ QUnit.module("Output terminal view", { beforeEach: function() { this.node = { output_terminals: [] }; this.output = { name: "o1", extensions: "txt" }; - this.view = new TerminalsView.OutputTerminalView({}, { - node: this.node, - output: this.output - }); + this.view = new TerminalsView.OutputTerminalView( + {}, + { + node: this.node, + output: this.output + } + ); } }); @@ -934,7 +940,7 @@ QUnit.module("terminal mapping logic", { var node = terminal.node; if (connected) { var inputTerminal = self.newInputTerminal(); - new Connector(inputTerminal, output); + new Connector({}, inputTerminal, output); } this._addTerminalTo(output, node.output_terminals); return output; @@ -959,7 +965,7 @@ QUnit.module("terminal mapping logic", { var connectedInput = this.newInputTerminal(); var node = terminal.node; var outputTerminal = self.newOutputTerminal(); - new Connector(connectedInput, outputTerminal); + new Connector({}, connectedInput, outputTerminal); this._addTerminalTo(connectedInput, node.input_terminals); return connectedInput; }, From a825c614f0196b3b6a45914763fb32122247acbb Mon Sep 17 00:00:00 2001 From: guerler Date: Sun, 9 Feb 2020 17:49:52 -0500 Subject: [PATCH 08/62] Remove globals from subtype testing, move to workflow manager --- .../scripts/mvc/workflow/workflow-manager.js | 5 ++++ .../mvc/workflow/workflow-terminals.js | 3 +- .../mvc/workflow/workflow-view-terminals.js | 4 ++- .../scripts/mvc/workflow/workflow-view.js | 12 ++------ .../qunit/tests/workflow_editor_tests.js | 30 ++++++++++++------- 5 files changed, 32 insertions(+), 22 deletions(-) diff --git a/client/galaxy/scripts/mvc/workflow/workflow-manager.js b/client/galaxy/scripts/mvc/workflow/workflow-manager.js index 5bb40026764..26f0cfd7367 100644 --- a/client/galaxy/scripts/mvc/workflow/workflow-manager.js +++ b/client/galaxy/scripts/mvc/workflow/workflow-manager.js @@ -24,6 +24,11 @@ class Workflow { $("#overview") ); } + isSubType(child, parent) { + child = this.app.ext_to_type[child]; + parent = this.app.ext_to_type[parent]; + return this.app.type_to_type[child] && parent in this.app.type_to_type[child]; + } canLabelOutputWith(label) { if (label) { return !(label in this.workflowOutputLabels); diff --git a/client/galaxy/scripts/mvc/workflow/workflow-terminals.js b/client/galaxy/scripts/mvc/workflow/workflow-terminals.js index 9099fcd2c02..f0ea830f134 100644 --- a/client/galaxy/scripts/mvc/workflow/workflow-terminals.js +++ b/client/galaxy/scripts/mvc/workflow/workflow-terminals.js @@ -255,6 +255,7 @@ var OutputTerminal = Terminal.extend({ var BaseInputTerminal = Terminal.extend({ initialize: function(attr) { Terminal.prototype.initialize.call(this, attr); + this.app = attr.app; this.update(attr.input); // subclasses should implement this... }, canAccept: function(other) { @@ -366,7 +367,7 @@ var BaseInputTerminal = Terminal.extend({ if ( other_datatype == "input" || other_datatype == "_sniff_" || - window.workflow_globals.app.isSubType(cat_outputs[other_datatype_i], thisDatatype) + this.app.isSubType(cat_outputs[other_datatype_i], thisDatatype) ) { return new ConnectionAcceptable(true, null); } diff --git a/client/galaxy/scripts/mvc/workflow/workflow-view-terminals.js b/client/galaxy/scripts/mvc/workflow/workflow-view-terminals.js index d7308770b29..484c210b966 100644 --- a/client/galaxy/scripts/mvc/workflow/workflow-view-terminals.js +++ b/client/galaxy/scripts/mvc/workflow/workflow-view-terminals.js @@ -51,7 +51,6 @@ export class InputTerminalMappingView extends TerminalMappingView { class TerminalView { setupMappingView(terminal) { - console.log(this.terminalMappingClass); var terminalMapping = new this.terminalMappingClass({ terminal: terminal }); @@ -185,6 +184,7 @@ export class InputTerminalView extends BaseInputTerminalView { } terminalForInput(input) { return new Terminals.InputTerminal({ + app: this.app, element: this.el, input: input }); @@ -200,6 +200,7 @@ export class InputParameterTerminalView extends BaseInputTerminalView { } terminalForInput(input) { return new Terminals.InputParameterTerminal({ + app: this.app, element: this.el, input: input }); @@ -215,6 +216,7 @@ export class InputCollectionTerminalView extends BaseInputTerminalView { } terminalForInput(input = {}) { return new Terminals.InputCollectionTerminal({ + app: this.app, element: this.el, input: input }); diff --git a/client/galaxy/scripts/mvc/workflow/workflow-view.js b/client/galaxy/scripts/mvc/workflow/workflow-view.js index 083761ca2c0..f312b9caaaa 100644 --- a/client/galaxy/scripts/mvc/workflow/workflow-view.js +++ b/client/galaxy/scripts/mvc/workflow/workflow-view.js @@ -39,9 +39,6 @@ export class WorkflowView { this.options = options; this.reportsEditor = reportsEditor; - // Initialize workflow state - this.reset(); - // get available datatypes for post job action options this.datatypes = JSON.parse( $.ajax({ @@ -62,6 +59,9 @@ export class WorkflowView { this.ext_to_type = this.datatypes_mapping.ext_to_class_name; this.type_to_type = this.datatypes_mapping.class_to_classes; + // Initialize workflow state + this.reset(); + this.get_workflow_versions = function() { const _workflow_version_dropdown = {}; const workflow_versions = JSON.parse( @@ -405,12 +405,6 @@ export class WorkflowView { $container.scrollTop(); } - isSubType(child, parent) { - child = this.ext_to_type[child]; - parent = this.ext_to_type[parent]; - return this.type_to_type[child] && parent in this.type_to_type[child]; - } - report_changed(report_markdown) { this.workflow.has_changes = true; this.workflow.report.markdown = report_markdown; diff --git a/client/galaxy/scripts/qunit/tests/workflow_editor_tests.js b/client/galaxy/scripts/qunit/tests/workflow_editor_tests.js index ac0a17769f7..70a522793b4 100644 --- a/client/galaxy/scripts/qunit/tests/workflow_editor_tests.js +++ b/client/galaxy/scripts/qunit/tests/workflow_editor_tests.js @@ -38,10 +38,10 @@ var create_app = function() { QUnit.module("Input terminal model test", { beforeEach: function() { testApp.create(); - var app = create_app(); - this.node = new Node(app.workflow, {}); + this.app = create_app(); + this.node = new Node(this.app.workflow, {}); this.input = { extensions: ["txt"], multiple: false, optional: false }; - this.input_terminal = new Terminals.InputTerminal({ input: this.input }); + this.input_terminal = new Terminals.InputTerminal({ app: this.app.workflow, input: this.input }); this.input_terminal.node = this.node; }, afterEach: function() { @@ -287,10 +287,10 @@ QUnit.test("initial redraw", function(assert) { QUnit.module("Input collection terminal model test", { beforeEach: function() { testApp.create(); - var app = create_app(); - this.node = new Node(app.workflow, {}); + this.app = create_app(); + this.node = new Node(this.app.workflow, {}); this.input = { extensions: ["txt"], collection_types: ["list"] }; - this.input_terminal = new Terminals.InputCollectionTerminal({ input: this.input }); + this.input_terminal = new Terminals.InputCollectionTerminal({ app: this.app.workflow, input: this.input }); this.input_terminal.node = this.node; }, afterEach: function() { @@ -538,6 +538,8 @@ QUnit.test("node added to workflow", function(assert) { // global NodeView QUnit.module("Node view ", { beforeEach: function() { + testApp.create(); + this.app = create_app(); this.set_for_node({ input_terminals: {}, output_terminals: {}, @@ -552,7 +554,7 @@ QUnit.module("Node view ", { }, set_for_node: function(node) { var element = $("
"); - this.view = new NodeView({}, { node: node, $el: element }); + this.view = new NodeView(this.app.workflow, { node: node, $el: element }); }, connectAttachedTerminal: function(inputType, outputType) { this.view.addDataInput({ name: "TestName", extensions: [inputType] }); @@ -701,10 +703,12 @@ QUnit.test("replacing terminal on data collection input with simple input change // global InputTerminalView QUnit.module("Input terminal view", { beforeEach: function() { + testApp.create(); + this.app = create_app(); this.node = { input_terminals: [] }; this.input = { name: "i1", extensions: "txt", multiple: false }; this.view = new TerminalsView.InputTerminalView( - {}, + this.app.workflow, { node: this.node, input: this.input @@ -727,10 +731,12 @@ QUnit.test("terminal element", function(assert) { QUnit.module("Output terminal view", { beforeEach: function() { + testApp.create(); + this.app = create_app(); this.node = { output_terminals: [] }; this.output = { name: "o1", extensions: "txt" }; this.view = new TerminalsView.OutputTerminalView( - {}, + this.app.workflow, { node: this.node, output: this.output @@ -875,7 +881,8 @@ QUnit.module("terminal mapping logic", { input["extensions"] = ["data"]; } var inputEl = $("
")[0]; - var inputTerminal = new Terminals.InputTerminal({ element: inputEl, input: input }); + const app = create_app(); + var inputTerminal = new Terminals.InputTerminal({ app: app.workflow, element: inputEl, input: input }); var inputTerminalMapping = new Terminals.TerminalMapping({ terminal: inputTerminal }); inputTerminal.node = node; if (mapOver) { @@ -890,7 +897,8 @@ QUnit.module("terminal mapping logic", { input["extensions"] = ["data"]; } const inputEl = $("
")[0]; - const inputTerminal = new Terminals.InputCollectionTerminal({ element: inputEl, input: input }); + const app = create_app(); + const inputTerminal = new Terminals.InputCollectionTerminal({ app: app.workflow, element: inputEl, input: input }); new Terminals.TerminalMapping({ terminal: inputTerminal }); inputTerminal.node = node; return inputTerminal; From 92fd49892d32d3393abb9a1300c709009a3c7139 Mon Sep 17 00:00:00 2001 From: guerler Date: Sun, 9 Feb 2020 19:08:58 -0500 Subject: [PATCH 09/62] Move Workflow components from mako to mount helper --- client/galaxy/scripts/bundleEntries.js | 3 +- .../galaxy/scripts/components/Panels/mount.js | 31 ---------------- .../components/Workflow/Editor/mount.js | 36 ++++++++++++++----- templates/webapps/galaxy/workflow/editor.mako | 2 -- 4 files changed, 29 insertions(+), 43 deletions(-) delete mode 100644 client/galaxy/scripts/components/Panels/mount.js 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/mount.js b/client/galaxy/scripts/components/Panels/mount.js deleted file mode 100644 index d3f92f69607..00000000000 --- a/client/galaxy/scripts/components/Panels/mount.js +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Endpoint for mounting Panel components - */ -import Vue from "vue"; -import _l from "utils/localization"; -import SidePanel from "./SidePanel"; -import ToolBoxWorkflow from "./ToolBoxWorkflow"; - -export const mountToolBoxWorkflow = options => { - const component = Vue.extend(SidePanel); - return new component({ - propsData: { - side: "left", - currentPanel: ToolBoxWorkflow, - currentPanelProperties: { - toolbox: options.toolbox, - workflowGlobals: options.workflow_globals, - moduleSections: options.module_sections, - dataManagers: { - name: _l("Data Managers"), - elems: options.data_managers - }, - workflowSection: { - name: _l("Workflows"), - elems: options.workflows - } - } - }, - el: "#left" - }); -}; diff --git a/client/galaxy/scripts/components/Workflow/Editor/mount.js b/client/galaxy/scripts/components/Workflow/Editor/mount.js index 19eb6fb00fb..4e397540591 100644 --- a/client/galaxy/scripts/components/Workflow/Editor/mount.js +++ b/client/galaxy/scripts/components/Workflow/Editor/mount.js @@ -6,23 +6,43 @@ import SidePanel from "components/Panels/SidePanel"; import Index from "./Index"; import Node from "./Node"; import WorkflowPanel from "./WorkflowPanel"; +import ToolBoxWorkflow from "components/Panels/ToolBoxWorkflow"; +import _l from "utils/localization"; export const mountWorkflowEditor = editorConfig => { const propsData = { editorConfig }; - const component = Vue.extend(Index); - return new component({ propsData: propsData, el: "#center" }); -}; - -export const mountWorkflowPanel = propsData => { - const component = Vue.extend(SidePanel); - return new component({ + const rightPanel = Vue.extend(SidePanel); + new rightPanel({ propsData: { side: "right", currentPanel: WorkflowPanel, - currentPanelProperties: propsData + currentPanelProperties: editorConfig }, el: "#right" }); + const leftPanel = Vue.extend(SidePanel); + new leftPanel({ + propsData: { + side: "left", + currentPanel: ToolBoxWorkflow, + currentPanelProperties: { + toolbox: editorConfig.toolbox, + workflowGlobals: editorConfig.workflow_globals, + moduleSections: editorConfig.module_sections, + dataManagers: { + name: _l("Data Managers"), + elems: editorConfig.data_managers + }, + workflowSection: { + name: _l("Workflows"), + elems: editorConfig.workflows + } + } + }, + el: "#left" + }); + const component = Vue.extend(Index); + return new component({ propsData: propsData, el: "#center" }); }; export const mountWorkflowNode = (container, propsData) => { diff --git a/templates/webapps/galaxy/workflow/editor.mako b/templates/webapps/galaxy/workflow/editor.mako index b623b14d152..758f7ec7762 100644 --- a/templates/webapps/galaxy/workflow/editor.mako +++ b/templates/webapps/galaxy/workflow/editor.mako @@ -19,8 +19,6 @@ config.addInitialization(function(galaxy, config) { console.log("workflow/editor.mako, editorConfig", editorConfig); window.bundleEntries.mountWorkflowEditor(editorConfig); - window.bundleEntries.mountToolBoxWorkflow(editorConfig); - window.bundleEntries.mountWorkflowPanel(editorConfig); }); From 1425f6b93e6febeb1288e589cde6b53e71861676 Mon Sep 17 00:00:00 2001 From: guerler Date: Sun, 9 Feb 2020 19:29:40 -0500 Subject: [PATCH 10/62] Explicitly parse attributes to right workflow panel --- .../scripts/components/Workflow/Editor/mount.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/client/galaxy/scripts/components/Workflow/Editor/mount.js b/client/galaxy/scripts/components/Workflow/Editor/mount.js index 4e397540591..fee3dfb0c44 100644 --- a/client/galaxy/scripts/components/Workflow/Editor/mount.js +++ b/client/galaxy/scripts/components/Workflow/Editor/mount.js @@ -10,13 +10,17 @@ import ToolBoxWorkflow from "components/Panels/ToolBoxWorkflow"; import _l from "utils/localization"; export const mountWorkflowEditor = editorConfig => { - const propsData = { editorConfig }; const rightPanel = Vue.extend(SidePanel); new rightPanel({ propsData: { side: "right", currentPanel: WorkflowPanel, - currentPanelProperties: editorConfig + currentPanelProperties: { + id: editorConfig.id, + name: editorConfig.name, + tags: editorConfig.tags, + annotation: editorConfig.annotation + } }, el: "#right" }); @@ -42,7 +46,9 @@ export const mountWorkflowEditor = editorConfig => { el: "#left" }); const component = Vue.extend(Index); - return new component({ propsData: propsData, el: "#center" }); + return new component({ propsData: { + editorConfig + }, el: "#center" }); }; export const mountWorkflowNode = (container, propsData) => { From c1efddb08c6d289551d839574c1dd2e59010f6fe Mon Sep 17 00:00:00 2001 From: guerler Date: Sun, 9 Feb 2020 19:48:16 -0500 Subject: [PATCH 11/62] Move workflowpanel into index --- .../components/Workflow/Editor/Index.vue | 22 ++++++++++++++++++- .../components/Workflow/Editor/mount.js | 15 ------------- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/client/galaxy/scripts/components/Workflow/Editor/Index.vue b/client/galaxy/scripts/components/Workflow/Editor/Index.vue index dbf04825155..3d6ea05ae28 100644 --- a/client/galaxy/scripts/components/Workflow/Editor/Index.vue +++ b/client/galaxy/scripts/components/Workflow/Editor/Index.vue @@ -1,5 +1,10 @@