import type { DnsOverride, Workspace } from "@yaakapp-internal/models"; import { patchModel } from "@yaakapp-internal/models"; import { useCallback, useId, useMemo } from "react"; import { fireAndForget } from "../lib/fireAndForget"; import { Button } from "./core/Button"; import { Checkbox } from "./core/Checkbox"; import { IconButton } from "./core/IconButton"; import { PlainInput } from "./core/PlainInput"; import { HStack, VStack } from "./core/Stacks"; import { Table, TableBody, TableCell, TableHead, TableHeaderCell, TableRow } from "./core/Table"; interface Props { workspace: Workspace; } interface DnsOverrideWithId extends DnsOverride { _id: string; } export function DnsOverridesEditor({ workspace }: Props) { const reactId = useId(); // Ensure each override has an internal ID for React keys const overridesWithIds = useMemo(() => { return workspace.settingDnsOverrides.map((override, index) => ({ ...override, _id: `${reactId}-${index}`, })); }, [workspace.settingDnsOverrides, reactId]); const handleChange = useCallback( (overrides: DnsOverride[]) => { fireAndForget(patchModel(workspace, { settingDnsOverrides: overrides })); }, [workspace], ); const handleAdd = useCallback(() => { const newOverride: DnsOverride = { hostname: "", ipv4: [""], ipv6: [], enabled: true, }; handleChange([...workspace.settingDnsOverrides, newOverride]); }, [workspace.settingDnsOverrides, handleChange]); const handleUpdate = useCallback( (index: number, update: Partial) => { const updated = workspace.settingDnsOverrides.map((o, i) => i === index ? { ...o, ...update } : o, ); handleChange(updated); }, [workspace.settingDnsOverrides, handleChange], ); const handleDelete = useCallback( (index: number) => { const updated = workspace.settingDnsOverrides.filter((_, i) => i !== index); handleChange(updated); }, [workspace.settingDnsOverrides, handleChange], ); return (
Override DNS resolution for specific hostnames. This works like{" "} /etc/hosts but only for requests made from this workspace.
{overridesWithIds.length > 0 && ( Hostname IPv4 Address IPv6 Address {overridesWithIds.map((override, index) => ( handleUpdate(index, update)} onDelete={() => handleDelete(index)} /> ))}
)}
); } interface DnsOverrideRowProps { override: DnsOverride; onUpdate: (update: Partial) => void; onDelete: () => void; } function DnsOverrideRow({ override, onUpdate, onDelete }: DnsOverrideRowProps) { const ipv4Value = override.ipv4.join(", "); const ipv6Value = override.ipv6.join(", "); return ( onUpdate({ enabled })} /> onUpdate({ hostname })} /> onUpdate({ ipv4: value .split(",") .map((s) => s.trim()) .filter(Boolean), }) } /> onUpdate({ ipv6: value .split(",") .map((s) => s.trim()) .filter(Boolean), }) } /> ); }