import { apiFetch, apiPath, type ApiSettings, type EffectiveViewProjection, type NavigationPreferences, type ViewPresentation } from "@govoplan/core-webui"; export type ViewScopeType = "system" | "tenant" | "group" | "user"; 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[]; presentation: { navigation?: NavigationPreferences | null; navigation_mode?: "grouped" | "flat"; product_area_order?: string[]; product_area_labels?: Record; quick_access_recommended_tool_ids?: string[]; quick_access_focused_tool_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; scope_label?: string | null; scope_detail?: string | null; definition_id: string; revision_id?: string | null; mode: ViewAssignmentMode; priority: number; is_active: boolean; metadata: Record; created_by?: string | null; updated_by?: string | null; created_at: string; updated_at: string; }; export type ViewAssignmentTarget = { id: string; scope_type: "group" | "user"; label: string; detail?: string | null; disabled: boolean; disabled_reason?: string | null; }; export type ViewAssignmentTargetList = { directory_available: boolean; targets: ViewAssignmentTarget[]; unavailable_reason?: string | null; }; type EffectiveViewApiResponse = { active_view_id?: string | null; active_revision_id?: string | null; active_view_name?: string | null; visible_surface_ids: string[]; presentation?: ViewRevision["presentation"]; 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, presentation: presentationFromApi(response.presentation), 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 { return projection( await apiFetch( settings, "/api/v1/views/effective", { cache: "no-store" } ) ); } export async function selectEffectiveView( settings: ApiSettings, viewId: string | null ): Promise { return projection( await apiFetch( settings, "/api/v1/views/selection", { method: "PUT", ...jsonBody({ view_id: viewId }) } ) ); } export async function resolveWorkflowView( settings: ApiSettings, context: { viewId: string; revisionId?: string | null; visibleSurfaceIds?: string[]; } ): Promise { return projection( await apiFetch( settings, "/api/v1/views/effective/workflow", { method: "POST", ...jsonBody({ view_id: context.viewId, revision_id: context.revisionId ?? null, visible_surface_ids: context.visibleSurfaceIds ?? [] }) } ) ); } export async function fetchViewDefinitions( settings: ApiSettings, scopeType: ViewScopeType, scopeId?: string | null ): Promise { const response = await apiFetch<{ definitions: ViewDefinition[] }>( settings, apiPath("/api/v1/views/definitions", { scope_type: scopeType, scope_id: scopeId || undefined, include_inherited: scopeType === "tenant" }) ); return response.definitions; } export function createViewDefinition( settings: ApiSettings, payload: { scope_type: ViewScopeType; scope_id?: string | null; name: string; description?: string | null; visible_surface_ids: string[]; presentation?: ViewRevision["presentation"]; } ): Promise { 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 { return apiFetch(settings, `/api/v1/views/definitions/${definitionId}`, { method: "PATCH", ...jsonBody(payload) }); } export function createViewRevision( settings: ApiSettings, definitionId: string, visibleSurfaceIds: string[], presentation: ViewPresentation ): Promise { return apiFetch( settings, `/api/v1/views/definitions/${definitionId}/revisions`, { method: "POST", ...jsonBody({ visible_surface_ids: visibleSurfaceIds, presentation: presentationToApi(presentation) }) } ); } export function presentationFromApi( value: ViewRevision["presentation"] | undefined ): ViewPresentation { return { navigation: value?.navigation ?? null, navigationMode: value?.navigation_mode, productAreaOrder: value?.product_area_order ?? [], productAreaLabels: value?.product_area_labels ?? {}, quickAccessRecommendedToolIds: value?.quick_access_recommended_tool_ids ?? [], quickAccessFocusedToolIds: value?.quick_access_focused_tool_ids ?? [] }; } export function presentationToApi( value: ViewPresentation ): ViewRevision["presentation"] { return { navigation: value.navigation ?? null, navigation_mode: value.navigationMode ?? "grouped", product_area_order: value.productAreaOrder ?? [], product_area_labels: value.productAreaLabels ?? {}, quick_access_recommended_tool_ids: value.quickAccessRecommendedToolIds ?? [], quick_access_focused_tool_ids: value.quickAccessFocusedToolIds ?? [] }; } export function publishViewRevision( settings: ApiSettings, definitionId: string, revisionId: string ): Promise { return apiFetch( settings, `/api/v1/views/definitions/${definitionId}/revisions/${revisionId}/publish`, { method: "POST" } ); } export function archiveViewDefinition( settings: ApiSettings, definitionId: string ): Promise { return apiFetch(settings, `/api/v1/views/definitions/${definitionId}`, { method: "DELETE" }); } export async function fetchViewAssignments( settings: ApiSettings, scopeType: ViewScopeType ): Promise { const response = await apiFetch<{ assignments: ViewAssignment[] }>( settings, apiPath("/api/v1/views/assignments", { scope_type: scopeType, include_inherited: scopeType === "tenant" }) ); return response.assignments; } export function fetchViewAssignmentTargets( settings: ApiSettings, scopeType: "group" | "user", query: string, limit: number, signal?: AbortSignal ): Promise { return apiFetch( settings, apiPath("/api/v1/views/assignment-targets", { scope_type: scopeType, query: query || undefined, limit }), { signal } ); } 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 { 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 { return apiFetch(settings, `/api/v1/views/assignments/${assignmentId}`, { method: "PATCH", ...jsonBody(payload) }); } export function deleteViewAssignment( settings: ApiSettings, assignmentId: string ): Promise { return apiFetch(settings, `/api/v1/views/assignments/${assignmentId}`, { method: "DELETE" }); }