/** * Entity assignment normalization and display utilities. * * Extracted from pages/machines/new.vue – these pure functions resolve * machine / component / piece assignments from nested API payloads. */ type AnyRecord = Record // --------------------------------------------------------------------------- // Primitive helpers // --------------------------------------------------------------------------- const isPlainObject = (value: unknown): value is AnyRecord => value !== null && typeof value === 'object' && !Array.isArray(value) const toTrimmedString = (value: unknown): string | null => { if (typeof value === 'string') { const trimmed = value.trim() return trimmed.length > 0 ? trimmed : null } if (typeof value === 'number' && Number.isFinite(value)) { return String(value) } return null } // --------------------------------------------------------------------------- // Dedup // --------------------------------------------------------------------------- export const dedupeAssignments = ( assignments: AnyRecord[], ): AnyRecord[] => { const seen = new Set() return assignments.filter((assignment) => { if (!assignment) return false const id = assignment.id != null ? String(assignment.id) : '' const name = assignment.name != null ? String(assignment.name) : '' const key = `${id}::${name}` if (!id && !name) return false if (seen.has(key)) return false seen.add(key) return true }) } // --------------------------------------------------------------------------- // Machine assignments // --------------------------------------------------------------------------- export const normalizeMachineAssignment = (input: unknown): AnyRecord | null => { if (!input) return null if (typeof input === 'string') { const name = toTrimmedString(input) return name ? { id: name, name } : null } if (typeof input === 'number' && Number.isFinite(input)) { const value = String(input) return { id: value, name: value } } const container = (input as AnyRecord).machine || (input as AnyRecord).machineData || input if (!isPlainObject(container)) return null const id = container.id ?? (input as AnyRecord).machineId ?? (input as AnyRecord).id ?? null const name = container.name || (input as AnyRecord).machineName || container.label || container.title || (typeof id === 'string' ? id : null) || (typeof id === 'number' ? String(id) : null) if (id == null && name == null) return null return { id: id != null ? id : null, name: name != null ? name : null, } } export const collectMachineAssignments = (source: unknown): AnyRecord[] => { if (!isPlainObject(source)) return [] const candidates = [ source.machines, source.machineLinks, source.machineAssignments, source.machinesAssignments, source.linkedMachines, ] const assignments: AnyRecord[] = [] candidates.forEach((list) => { if (Array.isArray(list)) { list.forEach((item) => { const normalized = normalizeMachineAssignment(item) if (normalized) assignments.push(normalized) }) } }) if (!assignments.length) { const direct = normalizeMachineAssignment(source.machine) if (direct) assignments.push(direct) } if (!assignments.length) { const idCandidate = source.machineId ?? source.machineID ?? null const nameCandidate = source.machineName ?? null const normalized = normalizeMachineAssignment(nameCandidate || idCandidate) if (normalized) assignments.push(normalized) } return dedupeAssignments(assignments) } // --------------------------------------------------------------------------- // Component assignments // --------------------------------------------------------------------------- export const normalizeComponentAssignment = (input: unknown): AnyRecord | null => { if (!input) return null if (typeof input === 'string') { const value = toTrimmedString(input) return value ? { id: value, name: value } : null } if (typeof input === 'number' && Number.isFinite(input)) { const value = String(input) return { id: value, name: value } } const container = (input as AnyRecord).component || (input as AnyRecord).composant || input if (!isPlainObject(container)) return null const id = container.id ?? (input as AnyRecord).componentId ?? (input as AnyRecord).composantId ?? (input as AnyRecord).id ?? null const name = container.name || (input as AnyRecord).componentName || (input as AnyRecord).composantName || container.label || (typeof id === 'string' ? id : null) || (typeof id === 'number' ? String(id) : null) if (id == null && name == null) return null return { id: id != null ? id : null, name: name != null ? name : null, } } export const collectComponentAssignments = (source: unknown): AnyRecord[] => { if (!isPlainObject(source)) return [] const candidates = [ source.components, source.composants, source.componentLinks, source.linkedComponents, ] const assignments: AnyRecord[] = [] candidates.forEach((list) => { if (Array.isArray(list)) { list.forEach((item) => { const normalized = normalizeComponentAssignment(item) if (normalized) assignments.push(normalized) }) } }) if (!assignments.length) { const direct = normalizeComponentAssignment(source.component || source.composant) if (direct) assignments.push(direct) } if (!assignments.length) { const idCandidate = source.componentId ?? source.composantId ?? null const normalized = normalizeComponentAssignment(idCandidate) if (normalized) assignments.push(normalized) } return dedupeAssignments(assignments) } // --------------------------------------------------------------------------- // Convenience wrappers // --------------------------------------------------------------------------- export const getComponentMachineAssignments = (component: unknown): AnyRecord[] => collectMachineAssignments(component || {}) export const getPieceMachineAssignments = (piece: unknown): AnyRecord[] => collectMachineAssignments(piece || {}) export const getPieceComponentAssignments = (piece: unknown): AnyRecord[] => collectComponentAssignments(piece || {}) // --------------------------------------------------------------------------- // Display // --------------------------------------------------------------------------- export const formatAssignmentList = (assignments: AnyRecord[]): string => { if (!Array.isArray(assignments) || assignments.length === 0) return '' return assignments .map((assignment) => (assignment?.name || assignment?.id) as string) .filter(Boolean) .join(', ') }