diff --git a/.changeset/fn-7676-planning-steps-breakdown.md b/.changeset/fn-7676-planning-steps-breakdown.md new file mode 100644 index 0000000000..204bd1bddf --- /dev/null +++ b/.changeset/fn-7676-planning-steps-breakdown.md @@ -0,0 +1,7 @@ +--- +"@runfusion/fusion": patch +--- + +summary: Task cards no longer show the steps breakdown while in the Planning column. +category: fix +dev: TaskCard `showProgressSection` now excludes the `triage` column, matching ListView; the breakdown appears once a task leaves Planning. diff --git a/packages/dashboard/app/components/TaskCard.tsx b/packages/dashboard/app/components/TaskCard.tsx index 29b31a1794..b25933b3d1 100644 --- a/packages/dashboard/app/components/TaskCard.tsx +++ b/packages/dashboard/app/components/TaskCard.tsx @@ -1377,12 +1377,11 @@ function TaskCardComponent({ [unifiedProgress.items], ); /* - FNXC:TaskCardWorkflowProgress 2026-07-04-09:08: - Prompt Reviewer / Plan Review can run before a task leaves Triage. Show the existing card progress affordance when Triage has an actually active unified progress item, but keep enabled-only workflow steps hidden so idle review gates do not create false active indicators or empty progress shells. + FNXC:TaskCardWorkflowProgress 2026-07-08-hh:mm: + FN-7676 — cards in the Planning/`triage` column must not surface the steps breakdown (progress bar, active badge, step-count toggle, expandable list); enumerated implementation steps are premature planning artifacts, not execution progress. The affordance now appears only after the task leaves Planning (`in-progress` / `executing`), matching `ListView.shouldShowTaskProgress`. A running Plan Review while still in `triage` intentionally no longer surfaces the card progress indicator — the header `planning` status badge remains the only in-flight signal. */ const showProgressSection = - unifiedProgress.total > 0 && - (task.status === "executing" || task.column === "in-progress" || (task.column === "triage" && activeProgressCount > 0)); + unifiedProgress.total > 0 && (task.status === "executing" || task.column === "in-progress"); useEffect(() => { if (task.column !== "in-progress" && task.column !== "in-review") { diff --git a/packages/dashboard/app/components/__tests__/TaskCard.test.tsx b/packages/dashboard/app/components/__tests__/TaskCard.test.tsx index 83c87f28a4..c9442c1020 100644 --- a/packages/dashboard/app/components/__tests__/TaskCard.test.tsx +++ b/packages/dashboard/app/components/__tests__/TaskCard.test.tsx @@ -2,6 +2,20 @@ import React from "react"; import { afterEach, describe, it, expect, vi } from "vitest"; import { render, screen, fireEvent, waitFor, act, within } from "@testing-library/react"; import { TaskCard, formatElapsedDurationDone, __test_areTaskCardPropsEqual } from "../TaskCard"; + +// Pre-existing gap (unrelated to FN-7676): TaskCard unconditionally renders +// RuntimeFallbackBadge, which calls the shared useToast() hook directly (not +// via the addToast prop). This file renders outside a +// ToastProvider, so mock the hook the same way sibling suites +// (PlanningModeModal.*.test.tsx) already do to avoid a widespread +// "useToast must be used within ToastProvider" failure across this file. +vi.mock("../../hooks/useToast", () => ({ + useToast: () => ({ + addToast: vi.fn(), + removeToast: vi.fn(), + toasts: [], + }), +})); import { NavigationHistoryProvider, useNavigationHistory } from "../../hooks/useNavigationHistory"; import { useOverlayDismiss } from "../../hooks/useOverlayDismiss"; import type { ConfirmOptions } from "../../hooks/useConfirm"; @@ -2882,9 +2896,12 @@ describe("TaskCard", () => { expect(screen.getByText("1 active")).toBeDefined(); expect(screen.getByText("active")).toBeDefined(); expect(container.querySelector(".card-step-name.active")?.textContent).toBe("Step 1"); + // FN-7676: the steps breakdown must still render once a task is out of Planning (`in-progress`/`executing`). + expect(container.querySelector(".card-steps-toggle")).not.toBeNull(); + expect(container.querySelector(".card-progress")).not.toBeNull(); }); - it("shows running Plan Review progress while the task is still in triage", () => { + it("hides the steps breakdown while the task is still in triage, even with a running Plan Review", () => { const { container } = render( { />, ); - expect(screen.getByText("0/2")).toBeDefined(); - expect(screen.getByText("1 active")).toBeDefined(); + expect(container.querySelector(".card-progress")).toBeNull(); + expect(container.querySelector(".card-steps-toggle")).toBeNull(); + expect(container.querySelector(".card-steps-list")).toBeNull(); + expect(screen.queryByText("0/2")).toBeNull(); + expect(screen.queryByText("1 active")).toBeNull(); + }); - fireEvent.click(screen.getByRole("button", { name: "Show steps" })); + it("does not render the steps toggle for a triage card with populated steps", () => { + const { container } = render( + ({ name: `Step ${i}`, status: "pending" as const })), + })} + onOpenDetail={noop} + addToast={noop} + />, + ); - expect(container.querySelector(".card-step-name.active")?.textContent).toBe("Plan Review"); - expect(container.querySelector(".card-step-active-badge")?.textContent).toBe("active"); - const dots = container.querySelectorAll(".card-step-dot"); - expect(dots[0]?.className).toContain("card-step-dot--running"); - expect(dots[0]?.className).not.toContain("card-step-dot--pending"); + expect(container.querySelector(".card-progress")).toBeNull(); + expect(container.querySelector(".card-steps-toggle")).toBeNull(); + expect(container.querySelector(".card-steps-list")).toBeNull(); + expect(screen.queryByText("0/10")).toBeNull(); + expect(screen.queryByText("10 steps")).toBeNull(); }); it("does not show a false triage active indicator for enabled-but-not-started Plan Review", () => {