Skip to content

Commit

Permalink
presentation/default units (#657)
Browse files Browse the repository at this point in the history
* Add default-units functionality and testing

* change and API

* PR Fixes

* PR fixes

* renaming

* PR fix

* style fix

* PR fixes

* NextVersion and minor fixes

* PR fixes

* minor fix

* PR fixes

* minor fix
  • Loading branch information
aurislt7 authored Feb 5, 2021
1 parent 83e76fd commit 4801756
Show file tree
Hide file tree
Showing 12 changed files with 1,404 additions and 1,186 deletions.
5 changes: 5 additions & 0 deletions common/api/presentation-backend.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { DistinctValuesRequestOptions } from '@bentley/presentation-common';
import { EventSink } from '@bentley/imodeljs-backend';
import { ExtendedContentRequestOptions } from '@bentley/presentation-common';
import { ExtendedHierarchyRequestOptions } from '@bentley/presentation-common';
import { FormatProps } from '@bentley/imodeljs-quantity';
import { HierarchyRequestOptions } from '@bentley/presentation-common';
import { Id64String } from '@bentley/bentleyjs-core';
import { IDisposable } from '@bentley/bentleyjs-core';
Expand Down Expand Up @@ -254,6 +255,10 @@ export interface PresentationManagerProps {
cacheConfig?: HierarchyCacheConfig;
// @alpha (undocumented)
contentCacheSize?: number;
// @alpha
defaultFormats?: {
[phenomenon: string]: UnitSystemFormat;
};
enableSchemasPreload?: boolean;
// @internal (undocumented)
eventSink?: EventSink;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"changes": [
{
"packageName": "@bentley/presentation-backend",
"comment": "Added a way to set default property formatting",
"type": "none"
}
],
"packageName": "@bentley/presentation-backend",
"email": "30312645+aurislt7@users.noreply.github.com"
}
2 changes: 1 addition & 1 deletion common/config/rush/browser-approved-packages.json
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@
},
{
"name": "@bentley/imodeljs-quantity",
"allowedCategories": [ "common", "extensions", "frontend", "integration-testing", "internal" ]
"allowedCategories": [ "backend", "common", "extensions", "frontend", "integration-testing", "internal" ]
},
{
"name": "@bentley/itwin-client",
Expand Down
21 changes: 21 additions & 0 deletions docs/changehistory/NextVersion.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,24 @@ In order to support partial updates and clearing an existing value, the update e
The new behavior is documented as part of the method documentation here:

[IModelDb.Elements.updateElement]($backend)

## Presentation

### Setting up default formats

A new feature was introduced, which allows supplying default unit formats to use for formatting properties that don't have a presentation unit for requested unit system. The formats are set when initializing [Presentation]($presentation-backend) and passing [PresentationManagerProps.defaultFormats]($presentation-backend).
Example:

```ts
Presentation.initialize({
defaultFormats: {
length: {
unitSystems: [PresentationUnitSystem.BritishImperial],
format: MY_DEFAULT_FORMAT_FOR_LENGTHS_IN_BRITISH_IMPERIAL_UNITS,
},
area: {
unitSystems: [PresentationUnitSystem.UsCustomary, PresentationUnitSystem.UsSurvey],
format: MY_DEFAULT_FORMAT_FOR_AREAS_IN_US_UNITS,
},
},
});
2 changes: 1 addition & 1 deletion full-stack-tests/presentation/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -90,4 +90,4 @@
],
"extends": "plugin:@bentley/imodeljs-recommended"
}
}
}
32 changes: 32 additions & 0 deletions full-stack-tests/presentation/src/Utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/

import { Field } from "@bentley/presentation-common";

/** Returns field by given label.
* @internal
*/
export function findFieldByLabel(fields: Field[], label: string, allFields?: Field[]): Field | undefined {
const isTopLevel = (undefined === allFields);
if (!allFields)
allFields = new Array<Field>();
for (const field of fields) {
if (field.label === label)
return field;

if (field.isNestedContentField()) {
const nestedMatchingField = findFieldByLabel(field.nestedFields, label, allFields);
if (nestedMatchingField)
return nestedMatchingField;
}

allFields.push(field);
}
if (isTopLevel) {
// eslint-disable-next-line no-console
console.error(`Field '${label}' not found. Available fields: [${allFields.map((f) => `"${f.label}"`).join(", ")}]`);
}
return undefined;
}
110 changes: 110 additions & 0 deletions full-stack-tests/presentation/src/backend/PresentationManager.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
import { expect } from "chai";
import { ClientRequestContext, Guid } from "@bentley/bentleyjs-core";
import { IModelDb, SnapshotDb } from "@bentley/imodeljs-backend";
import { PresentationManager } from "@bentley/presentation-backend";
import { UnitSystemFormat } from "@bentley/presentation-backend/lib/presentation-backend/PresentationManager";
import {
ContentSpecificationTypes, DisplayValue, DisplayValuesArray, DisplayValuesMap, KeySet, PresentationUnitSystem, Ruleset, RuleTypes,
} from "@bentley/presentation-common";
import { initialize, terminate } from "../IntegrationTests";
import { findFieldByLabel } from "../Utils";

describe("PresentationManager", () => {

let imodel: IModelDb;
before(async () => {
await initialize();
imodel = SnapshotDb.openFile("assets/datasets/Properties_60InstancesWithUrl2.ibim");
expect(imodel).is.not.null;
});

after(async () => {
imodel.close();
await terminate();
});

describe("Property value formatting", () => {

const ruleset: Ruleset = {
id: Guid.createValue(),
rules: [{
ruleType: RuleTypes.Content,
specifications: [{ specType: ContentSpecificationTypes.SelectedNodeInstances }],
}],
};
const keys = KeySet.fromJSON({ instanceKeys: [["Generic:PhysicalObject", ["0x74"]]], nodeKeys: [] });

it("formats property with default kind of quantity format when it doesn't have format for requested unit system", async () => {
expect(await getAreaDisplayValue(PresentationUnitSystem.BritishImperial)).to.eq("150.1235 cm²");

});

it("formats property using default format when it doesn't have format for requested unit system", async () => {
const formatProps = {
composite: {
includeZero: true,
spacer: " ",
units: [
{ label: "ft²", name: "SQ_FT" },
],
},
formatTraits: "KeepSingleZero|KeepDecimalPoint|ShowUnitLabel",
precision: 4,
type: "Decimal",
uomSeparator: "",
};

const defaultFormats = {
area: { unitSystems: [PresentationUnitSystem.BritishImperial], format: formatProps },
};

expect(await getAreaDisplayValue(PresentationUnitSystem.BritishImperial, defaultFormats)).to.eq("0.1616 ft²");
});

it("formats property using provided format when it has provided format and default format for requested unit system", async () => {
const formatProps = {
composite: {
includeZero: true,
spacer: " ",
units: [
{ label: "ft²", name: "SQ_FT" },
],
},
formatTraits: "KeepSingleZero|KeepDecimalPoint|ShowUnitLabel",
precision: 4,
type: "Decimal",
uomSeparator: "",
};

const defaultFormats = {
area: { unitSystems: [PresentationUnitSystem.Metric], format: formatProps },
};

expect(await getAreaDisplayValue(PresentationUnitSystem.Metric, defaultFormats)).to.eq("150.1235 cm²");
});

async function getAreaDisplayValue(unitSystem: PresentationUnitSystem, defaultFormats?: { [phenomenon: string]: UnitSystemFormat }): Promise<DisplayValue> {
const manager: PresentationManager = new PresentationManager({ defaultFormats });
const descriptor = await manager.getContentDescriptor({
imodel,
rulesetOrId: ruleset,
keys,
displayType: "Grid",
requestContext: new ClientRequestContext(),
unitSystem,
});
expect(descriptor).to.not.be.undefined;
const field = findFieldByLabel(descriptor!.fields, "cm2")!;
expect(field).not.to.be.undefined;
const content = await manager.getContent({ imodel, rulesetOrId: ruleset, keys, descriptor: descriptor!, requestContext: new ClientRequestContext(), unitSystem });
const displayValues = content!.contentSet[0].displayValues.rc_generic_PhysicalObject_ncc_MyProp_areaElementAspect as DisplayValuesArray;
expect(displayValues.length).is.eq(1);
return ((displayValues[0] as DisplayValuesMap).displayValues as DisplayValuesMap)[field.name]!;
}
});

});
24 changes: 1 addition & 23 deletions full-stack-tests/presentation/src/frontend/Content.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
} from "@bentley/presentation-common";
import { Presentation } from "@bentley/presentation-frontend";
import { initialize, terminate } from "../IntegrationTests";
import { findFieldByLabel } from "../Utils";

import sinon = require("sinon");

Expand Down Expand Up @@ -574,26 +575,3 @@ class ECClassHierarchy {
};
}
}

function findFieldByLabel(fields: Field[], label: string, allFields?: Field[]): Field | undefined {
const isTopLevel = (undefined === allFields);
if (!allFields)
allFields = new Array<Field>();
for (const field of fields) {
if (field.label === label)
return field;

if (field.isNestedContentField()) {
const nestedMatchingField = findFieldByLabel(field.nestedFields, label, allFields);
if (nestedMatchingField)
return nestedMatchingField;
}

allFields.push(field);
}
if (isTopLevel) {
// eslint-disable-next-line no-console
console.error(`Field '${label}' not found. Available fields: [${allFields.map((f) => `"${f.label}"`).join(", ")}]`);
}
return undefined;
}
4 changes: 3 additions & 1 deletion presentation/backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"@bentley/bentleyjs-core": "^2.12.0-dev.16",
"@bentley/imodeljs-backend": "^2.12.0-dev.16",
"@bentley/imodeljs-common": "^2.12.0-dev.16",
"@bentley/imodeljs-quantity": "^2.12.0-dev.16",
"@bentley/presentation-common": "^2.12.0-dev.16"
},
"devDependencies": {
Expand All @@ -48,6 +49,7 @@
"@bentley/eslint-plugin": "2.12.0-dev.16",
"@bentley/imodeljs-backend": "2.12.0-dev.16",
"@bentley/imodeljs-common": "2.12.0-dev.16",
"@bentley/imodeljs-quantity": "2.12.0-dev.16",
"@bentley/presentation-common": "2.12.0-dev.16",
"@types/chai": "^4.1.4",
"@types/chai-as-promised": "^7",
Expand Down Expand Up @@ -96,4 +98,4 @@
],
"extends": "plugin:@bentley/imodeljs-recommended"
}
}
}
Loading

0 comments on commit 4801756

Please sign in to comment.