import { useState } from 'react';
import { KeyRound, Plus, Trash2, TimerOff, Copy, Check, Loader2, ShieldAlert } from 'lucide-react';
import type { HeadscalePreAuthKey } from './shared';
import { useHeadscaleKeys, useHeadscaleUsers } from './useHeadscaleData';
import { useHeadscaleServers, headscaleErrorMessage } from './useHeadscaleServers';
import { timeAgo, timeUntil, fullDate } from './format';
import { Card, Button, Field, Badge, Dot, ErrorNote } from './Cards';
import { ViewShell, EmptyBody } from './ViewShell';
import { copyToClipboard } from 'helpers/clipboard';
// Pre-auth keys — the tokens a machine presents to join the tailnet.
//
// The whole screen is shaped by one fact: Headscale hashes keys, so the secret exists exactly once, in the
// create response. If this view renders it into a list, or lets a re-render drop it, the key is gone and the
// owner has to make another. Hence the show-once panel: it holds the secret in local state, offers the copy
// and the ready-to-paste join command, and only clears on an explicit dismiss.
//
// The list defaults to active keys because a long-lived server accumulates hundreds of spent ones.
const STATUS_FILTERS = [
{ id: 'active', label: 'Active' },
{ id: 'all', label: 'All' },
] as const;
type StatusFilter = (typeof STATUS_FILTERS)[number]['id'];
const STATUS_TONE = { active: 'ok', used: 'idle', expired: 'bad' } as const;
const CopyButton = ({ value, label }: { value: string; label: string }) => {
const [done, setDone] = useState(false);
const copy = () => {
void copyToClipboard(value);
setDone(true);
window.setTimeout(() => setDone(false), 1500);
};
return (
);
};
type SecretPanelProps = { secret: string; loginServer: string; onDismiss: () => void };
const SecretPanel = ({ secret, loginServer, onDismiss }: SecretPanelProps) => {
const command = `tailscale up --login-server ${loginServer} --authkey ${secret}`;
return (
Copy this key now
Headscale stores it hashed. Once you dismiss this, nothing — not Officer, not the server — can show it
again.