@hmcts/ccd-case-ui-toolkit 7.3.54-pofcc-214-v1 → 7.3.54-polling

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.
@@ -8,11 +8,10 @@ import * as i1$1 from '@angular/router';
8
8
  import { RouterModule, NavigationStart, NavigationEnd } from '@angular/router';
9
9
  import * as i4 from '@angular/forms';
10
10
  import { NG_VALUE_ACCESSOR, NG_VALIDATORS, FormArray, FormGroup, FormControl, Validators, ReactiveFormsModule, FormsModule } from '@angular/forms';
11
- import { BehaviorSubject, throwError, Subject, EMPTY, Observable, skip, of, timer, forkJoin, fromEvent, Subscription, combineLatest } from 'rxjs';
11
+ import { BehaviorSubject, throwError, Subject, EMPTY, concat, defer, timer, Observable, skip, of, forkJoin, fromEvent, Subscription, combineLatest } from 'rxjs';
12
+ import { distinctUntilChanged, catchError, map, switchMap, repeat, retry, publish, refCount, debounceTime, delay, finalize, timeout, mergeMap, retryWhen, tap, delayWhen, publishReplay, take, first, takeUntil, filter } from 'rxjs/operators';
12
13
  import * as i1$2 from '@angular/common/http';
13
14
  import { HttpErrorResponse, HttpHeaders, HttpParams } from '@angular/common/http';
14
- import { distinctUntilChanged, catchError, map, publish, refCount, switchMap, debounceTime, delay, finalize, timeout, mergeMap, retryWhen, tap, delayWhen, publishReplay, take, first, takeUntil, filter } from 'rxjs/operators';
15
- import { polling } from 'rx-polling-hmcts';
16
15
  import { Type, Exclude, Expose, plainToClassFromExist, plainToClass } from 'class-transformer';
17
16
  import moment from 'moment';
18
17
  import { __decorate, __metadata } from 'tslib';
@@ -1829,8 +1828,7 @@ class ActivityPollingService {
1829
1828
  this.config = config;
1830
1829
  this.pollConfig = {
1831
1830
  interval: config.getActivityNexPollRequestMs(),
1832
- attempts: config.getActivityRetry(),
1833
- backgroundPolling: true
1831
+ attempts: config.getActivityRetry()
1834
1832
  };
1835
1833
  this.batchCollectionDelayMs = config.getActivityBatchCollectionDelayMs();
1836
1834
  this.maxRequestsPerBatch = config.getActivityMaxRequestPerBatch();
@@ -1847,17 +1845,18 @@ class ActivityPollingService {
1847
1845
  subject.subscribe(done);
1848
1846
  }
1849
1847
  else {
1848
+ // Only the first pending request should start the batch collection timer.
1849
+ const wasEmpty = this.pendingRequests.size === 0;
1850
1850
  subject = new Subject();
1851
1851
  subject.subscribe(done);
1852
- this.pendingRequests.set(caseId, subject);
1853
- }
1854
- if (this.pendingRequests.size === 1) {
1855
- this.ngZone.runOutsideAngular(() => {
1856
- this.currentTimeoutHandle = setTimeout(() => this.ngZone.run(() => {
1857
- // console.log('timeout: flushing requests')
1858
- this.flushRequests();
1859
- }), this.batchCollectionDelayMs);
1860
- });
1852
+ this.addPendingRequest(caseId, subject);
1853
+ if (wasEmpty) {
1854
+ this.ngZone.runOutsideAngular(() => {
1855
+ this.currentTimeoutHandle = setTimeout(() => this.ngZone.run(() => {
1856
+ this.flushRequests();
1857
+ }), this.batchCollectionDelayMs);
1858
+ });
1859
+ }
1861
1860
  }
1862
1861
  if (this.pendingRequests.size >= this.maxRequestsPerBatch) {
1863
1862
  // console.log('max pending hit: flushing requests');
@@ -1875,6 +1874,9 @@ class ActivityPollingService {
1875
1874
  clearTimeout(this.currentTimeoutHandle);
1876
1875
  this.currentTimeoutHandle = undefined;
1877
1876
  }
1877
+ if (!this.pendingRequests.size) {
1878
+ return;
1879
+ }
1878
1880
  const requests = new Map(this.pendingRequests);
1879
1881
  this.pendingRequests.clear();
1880
1882
  this.performBatchRequest(requests);
@@ -1883,7 +1885,7 @@ class ActivityPollingService {
1883
1885
  if (!this.isEnabled) {
1884
1886
  return EMPTY;
1885
1887
  }
1886
- return polling(this.activityService.getActivities(...caseIds), this.pollConfig);
1888
+ return this.polling(this.activityService.getActivities(...caseIds), this.pollConfig);
1887
1889
  }
1888
1890
  postViewActivity(caseId) {
1889
1891
  return this.postActivity(caseId, ActivityService.ACTIVITY_VIEW);
@@ -1896,17 +1898,19 @@ class ActivityPollingService {
1896
1898
  // console.log('issuing batch request for cases: ' + caseIds);
1897
1899
  this.ngZone.runOutsideAngular(() => {
1898
1900
  // run polling outside angular zone so it does not trigger change detection
1899
- this.pollActivitiesSubscription = this.pollActivities(caseIds).subscribe(
1900
- // process activity inside zone so it triggers change detection for activity.component.ts
1901
- (activities) => this.ngZone.run(() => {
1902
- activities.forEach((activity) => {
1903
- // console.log('pushing activity: ' + activity.caseId);
1904
- requests.get(activity.caseId).next(activity);
1905
- });
1906
- }, (err) => {
1907
- console.log(`error: ${err}`);
1908
- Array.from(requests.values()).forEach((subject) => subject.error(err));
1909
- }));
1901
+ this.pollActivitiesSubscription = this.pollActivities(caseIds).subscribe({
1902
+ // process activity inside zone so it triggers change detection for activity.component.ts
1903
+ next: (activities) => this.ngZone.run(() => {
1904
+ activities.forEach((activity) => {
1905
+ // Ignore activities returned for cases outside this local batch.
1906
+ requests.get(activity.caseId)?.next(activity);
1907
+ });
1908
+ }),
1909
+ error: (err) => this.ngZone.run(() => {
1910
+ console.log(`error: ${err}`);
1911
+ Array.from(requests.values()).forEach((subject) => subject.error(err));
1912
+ })
1913
+ });
1910
1914
  });
1911
1915
  }
1912
1916
  postActivity(caseId, activityType) {
@@ -1917,7 +1921,42 @@ class ActivityPollingService {
1917
1921
  ...this.pollConfig,
1918
1922
  interval: 5000 // inline with CCD Backend
1919
1923
  };
1920
- return polling(this.activityService.postActivity(caseId, activityType), pollingConfig);
1924
+ return this.polling(this.activityService.postActivity(caseId, activityType), pollingConfig);
1925
+ }
1926
+ addPendingRequest(caseId, subject) {
1927
+ this.pendingRequests.set(caseId, subject);
1928
+ // Components complete their returned Subject on destroy; remove it so a later same-case subscription gets a fresh Subject.
1929
+ subject.subscribe({
1930
+ complete: () => this.removePendingRequest(caseId, subject),
1931
+ error: () => this.removePendingRequest(caseId, subject)
1932
+ });
1933
+ }
1934
+ removePendingRequest(caseId, subject) {
1935
+ if (this.pendingRequests.get(caseId) !== subject) {
1936
+ return;
1937
+ }
1938
+ this.pendingRequests.delete(caseId);
1939
+ if (!this.pendingRequests.size && this.currentTimeoutHandle) {
1940
+ clearTimeout(this.currentTimeoutHandle);
1941
+ this.currentTimeoutHandle = undefined;
1942
+ }
1943
+ }
1944
+ polling(request$, options) {
1945
+ const pollingOptions = {
1946
+ interval: options.interval,
1947
+ attempts: options.attempts ?? 9,
1948
+ exponentialUnit: options.exponentialUnit ?? 1000
1949
+ };
1950
+ return concat(request$, defer(() => timer(pollingOptions.interval).pipe(switchMap(() => request$))).pipe(repeat())).pipe(
1951
+ // Preserve consecutive-failure retry behaviour using the current RxJS retry config.
1952
+ retry({
1953
+ count: pollingOptions.attempts,
1954
+ delay: (_error, retryCount) => timer(this.getExponentialRetryDelay(retryCount, pollingOptions.exponentialUnit)),
1955
+ resetOnSuccess: true
1956
+ }));
1957
+ }
1958
+ getExponentialRetryDelay(consecutiveErrorsCount, exponentialUnit) {
1959
+ return Math.pow(2, consecutiveErrorsCount - 1) * exponentialUnit;
1921
1960
  }
1922
1961
  static ɵfac = function ActivityPollingService_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ActivityPollingService)(i0.ɵɵinject(ActivityService), i0.ɵɵinject(i0.NgZone), i0.ɵɵinject(AbstractAppConfig)); };
1923
1962
  static ɵprov = /*@__PURE__*/ i0.ɵɵdefineInjectable({ token: ActivityPollingService, factory: ActivityPollingService.ɵfac });
@@ -9978,7 +10017,7 @@ class CaseEditComponent {
9978
10017
  return of(true);
9979
10018
  }
9980
10019
  finishEventCompletionLogic(eventResponse) {
9981
- this.caseNotifier.removeCachedCase();
10020
+ this.caseNotifier.cachedCaseView = null;
9982
10021
  this.sessionStorageService.removeItem('eventUrl');
9983
10022
  const confirmation = this.buildConfirmation(eventResponse);
9984
10023
  if (confirmation && (confirmation.getHeader() || confirmation.getBody())) {
@@ -11813,8 +11852,6 @@ class CaseEditPageComponent {
11813
11852
  else {
11814
11853
  this.caseEdit.cancelled.emit();
11815
11854
  }
11816
- // clear CaseView cache to allow any incidental changes to get picked up once the edit has cancelled
11817
- this.caseEdit.caseNotifier.removeCachedCase();
11818
11855
  this.caseEditDataService.clearFormValidationErrors();
11819
11856
  this.multipageComponentStateService.reset();
11820
11857
  }