Merge pull request #9332 from guerler/workflow_editor_node

Replacing Workflow Editor Node with Vue-component
This commit is contained in:
John Chilton
2020-02-10 09:08:05 -05:00
committed by GitHub
10 changed files with 271 additions and 243 deletions
@@ -44,7 +44,7 @@
</template>
<script>
import WorkflowView from "mvc/workflow/workflow-view";
import { WorkflowView } from "mvc/workflow/workflow-view";
import WorkflowOptions from "./Options";
import MarkdownEditor from "components/Markdown/MarkdownEditor";
import { getAppRoot } from "onload/loadConfig";
@@ -0,0 +1,72 @@
<template>
<div>
<div class="toolFormTitle unselectable clearfix">
<i :class="iconClass" />
<span class="nodeTitle">{{ title }}</span>
<span class="sr-only">&nbsp;Node</span>
<div class="buttons float-right">
<a
v-if="canClone"
class="fa-icon-button fa fa-files-o node-clone"
aria-label="clone node"
role="button"
href="#"
@click="onClone"
/>
<a
class="fa-icon-button fa fa-times node-destroy"
aria-label="destroy node"
role="button"
href="#"
@click="onDestroy"
/>
</div>
</div>
<div class="toolFormBody">
<div><span class="fa fa-spinner fa-spin" /> Loading details...</div>
</div>
</div>
</template>
<script>
import WorkflowIcons from "mvc/workflow/workflow-icons";
export default {
props: {
id: {
type: String
},
title: {
type: String,
default: "title"
},
type: {
type: String,
default: "tool"
},
node: {
type: Object
}
},
computed: {
iconClass() {
const iconType = WorkflowIcons[this.type];
if (iconType) {
return `icon fa ${iconType}`;
}
return null;
},
canClone() {
return this.type != "subworkflow";
}
},
methods: {
onDestroy() {
this.node.destroy();
},
onClone() {
this.node.clone();
}
}
};
</script>
@@ -4,6 +4,7 @@
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 => {
@@ -23,3 +24,8 @@ export const mountWorkflowPanel = propsData => {
el: "#right"
});
};
export const mountWorkflowNode = (container, propsData) => {
const component = Vue.extend(Node);
return new component({ propsData: propsData, el: container });
};
@@ -277,8 +277,7 @@ class Workflow {
$.each(node.output_terminals, (ot_id, ot) => {
if (node.post_job_actions[`HideDatasetAction${ot.name}`] === undefined) {
node.addWorkflowOutput(ot.name);
var callout = $(node.element).find(`.callout-terminal.${ot.name.replace(/(?=[()])/g, "\\")}`);
callout.find("icon").addClass("mark-terminal-active");
node.markWorkflowOutput(ot.name);
wf.has_changes = true;
}
});
@@ -1,37 +1,33 @@
import _ from "underscore";
import $ from "jquery";
import Backbone from "backbone";
import { getAppRoot } from "onload/loadConfig";
import Utils from "utils/utils";
import NodeView from "mvc/workflow/workflow-view-node";
import { NodeView } from "./workflow-view-node";
// unused
//var StepParameterTypes = ["text", "integer", "float", "boolean", "color"];
var Node = Backbone.Model.extend({
initialize: function(app, attr) {
export class Node {
constructor(app, attr = {}) {
this.app = app;
this.element = attr.element;
this.input_terminals = {};
this.output_terminals = {};
this.errors = {};
this.workflow_outputs = [];
},
getWorkflowOutput: function(outputName) {
}
getWorkflowOutput(outputName) {
return _.findWhere(this.workflow_outputs, {
output_name: outputName
});
},
isWorkflowOutput: function(outputName) {
}
isWorkflowOutput(outputName) {
return this.getWorkflowOutput(outputName) !== undefined;
},
removeWorkflowOutput: function(outputName) {
}
removeWorkflowOutput(outputName) {
while (this.isWorkflowOutput(outputName)) {
const target = this.getWorkflowOutput(outputName);
this.workflow_outputs.splice(_.indexOf(this.workflow_outputs, target), 1);
}
},
addWorkflowOutput: function(outputName, label) {
}
addWorkflowOutput(outputName, label) {
if (!this.isWorkflowOutput(outputName)) {
var output = { output_name: outputName };
if (label) {
@@ -41,8 +37,12 @@ var Node = Backbone.Model.extend({
return true;
}
return false;
},
labelWorkflowOutput: function(outputName, label) {
}
markWorkflowOutput(outputName) {
var callout = $(this.element).find(`.callout-terminal.${outputName.replace(/(?=[()])/g, "\\")}`);
callout.find("icon").addClass("mark-terminal-active");
}
labelWorkflowOutput(outputName, label) {
var changed = false;
var oldLabel = null;
if (this.isWorkflowOutput(outputName)) {
@@ -59,8 +59,8 @@ var Node = Backbone.Model.extend({
this.nodeView.redrawWorkflowOutputs();
}
return changed;
},
changeOutputDatatype: function(outputName, datatype) {
}
changeOutputDatatype(outputName, datatype) {
const output_terminal = this.output_terminals[outputName];
const output = this.nodeView.outputViews[outputName].output;
output_terminal.force_datatype = datatype;
@@ -76,11 +76,11 @@ var Node = Backbone.Model.extend({
}
this.markChanged();
output_terminal.destroyInvalidConnections();
},
connectedOutputTerminals: function() {
}
connectedOutputTerminals() {
return this._connectedTerminals(this.output_terminals);
},
_connectedTerminals: function(terminals) {
}
_connectedTerminals(terminals) {
var connectedTerminals = [];
$.each(terminals, (_, t) => {
if (t.connectors.length > 0) {
@@ -88,8 +88,8 @@ var Node = Backbone.Model.extend({
}
});
return connectedTerminals;
},
hasConnectedOutputTerminals: function() {
}
hasConnectedOutputTerminals() {
// return this.connectedOutputTerminals().length > 0; <- optimized this
var outputTerminals = this.output_terminals;
for (var outputName in outputTerminals) {
@@ -98,11 +98,11 @@ var Node = Backbone.Model.extend({
}
}
return false;
},
connectedMappedInputTerminals: function() {
}
connectedMappedInputTerminals() {
return this._connectedMappedTerminals(this.input_terminals);
},
hasConnectedMappedInputTerminals: function() {
}
hasConnectedMappedInputTerminals() {
// return this.connectedMappedInputTerminals().length > 0; <- optimized this
var inputTerminals = this.input_terminals;
for (var inputName in inputTerminals) {
@@ -112,8 +112,8 @@ var Node = Backbone.Model.extend({
}
}
return false;
},
_connectedMappedTerminals: function(terminals) {
}
_connectedMappedTerminals(terminals) {
var mapped_outputs = [];
$.each(terminals, (_, t) => {
var mapOver = t.mapOver();
@@ -124,11 +124,11 @@ var Node = Backbone.Model.extend({
}
});
return mapped_outputs;
},
mappedInputTerminals: function() {
}
mappedInputTerminals() {
return this._mappedTerminals(this.input_terminals);
},
_mappedTerminals: function(terminals) {
}
_mappedTerminals(terminals) {
var mappedTerminals = [];
$.each(terminals, (_, t) => {
var mapOver = t.mapOver();
@@ -137,8 +137,8 @@ var Node = Backbone.Model.extend({
}
});
return mappedTerminals;
},
hasMappedOverInputTerminals: function() {
}
hasMappedOverInputTerminals() {
var found = false;
_.each(this.input_terminals, t => {
var mapOver = t.mapOver();
@@ -147,16 +147,16 @@ var Node = Backbone.Model.extend({
}
});
return found;
},
redraw: function() {
}
redraw() {
$.each(this.input_terminals, (_, t) => {
t.redraw();
});
$.each(this.output_terminals, (_, t) => {
t.redraw();
});
},
clone: function() {
}
clone() {
var copiedData = {
name: this.name,
label: this.label,
@@ -180,8 +180,8 @@ var Node = Backbone.Model.extend({
this.app.workflow.activate_node(node);
}
});
},
destroy: function() {
}
destroy() {
$.each(this.input_terminals, (k, t) => {
t.destroy();
});
@@ -190,11 +190,11 @@ var Node = Backbone.Model.extend({
});
this.app.workflow.remove_node(this);
$(this.element).remove();
},
make_active: function() {
}
make_active() {
$(this.element).addClass("toolForm-active");
},
make_inactive: function() {
}
make_inactive() {
// Keep inactive nodes stacked from most to least recently active
// by moving element to the end of parent's node list
var element = this.element.get(0);
@@ -204,15 +204,14 @@ var Node = Backbone.Model.extend({
})(element.parentNode);
// Remove active class
$(element).removeClass("toolForm-active");
},
set_tool_version: function() {
}
set_tool_version() {
if (this.type === "tool" && this.config_form) {
this.tool_version = this.config_form.version;
this.content_id = this.config_form.id;
}
},
init_field_data: function(data) {
}
init_field_data(data) {
//console.debug("init_field_data: ", data);
if (data.type) {
this.type = data.type;
@@ -230,7 +229,7 @@ var Node = Backbone.Model.extend({
this.workflow_outputs = data.workflow_outputs ? data.workflow_outputs : [];
var node = this;
var nodeView = new NodeView({
el: this.element[0],
$el: this.element,
node: node
});
node.nodeView = nodeView;
@@ -246,8 +245,8 @@ var Node = Backbone.Model.extend({
});
nodeView.render();
this.app.workflow.node_changed(this, true);
},
update_field_data: function(data) {
}
update_field_data(data) {
var node = this;
var nodeView = node.nodeView;
// remove unused output views and remove pre-existing output views from data.outputs,
@@ -269,7 +268,6 @@ var Node = Backbone.Model.extend({
unused_outputs.push(cur_name);
}
});
// Remove the unused outputs
_.each(unused_outputs, unused_output => {
_.each(nodeView.outputViews[unused_output].terminalElement.terminal.connectors, x => {
@@ -314,7 +312,7 @@ var Node = Backbone.Model.extend({
}
node.nodeView.renderToolErrors();
// Update input rows
var old_body = nodeView.$("div.inputs");
var old_body = nodeView.$el.find("div.inputs");
var new_body = nodeView.newInputsDiv();
var newTerminalViews = {};
_.each(data.inputs, input => {
@@ -342,17 +340,16 @@ var Node = Backbone.Model.extend({
// If active, reactivate with new config_form
this.markChanged();
this.redraw();
},
error: function(text) {
}
error(text) {
var b = $(this.element).find(".toolFormBody");
b.find("div").remove();
var tmp = `<div style='color: red; text-style: italic;'>${text}</div>`;
this.config_form = tmp;
b.html(tmp);
this.app.workflow.node_changed(this);
},
markChanged: function() {
}
markChanged() {
this.app.workflow.node_changed(this);
}
});
export default Node;
}
@@ -1,20 +1,15 @@
import $ from "jquery";
import Backbone from "backbone";
// import { getAppRoot } from "onload/loadConfig";
// TODO; tie into Galaxy state?
window.workflow_globals = window.workflow_globals || {};
const DataInputView = Backbone.View.extend({
className: "form-row dataRow input-data-row",
initialize: function(options) {
export class DataInputView {
constructor(options = {}) {
this.input = options.input;
this.nodeView = options.nodeView;
this.terminalElement = options.terminalElement;
this.$el = $("<div class='form-row dataRow input-data-row'/>");
this.$el.attr("name", this.input.name).html(this.input.label || this.input.name);
if (!options.skipResize) {
this.$el.css({
position: "absolute",
@@ -33,20 +28,17 @@ const DataInputView = Backbone.View.extend({
this.$el.remove();
}
}
});
}
const DataOutputView = Backbone.View.extend({
className: "form-row dataRow",
initialize: function(options) {
export class DataOutputView {
constructor(options = {}) {
this.$el = $("<div class='form-row dataRow'/>");
this.output = options.output;
this.terminalElement = options.terminalElement;
this.nodeView = options.nodeView;
const output = this.output;
let label = output.label || output.name;
const node = this.nodeView.node;
const isInput = output.extensions.indexOf("input") >= 0;
if (!isInput) {
label = `${label} (${output.force_datatype || output.extensions.join(", ")})`;
@@ -78,26 +70,23 @@ const DataOutputView = Backbone.View.extend({
display: ""
})
.detach();
},
redrawWorkflowOutput: function() {
}
redrawWorkflowOutput() {
if (this.calloutView) {
this.calloutView.resetImage();
}
}
});
}
const ParameterOutputView = Backbone.View.extend({
className: "form-row dataRow",
initialize: function(options) {
export class ParameterOutputView {
constructor(options = {}) {
this.$el = $("<div class='form-row dataRow'/>");
this.output = options.output;
this.terminalElement = options.terminalElement;
this.nodeView = options.nodeView;
const output = this.output;
const label = output.label || output.name;
const node = this.nodeView.node;
this.$el.html(label);
this.calloutView = null;
if (["tool", "subworkflow"].indexOf(node.type) >= 0) {
@@ -125,18 +114,17 @@ const ParameterOutputView = Backbone.View.extend({
display: ""
})
.detach();
},
redrawWorkflowOutput: function() {
}
redrawWorkflowOutput() {
if (this.calloutView) {
this.calloutView.resetImage();
}
}
});
}
const OutputCalloutView = Backbone.View.extend({
tagName: "div",
initialize: function(options) {
export class OutputCalloutView {
constructor(options = {}) {
this.$el = $("<div/>");
this.label = options.label;
this.node = options.node;
this.output = options.output;
@@ -171,19 +159,12 @@ const OutputCalloutView = Backbone.View.extend({
});
this.$el.show();
this.resetImage();
},
resetImage: function() {
}
resetImage() {
if (!this.node.isWorkflowOutput(this.output.name)) {
this.$("icon").removeClass("mark-terminal-active");
this.$el.find("icon").removeClass("mark-terminal-active");
} else {
this.$("icon").addClass("mark-terminal-active");
this.$el.find("icon").addClass("mark-terminal-active");
}
}
});
export default {
DataInputView: DataInputView,
DataOutputView: DataOutputView,
ParameterOutputView: ParameterOutputView
};
}
@@ -1,11 +1,11 @@
import $ from "jquery";
import _ from "libs/underscore";
import Backbone from "backbone";
import TerminalViews from "mvc/workflow/workflow-view-terminals";
import DataViews from "mvc/workflow/workflow-view-data";
import { DataInputView, DataOutputView, ParameterOutputView } from "mvc/workflow/workflow-view-data";
export default Backbone.View.extend({
initialize: function(options) {
export class NodeView {
constructor(options) {
this.$el = options.$el;
this.node = options.node;
this.output_width = Math.max(150, this.$el.width());
this.tool_body = this.$el.find(".toolFormBody");
@@ -13,39 +13,39 @@ export default Backbone.View.extend({
this.newInputsDiv().appendTo(this.tool_body);
this.terminalViews = {};
this.outputViews = {};
},
}
render: function() {
render() {
this.renderToolLabel();
this.renderToolErrors();
this.$el.css("width", Math.min(250, Math.max(this.$el.width(), this.output_width)));
},
}
renderToolLabel: function() {
this.$(".nodeTitle").text(this.node.label || this.node.name);
renderToolLabel() {
this.$el.find(".nodeTitle").text(this.node.label || this.node.name);
this.$el.attr("node-label", this.node.label);
},
}
renderToolErrors: function() {
renderToolErrors() {
this.node.errors ? this.$el.addClass("tool-node-error") : this.$el.removeClass("tool-node-error");
},
}
newInputsDiv: function() {
newInputsDiv() {
return $("<div/>").addClass("inputs");
},
}
updateMaxWidth: function(newWidth) {
updateMaxWidth(newWidth) {
this.output_width = Math.max(this.output_width, newWidth);
},
}
addRule: function() {
addRule() {
this.tool_body.append($("<div/>").addClass("rule"));
},
}
addDataInput: function(input, body) {
addDataInput(input, body) {
var skipResize = true;
if (!body) {
body = this.$(".inputs");
body = this.$el.find(".inputs");
// initial addition to node - resize input to help calculate node
// width.
skipResize = false;
@@ -73,7 +73,7 @@ export default Backbone.View.extend({
}
this.terminalViews[input.name] = terminalView;
var terminalElement = terminalView.el;
var inputView = new DataViews.DataInputView({
var inputView = new DataInputView({
terminalElement: terminalElement,
input: input,
nodeView: this,
@@ -82,9 +82,9 @@ export default Backbone.View.extend({
var ib = inputView.$el;
body.append(ib.prepend(terminalView.terminalElements()));
return terminalView;
},
}
terminalViewForOutput: function(output) {
terminalViewForOutput(output) {
let terminalViewClass = TerminalViews.OutputTerminalView;
if (output.collection) {
terminalViewClass = TerminalViews.OutputCollectionTerminalView;
@@ -95,32 +95,32 @@ export default Backbone.View.extend({
node: this.node,
output: output
});
},
}
outputViewforOutput: function(output, terminalView) {
const outputViewClass = output.parameter ? DataViews.ParameterOutputView : DataViews.DataOutputView;
outputViewforOutput(output, terminalView) {
const outputViewClass = output.parameter ? ParameterOutputView : DataOutputView;
return new outputViewClass({
output: output,
terminalElement: terminalView.el,
nodeView: this
});
},
}
addDataOutput: function(output) {
addDataOutput(output) {
const terminalView = this.terminalViewForOutput(output);
const outputView = this.outputViewforOutput(output, terminalView);
this.outputViews[output.name] = outputView;
this.tool_body.append(outputView.$el.append(terminalView.terminalElements()));
},
}
redrawWorkflowOutputs: function() {
redrawWorkflowOutputs() {
_.each(this.outputViews, outputView => {
outputView.redrawWorkflowOutput();
});
},
}
updateDataOutput: function(output) {
updateDataOutput(output) {
var outputTerminal = this.node.output_terminals[output.name];
outputTerminal.update(output);
}
});
}
@@ -7,6 +7,7 @@ import ariaAlert from "utils/ariaAlert";
// TODO; tie into Galaxy state?
window.workflow_globals = window.workflow_globals || {};
var NODEINDEX = 0;
var TerminalMappingView = Backbone.View.extend({
tagName: "div",
@@ -76,6 +77,7 @@ var BaseInputTerminalView = TerminalView.extend({
const node = options.node;
const input = options.input;
const name = input.name;
node.cid = NODEINDEX++;
const id = `node-${node.cid}-input-${name}`;
const terminal = this.terminalForInput(input);
this.setupMappingView(terminal);
@@ -207,6 +209,7 @@ var BaseOutputTerminalView = TerminalView.extend({
const node = options.node;
const output = options.output;
const name = output.name;
node.cid = NODEINDEX++;
const id = `node-${node.cid}-output-${name}`;
const terminal = this.terminalForOutput(output);
this.setupMappingView(terminal);
@@ -1,15 +1,15 @@
import _ from "underscore";
import $ from "jquery";
import Backbone from "backbone";
import { getAppRoot } from "onload/loadConfig";
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 Node from "mvc/workflow/workflow-node";
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";
@@ -36,17 +36,8 @@ workflow_display()
\`\`\`
`;
function add_node_icon($to_el, nodeType) {
var iconStyle = WorkflowIcons[nodeType];
if (iconStyle) {
var $icon = $('<i class="icon fa">&nbsp;</i>').addClass(iconStyle);
$to_el.before($icon);
}
}
// create form view
export default Backbone.View.extend({
initialize: function(options, reportsEditor) {
export class WorkflowView {
constructor(options, reportsEditor = {}) {
var self = (window.workflow_globals.app = this);
this.options = options;
this.reportsEditor = reportsEditor;
@@ -216,9 +207,9 @@ export default Backbone.View.extend({
return "There are unsaved changes to your workflow which will be lost.";
}
};
},
}
copy_into_workflow: function(id, stepCount = 0) {
copy_into_workflow(id = null, stepCount = null) {
const Galaxy = getGalaxyInstance();
if (stepCount < 2) {
this._copy_into_workflow_ajax(id);
@@ -239,9 +230,9 @@ export default Backbone.View.extend({
}
});
}
},
}
_copy_into_workflow_ajax: function(workflowId) {
_copy_into_workflow_ajax(workflowId) {
// Load workflow definition
var self = this;
this._workflowLoadAjax(workflowId, null, {
@@ -266,21 +257,21 @@ export default Backbone.View.extend({
hide_modal();
}
},
beforeSubmit: function(data) {
beforeSubmit: function() {
show_message("Importing workflow", "progress");
}
});
},
}
// Global state for the whole workflow
reset: function() {
reset() {
if (this.workflow) {
this.workflow.remove_all();
}
this.workflow = window.workflow_globals.workflow = new Workflow(this, $("#canvas-container"));
},
}
scroll_to_nodes: function() {
scroll_to_nodes() {
var cv = $("#canvas-viewport");
var cc = $("#canvas-container");
var top;
@@ -296,9 +287,9 @@ export default Backbone.View.extend({
top = 0;
}
cc.css({ left: left, top: top });
},
}
_workflowLoadAjax: function(workflowId, version, options) {
_workflowLoadAjax(workflowId, version, options) {
$.ajax(
Utils.merge(options, {
url: `${getAppRoot()}workflow/load_workflow`,
@@ -307,9 +298,9 @@ export default Backbone.View.extend({
cache: false
})
);
},
}
_moduleInitAjax: function(node, request_data) {
_moduleInitAjax(node, request_data) {
var self = this;
Utils.request({
type: "POST",
@@ -332,43 +323,43 @@ export default Backbone.View.extend({
self.workflow.activate_node(node);
}
});
},
}
// Add a new step to the workflow by tool id
add_node_for_tool: function(id, title) {
add_node_for_tool(id, title) {
var node = this.workflow.create_node("tool", title, id);
this._moduleInitAjax(node, {
type: "tool",
tool_id: id,
_: "true"
});
},
}
// Add a new step to the workflow by tool id
add_node_for_subworkflow: function(id, title) {
add_node_for_subworkflow(id, title) {
var node = this.workflow.create_node("subworkflow", title, id);
this._moduleInitAjax(node, {
type: "subworkflow",
content_id: id,
_: "true"
});
},
}
add_node_for_module: function(type, title) {
add_node_for_module(type, title) {
var node = this.workflow.create_node(type, title);
this._moduleInitAjax(node, { type: type, _: "true" });
},
}
display_file_list: function(node) {
display_file_list(node) {
var addlist = "<select id='node_data_list' name='node_data_list'>";
for (var out_terminal in node.output_terminals) {
addlist += `<option value='${out_terminal}'>${out_terminal}</option>`;
}
addlist += "</select>";
return addlist;
},
}
showWorkflowParameters: function() {
showWorkflowParameters() {
var parameter_re = /\$\{.+?\}/g;
var workflow_parameters = [];
var wf_parm_container = $("#workflow-parameters-container");
@@ -418,14 +409,14 @@ export default Backbone.View.extend({
wf_parm_container.html(new_parameter_content);
wf_parm_box.hide();
}
},
}
showAttributes: function() {
showAttributes() {
$(".right-content").hide();
$("#edit-attributes").show();
},
}
showForm: function(content, node) {
showForm(content, node) {
const cls = "right-content";
var id = `${cls}-${node.id}`;
var $container = $(`#${cls}`);
@@ -449,18 +440,18 @@ export default Backbone.View.extend({
$container.find(`#${id}`).show();
$container.show();
$container.scrollTop();
},
}
isSubType: function(child, parent) {
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;
},
}
save_current_workflow() {
const self = this;
@@ -507,9 +498,9 @@ export default Backbone.View.extend({
show_modal("Saving workflow failed.", response.err_msg, { Ok: hide_modal });
}
});
},
}
workflow_save_as: function() {
workflow_save_as() {
const self = this;
var body = $(
'<form><label style="display:inline-block; width: 100%;">Save as name: </label><input type="text" id="workflow_rename" style="width: 80%;" autofocus/>' +
@@ -546,73 +537,52 @@ export default Backbone.View.extend({
},
Cancel: hide_modal
});
},
}
layout_editor: function() {
layout_editor() {
this.workflow.layout();
this.workflow.fit_canvas_to_nodes();
this.scroll_to_nodes();
this.canvas_manager.draw_overview();
},
}
prebuildNode: function(type, title_text, content_id) {
prebuildNode(type, title_text, content_id) {
var self = this;
var $f = $(`<div class='toolForm toolFormInCanvas'/>`);
var $title = $(
`<div class='toolFormTitle unselectable'><span class='nodeTitle'>${title_text}</span><span class="sr-only">&nbspNode</span></div>`
);
add_node_icon($title.find(".nodeTitle"), type);
$f.append($title);
$f.css("left", $(window).scrollLeft() + 20);
$f.css("top", $(window).scrollTop() + 20);
$f.append($("<div class='toolFormBody'></div>"));
// 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;
var tmp = `<div><img alt="loading" height='16' align='middle' src='${getAppRoot()}static/images/loading_small_white_bg.gif'/> loading tool info...</div>`;
$f.find(".toolFormBody").append(tmp);
// Fix width to computed width
// Now add floats
var buttons = $("<div class='buttons' style='float: right;'></div>");
if (type !== "subworkflow") {
buttons.append(
$("<a/>")
.attr({
"aria-label": "clone node",
role: "button",
href: "javascript:void(0)"
})
.addClass("fa-icon-button fa fa-files-o node-clone")
.click(e => {
node.clone();
})
);
}
buttons.append(
$("<a/>")
.attr({
"aria-label": "destroy node",
role: "button",
href: "javascript:void(0)"
})
.addClass("fa-icon-button fa fa-times node-destroy")
.click(e => {
node.destroy();
})
);
// Place inside container
$f.appendTo("#canvas-container");
// 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.width();
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
});
buttons.appendTo($f.find(".toolFormTitle"));
width += buttons.width() + 10;
$f.css("width", width);
$f.bind("dragstart", () => {
self.workflow.activate_node(node);
@@ -643,4 +613,4 @@ export default Backbone.View.extend({
});
return node;
}
});
}
@@ -3,9 +3,9 @@ import $ from "jquery";
import testApp from "qunit/test-app";
import sinon from "sinon";
import Utils from "utils/utils";
import App from "mvc/workflow/workflow-view";
import Node from "mvc/workflow/workflow-node";
import NodeView from "mvc/workflow/workflow-view-node";
import { WorkflowView } from "mvc/workflow/workflow-view";
import { Node } from "mvc/workflow/workflow-node";
import { NodeView } from "mvc/workflow/workflow-view-node";
import Terminals from "mvc/workflow/workflow-terminals";
import TerminalsView from "mvc/workflow/workflow-view-terminals";
import Connector from "mvc/workflow/workflow-connector";
@@ -28,7 +28,7 @@ var create_app = function() {
);
// build app
return new App({
return new WorkflowView({
id: null,
urls: { get_datatypes: getAppRoot() + "api/datatypes/mapping" },
workflows: []
@@ -550,7 +550,7 @@ QUnit.module("Node view ", {
},
set_for_node: function(node) {
var element = $("<div><div class='toolFormBody'></div></div>");
this.view = new NodeView({ node: node, el: element[0] });
this.view = new NodeView({ node: node, $el: element });
},
connectAttachedTerminal: function(inputType, outputType) {
this.view.addDataInput({ name: "TestName", extensions: [inputType] });