refactor(custom-fields) : unify 3 parallel implementations into 1 module

Replace ~2900 lines across 9 files with ~400 lines in 2 files:
- shared/utils/customFields.ts (types + pure helpers)
- composables/useCustomFieldInputs.ts (reactive composable)

Migrated all consumers:
- Backend: add defaultValue to API Platform serialization groups
- Standalone pages: component edit/create, piece edit/create, product edit/create/detail
- Machine page: MachineCustomFieldsCard, MachineInfoCard, useMachineDetailCustomFields
- Hierarchy: ComponentItem, PieceItem
- Shared: CustomFieldDisplay, CustomFieldInputGrid
- Category editor: componentStructure.ts

Deleted:
- entityCustomFieldLogic.ts (335 lines)
- customFieldUtils.ts (440 lines)
- customFieldFormUtils.ts (404 lines)
- useEntityCustomFields.ts (181 lines)
- customFieldFormUtils.test.ts

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-04 13:09:27 +02:00
parent f2eff89e00
commit 894d522036
25 changed files with 861 additions and 2279 deletions

View File

@@ -4,6 +4,7 @@ import {
type ComponentModelStructure,
type ComponentModelStructureNode,
} from '../types/inventory'
import { mergeDefinitionsWithValues } from '../utils/customFields'
// Import for internal use in this file
import { sanitizeCustomFields, sanitizePieces, sanitizeProducts, sanitizeSubcomponents } from './componentStructureSanitize'
@@ -86,30 +87,22 @@ export const cloneStructure = (input: any): ComponentModelStructure => {
export const normalizeStructureForEditor = (input: any): ComponentModelStructure => {
const source = cloneStructure(input)
const sanitizedCustomFields = sanitizeCustomFields(source.customFields)
const customFields = sanitizedCustomFields.map((field) => {
const options = Array.isArray(field.options) ? [...field.options] : []
const optionsText = options.length ? options.join('\n') : ''
const defaultValue =
field.defaultValue !== undefined && field.defaultValue !== null && field.defaultValue !== ''
? String(field.defaultValue)
: null
const copy: ComponentModelCustomField = {
name: field.name,
type: field.type,
required: field.required,
machineContextOnly: !!field.machineContextOnly,
options,
defaultValue,
optionsText,
id: field.id,
customFieldId: field.customFieldId,
}
return copy
})
const merged = mergeDefinitionsWithValues(source.customFields, [])
const customFields: ComponentModelCustomField[] = merged.map((field) => ({
name: field.name,
type: field.type as ComponentModelCustomField['type'],
required: field.required,
machineContextOnly: field.machineContextOnly,
options: field.options,
defaultValue: field.defaultValue,
optionsText: field.optionsText,
id: field.customFieldId ?? undefined,
customFieldId: field.customFieldId ?? undefined,
orderIndex: field.orderIndex,
}))
const result: ComponentModelStructure = {
customFields: customFields as ComponentModelCustomField[],
customFields,
pieces: sanitizePieces(source.pieces),
products: sanitizeProducts(source.products),
subcomponents: hydrateSubcomponents(source.subcomponents),