Skip to content

Commit

Permalink
Promote filter building APIs (#316)
Browse files Browse the repository at this point in the history
* Add query builder to test-app

* Fix build

* Cleanup filter building API

* Revert demo changes to test-app

* Cleanup

* changes

* extract-api

* Apply PR suggestions

* Handle related same related class reach through different path

* extract-api

* Apply suggestions from code review

Co-authored-by: Grigas <[email protected]>

* Show error state when error is thrown in filtering dialog

---------

Co-authored-by: Grigas <[email protected]>
  • Loading branch information
saskliutas and grigasp authored Oct 23, 2023
1 parent fd0575f commit c6b6167
Show file tree
Hide file tree
Showing 30 changed files with 1,378 additions and 896 deletions.
5 changes: 5 additions & 0 deletions .changeset/chatty-eyes-sniff.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@itwin/presentation-components": minor
---

Added `GenericInstanceFilter` data structure that has all the data needed to convert an instance filter to `ECSQL`, `ECExpression` or other formats. The data structure can be created from `PresentationInstanceFilter` using the `GenericInstanceFilter.fromPresentationInstanceFilter` call.
16 changes: 16 additions & 0 deletions .changeset/gorgeous-sloths-hang.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
"@itwin/presentation-components": minor
---

Promoted some instance filtering - related `internal` APIs to `beta`:

- `useInstanceFilterPropertyInfos` - for creating a property list based on supplied `Descriptor`. The property list is necessary for rendering the `PropertyFilterBuilder` component from `@itwin/component-react` package.
- `PresentationFilterBuilderValueRenderer` - a custom renderer for property value input. It renders unique values selector for `Equal` / `NotEqual` rules and handles unit conversion on top of the general value input.
- `PresentationInstanceFilter.fromComponentsPropertyFilter` - for adding presentation data to `PropertyFilter` built by `usePropertyFilterBuilder`.
- `PresentationInstanceFilter.toComponentsPropertyFilter` - for stripping out presentation data from filter for usage with `usePropertyFilterBuilder`.
- `PresentationInstanceFilterPropertyInfo` - data structure defining a property used in instance filter.

Also, moved a couple of beta APIs to a common namespace to make them more discoverable:

- `convertToInstanceFilterDefinition` -> `PresentationInstanceFilter.toInstanceFilterDefinition`,
- `isPresentationInstanceFilterConditionGroup` -> `PresentationInstanceFilter.isConditionGroup`.
83 changes: 75 additions & 8 deletions packages/components/api/presentation-components.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import { AbstractTreeNodeLoaderWithProvider } from '@itwin/components-react';
import { ActiveMatchInfo } from '@itwin/components-react';
import { CategoryDescription } from '@itwin/presentation-common';
import { ClassId } from '@itwin/presentation-common';
import { ClassInfo } from '@itwin/presentation-common';
import { ClientDiagnosticsHandler } from '@itwin/presentation-common';
import { ClientDiagnosticsOptions } from '@itwin/presentation-common';
Expand Down Expand Up @@ -60,6 +61,8 @@ import { PropertyDataChangeEvent } from '@itwin/components-react';
import { PropertyDataFiltererBase } from '@itwin/components-react';
import { PropertyDataFilterResult } from '@itwin/components-react';
import { PropertyDescription } from '@itwin/appui-abstract';
import { PropertyFilter } from '@itwin/components-react';
import { PropertyFilterBuilderRuleValueRendererProps } from '@itwin/components-react';
import { PropertyFilterRuleGroupOperator } from '@itwin/components-react';
import { PropertyFilterRuleOperator } from '@itwin/components-react';
import { PropertyRecord } from '@itwin/appui-abstract';
Expand All @@ -80,6 +83,7 @@ import { StartContentProps } from '@itwin/presentation-common';
import { StartFieldProps } from '@itwin/presentation-common';
import { StartItemProps } from '@itwin/presentation-common';
import { StartStructProps } from '@itwin/presentation-common';
import { StrippedRelationshipPath } from '@itwin/presentation-common';
import { Subscription } from '@itwin/components-react';
import { TreeEditingParams } from '@itwin/components-react';
import { TreeEventHandler } from '@itwin/components-react';
Expand Down Expand Up @@ -154,9 +158,6 @@ export interface ControlledPresentationTreeFilteringProps {
nodeLoader: AbstractTreeNodeLoaderWithProvider<IPresentationTreeDataProvider>;
}

// @beta
export function convertToInstanceFilterDefinition(filter: PresentationInstanceFilter, imodel: IModelConnection): Promise<InstanceFilterDefinition>;

// @alpha
export function createDiagnosticsOptions(props: DiagnosticsProps): ClientDiagnosticsOptions | undefined;

Expand Down Expand Up @@ -312,8 +313,33 @@ export interface FilteredPresentationTreeDataProviderProps {
paths: ReadonlyArray<Readonly<NodePathElement>>;
}

// @internal (undocumented)
export function findBaseExpressionClass(imodel: IModelConnection, propertyClasses: ClassInfo[]): Promise<ClassInfo>;
// @beta
export interface GenericInstanceFilter {
propertyClasses: ClassInfo[];
relatedInstances: RelatedInstanceDescription[];
rules: GenericInstanceFilterRule | GenericInstanceFilterRuleGroup;
}

// @beta (undocumented)
export namespace GenericInstanceFilter {
export function fromPresentationInstanceFilter(filter: PresentationInstanceFilter): GenericInstanceFilter;
export function isFilterRuleGroup(obj: GenericInstanceFilterRule | GenericInstanceFilterRuleGroup): obj is GenericInstanceFilterRuleGroup;
}

// @beta
export interface GenericInstanceFilterRule {
operator: PropertyFilterRuleOperator;
propertyName: string;
propertyTypeName: string;
sourceAlias: string;
value?: PrimitiveValue;
}

// @beta
export interface GenericInstanceFilterRuleGroup {
operator: PropertyFilterRuleGroupOperator;
rules: Array<GenericInstanceFilterRule | GenericInstanceFilterRuleGroup>;
}

// @internal (undocumented)
export const getFavoritesCategory: () => CategoryDescription;
Expand Down Expand Up @@ -407,9 +433,6 @@ export function isFilterablePresentationTreeNodeItem(item: PresentationTreeNodeI
// @beta
export function isPresentationInfoTreeNodeItem(item: TreeNodeItem): item is PresentationInfoTreeNodeItem;

// @beta
export function isPresentationInstanceFilterConditionGroup(filter: PresentationInstanceFilter): filter is PresentationInstanceFilterConditionGroup;

// @beta
export function isPresentationTreeNodeItem(item: TreeNodeItem): item is PresentationTreeNodeItem;

Expand All @@ -436,6 +459,16 @@ export enum PresentationComponentsLoggerCategory {
Package = "presentation-components"
}

// @beta
export function PresentationFilterBuilderValueRenderer({ imodel, descriptor, descriptorInputKeys, ...props }: PresentationFilterBuilderValueRendererProps): JSX.Element;

// @beta
export interface PresentationFilterBuilderValueRendererProps extends PropertyFilterBuilderRuleValueRendererProps {
descriptor: Descriptor;
descriptorInputKeys?: Keys;
imodel: IModelConnection;
}

// @beta
export interface PresentationInfoTreeNodeItem extends ImmediatelyLoadedTreeNodeItem {
children: undefined;
Expand All @@ -447,6 +480,14 @@ export interface PresentationInfoTreeNodeItem extends ImmediatelyLoadedTreeNodeI
// @beta
export type PresentationInstanceFilter = PresentationInstanceFilterConditionGroup | PresentationInstanceFilterCondition;

// @beta (undocumented)
export namespace PresentationInstanceFilter {
export function fromComponentsPropertyFilter(descriptor: Descriptor, filter: PropertyFilter): PresentationInstanceFilter;
export function isConditionGroup(filter: PresentationInstanceFilter): filter is PresentationInstanceFilterConditionGroup;
export function toComponentsPropertyFilter(descriptor: Descriptor, filter: PresentationInstanceFilter): PropertyFilter;
export function toInstanceFilterDefinition(filter: PresentationInstanceFilter, imodel: IModelConnection): Promise<InstanceFilterDefinition>;
}

// @beta
export interface PresentationInstanceFilterCondition {
field: PropertiesField;
Expand Down Expand Up @@ -483,6 +524,15 @@ export interface PresentationInstanceFilterInfo {
usedClasses: ClassInfo[];
}

// @beta
export interface PresentationInstanceFilterPropertyInfo {
categoryLabel?: string;
className: string;
field: PropertiesField;
propertyDescription: PropertyDescription;
sourceClassId: ClassId;
}

// @public
export class PresentationLabelsProvider implements IPresentationLabelsProvider {
constructor(props: PresentationLabelsProviderProps);
Expand Down Expand Up @@ -682,6 +732,12 @@ export abstract class PropertyRecordsBuilder implements IContentVisitor {
startStruct(props: StartStructProps): boolean;
}

// @beta
export interface RelatedInstanceDescription {
alias: string;
path: StrippedRelationshipPath;
}

// @beta
export interface SchemaMetadataContext {
schemaContext: SchemaContext;
Expand Down Expand Up @@ -809,6 +865,17 @@ export interface UseHierarchyLevelFilteringProps {
nodeLoader: ITreeNodeLoader;
}

// @beta
export function useInstanceFilterPropertyInfos({ descriptor }: UseInstanceFilterPropertyInfosProps): {
propertyInfos: PresentationInstanceFilterPropertyInfo[];
propertyRenderer: (name: string) => JSX.Element;
};

// @beta
export interface UseInstanceFilterPropertyInfosProps {
descriptor: Descriptor;
}

// @beta
export function useNavigationPropertyEditingContext(imodel: IModelConnection, dataProvider: IContentDataProvider): NavigationPropertyEditorContextProps;

Expand Down
14 changes: 11 additions & 3 deletions packages/components/api/presentation-components.exports.csv
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ public;CacheInvalidationProps
public;ContentDataProvider
public;ContentDataProviderProps
public;ControlledPresentationTreeFilteringProps
beta;convertToInstanceFilterDefinition(filter: PresentationInstanceFilter, imodel: IModelConnection): Promise
alpha;createDiagnosticsOptions(props: DiagnosticsProps): ClientDiagnosticsOptions | undefined
internal;createFieldInfo(field: Field, parentFieldName?: string):
internal;createPropertyDescriptionFromFieldInfo(info: FieldInfo): PropertyDescription
Expand All @@ -22,7 +21,10 @@ internal;FieldRecord
beta;FilterablePresentationTreeNodeItem = PresentationTreeNodeItem &
internal;FilteredPresentationTreeDataProvider
internal;FilteredPresentationTreeDataProviderProps
internal;findBaseExpressionClass(imodel: IModelConnection, propertyClasses: ClassInfo[]): Promise
beta;GenericInstanceFilter
beta;GenericInstanceFilter
beta;GenericInstanceFilterRule
beta;GenericInstanceFilterRuleGroup
internal;getFavoritesCategory: () => CategoryDescription
beta;HierarchyLevelFilteringDescriptor = Descriptor | (() => Promise
public;IContentDataProvider
Expand All @@ -37,19 +39,22 @@ public;IPresentationTreeDataProvider
internal;IPropertiesAppender
beta;isFilterablePresentationTreeNodeItem(item: PresentationTreeNodeItem): item is FilterablePresentationTreeNodeItem
beta;isPresentationInfoTreeNodeItem(item: TreeNodeItem): item is PresentationInfoTreeNodeItem
beta;isPresentationInstanceFilterConditionGroup(filter: PresentationInstanceFilter): filter is PresentationInstanceFilterConditionGroup
beta;isPresentationTreeNodeItem(item: TreeNodeItem): item is PresentationTreeNodeItem
public;IUnifiedSelectionComponent
beta;navigationPropertyEditorContext: Context
beta;NavigationPropertyEditorContextProps
public;PresentationComponentsLoggerCategory
beta;PresentationFilterBuilderValueRenderer({ imodel, descriptor, descriptorInputKeys, ...props }: PresentationFilterBuilderValueRendererProps): JSX.Element
beta;PresentationFilterBuilderValueRendererProps
beta;PresentationInfoTreeNodeItem
beta;PresentationInstanceFilter = PresentationInstanceFilterConditionGroup | PresentationInstanceFilterCondition
beta;PresentationInstanceFilter
beta;PresentationInstanceFilterCondition
beta;PresentationInstanceFilterConditionGroup
beta;PresentationInstanceFilterDialog(props: PresentationInstanceFilterDialogProps): JSX.Element
beta;PresentationInstanceFilterDialogProps
beta;PresentationInstanceFilterInfo
beta;PresentationInstanceFilterPropertyInfo
public;PresentationLabelsProvider
public;PresentationLabelsProviderProps
public;PresentationPropertyDataProvider
Expand All @@ -67,6 +72,7 @@ beta;PresentationTreeRenderer(props: PresentationTreeRendererProps): JSX.Element
beta;PresentationTreeRendererProps
public;PropertyDataProviderWithUnifiedSelectionProps
internal;class PropertyRecordsBuilder
beta;RelatedInstanceDescription
beta;SchemaMetadataContext
beta;SchemaMetadataContextProvider({ schemaContextProvider, imodel, children }: PropsWithChildren
beta;SchemaMetadataContextProviderProps
Expand All @@ -85,6 +91,8 @@ public;useControlledPresentationTreeFiltering(props: ControlledPresentationTreeF
internal;useFilteredNodeLoader(dataProvider: IPresentationTreeDataProvider, filter: string | undefined):
beta;useHierarchyLevelFiltering(props: UseHierarchyLevelFilteringProps):
beta;UseHierarchyLevelFilteringProps
beta;useInstanceFilterPropertyInfos({ descriptor }: UseInstanceFilterPropertyInfosProps):
beta;UseInstanceFilterPropertyInfosProps
beta;useNavigationPropertyEditingContext(imodel: IModelConnection, dataProvider: IContentDataProvider): NavigationPropertyEditorContextProps
internal;useNodeHighlightingProps(filter: string | undefined, filteredNodeLoader?: ITreeNodeLoaderWithProvider
beta;usePresentationTable
Expand Down
3 changes: 2 additions & 1 deletion packages/components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,13 @@
},
"dependencies": {
"@itwin/itwinui-icons-react": "^2.4.0",
"@itwin/itwinui-illustrations-react": "^2.1.0",
"@itwin/itwinui-react": "^2.12.10",
"@itwin/itwinui-variables": "^2.1.0",
"classnames": "^2.3.2",
"fast-deep-equal": "^3.1.3",
"fast-sort": "^3.4.0",
"micro-memoize": "^4.1.2",
"react-error-boundary": "^4.0.11",
"react-select": "5.7.0",
"react-select-async-paginate": "0.7.2",
"rxjs": "^7.8.1"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
}
},
"general": {
"display-label": "Label"
"display-label": "Label",
"error": "Error",
"generic-error-description": "An unexpected error was encountered."
},
"property-grid": {
"too-many-elements-selected": "Too many elements selected"
Expand Down
4 changes: 2 additions & 2 deletions packages/components/src/presentation-components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,8 @@ export * from "./presentation-components/unified-selection/UnifiedSelectionConte
* Utilities for creating filters for filtering presentation data.
*/
export * from "./presentation-components/instance-filter-builder/PresentationInstanceFilterDialog";
export * from "./presentation-components/instance-filter-builder/InstanceFilterConverter";
export * from "./presentation-components/instance-filter-builder/Types";
export * from "./presentation-components/instance-filter-builder/PresentationFilterBuilder";
export * from "./presentation-components/instance-filter-builder/GenericInstanceFilter";

/**
* @module Internal
Expand Down
Loading

0 comments on commit c6b6167

Please sign in to comment.