Removable reference curves, audit fixes across pages, shaded Academy art
Test and deploy / test-and-deploy (push) Successful in 1m8s

The planner's Artisan .alog drawer now shows what's attached with a
"Remove reference curve" control (re-rendered per drawer open), so adding
a reference curve is no longer a one-way door; /api/alog shares the 8 MB
body cap so real-sized logs parse instead of failing with "bad_request".

Deep-evaluation fixes: editing a brew of an archived bean no longer
silently detaches the bean; the roasts pending-review poll no longer
wipes in-progress after-roast edits; roasters gain an Edit (rename/model)
action; the gear page refuses to autosave over a failed load; duplicating
a plan carries its custom name; cupping sessions can attach a plan after
creation (ownership-checked PUT + selector); admin user deletion also
refreshes plans/audit; cupping cup-count subtitle stays live; roasts
error-row colspan corrected. Regression tests cover the new cupping PUT
and the /api/alog body cap.

Academy scenes drop the flat paper-cutout look: shared defs provide
radial-gradient shading on every bean/half-bean/particle, flame gradients
with radiant halos, soft ground shadows, and a warm-lit stage background;
fill-shift animations now ride a partial-opacity tint overlay so shading
survives the color change.

Co-Authored-By: Claude Fable 5 <[email protected]>
This commit is contained in:
2026-08-11 16:59:28 -04:00
co-authored by Claude Fable 5
parent 8b80c3fa6f
commit 385474ecef
14 changed files with 368 additions and 34 deletions
+8
View File
@@ -10,6 +10,9 @@ import {
const SVG_NS = "http://www.w3.org/2000/svg";
let gear = { brewers: [], grinders: [] };
let saveTimer = null;
// Never save over the server until we've successfully read its state: the PUT replaces both
// arrays wholesale, so saving after a failed load would wipe the user's stored equipment.
let loaded = false;
function silhouetteSvg(methodKey) {
const svg = document.createElementNS(SVG_NS, "svg");
@@ -29,6 +32,10 @@ function silhouetteSvg(methodKey) {
// Saves shortly after the last toggle rather than needing a Save button — an equipment page
// is set-and-forget, so every change should just stick.
function scheduleSave() {
if (!loaded) {
showToast("Equipment didn't load — reload the page before making changes.", "fail");
return;
}
clearTimeout(saveTimer);
saveTimer = setTimeout(async () => {
try {
@@ -144,6 +151,7 @@ async function init() {
if (!user) return;
try {
gear = (await api("/api/gear")).gear;
loaded = true;
} catch {
showToast("Could not load equipment.", "fail");
}