feat: Add enable/disable functionality to form components (#10215)
* Added new condition type * Added new variables to cater to enable/disable conditionals * Adding functionality to disable the drop down control * Added ability to enable/disable to dynamic input text fields * Updated input text control to have enabled/disabled feature * Added enable/disable functionality to FixedKeyInputControl * Added enable/disable func to switch control and stanrdasied var name * Added disable functionality for file picker * Added enable/disable functionality to QUER_DYNAMIC_TEXT
This commit is contained in:
parent
92a5cbf7f2
commit
3ab11fa942
|
|
@ -22,6 +22,7 @@ class DynamicTextField extends React.Component<
|
|||
border?: CodeEditorBorder;
|
||||
showLightningMenu?: boolean;
|
||||
height?: string;
|
||||
disabled?: boolean;
|
||||
}
|
||||
> {
|
||||
render() {
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@ export interface ControlData {
|
|||
propertyName?: string;
|
||||
identifier?: string;
|
||||
sectionName?: string;
|
||||
disabled?: boolean;
|
||||
}
|
||||
export type FormConfig = Omit<ControlData, "configProperty"> & {
|
||||
configProperty?: string;
|
||||
|
|
|
|||
|
|
@ -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 (
|
||||
<Dropdown
|
||||
boundary="window"
|
||||
disabled={props.disabled}
|
||||
dontUsePortal={false}
|
||||
dropdownMaxHeight="250px"
|
||||
errorMsg={props.props?.errorText}
|
||||
|
|
@ -83,7 +88,6 @@ export interface DropDownControlProps extends ControlProps {
|
|||
propertyValue: string;
|
||||
subtitle?: string;
|
||||
isMultiSelect?: boolean;
|
||||
isDisabled?: boolean;
|
||||
isSearchable?: boolean;
|
||||
fetchOptionsCondtionally?: boolean;
|
||||
}
|
||||
|
|
@ -97,6 +101,19 @@ const mapStateToProps = (state: AppState, ownProps: DropDownControlProps) => {
|
|||
{ 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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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: {
|
|||
<div style={customStyle}>
|
||||
<StyledDynamicTextField
|
||||
dataTreePath={dataTreePath}
|
||||
disabled={props.disabled}
|
||||
name={name}
|
||||
placeholder={placeholder}
|
||||
showLightningMenu={false}
|
||||
|
|
@ -86,6 +88,7 @@ class DynamicInputTextControl extends BaseControl<DynamicInputControlProps> {
|
|||
actionName,
|
||||
configProperty,
|
||||
customStyles,
|
||||
disabled,
|
||||
inputType,
|
||||
label,
|
||||
placeholderText,
|
||||
|
|
@ -100,6 +103,7 @@ class DynamicInputTextControl extends BaseControl<DynamicInputControlProps> {
|
|||
<InputText
|
||||
actionName={actionName}
|
||||
customStyles={customStyles}
|
||||
disabled={disabled}
|
||||
inputType={inputTypeProp}
|
||||
label={label}
|
||||
name={configProperty}
|
||||
|
|
|
|||
|
|
@ -99,6 +99,7 @@ class DynamicTextControl extends BaseControl<
|
|||
<DynamicTextField
|
||||
className="dynamic-text-field"
|
||||
dataTreePath={dataTreePath}
|
||||
disabled={this.props.disabled}
|
||||
evaluationSubstitutionType={evaluationSubstitutionType}
|
||||
mode={mode}
|
||||
name={this.props.configProperty}
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ const FilePickerWrapper = styled.div`
|
|||
type RenderFilePickerProps = FilePickerControlProps & {
|
||||
input?: WrappedFieldInputProps;
|
||||
meta?: WrappedFieldMetaProps;
|
||||
disabled?: boolean;
|
||||
onChange: (event: any) => void;
|
||||
};
|
||||
|
||||
|
|
@ -110,6 +111,7 @@ function RenderFilePicker(props: RenderFilePickerProps) {
|
|||
<SelectButton
|
||||
buttonStyle="PRIMARY"
|
||||
buttonVariant={ButtonVariantTypes.SECONDARY}
|
||||
disabled={props.disabled}
|
||||
onClick={() => {
|
||||
setIsOpen(true);
|
||||
}}
|
||||
|
|
@ -145,8 +147,14 @@ class FilePickerControl extends BaseControl<FilePickerControlProps> {
|
|||
}
|
||||
|
||||
render() {
|
||||
const { configProperty } = this.props;
|
||||
return <Field component={RenderFilePicker} name={configProperty} />;
|
||||
const { configProperty, disabled } = this.props;
|
||||
return (
|
||||
<Field
|
||||
component={RenderFilePicker}
|
||||
disabled={disabled}
|
||||
name={configProperty}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
getControlType(): ControlType {
|
||||
|
|
|
|||
|
|
@ -11,11 +11,18 @@ const Wrapper = styled.div`
|
|||
|
||||
class FixKeyInputControl extends BaseControl<FixedKeyInputControlProps> {
|
||||
render() {
|
||||
const { configProperty, dataType, fixedKey, placeholderText } = this.props;
|
||||
const {
|
||||
configProperty,
|
||||
dataType,
|
||||
disabled,
|
||||
fixedKey,
|
||||
placeholderText,
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<Wrapper>
|
||||
<TextField
|
||||
disabled={disabled}
|
||||
format={(value) => {
|
||||
// Get the value property
|
||||
if (value) {
|
||||
|
|
|
|||
|
|
@ -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<SwitchFieldProps, any> {
|
|||
<SwitchWrapped data-cy={this.props.input.name}>
|
||||
<StyledToggle
|
||||
className="switch-control"
|
||||
disabled={this.props.disabled}
|
||||
name={this.props.input.name}
|
||||
onToggle={(value: any) => {
|
||||
this.props.input.onChange(value);
|
||||
|
|
@ -66,11 +68,12 @@ export class SwitchField extends React.Component<SwitchFieldProps, any> {
|
|||
|
||||
class SwitchControl extends BaseControl<SwitchControlProps> {
|
||||
render() {
|
||||
const { configProperty, info, isRequired, label } = this.props;
|
||||
const { configProperty, disabled, info, isRequired, label } = this.props;
|
||||
|
||||
return (
|
||||
<Field
|
||||
component={SwitchField}
|
||||
disabled={disabled}
|
||||
info={info}
|
||||
isRequired={isRequired}
|
||||
label={label}
|
||||
|
|
|
|||
|
|
@ -76,6 +76,10 @@ import { DEBUGGER_TAB_KEYS } from "components/editorComponents/Debugger/helpers"
|
|||
import { getErrorAsString } from "sagas/ActionExecution/errorUtils";
|
||||
import { EDITOR_TABS } from "constants/QueryEditorConstants";
|
||||
import Spinner from "components/ads/Spinner";
|
||||
import {
|
||||
ConditionalOutput,
|
||||
FormEvalOutput,
|
||||
} from "reducers/evaluationReducers/formEvaluationReducer";
|
||||
|
||||
const QueryFormContainer = styled.form`
|
||||
flex: 1;
|
||||
|
|
@ -417,7 +421,7 @@ type ReduxProps = {
|
|||
plugin?: Plugin;
|
||||
pluginId: string;
|
||||
documentationLink: string | undefined;
|
||||
formEvaluationState: Record<string, any>;
|
||||
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 (
|
||||
<FieldWrapper key={`${configProperty}_${idx}`}>
|
||||
<FormControl config={section} formName={formName} />
|
||||
<FormControl config={modifiedSection} formName={formName} />
|
||||
</FieldWrapper>
|
||||
);
|
||||
} catch (e) {
|
||||
|
|
|
|||
|
|
@ -4,13 +4,13 @@ import { FetchPageRequest } from "api/PageApi";
|
|||
|
||||
export type ConditonalObject = Record<string, string>;
|
||||
|
||||
export type FormEvalOutput = Record<
|
||||
string,
|
||||
{
|
||||
visible?: boolean;
|
||||
conditionals?: ConditonalObject;
|
||||
}
|
||||
>;
|
||||
export type ConditionalOutput = {
|
||||
visible?: boolean;
|
||||
enabled?: boolean;
|
||||
conditionals?: ConditonalObject;
|
||||
};
|
||||
|
||||
export type FormEvalOutput = Record<string, ConditionalOutput>;
|
||||
|
||||
export type FormEvaluationState = Record<string, FormEvalOutput>;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user