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

577 lines
14 KiB
TypeScript

import {
apiFetch,
apiReferenceOptionProvider,
type ApiSettings,
type ReferenceOptionProvider
} from "@govoplan/core-webui";
import type {
DefinitionGraph,
DefinitionGraphEdge,
DefinitionGraphNode,
DefinitionGraphNodeType
} from "@govoplan/core-webui/definition-graph";
export type WorkflowStatus = "draft" | "active" | "archived";
export type DefinitionScopeType = "system" | "tenant" | "group" | "user";
export type DefinitionKind = "flow" | "template";
export type WorkflowExecutionMode = "guided" | "automated" | "hybrid";
export type WorkflowStartOrigin =
| "user"
| "api"
| "schedule"
| "event"
| "parent_workflow"
| "dependency"
| "retry"
| "replay"
| "backfill";
export type WorkflowGraphNode = DefinitionGraphNode & {
size?: { width: number; height: number } | null;
parent_id?: string | null;
process_id?: string | null;
};
export type WorkflowGraphEdge = DefinitionGraphEdge & {
type:
| "bpmn.sequenceFlow"
| "bpmn.messageFlow"
| "bpmn.association"
| "bpmn.dataInputAssociation"
| "bpmn.dataOutputAssociation"
| "bpmn.conversationLink";
label: string;
config: Record<string, unknown>;
waypoints: Array<{ x: number; y: number }>;
};
export type WorkflowGraph = Omit<DefinitionGraph, "nodes" | "edges"> & {
schema_version: 1;
nodes: WorkflowGraphNode[];
edges: WorkflowGraphEdge[];
metadata: Record<string, unknown>;
};
export type WorkflowDiagnostic = {
severity: "error" | "warning";
code: string;
message: string;
node_id?: string | null;
field?: string | null;
};
export type WorkflowNodeType = DefinitionGraphNodeType;
export type BpmnRuntimeKind = "model_only" | "native_graph" | "external";
export type BpmnDiagnostic = {
severity: "error" | "warning" | "info";
code: string;
message: string;
element_id?: string | null;
};
export type BpmnAdapterProfile = {
id: string;
version: string;
label: string;
description: string;
conformance: string;
runtime_kind: BpmnRuntimeKind;
executable: boolean;
supported_elements: string[];
supported_event_definitions: string[];
requirements: string[];
};
export type BpmnInspection = {
valid_xml: boolean;
definitions_id?: string | null;
target_namespace?: string | null;
process_count: number;
executable_process_count: number;
collaboration_count: number;
choreography_count: number;
element_counts: Record<string, number>;
support_counts: Record<string, number>;
elements: Array<{
element_type: string;
element_id?: string | null;
name?: string | null;
parent_type?: string | null;
parent_id?: string | null;
support_level: "interchange_only" | "native_mapping" | "native_execution";
}>;
diagnostics: BpmnDiagnostic[];
adapter_id?: string | null;
adapter_version?: string | null;
runtime_kind?: BpmnRuntimeKind | null;
executable: boolean;
activatable: boolean;
};
export type BpmnRevisionSummary = {
format: "bpmn-2.0";
content_hash: string;
adapter_id: string;
adapter_version: string;
runtime_kind: BpmnRuntimeKind;
executable: boolean;
adapter_available: boolean;
};
export type BpmnRevisionDocument = BpmnRevisionSummary & {
definition_id: string;
revision: number;
xml: string;
inspection: BpmnInspection;
};
export type WorkflowRevision = {
id: string;
revision: number;
schema_version: number;
graph: WorkflowGraph;
content_hash: string;
library_id: string;
library_version: string;
execution_mode: WorkflowExecutionMode;
view_id?: string | null;
view_revision_id?: string | null;
bpmn?: BpmnRevisionSummary | null;
created_by?: string | null;
created_at: string;
};
export type WorkflowDefinition = {
id: string;
tenant_id: string | null;
key: string;
name: string;
description?: string | null;
status: WorkflowStatus;
current_revision: number;
active_revision?: number | null;
metadata: Record<string, unknown>;
created_by?: string | null;
updated_by?: string | null;
created_at: string;
updated_at: string;
revision: WorkflowRevision;
governance: WorkflowGovernance;
};
export type WorkflowActionDecision = {
allowed: boolean;
reason?: string | null;
source_path: Array<Record<string, unknown>>;
requirements: string[];
details: Record<string, unknown>;
};
export type WorkflowGovernance = {
scope_type: DefinitionScopeType;
scope_id?: string | null;
definition_kind: DefinitionKind;
inherit_to_lower_scopes: boolean;
allow_start: boolean;
allow_reuse: boolean;
allow_automation: boolean;
derived_from_definition_id?: string | null;
derived_from_revision?: number | null;
derived_from_hash?: string | null;
derivation_provenance: Record<string, unknown>;
actions: Record<string, WorkflowActionDecision>;
automation_runtime_available: boolean;
automation_runtime_reason?: string | null;
};
export type WorkflowInstanceStatus =
| "running"
| "waiting"
| "completed"
| "failed"
| "cancelled";
export type WorkflowStepStatus =
| "running"
| "waiting"
| "completed"
| "failed"
| "cancelled"
| "superseded";
export type WorkflowInstanceStep = {
id: string;
sequence: number;
node_id: string;
node_type: string;
status: WorkflowStepStatus;
attempt: number;
input: Record<string, unknown>;
output: Record<string, unknown>;
handoff: Record<string, unknown>;
external_ref?: string | null;
started_at?: string | null;
finished_at?: string | null;
error?: string | null;
completed_by?: string | null;
created_at: string;
updated_at: string;
};
export type WorkflowInstanceEvent = {
id: string;
sequence: number;
step_id?: string | null;
kind: string;
actor_id?: string | null;
payload: Record<string, unknown>;
created_at: string;
};
export type WorkflowInstance = {
id: string;
definition_id: string;
definition_name: string;
definition_revision: number;
definition_hash: string;
execution_mode: WorkflowExecutionMode;
start_origin: WorkflowStartOrigin;
view_context?: {
view_id: string;
revision_id?: string | null;
visible_surface_ids: string[];
step_id?: string | null;
node_id?: string | null;
} | null;
status: WorkflowInstanceStatus;
idempotency_key: string;
correlation_id?: string | null;
current_step_id?: string | null;
input: Record<string, unknown>;
context: Record<string, unknown>;
output: Record<string, unknown>;
started_at: string;
finished_at?: string | null;
cancellation_requested_at?: string | null;
error?: string | null;
created_by?: string | null;
created_at: string;
updated_at: string;
steps: WorkflowInstanceStep[];
events: WorkflowInstanceEvent[];
replayed: boolean;
};
export type WorkflowDefinitionPayload = {
name: string;
description?: string | null;
graph: WorkflowGraph;
bpmn?: {
xml: string;
adapter_id: string;
adapter_version?: string | null;
} | null;
metadata: Record<string, unknown>;
scope_type: DefinitionScopeType;
scope_id?: string | null;
definition_kind: DefinitionKind;
inherit_to_lower_scopes: boolean;
allow_start: boolean;
allow_reuse: boolean;
allow_automation: boolean;
execution_mode: WorkflowExecutionMode;
view_id?: string | null;
view_revision_id?: string | null;
};
export async function getBpmnSupportProfile(
settings: ApiSettings
): Promise<{
specification: string;
model_namespace: string;
interchange: string;
native_runtime: string;
native_execution_elements: string[];
native_mapping_elements: string[];
adapters: BpmnAdapterProfile[];
}> {
return apiFetch(settings, "/api/v1/workflow/bpmn/profile");
}
export function inspectWorkflowBpmn(
settings: ApiSettings,
payload: {
xml: string;
adapter_id: string;
adapter_version?: string | null;
activation?: boolean;
}
): Promise<BpmnInspection> {
return apiFetch(settings, "/api/v1/workflow/bpmn/inspect", {
method: "POST",
body: JSON.stringify(payload)
});
}
export function compileWorkflowBpmn(
settings: ApiSettings,
payload: {
xml: string;
adapter_id: string;
adapter_version?: string | null;
}
): Promise<{
adapter: BpmnAdapterProfile;
graph: WorkflowGraph;
inspection: BpmnInspection;
}> {
return apiFetch(settings, "/api/v1/workflow/bpmn/compile", {
method: "POST",
body: JSON.stringify(payload)
});
}
export function renderWorkflowBpmn(
settings: ApiSettings,
payload: { graph: WorkflowGraph; name?: string }
): Promise<{ xml: string; inspection: BpmnInspection }> {
return apiFetch(settings, "/api/v1/workflow/bpmn/render", {
method: "POST",
body: JSON.stringify(payload)
});
}
export async function listWorkflowNodeTypes(
settings: ApiSettings
): Promise<{ id: string; version: string; allows_cycles: boolean; nodes: WorkflowNodeType[] }> {
return apiFetch(settings, "/api/v1/workflow/node-types");
}
export async function listWorkflowDefinitions(
settings: ApiSettings
): Promise<WorkflowDefinition[]> {
const response = await apiFetch<{ definitions: WorkflowDefinition[] }>(
settings,
"/api/v1/workflow/definitions"
);
return response.definitions;
}
export function createWorkflowDefinition(
settings: ApiSettings,
payload: WorkflowDefinitionPayload
): Promise<WorkflowDefinition> {
return apiFetch(settings, "/api/v1/workflow/definitions", {
method: "POST",
body: JSON.stringify(payload)
});
}
export function updateWorkflowDefinition(
settings: ApiSettings,
definitionId: string,
payload: WorkflowDefinitionPayload & { expected_revision: number }
): Promise<WorkflowDefinition> {
return apiFetch(
settings,
`/api/v1/workflow/definitions/${encodeURIComponent(definitionId)}`,
{
method: "PUT",
body: JSON.stringify(payload)
}
);
}
export function deriveWorkflowDefinition(
settings: ApiSettings,
definitionId: string,
payload: {
key?: string | null;
name: string;
description?: string | null;
source_revision?: number | null;
metadata: Record<string, unknown>;
scope_type: DefinitionScopeType;
scope_id?: string | null;
definition_kind: DefinitionKind;
inherit_to_lower_scopes: boolean;
allow_start: boolean;
allow_reuse: boolean;
allow_automation: boolean;
execution_mode?: WorkflowExecutionMode | null;
view_id?: string | null;
view_revision_id?: string | null;
}
): Promise<WorkflowDefinition> {
return apiFetch(
settings,
`/api/v1/workflow/definitions/${encodeURIComponent(definitionId)}/derive`,
{ method: "POST", body: JSON.stringify(payload) }
);
}
export async function listWorkflowRevisions(
settings: ApiSettings,
definitionId: string
): Promise<WorkflowRevision[]> {
const response = await apiFetch<{ revisions: WorkflowRevision[] }>(
settings,
`/api/v1/workflow/definitions/${encodeURIComponent(definitionId)}/revisions`
);
return response.revisions;
}
export function getWorkflowRevisionBpmn(
settings: ApiSettings,
definitionId: string,
revision: number
): Promise<BpmnRevisionDocument> {
return apiFetch(
settings,
`/api/v1/workflow/definitions/${encodeURIComponent(definitionId)}/revisions/${revision}/bpmn`
);
}
export function activateWorkflowDefinition(
settings: ApiSettings,
definitionId: string,
revision?: number
): Promise<WorkflowDefinition> {
return apiFetch(
settings,
`/api/v1/workflow/definitions/${encodeURIComponent(definitionId)}/activate`,
{
method: "POST",
body: JSON.stringify({ revision })
}
);
}
export function archiveWorkflowDefinition(
settings: ApiSettings,
definitionId: string
): Promise<WorkflowDefinition> {
return apiFetch(
settings,
`/api/v1/workflow/definitions/${encodeURIComponent(definitionId)}/archive`,
{ method: "POST" }
);
}
export function deleteWorkflowDefinition(
settings: ApiSettings,
definitionId: string
): Promise<{ deleted: boolean; definition_id: string }> {
return apiFetch(
settings,
`/api/v1/workflow/definitions/${encodeURIComponent(definitionId)}`,
{ method: "DELETE" }
);
}
export function validateWorkflowDefinition(
settings: ApiSettings,
graph: WorkflowGraph
): Promise<{ valid: boolean; diagnostics: WorkflowDiagnostic[] }> {
return apiFetch(settings, "/api/v1/workflow/definitions/validate", {
method: "POST",
body: JSON.stringify({ graph })
});
}
export function workflowScopeReferenceProvider(
settings: ApiSettings,
scopeType: "user" | "group"
): ReferenceOptionProvider {
return apiReferenceOptionProvider(
settings,
"/api/v1/workflow/scope-targets",
{ scope_type: scopeType }
);
}
export async function listWorkflowInstances(
settings: ApiSettings,
definitionId?: string | null
): Promise<WorkflowInstance[]> {
const params = new URLSearchParams();
if (definitionId) params.set("definition_id", definitionId);
const query = params.size ? `?${params.toString()}` : "";
const response = await apiFetch<{ instances: WorkflowInstance[] }>(
settings,
`/api/v1/workflow/instances${query}`
);
return response.instances;
}
export function startWorkflowInstance(
settings: ApiSettings,
definitionId: string,
payload: {
idempotency_key: string;
input?: Record<string, unknown>;
correlation_id?: string | null;
}
): Promise<WorkflowInstance> {
return apiFetch(
settings,
`/api/v1/workflow/definitions/${encodeURIComponent(definitionId)}/instances`,
{
method: "POST",
body: JSON.stringify(payload)
}
);
}
export function getWorkflowInstance(
settings: ApiSettings,
instanceId: string
): Promise<WorkflowInstance> {
return apiFetch(
settings,
`/api/v1/workflow/instances/${encodeURIComponent(instanceId)}`
);
}
export function reconcileWorkflowInstance(
settings: ApiSettings,
instanceId: string
): Promise<WorkflowInstance> {
return apiFetch(
settings,
`/api/v1/workflow/instances/${encodeURIComponent(instanceId)}/reconcile`,
{ method: "POST" }
);
}
export function resolveWorkflowStep(
settings: ApiSettings,
instanceId: string,
stepId: string,
payload: {
action: "complete" | "approve" | "changes" | "reject" | "resume" | "retry" | "cancel";
output?: Record<string, unknown>;
evidence?: string[];
comment?: string | null;
}
): Promise<WorkflowInstance> {
return apiFetch(
settings,
`/api/v1/workflow/instances/${encodeURIComponent(instanceId)}/steps/${encodeURIComponent(stepId)}/actions`,
{
method: "POST",
body: JSON.stringify(payload)
}
);
}
export function cancelWorkflowInstance(
settings: ApiSettings,
instanceId: string
): Promise<WorkflowInstance> {
return apiFetch(
settings,
`/api/v1/workflow/instances/${encodeURIComponent(instanceId)}/cancel`,
{ method: "POST" }
);
}