@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.
- package/dist/lib/aggregate-panel/aggregate-panel.component.d.ts +18 -2
- package/dist/lib/aggregate-panel/aggregate-panel.component.d.ts.map +1 -1
- package/dist/lib/aggregate-panel/aggregate-panel.component.js +47 -18
- package/dist/lib/aggregate-panel/aggregate-panel.component.js.map +1 -1
- package/dist/lib/aggregate-setup-dialog/aggregate-setup-dialog.component.d.ts +22 -0
- package/dist/lib/aggregate-setup-dialog/aggregate-setup-dialog.component.d.ts.map +1 -1
- package/dist/lib/aggregate-setup-dialog/aggregate-setup-dialog.component.js +57 -13
- package/dist/lib/aggregate-setup-dialog/aggregate-setup-dialog.component.js.map +1 -1
- package/dist/lib/entity-cards/entity-cards.component.d.ts +68 -5
- package/dist/lib/entity-cards/entity-cards.component.d.ts.map +1 -1
- package/dist/lib/entity-cards/entity-cards.component.js +213 -73
- package/dist/lib/entity-cards/entity-cards.component.js.map +1 -1
- package/dist/lib/entity-data-grid/entity-data-grid.component.d.ts +156 -14
- package/dist/lib/entity-data-grid/entity-data-grid.component.d.ts.map +1 -1
- package/dist/lib/entity-data-grid/entity-data-grid.component.js +432 -138
- package/dist/lib/entity-data-grid/entity-data-grid.component.js.map +1 -1
- package/dist/lib/entity-data-grid/events/grid-events.js +67 -67
- package/dist/lib/entity-data-grid/events/grid-events.js.map +1 -1
- package/dist/lib/entity-record-detail-panel/entity-record-detail-panel.component.d.ts +112 -8
- package/dist/lib/entity-record-detail-panel/entity-record-detail-panel.component.d.ts.map +1 -1
- package/dist/lib/entity-record-detail-panel/entity-record-detail-panel.component.js +255 -69
- package/dist/lib/entity-record-detail-panel/entity-record-detail-panel.component.js.map +1 -1
- package/dist/lib/entity-viewer/entity-viewer.component.d.ts +11 -0
- package/dist/lib/entity-viewer/entity-viewer.component.d.ts.map +1 -1
- package/dist/lib/entity-viewer/entity-viewer.component.js +45 -8
- package/dist/lib/entity-viewer/entity-viewer.component.js.map +1 -1
- package/dist/lib/pill/pill.component.d.ts +13 -3
- package/dist/lib/pill/pill.component.d.ts.map +1 -1
- package/dist/lib/pill/pill.component.js +34 -10
- package/dist/lib/pill/pill.component.js.map +1 -1
- package/dist/lib/quick-save-dialog/quick-save-dialog.component.d.ts +29 -3
- package/dist/lib/quick-save-dialog/quick-save-dialog.component.d.ts.map +1 -1
- package/dist/lib/quick-save-dialog/quick-save-dialog.component.js +173 -114
- package/dist/lib/quick-save-dialog/quick-save-dialog.component.js.map +1 -1
- package/dist/lib/recycle-bin/recycle-bin.component.d.ts +4 -0
- package/dist/lib/recycle-bin/recycle-bin.component.d.ts.map +1 -1
- package/dist/lib/recycle-bin/recycle-bin.component.js +10 -2
- package/dist/lib/recycle-bin/recycle-bin.component.js.map +1 -1
- package/dist/lib/utils/aggregate-field.util.d.ts +21 -0
- package/dist/lib/utils/aggregate-field.util.d.ts.map +1 -0
- package/dist/lib/utils/aggregate-field.util.js +40 -0
- package/dist/lib/utils/aggregate-field.util.js.map +1 -0
- package/dist/lib/utils/highlight.util.d.ts +6 -0
- package/dist/lib/utils/highlight.util.d.ts.map +1 -1
- package/dist/lib/utils/highlight.util.js +23 -11
- package/dist/lib/utils/highlight.util.js.map +1 -1
- package/dist/lib/utils/record.util.d.ts +10 -0
- package/dist/lib/utils/record.util.d.ts.map +1 -1
- package/dist/lib/utils/record.util.js +20 -4
- package/dist/lib/utils/record.util.js.map +1 -1
- package/dist/lib/view-config-panel/view-config-panel.component.d.ts +22 -2
- package/dist/lib/view-config-panel/view-config-panel.component.d.ts.map +1 -1
- package/dist/lib/view-config-panel/view-config-panel.component.js +54 -14
- package/dist/lib/view-config-panel/view-config-panel.component.js.map +1 -1
- package/dist/lib/view-selector/view-selector.component.js +2 -2
- package/dist/lib/view-types/renderers/cards-view-renderer.component.d.ts +15 -3
- package/dist/lib/view-types/renderers/cards-view-renderer.component.d.ts.map +1 -1
- package/dist/lib/view-types/renderers/cards-view-renderer.component.js +33 -5
- package/dist/lib/view-types/renderers/cards-view-renderer.component.js.map +1 -1
- package/dist/lib/view-types/renderers/grid-view-renderer.component.d.ts +160 -5
- package/dist/lib/view-types/renderers/grid-view-renderer.component.d.ts.map +1 -1
- package/dist/lib/view-types/renderers/grid-view-renderer.component.js +576 -36
- package/dist/lib/view-types/renderers/grid-view-renderer.component.js.map +1 -1
- package/dist/lib/view-types/renderers/map-view-renderer.component.d.ts +16 -2
- package/dist/lib/view-types/renderers/map-view-renderer.component.d.ts.map +1 -1
- package/dist/lib/view-types/renderers/map-view-renderer.component.js +37 -9
- package/dist/lib/view-types/renderers/map-view-renderer.component.js.map +1 -1
- package/dist/lib/view-types/view-type.contracts.js.map +1 -1
- package/dist/lib/view-workspace/view-workspace.component.d.ts +235 -24
- package/dist/lib/view-workspace/view-workspace.component.d.ts.map +1 -1
- package/dist/lib/view-workspace/view-workspace.component.js +600 -174
- package/dist/lib/view-workspace/view-workspace.component.js.map +1 -1
- package/dist/module.d.ts +5 -4
- package/dist/module.d.ts.map +1 -1
- package/dist/module.js +8 -1
- package/dist/module.js.map +1 -1
- package/dist/public-api.d.ts +1 -0
- package/dist/public-api.d.ts.map +1 -1
- package/dist/public-api.js +1 -0
- package/dist/public-api.js.map +1 -1
- 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,
|
|
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
|
-
|
|
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:
|
|
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":"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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
575
|
+
OnColumnSelected(newColumn) {
|
|
568
576
|
const previousColumn = this._previousColumn;
|
|
569
577
|
this._previousColumn = newColumn;
|
|
570
|
-
this.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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);
|