@memberjunction/ng-entity-viewer 6.1.4 → 6.2.0-edge.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/dist/lib/aggregate-panel/aggregate-panel.component.d.ts +18 -2
  2. package/dist/lib/aggregate-panel/aggregate-panel.component.d.ts.map +1 -1
  3. package/dist/lib/aggregate-panel/aggregate-panel.component.js +47 -18
  4. package/dist/lib/aggregate-panel/aggregate-panel.component.js.map +1 -1
  5. package/dist/lib/aggregate-setup-dialog/aggregate-setup-dialog.component.d.ts +22 -0
  6. package/dist/lib/aggregate-setup-dialog/aggregate-setup-dialog.component.d.ts.map +1 -1
  7. package/dist/lib/aggregate-setup-dialog/aggregate-setup-dialog.component.js +57 -13
  8. package/dist/lib/aggregate-setup-dialog/aggregate-setup-dialog.component.js.map +1 -1
  9. package/dist/lib/entity-cards/entity-cards.component.d.ts +68 -5
  10. package/dist/lib/entity-cards/entity-cards.component.d.ts.map +1 -1
  11. package/dist/lib/entity-cards/entity-cards.component.js +213 -73
  12. package/dist/lib/entity-cards/entity-cards.component.js.map +1 -1
  13. package/dist/lib/entity-data-grid/entity-data-grid.component.d.ts +156 -14
  14. package/dist/lib/entity-data-grid/entity-data-grid.component.d.ts.map +1 -1
  15. package/dist/lib/entity-data-grid/entity-data-grid.component.js +432 -138
  16. package/dist/lib/entity-data-grid/entity-data-grid.component.js.map +1 -1
  17. package/dist/lib/entity-data-grid/events/grid-events.js +67 -67
  18. package/dist/lib/entity-data-grid/events/grid-events.js.map +1 -1
  19. package/dist/lib/entity-record-detail-panel/entity-record-detail-panel.component.d.ts +112 -8
  20. package/dist/lib/entity-record-detail-panel/entity-record-detail-panel.component.d.ts.map +1 -1
  21. package/dist/lib/entity-record-detail-panel/entity-record-detail-panel.component.js +255 -69
  22. package/dist/lib/entity-record-detail-panel/entity-record-detail-panel.component.js.map +1 -1
  23. package/dist/lib/entity-viewer/entity-viewer.component.d.ts +11 -0
  24. package/dist/lib/entity-viewer/entity-viewer.component.d.ts.map +1 -1
  25. package/dist/lib/entity-viewer/entity-viewer.component.js +45 -8
  26. package/dist/lib/entity-viewer/entity-viewer.component.js.map +1 -1
  27. package/dist/lib/pill/pill.component.d.ts +13 -3
  28. package/dist/lib/pill/pill.component.d.ts.map +1 -1
  29. package/dist/lib/pill/pill.component.js +34 -10
  30. package/dist/lib/pill/pill.component.js.map +1 -1
  31. package/dist/lib/quick-save-dialog/quick-save-dialog.component.d.ts +29 -3
  32. package/dist/lib/quick-save-dialog/quick-save-dialog.component.d.ts.map +1 -1
  33. package/dist/lib/quick-save-dialog/quick-save-dialog.component.js +173 -114
  34. package/dist/lib/quick-save-dialog/quick-save-dialog.component.js.map +1 -1
  35. package/dist/lib/recycle-bin/recycle-bin.component.d.ts +4 -0
  36. package/dist/lib/recycle-bin/recycle-bin.component.d.ts.map +1 -1
  37. package/dist/lib/recycle-bin/recycle-bin.component.js +10 -2
  38. package/dist/lib/recycle-bin/recycle-bin.component.js.map +1 -1
  39. package/dist/lib/utils/aggregate-field.util.d.ts +21 -0
  40. package/dist/lib/utils/aggregate-field.util.d.ts.map +1 -0
  41. package/dist/lib/utils/aggregate-field.util.js +40 -0
  42. package/dist/lib/utils/aggregate-field.util.js.map +1 -0
  43. package/dist/lib/utils/highlight.util.d.ts +6 -0
  44. package/dist/lib/utils/highlight.util.d.ts.map +1 -1
  45. package/dist/lib/utils/highlight.util.js +23 -11
  46. package/dist/lib/utils/highlight.util.js.map +1 -1
  47. package/dist/lib/utils/record.util.d.ts +10 -0
  48. package/dist/lib/utils/record.util.d.ts.map +1 -1
  49. package/dist/lib/utils/record.util.js +20 -4
  50. package/dist/lib/utils/record.util.js.map +1 -1
  51. package/dist/lib/view-config-panel/view-config-panel.component.d.ts +22 -2
  52. package/dist/lib/view-config-panel/view-config-panel.component.d.ts.map +1 -1
  53. package/dist/lib/view-config-panel/view-config-panel.component.js +54 -14
  54. package/dist/lib/view-config-panel/view-config-panel.component.js.map +1 -1
  55. package/dist/lib/view-selector/view-selector.component.js +2 -2
  56. package/dist/lib/view-types/renderers/cards-view-renderer.component.d.ts +15 -3
  57. package/dist/lib/view-types/renderers/cards-view-renderer.component.d.ts.map +1 -1
  58. package/dist/lib/view-types/renderers/cards-view-renderer.component.js +33 -5
  59. package/dist/lib/view-types/renderers/cards-view-renderer.component.js.map +1 -1
  60. package/dist/lib/view-types/renderers/grid-view-renderer.component.d.ts +160 -5
  61. package/dist/lib/view-types/renderers/grid-view-renderer.component.d.ts.map +1 -1
  62. package/dist/lib/view-types/renderers/grid-view-renderer.component.js +576 -36
  63. package/dist/lib/view-types/renderers/grid-view-renderer.component.js.map +1 -1
  64. package/dist/lib/view-types/renderers/map-view-renderer.component.d.ts +16 -2
  65. package/dist/lib/view-types/renderers/map-view-renderer.component.d.ts.map +1 -1
  66. package/dist/lib/view-types/renderers/map-view-renderer.component.js +37 -9
  67. package/dist/lib/view-types/renderers/map-view-renderer.component.js.map +1 -1
  68. package/dist/lib/view-types/view-type.contracts.js.map +1 -1
  69. package/dist/lib/view-workspace/view-workspace.component.d.ts +235 -24
  70. package/dist/lib/view-workspace/view-workspace.component.d.ts.map +1 -1
  71. package/dist/lib/view-workspace/view-workspace.component.js +600 -174
  72. package/dist/lib/view-workspace/view-workspace.component.js.map +1 -1
  73. package/dist/module.d.ts +5 -4
  74. package/dist/module.d.ts.map +1 -1
  75. package/dist/module.js +8 -1
  76. package/dist/module.js.map +1 -1
  77. package/dist/public-api.d.ts +1 -0
  78. package/dist/public-api.d.ts.map +1 -1
  79. package/dist/public-api.js +1 -0
  80. package/dist/public-api.js.map +1 -1
  81. package/package.json +21 -20
@@ -1,6 +1,6 @@
1
1
  import { EventEmitter, OnInit } from '@angular/core';
2
2
  import { MJUserViewEntity_IGridAggregate as ViewGridAggregate } from '@memberjunction/core-entities';
3
- import { AggregateValue } from '@memberjunction/core';
3
+ import { AggregateValue, EntityInfo } from '@memberjunction/core';
4
4
  import * as i0 from "@angular/core";
5
5
  /**
6
6
  * AggregatePanelComponent displays aggregate values in a card-based panel.
@@ -18,6 +18,13 @@ export declare class AggregatePanelComponent implements OnInit {
18
18
  * Array of aggregate configurations to display
19
19
  */
20
20
  Aggregates: ViewGridAggregate[];
21
+ /**
22
+ * The entity the aggregates are computed over. Optional: with it, the panel can read the SQL
23
+ * type of the column an aggregate summarises (`MIN(IntakeDate)`), so a `date` column renders as
24
+ * its stored calendar day and a timestamp in the reader's local time (MJ#4210). Without it, a
25
+ * date aggregate prints exactly as it arrives, which over GraphQL is an ISO string.
26
+ */
27
+ Entity: EntityInfo | null;
21
28
  /**
22
29
  * Map of aggregate values, keyed by expression or id
23
30
  */
@@ -81,6 +88,13 @@ export declare class AggregatePanelComponent implements OnInit {
81
88
  * Get the formatted value for an aggregate
82
89
  */
83
90
  FormatValue(agg: ViewGridAggregate): string;
91
+ /**
92
+ * A date-family aggregate whose column type is known. The value may be a Date or, over
93
+ * GraphQL, the ISO string the server serialised it to. A `date` column is a calendar day at UTC
94
+ * midnight and is rendered in UTC so the day does not shift west of Greenwich; a timestamp is an
95
+ * instant and is rendered in local time.
96
+ */
97
+ private formatDateField;
84
98
  /**
85
99
  * Get the CSS class for conditional styling
86
100
  */
@@ -113,11 +127,13 @@ export declare class AggregatePanelComponent implements OnInit {
113
127
  * Format a date value
114
128
  */
115
129
  private formatDate;
130
+ /** The Intl options for a simple date format preset. */
131
+ private dateOptions;
116
132
  /**
117
133
  * Evaluate a conditional styling rule
118
134
  */
119
135
  private evaluateCondition;
120
136
  static ɵfac: i0.ɵɵFactoryDeclaration<AggregatePanelComponent, never>;
121
- static ɵcmp: i0.ɵɵComponentDeclaration<AggregatePanelComponent, "mj-aggregate-panel", never, { "Aggregates": { "alias": "Aggregates"; "required": false; }; "Values": { "alias": "Values"; "required": false; }; "Position": { "alias": "Position"; "required": false; }; "Width": { "alias": "Width"; "required": false; }; "Layout": { "alias": "Layout"; "required": false; }; "GridColumns": { "alias": "GridColumns"; "required": false; }; "Title": { "alias": "Title"; "required": false; }; "Collapsible": { "alias": "Collapsible"; "required": false; }; "StartCollapsed": { "alias": "StartCollapsed"; "required": false; }; "Loading": { "alias": "Loading"; "required": false; }; }, { "CollapsedChange": "CollapsedChange"; "AggregateClick": "AggregateClick"; }, never, never, false, never>;
137
+ static ɵcmp: i0.ɵɵComponentDeclaration<AggregatePanelComponent, "mj-aggregate-panel", never, { "Aggregates": { "alias": "Aggregates"; "required": false; }; "Entity": { "alias": "Entity"; "required": false; }; "Values": { "alias": "Values"; "required": false; }; "Position": { "alias": "Position"; "required": false; }; "Width": { "alias": "Width"; "required": false; }; "Layout": { "alias": "Layout"; "required": false; }; "GridColumns": { "alias": "GridColumns"; "required": false; }; "Title": { "alias": "Title"; "required": false; }; "Collapsible": { "alias": "Collapsible"; "required": false; }; "StartCollapsed": { "alias": "StartCollapsed"; "required": false; }; "Loading": { "alias": "Loading"; "required": false; }; }, { "CollapsedChange": "CollapsedChange"; "AggregateClick": "AggregateClick"; }, never, never, false, never>;
122
138
  }
123
139
  //# sourceMappingURL=aggregate-panel.component.d.ts.map
@@ -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;;;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
+ {"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,EAAqB,UAAU,EAAqC,MAAM,sBAAsB,CAAC;;AAGxH;;;;;;;;;;GAUG;AACH,qBAMa,uBAAwB,YAAW,MAAM;IACpD;;OAEG;IACM,UAAU,EAAE,iBAAiB,EAAE,CAAM;IAE9C;;;;;OAKG;IACM,MAAM,EAAE,UAAU,GAAG,IAAI,CAAQ;IAE1C;;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;IAgB3C;;;;;OAKG;IACH,OAAO,CAAC,eAAe;IASvB;;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;IAQlB,wDAAwD;IACxD,OAAO,CAAC,WAAW;IAYnB;;OAEG;IACH,OAAO,CAAC,iBAAiB;yCA7Qd,uBAAuB;2CAAvB,uBAAuB;CAmSnC"}
@@ -1,4 +1,6 @@
1
1
  import { Component, Input, Output, EventEmitter } from '@angular/core';
2
+ import { EntityFieldTSType, FormatDateOnly, IsDateOnlySQLType } from '@memberjunction/core';
3
+ import { AggregateField } from '../utils/aggregate-field.util';
2
4
  import * as i0 from "@angular/core";
3
5
  import * as i1 from "@angular/common";
4
6
  import * as i2 from "@memberjunction/ng-ui-components";
@@ -93,6 +95,13 @@ export class AggregatePanelComponent {
93
95
  * Array of aggregate configurations to display
94
96
  */
95
97
  Aggregates = [];
98
+ /**
99
+ * The entity the aggregates are computed over. Optional: with it, the panel can read the SQL
100
+ * type of the column an aggregate summarises (`MIN(IntakeDate)`), so a `date` column renders as
101
+ * its stored calendar day and a timestamp in the reader's local time (MJ#4210). Without it, a
102
+ * date aggregate prints exactly as it arrives, which over GraphQL is an ISO string.
103
+ */
104
+ Entity = null;
96
105
  /**
97
106
  * Map of aggregate values, keyed by expression or id
98
107
  */
@@ -173,8 +182,29 @@ export class AggregatePanelComponent {
173
182
  if (value == null)
174
183
  return '—';
175
184
  const format = agg.format || {};
185
+ // Only a value that is itself a date takes the date path. `COUNT(IntakeDate)` also resolves
186
+ // to the date column, but its value is the count — a number — and must format as one.
187
+ const field = AggregateField(agg, this.Entity);
188
+ if (field?.TSType === EntityFieldTSType.Date && (value instanceof Date || typeof value === 'string')) {
189
+ return this.formatDateField(value, field.Type, format);
190
+ }
176
191
  return this.formatByType(value, format);
177
192
  }
193
+ /**
194
+ * A date-family aggregate whose column type is known. The value may be a Date or, over
195
+ * GraphQL, the ISO string the server serialised it to. A `date` column is a calendar day at UTC
196
+ * midnight and is rendered in UTC so the day does not shift west of Greenwich; a timestamp is an
197
+ * instant and is rendered in local time.
198
+ */
199
+ formatDateField(value, sqlType, format) {
200
+ const date = value instanceof Date ? value : new Date(value);
201
+ if (isNaN(date.getTime()))
202
+ return String(value);
203
+ if (IsDateOnlySQLType(sqlType)) {
204
+ return FormatDateOnly(date, this.dateOptions(format.dateFormat), 'en-US');
205
+ }
206
+ return this.formatDate(date, format.dateFormat);
207
+ }
178
208
  /**
179
209
  * Get the CSS class for conditional styling
180
210
  */
@@ -274,27 +304,24 @@ export class AggregatePanelComponent {
274
304
  */
275
305
  formatDate(value, dateFormat) {
276
306
  try {
277
- // Simple format presets
278
- const options = {};
279
- switch (dateFormat) {
280
- case 'short':
281
- options.dateStyle = 'short';
282
- break;
283
- case 'medium':
284
- options.dateStyle = 'medium';
285
- break;
286
- case 'long':
287
- options.dateStyle = 'long';
288
- break;
289
- default:
290
- options.dateStyle = 'medium';
291
- }
292
- return new Intl.DateTimeFormat('en-US', options).format(value);
307
+ return new Intl.DateTimeFormat('en-US', this.dateOptions(dateFormat)).format(value);
293
308
  }
294
309
  catch {
295
310
  return String(value);
296
311
  }
297
312
  }
313
+ /** The Intl options for a simple date format preset. */
314
+ dateOptions(dateFormat) {
315
+ switch (dateFormat) {
316
+ case 'short':
317
+ return { dateStyle: 'short' };
318
+ case 'long':
319
+ return { dateStyle: 'long' };
320
+ case 'medium':
321
+ default:
322
+ return { dateStyle: 'medium' };
323
+ }
324
+ }
298
325
  /**
299
326
  * Evaluate a conditional styling rule
300
327
  */
@@ -321,7 +348,7 @@ export class AggregatePanelComponent {
321
348
  }
322
349
  }
323
350
  static ɵfac = function AggregatePanelComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || AggregatePanelComponent)(); };
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) {
351
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: AggregatePanelComponent, selectors: [["mj-aggregate-panel"]], inputs: { Aggregates: "Aggregates", Entity: "Entity", 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
352
  i0.ɵɵelementStart(0, "div", 0)(1, "mj-accordion-panel", 1);
326
353
  i0.ɵɵlistener("ExpandedChange", function AggregatePanelComponent_Template_mj_accordion_panel_ExpandedChange_1_listener($event) { return ctx.OnPanelExpandedChange($event); });
327
354
  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);
@@ -338,6 +365,8 @@ export class AggregatePanelComponent {
338
365
  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"] }]
339
366
  }], null, { Aggregates: [{
340
367
  type: Input
368
+ }], Entity: [{
369
+ type: Input
341
370
  }], Values: [{
342
371
  type: Input
343
372
  }], Position: [{
@@ -361,5 +390,5 @@ export class AggregatePanelComponent {
361
390
  }], AggregateClick: [{
362
391
  type: Output
363
392
  }] }); })();
364
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(AggregatePanelComponent, { className: "AggregatePanelComponent", filePath: "src/lib/aggregate-panel/aggregate-panel.component.ts", lineNumber: 32 }); })();
393
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(AggregatePanelComponent, { className: "AggregatePanelComponent", filePath: "src/lib/aggregate-panel/aggregate-panel.component.ts", lineNumber: 33 }); })();
365
394
  //# sourceMappingURL=aggregate-panel.component.js.map
@@ -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 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"]}
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, EntityFieldTSType, EntityInfo, FormatDateOnly, IsDateOnlySQLType } from '@memberjunction/core';\nimport { AggregateField } from '../utils/aggregate-field.util';\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 * The entity the aggregates are computed over. Optional: with it, the panel can read the SQL\n * type of the column an aggregate summarises (`MIN(IntakeDate)`), so a `date` column renders as\n * its stored calendar day and a timestamp in the reader's local time (MJ#4210). Without it, a\n * date aggregate prints exactly as it arrives, which over GraphQL is an ISO string.\n */\n @Input() Entity: EntityInfo | null = null;\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 // Only a value that is itself a date takes the date path. `COUNT(IntakeDate)` also resolves\n // to the date column, but its value is the count — a number — and must format as one.\n const field = AggregateField(agg, this.Entity);\n if (field?.TSType === EntityFieldTSType.Date && (value instanceof Date || typeof value === 'string')) {\n return this.formatDateField(value, field.Type, format);\n }\n return this.formatByType(value, format);\n }\n\n /**\n * A date-family aggregate whose column type is known. The value may be a Date or, over\n * GraphQL, the ISO string the server serialised it to. A `date` column is a calendar day at UTC\n * midnight and is rendered in UTC so the day does not shift west of Greenwich; a timestamp is an\n * instant and is rendered in local time.\n */\n private formatDateField(value: string | Date, sqlType: string, format: AggregateValueFormat): string {\n const date = value instanceof Date ? value : new Date(value);\n if (isNaN(date.getTime())) return String(value);\n if (IsDateOnlySQLType(sqlType)) {\n return FormatDateOnly(date, this.dateOptions(format.dateFormat), 'en-US');\n }\n return this.formatDate(date, format.dateFormat);\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 return new Intl.DateTimeFormat('en-US', this.dateOptions(dateFormat)).format(value);\n } catch {\n return String(value);\n }\n }\n\n /** The Intl options for a simple date format preset. */\n private dateOptions(dateFormat?: string): Intl.DateTimeFormatOptions {\n switch (dateFormat) {\n case 'short':\n return { dateStyle: 'short' };\n case 'long':\n return { dateStyle: 'long' };\n case 'medium':\n default:\n return { dateStyle: 'medium' };\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"]}
@@ -105,11 +105,15 @@ export declare class AggregateSetupDialogComponent implements OnInit, OnChanges
105
105
  /**
106
106
  * Set the setup mode
107
107
  */
108
+ SetMode(mode: AggregateSetupMode): void;
109
+ /** @deprecated Use {@link SetMode}. */
108
110
  setMode(mode: AggregateSetupMode): void;
109
111
  /**
110
112
  * Handle function button click - captures old value before changing
111
113
  * Called from template when user clicks a function button
112
114
  */
115
+ SelectFunction(newFunction: AggregateFunctionType): void;
116
+ /** @deprecated Use {@link SelectFunction}. */
113
117
  selectFunction(newFunction: AggregateFunctionType): void;
114
118
  /**
115
119
  * Handle column selection from dropdown
@@ -117,6 +121,8 @@ export declare class AggregateSetupDialogComponent implements OnInit, OnChanges
117
121
  * We track the previous value internally
118
122
  */
119
123
  private _previousColumn;
124
+ OnColumnSelected(newColumn: string): void;
125
+ /** @deprecated Use {@link OnColumnSelected}. */
120
126
  onColumnSelected(newColumn: string): void;
121
127
  /**
122
128
  * Handle function selection change (internal)
@@ -125,6 +131,8 @@ export declare class AggregateSetupDialogComponent implements OnInit, OnChanges
125
131
  /**
126
132
  * Handle column selection change
127
133
  */
134
+ OnColumnChange(previousColumn: string): void;
135
+ /** @deprecated Use {@link OnColumnChange}. */
128
136
  onColumnChange(previousColumn: string): void;
129
137
  /**
130
138
  * Check if the current label matches what we would have auto-generated
@@ -145,10 +153,14 @@ export declare class AggregateSetupDialogComponent implements OnInit, OnChanges
145
153
  /**
146
154
  * Select an icon
147
155
  */
156
+ SelectIcon(icon: string): void;
157
+ /** @deprecated Use {@link SelectIcon}. */
148
158
  selectIcon(icon: string): void;
149
159
  /**
150
160
  * Clear the icon
151
161
  */
162
+ ClearIcon(): void;
163
+ /** @deprecated Use {@link ClearIcon}. */
152
164
  clearIcon(): void;
153
165
  /**
154
166
  * Build the expression based on current mode
@@ -165,6 +177,8 @@ export declare class AggregateSetupDialogComponent implements OnInit, OnChanges
165
177
  /**
166
178
  * Save the aggregate
167
179
  */
180
+ OnSave(): void;
181
+ /** @deprecated Use {@link OnSave}. */
168
182
  onSave(): void;
169
183
  /**
170
184
  * Get default icon based on function
@@ -177,19 +191,27 @@ export declare class AggregateSetupDialogComponent implements OnInit, OnChanges
177
191
  /**
178
192
  * Close the dialog
179
193
  */
194
+ OnClose(): void;
195
+ /** @deprecated Use {@link OnClose}. */
180
196
  onClose(): void;
181
197
  /**
182
198
  * Handle smart prompt generation (placeholder - actual AI call would be made by parent)
183
199
  */
200
+ OnGenerateFromPrompt(): void;
201
+ /** @deprecated Use {@link OnGenerateFromPrompt}. */
184
202
  onGenerateFromPrompt(): void;
185
203
  /**
186
204
  * Clear the generated expression and allow editing prompt
187
205
  */
206
+ ClearGeneratedExpression(): void;
207
+ /** @deprecated Use {@link ClearGeneratedExpression}. */
188
208
  clearGeneratedExpression(): void;
189
209
  /**
190
210
  * Get display label for field dropdown showing "Name (DisplayName)" format
191
211
  * If DisplayName equals Name or is not set, just show Name
192
212
  */
213
+ GetFieldDisplayLabel(field: EntityFieldInfo): string;
214
+ /** @deprecated Use {@link GetFieldDisplayLabel}. */
193
215
  getFieldDisplayLabel(field: EntityFieldInfo): string;
194
216
  static ɵfac: i0.ɵɵFactoryDeclaration<AggregateSetupDialogComponent, never>;
195
217
  static ɵcmp: i0.ɵɵComponentDeclaration<AggregateSetupDialogComponent, "mj-aggregate-setup-dialog", never, { "Entity": { "alias": "Entity"; "required": false; }; "Aggregate": { "alias": "Aggregate"; "required": false; }; "IsOpen": { "alias": "IsOpen"; "required": false; }; }, { "Close": "Close"; "Save": "Save"; }, never, never, false, never>;
@@ -1 +1 @@
1
- {"version":3,"file":"aggregate-setup-dialog.component.d.ts","sourceRoot":"","sources":["../../../src/lib/aggregate-setup-dialog/aggregate-setup-dialog.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAC5H,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACnE,OAAO,EAAE,+BAA+B,IAAI,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;;AAErG,KAAK,oBAAoB,GAAG,QAAQ,GAAG,MAAM,CAAC;AAE9C;;GAEG;AACH,MAAM,MAAM,qBAAqB,GAAG,KAAK,GAAG,KAAK,GAAG,OAAO,GAAG,KAAK,GAAG,KAAK,GAAG,gBAAgB,CAAC;AAE/F;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG,QAAQ,GAAG,UAAU,GAAG,OAAO,CAAC;AA0BjE;;;;;;;;;;GAUG;AACH,qBAMa,6BAA8B,YAAW,MAAM,EAAE,SAAS;IAyEzD,OAAO,CAAC,GAAG;IAxEvB;;OAEG;IACM,MAAM,EAAE,UAAU,GAAG,IAAI,CAAQ;IAE1C;;OAEG;IACM,SAAS,EAAE,iBAAiB,GAAG,IAAI,CAAQ;IAEpD;;OAEG;IACM,MAAM,EAAE,OAAO,CAAS;IAEjC;;OAEG;IACO,KAAK,qBAA4B;IAE3C;;OAEG;IACO,IAAI,kCAAyC;IAGvD,IAAI,EAAE,kBAAkB,CAAY;IAGpC,cAAc,EAAE,MAAM,CAAM;IAC5B,gBAAgB,EAAE,qBAAqB,CAAS;IAGhD,UAAU,EAAE,MAAM,CAAM;IAGxB,WAAW,EAAE,MAAM,CAAM;IACzB,mBAAmB,EAAE,MAAM,CAAM;IACjC,YAAY,EAAE,OAAO,CAAS;IAG9B,KAAK,EAAE,MAAM,CAAM;IACnB,WAAW,EAAE,oBAAoB,CAAU;IAC3C,IAAI,EAAE,MAAM,CAAM;IAClB,WAAW,EAAE,MAAM,CAAM;IAGzB,kBAAkB,EAAE;QAAE,KAAK,EAAE,qBAAqB,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAOjF;IAGF,WAAW,EAAE,MAAM,EAAE,CAanB;gBAEkB,GAAG,EAAE,iBAAiB;IAE1C,QAAQ,IAAI,IAAI;IAIhB,WAAW,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI;IAUzC;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAuC/B;;OAEG;IACH,OAAO,CAAC,SAAS;IAcjB;;;OAGG;IACH,OAAO,CAAC,kBAAkB;IAK1B;;;OAGG;IACH,OAAO,CAAC,qBAAqB;IAW7B;;OAEG;IACH,IAAI,aAAa,IAAI,eAAe,EAAE,CAWrC;IAED;;OAEG;IACH,IAAI,UAAU,IAAI,eAAe,EAAE,CAMlC;IAED;;OAEG;IACH,IAAI,YAAY,IAAI,eAAe,EAAE,CAMpC;IAED;;OAEG;IACH,IAAI,SAAS,IAAI,eAAe,EAAE,CAGjC;IAED;;OAEG;IACH,IAAI,eAAe,IAAI,eAAe,EAAE,CAuBvC;IAED;;OAEG;IACH,OAAO,CAAC,IAAI,EAAE,kBAAkB,GAAG,IAAI;IAWvC;;;OAGG;IACH,cAAc,CAAC,WAAW,EAAE,qBAAqB,GAAG,IAAI;IAQxD;;;;OAIG;IACH,OAAO,CAAC,eAAe,CAAc;IAErC,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAMzC;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAmBxB;;OAEG;IACH,cAAc,CAAC,cAAc,EAAE,MAAM,GAAG,IAAI;IAY5C;;;;OAIG;IACH,OAAO,CAAC,qBAAqB;IAS7B;;;;OAIG;IACH,OAAO,CAAC,iBAAiB;IAkBzB;;OAEG;IACH,OAAO,CAAC,YAAY;IAOpB;;OAEG;IACH,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAK9B;;OAEG;IACH,SAAS,IAAI,IAAI;IAKjB;;OAEG;IACH,OAAO,CAAC,eAAe;IAgCvB;;OAEG;IACH,IAAI,OAAO,IAAI,OAAO,CAIrB;IAED;;OAEG;IACH,IAAI,iBAAiB,IAAI,MAAM,CAsB9B;IAED;;OAEG;IACH,MAAM,IAAI,IAAI;IAuBd;;OAEG;IACH,OAAO,CAAC,cAAc;IAOtB;;OAEG;IACH,OAAO,CAAC,UAAU;IAIlB;;OAEG;IACH,OAAO,IAAI,IAAI;IAIf;;OAEG;IACH,oBAAoB,IAAI,IAAI;IAiB5B;;OAEG;IACH,wBAAwB,IAAI,IAAI;IAKhC;;;OAGG;IACH,oBAAoB,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM;yCA1hBzC,6BAA6B;2CAA7B,6BAA6B;CAgiBzC"}
1
+ {"version":3,"file":"aggregate-setup-dialog.component.d.ts","sourceRoot":"","sources":["../../../src/lib/aggregate-setup-dialog/aggregate-setup-dialog.component.ts"],"names":[],"mappings":"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"}
@@ -539,7 +539,7 @@ export class AggregateSetupDialogComponent {
539
539
  /**
540
540
  * Set the setup mode
541
541
  */
542
- setMode(mode) {
542
+ SetMode(mode) {
543
543
  this.Mode = mode;
544
544
  // If switching from smart mode with generated expression, populate advanced mode
545
545
  if (mode === 'advanced' && this.GeneratedExpression) {
@@ -547,27 +547,39 @@ export class AggregateSetupDialogComponent {
547
547
  }
548
548
  this.cdr.detectChanges();
549
549
  }
550
+ /** @deprecated Use {@link SetMode}. */
551
+ setMode(mode) {
552
+ return this.SetMode(mode);
553
+ }
550
554
  /**
551
555
  * Handle function button click - captures old value before changing
552
556
  * Called from template when user clicks a function button
553
557
  */
554
- selectFunction(newFunction) {
558
+ SelectFunction(newFunction) {
555
559
  if (newFunction === this.SelectedFunction)
556
560
  return;
557
561
  const previousFunction = this.SelectedFunction;
558
562
  this.SelectedFunction = newFunction;
559
563
  this.onFunctionChange(previousFunction);
560
564
  }
565
+ /** @deprecated Use {@link SelectFunction}. */
566
+ selectFunction(newFunction) {
567
+ return this.SelectFunction(newFunction);
568
+ }
561
569
  /**
562
570
  * Handle column selection from dropdown
563
571
  * Called from template with the NEW value from ngModelChange
564
572
  * We track the previous value internally
565
573
  */
566
574
  _previousColumn = '';
567
- onColumnSelected(newColumn) {
575
+ OnColumnSelected(newColumn) {
568
576
  const previousColumn = this._previousColumn;
569
577
  this._previousColumn = newColumn;
570
- this.onColumnChange(previousColumn);
578
+ this.OnColumnChange(previousColumn);
579
+ }
580
+ /** @deprecated Use {@link OnColumnSelected}. */
581
+ onColumnSelected(newColumn) {
582
+ return this.OnColumnSelected(newColumn);
571
583
  }
572
584
  /**
573
585
  * Handle function selection change (internal)
@@ -590,7 +602,7 @@ export class AggregateSetupDialogComponent {
590
602
  /**
591
603
  * Handle column selection change
592
604
  */
593
- onColumnChange(previousColumn) {
605
+ OnColumnChange(previousColumn) {
594
606
  // Check if label matches what we would have auto-generated for the OLD column
595
607
  const shouldUpdateLabel = this.shouldAutoUpdateLabel(this.SelectedFunction, previousColumn);
596
608
  // Update label if it was auto-generated (matches old pattern) or is empty
@@ -599,6 +611,10 @@ export class AggregateSetupDialogComponent {
599
611
  }
600
612
  this.cdr.detectChanges();
601
613
  }
614
+ /** @deprecated Use {@link OnColumnChange}. */
615
+ onColumnChange(previousColumn) {
616
+ return this.OnColumnChange(previousColumn);
617
+ }
602
618
  /**
603
619
  * Check if the current label matches what we would have auto-generated
604
620
  * for the given function and column. If so, we should update the label
@@ -645,17 +661,25 @@ export class AggregateSetupDialogComponent {
645
661
  /**
646
662
  * Select an icon
647
663
  */
648
- selectIcon(icon) {
664
+ SelectIcon(icon) {
649
665
  this.Icon = icon;
650
666
  this.cdr.detectChanges();
651
667
  }
668
+ /** @deprecated Use {@link SelectIcon}. */
669
+ selectIcon(icon) {
670
+ return this.SelectIcon(icon);
671
+ }
652
672
  /**
653
673
  * Clear the icon
654
674
  */
655
- clearIcon() {
675
+ ClearIcon() {
656
676
  this.Icon = '';
657
677
  this.cdr.detectChanges();
658
678
  }
679
+ /** @deprecated Use {@link ClearIcon}. */
680
+ clearIcon() {
681
+ return this.ClearIcon();
682
+ }
659
683
  /**
660
684
  * Build the expression based on current mode
661
685
  */
@@ -725,7 +749,7 @@ export class AggregateSetupDialogComponent {
725
749
  /**
726
750
  * Save the aggregate
727
751
  */
728
- onSave() {
752
+ OnSave() {
729
753
  if (!this.IsValid)
730
754
  return;
731
755
  const aggregate = {
@@ -743,7 +767,11 @@ export class AggregateSetupDialogComponent {
743
767
  aggregate.smartPrompt = this.SmartPrompt;
744
768
  }
745
769
  this.Save.emit(aggregate);
746
- this.onClose();
770
+ this.OnClose();
771
+ }
772
+ /** @deprecated Use {@link OnSave}. */
773
+ onSave() {
774
+ return this.OnSave();
747
775
  }
748
776
  /**
749
777
  * Get default icon based on function
@@ -763,13 +791,17 @@ export class AggregateSetupDialogComponent {
763
791
  /**
764
792
  * Close the dialog
765
793
  */
766
- onClose() {
794
+ OnClose() {
767
795
  this.Close.emit();
768
796
  }
797
+ /** @deprecated Use {@link OnClose}. */
798
+ onClose() {
799
+ return this.OnClose();
800
+ }
769
801
  /**
770
802
  * Handle smart prompt generation (placeholder - actual AI call would be made by parent)
771
803
  */
772
- onGenerateFromPrompt() {
804
+ OnGenerateFromPrompt() {
773
805
  if (!this.SmartPrompt.trim())
774
806
  return;
775
807
  this.IsGenerating = true;
@@ -784,23 +816,35 @@ export class AggregateSetupDialogComponent {
784
816
  this.cdr.detectChanges();
785
817
  }, 500);
786
818
  }
819
+ /** @deprecated Use {@link OnGenerateFromPrompt}. */
820
+ onGenerateFromPrompt() {
821
+ return this.OnGenerateFromPrompt();
822
+ }
787
823
  /**
788
824
  * Clear the generated expression and allow editing prompt
789
825
  */
790
- clearGeneratedExpression() {
826
+ ClearGeneratedExpression() {
791
827
  this.GeneratedExpression = '';
792
828
  this.cdr.detectChanges();
793
829
  }
830
+ /** @deprecated Use {@link ClearGeneratedExpression}. */
831
+ clearGeneratedExpression() {
832
+ return this.ClearGeneratedExpression();
833
+ }
794
834
  /**
795
835
  * Get display label for field dropdown showing "Name (DisplayName)" format
796
836
  * If DisplayName equals Name or is not set, just show Name
797
837
  */
798
- getFieldDisplayLabel(field) {
838
+ GetFieldDisplayLabel(field) {
799
839
  if (field.DisplayName && field.DisplayName !== field.Name) {
800
840
  return `${field.Name} (${field.DisplayName})`;
801
841
  }
802
842
  return field.Name;
803
843
  }
844
+ /** @deprecated Use {@link GetFieldDisplayLabel}. */
845
+ getFieldDisplayLabel(field) {
846
+ return this.GetFieldDisplayLabel(field);
847
+ }
804
848
  static ɵfac = function AggregateSetupDialogComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || AggregateSetupDialogComponent)(i0.ɵɵdirectiveInject(i0.ChangeDetectorRef)); };
805
849
  static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: AggregateSetupDialogComponent, selectors: [["mj-aggregate-setup-dialog"]], inputs: { Entity: "Entity", Aggregate: "Aggregate", IsOpen: "IsOpen" }, outputs: { Close: "Close", Save: "Save" }, standalone: false, features: [i0.ɵɵNgOnChangesFeature], decls: 75, vars: 23, consts: [[1, "dialog-backdrop"], [1, "dialog-panel"], [1, "dialog-header"], [1, "header-title"], [1, "fa-solid", "fa-chart-simple"], ["title", "Close", "aria-label", "Close dialog", 1, "close-btn", 3, "click"], [1, "fa-solid", "fa-times"], [1, "mode-selector"], ["title", "Pick a column and function", 1, "mode-btn", 3, "click"], [1, "fa-solid", "fa-wand-sparkles"], ["title", "Write custom SQL expression", 1, "mode-btn", 3, "click"], [1, "fa-solid", "fa-code"], ["title", "Describe in natural language", 1, "mode-btn", 3, "click"], [1, "fa-solid", "fa-wand-magic-sparkles"], [1, "dialog-content"], [1, "mode-content", "simple-mode"], [1, "mode-content", "advanced-mode"], [1, "mode-content", "smart-mode"], [1, "config-section"], [1, "section-divider"], [1, "form-section"], [1, "form-label", "required"], ["type", "text", "placeholder", "e.g., Total Revenue, Average Order Value", 1, "form-input", 3, "ngModelChange", "ngModel"], [1, "form-label"], [1, "optional"], ["type", "text", "placeholder", "Brief explanation of what this shows", 1, "form-input", 3, "ngModelChange", "ngModel"], [1, "display-type-toggle"], [1, "display-type-btn", 3, "click"], [1, "fa-solid", "fa-id-card"], [1, "fa-solid", "fa-table-columns"], [1, "icon-selector"], [1, "selected-icon"], [1, "icon-grid"], [1, "icon-btn", 3, "active", "title"], [1, "dialog-footer"], [1, "footer-left"], [1, "footer-btn", "save-btn", "primary", 3, "click", "disabled"], [1, "fa-solid", "fa-check"], [1, "footer-btn", "cancel-btn", 3, "click"], [1, "validation-message"], [1, "dialog-backdrop", 3, "click"], [1, "mode-description"], [1, "fa-solid", "fa-info-circle"], [1, "function-grid"], [1, "function-btn", 3, "active", "title"], [1, "form-select", 3, "ngModelChange", "ngModel"], ["value", ""], [3, "value"], [1, "field-hint", "warning"], [1, "field-hint", "info"], [1, "expression-preview"], [1, "function-btn", 3, "click", "title"], [1, "fa-solid", "fa-exclamation-triangle"], [1, "preview-label"], [1, "preview-code"], ["placeholder", "e.g., SUM(Amount * Quantity) or COUNT(CASE WHEN Status = 'Active' THEN 1 END)", "rows", "3", 1, "form-textarea", "code-input", 3, "ngModelChange", "ngModel"], [1, "field-hint"], [1, "fa-solid", "fa-lightbulb"], [1, "form-label", "examples-label"], [1, "example-chips"], [1, "example-chip", 3, "click"], [1, "smart-input-container"], ["placeholder", "e.g., 'Total revenue from completed orders' or 'Average order value for premium customers'", "rows", "3", 1, "form-textarea", "smart-input", 3, "ngModelChange", "ngModel", "disabled"], [1, "generate-btn", 3, "disabled"], [1, "generated-section"], [1, "smart-tips"], [1, "tips-header"], [1, "tips-list"], [1, "generate-btn", 3, "click", "disabled"], [1, "fa-solid", "fa-spinner", "fa-spin"], [1, "generated-header"], ["title", "Edit prompt", 1, "clear-generated-btn", 3, "click"], [1, "fa-solid", "fa-pen"], [1, "generated-code"], [1, "generated-info"], ["title", "Remove icon", "aria-label", "Remove icon", 1, "clear-icon-btn", 3, "click"], [1, "icon-btn", 3, "click", "title"], [1, "fa-solid", "fa-exclamation-circle"]], template: function AggregateSetupDialogComponent_Template(rf, ctx) { if (rf & 1) {
806
850
  i0.ɵɵconditionalCreate(0, AggregateSetupDialogComponent_Conditional_0_Template, 1, 0, "div", 0);