diff --git a/src/types/BaseComponent.ts b/src/types/BaseComponent.ts index 4b976a44..926e988a 100644 --- a/src/types/BaseComponent.ts +++ b/src/types/BaseComponent.ts @@ -16,6 +16,7 @@ export type SimpleConditional = { export type BaseComponent = { input: boolean; + component?: BaseComponent type: string; key: string; path?: string; diff --git a/src/types/PassedComponentInstance.ts b/src/types/PassedComponentInstance.ts index e0f9e5d1..abd4a4dd 100644 --- a/src/types/PassedComponentInstance.ts +++ b/src/types/PassedComponentInstance.ts @@ -16,6 +16,7 @@ export type PassedComponentInstance = { form: Form; options: Record; }; + parent?: Component; evaluate: (expression: string, additionalContext?: Record) => any; interpolate: (text: string, additionalContext?: Record) => string; shouldSkipValidation: (data?: DataObject, row?: DataObject) => boolean; diff --git a/src/utils/conditions.ts b/src/utils/conditions.ts index d1d4cd78..93aab0be 100644 --- a/src/utils/conditions.ts +++ b/src/utils/conditions.ts @@ -3,6 +3,8 @@ import { EvaluatorFn, evaluate, JSONLogicEvaluator } from 'modules/jsonlogic'; import { flattenComponents, getComponent, getComponentActualValue } from './formUtil'; import { has, isObject, map, every, some, find, filter, isBoolean, split } from 'lodash'; import ConditionOperators from './operators'; +import _ from 'lodash'; +import { checkComponentType } from './utils'; export const isJSONConditional = (conditional: any): conditional is JSONConditional => { return conditional && conditional.json && isObject(conditional.json); @@ -117,6 +119,45 @@ function isConditionPotentiallyBasedOnValuePath(condition: any = {}) { ); } +function getConditionalPathsRecursive(conditionPaths: string[], data: any): any { + let currentGlobalIndex = 0; + const conditionalPathsArray: string[] = []; + const getConditionalPaths = (data: any, currentPath = '', localIndex = 0) => { + currentPath = currentPath.replace(/^\.+|\.+$/g, ''); + const currentLocalIndex = localIndex; + const currentData = _.get(data, currentPath); + if (Array.isArray(currentData) && currentData.filter(Boolean).length > 0) { + if (currentData.some(element => typeof element !== 'object')) { + return; + } + const hasInnerDataArray = currentData.find(x => Array.isArray(x[conditionPaths[currentLocalIndex]])); + if (hasInnerDataArray) { + currentData.forEach((_, indexOutside) => { + const innerCompDataPath = `${currentPath}[${indexOutside}].${conditionPaths[currentLocalIndex]}`; + getConditionalPaths(data, innerCompDataPath, currentLocalIndex + 1); + }); + } + else { + currentData.forEach((x, index) => { + if (!_.isNil(x[conditionPaths[currentLocalIndex]])) { + const compDataPath = `${currentPath}[${index}].${conditionPaths[currentLocalIndex]}`; + conditionalPathsArray.push(compDataPath); + } + }); + } + } + else { + if (!conditionPaths[currentGlobalIndex]) { + return; + } + currentGlobalIndex = currentGlobalIndex + 1; + getConditionalPaths(data, `${currentPath}.${conditionPaths[currentGlobalIndex - 1]}`, currentGlobalIndex); + } + }; + getConditionalPaths(data); + return conditionalPathsArray; +} + /** * Checks the simple conditionals. * @param conditional @@ -181,22 +222,35 @@ export function checkSimpleConditional( } } - const value = conditionComponent - ? getComponentActualValue(conditionComponent, conditionComponentPath, data, row) - : null; - - const ConditionOperator = ConditionOperators[operator]; - return ConditionOperator - ? new ConditionOperator().getResult({ - value, - comparedValue, - instance, - component, - conditionComponent, - conditionComponentPath, - data, - }) - : true; + const splittedConditionPath = conditionComponentPath.split('.'); + const isParentGrid = (component?.parent?.type || instance?.parent?.type) === 'datagrid' || (component?.parent?.type || instance?.parent?.type) === 'editgrid' + const conditionalPaths = isParentGrid ? [] : getConditionalPathsRecursive(splittedConditionPath, data); + + if (checkComponentType(conditionComponent, "checkbox")) { + if (typeof comparedValue === 'string') { + comparedValue = comparedValue === 'true' + } + } + if (checkComponentType(conditionComponent, "select")) { + conditionComponent = conditionComponent?.component || conditionComponent; + } + if (conditionalPaths.length > 0) { + return conditionalPaths.map((path: string) => { + const value = getComponentActualValue(conditionComponent, path, data, row); + + const ConditionOperator = ConditionOperators[operator]; + return ConditionOperator + ? new ConditionOperator().getResult({ value, comparedValue, instance, component, conditionComponentPath }) + : true; + }); + } + else { + const value = getComponentActualValue(conditionComponent, conditionComponentPath, data, row); + const СonditionOperator = ConditionOperators[operator]; + return СonditionOperator + ? new СonditionOperator().getResult({ value, comparedValue, instance, component, conditionComponentPath, conditionComponent }) + : true; + } }), (res) => res !== null, ); @@ -204,10 +258,11 @@ export function checkSimpleConditional( let result = false; switch (conjunction) { case 'any': - result = some(conditionsResult, (res) => !!res); + result = some(conditionsResult.flat(), (res) => !!res); break; default: - result = every(conditionsResult, (res) => !!res); + result = every(conditionsResult.flat(), (res) => !!res); } return show ? result : !result; } + diff --git a/src/utils/formUtil/index.ts b/src/utils/formUtil/index.ts index a15ae3bc..df68b288 100644 --- a/src/utils/formUtil/index.ts +++ b/src/utils/formUtil/index.ts @@ -46,6 +46,7 @@ import { eachComponent } from './eachComponent'; import { eachComponentData } from './eachComponentData'; import { eachComponentAsync } from './eachComponentAsync'; import { eachComponentDataAsync } from './eachComponentDataAsync'; +import { checkComponentType } from 'utils/utils'; /** * Flatten the form components for data manipulation. @@ -290,8 +291,8 @@ export function getContextualRowData(component: Component, path: string, data: a } export function componentInfo(component: any) { - const hasColumns = component.columns && Array.isArray(component.columns); - const hasRows = component.rows && Array.isArray(component.rows); + const hasColumns = component.columns && Array.isArray(component.columns)&& component?.component?.type !=="datagrid"; + const hasRows = component.rows && Array.isArray(component.rows) const hasComps = component.components && Array.isArray(component.components); const isContent = getModelType(component) === 'content'; const isLayout = getModelType(component) === 'none'; @@ -323,7 +324,7 @@ export function getComponentData(components: Component[], data: DataObject, path } export function getComponentActualValue( - component: Component, + component: Component | undefined, compPath: string, data: any, row: any, @@ -341,6 +342,9 @@ export function getComponentActualValue( let parent = component; let rowPath = ''; + const compPathModified = compPath.split("."); + rowPath = (compPathModified.length > 1)? compPathModified[compPathModified.length-1]: compPath; + while (parent?.parent?.path && !parentInputComponent) { parent = parent.parent; if (parent.input) { @@ -357,6 +361,13 @@ export function getComponentActualValue( let value = null; if (data) { value = get(data, compPath); + if(checkComponentType(component, "address")) { + const addressIgnoreProperties = ['mode', 'address']; + const result = Object.values(omit(value, addressIgnoreProperties)).some(Boolean); + if(!result) { + value = '' + } + } } if (rowPath && row && isNil(value)) { value = get(row, rowPath); diff --git a/src/utils/operators/IsEqualTo.js b/src/utils/operators/IsEqualTo.js index c7ad34e9..ed1ed7b8 100644 --- a/src/utils/operators/IsEqualTo.js +++ b/src/utils/operators/IsEqualTo.js @@ -36,7 +36,7 @@ export default class IsEqualTo extends ConditionOperator { if ( conditionComponent && isSelectResourceWithObjectValue(conditionComponent) && - conditionComponent.template + conditionComponent?.template ) { return compareSelectResourceWithObjectTypeValues(value, comparedValue, conditionComponent); } diff --git a/src/utils/utils.ts b/src/utils/utils.ts index b78ad80a..8d2506a1 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -126,3 +126,7 @@ export function resetEphemeralState(component: Component) { delete component.ephemeralState; } } + +export function checkComponentType(component: Component | undefined, type:string) { + return component?.type === type; +}