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
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:
@@ -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",
|
||||
|
||||
@@ -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"));
|
||||
|
||||
@@ -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 (
|
||||
<ColumnShell
|
||||
title="Done"
|
||||
@@ -30,7 +35,7 @@ export function DoneColumn({ items, onMutate }: DoneColumnProps) {
|
||||
? "Done — awaiting post-job verification"
|
||||
: "Error";
|
||||
return (
|
||||
<div key={item.id} className="rounded border bg-white p-2">
|
||||
<div key={item.id} className="group rounded border bg-white p-2">
|
||||
<div className="flex items-start gap-1.5">
|
||||
<span
|
||||
title={markTitle}
|
||||
@@ -48,7 +53,18 @@ export function DoneColumn({ items, onMutate }: DoneColumnProps) {
|
||||
>
|
||||
{item.name}
|
||||
</Link>
|
||||
<Badge variant={item.status === "done" ? "done" : "error"}>{item.status}</Badge>
|
||||
<div className="flex items-center gap-1.5 mt-0.5">
|
||||
<Badge variant={item.status === "done" ? "done" : "error"}>{item.status}</Badge>
|
||||
<div className="flex-1" />
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => reopen(item.item_id)}
|
||||
title="Send this item back to the Review column to redecide and re-queue"
|
||||
className="text-[0.68rem] px-1.5 py-0.5 rounded border border-gray-300 bg-white text-gray-700 hover:bg-gray-100 opacity-0 group-hover:opacity-100 transition-opacity shrink-0"
|
||||
>
|
||||
← Back to review
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -194,7 +194,7 @@ export function PipelineCard({
|
||||
<button
|
||||
type="button"
|
||||
onClick={onUnapprove}
|
||||
className="text-xs px-3 py-1 rounded border border-gray-300 bg-white text-gray-700 hover:bg-gray-100"
|
||||
className="text-xs px-3 py-1 rounded border border-gray-300 bg-white text-gray-700 hover:bg-gray-100 opacity-0 group-hover:opacity-100 transition-opacity"
|
||||
>
|
||||
← Back to review
|
||||
</button>
|
||||
|
||||
Reference in New Issue
Block a user