diff --git a/apps/web/src/app/tools/import-export/dialog/import-error-dialog.component.html b/apps/web/src/app/tools/import-export/dialog/import-error-dialog.component.html new file mode 100644 index 0000000000..c1ad8b5393 --- /dev/null +++ b/apps/web/src/app/tools/import-export/dialog/import-error-dialog.component.html @@ -0,0 +1,29 @@ + + + {{ "importError" | i18n }} + + + +
{{ "resolveTheErrorsBelowAndTryAgain" | i18n }}
+ + + + {{ "name" | i18n }} + {{ "description" | i18n }} + + + + + {{ r.type }} + {{ r.message }} + + + +
+ +
+ +
+
diff --git a/apps/web/src/app/tools/import-export/dialog/import-error-dialog.component.ts b/apps/web/src/app/tools/import-export/dialog/import-error-dialog.component.ts new file mode 100644 index 0000000000..abb68cf53b --- /dev/null +++ b/apps/web/src/app/tools/import-export/dialog/import-error-dialog.component.ts @@ -0,0 +1,33 @@ +import { DialogRef, DIALOG_DATA } from "@angular/cdk/dialog"; +import { Component, Inject, OnInit } from "@angular/core"; + +import { TableDataSource } from "@bitwarden/components"; + +export interface ErrorListItem { + type: string; + message: string; +} + +@Component({ + selector: "app-import-error-dialog", + templateUrl: "./import-error-dialog.component.html", +}) +export class ImportErrorDialogComponent implements OnInit { + protected dataSource = new TableDataSource(); + + constructor(public dialogRef: DialogRef, @Inject(DIALOG_DATA) public data: Error) {} + + ngOnInit(): void { + const split = this.data.message.split("\n\n"); + if (split.length == 1) { + this.dataSource.data = [{ type: "", message: this.data.message }]; + return; + } + + const data: ErrorListItem[] = []; + split.forEach((line) => { + data.push({ type: "", message: line }); + }); + this.dataSource.data = data; + } +} diff --git a/apps/web/src/app/tools/import-export/dialog/index.ts b/apps/web/src/app/tools/import-export/dialog/index.ts index 7ad42fe1db..641cd6600a 100644 --- a/apps/web/src/app/tools/import-export/dialog/index.ts +++ b/apps/web/src/app/tools/import-export/dialog/index.ts @@ -1,2 +1,3 @@ +export * from "./import-error-dialog.component"; export * from "./import-success-dialog.component"; export * from "./file-password-prompt.component"; diff --git a/apps/web/src/app/tools/import-export/import-export.module.ts b/apps/web/src/app/tools/import-export/import-export.module.ts index 4d59f41236..d180417cdc 100644 --- a/apps/web/src/app/tools/import-export/import-export.module.ts +++ b/apps/web/src/app/tools/import-export/import-export.module.ts @@ -15,7 +15,11 @@ import { import { LooseComponentsModule, SharedModule } from "../../shared"; -import { ImportSuccessDialogComponent, FilePasswordPromptComponent } from "./dialog"; +import { + ImportErrorDialogComponent, + ImportSuccessDialogComponent, + FilePasswordPromptComponent, +} from "./dialog"; import { ExportComponent } from "./export.component"; import { ImportExportRoutingModule } from "./import-export-routing.module"; import { ImportComponent } from "./import.component"; @@ -26,6 +30,7 @@ import { ImportComponent } from "./import.component"; ImportComponent, ExportComponent, FilePasswordPromptComponent, + ImportErrorDialogComponent, ImportSuccessDialogComponent, ], providers: [ diff --git a/apps/web/src/app/tools/import-export/import.component.ts b/apps/web/src/app/tools/import-export/import.component.ts index eb9201f021..fb7d1d5501 100644 --- a/apps/web/src/app/tools/import-export/import.component.ts +++ b/apps/web/src/app/tools/import-export/import.component.ts @@ -4,7 +4,6 @@ import { Router } from "@angular/router"; import * as JSZip from "jszip"; import { concat, Observable, Subject, lastValueFrom, combineLatest } from "rxjs"; import { map, takeUntil } from "rxjs/operators"; -import Swal, { SweetAlertIcon } from "sweetalert2"; import { ModalService } from "@bitwarden/angular/services/modal.service"; import { @@ -31,7 +30,11 @@ import { ImportType, } from "@bitwarden/importer"; -import { FilePasswordPromptComponent, ImportSuccessDialogComponent } from "./dialog"; +import { + FilePasswordPromptComponent, + ImportErrorDialogComponent, + ImportSuccessDialogComponent, +} from "./dialog"; @Component({ selector: "app-import", @@ -247,7 +250,9 @@ export class ImportComponent implements OnInit, OnDestroy { this.syncService.fullSync(true); await this.onSuccessfulImport(); } catch (e) { - this.error(e); + this.dialogService.open(ImportErrorDialogComponent, { + data: e, + }); this.logService.error(e); } } @@ -303,27 +308,6 @@ export class ImportComponent implements OnInit, OnDestroy { this.fileSelected = fileInputEl.files.length > 0 ? fileInputEl.files[0] : null; } - private async error(error: Error) { - await Swal.fire({ - heightAuto: false, - buttonsStyling: false, - icon: "error" as SweetAlertIcon, - iconHtml: ``, - input: "textarea", - inputValue: error.message, - inputAttributes: { - readonly: "true", - }, - titleText: 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 { if (this.format === "1password1pux") { return this.extractZipContent(file, "export.data");