diff --git a/app/client/src/components/editorComponents/form/fields/DynamicTextField.tsx b/app/client/src/components/editorComponents/form/fields/DynamicTextField.tsx index 0b766a2fd6..5ce1d19f2f 100644 --- a/app/client/src/components/editorComponents/form/fields/DynamicTextField.tsx +++ b/app/client/src/components/editorComponents/form/fields/DynamicTextField.tsx @@ -22,6 +22,7 @@ class DynamicTextField extends React.Component< border?: CodeEditorBorder; showLightningMenu?: boolean; height?: string; + disabled?: boolean; } > { render() { diff --git a/app/client/src/components/formControls/BaseControl.tsx b/app/client/src/components/formControls/BaseControl.tsx index 8bfac2babc..6d19ffa6a9 100644 --- a/app/client/src/components/formControls/BaseControl.tsx +++ b/app/client/src/components/formControls/BaseControl.tsx @@ -72,6 +72,7 @@ export interface ControlData { propertyName?: string; identifier?: string; sectionName?: string; + disabled?: boolean; } export type FormConfig = Omit & { configProperty?: string; diff --git a/app/client/src/components/formControls/DropDownControl.tsx b/app/client/src/components/formControls/DropDownControl.tsx index e8a24d0612..0f55dab2e8 100644 --- a/app/client/src/components/formControls/DropDownControl.tsx +++ b/app/client/src/components/formControls/DropDownControl.tsx @@ -6,11 +6,14 @@ import { ControlType } from "constants/PropertyControlConstants"; import _ from "lodash"; import { Field, + getFormValues, WrappedFieldInputProps, WrappedFieldMetaProps, } from "redux-form"; import { connect } from "react-redux"; import { AppState } from "reducers"; +import { QUERY_EDITOR_FORM_NAME } from "constants/forms"; +import { QueryAction } from "entities/Action"; const DropdownSelect = styled.div` font-size: 14px; @@ -49,6 +52,7 @@ function renderDropdown(props: { fetchOptionsCondtionally: boolean; formName: string; dropDownOptions: DropdownOption[]; + disabled?: boolean; }): JSX.Element { let selectedValue = props.input?.value; if (_.isUndefined(props.input?.value)) { @@ -61,6 +65,7 @@ function renderDropdown(props: { return ( { { label: "Test1", value: "SINGLE" }, { label: "Test2", value: "ALL" }, ]; + const dynamicFormDataString = _.get( + getFormValues(QUERY_EDITOR_FORM_NAME)(state) as QueryAction, + "actionConfiguration.formData.updateMany.query", + ); + + // ownProps.configProperty will be used to filter from the array of data + // const dynamicFormDataString = getFormEvaluationState(state); + + try { + dropDownOptions = JSON.parse(dynamicFormDataString); + } catch (e) { + dropDownOptions = []; + } } else { dropDownOptions = ownProps.options; } diff --git a/app/client/src/components/formControls/DynamicInputTextControl.tsx b/app/client/src/components/formControls/DynamicInputTextControl.tsx index ca8a7f464a..4be46afbbd 100644 --- a/app/client/src/components/formControls/DynamicInputTextControl.tsx +++ b/app/client/src/components/formControls/DynamicInputTextControl.tsx @@ -43,6 +43,7 @@ export function InputText(props: { actionName: string; inputType?: INPUT_TEXT_INPUT_TYPES; customStyles?: any; + disabled?: boolean; }) { const { actionName, inputType, name, placeholder } = props; const dataTreePath = actionPathFromName(actionName, name); @@ -70,6 +71,7 @@ export function InputText(props: {
{ actionName, configProperty, customStyles, + disabled, inputType, label, placeholderText, @@ -100,6 +103,7 @@ class DynamicInputTextControl extends BaseControl { void; }; @@ -110,6 +111,7 @@ function RenderFilePicker(props: RenderFilePickerProps) { { setIsOpen(true); }} @@ -145,8 +147,14 @@ class FilePickerControl extends BaseControl { } render() { - const { configProperty } = this.props; - return ; + const { configProperty, disabled } = this.props; + return ( + + ); } getControlType(): ControlType { diff --git a/app/client/src/components/formControls/FixedKeyInputControl.tsx b/app/client/src/components/formControls/FixedKeyInputControl.tsx index bacb47ffe3..efb3405b14 100644 --- a/app/client/src/components/formControls/FixedKeyInputControl.tsx +++ b/app/client/src/components/formControls/FixedKeyInputControl.tsx @@ -11,11 +11,18 @@ const Wrapper = styled.div` class FixKeyInputControl extends BaseControl { render() { - const { configProperty, dataType, fixedKey, placeholderText } = this.props; + const { + configProperty, + dataType, + disabled, + fixedKey, + placeholderText, + } = this.props; return ( { // Get the value property if (value) { diff --git a/app/client/src/components/formControls/SwitchControl.tsx b/app/client/src/components/formControls/SwitchControl.tsx index 94e8316d03..fdfadc43f9 100644 --- a/app/client/src/components/formControls/SwitchControl.tsx +++ b/app/client/src/components/formControls/SwitchControl.tsx @@ -9,6 +9,7 @@ type SwitchFieldProps = WrappedFieldProps & { label: string; isRequired: boolean; info: string; + disabled: boolean; }; const StyledToggle = styled(Toggle)` @@ -52,6 +53,7 @@ export class SwitchField extends React.Component { { this.props.input.onChange(value); @@ -66,11 +68,12 @@ export class SwitchField extends React.Component { class SwitchControl extends BaseControl { render() { - const { configProperty, info, isRequired, label } = this.props; + const { configProperty, disabled, info, isRequired, label } = this.props; return ( ; + formEvaluationState: FormEvalOutput; }; export type EditorJSONtoFormProps = QueryFormProps & ReduxProps; @@ -591,38 +595,65 @@ export function EditorJSONtoForm(props: Props) { } }; - // Function to check if the section config is allowed to render (Only for UQI forms) - const checkIfSectionCanRender = (section: any) => { - // By default, allow the section to render. This is to allow for the case where no conditional is provided. - // The evaluation state disallows the section to render if the condition is not met. (Checkout formEval.ts) - let allowToRender = true; + const extractConditionalOutput = (section: any): ConditionalOutput => { + let conditionalOutput: ConditionalOutput = {}; if ( section.hasOwnProperty("propertyName") && props.formEvaluationState.hasOwnProperty(section.propertyName) ) { - allowToRender = props?.formEvaluationState[section.propertyName].visible; + conditionalOutput = props?.formEvaluationState[section.propertyName]; } else if ( section.hasOwnProperty("configProperty") && props.formEvaluationState.hasOwnProperty(section.configProperty) ) { - allowToRender = - props?.formEvaluationState[section.configProperty].visible; + conditionalOutput = props?.formEvaluationState[section.configProperty]; } else if ( section.hasOwnProperty("identifier") && !!section.identifier && props.formEvaluationState.hasOwnProperty(section.identifier) ) { - allowToRender = props?.formEvaluationState[section.identifier].visible; + conditionalOutput = props?.formEvaluationState[section.identifier]; + } + return conditionalOutput; + }; + + // Function to check if the section config is allowed to render (Only for UQI forms) + const checkIfSectionCanRender = (conditionalOutput: ConditionalOutput) => { + // By default, allow the section to render. This is to allow for the case where no conditional is provided. + // The evaluation state disallows the section to render if the condition is not met. (Checkout formEval.ts) + let allowToRender = true; + if ( + conditionalOutput.hasOwnProperty("visible") && + typeof conditionalOutput.visible === "boolean" + ) { + allowToRender = conditionalOutput.visible; } return allowToRender; }; + // Function to check if the section config is enabled (Only for UQI forms) + const checkIfSectionIsEnabled = (conditionalOutput: ConditionalOutput) => { + // By default, the section is enabled. This is to allow for the case where no conditional is provided. + // The evaluation state disables the section if the condition is not met. (Checkout formEval.ts) + let enabled = true; + if ( + conditionalOutput.hasOwnProperty("enabled") && + typeof conditionalOutput.enabled === "boolean" + ) { + enabled = conditionalOutput.enabled; + } + return enabled; + }; + // Render function to render the V2 of form editor type (UQI) // Section argument is a nested config object, this function recursively renders the UI based on the config const renderEachConfigV2 = (formName: string, section: any, idx: number) => { + let enabled = true; if (!!section) { // If the component is not allowed to render, return null - if (!checkIfSectionCanRender(section)) return null; + const conditionalOutput = extractConditionalOutput(section); + if (!checkIfSectionCanRender(conditionalOutput)) return null; + enabled = checkIfSectionIsEnabled(conditionalOutput); } if (section.hasOwnProperty("controlType")) { // If component is type section, render it's children @@ -636,9 +667,15 @@ export function EditorJSONtoForm(props: Props) { } try { const { configProperty } = section; + let modifiedSection; + if (!enabled) { + modifiedSection = { ...section, disabled: true }; + } else { + modifiedSection = { ...section }; + } return ( - + ); } catch (e) { diff --git a/app/client/src/reducers/evaluationReducers/formEvaluationReducer.ts b/app/client/src/reducers/evaluationReducers/formEvaluationReducer.ts index 6c170524ef..47bf929cb4 100644 --- a/app/client/src/reducers/evaluationReducers/formEvaluationReducer.ts +++ b/app/client/src/reducers/evaluationReducers/formEvaluationReducer.ts @@ -4,13 +4,13 @@ import { FetchPageRequest } from "api/PageApi"; export type ConditonalObject = Record; -export type FormEvalOutput = Record< - string, - { - visible?: boolean; - conditionals?: ConditonalObject; - } ->; +export type ConditionalOutput = { + visible?: boolean; + enabled?: boolean; + conditionals?: ConditonalObject; +}; + +export type FormEvalOutput = Record; export type FormEvaluationState = Record; diff --git a/app/client/src/workers/formEval.ts b/app/client/src/workers/formEval.ts index cc01a3afdc..34ded6f683 100644 --- a/app/client/src/workers/formEval.ts +++ b/app/client/src/workers/formEval.ts @@ -10,6 +10,8 @@ import { FormConfig } from "components/formControls/BaseControl"; export enum ConditionType { HIDE = "hide", // When set, the component will be shown until condition is true SHOW = "show", // When set, the component will be hidden until condition is true + ENABLE = "enable", // When set, the component will be enabled until condition is true + DISABLE = "disable", // When set, the component will be disabled until condition is true } // Object to hold the initial eval object @@ -18,6 +20,8 @@ let finalEvalObj: FormEvalOutput; // Recursive function to generate the evaluation state for form config const generateInitialEvalState = (formConfig: FormConfig) => { const visible = false; + const enabled = true; + let conditionTypes = {}; // Any element is only added to the eval state if they have a conditional statement present, if not they are allowed to be rendered if ("conditionals" in formConfig && !!formConfig.conditionals) { @@ -32,9 +36,29 @@ const generateInitialEvalState = (formConfig: FormConfig) => { key = formConfig.identifier; } + const allConditionTypes = Object.keys(formConfig.conditionals); + if ( + allConditionTypes.includes(ConditionType.HIDE) || + allConditionTypes.includes(ConditionType.SHOW) + ) { + conditionTypes = { + ...conditionTypes, + visible, + }; + } + + if ( + allConditionTypes.includes(ConditionType.ENABLE) || + allConditionTypes.includes(ConditionType.DISABLE) + ) { + conditionTypes = { + ...conditionTypes, + enabled, + }; + } // Conditionals are stored in the eval state itself for quick access finalEvalObj[key] = { - visible, + ...conditionTypes, conditionals: formConfig.conditionals, }; } @@ -61,6 +85,10 @@ function evaluate( currentEvalState[key].visible = !output; } else if (conditionType === ConditionType.SHOW) { currentEvalState[key].visible = output; + } else if (conditionType === ConditionType.DISABLE) { + currentEvalState[key].enabled = !output; + } else if (conditionType === ConditionType.ENABLE) { + currentEvalState[key].enabled = output; } }); }