@memberjunction/ng-entity-viewer 5.43.0 → 5.45.0

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 (75) hide show
  1. package/dist/lib/aggregate-panel/aggregate-panel.component.d.ts +5 -0
  2. package/dist/lib/aggregate-panel/aggregate-panel.component.d.ts.map +1 -1
  3. package/dist/lib/aggregate-panel/aggregate-panel.component.js +45 -47
  4. package/dist/lib/aggregate-panel/aggregate-panel.component.js.map +1 -1
  5. package/dist/lib/entity-cards/entity-cards.component.js +7 -10
  6. package/dist/lib/entity-cards/entity-cards.component.js.map +1 -1
  7. package/dist/lib/entity-data-grid/entity-data-grid.component.d.ts +10 -1
  8. package/dist/lib/entity-data-grid/entity-data-grid.component.d.ts.map +1 -1
  9. package/dist/lib/entity-data-grid/entity-data-grid.component.js +35 -34
  10. package/dist/lib/entity-data-grid/entity-data-grid.component.js.map +1 -1
  11. package/dist/lib/entity-record-detail-panel/entity-record-detail-panel.component.d.ts +0 -4
  12. package/dist/lib/entity-record-detail-panel/entity-record-detail-panel.component.d.ts.map +1 -1
  13. package/dist/lib/entity-record-detail-panel/entity-record-detail-panel.component.js +166 -207
  14. package/dist/lib/entity-record-detail-panel/entity-record-detail-panel.component.js.map +1 -1
  15. package/dist/lib/entity-viewer/entity-viewer.component.d.ts +109 -5
  16. package/dist/lib/entity-viewer/entity-viewer.component.d.ts.map +1 -1
  17. package/dist/lib/entity-viewer/entity-viewer.component.js +287 -42
  18. package/dist/lib/entity-viewer/entity-viewer.component.js.map +1 -1
  19. package/dist/lib/recycle-bin/recycle-bin.component.js +21 -44
  20. package/dist/lib/recycle-bin/recycle-bin.component.js.map +1 -1
  21. package/dist/lib/shared-view-warning-dialog/shared-view-warning-dialog.component.js +19 -20
  22. package/dist/lib/shared-view-warning-dialog/shared-view-warning-dialog.component.js.map +1 -1
  23. package/dist/lib/view-config-panel/view-config-panel.component.js +268 -301
  24. package/dist/lib/view-config-panel/view-config-panel.component.js.map +1 -1
  25. package/dist/lib/view-selector/view-selector.component.d.ts +26 -1
  26. package/dist/lib/view-selector/view-selector.component.d.ts.map +1 -1
  27. package/dist/lib/view-selector/view-selector.component.js +118 -76
  28. package/dist/lib/view-selector/view-selector.component.js.map +1 -1
  29. package/dist/lib/view-types/descriptors/grid-view-type.d.ts +7 -0
  30. package/dist/lib/view-types/descriptors/grid-view-type.d.ts.map +1 -1
  31. package/dist/lib/view-types/descriptors/grid-view-type.js +7 -0
  32. package/dist/lib/view-types/descriptors/grid-view-type.js.map +1 -1
  33. package/dist/lib/view-types/renderers/grid-view-renderer.component.d.ts +18 -1
  34. package/dist/lib/view-types/renderers/grid-view-renderer.component.d.ts.map +1 -1
  35. package/dist/lib/view-types/renderers/grid-view-renderer.component.js +29 -3
  36. package/dist/lib/view-types/renderers/grid-view-renderer.component.js.map +1 -1
  37. package/dist/lib/view-types/renderers/map-view-renderer.component.d.ts.map +1 -1
  38. package/dist/lib/view-types/renderers/map-view-renderer.component.js +11 -14
  39. package/dist/lib/view-types/renderers/map-view-renderer.component.js.map +1 -1
  40. package/dist/lib/view-types/renderers/timeline-view-renderer.component.d.ts.map +1 -1
  41. package/dist/lib/view-types/renderers/timeline-view-renderer.component.js +12 -14
  42. package/dist/lib/view-types/renderers/timeline-view-renderer.component.js.map +1 -1
  43. package/dist/lib/view-types/view-type.contracts.d.ts +44 -0
  44. package/dist/lib/view-types/view-type.contracts.d.ts.map +1 -1
  45. package/dist/lib/view-types/view-type.contracts.js +6 -0
  46. package/dist/lib/view-types/view-type.contracts.js.map +1 -1
  47. package/dist/lib/view-workspace/view-workspace.component.d.ts +32 -1
  48. package/dist/lib/view-workspace/view-workspace.component.d.ts.map +1 -1
  49. package/dist/lib/view-workspace/view-workspace.component.js +68 -7
  50. package/dist/lib/view-workspace/view-workspace.component.js.map +1 -1
  51. package/dist/module.d.ts +1 -1
  52. package/dist/module.d.ts.map +1 -1
  53. package/dist/module.js +10 -1
  54. package/dist/module.js.map +1 -1
  55. package/package.json +18 -17
  56. package/dist/__tests__/entity-cards-selection.test.d.ts +0 -2
  57. package/dist/__tests__/entity-cards-selection.test.d.ts.map +0 -1
  58. package/dist/__tests__/entity-cards-selection.test.js +0 -149
  59. package/dist/__tests__/entity-cards-selection.test.js.map +0 -1
  60. package/dist/__tests__/entity-cards-viewmodel.test.d.ts +0 -2
  61. package/dist/__tests__/entity-cards-viewmodel.test.d.ts.map +0 -1
  62. package/dist/__tests__/entity-cards-viewmodel.test.js +0 -208
  63. package/dist/__tests__/entity-cards-viewmodel.test.js.map +0 -1
  64. package/dist/__tests__/highlight.test.d.ts +0 -2
  65. package/dist/__tests__/highlight.test.d.ts.map +0 -1
  66. package/dist/__tests__/highlight.test.js +0 -67
  67. package/dist/__tests__/highlight.test.js.map +0 -1
  68. package/dist/__tests__/index.test.d.ts +0 -2
  69. package/dist/__tests__/index.test.d.ts.map +0 -1
  70. package/dist/__tests__/index.test.js +0 -7
  71. package/dist/__tests__/index.test.js.map +0 -1
  72. package/dist/__tests__/view-types.test.d.ts +0 -2
  73. package/dist/__tests__/view-types.test.d.ts.map +0 -1
  74. package/dist/__tests__/view-types.test.js +0 -102
  75. package/dist/__tests__/view-types.test.js.map +0 -1
@@ -68,6 +68,11 @@ export declare class AggregatePanelComponent implements OnInit {
68
68
  * Toggle panel collapsed state
69
69
  */
70
70
  ToggleCollapse(): void;
71
+ /**
72
+ * Handle the accordion panel's ExpandedChange. Accordion `Expanded` is the
73
+ * inverse of our `IsCollapsed`; preserves the CollapsedChange emit side-effect.
74
+ */
75
+ OnPanelExpandedChange(expanded: boolean): void;
71
76
  /**
72
77
  * Handle click on an aggregate card
73
78
  */
@@ -1 +1 @@
1
- {"version":3,"file":"aggregate-panel.component.d.ts","sourceRoot":"","sources":["../../../src/lib/aggregate-panel/aggregate-panel.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,YAAY,EACZ,MAAM,EACP,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,+BAA+B,IAAI,iBAAiB,EAGrD,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;;AAEtD;;;;;;;;;;GAUG;AACH,qBAMa,uBAAwB,YAAW,MAAM;IACpD;;OAEG;IACM,UAAU,EAAE,iBAAiB,EAAE,CAAM;IAE9C;;OAEG;IACM,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAAa;IAEzD;;OAEG;IACM,QAAQ,EAAE,OAAO,GAAG,QAAQ,CAAW;IAEhD;;OAEG;IACM,KAAK,EAAE,MAAM,CAAO;IAE7B;;OAEG;IACM,MAAM,EAAE,YAAY,GAAG,UAAU,GAAG,MAAM,CAAc;IAEjE;;OAEG;IACM,WAAW,EAAE,MAAM,CAAK;IAEjC;;OAEG;IACM,KAAK,EAAE,MAAM,CAAa;IAEnC;;OAEG;IACM,WAAW,EAAE,OAAO,CAAQ;IAErC;;OAEG;IACM,cAAc,EAAE,OAAO,CAAS;IAEzC;;OAEG;IACM,OAAO,EAAE,OAAO,CAAS;IAElC;;OAEG;IACO,eAAe,wBAA+B;IAExD;;OAEG;IACO,cAAc,kCAAyC;IAEjE,WAAW,UAAS;IAEpB,QAAQ,IAAI,IAAI;IAIhB;;OAEG;IACH,cAAc,IAAI,IAAI;IAOtB;;OAEG;IACH,gBAAgB,CAAC,GAAG,EAAE,iBAAiB,GAAG,IAAI;IAI9C;;OAEG;IACH,WAAW,CAAC,GAAG,EAAE,iBAAiB,GAAG,MAAM;IAU3C;;OAEG;IACH,aAAa,CAAC,GAAG,EAAE,iBAAiB,GAAG,MAAM;IAc7C;;OAEG;IACH,IAAI,iBAAiB,IAAI,iBAAiB,EAAE,CAE3C;IAED;;OAEG;IACH,IAAI,cAAc,IAAI,iBAAiB,EAAE,CAIxC;IAED;;OAEG;IACH,IAAI,UAAU,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAQvC;IAED;;OAEG;IACH,IAAI,mBAAmB,IAAI,MAAM,CAKhC;IAED;;OAEG;IACH,OAAO,CAAC,YAAY;IAyBpB;;OAEG;IACH,OAAO,CAAC,YAAY;IAoBpB;;OAEG;IACH,OAAO,CAAC,UAAU;IAyBlB;;OAEG;IACH,OAAO,CAAC,iBAAiB;yCA3Od,uBAAuB;2CAAvB,uBAAuB;CAiQnC"}
1
+ {"version":3,"file":"aggregate-panel.component.d.ts","sourceRoot":"","sources":["../../../src/lib/aggregate-panel/aggregate-panel.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,YAAY,EACZ,MAAM,EACP,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,+BAA+B,IAAI,iBAAiB,EAGrD,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;;AAEtD;;;;;;;;;;GAUG;AACH,qBAMa,uBAAwB,YAAW,MAAM;IACpD;;OAEG;IACM,UAAU,EAAE,iBAAiB,EAAE,CAAM;IAE9C;;OAEG;IACM,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAAa;IAEzD;;OAEG;IACM,QAAQ,EAAE,OAAO,GAAG,QAAQ,CAAW;IAEhD;;OAEG;IACM,KAAK,EAAE,MAAM,CAAO;IAE7B;;OAEG;IACM,MAAM,EAAE,YAAY,GAAG,UAAU,GAAG,MAAM,CAAc;IAEjE;;OAEG;IACM,WAAW,EAAE,MAAM,CAAK;IAEjC;;OAEG;IACM,KAAK,EAAE,MAAM,CAAa;IAEnC;;OAEG;IACM,WAAW,EAAE,OAAO,CAAQ;IAErC;;OAEG;IACM,cAAc,EAAE,OAAO,CAAS;IAEzC;;OAEG;IACM,OAAO,EAAE,OAAO,CAAS;IAElC;;OAEG;IACO,eAAe,wBAA+B;IAExD;;OAEG;IACO,cAAc,kCAAyC;IAEjE,WAAW,UAAS;IAEpB,QAAQ,IAAI,IAAI;IAIhB;;OAEG;IACH,cAAc,IAAI,IAAI;IAOtB;;;OAGG;IACH,qBAAqB,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI;IAK9C;;OAEG;IACH,gBAAgB,CAAC,GAAG,EAAE,iBAAiB,GAAG,IAAI;IAI9C;;OAEG;IACH,WAAW,CAAC,GAAG,EAAE,iBAAiB,GAAG,MAAM;IAU3C;;OAEG;IACH,aAAa,CAAC,GAAG,EAAE,iBAAiB,GAAG,MAAM;IAc7C;;OAEG;IACH,IAAI,iBAAiB,IAAI,iBAAiB,EAAE,CAE3C;IAED;;OAEG;IACH,IAAI,cAAc,IAAI,iBAAiB,EAAE,CAIxC;IAED;;OAEG;IACH,IAAI,UAAU,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAQvC;IAED;;OAEG;IACH,IAAI,mBAAmB,IAAI,MAAM,CAKhC;IAED;;OAEG;IACH,OAAO,CAAC,YAAY;IAyBpB;;OAEG;IACH,OAAO,CAAC,YAAY;IAoBpB;;OAEG;IACH,OAAO,CAAC,UAAU;IAyBlB;;OAEG;IACH,OAAO,CAAC,iBAAiB;yCApPd,uBAAuB;2CAAvB,uBAAuB;CA0QnC"}
@@ -1,31 +1,34 @@
1
1
  import { Component, Input, Output, EventEmitter } from '@angular/core';
2
2
  import * as i0 from "@angular/core";
3
3
  import * as i1 from "@angular/common";
4
+ import * as i2 from "@memberjunction/ng-ui-components";
4
5
  const _c0 = a0 => ({ "grid-template-columns": a0 });
5
6
  const _c1 = () => ({});
6
- function AggregatePanelComponent_Conditional_5_Template(rf, ctx) { if (rf & 1) {
7
- i0.ɵɵelementStart(0, "span", 4);
8
- i0.ɵɵelement(1, "i", 7);
7
+ function AggregatePanelComponent_ng_template_2_Template(rf, ctx) { if (rf & 1) {
8
+ i0.ɵɵelementStart(0, "span", 5);
9
+ i0.ɵɵtext(1);
9
10
  i0.ɵɵelementEnd();
11
+ } if (rf & 2) {
12
+ const ctx_r0 = i0.ɵɵnextContext();
13
+ i0.ɵɵadvance();
14
+ i0.ɵɵtextInterpolate(ctx_r0.Title);
10
15
  } }
11
- function AggregatePanelComponent_Conditional_6_Template(rf, ctx) { if (rf & 1) {
12
- i0.ɵɵelementStart(0, "button", 5);
13
- i0.ɵɵelement(1, "i", 8);
16
+ function AggregatePanelComponent_ng_template_3_Conditional_0_Template(rf, ctx) { if (rf & 1) {
17
+ i0.ɵɵelementStart(0, "span", 6);
18
+ i0.ɵɵelement(1, "i", 7);
14
19
  i0.ɵɵelementEnd();
20
+ } }
21
+ function AggregatePanelComponent_ng_template_3_Template(rf, ctx) { if (rf & 1) {
22
+ i0.ɵɵconditionalCreate(0, AggregatePanelComponent_ng_template_3_Conditional_0_Template, 2, 0, "span", 6);
15
23
  } if (rf & 2) {
16
24
  const ctx_r0 = i0.ɵɵnextContext();
17
- i0.ɵɵadvance();
18
- i0.ɵɵclassProp("fa-chevron-up", !ctx_r0.IsCollapsed)("fa-chevron-down", ctx_r0.IsCollapsed);
25
+ i0.ɵɵconditional(ctx_r0.Loading ? 0 : -1);
19
26
  } }
20
- function AggregatePanelComponent_Conditional_7_Conditional_1_Template(rf, ctx) { if (rf & 1) {
21
- i0.ɵɵelementStart(0, "div", 9);
22
- i0.ɵɵelement(1, "i", 12);
23
- i0.ɵɵelementStart(2, "p");
24
- i0.ɵɵtext(3, "No summaries configured");
25
- i0.ɵɵelementEnd()();
27
+ function AggregatePanelComponent_ng_template_4_Conditional_1_Template(rf, ctx) { if (rf & 1) {
28
+ i0.ɵɵelement(0, "mj-empty-state", 9);
26
29
  } }
27
- function AggregatePanelComponent_Conditional_7_For_4_Conditional_1_Template(rf, ctx) { if (rf & 1) {
28
- i0.ɵɵelementStart(0, "div", 14);
30
+ function AggregatePanelComponent_ng_template_4_For_4_Conditional_1_Template(rf, ctx) { if (rf & 1) {
31
+ i0.ɵɵelementStart(0, "div", 13);
29
32
  i0.ɵɵelement(1, "i");
30
33
  i0.ɵɵelementEnd();
31
34
  } if (rf & 2) {
@@ -33,15 +36,15 @@ function AggregatePanelComponent_Conditional_7_For_4_Conditional_1_Template(rf,
33
36
  i0.ɵɵadvance();
34
37
  i0.ɵɵclassMap(agg_r3.icon);
35
38
  } }
36
- function AggregatePanelComponent_Conditional_7_For_4_Template(rf, ctx) { if (rf & 1) {
39
+ function AggregatePanelComponent_ng_template_4_For_4_Template(rf, ctx) { if (rf & 1) {
37
40
  const _r2 = i0.ɵɵgetCurrentView();
38
- i0.ɵɵelementStart(0, "div", 13);
39
- i0.ɵɵlistener("click", function AggregatePanelComponent_Conditional_7_For_4_Template_div_click_0_listener() { const agg_r3 = i0.ɵɵrestoreView(_r2).$implicit; const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.OnAggregateClick(agg_r3)); });
40
- i0.ɵɵconditionalCreate(1, AggregatePanelComponent_Conditional_7_For_4_Conditional_1_Template, 2, 2, "div", 14);
41
- i0.ɵɵelementStart(2, "div", 15)(3, "div", 16);
41
+ i0.ɵɵelementStart(0, "div", 12);
42
+ i0.ɵɵlistener("click", function AggregatePanelComponent_ng_template_4_For_4_Template_div_click_0_listener() { const agg_r3 = i0.ɵɵrestoreView(_r2).$implicit; const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.OnAggregateClick(agg_r3)); });
43
+ i0.ɵɵconditionalCreate(1, AggregatePanelComponent_ng_template_4_For_4_Conditional_1_Template, 2, 2, "div", 13);
44
+ i0.ɵɵelementStart(2, "div", 14)(3, "div", 15);
42
45
  i0.ɵɵtext(4);
43
46
  i0.ɵɵelementEnd();
44
- i0.ɵɵelementStart(5, "div", 17);
47
+ i0.ɵɵelementStart(5, "div", 16);
45
48
  i0.ɵɵtext(6);
46
49
  i0.ɵɵelementEnd()()();
47
50
  } if (rf & 2) {
@@ -58,11 +61,11 @@ function AggregatePanelComponent_Conditional_7_For_4_Template(rf, ctx) { if (rf
58
61
  i0.ɵɵadvance(2);
59
62
  i0.ɵɵtextInterpolate(agg_r3.label);
60
63
  } }
61
- function AggregatePanelComponent_Conditional_7_Template(rf, ctx) { if (rf & 1) {
62
- i0.ɵɵelementStart(0, "div", 6);
63
- i0.ɵɵconditionalCreate(1, AggregatePanelComponent_Conditional_7_Conditional_1_Template, 4, 0, "div", 9);
64
+ function AggregatePanelComponent_ng_template_4_Template(rf, ctx) { if (rf & 1) {
65
+ i0.ɵɵelementStart(0, "div", 8);
66
+ i0.ɵɵconditionalCreate(1, AggregatePanelComponent_ng_template_4_Conditional_1_Template, 1, 0, "mj-empty-state", 9);
64
67
  i0.ɵɵelementStart(2, "div", 10);
65
- i0.ɵɵrepeaterCreate(3, AggregatePanelComponent_Conditional_7_For_4_Template, 7, 8, "div", 11, i0.ɵɵrepeaterTrackByIdentity);
68
+ i0.ɵɵrepeaterCreate(3, AggregatePanelComponent_ng_template_4_For_4_Template, 7, 8, "div", 11, i0.ɵɵrepeaterTrackByIdentity);
66
69
  i0.ɵɵelementEnd()();
67
70
  } if (rf & 2) {
68
71
  const ctx_r0 = i0.ɵɵnextContext();
@@ -147,6 +150,14 @@ export class AggregatePanelComponent {
147
150
  this.CollapsedChange.emit(this.IsCollapsed);
148
151
  }
149
152
  }
153
+ /**
154
+ * Handle the accordion panel's ExpandedChange. Accordion `Expanded` is the
155
+ * inverse of our `IsCollapsed`; preserves the CollapsedChange emit side-effect.
156
+ */
157
+ OnPanelExpandedChange(expanded) {
158
+ this.IsCollapsed = !expanded;
159
+ this.CollapsedChange.emit(this.IsCollapsed);
160
+ }
150
161
  /**
151
162
  * Handle click on an aggregate card
152
163
  */
@@ -310,34 +321,21 @@ export class AggregatePanelComponent {
310
321
  }
311
322
  }
312
323
  static ɵfac = function AggregatePanelComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || AggregatePanelComponent)(); };
313
- static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: AggregatePanelComponent, selectors: [["mj-aggregate-panel"]], inputs: { Aggregates: "Aggregates", Values: "Values", Position: "Position", Width: "Width", Layout: "Layout", GridColumns: "GridColumns", Title: "Title", Collapsible: "Collapsible", StartCollapsed: "StartCollapsed", Loading: "Loading" }, outputs: { CollapsedChange: "CollapsedChange", AggregateClick: "AggregateClick" }, standalone: false, decls: 8, vars: 11, consts: [[1, "aggregate-panel", 3, "ngStyle"], [1, "panel-header", 3, "click"], [1, "panel-title"], [1, "panel-header-right"], [1, "loading-indicator"], ["type", "button", 1, "collapse-toggle"], [1, "panel-content"], [1, "fa-solid", "fa-spinner", "fa-spin"], [1, "fa-solid"], [1, "empty-state"], [1, "cards-container", 3, "ngStyle"], [1, "aggregate-card", 3, "class", "title"], [1, "fa-solid", "fa-chart-simple"], [1, "aggregate-card", 3, "click", "title"], [1, "card-icon"], [1, "card-content"], [1, "card-value"], [1, "card-label"]], template: function AggregatePanelComponent_Template(rf, ctx) { if (rf & 1) {
314
- i0.ɵɵelementStart(0, "div", 0)(1, "div", 1);
315
- i0.ɵɵlistener("click", function AggregatePanelComponent_Template_div_click_1_listener() { return ctx.ToggleCollapse(); });
316
- i0.ɵɵelementStart(2, "span", 2);
317
- i0.ɵɵtext(3);
318
- i0.ɵɵelementEnd();
319
- i0.ɵɵelementStart(4, "div", 3);
320
- i0.ɵɵconditionalCreate(5, AggregatePanelComponent_Conditional_5_Template, 2, 0, "span", 4);
321
- i0.ɵɵconditionalCreate(6, AggregatePanelComponent_Conditional_6_Template, 2, 4, "button", 5);
324
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: AggregatePanelComponent, selectors: [["mj-aggregate-panel"]], inputs: { Aggregates: "Aggregates", Values: "Values", Position: "Position", Width: "Width", Layout: "Layout", GridColumns: "GridColumns", Title: "Title", Collapsible: "Collapsible", StartCollapsed: "StartCollapsed", Loading: "Loading" }, outputs: { CollapsedChange: "CollapsedChange", AggregateClick: "AggregateClick" }, standalone: false, decls: 5, vars: 8, consts: [[1, "aggregate-panel", 3, "ngStyle"], ["Size", "sm", 3, "ExpandedChange", "FlushBody", "Expanded", "Disabled"], ["mjAccordionTitle", ""], ["mjAccordionActions", ""], ["mjAccordionBody", ""], [1, "panel-title"], [1, "loading-indicator"], [1, "fa-solid", "fa-spinner", "fa-spin"], [1, "panel-content"], ["Size", "compact", "Icon", "fa-solid fa-chart-simple", "Title", "No summaries configured"], [1, "cards-container", 3, "ngStyle"], [1, "aggregate-card", 3, "class", "title"], [1, "aggregate-card", 3, "click", "title"], [1, "card-icon"], [1, "card-content"], [1, "card-value"], [1, "card-label"]], template: function AggregatePanelComponent_Template(rf, ctx) { if (rf & 1) {
325
+ i0.ɵɵelementStart(0, "div", 0)(1, "mj-accordion-panel", 1);
326
+ i0.ɵɵlistener("ExpandedChange", function AggregatePanelComponent_Template_mj_accordion_panel_ExpandedChange_1_listener($event) { return ctx.OnPanelExpandedChange($event); });
327
+ i0.ɵɵtemplate(2, AggregatePanelComponent_ng_template_2_Template, 2, 1, "ng-template", 2)(3, AggregatePanelComponent_ng_template_3_Template, 1, 1, "ng-template", 3)(4, AggregatePanelComponent_ng_template_4_Template, 5, 11, "ng-template", 4);
322
328
  i0.ɵɵelementEnd()();
323
- i0.ɵɵconditionalCreate(7, AggregatePanelComponent_Conditional_7_Template, 5, 11, "div", 6);
324
- i0.ɵɵelementEnd();
325
329
  } if (rf & 2) {
326
- i0.ɵɵclassProp("position-right", ctx.Position === "right")("position-bottom", ctx.Position === "bottom")("collapsed", ctx.IsCollapsed);
330
+ i0.ɵɵclassProp("position-right", ctx.Position === "right")("position-bottom", ctx.Position === "bottom");
327
331
  i0.ɵɵproperty("ngStyle", ctx.PanelStyle);
328
- i0.ɵɵadvance(3);
329
- i0.ɵɵtextInterpolate(ctx.Title);
330
- i0.ɵɵadvance(2);
331
- i0.ɵɵconditional(ctx.Loading ? 5 : -1);
332
- i0.ɵɵadvance();
333
- i0.ɵɵconditional(ctx.Collapsible ? 6 : -1);
334
332
  i0.ɵɵadvance();
335
- i0.ɵɵconditional(!ctx.IsCollapsed ? 7 : -1);
336
- } }, dependencies: [i1.NgStyle], styles: ["\n\n\n.aggregate-panel[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n overflow: hidden;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);\n}\n\n\n\n.position-right[_ngcontent-%COMP%] {\n height: 100%;\n border-left-width: 1px;\n border-radius: 0 8px 8px 0;\n}\n\n.position-bottom[_ngcontent-%COMP%] {\n width: 100%;\n border-top-width: 1px;\n border-radius: 0 0 8px 8px;\n}\n\n\n\n.collapsed[_ngcontent-%COMP%] .panel-content[_ngcontent-%COMP%] {\n display: none;\n}\n\n.collapsed.position-right[_ngcontent-%COMP%] {\n width: auto !important;\n min-width: auto !important;\n}\n\n\n\n.panel-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 16px;\n background: var(--mj-bg-surface-card);\n border-bottom: 1px solid var(--mj-border-default);\n cursor: pointer;\n user-select: none;\n}\n\n.panel-header[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n}\n\n.panel-title[_ngcontent-%COMP%] {\n font-weight: 600;\n font-size: 14px;\n color: var(--mj-text-primary);\n}\n\n.panel-header-right[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.loading-indicator[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n font-size: 14px;\n}\n\n.collapse-toggle[_ngcontent-%COMP%] {\n background: none;\n border: none;\n padding: 4px 8px;\n cursor: pointer;\n color: var(--mj-text-secondary);\n font-size: 12px;\n border-radius: 4px;\n transition: background-color 0.2s, color 0.2s;\n}\n\n.collapse-toggle[_ngcontent-%COMP%]:hover {\n background: rgba(0, 0, 0, 0.05);\n color: var(--mj-text-primary);\n}\n\n\n\n.panel-content[_ngcontent-%COMP%] {\n padding: 16px;\n overflow-y: auto;\n flex: 1;\n}\n\n\n\n.empty-state[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 24px;\n color: var(--mj-text-disabled);\n text-align: center;\n}\n\n.empty-state[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 32px;\n margin-bottom: 12px;\n opacity: 0.5;\n}\n\n.empty-state[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 13px;\n}\n\n\n\n.cards-container[_ngcontent-%COMP%] {\n display: flex;\n gap: 12px;\n}\n\n.layout-horizontal[_ngcontent-%COMP%] {\n flex-direction: row;\n flex-wrap: wrap;\n}\n\n.layout-vertical[_ngcontent-%COMP%] {\n flex-direction: column;\n}\n\n.layout-grid[_ngcontent-%COMP%] {\n display: grid;\n gap: 12px;\n}\n\n\n\n.aggregate-card[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-start;\n gap: 12px;\n padding: 12px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n cursor: pointer;\n transition: border-color 0.2s, box-shadow 0.2s, transform 0.2s;\n}\n\n.aggregate-card[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 2px 8px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n transform: translateY(-1px);\n}\n\n\n\n.card-icon[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 40px;\n height: 40px;\n background: var(--mj-bg-surface-card);\n border-radius: 8px;\n color: var(--mj-brand-primary);\n font-size: 18px;\n flex-shrink: 0;\n}\n\n\n\n.card-content[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n.card-value[_ngcontent-%COMP%] {\n font-size: 20px;\n font-weight: 700;\n color: var(--mj-text-primary);\n line-height: 1.2;\n margin-bottom: 4px;\n word-break: break-word;\n}\n\n.card-value.loading[_ngcontent-%COMP%] {\n color: var(--mj-text-disabled);\n}\n\n.card-label[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-secondary);\n line-height: 1.3;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n\n\n.style-success[_ngcontent-%COMP%] {\n border-left: 4px solid var(--mj-status-success);\n}\n\n.style-success[_ngcontent-%COMP%] .card-value[_ngcontent-%COMP%] {\n color: var(--mj-status-success);\n}\n\n.style-success[_ngcontent-%COMP%] .card-icon[_ngcontent-%COMP%] {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success);\n}\n\n.style-warning[_ngcontent-%COMP%] {\n border-left: 4px solid var(--mj-status-warning);\n}\n\n.style-warning[_ngcontent-%COMP%] .card-value[_ngcontent-%COMP%] {\n color: var(--mj-status-warning-text);\n}\n\n.style-warning[_ngcontent-%COMP%] .card-icon[_ngcontent-%COMP%] {\n background: var(--mj-status-warning-bg);\n color: var(--mj-status-warning-text);\n}\n\n.style-danger[_ngcontent-%COMP%] {\n border-left: 4px solid var(--mj-status-error);\n}\n\n.style-danger[_ngcontent-%COMP%] .card-value[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n}\n\n.style-danger[_ngcontent-%COMP%] .card-icon[_ngcontent-%COMP%] {\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error);\n}\n\n.style-info[_ngcontent-%COMP%] {\n border-left: 4px solid var(--mj-brand-primary);\n}\n\n.style-info[_ngcontent-%COMP%] .card-value[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n\n.style-info[_ngcontent-%COMP%] .card-icon[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.style-muted[_ngcontent-%COMP%] {\n border-left: 4px solid var(--mj-text-muted);\n}\n\n.style-muted[_ngcontent-%COMP%] .card-value[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n}\n\n.style-muted[_ngcontent-%COMP%] .card-icon[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-muted);\n}\n\n\n\n.position-bottom[_ngcontent-%COMP%] .cards-container.layout-vertical[_ngcontent-%COMP%] {\n flex-direction: row;\n flex-wrap: wrap;\n}\n\n.position-bottom[_ngcontent-%COMP%] .cards-container.layout-vertical[_ngcontent-%COMP%] .aggregate-card[_ngcontent-%COMP%] {\n flex: 1 1 200px;\n max-width: 300px;\n}"] });
333
+ i0.ɵɵproperty("FlushBody", true)("Expanded", !ctx.IsCollapsed)("Disabled", !ctx.Collapsible);
334
+ } }, dependencies: [i1.NgStyle, i2.MJAccordionPanelComponent, i2.MJAccordionTitleDirective, i2.MJAccordionActionsDirective, i2.MJAccordionBodyDirective, i2.MJEmptyStateComponent], styles: ["\n\n\n\n\n\n.aggregate-panel[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n}\n\n\n\n.position-right[_ngcontent-%COMP%] {\n height: 100%;\n}\n\n.position-bottom[_ngcontent-%COMP%] {\n width: 100%;\n}\n\n\n\n.panel-title[_ngcontent-%COMP%] {\n font-weight: 600;\n font-size: 14px;\n color: var(--mj-text-primary);\n}\n\n\n\n.loading-indicator[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n font-size: 14px;\n}\n\n\n\n.panel-content[_ngcontent-%COMP%] {\n padding: 16px;\n overflow-y: auto;\n flex: 1;\n}\n\n\n\n.cards-container[_ngcontent-%COMP%] {\n display: flex;\n gap: 12px;\n}\n\n.layout-horizontal[_ngcontent-%COMP%] {\n flex-direction: row;\n flex-wrap: wrap;\n}\n\n.layout-vertical[_ngcontent-%COMP%] {\n flex-direction: column;\n}\n\n.layout-grid[_ngcontent-%COMP%] {\n display: grid;\n gap: 12px;\n}\n\n\n\n.aggregate-card[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-start;\n gap: 12px;\n padding: 12px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n cursor: pointer;\n transition: border-color 0.2s, box-shadow 0.2s, transform 0.2s;\n}\n\n.aggregate-card[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 2px 8px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n transform: translateY(-1px);\n}\n\n\n\n.card-icon[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 40px;\n height: 40px;\n background: var(--mj-bg-surface-card);\n border-radius: 8px;\n color: var(--mj-brand-primary);\n font-size: 18px;\n flex-shrink: 0;\n}\n\n\n\n.card-content[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n.card-value[_ngcontent-%COMP%] {\n font-size: 20px;\n font-weight: 700;\n color: var(--mj-text-primary);\n line-height: 1.2;\n margin-bottom: 4px;\n word-break: break-word;\n}\n\n.card-value.loading[_ngcontent-%COMP%] {\n color: var(--mj-text-disabled);\n}\n\n.card-label[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-secondary);\n line-height: 1.3;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n\n\n.style-success[_ngcontent-%COMP%] {\n border-left: 4px solid var(--mj-status-success);\n}\n\n.style-success[_ngcontent-%COMP%] .card-value[_ngcontent-%COMP%] {\n color: var(--mj-status-success);\n}\n\n.style-success[_ngcontent-%COMP%] .card-icon[_ngcontent-%COMP%] {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success);\n}\n\n.style-warning[_ngcontent-%COMP%] {\n border-left: 4px solid var(--mj-status-warning);\n}\n\n.style-warning[_ngcontent-%COMP%] .card-value[_ngcontent-%COMP%] {\n color: var(--mj-status-warning-text);\n}\n\n.style-warning[_ngcontent-%COMP%] .card-icon[_ngcontent-%COMP%] {\n background: var(--mj-status-warning-bg);\n color: var(--mj-status-warning-text);\n}\n\n.style-danger[_ngcontent-%COMP%] {\n border-left: 4px solid var(--mj-status-error);\n}\n\n.style-danger[_ngcontent-%COMP%] .card-value[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n}\n\n.style-danger[_ngcontent-%COMP%] .card-icon[_ngcontent-%COMP%] {\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error);\n}\n\n.style-info[_ngcontent-%COMP%] {\n border-left: 4px solid var(--mj-brand-primary);\n}\n\n.style-info[_ngcontent-%COMP%] .card-value[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n\n.style-info[_ngcontent-%COMP%] .card-icon[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.style-muted[_ngcontent-%COMP%] {\n border-left: 4px solid var(--mj-text-muted);\n}\n\n.style-muted[_ngcontent-%COMP%] .card-value[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n}\n\n.style-muted[_ngcontent-%COMP%] .card-icon[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-muted);\n}\n\n\n\n.position-bottom[_ngcontent-%COMP%] .cards-container.layout-vertical[_ngcontent-%COMP%] {\n flex-direction: row;\n flex-wrap: wrap;\n}\n\n.position-bottom[_ngcontent-%COMP%] .cards-container.layout-vertical[_ngcontent-%COMP%] .aggregate-card[_ngcontent-%COMP%] {\n flex: 1 1 200px;\n max-width: 300px;\n}"] });
337
335
  }
338
336
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(AggregatePanelComponent, [{
339
337
  type: Component,
340
- args: [{ standalone: false, selector: 'mj-aggregate-panel', template: "<div class=\"aggregate-panel\"\n [class.position-right]=\"Position === 'right'\"\n [class.position-bottom]=\"Position === 'bottom'\"\n [class.collapsed]=\"IsCollapsed\"\n [ngStyle]=\"PanelStyle\">\n\n <!-- Panel Header -->\n <div class=\"panel-header\" (click)=\"ToggleCollapse()\">\n <span class=\"panel-title\">{{ Title }}</span>\n\n <div class=\"panel-header-right\">\n <!-- Loading indicator -->\n @if (Loading) {\n <span class=\"loading-indicator\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n </span>\n }\n\n <!-- Collapse toggle -->\n @if (Collapsible) {\n <button class=\"collapse-toggle\" type=\"button\">\n <i class=\"fa-solid\" [class.fa-chevron-up]=\"!IsCollapsed\" [class.fa-chevron-down]=\"IsCollapsed\"></i>\n </button>\n }\n </div>\n </div>\n\n <!-- Panel Content -->\n @if (!IsCollapsed) {\n <div class=\"panel-content\">\n <!-- Empty state -->\n @if (CardAggregates.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-chart-simple\"></i>\n <p>No summaries configured</p>\n </div>\n }\n <!-- Cards Container -->\n <div class=\"cards-container\"\n [class.layout-horizontal]=\"Layout === 'horizontal'\"\n [class.layout-vertical]=\"Layout === 'vertical'\"\n [class.layout-grid]=\"Layout === 'grid'\"\n [ngStyle]=\"Layout === 'grid' ? {'grid-template-columns': GridTemplateColumns} : {}\">\n <!-- Individual Aggregate Cards -->\n @for (agg of CardAggregates; track agg) {\n <div class=\"aggregate-card\"\n [class]=\"GetStyleClass(agg)\"\n (click)=\"OnAggregateClick(agg)\"\n [title]=\"agg.description || agg.label\">\n <!-- Icon -->\n @if (agg.icon) {\n <div class=\"card-icon\">\n <i [class]=\"agg.icon\"></i>\n </div>\n }\n <!-- Content -->\n <div class=\"card-content\">\n <div class=\"card-value\" [class.loading]=\"Loading\">\n {{ Loading ? '...' : FormatValue(agg) }}\n </div>\n <div class=\"card-label\">{{ agg.label }}</div>\n </div>\n </div>\n }\n </div>\n </div>\n }\n</div>\n", styles: ["/* Aggregate Panel Component Styles */\n\n.aggregate-panel {\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n overflow: hidden;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);\n}\n\n/* Position variants */\n.position-right {\n height: 100%;\n border-left-width: 1px;\n border-radius: 0 8px 8px 0;\n}\n\n.position-bottom {\n width: 100%;\n border-top-width: 1px;\n border-radius: 0 0 8px 8px;\n}\n\n/* Collapsed state */\n.collapsed .panel-content {\n display: none;\n}\n\n.collapsed.position-right {\n width: auto !important;\n min-width: auto !important;\n}\n\n/* Panel Header */\n.panel-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 16px;\n background: var(--mj-bg-surface-card);\n border-bottom: 1px solid var(--mj-border-default);\n cursor: pointer;\n user-select: none;\n}\n\n.panel-header:hover {\n background: var(--mj-bg-surface-sunken);\n}\n\n.panel-title {\n font-weight: 600;\n font-size: 14px;\n color: var(--mj-text-primary);\n}\n\n.panel-header-right {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.loading-indicator {\n color: var(--mj-brand-primary);\n font-size: 14px;\n}\n\n.collapse-toggle {\n background: none;\n border: none;\n padding: 4px 8px;\n cursor: pointer;\n color: var(--mj-text-secondary);\n font-size: 12px;\n border-radius: 4px;\n transition: background-color 0.2s, color 0.2s;\n}\n\n.collapse-toggle:hover {\n background: rgba(0, 0, 0, 0.05);\n color: var(--mj-text-primary);\n}\n\n/* Panel Content */\n.panel-content {\n padding: 16px;\n overflow-y: auto;\n flex: 1;\n}\n\n/* Empty State */\n.empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 24px;\n color: var(--mj-text-disabled);\n text-align: center;\n}\n\n.empty-state i {\n font-size: 32px;\n margin-bottom: 12px;\n opacity: 0.5;\n}\n\n.empty-state p {\n margin: 0;\n font-size: 13px;\n}\n\n/* Cards Container */\n.cards-container {\n display: flex;\n gap: 12px;\n}\n\n.layout-horizontal {\n flex-direction: row;\n flex-wrap: wrap;\n}\n\n.layout-vertical {\n flex-direction: column;\n}\n\n.layout-grid {\n display: grid;\n gap: 12px;\n}\n\n/* Aggregate Card */\n.aggregate-card {\n display: flex;\n align-items: flex-start;\n gap: 12px;\n padding: 12px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n cursor: pointer;\n transition: border-color 0.2s, box-shadow 0.2s, transform 0.2s;\n}\n\n.aggregate-card:hover {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 2px 8px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n transform: translateY(-1px);\n}\n\n/* Card Icon */\n.card-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 40px;\n height: 40px;\n background: var(--mj-bg-surface-card);\n border-radius: 8px;\n color: var(--mj-brand-primary);\n font-size: 18px;\n flex-shrink: 0;\n}\n\n/* Card Content */\n.card-content {\n flex: 1;\n min-width: 0;\n}\n\n.card-value {\n font-size: 20px;\n font-weight: 700;\n color: var(--mj-text-primary);\n line-height: 1.2;\n margin-bottom: 4px;\n word-break: break-word;\n}\n\n.card-value.loading {\n color: var(--mj-text-disabled);\n}\n\n.card-label {\n font-size: 12px;\n color: var(--mj-text-secondary);\n line-height: 1.3;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* Conditional Style Classes */\n.style-success {\n border-left: 4px solid var(--mj-status-success);\n}\n\n.style-success .card-value {\n color: var(--mj-status-success);\n}\n\n.style-success .card-icon {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success);\n}\n\n.style-warning {\n border-left: 4px solid var(--mj-status-warning);\n}\n\n.style-warning .card-value {\n color: var(--mj-status-warning-text);\n}\n\n.style-warning .card-icon {\n background: var(--mj-status-warning-bg);\n color: var(--mj-status-warning-text);\n}\n\n.style-danger {\n border-left: 4px solid var(--mj-status-error);\n}\n\n.style-danger .card-value {\n color: var(--mj-status-error);\n}\n\n.style-danger .card-icon {\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error);\n}\n\n.style-info {\n border-left: 4px solid var(--mj-brand-primary);\n}\n\n.style-info .card-value {\n color: var(--mj-brand-primary);\n}\n\n.style-info .card-icon {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.style-muted {\n border-left: 4px solid var(--mj-text-muted);\n}\n\n.style-muted .card-value {\n color: var(--mj-text-muted);\n}\n\n.style-muted .card-icon {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-muted);\n}\n\n/* Responsive adjustments for bottom position */\n.position-bottom .cards-container.layout-vertical {\n flex-direction: row;\n flex-wrap: wrap;\n}\n\n.position-bottom .cards-container.layout-vertical .aggregate-card {\n flex: 1 1 200px;\n max-width: 300px;\n}\n"] }]
338
+ args: [{ standalone: false, selector: 'mj-aggregate-panel', template: "<div class=\"aggregate-panel\"\n [class.position-right]=\"Position === 'right'\"\n [class.position-bottom]=\"Position === 'bottom'\"\n [ngStyle]=\"PanelStyle\">\n\n <!-- Migrated to <mj-accordion-panel>. The bespoke .panel-header / .collapse-toggle\n and the @if(!IsCollapsed) body gate are replaced by the accordion's own header,\n chevron, and lazy/animated body. Expanded is the inverse of IsCollapsed; the\n (ExpandedChange) handler preserves the CollapsedChange emit side-effect. -->\n <mj-accordion-panel\n Size=\"sm\"\n [FlushBody]=\"true\"\n [Expanded]=\"!IsCollapsed\"\n [Disabled]=\"!Collapsible\"\n (ExpandedChange)=\"OnPanelExpandedChange($event)\">\n\n <ng-template mjAccordionTitle>\n <span class=\"panel-title\">{{ Title }}</span>\n </ng-template>\n\n <!-- Loading indicator lives in the header actions slot (sibling of the chevron). -->\n <ng-template mjAccordionActions>\n @if (Loading) {\n <span class=\"loading-indicator\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n </span>\n }\n </ng-template>\n\n <ng-template mjAccordionBody>\n <div class=\"panel-content\">\n <!-- Empty state -->\n @if (CardAggregates.length === 0) {\n <mj-empty-state\n Size=\"compact\"\n Icon=\"fa-solid fa-chart-simple\"\n Title=\"No summaries configured\" />\n }\n <!-- Cards Container -->\n <div class=\"cards-container\"\n [class.layout-horizontal]=\"Layout === 'horizontal'\"\n [class.layout-vertical]=\"Layout === 'vertical'\"\n [class.layout-grid]=\"Layout === 'grid'\"\n [ngStyle]=\"Layout === 'grid' ? {'grid-template-columns': GridTemplateColumns} : {}\">\n <!-- Individual Aggregate Cards -->\n @for (agg of CardAggregates; track agg) {\n <div class=\"aggregate-card\"\n [class]=\"GetStyleClass(agg)\"\n (click)=\"OnAggregateClick(agg)\"\n [title]=\"agg.description || agg.label\">\n <!-- Icon -->\n @if (agg.icon) {\n <div class=\"card-icon\">\n <i [class]=\"agg.icon\"></i>\n </div>\n }\n <!-- Content -->\n <div class=\"card-content\">\n <div class=\"card-value\" [class.loading]=\"Loading\">\n {{ Loading ? '...' : FormatValue(agg) }}\n </div>\n <div class=\"card-label\">{{ agg.label }}</div>\n </div>\n </div>\n }\n </div>\n </div>\n </ng-template>\n </mj-accordion-panel>\n</div>\n", styles: ["/* Aggregate Panel Component Styles */\n\n/* Layout/positioning only \u2014 visual chrome (border, radius, shadow, header,\n chevron, and .collapsed body-hiding) is now owned by <mj-accordion-panel>. */\n.aggregate-panel {\n display: flex;\n flex-direction: column;\n}\n\n/* Position variants */\n.position-right {\n height: 100%;\n}\n\n.position-bottom {\n width: 100%;\n}\n\n/* Title (projected into the accordion title slot) */\n.panel-title {\n font-weight: 600;\n font-size: 14px;\n color: var(--mj-text-primary);\n}\n\n/* Loading indicator (projected into the accordion actions slot) */\n.loading-indicator {\n color: var(--mj-brand-primary);\n font-size: 14px;\n}\n\n/* Panel Content */\n.panel-content {\n padding: 16px;\n overflow-y: auto;\n flex: 1;\n}\n\n/* Cards Container */\n.cards-container {\n display: flex;\n gap: 12px;\n}\n\n.layout-horizontal {\n flex-direction: row;\n flex-wrap: wrap;\n}\n\n.layout-vertical {\n flex-direction: column;\n}\n\n.layout-grid {\n display: grid;\n gap: 12px;\n}\n\n/* Aggregate Card */\n.aggregate-card {\n display: flex;\n align-items: flex-start;\n gap: 12px;\n padding: 12px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n cursor: pointer;\n transition: border-color 0.2s, box-shadow 0.2s, transform 0.2s;\n}\n\n.aggregate-card:hover {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 2px 8px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n transform: translateY(-1px);\n}\n\n/* Card Icon */\n.card-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 40px;\n height: 40px;\n background: var(--mj-bg-surface-card);\n border-radius: 8px;\n color: var(--mj-brand-primary);\n font-size: 18px;\n flex-shrink: 0;\n}\n\n/* Card Content */\n.card-content {\n flex: 1;\n min-width: 0;\n}\n\n.card-value {\n font-size: 20px;\n font-weight: 700;\n color: var(--mj-text-primary);\n line-height: 1.2;\n margin-bottom: 4px;\n word-break: break-word;\n}\n\n.card-value.loading {\n color: var(--mj-text-disabled);\n}\n\n.card-label {\n font-size: 12px;\n color: var(--mj-text-secondary);\n line-height: 1.3;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* Conditional Style Classes */\n.style-success {\n border-left: 4px solid var(--mj-status-success);\n}\n\n.style-success .card-value {\n color: var(--mj-status-success);\n}\n\n.style-success .card-icon {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success);\n}\n\n.style-warning {\n border-left: 4px solid var(--mj-status-warning);\n}\n\n.style-warning .card-value {\n color: var(--mj-status-warning-text);\n}\n\n.style-warning .card-icon {\n background: var(--mj-status-warning-bg);\n color: var(--mj-status-warning-text);\n}\n\n.style-danger {\n border-left: 4px solid var(--mj-status-error);\n}\n\n.style-danger .card-value {\n color: var(--mj-status-error);\n}\n\n.style-danger .card-icon {\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error);\n}\n\n.style-info {\n border-left: 4px solid var(--mj-brand-primary);\n}\n\n.style-info .card-value {\n color: var(--mj-brand-primary);\n}\n\n.style-info .card-icon {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.style-muted {\n border-left: 4px solid var(--mj-text-muted);\n}\n\n.style-muted .card-value {\n color: var(--mj-text-muted);\n}\n\n.style-muted .card-icon {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-muted);\n}\n\n/* Responsive adjustments for bottom position */\n.position-bottom .cards-container.layout-vertical {\n flex-direction: row;\n flex-wrap: wrap;\n}\n\n.position-bottom .cards-container.layout-vertical .aggregate-card {\n flex: 1 1 200px;\n max-width: 300px;\n}\n"] }]
341
339
  }], null, { Aggregates: [{
342
340
  type: Input
343
341
  }], Values: [{
@@ -1 +1 @@
1
- {"version":3,"file":"aggregate-panel.component.js","sourceRoot":"","sources":["../../../src/lib/aggregate-panel/aggregate-panel.component.ts","../../../src/lib/aggregate-panel/aggregate-panel.component.html"],"names":[],"mappings":"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","sourcesContent":["import {\n Component,\n Input,\n Output,\n EventEmitter,\n OnInit\n} from '@angular/core';\nimport {\n MJUserViewEntity_IGridAggregate as ViewGridAggregate,\n MJUserViewEntity_IAggregateValueFormat as AggregateValueFormat,\n MJUserViewEntity_IAggregateConditionalStyle as AggregateConditionalStyle\n} from '@memberjunction/core-entities';\nimport { AggregateValue } from '@memberjunction/core';\n\n/**\n * AggregatePanelComponent displays aggregate values in a card-based panel.\n * Can be positioned to the right or bottom of the grid, with various layout options.\n *\n * Features:\n * - Collapsible panel with customizable title\n * - Multiple layout options (horizontal, vertical, grid)\n * - Value formatting (number, currency, percent, date)\n * - Conditional styling (green/yellow/red based on value thresholds)\n * - Icon support for visual indicators\n */\n@Component({\n standalone: false,\n selector: 'mj-aggregate-panel',\n templateUrl: './aggregate-panel.component.html',\n styleUrls: ['./aggregate-panel.component.css']\n})\nexport class AggregatePanelComponent implements OnInit {\n /**\n * Array of aggregate configurations to display\n */\n @Input() Aggregates: ViewGridAggregate[] = [];\n\n /**\n * Map of aggregate values, keyed by expression or id\n */\n @Input() Values: Map<string, AggregateValue> = new Map();\n\n /**\n * Panel position relative to the grid\n */\n @Input() Position: 'right' | 'bottom' = 'right';\n\n /**\n * Panel width in pixels (only applies when Position is 'right')\n */\n @Input() Width: number = 280;\n\n /**\n * Layout style for aggregate cards\n */\n @Input() Layout: 'horizontal' | 'vertical' | 'grid' = 'vertical';\n\n /**\n * Number of columns when Layout is 'grid'\n */\n @Input() GridColumns: number = 2;\n\n /**\n * Panel title\n */\n @Input() Title: string = 'Summary';\n\n /**\n * Whether the panel can be collapsed\n */\n @Input() Collapsible: boolean = true;\n\n /**\n * Whether the panel starts in collapsed state\n */\n @Input() StartCollapsed: boolean = false;\n\n /**\n * Whether aggregates are currently loading\n */\n @Input() Loading: boolean = false;\n\n /**\n * Emitted when panel collapsed state changes\n */\n @Output() CollapsedChange = new EventEmitter<boolean>();\n\n /**\n * Emitted when user clicks an aggregate card (for editing/details)\n */\n @Output() AggregateClick = new EventEmitter<ViewGridAggregate>();\n\n IsCollapsed = false;\n\n ngOnInit(): void {\n this.IsCollapsed = this.StartCollapsed;\n }\n\n /**\n * Toggle panel collapsed state\n */\n ToggleCollapse(): void {\n if (this.Collapsible) {\n this.IsCollapsed = !this.IsCollapsed;\n this.CollapsedChange.emit(this.IsCollapsed);\n }\n }\n\n /**\n * Handle click on an aggregate card\n */\n OnAggregateClick(agg: ViewGridAggregate): void {\n this.AggregateClick.emit(agg);\n }\n\n /**\n * Get the formatted value for an aggregate\n */\n FormatValue(agg: ViewGridAggregate): string {\n const key = agg.id || agg.expression;\n const value = this.Values.get(key);\n\n if (value == null) return '—';\n\n const format = agg.format || {};\n return this.formatByType(value, format);\n }\n\n /**\n * Get the CSS class for conditional styling\n */\n GetStyleClass(agg: ViewGridAggregate): string {\n const key = agg.id || agg.expression;\n const value = this.Values.get(key);\n\n if (value == null || !agg.conditionalStyles?.length) return '';\n\n for (const rule of agg.conditionalStyles) {\n if (this.evaluateCondition(value, rule)) {\n return `style-${rule.style}`;\n }\n }\n return '';\n }\n\n /**\n * Get enabled aggregates (filter out disabled ones)\n */\n get EnabledAggregates(): ViewGridAggregate[] {\n return this.Aggregates.filter(a => a.enabled !== false);\n }\n\n /**\n * Get card aggregates sorted by order\n */\n get CardAggregates(): ViewGridAggregate[] {\n return this.EnabledAggregates\n .filter(a => a.displayType === 'card')\n .sort((a, b) => (a.order || 0) - (b.order || 0));\n }\n\n /**\n * Get panel style for right position\n */\n get PanelStyle(): Record<string, string> {\n if (this.Position === 'right') {\n return {\n width: `${this.Width}px`,\n minWidth: `${this.Width}px`\n };\n }\n return {};\n }\n\n /**\n * Get grid template columns for grid layout\n */\n get GridTemplateColumns(): string {\n if (this.Layout === 'grid') {\n return `repeat(${this.GridColumns}, 1fr)`;\n }\n return '';\n }\n\n /**\n * Format value based on type configuration\n */\n private formatByType(value: AggregateValue, format: AggregateValueFormat): string {\n if (value == null) return '—';\n\n // Handle prefix/suffix\n const prefix = format.prefix || '';\n const suffix = format.suffix || '';\n\n // Handle different value types\n if (typeof value === 'number') {\n const formatted = this.formatNumber(value, format);\n return `${prefix}${formatted}${suffix}`;\n }\n\n if (value instanceof Date) {\n return this.formatDate(value, format.dateFormat);\n }\n\n if (typeof value === 'boolean') {\n return value ? 'Yes' : 'No';\n }\n\n // String or unknown type\n return `${prefix}${String(value)}${suffix}`;\n }\n\n /**\n * Format a number value\n */\n private formatNumber(value: number, format: AggregateValueFormat): string {\n const options: Intl.NumberFormatOptions = {\n minimumFractionDigits: format.decimals ?? 0,\n maximumFractionDigits: format.decimals ?? 2,\n useGrouping: format.thousandsSeparator !== false\n };\n\n // Handle currency\n if (format.currencyCode) {\n options.style = 'currency';\n options.currency = format.currencyCode;\n }\n\n try {\n return new Intl.NumberFormat('en-US', options).format(value);\n } catch {\n return String(value);\n }\n }\n\n /**\n * Format a date value\n */\n private formatDate(value: Date, dateFormat?: string): string {\n try {\n // Simple format presets\n const options: Intl.DateTimeFormatOptions = {};\n\n switch (dateFormat) {\n case 'short':\n options.dateStyle = 'short';\n break;\n case 'medium':\n options.dateStyle = 'medium';\n break;\n case 'long':\n options.dateStyle = 'long';\n break;\n default:\n options.dateStyle = 'medium';\n }\n\n return new Intl.DateTimeFormat('en-US', options).format(value);\n } catch {\n return String(value);\n }\n }\n\n /**\n * Evaluate a conditional styling rule\n */\n private evaluateCondition(value: AggregateValue, rule: AggregateConditionalStyle): boolean {\n // For non-numeric values, only support equality checks\n if (typeof value !== 'number') {\n if (rule.operator === 'eq') return value === rule.value;\n if (rule.operator === 'neq') return value !== rule.value;\n return false;\n }\n\n const numValue = Number(rule.value);\n const numValue2 = rule.value2 != null ? Number(rule.value2) : numValue;\n\n switch (rule.operator) {\n case 'gt': return value > numValue;\n case 'gte': return value >= numValue;\n case 'lt': return value < numValue;\n case 'lte': return value <= numValue;\n case 'eq': return value === numValue;\n case 'neq': return value !== numValue;\n case 'between': return value >= numValue && value <= numValue2;\n default: return false;\n }\n }\n}\n","<div class=\"aggregate-panel\"\n [class.position-right]=\"Position === 'right'\"\n [class.position-bottom]=\"Position === 'bottom'\"\n [class.collapsed]=\"IsCollapsed\"\n [ngStyle]=\"PanelStyle\">\n\n <!-- Panel Header -->\n <div class=\"panel-header\" (click)=\"ToggleCollapse()\">\n <span class=\"panel-title\">{{ Title }}</span>\n\n <div class=\"panel-header-right\">\n <!-- Loading indicator -->\n @if (Loading) {\n <span class=\"loading-indicator\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n </span>\n }\n\n <!-- Collapse toggle -->\n @if (Collapsible) {\n <button class=\"collapse-toggle\" type=\"button\">\n <i class=\"fa-solid\" [class.fa-chevron-up]=\"!IsCollapsed\" [class.fa-chevron-down]=\"IsCollapsed\"></i>\n </button>\n }\n </div>\n </div>\n\n <!-- Panel Content -->\n @if (!IsCollapsed) {\n <div class=\"panel-content\">\n <!-- Empty state -->\n @if (CardAggregates.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-chart-simple\"></i>\n <p>No summaries configured</p>\n </div>\n }\n <!-- Cards Container -->\n <div class=\"cards-container\"\n [class.layout-horizontal]=\"Layout === 'horizontal'\"\n [class.layout-vertical]=\"Layout === 'vertical'\"\n [class.layout-grid]=\"Layout === 'grid'\"\n [ngStyle]=\"Layout === 'grid' ? {'grid-template-columns': GridTemplateColumns} : {}\">\n <!-- Individual Aggregate Cards -->\n @for (agg of CardAggregates; track agg) {\n <div class=\"aggregate-card\"\n [class]=\"GetStyleClass(agg)\"\n (click)=\"OnAggregateClick(agg)\"\n [title]=\"agg.description || agg.label\">\n <!-- Icon -->\n @if (agg.icon) {\n <div class=\"card-icon\">\n <i [class]=\"agg.icon\"></i>\n </div>\n }\n <!-- Content -->\n <div class=\"card-content\">\n <div class=\"card-value\" [class.loading]=\"Loading\">\n {{ Loading ? '...' : FormatValue(agg) }}\n </div>\n <div class=\"card-label\">{{ agg.label }}</div>\n </div>\n </div>\n }\n </div>\n </div>\n }\n</div>\n"]}
1
+ {"version":3,"file":"aggregate-panel.component.js","sourceRoot":"","sources":["../../../src/lib/aggregate-panel/aggregate-panel.component.ts","../../../src/lib/aggregate-panel/aggregate-panel.component.html"],"names":[],"mappings":"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","sourcesContent":["import {\n Component,\n Input,\n Output,\n EventEmitter,\n OnInit\n} from '@angular/core';\nimport {\n MJUserViewEntity_IGridAggregate as ViewGridAggregate,\n MJUserViewEntity_IAggregateValueFormat as AggregateValueFormat,\n MJUserViewEntity_IAggregateConditionalStyle as AggregateConditionalStyle\n} from '@memberjunction/core-entities';\nimport { AggregateValue } from '@memberjunction/core';\n\n/**\n * AggregatePanelComponent displays aggregate values in a card-based panel.\n * Can be positioned to the right or bottom of the grid, with various layout options.\n *\n * Features:\n * - Collapsible panel with customizable title\n * - Multiple layout options (horizontal, vertical, grid)\n * - Value formatting (number, currency, percent, date)\n * - Conditional styling (green/yellow/red based on value thresholds)\n * - Icon support for visual indicators\n */\n@Component({\n standalone: false,\n selector: 'mj-aggregate-panel',\n templateUrl: './aggregate-panel.component.html',\n styleUrls: ['./aggregate-panel.component.css']\n})\nexport class AggregatePanelComponent implements OnInit {\n /**\n * Array of aggregate configurations to display\n */\n @Input() Aggregates: ViewGridAggregate[] = [];\n\n /**\n * Map of aggregate values, keyed by expression or id\n */\n @Input() Values: Map<string, AggregateValue> = new Map();\n\n /**\n * Panel position relative to the grid\n */\n @Input() Position: 'right' | 'bottom' = 'right';\n\n /**\n * Panel width in pixels (only applies when Position is 'right')\n */\n @Input() Width: number = 280;\n\n /**\n * Layout style for aggregate cards\n */\n @Input() Layout: 'horizontal' | 'vertical' | 'grid' = 'vertical';\n\n /**\n * Number of columns when Layout is 'grid'\n */\n @Input() GridColumns: number = 2;\n\n /**\n * Panel title\n */\n @Input() Title: string = 'Summary';\n\n /**\n * Whether the panel can be collapsed\n */\n @Input() Collapsible: boolean = true;\n\n /**\n * Whether the panel starts in collapsed state\n */\n @Input() StartCollapsed: boolean = false;\n\n /**\n * Whether aggregates are currently loading\n */\n @Input() Loading: boolean = false;\n\n /**\n * Emitted when panel collapsed state changes\n */\n @Output() CollapsedChange = new EventEmitter<boolean>();\n\n /**\n * Emitted when user clicks an aggregate card (for editing/details)\n */\n @Output() AggregateClick = new EventEmitter<ViewGridAggregate>();\n\n IsCollapsed = false;\n\n ngOnInit(): void {\n this.IsCollapsed = this.StartCollapsed;\n }\n\n /**\n * Toggle panel collapsed state\n */\n ToggleCollapse(): void {\n if (this.Collapsible) {\n this.IsCollapsed = !this.IsCollapsed;\n this.CollapsedChange.emit(this.IsCollapsed);\n }\n }\n\n /**\n * Handle the accordion panel's ExpandedChange. Accordion `Expanded` is the\n * inverse of our `IsCollapsed`; preserves the CollapsedChange emit side-effect.\n */\n OnPanelExpandedChange(expanded: boolean): void {\n this.IsCollapsed = !expanded;\n this.CollapsedChange.emit(this.IsCollapsed);\n }\n\n /**\n * Handle click on an aggregate card\n */\n OnAggregateClick(agg: ViewGridAggregate): void {\n this.AggregateClick.emit(agg);\n }\n\n /**\n * Get the formatted value for an aggregate\n */\n FormatValue(agg: ViewGridAggregate): string {\n const key = agg.id || agg.expression;\n const value = this.Values.get(key);\n\n if (value == null) return '—';\n\n const format = agg.format || {};\n return this.formatByType(value, format);\n }\n\n /**\n * Get the CSS class for conditional styling\n */\n GetStyleClass(agg: ViewGridAggregate): string {\n const key = agg.id || agg.expression;\n const value = this.Values.get(key);\n\n if (value == null || !agg.conditionalStyles?.length) return '';\n\n for (const rule of agg.conditionalStyles) {\n if (this.evaluateCondition(value, rule)) {\n return `style-${rule.style}`;\n }\n }\n return '';\n }\n\n /**\n * Get enabled aggregates (filter out disabled ones)\n */\n get EnabledAggregates(): ViewGridAggregate[] {\n return this.Aggregates.filter(a => a.enabled !== false);\n }\n\n /**\n * Get card aggregates sorted by order\n */\n get CardAggregates(): ViewGridAggregate[] {\n return this.EnabledAggregates\n .filter(a => a.displayType === 'card')\n .sort((a, b) => (a.order || 0) - (b.order || 0));\n }\n\n /**\n * Get panel style for right position\n */\n get PanelStyle(): Record<string, string> {\n if (this.Position === 'right') {\n return {\n width: `${this.Width}px`,\n minWidth: `${this.Width}px`\n };\n }\n return {};\n }\n\n /**\n * Get grid template columns for grid layout\n */\n get GridTemplateColumns(): string {\n if (this.Layout === 'grid') {\n return `repeat(${this.GridColumns}, 1fr)`;\n }\n return '';\n }\n\n /**\n * Format value based on type configuration\n */\n private formatByType(value: AggregateValue, format: AggregateValueFormat): string {\n if (value == null) return '—';\n\n // Handle prefix/suffix\n const prefix = format.prefix || '';\n const suffix = format.suffix || '';\n\n // Handle different value types\n if (typeof value === 'number') {\n const formatted = this.formatNumber(value, format);\n return `${prefix}${formatted}${suffix}`;\n }\n\n if (value instanceof Date) {\n return this.formatDate(value, format.dateFormat);\n }\n\n if (typeof value === 'boolean') {\n return value ? 'Yes' : 'No';\n }\n\n // String or unknown type\n return `${prefix}${String(value)}${suffix}`;\n }\n\n /**\n * Format a number value\n */\n private formatNumber(value: number, format: AggregateValueFormat): string {\n const options: Intl.NumberFormatOptions = {\n minimumFractionDigits: format.decimals ?? 0,\n maximumFractionDigits: format.decimals ?? 2,\n useGrouping: format.thousandsSeparator !== false\n };\n\n // Handle currency\n if (format.currencyCode) {\n options.style = 'currency';\n options.currency = format.currencyCode;\n }\n\n try {\n return new Intl.NumberFormat('en-US', options).format(value);\n } catch {\n return String(value);\n }\n }\n\n /**\n * Format a date value\n */\n private formatDate(value: Date, dateFormat?: string): string {\n try {\n // Simple format presets\n const options: Intl.DateTimeFormatOptions = {};\n\n switch (dateFormat) {\n case 'short':\n options.dateStyle = 'short';\n break;\n case 'medium':\n options.dateStyle = 'medium';\n break;\n case 'long':\n options.dateStyle = 'long';\n break;\n default:\n options.dateStyle = 'medium';\n }\n\n return new Intl.DateTimeFormat('en-US', options).format(value);\n } catch {\n return String(value);\n }\n }\n\n /**\n * Evaluate a conditional styling rule\n */\n private evaluateCondition(value: AggregateValue, rule: AggregateConditionalStyle): boolean {\n // For non-numeric values, only support equality checks\n if (typeof value !== 'number') {\n if (rule.operator === 'eq') return value === rule.value;\n if (rule.operator === 'neq') return value !== rule.value;\n return false;\n }\n\n const numValue = Number(rule.value);\n const numValue2 = rule.value2 != null ? Number(rule.value2) : numValue;\n\n switch (rule.operator) {\n case 'gt': return value > numValue;\n case 'gte': return value >= numValue;\n case 'lt': return value < numValue;\n case 'lte': return value <= numValue;\n case 'eq': return value === numValue;\n case 'neq': return value !== numValue;\n case 'between': return value >= numValue && value <= numValue2;\n default: return false;\n }\n }\n}\n","<div class=\"aggregate-panel\"\n [class.position-right]=\"Position === 'right'\"\n [class.position-bottom]=\"Position === 'bottom'\"\n [ngStyle]=\"PanelStyle\">\n\n <!-- Migrated to <mj-accordion-panel>. The bespoke .panel-header / .collapse-toggle\n and the @if(!IsCollapsed) body gate are replaced by the accordion's own header,\n chevron, and lazy/animated body. Expanded is the inverse of IsCollapsed; the\n (ExpandedChange) handler preserves the CollapsedChange emit side-effect. -->\n <mj-accordion-panel\n Size=\"sm\"\n [FlushBody]=\"true\"\n [Expanded]=\"!IsCollapsed\"\n [Disabled]=\"!Collapsible\"\n (ExpandedChange)=\"OnPanelExpandedChange($event)\">\n\n <ng-template mjAccordionTitle>\n <span class=\"panel-title\">{{ Title }}</span>\n </ng-template>\n\n <!-- Loading indicator lives in the header actions slot (sibling of the chevron). -->\n <ng-template mjAccordionActions>\n @if (Loading) {\n <span class=\"loading-indicator\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n </span>\n }\n </ng-template>\n\n <ng-template mjAccordionBody>\n <div class=\"panel-content\">\n <!-- Empty state -->\n @if (CardAggregates.length === 0) {\n <mj-empty-state\n Size=\"compact\"\n Icon=\"fa-solid fa-chart-simple\"\n Title=\"No summaries configured\" />\n }\n <!-- Cards Container -->\n <div class=\"cards-container\"\n [class.layout-horizontal]=\"Layout === 'horizontal'\"\n [class.layout-vertical]=\"Layout === 'vertical'\"\n [class.layout-grid]=\"Layout === 'grid'\"\n [ngStyle]=\"Layout === 'grid' ? {'grid-template-columns': GridTemplateColumns} : {}\">\n <!-- Individual Aggregate Cards -->\n @for (agg of CardAggregates; track agg) {\n <div class=\"aggregate-card\"\n [class]=\"GetStyleClass(agg)\"\n (click)=\"OnAggregateClick(agg)\"\n [title]=\"agg.description || agg.label\">\n <!-- Icon -->\n @if (agg.icon) {\n <div class=\"card-icon\">\n <i [class]=\"agg.icon\"></i>\n </div>\n }\n <!-- Content -->\n <div class=\"card-content\">\n <div class=\"card-value\" [class.loading]=\"Loading\">\n {{ Loading ? '...' : FormatValue(agg) }}\n </div>\n <div class=\"card-label\">{{ agg.label }}</div>\n </div>\n </div>\n }\n </div>\n </div>\n </ng-template>\n </mj-accordion-panel>\n</div>\n"]}
@@ -6,7 +6,8 @@ import { PillColorUtil } from '../pill/pill.component';
6
6
  import { HighlightUtil } from '../utils/highlight.util';
7
7
  import * as i0 from "@angular/core";
8
8
  import * as i1 from "@memberjunction/ng-shared-generic";
9
- import * as i2 from "../pill/pill.component";
9
+ import * as i2 from "@memberjunction/ng-ui-components";
10
+ import * as i3 from "../pill/pill.component";
10
11
  const _forTrack0 = ($index, $item) => $item.trackId;
11
12
  const _forTrack1 = ($index, $item) => $item.field.name;
12
13
  function EntityCardsComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
@@ -201,16 +202,12 @@ function EntityCardsComponent_Conditional_2_For_2_Template(rf, ctx) { if (rf & 1
201
202
  i0.ɵɵconditional(vm_r2.hasHiddenFieldMatch ? 14 : -1);
202
203
  } }
203
204
  function EntityCardsComponent_Conditional_2_Conditional_3_Template(rf, ctx) { if (rf & 1) {
204
- i0.ɵɵelementStart(0, "div", 5);
205
- i0.ɵɵelement(1, "i", 31);
206
- i0.ɵɵelementStart(2, "p");
207
- i0.ɵɵtext(3, "No records to display");
208
- i0.ɵɵelementEnd()();
205
+ i0.ɵɵelement(0, "mj-empty-state", 5);
209
206
  } }
210
207
  function EntityCardsComponent_Conditional_2_Template(rf, ctx) { if (rf & 1) {
211
208
  i0.ɵɵelementStart(0, "div", 2);
212
209
  i0.ɵɵrepeaterCreate(1, EntityCardsComponent_Conditional_2_For_2_Template, 15, 9, "div", 4, _forTrack0);
213
- i0.ɵɵconditionalCreate(3, EntityCardsComponent_Conditional_2_Conditional_3_Template, 4, 0, "div", 5);
210
+ i0.ɵɵconditionalCreate(3, EntityCardsComponent_Conditional_2_Conditional_3_Template, 1, 0, "mj-empty-state", 5);
214
211
  i0.ɵɵelementEnd();
215
212
  } if (rf & 2) {
216
213
  const ctx_r2 = i0.ɵɵnextContext();
@@ -917,18 +914,18 @@ export class EntityCardsComponent extends BaseAngularComponent {
917
914
  return HighlightUtil.highlight(text, this.filterText, false);
918
915
  }
919
916
  static ɵfac = function EntityCardsComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || EntityCardsComponent)(i0.ɵɵdirectiveInject(i0.ElementRef), i0.ɵɵdirectiveInject(i0.ChangeDetectorRef)); };
920
- static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: EntityCardsComponent, selectors: [["mj-entity-cards"]], inputs: { entity: "entity", records: "records", selectedRecordId: "selectedRecordId", cardTemplate: "cardTemplate", hiddenFieldMatches: "hiddenFieldMatches", filterText: "filterText", pageSize: "pageSize" }, outputs: { recordSelected: "recordSelected", recordOpened: "recordOpened" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature, i0.ɵɵNgOnChangesFeature], decls: 3, vars: 1, consts: [[1, "cards-view-wrapper"], [1, "loading-container"], [1, "cards-container"], ["text", "Loading records..."], [1, "data-card", 3, "selected"], [1, "no-results"], [1, "data-card", 3, "click"], [1, "card-header"], [1, "card-thumbnail"], [1, "card-avatar", 3, "background-color"], [1, "card-header-content"], [1, "card-title", 3, "innerHTML"], ["title", "Open Record", 1, "card-open-btn", 3, "click"], [1, "fa-solid", "fa-external-link-alt"], [1, "card-body"], [1, "card-description", 3, "innerHTML"], [1, "card-fields"], [1, "card-footer"], [1, "hidden-match-indicator", 3, "title"], ["alt", "", 3, "src"], [1, "card-avatar"], [3, "value"], [1, "card-subtitle", 3, "innerHTML"], [1, "field-item", 3, "field-boolean", "field-text"], [1, "field-item"], [1, "field-icon"], [1, "field-label"], [1, "field-value"], [1, "field-value", "field-date"], [1, "field-text-value", 3, "innerHTML"], [1, "fa-solid", "fa-magnifying-glass"], [1, "fa-solid", "fa-inbox"]], template: function EntityCardsComponent_Template(rf, ctx) { if (rf & 1) {
917
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: EntityCardsComponent, selectors: [["mj-entity-cards"]], inputs: { entity: "entity", records: "records", selectedRecordId: "selectedRecordId", cardTemplate: "cardTemplate", hiddenFieldMatches: "hiddenFieldMatches", filterText: "filterText", pageSize: "pageSize" }, outputs: { recordSelected: "recordSelected", recordOpened: "recordOpened" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature, i0.ɵɵNgOnChangesFeature], decls: 3, vars: 1, consts: [[1, "cards-view-wrapper"], [1, "loading-container"], [1, "cards-container"], ["text", "Loading records..."], [1, "data-card", 3, "selected"], ["Variant", "no-results", "Title", "No records to display", 1, "no-results"], [1, "data-card", 3, "click"], [1, "card-header"], [1, "card-thumbnail"], [1, "card-avatar", 3, "background-color"], [1, "card-header-content"], [1, "card-title", 3, "innerHTML"], ["title", "Open Record", 1, "card-open-btn", 3, "click"], [1, "fa-solid", "fa-external-link-alt"], [1, "card-body"], [1, "card-description", 3, "innerHTML"], [1, "card-fields"], [1, "card-footer"], [1, "hidden-match-indicator", 3, "title"], ["alt", "", 3, "src"], [1, "card-avatar"], [3, "value"], [1, "card-subtitle", 3, "innerHTML"], [1, "field-item", 3, "field-boolean", "field-text"], [1, "field-item"], [1, "field-icon"], [1, "field-label"], [1, "field-value"], [1, "field-value", "field-date"], [1, "field-text-value", 3, "innerHTML"], [1, "fa-solid", "fa-magnifying-glass"]], template: function EntityCardsComponent_Template(rf, ctx) { if (rf & 1) {
921
918
  i0.ɵɵelementStart(0, "div", 0);
922
919
  i0.ɵɵconditionalCreate(1, EntityCardsComponent_Conditional_1_Template, 2, 0, "div", 1)(2, EntityCardsComponent_Conditional_2_Template, 4, 1, "div", 2);
923
920
  i0.ɵɵelementEnd();
924
921
  } if (rf & 2) {
925
922
  i0.ɵɵadvance();
926
923
  i0.ɵɵconditional(ctx.isLoading && ctx.effectiveRecords.length === 0 ? 1 : 2);
927
- } }, dependencies: [i1.LoadingComponent, i2.PillComponent], styles: ["/* Scoped to mj-entity-cards to prevent style leakage with ViewEncapsulation.None */\nmj-entity-cards .cards-view-wrapper {\n height: 100%;\n overflow-y: auto;\n overflow-x: hidden;\n}\n\nmj-entity-cards .cards-container {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));\n gap: 20px;\n padding: 4px;\n}\n\nmj-entity-cards .data-card {\n background: var(--mj-bg-surface);\n border-radius: 12px;\n border: 1px solid var(--mj-border-default);\n overflow: hidden;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n/* Hover state for unselected cards */\nmj-entity-cards .data-card:hover:not(.selected) {\n border-color: var(--mj-border-strong);\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);\n transform: translateY(-2px);\n}\nmj-entity-cards .data-card:hover .card-open-btn {\n opacity: 1;\n}\n\n/* Selected state - subtle but clear */\nmj-entity-cards .data-card.selected {\n border-color: var(--mj-brand-primary);\n}\n\nmj-entity-cards .data-card.selected .card-title {\n color: var(--mj-brand-primary-hover);\n}\n\n/* Selected + hover state - same as regular hover */\nmj-entity-cards .data-card.selected:hover {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);\n transform: translateY(-2px);\n}\n\nmj-entity-cards .card-header {\n display: flex;\n align-items: flex-start;\n padding: 16px;\n gap: 12px;\n}\n\nmj-entity-cards .card-thumbnail {\n width: 48px;\n height: 48px;\n border-radius: 8px;\n overflow: hidden;\n flex-shrink: 0;\n}\nmj-entity-cards .card-thumbnail img {\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n\nmj-entity-cards .card-avatar {\n width: 48px;\n height: 48px;\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 16px;\n font-weight: 600;\n color: var(--mj-text-inverse);\n flex-shrink: 0;\n}\n\nmj-entity-cards .card-header-content {\n flex: 1;\n min-width: 0;\n}\n\nmj-entity-cards .card-title {\n margin: 0;\n font-size: 15px;\n font-weight: 600;\n color: var(--mj-text-primary);\n line-height: 1.3;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\nmj-entity-cards .card-subtitle {\n display: block;\n margin-top: 2px;\n font-size: 12px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\nmj-entity-cards .card-open-btn {\n width: 32px;\n height: 32px;\n border: none;\n background: transparent;\n border-radius: 6px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-muted);\n opacity: 0;\n transition: all 0.15s ease;\n flex-shrink: 0;\n}\nmj-entity-cards .card-open-btn:hover {\n background: var(--mj-bg-surface-card);\n color: var(--mj-brand-primary);\n}\n\nmj-entity-cards .card-body {\n padding: 0 16px 16px 16px;\n}\n\nmj-entity-cards .card-description {\n margin: 0 0 12px 0;\n font-size: 13px;\n color: var(--mj-text-secondary);\n line-height: 1.5;\n}\n\n/* Card Display Fields */\nmj-entity-cards .card-fields {\n display: flex;\n flex-wrap: wrap;\n gap: 12px;\n padding-top: 12px;\n border-top: 1px solid var(--mj-border-subtle);\n}\n\nmj-entity-cards .field-item {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 60px;\n}\n\nmj-entity-cards .field-item .field-value {\n font-size: 15px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\nmj-entity-cards .field-item .field-label {\n font-size: 10px;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.3px;\n}\n\n/* Boolean fields */\nmj-entity-cards .field-item.field-boolean {\n flex-direction: row;\n align-items: center;\n gap: 6px;\n min-width: auto;\n}\n\nmj-entity-cards .field-item.field-boolean .field-icon {\n font-size: 14px;\n}\n\nmj-entity-cards .field-item.field-boolean .field-icon.bool-true {\n color: var(--mj-status-success);\n}\n\nmj-entity-cards .field-item.field-boolean .field-icon.bool-false {\n color: var(--mj-text-muted);\n}\n\nmj-entity-cards .field-item.field-boolean .field-label {\n font-size: 12px;\n text-transform: none;\n color: var(--mj-text-secondary);\n}\n\n/* Text fields */\nmj-entity-cards .field-item.field-text {\n flex: 1 1 100%;\n max-width: 100%;\n}\n\nmj-entity-cards .field-item .field-text-value {\n font-size: 13px;\n color: var(--mj-text-secondary);\n line-height: 1.4;\n word-break: break-word;\n}\n\n/* Date fields */\nmj-entity-cards .field-item .field-date {\n font-size: 13px;\n font-weight: 500;\n}\n\nmj-entity-cards .card-footer {\n padding: 12px 16px;\n background: var(--mj-bg-surface-card);\n border-top: 1px solid var(--mj-border-subtle);\n}\n\n/* Highlight matches - scoped to work with innerHTML */\nmj-entity-cards .highlight-match {\n background-color: color-mix(in srgb, var(--mj-status-warning) 40%, var(--mj-bg-surface));\n border-radius: 2px;\n}\n\n/* Pill spacing when used as subtitle */\nmj-entity-cards .card-header-content mj-pill {\n display: block;\n margin-top: 4px;\n}\n\n/* Hidden field match indicator */\nmj-entity-cards .hidden-match-indicator {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 8px 16px;\n background: var(--mj-status-warning-bg);\n border-top: 1px solid var(--mj-status-warning-border);\n font-size: 11px;\n color: var(--mj-status-warning);\n}\n\nmj-entity-cards .hidden-match-indicator i {\n font-size: 10px;\n}\n\nmj-entity-cards .hidden-match-indicator span {\n font-weight: 500;\n}\n\n/* Loading state */\nmj-entity-cards .loading-container {\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 200px;\n padding: 40px;\n}\n\n/* No results state */\nmj-entity-cards .no-results {\n grid-column: 1 / -1;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 60px 20px;\n color: var(--mj-text-muted);\n text-align: center;\n}\nmj-entity-cards .no-results i {\n font-size: 48px;\n margin-bottom: 16px;\n opacity: 0.5;\n}\nmj-entity-cards .no-results p {\n margin: 0;\n font-size: 14px;\n}\n"], encapsulation: 2 });
924
+ } }, dependencies: [i1.LoadingComponent, i2.MJEmptyStateComponent, i3.PillComponent], styles: ["/* Scoped to mj-entity-cards to prevent style leakage with ViewEncapsulation.None */\nmj-entity-cards .cards-view-wrapper {\n height: 100%;\n overflow-y: auto;\n overflow-x: hidden;\n}\n\nmj-entity-cards .cards-container {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));\n gap: 20px;\n padding: 4px;\n}\n\nmj-entity-cards .data-card {\n background: var(--mj-bg-surface);\n border-radius: 12px;\n border: 1px solid var(--mj-border-default);\n overflow: hidden;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n/* Hover state for unselected cards */\nmj-entity-cards .data-card:hover:not(.selected) {\n border-color: var(--mj-border-strong);\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);\n transform: translateY(-2px);\n}\nmj-entity-cards .data-card:hover .card-open-btn {\n opacity: 1;\n}\n\n/* Selected state - subtle but clear */\nmj-entity-cards .data-card.selected {\n border-color: var(--mj-brand-primary);\n}\n\nmj-entity-cards .data-card.selected .card-title {\n color: var(--mj-brand-primary-hover);\n}\n\n/* Selected + hover state - same as regular hover */\nmj-entity-cards .data-card.selected:hover {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);\n transform: translateY(-2px);\n}\n\nmj-entity-cards .card-header {\n display: flex;\n align-items: flex-start;\n padding: 16px;\n gap: 12px;\n}\n\nmj-entity-cards .card-thumbnail {\n width: 48px;\n height: 48px;\n border-radius: 8px;\n overflow: hidden;\n flex-shrink: 0;\n}\nmj-entity-cards .card-thumbnail img {\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n\nmj-entity-cards .card-avatar {\n width: 48px;\n height: 48px;\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 16px;\n font-weight: 600;\n color: var(--mj-text-inverse);\n flex-shrink: 0;\n}\n\nmj-entity-cards .card-header-content {\n flex: 1;\n min-width: 0;\n}\n\nmj-entity-cards .card-title {\n margin: 0;\n font-size: 15px;\n font-weight: 600;\n color: var(--mj-text-primary);\n line-height: 1.3;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\nmj-entity-cards .card-subtitle {\n display: block;\n margin-top: 2px;\n font-size: 12px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\nmj-entity-cards .card-open-btn {\n width: 32px;\n height: 32px;\n border: none;\n background: transparent;\n border-radius: 6px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-muted);\n opacity: 0;\n transition: all 0.15s ease;\n flex-shrink: 0;\n}\nmj-entity-cards .card-open-btn:hover {\n background: var(--mj-bg-surface-card);\n color: var(--mj-brand-primary);\n}\n\nmj-entity-cards .card-body {\n padding: 0 16px 16px 16px;\n}\n\nmj-entity-cards .card-description {\n margin: 0 0 12px 0;\n font-size: 13px;\n color: var(--mj-text-secondary);\n line-height: 1.5;\n}\n\n/* Card Display Fields */\nmj-entity-cards .card-fields {\n display: flex;\n flex-wrap: wrap;\n gap: 12px;\n padding-top: 12px;\n border-top: 1px solid var(--mj-border-subtle);\n}\n\nmj-entity-cards .field-item {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 60px;\n}\n\nmj-entity-cards .field-item .field-value {\n font-size: 15px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\nmj-entity-cards .field-item .field-label {\n font-size: 10px;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.3px;\n}\n\n/* Boolean fields */\nmj-entity-cards .field-item.field-boolean {\n flex-direction: row;\n align-items: center;\n gap: 6px;\n min-width: auto;\n}\n\nmj-entity-cards .field-item.field-boolean .field-icon {\n font-size: 14px;\n}\n\nmj-entity-cards .field-item.field-boolean .field-icon.bool-true {\n color: var(--mj-status-success);\n}\n\nmj-entity-cards .field-item.field-boolean .field-icon.bool-false {\n color: var(--mj-text-muted);\n}\n\nmj-entity-cards .field-item.field-boolean .field-label {\n font-size: 12px;\n text-transform: none;\n color: var(--mj-text-secondary);\n}\n\n/* Text fields */\nmj-entity-cards .field-item.field-text {\n flex: 1 1 100%;\n max-width: 100%;\n}\n\nmj-entity-cards .field-item .field-text-value {\n font-size: 13px;\n color: var(--mj-text-secondary);\n line-height: 1.4;\n word-break: break-word;\n}\n\n/* Date fields */\nmj-entity-cards .field-item .field-date {\n font-size: 13px;\n font-weight: 500;\n}\n\nmj-entity-cards .card-footer {\n padding: 12px 16px;\n background: var(--mj-bg-surface-card);\n border-top: 1px solid var(--mj-border-subtle);\n}\n\n/* Highlight matches - scoped to work with innerHTML */\nmj-entity-cards .highlight-match {\n background-color: color-mix(in srgb, var(--mj-status-warning) 40%, var(--mj-bg-surface));\n border-radius: 2px;\n}\n\n/* Pill spacing when used as subtitle */\nmj-entity-cards .card-header-content mj-pill {\n display: block;\n margin-top: 4px;\n}\n\n/* Hidden field match indicator */\nmj-entity-cards .hidden-match-indicator {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 8px 16px;\n background: var(--mj-status-warning-bg);\n border-top: 1px solid var(--mj-status-warning-border);\n font-size: 11px;\n color: var(--mj-status-warning);\n}\n\nmj-entity-cards .hidden-match-indicator i {\n font-size: 10px;\n}\n\nmj-entity-cards .hidden-match-indicator span {\n font-weight: 500;\n}\n\n/* Loading state */\nmj-entity-cards .loading-container {\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 200px;\n padding: 40px;\n}\n\n/* No results state \u2014 span the full grid width */\nmj-entity-cards .no-results {\n grid-column: 1 / -1;\n}\n"], encapsulation: 2 });
928
925
  }
929
926
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(EntityCardsComponent, [{
930
927
  type: Component,
931
- args: [{ standalone: false, selector: 'mj-entity-cards', encapsulation: ViewEncapsulation.None, template: "<div class=\"cards-view-wrapper\">\n @if (isLoading && effectiveRecords.length === 0) {\n <div class=\"loading-container\">\n <mj-loading text=\"Loading records...\"></mj-loading>\n </div>\n } @else {\n <div class=\"cards-container\">\n @for (vm of cardViewModels; track vm.trackId) {\n <div\n class=\"data-card\"\n [class.selected]=\"vm.isSelected\"\n (click)=\"onCardClick(vm.record)\">\n\n <!-- Card Header with Avatar/Icon -->\n <div class=\"card-header\">\n @switch (vm.thumbnailType) {\n @case ('image') {\n <div class=\"card-thumbnail\">\n <img [src]=\"vm.thumbnailUrl\" alt=\"\" />\n </div>\n }\n @case ('icon') {\n <div class=\"card-avatar\" [style.background-color]=\"vm.color\">\n <i [class]=\"vm.thumbnailUrl\"></i>\n </div>\n }\n @default {\n <div class=\"card-avatar\" [style.background-color]=\"vm.color\">\n {{ vm.initials }}\n </div>\n }\n }\n\n <div class=\"card-header-content\">\n <h3 class=\"card-title\" [innerHTML]=\"vm.highlightedTitle\"></h3>\n @if (effectiveTemplate?.subtitleField) {\n @if (subtitleIsPill) {\n <mj-pill [value]=\"vm.subtitleValue\"></mj-pill>\n } @else {\n <span class=\"card-subtitle\" [innerHTML]=\"vm.highlightedSubtitle\"></span>\n }\n }\n </div>\n\n <button class=\"card-open-btn\" (click)=\"onOpenClick($event, vm.record)\" title=\"Open Record\">\n <i class=\"fa-solid fa-external-link-alt\"></i>\n </button>\n </div>\n\n <!-- Card Body -->\n <div class=\"card-body\">\n @if (effectiveTemplate?.descriptionField) {\n <p class=\"card-description\" [innerHTML]=\"vm.highlightedDescription\"></p>\n }\n\n <!-- Display Fields -->\n @if (vm.displayFields.length > 0) {\n <div class=\"card-fields\">\n @for (df of vm.displayFields; track df.field.name) {\n <div class=\"field-item\" [class.field-boolean]=\"df.field.type === 'boolean'\" [class.field-text]=\"df.field.type === 'text'\">\n @switch (df.field.type) {\n @case ('boolean') {\n <i class=\"field-icon\" [class.fa-solid]=\"true\"\n [class.fa-check]=\"df.booleanValue\"\n [class.fa-minus]=\"!df.booleanValue\"\n [class.bool-true]=\"df.booleanValue\"\n [class.bool-false]=\"!df.booleanValue\"></i>\n <span class=\"field-label\">{{ df.field.label }}</span>\n }\n @case ('number') {\n <span class=\"field-value\">{{ df.numericValue }}</span>\n <span class=\"field-label\">{{ df.field.label }}</span>\n }\n @case ('date') {\n <span class=\"field-value field-date\">{{ df.dateValue }}</span>\n <span class=\"field-label\">{{ df.field.label }}</span>\n }\n @default {\n <span class=\"field-label\">{{ df.field.label }}</span>\n <span class=\"field-text-value\" [innerHTML]=\"df.highlightedText\"></span>\n }\n }\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Card Footer with Badge -->\n @if (effectiveTemplate?.badgeField) {\n <div class=\"card-footer\">\n <mj-pill [value]=\"vm.badgeValue\"></mj-pill>\n </div>\n }\n\n <!-- Hidden field match indicator -->\n @if (vm.hasHiddenFieldMatch) {\n <div class=\"hidden-match-indicator\" [title]=\"'Matched in: ' + vm.hiddenMatchFieldName\">\n <i class=\"fa-solid fa-magnifying-glass\"></i>\n <span>{{ vm.hiddenMatchFieldName }}</span>\n </div>\n }\n </div>\n }\n\n @if (effectiveRecords.length === 0) {\n <div class=\"no-results\">\n <i class=\"fa-solid fa-inbox\"></i>\n <p>No records to display</p>\n </div>\n }\n </div>\n }\n</div>\n", styles: ["/* Scoped to mj-entity-cards to prevent style leakage with ViewEncapsulation.None */\nmj-entity-cards .cards-view-wrapper {\n height: 100%;\n overflow-y: auto;\n overflow-x: hidden;\n}\n\nmj-entity-cards .cards-container {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));\n gap: 20px;\n padding: 4px;\n}\n\nmj-entity-cards .data-card {\n background: var(--mj-bg-surface);\n border-radius: 12px;\n border: 1px solid var(--mj-border-default);\n overflow: hidden;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n/* Hover state for unselected cards */\nmj-entity-cards .data-card:hover:not(.selected) {\n border-color: var(--mj-border-strong);\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);\n transform: translateY(-2px);\n}\nmj-entity-cards .data-card:hover .card-open-btn {\n opacity: 1;\n}\n\n/* Selected state - subtle but clear */\nmj-entity-cards .data-card.selected {\n border-color: var(--mj-brand-primary);\n}\n\nmj-entity-cards .data-card.selected .card-title {\n color: var(--mj-brand-primary-hover);\n}\n\n/* Selected + hover state - same as regular hover */\nmj-entity-cards .data-card.selected:hover {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);\n transform: translateY(-2px);\n}\n\nmj-entity-cards .card-header {\n display: flex;\n align-items: flex-start;\n padding: 16px;\n gap: 12px;\n}\n\nmj-entity-cards .card-thumbnail {\n width: 48px;\n height: 48px;\n border-radius: 8px;\n overflow: hidden;\n flex-shrink: 0;\n}\nmj-entity-cards .card-thumbnail img {\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n\nmj-entity-cards .card-avatar {\n width: 48px;\n height: 48px;\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 16px;\n font-weight: 600;\n color: var(--mj-text-inverse);\n flex-shrink: 0;\n}\n\nmj-entity-cards .card-header-content {\n flex: 1;\n min-width: 0;\n}\n\nmj-entity-cards .card-title {\n margin: 0;\n font-size: 15px;\n font-weight: 600;\n color: var(--mj-text-primary);\n line-height: 1.3;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\nmj-entity-cards .card-subtitle {\n display: block;\n margin-top: 2px;\n font-size: 12px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\nmj-entity-cards .card-open-btn {\n width: 32px;\n height: 32px;\n border: none;\n background: transparent;\n border-radius: 6px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-muted);\n opacity: 0;\n transition: all 0.15s ease;\n flex-shrink: 0;\n}\nmj-entity-cards .card-open-btn:hover {\n background: var(--mj-bg-surface-card);\n color: var(--mj-brand-primary);\n}\n\nmj-entity-cards .card-body {\n padding: 0 16px 16px 16px;\n}\n\nmj-entity-cards .card-description {\n margin: 0 0 12px 0;\n font-size: 13px;\n color: var(--mj-text-secondary);\n line-height: 1.5;\n}\n\n/* Card Display Fields */\nmj-entity-cards .card-fields {\n display: flex;\n flex-wrap: wrap;\n gap: 12px;\n padding-top: 12px;\n border-top: 1px solid var(--mj-border-subtle);\n}\n\nmj-entity-cards .field-item {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 60px;\n}\n\nmj-entity-cards .field-item .field-value {\n font-size: 15px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\nmj-entity-cards .field-item .field-label {\n font-size: 10px;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.3px;\n}\n\n/* Boolean fields */\nmj-entity-cards .field-item.field-boolean {\n flex-direction: row;\n align-items: center;\n gap: 6px;\n min-width: auto;\n}\n\nmj-entity-cards .field-item.field-boolean .field-icon {\n font-size: 14px;\n}\n\nmj-entity-cards .field-item.field-boolean .field-icon.bool-true {\n color: var(--mj-status-success);\n}\n\nmj-entity-cards .field-item.field-boolean .field-icon.bool-false {\n color: var(--mj-text-muted);\n}\n\nmj-entity-cards .field-item.field-boolean .field-label {\n font-size: 12px;\n text-transform: none;\n color: var(--mj-text-secondary);\n}\n\n/* Text fields */\nmj-entity-cards .field-item.field-text {\n flex: 1 1 100%;\n max-width: 100%;\n}\n\nmj-entity-cards .field-item .field-text-value {\n font-size: 13px;\n color: var(--mj-text-secondary);\n line-height: 1.4;\n word-break: break-word;\n}\n\n/* Date fields */\nmj-entity-cards .field-item .field-date {\n font-size: 13px;\n font-weight: 500;\n}\n\nmj-entity-cards .card-footer {\n padding: 12px 16px;\n background: var(--mj-bg-surface-card);\n border-top: 1px solid var(--mj-border-subtle);\n}\n\n/* Highlight matches - scoped to work with innerHTML */\nmj-entity-cards .highlight-match {\n background-color: color-mix(in srgb, var(--mj-status-warning) 40%, var(--mj-bg-surface));\n border-radius: 2px;\n}\n\n/* Pill spacing when used as subtitle */\nmj-entity-cards .card-header-content mj-pill {\n display: block;\n margin-top: 4px;\n}\n\n/* Hidden field match indicator */\nmj-entity-cards .hidden-match-indicator {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 8px 16px;\n background: var(--mj-status-warning-bg);\n border-top: 1px solid var(--mj-status-warning-border);\n font-size: 11px;\n color: var(--mj-status-warning);\n}\n\nmj-entity-cards .hidden-match-indicator i {\n font-size: 10px;\n}\n\nmj-entity-cards .hidden-match-indicator span {\n font-weight: 500;\n}\n\n/* Loading state */\nmj-entity-cards .loading-container {\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 200px;\n padding: 40px;\n}\n\n/* No results state */\nmj-entity-cards .no-results {\n grid-column: 1 / -1;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 60px 20px;\n color: var(--mj-text-muted);\n text-align: center;\n}\nmj-entity-cards .no-results i {\n font-size: 48px;\n margin-bottom: 16px;\n opacity: 0.5;\n}\nmj-entity-cards .no-results p {\n margin: 0;\n font-size: 14px;\n}\n"] }]
928
+ args: [{ standalone: false, selector: 'mj-entity-cards', encapsulation: ViewEncapsulation.None, template: "<div class=\"cards-view-wrapper\">\n @if (isLoading && effectiveRecords.length === 0) {\n <div class=\"loading-container\">\n <mj-loading text=\"Loading records...\"></mj-loading>\n </div>\n } @else {\n <div class=\"cards-container\">\n @for (vm of cardViewModels; track vm.trackId) {\n <div\n class=\"data-card\"\n [class.selected]=\"vm.isSelected\"\n (click)=\"onCardClick(vm.record)\">\n\n <!-- Card Header with Avatar/Icon -->\n <div class=\"card-header\">\n @switch (vm.thumbnailType) {\n @case ('image') {\n <div class=\"card-thumbnail\">\n <img [src]=\"vm.thumbnailUrl\" alt=\"\" />\n </div>\n }\n @case ('icon') {\n <div class=\"card-avatar\" [style.background-color]=\"vm.color\">\n <i [class]=\"vm.thumbnailUrl\"></i>\n </div>\n }\n @default {\n <div class=\"card-avatar\" [style.background-color]=\"vm.color\">\n {{ vm.initials }}\n </div>\n }\n }\n\n <div class=\"card-header-content\">\n <h3 class=\"card-title\" [innerHTML]=\"vm.highlightedTitle\"></h3>\n @if (effectiveTemplate?.subtitleField) {\n @if (subtitleIsPill) {\n <mj-pill [value]=\"vm.subtitleValue\"></mj-pill>\n } @else {\n <span class=\"card-subtitle\" [innerHTML]=\"vm.highlightedSubtitle\"></span>\n }\n }\n </div>\n\n <button class=\"card-open-btn\" (click)=\"onOpenClick($event, vm.record)\" title=\"Open Record\">\n <i class=\"fa-solid fa-external-link-alt\"></i>\n </button>\n </div>\n\n <!-- Card Body -->\n <div class=\"card-body\">\n @if (effectiveTemplate?.descriptionField) {\n <p class=\"card-description\" [innerHTML]=\"vm.highlightedDescription\"></p>\n }\n\n <!-- Display Fields -->\n @if (vm.displayFields.length > 0) {\n <div class=\"card-fields\">\n @for (df of vm.displayFields; track df.field.name) {\n <div class=\"field-item\" [class.field-boolean]=\"df.field.type === 'boolean'\" [class.field-text]=\"df.field.type === 'text'\">\n @switch (df.field.type) {\n @case ('boolean') {\n <i class=\"field-icon\" [class.fa-solid]=\"true\"\n [class.fa-check]=\"df.booleanValue\"\n [class.fa-minus]=\"!df.booleanValue\"\n [class.bool-true]=\"df.booleanValue\"\n [class.bool-false]=\"!df.booleanValue\"></i>\n <span class=\"field-label\">{{ df.field.label }}</span>\n }\n @case ('number') {\n <span class=\"field-value\">{{ df.numericValue }}</span>\n <span class=\"field-label\">{{ df.field.label }}</span>\n }\n @case ('date') {\n <span class=\"field-value field-date\">{{ df.dateValue }}</span>\n <span class=\"field-label\">{{ df.field.label }}</span>\n }\n @default {\n <span class=\"field-label\">{{ df.field.label }}</span>\n <span class=\"field-text-value\" [innerHTML]=\"df.highlightedText\"></span>\n }\n }\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Card Footer with Badge -->\n @if (effectiveTemplate?.badgeField) {\n <div class=\"card-footer\">\n <mj-pill [value]=\"vm.badgeValue\"></mj-pill>\n </div>\n }\n\n <!-- Hidden field match indicator -->\n @if (vm.hasHiddenFieldMatch) {\n <div class=\"hidden-match-indicator\" [title]=\"'Matched in: ' + vm.hiddenMatchFieldName\">\n <i class=\"fa-solid fa-magnifying-glass\"></i>\n <span>{{ vm.hiddenMatchFieldName }}</span>\n </div>\n }\n </div>\n }\n\n @if (effectiveRecords.length === 0) {\n <mj-empty-state\n class=\"no-results\"\n Variant=\"no-results\"\n Title=\"No records to display\" />\n }\n </div>\n }\n</div>\n", styles: ["/* Scoped to mj-entity-cards to prevent style leakage with ViewEncapsulation.None */\nmj-entity-cards .cards-view-wrapper {\n height: 100%;\n overflow-y: auto;\n overflow-x: hidden;\n}\n\nmj-entity-cards .cards-container {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));\n gap: 20px;\n padding: 4px;\n}\n\nmj-entity-cards .data-card {\n background: var(--mj-bg-surface);\n border-radius: 12px;\n border: 1px solid var(--mj-border-default);\n overflow: hidden;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n/* Hover state for unselected cards */\nmj-entity-cards .data-card:hover:not(.selected) {\n border-color: var(--mj-border-strong);\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);\n transform: translateY(-2px);\n}\nmj-entity-cards .data-card:hover .card-open-btn {\n opacity: 1;\n}\n\n/* Selected state - subtle but clear */\nmj-entity-cards .data-card.selected {\n border-color: var(--mj-brand-primary);\n}\n\nmj-entity-cards .data-card.selected .card-title {\n color: var(--mj-brand-primary-hover);\n}\n\n/* Selected + hover state - same as regular hover */\nmj-entity-cards .data-card.selected:hover {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);\n transform: translateY(-2px);\n}\n\nmj-entity-cards .card-header {\n display: flex;\n align-items: flex-start;\n padding: 16px;\n gap: 12px;\n}\n\nmj-entity-cards .card-thumbnail {\n width: 48px;\n height: 48px;\n border-radius: 8px;\n overflow: hidden;\n flex-shrink: 0;\n}\nmj-entity-cards .card-thumbnail img {\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n\nmj-entity-cards .card-avatar {\n width: 48px;\n height: 48px;\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 16px;\n font-weight: 600;\n color: var(--mj-text-inverse);\n flex-shrink: 0;\n}\n\nmj-entity-cards .card-header-content {\n flex: 1;\n min-width: 0;\n}\n\nmj-entity-cards .card-title {\n margin: 0;\n font-size: 15px;\n font-weight: 600;\n color: var(--mj-text-primary);\n line-height: 1.3;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\nmj-entity-cards .card-subtitle {\n display: block;\n margin-top: 2px;\n font-size: 12px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\nmj-entity-cards .card-open-btn {\n width: 32px;\n height: 32px;\n border: none;\n background: transparent;\n border-radius: 6px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-muted);\n opacity: 0;\n transition: all 0.15s ease;\n flex-shrink: 0;\n}\nmj-entity-cards .card-open-btn:hover {\n background: var(--mj-bg-surface-card);\n color: var(--mj-brand-primary);\n}\n\nmj-entity-cards .card-body {\n padding: 0 16px 16px 16px;\n}\n\nmj-entity-cards .card-description {\n margin: 0 0 12px 0;\n font-size: 13px;\n color: var(--mj-text-secondary);\n line-height: 1.5;\n}\n\n/* Card Display Fields */\nmj-entity-cards .card-fields {\n display: flex;\n flex-wrap: wrap;\n gap: 12px;\n padding-top: 12px;\n border-top: 1px solid var(--mj-border-subtle);\n}\n\nmj-entity-cards .field-item {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 60px;\n}\n\nmj-entity-cards .field-item .field-value {\n font-size: 15px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\nmj-entity-cards .field-item .field-label {\n font-size: 10px;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.3px;\n}\n\n/* Boolean fields */\nmj-entity-cards .field-item.field-boolean {\n flex-direction: row;\n align-items: center;\n gap: 6px;\n min-width: auto;\n}\n\nmj-entity-cards .field-item.field-boolean .field-icon {\n font-size: 14px;\n}\n\nmj-entity-cards .field-item.field-boolean .field-icon.bool-true {\n color: var(--mj-status-success);\n}\n\nmj-entity-cards .field-item.field-boolean .field-icon.bool-false {\n color: var(--mj-text-muted);\n}\n\nmj-entity-cards .field-item.field-boolean .field-label {\n font-size: 12px;\n text-transform: none;\n color: var(--mj-text-secondary);\n}\n\n/* Text fields */\nmj-entity-cards .field-item.field-text {\n flex: 1 1 100%;\n max-width: 100%;\n}\n\nmj-entity-cards .field-item .field-text-value {\n font-size: 13px;\n color: var(--mj-text-secondary);\n line-height: 1.4;\n word-break: break-word;\n}\n\n/* Date fields */\nmj-entity-cards .field-item .field-date {\n font-size: 13px;\n font-weight: 500;\n}\n\nmj-entity-cards .card-footer {\n padding: 12px 16px;\n background: var(--mj-bg-surface-card);\n border-top: 1px solid var(--mj-border-subtle);\n}\n\n/* Highlight matches - scoped to work with innerHTML */\nmj-entity-cards .highlight-match {\n background-color: color-mix(in srgb, var(--mj-status-warning) 40%, var(--mj-bg-surface));\n border-radius: 2px;\n}\n\n/* Pill spacing when used as subtitle */\nmj-entity-cards .card-header-content mj-pill {\n display: block;\n margin-top: 4px;\n}\n\n/* Hidden field match indicator */\nmj-entity-cards .hidden-match-indicator {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 8px 16px;\n background: var(--mj-status-warning-bg);\n border-top: 1px solid var(--mj-status-warning-border);\n font-size: 11px;\n color: var(--mj-status-warning);\n}\n\nmj-entity-cards .hidden-match-indicator i {\n font-size: 10px;\n}\n\nmj-entity-cards .hidden-match-indicator span {\n font-weight: 500;\n}\n\n/* Loading state */\nmj-entity-cards .loading-container {\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 200px;\n padding: 40px;\n}\n\n/* No results state \u2014 span the full grid width */\nmj-entity-cards .no-results {\n grid-column: 1 / -1;\n}\n"] }]
932
929
  }], () => [{ type: i0.ElementRef }, { type: i0.ChangeDetectorRef }], { entity: [{
933
930
  type: Input
934
931
  }], records: [{