every section was clickable and every one of them showed the same connection form,
because the panel forced it and the nav did not know. nine doors onto one message
taught nobody anything and made a setup step look like nine faults.
so there is now a gate, `useReady`, and both panels read it. that is the point of
putting it in a hook rather than in either panel: a nav that offers a row the
detail panel then refuses is worse than one that does not offer it.
the nav DECLINES TO OFFER — a locked section is a <div>, not a <Link>, so there is
no href to hover, no cmd-click into a new tab and nothing to focus. rendering a
link and swallowing the click leaves a row that looks navigable and behaves like
one everywhere except the click.
the detail panel HOLDS THE LOCK, and it has to, because `?section=gallery` typed
into the address bar or arriving from an old bookmark never passes through the
nav.
one line of copy in the foot rather than a badge on nine dimmed rows. without it a
locked nav reads as broken instead of as one step not done: the rows go grey and
nothing says why or what to do about it.
THE CONDITION IS HARDCODED FALSE, as asked. the plumbing around it is real — it
asks /status, re-asks when the connection changes, and reports while it is still
asking — so switching the gate on is one line. it returns a single boolean and not
its parts deliberately: "all the info needed in Administration" will grow past
`configured && lastProbeOk`, and callers must not start assembling their own
version of it out of the pieces.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
it was last in SECTIONS, so it rendered as the tenth row and then stopped —
directly under Messages, with empty panel beneath it. that is the bottom of the
LIST. what it wanted is the bottom of the PANEL, the way Update-all sits in the
plugins nav.
`mt-auto` on a second group, divided by the same border the rows already use. it
holds whether there are ten sections or two, and it does not need a spacer element
to push it down.
the split is a `pinned` flag on the section rather than the nav testing for the
key. which sections are the client's site and which are this plugin's own
machinery is a fact about the section, and the nav should be reading it, not
knowing it. one array still — `sectionFor` and `isSectionKey` have to resolve
every key, and a second exported list is a second place to forget one.
the row body came out into `renderRow` so both groups draw the same row. no
change to what a row looks like.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
the connection form — where fofos is, and the token — was reached through
`?config=1` and a link in the detail header, because it was not one of the nine
sections. it is now the tenth, called Administration, last in the nav.
that removes the overlay and the second route to it. the two could disagree: the
form covered whatever section was selected underneath, so the nav highlighted one
thing while the panel showed another, and an unconfigured plugin rendered the form
with no header at all — which reads as the selected section being broken rather
than as one setup step not done yet. unconfigured now goes to Administration and
the header says so.
`site` and `administration` are deliberately separate and the file says why. Site
settings is the CLIENT's — partners, social links, contact details, all of it
public copy. Administration is Officer's end: how this plugin reaches fofos, and
whatever else it will need to know. nothing in it ever appears on the site, and
the people who touch the two are not the same people.
`path: null`, alone among the sections: it reads nothing from fofos, which is why
it keeps working when fofos is unreachable and the others do not.
the header's settings link is replaced by the section's own hint, so the row still
says what it is once you are in it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
manifest, one table, a router and two panels. Discovery is by convention, so
this is the point at which the directory stops being a directory and becomes
something Officer can install.
The manifest holds only what a listing cannot say. One permission, grantable,
with ownerOnly on /_config — reading and editing the site is exactly what a
member might be brought in for, but the token is unrestricted write authority
over everything the public sees, so handing it over is the owner's.
db/schema.ts is ONE table and should stay that way. fofos owns its own Postgres
and its own media store; this holds a URL and a token. That is what makes the
strongest thing about this plugin true: no operation on it can destroy the
client's work, checkbox ticked or not, because none of it was ever here. A cache
would be the thin end of that.
The router mostly forwards. fofos's /api/admin already answers in the shape a
panel wants, so re-wrapping it would be a second place for the contract to drift.
Two things in it are load-bearing rather than style:
registerProxiedPrefix('/api/fofos-admin/media'). bodyParser calls parseBody on
multipart across the whole protected router, and Hono then caches the parsed
FormData — so asking for the bytes afterwards re-serialises them under a NEW
boundary while the ORIGINAL content-type header is what gets forwarded. Header
and body disagree and every upload fails with "Unexpected end of form".
Narrow to the one route: everything else is JSON that is fine to parse.
The catch-all is LAST in the file. Hono runs matching handlers in registration
order, so /* above /_config would swallow it and the settings form would
forward itself to fofos, which has no such endpoint — a 404 from a plugin that
is working perfectly.
Panels are a nav and a detail pane that never speak to each other: the nav writes
?section=, the detail pane reads it. Real <Link>s rather than the buttons
proxy-manager uses — AGENTS.md says nav items are links, and the file documenting
that pattern says not to copy the older one. <Link> and not <NavLink> because
active state here is a query parameter and NavLink compares paths, which would
light every row at once.
Which component renders which section is a MAP, not a conditional on `built`.
The first version read `built ? <MessagesPanel/> : <Planned/>`, which is correct
only while exactly one section exists — the second one finished would have
rendered Messages under its own name.
Messages is the only section built, chosen because it is one read-only route: it
proves the path from an Officer panel through this proxy to fofos and back with
nothing else able to be wrong at the same time. The other eight are in the nav,
dimmed and labelled, saying what they will do and that the old admin still edits
them. A nav that hides what is unfinished gives no sense of what the thing is for.
Typechecked against the platform — and the typechecker was verified to actually
cover plugins/ by planting an error and watching it fail, because a clean run
that does not include your files is worse than no run.
NOT yet: installed, or run against a live fofos. Nothing here has been through
the permission gate or a real request.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>