diff --git a/dmp-backend/notification-service/notification/src/main/java/gr/cite/notification/data/TenantScopedEntityManager.java b/dmp-backend/notification-service/notification/src/main/java/gr/cite/notification/data/TenantScopedEntityManager.java index 4426b514b..eff2eac3e 100644 --- a/dmp-backend/notification-service/notification/src/main/java/gr/cite/notification/data/TenantScopedEntityManager.java +++ b/dmp-backend/notification-service/notification/src/main/java/gr/cite/notification/data/TenantScopedEntityManager.java @@ -32,7 +32,8 @@ public class TenantScopedEntityManager { public int getBulkSize() { Session session = this.entityManager.unwrap(Session.class); - return session.getJdbcBatchSize(); + if (session.getJdbcBatchSize() != null) return session.getJdbcBatchSize(); + return 0; } public void setBulkSize(int size) { diff --git a/dmp-frontend/src/app/core/services/configuration/configuration.service.ts b/dmp-frontend/src/app/core/services/configuration/configuration.service.ts index 02cb670fb..b9ebaae25 100644 --- a/dmp-frontend/src/app/core/services/configuration/configuration.service.ts +++ b/dmp-frontend/src/app/core/services/configuration/configuration.service.ts @@ -118,6 +118,11 @@ export class ConfigurationService extends BaseComponent { return this._notificationServiceEnabled; } + private _inAppNotificationsCountInterval: number; + get inAppNotificationsCountInterval(): number { + return this._inAppNotificationsCountInterval || 3200; + } + public loadConfiguration(): Promise { return new Promise((r, e) => { // 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._notificationServiceAddress = config.notification_service.address; } + this._inAppNotificationsCountInterval = config.inAppNotificationsCountInterval; } } diff --git a/dmp-frontend/src/app/core/services/inapp-notification/inapp-notification.service.ts b/dmp-frontend/src/app/core/services/inapp-notification/inapp-notification.service.ts index 761495df3..06dab8b66 100644 --- a/dmp-frontend/src/app/core/services/inapp-notification/inapp-notification.service.ts +++ b/dmp-frontend/src/app/core/services/inapp-notification/inapp-notification.service.ts @@ -57,6 +57,14 @@ export class InAppNotificationService { catchError((error: any) => throwError(error))); } + readAll(): Observable { + const url = `${this.apiBase}/read-all`; + + return this.http + .post(url, {}).pipe( + catchError((error: any) => throwError(error))); + } + delete(id: Guid): Observable { const url = `${this.apiBase}/${id}`; return this.http diff --git a/dmp-frontend/src/app/ui/inapp-notification/inapp-notification.module.ts b/dmp-frontend/src/app/ui/inapp-notification/inapp-notification.module.ts index 33f09eac3..7717c1225 100644 --- a/dmp-frontend/src/app/ui/inapp-notification/inapp-notification.module.ts +++ b/dmp-frontend/src/app/ui/inapp-notification/inapp-notification.module.ts @@ -37,7 +37,6 @@ import { CommonFormattingModule } from '@common/formatting/common-formatting.mod // ], exports: [ InAppNotificationListingComponent, - InAppNotificationListingDialogComponent ] }) export class InAppNotificationModule { } diff --git a/dmp-frontend/src/app/ui/inapp-notification/listing-dialog/inapp-notification-listing-dialog.component.html b/dmp-frontend/src/app/ui/inapp-notification/listing-dialog/inapp-notification-listing-dialog.component.html index 1ecd1ee51..99d4eb09b 100644 --- a/dmp-frontend/src/app/ui/inapp-notification/listing-dialog/inapp-notification-listing-dialog.component.html +++ b/dmp-frontend/src/app/ui/inapp-notification/listing-dialog/inapp-notification-listing-dialog.component.html @@ -6,8 +6,12 @@ {{ inappNotification.createdAt | date : 'short'}} - - {{'APP.NAVIGATION.ALL-INAPP-NOTIFICATIONS' + + {{'NAV-BAR.INAPP-NOTIFICATIONS' + | translate}} + + + {{'NAV-BAR.READ-ALL-INAPP-NOTIFICATIONS' | translate}} diff --git a/dmp-frontend/src/app/ui/inapp-notification/listing-dialog/inapp-notification-listing-dialog.component.scss b/dmp-frontend/src/app/ui/inapp-notification/listing-dialog/inapp-notification-listing-dialog.component.scss index 7d81257f9..7cbca544f 100644 --- a/dmp-frontend/src/app/ui/inapp-notification/listing-dialog/inapp-notification-listing-dialog.component.scss +++ b/dmp-frontend/src/app/ui/inapp-notification/listing-dialog/inapp-notification-listing-dialog.component.scss @@ -8,4 +8,8 @@ .secondary-text { color: rgba(0, 0, 0, 0.54); } + + .mat-list-item-content { + text-align: center + } } diff --git a/dmp-frontend/src/app/ui/inapp-notification/listing-dialog/inapp-notification-listing-dialog.component.ts b/dmp-frontend/src/app/ui/inapp-notification/listing-dialog/inapp-notification-listing-dialog.component.ts index b95f85caa..7b51ba03a 100644 --- a/dmp-frontend/src/app/ui/inapp-notification/listing-dialog/inapp-notification-listing-dialog.component.ts +++ b/dmp-frontend/src/app/ui/inapp-notification/listing-dialog/inapp-notification-listing-dialog.component.ts @@ -85,4 +85,12 @@ export class InAppNotificationListingDialogComponent extends BaseComponent imple this.router.navigate(['/inapp-notifications']); this.dialogRef.close(); } + + readAllNotifications() { + this.inappNotificationService.readAll() + .pipe(takeUntil(this._destroyed)) + .subscribe( + data => {}, + ); + } } diff --git a/dmp-frontend/src/app/ui/inapp-notification/listing/filters/inapp-notification-listing-filters.component.html b/dmp-frontend/src/app/ui/inapp-notification/listing/filters/inapp-notification-listing-filters.component.html index 7221b4ad0..3d923d241 100644 --- a/dmp-frontend/src/app/ui/inapp-notification/listing/filters/inapp-notification-listing-filters.component.html +++ b/dmp-frontend/src/app/ui/inapp-notification/listing/filters/inapp-notification-listing-filters.component.html @@ -22,7 +22,7 @@
- {{'NOTIFICATION-SERVICE.INAPP-NOTIFICATION-LISTING.FILTER.SHOW-INACTIVE' | translate}} + {{'NOTIFICATION-SERVICE.INAPP-NOTIFICATION-LISTING.FILTER.IS-ACTIVE' | translate}}
diff --git a/dmp-frontend/src/app/ui/inapp-notification/listing/filters/inapp-notification-listing-filters.component.ts b/dmp-frontend/src/app/ui/inapp-notification/listing/filters/inapp-notification-listing-filters.component.ts index 3ee0ab0a8..0418ee1cc 100644 --- a/dmp-frontend/src/app/ui/inapp-notification/listing/filters/inapp-notification-listing-filters.component.ts +++ b/dmp-frontend/src/app/ui/inapp-notification/listing/filters/inapp-notification-listing-filters.component.ts @@ -60,7 +60,14 @@ export class InAppNotificationListingFiltersComponent extends BaseComponent impl return this.filter.trackingState ? this.filter.trackingState : null; } 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); } } diff --git a/dmp-frontend/src/app/ui/inapp-notification/listing/inapp-notification-listing.component.ts b/dmp-frontend/src/app/ui/inapp-notification/listing/inapp-notification-listing.component.ts index 6c8503151..a5b5264c3 100644 --- a/dmp-frontend/src/app/ui/inapp-notification/listing/inapp-notification-listing.component.ts +++ b/dmp-frontend/src/app/ui/inapp-notification/listing/inapp-notification-listing.component.ts @@ -78,16 +78,16 @@ export class InAppNotificationListingComponent extends BaseListingComponent(x => x.subject), sortable: true, - languageName: 'INAPP-NOTIFICATION-LISTING.FIELDS.SUBJECT' + languageName: 'NOTIFICATION-SERVICE.INAPP-NOTIFICATION-LISTING.FIELDS.SUBJECT' }, { prop: nameof(x => x.trackingState), sortable: true, - languageName: 'INAPP-NOTIFICATION-LISTING.FIELDS.TRACKING-STATE', + languageName: 'NOTIFICATION-SERVICE.INAPP-NOTIFICATION-LISTING.FIELDS.TRACKING-STATE', pipe: this.pipeService.getPipe(NotificationInAppTrackingTypePipe) }, { prop: nameof(x => x.createdAt), sortable: true, - languageName: 'INAPP-NOTIFICATION-LISTING.FIELDS.CREATED-AT', + languageName: 'NOTIFICATION-SERVICE.INAPP-NOTIFICATION-LISTING.FIELDS.CREATED-AT', pipe: this.pipeService.getPipe(DataTableDateTimeFormatPipe).withFormat('short') }]); } @@ -105,6 +105,7 @@ export class InAppNotificationListingComponent extends BaseListingComponent> { + console.log(this.lookup); return this.inappNotificationService.query(this.lookup); } diff --git a/dmp-frontend/src/app/ui/navbar/navbar.component.html b/dmp-frontend/src/app/ui/navbar/navbar.component.html index d2023d286..4602acb15 100644 --- a/dmp-frontend/src/app/ui/navbar/navbar.component.html +++ b/dmp-frontend/src/app/ui/navbar/navbar.component.html @@ -32,6 +32,11 @@ +
+ +
diff --git a/dmp-frontend/src/app/ui/navbar/navbar.component.ts b/dmp-frontend/src/app/ui/navbar/navbar.component.ts index d46499f7d..5192c3085 100644 --- a/dmp-frontend/src/app/ui/navbar/navbar.component.ts +++ b/dmp-frontend/src/app/ui/navbar/navbar.component.ts @@ -1,6 +1,6 @@ import { Location } from '@angular/common'; 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 { Router } from '@angular/router'; 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 { UserDialogComponent } from './user-dialog/user-dialog.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({ selector: 'app-navbar', @@ -33,18 +37,22 @@ export class NavbarComponent extends BaseComponent implements OnInit { currentRoute: string; selectedLanguage: string; private user: User; + inAppNotificationDialog: MatDialogRef = null; + inAppNotificationCount = 0; @Output() sidebarToggled: EventEmitter = new EventEmitter(); @ViewChild(MatMenuTrigger) trigger: MatMenuTrigger; constructor(location: Location, private element: ElementRef, private router: Router, - private authentication: AuthService, + public authentication: AuthService, private dialog: MatDialog, private progressIndicationService: ProgressIndicationService, private languageService: LanguageService, private matomoService: MatomoService, private sidenavService: SideNavService, + private inappNotificationService: InAppNotificationService, + private configurationService: ConfigurationService ) { super(); this.location = location; @@ -75,6 +83,23 @@ export class NavbarComponent extends BaseComponent implements OnInit { this.progressIndicationService.getProgressIndicationObservable().pipe(takeUntil(this._destroyed)).subscribe(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 { @@ -273,4 +298,21 @@ export class NavbarComponent extends BaseComponent implements OnInit { 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; + }); + } + } + } diff --git a/dmp-frontend/src/assets/config/config.json b/dmp-frontend/src/assets/config/config.json index 5f6f4c949..5b5690136 100644 --- a/dmp-frontend/src/assets/config/config.json +++ b/dmp-frontend/src/assets/config/config.json @@ -19,6 +19,7 @@ "clientSecret": null, "grantType": "code" }, + "inAppNotificationsCountInterval": "30", "notification_service": { "enabled": true, "address": "http://localhost:8086/api/" diff --git a/dmp-frontend/src/assets/i18n/en.json b/dmp-frontend/src/assets/i18n/en.json index 9b995fcc5..a87e020fc 100644 --- a/dmp-frontend/src/assets/i18n/en.json +++ b/dmp-frontend/src/assets/i18n/en.json @@ -314,7 +314,9 @@ "DMP": "DMP", "GRANT": "Grant", "PUBLISHED": "Published" - } + }, + "INAPP-NOTIFICATIONS": "All Notifications", + "READ-ALL-INAPP-NOTIFICATIONS": "Read All" }, "SIDE-BAR": { "GENERAL": "GENERAL", @@ -1328,6 +1330,43 @@ } }, "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": { "NEW": "New Notification Template", "FIELDS": { @@ -2275,6 +2314,10 @@ "DESCRIPTION-TEMPLATE-INVITATION": "Description Template Invitation", "CONTACT-SUPPORT": "Contact Support", "PUBLIC-CONTACT-SUPPORT": "Public Contact Support" + }, + "NOTIFICATION-INAPP-TRACKING": { + "STORED": "Stored", + "DELIVERED": "Delivered" } }, "ADDRESEARCHERS-EDITOR": {