@memberjunction/ng-query-viewer 6.2.0-edge.0 → 6.2.0-edge.2

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 (34) hide show
  1. package/dist/lib/query-data-grid/models/query-grid-types.d.ts +10 -0
  2. package/dist/lib/query-data-grid/models/query-grid-types.d.ts.map +1 -1
  3. package/dist/lib/query-data-grid/models/query-grid-types.js +26 -6
  4. package/dist/lib/query-data-grid/models/query-grid-types.js.map +1 -1
  5. package/dist/lib/query-data-grid/query-data-grid.component.d.ts.map +1 -1
  6. package/dist/lib/query-data-grid/query-data-grid.component.js +19 -11
  7. package/dist/lib/query-data-grid/query-data-grid.component.js.map +1 -1
  8. package/dist/lib/query-pivot/query-pivot.component.d.ts +144 -0
  9. package/dist/lib/query-pivot/query-pivot.component.d.ts.map +1 -0
  10. package/dist/lib/query-pivot/query-pivot.component.js +434 -0
  11. package/dist/lib/query-pivot/query-pivot.component.js.map +1 -0
  12. package/dist/lib/query-pivot/query-pivot.compute.d.ts +36 -0
  13. package/dist/lib/query-pivot/query-pivot.compute.d.ts.map +1 -0
  14. package/dist/lib/query-pivot/query-pivot.compute.js +324 -0
  15. package/dist/lib/query-pivot/query-pivot.compute.js.map +1 -0
  16. package/dist/lib/query-pivot/query-pivot.types.d.ts +74 -0
  17. package/dist/lib/query-pivot/query-pivot.types.d.ts.map +1 -0
  18. package/dist/lib/query-pivot/query-pivot.types.js +2 -0
  19. package/dist/lib/query-pivot/query-pivot.types.js.map +1 -0
  20. package/dist/lib/query-row-detail/query-row-detail.component.d.ts +26 -0
  21. package/dist/lib/query-row-detail/query-row-detail.component.d.ts.map +1 -1
  22. package/dist/lib/query-row-detail/query-row-detail.component.js +79 -23
  23. package/dist/lib/query-row-detail/query-row-detail.component.js.map +1 -1
  24. package/dist/lib/query-viewer/query-viewer.component.js +5 -5
  25. package/dist/lib/query-viewer/query-viewer.component.js.map +1 -1
  26. package/dist/lib/query-viewer.module.d.ts +11 -10
  27. package/dist/lib/query-viewer.module.d.ts.map +1 -1
  28. package/dist/lib/query-viewer.module.js +9 -4
  29. package/dist/lib/query-viewer.module.js.map +1 -1
  30. package/dist/public-api.d.ts +3 -0
  31. package/dist/public-api.d.ts.map +1 -1
  32. package/dist/public-api.js +4 -1
  33. package/dist/public-api.js.map +1 -1
  34. package/package.json +14 -14
@@ -0,0 +1,434 @@
1
+ import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core';
2
+ import { Subject } from 'rxjs';
3
+ import { RunQuery } from '@memberjunction/core';
4
+ import { BaseAngularComponent } from '@memberjunction/ng-base-types';
5
+ import { ComputePivot } from './query-pivot.compute';
6
+ import * as i0 from "@angular/core";
7
+ import * as i1 from "@memberjunction/ng-shared-generic";
8
+ import * as i2 from "../query-data-grid/query-data-grid.component";
9
+ function QueryPivotComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
10
+ i0.ɵɵelementStart(0, "div", 1);
11
+ i0.ɵɵelement(1, "mj-loading", 5);
12
+ i0.ɵɵelementEnd();
13
+ } }
14
+ function QueryPivotComponent_Conditional_2_Template(rf, ctx) { if (rf & 1) {
15
+ i0.ɵɵelementStart(0, "div", 2)(1, "span", 6);
16
+ i0.ɵɵtext(2);
17
+ i0.ɵɵelementEnd()();
18
+ } if (rf & 2) {
19
+ const ctx_r0 = i0.ɵɵnextContext();
20
+ i0.ɵɵadvance(2);
21
+ i0.ɵɵtextInterpolate(ctx_r0.LastError);
22
+ } }
23
+ /**
24
+ * A generic pivot table component that runs any saved Query or ad-hoc query parameters,
25
+ * groups and aggregates rows across dimensions and time grains, handles comparison windows,
26
+ * formats null values as em dashes ('—'), and renders via mj-query-data-grid.
27
+ *
28
+ * @example
29
+ * ```html
30
+ * <mj-query-pivot
31
+ * [QueryName]="'AIUsageHourly'"
32
+ * [DimensionColumns]="['Agent']"
33
+ * [MeasureColumns]="[{ Key: 'TotalCost', Label: 'Cost', Format: 'currency' }]"
34
+ * (RowActivated)="onRowSelected($event)">
35
+ * </mj-query-pivot>
36
+ * ```
37
+ */
38
+ export class QueryPivotComponent extends BaseAngularComponent {
39
+ cdr;
40
+ // Inputs are setters rather than an ngOnChanges switch (packages/Angular/CLAUDE.md). Each setter
41
+ // reacts only when its own value actually changes, so a host that rebinds an equal value — or an
42
+ // unrelated change-detection pass — never triggers a re-query or a full re-pivot.
43
+ // ========================================
44
+ // Inputs: Query Identification & Params
45
+ // ========================================
46
+ _queryName = null;
47
+ /** Name of the saved Query to execute */
48
+ set QueryName(value) {
49
+ if (value === this._queryName)
50
+ return;
51
+ this._queryName = value;
52
+ this.onQueryIdentityChanged();
53
+ }
54
+ get QueryName() { return this._queryName; }
55
+ /** Category path of the saved Query */
56
+ CategoryPath = null;
57
+ _queryID = null;
58
+ /** ID of the saved Query (alternative to QueryName) */
59
+ set QueryID(value) {
60
+ if (value === this._queryID)
61
+ return;
62
+ this._queryID = value;
63
+ this.onQueryIdentityChanged();
64
+ }
65
+ get QueryID() { return this._queryID; }
66
+ _queryParams = null;
67
+ /** Full RunQueryParams object passed by host */
68
+ set QueryParams(value) {
69
+ if (value === this._queryParams)
70
+ return;
71
+ this._queryParams = value;
72
+ this.onQueryIdentityChanged();
73
+ }
74
+ get QueryParams() { return this._queryParams; }
75
+ _parameters = null;
76
+ /** Parameter values to supply to the query */
77
+ set Parameters(value) {
78
+ if (value === this._parameters)
79
+ return;
80
+ this._parameters = value;
81
+ this.onQueryIdentityChanged();
82
+ }
83
+ get Parameters() { return this._parameters; }
84
+ /** Data source to query from: 'Materialized' (default) or 'Live' */
85
+ DataSource = 'Materialized';
86
+ /** Whether to automatically execute the query when inputs initialize or change */
87
+ AutoRun = true;
88
+ // ========================================
89
+ // Inputs: Pivot Configuration
90
+ // ========================================
91
+ _dimensionColumns = [];
92
+ /** Array of column names to group by */
93
+ set DimensionColumns(value) {
94
+ if (value === this._dimensionColumns)
95
+ return;
96
+ this._dimensionColumns = value ?? [];
97
+ this.onPivotConfigChanged();
98
+ }
99
+ get DimensionColumns() { return this._dimensionColumns; }
100
+ _measureColumns = [];
101
+ /** Array of measure specifications to aggregate */
102
+ set MeasureColumns(value) {
103
+ if (value === this._measureColumns)
104
+ return;
105
+ this._measureColumns = value ?? [];
106
+ this.onPivotConfigChanged();
107
+ }
108
+ get MeasureColumns() { return this._measureColumns; }
109
+ _timeColumn = null;
110
+ /** Optional date/time column for time bucketing */
111
+ set TimeColumn(value) {
112
+ if (value === this._timeColumn)
113
+ return;
114
+ this._timeColumn = value;
115
+ this.onPivotConfigChanged();
116
+ }
117
+ get TimeColumn() { return this._timeColumn; }
118
+ _grain = null;
119
+ /** Grain for time bucketing: 'hour' | 'day' */
120
+ set Grain(value) {
121
+ if (value === this._grain)
122
+ return;
123
+ this._grain = value;
124
+ this.onPivotConfigChanged();
125
+ }
126
+ get Grain() { return this._grain; }
127
+ _comparisonWindow = false;
128
+ /** Whether to compute comparison window metrics and deltas */
129
+ set ComparisonWindow(value) {
130
+ if (value === this._comparisonWindow)
131
+ return;
132
+ this._comparisonWindow = value;
133
+ this.onPivotConfigChanged();
134
+ }
135
+ get ComparisonWindow() { return this._comparisonWindow; }
136
+ _comparisonPeriodColumn = null;
137
+ /** Optional column identifying comparison/previous period rows */
138
+ set ComparisonPeriodColumn(value) {
139
+ if (value === this._comparisonPeriodColumn)
140
+ return;
141
+ this._comparisonPeriodColumn = value;
142
+ this.onPivotConfigChanged();
143
+ }
144
+ get ComparisonPeriodColumn() { return this._comparisonPeriodColumn; }
145
+ _columnLabels = {};
146
+ /** Header titles for dimension/time columns, keyed by column name. */
147
+ set ColumnLabels(value) {
148
+ if (value === this._columnLabels)
149
+ return;
150
+ this._columnLabels = value ?? {};
151
+ this.onPivotConfigChanged();
152
+ }
153
+ get ColumnLabels() { return this._columnLabels; }
154
+ _hiddenColumns = [];
155
+ /** Dimension columns used for grouping but not displayed (e.g. an ID shown via its name column). */
156
+ set HiddenColumns(value) {
157
+ if (value === this._hiddenColumns)
158
+ return;
159
+ this._hiddenColumns = value ?? [];
160
+ this.onPivotConfigChanged();
161
+ }
162
+ get HiddenColumns() { return this._hiddenColumns; }
163
+ // ========================================
164
+ // Inputs: Data & Display Overrides
165
+ // ========================================
166
+ _data = null;
167
+ /** Optional raw data input (bypasses remote query execution if supplied) */
168
+ set Data(value) {
169
+ if (value === this._data)
170
+ return;
171
+ this._data = value;
172
+ if (this.initialized && value) {
173
+ this.ApplyPivot(value);
174
+ }
175
+ }
176
+ get Data() { return this._data; }
177
+ /** External loading state override */
178
+ IsLoading = false;
179
+ /** Height of the pivot container */
180
+ Height = '100%';
181
+ /** Grid row selection mode */
182
+ SelectionMode = 'single';
183
+ /** Whether to show the grid toolbar */
184
+ ShowToolbar = true;
185
+ /** Visual configuration passed to data grid */
186
+ VisualConfig = {};
187
+ // ========================================
188
+ // Outputs
189
+ // ========================================
190
+ /**
191
+ * Emitted when a row is clicked or activated.
192
+ */
193
+ RowActivated = new EventEmitter();
194
+ /** Fired when query execution starts */
195
+ QueryStart = new EventEmitter();
196
+ /** Fired when query execution completes */
197
+ QueryComplete = new EventEmitter();
198
+ /** Fired when query execution encounters an error */
199
+ QueryError = new EventEmitter();
200
+ /** Fired when pivot calculation finishes */
201
+ PivotComplete = new EventEmitter();
202
+ // ========================================
203
+ // Internal State
204
+ // ========================================
205
+ PivotedData = [];
206
+ ColumnConfigs = [];
207
+ RawData = [];
208
+ LastError = null;
209
+ ExecutionTimeMs = null;
210
+ TotalInputRows = 0;
211
+ GroupedRowCount = 0;
212
+ internalIsLoading = false;
213
+ initialized = false;
214
+ runScheduled = false;
215
+ destroy$ = new Subject();
216
+ constructor(cdr) {
217
+ super();
218
+ this.cdr = cdr;
219
+ }
220
+ get Loading() {
221
+ return this.IsLoading || this.internalIsLoading;
222
+ }
223
+ ngOnInit() {
224
+ this.initialized = true;
225
+ if (this.Data && this.Data.length > 0) {
226
+ this.ApplyPivot(this.Data);
227
+ }
228
+ else if (this.AutoRun && (this.QueryName || this.QueryID || this.QueryParams)) {
229
+ void this.Run();
230
+ }
231
+ }
232
+ ngOnDestroy() {
233
+ this.destroy$.next();
234
+ this.destroy$.complete();
235
+ }
236
+ /**
237
+ * A change to what the query is re-runs it; initial values are handled once by ngOnInit. Coalesced
238
+ * to one run per turn, because a host commonly rebinds QueryName and Parameters in the same pass.
239
+ */
240
+ onQueryIdentityChanged() {
241
+ if (!this.initialized || !this.AutoRun || this.runScheduled) {
242
+ return;
243
+ }
244
+ this.runScheduled = true;
245
+ queueMicrotask(() => {
246
+ this.runScheduled = false;
247
+ void this.Run();
248
+ });
249
+ }
250
+ /** A change to how rows are pivoted re-pivots the rows already held; no query round trip. */
251
+ onPivotConfigChanged() {
252
+ if (this.initialized && this.RawData.length > 0) {
253
+ this.ApplyPivot(this.RawData);
254
+ }
255
+ }
256
+ // ========================================
257
+ // Execution & Calculation
258
+ // ========================================
259
+ /**
260
+ * Executes the query and calculates the pivot results.
261
+ */
262
+ async Run() {
263
+ if (this.Data && this.Data.length > 0) {
264
+ this.ApplyPivot(this.Data);
265
+ return;
266
+ }
267
+ if (!this.QueryName && !this.QueryID && !this.QueryParams) {
268
+ return;
269
+ }
270
+ this.internalIsLoading = true;
271
+ this.LastError = null;
272
+ this.QueryStart.emit();
273
+ this.cdr.markForCheck();
274
+ const startTime = performance.now();
275
+ try {
276
+ const rq = new RunQuery(this.RunQueryToUse);
277
+ const runParams = {
278
+ ...(this.QueryParams || {}),
279
+ DataSource: this.DataSource || 'Materialized'
280
+ };
281
+ if (this.QueryID)
282
+ runParams.QueryID = this.QueryID;
283
+ if (this.QueryName)
284
+ runParams.QueryName = this.QueryName;
285
+ if (this.CategoryPath)
286
+ runParams.CategoryPath = this.CategoryPath;
287
+ if (this.Parameters)
288
+ runParams.Parameters = this.Parameters;
289
+ const result = await rq.RunQuery(runParams);
290
+ this.ExecutionTimeMs = Math.round(performance.now() - startTime);
291
+ if (result.Success) {
292
+ this.RawData = result.Results || [];
293
+ this.ApplyPivot(this.RawData);
294
+ this.QueryComplete.emit(result);
295
+ }
296
+ else {
297
+ this.LastError = result.ErrorMessage || 'Query pivot execution failed';
298
+ this.QueryError.emit(new Error(this.LastError));
299
+ }
300
+ }
301
+ catch (error) {
302
+ this.ExecutionTimeMs = Math.round(performance.now() - startTime);
303
+ const message = error instanceof Error ? error.message : 'Unknown error during query pivot';
304
+ this.LastError = message;
305
+ this.QueryError.emit(error instanceof Error ? error : new Error(message));
306
+ }
307
+ finally {
308
+ this.internalIsLoading = false;
309
+ this.cdr.markForCheck();
310
+ }
311
+ }
312
+ /**
313
+ * Purely calculates the pivot over provided rows and updates the view.
314
+ */
315
+ ApplyPivot(rows) {
316
+ this.RawData = rows;
317
+ const config = {
318
+ DimensionColumns: this.DimensionColumns || [],
319
+ MeasureColumns: this.MeasureColumns || [],
320
+ TimeColumn: this.TimeColumn,
321
+ Grain: this.Grain,
322
+ ComparisonWindow: this.ComparisonWindow,
323
+ ComparisonPeriodColumn: this.ComparisonPeriodColumn,
324
+ ColumnLabels: this.ColumnLabels,
325
+ HiddenColumns: this.HiddenColumns
326
+ };
327
+ const pivotResult = ComputePivot(rows, config);
328
+ this.PivotedData = pivotResult.Rows;
329
+ this.ColumnConfigs = pivotResult.ColumnConfigs;
330
+ this.TotalInputRows = pivotResult.TotalInputRows;
331
+ this.GroupedRowCount = pivotResult.GroupedRowCount;
332
+ this.PivotComplete.emit(pivotResult);
333
+ this.cdr.markForCheck();
334
+ }
335
+ /**
336
+ * Refreshes the query execution.
337
+ */
338
+ Refresh() {
339
+ void this.Run();
340
+ }
341
+ // ========================================
342
+ // Event Handlers
343
+ // ========================================
344
+ OnRowClick(event) {
345
+ if (event && event.rowData) {
346
+ this.RowActivated.emit(event.rowData);
347
+ }
348
+ }
349
+ OnRowDoubleClick(event) {
350
+ if (event && event.rowData) {
351
+ this.RowActivated.emit(event.rowData);
352
+ }
353
+ }
354
+ OnRefreshRequest() {
355
+ this.Refresh();
356
+ }
357
+ static ɵfac = function QueryPivotComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || QueryPivotComponent)(i0.ɵɵdirectiveInject(i0.ChangeDetectorRef)); };
358
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: QueryPivotComponent, selectors: [["mj-query-pivot"]], inputs: { QueryName: "QueryName", CategoryPath: "CategoryPath", QueryID: "QueryID", QueryParams: "QueryParams", Parameters: "Parameters", DataSource: "DataSource", AutoRun: "AutoRun", DimensionColumns: "DimensionColumns", MeasureColumns: "MeasureColumns", TimeColumn: "TimeColumn", Grain: "Grain", ComparisonWindow: "ComparisonWindow", ComparisonPeriodColumn: "ComparisonPeriodColumn", ColumnLabels: "ColumnLabels", HiddenColumns: "HiddenColumns", Data: "Data", IsLoading: "IsLoading", Height: "Height", SelectionMode: "SelectionMode", ShowToolbar: "ShowToolbar", VisualConfig: "VisualConfig" }, outputs: { RowActivated: "RowActivated", QueryStart: "QueryStart", QueryComplete: "QueryComplete", QueryError: "QueryError", PivotComplete: "PivotComplete" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 5, vars: 11, consts: [[1, "mj-query-pivot-container"], ["role", "status", "aria-live", "polite", 1, "mj-query-pivot-loading"], ["role", "alert", 1, "mj-query-pivot-error"], [1, "mj-query-pivot-grid-wrapper"], [3, "RowClick", "RowDoubleClick", "RefreshRequest", "ColumnConfigs", "Data", "SelectionMode", "ShowToolbar", "VisualConfig"], ["text", "Loading pivot data..."], [1, "mj-query-pivot-error-text"]], template: function QueryPivotComponent_Template(rf, ctx) { if (rf & 1) {
359
+ i0.ɵɵelementStart(0, "div", 0);
360
+ i0.ɵɵconditionalCreate(1, QueryPivotComponent_Conditional_1_Template, 2, 0, "div", 1);
361
+ i0.ɵɵconditionalCreate(2, QueryPivotComponent_Conditional_2_Template, 3, 1, "div", 2);
362
+ i0.ɵɵelementStart(3, "div", 3)(4, "mj-query-data-grid", 4);
363
+ i0.ɵɵlistener("RowClick", function QueryPivotComponent_Template_mj_query_data_grid_RowClick_4_listener($event) { return ctx.OnRowClick($event); })("RowDoubleClick", function QueryPivotComponent_Template_mj_query_data_grid_RowDoubleClick_4_listener($event) { return ctx.OnRowDoubleClick($event); })("RefreshRequest", function QueryPivotComponent_Template_mj_query_data_grid_RefreshRequest_4_listener() { return ctx.OnRefreshRequest(); });
364
+ i0.ɵɵelementEnd()()();
365
+ } if (rf & 2) {
366
+ i0.ɵɵstyleProp("height", ctx.Height);
367
+ i0.ɵɵadvance();
368
+ i0.ɵɵconditional(ctx.Loading && ctx.PivotedData.length === 0 ? 1 : -1);
369
+ i0.ɵɵadvance();
370
+ i0.ɵɵconditional(ctx.LastError ? 2 : -1);
371
+ i0.ɵɵadvance();
372
+ i0.ɵɵclassProp("mj-query-pivot-dimmed", ctx.Loading);
373
+ i0.ɵɵadvance();
374
+ i0.ɵɵproperty("ColumnConfigs", ctx.ColumnConfigs)("Data", ctx.PivotedData)("SelectionMode", ctx.SelectionMode)("ShowToolbar", ctx.ShowToolbar)("VisualConfig", ctx.VisualConfig);
375
+ } }, dependencies: [i1.LoadingComponent, i2.QueryDataGridComponent], styles: ["[_nghost-%COMP%] {\n display: block;\n width: 100%;\n height: 100%;\n}\n\n.mj-query-pivot-container[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n width: 100%;\n position: relative;\n background-color: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n}\n\n.mj-query-pivot-loading[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: var(--mj-space-6);\n background-color: var(--mj-bg-surface);\n}\n\n.mj-query-pivot-error[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n padding: var(--mj-space-2) var(--mj-space-4);\n margin: var(--mj-space-1);\n background-color: var(--mj-status-error-bg);\n border: 1px solid var(--mj-status-error-border);\n border-radius: var(--mj-radius-sm);\n color: var(--mj-status-error-text);\n font-size: var(--mj-text-sm);\n}\n\n.mj-query-pivot-grid-wrapper[_ngcontent-%COMP%] {\n flex: 1;\n min-height: 0;\n width: 100%;\n display: flex;\n flex-direction: column;\n}\n\n.mj-query-pivot-dimmed[_ngcontent-%COMP%] {\n opacity: 0.6;\n pointer-events: none;\n}"], changeDetection: 0 });
376
+ }
377
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(QueryPivotComponent, [{
378
+ type: Component,
379
+ args: [{ standalone: false, selector: 'mj-query-pivot', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"mj-query-pivot-container\" [style.height]=\"Height\">\n @if (Loading && PivotedData.length === 0) {\n <div class=\"mj-query-pivot-loading\" role=\"status\" aria-live=\"polite\">\n <mj-loading text=\"Loading pivot data...\"></mj-loading>\n </div>\n }\n\n @if (LastError) {\n <div class=\"mj-query-pivot-error\" role=\"alert\">\n <span class=\"mj-query-pivot-error-text\">{{ LastError }}</span>\n </div>\n }\n\n <div class=\"mj-query-pivot-grid-wrapper\" [class.mj-query-pivot-dimmed]=\"Loading\">\n <mj-query-data-grid\n [ColumnConfigs]=\"ColumnConfigs\"\n [Data]=\"PivotedData\"\n [SelectionMode]=\"SelectionMode\"\n [ShowToolbar]=\"ShowToolbar\"\n [VisualConfig]=\"VisualConfig\"\n (RowClick)=\"OnRowClick($event)\"\n (RowDoubleClick)=\"OnRowDoubleClick($event)\"\n (RefreshRequest)=\"OnRefreshRequest()\">\n </mj-query-data-grid>\n </div>\n</div>\n", styles: [":host {\n display: block;\n width: 100%;\n height: 100%;\n}\n\n.mj-query-pivot-container {\n display: flex;\n flex-direction: column;\n width: 100%;\n position: relative;\n background-color: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n}\n\n.mj-query-pivot-loading {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: var(--mj-space-6);\n background-color: var(--mj-bg-surface);\n}\n\n.mj-query-pivot-error {\n display: flex;\n align-items: center;\n padding: var(--mj-space-2) var(--mj-space-4);\n margin: var(--mj-space-1);\n background-color: var(--mj-status-error-bg);\n border: 1px solid var(--mj-status-error-border);\n border-radius: var(--mj-radius-sm);\n color: var(--mj-status-error-text);\n font-size: var(--mj-text-sm);\n}\n\n.mj-query-pivot-grid-wrapper {\n flex: 1;\n min-height: 0;\n width: 100%;\n display: flex;\n flex-direction: column;\n}\n\n.mj-query-pivot-dimmed {\n opacity: 0.6;\n pointer-events: none;\n}\n"] }]
380
+ }], () => [{ type: i0.ChangeDetectorRef }], { QueryName: [{
381
+ type: Input
382
+ }], CategoryPath: [{
383
+ type: Input
384
+ }], QueryID: [{
385
+ type: Input
386
+ }], QueryParams: [{
387
+ type: Input
388
+ }], Parameters: [{
389
+ type: Input
390
+ }], DataSource: [{
391
+ type: Input
392
+ }], AutoRun: [{
393
+ type: Input
394
+ }], DimensionColumns: [{
395
+ type: Input
396
+ }], MeasureColumns: [{
397
+ type: Input
398
+ }], TimeColumn: [{
399
+ type: Input
400
+ }], Grain: [{
401
+ type: Input
402
+ }], ComparisonWindow: [{
403
+ type: Input
404
+ }], ComparisonPeriodColumn: [{
405
+ type: Input
406
+ }], ColumnLabels: [{
407
+ type: Input
408
+ }], HiddenColumns: [{
409
+ type: Input
410
+ }], Data: [{
411
+ type: Input
412
+ }], IsLoading: [{
413
+ type: Input
414
+ }], Height: [{
415
+ type: Input
416
+ }], SelectionMode: [{
417
+ type: Input
418
+ }], ShowToolbar: [{
419
+ type: Input
420
+ }], VisualConfig: [{
421
+ type: Input
422
+ }], RowActivated: [{
423
+ type: Output
424
+ }], QueryStart: [{
425
+ type: Output
426
+ }], QueryComplete: [{
427
+ type: Output
428
+ }], QueryError: [{
429
+ type: Output
430
+ }], PivotComplete: [{
431
+ type: Output
432
+ }] }); })();
433
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(QueryPivotComponent, { className: "QueryPivotComponent", filePath: "src/lib/query-pivot/query-pivot.component.ts", lineNumber: 50 }); })();
434
+ //# sourceMappingURL=query-pivot.component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query-pivot.component.js","sourceRoot":"","sources":["../../../src/lib/query-pivot/query-pivot.component.ts","../../../src/lib/query-pivot/query-pivot.component.html"],"names":[],"mappings":"AAAA,OAAO,EACH,uBAAuB,EAEvB,SAAS,EACT,YAAY,EACZ,KAAK,EAGL,MAAM,EACT,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAC/B,OAAO,EAAE,QAAQ,EAAkC,MAAM,sBAAsB,CAAC;AAChF,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAOrE,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;;;;;ICjB7C,8BAAqE;IACjE,gCAAsD;IAC1D,iBAAM;;;IAKF,AADJ,8BAA+C,cACH;IAAA,YAAe;IAC3D,AAD2D,iBAAO,EAC5D;;;IADsC,eAAe;IAAf,sCAAe;;ADkBnE;;;;;;;;;;;;;;GAcG;AAQH,MAAM,OAAO,mBAAoB,SAAQ,oBAAoB;IAmNrC;IAlNpB,iGAAiG;IACjG,iGAAiG;IACjG,kFAAkF;IAElF,2CAA2C;IAC3C,wCAAwC;IACxC,2CAA2C;IAEnC,UAAU,GAAkB,IAAI,CAAC;IACzC,yCAAyC;IACzC,IACI,SAAS,CAAC,KAAoB;QAC9B,IAAI,KAAK,KAAK,IAAI,CAAC,UAAU;YAAE,OAAO;QACtC,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;QACxB,IAAI,CAAC,sBAAsB,EAAE,CAAC;IAClC,CAAC;IACD,IAAI,SAAS,KAAoB,OAAO,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;IAE1D,uCAAuC;IAC9B,YAAY,GAAkB,IAAI,CAAC;IAEpC,QAAQ,GAAkB,IAAI,CAAC;IACvC,uDAAuD;IACvD,IACI,OAAO,CAAC,KAAoB;QAC5B,IAAI,KAAK,KAAK,IAAI,CAAC,QAAQ;YAAE,OAAO;QACpC,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;QACtB,IAAI,CAAC,sBAAsB,EAAE,CAAC;IAClC,CAAC;IACD,IAAI,OAAO,KAAoB,OAAO,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;IAE9C,YAAY,GAA0B,IAAI,CAAC;IACnD,gDAAgD;IAChD,IACI,WAAW,CAAC,KAA4B;QACxC,IAAI,KAAK,KAAK,IAAI,CAAC,YAAY;YAAE,OAAO;QACxC,IAAI,CAAC,YAAY,GAAG,KAAK,CAAC;QAC1B,IAAI,CAAC,sBAAsB,EAAE,CAAC;IAClC,CAAC;IACD,IAAI,WAAW,KAA4B,OAAO,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC;IAE9D,WAAW,GAAmC,IAAI,CAAC;IAC3D,8CAA8C;IAC9C,IACI,UAAU,CAAC,KAAqC;QAChD,IAAI,KAAK,KAAK,IAAI,CAAC,WAAW;YAAE,OAAO;QACvC,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;QACzB,IAAI,CAAC,sBAAsB,EAAE,CAAC;IAClC,CAAC;IACD,IAAI,UAAU,KAAqC,OAAO,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC;IAE7E,oEAAoE;IAC3D,UAAU,GAA4B,cAAc,CAAC;IAE9D,kFAAkF;IACzE,OAAO,GAAY,IAAI,CAAC;IAEjC,2CAA2C;IAC3C,8BAA8B;IAC9B,2CAA2C;IAEnC,iBAAiB,GAAa,EAAE,CAAC;IACzC,wCAAwC;IACxC,IACI,gBAAgB,CAAC,KAAe;QAChC,IAAI,KAAK,KAAK,IAAI,CAAC,iBAAiB;YAAE,OAAO;QAC7C,IAAI,CAAC,iBAAiB,GAAG,KAAK,IAAI,EAAE,CAAC;QACrC,IAAI,CAAC,oBAAoB,EAAE,CAAC;IAChC,CAAC;IACD,IAAI,gBAAgB,KAAe,OAAO,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC;IAE3D,eAAe,GAAyB,EAAE,CAAC;IACnD,mDAAmD;IACnD,IACI,cAAc,CAAC,KAA2B;QAC1C,IAAI,KAAK,KAAK,IAAI,CAAC,eAAe;YAAE,OAAO;QAC3C,IAAI,CAAC,eAAe,GAAG,KAAK,IAAI,EAAE,CAAC;QACnC,IAAI,CAAC,oBAAoB,EAAE,CAAC;IAChC,CAAC;IACD,IAAI,cAAc,KAA2B,OAAO,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC;IAEnE,WAAW,GAAkB,IAAI,CAAC;IAC1C,mDAAmD;IACnD,IACI,UAAU,CAAC,KAAoB;QAC/B,IAAI,KAAK,KAAK,IAAI,CAAC,WAAW;YAAE,OAAO;QACvC,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;QACzB,IAAI,CAAC,oBAAoB,EAAE,CAAC;IAChC,CAAC;IACD,IAAI,UAAU,KAAoB,OAAO,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC;IAEpD,MAAM,GAA0B,IAAI,CAAC;IAC7C,+CAA+C;IAC/C,IACI,KAAK,CAAC,KAA4B;QAClC,IAAI,KAAK,KAAK,IAAI,CAAC,MAAM;YAAE,OAAO;QAClC,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;QACpB,IAAI,CAAC,oBAAoB,EAAE,CAAC;IAChC,CAAC;IACD,IAAI,KAAK,KAA4B,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;IAElD,iBAAiB,GAAG,KAAK,CAAC;IAClC,8DAA8D;IAC9D,IACI,gBAAgB,CAAC,KAAc;QAC/B,IAAI,KAAK,KAAK,IAAI,CAAC,iBAAiB;YAAE,OAAO;QAC7C,IAAI,CAAC,iBAAiB,GAAG,KAAK,CAAC;QAC/B,IAAI,CAAC,oBAAoB,EAAE,CAAC;IAChC,CAAC;IACD,IAAI,gBAAgB,KAAc,OAAO,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC;IAE1D,uBAAuB,GAAkB,IAAI,CAAC;IACtD,kEAAkE;IAClE,IACI,sBAAsB,CAAC,KAAoB;QAC3C,IAAI,KAAK,KAAK,IAAI,CAAC,uBAAuB;YAAE,OAAO;QACnD,IAAI,CAAC,uBAAuB,GAAG,KAAK,CAAC;QACrC,IAAI,CAAC,oBAAoB,EAAE,CAAC;IAChC,CAAC;IACD,IAAI,sBAAsB,KAAoB,OAAO,IAAI,CAAC,uBAAuB,CAAC,CAAC,CAAC;IAE5E,aAAa,GAA2B,EAAE,CAAC;IACnD,sEAAsE;IACtE,IACI,YAAY,CAAC,KAA6B;QAC1C,IAAI,KAAK,KAAK,IAAI,CAAC,aAAa;YAAE,OAAO;QACzC,IAAI,CAAC,aAAa,GAAG,KAAK,IAAI,EAAE,CAAC;QACjC,IAAI,CAAC,oBAAoB,EAAE,CAAC;IAChC,CAAC;IACD,IAAI,YAAY,KAA6B,OAAO,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC;IAEjE,cAAc,GAAa,EAAE,CAAC;IACtC,oGAAoG;IACpG,IACI,aAAa,CAAC,KAAe;QAC7B,IAAI,KAAK,KAAK,IAAI,CAAC,cAAc;YAAE,OAAO;QAC1C,IAAI,CAAC,cAAc,GAAG,KAAK,IAAI,EAAE,CAAC;QAClC,IAAI,CAAC,oBAAoB,EAAE,CAAC;IAChC,CAAC;IACD,IAAI,aAAa,KAAe,OAAO,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC;IAE7D,2CAA2C;IAC3C,mCAAmC;IACnC,2CAA2C;IAEnC,KAAK,GAAqC,IAAI,CAAC;IACvD,4EAA4E;IAC5E,IACI,IAAI,CAAC,KAAuC;QAC5C,IAAI,KAAK,KAAK,IAAI,CAAC,KAAK;YAAE,OAAO;QACjC,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,IAAI,CAAC,WAAW,IAAI,KAAK,EAAE,CAAC;YAC5B,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;QAC3B,CAAC;IACL,CAAC;IACD,IAAI,IAAI,KAAuC,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;IAEnE,sCAAsC;IAC7B,SAAS,GAAY,KAAK,CAAC;IAEpC,oCAAoC;IAC3B,MAAM,GAAW,MAAM,CAAC;IAEjC,8BAA8B;IACrB,aAAa,GAA2B,QAAQ,CAAC;IAE1D,uCAAuC;IAC9B,WAAW,GAAY,IAAI,CAAC;IAErC,+CAA+C;IACtC,YAAY,GAA0B,EAAE,CAAC;IAElD,2CAA2C;IAC3C,UAAU;IACV,2CAA2C;IAE3C;;OAEG;IACO,YAAY,GAAG,IAAI,YAAY,EAA2B,CAAC;IAErE,wCAAwC;IAC9B,UAAU,GAAG,IAAI,YAAY,EAAQ,CAAC;IAEhD,2CAA2C;IACjC,aAAa,GAAG,IAAI,YAAY,EAAkB,CAAC;IAE7D,qDAAqD;IAC3C,UAAU,GAAG,IAAI,YAAY,EAAS,CAAC;IAEjD,4CAA4C;IAClC,aAAa,GAAG,IAAI,YAAY,EAAe,CAAC;IAE1D,2CAA2C;IAC3C,iBAAiB;IACjB,2CAA2C;IAEpC,WAAW,GAA8B,EAAE,CAAC;IAC5C,aAAa,GAA4B,EAAE,CAAC;IAC5C,OAAO,GAA8B,EAAE,CAAC;IACxC,SAAS,GAAkB,IAAI,CAAC;IAChC,eAAe,GAAkB,IAAI,CAAC;IACtC,cAAc,GAAW,CAAC,CAAC;IAC3B,eAAe,GAAW,CAAC,CAAC;IAE3B,iBAAiB,GAAY,KAAK,CAAC;IACnC,WAAW,GAAG,KAAK,CAAC;IACpB,YAAY,GAAG,KAAK,CAAC;IACrB,QAAQ,GAAG,IAAI,OAAO,EAAQ,CAAC;IAEvC,YAAoB,GAAsB;QACtC,KAAK,EAAE,CAAC;QADQ,QAAG,GAAH,GAAG,CAAmB;IAE1C,CAAC;IAED,IAAW,OAAO;QACd,OAAO,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,iBAAiB,CAAC;IACpD,CAAC;IAED,QAAQ;QACJ,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;QACxB,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACpC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/B,CAAC;aAAM,IAAI,IAAI,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;YAC9E,KAAK,IAAI,CAAC,GAAG,EAAE,CAAC;QACpB,CAAC;IACL,CAAC;IAED,WAAW;QACP,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;QACrB,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC;IAC7B,CAAC;IAED;;;OAGG;IACK,sBAAsB;QAC1B,IAAI,CAAC,IAAI,CAAC,WAAW,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;YAC1D,OAAO;QACX,CAAC;QACD,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QACzB,cAAc,CAAC,GAAG,EAAE;YAChB,IAAI,CAAC,YAAY,GAAG,KAAK,CAAC;YAC1B,KAAK,IAAI,CAAC,GAAG,EAAE,CAAC;QACpB,CAAC,CAAC,CAAC;IACP,CAAC;IAED,6FAA6F;IACrF,oBAAoB;QACxB,IAAI,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC9C,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAClC,CAAC;IACL,CAAC;IAED,2CAA2C;IAC3C,0BAA0B;IAC1B,2CAA2C;IAE3C;;OAEG;IACI,KAAK,CAAC,GAAG;QACZ,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACpC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC3B,OAAO;QACX,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,SAAS,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;YACxD,OAAO;QACX,CAAC;QAED,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC;QAC9B,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACtB,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC;QACvB,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC;QAExB,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;QAEpC,IAAI,CAAC;YACD,MAAM,EAAE,GAAG,IAAI,QAAQ,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;YAC5C,MAAM,SAAS,GAAmB;gBAC9B,GAAG,CAAC,IAAI,CAAC,WAAW,IAAI,EAAE,CAAC;gBAC3B,UAAU,EAAE,IAAI,CAAC,UAAU,IAAI,cAAc;aAChD,CAAC;YAEF,IAAI,IAAI,CAAC,OAAO;gBAAE,SAAS,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;YACnD,IAAI,IAAI,CAAC,SAAS;gBAAE,SAAS,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC;YACzD,IAAI,IAAI,CAAC,YAAY;gBAAE,SAAS,CAAC,YAAY,GAAG,IAAI,CAAC,YAAY,CAAC;YAClE,IAAI,IAAI,CAAC,UAAU;gBAAE,SAAS,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC;YAE5D,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;YAC5C,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC,CAAC;YAEjE,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;gBACjB,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,IAAI,EAAE,CAAC;gBACpC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;gBAC9B,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACpC,CAAC;iBAAM,CAAC;gBACJ,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,YAAY,IAAI,8BAA8B,CAAC;gBACvE,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;YACpD,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC,CAAC;YACjE,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,kCAAkC,CAAC;YAC5F,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC;YACzB,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;QAC9E,CAAC;gBAAS,CAAC;YACP,IAAI,CAAC,iBAAiB,GAAG,KAAK,CAAC;YAC/B,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC;QAC5B,CAAC;IACL,CAAC;IAED;;OAEG;IACI,UAAU,CAAC,IAA+B;QAC7C,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,MAAM,MAAM,GAAqB;YAC7B,gBAAgB,EAAE,IAAI,CAAC,gBAAgB,IAAI,EAAE;YAC7C,cAAc,EAAE,IAAI,CAAC,cAAc,IAAI,EAAE;YACzC,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,gBAAgB,EAAE,IAAI,CAAC,gBAAgB;YACvC,sBAAsB,EAAE,IAAI,CAAC,sBAAsB;YACnD,YAAY,EAAE,IAAI,CAAC,YAAY;YAC/B,aAAa,EAAE,IAAI,CAAC,aAAa;SACpC,CAAC;QAEF,MAAM,WAAW,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAC/C,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC,IAAI,CAAC;QACpC,IAAI,CAAC,aAAa,GAAG,WAAW,CAAC,aAAa,CAAC;QAC/C,IAAI,CAAC,cAAc,GAAG,WAAW,CAAC,cAAc,CAAC;QACjD,IAAI,CAAC,eAAe,GAAG,WAAW,CAAC,eAAe,CAAC;QACnD,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACrC,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC;IAC5B,CAAC;IAED;;OAEG;IACI,OAAO;QACV,KAAK,IAAI,CAAC,GAAG,EAAE,CAAC;IACpB,CAAC;IAED,2CAA2C;IAC3C,iBAAiB;IACjB,2CAA2C;IAEpC,UAAU,CAAC,KAAyB;QACvC,IAAI,KAAK,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;YACzB,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC1C,CAAC;IACL,CAAC;IAEM,gBAAgB,CAAC,KAAyB;QAC7C,IAAI,KAAK,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;YACzB,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC1C,CAAC;IACL,CAAC;IAEM,gBAAgB;QACnB,IAAI,CAAC,OAAO,EAAE,CAAC;IACnB,CAAC;6GA3WQ,mBAAmB;6DAAnB,mBAAmB;YCjDhC,8BAA8D;YAC1D,qFAA2C;YAM3C,qFAAiB;YAOb,AADJ,8BAAiF,4BASnC;YAAtC,AADA,AADA,wHAAY,sBAAkB,IAAC,uHACb,4BAAwB,IAAC,iHACzB,sBAAkB,IAAC;YAGjD,AADI,AADI,iBAAqB,EACnB,EACJ;;YAzBgC,oCAAuB;YACzD,cAIC;YAJD,sEAIC;YAED,cAIC;YAJD,wCAIC;YAEwC,cAAuC;YAAvC,oDAAuC;YAExE,cAA+B;YAI/B,AADA,AADA,AADA,AADA,iDAA+B,yBACX,oCACW,gCACJ,kCACE;;;iFD8B5B,mBAAmB;cAP/B,SAAS;6BACM,KAAK,YACP,gBAAgB,mBAGT,uBAAuB,CAAC,MAAM;;kBAa9C,KAAK;;kBASL,KAAK;;kBAIL,KAAK;;kBAUL,KAAK;;kBAUL,KAAK;;kBASL,KAAK;;kBAGL,KAAK;;kBAQL,KAAK;;kBAUL,KAAK;;kBAUL,KAAK;;kBAUL,KAAK;;kBAUL,KAAK;;kBAUL,KAAK;;kBAUL,KAAK;;kBAUL,KAAK;;kBAcL,KAAK;;kBAWL,KAAK;;kBAGL,KAAK;;kBAGL,KAAK;;kBAGL,KAAK;;kBAGL,KAAK;;kBASL,MAAM;;kBAGN,MAAM;;kBAGN,MAAM;;kBAGN,MAAM;;kBAGN,MAAM;;kFAhME,mBAAmB","sourcesContent":["import {\n ChangeDetectionStrategy,\n ChangeDetectorRef,\n Component,\n EventEmitter,\n Input,\n OnDestroy,\n OnInit,\n Output\n} from '@angular/core';\nimport { Subject } from 'rxjs';\nimport { RunQuery, RunQueryParams, RunQueryResult } from '@memberjunction/core';\nimport { BaseAngularComponent } from '@memberjunction/ng-base-types';\nimport {\n QueryGridColumnConfig,\n QueryGridSelectionMode,\n QueryGridVisualConfig,\n QueryRowClickEvent\n} from '../query-data-grid/models/query-grid-types';\nimport { ComputePivot } from './query-pivot.compute';\nimport {\n PivotMeasureColumn,\n PivotResult,\n PivotTimeGrain,\n QueryPivotConfig\n} from './query-pivot.types';\n\n/**\n * A generic pivot table component that runs any saved Query or ad-hoc query parameters,\n * groups and aggregates rows across dimensions and time grains, handles comparison windows,\n * formats null values as em dashes ('—'), and renders via mj-query-data-grid.\n *\n * @example\n * ```html\n * <mj-query-pivot\n * [QueryName]=\"'AIUsageHourly'\"\n * [DimensionColumns]=\"['Agent']\"\n * [MeasureColumns]=\"[{ Key: 'TotalCost', Label: 'Cost', Format: 'currency' }]\"\n * (RowActivated)=\"onRowSelected($event)\">\n * </mj-query-pivot>\n * ```\n */\n@Component({\n standalone: false,\n selector: 'mj-query-pivot',\n templateUrl: './query-pivot.component.html',\n styleUrls: ['./query-pivot.component.css'],\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class QueryPivotComponent extends BaseAngularComponent implements OnInit, OnDestroy {\n // Inputs are setters rather than an ngOnChanges switch (packages/Angular/CLAUDE.md). Each setter\n // reacts only when its own value actually changes, so a host that rebinds an equal value — or an\n // unrelated change-detection pass — never triggers a re-query or a full re-pivot.\n\n // ========================================\n // Inputs: Query Identification & Params\n // ========================================\n\n private _queryName: string | null = null;\n /** Name of the saved Query to execute */\n @Input()\n set QueryName(value: string | null) {\n if (value === this._queryName) return;\n this._queryName = value;\n this.onQueryIdentityChanged();\n }\n get QueryName(): string | null { return this._queryName; }\n\n /** Category path of the saved Query */\n @Input() CategoryPath: string | null = null;\n\n private _queryID: string | null = null;\n /** ID of the saved Query (alternative to QueryName) */\n @Input()\n set QueryID(value: string | null) {\n if (value === this._queryID) return;\n this._queryID = value;\n this.onQueryIdentityChanged();\n }\n get QueryID(): string | null { return this._queryID; }\n\n private _queryParams: RunQueryParams | null = null;\n /** Full RunQueryParams object passed by host */\n @Input()\n set QueryParams(value: RunQueryParams | null) {\n if (value === this._queryParams) return;\n this._queryParams = value;\n this.onQueryIdentityChanged();\n }\n get QueryParams(): RunQueryParams | null { return this._queryParams; }\n\n private _parameters: Record<string, unknown> | null = null;\n /** Parameter values to supply to the query */\n @Input()\n set Parameters(value: Record<string, unknown> | null) {\n if (value === this._parameters) return;\n this._parameters = value;\n this.onQueryIdentityChanged();\n }\n get Parameters(): Record<string, unknown> | null { return this._parameters; }\n\n /** Data source to query from: 'Materialized' (default) or 'Live' */\n @Input() DataSource: 'Materialized' | 'Live' = 'Materialized';\n\n /** Whether to automatically execute the query when inputs initialize or change */\n @Input() AutoRun: boolean = true;\n\n // ========================================\n // Inputs: Pivot Configuration\n // ========================================\n\n private _dimensionColumns: string[] = [];\n /** Array of column names to group by */\n @Input()\n set DimensionColumns(value: string[]) {\n if (value === this._dimensionColumns) return;\n this._dimensionColumns = value ?? [];\n this.onPivotConfigChanged();\n }\n get DimensionColumns(): string[] { return this._dimensionColumns; }\n\n private _measureColumns: PivotMeasureColumn[] = [];\n /** Array of measure specifications to aggregate */\n @Input()\n set MeasureColumns(value: PivotMeasureColumn[]) {\n if (value === this._measureColumns) return;\n this._measureColumns = value ?? [];\n this.onPivotConfigChanged();\n }\n get MeasureColumns(): PivotMeasureColumn[] { return this._measureColumns; }\n\n private _timeColumn: string | null = null;\n /** Optional date/time column for time bucketing */\n @Input()\n set TimeColumn(value: string | null) {\n if (value === this._timeColumn) return;\n this._timeColumn = value;\n this.onPivotConfigChanged();\n }\n get TimeColumn(): string | null { return this._timeColumn; }\n\n private _grain: PivotTimeGrain | null = null;\n /** Grain for time bucketing: 'hour' | 'day' */\n @Input()\n set Grain(value: PivotTimeGrain | null) {\n if (value === this._grain) return;\n this._grain = value;\n this.onPivotConfigChanged();\n }\n get Grain(): PivotTimeGrain | null { return this._grain; }\n\n private _comparisonWindow = false;\n /** Whether to compute comparison window metrics and deltas */\n @Input()\n set ComparisonWindow(value: boolean) {\n if (value === this._comparisonWindow) return;\n this._comparisonWindow = value;\n this.onPivotConfigChanged();\n }\n get ComparisonWindow(): boolean { return this._comparisonWindow; }\n\n private _comparisonPeriodColumn: string | null = null;\n /** Optional column identifying comparison/previous period rows */\n @Input()\n set ComparisonPeriodColumn(value: string | null) {\n if (value === this._comparisonPeriodColumn) return;\n this._comparisonPeriodColumn = value;\n this.onPivotConfigChanged();\n }\n get ComparisonPeriodColumn(): string | null { return this._comparisonPeriodColumn; }\n\n private _columnLabels: Record<string, string> = {};\n /** Header titles for dimension/time columns, keyed by column name. */\n @Input()\n set ColumnLabels(value: Record<string, string>) {\n if (value === this._columnLabels) return;\n this._columnLabels = value ?? {};\n this.onPivotConfigChanged();\n }\n get ColumnLabels(): Record<string, string> { return this._columnLabels; }\n\n private _hiddenColumns: string[] = [];\n /** Dimension columns used for grouping but not displayed (e.g. an ID shown via its name column). */\n @Input()\n set HiddenColumns(value: string[]) {\n if (value === this._hiddenColumns) return;\n this._hiddenColumns = value ?? [];\n this.onPivotConfigChanged();\n }\n get HiddenColumns(): string[] { return this._hiddenColumns; }\n\n // ========================================\n // Inputs: Data & Display Overrides\n // ========================================\n\n private _data: Record<string, unknown>[] | null = null;\n /** Optional raw data input (bypasses remote query execution if supplied) */\n @Input()\n set Data(value: Record<string, unknown>[] | null) {\n if (value === this._data) return;\n this._data = value;\n if (this.initialized && value) {\n this.ApplyPivot(value);\n }\n }\n get Data(): Record<string, unknown>[] | null { return this._data; }\n\n /** External loading state override */\n @Input() IsLoading: boolean = false;\n\n /** Height of the pivot container */\n @Input() Height: string = '100%';\n\n /** Grid row selection mode */\n @Input() SelectionMode: QueryGridSelectionMode = 'single';\n\n /** Whether to show the grid toolbar */\n @Input() ShowToolbar: boolean = true;\n\n /** Visual configuration passed to data grid */\n @Input() VisualConfig: QueryGridVisualConfig = {};\n\n // ========================================\n // Outputs\n // ========================================\n\n /**\n * Emitted when a row is clicked or activated.\n */\n @Output() RowActivated = new EventEmitter<Record<string, unknown>>();\n\n /** Fired when query execution starts */\n @Output() QueryStart = new EventEmitter<void>();\n\n /** Fired when query execution completes */\n @Output() QueryComplete = new EventEmitter<RunQueryResult>();\n\n /** Fired when query execution encounters an error */\n @Output() QueryError = new EventEmitter<Error>();\n\n /** Fired when pivot calculation finishes */\n @Output() PivotComplete = new EventEmitter<PivotResult>();\n\n // ========================================\n // Internal State\n // ========================================\n\n public PivotedData: Record<string, unknown>[] = [];\n public ColumnConfigs: QueryGridColumnConfig[] = [];\n public RawData: Record<string, unknown>[] = [];\n public LastError: string | null = null;\n public ExecutionTimeMs: number | null = null;\n public TotalInputRows: number = 0;\n public GroupedRowCount: number = 0;\n\n private internalIsLoading: boolean = false;\n private initialized = false;\n private runScheduled = false;\n private destroy$ = new Subject<void>();\n\n constructor(private cdr: ChangeDetectorRef) {\n super();\n }\n\n public get Loading(): boolean {\n return this.IsLoading || this.internalIsLoading;\n }\n\n ngOnInit(): void {\n this.initialized = true;\n if (this.Data && this.Data.length > 0) {\n this.ApplyPivot(this.Data);\n } else if (this.AutoRun && (this.QueryName || this.QueryID || this.QueryParams)) {\n void this.Run();\n }\n }\n\n ngOnDestroy(): void {\n this.destroy$.next();\n this.destroy$.complete();\n }\n\n /**\n * A change to what the query is re-runs it; initial values are handled once by ngOnInit. Coalesced\n * to one run per turn, because a host commonly rebinds QueryName and Parameters in the same pass.\n */\n private onQueryIdentityChanged(): void {\n if (!this.initialized || !this.AutoRun || this.runScheduled) {\n return;\n }\n this.runScheduled = true;\n queueMicrotask(() => {\n this.runScheduled = false;\n void this.Run();\n });\n }\n\n /** A change to how rows are pivoted re-pivots the rows already held; no query round trip. */\n private onPivotConfigChanged(): void {\n if (this.initialized && this.RawData.length > 0) {\n this.ApplyPivot(this.RawData);\n }\n }\n\n // ========================================\n // Execution & Calculation\n // ========================================\n\n /**\n * Executes the query and calculates the pivot results.\n */\n public async Run(): Promise<void> {\n if (this.Data && this.Data.length > 0) {\n this.ApplyPivot(this.Data);\n return;\n }\n\n if (!this.QueryName && !this.QueryID && !this.QueryParams) {\n return;\n }\n\n this.internalIsLoading = true;\n this.LastError = null;\n this.QueryStart.emit();\n this.cdr.markForCheck();\n\n const startTime = performance.now();\n\n try {\n const rq = new RunQuery(this.RunQueryToUse);\n const runParams: RunQueryParams = {\n ...(this.QueryParams || {}),\n DataSource: this.DataSource || 'Materialized'\n };\n\n if (this.QueryID) runParams.QueryID = this.QueryID;\n if (this.QueryName) runParams.QueryName = this.QueryName;\n if (this.CategoryPath) runParams.CategoryPath = this.CategoryPath;\n if (this.Parameters) runParams.Parameters = this.Parameters;\n\n const result = await rq.RunQuery(runParams);\n this.ExecutionTimeMs = Math.round(performance.now() - startTime);\n\n if (result.Success) {\n this.RawData = result.Results || [];\n this.ApplyPivot(this.RawData);\n this.QueryComplete.emit(result);\n } else {\n this.LastError = result.ErrorMessage || 'Query pivot execution failed';\n this.QueryError.emit(new Error(this.LastError));\n }\n } catch (error) {\n this.ExecutionTimeMs = Math.round(performance.now() - startTime);\n const message = error instanceof Error ? error.message : 'Unknown error during query pivot';\n this.LastError = message;\n this.QueryError.emit(error instanceof Error ? error : new Error(message));\n } finally {\n this.internalIsLoading = false;\n this.cdr.markForCheck();\n }\n }\n\n /**\n * Purely calculates the pivot over provided rows and updates the view.\n */\n public ApplyPivot(rows: Record<string, unknown>[]): void {\n this.RawData = rows;\n const config: QueryPivotConfig = {\n DimensionColumns: this.DimensionColumns || [],\n MeasureColumns: this.MeasureColumns || [],\n TimeColumn: this.TimeColumn,\n Grain: this.Grain,\n ComparisonWindow: this.ComparisonWindow,\n ComparisonPeriodColumn: this.ComparisonPeriodColumn,\n ColumnLabels: this.ColumnLabels,\n HiddenColumns: this.HiddenColumns\n };\n\n const pivotResult = ComputePivot(rows, config);\n this.PivotedData = pivotResult.Rows;\n this.ColumnConfigs = pivotResult.ColumnConfigs;\n this.TotalInputRows = pivotResult.TotalInputRows;\n this.GroupedRowCount = pivotResult.GroupedRowCount;\n this.PivotComplete.emit(pivotResult);\n this.cdr.markForCheck();\n }\n\n /**\n * Refreshes the query execution.\n */\n public Refresh(): void {\n void this.Run();\n }\n\n // ========================================\n // Event Handlers\n // ========================================\n\n public OnRowClick(event: QueryRowClickEvent): void {\n if (event && event.rowData) {\n this.RowActivated.emit(event.rowData);\n }\n }\n\n public OnRowDoubleClick(event: QueryRowClickEvent): void {\n if (event && event.rowData) {\n this.RowActivated.emit(event.rowData);\n }\n }\n\n public OnRefreshRequest(): void {\n this.Refresh();\n }\n}\n","<div class=\"mj-query-pivot-container\" [style.height]=\"Height\">\n @if (Loading && PivotedData.length === 0) {\n <div class=\"mj-query-pivot-loading\" role=\"status\" aria-live=\"polite\">\n <mj-loading text=\"Loading pivot data...\"></mj-loading>\n </div>\n }\n\n @if (LastError) {\n <div class=\"mj-query-pivot-error\" role=\"alert\">\n <span class=\"mj-query-pivot-error-text\">{{ LastError }}</span>\n </div>\n }\n\n <div class=\"mj-query-pivot-grid-wrapper\" [class.mj-query-pivot-dimmed]=\"Loading\">\n <mj-query-data-grid\n [ColumnConfigs]=\"ColumnConfigs\"\n [Data]=\"PivotedData\"\n [SelectionMode]=\"SelectionMode\"\n [ShowToolbar]=\"ShowToolbar\"\n [VisualConfig]=\"VisualConfig\"\n (RowClick)=\"OnRowClick($event)\"\n (RowDoubleClick)=\"OnRowDoubleClick($event)\"\n (RefreshRequest)=\"OnRefreshRequest()\">\n </mj-query-data-grid>\n </div>\n</div>\n"]}
@@ -0,0 +1,36 @@
1
+ import { PivotAggregationType, PivotMeasureFormat, PivotResult, PivotTimeGrain, QueryPivotConfig } from './query-pivot.types';
2
+ /**
3
+ * Formats a numeric measure value according to the specified format style.
4
+ * Null and undefined values always render as an em dash ('—').
5
+ */
6
+ export declare function FormatMeasureValue(value: number | null | undefined, format: PivotMeasureFormat, currencyCode?: string): string;
7
+ /**
8
+ * Formats a duration in milliseconds into a concise readable unit (ms, s, m s).
9
+ */
10
+ export declare function FormatDuration(ms: number): string;
11
+ /**
12
+ * Formats a comparison delta percentage with sign prefix and em dash fallback.
13
+ */
14
+ export declare function FormatDelta(deltaPercent: number | null | undefined): string;
15
+ /**
16
+ * Buckets a date/time value into the given time grain (hour or day).
17
+ */
18
+ export declare function BucketTimestamp(value: unknown, grain: PivotTimeGrain): string;
19
+ /**
20
+ * Computes an aggregate over an array of numeric values, ignoring nulls.
21
+ * If all values are null/undefined/NaN, returns null.
22
+ *
23
+ * NOTE: For 'count' aggregation, this returns the count of non-null values
24
+ * for the measure column in this group (matching SQL COUNT(column) semantics).
25
+ */
26
+ export declare function AggregateValues(values: (number | null | undefined)[], aggregation?: PivotAggregationType): number | null;
27
+ /**
28
+ * Computes percentage delta between current and previous values.
29
+ */
30
+ export declare function ComputeDeltaPercent(current: number | null, previous: number | null): number | null;
31
+ /**
32
+ * Pure pivot function: aggregates query rows by dimensions, applies measure aggregations,
33
+ * computes comparison deltas, formats null values as em dashes ('—'), and builds grid column defs.
34
+ */
35
+ export declare function ComputePivot(rows: Record<string, unknown>[], config: QueryPivotConfig): PivotResult;
36
+ //# sourceMappingURL=query-pivot.compute.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query-pivot.compute.d.ts","sourceRoot":"","sources":["../../../src/lib/query-pivot/query-pivot.compute.ts"],"names":[],"mappings":"AACA,OAAO,EACH,oBAAoB,EAEpB,kBAAkB,EAClB,WAAW,EACX,cAAc,EACd,gBAAgB,EACnB,MAAM,qBAAqB,CAAC;AAE7B;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,MAAM,EAAE,kBAAkB,EAAE,YAAY,GAAE,MAAc,GAAG,MAAM,CA2BrI;AA0BD;;GAEG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAUjD;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAM3E;AAaD;;GAEG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,cAAc,GAAG,MAAM,CAoB7E;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC3B,MAAM,EAAE,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,EAAE,EACrC,WAAW,GAAE,oBAA4B,GAC1C,MAAM,GAAG,IAAI,CA6Bf;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAKlG;AA8MD;;;GAGG;AACH,wBAAgB,YAAY,CACxB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAC/B,MAAM,EAAE,gBAAgB,GACzB,WAAW,CA2Bb"}