281 lines
6.8 KiB
TypeScript
281 lines
6.8 KiB
TypeScript
import {
|
|
apiFetch,
|
|
apiPath,
|
|
type ApiSettings,
|
|
type EffectiveViewProjection
|
|
} from "@govoplan/core-webui";
|
|
|
|
export type ViewScopeType = "system" | "tenant";
|
|
export type ViewAssignmentScopeType = "system" | "tenant" | "group" | "user";
|
|
export type ViewAssignmentMode = "available" | "default" | "required";
|
|
|
|
export type ViewRevision = {
|
|
id: string;
|
|
definition_id: string;
|
|
revision: number;
|
|
surface_contract_version: string;
|
|
visible_surface_ids: string[];
|
|
content_hash: string;
|
|
created_by?: string | null;
|
|
created_at: string;
|
|
};
|
|
|
|
export type ViewDefinition = {
|
|
id: string;
|
|
tenant_id?: string | null;
|
|
scope_type: ViewScopeType;
|
|
scope_id?: string | null;
|
|
definition_key: string;
|
|
name: string;
|
|
description?: string | null;
|
|
status: "draft" | "published" | "archived";
|
|
current_revision: number;
|
|
latest_revision: ViewRevision;
|
|
published_revision?: ViewRevision | null;
|
|
readonly: boolean;
|
|
stale_surface_ids: string[];
|
|
created_by?: string | null;
|
|
updated_by?: string | null;
|
|
created_at: string;
|
|
updated_at: string;
|
|
};
|
|
|
|
export type ViewAssignment = {
|
|
id: string;
|
|
tenant_id?: string | null;
|
|
scope_type: ViewAssignmentScopeType;
|
|
scope_id?: string | null;
|
|
definition_id: string;
|
|
revision_id?: string | null;
|
|
mode: ViewAssignmentMode;
|
|
priority: number;
|
|
is_active: boolean;
|
|
metadata: Record<string, unknown>;
|
|
created_by?: string | null;
|
|
updated_by?: string | null;
|
|
created_at: string;
|
|
updated_at: string;
|
|
};
|
|
|
|
type EffectiveViewApiResponse = {
|
|
active_view_id?: string | null;
|
|
active_revision_id?: string | null;
|
|
active_view_name?: string | null;
|
|
visible_surface_ids: string[];
|
|
locked: boolean;
|
|
available_views: Array<{
|
|
id: string;
|
|
name: string;
|
|
description?: string | null;
|
|
revision_id: string;
|
|
}>;
|
|
provenance: Array<{
|
|
source: string;
|
|
scope_type?: string | null;
|
|
scope_id?: string | null;
|
|
detail?: string | null;
|
|
}>;
|
|
diagnostics?: Array<{
|
|
severity: "warning" | "error";
|
|
code: string;
|
|
message: string;
|
|
surface_ids: string[];
|
|
}>;
|
|
};
|
|
|
|
function jsonBody(payload: unknown): RequestInit {
|
|
return {
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify(payload)
|
|
};
|
|
}
|
|
|
|
function projection(response: EffectiveViewApiResponse): EffectiveViewProjection {
|
|
return {
|
|
activeViewId: response.active_view_id ?? null,
|
|
activeRevisionId: response.active_revision_id ?? null,
|
|
activeViewName: response.active_view_name ?? null,
|
|
visibleSurfaceIds: response.visible_surface_ids,
|
|
locked: response.locked,
|
|
availableViews: response.available_views.map((view) => ({
|
|
id: view.id,
|
|
name: view.name,
|
|
description: view.description,
|
|
revisionId: view.revision_id
|
|
})),
|
|
provenance: response.provenance.map((item) => ({
|
|
source: item.source,
|
|
scopeType: item.scope_type,
|
|
scopeId: item.scope_id,
|
|
detail: item.detail
|
|
})),
|
|
diagnostics: (response.diagnostics ?? []).map((item) => ({
|
|
severity: item.severity,
|
|
code: item.code,
|
|
message: item.message,
|
|
surfaceIds: item.surface_ids
|
|
}))
|
|
};
|
|
}
|
|
|
|
export async function fetchEffectiveView(
|
|
settings: ApiSettings
|
|
): Promise<EffectiveViewProjection> {
|
|
return projection(
|
|
await apiFetch<EffectiveViewApiResponse>(
|
|
settings,
|
|
"/api/v1/views/effective",
|
|
{ cache: "no-store" }
|
|
)
|
|
);
|
|
}
|
|
|
|
export async function selectEffectiveView(
|
|
settings: ApiSettings,
|
|
viewId: string | null
|
|
): Promise<EffectiveViewProjection> {
|
|
return projection(
|
|
await apiFetch<EffectiveViewApiResponse>(
|
|
settings,
|
|
"/api/v1/views/selection",
|
|
{
|
|
method: "PUT",
|
|
...jsonBody({ view_id: viewId })
|
|
}
|
|
)
|
|
);
|
|
}
|
|
|
|
export async function fetchViewDefinitions(
|
|
settings: ApiSettings,
|
|
scopeType: ViewScopeType
|
|
): Promise<ViewDefinition[]> {
|
|
const response = await apiFetch<{ definitions: ViewDefinition[] }>(
|
|
settings,
|
|
apiPath("/api/v1/views/definitions", {
|
|
scope_type: scopeType,
|
|
include_inherited: scopeType === "tenant"
|
|
})
|
|
);
|
|
return response.definitions;
|
|
}
|
|
|
|
export function createViewDefinition(
|
|
settings: ApiSettings,
|
|
payload: {
|
|
scope_type: ViewScopeType;
|
|
name: string;
|
|
description?: string | null;
|
|
visible_surface_ids: string[];
|
|
}
|
|
): Promise<ViewDefinition> {
|
|
return apiFetch(settings, "/api/v1/views/definitions", {
|
|
method: "POST",
|
|
...jsonBody(payload)
|
|
});
|
|
}
|
|
|
|
export function updateViewDefinition(
|
|
settings: ApiSettings,
|
|
definitionId: string,
|
|
payload: { name: string; description?: string | null }
|
|
): Promise<ViewDefinition> {
|
|
return apiFetch(settings, `/api/v1/views/definitions/${definitionId}`, {
|
|
method: "PATCH",
|
|
...jsonBody(payload)
|
|
});
|
|
}
|
|
|
|
export function createViewRevision(
|
|
settings: ApiSettings,
|
|
definitionId: string,
|
|
visibleSurfaceIds: string[]
|
|
): Promise<ViewDefinition> {
|
|
return apiFetch(
|
|
settings,
|
|
`/api/v1/views/definitions/${definitionId}/revisions`,
|
|
{
|
|
method: "POST",
|
|
...jsonBody({ visible_surface_ids: visibleSurfaceIds })
|
|
}
|
|
);
|
|
}
|
|
|
|
export function publishViewRevision(
|
|
settings: ApiSettings,
|
|
definitionId: string,
|
|
revisionId: string
|
|
): Promise<ViewDefinition> {
|
|
return apiFetch(
|
|
settings,
|
|
`/api/v1/views/definitions/${definitionId}/revisions/${revisionId}/publish`,
|
|
{ method: "POST" }
|
|
);
|
|
}
|
|
|
|
export function archiveViewDefinition(
|
|
settings: ApiSettings,
|
|
definitionId: string
|
|
): Promise<ViewDefinition> {
|
|
return apiFetch(settings, `/api/v1/views/definitions/${definitionId}`, {
|
|
method: "DELETE"
|
|
});
|
|
}
|
|
|
|
export async function fetchViewAssignments(
|
|
settings: ApiSettings,
|
|
scopeType: ViewScopeType
|
|
): Promise<ViewAssignment[]> {
|
|
const response = await apiFetch<{ assignments: ViewAssignment[] }>(
|
|
settings,
|
|
apiPath("/api/v1/views/assignments", {
|
|
scope_type: scopeType,
|
|
include_inherited: scopeType === "tenant"
|
|
})
|
|
);
|
|
return response.assignments;
|
|
}
|
|
|
|
export function createViewAssignment(
|
|
settings: ApiSettings,
|
|
payload: {
|
|
scope_type: ViewAssignmentScopeType;
|
|
scope_id?: string | null;
|
|
definition_id: string;
|
|
revision_id?: string | null;
|
|
mode: ViewAssignmentMode;
|
|
priority: number;
|
|
is_active: boolean;
|
|
}
|
|
): Promise<ViewAssignment> {
|
|
return apiFetch(settings, "/api/v1/views/assignments", {
|
|
method: "POST",
|
|
...jsonBody(payload)
|
|
});
|
|
}
|
|
|
|
export function updateViewAssignment(
|
|
settings: ApiSettings,
|
|
assignmentId: string,
|
|
payload: {
|
|
revision_id?: string | null;
|
|
mode?: ViewAssignmentMode;
|
|
priority?: number;
|
|
is_active?: boolean;
|
|
}
|
|
): Promise<ViewAssignment> {
|
|
return apiFetch(settings, `/api/v1/views/assignments/${assignmentId}`, {
|
|
method: "PATCH",
|
|
...jsonBody(payload)
|
|
});
|
|
}
|
|
|
|
export function deleteViewAssignment(
|
|
settings: ApiSettings,
|
|
assignmentId: string
|
|
): Promise<void> {
|
|
return apiFetch(settings, `/api/v1/views/assignments/${assignmentId}`, {
|
|
method: "DELETE"
|
|
});
|
|
}
|