UNPKG

payloadcms-import-export-plugin

Version:

A comprehensive Payload CMS plugin that enables seamless import and export of collection data with support for CSV and JSON formats, featuring advanced field mapping, duplicate handling, and batch processing capabilities.

157 lines (156 loc) 6.87 kB
import { addDataAndFileToRequest, deepMergeSimple, flattenTopLevelFields } from 'payload'; import { flattenObject } from './export/flattenObject.js'; import { getCreateCollectionExportTask } from './export/getCreateExportCollectionTask.js'; import { getCustomFieldFunctions } from './export/getCustomFieldFunctions.js'; import { getSelect } from './export/getSelect.js'; import { getExportCollection } from './getExportCollection.js'; import { getImportCollection } from './getImportCollection.js'; import { translations } from './translations/index.js'; import { getFlattenedFieldKeys } from './utilities/getFlattenedFieldKeys.js'; export const importExportPlugin = (pluginConfig)=>(config)=>{ const exportCollection = getExportCollection({ config, pluginConfig }); const importCollection = getImportCollection({ config, pluginConfig }); if (config.collections) { config.collections.push(exportCollection, importCollection); } else { config.collections = [ exportCollection, importCollection ]; } // inject custom import export provider config.admin = config.admin || {}; config.admin.components = config.admin.components || {}; config.admin.components.providers = config.admin.components.providers || []; config.admin.components.providers.push('payloadcms-import-export-plugin/rsc#ImportExportProvider'); // inject the createExport job into the config if (!config.jobs) { config.jobs = { tasks: [] }; } else if (!Array.isArray(config.jobs.tasks)) { config.jobs.tasks = []; } config.jobs.tasks.push(getCreateCollectionExportTask(config, pluginConfig)); let collectionsToUpdate = config.collections; const usePluginCollections = pluginConfig.collections && pluginConfig.collections?.length > 0; if (usePluginCollections) { collectionsToUpdate = config.collections?.filter((collection)=>{ return pluginConfig.collections?.includes(collection.slug); }); } collectionsToUpdate.forEach((collection)=>{ if (!collection.admin) { collection.admin = { components: { listMenuItems: [] } }; } const components = collection.admin.components || {}; if (!components.listMenuItems) { components.listMenuItems = []; } components.listMenuItems.push({ clientProps: { exportCollectionSlug: exportCollection.slug }, path: 'payloadcms-import-export-plugin/rsc#ExportListMenuItem' }); components.listMenuItems.push({ clientProps: { importCollectionSlug: importCollection.slug }, path: 'payloadcms-import-export-plugin/rsc#ImportListMenuItem' }); // Flatten top-level fields to expose nested fields for export config const flattenedFields = flattenTopLevelFields(collection.fields, true); // Find fields explicitly marked as disabled for import/export const disabledFieldAccessors = flattenedFields.filter((field)=>field.custom?.['plugin-import-export']?.disabled)// .map((field) => field?.accessor || field.name) .map((field)=>field.name); // Store disabled field accessors in the admin config for use in the UI collection.admin.custom = { ...collection.admin.custom || {}, 'plugin-import-export': { ...collection.admin.custom?.['plugin-import-export'] || {}, disabledFields: disabledFieldAccessors } }; collection.admin.components = components; }); if (!config.i18n) { config.i18n = {}; } // config.i18n.translations = deepMergeSimple(translations, config.i18n?.translations ?? {}) // Inject custom REST endpoints into the config config.endpoints = config.endpoints || []; config.endpoints.push({ handler: async (req)=>{ await addDataAndFileToRequest(req); const { collectionSlug, draft, fields, limit, locale, sort, where } = req.data; const collection = req.payload.collections[collectionSlug]; if (!collection) { return Response.json({ error: `Collection with slug ${collectionSlug} not found` }, { status: 400 }); } const select = Array.isArray(fields) && fields.length > 0 ? getSelect(fields) : undefined; const result = await req.payload.find({ collection: collectionSlug, depth: 1, draft: draft === 'yes', limit: limit && limit > 10 ? 10 : limit, locale, overrideAccess: false, req, select, sort, where }); const docs = result.docs; const toCSVFunctions = getCustomFieldFunctions({ fields: collection.config.fields }); const possibleKeys = getFlattenedFieldKeys(collection.config.fields); const transformed = docs.map((doc)=>{ const row = flattenObject({ doc, fields, toCSVFunctions }); for (const key of possibleKeys){ if (!(key in row)) { row[key] = null; } } return row; }); return Response.json({ docs: transformed, totalDocs: result.totalDocs }); }, method: 'post', path: '/preview-data' }); /** * Merge plugin translations */ const simplifiedTranslations = Object.entries(translations).reduce((acc, [key, value])=>{ acc[key] = value?.translations; return acc; }, {}); config.i18n = { ...config.i18n, translations: deepMergeSimple(simplifiedTranslations, config.i18n?.translations ?? {}) }; return config; }; //# sourceMappingURL=index.js.map