The Overview page takes the decided visual language (specs/ui-visual-redesign.md): four centred totals with their Activity links, a smoothed area chart of total and blocked queries with point hover and a tooltip beside the point, a stacked client chart in eight distinct hues plus one Other band, and a card row with the cache hit rate, the query types as a single-hue ramp ring, and the upstream breakdown. GET /api/overview takes a client parameter; the scoped read uses idx_query_log_ts and the cache keeps scoped slots. The device selector beside the period selector is URL state, so a scoped view is a link, and the tile links carry the scope into Activity. All numbers go through admin/src/lib/format.ts: grouped counts, two-decimal percentages, one-decimal rates, durations as the two largest nonzero units. A sweep test refuses toFixed, toLocaleString, Intl.NumberFormat and padStart anywhere else. Chrome: one 4px radius from the metrics constants, shared Card with a prominent title and description, the sidebar grouped into Monitoring and System with a status block (protection, queries per minute on Overview, uptime), and the accent darkened to 5.43:1 on its wash. Not built: the spec's ranked-list primitive, which has no consumer and no API rows. Codex could not review sessions B to D, its endpoint returned 404 for every call on 2026-09-03; the owner accepted the smoke-server screenshots.
128 lines
3.5 KiB
TypeScript
128 lines
3.5 KiB
TypeScript
/**
|
|
* The destructive-action confirmation (milestone 23, ruling 5), which replaces
|
|
* every `window.confirm` call in the app.
|
|
*
|
|
* `role="alertdialog"` rather than `dialog`: the message is the reason the
|
|
* dialog exists, so it is announced with the dialog instead of after it. The
|
|
* overlay is deliberately not dismissable — a delete needs an explicit answer,
|
|
* and a stray outside click is not one. Escape still cancels.
|
|
*/
|
|
|
|
import type { ReactNode } from "react";
|
|
import * as stylex from "@stylexjs/stylex";
|
|
import { Dialog as AriaDialog, Heading, Modal, ModalOverlay } from "react-aria-components";
|
|
import { colors, layers, metrics } from "./tokens.stylex";
|
|
import { styles as shared } from "./styles";
|
|
|
|
interface Props {
|
|
isOpen: boolean;
|
|
title: string;
|
|
/** The full sentence the operator reads before confirming; names the entity. */
|
|
message: string;
|
|
confirmLabel: string;
|
|
/**
|
|
* Stands in for the confirm action when the write can no longer land, the way
|
|
* an open edit dialog drops its Save. Closing the dialog instead would throw
|
|
* focus at a control that is now disabled and say nothing about why, so the
|
|
* question stays on screen and only the answer that would fail is withdrawn.
|
|
* Cancel is always live.
|
|
*/
|
|
lock?: ReactNode;
|
|
onConfirm: () => void;
|
|
onCancel: () => void;
|
|
}
|
|
|
|
const styles = stylex.create({
|
|
overlay: {
|
|
position: "fixed",
|
|
inset: 0,
|
|
zIndex: layers.confirm,
|
|
display: "flex",
|
|
alignItems: "center",
|
|
justifyContent: "center",
|
|
padding: "1rem",
|
|
backgroundColor: "rgba(0, 0, 0, 0.4)",
|
|
},
|
|
panel: {
|
|
width: "100%",
|
|
maxWidth: "26rem",
|
|
borderRadius: "0.5rem",
|
|
borderWidth: 1,
|
|
borderStyle: "solid",
|
|
borderColor: colors.dangerBorder,
|
|
backgroundColor: colors.surfaceRaised,
|
|
color: colors.text,
|
|
padding: "1.5rem",
|
|
boxShadow: "0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)",
|
|
},
|
|
body: {
|
|
outlineStyle: "none",
|
|
},
|
|
title: {
|
|
fontSize: "1.125rem",
|
|
lineHeight: "1.75rem",
|
|
fontWeight: 600,
|
|
},
|
|
message: {
|
|
marginTop: "0.5rem",
|
|
fontSize: "0.875rem",
|
|
lineHeight: "1.25rem",
|
|
color: colors.textMuted,
|
|
},
|
|
actions: {
|
|
display: "flex",
|
|
justifyContent: "flex-end",
|
|
gap: "0.5rem",
|
|
marginTop: "1.5rem",
|
|
},
|
|
dangerButton: {
|
|
cursor: { default: "pointer", ":disabled": "not-allowed" },
|
|
borderRadius: metrics.radius,
|
|
borderStyle: "none",
|
|
backgroundColor: colors.danger,
|
|
color: colors.primaryText,
|
|
paddingInline: "0.75rem",
|
|
paddingBlock: "0.375rem",
|
|
fontSize: "0.875rem",
|
|
lineHeight: "1.25rem",
|
|
fontWeight: 500,
|
|
},
|
|
});
|
|
|
|
export default function ConfirmDialog({ isOpen, title, message, confirmLabel, lock, onConfirm, onCancel }: Props) {
|
|
return (
|
|
<ModalOverlay
|
|
isOpen={isOpen}
|
|
onOpenChange={(open) => {
|
|
if (!open) onCancel();
|
|
}}
|
|
className={() => stylex.props(styles.overlay).className ?? ""}
|
|
>
|
|
<Modal className={() => stylex.props(styles.panel).className ?? ""}>
|
|
<AriaDialog role="alertdialog" {...stylex.props(styles.body)}>
|
|
<Heading slot="title" level={2} {...stylex.props(styles.title)}>
|
|
{title}
|
|
</Heading>
|
|
<p {...stylex.props(styles.message)}>{message}</p>
|
|
<div {...stylex.props(styles.actions)}>
|
|
<button type="button" onClick={onCancel} {...stylex.props(shared.button, shared.focusRing)}>
|
|
Cancel
|
|
</button>
|
|
{lock === undefined ? (
|
|
<button
|
|
type="button"
|
|
onClick={onConfirm}
|
|
{...stylex.props(styles.dangerButton, shared.focusRing)}
|
|
>
|
|
{confirmLabel}
|
|
</button>
|
|
) : (
|
|
lock
|
|
)}
|
|
</div>
|
|
</AriaDialog>
|
|
</Modal>
|
|
</ModalOverlay>
|
|
);
|
|
}
|