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
JavaScript
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