@contrail/data-grouping 1.1.0 → 1.2.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.
@@ -0,0 +1,3 @@
1
+ {
2
+ "js/ts.tsdk.path": "node_modules/typescript/lib"
3
+ }
package/CHANGELOG.md CHANGED
@@ -7,6 +7,12 @@ Versioning follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [1.2.0] - 2026-06-05
11
+
12
+ ### Added
13
+
14
+ - `buildDataGroupStructure` now accepts an optional trailing `filterDefinition` argument. When a grouping property is multi-select and the same property is filtered, the library derives an include/exclude rule (new `deriveValueFilterRule`) and prunes the fan-out to the filter-selected values — so consumers no longer translate filter criteria into a grouping rule themselves. Backwards-compatible: existing positional calls are unaffected and `DataGroupingProperty.valueFilter` is retained (now also populated internally). Adds an `@contrail/filters` dependency. (VIBE-10759)
15
+
10
16
  ## [1.1.0] - 2026-06-03
11
17
 
12
18
  ### Added
@@ -1,5 +1,6 @@
1
- import { DataGroup, DataGroupStructure, DataGroupingProperty } from '../interfaces';
1
+ import { DataGroup, DataGroupStructure, DataGroupingProperty, GroupingValueFilterRule } from '../interfaces';
2
2
  import { TypePropertySortOrder } from '@contrail/types';
3
+ import { FilterDefinition } from '@contrail/filters';
3
4
  export declare class DataGroupGenerator {
4
5
  static isEmptyGroupingValue(value: any): boolean;
5
6
  static getDistinctValues(data: any, rootIndex: any, slugIndex?: any, rootAltIndex?: any, slugAltIndex?: any, groupMultiSelectInSeparateFrame?: boolean, sortOptions?: {
@@ -9,8 +10,9 @@ export declare class DataGroupGenerator {
9
10
  isDate: boolean;
10
11
  isNumber: boolean;
11
12
  }, displayItemsWithEmptyGroupingValues?: boolean, displayOptionFrameWithNoData?: boolean): any[];
12
- static applyGroupingValueFilter(distinctValues: Array<any>, groupingProperty: DataGroupingProperty, groupMultiSelectInSeparateFrame: boolean): Array<any>;
13
- static buildChildDataGroups(data: any, parentGroup: DataGroup, groupingProperties: Array<DataGroupingProperty>, leafNodeDataCount: any, currentDepth: any, groupMultiSelectInSeparateFrame?: boolean, displayItemsWithEmptyGroupingValues?: boolean, displayOptionFrameWithNoData?: boolean): void;
14
- static buildDataGroupStructure(data: Array<any>, groupingProperties: Array<DataGroupingProperty>, leafNodeDataCount: number, groupMultiSelectInSeparateFrame?: boolean, displayItemsWithEmptyGroupingValues?: boolean, displayOptionFrameWithNoData?: boolean): DataGroupStructure;
13
+ static deriveValueFilterRule(groupingProperty: DataGroupingProperty, filterDefinition?: FilterDefinition): GroupingValueFilterRule | null;
14
+ static applyGroupingValueFilter<T>(distinctValues: Array<T>, groupingProperty: DataGroupingProperty, groupMultiSelectInSeparateFrame: boolean): Array<T>;
15
+ static buildChildDataGroups(data: any, parentGroup: DataGroup, groupingProperties: Array<DataGroupingProperty>, leafNodeDataCount: any, currentDepth: any, groupMultiSelectInSeparateFrame?: boolean, displayItemsWithEmptyGroupingValues?: boolean, displayOptionFrameWithNoData?: boolean, filterDefinition?: FilterDefinition): void;
16
+ static buildDataGroupStructure(data: Array<any>, groupingProperties: Array<DataGroupingProperty>, leafNodeDataCount: number, groupMultiSelectInSeparateFrame?: boolean, displayItemsWithEmptyGroupingValues?: boolean, displayOptionFrameWithNoData?: boolean, filterDefinition?: FilterDefinition): DataGroupStructure;
15
17
  static createPartitionedGroupsFromData(parentGroup: DataGroup, data: Array<any>, leafNodeDataCount: number): Array<DataGroup>;
16
18
  }
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.DataGroupGenerator = void 0;
4
4
  const util_1 = require("@contrail/util");
5
5
  const types_1 = require("@contrail/types");
6
+ const filters_1 = require("@contrail/filters");
6
7
  class DataGroupGenerator {
7
8
  static isEmptyGroupingValue(value) {
8
9
  return ((value === undefined ||
@@ -114,6 +115,27 @@ class DataGroupGenerator {
114
115
  }
115
116
  return distinctValues;
116
117
  }
118
+ static deriveValueFilterRule(groupingProperty, filterDefinition) {
119
+ var _a, _b;
120
+ if (!filterDefinition || ((_a = groupingProperty === null || groupingProperty === void 0 ? void 0 : groupingProperty.propertyDefinition) === null || _a === void 0 ? void 0 : _a.propertyType) !== types_1.PropertyType.MultiSelect) {
121
+ return null;
122
+ }
123
+ const propertyCriteria = ((_b = filterDefinition === null || filterDefinition === void 0 ? void 0 : filterDefinition.filterCriteria) === null || _b === void 0 ? void 0 : _b.propertyCriteria) || [];
124
+ const expectedSlug = util_1.StringUtil.convertToCamelCase(groupingProperty.typeRootSlug) + '.' + groupingProperty.propertyDefinition.slug;
125
+ const matching = propertyCriteria.filter((criterion) => { var _a; return ((_a = criterion === null || criterion === void 0 ? void 0 : criterion.filterPropertyDefinition) === null || _a === void 0 ? void 0 : _a.slug) === expectedSlug; });
126
+ if (matching.length !== 1 || !Array.isArray(matching[0].criteriaValue)) {
127
+ return null;
128
+ }
129
+ const criterion = matching[0];
130
+ if (criterion.filterConditionType === filters_1.FilterConditionType.IS_ANY_OF ||
131
+ criterion.filterConditionType === filters_1.FilterConditionType.EQUALS) {
132
+ return { mode: 'include', values: criterion.criteriaValue };
133
+ }
134
+ if (criterion.filterConditionType === filters_1.FilterConditionType.IS_NONE_OF) {
135
+ return { mode: 'exclude', values: criterion.criteriaValue };
136
+ }
137
+ return null;
138
+ }
117
139
  static applyGroupingValueFilter(distinctValues, groupingProperty, groupMultiSelectInSeparateFrame) {
118
140
  var _a;
119
141
  const rule = groupingProperty === null || groupingProperty === void 0 ? void 0 : groupingProperty.valueFilter;
@@ -132,7 +154,7 @@ class DataGroupGenerator {
132
154
  return rule.mode === 'exclude' ? !ruleValues.has(value) : ruleValues.has(value);
133
155
  });
134
156
  }
135
- static buildChildDataGroups(data, parentGroup, groupingProperties, leafNodeDataCount, currentDepth, groupMultiSelectInSeparateFrame = false, displayItemsWithEmptyGroupingValues = false, displayOptionFrameWithNoData = false) {
157
+ static buildChildDataGroups(data, parentGroup, groupingProperties, leafNodeDataCount, currentDepth, groupMultiSelectInSeparateFrame = false, displayItemsWithEmptyGroupingValues = false, displayOptionFrameWithNoData = false, filterDefinition) {
136
158
  var _a, _b, _c, _d, _e;
137
159
  const groupingProperty = groupingProperties[currentDepth];
138
160
  const isDateProperty = ((_a = groupingProperty === null || groupingProperty === void 0 ? void 0 : groupingProperty.propertyDefinition) === null || _a === void 0 ? void 0 : _a.propertyType) === 'date';
@@ -149,7 +171,12 @@ class DataGroupGenerator {
149
171
  const sort = groupingProperty.sort || types_1.TypePropertySortOrder.ASCENDING;
150
172
  const options = ((_e = (_d = groupingProperty.propertyDefinition) === null || _d === void 0 ? void 0 : _d.options) === null || _e === void 0 ? void 0 : _e.map((x) => x.value)) || null;
151
173
  let distinctValues = this.getDistinctValues(data, rootIndex, slugIndex, rootAltIndex, slugAltIndex, groupMultiSelectInSeparateFrame, { sortOrder: sort, options }, propertyTypeOptions, displayItemsWithEmptyGroupingValues, displayOptionFrameWithNoData);
152
- distinctValues = this.applyGroupingValueFilter(distinctValues, groupingProperty, groupMultiSelectInSeparateFrame);
174
+ let effectiveGroupingProperty = groupingProperty;
175
+ const derivedRule = this.deriveValueFilterRule(groupingProperty, filterDefinition);
176
+ if (derivedRule) {
177
+ effectiveGroupingProperty = Object.assign(Object.assign({}, groupingProperty), { valueFilter: derivedRule });
178
+ }
179
+ distinctValues = this.applyGroupingValueFilter(distinctValues, effectiveGroupingProperty, groupMultiSelectInSeparateFrame);
153
180
  for (let val of distinctValues) {
154
181
  const groupData = data.filter((obj) => {
155
182
  const objVal = util_1.ObjectUtil.getBySlugs(obj, rootIndex, slugIndex) || util_1.ObjectUtil.getBySlugs(obj, rootAltIndex, slugAltIndex);
@@ -196,12 +223,12 @@ class DataGroupGenerator {
196
223
  group.subGroups = this.createPartitionedGroupsFromData(group, groupData, leafNodeDataCount);
197
224
  }
198
225
  else if (currentDepth < groupingProperties.length - 1) {
199
- this.buildChildDataGroups(groupData, group, groupingProperties, leafNodeDataCount, currentDepth + 1, groupMultiSelectInSeparateFrame, displayItemsWithEmptyGroupingValues, displayOptionFrameWithNoData);
226
+ this.buildChildDataGroups(groupData, group, groupingProperties, leafNodeDataCount, currentDepth + 1, groupMultiSelectInSeparateFrame, displayItemsWithEmptyGroupingValues, displayOptionFrameWithNoData, filterDefinition);
200
227
  }
201
228
  parentGroup.subGroups.push(group);
202
229
  }
203
230
  }
204
- static buildDataGroupStructure(data, groupingProperties, leafNodeDataCount, groupMultiSelectInSeparateFrame = false, displayItemsWithEmptyGroupingValues = false, displayOptionFrameWithNoData = false) {
231
+ static buildDataGroupStructure(data, groupingProperties, leafNodeDataCount, groupMultiSelectInSeparateFrame = false, displayItemsWithEmptyGroupingValues = false, displayOptionFrameWithNoData = false, filterDefinition) {
205
232
  const structure = {
206
233
  rootGroup: {
207
234
  subGroups: [],
@@ -212,7 +239,7 @@ class DataGroupGenerator {
212
239
  groupingProperties,
213
240
  depth: groupingProperties ? groupingProperties.length : 0,
214
241
  };
215
- this.buildChildDataGroups(data, structure.rootGroup, groupingProperties, leafNodeDataCount, 0, groupMultiSelectInSeparateFrame, displayItemsWithEmptyGroupingValues, displayOptionFrameWithNoData);
242
+ this.buildChildDataGroups(data, structure.rootGroup, groupingProperties, leafNodeDataCount, 0, groupMultiSelectInSeparateFrame, displayItemsWithEmptyGroupingValues, displayOptionFrameWithNoData, filterDefinition);
216
243
  return structure;
217
244
  }
218
245
  static createPartitionedGroupsFromData(parentGroup, data, leafNodeDataCount) {
@@ -22,14 +22,15 @@ export interface DataGroupStructure {
22
22
  sortDefinition?: any;
23
23
  };
24
24
  }
25
+ export interface GroupingValueFilterRule {
26
+ mode: 'include' | 'exclude';
27
+ values: Array<string>;
28
+ }
25
29
  export interface DataGroupingProperty {
26
30
  propertyDefinition: TypeProperty;
27
31
  values?: Array<string>;
28
32
  typeRootSlug: string;
29
33
  sort: TypePropertySortOrder;
30
34
  isSecondaryGroup?: boolean;
31
- valueFilter?: {
32
- mode: 'include' | 'exclude';
33
- values: Array<string>;
34
- };
35
+ valueFilter?: GroupingValueFilterRule;
35
36
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contrail/data-grouping",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "Utilities and interfaces for grouping data into hierarchial data structures based on properties.",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -14,7 +14,6 @@
14
14
  "author": "",
15
15
  "license": "ISC",
16
16
  "devDependencies": {
17
- "@contrail/util": "^1.3.0",
18
17
  "@types/jest": "^29.5.2",
19
18
  "jest": "^29.5.0",
20
19
  "prettier": "^1.19.1",
@@ -39,6 +38,8 @@
39
38
  },
40
39
  "dependencies": {
41
40
  "@contrail/documents": "^1.5.0",
42
- "@contrail/types": "^3.4.0"
41
+ "@contrail/filters": "^1.3.0",
42
+ "@contrail/types": "^3.4.0",
43
+ "@contrail/util": "^1.3.0"
43
44
  }
44
45
  }