From 728f052cd2391e4ed64cb36bcb0d4fa43919d90f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adina=20=C8=9Aeudan?= Date: Fri, 30 Oct 2020 12:21:43 +0200 Subject: [PATCH] New rule marker and custom toast component --- apps/red-ui/src/app/app.module.ts | 10 ++- .../simple-doughnut-chart.component.scss | 51 --------------- .../status-bar/status-bar.component.scss | 36 ----------- .../app/components/toast/toast.component.html | 32 ++++++++++ .../app/components/toast/toast.component.scss | 1 + .../app/components/toast/toast.component.ts | 26 ++++++++ .../app/notification/notification.service.ts | 17 +++-- .../project-overview-screen.component.html | 19 ++++-- .../project-overview-screen.component.scss | 7 +++ .../project-overview-screen.component.ts | 43 ++++++++++++- apps/red-ui/src/assets/i18n/en.json | 16 +++++ .../src/assets/styles/red-components.scss | 62 +++++++++++++++++++ apps/red-ui/src/assets/styles/red-toasts.scss | 27 +++++++- 13 files changed, 243 insertions(+), 104 deletions(-) create mode 100644 apps/red-ui/src/app/components/toast/toast.component.html create mode 100644 apps/red-ui/src/app/components/toast/toast.component.scss create mode 100644 apps/red-ui/src/app/components/toast/toast.component.ts diff --git a/apps/red-ui/src/app/app.module.ts b/apps/red-ui/src/app/app.module.ts index 2cbdb6539..e151ff455 100644 --- a/apps/red-ui/src/app/app.module.ts +++ b/apps/red-ui/src/app/app.module.ts @@ -61,6 +61,7 @@ import { MatInputModule } from '@angular/material/input'; import { ProjectMemberGuard } from './auth/project-member-guard.service'; import { HumanizePipe } from './utils/humanize.pipe'; import { ManualAnnotationDialogComponent } from './dialogs/manual-redaction-dialog/manual-annotation-dialog.component'; +import { ToastComponent } from './components/toast/toast.component'; export function HttpLoaderFactory(httpClient: HttpClient) { return new TranslateHttpLoader(httpClient, '/assets/i18n/', '.json'); @@ -86,7 +87,8 @@ export function HttpLoaderFactory(httpClient: HttpClient) { ManualAnnotationDialogComponent, AnnotationIconComponent, AuthErrorComponent, - HumanizePipe + HumanizePipe, + ToastComponent ], imports: [ BrowserModule, @@ -169,7 +171,11 @@ export function HttpLoaderFactory(httpClient: HttpClient) { MatTabsModule, MatButtonToggleModule, MatFormFieldModule, - ToastrModule.forRoot({ closeButton: true }), + ToastrModule.forRoot({ + closeButton: true, + enableHtml: true, + toastComponent: ToastComponent + }), MatSelectModule, MatSidenavModule, FileUploadModule, diff --git a/apps/red-ui/src/app/components/simple-doughnut-chart/simple-doughnut-chart.component.scss b/apps/red-ui/src/app/components/simple-doughnut-chart/simple-doughnut-chart.component.scss index cb54c37e8..895fa4c83 100644 --- a/apps/red-ui/src/app/components/simple-doughnut-chart/simple-doughnut-chart.component.scss +++ b/apps/red-ui/src/app/components/simple-doughnut-chart/simple-doughnut-chart.component.scss @@ -38,54 +38,3 @@ gap: 8px; } } - -// 'UNPROCESSED' -// | 'REPROCESS' -// | 'PROCESSING'REPROCESS -// | 'ERROR' -// | 'UNASSIGNED' -// | 'UNDER_REVIEW' -// | 'UNDER_APPROVAL' -// | 'APPROVED'; - -circle { - &.UNASSIGNED { - stroke: $grey-5; - } - - &.UNPROCESSED { - stroke: $grey-3; - } - - &.UNDER_REVIEW { - stroke: $yellow-1; - } - - &.UNDER_APPROVAL { - stroke: $blue-4; - } - - &.APPROVED { - stroke: $blue-3; - } - - &.PROCESSING { - stroke: $green-2; - } - - &.REPROCESS { - stroke: $green-1; - } - - &.ERROR { - stroke: $red-1; - } - - &.ACTIVE { - stroke: $primary; - } - - &.ARCHIVED { - stroke: rgba($red-1, 0.1); - } -} diff --git a/apps/red-ui/src/app/components/status-bar/status-bar.component.scss b/apps/red-ui/src/app/components/status-bar/status-bar.component.scss index e0e0a814b..6d41e9b55 100644 --- a/apps/red-ui/src/app/components/status-bar/status-bar.component.scss +++ b/apps/red-ui/src/app/components/status-bar/status-bar.component.scss @@ -38,41 +38,5 @@ .rectangle { height: 4px; - - &.UNASSIGNED { - background-color: $grey-5; - } - - &.UNDER_REVIEW { - background-color: $yellow-1; - } - - &.UNDER_APPROVAL { - background-color: $red-1; - } - - &.APPROVED { - background-color: $blue-2; - } - - &.SUBMITTED { - background-color: $blue-3; - } - - &.EFSA { - background-color: $blue-4; - } - - &.FINISHED { - background-color: $green-2; - } - - &.ACTIVE { - background-color: $primary; - } - - &.ARCHIVED { - background-color: rgba($red-1, 0.1); - } } } diff --git a/apps/red-ui/src/app/components/toast/toast.component.html b/apps/red-ui/src/app/components/toast/toast.component.html new file mode 100644 index 000000000..3ec0115cc --- /dev/null +++ b/apps/red-ui/src/app/components/toast/toast.component.html @@ -0,0 +1,32 @@ +
+
+ {{ title }} +
+
+
+ {{ message }} +
+ + +
+
+ + + +
diff --git a/apps/red-ui/src/app/components/toast/toast.component.scss b/apps/red-ui/src/app/components/toast/toast.component.scss new file mode 100644 index 000000000..93be7acbb --- /dev/null +++ b/apps/red-ui/src/app/components/toast/toast.component.scss @@ -0,0 +1 @@ +@import '../../../assets/styles/red-variables'; diff --git a/apps/red-ui/src/app/components/toast/toast.component.ts b/apps/red-ui/src/app/components/toast/toast.component.ts new file mode 100644 index 000000000..66f5412fb --- /dev/null +++ b/apps/red-ui/src/app/components/toast/toast.component.ts @@ -0,0 +1,26 @@ +import { Component } from '@angular/core'; +import { Toast, ToastPackage, ToastrService } from 'ngx-toastr'; + +@Component({ + selector: 'redaction-toast', + templateUrl: './toast.component.html', + styleUrls: ['./toast.component.scss'] +}) +export class ToastComponent extends Toast { + constructor(protected toastrService: ToastrService, public toastPackage: ToastPackage) { + super(toastrService, toastPackage); + } + + public get actions() { + // @ts-ignore + return this.options.actions; + } + + public callAction($event: MouseEvent, action: Function) { + $event.stopPropagation(); + if (action) { + action(); + } + this.remove(); + } +} diff --git a/apps/red-ui/src/app/notification/notification.service.ts b/apps/red-ui/src/app/notification/notification.service.ts index 0d2a7463b..c15f7fc72 100644 --- a/apps/red-ui/src/app/notification/notification.service.ts +++ b/apps/red-ui/src/app/notification/notification.service.ts @@ -1,6 +1,7 @@ import { Injectable } from '@angular/core'; import { MatSnackBar } from '@angular/material/snack-bar'; import { ToastrService } from 'ngx-toastr'; +import { IndividualConfig } from 'ngx-toastr/toastr/toastr-config'; export enum NotificationType { SUCCESS = 'SUCCESS', @@ -9,6 +10,11 @@ export enum NotificationType { INFO = 'INFO' } +export class Action { + title: string; + action?: Function; +} + @Injectable({ providedIn: 'root' }) @@ -18,20 +24,21 @@ export class NotificationService { showToastNotification( message: string, title?: string, - notificationType: NotificationType = NotificationType.INFO + notificationType: NotificationType = NotificationType.INFO, + options?: Partial & { actions: Action[] } ) { switch (notificationType) { case NotificationType.ERROR: - this._toastr.error(message, title); + this._toastr.error(message, title, options); break; case NotificationType.SUCCESS: - this._toastr.success(message, title); + this._toastr.success(message, title, options); break; case NotificationType.WARNING: - this._toastr.warning(message, title); + this._toastr.warning(message, title, options); break; case NotificationType.INFO: - this._toastr.info(message, title); + this._toastr.info(message, title, options); break; } } diff --git a/apps/red-ui/src/app/screens/project-overview-screen/project-overview-screen.component.html b/apps/red-ui/src/app/screens/project-overview-screen/project-overview-screen.component.html index 6235f9051..e6736dbb9 100644 --- a/apps/red-ui/src/app/screens/project-overview-screen/project-overview-screen.component.html +++ b/apps/red-ui/src/app/screens/project-overview-screen/project-overview-screen.component.html @@ -144,12 +144,19 @@
-
- {{ fileStatus.filename }} +
+
+ {{ fileStatus.filename }} +
+
diff --git a/apps/red-ui/src/app/screens/project-overview-screen/project-overview-screen.component.scss b/apps/red-ui/src/app/screens/project-overview-screen/project-overview-screen.component.scss index ff8b54350..5af26257f 100644 --- a/apps/red-ui/src/app/screens/project-overview-screen/project-overview-screen.component.scss +++ b/apps/red-ui/src/app/screens/project-overview-screen/project-overview-screen.component.scss @@ -67,6 +67,13 @@ .status-container { align-items: flex-end; } + + .filename-wrapper { + display: flex; + justify-content: space-between; + align-items: center; + gap: 8px; + } } } diff --git a/apps/red-ui/src/app/screens/project-overview-screen/project-overview-screen.component.ts b/apps/red-ui/src/app/screens/project-overview-screen/project-overview-screen.component.ts index f9fe26a02..4c38935ab 100644 --- a/apps/red-ui/src/app/screens/project-overview-screen/project-overview-screen.component.ts +++ b/apps/red-ui/src/app/screens/project-overview-screen/project-overview-screen.component.ts @@ -6,7 +6,7 @@ import { ReanalysisControllerService, StatusControllerService } from '@redaction/red-ui-http'; -import { NotificationService } from '../../notification/notification.service'; +import { NotificationService, NotificationType } from '../../notification/notification.service'; import { AppStateService } from '../../state/app-state.service'; import { FileDropOverlayService } from '../../upload/file-drop/service/file-drop-overlay.service'; import { FileUploadModel } from '../../upload/model/file-upload.model'; @@ -17,6 +17,7 @@ import { SortingOption } from '../../utils/types'; import { DoughnutChartConfig } from '../../components/simple-doughnut-chart/simple-doughnut-chart.component'; import { groupBy } from '../../utils/functions'; import { DialogService } from '../../dialogs/dialog.service'; +import { TranslateService } from '@ngx-translate/core'; @Component({ selector: 'redaction-project-overview-screen', @@ -60,6 +61,7 @@ export class ProjectOverviewScreenComponent implements OnInit, OnDestroy { private readonly _uploadStatusOverlayService: UploadStatusOverlayService, private readonly _reanalysisControllerService: ReanalysisControllerService, private readonly _router: Router, + private readonly _translateService: TranslateService, private readonly _fileDropOverlayService: FileDropOverlayService ) { this._activatedRoute.params.subscribe((params) => { @@ -74,6 +76,7 @@ export class ProjectOverviewScreenComponent implements OnInit, OnDestroy { ngOnInit(): void { this._fileDropOverlayService.initFileDropHandling(); this._calculateChartConfig(); + this._displayNewRuleToast(); } ngOnDestroy(): void { @@ -112,6 +115,44 @@ export class ProjectOverviewScreenComponent implements OnInit, OnDestroy { ); } + private _displayNewRuleToast() { + // @ts-ignore + if (!this.appStateService.activeProject.files.filter((file) => file.newRule).length) { + return; + } + + this._notificationService.showToastNotification( + `${this._translateService.instant( + 'project-overview.new-rule.toast.message.label' + )} ${this._translateService.instant( + 'project-overview.new-rule.label' + )}`, + null, + NotificationType.WARNING, + { + disableTimeOut: true, + positionClass: 'toast-top-left', + actions: [ + { + title: this._translateService.instant( + 'project-overview.new-rule.toast.actions.reanalyse-all.label' + ), + action: () => + this._reanalysisControllerService + .reanalyzeProject(this.activeProject.projectId) + .toPromise() + .then(() => this._reloadProjects()) + }, + { + title: this._translateService.instant( + 'project-overview.new-rule.toast.actions.later.label' + ) + } + ] + } + ); + } + private _reloadProjects() { this.appStateService.loadAllProjects().then(() => { this._calculateChartConfig(); diff --git a/apps/red-ui/src/assets/i18n/en.json b/apps/red-ui/src/assets/i18n/en.json index 12b4cb8dd..e302ad2f2 100644 --- a/apps/red-ui/src/assets/i18n/en.json +++ b/apps/red-ui/src/assets/i18n/en.json @@ -323,6 +323,22 @@ } }, "project-overview": { + "new-rule": { + "label": "New Rule", + "toast": { + "message": { + "label": "Some documents were not processed with the latest rule/dictionary set. They are marked with:\n\n" + }, + "actions": { + "reanalyse-all": { + "label": "Reanalyse all" + }, + "later": { + "label": "Later" + } + } + } + }, "report": { "action": { "label": "Download Redaction Report" diff --git a/apps/red-ui/src/assets/styles/red-components.scss b/apps/red-ui/src/assets/styles/red-components.scss index f5f8828ba..48797f95f 100644 --- a/apps/red-ui/src/assets/styles/red-components.scss +++ b/apps/red-ui/src/assets/styles/red-components.scss @@ -69,3 +69,65 @@ margin-right: 4px; } } + +.pill { + padding: 2px 5px; + border-radius: 9px; + background-color: $primary; + color: $white; + font-size: 10px; + font-weight: 600; + line-height: 12px; + text-align: center; + white-space: pre; +} + +.UNASSIGNED { + stroke: $grey-5; + background-color: $grey-5; +} + +.UNPROCESSED { + stroke: $grey-3; + background-color: $grey-3; +} + +.UNDER_REVIEW { + stroke: $yellow-1; + background-color: $yellow-1; +} + +.UNDER_APPROVAL { + stroke: $blue-4; + background-color: $blue-4; +} + +.APPROVED { + stroke: $blue-3; + background-color: $blue-3; +} + +.PROCESSING { + stroke: $green-2; + background-color: $green-2; +} + +.REPROCESS { + stroke: $green-1; + background-color: $green-1; +} + +.ERROR { + stroke: $red-1; + background-color: $red-1; +} + +.ACTIVE { + stroke: $primary; + background-color: $primary; +} + +.ARCHIVED { + stroke: rgba($red-1, 0.1); + background-color: rgba($red-1, 0.1); +} diff --git a/apps/red-ui/src/assets/styles/red-toasts.scss b/apps/red-ui/src/assets/styles/red-toasts.scss index 7ad1c7a77..eae83ee2f 100644 --- a/apps/red-ui/src/assets/styles/red-toasts.scss +++ b/apps/red-ui/src/assets/styles/red-toasts.scss @@ -9,7 +9,6 @@ line-height: 18px; width: 400px; display: flex; - flex-direction: row-reverse; justify-content: space-between; align-items: center; gap: 10px; @@ -18,15 +17,37 @@ &:hover { box-shadow: none; } + + .actions-wrapper { + margin-top: 24px; + display: flex; + gap: 24px; + + a { + font-size: 11px; + font-weight: 600; + line-height: 14px; + color: $accent; + text-transform: uppercase; + cursor: pointer; + } + } +} + +.toast-top-right, +.toast-top-left { + top: 100px; } .toast-close-button { position: initial; opacity: 1; - font-weight: 500; - font-size: 22px; text-shadow: none; + mat-icon { + width: 10px; + } + &:hover { opacity: 1; }