Prepare v0.1.0 release dependencies

This commit is contained in:
2026-06-24 20:02:49 +02:00
parent ce30b4d054
commit 9c2b84a64a
27 changed files with 900 additions and 48 deletions

View File

@@ -13,6 +13,8 @@ import {
import Button from "../../components/Button";
import Card from "../../components/Card";
import DismissibleAlert from "../../components/DismissibleAlert";
import EffectivePolicyBlock, { EffectivePolicyValue } from "../../components/EffectivePolicyBlock";
import type { PolicySourcePathItem } from "../../components/PolicySourcePath";
import FormField from "../../components/FormField";
import ToggleSwitch from "../../components/ToggleSwitch";
@@ -158,6 +160,7 @@ export function RetentionPolicyEditor({
const [policy, setPolicy] = useState<PrivacyRetentionPolicyPatch>({});
const [effectivePolicy, setEffectivePolicy] = useState<PrivacyRetentionPolicy | null>(null);
const [parentPolicy, setParentPolicy] = useState<PrivacyRetentionPolicy | null>(null);
const [effectivePolicySources, setEffectivePolicySources] = useState<PolicySourcePathItem[]>([]);
const [loading, setLoading] = useState(false);
const [busy, setBusy] = useState(false);
const [error, setError] = useState("");
@@ -181,6 +184,7 @@ export function RetentionPolicyEditor({
setPolicy({});
setEffectivePolicy(null);
setParentPolicy(null);
setEffectivePolicySources([]);
return;
}
setLoading(true);
@@ -189,10 +193,12 @@ export function RetentionPolicyEditor({
setPolicy(isSystem ? normalizeFullPolicy(response.policy) : normalizePatch(response.policy));
setEffectivePolicy(normalizeFullPolicy(response.effective_policy));
setParentPolicy(response.parent_policy ? normalizeFullPolicy(response.parent_policy) : null);
setEffectivePolicySources(response.effective_policy_sources ?? []);
} catch (err) {
setPolicy({});
setEffectivePolicy(null);
setParentPolicy(null);
setEffectivePolicySources([]);
setError(errorMessage(err));
} finally {
setLoading(false);
@@ -210,6 +216,7 @@ export function RetentionPolicyEditor({
setPolicy(isSystem ? normalizeFullPolicy(response.policy) : normalizePatch(response.policy));
setEffectivePolicy(normalizeFullPolicy(response.effective_policy));
setParentPolicy(response.parent_policy ? normalizeFullPolicy(response.parent_policy) : null);
setEffectivePolicySources(response.effective_policy_sources ?? []);
setSuccess("Retention policy saved.");
} catch (err) {
setError(errorMessage(err));
@@ -316,19 +323,21 @@ export function RetentionPolicyEditor({
</section>
{effectivePolicy && (
<section className="retention-policy-section retention-policy-effective">
<h3>Effective policy</h3>
<div className="retention-policy-effective-grid">
<PolicyValue label="Raw JSON" value={effectivePolicy.store_raw_campaign_json ? "Stored" : "Disabled"} />
<PolicyValue label="Raw JSON days" value={daysLabel(effectivePolicy.raw_campaign_json_retention_days)} />
<PolicyValue label="Generated EML days" value={daysLabel(effectivePolicy.generated_eml_retention_days)} />
<PolicyValue label="Report detail days" value={daysLabel(effectivePolicy.stored_report_detail_retention_days)} />
<PolicyValue label="Mock mailbox days" value={daysLabel(effectivePolicy.mock_mailbox_retention_days)} />
<PolicyValue label="Audit detail days" value={daysLabel(effectivePolicy.audit_detail_retention_days)} />
<PolicyValue label="Audit detail" value={auditDetailLabel(effectivePolicy.audit_detail_level)} />
{showAllowColumn && <PolicyValue label="Lower limits" value={allowLowerSummary(effectivePolicy.allow_lower_level_limits)} />}
</div>
</section>
<EffectivePolicyBlock
title="Effective policy"
sourcePath={effectivePolicySources.length > 0 ? effectivePolicySources : retentionPolicySourcePath(scopeType)}
className="retention-policy-section retention-policy-effective"
gridClassName="retention-policy-effective-grid"
>
<EffectivePolicyValue label="Raw JSON" value={effectivePolicy.store_raw_campaign_json ? "Stored" : "Disabled"} />
<EffectivePolicyValue label="Raw JSON days" value={daysLabel(effectivePolicy.raw_campaign_json_retention_days)} />
<EffectivePolicyValue label="Generated EML days" value={daysLabel(effectivePolicy.generated_eml_retention_days)} />
<EffectivePolicyValue label="Report detail days" value={daysLabel(effectivePolicy.stored_report_detail_retention_days)} />
<EffectivePolicyValue label="Mock mailbox days" value={daysLabel(effectivePolicy.mock_mailbox_retention_days)} />
<EffectivePolicyValue label="Audit detail days" value={daysLabel(effectivePolicy.audit_detail_retention_days)} />
<EffectivePolicyValue label="Audit detail" value={auditDetailLabel(effectivePolicy.audit_detail_level)} />
{showAllowColumn && <EffectivePolicyValue label="Lower limits" value={allowLowerSummary(effectivePolicy.allow_lower_level_limits)} />}
</EffectivePolicyBlock>
)}
</div>
</Card>
@@ -399,10 +408,6 @@ function AuditDetailSelect({ value, includeInherit, disabled, onChange }: { valu
);
}
function PolicyValue({ label, value }: { label: string; value: string }) {
return <div><span>{label}</span><strong>{value}</strong></div>;
}
function rawJsonValue(value: boolean | undefined): RawJsonValue {
if (value === undefined) return "inherit";
return value ? "keep" : "disable";
@@ -440,6 +445,14 @@ function localPolicyCount(policy: PrivacyRetentionPolicyPatch): string {
return count === 0 ? "Fully inherited" : `${count} local override${count === 1 ? "" : "s"}`;
}
function retentionPolicySourcePath(scopeType: PrivacyRetentionPolicyScope): string[] {
if (scopeType === "system") return ["System"];
if (scopeType === "tenant") return ["System", "Tenant"];
if (scopeType === "user") return ["System", "Tenant", "User"];
if (scopeType === "group") return ["System", "Tenant", "Group"];
return ["System", "Tenant", "Owner policy", "Campaign"];
}
function normalizeAllowLimits(value: PrivacyRetentionLimitPermissionPatch | PrivacyRetentionLimitPermissions | null | undefined): PrivacyRetentionLimitPermissions {
return { ...defaultAllowLowerLevelLimits, ...(value ?? {}) };
}