UNPKG

@itwin/presentation-components

Version:

React components based on iTwin.js Presentation library

177 lines 7.28 kB
"use strict"; /*--------------------------------------------------------------------------------------------- * Copyright (c) Bentley Systems, Incorporated. All rights reserved. * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ /** @packageDocumentation * @module Internal */ Object.defineProperty(exports, "__esModule", { value: true }); exports.NavigationPropertyItemsLoader = void 0; exports.useNavigationPropertyTargetsLoader = useNavigationPropertyTargetsLoader; exports.useNavigationPropertyTargetsRuleset = useNavigationPropertyTargetsRuleset; require("../../common/DisposePolyfill.js"); const react_1 = require("react"); const rxjs_1 = require("rxjs"); const presentation_common_1 = require("@itwin/presentation-common"); const presentation_frontend_1 = require("@itwin/presentation-frontend"); const ItemsLoader_js_1 = require("./ItemsLoader.js"); /** @internal */ function useNavigationPropertyTargetsLoader(props) { const { imodel, ruleset, filterText, initialSelectedTarget } = props; const [itemsLoader, setItemsLoader] = (0, react_1.useState)(); const [state, setLoadedOptions] = (0, react_1.useState)({ options: [], isLoading: false, }); // Get initial loader and values (0, react_1.useEffect)(() => { setLoadedOptions({ options: [], isLoading: false }); if (!ruleset) { return; } const loader = new NavigationPropertyItemsLoader(() => { setLoadedOptions((prev) => ({ ...prev, isLoading: true })); }, (newItems) => { setLoadedOptions((prev) => ({ options: [...prev.options, ...newItems], isLoading: false, })); }, async (filter) => getItems(imodel, ruleset, filter)); void loader.loadItems(initialSelectedTarget ?? ""); setItemsLoader(loader); return () => { loader[Symbol.dispose](); }; }, [imodel, initialSelectedTarget, ruleset]); // On filter text change, check if more items need to be loaded (0, react_1.useEffect)(() => { if (!itemsLoader) { return; } const timeout = setTimeout(() => { void itemsLoader.loadItems(filterText); }, 250); return () => { clearTimeout(timeout); }; }, [itemsLoader, filterText]); return { selectOptions: (0, react_1.useMemo)(() => { const options = state.options.map((option) => { return { label: option.label.displayValue, value: option.label.displayValue, }; }); if (options.length >= ItemsLoader_js_1.VALUE_BATCH_SIZE) { options.push(ItemsLoader_js_1.FILTER_WARNING_OPTION); } return options; }, [state.options]), loadedOptions: state.options, isLoading: state.isLoading, }; } /** @internal */ function useNavigationPropertyTargetsRuleset(getNavigationPropertyInfo, property) { const [ruleset, setRuleset] = (0, react_1.useState)(); (0, react_1.useEffect)(() => { let disposed = false; void (async () => { const propertyInfo = await getNavigationPropertyInfo(property); if (!disposed && propertyInfo) { setRuleset(createNavigationPropertyTargetsRuleset(propertyInfo)); } })(); return () => { disposed = true; }; }, [property, getNavigationPropertyInfo]); return ruleset; } function createNavigationPropertyTargetsRuleset(propertyInfo) { const [schemaName, className] = propertyInfo.targetClassInfo.name.split(":"); return { id: `navigation-property-targets`, rules: [ { ruleType: presentation_common_1.RuleTypes.Content, specifications: [ { specType: presentation_common_1.ContentSpecificationTypes.ContentInstancesOfSpecificClasses, classes: { schemaName, classNames: [className], arePolymorphic: propertyInfo.isTargetPolymorphic }, }, ], }, ], }; } async function getItems(imodel, ruleset, filter) { const requestProps = { imodel, rulesetOrId: ruleset, keys: new presentation_common_1.KeySet(), descriptor: { contentFlags: presentation_common_1.ContentFlags.ShowLabels | presentation_common_1.ContentFlags.NoFields, fieldsFilterExpression: filter ? `/DisplayLabel/ ~ \"%${filter}%\"` : undefined, }, paging: { size: ItemsLoader_js_1.VALUE_BATCH_SIZE }, }; const items = await new Promise((resolve, reject) => { (presentation_frontend_1.Presentation.presentation.getContentIterator ? (0, rxjs_1.from)(presentation_frontend_1.Presentation.presentation.getContentIterator(requestProps)).pipe((0, rxjs_1.mergeMap)((result) => (result ? result.items : rxjs_1.EMPTY)), (0, rxjs_1.toArray)()) : // eslint-disable-next-line @typescript-eslint/no-deprecated (0, rxjs_1.from)(presentation_frontend_1.Presentation.presentation.getContent(requestProps)).pipe((0, rxjs_1.map)((content) => (content ? content.contentSet : [])))).subscribe({ next: resolve, error: reject, }); }); const results = items.map((item) => ({ label: item.label, key: item.primaryKeys[0], })); return results; } /** @internal */ class NavigationPropertyItemsLoader { _beforeLoad; _onItemsLoaded; _loadItems; _loadedItems = []; _isLoading = false; _disposed = false; constructor(_beforeLoad, _onItemsLoaded, _loadItems) { this._beforeLoad = _beforeLoad; this._onItemsLoaded = _onItemsLoaded; this._loadItems = _loadItems; } [Symbol.dispose]() { this._disposed = true; } async loadItems(filterText) { if (this._isLoading || filterText === undefined || (filterText === "" && this._loadedItems.length >= ItemsLoader_js_1.VALUE_BATCH_SIZE)) { return; } const filteredItems = this._loadedItems.filter((option) => option.label.displayValue.toLowerCase().includes(filterText.toLowerCase())); if (filteredItems.length >= ItemsLoader_js_1.VALUE_BATCH_SIZE) { return; } this._isLoading = true; this._beforeLoad(); const options = await this._loadItems(filterText); if (this._disposed) { return; } const uniqueOptions = options.filter((option) => { return !this._loadedItems.some((loadedItem) => { return loadedItem.key.id === option.key.id && loadedItem.label.displayValue === option.label.displayValue; }); }); this._loadedItems.push(...uniqueOptions); this._onItemsLoaded(uniqueOptions); this._isLoading = false; } } exports.NavigationPropertyItemsLoader = NavigationPropertyItemsLoader; //# sourceMappingURL=UseNavigationPropertyTargetsLoader.js.map