@genesislcap/grid-pro 14.285.1 → 14.286.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/README.md +2 -1
  2. package/dist/custom-elements.json +142 -5
  3. package/dist/dts/datasource/base.datasource.d.ts +4 -1
  4. package/dist/dts/datasource/base.datasource.d.ts.map +1 -1
  5. package/dist/dts/datasource/server-side.datasource.d.ts +20 -3
  6. package/dist/dts/datasource/server-side.datasource.d.ts.map +1 -1
  7. package/dist/dts/datasource/server-side.grid-definitions.d.ts +1 -1
  8. package/dist/dts/datasource/server-side.resource-base.d.ts +6 -0
  9. package/dist/dts/datasource/server-side.resource-base.d.ts.map +1 -1
  10. package/dist/dts/datasource/server-side.resource-dataserver.d.ts +1 -1
  11. package/dist/dts/datasource/server-side.resource-dataserver.d.ts.map +1 -1
  12. package/dist/dts/datasource/server-side.resource-reqrep.d.ts +1 -1
  13. package/dist/dts/grid-pro.d.ts +14 -2
  14. package/dist/dts/grid-pro.d.ts.map +1 -1
  15. package/dist/dts/grid-pro.styles.d.ts.map +1 -1
  16. package/dist/dts/status-bar-components/pagination.status-bar.d.ts +1 -1
  17. package/dist/dts/status-bar-components/pagination.status-bar.d.ts.map +1 -1
  18. package/dist/esm/datasource/base.datasource.js +2 -1
  19. package/dist/esm/datasource/server-side.datasource.js +102 -16
  20. package/dist/esm/datasource/server-side.grid-definitions.js +1 -1
  21. package/dist/esm/datasource/server-side.resource-base.js +7 -1
  22. package/dist/esm/datasource/server-side.resource-dataserver.js +3 -2
  23. package/dist/esm/datasource/server-side.resource-reqrep.js +1 -1
  24. package/dist/esm/grid-pro.js +74 -41
  25. package/dist/esm/grid-pro.styles.js +15 -0
  26. package/dist/esm/status-bar-components/pagination.status-bar.js +16 -12
  27. package/dist/grid-pro.api.json +862 -1
  28. package/dist/grid-pro.d.ts +38 -7
  29. package/docs/api/grid-pro.gridpro.isserverside.md +12 -0
  30. package/docs/api/grid-pro.gridpro.md +1 -0
  31. package/docs/api/grid-pro.gridpro.paginationpagesize.md +5 -1
  32. package/docs/api/grid-pro.gridproserversidedatasource.applyasyncfuncname.md +14 -0
  33. package/docs/api/grid-pro.gridproserversidedatasource.applyfuncname.md +14 -0
  34. package/docs/api/grid-pro.gridproserversidedatasource.applytransaction.md +25 -0
  35. package/docs/api/grid-pro.gridproserversidedatasource.applytransactionasync.md +26 -0
  36. package/docs/api/grid-pro.gridproserversidedatasource.connectedcallback.md +18 -0
  37. package/docs/api/grid-pro.gridproserversidedatasource.criteriachanged.md +26 -0
  38. package/docs/api/grid-pro.gridproserversidedatasource.deepclone.md +18 -0
  39. package/docs/api/grid-pro.gridproserversidedatasource.destroy.md +18 -0
  40. package/docs/api/grid-pro.gridproserversidedatasource.disconnectedcallback.md +18 -0
  41. package/docs/api/grid-pro.gridproserversidedatasource.init.md +18 -0
  42. package/docs/api/grid-pro.gridproserversidedatasource.liveupdates.md +21 -0
  43. package/docs/api/grid-pro.gridproserversidedatasource.loadmore.md +18 -0
  44. package/docs/api/grid-pro.gridproserversidedatasource.md +54 -0
  45. package/docs/api/grid-pro.gridproserversidedatasource.onpaginationchanged.md +25 -0
  46. package/docs/api/grid-pro.gridproserversidedatasource.params.md +14 -0
  47. package/docs/api/grid-pro.gridproserversidedatasource.reloadresourcedata.md +31 -0
  48. package/docs/api/grid-pro.gridproserversidedatasource.request.md +14 -0
  49. package/docs/api/grid-pro.gridproserversidedatasource.resourcenamechanged.md +26 -0
  50. package/docs/api/grid-pro.gridproserversidedatasource.restart.md +18 -0
  51. package/docs/api/grid-pro.gridproserversidedatasource.rowmodel.md +14 -0
  52. package/docs/api/grid-pro.gridproserversidedatasource.zerobasedviewnumber.md +21 -0
  53. package/docs/api/grid-pro.md +1 -0
  54. package/docs/api-report.md +5 -4
  55. package/package.json +13 -13
@@ -1,7 +1,7 @@
1
1
  import { __awaiter, __decorate } from "tslib";
2
2
  import { Events, } from '@ag-grid-community/core';
3
3
  import { dataServerResultFilter, MessageType, normaliseCriteria, toFieldMetadata, } from '@genesislcap/foundation-comms';
4
- import { LifecycleMixin } from '@genesislcap/foundation-utils';
4
+ import { LifecycleMixin, insertDocumentCSSRule } from '@genesislcap/foundation-utils';
5
5
  import { attr, customElement, DOM, observable } from '@microsoft/fast-element';
6
6
  import { gridProGenesisDatasourceEventNames } from '../grid-pro-genesis-datasource';
7
7
  import { logger } from '../utils';
@@ -12,10 +12,59 @@ import { ReqRepServerSideDatasource } from './server-side.resource-reqrep';
12
12
  const criteriaDelimiter = ';';
13
13
  const withoutColumnDefs = null;
14
14
  const timeoutInMs = 500;
15
+ /**
16
+ * Custom CSS for server-side datasource sort indicators
17
+ * Makes sort indicators always visible with custom styling
18
+ */
19
+ const serverSideSortIndicatorCSS = `
20
+ .grid-pro-server-side .ag-header-cell-sortable .ag-sort-indicator-container {
21
+ opacity: 1 !important;
22
+ visibility: visible !important;
23
+ }
24
+
25
+ .grid-pro-server-side .ag-header-cell-sortable:not(.ag-header-cell-sorted) .ag-sort-indicator-container {
26
+ opacity: 0.4 !important;
27
+ }
28
+
29
+ .grid-pro-server-side .ag-header-cell-sorted .ag-sort-indicator-container {
30
+ opacity: 1 !important;
31
+ }
32
+
33
+ .grid-pro-server-side .ag-sort-ascending-icon::before,
34
+ .grid-pro-server-side .ag-sort-descending-icon::before,
35
+ .grid-pro-server-side .ag-header-cell-sortable:not(.ag-header-cell-sorted) .ag-sort-indicator-icon::before {
36
+ font-family: var(--ag-icon-font-family, agGridAlpine) !important;
37
+ font-size: var(--ag-icon-size, 16px) !important;
38
+ color: var(--ag-header-foreground-color, var(--ag-foreground-color)) !important;
39
+ }
40
+
41
+ .grid-pro-server-side .ag-sort-ascending-icon::before {
42
+ content: "\\e90d" !important; /* AG Grid sort up icon */
43
+ }
44
+
45
+ .grid-pro-server-side .ag-sort-descending-icon::before {
46
+ content: "\\e90c" !important; /* AG Grid sort down icon */
47
+ }
48
+
49
+ .grid-pro-server-side .ag-header-cell-sortable:not(.ag-header-cell-sorted) .ag-sort-indicator-icon::before {
50
+ content: "\\e90b" !important; /* AG Grid sort icon */
51
+ opacity: 0.6 !important;
52
+ }
53
+
54
+ /* Ensure the sort indicator is always visible for sortable columns in server-side mode */
55
+ .grid-pro-server-side .ag-header-cell-sortable .ag-sort-indicator-icon {
56
+ display: inline-block !important;
57
+ }
58
+ `;
15
59
  /**
16
60
  * A Genesis Datasource element, for server-side | SSRM-compatible data fetching and used exclusively by the GridPro element.
17
61
  * @remarks Only supports Server-Side Row Model. Requires `@ag-grid-enterprise/server-side-row-model` setup and valid AG Grid Enterprise license.
18
- * @alpha
62
+ *
63
+ * **Custom Sort Indicators**: This datasource automatically applies custom sort indicators that are always visible (instead of only on hover).
64
+ * Sortable columns will show a subtle sort icon even when not sorted, and active sort indicators will be more prominent.
65
+ * The custom styling uses AG Grid's native icon font for consistency with the grid theme.
66
+ *
67
+ * @beta
19
68
  */
20
69
  let GridProServerSideDatasource = class GridProServerSideDatasource extends LifecycleMixin(GridProBaseDatasource) {
21
70
  constructor() {
@@ -33,6 +82,7 @@ let GridProServerSideDatasource = class GridProServerSideDatasource extends Life
33
82
  */
34
83
  this.liveUpdates = false;
35
84
  this.request = {};
85
+ this.sortIndicatorCSSDestroy = null;
36
86
  }
37
87
  resourceNameChanged(oldValue, newValue) {
38
88
  if (!oldValue || oldValue === newValue)
@@ -45,7 +95,7 @@ let GridProServerSideDatasource = class GridProServerSideDatasource extends Life
45
95
  const criteriaIsNotDuplicate = oldCriteria !== normaliseCriteria(newCriteria, criteriaDelimiter);
46
96
  if (this.ssrmDatasource && criteriaIsNotDuplicate) {
47
97
  DOM.queueUpdate(() => __awaiter(this, void 0, void 0, function* () {
48
- yield this.reloadResourceData();
98
+ yield this.restart();
49
99
  }));
50
100
  }
51
101
  }
@@ -76,7 +126,7 @@ let GridProServerSideDatasource = class GridProServerSideDatasource extends Life
76
126
  /**
77
127
  * Resets the grid data while keeping columnDefs and reloads data.
78
128
  * @remarks This is used when the grid is already initialized and we want to reload the data due to a criteria/filter change.
79
- * @public
129
+ * @beta
80
130
  */
81
131
  reloadResourceData(params) {
82
132
  var _a, _b, _c, _d, _e, _f, _g;
@@ -87,13 +137,12 @@ let GridProServerSideDatasource = class GridProServerSideDatasource extends Life
87
137
  // Cache the current filter model before clearing data to preserve column filters
88
138
  yield ((_b = this.agGrid) === null || _b === void 0 ? void 0 : _b.cacheFilterConfig());
89
139
  this.clearRowData(withoutColumnDefs);
140
+ (_c = this.agGrid.gridApi) === null || _c === void 0 ? void 0 : _c.refreshServerSide({ purge: true });
90
141
  if (params) {
91
- // this.datasource.stream = undefined;
92
142
  const options = Object.assign(Object.assign({}, this.datasourceOptions()), params);
93
143
  const initOK = yield this.datasource.init(options, true, false);
94
- // this.$emit(gridProGenesisDatasourceEventNames.dataInit);
95
144
  if (!initOK) {
96
- (_c = this.agGrid.gridApi) === null || _c === void 0 ? void 0 : _c.setServerSideDatasource(null);
145
+ (_d = this.agGrid.gridApi) === null || _d === void 0 ? void 0 : _d.setServerSideDatasource(null);
97
146
  logger.error('Genesis Datasource re-init failed on filtering/sorting.');
98
147
  }
99
148
  }
@@ -102,13 +151,48 @@ let GridProServerSideDatasource = class GridProServerSideDatasource extends Life
102
151
  yield this.ssrmDatasource.destroy();
103
152
  this.ssrmDatasource = undefined;
104
153
  }
105
- (_d = this.agGrid.gridApi) === null || _d === void 0 ? void 0 : _d.setServerSideDatasource(null);
106
- (_e = this.agGrid.gridApi) === null || _e === void 0 ? void 0 : _e.refreshServerSide({ purge: true });
154
+ (_e = this.agGrid.gridApi) === null || _e === void 0 ? void 0 : _e.setServerSideDatasource(null);
107
155
  (_g = (_f = this.agGrid) === null || _f === void 0 ? void 0 : _f.gridApi) === null || _g === void 0 ? void 0 : _g.showLoadingOverlay();
108
156
  yield this.init();
109
157
  }
110
158
  });
111
159
  }
160
+ /**
161
+ * Applies custom sort indicator styling for server-side datasource
162
+ * @internal
163
+ */
164
+ applyServerSideSortIndicatorStyling() {
165
+ var _a, _b;
166
+ // Remove existing styling if present
167
+ this.removeServerSideSortIndicatorStyling();
168
+ // Add custom CSS class to the grid container
169
+ if ((_a = this.agGrid) === null || _a === void 0 ? void 0 : _a.gridApi) {
170
+ // Add CSS class to grid element
171
+ const gridElement = ((_b = this.agGrid.gridSlot) === null || _b === void 0 ? void 0 : _b.parentElement) || this.agGrid;
172
+ if (gridElement) {
173
+ gridElement.classList.add('grid-pro-server-side');
174
+ }
175
+ }
176
+ // Insert custom CSS rules
177
+ this.sortIndicatorCSSDestroy = insertDocumentCSSRule(serverSideSortIndicatorCSS, 'grid-pro-server-side-sort');
178
+ }
179
+ /**
180
+ * Removes custom sort indicator styling
181
+ * @internal
182
+ */
183
+ removeServerSideSortIndicatorStyling() {
184
+ var _a, _b;
185
+ // Remove CSS class from grid element
186
+ const gridElement = ((_b = (_a = this.agGrid) === null || _a === void 0 ? void 0 : _a.gridSlot) === null || _b === void 0 ? void 0 : _b.parentElement) || this.agGrid;
187
+ if (gridElement) {
188
+ gridElement.classList.remove('grid-pro-server-side');
189
+ }
190
+ // Remove custom CSS rules
191
+ if (this.sortIndicatorCSSDestroy) {
192
+ this.sortIndicatorCSSDestroy();
193
+ this.sortIndicatorCSSDestroy = null;
194
+ }
195
+ }
112
196
  init() {
113
197
  return __awaiter(this, void 0, void 0, function* () {
114
198
  if (this.agGrid) {
@@ -126,7 +210,8 @@ let GridProServerSideDatasource = class GridProServerSideDatasource extends Life
126
210
  filter: true,
127
211
  resizable: true,
128
212
  sortable: false,
129
- }, pagination: this.pagination, paginationPageSize: this.maxRows, rowBuffer: 0, rowModelType: 'serverSide', suppressServerSideInfiniteScroll: false, suppressMultiSort: true, onFilterChanged: (params) => { }, onSortChanged: (params) => { }, onPaginationChanged: (event) => this.onPaginationChanged(event) }, this.agGrid['agGridOptions']), this.deferredGridOptions);
213
+ unSortIcon: true,
214
+ }, rowBuffer: 0, rowModelType: 'serverSide', suppressServerSideInfiniteScroll: false, suppressMultiSort: true, onFilterChanged: (params) => { }, onSortChanged: (params) => { }, onPaginationChanged: (event) => this.onPaginationChanged(event) }, this.agGrid['agGridOptions']), this.deferredGridOptions);
130
215
  this.agGrid.gridOptions = gridOptions;
131
216
  this.agGrid['initGrid']();
132
217
  this.agGrid.addEventListener(Events.EVENT_GRID_READY, () => __awaiter(this, void 0, void 0, function* () {
@@ -174,6 +259,8 @@ let GridProServerSideDatasource = class GridProServerSideDatasource extends Life
174
259
  this.agGrid.gridApi.setServerSideDatasource(this.ssrmDatasource);
175
260
  // Restore cached filter config after setting the server-side datasource
176
261
  this.agGrid.restoreCachedFilterConfig();
262
+ // Apply custom sort indicator styling for server-side datasource
263
+ this.applyServerSideSortIndicatorStyling();
177
264
  }), { once: true });
178
265
  return;
179
266
  }
@@ -197,6 +284,8 @@ let GridProServerSideDatasource = class GridProServerSideDatasource extends Life
197
284
  yield this.ssrmDatasource.destroy();
198
285
  this.ssrmDatasource = undefined;
199
286
  }
287
+ // Remove custom sort indicator styling
288
+ this.removeServerSideSortIndicatorStyling();
200
289
  (_b = this.agGrid.gridApi) === null || _b === void 0 ? void 0 : _b.setServerSideDatasource(null);
201
290
  (_c = this.agGrid.gridApi) === null || _c === void 0 ? void 0 : _c.refreshServerSide({ purge: true });
202
291
  });
@@ -246,7 +335,6 @@ let GridProServerSideDatasource = class GridProServerSideDatasource extends Life
246
335
  logger.warn('Specified [orderBy] index is not valid and will not be used. See https://learn.genesis.global/docs/database/data-types/index-entities/ - Available indexes:', validIndexes);
247
336
  }
248
337
  }
249
- logger.debug('Getting configured params:', params);
250
338
  return params;
251
339
  }
252
340
  get rowModel() {
@@ -280,7 +368,7 @@ let GridProServerSideDatasource = class GridProServerSideDatasource extends Life
280
368
  // this.handleStreamDeletes(nextMessage.deletes);
281
369
  // this.ssrmDatasource.client_ROWS_COUNT -= nextMessage.deletes.length ?? 0;
282
370
  // this.ssrmDatasource.server_ROWS_COUNT -= nextMessage.deletes.length ?? 0;
283
- if (this.agGrid.pagination) {
371
+ if (this.pagination) {
284
372
  this.applyAllAgTransactions();
285
373
  }
286
374
  else {
@@ -318,10 +406,8 @@ let GridProServerSideDatasource = class GridProServerSideDatasource extends Life
318
406
  getAgColumnDefs(fieldsMetadata) {
319
407
  return __awaiter(this, void 0, void 0, function* () {
320
408
  const colDefsFromGenesisData = this.generateColumnDefsFromMetadata(fieldsMetadata, getServerSideFilterParamsByFieldType);
321
- colDefsFromGenesisData.map((colDef) => {
322
- return {
323
- sortable: [].concat(...this.indexes.values()).includes(colDef.field),
324
- };
409
+ colDefsFromGenesisData.forEach((colDef) => {
410
+ colDef.sortable = [].concat(...this.indexes.values()).includes(colDef.field);
325
411
  });
326
412
  const colDefsMergedWithTemplateDefs = yield this.agGrid.mergeAllColumnDefsAndStates(colDefsFromGenesisData, true);
327
413
  return colDefsMergedWithTemplateDefs;
@@ -4,7 +4,7 @@ import { FieldTypeEnum } from '@genesislcap/foundation-comms';
4
4
  * @param type - The type of the field/column
5
5
  * @returns the filter params for the specified field type
6
6
  * @remarks Currently only returns a default filter params object, for all field types
7
- * @alpha
7
+ * @beta
8
8
  */
9
9
  export function getServerSideFilterParamsByFieldType(type) {
10
10
  switch (type) {
@@ -2,6 +2,12 @@ import { __awaiter, __decorate } from "tslib";
2
2
  import { Auth, Connect, logger, } from '@genesislcap/foundation-comms';
3
3
  import { UUID } from '@genesislcap/foundation-utils';
4
4
  import { getAvailableIndexes, getAvailableIndexFields } from '../utils';
5
+ /**
6
+ * Base class for server-side resource datasources used in Grid Pro SSRM implementations.
7
+ * Provides common logic for filtering, sorting, and pagination.
8
+ *
9
+ * @beta
10
+ */
5
11
  export class BaseServerSideDatasource {
6
12
  constructor(options) {
7
13
  this.rowData = new Map();
@@ -66,7 +72,6 @@ export class BaseServerSideDatasource {
66
72
  return;
67
73
  }
68
74
  else if (toBeAppliedSortModel.length > 0) {
69
- this.currentSortModel = toBeAppliedSortModel;
70
75
  const coldIdBeingSorted = toBeAppliedSortModel[0].colId; // Not allowing multiple sorts by user
71
76
  const sortTypeBeingApplied = toBeAppliedSortModel[0].sort;
72
77
  const orderByAndToBeSortedColIds = this.getOrderByAndToBeSortedColIds(this.resourceIndexes, coldIdBeingSorted);
@@ -81,6 +86,7 @@ export class BaseServerSideDatasource {
81
86
  return;
82
87
  }
83
88
  else if (JSON.stringify(toBeAppliedSortModel) !== JSON.stringify(this.currentSortModel)) {
89
+ this.currentSortModel = toBeAppliedSortModel;
84
90
  this.resourceParams.ORDER_BY = orderByAndToBeSortedColIds.orderBy;
85
91
  this.resourceParams.REVERSE = sortTypeBeingApplied === 'desc' ? true : false;
86
92
  yield this.refreshDatasource(params);
@@ -4,7 +4,7 @@ import { DOM } from '@microsoft/fast-element';
4
4
  import { BaseServerSideDatasource } from './server-side.resource-base';
5
5
  /**
6
6
  * The DATASERVER IServerSideDatasource implementation, used for SSRM (Server-Side Row Model) in the grid.
7
- * @alpha
7
+ * @beta
8
8
  */
9
9
  export class DataserverServerSideDatasource extends BaseServerSideDatasource {
10
10
  constructor(options) {
@@ -49,7 +49,8 @@ export class DataserverServerSideDatasource extends BaseServerSideDatasource {
49
49
  this.dataserverStreamSubscription = this.dataserverStream.subscribe((dataserverResult) => {
50
50
  if (applyResult) {
51
51
  DOM.queueUpdate(() => __awaiter(this, void 0, void 0, function* () {
52
- if (this.resourceParams.CRITERIA_MATCH) {
52
+ // TODO: this is a bit of hack, due GSF not returning a different ROWS_COUNT when there is a CRITERIA_MATCH
53
+ if (this.resourceParams.CRITERIA_MATCH && this.pagination) {
53
54
  const updatedInfo = yield this.connect.snapshot(this.resourceName, {
54
55
  MAX_ROWS: this.maxView,
55
56
  MAX_VIEW: this.maxView,
@@ -4,7 +4,7 @@ import { logger } from '../utils';
4
4
  import { BaseServerSideDatasource } from './server-side.resource-base';
5
5
  /**
6
6
  * The REQUEST_SERVER IServerSideDatasource implementation, used for SSRM (Server-Side Row Model) in the grid.
7
- * @alpha
7
+ * @beta
8
8
  */
9
9
  export class ReqRepServerSideDatasource extends BaseServerSideDatasource {
10
10
  constructor(options) {
@@ -135,14 +135,6 @@ export class GridPro extends LifecycleMixin(FoundationElement) {
135
135
  * @see https://www.ag-grid.com/javascript-data-grid/server-side-model-pagination/
136
136
  */
137
137
  this.pagination = false;
138
- /**
139
- * Number of rows per page when pagination is enabled.
140
- * @remarks
141
- * **Default Value:** `DatasourceDefaults.DEFAULT_PAGINATION_PAGE_SIZE (25)` (default MAX_ROWS divided by 10)
142
- * Only used when pagination is enabled.
143
- * Note that AG Grid's full pagination functionality requires the Enterprise module.
144
- */
145
- this.paginationPageSize = DatasourceDefaults.DEFAULT_PAGINATION_PAGE_SIZE;
146
138
  /**
147
139
  * Configuration for the grid status bar components.
148
140
  * @remarks
@@ -229,6 +221,9 @@ export class GridPro extends LifecycleMixin(FoundationElement) {
229
221
  this.rootEventsListeners.forEach(({ key, action }) => {
230
222
  this.addEventListener(key, action);
231
223
  });
224
+ this.paginationPageSize = this.isServerSide
225
+ ? this.gridProDatasource.maxRows
226
+ : DatasourceDefaults.DEFAULT_PAGINATION_PAGE_SIZE;
232
227
  }
233
228
  disconnectedCallback() {
234
229
  super.disconnectedCallback();
@@ -364,6 +359,12 @@ export class GridPro extends LifecycleMixin(FoundationElement) {
364
359
  get gridOptions() {
365
360
  return this.agGridOptions;
366
361
  }
362
+ /**
363
+ * @public
364
+ */
365
+ get isServerSide() {
366
+ return this.gridProDatasource instanceof GridProServerSideDatasource;
367
+ }
367
368
  /**
368
369
  * @public
369
370
  */
@@ -555,30 +556,29 @@ export class GridPro extends LifecycleMixin(FoundationElement) {
555
556
  return colDefsToReturn;
556
557
  });
557
558
  }
558
- setupPaginationAndStatusBar(gridOptions) {
559
- var _a;
560
- // TODO: when this happens "pagination" is undefined, (due init cycles, DS being child of grid) so we need to use this['_pagination'] for now
561
- const pagination = this['_pagination'];
562
- if (pagination && gridOptions.rowModelType) {
563
- gridOptions.pagination = true;
564
- gridOptions.paginationPageSize = this.paginationPageSize;
565
- gridOptions.suppressScrollOnNewData = true;
559
+ panelExists(statusPanelType, panels) {
560
+ return panels.some((panel) => panel.statusPanel === statusPanelType);
561
+ }
562
+ addRowCountPanel(statusPanels) {
563
+ // For server-side models, AG Grid's built-in row count components don't work properly
564
+ // because they expect access to the complete dataset. Instead, rely on our custom
565
+ // pagination component which properly handles server-side row counts.
566
+ if (this.isServerSide) {
567
+ return;
566
568
  }
567
- // Set default status bar with components based on configuration
568
- if (this.withStatusBar && this.statusBarConfig) {
569
- // Create status panels based on config
570
- const statusPanels = [];
571
- // Always add row count component
572
- if (this.statusBarConfig && this.statusBarConfig.rows === true) {
569
+ if (this.statusBarConfig && this.statusBarConfig.rows === true) {
570
+ const rowCountStatusPanel = 'agTotalAndFilteredRowCountComponent';
571
+ if (!this.panelExists(rowCountStatusPanel, statusPanels)) {
573
572
  statusPanels.push({
574
- statusPanel: gridOptions.rowModelType === 'serverSide'
575
- ? 'agTotalRowCountComponent'
576
- : 'agTotalAndFilteredRowCountComponent',
573
+ statusPanel: rowCountStatusPanel,
577
574
  align: 'left',
578
575
  });
579
576
  }
580
- // Add max rows component if explicitly enabled
581
- if (this.statusBarConfig && this.statusBarConfig.maxRows === true) {
577
+ }
578
+ }
579
+ addMaxRowsPanel(statusPanels) {
580
+ if (this.statusBarConfig && this.statusBarConfig.maxRows === true) {
581
+ if (!this.panelExists(GridProStatusBarTypes.labelValue, statusPanels)) {
582
582
  statusPanels.push({
583
583
  statusPanel: GridProStatusBarTypes.labelValue,
584
584
  statusPanelParams: {
@@ -589,31 +589,64 @@ export class GridPro extends LifecycleMixin(FoundationElement) {
589
589
  align: 'left',
590
590
  });
591
591
  }
592
- // Add aggregation component if explicitly enabled
593
- if (this.statusBarConfig && this.statusBarConfig.aggregation === true) {
592
+ }
593
+ }
594
+ addAggregationPanel(statusPanels) {
595
+ if (this.statusBarConfig && this.statusBarConfig.aggregation === true) {
596
+ if (!this.panelExists('agAggregationComponent', statusPanels)) {
594
597
  statusPanels.push({
595
598
  statusPanel: 'agAggregationComponent',
596
599
  align: 'right',
597
600
  });
598
601
  }
599
- // Add datasource-specific status bar components
600
- if (this.gridProDatasource) {
601
- const isServerSide = gridOptions.rowModelType === 'serverSide';
602
- const datasourceStatusPanels = this.gridProDatasource.getDatasourceStatusBarPanels(isServerSide);
603
- statusPanels.push(...datasourceStatusPanels);
604
- }
605
- // Add pagination status if pagination is enabled
606
- if (pagination) {
607
- gridOptions.suppressPaginationPanel = true;
602
+ }
603
+ }
604
+ addDatasourcePanels(statusPanels) {
605
+ if (this.gridProDatasource) {
606
+ const datasourceStatusPanels = this.gridProDatasource.getDatasourceStatusBarPanels(this.isServerSide);
607
+ // Filter out duplicate datasource panels
608
+ const newDatasourcePanels = datasourceStatusPanels.filter((panel) => !this.panelExists(panel.statusPanel, statusPanels));
609
+ statusPanels.push(...newDatasourcePanels);
610
+ }
611
+ }
612
+ addPaginationPanel(statusPanels) {
613
+ if (this['_pagination']) {
614
+ if (!this.panelExists(GridProStatusBarTypes.pagination, statusPanels)) {
608
615
  statusPanels.push({
609
616
  statusPanel: GridProStatusBarTypes.pagination,
610
617
  align: 'right',
611
618
  });
612
619
  }
613
- // Store user-defined status panels for later
614
- const userDefinedStatusPanels = ((_a = gridOptions.statusBar) === null || _a === void 0 ? void 0 : _a.statusPanels) || [];
620
+ }
621
+ }
622
+ setupPaginationAndStatusBar(gridOptions) {
623
+ // Keep the guard for production code, but allow override for testing
624
+ // if (this.initialised && !allowDuplicateCheck) return;
625
+ var _a, _b;
626
+ if (this['_pagination']) {
627
+ gridOptions.pagination = true;
628
+ gridOptions.suppressScrollOnNewData = true;
629
+ gridOptions.paginationPageSize = this.paginationPageSize;
630
+ }
631
+ // Set default status bar with components based on configuration
632
+ if (this.withStatusBar && this.statusBarConfig) {
633
+ // For duplicate checking (testing scenario), clear existing status panels to prevent duplicates
634
+ // unless they are user-defined panels that we want to preserve
635
+ const existingPanels = ((_a = gridOptions.statusBar) === null || _a === void 0 ? void 0 : _a.statusPanels) || [];
636
+ const statusPanels = [...existingPanels];
637
+ this.addRowCountPanel(statusPanels);
638
+ this.addMaxRowsPanel(statusPanels);
639
+ this.addAggregationPanel(statusPanels);
640
+ this.addDatasourcePanels(statusPanels);
641
+ if (this['_pagination']) {
642
+ gridOptions.suppressPaginationPanel = true;
643
+ this.addPaginationPanel(statusPanels);
644
+ }
645
+ const userDefinedStatusPanels = ((_b = gridOptions.statusBar) === null || _b === void 0 ? void 0 : _b.statusPanels) || [];
646
+ const newUserDefinedPanels = userDefinedStatusPanels.filter((panel) => !this.panelExists(panel.statusPanel, statusPanels));
647
+ statusPanels.push(...newUserDefinedPanels);
615
648
  gridOptions.statusBar = {
616
- statusPanels: [...statusPanels, ...userDefinedStatusPanels],
649
+ statusPanels: statusPanels,
617
650
  };
618
651
  }
619
652
  }
@@ -77,4 +77,19 @@ export const foundationGridProStyles = css `
77
77
  padding-top: var(--ag-grid-size);
78
78
  padding-bottom: var(--ag-grid-size);
79
79
  }
80
+
81
+ /* Custom styling for the unsort icon (sortNone) - only for sortable columns */
82
+ .ag-header-cell.ag-header-cell-sortable .ag-icon-none {
83
+ opacity: 100%;
84
+ color: var(--rapid-ag-header-foreground-color, var(--ag-foreground-color, #fff));
85
+ font-size: calc(var(--ag-icon-size, 12px) * 1.2);
86
+ font-weight: bold;
87
+ }
88
+
89
+ .ag-header-cell.ag-header-cell-sortable:hover .ag-icon-none {
90
+ opacity: 100%;
91
+ color: var(--rapid-ag-header-foreground-color, var(--ag-foreground-color, #fff));
92
+ transform: scale(1.1);
93
+ transition: transform 0.2s ease;
94
+ }
80
95
  `;
@@ -6,24 +6,26 @@
6
6
  export class PaginationStatusBarComponent {
7
7
  init(params) {
8
8
  this.api = params.api;
9
- this.eGui = document.createElement('div');
10
- this.eGui.className = 'ag-status-panel';
11
- this.eGui.setAttribute('data-test-id', 'grid-pagination-panel');
12
- this.eGui.setAttribute('role', 'navigation');
13
- this.eGui.setAttribute('aria-label', 'Pagination controls');
14
- this.eGui.style.display = 'flex';
15
- this.eGui.style.alignItems = 'center';
16
- this.eGui.style.justifyContent = 'flex-end';
17
- this.eGui.style.height = 'var(--ag-status-bar-height)';
9
+ this.element = document.createElement('div');
10
+ this.element.className = 'ag-status-panel';
11
+ this.element.setAttribute('data-test-id', 'grid-pagination-panel');
12
+ this.element.setAttribute('role', 'navigation');
13
+ this.element.setAttribute('aria-label', 'Pagination controls');
14
+ this.element.style.display = 'flex';
15
+ this.element.style.alignItems = 'center';
16
+ this.element.style.justifyContent = 'flex-end';
17
+ this.element.style.height = 'var(--ag-status-bar-height)';
18
18
  this.createPaginationPanel();
19
19
  // Initial update
20
20
  this.updateDisplay();
21
21
  // Listen to pagination changes
22
- this.paginationChangedHandler = this.updateDisplay.bind(this);
22
+ this.paginationChangedHandler = () => {
23
+ this.updateDisplay();
24
+ };
23
25
  this.api.addEventListener('paginationChanged', this.paginationChangedHandler);
24
26
  }
25
27
  getGui() {
26
- return this.eGui;
28
+ return this.element;
27
29
  }
28
30
  createPaginationPanel() {
29
31
  // Create the main pagination panel
@@ -96,7 +98,7 @@ export class PaginationStatusBarComponent {
96
98
  this.paginationPanel.appendChild(this.nextPageButton);
97
99
  this.paginationPanel.appendChild(this.lastPageButton);
98
100
  // Add to main container
99
- this.eGui.appendChild(this.paginationPanel);
101
+ this.element.appendChild(this.paginationPanel);
100
102
  // Add event listeners with keyboard support
101
103
  this.addPaginationEventListeners();
102
104
  }
@@ -202,5 +204,7 @@ export class PaginationStatusBarComponent {
202
204
  if (this.api && this.paginationChangedHandler) {
203
205
  this.api.removeEventListener('paginationChanged', this.paginationChangedHandler);
204
206
  }
207
+ this.api = null;
208
+ this.paginationChangedHandler = null;
205
209
  }
206
210
  }