feat: add contextual retention guidance

This commit is contained in:
2026-08-17 17:42:26 +02:00
parent 65159dec5f
commit fba4117b0c
4 changed files with 127 additions and 10 deletions
@@ -8,6 +8,10 @@ const panel = readFileSync(resolve(webuiRoot, "src/features/policy/RetentionPoli
assert.match(panel, /<RetentionPolicyScopeManager/, "Policy delegates effective-policy blockers and provenance to the shared Core contract");
assert.match(panel, /contextId: "policy\.retention"/, "retention exposes stable contextual documentation");
assert.match(panel, /policy\.retention\.action\.dry-run/, "retention dry runs expose exact contextual help");
assert.match(panel, /policy\.retention\.action\.apply/, "destructive retention exposes exact contextual help");
assert.match(panel, /policy\.retention\.confirm-apply/, "retention confirmation exposes consequence and recovery help");
assert.match(panel, /helpModuleId="policy"/, "retention confirmation retains Policy as its documentation owner");
assert.match(panel, /disabledReason=\{actionDisabledReason\}/, "retention execution explains unavailable actions");
assert.match(panel, /<ConfirmDialog/, "destructive retention uses shared confirmation");
assert.match(panel, /<DataGrid/, "retention outcomes use the shared data-grid pattern");
@@ -190,6 +190,7 @@ export default function RetentionPoliciesPanel({ settings, scopeType, canWrite }
<AdminPageLayout
title={labels.title}
description={labels.description}
helpContextId="policy.retention"
loading={loadingTargets}
error={targetError || runError}
success={success}
@@ -199,6 +200,7 @@ export default function RetentionPoliciesPanel({ settings, scopeType, canWrite }
<Button
title="Reload policy targets"
aria-label="Reload policy targets"
helpContextId="policy.retention.action.reload-targets"
onClick={() => void loadTargets()}
disabled={loadingTargets}
disabledReason={loadingTargets ? "Policy targets are already loading." : undefined}
@@ -224,16 +226,17 @@ export default function RetentionPoliciesPanel({ settings, scopeType, canWrite }
<div className="retention-run-section">
<Card
title="Retention execution"
helpContextId="policy.retention.execution"
actions={<DocumentationHelpLink reference={RETENTION_DOCUMENTATION} label="i18n:govoplan-core.open_admin_documentation.6adbdae3" />}
>
<p className="muted small-note">Run the saved effective retention policy against retained platform data.</p>
<div className="button-row compact-actions subsection-bottom-actions">
<Button onClick={() => void runRetention(true)} disabled={Boolean(actionDisabledReason)} disabledReason={actionDisabledReason}>Dry run</Button>
<Button variant="danger" onClick={() => setConfirmRetentionRun(true)} disabled={Boolean(actionDisabledReason)} disabledReason={actionDisabledReason}>Apply retention</Button>
<Button helpContextId="policy.retention.action.dry-run" onClick={() => void runRetention(true)} disabled={Boolean(actionDisabledReason)} disabledReason={actionDisabledReason}>Dry run</Button>
<Button helpContextId="policy.retention.action.apply" variant="danger" onClick={() => setConfirmRetentionRun(true)} disabled={Boolean(actionDisabledReason)} disabledReason={actionDisabledReason}>Apply retention</Button>
</div>
</Card>
{retentionResult && (
<Card title="Latest retention outcome">
<Card title="Latest retention outcome" helpContextId="policy.retention.outcome">
<dl className="detail-list compact-detail-list">
<div>
<dt>Operation</dt>
@@ -259,6 +262,8 @@ export default function RetentionPoliciesPanel({ settings, scopeType, canWrite }
</AdminPageLayout>
<ConfirmDialog
open={confirmRetentionRun}
helpContextId="policy.retention.confirm-apply"
helpModuleId="policy"
title="Apply retention policy"
message="This will redact or delete eligible retained data according to the saved policy. The application cannot restore deleted content; the run and bounded outcome counts remain in audit evidence. Run a dry run first and verify recovery evidence before continuing."
confirmLabel="Apply retention"