diff --git a/src/Frontend/package-lock.json b/src/Frontend/package-lock.json index 7e66459fd..095ff0231 100644 --- a/src/Frontend/package-lock.json +++ b/src/Frontend/package-lock.json @@ -11,6 +11,7 @@ "@codemirror/lang-json": "^6.0.1", "@codemirror/lang-xml": "^6.1.0", "@codemirror/legacy-modes": "^6.5.0", + "@dagrejs/dagre": "^1.1.4", "@tinyhttp/content-disposition": "^2.2.2", "@vue-flow/controls": "^1.1.2", "@vue-flow/core": "^1.42.5", @@ -459,6 +460,24 @@ "node": ">=18" } }, + "node_modules/@dagrejs/dagre": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@dagrejs/dagre/-/dagre-1.1.4.tgz", + "integrity": "sha512-QUTc54Cg/wvmlEUxB+uvoPVKFazM1H18kVHBQNmK2NbrDR5ihOCR6CXLnDSZzMcSQKJtabPUWridBOlJM3WkDg==", + "license": "MIT", + "dependencies": { + "@dagrejs/graphlib": "2.2.4" + } + }, + "node_modules/@dagrejs/graphlib": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/@dagrejs/graphlib/-/graphlib-2.2.4.tgz", + "integrity": "sha512-mepCf/e9+SKYy1d02/UkvSy6+6MoyXhVxP8lLDfA7BPE1X1d4dR0sZznmbM8/XVJ1GPM+Svnx7Xj6ZweByWUkw==", + "license": "MIT", + "engines": { + "node": ">17.0.0" + } + }, "node_modules/@esbuild/aix-ppc64": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.1.tgz", diff --git a/src/Frontend/package.json b/src/Frontend/package.json index c558c45ed..f799210a3 100644 --- a/src/Frontend/package.json +++ b/src/Frontend/package.json @@ -20,6 +20,7 @@ "@codemirror/lang-json": "^6.0.1", "@codemirror/lang-xml": "^6.1.0", "@codemirror/legacy-modes": "^6.5.0", + "@dagrejs/dagre": "^1.1.4", "@tinyhttp/content-disposition": "^2.2.2", "@vue-flow/controls": "^1.1.2", "@vue-flow/core": "^1.42.5", diff --git a/src/Frontend/src/assets/endpoint-lost.svg b/src/Frontend/src/assets/endpoint-lost.svg index 2be2dd02c..a6c73ab95 100644 --- a/src/Frontend/src/assets/endpoint-lost.svg +++ b/src/Frontend/src/assets/endpoint-lost.svg @@ -1 +1,10 @@ - \ No newline at end of file + + + + + + + + + + \ No newline at end of file diff --git a/src/Frontend/src/assets/saga-completed.svg b/src/Frontend/src/assets/saga-completed.svg new file mode 100644 index 000000000..e63f5a58e --- /dev/null +++ b/src/Frontend/src/assets/saga-completed.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/Frontend/src/assets/saga-initiated.svg b/src/Frontend/src/assets/saga-initiated.svg new file mode 100644 index 000000000..969373a9c --- /dev/null +++ b/src/Frontend/src/assets/saga-initiated.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/Frontend/src/assets/saga-trigger.svg b/src/Frontend/src/assets/saga-trigger.svg new file mode 100644 index 000000000..0b809af35 --- /dev/null +++ b/src/Frontend/src/assets/saga-trigger.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/Frontend/src/assets/saga.svg b/src/Frontend/src/assets/saga.svg deleted file mode 100644 index f284fcc52..000000000 --- a/src/Frontend/src/assets/saga.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/src/Frontend/src/components/messages/FlowDiagram.vue b/src/Frontend/src/components/messages/FlowDiagram.vue index 210accdb2..e2eaea508 100644 --- a/src/Frontend/src/components/messages/FlowDiagram.vue +++ b/src/Frontend/src/components/messages/FlowDiagram.vue @@ -371,7 +371,7 @@ function typeIcon(type: MessageType) { } .pa-flow-saga { - background-image: url("@/assets/saga.svg"); + background-image: url("@/assets/saga-completed.svg"); background-position: center; background-repeat: no-repeat; height: 15px; diff --git a/src/Frontend/src/components/messages2/FlowDiagram.vue b/src/Frontend/src/components/messages2/FlowDiagram.vue deleted file mode 100644 index 44a004bb5..000000000 --- a/src/Frontend/src/components/messages2/FlowDiagram.vue +++ /dev/null @@ -1,457 +0,0 @@ - - - - - - - diff --git a/src/Frontend/src/components/messages2/FlowDiagram/FlowDiagram.vue b/src/Frontend/src/components/messages2/FlowDiagram/FlowDiagram.vue new file mode 100644 index 000000000..8432156d8 --- /dev/null +++ b/src/Frontend/src/components/messages2/FlowDiagram/FlowDiagram.vue @@ -0,0 +1,450 @@ + + + + + + + diff --git a/src/Frontend/src/components/messages2/FlowDiagram/useLayout.ts b/src/Frontend/src/components/messages2/FlowDiagram/useLayout.ts new file mode 100644 index 000000000..7f58dd711 --- /dev/null +++ b/src/Frontend/src/components/messages2/FlowDiagram/useLayout.ts @@ -0,0 +1,48 @@ +import dagre from "@dagrejs/dagre"; +import { DefaultEdge, Node, Position, useVueFlow } from "@vue-flow/core"; +import { ref } from "vue"; + +export function useLayout() { + const { findNode } = useVueFlow(); + + const graph = ref(new dagre.graphlib.Graph()); + + function layout(nodes: Node[], edges: DefaultEdge[], showAddress: boolean) { + // we create a new graph instance, in case some nodes/edges were removed, otherwise dagre would act as if they were still there + const dagreGraph = new dagre.graphlib.Graph(); + + graph.value = dagreGraph; + + dagreGraph.setDefaultEdgeLabel(() => ({})); + + const isHorizontal = false; + dagreGraph.setGraph({ rankdir: "TB" }); + + for (const node of nodes) { + const graphNode = findNode(node.id); + if (graphNode === undefined) continue; + + dagreGraph.setNode(node.id, { width: graphNode.dimensions.width || 250, height: (graphNode.dimensions.height || 55) + (showAddress ? 40 : 0) }); + } + + for (const edge of edges) { + dagreGraph.setEdge(edge.source, edge.target); + } + + dagre.layout(dagreGraph); + + // set nodes with updated positions + return nodes.map((node) => { + const nodeWithPosition = dagreGraph.node(node.id); + + return { + ...node, + targetPosition: isHorizontal ? Position.Left : Position.Top, + sourcePosition: isHorizontal ? Position.Right : Position.Bottom, + position: { x: nodeWithPosition.x, y: nodeWithPosition.y }, + }; + }); + } + + return { graph, layout }; +} diff --git a/src/Frontend/src/components/messages2/MessageView.vue b/src/Frontend/src/components/messages2/MessageView.vue index 9c7ce73c4..c22b956fd 100644 --- a/src/Frontend/src/components/messages2/MessageView.vue +++ b/src/Frontend/src/components/messages2/MessageView.vue @@ -3,7 +3,7 @@ import { computed, watch } from "vue"; import { RouterLink, useRoute } from "vue-router"; import NoData from "../NoData.vue"; import TimeSince from "../TimeSince.vue"; -import FlowDiagram from "./FlowDiagram.vue"; +import FlowDiagram from "./FlowDiagram/FlowDiagram.vue"; import SequenceDiagram from "./SequenceDiagram.vue"; import routeLinks from "@/router/routeLinks"; import { useIsMassTransitConnected } from "@/composables/useIsMassTransitConnected"; diff --git a/src/Frontend/src/resources/Message.ts b/src/Frontend/src/resources/Message.ts index 7bc049462..ed1386960 100644 --- a/src/Frontend/src/resources/Message.ts +++ b/src/Frontend/src/resources/Message.ts @@ -42,7 +42,7 @@ export enum MessageIntent { Init = "init", } -interface SagaInfo { +export interface SagaInfo { change_status?: string; saga_type: string; saga_id: string;