Skip to content

Commit 50540db

Browse files
committed
v1 of using code editor for message data
1 parent 1b813e2 commit 50540db

File tree

4 files changed

+120
-100
lines changed

4 files changed

+120
-100
lines changed

src/Frontend/src/components/MaximizableCodeEditor.vue

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,8 @@ import DiffCloseIcon from "@/assets/diff-close.svg";
66
import { Extension } from "@codemirror/state";
77
import { CodeLanguage } from "@/components/codeEditorTypes";
88
9-
// Define the model value to be passed to CodeEditor
109
const modelValue = defineModel<string>({ required: true });
1110
12-
// Define props by extending the CodeEditor props and adding maximize-specific ones
1311
withDefaults(
1412
defineProps<{
1513
language?: CodeLanguage;

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

Lines changed: 51 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,51 @@
11
<script setup lang="ts">
2-
import { SagaMessageDataItem, useSagaDiagramStore } from "@/stores/SagaDiagramStore";
2+
import { SagaMessageData, useSagaDiagramStore } from "@/stores/SagaDiagramStore";
33
import { storeToRefs } from "pinia";
44
import LoadingSpinner from "@/components/LoadingSpinner.vue";
5+
import MaximizableCodeEditor from "@/components/MaximizableCodeEditor.vue";
6+
import { computed } from "vue";
7+
import { CodeLanguage } from "@/components/codeEditorTypes";
8+
import { parse, stringify } from "lossless-json";
59
6-
defineProps<{
7-
messageData: SagaMessageDataItem[];
10+
const props = defineProps<{
11+
messageData: SagaMessageData;
812
}>();
913
1014
const sagaDiagramStore = useSagaDiagramStore();
1115
const { messageDataLoading } = storeToRefs(sagaDiagramStore);
16+
17+
const formattedData = computed(() => {
18+
if (props.messageData.type === "json" && props.messageData.data) {
19+
try {
20+
// Parse and then stringify with indentation to ensure proper formatting
21+
const parsed = parse(props.messageData.data);
22+
return stringify(parsed, null, 2);
23+
} catch {
24+
return props.messageData.data;
25+
}
26+
}
27+
return props.messageData.data;
28+
});
29+
30+
// Ensure language is properly typed as CodeLanguage
31+
const editorLanguage = computed<CodeLanguage>(() => {
32+
const type = props.messageData.type?.toLowerCase();
33+
return (type === "xml" ? "xml" : "json") as CodeLanguage;
34+
});
1235
</script>
1336

1437
<template>
1538
<div v-if="messageDataLoading" class="message-data-loading">
1639
<LoadingSpinner />
1740
</div>
18-
<div v-else-if="!messageDataLoading && messageData.length === 0" class="message-data-box">
41+
<div v-else-if="messageData.error" class="message-data-box message-data-box-error">
42+
<span class="message-data-box-text--error">An error occurred while parsing the message data</span>
43+
</div>
44+
<div v-else-if="!messageDataLoading && messageData.data === ''" class="message-data-box">
1945
<span class="message-data-box-text--empty">Empty</span>
2046
</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>
23-
<span class="message-data-box-text">=</span>
24-
<span class="message-data-box-text--ellipsis" :title="item.value">{{ item.value }}</span>
47+
<div v-else class="message-data-box message-data-box-content">
48+
<MaximizableCodeEditor :model-value="formattedData || ''" :language="editorLanguage" :read-only="true" :show-gutter="false" modalTitle="Message Data" />
2549
</div>
2650
</template>
2751

@@ -30,6 +54,10 @@ const { messageDataLoading } = storeToRefs(sagaDiagramStore);
3054
display: flex;
3155
}
3256
57+
.message-data-box-content {
58+
display: block;
59+
}
60+
3361
.message-data-box-text {
3462
display: inline-block;
3563
margin-right: 0.25rem;
@@ -48,11 +76,26 @@ const { messageDataLoading } = storeToRefs(sagaDiagramStore);
4876
display: inline-block;
4977
width: 100%;
5078
text-align: center;
79+
color: #666;
80+
font-style: italic;
81+
}
82+
83+
.message-data-box-text--error {
84+
display: inline-block;
85+
width: 100%;
86+
text-align: center;
87+
color: #a94442;
88+
font-style: italic;
5189
}
5290
5391
.message-data-loading {
5492
display: flex;
5593
justify-content: center;
5694
align-items: center;
5795
}
96+
97+
.message-data-box-error {
98+
padding: 1rem;
99+
justify-content: center;
100+
}
58101
</style>

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

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import { SagaHistory } from "@/resources/SagaHistory";
22
import { typeToName } from "@/composables/typeHumanizer";
3-
import { SagaMessageData, SagaMessageDataItem } from "@/stores/SagaDiagramStore";
3+
import { SagaMessageData } from "@/stores/SagaDiagramStore";
44
import { getTimeoutFriendly } from "@/composables/deliveryDelayParser";
55

66
export interface SagaMessageViewModel {
77
MessageId: string;
88
MessageFriendlyTypeName: string;
99
FormattedTimeSent: string;
10-
Data: SagaMessageDataItem[];
10+
Data: SagaMessageData;
1111
IsEventMessage: boolean;
1212
IsCommandMessage: boolean;
1313
}
@@ -78,7 +78,7 @@ export function parseSagaUpdates(sagaHistory: SagaHistory | null, messagesData:
7878
const initiatingMessageTimestamp = new Date(update.initiating_message?.time_sent || Date.now());
7979

8080
// Find message data for initiating message
81-
const initiatingMessageData = update.initiating_message ? messagesData.find((m) => m.message_id === update.initiating_message.message_id)?.data || [] : [];
81+
const initiatingMessageData = update.initiating_message ? findMessageData(messagesData, update.initiating_message.message_id) : createEmptyMessageData();
8282

8383
// Create common base message objects with shared properties
8484
const outgoingMessages = update.outgoing_messages.map((msg) => {
@@ -89,7 +89,7 @@ export function parseSagaUpdates(sagaHistory: SagaHistory | null, messagesData:
8989
const isEventMessage = msg.intent === "Publish";
9090

9191
// Find corresponding message data
92-
const messageData = messagesData.find((m) => m.message_id === msg.message_id)?.data || [];
92+
const messageData = findMessageData(messagesData, msg.message_id);
9393
return {
9494
MessageType: msg.message_type || "",
9595
MessageId: msg.message_id,
@@ -160,3 +160,19 @@ export function parseSagaUpdates(sagaHistory: SagaHistory | null, messagesData:
160160

161161
return updates;
162162
}
163+
164+
// Helper function to find message data or create empty data if not found
165+
function findMessageData(messagesData: SagaMessageData[], messageId: string): SagaMessageData {
166+
const messageData = messagesData.find((m) => m.message_id === messageId);
167+
return messageData || createEmptyMessageData();
168+
}
169+
170+
// Helper function to create an empty message data object
171+
function createEmptyMessageData(): SagaMessageData {
172+
return {
173+
message_id: "",
174+
data: "",
175+
type: "json",
176+
error: false,
177+
};
178+
}

src/Frontend/src/stores/SagaDiagramStore.ts

Lines changed: 49 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,12 @@ import { ref, watch } from "vue";
33
import { SagaHistory, SagaMessage } from "@/resources/SagaHistory";
44
import { useFetchFromServiceControl } from "@/composables/serviceServiceControlUrls";
55
import Message from "@/resources/Message";
6-
import { parse } from "lossless-json";
7-
import { useMessageStore } from "@/stores/MessageStore";
86

9-
const StandardKeys = ["$type", "Id", "Originator", "OriginalMessageId"];
10-
export interface SagaMessageDataItem {
11-
key: string;
12-
value: string;
13-
}
147
export interface SagaMessageData {
158
message_id: string;
16-
data: SagaMessageDataItem[];
9+
data: string;
10+
type: "json" | "xml";
11+
error: boolean;
1712
}
1813
export const useSagaDiagramStore = defineStore("SagaDiagramStore", () => {
1914
const sagaHistory = ref<SagaHistory | null>(null);
@@ -90,44 +85,68 @@ export const useSagaDiagramStore = defineStore("SagaDiagramStore", () => {
9085
}
9186
}
9287

93-
function createEmptyMessageData(message_id: string): SagaMessageData {
94-
return {
95-
message_id,
96-
data: [],
97-
};
98-
}
99-
10088
async function fetchSagaMessageData(message: SagaMessage): Promise<SagaMessageData> {
10189
const bodyUrl = (message.body_url ?? formatUrl(MessageBodyEndpoint, message.message_id)).replace(/^\//, "");
10290

10391
try {
10492
const response = await useFetchFromServiceControl(bodyUrl, { cache: "no-store" });
93+
94+
// Treat 404 as empty data, not as an error
95+
if (response.status === 404) {
96+
return {
97+
message_id: message.message_id,
98+
data: "",
99+
type: "json",
100+
error: false,
101+
};
102+
}
103+
104+
// Handle other non-OK responses as errors
105105
if (!response.ok) {
106-
throw new Error(`HTTP error! status: ${response.status}`);
106+
error.value = `HTTP error! status: ${response.status}`;
107+
return {
108+
message_id: message.message_id,
109+
data: "",
110+
type: "json",
111+
error: true,
112+
};
107113
}
108-
const body = await response.json();
114+
115+
const body = await response.text();
109116

110117
if (!body) {
111-
return createEmptyMessageData(message.message_id);
118+
return {
119+
message_id: message.message_id,
120+
data: "",
121+
type: "json",
122+
error: false,
123+
};
112124
}
113125

114-
let data: SagaMessageDataItem[];
115-
if (typeof body === "string" && body.trim().startsWith("<?xml")) {
116-
data = getXmlData(body);
126+
// Determine the content type
127+
if (body.trim().startsWith("<?xml")) {
128+
return {
129+
message_id: message.message_id,
130+
data: body,
131+
type: "xml",
132+
error: false,
133+
};
117134
} else {
118-
data = processJsonValues(body);
119-
}
120-
// Check if parsed data is empty
121-
if (!data || data.length === 0) {
122-
return createEmptyMessageData(message.message_id);
135+
return {
136+
message_id: message.message_id,
137+
data: body,
138+
type: "json",
139+
error: false,
140+
};
123141
}
142+
} catch (e) {
143+
error.value = e instanceof Error ? e.message : "Unknown error occurred";
124144
return {
125145
message_id: message.message_id,
126-
data,
146+
data: "",
147+
type: "json",
148+
error: true,
127149
};
128-
} catch (e) {
129-
error.value = e instanceof Error ? e.message : "Unknown error occurred";
130-
return createEmptyMessageData(message.message_id);
131150
}
132151
}
133152

@@ -144,62 +163,6 @@ export const useSagaDiagramStore = defineStore("SagaDiagramStore", () => {
144163
}
145164
}
146165

147-
function getXmlData(xmlString: string): SagaMessageDataItem[] {
148-
try {
149-
const parser = new DOMParser();
150-
const xmlDoc = parser.parseFromString(xmlString, "application/xml");
151-
152-
// Get the root element
153-
const rootElement = xmlDoc.documentElement;
154-
if (!rootElement) {
155-
return [];
156-
}
157-
158-
// Handle both v5 and pre-v5 message formats
159-
const messageRoot = rootElement.nodeName === "Messages" ? Array.from(rootElement.children)[0] : rootElement;
160-
161-
if (!messageRoot) {
162-
return [];
163-
}
164-
165-
// Convert child elements to SagaMessageDataItems
166-
return Array.from(messageRoot.children).map((node) => ({
167-
key: node.nodeName,
168-
value: node.textContent?.trim() || "",
169-
}));
170-
} catch (error) {
171-
console.error("Error parsing message data:", error);
172-
return [];
173-
}
174-
}
175-
176-
function processJsonValues(jsonBody: string | Record<string, unknown>): SagaMessageDataItem[] {
177-
let parsedBody: Record<string, unknown>;
178-
if (typeof jsonBody === "string") {
179-
try {
180-
parsedBody = parse(jsonBody) as Record<string, unknown>;
181-
} catch (e) {
182-
console.error("Error parsing JSON:", e);
183-
return [];
184-
}
185-
} else {
186-
parsedBody = jsonBody;
187-
}
188-
189-
const items: SagaMessageDataItem[] = [];
190-
191-
for (const key in parsedBody) {
192-
if (!StandardKeys.includes(key)) {
193-
items.push({
194-
key: key,
195-
value: String(parsedBody[key] ?? ""),
196-
});
197-
}
198-
}
199-
200-
return items;
201-
}
202-
203166
function clearSagaHistory() {
204167
sagaHistory.value = null;
205168
sagaId.value = null;

0 commit comments

Comments
 (0)