refactor(telemetry): chart scale labels, calmer vitals and error styling, usage-first tabs
- sparklines get start/end date and max-value footers - vitals rating shown by value color instead of badges - error rows use plain counts, subtle resolve button, terse empty state - telemetry tab order: usage, players, functions, events, errors; usage is default
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
import { Suspense, useMemo, useState } from "react";
|
||||
import { Trans, useLingui } from "@lingui/react/macro";
|
||||
import {
|
||||
Badge,
|
||||
Divider,
|
||||
Group,
|
||||
SegmentedControl,
|
||||
@@ -45,25 +44,18 @@ const vitalRating = (name: VitalName, value: number): "good" | "ok" | "poor" =>
|
||||
return "ok";
|
||||
};
|
||||
|
||||
const VitalBadge = ({ name, value }: { name: VitalName; value: number }) => {
|
||||
const vitalColor = (name: VitalName, value: number): string | undefined => {
|
||||
const rating = vitalRating(name, value);
|
||||
const color = rating === "good" ? "green" : rating === "ok" ? "yellow" : "red";
|
||||
return (
|
||||
<Badge color={color} variant="light" size="sm">
|
||||
{rating === "good" ? (
|
||||
<Trans>Good</Trans>
|
||||
) : rating === "ok" ? (
|
||||
<Trans>Needs improvement</Trans>
|
||||
) : (
|
||||
<Trans>Poor</Trans>
|
||||
)}
|
||||
</Badge>
|
||||
);
|
||||
if (rating === "good") return undefined;
|
||||
return rating === "ok" ? "yellow.8" : "red";
|
||||
};
|
||||
|
||||
const formatVital = (name: VitalName, value: number) =>
|
||||
name === "CLS" ? value.toFixed(2) : `${Math.round(value)}ms`;
|
||||
|
||||
const dayLabel = (i18n: { date: (d: Date, opts?: Intl.DateTimeFormatOptions) => string }, day: string) =>
|
||||
i18n.date(new Date(`${day}T12:00:00Z`), { month: "short", day: "numeric" });
|
||||
|
||||
const topItems = (totals: Map<string, number>, onClick?: (dim: string) => void) =>
|
||||
[...totals.entries()]
|
||||
.sort((a, b) => b[1] - a[1])
|
||||
@@ -75,6 +67,7 @@ const topItems = (totals: Map<string, number>, onClick?: (dim: string) => void)
|
||||
}));
|
||||
|
||||
const FnDurationDetail = ({ fn, from, to }: { fn: string; from: string; to: string }) => {
|
||||
const { i18n } = useLingui();
|
||||
const { data: rows } = useRollupRange({
|
||||
metrics: ["server_fn.duration.p50", "server_fn.duration.p95"],
|
||||
from,
|
||||
@@ -87,7 +80,17 @@ const FnDurationDetail = ({ fn, from, to }: { fn: string; from: string; to: stri
|
||||
|
||||
return (
|
||||
<Stack gap="xs">
|
||||
<Sparkline data={p50} series2={p95} height={64} showArea />
|
||||
<Sparkline
|
||||
data={p50}
|
||||
series2={p95}
|
||||
height={64}
|
||||
showArea
|
||||
scale={{
|
||||
start: dayLabel(i18n, from),
|
||||
end: dayLabel(i18n, to),
|
||||
formatValue: (value) => `${Math.round(value)}ms`,
|
||||
}}
|
||||
/>
|
||||
<Group gap="md">
|
||||
<Group gap={6}>
|
||||
<svg width={18} height={8} aria-hidden>
|
||||
@@ -119,7 +122,7 @@ const FnDurationDetail = ({ fn, from, to }: { fn: string; from: string; to: stri
|
||||
};
|
||||
|
||||
const UsageSections = ({ from, to }: { from: string; to: string }) => {
|
||||
const { t } = useLingui();
|
||||
const { t, i18n } = useLingui();
|
||||
const [selectedFn, setSelectedFn] = useState<string | null>(null);
|
||||
const { isOpen: fnDetailOpened, open: openFnDetail, close: closeFnDetail } = useSheet();
|
||||
|
||||
@@ -159,6 +162,7 @@ const UsageSections = ({ from, to }: { from: string; to: string }) => {
|
||||
label={<Trans>Daily active players</Trans>}
|
||||
value={(dauSeries[dauSeries.length - 1] ?? 0).toLocaleString()}
|
||||
spark={dauSeries}
|
||||
sparkScale={{ start: dayLabel(i18n, from), end: dayLabel(i18n, to) }}
|
||||
/>
|
||||
<SimpleGrid cols={3} spacing="sm">
|
||||
<StatTile
|
||||
@@ -200,9 +204,10 @@ const UsageSections = ({ from, to }: { from: string; to: string }) => {
|
||||
<Trans>Errors</Trans>
|
||||
</Title>
|
||||
<StatTile
|
||||
label={<Trans>Client errors per day</Trans>}
|
||||
label={<Trans>Client errors</Trans>}
|
||||
value={errorSeries.reduce((sum, value) => sum + value, 0).toLocaleString()}
|
||||
spark={errorSeries}
|
||||
sparkScale={{ start: dayLabel(i18n, from), end: dayLabel(i18n, to) }}
|
||||
/>
|
||||
</Stack>
|
||||
|
||||
@@ -218,7 +223,7 @@ const UsageSections = ({ from, to }: { from: string; to: string }) => {
|
||||
key={name}
|
||||
label={name}
|
||||
value={value !== undefined ? formatVital(name, value) : "—"}
|
||||
caption={value !== undefined ? <VitalBadge name={name} value={value} /> : undefined}
|
||||
valueColor={value !== undefined ? vitalColor(name, value) : undefined}
|
||||
/>
|
||||
))}
|
||||
</SimpleGrid>
|
||||
|
||||
Reference in New Issue
Block a user