mirror of
https://github.com/bulwarkmail/webmail.git
synced 2026-10-31 08:13:50 +00:00
61 lines
2.6 KiB
TypeScript
61 lines
2.6 KiB
TypeScript
import type { SettingsPolicy } from './types';
|
|
|
|
export interface KeyChanges {
|
|
added: string[];
|
|
changed: string[];
|
|
removed: string[];
|
|
}
|
|
|
|
/** What importing a policy file would change, for the preview before applying it. */
|
|
export interface PolicyChangeSummary {
|
|
scopes: KeyChanges;
|
|
features: KeyChanges;
|
|
restrictions: KeyChanges;
|
|
defaults: KeyChanges;
|
|
/** Organisation sections, by name (signature, session...). */
|
|
organisation: KeyChanges;
|
|
/** Other top-level parts (theme policy, plugins, push relays, sidebar apps). */
|
|
other: string[];
|
|
/** Nothing would change. */
|
|
unchanged: boolean;
|
|
}
|
|
|
|
const same = (a: unknown, b: unknown) => JSON.stringify(a) === JSON.stringify(b);
|
|
|
|
function keyChanges(before: Record<string, unknown> = {}, after: Record<string, unknown> = {}): KeyChanges {
|
|
const out: KeyChanges = { added: [], changed: [], removed: [] };
|
|
for (const key of Object.keys(after)) {
|
|
if (!(key in before)) out.added.push(key);
|
|
else if (!same(before[key], after[key])) out.changed.push(key);
|
|
}
|
|
for (const key of Object.keys(before)) if (!(key in after)) out.removed.push(key);
|
|
return out;
|
|
}
|
|
|
|
const empty = (c: KeyChanges) => c.added.length + c.changed.length + c.removed.length === 0;
|
|
|
|
/** Compares two complete policies (both as configManager stores them). */
|
|
export function summarizePolicyChange(current: SettingsPolicy, next: SettingsPolicy): PolicyChangeSummary {
|
|
const byId = (policy: SettingsPolicy) => Object.fromEntries((policy.scopes ?? []).map((s) => [s.label ? `${s.label} (${s.id})` : s.id, s]));
|
|
const summary: PolicyChangeSummary = {
|
|
scopes: keyChanges(byId(current), byId(next)),
|
|
features: keyChanges(current.features as unknown as Record<string, unknown>, next.features as unknown as Record<string, unknown>),
|
|
restrictions: keyChanges(current.restrictions, next.restrictions),
|
|
defaults: keyChanges(current.defaults, next.defaults),
|
|
organisation: keyChanges(
|
|
current.organisation as unknown as Record<string, unknown>,
|
|
next.organisation as unknown as Record<string, unknown>,
|
|
),
|
|
other: [],
|
|
unchanged: false,
|
|
};
|
|
const covered = new Set(['scopes', 'features', 'restrictions', 'defaults', 'organisation']);
|
|
for (const key of new Set([...Object.keys(current), ...Object.keys(next)])) {
|
|
if (covered.has(key)) continue;
|
|
if (!same((current as unknown as Record<string, unknown>)[key], (next as unknown as Record<string, unknown>)[key])) summary.other.push(key);
|
|
}
|
|
summary.unchanged = [summary.scopes, summary.features, summary.restrictions, summary.defaults, summary.organisation].every(empty)
|
|
&& summary.other.length === 0;
|
|
return summary;
|
|
}
|