import { useCallback, useEffect, useState } from "react"; import type { AnalyticsGroup, Coverage } from "../api/analytics-types.ts"; import { api } from "../api/client.ts"; import { AnalyticsPanels } from "./analytics-panels.tsx"; // The footnote every panel is read under. Two of the three classes of row // were reconstructed rather than observed, and a chart that does not say so // is a chart that quietly overstates what is known. export function Sources({ coverage: measured }: Readonly<{ coverage: Coverage }>): React.JSX.Element { return (

{measured.events} recorded {measured.events === 1 ? "use" : "uses"} over{" "} {measured.days} {measured.days === 1 ? "day" : "days"} {measured.first_day === "" ? "" : ` (${measured.first_day} – ${measured.last_day})`}.{" "} {measured.sources.live} observed live,{" "} {measured.sources.journald} reconstructed from the journal with a real hour,{" "} {measured.sources.daily_uses} recovered as daily counts with no hour at all — those are counted everywhere and excluded from every chart with an hour on its axis, because they have none. {measured.enough_for_a_trend ? "" : " Too few days to state a trend; the series is drawn, the direction is not claimed."}

); } export function Analytics(): React.JSX.Element { const [groups, setGroups] = useState(null); const [group, setGroup] = useState(null); const refresh = useCallback(() => { void api.analyticsGroups().then((body) => { setGroups(body.groups); }); }, []); useEffect(refresh, [refresh]); const pick = useCallback((event: React.ChangeEvent) => { setGroup(event.target.value === "" ? null : event.target.value); }, []); if (groups === null) { return

Reading the database…

; } return (

Analytics

); }