mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-11 13:52:20 +00:00
fix(gki): draw the index chart in a chart token
The custom metric chart drew its line in --primary, which put the index in the action colour right under the ketone series drawn in a chart token. Give the chart an optional series colour, default primary so a custom metric looks as before, and draw the index in --chart-4.
This commit is contained in:
1 parent
35b4e75a53
commit
8aa8379861
4 files changed
+78
-12
No files matched your search
@@ -88,7 +88,10 @@ describe("DELETE /api/cycle/feed-subscription", () => {
|
||||
m.findMany.mockResolvedValue([OLD, SUCCESSOR]);
|
||||
|
||||
await (DELETE as unknown as () => Promise<Response>)();
|
||||
expect(m.audit.mock.calls.map((c) => c[1].details.feedId)).toEqual([
|
||||
const calls = m.audit.mock.calls as unknown as Array<
|
||||
[string, { details: { feedId: string } }]
|
||||
>;
|
||||
expect(calls.map((c) => c[1].details.feedId)).toEqual([
|
||||
OLD.id,
|
||||
SUCCESSOR.id,
|
||||
]);
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { renderWithApp } from "../../../../tests/browser/render";
|
||||
import { CustomMetricChart } from "../custom-metric-chart";
|
||||
|
||||
/**
|
||||
* The line takes the series colour it is given (the GKI draws in a chart
|
||||
* token beside the ketone series) and keeps primary when it is given none,
|
||||
* so a custom metric's chart looks as it always has.
|
||||
*/
|
||||
|
||||
const NOW = Date.now();
|
||||
const ENTRIES = [3, 2, 1].map((daysAgo, i) => ({
|
||||
id: `e${i}`,
|
||||
customMetricId: "",
|
||||
value: 2 + i,
|
||||
unit: "",
|
||||
measuredAt: new Date(NOW - daysAgo * 86_400_000).toISOString(),
|
||||
note: null,
|
||||
}));
|
||||
|
||||
async function lineStroke(color?: string): Promise<string | null> {
|
||||
const { screen } = await renderWithApp(
|
||||
<div style={{ width: 600 }}>
|
||||
<CustomMetricChart
|
||||
name="Index"
|
||||
unit=""
|
||||
targetLow={null}
|
||||
targetHigh={null}
|
||||
decimals={1}
|
||||
entries={ENTRIES as never}
|
||||
{...(color ? { color } : {})}
|
||||
/>
|
||||
</div>,
|
||||
);
|
||||
const curve = () => screen.container.querySelector(".recharts-line-curve");
|
||||
await expect.poll(curve).not.toBeNull();
|
||||
return curve()!.getAttribute("stroke");
|
||||
}
|
||||
|
||||
describe("<CustomMetricChart> series colour", () => {
|
||||
it("draws the line in the colour it is given", async () => {
|
||||
expect(await lineStroke("var(--chart-4)")).toBe("var(--chart-4)");
|
||||
});
|
||||
|
||||
it("keeps primary by default", async () => {
|
||||
expect(await lineStroke()).toBe("var(--primary)");
|
||||
});
|
||||
});
|
||||
@@ -58,6 +58,22 @@ interface ChartPoint {
|
||||
value: number;
|
||||
}
|
||||
|
||||
/** The values and any target bound, padded by a tenth of their spread. */
|
||||
function yDomainOf(
|
||||
points: readonly ChartPoint[],
|
||||
targetLow: number | null,
|
||||
targetHigh: number | null,
|
||||
): [number, number] {
|
||||
const candidates = points.map((p) => p.value);
|
||||
if (targetLow != null) candidates.push(targetLow);
|
||||
if (targetHigh != null) candidates.push(targetHigh);
|
||||
if (candidates.length === 0) return [0, 1];
|
||||
const min = Math.min(...candidates);
|
||||
const max = Math.max(...candidates);
|
||||
const pad = (max - min || Math.abs(max) || 1) * 0.1;
|
||||
return [min - pad, max + pad];
|
||||
}
|
||||
|
||||
export function CustomMetricChart({
|
||||
entries,
|
||||
name,
|
||||
@@ -65,6 +81,7 @@ export function CustomMetricChart({
|
||||
targetLow,
|
||||
targetHigh,
|
||||
decimals,
|
||||
color = "var(--primary)",
|
||||
}: {
|
||||
/** The metric's name: the day's focus label and the data table's caption. */
|
||||
name: string;
|
||||
@@ -74,6 +91,8 @@ export function CustomMetricChart({
|
||||
targetLow: number | null;
|
||||
targetHigh: number | null;
|
||||
decimals: number | null;
|
||||
/** The series colour; a chart token where it sits beside other series. */
|
||||
color?: string;
|
||||
}) {
|
||||
const { t } = useTranslations();
|
||||
const fmt = useFormatters();
|
||||
@@ -99,16 +118,10 @@ export function CustomMetricChart({
|
||||
}));
|
||||
}, [entries, range, nowMs]);
|
||||
|
||||
const yDomain = useMemo<[number, number]>(() => {
|
||||
const candidates = points.map((p) => p.value);
|
||||
if (targetLow != null) candidates.push(targetLow);
|
||||
if (targetHigh != null) candidates.push(targetHigh);
|
||||
if (candidates.length === 0) return [0, 1];
|
||||
const min = Math.min(...candidates);
|
||||
const max = Math.max(...candidates);
|
||||
const pad = (max - min || Math.abs(max) || 1) * 0.1;
|
||||
return [min - pad, max + pad];
|
||||
}, [points, targetLow, targetHigh]);
|
||||
const yDomain = useMemo(
|
||||
() => yDomainOf(points, targetLow, targetHigh),
|
||||
[points, targetLow, targetHigh],
|
||||
);
|
||||
|
||||
// v1.42 — each value opens its day (the calendar day of its instant in
|
||||
// the record's zone) through the doors every day-linked chart has.
|
||||
@@ -134,7 +147,7 @@ export function CustomMetricChart({
|
||||
chartDays.openIndex !== undefined ? points[chartDays.openIndex] : undefined;
|
||||
|
||||
const animate = !prefersReducedMotion();
|
||||
const primary = "var(--primary)";
|
||||
const primary = color;
|
||||
|
||||
return (
|
||||
<div className="space-y-3">
|
||||
|
||||
@@ -96,6 +96,7 @@ export function GkiCard() {
|
||||
targetLow={null}
|
||||
targetHigh={null}
|
||||
decimals={1}
|
||||
color="var(--chart-4)"
|
||||
entries={points.map((p) => ({
|
||||
id: p.id,
|
||||
customMetricId: "",
|
||||
|
||||
Reference in new issue
Block a user