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
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:
@@ -0,0 +1,178 @@
|
||||
/**
|
||||
* The five health conditions, compactly, at the top of the page that explains
|
||||
* failures. Healthy conditions stay quiet; a degraded one is highlighted and
|
||||
* offers the way out.
|
||||
*
|
||||
* A degraded condition whose explanation is on this page narrows this page
|
||||
* rather than navigating away: the filter link sets `component` and drops every
|
||||
* other filter. A time window, a severity or a `state=resolved` left from an
|
||||
* earlier investigation would each hide the very episode the reader was sent to
|
||||
* read, and a link that lands on "no events" states something false.
|
||||
*
|
||||
* The load contract is the one the deleted Overview status section carried: a
|
||||
* visible loading state before the first reading, and a refetch failure that
|
||||
* says so — the conditions on screen become the last reading that arrived, never
|
||||
* a claim about the current state, until a poll succeeds again.
|
||||
*/
|
||||
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { Link } from "@tanstack/react-router";
|
||||
import * as stylex from "@stylexjs/stylex";
|
||||
import InlineError from "@/lib/InlineError";
|
||||
import { healthQuery } from "@/lib/queries";
|
||||
import { styles as shared } from "@/ui/styles";
|
||||
import { colors } from "@/ui/tokens.stylex";
|
||||
import { healthFacts, type FactLink, type FactTone, type HealthFact } from "./healthFacts";
|
||||
|
||||
const DARK = "@media (prefers-color-scheme: dark)";
|
||||
|
||||
const styles = stylex.create({
|
||||
list: {
|
||||
marginTop: "0.75rem",
|
||||
display: "grid",
|
||||
gap: "0.5rem",
|
||||
// Five is prime, so every count between one and five leaves a short last
|
||||
// row; three columns made it 3 then 2, which reads as a layout that ran out
|
||||
// of room rather than one that chose. So the strip goes from one column
|
||||
// straight to two and then to a single row of five, and is never ragged.
|
||||
gridTemplateColumns: {
|
||||
default: "minmax(0, 1fr)",
|
||||
"@media (min-width: 640px)": "repeat(2, minmax(0, 1fr))",
|
||||
"@media (min-width: 1100px)": "repeat(5, minmax(0, 1fr))",
|
||||
},
|
||||
listStyleType: "none",
|
||||
padding: 0,
|
||||
},
|
||||
fact: {
|
||||
display: "flex",
|
||||
flexWrap: "wrap",
|
||||
alignItems: "baseline",
|
||||
gap: "0.375rem",
|
||||
borderRadius: "0.25rem",
|
||||
borderWidth: 1,
|
||||
borderStyle: "solid",
|
||||
paddingInline: "0.625rem",
|
||||
paddingBlock: "0.5rem",
|
||||
fontSize: "0.875rem",
|
||||
lineHeight: "1.25rem",
|
||||
},
|
||||
/** Quiet: a healthy condition is the normal state and gets no emphasis. */
|
||||
quiet: {
|
||||
borderColor: colors.border,
|
||||
backgroundColor: "transparent",
|
||||
},
|
||||
highlighted: {
|
||||
borderColor: colors.borderStrong,
|
||||
backgroundColor: colors.surfaceRaised,
|
||||
},
|
||||
label: {
|
||||
color: colors.textSecondary,
|
||||
},
|
||||
value: {
|
||||
fontWeight: 500,
|
||||
},
|
||||
detail: {
|
||||
flexBasis: "100%",
|
||||
fontSize: "0.75rem",
|
||||
lineHeight: "1rem",
|
||||
color: colors.textMuted,
|
||||
},
|
||||
link: {
|
||||
fontSize: "0.875rem",
|
||||
lineHeight: "1.25rem",
|
||||
color: colors.primaryOnSurface,
|
||||
textDecorationLine: "none",
|
||||
},
|
||||
ok: {
|
||||
color: { default: "oklch(43.2% 0.095 166.913)", [DARK]: "oklch(84.5% 0.143 164.978)" },
|
||||
},
|
||||
notice: {
|
||||
color: { default: "oklch(47.3% 0.137 46.201)", [DARK]: "oklch(87.9% 0.169 91.605)" },
|
||||
},
|
||||
warn: {
|
||||
color: { default: "oklch(47.3% 0.137 46.201)", [DARK]: "oklch(87.9% 0.169 91.605)" },
|
||||
},
|
||||
danger: {
|
||||
color: colors.dangerText,
|
||||
},
|
||||
message: {
|
||||
marginTop: "0.5rem",
|
||||
fontSize: "0.875rem",
|
||||
lineHeight: "1.25rem",
|
||||
color: colors.textMuted,
|
||||
},
|
||||
});
|
||||
|
||||
const TONES = { ok: styles.ok, notice: styles.notice, warn: styles.warn, danger: styles.danger } as const;
|
||||
|
||||
/** Text and icon carry the state; the colour only agrees with them. */
|
||||
const ICONS: Record<FactTone, string> = { ok: "●", notice: "‖", warn: "!", danger: "✕" };
|
||||
|
||||
function FactLinkAnchor({ link }: { link: FactLink }) {
|
||||
if (link.kind === "filter") {
|
||||
return (
|
||||
<Link
|
||||
to="/diagnostics"
|
||||
// Sets the component and clears every filter that could hide what it
|
||||
// points at: a time window from an older investigation, and a severity
|
||||
// or state — `resolved` above all — that would exclude the very episode
|
||||
// explaining the condition this link came from.
|
||||
search={() => ({ component: link.component })}
|
||||
{...stylex.props(styles.link, shared.focusRing)}
|
||||
>
|
||||
{link.label}
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Link to={link.to} {...stylex.props(styles.link, shared.focusRing)}>
|
||||
{link.label}
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
|
||||
function Fact({ fact }: { fact: HealthFact }) {
|
||||
return (
|
||||
<li {...stylex.props(styles.fact, fact.tone === "ok" ? styles.quiet : styles.highlighted)}>
|
||||
<span aria-hidden="true" {...stylex.props(TONES[fact.tone])}>
|
||||
{ICONS[fact.tone]}
|
||||
</span>
|
||||
<span {...stylex.props(styles.label)}>{fact.label}</span>
|
||||
<span {...stylex.props(styles.value, TONES[fact.tone])}>{fact.value}</span>
|
||||
{fact.link !== undefined && <FactLinkAnchor link={fact.link} />}
|
||||
{fact.detail !== undefined && <span {...stylex.props(styles.detail)}>{fact.detail}</span>}
|
||||
</li>
|
||||
);
|
||||
}
|
||||
|
||||
export default function HealthStrip() {
|
||||
const health = useQuery(healthQuery());
|
||||
|
||||
if (health.data === undefined) {
|
||||
return health.isError ? (
|
||||
<InlineError error={health.error} onRetry={() => void health.refetch()} />
|
||||
) : (
|
||||
<p role="status" {...stylex.props(styles.message, shared.pulse)}>
|
||||
Loading status…
|
||||
</p>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<ul aria-label="Current status" {...stylex.props(styles.list)}>
|
||||
{healthFacts(health.data).map((fact) => (
|
||||
<Fact key={fact.key} fact={fact} />
|
||||
))}
|
||||
</ul>
|
||||
{health.isError && (
|
||||
<>
|
||||
<p role="status" {...stylex.props(styles.message)}>
|
||||
This is the last reading that arrived. The current state is unknown.
|
||||
</p>
|
||||
<InlineError error={health.error} onRetry={() => void health.refetch()} />
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user