@dsivd/prestations-ng 19.2.0-beta.5 → 19.2.0-beta.6

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.
package/CHANGELOG.md CHANGED
@@ -98,6 +98,9 @@ Please check the [UPGRADING_V19.md](UPGRADING_V19.md) guide for more information
98
98
 
99
99
  ### Fixed
100
100
 
101
+ - `providePrestationsNgCore()` registers again the HTTP interceptors lost with `FoehnPageModule` in 19.0.0: the
102
+ `foehn-transmit-waiting-modal` is displayed again during a long transmission, the warning before the expiration of
103
+ the session receives its date again, and a new version of the application deployed meanwhile is detected again.
101
104
  - `foehn-select`, `foehn-radio`, `foehn-checkbox` and the autocompletes:
102
105
  - the model is no longer set back to its previous value when the parent changes `elements` and `model`
103
106
  at the same time
@@ -5461,6 +5461,203 @@ class I18nForm {
5461
5461
  referenceInterne = undefined;
5462
5462
  }
5463
5463
 
5464
+ const APP_VERSION_HEADER = 'app-version';
5465
+ class AppInfoHeadersInterceptor {
5466
+ foehnPageService = inject(FoehnPageService);
5467
+ appVersion = undefined;
5468
+ errorListenerRegistered = false;
5469
+ constructor() {
5470
+ // Enregistrer une seule fois
5471
+ if (!this.errorListenerRegistered) {
5472
+ window.addEventListener('error', (event) => {
5473
+ if (event.message?.includes('ChunkLoadError') ||
5474
+ event.message?.includes('Loading chunk')) {
5475
+ this.foehnPageService.setAppVersionMismatch();
5476
+ }
5477
+ });
5478
+ this.errorListenerRegistered = true;
5479
+ }
5480
+ }
5481
+ intercept(request, next) {
5482
+ return next.handle(request).pipe(tap$1((httpEvent) => {
5483
+ if (httpEvent instanceof HttpResponse) {
5484
+ const appVersionInHeader = httpEvent.headers.get(APP_VERSION_HEADER);
5485
+ if (!this.appVersion?.length) {
5486
+ this.appVersion = appVersionInHeader ?? '';
5487
+ }
5488
+ else if (appVersionInHeader &&
5489
+ this.appVersion !== appVersionInHeader) {
5490
+ this.foehnPageService.setAppVersionMismatch();
5491
+ }
5492
+ }
5493
+ }));
5494
+ }
5495
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.23", ngImport: i0, type: AppInfoHeadersInterceptor, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
5496
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.23", ngImport: i0, type: AppInfoHeadersInterceptor, providedIn: 'root' });
5497
+ }
5498
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.23", ngImport: i0, type: AppInfoHeadersInterceptor, decorators: [{
5499
+ type: Injectable,
5500
+ args: [{
5501
+ providedIn: 'root',
5502
+ }]
5503
+ }], ctorParameters: () => [] });
5504
+ const APP_INFO_HEADERS_INTERCEPTOR_PROVIDER = [
5505
+ {
5506
+ provide: HTTP_INTERCEPTORS,
5507
+ useExisting: AppInfoHeadersInterceptor,
5508
+ multi: true,
5509
+ },
5510
+ ];
5511
+
5512
+ class CurrentSessionExpiration {
5513
+ expiration = undefined;
5514
+ type = undefined;
5515
+ }
5516
+
5517
+ class IntervalHelper {
5518
+ static accurateInterval(
5519
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
5520
+ callBack, intervalInMilliseconds,
5521
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
5522
+ errorCallBack) {
5523
+ let timeout = null;
5524
+ let nextAt = Date.now() + intervalInMilliseconds;
5525
+ const clear = () => {
5526
+ if (timeout !== null) {
5527
+ clearTimeout(timeout);
5528
+ }
5529
+ };
5530
+ const timerHandler = () => {
5531
+ nextAt += intervalInMilliseconds;
5532
+ // Avoid time drift by doing "nextAt - Date.now()"
5533
+ const calculatedTimeout = nextAt - Date.now();
5534
+ // Verify browser tab inactivity
5535
+ if (calculatedTimeout < 0) {
5536
+ if (errorCallBack) {
5537
+ clear();
5538
+ return errorCallBack();
5539
+ }
5540
+ }
5541
+ timeout = setTimeout(timerHandler, Math.max(0, nextAt - Date.now()));
5542
+ callBack();
5543
+ };
5544
+ // Avoid time drift by doing "nextAt - Date.now()"
5545
+ timeout = setTimeout(timerHandler, nextAt - Date.now());
5546
+ return { clear };
5547
+ }
5548
+ }
5549
+
5550
+ class DemandeExpirationService {
5551
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
5552
+ interval;
5553
+ PULLING_IN_MILLISECONDS = 1000;
5554
+ _demandeExpirationDateTimeSubject = new BehaviorSubject(null);
5555
+ intervalSubject = new BehaviorSubject(undefined);
5556
+ shouldDisplayExpirationTimerMessage() {
5557
+ return combineLatest([
5558
+ this.getDemandeExpirationDateTime(),
5559
+ this.intervalSubject.asObservable(),
5560
+ ]).pipe(map(([value]) => !dayjs().isBefore(value?.expiration)), tap((visible) => {
5561
+ if (visible) {
5562
+ this.clearPulling();
5563
+ }
5564
+ }),
5565
+ // Checked every second: only a change must refresh the views.
5566
+ distinctUntilChanged(), shareReplay(1));
5567
+ }
5568
+ setDemandeExpirationDateTime(expiration) {
5569
+ this._demandeExpirationDateTimeSubject.next(expiration);
5570
+ }
5571
+ getDemandeExpirationDateTime() {
5572
+ return this._demandeExpirationDateTimeSubject.asObservable().pipe(filter((value) => !!value?.expiration?.isValid()), tap((value) => {
5573
+ if (dayjs().isBefore(value.expiration)) {
5574
+ this.startPulling();
5575
+ }
5576
+ }), shareReplay(1));
5577
+ }
5578
+ startPulling() {
5579
+ this.clearPulling();
5580
+ this.interval = IntervalHelper.accurateInterval(() => {
5581
+ this.intervalSubject.next();
5582
+ }, this.PULLING_IN_MILLISECONDS, () => {
5583
+ this.startPulling();
5584
+ });
5585
+ }
5586
+ clearPulling() {
5587
+ this.interval?.clear();
5588
+ }
5589
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.23", ngImport: i0, type: DemandeExpirationService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
5590
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.23", ngImport: i0, type: DemandeExpirationService, providedIn: 'root' });
5591
+ }
5592
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.23", ngImport: i0, type: DemandeExpirationService, decorators: [{
5593
+ type: Injectable,
5594
+ args: [{
5595
+ providedIn: 'root',
5596
+ }]
5597
+ }] });
5598
+
5599
+ const EXPIRATION_HEADER = 'Sessions-Expirations';
5600
+ class DemandeExpirationInterceptor {
5601
+ demandeExpirationService = inject(DemandeExpirationService);
5602
+ intercept(request, next) {
5603
+ return next.handle(request).pipe(tap$1((httpEvent) => {
5604
+ if (httpEvent.type === HttpEventType.Sent) {
5605
+ return;
5606
+ }
5607
+ if (httpEvent instanceof HttpResponse) {
5608
+ if (httpEvent.headers.has(EXPIRATION_HEADER)) {
5609
+ const expirationHeader = httpEvent.headers.get(EXPIRATION_HEADER);
5610
+ if (expirationHeader) {
5611
+ this.manageDemandeExpirationHeader(expirationHeader, httpEvent.body);
5612
+ }
5613
+ }
5614
+ }
5615
+ }));
5616
+ }
5617
+ manageDemandeExpirationHeader(expirationByDemande, responseBody) {
5618
+ const expirationByDemandeMap = this.getExpirationByDemandeMap(expirationByDemande);
5619
+ const expiration = new CurrentSessionExpiration();
5620
+ const reference = responseBody?.meta?.reference || '';
5621
+ const dateTimeForReference = expirationByDemandeMap.get(reference);
5622
+ const dateTimeForIam = expirationByDemandeMap.get('IAM');
5623
+ if (dateTimeForReference) {
5624
+ expiration.type = 'SESSION-TOKEN';
5625
+ expiration.expiration = dayjs(dateTimeForReference);
5626
+ }
5627
+ else if (dateTimeForIam) {
5628
+ expiration.type = 'IAM';
5629
+ expiration.expiration = dayjs(dateTimeForIam);
5630
+ }
5631
+ if (expiration.expiration?.isValid()) {
5632
+ this.demandeExpirationService.setDemandeExpirationDateTime(expiration);
5633
+ }
5634
+ }
5635
+ getExpirationByDemandeMap(expirationByDemande) {
5636
+ const myMap = new Map();
5637
+ const expirationByDemandesAsArray = expirationByDemande.split(';');
5638
+ expirationByDemandesAsArray.forEach((value) => {
5639
+ const valueAsArray = value.split(',');
5640
+ myMap.set(valueAsArray[0], new Date(valueAsArray[1]));
5641
+ });
5642
+ return myMap;
5643
+ }
5644
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.23", ngImport: i0, type: DemandeExpirationInterceptor, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
5645
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.23", ngImport: i0, type: DemandeExpirationInterceptor, providedIn: 'root' });
5646
+ }
5647
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.23", ngImport: i0, type: DemandeExpirationInterceptor, decorators: [{
5648
+ type: Injectable,
5649
+ args: [{
5650
+ providedIn: 'root',
5651
+ }]
5652
+ }] });
5653
+ const DEMANDE_EXPIRATION_INTERCEPTOR_PROVIDER = [
5654
+ {
5655
+ provide: HTTP_INTERCEPTORS,
5656
+ useExisting: DemandeExpirationInterceptor,
5657
+ multi: true,
5658
+ },
5659
+ ];
5660
+
5464
5661
  const OIDC_ENABLED = new InjectionToken('enable.oidc.interceptor', {
5465
5662
  factory: () => false,
5466
5663
  });
@@ -5531,6 +5728,11 @@ function providePrestationsNgCore() {
5531
5728
  useExisting: IamExpiredInterceptorService,
5532
5729
  multi: true,
5533
5730
  },
5731
+ // Formerly provided by FoehnPageModule: the version of the application changed during a deployment,
5732
+ // the expiration of the session and the modal displayed during the transmission
5733
+ APP_INFO_HEADERS_INTERCEPTOR_PROVIDER,
5734
+ DEMANDE_EXPIRATION_INTERCEPTOR_PROVIDER,
5735
+ DEMANDE_TRANSMIT_INTERCEPTOR_PROVIDER,
5534
5736
  {
5535
5737
  provide: ErrorHandler,
5536
5738
  useClass: ChunkLoadErrorHandler,
@@ -7456,88 +7658,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.23", ngImpo
7456
7658
  args: [{ selector: 'foehn-app-version-mis-match-modal', imports: [FoehnModalComponent, AsyncPipe, SdkDictionaryPipe], template: "<foehn-modal\n [id]=\"'foehn-app-version-mismatch-modal'\"\n [modalHeaderText]=\"\n 'foehn-app-version-mismatch-modal.title' | fromDictionary\n \"\n modalSize=\"modal-md\"\n [isModalVisible]=\"(isModalVisible | async) ?? false\"\n [closeable]=\"false\"\n>\n <div\n id=\"foehn-app-version-mismatch-modal-body\"\n [innerHTML]=\"\n 'foehn-app-version-mismatch-modal.content' | fromDictionary\n \"\n ></div>\n\n <div modal-footer class=\"w-100\">\n <div class=\"d-flex\">\n <button\n id=\"saveAndReloadBtn\"\n type=\"button\"\n class=\"btn btn-primary ms-auto\"\n [innerHTML]=\"\n (hasDemandeInProgress\n ? 'foehn-app-version-mismatch-modal.btn.save-and-reload'\n : 'foehn-app-version-mismatch-modal.btn.reload'\n ) | fromDictionary\n \"\n (click)=\"saveAndReload()\"\n ></button>\n </div>\n </div>\n</foehn-modal>\n", styles: [":host ::ng-deep .modal{z-index:10000}\n"] }]
7457
7659
  }], ctorParameters: () => [] });
7458
7660
 
7459
- class IntervalHelper {
7460
- static accurateInterval(
7461
- // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
7462
- callBack, intervalInMilliseconds,
7463
- // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
7464
- errorCallBack) {
7465
- let timeout = null;
7466
- let nextAt = Date.now() + intervalInMilliseconds;
7467
- const clear = () => {
7468
- if (timeout !== null) {
7469
- clearTimeout(timeout);
7470
- }
7471
- };
7472
- const timerHandler = () => {
7473
- nextAt += intervalInMilliseconds;
7474
- // Avoid time drift by doing "nextAt - Date.now()"
7475
- const calculatedTimeout = nextAt - Date.now();
7476
- // Verify browser tab inactivity
7477
- if (calculatedTimeout < 0) {
7478
- if (errorCallBack) {
7479
- clear();
7480
- return errorCallBack();
7481
- }
7482
- }
7483
- timeout = setTimeout(timerHandler, Math.max(0, nextAt - Date.now()));
7484
- callBack();
7485
- };
7486
- // Avoid time drift by doing "nextAt - Date.now()"
7487
- timeout = setTimeout(timerHandler, nextAt - Date.now());
7488
- return { clear };
7489
- }
7490
- }
7491
-
7492
- class DemandeExpirationService {
7493
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
7494
- interval;
7495
- PULLING_IN_MILLISECONDS = 1000;
7496
- _demandeExpirationDateTimeSubject = new BehaviorSubject(null);
7497
- intervalSubject = new BehaviorSubject(undefined);
7498
- shouldDisplayExpirationTimerMessage() {
7499
- return combineLatest([
7500
- this.getDemandeExpirationDateTime(),
7501
- this.intervalSubject.asObservable(),
7502
- ]).pipe(map(([value]) => !dayjs().isBefore(value?.expiration)), tap((visible) => {
7503
- if (visible) {
7504
- this.clearPulling();
7505
- }
7506
- }),
7507
- // Checked every second: only a change must refresh the views.
7508
- distinctUntilChanged(), shareReplay(1));
7509
- }
7510
- setDemandeExpirationDateTime(expiration) {
7511
- this._demandeExpirationDateTimeSubject.next(expiration);
7512
- }
7513
- getDemandeExpirationDateTime() {
7514
- return this._demandeExpirationDateTimeSubject.asObservable().pipe(filter((value) => !!value?.expiration?.isValid()), tap((value) => {
7515
- if (dayjs().isBefore(value.expiration)) {
7516
- this.startPulling();
7517
- }
7518
- }), shareReplay(1));
7519
- }
7520
- startPulling() {
7521
- this.clearPulling();
7522
- this.interval = IntervalHelper.accurateInterval(() => {
7523
- this.intervalSubject.next();
7524
- }, this.PULLING_IN_MILLISECONDS, () => {
7525
- this.startPulling();
7526
- });
7527
- }
7528
- clearPulling() {
7529
- this.interval?.clear();
7530
- }
7531
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.23", ngImport: i0, type: DemandeExpirationService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
7532
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.23", ngImport: i0, type: DemandeExpirationService, providedIn: 'root' });
7533
- }
7534
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.23", ngImport: i0, type: DemandeExpirationService, decorators: [{
7535
- type: Injectable,
7536
- args: [{
7537
- providedIn: 'root',
7538
- }]
7539
- }] });
7540
-
7541
7661
  class FoehnPageExpirationTimerComponent {
7542
7662
  isVisible;
7543
7663
  countDownTimeToDisplay;