FN-7525: add Revert/Undo affordance to Done and Archived task cards
Adds a Revert action so operators can undo landed changes for Done/Archived tasks directly from the board. - Adds onRevertTask wiring through Board, Column, Lane, ListView, TaskDetailModal, and WorktreeGroup surfaces - Adds a Revert affordance to TaskCard (Done/Archived states) with confirm UX and CSS - Adds POST /tasks/:id/revert legacy API route supporting "auto" mode with an AI-undo fallback (mode: "ai") on conflict - Wires useTasks hook and dashboard MainContent/types to support the new revert action - Adds new i18n strings for the revert affordance - Adds a minor changeset for @runfusion/fusion documenting the feature - Adds/updates tests: TaskCard.test.tsx, board-mobile.test.tsx, api-git.test.ts - Updates docs/dashboard-guide.md and docs/task-management.md Files changed: .changeset/fn-7525-revert-card-affordance.md | 7 + docs/dashboard-guide.md | 2 +- docs/task-management.md | 10 ++ packages/dashboard/app/App.tsx | 7 +- packages/dashboard/app/__tests__/api-git.test.ts | 51 +++++++ packages/dashboard/app/api/legacy.ts | 51 +++++++ packages/dashboard/app/components/AppModals.tsx | 5 +- packages/dashboard/app/components/Board.tsx | 10 +- packages/dashboard/app/components/Column.tsx | 8 +- packages/dashboard/app/components/Lane.tsx | 5 +- packages/dashboard/app/components/ListView.tsx | 80 ++++++++++- packages/dashboard/app/components/TaskCard.css | 24 +++- packages/dashboard/app/components/TaskCard.tsx | 127 ++++++++++++++++- packages/dashboard/app/components/TaskDetailModal.tsx | 85 ++++++++++++ packages/dashboard/app/components/WorktreeGroup.tsx | 6 + packages/dashboard/app/components/__tests__/TaskCard.test.tsx | 151 +++++++++++++++++++++ packages/dashboard/app/components/__tests__/board-mobile.test.tsx | 63 +++++++++ packages/dashboard/app/components/dashboard/MainContent.tsx | 4 + packages/dashboard/app/components/dashboard/types.ts | 8 ++ packages/dashboard/app/components/useRightDockController.tsx | 4 + packages/dashboard/app/hooks/useTasks.ts | 21 ++- packages/i18n/locales/en/app.json | 11 ++ 22 files changed, 718 insertions(+), 22 deletions(-) Fusion-Task-Id: FN-7525 Fusion-Task-Lineage: b9e2ca94-4ec6-4443-8e41-cf4828018856 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
This commit is contained in:
@@ -876,6 +876,57 @@ export function unarchiveTask(id: string, projectId?: string): Promise<Task> {
|
||||
return api<Task>(withProjectId(`/tasks/${id}/unarchive`, projectId), { method: "POST" });
|
||||
}
|
||||
|
||||
/*
|
||||
FNXC:TaskRevert 2026-07-05-00:00 (FN-7525):
|
||||
Client-side contract for `POST /tasks/:id/revert` (route owned by FN-7523/
|
||||
FN-7524/FN-7547/FN-7548 — see the `FNXC:TaskRevert` block in
|
||||
`register-task-workflow-routes.ts`). This is a discriminated union, NOT a
|
||||
`Task` — the source task's column/status is never mutated by this call; the
|
||||
caller (useTasks' `revertTask` op) refreshes the task list afterward so any
|
||||
newly-created revert commit / AI-undo task becomes visible, without patching
|
||||
the source task's column directly.
|
||||
*/
|
||||
export interface RevertTaskWorkspaceRepoResult {
|
||||
repo: string;
|
||||
classification?: string;
|
||||
revertCommitSha?: string;
|
||||
conflicts?: unknown;
|
||||
alreadyReverted?: boolean;
|
||||
}
|
||||
|
||||
export interface RevertTaskGitResult {
|
||||
mode: "git";
|
||||
clean: boolean;
|
||||
revertCommitSha?: string;
|
||||
revertCommitShas?: string[];
|
||||
conflicts?: unknown;
|
||||
alreadyReverted?: boolean;
|
||||
unsupported?: boolean;
|
||||
needsHuman?: boolean;
|
||||
reason?: string;
|
||||
workspace?: { repos: RevertTaskWorkspaceRepoResult[] };
|
||||
}
|
||||
|
||||
export interface RevertTaskAiResult {
|
||||
mode: "ai";
|
||||
createdTaskId: string;
|
||||
alreadyOpen?: boolean;
|
||||
}
|
||||
|
||||
export type RevertTaskResult = RevertTaskGitResult | RevertTaskAiResult;
|
||||
|
||||
export interface RevertTaskOptions {
|
||||
mode?: "git" | "ai" | "auto";
|
||||
granularity?: "squash" | "per-sha";
|
||||
}
|
||||
|
||||
export function revertTask(id: string, projectId?: string, body?: RevertTaskOptions): Promise<RevertTaskResult> {
|
||||
return api<RevertTaskResult>(withProjectId(`/tasks/${id}/revert`, projectId), {
|
||||
method: "POST",
|
||||
body: JSON.stringify(body ?? {}),
|
||||
});
|
||||
}
|
||||
|
||||
export function archiveAllDone(projectId?: string): Promise<Task[]> {
|
||||
return api<{ archived: Task[] }>(withProjectId("/tasks/archive-all-done", projectId), { method: "POST" }).then(
|
||||
(response) => response.archived
|
||||
|
||||
Reference in New Issue
Block a user