@acorex-platform/module-background-job-management-client 0.0.30 → 0.0.32

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.
Files changed (24) hide show
  1. package/fesm2022/{acorex-platform-module-background-job-management-client-background-job-command-error.util-BzDLhWRP.mjs → acorex-platform-module-background-job-management-client-background-job-command-error.util-BHBmSbvw.mjs} +5 -1
  2. package/fesm2022/acorex-platform-module-background-job-management-client-background-job-command-error.util-BHBmSbvw.mjs.map +1 -0
  3. package/fesm2022/acorex-platform-module-background-job-management-client-background-job-source-column.component-JzU8l_7q.mjs +83 -0
  4. package/fesm2022/acorex-platform-module-background-job-management-client-background-job-source-column.component-JzU8l_7q.mjs.map +1 -0
  5. package/fesm2022/{acorex-platform-module-background-job-management-client-cancel-background-job.command-OZPzjIow.mjs → acorex-platform-module-background-job-management-client-cancel-background-job.command-BHCWX1c1.mjs} +2 -2
  6. package/fesm2022/{acorex-platform-module-background-job-management-client-cancel-background-job.command-OZPzjIow.mjs.map → acorex-platform-module-background-job-management-client-cancel-background-job.command-BHCWX1c1.mjs.map} +1 -1
  7. package/fesm2022/acorex-platform-module-background-job-management-client-contracts.mjs +6 -1
  8. package/fesm2022/acorex-platform-module-background-job-management-client-contracts.mjs.map +1 -1
  9. package/fesm2022/acorex-platform-module-background-job-management-client-replay-dead-letter.command-BM4NYBxr.mjs +37 -0
  10. package/fesm2022/acorex-platform-module-background-job-management-client-replay-dead-letter.command-BM4NYBxr.mjs.map +1 -0
  11. package/fesm2022/{acorex-platform-module-background-job-management-client-retry-background-job.command-BdJ_PC_y.mjs → acorex-platform-module-background-job-management-client-retry-background-job.command-BBEAc_i7.mjs} +2 -2
  12. package/fesm2022/{acorex-platform-module-background-job-management-client-retry-background-job.command-BdJ_PC_y.mjs.map → acorex-platform-module-background-job-management-client-retry-background-job.command-BBEAc_i7.mjs.map} +1 -1
  13. package/fesm2022/{acorex-platform-module-background-job-management-client-run-schedule-now.command-orzJ7ZmD.mjs → acorex-platform-module-background-job-management-client-run-schedule-now.command-5RV6hAnH.mjs} +2 -2
  14. package/fesm2022/{acorex-platform-module-background-job-management-client-run-schedule-now.command-orzJ7ZmD.mjs.map → acorex-platform-module-background-job-management-client-run-schedule-now.command-5RV6hAnH.mjs.map} +1 -1
  15. package/fesm2022/acorex-platform-module-background-job-management-client-tray-execute-click.command-CEVhvrDQ.mjs +27 -0
  16. package/fesm2022/acorex-platform-module-background-job-management-client-tray-execute-click.command-CEVhvrDQ.mjs.map +1 -0
  17. package/fesm2022/acorex-platform-module-background-job-management-client-tray-run-action.command-B9SFMGxf.mjs +38 -0
  18. package/fesm2022/acorex-platform-module-background-job-management-client-tray-run-action.command-B9SFMGxf.mjs.map +1 -0
  19. package/fesm2022/acorex-platform-module-background-job-management-client.mjs +556 -17
  20. package/fesm2022/acorex-platform-module-background-job-management-client.mjs.map +1 -1
  21. package/package.json +1 -1
  22. package/types/acorex-platform-module-background-job-management-client-contracts.d.ts +6 -1
  23. package/types/acorex-platform-module-background-job-management-client.d.ts +9 -2
  24. package/fesm2022/acorex-platform-module-background-job-management-client-background-job-command-error.util-BzDLhWRP.mjs.map +0 -1
@@ -1,15 +1,20 @@
1
- import { AXP_BACKGROUND_JOB_SCHEDULE_STATUS_DEFINITION_KEY, AXP_BACKGROUND_JOB_SCHEDULE_STATUS_ACTIVE, AXP_BACKGROUND_JOB_STATUS_DEFINITION_KEY, AXP_BACKGROUND_JOB_STATUS_CREATED, AXPBackgroundJobCommandKeys } from '@acorex-platform/framework-shared/background-job';
2
- import { AXPSessionService, AXP_PERMISSION_DEFINITION_PROVIDER } from '@acorex-platform/framework-client/auth';
3
- import { AXP_STATUS_PROVIDERS, AXP_MENU_PROVIDER, AXP_SETTING_DEFINITION_PROVIDER } from '@acorex-platform/framework-client/common';
4
- import { AXP_MODULE_MANIFEST_PROVIDER } from '@acorex-platform/framework-client/core';
5
- import { provideCommandSetups } from '@acorex-platform/framework-client/runtime';
1
+ import { AXP_BACKGROUND_JOB_SCHEDULE_STATUS_DEFINITION_KEY, AXP_BACKGROUND_JOB_SCHEDULE_STATUS_ACTIVE, AXP_BACKGROUND_JOB_STATUS_DEFINITION_KEY, AXP_BACKGROUND_JOB_STATUS_CREATED, AXPBackgroundJobQueryKeys, isBackgroundJobTerminal, AXPBackgroundJobCommandKeys } from '@acorex-platform/framework-shared/background-job';
2
+ import { AXPSessionService, AXPSessionStatus, AXP_PERMISSION_DEFINITION_PROVIDER } from '@acorex-platform/framework-client/auth';
3
+ import { axpCoerceBackgroundOperationDate, axpBackgroundOperationFailurePolicy, axpBackgroundOperationCapabilities, AXPBackgroundOperationProvider, AXP_BACKGROUND_OPERATION_PROVIDERS, AXP_STATUS_PROVIDERS, AXP_MENU_PROVIDER, AXP_SETTING_DEFINITION_PROVIDER } from '@acorex-platform/framework-client/common';
4
+ import { provideAppStartUpTask, AXP_APP_STARTUP_PRIORITY, AXP_MODULE_MANIFEST_PROVIDER } from '@acorex-platform/framework-client/core';
5
+ import { AXPQueryService, provideCommandSetups } from '@acorex-platform/framework-client/runtime';
6
+ import { AXPWidgetCoreModule, AXP_WIDGET_DEFINITION_PROVIDER } from '@acorex-platform/framework-client/layout/widget-core';
6
7
  import * as i0 from '@angular/core';
7
- import { inject, Injectable, NgModule } from '@angular/core';
8
- import { AXPStatusProvider, AXPWidgetsList } from '@acorex-platform/framework-shared/core';
9
- import { RootConfig, AXPAdministrationPermissionKeys, AXPBackgroundJobManagementMenuKeys, AXPBackgroundJobManagementSettings } from '@acorex-platform/module-background-job-management-client/contracts';
8
+ import { Injectable, inject, DestroyRef, signal, computed, NgModule } from '@angular/core';
9
+ import { BACKGROUND_JOB_SOURCE_COLUMN_WIDGET, RootConfig, AXPAdministrationPermissionKeys, AXPBackgroundJobManagementMenuKeys, AXPBackgroundJobManagementSettings } from '@acorex-platform/module-background-job-management-client/contracts';
10
+ import { AXPWidgetGroupEnum } from '@acorex-platform/framework-shared/widget-core';
11
+ import { AXPStatusProvider, runtimeQueryCollectionData, AXPWidgetsList } from '@acorex-platform/framework-shared/core';
12
+ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
13
+ import { filter } from 'rxjs/operators';
14
+ import { Subject, distinctUntilChanged, timer, switchMap, EMPTY, firstValueFrom } from 'rxjs';
15
+ import { AXPRealtimeConnectionService, AXPRealtimeDispatcherService, AXP_REALTIME_TOPIC_BACKGROUND_JOB_TRAY_REFRESH } from '@acorex-platform/framework-client/realtime';
10
16
  import { AXPCommonMenuKeys, AXPCommonPermissionGroupKeys } from '@acorex-platform/module-common-client/contracts';
11
17
  import { AXPEntityService } from '@acorex-platform/framework-client/layout/entity';
12
- import { firstValueFrom } from 'rxjs';
13
18
 
14
19
  //#region ---- Client port ----
15
20
  /**
@@ -20,6 +25,37 @@ class AXPBackgroundJobManagementClient {
20
25
  }
21
26
  //#endregion
22
27
 
28
+ //#region ----- Imports -----
29
+ //#endregion
30
+ //#region ----- Widget -----
31
+ const BackgroundJobSourceColumnWidget = {
32
+ name: BACKGROUND_JOB_SOURCE_COLUMN_WIDGET,
33
+ title: '@background-job-management:jobs.entities.background-job.fields.source.title',
34
+ icon: 'fa-light fa-user',
35
+ groups: [AXPWidgetGroupEnum.BaseWidget],
36
+ type: 'editor',
37
+ components: {
38
+ column: {
39
+ component: () => import('./acorex-platform-module-background-job-management-client-background-job-source-column.component-JzU8l_7q.mjs').then((c) => c.BackgroundJobSourceColumnComponent),
40
+ },
41
+ },
42
+ };
43
+ //#endregion
44
+
45
+ //#endregion
46
+ //#region ----- Widgets provider -----
47
+ const BACKGROUND_JOB_WIDGETS = [BackgroundJobSourceColumnWidget];
48
+ class AXMBackgroundJobManagementWidgetsProvider {
49
+ getWidgets() {
50
+ return BACKGROUND_JOB_WIDGETS;
51
+ }
52
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMBackgroundJobManagementWidgetsProvider, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
53
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMBackgroundJobManagementWidgetsProvider }); }
54
+ }
55
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMBackgroundJobManagementWidgetsProvider, decorators: [{
56
+ type: Injectable
57
+ }] });
58
+
23
59
  const I18N$1 = '@background-job-management:schedules.entities.background-job-schedule';
24
60
  //#region ---- Job schedule status provider ----
25
61
  class AXMBackgroundJobScheduleStatusProvider extends AXPStatusProvider {
@@ -138,6 +174,472 @@ class AXMBackgroundJobStatusProvider extends AXPStatusProvider {
138
174
  }
139
175
  //#endregion
140
176
 
177
+ //#region ----- Status mapping -----
178
+ const ACTIVE_JOB_STATUSES = new Set([
179
+ 'created',
180
+ 'scheduled',
181
+ 'queued',
182
+ 'running',
183
+ 'paused',
184
+ ]);
185
+ function mapBackgroundJobStatusToOperationStatus(status) {
186
+ switch (status) {
187
+ case 'running':
188
+ return 'running';
189
+ case 'paused':
190
+ return 'paused';
191
+ case 'completed':
192
+ return 'completed';
193
+ case 'failed':
194
+ case 'dead-lettered':
195
+ return 'failed';
196
+ case 'cancelled':
197
+ return 'cancelled';
198
+ case 'created':
199
+ case 'scheduled':
200
+ case 'queued':
201
+ default:
202
+ return 'queued';
203
+ }
204
+ }
205
+ //#endregion
206
+ //#region ----- Job → tray operation -----
207
+ function mapBackgroundJobToTrayOperation(job) {
208
+ const status = mapBackgroundJobStatusToOperationStatus(job.status);
209
+ const isActive = ACTIVE_JOB_STATUSES.has(job.status);
210
+ const capabilities = job.capabilities ?? {};
211
+ const createdAt = axpCoerceBackgroundOperationDate(job.createdAt) ?? new Date();
212
+ return {
213
+ id: job.id,
214
+ providerKey: job.providerKey,
215
+ title: job.title,
216
+ status,
217
+ progress: job.progress,
218
+ statusText: job.statusText,
219
+ currentStep: job.currentStep,
220
+ createdAt,
221
+ startedAt: axpCoerceBackgroundOperationDate(job.firstStartedAt) ??
222
+ axpCoerceBackgroundOperationDate(job.executedAt) ??
223
+ undefined,
224
+ completedAt: axpCoerceBackgroundOperationDate(job.completedAt) ?? undefined,
225
+ capabilities: axpBackgroundOperationCapabilities({
226
+ cancellable: isActive &&
227
+ (capabilities.supportsCooperativeCancellation === true || capabilities.canCancelQueued === true),
228
+ pausable: isActive && capabilities.supportsCooperativePause === true,
229
+ resumable: status === 'paused' && capabilities.supportsCooperativePause === true,
230
+ retryable: status === 'failed',
231
+ supportsProgress: capabilities.supportsProgress === true || typeof job.progress === 'number',
232
+ supportsEstimate: capabilities.supportsEstimate === true,
233
+ clickable: capabilities.clickable === true,
234
+ keepInTrayAfterComplete: capabilities.keepInTrayAfterComplete === true,
235
+ notifyOnComplete: capabilities.notifyOnComplete !== false,
236
+ notifyOnFailed: capabilities.notifyOnFailed !== false,
237
+ }),
238
+ failurePolicy: axpBackgroundOperationFailurePolicy({
239
+ maxRetries: job.maxAttempts,
240
+ retryCount: Math.max(0, job.currentAttempt - 1),
241
+ }),
242
+ error: job.result?.message
243
+ ? {
244
+ message: job.result.message,
245
+ code: typeof job.result.data?.['code'] === 'string' ? job.result.data['code'] : undefined,
246
+ }
247
+ : undefined,
248
+ data: {
249
+ jobId: job.id,
250
+ providerKey: job.providerKey,
251
+ command: job.command,
252
+ payload: job.command?.payload,
253
+ reportRequestId: typeof job.command?.payload?.['reportRequestId'] === 'string'
254
+ ? job.command.payload['reportRequestId']
255
+ : undefined,
256
+ },
257
+ };
258
+ }
259
+ //#endregion
260
+
261
+ //#endregion
262
+ //#region ----- Tray realtime events -----
263
+ class BackgroundJobTrayRealtimeService {
264
+ constructor() {
265
+ this.changedSubject = new Subject();
266
+ this.changed$ = this.changedSubject.asObservable();
267
+ }
268
+ notifyChanged(payload) {
269
+ this.changedSubject.next({ payload });
270
+ }
271
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: BackgroundJobTrayRealtimeService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
272
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: BackgroundJobTrayRealtimeService, providedIn: 'root' }); }
273
+ }
274
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: BackgroundJobTrayRealtimeService, decorators: [{
275
+ type: Injectable,
276
+ args: [{
277
+ providedIn: 'root',
278
+ }]
279
+ }] });
280
+
281
+ //#region ----- Constants -----
282
+ /** Safety net while a job is active if a realtime tick was missed. */
283
+ const ACTIVE_JOB_WATCHDOG_MS = 30_000;
284
+ /** Coalesce consecutive full-list fetches (e.g. create + early progress before local row exists). */
285
+ const FULL_REFRESH_DEBOUNCE_MS = 250;
286
+ const TERMINAL_STATUSES = new Set(['completed', 'failed', 'cancelled', 'dead-lettered']);
287
+ //#endregion
288
+ //#region ----- Tray sync service -----
289
+ class BackgroundJobTraySyncService {
290
+ constructor() {
291
+ //#region ----- Dependencies -----
292
+ this.queryService = inject(AXPQueryService);
293
+ this.sessionService = inject(AXPSessionService);
294
+ this.client = inject(AXPBackgroundJobManagementClient);
295
+ this.destroyRef = inject(DestroyRef);
296
+ this.trayRealtime = inject(BackgroundJobTrayRealtimeService, { optional: true });
297
+ //#endregion
298
+ //#region ----- State -----
299
+ this.jobs = signal([], /* @ts-ignore */
300
+ ...(ngDevMode ? [{ debugName: "jobs" }] : /* istanbul ignore next */ []));
301
+ this.started = false;
302
+ this.refreshGeneration = 0;
303
+ this.refreshInFlight = false;
304
+ this.refreshQueued = false;
305
+ this.watchdogTimer = null;
306
+ this.fullRefreshTimer = null;
307
+ this.operations = computed(() => this.jobs().map((job) => mapBackgroundJobToTrayOperation(job)), /* @ts-ignore */
308
+ ...(ngDevMode ? [{ debugName: "operations" }] : /* istanbul ignore next */ []));
309
+ }
310
+ //#endregion
311
+ //#region ----- Lifecycle -----
312
+ start() {
313
+ if (this.started) {
314
+ return;
315
+ }
316
+ this.started = true;
317
+ this.destroyRef.onDestroy(() => {
318
+ this.clearActiveWatchdog();
319
+ this.clearFullRefreshTimer();
320
+ });
321
+ this.sessionService.status$
322
+ .pipe(filter((status) => status === AXPSessionStatus.Authorized), takeUntilDestroyed(this.destroyRef))
323
+ .subscribe(() => {
324
+ void this.refresh();
325
+ });
326
+ this.sessionService.status$
327
+ .pipe(filter((status) => status !== AXPSessionStatus.Authorized), takeUntilDestroyed(this.destroyRef))
328
+ .subscribe(() => {
329
+ this.clearActiveWatchdog();
330
+ this.clearFullRefreshTimer();
331
+ this.jobs.set([]);
332
+ });
333
+ this.trayRealtime?.changed$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(({ payload }) => {
334
+ this.applyRealtimePayload(payload);
335
+ });
336
+ if (this.sessionService.isAuthorized) {
337
+ void this.refresh();
338
+ }
339
+ }
340
+ async refresh() {
341
+ this.clearFullRefreshTimer();
342
+ if (this.refreshInFlight) {
343
+ this.refreshQueued = true;
344
+ return;
345
+ }
346
+ this.refreshInFlight = true;
347
+ const generation = ++this.refreshGeneration;
348
+ try {
349
+ if (!this.sessionService.isAuthorized) {
350
+ if (generation === this.refreshGeneration) {
351
+ this.clearActiveWatchdog();
352
+ this.jobs.set([]);
353
+ }
354
+ return;
355
+ }
356
+ try {
357
+ const result = await this.queryService.fetch(AXPBackgroundJobQueryKeys.JobListActiveForTray, { take: 100 });
358
+ if (generation !== this.refreshGeneration) {
359
+ return;
360
+ }
361
+ const items = runtimeQueryCollectionData(result)?.items ?? [];
362
+ this.jobs.set(items);
363
+ this.armActiveWatchdog();
364
+ }
365
+ catch {
366
+ // Keep the last known tray snapshot when sync fails transiently.
367
+ if (generation === this.refreshGeneration) {
368
+ this.armActiveWatchdog();
369
+ }
370
+ }
371
+ }
372
+ finally {
373
+ this.refreshInFlight = false;
374
+ if (this.refreshQueued) {
375
+ this.refreshQueued = false;
376
+ if (this.sessionService.isAuthorized) {
377
+ void this.refresh();
378
+ }
379
+ }
380
+ }
381
+ }
382
+ async dismissJobs(jobIds) {
383
+ const ids = [...new Set(jobIds.map((id) => id?.trim()).filter(Boolean))];
384
+ if (ids.length === 0) {
385
+ return;
386
+ }
387
+ // Optimistic hide; realtime `dismissed` keeps other tabs in sync without a list refetch.
388
+ this.removeJobs(ids);
389
+ await this.client.dismissJobs(ids);
390
+ }
391
+ //#endregion
392
+ //#region ----- Private helpers -----
393
+ applyRealtimePayload(payload) {
394
+ if (!this.sessionService.isAuthorized) {
395
+ return;
396
+ }
397
+ const jobId = payload.jobId?.trim();
398
+ if (!jobId) {
399
+ this.scheduleFullRefresh();
400
+ return;
401
+ }
402
+ if (payload.op === 'dismissed' || payload.trayDismissedAt) {
403
+ this.removeJobs([jobId]);
404
+ return;
405
+ }
406
+ if (payload.op === 'created') {
407
+ // New jobs need the full row (title, capabilities, command payload).
408
+ this.scheduleFullRefresh();
409
+ return;
410
+ }
411
+ const existing = this.jobs().find((job) => job.id === jobId);
412
+ if (!existing) {
413
+ this.scheduleFullRefresh();
414
+ return;
415
+ }
416
+ const nextStatus = (payload.status?.trim() || existing.status);
417
+ const keepInTray = payload.keepInTrayAfterComplete === true || existing.capabilities?.keepInTrayAfterComplete === true;
418
+ if (isBackgroundJobTerminal(nextStatus) && !keepInTray) {
419
+ this.removeJobs([jobId]);
420
+ return;
421
+ }
422
+ this.jobs.update((current) => current.map((job) => {
423
+ if (job.id !== jobId) {
424
+ return job;
425
+ }
426
+ return {
427
+ ...job,
428
+ status: nextStatus,
429
+ progress: typeof payload.progress === 'number' ? payload.progress : job.progress,
430
+ statusText: payload.statusText ?? job.statusText,
431
+ currentStep: payload.currentStep ?? job.currentStep,
432
+ capabilities: {
433
+ ...(job.capabilities ?? {}),
434
+ supportsProgress: job.capabilities?.supportsProgress === true ||
435
+ payload.supportsProgress === true ||
436
+ typeof payload.progress === 'number',
437
+ },
438
+ completedAt: payload.completedAt ??
439
+ (TERMINAL_STATUSES.has(nextStatus) ? job.completedAt ?? new Date().toISOString() : job.completedAt),
440
+ };
441
+ }));
442
+ this.armActiveWatchdog();
443
+ }
444
+ scheduleFullRefresh() {
445
+ this.clearFullRefreshTimer();
446
+ this.fullRefreshTimer = setTimeout(() => {
447
+ this.fullRefreshTimer = null;
448
+ void this.refresh();
449
+ }, FULL_REFRESH_DEBOUNCE_MS);
450
+ }
451
+ clearFullRefreshTimer() {
452
+ if (!this.fullRefreshTimer) {
453
+ return;
454
+ }
455
+ clearTimeout(this.fullRefreshTimer);
456
+ this.fullRefreshTimer = null;
457
+ }
458
+ removeJobs(jobIds) {
459
+ const idSet = new Set(jobIds);
460
+ this.jobs.update((current) => current.filter((job) => !idSet.has(job.id)));
461
+ this.armActiveWatchdog();
462
+ }
463
+ hasActiveTrayJob() {
464
+ return this.jobs().some((job) => !isBackgroundJobTerminal(job.status));
465
+ }
466
+ armActiveWatchdog() {
467
+ this.clearActiveWatchdog();
468
+ if (!this.sessionService.isAuthorized || !this.hasActiveTrayJob()) {
469
+ return;
470
+ }
471
+ this.watchdogTimer = setTimeout(() => {
472
+ this.watchdogTimer = null;
473
+ void this.refresh();
474
+ }, ACTIVE_JOB_WATCHDOG_MS);
475
+ }
476
+ clearActiveWatchdog() {
477
+ if (!this.watchdogTimer) {
478
+ return;
479
+ }
480
+ clearTimeout(this.watchdogTimer);
481
+ this.watchdogTimer = null;
482
+ }
483
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: BackgroundJobTraySyncService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
484
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: BackgroundJobTraySyncService, providedIn: 'root' }); }
485
+ }
486
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: BackgroundJobTraySyncService, decorators: [{
487
+ type: Injectable,
488
+ args: [{ providedIn: 'root' }]
489
+ }] });
490
+
491
+ //#region ----- Tray operation provider -----
492
+ class BackgroundJobTrayOperationProvider extends AXPBackgroundOperationProvider {
493
+ constructor() {
494
+ super(...arguments);
495
+ this.key = 'background-job';
496
+ this.sync = inject(BackgroundJobTraySyncService);
497
+ this.client = inject(AXPBackgroundJobManagementClient);
498
+ this.operations = this.sync.operations;
499
+ }
500
+ async create(_request) {
501
+ throw new Error('Background jobs are created on the server.');
502
+ }
503
+ async cancel(operationId) {
504
+ await this.client.cancelJob(operationId);
505
+ await this.sync.refresh();
506
+ }
507
+ async pause(_operationId) {
508
+ throw new Error('Pause is not supported from the tray yet.');
509
+ }
510
+ async resume(_operationId) {
511
+ throw new Error('Resume is not supported from the tray yet.');
512
+ }
513
+ async retry(operationId) {
514
+ await this.client.retryJob(operationId);
515
+ await this.sync.refresh();
516
+ }
517
+ async dismiss(operationId) {
518
+ await this.sync.dismissJobs([operationId]);
519
+ }
520
+ async dismissMany(operationIds) {
521
+ await this.sync.dismissJobs(operationIds);
522
+ }
523
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: BackgroundJobTrayOperationProvider, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
524
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: BackgroundJobTrayOperationProvider }); }
525
+ }
526
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: BackgroundJobTrayOperationProvider, decorators: [{
527
+ type: Injectable
528
+ }] });
529
+
530
+ //#region ----- Constants -----
531
+ const POLL_INTERVAL_MS = 60_000;
532
+ const RECONNECT_REFRESH_DELAY_MS = 250;
533
+ //#endregion
534
+ //#region ----- Tray fallback sync -----
535
+ /**
536
+ * Keeps the footer tray fresh when Socket.IO is down: poll while disconnected,
537
+ * refresh on reconnect and when the tab becomes visible again.
538
+ */
539
+ function provideBackgroundJobTrayFallbackSync() {
540
+ return [
541
+ provideAppStartUpTask(() => {
542
+ const sync = inject(BackgroundJobTraySyncService);
543
+ const sessionService = inject(AXPSessionService);
544
+ const connection = inject(AXPRealtimeConnectionService, { optional: true });
545
+ const destroyRef = inject(DestroyRef);
546
+ const refreshIfAuthorized = () => {
547
+ if (sessionService.isReadyForAppScopedApi) {
548
+ void sync.refresh();
549
+ }
550
+ };
551
+ return {
552
+ name: 'background-job-tray-fallback-sync',
553
+ priority: AXP_APP_STARTUP_PRIORITY.realtimeSubscriptions,
554
+ run: async () => {
555
+ if (!connection) {
556
+ return;
557
+ }
558
+ let wasConnected = connection.isSocketConnected();
559
+ connection.connectionStatus$
560
+ .pipe(distinctUntilChanged(), takeUntilDestroyed(destroyRef))
561
+ .subscribe((status) => {
562
+ const connected = status === 'connected';
563
+ if (connected && !wasConnected) {
564
+ timer(RECONNECT_REFRESH_DELAY_MS)
565
+ .pipe(takeUntilDestroyed(destroyRef))
566
+ .subscribe(() => {
567
+ refreshIfAuthorized();
568
+ });
569
+ }
570
+ wasConnected = connected;
571
+ });
572
+ connection.connectionStatus$
573
+ .pipe(distinctUntilChanged(), switchMap((status) => {
574
+ if (status === 'connected') {
575
+ return EMPTY;
576
+ }
577
+ return timer(POLL_INTERVAL_MS, POLL_INTERVAL_MS);
578
+ }), takeUntilDestroyed(destroyRef))
579
+ .subscribe(() => {
580
+ refreshIfAuthorized();
581
+ });
582
+ document.addEventListener('visibilitychange', () => {
583
+ if (document.visibilityState === 'visible') {
584
+ refreshIfAuthorized();
585
+ }
586
+ }, { passive: true });
587
+ },
588
+ };
589
+ }),
590
+ ];
591
+ }
592
+ //#endregion
593
+
594
+ //#region ----- Tray realtime topic handler -----
595
+ function provideBackgroundJobTrayRealtimeHandlers() {
596
+ return [
597
+ provideAppStartUpTask(() => {
598
+ const dispatcher = inject(AXPRealtimeDispatcherService, { optional: true });
599
+ const trayRealtime = inject(BackgroundJobTrayRealtimeService);
600
+ return {
601
+ name: 'background-job-tray-realtime-handlers',
602
+ priority: AXP_APP_STARTUP_PRIORITY.realtimeHandlers,
603
+ run: async () => {
604
+ dispatcher?.register({
605
+ topic: AXP_REALTIME_TOPIC_BACKGROUND_JOB_TRAY_REFRESH,
606
+ handle: (envelope) => {
607
+ const payload = (envelope.payload ?? {});
608
+ trayRealtime.notifyChanged(payload);
609
+ },
610
+ });
611
+ },
612
+ };
613
+ }),
614
+ ];
615
+ }
616
+ //#endregion
617
+
618
+ //#region ----- Tray providers -----
619
+ function provideBackgroundJobTray() {
620
+ return [
621
+ BackgroundJobTrayOperationProvider,
622
+ {
623
+ provide: AXP_BACKGROUND_OPERATION_PROVIDERS,
624
+ useExisting: BackgroundJobTrayOperationProvider,
625
+ multi: true,
626
+ },
627
+ ...provideBackgroundJobTrayRealtimeHandlers(),
628
+ ...provideBackgroundJobTrayFallbackSync(),
629
+ provideAppStartUpTask(() => {
630
+ const sync = inject(BackgroundJobTraySyncService);
631
+ return {
632
+ name: 'background-job-tray-sync',
633
+ priority: AXP_APP_STARTUP_PRIORITY.realtimeHandlers,
634
+ run: async () => {
635
+ sync.start();
636
+ },
637
+ };
638
+ }),
639
+ ];
640
+ }
641
+ //#endregion
642
+
141
643
  /** Background Job Management module manifest. */
142
644
  const BackgroundJobManagementManifest = {
143
645
  name: RootConfig.module.name,
@@ -308,20 +810,38 @@ class AXMBackgroundJobManagementSettingProvider {
308
810
 
309
811
  class AXMBackgroundJobManagementModule {
310
812
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMBackgroundJobManagementModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
311
- static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "22.0.8", ngImport: i0, type: AXMBackgroundJobManagementModule }); }
813
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "22.0.8", ngImport: i0, type: AXMBackgroundJobManagementModule, imports: [AXPWidgetCoreModule] }); }
312
814
  static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMBackgroundJobManagementModule, providers: [
815
+ {
816
+ provide: AXP_WIDGET_DEFINITION_PROVIDER,
817
+ useClass: AXMBackgroundJobManagementWidgetsProvider,
818
+ multi: true,
819
+ },
820
+ ...provideBackgroundJobTray(),
313
821
  provideCommandSetups([
314
822
  {
315
823
  key: AXPBackgroundJobCommandKeys.JobCancel,
316
- command: () => import('./acorex-platform-module-background-job-management-client-cancel-background-job.command-OZPzjIow.mjs').then((c) => c.CancelBackgroundJobCommand),
824
+ command: () => import('./acorex-platform-module-background-job-management-client-cancel-background-job.command-BHCWX1c1.mjs').then((c) => c.CancelBackgroundJobCommand),
317
825
  },
318
826
  {
319
827
  key: AXPBackgroundJobCommandKeys.JobRetry,
320
- command: () => import('./acorex-platform-module-background-job-management-client-retry-background-job.command-BdJ_PC_y.mjs').then((c) => c.RetryBackgroundJobCommand),
828
+ command: () => import('./acorex-platform-module-background-job-management-client-retry-background-job.command-BBEAc_i7.mjs').then((c) => c.RetryBackgroundJobCommand),
829
+ },
830
+ {
831
+ key: AXPBackgroundJobCommandKeys.JobReplayDeadLetter,
832
+ command: () => import('./acorex-platform-module-background-job-management-client-replay-dead-letter.command-BM4NYBxr.mjs').then((c) => c.ReplayDeadLetterBackgroundJobCommand),
833
+ },
834
+ {
835
+ key: AXPBackgroundJobCommandKeys.TrayExecuteClick,
836
+ command: () => import('./acorex-platform-module-background-job-management-client-tray-execute-click.command-CEVhvrDQ.mjs').then((c) => c.BackgroundJobTrayExecuteClickCommand),
837
+ },
838
+ {
839
+ key: AXPBackgroundJobCommandKeys.TrayRunAction,
840
+ command: () => import('./acorex-platform-module-background-job-management-client-tray-run-action.command-B9SFMGxf.mjs').then((c) => c.BackgroundJobTrayRunActionCommand),
321
841
  },
322
842
  {
323
843
  key: AXPBackgroundJobCommandKeys.ScheduleRunNow,
324
- command: () => import('./acorex-platform-module-background-job-management-client-run-schedule-now.command-orzJ7ZmD.mjs').then((c) => c.RunScheduleNowCommand),
844
+ command: () => import('./acorex-platform-module-background-job-management-client-run-schedule-now.command-5RV6hAnH.mjs').then((c) => c.RunScheduleNowCommand),
325
845
  },
326
846
  ]),
327
847
  {
@@ -354,24 +874,43 @@ class AXMBackgroundJobManagementModule {
354
874
  useValue: BackgroundJobManagementManifest,
355
875
  multi: true,
356
876
  },
357
- ] }); }
877
+ ], imports: [AXPWidgetCoreModule] }); }
358
878
  }
359
879
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMBackgroundJobManagementModule, decorators: [{
360
880
  type: NgModule,
361
881
  args: [{
882
+ imports: [AXPWidgetCoreModule],
362
883
  providers: [
884
+ {
885
+ provide: AXP_WIDGET_DEFINITION_PROVIDER,
886
+ useClass: AXMBackgroundJobManagementWidgetsProvider,
887
+ multi: true,
888
+ },
889
+ ...provideBackgroundJobTray(),
363
890
  provideCommandSetups([
364
891
  {
365
892
  key: AXPBackgroundJobCommandKeys.JobCancel,
366
- command: () => import('./acorex-platform-module-background-job-management-client-cancel-background-job.command-OZPzjIow.mjs').then((c) => c.CancelBackgroundJobCommand),
893
+ command: () => import('./acorex-platform-module-background-job-management-client-cancel-background-job.command-BHCWX1c1.mjs').then((c) => c.CancelBackgroundJobCommand),
367
894
  },
368
895
  {
369
896
  key: AXPBackgroundJobCommandKeys.JobRetry,
370
- command: () => import('./acorex-platform-module-background-job-management-client-retry-background-job.command-BdJ_PC_y.mjs').then((c) => c.RetryBackgroundJobCommand),
897
+ command: () => import('./acorex-platform-module-background-job-management-client-retry-background-job.command-BBEAc_i7.mjs').then((c) => c.RetryBackgroundJobCommand),
898
+ },
899
+ {
900
+ key: AXPBackgroundJobCommandKeys.JobReplayDeadLetter,
901
+ command: () => import('./acorex-platform-module-background-job-management-client-replay-dead-letter.command-BM4NYBxr.mjs').then((c) => c.ReplayDeadLetterBackgroundJobCommand),
902
+ },
903
+ {
904
+ key: AXPBackgroundJobCommandKeys.TrayExecuteClick,
905
+ command: () => import('./acorex-platform-module-background-job-management-client-tray-execute-click.command-CEVhvrDQ.mjs').then((c) => c.BackgroundJobTrayExecuteClickCommand),
906
+ },
907
+ {
908
+ key: AXPBackgroundJobCommandKeys.TrayRunAction,
909
+ command: () => import('./acorex-platform-module-background-job-management-client-tray-run-action.command-B9SFMGxf.mjs').then((c) => c.BackgroundJobTrayRunActionCommand),
371
910
  },
372
911
  {
373
912
  key: AXPBackgroundJobCommandKeys.ScheduleRunNow,
374
- command: () => import('./acorex-platform-module-background-job-management-client-run-schedule-now.command-orzJ7ZmD.mjs').then((c) => c.RunScheduleNowCommand),
913
+ command: () => import('./acorex-platform-module-background-job-management-client-run-schedule-now.command-5RV6hAnH.mjs').then((c) => c.RunScheduleNowCommand),
375
914
  },
376
915
  ]),
377
916
  {