diff --git a/.changeset/fn-6983-task-detail-rebind-warning.md b/.changeset/fn-6983-task-detail-rebind-warning.md new file mode 100644 index 0000000000..e4fbbae433 --- /dev/null +++ b/.changeset/fn-6983-task-detail-rebind-warning.md @@ -0,0 +1,7 @@ +--- +"@runfusion/fusion": patch +--- + +summary: Stop showing branch reattachment warnings in Task Detail. +category: fix +dev: Removes stale TaskDetailModal rebind-banner CSS/mocks and covers missing-branch workspace shapes. diff --git a/packages/dashboard/app/components/TaskDetailModal.css b/packages/dashboard/app/components/TaskDetailModal.css index 1954edac2d..cffe2727c8 100644 --- a/packages/dashboard/app/components/TaskDetailModal.css +++ b/packages/dashboard/app/components/TaskDetailModal.css @@ -2271,48 +2271,8 @@ Narrow mobile task detail surfaces from both Board and List must allow horizonta gap: var(--space-sm); } -.rebind-banner { - display: flex; - flex-direction: column; - gap: var(--space-sm); - padding: var(--space-lg); - border-radius: var(--radius-md); - background: color-mix(in srgb, var(--color-warning) 8%, transparent); - border: 1px solid color-mix(in srgb, var(--color-warning) 30%, transparent); -} - -.rebind-banner-header { - display: flex; - align-items: center; - gap: var(--space-sm); -} - -.rebind-banner-headline { - font-weight: 600; - color: var(--text); -} - -.rebind-banner-copy { - margin: 0; - color: var(--text); -} - -.rebind-banner-result { - color: var(--text-muted); - display: flex; - flex-direction: column; - gap: var(--space-xs); -} - -.rebind-banner-actions { - display: flex; - align-items: center; - gap: var(--space-sm); -} - @media (max-width: 768px) { - .detail-near-duplicate-banner__actions, - .rebind-banner-actions { + .detail-near-duplicate-banner__actions { flex-direction: column; align-items: flex-start; } diff --git a/packages/dashboard/app/components/__tests__/TaskDetailModal.create-pr-e2e.test.tsx b/packages/dashboard/app/components/__tests__/TaskDetailModal.create-pr-e2e.test.tsx index bc7b77332e..2d15be3917 100644 --- a/packages/dashboard/app/components/__tests__/TaskDetailModal.create-pr-e2e.test.tsx +++ b/packages/dashboard/app/components/__tests__/TaskDetailModal.create-pr-e2e.test.tsx @@ -31,7 +31,6 @@ vi.mock("../../api", async (importOriginal) => { updateGlobalSettings: vi.fn().mockResolvedValue({}), pauseTask: vi.fn().mockResolvedValue({}), unpauseTask: vi.fn().mockResolvedValue({}), - recoverBranchBinding: vi.fn(), fetchWorkflowResults: vi.fn().mockResolvedValue([]), fetchTaskReview: vi.fn().mockResolvedValue({ reviewState: { source: "reviewer-agent", items: [], addressing: [] }, automationStatus: null, emptyMessage: "No reviewer feedback yet" }), refreshTaskReview: vi.fn().mockResolvedValue({ reviewState: undefined, automationStatus: null }), diff --git a/packages/dashboard/app/components/__tests__/TaskDetailModal.create-pr-integration.test.tsx b/packages/dashboard/app/components/__tests__/TaskDetailModal.create-pr-integration.test.tsx index 5142cbe91b..5392bd3f9e 100644 --- a/packages/dashboard/app/components/__tests__/TaskDetailModal.create-pr-integration.test.tsx +++ b/packages/dashboard/app/components/__tests__/TaskDetailModal.create-pr-integration.test.tsx @@ -37,7 +37,6 @@ vi.mock("../../api", async (importOriginal) => { updateGlobalSettings: vi.fn().mockResolvedValue({}), pauseTask: vi.fn().mockResolvedValue({}), unpauseTask: vi.fn().mockResolvedValue({}), - recoverBranchBinding: vi.fn(), fetchWorkflowResults: vi.fn().mockResolvedValue([]), fetchTaskReview: vi.fn().mockResolvedValue({ reviewState: { source: "reviewer-agent", items: [], addressing: [] }, automationStatus: null, emptyMessage: "No reviewer feedback yet" }), refreshTaskReview: vi.fn().mockResolvedValue({ reviewState: undefined, automationStatus: null }), diff --git a/packages/dashboard/app/components/__tests__/TaskDetailModal.rendering.test.tsx b/packages/dashboard/app/components/__tests__/TaskDetailModal.rendering.test.tsx index 048c63a0a7..f7ff29ffd8 100644 --- a/packages/dashboard/app/components/__tests__/TaskDetailModal.rendering.test.tsx +++ b/packages/dashboard/app/components/__tests__/TaskDetailModal.rendering.test.tsx @@ -742,6 +742,86 @@ describe("TaskDetailModal", () => { expect(onRequestClose).toHaveBeenCalledTimes(1); }); + function expectNoBranchReattachmentAffordance(container: HTMLElement): void { + // FN-6983: Task Detail must not ask users to manually reattach branches; self-healing owns recovery. + expect(screen.queryByText(/Branch needs reattachment/i)).not.toBeInTheDocument(); + expect(screen.queryByText(/Branch binding lost/i)).not.toBeInTheDocument(); + expect(screen.queryByText(/isn't currently attached to a fusion branch/i)).not.toBeInTheDocument(); + expect(screen.queryByText(/Reattached branch/i)).not.toBeInTheDocument(); + expect(screen.queryByRole("button", { name: /Reattach branch/i })).not.toBeInTheDocument(); + expect(container.querySelector(".rebind-banner")).toBeNull(); + expect(container.querySelector(".rebind-banner-actions")).toBeNull(); + expect(container.querySelector(".rebind-banner-result")).toBeNull(); + } + + function renderTaskDetail(task: ReturnType, mobileHeaderMode?: "back") { + return render( + , + ); + } + + describe("branch reattachment affordance absence", () => { + it.each([ + ["null branch and worktree", makeTask({ column: "in-review", branch: null, worktree: null })], + ["undefined branch with missing worktree", makeTask({ column: "in-review", branch: undefined, worktree: null })], + ["populated branch control", makeTask({ column: "in-review", branch: "fusion/fn-099", worktree: "/tmp/fn-099" })], + ["non-in-review missing branch", makeTask({ column: "todo", branch: null, worktree: null })], + ] as const)("renders no reattachment banner for %s", (_label, task) => { + const { container } = renderTaskDetail(task); + + expectNoBranchReattachmentAffordance(container); + }); + + it("renders no reattachment banner for workspace in-review tasks with no singular branch", () => { + const task = makeTask({ + column: "in-review", + worktree: null, + workspaceWorktrees: { + "repo-a": { worktreePath: "/tmp/fn-099/repo-a", branch: "fusion/fn-099", baseCommitSha: "abc123" }, + "repo-b": { worktreePath: "/tmp/fn-099/repo-b", branch: "fusion/fn-099" }, + }, + }); + delete (task as { branch?: string | null }).branch; + + const { container } = renderTaskDetail(task); + + expectNoBranchReattachmentAffordance(container); + }); + + it("keeps the removed mobile rebind action shell absent in narrow task detail rendering", () => { + const { container } = renderTaskDetail(makeTask({ column: "in-review", branch: null, worktree: null }), "back"); + + expect(screen.getByRole("button", { name: "Back to task list" })).toBeInTheDocument(); + expectNoBranchReattachmentAffordance(container); + }); + + it("renders no reattachment banner from embedded TaskDetailContent", () => { + const { container } = render( + , + ); + + expectNoBranchReattachmentAffordance(container); + }); + }); + it("styles detail-body scrollbar rules", () => { const css = readDashboardStylesSource(); diff --git a/packages/dashboard/app/components/__tests__/TaskDetailModal.test-helpers.ts b/packages/dashboard/app/components/__tests__/TaskDetailModal.test-helpers.ts index d00536042d..1eeebc5a27 100644 --- a/packages/dashboard/app/components/__tests__/TaskDetailModal.test-helpers.ts +++ b/packages/dashboard/app/components/__tests__/TaskDetailModal.test-helpers.ts @@ -37,7 +37,6 @@ vi.mock("../../api", async (importOriginal) => { updateGlobalSettings: vi.fn().mockResolvedValue({}), pauseTask: vi.fn().mockResolvedValue({}), unpauseTask: vi.fn().mockResolvedValue({}), - recoverBranchBinding: vi.fn(), refreshPrStatus: vi.fn(), fetchWorkflowResults: vi.fn().mockResolvedValue([]), fetchTaskReview: vi.fn().mockResolvedValue({ reviewState: { source: "reviewer-agent", items: [], addressing: [] }, automationStatus: null, emptyMessage: "No reviewer feedback yet — this task has not produced reviewer-agent feedback in direct mode." }),