Files
govoplan-dist-lists/webui/src/api/distLists.ts
T

310 lines
7.8 KiB
TypeScript

import {
apiFetch,
apiPath,
type ApiSettings
} from "@govoplan/core-webui";
export type DefinitionKind = "static" | "parameterized" | "dynamic" | "template";
export type EntryMode = "include" | "exclude" | "override";
export type EntryKind =
| "address_contact"
| "address_list"
| "address_email"
| "raw_email"
| "raw_postal_address"
| "internal_mail"
| "portal"
| "idm_identity"
| "idm_group"
| "organization_unit"
| "function"
| "effective_function_incumbent"
| "dataflow_result"
| "distribution_list";
export type DistributionChannel = "email" | "postal" | "internal_mail" | "portal";
export type DistributionOutcome =
| "usable"
| "unresolved"
| "invalid"
| "suppressed"
| "ambiguous"
| "duplicate"
| "policy_blocked"
| "provider_unavailable"
| "stale";
export type SourceReference = {
provider: string;
resource_type: string;
resource_id: string;
revision?: string | null;
fingerprint?: string | null;
label?: string | null;
metadata: Record<string, unknown>;
};
export type DistributionParameter = {
key: string;
value_type: "string" | "integer" | "number" | "boolean" | "date" | "datetime" | "string_list";
label?: string | null;
required: boolean;
default?: unknown;
allowed_values: unknown[];
minimum?: number | null;
maximum?: number | null;
pattern?: string | null;
description?: string | null;
};
export type DistributionListEntryInput = {
entry_key?: string | null;
kind: EntryKind;
mode: EntryMode;
source: SourceReference;
label?: string | null;
purpose?: string | null;
requested_channels: DistributionChannel[];
effective_from?: string | null;
effective_until?: string | null;
configuration: Record<string, unknown>;
};
export type DistributionListEntry = DistributionListEntryInput & {
id: string;
entry_key: string;
order: number;
};
export type DistributionListRevision = {
id: string;
revision: number;
definition_kind: DefinitionKind;
definition_hash: string;
parameters: DistributionParameter[];
constraints: Record<string, unknown>;
source_fingerprints: Array<Record<string, unknown>>;
entries: DistributionListEntry[];
created_by_account_id?: string | null;
created_at: string;
};
export type DistributionList = {
id: string;
tenant_id: string;
scope_type: "tenant" | "group" | "user";
scope_id?: string | null;
name: string;
description?: string | null;
status: string;
current_revision: number;
resource_revision: number;
etag: string;
metadata: Record<string, unknown>;
deleted_at?: string | null;
created_at: string;
updated_at: string;
revision: DistributionListRevision;
};
export type DistributionListPayload = {
name: string;
description?: string | null;
scope_type: "tenant" | "group" | "user";
scope_id?: string | null;
definition_kind: DefinitionKind;
parameters: DistributionParameter[];
constraints: Record<string, unknown>;
entries: DistributionListEntryInput[];
metadata: Record<string, unknown>;
};
export type DistributionExplanation = {
code: string;
message: string;
severity: "info" | "warning" | "error";
provider?: string | null;
source?: SourceReference | null;
provenance: Record<string, unknown>;
};
export type DistributionChannelCandidate = {
channel: DistributionChannel;
target: string;
target_key: string;
status: DistributionOutcome;
contact_point_id?: string | null;
locale?: string | null;
preferred: boolean;
reason_code?: string | null;
explanation?: string | null;
source?: SourceReference | null;
decision_provenance: Record<string, unknown>;
};
export type DistributionRecipient = {
recipient_key: string;
display_name: string;
status: DistributionOutcome;
channels: DistributionChannelCandidate[];
identity_id?: string | null;
account_id?: string | null;
contact_id?: string | null;
organization_unit_id?: string | null;
function_id?: string | null;
source_entry_ids: string[];
explanations: DistributionExplanation[];
attributes: Record<string, unknown>;
provenance: Record<string, unknown>;
};
export type ProviderEvidence = {
provider: string;
source: SourceReference;
actual_revision?: string | null;
actual_fingerprint?: string | null;
stale: boolean;
generated_at?: string | null;
details: Record<string, unknown>;
};
export type ExpansionResult = {
list_id: string;
revision_id: string;
revision: number;
definition_hash: string;
recipients: DistributionRecipient[];
excluded: DistributionRecipient[];
diagnostics: DistributionExplanation[];
provider_evidence: ProviderEvidence[];
expansion_hash: string;
generated_at: string;
snapshot_id?: string | null;
stale: boolean;
truncated: boolean;
};
export type ExpansionPayload = {
revision?: number | null;
effective_at?: string | null;
purpose?: string | null;
requested_channels?: DistributionChannel[];
parameters?: Record<string, unknown>;
preview?: boolean;
freeze?: boolean;
idempotency_key?: string | null;
max_entries?: number;
max_results?: number;
max_depth?: number;
max_provider_results?: number;
};
export type DistributionSnapshot = {
id: string;
list_id: string;
revision_id: string;
revision: number;
expansion_hash: string;
effective_at: string;
recipient_count: number;
excluded_count: number;
stale: boolean;
truncated: boolean;
created_at: string;
};
export type ProviderOption = {
key: string;
kind: EntryKind;
label: string;
description?: string | null;
provider: string;
source: SourceReference;
available: boolean;
reason?: string | null;
metadata: Record<string, unknown>;
};
export type ProviderCatalogue = {
items: ProviderOption[];
unavailable_providers: DistributionExplanation[];
};
export async function listDistributionLists(
settings: ApiSettings,
query = ""
): Promise<DistributionList[]> {
const result = await apiFetch<{ items: DistributionList[] }>(
settings,
apiPath("/api/v1/dist-lists/lists", { query, limit: 500 })
);
return result.items;
}
export function createDistributionList(
settings: ApiSettings,
payload: DistributionListPayload
): Promise<DistributionList> {
return apiFetch(settings, "/api/v1/dist-lists/lists", {
method: "POST",
body: JSON.stringify(payload)
});
}
export function updateDistributionList(
settings: ApiSettings,
item: DistributionList,
payload: DistributionListPayload
): Promise<DistributionList> {
return apiFetch(settings, `/api/v1/dist-lists/lists/${encodeURIComponent(item.id)}`, {
method: "PUT",
headers: { "If-Match": item.etag },
body: JSON.stringify({ ...payload, base_revision: item.resource_revision })
});
}
export function deleteDistributionList(
settings: ApiSettings,
item: DistributionList
): Promise<void> {
return apiFetch(settings, `/api/v1/dist-lists/lists/${encodeURIComponent(item.id)}`, {
method: "DELETE",
headers: { "If-Match": item.etag },
body: JSON.stringify({ base_revision: item.resource_revision })
});
}
export function expandDistributionList(
settings: ApiSettings,
listId: string,
payload: ExpansionPayload
): Promise<ExpansionResult> {
return apiFetch(settings, `/api/v1/dist-lists/lists/${encodeURIComponent(listId)}/expand`, {
method: "POST",
body: JSON.stringify(payload)
});
}
export async function listDistributionSnapshots(
settings: ApiSettings,
listId: string
): Promise<DistributionSnapshot[]> {
const result = await apiFetch<{ items: DistributionSnapshot[] }>(
settings,
`/api/v1/dist-lists/lists/${encodeURIComponent(listId)}/snapshots`
);
return result.items;
}
export function listProviderOptions(
settings: ApiSettings,
query = "",
limit = 50,
signal?: AbortSignal
): Promise<ProviderCatalogue> {
return apiFetch(
settings,
apiPath("/api/v1/dist-lists/providers", { query, limit }),
{ signal }
);
}