UI: Add notification not in popover and added filter for noification template

This commit is contained in:
Vladyslav_Prykhodko 2023-01-23 12:47:00 +02:00
parent baade28170
commit 25f2a54e5b
9 changed files with 41 additions and 23 deletions

View File

@ -29,10 +29,12 @@ import {
NotificationSettings, NotificationSettings,
NotificationTarget, NotificationTarget,
NotificationTemplate, NotificationTemplate,
NotificationType,
SlackChanelType, SlackChanelType,
SlackConversation SlackConversation
} from '@shared/models/notification.models'; } from '@shared/models/notification.models';
import { User } from '@shared/models/user.model'; import { User } from '@shared/models/user.model';
import { isDefinedAndNotNull } from '@core/utils';
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
@ -143,8 +145,12 @@ export class NotificationService {
return this.http.delete<void>(`/api/notification/template/${id}`, defaultHttpOptionsFromConfig(config)); return this.http.delete<void>(`/api/notification/template/${id}`, defaultHttpOptionsFromConfig(config));
} }
public getNotificationTemplates(pageLink: PageLink, config?: RequestConfig): Observable<PageData<NotificationTemplate>> { public getNotificationTemplates(pageLink: PageLink, notificationTypes?: NotificationType,
return this.http.get<PageData<NotificationTemplate>>(`/api/notification/templates${pageLink.toQuery()}`, config?: RequestConfig): Observable<PageData<NotificationTemplate>> {
defaultHttpOptionsFromConfig(config)); let url = `/api/notification/templates${pageLink.toQuery()}`;
if (isDefinedAndNotNull(notificationTypes)) {
url += `&notificationTypes=${notificationTypes}`;
}
return this.http.get<PageData<NotificationTemplate>>(url, defaultHttpOptionsFromConfig(config));
} }
} }

View File

@ -54,6 +54,7 @@ export class NotificationBellComponent implements OnInit {
this.notificationSubscriber = NotificationSubscriber.createNotificationCountSubscription( this.notificationSubscriber = NotificationSubscriber.createNotificationCountSubscription(
this.notificationWsService, this.zone); this.notificationWsService, this.zone);
this.notificationSubscriber.subscribe(); this.notificationSubscriber.subscribe();
this.count$ = this.notificationSubscriber.notificationCount$.pipe( this.count$ = this.notificationSubscriber.notificationCount$.pipe(
distinctUntilChanged(), distinctUntilChanged(),
publishReplay(1), publishReplay(1),

View File

@ -15,25 +15,25 @@
limitations under the License. limitations under the License.
--> -->
<section fxLayout="row" fxLayoutAlign="space-between center" style="margin-bottom: 4px"> <section fxLayout="row" fxLayoutAlign="space-between center" style="margin-bottom: 4px; min-height: 36px">
<div style="font-weight: 500; letter-spacing: .25px" translate>notification.notification</div> <div style="font-weight: 500; letter-spacing: .25px" translate>notification.notification</div>
<button mat-button color="primary" <button mat-button color="primary"
[disabled]="!(notifications$ | async).length" *ngIf="(notifications$ | async).length"
(click)="markAsAllRead($event)"> (click)="markAsAllRead($event)">
{{ 'notification.mark-all-as-read' | translate }} {{ 'notification.mark-all-as-read' | translate }}
</button> </button>
</section> </section>
<mat-divider></mat-divider> <mat-divider></mat-divider>
<section style="min-height: 100px; overflow: auto"> <div *ngIf="(notifications$ | async).length; else emptyNotification">
<div *ngFor="let notification of (notifications$ | async); let last = last"> <section style="min-height: 100px; overflow: auto">
<tb-notification [notification]="notification" <div *ngFor="let notification of (notifications$ | async); let last = last">
[onClose]="onClose" <tb-notification [notification]="notification"
(markAsRead)="markAsRead($event)"> [onClose]="onClose"
</tb-notification> (markAsRead)="markAsRead($event)">
<mat-divider *ngIf="!last" style="margin-bottom: 4px"></mat-divider> </tb-notification>
</div> <mat-divider *ngIf="!last" style="margin-bottom: 4px"></mat-divider>
</section> </div>
<div *ngIf="(notifications$ | async).length"> </section>
<mat-divider></mat-divider> <mat-divider></mat-divider>
<section fxLayoutAlign="center center"> <section fxLayoutAlign="center center">
<button fxFlex mat-button color="primary" (click)="viewAll($event)"> <button fxFlex mat-button color="primary" (click)="viewAll($event)">
@ -41,3 +41,7 @@
</button> </button>
</section> </section>
</div> </div>
<ng-template #emptyNotification>
<img src="assets/notification-bell.svg" alt="empty notification" style="margin: 20px 24%">
<span style="text-align: center; margin-bottom: 12px" translate>notification.no-notifications-yet</span>
</ng-template>

View File

@ -56,11 +56,7 @@ export class ShowNotificationPopoverComponent extends PageComponent implements O
this.notifications$ = this.notificationSubscriber.notifications$.pipe( this.notifications$ = this.notificationSubscriber.notifications$.pipe(
publishReplay(1), publishReplay(1),
refCount(), refCount(),
tap(() => { tap(() => setTimeout(() => this.cd.markForCheck()))
setTimeout(() => {
this.cd.markForCheck();
});
})
); );
this.notificationSubscriber.subscribe(); this.notificationSubscriber.subscribe();
} }

View File

@ -39,6 +39,7 @@
<form [formGroup]="notificationRequestForm" style="padding-bottom: 16px;"> <form [formGroup]="notificationRequestForm" style="padding-bottom: 16px;">
<tb-template-autocomplete <tb-template-autocomplete
required required
[notificationTypes]="notificationType.GENERAL"
formControlName="templateId"> formControlName="templateId">
</tb-template-autocomplete> </tb-template-autocomplete>
<tb-entity-list <tb-entity-list

View File

@ -14,7 +14,7 @@
/// limitations under the License. /// limitations under the License.
/// ///
import { NotificationRequest, NotificationRequestPreview } from '@shared/models/notification.models'; import { NotificationRequest, NotificationRequestPreview, NotificationType } from '@shared/models/notification.models';
import { Component, Inject, OnDestroy, ViewChild } from '@angular/core'; import { Component, Inject, OnDestroy, ViewChild } from '@angular/core';
import { DialogComponent } from '@shared/components/dialog.component'; import { DialogComponent } from '@shared/components/dialog.component';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
@ -49,6 +49,7 @@ export class RequestNotificationDialogComponent extends
stepperOrientation: Observable<StepperOrientation>; stepperOrientation: Observable<StepperOrientation>;
isAdd = true; isAdd = true;
entityType = EntityType; entityType = EntityType;
notificationType = NotificationType;
notificationRequestForm: FormGroup; notificationRequestForm: FormGroup;
selectedIndex = 0; selectedIndex = 0;

View File

@ -28,7 +28,11 @@ import { TruncatePipe } from '@shared/pipe/truncate.pipe';
import { PageLink } from '@shared/models/page/page-link'; import { PageLink } from '@shared/models/page/page-link';
import { Direction } from '@shared/models/page/sort-order'; import { Direction } from '@shared/models/page/sort-order';
import { emptyPageData } from '@shared/models/page/page-data'; import { emptyPageData } from '@shared/models/page/page-data';
import { NotificationDeliveryMethodTranslateMap, NotificationTemplate } from '@shared/models/notification.models'; import {
NotificationDeliveryMethodTranslateMap,
NotificationTemplate,
NotificationType
} from '@shared/models/notification.models';
import { NotificationService } from '@core/http/notification.service'; import { NotificationService } from '@core/http/notification.service';
import { isEqual } from '@core/utils'; import { isEqual } from '@core/utils';
@ -65,6 +69,9 @@ export class TemplateAutocompleteComponent implements ControlValueAccessor, OnIn
@Input() @Input()
disabled: boolean; disabled: boolean;
@Input()
notificationTypes: NotificationType;
@ViewChild('templateInput', {static: true}) templateInput: ElementRef; @ViewChild('templateInput', {static: true}) templateInput: ElementRef;
filteredTemplate: Observable<Array<NotificationTemplate>>; filteredTemplate: Observable<Array<NotificationTemplate>>;
@ -187,7 +194,7 @@ export class TemplateAutocompleteComponent implements ControlValueAccessor, OnIn
property: 'name', property: 'name',
direction: Direction.ASC direction: Direction.ASC
}); });
return this.notificationService.getNotificationTemplates(pageLink, {ignoreLoading: true}).pipe( return this.notificationService.getNotificationTemplates(pageLink, this.notificationTypes, {ignoreLoading: true}).pipe(
catchError(() => of(emptyPageData<NotificationTemplate>())), catchError(() => of(emptyPageData<NotificationTemplate>())),
map(pageData => { map(pageData => {
return pageData.data; return pageData.data;

View File

@ -2714,6 +2714,7 @@
"no-inbox-notification": "No notification found", "no-inbox-notification": "No notification found",
"no-notification-request": "No notification request", "no-notification-request": "No notification request",
"no-notification-templates": "No notification templates", "no-notification-templates": "No notification templates",
"no-notifications-yet": "No notifications yet",
"no-targets-notification": "No targets notification", "no-targets-notification": "No targets notification",
"notification": "Notification", "notification": "Notification",
"notification-center": "Notification center", "notification-center": "Notification center",

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="234" height="245" fill="none"><rect width="100%" height="100%"/><mask id="a" fill="#fff"><path d="M144.998 161.896a18.006 18.006 0 0 1-.561 13.766 17.988 17.988 0 0 1-10.13 9.336 18.001 18.001 0 0 1-23.102-10.691l16.897-6.205 16.896-6.206Z"/></mask><g class="currentLayer"><path fill="#fff" d="M0 0h234v245H0z"/><path d="M3.186 131.261a100 100 0 0 1 23.92-91.658l6.805-7.324C71.513-8.188 134.803-10.502 175.26 27.111l26.547 24.682c44.827 41.677 42.031 113.484-5.902 151.548l-24.43 19.4c-57.171 45.4-142.145 16.223-159.366-54.722l-8.922-36.758Z" fill="#F3F7FF"/><circle opacity=".4" cx="195" cy="67" r="6" fill="#6794C7"/><circle opacity=".4" cx="121.5" cy="15.5" r="10.5" fill="#6794C7"/><circle opacity=".4" cx="41" cy="73" r="9" fill="#6794C7"/><circle opacity=".4" cx="116.5" cy="47.5" r="2.5" fill="#6794C7"/><circle opacity=".4" cx="196.5" cy="179.5" r="3.5" fill="#6794C7"/><circle opacity=".4" cx="102.5" cy="185.5" r="3.5" fill="#6794C7"/><circle opacity=".4" cx="28" cy="150" r="6" fill="#6794C7"/><path d="M144.998 161.896a18.006 18.006 0 0 1-.561 13.766 17.988 17.988 0 0 1-10.13 9.336 18.001 18.001 0 0 1-23.102-10.691l16.897-6.205 16.896-6.206Z" fill="#fff" stroke="#6794C7" stroke-width="6" mask="url(#a)"/><ellipse opacity=".4" cx="113" cy="202" rx="70" ry="5" fill="#6794C7"/><path d="m76.238 66.355.9-.666-.383-1.052-.705-1.938a12.722 12.722 0 0 1 23.91-8.703l.705 1.938.383 1.053 1.118-.069c21.32-1.302 40.916 11.6 48.23 31.693l12.326 33.866a17.494 17.494 0 0 0 9.049 9.875l11.659 5.437 1.707 4.689L67.675 185.23l-1.706-4.688 5.436-11.66a17.5 17.5 0 0 0 .585-13.381l-12.327-33.866c-7.313-20.093-.595-42.573 16.575-55.28Z" fill="#fff" stroke="#6794C7" stroke-width="3"/></g></svg>

After

Width:  |  Height:  |  Size: 1.7 KiB