Files
beavergram/frontend/src/lib/format/policy.ts
T

169 lines
4.7 KiB
TypeScript

import type { CaptureToggles, PolicyScopeType } from "#lib/api/types.js";
import { t } from "#lib/i18n/locale.svelte.js";
export type ToggleKey = keyof CaptureToggles;
type DefaultScope = "channel" | "dm" | "group";
export const TOGGLE_KEYS: ToggleKey[] = [
"messages",
"media",
"self_destruct_media",
"stt",
"reactions",
"track_edits_deletes",
"profile_history",
"stories",
"presence",
"backfill",
];
const DEFAULT_SCOPES: Partial<Record<PolicyScopeType, DefaultScope>> = {
default_channel: "channel",
default_dm: "dm",
default_group: "group",
};
const SHOWN_CHIPS = 3;
const SHORT_LIST = 2;
export interface Chip {
hint?: string;
label: string;
sign: "plus" | "minus";
}
export function toggleLabel(key: ToggleKey): string {
return t(`policy.toggle.${key}`);
}
function exceptLabel(key: ToggleKey): string {
return t(`policy.except.${key}`);
}
export function defaultLabel(scopeType: PolicyScopeType): string {
const scope = DEFAULT_SCOPES[scopeType];
return scope ? t(`policy.default.${scope}`) : "";
}
export function pickToggles(source: CaptureToggles): CaptureToggles {
return {
backfill: source.backfill,
media: source.media,
messages: source.messages,
presence: source.presence,
profile_history: source.profile_history,
reactions: source.reactions,
self_destruct_media: source.self_destruct_media,
stories: source.stories,
stt: source.stt,
track_edits_deletes: source.track_edits_deletes,
};
}
export function preset(only: ToggleKey[] | "all"): CaptureToggles {
const toggles = {} as CaptureToggles;
for (const key of TOGGLE_KEYS) {
toggles[key] = only === "all" || only.includes(key);
}
return toggles;
}
export function sameToggles(a: CaptureToggles, b: CaptureToggles): boolean {
return TOGGLE_KEYS.every((key) => a[key] === b[key]);
}
function exceptList(keys: ToggleKey[]): string {
const [first, second] = keys.map(exceptLabel);
return second === undefined
? (first ?? "")
: t("policy.summary.pair", { a: first ?? "", b: second });
}
export function summary(toggles: CaptureToggles): string {
const on = TOGGLE_KEYS.filter((key) => toggles[key]);
const off = TOGGLE_KEYS.filter((key) => !toggles[key]);
if (off.length === 0) {
return t("policy.summary.all");
}
if (on.length === 0) {
return t("policy.summary.none");
}
if (on.length === 1 && on[0] === "messages") {
return t("policy.summary.messagesOnly");
}
if (off.length <= SHORT_LIST) {
return t("policy.summary.except", { list: exceptList(off) });
}
const names = on.slice(0, SHORT_LIST).map(toggleLabel).join(", ");
const rest = on.length - SHORT_LIST;
return rest > 0 ? t("policy.summary.more", { count: rest, names }) : names;
}
export function parentLabel(
scopeType: PolicyScopeType,
title: string | null
): string {
if (scopeType === "folder") {
return t("policy.parent.folder", {
title: title ?? t("policy.parent.untitled"),
});
}
const scope = DEFAULT_SCOPES[scopeType];
return scope ? t(`policy.parent.${scope}`) : t("policy.parent.default");
}
function labelList(keys: ToggleKey[]): string {
return keys.map(toggleLabel).join(", ");
}
function named(keys: ToggleKey[], sign: Chip["sign"]): Chip[] {
return keys.map((key) => ({ label: toggleLabel(key), sign }));
}
function counted(keys: ToggleKey[], sign: Chip["sign"]): Chip[] {
if (keys.length === 0) {
return [];
}
if (keys.length <= SHOWN_CHIPS) {
return named(keys, sign);
}
return [
{
hint: labelList(keys),
label: t("policy.chip.settings", { count: keys.length }),
sign,
},
];
}
export function contentChips(rule: CaptureToggles): Chip[] {
const on = TOGGLE_KEYS.filter((key) => rule[key]);
const off = TOGGLE_KEYS.filter((key) => !rule[key]);
if (off.length === 0) {
return [{ label: t("policy.chip.allOn"), sign: "plus" }];
}
if (on.length === 0) {
return [{ label: t("policy.chip.allOff"), sign: "minus" }];
}
if (off.length <= SHOWN_CHIPS) {
return [
{ label: t("policy.summary.all"), sign: "plus" },
...named(off, "minus"),
];
}
return [...counted(on, "plus"), ...counted(off, "minus")];
}
export function diffChips(rule: CaptureToggles, base: CaptureToggles): Chip[] {
const plus = TOGGLE_KEYS.filter((key) => rule[key] && !base[key]);
const minus = TOGGLE_KEYS.filter((key) => !rule[key] && base[key]);
if (plus.length > SHOWN_CHIPS && TOGGLE_KEYS.every((key) => rule[key])) {
return [{ label: t("policy.chip.allOn"), sign: "plus" }];
}
if (minus.length > SHOWN_CHIPS && TOGGLE_KEYS.every((key) => !rule[key])) {
return [{ label: t("policy.chip.allOff"), sign: "minus" }];
}
return [...counted(plus, "plus"), ...counted(minus, "minus")];
}