From 85856d839021a83a994cc961189522f744a24c24 Mon Sep 17 00:00:00 2001 From: Thomas Rittson <31796059+eliykat@users.noreply.github.com> Date: Wed, 24 Feb 2021 05:48:30 +1000 Subject: [PATCH] Improve import error messages (#841) * Display server import errors in modal * Fix UI text and modal appearance * Fix loading spinner behaviour * Fix linting * Update jslib version --- jslib | 2 +- .../organizations/tools/import.component.ts | 4 +-- src/app/services/services.module.ts | 3 +- src/app/tools/import.component.html | 4 +-- src/app/tools/import.component.ts | 36 +++++++++++++++++-- src/locales/en/messages.json | 6 ++++ 6 files changed, 46 insertions(+), 9 deletions(-) diff --git a/jslib b/jslib index 0951424de7..42348e2fdc 160000 --- a/jslib +++ b/jslib @@ -1 +1 @@ -Subproject commit 0951424de77fbb61a38616d13d6c67f74ee19775 +Subproject commit 42348e2fdc6206157d68d8a9f496eaa70520ab01 diff --git a/src/app/organizations/tools/import.component.ts b/src/app/organizations/tools/import.component.ts index f5f11d5f13..db2021909d 100644 --- a/src/app/organizations/tools/import.component.ts +++ b/src/app/organizations/tools/import.component.ts @@ -24,9 +24,9 @@ export class ImportComponent extends BaseImportComponent { constructor(i18nService: I18nService, analytics: Angulartics2, toasterService: ToasterService, importService: ImportService, router: Router, private route: ActivatedRoute, - private platformUtilsService: PlatformUtilsService, + platformUtilsService: PlatformUtilsService, private userService: UserService) { - super(i18nService, analytics, toasterService, importService, router); + super(i18nService, analytics, toasterService, importService, router, platformUtilsService); } async ngOnInit() { diff --git a/src/app/services/services.module.ts b/src/app/services/services.module.ts index 3b02ccda30..e5c48fe956 100644 --- a/src/app/services/services.module.ts +++ b/src/app/services/services.module.ts @@ -128,7 +128,8 @@ const authService = new AuthService(cryptoService, apiService, userService, tokenService, appIdService, i18nService, platformUtilsService, messagingService, vaultTimeoutService, consoleLogService); const exportService = new ExportService(folderService, cipherService, apiService); -const importService = new ImportService(cipherService, folderService, apiService, i18nService, collectionService); +const importService = new ImportService(cipherService, folderService, apiService, i18nService, collectionService, + platformUtilsService); const notificationsService = new NotificationsService(userService, syncService, appIdService, apiService, vaultTimeoutService, async () => messagingService.send('logout', { expired: true }), consoleLogService); const environmentService = new EnvironmentService(apiService, storageService, notificationsService); diff --git a/src/app/tools/import.component.html b/src/app/tools/import.component.html index 805ee7824e..578695f36a 100644 --- a/src/app/tools/import.component.html +++ b/src/app/tools/import.component.html @@ -1,7 +1,7 @@ -
+
@@ -248,7 +248,7 @@
- diff --git a/src/app/tools/import.component.ts b/src/app/tools/import.component.ts index b9451dba20..bf38ce51e2 100644 --- a/src/app/tools/import.component.ts +++ b/src/app/tools/import.component.ts @@ -9,6 +9,9 @@ import { Angulartics2 } from 'angulartics2'; import { I18nService } from 'jslib/abstractions/i18n.service'; import { ImportOption, ImportService } from 'jslib/abstractions/import.service'; +import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service'; + +import Swal, { SweetAlertIcon } from 'sweetalert2/dist/sweetalert2.js'; @Component({ selector: 'app-import', @@ -20,13 +23,14 @@ export class ImportComponent implements OnInit { format: string = null; fileContents: string; formPromise: Promise; + loading: boolean = false; protected organizationId: string = null; protected successNavigate: any[] = ['vault']; constructor(protected i18nService: I18nService, protected analytics: Angulartics2, protected toasterService: ToasterService, protected importService: ImportService, - protected router: Router) { } + protected router: Router, protected platformUtilsService: PlatformUtilsService) { } ngOnInit() { this.setImportOptions(); @@ -47,10 +51,13 @@ export class ImportComponent implements OnInit { } async submit() { + this.loading = true; + const importer = this.importService.getImporter(this.format, this.organizationId); if (importer === null) { this.toasterService.popAsync('error', this.i18nService.t('errorOccurred'), this.i18nService.t('selectFormat')); + this.loading = false; return; } @@ -59,6 +66,7 @@ export class ImportComponent implements OnInit { if ((files == null || files.length === 0) && (this.fileContents == null || this.fileContents === '')) { this.toasterService.popAsync('error', this.i18nService.t('errorOccurred'), this.i18nService.t('selectFile')); + this.loading = false; return; } @@ -75,6 +83,7 @@ export class ImportComponent implements OnInit { if (fileContents == null || fileContents === '') { this.toasterService.popAsync('error', this.i18nService.t('errorOccurred'), this.i18nService.t('selectFile')); + this.loading = false; return; } @@ -83,6 +92,7 @@ export class ImportComponent implements OnInit { const error = await this.formPromise; if (error != null) { this.error(error); + this.loading = false; return; } this.analytics.eventTrack.next({ @@ -92,6 +102,8 @@ export class ImportComponent implements OnInit { this.toasterService.popAsync('success', null, this.i18nService.t('importSuccess')); this.router.navigate(this.successNavigate); } catch { } + + this.loading = false; } getFormatInstructionTitle() { @@ -114,12 +126,30 @@ export class ImportComponent implements OnInit { this.importOptions = this.importService.regularImportOptions; } - private error(error: Error) { + private async error(error: Error) { this.analytics.eventTrack.next({ action: 'Import Data Failed', properties: { label: this.format }, }); - this.toasterService.popAsync('error', this.i18nService.t('errorOccurred'), error.message); + + await Swal.fire({ + heightAuto: false, + buttonsStyling: false, + icon: 'error' as SweetAlertIcon, + iconHtml: ``, + input: 'textarea', + inputValue: error.message, + inputAttributes: { + 'readonly': 'true', + }, + title: this.i18nService.t('importError'), + text: this.i18nService.t('importErrorDesc'), + showConfirmButton: true, + confirmButtonText: this.i18nService.t('ok'), + onOpen: popupEl => { + popupEl.querySelector('.swal2-textarea').scrollTo(0, 0); + }, + }); } private getFileContents(file: File): Promise { diff --git a/src/locales/en/messages.json b/src/locales/en/messages.json index 4e8249acc6..f09dcf1e35 100644 --- a/src/locales/en/messages.json +++ b/src/locales/en/messages.json @@ -1000,6 +1000,12 @@ "importData": { "message": "Import Data" }, + "importError": { + "message": "Import Error" + }, + "importErrorDesc": { + "message": "There was a problem with the data you tried to import. Please resolve the errors listed below in your source file and try again." + }, "importSuccess": { "message": "Data has been successfully imported into your vault." },