import { useCallback, useEffect, useRef, useState } from 'react';
import { Link, useSearchParams } from 'react-router';
import { Settings } from 'lucide-react';
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. `?config=1` renders the connection form over the top of
* whatever is selected, so settings are addressable too.
*
* ── The unconfigured check lives HERE, once ──
*
* Every section needs a connection, so every section would otherwise have to handle its absence and
* each would word it slightly differently. Asking `/status` once and rendering the connection form
* instead of any section is one answer for all nine, 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,
};
export const DetailPanel = () => {
const [params] = useSearchParams();
const raw = params.get('section');
const section: SectionKey = isSectionKey(raw) ? raw : DEFAULT_SECTION;
const showingConfig = params.get('config') === '1';
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…
;
}
if (showingConfig || !configured) return ;
const current = sectionFor(section);
// Everything but `config`, so the settings link keeps the section underneath it.
const configSearch = new URLSearchParams(params);
configSearch.set('config', '1');
const Panel = current.built ? PANELS[current.key] : undefined;
return (
{current.label}
{/* A real link, so the settings are addressable and cmd-clickable like anything else. */}
Connection