diff --git a/common/changes/@itwin/presentation-common/presentation-common-rule-docs_2022-03-03-11-17.json b/common/changes/@itwin/presentation-common/presentation-common-rule-docs_2022-03-03-11-17.json new file mode 100644 index 000000000000..832da0bf5908 --- /dev/null +++ b/common/changes/@itwin/presentation-common/presentation-common-rule-docs_2022-03-03-11-17.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@itwin/presentation-common", + "comment": "", + "type": "none" + } + ], + "packageName": "@itwin/presentation-common" +} \ No newline at end of file diff --git a/docs/changehistory/2.11.0.md b/docs/changehistory/2.11.0.md index 44d886f2f7c1..2645499506aa 100644 --- a/docs/changehistory/2.11.0.md +++ b/docs/changehistory/2.11.0.md @@ -296,7 +296,7 @@ A property value renderer for instance key values has been added, which allows u ### Breaking changes to `ContentRelatedInstances` -Behavior of `ContentRelatedInstances` specification used in content rules was changed. It used to include input instances into the result if all paths in `relationshipPaths` property had `count: "*"` and target class matched input instance class. The behavior was changed to match cases where steps `relationshipPaths` have `count` set to specific number - the result only includes instances resulting from step outputs. See [RelationshipPathSpecification documentation]($docs/presentation/Common-Rules/RelationshipPathSpecification.md) for more details and examples. +Behavior of `ContentRelatedInstances` specification used in content rules was changed. It used to include input instances into the result if all paths in `relationshipPaths` property had `count: "*"` and target class matched input instance class. The behavior was changed to match cases where steps `relationshipPaths` have `count` set to specific number - the result only includes instances resulting from step outputs. See [RelationshipPathSpecification documentation]($docs/presentation/RelationshipPathSpecification.md) for more details and examples. Example: diff --git a/docs/presentation/Common-Rules/RelatedInstanceSpecification.md b/docs/presentation/Common-Rules/RelatedInstanceSpecification.md deleted file mode 100644 index 2bc621eb74af..000000000000 --- a/docs/presentation/Common-Rules/RelatedInstanceSpecification.md +++ /dev/null @@ -1,32 +0,0 @@ -# RelatedInstance Specification - -> TypeScript type: [RelatedInstanceSpecification]($presentation-common). - -Related instance specification can be used in conjunction with both content -and hierarchy related rules. It's primary purpose is to *join* primary instance -with some related instance and allow using them both for: - -- filtering -- labeling -- grouping - -## Attributes - -| Name | Required? | Type | Default | Meaning | -| ------------------ | --------- | --------------------------------------------------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `relationshipPath` | Yes | [`RelationshipPathSpecification`](./RelationshipPathSpecification.md) | | [Specification of the relationship path](./RelationshipPathSpecification.md) to use for joining the related instance. | -| `alias` | Yes | `string` | | The alias to give for the joined related instance. Used to reference the related instance in instance filter and customization rules. **The value must be unique per-specification.** | -| `isRequired` | No | `boolean` | `false` | Is the related instance required to exist. If yes, primary instance won't be returned if the related instance doesn't exist. If not, primary instance will be returned, but related instance will be null. In SQL terms in can be compared to INNER JOIN vs OUTER JOIN. | - -## Example - -```JSON -{ - "relationshipPath": { - "relationship": { "schemaName": "BisCore", "className": "ModelModelsElement" }, - "direction": "Forward", - "targetClass": { "schemaName": "BisCore", "className": "Element" } - }, - "alias": "modeledElement" -} -``` diff --git a/docs/presentation/Common-Rules/RelationshipPathSpecification.md b/docs/presentation/Common-Rules/RelationshipPathSpecification.md deleted file mode 100644 index 59c1013723e1..000000000000 --- a/docs/presentation/Common-Rules/RelationshipPathSpecification.md +++ /dev/null @@ -1,108 +0,0 @@ -# RelationshipPath Specification - -> TypeScript type: [RepeatableRelationshipPathSpecification]($presentation-common). - -Relationship path specification and it's *repeatable* counterpart are used to define paths from one ECClass to another, optionally traversing through multiple relationships. - -## Attributes - -| Name | Required? | Type | Default | Meaning | -| -------------- | --------- | -------------------------------- | ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `relationship` | Yes | `SingleSchemaClassSpecification` | | Specification of the relationship to follow. | -| `direction` | Yes | `"Forward" \| "Backward"` | | Direction in which the relationship should be followed. | -| `targetClass` | No | `SingleSchemaClassSpecification` | Other end of relationship | Specification of the related class. | -| `count` | No | `number \| "*"` | 1 | Number of times the relationship should be traversed. `"*"` makes the step optional, so results of previous step are also included in results of this step, no matter if this step has any output of its own or not. | - -## Example - -A single-step relationship path which simply jumps from *current* ECClass to *BisCore.PhysicalElement* through *BisCore.ModelModelsElement* relationship: - -```JSON -{ - "relationship": { "schemaName": "BisCore", "className": "ModelModelsElement" }, - "direction": "Forward", - "targetClass": { "schemaName": "BisCore", "className": "PhysicalElement" } -} -``` - -A multi-step relationship path which jumps from *current* ECClass through *BisCore.ElementOwnsChildElements* relationship two times in a backward direction: - -```JSON -{ - "relationship": { "schemaName": "BisCore", "className": "ElementOwnsChildElements" }, - "direction": "Backward", - "count": 2 -} -``` - -A two-step relationship path that first jumps from *current* ECClass through *BisCore.ModelModelsElement* and then through *BisCore.ElementOwnsUniqueAspects*: - -```JSON -[{ - "relationship": { "schemaName": "BisCore", "className": "ModelModelsElement" }, - "direction": "Forward" -}, { - "relationship": { "schemaName": "BisCore", "className": "ElementOwnsUniqueAspects" }, - "direction": "Forward" -}] -``` - -A recursive relationship path which recursively walks through a relationship and accumulates all ECInstances it finds: - -```JSON -{ - "relationship": { "schemaName": "BisCore", "className": "ElementOwnsChildElements" }, - "direction": "Forward", - "count": "*" -} -``` - -A two-step relationship path that first jumps from *current* ECClass through *BisCore.ModelModelsElement*, then recursively walks through *BisCore.ElementOwnsChildElements* relationship and then finds all related *BisCore.ElementUniqueAspect*s: - -```JSON -[{ - "relationship": { "schemaName": "BisCore", "className": "ModelModelsElement" }, - "direction": "Forward" -}, { - "relationship": { "schemaName": "BisCore", "className": "ElementOwnsChildElements" }, - "direction": "Forward", - "count": "*" -}, { - "relationship": { "schemaName": "BisCore", "className": "ElementOwnsUniqueAspects" }, - "direction": "Forward", - "targetClass": { "schemaName": "BisCore", "className": "ElementUniqueAspect" } -}] -``` - -A two-step relationship path that finds all *BisCore.Elements* related to *current* ECClass through *BisCore.ModelModelsElement*, then finds all recursively related *BisCore.Element*s to *BisCore.Element*s from the first step through *BisCore.ElementOwnsChildElements* relationship: - -```JSON -[{ - "relationship": { "schemaName": "BisCore", "className": "ModelModelsElement" }, - "direction": "Forward" -}, { - "relationship": { "schemaName": "BisCore", "className": "ElementOwnsChildElements" }, - "direction": "Forward", - "count": "*" -}] -``` - -A three-step relationship path that finds all *BisCore.GeometricElement3d* related to *current* ECClass through *BisCore.ModelContainsElements* relationship, then finds all *BisCore.SpatialCategory*s related to *BisCore.GeometricElement3d*s found in the previous step through *BisCore.GeometricElement3dIsInCategory* relationship and finds all *BisCore.SubCategory*s related to *BisCore.SpatialCategory*s found in the previous step through *BisCore.CategoryOwnsSubCategories* relationship. Result includes *BisCore.GeometricElement3d*s, *BisCore.SpatialCategory*s and *BisCore.SubCategory*s: - -```JSON -[{ - "relationship": { "schemaName": "BisCore", "className": "ModelContainsElements" }, - "direction": "Forward", - "targetClass": { "schemaName": "BisCore", "className": "GeometricElement3d" }, - "count": "*" -}, { - "relationship": { "schemaName": "BisCore", "className": "GeometricElement3dIsInCategory" }, - "direction": "Forward", - "targetClass": { "schemaName": "BisCore", "className": "SpatialCategory" }, - "count": "*" -}, { - "relationship": { "schemaName": "BisCore", "className": "CategoryOwnsSubCategories" }, - "direction": "Forward", - "count": "*" -}] -``` diff --git a/docs/presentation/Content/ContentInstancesOfSpecificClasses.md b/docs/presentation/Content/ContentInstancesOfSpecificClasses.md index 7b9dca91ee5d..44ded0435916 100644 --- a/docs/presentation/Content/ContentInstancesOfSpecificClasses.md +++ b/docs/presentation/Content/ContentInstancesOfSpecificClasses.md @@ -6,28 +6,28 @@ This specification creates content for all instances of specific ECClasses. ## Attributes -| Name | Required? | Type | Default | -| ------------------------------------------------------------------------------- | --------- | ---------------------------------------------------------------------------------------------------------------------------- | ------- | +| Name | Required? | Type | Default | +| ------------------------------------------------------------------------------- | --------- | --------------------------------------------------------------------------------------------------------------- | ------- | | *Filtering* | -| [`classes`](#attribute-classes) | Yes | [`MultiSchemaClassesSpecification \| MultiSchemaClassesSpecification[]`](../Common-Rules/MultiSchemaClassesSpecification.md) | `[]` | -| [`excludedClasses`](#attribute-excludedclasses) | No | [`MultiSchemaClassesSpecification \| MultiSchemaClassesSpecification[]`](../Common-Rules/MultiSchemaClassesSpecification.md) | `[]` | -| [`handlePropertiesPolymorphically`](#attribute-handlepropertiespolymorphically) | No | `boolean` | `false` | -| [`instanceFilter`](#attribute-instancefilter) | No | [ECExpression](./ECExpressions.md#instance-filter) | `""` | -| [`onlyIfNotHandled`](#attribute-onlyifnothandled) | No | `boolean` | `false` | +| [`classes`](#attribute-classes) | Yes | [`MultiSchemaClassesSpecification \| MultiSchemaClassesSpecification[]`](../MultiSchemaClassesSpecification.md) | `[]` | +| [`excludedClasses`](#attribute-excludedclasses) | No | [`MultiSchemaClassesSpecification \| MultiSchemaClassesSpecification[]`](../MultiSchemaClassesSpecification.md) | `[]` | +| [`handlePropertiesPolymorphically`](#attribute-handlepropertiespolymorphically) | No | `boolean` | `false` | +| [`instanceFilter`](#attribute-instancefilter) | No | [ECExpression](./ECExpressions.md#instance-filter) | `""` | +| [`onlyIfNotHandled`](#attribute-onlyifnothandled) | No | `boolean` | `false` | | *Ordering* | -| [`priority`](#attribute-priority) | No | `number` | `1000` | +| [`priority`](#attribute-priority) | No | `number` | `1000` | | *Content Modifiers* | -| [`relatedProperties`](#attribute-relatedproperties) | No | `RelatedPropertiesSpecification[]` | `[]` | -| [`calculatedProperties`](#attribute-calculatedproperties) | No | `CalculatedPropertiesSpecification[]` | `[]` | -| [`propertyCategories`](#attribute-propertycategories) | No | `PropertyCategorySpecification[]` | `[]` | -| [`propertyOverrides`](#attribute-propertyoverrides) | No | `PropertySpecification[]` | `[]` | -| [`showImages`](#attribute-showimages) | No | `boolean` | `false` | +| [`relatedProperties`](#attribute-relatedproperties) | No | `RelatedPropertiesSpecification[]` | `[]` | +| [`calculatedProperties`](#attribute-calculatedproperties) | No | `CalculatedPropertiesSpecification[]` | `[]` | +| [`propertyCategories`](#attribute-propertycategories) | No | `PropertyCategorySpecification[]` | `[]` | +| [`propertyOverrides`](#attribute-propertyoverrides) | No | `PropertySpecification[]` | `[]` | +| [`showImages`](#attribute-showimages) | No | `boolean` | `false` | | *Misc.* | -| [`relatedInstances`](#attribute-relatedinstances) | No | [`RelatedInstanceSpecification[]`](../Common-Rules/RelatedInstanceSpecification.md) | `[]` | +| [`relatedInstances`](#attribute-relatedinstances) | No | [`RelatedInstanceSpecification[]`](../RelatedInstanceSpecification.md) | `[]` | ### Attribute: `classes` -Defines a set of [multi schema classes](../Common-Rules/MultiSchemaClassesSpecification.md) that specify which ECClasses need to be selected to form the result. +Defines a set of [multi schema classes](../MultiSchemaClassesSpecification.md) that specify which ECClasses need to be selected to form the result. ```ts [[include:ContentInstancesOfSpecificClasses.Classes.Ruleset]] @@ -37,7 +37,7 @@ Defines a set of [multi schema classes](../Common-Rules/MultiSchemaClassesSpecif ### Attribute: `excludedClasses` -Defines a set of [multi schema classes](../Common-Rules/MultiSchemaClassesSpecification.md) that prevents specified ECClasses and subclasses from being selected by [`classes` attribute](#attribute-classes). +Defines a set of [multi schema classes](../MultiSchemaClassesSpecification.md) that prevents specified ECClasses and subclasses from being selected by [`classes` attribute](#attribute-classes). ```ts [[include:ContentInstancesOfSpecificClasses.ExcludedClasses.Ruleset]] @@ -150,7 +150,6 @@ Specifications of various [property overrides](./PropertySpecification.md) that | before | ![Example when doing normal property select](./media/sharedattributes-with-propertyoverrides-1.png) | | after | ![Example when selecting with "property overrides"](./media/sharedattributes-with-propertyoverrides-2.png) | - ### Attribute: `showImages` > **Default value:** `false` @@ -159,17 +158,17 @@ Should image IDs be calculated for the returned instances. When `true`, [ImageId ### Attribute: `relatedInstances` -Specifications of [related instances](../Common-Rules/RelatedInstanceSpecification.md) that can be used when creating the content. There are several use cases when this is useful: +Specifications of [related instances](../RelatedInstanceSpecification.md) that can be used when creating the content. There are several use cases when this is useful: -- When there's a need to only load instances that have a related instance. Providing a [related instance](../Common-Rules/RelatedInstanceSpecification.md) - specification with [isRequired](../Common-Rules/RelatedInstanceSpecification.md) set to `true` filters-out the instances that don't have the related instance. +- When there's a need to only load instances that have a related instance. Providing a [related instance](../RelatedInstanceSpecification.md) + specification with [isRequired](../RelatedInstanceSpecification.md#attribute-isrequired) set to `true` filters-out the instances that don't have the related instance. -- When there's a need to filter instances by a related instance value. The [alias](../Common-Rules/RelatedInstanceSpecification.md) attribute may then be used +- When there's a need to filter instances by a related instance value. The [alias](../RelatedInstanceSpecification.md) attribute may then be used in the [`instanceFilter` attribute](#attribute-instancefilter) to reference related instance property values. - When there's a need to customize content based on related instance property values. Related instance classes are included when looking for [customization rules](../Customization/index.md), which allows referencing related instances and their properties in [customization rule ECExpressions](../Customization/ECExpressions.md#override-value) by their - [alias](../Common-Rules/RelatedInstanceSpecification.md). + [alias](../RelatedInstanceSpecification.md#attribute-alias). ```ts [[include:SharedAttributes.RelatedInstances.Ruleset]] @@ -189,4 +188,5 @@ Specifications of [related instances](../Common-Rules/RelatedInstanceSpecificati Tells whether selecting instances from ECClasses specified in [`classes`](#attribute-classes) and [`excludedClasses`](#attribute-excludedclasses) attributes should be polymorphic or not. -The attribute was replaced by [MultiSchemaClasses.arePolymorphic](../Common-Rules/MultiSchemaClassesSpecification.md#attribute-arepolymorphic) attribute specified individually for each class definition under [`classes`](#attribute-classes) and [`excludedClasses`](#attribute-excludedclasses) attributes. At the moment, to keep backwards compatibility, this attribute acts as a fallback value in case the flag is not specified individually for a class definition. +The attribute was replaced by [MultiSchemaClasses.arePolymorphic](../MultiSchemaClassesSpecification.md#attribute-arepolymorphic) attribute specified individually for each class definition under [`classes`](#attribute-classes) +and [`excludedClasses`](#attribute-excludedclasses) attributes. At the moment, to keep backwards compatibility, this attribute acts as a fallback value in case the flag is not specified individually for a class definition. diff --git a/docs/presentation/Content/ContentRelatedInstances.md b/docs/presentation/Content/ContentRelatedInstances.md index c0136ac2dc6b..1dfd29560b1a 100644 --- a/docs/presentation/Content/ContentRelatedInstances.md +++ b/docs/presentation/Content/ContentRelatedInstances.md @@ -6,26 +6,26 @@ Returns content for instances related to the selected (input) instances. ## Attributes -| Name | Required? | Type | Default | -| --------------------------------------------------------- | --------- | ------------------------------------------------------------------------------------- | ------- | +| Name | Required? | Type | Default | +| --------------------------------------------------------- | --------- | -------------------------------------------------------------------------------------------- | ------- | | *Filtering* | -| [`relationshipPaths`](#attribute-relationshippaths) | Yes | [`RelationshipPathSpecification[]`](../Common-Rules/RelationshipPathSpecification.md) | -| [`instanceFilter`](#attribute-instancefilter) | No | [ECExpression](./ECExpressions.md#instance-filter) | `""` | -| [`onlyIfNotHandled`](#attribute-onlyifnothandled) | No | `boolean` | `false` | +| [`relationshipPaths`](#attribute-relationshippaths) | Yes | [`RepeatableRelationshipPathSpecification[]`](../RepeatableRelationshipPathSpecification.md) | +| [`instanceFilter`](#attribute-instancefilter) | No | [ECExpression](./ECExpressions.md#instance-filter) | `""` | +| [`onlyIfNotHandled`](#attribute-onlyifnothandled) | No | `boolean` | `false` | | *Ordering* | -| [`priority`](#attribute-priority) | No | `number` | `1000` | +| [`priority`](#attribute-priority) | No | `number` | `1000` | | *Content Modifiers* | -| [`relatedProperties`](#attribute-relatedproperties) | No | `RelatedPropertiesSpecification[]` | `[]` | -| [`calculatedProperties`](#attribute-calculatedproperties) | No | `CalculatedPropertiesSpecification[]` | `[]` | -| [`propertyCategories`](#attribute-propertycategories) | No | `PropertyCategorySpecification[]` | `[]` | -| [`propertyOverrides`](#attribute-propertyoverrides) | No | `PropertySpecification[]` | `[]` | -| [`showImages`](#attribute-showimages) | No | `boolean` | `false` | +| [`relatedProperties`](#attribute-relatedproperties) | No | `RelatedPropertiesSpecification[]` | `[]` | +| [`calculatedProperties`](#attribute-calculatedproperties) | No | `CalculatedPropertiesSpecification[]` | `[]` | +| [`propertyCategories`](#attribute-propertycategories) | No | `PropertyCategorySpecification[]` | `[]` | +| [`propertyOverrides`](#attribute-propertyoverrides) | No | `PropertySpecification[]` | `[]` | +| [`showImages`](#attribute-showimages) | No | `boolean` | `false` | | *Misc.* | -| [`relatedInstances`](#attribute-relatedinstances) | No | [`RelatedInstanceSpecification[]`](../Common-Rules/RelatedInstanceSpecification.md) | `[]` | +| [`relatedInstances`](#attribute-relatedinstances) | No | [`RelatedInstanceSpecification[]`](../RelatedInstanceSpecification.md) | `[]` | ### Attribute: `relationshipPaths` -Specifies a chain of [relationship path specifications](../Common-Rules/RelationshipPathSpecification.md) that forms a path from an input instance to the output instances. When this array is empty, the specification produces no results. +Specifies a chain of [relationship path specifications](../RepeatableRelationshipPathSpecification.md) that forms a path from an input instance to the output instances. When this array is empty, the specification produces no results. ```ts [[include:ContentRelatedInstances.RelationshipPaths.Ruleset]] @@ -130,17 +130,17 @@ Should image IDs be calculated for the returned instances. When `true`, [ImageId ### Attribute: `relatedInstances` -Specifications of [related instances](../Common-Rules/RelatedInstanceSpecification.md) that can be used when creating the content. There are several use cases when this is useful: +Specifications of [related instances](../RelatedInstanceSpecification.md) that can be used when creating the content. There are several use cases when this is useful: -- When there's a need to only load instances that have a related instance. Providing a [related instance](../Common-Rules/RelatedInstanceSpecification.md) - specification with [isRequired](../Common-Rules/RelatedInstanceSpecification.md) set to `true` filters-out the instances that don't have the related instance. +- When there's a need to only load instances that have a related instance. Providing a [related instance](../RelatedInstanceSpecification.md) + specification with [isRequired](../RelatedInstanceSpecification.md#attribute-isrequired) set to `true` filters-out the instances that don't have the related instance. -- When there's a need to filter instances by a related instance value. The [alias](../Common-Rules/RelatedInstanceSpecification.md) attribute may then be used +- When there's a need to filter instances by a related instance value. The [alias](../RelatedInstanceSpecification.md#attribute-alias) attribute may then be used in the [`instanceFilter` attribute](#attribute-instancefilter) to reference related instance property values. - When there's a need to customize content based on related instance property values. Related instance classes are included when looking for [customization rules](../Customization/index.md), which allows referencing related instances and their properties in [customization rule ECExpressions](../Customization/ECExpressions.md#override-value) by their - [alias](../Common-Rules/RelatedInstanceSpecification.md). + [alias](../RelatedInstanceSpecification.md#attribute-alias). ```ts [[include:SharedAttributes.RelatedInstances.Ruleset]] diff --git a/docs/presentation/Content/RelatedPropertiesSpecification.md b/docs/presentation/Content/RelatedPropertiesSpecification.md index 9e57768f5ae6..9e5025d2ea86 100644 --- a/docs/presentation/Content/RelatedPropertiesSpecification.md +++ b/docs/presentation/Content/RelatedPropertiesSpecification.md @@ -6,19 +6,19 @@ This specification allows including related instance properties into the content ## Attributes -| Name | Required? | Type | Default | -| --------------------------------------------------------------------------------- | --------- | ----------------------------------------------------------------------------------- | ------------------- | -| [`propertiesSource`](#attribute-propertiessource) | Yes | [`RelationshipPathSpecification`](../Common-Rules/RelationshipPathSpecification.md) | | -| [`handleTargetClassPolymorphically`](#attribute-handletargetclasspolymorphically) | No | `boolean` | `false` | -| [`relationshipMeaning`](#attribute-relationshipmeaning) | No | `"SameInstance" \| "RelatedInstance"` | `"RelatedInstance"` | -| [`properties`](#attribute-properties) | No | `Array \| "_none_" \| "*"` | `"*"` | -| [`autoExpand`](#attribute-autoexpand) | No | `boolean` | `false` | -| [`skipIfDuplicate`](#attribute-skipifduplicate) | No | `boolean` | `false` | -| [`nestedRelatedProperties`](#attribute-nestedrelatedproperties) | No | [`RelatedPropertiesSpecification[]`](#related-properties-specification) | `[]` | +| Name | Required? | Type | Default | +| --------------------------------------------------------------------------------- | --------- | ----------------------------------------------------------------------- | ------------------- | +| [`propertiesSource`](#attribute-propertiessource) | Yes | [`RelationshipPathSpecification`](../RelationshipPathSpecification.md) | | +| [`handleTargetClassPolymorphically`](#attribute-handletargetclasspolymorphically) | No | `boolean` | `false` | +| [`relationshipMeaning`](#attribute-relationshipmeaning) | No | `"SameInstance" \| "RelatedInstance"` | `"RelatedInstance"` | +| [`properties`](#attribute-properties) | No | `Array \| "_none_" \| "*"` | `"*"` | +| [`autoExpand`](#attribute-autoexpand) | No | `boolean` | `false` | +| [`skipIfDuplicate`](#attribute-skipifduplicate) | No | `boolean` | `false` | +| [`nestedRelatedProperties`](#attribute-nestedrelatedproperties) | No | [`RelatedPropertiesSpecification[]`](#related-properties-specification) | `[]` | ### Attribute: `propertiesSource` -Specifies a chain of [relationship path specifications](../Common-Rules/RelationshipPathSpecification.md) that forms a path from the content instance to the related instance(s) whose properties should additionally be loaded. +Specifies a chain of [relationship path specifications](../RelationshipPathSpecification.md) that forms a path from the content instance to the related instance(s) whose properties should additionally be loaded. The path may point to more than one related instance, so the result always stores related properties in a form of a struct-array, where each struct represents a single related instance. However, often there's only one related instance and in that case a UI component displaying the result may choose to "destructure" the struct-array. An example of such component is the Property Grid: diff --git a/docs/presentation/Content/SelectedNodeInstances.md b/docs/presentation/Content/SelectedNodeInstances.md index 88ec31392535..14889e44de3b 100644 --- a/docs/presentation/Content/SelectedNodeInstances.md +++ b/docs/presentation/Content/SelectedNodeInstances.md @@ -6,23 +6,23 @@ Returns content for selected (input) instances. ## Attributes -| Name | Required? | Type | Default | -| ------------------------------------------------------------------- | --------- | ----------------------------------------------------------------------------------- | ------- | +| Name | Required? | Type | Default | +| ------------------------------------------------------------------- | --------- | ---------------------------------------------------------------------- | ------- | | *Filtering* | -| [`acceptableSchemaName`](#attribute-acceptableschemaname) | No | `string` | `""` | -| [`acceptableClassNames`](#attribute-acceptableclassnames) | No | `string[]` | `[]` | -| [`acceptablePolymorphically`](#attribute-acceptablepolymorphically) | No | `boolean` | `false` | -| [`onlyIfNotHandled`](#attribute-onlyifnothandled) | No | `boolean` | `false` | +| [`acceptableSchemaName`](#attribute-acceptableschemaname) | No | `string` | `""` | +| [`acceptableClassNames`](#attribute-acceptableclassnames) | No | `string[]` | `[]` | +| [`acceptablePolymorphically`](#attribute-acceptablepolymorphically) | No | `boolean` | `false` | +| [`onlyIfNotHandled`](#attribute-onlyifnothandled) | No | `boolean` | `false` | | *Ordering* | -| [`priority`](#attribute-priority) | No | `number` | `1000` | +| [`priority`](#attribute-priority) | No | `number` | `1000` | | *Content Modifiers* | -| [`relatedProperties`](#attribute-relatedproperties) | No | `RelatedPropertiesSpecification[]` | `[]` | -| [`calculatedProperties`](#attribute-calculatedproperties) | No | `CalculatedPropertiesSpecification[]` | `[]` | -| [`propertyCategories`](#attribute-propertycategories) | No | `PropertyCategorySpecification[]` | `[]` | -| [`propertyOverrides`](#attribute-propertyoverrides) | No | `PropertySpecification[]` | `[]` | -| [`showImages`](#attribute-showimages) | No | `boolean` | `false` | +| [`relatedProperties`](#attribute-relatedproperties) | No | `RelatedPropertiesSpecification[]` | `[]` | +| [`calculatedProperties`](#attribute-calculatedproperties) | No | `CalculatedPropertiesSpecification[]` | `[]` | +| [`propertyCategories`](#attribute-propertycategories) | No | `PropertyCategorySpecification[]` | `[]` | +| [`propertyOverrides`](#attribute-propertyoverrides) | No | `PropertySpecification[]` | `[]` | +| [`showImages`](#attribute-showimages) | No | `boolean` | `false` | | *Misc.* | -| [`relatedInstances`](#attribute-relatedinstances) | No | [`RelatedInstanceSpecification[]`](../Common-Rules/RelatedInstanceSpecification.md) | `[]` | +| [`relatedInstances`](#attribute-relatedinstances) | No | [`RelatedInstanceSpecification[]`](../RelatedInstanceSpecification.md) | `[]` | ### Attribute: `acceptableSchemaName` @@ -39,7 +39,6 @@ Specifies ECSchema name which the input instances have to match for the specific | `BisCore.SpatialViewDefinition` | ![Example when selecting "SpatialViewDefinition"](./media/selectednodeinstances-with-spatialviewdefinition.png) | | `Generic.GroupModel` | ![Example when selecting "GroupModel"](./media/content-empty-table.png) | - ### Attribute: `acceptableClassNames` > **Default behaviour:** All class names accepted @@ -65,10 +64,10 @@ Specifies whether derived classes of `acceptableClassNames` should be included i [[include:SelectedNodeInstances.AcceptablePolymorphically.Ruleset]] ``` - | Selecting `BisCore.ViewDefinition` input with `acceptablePolymorphically` set to | Result | - | -------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | + | Selecting `BisCore.ViewDefinition` input with `acceptablePolymorphically` set to | Result | + | -------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | | `true` | ![Example of "acceptable polymorphically" attribute set to "true"](./media/selectednodeinstances-with-spatialviewdefinition.png) | - | `false` | ![Example of "acceptable polymorphically" attribute set to "false"](./media/content-empty-table.png) | + | `false` | ![Example of "acceptable polymorphically" attribute set to "false"](./media/content-empty-table.png) | ### Attribute: `onlyIfNotHandled` @@ -152,17 +151,17 @@ Should image IDs be calculated for the returned instances. When `true`, [ImageId ### Attribute: `relatedInstances` -Specifications of [related instances](../Common-Rules/RelatedInstanceSpecification.md) that can be used when creating the content. There are several use cases when this is useful: +Specifications of [related instances](../RelatedInstanceSpecification.md) that can be used when creating the content. There are several use cases when this is useful: -- When there's a need to only load instances that have a related instance. Providing a [related instance](../Common-Rules/RelatedInstanceSpecification.md) - specification with [isRequired](../Common-Rules/RelatedInstanceSpecification.md) set to `true` filters-out the instances that don't have the related instance. +- When there's a need to only load instances that have a related instance. Providing a [related instance](../RelatedInstanceSpecification.md) + specification with [isRequired](../RelatedInstanceSpecification.md#attribute-isrequired) set to `true` filters-out the instances that don't have the related instance. -- When there's a need to filter instances by a related instance value. The [alias](../Common-Rules/RelatedInstanceSpecification.md) attribute may then be used +- When there's a need to filter instances by a related instance value. The [alias](../RelatedInstanceSpecification.md#attribute-alias) attribute may then be used in the [`instanceFilter` attribute](#attribute-instancefilter) to reference related instance property values. - When there's a need to customize content based on related instance property values. Related instance classes are included when looking for [customization rules](../Customization/index.md), which allows referencing related instances and their properties in [customization rule ECExpressions](../Customization/ECExpressions.md#override-value) by their - [alias](../Common-Rules/RelatedInstanceSpecification.md). + [alias](../RelatedInstanceSpecification.md#attribute-alias). ```ts [[include:SharedAttributes.RelatedInstances.Ruleset]] @@ -172,4 +171,4 @@ Specifications of [related instances](../Common-Rules/RelatedInstanceSpecificati | ----------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | | `SpatialViewDefinition` instances | ![A list of spatial view definitions](./media/sharedattributes-with-relatedinstances-3.png) | | `ModelSelector` instances | ![A list of model selectors](./media/sharedattributes-with-relatedinstances-2.png) | - | `ModelSelector` instances filtered by `SpatialViewDefinition.Yaw` | ![A list of model selectors filtered by yaw of related spatial view definition](./media/sharedattributes-with-relatedinstances-1.png) | \ No newline at end of file + | `ModelSelector` instances filtered by `SpatialViewDefinition.Yaw` | ![A list of model selectors filtered by yaw of related spatial view definition](./media/sharedattributes-with-relatedinstances-1.png) | diff --git a/docs/presentation/Customization/InstanceLabelOverride.md b/docs/presentation/Customization/InstanceLabelOverride.md index 61b972ac55a7..7064538a3212 100644 --- a/docs/presentation/Customization/InstanceLabelOverride.md +++ b/docs/presentation/Customization/InstanceLabelOverride.md @@ -33,10 +33,10 @@ label, but costs more performance-wise. `InstanceLabelOverridePropertyValueSpecification` uses property value as the label content. -| Name | Required? | Type | Default | Meaning | -| ---------------- | --------- | ----------------------------------------------------------------------------------- | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `propertyName` | Yes | `string` | | Name of the property whose value should be used. | -| `propertySource` | No | [`RelationshipPathSpecification`](../Common-Rules/RelationshipPathSpecification.md) | Empty path | [Specification of the relationship path](../Common-Rules/RelationshipPathSpecification.md) from `InstanceLabelOverride.class` to class of the property. | +| Name | Required? | Type | Default | Meaning | +| ---------------- | --------- | ---------------------------------------------------------------------- | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------ | +| `propertyName` | Yes | `string` | | Name of the property whose value should be used. | +| `propertySource` | No | [`RelationshipPathSpecification`](../RelationshipPathSpecification.md) | Empty path | [Specification of the relationship path](../RelationshipPathSpecification.md) from `InstanceLabelOverride.class` to class of the property. | ### String @@ -70,9 +70,9 @@ label, but costs more performance-wise. `InstanceLabelOverrideRelatedInstanceLabelSpecification` uses label of another related instance as the label content. -| Name | Required? | Type | Default | Meaning | -| ----------------------- | --------- | ----------------------------------------------------------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `pathToRelatedInstance` | Yes | [`RelationshipPathSpecification`](../Common-Rules/RelationshipPathSpecification.md) | | [Specification of the relationship path](../Common-Rules/RelationshipPathSpecification.md) from `InstanceLabelOverride.class` to class of the related instance. | +| Name | Required? | Type | Default | Meaning | +| ----------------------- | --------- | ---------------------------------------------------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | +| `pathToRelatedInstance` | Yes | [`RelationshipPathSpecification`](../RelationshipPathSpecification.md) | | [Specification of the relationship path](../RelationshipPathSpecification.md) from `InstanceLabelOverride.class` to class of the related instance. | ## Example diff --git a/docs/presentation/Hierarchies/CustomQueryInstanceNodes.md b/docs/presentation/Hierarchies/CustomQueryInstanceNodes.md index 4746ea622a80..c9024482cb2f 100644 --- a/docs/presentation/Hierarchies/CustomQueryInstanceNodes.md +++ b/docs/presentation/Hierarchies/CustomQueryInstanceNodes.md @@ -6,24 +6,24 @@ Returns nodes for instances returned by a provided ECSQL query. ## Attributes -| Name | Required? | Type | Default | -| --------------------------------------------------------------------------- | --------- | ----------------------------------------------------------------------------------- | ----------- | +| Name | Required? | Type | Default | +| --------------------------------------------------------------------------- | --------- | ---------------------------------------------------------------------- | ----------- | | *Filtering* | -| [`queries`](#attribute-queries) | No | [`QuerySpecification[]`](#string-query-specification) | `[]` | -| [`hideNodesInHierarchy`](#attribute-hidenodesinhierarchy) | No | `boolean` | `false` | -| [`hideIfNoChildren`](#attribute-hideifnochildren) | No | `boolean` | `false` | -| [`hideExpression`](#attribute-hideexpression) | No | [ECExpression](./ECExpressions.md#specification) | `""` | -| [`suppressSimilarAncestorsCheck`](#attribute-suppresssimilarancestorscheck) | No | `boolean` | `false` | +| [`queries`](#attribute-queries) | No | [`QuerySpecification[]`](#string-query-specification) | `[]` | +| [`hideNodesInHierarchy`](#attribute-hidenodesinhierarchy) | No | `boolean` | `false` | +| [`hideIfNoChildren`](#attribute-hideifnochildren) | No | `boolean` | `false` | +| [`hideExpression`](#attribute-hideexpression) | No | [ECExpression](./ECExpressions.md#specification) | `""` | +| [`suppressSimilarAncestorsCheck`](#attribute-suppresssimilarancestorscheck) | No | `boolean` | `false` | | *Ordering* | -| [`priority`](#attribute-priority) | No | `number` | `1000` | -| [`doNotSort`](#attribute-donotsort) | No | `boolean` | `false` | +| [`priority`](#attribute-priority) | No | `number` | `1000` | +| [`doNotSort`](#attribute-donotsort) | No | `boolean` | `false` | | *Grouping* | -| [`groupByClass`](#attribute-groupbyclass) | No | `boolean` | `true` | -| [`groupByLabel`](#attribute-groupbylabel) | No | `boolean` | `true` | +| [`groupByClass`](#attribute-groupbyclass) | No | `boolean` | `true` | +| [`groupByLabel`](#attribute-groupbylabel) | No | `boolean` | `true` | | *Misc.* | -| [`hasChildren`](#attribute-haschildren) | No | `"Always" \| "Never" \| "Unknown"` | `"Unknown"` | -| [`relatedInstances`](#attribute-relatedinstances) | No | [`RelatedInstanceSpecification[]`](../Common-Rules/RelatedInstanceSpecification.md) | `[]` | -| [`nestedRules`](#attribute-nestedrules) | No | [`ChildNodeRule[]`](./ChildNodeRule.md) | `[]` | +| [`hasChildren`](#attribute-haschildren) | No | `"Always" \| "Never" \| "Unknown"` | `"Unknown"` | +| [`relatedInstances`](#attribute-relatedinstances) | No | [`RelatedInstanceSpecification[]`](../RelatedInstanceSpecification.md) | `[]` | +| [`nestedRules`](#attribute-nestedrules) | No | [`ChildNodeRule[]`](./ChildNodeRule.md) | `[]` | ### Attribute: `queries` @@ -218,13 +218,13 @@ list even if there are child node rules that define children for it. > **Default value:** `[]` -Specifications of [related instances](../Common-Rules/RelatedInstanceSpecification.md) that can be used when creating the nodes. There +Specifications of [related instances](../RelatedInstanceSpecification.md) that can be used when creating the nodes. There are several use cases when this is useful: -- When there's a need to only load instances that have a related instance. Providing a [related instance](../Common-Rules/RelatedInstanceSpecification.md) - specification with [isRequired](../Common-Rules/RelatedInstanceSpecification.md) set to `true` filters-out the instances that don't have the related instance. +- When there's a need to only load instances that have a related instance. Providing a [related instance](../RelatedInstanceSpecification.md) + specification with [isRequired](../RelatedInstanceSpecification.md#attribute-isrequired) set to `true` filters-out the instances that don't have the related instance. -- When there's a need to filter instances by a related instance value. The [alias](../Common-Rules/RelatedInstanceSpecification.md) attribute may then be used +- When there's a need to filter instances by a related instance value. The [alias](../RelatedInstanceSpecification.md#attribute-alias) attribute may then be used in the [`instanceFilter` attribute](#attribute-instancefilter) to reference related instance property values. - When there's a need to group by related instance property values. Related instance classes are included when looking for [grouping rules](./GroupingRule.md), which allows @@ -232,7 +232,7 @@ are several use cases when this is useful: - When there's a need to customize nodes based on related instance property values. Related instance classes are included when looking for [customization rules](../Customization/index.md), which allows referencing related instances and their properties in [customization rule ECExpressions](../Customization/ECExpressions.md#override-value) by their - [alias](../Common-Rules/RelatedInstanceSpecification.md). + [alias](../RelatedInstanceSpecification.md#attribute-alias). ```ts [[include:Hierarchies.Specification.RelatedInstances.Ruleset]] diff --git a/docs/presentation/Hierarchies/InstanceNodesOfSpecificClasses.md b/docs/presentation/Hierarchies/InstanceNodesOfSpecificClasses.md index 10719aecfe58..c42570adff05 100644 --- a/docs/presentation/Hierarchies/InstanceNodesOfSpecificClasses.md +++ b/docs/presentation/Hierarchies/InstanceNodesOfSpecificClasses.md @@ -6,30 +6,30 @@ Returns nodes for instances of specific ECClasses. ## Attributes -| Name | Required? | Type | Default | -| --------------------------------------------------------------------------- | --------- | ----------------------------------------------------------------------------------- | ----------- | +| Name | Required? | Type | Default | +| --------------------------------------------------------------------------- | --------- | ---------------------------------------------------------------------- | ----------- | | *Filtering* | -| [`classes`](#attribute-classes) | Yes | `MultiSchemaClassesSpecification \| MultiSchemaClassesSpecification[]` | | -| [`excludedClasses`](#attribute-excludedclasses) | No | `MultiSchemaClassesSpecification \| MultiSchemaClassesSpecification[]` | `[]` | -| [`instanceFilter`](#attribute-instancefilter) | No | [ECExpression](./ECExpressions.md#instance-filter) | `""` | -| [`hideNodesInHierarchy`](#attribute-hidenodesinhierarchy) | No | `boolean` | `false` | -| [`hideIfNoChildren`](#attribute-hideifnochildren) | No | `boolean` | `false` | -| [`hideExpression`](#attribute-hideexpression) | No | [ECExpression](./ECExpressions.md#specification) | `""` | -| [`suppressSimilarAncestorsCheck`](#attribute-suppresssimilarancestorscheck) | No | `boolean` | `false` | +| [`classes`](#attribute-classes) | Yes | `MultiSchemaClassesSpecification \| MultiSchemaClassesSpecification[]` | | +| [`excludedClasses`](#attribute-excludedclasses) | No | `MultiSchemaClassesSpecification \| MultiSchemaClassesSpecification[]` | `[]` | +| [`instanceFilter`](#attribute-instancefilter) | No | [ECExpression](./ECExpressions.md#instance-filter) | `""` | +| [`hideNodesInHierarchy`](#attribute-hidenodesinhierarchy) | No | `boolean` | `false` | +| [`hideIfNoChildren`](#attribute-hideifnochildren) | No | `boolean` | `false` | +| [`hideExpression`](#attribute-hideexpression) | No | [ECExpression](./ECExpressions.md#specification) | `""` | +| [`suppressSimilarAncestorsCheck`](#attribute-suppresssimilarancestorscheck) | No | `boolean` | `false` | | *Ordering* | -| [`priority`](#attribute-priority) | No | `number` | `1000` | -| [`doNotSort`](#attribute-donotsort) | No | `boolean` | `false` | +| [`priority`](#attribute-priority) | No | `number` | `1000` | +| [`doNotSort`](#attribute-donotsort) | No | `boolean` | `false` | | *Grouping* | -| [`groupByClass`](#attribute-groupbyclass) | No | `boolean` | `true` | -| [`groupByLabel`](#attribute-groupbylabel) | No | `boolean` | `true` | +| [`groupByClass`](#attribute-groupbyclass) | No | `boolean` | `true` | +| [`groupByLabel`](#attribute-groupbylabel) | No | `boolean` | `true` | | *Misc.* | -| [`hasChildren`](#attribute-haschildren) | No | `"Always" \| "Never" \| "Unknown"` | `"Unknown"` | -| [`relatedInstances`](#attribute-relatedinstances) | No | [`RelatedInstanceSpecification[]`](../Common-Rules/RelatedInstanceSpecification.md) | `[]` | -| [`nestedRules`](#attribute-nestedrules) | No | [`ChildNodeRule[]`](./ChildNodeRule.md) | `[]` | +| [`hasChildren`](#attribute-haschildren) | No | `"Always" \| "Never" \| "Unknown"` | `"Unknown"` | +| [`relatedInstances`](#attribute-relatedinstances) | No | [`RelatedInstanceSpecification[]`](../RelatedInstanceSpecification.md) | `[]` | +| [`nestedRules`](#attribute-nestedrules) | No | [`ChildNodeRule[]`](./ChildNodeRule.md) | `[]` | ### Attribute: `classes` -Defines a set of [multi schema classes](../Common-Rules/MultiSchemaClassesSpecification.md) that specify which ECClasses need to be selected to form the result. +Defines a set of [multi schema classes](../MultiSchemaClassesSpecification.md) that specify which ECClasses need to be selected to form the result. ```ts [[include:Hierarchies.InstanceNodesOfSpecificClassesSpecification.Classes.Ruleset]] @@ -41,7 +41,7 @@ Defines a set of [multi schema classes](../Common-Rules/MultiSchemaClassesSpecif > **Default value:** `[]` -Defines a set of [multi schema classes](../Common-Rules/MultiSchemaClassesSpecification.md) that prevents specified ECClasses and subclasses from being selected by [`classes` attribute](#attribute-classes). +Defines a set of [multi schema classes](../MultiSchemaClassesSpecification.md) that prevents specified ECClasses and subclasses from being selected by [`classes` attribute](#attribute-classes). ```ts [[include:Hierarchies.InstanceNodesOfSpecificClassesSpecification.ExcludedClasses.Ruleset]] @@ -205,13 +205,13 @@ list even if there are child node rules that define children for it. > **Default value:** `[]` -Specifications of [related instances](../Common-Rules/RelatedInstanceSpecification.md) that can be used when creating the nodes. There +Specifications of [related instances](../RelatedInstanceSpecification.md) that can be used when creating the nodes. There are several use cases when this is useful: -- When there's a need to only load instances that have a related instance. Providing a [related instance](../Common-Rules/RelatedInstanceSpecification.md) - specification with [isRequired](../Common-Rules/RelatedInstanceSpecification.md) set to `true` filters-out the instances that don't have the related instance. +- When there's a need to only load instances that have a related instance. Providing a [related instance](../RelatedInstanceSpecification.md) + specification with [isRequired](../RelatedInstanceSpecification.md#attribute-isrequired) set to `true` filters-out the instances that don't have the related instance. -- When there's a need to filter instances by a related instance value. The [alias](../Common-Rules/RelatedInstanceSpecification.md) attribute may then be used +- When there's a need to filter instances by a related instance value. The [alias](../RelatedInstanceSpecification.md#attribute-alias) attribute may then be used in the [`instanceFilter` attribute](#attribute-instancefilter) to reference related instance property values. - When there's a need to group by related instance property values. Related instance classes are included when looking for [grouping rules](./GroupingRule.md), which allows @@ -219,7 +219,7 @@ are several use cases when this is useful: - When there's a need to customize nodes based on related instance property values. Related instance classes are included when looking for [customization rules](../Customization/index.md), which allows referencing related instances and their properties in [customization rule ECExpressions](../Customization/ECExpressions.md#override-value) by their - [alias](../Common-Rules/RelatedInstanceSpecification.md). + [alias](../RelatedInstanceSpecification.md#attribute-alias). ```ts [[include:Hierarchies.Specification.RelatedInstances.Ruleset]] diff --git a/docs/presentation/Hierarchies/RelatedInstanceNodes.md b/docs/presentation/Hierarchies/RelatedInstanceNodes.md index a9e513746938..a47d77686040 100644 --- a/docs/presentation/Hierarchies/RelatedInstanceNodes.md +++ b/docs/presentation/Hierarchies/RelatedInstanceNodes.md @@ -6,29 +6,29 @@ Produces ECInstance nodes that are related to some source ECInstance. The source ## Attributes -| Name | Required? | Type | Default | -| --------------------------------------------------------------------------- | --------- | ------------------------------------------------------------------------------------- | ----------- | +| Name | Required? | Type | Default | +| --------------------------------------------------------------------------- | --------- | -------------------------------------------------------------------------------------------- | ----------- | | *Filtering* | -| [`relationshipPaths`](#attribute-relationshippaths) | Yes | [`RelationshipPathSpecification[]`](../Common-Rules/RelationshipPathSpecification.md) | | -| [`instanceFilter`](#attribute-instancefilter) | No | [ECExpression](./ECExpressions.md#instance-filter) | `""` | -| [`hideNodesInHierarchy`](#attribute-hidenodesinhierarchy) | No | `boolean` | `false` | -| [`hideIfNoChildren`](#attribute-hideifnochildren) | No | `boolean` | `false` | -| [`hideExpression`](#attribute-hideexpression) | No | [ECExpression](./ECExpressions.md#specification) | `""` | -| [`suppressSimilarAncestorsCheck`](#attribute-suppresssimilarancestorscheck) | No | `boolean` | `false` | +| [`relationshipPaths`](#attribute-relationshippaths) | Yes | [`RepeatableRelationshipPathSpecification[]`](../RepeatableRelationshipPathSpecification.md) | | +| [`instanceFilter`](#attribute-instancefilter) | No | [ECExpression](./ECExpressions.md#instance-filter) | `""` | +| [`hideNodesInHierarchy`](#attribute-hidenodesinhierarchy) | No | `boolean` | `false` | +| [`hideIfNoChildren`](#attribute-hideifnochildren) | No | `boolean` | `false` | +| [`hideExpression`](#attribute-hideexpression) | No | [ECExpression](./ECExpressions.md#specification) | `""` | +| [`suppressSimilarAncestorsCheck`](#attribute-suppresssimilarancestorscheck) | No | `boolean` | `false` | | *Ordering* | -| [`priority`](#attribute-priority) | No | `number` | `1000` | -| [`doNotSort`](#attribute-donotsort) | No | `boolean` | `false` | +| [`priority`](#attribute-priority) | No | `number` | `1000` | +| [`doNotSort`](#attribute-donotsort) | No | `boolean` | `false` | | *Grouping* | -| [`groupByClass`](#attribute-groupbyclass) | No | `boolean` | `true` | -| [`groupByLabel`](#attribute-groupbylabel) | No | `boolean` | `true` | +| [`groupByClass`](#attribute-groupbyclass) | No | `boolean` | `true` | +| [`groupByLabel`](#attribute-groupbylabel) | No | `boolean` | `true` | | *Misc.* | -| [`hasChildren`](#attribute-haschildren) | No | `"Always" \| "Never" \| "Unknown"` | `"Unknown"` | -| [`relatedInstances`](#attribute-relatedinstances) | No | [`RelatedInstanceSpecification[]`](../Common-Rules/RelatedInstanceSpecification.md) | `[]` | -| [`nestedRules`](#attribute-nestedrules) | No | [`ChildNodeRule[]`](./ChildNodeRule.md) | `[]` | +| [`hasChildren`](#attribute-haschildren) | No | `"Always" \| "Never" \| "Unknown"` | `"Unknown"` | +| [`relatedInstances`](#attribute-relatedinstances) | No | [`RelatedInstanceSpecification[]`](../RelatedInstanceSpecification.md) | `[]` | +| [`nestedRules`](#attribute-nestedrules) | No | [`ChildNodeRule[]`](./ChildNodeRule.md) | `[]` | ### Attribute: `relationshipPaths` -Specifies a chain of [relationship path specifications](../Common-Rules/RelationshipPathSpecification.md) that forms a path from a source instance to the output instances. When this array is empty, the specification produces no results. +Specifies a chain of [relationship path specifications](../RepeatableRelationshipPathSpecification.md) that forms a path from a source instance to the output instances. When this array is empty, the specification produces no results. ```ts [[include:Hierarchies.RelatedInstanceNodesSpecification.RelationshipPaths.Ruleset]] @@ -192,13 +192,13 @@ list even if there are child node rules that define children for it. > **Default value:** `[]` -Specifications of [related instances](../Common-Rules/RelatedInstanceSpecification.md) that can be used when creating the nodes. There +Specifications of [related instances](../RelatedInstanceSpecification.md) that can be used when creating the nodes. There are several use cases when this is useful: -- When there's a need to only load instances that have a related instance. Providing a [related instance](../Common-Rules/RelatedInstanceSpecification.md) - specification with [isRequired](../Common-Rules/RelatedInstanceSpecification.md) set to `true` filters-out the instances that don't have the related instance. +- When there's a need to only load instances that have a related instance. Providing a [related instance](../RelatedInstanceSpecification.md) + specification with [isRequired](../RelatedInstanceSpecification.md#attribute-isrequired) set to `true` filters-out the instances that don't have the related instance. -- When there's a need to filter instances by a related instance value. The [alias](../Common-Rules/RelatedInstanceSpecification.md) attribute may then be used +- When there's a need to filter instances by a related instance value. The [alias](../RelatedInstanceSpecification.md#attribute-alias) attribute may then be used in the [`instanceFilter` attribute](#attribute-instancefilter) to reference related instance property values. - When there's a need to group by related instance property values. Related instance classes are included when looking for [grouping rules](./GroupingRule.md), which allows @@ -206,7 +206,7 @@ are several use cases when this is useful: - When there's a need to customize nodes based on related instance property values. Related instance classes are included when looking for [customization rules](../Customization/index.md), which allows referencing related instances and their properties in [customization rule ECExpressions](../Customization/ECExpressions.md#override-value) by their - [alias](../Common-Rules/RelatedInstanceSpecification.md). + [alias](../RelatedInstanceSpecification.md#attribute-alias). ```ts [[include:Hierarchies.Specification.RelatedInstances.Ruleset]] diff --git a/docs/presentation/Common-Rules/MultiSchemaClassesSpecification.md b/docs/presentation/MultiSchemaClassesSpecification.md similarity index 88% rename from docs/presentation/Common-Rules/MultiSchemaClassesSpecification.md rename to docs/presentation/MultiSchemaClassesSpecification.md index 1c8142e4548c..8865ebf28be4 100644 --- a/docs/presentation/Common-Rules/MultiSchemaClassesSpecification.md +++ b/docs/presentation/MultiSchemaClassesSpecification.md @@ -29,5 +29,7 @@ Defines whether the derived ECClasses should be included in the result. ## Example ```ts -[[include:ContentInstancesOfSpecificClasses.MultiSchemaClasses.Ruleset]] +[[include:MultiSchemaClasses.Ruleset]] ``` + +![Content of physical models and spatial categories](./media/multischemaclasses.png) diff --git a/docs/presentation/RelatedInstanceSpecification.md b/docs/presentation/RelatedInstanceSpecification.md new file mode 100644 index 000000000000..76740170aa1b --- /dev/null +++ b/docs/presentation/RelatedInstanceSpecification.md @@ -0,0 +1,70 @@ +# Related Instance Specification + +> TypeScript type: [RelatedInstanceSpecification]($presentation-common). + +Related instance specification is used in [content](../Content/ContentRule.md#attribute-specifications) and +[hierarchy](../Hierarchies/ChildNodeRule.md#attribute-specifications) specifications to "join" the primary instance +with its related instance and allow using the related instance for: + +- [Filtering](#using-related-instances-in-instance-filter), when used in `instanceFilter`. +- [Customization](#using-related-instances-for-customizing), when used in [customization rules](../Customization/index.md). +- [Grouping](#using-related-instances-for-grouping), when used in [grouping rules](../Hierarchies/GroupingRule.md). + +## Attributes + +| Name | Required? | Type | Default | +| ------------------------------------------------ | --------- | --------------------------------------------------------------------- | ------- | +| [`relationshipPath`](#attribute-relationshipath) | Yes | [`RelationshipPathSpecification`](./RelationshipPathSpecification.md) | | +| [`alias`](#attribute-alias) | Yes | `string` | | +| [`isRequired`](#attribute-isrequired) | No | `boolean` | `false` | + +### Attribute: `relationshipPath` + +Specifies a chain of [relationship path specifications](./RelationshipPathSpecification.md) that forms a path from the primary instance to the related instances. + +### Attribute: `alias` + +Specifies an an alias that given to the related instance. The alias can be used to reference the instance in instance filter and customization rules. + +> **Note:** The value must be unique per hierarchy specification. If there are multiple related instance specifications using the same alias, the +> library uses the first one and ignores the rest of them. + +### Attribute: `isRequired` + +> **Default value:** `false` + +Specifies whether to omit the primary instance from the result if the other end of [`relationshipPath`](#attribute-relationshipath) does not yield any related instances. + +## Examples + +### Using related instances in instance filter + +```ts +[[include:RelatedInstanceSpecification.UsingInInstanceFilter.Ruleset]] +``` + +| | Result | +| ----------------------- | ------------------------------------------------------------------------------------------------------ | +| without instance filter | ![Example without instance filter](./media/relatedinstancespecification-usage-in-instancefilter-1.png) | +| with instance filter | ![Example with instance filter](./media/relatedinstancespecification-usage-in-instancefilter-2.png) | + +### Using related instances for customization + +```ts +[[include:RelatedInstanceSpecification.UsingForCustomization.Ruleset]] +``` + +```ts +[[include:RelatedInstanceSpecification.UsingForCustomization.Result]] +``` + +### Using related instances for grouping + +```ts +[[include:RelatedInstanceSpecification.UsingForGrouping.Ruleset]] +``` + +| | Result | +| -------------------------------------- | ---------------------------------------------------------------------------------------------------------------- | +| without related instance specification | ![Example without related instance specification](./media/relatedinstancespecification-usage-for-grouping-1.png) | +| with related instance specification | ![Example with related instance specification](./media/relatedinstancespecification-usage-for-grouping-2.png) | diff --git a/docs/presentation/RelationshipPathSpecification.md b/docs/presentation/RelationshipPathSpecification.md new file mode 100644 index 000000000000..15104af30030 --- /dev/null +++ b/docs/presentation/RelationshipPathSpecification.md @@ -0,0 +1,57 @@ +# Relationship Path Specification + +> TypeScript type: [RelationshipPathSpecification]($presentation-common). + +Relationship path specification is used to define a relationship path to an ECClass. + +The specification is always used in a context where source class already exists, so it only requires the relationship and direction. The +target class can be inferred from the two required attributes or specified with the [`targetClass` attribute](#attribute-targetclass). In case of a +multi-step path, target of the current step is used as the source of the next step. + +## Attributes + +| Name | Required? | Type | Default | +| ----------------------------------------- | --------- | -------------------------------- | ----------------------------- | +| [`relationship`](#attribute-relationship) | Yes | `SingleSchemaClassSpecification` | | +| [`direction`](#attribute-direction) | Yes | `"Forward" \| "Backward"` | | +| [`targetClass`](#attribute-targetclass) | No | `SingleSchemaClassSpecification` | Other end of the relationship | + +### Attribute: `relationship` + +This attribute specifies the ECRelationship that should be used to traverse to target class. + +### Attribute: `direction` + +This attribute specifies the direction in which the [relationship](#attribute-relationship) should be followed: + +- `"Forward"` - the relationship is traversed from source to target of the relationship. +- `"Backward"` - the relationship is traversed from target to source of the relationship. + +### Attribute: `targetClass` + +> **Default value:** Target ECClass of the [relationship](#attribute-relationship) if the [direction](#attribute-direction) is `"Forward"` or +> source ECClass if the [direction](#attribute-direction) is `"Backward"`. + +This attribute may be used to specialize the target of the relationship. E.g. when relationship points to a class like `bis.Element`, this +attribute allows specializing it to `bis.PhysicalElement` or some other `bis.Element` subclass. + +## Examples + +### Using single-step relationship path + +```ts +[[include:RelationshipPathSpecification.SingleStep.Ruleset]] +``` + +| Input | Result | +| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------- | +| `bis.PhysicalModel` instance | ![Result when input is bis physical model instance](./media/relationshippathspecification-singlestep-with-matching-target.png) | +| `bis.DefinitionModel` instance | ![Results when input is bis definition model instance](./media/relationshippathspecification-singlestep-with-non-matching-target.png) | + +### Using multi-step relationship path + +```ts +[[include:RelationshipPathSpecification.MultiStep.Ruleset]] +``` + +![Categories of input model elements](./media/relationshippathspecification-multistep.png) diff --git a/docs/presentation/RepeatableRelationshipPathSpecification.md b/docs/presentation/RepeatableRelationshipPathSpecification.md new file mode 100644 index 000000000000..d94ed3c43803 --- /dev/null +++ b/docs/presentation/RepeatableRelationshipPathSpecification.md @@ -0,0 +1,85 @@ +# Repeatable Relationship Path Specification + +> TypeScript type: [RepeatableRelationshipPathSpecification]($presentation-common). + +This specification declares a step in a relationship path between a source and target ECInstances. A step can optionally be repeated a number of times to traverse the same relationship recursively. Multiple specifications of this type can be chained together to express complex indirect relationships. + +The specification is always used in a context where source class already exists, so it only requires the relationship and direction. The +target class can be inferred from the two required attributes or specified with the [`targetClass` attribute](#attribute-targetclass). In case of a +multi-step path, target of the current step is used as the source of the next step. + +## Attributes + +| Name | Required? | Type | Default | +| ----------------------------------------- | --------- | -------------------------------- | ----------------------------- | +| [`relationship`](#attribute-relationship) | Yes | `SingleSchemaClassSpecification` | | +| [`direction`](#attribute-direction) | Yes | `"Forward" \| "Backward"` | | +| [`targetClass`](#attribute-targetclass) | No | `SingleSchemaClassSpecification` | Other end of the relationship | +| [`count`](#attribute-count) | No | `number \| "*"` | `1` | + +### Attribute: `relationship` + +This attribute specifies the ECRelationship that should be used to traverse to target class. + +### Attribute: `direction` + +This attribute specifies the direction in which the [relationship](#attribute-relationship) should be followed: + +- `"Forward"` - the relationship is traversed from source to target of the relationship. +- `"Backward"` - the relationship is traversed from target to source of the relationship. + +### Attribute: `targetClass` + +> **Default value:** Target ECClass of the [relationship](#attribute-relationship) if the [direction](#attribute-direction) is `"Forward"` or +> source ECClass if the [direction](#attribute-direction) is `"Backward"`. + +This attribute may be used to specialize the target of the relationship. E.g. when relationship points to a class like `bis.Element`, this +attribute allows specializing it to `bis.PhysicalElement` or some other `bis.Element` subclass. + +### Attribute: `count` + +> **Default value:** `1` + +When a number is specified, the relationship is traversed recursively the specified number of times. + +When it is set to a special value `"*"`, the same relationship is traversed recursively unbounded number of times, starting from zero (the relationship is not followed). On each traversal iteration, Presentation rules engine accumulates all indirectly related ECInstances as defined by the remaining relationship path. + +## Examples + +When the [`count` attribute](#attribute-count) is omitted or set to `1`, the specification works similarly to [RelationshipPathSpecification](./RelationshipPathSpecification.md). See its [examples section](./RelationshipPathSpecification.md#examples) for those simpler cases. + +### Jumping through the same relationship recursively fixed number of times + +```ts +[[include:RepeatableRelationshipPathSpecification.SingleStepWithCount.Ruleset]] +``` + +![Content of the grand-parent element](./media/repeatablerelationshippathspecification-singlestep-with-count.png) + +### Jumping through the relationship recursively unbounded number of times + +```ts +[[include:RepeatableRelationshipPathSpecification.RecursiveSingleStep.Ruleset]] +``` + +When the root subject is provided as input, content for all its child elements is returned: + +![Content of all root subject's child elements](./media/repeatablerelationshippathspecification-recursivesinglestep.png) + +### Combining recursive and non-recursive steps + +```ts +[[include:RepeatableRelationshipPathSpecification.RecursiveAndNonRecursiveSpecificationsCombination.Ruleset]] +``` + +When a physical model is provided as input, categories' content of all its elements and their children is returned: + +![Categories' content of model elements and their children](./media/repeatablerelationshippathspecification-combinedsteps.png) + +### Combining multiple unbounded recursive steps + +```ts +[[include:RepeatableRelationshipPathSpecification.MultipleRecursiveSpecificationsCombination.Ruleset]] +``` + +![Content of multiple recursive relationship steps](./media/repeatablerelationshippathspecification-combinedrecursivesteps.png) diff --git a/docs/presentation/media/multischemaclasses.png b/docs/presentation/media/multischemaclasses.png new file mode 100644 index 000000000000..323c465ff726 Binary files /dev/null and b/docs/presentation/media/multischemaclasses.png differ diff --git a/docs/presentation/media/relatedinstancespecification-usage-for-grouping-1.png b/docs/presentation/media/relatedinstancespecification-usage-for-grouping-1.png new file mode 100644 index 000000000000..4b1c6e7a91d7 Binary files /dev/null and b/docs/presentation/media/relatedinstancespecification-usage-for-grouping-1.png differ diff --git a/docs/presentation/media/relatedinstancespecification-usage-for-grouping-2.png b/docs/presentation/media/relatedinstancespecification-usage-for-grouping-2.png new file mode 100644 index 000000000000..dc80ede61bdd Binary files /dev/null and b/docs/presentation/media/relatedinstancespecification-usage-for-grouping-2.png differ diff --git a/docs/presentation/media/relatedinstancespecification-usage-in-instancefilter-1.png b/docs/presentation/media/relatedinstancespecification-usage-in-instancefilter-1.png new file mode 100644 index 000000000000..d25e29cfd30c Binary files /dev/null and b/docs/presentation/media/relatedinstancespecification-usage-in-instancefilter-1.png differ diff --git a/docs/presentation/media/relatedinstancespecification-usage-in-instancefilter-2.png b/docs/presentation/media/relatedinstancespecification-usage-in-instancefilter-2.png new file mode 100644 index 000000000000..93c588f65765 Binary files /dev/null and b/docs/presentation/media/relatedinstancespecification-usage-in-instancefilter-2.png differ diff --git a/docs/presentation/media/relationshippathspecification-multistep.png b/docs/presentation/media/relationshippathspecification-multistep.png new file mode 100644 index 000000000000..452a02c7febc Binary files /dev/null and b/docs/presentation/media/relationshippathspecification-multistep.png differ diff --git a/docs/presentation/media/relationshippathspecification-singlestep-with-matching-target.png b/docs/presentation/media/relationshippathspecification-singlestep-with-matching-target.png new file mode 100644 index 000000000000..b551f94dbbe7 Binary files /dev/null and b/docs/presentation/media/relationshippathspecification-singlestep-with-matching-target.png differ diff --git a/docs/presentation/media/relationshippathspecification-singlestep-with-non-matching-target.png b/docs/presentation/media/relationshippathspecification-singlestep-with-non-matching-target.png new file mode 100644 index 000000000000..0348ca63d1ed Binary files /dev/null and b/docs/presentation/media/relationshippathspecification-singlestep-with-non-matching-target.png differ diff --git a/docs/presentation/media/repeatablerelationshippathspecification-combinedrecursivesteps.png b/docs/presentation/media/repeatablerelationshippathspecification-combinedrecursivesteps.png new file mode 100644 index 000000000000..aaeadd4b2790 Binary files /dev/null and b/docs/presentation/media/repeatablerelationshippathspecification-combinedrecursivesteps.png differ diff --git a/docs/presentation/media/repeatablerelationshippathspecification-combinedsteps.png b/docs/presentation/media/repeatablerelationshippathspecification-combinedsteps.png new file mode 100644 index 000000000000..82482b893328 Binary files /dev/null and b/docs/presentation/media/repeatablerelationshippathspecification-combinedsteps.png differ diff --git a/docs/presentation/media/repeatablerelationshippathspecification-recursivesinglestep.png b/docs/presentation/media/repeatablerelationshippathspecification-recursivesinglestep.png new file mode 100644 index 000000000000..9df5d507b0e6 Binary files /dev/null and b/docs/presentation/media/repeatablerelationshippathspecification-recursivesinglestep.png differ diff --git a/docs/presentation/media/repeatablerelationshippathspecification-singlestep-with-count.png b/docs/presentation/media/repeatablerelationshippathspecification-singlestep-with-count.png new file mode 100644 index 000000000000..caec7f389946 Binary files /dev/null and b/docs/presentation/media/repeatablerelationshippathspecification-singlestep-with-count.png differ diff --git a/docs/presentation/media/source/multischemaclasses.snag b/docs/presentation/media/source/multischemaclasses.snag new file mode 100644 index 000000000000..74495d651b63 Binary files /dev/null and b/docs/presentation/media/source/multischemaclasses.snag differ diff --git a/docs/presentation/media/source/relatedinstancespecification-usage-for-grouping-1.snag b/docs/presentation/media/source/relatedinstancespecification-usage-for-grouping-1.snag new file mode 100644 index 000000000000..40ba97283f7b Binary files /dev/null and b/docs/presentation/media/source/relatedinstancespecification-usage-for-grouping-1.snag differ diff --git a/docs/presentation/media/source/relatedinstancespecification-usage-for-grouping-2.snag b/docs/presentation/media/source/relatedinstancespecification-usage-for-grouping-2.snag new file mode 100644 index 000000000000..16ec91a48549 Binary files /dev/null and b/docs/presentation/media/source/relatedinstancespecification-usage-for-grouping-2.snag differ diff --git a/docs/presentation/media/source/relatedinstancespecification-usage-in-instancefilter-1.snag b/docs/presentation/media/source/relatedinstancespecification-usage-in-instancefilter-1.snag new file mode 100644 index 000000000000..fa971b870ff4 Binary files /dev/null and b/docs/presentation/media/source/relatedinstancespecification-usage-in-instancefilter-1.snag differ diff --git a/docs/presentation/media/source/relatedinstancespecification-usage-in-instancefilter-2.snag b/docs/presentation/media/source/relatedinstancespecification-usage-in-instancefilter-2.snag new file mode 100644 index 000000000000..75a2a6a27744 Binary files /dev/null and b/docs/presentation/media/source/relatedinstancespecification-usage-in-instancefilter-2.snag differ diff --git a/docs/presentation/media/source/relationshippathspecification-multistep.snag b/docs/presentation/media/source/relationshippathspecification-multistep.snag new file mode 100644 index 000000000000..b02bbeca213b Binary files /dev/null and b/docs/presentation/media/source/relationshippathspecification-multistep.snag differ diff --git a/docs/presentation/media/source/relationshippathspecification-singlestep-with-matching-target.snag b/docs/presentation/media/source/relationshippathspecification-singlestep-with-matching-target.snag new file mode 100644 index 000000000000..c95841eb12a9 Binary files /dev/null and b/docs/presentation/media/source/relationshippathspecification-singlestep-with-matching-target.snag differ diff --git a/docs/presentation/media/source/relationshippathspecification-singlestep-with-non-matching-target.snag b/docs/presentation/media/source/relationshippathspecification-singlestep-with-non-matching-target.snag new file mode 100644 index 000000000000..d91a823121a4 Binary files /dev/null and b/docs/presentation/media/source/relationshippathspecification-singlestep-with-non-matching-target.snag differ diff --git a/docs/presentation/media/source/repeatablerelationshippathspecification-combinedrecursivesteps.snag b/docs/presentation/media/source/repeatablerelationshippathspecification-combinedrecursivesteps.snag new file mode 100644 index 000000000000..57bcad54ce34 Binary files /dev/null and b/docs/presentation/media/source/repeatablerelationshippathspecification-combinedrecursivesteps.snag differ diff --git a/docs/presentation/media/source/repeatablerelationshippathspecification-combinedsteps.snag b/docs/presentation/media/source/repeatablerelationshippathspecification-combinedsteps.snag new file mode 100644 index 000000000000..59dcda7438fa Binary files /dev/null and b/docs/presentation/media/source/repeatablerelationshippathspecification-combinedsteps.snag differ diff --git a/docs/presentation/media/source/repeatablerelationshippathspecification-recursivesinglestep.snag b/docs/presentation/media/source/repeatablerelationshippathspecification-recursivesinglestep.snag new file mode 100644 index 000000000000..187b0b90f990 Binary files /dev/null and b/docs/presentation/media/source/repeatablerelationshippathspecification-recursivesinglestep.snag differ diff --git a/docs/presentation/media/source/repeatablerelationshippathspecification-singlestep-with-count.snag b/docs/presentation/media/source/repeatablerelationshippathspecification-singlestep-with-count.snag new file mode 100644 index 000000000000..ae25df7d76ea Binary files /dev/null and b/docs/presentation/media/source/repeatablerelationshippathspecification-singlestep-with-count.snag differ diff --git a/full-stack-tests/presentation/package.json b/full-stack-tests/presentation/package.json index a9ff1d4c03dd..9de6e487d6d8 100644 --- a/full-stack-tests/presentation/package.json +++ b/full-stack-tests/presentation/package.json @@ -113,4 +113,4 @@ "./lib/**/*.js" ] } -} \ No newline at end of file +} diff --git a/full-stack-tests/presentation/src/learning-snippets/CommonRules.test.ts b/full-stack-tests/presentation/src/learning-snippets/CommonRules.test.ts new file mode 100644 index 000000000000..1bbb0da3d9b0 --- /dev/null +++ b/full-stack-tests/presentation/src/learning-snippets/CommonRules.test.ts @@ -0,0 +1,519 @@ +/*--------------------------------------------------------------------------------------------- +* Copyright (c) Bentley Systems, Incorporated. All rights reserved. +* See LICENSE.md in the project root for license terms and full copyright notice. +*--------------------------------------------------------------------------------------------*/ +import { expect } from "chai"; +import { IModelConnection, SnapshotConnection } from "@itwin/core-frontend"; +import { + ChildNodeSpecificationTypes, ContentSpecificationTypes, GroupingSpecificationTypes, KeySet, RelationshipDirection, Ruleset, RuleTypes, + StandardNodeTypes, +} from "@itwin/presentation-common"; +import { Presentation } from "@itwin/presentation-frontend"; +import { initialize, terminate } from "../IntegrationTests"; +import { getFieldByLabel } from "../Utils"; + +describe("Learning Snippets", () => { + + let imodel: IModelConnection; + + beforeEach(async () => { + await initialize(); + imodel = await SnapshotConnection.openFile("assets/datasets/Properties_60InstancesWithUrl2.ibim"); + }); + + afterEach(async () => { + await imodel.close(); + await terminate(); + }); + + describe("MultiSchemaClasses", () => { + + it("uses all attributes", async () => { + // __PUBLISH_EXTRACT_START__ MultiSchemaClasses.Ruleset + // This ruleset produces content for instances of `bis.PhysicalModel` and `bis.SpatialCategory` classes. + // Descendants of these classes will be considered incompatible with the specified class filter because + // `arePolymorphic` attribute is set to`false`. + const ruleset: Ruleset = { + id: "example", + rules: [{ + ruleType: RuleTypes.Content, + specifications: [{ + specType: ContentSpecificationTypes.ContentInstancesOfSpecificClasses, + classes: { + schemaName: "BisCore", + classNames: ["PhysicalModel", "SpatialCategory"], + arePolymorphic: false, + }, + }], + }], + }; + // __PUBLISH_EXTRACT_END__ + printRuleset(ruleset); + + // Ensure that `bis.PhysicalModel` and `bis.SpatialCategory` instances are selected. + const content = await Presentation.presentation.getContent({ + imodel, + rulesetOrId: ruleset, + keys: new KeySet(), + descriptor: {}, + }); + + expect(content!.contentSet).to.have.lengthOf(2); + expect(content!.contentSet).to.containSubset([{ + primaryKeys: [{ className: "BisCore:PhysicalModel" }], + }]); + expect(content!.contentSet).to.containSubset([{ + primaryKeys: [{ className: "BisCore:SpatialCategory" }], + }]); + }); + + }); + + describe("RelatedInstanceSpecification", () => { + + it("using in instance filter", async () => { + // __PUBLISH_EXTRACT_START__ RelatedInstanceSpecification.UsingInInstanceFilter.Ruleset + // This ruleset defines a specification that returns content for `bis.ViewDefinition` instances. In addition, + // there's a related instance specification, that describes a path to a related display style, and an + // instance filter that filters using its property. + const ruleset: Ruleset = { + id: "example", + rules: [{ + ruleType: RuleTypes.Content, + specifications: [ + { + specType: ContentSpecificationTypes.ContentInstancesOfSpecificClasses, + classes: { schemaName: "BisCore", classNames: ["ViewDefinition"], arePolymorphic: true }, + relatedInstances: [{ + relationshipPath: { + relationship: { schemaName: "BisCore", className: "ViewDefinitionUsesDisplayStyle" }, + direction: RelationshipDirection.Forward, + }, + alias: "display_style", + isRequired: true, + }], + instanceFilter: `display_style.CodeValue ~ "%View%"`, + }, + ], + }], + }; + // __PUBLISH_EXTRACT_END__ + printRuleset(ruleset); + + // Ensure that only `bis.ViewDefinition` instances are selected. + const content = await Presentation.presentation.getContent({ + imodel, + rulesetOrId: ruleset, + keys: new KeySet(), + descriptor: {}, + }); + + expect(content!.contentSet.length).to.eq(3); + const field = getFieldByLabel(content!.descriptor.fields, "Display Style"); + content!.contentSet.forEach((record) => { + expect(record.displayValues[field.name]).to.contain("View"); + }); + }); + + it("using for customization", async () => { + // __PUBLISH_EXTRACT_START__ RelatedInstanceSpecification.UsingForCustomization.Ruleset + // This ruleset defines a specification that returns nodes for `meta.ECClassDef` instances. In addition, + // there's a related instance specification, that describes a path to the schema that the class belongs to. + // Finally, there's an extended data rule that sets full class name on each of the nodes. Full class name consists + // of schema and class names and the schema instance can be referenced through the alias specified in related + // instance specification. + const ruleset: Ruleset = { + id: "example", + rules: [{ + ruleType: RuleTypes.RootNodes, + specifications: [ + { + specType: ChildNodeSpecificationTypes.InstanceNodesOfSpecificClasses, + classes: { schemaName: "ECDbMeta", classNames: ["ECClassDef"] }, + groupByClass: false, + groupByLabel: false, + relatedInstances: [{ + relationshipPath: { + relationship: { schemaName: "ECDbMeta", className: "SchemaOwnsClasses" }, + direction: RelationshipDirection.Backward, + }, + alias: "schema", + isRequired: true, + }], + }, + ], + customizationRules: [{ + ruleType: RuleTypes.ExtendedData, + items: { + fullClassName: `schema.Name & "." & this.Name`, + }, + }], + }], + }; + // __PUBLISH_EXTRACT_END__ + printRuleset(ruleset); + + // __PUBLISH_EXTRACT_START__ RelatedInstanceSpecification.UsingForCustomization.Result + // Every node should have its full class name in extended data + const nodes = await Presentation.presentation.getNodes({ + imodel, + rulesetOrId: ruleset, + }); + expect(nodes.length).to.eq(417); + nodes.forEach((node) => { + const fullClassName = node.extendedData!.fullClassName; + const [schemaName, className] = fullClassName.split("."); + expect(schemaName).to.not.be.empty; + expect(className).to.not.be.empty; + }); + // __PUBLISH_EXTRACT_END__ + }); + + it("using for grouping", async () => { + // __PUBLISH_EXTRACT_START__ RelatedInstanceSpecification.UsingForGrouping.Ruleset + // This ruleset defines a specification that returns nodes for `meta.ECClassDef` instances. In addition, + // there's a related instance specification, that describes a path to the schema that the class belongs to. + // Finally, there's a grouping rule that requests grouping on `ECSchemaDef.Name` property. Because + // the `ECClassDef` instances are "linked" to related `ECSchemaDef` instances, the grouping takes effect + // and classes get grouped by related schema names. + const ruleset: Ruleset = { + id: "example", + rules: [{ + ruleType: RuleTypes.RootNodes, + specifications: [ + { + specType: ChildNodeSpecificationTypes.InstanceNodesOfSpecificClasses, + classes: { schemaName: "ECDbMeta", classNames: ["ECClassDef"] }, + groupByClass: false, + groupByLabel: false, + relatedInstances: [{ + relationshipPath: { + relationship: { schemaName: "ECDbMeta", className: "SchemaOwnsClasses" }, + direction: RelationshipDirection.Backward, + }, + alias: "schema", + isRequired: true, + }], + }, + ], + customizationRules: [{ + ruleType: RuleTypes.Grouping, + class: { schemaName: "ECDbMeta", className: "ECSchemaDef" }, + groups: [{ + specType: GroupingSpecificationTypes.Property, + propertyName: "Name", + createGroupForSingleItem: true, + }], + }], + }], + }; + // __PUBLISH_EXTRACT_END__ + printRuleset(ruleset); + + // Every node should have its full class name in extended data + const schemaNodes = await Presentation.presentation.getNodes({ + imodel, + rulesetOrId: ruleset, + }); + expect(schemaNodes.length).to.eq(18); + await Promise.all(schemaNodes.map(async (schemaNode) => { + expect(schemaNode).to.containSubset({ + key: { + type: StandardNodeTypes.ECPropertyGroupingNode, + className: "ECDbMeta:ECSchemaDef", + propertyName: "Name", + }, + }); + const classNodes = await Presentation.presentation.getNodes({ + imodel, + rulesetOrId: ruleset, + parentKey: schemaNode.key, + }); + expect(classNodes).to.not.be.empty; + })); + }); + + }); + + describe("RelationshipPathSpecification", () => { + + it("using single-step specification", async () => { + // __PUBLISH_EXTRACT_START__ RelationshipPathSpecification.SingleStep.Ruleset + // This ruleset defines a specification that returns content for given `bis.Model` instances. The + // content is created for model elements found by following the `bis.ModelContainsElements` + // relationship and picking only `bis.PhysicalElement` type of elements. + const ruleset: Ruleset = { + id: "example", + rules: [{ + ruleType: RuleTypes.Content, + condition: `SelectedNode.IsOfClass("Model", "BisCore")`, + specifications: [ + { + specType: ContentSpecificationTypes.ContentRelatedInstances, + relationshipPaths: [{ + relationship: { schemaName: "BisCore", className: "ModelContainsElements" }, + direction: RelationshipDirection.Forward, + targetClass: { schemaName: "BisCore", className: "PhysicalElement" }, + }], + }, + ], + }], + }; + // __PUBLISH_EXTRACT_END__ + printRuleset(ruleset); + + // Ensure that all model elements are selected + const physicalModelContent = await Presentation.presentation.getContent({ + imodel, + rulesetOrId: ruleset, + keys: new KeySet([{ className: "BisCore:PhysicalModel", id: "0x1c" }]), + descriptor: {}, + }); + expect(physicalModelContent!.contentSet.length).to.eq(62); + + // Ensure that non-physical model elements are not selected + const definitionModelContent = await Presentation.presentation.getContent({ + imodel, + rulesetOrId: ruleset, + keys: new KeySet([{ className: "BisCore:DefinitionModel", id: "0x16" }]), + descriptor: {}, + }); + expect(definitionModelContent).to.be.undefined; + }); + + it("using multi-step specification", async () => { + // __PUBLISH_EXTRACT_START__ RelationshipPathSpecification.MultiStep.Ruleset + // This ruleset defines a specification that returns content for given `bis.GeometricModel3d` instances. The + // content is created for categories of model elements found by following the `bis.ModelContainsElements` and + // `bis.GeometricElement3dIsInCategory` relationships. + const ruleset: Ruleset = { + id: "example", + rules: [{ + ruleType: RuleTypes.Content, + condition: `SelectedNode.IsOfClass("GeometricModel3d", "BisCore")`, + specifications: [ + { + specType: ContentSpecificationTypes.ContentRelatedInstances, + relationshipPaths: [[{ + relationship: { schemaName: "BisCore", className: "ModelContainsElements" }, + direction: RelationshipDirection.Forward, + }, { + relationship: { schemaName: "BisCore", className: "GeometricElement3dIsInCategory" }, + direction: RelationshipDirection.Forward, + }]], + }, + ], + }], + }; + // __PUBLISH_EXTRACT_END__ + printRuleset(ruleset); + + // Ensure that all model elements are selected + const physicalModelContent = await Presentation.presentation.getContent({ + imodel, + rulesetOrId: ruleset, + keys: new KeySet([{ className: "BisCore:PhysicalModel", id: "0x1c" }]), + descriptor: {}, + }); + expect(physicalModelContent!.contentSet.length).to.eq(1); + }); + + }); + + describe("RepeatableRelationshipPathSpecification", () => { + + it("using single-step specification with `count`", async () => { + // __PUBLISH_EXTRACT_START__ RepeatableRelationshipPathSpecification.SingleStepWithCount.Ruleset + // This ruleset defines a specification that returns content for given `bis.Element` instances by + // returning their grandparent property values. + const ruleset: Ruleset = { + id: "example", + rules: [{ + ruleType: RuleTypes.Content, + condition: `SelectedNode.IsOfClass("Element", "BisCore")`, + specifications: [ + { + specType: ContentSpecificationTypes.ContentRelatedInstances, + relationshipPaths: [{ + relationship: { schemaName: "BisCore", className: "ElementOwnsChildElements" }, + direction: RelationshipDirection.Backward, + count: 2, + }], + }, + ], + }], + }; + // __PUBLISH_EXTRACT_END__ + printRuleset(ruleset); + + // Ensure that content of grandparent element is returned + const content = await Presentation.presentation.getContent({ + imodel, + rulesetOrId: ruleset, + keys: new KeySet([{ className: "BisCore:Element", id: "0x1b" }]), + descriptor: {}, + }); + expect(content!.contentSet).to.have.lengthOf(1).and.to.containSubset([{ + primaryKeys: [{ id: "0x1" }], + }]); + }); + + it("using recursive specification", async () => { + // __PUBLISH_EXTRACT_START__ RepeatableRelationshipPathSpecification.RecursiveSingleStep.Ruleset + // This ruleset defines a specification that returns content for all children of the given `bis.Element`. + const ruleset: Ruleset = { + id: "example", + rules: [{ + ruleType: RuleTypes.Content, + condition: `SelectedNode.IsOfClass("Element", "BisCore")`, + specifications: [ + { + specType: ContentSpecificationTypes.ContentRelatedInstances, + relationshipPaths: [{ + relationship: { schemaName: "BisCore", className: "ElementOwnsChildElements" }, + direction: RelationshipDirection.Forward, + count: "*", + }], + }, + ], + }], + }; + // __PUBLISH_EXTRACT_END__ + printRuleset(ruleset); + + // Ensure that content of the root subject's children is returned + const content = await Presentation.presentation.getContent({ + imodel, + rulesetOrId: ruleset, + keys: new KeySet([{ className: "BisCore:Element", id: "0x1" }]), + descriptor: {}, + }); + expect(content!.contentSet).to.have.lengthOf(9).and.to.containSubset([{ + primaryKeys: [{ id: "0xe" }], + }, { + primaryKeys: [{ id: "0x10" }], + }, { + primaryKeys: [{ id: "0x12" }], + }, { + primaryKeys: [{ id: "0x13" }], + }, { + primaryKeys: [{ id: "0x14" }], + }, { + primaryKeys: [{ id: "0x15" }], + }, { + primaryKeys: [{ id: "0x16" }], + }, { + primaryKeys: [{ id: "0x1b" }], + }, { + primaryKeys: [{ id: "0x1c" }], + }]); + }); + + it("combining recursive and non-recursive specifications", async () => { + // __PUBLISH_EXTRACT_START__ RepeatableRelationshipPathSpecification.RecursiveAndNonRecursiveSpecificationsCombination.Ruleset + // This ruleset defines a specification that returns content for categories of all elements in + // the given `bis.Model` and their children. + const ruleset: Ruleset = { + id: "example", + rules: [{ + ruleType: RuleTypes.Content, + condition: `SelectedNode.IsOfClass("Model", "BisCore")`, + specifications: [ + { + specType: ContentSpecificationTypes.ContentRelatedInstances, + relationshipPaths: [[{ + relationship: { schemaName: "BisCore", className: "ModelContainsElements" }, + direction: RelationshipDirection.Forward, + targetClass: { schemaName: "BisCore", className: "GeometricElement3d" }, + }, { + relationship: { schemaName: "BisCore", className: "ElementOwnsChildElements" }, + direction: RelationshipDirection.Forward, + targetClass: { schemaName: "BisCore", className: "GeometricElement3d" }, + count: "*", + }, { + relationship: { schemaName: "BisCore", className: "GeometricElement3dIsInCategory" }, + direction: RelationshipDirection.Forward, + }]], + }, + ], + }], + }; + // __PUBLISH_EXTRACT_END__ + printRuleset(ruleset); + + // Ensure that elements' category is returned when requesting content for those elements' model + const content = await Presentation.presentation.getContent({ + imodel, + rulesetOrId: ruleset, + keys: new KeySet([{ className: "BisCore:PhysicalModel", id: "0x1c" }]), + descriptor: {}, + }); + expect(content!.contentSet).to.have.lengthOf(1).and.to.containSubset([{ + primaryKeys: [{ id: "0x17" }], + }]); + }); + + it("combining multiple recursive specifications", async () => { + // __PUBLISH_EXTRACT_START__ RepeatableRelationshipPathSpecification.MultipleRecursiveSpecificationsCombination.Ruleset + // The ruleset contains a three-step relationship path that finds all `bis.GeometricElement3d` elements related to given model + // through the `bis.ModelContainsElements` relationship, then finds all `bis.SpatialCategory` elements related to `bis.GeometricElement3d` + // found in the previous step through `bis.GeometricElement3dIsInCategory` relationship and finds all `bis.SubCategory` elements related + // to `bis.SpatialCategory` found in the previous step through `bis.CategoryOwnsSubCategories` relationship. + // The result includes `bis.GeometricElement3d`, `bis.SpatialCategory` and `bis.SubCategory` elements. + const ruleset: Ruleset = { + id: "example", + rules: [{ + ruleType: RuleTypes.Content, + condition: `SelectedNode.IsOfClass("Model", "BisCore")`, + specifications: [ + { + specType: ContentSpecificationTypes.ContentRelatedInstances, + relationshipPaths: [[{ + relationship: { schemaName: "BisCore", className: "ModelContainsElements" }, + direction: RelationshipDirection.Forward, + targetClass: { schemaName: "BisCore", className: "GeometricElement3d" }, + count: "*", + }, { + relationship: { schemaName: "BisCore", className: "GeometricElement3dIsInCategory" }, + direction: RelationshipDirection.Forward, + targetClass: { schemaName: "BisCore", className: "SpatialCategory" }, + count: "*", + }, { + relationship: { schemaName: "BisCore", className: "CategoryOwnsSubCategories" }, + direction: RelationshipDirection.Forward, + count: "*", + }]], + }, + ], + }], + }; + // __PUBLISH_EXTRACT_END__ + printRuleset(ruleset); + + // Ensure that the count is correct (62 elements + 1 category + 1 sub-category) and both + // categories are included. Not checking the elements... + const content = await Presentation.presentation.getContent({ + imodel, + rulesetOrId: ruleset, + keys: new KeySet([{ className: "BisCore:PhysicalModel", id: "0x1c" }]), + descriptor: {}, + }); + expect(content!.contentSet).to.have.lengthOf(62 + 1 + 1); + expect(content!.contentSet).to.containSubset([{ + primaryKeys: [{ className: "BisCore:SpatialCategory", id: "0x17" }], + }]); + expect(content!.contentSet).to.containSubset([{ + primaryKeys: [{ className: "BisCore:SubCategory", id: "0x18" }], + }]); + }); + + }); + +}); + +function printRuleset(ruleset: Ruleset) { + if (process.env.PRINT_RULESETS) { + // eslint-disable-next-line no-console + console.log(JSON.stringify(ruleset, undefined, 2)); + } +} diff --git a/full-stack-tests/presentation/src/learning-snippets/Content.test.ts b/full-stack-tests/presentation/src/learning-snippets/Content.test.ts index dc06dd8f0bb4..003ace4a2306 100644 --- a/full-stack-tests/presentation/src/learning-snippets/Content.test.ts +++ b/full-stack-tests/presentation/src/learning-snippets/Content.test.ts @@ -1076,39 +1076,6 @@ describe("Learning Snippets", () => { await terminate(); }); - it("uses `MultiSchemaClassesSpecification`", async () => { - const ruleset: Ruleset = { - id: "example", - rules: [{ - ruleType: RuleTypes.Content, - specifications: [{ - specType: ContentSpecificationTypes.ContentInstancesOfSpecificClasses, - // __PUBLISH_EXTRACT_START__ ContentInstancesOfSpecificClasses.MultiSchemaClasses.Ruleset - // This specification selects instances of `bis.PhysicalModel` and `bis.SpatialViewDefinition` classes. Classes that derive from this list will not be included. - classes: { - schemaName: "BisCore", - classNames: ["PhysicalModel", "SpatialViewDefinition"], - arePolymorphic: false, - }, - // __PUBLISH_EXTRACT_END__ - }], - }], - }; - - // Ensure that `bis.PhysicalModel` and `bis.SpatialViewDefinition` instances are selected. - const content = await Presentation.presentation.getContent({ - imodel, - rulesetOrId: ruleset, - keys: new KeySet(), - descriptor: {}, - }); - - expect(content!.contentSet.length).to.eq(5); - content!.contentSet.forEach((record) => { - expect(record.primaryKeys[0].className).to.be.oneOf(["BisCore:PhysicalModel", "BisCore:SpatialViewDefinition"]); - }); - }); - it("uses `classes` attribute", async () => { // __PUBLISH_EXTRACT_START__ ContentInstancesOfSpecificClasses.Classes.Ruleset // The specification returns content of all `bis.PhysicalModel` classes. diff --git a/presentation/common/src/presentation-common/rules/RelatedInstanceSpecification.ts b/presentation/common/src/presentation-common/rules/RelatedInstanceSpecification.ts index 40bd4d3d5566..b23ab1a763d1 100644 --- a/presentation/common/src/presentation-common/rules/RelatedInstanceSpecification.ts +++ b/presentation/common/src/presentation-common/rules/RelatedInstanceSpecification.ts @@ -61,7 +61,7 @@ import { RelationshipPathSpecification } from "./RelationshipPathSpecification"; * - The `LabelOverride` rule to use `modeledElement` alias to access properties of the joined related instance. * - The `GroupingRule` to be applied because it's grouping `BisCore:Element` which is now part of the generated nodes. * - * @see [More details]($docs/presentation/Common-Rules/RelatedInstanceSpecification.md) + * @see [More details]($docs/presentation/RelatedInstanceSpecification.md) * @public */ export interface RelatedInstanceSpecification { diff --git a/presentation/common/src/presentation-common/rules/RelationshipPathSpecification.ts b/presentation/common/src/presentation-common/rules/RelationshipPathSpecification.ts index a3c1cab24a65..cfc3c45c7900 100644 --- a/presentation/common/src/presentation-common/rules/RelationshipPathSpecification.ts +++ b/presentation/common/src/presentation-common/rules/RelationshipPathSpecification.ts @@ -43,7 +43,7 @@ export interface RepeatableRelationshipStepSpecification extends RelationshipSte /** * Specification of a relationship path. * - * @see [More details]($docs/presentation/Common-Rules/RelationshipPathSpecification.md) + * @see [More details]($docs/presentation/RelationshipPathSpecification.md) * @public */ export type RelationshipPathSpecification = RelationshipStepSpecification | RelationshipStepSpecification[]; @@ -51,7 +51,7 @@ export type RelationshipPathSpecification = RelationshipStepSpecification | Rela /** * Specification of a repeatable relationship path. * - * @see [More details]($docs/presentation/Common-Rules/RelationshipPathSpecification.md) + * @see [More details]($docs/presentation/RepeatableRelationshipPathSpecification.md) * @public */ export type RepeatableRelationshipPathSpecification = RepeatableRelationshipStepSpecification | RepeatableRelationshipStepSpecification[];