feat: synchronize governance templates in bulk

This commit is contained in:
2026-08-20 19:47:02 +02:00
parent 935cee8ccd
commit 550c14b92e
9 changed files with 550 additions and 41 deletions
@@ -1,6 +1,6 @@
import { DescriptionItem, DescriptionList } from "@govoplan/core-webui";
import { useEffect, useMemo, useState } from "react";
import { Search, Pencil, Plus, Trash2 } from "lucide-react";
import { Search, Pencil, Plus, RefreshCw, Trash2 } from "lucide-react";
import type { FormGrid, ApiSettings } from "@govoplan/core-webui";
import { Button } from "@govoplan/core-webui";
import { ConfirmDialog } from "@govoplan/core-webui";
@@ -14,6 +14,7 @@ import {
fetchGovernanceTemplates,
fetchPermissionCatalog,
fetchTenants,
synchronizeGovernanceTemplates,
updateGovernanceTemplate,
type GovernanceAssignment,
type GovernanceTemplateItem,
@@ -168,6 +169,23 @@ export default function GovernanceTemplatesPanel({
{setBusy(false);}
}
async function synchronize(item: GovernanceTemplateItem) {
setBusy(true);
setError("");
try {
const result = await synchronizeGovernanceTemplates(settings, [item.id]);
const blocked = result.outcomes.filter((outcome) => outcome.status === "blocked" || outcome.status === "failed");
if (blocked.length) {
setError(blocked.map((outcome) => outcome.message || outcome.blocker_codes.join(", ")).join("; "));
} else {
setSuccess(i18nMessage("i18n:govoplan-admin.value_updated_and_synchronized_to_assigned_tenan.d136eef2", { value0: item.name }));
}
await load();
await onAuthRefresh();
} catch (err) {setError(adminErrorMessage(err));} finally
{setBusy(false);}
}
const columns = useMemo<DataGridColumn<GovernanceTemplateItem>[]>(() => [
{
id: "template", header: kind === "group" ? "i18n:govoplan-admin.group_template.973e0fa6" : "i18n:govoplan-admin.tenant_role.6b53115d", width: "minmax(240px, 1.2fr)", minWidth: 210, resizable: true, sticky: "start", sortable: true, filterable: true,
@@ -192,10 +210,11 @@ export default function GovernanceTemplatesPanel({
render: (row) => <TableActionGroup actions={[
{ id: "inspect", label: i18nMessage("i18n:govoplan-admin.inspect_value.9d5d1071", { value0: row.name }), icon: <Search />, onClick: () => setViewing(row) },
{ id: "edit", label: i18nMessage("i18n:govoplan-admin.edit_value.fad75899", { value0: row.name }), icon: <Pencil />, disabled: !canWrite, disabledReason: !canWrite ? ADMIN_INTERFACE_I18N.governanceWriteRequired : undefined, onClick: () => openEdit(row) },
{ id: "synchronize", label: "i18n:govoplan-admin.sync.905f6309", icon: <RefreshCw />, disabled: !canWrite || busy, disabledReason: !canWrite ? ADMIN_INTERFACE_I18N.governanceWriteRequired : busy ? ADMIN_INTERFACE_I18N.busy : undefined, onClick: () => void synchronize(row) },
{ id: "delete", label: i18nMessage("i18n:govoplan-admin.delete_value.4d18989e", { value0: row.name }), icon: <Trash2 />, variant: "danger", disabled: !canWrite, disabledReason: !canWrite ? ADMIN_INTERFACE_I18N.governanceWriteRequired : undefined, onClick: () => setDeleting(row) }
]} />
}],
[canWrite, kind, tenants]);
[busy, canWrite, kind, tenants]);
const title = kind === "group" ? "i18n:govoplan-admin.central_groups.5c9b5b66" : "i18n:govoplan-admin.tenant_roles.51aca82d";
const description = kind === "group" ?