Files
govoplan-forms/webui/src/api/forms.ts
T

154 lines
4.6 KiB
TypeScript

import { apiFetch, apiPath, type ApiSettings } from "@govoplan/core-webui";
export type FormValueType = "text" | "multiline_text" | "integer" | "number" | "boolean" | "date" | "datetime" | "email" | "choice" | "multi_choice" | "object" | "list";
export type FormCondition =
| { kind: "predicate"; field_key: string; operator: "eq" | "neq" | "lt" | "lte" | "gt" | "gte" | "in" | "not_in" | "contains" | "is_empty" | "is_not_empty"; value?: unknown }
| { kind: "all" | "any"; conditions: FormCondition[] }
| { kind: "not"; conditions: [FormCondition] };
export type FormFieldDefinition = {
key: string;
label: string;
value_type: FormValueType;
required: boolean;
help_text?: string | null;
options: string[];
constraints: Record<string, unknown>;
default_value?: unknown;
visibility_condition?: FormCondition | null;
accessibility?: Record<string, unknown>;
};
export type FormSectionDefinition = {
key: string;
title: string;
description?: string | null;
field_keys: string[];
visibility_condition?: FormCondition | null;
};
export type FormPageDefinition = {
key: string;
title: string;
description?: string | null;
sections: FormSectionDefinition[];
visibility_condition?: FormCondition | null;
};
export type FormLocalization = {
locale: string;
title?: string | null;
description?: string | null;
field_labels: Record<string, string>;
field_help_texts: Record<string, string>;
option_labels: Record<string, Record<string, string>>;
page_titles: Record<string, string>;
section_titles: Record<string, string>;
};
export type FormDefinition = {
reference: {
kind: "form";
owner_module: "forms";
object_id: string;
tenant_id: string;
version: string;
};
key: string;
temporal: {
revision: string;
valid_from?: string | null;
valid_to?: string | null;
recorded_at: string;
superseded_at?: string | null;
change_reason: string;
};
title: string;
description?: string | null;
fields: FormFieldDefinition[];
publication_state: "draft" | "published" | "retired";
allow_drafts: boolean;
max_attachments: number;
signature_requirement: "none" | "optional" | "required";
policy_refs: string[];
handoff_kinds: string[];
pages?: FormPageDefinition[];
fallback_locale?: string | null;
localizations?: FormLocalization[];
accessibility?: Record<string, unknown>;
metadata: Record<string, unknown>;
};
export type FormPackageFragment = {
kind: "govoplan.forms.definition";
contract_version: "0.1.0";
definition: FormDefinition;
definition_sha256: string;
provenance: Record<string, unknown>;
};
export function listFormDefinitions(
settings: ApiSettings,
options: { query?: string; states?: string[]; offset?: number; limit?: number } = {},
signal?: AbortSignal
): Promise<{ definitions: FormDefinition[]; total: number }> {
return apiFetch(settings, apiPath("/api/v1/forms/definitions", {
q: options.query,
publication_state: options.states,
offset: options.offset ?? 0,
limit: options.limit ?? 200
}), { signal });
}
export function saveFormDefinition(
settings: ApiSettings,
definition: FormDefinition,
expectedRevision?: string | null
): Promise<FormDefinition> {
return apiFetch(settings, `/api/v1/forms/definitions/${encodeURIComponent(definition.reference.object_id)}`, {
method: "PUT",
body: JSON.stringify({
definition,
expected_revision: expectedRevision ?? null
})
});
}
export function exportFormDefinitionPackage(
settings: ApiSettings,
formId: string,
revision: string
): Promise<FormPackageFragment> {
return apiFetch(settings, apiPath(`/api/v1/forms/definitions/${encodeURIComponent(formId)}/package`, { revision }));
}
export function assessFormDefinitionPackage(
settings: ApiSettings,
fragment: FormPackageFragment
): Promise<{ outcome: string; requires_remap: boolean; current_revision?: string | null }> {
return apiFetch(settings, "/api/v1/forms/packages/assess", {
method: "POST",
body: JSON.stringify({ fragment })
});
}
export function importFormDefinitionPackage(
settings: ApiSettings,
fragment: FormPackageFragment,
options: { targetFormId?: string; targetKey?: string; expectedRevision?: string; changeReason: string }
): Promise<FormDefinition> {
return apiFetch(settings, "/api/v1/forms/packages/import", {
method: "POST",
body: JSON.stringify({
fragment,
target_form_id: options.targetFormId || null,
target_key: options.targetKey || null,
expected_revision: options.expectedRevision || null,
change_reason: options.changeReason,
recorded_at: new Date().toISOString()
})
});
}