diff --git a/packages/plugin-import-export/src/components/ExportSaveButton/index.tsx b/packages/plugin-import-export/src/components/ExportSaveButton/index.tsx index cf8d0d3dc60..67aa84644eb 100644 --- a/packages/plugin-import-export/src/components/ExportSaveButton/index.tsx +++ b/packages/plugin-import-export/src/components/ExportSaveButton/index.tsx @@ -73,7 +73,17 @@ export const ExportSaveButton: React.FC = () => { } if (!response.ok) { - throw new Error('Failed to download file') + // Try to parse the error message from the JSON response + let errorMsg = 'Failed to download file' + try { + const errorJson = await response.json() + if (errorJson?.errors?.[0]?.message) { + errorMsg = errorJson.errors[0].message + } + } catch { + // Ignore JSON parse errors, fallback to generic message + } + throw new Error(errorMsg) } const fileStream = response.body @@ -98,9 +108,8 @@ export const ExportSaveButton: React.FC = () => { a.click() document.body.removeChild(a) URL.revokeObjectURL(url) - } catch (error) { - console.error('Error downloading file:', error) - toast.error('Error downloading file') + } catch (error: any) { + toast.error(error.message || 'Error downloading file') } } diff --git a/packages/plugin-import-export/src/components/Page/index.scss b/packages/plugin-import-export/src/components/Page/index.scss new file mode 100644 index 00000000000..286b05914a1 --- /dev/null +++ b/packages/plugin-import-export/src/components/Page/index.scss @@ -0,0 +1,3 @@ +.page-field { + --field-width: 33.3333%; +} diff --git a/packages/plugin-import-export/src/components/Page/index.tsx b/packages/plugin-import-export/src/components/Page/index.tsx new file mode 100644 index 00000000000..81c5e95c89f --- /dev/null +++ b/packages/plugin-import-export/src/components/Page/index.tsx @@ -0,0 +1,41 @@ +'use client' + +import type { NumberFieldClientComponent } from 'payload' + +import { NumberField, useField } from '@payloadcms/ui' +import React, { useEffect } from 'react' + +import './index.scss' + +const baseClass = 'page-field' + +export const Page: NumberFieldClientComponent = (props) => { + const { setValue } = useField() + const { value: limitValue } = useField({ path: 'limit' }) + + // Effect to reset page to 1 if limit is removed + useEffect(() => { + if (!limitValue) { + setValue(1) // Reset page to 1 + } + }, [limitValue, setValue]) + + return ( +
+ setValue(value ?? 1)} // Update the page value on change + path={props.path} + /> +
+ ) +} diff --git a/packages/plugin-import-export/src/components/Preview/index.tsx b/packages/plugin-import-export/src/components/Preview/index.tsx index 3dbdd9a417e..cc5dbb3171a 100644 --- a/packages/plugin-import-export/src/components/Preview/index.tsx +++ b/packages/plugin-import-export/src/components/Preview/index.tsx @@ -28,6 +28,7 @@ export const Preview = () => { const { collection } = useImportExport() const { config } = useConfig() const { value: where } = useField({ path: 'where' }) + const { value: page } = useField({ path: 'page' }) const { value: limit } = useField({ path: 'limit' }) const { value: fields } = useField({ path: 'fields' }) const { value: sort } = useField({ path: 'sort' }) @@ -71,6 +72,7 @@ export const Preview = () => { format, limit, locale, + page, sort, where, }), @@ -168,6 +170,7 @@ export const Preview = () => { i18n, limit, locale, + page, sort, where, ]) diff --git a/packages/plugin-import-export/src/components/SortBy/index.scss b/packages/plugin-import-export/src/components/SortBy/index.scss index b142d9f3c35..1f99204e341 100644 --- a/packages/plugin-import-export/src/components/SortBy/index.scss +++ b/packages/plugin-import-export/src/components/SortBy/index.scss @@ -1,4 +1,3 @@ .sort-by-fields { - display: block; - width: 33%; + --field-width: 25%; } diff --git a/packages/plugin-import-export/src/components/SortBy/index.tsx b/packages/plugin-import-export/src/components/SortBy/index.tsx index 8952ba4d959..742f362f1bc 100644 --- a/packages/plugin-import-export/src/components/SortBy/index.tsx +++ b/packages/plugin-import-export/src/components/SortBy/index.tsx @@ -15,6 +15,7 @@ import React, { useEffect, useState } from 'react' import { reduceFields } from '../FieldsToExport/reduceFields.js' import { useImportExport } from '../ImportExportProvider/index.js' +import './index.scss' const baseClass = 'sort-by-fields' @@ -71,7 +72,7 @@ export const SortBy: SelectFieldClientComponent = (props) => { } return ( -
+
{ locale: localeInput, sort, user, + page, + limit: incomingLimit, where, }, req: { locale: localeArg, payload }, @@ -87,14 +92,30 @@ export const createExport = async (args: CreateExportArgs) => { req.payload.logger.debug({ message: 'Export configuration:', name, isCSV, locale }) } + const batchSize = 100 // fixed per request + + const hardLimit = + typeof incomingLimit === 'number' && incomingLimit > 0 ? incomingLimit : undefined + + const { totalDocs } = await payload.count({ + collection: collectionSlug, + user, + locale, + overrideAccess: false, + }) + + const totalPages = Math.max(1, Math.ceil(totalDocs / batchSize)) + const requestedPage = page || 1 + const adjustedPage = requestedPage > totalPages ? 1 : requestedPage + const findArgs = { collection: collectionSlug, depth: 1, draft: drafts === 'yes', - limit: 100, + limit: batchSize, locale, overrideAccess: false, - page: 0, + page: 0, // The page will be incremented manually in the loop select, sort, user, @@ -156,15 +177,37 @@ export const createExport = async (args: CreateExportArgs) => { req.payload.logger.debug('Pre-scanning all columns before streaming') } + const limitErrorMsg = validateLimitValue( + incomingLimit, + req.t, + batchSize, // step i.e. 100 + ) + if (limitErrorMsg) { + throw new APIError(limitErrorMsg) + } + const allColumns: string[] = [] if (isCSV) { const allColumnsSet = new Set() - let scanPage = 1 + + // Use the incoming page value here, defaulting to 1 if undefined + let scanPage = adjustedPage let hasMore = true + let fetched = 0 + const maxDocs = typeof hardLimit === 'number' ? hardLimit : Number.POSITIVE_INFINITY while (hasMore) { - const result = await payload.find({ ...findArgs, page: scanPage }) + const remaining = Math.max(0, maxDocs - fetched) + if (remaining === 0) { + break + } + + const result = await payload.find({ + ...findArgs, + page: scanPage, + limit: Math.min(batchSize, remaining), + }) result.docs.forEach((doc) => { const flat = filterDisabledCSV(flattenObject({ doc, fields, toCSVFunctions })) @@ -176,8 +219,9 @@ export const createExport = async (args: CreateExportArgs) => { }) }) - hasMore = result.hasNextPage - scanPage += 1 + fetched += result.docs.length + scanPage += 1 // Increment page for next batch + hasMore = result.hasNextPage && fetched < maxDocs } if (debug) { @@ -187,11 +231,27 @@ export const createExport = async (args: CreateExportArgs) => { const encoder = new TextEncoder() let isFirstBatch = true - let streamPage = 1 + let streamPage = adjustedPage + let fetched = 0 + const maxDocs = typeof hardLimit === 'number' ? hardLimit : Number.POSITIVE_INFINITY const stream = new Readable({ async read() { - const result = await payload.find({ ...findArgs, page: streamPage }) + const remaining = Math.max(0, maxDocs - fetched) + + if (remaining === 0) { + if (!isCSV) { + this.push(encoder.encode(']')) + } + this.push(null) + return + } + + const result = await payload.find({ + ...findArgs, + page: streamPage, + limit: Math.min(batchSize, remaining), + }) if (debug) { req.payload.logger.debug(`Streaming batch ${streamPage} with ${result.docs.length} docs`) @@ -240,10 +300,11 @@ export const createExport = async (args: CreateExportArgs) => { } } + fetched += result.docs.length isFirstBatch = false - streamPage += 1 + streamPage += 1 // Increment stream page for the next batch - if (!result.hasNextPage) { + if (!result.hasNextPage || fetched >= maxDocs) { if (debug) { req.payload.logger.debug('Stream complete - no more pages') } @@ -272,18 +333,29 @@ export const createExport = async (args: CreateExportArgs) => { const rows: Record[] = [] const columnsSet = new Set() const columns: string[] = [] - let page = 1 + + // Start from the incoming page value, defaulting to 1 if undefined + let currentPage = adjustedPage + let fetched = 0 let hasNextPage = true + const maxDocs = typeof hardLimit === 'number' ? hardLimit : Number.POSITIVE_INFINITY while (hasNextPage) { + const remaining = Math.max(0, maxDocs - fetched) + + if (remaining === 0) { + break + } + const result = await payload.find({ ...findArgs, - page, + page: currentPage, + limit: Math.min(batchSize, remaining), }) if (debug) { req.payload.logger.debug( - `Processing batch ${findArgs.page} with ${result.docs.length} documents`, + `Processing batch ${currentPage} with ${result.docs.length} documents`, ) } @@ -308,10 +380,12 @@ export const createExport = async (args: CreateExportArgs) => { outputData.push(batchRows.map((doc) => JSON.stringify(doc)).join(',\n')) } - hasNextPage = result.hasNextPage - page += 1 + fetched += result.docs.length + hasNextPage = result.hasNextPage && fetched < maxDocs + currentPage += 1 // Increment page for next batch } + // Prepare final output if (isCSV) { const paddedRows = rows.map((row) => { const fullRow: Record = {} diff --git a/packages/plugin-import-export/src/export/download.ts b/packages/plugin-import-export/src/export/download.ts index bebf8bc3628..31033799d7c 100644 --- a/packages/plugin-import-export/src/export/download.ts +++ b/packages/plugin-import-export/src/export/download.ts @@ -5,22 +5,33 @@ import { APIError } from 'payload' import { createExport } from './createExport.js' export const download = async (req: PayloadRequest, debug = false) => { - let body - if (typeof req?.json === 'function') { - body = await req.json() - } + try { + let body + if (typeof req?.json === 'function') { + body = await req.json() + } - if (!body || !body.data) { - throw new APIError('Request data is required.') - } + if (!body || !body.data) { + throw new APIError('Request data is required.') + } - req.payload.logger.info(`Download request received ${body.data.collectionSlug}`) + const { collectionSlug } = body.data || {} - body.data.user = req.user + req.payload.logger.info(`Download request received ${collectionSlug}`) + body.data.user = req.user - return createExport({ - download: true, - input: { ...body.data, debug }, - req, - }) as Promise + const res = await createExport({ + download: true, + input: { ...body.data, debug }, + req, + }) + + return res as Response + } catch (err) { + // Return JSON for front-end toast + return new Response( + JSON.stringify({ errors: [{ message: (err as Error).message || 'Something went wrong' }] }), + { headers: { 'Content-Type': 'application/json' }, status: 400 }, + ) + } } diff --git a/packages/plugin-import-export/src/export/getFields.ts b/packages/plugin-import-export/src/export/getFields.ts index f095c5b7982..9b744e88a7a 100644 --- a/packages/plugin-import-export/src/export/getFields.ts +++ b/packages/plugin-import-export/src/export/getFields.ts @@ -1,7 +1,9 @@ +import type { TFunction } from '@payloadcms/translations' import type { Config, Field, SelectField } from 'payload' import type { ImportExportPluginConfig } from '../types.js' +import { validateLimitValue } from '../utilities/validateLimitValue.js' import { getFilename } from './getFilename.js' export const getFields = (config: Config, pluginConfig?: ImportExportPluginConfig): Field[] => { @@ -11,7 +13,7 @@ export const getFields = (config: Config, pluginConfig?: ImportExportPluginConfi name: 'locale', type: 'select', admin: { - width: '33%', + width: '25%', }, defaultValue: 'all', // @ts-expect-error - this is not correctly typed in plugins right now @@ -49,7 +51,7 @@ export const getFields = (config: Config, pluginConfig?: ImportExportPluginConfi admin: { // Hide if a forced format is set via plugin config condition: () => !pluginConfig?.format, - width: '33%', + width: '33.3333%', }, defaultValue: (() => { // Default to plugin-defined format, otherwise 'csv' @@ -74,27 +76,48 @@ export const getFields = (config: Config, pluginConfig?: ImportExportPluginConfi type: 'number', admin: { placeholder: 'No limit', - width: '33%', + step: 100, + width: '33.3333%', + }, + validate: (value: null | number | undefined, { req }: { req: { t: TFunction } }) => { + return validateLimitValue(value, req.t) ?? true }, // @ts-expect-error - this is not correctly typed in plugins right now label: ({ t }) => t('plugin-import-export:field-limit-label'), }, { - name: 'sort', - type: 'text', + name: 'page', + type: 'number', admin: { components: { - Field: '@payloadcms/plugin-import-export/rsc#SortBy', + Field: '@payloadcms/plugin-import-export/rsc#Page', }, + condition: ({ limit }) => { + // Show the page field only if limit is set + return typeof limit === 'number' && limit !== 0 + }, + width: '33.3333%', }, + defaultValue: 1, // @ts-expect-error - this is not correctly typed in plugins right now - label: ({ t }) => t('plugin-import-export:field-sort-label'), + label: ({ t }) => t('plugin-import-export:field-page-label'), }, ], }, { type: 'row', fields: [ + { + name: 'sort', + type: 'text', + admin: { + components: { + Field: '@payloadcms/plugin-import-export/rsc#SortBy', + }, + }, + // @ts-expect-error - this is not correctly typed in plugins right now + label: ({ t }) => t('plugin-import-export:field-sort-label'), + }, ...(localeField ? [localeField] : []), { name: 'drafts', @@ -109,7 +132,7 @@ export const getFields = (config: Config, pluginConfig?: ImportExportPluginConfi collectionConfig?.versions?.drafts, ) }, - width: '33%', + width: '25%', }, defaultValue: 'yes', // @ts-expect-error - this is not correctly typed in plugins right now @@ -163,6 +186,7 @@ export const getFields = (config: Config, pluginConfig?: ImportExportPluginConfi value: 'all', }, ], + virtual: true, }, { name: 'fields', diff --git a/packages/plugin-import-export/src/exports/rsc.ts b/packages/plugin-import-export/src/exports/rsc.ts index 9f2339b7bf6..51a2d88027d 100644 --- a/packages/plugin-import-export/src/exports/rsc.ts +++ b/packages/plugin-import-export/src/exports/rsc.ts @@ -3,6 +3,7 @@ export { ExportListMenuItem } from '../components/ExportListMenuItem/index.js' export { ExportSaveButton } from '../components/ExportSaveButton/index.js' export { FieldsToExport } from '../components/FieldsToExport/index.js' export { ImportExportProvider } from '../components/ImportExportProvider/index.js' +export { Page } from '../components/Page/index.js' export { Preview } from '../components/Preview/index.js' export { SelectionToUseField } from '../components/SelectionToUseField/index.js' export { SortBy } from '../components/SortBy/index.js' diff --git a/packages/plugin-import-export/src/index.ts b/packages/plugin-import-export/src/index.ts index e3b4f99f96d..939e4810970 100644 --- a/packages/plugin-import-export/src/index.ts +++ b/packages/plugin-import-export/src/index.ts @@ -63,7 +63,7 @@ export const importExportPlugin = path: '@payloadcms/plugin-import-export/rsc#ExportListMenuItem', }) - // // Find fields explicitly marked as disabled for import/export + // Find fields explicitly marked as disabled for import/export const disabledFieldAccessors = collectDisabledFieldPaths(collection.fields) // Store disabled field accessors in the admin config for use in the UI @@ -90,13 +90,14 @@ export const importExportPlugin = handler: async (req) => { await addDataAndFileToRequest(req) - const { collectionSlug, draft, fields, limit, locale, sort, where } = req.data as { + const { collectionSlug, draft, fields, limit, locale, page, sort, where } = req.data as { collectionSlug: string draft?: 'no' | 'yes' fields?: string[] format?: 'csv' | 'json' limit?: number locale?: string + page?: number sort?: any where?: any } @@ -118,6 +119,7 @@ export const importExportPlugin = limit: limit && limit > 10 ? 10 : limit, locale, overrideAccess: false, + page, req, select, sort, diff --git a/packages/plugin-import-export/src/translations/languages/ar.ts b/packages/plugin-import-export/src/translations/languages/ar.ts index 463e02dbbf9..7a06c9d4748 100644 --- a/packages/plugin-import-export/src/translations/languages/ar.ts +++ b/packages/plugin-import-export/src/translations/languages/ar.ts @@ -12,6 +12,7 @@ export const arTranslations: PluginDefaultTranslationsObject = { 'field-limit-label': 'حد', 'field-locale-label': 'موقع', 'field-name-label': 'اسم الملف', + 'field-page-label': 'صفحة', 'field-selectionToUse-label': 'اختيار للاستخدام', 'field-sort-label': 'ترتيب حسب', 'selectionToUse-allDocuments': 'استخدم جميع الوثائق', diff --git a/packages/plugin-import-export/src/translations/languages/az.ts b/packages/plugin-import-export/src/translations/languages/az.ts index c5fd9a24dd6..7fb36d71bd7 100644 --- a/packages/plugin-import-export/src/translations/languages/az.ts +++ b/packages/plugin-import-export/src/translations/languages/az.ts @@ -12,6 +12,7 @@ export const azTranslations: PluginDefaultTranslationsObject = { 'field-limit-label': 'Hədd', 'field-locale-label': 'Yerli', 'field-name-label': 'Fayl adı', + 'field-page-label': 'Səhifə', 'field-selectionToUse-label': 'İstifadə etmək üçün seçim', 'field-sort-label': 'Sırala', 'selectionToUse-allDocuments': 'Bütün sənədlərdən istifadə edin', diff --git a/packages/plugin-import-export/src/translations/languages/bg.ts b/packages/plugin-import-export/src/translations/languages/bg.ts index a7b806c8ae9..91a636f09c6 100644 --- a/packages/plugin-import-export/src/translations/languages/bg.ts +++ b/packages/plugin-import-export/src/translations/languages/bg.ts @@ -12,6 +12,7 @@ export const bgTranslations: PluginDefaultTranslationsObject = { 'field-limit-label': 'Лимит', 'field-locale-label': 'Регион', 'field-name-label': 'Име на файла', + 'field-page-label': 'Страница', 'field-selectionToUse-label': 'Избор за използване', 'field-sort-label': 'Сортирай по', 'selectionToUse-allDocuments': 'Използвайте всички документи', diff --git a/packages/plugin-import-export/src/translations/languages/ca.ts b/packages/plugin-import-export/src/translations/languages/ca.ts index c53eac228bd..63eed248197 100644 --- a/packages/plugin-import-export/src/translations/languages/ca.ts +++ b/packages/plugin-import-export/src/translations/languages/ca.ts @@ -12,6 +12,7 @@ export const caTranslations: PluginDefaultTranslationsObject = { 'field-limit-label': 'Límit', 'field-locale-label': 'Local', 'field-name-label': 'Nom del fitxer', + 'field-page-label': 'Pàgina', 'field-selectionToUse-label': 'Selecció per utilitzar', 'field-sort-label': 'Ordena per', 'selectionToUse-allDocuments': 'Utilitzeu tots els documents', diff --git a/packages/plugin-import-export/src/translations/languages/cs.ts b/packages/plugin-import-export/src/translations/languages/cs.ts index 7e89a521013..9a2ea349a58 100644 --- a/packages/plugin-import-export/src/translations/languages/cs.ts +++ b/packages/plugin-import-export/src/translations/languages/cs.ts @@ -12,6 +12,7 @@ export const csTranslations: PluginDefaultTranslationsObject = { 'field-limit-label': 'Limita', 'field-locale-label': 'Místní', 'field-name-label': 'Název souboru', + 'field-page-label': 'Stránka', 'field-selectionToUse-label': 'Výběr k použití', 'field-sort-label': 'Seřadit podle', 'selectionToUse-allDocuments': 'Použijte všechny dokumenty', diff --git a/packages/plugin-import-export/src/translations/languages/da.ts b/packages/plugin-import-export/src/translations/languages/da.ts index 94f8d374ba7..33f4b3a56df 100644 --- a/packages/plugin-import-export/src/translations/languages/da.ts +++ b/packages/plugin-import-export/src/translations/languages/da.ts @@ -12,6 +12,7 @@ export const daTranslations: PluginDefaultTranslationsObject = { 'field-limit-label': 'Begrænsning', 'field-locale-label': 'Lokale', 'field-name-label': 'Filnavn', + 'field-page-label': 'Side', 'field-selectionToUse-label': 'Valg til brug', 'field-sort-label': 'Sorter efter', 'selectionToUse-allDocuments': 'Brug alle dokumenter', diff --git a/packages/plugin-import-export/src/translations/languages/de.ts b/packages/plugin-import-export/src/translations/languages/de.ts index f416cd800d0..5c844cb1eca 100644 --- a/packages/plugin-import-export/src/translations/languages/de.ts +++ b/packages/plugin-import-export/src/translations/languages/de.ts @@ -12,6 +12,7 @@ export const deTranslations: PluginDefaultTranslationsObject = { 'field-limit-label': 'Grenze', 'field-locale-label': 'Ort', 'field-name-label': 'Dateiname', + 'field-page-label': 'Seite', 'field-selectionToUse-label': 'Auswahl zur Verwendung', 'field-sort-label': 'Sortieren nach', 'selectionToUse-allDocuments': 'Verwenden Sie alle Dokumente.', diff --git a/packages/plugin-import-export/src/translations/languages/en.ts b/packages/plugin-import-export/src/translations/languages/en.ts index d8dcec9e8b2..e32d5c48790 100644 --- a/packages/plugin-import-export/src/translations/languages/en.ts +++ b/packages/plugin-import-export/src/translations/languages/en.ts @@ -11,6 +11,7 @@ export const enTranslations = { 'field-limit-label': 'Limit', 'field-locale-label': 'Locale', 'field-name-label': 'File name', + 'field-page-label': 'Page', 'field-selectionToUse-label': 'Selection to use', 'field-sort-label': 'Sort by', 'selectionToUse-allDocuments': 'Use all documents', diff --git a/packages/plugin-import-export/src/translations/languages/es.ts b/packages/plugin-import-export/src/translations/languages/es.ts index 82301564ffe..6a2ab7af979 100644 --- a/packages/plugin-import-export/src/translations/languages/es.ts +++ b/packages/plugin-import-export/src/translations/languages/es.ts @@ -12,6 +12,7 @@ export const esTranslations: PluginDefaultTranslationsObject = { 'field-limit-label': 'Límite', 'field-locale-label': 'Localidad', 'field-name-label': 'Nombre del archivo', + 'field-page-label': 'Página', 'field-selectionToUse-label': 'Selección para usar', 'field-sort-label': 'Ordenar por', 'selectionToUse-allDocuments': 'Utilice todos los documentos', diff --git a/packages/plugin-import-export/src/translations/languages/et.ts b/packages/plugin-import-export/src/translations/languages/et.ts index f816eca979f..b69573bac30 100644 --- a/packages/plugin-import-export/src/translations/languages/et.ts +++ b/packages/plugin-import-export/src/translations/languages/et.ts @@ -12,6 +12,7 @@ export const etTranslations: PluginDefaultTranslationsObject = { 'field-limit-label': 'Piirang', 'field-locale-label': 'Lokaal', 'field-name-label': 'Faili nimi', + 'field-page-label': 'Leht', 'field-selectionToUse-label': 'Valiku kasutamine', 'field-sort-label': 'Sorteeri järgi', 'selectionToUse-allDocuments': 'Kasutage kõiki dokumente', diff --git a/packages/plugin-import-export/src/translations/languages/fa.ts b/packages/plugin-import-export/src/translations/languages/fa.ts index 0eb0969fd4e..29c8867483b 100644 --- a/packages/plugin-import-export/src/translations/languages/fa.ts +++ b/packages/plugin-import-export/src/translations/languages/fa.ts @@ -12,6 +12,7 @@ export const faTranslations: PluginDefaultTranslationsObject = { 'field-limit-label': 'محدودیت', 'field-locale-label': 'محلی', 'field-name-label': 'نام فایل', + 'field-page-label': 'صفحه', 'field-selectionToUse-label': 'انتخاب برای استفاده', 'field-sort-label': 'مرتب سازی بر اساس', 'selectionToUse-allDocuments': 'از تمام مستندات استفاده کنید', diff --git a/packages/plugin-import-export/src/translations/languages/fr.ts b/packages/plugin-import-export/src/translations/languages/fr.ts index c1520df40dd..2e5f1195077 100644 --- a/packages/plugin-import-export/src/translations/languages/fr.ts +++ b/packages/plugin-import-export/src/translations/languages/fr.ts @@ -12,6 +12,7 @@ export const frTranslations: PluginDefaultTranslationsObject = { 'field-limit-label': 'Limite', 'field-locale-label': 'Localisation', 'field-name-label': 'Nom de fichier', + 'field-page-label': 'Page', 'field-selectionToUse-label': 'Sélection à utiliser', 'field-sort-label': 'Trier par', 'selectionToUse-allDocuments': 'Utilisez tous les documents', diff --git a/packages/plugin-import-export/src/translations/languages/he.ts b/packages/plugin-import-export/src/translations/languages/he.ts index edced9c7319..fca29ad1ddc 100644 --- a/packages/plugin-import-export/src/translations/languages/he.ts +++ b/packages/plugin-import-export/src/translations/languages/he.ts @@ -12,6 +12,7 @@ export const heTranslations: PluginDefaultTranslationsObject = { 'field-limit-label': 'הגבלה', 'field-locale-label': 'מקום', 'field-name-label': 'שם הקובץ', + 'field-page-label': 'עמוד', 'field-selectionToUse-label': 'בחירה לשימוש', 'field-sort-label': 'מיין לפי', 'selectionToUse-allDocuments': 'השתמש בכל המסמכים', diff --git a/packages/plugin-import-export/src/translations/languages/hr.ts b/packages/plugin-import-export/src/translations/languages/hr.ts index 68bf077caba..32e67b7e009 100644 --- a/packages/plugin-import-export/src/translations/languages/hr.ts +++ b/packages/plugin-import-export/src/translations/languages/hr.ts @@ -12,6 +12,7 @@ export const hrTranslations: PluginDefaultTranslationsObject = { 'field-limit-label': 'Ograničenje', 'field-locale-label': 'Lokalitet', 'field-name-label': 'Naziv datoteke', + 'field-page-label': 'Stranica', 'field-selectionToUse-label': 'Odabir za upotrebu', 'field-sort-label': 'Sortiraj po', 'selectionToUse-allDocuments': 'Koristite sve dokumente', diff --git a/packages/plugin-import-export/src/translations/languages/hu.ts b/packages/plugin-import-export/src/translations/languages/hu.ts index 6ef2a2a6874..4749fe5e0f8 100644 --- a/packages/plugin-import-export/src/translations/languages/hu.ts +++ b/packages/plugin-import-export/src/translations/languages/hu.ts @@ -12,6 +12,7 @@ export const huTranslations: PluginDefaultTranslationsObject = { 'field-limit-label': 'Korlát', 'field-locale-label': 'Helyszín', 'field-name-label': 'Fájlnév', + 'field-page-label': 'Oldal', 'field-selectionToUse-label': 'Használatra kiválasztva', 'field-sort-label': 'Rendezés szerint', 'selectionToUse-allDocuments': 'Használjon minden dokumentumot', diff --git a/packages/plugin-import-export/src/translations/languages/hy.ts b/packages/plugin-import-export/src/translations/languages/hy.ts index 84a379d0f5c..052fcee1a09 100644 --- a/packages/plugin-import-export/src/translations/languages/hy.ts +++ b/packages/plugin-import-export/src/translations/languages/hy.ts @@ -12,6 +12,7 @@ export const hyTranslations: PluginDefaultTranslationsObject = { 'field-limit-label': 'Սահմանափակում', 'field-locale-label': 'Լոկալ', 'field-name-label': 'Ֆայլի անվանումը', + 'field-page-label': 'Էջ', 'field-selectionToUse-label': 'Օգտագործման ընտրություն', 'field-sort-label': 'Դասավորել ըստ', 'selectionToUse-allDocuments': 'Օգտագործեք բոլոր փաստաթղթերը', diff --git a/packages/plugin-import-export/src/translations/languages/it.ts b/packages/plugin-import-export/src/translations/languages/it.ts index fcd56f25f86..4f53b901ec4 100644 --- a/packages/plugin-import-export/src/translations/languages/it.ts +++ b/packages/plugin-import-export/src/translations/languages/it.ts @@ -12,6 +12,7 @@ export const itTranslations: PluginDefaultTranslationsObject = { 'field-limit-label': 'Limite', 'field-locale-label': 'Locale', 'field-name-label': 'Nome del file', + 'field-page-label': 'Pagina', 'field-selectionToUse-label': 'Selezione da utilizzare', 'field-sort-label': 'Ordina per', 'selectionToUse-allDocuments': 'Utilizza tutti i documenti', diff --git a/packages/plugin-import-export/src/translations/languages/ja.ts b/packages/plugin-import-export/src/translations/languages/ja.ts index 6cac8931a6a..8c5bf2630eb 100644 --- a/packages/plugin-import-export/src/translations/languages/ja.ts +++ b/packages/plugin-import-export/src/translations/languages/ja.ts @@ -12,6 +12,7 @@ export const jaTranslations: PluginDefaultTranslationsObject = { 'field-limit-label': '制限', 'field-locale-label': 'ロケール', 'field-name-label': 'ファイル名', + 'field-page-label': 'ページ', 'field-selectionToUse-label': '使用する選択', 'field-sort-label': '並び替える', 'selectionToUse-allDocuments': 'すべての文書を使用してください。', diff --git a/packages/plugin-import-export/src/translations/languages/ko.ts b/packages/plugin-import-export/src/translations/languages/ko.ts index cf90f5b3ff4..b6dd57c7e60 100644 --- a/packages/plugin-import-export/src/translations/languages/ko.ts +++ b/packages/plugin-import-export/src/translations/languages/ko.ts @@ -12,6 +12,7 @@ export const koTranslations: PluginDefaultTranslationsObject = { 'field-limit-label': '한계', 'field-locale-label': '지역', 'field-name-label': '파일 이름', + 'field-page-label': '페이지', 'field-selectionToUse-label': '사용할 선택', 'field-sort-label': '정렬 방식', 'selectionToUse-allDocuments': '모든 문서를 사용하십시오.', diff --git a/packages/plugin-import-export/src/translations/languages/lt.ts b/packages/plugin-import-export/src/translations/languages/lt.ts index f9133a52345..e6d872f6826 100644 --- a/packages/plugin-import-export/src/translations/languages/lt.ts +++ b/packages/plugin-import-export/src/translations/languages/lt.ts @@ -12,6 +12,7 @@ export const ltTranslations: PluginDefaultTranslationsObject = { 'field-limit-label': 'Ribos', 'field-locale-label': 'Lokalė', 'field-name-label': 'Failo pavadinimas', + 'field-page-label': 'Puslapis', 'field-selectionToUse-label': 'Naudojimo pasirinkimas', 'field-sort-label': 'Rūšiuoti pagal', 'selectionToUse-allDocuments': 'Naudokite visus dokumentus.', diff --git a/packages/plugin-import-export/src/translations/languages/lv.ts b/packages/plugin-import-export/src/translations/languages/lv.ts index ca1a4862d92..1ff5263c831 100644 --- a/packages/plugin-import-export/src/translations/languages/lv.ts +++ b/packages/plugin-import-export/src/translations/languages/lv.ts @@ -12,6 +12,7 @@ export const lvTranslations: PluginDefaultTranslationsObject = { 'field-limit-label': 'Limits', 'field-locale-label': 'Lokalizācija', 'field-name-label': 'Faila nosaukums', + 'field-page-label': 'Lapa', 'field-selectionToUse-label': 'Izvēles lietošana', 'field-sort-label': 'Kārtot pēc', 'selectionToUse-allDocuments': 'Izmantojiet visus dokumentus', diff --git a/packages/plugin-import-export/src/translations/languages/my.ts b/packages/plugin-import-export/src/translations/languages/my.ts index 16154d46e1a..b8a60878e8f 100644 --- a/packages/plugin-import-export/src/translations/languages/my.ts +++ b/packages/plugin-import-export/src/translations/languages/my.ts @@ -12,6 +12,7 @@ export const myTranslations: PluginDefaultTranslationsObject = { 'field-limit-label': 'ကန့်သတ်ချက်', 'field-locale-label': 'Tempatan', 'field-name-label': 'ဖိုင်နာမည်', + 'field-page-label': 'စာမျက်နှာ', 'field-selectionToUse-label': 'Pilihan untuk digunakan', 'field-sort-label': 'စီမံအလိုက်', 'selectionToUse-allDocuments': 'Gunakan semua dokumen', diff --git a/packages/plugin-import-export/src/translations/languages/nb.ts b/packages/plugin-import-export/src/translations/languages/nb.ts index f42611fe902..512e561eeb3 100644 --- a/packages/plugin-import-export/src/translations/languages/nb.ts +++ b/packages/plugin-import-export/src/translations/languages/nb.ts @@ -12,6 +12,7 @@ export const nbTranslations: PluginDefaultTranslationsObject = { 'field-limit-label': 'Begrensning', 'field-locale-label': 'Lokal', 'field-name-label': 'Filnavn', + 'field-page-label': 'Side', 'field-selectionToUse-label': 'Valg til bruk', 'field-sort-label': 'Sorter etter', 'selectionToUse-allDocuments': 'Bruk alle dokumentene', diff --git a/packages/plugin-import-export/src/translations/languages/nl.ts b/packages/plugin-import-export/src/translations/languages/nl.ts index 48067e048a4..b555e2bee43 100644 --- a/packages/plugin-import-export/src/translations/languages/nl.ts +++ b/packages/plugin-import-export/src/translations/languages/nl.ts @@ -12,6 +12,7 @@ export const nlTranslations: PluginDefaultTranslationsObject = { 'field-limit-label': 'Limiet', 'field-locale-label': 'Lokale', 'field-name-label': 'Bestandsnaam', + 'field-page-label': 'Pagina', 'field-selectionToUse-label': 'Selectie om te gebruiken', 'field-sort-label': 'Sorteer op', 'selectionToUse-allDocuments': 'Gebruik alle documenten', diff --git a/packages/plugin-import-export/src/translations/languages/pl.ts b/packages/plugin-import-export/src/translations/languages/pl.ts index 0c3708b6de5..8d2ef5c55b7 100644 --- a/packages/plugin-import-export/src/translations/languages/pl.ts +++ b/packages/plugin-import-export/src/translations/languages/pl.ts @@ -12,6 +12,7 @@ export const plTranslations: PluginDefaultTranslationsObject = { 'field-limit-label': 'Limit', 'field-locale-label': 'Lokalizacja', 'field-name-label': 'Nazwa pliku', + 'field-page-label': 'Strona', 'field-selectionToUse-label': 'Wybór do użycia', 'field-sort-label': 'Sortuj według', 'selectionToUse-allDocuments': 'Użyj wszystkich dokumentów.', diff --git a/packages/plugin-import-export/src/translations/languages/pt.ts b/packages/plugin-import-export/src/translations/languages/pt.ts index c3cc423805b..efdb8046b4a 100644 --- a/packages/plugin-import-export/src/translations/languages/pt.ts +++ b/packages/plugin-import-export/src/translations/languages/pt.ts @@ -12,6 +12,7 @@ export const ptTranslations: PluginDefaultTranslationsObject = { 'field-limit-label': 'Limite', 'field-locale-label': 'Localização', 'field-name-label': 'Nome do arquivo', + 'field-page-label': 'Página', 'field-selectionToUse-label': 'Seleção para usar', 'field-sort-label': 'Ordenar por', 'selectionToUse-allDocuments': 'Use todos os documentos', diff --git a/packages/plugin-import-export/src/translations/languages/ro.ts b/packages/plugin-import-export/src/translations/languages/ro.ts index 02ba449473c..1a0f34ac20e 100644 --- a/packages/plugin-import-export/src/translations/languages/ro.ts +++ b/packages/plugin-import-export/src/translations/languages/ro.ts @@ -12,6 +12,7 @@ export const roTranslations: PluginDefaultTranslationsObject = { 'field-limit-label': 'Limită', 'field-locale-label': 'Localizare', 'field-name-label': 'Numele fișierului', + 'field-page-label': 'Pagina', 'field-selectionToUse-label': 'Selectarea pentru utilizare', 'field-sort-label': 'Sortează după', 'selectionToUse-allDocuments': 'Utilizați toate documentele.', diff --git a/packages/plugin-import-export/src/translations/languages/rs.ts b/packages/plugin-import-export/src/translations/languages/rs.ts index 7cd8f7499ac..fba6205ba71 100644 --- a/packages/plugin-import-export/src/translations/languages/rs.ts +++ b/packages/plugin-import-export/src/translations/languages/rs.ts @@ -12,6 +12,7 @@ export const rsTranslations: PluginDefaultTranslationsObject = { 'field-limit-label': 'Ograničenje', 'field-locale-label': 'Локалитет', 'field-name-label': 'Ime datoteke', + 'field-page-label': 'Strana', 'field-selectionToUse-label': 'Izbor za upotrebu', 'field-sort-label': 'Sortiraj po', 'selectionToUse-allDocuments': 'Koristite sve dokumente', diff --git a/packages/plugin-import-export/src/translations/languages/rsLatin.ts b/packages/plugin-import-export/src/translations/languages/rsLatin.ts index 1e61b020363..a1dff02b90c 100644 --- a/packages/plugin-import-export/src/translations/languages/rsLatin.ts +++ b/packages/plugin-import-export/src/translations/languages/rsLatin.ts @@ -12,6 +12,7 @@ export const rsLatinTranslations: PluginDefaultTranslationsObject = { 'field-limit-label': 'Ograničenje', 'field-locale-label': 'Lokalitet', 'field-name-label': 'Ime datoteke', + 'field-page-label': 'Strana', 'field-selectionToUse-label': 'Izbor za upotrebu', 'field-sort-label': 'Sortiraj po', 'selectionToUse-allDocuments': 'Koristite sve dokumente', diff --git a/packages/plugin-import-export/src/translations/languages/ru.ts b/packages/plugin-import-export/src/translations/languages/ru.ts index 7dc8f5bcd55..82ea8091579 100644 --- a/packages/plugin-import-export/src/translations/languages/ru.ts +++ b/packages/plugin-import-export/src/translations/languages/ru.ts @@ -12,6 +12,7 @@ export const ruTranslations: PluginDefaultTranslationsObject = { 'field-limit-label': 'Лимит', 'field-locale-label': 'Локаль', 'field-name-label': 'Имя файла', + 'field-page-label': 'Страница', 'field-selectionToUse-label': 'Выбор использования', 'field-sort-label': 'Сортировать по', 'selectionToUse-allDocuments': 'Используйте все документы', diff --git a/packages/plugin-import-export/src/translations/languages/sk.ts b/packages/plugin-import-export/src/translations/languages/sk.ts index 6c0a797837a..837ba8f224e 100644 --- a/packages/plugin-import-export/src/translations/languages/sk.ts +++ b/packages/plugin-import-export/src/translations/languages/sk.ts @@ -12,6 +12,7 @@ export const skTranslations: PluginDefaultTranslationsObject = { 'field-limit-label': 'Limit', 'field-locale-label': 'Lokalita', 'field-name-label': 'Názov súboru', + 'field-page-label': 'Stránka', 'field-selectionToUse-label': 'Výber na použitie', 'field-sort-label': 'Triediť podľa', 'selectionToUse-allDocuments': 'Použite všetky dokumenty', diff --git a/packages/plugin-import-export/src/translations/languages/sl.ts b/packages/plugin-import-export/src/translations/languages/sl.ts index 1569f3709c4..247c77041f8 100644 --- a/packages/plugin-import-export/src/translations/languages/sl.ts +++ b/packages/plugin-import-export/src/translations/languages/sl.ts @@ -12,6 +12,7 @@ export const slTranslations: PluginDefaultTranslationsObject = { 'field-limit-label': 'Omejitev', 'field-locale-label': 'Lokalno', 'field-name-label': 'Ime datoteke', + 'field-page-label': 'Stran', 'field-selectionToUse-label': 'Izbor za uporabo', 'field-sort-label': 'Razvrsti po', 'selectionToUse-allDocuments': 'Uporabite vse dokumente', diff --git a/packages/plugin-import-export/src/translations/languages/sv.ts b/packages/plugin-import-export/src/translations/languages/sv.ts index e62ab5d5c1b..1cd37d1db1d 100644 --- a/packages/plugin-import-export/src/translations/languages/sv.ts +++ b/packages/plugin-import-export/src/translations/languages/sv.ts @@ -12,6 +12,7 @@ export const svTranslations: PluginDefaultTranslationsObject = { 'field-limit-label': 'Begränsning', 'field-locale-label': 'Lokal', 'field-name-label': 'Filnamn', + 'field-page-label': 'Sida', 'field-selectionToUse-label': 'Val att använda', 'field-sort-label': 'Sortera efter', 'selectionToUse-allDocuments': 'Använd alla dokument', diff --git a/packages/plugin-import-export/src/translations/languages/th.ts b/packages/plugin-import-export/src/translations/languages/th.ts index 72785fbb32f..19bb2af5912 100644 --- a/packages/plugin-import-export/src/translations/languages/th.ts +++ b/packages/plugin-import-export/src/translations/languages/th.ts @@ -12,6 +12,7 @@ export const thTranslations: PluginDefaultTranslationsObject = { 'field-limit-label': 'จำกัด', 'field-locale-label': 'ที่ตั้ง', 'field-name-label': 'ชื่อไฟล์', + 'field-page-label': 'หน้า', 'field-selectionToUse-label': 'การเลือกใช้', 'field-sort-label': 'เรียงตาม', 'selectionToUse-allDocuments': 'ใช้เอกสารทั้งหมด', diff --git a/packages/plugin-import-export/src/translations/languages/tr.ts b/packages/plugin-import-export/src/translations/languages/tr.ts index 2518b98a5b1..9b7512e56d0 100644 --- a/packages/plugin-import-export/src/translations/languages/tr.ts +++ b/packages/plugin-import-export/src/translations/languages/tr.ts @@ -12,6 +12,7 @@ export const trTranslations: PluginDefaultTranslationsObject = { 'field-limit-label': 'Sınır', 'field-locale-label': 'Yerel', 'field-name-label': 'Dosya adı', + 'field-page-label': 'Sayfa', 'field-selectionToUse-label': 'Kullanılacak seçim', 'field-sort-label': 'Sırala', 'selectionToUse-allDocuments': 'Tüm belgeleri kullanın', diff --git a/packages/plugin-import-export/src/translations/languages/translation-schema.json b/packages/plugin-import-export/src/translations/languages/translation-schema.json index dd222f4c219..00abea91fc7 100644 --- a/packages/plugin-import-export/src/translations/languages/translation-schema.json +++ b/packages/plugin-import-export/src/translations/languages/translation-schema.json @@ -49,6 +49,9 @@ "field-name-label": { "type": "string" }, + "field-page-label": { + "type": "string" + }, "field-selectionToUse-label": { "type": "string" }, diff --git a/packages/plugin-import-export/src/translations/languages/uk.ts b/packages/plugin-import-export/src/translations/languages/uk.ts index 690f8675c53..3d7ffec5423 100644 --- a/packages/plugin-import-export/src/translations/languages/uk.ts +++ b/packages/plugin-import-export/src/translations/languages/uk.ts @@ -12,6 +12,7 @@ export const ukTranslations: PluginDefaultTranslationsObject = { 'field-limit-label': 'Обмеження', 'field-locale-label': 'Локалізація', 'field-name-label': 'Назва файлу', + 'field-page-label': 'Сторінка', 'field-selectionToUse-label': 'Вибір для використання', 'field-sort-label': 'Сортувати за', 'selectionToUse-allDocuments': 'Використовуйте всі документи', diff --git a/packages/plugin-import-export/src/translations/languages/vi.ts b/packages/plugin-import-export/src/translations/languages/vi.ts index f6a545958f5..0eee6b2cbcd 100644 --- a/packages/plugin-import-export/src/translations/languages/vi.ts +++ b/packages/plugin-import-export/src/translations/languages/vi.ts @@ -12,6 +12,7 @@ export const viTranslations: PluginDefaultTranslationsObject = { 'field-limit-label': 'Giới hạn', 'field-locale-label': 'Địa phương', 'field-name-label': 'Tên tệp', + 'field-page-label': 'Trang', 'field-selectionToUse-label': 'Lựa chọn để sử dụng', 'field-sort-label': 'Sắp xếp theo', 'selectionToUse-allDocuments': 'Sử dụng tất cả các tài liệu', diff --git a/packages/plugin-import-export/src/translations/languages/zh.ts b/packages/plugin-import-export/src/translations/languages/zh.ts index 4ca2d311def..820a694fb0a 100644 --- a/packages/plugin-import-export/src/translations/languages/zh.ts +++ b/packages/plugin-import-export/src/translations/languages/zh.ts @@ -12,6 +12,7 @@ export const zhTranslations: PluginDefaultTranslationsObject = { 'field-limit-label': '限制', 'field-locale-label': '语言环境', 'field-name-label': '文件名', + 'field-page-label': '页面', 'field-selectionToUse-label': '选择范围', 'field-sort-label': '排序方式', 'selectionToUse-allDocuments': '使用所有文档', diff --git a/packages/plugin-import-export/src/translations/languages/zhTw.ts b/packages/plugin-import-export/src/translations/languages/zhTw.ts index fdcefe21ce3..f9b5503f247 100644 --- a/packages/plugin-import-export/src/translations/languages/zhTw.ts +++ b/packages/plugin-import-export/src/translations/languages/zhTw.ts @@ -12,6 +12,7 @@ export const zhTwTranslations: PluginDefaultTranslationsObject = { 'field-limit-label': '筆數上限', 'field-locale-label': '語言地區', 'field-name-label': '檔案名稱', + 'field-page-label': '頁面', 'field-selectionToUse-label': '使用的選取範圍', 'field-sort-label': '排序方式', 'selectionToUse-allDocuments': '使用所有文件', diff --git a/packages/plugin-import-export/src/translations/types.ts b/packages/plugin-import-export/src/translations/types.ts index aa58071cb66..1c3126e993c 100644 --- a/packages/plugin-import-export/src/translations/types.ts +++ b/packages/plugin-import-export/src/translations/types.ts @@ -13,6 +13,7 @@ export type PluginLanguage = Language<{ 'field-limit-label': string 'field-locale-label': string 'field-name-label': string + 'field-page-label': string 'field-selectionToUse-label': string 'field-sort-label': string 'selectionToUse-allDocuments': string diff --git a/packages/plugin-import-export/src/utilities/validateLimitValue.ts b/packages/plugin-import-export/src/utilities/validateLimitValue.ts new file mode 100644 index 00000000000..61d1cdff066 --- /dev/null +++ b/packages/plugin-import-export/src/utilities/validateLimitValue.ts @@ -0,0 +1,17 @@ +import type { TFunction } from '@payloadcms/translations' + +export const validateLimitValue = ( + value: null | number | undefined, + t: TFunction, + step = 100, +): string | undefined => { + if (value && value < 0) { + return t('validation:lessThanMin', { label: t('general:value'), min: 0, value }) + } + + if (value && value % step !== 0) { + return `Limit must be a multiple of ${step}` + } + + return undefined +} diff --git a/test/plugin-import-export/int.spec.ts b/test/plugin-import-export/int.spec.ts index caa57f5d2e7..3277edde3d4 100644 --- a/test/plugin-import-export/int.spec.ts +++ b/test/plugin-import-export/int.spec.ts @@ -87,6 +87,129 @@ describe('@payloadcms/plugin-import-export', () => { expect(data[0].updatedAt).toBeDefined() }) + it('should create a file for collection csv with all documents when limit 0', async () => { + let doc = await payload.create({ + collection: 'exports', + user, + data: { + collectionSlug: 'pages', + format: 'csv', + limit: 0, + }, + }) + + 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).toHaveLength(250) + }) + + it('should create a file for collection csv with all documents when no limit', async () => { + let doc = await payload.create({ + collection: 'exports', + user, + data: { + collectionSlug: 'pages', + 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).toHaveLength(250) + }) + + it('should create a file for collection csv from limit and page 1', async () => { + let doc = await payload.create({ + collection: 'exports', + user, + data: { + collectionSlug: 'pages', + format: 'csv', + limit: 100, + page: 1, + }, + }) + + 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].title).toStrictEqual('Polymorphic 4') + }) + + it('should create a file for collection csv from limit and page 2', async () => { + let doc = await payload.create({ + collection: 'exports', + user, + data: { + collectionSlug: 'pages', + format: 'csv', + limit: 100, + page: 2, + }, + }) + + 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].title).toStrictEqual('Doc 149') + }) + + it('should not create a file for collection csv when limit < 0', async () => { + await expect( + payload.create({ + collection: 'exports', + user, + data: { + collectionSlug: 'pages', + format: 'csv', + limit: -1, + }, + }), + ).rejects.toThrow(/Limit/) + }) + + it('should not create a file for collection csv when limit is not a multiple of 100', async () => { + await expect( + payload.create({ + collection: 'exports', + user, + data: { + collectionSlug: 'pages', + format: 'csv', + limit: 99, + }, + }), + ).rejects.toThrow(/Limit/) + }) + it('should create a file for collection csv with draft data', async () => { const draftPage = await payload.create({ collection: 'pages', diff --git a/test/plugin-import-export/payload-types.ts b/test/plugin-import-export/payload-types.ts index c598e3b25eb..3d74330e49b 100644 --- a/test/plugin-import-export/payload-types.ts +++ b/test/plugin-import-export/payload-types.ts @@ -267,6 +267,7 @@ export interface Export { name?: string | null; format?: ('csv' | 'json') | null; limit?: number | null; + page?: number | null; sort?: string | null; locale?: ('all' | 'en' | 'es' | 'de') | null; drafts?: ('yes' | 'no') | null; @@ -303,6 +304,7 @@ export interface ExportsTask { name?: string | null; format?: ('csv' | 'json') | null; limit?: number | null; + page?: number | null; sort?: string | null; locale?: ('all' | 'en' | 'es' | 'de') | null; drafts?: ('yes' | 'no') | null; @@ -603,6 +605,7 @@ export interface ExportsSelect { name?: T; format?: T; limit?: T; + page?: T; sort?: T; locale?: T; drafts?: T; @@ -630,6 +633,7 @@ export interface ExportsTasksSelect { name?: T; format?: T; limit?: T; + page?: T; sort?: T; locale?: T; drafts?: T; @@ -721,6 +725,7 @@ export interface TaskCreateCollectionExport { name?: string | null; format?: ('csv' | 'json') | null; limit?: number | null; + page?: number | null; sort?: string | null; locale?: ('all' | 'en' | 'es' | 'de') | null; drafts?: ('yes' | 'no') | null; diff --git a/test/plugin-import-export/seed/index.ts b/test/plugin-import-export/seed/index.ts index 4002d6a3374..d04b1b40f39 100644 --- a/test/plugin-import-export/seed/index.ts +++ b/test/plugin-import-export/seed/index.ts @@ -26,6 +26,15 @@ export const seed = async (payload: Payload): Promise => { posts.push(post) } // create pages + for (let i = 0; i < 195; i++) { + await payload.create({ + collection: 'pages', + data: { + title: `Doc ${i}`, + }, + }) + } + for (let i = 0; i < 5; i++) { await payload.create({ collection: 'pages',