done column: hover 'back to review' to re-queue a done/errored plan
All checks were successful
Build and Push Docker Image / build (push) Successful in 45s

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) <noreply@anthropic.com>
This commit is contained in:
2026-04-14 18:50:54 +02:00
parent d2983d5f38
commit 3be22a5742
4 changed files with 44 additions and 4 deletions

View File

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