From bf12af5bbe9dbe93868f0cf616b0e0a9db05e114 Mon Sep 17 00:00:00 2001 From: mvdbeek Date: Tue, 27 Dec 2022 10:41:12 +0100 Subject: [PATCH] D3, aria etc --- client/package.json | 3 +- client/src/components/ToolRecommendation.vue | 2 +- .../Workflow/Editor/ConnectionMenu.vue | 107 +++++ .../components/Workflow/Editor/Connector.vue | 118 ++--- .../src/components/Workflow/Editor/Index.vue | 27 +- .../src/components/Workflow/Editor/Node.vue | 8 +- .../components/Workflow/Editor/NodeInput.vue | 19 +- .../components/Workflow/Editor/NodeOutput.vue | 60 ++- .../Workflow/Editor/TerminalConnector.vue | 63 ++- .../Workflow/Editor/WorkflowEdges.vue | 29 +- .../Workflow/Editor/WorkflowGraph.vue | 16 +- .../Editor/composables/useTerminal.ts | 19 + .../Editor/composables/useWorkflowState.js | 19 - .../Workflow/Editor/modules/model.js | 9 - .../Workflow/Editor/modules/terminals.test.ts | 11 +- .../Workflow/Editor/modules/terminals.ts | 46 +- client/src/composables/useActiveElement.ts | 56 +++ client/src/reports/run_stats.js | 39 +- client/src/store/index.js | 2 - client/src/store/workflowEditorStateStore.js | 82 ---- client/src/stores/workflowEditorStateStore.ts | 83 ++++ client/src/viz/tools.js | 2 +- client/yarn.lock | 442 +++++++++++++++++- 23 files changed, 950 insertions(+), 312 deletions(-) create mode 100644 client/src/components/Workflow/Editor/ConnectionMenu.vue create mode 100644 client/src/components/Workflow/Editor/composables/useTerminal.ts delete mode 100644 client/src/components/Workflow/Editor/composables/useWorkflowState.js create mode 100644 client/src/composables/useActiveElement.ts delete mode 100644 client/src/store/workflowEditorStateStore.js create mode 100644 client/src/stores/workflowEditorStateStore.ts 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 @@ -