Skip to content

Commit 1ee19d3

Browse files
feat: bulk upload (#7800)
## Description Adds bulk upload functionality to upload enabled configs. You can disable the ability by defining `upload.bulkUpload: false` in your upload enabled config. - [x] I have read and understand the [CONTRIBUTING.md](https://github.com/payloadcms/payload/blob/main/CONTRIBUTING.md) document in this repository. ## Type of change - [x] New feature (non-breaking change which adds functionality) ## Checklist: - [ ] I have added tests that prove my fix is effective or that my feature works - [ ] Existing test suite passes locally with my changes - [ ] I have made corresponding changes to the documentation
1 parent af0105c commit 1ee19d3

File tree

63 files changed

+1936
-5
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+1936
-5
lines changed

docs/upload/overview.mdx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ _An asterisk denotes that an option is required._
9292
| Option | Description |
9393
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
9494
| **`adminThumbnail`** | Set the way that the [Admin Panel](../admin/overview) will display thumbnails for this Collection. [More](#admin-thumbnails) |
95+
| **`bulkUpload`** | Allow users to upload in bulk from the list view, default is true |
9596
| **`crop`** | Set to `false` to disable the cropping tool in the [Admin Panel](../admin/overview). Crop is enabled by default. [More](#crop-and-focal-point-selector) |
9697
| **`disableLocalStorage`** | Completely disable uploading files to disk locally. [More](#disabling-local-upload-storage) |
9798
| **`displayPreview`** | Enable displaying preview of the uploaded file in Upload fields related to this Collection. Can be locally overridden by `displayPreview` option in Upload field. [More](/docs/fields/upload#config-options). |

packages/next/src/views/List/Default/index.tsx

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import type { ClientCollectionConfig } from 'payload'
44

55
import { getTranslation } from '@payloadcms/translations'
66
import {
7+
BulkUploadDrawer,
78
Button,
89
DeleteMany,
910
EditMany,
@@ -13,6 +14,7 @@ import {
1314
ListSelection,
1415
Pagination,
1516
PerPage,
17+
PopupList,
1618
PublishMany,
1719
RelationshipProvider,
1820
RenderComponent,
@@ -22,10 +24,13 @@ import {
2224
Table,
2325
UnpublishMany,
2426
ViewDescription,
27+
bulkUploadDrawerSlug,
2528
useConfig,
2629
useEditDepth,
2730
useListInfo,
2831
useListQuery,
32+
useModal,
33+
useRouteCache,
2934
useSearchParams,
3035
useStepNav,
3136
useTranslation,
@@ -44,6 +49,8 @@ export const DefaultListView: React.FC = () => {
4449
const { Header, collectionSlug, hasCreatePermission, newDocumentURL } = useListInfo()
4550
const { data, defaultLimit, handlePageChange, handlePerPageChange } = useListQuery()
4651
const { searchParams } = useSearchParams()
52+
const { openModal } = useModal()
53+
const { clearRouteCache } = useRouteCache()
4754

4855
const { getEntityConfig } = useConfig()
4956

@@ -67,7 +74,7 @@ export const DefaultListView: React.FC = () => {
6774
labels,
6875
} = collectionConfig
6976

70-
const { i18n } = useTranslation()
77+
const { i18n, t } = useTranslation()
7178

7279
const drawerDepth = useEditDepth()
7380

@@ -79,7 +86,9 @@ export const DefaultListView: React.FC = () => {
7986

8087
let docs = data.docs || []
8188

82-
if (collectionConfig.upload) {
89+
const isUploadCollection = Boolean(collectionConfig.upload)
90+
91+
if (isUploadCollection) {
8392
docs = docs?.map((doc) => {
8493
return {
8594
...doc,
@@ -109,6 +118,15 @@ export const DefaultListView: React.FC = () => {
109118
{hasCreatePermission && (
110119
<Button
111120
Link={Link}
121+
SubMenuPopupContent={
122+
isUploadCollection && collectionConfig.upload.bulkUpload ? (
123+
<PopupList.ButtonGroup>
124+
<PopupList.Button onClick={() => openModal(bulkUploadDrawerSlug)}>
125+
{t('upload:bulkUpload')}
126+
</PopupList.Button>
127+
</PopupList.ButtonGroup>
128+
) : null
129+
}
112130
aria-label={i18n.t('general:createNewLabel', {
113131
label: getTranslation(labels?.singular, i18n),
114132
})}
@@ -128,6 +146,12 @@ export const DefaultListView: React.FC = () => {
128146
<ViewDescription Description={Description} description={description} />
129147
</div>
130148
)}
149+
{isUploadCollection && collectionConfig.upload.bulkUpload ? (
150+
<BulkUploadDrawer
151+
collectionSlug={collectionSlug}
152+
onSuccess={() => clearRouteCache()}
153+
/>
154+
) : null}
131155
</ListHeader>
132156
)}
133157
<ListControls collectionConfig={collectionConfig} fields={fields} />

packages/payload/src/collections/config/sanitize.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ export const sanitizeCollection = async (
120120
// disable duplicate for uploads by default
121121
sanitized.disableDuplicate = sanitized.disableDuplicate || true
122122

123+
sanitized.upload.bulkUpload = sanitized.upload?.bulkUpload ?? true
123124
sanitized.upload.staticDir = sanitized.upload.staticDir || sanitized.slug
124125
sanitized.admin.useAsTitle =
125126
sanitized.admin.useAsTitle && sanitized.admin.useAsTitle !== 'id'

packages/payload/src/uploads/types.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,11 @@ export type UploadConfig = {
9595
* - A function that generates a fully qualified URL for the thumbnail, receives the doc as the only argument.
9696
**/
9797
adminThumbnail?: GetAdminThumbnail | string
98+
/**
99+
* Enables bulk upload of files from the list view.
100+
* @default true
101+
*/
102+
bulkUpload?: boolean
98103
/**
99104
* Enables cropping of images.
100105
* @default true

packages/translations/src/clientKeys.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@ export const clientTranslationKeys = createClientTranslationKeys([
188188
'general:menu',
189189
'general:moveDown',
190190
'general:moveUp',
191+
'general:next',
191192
'general:noFiltersSet',
192193
'general:noLabel',
193194
'general:none',
@@ -204,6 +205,7 @@ export const clientTranslationKeys = createClientTranslationKeys([
204205
'general:password',
205206
'general:payloadSettings',
206207
'general:perPage',
208+
'general:previous',
207209
'general:remove',
208210
'general:reset',
209211
'general:row',
@@ -239,6 +241,7 @@ export const clientTranslationKeys = createClientTranslationKeys([
239241
'general:updatedCountSuccessfully',
240242
'general:updatedSuccessfully',
241243
'general:updating',
244+
'general:uploading',
242245
'general:welcome',
243246

244247
'operators:equals',
@@ -256,11 +259,15 @@ export const clientTranslationKeys = createClientTranslationKeys([
256259
'operators:within',
257260
'operators:intersects',
258261

262+
'upload:addFile',
263+
'upload:addFiles',
264+
'upload:bulkUpload',
259265
'upload:crop',
260266
'upload:cropToolDescription',
261267
'upload:dragAndDrop',
262-
'upload:addFile',
263268
'upload:editImage',
269+
'upload:fileToUpload',
270+
'upload:filesToUpload',
264271
'upload:focalPoint',
265272
'upload:focalPointDescription',
266273
'upload:height',

packages/translations/src/languages/ar.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,7 @@ export const arTranslations: DefaultTranslationsObject = {
244244
moveDown: 'التّحريك إلى الأسفل',
245245
moveUp: 'التّحريك إلى الأعلى',
246246
newPassword: 'كلمة مرور جديدة',
247+
next: 'التالي',
247248
noFiltersSet: 'لم يتم تعيين أي عوامل تصفية',
248249
noLabel: '<لا {{label}}>',
249250
noOptions: 'لا خيارات',
@@ -261,6 +262,7 @@ export const arTranslations: DefaultTranslationsObject = {
261262
password: 'كلمة المرور',
262263
payloadSettings: 'الإعدادات',
263264
perPage: 'لكلّ صفحة: {{limit}}',
265+
previous: 'سابق',
264266
remove: 'إزالة',
265267
reset: 'إعادة تعيين',
266268
row: 'سطر',
@@ -318,13 +320,17 @@ export const arTranslations: DefaultTranslationsObject = {
318320
},
319321
upload: {
320322
addFile: 'إضافة ملف',
323+
addFiles: 'أضف ملفات',
324+
bulkUpload: 'تحميل بالجملة',
321325
crop: 'محصول',
322326
cropToolDescription: 'اسحب الزوايا المحددة للمنطقة، رسم منطقة جديدة أو قم بضبط القيم أدناه.',
323327
dragAndDrop: 'قم بسحب وإسقاط ملفّ',
324328
dragAndDropHere: 'أو اسحب الملفّ وأفلته هنا',
325329
editImage: 'تعديل الصورة',
326330
fileName: 'اسم الملفّ',
327331
fileSize: 'حجم الملفّ',
332+
fileToUpload: 'ملف للتحميل',
333+
filesToUpload: 'ملفات للتحميل',
328334
focalPoint: 'نقطة التركيز',
329335
focalPointDescription: 'اسحب النقطة المركزية مباشرة على المعاينة أو قم بضبط القيم أدناه.',
330336
height: 'الطّول',

packages/translations/src/languages/az.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,7 @@ export const azTranslations: DefaultTranslationsObject = {
246246
moveDown: 'Aşağı hərəkət et',
247247
moveUp: 'Yuxarı hərəkət et',
248248
newPassword: 'Yeni şifrə',
249+
next: 'Növbəti',
249250
noFiltersSet: 'Filter təyin edilməyib',
250251
noLabel: '<Heç bir {{label}}>',
251252
noOptions: 'Heç bir seçim yoxdur',
@@ -263,6 +264,7 @@ export const azTranslations: DefaultTranslationsObject = {
263264
password: 'Şifrə',
264265
payloadSettings: 'Payload Parametrləri',
265266
perPage: 'Hər səhifədə: {{limit}}',
267+
previous: 'Əvvəlki',
266268
remove: 'Sil',
267269
reset: 'Yenidən başlat',
268270
row: 'Sətir',
@@ -321,6 +323,8 @@ export const azTranslations: DefaultTranslationsObject = {
321323
},
322324
upload: {
323325
addFile: 'Fayl əlavə et',
326+
addFiles: 'Faylları Əlavə Edin',
327+
bulkUpload: 'Kütləvi Yükləmə',
324328
crop: 'Məhsul',
325329
cropToolDescription:
326330
'Seçilmiş sahənin köşələrini sürükləyin, yeni bir sahə çəkin və ya aşağıdakı dəyərləri düzəltin.',
@@ -329,6 +333,8 @@ export const azTranslations: DefaultTranslationsObject = {
329333
editImage: 'Şəkili Redaktə Et',
330334
fileName: 'Faylın Adı',
331335
fileSize: 'Faylım Ölçüsü',
336+
fileToUpload: 'Yükləmək üçün Fayl',
337+
filesToUpload: 'Yükləmək üçün fayllar',
332338
focalPoint: 'Mərkəzi Nöqtə',
333339
focalPointDescription:
334340
'Fokus nöqtəsini birbaşa önizləməyə sürükləyin və ya aşağıdakı dəyərləri düzəltin.',

packages/translations/src/languages/bg.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,7 @@ export const bgTranslations: DefaultTranslationsObject = {
245245
moveDown: 'Надолу',
246246
moveUp: 'Нагоре',
247247
newPassword: 'Нова парола',
248+
next: 'Следващ',
248249
noFiltersSet: 'Няма зададени филтри',
249250
noLabel: '<Няма {{label}}>',
250251
noOptions: 'Няма опции',
@@ -262,6 +263,7 @@ export const bgTranslations: DefaultTranslationsObject = {
262263
password: 'Парола',
263264
payloadSettings: 'Настройки на Payload',
264265
perPage: 'На страница: {{limit}}',
266+
previous: 'Предишен',
265267
remove: 'Премахни',
266268
reset: 'Нулиране',
267269
row: 'ред',
@@ -319,6 +321,8 @@ export const bgTranslations: DefaultTranslationsObject = {
319321
},
320322
upload: {
321323
addFile: 'Добавяне на файл',
324+
addFiles: 'Добави файлове',
325+
bulkUpload: 'Масово Качване',
322326
crop: 'Изрязване',
323327
cropToolDescription:
324328
'Плъзни ъглите на избраната област, избери нова област или коригирай стойностите по-долу.',
@@ -327,6 +331,8 @@ export const bgTranslations: DefaultTranslationsObject = {
327331
editImage: 'Редактирай изображение',
328332
fileName: 'Име на файла',
329333
fileSize: 'Големина на файла',
334+
fileToUpload: 'Файл за качване',
335+
filesToUpload: 'Файлове за качване',
330336
focalPoint: 'Фокусна точка',
331337
focalPointDescription:
332338
'Премести фокусната точка директно върху визуализацията или регулирай стойностите по-долу.',

packages/translations/src/languages/cs.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,7 @@ export const csTranslations: DefaultTranslationsObject = {
245245
moveDown: 'Posunout dolů',
246246
moveUp: 'Posunout nahoru',
247247
newPassword: 'Nové heslo',
248+
next: 'Další',
248249
noFiltersSet: 'Nenastaveny žádné filtry',
249250
noLabel: '<Žádný {{label}}>',
250251
noOptions: 'Žádné možnosti',
@@ -262,6 +263,7 @@ export const csTranslations: DefaultTranslationsObject = {
262263
password: 'Heslo',
263264
payloadSettings: 'Payload nastavení',
264265
perPage: 'Na stránku: {{limit}}',
266+
previous: 'Předchozí',
265267
remove: 'Odstranit',
266268
reset: 'Resetovat',
267269
row: 'Řádek',
@@ -319,6 +321,8 @@ export const csTranslations: DefaultTranslationsObject = {
319321
},
320322
upload: {
321323
addFile: 'Přidat soubor',
324+
addFiles: 'Přidat soubory',
325+
bulkUpload: 'Hromadné nahrání',
322326
crop: 'Ořez',
323327
cropToolDescription:
324328
'Přetáhněte rohy vybrané oblasti, nakreslete novou oblast nebo upravte níže uvedené hodnoty.',
@@ -327,6 +331,8 @@ export const csTranslations: DefaultTranslationsObject = {
327331
editImage: 'Upravit obrázek',
328332
fileName: 'Název souboru',
329333
fileSize: 'Velikost souboru',
334+
fileToUpload: 'Soubor k nahrání',
335+
filesToUpload: 'Soubory k nahrání',
330336
focalPoint: 'Středobod',
331337
focalPointDescription:
332338
'Přetáhněte bod zaměření přímo na náhled nebo upravte níže uvedené hodnoty.',

packages/translations/src/languages/de.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,7 @@ export const deTranslations: DefaultTranslationsObject = {
250250
moveDown: 'Nach unten bewegen',
251251
moveUp: 'Nach oben bewegen',
252252
newPassword: 'Neues Passwort',
253+
next: 'Nächste',
253254
noFiltersSet: 'Keine Filter gesetzt',
254255
noLabel: '<Kein {{label}}>',
255256
noOptions: 'Keine Optionen',
@@ -267,6 +268,7 @@ export const deTranslations: DefaultTranslationsObject = {
267268
password: 'Passwort',
268269
payloadSettings: 'Payload Einstellungen',
269270
perPage: 'Pro Seite: {{limit}}',
271+
previous: 'Vorherige',
270272
remove: 'Entfernen',
271273
reset: 'Zurücksetzen',
272274
row: 'Zeile',
@@ -325,6 +327,8 @@ export const deTranslations: DefaultTranslationsObject = {
325327
},
326328
upload: {
327329
addFile: 'Datei hinzufügen',
330+
addFiles: 'Dateien hinzufügen',
331+
bulkUpload: 'Massenupload',
328332
crop: 'Zuschneiden',
329333
cropToolDescription:
330334
'Ziehen Sie die Ecken des ausgewählten Bereichs, zeichnen Sie einen neuen Bereich oder passen Sie die Werte unten an.',
@@ -333,6 +337,8 @@ export const deTranslations: DefaultTranslationsObject = {
333337
editImage: 'Bild bearbeiten',
334338
fileName: 'Dateiname',
335339
fileSize: 'Dateigröße',
340+
fileToUpload: 'Datei zum Hochladen',
341+
filesToUpload: 'Dateien zum Hochladen',
336342
focalPoint: 'Brennpunkt',
337343
focalPointDescription:
338344
'Ziehen Sie den Fokuspunkt direkt auf die Vorschau oder passen Sie die Werte unten an.',

0 commit comments

Comments
 (0)