Merge branch 'feature/graph-components' into 'release'

Feature/graph components

Support for Graph components, Line|Bar|Pie|Area|Column graphs added

See merge request theappsmith/internal-tools-client!334
This commit is contained in:
Abhinav Jha 2020-03-13 12:06:42 +00:00
commit 4b9d8a9d43
14 changed files with 434 additions and 2127 deletions

View File

@ -44,6 +44,7 @@
"flow-bin": "^0.91.0",
"fontfaceobserver": "^2.1.0",
"fuse.js": "^3.4.5",
"fusioncharts": "^3.15.0-sr.1",
"history": "^4.10.1",
"husky": "^3.0.5",
"interweave": "^12.1.1",
@ -67,6 +68,7 @@
"react-dnd-html5-backend": "^9.3.4",
"react-dnd-touch-backend": "^9.4.0",
"react-dom": "^16.7.0",
"react-fusioncharts": "^3.1.2",
"react-helmet": "^5.2.1",
"react-redux": "^7.1.3",
"react-router": "^5.1.2",

View File

@ -0,0 +1,3 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M16.7494 13.8508L13.069 10.0279L4.21712 19.024L3 17.8274L13.0818 7.58082L16.798 11.4404L23.1909 5.31898L21.3593 3.48817H26.1416V8.26875L24.3978 6.52586L16.7494 13.8508ZM7.23518 26.3199H12.9965V18.2114H7.23518V26.3199ZM16.237 26.3199H20.9982V15.6509H16.237V26.3199ZM24.2387 10.3164V26.3199H29V10.3164H24.2387Z" fill="#F1F7FC"/>
</svg>

After

Width:  |  Height:  |  Size: 439 B

View File

@ -0,0 +1,83 @@
import React from "react";
import ReactFC from "react-fusioncharts";
import FusionCharts from "fusioncharts";
import Column2D from "fusioncharts/fusioncharts.charts";
import FusionTheme from "fusioncharts/themes/fusioncharts.theme.fusion";
import { ChartType, ChartData } from "widgets/ChartWidget";
import styled from "styled-components";
import { invisible } from "constants/DefaultTheme";
ReactFC.fcRoot(FusionCharts, Column2D, FusionTheme);
export interface ChartComponentProps {
chartType: ChartType;
chartData: ChartData[];
xAxisName: string;
yAxisName: string;
chartName: string;
componentWidth: number;
componentHeight: number;
isVisible?: boolean;
}
const CanvasContainer = styled.div<ChartComponentProps>`
border: none;
border-radius: ${props => `${props.theme.radii[1]}px`};
height: 100%;
width: 100%;
background: white;
box-shadow: 0 1px 1px 0 rgba(60,75,100,.14),0 2px 1px -1px rgba(60,75,100,.12),0 1px 3px 0 rgba(60,75,100,.2);
position: relative;
${props => (!props.isVisible ? invisible : "")};
}`;
/* eslint-disable react/display-name */
const ChartComponent = (props: ChartComponentProps) => {
const getChartType = (chartType: ChartType) => {
switch (chartType) {
case "LINE_CHART":
return "line";
case "BAR_CHART":
return "bar2d";
case "PIE_CHART":
return "pie2d";
case "COLUMN_CHART":
return "column2d";
case "AREA_CHART":
return "area2d";
default:
return "column2d";
}
};
const getChartData = (chartData: ChartData[]) => {
return chartData.map(item => {
return {
label: item.x,
value: item.y,
};
});
};
return (
<CanvasContainer {...props}>
<ReactFC
type={getChartType(props.chartType)}
width={props.componentWidth.toString()}
height={props.componentHeight.toString()}
dataForma="json"
dataSource={{
chart: {
xAxisName: props.xAxisName,
yAxisName: props.yAxisName,
theme: "fusion",
caption: props.chartName,
},
data: getChartData(props.chartData),
}}
/>
</CanvasContainer>
);
};
export default ChartComponent;

View File

@ -11,6 +11,7 @@ export type WidgetType =
| "RADIO_GROUP_WIDGET"
| "FILE_PICKER_WIDGET"
| "INPUT_WIDGET"
| "CHART_WIDGET"
| "SWITCH_WIDGET"
| "FORM_WIDGET"
| "FORM_BUTTON_WIDGET";
@ -28,6 +29,7 @@ export const WidgetTypes: { [id: string]: WidgetType } = {
DROP_DOWN_WIDGET: "DROP_DOWN_WIDGET",
CHECKBOX_WIDGET: "CHECKBOX_WIDGET",
RADIO_GROUP_WIDGET: "RADIO_GROUP_WIDGET",
CHART_WIDGET: "CHART_WIDGET",
FORM_WIDGET: "FORM_WIDGET",
FORM_BUTTON_WIDGET: "FORM_BUTTON_WIDGET",
};

View File

@ -8,6 +8,7 @@ export const VALIDATION_TYPES = {
TABLE_DATA: "TABLE_DATA",
OPTIONS_DATA: "OPTIONS_DATA",
DATE: "DATE",
CHART_DATA: "CHART_DATA",
};
export type ValidationResponse = {

View File

@ -14,6 +14,7 @@ import { ReactComponent as SwitchIcon } from "assets/icons/widget/switch.svg";
import { ReactComponent as TextIcon } from "assets/icons/widget/text.svg";
import { ReactComponent as ImageIcon } from "assets/icons/widget/image.svg";
import { ReactComponent as FilePickerIcon } from "assets/icons/widget/filepicker.svg";
import { ReactComponent as ChartIcon } from "assets/icons/widget/chart.svg";
import { ReactComponent as FormIcon } from "assets/icons/widget/form.svg";
/* eslint-disable react/display-name */
@ -91,6 +92,11 @@ export const WidgetIcons: {
<FilePickerIcon />
</IconWrapper>
),
CHART_WIDGET: (props: IconProps) => (
<IconWrapper {...props}>
<ChartIcon />
</IconWrapper>
),
FORM_WIDGET: (props: IconProps) => (
<IconWrapper {...props}>
<FormIcon />

View File

@ -885,6 +885,67 @@ const PropertyPaneConfigResponse = {
],
},
],
CHART_WIDGET: [
{
sectionName: "General",
id: "21",
children: [
{
id: "21.1",
propertyName: "chartType",
label: "Chart Type",
controlType: "DROP_DOWN",
options: [
{
label: "Line Chart",
value: "LINE_CHART",
},
{
label: "Bar Chart",
value: "BAR_CHART",
},
{
label: "Pie Chart",
value: "PIE_CHART",
},
{
label: "Column Chart",
value: "COLUMN_CHART",
},
{
label: "Area Chart",
value: "AREA_CHART",
},
],
},
{
id: "21.2",
propertyName: "chartName",
label: "Chart Name",
controlType: "INPUT_TEXT",
},
{
id: "21.3",
propertyName: "xAxisName",
label: "X-axis Label",
controlType: "INPUT_TEXT",
},
{
id: "21.4",
propertyName: "yAxisName",
label: "Y-axis Label",
controlType: "INPUT_TEXT",
},
{
id: "21.5",
propertyName: "chartData",
label: "Chart Data",
controlType: "INPUT_TEXT",
inputType: "ARRAY",
},
],
},
],
},
name: "propertyPane",
};

View File

@ -154,6 +154,45 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
widgetName: "FilePicker",
isDefaultClickDisabled: true,
},
CHART_WIDGET: {
rows: 8,
columns: 6,
widgetName: "Chart",
chartType: "LINE_CHART",
chartName: "Sales on working days",
chartData: [
{
x: "Mon",
y: 10000,
},
{
x: "Tue",
y: 12000,
},
{
x: "Wed",
y: 32000,
},
{
x: "Thu",
y: 28000,
},
{
x: "Fri",
y: 14000,
},
{
x: "Sat",
y: 19000,
},
{
x: "Sun",
y: 36000,
},
],
xAxisName: "Last Week",
yAxisName: "Total Order Revenue $",
},
FORM_BUTTON_WIDGET: {
rows: 1,
columns: 3,

View File

@ -96,6 +96,11 @@ const WidgetSidebarResponse: {
widgetCardName: "Table",
key: generateReactKey(),
},
{
type: "CHART_WIDGET",
widgetCardName: "Chart",
key: generateReactKey(),
},
],
["Layout widgets"]: [
{

View File

@ -9,13 +9,14 @@ import { ImageWidgetProps } from "widgets/ImageWidget";
import { InputWidgetProps } from "widgets/InputWidget";
import { SwitchWidgetProps } from "widgets/SwitchWidget";
import { SpinnerWidgetProps } from "widgets/SpinnerWidget";
import { DatePickerWidgetProps } from "widgets/DatePickerWidget";
import { TableWidgetProps } from "widgets/TableWidget";
import { DropdownWidgetProps } from "widgets/DropdownWidget";
import { CheckboxWidgetProps } from "widgets/CheckboxWidget";
import { RadioGroupWidgetProps } from "widgets/RadioGroupWidget";
import { AlertWidgetProps } from "widgets/AlertWidget";
import { FilePickerWidgetProps } from "widgets/FilepickerWidget";
import { DatePickerWidgetProps } from "../../widgets/DatePickerWidget";
import { TableWidgetProps } from "../../widgets/TableWidget";
import { DropdownWidgetProps } from "../../widgets/DropdownWidget";
import { CheckboxWidgetProps } from "../../widgets/CheckboxWidget";
import { RadioGroupWidgetProps } from "../../widgets/RadioGroupWidget";
import { AlertWidgetProps } from "../../widgets/AlertWidget";
import { FilePickerWidgetProps } from "../../widgets/FilepickerWidget";
import { ChartWidgetProps } from "../../widgets/ChartWidget";
import { FormWidgetProps } from "widgets/FormWidget";
import { FormButtonWidgetProps } from "widgets/FormButtonWidget";
@ -53,6 +54,7 @@ export interface WidgetConfigReducerState {
RADIO_GROUP_WIDGET: Partial<RadioGroupWidgetProps> & WidgetConfigProps;
ALERT_WIDGET: Partial<AlertWidgetProps> & WidgetConfigProps;
FILE_PICKER_WIDGET: Partial<FilePickerWidgetProps> & WidgetConfigProps;
CHART_WIDGET: Partial<ChartWidgetProps> & WidgetConfigProps;
FORM_WIDGET: Partial<FormWidgetProps> & WidgetConfigProps;
FORM_BUTTON_WIDGET: Partial<FormButtonWidgetProps> & WidgetConfigProps;
};

View File

@ -174,6 +174,23 @@ export const VALIDATORS: Record<ValidationType, Validator> = {
}
return { isValid, parsed };
},
[VALIDATION_TYPES.CHART_DATA]: (value: any): ValidationResponse => {
const { isValid, parsed } = VALIDATORS[VALIDATION_TYPES.ARRAY](value);
if (!isValid) {
return {
isValid,
parsed,
message: `${WIDGET_TYPE_VALIDATION_ERROR}: Chart Data`,
};
} else if (!_.every(parsed, datum => _.isObject(datum))) {
return {
isValid: false,
parsed: [],
message: `${WIDGET_TYPE_VALIDATION_ERROR}: Chart Data`,
};
}
return { isValid, parsed };
},
[VALIDATION_TYPES.OPTIONS_DATA]: (value: any): ValidationResponse => {
const { isValid, parsed } = VALIDATORS[VALIDATION_TYPES.ARRAY](value);
if (!isValid) {

View File

@ -13,6 +13,7 @@ import ButtonWidget, { ButtonWidgetProps } from "widgets/ButtonWidget";
import DropdownWidget, { DropdownWidgetProps } from "widgets/DropdownWidget";
import ImageWidget, { ImageWidgetProps } from "widgets/ImageWidget";
import TableWidget, { TableWidgetProps } from "widgets/TableWidget";
import ChartWidget, { ChartWidgetProps } from "widgets/ChartWidget";
import FilePickerWidget, {
FilePickerWidgetProps,
@ -169,7 +170,17 @@ class WidgetBuilderRegistry {
DatePickerWidget.getDerivedPropertiesMap(),
DatePickerWidget.getTriggerPropertyMap(),
);
WidgetFactory.registerWidgetBuilder(
"CHART_WIDGET",
{
buildWidget(widgetData: ChartWidgetProps): JSX.Element {
return <ChartWidget {...widgetData} />;
},
},
ChartWidget.getPropertyValidationMap(),
ChartWidget.getDerivedPropertiesMap(),
ChartWidget.getTriggerPropertyMap(),
);
WidgetFactory.registerWidgetBuilder(
"FORM_WIDGET",
{

View File

@ -0,0 +1,63 @@
import React from "react";
import BaseWidget, { WidgetProps, WidgetState } from "./BaseWidget";
import { WidgetType } from "constants/WidgetConstants";
import ChartComponent from "components/designSystems/appsmith/ChartComponent";
import { WidgetPropertyValidationType } from "utils/ValidationFactory";
import { VALIDATION_TYPES } from "constants/WidgetValidation";
class ChartWidget extends BaseWidget<ChartWidgetProps, WidgetState> {
static getPropertyValidationMap(): WidgetPropertyValidationType {
return {
chartData: VALIDATION_TYPES.CHART_DATA,
xAxisName: VALIDATION_TYPES.TEXT,
yAxisName: VALIDATION_TYPES.TEXT,
chartName: VALIDATION_TYPES.TEXT,
};
}
getPageView() {
return (
<ChartComponent
key={this.props.widgetId}
isVisible={this.props.isVisible}
chartType={this.props.chartType}
xAxisName={this.props.xAxisName}
yAxisName={this.props.yAxisName}
chartName={this.props.chartName}
componentWidth={this.state.componentWidth - 10}
componentHeight={this.state.componentHeight - 10}
chartData={this.props.chartData}
/>
);
}
getWidgetType(): WidgetType {
return "CHART_WIDGET";
}
}
export type ChartType =
| "LINE_CHART"
| "BAR_CHART"
| "PIE_CHART"
| "COLUMN_CHART"
| "AREA_CHART"
| "SCATTER_CHART";
export interface ChartData {
x: any;
y: any;
}
export interface ChartWidgetProps extends WidgetProps {
chartType: ChartType;
chartData: ChartData[];
xAxisName: string;
yAxisName: string;
chartName: string;
componentWidth: number;
componentHeight: number;
isVisible?: boolean;
}
export default ChartWidget;

File diff suppressed because it is too large Load Diff