Scroll the runs table, pick a range, and choose what a comparison plots against
Docs / docs (push) Successful in 35s
Playwright Tests / test-playwright (1, 2) (push) Failing after 3m14s
Playwright Tests / test-playwright (2, 2) (push) Failing after 1m44s
pre-commit / pre-commit (push) Failing after 3m54s
Test Backend / test-backend (push) Successful in 3m12s
Compose Smoke Test / test-compose (push) Successful in 32s
Playwright Tests / merge-reports (push) Failing after 1m28s
Docs / docs (push) Successful in 35s
Playwright Tests / test-playwright (1, 2) (push) Failing after 3m14s
Playwright Tests / test-playwright (2, 2) (push) Failing after 1m44s
pre-commit / pre-commit (push) Failing after 3m54s
Test Backend / test-backend (push) Successful in 3m12s
Compose Smoke Test / test-compose (push) Successful in 32s
Playwright Tests / merge-reports (push) Failing after 1m28s
This commit is contained in:
@@ -9,11 +9,14 @@ import {
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select"
|
||||
import { cn } from "@/lib/utils"
|
||||
import {
|
||||
compareQueryOptions,
|
||||
NO_CURVE,
|
||||
runMetricsQueryOptions,
|
||||
STEP_AXIS,
|
||||
shortenRunLabel,
|
||||
TIME_AXIS,
|
||||
} from "./queries"
|
||||
|
||||
/** The metrics one run recorded, in the order they are worth offering. */
|
||||
@@ -28,32 +31,41 @@ export function useMetricNames(runId: string | undefined) {
|
||||
}
|
||||
|
||||
/**
|
||||
* One metric across one or more runs, drawn on a step axis.
|
||||
* One metric across one or more runs.
|
||||
*
|
||||
* The endpoint answers in the chart widget's own series shape, so comparing
|
||||
* three curves and showing one are the same call with a different id list.
|
||||
*
|
||||
* `x` is what the readings are plotted against: the step they were recorded
|
||||
* at, the seconds since the run's own first one, or another metric of the same
|
||||
* runs. Never a clock — even "time" is an elapsed count, which is what makes
|
||||
* two runs started hours apart comparable.
|
||||
*/
|
||||
export function RunMetricChart({
|
||||
ids,
|
||||
metric,
|
||||
x = STEP_AXIS,
|
||||
refreshMs,
|
||||
className,
|
||||
}: {
|
||||
ids: string[]
|
||||
metric: string
|
||||
x?: string
|
||||
refreshMs?: number
|
||||
className?: string
|
||||
}) {
|
||||
const { data, isPending } = useQuery(
|
||||
compareQueryOptions(ids, metric, refreshMs),
|
||||
compareQueryOptions(ids, metric, x, refreshMs),
|
||||
)
|
||||
const lines = (data?.lines ?? []).slice(0, MAX_SERIES)
|
||||
const labels = lines.map((line) => shortenRunLabel(line.label))
|
||||
const plots: HistoryPoint[][] = lines.map((line) =>
|
||||
(line.points ?? []).map(([step, value]) => ({ ts: step, value })),
|
||||
(line.points ?? []).map(([at, value]) => ({ ts: at, value })),
|
||||
)
|
||||
const drawn = plots.reduce((total, plot) => total + plot.length, 0)
|
||||
|
||||
return (
|
||||
<div className="flex h-64 flex-col gap-2">
|
||||
<div className={cn("flex min-h-0 flex-col gap-2", className ?? "h-64")}>
|
||||
<UplotChart
|
||||
labels={labels}
|
||||
plots={plots}
|
||||
@@ -84,7 +96,7 @@ export function MetricPicker({
|
||||
if (names.length === 0) return null
|
||||
return (
|
||||
<Select value={value} onValueChange={onChange}>
|
||||
<SelectTrigger className="h-8 w-56">
|
||||
<SelectTrigger className="h-8 w-56" aria-label="Metric">
|
||||
<SelectValue placeholder="Metric" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
@@ -97,3 +109,44 @@ export function MetricPicker({
|
||||
</Select>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* What the comparison is plotted against.
|
||||
*
|
||||
* Doubles as the axis label — it sits directly above the chart, and naming the
|
||||
* axis twice is one caption too many.
|
||||
*/
|
||||
export function AxisPicker({
|
||||
names,
|
||||
metric,
|
||||
value,
|
||||
onChange,
|
||||
}: {
|
||||
names: string[]
|
||||
/** Excluded from the choices: a metric against itself is a straight line. */
|
||||
metric: string
|
||||
value: string
|
||||
onChange: (x: string) => void
|
||||
}) {
|
||||
const options = [
|
||||
{ value: STEP_AXIS, label: "vs step" },
|
||||
{ value: TIME_AXIS, label: "vs time (s)" },
|
||||
...names
|
||||
.filter((name) => name !== metric)
|
||||
.map((name) => ({ value: name, label: `vs ${name}` })),
|
||||
]
|
||||
return (
|
||||
<Select value={value} onValueChange={onChange}>
|
||||
<SelectTrigger className="h-8 w-44" aria-label="Plotted against">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{options.map((option) => (
|
||||
<SelectItem key={option.value} value={option.value}>
|
||||
{option.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user