diff --git a/jslib b/jslib index 5db94cc9..a6b95b15 160000 --- a/jslib +++ b/jslib @@ -1 +1 @@ -Subproject commit 5db94cc9d06ba478a29e9b625993108dfa0d7ec8 +Subproject commit a6b95b15e36737ccf2e7664ed3c881bc19366b84 diff --git a/package-lock.json b/package-lock.json index 32205c90..c28bea28 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,7 @@ "@bitwarden/jslib-angular": "file:jslib/angular", "@bitwarden/jslib-common": "file:jslib/common", "@bitwarden/jslib-electron": "file:jslib/electron", - "angular2-toaster": "^11.0.1", + "ngx-toastr": "^13.2.1", "node-ipc": "^9.1.4", "nord": "^0.2.1", "regedit": "^3.0.3", @@ -1740,20 +1740,6 @@ "ajv": "^6.9.1" } }, - "node_modules/angular2-toaster": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/angular2-toaster/-/angular2-toaster-11.0.1.tgz", - "integrity": "sha512-IRXE5zujPMNOhckcp+Hk2n+UrKSrlAviz55wGvSd9ECrqsSRjgh148UEtgsqkcYQ8leKcybZ4d0lrueDuQofNA==", - "dependencies": { - "tslib": "^2.0.0" - }, - "peerDependencies": { - "@angular/common": "^11.0.0", - "@angular/compiler": "^11.0.0", - "@angular/core": "^11.0.0", - "rxjs": "^6.5.3" - } - }, "node_modules/ansi-align": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", @@ -8478,6 +8464,19 @@ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", "dev": true }, + "node_modules/ngx-toastr": { + "version": "13.2.1", + "resolved": "https://registry.npmjs.org/ngx-toastr/-/ngx-toastr-13.2.1.tgz", + "integrity": "sha512-UAzp7/xWK9IXA2LsOmhpaaIGCqscvJokoQpBNpAMrjEkDeSlFf8PWQAuQY795KW0mJb3qF9UG/s23nsXfMYKmg==", + "dependencies": { + "tslib": "^2.0.0" + }, + "peerDependencies": { + "@angular/common": ">=10.0.0-0", + "@angular/core": ">=10.0.0-0", + "@angular/platform-browser": ">=10.0.0-0" + } + }, "node_modules/no-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", @@ -15472,14 +15471,6 @@ "dev": true, "requires": {} }, - "angular2-toaster": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/angular2-toaster/-/angular2-toaster-11.0.1.tgz", - "integrity": "sha512-IRXE5zujPMNOhckcp+Hk2n+UrKSrlAviz55wGvSd9ECrqsSRjgh148UEtgsqkcYQ8leKcybZ4d0lrueDuQofNA==", - "requires": { - "tslib": "^2.0.0" - } - }, "ansi-align": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", @@ -20732,6 +20723,14 @@ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", "dev": true }, + "ngx-toastr": { + "version": "13.2.1", + "resolved": "https://registry.npmjs.org/ngx-toastr/-/ngx-toastr-13.2.1.tgz", + "integrity": "sha512-UAzp7/xWK9IXA2LsOmhpaaIGCqscvJokoQpBNpAMrjEkDeSlFf8PWQAuQY795KW0mJb3qF9UG/s23nsXfMYKmg==", + "requires": { + "tslib": "^2.0.0" + } + }, "no-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", diff --git a/package.json b/package.json index 574fefd5..484e1dd8 100644 --- a/package.json +++ b/package.json @@ -285,7 +285,7 @@ "@bitwarden/jslib-angular": "file:jslib/angular", "@bitwarden/jslib-common": "file:jslib/common", "@bitwarden/jslib-electron": "file:jslib/electron", - "angular2-toaster": "^11.0.1", + "ngx-toastr": "^13.2.1", "node-ipc": "^9.1.4", "nord": "^0.2.1", "regedit": "^3.0.3", diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 521634bb..a284a63e 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -1,10 +1,3 @@ -import { - BodyOutputType, - Toast, - ToasterConfig, - ToasterService, -} from 'angular2-toaster'; - import { Component, NgZone, @@ -16,6 +9,10 @@ import { } from '@angular/core'; import { DomSanitizer } from '@angular/platform-browser'; import { Router } from '@angular/router'; +import { + IndividualConfig, + ToastrService, +} from 'ngx-toastr'; import { PremiumComponent } from './accounts/premium.component'; import { SettingsComponent } from './accounts/settings.component'; @@ -64,7 +61,6 @@ const SyncInterval = 6 * 60 * 60 * 1000; // 6 hours selector: 'app-root', styles: [], template: ` - @@ -83,13 +79,6 @@ export class AppComponent implements OnInit { @ViewChild('appPasswordGenerator', { read: ViewContainerRef, static: true }) passwordGeneratorModalRef: ViewContainerRef; - toasterConfig: ToasterConfig = new ToasterConfig({ - showCloseButton: true, - mouseoverTimerStop: true, - animation: 'flyRight', - limit: 5, - }); - private lastActivity: number = null; private modal: ModalRef = null; private idleTimer: number = null; @@ -100,7 +89,7 @@ export class AppComponent implements OnInit { private settingsService: SettingsService, private syncService: SyncService, private passwordGenerationService: PasswordGenerationService, private cipherService: CipherService, private authService: AuthService, private router: Router, - private toasterService: ToasterService, private i18nService: I18nService, + private toastrService: ToastrService, private i18nService: I18nService, private sanitizer: DomSanitizer, private ngZone: NgZone, private vaultTimeoutService: VaultTimeoutService, private storageService: StorageService, private cryptoService: CryptoService, private logService: LogService, @@ -224,9 +213,9 @@ export class AppComponent implements OnInit { case 'syncVault': try { await this.syncService.fullSync(true, true); - this.toasterService.popAsync('success', null, this.i18nService.t('syncingComplete')); + this.platformUtilsService.showToast('success', null, this.i18nService.t('syncingComplete')); } catch { - this.toasterService.popAsync('error', null, this.i18nService.t('syncingFailed')); + this.platformUtilsService.showToast('error', null, this.i18nService.t('syncingFailed')); } break; case 'checkSyncVault': @@ -374,7 +363,7 @@ export class AppComponent implements OnInit { this.searchService.clearIndex(); this.authService.logOut(async () => { if (expired) { - this.toasterService.popAsync('warning', this.i18nService.t('loggedOut'), + this.platformUtilsService.showToast('warning', this.i18nService.t('loggedOut'), this.i18nService.t('loginExpired')); } this.router.navigate(['login']); @@ -428,30 +417,29 @@ export class AppComponent implements OnInit { } private showToast(msg: any) { - const toast: Toast = { - type: msg.type, - title: msg.title, - }; + let message = ''; + + const options: Partial = {}; + if (typeof (msg.text) === 'string') { - toast.body = msg.text; + message = msg.text; } else if (msg.text.length === 1) { - toast.body = msg.text[0]; + message = msg.text[0]; } else { - let message = ''; msg.text.forEach((t: string) => message += ('

' + this.sanitizer.sanitize(SecurityContext.HTML, t) + '

')); - toast.body = message; - toast.bodyOutputType = BodyOutputType.TrustedHtml; + options.enableHtml = true; } if (msg.options != null) { if (msg.options.trustedHtml === true) { - toast.bodyOutputType = BodyOutputType.TrustedHtml; + options.enableHtml = true; } if (msg.options.timeout != null && msg.options.timeout > 0) { - toast.timeout = msg.options.timeout; + options.timeOut = msg.options.timeout; } } - this.toasterService.popAsync(toast); + + this.toastrService.show(message, msg.title, options, 'toast-' + msg.type); } private routeToVault(action: string, cipherType: CipherType) { diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 50e7180a..3bbb5248 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -1,7 +1,5 @@ import 'zone.js/dist/zone'; -import { ToasterModule } from 'angular2-toaster'; - import { AppRoutingModule } from './app-routing.module'; import { ServicesModule } from './services.module'; @@ -33,6 +31,7 @@ import { VaultTimeoutInputComponent } from './accounts/vault-timeout-input.compo import { CalloutComponent } from 'jslib-angular/components/callout.component'; import { IconComponent } from 'jslib-angular/components/icon.component'; +import { BitwardenToastModule } from 'jslib-angular/components/toastr.component'; import { A11yTitleDirective } from 'jslib-angular/directives/a11y-title.directive'; import { ApiActionDirective } from 'jslib-angular/directives/api-action.directive'; @@ -177,7 +176,11 @@ registerLocaleData(localeZhTw, 'zh-TW'); FormsModule, ReactiveFormsModule, ServicesModule, - ToasterModule.forRoot(), + BitwardenToastModule.forRoot({ + maxOpened: 5, + autoDismiss: true, + closeButton: true, + }), ScrollingModule, A11yModule, ], diff --git a/src/app/vault/vault.component.ts b/src/app/vault/vault.component.ts index b8a5c01c..be6fc541 100644 --- a/src/app/vault/vault.component.ts +++ b/src/app/vault/vault.component.ts @@ -14,8 +14,6 @@ import { import { first } from 'rxjs/operators'; -import { ToasterService } from 'angular2-toaster'; - import { AddEditComponent } from './add-edit.component'; import { AttachmentsComponent } from './attachments.component'; import { CiphersComponent } from './ciphers.component'; @@ -86,7 +84,7 @@ export class VaultComponent implements OnInit, OnDestroy { private i18nService: I18nService, private modalService: ModalService, private broadcasterService: BroadcasterService, private changeDetectorRef: ChangeDetectorRef, private ngZone: NgZone, private syncService: SyncService, - private toasterService: ToasterService, private messagingService: MessagingService, + private messagingService: MessagingService, private platformUtilsService: PlatformUtilsService, private eventService: EventService, private totpService: TotpService, private userService: UserService, private passwordRepromptService: PasswordRepromptService) { } @@ -651,7 +649,7 @@ export class VaultComponent implements OnInit, OnDestroy { } this.platformUtilsService.copyToClipboard(value); - this.toasterService.popAsync('info', null, + this.platformUtilsService.showToast('info', null, this.i18nService.t('valueCopied', this.i18nService.t(labelI18nKey))); if (this.action === 'view') { this.messagingService.send('minimizeOnCopy'); diff --git a/src/scss/plugins.scss b/src/scss/plugins.scss index ca525cac..461a46dd 100644 --- a/src/scss/plugins.scss +++ b/src/scss/plugins.scss @@ -1,43 +1,41 @@ $fa-font-path: "~font-awesome/fonts"; @import "~font-awesome/scss/font-awesome.scss"; -@import "~angular2-toaster/toaster"; +@import '~ngx-toastr/toastr'; @import "~sweetalert2/src/sweetalert2.scss"; @import "variables.scss"; .toast-container { .toast-close-button { - margin-right: 4px; font-size: 18px; + margin-right: 4px; } - .toast { - opacity: 1 !important; + .ngx-toastr { + align-items: center; background-image: none !important; border-radius: $border-radius; box-shadow: 0 0 8px rgba(0, 0, 0, 0.35); display: flex; - align-items: center; + padding: 15px; + + .toast-close-button { + position: absolute; + right: 5px; + top: 0; + } &:hover { box-shadow: 0 0 10px rgba(0, 0, 0, 0.6); } - &:before { + .icon i::before { + float: left; + font-style: normal; font-family: FontAwesome; font-size: 25px; line-height: 20px; - float: left; - color: #ffffff; - margin: auto 0 auto 15px; - } - - .toast-content { - padding: 15px; - } - - .toaster-icon { - display: none; + padding-right: 15px; } .toast-message { @@ -51,49 +49,41 @@ $fa-font-path: "~font-awesome/fonts"; } &.toast-danger, &.toast-error { - background-image: none !important; - @include themify($themes) { background-color: themed('dangerColor'); } - &:before { + .icon i::before { content: "\f0e7"; } } &.toast-warning { - background-image: none !important; - @include themify($themes) { background-color: themed('warningColor'); } - &:before { + .icon i::before { content: "\f071"; } } &.toast-info { - background-image: none !important; - @include themify($themes) { background-color: themed('infoColor'); } - &:before { + .icon i:before { content: "\f05a"; } } &.toast-success { - background-image: none !important; - @include themify($themes) { background-color: themed('successColor'); } - &:before { + .icon i:before { content: "\f00C"; } }