From 33c73de0161146bfb01d6bffa282934f5949cabb Mon Sep 17 00:00:00 2001 From: Grisha Ghukasyan Date: Tue, 28 Sep 2021 17:17:53 +0200 Subject: [PATCH] feat: multiple collections --- .../query-collections.component.html | 2 +- .../query-collections.component.spec.ts | 8 ++-- .../query-collections.component.ts | 2 +- .../altair/containers/app/app.component.html | 2 +- .../altair/containers/app/app.component.ts | 4 +- .../altair/effects/query-collection.effect.ts | 48 +++++++++++-------- .../store/collection/collection.action.ts | 8 ++-- .../src/app/modules/altair/utils/index.ts | 28 ++++++++++- 8 files changed, 69 insertions(+), 33 deletions(-) diff --git a/packages/altair-app/src/app/modules/altair/components/query-collections/query-collections.component.html b/packages/altair-app/src/app/modules/altair/components/query-collections/query-collections.component.html index c593cdb992..3dbf5354c5 100644 --- a/packages/altair-app/src/app/modules/altair/components/query-collections/query-collections.component.html +++ b/packages/altair-app/src/app/modules/altair/components/query-collections/query-collections.component.html @@ -8,7 +8,7 @@ data-test-id="import-collection" [popper]="'COLLECTIONS_IMPORT_TEXT' | translate" [popperPlacement]="'bottom'" - (click)="importCollectionChange.next()" + (click)="importCollectionsChange.next()" > diff --git a/packages/altair-app/src/app/modules/altair/components/query-collections/query-collections.component.spec.ts b/packages/altair-app/src/app/modules/altair/components/query-collections/query-collections.component.spec.ts index 05af22eff4..a37b9fb064 100644 --- a/packages/altair-app/src/app/modules/altair/components/query-collections/query-collections.component.spec.ts +++ b/packages/altair-app/src/app/modules/altair/components/query-collections/query-collections.component.spec.ts @@ -189,7 +189,7 @@ describe('QueryCollectionsComponent', () => { expect(wrapper.emitted('exportCollectionChange')).toBeTruthy(); }); - it('should emit "importCollectionChange" when clicking import collection button', async() => { + it('should emit "importCollectionsChange" when clicking import collection button', async() => { wrapper.setProps({ showCollections: true, collections: [ @@ -203,11 +203,11 @@ describe('QueryCollectionsComponent', () => { await wrapper.nextTick(); - const importCollectionButton = wrapper.find('[data-test-id="import-collection"]'); + const importCollectionsButton = wrapper.find('[data-test-id="import-collection"]'); - importCollectionButton.emit('click'); + importCollectionsButton.emit('click'); - expect(wrapper.emitted('importCollectionChange')).toBeTruthy(); + expect(wrapper.emitted('importCollectionsChange')).toBeTruthy(); }); it('should emit "sortCollectionsChange" when clicking one of the sort options', async() => { diff --git a/packages/altair-app/src/app/modules/altair/components/query-collections/query-collections.component.ts b/packages/altair-app/src/app/modules/altair/components/query-collections/query-collections.component.ts index 1a5bd78aaa..819d9734e0 100644 --- a/packages/altair-app/src/app/modules/altair/components/query-collections/query-collections.component.ts +++ b/packages/altair-app/src/app/modules/altair/components/query-collections/query-collections.component.ts @@ -17,7 +17,7 @@ export class QueryCollectionsComponent implements OnInit { @Output() deleteCollectionChange: EventEmitter<{ collectionId: IQueryCollection['id'] }> = new EventEmitter(); @Output() editCollectionChange: EventEmitter<{ collection: IQueryCollection }> = new EventEmitter(); @Output() exportCollectionChange = new EventEmitter(); - @Output() importCollectionChange = new EventEmitter(); + @Output() importCollectionsChange = new EventEmitter(); @Output() sortCollectionsChange = new EventEmitter(); constructor( diff --git a/packages/altair-app/src/app/modules/altair/containers/app/app.component.html b/packages/altair-app/src/app/modules/altair/containers/app/app.component.html index 9cb139ce95..9f028033cd 100644 --- a/packages/altair-app/src/app/modules/altair/containers/app/app.component.html +++ b/packages/altair-app/src/app/modules/altair/containers/app/app.component.html @@ -308,7 +308,7 @@ (deleteCollectionChange)="deleteCollection($event)" (editCollectionChange)="toggleEditCollectionDialog($event)" (exportCollectionChange)="exportCollection($event)" - (importCollectionChange)="importCollection()" + (importCollectionsChange)="importCollections()" (sortCollectionsChange)="sortCollections($event)" > diff --git a/packages/altair-app/src/app/modules/altair/containers/app/app.component.ts b/packages/altair-app/src/app/modules/altair/containers/app/app.component.ts index c1e0befd7b..fd5dba2124 100644 --- a/packages/altair-app/src/app/modules/altair/containers/app/app.component.ts +++ b/packages/altair-app/src/app/modules/altair/containers/app/app.component.ts @@ -482,8 +482,8 @@ export class AppComponent { this.store.dispatch(new collectionActions.ExportCollectionAction({ collectionId })); } - importCollection() { - this.store.dispatch(new collectionActions.ImportCollectionAction()); + importCollections() { + this.store.dispatch(new collectionActions.ImportCollectionsAction()); } toggleEditCollectionDialog({ collection }: { collection: IQueryCollection }) { diff --git a/packages/altair-app/src/app/modules/altair/effects/query-collection.effect.ts b/packages/altair-app/src/app/modules/altair/effects/query-collection.effect.ts index 355f90d8a4..6b871bf6d9 100644 --- a/packages/altair-app/src/app/modules/altair/effects/query-collection.effect.ts +++ b/packages/altair-app/src/app/modules/altair/effects/query-collection.effect.ts @@ -1,7 +1,7 @@ -import { EMPTY, Observable, of, zip, forkJoin, from } from 'rxjs'; +import { EMPTY, Observable, of, zip, forkJoin, from, pipe } from 'rxjs'; -import { map, withLatestFrom, switchMap, tap, catchError } from 'rxjs/operators'; +import { map, withLatestFrom, switchMap, tap, catchError, filter } from 'rxjs/operators'; import { Injectable } from '@angular/core'; import { Store, Action } from '@ngrx/store'; import { createEffect, Actions, ofType } from '@ngrx/effects'; @@ -10,7 +10,7 @@ import * as fromRoot from '../store'; import * as collectionActions from '../store/collection/collection.action'; import { QueryCollectionService, WindowService, NotifyService } from '../services'; -import { downloadJson, openFile } from '../utils'; +import { downloadJson, openFile, openFiles } from '../utils'; import { RootState } from 'altair-graphql-core/build/types/state/state.interfaces'; @@ -155,24 +155,34 @@ export class QueryCollectionEffects { }, { dispatch: false }); - importCollection$: Observable = createEffect(() => { - return this.actions$ - .pipe( - ofType(collectionActions.IMPORT_COLLECTION), - switchMap(() => { - return from(openFile({ accept: '.agc' })); - }), - switchMap((data: string) => this.collectionService.importCollectionDataFromJson(data)), - tap(() => this.notifyService.success('Successfully imported collection.')), - map(() => new collectionActions.LoadCollectionsAction()), - catchError((error) => { - const errorMessage = error.message ? error.message : error.toString(); - this.notifyService.error(`Something went wrong importing collection. Error: ${errorMessage}`); - return EMPTY; - }), - ) + + importCollections$: Observable = createEffect(() => { + return this.actions$.pipe( + ofType(collectionActions.IMPORT_COLLECTIONS), + switchMap(() => { + return from(openFiles({ accept: ".agc" })); + }), + pipe(filter((e) => e !== undefined)), + switchMap((data: string[]) => + data.map((elem) => + this.collectionService.importCollectionDataFromJson(elem) + ) + ), + tap(() => + this.notifyService.success("Successfully imported collection.") + ), + map(() => new collectionActions.LoadCollectionsAction()), + catchError((error) => { + const errorMessage = error.message ? error.message : error.toString(); + this.notifyService.error( + `Something went wrong importing collection. Error: ${errorMessage}` + ); + return EMPTY; + }) + ); }); + constructor( private actions$: Actions, private store: Store, diff --git a/packages/altair-app/src/app/modules/altair/store/collection/collection.action.ts b/packages/altair-app/src/app/modules/altair/store/collection/collection.action.ts index d44b493aec..8a46329721 100644 --- a/packages/altair-app/src/app/modules/altair/store/collection/collection.action.ts +++ b/packages/altair-app/src/app/modules/altair/store/collection/collection.action.ts @@ -12,7 +12,7 @@ export const LOAD_COLLECTIONS = 'LOAD_COLLECTIONS'; export const SET_ACTIVE_COLLECTION = 'SET_ACTIVE_COLLECTION'; export const UPDATE_COLLECTION = 'UPDATE_COLLECTION'; -export const IMPORT_COLLECTION = 'IMPORT_COLLECTION'; +export const IMPORT_COLLECTIONS = 'IMPORT_COLLECTIONS'; export const EXPORT_COLLECTION = 'EXPORT_COLLECTION'; export const SORT_COLLECTIONS = 'SORT_COLLECTIONS'; @@ -75,8 +75,8 @@ export class ExportCollectionAction implements NGRXAction { constructor(public payload: { collectionId: number }) {} } -export class ImportCollectionAction implements NGRXAction { - readonly type = IMPORT_COLLECTION; +export class ImportCollectionsAction implements NGRXAction { + readonly type = IMPORT_COLLECTIONS; } export class SortCollectionsAction implements NGRXAction { @@ -96,6 +96,6 @@ export type Action = | UpdateCollectionAction | LoadCollectionsAction | ExportCollectionAction - | ImportCollectionAction + | ImportCollectionsAction | SortCollectionsAction ; diff --git a/packages/altair-app/src/app/modules/altair/utils/index.ts b/packages/altair-app/src/app/modules/altair/utils/index.ts index 9bb52c5d0a..42998f32c5 100644 --- a/packages/altair-app/src/app/modules/altair/utils/index.ts +++ b/packages/altair-app/src/app/modules/altair/utils/index.ts @@ -64,6 +64,24 @@ export const getFileStr = (files: FileList) => { fileReader.readAsText(files[0]); }); }; + +export const getFilesStr = (files: FileList) => { + return Promise.all( + Array(files.length).map( + (_, index) => + new Promise((resolve, reject) => { + const fileReader = new FileReader(); + fileReader.onload = function (e: any) { + const contents: string = e.target.result; + + // Resolve file content + resolve(contents); + }; + fileReader.readAsText(files[index]); + }) + ) + ); +}; interface FileDialogOptions { readonly multiple?: boolean; readonly accept?: string|ReadonlyArray; @@ -75,7 +93,15 @@ export const openFile = async (opts: FileDialogOptions = {}) => { } catch (err) { debug.log('There was an issue while opening the file: ', err); } -} +}; +export const openFiles = async (opts: FileDialogOptions = {}) => { + try { + const files = await fileDialog({ ...opts, multiple: true }); + return getFilesStr(files); + } catch (err) { + debug.log('There was an issue while opening the files: ', err); + } +}; export const isExtension = !!((window as any).chrome && (window as any).chrome.runtime && (window as any).chrome.runtime.id); export const isFirefoxExtension = !!((window as any).chrome && (window as any).chrome.geckoProfiler);