Two things a second site ran into.
The network device form asked for the map position as two raw numbers, so
placing a device meant reading coordinates off another screen and typing them
in. Machines, PCs and printers have had a "Set Location on Map" picker all
along, and the network API already accepted mapx and mapy - only the form was
missing. Same picker, same modal.
The 3D parts kiosk hardcoded 'WJ' as the prefix shown before the number box,
with a comment inviting whoever needed something else to edit the source. That
is West Jefferson's gage-lab tag format and nobody else's, so another site's
operators were told to expect letters that are not on their labels.
It is now printedparts_label_prefix, set in Settings, defaulting to EMPTY - a
site that has not set one sees no prefix rather than inheriting another site's
convention. West Jefferson sets it to WJ once. The kiosk hides the prefix
entirely when unset and falls back to no prefix if the setting cannot be read,
because a cosmetic hint must never stop a kiosk working.
Not to be confused with printedparts_code_prefix, which mints item codes like
3DP0042 and was already configurable. That is the code we generate; this is the
tag already printed on the label.
Support teams gain a webhookurl (migration 7d29 + API + settings-page field), so
a team is a notification target. send_webhook(url=) lets a caller override the
site default with a team's webhook. Printedparts gains a 'alert support team'
setting (printedparts_alert_supportteamid) + selector on its settings page;
low-stock alerts post to that team's webhook, falling back to the site
alert_webhook_url. Email leg unchanged. Same pattern extends to other alerting
plugins (printers low-toner next).
The staging step that makes lean per-site frontend builds possible, plus the
first plugin relocated as the pilot.
- scripts/stage-frontend.mjs: copies each chosen plugin's plugins/<name>/frontend/
into frontend/src/.plugins-staged/<name>/ and codegens routes.gen.js. Plugin
selection via SITE_PLUGINS (comma-separated); empty = all plugins that have a
frontend/ (the full build). Wired as npm predev/prebuild; outputs gitignored.
- Router imports routes.gen.js and merges staged routes with the in-tree
./routes/*.js glob - dual-location during the transition.
- printedparts relocated: its 6 views (list/detail/form/kiosk + the settings and
labels views from the shared dirs) moved into plugins/printedparts/frontend/
views/, core imports rewritten to the @/ alias; routes.js is the self-contained
route module. Its old in-tree route file is removed.
Also fixes a crash the previous commit (37c764b) shipped: slides.js exports only
`toplevel` (its child routes live in core.js), so the router's
flatMap(m => m.default) produced an undefined child and threw
"Cannot read properties of undefined (reading 'path')" at load - the whole SPA
went blank. Guarded with `m.default || []`. (The earlier "print pages are blank"
reading was this crash, not page nature.)
Verified live: /machines renders again; the relocated /printedparts list renders
identically from the staged plugin frontend; SITE_PLUGINS=machines excludes
printedparts from routes.gen. Build (via npm, runs stage) + vitest + naming green.