@acorex-platform/module-report-management-client 0.0.30 → 0.0.33
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/{acorex-platform-module-report-management-client-acorex-platform-module-report-management-client-BDCuhd5O.mjs → acorex-platform-module-report-management-client-acorex-platform-module-report-management-client-DENcGULA.mjs} +1018 -386
- package/fesm2022/acorex-platform-module-report-management-client-acorex-platform-module-report-management-client-DENcGULA.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-report-management-client-contracts-entities-query-snapshot-policy.mjs +143 -0
- package/fesm2022/acorex-platform-module-report-management-client-contracts-entities-query-snapshot-policy.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-report-management-client-contracts-entities-query-snapshot.mjs +183 -0
- package/fesm2022/acorex-platform-module-report-management-client-contracts-entities-query-snapshot.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-report-management-client-contracts-entities-report-category.mjs +129 -0
- package/fesm2022/acorex-platform-module-report-management-client-contracts-entities-report-category.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-report-management-client-contracts-entities-report-generation-request.mjs +260 -0
- package/fesm2022/acorex-platform-module-report-management-client-contracts-entities-report-generation-request.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-report-management-client-contracts-entities-report.mjs +170 -0
- package/fesm2022/acorex-platform-module-report-management-client-contracts-entities-report.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-report-management-client-contracts-entity-catalog-acorex-platform-module-report-management-client-contracts-entity-catalog-CgrfJQLl.mjs +83 -0
- package/fesm2022/acorex-platform-module-report-management-client-contracts-entity-catalog-acorex-platform-module-report-management-client-contracts-entity-catalog-CgrfJQLl.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-report-management-client-contracts-entity-catalog-query-snapshot-policy.entity-D50GUBH6.mjs +83 -0
- package/fesm2022/acorex-platform-module-report-management-client-contracts-entity-catalog-query-snapshot-policy.entity-D50GUBH6.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-report-management-client-contracts-entity-catalog-query-snapshot.entity-DuR9ZuN2.mjs +123 -0
- package/fesm2022/acorex-platform-module-report-management-client-contracts-entity-catalog-query-snapshot.entity-DuR9ZuN2.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-report-management-client-contracts-entity-catalog-report-category.entity-Dc4uvjsG.mjs +69 -0
- package/fesm2022/acorex-platform-module-report-management-client-contracts-entity-catalog-report-category.entity-Dc4uvjsG.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-report-management-client-contracts-entity-catalog-report-generation-request.entity-mJUQuk89.mjs +200 -0
- package/fesm2022/acorex-platform-module-report-management-client-contracts-entity-catalog-report-generation-request.entity-mJUQuk89.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-report-management-client-contracts-entity-catalog-report.entity-CMDFRHeK.mjs +110 -0
- package/fesm2022/acorex-platform-module-report-management-client-contracts-entity-catalog-report.entity-CMDFRHeK.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-report-management-client-contracts-entity-catalog.mjs +2 -0
- package/fesm2022/acorex-platform-module-report-management-client-contracts-entity-catalog.mjs.map +1 -0
- package/fesm2022/acorex-platform-module-report-management-client-contracts.mjs +23 -1
- package/fesm2022/acorex-platform-module-report-management-client-contracts.mjs.map +1 -1
- package/fesm2022/{acorex-platform-module-report-management-client-entity-reports-page-component.provider-C6tJPxri.mjs → acorex-platform-module-report-management-client-entity-reports-page-component.provider-B_i4p7tQ.mjs} +3 -3
- package/fesm2022/{acorex-platform-module-report-management-client-entity-reports-page-component.provider-C6tJPxri.mjs.map → acorex-platform-module-report-management-client-entity-reports-page-component.provider-B_i4p7tQ.mjs.map} +1 -1
- package/fesm2022/{acorex-platform-module-report-management-client-entity-reports-page.component-fBftKdQW.mjs → acorex-platform-module-report-management-client-entity-reports-page.component-D27Gtma6.mjs} +2 -2
- package/fesm2022/{acorex-platform-module-report-management-client-entity-reports-page.component-fBftKdQW.mjs.map → acorex-platform-module-report-management-client-entity-reports-page.component-D27Gtma6.mjs.map} +1 -1
- package/fesm2022/acorex-platform-module-report-management-client-local-entities.mjs +33 -0
- package/fesm2022/acorex-platform-module-report-management-client-local-entities.mjs.map +1 -0
- package/fesm2022/{acorex-platform-module-report-management-client-report-popup-viewer.component-B9msMMod.mjs → acorex-platform-module-report-management-client-report-popup-viewer.component-B6aTfRp0.mjs} +2 -2
- package/fesm2022/{acorex-platform-module-report-management-client-report-popup-viewer.component-B9msMMod.mjs.map → acorex-platform-module-report-management-client-report-popup-viewer.component-B6aTfRp0.mjs.map} +1 -1
- package/fesm2022/acorex-platform-module-report-management-client.mjs +1 -1
- package/package.json +29 -1
- package/types/acorex-platform-module-report-management-client-contracts-entities-query-snapshot-policy.d.ts +5 -0
- package/types/acorex-platform-module-report-management-client-contracts-entities-query-snapshot.d.ts +5 -0
- package/types/acorex-platform-module-report-management-client-contracts-entities-report-category.d.ts +5 -0
- package/types/acorex-platform-module-report-management-client-contracts-entities-report-generation-request.d.ts +5 -0
- package/types/acorex-platform-module-report-management-client-contracts-entities-report.d.ts +5 -0
- package/types/acorex-platform-module-report-management-client-contracts-entity-catalog.d.ts +10 -0
- package/types/acorex-platform-module-report-management-client-contracts.d.ts +99 -58
- package/types/acorex-platform-module-report-management-client-local-entities.d.ts +12 -0
- package/types/acorex-platform-module-report-management-client.d.ts +46 -4
- package/fesm2022/acorex-platform-module-report-management-client-acorex-platform-module-report-management-client-BDCuhd5O.mjs.map +0 -1
|
@@ -1,21 +1,24 @@
|
|
|
1
|
-
import { AXPExpressionEvaluatorService, AXP_MODULE_MANIFEST_PROVIDER, AXP_FEATURE_DEFINITION_PROVIDER, provideLazyProvider, applySystemActionDefault, AXPDeviceService } from '@acorex-platform/framework-client/core';
|
|
2
|
-
import { RootConfig, AXPInsightsReportingPermissionKeys, AXPReportManagementMenuKeys, AXPReportManagementFeatureKeys, AXMReportManagementQueryKeys, AXMReportManagementCommandKeys } from '@acorex-platform/module-report-management-client/contracts';
|
|
1
|
+
import { AXPExpressionEvaluatorService, provideAppStartUpTask, AXP_APP_STARTUP_PRIORITY, AXP_MODULE_MANIFEST_PROVIDER, AXP_FEATURE_DEFINITION_PROVIDER, provideLazyProvider, applySystemActionDefault, AXPDeviceService } from '@acorex-platform/framework-client/core';
|
|
2
|
+
import { RootConfig, AXPInsightsReportingPermissionKeys, AXPReportManagementMenuKeys, AXPReportManagementFeatureKeys, AXPReportManagementSettings, AXP_REPORT_MANAGEMENT_GENERATION_SETTING_DEFAULTS, buildReportGenerationNotificationCorrelationId, AXMReportManagementQueryKeys, REPORT_GENERATION_NOTIFICATION_DEFINITION_KEY, AXMReportManagementCommandKeys } from '@acorex-platform/module-report-management-client/contracts';
|
|
3
3
|
import { AXPDomainModule } from '@acorex-platform/framework-client/domain';
|
|
4
4
|
import { AXPEntityService, resolveEntityPluginDetailPageOrder, AXP_ENTITY_ACTION_PLUGIN, provideEntity } from '@acorex-platform/framework-client/layout/entity';
|
|
5
5
|
import { AXP_PAGE_COMPONENT_PROVIDER, AXPStateMessageComponent, AXPTextCommandColumnComponent, AXPThemeLayoutStartSideComponent, AXPThemeLayoutHeaderComponent, AXPThemeLayoutBlockComponent, AXPThemeLayoutFooterComponent } from '@acorex-platform/framework-client/layout/components';
|
|
6
6
|
import { AXPRootLayoutComponent } from '@acorex-platform/framework-client/themes/default';
|
|
7
7
|
import * as i0 from '@angular/core';
|
|
8
|
-
import { Injectable, inject, Injector, NgModule, computed,
|
|
9
|
-
import { ROUTES, ActivatedRoute } from '@angular/router';
|
|
10
|
-
import { AXPTabNavigationService, AXPBackgroundOperationHandler, AXP_BACKGROUND_OPERATION_HANDLERS, AXP_PROTECTED_ROUTE_GUARDS, AXP_MENU_PROVIDER, AXPSettingsService, commandMessageTextForError, AXPCommonSettings } from '@acorex-platform/framework-client/common';
|
|
8
|
+
import { Injectable, inject, DestroyRef, Injector, effect, NgModule, computed, untracked, signal, ChangeDetectionStrategy, Component, ViewEncapsulation, viewChild, input } from '@angular/core';
|
|
9
|
+
import { ROUTES, ActivatedRoute, NavigationStart } from '@angular/router';
|
|
10
|
+
import { AXPTabNavigationService, AXPBackgroundOperationHandler, AXP_BACKGROUND_OPERATION_HANDLERS, AXP_USER_NOTIFICATION_SERVICE, AXP_PROTECTED_ROUTE_GUARDS, AXP_MENU_PROVIDER, AXP_SETTING_DEFINITION_PROVIDER, AXPSettingsService, commandMessageTextForError, AXPCommonSettings } from '@acorex-platform/framework-client/common';
|
|
11
11
|
import { AXPSessionService, AXP_PERMISSION_DEFINITION_PROVIDER } from '@acorex-platform/framework-client/auth';
|
|
12
|
-
import { AXPQueryService, AXPRuntimeModule, provideCommandSetups
|
|
12
|
+
import { AXPQueryService, AXPCommandService, AXPRuntimeModule, provideCommandSetups } from '@acorex-platform/framework-client/runtime';
|
|
13
13
|
import { AXPCommonPermissionGroupKeys } from '@acorex-platform/module-common-client/contracts';
|
|
14
|
+
import { AXPWidgetsList, runtimeQueryPayloadData, resolveMultiLanguageString, runtimeQueryObjectData, runtimeQueryCollectionData, AXPPlatformScope, runtimeCommandPayloadData, getSystemActions } from '@acorex-platform/framework-shared/core';
|
|
14
15
|
import { get, isString } from 'lodash-es';
|
|
15
|
-
import { AXPopupService } from '@acorex/components/popup';
|
|
16
|
-
import { resolveMultiLanguageString, runtimeQueryPayloadData, runtimeQueryObjectData, runtimeQueryCollectionData, AXPPlatformScope, AXPWidgetsList, getSystemActions } from '@acorex-platform/framework-shared/core';
|
|
17
16
|
import * as i1 from '@acorex/core/translation';
|
|
18
17
|
import { AXTranslationService, AXTranslationModule } from '@acorex/core/translation';
|
|
18
|
+
import { AXPInAppInboxConnectorService } from '@acorex-platform/module-communication-management-client';
|
|
19
|
+
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
20
|
+
import { map, distinctUntilChanged, Subscription, combineLatest } from 'rxjs';
|
|
21
|
+
import { AXPopupService } from '@acorex/components/popup';
|
|
19
22
|
import { AXBadgeModule } from '@acorex/components/badge';
|
|
20
23
|
import * as i1$2 from '@acorex/components/button';
|
|
21
24
|
import { AXButtonModule } from '@acorex/components/button';
|
|
@@ -33,12 +36,11 @@ import * as i2 from '@angular/common';
|
|
|
33
36
|
import { CommonModule } from '@angular/common';
|
|
34
37
|
import * as i2$2 from '@angular/forms';
|
|
35
38
|
import { FormsModule } from '@angular/forms';
|
|
36
|
-
import {
|
|
39
|
+
import { filter } from 'rxjs/operators';
|
|
37
40
|
import { AXPPageStatus } from '@acorex-platform/framework-shared/widget-core';
|
|
38
41
|
import { AXLocaleService } from '@acorex/core/locale';
|
|
39
42
|
import * as i2$1 from '@acorex-platform/framework-client/layout/widget-core';
|
|
40
43
|
import { AXPWidgetRegistryService, AXPWidgetCoreModule } from '@acorex-platform/framework-client/layout/widget-core';
|
|
41
|
-
import { AXToastService } from '@acorex/components/toast';
|
|
42
44
|
import { signalStore, withState, withComputed, withMethods, patchState, withHooks } from '@ngrx/signals';
|
|
43
45
|
import { set } from 'lodash';
|
|
44
46
|
import { AXBarChartComponent } from '@acorex/charts/bar-chart';
|
|
@@ -163,6 +165,79 @@ class AXPReportManagementFeatureDefinitionProvider {
|
|
|
163
165
|
}
|
|
164
166
|
//#endregion
|
|
165
167
|
|
|
168
|
+
//#region ----- Report management settings -----
|
|
169
|
+
const DEDUPE_POLICY_ITEMS = [
|
|
170
|
+
{
|
|
171
|
+
value: 'none',
|
|
172
|
+
text: '@report-management:settings.generation.items.dedupe-policy.options.none',
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
value: 'in-flight',
|
|
176
|
+
text: '@report-management:settings.generation.items.dedupe-policy.options.in-flight',
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
value: 'in-flight-or-cooldown',
|
|
180
|
+
text: '@report-management:settings.generation.items.dedupe-policy.options.in-flight-or-cooldown',
|
|
181
|
+
},
|
|
182
|
+
];
|
|
183
|
+
class AXMReportManagementSettingProvider {
|
|
184
|
+
async provide(context) {
|
|
185
|
+
const cooldownPolicy = `{{ context.eval('${AXPReportManagementSettings.GenerationDedupePolicy}') === 'in-flight-or-cooldown' }}`;
|
|
186
|
+
context
|
|
187
|
+
.addGroup('report-management', '@report-management:settings.group.title', '@report-management:settings.group.description', 'fa-light fa-chart-line', undefined, 840)
|
|
188
|
+
.addSection('generation', '@report-management:settings.generation.title', '@report-management:settings.generation.description')
|
|
189
|
+
.addSetting({
|
|
190
|
+
key: AXPReportManagementSettings.GenerationDedupePolicy,
|
|
191
|
+
title: '@report-management:settings.generation.items.dedupe-policy.title',
|
|
192
|
+
description: '@report-management:settings.generation.items.dedupe-policy.description',
|
|
193
|
+
scope: 'P',
|
|
194
|
+
overridableAt: [],
|
|
195
|
+
isInherited: false,
|
|
196
|
+
defaultValue: AXP_REPORT_MANAGEMENT_GENERATION_SETTING_DEFAULTS[AXPReportManagementSettings.GenerationDedupePolicy],
|
|
197
|
+
widget: {
|
|
198
|
+
type: AXPWidgetsList.Editors.SelectBox,
|
|
199
|
+
options: {
|
|
200
|
+
valueField: 'value',
|
|
201
|
+
textField: 'text',
|
|
202
|
+
dataSource: DEDUPE_POLICY_ITEMS,
|
|
203
|
+
},
|
|
204
|
+
},
|
|
205
|
+
validationRules: [{ rule: 'required' }],
|
|
206
|
+
})
|
|
207
|
+
.addSetting({
|
|
208
|
+
key: AXPReportManagementSettings.GenerationDedupeCooldownMinutes,
|
|
209
|
+
title: '@report-management:settings.generation.items.dedupe-cooldown-minutes.title',
|
|
210
|
+
description: '@report-management:settings.generation.items.dedupe-cooldown-minutes.description',
|
|
211
|
+
scope: 'P',
|
|
212
|
+
overridableAt: [],
|
|
213
|
+
isInherited: false,
|
|
214
|
+
defaultValue: AXP_REPORT_MANAGEMENT_GENERATION_SETTING_DEFAULTS[AXPReportManagementSettings.GenerationDedupeCooldownMinutes],
|
|
215
|
+
widget: {
|
|
216
|
+
type: AXPWidgetsList.Editors.NumberBox,
|
|
217
|
+
options: { minValue: 0, maxValue: 1440, visibility: cooldownPolicy },
|
|
218
|
+
},
|
|
219
|
+
validationRules: [{ rule: 'required' }],
|
|
220
|
+
})
|
|
221
|
+
.addSetting({
|
|
222
|
+
key: AXPReportManagementSettings.GenerationMaxConcurrentPerUser,
|
|
223
|
+
title: '@report-management:settings.generation.items.max-concurrent-per-user.title',
|
|
224
|
+
description: '@report-management:settings.generation.items.max-concurrent-per-user.description',
|
|
225
|
+
scope: 'P',
|
|
226
|
+
overridableAt: [],
|
|
227
|
+
isInherited: false,
|
|
228
|
+
defaultValue: AXP_REPORT_MANAGEMENT_GENERATION_SETTING_DEFAULTS[AXPReportManagementSettings.GenerationMaxConcurrentPerUser],
|
|
229
|
+
widget: {
|
|
230
|
+
type: AXPWidgetsList.Editors.NumberBox,
|
|
231
|
+
options: { minValue: 0, maxValue: 50 },
|
|
232
|
+
},
|
|
233
|
+
validationRules: [{ rule: 'required' }],
|
|
234
|
+
})
|
|
235
|
+
.endSection()
|
|
236
|
+
.endGroup();
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
//#endregion
|
|
240
|
+
|
|
166
241
|
//#region ----- Types -----
|
|
167
242
|
//#endregion
|
|
168
243
|
//#region ----- Date helpers -----
|
|
@@ -416,6 +491,558 @@ function createEntityReportsPlugin(_injector) {
|
|
|
416
491
|
}
|
|
417
492
|
//#endregion
|
|
418
493
|
|
|
494
|
+
//#region ----- Imports -----
|
|
495
|
+
//#endregion
|
|
496
|
+
//#region ----- Command -----
|
|
497
|
+
/** Opens a report in the full-page report viewer. */
|
|
498
|
+
class AXPOpenReportViewerCommand {
|
|
499
|
+
constructor() {
|
|
500
|
+
//#region ----- Services & Dependencies -----
|
|
501
|
+
this.sessionService = inject(AXPSessionService);
|
|
502
|
+
this.tabNavigation = inject(AXPTabNavigationService);
|
|
503
|
+
this.expressionEvaluator = inject(AXPExpressionEvaluatorService);
|
|
504
|
+
this.translate = inject(AXTranslationService);
|
|
505
|
+
this.inboxConnector = inject(AXPInAppInboxConnectorService, { optional: true });
|
|
506
|
+
}
|
|
507
|
+
//#endregion
|
|
508
|
+
//#region ----- Command Implementation -----
|
|
509
|
+
async execute(input) {
|
|
510
|
+
const rowData = this.resolveRowData(input);
|
|
511
|
+
const options = await this.resolveOptions(input, rowData);
|
|
512
|
+
if (!options.reportId) {
|
|
513
|
+
return {
|
|
514
|
+
success: false,
|
|
515
|
+
message: {
|
|
516
|
+
text: await this.translate.translateAsync('@report-management:report-viewer.messages.error.invalid-popup-target'),
|
|
517
|
+
},
|
|
518
|
+
};
|
|
519
|
+
}
|
|
520
|
+
const runId = typeof options.runId === 'string' ? options.runId.trim() : '';
|
|
521
|
+
if (runId) {
|
|
522
|
+
await this.dismissReportGenerationInboxNotification(runId);
|
|
523
|
+
}
|
|
524
|
+
const appName = this.sessionService.application?.name;
|
|
525
|
+
if (!appName) {
|
|
526
|
+
return {
|
|
527
|
+
success: false,
|
|
528
|
+
message: {
|
|
529
|
+
text: await this.translate.translateAsync('@report-management:report-viewer.messages.error.invalid-popup-target'),
|
|
530
|
+
},
|
|
531
|
+
};
|
|
532
|
+
}
|
|
533
|
+
// Put reportId in the path (not queryParams): tabular navigation drops NavigationExtras.
|
|
534
|
+
const path = runId
|
|
535
|
+
? `${appName}/${RootConfig.module.route}/viewer/${options.reportId}?runId=${encodeURIComponent(runId)}`
|
|
536
|
+
: `${appName}/${RootConfig.module.route}/viewer/${options.reportId}`;
|
|
537
|
+
await this.tabNavigation.navigate(path);
|
|
538
|
+
return { success: true, kind: 'object', data: undefined };
|
|
539
|
+
}
|
|
540
|
+
//#endregion
|
|
541
|
+
//#region ----- Helpers -----
|
|
542
|
+
async dismissReportGenerationInboxNotification(runId) {
|
|
543
|
+
if (!this.inboxConnector) {
|
|
544
|
+
return;
|
|
545
|
+
}
|
|
546
|
+
try {
|
|
547
|
+
await this.inboxConnector.dismissByCorrelationId(buildReportGenerationNotificationCorrelationId(runId));
|
|
548
|
+
}
|
|
549
|
+
catch {
|
|
550
|
+
// Best-effort — navigation should still proceed.
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
resolveRowData(input) {
|
|
554
|
+
const ctx = input;
|
|
555
|
+
if (ctx?.data && typeof ctx.data === 'object') {
|
|
556
|
+
return ctx.data;
|
|
557
|
+
}
|
|
558
|
+
if (input['data'] &&
|
|
559
|
+
typeof input['data'] === 'object') {
|
|
560
|
+
return input['data'];
|
|
561
|
+
}
|
|
562
|
+
return input;
|
|
563
|
+
}
|
|
564
|
+
async resolveOptions(input, rowData) {
|
|
565
|
+
const typedInput = input;
|
|
566
|
+
const rawOptions = {
|
|
567
|
+
reportId: typedInput.reportId,
|
|
568
|
+
runId: typedInput.runId,
|
|
569
|
+
...(typedInput.options ?? {}),
|
|
570
|
+
};
|
|
571
|
+
const scope = {
|
|
572
|
+
context: {
|
|
573
|
+
eval: (path) => get(rowData, path),
|
|
574
|
+
},
|
|
575
|
+
};
|
|
576
|
+
return (await this.expressionEvaluator.evaluate(rawOptions, scope));
|
|
577
|
+
}
|
|
578
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPOpenReportViewerCommand, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
579
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPOpenReportViewerCommand, providedIn: 'root' }); }
|
|
580
|
+
}
|
|
581
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPOpenReportViewerCommand, decorators: [{
|
|
582
|
+
type: Injectable,
|
|
583
|
+
args: [{ providedIn: 'root' }]
|
|
584
|
+
}] });
|
|
585
|
+
|
|
586
|
+
var openReportViewer_command = /*#__PURE__*/Object.freeze({
|
|
587
|
+
__proto__: null,
|
|
588
|
+
AXPOpenReportViewerCommand: AXPOpenReportViewerCommand
|
|
589
|
+
});
|
|
590
|
+
|
|
591
|
+
//#region ----- Imports -----
|
|
592
|
+
//#endregion
|
|
593
|
+
//#region ----- Handler -----
|
|
594
|
+
class AXMReportGenerationBackgroundOperationHandler extends AXPBackgroundOperationHandler {
|
|
595
|
+
constructor() {
|
|
596
|
+
super(...arguments);
|
|
597
|
+
this.providerKey = 'report-management';
|
|
598
|
+
this.openViewer = inject(AXPOpenReportViewerCommand);
|
|
599
|
+
this.queryService = inject(AXPQueryService);
|
|
600
|
+
}
|
|
601
|
+
async execute(command, operation) {
|
|
602
|
+
if (command.name !== 'click') {
|
|
603
|
+
return;
|
|
604
|
+
}
|
|
605
|
+
const reportRequestId = get(operation.data, 'reportRequestId') ??
|
|
606
|
+
get(operation.data, 'payload.reportRequestId') ??
|
|
607
|
+
get(operation.data, 'command.payload.reportRequestId');
|
|
608
|
+
if (typeof reportRequestId !== 'string' || !reportRequestId.trim()) {
|
|
609
|
+
return;
|
|
610
|
+
}
|
|
611
|
+
const result = await this.queryService.fetch(AXMReportManagementQueryKeys.ReportGeneration.Get, { id: reportRequestId });
|
|
612
|
+
const request = runtimeQueryPayloadData(result);
|
|
613
|
+
if (!request?.reportId) {
|
|
614
|
+
return;
|
|
615
|
+
}
|
|
616
|
+
if (request.status === 'completed') {
|
|
617
|
+
await this.openViewer.execute({ reportId: request.reportId, runId: request.id });
|
|
618
|
+
return;
|
|
619
|
+
}
|
|
620
|
+
await this.openViewer.execute({ reportId: request.reportId });
|
|
621
|
+
}
|
|
622
|
+
resolveCta(operation) {
|
|
623
|
+
if (operation.status === 'failed' && operation.capabilities.retryable) {
|
|
624
|
+
return {
|
|
625
|
+
text: '@general:background-operation.actions.retry',
|
|
626
|
+
icon: 'fa-light fa-arrow-rotate-right',
|
|
627
|
+
color: 'primary',
|
|
628
|
+
look: 'solid',
|
|
629
|
+
command: { name: 'retry' },
|
|
630
|
+
};
|
|
631
|
+
}
|
|
632
|
+
if (operation.status === 'completed' && operation.capabilities.clickable) {
|
|
633
|
+
return {
|
|
634
|
+
text: '@report-management:report-generation.notifications.actions.open-viewer',
|
|
635
|
+
icon: 'fa-light fa-file-chart-column',
|
|
636
|
+
color: 'primary',
|
|
637
|
+
look: 'solid',
|
|
638
|
+
command: { name: 'click' },
|
|
639
|
+
};
|
|
640
|
+
}
|
|
641
|
+
return null;
|
|
642
|
+
}
|
|
643
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMReportGenerationBackgroundOperationHandler, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
644
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMReportGenerationBackgroundOperationHandler }); }
|
|
645
|
+
}
|
|
646
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMReportGenerationBackgroundOperationHandler, decorators: [{
|
|
647
|
+
type: Injectable
|
|
648
|
+
}] });
|
|
649
|
+
//#endregion
|
|
650
|
+
//#region ----- Providers -----
|
|
651
|
+
const AXM_REPORT_GENERATION_BACKGROUND_OPERATION_HANDLERS = [
|
|
652
|
+
{
|
|
653
|
+
provide: AXP_BACKGROUND_OPERATION_HANDLERS,
|
|
654
|
+
useExisting: AXMReportGenerationBackgroundOperationHandler,
|
|
655
|
+
multi: true,
|
|
656
|
+
},
|
|
657
|
+
AXMReportGenerationBackgroundOperationHandler,
|
|
658
|
+
];
|
|
659
|
+
|
|
660
|
+
//#region ----- Imports -----
|
|
661
|
+
//#endregion
|
|
662
|
+
//#region ----- Constants -----
|
|
663
|
+
const TOASTED_KEYS_STORAGE = 'axp:report-generation-inbox-toast-keys';
|
|
664
|
+
//#endregion
|
|
665
|
+
//#region ----- Bridge -----
|
|
666
|
+
/**
|
|
667
|
+
* When a report-generation inbox row arrives (user was not watching inline),
|
|
668
|
+
* mirrors it as a transient toast with an open action. Inbox persistence stays server-owned.
|
|
669
|
+
*/
|
|
670
|
+
class AXMReportGenerationInboxToastBridgeService {
|
|
671
|
+
constructor() {
|
|
672
|
+
//#region ----- Dependencies -----
|
|
673
|
+
this.inboxConnector = inject(AXPInAppInboxConnectorService, { optional: true });
|
|
674
|
+
this.userNotificationService = inject(AXP_USER_NOTIFICATION_SERVICE);
|
|
675
|
+
this.commandService = inject(AXPCommandService);
|
|
676
|
+
this.translationService = inject(AXTranslationService);
|
|
677
|
+
this.sessionService = inject(AXPSessionService);
|
|
678
|
+
this.destroyRef = inject(DestroyRef);
|
|
679
|
+
this.injector = inject(Injector);
|
|
680
|
+
//#endregion
|
|
681
|
+
//#region ----- State -----
|
|
682
|
+
this.started = false;
|
|
683
|
+
this.inboxBaselined = false;
|
|
684
|
+
this.boundUserId = null;
|
|
685
|
+
this.toastedKeys = new Set();
|
|
686
|
+
}
|
|
687
|
+
//#endregion
|
|
688
|
+
//#region ----- Lifecycle -----
|
|
689
|
+
start() {
|
|
690
|
+
if (this.started || !this.inboxConnector) {
|
|
691
|
+
return;
|
|
692
|
+
}
|
|
693
|
+
this.started = true;
|
|
694
|
+
this.sessionService.isReadyForAppScopedApi$
|
|
695
|
+
.pipe(map(() => this.sessionService.user?.id?.trim() || null), distinctUntilChanged(), takeUntilDestroyed(this.destroyRef))
|
|
696
|
+
.subscribe((userId) => {
|
|
697
|
+
this.bindSessionUser(userId);
|
|
698
|
+
});
|
|
699
|
+
this.bindSessionUser(this.sessionService.user?.id?.trim() || null);
|
|
700
|
+
effect(() => {
|
|
701
|
+
const userId = this.sessionService.user?.id?.trim();
|
|
702
|
+
const inboxLoading = this.inboxConnector?.loading() ?? false;
|
|
703
|
+
const items = this.readReportGenerationItems();
|
|
704
|
+
if (!this.sessionService.isReadyForAppScopedApi || !userId) {
|
|
705
|
+
return;
|
|
706
|
+
}
|
|
707
|
+
if (!this.inboxBaselined) {
|
|
708
|
+
for (const item of items) {
|
|
709
|
+
this.markToasted(this.toastKey(item));
|
|
710
|
+
}
|
|
711
|
+
if (!inboxLoading) {
|
|
712
|
+
this.inboxBaselined = true;
|
|
713
|
+
}
|
|
714
|
+
return;
|
|
715
|
+
}
|
|
716
|
+
for (const item of items) {
|
|
717
|
+
const key = this.toastKey(item);
|
|
718
|
+
if (this.toastedKeys.has(key)) {
|
|
719
|
+
continue;
|
|
720
|
+
}
|
|
721
|
+
this.markToasted(key);
|
|
722
|
+
void this.showToastForInboxItem(item);
|
|
723
|
+
}
|
|
724
|
+
}, { injector: this.injector });
|
|
725
|
+
}
|
|
726
|
+
//#endregion
|
|
727
|
+
//#region ----- Toast -----
|
|
728
|
+
async showToastForInboxItem(item) {
|
|
729
|
+
const action = item.actions?.[0];
|
|
730
|
+
const actionTitle = action?.title
|
|
731
|
+
? await this.translationService.translateAsync(action.title)
|
|
732
|
+
: await this.translationService.translateAsync('@report-management:report-generation.notifications.actions.open-viewer');
|
|
733
|
+
const toastActions = action?.command?.name
|
|
734
|
+
? [
|
|
735
|
+
{
|
|
736
|
+
text: actionTitle,
|
|
737
|
+
color: 'primary',
|
|
738
|
+
onClick: () => this.executeInboxAction(item, action),
|
|
739
|
+
},
|
|
740
|
+
]
|
|
741
|
+
: undefined;
|
|
742
|
+
await this.userNotificationService.notify({
|
|
743
|
+
correlationId: item.correlationId?.trim() || item.id,
|
|
744
|
+
title: await this.resolveText(item.title),
|
|
745
|
+
body: await this.resolveText(item.body),
|
|
746
|
+
icon: item.iconClass ?? this.resolveIcon(item),
|
|
747
|
+
delivery: {
|
|
748
|
+
toast: {
|
|
749
|
+
color: this.resolveToastColor(item),
|
|
750
|
+
location: 'bottom-center',
|
|
751
|
+
closeButton: true,
|
|
752
|
+
timeOut: 8_000,
|
|
753
|
+
timeOutProgress: true,
|
|
754
|
+
showActions: !!toastActions?.length,
|
|
755
|
+
},
|
|
756
|
+
},
|
|
757
|
+
toastActions,
|
|
758
|
+
});
|
|
759
|
+
}
|
|
760
|
+
async executeInboxAction(item, action) {
|
|
761
|
+
if (!action.command?.name) {
|
|
762
|
+
return;
|
|
763
|
+
}
|
|
764
|
+
await this.commandService.execute(action.command.name, action.command.options ?? {});
|
|
765
|
+
}
|
|
766
|
+
//#endregion
|
|
767
|
+
//#region ----- Helpers -----
|
|
768
|
+
readReportGenerationItems() {
|
|
769
|
+
const userId = this.sessionService.user?.id?.trim();
|
|
770
|
+
return (this.inboxConnector?.inboxList() ?? []).filter((item) => {
|
|
771
|
+
if (item.definitionKey !== REPORT_GENERATION_NOTIFICATION_DEFINITION_KEY) {
|
|
772
|
+
return false;
|
|
773
|
+
}
|
|
774
|
+
const recipientUserId = item.recipientUserId?.trim();
|
|
775
|
+
return !recipientUserId || recipientUserId === userId;
|
|
776
|
+
});
|
|
777
|
+
}
|
|
778
|
+
toastKey(item) {
|
|
779
|
+
return item.correlationId?.trim() || item.id;
|
|
780
|
+
}
|
|
781
|
+
bindSessionUser(userId) {
|
|
782
|
+
if (userId === this.boundUserId) {
|
|
783
|
+
return;
|
|
784
|
+
}
|
|
785
|
+
this.boundUserId = userId;
|
|
786
|
+
this.inboxBaselined = false;
|
|
787
|
+
this.toastedKeys.clear();
|
|
788
|
+
if (userId) {
|
|
789
|
+
this.loadPersistedToastedKeys(userId);
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
markToasted(key) {
|
|
793
|
+
const normalized = key.trim();
|
|
794
|
+
if (!normalized) {
|
|
795
|
+
return;
|
|
796
|
+
}
|
|
797
|
+
this.toastedKeys.add(normalized);
|
|
798
|
+
this.persistToastedKeys();
|
|
799
|
+
}
|
|
800
|
+
toastedStorageKey(userId) {
|
|
801
|
+
return `${TOASTED_KEYS_STORAGE}:${userId}`;
|
|
802
|
+
}
|
|
803
|
+
loadPersistedToastedKeys(userId) {
|
|
804
|
+
try {
|
|
805
|
+
const raw = sessionStorage.getItem(this.toastedStorageKey(userId));
|
|
806
|
+
if (!raw) {
|
|
807
|
+
return;
|
|
808
|
+
}
|
|
809
|
+
const parsed = JSON.parse(raw);
|
|
810
|
+
if (!Array.isArray(parsed)) {
|
|
811
|
+
return;
|
|
812
|
+
}
|
|
813
|
+
for (const entry of parsed) {
|
|
814
|
+
if (typeof entry === 'string' && entry.trim()) {
|
|
815
|
+
this.toastedKeys.add(entry.trim());
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
catch {
|
|
820
|
+
// Ignore corrupt session storage.
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
persistToastedKeys() {
|
|
824
|
+
const userId = this.boundUserId?.trim();
|
|
825
|
+
if (!userId) {
|
|
826
|
+
return;
|
|
827
|
+
}
|
|
828
|
+
try {
|
|
829
|
+
sessionStorage.setItem(this.toastedStorageKey(userId), JSON.stringify([...this.toastedKeys]));
|
|
830
|
+
}
|
|
831
|
+
catch {
|
|
832
|
+
// Ignore quota / privacy errors.
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
async resolveText(value) {
|
|
836
|
+
const text = value?.trim();
|
|
837
|
+
if (!text) {
|
|
838
|
+
return '';
|
|
839
|
+
}
|
|
840
|
+
if (text.startsWith('@')) {
|
|
841
|
+
return this.translationService.translateAsync(text);
|
|
842
|
+
}
|
|
843
|
+
return text;
|
|
844
|
+
}
|
|
845
|
+
resolveToastColor(item) {
|
|
846
|
+
switch (item.priority) {
|
|
847
|
+
case 'Danger':
|
|
848
|
+
return 'danger';
|
|
849
|
+
case 'Warning':
|
|
850
|
+
return 'warning';
|
|
851
|
+
default:
|
|
852
|
+
return 'success';
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
resolveIcon(item) {
|
|
856
|
+
if (item.priority === 'Danger') {
|
|
857
|
+
return 'fa-light fa-circle-exclamation';
|
|
858
|
+
}
|
|
859
|
+
if (item.priority === 'Warning') {
|
|
860
|
+
return 'fa-light fa-triangle-exclamation';
|
|
861
|
+
}
|
|
862
|
+
return 'fa-light fa-circle-check';
|
|
863
|
+
}
|
|
864
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMReportGenerationInboxToastBridgeService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
865
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMReportGenerationInboxToastBridgeService, providedIn: 'root' }); }
|
|
866
|
+
}
|
|
867
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMReportGenerationInboxToastBridgeService, decorators: [{
|
|
868
|
+
type: Injectable,
|
|
869
|
+
args: [{ providedIn: 'root' }]
|
|
870
|
+
}] });
|
|
871
|
+
|
|
872
|
+
//#region ----- Imports -----
|
|
873
|
+
//#endregion
|
|
874
|
+
//#region ----- Providers -----
|
|
875
|
+
function provideReportGenerationInboxToastBridge() {
|
|
876
|
+
return [
|
|
877
|
+
provideAppStartUpTask(() => {
|
|
878
|
+
const bridge = inject(AXMReportGenerationInboxToastBridgeService);
|
|
879
|
+
const inbox = inject(AXPInAppInboxConnectorService, { optional: true });
|
|
880
|
+
return {
|
|
881
|
+
name: 'report-generation-inbox-toast-bridge',
|
|
882
|
+
priority: AXP_APP_STARTUP_PRIORITY.realtimeHandlers,
|
|
883
|
+
run: async () => {
|
|
884
|
+
if (inbox) {
|
|
885
|
+
await inbox.ensureReady();
|
|
886
|
+
await inbox.refresh();
|
|
887
|
+
}
|
|
888
|
+
bridge.start();
|
|
889
|
+
},
|
|
890
|
+
};
|
|
891
|
+
}),
|
|
892
|
+
];
|
|
893
|
+
}
|
|
894
|
+
//#endregion
|
|
895
|
+
|
|
896
|
+
function routesFacory() {
|
|
897
|
+
let routes = [
|
|
898
|
+
{
|
|
899
|
+
path: `:app/${RootConfig.module.route}/viewer`,
|
|
900
|
+
canActivate: [...AXP_PROTECTED_ROUTE_GUARDS],
|
|
901
|
+
data: { tab: true, rootLayout: true },
|
|
902
|
+
loadComponent: () => {
|
|
903
|
+
return AXPRootLayoutComponent;
|
|
904
|
+
},
|
|
905
|
+
children: [
|
|
906
|
+
{
|
|
907
|
+
path: ':reportId',
|
|
908
|
+
loadComponent: () => Promise.resolve().then(function () { return reportViewerPage_component; }).then((c) => c.AXPReportViewerPageComponent),
|
|
909
|
+
data: { reuse: true },
|
|
910
|
+
},
|
|
911
|
+
{
|
|
912
|
+
path: '',
|
|
913
|
+
loadComponent: () => Promise.resolve().then(function () { return reportViewerPage_component; }).then((c) => c.AXPReportViewerPageComponent),
|
|
914
|
+
data: { reuse: true },
|
|
915
|
+
},
|
|
916
|
+
],
|
|
917
|
+
},
|
|
918
|
+
];
|
|
919
|
+
return routes;
|
|
920
|
+
}
|
|
921
|
+
class AXMReportManagementModule {
|
|
922
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMReportManagementModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
923
|
+
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "22.0.8", ngImport: i0, type: AXMReportManagementModule, imports: [AXPDomainModule,
|
|
924
|
+
AXPRuntimeModule] }); }
|
|
925
|
+
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMReportManagementModule, providers: [
|
|
926
|
+
{
|
|
927
|
+
provide: ROUTES,
|
|
928
|
+
multi: true,
|
|
929
|
+
useFactory: routesFacory,
|
|
930
|
+
},
|
|
931
|
+
provideEntity([RootConfig.entities.report.fullName, RootConfig.entities.category.fullName]),
|
|
932
|
+
// Module Manifest Provider
|
|
933
|
+
{
|
|
934
|
+
provide: AXP_MODULE_MANIFEST_PROVIDER,
|
|
935
|
+
useValue: ReportManagementManifest,
|
|
936
|
+
multi: true,
|
|
937
|
+
},
|
|
938
|
+
// Provider references (now using tokens)
|
|
939
|
+
{
|
|
940
|
+
provide: AXP_PERMISSION_DEFINITION_PROVIDER,
|
|
941
|
+
useClass: AXMPermissionDefinitionProvider,
|
|
942
|
+
multi: true,
|
|
943
|
+
},
|
|
944
|
+
{
|
|
945
|
+
provide: AXP_MENU_PROVIDER,
|
|
946
|
+
useClass: AXMMenuProvider,
|
|
947
|
+
multi: true,
|
|
948
|
+
},
|
|
949
|
+
{
|
|
950
|
+
provide: AXP_FEATURE_DEFINITION_PROVIDER,
|
|
951
|
+
useClass: AXPReportManagementFeatureDefinitionProvider,
|
|
952
|
+
multi: true,
|
|
953
|
+
},
|
|
954
|
+
{
|
|
955
|
+
provide: AXP_SETTING_DEFINITION_PROVIDER,
|
|
956
|
+
useClass: AXMReportManagementSettingProvider,
|
|
957
|
+
multi: true,
|
|
958
|
+
},
|
|
959
|
+
...AXM_REPORT_GENERATION_BACKGROUND_OPERATION_HANDLERS,
|
|
960
|
+
...provideReportGenerationInboxToastBridge(),
|
|
961
|
+
provideCommandSetups([
|
|
962
|
+
{
|
|
963
|
+
key: 'ReportManagement.Report:OpenInPopup',
|
|
964
|
+
command: () => Promise.resolve().then(function () { return openReportInPopup_command; }).then((c) => c.AXPOpenReportInPopupCommand),
|
|
965
|
+
},
|
|
966
|
+
{
|
|
967
|
+
key: 'ReportManagement.Report:OpenViewer',
|
|
968
|
+
command: () => Promise.resolve().then(function () { return openReportViewer_command; }).then((c) => c.AXPOpenReportViewerCommand),
|
|
969
|
+
},
|
|
970
|
+
]),
|
|
971
|
+
{
|
|
972
|
+
provide: AXP_ENTITY_ACTION_PLUGIN,
|
|
973
|
+
multi: true,
|
|
974
|
+
useFactory: () => createEntityReportsPlugin(inject(Injector)),
|
|
975
|
+
},
|
|
976
|
+
provideLazyProvider(AXP_PAGE_COMPONENT_PROVIDER, () => import('./acorex-platform-module-report-management-client-entity-reports-page-component.provider-B_i4p7tQ.mjs').then((m) => m.AXMEntityReportsPageComponentProvider)),
|
|
977
|
+
], imports: [AXPDomainModule,
|
|
978
|
+
AXPRuntimeModule] }); }
|
|
979
|
+
}
|
|
980
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMReportManagementModule, decorators: [{
|
|
981
|
+
type: NgModule,
|
|
982
|
+
args: [{
|
|
983
|
+
imports: [
|
|
984
|
+
AXPDomainModule,
|
|
985
|
+
AXPRuntimeModule,
|
|
986
|
+
// Entity Modules
|
|
987
|
+
],
|
|
988
|
+
exports: [],
|
|
989
|
+
declarations: [],
|
|
990
|
+
providers: [
|
|
991
|
+
{
|
|
992
|
+
provide: ROUTES,
|
|
993
|
+
multi: true,
|
|
994
|
+
useFactory: routesFacory,
|
|
995
|
+
},
|
|
996
|
+
provideEntity([RootConfig.entities.report.fullName, RootConfig.entities.category.fullName]),
|
|
997
|
+
// Module Manifest Provider
|
|
998
|
+
{
|
|
999
|
+
provide: AXP_MODULE_MANIFEST_PROVIDER,
|
|
1000
|
+
useValue: ReportManagementManifest,
|
|
1001
|
+
multi: true,
|
|
1002
|
+
},
|
|
1003
|
+
// Provider references (now using tokens)
|
|
1004
|
+
{
|
|
1005
|
+
provide: AXP_PERMISSION_DEFINITION_PROVIDER,
|
|
1006
|
+
useClass: AXMPermissionDefinitionProvider,
|
|
1007
|
+
multi: true,
|
|
1008
|
+
},
|
|
1009
|
+
{
|
|
1010
|
+
provide: AXP_MENU_PROVIDER,
|
|
1011
|
+
useClass: AXMMenuProvider,
|
|
1012
|
+
multi: true,
|
|
1013
|
+
},
|
|
1014
|
+
{
|
|
1015
|
+
provide: AXP_FEATURE_DEFINITION_PROVIDER,
|
|
1016
|
+
useClass: AXPReportManagementFeatureDefinitionProvider,
|
|
1017
|
+
multi: true,
|
|
1018
|
+
},
|
|
1019
|
+
{
|
|
1020
|
+
provide: AXP_SETTING_DEFINITION_PROVIDER,
|
|
1021
|
+
useClass: AXMReportManagementSettingProvider,
|
|
1022
|
+
multi: true,
|
|
1023
|
+
},
|
|
1024
|
+
...AXM_REPORT_GENERATION_BACKGROUND_OPERATION_HANDLERS,
|
|
1025
|
+
...provideReportGenerationInboxToastBridge(),
|
|
1026
|
+
provideCommandSetups([
|
|
1027
|
+
{
|
|
1028
|
+
key: 'ReportManagement.Report:OpenInPopup',
|
|
1029
|
+
command: () => Promise.resolve().then(function () { return openReportInPopup_command; }).then((c) => c.AXPOpenReportInPopupCommand),
|
|
1030
|
+
},
|
|
1031
|
+
{
|
|
1032
|
+
key: 'ReportManagement.Report:OpenViewer',
|
|
1033
|
+
command: () => Promise.resolve().then(function () { return openReportViewer_command; }).then((c) => c.AXPOpenReportViewerCommand),
|
|
1034
|
+
},
|
|
1035
|
+
]),
|
|
1036
|
+
{
|
|
1037
|
+
provide: AXP_ENTITY_ACTION_PLUGIN,
|
|
1038
|
+
multi: true,
|
|
1039
|
+
useFactory: () => createEntityReportsPlugin(inject(Injector)),
|
|
1040
|
+
},
|
|
1041
|
+
provideLazyProvider(AXP_PAGE_COMPONENT_PROVIDER, () => import('./acorex-platform-module-report-management-client-entity-reports-page-component.provider-B_i4p7tQ.mjs').then((m) => m.AXMEntityReportsPageComponentProvider)),
|
|
1042
|
+
],
|
|
1043
|
+
}]
|
|
1044
|
+
}] });
|
|
1045
|
+
|
|
419
1046
|
//#endregion
|
|
420
1047
|
|
|
421
1048
|
//#region ---- Imports ----
|
|
@@ -843,6 +1470,7 @@ class AXPOpenReportInPopupCommand {
|
|
|
843
1470
|
this.expressionEvaluator = inject(AXPExpressionEvaluatorService);
|
|
844
1471
|
this.translate = inject(AXTranslationService);
|
|
845
1472
|
this.reportViewerService = inject(AXPReportViewerService);
|
|
1473
|
+
this.inboxConnector = inject(AXPInAppInboxConnectorService, { optional: true });
|
|
846
1474
|
}
|
|
847
1475
|
//#endregion
|
|
848
1476
|
//#region ----- Command Implementation -----
|
|
@@ -858,9 +1486,12 @@ class AXPOpenReportInPopupCommand {
|
|
|
858
1486
|
};
|
|
859
1487
|
}
|
|
860
1488
|
const runId = typeof options.runId === 'string' ? options.runId.trim() : '';
|
|
1489
|
+
if (runId) {
|
|
1490
|
+
await this.dismissReportGenerationInboxNotification(runId);
|
|
1491
|
+
}
|
|
861
1492
|
const popupTitle = await this.resolvePopupTitle(options, rowData, runId);
|
|
862
1493
|
const parameters = resolveReportParameterValues(options.parameters);
|
|
863
|
-
const comp = (await import('./acorex-platform-module-report-management-client-report-popup-viewer.component-
|
|
1494
|
+
const comp = (await import('./acorex-platform-module-report-management-client-report-popup-viewer.component-B6aTfRp0.mjs')).AXPReportPopupViewerComponent;
|
|
864
1495
|
this.popupService.open(comp, {
|
|
865
1496
|
title: popupTitle,
|
|
866
1497
|
size: 'lg',
|
|
@@ -941,295 +1572,37 @@ class AXPOpenReportInPopupCommand {
|
|
|
941
1572
|
return '';
|
|
942
1573
|
}
|
|
943
1574
|
const scope = {
|
|
944
|
-
context: {
|
|
945
|
-
eval: (path) => get(rowData, path),
|
|
946
|
-
},
|
|
947
|
-
};
|
|
948
|
-
const evaluated = await this.expressionEvaluator.evaluate(title, scope);
|
|
949
|
-
return isString(evaluated) ? evaluated : title;
|
|
950
|
-
}
|
|
951
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPOpenReportInPopupCommand, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
952
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPOpenReportInPopupCommand, providedIn: 'root' }); }
|
|
953
|
-
}
|
|
954
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPOpenReportInPopupCommand, decorators: [{
|
|
955
|
-
type: Injectable,
|
|
956
|
-
args: [{ providedIn: 'root' }]
|
|
957
|
-
}] });
|
|
958
|
-
|
|
959
|
-
var openReportInPopup_command = /*#__PURE__*/Object.freeze({
|
|
960
|
-
__proto__: null,
|
|
961
|
-
AXPOpenReportInPopupCommand: AXPOpenReportInPopupCommand
|
|
962
|
-
});
|
|
963
|
-
|
|
964
|
-
//#region ----- Imports -----
|
|
965
|
-
//#endregion
|
|
966
|
-
//#region ----- Command -----
|
|
967
|
-
/** Opens a report in the full-page report viewer. */
|
|
968
|
-
class AXPOpenReportViewerCommand {
|
|
969
|
-
constructor() {
|
|
970
|
-
//#region ----- Services & Dependencies -----
|
|
971
|
-
this.sessionService = inject(AXPSessionService);
|
|
972
|
-
this.tabNavigation = inject(AXPTabNavigationService);
|
|
973
|
-
this.expressionEvaluator = inject(AXPExpressionEvaluatorService);
|
|
974
|
-
this.translate = inject(AXTranslationService);
|
|
975
|
-
}
|
|
976
|
-
//#endregion
|
|
977
|
-
//#region ----- Command Implementation -----
|
|
978
|
-
async execute(input) {
|
|
979
|
-
const rowData = this.resolveRowData(input);
|
|
980
|
-
const options = await this.resolveOptions(input, rowData);
|
|
981
|
-
if (!options.reportId) {
|
|
982
|
-
return {
|
|
983
|
-
success: false,
|
|
984
|
-
message: {
|
|
985
|
-
text: await this.translate.translateAsync('@report-management:report-viewer.messages.error.invalid-popup-target'),
|
|
986
|
-
},
|
|
987
|
-
};
|
|
988
|
-
}
|
|
989
|
-
const appName = this.sessionService.application?.name;
|
|
990
|
-
if (!appName) {
|
|
991
|
-
return {
|
|
992
|
-
success: false,
|
|
993
|
-
message: {
|
|
994
|
-
text: await this.translate.translateAsync('@report-management:report-viewer.messages.error.invalid-popup-target'),
|
|
995
|
-
},
|
|
996
|
-
};
|
|
997
|
-
}
|
|
998
|
-
// Put reportId in the path (not queryParams): tabular navigation drops NavigationExtras.
|
|
999
|
-
const runId = typeof options.runId === 'string' ? options.runId.trim() : '';
|
|
1000
|
-
const path = runId
|
|
1001
|
-
? `${appName}/${RootConfig.module.route}/viewer/${options.reportId}?runId=${encodeURIComponent(runId)}`
|
|
1002
|
-
: `${appName}/${RootConfig.module.route}/viewer/${options.reportId}`;
|
|
1003
|
-
await this.tabNavigation.navigate(path);
|
|
1004
|
-
return { success: true, kind: 'object', data: undefined };
|
|
1005
|
-
}
|
|
1006
|
-
//#endregion
|
|
1007
|
-
//#region ----- Helpers -----
|
|
1008
|
-
resolveRowData(input) {
|
|
1009
|
-
const ctx = input;
|
|
1010
|
-
if (ctx?.data && typeof ctx.data === 'object') {
|
|
1011
|
-
return ctx.data;
|
|
1012
|
-
}
|
|
1013
|
-
if (input['data'] &&
|
|
1014
|
-
typeof input['data'] === 'object') {
|
|
1015
|
-
return input['data'];
|
|
1016
|
-
}
|
|
1017
|
-
return input;
|
|
1018
|
-
}
|
|
1019
|
-
async resolveOptions(input, rowData) {
|
|
1020
|
-
const typedInput = input;
|
|
1021
|
-
const rawOptions = {
|
|
1022
|
-
reportId: typedInput.reportId,
|
|
1023
|
-
runId: typedInput.runId,
|
|
1024
|
-
...(typedInput.options ?? {}),
|
|
1025
|
-
};
|
|
1026
|
-
const scope = {
|
|
1027
|
-
context: {
|
|
1028
|
-
eval: (path) => get(rowData, path),
|
|
1029
|
-
},
|
|
1030
|
-
};
|
|
1031
|
-
return (await this.expressionEvaluator.evaluate(rawOptions, scope));
|
|
1032
|
-
}
|
|
1033
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPOpenReportViewerCommand, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1034
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPOpenReportViewerCommand, providedIn: 'root' }); }
|
|
1035
|
-
}
|
|
1036
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPOpenReportViewerCommand, decorators: [{
|
|
1037
|
-
type: Injectable,
|
|
1038
|
-
args: [{ providedIn: 'root' }]
|
|
1039
|
-
}] });
|
|
1040
|
-
|
|
1041
|
-
var openReportViewer_command = /*#__PURE__*/Object.freeze({
|
|
1042
|
-
__proto__: null,
|
|
1043
|
-
AXPOpenReportViewerCommand: AXPOpenReportViewerCommand
|
|
1044
|
-
});
|
|
1045
|
-
|
|
1046
|
-
//#region ----- Imports -----
|
|
1047
|
-
//#endregion
|
|
1048
|
-
//#region ----- Handler -----
|
|
1049
|
-
class AXMReportGenerationBackgroundOperationHandler extends AXPBackgroundOperationHandler {
|
|
1050
|
-
constructor() {
|
|
1051
|
-
super(...arguments);
|
|
1052
|
-
this.providerKey = 'report-management';
|
|
1053
|
-
this.openPopup = inject(AXPOpenReportInPopupCommand);
|
|
1054
|
-
this.openViewer = inject(AXPOpenReportViewerCommand);
|
|
1055
|
-
this.queryService = inject(AXPQueryService);
|
|
1056
|
-
}
|
|
1057
|
-
async execute(command, operation) {
|
|
1058
|
-
if (command.name !== 'click') {
|
|
1059
|
-
return;
|
|
1060
|
-
}
|
|
1061
|
-
const reportRequestId = get(operation.data, 'reportRequestId') ??
|
|
1062
|
-
get(operation.data, 'payload.reportRequestId') ??
|
|
1063
|
-
get(operation.data, 'command.payload.reportRequestId');
|
|
1064
|
-
if (typeof reportRequestId !== 'string' || !reportRequestId.trim()) {
|
|
1065
|
-
return;
|
|
1066
|
-
}
|
|
1067
|
-
const result = await this.queryService.fetch(AXMReportManagementQueryKeys.ReportGeneration.Get, { id: reportRequestId });
|
|
1068
|
-
const request = runtimeQueryPayloadData(result);
|
|
1069
|
-
if (!request?.reportId) {
|
|
1070
|
-
return;
|
|
1071
|
-
}
|
|
1072
|
-
if (request.status === 'completed') {
|
|
1073
|
-
await this.openPopup.execute({ reportId: request.reportId, runId: request.id });
|
|
1074
|
-
return;
|
|
1075
|
-
}
|
|
1076
|
-
await this.openViewer.execute({ reportId: request.reportId });
|
|
1077
|
-
}
|
|
1078
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMReportGenerationBackgroundOperationHandler, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1079
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMReportGenerationBackgroundOperationHandler }); }
|
|
1080
|
-
}
|
|
1081
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMReportGenerationBackgroundOperationHandler, decorators: [{
|
|
1082
|
-
type: Injectable
|
|
1083
|
-
}] });
|
|
1084
|
-
//#endregion
|
|
1085
|
-
//#region ----- Providers -----
|
|
1086
|
-
const AXM_REPORT_GENERATION_BACKGROUND_OPERATION_HANDLERS = [
|
|
1087
|
-
{
|
|
1088
|
-
provide: AXP_BACKGROUND_OPERATION_HANDLERS,
|
|
1089
|
-
useExisting: AXMReportGenerationBackgroundOperationHandler,
|
|
1090
|
-
multi: true,
|
|
1091
|
-
},
|
|
1092
|
-
AXMReportGenerationBackgroundOperationHandler,
|
|
1093
|
-
];
|
|
1094
|
-
|
|
1095
|
-
function routesFacory() {
|
|
1096
|
-
let routes = [
|
|
1097
|
-
{
|
|
1098
|
-
path: `:app/${RootConfig.module.route}/viewer`,
|
|
1099
|
-
canActivate: [...AXP_PROTECTED_ROUTE_GUARDS],
|
|
1100
|
-
data: { tab: true, rootLayout: true },
|
|
1101
|
-
loadComponent: () => {
|
|
1102
|
-
return AXPRootLayoutComponent;
|
|
1103
|
-
},
|
|
1104
|
-
children: [
|
|
1105
|
-
{
|
|
1106
|
-
path: ':reportId',
|
|
1107
|
-
loadComponent: () => Promise.resolve().then(function () { return reportViewerPage_component; }).then((c) => c.AXPReportViewerPageComponent),
|
|
1108
|
-
data: { reuse: true },
|
|
1109
|
-
},
|
|
1110
|
-
{
|
|
1111
|
-
path: '',
|
|
1112
|
-
loadComponent: () => Promise.resolve().then(function () { return reportViewerPage_component; }).then((c) => c.AXPReportViewerPageComponent),
|
|
1113
|
-
data: { reuse: true },
|
|
1114
|
-
},
|
|
1115
|
-
],
|
|
1116
|
-
},
|
|
1117
|
-
];
|
|
1118
|
-
return routes;
|
|
1119
|
-
}
|
|
1120
|
-
class AXMReportManagementModule {
|
|
1121
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMReportManagementModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
1122
|
-
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "22.0.8", ngImport: i0, type: AXMReportManagementModule, imports: [AXPDomainModule,
|
|
1123
|
-
AXPRuntimeModule] }); }
|
|
1124
|
-
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMReportManagementModule, providers: [
|
|
1125
|
-
{
|
|
1126
|
-
provide: ROUTES,
|
|
1127
|
-
multi: true,
|
|
1128
|
-
useFactory: routesFacory,
|
|
1129
|
-
},
|
|
1130
|
-
provideEntity([RootConfig.entities.report.fullName, RootConfig.entities.category.fullName]),
|
|
1131
|
-
// Module Manifest Provider
|
|
1132
|
-
{
|
|
1133
|
-
provide: AXP_MODULE_MANIFEST_PROVIDER,
|
|
1134
|
-
useValue: ReportManagementManifest,
|
|
1135
|
-
multi: true,
|
|
1136
|
-
},
|
|
1137
|
-
// Provider references (now using tokens)
|
|
1138
|
-
{
|
|
1139
|
-
provide: AXP_PERMISSION_DEFINITION_PROVIDER,
|
|
1140
|
-
useClass: AXMPermissionDefinitionProvider,
|
|
1141
|
-
multi: true,
|
|
1142
|
-
},
|
|
1143
|
-
{
|
|
1144
|
-
provide: AXP_MENU_PROVIDER,
|
|
1145
|
-
useClass: AXMMenuProvider,
|
|
1146
|
-
multi: true,
|
|
1147
|
-
},
|
|
1148
|
-
{
|
|
1149
|
-
provide: AXP_FEATURE_DEFINITION_PROVIDER,
|
|
1150
|
-
useClass: AXPReportManagementFeatureDefinitionProvider,
|
|
1151
|
-
multi: true,
|
|
1152
|
-
},
|
|
1153
|
-
...AXM_REPORT_GENERATION_BACKGROUND_OPERATION_HANDLERS,
|
|
1154
|
-
provideCommandSetups([
|
|
1155
|
-
{
|
|
1156
|
-
key: 'ReportManagement.Report:OpenInPopup',
|
|
1157
|
-
command: () => Promise.resolve().then(function () { return openReportInPopup_command; }).then((c) => c.AXPOpenReportInPopupCommand),
|
|
1158
|
-
},
|
|
1159
|
-
{
|
|
1160
|
-
key: 'ReportManagement.Report:OpenViewer',
|
|
1161
|
-
command: () => Promise.resolve().then(function () { return openReportViewer_command; }).then((c) => c.AXPOpenReportViewerCommand),
|
|
1162
|
-
},
|
|
1163
|
-
]),
|
|
1164
|
-
{
|
|
1165
|
-
provide: AXP_ENTITY_ACTION_PLUGIN,
|
|
1166
|
-
multi: true,
|
|
1167
|
-
useFactory: () => createEntityReportsPlugin(inject(Injector)),
|
|
1575
|
+
context: {
|
|
1576
|
+
eval: (path) => get(rowData, path),
|
|
1168
1577
|
},
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1578
|
+
};
|
|
1579
|
+
const evaluated = await this.expressionEvaluator.evaluate(title, scope);
|
|
1580
|
+
return isString(evaluated) ? evaluated : title;
|
|
1581
|
+
}
|
|
1582
|
+
async dismissReportGenerationInboxNotification(runId) {
|
|
1583
|
+
if (!this.inboxConnector) {
|
|
1584
|
+
return;
|
|
1585
|
+
}
|
|
1586
|
+
try {
|
|
1587
|
+
await this.inboxConnector.dismissByCorrelationId(buildReportGenerationNotificationCorrelationId(runId));
|
|
1588
|
+
}
|
|
1589
|
+
catch {
|
|
1590
|
+
// Best-effort — opening the report should still proceed.
|
|
1591
|
+
}
|
|
1592
|
+
}
|
|
1593
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPOpenReportInPopupCommand, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1594
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPOpenReportInPopupCommand, providedIn: 'root' }); }
|
|
1172
1595
|
}
|
|
1173
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type:
|
|
1174
|
-
type:
|
|
1175
|
-
args: [{
|
|
1176
|
-
imports: [
|
|
1177
|
-
AXPDomainModule,
|
|
1178
|
-
AXPRuntimeModule,
|
|
1179
|
-
// Entity Modules
|
|
1180
|
-
],
|
|
1181
|
-
exports: [],
|
|
1182
|
-
declarations: [],
|
|
1183
|
-
providers: [
|
|
1184
|
-
{
|
|
1185
|
-
provide: ROUTES,
|
|
1186
|
-
multi: true,
|
|
1187
|
-
useFactory: routesFacory,
|
|
1188
|
-
},
|
|
1189
|
-
provideEntity([RootConfig.entities.report.fullName, RootConfig.entities.category.fullName]),
|
|
1190
|
-
// Module Manifest Provider
|
|
1191
|
-
{
|
|
1192
|
-
provide: AXP_MODULE_MANIFEST_PROVIDER,
|
|
1193
|
-
useValue: ReportManagementManifest,
|
|
1194
|
-
multi: true,
|
|
1195
|
-
},
|
|
1196
|
-
// Provider references (now using tokens)
|
|
1197
|
-
{
|
|
1198
|
-
provide: AXP_PERMISSION_DEFINITION_PROVIDER,
|
|
1199
|
-
useClass: AXMPermissionDefinitionProvider,
|
|
1200
|
-
multi: true,
|
|
1201
|
-
},
|
|
1202
|
-
{
|
|
1203
|
-
provide: AXP_MENU_PROVIDER,
|
|
1204
|
-
useClass: AXMMenuProvider,
|
|
1205
|
-
multi: true,
|
|
1206
|
-
},
|
|
1207
|
-
{
|
|
1208
|
-
provide: AXP_FEATURE_DEFINITION_PROVIDER,
|
|
1209
|
-
useClass: AXPReportManagementFeatureDefinitionProvider,
|
|
1210
|
-
multi: true,
|
|
1211
|
-
},
|
|
1212
|
-
...AXM_REPORT_GENERATION_BACKGROUND_OPERATION_HANDLERS,
|
|
1213
|
-
provideCommandSetups([
|
|
1214
|
-
{
|
|
1215
|
-
key: 'ReportManagement.Report:OpenInPopup',
|
|
1216
|
-
command: () => Promise.resolve().then(function () { return openReportInPopup_command; }).then((c) => c.AXPOpenReportInPopupCommand),
|
|
1217
|
-
},
|
|
1218
|
-
{
|
|
1219
|
-
key: 'ReportManagement.Report:OpenViewer',
|
|
1220
|
-
command: () => Promise.resolve().then(function () { return openReportViewer_command; }).then((c) => c.AXPOpenReportViewerCommand),
|
|
1221
|
-
},
|
|
1222
|
-
]),
|
|
1223
|
-
{
|
|
1224
|
-
provide: AXP_ENTITY_ACTION_PLUGIN,
|
|
1225
|
-
multi: true,
|
|
1226
|
-
useFactory: () => createEntityReportsPlugin(inject(Injector)),
|
|
1227
|
-
},
|
|
1228
|
-
provideLazyProvider(AXP_PAGE_COMPONENT_PROVIDER, () => import('./acorex-platform-module-report-management-client-entity-reports-page-component.provider-C6tJPxri.mjs').then((m) => m.AXMEntityReportsPageComponentProvider)),
|
|
1229
|
-
],
|
|
1230
|
-
}]
|
|
1596
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPOpenReportInPopupCommand, decorators: [{
|
|
1597
|
+
type: Injectable,
|
|
1598
|
+
args: [{ providedIn: 'root' }]
|
|
1231
1599
|
}] });
|
|
1232
1600
|
|
|
1601
|
+
var openReportInPopup_command = /*#__PURE__*/Object.freeze({
|
|
1602
|
+
__proto__: null,
|
|
1603
|
+
AXPOpenReportInPopupCommand: AXPOpenReportInPopupCommand
|
|
1604
|
+
});
|
|
1605
|
+
|
|
1233
1606
|
//#region ---- Report Viewer User Settings Service ----
|
|
1234
1607
|
class AXPReportViewerUserSettingsService {
|
|
1235
1608
|
constructor() {
|
|
@@ -1532,6 +1905,7 @@ function applyGroupByDrillLinksToColumns(columns, groupByDefinitions) {
|
|
|
1532
1905
|
}
|
|
1533
1906
|
//#endregion
|
|
1534
1907
|
|
|
1908
|
+
const OPEN_REPORT_VIEWER_COMMAND = 'ReportManagement.Report:OpenViewer';
|
|
1535
1909
|
const AXPReportViewerViewModel = signalStore(withState(() => ({
|
|
1536
1910
|
reportDefinition: null,
|
|
1537
1911
|
currentLayout: null,
|
|
@@ -1549,6 +1923,9 @@ const AXPReportViewerViewModel = signalStore(withState(() => ({
|
|
|
1549
1923
|
frozen: false,
|
|
1550
1924
|
freeze: null,
|
|
1551
1925
|
backgroundQueued: false,
|
|
1926
|
+
backgroundGenerationRequestId: null,
|
|
1927
|
+
/** When true, completion is delivered inline on the viewer (no server inbox toast). */
|
|
1928
|
+
inlineGenerationWatchActive: false,
|
|
1552
1929
|
parametersReadonly: false,
|
|
1553
1930
|
selectedLayoutIds: [],
|
|
1554
1931
|
})), withComputed((store, widgetRegistryService = inject(AXPWidgetRegistryService)) => ({
|
|
@@ -1602,7 +1979,7 @@ const AXPReportViewerViewModel = signalStore(withState(() => ({
|
|
|
1602
1979
|
return true;
|
|
1603
1980
|
}
|
|
1604
1981
|
if ((store.reportDefinition()?.generation?.mode ?? 'interactive') === 'background') {
|
|
1605
|
-
if (store.backgroundQueued()) {
|
|
1982
|
+
if (store.backgroundQueued() && !store.frozen()) {
|
|
1606
1983
|
return false;
|
|
1607
1984
|
}
|
|
1608
1985
|
return store.selectedLayoutIds().length > 0;
|
|
@@ -1735,6 +2112,12 @@ const AXPReportViewerViewModel = signalStore(withState(() => ({
|
|
|
1735
2112
|
isBackgroundReportMode: computed(() => (store.reportDefinition()?.generation?.mode ?? 'interactive') === 'background'),
|
|
1736
2113
|
hasSelectedBackgroundLayouts: computed(() => store.selectedLayoutIds().length > 0),
|
|
1737
2114
|
areParametersReadonly: computed(() => store.parametersReadonly() || store.frozen()),
|
|
2115
|
+
isBackgroundGenerateDisabled: computed(() => {
|
|
2116
|
+
if ((store.reportDefinition()?.generation?.mode ?? 'interactive') !== 'background') {
|
|
2117
|
+
return false;
|
|
2118
|
+
}
|
|
2119
|
+
return store.backgroundQueued() || store.selectedLayoutIds().length === 0;
|
|
2120
|
+
}),
|
|
1738
2121
|
canSwitchLayout: computed(() => {
|
|
1739
2122
|
if (store.frozen() && (store.freeze()?.dataSources?.length ?? 0) <= 1) {
|
|
1740
2123
|
return false;
|
|
@@ -1743,8 +2126,207 @@ const AXPReportViewerViewModel = signalStore(withState(() => ({
|
|
|
1743
2126
|
}),
|
|
1744
2127
|
generationMode: computed(() => store.reportDefinition()?.generation?.mode ?? 'interactive'),
|
|
1745
2128
|
//#endregion
|
|
1746
|
-
})), withMethods((store, reportDefinitionService = inject(AXPReportViewerService), reportUserSettingsService = inject(AXPReportViewerUserSettingsService), queryService = inject(AXPQueryService), commandService = inject(AXPCommandService),
|
|
2129
|
+
})), withMethods((store, reportDefinitionService = inject(AXPReportViewerService), reportUserSettingsService = inject(AXPReportViewerUserSettingsService), queryService = inject(AXPQueryService), commandService = inject(AXPCommandService), userNotificationService = inject(AXP_USER_NOTIFICATION_SERVICE), translationService = inject(AXTranslationService), inboxConnector = inject(AXPInAppInboxConnectorService, {
|
|
2130
|
+
optional: true,
|
|
2131
|
+
})) => {
|
|
1747
2132
|
let activeFetchCount = 0;
|
|
2133
|
+
let activeGenerationWatchId = null;
|
|
2134
|
+
const BACKGROUND_GENERATION_POLL_MS = 3_000;
|
|
2135
|
+
const dismissReportGenerationInboxNotification = async (runId) => {
|
|
2136
|
+
const normalized = runId.trim();
|
|
2137
|
+
if (!normalized || !inboxConnector) {
|
|
2138
|
+
return;
|
|
2139
|
+
}
|
|
2140
|
+
try {
|
|
2141
|
+
await inboxConnector.dismissByCorrelationId(buildReportGenerationNotificationCorrelationId(normalized));
|
|
2142
|
+
}
|
|
2143
|
+
catch {
|
|
2144
|
+
// Best-effort — the report viewer should still open.
|
|
2145
|
+
}
|
|
2146
|
+
};
|
|
2147
|
+
const openGeneratedReportFromNotification = async (runId) => {
|
|
2148
|
+
const report = store.reportDefinition();
|
|
2149
|
+
const normalizedRunId = runId.trim();
|
|
2150
|
+
if (!report?.id || !normalizedRunId) {
|
|
2151
|
+
return;
|
|
2152
|
+
}
|
|
2153
|
+
await dismissReportGenerationInboxNotification(normalizedRunId);
|
|
2154
|
+
await commandService.execute(OPEN_REPORT_VIEWER_COMMAND, {
|
|
2155
|
+
reportId: report.id,
|
|
2156
|
+
runId: normalizedRunId,
|
|
2157
|
+
});
|
|
2158
|
+
};
|
|
2159
|
+
const showGenerationNotification = async (options) => {
|
|
2160
|
+
const runId = options.runId?.trim();
|
|
2161
|
+
const showOpenAction = options.showOpenAction === true && !!runId;
|
|
2162
|
+
const toastActions = showOpenAction
|
|
2163
|
+
? [
|
|
2164
|
+
{
|
|
2165
|
+
text: await translationService.translateAsync('@report-management:report-generation.notifications.actions.open-viewer'),
|
|
2166
|
+
color: 'primary',
|
|
2167
|
+
onClick: () => openGeneratedReportFromNotification(runId),
|
|
2168
|
+
},
|
|
2169
|
+
]
|
|
2170
|
+
: undefined;
|
|
2171
|
+
await userNotificationService.notify({
|
|
2172
|
+
correlationId: runId
|
|
2173
|
+
? buildReportGenerationNotificationCorrelationId(runId)
|
|
2174
|
+
: `report-generation-ui:${options.titleKey}`,
|
|
2175
|
+
title: await translationService.translateAsync(options.titleKey),
|
|
2176
|
+
body: await translationService.translateAsync(options.bodyKey),
|
|
2177
|
+
icon: options.icon,
|
|
2178
|
+
delivery: {
|
|
2179
|
+
toast: {
|
|
2180
|
+
color: options.color,
|
|
2181
|
+
location: 'bottom-center',
|
|
2182
|
+
closeButton: true,
|
|
2183
|
+
timeOut: showOpenAction ? 8_000 : 3_000,
|
|
2184
|
+
timeOutProgress: true,
|
|
2185
|
+
showActions: showOpenAction,
|
|
2186
|
+
},
|
|
2187
|
+
},
|
|
2188
|
+
toastActions,
|
|
2189
|
+
});
|
|
2190
|
+
};
|
|
2191
|
+
const showGenerationReadyNotification = async (runId) => {
|
|
2192
|
+
await showGenerationNotification({
|
|
2193
|
+
color: 'success',
|
|
2194
|
+
icon: 'fa-light fa-circle-check',
|
|
2195
|
+
titleKey: '@report-management:report-generation.notifications.complete.title',
|
|
2196
|
+
bodyKey: '@report-management:report-generation.notifications.complete.body',
|
|
2197
|
+
runId,
|
|
2198
|
+
showOpenAction: false,
|
|
2199
|
+
});
|
|
2200
|
+
};
|
|
2201
|
+
const showGenerationFailedNotification = async () => {
|
|
2202
|
+
await showGenerationNotification({
|
|
2203
|
+
color: 'danger',
|
|
2204
|
+
icon: 'fa-light fa-circle-exclamation',
|
|
2205
|
+
titleKey: '@report-management:report-generation.notifications.failed.title',
|
|
2206
|
+
bodyKey: '@report-management:report-generation.notifications.failed.body',
|
|
2207
|
+
});
|
|
2208
|
+
};
|
|
2209
|
+
const api = {
|
|
2210
|
+
loadFrozenRun: async (_runId) => { },
|
|
2211
|
+
startBackgroundGenerationWatch: async (_requestId) => { },
|
|
2212
|
+
};
|
|
2213
|
+
api.loadFrozenRun = async (runId) => {
|
|
2214
|
+
patchState(store, { status: AXPPageStatus.Processing, error: null });
|
|
2215
|
+
try {
|
|
2216
|
+
const result = await queryService.fetch(AXMReportManagementQueryKeys.ReportGeneration.GetViewerFreeze, { id: runId });
|
|
2217
|
+
const freeze = runtimeQueryPayloadData(result);
|
|
2218
|
+
if (!result?.success || !freeze) {
|
|
2219
|
+
patchState(store, {
|
|
2220
|
+
error: commandMessageTextForError(result?.message?.text) ||
|
|
2221
|
+
'@report-management:report-generation.errors.freeze-not-found',
|
|
2222
|
+
});
|
|
2223
|
+
return;
|
|
2224
|
+
}
|
|
2225
|
+
let report = store.reportDefinition();
|
|
2226
|
+
if (freeze.definition) {
|
|
2227
|
+
report = {
|
|
2228
|
+
id: freeze.reportId,
|
|
2229
|
+
title: freeze.definition.title,
|
|
2230
|
+
categoryIds: report?.categoryIds ?? [],
|
|
2231
|
+
parameterGroups: report?.parameterGroups ?? [],
|
|
2232
|
+
layouts: freeze.definition.layouts,
|
|
2233
|
+
defaultLayoutId: freeze.definition.defaultLayoutId,
|
|
2234
|
+
generation: report?.generation,
|
|
2235
|
+
};
|
|
2236
|
+
}
|
|
2237
|
+
else if (!report) {
|
|
2238
|
+
report = (await reportDefinitionService.getReportById(freeze.reportId)) ?? null;
|
|
2239
|
+
}
|
|
2240
|
+
if (!report) {
|
|
2241
|
+
patchState(store, {
|
|
2242
|
+
error: '@report-management:report-viewer.messages.error.failed-to-load',
|
|
2243
|
+
});
|
|
2244
|
+
return;
|
|
2245
|
+
}
|
|
2246
|
+
const defaultLayout = report.layouts.find((layout) => layout.id === freeze.definition?.defaultLayoutId) ||
|
|
2247
|
+
report.layouts.find((layout) => layout.id === freeze.dataSources[0]?.layoutId) ||
|
|
2248
|
+
report.layouts[0];
|
|
2249
|
+
patchState(store, {
|
|
2250
|
+
reportDefinition: report,
|
|
2251
|
+
currentLayout: defaultLayout,
|
|
2252
|
+
filterContext: freeze.parameters ?? {},
|
|
2253
|
+
lastAppliedFilterContext: freeze.parameters ?? {},
|
|
2254
|
+
allowFetchData: true,
|
|
2255
|
+
shouldExecuteReport: true,
|
|
2256
|
+
hasBeenExecuted: true,
|
|
2257
|
+
executionRequestId: store.executionRequestId() + 1,
|
|
2258
|
+
runId,
|
|
2259
|
+
frozen: true,
|
|
2260
|
+
freeze,
|
|
2261
|
+
backgroundQueued: false,
|
|
2262
|
+
backgroundGenerationRequestId: null,
|
|
2263
|
+
inlineGenerationWatchActive: false,
|
|
2264
|
+
parametersReadonly: true,
|
|
2265
|
+
status: AXPPageStatus.Idle,
|
|
2266
|
+
});
|
|
2267
|
+
}
|
|
2268
|
+
catch (error) {
|
|
2269
|
+
patchState(store, {
|
|
2270
|
+
error: error instanceof Error
|
|
2271
|
+
? error.message
|
|
2272
|
+
: '@report-management:report-generation.errors.freeze-not-found',
|
|
2273
|
+
});
|
|
2274
|
+
}
|
|
2275
|
+
finally {
|
|
2276
|
+
patchState(store, { status: AXPPageStatus.Idle });
|
|
2277
|
+
}
|
|
2278
|
+
};
|
|
2279
|
+
api.startBackgroundGenerationWatch = async (requestId) => {
|
|
2280
|
+
activeGenerationWatchId = requestId;
|
|
2281
|
+
while (activeGenerationWatchId === requestId) {
|
|
2282
|
+
if (!store.backgroundQueued() || store.backgroundGenerationRequestId() !== requestId) {
|
|
2283
|
+
return;
|
|
2284
|
+
}
|
|
2285
|
+
await new Promise((resolve) => setTimeout(resolve, BACKGROUND_GENERATION_POLL_MS));
|
|
2286
|
+
if (activeGenerationWatchId !== requestId) {
|
|
2287
|
+
return;
|
|
2288
|
+
}
|
|
2289
|
+
try {
|
|
2290
|
+
const result = await queryService.fetch(AXMReportManagementQueryKeys.ReportGeneration.Get, { id: requestId });
|
|
2291
|
+
const request = runtimeQueryPayloadData(result);
|
|
2292
|
+
if (!request || activeGenerationWatchId !== requestId) {
|
|
2293
|
+
continue;
|
|
2294
|
+
}
|
|
2295
|
+
if (request.status === 'completed') {
|
|
2296
|
+
activeGenerationWatchId = null;
|
|
2297
|
+
const inlineWatchActive = store.inlineGenerationWatchActive();
|
|
2298
|
+
patchState(store, {
|
|
2299
|
+
backgroundQueued: false,
|
|
2300
|
+
inlineGenerationWatchActive: false,
|
|
2301
|
+
...(inlineWatchActive ? {} : { backgroundGenerationRequestId: null }),
|
|
2302
|
+
});
|
|
2303
|
+
if (!inlineWatchActive) {
|
|
2304
|
+
return;
|
|
2305
|
+
}
|
|
2306
|
+
await api.loadFrozenRun(requestId);
|
|
2307
|
+
if (!store.error()) {
|
|
2308
|
+
await showGenerationReadyNotification(requestId);
|
|
2309
|
+
}
|
|
2310
|
+
return;
|
|
2311
|
+
}
|
|
2312
|
+
if (request.status === 'failed' || request.status === 'cancelled') {
|
|
2313
|
+
activeGenerationWatchId = null;
|
|
2314
|
+
patchState(store, {
|
|
2315
|
+
backgroundQueued: false,
|
|
2316
|
+
backgroundGenerationRequestId: null,
|
|
2317
|
+
inlineGenerationWatchActive: false,
|
|
2318
|
+
status: AXPPageStatus.Error,
|
|
2319
|
+
error: '@report-management:report-generation.notifications.failed.body',
|
|
2320
|
+
});
|
|
2321
|
+
await showGenerationFailedNotification();
|
|
2322
|
+
return;
|
|
2323
|
+
}
|
|
2324
|
+
}
|
|
2325
|
+
catch {
|
|
2326
|
+
// Keep polling while the run is still active.
|
|
2327
|
+
}
|
|
2328
|
+
}
|
|
2329
|
+
};
|
|
1748
2330
|
const generateInBackground = async () => {
|
|
1749
2331
|
const report = store.reportDefinition();
|
|
1750
2332
|
const isBackgroundMode = (report?.generation?.mode ?? 'interactive') === 'background';
|
|
@@ -1762,6 +2344,16 @@ const AXPReportViewerViewModel = signalStore(withState(() => ({
|
|
|
1762
2344
|
return;
|
|
1763
2345
|
}
|
|
1764
2346
|
patchState(store, { status: AXPPageStatus.Submitting, error: null });
|
|
2347
|
+
if (store.frozen()) {
|
|
2348
|
+
patchState(store, {
|
|
2349
|
+
frozen: false,
|
|
2350
|
+
freeze: null,
|
|
2351
|
+
runId: null,
|
|
2352
|
+
hasBeenExecuted: false,
|
|
2353
|
+
allowFetchData: false,
|
|
2354
|
+
parametersReadonly: false,
|
|
2355
|
+
});
|
|
2356
|
+
}
|
|
1765
2357
|
try {
|
|
1766
2358
|
const result = await commandService.executeRemote(AXMReportManagementCommandKeys.ReportGeneration.Create, {
|
|
1767
2359
|
reportId: report.id,
|
|
@@ -1769,6 +2361,7 @@ const AXPReportViewerViewModel = signalStore(withState(() => ({
|
|
|
1769
2361
|
layoutId: layoutIds[0],
|
|
1770
2362
|
parameters: store.filterContext(),
|
|
1771
2363
|
trigger: 'manual',
|
|
2364
|
+
suppressNotificationOnComplete: true,
|
|
1772
2365
|
});
|
|
1773
2366
|
if (!result?.success) {
|
|
1774
2367
|
patchState(store, {
|
|
@@ -1778,17 +2371,47 @@ const AXPReportViewerViewModel = signalStore(withState(() => ({
|
|
|
1778
2371
|
});
|
|
1779
2372
|
return;
|
|
1780
2373
|
}
|
|
2374
|
+
const createResult = runtimeCommandPayloadData(result);
|
|
2375
|
+
const requestId = createResult?.id?.trim();
|
|
2376
|
+
if (!createResult || !requestId) {
|
|
2377
|
+
patchState(store, {
|
|
2378
|
+
status: AXPPageStatus.Error,
|
|
2379
|
+
error: '@report-management:report-generation.errors.create-failed',
|
|
2380
|
+
});
|
|
2381
|
+
return;
|
|
2382
|
+
}
|
|
2383
|
+
if (createResult.status === 'completed') {
|
|
2384
|
+
patchState(store, { status: AXPPageStatus.Idle, error: null });
|
|
2385
|
+
await api.loadFrozenRun(requestId);
|
|
2386
|
+
if (!store.error()) {
|
|
2387
|
+
await showGenerationReadyNotification(requestId);
|
|
2388
|
+
}
|
|
2389
|
+
return;
|
|
2390
|
+
}
|
|
1781
2391
|
patchState(store, {
|
|
1782
2392
|
status: AXPPageStatus.Submitted,
|
|
1783
2393
|
backgroundQueued: true,
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
toastService.show({
|
|
1788
|
-
color: 'success',
|
|
1789
|
-
title: await translationService.translateAsync('@report-management:report-generation.messages.queued-title'),
|
|
1790
|
-
content: await translationService.translateAsync('@report-management:report-generation.messages.queued-body'),
|
|
2394
|
+
backgroundGenerationRequestId: requestId,
|
|
2395
|
+
inlineGenerationWatchActive: true,
|
|
2396
|
+
error: null,
|
|
1791
2397
|
});
|
|
2398
|
+
if (createResult.deduplicated) {
|
|
2399
|
+
await showGenerationNotification({
|
|
2400
|
+
color: 'warning',
|
|
2401
|
+
icon: 'fa-light fa-triangle-exclamation',
|
|
2402
|
+
titleKey: '@report-management:report-generation.messages.deduplicated-title',
|
|
2403
|
+
bodyKey: '@report-management:report-generation.messages.deduplicated-body',
|
|
2404
|
+
});
|
|
2405
|
+
}
|
|
2406
|
+
else {
|
|
2407
|
+
await showGenerationNotification({
|
|
2408
|
+
color: 'success',
|
|
2409
|
+
icon: 'fa-light fa-clock',
|
|
2410
|
+
titleKey: '@report-management:report-generation.messages.queued-title',
|
|
2411
|
+
bodyKey: '@report-management:report-generation.messages.queued-body',
|
|
2412
|
+
});
|
|
2413
|
+
}
|
|
2414
|
+
void api.startBackgroundGenerationWatch(requestId);
|
|
1792
2415
|
}
|
|
1793
2416
|
catch (error) {
|
|
1794
2417
|
patchState(store, {
|
|
@@ -1799,12 +2422,34 @@ const AXPReportViewerViewModel = signalStore(withState(() => ({
|
|
|
1799
2422
|
});
|
|
1800
2423
|
}
|
|
1801
2424
|
};
|
|
2425
|
+
const releaseInlineNotificationWatch = async () => {
|
|
2426
|
+
const requestId = store.backgroundGenerationRequestId()?.trim();
|
|
2427
|
+
activeGenerationWatchId = null;
|
|
2428
|
+
patchState(store, {
|
|
2429
|
+
inlineGenerationWatchActive: false,
|
|
2430
|
+
backgroundQueued: false,
|
|
2431
|
+
});
|
|
2432
|
+
if (!requestId) {
|
|
2433
|
+
return;
|
|
2434
|
+
}
|
|
2435
|
+
try {
|
|
2436
|
+
await commandService.executeRemote(AXMReportManagementCommandKeys.ReportGeneration.ReleaseInlineWatch, { id: requestId });
|
|
2437
|
+
}
|
|
2438
|
+
catch {
|
|
2439
|
+
// Best-effort — completion notify re-reads the flag from storage.
|
|
2440
|
+
}
|
|
2441
|
+
};
|
|
1802
2442
|
const executeReport = async () => {
|
|
1803
2443
|
try {
|
|
1804
2444
|
if (store.status() === AXPPageStatus.Processing ||
|
|
1805
2445
|
store.status() === AXPPageStatus.Submitting) {
|
|
1806
2446
|
return;
|
|
1807
2447
|
}
|
|
2448
|
+
const report = store.reportDefinition();
|
|
2449
|
+
if ((report?.generation?.mode ?? 'interactive') === 'background') {
|
|
2450
|
+
await generateInBackground();
|
|
2451
|
+
return;
|
|
2452
|
+
}
|
|
1808
2453
|
if (store.frozen()) {
|
|
1809
2454
|
patchState(store, {
|
|
1810
2455
|
allowFetchData: true,
|
|
@@ -1814,7 +2459,6 @@ const AXPReportViewerViewModel = signalStore(withState(() => ({
|
|
|
1814
2459
|
});
|
|
1815
2460
|
return;
|
|
1816
2461
|
}
|
|
1817
|
-
const report = store.reportDefinition();
|
|
1818
2462
|
const layout = store.currentLayout();
|
|
1819
2463
|
if (!report || !layout) {
|
|
1820
2464
|
patchState(store, {
|
|
@@ -1822,10 +2466,6 @@ const AXPReportViewerViewModel = signalStore(withState(() => ({
|
|
|
1822
2466
|
});
|
|
1823
2467
|
return;
|
|
1824
2468
|
}
|
|
1825
|
-
if ((report.generation?.mode ?? 'interactive') === 'background') {
|
|
1826
|
-
await generateInBackground();
|
|
1827
|
-
return;
|
|
1828
|
-
}
|
|
1829
2469
|
patchState(store, {
|
|
1830
2470
|
status: AXPPageStatus.Submitting,
|
|
1831
2471
|
error: null,
|
|
@@ -1956,6 +2596,7 @@ const AXPReportViewerViewModel = signalStore(withState(() => ({
|
|
|
1956
2596
|
return {
|
|
1957
2597
|
//#region ---- Report Loading ----
|
|
1958
2598
|
async loadReport(reportId) {
|
|
2599
|
+
await releaseInlineNotificationWatch();
|
|
1959
2600
|
patchState(store, {
|
|
1960
2601
|
status: AXPPageStatus.Processing,
|
|
1961
2602
|
error: null,
|
|
@@ -1986,6 +2627,8 @@ const AXPReportViewerViewModel = signalStore(withState(() => ({
|
|
|
1986
2627
|
frozen: false,
|
|
1987
2628
|
freeze: null,
|
|
1988
2629
|
backgroundQueued: false,
|
|
2630
|
+
backgroundGenerationRequestId: null,
|
|
2631
|
+
inlineGenerationWatchActive: false,
|
|
1989
2632
|
parametersReadonly: false,
|
|
1990
2633
|
selectedLayoutIds: report.layouts.map((layout) => layout.id),
|
|
1991
2634
|
});
|
|
@@ -2087,76 +2730,14 @@ const AXPReportViewerViewModel = signalStore(withState(() => ({
|
|
|
2087
2730
|
executeReport,
|
|
2088
2731
|
fetchData,
|
|
2089
2732
|
generateInBackground,
|
|
2733
|
+
releaseInlineNotificationWatch,
|
|
2090
2734
|
nudgeFetch() {
|
|
2091
2735
|
if (!store.allowFetchData()) {
|
|
2092
2736
|
return;
|
|
2093
2737
|
}
|
|
2094
2738
|
patchState(store, { executionRequestId: store.executionRequestId() + 1 });
|
|
2095
2739
|
},
|
|
2096
|
-
|
|
2097
|
-
patchState(store, { status: AXPPageStatus.Processing, error: null });
|
|
2098
|
-
try {
|
|
2099
|
-
const result = await queryService.fetch(AXMReportManagementQueryKeys.ReportGeneration.GetViewerFreeze, { id: runId });
|
|
2100
|
-
const freeze = runtimeQueryPayloadData(result);
|
|
2101
|
-
if (!result?.success || !freeze) {
|
|
2102
|
-
patchState(store, {
|
|
2103
|
-
error: commandMessageTextForError(result?.message?.text) ||
|
|
2104
|
-
'@report-management:report-generation.errors.freeze-not-found',
|
|
2105
|
-
});
|
|
2106
|
-
return;
|
|
2107
|
-
}
|
|
2108
|
-
let report = store.reportDefinition();
|
|
2109
|
-
if (freeze.definition) {
|
|
2110
|
-
report = {
|
|
2111
|
-
id: freeze.reportId,
|
|
2112
|
-
title: freeze.definition.title,
|
|
2113
|
-
categoryIds: report?.categoryIds ?? [],
|
|
2114
|
-
parameterGroups: report?.parameterGroups ?? [],
|
|
2115
|
-
layouts: freeze.definition.layouts,
|
|
2116
|
-
defaultLayoutId: freeze.definition.defaultLayoutId,
|
|
2117
|
-
generation: report?.generation,
|
|
2118
|
-
};
|
|
2119
|
-
}
|
|
2120
|
-
else if (!report) {
|
|
2121
|
-
report = (await reportDefinitionService.getReportById(freeze.reportId)) ?? null;
|
|
2122
|
-
}
|
|
2123
|
-
if (!report) {
|
|
2124
|
-
patchState(store, {
|
|
2125
|
-
error: '@report-management:report-viewer.messages.error.failed-to-load',
|
|
2126
|
-
});
|
|
2127
|
-
return;
|
|
2128
|
-
}
|
|
2129
|
-
const defaultLayout = report.layouts.find((layout) => layout.id === freeze.definition?.defaultLayoutId) ||
|
|
2130
|
-
report.layouts.find((layout) => layout.id === freeze.dataSources[0]?.layoutId) ||
|
|
2131
|
-
report.layouts[0];
|
|
2132
|
-
patchState(store, {
|
|
2133
|
-
reportDefinition: report,
|
|
2134
|
-
currentLayout: defaultLayout,
|
|
2135
|
-
filterContext: freeze.parameters ?? {},
|
|
2136
|
-
lastAppliedFilterContext: freeze.parameters ?? {},
|
|
2137
|
-
allowFetchData: true,
|
|
2138
|
-
shouldExecuteReport: true,
|
|
2139
|
-
hasBeenExecuted: true,
|
|
2140
|
-
executionRequestId: store.executionRequestId() + 1,
|
|
2141
|
-
runId,
|
|
2142
|
-
frozen: true,
|
|
2143
|
-
freeze,
|
|
2144
|
-
backgroundQueued: false,
|
|
2145
|
-
parametersReadonly: true,
|
|
2146
|
-
status: AXPPageStatus.Idle,
|
|
2147
|
-
});
|
|
2148
|
-
}
|
|
2149
|
-
catch (error) {
|
|
2150
|
-
patchState(store, {
|
|
2151
|
-
error: error instanceof Error
|
|
2152
|
-
? error.message
|
|
2153
|
-
: '@report-management:report-generation.errors.freeze-not-found',
|
|
2154
|
-
});
|
|
2155
|
-
}
|
|
2156
|
-
finally {
|
|
2157
|
-
patchState(store, { status: AXPPageStatus.Idle });
|
|
2158
|
-
}
|
|
2159
|
-
},
|
|
2740
|
+
loadFrozenRun: api.loadFrozenRun,
|
|
2160
2741
|
//#endregion
|
|
2161
2742
|
//#region ---- Drill View ----
|
|
2162
2743
|
/**
|
|
@@ -2264,6 +2845,8 @@ const AXPReportViewerViewModel = signalStore(withState(() => ({
|
|
|
2264
2845
|
frozen: false,
|
|
2265
2846
|
freeze: null,
|
|
2266
2847
|
backgroundQueued: false,
|
|
2848
|
+
backgroundGenerationRequestId: null,
|
|
2849
|
+
inlineGenerationWatchActive: false,
|
|
2267
2850
|
parametersReadonly: false,
|
|
2268
2851
|
});
|
|
2269
2852
|
},
|
|
@@ -3290,14 +3873,50 @@ class AXPReportViewerPageComponent extends AXPPageLayoutBaseComponent {
|
|
|
3290
3873
|
});
|
|
3291
3874
|
}, /* @ts-ignore */
|
|
3292
3875
|
...(ngDevMode ? [{ debugName: "watchNavigationLoading" }] : /* istanbul ignore next */ []));
|
|
3876
|
+
this.syncFrozenRunUrl = effect(() => {
|
|
3877
|
+
const runId = this.vm.runId();
|
|
3878
|
+
const frozen = this.vm.isFrozen();
|
|
3879
|
+
const queued = this.vm.isBackgroundQueued();
|
|
3880
|
+
if (queued) {
|
|
3881
|
+
untracked(() => {
|
|
3882
|
+
const currentRunId = this.route.snapshot.queryParamMap.get('runId')?.trim();
|
|
3883
|
+
if (!currentRunId) {
|
|
3884
|
+
return;
|
|
3885
|
+
}
|
|
3886
|
+
void this.router.navigate([], {
|
|
3887
|
+
relativeTo: this.route,
|
|
3888
|
+
queryParams: { runId: null },
|
|
3889
|
+
queryParamsHandling: 'merge',
|
|
3890
|
+
replaceUrl: true,
|
|
3891
|
+
});
|
|
3892
|
+
});
|
|
3893
|
+
return;
|
|
3894
|
+
}
|
|
3895
|
+
if (!frozen || !runId) {
|
|
3896
|
+
return;
|
|
3897
|
+
}
|
|
3898
|
+
untracked(() => {
|
|
3899
|
+
const currentRunId = this.route.snapshot.queryParamMap.get('runId')?.trim();
|
|
3900
|
+
if (currentRunId === runId) {
|
|
3901
|
+
return;
|
|
3902
|
+
}
|
|
3903
|
+
void this.router.navigate([], {
|
|
3904
|
+
relativeTo: this.route,
|
|
3905
|
+
queryParams: { runId },
|
|
3906
|
+
queryParamsHandling: 'merge',
|
|
3907
|
+
replaceUrl: true,
|
|
3908
|
+
});
|
|
3909
|
+
this.recompute();
|
|
3910
|
+
});
|
|
3911
|
+
}, /* @ts-ignore */
|
|
3912
|
+
...(ngDevMode ? [{ debugName: "syncFrozenRunUrl" }] : /* istanbul ignore next */ []));
|
|
3293
3913
|
//#endregion
|
|
3294
3914
|
this.loadingDialogRef = null;
|
|
3295
3915
|
this.isDialogOpening = false;
|
|
3296
3916
|
this.lastReportRouteKey = null;
|
|
3297
3917
|
//#region ---- Computed Properties ----
|
|
3298
3918
|
this.showFiltersPanel = () => this.deviceService.isLarge();
|
|
3299
|
-
this.showReportDisplay = () => !this.vm.isBackgroundReportMode() &&
|
|
3300
|
-
!this.vm.isBackgroundQueued() &&
|
|
3919
|
+
this.showReportDisplay = () => (!this.vm.isBackgroundReportMode() || this.vm.isFrozen()) &&
|
|
3301
3920
|
(this.deviceService.isLarge() || (this.deviceService.isSmall() && this.vm.hasBeenExecuted()));
|
|
3302
3921
|
//#endregion
|
|
3303
3922
|
//#region ---- Layout Configurations ----
|
|
@@ -3316,17 +3935,31 @@ class AXPReportViewerPageComponent extends AXPPageLayoutBaseComponent {
|
|
|
3316
3935
|
},
|
|
3317
3936
|
});
|
|
3318
3937
|
this.layoutPageIcon = reportLayoutPageIcon;
|
|
3319
|
-
this.destroyRef.onDestroy(() =>
|
|
3938
|
+
this.destroyRef.onDestroy(() => {
|
|
3939
|
+
this.closeContentLoading();
|
|
3940
|
+
void this.vm.releaseInlineNotificationWatch();
|
|
3941
|
+
});
|
|
3320
3942
|
}
|
|
3321
3943
|
reportsListPath() {
|
|
3322
3944
|
return this.entityService
|
|
3323
3945
|
.withEntity(RootConfig.module.name, RootConfig.entities.report.name)
|
|
3324
3946
|
.createPath();
|
|
3325
3947
|
}
|
|
3948
|
+
isReportViewerUrl(url) {
|
|
3949
|
+
return url.includes(`/${RootConfig.module.route}/viewer`);
|
|
3950
|
+
}
|
|
3326
3951
|
//#endregion
|
|
3327
3952
|
//#region ---- Lifecycle ----
|
|
3328
3953
|
async ngOnInit() {
|
|
3329
3954
|
await super.ngOnInit();
|
|
3955
|
+
this.unsubscriber
|
|
3956
|
+
.takeUntilDestroy(this.router.events.pipe(filter((event) => event instanceof NavigationStart)))
|
|
3957
|
+
.subscribe((event) => {
|
|
3958
|
+
const navigation = event;
|
|
3959
|
+
if (this.isReportViewerUrl(this.router.url) && !this.isReportViewerUrl(navigation.url)) {
|
|
3960
|
+
void this.vm.releaseInlineNotificationWatch();
|
|
3961
|
+
}
|
|
3962
|
+
});
|
|
3330
3963
|
// Reload when reportId or runId changes. Ignore other query params (live filters).
|
|
3331
3964
|
this.unsubscriber
|
|
3332
3965
|
.takeUntilDestroy(combineLatest([this.route.paramMap, this.route.queryParamMap]))
|
|
@@ -3754,7 +4387,7 @@ class AXPReportViewerPageComponent extends AXPPageLayoutBaseComponent {
|
|
|
3754
4387
|
this.vm.updateFilterContext(event);
|
|
3755
4388
|
}
|
|
3756
4389
|
async handleExecuteReport() {
|
|
3757
|
-
if (this.vm.isFrozen()) {
|
|
4390
|
+
if (this.vm.isFrozen() && !this.vm.isBackgroundReportMode()) {
|
|
3758
4391
|
return;
|
|
3759
4392
|
}
|
|
3760
4393
|
const isValid = await this.filtersForm()?.validate();
|
|
@@ -3762,9 +4395,10 @@ class AXPReportViewerPageComponent extends AXPPageLayoutBaseComponent {
|
|
|
3762
4395
|
return;
|
|
3763
4396
|
}
|
|
3764
4397
|
await this.vm.executeReport();
|
|
4398
|
+
this.recompute();
|
|
3765
4399
|
}
|
|
3766
4400
|
async handleGenerateInBackground() {
|
|
3767
|
-
if (this.vm.isFrozen()) {
|
|
4401
|
+
if (this.vm.isFrozen() && !this.vm.isBackgroundReportMode()) {
|
|
3768
4402
|
return;
|
|
3769
4403
|
}
|
|
3770
4404
|
const isValid = await this.filtersForm()?.validate();
|
|
@@ -3915,8 +4549,7 @@ class AXPReportViewerPageComponent extends AXPPageLayoutBaseComponent {
|
|
|
3915
4549
|
return reportDefinition?.description || null;
|
|
3916
4550
|
}
|
|
3917
4551
|
getPageIcon() {
|
|
3918
|
-
if (this.vm.isBackgroundReportMode() ||
|
|
3919
|
-
this.vm.isBackgroundQueued() ||
|
|
4552
|
+
if ((this.vm.isBackgroundReportMode() && !this.vm.isFrozen()) ||
|
|
3920
4553
|
!this.vm.hasMultipleLayouts() ||
|
|
3921
4554
|
!this.showReportDisplay()) {
|
|
3922
4555
|
return null;
|
|
@@ -3930,8 +4563,7 @@ class AXPReportViewerPageComponent extends AXPPageLayoutBaseComponent {
|
|
|
3930
4563
|
});
|
|
3931
4564
|
}
|
|
3932
4565
|
async getTitleActions() {
|
|
3933
|
-
if (this.vm.isBackgroundReportMode() ||
|
|
3934
|
-
this.vm.isBackgroundQueued() ||
|
|
4566
|
+
if ((this.vm.isBackgroundReportMode() && !this.vm.isFrozen()) ||
|
|
3935
4567
|
!this.vm.hasMultipleLayouts() ||
|
|
3936
4568
|
!this.showReportDisplay()) {
|
|
3937
4569
|
return [];
|
|
@@ -4063,7 +4695,7 @@ class AXPReportViewerPageComponent extends AXPPageLayoutBaseComponent {
|
|
|
4063
4695
|
provide: AXPPageLayoutBase,
|
|
4064
4696
|
useExisting: AXPReportViewerPageComponent,
|
|
4065
4697
|
},
|
|
4066
|
-
], viewQueries: [{ propertyName: "filtersForm", first: true, predicate: ["filtersForm"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<axp-page-layout *translate=\"let t\">\n <!-- Left Panel: Filters (Always visible for desktop) -->\n @if (showFiltersPanel()) {\n <axp-layout-start-side>\n <axp-layout-header>\n <axp-layout-title>\n {{ t('@report-management:report-viewer.components.filters.title') | async }}\n </axp-layout-title>\n </axp-layout-header>\n <axp-layout-content>\n @if (vm.reportDefinition()) {\n <axp-layout-renderer #filtersForm [layout]=\"vm.formDefinition()\" [context]=\"vm.filterContext()\" [look]=\"'card'\"\n (contextChange)=\"handleFiltersChange($event)\" (contextInitiated)=\"handleFiltersInitiated($event)\">\n </axp-layout-renderer>\n <!-- ----- Background report layout multi-select ----- -->\n @if (vm.isBackgroundReportMode() && !vm.isBackgroundQueued() && vm.availableLayouts().length > 0) {\n <div class=\"mt-4 pt-4 border-t\">\n <div class=\"mb-2\">\n <span class=\"text-sm font-medium\">\n {{ t('@report-management:report-generation.components.background-layouts.title') | async }}\n </span>\n </div>\n <p class=\"text-xs opacity-70 mb-3\">\n {{ t('@report-management:report-generation.components.background-layouts.description') | async }}\n </p>\n <div class=\"flex flex-col gap-2\">\n @for (layout of vm.availableLayouts(); track layout.id) {\n <label class=\"flex items-center gap-2 p-2 rounded border cursor-pointer hover:bg-neutral-50\">\n <ax-check-box\n [ngModel]=\"vm.isBackgroundLayoutSelected(layout.id)\"\n (ngModelChange)=\"handleBackgroundLayoutToggle(layout.id, $event)\"\n ></ax-check-box>\n <ax-icon [icon]=\"layoutPageIcon(layout.icon, layout)\"></ax-icon>\n <span class=\"text-sm\">{{ getLayoutSelectionLabel(layout) | translate | async }}</span>\n </label>\n }\n </div>\n </div>\n }\n }\n </axp-layout-content>\n <axp-layout-footer class=\"p-4 border-t\" *translate=\"let t\">\n @if (vm.hasUnappliedFilters()) {\n <div class=\"w-full warning-lightest-surface mb-2 p-2 rounded border border-warning-200\">\n <div class=\"flex items-center gap-2 text-warning-800\">\n <ax-icon class=\"fa-light fa-exclamation-triangle text-sm\"></ax-icon>\n <span class=\"text-xs\">{{\n t('@report-management:report-viewer.components.filters.messages.warning.unapplied') | async\n }}</span>\n </div>\n </div>\n }\n @if (vm.isBackgroundReportMode() && !vm.hasSelectedBackgroundLayouts() && !vm.isBackgroundQueued()) {\n <div class=\"w-full warning-lightest-surface mb-2 p-2 rounded border border-warning-200\">\n <div class=\"flex items-center gap-2 text-warning-800\">\n <ax-icon class=\"fa-light fa-exclamation-triangle text-sm\"></ax-icon>\n <span class=\"text-xs\">{{\n t('@report-management:report-generation.errors.no-layouts-selected') | async\n }}</span>\n </div>\n </div>\n }\n <ax-button class=\"w-full\" [disabled]=\"!vm.canExecute() || vm.areParametersReadonly() || vm.isBackgroundQueued()\"\n [text]=\"(vm.isBackgroundReportMode()\n ? t('@report-management:report-generation.actions.generate-in-background')\n : t('@report-management:report-viewer.actions.execute.title')) | async\" [color]=\"'primary'\"\n (onClick)=\"execute({ name: 'execute-report' })\">\n <ax-prefix>\n <ax-icon [icon]=\"vm.isBackgroundReportMode() ? 'fa-light fa-clock' : 'fa-light fa-play'\"></ax-icon>\n </ax-prefix>\n </ax-button>\n <!-- ----- Secondary background generate for choose mode ----- -->\n @if (canGenerateInBackground() && vm.generationMode() === 'choose') {\n <ax-button class=\"w-full mt-2\" [disabled]=\"vm.areParametersReadonly()\"\n [text]=\"t('@report-management:report-generation.actions.generate-in-background') | async\" [color]=\"'default'\"\n (onClick)=\"execute({ name: 'generate-in-background' })\">\n <ax-prefix>\n <ax-icon icon=\"fa-light fa-clock\"></ax-icon>\n </ax-prefix>\n </ax-button>\n }\n </axp-layout-footer>\n </axp-layout-start-side>\n }\n <!-- Main Content: Report Display -->\n <axp-page-content class=\"overflow-auto\">\n @if (vm.isFrozen()) {\n <!-- ----- Frozen run banner ----- -->\n <div class=\"warning-lightest-surface mb-3 p-3 rounded border border-warning-200 text-warning-800 text-sm\">\n {{ t('@report-management:report-generation.banners.frozen') | async }}\n </div>\n }\n @if (vm.hasError()) {\n <!-- Error State -->\n <axp-state-message icon=\"fa-light fa-exclamation-triangle\"\n [title]=\"'@report-management:report-viewer.messages.error.fetch-title'\"\n [description]=\"vm.error() || '@report-management:report-viewer.messages.error.unexpected'\">\n <div slot=\"actions\">\n <ax-button look=\"outline\" color=\"primary\"\n [text]=\"t('@report-management:report-viewer.actions.retry.title') | async\" (onClick)=\"vm.clearError()\">\n <ax-prefix>\n <ax-icon class=\"fa-light fa-refresh\"></ax-icon>\n </ax-prefix>\n </ax-button>\n </div>\n </axp-state-message>\n } @else if (!vm.reportDefinition()) {\n <!-- No Report Selected State -->\n <axp-state-message icon=\"fa-light fa-chart-line\"\n [title]=\"'@report-management:report-viewer.components.report-viewer.empty-states.no-report.title'\"\n [description]=\"'@report-management:report-viewer.components.report-viewer.empty-states.no-report.description'\">\n <div slot=\"actions\">\n <ax-button look=\"outline\" color=\"primary\"\n [text]=\"t('@report-management:report-viewer.actions.browse-reports.title') | async\">\n <ax-prefix>\n <ax-icon class=\"fa-light fa-folder-open\"></ax-icon>\n </ax-prefix>\n </ax-button>\n </div>\n </axp-state-message>\n <!-- ----- Background report message state (no live layout preview) ----- -->\n } @else if (vm.isBackgroundReportMode() || vm.isBackgroundQueued()) {\n <!-- ----- Mobile filters and layout selection for background reports ----- -->\n @if (deviceService.isSmall() && !vm.isBackgroundQueued()) {\n <axp-layout-renderer #filtersForm [layout]=\"vm.formDefinition()\" [context]=\"vm.filterContext()\" [look]=\"'fieldset'\"\n (contextChange)=\"handleFiltersChange($event)\" (contextInitiated)=\"handleFiltersInitiated($event)\">\n </axp-layout-renderer>\n @if (vm.availableLayouts().length > 0) {\n <div class=\"mt-4 pt-4 border-t\">\n <div class=\"flex items-center justify-between gap-2 mb-2\">\n <span class=\"text-sm font-medium\">\n {{ t('@report-management:report-generation.components.background-layouts.title') | async }}\n </span>\n </div>\n <p class=\"text-xs opacity-70 mb-3\">\n {{ t('@report-management:report-generation.components.background-layouts.description') | async }}\n </p>\n <div class=\"flex flex-col gap-2\">\n @for (layout of vm.availableLayouts(); track layout.id) {\n <label class=\"flex items-center gap-2 p-2 rounded border cursor-pointer\">\n <ax-check-box\n [ngModel]=\"vm.isBackgroundLayoutSelected(layout.id)\"\n (ngModelChange)=\"handleBackgroundLayoutToggle(layout.id, $event)\"\n ></ax-check-box>\n <ax-icon [icon]=\"layoutPageIcon(layout.icon, layout)\"></ax-icon>\n <span class=\"text-sm\">{{ getLayoutSelectionLabel(layout) | translate | async }}</span>\n </label>\n }\n </div>\n </div>\n }\n }\n @if (vm.isBackgroundQueued()) {\n <axp-state-message icon=\"fa-light fa-clock\"\n [title]=\"'@report-management:report-generation.empty-states.background.queued-title'\"\n [description]=\"'@report-management:report-generation.empty-states.background.queued-description'\">\n </axp-state-message>\n } @else {\n <axp-state-message icon=\"fa-light fa-clock\"\n [title]=\"'@report-management:report-generation.empty-states.background.title'\"\n [description]=\"'@report-management:report-generation.empty-states.background.description'\">\n </axp-state-message>\n }\n } @else {\n <ng-container *ngTemplateOutlet=\"reportDisplay\"></ng-container>\n }\n </axp-page-content>\n</axp-page-layout>\n\n<!-- Desktop: Report Display Area -->\n<ng-template #reportDisplay>\n @if (showReportDisplay()) {\n <!-- Desktop & Mobile: Report Display Area -->\n @if (vm.isTableLayout()) {\n <axp-report-table-view> </axp-report-table-view>\n } @else if (vm.isChartLayout()) {\n <axp-report-chart-view> </axp-report-chart-view>\n } @else if (vm.isPdfLayout()) {\n <axp-report-pdf-view> </axp-report-pdf-view>\n }\n } @else if (vm.reportDefinition()) {\n <!-- Mobile: Show filters -->\n <axp-layout-renderer #filtersForm [layout]=\"vm.formDefinition()\" [context]=\"vm.filterContext()\" [look]=\"'fieldset'\">\n </axp-layout-renderer>\n }\n</ng-template>\n\n<!-- Mobile: Execute Button -->\n@if (deviceService.isSmall() && ((!vm.isBackgroundReportMode() && !vm.hasBeenExecuted()) || (vm.isBackgroundReportMode() && !vm.isBackgroundQueued()))) {\n<axp-page-footer class=\"p-2 border-t\">\n <ax-button class=\"w-full\" [disabled]=\"!vm.canExecute() || vm.areParametersReadonly()\"\n [text]=\"(vm.isBackgroundReportMode()\n ? '@report-management:report-generation.actions.generate-in-background'\n : '@report-management:report-viewer.actions.execute.title') | translate | async\" [color]=\"'primary'\"\n (onClick)=\"execute({ name: 'execute-report' })\">\n <ax-prefix>\n <ax-icon [icon]=\"vm.isBackgroundReportMode() ? 'fa-light fa-clock' : 'fa-light fa-play'\"></ax-icon>\n </ax-prefix>\n </ax-button>\n</axp-page-footer>\n}\n", styles: ["@layer properties;.axp-report-viewer-page{display:flex;height:100%;width:100%;flex-direction:column}.axp-report-viewer-page axp-layout-start-side{height:100%;width:calc(var(--spacing, .25rem) * 80);border-inline-end-style:var(--tw-border-style);border-inline-end-width:1px}@media(width>=1920px){.axp-report-viewer-page axp-layout-start-side{width:calc(var(--spacing, .25rem) * 96)}}.axp-report-viewer-page axp-layout-start-side>axp-layout-header{height:73px;border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.axp-report-viewer-page axp-layout-start-side axp-layout-content{overflow-x:auto;padding:calc(var(--spacing, .25rem) * 4)}.axp-report-viewer-page .__mobile-filters{display:flex;height:100%;flex-direction:column;overflow-y:auto}.axp-report-viewer-page .__mobile-filters .__mobile-filters-content{flex:1}.axp-report-viewer-page .__mobile-filters .__mobile-filters-footer{position:sticky;bottom:0;border-top-style:var(--tw-border-style);border-top-width:1px;background-color:var(--color-lightest);color:var(--color-on-lightest);border-color:var(--color-border-lightest);padding-top:calc(var(--spacing, .25rem) * 2)}.axp-report-viewer-page axp-page-content{display:flex;height:100%;flex-direction:column}.axp-report-viewer-page axp-report-table-view{flex:1;overflow:hidden}@property --tw-border-style{syntax: \"*\"; inherits: false; initial-value: solid;}@layer properties{@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-border-style: solid}}}\n/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1$2.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXCheckBoxModule }, { kind: "component", type: i4.AXCheckBoxComponent, selector: "ax-check-box", inputs: ["disabled", "tabIndex", "readonly", "color", "value", "name", "id", "isLoading", "indeterminate"], outputs: ["onBlur", "onFocus", "valueChange", "onValueChanged"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i2$3.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i2$3.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXLoadingModule }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "directive", type: i1.AXTranslatorDirective, selector: "[translate]" }, { kind: "ngmodule", type: AXBadgeModule }, { kind: "ngmodule", type: AXLoadingDialogModule }, { kind: "component", type:
|
|
4698
|
+
], viewQueries: [{ propertyName: "filtersForm", first: true, predicate: ["filtersForm"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<axp-page-layout *translate=\"let t\">\n <!-- Left Panel: Filters (Always visible for desktop) -->\n @if (showFiltersPanel()) {\n <axp-layout-start-side>\n <axp-layout-header>\n <axp-layout-title>\n {{ t('@report-management:report-viewer.components.filters.title') | async }}\n </axp-layout-title>\n </axp-layout-header>\n <axp-layout-content>\n @if (vm.reportDefinition()) {\n <axp-layout-renderer #filtersForm [layout]=\"vm.formDefinition()\" [context]=\"vm.filterContext()\" [look]=\"'card'\"\n (contextChange)=\"handleFiltersChange($event)\" (contextInitiated)=\"handleFiltersInitiated($event)\">\n </axp-layout-renderer>\n <!-- ----- Background report layout multi-select ----- -->\n @if (vm.isBackgroundReportMode() && !vm.isBackgroundQueued() && vm.availableLayouts().length > 0) {\n <div class=\"mt-4 pt-4 border-t\">\n <div class=\"mb-2\">\n <span class=\"text-sm font-medium\">\n {{ t('@report-management:report-generation.components.background-layouts.title') | async }}\n </span>\n </div>\n <p class=\"text-xs opacity-70 mb-3\">\n {{ t('@report-management:report-generation.components.background-layouts.description') | async }}\n </p>\n <div class=\"flex flex-col gap-2\">\n @for (layout of vm.availableLayouts(); track layout.id) {\n <label class=\"flex items-center gap-2 p-2 rounded border cursor-pointer hover:bg-neutral-50\">\n <ax-check-box\n [ngModel]=\"vm.isBackgroundLayoutSelected(layout.id)\"\n (ngModelChange)=\"handleBackgroundLayoutToggle(layout.id, $event)\"\n ></ax-check-box>\n <ax-icon [icon]=\"layoutPageIcon(layout.icon, layout)\"></ax-icon>\n <span class=\"text-sm\">{{ getLayoutSelectionLabel(layout) | translate | async }}</span>\n </label>\n }\n </div>\n </div>\n }\n }\n </axp-layout-content>\n <axp-layout-footer class=\"p-4 border-t\" *translate=\"let t\">\n @if (vm.hasUnappliedFilters()) {\n <div class=\"w-full warning-lightest-surface mb-2 p-2 rounded border border-warning-200\">\n <div class=\"flex items-center gap-2 text-warning-800\">\n <ax-icon class=\"fa-light fa-exclamation-triangle text-sm\"></ax-icon>\n <span class=\"text-xs\">{{\n t('@report-management:report-viewer.components.filters.messages.warning.unapplied') | async\n }}</span>\n </div>\n </div>\n }\n @if (vm.isBackgroundReportMode() && !vm.hasSelectedBackgroundLayouts() && !vm.isBackgroundQueued()) {\n <div class=\"w-full warning-lightest-surface mb-2 p-2 rounded border border-warning-200\">\n <div class=\"flex items-center gap-2 text-warning-800\">\n <ax-icon class=\"fa-light fa-exclamation-triangle text-sm\"></ax-icon>\n <span class=\"text-xs\">{{\n t('@report-management:report-generation.errors.no-layouts-selected') | async\n }}</span>\n </div>\n </div>\n }\n <ax-button class=\"w-full\" [disabled]=\"vm.isBackgroundReportMode() ? vm.isBackgroundGenerateDisabled() : (!vm.canExecute() || vm.areParametersReadonly())\"\n [text]=\"(vm.isBackgroundReportMode()\n ? t('@report-management:report-generation.actions.generate-in-background')\n : t('@report-management:report-viewer.actions.execute.title')) | async\" [color]=\"'primary'\"\n (onClick)=\"execute({ name: 'execute-report' })\">\n <ax-prefix>\n <ax-icon [icon]=\"vm.isBackgroundReportMode() ? 'fa-light fa-clock' : 'fa-light fa-play'\"></ax-icon>\n </ax-prefix>\n </ax-button>\n <!-- ----- Secondary background generate for choose mode ----- -->\n @if (canGenerateInBackground() && vm.generationMode() === 'choose') {\n <ax-button class=\"w-full mt-2\" [disabled]=\"vm.areParametersReadonly()\"\n [text]=\"t('@report-management:report-generation.actions.generate-in-background') | async\" [color]=\"'default'\"\n (onClick)=\"execute({ name: 'generate-in-background' })\">\n <ax-prefix>\n <ax-icon icon=\"fa-light fa-clock\"></ax-icon>\n </ax-prefix>\n </ax-button>\n }\n </axp-layout-footer>\n </axp-layout-start-side>\n }\n <!-- Main Content: Report Display -->\n <axp-page-content class=\"overflow-auto\">\n @if (vm.isFrozen()) {\n <!-- ----- Frozen run banner ----- -->\n <div class=\"warning-lightest-surface mb-3 p-3 rounded border border-warning-200 text-warning-800 text-sm\">\n {{ t('@report-management:report-generation.banners.frozen') | async }}\n </div>\n }\n @if (vm.hasError()) {\n <!-- Error State -->\n <axp-state-message icon=\"fa-light fa-exclamation-triangle\"\n [title]=\"'@report-management:report-viewer.messages.error.fetch-title'\"\n [description]=\"vm.error() || '@report-management:report-viewer.messages.error.unexpected'\">\n <div slot=\"actions\">\n <ax-button look=\"outline\" color=\"primary\"\n [text]=\"t('@report-management:report-viewer.actions.retry.title') | async\" (onClick)=\"vm.clearError()\">\n <ax-prefix>\n <ax-icon class=\"fa-light fa-refresh\"></ax-icon>\n </ax-prefix>\n </ax-button>\n </div>\n </axp-state-message>\n } @else if (!vm.reportDefinition()) {\n <!-- No Report Selected State -->\n <axp-state-message icon=\"fa-light fa-chart-line\"\n [title]=\"'@report-management:report-viewer.components.report-viewer.empty-states.no-report.title'\"\n [description]=\"'@report-management:report-viewer.components.report-viewer.empty-states.no-report.description'\">\n <div slot=\"actions\">\n <ax-button look=\"outline\" color=\"primary\"\n [text]=\"t('@report-management:report-viewer.actions.browse-reports.title') | async\">\n <ax-prefix>\n <ax-icon class=\"fa-light fa-folder-open\"></ax-icon>\n </ax-prefix>\n </ax-button>\n </div>\n </axp-state-message>\n <!-- ----- Background report message state (no live layout preview) ----- -->\n } @else if (vm.isBackgroundReportMode() && !vm.isFrozen()) {\n <!-- ----- Mobile filters and layout selection for background reports ----- -->\n @if (deviceService.isSmall() && !vm.isBackgroundQueued()) {\n <axp-layout-renderer #filtersForm [layout]=\"vm.formDefinition()\" [context]=\"vm.filterContext()\" [look]=\"'fieldset'\"\n (contextChange)=\"handleFiltersChange($event)\" (contextInitiated)=\"handleFiltersInitiated($event)\">\n </axp-layout-renderer>\n @if (vm.availableLayouts().length > 0) {\n <div class=\"mt-4 pt-4 border-t\">\n <div class=\"flex items-center justify-between gap-2 mb-2\">\n <span class=\"text-sm font-medium\">\n {{ t('@report-management:report-generation.components.background-layouts.title') | async }}\n </span>\n </div>\n <p class=\"text-xs opacity-70 mb-3\">\n {{ t('@report-management:report-generation.components.background-layouts.description') | async }}\n </p>\n <div class=\"flex flex-col gap-2\">\n @for (layout of vm.availableLayouts(); track layout.id) {\n <label class=\"flex items-center gap-2 p-2 rounded border cursor-pointer\">\n <ax-check-box\n [ngModel]=\"vm.isBackgroundLayoutSelected(layout.id)\"\n (ngModelChange)=\"handleBackgroundLayoutToggle(layout.id, $event)\"\n ></ax-check-box>\n <ax-icon [icon]=\"layoutPageIcon(layout.icon, layout)\"></ax-icon>\n <span class=\"text-sm\">{{ getLayoutSelectionLabel(layout) | translate | async }}</span>\n </label>\n }\n </div>\n </div>\n }\n }\n @if (vm.isBackgroundQueued()) {\n <axp-state-message icon=\"fa-light fa-clock\"\n [title]=\"'@report-management:report-generation.empty-states.background.queued-title'\"\n [description]=\"'@report-management:report-generation.empty-states.background.queued-description'\">\n </axp-state-message>\n } @else {\n <axp-state-message icon=\"fa-light fa-clock\"\n [title]=\"'@report-management:report-generation.empty-states.background.title'\"\n [description]=\"'@report-management:report-generation.empty-states.background.description'\">\n </axp-state-message>\n }\n } @else {\n <ng-container *ngTemplateOutlet=\"reportDisplay\"></ng-container>\n }\n </axp-page-content>\n</axp-page-layout>\n\n<!-- Desktop: Report Display Area -->\n<ng-template #reportDisplay>\n @if (showReportDisplay()) {\n <!-- Desktop & Mobile: Report Display Area -->\n @if (vm.isTableLayout()) {\n <axp-report-table-view> </axp-report-table-view>\n } @else if (vm.isChartLayout()) {\n <axp-report-chart-view> </axp-report-chart-view>\n } @else if (vm.isPdfLayout()) {\n <axp-report-pdf-view> </axp-report-pdf-view>\n }\n } @else if (vm.reportDefinition()) {\n <!-- Mobile: Show filters -->\n <axp-layout-renderer #filtersForm [layout]=\"vm.formDefinition()\" [context]=\"vm.filterContext()\" [look]=\"'fieldset'\">\n </axp-layout-renderer>\n }\n</ng-template>\n\n<!-- Mobile: Execute Button -->\n@if (deviceService.isSmall() && ((!vm.isBackgroundReportMode() && !vm.hasBeenExecuted()) || (vm.isBackgroundReportMode() && !vm.isBackgroundQueued()))) {\n<axp-page-footer class=\"p-2 border-t\">\n <ax-button class=\"w-full\" [disabled]=\"vm.isBackgroundReportMode() ? vm.isBackgroundGenerateDisabled() : (!vm.canExecute() || vm.areParametersReadonly())\"\n [text]=\"(vm.isBackgroundReportMode()\n ? '@report-management:report-generation.actions.generate-in-background'\n : '@report-management:report-viewer.actions.execute.title') | translate | async\" [color]=\"'primary'\"\n (onClick)=\"execute({ name: 'execute-report' })\">\n <ax-prefix>\n <ax-icon [icon]=\"vm.isBackgroundReportMode() ? 'fa-light fa-clock' : 'fa-light fa-play'\"></ax-icon>\n </ax-prefix>\n </ax-button>\n</axp-page-footer>\n}\n", styles: ["@layer properties;.axp-report-viewer-page{display:flex;height:100%;width:100%;flex-direction:column}.axp-report-viewer-page axp-layout-start-side{height:100%;width:calc(var(--spacing, .25rem) * 80);border-inline-end-style:var(--tw-border-style);border-inline-end-width:1px}@media(width>=1920px){.axp-report-viewer-page axp-layout-start-side{width:calc(var(--spacing, .25rem) * 96)}}.axp-report-viewer-page axp-layout-start-side>axp-layout-header{height:73px;border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.axp-report-viewer-page axp-layout-start-side axp-layout-content{overflow-x:auto;padding:calc(var(--spacing, .25rem) * 4)}.axp-report-viewer-page .__mobile-filters{display:flex;height:100%;flex-direction:column;overflow-y:auto}.axp-report-viewer-page .__mobile-filters .__mobile-filters-content{flex:1}.axp-report-viewer-page .__mobile-filters .__mobile-filters-footer{position:sticky;bottom:0;border-top-style:var(--tw-border-style);border-top-width:1px;background-color:var(--color-lightest);color:var(--color-on-lightest);border-color:var(--color-border-lightest);padding-top:calc(var(--spacing, .25rem) * 2)}.axp-report-viewer-page axp-page-content{display:flex;height:100%;flex-direction:column}.axp-report-viewer-page axp-report-table-view{flex:1;overflow:hidden}@property --tw-border-style{syntax: \"*\"; inherits: false; initial-value: solid;}@layer properties{@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-border-style: solid}}}\n/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1$2.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXCheckBoxModule }, { kind: "component", type: i4.AXCheckBoxComponent, selector: "ax-check-box", inputs: ["disabled", "tabIndex", "readonly", "color", "value", "name", "id", "isLoading", "indeterminate"], outputs: ["onBlur", "onFocus", "valueChange", "onValueChanged"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i2$3.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i2$3.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXLoadingModule }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "directive", type: i1.AXTranslatorDirective, selector: "[translate]" }, { kind: "ngmodule", type: AXBadgeModule }, { kind: "ngmodule", type: AXLoadingDialogModule }, { kind: "component", type:
|
|
4067
4699
|
//
|
|
4068
4700
|
AXPLayoutRendererComponent, selector: "axp-layout-renderer", inputs: ["layout", "context", "look", "mode"], outputs: ["contextChange", "contextInitiated", "validityChange"] }, { kind: "component", type: AXPPageLayoutComponent, selector: "axp-page-layout" }, { kind: "component", type: AXPThemeLayoutStartSideComponent, selector: "axp-layout-page-start-side, axp-layout-start-side" }, { kind: "component", type: AXPThemeLayoutHeaderComponent, selector: "axp-layout-header" }, { kind: "component", type: AXPThemeLayoutBlockComponent, selector: " axp-page-content, axp-page-footer-container, axp-page-footer, axp-page-header, axp-page-header-container, axp-page-toolbar, axp-layout-content, axp-layout-page-content, axp-layout-sections, axp-layout-body, axp-layout-page-body, axp-layout-prefix, axp-layout-suffix, axp-layout-title-bar, axp-layout-title, axp-layout-title-actions, axp-layout-nav-button, axp-layout-description, axp-layout-breadcrumbs, axp-layout-list-action, " }, { kind: "component", type: AXPReportTableViewComponent, selector: "axp-report-table-view" }, { kind: "component", type: AXPThemeLayoutFooterComponent, selector: "axp-layout-footer, axp-layout-page-footer" }, { kind: "component", type: AXPReportChartViewComponent, selector: "axp-report-chart-view" }, { kind: "component", type: AXPReportPdfViewComponent, selector: "axp-report-pdf-view" }, { kind: "component", type: AXPStateMessageComponent, selector: "axp-state-message", inputs: ["mode", "icon", "title", "description", "titleParams", "descriptionParams", "look"] }, { kind: "pipe", type: i2.AsyncPipe, name: "async" }, { kind: "pipe", type: i1.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
4069
4701
|
}
|
|
@@ -4097,7 +4729,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
|
|
|
4097
4729
|
provide: AXPPageLayoutBase,
|
|
4098
4730
|
useExisting: AXPReportViewerPageComponent,
|
|
4099
4731
|
},
|
|
4100
|
-
], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: { class: 'axp-report-viewer-page' }, template: "<axp-page-layout *translate=\"let t\">\n <!-- Left Panel: Filters (Always visible for desktop) -->\n @if (showFiltersPanel()) {\n <axp-layout-start-side>\n <axp-layout-header>\n <axp-layout-title>\n {{ t('@report-management:report-viewer.components.filters.title') | async }}\n </axp-layout-title>\n </axp-layout-header>\n <axp-layout-content>\n @if (vm.reportDefinition()) {\n <axp-layout-renderer #filtersForm [layout]=\"vm.formDefinition()\" [context]=\"vm.filterContext()\" [look]=\"'card'\"\n (contextChange)=\"handleFiltersChange($event)\" (contextInitiated)=\"handleFiltersInitiated($event)\">\n </axp-layout-renderer>\n <!-- ----- Background report layout multi-select ----- -->\n @if (vm.isBackgroundReportMode() && !vm.isBackgroundQueued() && vm.availableLayouts().length > 0) {\n <div class=\"mt-4 pt-4 border-t\">\n <div class=\"mb-2\">\n <span class=\"text-sm font-medium\">\n {{ t('@report-management:report-generation.components.background-layouts.title') | async }}\n </span>\n </div>\n <p class=\"text-xs opacity-70 mb-3\">\n {{ t('@report-management:report-generation.components.background-layouts.description') | async }}\n </p>\n <div class=\"flex flex-col gap-2\">\n @for (layout of vm.availableLayouts(); track layout.id) {\n <label class=\"flex items-center gap-2 p-2 rounded border cursor-pointer hover:bg-neutral-50\">\n <ax-check-box\n [ngModel]=\"vm.isBackgroundLayoutSelected(layout.id)\"\n (ngModelChange)=\"handleBackgroundLayoutToggle(layout.id, $event)\"\n ></ax-check-box>\n <ax-icon [icon]=\"layoutPageIcon(layout.icon, layout)\"></ax-icon>\n <span class=\"text-sm\">{{ getLayoutSelectionLabel(layout) | translate | async }}</span>\n </label>\n }\n </div>\n </div>\n }\n }\n </axp-layout-content>\n <axp-layout-footer class=\"p-4 border-t\" *translate=\"let t\">\n @if (vm.hasUnappliedFilters()) {\n <div class=\"w-full warning-lightest-surface mb-2 p-2 rounded border border-warning-200\">\n <div class=\"flex items-center gap-2 text-warning-800\">\n <ax-icon class=\"fa-light fa-exclamation-triangle text-sm\"></ax-icon>\n <span class=\"text-xs\">{{\n t('@report-management:report-viewer.components.filters.messages.warning.unapplied') | async\n }}</span>\n </div>\n </div>\n }\n @if (vm.isBackgroundReportMode() && !vm.hasSelectedBackgroundLayouts() && !vm.isBackgroundQueued()) {\n <div class=\"w-full warning-lightest-surface mb-2 p-2 rounded border border-warning-200\">\n <div class=\"flex items-center gap-2 text-warning-800\">\n <ax-icon class=\"fa-light fa-exclamation-triangle text-sm\"></ax-icon>\n <span class=\"text-xs\">{{\n t('@report-management:report-generation.errors.no-layouts-selected') | async\n }}</span>\n </div>\n </div>\n }\n <ax-button class=\"w-full\" [disabled]=\"!vm.canExecute() || vm.areParametersReadonly() || vm.isBackgroundQueued()\"\n [text]=\"(vm.isBackgroundReportMode()\n ? t('@report-management:report-generation.actions.generate-in-background')\n : t('@report-management:report-viewer.actions.execute.title')) | async\" [color]=\"'primary'\"\n (onClick)=\"execute({ name: 'execute-report' })\">\n <ax-prefix>\n <ax-icon [icon]=\"vm.isBackgroundReportMode() ? 'fa-light fa-clock' : 'fa-light fa-play'\"></ax-icon>\n </ax-prefix>\n </ax-button>\n <!-- ----- Secondary background generate for choose mode ----- -->\n @if (canGenerateInBackground() && vm.generationMode() === 'choose') {\n <ax-button class=\"w-full mt-2\" [disabled]=\"vm.areParametersReadonly()\"\n [text]=\"t('@report-management:report-generation.actions.generate-in-background') | async\" [color]=\"'default'\"\n (onClick)=\"execute({ name: 'generate-in-background' })\">\n <ax-prefix>\n <ax-icon icon=\"fa-light fa-clock\"></ax-icon>\n </ax-prefix>\n </ax-button>\n }\n </axp-layout-footer>\n </axp-layout-start-side>\n }\n <!-- Main Content: Report Display -->\n <axp-page-content class=\"overflow-auto\">\n @if (vm.isFrozen()) {\n <!-- ----- Frozen run banner ----- -->\n <div class=\"warning-lightest-surface mb-3 p-3 rounded border border-warning-200 text-warning-800 text-sm\">\n {{ t('@report-management:report-generation.banners.frozen') | async }}\n </div>\n }\n @if (vm.hasError()) {\n <!-- Error State -->\n <axp-state-message icon=\"fa-light fa-exclamation-triangle\"\n [title]=\"'@report-management:report-viewer.messages.error.fetch-title'\"\n [description]=\"vm.error() || '@report-management:report-viewer.messages.error.unexpected'\">\n <div slot=\"actions\">\n <ax-button look=\"outline\" color=\"primary\"\n [text]=\"t('@report-management:report-viewer.actions.retry.title') | async\" (onClick)=\"vm.clearError()\">\n <ax-prefix>\n <ax-icon class=\"fa-light fa-refresh\"></ax-icon>\n </ax-prefix>\n </ax-button>\n </div>\n </axp-state-message>\n } @else if (!vm.reportDefinition()) {\n <!-- No Report Selected State -->\n <axp-state-message icon=\"fa-light fa-chart-line\"\n [title]=\"'@report-management:report-viewer.components.report-viewer.empty-states.no-report.title'\"\n [description]=\"'@report-management:report-viewer.components.report-viewer.empty-states.no-report.description'\">\n <div slot=\"actions\">\n <ax-button look=\"outline\" color=\"primary\"\n [text]=\"t('@report-management:report-viewer.actions.browse-reports.title') | async\">\n <ax-prefix>\n <ax-icon class=\"fa-light fa-folder-open\"></ax-icon>\n </ax-prefix>\n </ax-button>\n </div>\n </axp-state-message>\n <!-- ----- Background report message state (no live layout preview) ----- -->\n } @else if (vm.isBackgroundReportMode() || vm.isBackgroundQueued()) {\n <!-- ----- Mobile filters and layout selection for background reports ----- -->\n @if (deviceService.isSmall() && !vm.isBackgroundQueued()) {\n <axp-layout-renderer #filtersForm [layout]=\"vm.formDefinition()\" [context]=\"vm.filterContext()\" [look]=\"'fieldset'\"\n (contextChange)=\"handleFiltersChange($event)\" (contextInitiated)=\"handleFiltersInitiated($event)\">\n </axp-layout-renderer>\n @if (vm.availableLayouts().length > 0) {\n <div class=\"mt-4 pt-4 border-t\">\n <div class=\"flex items-center justify-between gap-2 mb-2\">\n <span class=\"text-sm font-medium\">\n {{ t('@report-management:report-generation.components.background-layouts.title') | async }}\n </span>\n </div>\n <p class=\"text-xs opacity-70 mb-3\">\n {{ t('@report-management:report-generation.components.background-layouts.description') | async }}\n </p>\n <div class=\"flex flex-col gap-2\">\n @for (layout of vm.availableLayouts(); track layout.id) {\n <label class=\"flex items-center gap-2 p-2 rounded border cursor-pointer\">\n <ax-check-box\n [ngModel]=\"vm.isBackgroundLayoutSelected(layout.id)\"\n (ngModelChange)=\"handleBackgroundLayoutToggle(layout.id, $event)\"\n ></ax-check-box>\n <ax-icon [icon]=\"layoutPageIcon(layout.icon, layout)\"></ax-icon>\n <span class=\"text-sm\">{{ getLayoutSelectionLabel(layout) | translate | async }}</span>\n </label>\n }\n </div>\n </div>\n }\n }\n @if (vm.isBackgroundQueued()) {\n <axp-state-message icon=\"fa-light fa-clock\"\n [title]=\"'@report-management:report-generation.empty-states.background.queued-title'\"\n [description]=\"'@report-management:report-generation.empty-states.background.queued-description'\">\n </axp-state-message>\n } @else {\n <axp-state-message icon=\"fa-light fa-clock\"\n [title]=\"'@report-management:report-generation.empty-states.background.title'\"\n [description]=\"'@report-management:report-generation.empty-states.background.description'\">\n </axp-state-message>\n }\n } @else {\n <ng-container *ngTemplateOutlet=\"reportDisplay\"></ng-container>\n }\n </axp-page-content>\n</axp-page-layout>\n\n<!-- Desktop: Report Display Area -->\n<ng-template #reportDisplay>\n @if (showReportDisplay()) {\n <!-- Desktop & Mobile: Report Display Area -->\n @if (vm.isTableLayout()) {\n <axp-report-table-view> </axp-report-table-view>\n } @else if (vm.isChartLayout()) {\n <axp-report-chart-view> </axp-report-chart-view>\n } @else if (vm.isPdfLayout()) {\n <axp-report-pdf-view> </axp-report-pdf-view>\n }\n } @else if (vm.reportDefinition()) {\n <!-- Mobile: Show filters -->\n <axp-layout-renderer #filtersForm [layout]=\"vm.formDefinition()\" [context]=\"vm.filterContext()\" [look]=\"'fieldset'\">\n </axp-layout-renderer>\n }\n</ng-template>\n\n<!-- Mobile: Execute Button -->\n@if (deviceService.isSmall() && ((!vm.isBackgroundReportMode() && !vm.hasBeenExecuted()) || (vm.isBackgroundReportMode() && !vm.isBackgroundQueued()))) {\n<axp-page-footer class=\"p-2 border-t\">\n <ax-button class=\"w-full\" [disabled]=\"!vm.canExecute() || vm.areParametersReadonly()\"\n [text]=\"(vm.isBackgroundReportMode()\n ? '@report-management:report-generation.actions.generate-in-background'\n : '@report-management:report-viewer.actions.execute.title') | translate | async\" [color]=\"'primary'\"\n (onClick)=\"execute({ name: 'execute-report' })\">\n <ax-prefix>\n <ax-icon [icon]=\"vm.isBackgroundReportMode() ? 'fa-light fa-clock' : 'fa-light fa-play'\"></ax-icon>\n </ax-prefix>\n </ax-button>\n</axp-page-footer>\n}\n", styles: ["@layer properties;.axp-report-viewer-page{display:flex;height:100%;width:100%;flex-direction:column}.axp-report-viewer-page axp-layout-start-side{height:100%;width:calc(var(--spacing, .25rem) * 80);border-inline-end-style:var(--tw-border-style);border-inline-end-width:1px}@media(width>=1920px){.axp-report-viewer-page axp-layout-start-side{width:calc(var(--spacing, .25rem) * 96)}}.axp-report-viewer-page axp-layout-start-side>axp-layout-header{height:73px;border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.axp-report-viewer-page axp-layout-start-side axp-layout-content{overflow-x:auto;padding:calc(var(--spacing, .25rem) * 4)}.axp-report-viewer-page .__mobile-filters{display:flex;height:100%;flex-direction:column;overflow-y:auto}.axp-report-viewer-page .__mobile-filters .__mobile-filters-content{flex:1}.axp-report-viewer-page .__mobile-filters .__mobile-filters-footer{position:sticky;bottom:0;border-top-style:var(--tw-border-style);border-top-width:1px;background-color:var(--color-lightest);color:var(--color-on-lightest);border-color:var(--color-border-lightest);padding-top:calc(var(--spacing, .25rem) * 2)}.axp-report-viewer-page axp-page-content{display:flex;height:100%;flex-direction:column}.axp-report-viewer-page axp-report-table-view{flex:1;overflow:hidden}@property --tw-border-style{syntax: \"*\"; inherits: false; initial-value: solid;}@layer properties{@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-border-style: solid}}}\n/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\n"] }]
|
|
4732
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: { class: 'axp-report-viewer-page' }, template: "<axp-page-layout *translate=\"let t\">\n <!-- Left Panel: Filters (Always visible for desktop) -->\n @if (showFiltersPanel()) {\n <axp-layout-start-side>\n <axp-layout-header>\n <axp-layout-title>\n {{ t('@report-management:report-viewer.components.filters.title') | async }}\n </axp-layout-title>\n </axp-layout-header>\n <axp-layout-content>\n @if (vm.reportDefinition()) {\n <axp-layout-renderer #filtersForm [layout]=\"vm.formDefinition()\" [context]=\"vm.filterContext()\" [look]=\"'card'\"\n (contextChange)=\"handleFiltersChange($event)\" (contextInitiated)=\"handleFiltersInitiated($event)\">\n </axp-layout-renderer>\n <!-- ----- Background report layout multi-select ----- -->\n @if (vm.isBackgroundReportMode() && !vm.isBackgroundQueued() && vm.availableLayouts().length > 0) {\n <div class=\"mt-4 pt-4 border-t\">\n <div class=\"mb-2\">\n <span class=\"text-sm font-medium\">\n {{ t('@report-management:report-generation.components.background-layouts.title') | async }}\n </span>\n </div>\n <p class=\"text-xs opacity-70 mb-3\">\n {{ t('@report-management:report-generation.components.background-layouts.description') | async }}\n </p>\n <div class=\"flex flex-col gap-2\">\n @for (layout of vm.availableLayouts(); track layout.id) {\n <label class=\"flex items-center gap-2 p-2 rounded border cursor-pointer hover:bg-neutral-50\">\n <ax-check-box\n [ngModel]=\"vm.isBackgroundLayoutSelected(layout.id)\"\n (ngModelChange)=\"handleBackgroundLayoutToggle(layout.id, $event)\"\n ></ax-check-box>\n <ax-icon [icon]=\"layoutPageIcon(layout.icon, layout)\"></ax-icon>\n <span class=\"text-sm\">{{ getLayoutSelectionLabel(layout) | translate | async }}</span>\n </label>\n }\n </div>\n </div>\n }\n }\n </axp-layout-content>\n <axp-layout-footer class=\"p-4 border-t\" *translate=\"let t\">\n @if (vm.hasUnappliedFilters()) {\n <div class=\"w-full warning-lightest-surface mb-2 p-2 rounded border border-warning-200\">\n <div class=\"flex items-center gap-2 text-warning-800\">\n <ax-icon class=\"fa-light fa-exclamation-triangle text-sm\"></ax-icon>\n <span class=\"text-xs\">{{\n t('@report-management:report-viewer.components.filters.messages.warning.unapplied') | async\n }}</span>\n </div>\n </div>\n }\n @if (vm.isBackgroundReportMode() && !vm.hasSelectedBackgroundLayouts() && !vm.isBackgroundQueued()) {\n <div class=\"w-full warning-lightest-surface mb-2 p-2 rounded border border-warning-200\">\n <div class=\"flex items-center gap-2 text-warning-800\">\n <ax-icon class=\"fa-light fa-exclamation-triangle text-sm\"></ax-icon>\n <span class=\"text-xs\">{{\n t('@report-management:report-generation.errors.no-layouts-selected') | async\n }}</span>\n </div>\n </div>\n }\n <ax-button class=\"w-full\" [disabled]=\"vm.isBackgroundReportMode() ? vm.isBackgroundGenerateDisabled() : (!vm.canExecute() || vm.areParametersReadonly())\"\n [text]=\"(vm.isBackgroundReportMode()\n ? t('@report-management:report-generation.actions.generate-in-background')\n : t('@report-management:report-viewer.actions.execute.title')) | async\" [color]=\"'primary'\"\n (onClick)=\"execute({ name: 'execute-report' })\">\n <ax-prefix>\n <ax-icon [icon]=\"vm.isBackgroundReportMode() ? 'fa-light fa-clock' : 'fa-light fa-play'\"></ax-icon>\n </ax-prefix>\n </ax-button>\n <!-- ----- Secondary background generate for choose mode ----- -->\n @if (canGenerateInBackground() && vm.generationMode() === 'choose') {\n <ax-button class=\"w-full mt-2\" [disabled]=\"vm.areParametersReadonly()\"\n [text]=\"t('@report-management:report-generation.actions.generate-in-background') | async\" [color]=\"'default'\"\n (onClick)=\"execute({ name: 'generate-in-background' })\">\n <ax-prefix>\n <ax-icon icon=\"fa-light fa-clock\"></ax-icon>\n </ax-prefix>\n </ax-button>\n }\n </axp-layout-footer>\n </axp-layout-start-side>\n }\n <!-- Main Content: Report Display -->\n <axp-page-content class=\"overflow-auto\">\n @if (vm.isFrozen()) {\n <!-- ----- Frozen run banner ----- -->\n <div class=\"warning-lightest-surface mb-3 p-3 rounded border border-warning-200 text-warning-800 text-sm\">\n {{ t('@report-management:report-generation.banners.frozen') | async }}\n </div>\n }\n @if (vm.hasError()) {\n <!-- Error State -->\n <axp-state-message icon=\"fa-light fa-exclamation-triangle\"\n [title]=\"'@report-management:report-viewer.messages.error.fetch-title'\"\n [description]=\"vm.error() || '@report-management:report-viewer.messages.error.unexpected'\">\n <div slot=\"actions\">\n <ax-button look=\"outline\" color=\"primary\"\n [text]=\"t('@report-management:report-viewer.actions.retry.title') | async\" (onClick)=\"vm.clearError()\">\n <ax-prefix>\n <ax-icon class=\"fa-light fa-refresh\"></ax-icon>\n </ax-prefix>\n </ax-button>\n </div>\n </axp-state-message>\n } @else if (!vm.reportDefinition()) {\n <!-- No Report Selected State -->\n <axp-state-message icon=\"fa-light fa-chart-line\"\n [title]=\"'@report-management:report-viewer.components.report-viewer.empty-states.no-report.title'\"\n [description]=\"'@report-management:report-viewer.components.report-viewer.empty-states.no-report.description'\">\n <div slot=\"actions\">\n <ax-button look=\"outline\" color=\"primary\"\n [text]=\"t('@report-management:report-viewer.actions.browse-reports.title') | async\">\n <ax-prefix>\n <ax-icon class=\"fa-light fa-folder-open\"></ax-icon>\n </ax-prefix>\n </ax-button>\n </div>\n </axp-state-message>\n <!-- ----- Background report message state (no live layout preview) ----- -->\n } @else if (vm.isBackgroundReportMode() && !vm.isFrozen()) {\n <!-- ----- Mobile filters and layout selection for background reports ----- -->\n @if (deviceService.isSmall() && !vm.isBackgroundQueued()) {\n <axp-layout-renderer #filtersForm [layout]=\"vm.formDefinition()\" [context]=\"vm.filterContext()\" [look]=\"'fieldset'\"\n (contextChange)=\"handleFiltersChange($event)\" (contextInitiated)=\"handleFiltersInitiated($event)\">\n </axp-layout-renderer>\n @if (vm.availableLayouts().length > 0) {\n <div class=\"mt-4 pt-4 border-t\">\n <div class=\"flex items-center justify-between gap-2 mb-2\">\n <span class=\"text-sm font-medium\">\n {{ t('@report-management:report-generation.components.background-layouts.title') | async }}\n </span>\n </div>\n <p class=\"text-xs opacity-70 mb-3\">\n {{ t('@report-management:report-generation.components.background-layouts.description') | async }}\n </p>\n <div class=\"flex flex-col gap-2\">\n @for (layout of vm.availableLayouts(); track layout.id) {\n <label class=\"flex items-center gap-2 p-2 rounded border cursor-pointer\">\n <ax-check-box\n [ngModel]=\"vm.isBackgroundLayoutSelected(layout.id)\"\n (ngModelChange)=\"handleBackgroundLayoutToggle(layout.id, $event)\"\n ></ax-check-box>\n <ax-icon [icon]=\"layoutPageIcon(layout.icon, layout)\"></ax-icon>\n <span class=\"text-sm\">{{ getLayoutSelectionLabel(layout) | translate | async }}</span>\n </label>\n }\n </div>\n </div>\n }\n }\n @if (vm.isBackgroundQueued()) {\n <axp-state-message icon=\"fa-light fa-clock\"\n [title]=\"'@report-management:report-generation.empty-states.background.queued-title'\"\n [description]=\"'@report-management:report-generation.empty-states.background.queued-description'\">\n </axp-state-message>\n } @else {\n <axp-state-message icon=\"fa-light fa-clock\"\n [title]=\"'@report-management:report-generation.empty-states.background.title'\"\n [description]=\"'@report-management:report-generation.empty-states.background.description'\">\n </axp-state-message>\n }\n } @else {\n <ng-container *ngTemplateOutlet=\"reportDisplay\"></ng-container>\n }\n </axp-page-content>\n</axp-page-layout>\n\n<!-- Desktop: Report Display Area -->\n<ng-template #reportDisplay>\n @if (showReportDisplay()) {\n <!-- Desktop & Mobile: Report Display Area -->\n @if (vm.isTableLayout()) {\n <axp-report-table-view> </axp-report-table-view>\n } @else if (vm.isChartLayout()) {\n <axp-report-chart-view> </axp-report-chart-view>\n } @else if (vm.isPdfLayout()) {\n <axp-report-pdf-view> </axp-report-pdf-view>\n }\n } @else if (vm.reportDefinition()) {\n <!-- Mobile: Show filters -->\n <axp-layout-renderer #filtersForm [layout]=\"vm.formDefinition()\" [context]=\"vm.filterContext()\" [look]=\"'fieldset'\">\n </axp-layout-renderer>\n }\n</ng-template>\n\n<!-- Mobile: Execute Button -->\n@if (deviceService.isSmall() && ((!vm.isBackgroundReportMode() && !vm.hasBeenExecuted()) || (vm.isBackgroundReportMode() && !vm.isBackgroundQueued()))) {\n<axp-page-footer class=\"p-2 border-t\">\n <ax-button class=\"w-full\" [disabled]=\"vm.isBackgroundReportMode() ? vm.isBackgroundGenerateDisabled() : (!vm.canExecute() || vm.areParametersReadonly())\"\n [text]=\"(vm.isBackgroundReportMode()\n ? '@report-management:report-generation.actions.generate-in-background'\n : '@report-management:report-viewer.actions.execute.title') | translate | async\" [color]=\"'primary'\"\n (onClick)=\"execute({ name: 'execute-report' })\">\n <ax-prefix>\n <ax-icon [icon]=\"vm.isBackgroundReportMode() ? 'fa-light fa-clock' : 'fa-light fa-play'\"></ax-icon>\n </ax-prefix>\n </ax-button>\n</axp-page-footer>\n}\n", styles: ["@layer properties;.axp-report-viewer-page{display:flex;height:100%;width:100%;flex-direction:column}.axp-report-viewer-page axp-layout-start-side{height:100%;width:calc(var(--spacing, .25rem) * 80);border-inline-end-style:var(--tw-border-style);border-inline-end-width:1px}@media(width>=1920px){.axp-report-viewer-page axp-layout-start-side{width:calc(var(--spacing, .25rem) * 96)}}.axp-report-viewer-page axp-layout-start-side>axp-layout-header{height:73px;border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.axp-report-viewer-page axp-layout-start-side axp-layout-content{overflow-x:auto;padding:calc(var(--spacing, .25rem) * 4)}.axp-report-viewer-page .__mobile-filters{display:flex;height:100%;flex-direction:column;overflow-y:auto}.axp-report-viewer-page .__mobile-filters .__mobile-filters-content{flex:1}.axp-report-viewer-page .__mobile-filters .__mobile-filters-footer{position:sticky;bottom:0;border-top-style:var(--tw-border-style);border-top-width:1px;background-color:var(--color-lightest);color:var(--color-on-lightest);border-color:var(--color-border-lightest);padding-top:calc(var(--spacing, .25rem) * 2)}.axp-report-viewer-page axp-page-content{display:flex;height:100%;flex-direction:column}.axp-report-viewer-page axp-report-table-view{flex:1;overflow:hidden}@property --tw-border-style{syntax: \"*\"; inherits: false; initial-value: solid;}@layer properties{@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-border-style: solid}}}\n/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\n"] }]
|
|
4101
4733
|
}], ctorParameters: () => [], propDecorators: { reportId: [{ type: i0.Input, args: [{ isSignal: true, alias: "reportId", required: false }] }], reportParameters: [{ type: i0.Input, args: [{ isSignal: true, alias: "reportParameters", required: false }] }], filtersForm: [{ type: i0.ViewChild, args: ['filtersForm', { isSignal: true }] }] } });
|
|
4102
4734
|
|
|
4103
4735
|
var reportViewerPage_component = /*#__PURE__*/Object.freeze({
|
|
@@ -4229,4 +4861,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
|
|
|
4229
4861
|
*/
|
|
4230
4862
|
|
|
4231
4863
|
export { AXPReportViewerViewModel as A, mapEntityBindingParameters as B, queryResultToChartSeries as C, queryResultToPdfSource as D, ENTITY_REPORTS_PAGE_COMPONENT_KEY as E, resolveReportParameterValues as F, resolveTodayDateRange as G, toReportDateRangeFilterValue as H, OPEN_REPORT_IN_POPUP_COMMAND$1 as O, AXPOpenReportViewerCommand as a, resolveReportFilterDefaultValue as b, reportLayoutTitleKey as c, AXPReportTableViewComponent as d, AXPReportChartViewComponent as e, AXPReportPdfViewComponent as f, AXPReportViewerService as g, bindingShowsOnPage as h, isDistinctLayoutTitle as i, buildOpenInPopupCommandOptions as j, resolveBindingTitle as k, resolveBindingDescription as l, AXBarChartReportMapper as m, AXLineChartReportMapper as n, AXMPermissionDefinitionProvider as o, AXMReportManagementModule as p, AXPOpenReportInPopupCommand as q, reportLayoutPageIcon as r, AXPReportBarChartViewComponent as s, AXPReportViewerPageComponent as t, AXPieChartReportMapper as u, collectReportParameterDefaults as v, convertContextDataToFilterClause as w, flattenReportParametersToQueryParams as x, formatReportDateOnly as y, isReportDateRangeObject as z };
|
|
4232
|
-
//# sourceMappingURL=acorex-platform-module-report-management-client-acorex-platform-module-report-management-client-
|
|
4864
|
+
//# sourceMappingURL=acorex-platform-module-report-management-client-acorex-platform-module-report-management-client-DENcGULA.mjs.map
|