UNPKG

@itwin/presentation-frontend

Version:

Frontend of iModel.js Presentation library

317 lines • 15.1 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 Core */ Object.defineProperty(exports, "__esModule", { value: true }); exports.BrowserLocalFavoritePropertiesStorage = exports.NoopFavoritePropertiesStorage = exports.OfflineCachingFavoritePropertiesStorage = exports.IModelAppFavoritePropertiesStorage = exports.DefaultFavoritePropertiesStorageTypes = exports.FAVORITE_PROPERTIES_ORDER_INFO_SETTING_NAME = exports.FAVORITE_PROPERTIES_SETTING_NAME = exports.DEPRECATED_PROPERTIES_SETTING_NAMESPACE = exports.IMODELJS_PRESENTATION_SETTING_NAMESPACE = void 0; exports.createFavoritePropertiesStorage = createFavoritePropertiesStorage; const core_bentley_1 = require("@itwin/core-bentley"); const core_common_1 = require("@itwin/core-common"); const core_frontend_1 = require("@itwin/core-frontend"); const presentation_common_1 = require("@itwin/presentation-common"); const ConnectivityInformationProvider_js_1 = require("../ConnectivityInformationProvider.js"); /** @internal */ exports.IMODELJS_PRESENTATION_SETTING_NAMESPACE = "imodeljs.presentation"; /** @internal */ exports.DEPRECATED_PROPERTIES_SETTING_NAMESPACE = "Properties"; /** @internal */ exports.FAVORITE_PROPERTIES_SETTING_NAME = "FavoriteProperties"; /** @internal */ exports.FAVORITE_PROPERTIES_ORDER_INFO_SETTING_NAME = "FavoritePropertiesOrderInfo"; /** * Available implementations of [[IFavoritePropertiesStorage]]. * @public */ var DefaultFavoritePropertiesStorageTypes; (function (DefaultFavoritePropertiesStorageTypes) { /** A no-op storage that doesn't store or return anything. Used for cases when favorite properties aren't used by the application. */ DefaultFavoritePropertiesStorageTypes[DefaultFavoritePropertiesStorageTypes["Noop"] = 0] = "Noop"; /** A storage that stores favorite properties information in a browser local storage. */ DefaultFavoritePropertiesStorageTypes[DefaultFavoritePropertiesStorageTypes["BrowserLocalStorage"] = 1] = "BrowserLocalStorage"; /** A storage that stores favorite properties in a user preferences storage (see [[IModelApp.userPreferences]]). */ DefaultFavoritePropertiesStorageTypes[DefaultFavoritePropertiesStorageTypes["UserPreferencesStorage"] = 2] = "UserPreferencesStorage"; })(DefaultFavoritePropertiesStorageTypes || (exports.DefaultFavoritePropertiesStorageTypes = DefaultFavoritePropertiesStorageTypes = {})); /** * A factory method to create one of the available [[IFavoritePropertiesStorage]] implementations. * @public */ function createFavoritePropertiesStorage(type) { switch (type) { case DefaultFavoritePropertiesStorageTypes.Noop: return new NoopFavoritePropertiesStorage(); case DefaultFavoritePropertiesStorageTypes.BrowserLocalStorage: return new BrowserLocalFavoritePropertiesStorage(); case DefaultFavoritePropertiesStorageTypes.UserPreferencesStorage: return new OfflineCachingFavoritePropertiesStorage({ impl: new IModelAppFavoritePropertiesStorage() }); } } /** * @internal */ class IModelAppFavoritePropertiesStorage { async ensureIsSignedIn() { const accessToken = core_frontend_1.IModelApp.authorizationClient ? await core_frontend_1.IModelApp.authorizationClient.getAccessToken() : ""; if (accessToken) { return { accessToken }; } throw new presentation_common_1.PresentationError(presentation_common_1.PresentationStatus.Error, "Current user is not authorized to use the settings service"); } async loadProperties(iTwinId, imodelId) { if (!core_frontend_1.IModelApp.userPreferences) { throw new presentation_common_1.PresentationError(presentation_common_1.PresentationStatus.Error, "User preferences service is not set up"); } const { accessToken } = await this.ensureIsSignedIn(); let setting = await core_frontend_1.IModelApp.userPreferences.get({ accessToken, iTwinId, iModelId: imodelId, namespace: exports.IMODELJS_PRESENTATION_SETTING_NAMESPACE, key: exports.FAVORITE_PROPERTIES_SETTING_NAME, }); if (setting !== undefined) { return new Set(setting); } // try to check the old namespace setting = await core_frontend_1.IModelApp.userPreferences.get({ accessToken, iTwinId, iModelId: imodelId, namespace: exports.DEPRECATED_PROPERTIES_SETTING_NAMESPACE, key: exports.FAVORITE_PROPERTIES_SETTING_NAME, }); if (setting !== undefined && setting.hasOwnProperty("nestedContentInfos") && setting.hasOwnProperty("propertyInfos") && setting.hasOwnProperty("baseFieldInfos")) { return new Set([...setting.nestedContentInfos, ...setting.propertyInfos, ...setting.baseFieldInfos]); } return undefined; } async saveProperties(properties, iTwinId, imodelId) { if (!core_frontend_1.IModelApp.userPreferences) { throw new presentation_common_1.PresentationError(presentation_common_1.PresentationStatus.Error, "User preferences service is not set up"); } const { accessToken } = await this.ensureIsSignedIn(); await core_frontend_1.IModelApp.userPreferences.save({ accessToken, iTwinId, iModelId: imodelId, namespace: exports.IMODELJS_PRESENTATION_SETTING_NAMESPACE, key: exports.FAVORITE_PROPERTIES_SETTING_NAME, content: Array.from(properties), }); } async loadPropertiesOrder(iTwinId, imodelId) { if (!core_frontend_1.IModelApp.userPreferences) { throw new presentation_common_1.PresentationError(presentation_common_1.PresentationStatus.Error, "User preferences service is not set up"); } const { accessToken } = await this.ensureIsSignedIn(); const setting = await core_frontend_1.IModelApp.userPreferences.get({ accessToken, iTwinId, iModelId: imodelId, namespace: exports.IMODELJS_PRESENTATION_SETTING_NAMESPACE, key: exports.FAVORITE_PROPERTIES_ORDER_INFO_SETTING_NAME, }); return setting; } async savePropertiesOrder(orderInfos, iTwinId, imodelId) { if (!core_frontend_1.IModelApp.userPreferences) { throw new presentation_common_1.PresentationError(presentation_common_1.PresentationStatus.Error, "User preferences service is not set up"); } const { accessToken } = await this.ensureIsSignedIn(); await core_frontend_1.IModelApp.userPreferences.save({ accessToken, iTwinId, iModelId: imodelId, namespace: exports.IMODELJS_PRESENTATION_SETTING_NAMESPACE, key: exports.FAVORITE_PROPERTIES_ORDER_INFO_SETTING_NAME, content: orderInfos, }); } } exports.IModelAppFavoritePropertiesStorage = IModelAppFavoritePropertiesStorage; /** @internal */ class OfflineCachingFavoritePropertiesStorage { _connectivityInfo; _impl; _propertiesOfflineCache = new DictionaryWithReservations(iTwinAndIModelIdsKeyComparer); _propertiesOrderOfflineCache = new DictionaryWithReservations(iTwinAndIModelIdsKeyComparer); constructor(props) { this._impl = props.impl; /* c8 ignore next */ this._connectivityInfo = props.connectivityInfo ?? new ConnectivityInformationProvider_js_1.ConnectivityInformationProvider(); this._connectivityInfo.onInternetConnectivityChanged.addListener(this.onConnectivityStatusChanged); } [Symbol.dispose]() { (0, core_bentley_1.isDisposable)(this._connectivityInfo) && this._connectivityInfo[Symbol.dispose](); } get impl() { return this._impl; } onConnectivityStatusChanged = (args) => { if (args.status === core_common_1.InternetConnectivityStatus.Online) { // note: we're copying the cached values to temp arrays because `saveProperties` and `savePropertiesOrder` both // attempt to modify cache dictionaries const propertiesCache = new Array(); this._propertiesOfflineCache.forEach((key, value) => propertiesCache.push({ properties: value, iTwinId: key[0], imodelId: key[1] })); propertiesCache.forEach(async (cached) => this.saveProperties(cached.properties, cached.iTwinId, cached.imodelId)); const ordersCache = new Array(); this._propertiesOrderOfflineCache.forEach((key, value) => ordersCache.push({ order: value, iTwinId: key[0], imodelId: key[1] })); ordersCache.forEach(async (cached) => this.savePropertiesOrder(cached.order, cached.iTwinId, cached.imodelId)); } }; async loadProperties(iTwinId, imodelId) { if (this._connectivityInfo.status === core_common_1.InternetConnectivityStatus.Online) { try { return await this._impl.loadProperties(iTwinId, imodelId); } catch { // return from offline cache if the above fails } } return this._propertiesOfflineCache.get([iTwinId, imodelId]); } async saveProperties(properties, iTwinId, imodelId) { const key = [iTwinId, imodelId]; if (this._connectivityInfo.status === core_common_1.InternetConnectivityStatus.Offline) { this._propertiesOfflineCache.set(key, properties); return; } const reservationId = this._propertiesOfflineCache.reserve(key); try { await this._impl.saveProperties(properties, iTwinId, imodelId); this._propertiesOfflineCache.reservedDelete(key, reservationId); } catch { this._propertiesOfflineCache.reservedSet(key, properties, reservationId); } } async loadPropertiesOrder(iTwinId, imodelId) { if (this._connectivityInfo.status === core_common_1.InternetConnectivityStatus.Online) { try { return await this._impl.loadPropertiesOrder(iTwinId, imodelId); } catch { // return from offline cache if the above fails } } return this._propertiesOrderOfflineCache.get([iTwinId, imodelId]); } async savePropertiesOrder(orderInfos, iTwinId, imodelId) { const key = [iTwinId, imodelId]; if (this._connectivityInfo.status === core_common_1.InternetConnectivityStatus.Offline) { this._propertiesOrderOfflineCache.set(key, orderInfos); return; } const reservationId = this._propertiesOrderOfflineCache.reserve(key); try { await this._impl.savePropertiesOrder(orderInfos, iTwinId, imodelId); this._propertiesOrderOfflineCache.reservedDelete(key, reservationId); } catch { this._propertiesOrderOfflineCache.reservedSet(key, orderInfos, reservationId); } } } exports.OfflineCachingFavoritePropertiesStorage = OfflineCachingFavoritePropertiesStorage; class DictionaryWithReservations { _impl; constructor(compareKeys) { this._impl = new core_bentley_1.Dictionary(compareKeys); } get(key) { return this._impl.get(key)?.value; } forEach(func) { this._impl.forEach((key, entry) => { if (entry.value) { func(key, entry.value); } }); } reserve(key) { const reservationId = core_bentley_1.Guid.createValue(); this._impl.set(key, { lastReservationId: reservationId }); return reservationId; } set(key, value) { return this._impl.set(key, { value }); } reservedSet(key, value, reservationId) { const entry = this._impl.get(key); if (entry && entry.lastReservationId === reservationId) { this._impl.set(key, { value }); } } reservedDelete(key, reservationId) { const entry = this._impl.get(key); if (entry && entry.lastReservationId === reservationId) { this._impl.delete(key); } } } /* c8 ignore next 4 */ function iTwinAndIModelIdsKeyComparer(lhs, rhs) { const iTwinIdCompare = (0, core_bentley_1.compareStrings)(lhs[0] ?? "", rhs[0] ?? ""); return iTwinIdCompare !== 0 ? iTwinIdCompare : (0, core_bentley_1.compareStrings)(lhs[1] ?? "", rhs[1] ?? ""); } /** @internal */ /* c8 ignore start */ class NoopFavoritePropertiesStorage { async loadProperties(_iTwinId, _imodelId) { return undefined; } async saveProperties(_properties, _iTwinId, _imodelId) { } async loadPropertiesOrder(_iTwinId, _imodelId) { return undefined; } async savePropertiesOrder(_orderInfos, _iTwinId, _imodelId) { } } exports.NoopFavoritePropertiesStorage = NoopFavoritePropertiesStorage; /* c8 ignore end */ /** @internal */ class BrowserLocalFavoritePropertiesStorage { _localStorage; constructor(props) { /* c8 ignore next */ this._localStorage = props?.localStorage ?? window.localStorage; } createFavoritesSettingItemKey(iTwinId, imodelId) { return `${exports.IMODELJS_PRESENTATION_SETTING_NAMESPACE}${exports.FAVORITE_PROPERTIES_SETTING_NAME}?iTwinId=${iTwinId}&imodelId=${imodelId}`; } createOrderSettingItemKey(iTwinId, imodelId) { return `${exports.IMODELJS_PRESENTATION_SETTING_NAMESPACE}${exports.FAVORITE_PROPERTIES_ORDER_INFO_SETTING_NAME}?iTwinId=${iTwinId}&imodelId=${imodelId}`; } async loadProperties(iTwinId, imodelId) { const value = this._localStorage.getItem(this.createFavoritesSettingItemKey(iTwinId, imodelId)); if (!value) { return undefined; } const properties = JSON.parse(value); return new Set(properties); } async saveProperties(properties, iTwinId, imodelId) { this._localStorage.setItem(this.createFavoritesSettingItemKey(iTwinId, imodelId), JSON.stringify([...properties])); } async loadPropertiesOrder(iTwinId, imodelId) { const value = this._localStorage.getItem(this.createOrderSettingItemKey(iTwinId, imodelId)); if (!value) { return undefined; } const orderInfos = JSON.parse(value).map((json) => ({ ...json, orderedTimestamp: new Date(json.orderedTimestamp), })); return orderInfos; } async savePropertiesOrder(orderInfos, iTwinId, imodelId) { this._localStorage.setItem(this.createOrderSettingItemKey(iTwinId, imodelId), JSON.stringify(orderInfos)); } } exports.BrowserLocalFavoritePropertiesStorage = BrowserLocalFavoritePropertiesStorage; //# sourceMappingURL=FavoritePropertiesStorage.js.map