Merge branch 'release' into 'master'
Release See merge request theappsmith/internal-tools-client!383
This commit is contained in:
commit
393f7fb33f
3
app/client/.gitignore
vendored
3
app/client/.gitignore
vendored
|
|
@ -29,4 +29,5 @@ yarn-error.log*
|
||||||
.idea
|
.idea
|
||||||
.storybook-out/
|
.storybook-out/
|
||||||
cypress/videos
|
cypress/videos
|
||||||
results/
|
cypress/screenshots
|
||||||
|
results/
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,7 @@ cypress-test:
|
||||||
- echo "127.0.0.1 dev.appsmith.com" >> /etc/hosts
|
- echo "127.0.0.1 dev.appsmith.com" >> /etc/hosts
|
||||||
- yarn test
|
- yarn test
|
||||||
artifacts:
|
artifacts:
|
||||||
|
when: on_failure
|
||||||
expire_in: 1 week
|
expire_in: 1 week
|
||||||
paths:
|
paths:
|
||||||
- build/
|
- build/
|
||||||
|
|
@ -61,7 +62,7 @@ cypress-test:
|
||||||
docker-package-release:
|
docker-package-release:
|
||||||
image: docker:dind
|
image: docker:dind
|
||||||
services:
|
services:
|
||||||
- docker:dind
|
- docker:dind
|
||||||
stage: package
|
stage: package
|
||||||
script:
|
script:
|
||||||
- docker build --build-arg REACT_APP_ENVIRONMENT=STAGING --build-arg GIT_SHA=$CI_COMMIT_SHORT_SHA -t appsmith/appsmith-editor:release .
|
- docker build --build-arg REACT_APP_ENVIRONMENT=STAGING --build-arg GIT_SHA=$CI_COMMIT_SHORT_SHA -t appsmith/appsmith-editor:release .
|
||||||
|
|
@ -75,7 +76,7 @@ docker-package-prod:
|
||||||
services:
|
services:
|
||||||
- docker:dind
|
- docker:dind
|
||||||
stage: package
|
stage: package
|
||||||
script:
|
script:
|
||||||
- docker build --build-arg REACT_APP_ENVIRONMENT=PRODUCTION --build-arg GIT_SHA=$CI_COMMIT_SHORT_SHA -t appsmith/appsmith-editor:latest .
|
- docker build --build-arg REACT_APP_ENVIRONMENT=PRODUCTION --build-arg GIT_SHA=$CI_COMMIT_SHORT_SHA -t appsmith/appsmith-editor:latest .
|
||||||
- docker login -u $DOCKER_HUB_USERNAME -p $DOCKER_HUB_ACCESS_TOKEN
|
- docker login -u $DOCKER_HUB_USERNAME -p $DOCKER_HUB_ACCESS_TOKEN
|
||||||
- docker push appsmith/appsmith-editor:latest
|
- docker push appsmith/appsmith-editor:latest
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,7 @@
|
||||||
"flow-bin": "^0.91.0",
|
"flow-bin": "^0.91.0",
|
||||||
"fontfaceobserver": "^2.1.0",
|
"fontfaceobserver": "^2.1.0",
|
||||||
"fuse.js": "^3.4.5",
|
"fuse.js": "^3.4.5",
|
||||||
|
"fusioncharts": "^3.15.0-sr.1",
|
||||||
"history": "^4.10.1",
|
"history": "^4.10.1",
|
||||||
"husky": "^3.0.5",
|
"husky": "^3.0.5",
|
||||||
"interweave": "^12.1.1",
|
"interweave": "^12.1.1",
|
||||||
|
|
@ -67,6 +68,7 @@
|
||||||
"react-dnd-html5-backend": "^9.3.4",
|
"react-dnd-html5-backend": "^9.3.4",
|
||||||
"react-dnd-touch-backend": "^9.4.0",
|
"react-dnd-touch-backend": "^9.4.0",
|
||||||
"react-dom": "^16.7.0",
|
"react-dom": "^16.7.0",
|
||||||
|
"react-fusioncharts": "^3.1.2",
|
||||||
"react-helmet": "^5.2.1",
|
"react-helmet": "^5.2.1",
|
||||||
"react-redux": "^7.1.3",
|
"react-redux": "^7.1.3",
|
||||||
"react-router": "^5.1.2",
|
"react-router": "^5.1.2",
|
||||||
|
|
@ -157,8 +159,7 @@
|
||||||
},
|
},
|
||||||
"husky": {
|
"husky": {
|
||||||
"hooks": {
|
"hooks": {
|
||||||
"pre-commit": "lint-staged",
|
"pre-commit": "lint-staged"
|
||||||
"pre-push": "yarn run test"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -62,12 +62,12 @@ export interface RestAction {
|
||||||
cacheResponse?: string;
|
cacheResponse?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type PaginationField = "PREV" | "NEXT" | undefined;
|
export type PaginationField = "PREV" | "NEXT";
|
||||||
|
|
||||||
export interface ExecuteActionRequest extends APIRequest {
|
export interface ExecuteActionRequest extends APIRequest {
|
||||||
action: Pick<RestAction, "id"> | Omit<RestAction, "id">;
|
action: Pick<RestAction, "id"> | Omit<RestAction, "id">;
|
||||||
params?: Property[];
|
params?: Property[];
|
||||||
paginationField: PaginationField;
|
paginationField?: PaginationField;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ExecuteActionResponse extends ApiResponse {
|
export interface ExecuteActionResponse extends ApiResponse {
|
||||||
|
|
@ -80,7 +80,7 @@ export interface ActionApiResponse {
|
||||||
data: {
|
data: {
|
||||||
body: object;
|
body: object;
|
||||||
headers: Record<string, string[]>;
|
headers: Record<string, string[]>;
|
||||||
statusCode: string | number;
|
statusCode: string;
|
||||||
};
|
};
|
||||||
clientMeta: {
|
clientMeta: {
|
||||||
duration: string;
|
duration: string;
|
||||||
|
|
@ -91,7 +91,7 @@ export interface ActionApiResponse {
|
||||||
export interface ActionResponse {
|
export interface ActionResponse {
|
||||||
body: object;
|
body: object;
|
||||||
headers: Record<string, string[]>;
|
headers: Record<string, string[]>;
|
||||||
statusCode: string | number;
|
statusCode: string;
|
||||||
duration: string;
|
duration: string;
|
||||||
size: string;
|
size: string;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
3
app/client/src/assets/icons/widget/chart.svg
Normal file
3
app/client/src/assets/icons/widget/chart.svg
Normal 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 |
|
|
@ -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;
|
||||||
|
|
@ -32,7 +32,7 @@ class FilePickerComponent extends React.Component<
|
||||||
<BaseButton
|
<BaseButton
|
||||||
accent="primary"
|
accent="primary"
|
||||||
filled
|
filled
|
||||||
className={this.props.isLoading ? "bp3-skeleton" : ""}
|
loading={this.props.isLoading}
|
||||||
text={label}
|
text={label}
|
||||||
onClick={this.openModal}
|
onClick={this.openModal}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -26,22 +26,22 @@ class CheckboxComponent extends React.Component<CheckboxComponentProps> {
|
||||||
className={
|
className={
|
||||||
this.props.isLoading ? "bp3-skeleton" : Classes.RUNNING_TEXT
|
this.props.isLoading ? "bp3-skeleton" : Classes.RUNNING_TEXT
|
||||||
}
|
}
|
||||||
defaultChecked={this.props.defaultCheckedState}
|
|
||||||
onChange={this.onCheckChange}
|
onChange={this.onCheckChange}
|
||||||
disabled={this.props.isDisabled}
|
disabled={this.props.isDisabled}
|
||||||
|
checked={this.props.isChecked}
|
||||||
/>
|
/>
|
||||||
</CheckboxContainer>
|
</CheckboxContainer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
onCheckChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
onCheckChange = () => {
|
||||||
this.props.onCheckChange(event.target.value === "true");
|
this.props.onCheckChange(!this.props.isChecked);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CheckboxComponentProps extends ComponentProps {
|
export interface CheckboxComponentProps extends ComponentProps {
|
||||||
label: string;
|
label: string;
|
||||||
defaultCheckedState: boolean;
|
isChecked: boolean;
|
||||||
onCheckChange: (isChecked: boolean) => void;
|
onCheckChange: (isChecked: boolean) => void;
|
||||||
isLoading: boolean;
|
isLoading: boolean;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,15 +8,39 @@ import moment from "moment-timezone";
|
||||||
import "../../../../node_modules/@blueprintjs/datetime/lib/css/blueprint-datetime.css";
|
import "../../../../node_modules/@blueprintjs/datetime/lib/css/blueprint-datetime.css";
|
||||||
import { DatePickerType } from "widgets/DatePickerWidget";
|
import { DatePickerType } from "widgets/DatePickerWidget";
|
||||||
import { WIDGET_PADDING } from "constants/WidgetConstants";
|
import { WIDGET_PADDING } from "constants/WidgetConstants";
|
||||||
|
import { Colors } from "constants/Colors";
|
||||||
|
|
||||||
const StyledControlGroup = styled(ControlGroup)`
|
const StyledControlGroup = styled(ControlGroup)`
|
||||||
&&& {
|
&&& {
|
||||||
|
.${Classes.INPUT} {
|
||||||
|
box-shadow: none;
|
||||||
|
border: 1px solid;
|
||||||
|
border-color: ${Colors.GEYSER_LIGHT};
|
||||||
|
border-radius: ${props => props.theme.radii[1]}px;
|
||||||
|
width: 100%;
|
||||||
|
height: inherit;
|
||||||
|
align-items: center;
|
||||||
|
&:active {
|
||||||
|
border-color: ${Colors.HIT_GRAY};
|
||||||
|
}
|
||||||
|
&:focus {
|
||||||
|
border-color: ${Colors.MYSTIC};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.${Classes.INPUT_GROUP} {
|
||||||
|
display: block;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
.${Classes.CONTROL_GROUP} {
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
label {
|
label {
|
||||||
${labelStyle}
|
${labelStyle}
|
||||||
flex: 0 1 30%;
|
flex: 0 1 30%;
|
||||||
|
margin: 7px ${WIDGET_PADDING * 2}px 0 0;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
margin: 0 ${WIDGET_PADDING * 2}px 0 0;
|
align-self: flex-start;
|
||||||
align-self: center;
|
max-width: calc(30% - ${WIDGET_PADDING}px);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
@ -47,14 +71,14 @@ class DatePickerComponent extends React.Component<DatePickerComponentProps> {
|
||||||
this.props.enableTimePicker
|
this.props.enableTimePicker
|
||||||
? {
|
? {
|
||||||
useAmPm: true,
|
useAmPm: true,
|
||||||
value: this.props.selectedDate || this.props.defaultDate,
|
value: this.props.selectedDate,
|
||||||
showArrowButtons: true,
|
showArrowButtons: true,
|
||||||
}
|
}
|
||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
closeOnSelection={true}
|
closeOnSelection={true}
|
||||||
onChange={this.onDateSelected}
|
onChange={this.onDateSelected}
|
||||||
value={this.props.selectedDate || this.props.defaultDate}
|
value={this.props.selectedDate}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<DateRangeInput
|
<DateRangeInput
|
||||||
|
|
@ -97,7 +121,6 @@ class DatePickerComponent extends React.Component<DatePickerComponentProps> {
|
||||||
|
|
||||||
export interface DatePickerComponentProps extends ComponentProps {
|
export interface DatePickerComponentProps extends ComponentProps {
|
||||||
label: string;
|
label: string;
|
||||||
defaultDate?: Date;
|
|
||||||
dateFormat: string;
|
dateFormat: string;
|
||||||
enableTimePicker?: boolean;
|
enableTimePicker?: boolean;
|
||||||
selectedDate?: Date;
|
selectedDate?: Date;
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import _ from "lodash";
|
||||||
import { WIDGET_PADDING } from "constants/WidgetConstants";
|
import { WIDGET_PADDING } from "constants/WidgetConstants";
|
||||||
import "../../../../node_modules/@blueprintjs/select/lib/css/blueprint-select.css";
|
import "../../../../node_modules/@blueprintjs/select/lib/css/blueprint-select.css";
|
||||||
import styled, {
|
import styled, {
|
||||||
|
createGlobalStyle,
|
||||||
labelStyle,
|
labelStyle,
|
||||||
BlueprintCSSTransform,
|
BlueprintCSSTransform,
|
||||||
BlueprintInputTransform,
|
BlueprintInputTransform,
|
||||||
|
|
@ -79,53 +80,61 @@ const StyledControlGroup = styled(ControlGroup)<{ haslabel: string }>`
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const DropdownContainer = styled.div`
|
const DropdownStyles = createGlobalStyle`
|
||||||
${BlueprintCSSTransform}
|
.select-popover-wrapper {
|
||||||
&&&& .${Classes.MENU_ITEM} {
|
|
||||||
border-radius: ${props => props.theme.radii[1]}px;
|
|
||||||
&:hover{
|
|
||||||
background: ${Colors.POLAR};
|
|
||||||
}
|
|
||||||
&.${Classes.ACTIVE} {
|
|
||||||
background: ${Colors.POLAR};
|
|
||||||
color: ${props => props.theme.colors.textDefault};
|
|
||||||
position:relative;
|
|
||||||
&.single-select{
|
|
||||||
&:before{
|
|
||||||
left: 0;
|
|
||||||
top: -2px;
|
|
||||||
position: absolute;
|
|
||||||
content: "";
|
|
||||||
background: ${props => props.theme.colors.primary};
|
|
||||||
border-radius: 4px 0 0 4px;
|
|
||||||
width: 4px;
|
|
||||||
height:100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&& .${Classes.POPOVER} {
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border-radius: ${props => props.theme.radii[1]}px;
|
border-radius: ${props => props.theme.radii[1]}px;
|
||||||
box-shadow: 0px 2px 4px rgba(67, 70, 74, 0.14);
|
box-shadow: 0px 2px 4px rgba(67, 70, 74, 0.14);
|
||||||
padding: ${props => props.theme.spaces[3]}px;
|
padding: ${props => props.theme.spaces[3]}px;
|
||||||
background: white;
|
background: white;
|
||||||
}
|
&& .${Classes.MENU} {
|
||||||
|
max-width: 100%;
|
||||||
&& .${Classes.POPOVER_WRAPPER} {
|
max-height: auto;
|
||||||
position:relative;
|
}
|
||||||
.${Classes.OVERLAY} {
|
&&&& .${Classes.MENU_ITEM} {
|
||||||
position: absolute;
|
border-radius: ${props => props.theme.radii[1]}px;
|
||||||
.${Classes.TRANSITION_CONTAINER} {
|
&:hover{
|
||||||
width: 100%;
|
background: ${Colors.POLAR};
|
||||||
|
}
|
||||||
|
&.${Classes.ACTIVE} {
|
||||||
|
background: ${Colors.POLAR};
|
||||||
|
color: ${props => props.theme.colors.textDefault};
|
||||||
|
position:relative;
|
||||||
|
&.single-select{
|
||||||
|
&:before{
|
||||||
|
left: 0;
|
||||||
|
top: -2px;
|
||||||
|
position: absolute;
|
||||||
|
content: "";
|
||||||
|
background: ${props => props.theme.colors.primary};
|
||||||
|
border-radius: 4px 0 0 4px;
|
||||||
|
width: 4px;
|
||||||
|
height:100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.${Classes.CONTROL} .${Classes.CONTROL_INDICATOR} {
|
||||||
|
background: white;
|
||||||
|
box-shadow: none;
|
||||||
|
border-width: 2px;
|
||||||
|
border-style: solid;
|
||||||
|
border-color: ${Colors.GEYSER};
|
||||||
|
&::before {
|
||||||
|
width: auto;
|
||||||
|
height: 1em;
|
||||||
|
}&
|
||||||
|
}
|
||||||
|
.${Classes.CONTROL} input:checked ~ .${Classes.CONTROL_INDICATOR} {
|
||||||
|
background: ${props => props.theme.colors.primary};
|
||||||
|
color: ${props => props.theme.colors.textOnDarkBG};
|
||||||
|
border-color: ${props => props.theme.colors.primary};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&& .${Classes.MENU} {
|
`;
|
||||||
max-width: 100%;
|
|
||||||
max-height: auto;
|
const DropdownContainer = styled.div`
|
||||||
}
|
${BlueprintCSSTransform}
|
||||||
width: 100%;
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const StyledMultiDropDown = styled(MultiDropDown)`
|
const StyledMultiDropDown = styled(MultiDropDown)`
|
||||||
|
|
@ -169,24 +178,6 @@ const StyledMultiDropDown = styled(MultiDropDown)`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&&&& {
|
|
||||||
.${Classes.CONTROL} .${Classes.CONTROL_INDICATOR} {
|
|
||||||
background: white;
|
|
||||||
box-shadow: none;
|
|
||||||
border-width: 2px;
|
|
||||||
border-style: solid;
|
|
||||||
border-color: ${Colors.GEYSER};
|
|
||||||
&::before {
|
|
||||||
width: auto;
|
|
||||||
height: 1em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.${Classes.CONTROL} input:checked ~ .${Classes.CONTROL_INDICATOR} {
|
|
||||||
background: ${props => props.theme.colors.primary};
|
|
||||||
color: ${props => props.theme.colors.textOnDarkBG};
|
|
||||||
border-color: ${props => props.theme.colors.primary};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const StyledCheckbox = styled(Checkbox)`
|
const StyledCheckbox = styled(Checkbox)`
|
||||||
|
|
@ -204,6 +195,7 @@ class DropDownComponent extends React.Component<DropDownComponentProps> {
|
||||||
: [];
|
: [];
|
||||||
return (
|
return (
|
||||||
<DropdownContainer>
|
<DropdownContainer>
|
||||||
|
<DropdownStyles />
|
||||||
<StyledControlGroup
|
<StyledControlGroup
|
||||||
fill
|
fill
|
||||||
haslabel={!!this.props.label ? "true" : "false"}
|
haslabel={!!this.props.label ? "true" : "false"}
|
||||||
|
|
@ -228,14 +220,16 @@ class DropDownComponent extends React.Component<DropDownComponentProps> {
|
||||||
onItemSelect={this.onItemSelect}
|
onItemSelect={this.onItemSelect}
|
||||||
popoverProps={{
|
popoverProps={{
|
||||||
minimal: true,
|
minimal: true,
|
||||||
usePortal: false,
|
usePortal: true,
|
||||||
|
popoverClassName: "select-popover-wrapper",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
rightIcon={IconNames.CHEVRON_DOWN}
|
rightIcon={IconNames.CHEVRON_DOWN}
|
||||||
text={
|
text={
|
||||||
!_.isEmpty(this.props.options) &&
|
!_.isEmpty(this.props.options) &&
|
||||||
this.props.selectedIndex !== undefined
|
this.props.selectedIndex !== undefined &&
|
||||||
|
this.props.selectedIndex > -1
|
||||||
? this.props.options[this.props.selectedIndex].label
|
? this.props.options[this.props.selectedIndex].label
|
||||||
: "-- Empty --"
|
: "-- Empty --"
|
||||||
}
|
}
|
||||||
|
|
@ -258,9 +252,10 @@ class DropDownComponent extends React.Component<DropDownComponentProps> {
|
||||||
onItemSelect={this.onItemSelect}
|
onItemSelect={this.onItemSelect}
|
||||||
popoverProps={{
|
popoverProps={{
|
||||||
minimal: true,
|
minimal: true,
|
||||||
usePortal: false,
|
usePortal: true,
|
||||||
|
popoverClassName: "select-popover-wrapper",
|
||||||
}}
|
}}
|
||||||
></StyledMultiDropDown>
|
/>
|
||||||
)}
|
)}
|
||||||
</StyledControlGroup>
|
</StyledControlGroup>
|
||||||
</DropdownContainer>
|
</DropdownContainer>
|
||||||
|
|
|
||||||
|
|
@ -27,8 +27,9 @@ import { INPUT_WIDGET_DEFAULT_VALIDATION_ERROR } from "constants/messages";
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const InputComponentWrapper = styled(props => (
|
const InputComponentWrapper = styled(props => (
|
||||||
<ControlGroup {..._.omit(props, ["hasError"])} />
|
<ControlGroup {..._.omit(props, ["hasError", "numeric"])} />
|
||||||
))<{
|
))<{
|
||||||
|
numeric: boolean;
|
||||||
multiline: string;
|
multiline: string;
|
||||||
hasError: boolean;
|
hasError: boolean;
|
||||||
}>`
|
}>`
|
||||||
|
|
@ -41,6 +42,13 @@ const InputComponentWrapper = styled(props => (
|
||||||
border-radius: ${props => props.theme.radii[1]}px;
|
border-radius: ${props => props.theme.radii[1]}px;
|
||||||
height: ${props => (props.multiline === "true" ? "100%" : "inherit")};
|
height: ${props => (props.multiline === "true" ? "100%" : "inherit")};
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
${props =>
|
||||||
|
props.numeric &&
|
||||||
|
`
|
||||||
|
border-top-right-radius: 0px;
|
||||||
|
border-bottom-right-radius: 0px;
|
||||||
|
border-right-width: 0px;
|
||||||
|
`}
|
||||||
&:active {
|
&:active {
|
||||||
border-color: ${({ hasError }) =>
|
border-color: ${({ hasError }) =>
|
||||||
hasError ? IntentColors.danger : Colors.HIT_GRAY};
|
hasError ? IntentColors.danger : Colors.HIT_GRAY};
|
||||||
|
|
@ -138,7 +146,6 @@ class InputComponent extends React.Component<
|
||||||
disabled={this.props.disabled}
|
disabled={this.props.disabled}
|
||||||
intent={this.props.intent}
|
intent={this.props.intent}
|
||||||
className={this.props.isLoading ? "bp3-skeleton" : Classes.FILL}
|
className={this.props.isLoading ? "bp3-skeleton" : Classes.FILL}
|
||||||
defaultValue={this.props.defaultValue}
|
|
||||||
onValueChange={this.onNumberChange}
|
onValueChange={this.onNumberChange}
|
||||||
leftIcon={
|
leftIcon={
|
||||||
this.props.inputType === "PHONE_NUMBER" ? "phone" : this.props.leftIcon
|
this.props.inputType === "PHONE_NUMBER" ? "phone" : this.props.leftIcon
|
||||||
|
|
@ -150,7 +157,7 @@ class InputComponent extends React.Component<
|
||||||
onBlur={() => this.setFocusState(false)}
|
onBlur={() => this.setFocusState(false)}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
private textAreaInputComponent = (
|
private textAreaInputComponent = () => (
|
||||||
<TextArea
|
<TextArea
|
||||||
value={this.props.value}
|
value={this.props.value}
|
||||||
placeholder={this.props.placeholder}
|
placeholder={this.props.placeholder}
|
||||||
|
|
@ -158,7 +165,6 @@ class InputComponent extends React.Component<
|
||||||
maxLength={this.props.maxChars}
|
maxLength={this.props.maxChars}
|
||||||
intent={this.props.intent}
|
intent={this.props.intent}
|
||||||
onChange={this.onTextChange}
|
onChange={this.onTextChange}
|
||||||
defaultValue={this.props.defaultValue}
|
|
||||||
className={this.props.isLoading ? "bp3-skeleton" : ""}
|
className={this.props.isLoading ? "bp3-skeleton" : ""}
|
||||||
growVertically={false}
|
growVertically={false}
|
||||||
onFocus={() => this.setFocusState(true)}
|
onFocus={() => this.setFocusState(true)}
|
||||||
|
|
@ -168,7 +174,7 @@ class InputComponent extends React.Component<
|
||||||
|
|
||||||
private textInputComponent = (isTextArea: boolean) =>
|
private textInputComponent = (isTextArea: boolean) =>
|
||||||
isTextArea ? (
|
isTextArea ? (
|
||||||
this.textAreaInputComponent
|
this.textAreaInputComponent()
|
||||||
) : (
|
) : (
|
||||||
<InputGroup
|
<InputGroup
|
||||||
value={this.props.value}
|
value={this.props.value}
|
||||||
|
|
@ -177,7 +183,6 @@ class InputComponent extends React.Component<
|
||||||
maxLength={this.props.maxChars}
|
maxLength={this.props.maxChars}
|
||||||
intent={this.props.intent}
|
intent={this.props.intent}
|
||||||
onChange={this.onTextChange}
|
onChange={this.onTextChange}
|
||||||
defaultValue={this.props.defaultValue}
|
|
||||||
className={this.props.isLoading ? "bp3-skeleton" : ""}
|
className={this.props.isLoading ? "bp3-skeleton" : ""}
|
||||||
rightElement={
|
rightElement={
|
||||||
this.props.inputType === "PASSWORD" ? (
|
this.props.inputType === "PASSWORD" ? (
|
||||||
|
|
@ -207,6 +212,7 @@ class InputComponent extends React.Component<
|
||||||
<InputComponentWrapper
|
<InputComponentWrapper
|
||||||
fill
|
fill
|
||||||
multiline={this.props.multiline.toString()}
|
multiline={this.props.multiline.toString()}
|
||||||
|
numeric={this.isNumberInputType(this.props.inputType)}
|
||||||
hasError={this.props.isInvalid}
|
hasError={this.props.isInvalid}
|
||||||
>
|
>
|
||||||
{this.props.label && (
|
{this.props.label && (
|
||||||
|
|
|
||||||
|
|
@ -17,15 +17,19 @@ const StyledControlGroup = styled(ControlGroup)`
|
||||||
& > label {
|
& > label {
|
||||||
${labelStyle}
|
${labelStyle}
|
||||||
flex: 0 1 30%;
|
flex: 0 1 30%;
|
||||||
align-self: flex-start;
|
margin: 7px ${WIDGET_PADDING * 2}px 0 0;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
margin: 0 ${WIDGET_PADDING * 2}px 0 0;
|
align-self: flex-start;
|
||||||
|
max-width: calc(30% - ${WIDGET_PADDING}px);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const StyledRadioGroup = styled(RadioGroup)`
|
const StyledRadioGroup = styled(RadioGroup)`
|
||||||
${BlueprintControlTransform};
|
${BlueprintControlTransform};
|
||||||
|
label {
|
||||||
|
margin: 7px ${WIDGET_PADDING * 2}px 0 0;
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
class RadioGroupComponent extends React.Component<RadioGroupComponentProps> {
|
class RadioGroupComponent extends React.Component<RadioGroupComponentProps> {
|
||||||
|
|
@ -44,11 +48,7 @@ class RadioGroupComponent extends React.Component<RadioGroupComponentProps> {
|
||||||
</Label>
|
</Label>
|
||||||
)}
|
)}
|
||||||
<StyledRadioGroup
|
<StyledRadioGroup
|
||||||
selectedValue={
|
selectedValue={this.props.selectedOptionValue}
|
||||||
this.props.selectedOptionValue === undefined
|
|
||||||
? this.props.defaultOptionValue
|
|
||||||
: this.props.selectedOptionValue
|
|
||||||
}
|
|
||||||
onChange={this.onRadioSelectionChange}
|
onChange={this.onRadioSelectionChange}
|
||||||
>
|
>
|
||||||
{this.props.options.map(option => {
|
{this.props.options.map(option => {
|
||||||
|
|
@ -77,7 +77,6 @@ export interface RadioGroupComponentProps extends ComponentProps {
|
||||||
onRadioSelectionChange: (updatedOptionValue: string) => void;
|
onRadioSelectionChange: (updatedOptionValue: string) => void;
|
||||||
selectedOptionValue: string;
|
selectedOptionValue: string;
|
||||||
isLoading: boolean;
|
isLoading: boolean;
|
||||||
defaultOptionValue: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default RadioGroupComponent;
|
export default RadioGroupComponent;
|
||||||
|
|
|
||||||
|
|
@ -318,7 +318,7 @@ class DynamicActionCreator extends React.Component<Props & ReduxStateProps> {
|
||||||
) => void,
|
) => void,
|
||||||
) => {
|
) => {
|
||||||
return (
|
return (
|
||||||
<div style={{ paddingLeft: 5 }}>
|
<div>
|
||||||
{selectedOption.arguments.map(arg => {
|
{selectedOption.arguments.map(arg => {
|
||||||
switch (arg.field) {
|
switch (arg.field) {
|
||||||
case "ACTION_SELECTOR_FIELD":
|
case "ACTION_SELECTOR_FIELD":
|
||||||
|
|
@ -328,6 +328,7 @@ class DynamicActionCreator extends React.Component<Props & ReduxStateProps> {
|
||||||
<StyledDropdown
|
<StyledDropdown
|
||||||
options={allOptions}
|
options={allOptions}
|
||||||
selectedValue={arg.getSelectedValue(value, false)}
|
selectedValue={arg.getSelectedValue(value, false)}
|
||||||
|
defaultText={"Select Action"}
|
||||||
onSelect={value =>
|
onSelect={value =>
|
||||||
handleUpdate(value, arg.valueChangeHandler)
|
handleUpdate(value, arg.valueChangeHandler)
|
||||||
}
|
}
|
||||||
|
|
@ -347,6 +348,7 @@ class DynamicActionCreator extends React.Component<Props & ReduxStateProps> {
|
||||||
<StyledDropdown
|
<StyledDropdown
|
||||||
options={this.props.pageNameDropdown}
|
options={this.props.pageNameDropdown}
|
||||||
selectedValue={arg.getSelectedValue(value, false)}
|
selectedValue={arg.getSelectedValue(value, false)}
|
||||||
|
defaultText={"Select Page"}
|
||||||
onSelect={value =>
|
onSelect={value =>
|
||||||
handleUpdate(value, arg.valueChangeHandler)
|
handleUpdate(value, arg.valueChangeHandler)
|
||||||
}
|
}
|
||||||
|
|
@ -355,14 +357,15 @@ class DynamicActionCreator extends React.Component<Props & ReduxStateProps> {
|
||||||
);
|
);
|
||||||
case "TEXT_FIELD":
|
case "TEXT_FIELD":
|
||||||
return (
|
return (
|
||||||
<React.Fragment key={arg.label}>
|
<ControlWrapper key={arg.label}>
|
||||||
|
<label>{arg.label}</label>
|
||||||
<InputText
|
<InputText
|
||||||
label={arg.label}
|
label={arg.label}
|
||||||
value={arg.getSelectedValue(value, false)}
|
value={arg.getSelectedValue(value, false)}
|
||||||
onChange={e => handleUpdate(e, arg.valueChangeHandler)}
|
onChange={e => handleUpdate(e, arg.valueChangeHandler)}
|
||||||
isValid={true}
|
isValid={true}
|
||||||
/>
|
/>
|
||||||
</React.Fragment>
|
</ControlWrapper>
|
||||||
);
|
);
|
||||||
case "ALERT_TYPE_SELECTOR_FIELD":
|
case "ALERT_TYPE_SELECTOR_FIELD":
|
||||||
return (
|
return (
|
||||||
|
|
@ -370,6 +373,7 @@ class DynamicActionCreator extends React.Component<Props & ReduxStateProps> {
|
||||||
<label>{arg.label}</label>
|
<label>{arg.label}</label>
|
||||||
<StyledDropdown
|
<StyledDropdown
|
||||||
options={ALERT_STYLE_OPTIONS}
|
options={ALERT_STYLE_OPTIONS}
|
||||||
|
defaultText={"Select type"}
|
||||||
selectedValue={arg.getSelectedValue(value, false)}
|
selectedValue={arg.getSelectedValue(value, false)}
|
||||||
onSelect={value =>
|
onSelect={value =>
|
||||||
handleUpdate(value, arg.valueChangeHandler)
|
handleUpdate(value, arg.valueChangeHandler)
|
||||||
|
|
@ -421,6 +425,7 @@ class DynamicActionCreator extends React.Component<Props & ReduxStateProps> {
|
||||||
<StyledDropdown
|
<StyledDropdown
|
||||||
options={actionOptions}
|
options={actionOptions}
|
||||||
selectedValue={topLevelFuncValue}
|
selectedValue={topLevelFuncValue}
|
||||||
|
defaultText={"Select"}
|
||||||
onSelect={value =>
|
onSelect={value =>
|
||||||
this.handleValueUpdate(value, handleTopLevelFuncUpdate)
|
this.handleValueUpdate(value, handleTopLevelFuncUpdate)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,27 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { Popover } from "@blueprintjs/core";
|
import { Popover } from "@blueprintjs/core";
|
||||||
import styled from "styled-components";
|
import styled, { createGlobalStyle } from "styled-components";
|
||||||
|
import { Colors } from "constants/Colors";
|
||||||
|
|
||||||
|
const TooltipStyles = createGlobalStyle`
|
||||||
|
.error-tooltip{
|
||||||
|
.bp3-popover {
|
||||||
|
.bp3-popover-arrow {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.bp3-popover-content {
|
||||||
|
padding: 8px;
|
||||||
|
color: ${Colors.RED};
|
||||||
|
text-align: center;
|
||||||
|
border-radius: 4px;
|
||||||
|
text-transform: initial;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
const Wrapper = styled.div`
|
const Wrapper = styled.div`
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
@ -10,21 +31,6 @@ const Wrapper = styled.div`
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
.bp3-popover {
|
|
||||||
.bp3-popover-arrow {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
.bp3-popover-content {
|
|
||||||
padding: 8px;
|
|
||||||
color: ${props => props.theme.colors.error};
|
|
||||||
text-align: center;
|
|
||||||
border-radius: 4px;
|
|
||||||
text-transform: initial;
|
|
||||||
font-weight: 500;
|
|
||||||
font-size: 12px;
|
|
||||||
line-height: 16px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
|
|
@ -36,16 +42,15 @@ interface Props {
|
||||||
const ErrorTooltip = (props: Props) => {
|
const ErrorTooltip = (props: Props) => {
|
||||||
return (
|
return (
|
||||||
<Wrapper>
|
<Wrapper>
|
||||||
|
<TooltipStyles />
|
||||||
<Popover
|
<Popover
|
||||||
autoFocus={true}
|
autoFocus={true}
|
||||||
canEscapeKeyClose={true}
|
canEscapeKeyClose={true}
|
||||||
content={props.message}
|
content={props.message}
|
||||||
position="bottom"
|
position="bottom"
|
||||||
isOpen={props.isOpen && !!props.message}
|
isOpen={props.isOpen && !!props.message}
|
||||||
usePortal={false}
|
usePortal
|
||||||
modifiers={{
|
portalClassName="error-tooltip"
|
||||||
offset: { offset: "0,0,-11px" },
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
{props.children}
|
{props.children}
|
||||||
</Popover>
|
</Popover>
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ import { IconNames } from "@blueprintjs/icons";
|
||||||
type ActionTypeDropdownProps = {
|
type ActionTypeDropdownProps = {
|
||||||
options: DropdownOption[];
|
options: DropdownOption[];
|
||||||
selectedValue: string;
|
selectedValue: string;
|
||||||
|
defaultText: string;
|
||||||
onSelect: (value: string) => void;
|
onSelect: (value: string) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -55,7 +56,9 @@ class StyledDropdown extends React.Component<ActionTypeDropdownProps> {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { selectedValue } = this.props;
|
const { selectedValue } = this.props;
|
||||||
let selectedOption = this.props.options[0];
|
let selectedOption = {
|
||||||
|
label: this.props.defaultText,
|
||||||
|
};
|
||||||
this.props.options.forEach(o => {
|
this.props.options.forEach(o => {
|
||||||
if (o.value === selectedValue) {
|
if (o.value === selectedValue) {
|
||||||
selectedOption = o;
|
selectedOption = o;
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ export interface ControlData {
|
||||||
id: string;
|
id: string;
|
||||||
label: string;
|
label: string;
|
||||||
propertyName: string;
|
propertyName: string;
|
||||||
|
isJSConvertible?: boolean;
|
||||||
controlType: ControlType;
|
controlType: ControlType;
|
||||||
propertyValue?: any;
|
propertyValue?: any;
|
||||||
isValid: boolean;
|
isValid: boolean;
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,9 @@ export function InputText(props: {
|
||||||
onChange: (event: React.ChangeEvent<HTMLTextAreaElement> | string) => void;
|
onChange: (event: React.ChangeEvent<HTMLTextAreaElement> | string) => void;
|
||||||
isValid: boolean;
|
isValid: boolean;
|
||||||
validationMessage?: string;
|
validationMessage?: string;
|
||||||
|
placeholder?: string;
|
||||||
}) {
|
}) {
|
||||||
const { validationMessage, value, isValid, onChange } = props;
|
const { validationMessage, value, isValid, onChange, placeholder } = props;
|
||||||
return (
|
return (
|
||||||
<StyledDynamicInput>
|
<StyledDynamicInput>
|
||||||
<DynamicAutocompleteInput
|
<DynamicAutocompleteInput
|
||||||
|
|
@ -26,6 +27,7 @@ export function InputText(props: {
|
||||||
}}
|
}}
|
||||||
theme={"DARK"}
|
theme={"DARK"}
|
||||||
singleLine={false}
|
singleLine={false}
|
||||||
|
placeholder={placeholder}
|
||||||
/>
|
/>
|
||||||
</StyledDynamicInput>
|
</StyledDynamicInput>
|
||||||
);
|
);
|
||||||
|
|
@ -33,7 +35,13 @@ export function InputText(props: {
|
||||||
|
|
||||||
class InputTextControl extends BaseControl<InputControlProps> {
|
class InputTextControl extends BaseControl<InputControlProps> {
|
||||||
render() {
|
render() {
|
||||||
const { validationMessage, propertyValue, isValid, label } = this.props;
|
const {
|
||||||
|
validationMessage,
|
||||||
|
propertyValue,
|
||||||
|
isValid,
|
||||||
|
label,
|
||||||
|
placeholderText,
|
||||||
|
} = this.props;
|
||||||
return (
|
return (
|
||||||
<InputText
|
<InputText
|
||||||
label={label}
|
label={label}
|
||||||
|
|
@ -41,6 +49,7 @@ class InputTextControl extends BaseControl<InputControlProps> {
|
||||||
onChange={this.onTextChange}
|
onChange={this.onTextChange}
|
||||||
isValid={isValid}
|
isValid={isValid}
|
||||||
validationMessage={validationMessage}
|
validationMessage={validationMessage}
|
||||||
|
placeholder={placeholderText}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,10 @@ const StyledOptionControlWrapper = styled(ControlWrapper)`
|
||||||
|
|
||||||
class OptionControl extends BaseControl<ControlProps> {
|
class OptionControl extends BaseControl<ControlProps> {
|
||||||
render() {
|
render() {
|
||||||
const options: DropdownOption[] = this.props.propertyValue || [{}];
|
const { propertyValue } = this.props;
|
||||||
|
const options: DropdownOption[] = Array.isArray(propertyValue)
|
||||||
|
? propertyValue
|
||||||
|
: [{}];
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
{options.map((option, index) => {
|
{options.map((option, index) => {
|
||||||
|
|
@ -77,13 +80,19 @@ class OptionControl extends BaseControl<ControlProps> {
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteOption = (index: number) => {
|
deleteOption = (index: number) => {
|
||||||
const options: DropdownOption[] = this.props.propertyValue.slice();
|
const { propertyValue } = this.props;
|
||||||
options.splice(index, 1);
|
const options: DropdownOption[] = Array.isArray(propertyValue)
|
||||||
this.updateProperty("options", options);
|
? propertyValue
|
||||||
|
: [{}];
|
||||||
|
const newOptions = options.filter((o, i) => i !== index);
|
||||||
|
this.updateProperty("options", newOptions);
|
||||||
};
|
};
|
||||||
|
|
||||||
updateOptionLabel = (index: number, updatedLabel: string) => {
|
updateOptionLabel = (index: number, updatedLabel: string) => {
|
||||||
const options: DropdownOption[] = this.props.propertyValue;
|
const { propertyValue } = this.props;
|
||||||
|
const options: DropdownOption[] = Array.isArray(propertyValue)
|
||||||
|
? propertyValue
|
||||||
|
: [{}];
|
||||||
this.updateProperty(
|
this.updateProperty(
|
||||||
"options",
|
"options",
|
||||||
options.map((option, optionIndex) => {
|
options.map((option, optionIndex) => {
|
||||||
|
|
@ -99,7 +108,10 @@ class OptionControl extends BaseControl<ControlProps> {
|
||||||
};
|
};
|
||||||
|
|
||||||
updateOptionValue = (index: number, updatedValue: string) => {
|
updateOptionValue = (index: number, updatedValue: string) => {
|
||||||
const options: DropdownOption[] = this.props.propertyValue;
|
const { propertyValue } = this.props;
|
||||||
|
const options: DropdownOption[] = Array.isArray(propertyValue)
|
||||||
|
? propertyValue
|
||||||
|
: [{}];
|
||||||
this.updateProperty(
|
this.updateProperty(
|
||||||
"options",
|
"options",
|
||||||
options.map((option, optionIndex) => {
|
options.map((option, optionIndex) => {
|
||||||
|
|
@ -115,9 +127,10 @@ class OptionControl extends BaseControl<ControlProps> {
|
||||||
};
|
};
|
||||||
|
|
||||||
addOption = () => {
|
addOption = () => {
|
||||||
const options: DropdownOption[] = this.props.propertyValue
|
const { propertyValue } = this.props;
|
||||||
? this.props.propertyValue.slice()
|
const options: DropdownOption[] = Array.isArray(propertyValue)
|
||||||
: [];
|
? propertyValue
|
||||||
|
: [{}];
|
||||||
options.push({ label: "", value: "" });
|
options.push({ label: "", value: "" });
|
||||||
this.updateProperty("options", options);
|
this.updateProperty("options", options);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -19,10 +19,3 @@ export type ControlType =
|
||||||
| "TIME_ZONE"
|
| "TIME_ZONE"
|
||||||
| "CODE_EDITOR"
|
| "CODE_EDITOR"
|
||||||
| "COLUMN_ACTION_SELECTOR";
|
| "COLUMN_ACTION_SELECTOR";
|
||||||
|
|
||||||
export const CONVERTIBLE_CONTROLS = [
|
|
||||||
"SWITCH",
|
|
||||||
"OPTION_INPUT",
|
|
||||||
"ACTION_SELECTOR",
|
|
||||||
"DATE_PICKER",
|
|
||||||
];
|
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ export type WidgetType =
|
||||||
| "RADIO_GROUP_WIDGET"
|
| "RADIO_GROUP_WIDGET"
|
||||||
| "FILE_PICKER_WIDGET"
|
| "FILE_PICKER_WIDGET"
|
||||||
| "INPUT_WIDGET"
|
| "INPUT_WIDGET"
|
||||||
|
| "CHART_WIDGET"
|
||||||
| "SWITCH_WIDGET"
|
| "SWITCH_WIDGET"
|
||||||
| "FORM_WIDGET"
|
| "FORM_WIDGET"
|
||||||
| "FORM_BUTTON_WIDGET";
|
| "FORM_BUTTON_WIDGET";
|
||||||
|
|
@ -28,6 +29,7 @@ export const WidgetTypes: { [id: string]: WidgetType } = {
|
||||||
DROP_DOWN_WIDGET: "DROP_DOWN_WIDGET",
|
DROP_DOWN_WIDGET: "DROP_DOWN_WIDGET",
|
||||||
CHECKBOX_WIDGET: "CHECKBOX_WIDGET",
|
CHECKBOX_WIDGET: "CHECKBOX_WIDGET",
|
||||||
RADIO_GROUP_WIDGET: "RADIO_GROUP_WIDGET",
|
RADIO_GROUP_WIDGET: "RADIO_GROUP_WIDGET",
|
||||||
|
CHART_WIDGET: "CHART_WIDGET",
|
||||||
FORM_WIDGET: "FORM_WIDGET",
|
FORM_WIDGET: "FORM_WIDGET",
|
||||||
FORM_BUTTON_WIDGET: "FORM_BUTTON_WIDGET",
|
FORM_BUTTON_WIDGET: "FORM_BUTTON_WIDGET",
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,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",
|
||||||
|
CHART_DATA: "CHART_DATA",
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ValidationResponse = {
|
export type ValidationResponse = {
|
||||||
|
|
|
||||||
|
|
@ -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 TextIcon } from "assets/icons/widget/text.svg";
|
||||||
import { ReactComponent as ImageIcon } from "assets/icons/widget/image.svg";
|
import { ReactComponent as ImageIcon } from "assets/icons/widget/image.svg";
|
||||||
import { ReactComponent as FilePickerIcon } from "assets/icons/widget/filepicker.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";
|
import { ReactComponent as FormIcon } from "assets/icons/widget/form.svg";
|
||||||
|
|
||||||
/* eslint-disable react/display-name */
|
/* eslint-disable react/display-name */
|
||||||
|
|
@ -91,6 +92,11 @@ export const WidgetIcons: {
|
||||||
<FilePickerIcon />
|
<FilePickerIcon />
|
||||||
</IconWrapper>
|
</IconWrapper>
|
||||||
),
|
),
|
||||||
|
CHART_WIDGET: (props: IconProps) => (
|
||||||
|
<IconWrapper {...props}>
|
||||||
|
<ChartIcon />
|
||||||
|
</IconWrapper>
|
||||||
|
),
|
||||||
FORM_WIDGET: (props: IconProps) => (
|
FORM_WIDGET: (props: IconProps) => (
|
||||||
<IconWrapper {...props}>
|
<IconWrapper {...props}>
|
||||||
<FormIcon />
|
<FormIcon />
|
||||||
|
|
|
||||||
|
|
@ -102,7 +102,7 @@ export default class RealmExecutor implements JSExecutor {
|
||||||
triggers,
|
triggers,
|
||||||
};
|
};
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(`Error: "${e.message}" when evaluating {{${sourceText}}}`);
|
// console.error(`Error: "${e.message}" when evaluating {{${sourceText}}}`);
|
||||||
return { result: undefined, triggers: [] };
|
return { result: undefined, triggers: [] };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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",
|
name: "propertyPane",
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,6 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
|
||||||
rows: 1,
|
rows: 1,
|
||||||
columns: 8,
|
columns: 8,
|
||||||
widgetName: "Input",
|
widgetName: "Input",
|
||||||
text: "",
|
|
||||||
},
|
},
|
||||||
SWITCH_WIDGET: {
|
SWITCH_WIDGET: {
|
||||||
isOn: false,
|
isOn: false,
|
||||||
|
|
@ -119,7 +118,6 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
|
||||||
{ label: "Option 5", value: "5" },
|
{ label: "Option 5", value: "5" },
|
||||||
],
|
],
|
||||||
widgetName: "Dropdown",
|
widgetName: "Dropdown",
|
||||||
selectedIndex: 0,
|
|
||||||
},
|
},
|
||||||
CHECKBOX_WIDGET: {
|
CHECKBOX_WIDGET: {
|
||||||
rows: 1,
|
rows: 1,
|
||||||
|
|
@ -156,6 +154,45 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
|
||||||
widgetName: "FilePicker",
|
widgetName: "FilePicker",
|
||||||
isDefaultClickDisabled: true,
|
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: {
|
FORM_BUTTON_WIDGET: {
|
||||||
rows: 1,
|
rows: 1,
|
||||||
columns: 3,
|
columns: 3,
|
||||||
|
|
|
||||||
|
|
@ -96,6 +96,11 @@ const WidgetSidebarResponse: {
|
||||||
widgetCardName: "Table",
|
widgetCardName: "Table",
|
||||||
key: generateReactKey(),
|
key: generateReactKey(),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
type: "CHART_WIDGET",
|
||||||
|
widgetCardName: "Chart",
|
||||||
|
key: generateReactKey(),
|
||||||
|
},
|
||||||
],
|
],
|
||||||
["Layout widgets"]: [
|
["Layout widgets"]: [
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ interface ReduxStateProps {
|
||||||
interface ReduxActionProps {
|
interface ReduxActionProps {
|
||||||
submitForm: (name: string) => void;
|
submitForm: (name: string) => void;
|
||||||
createAction: (values: RestAction) => void;
|
createAction: (values: RestAction) => void;
|
||||||
runAction: (id: string, paginationField: PaginationField) => void;
|
runAction: (id: string, paginationField?: PaginationField) => void;
|
||||||
deleteAction: (id: string, name: string) => void;
|
deleteAction: (id: string, name: string) => void;
|
||||||
updateAction: (data: RestAction) => void;
|
updateAction: (data: RestAction) => void;
|
||||||
}
|
}
|
||||||
|
|
@ -158,7 +158,7 @@ const mapStateToProps = (state: AppState): ReduxStateProps => ({
|
||||||
const mapDispatchToProps = (dispatch: any): ReduxActionProps => ({
|
const mapDispatchToProps = (dispatch: any): ReduxActionProps => ({
|
||||||
submitForm: (name: string) => dispatch(submit(name)),
|
submitForm: (name: string) => dispatch(submit(name)),
|
||||||
createAction: (action: RestAction) => dispatch(createActionRequest(action)),
|
createAction: (action: RestAction) => dispatch(createActionRequest(action)),
|
||||||
runAction: (id: string, paginationField: PaginationField) =>
|
runAction: (id: string, paginationField?: PaginationField) =>
|
||||||
dispatch(runApiAction(id, paginationField)),
|
dispatch(runApiAction(id, paginationField)),
|
||||||
deleteAction: (id: string, name: string) =>
|
deleteAction: (id: string, name: string) =>
|
||||||
dispatch(deleteAction({ id, name })),
|
dispatch(deleteAction({ id, name })),
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import { CONVERTIBLE_CONTROLS } from "constants/PropertyControlConstants";
|
|
||||||
import {
|
import {
|
||||||
ControlPropertyLabelContainer,
|
ControlPropertyLabelContainer,
|
||||||
ControlWrapper,
|
ControlWrapper,
|
||||||
|
|
@ -54,7 +53,7 @@ const PropertyControl = (props: Props) => {
|
||||||
["dynamicProperties", propertyName],
|
["dynamicProperties", propertyName],
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
const isConvertible = CONVERTIBLE_CONTROLS.indexOf(config.controlType) > -1;
|
const isConvertible = !!propertyConfig.isJSConvertible;
|
||||||
const className = propertyConfig.label
|
const className = propertyConfig.label
|
||||||
.split(" ")
|
.split(" ")
|
||||||
.join("")
|
.join("")
|
||||||
|
|
|
||||||
|
|
@ -9,13 +9,14 @@ import { ImageWidgetProps } from "widgets/ImageWidget";
|
||||||
import { InputWidgetProps } from "widgets/InputWidget";
|
import { InputWidgetProps } from "widgets/InputWidget";
|
||||||
import { SwitchWidgetProps } from "widgets/SwitchWidget";
|
import { SwitchWidgetProps } from "widgets/SwitchWidget";
|
||||||
import { SpinnerWidgetProps } from "widgets/SpinnerWidget";
|
import { SpinnerWidgetProps } from "widgets/SpinnerWidget";
|
||||||
import { DatePickerWidgetProps } from "widgets/DatePickerWidget";
|
import { DatePickerWidgetProps } from "../../widgets/DatePickerWidget";
|
||||||
import { TableWidgetProps } from "widgets/TableWidget";
|
import { TableWidgetProps } from "../../widgets/TableWidget";
|
||||||
import { DropdownWidgetProps } from "widgets/DropdownWidget";
|
import { DropdownWidgetProps } from "../../widgets/DropdownWidget";
|
||||||
import { CheckboxWidgetProps } from "widgets/CheckboxWidget";
|
import { CheckboxWidgetProps } from "../../widgets/CheckboxWidget";
|
||||||
import { RadioGroupWidgetProps } from "widgets/RadioGroupWidget";
|
import { RadioGroupWidgetProps } from "../../widgets/RadioGroupWidget";
|
||||||
import { AlertWidgetProps } from "widgets/AlertWidget";
|
import { AlertWidgetProps } from "../../widgets/AlertWidget";
|
||||||
import { FilePickerWidgetProps } from "widgets/FilepickerWidget";
|
import { FilePickerWidgetProps } from "../../widgets/FilepickerWidget";
|
||||||
|
import { ChartWidgetProps } from "../../widgets/ChartWidget";
|
||||||
import { FormWidgetProps } from "widgets/FormWidget";
|
import { FormWidgetProps } from "widgets/FormWidget";
|
||||||
import { FormButtonWidgetProps } from "widgets/FormButtonWidget";
|
import { FormButtonWidgetProps } from "widgets/FormButtonWidget";
|
||||||
|
|
||||||
|
|
@ -53,6 +54,7 @@ export interface WidgetConfigReducerState {
|
||||||
RADIO_GROUP_WIDGET: Partial<RadioGroupWidgetProps> & WidgetConfigProps;
|
RADIO_GROUP_WIDGET: Partial<RadioGroupWidgetProps> & WidgetConfigProps;
|
||||||
ALERT_WIDGET: Partial<AlertWidgetProps> & WidgetConfigProps;
|
ALERT_WIDGET: Partial<AlertWidgetProps> & WidgetConfigProps;
|
||||||
FILE_PICKER_WIDGET: Partial<FilePickerWidgetProps> & WidgetConfigProps;
|
FILE_PICKER_WIDGET: Partial<FilePickerWidgetProps> & WidgetConfigProps;
|
||||||
|
CHART_WIDGET: Partial<ChartWidgetProps> & WidgetConfigProps;
|
||||||
FORM_WIDGET: Partial<FormWidgetProps> & WidgetConfigProps;
|
FORM_WIDGET: Partial<FormWidgetProps> & WidgetConfigProps;
|
||||||
FORM_BUTTON_WIDGET: Partial<FormButtonWidgetProps> & WidgetConfigProps;
|
FORM_BUTTON_WIDGET: Partial<FormButtonWidgetProps> & WidgetConfigProps;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -38,12 +38,12 @@ import {
|
||||||
deleteActionSuccess,
|
deleteActionSuccess,
|
||||||
executeApiActionRequest,
|
executeApiActionRequest,
|
||||||
executeApiActionSuccess,
|
executeApiActionSuccess,
|
||||||
|
fetchActionsForPageSuccess,
|
||||||
FetchActionsPayload,
|
FetchActionsPayload,
|
||||||
moveActionError,
|
moveActionError,
|
||||||
moveActionSuccess,
|
moveActionSuccess,
|
||||||
runApiAction,
|
runApiAction,
|
||||||
updateActionSuccess,
|
updateActionSuccess,
|
||||||
fetchActionsForPageSuccess,
|
|
||||||
} from "actions/actionActions";
|
} from "actions/actionActions";
|
||||||
import {
|
import {
|
||||||
getDynamicBindings,
|
getDynamicBindings,
|
||||||
|
|
@ -82,11 +82,20 @@ export const getAction = (
|
||||||
return action ? action.config : undefined;
|
return action ? action.config : undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
const createActionResponse = (response: ActionApiResponse): ActionResponse => ({
|
const createActionSuccessResponse = (
|
||||||
|
response: ActionApiResponse,
|
||||||
|
): ActionResponse => ({
|
||||||
...response.data,
|
...response.data,
|
||||||
...response.clientMeta,
|
...response.clientMeta,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const isErrorResponse = (response: ActionApiResponse) => {
|
||||||
|
return (
|
||||||
|
(response.responseMeta && response.responseMeta.error) ||
|
||||||
|
!/2\d\d/.test(response.data.statusCode)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
function getCurrentPageNameByActionId(
|
function getCurrentPageNameByActionId(
|
||||||
state: AppState,
|
state: AppState,
|
||||||
actionId: string,
|
actionId: string,
|
||||||
|
|
@ -102,8 +111,7 @@ function getPageNameByPageId(state: AppState, pageId: string): string {
|
||||||
const page = state.entities.pageList.pages.find(
|
const page = state.entities.pageList.pages.find(
|
||||||
page => page.pageId === pageId,
|
page => page.pageId === pageId,
|
||||||
);
|
);
|
||||||
const pageName = page ? page.pageName : "";
|
return page ? page.pageName : "";
|
||||||
return pageName;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const createActionErrorResponse = (
|
const createActionErrorResponse = (
|
||||||
|
|
@ -111,7 +119,7 @@ const createActionErrorResponse = (
|
||||||
): ActionResponse => ({
|
): ActionResponse => ({
|
||||||
body: response.responseMeta.error || { error: "Error" },
|
body: response.responseMeta.error || { error: "Error" },
|
||||||
statusCode: response.responseMeta.error
|
statusCode: response.responseMeta.error
|
||||||
? response.responseMeta.error.code
|
? response.responseMeta.error.code.toString()
|
||||||
: "Error",
|
: "Error",
|
||||||
headers: {},
|
headers: {},
|
||||||
duration: "0",
|
duration: "0",
|
||||||
|
|
@ -157,7 +165,7 @@ export function* getActionParams(jsonPathKeys: string[] | undefined) {
|
||||||
// });
|
// });
|
||||||
// }
|
// }
|
||||||
|
|
||||||
export function* executeAPIQueryActionSaga(
|
export function* executeActionSaga(
|
||||||
apiAction: RunActionPayload,
|
apiAction: RunActionPayload,
|
||||||
event: ExecuteActionPayloadEvent,
|
event: ExecuteActionPayloadEvent,
|
||||||
) {
|
) {
|
||||||
|
|
@ -180,9 +188,8 @@ export function* executeAPIQueryActionSaga(
|
||||||
const response: ActionApiResponse = yield ActionAPI.executeAction(
|
const response: ActionApiResponse = yield ActionAPI.executeAction(
|
||||||
executeActionRequest,
|
executeActionRequest,
|
||||||
);
|
);
|
||||||
let payload = createActionResponse(response);
|
if (isErrorResponse(response)) {
|
||||||
if (response.responseMeta && response.responseMeta.error) {
|
const payload = createActionErrorResponse(response);
|
||||||
payload = createActionErrorResponse(response);
|
|
||||||
if (onError) {
|
if (onError) {
|
||||||
yield put(
|
yield put(
|
||||||
executeAction({
|
executeAction({
|
||||||
|
|
@ -206,6 +213,7 @@ export function* executeAPIQueryActionSaga(
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
const payload = createActionSuccessResponse(response);
|
||||||
yield put(
|
yield put(
|
||||||
executeApiActionSuccess({
|
executeApiActionSuccess({
|
||||||
id: apiAction.actionId,
|
id: apiAction.actionId,
|
||||||
|
|
@ -281,7 +289,7 @@ export function* executeActionTriggers(
|
||||||
) {
|
) {
|
||||||
switch (trigger.type) {
|
switch (trigger.type) {
|
||||||
case "RUN_ACTION":
|
case "RUN_ACTION":
|
||||||
yield call(executeAPIQueryActionSaga, trigger.payload, event);
|
yield call(executeActionSaga, trigger.payload, event);
|
||||||
break;
|
break;
|
||||||
case "NAVIGATE_TO":
|
case "NAVIGATE_TO":
|
||||||
AnalyticsUtil.logEvent("NAVIGATE", {
|
AnalyticsUtil.logEvent("NAVIGATE", {
|
||||||
|
|
@ -513,7 +521,7 @@ export function* runApiActionSaga(
|
||||||
params,
|
params,
|
||||||
paginationField,
|
paginationField,
|
||||||
});
|
});
|
||||||
let payload = createActionResponse(response);
|
let payload = createActionSuccessResponse(response);
|
||||||
if (response.responseMeta && response.responseMeta.error) {
|
if (response.responseMeta && response.responseMeta.error) {
|
||||||
payload = createActionErrorResponse(response);
|
payload = createActionErrorResponse(response);
|
||||||
}
|
}
|
||||||
|
|
@ -541,27 +549,44 @@ export function* runApiActionSaga(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function* executePageLoadAction(pageAction: PageAction) {
|
||||||
|
yield put(executeApiActionRequest({ id: pageAction.id }));
|
||||||
|
const params: Property[] = yield call(
|
||||||
|
getActionParams,
|
||||||
|
pageAction.jsonPathKeys,
|
||||||
|
);
|
||||||
|
const executeActionRequest: ExecuteActionRequest = {
|
||||||
|
action: { id: pageAction.id },
|
||||||
|
params,
|
||||||
|
};
|
||||||
|
const response: ActionApiResponse = yield ActionAPI.executeAction(
|
||||||
|
executeActionRequest,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isErrorResponse(response)) {
|
||||||
|
yield put(
|
||||||
|
executeActionError({
|
||||||
|
actionId: pageAction.id,
|
||||||
|
error: response.responseMeta.error,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
const payload = createActionSuccessResponse(response);
|
||||||
|
yield put(
|
||||||
|
executeApiActionSuccess({
|
||||||
|
id: pageAction.id,
|
||||||
|
response: payload,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function* executePageLoadActionsSaga(action: ReduxAction<PageAction[][]>) {
|
function* executePageLoadActionsSaga(action: ReduxAction<PageAction[][]>) {
|
||||||
const pageActions = action.payload;
|
const pageActions = action.payload;
|
||||||
const actionPayloads: RunActionPayload[][] = pageActions.map(actionSet =>
|
for (const actionSet of pageActions) {
|
||||||
actionSet.map(action => ({
|
|
||||||
actionId: action.id,
|
|
||||||
onSuccess: "",
|
|
||||||
onError: "",
|
|
||||||
})),
|
|
||||||
);
|
|
||||||
for (const actionSet of actionPayloads) {
|
|
||||||
const apiResponses = yield select(getActionResponses);
|
const apiResponses = yield select(getActionResponses);
|
||||||
const filteredSet = actionSet.filter(
|
const filteredSet = actionSet.filter(action => !apiResponses[action.id]);
|
||||||
action => !apiResponses[action.actionId],
|
yield* yield all(filteredSet.map(a => call(executePageLoadAction, a)));
|
||||||
);
|
|
||||||
yield* yield all(
|
|
||||||
filteredSet.map(a =>
|
|
||||||
call(executeAPIQueryActionSaga, a, {
|
|
||||||
type: EventType.ON_PAGE_LOAD,
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ import {
|
||||||
takeLatest,
|
takeLatest,
|
||||||
all,
|
all,
|
||||||
} from "redux-saga/effects";
|
} from "redux-saga/effects";
|
||||||
import { getNextEntityName } from "utils/AppsmithUtils";
|
import { convertToString, getNextEntityName } from "utils/AppsmithUtils";
|
||||||
import {
|
import {
|
||||||
SetWidgetDynamicPropertyPayload,
|
SetWidgetDynamicPropertyPayload,
|
||||||
updateWidgetProperty,
|
updateWidgetProperty,
|
||||||
|
|
@ -262,7 +262,8 @@ function* setWidgetDynamicPropertySaga(
|
||||||
};
|
};
|
||||||
if (isDynamic) {
|
if (isDynamic) {
|
||||||
dynamicProperties[propertyName] = true;
|
dynamicProperties[propertyName] = true;
|
||||||
yield put(updateWidgetProperty(widgetId, propertyName, "{{}}"));
|
const value = convertToString(widget[propertyName]);
|
||||||
|
yield put(updateWidgetProperty(widgetId, propertyName, value));
|
||||||
} else {
|
} else {
|
||||||
delete dynamicProperties[propertyName];
|
delete dynamicProperties[propertyName];
|
||||||
yield put(updateWidgetProperty(widgetId, propertyName, undefined));
|
yield put(updateWidgetProperty(widgetId, propertyName, undefined));
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { ReduxAction } from "../constants/ReduxActionConstants";
|
import { ReduxAction } from "constants/ReduxActionConstants";
|
||||||
import { getAppsmithConfigs } from "configs";
|
import { getAppsmithConfigs } from "configs";
|
||||||
import * as Sentry from "@sentry/browser";
|
import * as Sentry from "@sentry/browser";
|
||||||
import AnalyticsUtil from "./AnalyticsUtil";
|
import AnalyticsUtil from "./AnalyticsUtil";
|
||||||
|
|
@ -77,3 +77,14 @@ export const getNextEntityName = (prefix: string, existingNames: string[]) => {
|
||||||
export const noop = () => {
|
export const noop = () => {
|
||||||
console.log("noop");
|
console.log("noop");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const convertToString = (value: any): string => {
|
||||||
|
if (_.isUndefined(value)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
if (_.isObject(value)) {
|
||||||
|
return JSON.stringify(value, null, 2);
|
||||||
|
}
|
||||||
|
if (_.isString(value)) return value;
|
||||||
|
return value.toString();
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,18 @@
|
||||||
import { WidgetType } from "constants/WidgetConstants";
|
import { WidgetType } from "constants/WidgetConstants";
|
||||||
import WidgetFactory from "./WidgetFactory";
|
import WidgetFactory from "./WidgetFactory";
|
||||||
import {
|
import {
|
||||||
|
VALIDATION_TYPES,
|
||||||
ValidationResponse,
|
ValidationResponse,
|
||||||
ValidationType,
|
ValidationType,
|
||||||
Validator,
|
Validator,
|
||||||
} from "constants/WidgetValidation";
|
} from "constants/WidgetValidation";
|
||||||
|
|
||||||
// TODO: need to be strict about what the key can be
|
export const BASE_WIDGET_VALIDATION = {
|
||||||
|
isLoading: VALIDATION_TYPES.BOOLEAN,
|
||||||
|
isVisible: VALIDATION_TYPES.BOOLEAN,
|
||||||
|
isDisabled: VALIDATION_TYPES.BOOLEAN,
|
||||||
|
};
|
||||||
|
|
||||||
export type WidgetPropertyValidationType = Record<string, ValidationType>;
|
export type WidgetPropertyValidationType = Record<string, ValidationType>;
|
||||||
|
|
||||||
class ValidationFactory {
|
class ValidationFactory {
|
||||||
|
|
|
||||||
|
|
@ -11,11 +11,11 @@ import { WIDGET_TYPE_VALIDATION_ERROR } from "constants/messages";
|
||||||
export const VALIDATORS: Record<ValidationType, Validator> = {
|
export const VALIDATORS: Record<ValidationType, Validator> = {
|
||||||
[VALIDATION_TYPES.TEXT]: (value: any): ValidationResponse => {
|
[VALIDATION_TYPES.TEXT]: (value: any): ValidationResponse => {
|
||||||
let parsed = value;
|
let parsed = value;
|
||||||
if (_.isUndefined(value)) {
|
if (_.isUndefined(value) || value === null) {
|
||||||
return {
|
return {
|
||||||
isValid: false,
|
isValid: true,
|
||||||
parsed: "",
|
parsed: value,
|
||||||
message: `${WIDGET_TYPE_VALIDATION_ERROR}: text`,
|
message: "",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (_.isObject(value)) {
|
if (_.isObject(value)) {
|
||||||
|
|
@ -84,20 +84,16 @@ export const VALIDATORS: Record<ValidationType, Validator> = {
|
||||||
message: `${WIDGET_TYPE_VALIDATION_ERROR}: boolean`,
|
message: `${WIDGET_TYPE_VALIDATION_ERROR}: boolean`,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
let isValid = _.isBoolean(value);
|
const isBoolean = _.isBoolean(value);
|
||||||
|
const isStringTrueFalse = value === "true" || value === "false";
|
||||||
|
const isValid = isBoolean || isStringTrueFalse;
|
||||||
|
if (isStringTrueFalse) parsed = value !== "false";
|
||||||
if (!isValid) {
|
if (!isValid) {
|
||||||
try {
|
return {
|
||||||
parsed = !!value;
|
isValid: isValid,
|
||||||
isValid = true;
|
parsed: parsed,
|
||||||
} catch (e) {
|
message: `${WIDGET_TYPE_VALIDATION_ERROR}: boolean`,
|
||||||
console.error(`Error when parsing ${value} to boolean`);
|
};
|
||||||
console.error(e);
|
|
||||||
return {
|
|
||||||
isValid: false,
|
|
||||||
parsed: false,
|
|
||||||
message: `${WIDGET_TYPE_VALIDATION_ERROR}: boolean`,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return { isValid, parsed };
|
return { isValid, parsed };
|
||||||
},
|
},
|
||||||
|
|
@ -174,6 +170,23 @@ export const VALIDATORS: Record<ValidationType, Validator> = {
|
||||||
}
|
}
|
||||||
return { isValid, parsed };
|
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 => {
|
[VALIDATION_TYPES.OPTIONS_DATA]: (value: any): ValidationResponse => {
|
||||||
const { isValid, parsed } = VALIDATORS[VALIDATION_TYPES.ARRAY](value);
|
const { isValid, parsed } = VALIDATORS[VALIDATION_TYPES.ARRAY](value);
|
||||||
if (!isValid) {
|
if (!isValid) {
|
||||||
|
|
@ -200,6 +213,15 @@ export const VALIDATORS: Record<ValidationType, Validator> = {
|
||||||
return { isValid, parsed };
|
return { isValid, parsed };
|
||||||
},
|
},
|
||||||
[VALIDATION_TYPES.DATE]: (value: any): ValidationResponse => {
|
[VALIDATION_TYPES.DATE]: (value: any): ValidationResponse => {
|
||||||
|
if (value === undefined) {
|
||||||
|
const today = new Date();
|
||||||
|
today.setHours(0, 0, 0);
|
||||||
|
return {
|
||||||
|
isValid: false,
|
||||||
|
parsed: today,
|
||||||
|
message: `${WIDGET_TYPE_VALIDATION_ERROR}: Date`,
|
||||||
|
};
|
||||||
|
}
|
||||||
const isValid = moment(value).isValid();
|
const isValid = moment(value).isValid();
|
||||||
const parsed = isValid ? moment(value).toDate() : new Date();
|
const parsed = isValid ? moment(value).toDate() : new Date();
|
||||||
return {
|
return {
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,10 @@ import {
|
||||||
WidgetProps,
|
WidgetProps,
|
||||||
WidgetDataProps,
|
WidgetDataProps,
|
||||||
} from "widgets/BaseWidget";
|
} from "widgets/BaseWidget";
|
||||||
import { WidgetPropertyValidationType } from "./ValidationFactory";
|
import {
|
||||||
|
WidgetPropertyValidationType,
|
||||||
|
BASE_WIDGET_VALIDATION,
|
||||||
|
} from "./ValidationFactory";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
type WidgetDerivedPropertyType = any;
|
type WidgetDerivedPropertyType = any;
|
||||||
|
|
@ -78,7 +81,7 @@ class WidgetFactory {
|
||||||
const map = this.widgetPropValidationMap.get(widgetType);
|
const map = this.widgetPropValidationMap.get(widgetType);
|
||||||
if (!map) {
|
if (!map) {
|
||||||
console.error("Widget type validation is not defined");
|
console.error("Widget type validation is not defined");
|
||||||
return {};
|
return BASE_WIDGET_VALIDATION;
|
||||||
}
|
}
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ import ButtonWidget, { ButtonWidgetProps } from "widgets/ButtonWidget";
|
||||||
import DropdownWidget, { DropdownWidgetProps } from "widgets/DropdownWidget";
|
import DropdownWidget, { DropdownWidgetProps } from "widgets/DropdownWidget";
|
||||||
import ImageWidget, { ImageWidgetProps } from "widgets/ImageWidget";
|
import ImageWidget, { ImageWidgetProps } from "widgets/ImageWidget";
|
||||||
import TableWidget, { TableWidgetProps } from "widgets/TableWidget";
|
import TableWidget, { TableWidgetProps } from "widgets/TableWidget";
|
||||||
|
import ChartWidget, { ChartWidgetProps } from "widgets/ChartWidget";
|
||||||
|
|
||||||
import FilePickerWidget, {
|
import FilePickerWidget, {
|
||||||
FilePickerWidgetProps,
|
FilePickerWidgetProps,
|
||||||
|
|
@ -169,7 +170,17 @@ class WidgetBuilderRegistry {
|
||||||
DatePickerWidget.getDerivedPropertiesMap(),
|
DatePickerWidget.getDerivedPropertiesMap(),
|
||||||
DatePickerWidget.getTriggerPropertyMap(),
|
DatePickerWidget.getTriggerPropertyMap(),
|
||||||
);
|
);
|
||||||
|
WidgetFactory.registerWidgetBuilder(
|
||||||
|
"CHART_WIDGET",
|
||||||
|
{
|
||||||
|
buildWidget(widgetData: ChartWidgetProps): JSX.Element {
|
||||||
|
return <ChartWidget {...widgetData} />;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ChartWidget.getPropertyValidationMap(),
|
||||||
|
ChartWidget.getDerivedPropertiesMap(),
|
||||||
|
ChartWidget.getTriggerPropertyMap(),
|
||||||
|
);
|
||||||
WidgetFactory.registerWidgetBuilder(
|
WidgetFactory.registerWidgetBuilder(
|
||||||
"FORM_WIDGET",
|
"FORM_WIDGET",
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,10 @@ import { EditorContext } from "components/editorComponents/EditorContextProvider
|
||||||
import { PositionTypes } from "constants/WidgetConstants";
|
import { PositionTypes } from "constants/WidgetConstants";
|
||||||
|
|
||||||
import ErrorBoundary from "components/editorComponents/ErrorBoundry";
|
import ErrorBoundary from "components/editorComponents/ErrorBoundry";
|
||||||
import { WidgetPropertyValidationType } from "utils/ValidationFactory";
|
import {
|
||||||
|
BASE_WIDGET_VALIDATION,
|
||||||
|
WidgetPropertyValidationType,
|
||||||
|
} from "utils/ValidationFactory";
|
||||||
import {
|
import {
|
||||||
DerivedPropertiesMap,
|
DerivedPropertiesMap,
|
||||||
TriggerPropertiesMap,
|
TriggerPropertiesMap,
|
||||||
|
|
@ -66,7 +69,7 @@ abstract class BaseWidget<
|
||||||
// Needed to send a default no validation option. In case a widget needs
|
// Needed to send a default no validation option. In case a widget needs
|
||||||
// validation implement this in the widget class again
|
// validation implement this in the widget class again
|
||||||
static getPropertyValidationMap(): WidgetPropertyValidationType {
|
static getPropertyValidationMap(): WidgetPropertyValidationType {
|
||||||
return {};
|
return BASE_WIDGET_VALIDATION;
|
||||||
}
|
}
|
||||||
|
|
||||||
static getDerivedPropertiesMap(): DerivedPropertiesMap {
|
static getDerivedPropertiesMap(): DerivedPropertiesMap {
|
||||||
|
|
@ -166,7 +169,14 @@ abstract class BaseWidget<
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return this.getWidgetView();
|
let isValid = true;
|
||||||
|
if (this.props.invalidProps) {
|
||||||
|
isValid = _.keys(this.props.invalidProps).length === 0;
|
||||||
|
}
|
||||||
|
if (this.props.isLoading) isValid = true;
|
||||||
|
return (
|
||||||
|
<ErrorBoundary isValid={isValid}>{this.getWidgetView()}</ErrorBoundary>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private getWidgetView(): JSX.Element {
|
private getWidgetView(): JSX.Element {
|
||||||
|
|
@ -202,7 +212,7 @@ abstract class BaseWidget<
|
||||||
this.props.widgetId === "0"
|
this.props.widgetId === "0"
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<ErrorBoundary isValid>{this.getPageView()}</ErrorBoundary>
|
{this.getPageView()}
|
||||||
</PositionedContainer>
|
</PositionedContainer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -215,14 +225,7 @@ abstract class BaseWidget<
|
||||||
abstract getPageView(): JSX.Element;
|
abstract getPageView(): JSX.Element;
|
||||||
|
|
||||||
getCanvasView(): JSX.Element {
|
getCanvasView(): JSX.Element {
|
||||||
let isValid = true;
|
return this.getPageView();
|
||||||
if (this.props.invalidProps) {
|
|
||||||
isValid = _.keys(this.props.invalidProps).length === 0;
|
|
||||||
}
|
|
||||||
if (this.props.isLoading) isValid = true;
|
|
||||||
return (
|
|
||||||
<ErrorBoundary isValid={isValid}>{this.getPageView()}</ErrorBoundary>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(Nikhil): Revisit the inclusion of another library for shallowEqual.
|
// TODO(Nikhil): Revisit the inclusion of another library for shallowEqual.
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,10 @@ import ButtonComponent, {
|
||||||
ButtonType,
|
ButtonType,
|
||||||
} from "components/designSystems/blueprint/ButtonComponent";
|
} from "components/designSystems/blueprint/ButtonComponent";
|
||||||
import { EventType } from "constants/ActionConstants";
|
import { EventType } from "constants/ActionConstants";
|
||||||
import { WidgetPropertyValidationType } from "utils/ValidationFactory";
|
import {
|
||||||
|
WidgetPropertyValidationType,
|
||||||
|
BASE_WIDGET_VALIDATION,
|
||||||
|
} from "utils/ValidationFactory";
|
||||||
import { VALIDATION_TYPES } from "constants/WidgetValidation";
|
import { VALIDATION_TYPES } from "constants/WidgetValidation";
|
||||||
import { TriggerPropertiesMap } from "utils/WidgetFactory";
|
import { TriggerPropertiesMap } from "utils/WidgetFactory";
|
||||||
|
|
||||||
|
|
@ -30,9 +33,8 @@ class ButtonWidget extends BaseWidget<
|
||||||
|
|
||||||
static getPropertyValidationMap(): WidgetPropertyValidationType {
|
static getPropertyValidationMap(): WidgetPropertyValidationType {
|
||||||
return {
|
return {
|
||||||
|
...BASE_WIDGET_VALIDATION,
|
||||||
text: VALIDATION_TYPES.TEXT,
|
text: VALIDATION_TYPES.TEXT,
|
||||||
isDisabled: VALIDATION_TYPES.BOOLEAN,
|
|
||||||
isVisible: VALIDATION_TYPES.BOOLEAN,
|
|
||||||
buttonStyle: VALIDATION_TYPES.TEXT,
|
buttonStyle: VALIDATION_TYPES.TEXT,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
63
app/client/src/widgets/ChartWidget.tsx
Normal file
63
app/client/src/widgets/ChartWidget.tsx
Normal 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;
|
||||||
|
|
@ -4,16 +4,18 @@ import { WidgetType } from "constants/WidgetConstants";
|
||||||
import CheckboxComponent from "components/designSystems/blueprint/CheckboxComponent";
|
import CheckboxComponent from "components/designSystems/blueprint/CheckboxComponent";
|
||||||
import { EventType } from "constants/ActionConstants";
|
import { EventType } from "constants/ActionConstants";
|
||||||
import { VALIDATION_TYPES } from "constants/WidgetValidation";
|
import { VALIDATION_TYPES } from "constants/WidgetValidation";
|
||||||
import { WidgetPropertyValidationType } from "utils/ValidationFactory";
|
import {
|
||||||
|
WidgetPropertyValidationType,
|
||||||
|
BASE_WIDGET_VALIDATION,
|
||||||
|
} from "utils/ValidationFactory";
|
||||||
import { TriggerPropertiesMap } from "utils/WidgetFactory";
|
import { TriggerPropertiesMap } from "utils/WidgetFactory";
|
||||||
|
|
||||||
class CheckboxWidget extends BaseWidget<CheckboxWidgetProps, WidgetState> {
|
class CheckboxWidget extends BaseWidget<CheckboxWidgetProps, WidgetState> {
|
||||||
static getPropertyValidationMap(): WidgetPropertyValidationType {
|
static getPropertyValidationMap(): WidgetPropertyValidationType {
|
||||||
return {
|
return {
|
||||||
isDisabled: VALIDATION_TYPES.BOOLEAN,
|
...BASE_WIDGET_VALIDATION,
|
||||||
label: VALIDATION_TYPES.TEXT,
|
label: VALIDATION_TYPES.TEXT,
|
||||||
defaultCheckedState: VALIDATION_TYPES.BOOLEAN,
|
defaultCheckedState: VALIDATION_TYPES.BOOLEAN,
|
||||||
isChecked: VALIDATION_TYPES.BOOLEAN,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -23,10 +25,35 @@ class CheckboxWidget extends BaseWidget<CheckboxWidgetProps, WidgetState> {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
super.componentDidMount();
|
||||||
|
if (this.props.defaultCheckedState) {
|
||||||
|
this.updateWidgetMetaProperty(
|
||||||
|
"isChecked",
|
||||||
|
this.props.defaultCheckedState,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUpdate(prevProps: CheckboxWidgetProps) {
|
||||||
|
super.componentDidUpdate(prevProps);
|
||||||
|
if (
|
||||||
|
(this.props.isChecked !== prevProps.isChecked &&
|
||||||
|
this.props.isChecked === undefined) ||
|
||||||
|
this.props.defaultCheckedState.toString() !==
|
||||||
|
prevProps.defaultCheckedState.toString()
|
||||||
|
) {
|
||||||
|
this.updateWidgetMetaProperty(
|
||||||
|
"isChecked",
|
||||||
|
this.props.defaultCheckedState,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
getPageView() {
|
getPageView() {
|
||||||
return (
|
return (
|
||||||
<CheckboxComponent
|
<CheckboxComponent
|
||||||
defaultCheckedState={this.props.defaultCheckedState}
|
isChecked={!!this.props.isChecked}
|
||||||
label={this.props.label}
|
label={this.props.label}
|
||||||
widgetId={this.props.widgetId}
|
widgetId={this.props.widgetId}
|
||||||
key={this.props.widgetId}
|
key={this.props.widgetId}
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,6 @@ import {
|
||||||
CONTAINER_GRID_PADDING,
|
CONTAINER_GRID_PADDING,
|
||||||
WIDGET_PADDING,
|
WIDGET_PADDING,
|
||||||
MAIN_CONTAINER_WIDGET_ID,
|
MAIN_CONTAINER_WIDGET_ID,
|
||||||
RenderModes,
|
|
||||||
} from "constants/WidgetConstants";
|
} from "constants/WidgetConstants";
|
||||||
|
|
||||||
import ResizeBoundsContainerComponent from "components/editorComponents/ResizeBoundsContainerComponent";
|
import ResizeBoundsContainerComponent from "components/editorComponents/ResizeBoundsContainerComponent";
|
||||||
|
|
@ -64,12 +63,8 @@ class ContainerWidget extends BaseWidget<
|
||||||
return _.map(
|
return _.map(
|
||||||
// sort by row so stacking context is correct
|
// sort by row so stacking context is correct
|
||||||
// TODO(abhinav): This is hacky. The stacking context should increase for widgets rendered top to bottom, always.
|
// TODO(abhinav): This is hacky. The stacking context should increase for widgets rendered top to bottom, always.
|
||||||
// Figure out a way in which the stacking context is consitent.
|
// Figure out a way in which the stacking context is consistent.
|
||||||
_.sortBy(this.props.children, child => {
|
_.sortBy(this.props.children, child => child.topRow),
|
||||||
return this.props.renderMode === RenderModes.CANVAS
|
|
||||||
? child.topRow
|
|
||||||
: -child.topRow;
|
|
||||||
}),
|
|
||||||
this.renderChildWidget,
|
this.renderChildWidget,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,10 @@ import BaseWidget, { WidgetProps, WidgetState } from "./BaseWidget";
|
||||||
import { WidgetType } from "constants/WidgetConstants";
|
import { WidgetType } from "constants/WidgetConstants";
|
||||||
import { EventType } from "constants/ActionConstants";
|
import { EventType } from "constants/ActionConstants";
|
||||||
import DatePickerComponent from "components/designSystems/blueprint/DatePickerComponent";
|
import DatePickerComponent from "components/designSystems/blueprint/DatePickerComponent";
|
||||||
import { WidgetPropertyValidationType } from "utils/ValidationFactory";
|
import {
|
||||||
|
WidgetPropertyValidationType,
|
||||||
|
BASE_WIDGET_VALIDATION,
|
||||||
|
} from "utils/ValidationFactory";
|
||||||
import { VALIDATION_TYPES } from "constants/WidgetValidation";
|
import { VALIDATION_TYPES } from "constants/WidgetValidation";
|
||||||
import {
|
import {
|
||||||
DerivedPropertiesMap,
|
DerivedPropertiesMap,
|
||||||
|
|
@ -13,8 +16,8 @@ import {
|
||||||
class DatePickerWidget extends BaseWidget<DatePickerWidgetProps, WidgetState> {
|
class DatePickerWidget extends BaseWidget<DatePickerWidgetProps, WidgetState> {
|
||||||
static getPropertyValidationMap(): WidgetPropertyValidationType {
|
static getPropertyValidationMap(): WidgetPropertyValidationType {
|
||||||
return {
|
return {
|
||||||
|
...BASE_WIDGET_VALIDATION,
|
||||||
defaultDate: VALIDATION_TYPES.DATE,
|
defaultDate: VALIDATION_TYPES.DATE,
|
||||||
selectedDate: VALIDATION_TYPES.DATE,
|
|
||||||
timezone: VALIDATION_TYPES.TEXT,
|
timezone: VALIDATION_TYPES.TEXT,
|
||||||
enableTimePicker: VALIDATION_TYPES.BOOLEAN,
|
enableTimePicker: VALIDATION_TYPES.BOOLEAN,
|
||||||
dateFormat: VALIDATION_TYPES.TEXT,
|
dateFormat: VALIDATION_TYPES.TEXT,
|
||||||
|
|
@ -37,6 +40,21 @@ class DatePickerWidget extends BaseWidget<DatePickerWidgetProps, WidgetState> {
|
||||||
onDateSelected: true,
|
onDateSelected: true,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentDidUpdate(prevProps: DatePickerWidgetProps) {
|
||||||
|
super.componentDidUpdate(prevProps);
|
||||||
|
if (this.props.defaultDate) {
|
||||||
|
if (
|
||||||
|
(this.props.selectedDate !== prevProps.selectedDate &&
|
||||||
|
this.props.selectedDate === undefined) ||
|
||||||
|
this.props.defaultDate.toDateString() !==
|
||||||
|
prevProps.defaultDate.toDateString()
|
||||||
|
) {
|
||||||
|
this.updateWidgetMetaProperty("selectedDate", this.props.defaultDate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
getPageView() {
|
getPageView() {
|
||||||
return (
|
return (
|
||||||
<DatePickerComponent
|
<DatePickerComponent
|
||||||
|
|
@ -45,7 +63,6 @@ class DatePickerWidget extends BaseWidget<DatePickerWidgetProps, WidgetState> {
|
||||||
widgetId={this.props.widgetId}
|
widgetId={this.props.widgetId}
|
||||||
timezone={this.props.timezone}
|
timezone={this.props.timezone}
|
||||||
enableTimePicker={this.props.enableTimePicker}
|
enableTimePicker={this.props.enableTimePicker}
|
||||||
defaultDate={this.props.defaultDate}
|
|
||||||
datePickerType={"DATE_PICKER"}
|
datePickerType={"DATE_PICKER"}
|
||||||
onDateSelected={this.onDateSelected}
|
onDateSelected={this.onDateSelected}
|
||||||
selectedDate={this.props.selectedDate}
|
selectedDate={this.props.selectedDate}
|
||||||
|
|
@ -74,7 +91,7 @@ class DatePickerWidget extends BaseWidget<DatePickerWidgetProps, WidgetState> {
|
||||||
export type DatePickerType = "DATE_PICKER" | "DATE_RANGE_PICKER";
|
export type DatePickerType = "DATE_PICKER" | "DATE_RANGE_PICKER";
|
||||||
|
|
||||||
export interface DatePickerWidgetProps extends WidgetProps {
|
export interface DatePickerWidgetProps extends WidgetProps {
|
||||||
defaultDate?: Date;
|
defaultDate: Date;
|
||||||
selectedDate: Date;
|
selectedDate: Date;
|
||||||
timezone?: string;
|
timezone?: string;
|
||||||
enableTimePicker: boolean;
|
enableTimePicker: boolean;
|
||||||
|
|
|
||||||
|
|
@ -4,18 +4,21 @@ import { WidgetType } from "constants/WidgetConstants";
|
||||||
import { EventType } from "constants/ActionConstants";
|
import { EventType } 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 {
|
||||||
|
WidgetPropertyValidationType,
|
||||||
|
BASE_WIDGET_VALIDATION,
|
||||||
|
} from "utils/ValidationFactory";
|
||||||
import { VALIDATION_TYPES } from "constants/WidgetValidation";
|
import { VALIDATION_TYPES } from "constants/WidgetValidation";
|
||||||
import { TriggerPropertiesMap } from "utils/WidgetFactory";
|
import { TriggerPropertiesMap } from "utils/WidgetFactory";
|
||||||
|
|
||||||
class DropdownWidget extends BaseWidget<DropdownWidgetProps, WidgetState> {
|
class DropdownWidget extends BaseWidget<DropdownWidgetProps, WidgetState> {
|
||||||
static getPropertyValidationMap(): WidgetPropertyValidationType {
|
static getPropertyValidationMap(): WidgetPropertyValidationType {
|
||||||
return {
|
return {
|
||||||
|
...BASE_WIDGET_VALIDATION,
|
||||||
placeholderText: VALIDATION_TYPES.TEXT,
|
placeholderText: VALIDATION_TYPES.TEXT,
|
||||||
label: VALIDATION_TYPES.TEXT,
|
label: VALIDATION_TYPES.TEXT,
|
||||||
options: VALIDATION_TYPES.OPTIONS_DATA,
|
options: VALIDATION_TYPES.OPTIONS_DATA,
|
||||||
selectionType: VALIDATION_TYPES.TEXT,
|
selectionType: VALIDATION_TYPES.TEXT,
|
||||||
selectedIndex: VALIDATION_TYPES.NUMBER,
|
|
||||||
selectedIndexArr: VALIDATION_TYPES.ARRAY,
|
selectedIndexArr: VALIDATION_TYPES.ARRAY,
|
||||||
isRequired: VALIDATION_TYPES.BOOLEAN,
|
isRequired: VALIDATION_TYPES.BOOLEAN,
|
||||||
};
|
};
|
||||||
|
|
@ -44,6 +47,16 @@ class DropdownWidget extends BaseWidget<DropdownWidgetProps, WidgetState> {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
super.componentDidMount();
|
||||||
|
if (this.props.defaultOptionValue) {
|
||||||
|
const selectedIndex = _.findIndex(this.props.options, option => {
|
||||||
|
return option.value === this.props.defaultOptionValue;
|
||||||
|
});
|
||||||
|
this.updateWidgetMetaProperty("selectedIndex", selectedIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
componentDidUpdate(prevProps: DropdownWidgetProps) {
|
componentDidUpdate(prevProps: DropdownWidgetProps) {
|
||||||
super.componentDidUpdate(prevProps);
|
super.componentDidUpdate(prevProps);
|
||||||
if (
|
if (
|
||||||
|
|
@ -51,22 +64,26 @@ class DropdownWidget extends BaseWidget<DropdownWidgetProps, WidgetState> {
|
||||||
) {
|
) {
|
||||||
this.updateWidgetMetaProperty("selectedIndex", undefined);
|
this.updateWidgetMetaProperty("selectedIndex", undefined);
|
||||||
this.updateWidgetMetaProperty("selectedIndexArr", []);
|
this.updateWidgetMetaProperty("selectedIndexArr", []);
|
||||||
|
} else if (
|
||||||
|
(this.props.selectedIndex !== prevProps.selectedIndex &&
|
||||||
|
this.props.selectedIndex === undefined) ||
|
||||||
|
this.props.defaultOptionValue !== prevProps.defaultOptionValue
|
||||||
|
) {
|
||||||
|
const selectedIndex = _.findIndex(this.props.options, option => {
|
||||||
|
return option.value === this.props.defaultOptionValue;
|
||||||
|
});
|
||||||
|
if (selectedIndex > -1) {
|
||||||
|
this.updateWidgetMetaProperty("selectedIndex", selectedIndex);
|
||||||
|
} else {
|
||||||
|
this.updateWidgetMetaProperty("selectedIndex", undefined);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
getPageView() {
|
getPageView() {
|
||||||
const options = this.props.options || [];
|
const options = this.props.options || [];
|
||||||
let selectedIndex: number | undefined = undefined;
|
|
||||||
if (
|
|
||||||
this.props.selectedIndex !== undefined &&
|
|
||||||
this.props.selectedIndex < options.length &&
|
|
||||||
this.props.selectedIndex >= 0
|
|
||||||
) {
|
|
||||||
selectedIndex = this.props.selectedIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
const selectedIndexArr = this.props.selectedIndexArr || [];
|
const selectedIndexArr = this.props.selectedIndexArr || [];
|
||||||
let computedSelectedIndexArr = selectedIndexArr.slice();
|
let computedSelectedIndexArr = selectedIndexArr.slice();
|
||||||
selectedIndexArr.forEach((selectedIndex, index) => {
|
selectedIndexArr.forEach(selectedIndex => {
|
||||||
if (options[selectedIndex] === undefined) {
|
if (options[selectedIndex] === undefined) {
|
||||||
computedSelectedIndexArr = [];
|
computedSelectedIndexArr = [];
|
||||||
}
|
}
|
||||||
|
|
@ -80,7 +97,7 @@ class DropdownWidget extends BaseWidget<DropdownWidgetProps, WidgetState> {
|
||||||
placeholder={this.props.placeholderText}
|
placeholder={this.props.placeholderText}
|
||||||
options={options}
|
options={options}
|
||||||
selectionType={this.props.selectionType}
|
selectionType={this.props.selectionType}
|
||||||
selectedIndex={selectedIndex}
|
selectedIndex={this.props.selectedIndex}
|
||||||
selectedIndexArr={computedSelectedIndexArr}
|
selectedIndexArr={computedSelectedIndexArr}
|
||||||
label={`${this.props.label}${this.props.isRequired ? " *" : ""}`}
|
label={`${this.props.label}${this.props.isRequired ? " *" : ""}`}
|
||||||
isLoading={this.props.isLoading}
|
isLoading={this.props.isLoading}
|
||||||
|
|
@ -156,6 +173,7 @@ export interface DropdownWidgetProps extends WidgetProps {
|
||||||
selectionType: SelectionType;
|
selectionType: SelectionType;
|
||||||
options?: DropdownOption[];
|
options?: DropdownOption[];
|
||||||
onOptionChange?: string;
|
onOptionChange?: string;
|
||||||
|
defaultOptionValue?: string;
|
||||||
isRequired: boolean;
|
isRequired: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,12 @@ 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 {
|
||||||
|
WidgetPropertyValidationType,
|
||||||
|
BASE_WIDGET_VALIDATION,
|
||||||
|
} from "utils/ValidationFactory";
|
||||||
import { VALIDATION_TYPES } from "constants/WidgetValidation";
|
import { VALIDATION_TYPES } from "constants/WidgetValidation";
|
||||||
import { EventType } from "constants/ActionConstants";
|
import { EventType, ExecutionResult } from "constants/ActionConstants";
|
||||||
import {
|
import {
|
||||||
DerivedPropertiesMap,
|
DerivedPropertiesMap,
|
||||||
TriggerPropertiesMap,
|
TriggerPropertiesMap,
|
||||||
|
|
@ -28,9 +31,11 @@ class FilePickerWidget extends BaseWidget<FilePickerWidgetProps, WidgetState> {
|
||||||
|
|
||||||
static getPropertyValidationMap(): WidgetPropertyValidationType {
|
static getPropertyValidationMap(): WidgetPropertyValidationType {
|
||||||
return {
|
return {
|
||||||
|
...BASE_WIDGET_VALIDATION,
|
||||||
label: VALIDATION_TYPES.TEXT,
|
label: VALIDATION_TYPES.TEXT,
|
||||||
maxNumFiles: VALIDATION_TYPES.NUMBER,
|
maxNumFiles: VALIDATION_TYPES.NUMBER,
|
||||||
allowedFileTypes: VALIDATION_TYPES.ARRAY,
|
allowedFileTypes: VALIDATION_TYPES.ARRAY,
|
||||||
|
files: VALIDATION_TYPES.ARRAY,
|
||||||
isRequired: VALIDATION_TYPES.BOOLEAN,
|
isRequired: VALIDATION_TYPES.BOOLEAN,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -96,13 +101,15 @@ class FilePickerWidget extends BaseWidget<FilePickerWidgetProps, WidgetState> {
|
||||||
locale: {},
|
locale: {},
|
||||||
});
|
});
|
||||||
this.uppy.on("file-removed", (file: any) => {
|
this.uppy.on("file-removed", (file: any) => {
|
||||||
const updatedFiles = this.props.files.filter(dslFile => {
|
const updatedFiles = this.props.files
|
||||||
return file.id !== dslFile.id;
|
? this.props.files.filter(dslFile => {
|
||||||
});
|
return file.id !== dslFile.id;
|
||||||
|
})
|
||||||
|
: [];
|
||||||
this.updateWidgetMetaProperty("files", updatedFiles);
|
this.updateWidgetMetaProperty("files", updatedFiles);
|
||||||
});
|
});
|
||||||
this.uppy.on("file-added", (file: any) => {
|
this.uppy.on("file-added", (file: any) => {
|
||||||
const dslFiles = this.props.files;
|
const dslFiles = this.props.files || [];
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
reader.readAsDataURL(file.data);
|
reader.readAsDataURL(file.data);
|
||||||
reader.onloadend = () => {
|
reader.onloadend = () => {
|
||||||
|
|
@ -133,14 +140,30 @@ class FilePickerWidget extends BaseWidget<FilePickerWidgetProps, WidgetState> {
|
||||||
dynamicString: this.props.onFilesSelected,
|
dynamicString: this.props.onFilesSelected,
|
||||||
event: {
|
event: {
|
||||||
type: EventType.ON_FILES_SELECTED,
|
type: EventType.ON_FILES_SELECTED,
|
||||||
|
callback: this.handleFileUploaded,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleFileUploaded = (result: ExecutionResult) => {
|
||||||
|
if (result.success) {
|
||||||
|
this.updateWidgetMetaProperty(
|
||||||
|
"uploadedFileData",
|
||||||
|
this.props.uploadedFileUrls,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
componentDidUpdate(prevProps: FilePickerWidgetProps) {
|
componentDidUpdate(prevProps: FilePickerWidgetProps) {
|
||||||
super.componentDidUpdate(prevProps);
|
super.componentDidUpdate(prevProps);
|
||||||
if (
|
if (
|
||||||
|
prevProps.files &&
|
||||||
|
prevProps.files.length > 0 &&
|
||||||
|
this.props.files === undefined
|
||||||
|
) {
|
||||||
|
this.uppy.reset();
|
||||||
|
} else if (
|
||||||
!shallowequal(prevProps.allowedFileTypes, this.props.allowedFileTypes) ||
|
!shallowequal(prevProps.allowedFileTypes, this.props.allowedFileTypes) ||
|
||||||
prevProps.maxNumFiles !== this.props.maxNumFiles ||
|
prevProps.maxNumFiles !== this.props.maxNumFiles ||
|
||||||
prevProps.maxFileSize !== this.props.maxFileSize
|
prevProps.maxFileSize !== this.props.maxFileSize
|
||||||
|
|
@ -165,7 +188,7 @@ class FilePickerWidget extends BaseWidget<FilePickerWidgetProps, WidgetState> {
|
||||||
widgetId={this.props.widgetId}
|
widgetId={this.props.widgetId}
|
||||||
key={this.props.widgetId}
|
key={this.props.widgetId}
|
||||||
label={this.props.label}
|
label={this.props.label}
|
||||||
files={this.props.files}
|
files={this.props.files || []}
|
||||||
isLoading={this.props.isLoading}
|
isLoading={this.props.isLoading}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
@ -180,10 +203,11 @@ export interface FilePickerWidgetProps extends WidgetProps {
|
||||||
label: string;
|
label: string;
|
||||||
maxNumFiles?: number;
|
maxNumFiles?: number;
|
||||||
maxFileSize?: number;
|
maxFileSize?: number;
|
||||||
files: any[];
|
files?: any[];
|
||||||
allowedFileTypes: string[];
|
allowedFileTypes: string[];
|
||||||
onFilesSelected?: string;
|
onFilesSelected?: string;
|
||||||
isRequired?: boolean;
|
isRequired?: boolean;
|
||||||
|
uploadedFileUrls?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default FilePickerWidget;
|
export default FilePickerWidget;
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,10 @@ import ButtonComponent, {
|
||||||
ButtonType,
|
ButtonType,
|
||||||
} from "components/designSystems/blueprint/ButtonComponent";
|
} from "components/designSystems/blueprint/ButtonComponent";
|
||||||
import { EventType, ExecutionResult } from "constants/ActionConstants";
|
import { EventType, ExecutionResult } from "constants/ActionConstants";
|
||||||
import { WidgetPropertyValidationType } from "utils/ValidationFactory";
|
import {
|
||||||
|
BASE_WIDGET_VALIDATION,
|
||||||
|
WidgetPropertyValidationType,
|
||||||
|
} from "utils/ValidationFactory";
|
||||||
import { VALIDATION_TYPES } from "constants/WidgetValidation";
|
import { VALIDATION_TYPES } from "constants/WidgetValidation";
|
||||||
import { TriggerPropertiesMap } from "utils/WidgetFactory";
|
import { TriggerPropertiesMap } from "utils/WidgetFactory";
|
||||||
|
|
||||||
|
|
@ -30,10 +33,11 @@ class FormButtonWidget extends BaseWidget<
|
||||||
|
|
||||||
static getPropertyValidationMap(): WidgetPropertyValidationType {
|
static getPropertyValidationMap(): WidgetPropertyValidationType {
|
||||||
return {
|
return {
|
||||||
|
...BASE_WIDGET_VALIDATION,
|
||||||
text: VALIDATION_TYPES.TEXT,
|
text: VALIDATION_TYPES.TEXT,
|
||||||
disabledWhenInvalid: VALIDATION_TYPES.BOOLEAN,
|
disabledWhenInvalid: VALIDATION_TYPES.BOOLEAN,
|
||||||
isVisible: VALIDATION_TYPES.BOOLEAN,
|
|
||||||
buttonStyle: VALIDATION_TYPES.TEXT,
|
buttonStyle: VALIDATION_TYPES.TEXT,
|
||||||
|
buttonType: VALIDATION_TYPES.TEXT,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -55,6 +59,8 @@ class FormButtonWidget extends BaseWidget<
|
||||||
callback: this.handleActionResult,
|
callback: this.handleActionResult,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
} else if (this.props.resetFormOnClick && this.props.onReset) {
|
||||||
|
this.props.onReset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -84,7 +90,7 @@ class FormButtonWidget extends BaseWidget<
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
onClick={this.onButtonClickBound}
|
onClick={this.onButtonClickBound}
|
||||||
isLoading={this.props.isLoading || this.state.isLoading}
|
isLoading={this.props.isLoading || this.state.isLoading}
|
||||||
type={ButtonType.SUBMIT}
|
type={this.props.buttonType || ButtonType.BUTTON}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -105,6 +111,7 @@ export interface FormButtonWidgetProps extends WidgetProps {
|
||||||
buttonStyle?: ButtonStyle;
|
buttonStyle?: ButtonStyle;
|
||||||
onClick?: string;
|
onClick?: string;
|
||||||
isVisible?: boolean;
|
isVisible?: boolean;
|
||||||
|
buttonType: ButtonType;
|
||||||
isFormValid?: boolean;
|
isFormValid?: boolean;
|
||||||
resetFormOnClick?: boolean;
|
resetFormOnClick?: boolean;
|
||||||
onReset?: () => void;
|
onReset?: () => void;
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,16 @@ 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 {
|
||||||
|
WidgetPropertyValidationType,
|
||||||
|
BASE_WIDGET_VALIDATION,
|
||||||
|
} from "utils/ValidationFactory";
|
||||||
import { VALIDATION_TYPES } from "constants/WidgetValidation";
|
import { VALIDATION_TYPES } from "constants/WidgetValidation";
|
||||||
|
|
||||||
class ImageWidget extends BaseWidget<ImageWidgetProps, WidgetState> {
|
class ImageWidget extends BaseWidget<ImageWidgetProps, WidgetState> {
|
||||||
static getPropertyValidationMap(): WidgetPropertyValidationType {
|
static getPropertyValidationMap(): WidgetPropertyValidationType {
|
||||||
return {
|
return {
|
||||||
|
...BASE_WIDGET_VALIDATION,
|
||||||
image: VALIDATION_TYPES.TEXT,
|
image: VALIDATION_TYPES.TEXT,
|
||||||
imageShape: VALIDATION_TYPES.TEXT,
|
imageShape: VALIDATION_TYPES.TEXT,
|
||||||
defaultImage: VALIDATION_TYPES.TEXT,
|
defaultImage: VALIDATION_TYPES.TEXT,
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,10 @@ import InputComponent, {
|
||||||
InputComponentProps,
|
InputComponentProps,
|
||||||
} from "components/designSystems/blueprint/InputComponent";
|
} from "components/designSystems/blueprint/InputComponent";
|
||||||
import { EventType } from "constants/ActionConstants";
|
import { EventType } from "constants/ActionConstants";
|
||||||
import { WidgetPropertyValidationType } from "utils/ValidationFactory";
|
import {
|
||||||
|
WidgetPropertyValidationType,
|
||||||
|
BASE_WIDGET_VALIDATION,
|
||||||
|
} from "utils/ValidationFactory";
|
||||||
import { VALIDATION_TYPES } from "constants/WidgetValidation";
|
import { VALIDATION_TYPES } from "constants/WidgetValidation";
|
||||||
import { FIELD_REQUIRED_ERROR } from "constants/messages";
|
import { FIELD_REQUIRED_ERROR } from "constants/messages";
|
||||||
import {
|
import {
|
||||||
|
|
@ -16,6 +19,7 @@ import {
|
||||||
class InputWidget extends BaseWidget<InputWidgetProps, WidgetState> {
|
class InputWidget extends BaseWidget<InputWidgetProps, WidgetState> {
|
||||||
static getPropertyValidationMap(): WidgetPropertyValidationType {
|
static getPropertyValidationMap(): WidgetPropertyValidationType {
|
||||||
return {
|
return {
|
||||||
|
...BASE_WIDGET_VALIDATION,
|
||||||
inputType: VALIDATION_TYPES.TEXT,
|
inputType: VALIDATION_TYPES.TEXT,
|
||||||
defaultText: VALIDATION_TYPES.TEXT,
|
defaultText: VALIDATION_TYPES.TEXT,
|
||||||
isDisabled: VALIDATION_TYPES.BOOLEAN,
|
isDisabled: VALIDATION_TYPES.BOOLEAN,
|
||||||
|
|
@ -30,7 +34,9 @@ class InputWidget extends BaseWidget<InputWidgetProps, WidgetState> {
|
||||||
inputValidators: VALIDATION_TYPES.ARRAY,
|
inputValidators: VALIDATION_TYPES.ARRAY,
|
||||||
focusIndex: VALIDATION_TYPES.NUMBER,
|
focusIndex: VALIDATION_TYPES.NUMBER,
|
||||||
isAutoFocusEnabled: VALIDATION_TYPES.BOOLEAN,
|
isAutoFocusEnabled: VALIDATION_TYPES.BOOLEAN,
|
||||||
|
onTextChanged: VALIDATION_TYPES.TEXT,
|
||||||
isRequired: VALIDATION_TYPES.BOOLEAN,
|
isRequired: VALIDATION_TYPES.BOOLEAN,
|
||||||
|
isValid: VALIDATION_TYPES.BOOLEAN,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
static getTriggerPropertyMap(): TriggerPropertiesMap {
|
static getTriggerPropertyMap(): TriggerPropertiesMap {
|
||||||
|
|
@ -64,6 +70,16 @@ class InputWidget extends BaseWidget<InputWidgetProps, WidgetState> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentDidUpdate(prevProps: InputWidgetProps) {
|
||||||
|
super.componentDidUpdate(prevProps);
|
||||||
|
if (
|
||||||
|
(this.props.text !== prevProps.text && this.props.text === undefined) ||
|
||||||
|
this.props.defaultText !== prevProps.defaultText
|
||||||
|
) {
|
||||||
|
this.updateWidgetMetaProperty("text", this.props.defaultText);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onValueChange = (value: string) => {
|
onValueChange = (value: string) => {
|
||||||
this.updateWidgetMetaProperty("text", value);
|
this.updateWidgetMetaProperty("text", value);
|
||||||
if (!this.props.isDirty) {
|
if (!this.props.isDirty) {
|
||||||
|
|
@ -96,7 +112,6 @@ class InputWidget extends BaseWidget<InputWidgetProps, WidgetState> {
|
||||||
if (this.props.maxNum) conditionalProps.maxNum = this.props.maxNum;
|
if (this.props.maxNum) conditionalProps.maxNum = this.props.maxNum;
|
||||||
if (this.props.minNum) conditionalProps.minNum = this.props.minNum;
|
if (this.props.minNum) conditionalProps.minNum = this.props.minNum;
|
||||||
if (this.props.isRequired) conditionalProps.label = `${this.props.label} *`;
|
if (this.props.isRequired) conditionalProps.label = `${this.props.label} *`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InputComponent
|
<InputComponent
|
||||||
value={value}
|
value={value}
|
||||||
|
|
|
||||||
|
|
@ -3,16 +3,22 @@ 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 { EventType } from "constants/ActionConstants";
|
import { EventType } from "constants/ActionConstants";
|
||||||
import { WidgetPropertyValidationType } from "utils/ValidationFactory";
|
import {
|
||||||
|
WidgetPropertyValidationType,
|
||||||
|
BASE_WIDGET_VALIDATION,
|
||||||
|
} from "utils/ValidationFactory";
|
||||||
import { VALIDATION_TYPES } from "constants/WidgetValidation";
|
import { VALIDATION_TYPES } from "constants/WidgetValidation";
|
||||||
import { TriggerPropertiesMap } from "utils/WidgetFactory";
|
import { TriggerPropertiesMap } from "utils/WidgetFactory";
|
||||||
|
|
||||||
class RadioGroupWidget extends BaseWidget<RadioGroupWidgetProps, WidgetState> {
|
class RadioGroupWidget extends BaseWidget<RadioGroupWidgetProps, WidgetState> {
|
||||||
static getPropertyValidationMap(): WidgetPropertyValidationType {
|
static getPropertyValidationMap(): WidgetPropertyValidationType {
|
||||||
return {
|
return {
|
||||||
|
...BASE_WIDGET_VALIDATION,
|
||||||
label: VALIDATION_TYPES.TEXT,
|
label: VALIDATION_TYPES.TEXT,
|
||||||
options: VALIDATION_TYPES.OPTIONS_DATA,
|
options: VALIDATION_TYPES.OPTIONS_DATA,
|
||||||
selectedOptionValue: VALIDATION_TYPES.TEXT,
|
selectedOptionValue: VALIDATION_TYPES.TEXT,
|
||||||
|
onSelectionChange: VALIDATION_TYPES.TEXT,
|
||||||
|
defaultOptionValue: VALIDATION_TYPES.TEXT,
|
||||||
isRequired: VALIDATION_TYPES.BOOLEAN,
|
isRequired: VALIDATION_TYPES.BOOLEAN,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -28,6 +34,30 @@ class RadioGroupWidget extends BaseWidget<RadioGroupWidgetProps, WidgetState> {
|
||||||
onSelectionChange: true,
|
onSelectionChange: true,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
super.componentDidMount();
|
||||||
|
if (this.props.defaultOptionValue) {
|
||||||
|
this.updateWidgetMetaProperty(
|
||||||
|
"selectedOptionValue",
|
||||||
|
this.props.defaultOptionValue,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUpdate(prevProps: RadioGroupWidgetProps) {
|
||||||
|
super.componentDidUpdate(prevProps);
|
||||||
|
if (
|
||||||
|
(this.props.selectedOptionValue !== prevProps.selectedOptionValue &&
|
||||||
|
this.props.selectedOptionValue === undefined) ||
|
||||||
|
this.props.defaultOptionValue !== prevProps.defaultOptionValue
|
||||||
|
) {
|
||||||
|
this.updateWidgetMetaProperty(
|
||||||
|
"selectedOptionValue",
|
||||||
|
this.props.defaultOptionValue,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
getPageView() {
|
getPageView() {
|
||||||
return (
|
return (
|
||||||
<RadioGroupComponent
|
<RadioGroupComponent
|
||||||
|
|
@ -35,7 +65,6 @@ class RadioGroupWidget extends BaseWidget<RadioGroupWidgetProps, WidgetState> {
|
||||||
onRadioSelectionChange={this.onRadioSelectionChange}
|
onRadioSelectionChange={this.onRadioSelectionChange}
|
||||||
key={this.props.widgetId}
|
key={this.props.widgetId}
|
||||||
label={`${this.props.label}${this.props.isRequired ? " *" : ""}`}
|
label={`${this.props.label}${this.props.isRequired ? " *" : ""}`}
|
||||||
defaultOptionValue={this.props.defaultOptionValue}
|
|
||||||
selectedOptionValue={this.props.selectedOptionValue}
|
selectedOptionValue={this.props.selectedOptionValue}
|
||||||
options={this.props.options}
|
options={this.props.options}
|
||||||
isLoading={this.props.isLoading}
|
isLoading={this.props.isLoading}
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,16 @@ 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 {
|
||||||
|
WidgetPropertyValidationType,
|
||||||
|
BASE_WIDGET_VALIDATION,
|
||||||
|
} from "utils/ValidationFactory";
|
||||||
import { VALIDATION_TYPES } from "constants/WidgetValidation";
|
import { VALIDATION_TYPES } from "constants/WidgetValidation";
|
||||||
|
|
||||||
class SpinnerWidget extends BaseWidget<SpinnerWidgetProps, WidgetState> {
|
class SpinnerWidget extends BaseWidget<SpinnerWidgetProps, WidgetState> {
|
||||||
static getPropertyValidationMap(): WidgetPropertyValidationType {
|
static getPropertyValidationMap(): WidgetPropertyValidationType {
|
||||||
return {
|
return {
|
||||||
|
...BASE_WIDGET_VALIDATION,
|
||||||
size: VALIDATION_TYPES.NUMBER,
|
size: VALIDATION_TYPES.NUMBER,
|
||||||
value: VALIDATION_TYPES.NUMBER,
|
value: VALIDATION_TYPES.NUMBER,
|
||||||
ellipsize: VALIDATION_TYPES.BOOLEAN,
|
ellipsize: VALIDATION_TYPES.BOOLEAN,
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,10 @@ import { forIn } from "lodash";
|
||||||
import TableComponent from "components/designSystems/syncfusion/TableComponent";
|
import TableComponent from "components/designSystems/syncfusion/TableComponent";
|
||||||
|
|
||||||
import { VALIDATION_TYPES } from "constants/WidgetValidation";
|
import { VALIDATION_TYPES } from "constants/WidgetValidation";
|
||||||
import { WidgetPropertyValidationType } from "utils/ValidationFactory";
|
import {
|
||||||
|
WidgetPropertyValidationType,
|
||||||
|
BASE_WIDGET_VALIDATION,
|
||||||
|
} from "utils/ValidationFactory";
|
||||||
import { ColumnModel } from "@syncfusion/ej2-grids";
|
import { ColumnModel } from "@syncfusion/ej2-grids";
|
||||||
import { ColumnDirTypecast } from "@syncfusion/ej2-react-grids";
|
import { ColumnDirTypecast } from "@syncfusion/ej2-react-grids";
|
||||||
import { ColumnAction } from "components/propertyControls/ColumnActionSelectorControl";
|
import { ColumnAction } from "components/propertyControls/ColumnActionSelectorControl";
|
||||||
|
|
@ -30,6 +33,7 @@ function constructColumns(data: object[]): ColumnModel[] | ColumnDirTypecast[] {
|
||||||
class TableWidget extends BaseWidget<TableWidgetProps, WidgetState> {
|
class TableWidget extends BaseWidget<TableWidgetProps, WidgetState> {
|
||||||
static getPropertyValidationMap(): WidgetPropertyValidationType {
|
static getPropertyValidationMap(): WidgetPropertyValidationType {
|
||||||
return {
|
return {
|
||||||
|
...BASE_WIDGET_VALIDATION,
|
||||||
tableData: VALIDATION_TYPES.TABLE_DATA,
|
tableData: VALIDATION_TYPES.TABLE_DATA,
|
||||||
nextPageKey: VALIDATION_TYPES.TEXT,
|
nextPageKey: VALIDATION_TYPES.TEXT,
|
||||||
prevPageKey: VALIDATION_TYPES.TEXT,
|
prevPageKey: VALIDATION_TYPES.TEXT,
|
||||||
|
|
@ -156,11 +160,6 @@ class TableWidget extends BaseWidget<TableWidgetProps, WidgetState> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type RowData = {
|
|
||||||
rowIndex: number;
|
|
||||||
};
|
|
||||||
type SelectedRow = object & RowData;
|
|
||||||
|
|
||||||
export interface TableWidgetProps extends WidgetProps {
|
export interface TableWidgetProps extends WidgetProps {
|
||||||
nextPageKey?: string;
|
nextPageKey?: string;
|
||||||
prevPageKey?: string;
|
prevPageKey?: string;
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,10 @@ import BaseWidget, { WidgetProps, WidgetState } from "./BaseWidget";
|
||||||
import { WidgetType } from "constants/WidgetConstants";
|
import { WidgetType } from "constants/WidgetConstants";
|
||||||
import TextComponent from "components/designSystems/blueprint/TextComponent";
|
import TextComponent from "components/designSystems/blueprint/TextComponent";
|
||||||
import { VALIDATION_TYPES } from "constants/WidgetValidation";
|
import { VALIDATION_TYPES } from "constants/WidgetValidation";
|
||||||
import { WidgetPropertyValidationType } from "utils/ValidationFactory";
|
import {
|
||||||
|
WidgetPropertyValidationType,
|
||||||
|
BASE_WIDGET_VALIDATION,
|
||||||
|
} from "utils/ValidationFactory";
|
||||||
|
|
||||||
const LINE_HEIGHTS: { [key in TextStyle]: number } = {
|
const LINE_HEIGHTS: { [key in TextStyle]: number } = {
|
||||||
// The following values are arrived at by multiplying line-height with font-size
|
// The following values are arrived at by multiplying line-height with font-size
|
||||||
|
|
@ -16,9 +19,10 @@ const LINE_HEIGHTS: { [key in TextStyle]: number } = {
|
||||||
class TextWidget extends BaseWidget<TextWidgetProps, WidgetState> {
|
class TextWidget extends BaseWidget<TextWidgetProps, WidgetState> {
|
||||||
static getPropertyValidationMap(): WidgetPropertyValidationType {
|
static getPropertyValidationMap(): WidgetPropertyValidationType {
|
||||||
return {
|
return {
|
||||||
|
...BASE_WIDGET_VALIDATION,
|
||||||
text: VALIDATION_TYPES.TEXT,
|
text: VALIDATION_TYPES.TEXT,
|
||||||
textStyle: VALIDATION_TYPES.TEXT,
|
textStyle: VALIDATION_TYPES.TEXT,
|
||||||
isVisible: VALIDATION_TYPES.BOOLEAN,
|
shouldScroll: VALIDATION_TYPES.BOOLEAN,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
2250
app/client/yarn.lock
2250
app/client/yarn.lock
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user