From 414d297c692f0b0271ba313d393e8c32dfae0e0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Suwi=C5=84ski?= Date: Tue, 27 Sep 2022 18:02:31 +0200 Subject: [PATCH] feat: multiple file upload (#475) --- src/hydra/dataProvider.test.ts | 5 +++++ src/hydra/dataProvider.ts | 28 +++++++++++++++++++--------- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/src/hydra/dataProvider.test.ts b/src/hydra/dataProvider.test.ts index 33ccc639..0eb48c4c 100644 --- a/src/hydra/dataProvider.test.ts +++ b/src/hydra/dataProvider.test.ts @@ -216,11 +216,15 @@ describe('Transform a React Admin request to an Hydra request', () => { await dataProvider.introspect(); const file = new File(['foo'], 'foo.txt'); + const icons = [...Array(3).keys()].map((i) => ({ + rawFile: new File([`icon_${i}`], `icon_${i}.png`), + })); await dataProvider.create('resource', { data: { image: { rawFile: file, }, + icons, bar: 'baz', qux: null, array: ['foo', 'dummy'], @@ -238,6 +242,7 @@ describe('Transform a React Admin request to an Hydra request', () => { expect(options.body).toBeInstanceOf(FormData); expect(Array.from((options.body as FormData).entries())).toEqual([ ['image', file], + ...icons.map((icon) => ['icons[]', icon.rawFile]), ['bar', 'baz'], ['qux', 'null'], ['array', '["foo","dummy"]'], diff --git a/src/hydra/dataProvider.ts b/src/hydra/dataProvider.ts index 31707794..4c2c506c 100644 --- a/src/hydra/dataProvider.ts +++ b/src/hydra/dataProvider.ts @@ -255,11 +255,14 @@ function dataProvider( data as Record, ).then((hydraData) => { const values = Object.values(hydraData); - const containFile = (element: unknown) => - isPlainObject(element) && - Object.values(element as Record).some( - (value) => value instanceof File, - ); + const containFile = (element: unknown): boolean => + Array.isArray(element) + ? element.every((value) => containFile(value)) + : isPlainObject(element) && + Object.values(element as Record).some( + (value) => value instanceof File, + ); + type ToJSONObject = { toJSON(): string }; const hasToJSON = ( element: string | ToJSONObject, @@ -281,10 +284,17 @@ function dataProvider( ).forEach(([key, value]) => { // React-Admin FileInput format is an object containing a file. if (containFile(value)) { - body.append( - key, - Object.values(value).find((val) => val instanceof File), - ); + const findFile = (element: string | ToJSONObject): Blob => + Object.values(element).find((val) => val instanceof File); + // eslint-disable-next-line @typescript-eslint/no-unused-expressions + Array.isArray(value) + ? value + .map((val) => findFile(val)) + .forEach((file) => { + body.append(key.endsWith('[]') ? key : `${key}[]`, file); + }) + : body.append(key, findFile(value)); + return; } if (hasToJSON(value)) {