Fix desktop header overflow; add plan attachment on roast detail
Test and deploy / test-and-deploy (push) Successful in 55s

- The app header now wraps: brand + actions on the first row (actions
  shrink and wrap instead of pushing Print off-screen), section pills
  always on their own full-width row; the planner's sticky offsets use
  a two-row --header-h via body:has(#plan-form)
- Roast detail gains a Plan selector (attach/detach any of your plans)
  alongside the Machine selector; PUT /api/roasts/:id accepts
  roastPlanId with ownership checks

Co-Authored-By: Claude Fable 5 <[email protected]>
This commit is contained in:
Shane Maynard
2026-08-09 08:47:13 -04:00
co-authored by Claude Fable 5
parent 4a3d192c2c
commit c6c392730f
3 changed files with 86 additions and 11 deletions
+20 -1
View File
@@ -1750,6 +1750,24 @@ export function createApp({
params.push(roasterId);
sets.push(`roaster_id=$${params.length}`);
}
if (req.body.roastPlanId !== undefined) {
let roastPlanId = null;
if (req.body.roastPlanId !== null && req.body.roastPlanId !== "") {
if (!UUID_RE.test(req.body.roastPlanId))
return res.status(404).json({ ok: false, code: "not_found" });
const owns = (
await db.query(
"SELECT 1 FROM roast_plans WHERE id=$1 AND user_id=$2",
[req.body.roastPlanId, req.user.id],
)
).rowCount;
if (!owns)
return res.status(404).json({ ok: false, code: "not_found" });
roastPlanId = req.body.roastPlanId;
}
params.push(roastPlanId);
sets.push(`roast_plan_id=$${params.length}`);
}
if (req.body.after !== undefined) {
const after = sanitizeAfter(req.body.after);
if (!after)
@@ -1761,7 +1779,7 @@ export function createApp({
return res.status(400).json({ ok: false, code: "bad_request" });
params.push(req.params.id, req.user.id);
const r = await db.query(
`UPDATE actual_roasts SET ${sets.join(", ")}, updated_at=now() WHERE id=$${params.length - 1} AND user_id=$${params.length} RETURNING roaster_id, after`,
`UPDATE actual_roasts SET ${sets.join(", ")}, updated_at=now() WHERE id=$${params.length - 1} AND user_id=$${params.length} RETURNING roaster_id, roast_plan_id, after`,
params,
);
if (!r.rowCount)
@@ -1769,6 +1787,7 @@ export function createApp({
res.json({
ok: true,
roasterId: r.rows[0].roaster_id,
roastPlanId: r.rows[0].roast_plan_id,
after: r.rows[0].after,
});
} catch (e) {