@newheap/platform-common 0.20.6 → 1.0.0

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.
@@ -6,12 +6,11 @@ import * as i0 from '@angular/core';
6
6
  import { Injectable, PLATFORM_ID, REQUEST_CONTEXT, Inject, Optional, inject, NgZone, forwardRef, InjectionToken, afterNextRender, makeStateKey, Directive, input, Input, Component, viewChild, output, HostListener, EventEmitter, Pipe, HostBinding, ChangeDetectionStrategy, Output, ViewChild, ViewEncapsulation, model, ErrorHandler, provideAppInitializer, SkipSelf, NgModule } from '@angular/core';
7
7
  import * as i1$3 from '@angular/common';
8
8
  import { isPlatformServer, DOCUMENT, isPlatformBrowser, DatePipe, CommonModule } from '@angular/common';
9
- import { BehaviorSubject, lastValueFrom, tap, filter, map, Subject, share, switchMap, EMPTY, timer, from, Observable, of } from 'rxjs';
9
+ import { BehaviorSubject, lastValueFrom, tap, filter, map, Subject, share, switchMap, EMPTY, timer, exhaustMap, from, Subscription, defer, finalize as finalize$1, catchError, of, Observable } from 'rxjs';
10
10
  import * as i1 from 'ngx-cookie-service';
11
11
  import { DateTime } from 'luxon';
12
12
  import { Base64 } from 'js-base64';
13
13
  import { finalize, shareReplay, takeUntil, debounceTime, distinctUntilChanged } from 'rxjs/operators';
14
- import * as Sentry from '@sentry/angular';
15
14
  import * as i1$1 from '@angular/router';
16
15
  import { NavigationEnd, NavigationSkipped, NavigationSkippedCode, NavigationStart, Router, ActivatedRoute, RouterLink } from '@angular/router';
17
16
  import * as i2 from '@ngx-translate/core';
@@ -54,19 +53,13 @@ class UserNotificationNhCommonModuleConfig {
54
53
  Object.assign(this, init);
55
54
  }
56
55
  }
57
- class NhSentryErrorLoggingNhCommonModuleConfig {
56
+ class BackgroundOperationsNhCommonModuleConfig {
58
57
  constructor(init) {
59
- this.errorLoggingEnabled = false;
60
- this.tracingEnabled = false;
61
- this.beforeSendAddAuthServiceInformation = true;
62
- this.options = {};
63
- this.errorHandlerOptions = {};
64
- Object.assign(this, init);
65
- }
66
- }
67
- class NhErrorLoggingNhCommonModuleConfig {
68
- constructor(init) {
69
- this.sentry = new NhSentryErrorLoggingNhCommonModuleConfig();
58
+ this.urlSuffix = '/background-operations';
59
+ this.hubUrlSuffix = '/hub/background-operations';
60
+ this.pollingInterval = 5000;
61
+ this.liveUpdatesEnabled = true;
62
+ this.listPageSize = 100;
70
63
  Object.assign(this, init);
71
64
  }
72
65
  }
@@ -116,7 +109,7 @@ class NhCommonModuleConfig {
116
109
  this.defaultDateTimeFormat = 'dd-MM-yyyy HH:mm:ss';
117
110
  this.authentication = new AuthenticationNhCommonModuleConfig();
118
111
  this.userNotification = new UserNotificationNhCommonModuleConfig();
119
- this.errorLogging = new NhErrorLoggingNhCommonModuleConfig();
112
+ this.backgroundOperations = new BackgroundOperationsNhCommonModuleConfig();
120
113
  this.translation = new NhTranslationNhCommonModuleConfig();
121
114
  this.formDropdown = new NhFormDropDownNhCommonModuleConfig();
122
115
  this.http = new NhHttpNhCommonModuleConfig();
@@ -676,6 +669,50 @@ class NhUserNotificationData {
676
669
  }
677
670
  }
678
671
 
672
+ class NhBackgroundOperationCollectionHttpRequestOptions extends CollectionHttpRequestOptions {
673
+ constructor(init) {
674
+ super(init);
675
+ Object.assign(this, init);
676
+ }
677
+ }
678
+ function nhBackgroundOperationStatusName(status) {
679
+ if (typeof status === 'string') {
680
+ return status;
681
+ }
682
+ return {
683
+ 0: 'PendingDispatch',
684
+ 10: 'Queued',
685
+ 20: 'Running',
686
+ 25: 'WaitingForChildren',
687
+ 30: 'CancelRequested',
688
+ 40: 'RetryScheduled',
689
+ 100: 'Succeeded',
690
+ 110: 'Failed',
691
+ 120: 'Cancelled',
692
+ 130: 'TimedOut'
693
+ }[status] ?? 'Unknown';
694
+ }
695
+ function nhBackgroundOperationStepStatusName(status) {
696
+ if (typeof status === 'string') {
697
+ return status;
698
+ }
699
+ return {
700
+ 0: 'Pending',
701
+ 10: 'Running',
702
+ 100: 'Succeeded',
703
+ 110: 'Failed',
704
+ 120: 'Skipped',
705
+ 130: 'Cancelled',
706
+ 140: 'Indeterminate'
707
+ }[status] ?? 'Unknown';
708
+ }
709
+ function nhBackgroundOperationTranslationSegment(value) {
710
+ return value
711
+ .replace(/([a-z0-9])([A-Z])/g, '$1-$2')
712
+ .replace(/[_\s]+/g, '-')
713
+ .toLowerCase();
714
+ }
715
+
679
716
  const languageToCultureMap = {
680
717
  'nl': 'nl-NL',
681
718
  'en': 'en-US',
@@ -2901,7 +2938,15 @@ class NhErrorHandlerService {
2901
2938
  }
2902
2939
  handleError(error) {
2903
2940
  const handlers = this.injector.get(NH_ERROR_HANDLERS, []);
2904
- handlers.forEach(handle => handle.handleError(error));
2941
+ for (const handler of handlers) {
2942
+ try {
2943
+ handler.handleError(error);
2944
+ }
2945
+ catch {
2946
+ // A failing telemetry provider must not prevent the remaining handlers
2947
+ // from observing the original application error.
2948
+ }
2949
+ }
2905
2950
  }
2906
2951
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: NhErrorHandlerService, deps: [{ token: i0.Injector }], target: i0.ɵɵFactoryTarget.Injectable }); }
2907
2952
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: NhErrorHandlerService, providedIn: 'root' }); }
@@ -2911,322 +2956,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImpo
2911
2956
  args: [{ providedIn: 'root' }]
2912
2957
  }], ctorParameters: () => [{ type: i0.Injector }] });
2913
2958
 
2914
- const NH_SENTRY_BEFORE_SEND_HOOKS = new InjectionToken("NH_SENTRY_BEFORE_SEND_HOOKS");
2915
- const NH_SENTRY_BEFORE_SEND_LOG_HOOKS = new InjectionToken("NH_SENTRY_BEFORE_SEND_LOG_HOOKS");
2916
- const NH_SENTRY_BEFORE_SEND_SPAN_HOOKS = new InjectionToken("NH_SENTRY_BEFORE_SEND_SPAN_HOOKS");
2917
- const NH_SENTRY_BEFORE_SEND_TRANSACTION_HOOKS = new InjectionToken("NH_SENTRY_BEFORE_SEND_TRANSACTION_HOOKS");
2918
- const NH_SENTRY_BEFORE_BREADCRUMB_HOOKS = new InjectionToken("NH_SENTRY_BEFORE_BREADCRUMB_HOOKS");
2919
- class NhSentryInitializerService {
2920
- get hooksBeforeSend() {
2921
- return [...this.providedHooksBeforeSend, ...this.runtimeHooksBeforeSend];
2922
- }
2923
- get hooksBeforeSendLog() {
2924
- return [...this.providedHooksBeforeSendLog, ...this.runtimeHooksBeforeSendLog];
2925
- }
2926
- get hooksBeforeSendSpan() {
2927
- return [...this.providedHooksBeforeSendSpan, ...this.runtimeHooksBeforeSendSpan];
2928
- }
2929
- get hooksBeforeSendTransaction() {
2930
- return [...this.providedHooksBeforeSendTransaction, ...this.runtimeHooksBeforeSendTransaction];
2931
- }
2932
- get hooksBeforeBreadcrumb() {
2933
- return [...this.providedHooksBeforeBreadcrumb, ...this.runtimeHooksBeforeBreadcrumb];
2934
- }
2935
- get isEnabled() {
2936
- return this._sentryConfig.errorLoggingEnabled || this._sentryConfig.tracingEnabled;
2937
- }
2938
- get isInitializedAndEnabled() {
2939
- return this._didInitialize && this.isEnabled;
2940
- }
2941
- get sentry() {
2942
- return Sentry;
2943
- }
2944
- constructor(moduleConfig, authService, providedHooksBeforeSend = [], providedHooksBeforeSendLog = [], providedHooksBeforeSendSpan = [], providedHooksBeforeSendTransaction = [], providedHooksBeforeBreadcrumb = []) {
2945
- this.moduleConfig = moduleConfig;
2946
- this.authService = authService;
2947
- this.providedHooksBeforeSend = providedHooksBeforeSend;
2948
- this.providedHooksBeforeSendLog = providedHooksBeforeSendLog;
2949
- this.providedHooksBeforeSendSpan = providedHooksBeforeSendSpan;
2950
- this.providedHooksBeforeSendTransaction = providedHooksBeforeSendTransaction;
2951
- this.providedHooksBeforeBreadcrumb = providedHooksBeforeBreadcrumb;
2952
- this._didInitialize = false;
2953
- this.runtimeHooksBeforeSend = [];
2954
- this.runtimeHooksBeforeSendLog = [];
2955
- this.runtimeHooksBeforeSendSpan = [];
2956
- this.runtimeHooksBeforeSendTransaction = [];
2957
- this.runtimeHooksBeforeBreadcrumb = [];
2958
- this._sentryConfig = this.moduleConfig.errorLogging.sentry;
2959
- this.$auth = this.authService.authSubject.subscribe(async (authorization) => {
2960
- await this.authChanged(authorization);
2961
- });
2962
- this.initialize();
2963
- }
2964
- async authChanged(authorization) {
2965
- this.authorization = authorization;
2966
- if (!this.isInitializedAndEnabled) {
2967
- return;
2968
- }
2969
- }
2970
- registerHookBeforeSend(hook) {
2971
- this.runtimeHooksBeforeSend.push(hook);
2972
- }
2973
- registerHookBeforeSendLog(hook) {
2974
- this.runtimeHooksBeforeSendLog.push(hook);
2975
- }
2976
- registerHookBeforeSendSpan(hook) {
2977
- this.runtimeHooksBeforeSendSpan.push(hook);
2978
- }
2979
- registerHookBeforeSendTransaction(hook) {
2980
- this.runtimeHooksBeforeSendTransaction.push(hook);
2981
- }
2982
- registerHookBeforeBreadcrumb(hook) {
2983
- this.runtimeHooksBeforeBreadcrumb.push(hook);
2984
- }
2985
- async ourBeforeSendHook(event, hint) {
2986
- if (this._sentryConfig.beforeSendAddAuthServiceInformation
2987
- && this.authorization) {
2988
- const user = event.user ?? {};
2989
- user.id = this.authorization.user.id,
2990
- user.email = this.authorization.user.email,
2991
- user.username = this.authorization.user.email,
2992
- user.roles = (this.authorization.user.roles ?? []).join(', ');
2993
- if (this.authorization.activeDivision) {
2994
- user.activeDivisionId = this.authorization.activeDivision.id;
2995
- user.activeDivisionName = this.authorization.activeDivision.name;
2996
- }
2997
- event.user = user;
2998
- }
2999
- return event;
3000
- }
3001
- initialize() {
3002
- if (this._didInitialize) {
3003
- return;
3004
- }
3005
- this.registerHookBeforeSend(this.ourBeforeSendHook.bind(this));
3006
- if (!this.isEnabled) {
3007
- if (!Sentry.isInitialized()) {
3008
- const options = this.moduleConfig.errorLogging.sentry.options;
3009
- Sentry.init({
3010
- ...options,
3011
- beforeSend: (event, hint) => this.runHooksBeforeSend(event, hint),
3012
- beforeSendLog: (event) => this.runHooksBeforeSendLog(event),
3013
- beforeSendSpan: (event) => this.runHooksBeforeSendSpan(event),
3014
- beforeSendTransaction: (event, hint) => this.runHooksBeforeSendTransaction(event, hint),
3015
- beforeBreadcrumb: (event, hint) => this.runHooksBeforeBreadcrumb(event, hint),
3016
- });
3017
- }
3018
- }
3019
- this._didInitialize = true;
3020
- }
3021
- async runHooksBeforeSend(initialEvent, hint) {
3022
- const all = [...this.providedHooksBeforeSend, ...this.runtimeHooksBeforeSend];
3023
- let current = initialEvent;
3024
- for (const hook of all) {
3025
- if (!current)
3026
- return null;
3027
- current = await hook(current, hint);
3028
- }
3029
- return current;
3030
- }
3031
- runHooksBeforeSendLog(initialEvent) {
3032
- const all = [...this.providedHooksBeforeSendLog, ...this.runtimeHooksBeforeSendLog];
3033
- let current = initialEvent;
3034
- for (const hook of all) {
3035
- if (!current)
3036
- return null;
3037
- current = hook(current);
3038
- }
3039
- return current;
3040
- }
3041
- runHooksBeforeSendSpan(initialSpan) {
3042
- const all = [...this.providedHooksBeforeSendSpan, ...this.runtimeHooksBeforeSendSpan];
3043
- let current = initialSpan;
3044
- for (const hook of all) {
3045
- current = hook(current);
3046
- }
3047
- return current;
3048
- }
3049
- async runHooksBeforeSendTransaction(initialEvent, hint) {
3050
- const all = [...this.providedHooksBeforeSendTransaction, ...this.runtimeHooksBeforeSendTransaction];
3051
- let current = initialEvent;
3052
- for (const hook of all) {
3053
- if (!current)
3054
- return null;
3055
- current = await hook(current, hint);
3056
- }
3057
- return current;
3058
- }
3059
- runHooksBeforeBreadcrumb(initialBreadcrumb, hint) {
3060
- const all = [...this.providedHooksBeforeBreadcrumb, ...this.runtimeHooksBeforeBreadcrumb];
3061
- let current = initialBreadcrumb;
3062
- for (const hook of all) {
3063
- if (!current)
3064
- return null;
3065
- current = hook(current, hint);
3066
- }
3067
- return current;
3068
- }
3069
- ngOnDestroy() {
3070
- this.$auth?.unsubscribe();
3071
- }
3072
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: NhSentryInitializerService, deps: [{ token: NhCommonModuleConfig }, { token: NhAuthService }, { token: NH_SENTRY_BEFORE_SEND_HOOKS, optional: true }, { token: NH_SENTRY_BEFORE_SEND_LOG_HOOKS, optional: true }, { token: NH_SENTRY_BEFORE_SEND_SPAN_HOOKS, optional: true }, { token: NH_SENTRY_BEFORE_SEND_TRANSACTION_HOOKS, optional: true }, { token: NH_SENTRY_BEFORE_BREADCRUMB_HOOKS, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
3073
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: NhSentryInitializerService, providedIn: "root" }); }
3074
- }
3075
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: NhSentryInitializerService, decorators: [{
3076
- type: Injectable,
3077
- args: [{
3078
- providedIn: "root"
3079
- }]
3080
- }], ctorParameters: () => [{ type: NhCommonModuleConfig }, { type: NhAuthService }, { type: undefined, decorators: [{
3081
- type: Optional
3082
- }, {
3083
- type: Inject,
3084
- args: [NH_SENTRY_BEFORE_SEND_HOOKS]
3085
- }] }, { type: undefined, decorators: [{
3086
- type: Optional
3087
- }, {
3088
- type: Inject,
3089
- args: [NH_SENTRY_BEFORE_SEND_LOG_HOOKS]
3090
- }] }, { type: undefined, decorators: [{
3091
- type: Optional
3092
- }, {
3093
- type: Inject,
3094
- args: [NH_SENTRY_BEFORE_SEND_SPAN_HOOKS]
3095
- }] }, { type: undefined, decorators: [{
3096
- type: Optional
3097
- }, {
3098
- type: Inject,
3099
- args: [NH_SENTRY_BEFORE_SEND_TRANSACTION_HOOKS]
3100
- }] }, { type: undefined, decorators: [{
3101
- type: Optional
3102
- }, {
3103
- type: Inject,
3104
- args: [NH_SENTRY_BEFORE_BREADCRUMB_HOOKS]
3105
- }] }] });
3106
- class NhSentryService {
3107
- get isEnabled() {
3108
- return this.sentryInitializerService.isEnabled;
3109
- }
3110
- get isInitializedAndEnabled() {
3111
- return this.sentryInitializerService.isInitializedAndEnabled;
3112
- }
3113
- get sentry() {
3114
- return Sentry;
3115
- }
3116
- constructor(moduleConfig, sentryInitializerService) {
3117
- this.moduleConfig = moduleConfig;
3118
- this.sentryInitializerService = sentryInitializerService;
3119
- this._sentryConfig = this.moduleConfig.errorLogging.sentry;
3120
- }
3121
- registerHookBeforeSend(hook) {
3122
- this.sentryInitializerService.registerHookBeforeSend(hook);
3123
- }
3124
- registerHookBeforeSendLog(hook) {
3125
- this.sentryInitializerService.registerHookBeforeSendLog(hook);
3126
- }
3127
- registerHookBeforeSendSpan(hook) {
3128
- this.sentryInitializerService.registerHookBeforeSendSpan(hook);
3129
- }
3130
- registerHookBeforeSendTransaction(hook) {
3131
- this.sentryInitializerService.registerHookBeforeSendTransaction(hook);
3132
- }
3133
- registerHookBeforeBreadcrumb(hook) {
3134
- this.sentryInitializerService.registerHookBeforeBreadcrumb(hook);
3135
- }
3136
- ngOnDestroy() {
3137
- }
3138
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: NhSentryService, deps: [{ token: NhCommonModuleConfig }, { token: NhSentryInitializerService }], target: i0.ɵɵFactoryTarget.Injectable }); }
3139
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: NhSentryService, providedIn: "root" }); }
3140
- }
3141
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: NhSentryService, decorators: [{
3142
- type: Injectable,
3143
- args: [{
3144
- providedIn: "root"
3145
- }]
3146
- }], ctorParameters: () => [{ type: NhCommonModuleConfig }, { type: NhSentryInitializerService }] });
3147
-
3148
- class NhErrorHandlerSentryService {
3149
- get sentryErrorHandler() {
3150
- return this._sentryErrorHandler;
3151
- }
3152
- constructor(moduleConfig, sentryInitializerService) {
3153
- this.moduleConfig = moduleConfig;
3154
- this.sentryInitializerService = sentryInitializerService;
3155
- this._didInitialize = false;
3156
- this.initialize();
3157
- }
3158
- initialize() {
3159
- if (!this.moduleConfig.errorLogging.sentry.errorLoggingEnabled) {
3160
- this._sentryErrorHandler?.ngOnDestroy();
3161
- this._sentryErrorHandler = undefined;
3162
- return;
3163
- }
3164
- if (this._didInitialize) {
3165
- return;
3166
- }
3167
- this.sentryInitializerService.initialize();
3168
- this._sentryErrorHandler = Sentry.createErrorHandler(this.moduleConfig.errorLogging.sentry.errorHandlerOptions);
3169
- this._didInitialize = true;
3170
- }
3171
- handleError(error) {
3172
- this.initialize();
3173
- if (!this.moduleConfig.errorLogging.sentry.errorLoggingEnabled) {
3174
- return;
3175
- }
3176
- this._sentryErrorHandler?.handleError(error);
3177
- }
3178
- ngOnDestroy() {
3179
- this._sentryErrorHandler?.ngOnDestroy();
3180
- this._sentryErrorHandler = undefined;
3181
- }
3182
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: NhErrorHandlerSentryService, deps: [{ token: NhCommonModuleConfig }, { token: NhSentryInitializerService }], target: i0.ɵɵFactoryTarget.Injectable }); }
3183
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: NhErrorHandlerSentryService, providedIn: "root" }); }
3184
- }
3185
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: NhErrorHandlerSentryService, decorators: [{
3186
- type: Injectable,
3187
- args: [{
3188
- providedIn: "root"
3189
- }]
3190
- }], ctorParameters: () => [{ type: NhCommonModuleConfig }, { type: NhSentryInitializerService }] });
3191
-
3192
- class NhSentryTraceService {
3193
- get sentryTraceService() {
3194
- return this._sentryTraceService;
3195
- }
3196
- constructor(moduleConfig, sentryInitializerService, router) {
3197
- this.moduleConfig = moduleConfig;
3198
- this.sentryInitializerService = sentryInitializerService;
3199
- this.router = router;
3200
- this._didInitialize = false;
3201
- this.initialize();
3202
- }
3203
- initialize() {
3204
- if (!this.moduleConfig.errorLogging.sentry.tracingEnabled) {
3205
- this._sentryTraceService?.ngOnDestroy();
3206
- this._sentryTraceService = undefined;
3207
- return;
3208
- }
3209
- if (this._didInitialize) {
3210
- return;
3211
- }
3212
- this.sentryInitializerService.initialize();
3213
- this._sentryTraceService = new Sentry.TraceService(this.router);
3214
- this._didInitialize = true;
3215
- }
3216
- ngOnDestroy() {
3217
- this._sentryTraceService?.ngOnDestroy();
3218
- this._sentryTraceService = undefined;
3219
- }
3220
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: NhSentryTraceService, deps: [{ token: NhCommonModuleConfig }, { token: NhSentryInitializerService }, { token: i1$1.Router }], target: i0.ɵɵFactoryTarget.Injectable }); }
3221
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: NhSentryTraceService, providedIn: "root" }); }
3222
- }
3223
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: NhSentryTraceService, decorators: [{
3224
- type: Injectable,
3225
- args: [{
3226
- providedIn: "root"
3227
- }]
3228
- }], ctorParameters: () => [{ type: NhCommonModuleConfig }, { type: NhSentryInitializerService }, { type: i1$1.Router }] });
3229
-
3230
2959
  const APP_ORIGINATED_FROM_SERVER = 'APP_ORIGINATED_FROM_SERVER';
3231
2960
  class NhAppService {
3232
2961
  constructor(document, platformId, appRef, transferState, router) {
@@ -5613,7 +5342,7 @@ class NhUserNotificationService {
5613
5342
  ngOnDestroy() {
5614
5343
  this.taskSub?.unsubscribe();
5615
5344
  this.runningSubject.complete();
5616
- this.userNotificationStateSubject?.unsubscribe();
5345
+ this.userNotificationStateSubject.complete();
5617
5346
  }
5618
5347
  constructor(appService) {
5619
5348
  this.appService = appService;
@@ -5622,23 +5351,33 @@ class NhUserNotificationService {
5622
5351
  this.apiService = inject(NhApiService);
5623
5352
  this.runningSubject = new BehaviorSubject(false);
5624
5353
  this.isRunning$ = this.runningSubject.asObservable();
5354
+ this.runningConsumers = 0;
5625
5355
  this.userNotificationState = new NhUserNotificationState();
5626
5356
  this.userNotificationStateSubject = new BehaviorSubject(this.userNotificationState);
5627
5357
  this.userNotificationState$ = this.userNotificationStateSubject.asObservable();
5628
5358
  if (!this.appService.isPlatformServer()) {
5629
5359
  this.task$ = this.runningSubject.pipe(switchMap(isRunning => isRunning
5630
- ? timer(0, this.moduleConfig.userNotification.pollingInterval).pipe(tap(() => from(this.doWork())), takeUntil(this.runningSubject.pipe(switchMap(r => r ? EMPTY : EMPTY))))
5360
+ ? timer(0, this.moduleConfig.userNotification.pollingInterval).pipe(exhaustMap(() => from(this.doWork())))
5631
5361
  : EMPTY));
5632
5362
  this.taskSub = this.task$.subscribe();
5633
5363
  }
5634
5364
  this.baseUrl = this.moduleConfig.apiBaseUrl + this.urlSuffix;
5635
5365
  }
5636
- start() { if (this.isRunning()) {
5637
- return;
5638
- } this.runningSubject.next(true); }
5639
- stop() { if (!this.isRunning()) {
5640
- return;
5641
- } this.runningSubject.next(false); }
5366
+ start() {
5367
+ this.runningConsumers++;
5368
+ if (this.runningConsumers === 1) {
5369
+ this.runningSubject.next(true);
5370
+ }
5371
+ }
5372
+ stop() {
5373
+ if (this.runningConsumers === 0) {
5374
+ return;
5375
+ }
5376
+ this.runningConsumers--;
5377
+ if (this.runningConsumers === 0) {
5378
+ this.runningSubject.next(false);
5379
+ }
5380
+ }
5642
5381
  async doWork() {
5643
5382
  if (!this.isRunning()) {
5644
5383
  return;
@@ -5684,6 +5423,479 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImpo
5684
5423
  }]
5685
5424
  }], ctorParameters: () => [{ type: NhAppService }] });
5686
5425
 
5426
+ class NhBackgroundOperationService {
5427
+ constructor() {
5428
+ this.config = inject(NhCommonModuleConfig);
5429
+ this.api = inject(NhApiService);
5430
+ this.baseUrl = this.joinUrl(this.config.apiBaseUrl, this.config.backgroundOperations.urlSuffix);
5431
+ }
5432
+ list(request = new NhBackgroundOperationCollectionHttpRequestOptions({
5433
+ page: 1,
5434
+ itemsPerPage: this.config.backgroundOperations.listPageSize
5435
+ })) {
5436
+ return this.api.getCollection(this.baseUrl, request);
5437
+ }
5438
+ get(operationId, eventsAfterSequence) {
5439
+ let params = new HttpParams();
5440
+ if (eventsAfterSequence !== undefined) {
5441
+ params = params.set('eventsAfterSequence', eventsAfterSequence.toString());
5442
+ }
5443
+ return this.api.get(`${this.baseUrl}/${encodeURIComponent(operationId)}`, new HttpRequestOptions({ params }));
5444
+ }
5445
+ cancel(operationId) {
5446
+ return this.api.post(`${this.baseUrl}/${encodeURIComponent(operationId)}/cancel`, {});
5447
+ }
5448
+ retry(operationId) {
5449
+ return this.api.post(`${this.baseUrl}/${encodeURIComponent(operationId)}/retry`, {});
5450
+ }
5451
+ joinUrl(base, suffix) {
5452
+ return `${base.replace(/\/$/, '')}/${suffix.replace(/^\//, '')}`;
5453
+ }
5454
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: NhBackgroundOperationService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
5455
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: NhBackgroundOperationService, providedIn: 'root' }); }
5456
+ }
5457
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: NhBackgroundOperationService, decorators: [{
5458
+ type: Injectable,
5459
+ args: [{ providedIn: 'root' }]
5460
+ }] });
5461
+
5462
+ class NhBackgroundOperationLiveUpdateService {
5463
+ constructor(config, auth, app) {
5464
+ this.config = config;
5465
+ this.auth = auth;
5466
+ this.app = app;
5467
+ this.changedSubject = new Subject();
5468
+ this.resyncSubject = new Subject();
5469
+ this.connectionStateSubject = new BehaviorSubject('disconnected');
5470
+ this.consumers = 0;
5471
+ this.changed$ = this.changedSubject.asObservable();
5472
+ this.resync$ = this.resyncSubject.asObservable();
5473
+ this.connectionState$ = this.connectionStateSubject.asObservable();
5474
+ this.authorizationScopeKey = this.getAuthorizationScopeKey();
5475
+ if (!config.backgroundOperations.liveUpdatesEnabled || app.isPlatformServer()) {
5476
+ this.connectionStateSubject.next('disabled');
5477
+ }
5478
+ this.authSubscription = auth.authSubject.subscribe(() => {
5479
+ const nextScopeKey = this.getAuthorizationScopeKey();
5480
+ if (nextScopeKey === this.authorizationScopeKey) {
5481
+ return;
5482
+ }
5483
+ this.authorizationScopeKey = nextScopeKey;
5484
+ if (this.consumers > 0 && this.isEnabled()) {
5485
+ void this.restart();
5486
+ }
5487
+ });
5488
+ }
5489
+ start() {
5490
+ this.consumers++;
5491
+ if (this.consumers === 1 && this.isEnabled()) {
5492
+ void this.ensureConnected();
5493
+ }
5494
+ }
5495
+ stop() {
5496
+ if (this.consumers === 0) {
5497
+ return;
5498
+ }
5499
+ this.consumers--;
5500
+ if (this.consumers === 0) {
5501
+ this.clearReconnectTimer();
5502
+ void this.stopConnection();
5503
+ }
5504
+ }
5505
+ ngOnDestroy() {
5506
+ this.consumers = 0;
5507
+ this.clearReconnectTimer();
5508
+ this.authSubscription.unsubscribe();
5509
+ void this.stopConnection();
5510
+ this.changedSubject.complete();
5511
+ this.resyncSubject.complete();
5512
+ this.connectionStateSubject.complete();
5513
+ }
5514
+ isEnabled() {
5515
+ return this.config.backgroundOperations.liveUpdatesEnabled && !this.app.isPlatformServer();
5516
+ }
5517
+ async restart() {
5518
+ await this.stopConnection();
5519
+ if (this.consumers > 0) {
5520
+ await this.ensureConnected();
5521
+ }
5522
+ }
5523
+ ensureConnected() {
5524
+ if (this.connectPromise) {
5525
+ return this.connectPromise;
5526
+ }
5527
+ if (this.connection?.state === 'Connected') {
5528
+ return Promise.resolve();
5529
+ }
5530
+ this.connectPromise = this.connectCore().finally(() => {
5531
+ this.connectPromise = undefined;
5532
+ });
5533
+ return this.connectPromise;
5534
+ }
5535
+ async connectCore() {
5536
+ this.connectionStateSubject.next('connecting');
5537
+ try {
5538
+ this.connection ??= await this.buildConnection();
5539
+ await this.connection.start();
5540
+ this.connectionStateSubject.next('connected');
5541
+ this.resyncSubject.next();
5542
+ }
5543
+ catch {
5544
+ this.connectionStateSubject.next('disconnected');
5545
+ this.scheduleReconnect();
5546
+ }
5547
+ }
5548
+ async buildConnection() {
5549
+ const signalR = await import('@microsoft/signalr');
5550
+ const baseHubUrl = this.joinUrl(this.config.backgroundOperations.hubBaseUrl || this.config.baseUrl || this.config.apiBaseUrl, this.config.backgroundOperations.hubUrlSuffix);
5551
+ const divisionId = this.auth.getAuthorization()?.activeDivision?.id;
5552
+ const hubUrl = divisionId
5553
+ ? this.appendQueryParameter(baseHubUrl, 'divisionId', divisionId)
5554
+ : baseHubUrl;
5555
+ const connection = new signalR.HubConnectionBuilder()
5556
+ .withUrl(hubUrl, {
5557
+ withCredentials: true,
5558
+ accessTokenFactory: () => this.config.authType === 'header'
5559
+ ? this.auth.getAuthorization()?.token ?? ''
5560
+ : ''
5561
+ })
5562
+ .withAutomaticReconnect([0, 2000, 5000, 10000, 30000])
5563
+ .configureLogging(signalR.LogLevel.Warning)
5564
+ .build();
5565
+ connection.on('OperationChanged', (change) => {
5566
+ this.changedSubject.next(change);
5567
+ });
5568
+ connection.onreconnecting(() => this.connectionStateSubject.next('reconnecting'));
5569
+ connection.onreconnected(() => {
5570
+ this.connectionStateSubject.next('connected');
5571
+ this.resyncSubject.next();
5572
+ });
5573
+ connection.onclose(() => {
5574
+ this.connectionStateSubject.next('disconnected');
5575
+ this.scheduleReconnect();
5576
+ });
5577
+ return connection;
5578
+ }
5579
+ async stopConnection() {
5580
+ const connection = this.connection;
5581
+ this.connection = undefined;
5582
+ this.connectPromise = undefined;
5583
+ if (connection && connection.state !== 'Disconnected') {
5584
+ try {
5585
+ await connection.stop();
5586
+ }
5587
+ catch {
5588
+ // A failed transport is already disconnected from the application's
5589
+ // perspective. Polling remains the durable fallback.
5590
+ }
5591
+ }
5592
+ if (this.isEnabled()) {
5593
+ this.connectionStateSubject.next('disconnected');
5594
+ }
5595
+ }
5596
+ scheduleReconnect() {
5597
+ if (this.consumers === 0 || this.reconnectTimer || !this.isEnabled()) {
5598
+ return;
5599
+ }
5600
+ this.reconnectTimer = setTimeout(() => {
5601
+ this.reconnectTimer = undefined;
5602
+ void this.ensureConnected();
5603
+ }, 5000);
5604
+ }
5605
+ clearReconnectTimer() {
5606
+ if (this.reconnectTimer) {
5607
+ clearTimeout(this.reconnectTimer);
5608
+ this.reconnectTimer = undefined;
5609
+ }
5610
+ }
5611
+ joinUrl(base, suffix) {
5612
+ return `${base.replace(/\/$/, '')}/${suffix.replace(/^\//, '')}`;
5613
+ }
5614
+ appendQueryParameter(url, name, value) {
5615
+ const separator = url.includes('?') ? '&' : '?';
5616
+ return `${url}${separator}${encodeURIComponent(name)}=${encodeURIComponent(value)}`;
5617
+ }
5618
+ getAuthorizationScopeKey() {
5619
+ const authorization = this.auth.getAuthorization();
5620
+ return `${authorization?.user?.id ?? 'anonymous'}:${authorization?.activeDivision?.id ?? 'global'}`;
5621
+ }
5622
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: NhBackgroundOperationLiveUpdateService, deps: [{ token: NhCommonModuleConfig }, { token: NhAuthService }, { token: NhAppService }], target: i0.ɵɵFactoryTarget.Injectable }); }
5623
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: NhBackgroundOperationLiveUpdateService, providedIn: 'root' }); }
5624
+ }
5625
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: NhBackgroundOperationLiveUpdateService, decorators: [{
5626
+ type: Injectable,
5627
+ args: [{ providedIn: 'root' }]
5628
+ }], ctorParameters: () => [{ type: NhCommonModuleConfig }, { type: NhAuthService }, { type: NhAppService }] });
5629
+
5630
+ class NhBackgroundOperationStore {
5631
+ constructor(api, live, config, auth) {
5632
+ this.api = api;
5633
+ this.live = live;
5634
+ this.config = config;
5635
+ this.auth = auth;
5636
+ this.operationsSubject = new BehaviorSubject(new Map());
5637
+ this.errorSubject = new BehaviorSubject(undefined);
5638
+ this.subscriptions = new Subscription();
5639
+ this.watchedIds = new Map();
5640
+ this.refreshing = new Set();
5641
+ this.refreshAgain = new Set();
5642
+ this.consumers = 0;
5643
+ this.scopeGeneration = 0;
5644
+ this.operations$ = this.operationsSubject.pipe(map(items => [...items.values()].sort((left, right) => right.lastModifiedDateTime.localeCompare(left.lastModifiedDateTime))));
5645
+ this.error$ = this.errorSubject.asObservable();
5646
+ this.connectionState$ = this.live.connectionState$;
5647
+ this.scopeKey = this.getScopeKey(this.auth.getAuthorization());
5648
+ this.subscriptions.add(this.auth.authSubject.subscribe(authorization => this.onAuthorizationChanged(authorization)));
5649
+ this.subscriptions.add(this.live.changed$.subscribe(change => this.onLiveChange(change)));
5650
+ this.subscriptions.add(this.live.resync$.subscribe(() => {
5651
+ void this.refreshList();
5652
+ for (const id of this.watchedIds.keys()) {
5653
+ this.refreshOperation(id);
5654
+ }
5655
+ }));
5656
+ }
5657
+ watchAll() {
5658
+ return defer(() => {
5659
+ this.start();
5660
+ return this.operations$.pipe(finalize$1(() => this.stop()));
5661
+ });
5662
+ }
5663
+ watch(operationId) {
5664
+ return defer(() => {
5665
+ this.start();
5666
+ this.watchedIds.set(operationId, (this.watchedIds.get(operationId) ?? 0) + 1);
5667
+ this.refreshOperation(operationId);
5668
+ return this.operationsSubject.pipe(map(operations => operations.get(operationId)), finalize$1(() => {
5669
+ const watchers = (this.watchedIds.get(operationId) ?? 1) - 1;
5670
+ if (watchers <= 0) {
5671
+ this.watchedIds.delete(operationId);
5672
+ }
5673
+ else {
5674
+ this.watchedIds.set(operationId, watchers);
5675
+ }
5676
+ this.stop();
5677
+ }));
5678
+ });
5679
+ }
5680
+ start() {
5681
+ this.consumers++;
5682
+ if (this.consumers !== 1) {
5683
+ return;
5684
+ }
5685
+ this.live.start();
5686
+ this.pollingSubscription = timer(0, Math.max(1000, this.config.backgroundOperations.pollingInterval))
5687
+ .pipe(exhaustMap(() => this.loadSnapshot()))
5688
+ .subscribe();
5689
+ }
5690
+ stop() {
5691
+ if (this.consumers === 0) {
5692
+ return;
5693
+ }
5694
+ this.consumers--;
5695
+ if (this.consumers === 0) {
5696
+ this.pollingSubscription?.unsubscribe();
5697
+ this.pollingSubscription = undefined;
5698
+ this.live.stop();
5699
+ }
5700
+ }
5701
+ refreshList() {
5702
+ return new Promise(resolve => this.loadList().subscribe({ complete: resolve }));
5703
+ }
5704
+ cancel(operationId) {
5705
+ const generation = this.scopeGeneration;
5706
+ return this.api.cancel(operationId).pipe(map(operation => this.mergeDetail(operation, generation)));
5707
+ }
5708
+ retry(operationId) {
5709
+ const generation = this.scopeGeneration;
5710
+ return this.api.retry(operationId).pipe(map(operation => this.mergeDetail(operation, generation)));
5711
+ }
5712
+ ngOnDestroy() {
5713
+ this.pollingSubscription?.unsubscribe();
5714
+ this.subscriptions.unsubscribe();
5715
+ if (this.consumers > 0) {
5716
+ this.consumers = 0;
5717
+ this.live.stop();
5718
+ }
5719
+ this.operationsSubject.complete();
5720
+ this.errorSubject.complete();
5721
+ }
5722
+ loadList() {
5723
+ const generation = this.scopeGeneration;
5724
+ const request = new NhBackgroundOperationCollectionHttpRequestOptions({
5725
+ page: 1,
5726
+ itemsPerPage: this.config.backgroundOperations.listPageSize
5727
+ });
5728
+ return this.api.list(request).pipe(map(response => {
5729
+ if (generation !== this.scopeGeneration) {
5730
+ return;
5731
+ }
5732
+ this.replaceListSnapshot(response.items ?? []);
5733
+ this.errorSubject.next(undefined);
5734
+ }), catchError(error => {
5735
+ if (generation === this.scopeGeneration) {
5736
+ this.errorSubject.next(error);
5737
+ }
5738
+ return of(undefined);
5739
+ }));
5740
+ }
5741
+ loadSnapshot() {
5742
+ return this.loadList().pipe(map(() => {
5743
+ for (const id of this.watchedIds.keys()) {
5744
+ this.refreshOperation(id);
5745
+ }
5746
+ }));
5747
+ }
5748
+ onLiveChange(change) {
5749
+ const existing = this.operationsSubject.value.get(change.operationId);
5750
+ if (existing && existing.version >= change.version && existing.latestEventSequence >= change.latestEventSequence) {
5751
+ return;
5752
+ }
5753
+ this.refreshOperation(change.operationId);
5754
+ }
5755
+ refreshOperation(operationId) {
5756
+ const generation = this.scopeGeneration;
5757
+ const refreshKey = `${generation}:${operationId}`;
5758
+ if (this.refreshing.has(refreshKey)) {
5759
+ this.refreshAgain.add(refreshKey);
5760
+ return;
5761
+ }
5762
+ this.refreshing.add(refreshKey);
5763
+ const existing = this.operationsSubject.value.get(operationId);
5764
+ this.api
5765
+ .get(operationId, existing?.latestEventSequence)
5766
+ .pipe(catchError(error => {
5767
+ if (generation === this.scopeGeneration) {
5768
+ if (this.shouldRemoveAfterError(error)) {
5769
+ this.removeOperation(operationId);
5770
+ }
5771
+ this.errorSubject.next(error);
5772
+ }
5773
+ return EMPTY;
5774
+ }), finalize$1(() => {
5775
+ this.refreshing.delete(refreshKey);
5776
+ if (this.refreshAgain.delete(refreshKey) && generation === this.scopeGeneration) {
5777
+ this.refreshOperation(operationId);
5778
+ }
5779
+ }))
5780
+ .subscribe(operation => {
5781
+ if (generation === this.scopeGeneration) {
5782
+ this.mergeDetail(operation, generation);
5783
+ this.errorSubject.next(undefined);
5784
+ }
5785
+ });
5786
+ }
5787
+ mergeSummary(incoming) {
5788
+ const existing = this.operationsSubject.value.get(incoming.id);
5789
+ if (existing && incoming.version < existing.version) {
5790
+ return existing;
5791
+ }
5792
+ const merged = existing
5793
+ ? {
5794
+ ...incoming,
5795
+ attempts: existing.attempts,
5796
+ steps: existing.steps,
5797
+ children: existing.children,
5798
+ events: existing.events
5799
+ }
5800
+ : incoming;
5801
+ this.setOperation(merged);
5802
+ return merged;
5803
+ }
5804
+ mergeDetail(incoming, generation = this.scopeGeneration) {
5805
+ if (generation !== this.scopeGeneration) {
5806
+ return incoming;
5807
+ }
5808
+ const existing = this.operationsSubject.value.get(incoming.id);
5809
+ if (existing && incoming.version < existing.version) {
5810
+ return existing;
5811
+ }
5812
+ const events = new Map();
5813
+ for (const event of existing?.events ?? []) {
5814
+ events.set(event.sequence, event);
5815
+ }
5816
+ for (const event of incoming.events ?? []) {
5817
+ events.set(event.sequence, event);
5818
+ }
5819
+ const merged = {
5820
+ ...incoming,
5821
+ events: [...events.values()].sort((left, right) => left.sequence - right.sequence)
5822
+ };
5823
+ this.setOperation(merged);
5824
+ return merged;
5825
+ }
5826
+ setOperation(operation) {
5827
+ const operations = new Map(this.operationsSubject.value);
5828
+ operations.set(operation.id, operation);
5829
+ this.operationsSubject.next(operations);
5830
+ }
5831
+ replaceListSnapshot(incoming) {
5832
+ const current = this.operationsSubject.value;
5833
+ const next = new Map();
5834
+ for (const watchedId of this.watchedIds.keys()) {
5835
+ const watched = current.get(watchedId);
5836
+ if (watched) {
5837
+ next.set(watchedId, watched);
5838
+ }
5839
+ }
5840
+ for (const operation of incoming) {
5841
+ const existing = current.get(operation.id);
5842
+ if (existing && operation.version < existing.version) {
5843
+ next.set(operation.id, existing);
5844
+ continue;
5845
+ }
5846
+ next.set(operation.id, existing
5847
+ ? {
5848
+ ...operation,
5849
+ attempts: existing.attempts,
5850
+ steps: existing.steps,
5851
+ children: existing.children,
5852
+ events: existing.events
5853
+ }
5854
+ : operation);
5855
+ }
5856
+ this.operationsSubject.next(next);
5857
+ }
5858
+ onAuthorizationChanged(authorization) {
5859
+ const nextScopeKey = this.getScopeKey(authorization);
5860
+ if (nextScopeKey === this.scopeKey) {
5861
+ return;
5862
+ }
5863
+ this.scopeKey = nextScopeKey;
5864
+ this.scopeGeneration++;
5865
+ this.operationsSubject.next(new Map());
5866
+ this.errorSubject.next(undefined);
5867
+ if (this.consumers > 0) {
5868
+ void this.refreshList();
5869
+ for (const id of this.watchedIds.keys()) {
5870
+ this.refreshOperation(id);
5871
+ }
5872
+ }
5873
+ }
5874
+ getScopeKey(authorization) {
5875
+ const userId = authorization?.user?.id ?? 'anonymous';
5876
+ const divisionId = authorization?.activeDivision?.id ?? 'global';
5877
+ return `${userId}:${divisionId}`;
5878
+ }
5879
+ shouldRemoveAfterError(error) {
5880
+ return error instanceof HttpErrorResponse
5881
+ && [401, 403, 404].includes(error.status);
5882
+ }
5883
+ removeOperation(operationId) {
5884
+ if (!this.operationsSubject.value.has(operationId)) {
5885
+ return;
5886
+ }
5887
+ const operations = new Map(this.operationsSubject.value);
5888
+ operations.delete(operationId);
5889
+ this.operationsSubject.next(operations);
5890
+ }
5891
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: NhBackgroundOperationStore, deps: [{ token: NhBackgroundOperationService }, { token: NhBackgroundOperationLiveUpdateService }, { token: NhCommonModuleConfig }, { token: NhAuthService }], target: i0.ɵɵFactoryTarget.Injectable }); }
5892
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: NhBackgroundOperationStore, providedIn: 'root' }); }
5893
+ }
5894
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: NhBackgroundOperationStore, decorators: [{
5895
+ type: Injectable,
5896
+ args: [{ providedIn: 'root' }]
5897
+ }], ctorParameters: () => [{ type: NhBackgroundOperationService }, { type: NhBackgroundOperationLiveUpdateService }, { type: NhCommonModuleConfig }, { type: NhAuthService }] });
5898
+
5687
5899
  class NhContextMenuItem {
5688
5900
  constructor(init) {
5689
5901
  this.type = 'item';
@@ -7747,9 +7959,9 @@ class NhUserNotificationsAbstractComponent extends NhCollectionBaseComponent {
7747
7959
  this.lastUnreadNotificationCount = this.userNotificationState.overview.unreadCount;
7748
7960
  this.userNotificationSubscription = this.userNotificationService.userNotificationState$.subscribe(async (state) => {
7749
7961
  this.userNotificationState = state;
7750
- const hasNewNotifications = this.lastNotificationDate && this.lastNotificationDate != this.userNotificationState.overview.lastNotificationDate;
7751
- const countChanged = this.lastNotificationCount && this.lastNotificationCount != this.userNotificationState.overview.totalCount;
7752
- const unreadCountChanged = this.lastUnreadNotificationCount && this.lastUnreadNotificationCount != this.userNotificationState.overview.unreadCount;
7962
+ const hasNewNotifications = this.lastNotificationDate !== this.userNotificationState.overview.lastNotificationDate;
7963
+ const countChanged = this.lastNotificationCount !== this.userNotificationState.overview.totalCount;
7964
+ const unreadCountChanged = this.lastUnreadNotificationCount !== this.userNotificationState.overview.unreadCount;
7753
7965
  if (hasNewNotifications || countChanged || unreadCountChanged) {
7754
7966
  if (this.autoLoadNotificationChanges) {
7755
7967
  try {
@@ -7762,24 +7974,25 @@ class NhUserNotificationsAbstractComponent extends NhCollectionBaseComponent {
7762
7974
  this.onNewNotificationsAvailable(state).catch((error) => {
7763
7975
  console.error('Error handling user notification state change:', error);
7764
7976
  });
7977
+ this.captureOverview(state);
7765
7978
  }
7766
7979
  });
7767
7980
  }
7768
7981
  onNewNotificationsAvailable(state) {
7769
7982
  return Promise.resolve();
7770
7983
  }
7771
- ngOnInit() {
7772
- super.ngOnInit();
7984
+ async appOnInit() {
7985
+ await super.appOnInit();
7773
7986
  if (this.allowStart) {
7774
7987
  this.userNotificationService.start();
7775
7988
  }
7776
7989
  }
7777
- ngOnDestroy() {
7778
- super.ngOnDestroy();
7990
+ async appOnDestroy() {
7779
7991
  if (this.allowStop) {
7780
7992
  this.userNotificationService.stop();
7781
7993
  }
7782
7994
  this.userNotificationSubscription?.unsubscribe();
7995
+ await super.appOnDestroy();
7783
7996
  }
7784
7997
  getInitialRequestOptions() {
7785
7998
  return new NhUserNotificationCollectionHttpRequestOptions({
@@ -7793,9 +8006,7 @@ class NhUserNotificationsAbstractComponent extends NhCollectionBaseComponent {
7793
8006
  return this.userNotificationService.getNotifications(requestOptions);
7794
8007
  }
7795
8008
  async afterLoad() {
7796
- this.lastNotificationDate = this.userNotificationState.overview.lastNotificationDate;
7797
- this.lastNotificationCount = this.userNotificationState.overview.totalCount;
7798
- this.lastUnreadNotificationCount = this.userNotificationState.overview.unreadCount;
8009
+ this.captureOverview(this.userNotificationState);
7799
8010
  }
7800
8011
  async reload() {
7801
8012
  const currentPage = this.requestOptions.page;
@@ -7868,6 +8079,11 @@ class NhUserNotificationsAbstractComponent extends NhCollectionBaseComponent {
7868
8079
  await this.firstPage();
7869
8080
  return taskResult;
7870
8081
  }
8082
+ captureOverview(state) {
8083
+ this.lastNotificationDate = state.overview.lastNotificationDate;
8084
+ this.lastNotificationCount = state.overview.totalCount;
8085
+ this.lastUnreadNotificationCount = state.overview.unreadCount;
8086
+ }
7871
8087
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: NhUserNotificationsAbstractComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
7872
8088
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.28", type: NhUserNotificationsAbstractComponent, isStandalone: false, selector: "nh-user-notifications-abstract", inputs: { allowStart: { classPropertyName: "allowStart", publicName: "allowStart", isSignal: false, isRequired: false, transformFunction: null }, allowStop: { classPropertyName: "allowStop", publicName: "allowStop", isSignal: false, isRequired: false, transformFunction: null }, itemsPerPage: { classPropertyName: "itemsPerPage", publicName: "itemsPerPage", isSignal: false, isRequired: false, transformFunction: null }, autoLoadNotificationChanges: { classPropertyName: "autoLoadNotificationChanges", publicName: "autoLoadNotificationChanges", isSignal: false, isRequired: false, transformFunction: null }, partialLocalStorageKey: { classPropertyName: "partialLocalStorageKey", publicName: "partialLocalStorageKey", isSignal: true, isRequired: false, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: ``, isInline: true }); }
7873
8089
  }
@@ -7888,6 +8104,72 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImpo
7888
8104
  type: Input
7889
8105
  }], partialLocalStorageKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "partialLocalStorageKey", required: false }] }] } });
7890
8106
 
8107
+ class NhBackgroundOperationProgressComponent {
8108
+ constructor() {
8109
+ this.showEvents = true;
8110
+ this.showActions = false;
8111
+ this.cancelRequested = new EventEmitter();
8112
+ this.retryRequested = new EventEmitter();
8113
+ }
8114
+ statusKey(status) {
8115
+ return `nh-background-operations.status.${nhBackgroundOperationTranslationSegment(nhBackgroundOperationStatusName(status))}`;
8116
+ }
8117
+ stepStatusKey(status) {
8118
+ return `nh-background-operations.step-status.${nhBackgroundOperationTranslationSegment(nhBackgroundOperationStepStatusName(status))}`;
8119
+ }
8120
+ stepTitle(step) {
8121
+ return step.titleKey || step.stepKey;
8122
+ }
8123
+ percentage(value) {
8124
+ if (value === undefined || value === null || !Number.isFinite(value)) {
8125
+ return 0;
8126
+ }
8127
+ return Math.max(0, Math.min(100, value));
8128
+ }
8129
+ arguments(json) {
8130
+ if (!json) {
8131
+ return {};
8132
+ }
8133
+ try {
8134
+ const value = JSON.parse(json);
8135
+ return typeof value === 'object' && value !== null ? value : {};
8136
+ }
8137
+ catch {
8138
+ return {};
8139
+ }
8140
+ }
8141
+ hasBatch(step) {
8142
+ return step.discoveredItems > 0 || step.processedItems > 0 || step.activeItems > 0;
8143
+ }
8144
+ childLabel(child) {
8145
+ return child.fanOutItemKey || child.operationType;
8146
+ }
8147
+ canCancel(status) {
8148
+ return !['Succeeded', 'Failed', 'Cancelled', 'TimedOut'].includes(nhBackgroundOperationStatusName(status));
8149
+ }
8150
+ canRetry(operation) {
8151
+ return !operation.sensitiveDataRedactedAt
8152
+ && ['Failed', 'Cancelled', 'TimedOut'].includes(nhBackgroundOperationStatusName(operation.status));
8153
+ }
8154
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: NhBackgroundOperationProgressComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
8155
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.28", type: NhBackgroundOperationProgressComponent, isStandalone: true, selector: "nh-background-operation-progress", inputs: { operation: "operation", showEvents: "showEvents", showActions: "showActions" }, outputs: { cancelRequested: "cancelRequested", retryRequested: "retryRequested" }, ngImport: i0, template: "<section class=\"nh-operation\" [attr.data-status]=\"statusKey(operation.status)\">\n <header class=\"nh-operation__header\">\n <div>\n <p class=\"nh-operation__eyebrow\">{{ 'nh-background-operations.operation' | translate }}</p>\n <h2>{{ operation.operationType }}</h2>\n </div>\n <span class=\"nh-operation__status\">{{ statusKey(operation.status) | translate }}</span>\n </header>\n\n <div class=\"nh-operation__overall\">\n <div class=\"nh-operation__progress-label\">\n <span>{{ operation.progressMessageKey ? (operation.progressMessageKey | translate: arguments(operation.progressMessageArgumentsJson)) : ('nh-background-operations.progress' | translate) }}</span>\n <strong>{{ percentage(operation.progressPercentage) | number:'1.0-1' }}%</strong>\n </div>\n <div class=\"nh-operation__progress\" role=\"progressbar\"\n [attr.aria-label]=\"'nh-background-operations.overall-progress' | translate\"\n aria-valuemin=\"0\" aria-valuemax=\"100\"\n [attr.aria-valuenow]=\"percentage(operation.progressPercentage)\">\n <span [style.width.%]=\"percentage(operation.progressPercentage)\"></span>\n </div>\n </div>\n\n @if (showActions && (canCancel(operation.status) || canRetry(operation))) {\n <div class=\"nh-operation__actions\">\n @if (canCancel(operation.status)) {\n <button type=\"button\" (click)=\"cancelRequested.emit(operation.id)\">\n {{ 'nh-background-operations.cancel' | translate }}\n </button>\n }\n @if (canRetry(operation)) {\n <button type=\"button\" (click)=\"retryRequested.emit(operation.id)\">\n {{ 'nh-background-operations.retry' | translate }}\n </button>\n }\n </div>\n }\n\n <div class=\"nh-operation__steps\" role=\"list\" [attr.aria-label]=\"'nh-background-operations.steps' | translate\">\n <ng-template #renderStep let-step let-depth=\"depth\">\n <article class=\"nh-step\" role=\"listitem\" [style.--nh-step-depth]=\"depth\">\n <div class=\"nh-step__heading\">\n <div>\n <strong>{{ stepTitle(step) | translate: arguments(step.titleArgumentsJson) }}</strong>\n @if (step.messageKey) {\n <span>{{ step.messageKey | translate: arguments(step.messageArgumentsJson) }}</span>\n }\n </div>\n <span class=\"nh-step__status\">{{ stepStatusKey(step.status) | translate }}</span>\n </div>\n <div class=\"nh-step__progress\" role=\"progressbar\"\n [attr.aria-label]=\"stepTitle(step) | translate: arguments(step.titleArgumentsJson)\"\n aria-valuemin=\"0\" aria-valuemax=\"100\"\n [attr.aria-valuenow]=\"percentage(step.percentage)\">\n <span [style.width.%]=\"percentage(step.percentage)\"></span>\n </div>\n @if (hasBatch(step)) {\n <dl class=\"nh-step__batch\">\n <div><dt>{{ 'nh-background-operations.batch.processed' | translate }}</dt><dd>{{ step.processedItems }} / {{ step.discoveredItems }}</dd></div>\n <div><dt>{{ 'nh-background-operations.batch.succeeded' | translate }}</dt><dd>{{ step.succeededItems }}</dd></div>\n <div><dt>{{ 'nh-background-operations.batch.failed' | translate }}</dt><dd>{{ step.failedItems }}</dd></div>\n <div><dt>{{ 'nh-background-operations.batch.skipped' | translate }}</dt><dd>{{ step.skippedItems }}</dd></div>\n @if (step.retriedItems > 0) {\n <div><dt>{{ 'nh-background-operations.batch.retried' | translate }}</dt><dd>{{ step.retriedItems }}</dd></div>\n }\n @if (step.activeItems > 0) {\n <div><dt>{{ 'nh-background-operations.batch.active' | translate }}</dt><dd>{{ step.activeItems }}</dd></div>\n }\n </dl>\n }\n </article>\n @for (child of step.children; track child.id) {\n <ng-container *ngTemplateOutlet=\"renderStep; context: {$implicit: child, depth: depth + 1}\"></ng-container>\n }\n </ng-template>\n\n @for (step of operation.steps; track step.id) {\n <ng-container *ngTemplateOutlet=\"renderStep; context: {$implicit: step, depth: 0}\"></ng-container>\n } @empty {\n <p class=\"nh-operation__empty\">{{ 'nh-background-operations.no-steps' | translate }}</p>\n }\n </div>\n\n @if (operation.children.length > 0) {\n <section class=\"nh-operation__children\">\n <h3>{{ 'nh-background-operations.children' | translate }}</h3>\n <div role=\"list\" [attr.aria-label]=\"'nh-background-operations.children' | translate\">\n <ng-template #renderChild let-child let-depth=\"depth\">\n <article class=\"nh-child\" role=\"listitem\" [style.--nh-child-depth]=\"depth\">\n <div class=\"nh-child__heading\">\n <div>\n <strong>{{ childLabel(child) }}</strong>\n <span>{{ child.operationType }}</span>\n </div>\n <span class=\"nh-child__status\">{{ statusKey(child.status) | translate }}</span>\n </div>\n <div class=\"nh-step__progress\" role=\"progressbar\"\n [attr.aria-label]=\"childLabel(child)\"\n aria-valuemin=\"0\" aria-valuemax=\"100\"\n [attr.aria-valuenow]=\"percentage(child.progressPercentage)\">\n <span [style.width.%]=\"percentage(child.progressPercentage)\"></span>\n </div>\n @if (child.resultUrl) {\n <a [href]=\"child.resultUrl\">{{ 'nh-background-operations.open-result' | translate }}</a>\n }\n </article>\n @for (nestedChild of child.children; track nestedChild.id) {\n <ng-container *ngTemplateOutlet=\"renderChild; context: {$implicit: nestedChild, depth: depth + 1}\"></ng-container>\n }\n </ng-template>\n\n @for (child of operation.children; track child.id) {\n <ng-container *ngTemplateOutlet=\"renderChild; context: {$implicit: child, depth: 0}\"></ng-container>\n }\n </div>\n </section>\n }\n\n @if (showEvents && operation.events.length > 0) {\n <section class=\"nh-operation__events\">\n <h3>{{ 'nh-background-operations.activity' | translate }}</h3>\n <ol>\n @for (event of operation.events; track event.id) {\n @if (event.messageKey) {\n <li>\n <time [attr.datetime]=\"event.creationDateTime\">{{ event.creationDateTime | date:'short' }}</time>\n <span>{{ event.messageKey | translate: arguments(event.messageArgumentsJson) }}</span>\n @if (event.resultUrl) {\n <a [href]=\"event.resultUrl\">{{ 'nh-background-operations.open-result' | translate }}</a>\n }\n </li>\n }\n }\n </ol>\n </section>\n }\n</section>\n", styles: [":host{display:block;color:var(--nh-color-text, #fff)}.nh-operation{display:grid;gap:1rem;padding:1rem;border:1px solid var(--nh-color-border, rgba(255, 255, 255, .14));border-radius:1rem;background:var(--nh-color-surface, #101827)}.nh-operation__header,.nh-step__heading,.nh-child__heading,.nh-operation__progress-label,.nh-operation__actions{display:flex;align-items:center;justify-content:space-between;gap:.75rem}.nh-operation__header h2,.nh-operation__events h3,.nh-operation__children h3,.nh-operation__eyebrow,.nh-step__heading span,.nh-step__batch,.nh-operation__events ol{margin:0}.nh-operation__eyebrow{color:var(--nh-color-muted, #9aa8bc);font-size:.75rem;letter-spacing:.06em;text-transform:uppercase}.nh-operation__status,.nh-step__status{flex:none;padding:.25rem .5rem;border-radius:.4rem;background:var(--nh-color-status-background, rgba(2, 41, 98, .75));font-size:.75rem}.nh-operation__progress,.nh-step__progress{overflow:hidden;height:.5rem;border-radius:.25rem;background:var(--nh-color-progress-track, rgba(255, 255, 255, .1))}.nh-operation__progress span,.nh-step__progress span{display:block;height:100%;background:var(--nh-color-progress, #ff6700);transition:width .18s ease-out}.nh-operation__steps{display:grid;gap:.625rem}.nh-operation__children,.nh-operation__children>div{display:grid;gap:.625rem}.nh-child{display:grid;gap:.5rem;margin-inline-start:min(var(--nh-child-depth) * 1rem,3rem);padding:.75rem;border:1px solid var(--nh-color-border, rgba(255, 255, 255, .14));border-radius:.5rem;background:var(--nh-color-surface-subtle, rgba(255, 255, 255, .035))}.nh-child__heading{display:flex;align-items:center;justify-content:space-between;gap:.75rem}.nh-child__heading>div{display:grid;gap:.125rem}.nh-child__heading span{color:var(--nh-color-muted, #9aa8bc);font-size:.8rem}.nh-child__status{flex:none;padding:.25rem .5rem;border-radius:.4rem;background:var(--nh-color-status-background, rgba(2, 41, 98, .75));color:var(--nh-color-text, #fff);font-size:.75rem}.nh-child a{justify-self:start}.nh-step{display:grid;gap:.5rem;margin-inline-start:calc(var(--nh-step-depth) * 1rem);padding:.75rem;border-inline-start:2px solid var(--nh-color-progress, #ff6700);background:var(--nh-color-surface-subtle, rgba(255, 255, 255, .035))}.nh-step__heading>div{display:grid;gap:.125rem}.nh-step__heading span{color:var(--nh-color-muted, #9aa8bc);font-size:.8rem}.nh-step__batch{display:flex;flex-wrap:wrap;gap:.5rem 1rem;color:var(--nh-color-muted, #9aa8bc);font-size:.75rem}.nh-step__batch div{display:flex;gap:.25rem}.nh-step__batch dd{margin:0;color:var(--nh-color-text, #fff)}.nh-operation__actions{justify-content:flex-end}.nh-operation__actions button{min-height:2.25rem;padding:.4rem .75rem;border:1px solid var(--nh-color-border, rgba(255, 255, 255, .2));border-radius:.5rem;color:inherit;background:transparent}.nh-operation__actions button:focus-visible,.nh-child a:focus-visible,.nh-operation__events a:focus-visible{outline:2px solid var(--nh-color-progress, #ff6700);outline-offset:2px}.nh-operation__events ol{display:grid;gap:.5rem;padding:0;list-style:none}.nh-operation__events li{display:grid;grid-template-columns:minmax(7rem,auto) 1fr auto;gap:.75rem;color:var(--nh-color-muted, #9aa8bc);font-size:.8rem}.nh-operation__events li span{color:var(--nh-color-text, #fff)}@media(prefers-reduced-motion:reduce){.nh-operation__progress span,.nh-step__progress span{transition:none}}@media(max-width:40rem){.nh-operation__header,.nh-step__heading,.nh-child__heading,.nh-operation__events li{align-items:flex-start;grid-template-columns:1fr}.nh-operation__header,.nh-step__heading{flex-direction:column}.nh-child__heading{align-items:flex-start;flex-direction:column}.nh-step{margin-inline-start:min(var(--nh-step-depth) * .5rem,1.5rem)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i1$3.DecimalPipe, name: "number" }, { kind: "pipe", type: i1$3.DatePipe, name: "date" }, { kind: "pipe", type: i2.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
8156
+ }
8157
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: NhBackgroundOperationProgressComponent, decorators: [{
8158
+ type: Component,
8159
+ args: [{ selector: 'nh-background-operation-progress', standalone: true, imports: [CommonModule, TranslateModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<section class=\"nh-operation\" [attr.data-status]=\"statusKey(operation.status)\">\n <header class=\"nh-operation__header\">\n <div>\n <p class=\"nh-operation__eyebrow\">{{ 'nh-background-operations.operation' | translate }}</p>\n <h2>{{ operation.operationType }}</h2>\n </div>\n <span class=\"nh-operation__status\">{{ statusKey(operation.status) | translate }}</span>\n </header>\n\n <div class=\"nh-operation__overall\">\n <div class=\"nh-operation__progress-label\">\n <span>{{ operation.progressMessageKey ? (operation.progressMessageKey | translate: arguments(operation.progressMessageArgumentsJson)) : ('nh-background-operations.progress' | translate) }}</span>\n <strong>{{ percentage(operation.progressPercentage) | number:'1.0-1' }}%</strong>\n </div>\n <div class=\"nh-operation__progress\" role=\"progressbar\"\n [attr.aria-label]=\"'nh-background-operations.overall-progress' | translate\"\n aria-valuemin=\"0\" aria-valuemax=\"100\"\n [attr.aria-valuenow]=\"percentage(operation.progressPercentage)\">\n <span [style.width.%]=\"percentage(operation.progressPercentage)\"></span>\n </div>\n </div>\n\n @if (showActions && (canCancel(operation.status) || canRetry(operation))) {\n <div class=\"nh-operation__actions\">\n @if (canCancel(operation.status)) {\n <button type=\"button\" (click)=\"cancelRequested.emit(operation.id)\">\n {{ 'nh-background-operations.cancel' | translate }}\n </button>\n }\n @if (canRetry(operation)) {\n <button type=\"button\" (click)=\"retryRequested.emit(operation.id)\">\n {{ 'nh-background-operations.retry' | translate }}\n </button>\n }\n </div>\n }\n\n <div class=\"nh-operation__steps\" role=\"list\" [attr.aria-label]=\"'nh-background-operations.steps' | translate\">\n <ng-template #renderStep let-step let-depth=\"depth\">\n <article class=\"nh-step\" role=\"listitem\" [style.--nh-step-depth]=\"depth\">\n <div class=\"nh-step__heading\">\n <div>\n <strong>{{ stepTitle(step) | translate: arguments(step.titleArgumentsJson) }}</strong>\n @if (step.messageKey) {\n <span>{{ step.messageKey | translate: arguments(step.messageArgumentsJson) }}</span>\n }\n </div>\n <span class=\"nh-step__status\">{{ stepStatusKey(step.status) | translate }}</span>\n </div>\n <div class=\"nh-step__progress\" role=\"progressbar\"\n [attr.aria-label]=\"stepTitle(step) | translate: arguments(step.titleArgumentsJson)\"\n aria-valuemin=\"0\" aria-valuemax=\"100\"\n [attr.aria-valuenow]=\"percentage(step.percentage)\">\n <span [style.width.%]=\"percentage(step.percentage)\"></span>\n </div>\n @if (hasBatch(step)) {\n <dl class=\"nh-step__batch\">\n <div><dt>{{ 'nh-background-operations.batch.processed' | translate }}</dt><dd>{{ step.processedItems }} / {{ step.discoveredItems }}</dd></div>\n <div><dt>{{ 'nh-background-operations.batch.succeeded' | translate }}</dt><dd>{{ step.succeededItems }}</dd></div>\n <div><dt>{{ 'nh-background-operations.batch.failed' | translate }}</dt><dd>{{ step.failedItems }}</dd></div>\n <div><dt>{{ 'nh-background-operations.batch.skipped' | translate }}</dt><dd>{{ step.skippedItems }}</dd></div>\n @if (step.retriedItems > 0) {\n <div><dt>{{ 'nh-background-operations.batch.retried' | translate }}</dt><dd>{{ step.retriedItems }}</dd></div>\n }\n @if (step.activeItems > 0) {\n <div><dt>{{ 'nh-background-operations.batch.active' | translate }}</dt><dd>{{ step.activeItems }}</dd></div>\n }\n </dl>\n }\n </article>\n @for (child of step.children; track child.id) {\n <ng-container *ngTemplateOutlet=\"renderStep; context: {$implicit: child, depth: depth + 1}\"></ng-container>\n }\n </ng-template>\n\n @for (step of operation.steps; track step.id) {\n <ng-container *ngTemplateOutlet=\"renderStep; context: {$implicit: step, depth: 0}\"></ng-container>\n } @empty {\n <p class=\"nh-operation__empty\">{{ 'nh-background-operations.no-steps' | translate }}</p>\n }\n </div>\n\n @if (operation.children.length > 0) {\n <section class=\"nh-operation__children\">\n <h3>{{ 'nh-background-operations.children' | translate }}</h3>\n <div role=\"list\" [attr.aria-label]=\"'nh-background-operations.children' | translate\">\n <ng-template #renderChild let-child let-depth=\"depth\">\n <article class=\"nh-child\" role=\"listitem\" [style.--nh-child-depth]=\"depth\">\n <div class=\"nh-child__heading\">\n <div>\n <strong>{{ childLabel(child) }}</strong>\n <span>{{ child.operationType }}</span>\n </div>\n <span class=\"nh-child__status\">{{ statusKey(child.status) | translate }}</span>\n </div>\n <div class=\"nh-step__progress\" role=\"progressbar\"\n [attr.aria-label]=\"childLabel(child)\"\n aria-valuemin=\"0\" aria-valuemax=\"100\"\n [attr.aria-valuenow]=\"percentage(child.progressPercentage)\">\n <span [style.width.%]=\"percentage(child.progressPercentage)\"></span>\n </div>\n @if (child.resultUrl) {\n <a [href]=\"child.resultUrl\">{{ 'nh-background-operations.open-result' | translate }}</a>\n }\n </article>\n @for (nestedChild of child.children; track nestedChild.id) {\n <ng-container *ngTemplateOutlet=\"renderChild; context: {$implicit: nestedChild, depth: depth + 1}\"></ng-container>\n }\n </ng-template>\n\n @for (child of operation.children; track child.id) {\n <ng-container *ngTemplateOutlet=\"renderChild; context: {$implicit: child, depth: 0}\"></ng-container>\n }\n </div>\n </section>\n }\n\n @if (showEvents && operation.events.length > 0) {\n <section class=\"nh-operation__events\">\n <h3>{{ 'nh-background-operations.activity' | translate }}</h3>\n <ol>\n @for (event of operation.events; track event.id) {\n @if (event.messageKey) {\n <li>\n <time [attr.datetime]=\"event.creationDateTime\">{{ event.creationDateTime | date:'short' }}</time>\n <span>{{ event.messageKey | translate: arguments(event.messageArgumentsJson) }}</span>\n @if (event.resultUrl) {\n <a [href]=\"event.resultUrl\">{{ 'nh-background-operations.open-result' | translate }}</a>\n }\n </li>\n }\n }\n </ol>\n </section>\n }\n</section>\n", styles: [":host{display:block;color:var(--nh-color-text, #fff)}.nh-operation{display:grid;gap:1rem;padding:1rem;border:1px solid var(--nh-color-border, rgba(255, 255, 255, .14));border-radius:1rem;background:var(--nh-color-surface, #101827)}.nh-operation__header,.nh-step__heading,.nh-child__heading,.nh-operation__progress-label,.nh-operation__actions{display:flex;align-items:center;justify-content:space-between;gap:.75rem}.nh-operation__header h2,.nh-operation__events h3,.nh-operation__children h3,.nh-operation__eyebrow,.nh-step__heading span,.nh-step__batch,.nh-operation__events ol{margin:0}.nh-operation__eyebrow{color:var(--nh-color-muted, #9aa8bc);font-size:.75rem;letter-spacing:.06em;text-transform:uppercase}.nh-operation__status,.nh-step__status{flex:none;padding:.25rem .5rem;border-radius:.4rem;background:var(--nh-color-status-background, rgba(2, 41, 98, .75));font-size:.75rem}.nh-operation__progress,.nh-step__progress{overflow:hidden;height:.5rem;border-radius:.25rem;background:var(--nh-color-progress-track, rgba(255, 255, 255, .1))}.nh-operation__progress span,.nh-step__progress span{display:block;height:100%;background:var(--nh-color-progress, #ff6700);transition:width .18s ease-out}.nh-operation__steps{display:grid;gap:.625rem}.nh-operation__children,.nh-operation__children>div{display:grid;gap:.625rem}.nh-child{display:grid;gap:.5rem;margin-inline-start:min(var(--nh-child-depth) * 1rem,3rem);padding:.75rem;border:1px solid var(--nh-color-border, rgba(255, 255, 255, .14));border-radius:.5rem;background:var(--nh-color-surface-subtle, rgba(255, 255, 255, .035))}.nh-child__heading{display:flex;align-items:center;justify-content:space-between;gap:.75rem}.nh-child__heading>div{display:grid;gap:.125rem}.nh-child__heading span{color:var(--nh-color-muted, #9aa8bc);font-size:.8rem}.nh-child__status{flex:none;padding:.25rem .5rem;border-radius:.4rem;background:var(--nh-color-status-background, rgba(2, 41, 98, .75));color:var(--nh-color-text, #fff);font-size:.75rem}.nh-child a{justify-self:start}.nh-step{display:grid;gap:.5rem;margin-inline-start:calc(var(--nh-step-depth) * 1rem);padding:.75rem;border-inline-start:2px solid var(--nh-color-progress, #ff6700);background:var(--nh-color-surface-subtle, rgba(255, 255, 255, .035))}.nh-step__heading>div{display:grid;gap:.125rem}.nh-step__heading span{color:var(--nh-color-muted, #9aa8bc);font-size:.8rem}.nh-step__batch{display:flex;flex-wrap:wrap;gap:.5rem 1rem;color:var(--nh-color-muted, #9aa8bc);font-size:.75rem}.nh-step__batch div{display:flex;gap:.25rem}.nh-step__batch dd{margin:0;color:var(--nh-color-text, #fff)}.nh-operation__actions{justify-content:flex-end}.nh-operation__actions button{min-height:2.25rem;padding:.4rem .75rem;border:1px solid var(--nh-color-border, rgba(255, 255, 255, .2));border-radius:.5rem;color:inherit;background:transparent}.nh-operation__actions button:focus-visible,.nh-child a:focus-visible,.nh-operation__events a:focus-visible{outline:2px solid var(--nh-color-progress, #ff6700);outline-offset:2px}.nh-operation__events ol{display:grid;gap:.5rem;padding:0;list-style:none}.nh-operation__events li{display:grid;grid-template-columns:minmax(7rem,auto) 1fr auto;gap:.75rem;color:var(--nh-color-muted, #9aa8bc);font-size:.8rem}.nh-operation__events li span{color:var(--nh-color-text, #fff)}@media(prefers-reduced-motion:reduce){.nh-operation__progress span,.nh-step__progress span{transition:none}}@media(max-width:40rem){.nh-operation__header,.nh-step__heading,.nh-child__heading,.nh-operation__events li{align-items:flex-start;grid-template-columns:1fr}.nh-operation__header,.nh-step__heading{flex-direction:column}.nh-child__heading{align-items:flex-start;flex-direction:column}.nh-step{margin-inline-start:min(var(--nh-step-depth) * .5rem,1.5rem)}}\n"] }]
8160
+ }], propDecorators: { operation: [{
8161
+ type: Input,
8162
+ args: [{ required: true }]
8163
+ }], showEvents: [{
8164
+ type: Input
8165
+ }], showActions: [{
8166
+ type: Input
8167
+ }], cancelRequested: [{
8168
+ type: Output
8169
+ }], retryRequested: [{
8170
+ type: Output
8171
+ }] } });
8172
+
7891
8173
  class NhSearchInputComponent {
7892
8174
  constructor() {
7893
8175
  this.value = '';
@@ -8123,7 +8405,6 @@ class NhCommonModule {
8123
8405
  static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: NhCommonModule, providers: [
8124
8406
  provideAppInitializer(() => {
8125
8407
  const configService = inject(NhConfigCommonService);
8126
- const nhSentryTraceService = inject(NhSentryTraceService);
8127
8408
  return new Observable((observer) => {
8128
8409
  //
8129
8410
  // We use APP_INITIALIZER to load the configuration before the application starts. (Cuz DEPS calls for AppConfigService it is loaded soon in the lifecycle of the app.)
@@ -8163,14 +8444,6 @@ class NhCommonModule {
8163
8444
  useClass: NhDeduplicateGetRequestsInterceptor,
8164
8445
  multi: true
8165
8446
  },
8166
- // Tracing
8167
- {
8168
- provide: Sentry.TraceService,
8169
- useFactory: (nhSentryTraceService) => {
8170
- return nhSentryTraceService.sentryTraceService;
8171
- },
8172
- deps: [NhSentryTraceService]
8173
- },
8174
8447
  //Error handlers
8175
8448
  {
8176
8449
  provide: ErrorHandler, // Make support for multiple error handlers
@@ -8181,11 +8454,6 @@ class NhCommonModule {
8181
8454
  useClass: ErrorHandler,
8182
8455
  multi: true,
8183
8456
  },
8184
- {
8185
- provide: NH_ERROR_HANDLERS, // Register Sentry error handler
8186
- useClass: NhErrorHandlerSentryService,
8187
- multi: true,
8188
- },
8189
8457
  provideHttpClient(withInterceptorsFromDi(), withFetch()),
8190
8458
  // Guards
8191
8459
  NhCanCancelNavigationGuard,
@@ -8289,7 +8557,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImpo
8289
8557
  providers: [
8290
8558
  provideAppInitializer(() => {
8291
8559
  const configService = inject(NhConfigCommonService);
8292
- const nhSentryTraceService = inject(NhSentryTraceService);
8293
8560
  return new Observable((observer) => {
8294
8561
  //
8295
8562
  // We use APP_INITIALIZER to load the configuration before the application starts. (Cuz DEPS calls for AppConfigService it is loaded soon in the lifecycle of the app.)
@@ -8329,14 +8596,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImpo
8329
8596
  useClass: NhDeduplicateGetRequestsInterceptor,
8330
8597
  multi: true
8331
8598
  },
8332
- // Tracing
8333
- {
8334
- provide: Sentry.TraceService,
8335
- useFactory: (nhSentryTraceService) => {
8336
- return nhSentryTraceService.sentryTraceService;
8337
- },
8338
- deps: [NhSentryTraceService]
8339
- },
8340
8599
  //Error handlers
8341
8600
  {
8342
8601
  provide: ErrorHandler, // Make support for multiple error handlers
@@ -8347,11 +8606,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImpo
8347
8606
  useClass: ErrorHandler,
8348
8607
  multi: true,
8349
8608
  },
8350
- {
8351
- provide: NH_ERROR_HANDLERS, // Register Sentry error handler
8352
- useClass: NhErrorHandlerSentryService,
8353
- multi: true,
8354
- },
8355
8609
  provideHttpClient(withInterceptorsFromDi(), withFetch()),
8356
8610
  // Guards
8357
8611
  NhCanCancelNavigationGuard,
@@ -8448,5 +8702,5 @@ function nhTranslateBrowserLoaderFactory(httpClient, transferState) {
8448
8702
  * Generated bundle index. Do not edit.
8449
8703
  */
8450
8704
 
8451
- export { AbstractValueAccessor, AspMvcFormServerSideFormValidator, AuthSessionExpirationInformation, AuthenticateModel, AuthenticationNhCommonModuleConfig, AuthenticationSessionCreateResponse, BaseNhAuthService, CheckAuthenticateSessionModel, Claim, ClaimAuthenticateSessionAccountMutateModel, ClaimAuthenticateSessionAccountViewModel, ClaimTypes, CollectionHttpRequestOptions, CollectionHttpResponse, DefaultMultiSelectSettings, DefaultMultiSelectTexts, EndpointsAuthenticationNhCommonModuleConfig, FilterRequestOptions, FormError, FormValidationResult, HttpDownloadRequestOptions, HttpRequestOptions, HttpRequestOptionsArrayBuffer, HttpRequestOptionsText, ImpersonateAuthenticateModel, IsAllPermissionsGrantedPipe, IsAuthenticatedPipe, IsClaimGrantedPipe, IsDefined, IsGrantedRolePipe, IsOneActiveDivisionPermissionGrantedGuard, IsOneActiveDivisionPermissionGrantedPipe, IsOneActiveDivisionRoleGrantedGuard, IsOneActiveDivisionRoleGrantedPipe, IsOneClaimGrantedPipe, IsOneDivisionPermissionGrantedPipe, IsOneDivisionRoleGrantedPipe, IsOnePermissionGrantedPipe, IsOneRoleGrantedPipe, JsonLdDataChanged, ListSortDirection, MakeProvider, MutationType, NH_ERROR_HANDLERS, NH_ROUTER_LANGUAGE_CHANGE_METHOD, NH_ROUTER_ROOT_ROUTES, NH_SENTRY_BEFORE_BREADCRUMB_HOOKS, NH_SENTRY_BEFORE_SEND_HOOKS, NH_SENTRY_BEFORE_SEND_LOG_HOOKS, NH_SENTRY_BEFORE_SEND_SPAN_HOOKS, NH_SENTRY_BEFORE_SEND_TRANSACTION_HOOKS, NhAccountInformationResponse, NhAngularUtil, NhApiService, NhApiUtil, NhAppService, NhAsyncLock, NhAuthService, NhAuthorization, NhBaseApiService, NhBooleanToStringPipe, NhBreadCrumb, NhBreadCrumbItem, NhButtonDebounceDirective, NhCanCancelNavigationGuard, NhCollectionBaseComponent, NhCollectionTypeBaseComponent, NhCommonConfig, NhCommonConfigChanged, NhCommonModule, NhCommonModuleConfig, NhConfigCommonService, NhContextMenu, NhContextMenuItem, NhContextMenuService, NhContextMenuServiceConfig, NhCookieService, NhDatePipe, NhDateTimePipe, NhDateUtcPipe, NhDebounceDirective, NhDeduplicateGetRequestsInterceptor, NhDivision, NhDivisionRole, NhDivisionUser, NhEncodeHttpParamsInterceptor, NhEncodingUtil, NhErrorComponent, NhErrorHandlerSentryService, NhErrorHandlerService, NhErrorLoggingNhCommonModuleConfig, NhFormDropDownComponent, NhFormDropDownNhCommonModuleConfig, NhFormDropDownSettings, NhFormErrorMessageComponent, NhFormHelper, NhHeadService, NhHttpNhCommonModuleConfig, NhHttpUtil, NhInternetConnectionService, NhIsAllPermissionsGrantedGuard, NhIsAuthenticatedGuard, NhIsOneClaimGrantedGuard, NhIsOnePermissionGrantedGuard, NhIsOneRoleGrantedGuard, NhJsonLdComponent, NhJsonLdData, NhJsonLdDataItem, NhJsonLdService, NhLoaderComponent, NhMetaService, NhModalComponent, NhModalComponentClosed, NhModalComponentImpl, NhModalComponentRef, NhModalConfirmComponent, NhModalContentDirective, NhModalLoadingComponent, NhModalMutateBaseComponent, NhModalMutateBaseTypeComponent, NhModalOptions, NhModalService, NhMutateBaseComponent, NhMutateBaseTypeComponent, NhMutex, NhPageBaseComponent, NhPageService, NhPageSettings, NhPageSizeComponent, NhPageTypeBaseComponent, NhRegisterRoute, NhRequestScopedServerHttpInterceptorService, NhRoute, NhRouteInfo, NhRouteNavigationItem, NhRouterLinkDirective, NhRouterService, NhRouterSetupService, NhSearchInputComponent, NhSentryErrorLoggingNhCommonModuleConfig, NhSentryInitializerService, NhSentryService, NhSentryTraceService, NhServerHttpInterceptor, NhServerService, NhServerSideFormValidationService, NhSitemap, NhSitemapEntry, NhSitemapEntryItem, NhStringUtil, NhTaskResultFormValidationService, NhTitleService, NhToHeadDirective, NhTranslateBrowserLoader, NhTranslationNhCommonModuleConfig, NhTypedPageBaseComponent, NhTypedPageTypeBaseComponent, NhUrlEncodePipe, NhUser, NhUserNotification, NhUserNotificationCollectionHttpRequestOptions, NhUserNotificationData, NhUserNotificationMessage, NhUserNotificationOverview, NhUserNotificationService, NhUserNotificationState, NhUserNotificationsAbstractComponent, OrderByRequestOptions, PreConnectUrlItem, PreLoadUrlItem, REVIEW_AGGREGATE_RATING_KEY, REVIEW_KEY, RefreshTokenLoginAccountMutateModel, RevertImpersonateAuthenticateModel, SafeHtmlPipe, SafeResourceUrlPipe, SafeUrlPipe, SearchableCollectionHttpRequestOptions, SimpleCollectionHttpRequestOptions, SimpleCollectionHttpResponse, TaskResult, TaskResultItem, TypedNhPageSettings, UserNotificationNhCommonModuleConfig, enumIntValuesToArray, enumKeysToArray, enumStringValuesToArray, enumValuesToArray, getEmptyGuid, getRandomIdentifier, groupBy, languageToCultureMap, nameof, nhTranslateBrowserLoaderFactory, uppercaseFirst };
8705
+ export { AbstractValueAccessor, AspMvcFormServerSideFormValidator, AuthSessionExpirationInformation, AuthenticateModel, AuthenticationNhCommonModuleConfig, AuthenticationSessionCreateResponse, BackgroundOperationsNhCommonModuleConfig, BaseNhAuthService, CheckAuthenticateSessionModel, Claim, ClaimAuthenticateSessionAccountMutateModel, ClaimAuthenticateSessionAccountViewModel, ClaimTypes, CollectionHttpRequestOptions, CollectionHttpResponse, DefaultMultiSelectSettings, DefaultMultiSelectTexts, EndpointsAuthenticationNhCommonModuleConfig, FilterRequestOptions, FormError, FormValidationResult, HttpDownloadRequestOptions, HttpRequestOptions, HttpRequestOptionsArrayBuffer, HttpRequestOptionsText, ImpersonateAuthenticateModel, IsAllPermissionsGrantedPipe, IsAuthenticatedPipe, IsClaimGrantedPipe, IsDefined, IsGrantedRolePipe, IsOneActiveDivisionPermissionGrantedGuard, IsOneActiveDivisionPermissionGrantedPipe, IsOneActiveDivisionRoleGrantedGuard, IsOneActiveDivisionRoleGrantedPipe, IsOneClaimGrantedPipe, IsOneDivisionPermissionGrantedPipe, IsOneDivisionRoleGrantedPipe, IsOnePermissionGrantedPipe, IsOneRoleGrantedPipe, JsonLdDataChanged, ListSortDirection, MakeProvider, MutationType, NH_ERROR_HANDLERS, NH_ROUTER_LANGUAGE_CHANGE_METHOD, NH_ROUTER_ROOT_ROUTES, NhAccountInformationResponse, NhAngularUtil, NhApiService, NhApiUtil, NhAppService, NhAsyncLock, NhAuthService, NhAuthorization, NhBackgroundOperationCollectionHttpRequestOptions, NhBackgroundOperationLiveUpdateService, NhBackgroundOperationProgressComponent, NhBackgroundOperationService, NhBackgroundOperationStore, NhBaseApiService, NhBooleanToStringPipe, NhBreadCrumb, NhBreadCrumbItem, NhButtonDebounceDirective, NhCanCancelNavigationGuard, NhCollectionBaseComponent, NhCollectionTypeBaseComponent, NhCommonConfig, NhCommonConfigChanged, NhCommonModule, NhCommonModuleConfig, NhConfigCommonService, NhContextMenu, NhContextMenuItem, NhContextMenuService, NhContextMenuServiceConfig, NhCookieService, NhDatePipe, NhDateTimePipe, NhDateUtcPipe, NhDebounceDirective, NhDeduplicateGetRequestsInterceptor, NhDivision, NhDivisionRole, NhDivisionUser, NhEncodeHttpParamsInterceptor, NhEncodingUtil, NhErrorComponent, NhErrorHandlerService, NhFormDropDownComponent, NhFormDropDownNhCommonModuleConfig, NhFormDropDownSettings, NhFormErrorMessageComponent, NhFormHelper, NhHeadService, NhHttpNhCommonModuleConfig, NhHttpUtil, NhInternetConnectionService, NhIsAllPermissionsGrantedGuard, NhIsAuthenticatedGuard, NhIsOneClaimGrantedGuard, NhIsOnePermissionGrantedGuard, NhIsOneRoleGrantedGuard, NhJsonLdComponent, NhJsonLdData, NhJsonLdDataItem, NhJsonLdService, NhLoaderComponent, NhMetaService, NhModalComponent, NhModalComponentClosed, NhModalComponentImpl, NhModalComponentRef, NhModalConfirmComponent, NhModalContentDirective, NhModalLoadingComponent, NhModalMutateBaseComponent, NhModalMutateBaseTypeComponent, NhModalOptions, NhModalService, NhMutateBaseComponent, NhMutateBaseTypeComponent, NhMutex, NhPageBaseComponent, NhPageService, NhPageSettings, NhPageSizeComponent, NhPageTypeBaseComponent, NhRegisterRoute, NhRequestScopedServerHttpInterceptorService, NhRoute, NhRouteInfo, NhRouteNavigationItem, NhRouterLinkDirective, NhRouterService, NhRouterSetupService, NhSearchInputComponent, NhServerHttpInterceptor, NhServerService, NhServerSideFormValidationService, NhSitemap, NhSitemapEntry, NhSitemapEntryItem, NhStringUtil, NhTaskResultFormValidationService, NhTitleService, NhToHeadDirective, NhTranslateBrowserLoader, NhTranslationNhCommonModuleConfig, NhTypedPageBaseComponent, NhTypedPageTypeBaseComponent, NhUrlEncodePipe, NhUser, NhUserNotification, NhUserNotificationCollectionHttpRequestOptions, NhUserNotificationData, NhUserNotificationMessage, NhUserNotificationOverview, NhUserNotificationService, NhUserNotificationState, NhUserNotificationsAbstractComponent, OrderByRequestOptions, PreConnectUrlItem, PreLoadUrlItem, REVIEW_AGGREGATE_RATING_KEY, REVIEW_KEY, RefreshTokenLoginAccountMutateModel, RevertImpersonateAuthenticateModel, SafeHtmlPipe, SafeResourceUrlPipe, SafeUrlPipe, SearchableCollectionHttpRequestOptions, SimpleCollectionHttpRequestOptions, SimpleCollectionHttpResponse, TaskResult, TaskResultItem, TypedNhPageSettings, UserNotificationNhCommonModuleConfig, enumIntValuesToArray, enumKeysToArray, enumStringValuesToArray, enumValuesToArray, getEmptyGuid, getRandomIdentifier, groupBy, languageToCultureMap, nameof, nhBackgroundOperationStatusName, nhBackgroundOperationStepStatusName, nhBackgroundOperationTranslationSegment, nhTranslateBrowserLoaderFactory, uppercaseFirst };
8452
8706
  //# sourceMappingURL=newheap-platform-common.mjs.map