58 lines
2.0 KiB
TypeScript
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;
|
|
}
|