Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Property widget: Selection storage support #1184

Merged
merged 5 commits into from
Feb 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { expect } from "chai";
import sinon from "sinon";
import { StagePanelLocation, StagePanelSection, StageUsage } from "@itwin/appui-react";
import { PresentationPropertyDataProvider } from "@itwin/presentation-components";
import { createStorage } from "@itwin/unified-selection";
// __PUBLISH_EXTRACT_START__ PropertyGrid.RegisterPropertyGridWidgetImports
import { createPropertyGrid } from "@itwin/property-grid-react";
import { UiItemsManager } from "@itwin/appui-react";
Expand Down Expand Up @@ -50,6 +51,9 @@ describe("Property grid", () => {
it("registers customizable property grid", async function () {
const MY_CUSTOM_RULESET = undefined;

const selectionStorage = createStorage();
const getGlobalSelectionStorage = () => selectionStorage;

// __PUBLISH_EXTRACT_START__ PropertyGrid.RegisterCustomPropertyGridWidget
UiItemsManager.register({
id: "property-grid-provider",
Expand Down Expand Up @@ -82,6 +86,10 @@ describe("Property grid", () => {
// supply an optional custom storage for user preferences, e.g. the show/hide null values used above
preferencesStorage: new IModelAppUserPreferencesStorage("my-favorites-namespace"),

// supply the global selection storage that the widget will use to listen to selection
// changes (more details: https://github.com/iTwin/presentation/blob/master/packages/unified-selection/README.md)
selectionStorage: getGlobalSelectionStorage(),

// supply an optional data provider factory method to create a custom property data provider
createDataProvider: (imodel: IModelConnection) => new PresentationPropertyDataProvider({ imodel, ruleset: MY_CUSTOM_RULESET }),

Expand Down
1 change: 1 addition & 0 deletions apps/test-viewer/src/UiProvidersConfig.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ const configuredUiItems = new Map<string, UiItem>([
onFeatureUsed: (feature) => {
console.log(`PropertyGrid [${feature}] used`);
},
selectionStorage: unifiedSelectionStorage,
}),
];
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "minor",
"comment": "Added optional `selectionStorage` prop to `createPropertyGrid` function and `MultiElementPropertyGrid` component. This allows using `@itwin/unified-selection` to manage selection state, rather than relying on soon-to-be deprecated unified selection API from `@itwin/presentation-frontend`. The prop will be made required in next major release.",
"packageName": "@itwin/property-grid-react",
"email": "[email protected]",
"dependentChangeType": "patch"
}
18 changes: 17 additions & 1 deletion packages/itwin/property-grid/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ UiItemsManager.register({
// supply an optional custom storage for user preferences, e.g. the show/hide null values used above
preferencesStorage: new IModelAppUserPreferencesStorage("my-favorites-namespace"),

// supply the global selection storage that the widget will use to listen to selection
// changes (more details: https://github.com/iTwin/presentation/blob/master/packages/unified-selection/README.md)
selectionStorage: getGlobalSelectionStorage(),

// supply an optional data provider factory method to create a custom property data provider
createDataProvider: (imodel: IModelConnection) => new PresentationPropertyDataProvider({ imodel, ruleset: MY_CUSTOM_RULESET }),

Expand All @@ -99,7 +103,19 @@ UiItemsManager.register({

<!-- END EXTRACTION -->

As seen in the above code snippet, `createPropertyGrid` takes a number of props that allow customizing not only how the widget behaves, but also how it looks. The package delivers commonly used building blocks:
As seen in the above code snippet, `createPropertyGrid` takes a number of props that allow customizing not only how the widget behaves, but also how it looks.

### Hooking into unified selection

The widget and its components rely on [unified selection](https://github.com/iTwin/presentation/blob/master/packages/unified-selection/README.md#basic-concepts) system to tell them which element(s) are currently selected and when the selection changes. As of version `1.16`, there are two ways to hook into unified selection:

- Supply the `selectionStorage` prop to components that use the unified selection system. See [Basic usage](https://github.com/iTwin/presentation/blob/master/packages/unified-selection/README.md#basic-usage) example for how to set up the storage. At the moment the prop is optional and will only be made required in version `2.0`; the components fall back to the legacy system described below if it's not provided.

- The legacy `SelectionManager` from `@itwin/presentation-frontend` package, accessed through `Presentation.selection` API.

### Building blocks

The package delivers commonly used building blocks:

- context and setting menu items
- ancestor navigation controls
Expand Down
13 changes: 10 additions & 3 deletions packages/itwin/property-grid/api/property-grid-react.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,16 @@ import type { IModelConnection } from '@itwin/core-frontend';
import type { InstanceKey } from '@itwin/presentation-common';
import type { IPresentationPropertyDataProvider } from '@itwin/presentation-components';
import type { IPropertyDataFilterer } from '@itwin/components-react';
import type { KeySet } from '@itwin/presentation-common';
import { KeySet } from '@itwin/presentation-common';
import type { Localization } from '@itwin/core-common';
import type { PropertyCategory } from '@itwin/components-react';
import type { PropertyRecord } from '@itwin/appui-abstract';
import type { PropertyUpdatedArgs } from '@itwin/components-react';
import type { PropsWithChildren } from 'react';
import type { ReactNode } from 'react';
import { Ref } from 'react';
import { Selectables } from '@itwin/unified-selection';
import type { SelectionStorage as SelectionStorage_2 } from '@itwin/unified-selection';
import { StagePanelLocation } from '@itwin/appui-react';
import { StagePanelSection } from '@itwin/appui-react';
import type { TranslationOptions } from '@itwin/core-common';
Expand Down Expand Up @@ -97,6 +99,7 @@ export function MultiElementPropertyGrid({ ancestorsNavigationControls, ...props
// @public
export interface MultiElementPropertyGridProps extends Omit<PropertyGridProps, "headerControls" | "onBackButton"> {
ancestorsNavigationControls?: (props: AncestorsNavigationControlsProps) => ReactNode;
selectionStorage?: SelectionStorage;
}

// @public
Expand Down Expand Up @@ -207,9 +210,13 @@ export interface PropertyGridUiItemsProviderProps {
export const PropertyGridWidgetId = "vcr:PropertyGridComponent";

// @public
export interface PropertyGridWidgetProps extends PropertyGridComponentProps {
export type PropertyGridWidgetProps = PropertyGridComponentProps & ({
shouldShow?: (selection: Readonly<KeySet>) => boolean;
}
selectionStorage?: never;
} | {
shouldShow?: (selection: Selectables) => Promise<boolean>;
selectionStorage: SelectionStorage;
});

// @public
export function RemoveFavoritePropertyContextMenuItem({ field, imodel, scope, onSelect }: FavoritePropertiesContextMenuItemProps): JSX.Element | null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ deprecated;class;PropertyGridUiItemsProvider
public;interface;PropertyGridUiItemsProviderProps
deprecated;interface;PropertyGridUiItemsProviderProps
public;const;PropertyGridWidgetId
public;interface;PropertyGridWidgetProps
public;type;PropertyGridWidgetProps
public;function;RemoveFavoritePropertyContextMenuItem
public;interface;SettingsMenuItemProps
public;interface;SettingsMenuProps
Expand Down
7 changes: 5 additions & 2 deletions packages/itwin/property-grid/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
"copy:cjs": "cpx \"./src/**/*.scss\" ./lib/cjs",
"copy:esm": "cpx \"./src/**/*.scss\" ./lib/esm",
"cover": "c8 npm run test",
"extract-api": "betools extract-api --entry=property-grid-react --apiReportFolder=./api --apiReportTempFolder=./api/temp --apiSummaryFolder=./api",
"extract-api": "betools extract-api --entry=lib/esm/property-grid-react --apiReportFolder=./api --apiReportTempFolder=./api/temp --apiSummaryFolder=./api",
"check-internal": "node ../../../scripts/checkInternal.js --apiSummary ./api/property-grid-react.api.md",
"lint": "npm run lint:eslint && npm run lint:stylelint",
"lint:eslint": "eslint -f visualstudio \"./src/**/*.{ts,tsx}\" 1>&2",
Expand Down Expand Up @@ -73,6 +73,9 @@
"@itwin/itwinui-icons-react": "^2.8.0",
"@itwin/itwinui-illustrations-react": "^2.1.0",
"@itwin/itwinui-react": "^3.16.5",
"@itwin/presentation-core-interop": "^1.3.0",
"@itwin/presentation-shared": "^1.2.0",
"@itwin/unified-selection": "^1.3.0",
"classnames": "^2.5.1",
"react-error-boundary": "^4.0.10"
},
Expand Down Expand Up @@ -106,7 +109,7 @@
"@types/chai": "^4.3.16",
"@types/jsdom": "^21.1.6",
"@types/mocha": "^10.0.10",
"@types/node": "^18.18.10",
"@types/node": "^22.13.1",
"@types/react": "^18.0.34",
"@types/react-dom": "^18.0.11",
"@types/sinon": "^17.0.3",
Expand Down
Loading
Loading