From b10f82367200a189686730703eb0d7cc3ebd018f Mon Sep 17 00:00:00 2001 From: gsxdsm Date: Sun, 12 Jul 2026 12:26:54 -0700 Subject: [PATCH] FN-7867: make task-card priority badges icon-only to stop meta-badge wrapping Board TaskCard priority badges no longer render visible priority text, so the .card-meta-badges row cannot wrap onto a new line when a priority label widens it. - TaskCard.tsx: drop the visible priority-label , add title/aria-label with the full priority label, and keep the label reachable via a visually-hidden span for assistive tech - TaskCard.css: update the FNXC comment on .card-priority-badge to reflect the icon-only rationale (spacing/geometry rules unchanged, still shared with the Task Detail chip/select) - TaskCard.test.tsx: assert icon-only rendering (no visible text node/span), title/aria-label correctness, visually-hidden label content, and that the badge is absent for tasks without a priority; loosen the mocked lucide icons to forward arbitrary props - Add a patch changeset documenting the icon-only priority badge fix Files changed: .changeset/icon-only-priority-badges.md | 7 +++++ packages/dashboard/app/components/TaskCard.css | 2 +- packages/dashboard/app/components/TaskCard.tsx | 12 ++++++--- .../app/components/__tests__/TaskCard.test.tsx | 30 +++++++++++++++++----- 4 files changed, 39 insertions(+), 12 deletions(-) Fusion-Task-Id: FN-7867 Fusion-Task-Lineage: 5c845c23-0a9f-47b4-9a75-6c410b507ef4 Co-authored-by: Fusion (runfusion.ai) --- .changeset/icon-only-priority-badges.md | 7 +++++ .../dashboard/app/components/TaskCard.css | 2 +- .../dashboard/app/components/TaskCard.tsx | 12 +++++--- .../components/__tests__/TaskCard.test.tsx | 30 ++++++++++++++----- 4 files changed, 39 insertions(+), 12 deletions(-) create mode 100644 .changeset/icon-only-priority-badges.md diff --git a/.changeset/icon-only-priority-badges.md b/.changeset/icon-only-priority-badges.md new file mode 100644 index 0000000000..5cfefd74b2 --- /dev/null +++ b/.changeset/icon-only-priority-badges.md @@ -0,0 +1,7 @@ +--- +"@runfusion/fusion": patch +--- + +summary: Task card priority badges now show icon-only so they no longer wrap to a new line. +category: fix +dev: Updates the board TaskCard priority badge to keep labels in title, aria-label, and visually-hidden text. diff --git a/packages/dashboard/app/components/TaskCard.css b/packages/dashboard/app/components/TaskCard.css index 3f5492647d..12f7355590 100644 --- a/packages/dashboard/app/components/TaskCard.css +++ b/packages/dashboard/app/components/TaskCard.css @@ -516,7 +516,7 @@ FN-6774 removes the saturated stuck-task edge stripe from board cards. Keep the } .card-priority-badge { - /* FNXC:PriorityColorCoding 2026-07-11-00:00: Priority badges add a glyph beside the label; keep inline-flex geometry and token spacing so badge height/wrap invariants do not change. */ + /* FNXC:PriorityIconOnlyBadge 2026-07-12-00:00: FN-7867 removes visible priority text from board cards, so these shared spacing declarations no longer add card text width; keep them to preserve the Task Detail priority chip/select geometry that reuses the same badge class. */ gap: var(--space-xs); letter-spacing: 0.4px; } diff --git a/packages/dashboard/app/components/TaskCard.tsx b/packages/dashboard/app/components/TaskCard.tsx index 153bcc2650..064338e275 100644 --- a/packages/dashboard/app/components/TaskCard.tsx +++ b/packages/dashboard/app/components/TaskCard.tsx @@ -54,7 +54,7 @@ import { WorkspaceWorktreesSummary, isWorkspaceTask } from "./WorkspaceWorktrees import { WorkflowIcon } from "./WorkflowIcon"; import { TaskContextMenu, buildTaskActionMenuModel, getTaskPrAutomationLabel, type TaskContextMenuColumnFlags, type TaskContextMenuColumnMetadata, type TaskMenuActionDescriptor } from "./TaskContextMenu"; import { formatCost, hasTaskCost, taskTotalCost } from "../utils/taskTokenCost"; -import { getPriorityColorVar, getPriorityIcon } from "../utils/priorityIndicator"; +import { getPriorityColorVar, getPriorityIcon, getPriorityLabel } from "../utils/priorityIndicator"; /** Per-branch progress snapshot (U13). Surfaced as an optional additive field * on the task payload for the parallel-window badge (U9). */ @@ -3086,10 +3086,14 @@ function TaskCardComponent({ {hasCardMetaBadges && (
{showPriorityBadge && ( - - {/* FNXC:PriorityColorCoding 2026-07-11-00:00: Cards render the shared priority glyph with the priorityIndicator urgency color while preserving the existing badge text and non-normal visibility gate. */} + + {/* FNXC:PriorityIconOnlyBadge 2026-07-12-00:00: FN-7867 makes task-card priority badges icon-only so priority text cannot widen .card-meta-badges and force wrapping; preserve the label through title, aria-label, and visually-hidden text while keeping the shared urgency color. */} )} {task.executionMode === "fast" && ( diff --git a/packages/dashboard/app/components/__tests__/TaskCard.test.tsx b/packages/dashboard/app/components/__tests__/TaskCard.test.tsx index 66480933a2..f847aa4721 100644 --- a/packages/dashboard/app/components/__tests__/TaskCard.test.tsx +++ b/packages/dashboard/app/components/__tests__/TaskCard.test.tsx @@ -21,7 +21,7 @@ import { NavigationHistoryProvider, useNavigationHistory } from "../../hooks/use import { useOverlayDismiss } from "../../hooks/useOverlayDismiss"; import type { ConfirmOptions } from "../../hooks/useConfirm"; import { TASK_PRIORITIES, type Task, type TaskPriority } from "@fusion/core"; -import { getPriorityColorVar } from "../../utils/priorityIndicator"; +import { getPriorityColorVar, getPriorityLabel } from "../../utils/priorityIndicator"; // Mock lucide-react to avoid SVG rendering issues in test env vi.mock("lucide-react", () => ({ @@ -42,10 +42,10 @@ vi.mock("lucide-react", () => ({ RotateCw: () => null, Zap: () => , AlertTriangle: () => null, - ArrowDown: ({ style }: { style?: React.CSSProperties }) => , - Flag: ({ style }: { style?: React.CSSProperties }) => , - ArrowUp: ({ style }: { style?: React.CSSProperties }) => , - TriangleAlert: ({ style }: { style?: React.CSSProperties }) => , + ArrowDown: ({ style, ...props }: React.SVGProps) => , + Flag: ({ style, ...props }: React.SVGProps) => , + ArrowUp: ({ style, ...props }: React.SVGProps) => , + TriangleAlert: ({ style, ...props }: React.SVGProps) => , ArrowUpRight: () => null, // FN-7592: the overseer badge now renders an icon child instead of a text label, // so tests must see a real SVG (like Zap) rather than a no-op render. @@ -2790,7 +2790,7 @@ describe("TaskCard", () => { ]); }); - it("renders shared urgency-colored glyphs for visible priority badges while normal stays hidden", () => { + it("renders icon-only urgency-colored priority badges with accessible labels while normal stays hidden", () => { for (const priority of TASK_PRIORITIES) { const { container, unmount } = render( { continue; } + const label = getPriorityLabel(priority); expect(badge).not.toBeNull(); - expect(badge).toHaveTextContent(priority); + expect(badge).toHaveAttribute("aria-label", label); + expect(badge).toHaveAttribute("title", label); + expect(Array.from(badge?.childNodes ?? []).filter((node) => node.nodeType === Node.TEXT_NODE && node.textContent?.trim())).toEqual([]); + const visibleLabelSpans = Array.from(badge?.querySelectorAll("span") ?? []).filter((span) => !span.classList.contains("visually-hidden")); + expect(visibleLabelSpans).toEqual([]); + expect(badge?.querySelector(".visually-hidden")).toHaveTextContent(label); const icon = badge?.querySelector("svg"); expect(icon).not.toBeNull(); + expect(icon).toHaveAttribute("aria-hidden", "true"); expect(icon?.getAttribute("style")).toContain(`color: ${getPriorityColorVar(priority)}`); unmount(); } + + const { container } = render( + , + ); + expect(container.querySelector(".card-priority-badge")).toBeNull(); }); it("renders partial card meta groups without empty wrappers when time is absent", () => {