{apiId ? (
diff --git a/app/client/src/pages/Editor/DataSourceEditor/Collapsible.tsx b/app/client/src/pages/Editor/DataSourceEditor/Collapsible.tsx
index 156bbf0f29..7d67461003 100644
--- a/app/client/src/pages/Editor/DataSourceEditor/Collapsible.tsx
+++ b/app/client/src/pages/Editor/DataSourceEditor/Collapsible.tsx
@@ -27,6 +27,7 @@ interface ComponentState {
interface ComponentProps {
children: any;
title: string;
+ defaultIsOpen: boolean;
}
type Props = ComponentProps;
@@ -36,7 +37,7 @@ class Collapsible extends React.Component
{
super(props);
this.state = {
- isOpen: true,
+ isOpen: props.defaultIsOpen || false,
};
}
@@ -54,6 +55,7 @@ class Collapsible extends React.Component {
}}
/>
this.setState({ isOpen: !this.state.isOpen })}
>
{title}
diff --git a/app/client/src/pages/Editor/DataSourceEditor/DBForm.tsx b/app/client/src/pages/Editor/DataSourceEditor/DBForm.tsx
index 8f2f3e9911..b6f19fe5a2 100644
--- a/app/client/src/pages/Editor/DataSourceEditor/DBForm.tsx
+++ b/app/client/src/pages/Editor/DataSourceEditor/DBForm.tsx
@@ -332,9 +332,7 @@ class DatasourceDBEditor extends React.Component<
/>
{!_.isNil(sections)
- ? _.map(sections, section => {
- return this.renderMainSection(section);
- })
+ ? _.map(sections, this.renderMainSection)
: undefined}
{
+ renderMainSection = (section: any, index: number) => {
return (
-
+
{this.renderEachConfig(section)}
);
@@ -413,7 +411,7 @@ class DatasourceDBEditor extends React.Component<
}
return (
-
+
{controlType !== "KEYVALUE_ARRAY" &&
controlType !== "SWITCH" && (
diff --git a/app/client/src/pages/Editor/QueryEditor/Form.tsx b/app/client/src/pages/Editor/QueryEditor/Form.tsx
index 4f0f44a2d5..4ea450b47d 100644
--- a/app/client/src/pages/Editor/QueryEditor/Form.tsx
+++ b/app/client/src/pages/Editor/QueryEditor/Form.tsx
@@ -11,9 +11,16 @@ import {
ColumnsDirective,
ColumnDirective,
} from "@syncfusion/ej2-react-grids";
+import CheckboxField from "components/editorComponents/form/fields/CheckboxField";
import styled, { createGlobalStyle } from "styled-components";
import { Popover, Icon } from "@blueprintjs/core";
-import { components, MenuListComponentProps } from "react-select";
+import {
+ components,
+ MenuListComponentProps,
+ SingleValueProps,
+ OptionTypeBase,
+ OptionProps,
+} from "react-select";
import history from "utils/history";
import DynamicAutocompleteInput from "components/editorComponents/DynamicAutocompleteInput";
import { DATA_SOURCES_EDITOR_URL } from "constants/routes";
@@ -93,7 +100,7 @@ const ResponseContainer = styled.div`
const ResponseContent = styled.div`
height: calc(
- 100vh - (100vh / 3) - 150px - ${props => props.theme.headerHeight}
+ 100vh - (100vh / 3) - 175px - ${props => props.theme.headerHeight}
);
overflow: auto;
`;
@@ -175,7 +182,7 @@ const StyledGridComponent = styled(GridComponent)`
}
.e-gridcontent {
max-height: calc(
- 100vh - (100vh / 3) - 150px - 49px -
+ 100vh - (100vh / 3) - 175px - 49px -
${props => props.theme.headerHeight}
);
overflow: auto;
@@ -203,6 +210,31 @@ const CreateDatasource = styled.div`
}
`;
+const Container = styled.div`
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+
+ .plugin-image {
+ height: 20px;
+ width: auto;
+ }
+
+ .selected-value {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: no-wrap;
+ margin-left: 6px;
+ }
+`;
+
+const StyledCheckbox = styled(CheckboxField)`
+ &&& {
+ font-size: 14px;
+ margin-top: 10px;
+ }
+`;
+
type QueryFormProps = {
isCreating: boolean;
onDeleteClick: () => void;
@@ -299,6 +331,40 @@ const QueryEditorForm: React.FC = (props: Props) => {
);
};
+ const SingleValue = (props: SingleValueProps) => {
+ return (
+ <>
+
+
+
+ {props.children}
+
+
+ >
+ );
+ };
+
+ const CustomOption = (props: OptionProps) => {
+ return (
+ <>
+
+
+
+ {props.children}
+
+
+ >
+ );
+ };
+
return (
{dataSources.length === 0 && (
diff --git a/app/client/src/pages/Editor/QueryEditor/JSONViewer.tsx b/app/client/src/pages/Editor/QueryEditor/JSONViewer.tsx
index 43306d43f5..c8ef723d20 100644
--- a/app/client/src/pages/Editor/QueryEditor/JSONViewer.tsx
+++ b/app/client/src/pages/Editor/QueryEditor/JSONViewer.tsx
@@ -32,6 +32,7 @@ class JSONOutput extends React.Component {
style: {
fontSize: "14px",
},
+ collapsed: 1,
};
if (!src.length) {
diff --git a/app/client/src/pages/Editor/QueryEditor/helpers.ts b/app/client/src/pages/Editor/QueryEditor/helpers.ts
new file mode 100644
index 0000000000..5c2b7780a1
--- /dev/null
+++ b/app/client/src/pages/Editor/QueryEditor/helpers.ts
@@ -0,0 +1,21 @@
+import { Plugin } from "api/PluginApi";
+import {
+ PLUGIN_PACKAGE_MONGO,
+ PLUGIN_PACKAGE_POSTGRES,
+} from "constants/QueryEditorConstants";
+import ImageAlt from "assets/images/placeholder-image.svg";
+import Postgres from "assets/images/Postgress.png";
+import MongoDB from "assets/images/MongoDB.png";
+
+export const getPluginImage = (plugins: Plugin[], pluginId: string) => {
+ const plugin = plugins.find(plugin => plugin.id === pluginId);
+
+ switch (plugin?.packageName) {
+ case PLUGIN_PACKAGE_MONGO:
+ return MongoDB;
+ case PLUGIN_PACKAGE_POSTGRES:
+ return Postgres;
+ default:
+ return ImageAlt;
+ }
+};
diff --git a/app/client/src/pages/Editor/QueryEditor/index.tsx b/app/client/src/pages/Editor/QueryEditor/index.tsx
index 1b39d7e42f..9249dd9c36 100644
--- a/app/client/src/pages/Editor/QueryEditor/index.tsx
+++ b/app/client/src/pages/Editor/QueryEditor/index.tsx
@@ -17,11 +17,13 @@ import { deleteQuery, executeQuery } from "actions/queryPaneActions";
import { AppState } from "reducers";
import { getDataSources } from "selectors/editorSelectors";
import { QUERY_EDITOR_FORM_NAME } from "constants/forms";
+import { Plugin } from "api/PluginApi";
import { Datasource } from "api/DatasourcesApi";
import { QueryPaneReduxState } from "reducers/uiReducers/queryPaneReducer";
import {
getPluginIdsOfPackageNames,
getPluginPackageFromDatasourceId,
+ getPlugins,
} from "selectors/entitiesSelector";
import {
PLUGIN_PACKAGE_DBS,
@@ -30,6 +32,7 @@ import {
import { getCurrentApplication } from "selectors/applicationSelectors";
import { ApiPaneReduxState } from "reducers/uiReducers/apiPaneReducer";
import { QueryAction, RestAction } from "entities/Action";
+import { getPluginImage } from "pages/Editor/QueryEditor/helpers";
const EmptyStateContainer = styled.div`
display: flex;
@@ -38,6 +41,7 @@ const EmptyStateContainer = styled.div`
`;
type QueryPageProps = {
+ plugins: Plugin[];
dataSources: Datasource[];
queryPane: QueryPaneReduxState;
formData: RestAction;
@@ -117,6 +121,7 @@ class QueryEditor extends React.Component {
const DATASOURCES_OPTIONS = validDataSources.map(dataSource => ({
label: dataSource.name,
value: dataSource.id,
+ image: getPluginImage(this.props.plugins, dataSource.pluginId),
}));
return (
@@ -170,6 +175,7 @@ const mapStateToProps = (state: AppState): any => {
);
return {
+ plugins: getPlugins(state),
runErrorMessage,
apiPane: state.ui.apiPane,
pluginIds: getPluginIdsOfPackageNames(state, PLUGIN_PACKAGE_DBS),
diff --git a/app/client/src/pages/Editor/QuerySidebar.tsx b/app/client/src/pages/Editor/QuerySidebar.tsx
index dfd0b1398d..57715f1c41 100644
--- a/app/client/src/pages/Editor/QuerySidebar.tsx
+++ b/app/client/src/pages/Editor/QuerySidebar.tsx
@@ -9,18 +9,24 @@ import EditorSidebar from "pages/Editor/EditorSidebar";
import { QUERY_CONSTANT } from "constants/QueryEditorConstants";
import { QueryEditorRouteParams } from "constants/routes";
import { Datasource } from "api/DatasourcesApi";
+import { getPluginImage } from "pages/Editor/QueryEditor/helpers";
+import { Plugin } from "api/PluginApi";
import {
createActionRequest,
moveActionRequest,
copyActionRequest,
} from "actions/actionActions";
-import { deleteQuery } from "actions/queryPaneActions";
-import { changeQuery, initQueryPane } from "actions/queryPaneActions";
-import { getQueryActions } from "selectors/entitiesSelector";
+import {
+ deleteQuery,
+ changeQuery,
+ initQueryPane,
+} from "actions/queryPaneActions";
+import { getQueryActions, getPlugins } from "selectors/entitiesSelector";
import { getNextEntityName } from "utils/AppsmithUtils";
import { getDataSources } from "selectors/editorSelectors";
import { QUERY_EDITOR_URL_WITH_SELECTED_PAGE_ID } from "constants/routes";
import { RestAction } from "entities/Action";
+import { Colors } from "constants/Colors";
const ActionItem = styled.div`
flex: 1;
@@ -34,9 +40,23 @@ const ActionName = styled.span`
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
+ margin-left: 10px;
+ max-width: 125px;
+`;
+
+const StyledImage = styled.img`
+ height: 20px;
+ width: 20px;
+
+ svg {
+ path {
+ fill: ${Colors.WHITE};
+ }
+ }
`;
interface ReduxStateProps {
+ plugins: Plugin[];
queries: ActionDataState;
apiPane: ApiPaneReduxState;
actions: ActionDataState;
@@ -148,6 +168,11 @@ class QuerySidebar extends React.Component {
renderItem = (query: RestAction) => {
return (
+
{query.name}
);
@@ -191,6 +216,7 @@ class QuerySidebar extends React.Component {
}
const mapStateToProps = (state: AppState): ReduxStateProps => ({
+ plugins: getPlugins(state),
queries: getQueryActions(state),
apiPane: state.ui.apiPane,
actions: state.entities.actions,
diff --git a/app/client/src/utils/autocomplete/EntityDefinitions.ts b/app/client/src/utils/autocomplete/EntityDefinitions.ts
index 9f983e4922..0a64fd3c06 100644
--- a/app/client/src/utils/autocomplete/EntityDefinitions.ts
+++ b/app/client/src/utils/autocomplete/EntityDefinitions.ts
@@ -157,12 +157,13 @@ export const entityDefinitions = {
xAxisName: "string",
yAxisName: "string",
},
- FORM_WIDGET: {
+ FORM_WIDGET: (widget: any) => ({
"!doc":
"Form is used to capture a set of data inputs from a user. Forms are used specifically because they reset the data inputs when a form is submitted and disable submission for invalid data inputs",
"!url": "https://docs.appsmith.com/widget-reference/form",
isVisible: isVisible,
- },
+ data: generateTypeDef(widget.data),
+ }),
FORM_BUTTON_WIDGET: {
"!doc":
"Form button is provided by default to every form. It is used for form submission and resetting form inputs",
diff --git a/app/client/src/widgets/CheckboxWidget.tsx b/app/client/src/widgets/CheckboxWidget.tsx
index 1df4d69bbf..dbad707205 100644
--- a/app/client/src/widgets/CheckboxWidget.tsx
+++ b/app/client/src/widgets/CheckboxWidget.tsx
@@ -8,7 +8,10 @@ import {
WidgetPropertyValidationType,
BASE_WIDGET_VALIDATION,
} from "utils/ValidationFactory";
-import { TriggerPropertiesMap } from "utils/WidgetFactory";
+import {
+ TriggerPropertiesMap,
+ DerivedPropertiesMap,
+} from "utils/WidgetFactory";
class CheckboxWidget extends BaseWidget {
static getPropertyValidationMap(): WidgetPropertyValidationType {
@@ -32,6 +35,12 @@ class CheckboxWidget extends BaseWidget {
};
}
+ static getDerivedPropertiesMap(): DerivedPropertiesMap {
+ return {
+ value: `{{this.isChecked}}`,
+ };
+ }
+
static getMetaPropertiesMap(): Record {
return {
isChecked: undefined,
diff --git a/app/client/src/widgets/DatePickerWidget.tsx b/app/client/src/widgets/DatePickerWidget.tsx
index 4a33f731da..1dc11aedaf 100644
--- a/app/client/src/widgets/DatePickerWidget.tsx
+++ b/app/client/src/widgets/DatePickerWidget.tsx
@@ -34,6 +34,7 @@ class DatePickerWidget extends BaseWidget {
static getDerivedPropertiesMap(): DerivedPropertiesMap {
return {
isValid: `{{ this.isRequired ? !!this.selectedDate : true }}`,
+ value: `{{ this.selectedDate }}`,
};
}
diff --git a/app/client/src/widgets/DropdownWidget.tsx b/app/client/src/widgets/DropdownWidget.tsx
index b3cc7b0a80..7e2f29a603 100644
--- a/app/client/src/widgets/DropdownWidget.tsx
+++ b/app/client/src/widgets/DropdownWidget.tsx
@@ -63,6 +63,7 @@ class DropdownWidget extends BaseWidget {
},
};
}
+
static getDerivedPropertiesMap() {
return {
isValid: `{{this.isRequired ? this.selectionType === 'SINGLE_SELECT' ? !!this.selectedOption : !!this.selectedIndexArr && this.selectedIndexArr.length > 0 : true}}`,
@@ -70,6 +71,7 @@ class DropdownWidget extends BaseWidget {
selectedOptionArr: `{{this.selectionType === "MULTI_SELECT" ? this.options.filter(opt => _.includes(this.selectedOptionValueArr, opt.value)) : undefined}}`,
selectedIndex: `{{ _.findIndex(this.options, { value: this.selectedOption.value } ) }}`,
selectedIndexArr: `{{ this.selectedOptionValueArr.map(o => _.findIndex(this.options, { value: o })) }}`,
+ value: `{{ this.selectionType === 'SINGLE_SELECT' ? this.selectedOptionValue : this.selectedOptionValueArr }}`,
};
}
diff --git a/app/client/src/widgets/FilepickerWidget.tsx b/app/client/src/widgets/FilepickerWidget.tsx
index 137c530f5c..8c406b2810 100644
--- a/app/client/src/widgets/FilepickerWidget.tsx
+++ b/app/client/src/widgets/FilepickerWidget.tsx
@@ -49,6 +49,7 @@ class FilePickerWidget extends BaseWidget<
static getDerivedPropertiesMap(): DerivedPropertiesMap {
return {
isValid: `{{ this.isRequired ? this.files.length > 0 : true }}`,
+ value: `{{this.files}}`,
};
}
diff --git a/app/client/src/widgets/FormWidget.tsx b/app/client/src/widgets/FormWidget.tsx
index 5330f3f2e3..8349bc4d9e 100644
--- a/app/client/src/widgets/FormWidget.tsx
+++ b/app/client/src/widgets/FormWidget.tsx
@@ -2,8 +2,9 @@ import React from "react";
import _ from "lodash";
import { WidgetProps } from "./BaseWidget";
import { WidgetType } from "constants/WidgetConstants";
-import ContainerWidget from "widgets/ContainerWidget";
+import ContainerWidget, { ContainerWidgetProps } from "widgets/ContainerWidget";
import { ContainerComponentProps } from "components/designSystems/appsmith/ContainerComponent";
+import shallowEqual from "shallowequal";
class FormWidget extends ContainerWidget {
checkInvalidChildren = (children: WidgetProps[]): boolean => {
@@ -18,6 +19,36 @@ class FormWidget extends ContainerWidget {
super.resetChildrenMetaProperty(this.props.widgetId);
};
+ componentDidMount() {
+ super.componentDidMount();
+ this.updateFormData();
+ }
+
+ componentDidUpdate(prevProps: ContainerWidgetProps) {
+ super.componentDidUpdate(prevProps);
+ this.updateFormData();
+ }
+
+ updateFormData() {
+ if (this.props.children) {
+ const formData = this.getFormData(this.props.children[0]);
+ if (!shallowEqual(formData, this.props.data)) {
+ this.updateWidgetMetaProperty("data", formData);
+ }
+ }
+ }
+
+ getFormData(formWidget: ContainerWidgetProps) {
+ const formData: any = {};
+ if (formWidget.children)
+ formWidget.children.map(widgetData => {
+ if (widgetData.value) {
+ formData[widgetData.widgetName] = widgetData.value;
+ }
+ });
+ return formData;
+ }
+
renderChildWidget(childWidgetData: WidgetProps): React.ReactNode {
if (childWidgetData.children) {
const isInvalid = this.checkInvalidChildren(childWidgetData.children);
@@ -37,6 +68,7 @@ class FormWidget extends ContainerWidget {
export interface FormWidgetProps extends ContainerComponentProps {
name: string;
+ data: object;
}
export default FormWidget;
diff --git a/app/client/src/widgets/InputWidget.tsx b/app/client/src/widgets/InputWidget.tsx
index 097694bf53..38ff82c101 100644
--- a/app/client/src/widgets/InputWidget.tsx
+++ b/app/client/src/widgets/InputWidget.tsx
@@ -59,6 +59,7 @@ class InputWidget extends BaseWidget {
static getDerivedPropertiesMap(): DerivedPropertiesMap {
return {
isValid: `{{!!(this.isRequired ? this.text && this.text.length > 0 ? this.regex ? new RegExp(this.regex).test(this.text) : true : false : this.regex ? new RegExp(this.regex).test(this.text) : true)}}`,
+ value: `{{this.text}}`,
};
}
diff --git a/app/client/src/widgets/RadioGroupWidget.tsx b/app/client/src/widgets/RadioGroupWidget.tsx
index 76becbf687..f666cdac51 100644
--- a/app/client/src/widgets/RadioGroupWidget.tsx
+++ b/app/client/src/widgets/RadioGroupWidget.tsx
@@ -27,6 +27,7 @@ class RadioGroupWidget extends BaseWidget {
selectedOption:
"{{_.find(this.options, { value: this.selectedOptionValue })}}",
isValid: `{{ this.isRequired ? !!this.selectedOptionValue : true }}`,
+ value: `{{this.selectedOptionValue}}`,
};
}
static getTriggerPropertyMap(): TriggerPropertiesMap {
diff --git a/app/client/src/widgets/RichTextEditorWidget.tsx b/app/client/src/widgets/RichTextEditorWidget.tsx
index 2c0e85bbf3..04af041977 100644
--- a/app/client/src/widgets/RichTextEditorWidget.tsx
+++ b/app/client/src/widgets/RichTextEditorWidget.tsx
@@ -4,7 +4,10 @@ import { WidgetType } from "constants/WidgetConstants";
import { EventType } from "constants/ActionConstants";
import { WidgetPropertyValidationType } from "utils/ValidationFactory";
import { VALIDATION_TYPES } from "constants/WidgetValidation";
-import { TriggerPropertiesMap } from "utils/WidgetFactory";
+import {
+ TriggerPropertiesMap,
+ DerivedPropertiesMap,
+} from "utils/WidgetFactory";
import Skeleton from "components/utils/Skeleton";
const RichtextEditorComponent = lazy(() =>
@@ -45,6 +48,12 @@ class RichTextEditorWidget extends BaseWidget<
};
}
+ static getDerivedPropertiesMap(): DerivedPropertiesMap {
+ return {
+ value: `{{this.text}}`,
+ };
+ }
+
onValueChange = (text: string) => {
this.updateWidgetMetaProperty("text", text);
if (this.props.onTextChange) {
diff --git a/app/client/src/widgets/TextWidget.tsx b/app/client/src/widgets/TextWidget.tsx
index 8fed6bf5e3..a683a7c92e 100644
--- a/app/client/src/widgets/TextWidget.tsx
+++ b/app/client/src/widgets/TextWidget.tsx
@@ -7,6 +7,7 @@ import {
WidgetPropertyValidationType,
BASE_WIDGET_VALIDATION,
} from "utils/ValidationFactory";
+import { DerivedPropertiesMap } from "utils/WidgetFactory";
const LINE_HEIGHTS: { [key in TextStyle]: number } = {
// The following values are arrived at by multiplying line-height with font-size
@@ -48,6 +49,12 @@ class TextWidget extends BaseWidget {
);
}
+ static getDerivedPropertiesMap(): DerivedPropertiesMap {
+ return {
+ value: `{{ this.text }}`,
+ };
+ }
+
getWidgetType(): WidgetType {
return "TEXT_WIDGET";
}