From 1a71c8f317756fe67997a628374317b5ac76e061 Mon Sep 17 00:00:00 2001 From: Satbir Singh Date: Tue, 31 Mar 2020 03:21:35 +0000 Subject: [PATCH] Default option value multi select --- .../propertyControls/OptionControl.tsx | 1 - app/client/src/constants/WidgetValidation.ts | 4 +- app/client/src/sagas/WidgetOperationSagas.tsx | 1 + app/client/src/utils/AppsmithUtils.tsx | 1 - app/client/src/utils/DynamicBindingUtils.ts | 2 + app/client/src/utils/ValidationFactory.ts | 20 +++- app/client/src/widgets/DropdownWidget.tsx | 97 ++++++++++++++++--- 7 files changed, 107 insertions(+), 19 deletions(-) diff --git a/app/client/src/components/propertyControls/OptionControl.tsx b/app/client/src/components/propertyControls/OptionControl.tsx index db35c9d42d..2676a2a116 100644 --- a/app/client/src/components/propertyControls/OptionControl.tsx +++ b/app/client/src/components/propertyControls/OptionControl.tsx @@ -79,7 +79,6 @@ class OptionControl extends BaseControl< } render() { const { renderOptions } = this.state; - debugger; return ( {renderOptions.map((option, index) => { diff --git a/app/client/src/constants/WidgetValidation.ts b/app/client/src/constants/WidgetValidation.ts index 5f3dc32055..513e018ae6 100644 --- a/app/client/src/constants/WidgetValidation.ts +++ b/app/client/src/constants/WidgetValidation.ts @@ -1,3 +1,5 @@ +import { WidgetProps } from "widgets/BaseWidget"; + // Always add a validator function in ./Validators for these types export const VALIDATION_TYPES = { TEXT: "TEXT", @@ -18,4 +20,4 @@ export type ValidationResponse = { }; export type ValidationType = typeof VALIDATION_TYPES[keyof typeof VALIDATION_TYPES]; -export type Validator = (value: any) => ValidationResponse; +export type Validator = (value: any, props?: WidgetProps) => ValidationResponse; diff --git a/app/client/src/sagas/WidgetOperationSagas.tsx b/app/client/src/sagas/WidgetOperationSagas.tsx index 21814a42e3..dff53c77cd 100644 --- a/app/client/src/sagas/WidgetOperationSagas.tsx +++ b/app/client/src/sagas/WidgetOperationSagas.tsx @@ -332,6 +332,7 @@ function* setWidgetDynamicPropertySaga( widget.type, propertyName, propertyValue, + widget, ); yield put(updateWidgetProperty(widgetId, propertyName, parsed)); } diff --git a/app/client/src/utils/AppsmithUtils.tsx b/app/client/src/utils/AppsmithUtils.tsx index 12c3b600bf..34baa6209b 100644 --- a/app/client/src/utils/AppsmithUtils.tsx +++ b/app/client/src/utils/AppsmithUtils.tsx @@ -11,7 +11,6 @@ import moment from "moment-timezone"; import ValidationRegistry from "./ValidationRegistry"; import * as log from "loglevel"; import { LogLevelDesc } from "loglevel"; -import { AppsmithUIConfigs } from "configs/types"; export const createReducer = ( initialState: any, diff --git a/app/client/src/utils/DynamicBindingUtils.ts b/app/client/src/utils/DynamicBindingUtils.ts index d0ac1cc93c..c53daf5972 100644 --- a/app/client/src/utils/DynamicBindingUtils.ts +++ b/app/client/src/utils/DynamicBindingUtils.ts @@ -197,6 +197,7 @@ export const getValidatedTree = (tree: any) => { entity.type, property, value, + entity, ); parsedEntity[property] = parsed; if (!isValid) { @@ -415,6 +416,7 @@ export function dependencySortedEvaluateDataTree( entity.type, propertyPath, result, + entity, ); result = parsed; if (!isValid) { diff --git a/app/client/src/utils/ValidationFactory.ts b/app/client/src/utils/ValidationFactory.ts index 21911ce730..ab601f4533 100644 --- a/app/client/src/utils/ValidationFactory.ts +++ b/app/client/src/utils/ValidationFactory.ts @@ -6,6 +6,7 @@ import { ValidationType, Validator, } from "constants/WidgetValidation"; +import { WidgetProps } from "widgets/BaseWidget"; export const BASE_WIDGET_VALIDATION = { isLoading: VALIDATION_TYPES.BOOLEAN, @@ -13,7 +14,10 @@ export const BASE_WIDGET_VALIDATION = { isDisabled: VALIDATION_TYPES.BOOLEAN, }; -export type WidgetPropertyValidationType = Record; +export type WidgetPropertyValidationType = Record< + string, + ValidationType | Validator +>; class ValidationFactory { static validationMap: Map = new Map(); @@ -29,14 +33,22 @@ class ValidationFactory { widgetType: WidgetType, property: string, value: any, + //TODO: Satbir: Figure out a way to declare the right type. + props?: WidgetProps, ): ValidationResponse { const propertyValidationTypes = WidgetFactory.getWidgetPropertyValidationMap( widgetType, ); - const validationType = propertyValidationTypes[property]; - const validator = this.validationMap.get(validationType); + const validationTypeOrValidator = propertyValidationTypes[property]; + let validator; + + if (typeof validationTypeOrValidator === "function") { + validator = validationTypeOrValidator; + } else { + validator = this.validationMap.get(validationTypeOrValidator); + } if (validator) { - return validator(value); + return validator(value, props); } else { return { isValid: true, parsed: value }; } diff --git a/app/client/src/widgets/DropdownWidget.tsx b/app/client/src/widgets/DropdownWidget.tsx index 88b87441ee..c6dbfba739 100644 --- a/app/client/src/widgets/DropdownWidget.tsx +++ b/app/client/src/widgets/DropdownWidget.tsx @@ -10,8 +10,10 @@ import { } from "utils/ValidationFactory"; import { VALIDATION_TYPES } from "constants/WidgetValidation"; import { TriggerPropertiesMap } from "utils/WidgetFactory"; +import { VALIDATORS } from "utils/Validators"; class DropdownWidget extends BaseWidget { + defaultValueConsumed = false; static getPropertyValidationMap(): WidgetPropertyValidationType { return { ...BASE_WIDGET_VALIDATION, @@ -21,7 +23,34 @@ class DropdownWidget extends BaseWidget { selectionType: VALIDATION_TYPES.TEXT, selectedIndexArr: VALIDATION_TYPES.ARRAY, isRequired: VALIDATION_TYPES.BOOLEAN, - defaultOptionValue: VALIDATION_TYPES.TEXT, + defaultOptionValue: (value: string | string[], props?: WidgetProps) => { + let values = value; + + if (props) { + if (props.selectionType === "SINGLE_SELECT") { + return VALIDATORS[VALIDATION_TYPES.TEXT](value); + } else if (props.selectionType === "MULTI_SELECT") { + if (typeof value === "string") { + try { + values = JSON.parse(value); + if (!Array.isArray(values)) { + throw new Error(); + } + } catch { + values = value.split(","); + if (values.length > 0) { + values = values.map(value => value.trim()); + } + } + } + } + } + + return { + isValid: true, + parsed: values, + }; + }, }; } static getDerivedPropertiesMap() { @@ -51,10 +80,32 @@ class DropdownWidget extends BaseWidget { componentDidMount() { super.componentDidMount(); if (this.props.defaultOptionValue) { - const selectedIndex = _.findIndex(this.props.options, option => { - return option.value === this.props.defaultOptionValue; - }); - this.updateWidgetMetaProperty("selectedIndex", selectedIndex); + const selectionOptions: number[] = []; + if (this.props.selectionType === "SINGLE_SELECT") { + const selectedIndex = _.findIndex(this.props.options, option => { + return ( + option.value.toString() === + (this.props.defaultOptionValue as string).toString() + ); + }); + if (selectedIndex > -1) { + selectionOptions.push(selectedIndex); + } + } else { + (this.props.defaultOptionValue as string[]).forEach(optionValue => { + const selectedIndex = _.findIndex(this.props.options, option => { + return option.value.toString() === optionValue.toString(); + }); + if (selectedIndex > -1) { + selectionOptions.push(selectedIndex); + } + }); + } + + if (selectionOptions.length > 0) { + this.updateWidgetMetaProperty("selectedIndex", selectionOptions[0]); + this.updateWidgetMetaProperty("selectedIndexArr", selectionOptions[0]); + } } } @@ -65,20 +116,42 @@ class DropdownWidget extends BaseWidget { ) { this.updateWidgetMetaProperty("selectedIndex", undefined); this.updateWidgetMetaProperty("selectedIndexArr", []); + this.defaultValueConsumed = false; } - if (this.props.defaultOptionValue) { + if (this.props.defaultOptionValue && !this.defaultValueConsumed) { if ( (this.props.selectedIndex !== prevProps.selectedIndex && this.props.selectedIndex === undefined) || this.props.defaultOptionValue !== prevProps.defaultOptionValue ) { - const selectedIndex = _.findIndex(this.props.options, option => { - return option.value === this.props.defaultOptionValue; - }); - if (selectedIndex > -1) { - this.updateWidgetMetaProperty("selectedIndex", selectedIndex); + this.defaultValueConsumed = true; + const selectionOptions: number[] = []; + if (this.props.selectionType === "SINGLE_SELECT") { + const selectedIndex = _.findIndex(this.props.options, option => { + return ( + option.value.toString() === + (this.props.defaultOptionValue as string).toString() + ); + }); + if (selectedIndex > -1) { + selectionOptions.push(selectedIndex); + } + } else { + (this.props.defaultOptionValue as string[]).forEach(optionValue => { + const selectedIndex = _.findIndex(this.props.options, option => { + return option.value.toString() === optionValue.toString(); + }); + if (selectedIndex > -1) { + selectionOptions.push(selectedIndex); + } + }); + } + if (selectionOptions.length > 0) { + this.updateWidgetMetaProperty("selectedIndexArr", selectionOptions); + this.updateWidgetMetaProperty("selectedIndex", selectionOptions[0]); } else { this.updateWidgetMetaProperty("selectedIndex", undefined); + this.updateWidgetMetaProperty("selectedIndexArr", []); } } } @@ -177,7 +250,7 @@ export interface DropdownWidgetProps extends WidgetProps { selectionType: SelectionType; options?: DropdownOption[]; onOptionChange?: string; - defaultOptionValue?: string; + defaultOptionValue?: string | string[]; isRequired: boolean; }