3.0.0 Change Notes

With most major releases comes many new features and some breaking API changes. Several breaking changes are the removal of previously deprecated APIs. In other cases, some APIs have changed in ways that may require calling code to be adjusted. This document describes these in detail to help you upgrade.

The first step in migrating to 3.0 is to try out the new upgrade tool that makes it easy to react to all of the renames that took place during the 3.0 release.

The table of contents created below will make it easier to navigate through the various changes within the release. It provides a summary of the more complicated or extensive changes made and details on why the change has been made.

Table of Contents:

Upgrade guide

To aid in the update from iModel.js 2.x, a codemod tool using JSCodeshift has been released which should serve as a starting point for updating your project to iTwin.js 3.0. This tool can automate some upgrade tasks like updating package names and replacing usage of deprecated or removed APIs with their replacement APIs. Please see the included readme.md for instructions on running the tool against your project.

New features

Many of the enhancements introduced in iTwin.js 3.0 were directly motivated by feedback from users. If you have a new feature you'd like to see implemented, feel free to let us know!

Display system

Documentation

A collection of learning articles has been assembled to provide an overview of the features provided by the display system, illustrated by interactive samples.

Viewport.zoomToElements improvements

Viewport.zoomToElements accepts any number of element Ids and fits the viewport to the union of their Placements. A handful of shortcomings of the previous implementation have been addressed:

  • Previously, the element Ids were passed to IModelConnection.Elements.getProps, which returned all of the element's properties (potentially many megabytes of data), only to extract the PlacementProps for each element and discard the rest. Now, it uses the new IModelConnection.Elements.getPlacements function to query only the placements.
  • Previously, if a mix of 2d and 3d elements were specified, the viewport would attempt to union their 2d and 3d placements, typically causing it to fit incorrectly because 2d elements reside in a different coordinate space than 3d elements. Now, the viewport ignores 2d elements if it is viewing a 3d view, and vice-versa.

Fresnel effect

LightSettings has been enhanced to support a non-realistic Fresnel effect. As simply explained here, the effect causes surfaces to reflect more light based on the angle between the viewer's line of sight and the vector between the viewer and a given point on the surface. Use FresnelSettings to configure this effect.

Especially when combined with ambient occlusion, this effect can produce non-realistic views suitable for plant models and architectural models.

Fresnel effect applied to an architectural model:

Fresnel effect applied to an architectural model

Fresnel effect applied to a plant model:

Fresnel effect applied to a plant model

The following code applies a display style similar to those illustrated above to a Viewport:

  // Enable ambient occlusion.
  viewport.viewFlags = viewport.viewFlags.with("ambientOcclusion", true);

  // Configure the lighting.
  viewport.displayStyle.lightSettings = LightSettings.fromJSON({
    // A relatively bright ambient light is the only light source.
    ambient: {
      intensity: 0.55,
    },
    // Increase the brightness of surfaces that are closer to parallel with the viewer's line of sight.
    fresnel: {
      intensity: 0.8,
      invert: true,
    },
    // Disable directional lighting.
    solar: {
      intensity: 0,
    },
  });

Transparent viewport background

In some applications it is useful to be able to see HTML content underneath a Viewport. This can now be achieved by setting DisplayStyleSettings.backgroundColor to a color with a transparency value greater than zero. HTML content behind the viewport will blend with the viewport's background color.

Three overlapping viewports with transparent background colors:

Three overlapping viewports with transparent background colors

Wiremesh display

The graphics displayed by an iTwin.js Viewport consist primarily of triangulated meshes. It can sometimes be useful to visualize the triangulation of these meshes. A new view flag - ViewFlags.wiremesh - now enables wiremesh display. When wiremesh display is enabled, the edges of each triangle are overlaid on top of the mesh as anti-aliased black lines approximately 1 pixel wide.

To enable wiremesh display for a viewport:

  viewport.viewFlags = viewport.viewFlags.with("wiremesh", true);

Wiremesh applied to a plant model

Wiremesh applied to a reality model

Viewport synchronization

TwoWayViewportSync establishes a connection between two Viewports such that any change to one viewport is reflected in the other. This includes not only Frustum changes, but changes to the display style, category and model selectors, and so on. Synchronizing everything is not always desirable; and if the viewports are viewing two different IModelConnections it is not even meaningful, as category and model Ids from one iModel will not make sense in the context of the other iModel.

Now, TwoWayViewportSync is extensible, allowing subclasses to specify which aspects of the viewports should be synchronized by overriding TwoWayViewportSync.connectViewports and TwoWayViewportSync.syncViewports. To establish a connection between two viewports using your subclass MyViewportSync, use MyViewportSync.connect(viewport1, viewport2).

A new subclass TwoWayViewportFrustumSync is supplied that synchronizes only the frusta of the viewports. The viewports will view the same volume of space, but may display different contents or apply different display styles. To establish this connection, use TwoWayViewportFrustumSync.connect(viewport1, viewport2).

Environment decorations

A DisplayStyle3dSettings can specify a SkyBox and GroundPlane to be drawn as environmental decorations. Previously, DisplayStyle3dSettings.environment was a mutable JSON EnvironmentProps, while DisplayStyle3dState.environment was a mutable Environment object, formerly defined in the core-frontend package. This made the API quite awkward and led to bugs in synchronizing the Viewport's decorations with changes to the environment settings.

Now, DisplayStyle3dSettings.environment is an immutable Environment object consisting of a GroundPlane, SkyBox, and flags controlling the display of each. These changes require adjustment to existing code that toggles the display of either. For example:

// Replace this:
style.environment.sky.display = true;
style.environment.ground.display = false;
// With this:
style.environment = style.environment.withDisplay({ sky: true, ground: false });

Additionally, until now the images used by a SkySphere or SkyBox were required to be hosted by persistent Texture elements stored in the iModel. Now, they can also be specified as a URL resolving to an HTMLImageElement, allowing custom skyboxes to be created without modifying the iModel.

Merging appearance overrides

A Viewport can have any number of FeatureOverrideProviders, each of which can specify how to override the appearances of elements, models, and/or subcategories. Sometimes, multiple providers want to override aspects of the appearance of the same objects, which produces conflicts. The existing methods for defining overrides - FeatureOverrides.overrideElement, FeatureOverrides.overrideModel, and FeatureOverrides.overrideSubCategory - each take a boolean replaceExisting argument that defaults to true. This means that if one provider overrides the line width of an element and another wants to override the same element's transparency, the caller's only choice is to either replace the existing override, resulting in only transparency being overridden; or keep the existing override, resulting in only line width being overridden. But in most cases, the better result would be to merge the two sets of overrides such that both transparency and line width are overridden.

A new FeatureOverrides.override method has been introduced to support merging appearance overrides. The caller can specify one of four strategies for dealing with conflicts, or accept the default:

  • "replace": The existing appearance overrides are replaced by the caller's own overrides, equivalent to the default replaceExisting=true for methods like overrideElement;
  • "skip": The existing appearance overrides are retained and the caller's own overrides are ignored, equivalent to replaceExisting=false for methods like overrideElement; or
  • "extend": Merge the new appearance with the existing appearance such that any aspect of the appearance not overridden by the existing appearance can be overridden by the new appearance.
  • "subsume" (the default): Merge the new appearance with the existing appearance such that any aspects of the appearance overridden by the existing appearance are preserved only if the new appearance does not also override them.

For example, if one provider overrides an element's color and transparency, and a second provider attempts to override its transparency and line width, using the "extend" option means the second provider will only override the line width, leaving the existing color and transparency overrides intact. Using the "subsume" option, the second provider will override the transparency and line width, leaving the existing color override intact.

Because the previous default behavior is generally not desirable, overrideElement, overrideModel, and overrideSubCategory have been deprecated in favor of the new override method. Existing code can be updated as follows:

// To use the new default "extend" behavior, replace these:
ovrs.overrideElement("0x123", appearance);
ovrs.overrideModel("0x456", appearance);
ovrs.overrideSubCategory("0x789", appearance);
// With these:
ovrs.override({ elementId: "0x123", appearance });
ovrs.override({ modelId: "0x456", appearance });
ovrs.override({ subCategoryId: " 0x789", appearance });

// To use the previous default "replace" behavior, replace this:
ovrs.overrideElement("0x123", appearance, true); // third argument is optional - defaults to true
// With this:
ovrs.override({ elementId: "0x123", appearance, onConflict: "replace" });

// To use the `replaceExisting=false` behavior, replace this:
ovrs.overrideModel("0x456", appearance, false);
// With this:
ovrs.override({ modelId: "0x456", appearance, onConflict: "skip" });

Improve/enhance particle systems

Improvements were made to the performance of ParticleCollectionBuilder and an optional rotationMatrix was added to ParticleProps so that particles can be rotated.

New clustering algorithm for MarkerSet

The MarkerSet class now clusters markers by the screen distance between their positions rather than overlap of their rectangles, so the Cluster.rect property is no longer needed and has been removed. Instead, there is a new member MarkerSet.clusterRadius that controls when nearby Markers are clustered.

Support for glTF graphics

glTF has become the de facto standard format for 3d graphics on the web. Now you can create a RenderGraphic from a glTF asset for use with Decorators, using readGltfGraphics. This example demonstrates how to convert a glTF asset into a graphic and display it using a decorator.

Note: readGltfGraphics targets the glTF 2.0 specification, but implementation of the full specification is an ongoing work in progress. The current implementation can successfully read many glTF assets, but if a particular asset fails to load or display properly, please file an issue.

Replacement for Viewport.readImage

Viewport.readImage suffers from a cumbersome API and several bugs. In particular, if it is asked to read a sub-region of the image it will calculate the y values incorrectly; and it produces an upside-down image by default. It has been deprecated in favor of Viewport.readImageBuffer. Callers of readImage can be upgraded as follows:

  // Use default arguments for readImage.
  viewport.readImage(); // old - upside-down by default!
  viewport.readImageBuffer({ upsideDown: true }); // new

  // Read the entire image right-side-up - the typical case:
  viewport.readImage(undefined, undefined, false); // old - must explicitly request right-side-up!
  viewport.readImageBuffer(); // new

  // Read a sub-rect of the image
  viewport.readImage(rect); // old - produces incorrect results!
  viewport.readImageBuffer({ rect }); // new

  // Resize the image
  viewport.readImage(undefined, size); // old
  viewport.readImageBuffer({ size });

New presentation features

Presentation rule additions

Schema requirements

A new requiredSchemas attribute has been added: Ruleset.requiredSchemas and RuleBase.requiredSchemas. The attribute allows an easy way to filter presentation rules based on ECSchemas / domains available in the iModel. See more details in the Required schema specification reference documentation page.

Conditional root node rules

Similar to Child Node Rule, the Root Node Rule now also has a condition attribute. The attribute provides more flexibility in enabling or disabling the rule, including the use of ruleset variables.

More precise way to set class polymorphism

Previously polymorphism was specified at specification level using ContentInstancesOfSpecificClassesSpecification.handleInstancesPolymorphically and InstanceNodesOfSpecificClassesSpecification.arePolymorphic attributes. They're now deprecated in favor of the new MultiSchemaClassesSpecification.arePolymorphic attribute and act as default values if the new attribute is not specified.

The change allows ContentInstancesOfSpecificClassesSpecification and InstanceNodesOfSpecificClassesSpecification specify multiple classes with different polymorphism values, if necessary.

Excluding classes

A new excludedClasses attribute has been added: ContentInstancesOfSpecificClassesSpecification.excludedClasses and InstanceNodesOfSpecificClassesSpecification.excludedClasses. The attribute provides an easy way to omit instances of specific classes from the result set. This was previously possible only through the instanceFilter attribute, but the new approach is much cleaner.

API additions

Content instance keys

A new PresentationManager.getContentInstanceKeys has been added to allow getting keys of content instances much more effectively compared to getting content with all the properties and having to parse them from there, in cases when only keys are required.

Content sources

A new getContentSources API has been added to PresentationManager:

The API allows finding out what classes are used to get properties for specific class of elements based on default presentation rules. The default presentation rules set are set up to include properties of various related classes when requesting content for specific types of elements. For example:

  • Include properties of bis.ElementUniqueAspect and bis.ElementMultiAspect when creating content for any bis.Element.
  • Include properties of bis.PhysicalType when creating content for bis.PhysicalElement.
  • ...and much more.

That information may be useful when building ECSQL queries or anywhere else where there's a need to know the sources of element properties.

Getting properties of multiple elements at once

A new PresentationManager.getElementProperties override has been added for requesting element properties based on given element classes. Compared to PresentationManager.getContent that was already available and is more flexible, the new API is designed to retrieve the properties in a simplified and more efficient way, especially when requesting properties for large numbers of elements.

Auto-update

A number of improvements have been made to support hierarchy and content components' automatic updates when either of these events happen:

  • Data in iModel changes (only in IpcApp).
  • Presentation ruleset is modified.
  • Ruleset variable values for the ruleset are changed.

To enable the feature, an additional attribute has to be set when setting up presentation-rules-driven components:

  • When creating a node loader for ControlledTree using the usePresentationTreeNodeLoader hook, pass enableHierarchyAutoUpdate: true prop and resulting onItemsRendered callback to ControlledTree:

    const { nodeLoader, onItemsRendered } = usePresentationTreeNodeLoader({ ...otherLoaderProps, enableHierarchyAutoUpdate: true });
    return <ControlledTree {...otherTreeProps} nodeLoader={nodeLoader} onItemsRendered={onItemsRendered} />;
    
  • When creating PresentationPropertyDataProvider, pass enableContentAutoUpdate: true as a prop.

  • When creating PresentationTableDataProvider, pass enableContentAutoUpdate: true as a prop.

In addition, to enable iModels' change tracking, IPC backends should initialize Presentation with the following attributes:

Presentation.initialize({
  ...otherProps,

  // tell presentation system that data in iModels might change
  mode: PresentationManagerMode.ReadWrite,

  // tell presentation system how often (in milliseconds) it should poll for changes
  updatesPollInterval: 20,
});

New AppUi features

UiItemsProvider enhancements

UiItemsProviders will now filter out duplicate UiItems to ensure that only one of a particular item (e.g., Widget or Tool) will be added to a given stage. If you want the Select Tool is available in a stage, for example, you can include it in the Content Tools returned by your UiItemsProvider without checking to see if it's already in the stage you're augmenting. Until this release, the applicationData specified in the frontstage was obscured once the stage was instantiated. Now, the UiItemsProvider will pass that info along to to each of the provide*() callbacks for the UiItemsProvider to use if needed.

Window resize enhancements

A new ResizeObserver was has been implemented that supports both the main window and any pop-out windows.

New options for defining Frontstages

Class/Component Description
StandardFrontstageProvider Frontstage provider that provides an 'empty' stage that is to be populated via UiItemsProviders.
StandardContentToolsProvider UiItemsProvider that will add common tool entries to Tool Widget.
StandardNavigationToolsProvider UiItemsProvider that will add common view tool entries to Navigation Widget.
StandardStatusbarItemsProvider UiItemsProvider that will add common statusbar items.
ContentToolWidgetComposer Provides an empty Tool Widget that is to be populate via UiItemsProviders.
ViewToolWidgetComposer Provides an empty Navigation Widget that is to be populate via UiItemsProviders.
StandardContentLayouts Provides standard view layouts that can be used when defining a ContentGroup.
ContentGroupProvider Class that generates a ContentGroup at runtime when the frontstageDef is being constructed.

New timeline date marker

The TimelineComponent react component now accepts a property to mark a specific date in a date-based timeline. If the timeline has a defined start date and end date, a date between them can be marked in the timeline by specifying an instance of TimelineDateMarkerProps in the new markDate member of TimelineComponentProps. If the date member is left undefined, today's date will be used. The default marker is a short vertical bar, but a ReactNode can be specified in the dateMarker prop to customize the marker's appearance.

New Floating widget capabilities

Widgets provided via UiItemsProviders may now set defaultState: WidgetState.Floating and isFloatingStateSupported: true to open the widget in a floating container. The property defaultFloatingPosition may also be specified to define the position of the floating container. If a position is not defined the container will be centered in the AppUi area.

The method getFloatingWidgetContainerIds() has been added to FrontstageDef to retrieve the Ids for all floating widget containers for the active frontstage as specified by the frontstageDef. These ids can be used to query the size of the floating container via frontstageDef.getFloatingWidgetContainerBounds. The method frontstageDef.setFloatingWidgetContainerBounds can then be used to set the size and position of a floating widget container.

New API to enable and disable view overlays

UiFramework now offers a setViewOverlayDisplay(display:boolean) method to enable or disable viewports displaying overlays. By default, the display is enabled. The current setting is available in UiFramework.viewOverlayDisplay.

New ECSql features

Id64Set parameter bindings

It is now possible to efficiently bind a large set of ECInstanceIds to a query parameter. This can be very useful for IN clauses. For example, imagine you wanted to select some properties of all of the SpatialModels belonging to a ModelSelector. Previously you would need to write something like this:

  const ids = Array.from(modelSelector.models).join(",");
  db.query("SELECT IsPlanProjection, JsonProperties FROM bis.SpatialModel WHERE ECInstanceId IN (" + ids + ")");

The list of comma-separated Ids could be extremely long - in some cases, it might be so long that it would need to be split up into multiple queries!

Now, you can bind a set of Ids as a parameter for the IN clause. The Ids will be serialized in a compact string format.

  const params = new QueryBinder().bindIdSet("modelIds", modelSelector.models);
  db.query("SELECT IsPlanProjection, JsonProperties FROM bis.SpatialModel WHERE InVirtualSet(:modelIds, ECInstanceId)", params);

Breaking Changes

Application setup

A handful of changes have been made to simplify the process of setting up an application on both the backend and frontend side.

Removed default API keys

Previous versions of @itwin/core-frontend included API keys for Bing Maps, MapBox Imagery, and Cesium ION that would be used for all iTwin.js applications. These common keys are no longer supported and will soon be disabled. All applications will now need to provide their own keys.

A valid MapBox key is required for display of map imagery in views with BackgroundMapProvider.name set to "MapBoxProvider".

A valid Bing Maps key is required for:

A valid Cesium ION key is required for:

IModelAppOptions.mapLayerOptions can be used to configure keys for Bing Maps, MapBox, and/or any other map layer providers. TileAdmin.Props.cesiumIonKey can be used to configure the Cesium ION key. For example, the following configures the Bing Maps and Cesium ION keys at startup:

const appOptions: IModelAppOptions = {
  mapLayerOptions: {
    BingMaps: {
      key: "some key",
      value: "key",
    },
  },
  tileAdmin: {
    cesiumIonKey: "key",
  },
};

await IModelApp.startup(appOptions);

Deprecation of the settings on iModelApp

The previous IModelApp.settings API has been removed in favor of IModelApp.userPreferences. The updated API will provide a clear distinction between the "settings" within the control of the user (user preferences) and which are within control of the admin of an iModel/iTwin (Workspaces). The separation is intended to make it clear who is capable of modifying and overriding a given setting while making the API easier to use.

The new UserPreferencesAccess interface is a simple, easy-to-use API that can be implemented in many different ways. The core-frontend package does not dictate an implementation and could easily be setup using Local Storage (via Storage APIs) or by a cloud-hosted storage mechanism to share across user sessions.

Localization initialization

In previous versions, localization was provided via the I18N class. iTwin.js has been updated to instead use the Localization interface. The initialization of IModelApp now takes an optional object that implements Localization. The ITwinLocalization class supplies the default implementation, and may be customized with LocalizationOptions in the constructor and supplied via IModelAppOptions.localization.

The previous way to provide localization options:

const i18nOptions: I18NOptions = {
  urlTemplate: `${window.location.origin}/locales/{{lng}}/{{ns}}.json`
};

await IModelApp.startup({ i18n: i18nOptions });

Now becomes:

const localizationOptions: LocalizationOptions = {
  urlTemplate: `${window.location.origin}/locales/{{lng}}/{{ns}}.json`
};

await IModelApp.startup({ localization: new ITwinLocalization(localizationOptions) });

Simplification of CloudStorageService setup in iModelHost

IModelHostConfiguration.tileCacheCredentials is changed to IModelHostConfiguration.tileCacheAzureCredentials and used for setting Azure cloud storage for tile cache. IModelHost.tileCacheService is moved to IModelHostConfiguration.tileCacheService and is used to supply a different implementation for any service provider by setting this property with a custom CloudStorageService. If both tileCacheAzureCredentials and tileCacheService omitted - local cache will be used, if both set - error will be thrown.

To use Azure cloud storage for tile cache set IModelHostConfiguration.tileCacheAzureCredentials property:

  const config = new IModelHostConfiguration();
  // Replace this:
  config.tileCacheCredentials = {
    service: "azure",
    account: "account",
    accessKey: "accessKey",
  };
  // With this:
  config.tileCacheAzureCredentials = {
    account: "account",
    accessKey: "accessKey",
  };

To use AliCloud storage set IModelHostConfiguration.tileCacheService property with provided AliCloudStorageService implementation:

  import { AliCloudStorageService } from "@itwin/core-backend";

  const config = new IModelHostConfiguration();
  // Replace this:
  config.tileCacheCredentials = {
    service: "alicloud",
    account: "account",
    accessKey: "accessKey",
  };
  // With this:
  config.tileCacheService = new AliCloudStorageService({
    region: "region",
    accessKeyId: "accessKeyId",
    accessKeySecret: "accessKeySecret",
  });

To use any other external storage set IModelHostConfiguration.tileCacheService with a custom CloudStorageService implementation:

  const config = new IModelHostConfiguration();
  // Replace this:
  config.tileCacheCredentials = {
    service: "external",
    account: "",
    accessKey: "",
  };
  IModelHost.tileCacheService = new CustomCloudStorageService();
  // With this:
  config.tileCacheService = new CustomCloudStorageService();

@bentley/config-loader

The loader has been deprecated due to a preference for using the dotenv package instead. Any workflows using .env files will not be affected.

Authorization re-work

The release contains quite a few changes to authorization to make iTwin.js more flexible for different non-Bentley Identity Providers and removing the enforcement of OAuth2.0 in the core library. In order to make this change, a set of changes were made; the format of the token used, refactored how an access token is passed through the code and remove the default clients that made it challenging to use different authentication workflows.

AccessToken refactor

The previous AccessToken class has been completely removed in favor of a simple AccessToken string type. The core packages no longer interpret the token and only pass it around directly to the functions that need it using TokenArg.

ClientRequestContext and AuthorizedClientRequestContext have been removed

The classes ClientRequestContext and AuthorizedClientRequestContext existed to identify RPC requests between a web frontend and a cloud backend. They have been removed. Most places that previously used an AuthorizedClientRequestContext should now be replaced with AccessToken.

If you have code that has something like this:

requestContext.enter();

you can simply delete it.

This change mostly affects backend code. For backend RPC implementations, all unhandled exceptions will automatically be logged along the appropriate RPC metadata. For this reason, it often preferable to throw an exception rather than logging an error and returning a status in code that may or may not be called from RPC.

Authorization Clients

The class hierarchy of AuthorizationClients has been simplified in the core packages and the only contract of any authorization client is the AuthorizationClient interface.

iModels

Continued transition to ChangesetIndex

Every Changeset has both an Id (a string hash of its content and parent changeset) and an Index (a small integer representing its relative position on the iModel's timeline). Either value can be used to uniquely identify a changeset. However, it is often necessary to compare two changeset identifiers to determine relative order, or to supply a range of changesets of interest. In this case, Id is not useful and must be converted to an index via a round-trip to an iModelHub server. Unfortunately, much of the iTwin.js API uses only ChangesetId to identify a changeset. That was unfortunate, since ChangesetIndex is frequently needed and ChangesetId is rarely useful. For this reason we are migrating the API to prefer ChangesetIndex over several releases.

In version 2.19, we introduced the type ChangesetIdWithIndex to begin that migration. However, for 2.x compatibility we could not use it several places where it would have been helpful:

Each of these interfaces originally had only a member changeSetId: string, In 2.19, for backwards compatibility, a new member changeSetIndex?: number was added. In V3 those two members are now replaced with a single member changeset: ChangesetIdWithIndex. Note that this is a breaking change, and you may have to adjust your code. To get the changeset Id, use changeset.id. To get the changeset Index, use changeset.index (may be undefined). In V4, this will become changeset: ChangesetIndexAndId and index will be required.

Note: "Changeset" is one word. Apis should not use a capital "S" when referring to them.

Concurrency control

The previous implementation of ConcurrencyControl for locking elements has been replaced with the LockControl interface.

ConcurrencyControl relied on detecting a list of changed elements and deferring the acquisition of locks until the application called the asynchronous request method to acquire locks, after the fact, but before calling BriefcaseDb.saveChanges. The new approach is to require applications to call the asynchronous method LockControl.acquireLocks to get an exclusive lock on elements before update or delete, and shared locks on parents and models before insert. If an attempt is made to modify or insert without the required locks, an exception is thrown when the change is attempted. This will require tools to make the necessary lock calls.

Previously the concurrency "mode" was determined by applications when opening a briefcase. It is now established as a property of an iModel when it is first created (and "version0" is uploaded.) By default, iModels use pessimistic (i.e. locks) mode, so all previously created iModels will require locks. If you pass noLocks: true as an argument to BackendHubAccess.createNewIModel, a briefcase-local value is saved in rev0.bim before it is uploaded. Thereafter, all briefcases of that iModel will use use optimistic (i.e. no locks, change merging) mode, since everyone will use briefcases derived from rev0.bim. The value is inspected in the BriefcaseDb.useLockServer method called by BriefcaseDb.open.

Locks apply to Elements only. The "schema lock" is acquired by exclusively locking element id 0x1 (the root subject id). Models are locked via their modeled element (which has the same id as the model)

See the ConcurrencyControl learning article for more information and examples.

BriefcaseManager, BriefcaseDb, and IModelDb changes

The signatures to several methods in BriefcaseManager and BriefcaseDb have been changed to make optional the previously required argument called requestContext. That argument was poorly named, but used only to supply a "user access token". Since anywhere briefcases are relevant, an authenticated user access token is available via the static method IModelHost.getAccessToken, this argument is rarely needed. The only case where a caller needs to supply that argument is for tests that wish to simulate multiple users via a single backend (which is not permitted outside of tests.) It is now optional and called user.

Method New arguments notes
BriefcaseDb.onOpen OpenBriefcaseArgs event signature change
BriefcaseDb.onOpened BriefcaseDb,OpenBriefcaseArgs event signature change
BriefcaseDb.open OpenBriefcaseArgs
BriefcaseDb.pullChanges PullChangesArgs was called pullAndMergeChanges
BriefcaseDb.pushChanges PushChangesArgs
BriefcaseDb.upgradeSchemas OpenBriefcaseArgs requestContext removed
BriefcaseManager.acquireNewBriefcaseId IModelIdArg
BriefcaseManager.downloadBriefcase RequestNewBriefcaseArg
IModelDb.importSchemas LocalFileName[] requestContext removed

Changed return types

The backend methods IModelDb.saveFileProperty and IModelDb.deleteFileProperty used to return a DbResult. They now are void, and throw an exception if an error occurred. The error value can be retrieved in the errorNumber member of the exception object, if desired.

Signature change to backend Geocoordinate methods

The two methods IModelDb.getIModelCoordinatesFromGeoCoordinates and IModelDb.getGeoCoordinatesFromIModelCoordinates used to take a string argument that was a stringified IModelCoordinatesRequestProps and GeoCoordinatesRequestProps respectively. Those arguments were changed to accept the interfaces directly. You should remove JSON.stringify from your code if you get compile errors.

Coordinate conversion between iModel GeographicCRS and any other GeographicCRS

Coordinate conversions is now possible between the iModel Geographic Coordinate Reference System and any other Geographic Coordinate Reference System. Prior to this version, coordinate conversions were limited to those between the iModel Geographic Coordinate Reference System and latitude/longitude of a specified datum, usually WGS84.

To use, in the backend create either a IModelCoordinatesRequestProps or a GeoCoordinatesRequestProps depending on the direction coordinates are to be converted. Set the IModelCoordinatesRequestProps.source or the GeoCoordinatesRequestProps.target property to a string containing either the name of a datum (typically WGS84) or an empty string to specify the iModel Geographic CRS native datum or a stringified version of a GeographicCRSProps containing the definition of the source or target of the coordinate conversion. The request can be added coordinates to be converted and fed in methods iModel.getGeoCoordinatesFromIModelCoordinates or iModel.getIModelCoordinatesFromGeoCoordinates.

Specification of the GeographicCRS can be complete or incomplete. Although fully-defined custom Geographic CRS are supported, most of the time simply specifying the id or the epsg code of the GeographicCRS is sufficient.

Here are examples of typical GeographicCRS:

{ horizontalCRS: { id: "CA83-II" }, verticalCRS: { id: "NAVD88" } }

or

{ horizontalCRS: { epsg: 26942 }, verticalCRS: { id: "NAVD88" } },

These identifiers refer to either the key-name of a Geographic CRS in the list of the dictionary or a known EPSG code.

More complex Geographic CRS can also be used such as the following user-defined:

      {
        horizontalCRS: {
          id: "UserDef-On-NAD83/2011",
          description: "User Defined",
          datumId: "NAD83/2011",
          unit: "Meter",
          projection: {
            method: "TransverseMercator",
            centralMeridian: -1.5,
            latitudeOfOrigin: 52.30,
            scaleFactor: 1.0,
            falseEasting: 198873.0046,
            falseNorthing: 375064.3871,
          },
        },
        verticalCRS: {
          id: "GEOID",
        },
      }

On the frontend the GeoConverter class has been modified to accept either a string containing the datum or a GeographicCRSProps of a similar format retaining cache capability as before for either format.

NOTE: The IModelCoordinatesRequestProps.source and the GeoCoordinatesRequestProps.target were renamed from previous version that used the sourceDatum and targetDatum properties.

Utility methods

BentleyError constructor no longer logs

In V2, the constructor of the base exception class BentleyError accepted 5 arguments, the last 3 being optional. Arguments 3 and 4 were for logging the exception in the constructor itself. That is a bad idea, since exceptions are often handled and recovered in catch statements, so there is no actual "problem" to report. In that case the message in the log is either misleading or just plain wrong. Also, code in catch statements always has more "context" about why the error may have happened than the lower level code that threw (e.g. "invalid Id" vs. "invalid MyHashClass Id") so log messages from callers can be more helpful than from callees. Since every thrown exception must be caught somewhere, logging should be done when exceptions are caught, not when they're thrown.

The BentleyError constructor now accepts 3 arguments, the last argument (metaData) is optional. The previous log and category arguments were removed. If your code passed 5 arguments, remove the 3rd and 4th. If you previously passed 3 or 4 arguments, just leave the first two. Also, the previous version of the constructor required the metaData argument to be a function that returns an object. It may now also just be an object.

Logger functions

The optional metaData argument for the Logger functions was previously a function returning an object or undefined. That was to permit cases where it may be expensive to create the metadata to be elided when logging is turned off. However, there are many cases where the metaData object is directly available, so creating a function to return it created overhead whether or not logging is enabled. It may now also be just an object so you don't have to make a function.

Moved utility types

The AsyncFunction, AsyncMethodsOf, and PromiseReturnType types have moved to the @itwin/core-bentley package. The ones in @itwin/core-frontend have been deprecated.

Tool framework

Tool.run and Tool.parseAndRun are now async

In V2.0, the methods Tool.run and Tool.parseAndRun were synchronous. This was problematic in that it was impossible to invoke a tool and await its completion. Those two methods are now both async and return Promise<boolean>. This is obviously a breaking change. Any Tool subclasses that override those methods will need to become async, and any code that calls Tool.run or Tool.parseAndRun will need to appropriately handle the returned Promise (usually by awaiting it.)

In the process of converting Tool.run and Tool.parseAndRun to async, several other Tool class methods also became async and will likewise need to be modified if they are called or overridden.

These methods were previously synchronous and are now async:

Registering tools

In previous versions, the Tool.register method took an optional argument to supply the localization object. Since it always existed on IModelApp, that argument served no purpose and is now removed. If you previously passed it, simply remove it.

Display system breaking changes

Changes to GraphicBuilder

It is no longer necessary to supply a Viewport when creating a GraphicBuilder. Instead, you can supply to RenderSystem.createGraphic a CustomGraphicBuilderOptions containing a function that can compute the level of detail appropriate for the produced RenderGraphic.

GraphicBuilder's properties are all now read-only - you can no longer change placement, pickId, wantNormals, or wantEdges after creating the builder. Previously, a caller could create a graphic builder, add some geometry, then modify any of these properties before adding more geometry, more often than not producing surprising results.

Breaking map imagery API changes

Originally, the type of imagery to be displayed for the background map was defined by BackgroundMapSettings.providerName and BackgroundMapSettings.mapType. Later, support for any number of map layers from any source was added in the form of MapImagerySettings. The BackgroundMapSettings properties therefore became redundant with (and more limited than) MapImagerySettings.backgroundBase.

MapImagerySettings is now fully responsible for specifying the background map imagery; BackgroundMapSettings controls only how that imagery is applied to the view. The corresponding JSON properties have been removed from BackgroundMapProps; for backwards compatibility, they continue to exist in PersistentBackgroundMapProps and will be used as the background imagery if no background imagery is specified by MapImageryProps.backgroundBase.

Previously, most code would change the map imagery using Viewport.changeBackgroundMapProps or DisplayStyleState.changeBackgroundMapProps. Such code will no longer compile - it should instead use Viewport.changeBackgroundMapProvider or DisplayStyleState.changeBackgroundMapProvider. For example:

  // Replace this:
  viewport.changeBackgroundMapProps({ providerName: "BingMapProvider", providerData: { mapType: BackgroundMapType.Street } });
  // With this:
  viewport.changeBackgroundMapProvider({ name: "BingMapProvider", type: BackgroundMapType.Street });

Because a BaseLayerSettings can be either a BaseMapLayerSettings or a solid ColorDef, and the former can be configured to use a BackgroundMapProvider or any other imagery source, querying the current provider is now more complicated:

  // Replace this:
  const providerName: BackgroundMapProviderName = displayStyleSettings.backgroundMap.providerName;
  // With something like:
  let providerName: BackgroundMapProviderName | undefined;
  if (displayStyleSettings.mapImagery.backgroundBase instanceof BaseMapLayerSettings)
    providerName = displayStyleSettings.mapImagery.backgroundBase.provider?.name;

If you are producing JSON from a BackgroundMapSettings to be persisted as a DisplayStyleSettingsProps object, change your code as follows:

  // Replace this (no longer compiles):
  displayStyleSettingsProps.backgroundMap = backgroundMapSettings.toJSON();
  // With this:
  displayStyleSettingsProps.backgroundMap = backgroundMapSettings.toPersistentJSON();

Likewise if you are reading a BackgroundMapSettings directly from a persistent DisplayStyleSettingsProps, change your code as follows:
```typescript
  // Replace this (no longer compiles):
  const mapSettings = BackgroundMapSettings.fromJSON(displayStyleSettings.backgroundMap);
  // With this:
  const mapSettings = BackgroundMapSettings.fromPersistentJSON(displayStyleSettings.backgroundMap);

DisplayStyleSettings.onBackgroundMapChanged will no longer be raised when changing the imagery provider. Use DisplayStyleSettings.onMapImageryChanged instead.

ViewFlags

Immutability

ViewFlags has long been a common source of surprising behavior. Consider the following code:

function turnOnShadows(vp: Viewport) {
  vp.viewFlags.shadows = true;
}

You could be forgiven for expecting the image displayed in the Viewport to include shadows after calling this function, but that will not be the case. Instead, you must write the function as follows:

function turnOnShadows(vp: Viewport) {
  const vf = vp.viewFlags.clone();
  vf.shadows = true;
  vp.viewFlags = vf;
}

To rectify this, and to eliminate various other pitfalls associated with mutable state, ViewFlags has been converted to an immutable type - all of its properties are read-only and the only way to change a property is to create a copy. The function above can now be written as:

function turnOnShadows(vp: Viewport) {
  vp.viewFlags = vp.viewFlags.with("shadows", true);
  // or, equivalently, but less efficiently in this case:
  vp.viewFlags = vp.viewFlags.copy({ shadows: true });
}

Methods that mutate a ViewFlags object have been removed.

  • clone has been replaced with ViewFlags.copy, which returns a new object instead of modifying this.
  • createFrom has been removed. Because ViewFlags is immutable, it is never necessary to create an identical copy of one - just use the same object. Or, if for some reason you really want an identical copy, use the object spread operator.

If your code used to modify a single property, change it to use ViewFlags.with or ViewFlags.withRenderMode:

// Replace this...
viewport.viewFlags.clipVolume = true;
// ...with this:
viewport.viewFlags = viewFlags.with("clipVolume", true);

If your code used to modify multiple properties, change it to use ViewFlags.copy:

// Replace this...
viewport.viewFlags.shadows = viewport.viewFlags.lighting = true;
// ...with this:
viewport.viewFlags = viewport.viewFlags.copy({ shadows: true, lighting: true });

If your code used to create a new ViewFlags and then modify its properties, pass the initial properties to ViewFlags.create instead:

// Replace this...
const vf = new ViewFlags();
vf.shadows = vf.lighting = true;
// ...with this:
const vf = ViewFlags.create({ shadows: true, lighting: true });
Removal of unused properties

The following deprecated ViewFlagProps properties were removed: hlMatColors, edgeMask.

The following deprecated ViewFlags properties were removed: noGeometryMap, hLineMaterialColors, edgeMask, noSolarLight, noCameraLights, noSourceLights.

If you were using noCameraLights, noSourceLights, or noSolarLight, use ViewFlags.lighting instead. Set it to true if any of the old light-related properties were false.

Construction

ViewFlags.fromJSON accepts a ViewFlagProps, which is awkward and error-prone for reasons discussed in that type's documentation. The ViewFlags.constructor - like the new ViewFlags.create static method - now takes an optional ViewFlagsProperties, which has exactly the same properties as ViewFlags. Prefer to use either create or the constructor instead of fromJSON.

ViewState3d.lookAt arguments changed

ViewState3d.lookAt previously took 6 arguments. Also, the method ViewState3d.lookAtUsingLensAngle established a perspective ViewState3d from a field-of-view lens angle with many of the same arguments. There is now a new implementation of ViewState3d.lookAt that accepts named parameters to set up either a perspective or orthographic view, using the interfaces LookAtPerspectiveArgs, LookAtOrthoArgs, or LookAtUsingLensAngle.

This is a breaking change, so you may need to modify your code and replace the previous arguments with a single object with the appropriate names. For example,:

viewState.lookAt(
  eye,
  target,
  upVector,
  newExtents,
  undefined,
  backDistance,
  opts
);

can become:

viewState.lookAt({
  eyePoint: eye,
  targetPoint: target,
  upVector,
  newExtents,
  backDistance,
  opts,
});

likewise

viewState.lookAtUsingLensAngle(
  eye,
  target,
  up,
  lens,
  frontDistance,
  backDistance
);

can become:

viewState.lookAt({
  eyePoint: eye,
  targetPoint: target,
  upVector: up,
  lensAngle: lens,
  frontDistance,
  backDistance,
});

OnViewExtentsError and MarginOptions separated from ViewChangeOptions

The opts argument to ViewState3d.lookAt was previously declared to be of type ViewChangeOptions. However, it only used the onExtentsError member to handle invalid view extents. That caused confusion because it led you to believe that ViewState3d.lookAt performed a view change when it doesn't, it merely modifies the ViewState3d.

There is now a separate interface OnViewExtentsError that ViewState3d.lookAt accepts it as its opts argument. Likewise, ViewState3d.lookAtVolume and ViewState3d.lookAtViewAlignedVolume accept "MarginOptions & OnViewExtentsError" as their opts argument.

ViewFlagOverrides

This cumbersome, inefficient class has been replaced with the identically-named ViewFlagOverrides type, which is simply an interface that has all the same properties as ViewFlags, but each is optional. A flag is overridden if its value is not undefined.

Upgrade instructions:

let ovrs = new ViewFlagOverrides(); // Old code - nothing overridden.
let ovrs = {}; // New code

let ovrs = new ViewFlagOverrides(viewFlags); // Old code - override everything according to a ViewFlags
let ovrs = { ...viewFlags }; // New code

ovrs.overrideAll(viewFlags); // Old code - override everything according to a ViewFlags
ovrs = { ...viewFlags }; // New code.

ovrs.setThematicDisplay(true); // Old code - override thematic display to be true.
ovrs.thematicDisplay = true; // New code

ovrs.clone(other); // Old code - make other be a copy of ovrs
other = { ...other }; // New code

ovrs.copyFrom(other); // Old code - make ovrs be a copy of other
ovrs = { ...other }; // New code

if (ovrs.isPresent(ViewFlagPresence.ThematicDisplay))
  if (undefined !== ovrs.thematicDisplay)
    // Old code
    // New code

    ovrs.setPresent(ViewFlagPresence.ThematicDisplay); // Old code
ovrs.thematicDisplay = value; // New code, where "value" is whatever value thematicDisplay was set to in the old code

ovrs.clearPresent(ViewFlagPresence.ThematicDisplay); // Old code
ovrs.thematicDisplay = undefined; // New code

if (ovrs.anyOverridden()); // Old code - determine if any flags are overridden
if (JsonUtils.isNonEmptyObject(ovrs)); // New code

ovrs.clear(); // Old code - mark all flags as not overridden
ovrs = {}; // New code

ovrs.clearClipVolume(); // Old code - mark clip volume as not overridden
ovrs.clipVolume = undefined; // New code

const vf = ovrs.apply(viewFlags); // Old code - create a ViewFlags by applying the overrides to the input ViewFlags
const vf = viewFlags.override(ovrs); // New code

const props = ovrs.toJSON(); // Old code - obtain JSON representation
const props = ovrs; // New code

let ovrs = ViewFlagOverrides.fromJSON(props); // Old code - create from JSON representation
let ovrs = { ...props }; // New code

Simplification of texture creation APIs

Previously, creating a RenderTexture generally involved creating a RenderTexture.Params object and passing it along with an iModel and some representation of an image to one of a half-dozen RenderSystem APIs. Those APIs have been consolidated into a single API: RenderSystem.createTexture. RenderTexture.Params and the RenderSystem APIs that use it have been deprecated, and the key and isOwned properties have been removed from RenderTexture.

RenderSystem.createTexture takes a CreateTextureArgs specifying the type of texture to create, the image from which to create it, and optional ownership information. The image includes information about its transparency - that is, whether it contains only opaque pixels, only semi-transparent pixels, or a mixture of both, where fully transparent pixels are ignored. If the caller knows this information, it should be supplied; the default - TextureTransparency.Mixed - is somewhat more expensive to render.

Adjusting code to pass the RenderTexture.Type:

  // Replace this:
  system.createTextureFromImageBuffer(imageBuffer, iModel, new RenderTexture.Params(undefined, RenderTexture.Type.TileSection);
  // With this:
  system.createTexture({
    type: RenderTexture.Type.TileSection,
    image: { source: imageBuffer },
  });

Adjusting code that specifies RenderTexture.Params.isOwned:

  // Replace this:
  const isOwned = true;
  system.createTextureFromImageBuffer(imageBuffer, iModel, new RenderTexture.Params(undefined, undefined, isOwned);
  // With this:
  system.createTexture({
    ownership: "external",
    image: { source: imageBuffer },
  });

Adjusting code that specifies RenderTexture.Params.key:

  // Replace this:
  system.createTextureFromImageBuffer(imageBuffer, iModel, new RenderTexture.Params(myKey);
  // With this:
  system.createTexture({
    ownership: { iModel: myIModel, key: myKey },
    image: { source: imageBuffer },
  });

Adjusting callers of RenderSystem.createTextureFromImage:

  // Replace this:
  system.createTextureFromImage(image, hasAlpha, iModel, params);
  // With this:
  system.createTexture({
    image: {
      source: image,
      // If you know the texture contains only opaque or only translucent pixels, specify TextureTransparency.Opaque or TextureTransparency.Translucent;
      // otherwise omit it or specify TextureTransparency.Mixed.
      transparency: hasAlpha ? TextureTransparency.Translucent : TextureTransparency.Opaque,
    },
    // type and ownership as described above
  });

Adjusting callers of RenderSystem.createTextureFromImageBuffer:

  // Replace this:
  system.createTextureFromImageBuffer(buffer, iModel, params);
  // With this:
  system.createTexture({
    image: {
      source: buffer,
      // If the buffer's type is not RGBA, pass TextureTransparency.Opaque. Otherwise, if you don't know the transparency, omit it.
      transparency: TextureTransparency.Mixed,
    },
    // type and ownership as described above
  });

Adjusting callers of RenderSystem.createTextureFromImageSource:

  // Replace this:
  await system.createTextureFromImageSource(source, iModel, params);
  // With this:
  const image = await imageElementFromImageSource(source);
  system.createTexture({
    image: {
      source: image,
      // If the source was a JPEG, pass TextureTransparency.Opaque because JPEGs don't support transparency.
      // Otherwise, supply the transparency if you know it; otherwise omit it.
      transparency: TextureTransparency.Opaque,
    },
    // type and ownership as described above
  });

Default minimum level of detail for spatial views

TileAdmin.Props.minimumSpatialTolerance specifies the minimum level of detail to produce for views of spatial models. Previously, the default was undefined, indicating no minimum. The default has been changed to 1 millimeter. This means that when zooming in extremely closely, geometry that contains details on the order of 1mm or smaller will not refine further. This prevents the display system from requesting extraordinarily detailed graphics, improving performance.

To change the minimum, supply a different value at startup. For example, the following code sets the minimum to 1 centimeter:

await IModelApp.startup({
  tileAdmin: { minimumSpatialTolerance: 0.01 },
});

Presentation

Changes to @itwin/presentation-common

NodeKey

The NodeKey object contains a pathFromRoot attribute which can be used to uniquely identify a node in a hierarchy. In addition, the attribute is stable - the value for the same node is the same even when being created by different backends, which allows it to be persisted and later be used to identify specific nodes.

In 3.0 changes have been made that changed the way this attribute is calculated, which means the same node produced by pre-3.0 and 3.x versions of imodeljs will have keys with different pathFromRoot value. To help identify the version of NodeKey a new version attribute has been added, with undefined or 1 being assigned to keys produced by pre-3.0 and 2 being assigned to keys produced by 3.x versions of imodeljs. In addition, a new NodeKey.equals function has been added to help with the equality checking of node keys, taking their version into account.

KeySetJSON

The format of KeySetJSON has been changed to reduce its size. Instead of containing an array of instance IDs it now contains a single compressed IDs string. See CompressedId64Set for more details about compressing IDs.

Changes to Presentation initialization in @itwin/presentation-backend

  • PresentationManagerProps have been restructured to make attributes' purpose clearer. This affects calls to constructor of PresentationManager and Presentation.initialize. Typical migration:

    Before:

    await Presentation.initialize({
      // now `defaultLocale`
      activeLocale: "en-us",
    
      // now `defaultUnitSystem`
      activeUnitSystem: "metric",
    
      // now under `caching.hierarchies`
      cacheConfig: { mode: HierarchyCacheMode.Memory },
    
      // now under `caching.content.size`
      contentCacheSize: 999,
    
      // removed in favor of `workerThreadsCount`
      taskAllocationsMap: {
        [RequestPriority.Preload]: 1,
        [RequestPriority.Max]: 2,
      },
    });
    

    After:

    await Presentation.initialize({
      presentation: {
        defaultLocale: "en-us",
        defaultUnitSystem: "metric",
        caching: {
          hierarchies: {
            mode: HierarchyCacheMode.Memory,
          },
          content: {
            size: 999,
          },
        },
        workerThreadsCount: 3,
      },
    });
    

Changes to Presentation initialization in @itwin/presentation-frontend

  • Presentation.initialize used to take PresentationManagerProps as an argument. Now it takes PresentationProps which allows supplying props not only to PresentationManager, but also SelectionManager and FavoritePropertiesManager. Typical migration:

    Before:

    await Presentation.initialize({
      // ...props for presentation manager
      activeLocale: "en-us",
    });
    

    After:

    await Presentation.initialize({
      presentation: {
        // ...props for presentation manager
        activeLocale: "en-us",
      },
    });
    
  • The frontend used to by default initialize with an IFavoritePropertiesStorage implementation that uses Bentley's user settings service which may not be accessible by third party applications. The behavior was changed to use to a no-op storage by default with ability to choose an implementation that uses the settings service. Typical migration:

    Before:

    // no way to override favorite properties storage, so the implementation using settings service is used
    await Presentation.initialize();
    

    After:

    await Presentation.initialize({
      favorites: {
        // by default the no-op storage is used, but we can choose another option (or provide our own implementation)
        storage: createFavoritePropertiesStorage(
          DefaultFavoritePropertiesStorageTypes.UserPreferencesStorage,
        ),
      },
    });
    

ControlledTree API changes

ControlledTree component has received the following breaking changes:

  • The component now takes TreeModel rather than VisibleTreeNodes as a prop to avoid requiring consumers to manage VisibleTreeNodes object. As a result, the useVisibleTreeNodes hook was replaced with useTreeModel hook. Typical migration:

    Before:

    const visibleNodes = useVisibleTreeNodes(modelSource);
    return <ControlledTree visibleNodes={visibleNodes} {...otherProps} />;
    

    After:

    const treeModel = useTreeModel(modelSource);
    return <ControlledTree model={treeModel} {...otherProps} />;
    
  • Name of the treeEvents prop was changed to eventsHandler to make it clearer. Typical migration:

    Before:

    return <ControlledTree treeEvents={eventsHandler} {...otherProps} />;
    

    After:

    return <ControlledTree eventsHandler={eventsHandler} {...otherProps} />;
    
  • width and height properties are now required. Previously they were optional and forced us to use non-optimal approach when not provided. Now it's up to the consumer to tell the size of the component. Typical migration:

    Before:

    return <ControlledTree {...props} />;
    

    After:

    const width = 100;
    const height = 100;
    return <ControlledTree width={width} height={height} {...props} />;
    

    width and height props may be calculated dynamically using ResizeObserver API.

  • width and height are now required props for VirtualizedPropertyGrid and VirtualizedPropertyGridWithDataProvider. Also, width is now a required property for PropertyList. Previously they were optional and forced us to use non-optimal approach when not provided. Now it's up to the consumer to tell the size of the component. Typical migration:

    Before:

    return <VirtualizedPropertyGrid {...props} />;
    

    After:

    const width = 100;
    const height = 100;
    return <VirtualizedPropertyGrid width={width} height={height} {...props} />;
    

    width and height props may be calculated dynamically using ResizeObserver API.

  • Default value of PresentationPropertyDataProvider.isNestedPropertyCategoryGroupingEnabled was changed from false to true.

AppUi Changes

Some components in @itwin/core-react were deprecated in favor of components in @itwin/itwinui-react. A few constructs were deprecated in @itwin/core-react package with alternatives elsewhere. The Table component has been deprecated in favor of the Table in @itwin/itwinui-react. A new @itwin/imodel-components-react package has been added and contains items related to Color, Cube, LineWeight, Navigation Aids, Quantity Inputs, Timeline and Viewport.

The iTwin.js ui and @itwin/presentation-components packages are now dependent on React version 17. Applications using the ui packages must update to React 17. Details about React version 17 can be found in the React Blog.

React 16 is not an officially supported version of iTwin.js app or Extension development using the iTwin.js AppUi.

The component UiSettingsProvider has been renamed to UiStateStorageHandler and updated so it no longer takes a prop. Internally it now uses the value from UiFrameWork.getUiStateStorage and listens for changes to that value. This rename was to avoid confusion between UI State and User Preferences.

The component FrameworkVersion has been updated so it no longer takes a version prop. It now uses the value of frameworkState.configurableUiState.frameworkVersion from the redux store as the version. This value may be set using UiFramework.setUiVersion method and will be initialized to "2". Existing iModelApps using the 1.0 version of the user interface were not required to include the <FrameworkVersion> component in its component tree. It is now required that every iModelApp include the <FrameworkVersion> component and that the redux store entry mentioned above is specified to either "1" or "2". Below is a typical component tree for an iModeApp.

<Provider store={MyIModelApp.store} >
  <ThemeManager>
    <SafeAreaContext.Provider value={SafeAreaInsets.All}>
      <ToolbarDragInteractionContext.Provider value={false}>
        <FrameworkVersion>
          <UiStateStorageHandler>
            <ConfigurableUiContent
              appBackstage={<AppBackstageComposer />}
            />
          </UiStateStorageHandler>
        </FrameworkVersion>
      </ToolbarDragInteractionContext.Provider>
    </SafeAreaContext.Provider>
  <ThemeManager>
</Provider>

Removed user change monitoring from @itwin/appui-react

Previously UiFramework would monitor the state of an access token and would close all UI popups if the token was found to be empty. This feature has been removed. It is now the applications responsibility to enable this capability if they want it. The method ConfigurableUiManager.closeUi is now public and can be called by application to close the popup items.

Deprecated components in favor of iTwinUI-react components

Several UI components in the @itwin/core-react and @itwin/components-react packages have been deprecated. Developers should use equivalent components in @itwin/itwinui-react instead.

Deprecated in @itwin/core-react Use from @itwin/itwinui-react instead
Button Button
ButtonSize size prop for itwinui-react Button
ButtonType styleType prop for itwinui-react Button
Checkbox Checkbox
ExpandableBlock ExpandableBlock
Headline Headline
HorizontalTabs HorizontalTabs
Input Input
LabeledInput LabeledInput
LabeledSelect LabeledSelect
LabeledTextarea LabeledTextarea
LabeledToggle ToggleSwitch with labelPosition="right" prop
LeadingText Leading
ProgressBar ProgressLinear
ProgressSpinner ProgressRadial
Radio Radio
Select Select
SelectOption SelectOption
Slider Slider
SmallText Small
Spinner ProgressRadial with indeterminate prop
SpinnerSize size prop in ProgressRadialProps
SplitButton SplitButton
Subheading Subheading
Textarea Textarea
Tile Tile
Title Title
Toggle ToggleSwitch
Tooltip Tooltip
TooltipPlacement Placement
Deprecated in @itwin/components-react Use from @itwin/itwinui-react instead
Breadcrumb Breadcrumbs
Deprecated in @itwin/imodel-components-react Use from @itwin/itwinui-react instead
ColorPickerPanel ColorPicker
Slider

The deprecated Slider was a wrapper around the react-compound-slider that does not work properly in popout windows. To eliminate this issue, the deprecated Sliderwill now wrap the Slider component from @itwin/itwinui-react. This result is a couple prop changes. The onSlideStart or onSlideEnd props are ignored, use onUpdate and onChange props if needed. The only two modes that remain supported are 1 and 2.

Deprecated with alternatives elsewhere

A few constructs were deprecated in @itwin/core-react package. Some were copied to the @itwin/appui-abstract package. Some have replacements within the @itwin/core-react package.

Deprecated Replacement
DialogButtonDef in @itwin/core-react DialogButtonDef in @itwin/appui-abstract
DialogButtonStyle in @itwin/core-react DialogButtonStyle in @itwin/appui-abstract
DialogButtonType in @itwin/core-react DialogButtonType in @itwin/appui-abstract
LocalUiSettings in @itwin/core-react LocalStateStorage in @itwin/core-react
SessionUiSettings in @itwin/core-react eliminated

New @itwin/imodel-components-react package

A new @itwin/imodel-components-react package has been added, and some items were moved from @itwin/core-react and @itwin/components-react into this new package. The ui-imodel-components package contains React components that depend on the imodeljs-frontend, imodeljs-common or imodeljs-quantity packages. Dependencies on these other iTwin.js packages have been removed from core-react and components-react. The items moved to ui-imodel-components are related to Color, Cube, LineWeight, Navigation Aids, Quantity Inputs, Timeline and Viewport.

The following items were moved into the ui-imodel-components package. For a complete list, see iTwin.js Documentation.

  • ColorPickerButton, ColorPickerDialog, ColorPickerPopup, ColorPropertyEditor, ColorSwatch
  • Cube, CubeNavigationAid, CubeRotationChangeEventArgs
  • DrawingNavigationAid
  • QuantityInput, QuantityNumberInput
  • TimelineComponent, TimelineDataProvider, TimelineMenuItemProps
  • ViewportComponent, ViewportComponentEvents
  • LineWeightSwatch, WeightPickerButton, WeightPropertyEditor

Tasks and workflows deprecated

Classes and methods pertaining to Tasks and Workflows have been deprecated due to a change in the UX design. Please continue to use Frontstages.

Buildology

@itwin/build-tools has bumped the Typescript compilation target from ES2017 to ES2019

All packages will continue to build a CommonJS variant, but will now deliver it to lib/cjs. All frontend and shared ("common") packages will now build an ESModules variant, and deliver it to lib/esm. This change is intended to improve the bundle sizes of applications and allow for dynamic imports in order to tree-shake unused code.

If you were previously importing directly from the lib directory (e.g. import { ElectronHost } from "@itwin/core-electron/lib/ElectronBackend";), you will need to update your code to import from the new directory, lib/cjs, (e.g. import { ElectronHost } from "@itwin/core-electron/lib/cjs/ElectronBackend";).

This also affects how you will import *.scss from the ui packages. If you were previously importing scss from the lib directory (e.g. @import "~@itwin/ui-pkg/lib/ui-pkg/...";), you will need to update your code to import from the new directory, lib/esm, (e.g. @import "~@itwin/ui-pkg/lib/esm/ui-pkg/...";).

Updates to @bentley/build-tools

  • Removed test and test-tsnode scripts from @itwin/build-tools. Please use mocha directly instead.
  • Removed TSLint support from @itwin/build-tools. If you're still using it, please switch to ESLint.
  • Removed legacy .eslintrc.js file from the same package. Instead, use @itwin/eslint-plugin and the imodeljs-recommended config included in it.
  • Dropped support for ESLint 6.x.

Transformation

New @itwin/core-transformer package

APIs for importing and exporting data between iModels have moved from the @itwin/core-backend package to the new @itwin/core-transformer package. These APIs include IModelExporter, IModelImporter, and IModelTransformer.

IModelImporter property options deprecated in favor of constructor options

Configuration of an IModelImporter is now only represented by an IModelImportOptions object passed to the constructor. The ability to modify options with the IModelImporter properties simplifyElementGeometry, autoExtendProjectExtents, and preserveElementIdsForFiltering has been deprecated; instead, set these options while constructing your IModelImporter, and read them if necessary from IModelImporter.options. For example, replace the following:

  const importer = new IModelImporter(targetDb);
  importer.autoExtendProjectExtents = true;
  const isExtendingProjectExtents = importer.autoExtendProjectExtents;
}

With this:

  const importer = new IModelImporter(targetDb, { autoExtendProjectExtents: true });
  const isExtendingProjectExtents = importer.options.autoExtendProjectExtents;

Customized handling of dangling predecessor Ids

When the IModelTransformer encounters a dangling predecessor element id reference in an iModel, an element id for which no element exists in the database, by default the entire transformation is rejected. Now, there are multiple behaviors to choose from for the transformer to use when it encounters such references while analyzing predecessor elements. The danglingPredecessorBehavior option defaults to reject, or can be configured as ignore, which will instead leave the dangling reference as is while transforming to the target. You can configure the new behavior like so:

  const transformer = new IModelTransformer(sourceDb, targetDb, { danglingPredecessorBehavior: "ignore" });

Various changes

iTwinId

Several api's in iTwin.js refer to the "context" for an iModel, meaning the project or asset to which the iModel belongs, as its contextId. That is very confusing, as the term "context" is very overloaded in computer science in general, and in iTwin.js in particular. That is resolved in iTwin.js V3.0 by recognizing that every iModel exists within an iTwin, and every iTwin has a GUID called its iTwinId. All instances of contextId in public apis that mean the iTwin for this iModel are now replaced by iTwinId.

This is a breaking change for places like IModel.contextId. However, it should be a straightforward search-and-replace contextId -> iTwinId anywhere you get compilation errors in your code.

Changes to UnitProps

The altDisplayLabels property in UnitProps has been removed. AlternateLabels are now provided via a AlternateUnitLabelsProvider. The QuantityFormatter now provides one for use when parsing string to quantities. To add custom labels use QuantityFormatter.addAlternateLabels see example below.

IModelApp.quantityFormatter.addAlternateLabels("Units.FT", "feet", "foot");

@bentley/extension-cli

The cli tool has been deprecated due to an impending change of Extensions and the Extension Service. Please continue to use the 2.x version if you still require publishing Extensions.

The oidc-signin-tool contained various authorization testing tools. It has been relocated to the @itwin/auth-clients repository.

@itwin/core-geometry

The method BSplineCurve3d.createThroughPoints has been deprecated in favor of the more general method BSplineCurve3d.createFromInterpolationCurve3dOptions.

The property InterpolationCurve3dOptions.isChordLenTangent has been deprecated due to a naming inconsistency with similar adjacent properties. Use InterpolationCurve3dOptions.isChordLenTangents instead.

@itwin/core-common

The fromRadians, fromDegrees, and fromAngles methods of Cartographic now expect to receive a single input argument - an object containing a longitude, latitude and optional height property. The public constructor for Cartographic has also been removed. If you would like to create a Cartographic object without specifying longitude and latitude, you can use the new createZero method. These changes will help callers avoid mis-ordering longitude, latitude, and height when creating a Cartographic object. Additionally, the LatAndLong and LatLongAndHeight interfaces have been removed and replaced with a single CartographicProps interface.

@itwin/core-backend

Entity is no longer type-compatible with EntityProps - this was a common source of bugs. Likewise, each subclass of Entity - i.e., Element, Model, and Relationship - is now type-incompatible with its corresponding EntityProps sub-type - ElementProps, ModelProps, and RelationshipProps. Code that attempts to pass an Entity to a function expecting an EntityProps will now produce a compilation error.

An EntityProps can be obtained from an Entity by calling Entity.toJSON. However, for inserting or updating entities, each subclass provides a more convenient and less error-prone method, like Model.insert and Element.update. For example, you can make the following replacement:

  // Old code passing an Element in place of an ElementProps- no longer compiles:
  element.iModel.elements.insert(element);
  // New code - much less verbose:
  element.insert();

Changes to ECSql APIs

Several changes to the APIs for executing ECSql statements have been made to improve performance and flexibility. This involved breaking changes to the query, queryRowCount, and restartQuery methods of IModelConnection, IModelDb, and ECDb.

  • The query and restartQuery methods used to take multiple arguments indicating a limit on the number of rows to return, a priority, a quota, and so on. These have been combined into a single QueryOptions parameter.

  • Previously there was no way to control the format of each row returned by the query and restartQuery methods, and the default format was verbose and inefficient. Now, these methods accept a QueryRowFormat as part of their QueryOptions parameter describing the desired format. The default format returns each row as an array instead of an object.

  • The query, restartQuery, and queryRowCount methods used to accept the statement bindings as type any[] | object. The bindings are now specified instead as the more type-safe type QueryBinder.

Binding parameters using QueryBinder

QueryBinder is a more type-safe way to bind parameters to an ECSql statement. It allows mixing indexed and named parameters in a single statement. For example:

  const params = new QueryBinder()
    .bindString("name", "hello")
    .bindId(1, "0x123");

  for await (const row of db.query("SELECT ECInstanceId, Name from bis.Element WHERE ECInstanceId=? AND Name=:name", params)) {
    const obj = { id: row[0], name: row[1] };
    // ...
  }
Upgrading existing code to use the new query methods

The signature of the method has changed to:

query(ecsql: string, params?: QueryBinder, options?: QueryOptions): AsyncIterableIterator<any>;

The rowFormat property of the options parameter defaults to QueryRowFormat.UseECSqlPropertyIndexes. That format is more efficient so its use is preferred, but it differs from the previous row format. You can upgrade existing code to use the old format with minimal changes. For example, if your existing code passes query parameters as an array, change it as follows:

  // Replace this:
  db.query("SELECT * FROM bis.Element WHERE ECInstanceId=?", ["0x1"]);
  // With this:
  db.query("SELECT * FROM bis.Element WHERE ECInstanceId=?", QueryBinder.from(["0x1"]), { rowFormat: QueryRowFormat.UseJsPropertyNames });
  // The code that accesses the properties of each row can remain unchanged.

Similarly, if your existing code passes an object instead of an array as the query parameter, change it as follows:

  // Replace this:
  db.query("SELECT * FROM bis.Element WHERE ECInstanceId = :id", {id: "0x1"});
  // With this:
  db.query("SELECT * FROM bis.Element WHERE ECInstanceId=?", QueryBinder.from({id: "0x1"}), { rowFormat: QueryRowFormat.UseJsPropertyNames });
  // The code that accesses the properties of each row can remain unchanged.
Upgrading existing code to use the new restartQuery methods

The parameters have changed in the same way as query, so they can be changed as described for query above.

Upgrading existing code to use the new queryRowCount methods

The behavior of this method has not changed, but the parameters must be provided as a QueryBinder object instead of an array or object. Upgrade your existing code as described for query above.

Dependency updates

Updated minimum requirements

Support for Node 10 has been dropped. The new minimum Node version is 12.22.0. The recommended version is the latest LTS version of Node. Please visit our Supported Platforms documentation for a full breakdown of compatibility.

Various package updates

The following dependencies of iTwin.js have been updated;

  • openid-client updated from to ^3.15.3 -> ^4.7.4,
  • electron updated from to ^11.1.0 -> ^14.0.0,
  • react updated from to ^16.8.9 -> ^17.0.0,
  • react-dom updated from to ^16.8.9 -> ^17.0.0,

API rename

Several APIs previously marked as deprecated, renamed alpha/beta APIs and moved APIs from one package to another. Generally, the reason for the deprecation as well as the alternative suggestions can be found in the 2.x release notes. Most of the renames highlighted below are handled automatically in our upgrade tool but for reference an exhaustive list can be found below.

Package name changes

A number of packages have been renamed to use the @itwin scope rather than the @bentley scope, and we have modified a few package names to move towards a more consistent naming pattern. The full list of changed packages are listed in the table below.

Current New
@bentley/imodeljs-backend @itwin/core-backend
@bentley/imodeljs-common @itwin/core-common
@bentley/imodeljs-frontend @itwin/core-frontend
@bentley/geometry-core @itwin/core-geometry
@bentley/ecschema-metadata @itwin/ecschema-metadata
@bentley/ecschema-locaters @itwin/ecschema-locaters
@bentley/ecschema-editing @itwin/ecschema-editing
@bentley/bentleyjs-core @itwin/core-bentley
@bentley/orbitgt-core @itwin/core-orbitgt
@bentley/frontend-devtools @itwin/frontend-devtools
@bentley/webgl-compatibility @itwin/webgl-compatibility
@bentley/imodeljs-transformer @itwin/core-transformer
@bentley/imodeljs-markup @itwin/core-markup
@bentley/imodeljs-editor-common @itwin/editor-common
@bentley/imodeljs-editor-backend @itwin/editor-backend
@bentley/imodeljs-editor-frontend @itwin/editor-frontend
@bentley/analytical-backend @itwin/analytical-backend
@bentley/linear-referencing-backend @itwin/linear-referencing-backend
@bentley/linear-referencing-common @itwin/linear-referencing-common
@bentley/physical-material-backend @itwin/physical-material-backend
@bentley/presentation-backend @itwin/presentation-backend
@bentley/presentation-common @itwin/presentation-common
@bentley/presentation-frontend @itwin/presentation-frontend
@bentley/presentation-components @itwin/presentation-components
@bentley/presentation-testing @itwin/presentation-testing
@bentley/ui-abstract @itwin/appui-abstract
@bentley/ui-components @itwin/components-react
@bentley/ui-core @itwin/core-react
@bentley/ui-imodel-components @itwin/imodel-components-react
@bentley/ui-ninezone @itwin/appui-layout-react
@bentley/ui-framework @itwin/appui-react
@bentley/ecschema2ts @itwin/ecschema2ts
@bentley/webpack-tools-core @itwin/core-webpack-tools
@bentley/backend-webpack-tools @itwin/backend-webpack-tools
@bentley/build-tools @itwin/build-tools
@bentley/eslint-plugin @itwin/eslint-plugin
@bentley/imodeljs-quantity @itwin/core-quantity
@bentley/imodeljs-i18n @itwin/core-i18n
@bentley/hypermodeling-frontend @itwin/hypermodeling-frontend
@bentley/electron-manager @itwin/core-electron
@bentley/mobile-manager @itwin/core-mobile
@bentley/express-server @itwin/express-server
@bentley/ecschema-rpcinterface-common @itwin/ecschema-rpcinterface-common
@bentley/ecschema-rpcinterface-impl @itwin/ecschema-rpcinterface-impl
@bentley/ecschema-rpcinterface-tests @itwin/ecschema-rpcinterface-tests
@bentley/certa @itwin/certa
@bentley/perf-tools @itwin/perf-tools
@bentley/oidc-signin-tool @itwin/oidc-signin-tool
@bentley/geonames-extension @itwin/geonames-extension
@bentley/map-layers @itwin/map-layers
@bentley/rpcinterface-full-stack-tests @itwin/rpcinterface-full-stack-tests
@bentley/imodelhub-client-tests @itwin/imodelhub-client-tests

@itwin/core-backend

Removed Replacement
AutoPush eliminated
BriefcaseDb.reinstateChanges BriefcaseDb.pullChanges
BriefcaseDb.reverseChanges BriefcaseDb.pullChanges
BriefcaseIdValue BriefcaseIdValue in @itwin/core-common
BriefcaseManager.getCompatibilityFileName eliminated
BriefcaseManager.getCompatibilityPath eliminated
BriefcaseManager.isStandaloneBriefcaseId use id === BriefcaseIdValue.Unassigned
compatibilityDir argument of BriefcaseManager.initialize eliminated
DocumentCarrier eliminated
IModelDb.clearSqliteStatementCache IModelDb.clearCaches
IModelDb.clearStatementCache IModelDb.clearCaches
IModelHost.iModelClient IModelHubBackend.iModelClient
IModelHostConfiguration.briefcaseCacheDir IModelHostConfiguration.cacheDir
InformationCarrierElement eliminated
Platform.isDesktop ProcessDetector.isElectronAppBackend
Platform.isElectron ProcessDetector.isElectronAppBackend
Platform.isMobile ProcessDetector.isMobileAppBackend
Platform.isNodeJs ProcessDetector.isNodeProcess
SnapshotDb.filePath SnapshotDb.pathName
StandaloneDb.filePath StandaloneDb.pathName
Texture.width, height, flags eliminated
TxnAction TxnAction in @itwin/core-common
TxnChangedEntities.inserted, deleted, updated TxnChangedEntities.inserts, deletes, updates
NativeAppAuthorizationBackend Moved to @iTwin/auth-clients repo as ElectronAuthorizationBackend
ElectronAuthorizationEvents Moved to @iTwin/auth-clients repo
ElectronAuthorizationRequestHandler Moved to @iTwin/auth-clients repo

@itwin/core-common

Removed Replacement
AnalysisStyle.scalar AnalysisStyle.thematic
AnalysisStyleScalar AnalysisStyleThematic
AnalysisStyleScalarProps AnalysisStyleThematicProps
BriefcaseTypes.DeprecatedStandalone BriefcaseTypes.Unassigned
BriefcaseTypes.Standalone BriefcaseTypes.Unassigned
Code.getValue Code.value
CodeSpec.specScopeType CodeSpec.scopeType
DisplayStyleSettings.excludedElements DisplayStyleSettings.excludedElementIds
DisplayStyleOverridesOptions.includeProjectSpecific DisplayStyleOverridesOptions.includeITwinSpecific
IModel.changeSetId IModel.changeset.id
IModelVersion.evaluateChangeSet IModelHost/IModelApp hubAccess.getChangesetFromVersion
IModelVersion.fromJson IModelVersion.fromJSON
IModelVersion.getChangeSetFromNamedVersion IModelHost/IModelApp hubAccess.getChangesetFromNamedVersion
IModelVersion.getLatestChangeSetId IModelHost/IModelApp hubAccess.hubAccess.getLatestChangeset
IModelWriteRpcInterface Use IPC for writing to iModels
LatAndLong eliminated
LatLongAndHeight CartographicProps
TerrainSettings.locatable BackgroundMapSettings.locatable
TerrainSettingsProps.nonLocatable BackgroundMapProps.nonLocatable
ViewFlagOverrides class ViewFlagOverrides type
ViewFlagProps.edgeMask eliminated
ViewFlagProps.hlMatColors eliminated
ViewFlags.clone ViewFlags.copy
ViewFlags.edgeMask eliminated
ViewFlags.hLineMaterialColors eliminated
ViewFlags.noCameraLights ViewFlags.lighting
ViewFlags.noGeometryMap eliminated
ViewFlags.noSolarLight ViewFlags.lighting
ViewFlags.noSourceLights ViewFlags.lighting
NativeAppAuthorizationConfiguration MobileAppAuthorizationConfiguration in @itwin/core-mobile

@itwin/core-frontend

Removed Replacement
AppearanceOverrideProps AppearanceOverrideProps
AsyncMethodsOf AsyncMethodsOf
AsyncFunction AsyncFunction
EmphasizeElementsProps EmphasizeElementsProps
PromiseReturnType PromiseReturnType
CheckpointConnection.open CheckpointConnection.openRemote
DecorateContext.screenViewport DecorateContext.viewport
FeatureOverrideType FeatureOverrideType
FeatureSymbology.Appearance FeatureAppearance
FeatureSymbology.AppearanceProps FeatureAppearanceProps
findAvailableRealityModels getRealityDatas in @itwin/reality-data-client
findAvailableUnattachedRealityModels getRealityDatas in @itwin/reality-data-client
IModelApp.iModelClient IModelApp.hubAccess
IModelApp.settings IModelApp.userPreferences
IModelConnection.Models.loaded use for..of to iterate and getLoaded to look up by Id
IModelConnection.Views.saveThumbnail use IPC and IModelDb.saveThumbnail
IOidcFrontendClient eliminated
isIOidcFrontendClient eliminated
OidcBrowserClient BrowserAuthorizationClient in @itwin/browser-authorization
OidcFrontendClientConfiguration BrowserAuthorizationClientConfiguration in @itwin/browser-authorization
QuantityFormatter.onActiveUnitSystemChanged QuantityFormatter.onActiveFormattingUnitSystemChanged
QuantityFormatter.useImperialFormats QuantityFormatter.setActiveUnitSystem
RemoteBriefcaseConnection CheckpointConnection
ScreenViewport.decorationDiv DecorateContext.addHtmlDecoration
UnitSystemKey Moved to @bentley/imodeljs-quantity
ViewManager.forEachViewport Use a for..of loop
ViewState.isCameraEnabled Use view.is3d() && view.isCameraOn
ViewState3d.lookAtPerspectiveOrOrtho ViewState3d.LookAt
ViewState3d.lookAtUsingLensAngle ViewState3d.lookAt
Viewport.featureOverrideProvider Viewport.featureOverrideProviders
Viewport.setFlashed Viewport.flashedId
Viewport.setRedrawPending Viewport.requestRedraw
WebAppViewer eliminated
NativeAppAuthorization Moved to @iTwin/auth-clients repo as ElectronRendererAuthorization

@itwin/core-geometry

Removed Replacement
BSplineCurve3dBase.createThroughPoints BSplineCurve3dBase.createFromInterpolationCurve3dOptions
TransitionSpiralProps.curveLength TransitionSpiralProps.length
TransitionSpiralProps.fractionInterval TransitionSpiralProps.activeFractionInterval
TransitionSpiralProps.intervalFractions TransitionSpiralProps.activeFractionInterval
InterpolationCurve3dOptions.isChordLenTangent InterpolationCurve3dOptions.isChordLenTangents
Point3dArray.createRange Range3d.createFromVariantData

@bentley/backend-itwin-client

SAML support has officially been dropped as a supported workflow. All related APIs for SAML have been removed.

Removed Replacement
OidcDelegationClientConfiguration DelegationAuthorizationClientConfiguration
OidcDelegationClient DelegationAuthorizationClient
BackendAuthorizationClient Moved to @iTwin/auth-clients as BrowserAuthorizationClient
AgentAuthorizationClient Moved to @iTwin/auth-clients as SerivceAuthorizationClient
DelegationAuthorizationClient removed
IntrospectionClient Moved to @iTwin/auth-clients
ImsAuthorizationClient removed

@itwin/appui-abstract

Removed Replacement
ContentLayoutProps.priority eliminated
UiItemsArbiter eliminated
UiAbstract.messagePresenter UiAdmin.messagePresenter

@itwin/core-react

Removed Replacement
LoadingPromptProps.isDeterministic LoadingPromptProps.isDeterminate in @itwin/core-react
NumericInput component NumberInput component in @itwin/core-react
TabsProps.onClickLabel TabsProps.onActivateTab in @itwin/core-react
LocalSettingsStorage LocalStateStorage
UiSettingsResult UiStateStorageResult
UiSetting UiStateEntry
UiSettings UiStateStorage

@itwin/components-react

Removed Replacement
hasFlag hasSelectionModeFlag in @itwin/components-react
StandardEditorNames StandardEditorNames in @itwin/appui-abstract
StandardTypeConverterTypeNames StandardTypeNames in @itwin/appui-abstract
StandardTypeNames StandardTypeNames in @itwin/appui-abstract
Timeline TimelineComponent in @itwin/components-react
ControlledTreeProps.treeEvents ControlledTreeProps.eventsHandler
ControlledTreeProps.visibleNodes ControlledTreeProps.model
MutableTreeModel.computeVisibleNodes computeVisibleNodes in @itwin/components-react
TreeModelSource.getVisibleNodes memoized result of computeVisibleNodes
useVisibleTreeNodes useTreeModel and computeVisibleNodes
TreeRendererContext eliminated
TreeRendererContextProvider eliminated
TreeRendererContextConsumer eliminated
useTreeRendererContext eliminated
ExtendedTreeNodeRendererProps TreeNodeRendererProps
SignIn eliminated
All drag & drop related APIs Third party components. E.g. see this example
DEPRECATED_Tree, BeInspireTree and related APIs ControlledTree
PropertyValueRendererContext.decoratedTextElement IPropertyValueRenderer that can properly render a PropertyRecord
CommonPropertyGridProps.onPropertyLinkClick PropertyRecord.links.onClick
onPropertyLinkClick prop in usePropertyData PropertyRecord.links.onClick
onPropertyLinkClick prop in usePropertyGridModelSource PropertyRecord.links.onClick
FilteringInputProps.filteringInProgress FilteringInputProps.status
hasLinks !!PropertyRecord.links?.length
PropertyListProps.onListWidthChanged Width is now passed to PropertyList through PropertyListProps.width prop

@itwin/appui-react

Removed Replacement
COLOR_THEME_DEFAULT SYSTEM_PREFERRED_COLOR_THEME in @bentley/ui-framework is used as default color theme
FunctionKey FunctionKey in @bentley/ui-abstract
IModelAppUiSettings UserSettingsStorage in @bentley/ui-framework
ConfigurableUiManager.findFrontstageDef FrontstageManager.findFrontstageDef
ConfigurableUiManager.loadContentGroup eliminated
ConfigurableUiManager.loadContentGroups eliminated
ConfigurableUiManager.loadContentLayout eliminated
ConfigurableUiManager.loadContentLayouts eliminated
ContentGroupManager eliminated
Frontstage.initializeFrontstageDef FrontstageManager.getFrontstageDef (async method)
Frontstage.findFrontstageDef FrontstageManager.getFrontstageDef (async method)
Frontstage.initializeFromProvider Frontstage.create (async method)
FrontstageProps.defaultLayout ContentGroup now holds the layout information.
FrontstageProvider.initializeDef eliminated
FrontstageProvider.frontstageDef FrontstageManager.getFrontstageDef (async method)
reactElement in ContentControl ContentControl.reactNode
reactElement in NavigationAidControl NavigationAidControl.reactNode
reactElement in NavigationWidgetDef NavigationWidgetDef.reactNode
reactElement in ToolWidgetDef ToolWidgetDef.reactNode
reactElement in WidgetControl WidgetControl.reactNode
reactElement in WidgetDef WidgetDef.reactNode
ReactMessage ReactMessage in @itwin/core-react
SavedView ViewStateHelper
SavedViewProps ViewStateHelperProps
SavedViewLayout StageContentLayout
SavedViewLayoutProps StageContentLayoutProps
SpecialKey SpecialKey in @itwin/appui-abstract
WidgetState WidgetState in @itwin/appui-abstract
UserProfileBackstageItem eliminated
SignIn eliminated
SignOutModalFrontstage eliminated
IModelConnectedCategoryTree eliminated
IModelConnectedModelsTree eliminated
IModelConnectedSpatialContainmentTree eliminated
CategoryTreeWithSearchBox eliminated
UiSettingsProvider UiStateStorageHandler
useUiSettingsStorageContext useUiStateStorageHandler
VisibilityComponent TreeWidgetComponent in @bentley/tree-widget-react
VisibilityWidget TreeWidgetControl in @bentley/tree-widget-react
WidgetProvider Provide widget via UiItemsProvider
ContentLayoutProps ContentLayoutProps in @itwin/appui-abstract
All drag & drop related APIs Third party components. E.g. see this example
ModelsTreeProps.enablePreloading eliminated

@itwin/core-bentley

Removed Replacement
Config Use process.env to access environment variables directly
EnvMacroSubst eliminated

@itwin/presentation-common

Removed Replacement
CompressedDescriptorJSON DescriptorJSON
ContentInstancesOfSpecificClassesSpecification.arePolymorphic ContentInstancesOfSpecificClassesSpecification.handleInstancesPolymorphically
ContentModifiersList.propertiesDisplay ContentModifiersList.propertyOverrides
ContentModifiersList.propertyEditors ContentModifiersList.propertyOverrides
ContentRelatedInstancesSpecification.isRecursive eliminated
ContentRelatedInstancesSpecification.relatedClasses ContentRelatedInstancesSpecification.relationshipPaths.targetClass
ContentRelatedInstancesSpecification.relationships ContentRelatedInstancesSpecification.relationshipPaths.relationship
ContentRelatedInstancesSpecification.requiredDirection ContentRelatedInstancesSpecification.relationshipPaths.direction
ContentRelatedInstancesSpecification.skipRelatedLevel eliminated
Descriptor.toCompressedJSON Descriptor.toJSON
DescriptorOverrides.hiddenFieldNames DescriptorOverrides.fieldsSelector
DescriptorOverrides.sortDirection DescriptorOverrides.sorting.direction
DescriptorOverrides.sortingFieldName DescriptorOverrides.sorting.field
ECPropertyGroupingNodeKey.groupingValue ECPropertyGroupingNodeKey.groupingValues
ExtendedContentRequestOptions ContentRequestOptions
ExtendedContentRpcRequestOptions ContentRpcRequestOptions
ExtendedHierarchyRequestOptions HierarchyRequestOptions
ExtendedHierarchyRpcRequestOptions HierarchyRpcRequestOptions
Field.fromJSON Field.fromCompressedJSON
HierarchyCompareRpcOptions eliminated
LabelRequestOptions DisplayLabelRequestOptions
LabelRpcRequestOptions DisplayLabelRpcRequestOptions
LoggingNamespaces PresentationBackendLoggerCategory, PresentationBackendNativeLoggerCategory, PresentationFrontendLoggerCategory or PresentationComponentsLoggerCategory
NodeDeletionInfo.target NodeDeletionInfo.parent and NodeDeletionInfo.position
NodeDeletionInfoJSON.target NodeDeletionInfoJSON.parent and NodeDeletionInfoJSON.position
PresentationDataCompareOptions eliminated
PresentationRpcInterface.compareHierarchies eliminated
PresentationRpcInterface.compareHierarchiesPaged eliminated
PresentationRpcInterface.getContent PresentationRpcInterface.getPagedContent and getPagedContentSet
PresentationRpcInterface.getContentAndSize PresentationRpcInterface.getPagedContent and getPagedContentSet
PresentationRpcInterface.getDisplayLabelDefinitions PresentationRpcInterface.getPagedDisplayLabelDefinitions
PresentationRpcInterface.getDistinctValues PresentationRpcInterface.getPagedDistinctValues
PresentationRpcInterface.getNodes PresentationRpcInterface.getPagedNodes
PresentationRpcInterface.getNodesAndCount PresentationRpcInterface.getPagedNodes
PresentationRpcInterface.loadHierarchy eliminated
PresentationUnitSystem UnitSystemKey in @bentley/imodeljs-quantity
PropertiesFieldDescriptor.propertyClass PropertiesFieldDescriptor.properties.class
PropertiesFieldDescriptor.propertyName PropertiesFieldDescriptor.properties.name
Property.relatedClassPath NestedContentField.pathToPrimaryClass
PropertyJSON.relatedClassPath NestedContentFieldJSON.pathToPrimaryClass
RelatedInstanceNodesSpecification.relatedClasses RelatedInstanceNodesSpecification.relationshipPaths.targetClass
RelatedInstanceNodesSpecification.relationships RelatedInstanceNodesSpecification.relationshipPaths.relationship
RelatedInstanceNodesSpecification.requiredDirection RelatedInstanceNodesSpecification.relationshipPaths.direction
RelatedInstanceNodesSpecification.skipRelatedLevel eliminated
RelatedInstanceNodesSpecification.supportedSchemas eliminated
RelatedInstanceSpecification.class RelatedInstanceSpecification.relationshipPath.targetClass
RelatedInstanceSpecification.relationship RelatedInstanceSpecification.relationshipPath.relationship
RelatedInstanceSpecification.requiredDirection RelatedInstanceSpecification.relationshipPath.direction
RelatedPropertiesSpecification.isPolymorphic RelatedPropertiesSpecification.handleTargetClassPolymorphically
RelatedPropertiesSpecification.propertyNames RelatedPropertiesSpecification.properties
RelatedPropertiesSpecification.relatedClasses RelatedPropertiesSpecification.propertiesSource.targetClass
RelatedPropertiesSpecification.relationships RelatedPropertiesSpecification.propertiesSource.relationship
RelatedPropertiesSpecification.requiredDirection RelatedPropertiesSpecification.propertiesSource.direction
Ruleset.supportedSchemas Ruleset.requiredSchemas
RequestPriority eliminated
RequestOptions<TIModel>.priority eliminated
SelectClassInfo.pathToPrimaryClass SelectClassInfo.pathFromInputToSelectClass
SelectClassInfo.relatedInstanceClasses SelectClassInfo.relatedInstancePaths
SelectClassInfoJSON.pathToPrimaryClass SelectClassInfoJSON.pathFromInputToSelectClass
SelectClassInfoJSON.relatedInstanceClasses SelectClassInfoJSON.relatedInstancePaths

@itwin/presentation-backend

Removed Replacement
DuplicateRulesetHandlingStrategy RulesetInsertOptions
PresentationManager.activeUnitSystem Changed type from PresentationUnitSystem to UnitSystemKey
PresentationManager.getContentAndSize PresentationManager.getContent and getContentSetSize
PresentationManager.getDistinctValues PresentationManager.getPagedDistinctValues
PresentationManager.getNodesAndCount PresentationManager.getNodes and getNodesCount
PresentationManager.loadHierarchy eliminated
PresentationManagerProps.activeLocale PresentationManagerProps.defaultLocale
PresentationManagerProps.activeUnitSystem Renamed to PresentationManagerProps.defaultUnitSystem and changed type from PresentationUnitSystem to UnitSystemKey
PresentationManagerProps.cacheConfig PresentationManagerProps.caching.hierarchies
PresentationManagerProps.contentCacheSize PresentationManagerProps.caching.content.size
PresentationManagerProps.taskAllocationsMap PresentationManagerProps.workerThreadsCount
UnitSystemFormat.unitSystems Changed type from PresentationUnitSystem[] to UnitSystemKey[]
WithClientRequestContext<T> eliminated

@itwin/presentation-frontend

Removed Replacement
FavoritePropertiesScope.Project FavoritePropertiesScope.ITwin
PresentationManager.activeUnitSystem Changed type from PresentationUnitSystem to UnitSystemKey
PresentationManager.compareHierarchies eliminated
PresentationManager.getDistinctValues PresentationManager.getPagedDistinctValues
PresentationManager.loadHierarchy eliminated
PresentationManagerProps.activeUnitSystem Changed type from PresentationUnitSystem to UnitSystemKey

@itwin/presentation-components

Removed Replacement
ContentDataProvider.configureContentDescriptor ContentDataProvider.getDescriptorOverrides
ContentDataProvider.isFieldHidden ContentDataProvider.getDescriptorOverrides
ContentDataProvider.shouldConfigureContentDescriptor eliminated
ContentDataProvider.shouldExcludeFromDescriptor ContentDataProvider.getDescriptorOverrides
ControlledTreeFilteringProps ControlledPresentationTreeFilteringProps
DEPRECATED_controlledTreeWithFilteringSupport eliminated
DEPRECATED_controlledTreeWithVisibleNodes eliminated
DEPRECATED_treeWithFilteringSupport useControlledPresentationTreeFiltering
DEPRECATED_treeWithUnifiedSelection useUnifiedSelectionTreeEventHandler
FilteredPresentationTreeDataProvider.loadHierarchy eliminated
IPresentationTreeDataProvider.loadHierarchy eliminated
PresentationTreeDataProvider.loadHierarchy eliminated
PresentationTreeNodeLoaderProps.preloadingEnabled eliminated
propertyGridWithUnifiedSelection usePropertyDataProviderWithUnifiedSelection
PropertyGridWithUnifiedSelectionProps PropertyDataProviderWithUnifiedSelectionProps
TreeWithFilteringSupportProps ControlledPresentationTreeFilteringProps
TreeWithUnifiedSelectionProps UnifiedSelectionTreeEventHandlerParams
useControlledTreeFiltering useControlledPresentationTreeFiltering
Removed Replacement
IDiagnostic IDiagnostic in @itwin/ecschema-editing
BaseDiagnostic BaseDiagnostic in @itwin/ecschema-editing
DiagnosticType DiagnosticType in @itwin/ecschema-editing
DiagnosticCategory DiagnosticCategory in @itwin/ecschema-editing
DiagnosticCodes DiagnosticCodes in @itwin/ecschema-editing
Diagnostics Diagnostics in @itwin/ecschema-editing
IDiagnosticReporter IDiagnosticReporter in @itwin/ecschema-editing
SuppressionDiagnosticReporter SuppressionDiagnosticReporter in @itwin/ecschema-editing
FormatDiagnosticReporter FormatDiagnosticReporter in @itwin/ecschema-editing
LoggingDiagnosticReporter LoggingDiagnosticReporter in @itwin/ecschema-editing
IRuleSet IRuleSet in @itwin/ecschema-editing
ECRuleSet ECRuleSet in @itwin/ecschema-editing
ISuppressionRule ISuppressionRule in @itwin/ecschema-editing
BaseSuppressionRule BaseSuppressionRule in @itwin/ecschema-editing
IRuleSuppressionMap IRuleSuppressionMap in @itwin/ecschema-editing
BaseRuleSuppressionMap BaseRuleSuppressionMap in @itwin/ecschema-editing
IRuleSuppressionSet IRuleSuppressionSet in @itwin/ecschema-editing
SchemaCompareCodes SchemaCompareCodes in @itwin/ecschema-editing
SchemaCompareDiagnostics SchemaCompareDiagnostics in @itwin/ecschema-editing
SchemaValidater SchemaValidater in @itwin/ecschema-editing
SchemaValidationVisitor SchemaValidationVisitor in @itwin/ecschema-editing
RelationshipConstraint.deserialize RelationshipConstraint.fromJSON
RelationshipConstraint.deserializeSync RelationshipConstraint.fromJSONSync
RelationshipConstraint.toJson RelationshipConstraint.toJSON

@bentley/itwin-client

Removed Replacement
UserInfo eliminated
AuthorizationClient.isAuthorized eliminated

@bentley/frontend-authorization-client

Removed Replacement
FrontendAuthorizationClient removed
FrontendAuthorizationClientLoggerCategory removed
BrowserAuthorizationCallbackHandler Moved to iTwin/auth-clients
BrowserAuthorizationBase removed
BrowserAuthorizationClient Moved to iTwin/auth-clients
BrowserAuthorizationClientRedirectState Moved to iTwin/auth-clients
BrowserAuthorizationLogger Moved to iTwin/auth-clients

Last Updated: 12 February, 2024