Skip to content

Commit 4b17449

Browse files
committed
Adress comments
1 parent a0f2c43 commit 4b17449

File tree

7 files changed

+260
-253
lines changed

7 files changed

+260
-253
lines changed

packages/itwin/tree-widget/src/tree-widget-react/components/trees/categories-tree/internal/CategoriesTreeVisibilityHandler.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ class CategoriesTreeVisibilityHandlerImpl implements HierarchyVisibilityHandler
235235

236236
private getFilteredNodeVisibility(props: GetFilteredNodeVisibilityProps) {
237237
return from(this.getFilteredTreeTargets(props)).pipe(
238-
mergeMap(({ targets }) => {
238+
mergeMap((targets) => {
239239
if (!targets) {
240240
return EMPTY;
241241
}
@@ -657,12 +657,12 @@ class CategoriesTreeVisibilityHandlerImpl implements HierarchyVisibilityHandler
657657

658658
private async getFilteredTreeTargets({ node }: GetFilteredNodeVisibilityProps) {
659659
const filteredTree = await this._filteredTree;
660-
return filteredTree ? filteredTree.getFilterTargets(node) : {};
660+
return filteredTree ? filteredTree.getFilterTargets(node) : undefined;
661661
}
662662

663663
private changeFilteredNodeVisibility({ on, ...props }: ChangeFilteredNodeVisibilityProps) {
664664
return from(this.getFilteredTreeTargets(props)).pipe(
665-
mergeMap(({ targets }) => {
665+
mergeMap((targets) => {
666666
if (!targets) {
667667
return EMPTY;
668668
}

packages/itwin/tree-widget/src/tree-widget-react/components/trees/categories-tree/internal/FilteredTree.ts

Lines changed: 104 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,18 @@ import type { Id64Set, Id64String } from "@itwin/core-bentley";
1111
import type { HierarchyNode } from "@itwin/presentation-hierarchies";
1212
import type { ECClassHierarchyInspector, InstanceKey } from "@itwin/presentation-shared";
1313
import type { CategoryId, ElementId, ModelId, SubCategoryId } from "../../common/internal/Types.js";
14-
import type { FilteredTree, FilteredVisibilityTargets } from "../../common/internal/visibility/BaseFilteredTree.js";
14+
import type { FilteredTree } from "../../common/internal/visibility/BaseFilteredTree.js";
1515
import type { CategoriesTreeIdsCache } from "./CategoriesTreeIdsCache.js";
1616

17+
/** @internal */
18+
export interface CategoriesTreeFilterTargets {
19+
categories?: Array<{ modelId: Id64String | undefined; categoryIds: Id64Set }>;
20+
elements?: Array<{ modelId: Id64String; categoryId: Id64String; elementIds: Id64Set }>;
21+
definitionContainerIds?: Id64Set;
22+
modelIds?: Id64Set;
23+
subCategories?: Array<{ categoryId: Id64String; subCategoryIds: Id64Set }>;
24+
}
25+
1726
interface FilteredTreeRootNode {
1827
children: Map<Id64String, FilteredTreeNode>;
1928
}
@@ -64,35 +73,6 @@ type TemporaryFilteredTreeNode =
6473
| TemporaryElementFilteredNode
6574
| ModelFilteredTreeNode;
6675

67-
type ModelCategoryKey = `${ModelId}-${CategoryId}`;
68-
69-
function createModelCategoryKey(modelId: Id64String, categoryId: Id64String): ModelCategoryKey {
70-
return `${modelId}-${categoryId}`;
71-
}
72-
73-
/** @internal */
74-
function parseModelCategoryKey(key: ModelCategoryKey): { modelId: Id64String; categoryId: Id64String } {
75-
const [modelId, categoryId] = key.split("-");
76-
return { modelId, categoryId };
77-
}
78-
79-
/** @internal */
80-
export interface CategoriesTreeFilterTargets {
81-
categories?: Array<{ modelId: Id64String | undefined; categoryIds: Id64Set }>;
82-
elements?: Array<{ modelId: Id64String; categoryId: Id64String; elementIds: Id64Set }>;
83-
definitionContainerIds?: Id64Set;
84-
modelIds?: Id64Set;
85-
subCategories?: Array<{ categoryId: Id64String; subCategoryIds: Id64Set }>;
86-
}
87-
88-
interface FilterTargetsInternal {
89-
elements?: Map<ModelCategoryKey, Set<ElementId>>;
90-
categories?: Map<ModelId | undefined, Set<CategoryId>>;
91-
definitionContainerIds?: Id64Set;
92-
modelIds?: Id64Set;
93-
subCategories?: Map<CategoryId, Set<SubCategoryId>>;
94-
}
95-
9676
/** @internal */
9777
export async function createFilteredTree(props: {
9878
imodelAccess: ECClassHierarchyInspector;
@@ -155,13 +135,13 @@ export async function createFilteredTree(props: {
155135
};
156136
}
157137

158-
function getFilterTargets(root: FilteredTreeRootNode, node: HierarchyNode): FilteredVisibilityTargets<CategoriesTreeFilterTargets> {
138+
function getFilterTargets(root: FilteredTreeRootNode, node: HierarchyNode): CategoriesTreeFilterTargets | undefined {
139+
const filterTargetsHandler = new FilterTargetsHandler();
159140
let lookupParents: Array<{ children?: Map<Id64String, FilteredTreeNode> }> = [root];
160-
const filterTargets: FilterTargetsInternal = {};
161141

162142
const nodeKey = node.key;
163143
if (!HierarchyNodeKey.isInstances(nodeKey)) {
164-
return {};
144+
return undefined;
165145
}
166146

167147
// find the filtered parent nodes of the `node`
@@ -174,31 +154,43 @@ function getFilterTargets(root: FilteredTreeRootNode, node: HierarchyNode): Filt
174154
// and use them when checking for matching node in one level deeper.
175155
const parentNodes = findMatchingFilteredNodes(lookupParents, parentKey.instanceKeys);
176156
if (parentNodes.length === 0) {
177-
return {};
157+
return undefined;
178158
}
179159
lookupParents = parentNodes;
180160
}
181161

182162
// find filtered nodes that match the `node`
183163
const filteredNodes = findMatchingFilteredNodes(lookupParents, nodeKey.instanceKeys);
184164
if (filteredNodes.length === 0) {
185-
return {};
165+
return undefined;
186166
}
167+
const filterTargets: FilterTargetsInternal = {};
187168

188-
filteredNodes.forEach((filteredNode) => collectFilterTargets(filterTargets, filteredNode));
169+
filteredNodes.forEach((filteredNode) => filterTargetsHandler.collectFilterTargets(filterTargets, filteredNode));
189170

190-
if (
191-
!filterTargets.categories &&
192-
!filterTargets.definitionContainerIds &&
193-
!filterTargets.elements &&
194-
!filterTargets.modelIds &&
195-
!filterTargets.subCategories
196-
) {
197-
return {};
198-
}
171+
return filterTargetsHandler.convertInternalFilterTargets(filterTargets);
172+
}
199173

200-
return {
201-
targets: {
174+
interface FilterTargetsInternal {
175+
elements?: Map<ModelCategoryKey, Set<ElementId>>;
176+
categories?: Map<ModelId | undefined, Set<CategoryId>>;
177+
definitionContainerIds?: Id64Set;
178+
modelIds?: Id64Set;
179+
subCategories?: Map<CategoryId, Set<SubCategoryId>>;
180+
}
181+
182+
class FilterTargetsHandler {
183+
public convertInternalFilterTargets(filterTargets: FilterTargetsInternal): CategoriesTreeFilterTargets | undefined {
184+
if (
185+
!filterTargets.categories &&
186+
!filterTargets.definitionContainerIds &&
187+
!filterTargets.elements &&
188+
!filterTargets.modelIds &&
189+
!filterTargets.subCategories
190+
) {
191+
return undefined;
192+
}
193+
return {
202194
categories: filterTargets.categories
203195
? [...filterTargets.categories.entries()].map(([modelId, categoryIds]) => {
204196
return { modelId, categoryIds };
@@ -217,72 +209,83 @@ function getFilterTargets(root: FilteredTreeRootNode, node: HierarchyNode): Filt
217209
return { categoryId, subCategoryIds };
218210
})
219211
: undefined,
220-
},
221-
};
222-
}
223-
224-
function findMatchingFilteredNodes(lookupParents: Array<{ children?: Map<Id64String, FilteredTreeNode> }>, keys: InstanceKey[]) {
225-
return lookupParents
226-
.flatMap((lookup) => keys.map((key) => lookup.children?.get(key.id)))
227-
.filter((lookupNode): lookupNode is FilteredTreeNode => lookupNode !== undefined);
228-
}
229-
230-
function collectFilterTargets(changeTargets: FilterTargetsInternal, filteredNode: FilteredTreeNode) {
231-
if (filteredNode.isFilterTarget) {
232-
addTarget(changeTargets, filteredNode);
233-
return;
212+
};
234213
}
235214

236-
if (filteredNode.type === "element") {
237-
// need to add parent ids as filter target will be an element
238-
addTarget(changeTargets, filteredNode);
239-
}
215+
public collectFilterTargets(changeTargets: FilterTargetsInternal, filteredNode: FilteredTreeNode) {
216+
if (filteredNode.isFilterTarget) {
217+
this.addTarget(changeTargets, filteredNode);
218+
return;
219+
}
240220

241-
if (!filteredNode.children) {
242-
return;
243-
}
221+
if (filteredNode.type === "element") {
222+
// need to add parent ids as filter target will be an element
223+
this.addTarget(changeTargets, filteredNode);
224+
}
225+
226+
if (!filteredNode.children) {
227+
return;
228+
}
244229

245-
for (const child of filteredNode.children.values()) {
246-
collectFilterTargets(changeTargets, child);
230+
for (const child of filteredNode.children.values()) {
231+
this.collectFilterTargets(changeTargets, child);
232+
}
247233
}
248-
}
249234

250-
function addTarget(filterTargets: FilterTargetsInternal, node: FilteredTreeNode) {
251-
switch (node.type) {
252-
case "definitionContainer":
253-
(filterTargets.definitionContainerIds ??= new Set()).add(node.id);
254-
return;
255-
case "model":
256-
(filterTargets.modelIds ??= new Set()).add(node.id);
257-
return;
258-
case "subCategory":
259-
const subCategories = (filterTargets.subCategories ??= new Map()).get(node.categoryId);
260-
if (subCategories) {
261-
subCategories.add(node.id);
235+
private addTarget(filterTargets: FilterTargetsInternal, node: FilteredTreeNode) {
236+
switch (node.type) {
237+
case "definitionContainer":
238+
(filterTargets.definitionContainerIds ??= new Set()).add(node.id);
262239
return;
263-
}
264-
filterTargets.subCategories.set(node.categoryId, new Set([node.id]));
265-
return;
266-
case "category":
267-
const categories = (filterTargets.categories ??= new Map()).get(node.modelId);
268-
if (!categories) {
269-
categories.add(node.id);
240+
case "model":
241+
(filterTargets.modelIds ??= new Set()).add(node.id);
270242
return;
271-
}
272-
filterTargets.categories.set(node.modelId, new Set([node.id]));
273-
return;
274-
case "element":
275-
const modelCategoryKey = createModelCategoryKey(node.modelId, node.categoryId);
276-
const elements = (filterTargets.elements ??= new Map()).get(modelCategoryKey);
277-
if (elements) {
278-
elements.add(node.id);
243+
case "subCategory":
244+
const subCategories = (filterTargets.subCategories ??= new Map()).get(node.categoryId);
245+
if (subCategories) {
246+
subCategories.add(node.id);
247+
return;
248+
}
249+
filterTargets.subCategories.set(node.categoryId, new Set([node.id]));
279250
return;
280-
}
281-
filterTargets.elements.set(modelCategoryKey, new Set([node.id]));
282-
return;
251+
case "category":
252+
const categories = (filterTargets.categories ??= new Map()).get(node.modelId);
253+
if (!categories) {
254+
categories.add(node.id);
255+
return;
256+
}
257+
filterTargets.categories.set(node.modelId, new Set([node.id]));
258+
return;
259+
case "element":
260+
const modelCategoryKey = createModelCategoryKey(node.modelId, node.categoryId);
261+
const elements = (filterTargets.elements ??= new Map()).get(modelCategoryKey);
262+
if (elements) {
263+
elements.add(node.id);
264+
return;
265+
}
266+
filterTargets.elements.set(modelCategoryKey, new Set([node.id]));
267+
return;
268+
}
283269
}
284270
}
285271

272+
type ModelCategoryKey = `${ModelId}-${CategoryId}`;
273+
274+
function createModelCategoryKey(modelId: Id64String, categoryId: Id64String): ModelCategoryKey {
275+
return `${modelId}-${categoryId}`;
276+
}
277+
278+
function parseModelCategoryKey(key: ModelCategoryKey): { modelId: Id64String; categoryId: Id64String } {
279+
const [modelId, categoryId] = key.split("-");
280+
return { modelId, categoryId };
281+
}
282+
283+
function findMatchingFilteredNodes(lookupParents: Array<{ children?: Map<Id64String, FilteredTreeNode> }>, keys: InstanceKey[]) {
284+
return lookupParents
285+
.flatMap((lookup) => keys.map((key) => lookup.children?.get(key.id)))
286+
.filter((lookupNode): lookupNode is FilteredTreeNode => lookupNode !== undefined);
287+
}
288+
286289
function createFilteredTreeNode({
287290
type,
288291
id,

packages/itwin/tree-widget/src/tree-widget-react/components/trees/classifications-tree/internal/ClassificationsTreeVisibilityHandler.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ class ClassificationsTreeVisibilityHandlerImpl implements HierarchyVisibilityHan
196196

197197
private getFilteredNodeVisibility(props: GetFilteredNodeVisibilityProps) {
198198
return from(this.getFilteredTreeTargets(props)).pipe(
199-
mergeMap(({ targets }) => {
199+
mergeMap((targets) => {
200200
if (!targets) {
201201
return EMPTY;
202202
}
@@ -247,7 +247,7 @@ class ClassificationsTreeVisibilityHandlerImpl implements HierarchyVisibilityHan
247247

248248
private async getFilteredTreeTargets({ node }: GetFilteredNodeVisibilityProps) {
249249
const filteredTree = await this._filteredTree;
250-
return filteredTree ? filteredTree.getFilterTargets(node) : {};
250+
return filteredTree ? filteredTree.getFilterTargets(node) : undefined;
251251
}
252252

253253
private getClassificationTablesVisibilityStatus(props: { classificationTableIds: Id64Arg }): Observable<VisibilityStatus> {
@@ -621,7 +621,7 @@ class ClassificationsTreeVisibilityHandlerImpl implements HierarchyVisibilityHan
621621

622622
private changeFilteredNodeVisibility({ on, ...props }: ChangeFilteredNodeVisibilityProps) {
623623
return from(this.getFilteredTreeTargets(props)).pipe(
624-
mergeMap(({ targets }) => {
624+
mergeMap((targets) => {
625625
if (!targets) {
626626
return EMPTY;
627627
}

0 commit comments

Comments
 (0)