import { useMemo, useState } from 'react'; import { Check, Loader2, Sparkles, Wand2, X } from 'lucide-react'; import { useHeadscalePolicyAssist, assistFailure } from './useHeadscalePolicy'; import { collapseUnchanged, diffCounts, diffLines } from './diff'; import { Button, Card, ErrorNote } from './Cards'; // Ask for a policy change in English; read the diff; decide. // // The whole point of this panel is the middle step. The model is good at the grammar — HuJSON, tagOwners, // the src/dst shapes — and has no idea which of the owner's machines matter, so its proposal is a draft to // be read, not an answer to be trusted. Nothing here writes to Headscale: Apply puts the text in the editor // above and the existing Save button is still the only thing that leaves the browser. // // The diff is against what is CURRENTLY in the editor, which is also what was sent up, so it always shows // exactly what accepting would change on screen — including edits the owner made and hasn't saved. const EXAMPLES = [ 'let everyone reach the machines tagged tag:server on port 22', 'stop the phones from reaching anything except the DNS server', 'add a group for family with just my own user in it', ]; const DiffBody = ({ before, after }: { before: string; after: string }) => { const lines = useMemo(() => diffLines(before, after), [before, after]); const rows = useMemo(() => collapseUnchanged(lines), [lines]); const { added, removed } = useMemo(() => diffCounts(lines), [lines]); if (!added && !removed) { return
No change — the proposal matches what you have.
; } return ( <>{proposal.explanation}
)}