diff --git a/client/package.json b/client/package.json
index a1716135d2b..5e5d3a8af76 100644
--- a/client/package.json
+++ b/client/package.json
@@ -35,6 +35,7 @@
"@pinia/testing": "^0.0.14",
"@popperjs/core": "^2.11.5",
"@sentry/browser": "^6.17.4",
+ "@types/d3": "^7.4.0",
"@vue/runtime-dom": "^3.2.45",
"@vueuse/core": "https://github.com/mvdbeek/vueuse/releases/download/v9.3.0-useCapture/vueuse-core-v9.3.0.tgz",
"assert": "^2.0.0",
@@ -46,7 +47,7 @@
"citation-js": "^0.6.4",
"core-js": "^3.21.0",
"csv-parse": "^5.3.0",
- "d3": "3",
+ "d3": "^7.8.0",
"d3-zoom": "^3.0.0",
"date-fns": "^2.28.0",
"date-fns-tz": "^1.3.3",
diff --git a/client/src/components/ToolRecommendation.vue b/client/src/components/ToolRecommendation.vue
index f268ba82dff..5dac7555378 100644
--- a/client/src/components/ToolRecommendation.vue
+++ b/client/src/components/ToolRecommendation.vue
@@ -95,7 +95,7 @@ export default {
svgElem.setAttribute("viewBox", -translateX + " 0 " + 0.5 * clientW + " " + clientH);
svgElem.setAttribute("preserveAspectRatio", "xMidYMid meet");
- const tree = d3.layout.tree().size([clientH, clientW]);
+ const tree = d3.tree().size([clientH, clientW]);
const diagonal = d3.svg.diagonal().projection((d) => {
return [d.y, d.x];
});
diff --git a/client/src/components/Workflow/Editor/ConnectionMenu.vue b/client/src/components/Workflow/Editor/ConnectionMenu.vue
new file mode 100644
index 00000000000..97b8de0b989
--- /dev/null
+++ b/client/src/components/Workflow/Editor/ConnectionMenu.vue
@@ -0,0 +1,107 @@
+
+
+
+
diff --git a/client/src/components/Workflow/Editor/Connector.vue b/client/src/components/Workflow/Editor/Connector.vue
index e313706ea63..24f0fdb7e58 100644
--- a/client/src/components/Workflow/Editor/Connector.vue
+++ b/client/src/components/Workflow/Editor/Connector.vue
@@ -1,58 +1,72 @@
-
-
+
+
+
+
-
diff --git a/client/src/components/Workflow/Editor/Index.vue b/client/src/components/Workflow/Editor/Index.vue
index bf6b177ccc3..664572de148 100644
--- a/client/src/components/Workflow/Editor/Index.vue
+++ b/client/src/components/Workflow/Editor/Index.vue
@@ -206,7 +206,8 @@ import { useConnectionStore } from "@/stores/workflowConnectionStore";
import Vue from "vue";
import { ConfirmDialog } from "composables/confirmDialog";
-import { useWorkflowStepStore } from "stores/workflowStepStore";
+import { useWorkflowStepStore } from "@/stores/workflowStepStore";
+import { useWorkflowStateStore } from "@/stores/workflowEditorStateStore";
import { storeToRefs } from "pinia";
import { useDatatypesMapper } from "@/composables/datatypesMapper";
@@ -257,14 +258,20 @@ export default {
const connectionsStore = useConnectionStore();
const stepStore = useWorkflowStepStore();
const { getStepIndex, steps } = storeToRefs(stepStore);
+ const stateStore = useWorkflowStateStore();
+ const { nodes, activeNode, activeNodeId } = storeToRefs(stateStore);
return {
connectionsStore,
stepStore,
steps: steps,
nodeIndex: getStepIndex,
datatypes,
+ activeNode,
+ activeNodeId,
+ nodes,
datatypesMapper,
datatypesMapperLoading,
+ stateStore,
};
},
data() {
@@ -297,9 +304,6 @@ export default {
};
},
computed: {
- nodes() {
- return this.$store.getters["workflowState/getNodes"];
- },
showAttributes() {
return this.showInPanel == "attributes";
},
@@ -309,13 +313,6 @@ export default {
postJobActions() {
return this.activeNode.postJobActions;
},
- activeNode() {
- // TODO: replace usage of this with just data ?
- return this.nodes[this.activeNodeId];
- },
- activeNodeId() {
- return this.$store.getters["workflowState/getActiveNode"];
- },
activeNodeName() {
return this.activeNode?.name;
},
@@ -496,7 +493,7 @@ export default {
tool_state: JSON.parse(JSON.stringify(node.tool_state)),
post_job_actions: JSON.parse(JSON.stringify(node.postJobActions)),
});
- this.$store.commit("workflowState/setActiveNode", id);
+ this.stateStore.setActiveNode(id);
},
onInsertTool(tool_id, tool_name) {
this._insertStep(tool_id, tool_name, "tool");
@@ -569,11 +566,11 @@ export default {
},
onAttributes() {
this._ensureParametersSet();
- this.$store.commit("workflowState/setActiveNode", null);
+ this.stateStore.setActiveNode(null);
this.showInPanel = "attributes";
},
onWorkflowTextEditor() {
- this.$store.commit("workflowState/setActiveNode", null);
+ this.stateStore.setActiveNode(null);
this.showInPanel = "attributes";
},
onAnnotation(nodeId, newAnnotation) {
@@ -689,7 +686,7 @@ export default {
type: type,
position: defaultPosition(this.graphOffset, this.transform),
});
- this.$store.commit("workflowState/setActiveNode", this.nodeIndex);
+ this.stateStore.setActiveNode(this.nodeIndex);
},
async _loadEditorData(data) {
const report = data.report || {};
diff --git a/client/src/components/Workflow/Editor/Node.vue b/client/src/components/Workflow/Editor/Node.vue
index 2454ed44f90..77d653a2811 100644
--- a/client/src/components/Workflow/Editor/Node.vue
+++ b/client/src/components/Workflow/Editor/Node.vue
@@ -114,6 +114,7 @@ import DraggableWrapper from "./DraggablePan";
import { ActiveOutputs } from "./modules/outputs";
import { computed, inject, reactive, ref } from "vue";
import { useElementBounding } from "@vueuse/core";
+import { useWorkflowStateStore } from "@/stores/workflowEditorStateStore";
Vue.use(BootstrapVue);
@@ -171,7 +172,8 @@ export default {
const position = reactive(useElementBounding(el, { windowResize: false }));
const transform = inject("transform");
const postJobActions = computed(() => props.step.post_job_actions || {});
- return { el, position, transform, nodeIOKey, postJobActions };
+ const stateStore = useWorkflowStateStore();
+ return { el, position, transform, nodeIOKey, postJobActions, stateStore };
},
data() {
return {
@@ -246,7 +248,7 @@ export default {
},
},
created() {
- this.$store.commit("workflowState/setNode", this);
+ this.stateStore.setNode(this);
this.activeOutputs = new ActiveOutputs();
this.content_id = this.contentId;
// initialize node data
@@ -257,7 +259,7 @@ export default {
}
},
beforeDestroy() {
- this.$store.commit("workflowState/deleteNode", this.id);
+ this.stateStore.deleteNode(this.id);
},
methods: {
onMoveTo(position, event) {
diff --git a/client/src/components/Workflow/Editor/NodeInput.vue b/client/src/components/Workflow/Editor/NodeInput.vue
index 0d74b48455e..dadfcba56f2 100644
--- a/client/src/components/Workflow/Editor/NodeInput.vue
+++ b/client/src/components/Workflow/Editor/NodeInput.vue
@@ -28,6 +28,7 @@ import { computed } from "@vue/reactivity";
import { inject, ref, watchEffect } from "vue";
import { useTerminal } from "./composables/useTerminal";
import { DatatypesMapperModel } from "@/components/Datatypes/model";
+import { useWorkflowStateStore } from "@/stores/workflowEditorStateStore";
export default {
props: {
@@ -67,6 +68,7 @@ export default {
const connectedTerminals = ref([]);
watchEffect(() => (connectedTerminals.value = connectionStore.getOutputTerminalsForInputTerminal(id.value)));
const terminal = useTerminal(ref(props.stepId), ref(props.input), ref(props.datatypesMapper));
+ const stateStore = useWorkflowStateStore();
return {
el,
position,
@@ -77,6 +79,7 @@ export default {
iconId,
connectedTerminals,
terminal,
+ stateStore,
};
},
data() {
@@ -102,7 +105,6 @@ export default {
return this.input.label || this.input.name;
},
canAccept() {
- // TODO: put producesAcceptableDatatype ... in datatypesMapper ?
return this.draggingConnection && this.terminal.canAccept(this.draggingConnection.terminal);
},
reason() {
@@ -130,15 +132,11 @@ export default {
},
watch: {
terminalPosition(position) {
- this.$store.commit("workflowState/setInputTerminalPosition", {
- stepId: this.stepId,
- inputName: this.input.name,
- position,
- });
+ this.stateStore.setInputTerminalPosition(this.stepId, this.input.name, position);
},
},
beforeDestroy() {
- this.$store.commit("workflowState/deleteInputTerminalPosition", {
+ this.stateStore.deleteInputTerminalPosition({
stepId: this.stepId,
inputName: this.input.name,
});
@@ -148,7 +146,6 @@ export default {
if (this.reason) {
this.$root.$emit("bv::show::tooltip", this.iconId);
}
- console.log("dragover input", event);
},
dragLeave(event) {
this.$root.$emit("bv::hide::tooltip", this.iconId);
@@ -163,11 +160,7 @@ export default {
this.showRemove = false;
},
enter() {
- if (this.hasTerminals) {
- this.showRemove = true;
- } else {
- this.showRemove = false;
- }
+ this.showRemove = Boolean(this.hasTerminals);
},
leave() {
this.showRemove = false;
diff --git a/client/src/components/Workflow/Editor/NodeOutput.vue b/client/src/components/Workflow/Editor/NodeOutput.vue
index 4655b87e9d0..78bbe8c55d6 100644
--- a/client/src/components/Workflow/Editor/NodeOutput.vue
+++ b/client/src/components/Workflow/Editor/NodeOutput.vue
@@ -18,12 +18,22 @@
:prevent-default="false"
:stop-propagation="true"
draggable="true"
- @dragstart="dragStart"
@pan-by="onPanBy"
@start="isDragging = true"
@stop="onStopDragging"
@move="onMove">
-
+
+
+
@@ -32,11 +42,14 @@
import DraggableWrapper from "./DraggablePan";
import { useCoordinatePosition } from "./composables/useCoordinatePosition";
import { useTerminal } from "./composables/useTerminal";
-import { ref, computed, watch, reactive } from "vue";
+import { ref, computed, watch, nextTick } from "vue";
import { DatatypesMapperModel } from "@/components/Datatypes/model";
+import { useWorkflowStateStore } from "@/stores/workflowEditorStateStore";
+import ConnectionMenu from "@/components/Workflow/Editor/ConnectionMenu";
export default {
components: {
+ ConnectionMenu,
DraggableWrapper,
},
props: {
@@ -93,7 +106,35 @@ export default {
effectiveOutput.value = { ...props.output, extensions: extensions.value };
});
const terminal = useTerminal(ref(props.stepId), effectiveOutput, ref(props.datatypesMapper));
- return { el, position, terminal, extensions };
+
+ function closeMenu() {
+ console.log("closing Menu");
+ showChildComponent.value = false;
+ }
+
+ const menu = ref(null);
+ const showChildComponent = ref(false);
+ async function toggleChildComponent() {
+ showChildComponent.value = !showChildComponent.value;
+ if (showChildComponent.value) {
+ await nextTick();
+ console.log(menu);
+ menu.value.$el.focus();
+ }
+ }
+
+ const stateStore = useWorkflowStateStore();
+ return {
+ el,
+ position,
+ terminal,
+ extensions,
+ stateStore,
+ menu,
+ showChildComponent,
+ toggleChildComponent,
+ closeMenu,
+ };
},
data() {
return {
@@ -150,11 +191,7 @@ export default {
},
watch: {
terminalPosition(position) {
- this.$store.commit("workflowState/setOutputTerminalPosition", {
- stepId: this.stepId,
- outputName: this.output.name,
- position,
- });
+ this.stateStore.setOutputTerminalPosition(this.stepId, this.output.name, position);
},
dragPosition() {
if (this.isDragging) {
@@ -173,7 +210,7 @@ export default {
},
},
beforeDestroy() {
- this.$store.commit("workflowState/deleteOutputTerminalPosition", {
+ this.stateStore.deleteOutputTerminalPosition({
stepId: this.stepId,
outputName: this.output.name,
});
@@ -195,9 +232,6 @@ export default {
this.dragY = 0;
this.$emit("stopDragging");
},
- dragStart(e) {
- console.log("dragStart", e);
- },
inputDragEnter(e) {},
inputDragLeave(e) {},
onDrop(e) {},
diff --git a/client/src/components/Workflow/Editor/TerminalConnector.vue b/client/src/components/Workflow/Editor/TerminalConnector.vue
index a24b110d530..73f13ac2a39 100644
--- a/client/src/components/Workflow/Editor/TerminalConnector.vue
+++ b/client/src/components/Workflow/Editor/TerminalConnector.vue
@@ -1,40 +1,33 @@
-
+
-
-
-
diff --git a/client/src/components/Workflow/Editor/WorkflowEdges.vue b/client/src/components/Workflow/Editor/WorkflowEdges.vue
index f051709d1be..83c1f98ed91 100644
--- a/client/src/components/Workflow/Editor/WorkflowEdges.vue
+++ b/client/src/components/Workflow/Editor/WorkflowEdges.vue
@@ -1,16 +1,19 @@
-