feat: synchronize governance templates in bulk
This commit is contained in:
@@ -575,6 +575,27 @@ export type GovernanceTemplateItem = {
|
||||
updated_at: string;
|
||||
};
|
||||
|
||||
export type GovernanceSynchronizationOutcome = {
|
||||
assignment_id: string;
|
||||
template_id: string;
|
||||
tenant_id: string;
|
||||
kind: "group" | "role";
|
||||
operation: "upsert" | "remove";
|
||||
status: "created" | "updated" | "unchanged" | "removed" | "absent" | "blocked" | "failed";
|
||||
resource_id?: string | null;
|
||||
blocker_codes: string[];
|
||||
message?: string | null;
|
||||
provenance: Record<string, string>;
|
||||
};
|
||||
|
||||
export type GovernanceSynchronizationResponse = {
|
||||
version: "1";
|
||||
operation_id: string;
|
||||
dry_run: boolean;
|
||||
outcomes: GovernanceSynchronizationOutcome[];
|
||||
counts: Record<string, number>;
|
||||
};
|
||||
|
||||
export type DataSubjectSelector = {
|
||||
account_id?: string | null;
|
||||
identity_id?: string | null;
|
||||
@@ -819,6 +840,17 @@ export function deleteGovernanceTemplate(settings: ApiSettings, templateId: stri
|
||||
return apiFetch(settings, apiPath(`/api/v1/admin/system/governance-templates/${templateId}`, { change_request_id: changeRequestId }), { method: "DELETE" });
|
||||
}
|
||||
|
||||
export function synchronizeGovernanceTemplates(
|
||||
settings: ApiSettings,
|
||||
templateIds: string[],
|
||||
dryRun = false
|
||||
): Promise<GovernanceSynchronizationResponse> {
|
||||
return apiFetch(settings, "/api/v1/admin/system/governance-templates/synchronize", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ template_ids: templateIds, dry_run: dryRun })
|
||||
});
|
||||
}
|
||||
|
||||
export async function fetchDataSubjectRequests(settings: ApiSettings): Promise<DataSubjectRequestSummary[]> {
|
||||
const response = await apiFetch<{ items: DataSubjectRequestSummary[] }>(settings, "/api/v1/admin/privacy/data-subject-requests");
|
||||
return response.items;
|
||||
|
||||
@@ -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" ?
|
||||
|
||||
@@ -517,6 +517,7 @@ export const generatedTranslations: PlatformTranslations = {
|
||||
"i18n:govoplan-admin.users.57f2b181": "Users",
|
||||
"i18n:govoplan-admin.valid_after.c615c873": "· Valid after:",
|
||||
"i18n:govoplan-admin.valid_and_trusted.73cf89bc": "Valid and trusted",
|
||||
"i18n:govoplan-admin.sync.905f6309": "Sync",
|
||||
"i18n:govoplan-admin.valid.a4aefa35": "Valid",
|
||||
"i18n:govoplan-admin.valid.b374b8f9": "Valid:",
|
||||
"i18n:govoplan-admin.value_deleted.3c4bf574": "{value0} deleted.",
|
||||
@@ -1052,6 +1053,7 @@ export const generatedTranslations: PlatformTranslations = {
|
||||
"i18n:govoplan-admin.user_retention_policy_limits": "Aufbewahrungslimits fuer benutzereigene Datensaetze.",
|
||||
"i18n:govoplan-admin.users.57f2b181": "Benutzer",
|
||||
"i18n:govoplan-admin.valid_after.c615c873": "· Valid after:",
|
||||
"i18n:govoplan-admin.sync.905f6309": "Synchronisieren",
|
||||
"i18n:govoplan-admin.valid_and_trusted.73cf89bc": "Valid and trusted",
|
||||
"i18n:govoplan-admin.valid.a4aefa35": "Gültig",
|
||||
"i18n:govoplan-admin.valid.b374b8f9": "Valid:",
|
||||
|
||||
Reference in New Issue
Block a user