Merge branch 'feature/widget-property-parsing' into 'release'

Validation parse widget property

Closes: #298 
* Added functionality in validators to provide a parsed value to be used by widgets
* Added validation to (almost) all properties of the widgets

See merge request theappsmith/internal-tools-client!160
This commit is contained in:
Hetu Nandu 2019-11-22 13:12:39 +00:00
commit a55ff37ebd
19 changed files with 248 additions and 74 deletions

View File

@ -44,6 +44,7 @@
"jsonpath-plus": "^1.0.0", "jsonpath-plus": "^1.0.0",
"lint-staged": "^9.2.5", "lint-staged": "^9.2.5",
"lodash": "^4.17.11", "lodash": "^4.17.11",
"moment": "^2.24.0",
"moment-timezone": "^0.5.27", "moment-timezone": "^0.5.27",
"monaco-editor": "^0.15.1", "monaco-editor": "^0.15.1",
"monaco-editor-webpack-plugin": "^1.7.0", "monaco-editor-webpack-plugin": "^1.7.0",

View File

@ -36,10 +36,7 @@ class InputTextControl extends BaseControl<InputControlProps> {
} }
onTextChange = (event: React.ChangeEvent<HTMLInputElement>) => { onTextChange = (event: React.ChangeEvent<HTMLInputElement>) => {
let value: string | number = event.target.value; const value: string = event.target.value;
if (this.isNumberType()) {
value = _.toNumber(value);
}
this.updateProperty(this.props.propertyName, value); this.updateProperty(this.props.propertyName, value);
}; };

View File

@ -1,10 +1,18 @@
// Always add a validator function in ./Validators for these types
export const VALIDATION_TYPES = { export const VALIDATION_TYPES = {
TEXT: "TEXT", TEXT: "TEXT",
NUMBER: "NUMBER", NUMBER: "NUMBER",
BOOLEAN: "BOOLEAN", BOOLEAN: "BOOLEAN",
OBJECT: "OBJECT", OBJECT: "OBJECT",
ARRAY: "ARRAY",
TABLE_DATA: "TABLE_DATA", TABLE_DATA: "TABLE_DATA",
DATE: "DATE",
};
export type ValidationResponse = {
isValid: boolean;
parsed: any;
}; };
export type ValidationType = (typeof VALIDATION_TYPES)[keyof typeof VALIDATION_TYPES]; export type ValidationType = (typeof VALIDATION_TYPES)[keyof typeof VALIDATION_TYPES];
export type Validator = (value: any) => boolean; export type Validator = (value: any) => ValidationResponse;

View File

@ -124,5 +124,8 @@ const mapDispatchToProps = (dispatch: any) => ({
}); });
export default withRouter( export default withRouter(
connect(mapStateToProps, mapDispatchToProps)(Applications), connect(
mapStateToProps,
mapDispatchToProps,
)(Applications),
); );

View File

@ -78,7 +78,7 @@ export const getDynamicValue = (
export const enhanceWithDynamicValuesAndValidations = ( export const enhanceWithDynamicValuesAndValidations = (
widget: WidgetProps, widget: WidgetProps,
entities: DataTree, entities: DataTree,
safeValues: boolean, replaceWithParsed: boolean,
): WidgetProps => { ): WidgetProps => {
if (!widget) return widget; if (!widget) return widget;
const properties = { ...widget }; const properties = { ...widget };
@ -86,19 +86,19 @@ export const enhanceWithDynamicValuesAndValidations = (
Object.keys(widget).forEach((property: string) => { Object.keys(widget).forEach((property: string) => {
let value = widget[property]; let value = widget[property];
// Check for dynamic bindings // Check for dynamic bindings
if (isDynamicValue(value)) { if (widget.dynamicBindings && property in widget.dynamicBindings) {
value = getDynamicValue(value, entities); value = getDynamicValue(value, entities);
} }
const isValid = ValidationFactory.validateWidgetProperty( // Pass it through validation and parse
const { isValid, parsed } = ValidationFactory.validateWidgetProperty(
widget.type, widget.type,
property, property,
value, value,
); );
if (!isValid) { // Store all invalid props
if (safeValues) value = undefined; if (!isValid) invalidProps[property] = true;
invalidProps[property] = true; // Replace if flag is turned on
} if (replaceWithParsed) properties[property] = parsed;
if (safeValues) properties[property] = value;
}); });
return { ...properties, invalidProps }; return { ...properties, invalidProps };
}; };

View File

@ -1,6 +1,10 @@
import { WidgetType } from "constants/WidgetConstants"; import { WidgetType } from "constants/WidgetConstants";
import WidgetFactory from "./WidgetFactory"; import WidgetFactory from "./WidgetFactory";
import { ValidationType, Validator } from "../constants/WidgetValidation"; import {
ValidationResponse,
ValidationType,
Validator,
} from "../constants/WidgetValidation";
// TODO: need to be strict about what the key can be // TODO: need to be strict about what the key can be
export type WidgetPropertyValidationType = Record<string, ValidationType>; export type WidgetPropertyValidationType = Record<string, ValidationType>;
@ -19,17 +23,17 @@ class ValidationFactory {
widgetType: WidgetType, widgetType: WidgetType,
property: string, property: string,
value: any, value: any,
) { ): ValidationResponse {
let isValid = true;
const propertyValidationTypes = WidgetFactory.getWidgetPropertyValidationMap( const propertyValidationTypes = WidgetFactory.getWidgetPropertyValidationMap(
widgetType, widgetType,
); );
const validationType = propertyValidationTypes[property]; const validationType = propertyValidationTypes[property];
const validator = this.validationMap.get(validationType); const validator = this.validationMap.get(validationType);
if (validator) { if (validator) {
isValid = validator(value); return validator(value);
} else {
return { isValid: true, parsed: value };
} }
return isValid;
} }
} }

View File

@ -4,30 +4,9 @@ import { VALIDATORS } from "./Validators";
class ValidationRegistry { class ValidationRegistry {
static registerInternalValidators() { static registerInternalValidators() {
ValidationFactory.registerValidator( Object.keys(VALIDATION_TYPES).forEach(type => {
VALIDATION_TYPES.TEXT, ValidationFactory.registerValidator(type, VALIDATORS[type]);
VALIDATORS[VALIDATION_TYPES.TEXT], });
);
ValidationFactory.registerValidator(
VALIDATION_TYPES.NUMBER,
VALIDATORS[VALIDATION_TYPES.NUMBER],
);
ValidationFactory.registerValidator(
VALIDATION_TYPES.BOOLEAN,
VALIDATORS[VALIDATION_TYPES.BOOLEAN],
);
ValidationFactory.registerValidator(
VALIDATION_TYPES.OBJECT,
VALIDATORS[VALIDATION_TYPES.OBJECT],
);
ValidationFactory.registerValidator(
VALIDATION_TYPES.TABLE_DATA,
VALIDATORS[VALIDATION_TYPES.TABLE_DATA],
);
} }
} }

View File

@ -1,25 +1,115 @@
import _ from "lodash"; import _ from "lodash";
import { import {
VALIDATION_TYPES, VALIDATION_TYPES,
ValidationResponse,
ValidationType, ValidationType,
Validator, Validator,
} from "../constants/WidgetValidation"; } from "../constants/WidgetValidation";
import moment from "moment";
export const VALIDATORS: Record<ValidationType, Validator> = { export const VALIDATORS: Record<ValidationType, Validator> = {
[VALIDATION_TYPES.TEXT]: (value: any) => _.isString(value), [VALIDATION_TYPES.TEXT]: (value: any): ValidationResponse => {
[VALIDATION_TYPES.NUMBER]: (value: any) => _.isNumber(value), let parsed = value;
[VALIDATION_TYPES.BOOLEAN]: (value: any) => _.isBoolean(value), if (_.isUndefined(value) || _.isObject(value)) {
[VALIDATION_TYPES.OBJECT]: (value: any) => _.isObject(value), return { isValid: false, parsed: "" };
[VALIDATION_TYPES.TABLE_DATA]: (value: any) => { }
try { let isValid = _.isString(value);
let data = value; if (!isValid) {
if (_.isString(data)) { try {
data = JSON.parse(data as string); parsed = _.toString(value);
isValid = true;
} catch (e) {
console.error(`Error when parsing ${value} to string`);
console.error(e);
return { isValid: false, parsed: "" };
} }
if (!Array.isArray(data)) return false; }
return _.every(data, datum => _.isObject(datum)); return { isValid, parsed };
} catch { },
return false; [VALIDATION_TYPES.NUMBER]: (value: any): ValidationResponse => {
let parsed = value;
if (_.isUndefined(value)) {
return { isValid: false, parsed: 0 };
}
let isValid = _.isNumber(value);
if (!isValid) {
try {
parsed = _.toNumber(value);
isValid = true;
} catch (e) {
console.error(`Error when parsing ${value} to number`);
console.error(e);
return { isValid: false, parsed: 0 };
}
}
return { isValid, parsed };
},
[VALIDATION_TYPES.BOOLEAN]: (value: any): ValidationResponse => {
let parsed = value;
if (_.isUndefined(value)) {
return { isValid: false, parsed: false };
}
let isValid = _.isBoolean(value);
if (!isValid) {
try {
parsed = !!value;
isValid = true;
} catch (e) {
console.error(`Error when parsing ${value} to boolean`);
console.error(e);
return { isValid: false, parsed: false };
}
}
return { isValid, parsed };
},
[VALIDATION_TYPES.OBJECT]: (value: any): ValidationResponse => {
let parsed = value;
if (_.isUndefined(value)) {
return { isValid: false, parsed: {} };
}
let isValid = _.isObject(value);
if (!isValid) {
try {
parsed = JSON.parse(value);
isValid = true;
} catch (e) {
console.error(`Error when parsing ${value} to object`);
console.error(e);
return { isValid: false, parsed: {} };
}
}
return { isValid, parsed };
},
[VALIDATION_TYPES.ARRAY]: (value: any): ValidationResponse => {
let parsed = value;
try {
if (_.isUndefined(value)) {
return { isValid: false, parsed: [] };
}
if (_.isString(value)) {
parsed = JSON.parse(parsed as string);
}
if (!Array.isArray(parsed)) {
return { isValid: false, parsed: [] };
}
return { isValid: true, parsed };
} catch (e) {
console.error(e);
return { isValid: false, parsed: [] };
} }
}, },
[VALIDATION_TYPES.TABLE_DATA]: (value: any): ValidationResponse => {
const { isValid, parsed } = VALIDATORS[VALIDATION_TYPES.ARRAY](value);
if (!isValid) {
return { isValid, parsed };
} else if (!_.every(parsed, datum => _.isObject(datum))) {
return { isValid: false, parsed: [] };
}
return { isValid, parsed };
},
[VALIDATION_TYPES.DATE]: (value: any): ValidationResponse => {
const isValid = moment(value).isValid();
const parsed = isValid ? moment(value).toDate() : new Date();
return { isValid, parsed };
},
}; };

View File

@ -3,6 +3,8 @@ import BaseWidget, { WidgetProps, WidgetState } from "./BaseWidget";
import { WidgetType } from "../constants/WidgetConstants"; import { WidgetType } from "../constants/WidgetConstants";
import ButtonComponent from "../components/designSystems/blueprint/ButtonComponent"; import ButtonComponent from "../components/designSystems/blueprint/ButtonComponent";
import { ActionPayload } from "../constants/ActionConstants"; import { ActionPayload } from "../constants/ActionConstants";
import { WidgetPropertyValidationType } from "utils/ValidationFactory";
import { VALIDATION_TYPES } from "constants/WidgetValidation";
class ButtonWidget extends BaseWidget<ButtonWidgetProps, WidgetState> { class ButtonWidget extends BaseWidget<ButtonWidgetProps, WidgetState> {
onButtonClickBound: (event: React.MouseEvent<HTMLElement>) => void; onButtonClickBound: (event: React.MouseEvent<HTMLElement>) => void;
@ -12,6 +14,15 @@ class ButtonWidget extends BaseWidget<ButtonWidgetProps, WidgetState> {
this.onButtonClickBound = this.onButtonClick.bind(this); this.onButtonClickBound = this.onButtonClick.bind(this);
} }
static getPropertyValidationMap(): WidgetPropertyValidationType {
return {
text: VALIDATION_TYPES.TEXT,
isDisabled: VALIDATION_TYPES.BOOLEAN,
isVisible: VALIDATION_TYPES.BOOLEAN,
buttonStyle: VALIDATION_TYPES.TEXT,
};
}
onButtonClick() { onButtonClick() {
super.executeAction(this.props.onClick); super.executeAction(this.props.onClick);
} }

View File

@ -11,6 +11,8 @@ class CheckboxWidget extends BaseWidget<CheckboxWidgetProps, WidgetState> {
return { return {
isDisabled: VALIDATION_TYPES.BOOLEAN, isDisabled: VALIDATION_TYPES.BOOLEAN,
label: VALIDATION_TYPES.TEXT, label: VALIDATION_TYPES.TEXT,
defaultCheckedState: VALIDATION_TYPES.BOOLEAN,
isChecked: VALIDATION_TYPES.BOOLEAN,
}; };
} }

View File

@ -3,8 +3,23 @@ import BaseWidget, { WidgetProps, WidgetState } from "./BaseWidget";
import { WidgetType } from "../constants/WidgetConstants"; import { WidgetType } from "../constants/WidgetConstants";
import { ActionPayload } from "../constants/ActionConstants"; import { ActionPayload } from "../constants/ActionConstants";
import DatePickerComponent from "../components/designSystems/blueprint/DatePickerComponent"; import DatePickerComponent from "../components/designSystems/blueprint/DatePickerComponent";
import { WidgetPropertyValidationType } from "utils/ValidationFactory";
import { VALIDATION_TYPES } from "constants/WidgetValidation";
class DatePickerWidget extends BaseWidget<DatePickerWidgetProps, WidgetState> { class DatePickerWidget extends BaseWidget<DatePickerWidgetProps, WidgetState> {
static getPropertyValidationMap(): WidgetPropertyValidationType {
return {
defaultDate: VALIDATION_TYPES.DATE,
selectedDate: VALIDATION_TYPES.DATE,
timezone: VALIDATION_TYPES.TEXT,
enableTimePicker: VALIDATION_TYPES.BOOLEAN,
dateFormat: VALIDATION_TYPES.TEXT,
label: VALIDATION_TYPES.TEXT,
datePickerType: VALIDATION_TYPES.TEXT,
maxDate: VALIDATION_TYPES.DATE,
minDate: VALIDATION_TYPES.DATE,
};
}
getPageView() { getPageView() {
return ( return (
<DatePickerComponent <DatePickerComponent

View File

@ -4,8 +4,20 @@ import { WidgetType } from "../constants/WidgetConstants";
import { ActionPayload } from "../constants/ActionConstants"; import { ActionPayload } from "../constants/ActionConstants";
import DropDownComponent from "../components/designSystems/blueprint/DropdownComponent"; import DropDownComponent from "../components/designSystems/blueprint/DropdownComponent";
import _ from "lodash"; import _ from "lodash";
import { WidgetPropertyValidationType } from "utils/ValidationFactory";
import { VALIDATION_TYPES } from "constants/WidgetValidation";
class DropdownWidget extends BaseWidget<DropdownWidgetProps, WidgetState> { class DropdownWidget extends BaseWidget<DropdownWidgetProps, WidgetState> {
static getPropertyValidationMap(): WidgetPropertyValidationType {
return {
placeholderText: VALIDATION_TYPES.TEXT,
label: VALIDATION_TYPES.TEXT,
options: VALIDATION_TYPES.ARRAY,
selectionType: VALIDATION_TYPES.TEXT,
selectedIndex: VALIDATION_TYPES.NUMBER,
selectedIndexArr: VALIDATION_TYPES.ARRAY,
};
}
getPageView() { getPageView() {
return ( return (
<DropDownComponent <DropDownComponent

View File

@ -7,6 +7,8 @@ import Webcam from "@uppy/webcam";
import Url from "@uppy/url"; import Url from "@uppy/url";
import OneDrive from "@uppy/onedrive"; import OneDrive from "@uppy/onedrive";
import FilePickerComponent from "../components/designSystems/appsmith/FilePickerComponent"; import FilePickerComponent from "../components/designSystems/appsmith/FilePickerComponent";
import { WidgetPropertyValidationType } from "utils/ValidationFactory";
import { VALIDATION_TYPES } from "constants/WidgetValidation";
class FilePickerWidget extends BaseWidget<FilePickerWidgetProps, WidgetState> { class FilePickerWidget extends BaseWidget<FilePickerWidgetProps, WidgetState> {
uppy: any; uppy: any;
@ -16,6 +18,14 @@ class FilePickerWidget extends BaseWidget<FilePickerWidgetProps, WidgetState> {
this.refreshUppy(props); this.refreshUppy(props);
} }
static getPropertyValidationMap(): WidgetPropertyValidationType {
return {
label: VALIDATION_TYPES.TEXT,
maxNumFiles: VALIDATION_TYPES.NUMBER,
allowedFileTypes: VALIDATION_TYPES.ARRAY,
};
}
refreshUppy = (props: FilePickerWidgetProps) => { refreshUppy = (props: FilePickerWidgetProps) => {
this.uppy = Uppy({ this.uppy = Uppy({
id: this.props.widgetId, id: this.props.widgetId,

View File

@ -2,8 +2,17 @@ import * as React from "react";
import BaseWidget, { WidgetProps, WidgetState } from "./BaseWidget"; import BaseWidget, { WidgetProps, WidgetState } from "./BaseWidget";
import { WidgetType } from "../constants/WidgetConstants"; import { WidgetType } from "../constants/WidgetConstants";
import ImageComponent from "../components/designSystems/appsmith/ImageComponent"; import ImageComponent from "../components/designSystems/appsmith/ImageComponent";
import { WidgetPropertyValidationType } from "utils/ValidationFactory";
import { VALIDATION_TYPES } from "constants/WidgetValidation";
class ImageWidget extends BaseWidget<ImageWidgetProps, WidgetState> { class ImageWidget extends BaseWidget<ImageWidgetProps, WidgetState> {
static getPropertyValidationMap(): WidgetPropertyValidationType {
return {
image: VALIDATION_TYPES.TEXT,
imageShape: VALIDATION_TYPES.TEXT,
defaultImage: VALIDATION_TYPES.TEXT,
};
}
getPageView() { getPageView() {
return ( return (
<ImageComponent <ImageComponent

View File

@ -3,8 +3,28 @@ import BaseWidget, { WidgetProps, WidgetState } from "./BaseWidget";
import { WidgetType } from "constants/WidgetConstants"; import { WidgetType } from "constants/WidgetConstants";
import InputComponent from "components/designSystems/blueprint/InputComponent"; import InputComponent from "components/designSystems/blueprint/InputComponent";
import { ActionPayload } from "constants/ActionConstants"; import { ActionPayload } from "constants/ActionConstants";
import { WidgetPropertyValidationType } from "utils/ValidationFactory";
import { VALIDATION_TYPES } from "constants/WidgetValidation";
class InputWidget extends BaseWidget<InputWidgetProps, WidgetState> { class InputWidget extends BaseWidget<InputWidgetProps, WidgetState> {
static getPropertyValidationMap(): WidgetPropertyValidationType {
return {
inputType: VALIDATION_TYPES.TEXT,
defaultText: VALIDATION_TYPES.TEXT,
isDisabled: VALIDATION_TYPES.BOOLEAN,
text: VALIDATION_TYPES.TEXT,
regex: VALIDATION_TYPES.TEXT,
errorMessage: VALIDATION_TYPES.TEXT,
placeholderText: VALIDATION_TYPES.TEXT,
maxChars: VALIDATION_TYPES.NUMBER,
minNum: VALIDATION_TYPES.NUMBER,
maxNum: VALIDATION_TYPES.NUMBER,
label: VALIDATION_TYPES.TEXT,
inputValidators: VALIDATION_TYPES.ARRAY,
focusIndex: VALIDATION_TYPES.NUMBER,
isAutoFocusEnabled: VALIDATION_TYPES.BOOLEAN,
};
}
regex = new RegExp(""); regex = new RegExp("");
componentDidMount() { componentDidMount() {

View File

@ -3,8 +3,17 @@ import BaseWidget, { WidgetProps, WidgetState } from "./BaseWidget";
import { WidgetType } from "../constants/WidgetConstants"; import { WidgetType } from "../constants/WidgetConstants";
import RadioGroupComponent from "../components/designSystems/blueprint/RadioGroupComponent"; import RadioGroupComponent from "../components/designSystems/blueprint/RadioGroupComponent";
import { ActionPayload } from "../constants/ActionConstants"; import { ActionPayload } from "../constants/ActionConstants";
import { WidgetPropertyValidationType } from "utils/ValidationFactory";
import { VALIDATION_TYPES } from "constants/WidgetValidation";
class RadioGroupWidget extends BaseWidget<RadioGroupWidgetProps, WidgetState> { class RadioGroupWidget extends BaseWidget<RadioGroupWidgetProps, WidgetState> {
static getPropertyValidationMap(): WidgetPropertyValidationType {
return {
label: VALIDATION_TYPES.TEXT,
options: VALIDATION_TYPES.ARRAY,
selectedOptionValue: VALIDATION_TYPES.TEXT,
};
}
getPageView() { getPageView() {
return ( return (
<RadioGroupComponent <RadioGroupComponent

View File

@ -3,8 +3,17 @@ import BaseWidget, { WidgetProps, WidgetState } from "./BaseWidget";
import { WidgetType } from "../constants/WidgetConstants"; import { WidgetType } from "../constants/WidgetConstants";
import { Intent } from "@blueprintjs/core"; import { Intent } from "@blueprintjs/core";
import SpinnerComponent from "../components/designSystems/blueprint/SpinnerComponent"; import SpinnerComponent from "../components/designSystems/blueprint/SpinnerComponent";
import { WidgetPropertyValidationType } from "utils/ValidationFactory";
import { VALIDATION_TYPES } from "constants/WidgetValidation";
class SpinnerWidget extends BaseWidget<SpinnerWidgetProps, WidgetState> { class SpinnerWidget extends BaseWidget<SpinnerWidgetProps, WidgetState> {
static getPropertyValidationMap(): WidgetPropertyValidationType {
return {
size: VALIDATION_TYPES.NUMBER,
value: VALIDATION_TYPES.NUMBER,
ellipsize: VALIDATION_TYPES.BOOLEAN,
};
}
getPageView() { getPageView() {
return ( return (
<SpinnerComponent <SpinnerComponent

View File

@ -29,28 +29,20 @@ function constructColumns(data: object[]): Column[] {
return cols; return cols;
} }
const getTableArrayData = (
tableData: string | object[] | undefined,
): object[] => {
if (!tableData) return [];
if (_.isString(tableData)) {
return JSON.parse(tableData as string);
} else {
return tableData;
}
};
class TableWidget extends BaseWidget<TableWidgetProps, WidgetState> { class TableWidget extends BaseWidget<TableWidgetProps, WidgetState> {
static getPropertyValidationMap(): WidgetPropertyValidationType { static getPropertyValidationMap(): WidgetPropertyValidationType {
return { return {
tableData: VALIDATION_TYPES.TABLE_DATA, tableData: VALIDATION_TYPES.TABLE_DATA,
nextPageKey: VALIDATION_TYPES.TEXT,
prevPageKey: VALIDATION_TYPES.TEXT,
label: VALIDATION_TYPES.TEXT,
selectedRow: VALIDATION_TYPES.OBJECT,
}; };
} }
getPageView() { getPageView() {
const { tableData } = this.props; const { tableData } = this.props;
const data = getTableArrayData(tableData); const columns = constructColumns(tableData);
const columns = constructColumns(data);
return ( return (
<AutoResizer> <AutoResizer>
{({ width, height }: { width: number; height: number }) => ( {({ width, height }: { width: number; height: number }) => (
@ -58,7 +50,7 @@ class TableWidget extends BaseWidget<TableWidgetProps, WidgetState> {
width={width} width={width}
height={height} height={height}
columns={columns} columns={columns}
data={data} data={tableData}
maxHeight={height} maxHeight={height}
isLoading={this.props.isLoading} isLoading={this.props.isLoading}
selectedRowIndex={ selectedRowIndex={
@ -76,10 +68,12 @@ class TableWidget extends BaseWidget<TableWidgetProps, WidgetState> {
} }
componentDidUpdate(prevProps: TableWidgetProps) { componentDidUpdate(prevProps: TableWidgetProps) {
super.componentDidUpdate(prevProps); super.componentDidUpdate(prevProps);
const newData = getTableArrayData(this.props.tableData); if (
if (prevProps.tableData !== this.props.tableData && prevProps.selectedRow) { !_.isEqual(prevProps.tableData, this.props.tableData) &&
prevProps.selectedRow
) {
this.updateSelectedRowProperty( this.updateSelectedRowProperty(
newData[prevProps.selectedRow.rowIndex], this.props.tableData[prevProps.selectedRow.rowIndex],
prevProps.selectedRow.rowIndex, prevProps.selectedRow.rowIndex,
); );
} }
@ -113,7 +107,7 @@ export interface TableWidgetProps extends WidgetProps {
nextPageKey?: string; nextPageKey?: string;
prevPageKey?: string; prevPageKey?: string;
label: string; label: string;
tableData?: string | object[]; tableData: object[];
recordActions?: TableAction[]; recordActions?: TableAction[];
onPageChange?: ActionPayload[]; onPageChange?: ActionPayload[];
onRowSelected?: ActionPayload[]; onRowSelected?: ActionPayload[];

View File

@ -9,6 +9,7 @@ class TextWidget extends BaseWidget<TextWidgetProps, WidgetState> {
static getPropertyValidationMap(): WidgetPropertyValidationType { static getPropertyValidationMap(): WidgetPropertyValidationType {
return { return {
text: VALIDATION_TYPES.TEXT, text: VALIDATION_TYPES.TEXT,
textStyle: VALIDATION_TYPES.TEXT,
}; };
} }