@elite.framework/ng.ui.core 1.0.76 → 1.0.78

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.
@@ -0,0 +1,488 @@
1
+ import * as i0 from '@angular/core';
2
+ import { NgModule, inject, Input, ViewChild, Component } from '@angular/core';
3
+ import * as i2 from '@angular/common';
4
+ import { CommonModule } from '@angular/common';
5
+ import * as i3 from '@angular/forms';
6
+ import { FormGroup, ReactiveFormsModule, FormsModule } from '@angular/forms';
7
+ import * as i9 from '@ngx-formly/core';
8
+ import { FormlyModule } from '@ngx-formly/core';
9
+ import * as i11 from '@ngx-translate/core';
10
+ import { TranslateService, TranslateModule } from '@ngx-translate/core';
11
+ import * as i4 from 'primeng/button';
12
+ import { ButtonModule } from 'primeng/button';
13
+ import { DialogModule } from 'primeng/dialog';
14
+ import { MultiSelectModule } from 'primeng/multiselect';
15
+ import { InputTextModule } from 'primeng/inputtext';
16
+ import * as i6 from 'primeng/radiobutton';
17
+ import { RadioButtonModule } from 'primeng/radiobutton';
18
+ import * as i7 from 'primeng/checkbox';
19
+ import { CheckboxModule } from 'primeng/checkbox';
20
+ import { CardModule } from 'primeng/card';
21
+ import { DividerModule } from 'primeng/divider';
22
+ import * as i8 from 'primeng/tabs';
23
+ import { TabsModule } from 'primeng/tabs';
24
+ import * as i1 from 'primeng/dynamicdialog';
25
+ import { DynamicDialogModule, DialogService } from 'primeng/dynamicdialog';
26
+ import { SelectModule } from 'primeng/select';
27
+ import { RestService } from '@elite.framework/ng.core/services';
28
+ import { Subject, takeUntil } from 'rxjs';
29
+ import * as i10 from 'primeng/drawer';
30
+ import { DrawerModule } from 'primeng/drawer';
31
+ import { QueryBuilderService } from '@elite.framework/ng.ui.core/generic-search-advanced';
32
+ import * as i5 from 'primeng/api';
33
+
34
+ class GenericReportModule {
35
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.8", ngImport: i0, type: GenericReportModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
36
+ static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.1.8", ngImport: i0, type: GenericReportModule, imports: [CommonModule] });
37
+ static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.1.8", ngImport: i0, type: GenericReportModule, imports: [CommonModule] });
38
+ }
39
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.8", ngImport: i0, type: GenericReportModule, decorators: [{
40
+ type: NgModule,
41
+ args: [{
42
+ imports: [CommonModule],
43
+ }]
44
+ }] });
45
+
46
+ var ExportType;
47
+ (function (ExportType) {
48
+ ExportType[ExportType["LIST"] = 0] = "LIST";
49
+ ExportType[ExportType["HTML"] = 1] = "HTML";
50
+ ExportType[ExportType["PDF"] = 2] = "PDF";
51
+ ExportType[ExportType["EXCEL"] = 3] = "EXCEL";
52
+ ExportType[ExportType["PRINT"] = 4] = "PRINT";
53
+ })(ExportType || (ExportType = {}));
54
+ class GenericReportComponent {
55
+ ref;
56
+ config;
57
+ previewContainer;
58
+ filterFields = [];
59
+ fields_ = [];
60
+ availableColumns = [];
61
+ exportType = ExportType.EXCEL;
62
+ fileName = '';
63
+ showFilters = false;
64
+ loading = false;
65
+ activeTabIndex = 0;
66
+ currentDate = new Date();
67
+ previewData = [];
68
+ options = {};
69
+ enableQueryBuilder = true;
70
+ localExport = false;
71
+ queryString = '';
72
+ apiName = '';
73
+ model = {};
74
+ form = new FormGroup({});
75
+ exportConfig = {
76
+ columns: {},
77
+ filters: this.model,
78
+ exportType: this.exportType,
79
+ fileName: this.fileName
80
+ };
81
+ exportTypes = [
82
+ { value: ExportType.EXCEL, label: 'EXCEL', icon: 'pi pi-file-excel' },
83
+ { value: ExportType.PDF, label: 'PDF', icon: 'pi pi-file-pdf' },
84
+ { value: ExportType.HTML, label: 'HTML', icon: 'pi pi-code' },
85
+ { value: ExportType.PRINT, label: 'PRINT', icon: 'pi pi-print' }
86
+ ];
87
+ destroy$ = new Subject();
88
+ translate = inject(TranslateService);
89
+ restService = inject(RestService);
90
+ queryBuilder = inject(QueryBuilderService);
91
+ constructor(ref, config) {
92
+ this.ref = ref;
93
+ this.config = config;
94
+ }
95
+ ngOnInit() {
96
+ this.filterFields = this.config.data?.filterFields || [];
97
+ this.initializeComponent();
98
+ this.buildQueryUIFields();
99
+ }
100
+ get filterCount() {
101
+ const filters = ((this.model?.advancedFilters ?? [])[0]?.conditions?.length || 0) +
102
+ ((this.model?.sorting ?? [])?.length || 0) +
103
+ (this.model?.pagination && this.model?.pagination?.top ? 1 : 0);
104
+ return filters;
105
+ }
106
+ buildQueryUIFields() {
107
+ if (this.enableQueryBuilder) {
108
+ this.fields_ = this.queryBuilder.buildQueryUIFields(this.filterFields);
109
+ }
110
+ else {
111
+ this.fields_ = this.filterFields;
112
+ }
113
+ }
114
+ initializeComponent() {
115
+ this.apiName = this.config.data?.apiName || '';
116
+ const columnDefinitions = this.config.data?.columns || {};
117
+ if (Object.keys(columnDefinitions).length > 0) {
118
+ this.availableColumns = Object.keys(columnDefinitions).map(key => ({
119
+ key: String(key),
120
+ displayName: String(columnDefinitions[key]),
121
+ selected: true,
122
+ customName: String(columnDefinitions[key])
123
+ }));
124
+ }
125
+ else {
126
+ this.availableColumns = (this.filterFields || []).map(f => {
127
+ const key = String(f.key ?? '');
128
+ const label = String(f.props?.label ?? key);
129
+ return {
130
+ key,
131
+ displayName: this.translate.instant(label),
132
+ selected: true,
133
+ customName: label
134
+ };
135
+ });
136
+ }
137
+ this.filterFields = this.config.data?.filterFields || this.getDefaultFilterFields();
138
+ this.model = this.config.data?.model || {};
139
+ this.fileName = this.config.data?.defaultFileName || `export_${new Date().toISOString().split('T')[0]}`;
140
+ // Load sample data for preview
141
+ this.loadPreviewData();
142
+ }
143
+ getDefaultFilterFields() {
144
+ return [
145
+ {
146
+ key: 'search',
147
+ type: 'input',
148
+ props: {
149
+ label: this.translate.instant('SEARCH'),
150
+ placeholder: this.translate.instant('ENTER_SEARCH_TERM'),
151
+ }
152
+ }
153
+ ];
154
+ }
155
+ get selectedColumns() {
156
+ return this.availableColumns.filter(col => col.selected);
157
+ }
158
+ onExportTypeChange(type) {
159
+ this.exportType = type;
160
+ // Auto-switch to preview tab for HTML/Print
161
+ if ((type === ExportType.HTML || type === ExportType.PRINT) && this.selectedColumns.length > 0) {
162
+ this.activeTabIndex = 1;
163
+ }
164
+ }
165
+ onColumnToggle(column) {
166
+ if (!column.selected) {
167
+ column.customName = column.displayName;
168
+ }
169
+ // Refresh preview when columns change
170
+ if (this.activeTabIndex === 1) {
171
+ this.generatePreview();
172
+ }
173
+ }
174
+ onCustomNameChange(column) {
175
+ if (!column.customName?.trim()) {
176
+ column.customName = column.displayName;
177
+ }
178
+ // Refresh preview when column names change
179
+ if (this.activeTabIndex === 1) {
180
+ this.generatePreview();
181
+ }
182
+ }
183
+ selectAllColumns() {
184
+ this.availableColumns.forEach(col => {
185
+ col.selected = true;
186
+ col.customName = col.displayName;
187
+ });
188
+ this.generatePreview();
189
+ }
190
+ deselectAllColumns() {
191
+ this.availableColumns.forEach(col => {
192
+ col.selected = false;
193
+ });
194
+ this.previewData = [];
195
+ }
196
+ generatePreview() {
197
+ if (this.selectedColumns.length === 0) {
198
+ this.previewData = [];
199
+ return;
200
+ }
201
+ // In a real application, you would call your API here
202
+ // For demo purposes, we're using the sample data
203
+ this.loadPreviewData();
204
+ }
205
+ getPreviewValue(row, columnKey) {
206
+ // Handle nested properties with dot notation
207
+ return columnKey.split('.').reduce((obj, key) => obj?.[key], row) || '-';
208
+ }
209
+ getExportButtonText() {
210
+ switch (this.exportType) {
211
+ case ExportType.PRINT:
212
+ return this.translate.instant('PRINT');
213
+ case ExportType.HTML:
214
+ return this.translate.instant('GENERATE_REPORT');
215
+ default:
216
+ return this.translate.instant('EXPORT');
217
+ }
218
+ }
219
+ onSubmit() {
220
+ // Use the new QueryBuilderService methods
221
+ const odataParams = this.queryBuilder.buildODataFromQueryModel(this.model, this.filterFields);
222
+ // this.odataSearch.emit(odataParams);
223
+ // Generate query string using the unified method
224
+ this.queryString = this.queryBuilder.toODataQueryString(odataParams);
225
+ // console.log('OData Query String:', queryString);
226
+ if (this.model?.pagination && this.model?.pagination?.top) {
227
+ // this.paginationChange.emit({
228
+ // top:this.model?.pagination?.top,
229
+ // // skip:,
230
+ // });
231
+ }
232
+ // this.search.emit(
233
+ // {
234
+ // filter:this.model['filter'],
235
+ // query:this.queryString,
236
+ // // sorting:,
237
+ // // top:,
238
+ // // skip:,
239
+ // }
240
+ // );
241
+ this.loadPreviewData();
242
+ }
243
+ onReset() {
244
+ this.availableColumns.forEach(col => {
245
+ col.selected = true;
246
+ col.customName = col.displayName;
247
+ });
248
+ this.exportType = ExportType.EXCEL;
249
+ this.fileName = `export_${new Date().toISOString().split('T')[0]}`;
250
+ this.form.reset();
251
+ this.model = {};
252
+ this.activeTabIndex = 0;
253
+ this.generatePreview();
254
+ }
255
+ onExport() {
256
+ if (this.selectedColumns.length === 0)
257
+ return;
258
+ this.loading = true;
259
+ // Prepare columns mapping
260
+ const columnsMapping = {};
261
+ this.selectedColumns.forEach(col => {
262
+ columnsMapping[col.key] = col.customName || col.displayName;
263
+ });
264
+ const exportConfig = {
265
+ columns: columnsMapping,
266
+ filters: this.model,
267
+ exportType: this.exportType,
268
+ fileName: this.fileName
269
+ };
270
+ // Handle export based on type
271
+ switch (this.exportType) {
272
+ case ExportType.PRINT:
273
+ this.printPreview();
274
+ this.loading = false;
275
+ break;
276
+ case ExportType.HTML:
277
+ this.generateHtmlReport(exportConfig);
278
+ this.loading = false;
279
+ break;
280
+ default:
281
+ this.handleApiExport(exportConfig);
282
+ break;
283
+ }
284
+ }
285
+ generateHtmlReport(config) {
286
+ const htmlContent = this.previewContainer.nativeElement.innerHTML;
287
+ const blob = new Blob([htmlContent], { type: 'text/html' });
288
+ this.downloadFile(blob, `${config.fileName}.html`);
289
+ }
290
+ handleApiExport(config) {
291
+ if (this.form.invalid)
292
+ return;
293
+ this.loading = true;
294
+ const filters = {
295
+ fileName: config.fileName || '',
296
+ query: this.queryString,
297
+ exportType: config.exportType,
298
+ columns: JSON.stringify(config.columns),
299
+ // ...this.currentFilters,
300
+ // ...this.pageFilters,
301
+ // ...(this.searchGlobal ? { filter: this.searchGlobal } : {}),
302
+ };
303
+ const params = Object.keys(filters).reduce((acc, key) => {
304
+ acc[key] = filters[key];
305
+ return acc;
306
+ }, {});
307
+ this.restService.request({
308
+ method: 'GET',
309
+ url: `/${this.apiName}/export`,
310
+ // body: { ...config.filters, ...this.model },
311
+ params: params
312
+ }, { apiName: this.apiName })
313
+ .pipe(takeUntil(this.destroy$))
314
+ .subscribe({
315
+ next: (response) => {
316
+ this.loading = false;
317
+ if (config.exportType == ExportType.EXCEL) {
318
+ const blob = this.base64ToBlob(response, 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
319
+ this.downloadFile(blob, `${config.fileName}.${this.getFileExtension(config.exportType)}`);
320
+ }
321
+ this.loading = false;
322
+ },
323
+ error: (error) => {
324
+ console.error('Export failed:', error);
325
+ this.loading = false;
326
+ }
327
+ });
328
+ }
329
+ loadPreviewData() {
330
+ if (this.form.invalid)
331
+ return;
332
+ this.loading = true;
333
+ const filters = {
334
+ query: this.queryString,
335
+ exportType: ExportType.LIST,
336
+ columns: JSON.stringify(this.getPreviewColumns()),
337
+ // ...this.currentFilters,
338
+ // ...this.pageFilters,
339
+ // ...(this.searchGlobal ? { filter: this.searchGlobal } : {}),
340
+ };
341
+ const params = Object.keys(filters).reduce((acc, key) => {
342
+ acc[key] = filters[key];
343
+ return acc;
344
+ }, {});
345
+ this.restService.request({
346
+ method: 'GET',
347
+ url: `/${this.apiName}/export`,
348
+ params: params
349
+ }, { apiName: this.apiName })
350
+ .pipe(takeUntil(this.destroy$))
351
+ .subscribe({
352
+ next: (response) => {
353
+ this.previewData = response;
354
+ this.loading = false;
355
+ },
356
+ error: (error) => {
357
+ console.error('Preview load failed:', error);
358
+ this.loading = false;
359
+ }
360
+ });
361
+ }
362
+ getPreviewColumns() {
363
+ const columns = {};
364
+ this.selectedColumns.forEach(col => {
365
+ columns[col.key] = col.customName || col.displayName;
366
+ });
367
+ return columns;
368
+ }
369
+ base64ToBlob(base64, mime) {
370
+ const byteChars = atob(base64);
371
+ const byteNums = Array.from(byteChars, c => c.charCodeAt(0));
372
+ return new Blob([new Uint8Array(byteNums)], { type: mime });
373
+ }
374
+ downloadFile(blob, fileName) {
375
+ const url = window.URL.createObjectURL(blob);
376
+ const link = document.createElement('a');
377
+ link.href = url;
378
+ link.download = fileName;
379
+ document.body.appendChild(link);
380
+ link.click();
381
+ document.body.removeChild(link);
382
+ window.URL.revokeObjectURL(url);
383
+ }
384
+ getFileExtension(exportType) {
385
+ switch (exportType) {
386
+ case ExportType.EXCEL:
387
+ return 'xlsx';
388
+ case ExportType.PDF:
389
+ return 'pdf';
390
+ case ExportType.HTML:
391
+ return 'html';
392
+ default:
393
+ return 'xlsx';
394
+ }
395
+ }
396
+ printPreview() {
397
+ const printContent = this.previewContainer.nativeElement.innerHTML;
398
+ const originalContent = document.body.innerHTML;
399
+ // Create print window
400
+ const printWindow = window.open('', '_blank', 'width=800,height=600');
401
+ if (printWindow) {
402
+ printWindow.document.write(`
403
+ <!DOCTYPE html>
404
+ <html>
405
+ <head>
406
+ <title>${this.fileName}</title>
407
+ <style>
408
+ body { font-family: Arial, sans-serif; margin: 20px; }
409
+ table { width: 100%; border-collapse: collapse; }
410
+ th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
411
+ th { background-color: #f5f5f5; font-weight: bold; }
412
+ .header { text-align: center; margin-bottom: 20px; }
413
+ .footer { text-align: center; margin-top: 20px; font-size: 12px; color: #666; }
414
+ @media print {
415
+ body { margin: 0; }
416
+ .no-print { display: none; }
417
+ }
418
+ </style>
419
+ </head>
420
+ <body>
421
+ ${printContent}
422
+ <div class="footer no-print">
423
+ <button onclick="window.print()" style="padding: 10px 20px; margin: 10px; background: #007bff; color: white; border: none; border-radius: 4px; cursor: pointer;">
424
+ Print Report
425
+ </button>
426
+ <button onclick="window.close()" style="padding: 10px 20px; margin: 10px; background: #6c757d; color: white; border: none; border-radius: 4px; cursor: pointer;">
427
+ Close
428
+ </button>
429
+ </div>
430
+ </body>
431
+ </html>
432
+ `);
433
+ printWindow.document.close();
434
+ // Auto-print when window loads
435
+ printWindow.onload = () => {
436
+ printWindow.focus();
437
+ // Uncomment the line below for auto-print
438
+ // printWindow.print();
439
+ };
440
+ }
441
+ }
442
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.8", ngImport: i0, type: GenericReportComponent, deps: [{ token: i1.DynamicDialogRef }, { token: i1.DynamicDialogConfig }], target: i0.ɵɵFactoryTarget.Component });
443
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.8", type: GenericReportComponent, isStandalone: true, selector: "app-generic-report", inputs: { filterFields: "filterFields", enableQueryBuilder: "enableQueryBuilder", localExport: "localExport", queryString: "queryString", apiName: "apiName", model: "model" }, providers: [DialogService], viewQueries: [{ propertyName: "previewContainer", first: true, predicate: ["previewContainer"], descendants: true }], ngImport: i0, template: "\r\n <div class=\"flex flex-col h-full bg-white dark:bg-gray-900 rounded-lg max-w-6xl mx-auto\">\r\n <!-- Header -->\r\n <!-- <div class=\"flex items-center justify-between px-6 py-4 border-b border-gray-200 dark:border-gray-700\">\r\n <h2 class=\"text-lg font-semibold text-gray-900 dark:text-white\">\r\n {{ 'EXPORT_DATA' | translate }}\r\n </h2>\r\n <button\r\n (click)=\"ref?.close()\"\r\n class=\"p-1 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors\"\r\n aria-label=\"Close\">\r\n <i class=\"pi pi-times text-gray-500 dark:text-gray-400\"></i>\r\n </button>\r\n </div> -->\r\n\r\n <!-- Content -->\r\n <div class=\"flex-1 overflow-hidden\">\r\n <p-tabs [value]=\"activeTabIndex\">\r\n <!-- Configuration Tab -->\r\n <p-tablist>\r\n <p-tab value=\"0\">{{'CONFIGURATION' | translate}}</p-tab>\r\n <p-tab value=\"1\">{{'PREVIEW' | translate}}</p-tab>\r\n </p-tablist>\r\n <p-tabpanels>\r\n <p-tabpanel value=\"0\">\r\n <div class=\"grid grid-cols-1 lg:grid-cols-2 gap-6 p-4 max-h-[60vh] overflow-y-auto\">\r\n <!-- Left Column - Export Settings -->\r\n <div class=\"space-y-6\">\r\n <!-- File Name -->\r\n <div class=\"space-y-2\">\r\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300\">\r\n {{ 'FILE_NAME' | translate }}\r\n </label>\r\n <input\r\n type=\"text\"\r\n [(ngModel)]=\"fileName\"\r\n class=\"w-full p-3 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-800 text-gray-900 dark:text-white focus:ring-2 focus:ring-blue-500 focus:border-blue-500\"\r\n [placeholder]=\"'ENTER_FILE_NAME' | translate\">\r\n </div>\r\n\r\n <!-- Export Type -->\r\n <div class=\"space-y-3\">\r\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300\">\r\n {{ 'EXPORT_FORMAT' | translate }}\r\n </label>\r\n <div class=\"grid grid-cols-2 gap-3\">\r\n <div *ngFor=\"let type of exportTypes\" class=\"flex items-center\">\r\n <p-radioButton\r\n [name]=\"'exportType'\"\r\n [value]=\"type.value\"\r\n [(ngModel)]=\"exportType\"\r\n [inputId]=\"`${type.value}`\"\r\n (onClick)=\"onExportTypeChange(type.value)\"\r\n class=\"mr-3\">\r\n </p-radioButton>\r\n <label [for]=\"type.value\" class=\"flex items-center cursor-pointer text-sm text-gray-700 dark:text-gray-300\">\r\n <i [class]=\"type.icon + ' mr-2'\"></i>\r\n {{ type.label | translate }}\r\n </label>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Filters Section -->\r\n <div class=\"space-y-3\">\r\n <div class=\"flex items-center justify-between\">\r\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300\">\r\n {{ 'SEARCH_FILTERS' | translate }}\r\n </label>\r\n <button\r\n type=\"button\"\r\n (click)=\"showFilters = !showFilters\"\r\n class=\"text-sm text-blue-600 dark:text-blue-400 hover:underline\">\r\n {{ showFilters ? ('HIDE_FILTERS' | translate) : ('SHOW_FILTERS' | translate) }}\r\n </button>\r\n </div>\r\n\r\n <!-- <div *ngIf=\"showFilters\" class=\"space-y-4 p-4 border border-gray-200 dark:border-gray-700 rounded-lg bg-gray-50 dark:bg-gray-800\">\r\n <formly-form\r\n [form]=\"form\"\r\n [fields]=\"fields_\"\r\n [model]=\"model\">\r\n </formly-form>\r\n </div> -->\r\n </div>\r\n </div>\r\n\r\n <!-- Right Column - Column Selection -->\r\n <div class=\"space-y-4\">\r\n <div class=\"flex items-center justify-between\">\r\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300\">\r\n {{ 'SELECT_COLUMNS' | translate }}\r\n </label>\r\n <div class=\"flex gap-2\">\r\n <button\r\n type=\"button\"\r\n (click)=\"selectAllColumns()\"\r\n class=\"text-xs text-blue-600 dark:text-blue-400 hover:underline\">\r\n {{ 'SELECT_ALL' | translate }}\r\n </button>\r\n <button\r\n type=\"button\"\r\n (click)=\"deselectAllColumns()\"\r\n class=\"text-xs text-blue-600 dark:text-blue-400 hover:underline\">\r\n {{ 'DESELECT_ALL' | translate }}\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <div class=\"max-h-80 overflow-y-auto border border-gray-200 dark:border-gray-700 rounded-lg\">\r\n <div *ngFor=\"let column of availableColumns\" class=\"flex items-center p-3 border-b border-gray-100 dark:border-gray-600 last:border-b-0 hover:bg-gray-50 dark:hover:bg-gray-700\">\r\n <p-checkbox\r\n [binary]=\"true\"\r\n [(ngModel)]=\"column.selected\"\r\n [inputId]=\"column.key\"\r\n (onChange)=\"onColumnToggle(column)\"\r\n class=\"mr-3\">\r\n </p-checkbox>\r\n <label [for]=\"column.key\" class=\"flex-1 cursor-pointer text-sm text-gray-700 dark:text-gray-300\">\r\n {{ column.displayName }}\r\n </label>\r\n <div *ngIf=\"column.selected\" class=\"flex items-center gap-2\">\r\n <input\r\n type=\"text\"\r\n [(ngModel)]=\"column.customName\"\r\n (blur)=\"onCustomNameChange(column)\"\r\n [placeholder]=\"column.displayName\"\r\n class=\"text-xs p-1 border border-gray-300 dark:border-gray-600 rounded bg-white dark:bg-gray-800 text-gray-900 dark:text-white w-32\"\r\n [title]=\"'CUSTOM_COLUMN_NAME' | translate\">\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Selected Columns Summary -->\r\n <div *ngIf=\"selectedColumns.length > 0\" class=\"p-3 bg-blue-50 dark:bg-blue-900/20 rounded-lg\">\r\n <p class=\"text-sm text-blue-700 dark:text-blue-300\">\r\n {{ 'SELECTED_COLUMNS_COUNT' | translate: { count: selectedColumns.length } }}\r\n </p>\r\n </div>\r\n </div>\r\n </div>\r\n </p-tabpanel>\r\n\r\n <!-- Preview Tab -->\r\n <!-- [disabled]=\"selectedColumns.length === 0\" -->\r\n <p-tabpanel value=\"1\" >\r\n <div class=\"p-4 max-h-[60vh] overflow-y-auto\">\r\n <!-- Preview Actions -->\r\n <div class=\"flex justify-between items-center mb-4\">\r\n <h3 class=\"text-lg font-semibold text-gray-900 dark:text-white\">\r\n {{ 'REPORT_PREVIEW' | translate }}\r\n </h3>\r\n <div class=\"flex gap-2\">\r\n <button\r\n *ngIf=\"exportType === 1 || exportType === 4\"\r\n (click)=\"printPreview()\"\r\n class=\"flex items-center px-4 py-2 text-sm font-medium text-gray-700 dark:text-gray-300 border border-gray-300 dark:border-gray-600 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors\">\r\n <i class=\"pi pi-print mr-2\"></i>\r\n {{ 'PRINT' | translate }}\r\n </button>\r\n <button\r\n (click)=\"generatePreview()\"\r\n class=\"flex items-center px-4 py-2 text-sm font-medium text-white bg-blue-600 rounded-lg hover:bg-blue-700 transition-colors\">\r\n <i class=\"pi pi-refresh mr-2\"></i>\r\n {{ 'REFRESH_PREVIEW' | translate }}\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <!-- Preview Content -->\r\n <div #previewContainer class=\"bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg p-6\">\r\n <!-- Report Header -->\r\n <div class=\"text-center mb-6 border-b border-gray-200 dark:border-gray-700 pb-4\">\r\n <h1 class=\"text-2xl font-bold text-gray-900 dark:text-white\">{{ fileName }}</h1>\r\n <p class=\"text-gray-600 dark:text-gray-400 mt-2\">\r\n {{ 'GENERATED_ON' | translate }}: {{ currentDate | date:'medium' }}\r\n </p>\r\n </div>\r\n\r\n <!-- Report Table -->\r\n <div class=\"overflow-x-auto\">\r\n <table class=\"min-w-full divide-y divide-gray-200 dark:divide-gray-700\">\r\n <thead class=\"bg-gray-50 dark:bg-gray-700\">\r\n <tr>\r\n <th\r\n *ngFor=\"let column of selectedColumns\"\r\n class=\"px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider border border-gray-200 dark:border-gray-600\">\r\n {{ column.customName || column.displayName }}\r\n </th>\r\n </tr>\r\n </thead>\r\n <tbody class=\"bg-white dark:bg-gray-800 divide-y divide-gray-200 dark:divide-gray-700\">\r\n <tr *ngFor=\"let row of previewData; let i = index\"\r\n [class.bg-gray-50]=\"i % 2 === 0\"\r\n [class.dark:bg-gray-900]=\"i % 2 === 0\">\r\n <td\r\n *ngFor=\"let column of selectedColumns\"\r\n class=\"px-6 py-4 whitespace-nowrap text-sm text-gray-900 dark:text-white border border-gray-200 dark:border-gray-600\">\r\n {{ getPreviewValue(row, column.key) }}\r\n </td>\r\n </tr>\r\n </tbody>\r\n </table>\r\n </div>\r\n\r\n <!-- Empty State -->\r\n <div *ngIf=\"previewData.length === 0\" class=\"text-center py-8\">\r\n <i class=\"pi pi-inbox text-4xl text-gray-400 dark:text-gray-500 mb-4\"></i>\r\n <p class=\"text-gray-500 dark:text-gray-400\">{{ 'NO_PREVIEW_DATA' | translate }}</p>\r\n <button\r\n (click)=\"generatePreview()\"\r\n class=\"mt-4 px-4 py-2 text-sm font-medium text-blue-600 dark:text-blue-400 hover:underline\">\r\n {{ 'GENERATE_PREVIEW' | translate }}\r\n </button>\r\n </div>\r\n\r\n <!-- Report Footer -->\r\n <div class=\"text-center mt-6 border-t border-gray-200 dark:border-gray-700 pt-4\">\r\n <p class=\"text-sm text-gray-500 dark:text-gray-400\">\r\n {{ 'PAGE' | translate }} 1 of 1\r\n </p>\r\n </div>\r\n </div>\r\n\r\n <!-- Preview Info -->\r\n <div class=\"mt-4 p-3 bg-green-50 dark:bg-green-900/20 rounded-lg\">\r\n <p class=\"text-sm text-green-700 dark:text-green-300\">\r\n <i class=\"pi pi-info-circle mr-2\"></i>\r\n {{ 'PREVIEW_INFO' | translate }}\r\n </p>\r\n </div>\r\n </div>\r\n </p-tabpanel>\r\n\r\n </p-tabpanels>\r\n </p-tabs>\r\n </div>\r\n\r\n <!-- Footer -->\r\n <div class=\"border-t border-gray-200 dark:border-gray-700 px-6 py-4 bg-gray-50 dark:bg-gray-800\">\r\n <div class=\"flex justify-between items-center\">\r\n <button\r\n type=\"button\"\r\n (click)=\"onReset()\"\r\n class=\"flex items-center px-4 py-2 text-sm font-medium text-gray-700 dark:text-gray-300 hover:text-gray-900 dark:hover:text-white hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg transition-colors\"\r\n [disabled]=\"loading\">\r\n <i class=\"pi pi-refresh ml-2\"></i>\r\n {{ 'RESET' | translate }}\r\n </button>\r\n\r\n <div class=\"flex gap-2\">\r\n <button\r\n type=\"button\"\r\n (click)=\"ref?.close()\"\r\n class=\"px-4 py-2 text-sm font-medium text-gray-700 dark:text-gray-300 border border-gray-300 dark:border-gray-600 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors\"\r\n [disabled]=\"loading\">\r\n {{ 'CANCEL' | translate }}\r\n </button>\r\n\r\n <button\r\n type=\"button\"\r\n (click)=\"onExport()\"\r\n [disabled]=\"loading || selectedColumns.length === 0\"\r\n class=\"flex items-center px-4 py-2 text-sm font-medium text-white bg-blue-600 rounded-lg hover:bg-blue-700 disabled:bg-gray-300 disabled:cursor-not-allowed transition-colors\">\r\n <i class=\"pi pi-download ml-2\" [class.animate-spin]=\"loading\"></i>\r\n {{ getExportButtonText() }}\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n @if(showFilters){\r\n<p-drawer\r\n [(visible)]=\"showFilters\"\r\n position=\"right\"\r\n [styleClass]=\"'!w-full md:!w-80 lg:!w-[40rem] !h-full' \"\r\n [modal]=\"true\"\r\n [dismissible]=\"true\"\r\n styleClass=\"p-4 w-full max-w-md max-h-[90vh] flex flex-col\"\r\n>\r\n <!-- Entire form wrapper -->\r\n <form [formGroup]=\"form\" (ngSubmit)=\"onSubmit(); showFilters=false\" class=\"flex flex-col flex-1\">\r\n <!-- Scrollable Form -->\r\n <div class=\"flex-1 overflow-auto\">\r\n <formly-form\r\n [form]=\"form\"\r\n [fields]=\"fields_\"\r\n [model]=\"model\"\r\n [options]=\"options\"\r\n >\r\n </formly-form>\r\n </div>\r\n\r\n </form>\r\n <!-- Action Buttons -->\r\n <ng-template pTemplate=\"footer\">\r\n <div class=\"flex justify-end mt-2 space-x-2 flex-none\">\r\n <button\r\n type=\"submit\"\r\n pButton size=\"small\"\r\n (click)=\" onSubmit(); showFilters=false\"\r\n label=\"{{ 'SEARCH' | translate }}\">\r\n </button>\r\n <button\r\n type=\"button\"\r\n pButton\r\n size=\"small\"\r\n class=\"p-button-text\"\r\n (click)=\"onReset(); showFilters=false\"\r\n >\r\n {{ 'CLEAR' | translate }}\r\n </button>\r\n </div>\r\n </ng-template>\r\n</p-drawer>\r\n\r\n }\r\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i3.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i3.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i4.ButtonDirective, selector: "[pButton]", inputs: ["iconPos", "loadingIcon", "loading", "severity", "raised", "rounded", "text", "outlined", "size", "plain", "fluid", "label", "icon", "buttonProps"] }, { kind: "directive", type: i5.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: DialogModule }, { kind: "ngmodule", type: SelectModule }, { kind: "ngmodule", type: MultiSelectModule }, { kind: "ngmodule", type: InputTextModule }, { kind: "ngmodule", type: RadioButtonModule }, { kind: "component", type: i6.RadioButton, selector: "p-radioButton, p-radiobutton, p-radio-button", inputs: ["value", "tabindex", "inputId", "ariaLabelledBy", "ariaLabel", "styleClass", "autofocus", "binary", "variant", "size"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: CheckboxModule }, { kind: "component", type: i7.Checkbox, selector: "p-checkbox, p-checkBox, p-check-box", inputs: ["value", "binary", "ariaLabelledBy", "ariaLabel", "tabindex", "inputId", "inputStyle", "styleClass", "inputClass", "indeterminate", "formControl", "checkboxIcon", "readonly", "autofocus", "trueValue", "falseValue", "variant", "size"], outputs: ["onChange", "onFocus", "onBlur"] }, { kind: "ngmodule", type: CardModule }, { kind: "ngmodule", type: DividerModule }, { kind: "ngmodule", type: TabsModule }, { kind: "component", type: i8.Tabs, selector: "p-tabs", inputs: ["value", "scrollable", "lazy", "selectOnFocus", "showNavigators", "tabindex"], outputs: ["valueChange"] }, { kind: "component", type: i8.TabPanels, selector: "p-tabpanels" }, { kind: "component", type: i8.TabPanel, selector: "p-tabpanel", inputs: ["value"], outputs: ["valueChange"] }, { kind: "component", type: i8.TabList, selector: "p-tablist" }, { kind: "component", type: i8.Tab, selector: "p-tab", inputs: ["value", "disabled"], outputs: ["valueChange"] }, { kind: "ngmodule", type: FormlyModule }, { kind: "component", type: i9.LegacyFormlyForm, selector: "formly-form" }, { kind: "ngmodule", type: DynamicDialogModule }, { kind: "ngmodule", type: DrawerModule }, { kind: "component", type: i10.Drawer, selector: "p-drawer", inputs: ["appendTo", "blockScroll", "style", "styleClass", "ariaCloseLabel", "autoZIndex", "baseZIndex", "modal", "closeButtonProps", "dismissible", "showCloseIcon", "closeOnEscape", "transitionOptions", "visible", "position", "fullScreen", "header", "maskStyle", "closable"], outputs: ["onShow", "onHide", "visibleChange"] }, { kind: "pipe", type: i2.DatePipe, name: "date" }, { kind: "pipe", type: i11.TranslatePipe, name: "translate" }] });
444
+ }
445
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.8", ngImport: i0, type: GenericReportComponent, decorators: [{
446
+ type: Component,
447
+ args: [{ selector: 'app-generic-report', providers: [DialogService], imports: [
448
+ CommonModule,
449
+ ReactiveFormsModule,
450
+ FormsModule,
451
+ TranslateModule,
452
+ ButtonModule,
453
+ DialogModule,
454
+ SelectModule,
455
+ MultiSelectModule,
456
+ InputTextModule,
457
+ RadioButtonModule,
458
+ CheckboxModule,
459
+ CardModule,
460
+ DividerModule,
461
+ TabsModule,
462
+ FormlyModule,
463
+ DynamicDialogModule,
464
+ DrawerModule
465
+ ], template: "\r\n <div class=\"flex flex-col h-full bg-white dark:bg-gray-900 rounded-lg max-w-6xl mx-auto\">\r\n <!-- Header -->\r\n <!-- <div class=\"flex items-center justify-between px-6 py-4 border-b border-gray-200 dark:border-gray-700\">\r\n <h2 class=\"text-lg font-semibold text-gray-900 dark:text-white\">\r\n {{ 'EXPORT_DATA' | translate }}\r\n </h2>\r\n <button\r\n (click)=\"ref?.close()\"\r\n class=\"p-1 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors\"\r\n aria-label=\"Close\">\r\n <i class=\"pi pi-times text-gray-500 dark:text-gray-400\"></i>\r\n </button>\r\n </div> -->\r\n\r\n <!-- Content -->\r\n <div class=\"flex-1 overflow-hidden\">\r\n <p-tabs [value]=\"activeTabIndex\">\r\n <!-- Configuration Tab -->\r\n <p-tablist>\r\n <p-tab value=\"0\">{{'CONFIGURATION' | translate}}</p-tab>\r\n <p-tab value=\"1\">{{'PREVIEW' | translate}}</p-tab>\r\n </p-tablist>\r\n <p-tabpanels>\r\n <p-tabpanel value=\"0\">\r\n <div class=\"grid grid-cols-1 lg:grid-cols-2 gap-6 p-4 max-h-[60vh] overflow-y-auto\">\r\n <!-- Left Column - Export Settings -->\r\n <div class=\"space-y-6\">\r\n <!-- File Name -->\r\n <div class=\"space-y-2\">\r\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300\">\r\n {{ 'FILE_NAME' | translate }}\r\n </label>\r\n <input\r\n type=\"text\"\r\n [(ngModel)]=\"fileName\"\r\n class=\"w-full p-3 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-800 text-gray-900 dark:text-white focus:ring-2 focus:ring-blue-500 focus:border-blue-500\"\r\n [placeholder]=\"'ENTER_FILE_NAME' | translate\">\r\n </div>\r\n\r\n <!-- Export Type -->\r\n <div class=\"space-y-3\">\r\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300\">\r\n {{ 'EXPORT_FORMAT' | translate }}\r\n </label>\r\n <div class=\"grid grid-cols-2 gap-3\">\r\n <div *ngFor=\"let type of exportTypes\" class=\"flex items-center\">\r\n <p-radioButton\r\n [name]=\"'exportType'\"\r\n [value]=\"type.value\"\r\n [(ngModel)]=\"exportType\"\r\n [inputId]=\"`${type.value}`\"\r\n (onClick)=\"onExportTypeChange(type.value)\"\r\n class=\"mr-3\">\r\n </p-radioButton>\r\n <label [for]=\"type.value\" class=\"flex items-center cursor-pointer text-sm text-gray-700 dark:text-gray-300\">\r\n <i [class]=\"type.icon + ' mr-2'\"></i>\r\n {{ type.label | translate }}\r\n </label>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Filters Section -->\r\n <div class=\"space-y-3\">\r\n <div class=\"flex items-center justify-between\">\r\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300\">\r\n {{ 'SEARCH_FILTERS' | translate }}\r\n </label>\r\n <button\r\n type=\"button\"\r\n (click)=\"showFilters = !showFilters\"\r\n class=\"text-sm text-blue-600 dark:text-blue-400 hover:underline\">\r\n {{ showFilters ? ('HIDE_FILTERS' | translate) : ('SHOW_FILTERS' | translate) }}\r\n </button>\r\n </div>\r\n\r\n <!-- <div *ngIf=\"showFilters\" class=\"space-y-4 p-4 border border-gray-200 dark:border-gray-700 rounded-lg bg-gray-50 dark:bg-gray-800\">\r\n <formly-form\r\n [form]=\"form\"\r\n [fields]=\"fields_\"\r\n [model]=\"model\">\r\n </formly-form>\r\n </div> -->\r\n </div>\r\n </div>\r\n\r\n <!-- Right Column - Column Selection -->\r\n <div class=\"space-y-4\">\r\n <div class=\"flex items-center justify-between\">\r\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300\">\r\n {{ 'SELECT_COLUMNS' | translate }}\r\n </label>\r\n <div class=\"flex gap-2\">\r\n <button\r\n type=\"button\"\r\n (click)=\"selectAllColumns()\"\r\n class=\"text-xs text-blue-600 dark:text-blue-400 hover:underline\">\r\n {{ 'SELECT_ALL' | translate }}\r\n </button>\r\n <button\r\n type=\"button\"\r\n (click)=\"deselectAllColumns()\"\r\n class=\"text-xs text-blue-600 dark:text-blue-400 hover:underline\">\r\n {{ 'DESELECT_ALL' | translate }}\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <div class=\"max-h-80 overflow-y-auto border border-gray-200 dark:border-gray-700 rounded-lg\">\r\n <div *ngFor=\"let column of availableColumns\" class=\"flex items-center p-3 border-b border-gray-100 dark:border-gray-600 last:border-b-0 hover:bg-gray-50 dark:hover:bg-gray-700\">\r\n <p-checkbox\r\n [binary]=\"true\"\r\n [(ngModel)]=\"column.selected\"\r\n [inputId]=\"column.key\"\r\n (onChange)=\"onColumnToggle(column)\"\r\n class=\"mr-3\">\r\n </p-checkbox>\r\n <label [for]=\"column.key\" class=\"flex-1 cursor-pointer text-sm text-gray-700 dark:text-gray-300\">\r\n {{ column.displayName }}\r\n </label>\r\n <div *ngIf=\"column.selected\" class=\"flex items-center gap-2\">\r\n <input\r\n type=\"text\"\r\n [(ngModel)]=\"column.customName\"\r\n (blur)=\"onCustomNameChange(column)\"\r\n [placeholder]=\"column.displayName\"\r\n class=\"text-xs p-1 border border-gray-300 dark:border-gray-600 rounded bg-white dark:bg-gray-800 text-gray-900 dark:text-white w-32\"\r\n [title]=\"'CUSTOM_COLUMN_NAME' | translate\">\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Selected Columns Summary -->\r\n <div *ngIf=\"selectedColumns.length > 0\" class=\"p-3 bg-blue-50 dark:bg-blue-900/20 rounded-lg\">\r\n <p class=\"text-sm text-blue-700 dark:text-blue-300\">\r\n {{ 'SELECTED_COLUMNS_COUNT' | translate: { count: selectedColumns.length } }}\r\n </p>\r\n </div>\r\n </div>\r\n </div>\r\n </p-tabpanel>\r\n\r\n <!-- Preview Tab -->\r\n <!-- [disabled]=\"selectedColumns.length === 0\" -->\r\n <p-tabpanel value=\"1\" >\r\n <div class=\"p-4 max-h-[60vh] overflow-y-auto\">\r\n <!-- Preview Actions -->\r\n <div class=\"flex justify-between items-center mb-4\">\r\n <h3 class=\"text-lg font-semibold text-gray-900 dark:text-white\">\r\n {{ 'REPORT_PREVIEW' | translate }}\r\n </h3>\r\n <div class=\"flex gap-2\">\r\n <button\r\n *ngIf=\"exportType === 1 || exportType === 4\"\r\n (click)=\"printPreview()\"\r\n class=\"flex items-center px-4 py-2 text-sm font-medium text-gray-700 dark:text-gray-300 border border-gray-300 dark:border-gray-600 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors\">\r\n <i class=\"pi pi-print mr-2\"></i>\r\n {{ 'PRINT' | translate }}\r\n </button>\r\n <button\r\n (click)=\"generatePreview()\"\r\n class=\"flex items-center px-4 py-2 text-sm font-medium text-white bg-blue-600 rounded-lg hover:bg-blue-700 transition-colors\">\r\n <i class=\"pi pi-refresh mr-2\"></i>\r\n {{ 'REFRESH_PREVIEW' | translate }}\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <!-- Preview Content -->\r\n <div #previewContainer class=\"bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg p-6\">\r\n <!-- Report Header -->\r\n <div class=\"text-center mb-6 border-b border-gray-200 dark:border-gray-700 pb-4\">\r\n <h1 class=\"text-2xl font-bold text-gray-900 dark:text-white\">{{ fileName }}</h1>\r\n <p class=\"text-gray-600 dark:text-gray-400 mt-2\">\r\n {{ 'GENERATED_ON' | translate }}: {{ currentDate | date:'medium' }}\r\n </p>\r\n </div>\r\n\r\n <!-- Report Table -->\r\n <div class=\"overflow-x-auto\">\r\n <table class=\"min-w-full divide-y divide-gray-200 dark:divide-gray-700\">\r\n <thead class=\"bg-gray-50 dark:bg-gray-700\">\r\n <tr>\r\n <th\r\n *ngFor=\"let column of selectedColumns\"\r\n class=\"px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider border border-gray-200 dark:border-gray-600\">\r\n {{ column.customName || column.displayName }}\r\n </th>\r\n </tr>\r\n </thead>\r\n <tbody class=\"bg-white dark:bg-gray-800 divide-y divide-gray-200 dark:divide-gray-700\">\r\n <tr *ngFor=\"let row of previewData; let i = index\"\r\n [class.bg-gray-50]=\"i % 2 === 0\"\r\n [class.dark:bg-gray-900]=\"i % 2 === 0\">\r\n <td\r\n *ngFor=\"let column of selectedColumns\"\r\n class=\"px-6 py-4 whitespace-nowrap text-sm text-gray-900 dark:text-white border border-gray-200 dark:border-gray-600\">\r\n {{ getPreviewValue(row, column.key) }}\r\n </td>\r\n </tr>\r\n </tbody>\r\n </table>\r\n </div>\r\n\r\n <!-- Empty State -->\r\n <div *ngIf=\"previewData.length === 0\" class=\"text-center py-8\">\r\n <i class=\"pi pi-inbox text-4xl text-gray-400 dark:text-gray-500 mb-4\"></i>\r\n <p class=\"text-gray-500 dark:text-gray-400\">{{ 'NO_PREVIEW_DATA' | translate }}</p>\r\n <button\r\n (click)=\"generatePreview()\"\r\n class=\"mt-4 px-4 py-2 text-sm font-medium text-blue-600 dark:text-blue-400 hover:underline\">\r\n {{ 'GENERATE_PREVIEW' | translate }}\r\n </button>\r\n </div>\r\n\r\n <!-- Report Footer -->\r\n <div class=\"text-center mt-6 border-t border-gray-200 dark:border-gray-700 pt-4\">\r\n <p class=\"text-sm text-gray-500 dark:text-gray-400\">\r\n {{ 'PAGE' | translate }} 1 of 1\r\n </p>\r\n </div>\r\n </div>\r\n\r\n <!-- Preview Info -->\r\n <div class=\"mt-4 p-3 bg-green-50 dark:bg-green-900/20 rounded-lg\">\r\n <p class=\"text-sm text-green-700 dark:text-green-300\">\r\n <i class=\"pi pi-info-circle mr-2\"></i>\r\n {{ 'PREVIEW_INFO' | translate }}\r\n </p>\r\n </div>\r\n </div>\r\n </p-tabpanel>\r\n\r\n </p-tabpanels>\r\n </p-tabs>\r\n </div>\r\n\r\n <!-- Footer -->\r\n <div class=\"border-t border-gray-200 dark:border-gray-700 px-6 py-4 bg-gray-50 dark:bg-gray-800\">\r\n <div class=\"flex justify-between items-center\">\r\n <button\r\n type=\"button\"\r\n (click)=\"onReset()\"\r\n class=\"flex items-center px-4 py-2 text-sm font-medium text-gray-700 dark:text-gray-300 hover:text-gray-900 dark:hover:text-white hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg transition-colors\"\r\n [disabled]=\"loading\">\r\n <i class=\"pi pi-refresh ml-2\"></i>\r\n {{ 'RESET' | translate }}\r\n </button>\r\n\r\n <div class=\"flex gap-2\">\r\n <button\r\n type=\"button\"\r\n (click)=\"ref?.close()\"\r\n class=\"px-4 py-2 text-sm font-medium text-gray-700 dark:text-gray-300 border border-gray-300 dark:border-gray-600 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors\"\r\n [disabled]=\"loading\">\r\n {{ 'CANCEL' | translate }}\r\n </button>\r\n\r\n <button\r\n type=\"button\"\r\n (click)=\"onExport()\"\r\n [disabled]=\"loading || selectedColumns.length === 0\"\r\n class=\"flex items-center px-4 py-2 text-sm font-medium text-white bg-blue-600 rounded-lg hover:bg-blue-700 disabled:bg-gray-300 disabled:cursor-not-allowed transition-colors\">\r\n <i class=\"pi pi-download ml-2\" [class.animate-spin]=\"loading\"></i>\r\n {{ getExportButtonText() }}\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n @if(showFilters){\r\n<p-drawer\r\n [(visible)]=\"showFilters\"\r\n position=\"right\"\r\n [styleClass]=\"'!w-full md:!w-80 lg:!w-[40rem] !h-full' \"\r\n [modal]=\"true\"\r\n [dismissible]=\"true\"\r\n styleClass=\"p-4 w-full max-w-md max-h-[90vh] flex flex-col\"\r\n>\r\n <!-- Entire form wrapper -->\r\n <form [formGroup]=\"form\" (ngSubmit)=\"onSubmit(); showFilters=false\" class=\"flex flex-col flex-1\">\r\n <!-- Scrollable Form -->\r\n <div class=\"flex-1 overflow-auto\">\r\n <formly-form\r\n [form]=\"form\"\r\n [fields]=\"fields_\"\r\n [model]=\"model\"\r\n [options]=\"options\"\r\n >\r\n </formly-form>\r\n </div>\r\n\r\n </form>\r\n <!-- Action Buttons -->\r\n <ng-template pTemplate=\"footer\">\r\n <div class=\"flex justify-end mt-2 space-x-2 flex-none\">\r\n <button\r\n type=\"submit\"\r\n pButton size=\"small\"\r\n (click)=\" onSubmit(); showFilters=false\"\r\n label=\"{{ 'SEARCH' | translate }}\">\r\n </button>\r\n <button\r\n type=\"button\"\r\n pButton\r\n size=\"small\"\r\n class=\"p-button-text\"\r\n (click)=\"onReset(); showFilters=false\"\r\n >\r\n {{ 'CLEAR' | translate }}\r\n </button>\r\n </div>\r\n </ng-template>\r\n</p-drawer>\r\n\r\n }\r\n" }]
466
+ }], ctorParameters: () => [{ type: i1.DynamicDialogRef }, { type: i1.DynamicDialogConfig }], propDecorators: { previewContainer: [{
467
+ type: ViewChild,
468
+ args: ['previewContainer']
469
+ }], filterFields: [{
470
+ type: Input
471
+ }], enableQueryBuilder: [{
472
+ type: Input
473
+ }], localExport: [{
474
+ type: Input
475
+ }], queryString: [{
476
+ type: Input
477
+ }], apiName: [{
478
+ type: Input
479
+ }], model: [{
480
+ type: Input
481
+ }] } });
482
+
483
+ /**
484
+ * Generated bundle index. Do not edit.
485
+ */
486
+
487
+ export { ExportType, GenericReportComponent, GenericReportModule };
488
+ //# sourceMappingURL=elite.framework-ng.ui.core-generic-report.mjs.map