@itwin/presentation-common
Version:
Common pieces for iModel.js presentation packages
263 lines • 12.4 kB
JavaScript
;
/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
/** @packageDocumentation
* @module Content
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.Descriptor = exports.SortDirection = exports.ContentFlags = exports.SelectClassInfo = void 0;
const core_bentley_1 = require("@itwin/core-bentley");
const EC_js_1 = require("../EC.js");
const Utils_js_1 = require("../Utils.js");
const Category_js_1 = require("./Category.js");
const Fields_js_1 = require("./Fields.js");
/** @public */
var SelectClassInfo;
(function (SelectClassInfo) {
/** Deserialize [[SelectClassInfo]] from compressed JSON */
function fromCompressedJSON(json, classesMap) {
(0, core_bentley_1.assert)(classesMap.hasOwnProperty(json.selectClassInfo));
return {
selectClassInfo: { id: json.selectClassInfo, ...classesMap[json.selectClassInfo] },
isSelectPolymorphic: json.isSelectPolymorphic,
...(json.navigationPropertyClasses
? { navigationPropertyClasses: json.navigationPropertyClasses.map((item) => EC_js_1.RelatedClassInfo.fromCompressedJSON(item, classesMap)) }
: undefined),
...(json.relatedInstancePaths
? { relatedInstancePaths: json.relatedInstancePaths.map((rip) => rip.map((item) => EC_js_1.RelatedClassInfo.fromCompressedJSON(item, classesMap))) }
: undefined),
...(json.pathFromInputToSelectClass
? {
pathFromInputToSelectClass: json.pathFromInputToSelectClass.map((item) => EC_js_1.RelatedClassInfoWithOptionalRelationship.fromCompressedJSON(item, classesMap)),
}
: undefined),
...(json.relatedPropertyPaths
? { relatedPropertyPaths: json.relatedPropertyPaths.map((path) => path.map((item) => EC_js_1.RelatedClassInfo.fromCompressedJSON(item, classesMap))) }
: undefined),
};
}
SelectClassInfo.fromCompressedJSON = fromCompressedJSON;
/** Serialize [[SelectClassInfo]] to compressed JSON */
function toCompressedJSON(selectClass, classesMap) {
const { id, ...leftOverClassInfo } = selectClass.selectClassInfo;
classesMap[id] = leftOverClassInfo;
return {
selectClassInfo: id,
isSelectPolymorphic: selectClass.isSelectPolymorphic,
...(selectClass.relatedInstancePaths
? { relatedInstancePaths: selectClass.relatedInstancePaths.map((rip) => rip.map((item) => EC_js_1.RelatedClassInfo.toCompressedJSON(item, classesMap))) }
: undefined),
...(selectClass.navigationPropertyClasses
? {
navigationPropertyClasses: selectClass.navigationPropertyClasses.map((propertyClass) => EC_js_1.RelatedClassInfo.toCompressedJSON(propertyClass, classesMap)),
}
: undefined),
...(selectClass.pathFromInputToSelectClass
? {
pathFromInputToSelectClass: selectClass.pathFromInputToSelectClass.map((item) => EC_js_1.RelatedClassInfoWithOptionalRelationship.toCompressedJSON(item, classesMap)),
}
: undefined),
...(selectClass.relatedPropertyPaths
? {
relatedPropertyPaths: selectClass.relatedPropertyPaths.map((path) => path.map((relatedClass) => EC_js_1.RelatedClassInfo.toCompressedJSON(relatedClass, classesMap))),
}
: undefined),
};
}
SelectClassInfo.toCompressedJSON = toCompressedJSON;
})(SelectClassInfo || (exports.SelectClassInfo = SelectClassInfo = {}));
/**
* Flags that control content format.
* @public
*/
var ContentFlags;
(function (ContentFlags) {
/** Each content record only has [[InstanceKey]] and no data */
ContentFlags[ContentFlags["KeysOnly"] = 1] = "KeysOnly";
/** Each content record additionally has a display label */
ContentFlags[ContentFlags["ShowLabels"] = 4] = "ShowLabels";
/** All content records are merged into a single record (see [Merging values]($docs/presentation/content/terminology#value-merging)) */
ContentFlags[ContentFlags["MergeResults"] = 8] = "MergeResults";
/** Content has only distinct values */
ContentFlags[ContentFlags["DistinctValues"] = 16] = "DistinctValues";
/** Doesn't create property or calculated fields. Can be used in conjunction with [[ShowLabels]]. */
ContentFlags[ContentFlags["NoFields"] = 32] = "NoFields";
/**
* Set related input keys on [[Item]] objects when creating content. This helps identify which [[Item]] is associated to which
* given input key at the cost of performance creating those items.
*/
ContentFlags[ContentFlags["IncludeInputKeys"] = 256] = "IncludeInputKeys";
})(ContentFlags || (exports.ContentFlags = ContentFlags = {}));
/**
* Data sorting direction
* @public
*/
var SortDirection;
(function (SortDirection) {
SortDirection[SortDirection["Ascending"] = 0] = "Ascending";
SortDirection[SortDirection["Descending"] = 1] = "Descending";
})(SortDirection || (exports.SortDirection = SortDirection = {}));
/**
* Data structure that describes content: fields, sorting, filtering, format, etc.
* Descriptor may be changed to control how content is created.
*
* @public
*/
class Descriptor {
/** Id of the connection used to create the descriptor */
connectionId;
/** Hash of the input keys used to create the descriptor */
inputKeysHash;
/** Selection info used to create the descriptor */
selectionInfo;
/** Display type used to create the descriptor */
displayType;
/** A list of classes that will be selected when creating content with this descriptor */
selectClasses;
/** A list of content field categories used in this descriptor */
categories;
/** A list of fields contained in the descriptor */
fields;
/** [[ContentFlags]] used to create the descriptor */
contentFlags;
/**
* A ruleset used to create this descriptor.
* Only set if descriptor is created using a ruleset different from the input ruleset, e.g. when creating a hierarchy level descriptor.
*/
ruleset;
/** Field used to sort the content */
sortingField;
/** Sorting direction */
sortDirection;
/**
* [ECExpression]($docs/presentation/advanced/ECExpressions.md) for filtering content by
* select fields.
*
* This is different from [[instanceFilter]] as filtering is applied on the union of all selects,
* which removes access to content instance property values. Instead of referencing properties
* through `this.PropertyName` alias, the expression should reference them by field names. In cases
* when properties field merges multiple properties, this allows applying the filter on all of them
* at once. This is useful for filtering table rows by column value, when content is displayed in
* table format.
*/
fieldsFilterExpression;
/**
* Instances filter that allows filtering content by class, properties of specific class
* or properties of instances related to the content instance.
*
* This is different from [[fieldsFilterExpression]] as filter is applied at a lower level - on
* specific select class rather than a union of multiple select classes. This means the filter has
* access to properties of that class and they can be referenced using symbols like `this.Property`.
* This is useful for filtering instances of specific class.
*/
instanceFilter;
/** Construct a new Descriptor using a [[DescriptorSource]] */
constructor(source) {
this.connectionId = source.connectionId;
this.inputKeysHash = source.inputKeysHash;
this.selectionInfo = source.selectionInfo;
this.displayType = source.displayType;
this.contentFlags = source.contentFlags;
this.selectClasses = [...source.selectClasses];
this.categories = [...source.categories];
this.fields = [...source.fields];
this.sortingField = source.sortingField;
this.sortDirection = source.sortDirection;
this.fieldsFilterExpression = source.fieldsFilterExpression;
this.instanceFilter = source.instanceFilter;
this.ruleset = source.ruleset;
}
/** Serialize [[Descriptor]] to JSON */
toJSON() {
const classesMap = {};
const selectClasses = this.selectClasses.map((selectClass) => SelectClassInfo.toCompressedJSON(selectClass, classesMap));
const fields = this.fields.map((field) => field.toCompressedJSON(classesMap));
return (0, Utils_js_1.omitUndefined)({
displayType: this.displayType,
contentFlags: this.contentFlags,
categories: this.categories.map(Category_js_1.CategoryDescription.toJSON),
fields,
selectClasses,
classesMap,
connectionId: this.connectionId ?? "",
inputKeysHash: this.inputKeysHash ?? "",
sortingFieldName: this.sortingField?.name,
sortDirection: this.sortDirection,
fieldsFilterExpression: this.fieldsFilterExpression,
instanceFilter: this.instanceFilter,
selectionInfo: this.selectionInfo,
ruleset: this.ruleset,
});
}
/** Deserialize [[Descriptor]] from JSON */
static fromJSON(json) {
if (!json) {
return undefined;
}
const { categories: jsonCategories, selectClasses: jsonSelectClasses, fields: jsonFields, connectionId, inputKeysHash, classesMap, sortingFieldName, ...leftOverJson } = json;
const categories = Category_js_1.CategoryDescription.listFromJSON(jsonCategories);
const selectClasses = jsonSelectClasses.map((jsc) => SelectClassInfo.fromCompressedJSON(jsc, classesMap));
const fields = this.getFieldsFromJSON(jsonFields, (fieldJson) => Fields_js_1.Field.fromCompressedJSON(fieldJson, classesMap, categories));
return new Descriptor({
...leftOverJson,
...(connectionId ? /* c8 ignore next */ { connectionId } : undefined),
...(inputKeysHash ? /* c8 ignore next */ { inputKeysHash } : undefined),
selectClasses,
categories,
fields,
sortingField: (0, Fields_js_1.getFieldByName)(fields, sortingFieldName, true),
});
}
static getFieldsFromJSON(json, factory) {
return json
.map((fieldJson) => {
const field = factory(fieldJson);
if (field) {
field.rebuildParentship();
}
return field;
})
.filter((field) => !!field);
}
/**
* Get field by its name
* @param name Name of the field to find
* @param recurse Recurse into nested fields
*/
getFieldByName(name, recurse) {
return (0, Fields_js_1.getFieldByName)(this.fields, name, recurse);
}
/**
* Get field by its descriptor.
*/
getFieldByDescriptor(fieldDescriptor, recurse) {
return (0, Fields_js_1.getFieldByDescriptor)(this.fields, fieldDescriptor, recurse);
}
/**
* Create descriptor overrides object from this descriptor.
* @public
*/
createDescriptorOverrides() {
const overrides = {};
if (this.displayType) {
overrides.displayType = this.displayType;
}
if (this.contentFlags !== 0) {
overrides.contentFlags = this.contentFlags;
}
if (this.fieldsFilterExpression) {
overrides.fieldsFilterExpression = this.fieldsFilterExpression;
}
if (this.instanceFilter) {
overrides.instanceFilter = this.instanceFilter;
}
if (this.sortingField) {
overrides.sorting = { field: this.sortingField.getFieldDescriptor(), direction: this.sortDirection ?? SortDirection.Ascending };
}
return overrides;
}
}
exports.Descriptor = Descriptor;
//# sourceMappingURL=Descriptor.js.map