Skip to content

Commit e5d90d3

Browse files
soujaycquirosj
andauthored
Display message data for each saga element in the saga diagram (#2352)
* Display message data Co-authored-by: Christian <[email protected]>
1 parent 26d7f95 commit e5d90d3

File tree

11 files changed

+549
-103
lines changed

11 files changed

+549
-103
lines changed

src/Frontend/src/components/messages2/SagaDiagram.spec.ts

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { SagaHistory } from "@/resources/SagaHistory";
44
import makeRouter from "@/router";
55
import { createTestingPinia } from "@pinia/testing";
66
import { MessageStore } from "@/stores/MessageStore";
7+
import { MessageStatus } from "@/resources/Message";
78

89
//Defines a domain-specific language (DSL) for interacting with the system under test (sut)
910
interface componentDSL {
@@ -38,7 +39,7 @@ describe("Feature: Message not involved in Saga", () => {
3839
const componentDriver = rendercomponent({
3940
initialState: {
4041
MessageStore: messageStore,
41-
sagaHistory: undefined, // Lets pass undefined to simulate no saga data available
42+
SagaDiagramStore: undefined, // Lets pass undefined to simulate no saga data available
4243
},
4344
});
4445

@@ -63,7 +64,7 @@ describe("Feature: Detecting no Audited Saga Data Available", () => {
6364
const componentDriver = rendercomponent({
6465
initialState: {
6566
MessageStore: messageStore,
66-
sagaHistory: undefined, // Lets pass undefined to simulate no saga data available
67+
SagaDiagramStore: undefined, // Lets pass undefined to simulate no saga data available
6768
},
6869
});
6970

@@ -97,7 +98,7 @@ describe("Feature: Navigation and Contextual Information", () => {
9798
const componentDriver = rendercomponent({
9899
initialState: {
99100
MessageStore: messageStore,
100-
sagaHistory: { sagaHistory: sampleSagaHistory },
101+
SagaDiagramStore: { sagaHistory: sampleSagaHistory },
101102
},
102103
});
103104

@@ -120,7 +121,7 @@ describe("Feature: Navigation and Contextual Information", () => {
120121
const componentDriver = rendercomponent({
121122
initialState: {
122123
MessageStore: messageStore,
123-
sagaHistory: { sagaHistory: sampleSagaHistory },
124+
SagaDiagramStore: { sagaHistory: sampleSagaHistory },
124125
},
125126
});
126127

@@ -181,7 +182,7 @@ describe("Feature: 3 Visual Representation of Saga Timeline", () => {
181182
const componentDriver = rendercomponent({
182183
initialState: {
183184
MessageStore: messageStore,
184-
sagaHistory: { sagaHistory: sampleSagaHistory },
185+
SagaDiagramStore: { sagaHistory: sampleSagaHistory },
185186
},
186187
});
187188

@@ -247,7 +248,7 @@ describe("Feature: 3 Visual Representation of Saga Timeline", () => {
247248
const componentDriver = rendercomponent({
248249
initialState: {
249250
MessageStore: messageStore,
250-
sagaHistory: { sagaHistory: sampleSagaHistory },
251+
SagaDiagramStore: { sagaHistory: sampleSagaHistory },
251252
},
252253
});
253254

@@ -271,7 +272,7 @@ describe("Feature: 3 Visual Representation of Saga Timeline", () => {
271272
});
272273
});
273274

274-
function rendercomponent({ initialState = {} }: { initialState?: { MessageStore?: MessageStore; sagaHistory?: { sagaHistory: SagaHistory } } }): componentDSL {
275+
function rendercomponent({ initialState = {} }: { initialState?: { MessageStore?: MessageStore; SagaDiagramStore?: { sagaHistory: SagaHistory } } }): componentDSL {
275276
const router = makeRouter();
276277

277278
// Render with createTestingPinia
@@ -380,6 +381,8 @@ const sampleSagaHistory: SagaHistory = {
380381
time_sent: new Date("2025-03-28T03:04:06.321561Z"),
381382
message_type: "ServiceControl.SmokeTest.MyCustomTimeout",
382383
intent: "Send",
384+
body_url: "body_url",
385+
message_status: MessageStatus.Successful,
383386
},
384387
outgoing_messages: [],
385388
endpoint: "Endpoint1",
@@ -397,6 +400,8 @@ const sampleSagaHistory: SagaHistory = {
397400
time_sent: new Date("2025-03-28T03:04:05.37723Z"),
398401
message_type: "ServiceControl.SmokeTest.MyCustomTimeout",
399402
intent: "Send",
403+
body_url: "body_url",
404+
message_status: MessageStatus.Successful,
400405
},
401406
outgoing_messages: [],
402407
endpoint: "Endpoint1",
@@ -414,6 +419,8 @@ const sampleSagaHistory: SagaHistory = {
414419
time_sent: new Date("2025-03-28T03:04:06.293765Z"),
415420
message_type: "ServiceControl.SmokeTest.SagaMessage2",
416421
intent: "Send",
422+
body_url: "body_url",
423+
message_status: MessageStatus.Successful,
417424
},
418425
outgoing_messages: [
419426
{
@@ -423,6 +430,12 @@ const sampleSagaHistory: SagaHistory = {
423430
time_sent: new Date("2025-03-28T03:04:06.3214397Z"),
424431
message_type: "ServiceControl.SmokeTest.MyCustomTimeout",
425432
intent: "Send",
433+
deliver_at: new Date("2025-03-28T03:04:06.293765Z"),
434+
is_saga_timeout_message: false,
435+
originating_endpoint: "Sender",
436+
originating_machine: "mobvm2",
437+
body_url: "body_url",
438+
message_status: MessageStatus.Successful,
426439
},
427440
],
428441
endpoint: "Endpoint1",
@@ -440,6 +453,8 @@ const sampleSagaHistory: SagaHistory = {
440453
time_sent: new Date("2025-03-28T03:04:05.235534Z"),
441454
message_type: "ServiceControl.SmokeTest.SagaMessage1",
442455
intent: "Send",
456+
body_url: "body_url",
457+
message_status: MessageStatus.Successful,
443458
},
444459
outgoing_messages: [
445460
{
@@ -449,6 +464,12 @@ const sampleSagaHistory: SagaHistory = {
449464
time_sent: new Date("2025-03-28T03:04:05.3715034Z"),
450465
message_type: "ServiceControl.SmokeTest.MyCustomTimeout",
451466
intent: "Send",
467+
deliver_at: new Date("2025-03-28T03:04:06.293765Z"),
468+
is_saga_timeout_message: false,
469+
originating_endpoint: "Sender",
470+
originating_machine: "mobvm2",
471+
body_url: "body_url",
472+
message_status: MessageStatus.Successful,
452473
},
453474
],
454475
endpoint: "Endpoint1",

src/Frontend/src/components/messages2/SagaDiagram.vue

Lines changed: 30 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
<script setup lang="ts">
2-
import { computed, onUnmounted, watch, ref } from "vue";
2+
import { computed, onUnmounted, watch } from "vue";
33
import routeLinks from "@/router/routeLinks";
44
import { useSagaDiagramStore } from "@/stores/SagaDiagramStore";
55
import { useMessageStore } from "@/stores/MessageStore";
66
import { storeToRefs } from "pinia";
77
import ToolbarEndpointIcon from "@/assets/Shell_ToolbarEndpoint.svg";
8-
import { SagaViewModel, parseSagaUpdates } from "./SagaDiagram/useSagaDiagramParser";
8+
import { SagaViewModel, parseSagaUpdates } from "./SagaDiagram/SagaDiagramParser";
99
import { typeToName } from "@/composables/typeHumanizer";
10+
import LoadingSpinner from "@/components/LoadingSpinner.vue";
1011
1112
//Subcomponents
1213
import NoSagaData from "./SagaDiagram/NoSagaData.vue";
@@ -15,23 +16,17 @@ import SagaHeader from "./SagaDiagram/SagaHeader.vue";
1516
import SagaUpdateNode from "./SagaDiagram/SagaUpdateNode.vue";
1617
import SagaCompletedNode from "./SagaDiagram/SagaCompletedNode.vue";
1718
18-
const showMessageData = ref(false);
19-
20-
const toggleMessageData = () => {
21-
showMessageData.value = !showMessageData.value;
22-
};
23-
24-
const store = useMessageStore();
25-
const { state: messageState } = storeToRefs(store);
26-
2719
const sagaDiagramStore = useSagaDiagramStore();
20+
const { showMessageData, loading } = storeToRefs(sagaDiagramStore);
21+
22+
const messageStore = useMessageStore();
2823
29-
//Watch for message and set saga ID when component mounts or message changes
3024
watch(
31-
() => messageState.value.data.invoked_saga,
32-
(newSagas) => {
33-
if (newSagas.has_saga) {
34-
sagaDiagramStore.setSagaId(newSagas.saga_id || "");
25+
() => messageStore.state.data.invoked_saga?.has_saga,
26+
(hasSaga) => {
27+
const saga = messageStore.state.data.invoked_saga;
28+
if (hasSaga && saga?.saga_id) {
29+
sagaDiagramStore.setSagaId(saga.saga_id);
3530
} else {
3631
sagaDiagramStore.clearSagaHistory();
3732
}
@@ -47,7 +42,7 @@ const vm = computed<SagaViewModel>(() => {
4742
const completedUpdate = sagaDiagramStore.sagaHistory?.changes.find((update) => update.status === "completed");
4843
const completionTime = completedUpdate ? new Date(completedUpdate.finish_time) : null;
4944
50-
const { data } = messageState.value;
45+
const { data } = messageStore.state;
5146
const { invoked_saga: saga } = data;
5247
const sagaHistory = sagaDiagramStore.sagaHistory;
5348
@@ -67,7 +62,7 @@ const vm = computed<SagaViewModel>(() => {
6762
6863
// Display data
6964
FormattedCompletionTime: completionTime ? `${completionTime.toLocaleDateString()} ${completionTime.toLocaleTimeString()}` : "",
70-
SagaUpdates: parseSagaUpdates(sagaHistory),
65+
SagaUpdates: parseSagaUpdates(sagaHistory, sagaDiagramStore.messagesData),
7166
ShowMessageData: showMessageData.value,
7267
};
7368
});
@@ -77,20 +72,25 @@ const vm = computed<SagaViewModel>(() => {
7772
<div class="saga-container">
7873
<!-- Toolbar header -->
7974
<div v-if="vm.HasSagaData" class="header">
80-
<button :class="['saga-button', { 'saga-button--active': vm.ShowMessageData }]" aria-label="show-message-data-button" @click="toggleMessageData">
75+
<button :class="['saga-button', { 'saga-button--active': vm.ShowMessageData }]" aria-label="show-message-data-button" @click="sagaDiagramStore.toggleMessageData">
8176
<img class="saga-button-icon" :src="ToolbarEndpointIcon" alt="" />
8277
{{ vm.ShowMessageData ? "Hide Message Data" : "Show Message Data" }}
8378
</button>
8479
</div>
8580

81+
<!-- Loading Spinner -->
82+
<div v-if="loading" class="loading-container">
83+
<LoadingSpinner />
84+
</div>
85+
8686
<!-- No saga Data Available container -->
87-
<NoSagaData v-if="!vm.ParticipatedInSaga" />
87+
<NoSagaData v-else-if="!vm.ParticipatedInSaga" />
8888

8989
<!-- Saga Audit Plugin Needed container -->
90-
<SagaPluginNeeded v-if="vm.ShowNoPluginActiveLegend" />
90+
<SagaPluginNeeded v-else-if="vm.ShowNoPluginActiveLegend" />
9191

9292
<!-- Main Saga Data container -->
93-
<div v-if="vm.HasSagaData" role="table" aria-label="saga-sequence-list" class="body" style="display: flex">
93+
<div v-else-if="vm.HasSagaData" role="table" aria-label="saga-sequence-list" class="body" style="display: flex">
9494
<div class="container">
9595
<!-- Saga header with title and navigation -->
9696
<SagaHeader :saga-title="vm.SagaTitle" :saga-guid="vm.SagaGuid" :message-id-url="vm.MessageIdUrl" />
@@ -133,6 +133,14 @@ const vm = computed<SagaViewModel>(() => {
133133
min-width: 50rem;
134134
}
135135
136+
.loading-container {
137+
display: flex;
138+
flex: 1;
139+
justify-content: center;
140+
align-items: center;
141+
min-height: 200px;
142+
}
143+
136144
/* Button styles */
137145
138146
.saga-button {

src/Frontend/src/components/messages2/SagaDiagram/MessageDataBox.vue

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,27 @@
11
<script setup lang="ts">
2+
import { SagaMessageDataItem, useSagaDiagramStore } from "@/stores/SagaDiagramStore";
3+
import { storeToRefs } from "pinia";
4+
import LoadingSpinner from "@/components/LoadingSpinner.vue";
5+
26
defineProps<{
3-
propertyKey?: string;
4-
propertyValue?: string;
5-
title?: string;
7+
messageData: SagaMessageDataItem[];
68
}>();
9+
10+
const sagaDiagramStore = useSagaDiagramStore();
11+
const { messageDataLoading } = storeToRefs(sagaDiagramStore);
712
</script>
813

914
<template>
10-
<div class="message-data-box">
11-
<b class="message-data-box-text">{{ propertyKey || "OrderId" }}</b>
15+
<div v-if="messageDataLoading" class="message-data-loading">
16+
<LoadingSpinner />
17+
</div>
18+
<div v-else-if="!messageDataLoading && messageData.length === 0" class="message-data-box">
19+
<span class="message-data-box-text--empty">Empty</span>
20+
</div>
21+
<div v-else-if="messageData.length > 0" v-for="(item, index) in messageData" :key="index" class="message-data-box">
22+
<b class="message-data-box-text">{{ item.key }}</b>
1223
<span class="message-data-box-text">=</span>
13-
<span class="message-data-box-text--ellipsis" :title="title || propertyValue || 'Sample ID'">{{ propertyValue || "Sample ID" }}</span>
24+
<span class="message-data-box-text--ellipsis" :title="item.value">{{ item.value }}</span>
1425
</div>
1526
</template>
1627

@@ -32,4 +43,16 @@ defineProps<{
3243
white-space: nowrap;
3344
text-overflow: ellipsis;
3445
}
46+
47+
.message-data-box-text--empty {
48+
display: inline-block;
49+
width: 100%;
50+
text-align: center;
51+
}
52+
53+
.message-data-loading {
54+
display: flex;
55+
justify-content: center;
56+
align-items: center;
57+
}
3558
</style>

0 commit comments

Comments
 (0)