Skip to content

Commit

Permalink
Presentation: Introduce nth level element selection scope support (#3743
Browse files Browse the repository at this point in the history
)

* Introduce nth level element selection scope support

* Pass RPC request options as an object rather than individual arguments

* Avoid a breaking change
  • Loading branch information
grigasp authored Jun 6, 2022
1 parent e3ef2f5 commit 58d620f
Show file tree
Hide file tree
Showing 28 changed files with 505 additions and 202 deletions.
3 changes: 3 additions & 0 deletions common/api/presentation-backend.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
```ts

import { ClientRequestContext } from '@bentley/bentleyjs-core';
import { ComputeSelectionRequestOptions } from '@bentley/presentation-common';
import { Content } from '@bentley/presentation-common';
import { ContentDescriptorRequestOptions } from '@bentley/presentation-common';
import { ContentRequestOptions } from '@bentley/presentation-common';
Expand Down Expand Up @@ -163,6 +164,8 @@ export class PresentationManager {
ids: Id64String[];
scopeId: string;
}>): Promise<KeySet>;
// @alpha (undocumented)
computeSelection(requestOptions: WithClientRequestContext<ComputeSelectionRequestOptions<IModelDb>>): Promise<KeySet>;
dispose(): void;
// @deprecated
getContent(requestContext: ClientRequestContext, requestOptions: Paged<ContentRequestOptions<IModelDb>>, descriptorOrOverrides: Descriptor | DescriptorOverrides, keys: KeySet): Promise<Content | undefined>;
Expand Down
31 changes: 30 additions & 1 deletion common/api/presentation-common.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,17 @@ export type CompressedDescriptorJSON = Omit<DescriptorJSON, "selectClasses" | "f
// @public
export type ComputeDisplayValueCallback = (type: string, value: PrimitivePropertyValue, displayValue: string) => Promise<string>;

// @alpha
export interface ComputeSelectionRequestOptions<TIModel> extends RequestOptions<TIModel> {
// (undocumented)
elementIds: Id64String[];
// (undocumented)
scope: SelectionScopeProps;
}

// @alpha (undocumented)
export type ComputeSelectionRpcRequestOptions = PresentationRpcRequestOptions<ComputeSelectionRequestOptions<never>>;

// @public
export interface ConditionContainer {
condition?: string;
Expand Down Expand Up @@ -837,6 +848,14 @@ export interface ElementPropertiesStructPropertyItem extends ElementPropertiesPr
type: "struct";
}

// @alpha (undocumented)
export interface ElementSelectionScopeProps {
// (undocumented)
ancestorLevel?: number;
// (undocumented)
id: "element";
}

// @public
export interface EnumerationChoice {
label: string;
Expand Down Expand Up @@ -1343,6 +1362,9 @@ export interface IntsRulesetVariableJSON extends RulesetVariableBaseJSON {
value: number[];
}

// @internal (undocumented)
export function isComputeSelectionRequestOptions<TIModel>(options: ComputeSelectionRequestOptions<TIModel> | SelectionScopeRequestOptions<TIModel>): options is ComputeSelectionRequestOptions<TIModel>;

// @internal (undocumented)
export const isContentDescriptorRequestOptions: <TIModel, TKeySet, TRulesetVariable>(opts: ContentRequestOptions<TIModel, RulesetVariable> | ContentDescriptorRequestOptions<TIModel, TKeySet, TRulesetVariable>) => opts is ContentDescriptorRequestOptions<TIModel, TKeySet, TRulesetVariable>;

Expand Down Expand Up @@ -1963,6 +1985,8 @@ export class PresentationRpcInterface extends RpcInterface {
compareHierarchiesPaged(_token: IModelRpcProps, _options: HierarchyCompareRpcOptions): PresentationRpcResponse<HierarchyCompareInfoJSON>;
// (undocumented)
computeSelection(_token: IModelRpcProps, _options: SelectionScopeRpcRequestOptions, _ids: Id64String[], _scopeId: string): PresentationRpcResponse<KeySetJSON>;
// @alpha (undocumented)
computeSelection(_token: IModelRpcProps, _options: ComputeSelectionRpcRequestOptions): PresentationRpcResponse<KeySetJSON>;
// @deprecated (undocumented)
getContent(_token: IModelRpcProps, _options: ContentRpcRequestOptions, _descriptorOrOverrides: DescriptorJSON | DescriptorOverrides, _keys: KeySetJSON): PresentationRpcResponse<ContentJSON | undefined>;
// @deprecated (undocumented)
Expand Down Expand Up @@ -2550,7 +2574,7 @@ export class RpcRequestsHandler implements IDisposable {
// (undocumented)
compareHierarchiesPaged(options: HierarchyCompareOptions<IModelRpcProps, NodeKeyJSON, RulesetVariableJSON>): Promise<HierarchyCompareInfoJSON>;
// (undocumented)
computeSelection(options: SelectionScopeRequestOptions<IModelRpcProps>, ids: Id64String[], scopeId: string): Promise<KeySetJSON>;
computeSelection(options: ComputeSelectionRequestOptions<IModelRpcProps>): Promise<KeySetJSON>;
// (undocumented)
dispose(): void;
// (undocumented)
Expand Down Expand Up @@ -2767,6 +2791,11 @@ export interface SelectionScope {
label: string;
}

// @alpha (undocumented)
export type SelectionScopeProps = ElementSelectionScopeProps | {
id: string;
};

// @public
export interface SelectionScopeRequestOptions<TIModel> extends RequestOptions<TIModel> {
}
Expand Down
18 changes: 11 additions & 7 deletions common/api/presentation-frontend.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ import { Ruleset } from '@bentley/presentation-common';
import { RulesetVariable } from '@bentley/presentation-common';
import { SelectionInfo } from '@bentley/presentation-common';
import { SelectionScope } from '@bentley/presentation-common';
import { SelectionScopeProps } from '@bentley/presentation-common';
import { SetRulesetVariableParams } from '@bentley/presentation-common';
import { UnsetRulesetVariableParams } from '@bentley/presentation-common';
import { UpdateHierarchyStateParams } from '@bentley/presentation-common';
Expand All @@ -68,6 +69,9 @@ export function createCombinedDiagnosticsHandler(handlers: DiagnosticsHandler[])
// @internal (undocumented)
export const createFieldOrderInfos: (field: Field) => FavoritePropertiesOrderInfo[];

// @internal
export function createSelectionScopeProps(scope: SelectionScopeProps | SelectionScope | string | undefined): SelectionScopeProps;

// @public
export class FavoritePropertiesManager implements IDisposable {
constructor(props: FavoritePropertiesManagerProps);
Expand Down Expand Up @@ -123,7 +127,7 @@ export enum FavoritePropertiesScope {
// @internal (undocumented)
export const getFieldInfos: (field: Field) => Set<PropertyFullName>;

// @public
// @public @deprecated
export function getScopeId(scope: SelectionScope | string | undefined): string;

// @internal (undocumented)
Expand Down Expand Up @@ -477,15 +481,15 @@ export class SelectionHelper {
export class SelectionManager implements ISelectionProvider {
constructor(props: SelectionManagerProps);
addToSelection(source: string, imodel: IModelConnection, keys: Keys, level?: number, rulesetId?: string): void;
addToSelectionWithScope(source: string, imodel: IModelConnection, ids: Id64Arg, scope: SelectionScope | string, level?: number, rulesetId?: string): Promise<void>;
addToSelectionWithScope(source: string, imodel: IModelConnection, ids: Id64Arg, scope: SelectionScopeProps | SelectionScope | string, level?: number, rulesetId?: string): Promise<void>;
clearSelection(source: string, imodel: IModelConnection, level?: number, rulesetId?: string): void;
getHiliteSet(imodel: IModelConnection): Promise<HiliteSet>;
getSelection(imodel: IModelConnection, level?: number): Readonly<KeySet>;
getSelectionLevels(imodel: IModelConnection): number[];
removeFromSelection(source: string, imodel: IModelConnection, keys: Keys, level?: number, rulesetId?: string): void;
removeFromSelectionWithScope(source: string, imodel: IModelConnection, ids: Id64Arg, scope: SelectionScope | string, level?: number, rulesetId?: string): Promise<void>;
removeFromSelectionWithScope(source: string, imodel: IModelConnection, ids: Id64Arg, scope: SelectionScopeProps | SelectionScope | string, level?: number, rulesetId?: string): Promise<void>;
replaceSelection(source: string, imodel: IModelConnection, keys: Keys, level?: number, rulesetId?: string): void;
replaceSelectionWithScope(source: string, imodel: IModelConnection, ids: Id64Arg, scope: SelectionScope | string, level?: number, rulesetId?: string): Promise<void>;
replaceSelectionWithScope(source: string, imodel: IModelConnection, ids: Id64Arg, scope: SelectionScopeProps | SelectionScope | string, level?: number, rulesetId?: string): Promise<void>;
readonly scopes: SelectionScopesManager;
readonly selectionChange: SelectionChangeEvent;
setSyncWithIModelToolSelection(imodel: IModelConnection, sync?: boolean): void;
Expand All @@ -501,9 +505,9 @@ export interface SelectionManagerProps {
export class SelectionScopesManager {
constructor(props: SelectionScopesManagerProps);
get activeLocale(): string | undefined;
get activeScope(): SelectionScope | string | undefined;
set activeScope(scope: SelectionScope | string | undefined);
computeSelection(imodel: IModelConnection, ids: Id64Arg, scope: SelectionScope | string): Promise<KeySet>;
get activeScope(): SelectionScopeProps | SelectionScope | string | undefined;
set activeScope(scope: SelectionScopeProps | SelectionScope | string | undefined);
computeSelection(imodel: IModelConnection, ids: Id64Arg, scope: SelectionScopeProps | SelectionScope | string): Promise<KeySet>;
getSelectionScopes(imodel: IModelConnection, locale?: string): Promise<SelectionScope[]>;
}

Expand Down
5 changes: 5 additions & 0 deletions common/api/summary/presentation-common.exports.csv
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ internal;CommonIpcParams
public;CompressedClassInfoJSON
public;CompressedDescriptorJSON = Omit
public;ComputeDisplayValueCallback = (type: string, value: PrimitivePropertyValue, displayValue: string) => Promise
alpha;ComputeSelectionRequestOptions
alpha;ComputeSelectionRpcRequestOptions = PresentationRpcRequestOptions
public;ConditionContainer
public;Content
public;ContentDescriptorRequestOptions
Expand Down Expand Up @@ -120,6 +122,7 @@ beta;ElementPropertiesRequestOptions
beta;ElementPropertiesRpcRequestOptions = PresentationRpcRequestOptions
beta;ElementPropertiesStructArrayPropertyItem
beta;ElementPropertiesStructPropertyItem
alpha;ElementSelectionScopeProps
public;EnumerationChoice
public;EnumerationInfo
alpha;ExpandedNodeUpdateRecord
Expand Down Expand Up @@ -189,6 +192,7 @@ public;IntRulesetVariable
public;IntRulesetVariableJSON
public;IntsRulesetVariable
public;IntsRulesetVariableJSON
internal;isComputeSelectionRequestOptions
internal;isContentDescriptorRequestOptions:
internal;isDisplayLabelRequestOptions:
internal;isDisplayLabelsRequestOptions:
Expand Down Expand Up @@ -366,6 +370,7 @@ public;SelectClassInfoJSON
public;SelectedNodeInstancesSpecification
public;SelectionInfo
public;SelectionScope
alpha;SelectionScopeProps = ElementSelectionScopeProps |
public;SelectionScopeRequestOptions
public;SelectionScopeRpcRequestOptions = PresentationRpcRequestOptions
internal;SetRulesetVariableParams
Expand Down
2 changes: 2 additions & 0 deletions common/api/summary/presentation-frontend.exports.csv
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ internal;buildPagedResponse:
alpha;consoleDiagnosticsHandler(scopeLogs: DiagnosticsScopeLogs[]): void
alpha;createCombinedDiagnosticsHandler(handlers: DiagnosticsHandler[]): (scopeLogs: DiagnosticsScopeLogs[]) => void
internal;createFieldOrderInfos: (field: Field) => FavoritePropertiesOrderInfo[]
internal;createSelectionScopeProps(scope: SelectionScopeProps | SelectionScope | string | undefined): SelectionScopeProps
public;FavoritePropertiesManager
public;FavoritePropertiesManagerProps
public;FavoritePropertiesOrderInfo
public;FavoritePropertiesScope
internal;getFieldInfos: (field: Field) => Set
public;getScopeId(scope: SelectionScope | string | undefined): string
deprecated;getScopeId(scope: SelectionScope | string | undefined): string
internal;HILITE_RULESET: Ruleset
public;HiliteSet
public;HiliteSetProvider
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"changes": [
{
"packageName": "@bentley/presentation-backend",
"comment": "Add support for nth level element selection scopes.",
"type": "none"
}
],
"packageName": "@bentley/presentation-backend",
"email": "35135765+grigasp@users.noreply.github.com"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"changes": [
{
"packageName": "@bentley/presentation-common",
"comment": "Add support for nth level element selection scopes.",
"type": "none"
}
],
"packageName": "@bentley/presentation-common",
"email": "35135765+grigasp@users.noreply.github.com"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"changes": [
{
"packageName": "@bentley/presentation-components",
"comment": "",
"type": "none"
}
],
"packageName": "@bentley/presentation-components",
"email": "35135765+grigasp@users.noreply.github.com"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"changes": [
{
"packageName": "@bentley/presentation-frontend",
"comment": "Add support for nth level element selection scopes.",
"type": "none"
}
],
"packageName": "@bentley/presentation-frontend",
"email": "35135765+grigasp@users.noreply.github.com"
}
24 changes: 24 additions & 0 deletions full-stack-tests/presentation/src/frontend/SelectionScopes.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,14 @@ describe("Selection Scopes", () => {
expect(selection.has({ className: elementProps[0].classFullName, id: elementProps[0].id! }));
});

it("sets correct selection with 'element' 1st parent level selection scope", async () => {
const elementProps = await imodel.elements.getProps(Id64.fromUint32Pair(28, 0));
await Presentation.selection.addToSelectionWithScope("", imodel, elementProps[0].id!, { id: "element", ancestorLevel: 1 });
const selection = Presentation.selection.getSelection(imodel);
expect(selection.size).to.eq(1);
expect(selection.has({ className: "BisCore:Subject", id: Id64.fromUint32Pair(27, 0) }));
});

it("sets correct selection with 'assembly' selection scope", async () => {
const elementProps = await imodel.elements.getProps(Id64.fromUint32Pair(28, 0));
await Presentation.selection.addToSelectionWithScope("", imodel, elementProps[0].id!, "assembly");
Expand All @@ -49,6 +57,22 @@ describe("Selection Scopes", () => {
expect(selection.has({ className: "BisCore:Subject", id: Id64.fromUint32Pair(27, 0) }));
});

it("sets correct selection with 'element' 2nd parent level selection scope", async () => {
const elementProps = await imodel.elements.getProps(Id64.fromUint32Pair(28, 0));
await Presentation.selection.addToSelectionWithScope("", imodel, elementProps[0].id!, { id: "element", ancestorLevel: 2 });
const selection = Presentation.selection.getSelection(imodel);
expect(selection.size).to.eq(1);
expect(selection.has({ className: "BisCore:Subject", id: Id64.fromUint32Pair(1, 0) }));
});

it("sets correct selection with 'element' exceeding parent level selection scope", async () => {
const elementProps = await imodel.elements.getProps(Id64.fromUint32Pair(28, 0));
await Presentation.selection.addToSelectionWithScope("", imodel, elementProps[0].id!, { id: "element", ancestorLevel: 999 });
const selection = Presentation.selection.getSelection(imodel);
expect(selection.size).to.eq(1);
expect(selection.has({ className: "BisCore:Subject", id: Id64.fromUint32Pair(1, 0) }));
});

it("sets correct selection with 'top-assembly' selection scope", async () => {
const elementProps = await imodel.elements.getProps(Id64.fromUint32Pair(28, 0));
await Presentation.selection.addToSelectionWithScope("", imodel, elementProps[0].id!, "top-assembly");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ import { ClientRequestContext, Id64String, Logger } from "@bentley/bentleyjs-cor
import { BriefcaseDb, IModelDb, IModelJsNative, IpcHost } from "@bentley/imodeljs-backend";
import { FormatProps } from "@bentley/imodeljs-quantity";
import {
Content, ContentDescriptorRequestOptions, ContentFlags, ContentRequestOptions, DefaultContentDisplayTypes, Descriptor, DescriptorOverrides,
DiagnosticsOptionsWithHandler, DisplayLabelRequestOptions, DisplayLabelsRequestOptions, DisplayValueGroup, DistinctValuesRequestOptions,
ElementProperties, ElementPropertiesRequestOptions, ExtendedContentRequestOptions, ExtendedHierarchyRequestOptions, getLocalesDirectory,
HierarchyCompareInfo, HierarchyCompareOptions, HierarchyRequestOptions, InstanceKey, KeySet, LabelDefinition, LabelRequestOptions, Node, NodeKey,
NodePathElement, Paged, PagedResponse, PartialHierarchyModification, PresentationError, PresentationStatus, PresentationUnitSystem, RequestPriority,
Ruleset, SelectionInfo, SelectionScope, SelectionScopeRequestOptions,
ComputeSelectionRequestOptions, Content, ContentDescriptorRequestOptions, ContentFlags, ContentRequestOptions, DefaultContentDisplayTypes,
Descriptor, DescriptorOverrides, DiagnosticsOptionsWithHandler, DisplayLabelRequestOptions, DisplayLabelsRequestOptions, DisplayValueGroup,
DistinctValuesRequestOptions, ElementProperties, ElementPropertiesRequestOptions, ExtendedContentRequestOptions, ExtendedHierarchyRequestOptions,
getLocalesDirectory, HierarchyCompareInfo, HierarchyCompareOptions, HierarchyRequestOptions, InstanceKey, isComputeSelectionRequestOptions, KeySet, LabelDefinition,
LabelRequestOptions, Node, NodeKey, NodePathElement, Paged, PagedResponse, PartialHierarchyModification, PresentationError, PresentationStatus,
PresentationUnitSystem, RequestPriority, Ruleset, SelectionInfo, SelectionScope, SelectionScopeRequestOptions,
} from "@bentley/presentation-common";
import { PresentationBackendLoggerCategory } from "./BackendLoggerCategory";
import { PRESENTATION_BACKEND_ASSETS_ROOT, PRESENTATION_COMMON_ASSETS_ROOT } from "./Constants";
Expand Down Expand Up @@ -902,12 +902,20 @@ export class PresentationManager {
* @public
*/
public async computeSelection(requestOptions: WithClientRequestContext<SelectionScopeRequestOptions<IModelDb> & { ids: Id64String[], scopeId: string }>): Promise<KeySet>;
public async computeSelection(requestContextOrOptions: ClientRequestContext | WithClientRequestContext<SelectionScopeRequestOptions<IModelDb> & { ids: Id64String[], scopeId: string }>, deprecatedRequestOptions?: SelectionScopeRequestOptions<IModelDb>, deprecatedIds?: Id64String[], deprecatedScopeId?: string): Promise<KeySet> {
/** @alpha */
// eslint-disable-next-line @typescript-eslint/unified-signatures
public async computeSelection(requestOptions: WithClientRequestContext<ComputeSelectionRequestOptions<IModelDb>>): Promise<KeySet>;
public async computeSelection(requestContextOrOptions: ClientRequestContext | WithClientRequestContext<ComputeSelectionRequestOptions<IModelDb>> | WithClientRequestContext<SelectionScopeRequestOptions<IModelDb> & { ids: Id64String[], scopeId: string }>, deprecatedRequestOptions?: SelectionScopeRequestOptions<IModelDb>, deprecatedIds?: Id64String[], deprecatedScopeId?: string): Promise<KeySet> {
if (requestContextOrOptions instanceof ClientRequestContext) {
return this.computeSelection({ ...deprecatedRequestOptions!, requestContext: requestContextOrOptions, ids: deprecatedIds!, scopeId: deprecatedScopeId! });
return this.computeSelection({ ...deprecatedRequestOptions!, requestContext: requestContextOrOptions, elementIds: deprecatedIds!, scope: { id: deprecatedScopeId! } });
}
const { requestContext, ids, scopeId, ...requestOptions } = requestContextOrOptions; // eslint-disable-line @typescript-eslint/no-unused-vars
return SelectionScopesHelper.computeSelection(requestOptions, ids, scopeId);
const { requestContext, ...requestOptions } = requestContextOrOptions; // eslint-disable-line @typescript-eslint/no-unused-vars
return SelectionScopesHelper.computeSelection(isComputeSelectionRequestOptions(requestOptions)
? requestOptions
: (function () {
const { ids, scopeId, ...rest } = requestOptions;
return { ...rest, elementIds: ids, scope: { id: scopeId } };
})());
}

private async request<TParams extends { requestContext: ClientRequestContext, diagnostics?: DiagnosticsOptionsWithHandler, requestId: string, imodel: IModelDb, locale?: string, unitSystem?: PresentationUnitSystem }, TResult>(params: TParams, reviver?: (key: string, value: any) => any): Promise<TResult> {
Expand Down
Loading

0 comments on commit 58d620f

Please sign in to comment.