1import { createMemo, createSignal, type JSX, Show } from "solid-js";
2import type { Series } from "../types/model.ts";
3import { lastGood, Loaded } from "./Loaded.tsx";
4import { type MetricQuery, useMetric } from "./Metric.tsx";
5import { type ChartProps, TimeChart } from "./TimeChart.tsx";
6
7/** A chart's current value for its corner; `tip` is the next thing worth knowing about it. */
8export type Reading = { value: JSX.Element; tip?: string; stale?: boolean };
9
10/** A chart stacked with others on one time axis and crosshair, which only the `last` one labels. */
11export function Strip(props: Omit<ChartProps, "series" | "colors" | "inline" | "sync" | "timeAxis"> & MetricQuery & {
12 title: string;
13 height: number;
14 /** Multiplies every value, e.g. to turn cores into percent of the machine. */
15 scale?: number;
16 tabs?: JSX.Element;
17 now: (latest: Series[]) => Reading | undefined;
18 last?: boolean;
19}) {
20 const { data, refetch, shape } = useMetric(props);
21 const latest = lastGood(data);
22 const [hovered, setHovered] = createSignal(false);
23 return (
24 <section class="strip" aria-label={props.title}>
25 <div class="strip-head">
26 <h3>{props.title}</h3>
27 {props.tabs}
28 <span class="rule" />
29 <Show when={props.now(latest() ?? [])}>
30 {(now) => (
31 <span class="now" classList={{ stale: now().stale || hovered() }}
32 tabIndex={now().tip ? 0 : undefined} data-tip={now().tip}>
33 {now().value}
34 </span>
35 )}
36 </Show>
37 </div>
38 <Loaded data={data} what={`${props.title} history`} retry={refetch}
39 skeleton={<div class="skeleton" style={{ height: `${props.height}px` }} />}>
40 {(loaded) => {
41 const shaped = createMemo(() => {
42 const scale = props.scale ?? 1;
43 const shaped = shape(loaded());
44 // A lone line goes by the chart's name, so its hovered value reads "51% cpu".
45 const series = shaped.series.map((item) => ({
46 ...item, name: shaped.series.length === 1 ? props.title : item.name, v: item.v.map((v) => v && v * scale),
47 }));
48 return { ...shaped, series };
49 });
50 return (
51 <TimeChart series={shaped().series} colors={shaped().colors} format={props.format} stacked={props.stacked}
52 max={props.max} zero={props.zero} height={props.height} inline sync="strips" timeAxis={!!props.last}
53 onHover={(index) => setHovered(index !== null)} />
54 );
55 }}
56 </Loaded>
57 </section>
58 );
59}