import { useState } from "react"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import * as stylex from "@stylexjs/stylex"; import InlineError from "@/lib/InlineError"; import { upstreamCreateMutation, upstreamDeleteMutation, upstreamUpdateMutation, upstreamsQuery } from "@/lib/queries"; import type { Upstream, UpstreamInput } from "@/lib/types"; import ConfirmDialog from "@/ui/ConfirmDialog"; import FactLine from "@/ui/FactLine"; import { styles as shared } from "@/ui/styles"; import { colors } from "@/ui/tokens.stylex"; import Switch from "@/ui/Switch"; import AuthorityGate from "./AuthorityGate"; import FileModeNote from "./FileModeNote"; import QueryPanel from "./QueryPanel"; import UpstreamForm from "./UpstreamForm"; import { styles as config } from "./styles"; const INTRO = "The pool is rebuilt as you save, so an edit here applies to the next query."; /** * Narrower than the four columns side by side: below it the table keeps URL, * Enabled and the actions, and the URL cell carries the rest. */ const COMPACT = "@container (max-width: 42rem)"; const styles = stylex.create({ /** Cut to one line beside the other columns; whole, wrapping, where it is the row's only text column. */ url: { display: "block", maxWidth: "18rem", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: { default: "nowrap", [COMPACT]: "normal" }, overflowWrap: "anywhere", fontWeight: 500, }, unbroken: { overflowWrap: "anywhere", }, wide: { display: { default: null, [COMPACT]: "none" }, }, compact: { display: { default: "none", [COMPACT]: "block" }, marginTop: "0.125rem", color: colors.textMuted, overflowWrap: "anywhere", }, /** Stacked in the narrow form, which gives the first cell the width; the row is several lines tall there already. */ actions: { display: "flex", flexDirection: { default: null, [COMPACT]: "column" }, alignItems: { default: null, [COMPACT]: "flex-start" }, gap: { default: "0.75rem", [COMPACT]: "0.5rem" }, }, dimWhenDisabled: { opacity: { default: 1, ":disabled": 0.5 }, }, absent: { color: colors.textMuted, }, }); /** The hidden columns' facts for the compact URL cell; an empty TLS name has nothing to say there. */ function UpstreamFacts({ upstream }: { upstream: Upstream }) { const facts = [`Priority ${upstream.priority}`]; if (upstream.tls_name !== "") facts.push(`TLS name ${upstream.tls_name}`); return ( ); } export default function UpstreamsTab() { const upstreams = useQuery(upstreamsQuery()); return ( {(status) => (

{INTRO}

{status.authority === "managed_file" && } {(rows) => status.authority === "managed_file" ? ( ) : ( ) }
)}
); } function UpstreamsReadOnly({ upstreams }: { upstreams: Upstream[] }) { return (

Upstream pool upstreams

The resolvers nxdns forwards to when neither a local record nor the cache has the answer.

{upstreams.length === 0 ? (

The file declares no upstreams.

) : (
{upstreams.map((u) => ( ))}
URL Priority Enabled TLS name
{u.url} {u.priority} {String(u.enabled)} {u.tls_name === "" ? ( empty ) : ( u.tls_name )}
)}
); } function UpstreamsEditor({ upstreams }: { upstreams: Upstream[] }) { const queryClient = useQueryClient(); const [editing, setEditing] = useState(null); const [pendingDelete, setPendingDelete] = useState(null); const create = useMutation(upstreamCreateMutation(queryClient)); const save = useMutation(upstreamUpdateMutation(queryClient)); const toggle = useMutation(upstreamUpdateMutation(queryClient)); const remove = useMutation(upstreamDeleteMutation(queryClient)); async function submitForm(input: UpstreamInput) { if (editing === null) { await create.mutateAsync(input); } else { await save.mutateAsync({ id: editing.id, input }); setEditing(null); } } function toggleEnabled(u: Upstream) { toggle.mutate({ id: u.id, input: { url: u.url, priority: u.priority, enabled: !u.enabled, tls_name: u.tls_name }, }); } function confirmDelete() { if (pendingDelete === null) return; remove.mutate(pendingDelete.id); setPendingDelete(null); } const formError = editing === null ? create.error : save.error; const tableError = remove.error ?? toggle.error; return (
{upstreams.length === 0 ? (

No upstreams yet. Add one below.

) : (
{upstreams.map((u) => ( ))}
URL Priority Enabled TLS name Actions
{u.url} {u.priority} toggleEnabled(u)} /> {u.tls_name === "" ? "—" : u.tls_name}
)} setEditing(null)} /> setPendingDelete(null)} />
); }