@masterteam/dashboard-builder 0.0.1

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,595 @@
1
+ import * as i0 from '@angular/core';
2
+ import { inject, Injectable, input, signal, computed, Component } from '@angular/core';
3
+ import { CommonModule } from '@angular/common';
4
+ import { TranslocoService, TranslocoDirective } from '@jsverse/transloco';
5
+ import { ModalService } from '@masterteam/components/modal';
6
+ import { ModalRef } from '@masterteam/components/dialog';
7
+ import { Button } from '@masterteam/components/button';
8
+ import { DashboardItemStoreService, DashboardItem } from './masterteam-dashboard-builder.mjs';
9
+
10
+ /**
11
+ * Filter Utilities Service
12
+ *
13
+ * Handles dynamic filter processing for dashboard charts.
14
+ * Replaces old handleFilters.ts functionality.
15
+ */
16
+ class FilterUtilsService {
17
+ transloco = inject(TranslocoService);
18
+ // Registry of function placeholders
19
+ functionPlaceholders = {
20
+ startOfMonth: {
21
+ pattern: /^startOfMonth\((.+?),(.+?)\)$/,
22
+ handler: (args, params) => {
23
+ const month = parseInt(String(this.resolveValueForParam(args[0], params)), 10);
24
+ const year = parseInt(String(this.resolveValueForParam(args[1], params)), 10);
25
+ if (month && year) {
26
+ return this.formatDateDMY(1, month, year);
27
+ }
28
+ return '';
29
+ },
30
+ },
31
+ endOfMonth: {
32
+ pattern: /^endOfMonth\((.+?),(.+?)\)$/,
33
+ handler: (args, params) => {
34
+ const month = parseInt(String(this.resolveValueForParam(args[0], params)), 10);
35
+ const year = parseInt(String(this.resolveValueForParam(args[1], params)), 10);
36
+ if (month && year) {
37
+ const lastDay = this.getLastDayOfMonth(month, year);
38
+ return this.formatDateDMY(lastDay, month, year);
39
+ }
40
+ return '';
41
+ },
42
+ },
43
+ monthRange: {
44
+ pattern: /^monthRange\((.+?),(.+?)\)$/,
45
+ handler: (args, params) => {
46
+ const month = parseInt(String(this.resolveValueForParam(args[0], params)), 10);
47
+ const year = parseInt(String(this.resolveValueForParam(args[1], params)), 10);
48
+ if (month && year) {
49
+ const startDate = this.formatDateDMY(1, month, year);
50
+ const lastDay = this.getLastDayOfMonth(month, year);
51
+ const endDate = this.formatDateDMY(lastDay, month, year);
52
+ return `${startDate},${endDate}`;
53
+ }
54
+ return '';
55
+ },
56
+ },
57
+ };
58
+ /**
59
+ * Handle filters for custom chart requests
60
+ */
61
+ handleFiltersForCustom(configItem, params, extraFilters) {
62
+ // Deep clone to avoid mutation
63
+ const config = JSON.parse(JSON.stringify(configItem));
64
+ // Process selections
65
+ config.selection?.forEach((selection) => {
66
+ // Replace placeholders in moduleId
67
+ if (typeof selection.moduleId === 'string') {
68
+ selection.moduleId = this.dynamicTextReplace(selection.moduleId, params);
69
+ }
70
+ // Add dynamic filters from extraFilters
71
+ if (extraFilters?.dynamicFilters?.length) {
72
+ extraFilters.dynamicFilters.forEach((dynamicFilter) => {
73
+ const filterKey = dynamicFilter.key;
74
+ const paramValue = params?.[filterKey];
75
+ if (paramValue !== undefined &&
76
+ paramValue !== null &&
77
+ paramValue !== '') {
78
+ const configuration = dynamicFilter.configuration;
79
+ const templateFilter = configuration?.payload?.selection?.[0]?.filters?.[0];
80
+ if (templateFilter) {
81
+ const newFilter = {
82
+ propertyKey: templateFilter.propertyKey,
83
+ propertyValue: paramValue,
84
+ operation: configuration?.isMultiple ? 'OneOf' : 'Equal',
85
+ logical: 'And',
86
+ operationLevel: null,
87
+ };
88
+ if (templateFilter.propertyData) {
89
+ newFilter.propertyData = templateFilter.propertyData;
90
+ }
91
+ if (!selection.filters) {
92
+ selection.filters = [];
93
+ }
94
+ selection.filters.push(newFilter);
95
+ }
96
+ }
97
+ });
98
+ }
99
+ // Process and filter existing filters
100
+ selection.filters = selection.filters?.filter((filter) => {
101
+ let shouldKeepFilter = true;
102
+ let newPropertyValue = filter.propertyValue;
103
+ // Handle placeholders in filter.propertyValue
104
+ if (typeof newPropertyValue === 'string') {
105
+ const matches = newPropertyValue.match(/{{(.*?)}}(\?)?/g);
106
+ if (matches) {
107
+ for (const match of matches) {
108
+ const processedValue = this.processCommaPlaceholders(match, params);
109
+ if (processedValue === null) {
110
+ shouldKeepFilter = false;
111
+ break;
112
+ }
113
+ newPropertyValue = newPropertyValue.replace(match, processedValue);
114
+ }
115
+ if (shouldKeepFilter) {
116
+ newPropertyValue =
117
+ this.resolvePlaceholdersRecursively(newPropertyValue, params) ||
118
+ newPropertyValue;
119
+ filter.propertyValue = newPropertyValue;
120
+ }
121
+ }
122
+ }
123
+ // Remove if propertyValue is 'ignoreFilter'
124
+ if (shouldKeepFilter && filter.propertyValue === 'ignoreFilter') {
125
+ shouldKeepFilter = false;
126
+ }
127
+ // Check relations for conditional removal
128
+ if (shouldKeepFilter && Array.isArray(filter.relations)) {
129
+ for (const relation of filter.relations) {
130
+ if (relation.type === 'realationBetweenPageFilters') {
131
+ const paramVal = params?.[relation.key];
132
+ if (relation.value === 'deleteIfThereValue' && paramVal) {
133
+ shouldKeepFilter = false;
134
+ break;
135
+ }
136
+ else if (relation.value === 'deleteIfThereNoValue' &&
137
+ !paramVal) {
138
+ shouldKeepFilter = false;
139
+ break;
140
+ }
141
+ }
142
+ }
143
+ }
144
+ return shouldKeepFilter;
145
+ });
146
+ // Clean up empty properties on filters
147
+ selection.filters?.forEach((filter) => {
148
+ if (!filter?.operation)
149
+ delete filter.operation;
150
+ if (!filter?.operationLevel)
151
+ delete filter.operationLevel;
152
+ if (!filter?.logical)
153
+ delete filter.logical;
154
+ });
155
+ });
156
+ return config;
157
+ }
158
+ /**
159
+ * Handle filters for card/overview requests
160
+ */
161
+ handleFilterForCard(filters, params) {
162
+ const filteredList = filters.filter((filter) => {
163
+ const propertyValue = filter.propertyValue;
164
+ const matches = propertyValue?.match(/{{(.*?)}}(\?)?/g);
165
+ let shouldKeepFilter = true;
166
+ let newPropertyValue = propertyValue;
167
+ if (matches) {
168
+ for (const match of matches) {
169
+ const processedValue = this.processCommaPlaceholders(match, params);
170
+ if (processedValue === null) {
171
+ shouldKeepFilter = false;
172
+ break;
173
+ }
174
+ newPropertyValue = newPropertyValue.replace(match, processedValue);
175
+ }
176
+ if (shouldKeepFilter) {
177
+ newPropertyValue =
178
+ this.resolvePlaceholdersRecursively(newPropertyValue, params) ||
179
+ newPropertyValue;
180
+ filter.propertyValue = newPropertyValue;
181
+ }
182
+ }
183
+ return shouldKeepFilter;
184
+ });
185
+ const result = {};
186
+ filteredList.forEach((filter) => {
187
+ result[filter.propertyKey] = filter.propertyValue;
188
+ });
189
+ return result;
190
+ }
191
+ /**
192
+ * Handle filter for snapshot requests
193
+ */
194
+ handleFilterForSnapshot(levelId, params) {
195
+ return this.dynamicTextReplace(levelId, params);
196
+ }
197
+ /**
198
+ * Replace dynamic placeholders in text
199
+ */
200
+ dynamicTextReplace(text, params, keepIfNotFound = false) {
201
+ if (!text)
202
+ return '';
203
+ const enrichedParams = {
204
+ ...params,
205
+ currentYear: new Date().getFullYear().toString(),
206
+ currentWeek: this.getCurrentWeekOfYear().toString(),
207
+ createdAt: new Date().toLocaleDateString('en-US', {
208
+ day: 'numeric',
209
+ month: 'long',
210
+ year: 'numeric',
211
+ }),
212
+ };
213
+ return text.replace(/\{\{([\w.]+)\}\}/g, (match, key) => {
214
+ let value = this.getNestedValue(enrichedParams, key);
215
+ // Case-insensitive fallback
216
+ if (value === undefined) {
217
+ const lowerKey = key.toLowerCase();
218
+ const foundKey = Object.keys(enrichedParams).find((k) => k.toLowerCase() === lowerKey);
219
+ if (foundKey) {
220
+ value = this.getNestedValue(enrichedParams, foundKey);
221
+ }
222
+ }
223
+ return value !== undefined ? String(value) : keepIfNotFound ? match : '';
224
+ });
225
+ }
226
+ // ============================================
227
+ // Private Helper Methods
228
+ // ============================================
229
+ resolveValueForParam(value, params) {
230
+ const orParts = value.split('||').map((p) => p.trim());
231
+ for (const part of orParts) {
232
+ if (!isNaN(Number(part))) {
233
+ return Number(part);
234
+ }
235
+ const paramValue = this.getNestedValue(params, part);
236
+ if (paramValue !== undefined &&
237
+ paramValue !== null &&
238
+ paramValue !== '') {
239
+ return paramValue;
240
+ }
241
+ }
242
+ return null;
243
+ }
244
+ getLastDayOfMonth(month, year) {
245
+ return new Date(year, month, 0).getDate();
246
+ }
247
+ formatDateDMY(day, month, year) {
248
+ const dd = String(day).padStart(2, '0');
249
+ const mm = String(month).padStart(2, '0');
250
+ return `${dd}-${mm}-${year}`;
251
+ }
252
+ getCurrentWeekOfYear() {
253
+ const now = new Date();
254
+ const start = new Date(now.getFullYear(), 0, 1);
255
+ const diff = now.getTime() - start.getTime();
256
+ const oneWeek = 1000 * 60 * 60 * 24 * 7;
257
+ return Math.ceil(diff / oneWeek);
258
+ }
259
+ getNestedValue(obj, path) {
260
+ return path.split('.').reduce((current, key) => current?.[key], obj);
261
+ }
262
+ processFunctionPlaceholder(placeholder, params) {
263
+ for (const funcName in this.functionPlaceholders) {
264
+ const { pattern, handler } = this.functionPlaceholders[funcName];
265
+ const match = placeholder.match(pattern);
266
+ if (match) {
267
+ const args = match.slice(1).map((arg) => arg.trim());
268
+ return handler(args, params);
269
+ }
270
+ }
271
+ return null;
272
+ }
273
+ handleSpecialPlaceholders(placeholder, params) {
274
+ // Try function placeholders first
275
+ const functionResult = this.processFunctionPlaceholder(placeholder, params);
276
+ if (functionResult !== null) {
277
+ return functionResult;
278
+ }
279
+ const getCurrentDate = () => new Date();
280
+ const getFirstDateOfCurrentYear = () => {
281
+ const currentYear = new Date().getFullYear();
282
+ return new Date(Date.UTC(currentYear, 0, 1));
283
+ };
284
+ const getEndDateOfCurrentYear = () => {
285
+ const currentYear = new Date().getFullYear();
286
+ return new Date(Date.UTC(currentYear, 11, 31));
287
+ };
288
+ const adjustDate = (date, amount, unit) => {
289
+ const newDate = new Date(date);
290
+ switch (unit) {
291
+ case 'd':
292
+ newDate.setUTCDate(newDate.getUTCDate() + amount);
293
+ break;
294
+ case 'm':
295
+ newDate.setUTCMonth(newDate.getUTCMonth() + amount);
296
+ break;
297
+ case 'y':
298
+ newDate.setUTCFullYear(newDate.getUTCFullYear() + amount);
299
+ break;
300
+ }
301
+ return newDate;
302
+ };
303
+ // Date patterns
304
+ const datePattern = /^(currentDate|firstDateOfCurrentYear|startDateOfCurrentYear|endDateOfCurrentYear)([+-]\d+)?([dmy])?$/;
305
+ const dateMatches = placeholder.match(datePattern);
306
+ if (dateMatches) {
307
+ const [, baseDate, adjustment = '', unit = ''] = dateMatches;
308
+ let date;
309
+ switch (baseDate) {
310
+ case 'currentDate':
311
+ date = getCurrentDate();
312
+ break;
313
+ case 'firstDateOfCurrentYear':
314
+ case 'startDateOfCurrentYear':
315
+ date = getFirstDateOfCurrentYear();
316
+ break;
317
+ case 'endDateOfCurrentYear':
318
+ date = getEndDateOfCurrentYear();
319
+ break;
320
+ default:
321
+ date = getCurrentDate();
322
+ }
323
+ if (adjustment) {
324
+ const amount = parseInt(adjustment, 10);
325
+ const timeUnit = unit || 'd';
326
+ date = adjustDate(date, amount, timeUnit);
327
+ }
328
+ return date.toISOString().split('T')[0];
329
+ }
330
+ // Number patterns
331
+ const numberPattern = /^(\d+)([+-]\d+)?$/;
332
+ const numberMatches = placeholder.match(numberPattern);
333
+ if (numberMatches) {
334
+ const [, baseNumber, adjustment = ''] = numberMatches;
335
+ let resultNumber = parseInt(baseNumber, 10);
336
+ if (adjustment) {
337
+ resultNumber += parseInt(adjustment, 10);
338
+ }
339
+ return resultNumber.toString();
340
+ }
341
+ // Fallback to params
342
+ return this.getNestedValue(params, placeholder) || '';
343
+ }
344
+ resolveValue(value, params) {
345
+ // String literal
346
+ if ((value.startsWith('"') && value.endsWith('"')) ||
347
+ (value.startsWith("'") && value.endsWith("'"))) {
348
+ return value.slice(1, -1);
349
+ }
350
+ // Number
351
+ if (!isNaN(Number(value))) {
352
+ return Number(value);
353
+ }
354
+ // Boolean/null/undefined
355
+ if (value === 'true')
356
+ return true;
357
+ if (value === 'false')
358
+ return false;
359
+ if (value === 'null')
360
+ return null;
361
+ if (value === 'undefined')
362
+ return undefined;
363
+ // Parameter key
364
+ return this.getNestedValue(params, value);
365
+ }
366
+ evaluateConditionalExpression(expression, params) {
367
+ const ternaryPattern = /^(.+?)\s*\?\s*(.+?)\s*:\s*(.+?)$/;
368
+ const match = expression.match(ternaryPattern);
369
+ if (!match) {
370
+ return null;
371
+ }
372
+ const [, condition, trueValue, falseValue] = match;
373
+ let conditionResult = false;
374
+ const comparisonPattern = /^(.+?)\s*(==|===|!=|!==|>|<|>=|<=)\s*(.+?)$/;
375
+ const compMatch = condition.match(comparisonPattern);
376
+ if (compMatch) {
377
+ const [, left, operator, right] = compMatch;
378
+ const leftValue = this.resolveValue(left.trim(), params);
379
+ const rightValue = this.resolveValue(right.trim(), params);
380
+ switch (operator) {
381
+ case '==':
382
+ case '===':
383
+ conditionResult = leftValue == rightValue;
384
+ break;
385
+ case '!=':
386
+ case '!==':
387
+ conditionResult = leftValue != rightValue;
388
+ break;
389
+ case '>':
390
+ conditionResult = leftValue > rightValue;
391
+ break;
392
+ case '<':
393
+ conditionResult = leftValue < rightValue;
394
+ break;
395
+ case '>=':
396
+ conditionResult = leftValue >= rightValue;
397
+ break;
398
+ case '<=':
399
+ conditionResult = leftValue <= rightValue;
400
+ break;
401
+ }
402
+ }
403
+ else {
404
+ const value = this.resolveValue(condition.trim(), params);
405
+ conditionResult = !!value;
406
+ }
407
+ const resultValue = conditionResult ? trueValue.trim() : falseValue.trim();
408
+ if (resultValue === 'null')
409
+ return null;
410
+ if (resultValue === 'undefined')
411
+ return '';
412
+ return String(this.resolveValue(resultValue, params));
413
+ }
414
+ resolvePlaceholdersRecursively(value, params) {
415
+ if (!value.match(/{{(.*?)}}/)) {
416
+ return value;
417
+ }
418
+ const replaced = this.dynamicTextReplace(value, params);
419
+ if (replaced === value && replaced.match(/{{(.*?)}}/)) {
420
+ return null;
421
+ }
422
+ if (replaced.match(/{{(.*?)}}/)) {
423
+ return this.resolvePlaceholdersRecursively(replaced, params);
424
+ }
425
+ return replaced;
426
+ }
427
+ processCommaPlaceholders(match, params) {
428
+ const rawContent = match.replace(/{{|}}/g, '');
429
+ // Try function placeholders
430
+ const functionResult = this.processFunctionPlaceholder(rawContent, params);
431
+ if (functionResult !== null) {
432
+ return functionResult;
433
+ }
434
+ // Try conditional expression
435
+ if (rawContent.includes('?') && rawContent.includes(':')) {
436
+ const conditionalResult = this.evaluateConditionalExpression(rawContent, params);
437
+ if (conditionalResult !== null) {
438
+ return conditionalResult;
439
+ }
440
+ }
441
+ // Remove optional marker and process comma-separated params
442
+ const cleanContent = rawContent.replace(/\?/g, '');
443
+ const paramNames = cleanContent.split(',');
444
+ const paramValues = [];
445
+ for (const paramName of paramNames) {
446
+ const trimmedName = paramName.trim();
447
+ const orParts = trimmedName.split('||').map((p) => p.trim());
448
+ let resolvedValueForThisPart = null;
449
+ for (const orPart of orParts) {
450
+ const resolvedName = this.resolvePlaceholdersRecursively(orPart, params);
451
+ if (resolvedName) {
452
+ const finalValue = this.handleSpecialPlaceholders(resolvedName, params);
453
+ if (finalValue !== '') {
454
+ resolvedValueForThisPart = String(finalValue);
455
+ break;
456
+ }
457
+ }
458
+ }
459
+ if (!resolvedValueForThisPart) {
460
+ return null;
461
+ }
462
+ paramValues.push(resolvedValueForThisPart);
463
+ }
464
+ const hasEmptyValues = paramValues.some((value) => value === '' || value === undefined);
465
+ if (hasEmptyValues) {
466
+ return null;
467
+ }
468
+ return paramValues.join(',');
469
+ }
470
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: FilterUtilsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
471
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: FilterUtilsService, providedIn: 'root' });
472
+ }
473
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: FilterUtilsService, decorators: [{
474
+ type: Injectable,
475
+ args: [{
476
+ providedIn: 'root',
477
+ }]
478
+ }] });
479
+
480
+ /**
481
+ * Dashboard Dialog Component
482
+ *
483
+ * A flexible dialog wrapper that renders a DashboardItem inside.
484
+ * Uses the same ItemConfig structure - maximum code reuse.
485
+ *
486
+ * The dialog simply wraps DashboardItem, so any chart/table/card
487
+ * that works inline will work in a dialog too.
488
+ */
489
+ /**
490
+ * Dashboard Dialog Component
491
+ *
492
+ * Opened via ModalService, renders a DashboardItem inside.
493
+ * Usage:
494
+ * this.modalService.open(DashboardDialogComponent, {
495
+ * data: { config: itemConfig, params: queryParams }
496
+ * });
497
+ */
498
+ class DashboardDialogComponent {
499
+ itemStore = inject(DashboardItemStoreService);
500
+ filterUtils = inject(FilterUtilsService);
501
+ transloco = inject(TranslocoService);
502
+ modal = inject(ModalService);
503
+ ref = inject(ModalRef);
504
+ // Inputs from modal data
505
+ configInput = input(null, { ...(ngDevMode ? { debugName: "configInput" } : {}), alias: 'config' });
506
+ paramsInput = input({}, { ...(ngDevMode ? { debugName: "paramsInput" } : {}), alias: 'params' });
507
+ titleInput = input(null, { ...(ngDevMode ? { debugName: "titleInput" } : {}), alias: 'title' });
508
+ // State
509
+ dialogConfig = signal(null, ...(ngDevMode ? [{ debugName: "dialogConfig" }] : []));
510
+ actionParams = signal({}, ...(ngDevMode ? [{ debugName: "actionParams" }] : []));
511
+ // Computed
512
+ mergedParams = computed(() => ({
513
+ ...this.paramsInput(),
514
+ ...this.actionParams(),
515
+ }), ...(ngDevMode ? [{ debugName: "mergedParams" }] : []));
516
+ processedConfig = computed(() => {
517
+ debugger;
518
+ const config = this.dialogConfig();
519
+ if (!config)
520
+ return null;
521
+ // Deep clone and process filters
522
+ const cloned = JSON.parse(JSON.stringify(config));
523
+ // Apply filter processing if service config exists
524
+ if (cloned.serviceConfig) {
525
+ const processed = this.filterUtils.handleFiltersForCustom(cloned.serviceConfig, this.mergedParams());
526
+ cloned.serviceConfig = processed;
527
+ }
528
+ return cloned;
529
+ }, ...(ngDevMode ? [{ debugName: "processedConfig" }] : []));
530
+ ngOnInit() {
531
+ // Set config from input
532
+ const config = this.configInput();
533
+ if (config) {
534
+ this.dialogConfig.set(config);
535
+ }
536
+ // Set params from input
537
+ const params = this.paramsInput();
538
+ if (params) {
539
+ this.actionParams.set(params);
540
+ }
541
+ }
542
+ /**
543
+ * Close dialog
544
+ */
545
+ close(result) {
546
+ this.ref.close(result);
547
+ }
548
+ /**
549
+ * Handle actions from the inner DashboardItem
550
+ */
551
+ onItemAction(event) {
552
+ // If it's a close action, close the dialog
553
+ if (event?.type === 'closeDialog') {
554
+ this.close(event?.data);
555
+ return;
556
+ }
557
+ // For navigation actions, close dialog and let parent handle
558
+ if (event?.type === 'navigate' || event?.type === 'navigateTo') {
559
+ this.close(event);
560
+ return;
561
+ }
562
+ // For other actions, could emit to parent or handle internally
563
+ console.log('Dialog action:', event);
564
+ }
565
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: DashboardDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
566
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.3", type: DashboardDialogComponent, isStandalone: true, selector: "db-dashboard-dialog", inputs: { configInput: { classPropertyName: "configInput", publicName: "config", isSignal: true, isRequired: false, transformFunction: null }, paramsInput: { classPropertyName: "paramsInput", publicName: "params", isSignal: true, isRequired: false, transformFunction: null }, titleInput: { classPropertyName: "titleInput", publicName: "title", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div\r\n [class]=\"modal.contentClass + ' p-0 min-h-[300px] max-h-[80vh] overflow-auto'\"\r\n *transloco=\"let t; prefix: 'dashboard'\"\r\n>\r\n <!-- Dashboard Item renders whatever the config specifies -->\r\n @if (processedConfig()) {\r\n <mt-dashboard-item\r\n [config]=\"processedConfig()!\"\r\n [queryParams]=\"mergedParams()\"\r\n [isDialog]=\"true\"\r\n (actionTriggered)=\"onItemAction($event)\"\r\n />\r\n } @else {\r\n <!-- Loading state while config is being processed -->\r\n <div class=\"flex items-center justify-center min-h-[200px]\">\r\n <i class=\"pi pi-spin pi-spinner text-4xl text-primary\"></i>\r\n </div>\r\n }\r\n</div>\r\n<!--\r\n<div [class]=\"modal.footerClass\" *transloco=\"let t; prefix: 'dashboard'\">\r\n <mt-button [label]=\"t('close')\" severity=\"secondary\" (onClick)=\"close()\" />\r\n</div> -->\r\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "component", type: DashboardItem, selector: "mt-dashboard-item", inputs: ["config", "chartTypeId", "readonly", "inGroup", "isDialog", "queryParams"], outputs: ["actionTriggered"] }] });
567
+ }
568
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: DashboardDialogComponent, decorators: [{
569
+ type: Component,
570
+ args: [{ selector: 'db-dashboard-dialog', standalone: true, imports: [CommonModule, TranslocoDirective, Button, DashboardItem], template: "<div\r\n [class]=\"modal.contentClass + ' p-0 min-h-[300px] max-h-[80vh] overflow-auto'\"\r\n *transloco=\"let t; prefix: 'dashboard'\"\r\n>\r\n <!-- Dashboard Item renders whatever the config specifies -->\r\n @if (processedConfig()) {\r\n <mt-dashboard-item\r\n [config]=\"processedConfig()!\"\r\n [queryParams]=\"mergedParams()\"\r\n [isDialog]=\"true\"\r\n (actionTriggered)=\"onItemAction($event)\"\r\n />\r\n } @else {\r\n <!-- Loading state while config is being processed -->\r\n <div class=\"flex items-center justify-center min-h-[200px]\">\r\n <i class=\"pi pi-spin pi-spinner text-4xl text-primary\"></i>\r\n </div>\r\n }\r\n</div>\r\n<!--\r\n<div [class]=\"modal.footerClass\" *transloco=\"let t; prefix: 'dashboard'\">\r\n <mt-button [label]=\"t('close')\" severity=\"secondary\" (onClick)=\"close()\" />\r\n</div> -->\r\n" }]
571
+ }], propDecorators: { configInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: false }] }], paramsInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "params", required: false }] }], titleInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }] } });
572
+ /**
573
+ * Helper service for opening dashboard dialogs
574
+ */
575
+ function openDashboardDialog(modalService, config, params, options) {
576
+ const sizeClass = {
577
+ sm: 'max-w-md',
578
+ md: 'max-w-2xl',
579
+ lg: 'max-w-4xl',
580
+ xl: 'max-w-6xl',
581
+ full: 'max-w-[95vw]',
582
+ }[options?.size || 'lg'];
583
+ return modalService.openModal(DashboardDialogComponent, 'dialog', {
584
+ header: options?.title || '',
585
+ styleClass: sizeClass,
586
+ data: {
587
+ config,
588
+ params: params || {},
589
+ title: options?.title,
590
+ },
591
+ });
592
+ }
593
+
594
+ export { DashboardDialogComponent, openDashboardDialog };
595
+ //# sourceMappingURL=masterteam-dashboard-builder-dashboard-dialog.component-D1JNWQMI.mjs.map