import { useEffect, useMemo, useState } from "react"; import { Check, Download, Play, RefreshCw } from "lucide-react"; import type { ApiSettings } from "@govoplan/core-webui"; import { AdminPageLayout, Button, Card, StatusBadge, adminErrorMessage, i18nMessage } from "@govoplan/core-webui"; import { applyConfigurationPackage, createConfigurationChangeRequest, dryRunConfigurationPackage, exportConfigurationPackage, fetchConfigurationPackageCatalogValidation, type ConfigurationChangeRequest, type ConfigurationPackageDiagnostic, type ConfigurationPackagePlanItem, type ConfigurationPackageRequiredData } from "../../api/admin"; const SAMPLE_ACCESS_PACKAGE = { package_id: "govoplan.access.minimal-office", name: "i18n:govoplan-admin.minimal_office_access.af48f49a", version: "0.1.0", required_modules: [{ module_id: "access" }], required_capabilities: ["configuration.provider", "access.configuration"], fragments: [ { module_id: "access", fragment_type: "roles", payload: { items: [ { slug: "case-clerk", name: "i18n:govoplan-admin.case_clerk.b78a314a", description: "i18n:govoplan-admin.handles_incoming_administrative_work.dc80c349", permissions: ["admin:users:read"] }] } }, { module_id: "access", fragment_type: "groups", payload: { items: [{ slug: "front-office", name: "i18n:govoplan-admin.front_office.d9dcfee1" }] } }, { module_id: "access", fragment_type: "group_role_assignments", payload: { items: [{ group: "front-office", role: "case-clerk" }] } }] }; type DryRunResult = { diagnostics: ConfigurationPackageDiagnostic[]; required_data: ConfigurationPackageRequiredData[]; plan: ConfigurationPackagePlanItem[]; }; type ApplyResult = { diagnostics: ConfigurationPackageDiagnostic[]; created_refs: Record; updated_refs: Record; }; export default function ConfigurationPackagesPanel({ settings, canWrite }: {settings: ApiSettings;canWrite: boolean;}) { const [catalogValidation, setCatalogValidation] = useState | null>(null); const [packageText, setPackageText] = useState(() => JSON.stringify(SAMPLE_ACCESS_PACKAGE, null, 2)); const [tenantId, setTenantId] = useState(""); const [suppliedDataText, setSuppliedDataText] = useState("{}"); const [changeRequestId, setChangeRequestId] = useState(""); const [dryRun, setDryRun] = useState(null); const [applyResult, setApplyResult] = useState(null); const [exportText, setExportText] = useState(""); const [lastRequest, setLastRequest] = useState(null); const [loading, setLoading] = useState(true); const [busy, setBusy] = useState(""); const [error, setError] = useState(""); const [message, setMessage] = useState(""); const parsedPackage = useMemo(() => parseObject(packageText), [packageText]); const parsedSuppliedData = useMemo(() => parseObject(suppliedDataText), [suppliedDataText]); const canRun = Boolean(parsedPackage.value && parsedSuppliedData.value); async function loadCatalog() { setLoading(true); setError(""); try { const response = await fetchConfigurationPackageCatalogValidation(settings); setCatalogValidation(response.validation); } catch (err) { setError(adminErrorMessage(err)); } finally { setLoading(false); } } useEffect(() => {void loadCatalog();}, [settings.accessToken, settings.apiBaseUrl]); async function runDryRun() { const manifest = requireParsedPackage(); const suppliedData = requireParsedSuppliedData(); if (!manifest || !suppliedData) return; setBusy("dry-run"); setError(""); setMessage(""); setApplyResult(null); try { const result = await dryRunConfigurationPackage(settings, runPayload(manifest, suppliedData)); setDryRun(result); setMessage(result.diagnostics.some((item) => item.severity === "blocker") ? "i18n:govoplan-admin.preflight_finished_with_blockers.7e2ca12b" : "i18n:govoplan-admin.preflight_passed.c0c99055"); } catch (err) { setError(adminErrorMessage(err)); } finally { setBusy(""); } } async function requestApproval() { const manifest = requireParsedPackage(); if (!manifest) return; setBusy("approval"); setError(""); setMessage(""); try { const request = await createConfigurationChangeRequest(settings, { key: "configuration_packages.apply", value: manifest, dry_run: true, target: tenantId.trim() ? { tenant_id: tenantId.trim() } : {}, reason: "i18n:govoplan-admin.configuration_package_apply.c270e5f3" }); setLastRequest(request); setChangeRequestId(request.id); setMessage(i18nMessage("i18n:govoplan-admin.change_request_created_value.4af6d3d2", { value0: request.id })); } catch (err) { setError(adminErrorMessage(err)); } finally { setBusy(""); } } async function applyPackage() { const manifest = requireParsedPackage(); const suppliedData = requireParsedSuppliedData(); if (!manifest || !suppliedData) return; setBusy("apply"); setError(""); setMessage(""); try { const result = await applyConfigurationPackage(settings, runPayload(manifest, suppliedData, changeRequestId.trim() || null)); setApplyResult(result); setMessage(result.diagnostics.some((item) => item.severity === "blocker") ? "i18n:govoplan-admin.apply_finished_with_blockers.78487a12" : "i18n:govoplan-admin.package_applied.63782ce7"); } catch (err) { setError(adminErrorMessage(err)); } finally { setBusy(""); } } async function exportAccessPackage() { setBusy("export"); setError(""); setMessage(""); try { const result = await exportConfigurationPackage(settings, { tenant_id: tenantId.trim() || null, module_ids: ["access"], scopes: tenantId.trim() ? ["tenant"] : ["system"] }); const exported = { package_id: tenantId.trim() ? "govoplan.export.access-tenant" : "govoplan.export.access-system", name: tenantId.trim() ? "i18n:govoplan-admin.exported_tenant_access_configuration.9122c85c" : "i18n:govoplan-admin.exported_system_access_configuration.2e1c6f4c", version: "0.1.0", required_modules: [{ module_id: "access" }], required_capabilities: ["configuration.provider", "access.configuration"], fragments: result.fragments, data_requirements: result.data_requirements }; setExportText(JSON.stringify(exported, null, 2)); setMessage(result.diagnostics.some((item) => item.severity === "blocker") ? "i18n:govoplan-admin.export_finished_with_blockers.e2f70611" : "i18n:govoplan-admin.access_configuration_exported.098f200d"); } catch (err) { setError(adminErrorMessage(err)); } finally { setBusy(""); } } function runPayload(manifest: Record, suppliedData: Record, requestId?: string | null) { return { package: manifest, tenant_id: tenantId.trim() || null, supplied_data: suppliedData, change_request_id: requestId ?? null }; } function requireParsedPackage(): Record | null { if (!parsedPackage.value) { setError(parsedPackage.error || "i18n:govoplan-admin.package_json_must_be_an_object.db825bb3"); return null; } return parsedPackage.value; } function requireParsedSuppliedData(): Record | null { if (!parsedSuppliedData.value) { setError(parsedSuppliedData.error || "i18n:govoplan-admin.supplied_data_json_must_be_an_object.b265eb92"); return null; } return parsedSuppliedData.value; } return ( void loadCatalog()} disabled={loading || Boolean(busy)}> i18n:govoplan-admin.reload.cce71553}>
{catalogValidation?.signed !== undefined && } {catalogValidation?.trusted !== undefined && }
{JSON.stringify(catalogValidation ?? {}, null, 2)}