Four panels became three, and the arrangement carries the change: everything
that organises or configures is stacked in one narrow column, and the whole of
the rest is one surface for looking at images.
Collections is a LIST, not a grid of covers — it sits in a narrow column beside
the gallery, where two cards per row meant four collections visible. A row is a
name, a count, and rename/delete on hover. Create is a dialog rather than an
always-present input, and a filter field replaces it in that space, since
finding one is the frequent act and making one is not.
Selecting a collection now shows it in the GALLERY. It used to replace the list
inside its own panel, which meant the selector disappeared the moment it was
used, and both panels kept their own copy of one collection's images and
disagreed after any edit. `?collection=` is read by the gallery now; the
collections hook stopped fetching detail entirely.
Deleting asks the question that cannot be undone: keep the images, or delete
them too. That needed a server route — DELETE /collections/:id?images=delete —
which reads the members BEFORE the collection goes, since deleting it takes the
memberships with it. Unchecked by default: the recoverable answer is the one
you get by pressing Enter without reading.
Providers stopped being a panel. It was a card per provider, each with a key
field and three buttons, filling a quarter of the screen for something set once
— it is a dropdown at the top of Generate now, listing "adapter · model" with a
delete on each, and adding one opens a dialog. The form and the dropdown share
one provider list (useProviders); they were two fetches, so adding a provider
left the form showing the old models until a reload.
`IntegrationsSettings/index.tsx` has carried the rule since email was extracted
on 2026-08-18: a plugin contributes panels, not settings sections. the
extraction brief said the opposite and the brief was wrong.
settings living in the platform mean this plugin is not self-contained — it
cannot be configured on an older platform, and uninstalling would leave a dead
"Atelier" section in the settings screen for someone to delete by hand.
so: a fourth panel, `atelier-providers`, and the default layout stacks it under
Collections in the right column. smallest and last because it is configured once
and then ignored — but it has to be REACHABLE, which is the whole point.
Generate's empty state pointed at "Settings → Integrations → Atelier". it now
points at the Providers panel, which is where the key actually goes.
ported from the standalone app's hash-tab UI. The panels do not coordinate through props (the panel
contract only ever hands a component its panelId) or usePanelChannel-as-selection:
- Gallery's lightbox is ?selected=<id>, Collections' detail is ?collection=<id> — different names
since both panels render on the same route at once
- Generate bumps useAtelierRefresh (added to officerdev/src/channels.ts) when a job finishes;
Gallery subscribes to it — a genuine signal, not a selection, so it stays a channel
images render through GET /files/:filename with a ?token= query param appended client-side
(lib/api.ts's fileUrl), the same escape hatch FileViewer and the music plugin use for exactly this:
a browser cannot set an Authorization header on an <img src>.
Providers is not here — see PLUGIN.md for why it became a platform settings screen instead.
assets/icon.png and assets/splash.png are [placeholder] flat swatches, not real artwork — see
assets/PLACEHOLDER.md.