From 3be22a574260ec7897dc540a2fe37f03b8a9dff0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20F=C3=B6rtsch?= Date: Tue, 14 Apr 2026 18:50:54 +0200 Subject: [PATCH] done column: hover 'back to review' to re-queue a done/errored plan MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit adds POST /api/review/:id/reopen that flips done or errored plans back to pending, clears the lingering job row, resets verified=0, and keeps the prior ffmpeg error summary in the plan's notes so the user has context for redeciding. done column cards grow a hover-only '← back to review' button next to the status badge — works identically for both the ✓/✓✓ and the ✗ rows, since the server accepts either. also hid the existing queue card's back-to-review behind the same hover affordance so the two columns behave consistently and the cards stay visually calm when not hovered. Co-Authored-By: Claude Opus 4.6 (1M context) --- package.json | 2 +- server/api/review.ts | 24 ++++++++++++++++++++++++ src/features/pipeline/DoneColumn.tsx | 20 ++++++++++++++++++-- src/features/pipeline/PipelineCard.tsx | 2 +- 4 files changed, 44 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index e7823e1..723e48d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "netfelix-audio-fix", - "version": "2026.04.14.21", + "version": "2026.04.14.22", "scripts": { "dev:server": "NODE_ENV=development bun --hot server/index.tsx", "dev:client": "vite", diff --git a/server/api/review.ts b/server/api/review.ts index 9a37b02..cebb761 100644 --- a/server/api/review.ts +++ b/server/api/review.ts @@ -752,6 +752,30 @@ app.post("/:id/retry", (c) => { return c.json({ ok: true }); }); +// Reopen a completed or errored plan: flip it back to pending so the user +// can adjust decisions and re-approve. Used by the Done column's hover +// "Back to review" affordance. Unlike /unapprove (which rolls back an +// approved-but-not-yet-running plan), this handles the post-job states +// and drops the lingering job row so the pipeline doesn't show leftover +// history for an item that's about to be re-queued. +app.post("/:id/reopen", (c) => { + const db = getDb(); + const id = parseId(c.req.param("id")); + if (id == null) return c.json({ error: "invalid id" }, 400); + const plan = db.prepare("SELECT * FROM review_plans WHERE item_id = ?").get(id) as ReviewPlan | undefined; + if (!plan) return c.notFound(); + if (plan.status !== "done" && plan.status !== "error") { + return c.json({ ok: false, error: "Can only reopen plans with status done or error" }, 409); + } + db.transaction(() => { + // Leave plan.notes alone so the user keeps any ffmpeg error summary + // from the prior run — useful context when redeciding decisions. + db.prepare("UPDATE review_plans SET status = 'pending', verified = 0, reviewed_at = NULL WHERE id = ?").run(plan.id); + db.prepare("DELETE FROM jobs WHERE item_id = ? AND status IN ('done', 'error')").run(id); + })(); + return c.json({ ok: true }); +}); + app.post("/:id/unapprove", (c) => { const db = getDb(); const id = parseId(c.req.param("id")); diff --git a/src/features/pipeline/DoneColumn.tsx b/src/features/pipeline/DoneColumn.tsx index e96b7af..2ecd2b5 100644 --- a/src/features/pipeline/DoneColumn.tsx +++ b/src/features/pipeline/DoneColumn.tsx @@ -15,6 +15,11 @@ export function DoneColumn({ items, onMutate }: DoneColumnProps) { onMutate(); }; + const reopen = async (itemId: number) => { + await api.post(`/api/review/${itemId}/reopen`); + onMutate(); + }; + return ( +
{item.name} - {item.status} +
+ {item.status} +
+ +
diff --git a/src/features/pipeline/PipelineCard.tsx b/src/features/pipeline/PipelineCard.tsx index 8be9dc0..0063131 100644 --- a/src/features/pipeline/PipelineCard.tsx +++ b/src/features/pipeline/PipelineCard.tsx @@ -194,7 +194,7 @@ export function PipelineCard({