Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

presentation/default units #657

Merged
merged 14 commits into from
Feb 5, 2021
Merged
8 changes: 8 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,13 @@ export interface PresentationManagerProps {
cacheConfig?: HierarchyCacheConfig;
// @alpha (undocumented)
contentCacheSize?: number;
// @alpha
defaultFormatsMap?: {
[phenomenon: string]: {
unitSystems: string[];
grigasp marked this conversation as resolved.
Show resolved Hide resolved
format: FormatProps;
};
};
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/imodeljs-backend",
"comment": "Added default units map",
grigasp marked this conversation as resolved.
Show resolved Hide resolved
"type": "none"
}
],
"packageName": "@bentley/imodeljs-backend",
"email": "30312645+aurislt7@users.noreply.github.com"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"changes": [
{
"packageName": "@bentley/presentation-backend",
"comment": "added default units map",
grigasp marked this conversation as resolved.
Show resolved Hide resolved
"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
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/*---------------------------------------------------------------------------------------------
grigasp marked this conversation as resolved.
Show resolved Hide resolved
* 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 { ContentSpecificationTypes, Field, KeySet, PresentationUnitSystem, Ruleset, RuleTypes } from "@bentley/presentation-common";
import { initialize, terminate } from "../IntegrationTests";

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("Calculated Properties", () => {
grigasp marked this conversation as resolved.
Show resolved Hide resolved
const ruleset: Ruleset = {
id: Guid.createValue(),
rules: [{
ruleType: RuleTypes.Content,
specifications: [{ specType: ContentSpecificationTypes.SelectedNodeInstances }],
}],
};

const keys = KeySet.fromJSON({ instanceKeys: [["Generic:PhysicalObject", ["0x74"]]], nodeKeys: [] });
it("creates calculated fields without defaultMap", async () => {
const manager: PresentationManager = new PresentationManager();
const descriptor = await manager.getContentDescriptor({
imodel,
rulesetOrId: ruleset,
keys,
displayType: "Grid",
requestContext: new ClientRequestContext(),
unitSystem: PresentationUnitSystem.BritishImperial,
});
expect(descriptor).to.not.be.undefined;
const field = findFieldByLabel(descriptor!.fields, "cm2")!;
expect(field).not.to.be.undefined;
const allDistinctValues =await manager.getPagedDistinctValues({ imodel, rulesetOrId: ruleset, keys, descriptor: descriptor!, fieldDescriptor: field.getFieldDescriptor(), requestContext: new ClientRequestContext() });
grigasp marked this conversation as resolved.
Show resolved Hide resolved
expect(allDistinctValues.items[0].displayValue).to.eq("150.1235 cm²");
});
it("creates calculated fields with defaultMap", async () => {
grigasp marked this conversation as resolved.
Show resolved Hide resolved
const formatProps = {
composite:
{includeZero:true,
spacer:" ",
units:[{label:"ft²",name:"SQ_FT"}],
},
formatTraits:"KeepSingleZero|KeepDecimalPoint|ShowUnitLabel",
precision:4,
type:"Decimal",
uomSeparator:""};

const map = {
// eslint-disable-next-line @typescript-eslint/naming-convention
AREA: {unitSystems: ["Undefined"], format: formatProps},
};

const manager: PresentationManager = new PresentationManager({defaultFormatsMap: map});
const descriptor = await manager.getContentDescriptor({
imodel,
rulesetOrId: ruleset,
keys,
displayType: "Grid",
requestContext: new ClientRequestContext(),
unitSystem: PresentationUnitSystem.BritishImperial,
});
expect(descriptor).to.not.be.undefined;
const field = findFieldByLabel(descriptor!.fields, "cm2")!;
expect(field).not.to.be.undefined;
const allDistinctValues = await manager.getPagedDistinctValues({ imodel, rulesetOrId: ruleset, keys, descriptor: descriptor!, fieldDescriptor: field.getFieldDescriptor(), requestContext: new ClientRequestContext() });
expect(allDistinctValues.items[0].displayValue).to.eq("0.1616 ft²");
grigasp marked this conversation as resolved.
Show resolved Hide resolved
});

grigasp marked this conversation as resolved.
Show resolved Hide resolved
function findFieldByLabel(fields: Field[], label: string, allFields?: Field[]): Field | undefined {
grigasp marked this conversation as resolved.
Show resolved Hide resolved
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,7 +40,8 @@
"@bentley/bentleyjs-core": "^2.12.0-dev.10",
"@bentley/imodeljs-backend": "^2.12.0-dev.10",
"@bentley/imodeljs-common": "^2.12.0-dev.10",
"@bentley/presentation-common": "^2.12.0-dev.10"
"@bentley/presentation-common": "^2.12.0-dev.10",
"@bentley/imodeljs-quantity": "^2.12.0-dev.10"
grigasp marked this conversation as resolved.
Show resolved Hide resolved
},
"devDependencies": {
"@bentley/bentleyjs-core": "2.12.0-dev.10",
Expand All @@ -49,6 +50,7 @@
"@bentley/imodeljs-backend": "2.12.0-dev.10",
"@bentley/imodeljs-common": "2.12.0-dev.10",
"@bentley/presentation-common": "2.12.0-dev.10",
"@bentley/imodeljs-quantity": "2.12.0-dev.10",
"@types/chai": "^4.1.4",
"@types/chai-as-promised": "^7",
"@types/chai-jest-snapshot": "^1.3.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import { ClientRequestContext, IDisposable } from "@bentley/bentleyjs-core";
import { IModelDb, IModelHost, IModelJsNative } from "@bentley/imodeljs-backend";
import { FormatProps } from "@bentley/imodeljs-quantity";
import {
DiagnosticsScopeLogs, PresentationError, PresentationStatus, UpdateInfoJSON, VariableValueJSON, VariableValueTypes,
} from "@bentley/presentation-common";
Expand Down Expand Up @@ -68,6 +69,12 @@ export interface DefaultNativePlatformProps {
isChangeTrackingEnabled: boolean;
cacheConfig?: IModelJsNative.ECPresentationHierarchyCacheConfig;
contentCacheSize?: number;
defaultFormatsMap?: {
[phenomenon: string]: {
unitSystems: string[];
format: FormatProps;
};
};
}

/** @internal */
Expand All @@ -79,7 +86,8 @@ export const createDefaultNativePlatform = (props: DefaultNativePlatformProps):
public constructor() {
const mode = (props.mode === PresentationManagerMode.ReadOnly) ? IModelJsNative.ECPresentationManagerMode.ReadOnly : IModelJsNative.ECPresentationManagerMode.ReadWrite;
const cacheConfig = props.cacheConfig ?? { mode: HierarchyCacheMode.Disk, directory: "" };
this._nativeAddon = new IModelHost.platform.ECPresentationManager({ ...props, mode, cacheConfig });
const defaultFormatsMap = props.defaultFormatsMap ? this.getSerializedMap(props.defaultFormatsMap) : {};
this._nativeAddon = new IModelHost.platform.ECPresentationManager({ ...props, mode, cacheConfig, defaultFormatsMap});
}
private getStatus(responseStatus: IModelJsNative.ECPresentationStatus): PresentationStatus {
switch (responseStatus) {
Expand All @@ -88,6 +96,20 @@ export const createDefaultNativePlatform = (props: DefaultNativePlatformProps):
default: return PresentationStatus.Error;
}
}
private getSerializedMap(defaultMap: { [phenomenon: string]: { unitSystems: string[], format: FormatProps } }){
grigasp marked this conversation as resolved.
Show resolved Hide resolved
const res: {
[phenomenon: string]: {
unitSystems: string[];
serializedFormat: string;
};
} = {};
Object.keys(defaultMap).forEach((key) => {
const value = defaultMap[key];
res[key] = {unitSystems: value.unitSystems, serializedFormat: JSON.stringify(value.format)};
});

return res;
}
private createSuccessResponse<T>(response: IModelJsNative.ECPresentationManagerResponse<T>): NativePlatformResponse<T> {
const retValue: NativePlatformResponse<T> = { result: response.result! };
if (response.diagnostics)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import * as hash from "object-hash";
import * as path from "path";
import { ClientRequestContext, Id64String, Logger } from "@bentley/bentleyjs-core";
import { BriefcaseDb, EventSink, IModelDb, IModelHost, IModelJsNative } from "@bentley/imodeljs-backend";
import { FormatProps } from "@bentley/imodeljs-quantity";
import {
Content, ContentDescriptorRequestOptions, ContentFlags, ContentRequestOptions, DefaultContentDisplayTypes, Descriptor, DescriptorOverrides,
DisplayLabelRequestOptions, DisplayLabelsRequestOptions, DisplayValueGroup, DistinctValuesRequestOptions, ExtendedContentRequestOptions,
Expand Down Expand Up @@ -246,6 +247,16 @@ export interface PresentationManagerProps {
/** @alpha */
contentCacheSize?: number;

/**
* A map for setting up default formats.
grigasp marked this conversation as resolved.
Show resolved Hide resolved
* @alpha */
defaultFormatsMap?: {
grigasp marked this conversation as resolved.
Show resolved Hide resolved
[phenomenon: string]: {
unitSystems: string[];
format: FormatProps;
};
};

/**
* An identifier which helps separate multiple presentation managers. It's
* mostly useful in tests where multiple presentation managers can co-exist
Expand Down Expand Up @@ -307,6 +318,7 @@ export class PresentationManager {
isChangeTrackingEnabled,
cacheConfig: createCacheConfig(this._props.cacheConfig),
contentCacheSize: this._props.contentCacheSize,
defaultFormatsMap: this._props.defaultFormatsMap,
});
this._nativePlatform = new nativePlatformImpl();
}
Expand Down
6 changes: 6 additions & 0 deletions presentation/backend/src/test/PresentationManager.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ describe("PresentationManager", () => {
isChangeTrackingEnabled: false,
cacheConfig: { mode: HierarchyCacheMode.Disk, directory: "" },
contentCacheSize: undefined,
defaultFormatsMap: {},
});
});
});
Expand Down Expand Up @@ -127,6 +128,7 @@ describe("PresentationManager", () => {
isChangeTrackingEnabled: true,
cacheConfig: expectedCacheConfig,
contentCacheSize: 999,
defaultFormatsMap: {},
});
});
});
Expand All @@ -143,6 +145,7 @@ describe("PresentationManager", () => {
isChangeTrackingEnabled: false,
cacheConfig: { mode: HierarchyCacheMode.Disk, directory: "" },
contentCacheSize: undefined,
defaultFormatsMap: {},
});
});
constructorSpy.resetHistory();
Expand All @@ -161,6 +164,7 @@ describe("PresentationManager", () => {
isChangeTrackingEnabled: false,
cacheConfig: expectedConfig,
contentCacheSize: undefined,
defaultFormatsMap: {},
});
});
});
Expand All @@ -177,6 +181,7 @@ describe("PresentationManager", () => {
isChangeTrackingEnabled: false,
cacheConfig: { mode: HierarchyCacheMode.Hybrid, disk: undefined },
contentCacheSize: undefined,
defaultFormatsMap: {},
});
});
constructorSpy.resetHistory();
Expand All @@ -200,6 +205,7 @@ describe("PresentationManager", () => {
isChangeTrackingEnabled: false,
cacheConfig: expectedConfig,
contentCacheSize: undefined,
defaultFormatsMap: {},
});
});
});
Expand Down