add in app notification navbar
This commit is contained in:
parent
1f92872158
commit
da657b667b
|
@ -32,7 +32,8 @@ public class TenantScopedEntityManager {
|
||||||
|
|
||||||
public int getBulkSize() {
|
public int getBulkSize() {
|
||||||
Session session = this.entityManager.unwrap(Session.class);
|
Session session = this.entityManager.unwrap(Session.class);
|
||||||
return session.getJdbcBatchSize();
|
if (session.getJdbcBatchSize() != null) return session.getJdbcBatchSize();
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setBulkSize(int size) {
|
public void setBulkSize(int size) {
|
||||||
|
|
|
@ -118,6 +118,11 @@ export class ConfigurationService extends BaseComponent {
|
||||||
return this._notificationServiceEnabled;
|
return this._notificationServiceEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _inAppNotificationsCountInterval: number;
|
||||||
|
get inAppNotificationsCountInterval(): number {
|
||||||
|
return this._inAppNotificationsCountInterval || 3200;
|
||||||
|
}
|
||||||
|
|
||||||
public loadConfiguration(): Promise<any> {
|
public loadConfiguration(): Promise<any> {
|
||||||
return new Promise((r, e) => {
|
return new Promise((r, e) => {
|
||||||
// We need to exclude all interceptors here, for the initial configuration request.
|
// We need to exclude all interceptors here, for the initial configuration request.
|
||||||
|
@ -178,6 +183,7 @@ export class ConfigurationService extends BaseComponent {
|
||||||
this._notificationServiceEnabled = config.notification_service.enabled;
|
this._notificationServiceEnabled = config.notification_service.enabled;
|
||||||
this._notificationServiceAddress = config.notification_service.address;
|
this._notificationServiceAddress = config.notification_service.address;
|
||||||
}
|
}
|
||||||
|
this._inAppNotificationsCountInterval = config.inAppNotificationsCountInterval;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,6 +57,14 @@ export class InAppNotificationService {
|
||||||
catchError((error: any) => throwError(error)));
|
catchError((error: any) => throwError(error)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
readAll(): Observable<string> {
|
||||||
|
const url = `${this.apiBase}/read-all`;
|
||||||
|
|
||||||
|
return this.http
|
||||||
|
.post<string>(url, {}).pipe(
|
||||||
|
catchError((error: any) => throwError(error)));
|
||||||
|
}
|
||||||
|
|
||||||
delete(id: Guid): Observable<InAppNotification> {
|
delete(id: Guid): Observable<InAppNotification> {
|
||||||
const url = `${this.apiBase}/${id}`;
|
const url = `${this.apiBase}/${id}`;
|
||||||
return this.http
|
return this.http
|
||||||
|
|
|
@ -37,7 +37,6 @@ import { CommonFormattingModule } from '@common/formatting/common-formatting.mod
|
||||||
// ],
|
// ],
|
||||||
exports: [
|
exports: [
|
||||||
InAppNotificationListingComponent,
|
InAppNotificationListingComponent,
|
||||||
InAppNotificationListingDialogComponent
|
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class InAppNotificationModule { }
|
export class InAppNotificationModule { }
|
||||||
|
|
|
@ -6,8 +6,12 @@
|
||||||
<span mat-line class="secondary-text">{{ inappNotification.createdAt | date : 'short'}}</span>
|
<span mat-line class="secondary-text">{{ inappNotification.createdAt | date : 'short'}}</span>
|
||||||
<mat-divider inset *ngIf="!last"></mat-divider>
|
<mat-divider inset *ngIf="!last"></mat-divider>
|
||||||
</a>
|
</a>
|
||||||
<mat-list-item *ngIf="authService.hasPermission(authService.permissionEnum.ViewInAppNotificationPage)">
|
<mat-list-item class = "mat-list-item-content" *ngIf="authService.hasPermission(authService.permissionEnum.ViewInAppNotificationPage)">
|
||||||
<a (click)="goToNotifications()">{{'APP.NAVIGATION.ALL-INAPP-NOTIFICATIONS'
|
<a (click)="goToNotifications()">{{'NAV-BAR.INAPP-NOTIFICATIONS'
|
||||||
|
| translate}}</a>
|
||||||
|
</mat-list-item>
|
||||||
|
<mat-list-item class = "mat-list-item-content" *ngIf="authService.hasPermission(authService.permissionEnum.ViewInAppNotificationPage)">
|
||||||
|
<a (click)="readAllNotifications()">{{'NAV-BAR.READ-ALL-INAPP-NOTIFICATIONS'
|
||||||
| translate}}</a>
|
| translate}}</a>
|
||||||
</mat-list-item>
|
</mat-list-item>
|
||||||
</mat-nav-list>
|
</mat-nav-list>
|
||||||
|
|
|
@ -8,4 +8,8 @@
|
||||||
.secondary-text {
|
.secondary-text {
|
||||||
color: rgba(0, 0, 0, 0.54);
|
color: rgba(0, 0, 0, 0.54);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mat-list-item-content {
|
||||||
|
text-align: center
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,4 +85,12 @@ export class InAppNotificationListingDialogComponent extends BaseComponent imple
|
||||||
this.router.navigate(['/inapp-notifications']);
|
this.router.navigate(['/inapp-notifications']);
|
||||||
this.dialogRef.close();
|
this.dialogRef.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
readAllNotifications() {
|
||||||
|
this.inappNotificationService.readAll()
|
||||||
|
.pipe(takeUntil(this._destroyed))
|
||||||
|
.subscribe(
|
||||||
|
data => {},
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<div class="col-md-3 d-flex justify-content-center align-items-center">
|
<div class="col-md-3 d-flex justify-content-center align-items-center">
|
||||||
<mat-slide-toggle [(ngModel)]="isActive" class="toggle col-auto w-100">
|
<mat-slide-toggle [(ngModel)]="isActive" class="toggle col-auto w-100">
|
||||||
{{'NOTIFICATION-SERVICE.INAPP-NOTIFICATION-LISTING.FILTER.SHOW-INACTIVE' | translate}}
|
{{'NOTIFICATION-SERVICE.INAPP-NOTIFICATION-LISTING.FILTER.IS-ACTIVE' | translate}}
|
||||||
</mat-slide-toggle>
|
</mat-slide-toggle>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -60,7 +60,14 @@ export class InAppNotificationListingFiltersComponent extends BaseComponent impl
|
||||||
return this.filter.trackingState ? this.filter.trackingState : null;
|
return this.filter.trackingState ? this.filter.trackingState : null;
|
||||||
}
|
}
|
||||||
set trackingState(value: NotificationInAppTracking[]) {
|
set trackingState(value: NotificationInAppTracking[]) {
|
||||||
this.filter.trackingState = value && value.length > 0 ? value : null;
|
// this.filter.trackingState = value && value.length > 0 ? value : null;
|
||||||
|
if (value[0] == 0){
|
||||||
|
this.filter.trackingState = [NotificationInAppTracking.Stored];
|
||||||
|
} else if(value[0] == 1) {
|
||||||
|
this.filter.trackingState = [NotificationInAppTracking.Delivered];
|
||||||
|
} else {
|
||||||
|
this.filter.trackingState = null;
|
||||||
|
}
|
||||||
this.filterChange.emit(this.filter);
|
this.filterChange.emit(this.filter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,16 +78,16 @@ export class InAppNotificationListingComponent extends BaseListingComponent<InAp
|
||||||
}, {
|
}, {
|
||||||
prop: nameof<InAppNotification>(x => x.subject),
|
prop: nameof<InAppNotification>(x => x.subject),
|
||||||
sortable: true,
|
sortable: true,
|
||||||
languageName: 'INAPP-NOTIFICATION-LISTING.FIELDS.SUBJECT'
|
languageName: 'NOTIFICATION-SERVICE.INAPP-NOTIFICATION-LISTING.FIELDS.SUBJECT'
|
||||||
}, {
|
}, {
|
||||||
prop: nameof<InAppNotification>(x => x.trackingState),
|
prop: nameof<InAppNotification>(x => x.trackingState),
|
||||||
sortable: true,
|
sortable: true,
|
||||||
languageName: 'INAPP-NOTIFICATION-LISTING.FIELDS.TRACKING-STATE',
|
languageName: 'NOTIFICATION-SERVICE.INAPP-NOTIFICATION-LISTING.FIELDS.TRACKING-STATE',
|
||||||
pipe: this.pipeService.getPipe<NotificationInAppTrackingTypePipe>(NotificationInAppTrackingTypePipe)
|
pipe: this.pipeService.getPipe<NotificationInAppTrackingTypePipe>(NotificationInAppTrackingTypePipe)
|
||||||
}, {
|
}, {
|
||||||
prop: nameof<InAppNotification>(x => x.createdAt),
|
prop: nameof<InAppNotification>(x => x.createdAt),
|
||||||
sortable: true,
|
sortable: true,
|
||||||
languageName: 'INAPP-NOTIFICATION-LISTING.FIELDS.CREATED-AT',
|
languageName: 'NOTIFICATION-SERVICE.INAPP-NOTIFICATION-LISTING.FIELDS.CREATED-AT',
|
||||||
pipe: this.pipeService.getPipe<DataTableDateTimeFormatPipe>(DataTableDateTimeFormatPipe).withFormat('short')
|
pipe: this.pipeService.getPipe<DataTableDateTimeFormatPipe>(DataTableDateTimeFormatPipe).withFormat('short')
|
||||||
}]);
|
}]);
|
||||||
}
|
}
|
||||||
|
@ -105,6 +105,7 @@ export class InAppNotificationListingComponent extends BaseListingComponent<InAp
|
||||||
}
|
}
|
||||||
|
|
||||||
protected loadListing() : Observable<QueryResult<InAppNotification>> {
|
protected loadListing() : Observable<QueryResult<InAppNotification>> {
|
||||||
|
console.log(this.lookup);
|
||||||
return this.inappNotificationService.query(this.lookup);
|
return this.inappNotificationService.query(this.lookup);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,11 @@
|
||||||
<app-language (languageChange)="getLanguage($event)"></app-language>
|
<app-language (languageChange)="getLanguage($event)"></app-language>
|
||||||
</mat-menu>
|
</mat-menu>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-auto" *ngIf="isAuthenticated() && authentication.hasPermission(authentication.permissionEnum.ViewInAppNotificationPage)">
|
||||||
|
<button class="col-auto" mat-icon-button matTooltip="{{'NAV-BAR.INAPP-NOTIFICATIONS' | translate}}" (click)="toggleInAppNotifications()">
|
||||||
|
<mat-icon [matBadge]="inAppNotificationCount" [matBadgeHidden]="inAppNotificationCount <= 0" matBadgeColor="warn">mail</mat-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- <app-search></app-search> -->
|
<!-- <app-search></app-search> -->
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { Location } from '@angular/common';
|
import { Location } from '@angular/common';
|
||||||
import { Component, ElementRef, EventEmitter, OnInit, Output, ViewChild } from '@angular/core';
|
import { Component, ElementRef, EventEmitter, OnInit, Output, ViewChild } from '@angular/core';
|
||||||
import { MatDialog } from '@angular/material/dialog';
|
import { MatDialog, MatDialogRef } from '@angular/material/dialog';
|
||||||
import { MatMenuTrigger } from '@angular/material/menu';
|
import { MatMenuTrigger } from '@angular/material/menu';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import { AppRole } from '@app/core/common/enum/app-role';
|
import { AppRole } from '@app/core/common/enum/app-role';
|
||||||
|
@ -16,6 +16,10 @@ import { StartNewDmpDialogComponent } from '../dmp/new/start-new-dmp-dialogue/st
|
||||||
import { FaqDialogComponent } from '../faq/dialog/faq-dialog.component';
|
import { FaqDialogComponent } from '../faq/dialog/faq-dialog.component';
|
||||||
import { UserDialogComponent } from './user-dialog/user-dialog.component';
|
import { UserDialogComponent } from './user-dialog/user-dialog.component';
|
||||||
import { DATASETS_ROUTES, DMP_ROUTES, GENERAL_ROUTES } from '../sidebar/sidebar.component';
|
import { DATASETS_ROUTES, DMP_ROUTES, GENERAL_ROUTES } from '../sidebar/sidebar.component';
|
||||||
|
import { InAppNotificationListingDialogComponent } from '../inapp-notification/listing-dialog/inapp-notification-listing-dialog.component';
|
||||||
|
import { InAppNotificationService } from '@app/core/services/inapp-notification/inapp-notification.service';
|
||||||
|
import { timer } from 'rxjs';
|
||||||
|
import { ConfigurationService } from '@app/core/services/configuration/configuration.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-navbar',
|
selector: 'app-navbar',
|
||||||
|
@ -33,18 +37,22 @@ export class NavbarComponent extends BaseComponent implements OnInit {
|
||||||
currentRoute: string;
|
currentRoute: string;
|
||||||
selectedLanguage: string;
|
selectedLanguage: string;
|
||||||
private user: User;
|
private user: User;
|
||||||
|
inAppNotificationDialog: MatDialogRef<InAppNotificationListingDialogComponent> = null;
|
||||||
|
inAppNotificationCount = 0;
|
||||||
@Output() sidebarToggled: EventEmitter<any> = new EventEmitter();
|
@Output() sidebarToggled: EventEmitter<any> = new EventEmitter();
|
||||||
@ViewChild(MatMenuTrigger) trigger: MatMenuTrigger;
|
@ViewChild(MatMenuTrigger) trigger: MatMenuTrigger;
|
||||||
|
|
||||||
constructor(location: Location,
|
constructor(location: Location,
|
||||||
private element: ElementRef,
|
private element: ElementRef,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
private authentication: AuthService,
|
public authentication: AuthService,
|
||||||
private dialog: MatDialog,
|
private dialog: MatDialog,
|
||||||
private progressIndicationService: ProgressIndicationService,
|
private progressIndicationService: ProgressIndicationService,
|
||||||
private languageService: LanguageService,
|
private languageService: LanguageService,
|
||||||
private matomoService: MatomoService,
|
private matomoService: MatomoService,
|
||||||
private sidenavService: SideNavService,
|
private sidenavService: SideNavService,
|
||||||
|
private inappNotificationService: InAppNotificationService,
|
||||||
|
private configurationService: ConfigurationService
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
this.location = location;
|
this.location = location;
|
||||||
|
@ -75,6 +83,23 @@ export class NavbarComponent extends BaseComponent implements OnInit {
|
||||||
this.progressIndicationService.getProgressIndicationObservable().pipe(takeUntil(this._destroyed)).subscribe(x => {
|
this.progressIndicationService.getProgressIndicationObservable().pipe(takeUntil(this._destroyed)).subscribe(x => {
|
||||||
setTimeout(() => { this.progressIndication = x; });
|
setTimeout(() => { this.progressIndication = x; });
|
||||||
});
|
});
|
||||||
|
timer(2000, this.configurationService.inAppNotificationsCountInterval * 1000)
|
||||||
|
.pipe(takeUntil(this._destroyed))
|
||||||
|
.subscribe(x => {
|
||||||
|
this.countUnreadInappNotifications();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private countUnreadInappNotifications() {
|
||||||
|
if (this.isAuthenticated()) {
|
||||||
|
this.inappNotificationService.countUnread()
|
||||||
|
.pipe(takeUntil(this._destroyed))
|
||||||
|
.subscribe(
|
||||||
|
data => {
|
||||||
|
this.inAppNotificationCount = data;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public isAuthenticated(): boolean {
|
public isAuthenticated(): boolean {
|
||||||
|
@ -273,4 +298,21 @@ export class NavbarComponent extends BaseComponent implements OnInit {
|
||||||
this.router.navigate(['/logout']);
|
this.router.navigate(['/logout']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toggleInAppNotifications() {
|
||||||
|
if (this.inAppNotificationDialog != null) {
|
||||||
|
this.inAppNotificationDialog.close();
|
||||||
|
} else {
|
||||||
|
this.countUnreadInappNotifications();
|
||||||
|
this.inAppNotificationDialog = this.dialog.open(InAppNotificationListingDialogComponent, {
|
||||||
|
position: {
|
||||||
|
top: '64px', right: '0px'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.inAppNotificationDialog.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => {
|
||||||
|
this.countUnreadInappNotifications();
|
||||||
|
this.inAppNotificationDialog = null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
"clientSecret": null,
|
"clientSecret": null,
|
||||||
"grantType": "code"
|
"grantType": "code"
|
||||||
},
|
},
|
||||||
|
"inAppNotificationsCountInterval": "30",
|
||||||
"notification_service": {
|
"notification_service": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"address": "http://localhost:8086/api/"
|
"address": "http://localhost:8086/api/"
|
||||||
|
|
|
@ -314,7 +314,9 @@
|
||||||
"DMP": "DMP",
|
"DMP": "DMP",
|
||||||
"GRANT": "Grant",
|
"GRANT": "Grant",
|
||||||
"PUBLISHED": "Published"
|
"PUBLISHED": "Published"
|
||||||
}
|
},
|
||||||
|
"INAPP-NOTIFICATIONS": "All Notifications",
|
||||||
|
"READ-ALL-INAPP-NOTIFICATIONS": "Read All"
|
||||||
},
|
},
|
||||||
"SIDE-BAR": {
|
"SIDE-BAR": {
|
||||||
"GENERAL": "GENERAL",
|
"GENERAL": "GENERAL",
|
||||||
|
@ -1328,6 +1330,43 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"NOTIFICATION-SERVICE": {
|
"NOTIFICATION-SERVICE": {
|
||||||
|
"INAPP-NOTIFICATION-LISTING": {
|
||||||
|
"FIELDS": {
|
||||||
|
"SUBJECT": "Subject",
|
||||||
|
"TRACKING-STATE": "Tracking State",
|
||||||
|
"CREATED-AT": "Created",
|
||||||
|
"IS-ACTIVE": "Is Active"
|
||||||
|
},
|
||||||
|
"FILTER": {
|
||||||
|
"MORE-FILTERS": "More filters",
|
||||||
|
"TRACKING-STATE":"Tracking State",
|
||||||
|
"IS-ACTIVE": "Is Active",
|
||||||
|
"CHANNEL": "Channel",
|
||||||
|
"CANCEL": "Cancel",
|
||||||
|
"APPLY-FILTERS": "Apply filters"
|
||||||
|
},
|
||||||
|
"CONFIRM-DELETE-DIALOG": {
|
||||||
|
"MESSAGE": "Would you like to delete this Notification Template?",
|
||||||
|
"CONFIRM-BUTTON": "Yes, delete",
|
||||||
|
"CANCEL-BUTTON": "No"
|
||||||
|
},
|
||||||
|
"ACTIONS": {
|
||||||
|
"DELETE": "Delete",
|
||||||
|
"EDIT": "Edit"
|
||||||
|
},
|
||||||
|
"SUCCESSFUL-DELETE": "Successful Delete",
|
||||||
|
"UNSUCCESSFUL-DELETE": "This item could not be deleted."
|
||||||
|
},
|
||||||
|
"INAPP-NOTIFICATION-EDITOR": {
|
||||||
|
"FIELDS": {
|
||||||
|
|
||||||
|
},
|
||||||
|
"ACTIONS": {
|
||||||
|
"READ": "Read",
|
||||||
|
"CANCEL": "Cancel",
|
||||||
|
"DELETE": "Delete"
|
||||||
|
}
|
||||||
|
},
|
||||||
"NOTIFICATION-TEMPLATE-EDITOR": {
|
"NOTIFICATION-TEMPLATE-EDITOR": {
|
||||||
"NEW": "New Notification Template",
|
"NEW": "New Notification Template",
|
||||||
"FIELDS": {
|
"FIELDS": {
|
||||||
|
@ -2275,6 +2314,10 @@
|
||||||
"DESCRIPTION-TEMPLATE-INVITATION": "Description Template Invitation",
|
"DESCRIPTION-TEMPLATE-INVITATION": "Description Template Invitation",
|
||||||
"CONTACT-SUPPORT": "Contact Support",
|
"CONTACT-SUPPORT": "Contact Support",
|
||||||
"PUBLIC-CONTACT-SUPPORT": "Public Contact Support"
|
"PUBLIC-CONTACT-SUPPORT": "Public Contact Support"
|
||||||
|
},
|
||||||
|
"NOTIFICATION-INAPP-TRACKING": {
|
||||||
|
"STORED": "Stored",
|
||||||
|
"DELIVERED": "Delivered"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ADDRESEARCHERS-EDITOR": {
|
"ADDRESEARCHERS-EDITOR": {
|
||||||
|
|
Loading…
Reference in New Issue