/** * Kennzahlen und Diagramme. * * Alle zwoelf Diagramme aus dem Plan erscheinen. Das eine ohne Datengrundlage * — die Ressourcenlast der Agenten — steht mit dabei und sagt, was fehlt. * Dieselbe Regel wie in der Uebersicht: Ein weggelassenes Diagramm sieht aus wie * ein vergessenes, ein leeres wie eine Anlage ohne Betrieb. */ import { useCallback, useState } from 'react'; import { useApiResource } from '@/api/useApiResource'; import { describeApiError } from '@/api/useMutation'; import { PageHeader } from '@/components/layout/PageHeader'; import { Card, CardContent, CardHeader, ErrorState, LoadingState, SelectInput } from '@/components/ui'; import { LineChart } from './LineChart'; import { fetchChart, fetchChartCatalog } from './metricsApi'; import type { Chart, ChartCatalog, ChartDefinition } from './metricsApi'; /** Auswaehlbare Zeitraeume mit ihrer Beschriftung. */ const RANGE_OPTIONS: readonly { readonly value: string; readonly label: string }[] = [ { value: '1h', label: 'Letzte Stunde' }, { value: '24h', label: 'Letzte 24 Stunden' }, { value: '7d', label: 'Letzte 7 Tage' }, { value: '30d', label: 'Letzte 30 Tage' }, { value: '90d', label: 'Letzte 90 Tage' }, { value: '1y', label: 'Letztes Jahr' }, ]; /** Zeigt die Kennzahlen. */ export function MetricsPage(): React.JSX.Element { const [selectedRange, setSelectedRange] = useState('7d'); const loadCatalog = useCallback((abortSignal: AbortSignal) => fetchChartCatalog(abortSignal), []); const { loadState, data, loadError, reload } = useApiResource(loadCatalog); return ( <> setSelectedRange(changeEvent.target.value)} > {RANGE_OPTIONS.map((rangeOption) => ( ))} } /> {loadState === 'loading' ? ( ) : null} {loadState === 'failed' && loadError !== null ? ( ) : null} {loadState === 'loaded' && data !== null ? (
{data.charts.map((chartDefinition) => ( ))}
) : null} ); } /** Eigenschaften einer Diagrammkachel. */ interface ChartCardProperties { /** Das darzustellende Diagramm. */ readonly definition: ChartDefinition; /** Der gewaehlte Zeitraum. */ readonly timeRange: string; } /** Zeigt ein einzelnes Diagramm. */ function ChartCard({ definition, timeRange }: ChartCardProperties): React.JSX.Element { const loadChart = useCallback( (abortSignal: AbortSignal) => fetchChart(definition.metric, timeRange, abortSignal), [definition.metric, timeRange], ); // Ein Diagramm ohne Datengrundlage wird gar nicht erst abgerufen: Der Server // antwortete mit 501, und ein Fehler in der Oberflaeche saehe aus wie eine // Stoerung. Es ist keine — die Funktion gibt es nur noch nicht. const { loadState, data, loadError, reload } = useApiResource( loadChart, definition.available ? `${definition.metric}|${timeRange}` : 'unavailable', ); if (!definition.available) { return (

{definition.unavailable_reason}

); } return ( {loadState === 'loading' ? : null} {loadState === 'failed' && loadError !== null ? ( ) : null} {loadState === 'loaded' && data !== null ? ( <> {/* Der Hinweis ordnet ein, was die Kurve wert ist: Zwei Punkte sehen aus wie ein Trend und sind keiner. */} {data.note !== undefined && data.note !== '' ? (

{data.note}

) : null} ) : null}
); }