@genesislcap/grid-pro 15.21.1 → 15.22.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -53,11 +53,22 @@ export function convertTextFilterToCriteria(filterModel, fieldName) {
53
53
  * @returns Genesis criteria string or null
54
54
  */
55
55
  export function convertSetFilterToCriteria(filterModel, fieldName, colMeta) {
56
- var _a;
57
- const selectedValues = ((_a = filterModel === null || filterModel === void 0 ? void 0 : filterModel.values) !== null && _a !== void 0 ? _a : []);
58
- if (!selectedValues || selectedValues.length === 0) {
56
+ // A model with no values array at all (hand-written, or persisted by an older version) is an
57
+ // inactive filter EnumColumnFilter.setModel treats it the same way so it must translate to
58
+ // "no criteria", not to the match-nothing expression below.
59
+ if ((filterModel === null || filterModel === void 0 ? void 0 : filterModel.values) == null) {
59
60
  return null;
60
61
  }
62
+ const selectedValues = filterModel.values;
63
+ if (selectedValues.length === 0) {
64
+ // An explicitly empty selection means "match nothing" (that is how set filters treat it
65
+ // client-side). Returning no criteria would make the server send every row instead, so emit
66
+ // an expression that is false for every value — built only from comparisons the criteria
67
+ // language accepts. This does cost a server round trip that is guaranteed to return zero
68
+ // rows; the state is transient (the user is mid-selection), so that is accepted over
69
+ // teaching the datasource a short-circuit sentinel.
70
+ return `(${fieldName} == '' && ${fieldName} != '')`;
71
+ }
61
72
  // Try to detect "all values selected" using VALID_VALUES from metadata.
62
73
  // In that case we don't want to send any criteria, as it would be equivalent
63
74
  // to no filter at all.
@@ -68,17 +79,29 @@ export function convertSetFilterToCriteria(filterModel, fieldName, colMeta) {
68
79
  ? colMeta.VALID_VALUES
69
80
  : colMeta.VALID_VALUES.split('|');
70
81
  }
71
- catch (_b) {
82
+ catch (_a) {
72
83
  allValues = undefined;
73
84
  }
74
85
  }
75
86
  if (allValues &&
76
87
  allValues.length === selectedValues.length &&
77
88
  allValues.every((v) => selectedValues.includes(v))) {
78
- // All enum options are selected skip adding criteria for this column
79
- return null;
89
+ // Every enum option is selected, so the only thing this active model can still be excluding
90
+ // is blanks: interactive set filters (agSetColumnFilter and the grid-pro enum filter alike)
91
+ // report an all-inclusive selection as a null model, never as an explicit full list.
92
+ // Returning no criteria here would let blank rows through while the column shows as
93
+ // filtered — exclude blanks instead. Behaviour note: a model listing every VALID_VALUE set
94
+ // programmatically via setFilterModel (or persisted by an older version) previously produced
95
+ // no criteria and now excludes blanks — the faithful set-model reading, since blanks are not
96
+ // in the list.
97
+ return `(${fieldName} != '' && ${fieldName} != null)`;
80
98
  }
81
99
  const orConditions = selectedValues.map((val) => {
100
+ // A null entry is the set-filter convention for blanks; both agSetColumnFilter and the
101
+ // grid-pro enum filter emit it.
102
+ if (val === null) {
103
+ return `(${fieldName} == '' || ${fieldName} == null)`;
104
+ }
82
105
  return `${fieldName} == '${escapeCriteriaValue(val)}'`;
83
106
  });
84
107
  if (orConditions.length > 0) {
@@ -4,13 +4,14 @@ import { avoidTreeShaking, LifecycleMixin, respondToVisibility, } from '@genesis
4
4
  import { baseLayerLuminance, StandardLuminance } from '@microsoft/fast-components';
5
5
  import { attr, DOM, observable } from '@microsoft/fast-element';
6
6
  import { FoundationElement } from '@microsoft/fast-foundation';
7
- import { CellStyleModule, CheckboxEditorModule, ClientSideRowModelApiModule, ClientSideRowModelModule, ColumnApiModule, ColumnAutoSizeModule, createGrid, CsvExportModule, CustomEditorModule, DateEditorModule, DateFilterModule, EventApiModule, HighlightChangesModule, InfiniteRowModelModule, ModuleRegistry, NumberEditorModule, NumberFilterModule, PaginationModule, RenderApiModule, RowApiModule, RowDragModule, RowSelectionModule, RowStyleModule, SelectEditorModule, TextEditorModule, TextFilterModule, TooltipModule, } from 'ag-grid-community';
7
+ import { CellStyleModule, CheckboxEditorModule, ClientSideRowModelApiModule, ClientSideRowModelModule, ColumnApiModule, ColumnAutoSizeModule, createGrid, CsvExportModule, CustomEditorModule, CustomFilterModule, DateEditorModule, DateFilterModule, EventApiModule, HighlightChangesModule, InfiniteRowModelModule, ModuleRegistry, NumberEditorModule, NumberFilterModule, PaginationModule, RenderApiModule, RowApiModule, RowDragModule, RowSelectionModule, RowStyleModule, SelectEditorModule, TextEditorModule, TextFilterModule, TooltipModule, } from 'ag-grid-community';
8
8
  import * as changeCase from 'change-case';
9
9
  import debounce from 'lodash.debounce';
10
10
  import { GridProCell } from './cell';
11
11
  import { DateEditor, MultiselectEditor, NumberEditor, SelectEditor, StringEditor, } from './cell-editors';
12
12
  import { ActionRenderer, ActionsMenuRenderer, BooleanRenderer, EditableRenderer, IconRenderer, SelectRenderer, StatusPillRenderer, } from './cell-renderers';
13
13
  import { GridProColumn, resolveVisibleColumnFields } from './column';
14
+ import { EnumColumnFilter, EnumColumnFloatingFilter, GridProFilterTypes } from './column-filters';
14
15
  import { GridProClientSideDatasource, GridProInfiniteDatasource, GridProServerSideDatasource, } from './datasource';
15
16
  import { baseDatasourceEventNames } from './datasource/base.types';
16
17
  import { GridProGenesisDatasource, gridProGenesisDatasourceEventNames, } from './grid-pro-genesis-datasource';
@@ -47,6 +48,7 @@ ModuleRegistry.registerModules([
47
48
  DateEditorModule,
48
49
  SelectEditorModule,
49
50
  CheckboxEditorModule,
51
+ CustomFilterModule,
50
52
  InfiniteRowModelModule,
51
53
  // ValidationModule,
52
54
  ]);
@@ -501,31 +503,7 @@ export class GridProBeta extends LifecycleMixin(FoundationElement) {
501
503
  if (preSetColumnDefs && preSetColumnDefs.length > 0) {
502
504
  return;
503
505
  }
504
- // ag-grid from v35 is throwing an error if the MultiFilterModule is not registered
505
- // previously it would fallback to the text filter
506
- if (!this.gridApi.isModuleRegistered('MultiFilterModule')) {
507
- schema.forEach((colDef) => {
508
- if (colDef.filter === 'agMultiColumnFilter') {
509
- logger.warn('MultiFilterModule is not registered, falling back to text filter');
510
- colDef.filter = 'agTextColumnFilter';
511
- }
512
- });
513
- }
514
- // Same for the set filter, which enum columns ask for: it is Enterprise, so it only works
515
- // when the app registered SetFilterModule - otherwise AG raises error #200 and the column
516
- // ends up with no working filter at all.
517
- if (!this.gridApi.isModuleRegistered('SetFilterModule')) {
518
- schema.forEach((colDef) => {
519
- if (colDef.filter === 'agSetColumnFilter') {
520
- logger.warn('SetFilterModule is not registered, falling back to text filter');
521
- colDef.filter = 'agTextColumnFilter';
522
- // The set filter's value list means nothing to the text filter.
523
- if (colDef.filterParams) {
524
- delete colDef.filterParams.values;
525
- }
526
- }
527
- });
528
- }
506
+ this.applyCommunityFilterFallbacks(schema);
529
507
  // Merge with template definitions
530
508
  const mergedColumnDefs = yield this.mergeAllColumnDefsAndStates(schema, true);
531
509
  this.gridApi.setGridOption('columnDefs', mergedColumnDefs);
@@ -537,6 +515,58 @@ export class GridProBeta extends LifecycleMixin(FoundationElement) {
537
515
  this.restoreCachedFilterConfig();
538
516
  });
539
517
  }
518
+ /**
519
+ * Downgrades enterprise filters in metadata-generated colDefs when their modules are not
520
+ * registered — from v35 AG Grid throws on unregistered filters instead of falling back.
521
+ * Enum columns (recognised by their metadata-sourced set-filter values) keep those values by
522
+ * falling back to the community `EnumColumnFilter` instead of a plain text filter.
523
+ *
524
+ * The enum floating filter is only wired as the column's component, not enabled: AG's floating
525
+ * filter is a full-width header row, so enabling it for one column changes the layout of every
526
+ * column. Active-filter state is surfaced instead by AG's native header filter icon plus the
527
+ * header tooltip the enum filter maintains; consumers wanting the floating row opt in with
528
+ * `floatingFilter: true`.
529
+ * @internal
530
+ */
531
+ applyCommunityFilterFallbacks(schema) {
532
+ const hasSetFilter = this.gridApi.isModuleRegistered('SetFilterModule');
533
+ const hasMultiFilter = this.gridApi.isModuleRegistered('MultiFilterModule');
534
+ schema.forEach((colDef) => {
535
+ var _a, _b, _c, _d, _e;
536
+ if (colDef.filter === 'agSetColumnFilter' && !hasSetFilter) {
537
+ logger.debug(`SetFilterModule is not registered; column '${colDef.field}' falls back to the enum filter`);
538
+ colDef.filter = GridProFilterTypes.enumFilter;
539
+ (_a = colDef.floatingFilterComponent) !== null && _a !== void 0 ? _a : (colDef.floatingFilterComponent = GridProFilterTypes.enumFloatingFilter);
540
+ return;
541
+ }
542
+ if (colDef.filter !== 'agMultiColumnFilter') {
543
+ return;
544
+ }
545
+ const setSubFilter = (_c = (_b = colDef.filterParams) === null || _b === void 0 ? void 0 : _b.filters) === null || _c === void 0 ? void 0 : _c.find((subFilter) => subFilter.filter === 'agSetColumnFilter');
546
+ if (!hasMultiFilter) {
547
+ if ((_d = setSubFilter === null || setSubFilter === void 0 ? void 0 : setSubFilter.filterParams) === null || _d === void 0 ? void 0 : _d.values) {
548
+ logger.debug(`MultiFilterModule is not registered; enum column '${colDef.field}' falls back to the enum filter`);
549
+ colDef.filter = GridProFilterTypes.enumFilter;
550
+ // Carry the whole sub-filter config over, not just `values` — a consumer-authored
551
+ // multi filter may also set valueFormatter, blanks, etc.
552
+ colDef.filterParams = Object.assign({}, setSubFilter.filterParams);
553
+ (_e = colDef.floatingFilterComponent) !== null && _e !== void 0 ? _e : (colDef.floatingFilterComponent = GridProFilterTypes.enumFloatingFilter);
554
+ }
555
+ else {
556
+ logger.warn('MultiFilterModule is not registered, falling back to text filter');
557
+ colDef.filter = 'agTextColumnFilter';
558
+ }
559
+ return;
560
+ }
561
+ // The multi filter itself is available but its set sub-filter's module is not — opening
562
+ // the filter would throw AG error #256. The multi filter hosts custom child filters, so
563
+ // only the nested set filter is swapped for the enum filter (same params, same model).
564
+ if (!hasSetFilter && setSubFilter) {
565
+ logger.debug(`SetFilterModule is not registered; the set sub-filter of column '${colDef.field}' falls back to the enum filter`);
566
+ setSubFilter.filter = GridProFilterTypes.enumFilter;
567
+ }
568
+ });
569
+ }
540
570
  /**
541
571
  * Handles data clearing from datasource
542
572
  * @internal
@@ -729,6 +759,8 @@ export class GridProBeta extends LifecycleMixin(FoundationElement) {
729
759
  [GridProRendererTypes.multiselectEditor]: MultiselectEditor,
730
760
  [GridProRendererTypes.dateEditor]: DateEditor,
731
761
  [GridProRendererTypes.stringEditor]: StringEditor,
762
+ [GridProFilterTypes.enumFilter]: EnumColumnFilter,
763
+ [GridProFilterTypes.enumFloatingFilter]: EnumColumnFloatingFilter,
732
764
  [GridProStatusBarTypes.labelValue]: LabelValueStatusBarComponent,
733
765
  [GridProStatusBarTypes.loadMore]: LoadMoreStatusBarComponent,
734
766
  [GridProStatusBarTypes.reload]: ReloadStatusBarComponent,
@@ -1183,7 +1215,7 @@ export class GridProBeta extends LifecycleMixin(FoundationElement) {
1183
1215
  const templateColumnDefs = Array.from(this.querySelectorAll(this.columnComponentName))
1184
1216
  .map((templateColumn) => templateColumn.definition)
1185
1217
  .map((columnDef) => {
1186
- var _a, _b;
1218
+ var _a, _b, _c, _d, _e, _f;
1187
1219
  // enable cell flashing for each column if unspecified on column level but enabled on grid level
1188
1220
  if (this.enableCellFlashing && columnDef.enableCellChangeFlash === undefined) {
1189
1221
  columnDef.enableCellChangeFlash = true;
@@ -1194,14 +1226,21 @@ export class GridProBeta extends LifecycleMixin(FoundationElement) {
1194
1226
  * respect that choice and don't inject metadata values. This allows consumers to
1195
1227
  * opt out of metadata values and let AG Grid extract values from row data instead.
1196
1228
  */
1197
- if (columnDef.filter === 'agSetColumnFilter') {
1229
+ if (columnDef.filter === 'agSetColumnFilter' ||
1230
+ columnDef.filter === GridProFilterTypes.enumFilter) {
1198
1231
  const hasExplicitValues = columnDef.filterParams != null && 'values' in columnDef.filterParams;
1199
1232
  if (!hasExplicitValues) {
1200
- const metadataValues = (_b = (_a = columnDefinitionsFromMetadata.find((colDef) => colDef.field === columnDef.field)) === null || _a === void 0 ? void 0 : _a.filterParams) === null || _b === void 0 ? void 0 : _b.values;
1233
+ const metadataFilterParams = (_a = columnDefinitionsFromMetadata.find((colDef) => colDef.field === columnDef.field)) === null || _a === void 0 ? void 0 : _a.filterParams;
1234
+ // Metadata enum values are flat ({ values }) on the server-side datasource path, but
1235
+ // nested inside a multi-filter's set sub-filter on the client-side datasource path.
1236
+ const metadataValues = (_b = metadataFilterParams === null || metadataFilterParams === void 0 ? void 0 : metadataFilterParams.values) !== null && _b !== void 0 ? _b : (_e = (_d = (_c = metadataFilterParams === null || metadataFilterParams === void 0 ? void 0 : metadataFilterParams.filters) === null || _c === void 0 ? void 0 : _c.find((subFilter) => subFilter.filter === 'agSetColumnFilter')) === null || _d === void 0 ? void 0 : _d.filterParams) === null || _e === void 0 ? void 0 : _e.values;
1201
1237
  if (metadataValues) {
1202
1238
  columnDef.filterParams = Object.assign(Object.assign({}, columnDef.filterParams), { values: metadataValues });
1203
1239
  }
1204
1240
  }
1241
+ if (columnDef.filter === GridProFilterTypes.enumFilter) {
1242
+ (_f = columnDef.floatingFilterComponent) !== null && _f !== void 0 ? _f : (columnDef.floatingFilterComponent = GridProFilterTypes.enumFloatingFilter);
1243
+ }
1205
1244
  }
1206
1245
  if (columnDef.editable) {
1207
1246
  if (!columnDef.cellRenderer && !columnDef.cellRendererSelector) {
package/dist/esm/index.js CHANGED
@@ -2,6 +2,7 @@ export * from './cell';
2
2
  export * from './cell-renderers';
3
3
  export * from './cell-editors';
4
4
  export * from './column';
5
+ export * from './column-filters';
5
6
  export * from './datasource';
6
7
  export * from './external';
7
8
  export * from './grid-components';