From b13c1612faf82a0a7a29812c87f9b8182b727a8f Mon Sep 17 00:00:00 2001 From: Samuel Imolorhe Date: Sun, 7 Jul 2024 22:46:37 +0200 Subject: [PATCH] support placeholder in file variable name --- .../altair/services/gql/gql.service.spec.ts | 116 +++++++++++------- .../altair/services/gql/gql.service.ts | 12 +- .../src/request/handlers/http.spec.ts | 1 - .../altair-docs/docs/features/file-upload.md | 27 ++++ 4 files changed, 111 insertions(+), 45 deletions(-) diff --git a/packages/altair-app/src/app/modules/altair/services/gql/gql.service.spec.ts b/packages/altair-app/src/app/modules/altair/services/gql/gql.service.spec.ts index a843e625d1..2b1d96853c 100644 --- a/packages/altair-app/src/app/modules/altair/services/gql/gql.service.spec.ts +++ b/packages/altair-app/src/app/modules/altair/services/gql/gql.service.spec.ts @@ -274,9 +274,13 @@ describe('GqlService', () => { .toPromise(); expect(res?.body).toEqual( - JSON.stringify({ - data: 'introspection data', - }, null, 2) + JSON.stringify( + { + data: 'introspection data', + }, + null, + 2 + ) ); } )); @@ -333,9 +337,13 @@ describe('GqlService', () => { .toPromise(); expect(res?.body).toEqual( - JSON.stringify({ - data: 'second introspection data', - }, null, 2) + JSON.stringify( + { + data: 'second introspection data', + }, + null, + 2 + ) ); } )); @@ -940,47 +948,69 @@ describe('GqlService', () => { name: '', data: new File([''], 'unknown.file'), }, + { + name: 'input.files.$$.file', + isMultiple: true, + data: [ + new File([''], 'file1'), + new File([''], 'file2'), + new File([''], 'file3'), + {} as File, + ], + }, ]; const result = service.normalizeFiles(files); // expect(result).toBe(''); - expect(result.resolvedFiles.length).toBe(4); - expect(result.resolvedFiles).toEqual( - expect.arrayContaining([ - { - name: 'first', - data: expect.any(File), - }, - { - name: 'second.0', - data: expect.any(File), - }, - { - name: 'second.1', - data: expect.any(File), - }, - { - name: 'fourth.0', - data: expect.any(File), - }, - ]) - ); - expect(result.erroneousFiles).toEqual( - expect.arrayContaining([ - { - name: 'second.2', - data: expect.any(Object), - }, - { - name: 'third', - data: expect.any(Object), - }, - { - name: '', - data: expect.any(File), - }, - ]) - ); + expect(result.resolvedFiles.length).toBe(7); + expect(result.resolvedFiles).toEqual([ + { + name: 'first', + data: expect.any(File), + }, + { + name: 'second.0', + data: expect.any(File), + }, + { + name: 'second.1', + data: expect.any(File), + }, + { + name: 'fourth.0', + data: expect.any(File), + }, + { + name: 'input.files.0.file', + data: expect.any(File), + }, + { + name: 'input.files.1.file', + data: expect.any(File), + }, + { + name: 'input.files.2.file', + data: expect.any(File), + }, + ]); + expect(result.erroneousFiles).toEqual([ + { + name: 'second.2', + data: expect.any(Object), + }, + { + name: 'third', + data: expect.any(Object), + }, + { + name: '', + data: expect.any(File), + }, + { + name: 'input.files.3.file', + data: expect.any(Object), + }, + ]); } )); it('should return only the first file data if not multiple and has > 1 data', inject( diff --git a/packages/altair-app/src/app/modules/altair/services/gql/gql.service.ts b/packages/altair-app/src/app/modules/altair/services/gql/gql.service.ts index ee34c03c28..e080ef0ed8 100644 --- a/packages/altair-app/src/app/modules/altair/services/gql/gql.service.ts +++ b/packages/altair-app/src/app/modules/altair/services/gql/gql.service.ts @@ -648,8 +648,18 @@ export class GqlService { if (file.isMultiple) { if (Array.isArray(file.data)) { file.data.forEach((fileData, i) => { + let n = `${file.name}.${i}`; + // check if name contains the $$ placeholder, and replace it with the index + if (file.name.split('.').includes('$$')) { + n = file.name + .split('.') + .map((part) => { + return part === '$$' ? i : part; + }) + .join('.'); + } const newFileVariable = { - name: `${file.name}.${i}`, + name: n, data: fileData, }; diff --git a/packages/altair-core/src/request/handlers/http.spec.ts b/packages/altair-core/src/request/handlers/http.spec.ts index 17eb59762e..53f848e145 100644 --- a/packages/altair-core/src/request/handlers/http.spec.ts +++ b/packages/altair-core/src/request/handlers/http.spec.ts @@ -341,7 +341,6 @@ describe('HTTP handler', () => { ]); }); - it('should properly handle normal unsuccessful HTTP GET requests', async () => { const mockHandler = new MswMockRequestHandler( 'http://localhost:3000/graphql', diff --git a/packages/altair-docs/docs/features/file-upload.md b/packages/altair-docs/docs/features/file-upload.md index b27031d0ce..64f11967da 100644 --- a/packages/altair-docs/docs/features/file-upload.md +++ b/packages/altair-docs/docs/features/file-upload.md @@ -15,3 +15,30 @@ Altair supports uploading both single files and an array of files (by switching ![file variables](https://i.imgur.com/dVqWVoA.png) You add your files in the variables pane, and the files are added to the request as variables when the request is sent to the server. + +### Handling nested multiple file upload + +Consider the following schema: + +```graphql +input FileInput { + file: Upload!! +} + +input MyInput { + images: [FileInput!]! +} +``` + +And the following query: + +```graphql +mutation ($input: MyInput!) { + uploadImages(input: $input) { + success + } +} +``` + +You can upload multiple files with the single file mode by defining each file name as `input.images.0.file`, `input.images.1.file`, `input.images.2.file` and so on. This works but can be a bit daunting when you have a lot of files to upload. +You can switch to multiple file mode to make it easier to upload multiple files. For this case, you would define the file name for the files as `input.images.$$.file` (with `$$` as a placeholder for the index of the file). Altair would automatically replace `$$` with the index of the file when sending the request.