Files
HartOMat/frontend/src/components/workflows/workflowBlueprints.ts
T

79 lines
2.8 KiB
TypeScript

import type { WorkflowConfig, WorkflowDefinition } from '../../api/workflows'
import type { WorkflowGraphFamily, WorkflowNodeDefinitionMap } from './workflowNodeLibrary'
import { getNodeFamily } from './workflowNodeLibrary'
export const BLUEPRINT_LABELS: Record<string, string> = {
cad_intake: 'Reference Blueprint',
order_rendering: 'Reference Blueprint',
still_graph_reference: 'Graph Reference',
starter_cad_intake: 'Starter',
starter_order_rendering: 'Starter',
}
export const BLUEPRINT_DESCRIPTION: Record<string, string> = {
cad_intake: 'Canonical CAD-file workflow for intake, preview generation, and material discovery.',
order_rendering: 'Canonical order-line workflow for production rendering, exports, and notifications.',
still_graph_reference: 'Reference still-render graph that stays parallel to the legacy workflow while native nodes reach parity.',
starter_cad_intake: 'Minimal CAD-file starter graph.',
starter_order_rendering: 'Minimal order-line starter graph.',
}
export function inferWorkflowFamily(
config: WorkflowConfig,
nodeDefinitionsByStep?: WorkflowNodeDefinitionMap,
): WorkflowGraphFamily {
const nodes = Array.isArray(config.nodes) ? config.nodes : []
if (nodes.length > 0) {
const families = new Set(nodes.map(node => getNodeFamily(node.step, nodeDefinitionsByStep)))
if (families.size === 1) {
return Array.from(families)[0]
}
return 'mixed'
}
const presetType = config.ui?.preset ?? 'custom'
if (presetType === 'custom') {
return 'mixed'
}
return 'order_line'
}
export function getWorkflowBlueprint(config: WorkflowConfig): string | null {
const blueprint = config.ui?.blueprint
return typeof blueprint === 'string' && blueprint.trim().length > 0 ? blueprint : null
}
export function isReferenceBlueprint(config: WorkflowConfig): boolean {
const blueprint = getWorkflowBlueprint(config)
return blueprint === 'cad_intake' || blueprint === 'order_rendering' || blueprint === 'still_graph_reference'
}
export function cloneWorkflowConfig(config: WorkflowConfig, options?: { stripBlueprint?: boolean }): WorkflowConfig {
const nextUi = { ...(config.ui ?? {}) }
if (options?.stripBlueprint) {
delete nextUi.blueprint
}
return {
version: config.version,
nodes: config.nodes.map(node => ({
...node,
params: { ...(node.params ?? {}) },
ui: node.ui ? { ...node.ui } : undefined,
})),
edges: config.edges.map(edge => ({ ...edge })),
ui: nextUi,
}
}
export function compareWorkflows(a: WorkflowDefinition, b: WorkflowDefinition): number {
const blueprintRank = Number(isReferenceBlueprint(b.config)) - Number(isReferenceBlueprint(a.config))
if (blueprintRank !== 0) return blueprintRank
const activeRank = Number(b.is_active) - Number(a.is_active)
if (activeRank !== 0) return activeRank
return a.name.localeCompare(b.name)
}