@contrail/data-grouping 1.0.53-alpha.1 → 1.2.0-alpha.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/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,14 @@ 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-04
|
|
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
|
+
|
|
16
|
+
## [1.1.0] - 2026-06-03
|
|
17
|
+
|
|
10
18
|
### Added
|
|
11
19
|
|
|
12
20
|
- `DataGroupingProperty.valueFilter` (`{ mode: 'include' | 'exclude'; values: string[] }`): an optional, caller-supplied rule that restricts a multi-select grouping property's frames to the filter-selected values. Applied in `buildChildDataGroups` via the new `applyGroupingValueFilter` after `getDistinctValues` — pruning the fan-out to the included values (or dropping the excluded ones), while preserving the `(empty)` bucket. No-op for separate-frame mode (`groupMultiSelectInSeparateFrame`) and for non-multi-select grouping. Keeps this package decoupled from `@contrail/filters`: the caller translates its filter criteria into the rule. (VIBE-10759)
|
|
@@ -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[];
|
|
13
|
+
static deriveValueFilterRule(groupingProperty: DataGroupingProperty, filterDefinition?: FilterDefinition): GroupingValueFilterRule | null;
|
|
12
14
|
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;
|
|
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
|
-
|
|
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) {
|
package/lib/interfaces.d.ts
CHANGED
|
@@ -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.0
|
|
3
|
+
"version": "1.2.0-alpha.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/
|
|
41
|
+
"@contrail/filters": "^1.3.0",
|
|
42
|
+
"@contrail/types": "^3.4.0",
|
|
43
|
+
"@contrail/util": "^1.3.0"
|
|
43
44
|
}
|
|
44
45
|
}
|