This is an automated email from the ASF dual-hosted git repository.
lizhimins pushed a commit to branch rocketmq-studio
in repository https://gitbox.apache.org/repos/asf/rocketmq-dashboard.git
The following commit(s) were added to refs/heads/rocketmq-studio by this push:
new 8c0079be5 fix(trace): map failed trace nodes to the error step status
(#2576)
8c0079be5 is described below
commit 8c0079be55ebd4916c1d7c3bac4868bc66793fd7
Author: 0 <[email protected]>
AuthorDate: Thu Aug 27 15:29:12 2026 +0800
fix(trace): map failed trace nodes to the error step status (#2576)
The backend reports business statuses on trace nodes ("finish" |
"failed"), while the frontend TraceNode type and the Ant Design Steps
component only understand 'error' | 'wait' | 'process' | 'finish'. A
failed produce/consume/recall step therefore carried status "failed"
into the Steps items and never rendered as the red error state.
- map node statuses at the API boundary in getMessageTrace: "failed"
becomes "error", the four known step statuses pass through, and any
unknown status degrades to "wait" instead of a forced cast
Fixes #2502
Signed-off-by: 123123213weqw <[email protected]>
---
web/src/api/message.test.ts | 50 ++++++++++++++++++++++++++++++++++++++++++++-
web/src/api/message.ts | 21 ++++++++++++++++++-
2 files changed, 69 insertions(+), 2 deletions(-)
diff --git a/web/src/api/message.test.ts b/web/src/api/message.test.ts
index caa55b1b3..33a06d263 100644
--- a/web/src/api/message.test.ts
+++ b/web/src/api/message.test.ts
@@ -18,7 +18,12 @@
import MockAdapter from 'axios-mock-adapter';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import client from './client';
-import { consumeMessageDirectly, getMessageTrace, queryMessagePage,
queryMessages } from './message';
+import {
+ consumeMessageDirectly,
+ getMessageTrace,
+ queryMessagePage,
+ queryMessages,
+} from './message';
const mock = new MockAdapter(client);
@@ -125,6 +130,49 @@ describe('message API', () => {
await expect(getMessageTrace('msg-1', 'instance-1',
'orders')).resolves.toEqual(trace);
});
+ it('maps backend trace node statuses to Ant Design step statuses', async ()
=> {
+ const trace = {
+ nodes: [
+ {
+ title: 'Produce',
+ timestamp: 1784246400000,
+ status: 'failed',
+ costTime: 1,
+ description: 'x',
+ },
+ {
+ title: 'Consume',
+ timestamp: 1784246400000,
+ status: 'finish',
+ costTime: 1,
+ description: 'x',
+ },
+ {
+ title: 'In flight',
+ timestamp: 1784246400000,
+ status: 'process',
+ costTime: 1,
+ description: 'x',
+ },
+ {
+ title: 'Unknown',
+ timestamp: 1784246400000,
+ status: 'something-else',
+ costTime: 1,
+ description: 'x',
+ },
+ ],
+ consumerStatus: [],
+ };
+ mock
+ .onGet('/messages/msg-2/trace', { params: { instanceId: 'instance-1' } })
+ .reply(200, { code: 200, data: trace });
+
+ const mapped = await getMessageTrace('msg-2', 'instance-1');
+ expect(mapped.nodes.map((node) => node.status)).toEqual(['error',
'finish', 'process', 'wait']);
+ expect(mapped.consumerStatus).toEqual([]);
+ });
+
it('encodes message IDs before requesting trace records', async () => {
const trace = {
nodes: [],
diff --git a/web/src/api/message.ts b/web/src/api/message.ts
index 9fa57dfb7..101de0172 100644
--- a/web/src/api/message.ts
+++ b/web/src/api/message.ts
@@ -139,6 +139,18 @@ export async function queryMessagePage(
return { ...res.data.data, items:
sortMessagesByStoreTimeDesc(res.data.data.items) };
}
+// The backend reports business statuses ("finish" | "failed") on trace nodes,
+// while the Ant Design Steps component only understands
+// 'error' | 'wait' | 'process' | 'finish'. Map at the API boundary so the UI
+// never sees a status it cannot render.
+const mapTraceNodeStatus = (status: unknown): TraceNode['status'] => {
+ if (status === 'failed') return 'error';
+ if (status === 'finish' || status === 'process' || status === 'error' ||
status === 'wait') {
+ return status;
+ }
+ return 'wait';
+};
+
export async function getMessageTrace(
msgId: string,
instanceId?: string,
@@ -153,7 +165,14 @@ export async function getMessageTrace(
`/messages/${encodeURIComponent(msgId)}/trace`,
{ params },
);
- return res.data.data;
+ const trace = res.data.data;
+ return {
+ ...trace,
+ nodes: (trace.nodes ?? []).map((node) => ({
+ ...node,
+ status: mapTraceNodeStatus(node.status),
+ })),
+ };
}
export async function consumeMessageDirectly(data:
DirectConsumeMessageRequest) {