mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-05-12 17:04:57 +00:00
[AAE-4529] Refactor Notification History Component (#6620)
* [AAE-4529] Refactor Notification History Component * Improve code * Add maxNotifications * More changes * Add documentation * Rebase branch * Fix build * Update notification-history.component.md * Fix e2e tests Co-authored-by: Eugenio Romano <eromano@users.noreply.github.com>
This commit is contained in:
parent
7c1efe48c4
commit
94ec7d06a7
@ -26,3 +26,8 @@ The main purpose of the [Notification history component](../../core/components/n
|
||||
| --- | --- | --- | --- |
|
||||
| menuPositionX | `string` | "after" | Custom choice for opening the menu at the bottom. Can be `before` or `after`. |
|
||||
| menuPositionY | `string` | "below" | Custom choice for opening the menu at the bottom. Can be `above` or `below`. |
|
||||
| maxNotifications | `number` | 5 | Maximum number of notifications to display. The rest will remain hidden until load more is clicked. |
|
||||
|
||||
## See also
|
||||
|
||||
* [Notification Service](../../core/services/notification.service.md)
|
||||
|
@ -120,3 +120,12 @@ You can also change the default 5000 ms adding the following configuration in th
|
||||
```json
|
||||
"notificationDefaultDuration" : "7000"
|
||||
```
|
||||
|
||||
#### Notification types
|
||||
|
||||
| Name | Description |
|
||||
| --- | --- |
|
||||
| info | To notify messages. It will be displayed with an info icon next to it. |
|
||||
| warn | To notify warning messages. It will be displayed with a warning icon next to it. |
|
||||
| error | To notify errors. It will be displayed with an error icon next to it. |
|
||||
| recursive | To notify recursive messages. If a message is prompt to duplicate an existing notification and you don't want to overload the notification history component with the same message use the recursive type. I.e. notifications coming from an API call that are triggered every time a component is initialized. It will be displayed with an info icon next to it. |
|
||||
|
@ -6,10 +6,11 @@
|
||||
"UNCLAIM": "RELEASE",
|
||||
"START PROCESS": "START PROCESS",
|
||||
"NOTIFICATIONS": {
|
||||
"NO_MESSAGE": "No messages",
|
||||
"NO_MESSAGE": "You have no notifications at this time.",
|
||||
"TITLE": "Notifications",
|
||||
"MARK_AS_READ": "Mark all as read",
|
||||
"SYSTEM": "System"
|
||||
"SYSTEM": "System",
|
||||
"LOAD_MORE": "Load more"
|
||||
},
|
||||
"FORM": {
|
||||
"START_FORM": {
|
||||
|
@ -43,6 +43,7 @@ import { MatTableModule } from '@angular/material/table';
|
||||
import { MatTabsModule } from '@angular/material/tabs';
|
||||
import { MatToolbarModule } from '@angular/material/toolbar';
|
||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
import { MatBadgeModule } from '@angular/material/badge';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
@ -51,7 +52,7 @@ import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
MatInputModule, MatListModule, MatNativeDateModule, MatOptionModule, MatProgressSpinnerModule, MatRadioModule,
|
||||
MatRippleModule, MatSelectModule, MatSlideToggleModule, MatTableModule, MatTabsModule,
|
||||
MatMenuModule, MatProgressBarModule, MatSidenavModule, MatSnackBarModule, MatToolbarModule,
|
||||
MatTooltipModule, MatDatetimepickerModule, MatNativeDatetimeModule, MatExpansionModule
|
||||
MatTooltipModule, MatDatetimepickerModule, MatNativeDatetimeModule, MatExpansionModule, MatBadgeModule
|
||||
],
|
||||
exports: [
|
||||
MatAutocompleteModule, MatButtonModule, MatCardModule, MatCheckboxModule,
|
||||
@ -59,7 +60,7 @@ import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
MatInputModule, MatListModule, MatNativeDateModule, MatOptionModule, MatProgressSpinnerModule, MatRadioModule,
|
||||
MatRippleModule, MatSelectModule, MatSlideToggleModule, MatTableModule, MatTabsModule,
|
||||
MatMenuModule, MatProgressBarModule, MatSidenavModule, MatSnackBarModule, MatToolbarModule,
|
||||
MatTooltipModule, MatDatetimepickerModule, MatNativeDatetimeModule, MatExpansionModule
|
||||
MatTooltipModule, MatDatetimepickerModule, MatNativeDatetimeModule, MatExpansionModule, MatBadgeModule
|
||||
]
|
||||
})
|
||||
export class MaterialModule {}
|
||||
|
@ -1,34 +1,73 @@
|
||||
<div (keyup)="onKeyPress($event)">
|
||||
<button mat-button [matMenuTriggerFor]="menu" class="adf-notification-history-menu_button"
|
||||
id="adf-notification-history-open-button">
|
||||
<mat-icon>mail_outline</mat-icon>
|
||||
<button mat-button
|
||||
[matMenuTriggerFor]="menu"
|
||||
class="adf-notification-history-menu_button"
|
||||
id="adf-notification-history-open-button"
|
||||
(menuOpened)="onMenuOpened()">
|
||||
<mat-icon matBadge="⁠"
|
||||
[matBadgeHidden]="!notifications.length"
|
||||
matBadgeColor="accent"
|
||||
matBadgeSize="small">notifications</mat-icon>
|
||||
</button>
|
||||
<mat-menu #menu="matMenu" [xPosition]="menuPositionX" [yPosition]="menuPositionY"
|
||||
[overlapTrigger]="false" id="adf-notification-history-menu" class="adf-notification-history-menu">
|
||||
<mat-menu #menu="matMenu"
|
||||
[xPosition]="menuPositionX"
|
||||
[yPosition]="menuPositionY"
|
||||
id="adf-notification-history-menu"
|
||||
class="adf-notification-history-menu">
|
||||
|
||||
<div class="adf-notification-history-list"
|
||||
(click)="$event.stopPropagation()">
|
||||
<div mat-subheader>
|
||||
<span>{{ 'NOTIFICATIONS.TITLE' | translate }}</span>
|
||||
<button (click)="markAsRead()"
|
||||
id="adf-notification-history-mark-as-read"
|
||||
mat-button
|
||||
color="accent"
|
||||
*ngIf="notifications.length">
|
||||
{{ 'NOTIFICATIONS.MARK_AS_READ' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div id="adf-notification-history-list">
|
||||
<mat-list>
|
||||
<mat-list-item>
|
||||
<h6 mat-line>{{ 'NOTIFICATIONS.TITLE' | translate }}</h6>
|
||||
</mat-list-item>
|
||||
</mat-list>
|
||||
<mat-divider></mat-divider>
|
||||
|
||||
<mat-list>
|
||||
<mat-list-item *ngFor="let notification of notifications">
|
||||
<mat-icon mat-list-icon>{{ notification | noticicationIcon }}</mat-icon>
|
||||
<h4 *ngFor="let message of notification.messages" mat-line>{{ message }}</h4>
|
||||
<p mat-line> {{notification.datetime | date}} </p>
|
||||
<p mat-line> {{notification.initiator.displayName | translate}} </p>
|
||||
</mat-list-item>
|
||||
<mat-list-item *ngIf="isEmptyNotification()" id="adf-notification-history-component-no-message">
|
||||
<h4 mat-line>{{ 'NOTIFICATIONS.NO_MESSAGE' | translate }}</h4>
|
||||
</mat-list-item>
|
||||
<mat-action-list *ngIf="!isEmptyNotification()" id="adf-notification-history-mark-as-read">
|
||||
<button mat-list-item (click)="markAsRead()">{{ 'NOTIFICATIONS.MARK_AS_READ' | translate }}
|
||||
</button>
|
||||
</mat-action-list>
|
||||
<ng-container *ngIf="notifications.length; else empty_list_template">
|
||||
<mat-list-item *ngFor="let notification of paginatedNotifications"
|
||||
class="adf-notification-history-menu-item"
|
||||
(click)="onNotificationClick(notification)">
|
||||
<div *ngIf="notification.initiator; else no_avatar"
|
||||
matListAvatar
|
||||
[outerHTML]="notification.initiator | usernameInitials:'adf-notification-initiator-pic'">
|
||||
</div>
|
||||
<ng-template #no_avatar>
|
||||
<mat-icon mat-list-icon
|
||||
class="adf-notification-history-menu-initiator">{{ notification | notificationIcon
|
||||
}}</mat-icon>
|
||||
</ng-template>
|
||||
<p class="adf-notification-history-menu-message"
|
||||
*ngFor="let message of notification.messages"
|
||||
mat-line>{{ message }}</p>
|
||||
<p class="adf-notification-history-menu-date"
|
||||
mat-line> {{notification.datetime | adfTimeAgo}} </p>
|
||||
</mat-list-item>
|
||||
</ng-container>
|
||||
<ng-template #empty_list_template>
|
||||
<mat-list-item id="adf-notification-history-component-no-message"
|
||||
class="adf-notification-history-menu-no-message">
|
||||
<h4 mat-line>{{ 'NOTIFICATIONS.NO_MESSAGE' | translate }}</h4>
|
||||
</mat-list-item>
|
||||
</ng-template>
|
||||
</mat-list>
|
||||
|
||||
<mat-divider></mat-divider>
|
||||
|
||||
<div class="adf-notification-history-load-more"
|
||||
*ngIf="hasMoreNotifications()">
|
||||
<button mat-button
|
||||
(click)="loadMore()">
|
||||
{{ 'NOTIFICATIONS.LOAD_MORE' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</mat-menu>
|
||||
</div>
|
||||
|
@ -1,23 +1,76 @@
|
||||
.adf {
|
||||
@mixin adf-notification-history-theme($theme) {
|
||||
$background: map-get($theme, background);
|
||||
$accent: map-get($theme, accent);
|
||||
|
||||
&-notification-history-menu_button.mat-button {
|
||||
margin-right: 0;
|
||||
border-radius: 90%;
|
||||
padding: 0;
|
||||
min-width: 40px;
|
||||
height: 40px;
|
||||
.adf {
|
||||
&-notification-history-menu_button.mat-button {
|
||||
margin-right: 0;
|
||||
border-radius: 90%;
|
||||
padding: 0;
|
||||
min-width: 40px;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
&-notification-history-list .mat-subheader {
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
&-notification-history-menu {
|
||||
&-item {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&-item:focus {
|
||||
outline: none;
|
||||
background: mat-color($background, 'hover');
|
||||
}
|
||||
|
||||
&-item:hover {
|
||||
background-color: mat-color($background, 'hover');
|
||||
}
|
||||
|
||||
&-message, &-no-message {
|
||||
font-size: 13px !important;
|
||||
}
|
||||
|
||||
&-date {
|
||||
font-size: 12px !important;
|
||||
}
|
||||
|
||||
&-initiator {
|
||||
margin: 4px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
&-notification-initiator-pic {
|
||||
min-width: 40px;
|
||||
background: mat-color($accent);
|
||||
display: inline-block;
|
||||
height: 40px;
|
||||
border-radius: 100px;
|
||||
text-align: center;
|
||||
font-weight: bolder;
|
||||
font-size: 18px;
|
||||
text-transform: uppercase;
|
||||
vertical-align: middle;
|
||||
line-height: 40px;
|
||||
color: mat-color($mat-grey, 50);
|
||||
}
|
||||
|
||||
&-notification-history-load-more {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (min-device-width: 480px) {
|
||||
.mat-menu-panel.adf-notification-history-menu {
|
||||
max-height: 450px;
|
||||
min-width: 450px;
|
||||
overflow: auto;
|
||||
padding: 0;
|
||||
min-width: 320px;
|
||||
max-height: 500px;
|
||||
|
||||
.mat-menu-content {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.mat-menu-panel.adf-notification-history-menu .mat-menu-content {
|
||||
padding: 0;
|
||||
}
|
||||
|
@ -23,10 +23,12 @@ import { OverlayContainer } from '@angular/cdk/overlay';
|
||||
import { NotificationService } from '../services/notification.service';
|
||||
import { StorageService } from '../../services/storage.service';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { NotificationModel, NOTIFICATION_TYPE } from '../models/notification.model';
|
||||
|
||||
describe('Notification History Component', () => {
|
||||
|
||||
let fixture: ComponentFixture<NotificationHistoryComponent>;
|
||||
let component: NotificationHistoryComponent;
|
||||
let element: HTMLElement;
|
||||
let notificationService: NotificationService;
|
||||
let overlayContainerElement: HTMLElement;
|
||||
@ -48,10 +50,12 @@ describe('Notification History Component', () => {
|
||||
|
||||
beforeEach(async(() => {
|
||||
fixture = TestBed.createComponent(NotificationHistoryComponent);
|
||||
component = fixture.componentInstance;
|
||||
element = fixture.nativeElement;
|
||||
|
||||
storage = TestBed.inject(StorageService);
|
||||
notificationService = TestBed.inject(NotificationService);
|
||||
component.notifications = [];
|
||||
}));
|
||||
|
||||
beforeEach(inject([OverlayContainer], (oc: OverlayContainer) => {
|
||||
@ -59,6 +63,7 @@ describe('Notification History Component', () => {
|
||||
}));
|
||||
|
||||
afterEach(() => {
|
||||
storage.removeItem('notifications');
|
||||
fixture.destroy();
|
||||
});
|
||||
|
||||
@ -73,27 +78,110 @@ describe('Notification History Component', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('should message be present and empty message not be present when there are notifications in the history', (done) => {
|
||||
it('should remove notification when mark all as read is clicked', (done) => {
|
||||
fixture.detectChanges();
|
||||
notificationService.showInfo('Example Message Removed');
|
||||
openNotification();
|
||||
fixture.detectChanges();
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
expect(component.notifications.length).toBe(1);
|
||||
const markAllAsRead = <HTMLButtonElement> overlayContainerElement.querySelector('#adf-notification-history-mark-as-read');
|
||||
markAllAsRead.click();
|
||||
fixture.detectChanges();
|
||||
expect(storage.getItem('notifications')).toBeNull();
|
||||
expect(component.notifications.length).toBe(0);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should message be present and empty message not be present when there are notifications in the history', (done) => {
|
||||
fixture.detectChanges();
|
||||
notificationService.showInfo('Example Message');
|
||||
openNotification();
|
||||
fixture.detectChanges();
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
expect(overlayContainerElement.querySelector('#adf-notification-history-component-no-message')).toBeNull();
|
||||
expect(overlayContainerElement.querySelector('#adf-notification-history-list').innerHTML).toContain('Example Message');
|
||||
expect(overlayContainerElement.querySelector('.adf-notification-history-list').innerHTML).toContain('Example Message');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should remove notification from storage when mark all as read', (done) => {
|
||||
it('should show message when pushed directly to Notification History', (done) => {
|
||||
const callBackSpy = jasmine.createSpy('callBack');
|
||||
fixture.detectChanges();
|
||||
notificationService.pushToNotificationHistory(
|
||||
{
|
||||
clickCallBack: callBackSpy,
|
||||
messages: ['My new message'],
|
||||
datetime: new Date(),
|
||||
type: NOTIFICATION_TYPE.RECURSIVE
|
||||
|
||||
} as NotificationModel
|
||||
);
|
||||
openNotification();
|
||||
fixture.detectChanges();
|
||||
fixture.whenStable().then(() => {
|
||||
const markAllAsRead = <HTMLButtonElement> overlayContainerElement.querySelector('#adf-notification-history-mark-as-read button');
|
||||
markAllAsRead.click();
|
||||
fixture.detectChanges();
|
||||
expect(storage.getItem('notifications')).toBeNull();
|
||||
const notification = <HTMLButtonElement> overlayContainerElement.querySelector('.adf-notification-history-menu-item');
|
||||
notification.click();
|
||||
expect(callBackSpy).toHaveBeenCalled();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should show load more button when there are more notifications', (done) => {
|
||||
fixture.detectChanges();
|
||||
notificationService.showInfo('Example Message 1');
|
||||
notificationService.showInfo('Example Message 2');
|
||||
notificationService.showInfo('Example Message 3');
|
||||
notificationService.showInfo('Example Message 4');
|
||||
notificationService.showInfo('Example Message 5');
|
||||
notificationService.showInfo('Example Message 6');
|
||||
openNotification();
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
const loadMoreButton = <HTMLButtonElement> overlayContainerElement.querySelector('.adf-notification-history-load-more');
|
||||
expect(component.paginatedNotifications.length).toBe(5);
|
||||
expect(loadMoreButton).toBeDefined();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should read notifications from local storage', (done) => {
|
||||
storage.setItem('notifications', JSON.stringify([{
|
||||
messages: ['My new message'],
|
||||
datetime: new Date(),
|
||||
type: NOTIFICATION_TYPE.RECURSIVE
|
||||
|
||||
} as NotificationModel]));
|
||||
fixture.detectChanges();
|
||||
openNotification();
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
const notification = <HTMLButtonElement> overlayContainerElement.querySelector('.adf-notification-history-menu-item');
|
||||
expect(notification).toBeDefined();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should be able to change the maximum number of notifications displayed', (done) => {
|
||||
component.maxNotifications = 10;
|
||||
fixture.detectChanges();
|
||||
notificationService.showInfo('Example Message 1');
|
||||
notificationService.showInfo('Example Message 2');
|
||||
notificationService.showInfo('Example Message 3');
|
||||
notificationService.showInfo('Example Message 4');
|
||||
notificationService.showInfo('Example Message 5');
|
||||
notificationService.showInfo('Example Message 6');
|
||||
openNotification();
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
const notifications = overlayContainerElement.querySelectorAll('.adf-notification-history-menu-item');
|
||||
expect(notifications.length).toBe(6);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -15,26 +15,23 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Component, Input, ViewChild, OnDestroy } from '@angular/core';
|
||||
import { Component, Input, ViewChild, OnDestroy, OnInit, AfterViewInit, ChangeDetectorRef } from '@angular/core';
|
||||
import { NotificationService } from '../services/notification.service';
|
||||
import { NotificationModel } from '../models/notification.model';
|
||||
import { NotificationModel, NOTIFICATION_TYPE } from '../models/notification.model';
|
||||
import { MatMenuTrigger } from '@angular/material/menu';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
import { Subject } from 'rxjs';
|
||||
import { StorageService } from '../../services/storage.service';
|
||||
import { Pagination } from '@alfresco/js-api';
|
||||
|
||||
@Component({
|
||||
selector: 'adf-notification-history',
|
||||
styleUrls: ['notification-history.component.scss'],
|
||||
templateUrl: 'notification-history.component.html'
|
||||
})
|
||||
export class NotificationHistoryComponent implements OnDestroy {
|
||||
export class NotificationHistoryComponent implements OnDestroy, OnInit, AfterViewInit {
|
||||
|
||||
onDestroy$ = new Subject<boolean>();
|
||||
|
||||
notifications: NotificationModel[] = [];
|
||||
|
||||
MAX_NOTIFICATION_STACK_LENGTH = 100;
|
||||
public static MAX_NOTIFICATION_STACK_LENGTH = 100;
|
||||
|
||||
@ViewChild(MatMenuTrigger, { static: true })
|
||||
trigger: MatMenuTrigger;
|
||||
@ -47,33 +44,33 @@ export class NotificationHistoryComponent implements OnDestroy {
|
||||
@Input()
|
||||
menuPositionY: string = 'below';
|
||||
|
||||
/** Maximum number of notifications to display. The rest will remain hidden until load more is clicked */
|
||||
@Input()
|
||||
maxNotifications: number = 5;
|
||||
|
||||
onDestroy$ = new Subject<boolean>();
|
||||
notifications: NotificationModel[] = [];
|
||||
paginatedNotifications = [];
|
||||
pagination: Pagination;
|
||||
|
||||
constructor(
|
||||
private notificationService: NotificationService, public storageService: StorageService) {
|
||||
this.notifications = JSON.parse(storageService.getItem('notifications')) || [];
|
||||
private notificationService: NotificationService,
|
||||
public storageService: StorageService,
|
||||
public cd: ChangeDetectorRef) {
|
||||
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.notifications = JSON.parse(this.storageService.getItem('notifications')) || [];
|
||||
}
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
this.notificationService.notifications$
|
||||
.pipe(takeUntil(this.onDestroy$))
|
||||
.subscribe((message) => {
|
||||
this.notifications.push(message);
|
||||
|
||||
if (this.notifications.length > this.MAX_NOTIFICATION_STACK_LENGTH) {
|
||||
this.notifications.shift();
|
||||
}
|
||||
|
||||
storageService.setItem('notifications', JSON.stringify(this.notifications));
|
||||
});
|
||||
}
|
||||
|
||||
isEmptyNotification(): boolean {
|
||||
return (!this.notifications || this.notifications.length === 0);
|
||||
}
|
||||
|
||||
onKeyPress(event: KeyboardEvent) {
|
||||
this.closeUserModal(event);
|
||||
}
|
||||
|
||||
markAsRead() {
|
||||
this.storageService.removeItem('notifications');
|
||||
this.notifications = [];
|
||||
.pipe(takeUntil(this.onDestroy$))
|
||||
.subscribe((notification: NotificationModel) => {
|
||||
this.addNewNotification(notification);
|
||||
this.cd.detectChanges();
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
@ -81,9 +78,69 @@ export class NotificationHistoryComponent implements OnDestroy {
|
||||
this.onDestroy$.complete();
|
||||
}
|
||||
|
||||
addNewNotification(notification: NotificationModel) {
|
||||
this.notifications.unshift(notification);
|
||||
|
||||
if (this.notifications.length > NotificationHistoryComponent.MAX_NOTIFICATION_STACK_LENGTH) {
|
||||
this.notifications.shift();
|
||||
}
|
||||
|
||||
this.saveNotifications();
|
||||
this.createPagination();
|
||||
}
|
||||
|
||||
saveNotifications() {
|
||||
this.storageService.setItem('notifications', JSON.stringify(this.notifications.filter((notification) =>
|
||||
notification.type !== NOTIFICATION_TYPE.RECURSIVE
|
||||
)));
|
||||
}
|
||||
|
||||
onMenuOpened() {
|
||||
this.createPagination();
|
||||
}
|
||||
|
||||
onKeyPress(event: KeyboardEvent) {
|
||||
this.closeUserModal(event);
|
||||
}
|
||||
|
||||
private closeUserModal($event: KeyboardEvent) {
|
||||
if ($event.keyCode === 27) {
|
||||
this.trigger.closeMenu();
|
||||
}
|
||||
}
|
||||
|
||||
markAsRead() {
|
||||
this.notifications = [];
|
||||
this.paginatedNotifications = [];
|
||||
this.storageService.removeItem('notifications');
|
||||
this.createPagination();
|
||||
this.trigger.closeMenu();
|
||||
}
|
||||
|
||||
createPagination() {
|
||||
this.pagination = {
|
||||
skipCount: this.maxNotifications,
|
||||
maxItems: this.maxNotifications,
|
||||
totalItems: this.notifications.length,
|
||||
hasMoreItems: this.notifications.length > this.maxNotifications
|
||||
};
|
||||
this.paginatedNotifications = this.notifications.slice(0, this.pagination.skipCount);
|
||||
}
|
||||
|
||||
loadMore() {
|
||||
this.pagination.skipCount = this.pagination.maxItems + this.pagination.skipCount;
|
||||
this.pagination.hasMoreItems = this.notifications.length > this.pagination.skipCount;
|
||||
this.paginatedNotifications = this.notifications.slice(0, this.pagination.skipCount);
|
||||
}
|
||||
|
||||
hasMoreNotifications(): boolean {
|
||||
return this.pagination?.hasMoreItems;
|
||||
}
|
||||
|
||||
onNotificationClick(notification: NotificationModel) {
|
||||
if (notification.clickCallBack) {
|
||||
notification.clickCallBack(notification.args);
|
||||
this.trigger.closeMenu();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ import {
|
||||
|
||||
export const rootInitiator: NotificationInitiator = {
|
||||
key: '*',
|
||||
displayName: 'NOTIFICATIONS.SYSTEM'
|
||||
displayName: 'SYSTEM'
|
||||
};
|
||||
|
||||
export function info(messages: string | string[], initiator: NotificationInitiator = rootInitiator): NotificationModel {
|
||||
|
@ -18,12 +18,15 @@
|
||||
export enum NOTIFICATION_TYPE {
|
||||
INFO = 'info',
|
||||
WARN = 'warning',
|
||||
ERROR = 'error'
|
||||
ERROR = 'error',
|
||||
RECURSIVE = 'recursive'
|
||||
}
|
||||
|
||||
export interface NotificationInitiator {
|
||||
key: string | Symbol;
|
||||
displayName: string;
|
||||
firstName?: string;
|
||||
lastName?: string;
|
||||
extra?: any;
|
||||
}
|
||||
|
||||
@ -32,4 +35,7 @@ export interface NotificationModel {
|
||||
initiator: NotificationInitiator;
|
||||
datetime: Date;
|
||||
messages: string[];
|
||||
icon?: string;
|
||||
clickCallBack?: any;
|
||||
args?: any;
|
||||
}
|
||||
|
@ -18,16 +18,19 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { MaterialModule } from '../material.module';
|
||||
|
||||
import { PipeModule } from './../pipes/pipe.module';
|
||||
import { NotificationHistoryComponent } from './components/notification-history.component';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { NotificationIconPipe } from './pipes/notification-icon.pipe';
|
||||
import { PaginationModule } from './../pagination/pagination.module';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
MaterialModule,
|
||||
TranslateModule
|
||||
TranslateModule,
|
||||
PipeModule,
|
||||
PaginationModule
|
||||
],
|
||||
declarations: [
|
||||
NotificationHistoryComponent,
|
||||
|
@ -19,18 +19,22 @@ import { Pipe, PipeTransform } from '@angular/core';
|
||||
import { NotificationModel, NOTIFICATION_TYPE } from '../models/notification.model';
|
||||
|
||||
@Pipe({
|
||||
name: 'noticicationIcon'
|
||||
name: 'notificationIcon'
|
||||
})
|
||||
export class NotificationIconPipe implements PipeTransform {
|
||||
|
||||
transform(notification: NotificationModel): string {
|
||||
switch (notification.type) {
|
||||
case NOTIFICATION_TYPE.ERROR:
|
||||
return 'error';
|
||||
case NOTIFICATION_TYPE.WARN:
|
||||
return 'warning';
|
||||
default:
|
||||
return 'info';
|
||||
if (notification.icon) {
|
||||
return notification.icon;
|
||||
} else {
|
||||
switch (notification.type) {
|
||||
case NOTIFICATION_TYPE.ERROR:
|
||||
return 'error';
|
||||
case NOTIFICATION_TYPE.WARN:
|
||||
return 'warning';
|
||||
default:
|
||||
return 'info';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -102,6 +102,14 @@ export class NotificationService {
|
||||
return this.snackBar.dismiss();
|
||||
}
|
||||
|
||||
/**
|
||||
* Push new notification to Notification History
|
||||
* @param notification - Notification model to be pushed.
|
||||
*/
|
||||
pushToNotificationHistory(notification: NotificationModel) {
|
||||
this.notifications$.next(notification);
|
||||
}
|
||||
|
||||
private dispatchNotification(message: string, action?: string, config?: number | MatSnackBarConfig, interpolateArgs?: any): MatSnackBarRef<any> {
|
||||
const translatedMessage: string = this.translationService.instant(message, interpolateArgs);
|
||||
const translatedAction: string = this.translationService.instant(action, interpolateArgs);
|
||||
|
@ -38,6 +38,7 @@
|
||||
@import '../../core/search-text/search-text-input.component';
|
||||
@import './snackbar';
|
||||
@import '../directives/tooltip-card/tooltip-card.component';
|
||||
@import '../notifications/components/notification-history.component';
|
||||
|
||||
@mixin adf-core-theme($theme) {
|
||||
@include adf-colors-theme($theme);
|
||||
@ -81,4 +82,5 @@
|
||||
@include mat-datetimepicker-theme--fix($theme);
|
||||
@include adf-search-text-input-theme($theme);
|
||||
@include adf-tooltip-card-directive($theme);
|
||||
@include adf-notification-history-theme($theme);
|
||||
}
|
||||
|
@ -21,14 +21,14 @@ import { BrowserVisibility } from '../utils/browser-visibility';
|
||||
|
||||
export class NotificationHistoryPage {
|
||||
|
||||
notificationList = element(by.css('#adf-notification-history-list'));
|
||||
notificationList = element(by.css('.adf-notification-history-list'));
|
||||
|
||||
async clickNotificationButton(): Promise<void> {
|
||||
await BrowserActions.clickExecuteScript('#adf-notification-history-open-button');
|
||||
}
|
||||
|
||||
async clickMarkAsRead(): Promise<void> {
|
||||
await BrowserActions.click(element(by.css('#adf-notification-history-mark-as-read')));
|
||||
await BrowserActions.click(element(by.id('adf-notification-history-mark-as-read')));
|
||||
}
|
||||
|
||||
async checkNotificationIsPresent(text: string): Promise<void> {
|
||||
|
Loading…
x
Reference in New Issue
Block a user