import { useCallback } from "react"; import { Waypoints } from "lucide-react"; import { Link } from "react-router-dom"; import { DashboardWidgetList, DismissibleAlert, LoadingFrame, StatusBadge, useDashboardWidgetData, type ApiSettings, type DashboardWidgetConfiguration } from "@govoplan/core-webui"; import { listDataflowPipelines, type Pipeline } from "../../api/dataflow"; export default function DataflowPipelinesWidget({ settings, refreshKey, configuration }: { settings: ApiSettings; refreshKey: number; configuration: DashboardWidgetConfiguration; }) { const maxItems = numberSetting(configuration.maxItems, 5, 1, 12); const includeDrafts = configuration.includeDrafts !== false; const load = useCallback(async () => { const pipelines = await listDataflowPipelines(settings); return pipelines .filter((pipeline) => includeDrafts || pipeline.status !== "draft") .sort(comparePipelines) .slice(0, maxItems); }, [includeDrafts, maxItems, settings]); const { data: pipelines, loading, error } = useDashboardWidgetData( load, refreshKey ); return ( {error && ( {error} )} ({ id: pipeline.id, title: pipeline.name, detail: pipelineDescription(pipeline), meta: scopeLabel(pipeline), leading: ); } function comparePipelines(left: Pipeline, right: Pipeline): number { if (left.status !== right.status) { if (left.status === "active") return -1; if (right.status === "active") return 1; } return ( new Date(right.updated_at).getTime() - new Date(left.updated_at).getTime() ); } function pipelineDescription(pipeline: Pipeline): string { const nodeCount = pipeline.revision.graph.nodes.length; const kind = pipeline.governance.definition_kind === "template" ? "template" : "flow"; return `${nodeCount} ${nodeCount === 1 ? "node" : "nodes"} ยท ${kind}`; } function scopeLabel(pipeline: Pipeline): string { const scope = pipeline.governance.scope_type; return scope.charAt(0).toUpperCase() + scope.slice(1); } function numberSetting( 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.floor(numeric))) : fallback; }