/** * One query, explained in the order it met the pipeline. * * This is the body of the detail surface, with no route in it, because two * surfaces show it: the persisted detail page, which fetched the row by id, and * a live row, whose provenance arrived in the stream frame and which SQLite may * not have written yet. The related actions are links into routes, so the * caller passes them in already built. */ import type { ReactNode } from "react"; import * as stylex from "@stylexjs/stylex"; import { formatMicros, formatTime } from "@/lib/format"; import type { PolicyReason, Provenance } from "@/lib/types"; import { clientLabel, useClientNames } from "@/features/clients/clientNames"; import { policyActionLabel, policyReasonLabel, qclassName, rcodeName, routeKindLabel, } from "@/features/provenance/provenanceCopy"; import { qtypeName } from "@/features/provenance/qtype"; import { styles as shared } from "@/ui/styles"; import { colors } from "@/ui/tokens.stylex"; const styles = stylex.create({ heading: { marginTop: "0.5rem", fontSize: "1.5rem", lineHeight: "2rem", fontWeight: 600, wordBreak: "break-all", }, subtitle: { marginTop: "0.25rem", color: colors.textSecondary, }, /** The recorded facts, fenced off from the live links below them. */ record: { marginTop: "1rem", maxWidth: "48rem", borderRadius: "0.25rem", borderWidth: 1, borderStyle: "solid", borderColor: colors.border, backgroundColor: colors.surfaceRaised, padding: "1rem", }, recordNote: { fontSize: "0.8125rem", lineHeight: "1.25rem", color: colors.textMuted, }, section: { marginTop: "1rem", borderTopWidth: { default: 1, ":first-of-type": 0 }, borderTopStyle: "solid", borderTopColor: colors.border, paddingTop: { default: "1rem", ":first-of-type": 0 }, }, sectionHeading: { fontSize: "0.75rem", lineHeight: "1rem", fontWeight: 600, letterSpacing: "0.05em", textTransform: "uppercase", color: colors.textMuted, }, facts: { marginTop: "0.5rem", marginBottom: 0, display: "grid", gap: "0.375rem 1rem", gridTemplateColumns: { default: "auto", "@media (min-width: 640px)": "max-content 1fr", }, fontSize: "0.875rem", lineHeight: "1.25rem", }, term: { color: colors.textMuted, }, value: { margin: 0, wordBreak: "break-all", }, muted: { color: colors.textMuted, }, related: { marginTop: "1.5rem", maxWidth: "48rem", }, relatedHeading: { fontSize: "1.125rem", lineHeight: "1.75rem", fontWeight: 600, }, relatedNote: { marginTop: "0.25rem", fontSize: "0.875rem", lineHeight: "1.25rem", color: colors.textMuted, }, relatedList: { marginTop: "0.5rem", display: "flex", flexWrap: "wrap", gap: "0.75rem", fontSize: "0.875rem", lineHeight: "1.25rem", }, link: { color: colors.primaryOnSurface, }, }); /** The look of one related action, so every caller's links match. */ export const provenanceRelatedLink = styles.link; function Section({ title, children }: { title: string; children: ReactNode }) { return (

{title}

{children}
); } function Fact({ label, children }: { label: string; children: ReactNode }) { return ( <>
{label}
{children}
); } /** * A recorded name, in the face the rest of the interface gives to names. It * wraps the value rather than the row, so the prose that stands in for a * missing one is not set in the same typewriter face. */ function Mono({ children }: { children: string }) { return {children}; } /** An empty text field means the server recorded nothing there, never an empty value. */ function Absent({ children }: { children: string }) { return {children}; } /** * What an empty `matched` means. `no_match` is the only reason the matcher * itself records with nothing to show; every other empty one names a pipeline * step that answered before filtering — a local record, a forward zone, a pause * (see `PolicyReason` in src/storage/provenance.zig) — where "nothing matched" * would claim an evaluation that never happened. */ function unmatchedLabel(reason: PolicyReason): string { return reason === "no_match" ? "Nothing matched" : "The matcher never ran"; } interface Props { provenance: Provenance; /** * The log row this explains, or null for a frame read straight off the * stream. Null is the same fact `QuerySummary.id` carries: the event * precedes its own insert, so there is no row to name and none is invented. */ persistedId: number | null; /** The related-action links, built by whichever surface owns the routes. */ relatedActions: ReactNode; } export default function ProvenanceDetail({ provenance, persistedId, relatedActions }: Props) { const { request, group, policy, rewrites, route, response } = provenance; const clientNames = useClientNames(); const currentClient = clientLabel(request.client, clientNames); return ( <>

{request.domain}

{formatTime(request.time)} — {policyActionLabel(policy.action)} {/* The verdict alone reads as a success; a non-NOERROR answer says otherwise. */} {response.rcode !== 0 && ` — ${rcodeName(response.rcode)}`}

What was recorded when this query was answered. Group and blocklist names are the ones in force at that moment; they may have been renamed or deleted since. {persistedId === null && " This is the event as it was streamed; the query log may not have written it yet."}

{formatTime(request.time)} {request.domain} {request.client} {qtypeName(request.qtype)} {qclassName(request.qclass)}
{group.name === "" ? No group recorded : group.name} {group.id === null ? : group.id}
{policyActionLabel(policy.action)} {policyReasonLabel(policy.reason)} {policy.matched === "" ? ( {unmatchedLabel(policy.reason)} ) : ( {policy.matched} )} {policy.source_name === "" ? ( Not a blocklist decision ) : policy.source_id === null ? ( policy.source_name ) : ( `${policy.source_name} (#${policy.source_id})` )}
{rewrites.cname_target === "" ? ( The queried name was decided directly ) : ( {rewrites.cname_target} )} {rewrites.safe_search_target === "" ? ( No rewrite ) : ( {rewrites.safe_search_target} )}
{routeKindLabel(route.kind)} {route.forward_zone === "" ? : {route.forward_zone}} {route.upstream === "" ? No upstream exchange : {route.upstream}}
{rcodeName(response.rcode)} {response.duration_us === null ? ( Not measured ) : ( formatMicros(response.duration_us) )}
{/* A named region, because the Pause it may offer is not the only Pause on screen: the sidebar carries one too, and the two answer different questions. */}

These read the current configuration, which may no longer be the one that decided this query.

{currentClient !== null && (

{currentClient.learned ? ( <> Reverse DNS currently resolves {request.client} to{" "} {currentClient.text}. ) : ( <> The client list currently names {request.client} “{currentClient.text}”. )}

)}
{relatedActions}
); }