add sub componet in catego ske
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import {
|
||||
createEmptyComponentModelStructure,
|
||||
type ComponentModelCustomFieldType,
|
||||
type ComponentModelCustomField,
|
||||
type ComponentModelPiece,
|
||||
type ComponentModelStructure,
|
||||
@@ -61,6 +62,31 @@ export const cloneStructure = (input: any): ComponentModelStructure => {
|
||||
}
|
||||
}
|
||||
|
||||
const toStringArray = (input: unknown): string[] | undefined => {
|
||||
if (!Array.isArray(input)) {
|
||||
return undefined
|
||||
}
|
||||
const parsed = input
|
||||
.map((value) => {
|
||||
if (typeof value === 'string') {
|
||||
return value.trim()
|
||||
}
|
||||
if (value === null || value === undefined) {
|
||||
return ''
|
||||
}
|
||||
return String(value).trim()
|
||||
})
|
||||
.filter((value) => value.length > 0)
|
||||
return parsed.length ? parsed : undefined
|
||||
}
|
||||
|
||||
const extractFieldValueObject = (field: any): Record<string, any> => {
|
||||
if (isPlainObject(field?.value)) {
|
||||
return field.value as Record<string, any>
|
||||
}
|
||||
return {}
|
||||
}
|
||||
|
||||
const sanitizeCustomFields = (fields: any[]): ComponentModelCustomField[] => {
|
||||
if (!Array.isArray(fields)) {
|
||||
return []
|
||||
@@ -68,32 +94,84 @@ const sanitizeCustomFields = (fields: any[]): ComponentModelCustomField[] => {
|
||||
|
||||
return fields
|
||||
.map((field) => {
|
||||
const name = typeof field?.name === 'string' ? field.name.trim() : ''
|
||||
const rawName =
|
||||
typeof field?.name === 'string'
|
||||
? field.name
|
||||
: typeof field?.key === 'string'
|
||||
? field.key
|
||||
: ''
|
||||
const name = rawName.trim()
|
||||
if (!name) {
|
||||
return null
|
||||
}
|
||||
|
||||
const type = typeof field?.type === 'string' && field.type ? field.type : 'text'
|
||||
const required = !!field?.required
|
||||
const valueObject = extractFieldValueObject(field)
|
||||
|
||||
const candidateType =
|
||||
typeof field?.type === 'string' && field.type
|
||||
? field.type
|
||||
: typeof valueObject?.type === 'string'
|
||||
? valueObject.type
|
||||
: ''
|
||||
const allowedTypes: ComponentModelCustomFieldType[] = ['text', 'number', 'select', 'boolean', 'date']
|
||||
const type = allowedTypes.includes(candidateType as ComponentModelCustomFieldType)
|
||||
? (candidateType as ComponentModelCustomFieldType)
|
||||
: 'text'
|
||||
|
||||
const required =
|
||||
typeof valueObject?.required === 'boolean' ? valueObject.required : !!field?.required
|
||||
|
||||
let options: string[] | undefined
|
||||
if (type === 'select') {
|
||||
const rawOptions = typeof field?.optionsText === 'string'
|
||||
? field.optionsText
|
||||
: Array.isArray(field?.options)
|
||||
? field.options.join('\n')
|
||||
: ''
|
||||
const parsed = rawOptions
|
||||
.split(/\r?\n/)
|
||||
.map((option) => option.trim())
|
||||
.filter((option) => option.length > 0)
|
||||
options = parsed.length > 0 ? parsed : undefined
|
||||
options =
|
||||
toStringArray(valueObject?.options) ||
|
||||
toStringArray((valueObject as any)?.choices) ||
|
||||
toStringArray(field?.options)
|
||||
|
||||
if (!options && typeof field?.optionsText === 'string') {
|
||||
const parsedFromText = field.optionsText
|
||||
.split(/\r?\n/)
|
||||
.map((option) => option.trim())
|
||||
.filter((option) => option.length > 0)
|
||||
options = parsedFromText.length ? parsedFromText : undefined
|
||||
}
|
||||
}
|
||||
|
||||
const result: ComponentModelCustomField = { name, type, required }
|
||||
if (options) {
|
||||
result.options = options
|
||||
}
|
||||
const defaultCandidate =
|
||||
field?.defaultValue ?? valueObject?.defaultValue ?? field?.value ?? field?.default ?? null
|
||||
const resolvedDefault = (() => {
|
||||
if (defaultCandidate === undefined || defaultCandidate === null) {
|
||||
return undefined
|
||||
}
|
||||
if (typeof defaultCandidate === 'object') {
|
||||
if (defaultCandidate === null) {
|
||||
return undefined
|
||||
}
|
||||
if ('defaultValue' in (defaultCandidate as Record<string, any>)) {
|
||||
return (defaultCandidate as Record<string, any>).defaultValue
|
||||
}
|
||||
if ('value' in (defaultCandidate as Record<string, any>)) {
|
||||
return (defaultCandidate as Record<string, any>).value
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
return defaultCandidate
|
||||
})()
|
||||
if (resolvedDefault !== undefined && resolvedDefault !== null && resolvedDefault !== '') {
|
||||
result.defaultValue = String(resolvedDefault)
|
||||
}
|
||||
const id = typeof field?.id === 'string' ? field.id : undefined
|
||||
if (id) {
|
||||
result.id = id
|
||||
}
|
||||
const customFieldId = typeof field?.customFieldId === 'string' ? field.customFieldId : undefined
|
||||
if (customFieldId) {
|
||||
result.customFieldId = customFieldId
|
||||
}
|
||||
return result
|
||||
})
|
||||
.filter((field): field is ComponentModelCustomField => !!field)
|
||||
@@ -207,13 +285,142 @@ const sanitizeSubcomponents = (components: any[]): ComponentModelStructureNode[]
|
||||
.filter((component): component is ComponentModelStructureNode => !!component)
|
||||
}
|
||||
|
||||
export const normalizeStructureForSave = (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,
|
||||
options,
|
||||
defaultValue,
|
||||
optionsText,
|
||||
id: field.id,
|
||||
customFieldId: field.customFieldId,
|
||||
}
|
||||
return copy
|
||||
})
|
||||
|
||||
const result: ComponentModelStructure = {
|
||||
customFields: sanitizeCustomFields(source.customFields),
|
||||
customFields: customFields as ComponentModelCustomField[],
|
||||
pieces: sanitizePieces(source.pieces),
|
||||
subcomponents: sanitizeSubcomponents(source.subcomponents),
|
||||
subcomponents: hydrateSubcomponents(source.subcomponents),
|
||||
}
|
||||
|
||||
if (typeof source.typeComposantId === 'string' && source.typeComposantId.length > 0) {
|
||||
result.typeComposantId = source.typeComposantId
|
||||
}
|
||||
if (typeof source.typeComposantLabel === 'string' && source.typeComposantLabel.length > 0) {
|
||||
result.typeComposantLabel = source.typeComposantLabel
|
||||
}
|
||||
if (typeof source.modelId === 'string' && source.modelId.length > 0) {
|
||||
result.modelId = source.modelId
|
||||
}
|
||||
if (typeof source.familyCode === 'string' && source.familyCode.length > 0) {
|
||||
result.familyCode = source.familyCode
|
||||
}
|
||||
if (typeof source.alias === 'string' && source.alias.length > 0) {
|
||||
result.alias = source.alias
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
export const normalizeStructureForSave = (input: any): any => {
|
||||
const source = cloneStructure(input)
|
||||
|
||||
const sanitizedCustomFields = sanitizeCustomFields(source.customFields)
|
||||
const backendCustomFields = sanitizedCustomFields.map((field) => {
|
||||
const value: Record<string, any> = {
|
||||
type: field.type,
|
||||
required: !!field.required,
|
||||
}
|
||||
if (field.options && field.options.length) {
|
||||
value.options = field.options
|
||||
}
|
||||
if (field.defaultValue !== undefined && field.defaultValue !== null && field.defaultValue !== '') {
|
||||
value.defaultValue = field.defaultValue
|
||||
}
|
||||
const payload: Record<string, any> = {
|
||||
key: field.name,
|
||||
value,
|
||||
}
|
||||
if (field.id) {
|
||||
payload.id = field.id
|
||||
}
|
||||
if (field.customFieldId) {
|
||||
payload.customFieldId = field.customFieldId
|
||||
}
|
||||
return payload
|
||||
}) as any
|
||||
|
||||
const backendPieces = sanitizePieces(source.pieces).map((piece) => {
|
||||
const payload: Record<string, any> = {}
|
||||
if ((piece as any).familyCode) {
|
||||
payload.familyCode = (piece as any).familyCode
|
||||
}
|
||||
if (piece.typePieceId) {
|
||||
payload.typePieceId = piece.typePieceId
|
||||
}
|
||||
if (piece.typePieceLabel) {
|
||||
payload.typePieceLabel = piece.typePieceLabel
|
||||
}
|
||||
if (piece.reference) {
|
||||
payload.reference = piece.reference
|
||||
}
|
||||
return payload
|
||||
}) as any
|
||||
|
||||
const mapSubcomponentForSave = (subcomponent: ComponentModelStructureNode): any => {
|
||||
const payload: Record<string, any> = {}
|
||||
if (subcomponent.typeComposantId) {
|
||||
payload.typeComposantId = subcomponent.typeComposantId
|
||||
}
|
||||
if (subcomponent.modelId) {
|
||||
payload.modelId = subcomponent.modelId
|
||||
}
|
||||
if (subcomponent.familyCode) {
|
||||
payload.familyCode = subcomponent.familyCode
|
||||
}
|
||||
if (subcomponent.alias) {
|
||||
payload.alias = subcomponent.alias
|
||||
}
|
||||
if (Array.isArray(subcomponent.subcomponents) && subcomponent.subcomponents.length) {
|
||||
payload.subcomponents = subcomponent.subcomponents.map(mapSubcomponentForSave)
|
||||
}
|
||||
return payload
|
||||
}
|
||||
|
||||
const backendSubcomponents = sanitizeSubcomponents(source.subcomponents).map(mapSubcomponentForSave) as any
|
||||
|
||||
const result: ComponentModelStructure = {
|
||||
customFields: backendCustomFields,
|
||||
pieces: backendPieces,
|
||||
subcomponents: backendSubcomponents,
|
||||
}
|
||||
|
||||
if (typeof source.typeComposantId === 'string' && source.typeComposantId.length > 0) {
|
||||
(result as any).typeComposantId = source.typeComposantId
|
||||
}
|
||||
if (typeof source.typeComposantLabel === 'string' && source.typeComposantLabel.length > 0) {
|
||||
(result as any).typeComposantLabel = source.typeComposantLabel
|
||||
}
|
||||
if (typeof source.modelId === 'string' && source.modelId.length > 0) {
|
||||
(result as any).modelId = source.modelId
|
||||
}
|
||||
if (typeof source.familyCode === 'string' && source.familyCode.length > 0) {
|
||||
(result as any).familyCode = source.familyCode
|
||||
}
|
||||
if (typeof source.alias === 'string' && source.alias.length > 0) {
|
||||
(result as any).alias = source.alias
|
||||
}
|
||||
|
||||
return result
|
||||
@@ -224,13 +431,83 @@ const hydrateCustomFields = (fields: any[]): any[] => {
|
||||
return []
|
||||
}
|
||||
|
||||
return fields.map((field) => ({
|
||||
name: field?.name ?? '',
|
||||
type: field?.type ?? 'text',
|
||||
required: !!field?.required,
|
||||
options: Array.isArray(field?.options) ? field.options : [],
|
||||
optionsText: Array.isArray(field?.options) ? field.options.join('\n') : (field?.optionsText ?? ''),
|
||||
}))
|
||||
return fields.map((field) => {
|
||||
const valueObject = extractFieldValueObject(field)
|
||||
const name = typeof field?.name === 'string'
|
||||
? field.name
|
||||
: typeof field?.key === 'string'
|
||||
? field.key
|
||||
: ''
|
||||
|
||||
const candidateType =
|
||||
typeof field?.type === 'string' && field.type
|
||||
? field.type
|
||||
: typeof valueObject?.type === 'string'
|
||||
? valueObject.type
|
||||
: ''
|
||||
const allowedTypes: ComponentModelCustomFieldType[] = ['text', 'number', 'select', 'boolean', 'date']
|
||||
const type = allowedTypes.includes(candidateType as ComponentModelCustomFieldType)
|
||||
? (candidateType as ComponentModelCustomFieldType)
|
||||
: 'text'
|
||||
|
||||
const required =
|
||||
typeof field?.required === 'boolean'
|
||||
? field.required
|
||||
: typeof valueObject?.required === 'boolean'
|
||||
? valueObject.required
|
||||
: false
|
||||
|
||||
const options =
|
||||
toStringArray(field?.options) ||
|
||||
toStringArray(valueObject?.options) ||
|
||||
toStringArray((valueObject as any)?.choices) ||
|
||||
[]
|
||||
|
||||
const optionsText = typeof field?.optionsText === 'string'
|
||||
? field.optionsText
|
||||
: options.length
|
||||
? options.join('\n')
|
||||
: ''
|
||||
|
||||
const defaultCandidate =
|
||||
field?.defaultValue ?? valueObject?.defaultValue ?? field?.value ?? field?.default ?? null
|
||||
const resolvedDefault = (() => {
|
||||
if (defaultCandidate === undefined || defaultCandidate === null) {
|
||||
return undefined
|
||||
}
|
||||
if (typeof defaultCandidate === 'object') {
|
||||
if (defaultCandidate === null) {
|
||||
return undefined
|
||||
}
|
||||
if ('defaultValue' in (defaultCandidate as Record<string, any>)) {
|
||||
return (defaultCandidate as Record<string, any>).defaultValue
|
||||
}
|
||||
if ('value' in (defaultCandidate as Record<string, any>)) {
|
||||
return (defaultCandidate as Record<string, any>).value
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
return defaultCandidate
|
||||
})()
|
||||
const defaultValue =
|
||||
resolvedDefault !== undefined && resolvedDefault !== null && resolvedDefault !== ''
|
||||
? String(resolvedDefault)
|
||||
: ''
|
||||
|
||||
const id = typeof field?.id === 'string' ? field.id : undefined
|
||||
const customFieldId = typeof field?.customFieldId === 'string' ? field.customFieldId : undefined
|
||||
|
||||
return {
|
||||
name,
|
||||
type,
|
||||
required,
|
||||
options,
|
||||
optionsText,
|
||||
defaultValue,
|
||||
id,
|
||||
customFieldId,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const hydratePieces = (pieces: any[]): ComponentModelPiece[] => {
|
||||
@@ -280,27 +557,29 @@ export const hydrateStructureForEditor = (input: any): ComponentModelStructure =
|
||||
}
|
||||
}
|
||||
|
||||
const toOptionsText = (field: any) => {
|
||||
if (typeof field?.optionsText === 'string') {
|
||||
return field.optionsText
|
||||
}
|
||||
if (Array.isArray(field?.options)) {
|
||||
return field.options.join('\n')
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
const mapComponentCustomFields = (fields: any[]) => {
|
||||
if (!Array.isArray(fields)) {
|
||||
return []
|
||||
}
|
||||
return fields.map((field) => ({
|
||||
name: field?.name ?? '',
|
||||
type: field?.type ?? 'text',
|
||||
required: !!field?.required,
|
||||
options: Array.isArray(field?.options) ? field.options : [],
|
||||
optionsText: toOptionsText(field),
|
||||
}))
|
||||
return hydrateCustomFields(fields).map((field) => {
|
||||
const defaultValue =
|
||||
field?.defaultValue !== undefined && field?.defaultValue !== null && field?.defaultValue !== ''
|
||||
? field.defaultValue
|
||||
: null
|
||||
return {
|
||||
name: typeof field?.name === 'string' ? field.name : '',
|
||||
type: field?.type ?? 'text',
|
||||
required: !!field?.required,
|
||||
options: Array.isArray(field?.options) ? field.options : [],
|
||||
optionsText: typeof field?.optionsText === 'string' ? field.optionsText : '',
|
||||
defaultValue,
|
||||
id: typeof (field as any)?.id === 'string' ? (field as any).id : undefined,
|
||||
customFieldId:
|
||||
typeof (field as any)?.customFieldId === 'string'
|
||||
? (field as any).customFieldId
|
||||
: undefined,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const mapComponentPieces = (pieces: any[]): ComponentModelPiece[] => {
|
||||
@@ -352,7 +631,7 @@ export const extractStructureFromComponent = (component: any) => {
|
||||
alias: component?.alias ?? component?.name ?? '',
|
||||
}
|
||||
|
||||
return normalizeStructureForSave(raw)
|
||||
return normalizeStructureForEditor(raw)
|
||||
}
|
||||
|
||||
export const computeStructureStats = (structure: any): ModelStructurePreview => {
|
||||
@@ -518,7 +797,11 @@ const hydratePieceCustomFields = (fields: any[]): PieceModelStructureEditorField
|
||||
type: field?.type ?? 'text',
|
||||
required: !!field?.required,
|
||||
options: Array.isArray(field?.options) ? field.options : undefined,
|
||||
optionsText: Array.isArray(field?.options) ? field.options.join('\n') : (field?.optionsText ?? ''),
|
||||
optionsText: typeof field?.optionsText === 'string'
|
||||
? field.optionsText
|
||||
: Array.isArray(field?.options)
|
||||
? field.options.join('\n')
|
||||
: '',
|
||||
}))
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,10 @@ export interface ComponentModelCustomField {
|
||||
type: ComponentModelCustomFieldType
|
||||
required: boolean
|
||||
options?: string[]
|
||||
defaultValue?: string | null
|
||||
optionsText?: string
|
||||
id?: string
|
||||
customFieldId?: string
|
||||
}
|
||||
|
||||
export interface ComponentModelPiece {
|
||||
|
||||
Reference in New Issue
Block a user