import { useCallback, useEffect, useRef, useState } from 'react'; import { useSearchParams } from 'react-router'; import { useClient } from 'hooks/useClient'; import { DEFAULT_SECTION, isSectionKey, sectionFor, type SectionKey } from './sections'; import { ConnectionPanel } from './ConnectionPanel'; import { MessagesPanel } from './MessagesPanel'; import { PlannedSection } from './PlannedSection'; import { useFofosChanged } from './channel'; /** * The right column: whichever section the nav has selected. * * It reads `?section=` from the URL rather than being handed it — the two panels are siblings in a * workspace and neither owns the other. * * ── There used to be a `?config=1` ── * * The connection form was an overlay reached from a link in this header, because it was not one of the * sections. Now it IS one — Administration — so the overlay is gone and so is the link. A second route * to the same screen is a second thing to keep correct, and the two disagreed the moment a section was * selected underneath a form that covered it. * * ── The unconfigured check lives HERE, once ── * * Every OTHER section needs a connection, so each would otherwise have to handle its absence and each * would word it slightly differently. Asking `/status` once and sending an unconfigured plugin to * Administration is one answer for all of them, and it makes "not connected yet" read as a setup step * rather than as nine broken lists. */ type Status = { configured: boolean; lastProbeOk: boolean | null }; /** * Which component renders which section. * * A map rather than a conditional on `built`. The version of this that read * `built ? : ` was correct only while exactly one section existed — the * second one to be finished would have rendered Messages under its own name, which is the kind of bug * that looks like a data problem for an hour. A key with no entry here falls through to Planned, so * marking a section `built` in sections.ts without writing its panel fails visibly rather than * silently showing somebody else's. */ const PANELS: Partial React.JSX.Element>> = { messages: MessagesPanel, administration: ConnectionPanel, }; export const DetailPanel = () => { const [params] = useSearchParams(); const raw = params.get('section'); const selected: SectionKey = isSectionKey(raw) ? raw : DEFAULT_SECTION; const client = useClient(); const clientRef = useRef(client); clientRef.current = client; const [configured, setConfigured] = useState(null); const [signal] = useFofosChanged(); const check = useCallback(async () => { try { const status = await clientRef.current.get('/fofos-admin/status'); setConfigured(status.configured); } catch { // Cannot tell. Render the section rather than the setup form — a transient failure must not look // like "you have not set this up", which is a much more alarming thing to be told, and would // invite somebody to re-enter a connection that was never the problem. setConfigured(true); } }, []); useEffect(() => { void check(); }, [check, signal]); if (configured === null) { return
Loading…
; } /* Unconfigured, so Administration regardless of what the nav says. The header then NAMES it, which is the part the overlay could not do: the form used to appear under whichever row happened to be highlighted, so it read as that section being broken rather than as one step not done yet. */ const current = sectionFor(configured ? selected : 'administration'); const Panel = current.built ? PANELS[current.key] : undefined; return (

{current.label}

{current.hint}
{Panel ? : }
); };