PromucFlow_constructor/app/client/src/components/propertyControls/ChartDataControl.tsx
albinAppsmith 629999f124
feat: [epic] appsmith design system version 2 deduplication (#22030)
## Description

### Fixes
- [x] https://github.com/appsmithorg/appsmith/issues/19383
- [x] https://github.com/appsmithorg/appsmith/issues/19384
- [x] https://github.com/appsmithorg/appsmith/issues/19385
- [x] https://github.com/appsmithorg/appsmith/issues/19386
- [x] https://github.com/appsmithorg/appsmith/issues/19387
- [x] https://github.com/appsmithorg/appsmith/issues/19388
- [x] https://github.com/appsmithorg/appsmith/issues/19389
- [x] https://github.com/appsmithorg/appsmith/issues/19390
- [x] https://github.com/appsmithorg/appsmith/issues/19391
- [x] https://github.com/appsmithorg/appsmith/issues/19392
- [x] https://github.com/appsmithorg/appsmith/issues/19393
- [x] https://github.com/appsmithorg/appsmith/issues/19394
- [x] https://github.com/appsmithorg/appsmith/issues/19395
- [x] https://github.com/appsmithorg/appsmith/issues/19396
- [x] https://github.com/appsmithorg/appsmith/issues/19397
- [x] https://github.com/appsmithorg/appsmith/issues/19398
- [x] https://github.com/appsmithorg/appsmith/issues/19399
- [x] https://github.com/appsmithorg/appsmith/issues/19400
- [x] https://github.com/appsmithorg/appsmith/issues/19401
- [x] https://github.com/appsmithorg/appsmith/issues/19402
- [x] https://github.com/appsmithorg/appsmith/issues/19403
- [x] https://github.com/appsmithorg/appsmith/issues/19404
- [x] https://github.com/appsmithorg/appsmith/issues/19405
- [x] https://github.com/appsmithorg/appsmith/issues/19406
- [x] https://github.com/appsmithorg/appsmith/issues/19407
- [x] https://github.com/appsmithorg/appsmith/issues/19408
- [x] https://github.com/appsmithorg/appsmith/issues/19409

Fixes # (issue)
> if no issue exists, please create an issue and ask the maintainers
about this first


Media
> A video or a GIF is preferred. when using Loom, don’t embed because it
looks like it’s a GIF. instead, just link to the video


## Type of change

> Please delete options that are not relevant.

- Bug fix (non-breaking change which fixes an issue)
- New feature (non-breaking change which adds functionality)
- Breaking change (fix or feature that would cause existing
functionality to not work as expected)
- Chore (housekeeping or task changes that don't impact user perception)
- This change requires a documentation update


## How Has This Been Tested?
> Please describe the tests that you ran to verify your changes. Provide
instructions, so we can reproduce.
> Please also list any relevant details for your test configuration.
> Delete anything that is not important

- Manual
- Jest
- Cypress

### Test Plan
> Add Testsmith test cases links that relate to this PR

### Issues raised during DP testing
> Link issues raised during DP testing for better visiblity and tracking
(copy link from comments dropped on this PR)


## Checklist:
### Dev activity
- [ ] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [ ] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] PR is being merged under a feature flag


### QA activity:
- [ ] Test plan has been approved by relevant developers
- [ ] Test plan has been peer reviewed by QA
- [ ] Cypress test cases have been added and approved by either SDET or
manual QA
- [ ] Organized project review call with relevant stakeholders after
Round 1/2 of QA
- [ ] Added Test Plan Approved label after reveiwing all Cypress test

---------

Co-authored-by: Ankita Kinger <ankita@appsmith.com>
Co-authored-by: akash-codemonk <67054171+akash-codemonk@users.noreply.github.com>
Co-authored-by: Tanvi Bhakta <tanvi@appsmith.com>
Co-authored-by: Arsalan <arsalanyaldram0211@outlook.com>
Co-authored-by: Aman Agarwal <aman@appsmith.com>
Co-authored-by: Rohit Agarwal <rohit_agarwal@live.in>
Co-authored-by: Nilesh Sarupriya <nilesh@appsmith.com>
Co-authored-by: Nilesh Sarupriya <20905988+nsarupr@users.noreply.github.com>
Co-authored-by: Tanvi Bhakta <tanvibhakta@gmail.com>
Co-authored-by: Aishwarya UR <aishwarya@appsmith.com>
Co-authored-by: Parthvi Goswami <parthvigoswami@Parthvis-MacBook-Pro.local>
Co-authored-by: Vijetha-Kaja <vijetha@appsmith.com>
Co-authored-by: Parthvi <80334441+Parthvi12@users.noreply.github.com>
Co-authored-by: Apple <nandan@thinkify.io>
Co-authored-by: Saroj <43822041+sarojsarab@users.noreply.github.com>
Co-authored-by: Sangeeth Sivan <74818788+berzerkeer@users.noreply.github.com>
Co-authored-by: Ashok Kumar M <35134347+marks0351@users.noreply.github.com>
Co-authored-by: Aishwarya-U-R <91450662+Aishwarya-U-R@users.noreply.github.com>
Co-authored-by: rahulramesha <rahul@appsmith.com>
Co-authored-by: Aswath K <aswath.sana@gmail.com>
Co-authored-by: Preet Sidhu <preetsidhu.bits@gmail.com>
Co-authored-by: Vijetha-Kaja <119562824+Vijetha-Kaja@users.noreply.github.com>
Co-authored-by: Shrikant Sharat Kandula <shrikant@appsmith.com>
2023-05-20 00:07:06 +05:30

322 lines
8.5 KiB
TypeScript

import React from "react";
import { get, isString } from "lodash";
import styled from "styled-components";
import type { ControlProps } from "./BaseControl";
import BaseControl from "./BaseControl";
import { ControlWrapper } from "./StyledControls";
import type { CodeEditorExpected } from "components/editorComponents/CodeEditor";
import type { EditorTheme } from "components/editorComponents/CodeEditor/EditorConfig";
import {
EditorModes,
EditorSize,
TabBehaviour,
} from "components/editorComponents/CodeEditor/EditorConfig";
import { Button } from "design-system";
import type { AllChartData, ChartData } from "widgets/ChartWidget/constants";
import { generateReactKey } from "utils/generators";
import { AutocompleteDataType } from "utils/autocomplete/AutocompleteDataType";
import LazyCodeEditor from "components/editorComponents/LazyCodeEditor";
import ColorPickerComponent from "./ColorPickerComponentV2";
const Wrapper = styled.div`
background-color: var(--ads-v2-color-bg-subtle);
padding: 0 8px;
margin-bottom: 5px;
border-radius: var(--ads-v2-border-radius);
`;
const StyledOptionControlWrapper = styled(ControlWrapper)`
display: flex;
justify-content: flex-start;
padding: 0;
width: 100%;
> div {
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 StyledDeleteButton = styled(Button)`
padding: 0;
position: relative;
margin-left: 15px;
cursor: pointer;
`;
const ActionHolder = styled.div`
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
`;
const StyledLabel = styled.label`
margin: 8px auto 8px 0;
&& {
color: ${(props) => props.theme.colors.propertyPane.label};
}
`;
const Box = styled.div`
height: 16px;
`;
type RenderComponentProps = {
index: string;
item: ChartData;
length: number;
dataTreePath: string;
deleteOption: (index: string) => void;
updateOption: (index: string, key: string, value: string) => void;
evaluated: {
seriesName: string;
data: Array<{ x: string; y: string }> | any;
color: string;
};
theme: EditorTheme;
isPieChart?: boolean;
};
const expectedSeriesName: CodeEditorExpected = {
type: "string",
example: "series1",
autocompleteDataType: AutocompleteDataType.STRING,
};
const expectedSeriesData: CodeEditorExpected = {
type: "Array<{ x: string, y: number Required }>",
example: [
{
x: "Mon",
y: 10000,
},
],
autocompleteDataType: AutocompleteDataType.ARRAY,
};
function DataControlComponent(props: RenderComponentProps) {
const {
dataTreePath,
deleteOption,
evaluated,
index,
isPieChart,
item,
length,
updateOption,
} = props;
return (
<StyledOptionControlWrapper orientation={"VERTICAL"}>
<ActionHolder>
<StyledLabel>Series title</StyledLabel>
{length > 1 && (
<StyledDeleteButton
isIconButton
kind="tertiary"
onClick={() => {
deleteOption(index);
}}
size="md"
startIcon="delete-bin-line"
/>
)}
</ActionHolder>
<StyledOptionControlWrapper orientation={"HORIZONTAL"}>
<LazyCodeEditor
AIAssisted
dataTreePath={`${dataTreePath}.seriesName`}
evaluatedValue={evaluated?.seriesName}
expected={expectedSeriesName}
input={{
value: item.seriesName,
onChange: (
event: React.ChangeEvent<HTMLTextAreaElement> | string,
) => {
let value: string = event as string;
if (typeof event !== "string") {
value = event.target.value;
}
updateOption(index, "seriesName", value);
},
}}
mode={EditorModes.TEXT_WITH_BINDING}
placeholder="Series Name"
size={EditorSize.EXTENDED}
tabBehaviour={TabBehaviour.INPUT}
theme={props.theme}
/>
</StyledOptionControlWrapper>
{!isPieChart && (
<>
<StyledLabel>Series color</StyledLabel>
<StyledOptionControlWrapper orientation={"HORIZONTAL"}>
<ColorPickerComponent
changeColor={(
event: React.ChangeEvent<HTMLTextAreaElement> | string,
) => {
let value: string = event as string;
if (typeof event !== "string") {
value = event.target.value;
}
updateOption(index, "color", value);
}}
color={item.color || ""}
placeholderText="enter color hexcode"
showApplicationColors
/>
</StyledOptionControlWrapper>
</>
)}
<StyledLabel>Series data</StyledLabel>
<StyledDynamicInput
className={"t--property-control-chart-series-data-control"}
>
<LazyCodeEditor
AIAssisted
dataTreePath={`${dataTreePath}.data`}
evaluatedValue={evaluated?.data}
expected={expectedSeriesData}
input={{
value: item.data,
onChange: (
event: React.ChangeEvent<HTMLTextAreaElement> | string,
) => {
let value: string = event as string;
if (typeof event !== "string") {
value = event.target.value;
}
updateOption(index, "data", value);
},
}}
mode={EditorModes.JSON_WITH_BINDING}
placeholder=""
size={EditorSize.EXTENDED}
tabBehaviour={TabBehaviour.INPUT}
theme={props.theme}
/>
</StyledDynamicInput>
<Box />
</StyledOptionControlWrapper>
);
}
class ChartDataControl extends BaseControl<ControlProps> {
render() {
const chartData: AllChartData = isString(this.props.propertyValue)
? {}
: this.props.propertyValue;
const dataLength = Object.keys(chartData).length;
const evaluatedValue = this.props.evaluatedValue;
const firstKey = Object.keys(chartData)[0] as string;
if (this.props.widgetProperties.chartType === "PIE_CHART") {
const data = dataLength
? get(chartData, `${firstKey}`)
: {
seriesName: "",
data: [],
};
return (
<DataControlComponent
dataTreePath={`${this.props.dataTreePath}.${firstKey}`}
deleteOption={this.deleteOption}
evaluated={get(evaluatedValue, `${firstKey}`)}
index={firstKey}
isPieChart
item={data}
length={1}
theme={this.props.theme}
updateOption={this.updateOption}
/>
);
}
return (
<div className="flex flex-col gap-1">
<Wrapper>
{Object.keys(chartData).map((key: string) => {
const data = get(chartData, `${key}`);
return (
<DataControlComponent
dataTreePath={`${this.props.dataTreePath}.${key}`}
deleteOption={this.deleteOption}
evaluated={get(evaluatedValue, `${key}`)}
index={key}
item={data}
key={key}
length={dataLength}
theme={this.props.theme}
updateOption={this.updateOption}
/>
);
})}
</Wrapper>
<Button
className="self-end"
kind="tertiary"
onClick={this.addOption}
size="sm"
startIcon="plus"
>
Add series
</Button>
</div>
);
}
deleteOption = (index: string) => {
this.deleteProperties([`${this.props.propertyName}.${index}`]);
};
updateOption = (
index: string,
propertyName: string,
updatedValue: string,
) => {
this.updateProperty(
`${this.props.propertyName}.${index}.${propertyName}`,
updatedValue,
);
};
/**
* it adds new series data object in the chartData
*/
addOption = () => {
const randomString = generateReactKey();
this.updateProperty(`${this.props.propertyName}.${randomString}`, {
seriesName: "",
data: JSON.stringify([{ x: "label", y: 50 }]),
});
};
static getControlType() {
return "CHART_DATA";
}
}
export default ChartDataControl;