Complete governed reporting execution and publication

This commit is contained in:
2026-08-04 02:23:24 +02:00
parent a81151391b
commit 8337aec19a
29 changed files with 3611 additions and 81 deletions
@@ -0,0 +1,57 @@
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;
}