FN-7676: hide task-card steps breakdown while in Planning column

Task cards previously could show the progress/steps breakdown while still in the Planning (triage) column when a review gate was active; this changes it to only show once a task leaves Planning, matching ListView's behavior.

- TaskCard.showProgressSection now only shows for `in-progress`/`executing` tasks, dropping the special-case `triage` + active-progress-count branch
- Updated FNXC:TaskCardWorkflowProgress comment to document the FN-7676 requirement
- Updated TaskCard tests to cover the new triage-column behavior
- Added changeset for the patch

Files changed:
 .changeset/fn-7676-planning-steps-breakdown.md     |  7 +++
 packages/dashboard/app/components/TaskCard.tsx     |  7 ++-
 .../app/components/__tests__/TaskCard.test.tsx     | 50 ++++++++++++++++++----
 3 files changed, 51 insertions(+), 13 deletions(-)

Fusion-Task-Id: FN-7676

Fusion-Task-Lineage: 85fcf8f9-1010-4b68-9323-9d8ce03aa66f

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
This commit is contained in:
gsxdsm
2026-07-08 08:20:29 -07:00
parent 8ee8f15dc6
commit 297c7444f5
3 changed files with 51 additions and 13 deletions

View File

@@ -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.

View File

@@ -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") {

View File

@@ -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 <TaskCard> 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(
<TaskCard
task={makeTask({
@@ -2906,16 +2923,31 @@ describe("TaskCard", () => {
/>,
);
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(
<TaskCard
task={makeTask({
column: "triage",
status: "planning" as any,
steps: Array.from({ length: 10 }, (_, i) => ({ 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", () => {