Files
govoplan-reporting/webui/src/features/reporting/ReportingReportsWidget.tsx
T

58 lines
2.0 KiB
TypeScript

import { useCallback } from "react";
import { BarChart3 } from "lucide-react";
import { Link } from "react-router";
import {
DashboardWidgetList,
DismissibleAlert,
LoadingFrame,
StatusBadge,
useDashboardWidgetData,
type ApiSettings,
type DashboardWidgetConfiguration
} from "@govoplan/core-webui";
import { listDefinitions } from "../../api/reporting";
export default function ReportingReportsWidget({ settings, refreshKey, configuration }: {
settings: ApiSettings;
refreshKey: number;
configuration: DashboardWidgetConfiguration;
}) {
const maxItems = boundedNumber(configuration.maxItems, 5, 1, 12);
const load = useCallback(async () => {
const result = await listDefinitions(settings, {
kinds: ["report"],
status: ["active"],
limit: maxItems
});
return result.definitions.slice(0, maxItems);
}, [maxItems, settings]);
const { data, loading, error } = useDashboardWidgetData(load, refreshKey);
return (
<LoadingFrame loading={loading} label="Loading reports">
{error && <DismissibleAlert tone="warning" resetKey={error}>{error}</DismissibleAlert>}
<DashboardWidgetList
emptyText="No active reports are available."
items={(data ?? []).map((report) => ({
id: report.definition_id,
title: report.name,
detail: report.description || report.definition_key,
meta: `Revision ${report.revision}`,
leading: <BarChart3 size={17} aria-hidden="true" />,
trailing: <StatusBadge status={report.status} label={report.status} />,
to: "/reports"
}))}
/>
<div className="dashboard-contribution-footer">
<Link className="btn btn-secondary" to="/reports">Open reporting</Link>
</div>
</LoadingFrame>
);
}
function boundedNumber(value: unknown, fallback: number, minimum: number, maximum: number): number {
const numeric = typeof value === "number" ? value : Number(value);
return Number.isFinite(numeric) ? Math.max(minimum, Math.min(maximum, Math.round(numeric))) : fallback;
}