diff --git a/src/views/viewBase.ts b/src/views/viewBase.ts index d49ee3a..7376a4a 100644 --- a/src/views/viewBase.ts +++ b/src/views/viewBase.ts @@ -153,6 +153,113 @@ export abstract class ViewBase> implements TreeData return this._tree !== undefined ? this._tree.visible : false; } + async findNode( + id: string, + options?: { + allowPaging?: boolean; + getChildren?: (node: ViewNode) => ViewNode[] | Promise; + maxDepth?: number; + } + ): Promise; + async findNode( + predicate: (node: ViewNode) => boolean, + options?: { + allowPaging?: boolean; + getChildren?: (node: ViewNode) => ViewNode[] | Promise; + maxDepth?: number; + } + ): Promise; + @log({ + args: { + 0: (predicate: string | ((node: ViewNode) => boolean)) => + typeof predicate === 'string' ? predicate : false + } + }) + async findNode( + predicate: string | ((node: ViewNode) => boolean), + { + allowPaging = false, + getChildren, + maxDepth = 2 + }: { + allowPaging?: boolean; + getChildren?: (node: ViewNode) => ViewNode[] | Promise; + maxDepth?: number; + } = {} + ): Promise { + if (getChildren === undefined) { + getChildren = n => n.getChildren(); + } + + // If we have no root (e.g. never been initialized) force it so the tree will load properly + if (this._root === undefined) { + await this.show(); + } + + return this.findNodeCore( + typeof predicate === 'string' ? n => n.id === predicate : predicate, + await getChildren(this.ensureRoot()), + allowPaging, + getChildren, + maxDepth + ); + } + + private async findNodeCore( + predicate: (node: ViewNode) => boolean, + nodes: ViewNode[], + allowPaging: boolean, + getChildren: (node: ViewNode) => ViewNode[] | Promise, + depth: number + ): Promise { + const decendents: ViewNode[] = []; + + const defaultPageSize = Container.config.advanced.maxListItems; + + let child; + let children; + for (const node of nodes) { + children = await getChildren(node); + if (children.length === 0) continue; + + child = children.find(predicate); + if (child !== undefined) return child; + + if (PageableViewNode.is(node)) { + // Don't descend into paged children + if (!allowPaging || node.maxCount === 0) continue; + + if (defaultPageSize !== 0 && (node.maxCount === undefined || node.maxCount < defaultPageSize)) { + await this.showMoreNodeChildren(node, defaultPageSize); + + children = await getChildren(node); + if (children.length === 0) continue; + + child = children.find(predicate); + if (child !== undefined) return child; + } + + await this.showMoreNodeChildren(node, 0); + + children = await getChildren(node); + if (children.length === 0) continue; + + child = children.find(predicate); + if (child !== undefined) return child; + + // Don't descend into paged children + continue; + } + + decendents.push(...children); + } + + depth--; + if (depth === 0) return undefined; + + return this.findNodeCore(predicate, decendents, allowPaging, getChildren, depth); + } + @debug() async refresh(reset: boolean = false) { if (this._root !== undefined && this._root.refresh !== undefined) { @@ -248,6 +355,8 @@ export abstract class ViewBase> implements TreeData maxCount: number | undefined, previousNode?: ViewNode ) { + if (node.maxCount === maxCount) return Promise.resolve(); + if (maxCount === undefined || maxCount === 0) { node.maxCount = maxCount; } else {