From 28e664325144c6558bc7412532cb527e088e9cfb Mon Sep 17 00:00:00 2001 From: root Date: Mon, 20 Jul 2026 20:37:45 +0200 Subject: [PATCH] fix: move Workbench timing metadata below messages --- .../workbench/WorkbenchMessageCard.test.ts | 35 +++++++++++++++++++ .../workbench/WorkbenchMessageCard.vue | 28 ++++++++------- web/hwlab-cloud-web/src/styles/workbench.css | 28 ++++++++++++++- .../specs/message-timing.spec.ts | 6 ++-- 4 files changed, 80 insertions(+), 17 deletions(-) diff --git a/web/hwlab-cloud-web/src/components/workbench/WorkbenchMessageCard.test.ts b/web/hwlab-cloud-web/src/components/workbench/WorkbenchMessageCard.test.ts index 0dcbe9c7..4762e53f 100644 --- a/web/hwlab-cloud-web/src/components/workbench/WorkbenchMessageCard.test.ts +++ b/web/hwlab-cloud-web/src/components/workbench/WorkbenchMessageCard.test.ts @@ -46,6 +46,41 @@ describe("WorkbenchMessageCard startup visibility", () => { }); }); +describe("WorkbenchMessageCard metadata layout", () => { + it("renders recent activity at the footer left and elapsed time at the footer right", () => { + const now = Date.now(); + const wrapper = mount(WorkbenchMessageCard, { + props: { + detailEnabled: false, + message: { + id: "msg_timing_layout", + messageId: "msg_timing_layout", + role: "agent", + title: "Code Agent", + text: "", + status: "running", + traceId: "trc_timing_layout", + sessionId: "ses_timing_layout", + createdAt: new Date(now - 10_000).toISOString(), + timing: { + startedAt: new Date(now - 10_000).toISOString(), + lastEventAt: new Date(now - 4_000).toISOString() + } + } + }, + global: { stubs: componentStubs() } + }); + + const footer = wrapper.get(".message-meta-footer"); + expect(wrapper.find("article > header").exists()).toBe(false); + expect(footer.get(".message-activity-meta").text()).toMatch(/^最近更新:\d+ 秒前$/u); + expect(footer.get(".message-duration-meta").text()).toMatch(/^耗时 \d+ 秒$/u); + expect(footer.get(".message-footer-timing").element.firstElementChild).toBe(footer.get(".message-activity-meta").element); + expect(footer.get(".message-footer-timing").element.lastElementChild).toBe(footer.get(".message-duration-meta").element); + wrapper.unmount(); + }); +}); + describe("WorkbenchMessageCard semantic retry visibility", () => { it("shows Git mirror clone progress as runtime preparation", () => { const wrapper = mount(WorkbenchMessageCard, { diff --git a/web/hwlab-cloud-web/src/components/workbench/WorkbenchMessageCard.vue b/web/hwlab-cloud-web/src/components/workbench/WorkbenchMessageCard.vue index 8ad56495..e7d78afd 100644 --- a/web/hwlab-cloud-web/src/components/workbench/WorkbenchMessageCard.vue +++ b/web/hwlab-cloud-web/src/components/workbench/WorkbenchMessageCard.vue @@ -78,7 +78,7 @@ function messageActivityMeta(message: ChatMessage): { text: string; label: strin const ageMs = durationSince(timing?.lastEventAt); if (ageMs === null) return null; const value = formatDuration(ageMs) + "前"; - return { text: `最近 ${value}`, label: `最近事件:${value}` }; + return { text: `最近更新:${value}`, label: `最近更新:${value}` }; } function messageTimingForDisplay(message: ChatMessage): ChatMessage["timing"] { @@ -136,18 +136,6 @@ function traceStorageKey(message: ChatMessage): string { :data-trace-id="message.traceId || message.runnerTrace?.traceId || undefined" :data-turn-id="message.turnId || message.traceId || message.runnerTrace?.traceId || undefined" > -
-
- {{ message.title }} - {{ durationMeta.text }} -
-
- {{ activityMeta.text }} - - - -
-