UNPKG

@ai-stack/payloadcms

Version:

<p align="center"> <img alt="Payload AI Plugin" src="assets/payload-ai-intro.gif" width="100%" /> </p>

120 lines (119 loc) 4.96 kB
export const updateFieldsConfig = (collectionConfig)=>{ let schemaPathMap = {}; /** * Recursively updates field configuration to inject AI components * @param field - Payload field to process * @param parentPath - Schema path from parent (for nested fields) */ function updateField(field, parentPath = '') { const fieldWithName = field; const currentPath = parentPath ? `${parentPath}.${fieldWithName.name}` : fieldWithName.name; const currentSchemaPath = `${collectionConfig.slug}.${currentPath}`; // Disabled fields/ field types - skip processing const admin = field.admin; if (admin?.disabled || admin?.readOnly || admin?.hidden) { return field; } // Rows are layout-only constructs and should not add to the schema path (like tabs) // Process their nested fields but use parentPath to maintain correct path structure if (field.type === 'row' && 'fields' in field) { const fieldWithFields = field; return { ...field, fields: fieldWithFields.fields.map((subField)=>updateField(subField, parentPath)) }; } // Map field path for global fieldInstructionsMap to load related instructions // This is done due to save extra API call to get instructions when Field components are loaded in admin // Doing is will only call instructions data when user clicks on settings if (field.type && [ 'richText', 'text', 'textarea', 'upload' ].includes(field.type)) { const fieldAny = field; schemaPathMap = { ...schemaPathMap, [currentSchemaPath]: { type: field.type, label: fieldAny.label || fieldWithName.name, relationTo: fieldAny.relationTo } }; } // Inject AI actions, richText is not included here as it has to be explicitly defined by user if (field.type && [ 'text', 'textarea', 'upload' ].includes(field.type)) { const customField = {}; // Custom fields don't fully adhere to the Payload schema, making it difficult to // determine which components support injecting ComposeField as a Description. if (admin?.components) { // TODO: If a field already provides its own Description, we still inject our ComposeField // by overriding Description. If you need both, consider composing your own wrapper. // customField would be used here if needed } return { ...field, admin: { ...field.admin, components: { ...admin?.components || {}, Description: { clientProps: { schemaPath: currentSchemaPath }, path: '@ai-stack/payloadcms/client#ComposeField' }, ...customField } } }; } // Handle fields with nested fields (group, collapsible, etc.) if ('fields' in field && Array.isArray(field.fields)) { const fieldWithFields = field; return { ...field, fields: fieldWithFields.fields.map((subField)=>updateField(subField, currentPath)) }; } // Handle fields with tabs if ('tabs' in field && Array.isArray(field.tabs)) { const fieldWithTabs = field; return { ...field, tabs: fieldWithTabs.tabs.map((tab)=>{ return { ...tab, // Tabs are a UI construct and should not add to the schema path fields: (tab.fields || []).map((subField)=>updateField(subField, parentPath)) }; }) }; } // Handle fields with blocks if ('blocks' in field && Array.isArray(field.blocks)) { const fieldWithBlocks = field; return { ...field, blocks: fieldWithBlocks.blocks.map((block)=>({ ...block, fields: block.fields.map((subField)=>updateField(subField, `${currentPath}.${block.slug}`)) })) }; } return field; } const updatedCollectionConfig = { ...collectionConfig, fields: collectionConfig.fields.map((field)=>updateField(field)) }; return { schemaPathMap, updatedCollectionConfig }; }; //# sourceMappingURL=updateFieldsConfig.js.map