@itwin/presentation-components
Version:
React components based on iTwin.js Presentation library
161 lines • 6.98 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 InstancesFilter
*/
import { useMemo } from "react";
import { PropertyValueFormat, StandardTypeNames } from "@itwin/appui-abstract";
import { defaultPropertyFilterBuilderRuleValidator, isUnaryPropertyFilterBuilderOperator, PropertyFilterBuilderRuleRangeValue, } from "@itwin/components-react";
import { combineFieldNames } from "@itwin/presentation-common";
import { createFieldInfo, createPropertyDescriptionFromFieldInfo } from "../common/ContentBuilder.js";
import { translate } from "../common/Utils.js";
/** @internal */
export function createInstanceFilterPropertyInfos(descriptor) {
const propertyInfos = new Array();
for (const field of descriptor.fields) {
propertyInfos.push(...createPropertyInfos(field));
}
return propertyInfos;
}
/** @internal */
export function getInstanceFilterFieldName(property) {
const [_, fieldName] = property.name.split(INSTANCE_FILTER_FIELD_SEPARATOR);
return fieldName;
}
/** @internal */
export const DEFAULT_ROOT_CATEGORY_NAME = "/selected-item/";
function getPropertySourceClassInfos(field) {
if (field.parent) {
return getPropertySourceClassInfos(field.parent);
}
if (field.isPropertiesField()) {
return field.properties.map((fieldProperty) => fieldProperty.property.classInfo);
}
return [field.pathToPrimaryClass[field.pathToPrimaryClass.length - 1].targetClassInfo];
}
function getPropertyClassInfo(field) {
if (field.parent && field.parent.isNestedContentField()) {
return field.parent.contentClassInfo;
}
return field.properties[0].property.classInfo;
}
function createPropertyInfos(field) {
if (field.isNestedContentField()) {
return field.nestedFields.flatMap((nestedField) => createPropertyInfos(nestedField));
}
if (field.isPropertiesField()) {
return [createPropertyInfoFromPropertiesField(field)];
}
/* c8 ignore next 3 */
return [];
}
function getCategoryInfo(category, categoryInfo) {
if (category.name === DEFAULT_ROOT_CATEGORY_NAME) {
return categoryInfo;
}
const newInfo = {
name: categoryInfo.name ? `${category.name}/${categoryInfo.name}` : `${category.name}`,
label: categoryInfo.label ? `${category.label} | ${categoryInfo.label}` : `${category.label}`,
};
return category.parent ? getCategoryInfo(category.parent, newInfo) : newInfo;
}
function getParentNames(field, name) {
if (!field.parent) {
return combineFieldNames(name, field.name);
}
return getParentNames(field.parent, combineFieldNames(name, field.name));
}
/** @internal */
export function createPropertyInfoFromPropertiesField(field) {
const categoryInfo = getCategoryInfo(field.category, { name: undefined, label: undefined });
const name = field.parent ? getParentNames(field.parent, field.name) : field.name;
const propertyDescription = createPropertyDescriptionFromFieldInfo({
...createFieldInfo(field),
name: getCategorizedFieldName(name, categoryInfo.name),
});
const sourceClassIds = getPropertySourceClassInfos(field).map((classInfo) => classInfo.id);
return {
field,
sourceClassIds,
sourceClassId: sourceClassIds[0],
propertyDescription,
categoryLabel: categoryInfo.label,
className: getPropertyClassInfo(field).name,
};
}
/** @internal */
export function isFilterNonEmpty(rootGroup) {
return rootGroup.items.length > 1 || (rootGroup.items.length === 1 && rootGroup.items[0].operator !== undefined);
}
/** @internal */
export const INSTANCE_FILTER_FIELD_SEPARATOR = "#";
function getCategorizedFieldName(fieldName, categoryName) {
return `${categoryName ?? ""}${INSTANCE_FILTER_FIELD_SEPARATOR}${fieldName}`;
}
/** @internal */
export function useFilterBuilderNavigationPropertyEditorContextProviderProps(imodel, descriptor) {
return useMemo(() => ({
imodel,
getNavigationPropertyInfo: async (property) => {
const field = descriptor.getFieldByName(getInstanceFilterFieldName(property));
if (!field || !field.isPropertiesField()) {
return undefined;
}
return field.properties[0].property.navigationPropertyInfo;
},
}), [imodel, descriptor]);
}
/** @internal */
export function filterRuleValidator(item) {
// skip empty rules and rules that do not require value
if (item.property === undefined || item.operator === undefined || isUnaryPropertyFilterBuilderOperator(item.operator)) {
return undefined;
}
/* c8 ignore next 3 */
if (item.value !== undefined && item.value.valueFormat !== PropertyValueFormat.Primitive) {
return undefined;
}
const error = numericPropertyValidator({
property: item.property,
operator: item.operator,
value: item.value,
});
if (error) {
return error;
}
// TODO: refactor to `useDefaultPropertyFilterBuilderRuleValidator` after AppUI peer dep bumped to 5.0
// eslint-disable-next-line @typescript-eslint/no-deprecated
return defaultPropertyFilterBuilderRuleValidator(item);
}
function numericPropertyValidator({ property, value, operator }) {
// If equality operator is set the value should not be validated since it is supplied by the `UniquePropertyValuesSelector`.
if (!isPropertyNumeric(property.typename) || value === undefined || isEqualityOperator(operator)) {
return undefined;
}
function getErrorMessage() {
// eslint-disable-next-line @typescript-eslint/no-deprecated
return property.kindOfQuantityName === undefined && property.quantityType === undefined
? translate("instance-filter-builder.error-messages.not-a-number")
: translate("instance-filter-builder.error-messages.invalid");
}
if (operator === "between") {
const { from, to } = PropertyFilterBuilderRuleRangeValue.parse(value);
return isInvalidNumericValue(from) || isInvalidNumericValue(to) ? getErrorMessage() : undefined;
}
if (isInvalidNumericValue(value)) {
return getErrorMessage();
}
return undefined;
}
function isEqualityOperator(operator) {
return operator === "is-equal" || operator === "is-not-equal";
}
function isPropertyNumeric(typename) {
return (typename === StandardTypeNames.Number || typename === StandardTypeNames.Int || typename === StandardTypeNames.Float || typename === StandardTypeNames.Double);
}
function isInvalidNumericValue(value) {
return value.displayValue && isNaN(Number(value.value));
}
//# sourceMappingURL=Utils.js.map