mirror of
https://github.com/galaxyproject/galaxy.git
synced 2026-10-24 02:04:04 +08:00
Merge pull request #9332 from guerler/workflow_editor_node
Replacing Workflow Editor Node with Vue-component
This commit is contained in:
@@ -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"> 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"> </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"> Node</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] });
|
||||
|
||||
Reference in New Issue
Block a user