@acorex-platform/module-report-management-client 0.0.38 → 0.0.48

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/fesm2022/acorex-platform-module-report-management-client-acorex-platform-module-report-management-client-D5dCG62j.mjs +1545 -0
  2. package/fesm2022/acorex-platform-module-report-management-client-acorex-platform-module-report-management-client-D5dCG62j.mjs.map +1 -0
  3. package/fesm2022/acorex-platform-module-report-management-client-contracts-entities-query-snapshot-policy.mjs +14 -0
  4. package/fesm2022/acorex-platform-module-report-management-client-contracts-entities-query-snapshot-policy.mjs.map +1 -1
  5. package/fesm2022/acorex-platform-module-report-management-client-contracts-entities-query-snapshot.mjs +14 -0
  6. package/fesm2022/acorex-platform-module-report-management-client-contracts-entities-query-snapshot.mjs.map +1 -1
  7. package/fesm2022/acorex-platform-module-report-management-client-contracts-entities-report-category.mjs +13 -0
  8. package/fesm2022/acorex-platform-module-report-management-client-contracts-entities-report-category.mjs.map +1 -1
  9. package/fesm2022/acorex-platform-module-report-management-client-contracts-entities-report-generation-request.mjs +14 -0
  10. package/fesm2022/acorex-platform-module-report-management-client-contracts-entities-report-generation-request.mjs.map +1 -1
  11. package/fesm2022/acorex-platform-module-report-management-client-contracts-entities-report.mjs +14 -0
  12. package/fesm2022/acorex-platform-module-report-management-client-contracts-entities-report.mjs.map +1 -1
  13. package/fesm2022/{acorex-platform-module-report-management-client-contracts-entity-catalog-acorex-platform-module-report-management-client-contracts-entity-catalog-CgrfJQLl.mjs → acorex-platform-module-report-management-client-contracts-entity-catalog-acorex-platform-module-report-management-client-contracts-entity-catalog-CboBAIna.mjs} +6 -6
  14. package/fesm2022/{acorex-platform-module-report-management-client-contracts-entity-catalog-acorex-platform-module-report-management-client-contracts-entity-catalog-CgrfJQLl.mjs.map → acorex-platform-module-report-management-client-contracts-entity-catalog-acorex-platform-module-report-management-client-contracts-entity-catalog-CboBAIna.mjs.map} +1 -1
  15. package/fesm2022/{acorex-platform-module-report-management-client-contracts-entity-catalog-query-snapshot-policy.entity-D50GUBH6.mjs → acorex-platform-module-report-management-client-contracts-entity-catalog-query-snapshot-policy.entity-BUY06Dz0.mjs} +16 -2
  16. package/fesm2022/acorex-platform-module-report-management-client-contracts-entity-catalog-query-snapshot-policy.entity-BUY06Dz0.mjs.map +1 -0
  17. package/fesm2022/{acorex-platform-module-report-management-client-contracts-entity-catalog-query-snapshot.entity-DuR9ZuN2.mjs → acorex-platform-module-report-management-client-contracts-entity-catalog-query-snapshot.entity-CnnX3xZt.mjs} +16 -2
  18. package/fesm2022/acorex-platform-module-report-management-client-contracts-entity-catalog-query-snapshot.entity-CnnX3xZt.mjs.map +1 -0
  19. package/fesm2022/{acorex-platform-module-report-management-client-contracts-entity-catalog-report-category.entity-Dc4uvjsG.mjs → acorex-platform-module-report-management-client-contracts-entity-catalog-report-category.entity-BQFdNXAm.mjs} +15 -2
  20. package/fesm2022/acorex-platform-module-report-management-client-contracts-entity-catalog-report-category.entity-BQFdNXAm.mjs.map +1 -0
  21. package/fesm2022/{acorex-platform-module-report-management-client-contracts-entity-catalog-report-generation-request.entity-mJUQuk89.mjs → acorex-platform-module-report-management-client-contracts-entity-catalog-report-generation-request.entity-D381cWLE.mjs} +16 -2
  22. package/fesm2022/acorex-platform-module-report-management-client-contracts-entity-catalog-report-generation-request.entity-D381cWLE.mjs.map +1 -0
  23. package/fesm2022/{acorex-platform-module-report-management-client-contracts-entity-catalog-report.entity-CMDFRHeK.mjs → acorex-platform-module-report-management-client-contracts-entity-catalog-report.entity-Bwui0M8X.mjs} +16 -2
  24. package/fesm2022/acorex-platform-module-report-management-client-contracts-entity-catalog-report.entity-Bwui0M8X.mjs.map +1 -0
  25. package/fesm2022/acorex-platform-module-report-management-client-contracts-entity-catalog.mjs +1 -1
  26. package/fesm2022/acorex-platform-module-report-management-client-contracts.mjs +21 -1
  27. package/fesm2022/acorex-platform-module-report-management-client-contracts.mjs.map +1 -1
  28. package/fesm2022/{acorex-platform-module-report-management-client-entity-reports-page-component.provider-B0dU2K_E.mjs → acorex-platform-module-report-management-client-entity-reports-page-component.provider-0eSOzb0y.mjs} +3 -3
  29. package/fesm2022/{acorex-platform-module-report-management-client-entity-reports-page-component.provider-B0dU2K_E.mjs.map → acorex-platform-module-report-management-client-entity-reports-page-component.provider-0eSOzb0y.mjs.map} +1 -1
  30. package/fesm2022/{acorex-platform-module-report-management-client-entity-reports-page.component-D4SAGGn-.mjs → acorex-platform-module-report-management-client-entity-reports-page.component-CHBZbbaH.mjs} +4 -4
  31. package/fesm2022/{acorex-platform-module-report-management-client-entity-reports-page.component-D4SAGGn-.mjs.map → acorex-platform-module-report-management-client-entity-reports-page.component-CHBZbbaH.mjs.map} +1 -1
  32. package/fesm2022/acorex-platform-module-report-management-client-report-layout-switcher.util-BGhHRYfe.mjs +2266 -0
  33. package/fesm2022/acorex-platform-module-report-management-client-report-layout-switcher.util-BGhHRYfe.mjs.map +1 -0
  34. package/fesm2022/{acorex-platform-module-report-management-client-report-popup-viewer.component-Dg3IxjGy.mjs → acorex-platform-module-report-management-client-report-popup-viewer.component-BJq1BeUz.mjs} +5 -4
  35. package/fesm2022/{acorex-platform-module-report-management-client-report-popup-viewer.component-Dg3IxjGy.mjs.map → acorex-platform-module-report-management-client-report-popup-viewer.component-BJq1BeUz.mjs.map} +1 -1
  36. package/fesm2022/acorex-platform-module-report-management-client-report-viewer-page.component-YUdzA4B9.mjs +934 -0
  37. package/fesm2022/acorex-platform-module-report-management-client-report-viewer-page.component-YUdzA4B9.mjs.map +1 -0
  38. package/fesm2022/acorex-platform-module-report-management-client.mjs +1 -1
  39. package/package.json +1 -1
  40. package/types/acorex-platform-module-report-management-client-contracts.d.ts +8 -2
  41. package/types/acorex-platform-module-report-management-client.d.ts +16 -831
  42. package/fesm2022/acorex-platform-module-report-management-client-acorex-platform-module-report-management-client-DUdUNlnp.mjs +0 -4864
  43. package/fesm2022/acorex-platform-module-report-management-client-acorex-platform-module-report-management-client-DUdUNlnp.mjs.map +0 -1
  44. package/fesm2022/acorex-platform-module-report-management-client-contracts-entity-catalog-query-snapshot-policy.entity-D50GUBH6.mjs.map +0 -1
  45. package/fesm2022/acorex-platform-module-report-management-client-contracts-entity-catalog-query-snapshot.entity-DuR9ZuN2.mjs.map +0 -1
  46. package/fesm2022/acorex-platform-module-report-management-client-contracts-entity-catalog-report-category.entity-Dc4uvjsG.mjs.map +0 -1
  47. package/fesm2022/acorex-platform-module-report-management-client-contracts-entity-catalog-report-generation-request.entity-mJUQuk89.mjs.map +0 -1
  48. package/fesm2022/acorex-platform-module-report-management-client-contracts-entity-catalog-report.entity-CMDFRHeK.mjs.map +0 -1
@@ -0,0 +1,934 @@
1
+ import { runtimeQueryPayloadData, resolveMultiLanguageString } from '@acorex-platform/framework-shared/core';
2
+ import { AXBadgeModule } from '@acorex/components/badge';
3
+ import * as i1 from '@acorex/components/button';
4
+ import { AXButtonModule } from '@acorex/components/button';
5
+ import * as i4 from '@acorex/components/check-box';
6
+ import { AXCheckBoxModule } from '@acorex/components/check-box';
7
+ import * as i2$2 from '@acorex/components/decorators';
8
+ import { AXDecoratorModule } from '@acorex/components/decorators';
9
+ import { AXLoadingModule } from '@acorex/components/loading';
10
+ import { AXLoadingDialogService, AXLoadingDialogModule } from '@acorex/components/loading-dialog';
11
+ import * as i4$1 from '@acorex/core/translation';
12
+ import { AXTranslationModule } from '@acorex/core/translation';
13
+ import { AXUnsubscriber } from '@acorex/core/utils';
14
+ import { AXPDeviceService } from '@acorex-platform/framework-client/core';
15
+ import { AXPLayoutRendererComponent } from '@acorex-platform/framework-client/layout/builder';
16
+ import { AXPThemeLayoutStartSideComponent, AXPThemeLayoutHeaderComponent, AXPThemeLayoutBlockComponent, AXPThemeLayoutFooterComponent, AXPStateMessageComponent } from '@acorex-platform/framework-client/layout/components';
17
+ import { AXPEntityService } from '@acorex-platform/framework-client/layout/entity';
18
+ import { AXPPageLayoutBaseComponent, AXPPageLayoutComponent, AXPPageLayoutBase } from '@acorex-platform/framework-client/layout/views';
19
+ import { AXPLayoutThemeService } from '@acorex-platform/framework-client/themes/shared';
20
+ import { RootConfig, AXPReportManagementFeatureKeys } from '@acorex-platform/module-report-management-client/contracts';
21
+ import * as i2 from '@angular/common';
22
+ import { CommonModule } from '@angular/common';
23
+ import * as i0 from '@angular/core';
24
+ import { inject, DestroyRef, input, viewChild, effect, untracked, ViewEncapsulation, ChangeDetectionStrategy, Component } from '@angular/core';
25
+ import * as i2$1 from '@angular/forms';
26
+ import { FormsModule } from '@angular/forms';
27
+ import { ActivatedRoute, NavigationStart } from '@angular/router';
28
+ import { combineLatest } from 'rxjs';
29
+ import { filter } from 'rxjs/operators';
30
+ import { A as AXPReportViewerViewModel, r as reportLayoutPageIcon, i as isDistinctLayoutTitle, a as reportLayoutTitleKey, b as reportLayoutGlyph, c as AXPReportTableViewComponent, d as AXPReportChartViewComponent, e as AXPReportPdfViewComponent } from './acorex-platform-module-report-management-client-report-layout-switcher.util-BGhHRYfe.mjs';
31
+ import { A as AXPReportViewerService, r as resolveReportFilterDefaultValue, q as queryResultToPdfSource } from './acorex-platform-module-report-management-client-acorex-platform-module-report-management-client-D5dCG62j.mjs';
32
+
33
+ class AXPReportViewerPageComponent extends AXPPageLayoutBaseComponent {
34
+ constructor() {
35
+ super();
36
+ //#region ---- Dependencies ----
37
+ this.layoutService = inject(AXPLayoutThemeService);
38
+ this.deviceService = inject(AXPDeviceService);
39
+ this.route = inject(ActivatedRoute);
40
+ this.unsubscriber = inject(AXUnsubscriber);
41
+ this.loadingDialog = inject(AXLoadingDialogService);
42
+ this.destroyRef = inject(DestroyRef);
43
+ this.reportViewerService = inject(AXPReportViewerService);
44
+ this.entityService = inject(AXPEntityService);
45
+ //#endregion
46
+ //#region ---- Inputs ----
47
+ this.reportId = input(/* @ts-ignore */
48
+ ...(ngDevMode ? [undefined, { debugName: "reportId" }] : /* istanbul ignore next */ []));
49
+ this.reportParameters = input({}, /* @ts-ignore */
50
+ ...(ngDevMode ? [{ debugName: "reportParameters" }] : /* istanbul ignore next */ []));
51
+ //#endregion
52
+ //#region ---- ViewChildren ----
53
+ this.filtersForm = viewChild('filtersForm', /* @ts-ignore */
54
+ ...(ngDevMode ? [{ debugName: "filtersForm" }] : /* istanbul ignore next */ []));
55
+ //#endregion
56
+ //#region ---- ViewModel ----
57
+ this.vm = inject(AXPReportViewerViewModel);
58
+ //#endregion
59
+ //#region ---- Effects ----
60
+ this.watchNavigationLoading = effect(() => {
61
+ const isBusy = this.vm.isLoading() || this.vm.isExecuting();
62
+ untracked(() => {
63
+ this.layoutService.setNavigationLoading(isBusy);
64
+ //
65
+ if (isBusy) {
66
+ void this.openContentLoading();
67
+ }
68
+ else {
69
+ this.closeContentLoading();
70
+ }
71
+ });
72
+ }, /* @ts-ignore */
73
+ ...(ngDevMode ? [{ debugName: "watchNavigationLoading" }] : /* istanbul ignore next */ []));
74
+ this.syncFrozenRunUrl = effect(() => {
75
+ const runId = this.vm.runId();
76
+ const frozen = this.vm.isFrozen();
77
+ const queued = this.vm.isBackgroundQueued();
78
+ if (queued) {
79
+ untracked(() => {
80
+ const currentRunId = this.route.snapshot.queryParamMap.get('runId')?.trim();
81
+ if (!currentRunId) {
82
+ return;
83
+ }
84
+ void this.router.navigate([], {
85
+ relativeTo: this.route,
86
+ queryParams: { runId: null },
87
+ queryParamsHandling: 'merge',
88
+ replaceUrl: true,
89
+ });
90
+ });
91
+ return;
92
+ }
93
+ if (!frozen || !runId) {
94
+ return;
95
+ }
96
+ untracked(() => {
97
+ const currentRunId = this.route.snapshot.queryParamMap.get('runId')?.trim();
98
+ if (currentRunId === runId) {
99
+ return;
100
+ }
101
+ void this.router.navigate([], {
102
+ relativeTo: this.route,
103
+ queryParams: { runId },
104
+ queryParamsHandling: 'merge',
105
+ replaceUrl: true,
106
+ });
107
+ this.recompute();
108
+ });
109
+ }, /* @ts-ignore */
110
+ ...(ngDevMode ? [{ debugName: "syncFrozenRunUrl" }] : /* istanbul ignore next */ []));
111
+ //#endregion
112
+ this.loadingDialogRef = null;
113
+ this.isDialogOpening = false;
114
+ this.lastReportRouteKey = null;
115
+ //#region ---- Computed Properties ----
116
+ this.showFiltersPanel = () => this.deviceService.isLarge();
117
+ this.showReportDisplay = () => (!this.vm.isBackgroundReportMode() || this.vm.isFrozen()) &&
118
+ (this.deviceService.isLarge() || (this.deviceService.isSmall() && this.vm.hasBeenExecuted()));
119
+ //#endregion
120
+ //#region ---- Layout Configurations ----
121
+ this.defaultLayout = () => ({
122
+ positions: {
123
+ sm: { colSpan: 12 },
124
+ md: { colSpan: 6 },
125
+ lg: { colSpan: 12 },
126
+ },
127
+ });
128
+ this.compactLayout = () => ({
129
+ positions: {
130
+ sm: { colSpan: 12 },
131
+ md: { colSpan: 4 },
132
+ lg: { colSpan: 3 },
133
+ },
134
+ });
135
+ this.layoutPageIcon = reportLayoutPageIcon;
136
+ this.destroyRef.onDestroy(() => {
137
+ this.closeContentLoading();
138
+ void this.vm.releaseInlineNotificationWatch();
139
+ });
140
+ }
141
+ reportsListPath() {
142
+ return this.entityService
143
+ .withEntity(RootConfig.module.name, RootConfig.entities.report.name)
144
+ .createPath();
145
+ }
146
+ isReportViewerUrl(url) {
147
+ return url.includes(`/${RootConfig.module.route}/viewer`);
148
+ }
149
+ //#endregion
150
+ //#region ---- Lifecycle ----
151
+ async ngOnInit() {
152
+ await super.ngOnInit();
153
+ this.unsubscriber
154
+ .takeUntilDestroy(this.router.events.pipe(filter((event) => event instanceof NavigationStart)))
155
+ .subscribe((event) => {
156
+ const navigation = event;
157
+ if (this.isReportViewerUrl(this.router.url) && !this.isReportViewerUrl(navigation.url)) {
158
+ void this.vm.releaseInlineNotificationWatch();
159
+ }
160
+ });
161
+ // Reload when reportId or runId changes. Ignore other query params (live filters).
162
+ this.unsubscriber
163
+ .takeUntilDestroy(combineLatest([this.route.paramMap, this.route.queryParamMap]))
164
+ .subscribe(async ([params, queryParams]) => {
165
+ const reportId = params.get('reportId') || queryParams.get('reportId') || this.reportId();
166
+ if (!reportId) {
167
+ return;
168
+ }
169
+ const runId = queryParams.get('runId')?.trim() || '';
170
+ const routeKey = `${reportId}::${runId}`;
171
+ if (routeKey === this.lastReportRouteKey) {
172
+ return;
173
+ }
174
+ this.lastReportRouteKey = routeKey;
175
+ await this.loadReportAndRefresh(reportId);
176
+ });
177
+ }
178
+ /**
179
+ * Effect to handle data fetching when chart configuration changes
180
+ */
181
+ //#endregion
182
+ //#region ---- Helper Methods ----
183
+ async loadReportAndRefresh(reportId) {
184
+ const runId = this.route.snapshot.queryParamMap.get('runId')?.trim();
185
+ if (runId) {
186
+ await this.vm.loadReport(reportId);
187
+ await this.vm.loadFrozenRun(runId);
188
+ this.recompute();
189
+ return;
190
+ }
191
+ await this.vm.loadReport(reportId);
192
+ // Force refresh of page layout (breadcrumbs, title, etc.) after report loads
193
+ this.recompute();
194
+ // Handle initial parameters from query string
195
+ const queryParams = this.route.snapshot.queryParams;
196
+ const initialParams = { ...queryParams };
197
+ delete initialParams['reportId'];
198
+ delete initialParams['runId'];
199
+ // Parse filter context values coming from URL (they are strings)
200
+ const parsedInitialParams = this.parseFilterContextFromUrl(initialParams);
201
+ // Merge with component input parameters (`today` / `{ from, to }` → filter shape)
202
+ const rawParams = { ...parsedInitialParams, ...this.reportParameters() };
203
+ const allParams = Object.fromEntries(Object.entries(rawParams).map(([key, value]) => [key, resolveReportFilterDefaultValue(value)]));
204
+ if (Object.keys(allParams).length > 0) {
205
+ console.log('Applying initial parameters:', allParams);
206
+ this.vm.updateFilterContext(allParams);
207
+ // Auto-execute if parameters are provided
208
+ setTimeout(async () => {
209
+ await this.vm.executeReport();
210
+ }, 500); // Small delay to ensure form is ready
211
+ }
212
+ }
213
+ async openContentLoading() {
214
+ if (this.loadingDialogRef || this.isDialogOpening) {
215
+ return;
216
+ }
217
+ this.isDialogOpening = true;
218
+ try {
219
+ const [title, description, cancelText] = await Promise.all([
220
+ this.translateService.translateAsync('@report-management:report-viewer.messages.loading.in-progress-title'),
221
+ this.translateService.translateAsync('@report-management:report-viewer.messages.loading.in-progress-description'),
222
+ this.translateService.translateAsync('@report-management:report-viewer.messages.loading.cancel-button'),
223
+ ]);
224
+ this.loadingDialogRef = this.loadingDialog.show({
225
+ title,
226
+ mode: 'indeterminate',
227
+ progressColor: 'primary',
228
+ text: description,
229
+ buttons: [
230
+ {
231
+ text: cancelText,
232
+ color: 'danger',
233
+ onClick: () => {
234
+ this.closeContentLoading();
235
+ this.vm.cancel();
236
+ },
237
+ },
238
+ ],
239
+ });
240
+ }
241
+ finally {
242
+ this.isDialogOpening = false;
243
+ }
244
+ }
245
+ closeContentLoading() {
246
+ if (!this.loadingDialogRef) {
247
+ return;
248
+ }
249
+ this.loadingDialogRef.close();
250
+ this.loadingDialogRef = null;
251
+ }
252
+ /**
253
+ * Synchronizes filter context to URL query parameters using dot notation
254
+ * @param filterContext The current filter context to sync
255
+ */
256
+ syncFiltersToUrl(filterContext) {
257
+ // Get current query params
258
+ const currentParams = this.route.snapshot.queryParams;
259
+ const reportId = currentParams['reportId'];
260
+ // Get all filter keys from current params (excluding reportId and internal fields)
261
+ const currentFilterKeys = new Set();
262
+ Object.keys(currentParams).forEach((key) => {
263
+ if (key !== 'reportId' &&
264
+ key !== 'runId' &&
265
+ !key.endsWith('EditorObj') &&
266
+ !key.startsWith('__') &&
267
+ !key.endsWith('EditorValue') &&
268
+ !key.includes('.displayText')) {
269
+ // Extract root key (before first dot) for filter identification
270
+ const rootKey = key.includes('.') ? key.split('.')[0] : key;
271
+ currentFilterKeys.add(rootKey);
272
+ }
273
+ });
274
+ // Build new query params - start with current params and remove filter-related ones
275
+ const queryParams = { ...currentParams };
276
+ // Remove all filter-related params first (we'll add them back if they have values)
277
+ Object.keys(queryParams).forEach((key) => {
278
+ if (key !== 'reportId' &&
279
+ key !== 'runId' &&
280
+ !key.endsWith('EditorObj') &&
281
+ !key.startsWith('__') &&
282
+ !key.endsWith('EditorValue') &&
283
+ !key.includes('.displayText')) {
284
+ delete queryParams[key];
285
+ }
286
+ });
287
+ const processedFilterKeys = new Set();
288
+ // Add filter params that have values
289
+ Object.keys(filterContext).forEach((key) => {
290
+ // Skip internal editor fields (EditorObj, __EditorValue)
291
+ if (key.endsWith('EditorObj') || key.startsWith('__') || key.endsWith('EditorValue')) {
292
+ return;
293
+ }
294
+ processedFilterKeys.add(key);
295
+ const value = filterContext[key];
296
+ // Check if value is empty (null, undefined, empty string, or empty array)
297
+ const isEmpty = this.isFilterValueEmpty(value);
298
+ if (!isEmpty) {
299
+ const flattened = this.flattenToDotNotation(key, value);
300
+ Object.assign(queryParams, flattened);
301
+ }
302
+ // If empty, we don't add it to queryParams, so it will be removed from URL
303
+ });
304
+ // Remove filter keys that are no longer in filterContext
305
+ currentFilterKeys.forEach((filterKey) => {
306
+ if (!processedFilterKeys.has(filterKey)) {
307
+ // This filter was removed - ensure all related params are removed
308
+ Object.keys(currentParams).forEach((paramKey) => {
309
+ if (paramKey === filterKey || paramKey.startsWith(`${filterKey}.`)) {
310
+ delete queryParams[paramKey];
311
+ }
312
+ });
313
+ }
314
+ });
315
+ // Preserve reportId / runId if exists
316
+ if (reportId) {
317
+ queryParams['reportId'] = String(reportId);
318
+ }
319
+ else {
320
+ delete queryParams['reportId'];
321
+ }
322
+ const runId = currentParams['runId'];
323
+ if (runId) {
324
+ queryParams['runId'] = String(runId);
325
+ }
326
+ else {
327
+ delete queryParams['runId'];
328
+ }
329
+ // Update URL without reloading
330
+ this.router.navigate([], {
331
+ relativeTo: this.route,
332
+ queryParams: queryParams,
333
+ replaceUrl: true, // Don't add to browser history
334
+ });
335
+ }
336
+ /**
337
+ * Checks if a filter value is considered empty
338
+ */
339
+ isFilterValueEmpty(value) {
340
+ if (value === null || value === undefined || value === '') {
341
+ return true;
342
+ }
343
+ // Check if it's a filter object with empty value
344
+ if (typeof value === 'object' && !Array.isArray(value)) {
345
+ const filterObj = value;
346
+ const filterValue = filterObj.value;
347
+ if (filterValue === null || filterValue === undefined || filterValue === '') {
348
+ return true;
349
+ }
350
+ if (Array.isArray(filterValue) && filterValue.length === 0) {
351
+ return true;
352
+ }
353
+ // Check nested object values
354
+ if (typeof filterValue === 'object' && !Array.isArray(filterValue)) {
355
+ const hasAnyValue = Object.values(filterValue).some((v) => v !== null && v !== undefined && v !== '');
356
+ return !hasAnyValue;
357
+ }
358
+ }
359
+ // Check if it's an empty array
360
+ if (Array.isArray(value) && value.length === 0) {
361
+ return true;
362
+ }
363
+ return false;
364
+ }
365
+ /**
366
+ * Flattens filter context to dot notation query parameters
367
+ * Only includes operation.type and value - skips displayText and other fields
368
+ * Example: { operation: { type: 'in' }, value: ['POST', 'GET'] }
369
+ * -> { 'fieldName.operation.type': 'in', 'fieldName.value': 'POST,GET' }
370
+ */
371
+ flattenToDotNotation(prefix, value) {
372
+ const result = {};
373
+ if (value == null) {
374
+ return result;
375
+ }
376
+ // Handle filter context object - only extract operation.type and value
377
+ if (typeof value === 'object' && !Array.isArray(value)) {
378
+ const filterObj = value;
379
+ // Extract operation.type if exists
380
+ if (filterObj.operation?.type) {
381
+ result[`${prefix}.operation.type`] = String(filterObj.operation.type);
382
+ }
383
+ // Extract value - handle arrays and primitives
384
+ if (filterObj.value !== undefined && filterObj.value !== null && filterObj.value !== '') {
385
+ if (Array.isArray(filterObj.value)) {
386
+ if (filterObj.value.length > 0) {
387
+ result[`${prefix}.value`] = filterObj.value.map((v) => String(v)).join(',');
388
+ }
389
+ }
390
+ else if (typeof filterObj.value === 'object') {
391
+ // If value is an object, flatten it recursively
392
+ const flattenedValue = this.flattenValueObject(filterObj.value);
393
+ Object.assign(result, flattenedValue);
394
+ }
395
+ else {
396
+ result[`${prefix}.value`] = String(filterObj.value);
397
+ }
398
+ }
399
+ return result;
400
+ }
401
+ // Handle primitives directly
402
+ if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
403
+ result[prefix] = String(value);
404
+ return result;
405
+ }
406
+ // Handle arrays - join with comma
407
+ if (Array.isArray(value)) {
408
+ if (value.length > 0) {
409
+ result[prefix] = value.map(v => String(v)).join(',');
410
+ }
411
+ return result;
412
+ }
413
+ // Fallback: convert to string
414
+ result[prefix] = String(value);
415
+ return result;
416
+ }
417
+ /**
418
+ * Flattens a value object (for nested objects in value field)
419
+ */
420
+ flattenValueObject(obj, prefix = '') {
421
+ const result = {};
422
+ if (obj == null || typeof obj !== 'object') {
423
+ return result;
424
+ }
425
+ for (const [key, val] of Object.entries(obj)) {
426
+ const newPrefix = prefix ? `${prefix}.${key}` : key;
427
+ if (val == null) {
428
+ continue;
429
+ }
430
+ if (typeof val === 'string' || typeof val === 'number' || typeof val === 'boolean') {
431
+ result[newPrefix] = String(val);
432
+ }
433
+ else if (Array.isArray(val)) {
434
+ if (val.length > 0) {
435
+ result[newPrefix] = val.map((v) => String(v)).join(',');
436
+ }
437
+ }
438
+ else if (typeof val === 'object') {
439
+ const flattened = this.flattenValueObject(val, newPrefix);
440
+ Object.assign(result, flattened);
441
+ }
442
+ }
443
+ return result;
444
+ }
445
+ /**
446
+ * Reconstructs filter context from dot notation query parameters
447
+ * Only parses operation.type and value - ignores other fields
448
+ * Example: { 'fieldName.operation.type': 'in', 'fieldName.value': 'POST,GET' }
449
+ * -> { fieldName: { operation: { type: 'in' }, value: ['POST', 'GET'] } }
450
+ */
451
+ parseFilterContextFromUrl(params) {
452
+ const result = {};
453
+ // Filter out reportId and internal editor fields
454
+ const filteredParams = {};
455
+ for (const [key, value] of Object.entries(params)) {
456
+ // Skip reportId and internal editor fields (EditorObj, __EditorValue, displayText)
457
+ if (key !== 'reportId' &&
458
+ key !== 'runId' &&
459
+ !key.endsWith('EditorObj') &&
460
+ !key.startsWith('__') &&
461
+ !key.endsWith('EditorValue') &&
462
+ !key.includes('.displayText')) {
463
+ filteredParams[key] = value;
464
+ }
465
+ }
466
+ // Group by root key (before first dot)
467
+ for (const [key, value] of Object.entries(filteredParams)) {
468
+ if (!key.includes('.')) {
469
+ // Simple key without dot notation - skip (we only want operation.type and value)
470
+ continue;
471
+ }
472
+ // Split by dot and reconstruct nested structure
473
+ const parts = key.split('.');
474
+ const rootKey = parts[0];
475
+ const path = parts.slice(1);
476
+ // Only process operation.type and value paths
477
+ if (path.length === 2 && path[0] === 'operation' && path[1] === 'type') {
478
+ // operation.type
479
+ if (!result[rootKey]) {
480
+ result[rootKey] = { operation: {} };
481
+ }
482
+ if (!result[rootKey].operation) {
483
+ result[rootKey].operation = {};
484
+ }
485
+ result[rootKey].operation.type = String(value);
486
+ }
487
+ else if (path.length === 1 && path[0] === 'value') {
488
+ // value
489
+ if (!result[rootKey]) {
490
+ result[rootKey] = {};
491
+ }
492
+ result[rootKey].value = this.parseValue(String(value));
493
+ }
494
+ else if (path.length > 1 && path[0] === 'value') {
495
+ // nested value object (e.g., value.from, value.to for between)
496
+ if (!result[rootKey]) {
497
+ result[rootKey] = {};
498
+ }
499
+ if (!result[rootKey].value) {
500
+ result[rootKey].value = {};
501
+ }
502
+ const valuePath = path.slice(1);
503
+ this.setNestedValue(result[rootKey].value, valuePath, this.parseValue(String(value)));
504
+ }
505
+ }
506
+ // Post-process: Convert values to arrays if operation.type is 'in' or 'notIn'
507
+ // Also reconstruct EditorObj for lookup widgets (from value only, no displayText)
508
+ for (const [key, value] of Object.entries(result)) {
509
+ if (value && typeof value === 'object' && value.operation?.type) {
510
+ const operationType = value.operation.type;
511
+ // If operation is 'in' or 'notIn', ensure value is an array
512
+ if ((operationType === 'in' || operationType === 'notIn') && typeof value.value === 'string') {
513
+ // Convert comma-separated string to array
514
+ value.value = value.value.split(',').map((v) => v.trim()).filter((v) => v !== '');
515
+ }
516
+ // Reconstruct EditorObj for lookup widgets from value only
517
+ // This is needed because lookup widget expects EditorObj to exist
518
+ if (value.value !== undefined && value.value !== null && value.value !== '') {
519
+ const editorObjKey = `${key}EditorObj`;
520
+ const valueField = 'id'; // Default value field for lookup
521
+ const textField = 'title'; // Default text field for lookup
522
+ if (operationType === 'in' || operationType === 'notIn') {
523
+ // Multiple selection: create array of objects with value as both id and title
524
+ const values = Array.isArray(value.value) ? value.value : [value.value];
525
+ result[editorObjKey] = values.map((val) => ({
526
+ [valueField]: val,
527
+ [textField]: val // Use value as title since we don't have displayText
528
+ }));
529
+ }
530
+ else {
531
+ // Single selection: create single object
532
+ result[editorObjKey] = {
533
+ [valueField]: value.value,
534
+ [textField]: value.value // Use value as title since we don't have displayText
535
+ };
536
+ }
537
+ }
538
+ }
539
+ }
540
+ return result;
541
+ }
542
+ /**
543
+ * Sets a value in a nested object using a path array
544
+ */
545
+ setNestedValue(obj, path, value) {
546
+ let current = obj;
547
+ for (let i = 0; i < path.length - 1; i++) {
548
+ const key = path[i];
549
+ if (!current[key] || typeof current[key] !== 'object') {
550
+ current[key] = {};
551
+ }
552
+ current = current[key];
553
+ }
554
+ const lastKey = path[path.length - 1];
555
+ current[lastKey] = value;
556
+ }
557
+ /**
558
+ * Parses a string value, handling arrays (comma-separated) and primitives
559
+ */
560
+ parseValue(value) {
561
+ if (value === '') {
562
+ return value;
563
+ }
564
+ // Check if it's a comma-separated array
565
+ if (value.includes(',')) {
566
+ return value.split(',').map(v => this.parsePrimitive(v.trim()));
567
+ }
568
+ return this.parsePrimitive(value);
569
+ }
570
+ /**
571
+ * Parses a primitive value
572
+ * For query params, we keep everything as string to match user requirement
573
+ * Arrays are handled separately in parseValue
574
+ */
575
+ parsePrimitive(value) {
576
+ return value;
577
+ }
578
+ //#endregion
579
+ //#region ---- Event Handlers ----
580
+ handleFiltersChange(event) {
581
+ this.vm.updateFilterContext(event);
582
+ this.syncFiltersToUrl(event);
583
+ }
584
+ handleFiltersInitiated(event) {
585
+ this.vm.updateFilterContext(event);
586
+ }
587
+ async handleExecuteReport() {
588
+ if (this.vm.isFrozen() && !this.vm.isBackgroundReportMode()) {
589
+ return;
590
+ }
591
+ const isValid = await this.filtersForm()?.validate();
592
+ if (!isValid?.result) {
593
+ return;
594
+ }
595
+ await this.vm.executeReport();
596
+ this.recompute();
597
+ }
598
+ async handleGenerateInBackground() {
599
+ if (this.vm.isFrozen() && !this.vm.isBackgroundReportMode()) {
600
+ return;
601
+ }
602
+ const isValid = await this.filtersForm()?.validate();
603
+ if (!isValid?.result) {
604
+ return;
605
+ }
606
+ await this.vm.generateInBackground();
607
+ this.recompute();
608
+ }
609
+ canGenerateInBackground() {
610
+ return (this.sessionService.isFeatureEnabled(AXPReportManagementFeatureKeys.BackgroundReports) &&
611
+ !this.vm.isFrozen() &&
612
+ (this.vm.generationMode() === 'choose' || this.vm.generationMode() === 'background'));
613
+ }
614
+ handleRefresh() {
615
+ this.vm.refresh();
616
+ }
617
+ handleClearFilters() {
618
+ this.vm.clearFilters();
619
+ // Reset form if available
620
+ const form = this.filtersForm();
621
+ if (form) {
622
+ form.reset();
623
+ }
624
+ // Clear URL query parameters (preserve reportId if exists)
625
+ const currentParams = this.route.snapshot.queryParams;
626
+ const reportId = currentParams['reportId'];
627
+ const runId = currentParams['runId'];
628
+ this.router.navigate([], {
629
+ relativeTo: this.route,
630
+ queryParams: {
631
+ ...(reportId ? { reportId } : {}),
632
+ ...(runId ? { runId } : {}),
633
+ },
634
+ replaceUrl: true,
635
+ });
636
+ }
637
+ /**
638
+ * Handle download report action
639
+ * Gets PDF data from viewmodel and calls service executeAction method
640
+ */
641
+ async handleDownloadReport() {
642
+ if (!this.vm.isPdfLayout()) {
643
+ const warning = await this.translateService.translateAsync('@report-management:report-viewer.messages.warnings.download-pdf-only');
644
+ console.warn(warning);
645
+ return;
646
+ }
647
+ // Fetch PDF data if not already available
648
+ const pdfData = queryResultToPdfSource(await this.vm.fetchData());
649
+ if (pdfData) {
650
+ await this.reportViewerService.executeAction('download-report', { pdfData });
651
+ }
652
+ else {
653
+ const warning = await this.translateService.translateAsync('@report-management:report-viewer.messages.warnings.no-pdf-download');
654
+ console.warn(warning);
655
+ }
656
+ }
657
+ /**
658
+ * Handle print report action
659
+ * Gets PDF data from viewmodel and calls service executeAction method
660
+ */
661
+ async handlePrintReport() {
662
+ if (!this.vm.isPdfLayout()) {
663
+ const warning = await this.translateService.translateAsync('@report-management:report-viewer.messages.warnings.print-pdf-only');
664
+ console.warn(warning);
665
+ return;
666
+ }
667
+ // Fetch PDF data if not already available
668
+ const pdfData = queryResultToPdfSource(await this.vm.fetchData());
669
+ if (pdfData) {
670
+ await this.reportViewerService.executeAction('print-report', { pdfData });
671
+ }
672
+ else {
673
+ const warning = await this.translateService.translateAsync('@report-management:report-viewer.messages.warnings.no-pdf-print');
674
+ console.warn(warning);
675
+ }
676
+ }
677
+ /**
678
+ * Handle export report action
679
+ * Gets report data from viewmodel and calls service executeAction method
680
+ * @param format - Export format (excel, csv, pdf, image)
681
+ */
682
+ async handleExportReport(format) {
683
+ if (!format) {
684
+ const warning = await this.translateService.translateAsync('@report-management:report-viewer.messages.warnings.export-format-required');
685
+ console.warn(warning);
686
+ return;
687
+ }
688
+ // Fetch report data
689
+ const result = await this.vm.fetchData();
690
+ const reportData = runtimeQueryPayloadData(result);
691
+ if (reportData == null) {
692
+ const warning = await this.translateService.translateAsync('@report-management:report-viewer.messages.warnings.no-report-data-export');
693
+ console.warn(warning);
694
+ return;
695
+ }
696
+ const layout = this.vm.currentLayout();
697
+ await this.reportViewerService.executeAction('export-report', {
698
+ format,
699
+ reportData,
700
+ layoutDefinition: layout || undefined,
701
+ });
702
+ }
703
+ getLayoutSelectionLabel(layout) {
704
+ const locale = this.translateService.getActiveLang() || 'en-US';
705
+ const reportTitle = this.vm.reportDefinition()?.title;
706
+ if (isDistinctLayoutTitle(layout.title, reportTitle, locale)) {
707
+ return layout.title ?? reportLayoutTitleKey(layout);
708
+ }
709
+ return reportLayoutTitleKey(layout);
710
+ }
711
+ handleBackgroundLayoutToggle(layoutId, selected) {
712
+ this.vm.setBackgroundLayoutSelected(layoutId, selected);
713
+ }
714
+ //#endregion
715
+ //#region ---- Page Configuration Overrides ----
716
+ async getPageBreadcrumbs() {
717
+ const breadcrumbs = [
718
+ {
719
+ name: 'reports',
720
+ title: await this.translateService.translateAsync('@report-management:module.menus.root.title'),
721
+ command: {
722
+ name: 'navigate',
723
+ options: {
724
+ path: this.reportsListPath(),
725
+ },
726
+ },
727
+ },
728
+ ];
729
+ const reportDefinition = this.vm.reportDefinition();
730
+ if (reportDefinition) {
731
+ breadcrumbs.push({
732
+ name: 'report-viewer',
733
+ title: reportDefinition.title,
734
+ });
735
+ }
736
+ return breadcrumbs;
737
+ }
738
+ async getPageTitle() {
739
+ const reportDefinition = this.vm.reportDefinition();
740
+ if (reportDefinition) {
741
+ return reportDefinition.title;
742
+ }
743
+ return await this.translateService.translateAsync('@report-management:report-viewer.components.report-viewer.title');
744
+ }
745
+ async getPageDescription() {
746
+ const reportDefinition = this.vm.reportDefinition();
747
+ return reportDefinition?.description || null;
748
+ }
749
+ getPageIcon() {
750
+ if ((this.vm.isBackgroundReportMode() && !this.vm.isFrozen()) ||
751
+ !this.vm.hasMultipleLayouts() ||
752
+ !this.showReportDisplay()) {
753
+ return null;
754
+ }
755
+ const currentLayout = this.vm.currentLayout();
756
+ if (!currentLayout) {
757
+ return null;
758
+ }
759
+ return reportLayoutPageIcon(currentLayout.icon, {
760
+ type: currentLayout.layout.type,
761
+ });
762
+ }
763
+ async getTitleActions() {
764
+ if ((this.vm.isBackgroundReportMode() && !this.vm.isFrozen()) ||
765
+ !this.vm.hasMultipleLayouts() ||
766
+ !this.showReportDisplay()) {
767
+ return [];
768
+ }
769
+ const currentLayoutId = this.vm.currentLayout()?.id;
770
+ const reportTitle = this.vm.reportDefinition()?.title;
771
+ const locale = this.translateService.getActiveLang() || 'en-US';
772
+ const items = [];
773
+ for (const layout of this.vm.availableLayouts()) {
774
+ items.push({
775
+ title: await this.resolveLayoutSwitcherTitle(layout, reportTitle, locale),
776
+ icon: reportLayoutGlyph(layout.icon, layout),
777
+ command: {
778
+ name: 'switch-layout',
779
+ metadata: { isLayout: true, layoutId: layout.id, isSelected: layout.id === currentLayoutId },
780
+ },
781
+ });
782
+ }
783
+ return items.sort((a, b) => resolveMultiLanguageString(a.title, locale).localeCompare(resolveMultiLanguageString(b.title, locale), undefined, { sensitivity: 'base' }));
784
+ }
785
+ async resolveLayoutSwitcherTitle(layout, reportTitle, locale) {
786
+ if (isDistinctLayoutTitle(layout.title, reportTitle, locale)) {
787
+ if (typeof layout.title === 'string' && layout.title.startsWith('@')) {
788
+ return await this.translateService.translateAsync(layout.title);
789
+ }
790
+ if (typeof layout.title === 'object') {
791
+ return this.translateService.resolve(layout.title) || layout.title;
792
+ }
793
+ return layout.title;
794
+ }
795
+ return await this.translateService.translateAsync(reportLayoutTitleKey(layout));
796
+ }
797
+ async getBackButton() {
798
+ // On mobile, if report has been executed (showing report), show "Filters" as back button
799
+ if (this.deviceService.isSmall() && this.vm.hasBeenExecuted()) {
800
+ return {
801
+ title: await this.translateService.translateAsync('@general:terms.interface.filter.title'),
802
+ };
803
+ }
804
+ return {
805
+ title: await this.translateService.translateAsync('@report-management:module.menus.root.title'),
806
+ };
807
+ }
808
+ async onBackButtonClick() {
809
+ // On mobile, if report has been executed (showing report), go back to filters
810
+ if (this.deviceService.isSmall() && this.vm.hasBeenExecuted()) {
811
+ this.vm.clearExecutionState();
812
+ return;
813
+ }
814
+ await this.router.navigateByUrl(this.reportsListPath());
815
+ }
816
+ async getPrimaryMenuItems() {
817
+ if (this.vm.isBackgroundReportMode() && !this.vm.isFrozen()) {
818
+ return [];
819
+ }
820
+ const currentLayout = this.vm.currentLayout();
821
+ if (!currentLayout) {
822
+ return [];
823
+ }
824
+ // Get primary actions from service (includes general actions + layout-specific actions)
825
+ const primaryActions = this.reportViewerService.getPrimaryActions(currentLayout);
826
+ // Convert AXPReportLayoutAction[] to AXPActionMenuItem[] (remove priority property)
827
+ return primaryActions.map(({ priority, ...action }) => action);
828
+ }
829
+ async getSecondaryMenuItems() {
830
+ if (this.vm.isBackgroundReportMode() && !this.vm.isFrozen()) {
831
+ return [];
832
+ }
833
+ const currentLayout = this.vm.currentLayout();
834
+ if (!currentLayout) {
835
+ return [];
836
+ }
837
+ const secondaryActions = this.reportViewerService.getSecondaryActions(currentLayout);
838
+ const items = secondaryActions.map(({ priority, ...action }) => action);
839
+ if (this.canGenerateInBackground() && this.vm.generationMode() === 'choose') {
840
+ items.unshift({
841
+ title: '@report-management:report-generation.actions.generate-in-background',
842
+ icon: 'fa-light fa-clock',
843
+ command: { name: 'generate-in-background' },
844
+ });
845
+ }
846
+ return items;
847
+ }
848
+ async execute(command) {
849
+ // Handle layout switching from title actions
850
+ if (command.metadata?.['isLayout']) {
851
+ const layoutId = command.metadata?.['layoutId'];
852
+ if (layoutId) {
853
+ this.vm.switchLayout(layoutId);
854
+ this.recompute();
855
+ }
856
+ return;
857
+ }
858
+ switch (command.name) {
859
+ case 'execute-report':
860
+ await this.handleExecuteReport();
861
+ break;
862
+ case 'generate-in-background':
863
+ await this.handleGenerateInBackground();
864
+ break;
865
+ case 'refresh-report':
866
+ this.handleRefresh();
867
+ break;
868
+ case 'reset-filters':
869
+ this.handleClearFilters();
870
+ break;
871
+ case 'download-report':
872
+ this.handleDownloadReport();
873
+ break;
874
+ case 'print-report':
875
+ this.handlePrintReport();
876
+ break;
877
+ case 'export-report':
878
+ await this.handleExportReport(command.options?.['format']);
879
+ break;
880
+ default:
881
+ const warning = await this.translateService.translateAsync('@report-management:report-viewer.messages.warnings.unknown-command', {
882
+ params: { commandName: command.name },
883
+ });
884
+ console.warn(warning);
885
+ break;
886
+ }
887
+ }
888
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPReportViewerPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
889
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: AXPReportViewerPageComponent, isStandalone: true, selector: "axp-report-viewer-page", inputs: { reportId: { classPropertyName: "reportId", publicName: "reportId", isSignal: true, isRequired: false, transformFunction: null }, reportParameters: { classPropertyName: "reportParameters", publicName: "reportParameters", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "axp-report-viewer-page" }, providers: [
890
+ AXUnsubscriber,
891
+ AXPReportViewerViewModel,
892
+ {
893
+ provide: AXPPageLayoutBase,
894
+ useExisting: AXPReportViewerPageComponent,
895
+ },
896
+ ], 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$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "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$2.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i2$2.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: i4$1.AXTranslatorDirective, selector: "[translate]" }, { kind: "ngmodule", type: AXBadgeModule }, { kind: "ngmodule", type: AXLoadingDialogModule }, { kind: "component", type:
897
+ //
898
+ 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: i4$1.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
899
+ }
900
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPReportViewerPageComponent, decorators: [{
901
+ type: Component,
902
+ args: [{ selector: 'axp-report-viewer-page', standalone: true, imports: [
903
+ CommonModule,
904
+ FormsModule,
905
+ AXButtonModule,
906
+ AXCheckBoxModule,
907
+ AXDecoratorModule,
908
+ AXLoadingModule,
909
+ AXTranslationModule,
910
+ AXBadgeModule,
911
+ AXLoadingDialogModule,
912
+ //
913
+ AXPLayoutRendererComponent,
914
+ AXPPageLayoutComponent,
915
+ AXPThemeLayoutStartSideComponent,
916
+ AXPThemeLayoutHeaderComponent,
917
+ AXPThemeLayoutBlockComponent,
918
+ AXPReportTableViewComponent,
919
+ AXPThemeLayoutFooterComponent,
920
+ AXPReportChartViewComponent,
921
+ AXPReportPdfViewComponent,
922
+ AXPStateMessageComponent,
923
+ ], providers: [
924
+ AXUnsubscriber,
925
+ AXPReportViewerViewModel,
926
+ {
927
+ provide: AXPPageLayoutBase,
928
+ useExisting: AXPReportViewerPageComponent,
929
+ },
930
+ ], 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"] }]
931
+ }], 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 }] }] } });
932
+
933
+ export { AXPReportViewerPageComponent };
934
+ //# sourceMappingURL=acorex-platform-module-report-management-client-report-viewer-page.component-YUdzA4B9.mjs.map