Merge branch 'fix/chart-data-validation' into 'release'
Chart validations, Tabs add new tab issue fix * Chart validation fixes * Tab widget, adding new tab will display the same inside pane configurations See merge request theappsmith/internal-tools-client!574
This commit is contained in:
commit
2fb29290f1
|
|
@ -43,6 +43,16 @@ export class DroppableComponent extends React.Component<
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentDidUpdate(prevProps: DroppableComponentProps) {
|
||||||
|
if (this.props.items.length !== prevProps.items.length) {
|
||||||
|
this.setState({ items: this.props.items });
|
||||||
|
} else if (
|
||||||
|
JSON.stringify(this.props.items) !== JSON.stringify(prevProps.items)
|
||||||
|
) {
|
||||||
|
this.setState({ items: this.props.items });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onDragEnd = (result: any) => {
|
onDragEnd = (result: any) => {
|
||||||
const { destination, source } = result;
|
const { destination, source } = result;
|
||||||
if (!destination) {
|
if (!destination) {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
import _ from "lodash";
|
||||||
import BaseControl, { ControlProps } from "./BaseControl";
|
import BaseControl, { ControlProps } from "./BaseControl";
|
||||||
import {
|
import {
|
||||||
ControlWrapper,
|
ControlWrapper,
|
||||||
|
|
@ -65,12 +66,22 @@ type RenderComponentProps = {
|
||||||
data: Array<{ x: string; y: string }> | any;
|
data: Array<{ x: string; y: string }> | any;
|
||||||
};
|
};
|
||||||
length: number;
|
length: number;
|
||||||
|
isValid: boolean;
|
||||||
|
validationMessage: string;
|
||||||
deleteOption: Function;
|
deleteOption: Function;
|
||||||
updateOption: Function;
|
updateOption: Function;
|
||||||
};
|
};
|
||||||
|
|
||||||
function DataControlComponent(props: RenderComponentProps) {
|
function DataControlComponent(props: RenderComponentProps) {
|
||||||
const { deleteOption, updateOption, item, index, length } = props;
|
const {
|
||||||
|
deleteOption,
|
||||||
|
updateOption,
|
||||||
|
item,
|
||||||
|
index,
|
||||||
|
length,
|
||||||
|
isValid,
|
||||||
|
validationMessage,
|
||||||
|
} = props;
|
||||||
return (
|
return (
|
||||||
<StyledOptionControlWrapper orientation={"VERTICAL"}>
|
<StyledOptionControlWrapper orientation={"VERTICAL"}>
|
||||||
<StyledOptionControlWrapper orientation={"HORIZONTAL"}>
|
<StyledOptionControlWrapper orientation={"HORIZONTAL"}>
|
||||||
|
|
@ -107,7 +118,7 @@ function DataControlComponent(props: RenderComponentProps) {
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
meta={{
|
meta={{
|
||||||
error: "",
|
error: isValid ? "" : validationMessage,
|
||||||
touched: true,
|
touched: true,
|
||||||
}}
|
}}
|
||||||
theme={"DARK"}
|
theme={"DARK"}
|
||||||
|
|
@ -120,12 +131,52 @@ function DataControlComponent(props: RenderComponentProps) {
|
||||||
}
|
}
|
||||||
|
|
||||||
class ChartDataControl extends BaseControl<ControlProps> {
|
class ChartDataControl extends BaseControl<ControlProps> {
|
||||||
|
getValidations = (message: string, isValid: boolean, len: number) => {
|
||||||
|
const validations: Array<{
|
||||||
|
isValid: boolean;
|
||||||
|
validationMessage: string;
|
||||||
|
}> = [];
|
||||||
|
let index = -1;
|
||||||
|
let validationMessage = "";
|
||||||
|
if (message.indexOf("##") !== -1) {
|
||||||
|
const messages = message.split("##");
|
||||||
|
index = Number(messages[0]);
|
||||||
|
validationMessage = messages[1];
|
||||||
|
}
|
||||||
|
for (let i = 0; i < len; i++) {
|
||||||
|
if (i === index) {
|
||||||
|
validations.push({
|
||||||
|
isValid: false,
|
||||||
|
validationMessage: validationMessage,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
validations.push({
|
||||||
|
isValid: true,
|
||||||
|
validationMessage: "",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return validations;
|
||||||
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const chartData: Array<{
|
const chartData: Array<{
|
||||||
seriesName: string;
|
seriesName: string;
|
||||||
data: Array<{ x: string; y: string }> | any;
|
data: Array<{ x: string; y: string }> | any;
|
||||||
}> = this.props.propertyValue || [];
|
}> =
|
||||||
|
this.props.propertyValue && _.isString(this.props.propertyValue)
|
||||||
|
? JSON.parse(this.props.propertyValue)
|
||||||
|
: this.props.propertyValue;
|
||||||
const dataLength = chartData.length;
|
const dataLength = chartData.length;
|
||||||
|
const { validationMessage, isValid } = this.props;
|
||||||
|
const validations: Array<{
|
||||||
|
isValid: boolean;
|
||||||
|
validationMessage: string;
|
||||||
|
}> = this.getValidations(
|
||||||
|
validationMessage || "",
|
||||||
|
isValid,
|
||||||
|
chartData.length,
|
||||||
|
);
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
{chartData.map((data, index) => {
|
{chartData.map((data, index) => {
|
||||||
|
|
@ -137,6 +188,8 @@ class ChartDataControl extends BaseControl<ControlProps> {
|
||||||
length={dataLength}
|
length={dataLength}
|
||||||
deleteOption={this.deleteOption}
|
deleteOption={this.deleteOption}
|
||||||
updateOption={this.updateOption}
|
updateOption={this.updateOption}
|
||||||
|
isValid={validations[index].isValid}
|
||||||
|
validationMessage={validations[index].validationMessage}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|
@ -152,9 +205,12 @@ class ChartDataControl extends BaseControl<ControlProps> {
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteOption = (index: number) => {
|
deleteOption = (index: number) => {
|
||||||
const chartData: object[] = this.props.propertyValue.slice();
|
const chartData: object[] =
|
||||||
|
this.props.propertyValue && _.isString(this.props.propertyValue)
|
||||||
|
? JSON.parse(this.props.propertyValue)
|
||||||
|
: this.props.propertyValue;
|
||||||
chartData.splice(index, 1);
|
chartData.splice(index, 1);
|
||||||
this.updateProperty(this.props.propertyName, chartData);
|
this.updateProperty(this.props.propertyName, JSON.stringify(chartData));
|
||||||
};
|
};
|
||||||
|
|
||||||
updateOption = (
|
updateOption = (
|
||||||
|
|
@ -165,23 +221,27 @@ class ChartDataControl extends BaseControl<ControlProps> {
|
||||||
const chartData: Array<{
|
const chartData: Array<{
|
||||||
seriesName: string;
|
seriesName: string;
|
||||||
data: Array<{ x: string; y: string }> | any;
|
data: Array<{ x: string; y: string }> | any;
|
||||||
}> = this.props.propertyValue;
|
}> =
|
||||||
this.updateProperty(
|
this.props.propertyValue && _.isString(this.props.propertyValue)
|
||||||
this.props.propertyName,
|
? JSON.parse(this.props.propertyValue)
|
||||||
chartData.map((item, i) => {
|
: this.props.propertyValue;
|
||||||
if (index === i) {
|
const updatedChartData = chartData.map((item, i) => {
|
||||||
if (propertyName === "seriesName") {
|
if (index === i) {
|
||||||
item.seriesName = updatedValue;
|
if (propertyName === "seriesName") {
|
||||||
} else {
|
item.seriesName = updatedValue;
|
||||||
try {
|
} else {
|
||||||
item.data = JSON.parse(updatedValue);
|
try {
|
||||||
} catch (err) {
|
item.data = JSON.parse(updatedValue);
|
||||||
item.data = updatedValue;
|
} catch (err) {
|
||||||
}
|
item.data = updatedValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return item;
|
}
|
||||||
}),
|
return item;
|
||||||
|
});
|
||||||
|
this.updateProperty(
|
||||||
|
this.props.propertyName,
|
||||||
|
JSON.stringify(updatedChartData),
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -189,9 +249,12 @@ class ChartDataControl extends BaseControl<ControlProps> {
|
||||||
const chartData: Array<{
|
const chartData: Array<{
|
||||||
seriesName: string;
|
seriesName: string;
|
||||||
data: Array<{ x: string; y: string }> | any;
|
data: Array<{ x: string; y: string }> | any;
|
||||||
}> = this.props.propertyValue ? this.props.propertyValue.slice() : [];
|
}> =
|
||||||
|
this.props.propertyValue && _.isString(this.props.propertyValue)
|
||||||
|
? JSON.parse(this.props.propertyValue)
|
||||||
|
: this.props.propertyValue;
|
||||||
chartData.push({ seriesName: "", data: [{ x: "", y: "" }] });
|
chartData.push({ seriesName: "", data: [{ x: "", y: "" }] });
|
||||||
this.updateProperty(this.props.propertyName, chartData);
|
this.updateProperty(this.props.propertyName, JSON.stringify(chartData));
|
||||||
};
|
};
|
||||||
|
|
||||||
static getControlType() {
|
static getControlType() {
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import { ControlIcons } from "icons/ControlIcons";
|
||||||
import { AnyStyledComponent } from "styled-components";
|
import { AnyStyledComponent } from "styled-components";
|
||||||
import { generateReactKey } from "utils/generators";
|
import { generateReactKey } from "utils/generators";
|
||||||
import { DroppableComponent } from "../designSystems/appsmith/DraggableListComponent";
|
import { DroppableComponent } from "../designSystems/appsmith/DraggableListComponent";
|
||||||
|
import _ from "lodash";
|
||||||
|
|
||||||
const StyledDeleteIcon = styled(FormIcons.DELETE_ICON as AnyStyledComponent)`
|
const StyledDeleteIcon = styled(FormIcons.DELETE_ICON as AnyStyledComponent)`
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
|
@ -98,14 +99,16 @@ function TabControlComponent(props: RenderComponentProps) {
|
||||||
|
|
||||||
class TabControl extends BaseControl<ControlProps> {
|
class TabControl extends BaseControl<ControlProps> {
|
||||||
updateItems = (items: object[]) => {
|
updateItems = (items: object[]) => {
|
||||||
this.updateProperty(this.props.propertyName, items);
|
this.updateProperty(this.props.propertyName, JSON.stringify(items));
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const tabs: Array<{
|
const tabs: Array<{
|
||||||
id: string;
|
id: string;
|
||||||
label: string;
|
label: string;
|
||||||
}> = this.props.propertyValue || [{ id: "" }];
|
}> = _.isString(this.props.propertyValue)
|
||||||
|
? JSON.parse(this.props.propertyValue)
|
||||||
|
: this.props.propertyValue;
|
||||||
return (
|
return (
|
||||||
<TabsWrapper>
|
<TabsWrapper>
|
||||||
<DroppableComponent
|
<DroppableComponent
|
||||||
|
|
@ -128,35 +131,39 @@ class TabControl extends BaseControl<ControlProps> {
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteOption = (index: number) => {
|
deleteOption = (index: number) => {
|
||||||
const tabs: object[] = this.props.propertyValue.slice();
|
const tabs: object[] = _.isString(this.props.propertyValue)
|
||||||
|
? JSON.parse(this.props.propertyValue).slice()
|
||||||
|
: this.props.propertyValue.slice();
|
||||||
tabs.splice(index, 1);
|
tabs.splice(index, 1);
|
||||||
this.updateProperty(this.props.propertyName, tabs);
|
this.updateProperty(this.props.propertyName, JSON.stringify(tabs));
|
||||||
};
|
};
|
||||||
|
|
||||||
updateOption = (index: number, updatedLabel: string) => {
|
updateOption = (index: number, updatedLabel: string) => {
|
||||||
const tabs: Array<{
|
const tabs: Array<{
|
||||||
id: string;
|
id: string;
|
||||||
label: string;
|
label: string;
|
||||||
}> = this.props.propertyValue;
|
}> = _.isString(this.props.propertyValue)
|
||||||
this.updateProperty(
|
? JSON.parse(this.props.propertyValue)
|
||||||
this.props.propertyName,
|
: this.props.propertyValue;
|
||||||
tabs.map((tab, tabIndex) => {
|
const updatedTabs = tabs.map((tab, tabIndex) => {
|
||||||
if (index === tabIndex) {
|
if (index === tabIndex) {
|
||||||
tab.label = updatedLabel;
|
tab.label = updatedLabel;
|
||||||
}
|
}
|
||||||
return tab;
|
return tab;
|
||||||
}),
|
});
|
||||||
);
|
this.updateProperty(this.props.propertyName, JSON.stringify(updatedTabs));
|
||||||
};
|
};
|
||||||
|
|
||||||
addOption = () => {
|
addOption = () => {
|
||||||
const tabs: Array<{
|
const tabs: Array<{
|
||||||
id: string;
|
id: string;
|
||||||
label: string;
|
label: string;
|
||||||
}> = this.props.propertyValue ? this.props.propertyValue.slice() : [];
|
}> = _.isString(this.props.propertyValue)
|
||||||
|
? JSON.parse(this.props.propertyValue)
|
||||||
|
: this.props.propertyValue;
|
||||||
const newTabId = generateReactKey({ prefix: "tab" });
|
const newTabId = generateReactKey({ prefix: "tab" });
|
||||||
tabs.push({ id: newTabId, label: `Tab ${tabs.length + 1}` });
|
tabs.push({ id: newTabId, label: `Tab ${tabs.length + 1}` });
|
||||||
this.updateProperty(this.props.propertyName, tabs);
|
this.updateProperty(this.props.propertyName, JSON.stringify(tabs));
|
||||||
};
|
};
|
||||||
|
|
||||||
static getControlType() {
|
static getControlType() {
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ export const VALIDATION_TYPES = {
|
||||||
TABLE_DATA: "TABLE_DATA",
|
TABLE_DATA: "TABLE_DATA",
|
||||||
OPTIONS_DATA: "OPTIONS_DATA",
|
OPTIONS_DATA: "OPTIONS_DATA",
|
||||||
DATE: "DATE",
|
DATE: "DATE",
|
||||||
|
TABS_DATA: "TABS_DATA",
|
||||||
CHART_DATA: "CHART_DATA",
|
CHART_DATA: "CHART_DATA",
|
||||||
MARKERS: "MARKERS",
|
MARKERS: "MARKERS",
|
||||||
ACTION_SELECTOR: "ACTION_SELECTOR",
|
ACTION_SELECTOR: "ACTION_SELECTOR",
|
||||||
|
|
|
||||||
|
|
@ -143,6 +143,13 @@ export const createDynamicValueString = (
|
||||||
if (Array.isArray(value) || _.isObject(value)) {
|
if (Array.isArray(value) || _.isObject(value)) {
|
||||||
value = JSON.stringify(value);
|
value = JSON.stringify(value);
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
|
if (JSON.parse(value)) {
|
||||||
|
value = value.replace(/\\([\s\S])|(")/g, "\\$1$2");
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
finalValue = finalValue.replace(b, value);
|
finalValue = finalValue.replace(b, value);
|
||||||
});
|
});
|
||||||
return finalValue;
|
return finalValue;
|
||||||
|
|
|
||||||
|
|
@ -207,6 +207,31 @@ export const VALIDATORS: Record<ValidationType, Validator> = {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
[VALIDATION_TYPES.TABS_DATA]: (
|
||||||
|
value: any,
|
||||||
|
props: WidgetProps,
|
||||||
|
dataTree?: DataTree,
|
||||||
|
): ValidationResponse => {
|
||||||
|
const { isValid, parsed } = VALIDATORS[VALIDATION_TYPES.ARRAY](
|
||||||
|
value,
|
||||||
|
props,
|
||||||
|
dataTree,
|
||||||
|
);
|
||||||
|
if (!isValid) {
|
||||||
|
return {
|
||||||
|
isValid,
|
||||||
|
parsed,
|
||||||
|
message: `${WIDGET_TYPE_VALIDATION_ERROR}: Tabs Data`,
|
||||||
|
};
|
||||||
|
} else if (!_.every(parsed, datum => _.isObject(datum))) {
|
||||||
|
return {
|
||||||
|
isValid: false,
|
||||||
|
parsed: [],
|
||||||
|
message: `${WIDGET_TYPE_VALIDATION_ERROR}: Tabs Data`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return { isValid, parsed };
|
||||||
|
},
|
||||||
[VALIDATION_TYPES.TABLE_DATA]: (
|
[VALIDATION_TYPES.TABLE_DATA]: (
|
||||||
value: any,
|
value: any,
|
||||||
props: WidgetProps,
|
props: WidgetProps,
|
||||||
|
|
@ -237,6 +262,10 @@ export const VALIDATORS: Record<ValidationType, Validator> = {
|
||||||
props: WidgetProps,
|
props: WidgetProps,
|
||||||
dataTree?: DataTree,
|
dataTree?: DataTree,
|
||||||
): ValidationResponse => {
|
): ValidationResponse => {
|
||||||
|
if (_.isString(value)) {
|
||||||
|
value = value.replace(/\s/g, "");
|
||||||
|
value = `${value}`;
|
||||||
|
}
|
||||||
const { isValid, parsed } = VALIDATORS[VALIDATION_TYPES.ARRAY](
|
const { isValid, parsed } = VALIDATORS[VALIDATION_TYPES.ARRAY](
|
||||||
value,
|
value,
|
||||||
props,
|
props,
|
||||||
|
|
@ -249,27 +278,40 @@ export const VALIDATORS: Record<ValidationType, Validator> = {
|
||||||
message: `${WIDGET_TYPE_VALIDATION_ERROR}: Chart Data`,
|
message: `${WIDGET_TYPE_VALIDATION_ERROR}: Chart Data`,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
const hasChartData = _.every(
|
let validationMessage = "";
|
||||||
|
let index = 0;
|
||||||
|
const isValidChartData = _.every(
|
||||||
parsed,
|
parsed,
|
||||||
(datum: { seriesName: any; data: any }) => {
|
(datum: { name: string; data: any }) => {
|
||||||
if (_.isObject(datum)) {
|
const validatedResponse: {
|
||||||
return (
|
isValid: boolean;
|
||||||
_.isString(datum.seriesName) &&
|
parsed: object;
|
||||||
_.isArray(datum.data) &&
|
message?: string;
|
||||||
_.every(datum.data, (item: { x: any; y: any }) => {
|
} = VALIDATORS[VALIDATION_TYPES.ARRAY](datum.data, props, dataTree);
|
||||||
return _.isString(item.x) && !_.isUndefined(item.y);
|
validationMessage = `${index}##${WIDGET_TYPE_VALIDATION_ERROR}: [{ "x": "val", "y": "val" }]`;
|
||||||
})
|
let isValidChart = validatedResponse.isValid;
|
||||||
|
if (validatedResponse.isValid) {
|
||||||
|
datum.data = validatedResponse.parsed;
|
||||||
|
isValidChart = _.every(
|
||||||
|
datum.data,
|
||||||
|
(chartPoint: { x: string; y: any }) => {
|
||||||
|
return (
|
||||||
|
_.isObject(chartPoint) &&
|
||||||
|
_.isString(chartPoint.x) &&
|
||||||
|
!_.isUndefined(chartPoint.y)
|
||||||
|
);
|
||||||
|
},
|
||||||
);
|
);
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
index++;
|
||||||
|
return isValidChart;
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
if (!hasChartData) {
|
if (!isValidChartData) {
|
||||||
return {
|
return {
|
||||||
isValid: false,
|
isValid: false,
|
||||||
parsed: [],
|
parsed: [],
|
||||||
message: `${WIDGET_TYPE_VALIDATION_ERROR}: Chart Data`,
|
message: validationMessage,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return { isValid, parsed };
|
return { isValid, parsed };
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,19 @@ import { WidgetType, WidgetTypes } from "constants/WidgetConstants";
|
||||||
import BaseWidget, { WidgetProps, WidgetState } from "./BaseWidget";
|
import BaseWidget, { WidgetProps, WidgetState } from "./BaseWidget";
|
||||||
import WidgetFactory from "utils/WidgetFactory";
|
import WidgetFactory from "utils/WidgetFactory";
|
||||||
import { generateReactKey } from "utils/generators";
|
import { generateReactKey } from "utils/generators";
|
||||||
|
import { WidgetPropertyValidationType } from "utils/ValidationFactory";
|
||||||
|
import { VALIDATION_TYPES } from "constants/WidgetValidation";
|
||||||
|
|
||||||
class TabsWidget extends BaseWidget<
|
class TabsWidget extends BaseWidget<
|
||||||
TabsWidgetProps<TabContainerWidgetProps>,
|
TabsWidgetProps<TabContainerWidgetProps>,
|
||||||
WidgetState
|
WidgetState
|
||||||
> {
|
> {
|
||||||
|
static getPropertyValidationMap(): WidgetPropertyValidationType {
|
||||||
|
return {
|
||||||
|
tabs: VALIDATION_TYPES.TABS_DATA,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
onTabChange = (tabId: string) => {
|
onTabChange = (tabId: string) => {
|
||||||
this.updateWidgetMetaProperty("selectedTabId", tabId);
|
this.updateWidgetMetaProperty("selectedTabId", tabId);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user