From ddb5c5eca45bea0972e2f592df3b2febbc810cb0 Mon Sep 17 00:00:00 2001 From: gsxdsm Date: Wed, 22 Jul 2026 01:00:07 -0700 Subject: [PATCH] FN-8481: enable GitHub tracking for Ideas tasks Allow operators to manage GitHub tracking from Ideas intake and Coding (Ideas) task details. - Permit GitHub tracking toggles in the Ideas column and the built-in Coding (Ideas) workflow. - Cover fallback and resolved workflow metadata paths with dashboard tests. - Add a patch changeset for the operator-facing capability. Files changed: .changeset/fn-8481-ideas-github-tracking.md | 7 ++++ .../dashboard/app/components/TaskDetailModal.tsx | 13 +++++-- ...lModal.inline-editing-and-integrations.test.tsx | 40 ++++++++++++++++++++-- 3 files changed, 56 insertions(+), 4 deletions(-) Fusion-Task-Id: FN-8481 Fusion-Task-Lineage: d267e203-bceb-492b-b218-8829406ef537 Co-authored-by: Fusion (runfusion.ai) --- .changeset/fn-8481-ideas-github-tracking.md | 7 ++++ .../app/components/TaskDetailModal.tsx | 13 +++++- ...l.inline-editing-and-integrations.test.tsx | 40 ++++++++++++++++++- 3 files changed, 56 insertions(+), 4 deletions(-) create mode 100644 .changeset/fn-8481-ideas-github-tracking.md diff --git a/.changeset/fn-8481-ideas-github-tracking.md b/.changeset/fn-8481-ideas-github-tracking.md new file mode 100644 index 0000000000..11c795cc0f --- /dev/null +++ b/.changeset/fn-8481-ideas-github-tracking.md @@ -0,0 +1,7 @@ +--- +"@runfusion/fusion": patch +--- + +summary: Let operators enable or disable GitHub tracking from Coding Ideas task details. +category: feature +dev: GitHub tracking eligibility now recognizes the Ideas intake column and `builtin:coding-ideas` workflow ID. diff --git a/packages/dashboard/app/components/TaskDetailModal.tsx b/packages/dashboard/app/components/TaskDetailModal.tsx index 5c489184e1..aa1dbcf176 100644 --- a/packages/dashboard/app/components/TaskDetailModal.tsx +++ b/packages/dashboard/app/components/TaskDetailModal.tsx @@ -650,7 +650,16 @@ function getProvenanceLabel(task: Task | TaskDetail, options: ProvenanceLabelOpt // #1403: widened to ColumnId so `.has(task.column)` accepts custom column ids // (non-members correctly resolve to false → not editable). const EDITABLE_COLUMNS: Set = new Set(["triage", "todo"]); -const GITHUB_TRACKING_EDITABLE_COLUMNS: Set = new Set(["triage", "todo", "in-progress", "in-review"]); +const GITHUB_TRACKING_EDITABLE_COLUMNS: Set = new Set(["triage", "todo", "in-progress", "in-review", "ideas"]); +const CODING_IDEAS_WORKFLOW_ID = "builtin:coding-ideas"; + +/* +FNXC:GitHubTracking 2026-07-22-00:46: +Ideas tasks must be able to opt into or out of GitHub tracking before planning, whether they remain in the Ideas intake column or have advanced in Coding (Ideas). Use the resolved workflow ID rather than its display name so localized names and arbitrary custom workflows cannot gain this editing capability. +*/ +function canTaskEditGithubTracking(column: ColumnId, workflowId: string | undefined): boolean { + return GITHUB_TRACKING_EDITABLE_COLUMNS.has(column) || workflowId === CODING_IDEAS_WORKFLOW_ID; +} export function TaskDetailContent({ task, @@ -1618,7 +1627,7 @@ export function TaskDetailContent({ // Check if task can be edited const canEdit = EDITABLE_COLUMNS.has(task.column) && !isSaving; - const canEditGithubTracking = GITHUB_TRACKING_EDITABLE_COLUMNS.has(task.column) && !isSaving; + const canEditGithubTracking = canTaskEditGithubTracking(task.column, taskWorkflowBadge?.id) && !isSaving; const githubTrackingEnabled = githubTrackingEnabledDraft ?? (workingTask.githubTracking?.enabled === true); const githubTrackedIssue = workingTask.githubTracking?.issue; const gitlabTrackedItem = workingTask.gitlabTracking?.item; diff --git a/packages/dashboard/app/components/__tests__/TaskDetailModal.inline-editing-and-integrations.test.tsx b/packages/dashboard/app/components/__tests__/TaskDetailModal.inline-editing-and-integrations.test.tsx index fbc209a9a8..3943f49d0e 100644 --- a/packages/dashboard/app/components/__tests__/TaskDetailModal.inline-editing-and-integrations.test.tsx +++ b/packages/dashboard/app/components/__tests__/TaskDetailModal.inline-editing-and-integrations.test.tsx @@ -3414,14 +3414,50 @@ describe("TaskDetailModal inline action row parity (FN-8194)", () => { expect(toggle).toHaveClass("btn-primary"); }); - it("hides the GitHub toggle for non-editable and GitLab-tracked tasks", () => { + it("enables GitHub tracking for Ideas intake tasks after workflow metadata fails", async () => { + const { updateTask, fetchBoardWorkflows } = await import("../../api"); + const mockUpdate = vi.mocked(updateTask); + vi.mocked(fetchBoardWorkflows).mockRejectedValueOnce(new Error("workflow metadata unavailable")); + mockUpdate.mockResolvedValueOnce(makeTask({ id: "FN-ideas", column: "ideas", githubTracking: { enabled: true } }) as Task); + + renderDetail(makeTask({ id: "FN-ideas", column: "ideas", githubTracking: { enabled: false } })); + + const toggle = screen.getByTestId("detail-inline-github-toggle"); + expect(toggle).toHaveAttribute("aria-pressed", "false"); + fireEvent.click(toggle); + + await waitFor(() => { + expect(mockUpdate).toHaveBeenCalledWith("FN-ideas", { githubTracking: { enabled: true } }, undefined); + }); + expect(toggle).toHaveAttribute("aria-pressed", "true"); + }); + + it("shows the GitHub toggle after Coding (Ideas) workflow metadata resolves", async () => { + const { fetchBoardWorkflows } = await import("../../api"); + vi.mocked(fetchBoardWorkflows).mockResolvedValueOnce({ + flagEnabled: true, + defaultWorkflowId: "builtin:coding", + workflows: [ + { id: "builtin:coding", name: "Coding", columns: [{ id: "done", name: "Done", flags: {} }] }, + { id: "builtin:coding-ideas", name: "Coding (Ideas)", columns: [{ id: "done", name: "Done", flags: {} }] }, + ], + taskWorkflowIds: { "FN-ideas-workflow": "builtin:coding-ideas" }, + }); + + renderDetail(makeTask({ id: "FN-ideas-workflow", column: "done", githubTracking: { enabled: false } })); + + expect(screen.queryByTestId("detail-inline-github-toggle")).not.toBeInTheDocument(); + expect(await screen.findByTestId("detail-inline-github-toggle")).toHaveAttribute("aria-pressed", "false"); + }); + + it("hides the GitHub toggle for unrelated and GitLab-tracked tasks", () => { const { unmount } = renderDetail(makeTask({ id: "FN-8194", column: "done", githubTracking: { enabled: true } })); expect(screen.queryByTestId("detail-inline-github-toggle")).not.toBeInTheDocument(); unmount(); renderDetail(makeTask({ id: "FN-8195", - column: "todo", + column: "ideas", gitlabTracking: { item: { kind: "project_issue",