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
This commit is contained in:
parent
a975f6df2b
commit
85856d8390
2
jslib
2
jslib
|
@ -1 +1 @@
|
|||
Subproject commit 0951424de77fbb61a38616d13d6c67f74ee19775
|
||||
Subproject commit 42348e2fdc6206157d68d8a9f496eaa70520ab01
|
|
@ -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() {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<div class="page-header">
|
||||
<h1>{{'importData' | i18n}}</h1>
|
||||
</div>
|
||||
<form #form (ngSubmit)="submit()" [appApiAction]="formPromise" ngNativeValidate>
|
||||
<form #form (ngSubmit)="submit()" ngNativeValidate>
|
||||
<div class="row">
|
||||
<div class="col-6">
|
||||
<div class="form-group">
|
||||
|
@ -248,7 +248,7 @@
|
|||
<label for="fileContents">{{'orCopyPasteFileContents' | i18n}}</label>
|
||||
<textarea id="fileContents" class="form-control" name="FileContents" [(ngModel)]="fileContents"></textarea>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary btn-submit" [disabled]="form.loading">
|
||||
<button type="submit" class="btn btn-primary btn-submit" [disabled]="loading">
|
||||
<i class="fa fa-spinner fa-spin" title="{{'loading' | i18n}}" aria-hidden="true"></i>
|
||||
<span>{{'importData' | i18n}}</span>
|
||||
</button>
|
||||
|
|
|
@ -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<Error>;
|
||||
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: `<i class="swal-custom-icon fa fa-bolt text-danger"></i>`,
|
||||
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<string> {
|
||||
|
|
|
@ -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."
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue