@memberjunction/ng-query-viewer 5.48.0 → 5.50.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/query-data-grid/query-data-grid.component.d.ts +25 -4
- package/dist/lib/query-data-grid/query-data-grid.component.d.ts.map +1 -1
- package/dist/lib/query-data-grid/query-data-grid.component.js +100 -24
- package/dist/lib/query-data-grid/query-data-grid.component.js.map +1 -1
- package/dist/lib/query-viewer/query-viewer.component.d.ts +15 -0
- package/dist/lib/query-viewer/query-viewer.component.d.ts.map +1 -1
- package/dist/lib/query-viewer/query-viewer.component.js +44 -4
- package/dist/lib/query-viewer/query-viewer.component.js.map +1 -1
- package/package.json +14 -14
|
@@ -49,6 +49,14 @@ export declare class QueryDataGridComponent implements OnInit, OnDestroy {
|
|
|
49
49
|
set ColumnConfigs(value: QueryGridColumnConfig[] | null);
|
|
50
50
|
get ColumnConfigs(): QueryGridColumnConfig[] | null;
|
|
51
51
|
private _data;
|
|
52
|
+
/**
|
|
53
|
+
* Per-row synthetic identity for rows that have no natural key column, so the
|
|
54
|
+
* `getRowId` fallback can never return duplicate ids (ag-Grid silently merges
|
|
55
|
+
* rows that share an id). Keyed by the row object reference; entries are added
|
|
56
|
+
* as Data is assigned. A WeakMap so it never retains rows past their lifetime.
|
|
57
|
+
*/
|
|
58
|
+
private _syntheticRowIds;
|
|
59
|
+
private _syntheticRowIdSeq;
|
|
52
60
|
/**
|
|
53
61
|
* The query result data to display in the grid.
|
|
54
62
|
*/
|
|
@@ -143,6 +151,16 @@ export declare class QueryDataGridComponent implements OnInit, OnDestroy {
|
|
|
143
151
|
PageNumber: number;
|
|
144
152
|
/** Page size for server-side paging */
|
|
145
153
|
PageSize: number;
|
|
154
|
+
/**
|
|
155
|
+
* Optional provider that returns the FULL result set for export. When the grid is server-side
|
|
156
|
+
* paged, `Data` only holds the current page (default 100 rows), so exporting `Data` would silently
|
|
157
|
+
* cap the export at the page size (bug B3/C1). A host that owns the query (with its parameters) can
|
|
158
|
+
* supply this callback to fetch every matching row on demand; the grid awaits it when the user
|
|
159
|
+
* exports without an explicit row selection. When not provided, export falls back to the loaded page.
|
|
160
|
+
*/
|
|
161
|
+
ExportDataProvider: (() => Promise<Record<string, unknown>[]>) | null;
|
|
162
|
+
/** True while an export is fetching the full result set via ExportDataProvider. */
|
|
163
|
+
IsPreparingExport: boolean;
|
|
146
164
|
/** Fired when the user navigates to a different page */
|
|
147
165
|
PageChange: EventEmitter<PageChangeEvent>;
|
|
148
166
|
GridApi: GridApi | null;
|
|
@@ -218,7 +236,7 @@ export declare class QueryDataGridComponent implements OnInit, OnDestroy {
|
|
|
218
236
|
/**
|
|
219
237
|
* Opens the export dialog with current grid data
|
|
220
238
|
*/
|
|
221
|
-
OpenExportDialog(): void
|
|
239
|
+
OpenExportDialog(): Promise<void>;
|
|
222
240
|
/**
|
|
223
241
|
* Handle export dialog close
|
|
224
242
|
*/
|
|
@@ -228,9 +246,12 @@ export declare class QueryDataGridComponent implements OnInit, OnDestroy {
|
|
|
228
246
|
*/
|
|
229
247
|
Export(options?: Partial<ExportOptions>, download?: boolean): Promise<ExportResult>;
|
|
230
248
|
/**
|
|
231
|
-
*
|
|
249
|
+
* Resolves the rows to export. An explicit row selection always wins. Otherwise, if a host
|
|
250
|
+
* supplied an ExportDataProvider, the full result set is fetched (so export isn't silently
|
|
251
|
+
* capped at the current page — bug B3/C1); if it isn't supplied or the fetch yields nothing,
|
|
252
|
+
* export falls back to the loaded page (`_data`).
|
|
232
253
|
*/
|
|
233
|
-
private
|
|
254
|
+
private resolveExportData;
|
|
234
255
|
/**
|
|
235
256
|
* Get column definitions for export based on current grid columns
|
|
236
257
|
*/
|
|
@@ -259,6 +280,6 @@ export declare class QueryDataGridComponent implements OnInit, OnDestroy {
|
|
|
259
280
|
*/
|
|
260
281
|
OnRowDetailEntityLinkClick(event: RowDetailEntityLinkEvent): void;
|
|
261
282
|
static ɵfac: i0.ɵɵFactoryDeclaration<QueryDataGridComponent, never>;
|
|
262
|
-
static ɵcmp: i0.ɵɵComponentDeclaration<QueryDataGridComponent, "mj-query-data-grid", never, { "QueryInfo": { "alias": "QueryInfo"; "required": false; }; "ColumnConfigs": { "alias": "ColumnConfigs"; "required": false; }; "Data": { "alias": "Data"; "required": false; }; "SelectionMode": { "alias": "SelectionMode"; "required": false; }; "ShowToolbar": { "alias": "ShowToolbar"; "required": false; }; "ShowRowCount": { "alias": "ShowRowCount"; "required": false; }; "ShowSelectionCount": { "alias": "ShowSelectionCount"; "required": false; }; "ShowExport": { "alias": "ShowExport"; "required": false; }; "ShowRefresh": { "alias": "ShowRefresh"; "required": false; }; "AllowSorting": { "alias": "AllowSorting"; "required": false; }; "AllowColumnResize": { "alias": "AllowColumnResize"; "required": false; }; "AllowColumnReorder": { "alias": "AllowColumnReorder"; "required": false; }; "VisualConfig": { "alias": "VisualConfig"; "required": false; }; "IsLoading": { "alias": "IsLoading"; "required": false; }; "Height": { "alias": "Height"; "required": false; }; "InitialGridState": { "alias": "InitialGridState"; "required": false; }; "PersistState": { "alias": "PersistState"; "required": false; }; "TotalRowCount": { "alias": "TotalRowCount"; "required": false; }; "PageNumber": { "alias": "PageNumber"; "required": false; }; "PageSize": { "alias": "PageSize"; "required": false; }; }, { "RowClick": "RowClick"; "RowDoubleClick": "RowDoubleClick"; "EntityLinkClick": "EntityLinkClick"; "SelectionChange": "SelectionChange"; "GridStateChange": "GridStateChange"; "RefreshRequest": "RefreshRequest"; "PageChange": "PageChange"; }, never, never, false, never>;
|
|
283
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<QueryDataGridComponent, "mj-query-data-grid", never, { "QueryInfo": { "alias": "QueryInfo"; "required": false; }; "ColumnConfigs": { "alias": "ColumnConfigs"; "required": false; }; "Data": { "alias": "Data"; "required": false; }; "SelectionMode": { "alias": "SelectionMode"; "required": false; }; "ShowToolbar": { "alias": "ShowToolbar"; "required": false; }; "ShowRowCount": { "alias": "ShowRowCount"; "required": false; }; "ShowSelectionCount": { "alias": "ShowSelectionCount"; "required": false; }; "ShowExport": { "alias": "ShowExport"; "required": false; }; "ShowRefresh": { "alias": "ShowRefresh"; "required": false; }; "AllowSorting": { "alias": "AllowSorting"; "required": false; }; "AllowColumnResize": { "alias": "AllowColumnResize"; "required": false; }; "AllowColumnReorder": { "alias": "AllowColumnReorder"; "required": false; }; "VisualConfig": { "alias": "VisualConfig"; "required": false; }; "IsLoading": { "alias": "IsLoading"; "required": false; }; "Height": { "alias": "Height"; "required": false; }; "InitialGridState": { "alias": "InitialGridState"; "required": false; }; "PersistState": { "alias": "PersistState"; "required": false; }; "TotalRowCount": { "alias": "TotalRowCount"; "required": false; }; "PageNumber": { "alias": "PageNumber"; "required": false; }; "PageSize": { "alias": "PageSize"; "required": false; }; "ExportDataProvider": { "alias": "ExportDataProvider"; "required": false; }; }, { "RowClick": "RowClick"; "RowDoubleClick": "RowDoubleClick"; "EntityLinkClick": "EntityLinkClick"; "SelectionChange": "SelectionChange"; "GridStateChange": "GridStateChange"; "RefreshRequest": "RefreshRequest"; "PageChange": "PageChange"; }, never, never, false, never>;
|
|
263
284
|
}
|
|
264
285
|
//# sourceMappingURL=query-data-grid.component.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query-data-grid.component.d.ts","sourceRoot":"","sources":["../../../src/lib/query-data-grid/query-data-grid.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAIH,YAAY,EACZ,MAAM,EACN,SAAS,EACT,iBAAiB,EAEjB,UAAU,EAEb,MAAM,eAAe,CAAC;AAIvB,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAEhE,OAAO,EACH,MAAM,EACN,cAAc,EACd,eAAe,EACf,OAAO,EACP,qBAAqB,EAGrB,mBAAmB,EACnB,cAAc,EAEd,gBAAgB,IAAI,kBAAkB,EACtC,KAAK,KAAK,EACV,kBAAkB,EAClB,gBAAgB,EAChB,qBAAqB,EAErB,WAAW,EACd,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACH,aAAa,EACb,kBAAkB,EAClB,kBAAkB,EACrB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EACH,aAAa,EACb,YAAY,EAGf,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACH,sBAAsB,EACtB,qBAAqB,EACrB,kBAAkB,EAClB,cAAc,EACd,qBAAqB,EAErB,kBAAkB,EAClB,yBAAyB,EACzB,0BAA0B,EAC1B,0BAA0B,EAK7B,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,wBAAwB,EAAE,MAAM,gDAAgD,CAAC;;AAK1F;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAkBa,sBAAuB,YAAW,MAAM,EAAE,SAAS;
|
|
1
|
+
{"version":3,"file":"query-data-grid.component.d.ts","sourceRoot":"","sources":["../../../src/lib/query-data-grid/query-data-grid.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAIH,YAAY,EACZ,MAAM,EACN,SAAS,EACT,iBAAiB,EAEjB,UAAU,EAEb,MAAM,eAAe,CAAC;AAIvB,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAEhE,OAAO,EACH,MAAM,EACN,cAAc,EACd,eAAe,EACf,OAAO,EACP,qBAAqB,EAGrB,mBAAmB,EACnB,cAAc,EAEd,gBAAgB,IAAI,kBAAkB,EACtC,KAAK,KAAK,EACV,kBAAkB,EAClB,gBAAgB,EAChB,qBAAqB,EAErB,WAAW,EACd,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACH,aAAa,EACb,kBAAkB,EAClB,kBAAkB,EACrB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EACH,aAAa,EACb,YAAY,EAGf,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACH,sBAAsB,EACtB,qBAAqB,EACrB,kBAAkB,EAClB,cAAc,EACd,qBAAqB,EAErB,kBAAkB,EAClB,yBAAyB,EACzB,0BAA0B,EAC1B,0BAA0B,EAK7B,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,wBAAwB,EAAE,MAAM,gDAAgD,CAAC;;AAK1F;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAkBa,sBAAuB,YAAW,MAAM,EAAE,SAAS;IAiRxD,OAAO,CAAC,GAAG;IACX,OAAO,CAAC,UAAU;IAClB,OAAO,CAAC,aAAa;IA9QzB,OAAO,CAAC,UAAU,CAAsC;IACxD;;;OAGG;IACH,IACI,SAAS,CAAC,KAAK,EAAE,qBAAqB,GAAG,IAAI,EAUhD;IACD,IAAI,SAAS,IAAI,qBAAqB,GAAG,IAAI,CAE5C;IAED,OAAO,CAAC,cAAc,CAAwC;IAC9D;;;;;;OAMG;IACH,IACI,aAAa,CAAC,KAAK,EAAE,qBAAqB,EAAE,GAAG,IAAI,EAOtD;IACD,IAAI,aAAa,IAAI,qBAAqB,EAAE,GAAG,IAAI,CAElD;IAED,OAAO,CAAC,KAAK,CAAiC;IAE9C;;;;;OAKG;IACH,OAAO,CAAC,gBAAgB,CAAiC;IACzD,OAAO,CAAC,kBAAkB,CAAK;IAE/B;;OAEG;IACH,IACI,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAsBxC;IACD,IAAI,IAAI,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAEpC;IAED;;OAEG;IACM,aAAa,EAAE,sBAAsB,CAAc;IAE5D;;OAEG;IACM,WAAW,EAAE,OAAO,CAAQ;IAErC;;OAEG;IACM,YAAY,EAAE,OAAO,CAAQ;IAEtC;;OAEG;IACM,kBAAkB,EAAE,OAAO,CAAQ;IAE5C;;OAEG;IACM,UAAU,EAAE,OAAO,CAAQ;IAEpC;;OAEG;IACM,WAAW,EAAE,OAAO,CAAQ;IAErC;;OAEG;IACM,YAAY,EAAE,OAAO,CAAQ;IAEtC;;OAEG;IACM,iBAAiB,EAAE,OAAO,CAAQ;IAE3C;;OAEG;IACM,kBAAkB,EAAE,OAAO,CAAQ;IAE5C;;OAEG;IACM,YAAY,EAAE,qBAAqB,CAAM;IAElD;;OAEG;IACM,SAAS,EAAE,OAAO,CAAS;IAEpC;;OAEG;IACM,MAAM,EAAE,MAAM,CAAU;IAEjC;;OAEG;IACM,gBAAgB,EAAE,cAAc,GAAG,IAAI,CAAQ;IAExD;;OAEG;IACM,YAAY,EAAE,OAAO,CAAQ;IAMtC;;OAEG;IACO,QAAQ,mCAA0C;IAE5D;;OAEG;IACO,cAAc,mCAA0C;IAElE;;OAEG;IACO,eAAe,0CAAiD;IAE1E;;OAEG;IACO,eAAe,2CAAkD;IAE3E;;OAEG;IACO,eAAe,2CAAkD;IAE3E;;OAEG;IACO,cAAc,qBAA4B;IAEpD;;;OAGG;IACM,aAAa,EAAE,MAAM,CAAK;IAEnC,2DAA2D;IAClD,UAAU,EAAE,MAAM,CAAK;IAEhC,uCAAuC;IAC9B,QAAQ,EAAE,MAAM,CAAO;IAEhC;;;;;;OAMG;IACM,kBAAkB,EAAE,CAAC,MAAM,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI,CAAQ;IAEtF,mFAAmF;IAC5E,iBAAiB,EAAE,OAAO,CAAS;IAE1C,wDAAwD;IAC9C,UAAU,gCAAuC;IAMpD,OAAO,EAAE,OAAO,GAAG,IAAI,CAAQ;IAC/B,UAAU,EAAE,MAAM,EAAE,CAAM;IAC1B,OAAO,EAAE,qBAAqB,EAAE,CAAM;IACtC,SAAS,EAAE,kBAAkB,EAAE,CAAM;IACrC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAM;IAC7C,KAAK,EAAE,KAAK,CAiBhB;IAEH,OAAO,CAAC,QAAQ,CAAuB;IACvC,OAAO,CAAC,kBAAkB,CAA6C;IACvE,OAAO,CAAC,mBAAmB,CAAiC;IAC5D,OAAO,CAAC,mBAAmB,CAAgE;IAC3F,OAAO,CAAC,aAAa,CAA+B;IAG7C,WAAW,EAAE,WAAW,CAQ7B;IAEF,0DAA0D;IACnD,aAAa,EAAE,MAAM,CAI1B;gBAGU,GAAG,EAAE,iBAAiB,EACtB,UAAU,EAAE,UAAU,EACtB,aAAa,EAAE,aAAa;IAuBxC,QAAQ,IAAI,IAAI;IAKhB,WAAW,IAAI,IAAI;IAWZ,WAAW,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI;IA2B/C,OAAO,CAAC,kBAAkB;IA8B1B,OAAO,CAAC,6BAA6B;IAsBrC,OAAO,CAAC,eAAe;IAqEvB,OAAO,CAAC,YAAY;IAcpB,OAAO,CAAC,cAAc;IAYtB,OAAO,CAAC,eAAe;IAsDvB,OAAO,CAAC,oBAAoB;IAkC5B;;;OAGG;IACH,OAAO,CAAC,2BAA2B;IAyBnC,OAAO,CAAC,iBAAiB;IAwBlB,YAAY,CAAC,KAAK,EAAE,eAAe,GAAG,IAAI;IAY1C,kBAAkB,CAAC,KAAK,EAAE,qBAAqB,GAAG,IAAI;IAStD,kBAAkB,CAAC,KAAK,EAAE,qBAAqB,GAAG,IAAI;IAoBtD,aAAa,CAAC,KAAK,EAAE,kBAAkB,GAAG,IAAI;IAqB9C,eAAe,CAAC,KAAK,EAAE,kBAAkB,GAAG,IAAI;IAWhD,aAAa,CAAC,KAAK,EAAE,gBAAgB,GAAG,IAAI;IAmBnD,OAAO,CAAC,eAAe;IAKhB,YAAY,IAAI,cAAc;IAa9B,cAAc,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI;IAelD;;OAEG;IACH,OAAO,CAAC,kBAAkB;IA6B1B;;;OAGG;IACH,OAAO,CAAC,kBAAkB;IA+C1B;;OAEG;YACW,gBAAgB;IAa9B;;;;OAIG;IACI,UAAU,IAAI,IAAI;IAczB,OAAO,CAAC,iBAAiB;IAezB;;OAEG;IACI,mBAAmB,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAW9C,gBAAgB,EAAE,OAAO,CAAS;IAClC,kBAAkB,EAAE,kBAAkB,GAAG,IAAI,CAAQ;IAMrD,kBAAkB,EAAE,OAAO,CAAS;IACpC,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAQ;IACrD,cAAc,EAAE,MAAM,CAAK;IAM3B,OAAO,IAAI,IAAI;IAItB;;OAEG;IACU,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC;IA4B9C;;OAEG;IACI,oBAAoB,CAAC,MAAM,EAAE,kBAAkB,GAAG,IAAI;IAM7D;;OAEG;IACU,MAAM,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,EAAE,QAAQ,GAAE,OAAc,GAAG,OAAO,CAAC,YAAY,CAAC;IAsBtG;;;;;OAKG;YACW,iBAAiB;IAiB/B;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAUxB,OAAO,CAAC,sBAAsB;IAcvB,cAAc,IAAI,IAAI;IAUtB,eAAe,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE;IAInD,IAAW,QAAQ,IAAI,MAAM,CAE5B;IAED,IAAW,cAAc,IAAI,MAAM,CAElC;IAMM,qBAAqB,IAAI,mBAAmB,GAAG,SAAS;IAqBxD,QAAQ,GAAI,QAAQ,cAAc,KAAG,MAAM,CA2BhD;IAMF;;OAEG;IACI,kBAAkB,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAOnF;;OAEG;IACI,mBAAmB,IAAI,IAAI;IAMlC;;OAEG;IACI,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAwB1D;;OAEG;IACI,0BAA0B,CAAC,KAAK,EAAE,wBAAwB,GAAG,IAAI;yCA5oC/D,sBAAsB;2CAAtB,sBAAsB;CAupClC"}
|
|
@@ -13,16 +13,30 @@ import * as i4 from "@memberjunction/ng-shared-generic";
|
|
|
13
13
|
import * as i5 from "@memberjunction/ng-pagination";
|
|
14
14
|
import * as i6 from "@memberjunction/ng-ui-components";
|
|
15
15
|
import * as i7 from "../query-row-detail/query-row-detail.component";
|
|
16
|
+
function QueryDataGridComponent_Conditional_1_Conditional_2_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
17
|
+
i0.ɵɵtext(0);
|
|
18
|
+
i0.ɵɵpipe(1, "number");
|
|
19
|
+
i0.ɵɵpipe(2, "number");
|
|
20
|
+
} if (rf & 2) {
|
|
21
|
+
const ctx_r0 = i0.ɵɵnextContext(3);
|
|
22
|
+
i0.ɵɵtextInterpolate3(" ", i0.ɵɵpipeBind1(1, 3, ctx_r0.RowCount), " of ", i0.ɵɵpipeBind1(2, 5, ctx_r0.TotalRowCount), " ", ctx_r0.TotalRowCount === 1 ? "row" : "rows", " ");
|
|
23
|
+
} }
|
|
24
|
+
function QueryDataGridComponent_Conditional_1_Conditional_2_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
25
|
+
i0.ɵɵtext(0);
|
|
26
|
+
i0.ɵɵpipe(1, "number");
|
|
27
|
+
} if (rf & 2) {
|
|
28
|
+
const ctx_r0 = i0.ɵɵnextContext(3);
|
|
29
|
+
i0.ɵɵtextInterpolate2(" ", i0.ɵɵpipeBind1(1, 2, ctx_r0.RowCount), " ", ctx_r0.RowCount === 1 ? "row" : "rows", " ");
|
|
30
|
+
} }
|
|
16
31
|
function QueryDataGridComponent_Conditional_1_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
17
32
|
i0.ɵɵelementStart(0, "span", 10);
|
|
18
33
|
i0.ɵɵelement(1, "i", 15);
|
|
19
|
-
i0.ɵɵ
|
|
20
|
-
i0.ɵɵpipe(3, "number");
|
|
34
|
+
i0.ɵɵconditionalCreate(2, QueryDataGridComponent_Conditional_1_Conditional_2_Conditional_2_Template, 3, 7)(3, QueryDataGridComponent_Conditional_1_Conditional_2_Conditional_3_Template, 2, 4);
|
|
21
35
|
i0.ɵɵelementEnd();
|
|
22
36
|
} if (rf & 2) {
|
|
23
37
|
const ctx_r0 = i0.ɵɵnextContext(2);
|
|
24
38
|
i0.ɵɵadvance(2);
|
|
25
|
-
i0.ɵɵ
|
|
39
|
+
i0.ɵɵconditional(ctx_r0.TotalRowCount > ctx_r0.RowCount ? 2 : 3);
|
|
26
40
|
} }
|
|
27
41
|
function QueryDataGridComponent_Conditional_1_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
28
42
|
const _r2 = i0.ɵɵgetCurrentView();
|
|
@@ -60,16 +74,18 @@ function QueryDataGridComponent_Conditional_1_Conditional_6_Template(rf, ctx) {
|
|
|
60
74
|
i0.ɵɵelementEnd()();
|
|
61
75
|
} if (rf & 2) {
|
|
62
76
|
const ctx_r0 = i0.ɵɵnextContext(2);
|
|
63
|
-
i0.ɵɵproperty("disabled", ctx_r0.RowCount === 0);
|
|
77
|
+
i0.ɵɵproperty("disabled", ctx_r0.RowCount === 0 || ctx_r0.IsPreparingExport);
|
|
78
|
+
i0.ɵɵadvance();
|
|
79
|
+
i0.ɵɵclassProp("fa-file-export", !ctx_r0.IsPreparingExport)("fa-spinner", ctx_r0.IsPreparingExport)("fa-spin", ctx_r0.IsPreparingExport);
|
|
64
80
|
} }
|
|
65
81
|
function QueryDataGridComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
66
82
|
i0.ɵɵelementStart(0, "div", 1)(1, "div", 9);
|
|
67
|
-
i0.ɵɵconditionalCreate(2, QueryDataGridComponent_Conditional_1_Conditional_2_Template, 4,
|
|
83
|
+
i0.ɵɵconditionalCreate(2, QueryDataGridComponent_Conditional_1_Conditional_2_Template, 4, 1, "span", 10);
|
|
68
84
|
i0.ɵɵconditionalCreate(3, QueryDataGridComponent_Conditional_1_Conditional_3_Template, 5, 1, "span", 11);
|
|
69
85
|
i0.ɵɵelementEnd();
|
|
70
86
|
i0.ɵɵelementStart(4, "div", 12);
|
|
71
87
|
i0.ɵɵconditionalCreate(5, QueryDataGridComponent_Conditional_1_Conditional_5_Template, 2, 3, "button", 13);
|
|
72
|
-
i0.ɵɵconditionalCreate(6, QueryDataGridComponent_Conditional_1_Conditional_6_Template, 4,
|
|
88
|
+
i0.ɵɵconditionalCreate(6, QueryDataGridComponent_Conditional_1_Conditional_6_Template, 4, 7, "button", 14);
|
|
73
89
|
i0.ɵɵelementEnd()();
|
|
74
90
|
} if (rf & 2) {
|
|
75
91
|
const ctx_r0 = i0.ɵɵnextContext();
|
|
@@ -171,11 +187,27 @@ export class QueryDataGridComponent {
|
|
|
171
187
|
return this._columnConfigs;
|
|
172
188
|
}
|
|
173
189
|
_data = [];
|
|
190
|
+
/**
|
|
191
|
+
* Per-row synthetic identity for rows that have no natural key column, so the
|
|
192
|
+
* `getRowId` fallback can never return duplicate ids (ag-Grid silently merges
|
|
193
|
+
* rows that share an id). Keyed by the row object reference; entries are added
|
|
194
|
+
* as Data is assigned. A WeakMap so it never retains rows past their lifetime.
|
|
195
|
+
*/
|
|
196
|
+
_syntheticRowIds = new WeakMap();
|
|
197
|
+
_syntheticRowIdSeq = 0;
|
|
174
198
|
/**
|
|
175
199
|
* The query result data to display in the grid.
|
|
176
200
|
*/
|
|
177
201
|
set Data(value) {
|
|
178
202
|
this._data = value || [];
|
|
203
|
+
// Assign a stable synthetic id to each row up front, so the getRowId
|
|
204
|
+
// fallback (used only when a row has no natural key column) is
|
|
205
|
+
// collision-proof — rows with identical column values must NOT be merged.
|
|
206
|
+
for (const row of this._data) {
|
|
207
|
+
if (row && !this._syntheticRowIds.has(row)) {
|
|
208
|
+
this._syntheticRowIds.set(row, `mjrow_${this._syntheticRowIdSeq++}`);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
179
211
|
// If we have data but no columns from metadata or explicit configs, build from data
|
|
180
212
|
if (this._data.length > 0 && this.Columns.length === 0 && !this._columnConfigs) {
|
|
181
213
|
this.Columns = buildColumnsFromData(this._data);
|
|
@@ -281,6 +313,16 @@ export class QueryDataGridComponent {
|
|
|
281
313
|
PageNumber = 1;
|
|
282
314
|
/** Page size for server-side paging */
|
|
283
315
|
PageSize = 100;
|
|
316
|
+
/**
|
|
317
|
+
* Optional provider that returns the FULL result set for export. When the grid is server-side
|
|
318
|
+
* paged, `Data` only holds the current page (default 100 rows), so exporting `Data` would silently
|
|
319
|
+
* cap the export at the page size (bug B3/C1). A host that owns the query (with its parameters) can
|
|
320
|
+
* supply this callback to fetch every matching row on demand; the grid awaits it when the user
|
|
321
|
+
* exports without an explicit row selection. When not provided, export falls back to the loaded page.
|
|
322
|
+
*/
|
|
323
|
+
ExportDataProvider = null;
|
|
324
|
+
/** True while an export is fetching the full result set via ExportDataProvider. */
|
|
325
|
+
IsPreparingExport = false;
|
|
284
326
|
/** Fired when the user navigates to a different page */
|
|
285
327
|
PageChange = new EventEmitter();
|
|
286
328
|
// ========================================
|
|
@@ -875,10 +917,18 @@ export class QueryDataGridComponent {
|
|
|
875
917
|
/**
|
|
876
918
|
* Opens the export dialog with current grid data
|
|
877
919
|
*/
|
|
878
|
-
OpenExportDialog() {
|
|
920
|
+
async OpenExportDialog() {
|
|
879
921
|
if (!this._data.length)
|
|
880
922
|
return;
|
|
881
|
-
|
|
923
|
+
this.IsPreparingExport = true;
|
|
924
|
+
this.cdr.detectChanges();
|
|
925
|
+
let data;
|
|
926
|
+
try {
|
|
927
|
+
data = await this.resolveExportData();
|
|
928
|
+
}
|
|
929
|
+
finally {
|
|
930
|
+
this.IsPreparingExport = false;
|
|
931
|
+
}
|
|
882
932
|
const columns = this.getExportColumns();
|
|
883
933
|
const fileName = this._queryInfo?.Name || 'query-export';
|
|
884
934
|
this.ExportDialogConfig = {
|
|
@@ -906,7 +956,7 @@ export class QueryDataGridComponent {
|
|
|
906
956
|
* Export grid data directly without showing dialog
|
|
907
957
|
*/
|
|
908
958
|
async Export(options, download = true) {
|
|
909
|
-
const data = this.
|
|
959
|
+
const data = await this.resolveExportData();
|
|
910
960
|
const columns = this.getExportColumns();
|
|
911
961
|
const fileName = options?.fileName || this._queryInfo?.Name || 'query-export';
|
|
912
962
|
const exportOptions = {
|
|
@@ -923,12 +973,27 @@ export class QueryDataGridComponent {
|
|
|
923
973
|
return result;
|
|
924
974
|
}
|
|
925
975
|
/**
|
|
926
|
-
*
|
|
976
|
+
* Resolves the rows to export. An explicit row selection always wins. Otherwise, if a host
|
|
977
|
+
* supplied an ExportDataProvider, the full result set is fetched (so export isn't silently
|
|
978
|
+
* capped at the current page — bug B3/C1); if it isn't supplied or the fetch yields nothing,
|
|
979
|
+
* export falls back to the loaded page (`_data`).
|
|
927
980
|
*/
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
981
|
+
async resolveExportData() {
|
|
982
|
+
if (this.SelectedRows.length > 0) {
|
|
983
|
+
return this.SelectedRows;
|
|
984
|
+
}
|
|
985
|
+
if (this.ExportDataProvider) {
|
|
986
|
+
try {
|
|
987
|
+
const allRows = await this.ExportDataProvider();
|
|
988
|
+
if (allRows && allRows.length > 0) {
|
|
989
|
+
return allRows;
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
catch {
|
|
993
|
+
// Fall through to the loaded page on any fetch failure.
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
return this._data;
|
|
932
997
|
}
|
|
933
998
|
/**
|
|
934
999
|
* Get column definitions for export based on current grid columns
|
|
@@ -994,22 +1059,31 @@ export class QueryDataGridComponent {
|
|
|
994
1059
|
};
|
|
995
1060
|
}
|
|
996
1061
|
GetRowId = (params) => {
|
|
997
|
-
// Use data index as ID since query results don't have a guaranteed unique key
|
|
998
|
-
// We use JSON stringify on a subset of the data to create a deterministic key
|
|
999
1062
|
const data = params.data;
|
|
1000
1063
|
if (!data)
|
|
1001
|
-
return
|
|
1002
|
-
//
|
|
1003
|
-
//
|
|
1064
|
+
return `mjrow_${this._syntheticRowIdSeq++}`;
|
|
1065
|
+
// Prefer a natural unique key when the result exposes one — this keeps row
|
|
1066
|
+
// identity (and selection) stable across data refreshes.
|
|
1004
1067
|
const idFields = ['ID', 'Id', 'id', 'RowNumber', 'RowNum', '__row_index'];
|
|
1005
1068
|
for (const field of idFields) {
|
|
1006
1069
|
if (data[field] !== undefined && data[field] !== null) {
|
|
1007
1070
|
return String(data[field]);
|
|
1008
1071
|
}
|
|
1009
1072
|
}
|
|
1010
|
-
//
|
|
1011
|
-
|
|
1012
|
-
|
|
1073
|
+
// No natural key — use the per-row synthetic id assigned when Data was set.
|
|
1074
|
+
// The previous fallback hashed only the first 3 columns, so any rows that
|
|
1075
|
+
// matched on those columns collided to the same id and ag-Grid dropped all
|
|
1076
|
+
// but one (silently collapsing aggregate/GROUP BY results, or any query
|
|
1077
|
+
// without an ID column). A per-row synthetic id can never collide.
|
|
1078
|
+
// Trade-off: the id is per-object (not value-derived), so an id-less row
|
|
1079
|
+
// loses its selection across a data refresh — acceptable for query results,
|
|
1080
|
+
// where NOT dropping rows matters far more than preserving a selection.
|
|
1081
|
+
let synthetic = this._syntheticRowIds.get(data);
|
|
1082
|
+
if (!synthetic) {
|
|
1083
|
+
synthetic = `mjrow_${this._syntheticRowIdSeq++}`;
|
|
1084
|
+
this._syntheticRowIds.set(data, synthetic);
|
|
1085
|
+
}
|
|
1086
|
+
return synthetic;
|
|
1013
1087
|
};
|
|
1014
1088
|
// ========================================
|
|
1015
1089
|
// Row Detail Panel
|
|
@@ -1070,7 +1144,7 @@ export class QueryDataGridComponent {
|
|
|
1070
1144
|
});
|
|
1071
1145
|
}
|
|
1072
1146
|
static ɵfac = function QueryDataGridComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || QueryDataGridComponent)(i0.ɵɵdirectiveInject(i0.ChangeDetectorRef), i0.ɵɵdirectiveInject(i0.ElementRef), i0.ɵɵdirectiveInject(i1.ExportService)); };
|
|
1073
|
-
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: QueryDataGridComponent, selectors: [["mj-query-data-grid"]], inputs: { QueryInfo: "QueryInfo", ColumnConfigs: "ColumnConfigs", Data: "Data", SelectionMode: "SelectionMode", ShowToolbar: "ShowToolbar", ShowRowCount: "ShowRowCount", ShowSelectionCount: "ShowSelectionCount", ShowExport: "ShowExport", ShowRefresh: "ShowRefresh", AllowSorting: "AllowSorting", AllowColumnResize: "AllowColumnResize", AllowColumnReorder: "AllowColumnReorder", VisualConfig: "VisualConfig", IsLoading: "IsLoading", Height: "Height", InitialGridState: "InitialGridState", PersistState: "PersistState", TotalRowCount: "TotalRowCount", PageNumber: "PageNumber", PageSize: "PageSize" }, outputs: { RowClick: "RowClick", RowDoubleClick: "RowDoubleClick", EntityLinkClick: "EntityLinkClick", SelectionChange: "SelectionChange", GridStateChange: "GridStateChange", RefreshRequest: "RefreshRequest", PageChange: "PageChange" }, standalone: false, decls: 9, vars: 24, consts: [[1, "query-data-grid-container", 3, "ngClass"], [1, "grid-toolbar"], [1, "loading-overlay"], [1, "grid-wrapper"], [1, "query-grid", 3, "gridReady", "rowClicked", "rowDoubleClicked", "selectionChanged", "sortChanged", "columnResized", "columnMoved", "theme", "rowData", "columnDefs", "defaultColDef", "gridOptions", "rowSelection", "getRowId"], [3, "TotalRowCount", "PageNumber", "PageSize", "IsLoading"], ["Icon", "fa-solid fa-database", "Title", "No results", "Message", "Run the query to see results", 1, "empty-state"], [3, "closed", "visible", "config"], [3, "Close", "EntityLinkClick", "NavigateRow", "RowData", "Columns", "QueryInfo", "Visible", "RowIndex", "TotalRows"], [1, "toolbar-left"], [1, "row-count"], [1, "selection-count"], [1, "toolbar-right"], ["title", "Refresh data", 1, "toolbar-btn", "icon-only", 3, "disabled"], ["title", "Export data", 1, "toolbar-btn", 3, "disabled"], [1, "fa-solid", "fa-table-list"], [1, "fa-solid", "fa-check-square"], ["title", "Clear selection", 1, "clear-selection-btn", 3, "click"], [1, "fa-solid", "fa-times"], ["title", "Refresh data", 1, "toolbar-btn", "icon-only", 3, "click", "disabled"], [1, "fa-solid", "fa-sync-alt"], ["title", "Export data", 1, "toolbar-btn", 3, "click", "disabled"], [1, "fa-solid"
|
|
1147
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: QueryDataGridComponent, selectors: [["mj-query-data-grid"]], inputs: { QueryInfo: "QueryInfo", ColumnConfigs: "ColumnConfigs", Data: "Data", SelectionMode: "SelectionMode", ShowToolbar: "ShowToolbar", ShowRowCount: "ShowRowCount", ShowSelectionCount: "ShowSelectionCount", ShowExport: "ShowExport", ShowRefresh: "ShowRefresh", AllowSorting: "AllowSorting", AllowColumnResize: "AllowColumnResize", AllowColumnReorder: "AllowColumnReorder", VisualConfig: "VisualConfig", IsLoading: "IsLoading", Height: "Height", InitialGridState: "InitialGridState", PersistState: "PersistState", TotalRowCount: "TotalRowCount", PageNumber: "PageNumber", PageSize: "PageSize", ExportDataProvider: "ExportDataProvider" }, outputs: { RowClick: "RowClick", RowDoubleClick: "RowDoubleClick", EntityLinkClick: "EntityLinkClick", SelectionChange: "SelectionChange", GridStateChange: "GridStateChange", RefreshRequest: "RefreshRequest", PageChange: "PageChange" }, standalone: false, decls: 9, vars: 24, consts: [[1, "query-data-grid-container", 3, "ngClass"], [1, "grid-toolbar"], [1, "loading-overlay"], [1, "grid-wrapper"], [1, "query-grid", 3, "gridReady", "rowClicked", "rowDoubleClicked", "selectionChanged", "sortChanged", "columnResized", "columnMoved", "theme", "rowData", "columnDefs", "defaultColDef", "gridOptions", "rowSelection", "getRowId"], [3, "TotalRowCount", "PageNumber", "PageSize", "IsLoading"], ["Icon", "fa-solid fa-database", "Title", "No results", "Message", "Run the query to see results", 1, "empty-state"], [3, "closed", "visible", "config"], [3, "Close", "EntityLinkClick", "NavigateRow", "RowData", "Columns", "QueryInfo", "Visible", "RowIndex", "TotalRows"], [1, "toolbar-left"], [1, "row-count"], [1, "selection-count"], [1, "toolbar-right"], ["title", "Refresh data", 1, "toolbar-btn", "icon-only", 3, "disabled"], ["title", "Export data", 1, "toolbar-btn", 3, "disabled"], [1, "fa-solid", "fa-table-list"], [1, "fa-solid", "fa-check-square"], ["title", "Clear selection", 1, "clear-selection-btn", 3, "click"], [1, "fa-solid", "fa-times"], ["title", "Refresh data", 1, "toolbar-btn", "icon-only", 3, "click", "disabled"], [1, "fa-solid", "fa-sync-alt"], ["title", "Export data", 1, "toolbar-btn", 3, "click", "disabled"], [1, "fa-solid"], [1, "button-text"], ["text", "Loading query results..."], [3, "PageChange", "TotalRowCount", "PageNumber", "PageSize", "IsLoading"]], template: function QueryDataGridComponent_Template(rf, ctx) { if (rf & 1) {
|
|
1074
1148
|
i0.ɵɵelementStart(0, "div", 0);
|
|
1075
1149
|
i0.ɵɵconditionalCreate(1, QueryDataGridComponent_Conditional_1_Template, 7, 4, "div", 1);
|
|
1076
1150
|
i0.ɵɵconditionalCreate(2, QueryDataGridComponent_Conditional_2_Template, 2, 1, "div", 2);
|
|
@@ -1129,7 +1203,7 @@ export class QueryDataGridComponent {
|
|
|
1129
1203
|
animate('100ms ease-in', style({ opacity: 0, transform: 'translateY(-8px)' }))
|
|
1130
1204
|
])
|
|
1131
1205
|
])
|
|
1132
|
-
], template: "<!-- Query Data Grid Component -->\n<div class=\"query-data-grid-container\" [ngClass]=\"GetContainerClasses()\" [style.height]=\"Height\">\n <!-- Toolbar -->\n @if (ShowToolbar) {\n <div class=\"grid-toolbar\">\n <div class=\"toolbar-left\">\n <!-- Row count -->\n @if (ShowRowCount) {\n <span class=\"row-count\">\n <i class=\"fa-solid fa-table-list\"></i>\n {{ RowCount | number }} {{ RowCount === 1 ? 'row' : 'rows' }}\n </span>\n }\n <!-- Selection count -->\n @if (ShowSelectionCount && SelectionCount > 0) {\n <span class=\"selection-count\">\n <i class=\"fa-solid fa-check-square\"></i>\n {{ SelectionCount }} selected\n <button class=\"clear-selection-btn\" (click)=\"ClearSelection()\" title=\"Clear selection\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </span>\n }\n </div>\n <div class=\"toolbar-right\">\n <!-- Refresh button -->\n @if (ShowRefresh) {\n <button\n (click)=\"Refresh()\"\n [disabled]=\"IsLoading\"\n title=\"Refresh data\"\n class=\"toolbar-btn icon-only\">\n <i class=\"fa-solid fa-sync-alt\" [class.fa-spin]=\"IsLoading\"></i>\n </button>\n }\n <!-- Export button -->\n @if (ShowExport) {\n <button\n [disabled]=\"RowCount === 0\"\n title=\"Export data\"\n class=\"toolbar-btn\"\n (click)=\"OpenExportDialog()\">\n <i class=\"fa-solid fa-file-export\"></i>\n <span class=\"button-text\">Export</span>\n </button>\n }\n </div>\n </div>\n }\n\n <!-- Loading overlay -->\n @if (IsLoading) {\n <div class=\"loading-overlay\" @fadeIn>\n <mj-loading text=\"Loading query results...\"></mj-loading>\n </div>\n }\n\n <!-- AG Grid -->\n <div class=\"grid-wrapper\" [class.loading]=\"IsLoading\">\n <ag-grid-angular\n class=\"query-grid\"\n [theme]=\"Theme\"\n [rowData]=\"Data\"\n [columnDefs]=\"ColumnDefs\"\n [defaultColDef]=\"DefaultColDef\"\n [gridOptions]=\"GridOptions\"\n [rowSelection]=\"GetRowSelectionConfig()\"\n [getRowId]=\"GetRowId\"\n (gridReady)=\"OnGridReady($event)\"\n (rowClicked)=\"OnRowClicked($event)\"\n (rowDoubleClicked)=\"OnRowDoubleClicked($event)\"\n (selectionChanged)=\"OnSelectionChanged($event)\"\n (sortChanged)=\"OnSortChanged($event)\"\n (columnResized)=\"OnColumnResized($event)\"\n (columnMoved)=\"OnColumnMoved($event)\">\n </ag-grid-angular>\n </div>\n\n <!-- Pagination (only shown when server-side paging is active) -->\n @if (TotalRowCount > 0) {\n <mj-pagination\n [TotalRowCount]=\"TotalRowCount\"\n [PageNumber]=\"PageNumber\"\n [PageSize]=\"PageSize\"\n [IsLoading]=\"IsLoading\"\n (PageChange)=\"PageChange.emit($event)\">\n </mj-pagination>\n }\n\n <!-- Empty state -->\n @if (!IsLoading && RowCount === 0) {\n <mj-empty-state\n class=\"empty-state\"\n @fadeIn\n Icon=\"fa-solid fa-database\"\n Title=\"No results\"\n Message=\"Run the query to see results\" />\n }\n</div>\n\n<!-- Export Dialog -->\n<mj-export-dialog\n [visible]=\"ShowExportDialog\"\n [config]=\"ExportDialogConfig\"\n (closed)=\"OnExportDialogClosed($event)\">\n</mj-export-dialog>\n\n<!-- Row Detail Panel -->\n<mj-query-row-detail\n [RowData]=\"RowDetailData\"\n [Columns]=\"Columns\"\n [QueryInfo]=\"QueryInfo\"\n [Visible]=\"ShowRowDetailPanel\"\n [RowIndex]=\"RowDetailIndex\"\n [TotalRows]=\"RowCount\"\n (Close)=\"CloseRowDetailPanel()\"\n (EntityLinkClick)=\"OnRowDetailEntityLinkClick($event)\"\n (NavigateRow)=\"NavigateRowDetail($event)\">\n</mj-query-row-detail>\n", styles: ["/* Query Data Grid Component Styles */\n\n:host {\n display: block;\n height: 100%;\n --grid-accent-color: var(--mj-brand-primary);\n --grid-selection-indicator: var(--mj-status-warning);\n --grid-selection-bg: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n --grid-sort-indicator-color: var(--mj-brand-primary);\n}\n\n.query-data-grid-container {\n display: flex;\n flex-direction: column;\n height: 100%;\n position: relative;\n background: var(--mj-bg-surface);\n border-radius: 4px;\n overflow: hidden;\n}\n\n/* ========================================\n Toolbar\n ======================================== */\n\n.grid-toolbar {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 8px 12px;\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n min-height: 48px;\n flex-shrink: 0;\n}\n\n.toolbar-left,\n.toolbar-right {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.row-count,\n.selection-count {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 13px;\n color: var(--mj-text-secondary);\n font-weight: 500;\n}\n\n.row-count i,\n.selection-count i {\n color: var(--mj-text-muted);\n}\n\n.selection-count {\n padding: 4px 8px;\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-text-primary);\n border-radius: 4px;\n border-left: 3px solid var(--mj-brand-primary);\n}\n\n.clear-selection-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 18px;\n height: 18px;\n padding: 0;\n margin-left: 4px;\n border: none;\n background: transparent;\n color: var(--mj-text-muted);\n cursor: pointer;\n border-radius: 50%;\n transition: all 0.15s ease;\n}\n\n.clear-selection-btn:hover {\n background: color-mix(in srgb, var(--mj-text-primary) 10%, transparent);\n color: var(--mj-text-primary);\n}\n\n/* Toolbar buttons - consistent styling */\n.toolbar-btn {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 6px 12px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 4px;\n cursor: pointer;\n font-size: 13px;\n color: var(--mj-text-primary);\n transition: background-color 0.2s, border-color 0.2s;\n}\n\n.toolbar-btn:hover:not(:disabled) {\n background: var(--mj-bg-surface-sunken);\n border-color: var(--mj-border-strong);\n}\n\n.toolbar-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.toolbar-btn i {\n font-size: 14px;\n}\n\n/* Icon-only button */\n.toolbar-btn.icon-only {\n padding: 6px 8px;\n}\n\n.toolbar-btn.icon-only i {\n margin-right: 0;\n}\n\n/* ========================================\n Grid wrapper\n ======================================== */\n\n.grid-wrapper {\n flex: 1;\n min-height: 0;\n position: relative;\n transition: opacity 0.2s ease;\n}\n\n.grid-wrapper.loading {\n opacity: 0.5;\n pointer-events: none;\n}\n\n.query-grid {\n width: 100%;\n height: 100%;\n}\n\n/* ========================================\n Loading overlay\n ======================================== */\n\n.loading-overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--mj-bg-overlay);\n z-index: 100;\n}\n\n/* ========================================\n Empty state\n ======================================== */\n\n/* Absolute-center the empty state over the grid; mj-empty-state owns its content. */\n.empty-state {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n}\n\n/* ========================================\n Entity link cell\n ======================================== */\n\n::ng-deep .entity-link-cell {\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n::ng-deep .entity-link {\n color: var(--grid-accent-color);\n text-decoration: none;\n cursor: pointer;\n transition: color 0.15s ease;\n}\n\n::ng-deep .entity-link:hover {\n color: var(--mj-brand-primary-hover);\n text-decoration: underline;\n}\n\n::ng-deep .entity-link-icon {\n font-size: 10px;\n color: var(--mj-text-disabled);\n opacity: 0;\n transition: opacity 0.15s ease;\n}\n\n::ng-deep .entity-link-cell:hover .entity-link-icon {\n opacity: 1;\n}\n\n/* ========================================\n AG Grid customizations\n ======================================== */\n\n/* ========================================\n Visual Config: Zebra Striping\n (copied from entity-data-grid pattern)\n ======================================== */\n\n/* Subtle contrast */\n.alternate-rows-subtle ::ng-deep .ag-row-odd {\n background-color: color-mix(in srgb, var(--mj-text-primary) 1.5%, transparent);\n}\n\n.alternate-rows-subtle ::ng-deep .ag-row-odd:hover:not(.ag-row-selected) {\n background-color: var(--mj-bg-surface-hover);\n}\n\n/* Medium contrast (default) */\n.alternate-rows-medium ::ng-deep .ag-row-odd {\n background-color: color-mix(in srgb, var(--mj-text-primary) 2.5%, transparent);\n}\n\n.alternate-rows-medium ::ng-deep .ag-row-odd:hover:not(.ag-row-selected) {\n background-color: var(--mj-bg-surface-hover);\n}\n\n/* Strong contrast */\n.alternate-rows-strong ::ng-deep .ag-row-odd {\n background-color: color-mix(in srgb, var(--mj-text-primary) 4%, transparent);\n}\n\n.alternate-rows-strong ::ng-deep .ag-row-odd:hover:not(.ag-row-selected) {\n background-color: var(--mj-bg-surface-hover);\n}\n\n::ng-deep .ag-header-cell {\n font-weight: 600;\n font-size: 12px;\n text-transform: uppercase;\n letter-spacing: 0.3px;\n color: var(--mj-text-secondary);\n}\n\n::ng-deep .ag-header-cell:hover {\n background-color: color-mix(in srgb, var(--mj-text-primary) 4%, transparent);\n}\n\n/* Selected row styling */\n::ng-deep .ag-row-selected {\n background-color: var(--grid-selection-bg) !important;\n color: var(--mj-text-primary) !important;\n box-shadow: inset 4px 0 0 0 var(--grid-selection-indicator);\n}\n\n::ng-deep .ag-row-selected .ag-cell {\n color: var(--mj-text-primary) !important;\n}\n\n/* Row border */\n::ng-deep .ag-row {\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n\n/* Header alignment */\n::ng-deep .header-right .ag-header-cell-label {\n justify-content: flex-end;\n}\n\n::ng-deep .header-center .ag-header-cell-label {\n justify-content: center;\n}\n\n/* Checkbox styling */\n::ng-deep .ag-checkbox-input-wrapper {\n border-radius: 4px;\n width: 18px;\n height: 18px;\n}\n\n::ng-deep .ag-checkbox-input-wrapper.ag-checked {\n background-color: var(--grid-accent-color);\n border-color: var(--grid-accent-color);\n}\n\n::ng-deep .ag-checkbox-input-wrapper.ag-checked::after {\n color: var(--mj-text-inverse);\n}\n\n/* ========================================\n Sort Indicators - Arrow Only\n ======================================== */\n\n/* Sort icons - colored arrows only */\n:host ::ng-deep .ag-sort-ascending-icon {\n color: var(--mj-brand-primary) !important;\n}\n\n:host ::ng-deep .ag-sort-descending-icon {\n color: var(--mj-status-error) !important;\n}\n\n:host ::ng-deep .ag-sort-ascending-icon .ag-icon,\n:host ::ng-deep .ag-sort-descending-icon .ag-icon {\n font-size: 14px !important;\n}\n\n/* Sort order number (for multi-sort) */\n:host ::ng-deep .ag-sort-order {\n margin-left: 4px;\n font-size: 11px !important;\n font-weight: 700 !important;\n color: var(--mj-text-secondary) !important;\n}\n\n/* Hover state for sortable headers */\n:host ::ng-deep .ag-header-cell-sortable:hover {\n background: color-mix(in srgb, var(--mj-text-primary) 4%, transparent);\n}\n\n/* ========================================\n Scrollbar Styling\n ======================================== */\n\n::ng-deep .ag-body-viewport::-webkit-scrollbar {\n width: 8px;\n height: 8px;\n}\n\n::ng-deep .ag-body-viewport::-webkit-scrollbar-track {\n background: var(--mj-bg-surface-card);\n border-radius: 4px;\n}\n\n::ng-deep .ag-body-viewport::-webkit-scrollbar-thumb {\n background: var(--mj-border-strong);\n border-radius: 4px;\n}\n\n::ng-deep .ag-body-viewport::-webkit-scrollbar-thumb:hover {\n background: var(--mj-text-disabled);\n}\n\n/* ========================================\n Responsive adjustments\n ======================================== */\n\n@media (max-width: 768px) {\n .grid-toolbar {\n flex-wrap: wrap;\n gap: 8px;\n }\n\n .toolbar-left,\n .toolbar-right {\n flex-wrap: wrap;\n }\n\n /* Hide button text on mobile */\n .toolbar-btn .button-text {\n display: none;\n }\n}\n"] }]
|
|
1206
|
+
], template: "<!-- Query Data Grid Component -->\n<div class=\"query-data-grid-container\" [ngClass]=\"GetContainerClasses()\" [style.height]=\"Height\">\n <!-- Toolbar -->\n @if (ShowToolbar) {\n <div class=\"grid-toolbar\">\n <div class=\"toolbar-left\">\n <!-- Row count -->\n @if (ShowRowCount) {\n <span class=\"row-count\">\n <i class=\"fa-solid fa-table-list\"></i>\n @if (TotalRowCount > RowCount) {\n {{ RowCount | number }} of {{ TotalRowCount | number }} {{ TotalRowCount === 1 ? 'row' : 'rows' }}\n } @else {\n {{ RowCount | number }} {{ RowCount === 1 ? 'row' : 'rows' }}\n }\n </span>\n }\n <!-- Selection count -->\n @if (ShowSelectionCount && SelectionCount > 0) {\n <span class=\"selection-count\">\n <i class=\"fa-solid fa-check-square\"></i>\n {{ SelectionCount }} selected\n <button class=\"clear-selection-btn\" (click)=\"ClearSelection()\" title=\"Clear selection\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </span>\n }\n </div>\n <div class=\"toolbar-right\">\n <!-- Refresh button -->\n @if (ShowRefresh) {\n <button\n (click)=\"Refresh()\"\n [disabled]=\"IsLoading\"\n title=\"Refresh data\"\n class=\"toolbar-btn icon-only\">\n <i class=\"fa-solid fa-sync-alt\" [class.fa-spin]=\"IsLoading\"></i>\n </button>\n }\n <!-- Export button -->\n @if (ShowExport) {\n <button\n [disabled]=\"RowCount === 0 || IsPreparingExport\"\n title=\"Export data\"\n class=\"toolbar-btn\"\n (click)=\"OpenExportDialog()\">\n <i class=\"fa-solid\" [class.fa-file-export]=\"!IsPreparingExport\" [class.fa-spinner]=\"IsPreparingExport\" [class.fa-spin]=\"IsPreparingExport\"></i>\n <span class=\"button-text\">Export</span>\n </button>\n }\n </div>\n </div>\n }\n\n <!-- Loading overlay -->\n @if (IsLoading) {\n <div class=\"loading-overlay\" @fadeIn>\n <mj-loading text=\"Loading query results...\"></mj-loading>\n </div>\n }\n\n <!-- AG Grid -->\n <div class=\"grid-wrapper\" [class.loading]=\"IsLoading\">\n <ag-grid-angular\n class=\"query-grid\"\n [theme]=\"Theme\"\n [rowData]=\"Data\"\n [columnDefs]=\"ColumnDefs\"\n [defaultColDef]=\"DefaultColDef\"\n [gridOptions]=\"GridOptions\"\n [rowSelection]=\"GetRowSelectionConfig()\"\n [getRowId]=\"GetRowId\"\n (gridReady)=\"OnGridReady($event)\"\n (rowClicked)=\"OnRowClicked($event)\"\n (rowDoubleClicked)=\"OnRowDoubleClicked($event)\"\n (selectionChanged)=\"OnSelectionChanged($event)\"\n (sortChanged)=\"OnSortChanged($event)\"\n (columnResized)=\"OnColumnResized($event)\"\n (columnMoved)=\"OnColumnMoved($event)\">\n </ag-grid-angular>\n </div>\n\n <!-- Pagination (only shown when server-side paging is active) -->\n @if (TotalRowCount > 0) {\n <mj-pagination\n [TotalRowCount]=\"TotalRowCount\"\n [PageNumber]=\"PageNumber\"\n [PageSize]=\"PageSize\"\n [IsLoading]=\"IsLoading\"\n (PageChange)=\"PageChange.emit($event)\">\n </mj-pagination>\n }\n\n <!-- Empty state -->\n @if (!IsLoading && RowCount === 0) {\n <mj-empty-state\n class=\"empty-state\"\n @fadeIn\n Icon=\"fa-solid fa-database\"\n Title=\"No results\"\n Message=\"Run the query to see results\" />\n }\n</div>\n\n<!-- Export Dialog -->\n<mj-export-dialog\n [visible]=\"ShowExportDialog\"\n [config]=\"ExportDialogConfig\"\n (closed)=\"OnExportDialogClosed($event)\">\n</mj-export-dialog>\n\n<!-- Row Detail Panel -->\n<mj-query-row-detail\n [RowData]=\"RowDetailData\"\n [Columns]=\"Columns\"\n [QueryInfo]=\"QueryInfo\"\n [Visible]=\"ShowRowDetailPanel\"\n [RowIndex]=\"RowDetailIndex\"\n [TotalRows]=\"RowCount\"\n (Close)=\"CloseRowDetailPanel()\"\n (EntityLinkClick)=\"OnRowDetailEntityLinkClick($event)\"\n (NavigateRow)=\"NavigateRowDetail($event)\">\n</mj-query-row-detail>\n", styles: ["/* Query Data Grid Component Styles */\n\n:host {\n display: block;\n height: 100%;\n --grid-accent-color: var(--mj-brand-primary);\n --grid-selection-indicator: var(--mj-status-warning);\n --grid-selection-bg: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n --grid-sort-indicator-color: var(--mj-brand-primary);\n}\n\n.query-data-grid-container {\n display: flex;\n flex-direction: column;\n height: 100%;\n position: relative;\n background: var(--mj-bg-surface);\n border-radius: 4px;\n overflow: hidden;\n}\n\n/* ========================================\n Toolbar\n ======================================== */\n\n.grid-toolbar {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 8px 12px;\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n min-height: 48px;\n flex-shrink: 0;\n}\n\n.toolbar-left,\n.toolbar-right {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.row-count,\n.selection-count {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 13px;\n color: var(--mj-text-secondary);\n font-weight: 500;\n}\n\n.row-count i,\n.selection-count i {\n color: var(--mj-text-muted);\n}\n\n.selection-count {\n padding: 4px 8px;\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-text-primary);\n border-radius: 4px;\n border-left: 3px solid var(--mj-brand-primary);\n}\n\n.clear-selection-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 18px;\n height: 18px;\n padding: 0;\n margin-left: 4px;\n border: none;\n background: transparent;\n color: var(--mj-text-muted);\n cursor: pointer;\n border-radius: 50%;\n transition: all 0.15s ease;\n}\n\n.clear-selection-btn:hover {\n background: color-mix(in srgb, var(--mj-text-primary) 10%, transparent);\n color: var(--mj-text-primary);\n}\n\n/* Toolbar buttons - consistent styling */\n.toolbar-btn {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 6px 12px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 4px;\n cursor: pointer;\n font-size: 13px;\n color: var(--mj-text-primary);\n transition: background-color 0.2s, border-color 0.2s;\n}\n\n.toolbar-btn:hover:not(:disabled) {\n background: var(--mj-bg-surface-sunken);\n border-color: var(--mj-border-strong);\n}\n\n.toolbar-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.toolbar-btn i {\n font-size: 14px;\n}\n\n/* Icon-only button */\n.toolbar-btn.icon-only {\n padding: 6px 8px;\n}\n\n.toolbar-btn.icon-only i {\n margin-right: 0;\n}\n\n/* ========================================\n Grid wrapper\n ======================================== */\n\n.grid-wrapper {\n flex: 1;\n min-height: 0;\n position: relative;\n transition: opacity 0.2s ease;\n}\n\n.grid-wrapper.loading {\n opacity: 0.5;\n pointer-events: none;\n}\n\n.query-grid {\n width: 100%;\n height: 100%;\n}\n\n/* ========================================\n Loading overlay\n ======================================== */\n\n.loading-overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--mj-bg-overlay);\n z-index: 100;\n}\n\n/* ========================================\n Empty state\n ======================================== */\n\n/* Absolute-center the empty state over the grid; mj-empty-state owns its content. */\n.empty-state {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n}\n\n/* ========================================\n Entity link cell\n ======================================== */\n\n::ng-deep .entity-link-cell {\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n::ng-deep .entity-link {\n color: var(--grid-accent-color);\n text-decoration: none;\n cursor: pointer;\n transition: color 0.15s ease;\n}\n\n::ng-deep .entity-link:hover {\n color: var(--mj-brand-primary-hover);\n text-decoration: underline;\n}\n\n::ng-deep .entity-link-icon {\n font-size: 10px;\n color: var(--mj-text-disabled);\n opacity: 0;\n transition: opacity 0.15s ease;\n}\n\n::ng-deep .entity-link-cell:hover .entity-link-icon {\n opacity: 1;\n}\n\n/* ========================================\n AG Grid customizations\n ======================================== */\n\n/* ========================================\n Visual Config: Zebra Striping\n (copied from entity-data-grid pattern)\n ======================================== */\n\n/* Subtle contrast */\n.alternate-rows-subtle ::ng-deep .ag-row-odd {\n background-color: color-mix(in srgb, var(--mj-text-primary) 1.5%, transparent);\n}\n\n.alternate-rows-subtle ::ng-deep .ag-row-odd:hover:not(.ag-row-selected) {\n background-color: var(--mj-bg-surface-hover);\n}\n\n/* Medium contrast (default) */\n.alternate-rows-medium ::ng-deep .ag-row-odd {\n background-color: color-mix(in srgb, var(--mj-text-primary) 2.5%, transparent);\n}\n\n.alternate-rows-medium ::ng-deep .ag-row-odd:hover:not(.ag-row-selected) {\n background-color: var(--mj-bg-surface-hover);\n}\n\n/* Strong contrast */\n.alternate-rows-strong ::ng-deep .ag-row-odd {\n background-color: color-mix(in srgb, var(--mj-text-primary) 4%, transparent);\n}\n\n.alternate-rows-strong ::ng-deep .ag-row-odd:hover:not(.ag-row-selected) {\n background-color: var(--mj-bg-surface-hover);\n}\n\n::ng-deep .ag-header-cell {\n font-weight: 600;\n font-size: 12px;\n text-transform: uppercase;\n letter-spacing: 0.3px;\n color: var(--mj-text-secondary);\n}\n\n::ng-deep .ag-header-cell:hover {\n background-color: color-mix(in srgb, var(--mj-text-primary) 4%, transparent);\n}\n\n/* Selected row styling */\n::ng-deep .ag-row-selected {\n background-color: var(--grid-selection-bg) !important;\n color: var(--mj-text-primary) !important;\n box-shadow: inset 4px 0 0 0 var(--grid-selection-indicator);\n}\n\n::ng-deep .ag-row-selected .ag-cell {\n color: var(--mj-text-primary) !important;\n}\n\n/* Row border */\n::ng-deep .ag-row {\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n\n/* Header alignment */\n::ng-deep .header-right .ag-header-cell-label {\n justify-content: flex-end;\n}\n\n::ng-deep .header-center .ag-header-cell-label {\n justify-content: center;\n}\n\n/* Checkbox styling */\n::ng-deep .ag-checkbox-input-wrapper {\n border-radius: 4px;\n width: 18px;\n height: 18px;\n}\n\n::ng-deep .ag-checkbox-input-wrapper.ag-checked {\n background-color: var(--grid-accent-color);\n border-color: var(--grid-accent-color);\n}\n\n::ng-deep .ag-checkbox-input-wrapper.ag-checked::after {\n color: var(--mj-text-inverse);\n}\n\n/* ========================================\n Sort Indicators - Arrow Only\n ======================================== */\n\n/* Sort icons - colored arrows only */\n:host ::ng-deep .ag-sort-ascending-icon {\n color: var(--mj-brand-primary) !important;\n}\n\n:host ::ng-deep .ag-sort-descending-icon {\n color: var(--mj-status-error) !important;\n}\n\n:host ::ng-deep .ag-sort-ascending-icon .ag-icon,\n:host ::ng-deep .ag-sort-descending-icon .ag-icon {\n font-size: 14px !important;\n}\n\n/* Sort order number (for multi-sort) */\n:host ::ng-deep .ag-sort-order {\n margin-left: 4px;\n font-size: 11px !important;\n font-weight: 700 !important;\n color: var(--mj-text-secondary) !important;\n}\n\n/* Hover state for sortable headers */\n:host ::ng-deep .ag-header-cell-sortable:hover {\n background: color-mix(in srgb, var(--mj-text-primary) 4%, transparent);\n}\n\n/* ========================================\n Scrollbar Styling\n ======================================== */\n\n::ng-deep .ag-body-viewport::-webkit-scrollbar {\n width: 8px;\n height: 8px;\n}\n\n::ng-deep .ag-body-viewport::-webkit-scrollbar-track {\n background: var(--mj-bg-surface-card);\n border-radius: 4px;\n}\n\n::ng-deep .ag-body-viewport::-webkit-scrollbar-thumb {\n background: var(--mj-border-strong);\n border-radius: 4px;\n}\n\n::ng-deep .ag-body-viewport::-webkit-scrollbar-thumb:hover {\n background: var(--mj-text-disabled);\n}\n\n/* ========================================\n Responsive adjustments\n ======================================== */\n\n@media (max-width: 768px) {\n .grid-toolbar {\n flex-wrap: wrap;\n gap: 8px;\n }\n\n .toolbar-left,\n .toolbar-right {\n flex-wrap: wrap;\n }\n\n /* Hide button text on mobile */\n .toolbar-btn .button-text {\n display: none;\n }\n}\n"] }]
|
|
1133
1207
|
}], () => [{ type: i0.ChangeDetectorRef }, { type: i0.ElementRef }, { type: i1.ExportService }], { QueryInfo: [{
|
|
1134
1208
|
type: Input
|
|
1135
1209
|
}], ColumnConfigs: [{
|
|
@@ -1182,6 +1256,8 @@ export class QueryDataGridComponent {
|
|
|
1182
1256
|
type: Input
|
|
1183
1257
|
}], PageSize: [{
|
|
1184
1258
|
type: Input
|
|
1259
|
+
}], ExportDataProvider: [{
|
|
1260
|
+
type: Input
|
|
1185
1261
|
}], PageChange: [{
|
|
1186
1262
|
type: Output
|
|
1187
1263
|
}] }); })();
|