From 85e925a12a4272e7a1e3313162311661cd014cf6 Mon Sep 17 00:00:00 2001 From: gsxdsm Date: Tue, 30 Jun 2026 08:40:14 -0700 Subject: [PATCH] FN-7279: move workflow badges to task timestamps Move the task-detail workflow badge into the Updated timestamp metadata row. - Render one canonical workflow badge in the timestamp group for desktop and mobile task details. - Remove desktop/mobile workflow badge variants and keep timestamp layout from wrapping on mobile. - Update rendering and responsive CSS tests for the new badge ownership. - Add a patch changeset for the published Fusion package. Files changed: .../fn-7279-task-detail-workflow-timestamps.md | 7 ++++ .../dashboard/app/components/TaskDetailModal.css | 43 ++++++++++------------ .../dashboard/app/components/TaskDetailModal.tsx | 7 +--- .../__tests__/TaskDetailModal.rendering.test.tsx | 25 ++++++++----- ...etailModal.responsive-and-dependencies.test.tsx | 27 ++++++++------ 5 files changed, 58 insertions(+), 51 deletions(-) Fusion-Task-Id: FN-7279 Fusion-Task-Lineage: a1f11f51-99c9-42c7-bbb6-bb58384594a2 Co-authored-by: Fusion (runfusion.ai) --- ...fn-7279-task-detail-workflow-timestamps.md | 7 +++ .../app/components/TaskDetailModal.css | 43 ++++++++----------- .../app/components/TaskDetailModal.tsx | 7 +-- .../TaskDetailModal.rendering.test.tsx | 25 ++++++----- ...Modal.responsive-and-dependencies.test.tsx | 25 ++++++----- 5 files changed, 57 insertions(+), 50 deletions(-) create mode 100644 .changeset/fn-7279-task-detail-workflow-timestamps.md diff --git a/.changeset/fn-7279-task-detail-workflow-timestamps.md b/.changeset/fn-7279-task-detail-workflow-timestamps.md new file mode 100644 index 0000000000..1f83426412 --- /dev/null +++ b/.changeset/fn-7279-task-detail-workflow-timestamps.md @@ -0,0 +1,7 @@ +--- +"@runfusion/fusion": patch +--- + +summary: Move task-detail workflow badges into the Updated timestamp metadata row. +category: fix +dev: Uses one canonical task-detail workflow badge across desktop and mobile detail surfaces. diff --git a/packages/dashboard/app/components/TaskDetailModal.css b/packages/dashboard/app/components/TaskDetailModal.css index 1edb2a85dd..632960c338 100644 --- a/packages/dashboard/app/components/TaskDetailModal.css +++ b/packages/dashboard/app/components/TaskDetailModal.css @@ -29,7 +29,7 @@ The gray top header band (task id + column badge) was over-padded. Trim its vert .detail-title-row { display: flex; align-items: center; - gap: 10px; + gap: var(--space-sm); } .detail-id { @@ -39,28 +39,33 @@ The gray top header band (task id + column badge) was over-padded. Trim its vert color: var(--text-muted); } -.detail-column-badge, -.detail-workflow-badge { - font-size: 11px; - padding: 2px 8px; +.detail-column-badge { + font-size: 0.6875rem; + padding: calc(var(--space-xs) / 2) var(--space-sm); border-radius: var(--radius-pill); font-weight: 600; - letter-spacing: 0.5px; -} - -.detail-column-badge { + letter-spacing: 0.03125rem; text-transform: uppercase; } .detail-workflow-badge { + font-size: 0.6875rem; + padding: calc(var(--space-xs) / 2) var(--space-sm); + border-radius: var(--radius-pill); + font-weight: 600; + letter-spacing: 0.03125rem; + display: inline-flex; + align-items: center; + flex: 0 1 auto; + min-width: 0; + max-width: 100%; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; color: var(--text-muted); background: var(--surface-raised); border: 1px solid var(--border); } - -.detail-workflow-badge--mobile { - display: none; -} .badge-triage { background: var(--status-triage-bg); color: var(--triage); @@ -314,24 +319,14 @@ The task-detail modal metadata must keep priority, execution mode, provenance, P /* FNXC:TaskDetailWorkflow 2026-06-30-07:37: - Mobile task details need the workflow-name badge to read with the Updated timestamp instead of the compact header band. Keep desktop's header badge placement while showing exactly one mobile badge inside the timestamp group. + Task details show workflow identity in the Updated timestamp section across desktop and mobile. Keep the canonical badge inline with Created/Updated metadata so header rows, embedded detail hosts, and mobile back-header details do not render duplicate workflow badges or empty mobile-only shells. */ - .detail-workflow-badge--desktop { - display: none; - } - .detail-timestamps { display: flex; align-items: center; flex-wrap: nowrap; } - .detail-timestamps .detail-workflow-badge--mobile { - display: inline-flex; - align-items: center; - flex: 0 0 auto; - } - .detail-provenance-context { max-width: 20ch; } diff --git a/packages/dashboard/app/components/TaskDetailModal.tsx b/packages/dashboard/app/components/TaskDetailModal.tsx index e9a2239388..ff29c7b72d 100644 --- a/packages/dashboard/app/components/TaskDetailModal.tsx +++ b/packages/dashboard/app/components/TaskDetailModal.tsx @@ -2716,11 +2716,6 @@ export function TaskDetailContent({ {columnLabel(task.column)} - {taskWorkflowName && ( - - {taskWorkflowName} - - )}
{!isEditing && canEdit && ( @@ -3094,7 +3089,7 @@ export function TaskDetailContent({ {taskWorkflowName && ( - + {taskWorkflowName} )} diff --git a/packages/dashboard/app/components/__tests__/TaskDetailModal.rendering.test.tsx b/packages/dashboard/app/components/__tests__/TaskDetailModal.rendering.test.tsx index ad5815aa5b..ea5ceaf599 100644 --- a/packages/dashboard/app/components/__tests__/TaskDetailModal.rendering.test.tsx +++ b/packages/dashboard/app/components/__tests__/TaskDetailModal.rendering.test.tsx @@ -35,7 +35,7 @@ import { FileBrowserProvider } from "../../context/FileBrowserContext"; setupTaskDetailModalHooks(); describe("TaskDetailModal", () => { - describe("workflow header badge", () => { + describe("workflow timestamp badge", () => { const workflowPayload = { flagEnabled: true, defaultWorkflowId: "builtin:coding", @@ -71,14 +71,17 @@ describe("TaskDetailModal", () => { ); } - it("renders the resolved workflow name beside the task id and column badge", async () => { + it("renders the resolved workflow name in the timestamp section instead of the title row", async () => { vi.mocked(dashboardApi.fetchBoardWorkflows).mockResolvedValueOnce(workflowPayload); - renderDetail(); + const { container } = renderDetail(); const badge = await screen.findByTestId("task-detail-workflow-badge"); expect(badge).toHaveTextContent("Docs"); - expect(badge.parentElement).toHaveClass("detail-title-row"); + expect(badge.closest(".detail-timestamps")).toBeTruthy(); + expect(badge.closest(".detail-title-row")).toBeNull(); + expect(container.querySelector(".detail-title-row .detail-workflow-badge")).toBeNull(); + expect(screen.getAllByTestId("task-detail-workflow-badge")).toHaveLength(1); expect(screen.getByText("FN-101")).toBeInTheDocument(); expect(screen.getByText("Todo")).toBeInTheDocument(); expect(dashboardApi.fetchBoardWorkflows).toHaveBeenCalledTimes(1); @@ -170,7 +173,7 @@ describe("TaskDetailModal", () => { expect(container.querySelector(".detail-workflow-badge")).toBeNull(); }); - it("renders beside the Updated timestamp in the mobile back-header variant", async () => { + it("renders the canonical badge beside the Updated timestamp in the mobile back-header variant", async () => { vi.mocked(dashboardApi.fetchBoardWorkflows).mockResolvedValueOnce(workflowPayload); const { container } = render( @@ -187,13 +190,15 @@ describe("TaskDetailModal", () => { />, ); - expect(await screen.findByTestId("task-detail-workflow-badge")).toHaveTextContent("Docs"); - const mobileBadge = screen.getByTestId("task-detail-workflow-badge-mobile"); + const badge = await screen.findByTestId("task-detail-workflow-badge"); const timestamps = container.querySelector(".detail-timestamps"); const updatedLabel = screen.getByText("Updated").closest(".detail-timestamp-item"); - expect(mobileBadge).toHaveTextContent("Docs"); - expect(mobileBadge.parentElement).toBe(timestamps); - expect(updatedLabel?.nextElementSibling).toBe(mobileBadge); + expect(badge).toHaveTextContent("Docs"); + expect(badge.parentElement).toBe(timestamps); + expect(updatedLabel?.nextElementSibling).toBe(badge); + expect(screen.getAllByTestId("task-detail-workflow-badge")).toHaveLength(1); + expect(screen.queryByTestId("task-detail-workflow-badge-mobile")).toBeNull(); + expect(container.querySelector(".detail-title-row .detail-workflow-badge")).toBeNull(); expect(screen.getByRole("button", { name: "Back to task list" })).toBeInTheDocument(); }); }); diff --git a/packages/dashboard/app/components/__tests__/TaskDetailModal.responsive-and-dependencies.test.tsx b/packages/dashboard/app/components/__tests__/TaskDetailModal.responsive-and-dependencies.test.tsx index 74f89b6c0d..ee61c3ba1e 100644 --- a/packages/dashboard/app/components/__tests__/TaskDetailModal.responsive-and-dependencies.test.tsx +++ b/packages/dashboard/app/components/__tests__/TaskDetailModal.responsive-and-dependencies.test.tsx @@ -121,18 +121,23 @@ describe("TaskDetailModal", () => { expect(css).not.toMatch(/@media[^{]*\(max-width: 768px\)[^{]*\{[\s\S]*?\.detail-timestamp-separator\s*\{[^}]*display:\s*none;/); }); - it("places only the mobile workflow badge inside the timestamp group at the mobile breakpoint", () => { + it("keeps the canonical workflow badge owned by the timestamp group across breakpoints", () => { const css = readDashboardStylesSource(); - const mobileBlock = getCssAtRuleBlockContaining(css, "@media (max-width: 768px)", ".detail-timestamps .detail-workflow-badge--mobile"); - const mobileTimestampBadgeBlock = getCssRuleBlock(mobileBlock, ".detail-timestamps .detail-workflow-badge--mobile"); - const mobileDesktopBadgeBlock = getCssRuleBlock(mobileBlock, ".detail-workflow-badge--desktop"); + const workflowBadgeBlock = css.match(/^\.detail-workflow-badge\s*\{([^}]*)\}/m)?.[1] ?? ""; + const mobileBlock = getCssAtRuleBlockContaining(css, "@media (max-width: 768px)", ".detail-timestamps"); + const mobileTimestampsBlock = getCssRuleBlock(mobileBlock, ".detail-timestamps"); - expectBaseRule(css, ".detail-workflow-badge--mobile", "display: none;"); - expect(mobileDesktopBadgeBlock).toContain("display: none;"); - expect(mobileTimestampBadgeBlock).toContain("display: inline-flex;"); - expect(mobileTimestampBadgeBlock).toContain("align-items: center;"); - expect(mobileTimestampBadgeBlock).toContain("flex: 0 0 auto;"); - expect(css).not.toMatch(/@media[^{]*\(max-width: 768px\)[^{]*\{[\s\S]*?\.detail-title-row\s+\.detail-workflow-badge--mobile\s*\{/); + expect(workflowBadgeBlock).toContain("display: inline-flex;"); + expect(workflowBadgeBlock).toContain("align-items: center;"); + expect(workflowBadgeBlock).toContain("flex: 0 1 auto;"); + expect(workflowBadgeBlock).toContain("text-overflow: ellipsis;"); + expect(mobileTimestampsBlock).toContain("display: flex;"); + expect(mobileTimestampsBlock).toContain("align-items: center;"); + expect(mobileTimestampsBlock).toContain("flex-wrap: nowrap;"); + expect(css).not.toMatch(/detail-workflow-badge--desktop/); + expect(css).not.toMatch(/detail-workflow-badge--mobile/); + expect(css).not.toMatch(/task-detail-workflow-badge-mobile/); + expect(css).not.toMatch(/\.detail-title-row\s+\.detail-workflow-badge\s*\{/); }); it("keeps desktop and mobile modal sizing guards unchanged", () => { const css = readDashboardStylesSource();