milestone 30: overview as a dashboard, explicit health contract, period aggregations
Gates / frontend (push) Successful in 1m32s
Gates / test (push) Successful in 1m54s
Gates / package (push) Successful in 5m28s
Gates / container (push) Successful in 14s
Gates / test-aarch64 (push) Failing after 3h10m0s
CI / gates (push) Failing after 3h11m55s

This commit is contained in:
2026-08-22 16:45:15 +02:00
parent 17422fac21
commit 648d9b4496
89 changed files with 7222 additions and 4239 deletions
+59 -9
View File
@@ -4,8 +4,9 @@ import { Link, Outlet, useNavigate } from "@tanstack/react-router";
import * as stylex from "@stylexjs/stylex";
import { useAuth } from "@/auth/store";
import InlineError from "@/lib/InlineError";
import { versionQuery } from "@/lib/queries";
import PauseWidget from "../features/pause/PauseWidget";
import { healthQuery, versionQuery } from "@/lib/queries";
import PauseControl from "@/features/pause/PauseControl";
import { diagnosticsBadge } from "./diagnosticsBadge";
import ReadOnlyConfigBanner from "../features/settings/ReadOnlyConfigBanner";
import RestartBanner from "../features/settings/RestartBanner";
import { styles as shared } from "@/ui/styles";
@@ -16,7 +17,7 @@ const WIDE = "@media (min-width: 768px)";
const DARK = "@media (prefers-color-scheme: dark)";
const NAV_ITEMS = [
{ to: "/", label: "Dashboard" },
{ to: "/overview", label: "Overview" },
{ to: "/activity", label: "Activity" },
{ to: "/clients", label: "Clients" },
{ to: "/groups", label: "Groups" },
@@ -35,12 +36,40 @@ const styles = stylex.create({
gap: "0.25rem",
},
navLink: {
display: "block",
display: "flex",
alignItems: "center",
gap: "0.5rem",
borderRadius: "0.25rem",
paddingInline: "0.75rem",
paddingBlock: "0.375rem",
textDecorationLine: "none",
},
navLabel: {
flex: 1,
},
/**
* Neutral chrome: the mark is the message, and a coloured pill here would be
* the page's loudest element on every route. Text and shape carry it.
*/
badge: {
minWidth: "1.25rem",
borderRadius: "0.625rem",
borderWidth: 1,
borderStyle: "solid",
borderColor: colors.borderStrong,
backgroundColor: colors.surfaceHover,
paddingInline: "0.375rem",
fontSize: "0.75rem",
lineHeight: "1.125rem",
fontWeight: 500,
textAlign: "center",
color: colors.textSecondary,
},
/** The control sits with the footer, not in the scrolling nav list above it. */
sidebarFooter: {
paddingInline: "1rem",
paddingTop: "0.75rem",
},
/** The current page reads as a filled chip, heavier than the hover fill. */
navActive: {
backgroundColor: { default: "oklch(92% 0.004 286.32)", [DARK]: "oklch(27.4% 0.006 286.033)" },
@@ -135,6 +164,8 @@ const styles = stylex.create({
});
function NavLinks({ onNavigate }: { onNavigate?: () => void }) {
const health = useQuery(healthQuery());
const badge = diagnosticsBadge(health.data, health.isError);
return (
<ul {...stylex.props(styles.navList)}>
{NAV_ITEMS.map((item) => (
@@ -142,7 +173,6 @@ function NavLinks({ onNavigate }: { onNavigate?: () => void }) {
<Link
to={item.to}
onClick={onNavigate}
activeOptions={{ exact: item.to === "/" }}
activeProps={{
"aria-current": "page",
className: stylex.props(styles.navActive).className,
@@ -150,7 +180,12 @@ function NavLinks({ onNavigate }: { onNavigate?: () => void }) {
inactiveProps={{ className: stylex.props(styles.navIdle).className }}
{...stylex.props(styles.navLink, shared.focusRing)}
>
{item.label}
<span {...stylex.props(styles.navLabel)}>{item.label}</span>
{item.to === "/diagnostics" && badge !== null && (
<span aria-label={badge.label} {...stylex.props(styles.badge)}>
{badge.text}
</span>
)}
</Link>
</li>
))}
@@ -158,6 +193,22 @@ function NavLinks({ onNavigate }: { onNavigate?: () => void }) {
);
}
/**
* The sidebar's foot, in both renderings. Pause is a runtime action on the whole
* resolver rather than on the page in front of the reader, which is why it sits
* with the version label instead of in the header of every route.
*/
function SidebarFooter() {
return (
<>
<div {...stylex.props(styles.sidebarFooter)}>
<PauseControl />
</div>
<VersionFooter />
</>
);
}
function VersionFooter() {
const { data } = useQuery(versionQuery());
return (
@@ -201,7 +252,7 @@ export default function AppShell() {
<nav aria-label="Main" {...stylex.props(styles.sidebarNav)}>
<NavLinks />
</nav>
<VersionFooter />
<SidebarFooter />
</aside>
<div {...stylex.props(styles.column)}>
<header {...stylex.props(styles.header)}>
@@ -216,7 +267,6 @@ export default function AppShell() {
</button>
<span {...stylex.props(styles.narrowBrand)}>nxdns</span>
<div {...stylex.props(styles.headerRight)}>
<PauseWidget />
<LogoutButton />
</div>
</header>
@@ -227,7 +277,7 @@ export default function AppShell() {
<nav aria-label="Main" {...stylex.props(styles.drawerNav)}>
<NavLinks onNavigate={() => setDrawerOpen(false)} />
</nav>
<VersionFooter />
<SidebarFooter />
</div>
)}
<main {...stylex.props(styles.main)}>