UNPKG

@itwin/presentation-components

Version:

React components based on iTwin.js Presentation library

161 lines 6.98 kB
/*--------------------------------------------------------------------------------------------- * 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