Skip to content
21 changes: 12 additions & 9 deletions .changeset/odd-lilies-sniff.md
Comment thread
JonasDov marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,18 @@ The full class names used in this package were defined as `string`, although we

## Breaking changes

- `ClassGroupingNodeKey.className` is now of type `EC.FullClassName` instead of `string`.
- `NodesQueryClauseFactory.createSelectClause` prop `grouping.byBaseClasses.fullClassNames` is now of type `EC.FullClassName[]` instead of `string[]`.
- `NodesQueryClauseFactory.createSelectClause` prop `grouping.byProperties.propertiesClassName` is now of type `EC.FullClassName` instead of `string`.
- `HierarchyNodesDefinition.fullClassName` is now of type `EC.FullClassName` instead of `string`.
- `createPredicateBasedHierarchyDefinition` prop `hierarchies.childNodes[number].parentInstancesNodePredicate` now accepts `EC.FullClassName` instead of `string`.
- `NodesQueryClauseFactory.createFilterClauses` prop `contentClass.fullName` is now of type `EC.FullClassName` instead of `string`.
- `PropertyOtherValuesGroupingNodeKey.properties[number].className` is now of type `EC.FullClassName` instead of `string`.
- `PropertyValueGroupingNodeKey.propertyClassName` is now of type `EC.FullClassName` instead of `string`.
- `PropertyValueRangeGroupingNodeKey.propertyClassName` is now of type `EC.FullClassName` instead of `string`.
- `ClassGroupingNodeKey.className` is now of type `EC.FullClassNameDotNotation` instead of `string`.
- `PropertyOtherValuesGroupingNodeKey.properties[number].className` is now of type `EC.FullClassNameDotNotation` instead of `string`.
- `PropertyValueGroupingNodeKey.propertyClassName` is now of type `EC.FullClassNameDotNotation` instead of `string`.
- `PropertyValueRangeGroupingNodeKey.propertyClassName` is now of type `EC.FullClassNameDotNotation` instead of `string`.
- A hierarchy node's `processingParams.grouping.byBaseClasses.fullClassNames` is now of type `EC.FullClassNameDotNotation[]` instead of `string[]`.
- A hierarchy node's `processingParams.grouping.byProperties.propertiesClassName` is now of type `EC.FullClassNameDotNotation` instead of `string`.
- `NodesQueryClauseFactory.createSelectClause` prop `grouping.byBaseClasses.fullClassNames` is now of type `EC.FullClassNameDotNotation[]` instead of `string[]`.
- `NodesQueryClauseFactory.createSelectClause` prop `grouping.byProperties.propertiesClassName` is now of type `EC.FullClassNameDotNotation` instead of `string`.
- `NodesQueryClauseFactory.createFilterClauses` prop `contentClass.fullName` is now of type `EC.FullClassNameDotNotation` instead of `string`.
- `HierarchyNodesDefinition.fullClassName` is now of type `EC.FullClassNameDotNotation` instead of `string`.
- `createPredicateBasedHierarchyDefinition` prop `hierarchies.childNodes[number].parentInstancesNodePredicate` now accepts `EC.FullClassNameDotNotation` instead of `string`.
- `DefineInstanceNodeChildHierarchyLevelProps.parentNodeClassName` (provided to `HierarchyDefinition.defineHierarchyLevel`) is now of type `EC.FullClassNameDotNotation` instead of `string`.

In many cases migration will be seamless, as long as the input string matches the expected format. In some cases (e.g. when assigning a string variable to one of the affected properties), you may need to use `normalizeFullClassName` from `@itwin/presentation-shared` to ensure the value is of the correct type:

Expand Down
18 changes: 10 additions & 8 deletions .changeset/shaggy-shoes-deny.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,19 @@ The full class names used in this package were defined as `string`, although we

## Breaking changes

- Changed `EC.CustomAttribute.className` to be of type `EC.FullClassName` instead of `string`.
- Changed `EC.CustomAttributeSet.get` argument to be of type `EC.FullClassName` instead of `string`.
- Changed `EC.SchemaItem.fullName` to be of type `EC.FullClassName` instead of `string`.
- Changed `EC.CustomAttribute.className` to be of type `EC.FullClassNameDotNotation` instead of `string`.
- Changed `EC.CustomAttributeSet.get` argument to be of type `EC.FullClassNameDotNotation` instead of `string`.
- Changed `EC.SchemaItem.fullName` to be of type `EC.FullClassNameDotNotation` instead of `string`.
- Changed `compareFullClassNames` arguments to be of type `EC.FullClassName` instead of `string`.
Comment thread
JonasDov marked this conversation as resolved.
Outdated
- Changed `createClassBasedInstanceLabelSelectClauseFactory` prop `clauses` to take objects with `{ className: EC.FullClassName }` arguments instead of `{ className: string }`.
- Changed `IInstanceLabelSelectClauseFactory.createSelectClause` prop `className` to be of type `EC.FullClassName` instead of `string`.
- Changed `ECSql.createPrimitivePropertyValueSelectorProps` prop `propertyClassName` to be of type `EC.FullClassName` instead of `string`.
- Changed `ECSql.createRelationshipPathJoinClause` prop `path` to take class names (`relationshipName`, `sourceClassName` and `targetClassName`) of type `EC.FullClassName` instead of `string`.
- Changed `createClassBasedInstanceLabelSelectClauseFactory` prop `clauses` to take objects with `{ className: EC.FullClassNameDotNotation }` arguments instead of `{ className: string }`.
- Changed `IInstanceLabelSelectClauseFactory.createSelectClause` prop `className` to be of type `EC.FullClassNameDotNotation` instead of `string`.
- Changed `ECSql.createPrimitivePropertyValueSelectorProps` prop `propertyClassName` to be of type `EC.FullClassNameDotNotation` instead of `string`.
- Changed `ECSql.createRelationshipPathJoinClause` prop `path` to take class names (`relationshipName`, `sourceClassName` and `targetClassName`) of type `EC.FullClassNameDotNotation` instead of `string`.
- Changed `ECClassHierarchyInspector.classDerivesFrom` arguments to be of type `EC.FullClassName` instead of `string`.
- Changed the second argument of `getClass` to be of type `EC.FullClassName` instead of `string`.
- Changed `InstanceKey.className` to be of type `EC.FullClassName` instead of `string`.
- Changed `InstanceKey.className` to be of type `EC.FullClassNameDotNotation` instead of `string`. The value is now always in dot notation, so consumers no longer need to call `normalizeFullClassName` on it.
- Changed `RelationshipPathStep` class-name properties (`sourceClassName`, `targetClassName` and `relationshipName`) to be of type `EC.FullClassNameDotNotation` instead of `string`.
- Changed `NavigationValueDescriptor.targetClassName` to be of type `EC.FullClassNameDotNotation` instead of `string`.

In many cases migration will be seamless, as long as the input string matches the expected format. In some cases (e.g. when assigning a string variable to one of the affected properties), you may need to use `normalizeFullClassName` to ensure the value is of the correct type:

Expand Down
4 changes: 2 additions & 2 deletions apps/full-stack-tests/src/ECDbUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ export class ECDbBuilder {
}

public insertInstance(
fullClassName: EC.FullClassName,
fullClassName: EC.FullClassNameDotNotation,
props?: { [propertyName: string]: PrimitiveValue | undefined },
) {
const query = this.createInsertQuery(fullClassName, props);
Expand All @@ -153,7 +153,7 @@ export class ECDbBuilder {
}

public insertRelationship(
fullClassName: EC.FullClassName,
fullClassName: EC.FullClassNameDotNotation,
sourceId: Id64String,
targetId: Id64String,
props?: { [propertyName: string]: PrimitiveValue | undefined },
Expand Down
15 changes: 15 additions & 0 deletions apps/full-stack-tests/src/components/Utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/

import type { Id64String } from "@itwin/core-bentley";
import type { InstanceKey } from "@itwin/presentation-common";
import type { EC } from "@itwin/presentation-shared";

export function toColonInstanceKey(instanceKey: InstanceKey): {
Comment thread
JonasDov marked this conversation as resolved.
className: EC.FullClassNameColonNotation;
id: Id64String;
} {
return { ...instanceKey, className: instanceKey.className.replace(/\./g, ":") as EC.FullClassNameColonNotation };
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { Presentation } from "@itwin/presentation-frontend";
import { buildTestIModel } from "../../IModelUtils.js";
import { initialize, terminate } from "../../IntegrationTests.js";
import { importSchema } from "../../SchemaUtils.js";
import { toColonInstanceKey } from "../Utils.js";

import type { PrimitiveValue, PropertyDescription, PropertyRecord, PropertyValue } from "@itwin/appui-abstract";
import type { PropertyCategory } from "@itwin/components-react";
Expand Down Expand Up @@ -59,7 +60,7 @@ describe("PropertyDataProvider", async () => {
it("creates empty result when properties requested for 0 instances", async () => {
const { imodelConnection } = await buildTestIModel(async (imodel) => {
withEditTxn(imodel, (txn) => {
insertSpatialCategory({ txn, fullClassNameSeparator: ":", codeValue: "My Category" });
insertSpatialCategory({ txn, codeValue: "My Category" });
});
});
using provider = createProvider({ imodel: imodelConnection, ruleset: DEFAULT_PROPERTY_GRID_RULESET });
Expand All @@ -75,11 +76,11 @@ describe("PropertyDataProvider", async () => {

const { imodelConnection } = await buildTestIModel(async (imodel) => {
withEditTxn(imodel, (txn) => {
categoryKey = insertSpatialCategory({ txn, fullClassNameSeparator: ":", codeValue: "My Category" });
modelKey = insertPhysicalModelWithPartition({ txn, fullClassNameSeparator: ":", codeValue: "My Model" });
categoryKey = insertSpatialCategory({ txn, codeValue: "My Category" });
modelKey = insertPhysicalModelWithPartition({ txn, codeValue: "My Model" });
elementKey = insertPhysicalElement({
txn,
fullClassNameSeparator: ":",

Comment thread
JonasDov marked this conversation as resolved.
Outdated
userLabel: "My Element",
modelId: modelKey.id,
categoryId: categoryKey.id,
Expand Down Expand Up @@ -124,11 +125,11 @@ describe("PropertyDataProvider", async () => {

const { imodelConnection } = await buildTestIModel(async (imodel) => {
withEditTxn(imodel, (txn) => {
categoryKey = insertSpatialCategory({ txn, fullClassNameSeparator: ":", codeValue: "My Category" });
modelKey = insertPhysicalModelWithPartition({ txn, fullClassNameSeparator: ":", codeValue: "My Model" });
categoryKey = insertSpatialCategory({ txn, codeValue: "My Category" });
modelKey = insertPhysicalModelWithPartition({ txn, codeValue: "My Model" });
elementKey = insertPhysicalElement({
txn,
fullClassNameSeparator: ":",

userLabel: "My Element",
modelId: modelKey.id,
categoryId: categoryKey.id,
Expand Down Expand Up @@ -170,9 +171,7 @@ describe("PropertyDataProvider", async () => {
let categoryKey: InstanceKey;

const { imodelConnection } = await buildTestIModel(async (imodel) => {
categoryKey = withEditTxn(imodel, (txn) =>
insertSpatialCategory({ txn, fullClassNameSeparator: ":", codeValue: "My Category" }),
);
categoryKey = withEditTxn(imodel, (txn) => insertSpatialCategory({ txn, codeValue: "My Category" }));
});
using provider = createProvider({ imodel: imodelConnection, ruleset: DEFAULT_PROPERTY_GRID_RULESET });
vi.spyOn(provider as any, "isFieldFavorite").mockReturnValue(true);
Expand All @@ -197,9 +196,7 @@ describe("PropertyDataProvider", async () => {
let categoryKey: InstanceKey;

const { imodelConnection } = await buildTestIModel(async (imodel) => {
categoryKey = withEditTxn(imodel, (txn) =>
insertSpatialCategory({ txn, fullClassNameSeparator: ":", codeValue: "My Category" }),
);
categoryKey = withEditTxn(imodel, (txn) => insertSpatialCategory({ txn, codeValue: "My Category" }));
});
using provider = createProvider({
imodel: imodelConnection,
Expand Down Expand Up @@ -233,9 +230,7 @@ describe("PropertyDataProvider", async () => {
let categoryKey: InstanceKey;

const { imodelConnection } = await buildTestIModel(async (imodel) => {
categoryKey = withEditTxn(imodel, (txn) =>
insertSpatialCategory({ txn, fullClassNameSeparator: ":", codeValue: "My Category" }),
);
categoryKey = withEditTxn(imodel, (txn) => insertSpatialCategory({ txn, codeValue: "My Category" }));
});

using provider = createProvider({ imodel: imodelConnection, ruleset: DEFAULT_PROPERTY_GRID_RULESET });
Expand All @@ -249,7 +244,7 @@ describe("PropertyDataProvider", async () => {
expect(record).toBeDefined();

const keys = await provider.getPropertyRecordInstanceKeys(record!);
expect(keys).toEqual([categoryKey!]);
expect(keys).toEqual([toColonInstanceKey(categoryKey!)]);
});

it("finds nested property record keys", async () => {
Expand All @@ -258,28 +253,28 @@ describe("PropertyDataProvider", async () => {

const { imodelConnection } = await buildTestIModel(async (imodel) => {
withEditTxn(imodel, (txn) => {
const categoryKey = insertSpatialCategory({ txn, fullClassNameSeparator: ":", codeValue: "My Category" });
const categoryKey = insertSpatialCategory({ txn, codeValue: "My Category" });
const modelKey = insertPhysicalModelWithPartition({
txn,
fullClassNameSeparator: ":",

codeValue: "My Model",
});
elementKey = insertPhysicalElement({
txn,
fullClassNameSeparator: ":",

userLabel: "My Element",
modelId: modelKey.id,
categoryId: categoryKey.id,
});
const repositoryLinkKey = insertRepositoryLink({
txn,
fullClassNameSeparator: ":",

repositoryUrl: "Repository URL",
repositoryLabel: "Repository Label",
});
externalsSourceAspectKey = insertExternalSourceAspect({
txn,
fullClassNameSeparator: ":",

elementId: elementKey.id,
identifier: "My External Source Aspect",
repositoryId: repositoryLinkKey.id,
Expand Down Expand Up @@ -311,7 +306,7 @@ describe("PropertyDataProvider", async () => {
expect(record).toBeDefined();

const keys = await provider.getPropertyRecordInstanceKeys(record!);
expect(keys).toEqual([externalsSourceAspectKey!]);
expect(keys).toEqual([toColonInstanceKey(externalsSourceAspectKey!)]);
});
});
};
Expand Down Expand Up @@ -339,11 +334,11 @@ describe("PropertyDataProvider", async () => {
</ECEntityClass>
`,
);
const categoryKey = insertSpatialCategory({ txn, fullClassNameSeparator: ":", codeValue: "My Category" });
const modelKey = insertPhysicalModelWithPartition({ txn, fullClassNameSeparator: ":", codeValue: "My Model" });
const categoryKey = insertSpatialCategory({ txn, codeValue: "My Category" });
const modelKey = insertPhysicalModelWithPartition({ txn, codeValue: "My Model" });
const elementKey = insertPhysicalElement({
txn,
classFullName: `${schema.schemaAlias}:TestPhysicalObject` as const,
classFullName: `${schema.schemaAlias}.TestPhysicalObject` as const,
userLabel: "Test element",
modelId: modelKey.id,
categoryId: categoryKey.id,
Expand Down Expand Up @@ -508,9 +503,7 @@ describe("PropertyDataProvider", async () => {
let categoryKey: InstanceKey;

const { imodelConnection } = await buildTestIModel(async (imodel) => {
categoryKey = withEditTxn(imodel, (txn) =>
insertSpatialCategory({ txn, fullClassNameSeparator: ":", codeValue: "My Category" }),
);
categoryKey = withEditTxn(imodel, (txn) => insertSpatialCategory({ txn, codeValue: "My Category" }));
});
const checkDataProvider = async () => {
using provider = new PresentationPropertyDataProvider({ imodel: imodelConnection });
Expand Down Expand Up @@ -577,10 +570,10 @@ describe("PropertyDataProvider", async () => {
`,
);
return withEditTxn(imodel, (txn) => {
const categoryKey = insertSpatialCategory({ txn, fullClassNameSeparator: ":", codeValue: "My Category" });
const categoryKey = insertSpatialCategory({ txn, codeValue: "My Category" });
const modelKey = insertPhysicalModelWithPartition({
txn,
fullClassNameSeparator: ":",

codeValue: "My Model",
});
// Both selected elements have a `MyType` type definition (`PhysicalElement -> PhysicalType`),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { buildTestIModel } from "../../IModelUtils.js";
import { initialize, terminate } from "../../IntegrationTests.js";
import { act, fireEvent, render, waitFor } from "../../RenderUtils.js";
import { getNodeByLabel, isNodeSelectedInTree, toggleExpandNode } from "../TreeUtils.js";
import { toColonInstanceKey } from "../Utils.js";
Comment thread
JonasDov marked this conversation as resolved.

import type { IModelConnection } from "@itwin/core-frontend";
import type { InstanceKey, Ruleset } from "@itwin/presentation-common";
Expand Down Expand Up @@ -75,11 +76,11 @@ describe("Learning snippets", async () => {
let elementKey: InstanceKey;
const { imodelConnection } = await buildTestIModel(async (imodel) => {
withEditTxn(imodel, (txn) => {
const categoryKey = insertSpatialCategory({ txn, fullClassNameSeparator: ":", codeValue: "My Category" });
modelKey = insertPhysicalModelWithPartition({ txn, fullClassNameSeparator: ":", codeValue: "My Model" });
const categoryKey = insertSpatialCategory({ txn, codeValue: "My Category" });
modelKey = insertPhysicalModelWithPartition({ txn, codeValue: "My Model" });
elementKey = insertPhysicalElement({
txn,
fullClassNameSeparator: ":",

userLabel: "My Element",
modelId: modelKey.id,
categoryId: categoryKey.id,
Expand Down Expand Up @@ -112,11 +113,11 @@ describe("Learning snippets", async () => {
// test Tree selection -> Unified Selection synchronization
fireEvent.click(modelNode);
await waitFor(() => {
expect(getInstanceKeysInUnifiedSelection(imodelConnection)).toEqual([modelKey]);
expect(getInstanceKeysInUnifiedSelection(imodelConnection)).toEqual([toColonInstanceKey(modelKey)]);
});
fireEvent.click(elementNode);
await waitFor(() => {
expect(getInstanceKeysInUnifiedSelection(imodelConnection)).toEqual([elementKey]);
expect(getInstanceKeysInUnifiedSelection(imodelConnection)).toEqual([toColonInstanceKey(elementKey)]);
});
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,16 +52,16 @@ describe("Learning snippets", async () => {

const { imodelConnection } = await buildTestIModel(async (imodel) => {
withEditTxn(imodel, (txn) => {
const categoryKey = insertSpatialCategory({ txn, fullClassNameSeparator: ":", codeValue: "My Category" });
const categoryKey = insertSpatialCategory({ txn, codeValue: "My Category" });
const modelKey = insertPhysicalModelWithPartition({
txn,
fullClassNameSeparator: ":",

codeValue: "My Model",
});
(elementKeys.push(
insertPhysicalElement({
txn,
fullClassNameSeparator: ":",

userLabel: "My Assembly Element",
modelId: modelKey.id,
categoryId: categoryKey.id,
Expand All @@ -70,15 +70,15 @@ describe("Learning snippets", async () => {
elementKeys.push(
insertPhysicalElement({
txn,
fullClassNameSeparator: ":",

userLabel: "My Child Element 1",
modelId: modelKey.id,
categoryId: categoryKey.id,
parentId: elementKeys[0].id,
}),
insertPhysicalElement({
txn,
fullClassNameSeparator: ":",

userLabel: "My Child Element 2",
modelId: modelKey.id,
categoryId: categoryKey.id,
Expand Down
Loading
Loading