import { useCallback } from 'react'; import { Link } from 'react-router'; import { Loader2, TerminalSquare } from 'lucide-react'; import { headscaleSectionPath } from './shared'; import { useHeadscaleServers } from './useHeadscaleServers'; import { TerminalView } from 'officerdev'; import { Button } from './Cards'; // A shell on the machine behind the active Headscale server — the escape hatch for everything the API cannot // answer (why headscale won't start, what the logs say, whether the disk is full). // // It is deliberately the SAME terminal every other panel uses, driven by nothing more than `ssh ` typed // into a login shell. Officer holds no key, no password and no port: whatever `ssh` on this box can already // reach, this can reach, and nothing more. If the connection needs a jump host or an odd port, that belongs in // `~/.ssh/config` as a Host alias — which this field accepts by name. // // The session id is derived from the server id rather than minted per panel, so re-opening the Console lands // back in the shell that is already running and mid-command, and switching servers is a different shell rather // than the same one re-purposed. TerminalView suppresses its initial input when the sidecar replays a buffer, // which is what stops a re-attach from typing a second `ssh` inside the first. const consoleSessionId = (serverId: number) => `headscale-console-${serverId}`; const Centred = ({ children }: { children: React.ReactNode }) => (
{children}
); export const ConsoleView = () => { const { active, isLoading } = useHeadscaleServers(); // The terminal reports its connection state; nothing in this section acts on it yet, but TerminalView wants // a stable callback and an inline arrow would remount its effect on every render. const onConnectionChange = useCallback(() => {}, []); if (isLoading) { return (
Loading servers…
); } if (!active) { return (
No server selected

Pick one in the Servers section to open its console.

); } if (!active.sshHost) { return (
No SSH address for {active.name}

Add one on the server to open a shell on the machine behind it. Use the machine's own address rather than the Headscale hostname — the console is most useful exactly when that name has stopped answering.

); } return (
ssh {active.sshHost} · {active.name}
); };