1
0
mirror of https://github.com/bitwarden/browser.git synced 2024-12-27 17:18:04 +01:00

[PM-147] Import error states usability improvements (#6245)

* Add import error dialog

(cherry picked from commit 518211dae0)

* Rename ErrorList to ErrorListItem

(cherry picked from commit a7dd643710)
This commit is contained in:
Daniel James Smith 2023-09-11 16:41:34 +02:00 committed by GitHub
parent 30d8168c2e
commit 2323509dee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 77 additions and 25 deletions

View File

@ -0,0 +1,29 @@
<bit-dialog>
<span bitDialogTitle>
{{ "importError" | i18n }}
</span>
<span bitDialogContent>
<div>{{ "resolveTheErrorsBelowAndTryAgain" | i18n }}</div>
<bit-table [dataSource]="dataSource">
<ng-container header>
<tr>
<th bitCell>{{ "name" | i18n }}</th>
<th bitCell>{{ "description" | i18n }}</th>
</tr>
</ng-container>
<ng-template body let-rows$>
<tr bitRow *ngFor="let r of rows$ | async">
<td bitCell>{{ r.type }}</td>
<td bitCell>{{ r.message }}</td>
</tr>
</ng-template>
</bit-table>
</span>
<div bitDialogFooter>
<button bitButton bitDialogClose buttonType="primary" type="button">
{{ "ok" | i18n }}
</button>
</div>
</bit-dialog>

View File

@ -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<ErrorListItem>();
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;
}
}

View File

@ -1,2 +1,3 @@
export * from "./import-error-dialog.component";
export * from "./import-success-dialog.component";
export * from "./file-password-prompt.component";

View File

@ -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: [

View File

@ -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<unknown, Error>(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: `<i class="swal-custom-icon bwi bwi-error text-danger"></i>`,
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<string> {
if (this.format === "1password1pux") {
return this.extractZipContent(file, "export.data");