UNPKG

terriajs

Version:

Geospatial data visualization platform.

160 lines 7.33 kB
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; import { autorun, makeObservable, observable, runInAction } from "mobx"; import { Category, SearchAction } from "../../Core/AnalyticEvents/analyticEvents"; import { TerriaErrorSeverity } from "../../Core/TerriaError"; import GroupMixin from "../../ModelMixins/GroupMixin"; import ReferenceMixin from "../../ModelMixins/ReferenceMixin"; import CatalogSearchProviderMixin from "../../ModelMixins/SearchProviders/CatalogSearchProviderMixin"; import CatalogSearchProviderTraits from "../../Traits/SearchProviders/CatalogSearchProviderTraits"; import CommonStrata from "../Definition/CommonStrata"; import CreateModel from "../Definition/CreateModel"; import SearchResult from "./SearchResult"; export function loadAndSearchCatalogRecursively(models, searchTextLowercase, searchResults, resultMap, iteration = 0) { // checkTerriaAgainstResults(terria, searchResults) // don't go further than 10 deep, but also if we have references that never // resolve to a target, might overflow if (iteration > 10) { return Promise.resolve(); } // add some public interface for terria's `models`? const referencesAndGroupsToLoad = models.filter((model) => { if (resultMap.get(model.uniqueId) === undefined) { const modelToSave = model.target || model; // Use a flattened string of definition data later, // without only checking name/id/descriptions? // saveModelToJson(modelToSave, { // includeStrata: [CommonStrata.definition] // }); autorun((reaction) => { const searchString = `${modelToSave.name} ${modelToSave.uniqueId} ${modelToSave.description}`; const matchesString = searchString.toLowerCase().indexOf(searchTextLowercase) !== -1; resultMap.set(model.uniqueId, matchesString); if (matchesString) { runInAction(() => { searchResults.results.push(new SearchResult({ name: modelToSave.name, catalogItem: modelToSave })); }); } reaction.dispose(); }); } if (ReferenceMixin.isMixedInto(model) || GroupMixin.isMixedInto(model)) { return true; } // Could also check for loadMembers() here, but will be even slower // (relies on external non-magda services to be performant) return false; }); // If we have no members to load if (referencesAndGroupsToLoad.length === 0) { return Promise.resolve(); } return new Promise((resolve, reject) => { autorun((reaction) => { Promise.all(referencesAndGroupsToLoad.map(async (model) => { if (ReferenceMixin.isMixedInto(model)) { // TODO: could handle errors better here (await model.loadReference()).throwIfError(); } // TODO: investigate performant route for calling loadMembers on additional groupmixins // else if (GroupMixin.isMixedInto(model)) { // return model.loadMembers(); // } })) .then(() => { // Then call this function again to see if new child references were loaded in resolve(loadAndSearchCatalogRecursively(models, searchTextLowercase, searchResults, resultMap, iteration + 1)); }) .catch((error) => { reject(error); }); reaction.dispose(); }); }); } export default class CatalogSearchProvider extends CatalogSearchProviderMixin(CreateModel(CatalogSearchProviderTraits)) { static type = "catalog-search-provider"; isSearching = false; debounceDurationOnceLoaded = 300; constructor(id, terria) { super(id, terria); makeObservable(this); this.setTrait(CommonStrata.defaults, "minCharacters", terria.searchBarModel.minCharacters); } get type() { return CatalogSearchProvider.type; } logEvent(searchText) { this.terria.analytics?.logEvent(Category.search, SearchAction.catalog, searchText); } async doSearch(searchText, searchResults) { runInAction(() => (this.isSearching = true)); searchResults.results.length = 0; searchResults.message = undefined; if (searchText === undefined || /^\s*$/.test(searchText)) { runInAction(() => (this.isSearching = false)); return Promise.resolve(); } // Load catalogIndex if needed if (this.terria.catalogIndex && !this.terria.catalogIndex.loadPromise) { try { await this.terria.catalogIndex.load(); } catch (e) { this.terria.raiseErrorToUser(e, "Failed to load catalog index. Searching may be slow/inaccurate"); } } const resultMap = new Map(); try { if (this.terria.catalogIndex?.searchIndex) { const results = await this.terria.catalogIndex.search(searchText); runInAction(() => (searchResults.results = results)); } else { await loadAndSearchCatalogRecursively(this.terria.modelValues, searchText.toLowerCase(), searchResults, resultMap); } runInAction(() => { this.isSearching = false; }); if (searchResults.isCanceled) { // A new search has superseded this one, so ignore the result. return; } runInAction(() => { this.terria.catalogReferencesLoaded = true; }); if (searchResults.results.length === 0) { searchResults.message = { content: "translate#viewModels.searchNoCatalogueItem" }; } } catch (e) { this.terria.raiseErrorToUser(e, { message: "An error occurred while searching", severity: TerriaErrorSeverity.Warning }); if (searchResults.isCanceled) { // A new search has superseded this one, so ignore the result. return; } searchResults.message = { content: "translate#viewModels.searchErrorOccurred" }; } } } __decorate([ observable ], CatalogSearchProvider.prototype, "isSearching", void 0); __decorate([ observable ], CatalogSearchProvider.prototype, "debounceDurationOnceLoaded", void 0); //# sourceMappingURL=CatalogSearchProvider.js.map