oip-common 0.1.2 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -29,7 +29,7 @@ import { PrimeNG } from 'primeng/config';
29
29
  import * as i3 from 'primeng/selectbutton';
30
30
  import { SelectButtonModule } from 'primeng/selectbutton';
31
31
  import { OidcSecurityService, PublicEventsService, EventTypes, StsConfigHttpLoader } from 'angular-auth-oidc-client';
32
- import { filter, map, switchMap, catchError } from 'rxjs/operators';
32
+ import { filter, map, distinctUntilChanged, switchMap, catchError } from 'rxjs/operators';
33
33
  import { Tabs, TabList, Tab } from 'primeng/tabs';
34
34
  import * as i2$2 from 'primeng/avatar';
35
35
  import { AvatarModule } from 'primeng/avatar';
@@ -1475,6 +1475,10 @@ class KeycloakSecurityService extends OidcSecurityService {
1475
1475
  * Stores the decoded access token payload.
1476
1476
  */
1477
1477
  this.payload = new BehaviorSubject(null);
1478
+ /**
1479
+ * Stores user-specific data from the login response.
1480
+ */
1481
+ this.currentUser = new BehaviorSubject(null);
1478
1482
  this.publicEventsService
1479
1483
  .registerForEvents()
1480
1484
  .pipe(filter((event) => event.type === EventTypes.NewAuthenticationResult))
@@ -1483,14 +1487,17 @@ class KeycloakSecurityService extends OidcSecurityService {
1483
1487
  });
1484
1488
  }
1485
1489
  getCurrentUser() {
1486
- return this.userData;
1490
+ return this.currentUser.getValue();
1491
+ }
1492
+ getCurrentUser$() {
1493
+ return this.currentUser.asObservable();
1487
1494
  }
1488
1495
  /**
1489
1496
  * Returns the ID token for the sign-in.
1490
1497
  * @returns A string with the id token.
1491
1498
  */
1492
1499
  getAccessToken() {
1493
- return this.loginResponse.pipe(map((data) => data?.accessToken));
1500
+ return super.getAccessToken();
1494
1501
  }
1495
1502
  /**
1496
1503
  * Indicates whether the current user has the 'admin' role.
@@ -1507,7 +1514,7 @@ class KeycloakSecurityService extends OidcSecurityService {
1507
1514
  auth() {
1508
1515
  super.checkAuth().subscribe((_response) => {
1509
1516
  this.loginResponse.next(_response);
1510
- this.userData = _response.userData;
1517
+ this.currentUser.next(_response.userData);
1511
1518
  this.getPayloadFromAccessToken().subscribe((_token) => {
1512
1519
  this.payload.next(_token);
1513
1520
  });
@@ -1528,6 +1535,7 @@ class KeycloakSecurityService extends OidcSecurityService {
1528
1535
  ngOnDestroy() {
1529
1536
  this.loginResponse.complete();
1530
1537
  this.payload.complete();
1538
+ this.currentUser.complete();
1531
1539
  }
1532
1540
  /**
1533
1541
  * Checks whether the current access token is expired based on the 'exp' claim.
@@ -1554,6 +1562,7 @@ class UserService {
1554
1562
  constructor() {
1555
1563
  this.securityService = inject(SecurityService);
1556
1564
  this.baseDataService = inject(BaseDataService);
1565
+ this.requestedPhotoEmail = null;
1557
1566
  /**
1558
1567
  * Stores the user's photo as a data URL or binary blob, depending on how it's processed.
1559
1568
  */
@@ -1562,7 +1571,12 @@ class UserService {
1562
1571
  * Indicates whether the user photo has finished loading.
1563
1572
  */
1564
1573
  this.photoLoaded = false;
1565
- this.getUserPhoto();
1574
+ this.securityService
1575
+ .getCurrentUser$()
1576
+ .pipe(map((user) => user?.email ?? null), filter((email) => !!email), distinctUntilChanged())
1577
+ .subscribe(() => {
1578
+ this.getUserPhoto();
1579
+ });
1566
1580
  }
1567
1581
  /**
1568
1582
  * Returns a short label composed of the user's initials.
@@ -1585,9 +1599,12 @@ class UserService {
1585
1599
  getUserPhoto() {
1586
1600
  const email = this.securityService.getCurrentUser()?.email;
1587
1601
  if (!email) {
1588
- this.photoLoaded = true;
1589
1602
  return;
1590
1603
  }
1604
+ if (this.requestedPhotoEmail === email && (this.photoLoaded || this.photo)) {
1605
+ return;
1606
+ }
1607
+ this.requestedPhotoEmail = email;
1591
1608
  const url = this.baseDataService.buildUrl(`api/user-profile/get-user-photo?email=${email}`);
1592
1609
  this.baseDataService.getBlob(url).then((data) => {
1593
1610
  this.createImageFromBlob(data);
@@ -1988,15 +2005,18 @@ class HttpClient {
1988
2005
  this.layoutService = inject(LayoutService);
1989
2006
  this.baseUrl = "";
1990
2007
  this.securityData = null;
1991
- this.securityWorker = (securityData) => ({
1992
- headers: {
2008
+ this.securityWorker = (securityData) => {
2009
+ const headers = {
1993
2010
  "Accept-language": this.layoutService.language()
1994
2011
  ? this.layoutService.language()
1995
2012
  : "en",
1996
2013
  "X-Timezone": this.layoutService.timeZone(),
1997
- Authorization: `Bearer ${securityData}`,
1998
- },
1999
- });
2014
+ };
2015
+ if (securityData) {
2016
+ headers.Authorization = `Bearer ${securityData}`;
2017
+ }
2018
+ return { headers };
2019
+ };
2000
2020
  this.abortControllers = new Map();
2001
2021
  this.customFetch = (...fetchParams) => fetch(...fetchParams);
2002
2022
  this.baseApiParams = {
@@ -3128,7 +3148,8 @@ class MenuComponent {
3128
3148
  ];
3129
3149
  }
3130
3150
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: MenuComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3131
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: MenuComponent, isStandalone: true, selector: "app-menu", providers: [MenuApi], viewQueries: [{ propertyName: "menuItemCreateDialogComponent", first: true, predicate: MenuItemCreateDialogComponent, descendants: true }, { propertyName: "menuItemEditDialogComponent", first: true, predicate: MenuItemEditDialogComponent, descendants: true }, { propertyName: "contextMenu", first: true, predicate: ContextMenu, descendants: true }], ngImport: i0, template: ` <div #empty class="layout-sidebar" (contextmenu)="onContextMenu($event)">
3151
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: MenuComponent, isStandalone: true, selector: "app-menu", providers: [MenuApi], viewQueries: [{ propertyName: "menuItemCreateDialogComponent", first: true, predicate: MenuItemCreateDialogComponent, descendants: true }, { propertyName: "menuItemEditDialogComponent", first: true, predicate: MenuItemEditDialogComponent, descendants: true }, { propertyName: "contextMenu", first: true, predicate: ContextMenu, descendants: true }], ngImport: i0, template: `
3152
+ <div #empty class="layout-sidebar" (contextmenu)="onContextMenu($event)">
3132
3153
  <ul class="layout-menu">
3133
3154
  @for (item of menuService.menu; track item; let i = $index) {
3134
3155
  <ng-container>
@@ -3148,10 +3169,10 @@ class MenuComponent {
3148
3169
  }
3149
3170
  </ul>
3150
3171
  </div>
3151
- <p-contextMenu [target]="empty" />
3152
- @if (securityService.isAdmin) {
3153
- <menu-item-create-dialog />
3154
- <menu-item-edit-dialog />
3172
+ <p-contextMenu [target]="empty"/>
3173
+ @if (securityService.isAdmin()) {
3174
+ <menu-item-create-dialog/>
3175
+ <menu-item-edit-dialog/>
3155
3176
  }`, isInline: true, dependencies: [{ kind: "component", type: MenuItemComponent, selector: "[app-menuitem]", inputs: ["item", "index", "root", "parentKey", "menuItemCreateDialogComponent", "menuItemEditDialogComponent", "contextMenu"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "ngmodule", type: ContextMenuModule }, { kind: "component", type: i1$4.ContextMenu, selector: "p-contextMenu, p-contextmenu, p-context-menu", inputs: ["model", "triggerEvent", "target", "global", "style", "styleClass", "autoZIndex", "baseZIndex", "id", "breakpoint", "ariaLabel", "ariaLabelledBy", "pressDelay", "appendTo"], outputs: ["onShow", "onHide"] }, { kind: "ngmodule", type: DialogModule }, { kind: "ngmodule", type: InputTextModule }, { kind: "component", type: MenuItemCreateDialogComponent, selector: "menu-item-create-dialog", inputs: ["visible"], outputs: ["visibleChange"] }, { kind: "ngmodule", type: FormsModule }, { kind: "component", type: MenuItemEditDialogComponent, selector: "menu-item-edit-dialog", inputs: ["visible"], outputs: ["visibleChange"] }] }); }
3156
3177
  }
3157
3178
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: MenuComponent, decorators: [{
@@ -3170,7 +3191,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
3170
3191
  providers: [MenuApi],
3171
3192
  selector: 'app-menu',
3172
3193
  standalone: true,
3173
- template: ` <div #empty class="layout-sidebar" (contextmenu)="onContextMenu($event)">
3194
+ template: `
3195
+ <div #empty class="layout-sidebar" (contextmenu)="onContextMenu($event)">
3174
3196
  <ul class="layout-menu">
3175
3197
  @for (item of menuService.menu; track item; let i = $index) {
3176
3198
  <ng-container>
@@ -3190,10 +3212,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
3190
3212
  }
3191
3213
  </ul>
3192
3214
  </div>
3193
- <p-contextMenu [target]="empty" />
3194
- @if (securityService.isAdmin) {
3195
- <menu-item-create-dialog />
3196
- <menu-item-edit-dialog />
3215
+ <p-contextMenu [target]="empty"/>
3216
+ @if (securityService.isAdmin()) {
3217
+ <menu-item-create-dialog/>
3218
+ <menu-item-edit-dialog/>
3197
3219
  }`
3198
3220
  }]
3199
3221
  }], propDecorators: { menuItemCreateDialogComponent: [{
@@ -5925,17 +5947,10 @@ class NotificationService {
5925
5947
  this.securityService = inject(SecurityService);
5926
5948
  this.msgService = inject(MsgService);
5927
5949
  this.frontendConfig = inject(OIP_FRONTEND_CONFIG);
5928
- this.securityService.getAccessToken().subscribe((token) => {
5929
- this.securityData = token;
5930
- if (token) {
5931
- this.connection.stop().then(() => {
5932
- this.connection.start().then();
5933
- });
5934
- }
5935
- });
5950
+ this.securityData = null;
5936
5951
  this.connection = new signalR.HubConnectionBuilder()
5937
5952
  .withUrl(this.resolveHubUrl(), {
5938
- accessTokenFactory: () => this.securityData,
5953
+ accessTokenFactory: () => this.securityData ?? '',
5939
5954
  skipNegotiation: true,
5940
5955
  transport: signalR.HttpTransportType.WebSockets
5941
5956
  })
@@ -5950,6 +5965,19 @@ class NotificationService {
5950
5965
  };
5951
5966
  this.msgService.add(opt);
5952
5967
  });
5968
+ this.securityService.getAccessToken().subscribe((token) => {
5969
+ this.securityData = token;
5970
+ if (!token) {
5971
+ return;
5972
+ }
5973
+ if (this.connection.state === signalR.HubConnectionState.Disconnected) {
5974
+ this.connection.start().catch((error) => console.error('Failed to start notification connection', error));
5975
+ return;
5976
+ }
5977
+ this.connection.stop().then(() => {
5978
+ this.connection.start().catch((error) => console.error('Failed to restart notification connection', error));
5979
+ });
5980
+ });
5953
5981
  }
5954
5982
  resolveHubUrl() {
5955
5983
  if (this.frontendConfig.notificationHubUrl) {