feat: plugin-import-export initial work (#10795)
Adds new plugin-import-export initial version.
Allows for direct download and creation of downloadable collection data
stored to a json or csv uses the access control of the user creating the
request to make the file.
config options:
```ts
/**
* Collections to include the Import/Export controls in
* Defaults to all collections
*/
collections?: string[]
/**
* Enable to force the export to run synchronously
*/
disableJobsQueue?: boolean
/**
* This function takes the default export collection configured in the plugin and allows you to override it by modifying and returning it
* @param collection
* @returns collection
*/
overrideExportCollection?: (collection: CollectionOverride) => CollectionOverride
// payload.config.ts:
plugins: [
importExportPlugin({
collections: ['pages', 'users'],
overrideExportCollection: (collection) => {
collection.admin.group = 'System'
collection.upload.staticDir = path.resolve(dirname, 'uploads')
return collection
},
disableJobsQueue: true,
}),
],
```
---------
Co-authored-by: Jessica Chowdhury <jessica@trbl.design>
Co-authored-by: Kendell Joseph <kendelljoseph@gmail.com>
This commit is contained in:
@@ -1232,6 +1232,7 @@ export interface Auth {
|
||||
|
||||
|
||||
declare module 'payload' {
|
||||
// @ts-ignore
|
||||
// @ts-ignore
|
||||
export interface GeneratedTypes extends Config {}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
"@payloadcms/payload-cloud": "workspace:*",
|
||||
"@payloadcms/plugin-cloud-storage": "workspace:*",
|
||||
"@payloadcms/plugin-form-builder": "workspace:*",
|
||||
"@payloadcms/plugin-import-export": "workspace:*",
|
||||
"@payloadcms/plugin-multi-tenant": "workspace:*",
|
||||
"@payloadcms/plugin-nested-docs": "workspace:*",
|
||||
"@payloadcms/plugin-redirects": "workspace:*",
|
||||
@@ -65,6 +66,7 @@
|
||||
"babel-plugin-react-compiler": "19.0.0-beta-714736e-20250131",
|
||||
"comment-json": "^4.2.3",
|
||||
"create-payload-app": "workspace:*",
|
||||
"csv-parse": "^5.6.0",
|
||||
"dequal": "2.0.3",
|
||||
"dotenv": "16.4.7",
|
||||
"drizzle-kit": "0.28.0",
|
||||
|
||||
1
test/plugin-import-export/.gitignore
vendored
Normal file
1
test/plugin-import-export/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
uploads
|
||||
117
test/plugin-import-export/collections/Pages.ts
Normal file
117
test/plugin-import-export/collections/Pages.ts
Normal file
@@ -0,0 +1,117 @@
|
||||
import type { CollectionConfig } from 'payload'
|
||||
|
||||
import { pagesSlug } from '../shared.js'
|
||||
|
||||
export const Pages: CollectionConfig = {
|
||||
slug: pagesSlug,
|
||||
labels: {
|
||||
singular: 'Page',
|
||||
plural: 'Pages',
|
||||
},
|
||||
admin: {
|
||||
useAsTitle: 'title',
|
||||
},
|
||||
versions: {
|
||||
drafts: true,
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
label: 'Title',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'localized',
|
||||
type: 'text',
|
||||
localized: true,
|
||||
},
|
||||
{
|
||||
name: 'group',
|
||||
type: 'group',
|
||||
fields: [
|
||||
{
|
||||
name: 'value',
|
||||
type: 'text',
|
||||
defaultValue: 'group value',
|
||||
},
|
||||
{
|
||||
name: 'ignore',
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
name: 'array',
|
||||
type: 'array',
|
||||
fields: [
|
||||
{
|
||||
name: 'field1',
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
name: 'field2',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'array',
|
||||
type: 'array',
|
||||
fields: [
|
||||
{
|
||||
name: 'field1',
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
name: 'field2',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'blocks',
|
||||
type: 'blocks',
|
||||
blocks: [
|
||||
{
|
||||
slug: 'hero',
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
slug: 'content',
|
||||
fields: [
|
||||
{
|
||||
name: 'richText',
|
||||
type: 'richText',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'author',
|
||||
type: 'relationship',
|
||||
relationTo: 'users',
|
||||
},
|
||||
{
|
||||
name: 'hasManyNumber',
|
||||
type: 'number',
|
||||
hasMany: true,
|
||||
},
|
||||
{
|
||||
name: 'relationship',
|
||||
type: 'relationship',
|
||||
relationTo: 'users',
|
||||
},
|
||||
{
|
||||
name: 'excerpt',
|
||||
label: 'Excerpt',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
}
|
||||
16
test/plugin-import-export/collections/Users.ts
Normal file
16
test/plugin-import-export/collections/Users.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import type { CollectionConfig } from 'payload'
|
||||
|
||||
export const Users: CollectionConfig = {
|
||||
slug: 'users',
|
||||
auth: true,
|
||||
admin: {
|
||||
useAsTitle: 'email',
|
||||
},
|
||||
access: {
|
||||
read: () => true,
|
||||
},
|
||||
fields: [
|
||||
// Email added by default
|
||||
// Add more fields as needed
|
||||
],
|
||||
}
|
||||
51
test/plugin-import-export/config.ts
Normal file
51
test/plugin-import-export/config.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import path from 'path'
|
||||
const filename = fileURLToPath(import.meta.url)
|
||||
const dirname = path.dirname(filename)
|
||||
import { importExportPlugin } from '@payloadcms/plugin-import-export'
|
||||
|
||||
import { buildConfigWithDefaults } from '../buildConfigWithDefaults.js'
|
||||
import { Pages } from './collections/Pages.js'
|
||||
import { Users } from './collections/Users.js'
|
||||
import { seed } from './seed/index.js'
|
||||
|
||||
export default buildConfigWithDefaults({
|
||||
admin: {
|
||||
importMap: {
|
||||
baseDir: path.resolve(dirname),
|
||||
},
|
||||
},
|
||||
collections: [Users, Pages],
|
||||
localization: {
|
||||
defaultLocale: 'en',
|
||||
fallback: true,
|
||||
locales: ['en', 'es', 'de'],
|
||||
},
|
||||
onInit: async (payload) => {
|
||||
await seed(payload)
|
||||
},
|
||||
plugins: [
|
||||
importExportPlugin({
|
||||
overrideExportCollection: (collection) => {
|
||||
collection.admin.group = 'System'
|
||||
collection.upload.staticDir = path.resolve(dirname, 'uploads')
|
||||
return collection
|
||||
},
|
||||
disableJobsQueue: true,
|
||||
}),
|
||||
importExportPlugin({
|
||||
collections: ['pages'],
|
||||
overrideExportCollection: (collection) => {
|
||||
collection.slug = 'exports-tasks'
|
||||
if (collection.admin) {
|
||||
collection.admin.group = 'System'
|
||||
}
|
||||
collection.upload.staticDir = path.resolve(dirname, 'uploads')
|
||||
return collection
|
||||
},
|
||||
}),
|
||||
],
|
||||
typescript: {
|
||||
outputFile: path.resolve(dirname, 'payload-types.ts'),
|
||||
},
|
||||
})
|
||||
50
test/plugin-import-export/e2e.spec.ts
Normal file
50
test/plugin-import-export/e2e.spec.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import type { Page } from '@playwright/test'
|
||||
|
||||
import { expect, test } from '@playwright/test'
|
||||
import * as path from 'path'
|
||||
import { fileURLToPath } from 'url'
|
||||
|
||||
import type { PayloadTestSDK } from '../helpers/sdk/index.js'
|
||||
import type { Config } from './payload-types.js'
|
||||
|
||||
import { ensureCompilationIsDone, initPageConsoleErrorCatch } from '../helpers.js'
|
||||
import { AdminUrlUtil } from '../helpers/adminUrlUtil.js'
|
||||
import { initPayloadE2ENoConfig } from '../helpers/initPayloadE2ENoConfig.js'
|
||||
import { POLL_TOPASS_TIMEOUT, TEST_TIMEOUT_LONG } from '../playwright.config.js'
|
||||
|
||||
const filename = fileURLToPath(import.meta.url)
|
||||
const dirname = path.dirname(filename)
|
||||
|
||||
test.describe('Import Export', () => {
|
||||
let page: Page
|
||||
let pagesURL: AdminUrlUtil
|
||||
let payload: PayloadTestSDK<Config>
|
||||
|
||||
test.beforeAll(async ({ browser }, testInfo) => {
|
||||
testInfo.setTimeout(TEST_TIMEOUT_LONG)
|
||||
const { payload: payloadFromInit, serverURL } = await initPayloadE2ENoConfig<Config>({
|
||||
dirname,
|
||||
})
|
||||
pagesURL = new AdminUrlUtil(serverURL, 'pages')
|
||||
|
||||
payload = payloadFromInit
|
||||
|
||||
const context = await browser.newContext()
|
||||
page = await context.newPage()
|
||||
initPageConsoleErrorCatch(page)
|
||||
|
||||
await ensureCompilationIsDone({ page, serverURL })
|
||||
})
|
||||
|
||||
test.describe('Import', () => {
|
||||
test('works', async () => {
|
||||
// TODO: write e2e tests
|
||||
})
|
||||
})
|
||||
|
||||
test.describe('Export', () => {
|
||||
test('works', async () => {
|
||||
// TODO: write e2e tests
|
||||
})
|
||||
})
|
||||
})
|
||||
19
test/plugin-import-export/eslint.config.js
Normal file
19
test/plugin-import-export/eslint.config.js
Normal file
@@ -0,0 +1,19 @@
|
||||
import { rootParserOptions } from '../../eslint.config.js'
|
||||
import testEslintConfig from '../eslint.config.js'
|
||||
|
||||
/** @typedef {import('eslint').Linter.Config} Config */
|
||||
|
||||
/** @type {Config[]} */
|
||||
export const index = [
|
||||
...testEslintConfig,
|
||||
{
|
||||
languageOptions: {
|
||||
parserOptions: {
|
||||
tsconfigRootDir: import.meta.dirname,
|
||||
...rootParserOptions,
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
export default index
|
||||
51
test/plugin-import-export/helpers.ts
Normal file
51
test/plugin-import-export/helpers.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import { parse } from 'csv-parse'
|
||||
import fs from 'fs'
|
||||
|
||||
export const readCSV = async (path: string): Promise<any[]> => {
|
||||
const buffer = fs.readFileSync(path)
|
||||
const data: any[] = []
|
||||
const promise = new Promise<void>((resolve) => {
|
||||
const parser = parse({ bom: true, columns: true })
|
||||
|
||||
// Collect data from the CSV
|
||||
parser.on('readable', () => {
|
||||
let record
|
||||
while ((record = parser.read())) {
|
||||
data.push(record)
|
||||
}
|
||||
})
|
||||
|
||||
// Resolve the promise on 'end'
|
||||
parser.on('end', () => {
|
||||
resolve()
|
||||
})
|
||||
|
||||
// Handle errors (optional, but good practice)
|
||||
parser.on('error', (error) => {
|
||||
console.error('Error parsing CSV:', error)
|
||||
resolve() // Ensures promise doesn't hang on error
|
||||
})
|
||||
|
||||
// Pipe the buffer into the parser
|
||||
parser.write(buffer)
|
||||
parser.end()
|
||||
})
|
||||
|
||||
// Await the promise
|
||||
await promise
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
export const readJSON = async (path: string): Promise<any[]> => {
|
||||
const buffer = fs.readFileSync(path)
|
||||
const str = buffer.toString()
|
||||
|
||||
try {
|
||||
const json = await JSON.parse(str)
|
||||
return json
|
||||
} catch (error) {
|
||||
console.error('Error reading JSON file:', error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
400
test/plugin-import-export/int.spec.ts
Normal file
400
test/plugin-import-export/int.spec.ts
Normal file
@@ -0,0 +1,400 @@
|
||||
import type { CollectionSlug, Payload } from 'payload'
|
||||
|
||||
import path from 'path'
|
||||
import { fileURLToPath } from 'url'
|
||||
|
||||
import { devUser } from '../credentials.js'
|
||||
import { initPayloadInt } from '../helpers/initPayloadInt.js'
|
||||
import { readCSV, readJSON } from './helpers.js'
|
||||
import { richTextData } from './seed/richTextData.js'
|
||||
|
||||
let payload: Payload
|
||||
let user: any
|
||||
|
||||
const filename = fileURLToPath(import.meta.url)
|
||||
const dirname = path.dirname(filename)
|
||||
|
||||
describe('@payloadcms/plugin-import-export', () => {
|
||||
beforeAll(async () => {
|
||||
;({ payload } = (await initPayloadInt(dirname)) as { payload: Payload })
|
||||
user = await payload.login({
|
||||
collection: 'users',
|
||||
data: {
|
||||
email: devUser.email,
|
||||
password: devUser.password,
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
if (typeof payload.db.destroy === 'function') {
|
||||
await payload.db.destroy()
|
||||
}
|
||||
})
|
||||
|
||||
describe('exports', () => {
|
||||
it('should create a file for collection csv from defined fields', async () => {
|
||||
let doc = await payload.create({
|
||||
collection: 'exports',
|
||||
user,
|
||||
data: {
|
||||
collectionSlug: 'pages',
|
||||
sort: 'createdAt',
|
||||
fields: ['id', 'title', 'group.value', 'group.array.field1', 'createdAt', 'updatedAt'],
|
||||
format: 'csv',
|
||||
where: {
|
||||
title: { contains: 'Title ' },
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
doc = await payload.findByID({
|
||||
collection: 'exports',
|
||||
id: doc.id,
|
||||
})
|
||||
|
||||
expect(doc.filename).toContain('pages.csv')
|
||||
const expectedPath = path.join(dirname, './uploads', doc.filename as string)
|
||||
const data = await readCSV(expectedPath)
|
||||
|
||||
expect(data[0].id).toBeDefined()
|
||||
expect(data[0].title).toStrictEqual('Title 0')
|
||||
expect(data[0].group_value).toStrictEqual('group value')
|
||||
expect(data[0].group_ignore).toBeUndefined()
|
||||
expect(data[0].group_array_0_field1).toStrictEqual('test')
|
||||
expect(data[0].createdAt).toBeDefined()
|
||||
expect(data[0].updatedAt).toBeDefined()
|
||||
})
|
||||
|
||||
it('should create a file for collection csv from one locale', async () => {
|
||||
let doc = await payload.create({
|
||||
collection: 'exports',
|
||||
user,
|
||||
data: {
|
||||
collectionSlug: 'pages',
|
||||
fields: ['id', 'localized'],
|
||||
locale: 'en',
|
||||
format: 'csv',
|
||||
where: {
|
||||
title: { contains: 'Localized ' },
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
doc = await payload.findByID({
|
||||
collection: 'exports',
|
||||
id: doc.id,
|
||||
})
|
||||
|
||||
expect(doc.filename).toBeDefined()
|
||||
const expectedPath = path.join(dirname, './uploads', doc.filename as string)
|
||||
const data = await readCSV(expectedPath)
|
||||
|
||||
expect(data[0].id).toBeDefined()
|
||||
expect(data[0].localized).toStrictEqual('en test')
|
||||
})
|
||||
|
||||
it('should create a file for collection csv from multiple locales', async () => {
|
||||
let doc = await payload.create({
|
||||
collection: 'exports',
|
||||
user,
|
||||
data: {
|
||||
collectionSlug: 'pages',
|
||||
fields: ['id', 'localized'],
|
||||
locale: 'all',
|
||||
format: 'csv',
|
||||
where: {
|
||||
title: { contains: 'Localized ' },
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
doc = await payload.findByID({
|
||||
collection: 'exports',
|
||||
id: doc.id,
|
||||
})
|
||||
|
||||
expect(doc.filename).toBeDefined()
|
||||
const expectedPath = path.join(dirname, './uploads', doc.filename as string)
|
||||
const data = await readCSV(expectedPath)
|
||||
|
||||
expect(data[0].id).toBeDefined()
|
||||
expect(data[0].localized_en).toStrictEqual('en test')
|
||||
expect(data[0].localized_es).toStrictEqual('es test')
|
||||
})
|
||||
|
||||
it('should create a file for collection csv from array', async () => {
|
||||
let doc = await payload.create({
|
||||
collection: 'exports',
|
||||
user,
|
||||
data: {
|
||||
collectionSlug: 'pages',
|
||||
fields: ['id', 'array'],
|
||||
format: 'csv',
|
||||
where: {
|
||||
title: { contains: 'Array ' },
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
doc = await payload.findByID({
|
||||
collection: 'exports',
|
||||
id: doc.id,
|
||||
})
|
||||
|
||||
expect(doc.filename).toBeDefined()
|
||||
const expectedPath = path.join(dirname, './uploads', doc.filename as string)
|
||||
const data = await readCSV(expectedPath)
|
||||
|
||||
expect(data[0].array_0_field1).toStrictEqual('foo')
|
||||
expect(data[0].array_0_field2).toStrictEqual('bar')
|
||||
expect(data[0].array_1_field1).toStrictEqual('foo')
|
||||
expect(data[0].array_1_field2).toStrictEqual('baz')
|
||||
})
|
||||
|
||||
it('should create a file for collection csv from array.subfield', async () => {
|
||||
let doc = await payload.create({
|
||||
collection: 'exports',
|
||||
user,
|
||||
data: {
|
||||
collectionSlug: 'pages',
|
||||
fields: ['id', 'array.field1'],
|
||||
format: 'csv',
|
||||
where: {
|
||||
title: { contains: 'Array Subfield ' },
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
doc = await payload.findByID({
|
||||
collection: 'exports',
|
||||
id: doc.id,
|
||||
})
|
||||
|
||||
expect(doc.filename).toBeDefined()
|
||||
const expectedPath = path.join(dirname, './uploads', doc.filename as string)
|
||||
const data = await readCSV(expectedPath)
|
||||
|
||||
expect(data[0].array_0_field1).toStrictEqual('foo')
|
||||
expect(data[0].array_0_field2).toBeUndefined()
|
||||
expect(data[0].array_1_field1).toStrictEqual('foo')
|
||||
expect(data[0].array_1_field2).toBeUndefined()
|
||||
})
|
||||
|
||||
it('should create a file for collection csv from hasMany field', async () => {
|
||||
let doc = await payload.create({
|
||||
collection: 'exports',
|
||||
user,
|
||||
data: {
|
||||
collectionSlug: 'pages',
|
||||
fields: ['id', 'hasManyNumber'],
|
||||
format: 'csv',
|
||||
where: {
|
||||
title: { contains: 'hasMany Number ' },
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
doc = await payload.findByID({
|
||||
collection: 'exports',
|
||||
id: doc.id,
|
||||
})
|
||||
|
||||
expect(doc.filename).toBeDefined()
|
||||
const expectedPath = path.join(dirname, './uploads', doc.filename as string)
|
||||
const data = await readCSV(expectedPath)
|
||||
|
||||
expect(data[0].hasManyNumber_0).toStrictEqual('0')
|
||||
expect(data[0].hasManyNumber_1).toStrictEqual('1')
|
||||
expect(data[0].hasManyNumber_2).toStrictEqual('1')
|
||||
expect(data[0].hasManyNumber_3).toStrictEqual('2')
|
||||
expect(data[0].hasManyNumber_4).toStrictEqual('3')
|
||||
})
|
||||
|
||||
it('should create a file for collection csv from blocks field', async () => {
|
||||
let doc = await payload.create({
|
||||
collection: 'exports',
|
||||
user,
|
||||
data: {
|
||||
collectionSlug: 'pages',
|
||||
fields: ['id', 'blocks'],
|
||||
format: 'csv',
|
||||
where: {
|
||||
title: { contains: 'Blocks ' },
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
doc = await payload.findByID({
|
||||
collection: 'exports',
|
||||
id: doc.id,
|
||||
})
|
||||
|
||||
expect(doc.filename).toBeDefined()
|
||||
const expectedPath = path.join(dirname, './uploads', doc.filename as string)
|
||||
const data = await readCSV(expectedPath)
|
||||
|
||||
expect(data[0].blocks_0_blockType).toStrictEqual('hero')
|
||||
expect(data[0].blocks_1_blockType).toStrictEqual('content')
|
||||
})
|
||||
|
||||
it('should create a JSON file for collection', async () => {
|
||||
let doc = await payload.create({
|
||||
collection: 'exports',
|
||||
user,
|
||||
data: {
|
||||
collectionSlug: 'pages',
|
||||
fields: ['id', 'title'],
|
||||
format: 'json',
|
||||
sort: 'title',
|
||||
where: {
|
||||
title: { contains: 'JSON ' },
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
doc = await payload.findByID({
|
||||
collection: 'exports',
|
||||
id: doc.id,
|
||||
})
|
||||
|
||||
expect(doc.filename).toBeDefined()
|
||||
const expectedPath = path.join(dirname, './uploads', doc.filename as string)
|
||||
const data = await readJSON(expectedPath)
|
||||
|
||||
expect(data[0].title).toStrictEqual('JSON 0')
|
||||
})
|
||||
|
||||
it('should create an export with every field when no fields are defined', async () => {
|
||||
let doc = await payload.create({
|
||||
collection: 'exports',
|
||||
user,
|
||||
data: {
|
||||
collectionSlug: 'pages',
|
||||
format: 'json',
|
||||
sort: 'title',
|
||||
},
|
||||
})
|
||||
|
||||
doc = await payload.findByID({
|
||||
collection: 'exports',
|
||||
id: doc.id,
|
||||
})
|
||||
|
||||
expect(doc.filename).toBeDefined()
|
||||
const expectedPath = path.join(dirname, './uploads', doc.filename as string)
|
||||
const data = await readJSON(expectedPath)
|
||||
|
||||
expect(data[0].id).toBeDefined()
|
||||
expect(data[0].title).toBeDefined()
|
||||
expect(data[0].createdAt).toBeDefined()
|
||||
expect(data[0].updatedAt).toBeDefined()
|
||||
})
|
||||
|
||||
it('should create jobs task for exports', async () => {
|
||||
const doc = await payload.create({
|
||||
collection: 'exports-tasks' as CollectionSlug,
|
||||
user,
|
||||
data: {
|
||||
collectionSlug: 'pages',
|
||||
fields: ['id', 'title'],
|
||||
format: 'csv',
|
||||
sort: 'title',
|
||||
where: {
|
||||
title: { contains: 'Jobs ' },
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const { docs } = await payload.find({
|
||||
collection: 'payload-jobs' as CollectionSlug,
|
||||
})
|
||||
const job = docs[0]
|
||||
|
||||
expect(job).toBeDefined()
|
||||
|
||||
const { input } = job
|
||||
|
||||
expect(input.id).toBeDefined()
|
||||
expect(input.name).toBeDefined()
|
||||
expect(input.format).toStrictEqual('csv')
|
||||
expect(input.locale).toStrictEqual('all')
|
||||
expect(input.fields).toStrictEqual(['id', 'title'])
|
||||
expect(input.collectionSlug).toStrictEqual('pages')
|
||||
expect(input.exportsCollection).toStrictEqual('exports-tasks')
|
||||
expect(input.user).toBeDefined()
|
||||
expect(input.userCollection).toBeDefined()
|
||||
|
||||
await payload.jobs.run()
|
||||
|
||||
const exportDoc = await payload.findByID({
|
||||
collection: 'exports-tasks' as CollectionSlug,
|
||||
id: doc.id,
|
||||
})
|
||||
|
||||
expect(exportDoc.filename).toBeDefined()
|
||||
const expectedPath = path.join(dirname, './uploads', exportDoc.filename as string)
|
||||
const data = await readCSV(expectedPath)
|
||||
|
||||
expect(data[0].title).toStrictEqual('Jobs 0')
|
||||
})
|
||||
|
||||
// disabled so we don't always run a massive test
|
||||
it.skip('should create a file from a large set of collection documents', async () => {
|
||||
const allPromises = []
|
||||
let promises = []
|
||||
for (let i = 0; i < 100000; i++) {
|
||||
promises.push(
|
||||
payload.create({
|
||||
collectionSlug: 'pages',
|
||||
data: {
|
||||
title: `Array ${i}`,
|
||||
blocks: [
|
||||
{
|
||||
blockType: 'hero',
|
||||
title: 'test',
|
||||
},
|
||||
{
|
||||
blockType: 'content',
|
||||
richText: richTextData,
|
||||
},
|
||||
],
|
||||
},
|
||||
}),
|
||||
)
|
||||
if (promises.length >= 500) {
|
||||
await Promise.all(promises)
|
||||
promises = []
|
||||
}
|
||||
if (i % 1000 === 0) {
|
||||
console.log('created', i)
|
||||
}
|
||||
}
|
||||
await Promise.all(promises)
|
||||
|
||||
console.log('seeded')
|
||||
|
||||
let doc = await payload.create({
|
||||
collection: 'exports',
|
||||
user,
|
||||
data: {
|
||||
collectionSlug: 'pages',
|
||||
fields: ['id', 'blocks'],
|
||||
format: 'csv',
|
||||
},
|
||||
})
|
||||
|
||||
doc = await payload.findByID({
|
||||
collection: 'exports',
|
||||
id: doc.id,
|
||||
})
|
||||
|
||||
expect(doc.filename).toBeDefined()
|
||||
const expectedPath = path.join(dirname, './uploads', doc.filename as string)
|
||||
const data = await readCSV(expectedPath)
|
||||
|
||||
expect(data[0].blocks_0_blockType).toStrictEqual('hero')
|
||||
expect(data[0].blocks_1_blockType).toStrictEqual('content')
|
||||
})
|
||||
})
|
||||
})
|
||||
670
test/plugin-import-export/payload-types.ts
Normal file
670
test/plugin-import-export/payload-types.ts
Normal file
@@ -0,0 +1,670 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* This file was automatically generated by Payload.
|
||||
* DO NOT MODIFY IT BY HAND. Instead, modify your source Payload config,
|
||||
* and re-run `payload generate:types` to regenerate this file.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Supported timezones in IANA format.
|
||||
*
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "supportedTimezones".
|
||||
*/
|
||||
export type SupportedTimezones =
|
||||
| 'Pacific/Midway'
|
||||
| 'Pacific/Niue'
|
||||
| 'Pacific/Honolulu'
|
||||
| 'Pacific/Rarotonga'
|
||||
| 'America/Anchorage'
|
||||
| 'Pacific/Gambier'
|
||||
| 'America/Los_Angeles'
|
||||
| 'America/Tijuana'
|
||||
| 'America/Denver'
|
||||
| 'America/Phoenix'
|
||||
| 'America/Chicago'
|
||||
| 'America/Guatemala'
|
||||
| 'America/New_York'
|
||||
| 'America/Bogota'
|
||||
| 'America/Caracas'
|
||||
| 'America/Santiago'
|
||||
| 'America/Buenos_Aires'
|
||||
| 'America/Sao_Paulo'
|
||||
| 'Atlantic/South_Georgia'
|
||||
| 'Atlantic/Azores'
|
||||
| 'Atlantic/Cape_Verde'
|
||||
| 'Europe/London'
|
||||
| 'Europe/Berlin'
|
||||
| 'Africa/Lagos'
|
||||
| 'Europe/Athens'
|
||||
| 'Africa/Cairo'
|
||||
| 'Europe/Moscow'
|
||||
| 'Asia/Riyadh'
|
||||
| 'Asia/Dubai'
|
||||
| 'Asia/Baku'
|
||||
| 'Asia/Karachi'
|
||||
| 'Asia/Tashkent'
|
||||
| 'Asia/Calcutta'
|
||||
| 'Asia/Dhaka'
|
||||
| 'Asia/Almaty'
|
||||
| 'Asia/Jakarta'
|
||||
| 'Asia/Bangkok'
|
||||
| 'Asia/Shanghai'
|
||||
| 'Asia/Singapore'
|
||||
| 'Asia/Tokyo'
|
||||
| 'Asia/Seoul'
|
||||
| 'Australia/Sydney'
|
||||
| 'Pacific/Guam'
|
||||
| 'Pacific/Noumea'
|
||||
| 'Pacific/Auckland'
|
||||
| 'Pacific/Fiji';
|
||||
|
||||
export interface Config {
|
||||
auth: {
|
||||
users: UserAuthOperations;
|
||||
};
|
||||
blocks: {};
|
||||
collections: {
|
||||
users: User;
|
||||
pages: Page;
|
||||
exports: Export;
|
||||
'exports-tasks': ExportsTask;
|
||||
'payload-jobs': PayloadJob;
|
||||
'payload-locked-documents': PayloadLockedDocument;
|
||||
'payload-preferences': PayloadPreference;
|
||||
'payload-migrations': PayloadMigration;
|
||||
};
|
||||
collectionsJoins: {};
|
||||
collectionsSelect: {
|
||||
users: UsersSelect<false> | UsersSelect<true>;
|
||||
pages: PagesSelect<false> | PagesSelect<true>;
|
||||
exports: ExportsSelect<false> | ExportsSelect<true>;
|
||||
'exports-tasks': ExportsTasksSelect<false> | ExportsTasksSelect<true>;
|
||||
'payload-jobs': PayloadJobsSelect<false> | PayloadJobsSelect<true>;
|
||||
'payload-locked-documents': PayloadLockedDocumentsSelect<false> | PayloadLockedDocumentsSelect<true>;
|
||||
'payload-preferences': PayloadPreferencesSelect<false> | PayloadPreferencesSelect<true>;
|
||||
'payload-migrations': PayloadMigrationsSelect<false> | PayloadMigrationsSelect<true>;
|
||||
};
|
||||
db: {
|
||||
defaultIDType: string;
|
||||
};
|
||||
globals: {};
|
||||
globalsSelect: {};
|
||||
locale: 'en' | 'es' | 'de';
|
||||
user: User & {
|
||||
collection: 'users';
|
||||
};
|
||||
jobs: {
|
||||
tasks: {
|
||||
createCollectionExport: TaskCreateCollectionExport;
|
||||
inline: {
|
||||
input: unknown;
|
||||
output: unknown;
|
||||
};
|
||||
};
|
||||
workflows: unknown;
|
||||
};
|
||||
}
|
||||
export interface UserAuthOperations {
|
||||
forgotPassword: {
|
||||
email: string;
|
||||
password: string;
|
||||
};
|
||||
login: {
|
||||
email: string;
|
||||
password: string;
|
||||
};
|
||||
registerFirstUser: {
|
||||
email: string;
|
||||
password: string;
|
||||
};
|
||||
unlock: {
|
||||
email: string;
|
||||
password: string;
|
||||
};
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "users".
|
||||
*/
|
||||
export interface User {
|
||||
id: string;
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
email: string;
|
||||
resetPasswordToken?: string | null;
|
||||
resetPasswordExpiration?: string | null;
|
||||
salt?: string | null;
|
||||
hash?: string | null;
|
||||
loginAttempts?: number | null;
|
||||
lockUntil?: string | null;
|
||||
password?: string | null;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "pages".
|
||||
*/
|
||||
export interface Page {
|
||||
id: string;
|
||||
title: string;
|
||||
localized?: string | null;
|
||||
group?: {
|
||||
value?: string | null;
|
||||
ignore?: string | null;
|
||||
array?:
|
||||
| {
|
||||
field1?: string | null;
|
||||
field2?: string | null;
|
||||
id?: string | null;
|
||||
}[]
|
||||
| null;
|
||||
};
|
||||
array?:
|
||||
| {
|
||||
field1?: string | null;
|
||||
field2?: string | null;
|
||||
id?: string | null;
|
||||
}[]
|
||||
| null;
|
||||
blocks?:
|
||||
| (
|
||||
| {
|
||||
title?: string | null;
|
||||
id?: string | null;
|
||||
blockName?: string | null;
|
||||
blockType: 'hero';
|
||||
}
|
||||
| {
|
||||
richText?: {
|
||||
root: {
|
||||
type: string;
|
||||
children: {
|
||||
type: string;
|
||||
version: number;
|
||||
[k: string]: unknown;
|
||||
}[];
|
||||
direction: ('ltr' | 'rtl') | null;
|
||||
format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | '';
|
||||
indent: number;
|
||||
version: number;
|
||||
};
|
||||
[k: string]: unknown;
|
||||
} | null;
|
||||
id?: string | null;
|
||||
blockName?: string | null;
|
||||
blockType: 'content';
|
||||
}
|
||||
)[]
|
||||
| null;
|
||||
author?: (string | null) | User;
|
||||
hasManyNumber?: number[] | null;
|
||||
relationship?: (string | null) | User;
|
||||
excerpt?: string | null;
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
_status?: ('draft' | 'published') | null;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "exports".
|
||||
*/
|
||||
export interface Export {
|
||||
id: string;
|
||||
name?: string | null;
|
||||
format: 'csv' | 'json';
|
||||
limit?: number | null;
|
||||
sort?: string | null;
|
||||
locale?: ('all' | 'en' | 'es' | 'de') | null;
|
||||
drafts?: ('true' | 'false') | null;
|
||||
selectionToUse?: ('currentSelection' | 'currentFilters' | 'all') | null;
|
||||
fields?: string[] | null;
|
||||
collectionSlug: string;
|
||||
where?:
|
||||
| {
|
||||
[k: string]: unknown;
|
||||
}
|
||||
| unknown[]
|
||||
| string
|
||||
| number
|
||||
| boolean
|
||||
| null;
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
url?: string | null;
|
||||
thumbnailURL?: string | null;
|
||||
filename?: string | null;
|
||||
mimeType?: string | null;
|
||||
filesize?: number | null;
|
||||
width?: number | null;
|
||||
height?: number | null;
|
||||
focalX?: number | null;
|
||||
focalY?: number | null;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "exports-tasks".
|
||||
*/
|
||||
export interface ExportsTask {
|
||||
id: string;
|
||||
name?: string | null;
|
||||
format: 'csv' | 'json';
|
||||
limit?: number | null;
|
||||
sort?: string | null;
|
||||
locale?: ('all' | 'en' | 'es' | 'de') | null;
|
||||
drafts?: ('true' | 'false') | null;
|
||||
selectionToUse?: ('currentSelection' | 'currentFilters' | 'all') | null;
|
||||
fields?: string[] | null;
|
||||
collectionSlug: string;
|
||||
where?:
|
||||
| {
|
||||
[k: string]: unknown;
|
||||
}
|
||||
| unknown[]
|
||||
| string
|
||||
| number
|
||||
| boolean
|
||||
| null;
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
url?: string | null;
|
||||
thumbnailURL?: string | null;
|
||||
filename?: string | null;
|
||||
mimeType?: string | null;
|
||||
filesize?: number | null;
|
||||
width?: number | null;
|
||||
height?: number | null;
|
||||
focalX?: number | null;
|
||||
focalY?: number | null;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "payload-jobs".
|
||||
*/
|
||||
export interface PayloadJob {
|
||||
id: string;
|
||||
/**
|
||||
* Input data provided to the job
|
||||
*/
|
||||
input?:
|
||||
| {
|
||||
[k: string]: unknown;
|
||||
}
|
||||
| unknown[]
|
||||
| string
|
||||
| number
|
||||
| boolean
|
||||
| null;
|
||||
taskStatus?:
|
||||
| {
|
||||
[k: string]: unknown;
|
||||
}
|
||||
| unknown[]
|
||||
| string
|
||||
| number
|
||||
| boolean
|
||||
| null;
|
||||
completedAt?: string | null;
|
||||
totalTried?: number | null;
|
||||
/**
|
||||
* If hasError is true this job will not be retried
|
||||
*/
|
||||
hasError?: boolean | null;
|
||||
/**
|
||||
* If hasError is true, this is the error that caused it
|
||||
*/
|
||||
error?:
|
||||
| {
|
||||
[k: string]: unknown;
|
||||
}
|
||||
| unknown[]
|
||||
| string
|
||||
| number
|
||||
| boolean
|
||||
| null;
|
||||
/**
|
||||
* Task execution log
|
||||
*/
|
||||
log?:
|
||||
| {
|
||||
executedAt: string;
|
||||
completedAt: string;
|
||||
taskSlug: 'inline' | 'createCollectionExport';
|
||||
taskID: string;
|
||||
input?:
|
||||
| {
|
||||
[k: string]: unknown;
|
||||
}
|
||||
| unknown[]
|
||||
| string
|
||||
| number
|
||||
| boolean
|
||||
| null;
|
||||
output?:
|
||||
| {
|
||||
[k: string]: unknown;
|
||||
}
|
||||
| unknown[]
|
||||
| string
|
||||
| number
|
||||
| boolean
|
||||
| null;
|
||||
state: 'failed' | 'succeeded';
|
||||
error?:
|
||||
| {
|
||||
[k: string]: unknown;
|
||||
}
|
||||
| unknown[]
|
||||
| string
|
||||
| number
|
||||
| boolean
|
||||
| null;
|
||||
id?: string | null;
|
||||
}[]
|
||||
| null;
|
||||
taskSlug?: ('inline' | 'createCollectionExport') | null;
|
||||
queue?: string | null;
|
||||
waitUntil?: string | null;
|
||||
processing?: boolean | null;
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "payload-locked-documents".
|
||||
*/
|
||||
export interface PayloadLockedDocument {
|
||||
id: string;
|
||||
document?:
|
||||
| ({
|
||||
relationTo: 'users';
|
||||
value: string | User;
|
||||
} | null)
|
||||
| ({
|
||||
relationTo: 'pages';
|
||||
value: string | Page;
|
||||
} | null)
|
||||
| ({
|
||||
relationTo: 'exports';
|
||||
value: string | Export;
|
||||
} | null)
|
||||
| ({
|
||||
relationTo: 'exports-tasks';
|
||||
value: string | ExportsTask;
|
||||
} | null)
|
||||
| ({
|
||||
relationTo: 'payload-jobs';
|
||||
value: string | PayloadJob;
|
||||
} | null);
|
||||
globalSlug?: string | null;
|
||||
user: {
|
||||
relationTo: 'users';
|
||||
value: string | User;
|
||||
};
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "payload-preferences".
|
||||
*/
|
||||
export interface PayloadPreference {
|
||||
id: string;
|
||||
user: {
|
||||
relationTo: 'users';
|
||||
value: string | User;
|
||||
};
|
||||
key?: string | null;
|
||||
value?:
|
||||
| {
|
||||
[k: string]: unknown;
|
||||
}
|
||||
| unknown[]
|
||||
| string
|
||||
| number
|
||||
| boolean
|
||||
| null;
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "payload-migrations".
|
||||
*/
|
||||
export interface PayloadMigration {
|
||||
id: string;
|
||||
name?: string | null;
|
||||
batch?: number | null;
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "users_select".
|
||||
*/
|
||||
export interface UsersSelect<T extends boolean = true> {
|
||||
updatedAt?: T;
|
||||
createdAt?: T;
|
||||
email?: T;
|
||||
resetPasswordToken?: T;
|
||||
resetPasswordExpiration?: T;
|
||||
salt?: T;
|
||||
hash?: T;
|
||||
loginAttempts?: T;
|
||||
lockUntil?: T;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "pages_select".
|
||||
*/
|
||||
export interface PagesSelect<T extends boolean = true> {
|
||||
title?: T;
|
||||
localized?: T;
|
||||
group?:
|
||||
| T
|
||||
| {
|
||||
value?: T;
|
||||
ignore?: T;
|
||||
array?:
|
||||
| T
|
||||
| {
|
||||
field1?: T;
|
||||
field2?: T;
|
||||
id?: T;
|
||||
};
|
||||
};
|
||||
array?:
|
||||
| T
|
||||
| {
|
||||
field1?: T;
|
||||
field2?: T;
|
||||
id?: T;
|
||||
};
|
||||
blocks?:
|
||||
| T
|
||||
| {
|
||||
hero?:
|
||||
| T
|
||||
| {
|
||||
title?: T;
|
||||
id?: T;
|
||||
blockName?: T;
|
||||
};
|
||||
content?:
|
||||
| T
|
||||
| {
|
||||
richText?: T;
|
||||
id?: T;
|
||||
blockName?: T;
|
||||
};
|
||||
};
|
||||
author?: T;
|
||||
hasManyNumber?: T;
|
||||
relationship?: T;
|
||||
excerpt?: T;
|
||||
updatedAt?: T;
|
||||
createdAt?: T;
|
||||
_status?: T;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "exports_select".
|
||||
*/
|
||||
export interface ExportsSelect<T extends boolean = true> {
|
||||
name?: T;
|
||||
format?: T;
|
||||
limit?: T;
|
||||
sort?: T;
|
||||
locale?: T;
|
||||
drafts?: T;
|
||||
selectionToUse?: T;
|
||||
fields?: T;
|
||||
collectionSlug?: T;
|
||||
where?: T;
|
||||
updatedAt?: T;
|
||||
createdAt?: T;
|
||||
url?: T;
|
||||
thumbnailURL?: T;
|
||||
filename?: T;
|
||||
mimeType?: T;
|
||||
filesize?: T;
|
||||
width?: T;
|
||||
height?: T;
|
||||
focalX?: T;
|
||||
focalY?: T;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "exports-tasks_select".
|
||||
*/
|
||||
export interface ExportsTasksSelect<T extends boolean = true> {
|
||||
name?: T;
|
||||
format?: T;
|
||||
limit?: T;
|
||||
sort?: T;
|
||||
locale?: T;
|
||||
drafts?: T;
|
||||
selectionToUse?: T;
|
||||
fields?: T;
|
||||
collectionSlug?: T;
|
||||
where?: T;
|
||||
updatedAt?: T;
|
||||
createdAt?: T;
|
||||
url?: T;
|
||||
thumbnailURL?: T;
|
||||
filename?: T;
|
||||
mimeType?: T;
|
||||
filesize?: T;
|
||||
width?: T;
|
||||
height?: T;
|
||||
focalX?: T;
|
||||
focalY?: T;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "payload-jobs_select".
|
||||
*/
|
||||
export interface PayloadJobsSelect<T extends boolean = true> {
|
||||
input?: T;
|
||||
taskStatus?: T;
|
||||
completedAt?: T;
|
||||
totalTried?: T;
|
||||
hasError?: T;
|
||||
error?: T;
|
||||
log?:
|
||||
| T
|
||||
| {
|
||||
executedAt?: T;
|
||||
completedAt?: T;
|
||||
taskSlug?: T;
|
||||
taskID?: T;
|
||||
input?: T;
|
||||
output?: T;
|
||||
state?: T;
|
||||
error?: T;
|
||||
id?: T;
|
||||
};
|
||||
taskSlug?: T;
|
||||
queue?: T;
|
||||
waitUntil?: T;
|
||||
processing?: T;
|
||||
updatedAt?: T;
|
||||
createdAt?: T;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "payload-locked-documents_select".
|
||||
*/
|
||||
export interface PayloadLockedDocumentsSelect<T extends boolean = true> {
|
||||
document?: T;
|
||||
globalSlug?: T;
|
||||
user?: T;
|
||||
updatedAt?: T;
|
||||
createdAt?: T;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "payload-preferences_select".
|
||||
*/
|
||||
export interface PayloadPreferencesSelect<T extends boolean = true> {
|
||||
user?: T;
|
||||
key?: T;
|
||||
value?: T;
|
||||
updatedAt?: T;
|
||||
createdAt?: T;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "payload-migrations_select".
|
||||
*/
|
||||
export interface PayloadMigrationsSelect<T extends boolean = true> {
|
||||
name?: T;
|
||||
batch?: T;
|
||||
updatedAt?: T;
|
||||
createdAt?: T;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "TaskCreateCollectionExport".
|
||||
*/
|
||||
export interface TaskCreateCollectionExport {
|
||||
input: {
|
||||
name?: string | null;
|
||||
format: 'csv' | 'json';
|
||||
limit?: number | null;
|
||||
sort?: string | null;
|
||||
locale?: ('all' | 'en' | 'es' | 'de') | null;
|
||||
drafts?: ('true' | 'false') | null;
|
||||
selectionToUse?: ('currentSelection' | 'currentFilters' | 'all') | null;
|
||||
fields?: string[] | null;
|
||||
collectionSlug: string;
|
||||
where?:
|
||||
| {
|
||||
[k: string]: unknown;
|
||||
}
|
||||
| unknown[]
|
||||
| string
|
||||
| number
|
||||
| boolean
|
||||
| null;
|
||||
user?: string | null;
|
||||
userCollection?: string | null;
|
||||
exportsCollection?: string | null;
|
||||
};
|
||||
output: {
|
||||
success?: boolean | null;
|
||||
};
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "auth".
|
||||
*/
|
||||
export interface Auth {
|
||||
[k: string]: unknown;
|
||||
}
|
||||
|
||||
|
||||
declare module 'payload' {
|
||||
// @ts-ignore
|
||||
export interface GeneratedTypes extends Config {}
|
||||
}
|
||||
135
test/plugin-import-export/seed/index.ts
Normal file
135
test/plugin-import-export/seed/index.ts
Normal file
@@ -0,0 +1,135 @@
|
||||
import type { Payload } from 'payload'
|
||||
|
||||
import { devUser } from '../../credentials.js'
|
||||
import { richTextData } from './richTextData.js'
|
||||
|
||||
export const seed = async (payload: Payload): Promise<boolean> => {
|
||||
payload.logger.info('Seeding data...')
|
||||
try {
|
||||
await payload.create({
|
||||
collection: 'users',
|
||||
data: {
|
||||
email: devUser.email,
|
||||
password: devUser.password,
|
||||
},
|
||||
})
|
||||
// create pages
|
||||
for (let i = 0; i < 5; i++) {
|
||||
await payload.create({
|
||||
collection: 'pages',
|
||||
data: {
|
||||
title: `Title ${i}`,
|
||||
group: {
|
||||
array: [{ field1: 'test' }],
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
for (let i = 0; i < 5; i++) {
|
||||
const doc = await payload.create({
|
||||
collection: 'pages',
|
||||
data: {
|
||||
title: `Localized ${i}`,
|
||||
localized: 'en test',
|
||||
},
|
||||
locale: 'en',
|
||||
})
|
||||
await payload.update({
|
||||
collection: 'pages',
|
||||
id: doc.id,
|
||||
data: {
|
||||
localized: 'es test',
|
||||
},
|
||||
locale: 'es',
|
||||
})
|
||||
}
|
||||
for (let i = 0; i < 5; i++) {
|
||||
await payload.create({
|
||||
collection: 'pages',
|
||||
data: {
|
||||
title: `Array ${i}`,
|
||||
array: [
|
||||
{
|
||||
field1: 'foo',
|
||||
field2: 'bar',
|
||||
},
|
||||
{
|
||||
field1: 'foo',
|
||||
field2: 'baz',
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
}
|
||||
for (let i = 0; i < 5; i++) {
|
||||
await payload.create({
|
||||
collection: 'pages',
|
||||
data: {
|
||||
title: `Array Subfield ${i}`,
|
||||
array: [
|
||||
{
|
||||
field1: 'foo',
|
||||
field2: 'bar',
|
||||
},
|
||||
{
|
||||
field1: 'foo',
|
||||
field2: 'baz',
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
for (let i = 0; i < 5; i++) {
|
||||
await payload.create({
|
||||
collection: 'pages',
|
||||
data: {
|
||||
title: `hasMany Number ${i}`,
|
||||
hasManyNumber: [0, 1, 1, 2, 3, 5, 8, 13, 21],
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
for (let i = 0; i < 5; i++) {
|
||||
await payload.create({
|
||||
collection: 'pages',
|
||||
data: {
|
||||
title: `Blocks ${i}`,
|
||||
blocks: [
|
||||
{
|
||||
blockType: 'hero',
|
||||
title: 'test',
|
||||
},
|
||||
{
|
||||
blockType: 'content',
|
||||
richText: richTextData,
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
for (let i = 0; i < 5; i++) {
|
||||
await payload.create({
|
||||
collection: 'pages',
|
||||
data: {
|
||||
title: `JSON ${i}`,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
for (let i = 0; i < 5; i++) {
|
||||
await payload.create({
|
||||
collection: 'pages',
|
||||
data: {
|
||||
title: `Jobs ${i}`,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
return true
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
return false
|
||||
}
|
||||
}
|
||||
110
test/plugin-import-export/seed/richTextData.ts
Normal file
110
test/plugin-import-export/seed/richTextData.ts
Normal file
@@ -0,0 +1,110 @@
|
||||
export const richTextData = {
|
||||
root: {
|
||||
children: [
|
||||
{
|
||||
children: [
|
||||
{
|
||||
detail: 0,
|
||||
format: 0,
|
||||
mode: 'normal',
|
||||
style: '',
|
||||
text: 'This is some content in a block',
|
||||
type: 'text',
|
||||
version: 1,
|
||||
},
|
||||
],
|
||||
direction: 'ltr',
|
||||
format: '',
|
||||
indent: 0,
|
||||
type: 'heading',
|
||||
version: 1,
|
||||
tag: 'h2',
|
||||
},
|
||||
{
|
||||
children: [
|
||||
{
|
||||
detail: 0,
|
||||
format: 0,
|
||||
mode: 'normal',
|
||||
style: '',
|
||||
text: 'Paragraph of text',
|
||||
type: 'text',
|
||||
version: 1,
|
||||
},
|
||||
],
|
||||
direction: 'ltr',
|
||||
format: '',
|
||||
indent: 0,
|
||||
type: 'paragraph',
|
||||
version: 1,
|
||||
textFormat: 0,
|
||||
textStyle: '',
|
||||
},
|
||||
{
|
||||
children: [
|
||||
{
|
||||
children: [
|
||||
{
|
||||
detail: 0,
|
||||
format: 0,
|
||||
mode: 'normal',
|
||||
style: '',
|
||||
text: 'Testing ',
|
||||
type: 'text',
|
||||
version: 1,
|
||||
},
|
||||
],
|
||||
direction: 'ltr',
|
||||
format: '',
|
||||
indent: 0,
|
||||
type: 'listitem',
|
||||
version: 1,
|
||||
value: 1,
|
||||
},
|
||||
{
|
||||
children: [
|
||||
{
|
||||
detail: 0,
|
||||
format: 0,
|
||||
mode: 'normal',
|
||||
style: '',
|
||||
text: 'Richtext',
|
||||
type: 'text',
|
||||
version: 1,
|
||||
},
|
||||
],
|
||||
direction: 'ltr',
|
||||
format: '',
|
||||
indent: 0,
|
||||
type: 'listitem',
|
||||
version: 1,
|
||||
value: 2,
|
||||
},
|
||||
],
|
||||
direction: 'ltr',
|
||||
format: '',
|
||||
indent: 0,
|
||||
type: 'list',
|
||||
version: 1,
|
||||
listType: 'number',
|
||||
start: 1,
|
||||
tag: 'ol',
|
||||
},
|
||||
{
|
||||
children: [],
|
||||
direction: 'ltr',
|
||||
format: '',
|
||||
indent: 0,
|
||||
type: 'paragraph',
|
||||
version: 1,
|
||||
textFormat: 0,
|
||||
textStyle: '',
|
||||
},
|
||||
],
|
||||
direction: 'ltr',
|
||||
format: '',
|
||||
indent: 0,
|
||||
type: 'root',
|
||||
version: 1,
|
||||
},
|
||||
}
|
||||
1
test/plugin-import-export/shared.ts
Normal file
1
test/plugin-import-export/shared.ts
Normal file
@@ -0,0 +1 @@
|
||||
export const pagesSlug = 'pages'
|
||||
13
test/plugin-import-export/tsconfig.eslint.json
Normal file
13
test/plugin-import-export/tsconfig.eslint.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
// extend your base config to share compilerOptions, etc
|
||||
//"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
// ensure that nobody can accidentally use this config for a build
|
||||
"noEmit": true
|
||||
},
|
||||
"include": [
|
||||
// whatever paths you intend to lint
|
||||
"./**/*.ts",
|
||||
"./**/*.tsx"
|
||||
]
|
||||
}
|
||||
3
test/plugin-import-export/tsconfig.json
Normal file
3
test/plugin-import-export/tsconfig.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"extends": "../tsconfig.json"
|
||||
}
|
||||
@@ -23,6 +23,7 @@ export const tgzToPkgNameMap = {
|
||||
'@payloadcms/payload-cloud': 'payloadcms-payload-cloud-*',
|
||||
'@payloadcms/plugin-cloud-storage': 'payloadcms-plugin-cloud-storage-*',
|
||||
'@payloadcms/plugin-form-builder': 'payloadcms-plugin-form-builder-*',
|
||||
'@payloadcms/plugin-import-export': 'payloadcms-plugin-import-export-*',
|
||||
'@payloadcms/plugin-multi-tenant': 'payloadcms-plugin-multi-tenant-*',
|
||||
'@payloadcms/plugin-nested-docs': 'payloadcms-plugin-nested-docs-*',
|
||||
'@payloadcms/plugin-redirects': 'payloadcms-plugin-redirects-*',
|
||||
|
||||
Reference in New Issue
Block a user