Skip to content

Commit

Permalink
Presentation: Allow choosing favorite properties storage (and change …
Browse files Browse the repository at this point in the history
…default to no-op) (iTwin#2276)

* Allow choosing favorite properties storage (and change default to no-op)

* Use `BrowserLocalStorage` when ui-test-app asks for it

* Fix failing full stack test

* Use settings service storage for favorites' integration tests
  • Loading branch information
grigasp authored Sep 20, 2021
1 parent 343c7fd commit 3d3df8f
Show file tree
Hide file tree
Showing 15 changed files with 442 additions and 122 deletions.
59 changes: 53 additions & 6 deletions common/api/presentation-frontend.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,25 @@ import { UnsetRulesetVariableParams } from '@bentley/presentation-common';
import { UpdateHierarchyStateParams } from '@bentley/presentation-common';
import { VariableValue } from '@bentley/presentation-common';

// @internal (undocumented)
export class BrowserLocalFavoritePropertiesStorage implements IFavoritePropertiesStorage {
constructor(props?: {
localStorage?: Storage;
});
// (undocumented)
createFavoritesSettingItemKey(projectId?: string, imodelId?: string): string;
// (undocumented)
createOrderSettingItemKey(projectId?: string, imodelId?: string): string;
// (undocumented)
loadProperties(projectId?: string, imodelId?: string): Promise<Set<PropertyFullName> | undefined>;
// (undocumented)
loadPropertiesOrder(projectId: string | undefined, imodelId: string): Promise<FavoritePropertiesOrderInfo[] | undefined>;
// (undocumented)
saveProperties(properties: Set<PropertyFullName>, projectId?: string, imodelId?: string): Promise<void>;
// (undocumented)
savePropertiesOrder(orderInfos: FavoritePropertiesOrderInfo[], projectId: string | undefined, imodelId: string): Promise<void>;
}

// @internal (undocumented)
export const buildPagedResponse: <TItem>(requestedPage: PageOptions | undefined, getter: (page: Required<PageOptions>, requestIndex: number) => Promise<PagedResponse<TItem>>) => Promise<PagedResponse<TItem>>;

Expand All @@ -63,9 +82,19 @@ export function consoleDiagnosticsHandler(scopeLogs: DiagnosticsScopeLogs[]): vo
// @alpha (undocumented)
export function createCombinedDiagnosticsHandler(handlers: DiagnosticsHandler[]): (scopeLogs: DiagnosticsScopeLogs[]) => void;

// @public
export function createFavoritePropertiesStorage(type: DefaultFavoritePropertiesStorageTypes): IFavoritePropertiesStorage;

// @internal (undocumented)
export const createFieldOrderInfos: (field: Field) => FavoritePropertiesOrderInfo[];

// @public
export enum DefaultFavoritePropertiesStorageTypes {
BrowserLocalStorage = 1,
Noop = 0,
UserSettingsServiceStorage = 2
}

// @public
export class FavoritePropertiesManager implements IDisposable {
constructor(props: FavoritePropertiesManagerProps);
Expand Down Expand Up @@ -189,42 +218,53 @@ export interface NodeIdentifier {
key: NodeKey;
}

// @internal (undocumented)
export class NoopFavoritePropertiesStorage implements IFavoritePropertiesStorage {
// (undocumented)
loadProperties(_projectId?: string, _imodelId?: string): Promise<Set<PropertyFullName> | undefined>;
// (undocumented)
loadPropertiesOrder(_projectId: string | undefined, _imodelId: string): Promise<FavoritePropertiesOrderInfo[] | undefined>;
// (undocumented)
saveProperties(_properties: Set<PropertyFullName>, _projectId?: string, _imodelId?: string): Promise<void>;
// (undocumented)
savePropertiesOrder(_orderInfos: FavoritePropertiesOrderInfo[], _projectId: string | undefined, _imodelId: string): Promise<void>;
}

// @internal (undocumented)
export class OfflineCachingFavoritePropertiesStorage implements IFavoritePropertiesStorage, IDisposable {
constructor(props: OfflineCachingFavoritePropertiesStorageProps);
// (undocumented)
dispose(): void;
// (undocumented)
get impl(): IFavoritePropertiesStorage;
// (undocumented)
loadProperties(projectId?: string, imodelId?: string): Promise<Set<string> | undefined>;
// (undocumented)
loadPropertiesOrder(projectId: string | undefined, imodelId: string): Promise<FavoritePropertiesOrderInfo[] | undefined>;
// (undocumented)
saveProperties(properties: Set<PropertyFullName>, projectId?: string, imodelId?: string): Promise<void>;
// (undocumented)
savePropertiesOrder(orderInfos: FavoritePropertiesOrderInfo[], projectId: string | undefined, imodelId: string): Promise<void>;
}
}

// @internal (undocumented)
export interface OfflineCachingFavoritePropertiesStorageProps {
// (undocumented)
connectivityInfo: IConnectivityInformationProvider;
connectivityInfo?: IConnectivityInformationProvider;
// (undocumented)
impl: IFavoritePropertiesStorage;
}

// @public
export class Presentation {
static get connectivity(): IConnectivityInformationProvider;
static get favoriteProperties(): FavoritePropertiesManager;
static get i18n(): I18N;
static initialize(props?: PresentationManagerProps): Promise<void>;
static initialize(props?: PresentationProps): Promise<void>;
static get presentation(): PresentationManager;
// @internal
static registerInitializationHandler(handler: () => Promise<() => void>): void;
static get selection(): SelectionManager;
// @internal (undocumented)
static setConnectivityInformationProvider(value: IConnectivityInformationProvider): void;
// @internal (undocumented)
static setFavoritePropertiesManager(value: FavoritePropertiesManager): void;
// @internal (undocumented)
static setI18nManager(value: I18N): void;
Expand Down Expand Up @@ -299,6 +339,13 @@ export interface PresentationManagerProps {
stateTracker?: StateTracker;
}

// @public
export interface PresentationProps {
favorites?: FavoritePropertiesManagerProps;
presentation?: PresentationManagerProps;
selection?: SelectionManagerProps;
}

// @public
export type PropertyFullName = string;

Expand Down
4 changes: 2 additions & 2 deletions common/api/presentation-testing.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { Omit } from '@bentley/presentation-common';
import { PageOptions } from '@bentley/presentation-common';
import { PresentationManagerProps as PresentationBackendProps } from '@bentley/presentation-backend';
import { PresentationManagerMode } from '@bentley/presentation-backend';
import { PresentationManagerProps } from '@bentley/presentation-frontend';
import { PresentationProps } from '@bentley/presentation-frontend';
import { PropertyRecord } from '@bentley/ui-abstract';
import { Ruleset } from '@bentley/presentation-common';
import { TreeNodeItem } from '@bentley/ui-components';
Expand Down Expand Up @@ -92,7 +92,7 @@ export interface PresentationTestingInitProps {
startup: (opts?: IModelAppOptions) => Promise<void>;
};
frontendAppOptions?: IModelAppOptions;
frontendProps?: PresentationManagerProps;
frontendProps?: PresentationProps;
}

// @public
Expand Down
5 changes: 5 additions & 0 deletions common/api/summary/presentation-frontend.exports.csv
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
sep=;
Release Tag;API Item
internal;BrowserLocalFavoritePropertiesStorage
internal;buildPagedResponse:
alpha;consoleDiagnosticsHandler(scopeLogs: DiagnosticsScopeLogs[]): void
alpha;createCombinedDiagnosticsHandler(handlers: DiagnosticsHandler[]): (scopeLogs: DiagnosticsScopeLogs[]) => void
public;createFavoritePropertiesStorage(type: DefaultFavoritePropertiesStorageTypes): IFavoritePropertiesStorage
internal;createFieldOrderInfos: (field: Field) => FavoritePropertiesOrderInfo[]
public;DefaultFavoritePropertiesStorageTypes
public;FavoritePropertiesManager
public;FavoritePropertiesManagerProps
public;FavoritePropertiesOrderInfo
Expand All @@ -20,12 +23,14 @@ alpha;IModelContentChangeEventArgs
alpha;IModelHierarchyChangeEventArgs
public;ISelectionProvider
internal;NodeIdentifier
internal;NoopFavoritePropertiesStorage
internal;OfflineCachingFavoritePropertiesStorage
internal;OfflineCachingFavoritePropertiesStorageProps
public;Presentation
public;PresentationFrontendLoggerCategory
public;PresentationManager
public;PresentationManagerProps
public;PresentationProps
public;PropertyFullName = string
public;RulesetManager
internal;RulesetManagerImpl
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"changes": [
{
"packageName": "@bentley/presentation-frontend",
"comment": "Allow supplying `SelectionManager` and `FavoritePropertiesManager` props when initializing `Presentation`.",
"type": "none"
},
{
"packageName": "@bentley/presentation-frontend",
"comment": "Change default `IFavoritePropertiesStorage` implementation to no-op and provide ability to choose another one when initializing `Presentation`.",
"type": "none"
}
],
"packageName": "@bentley/presentation-frontend"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@bentley/presentation-testing",
"comment": "",
"type": "none"
}
],
"packageName": "@bentley/presentation-testing"
}
44 changes: 44 additions & 0 deletions docs/changehistory/NextVersion.md
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,50 @@ The [NodeKey]($presentation-common) object contains a `pathFromRoot` attribute w

In `3.0` changes have been made that changed the way this attribute is calculated, which means the same node produced by pre-3.0 and 3.x versions of `imodeljs` will have keys with different `pathFromRoot` value. To help identify the version of `NodeKey` a new `version` attribute has been added, with `undefined` or `1` being assigned to keys produced by pre-3.0 and `2` being assigned to keys produced by `3.x` versions of imodeljs. In addition, a new [NodeKey.equals]($presentation-common) function has been added to help with the equality checking of node keys, taking their version into account.

## Changes to `Presentation` initialization in `@bentley/presentation-frontend`

- [Presentation.initialize]($presentation-frontend) used to take [PresentationManagerProps]($presentation-frontend) as an argument. Now it takes [PresentationProps]($presentation-frontend) which allows supplying props not only to [PresentationManager]($presentation-frontend), but also [SelectionManager]($presentation-frontend) and [FavoritePropertiesManager]($presentation-frontend). Typical migration:

**Before:**

```ts
await Presentation.initialize({
// ...props for presentation manager
activeLocale: "en-us",
});
```

**After:**

```ts
await Presentation.initialize({
presentation: {
// ...props for presentation manager
activeLocale: "en-us",
},
});
```

- The frontend used to by default initialize with an [IFavoritePropertiesStorage]($presentation-frontend) implementation that uses Bentley's user settings service which may not be accessible by third party applications. The behavior was changed to use to a no-op storage by default with ability to choose an implementation that uses the settings service. Typical migration:

**Before:**

```ts
// no way to override favorite properties storage, so the implementation using settings service is used
await Presentation.initialize();
```

**After:**

```ts
await Presentation.initialize({
favorites: {
// by default the no-op storage is used, but we can choose another option (or provide our own implementation)
storage: createFavoritePropertiesStorage(DefaultFavoritePropertiesStorageTypes.UserSettingsServiceStorage),
},
});
```

## Changes to GraphicBuilder

It is no longer necessary to supply a [Viewport]($frontend) when creating a [GraphicBuilder]($frontend). Instead, you can supply to [RenderSystem.createGraphic]($frontend) a [CustomGraphicBuilderOptions]($frontend) containing a function that can compute the level of detail appropriate for the produced [RenderGraphic]($frontend).
Expand Down
9 changes: 5 additions & 4 deletions full-stack-tests/presentation/src/IntegrationTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,10 @@ import { I18NOptions } from "@bentley/imodeljs-i18n";
import { TestUsers } from "@bentley/oidc-signin-tool/lib/TestUsers";
import { TestUtility } from "@bentley/oidc-signin-tool/lib/TestUtility";
import {
HierarchyCacheMode, Presentation as PresentationBackend, PresentationBackendNativeLoggerCategory,
PresentationProps as PresentationBackendProps,
HierarchyCacheMode, Presentation as PresentationBackend, PresentationBackendNativeLoggerCategory, PresentationProps as PresentationBackendProps,
} from "@bentley/presentation-backend";
import { RequestPriority } from "@bentley/presentation-common";
import { PresentationManagerProps as PresentationFrontendProps } from "@bentley/presentation-frontend";
import { PresentationProps as PresentationFrontendProps } from "@bentley/presentation-frontend";
import { initialize as initializeTesting, PresentationTestingInitProps, terminate as terminateTesting } from "@bentley/presentation-testing";

/** Loads the provided `.env` file into process.env */
Expand Down Expand Up @@ -98,7 +97,9 @@ const initializeCommon = async (props: { backendTimeout?: number, useClientServi
cacheConfig: { mode: HierarchyCacheMode.Disk, directory: path.join(libDir, "cache") },
};
const frontendInitProps: PresentationFrontendProps = {
activeLocale: "en-PSEUDO",
presentation: {
activeLocale: "en-PSEUDO",
},
};

const frontendAppOptions: IModelAppOptions = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ import { Field, KeySet } from "@bentley/presentation-common";
import { PresentationPropertyDataProvider } from "@bentley/presentation-components";
import { FAVORITES_CATEGORY_NAME } from "@bentley/presentation-components/lib/presentation-components/favorite-properties/DataProvider";
import { DEFAULT_PROPERTY_GRID_RULESET } from "@bentley/presentation-components/lib/presentation-components/propertygrid/DataProvider";
import { FavoritePropertiesScope, Presentation } from "@bentley/presentation-frontend";
import {
createFavoritePropertiesStorage, DefaultFavoritePropertiesStorageTypes, FavoritePropertiesManager, FavoritePropertiesScope, Presentation,
} from "@bentley/presentation-frontend";
import { SettingsResult, SettingsStatus } from "@bentley/product-settings-client";
import { PropertyRecord } from "@bentley/ui-abstract";
import { PropertyData } from "@bentley/ui-components";
Expand Down Expand Up @@ -262,11 +264,19 @@ describe("Favorite properties", () => {

describe("#with-services", () => {

function setupFavoritesStorageWithSettingsService() {
Presentation.setFavoritePropertiesManager(new FavoritePropertiesManager({
storage: createFavoritePropertiesStorage(DefaultFavoritePropertiesStorageTypes.UserSettingsServiceStorage),
}));
}

before(async () => {
await imodel.close();
await terminate();
await initializeWithClientServices();
await openIModel();
setupFavoritesStorageWithSettingsService();
await Presentation.favoriteProperties.initializeConnection(imodel);
});

it("favorite properties survive Presentation re-initialization", async () => {
Expand Down Expand Up @@ -299,6 +309,9 @@ describe("Favorite properties", () => {
// refresh Presentation
Presentation.terminate();
await Presentation.initialize();
setupFavoritesStorageWithSettingsService();
await Presentation.favoriteProperties.initializeConnection(imodel);

propertiesDataProvider = new PresentationPropertyDataProvider({ imodel, ruleset: DEFAULT_PROPERTY_GRID_RULESET });
propertiesDataProvider.isNestedPropertyCategoryGroupingEnabled = false;
propertiesDataProvider.keys = new KeySet([{ className: "Generic:PhysicalObject", id: "0x74" }]);
Expand Down
Loading

0 comments on commit 3d3df8f

Please sign in to comment.