Skip to content

Commit 82a6402

Browse files
authored
Sequence Diagram tooltips (#2326)
1 parent 95fd4a4 commit 82a6402

16 files changed

+268
-48
lines changed

src/Frontend/src/components/messages/MessageView.vue

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import TimeSince from "../TimeSince.vue";
1010
import moment from "moment";
1111
import ConfirmDialog from "../ConfirmDialog.vue";
1212
import FlowDiagram from "./FlowDiagram.vue";
13-
import SequenceDiagram from "./SequenceDiagram.vue";
1413
import EditRetryDialog from "../failedmessages/EditRetryDialog.vue";
1514
import routeLinks from "@/router/routeLinks";
1615
import { EditAndRetryConfig } from "@/resources/Configuration";
@@ -44,7 +43,6 @@ const showEditRetryModal = ref(false);
4443
4544
const configuration = useConfiguration();
4645
const isMassTransitConnected = useIsMassTransitConnected();
47-
const showAllMessages = window.defaultConfig.showAllMessages;
4846
4947
async function loadFailedMessage() {
5048
const response = await useFetchFromServiceControl(`errors/last/${id.value}`);
@@ -351,13 +349,11 @@ onUnmounted(() => {
351349
<h5 :class="{ active: panel === 2 }" class="nav-item" @click.prevent="togglePanel(2)"><a href="#">Message body</a></h5>
352350
<h5 :class="{ active: panel === 3 }" class="nav-item" @click.prevent="togglePanel(3)"><a href="#">Headers</a></h5>
353351
<h5 v-if="!isMassTransitConnected" :class="{ active: panel === 4 }" class="nav-item" @click.prevent="togglePanel(4)"><a href="#">Flow Diagram</a></h5>
354-
<h5 v-if="showAllMessages" :class="{ active: panel === 5 }" class="nav-item" @click.prevent="togglePanel(5)"><a href="#">Sequence Diagram</a></h5>
355352
</div>
356353
<StackTraceView v-if="panel === 1 && failedMessage.exception?.stack_trace" :message="failedMessage" />
357354
<BodyView v-if="panel === 2" :message="failedMessage" />
358355
<HeadersView v-if="panel === 3" :message="failedMessage" />
359356
<FlowDiagram v-if="panel === 4" :message="failedMessage" />
360-
<SequenceDiagram v-if="showAllMessages && panel === 5" />
361357
</div>
362358
</div>
363359

src/Frontend/src/components/messages2/FlowDiagram.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ const nodeSpacingX = 300;
4141
const nodeSpacingY = 200;
4242
4343
const store = useMessageStore();
44-
const { state } = storeToRefs(useMessageStore());
44+
const { state } = storeToRefs(store);
4545
4646
async function getConversation(conversationId: string) {
4747
await store.loadConversation(conversationId);

src/Frontend/src/components/messages2/MessageView.vue

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { RouterLink, useRoute } from "vue-router";
44
import NoData from "../NoData.vue";
55
import TimeSince from "../TimeSince.vue";
66
import FlowDiagram from "./FlowDiagram.vue";
7+
import SequenceDiagram from "./SequenceDiagram.vue";
78
import routeLinks from "@/router/routeLinks";
89
import { useIsMassTransitConnected } from "@/composables/useIsMassTransitConnected";
910
import BodyView from "@/components/messages2/BodyView.vue";
@@ -51,6 +52,10 @@ const tabs = computed(() => {
5152
text: "Flow Diagram",
5253
component: FlowDiagram,
5354
});
55+
currentTabs.push({
56+
text: "Sequence Diagram",
57+
component: SequenceDiagram,
58+
});
5459
}
5560
5661
return currentTabs;

src/Frontend/src/components/messages/SequenceDiagram.vue renamed to src/Frontend/src/components/messages2/SequenceDiagram.vue

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,15 @@ import Handlers from "./SequenceDiagram/HandlersComponent.vue";
55
import Routes from "./SequenceDiagram/RoutesComponent.vue";
66
import { useSequenceDiagramStore } from "@/stores/SequenceDiagramStore";
77
import { storeToRefs } from "pinia";
8+
import useTooltips from "./SequenceDiagram/tooltipOverlay.ts";
9+
import { onMounted } from "vue";
810
911
const store = useSequenceDiagramStore();
10-
store.setConversationId("39907d51-12e5-4202-82c3-b2b30077ebd4");
11-
1212
const { maxWidth, maxHeight } = storeToRefs(store);
13+
14+
useTooltips();
15+
16+
onMounted(() => store.refreshConversation());
1317
</script>
1418

1519
<template>
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<script setup lang="ts">
2+
import { Endpoint } from "@/resources/SequenceDiagram/Endpoint";
3+
4+
defineProps<{ endpoint: Endpoint }>();
5+
</script>
6+
7+
<template>
8+
<div class="endpoint-tooltip">
9+
<label>Name:</label>
10+
<span>{{ endpoint.name }}</span>
11+
<label>NSB Version:</label>
12+
<span>{{ endpoint.version }}</span>
13+
<label>Host:</label>
14+
<span>{{ endpoint.host }}</span>
15+
</div>
16+
</template>
17+
18+
<style>
19+
.endpoint-tooltip {
20+
display: grid;
21+
grid-template-columns: auto auto;
22+
column-gap: 0.5em;
23+
}
24+
25+
.endpoint-tooltip label {
26+
grid-column: 1;
27+
justify-self: end;
28+
font-weight: bold;
29+
color: #b3b3b3;
30+
}
31+
32+
.endpoint-tooltip span {
33+
word-break: break-all;
34+
}
35+
</style>

src/Frontend/src/components/messages/SequenceDiagram/EndpointsComponent.vue renamed to src/Frontend/src/components/messages2/SequenceDiagram/EndpointsComponent.vue

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,11 @@ const Endpoint_Image_Width = 20;
2828
const store = useSequenceDiagramStore();
2929
const { startX, endpoints } = storeToRefs(store);
3030
31-
const epRefs = ref<SVGTextElement[]>([]);
31+
const epTextRefs = ref<SVGTextElement[]>([]);
3232
const endpointItems = computed(() =>
3333
endpoints.value.map((x, index) => {
3434
const endpoint = x as EndpointWithLocation;
35-
const el = epRefs.value[index];
35+
const el = epTextRefs.value[index];
3636
if (el) {
3737
const bounds = el.getBBox();
3838
const previousEndpoint = index > 0 ? endpointItems.value[index - 1] : undefined;
@@ -69,17 +69,17 @@ watch(endpointItems, () => {
6969
});
7070
7171
watch(startX, () => {
72-
epRefs.value = [];
72+
epTextRefs.value = [];
7373
endpoints.value.forEach((endpoint) => ((endpoint as EndpointWithLocation).surround = undefined));
7474
});
7575
76-
function setEndpointRef(el: SVGTextElement, index: number) {
77-
if (el) epRefs.value[index] = el;
76+
function setEndpointTextRef(el: SVGTextElement, index: number) {
77+
if (el) epTextRefs.value[index] = el;
7878
}
7979
</script>
8080

8181
<template>
82-
<g v-for="(endpoint, i) in endpointItems" :key="endpoint.name" transform="translate(0,15)">
82+
<g v-for="(endpoint, i) in endpointItems" :key="endpoint.name" transform="translate(0,15)" :ref="(el) => (endpoint.uiRef = el as SVGElement)">
8383
<rect
8484
v-if="endpoint.surround"
8585
:x="endpoint.surround.x"
@@ -93,7 +93,7 @@ function setEndpointRef(el: SVGTextElement, index: number) {
9393
></rect>
9494
<g :transform="`translate(${(endpoint.x ?? Endpoint_Width / 2) - ((endpoint.textWidth ?? 0) + Endpoint_Image_Width) / 2}, 0)`">
9595
<path fill="var(--gray40)" d="M 0,0 M 18,18 M 0,2 v 14 h 14 v -4 h -6 v -6 h 6 v -4 h -14 M 9,7 v 4 h 9 v -4"></path>
96-
<text :x="Endpoint_Image_Width" y="10" alignment-baseline="middle" text-anchor="start" :ref="(el) => setEndpointRef(el as SVGTextElement, i)">{{ endpoint.name }}</text>
96+
<text :x="Endpoint_Image_Width" y="10" alignment-baseline="middle" text-anchor="start" :ref="(el) => setEndpointTextRef(el as SVGTextElement, i)">{{ endpoint.name }}</text>
9797
</g>
9898
</g>
9999
</template>
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<script setup lang="ts">
2+
import { useFormatTime } from "@/composables/formatter";
3+
import { Handler } from "@/resources/SequenceDiagram/Handler";
4+
5+
defineProps<{ handler: Handler }>();
6+
7+
function formatTime(milliseconds: number) {
8+
const time = useFormatTime(milliseconds);
9+
return `${time.value} ${time.unit}`;
10+
}
11+
</script>
12+
13+
<template>
14+
<div v-if="handler.id === 'First'">Start of Conversation</div>
15+
<div v-else class="handler-tooltip">
16+
<div class="title">Processing of Message</div>
17+
<div class="details">
18+
<label>Processing Time:</label>
19+
<span>{{ formatTime(handler.processingTime ?? 0) }}</span>
20+
<label>Processing Of:</label>
21+
<span>{{ handler.name }}</span>
22+
<label v-if="handler.partOfSaga">Sagas Invoked:</label>
23+
<span v-if="handler.partOfSaga">{{ handler.partOfSaga }}</span>
24+
</div>
25+
</div>
26+
</template>
27+
28+
<style>
29+
.handler-tooltip {
30+
display: flex;
31+
flex-direction: column;
32+
}
33+
34+
.handler-tooltip .title {
35+
font-weight: bold;
36+
}
37+
38+
.handler-tooltip .details {
39+
display: grid;
40+
grid-template-columns: auto auto;
41+
column-gap: 0.5em;
42+
}
43+
44+
.handler-tooltip label {
45+
grid-column: 1;
46+
justify-self: end;
47+
font-weight: bold;
48+
color: #b3b3b3;
49+
}
50+
51+
.handler-tooltip span {
52+
word-break: break-all;
53+
}
54+
</style>

src/Frontend/src/components/messages/SequenceDiagram/HandlersComponent.vue renamed to src/Frontend/src/components/messages2/SequenceDiagram/HandlersComponent.vue

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,16 +43,18 @@ const handlerItems = computed(() => {
4343
4444
//determine which side of the handler to render the messageType on. If it's the left side (for a right arrow) then we apply a negative offset
4545
const messageTypeOffset = handler.direction === Direction.Right ? ((messageTypeElement?.getBBox().width ?? 0) + 24) * -1 : 20;
46-
if (messageTypeOffset < 0) {
47-
store.setStartX(-1 * messageTypeOffset);
46+
const left = (endpoint?.centre ?? 0) - Handler_Width / 2;
47+
const right = (endpoint?.centre ?? 0) + Handler_Width / 2;
48+
if (left + messageTypeOffset < 0) {
49+
store.setStartX(-1 * (left + messageTypeOffset) + 20);
4850
}
4951
5052
return {
5153
id: handler.id,
5254
endpointName: handler.endpoint.name,
5355
incomingId: handler.route?.name,
54-
left: (endpoint?.centre ?? 0) - Handler_Width / 2,
55-
right: (endpoint?.centre ?? 0) + Handler_Width / 2,
56+
left,
57+
right,
5658
y,
5759
height,
5860
fill,
@@ -61,6 +63,7 @@ const handlerItems = computed(() => {
6163
messageType: handler.name,
6264
messageTypeOffset,
6365
messageTypeHighlight: handler.route?.name === highlightId.value,
66+
setUIRef: (el: SVGElement) => (handler.uiRef = el),
6467
};
6568
});
6669
@@ -76,10 +79,12 @@ function setMessageTypeRef(el: SVGTextElement, index: number) {
7679
</script>
7780

7881
<template>
79-
<g v-for="(handler, i) in handlerItems" :key="handler.id" :transform="`translate(${handler.left}, ${handler.y})`">
82+
<g v-for="(handler, i) in handlerItems" :key="`${handler.id}###${handler.endpointName}`" :transform="`translate(${handler.left}, ${handler.y})`">
8083
<!--Handler Activation Box-->
81-
<rect :width="Handler_Width" :height="handler.height" :class="handler.incomingId && 'clickable'" :fill="handler.fill" @mouseover="() => store.setHighlightId(handler.incomingId)" @mouseleave="() => store.setHighlightId()" />
82-
<path v-if="handler.icon" :d="handler.icon" fill="white" :transform="`translate(${Handler_Width / 2 - handler.iconSize / 2}, ${handler.height / 2 - handler.iconSize / 2})`" />
84+
<g :ref="(el) => handler.setUIRef(el as SVGElement)">
85+
<rect :width="Handler_Width" :height="handler.height" :class="handler.incomingId && 'clickable'" :fill="handler.fill" @mouseover="() => store.setHighlightId(handler.incomingId)" @mouseleave="() => store.setHighlightId()" />
86+
<path v-if="handler.icon" :d="handler.icon" fill="white" :transform="`translate(${Handler_Width / 2 - handler.iconSize / 2}, ${handler.height / 2 - handler.iconSize / 2})`" />
87+
</g>
8388
<!--Message Type and Icon-->
8489
<g
8590
v-if="handler.messageType"
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<script setup lang="ts">
2+
import { RoutedMessage, RoutedMessageType } from "@/resources/SequenceDiagram/RoutedMessage";
3+
4+
defineProps<{ routedMessage: RoutedMessage }>();
5+
</script>
6+
7+
<template>
8+
<div class="route-tooltip">
9+
<div class="title">{{ RoutedMessageType[routedMessage.type] }}</div>
10+
<div class="details">
11+
<label>Message Type:</label>
12+
<span>{{ routedMessage.name }}</span>
13+
<label>Message Id:</label>
14+
<span>{{ routedMessage.messageId }}</span>
15+
<label>Sent From:</label>
16+
<span>{{ `${routedMessage.sending.name}@${routedMessage.sending.host}` }}</span>
17+
<label>Sent To:</label>
18+
<span>{{ `${routedMessage.receiving.name}@${routedMessage.receiving.host}` }}</span>
19+
</div>
20+
</div>
21+
</template>
22+
23+
<style>
24+
.route-tooltip {
25+
display: flex;
26+
flex-direction: column;
27+
}
28+
29+
.route-tooltip .title {
30+
font-weight: bold;
31+
}
32+
33+
.route-tooltip .details {
34+
display: grid;
35+
grid-template-columns: auto auto;
36+
column-gap: 0.5em;
37+
}
38+
39+
.route-tooltip label {
40+
grid-column: 1;
41+
justify-self: end;
42+
font-weight: bold;
43+
color: #b3b3b3;
44+
}
45+
46+
.route-tooltip span {
47+
word-break: break-all;
48+
}
49+
</style>

src/Frontend/src/components/messages/SequenceDiagram/RoutesComponent.vue renamed to src/Frontend/src/components/messages2/SequenceDiagram/RoutesComponent.vue

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ const arrows = computed(() =>
3636
route.fromRoutedMessage.direction = direction;
3737
3838
if (messageTypeOffset < 0) {
39-
store.setStartX(-1 * messageTypeOffset);
39+
store.setStartX(-1 * messageTypeOffset + 20);
4040
}
4141
4242
return {
@@ -53,6 +53,7 @@ const arrows = computed(() =>
5353
highlight: highlightId.value === route.name,
5454
highlightTextWidth: messageTypeElementBounds?.width,
5555
highlightTextHeight: messageTypeElementBounds?.height,
56+
setUIRef: (el: SVGElement) => (route.uiRef = el),
5657
};
5758
})
5859
);
@@ -78,11 +79,12 @@ function setMessageTypeRef(el: SVGTextElement, index: number) {
7879
</g>
7980
<!--Message Type and Icon-->
8081
<g
81-
class="clickable"
82+
class="clickable message-type"
8283
:transform="`translate(${arrow.messageTypeOffset}, ${arrow.y - 7.5 - Message_Type_Margin})`"
8384
:fill="arrow.highlight ? 'var(--highlight)' : 'black'"
8485
@mouseover="() => store.setHighlightId(arrow.id)"
8586
@mouseleave="() => store.setHighlightId()"
87+
:ref="(el) => arrow.setUIRef(el as SVGElement)"
8688
>
8789
<!--19 is width of MessageType icon, plus a gap-->
8890
<rect
@@ -113,4 +115,8 @@ function setMessageTypeRef(el: SVGTextElement, index: number) {
113115
.clickable {
114116
cursor: pointer;
115117
}
118+
119+
.message-type text::selection {
120+
fill: white;
121+
}
116122
</style>

0 commit comments

Comments
 (0)