feat(plugin-import-export): adds limit and page fields to export options (#13380)

### What:
This PR adds `limit` and `page` fields to the export options, allowing
users to control the number of documents exported and the page from
which to start the export. It also enforces that limit must be a
positive multiple of 100.

### Why:
This feature is needed to provide pagination support for large exports,
enabling users to export manageable chunks of data rather than the
entire dataset at once. Enforcing multiples-of-100 for `limit` ensures
consistent chunking behavior and prevents unexpected export issues.

### How:
- The `limit` field determines the maximum number of documents to export
and **must be a positive multiple of 100**.
- The `page` field defines the starting page of the export and is
displayed only when a `limit` is specified.
- If `limit` is cleared, the `page` resets to 1 to maintain consistency.
- Export logic was adjusted to respect the `limit` and `page` values
when fetching documents.

---------

Co-authored-by: Patrik Kozak <35232443+PatrikKozak@users.noreply.github.com>
This commit is contained in:
Dan Ribbens
2025-08-13 17:01:45 -04:00
committed by GitHub
parent 3e65111bc1
commit c1c68fbb55
56 changed files with 415 additions and 50 deletions

View File

@@ -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')
}
}

View File

@@ -0,0 +1,3 @@
.page-field {
--field-width: 33.3333%;
}

View File

@@ -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<number>()
const { value: limitValue } = useField<number>({ path: 'limit' })
// Effect to reset page to 1 if limit is removed
useEffect(() => {
if (!limitValue) {
setValue(1) // Reset page to 1
}
}, [limitValue, setValue])
return (
<div className={baseClass}>
<NumberField
field={{
name: props.field.name,
admin: {
autoComplete: undefined,
placeholder: undefined,
step: 1,
},
label: props.field.label,
min: 1,
}}
onChange={(value) => setValue(value ?? 1)} // Update the page value on change
path={props.path}
/>
</div>
)
}

View File

@@ -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<number>({ path: 'limit' })
const { value: fields } = useField<string[]>({ 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,
])

View File

@@ -1,4 +1,3 @@
.sort-by-fields {
display: block;
width: 33%;
--field-width: 25%;
}

View File

@@ -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 (
<div className={baseClass} style={{ '--field-width': '33%' } as React.CSSProperties}>
<div className={baseClass}>
<FieldLabel label={props.field.label} path={props.path} />
<ReactSelect
className={baseClass}

View File

@@ -6,6 +6,7 @@ import { APIError } from 'payload'
import { Readable } from 'stream'
import { buildDisabledFieldRegex } from '../utilities/buildDisabledFieldRegex.js'
import { validateLimitValue } from '../utilities/validateLimitValue.js'
import { flattenObject } from './flattenObject.js'
import { getCustomFieldFunctions } from './getCustomFieldFunctions.js'
import { getFilename } from './getFilename.js'
@@ -23,8 +24,10 @@ export type Export = {
format: 'csv' | 'json'
globals?: string[]
id: number | string
limit?: number
locale?: string
name: string
page?: number
slug: string
sort: Sort
user: string
@@ -57,6 +60,8 @@ export const createExport = async (args: CreateExportArgs) => {
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<string>()
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<string, unknown>[] = []
const columnsSet = new Set<string>()
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<string, unknown> = {}

View File

@@ -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.')
}
const { collectionSlug } = body.data || {}
req.payload.logger.info(`Download request received ${collectionSlug}`)
body.data.user = req.user
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 },
)
}
if (!body || !body.data) {
throw new APIError('Request data is required.')
}
req.payload.logger.info(`Download request received ${body.data.collectionSlug}`)
body.data.user = req.user
return createExport({
download: true,
input: { ...body.data, debug },
req,
}) as Promise<Response>
}

View File

@@ -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,11 +76,37 @@ 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: 'page',
type: 'number',
admin: {
components: {
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-page-label'),
},
],
},
{
type: 'row',
fields: [
{
name: 'sort',
type: 'text',
@@ -90,11 +118,6 @@ export const getFields = (config: Config, pluginConfig?: ImportExportPluginConfi
// @ts-expect-error - this is not correctly typed in plugins right now
label: ({ t }) => t('plugin-import-export:field-sort-label'),
},
],
},
{
type: 'row',
fields: [
...(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',

View File

@@ -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'

View File

@@ -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,

View File

@@ -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': 'استخدم جميع الوثائق',

View File

@@ -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',

View File

@@ -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': 'Използвайте всички документи',

View File

@@ -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',

View File

@@ -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',

View File

@@ -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',

View File

@@ -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.',

View File

@@ -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',

View File

@@ -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',

View File

@@ -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',

View File

@@ -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': 'از تمام مستندات استفاده کنید',

View File

@@ -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',

View File

@@ -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': 'השתמש בכל המסמכים',

View File

@@ -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',

View File

@@ -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',

View File

@@ -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': 'Օգտագործեք բոլոր փաստաթղթերը',

View File

@@ -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',

View File

@@ -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': 'すべての文書を使用してください。',

View File

@@ -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': '모든 문서를 사용하십시오.',

View File

@@ -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.',

View File

@@ -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',

View File

@@ -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',

View File

@@ -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',

View File

@@ -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',

View File

@@ -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.',

View File

@@ -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',

View File

@@ -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.',

View File

@@ -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',

View File

@@ -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',

View File

@@ -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': 'Используйте все документы',

View File

@@ -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',

View File

@@ -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',

View File

@@ -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',

View File

@@ -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': 'ใช้เอกสารทั้งหมด',

View File

@@ -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',

View File

@@ -49,6 +49,9 @@
"field-name-label": {
"type": "string"
},
"field-page-label": {
"type": "string"
},
"field-selectionToUse-label": {
"type": "string"
},

View File

@@ -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': 'Використовуйте всі документи',

View File

@@ -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',

View File

@@ -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': '使用所有文档',

View File

@@ -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': '使用所有文件',

View File

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

View File

@@ -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
}