import React from "react";
import _ from "lodash";
import BaseControl, { ControlProps } from "./BaseControl";
import { ControlWrapper, StyledPropertyPaneButton } from "./StyledControls";
import styled from "constants/DefaultTheme";
import { FormIcons } from "icons/FormIcons";
import { AnyStyledComponent } from "styled-components";
import CodeEditor from "components/editorComponents/CodeEditor";
import {
EditorModes,
EditorSize,
EditorTheme,
TabBehaviour,
} from "components/editorComponents/CodeEditor/EditorConfig";
import * as Sentry from "@sentry/react";
const StyledOptionControlWrapper = styled(ControlWrapper)`
display: flex;
justify-content: flex-start;
padding: 0;
width: 100%;
`;
const StyledDynamicInput = styled.div`
width: 100%;
&&& {
input {
border: none;
color: ${props => props.theme.colors.textOnDarkBG};
background: ${props => props.theme.colors.paneInputBG};
&:focus {
border: none;
color: ${props => props.theme.colors.textOnDarkBG};
background: ${props => props.theme.colors.paneInputBG};
}
}
}
`;
const StyledDeleteIcon = styled(FormIcons.DELETE_ICON as AnyStyledComponent)`
padding: 0;
position: relative;
margin-left: 15px;
cursor: pointer;
`;
type RenderComponentProps = {
index: number;
item: {
seriesName: string;
data: Array<{ x: string; y: string }> | string;
};
length: number;
isValid: boolean;
validationMessage: string;
deleteOption: (index: number) => void;
updateOption: (index: number, key: string, value: string) => void;
evaluated: {
seriesName: string;
data: Array<{ x: string; y: string }> | any;
};
};
function DataControlComponent(props: RenderComponentProps) {
const {
deleteOption,
updateOption,
item,
index,
length,
isValid,
evaluated,
} = props;
return (
| string,
) => {
let value: string = event as string;
if (typeof event !== "string") {
value = event.target.value;
}
updateOption(index, "seriesName", value);
},
}}
evaluatedValue={evaluated?.seriesName}
theme={EditorTheme.DARK}
size={EditorSize.EXTENDED}
mode={EditorModes.TEXT_WITH_BINDING}
tabBehaviour={TabBehaviour.INPUT}
placeholder="Series Name"
/>
{length > 1 && (
{
deleteOption(index);
}}
/>
)}
`}
input={{
value: item.data,
onChange: (
event: React.ChangeEvent | string,
) => {
let value: string = event as string;
if (typeof event !== "string") {
value = event.target.value;
}
updateOption(index, "data", value);
},
}}
evaluatedValue={evaluated?.data}
meta={{
error: isValid ? "" : "There is an error",
touched: true,
}}
theme={EditorTheme.DARK}
size={EditorSize.EXTENDED}
mode={EditorModes.JSON_WITH_BINDING}
tabBehaviour={TabBehaviour.INPUT}
placeholder=""
/>
);
}
class ChartDataControl extends BaseControl {
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;
};
getEvaluatedValue = () => {
if (Array.isArray(this.props.evaluatedValue)) {
return this.props.evaluatedValue;
}
return [];
};
componentDidMount() {
this.migrateChartData(this.props.propertyValue);
}
migrateChartData(chartData: Array<{ seriesName: string; data: string }>) {
// Added a migration script for older chart data that was strings
// deprecate after enough charts have moved to the new format
if (_.isString(chartData)) {
try {
const parsedData: Array<{
seriesName: string;
data: string;
}> = JSON.parse(chartData);
this.updateProperty(this.props.propertyName, parsedData);
return parsedData;
} catch (error) {
Sentry.captureException({
message: "Chart Migration Failed",
oldData: this.props.propertyValue,
});
}
} else {
return this.props.propertyValue;
}
}
render() {
const chartData: Array<{ seriesName: string; data: string }> = _.isString(
this.props.propertyValue,
)
? []
: this.props.propertyValue;
const dataLength = chartData.length;
const { validationMessage, isValid } = this.props;
const validations: Array<{
isValid: boolean;
validationMessage: string;
}> = this.getValidations(
validationMessage || "",
isValid,
chartData.length,
);
const evaluatedValue = this.getEvaluatedValue();
return (
{chartData.map((data, index) => {
return (
);
})}
);
}
deleteOption = (index: number) => {
const chartData: Array<{
seriesName: string;
data: string;
}> = this.props.propertyValue;
chartData.splice(index, 1);
this.updateProperty(this.props.propertyName, chartData);
};
updateOption = (
index: number,
propertyName: string,
updatedValue: string,
) => {
const chartData: Array<{
seriesName: string;
data: string;
}> = this.props.propertyValue;
const updatedChartData = chartData.map((item, i) => {
if (index === i) {
return {
...item,
[propertyName]: updatedValue,
};
}
return item;
});
this.updateProperty(this.props.propertyName, updatedChartData);
};
addOption = () => {
const chartData: Array<{
seriesName: string;
data: string;
}> = this.props.propertyValue;
chartData.push({ seriesName: "", data: '[{ x: "", y: "" }]' });
this.updateProperty(this.props.propertyName, chartData);
};
static getControlType() {
return "CHART_DATA";
}
}
export default ChartDataControl;