Merge branch 'release' of github.com:appsmithorg/appsmith into release
|
|
@ -4,7 +4,7 @@
|
|||
"createBlankApiCard": ".t--createBlankApiCard",
|
||||
"eachProviderCard": ".t--eachProviderCard",
|
||||
"nameOfApi": ".t--nameOfApi",
|
||||
"ApiNameField": ".t--action-name-edit-field span",
|
||||
"ApiNameField": ".bp3-editable-text",
|
||||
"addToPageBtn": ".t--addToPageBtn",
|
||||
"ApiDeleteBtn": ".t--apiFormDeleteBtn",
|
||||
"ApiRunBtn": ".t--apiFormRunBtn",
|
||||
|
|
|
|||
|
|
@ -331,7 +331,7 @@ Cypress.Commands.add("CreateAPI", apiname => {
|
|||
.type(apiname)
|
||||
.should("have.value", apiname)
|
||||
.blur();
|
||||
//cy.WaitAutoSave();
|
||||
cy.WaitAutoSave();
|
||||
// Added because api name edit takes some time to
|
||||
// reflect in api sidebar after the call passes.
|
||||
cy.wait(2000);
|
||||
|
|
@ -363,13 +363,17 @@ Cypress.Commands.add("EditApiName", apiname => {
|
|||
Cypress.Commands.add("WaitAutoSave", () => {
|
||||
// wait for save query to trigger
|
||||
cy.wait(200);
|
||||
cy.wait("@saveQuery");
|
||||
cy.wait("@saveAction");
|
||||
//cy.wait("@postExecute");
|
||||
});
|
||||
|
||||
Cypress.Commands.add("RunAPI", () => {
|
||||
cy.get(ApiEditor.ApiRunBtn).click({ force: true });
|
||||
cy.wait("@postExecute");
|
||||
cy.wait("@postExecute").should(
|
||||
"have.nested.property",
|
||||
"response.body.responseMeta.status",
|
||||
200,
|
||||
);
|
||||
});
|
||||
|
||||
Cypress.Commands.add("SaveAndRunAPI", () => {
|
||||
|
|
@ -1184,6 +1188,7 @@ Cypress.Commands.add("createAndFillApi", (url, parameters) => {
|
|||
cy.get(ApiEditor.ApiNameField).should("be.visible");
|
||||
cy.expect(response.response.body.responseMeta.success).to.eq(true);
|
||||
cy.get(ApiEditor.ApiNameField)
|
||||
.click()
|
||||
.invoke("text")
|
||||
.then(text => {
|
||||
const someText = text;
|
||||
|
|
|
|||
|
|
@ -7,8 +7,12 @@ export interface Plugin {
|
|||
name: string;
|
||||
type: "API" | "DB";
|
||||
packageName: string;
|
||||
iconLocation?: string;
|
||||
uiComponent: "ApiEditorForm" | "RapidApiEditorForm" | "DbEditorForm";
|
||||
allowUserDatasources?: boolean;
|
||||
templates: Record<string, string>;
|
||||
responseType?: "TABLE" | "JSON";
|
||||
documentationLink?: string;
|
||||
}
|
||||
|
||||
export interface DatasourceForm {
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 102 KiB |
|
Before Width: | Height: | Size: 58 KiB |
|
Before Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 318 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
|
@ -1 +1,2 @@
|
|||
export const DATASOURCE_CONSTANT = "DATASOURCE";
|
||||
export const APPSMITH_IP_ADDRESS = "18.223.74.85";
|
||||
|
|
|
|||
|
|
@ -87,6 +87,10 @@ export const HelpMap = {
|
|||
path: "/core-concepts/apis/taking-inputs-from-widgets",
|
||||
searchKey: "Taking Inputs from Widgets",
|
||||
},
|
||||
DATASOURCE_FORM: {
|
||||
path: "/core-concepts/connecting-to-databases",
|
||||
searchKey: "Connecting to databases",
|
||||
},
|
||||
};
|
||||
|
||||
export const HelpBaseURL = "https://docs.appsmith.com";
|
||||
|
|
|
|||
|
|
@ -2,11 +2,6 @@ import React from "react";
|
|||
import styled from "styled-components";
|
||||
import _ from "lodash";
|
||||
import { DATASOURCE_DB_FORM } from "constants/forms";
|
||||
import { REST_PLUGIN_PACKAGE_NAME } from "constants/ApiEditorConstants";
|
||||
import {
|
||||
PLUGIN_PACKAGE_MONGO,
|
||||
PLUGIN_PACKAGE_POSTGRES,
|
||||
} from "constants/QueryEditorConstants";
|
||||
import { Spinner } from "@blueprintjs/core";
|
||||
import { DATA_SOURCES_EDITOR_URL } from "constants/routes";
|
||||
import Collapsible from "./Collapsible";
|
||||
|
|
@ -14,18 +9,17 @@ import history from "utils/history";
|
|||
import FormLabel from "components/editorComponents/FormLabel";
|
||||
import { Icon } from "@blueprintjs/core";
|
||||
import FormTitle from "./FormTitle";
|
||||
import ImageAlt from "assets/images/placeholder-image.svg";
|
||||
import Postgres from "assets/images/Postgress.png";
|
||||
import MongoDB from "assets/images/MongoDB.png";
|
||||
import RestTemplateImage from "assets/images/RestAPI.png";
|
||||
import { ControlProps } from "components/formControls/BaseControl";
|
||||
import CenteredWrapper from "components/designSystems/appsmith/CenteredWrapper";
|
||||
import CollapsibleHelp from "components/designSystems/appsmith/help/CollapsibleHelp";
|
||||
|
||||
import FormControlFactory from "utils/FormControlFactory";
|
||||
import { HelpBaseURL, HelpMap } from "constants/HelpConstants";
|
||||
import Button from "components/editorComponents/Button";
|
||||
import { Datasource } from "api/DatasourcesApi";
|
||||
import { reduxForm, InjectedFormProps, Field } from "redux-form";
|
||||
import { BaseButton } from "components/designSystems/blueprint/ButtonComponent";
|
||||
import { APPSMITH_IP_ADDRESS } from "constants/DatasourceEditorConstants";
|
||||
|
||||
interface DatasourceDBEditorProps {
|
||||
onSave: (formValues: Datasource) => void;
|
||||
|
|
@ -42,6 +36,7 @@ interface DatasourceDBEditorProps {
|
|||
loadingFormConfigs: boolean;
|
||||
formConfig: [];
|
||||
isNewDatasource: boolean;
|
||||
pluginImage: string;
|
||||
}
|
||||
|
||||
interface DatasourceDBEditorState {
|
||||
|
|
@ -106,6 +101,17 @@ const LoadingContainer = styled(CenteredWrapper)`
|
|||
height: 50%;
|
||||
`;
|
||||
|
||||
const StyledOpenDocsIcon = styled(Icon)`
|
||||
svg {
|
||||
width: 12px;
|
||||
height: 18px;
|
||||
}
|
||||
`;
|
||||
|
||||
const CollapsibleWrapper = styled.div`
|
||||
width: max-content;
|
||||
`;
|
||||
|
||||
class DatasourceDBEditor extends React.Component<
|
||||
Props,
|
||||
DatasourceDBEditorState
|
||||
|
|
@ -181,19 +187,6 @@ class DatasourceDBEditor extends React.Component<
|
|||
return !_.isEmpty(errors);
|
||||
};
|
||||
|
||||
getImageSrc = (pluginPackage: string) => {
|
||||
switch (pluginPackage) {
|
||||
case PLUGIN_PACKAGE_POSTGRES:
|
||||
return Postgres;
|
||||
case PLUGIN_PACKAGE_MONGO:
|
||||
return MongoDB;
|
||||
case REST_PLUGIN_PACKAGE_NAME:
|
||||
return RestTemplateImage;
|
||||
default:
|
||||
return ImageAlt;
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const { loadingFormConfigs, formConfig } = this.props;
|
||||
const content = this.renderDataSourceConfigForm(formConfig);
|
||||
|
|
@ -287,7 +280,6 @@ class DatasourceDBEditor extends React.Component<
|
|||
|
||||
renderDataSourceConfigForm = (sections: any) => {
|
||||
const {
|
||||
selectedPluginPackage,
|
||||
isSaving,
|
||||
applicationId,
|
||||
pageId,
|
||||
|
|
@ -321,16 +313,26 @@ class DatasourceDBEditor extends React.Component<
|
|||
</span>
|
||||
<br />
|
||||
<FormTitleContainer>
|
||||
<PluginImage
|
||||
src={this.getImageSrc(selectedPluginPackage)}
|
||||
alt="Datasource"
|
||||
/>
|
||||
<PluginImage src={this.props.pluginImage} alt="Datasource" />
|
||||
<Field
|
||||
name="name"
|
||||
component={FormTitle}
|
||||
focusOnMount={this.props.isNewDatasource}
|
||||
/>
|
||||
</FormTitleContainer>
|
||||
<CollapsibleWrapper>
|
||||
<CollapsibleHelp>
|
||||
<span>{`Whitelist the IP ${APPSMITH_IP_ADDRESS} on your database instance to connect to it. `}</span>
|
||||
<a
|
||||
href={`${HelpBaseURL}${HelpMap["DATASOURCE_FORM"].path}`}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{"Read more "}
|
||||
<StyledOpenDocsIcon icon="document-open" />
|
||||
</a>
|
||||
</CollapsibleHelp>
|
||||
</CollapsibleWrapper>
|
||||
{!_.isNil(sections)
|
||||
? _.map(sections, this.renderMainSection)
|
||||
: undefined}
|
||||
|
|
|
|||
|
|
@ -3,18 +3,12 @@ import styled from "styled-components";
|
|||
import { connect } from "react-redux";
|
||||
import { initialize } from "redux-form";
|
||||
import { Card, Spinner } from "@blueprintjs/core";
|
||||
import { getDatasourcePlugins } from "selectors/entitiesSelector";
|
||||
import {
|
||||
getDatasourcePlugins,
|
||||
getPluginImages,
|
||||
} from "selectors/entitiesSelector";
|
||||
import { Plugin } from "api/PluginApi";
|
||||
import { DATASOURCE_DB_FORM } from "constants/forms";
|
||||
import ImageAlt from "assets/images/placeholder-image.svg";
|
||||
import Postgres from "assets/images/Postgress.png";
|
||||
import MongoDB from "assets/images/MongoDB.png";
|
||||
import RestTemplateImage from "assets/images/RestAPI.png";
|
||||
import { REST_PLUGIN_PACKAGE_NAME } from "constants/ApiEditorConstants";
|
||||
import {
|
||||
PLUGIN_PACKAGE_POSTGRES,
|
||||
PLUGIN_PACKAGE_MONGO,
|
||||
} from "constants/QueryEditorConstants";
|
||||
import {
|
||||
selectPlugin,
|
||||
createDatasourceFromForm,
|
||||
|
|
@ -120,6 +114,7 @@ interface ReduxDispatchProps {
|
|||
interface ReduxStateProps {
|
||||
plugins: Plugin[];
|
||||
currentApplication: UserApplication;
|
||||
pluginImages: Record<string, string>;
|
||||
}
|
||||
|
||||
type Props = ReduxStateProps & DatasourceHomeScreenProps & ReduxDispatchProps;
|
||||
|
|
@ -138,21 +133,8 @@ class DatasourceHomeScreen extends React.Component<Props> {
|
|||
});
|
||||
};
|
||||
|
||||
getImageSrc = (packageName: string) => {
|
||||
switch (packageName) {
|
||||
case PLUGIN_PACKAGE_POSTGRES:
|
||||
return Postgres;
|
||||
case PLUGIN_PACKAGE_MONGO:
|
||||
return MongoDB;
|
||||
case REST_PLUGIN_PACKAGE_NAME:
|
||||
return RestTemplateImage;
|
||||
default:
|
||||
return ImageAlt;
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const { plugins, isSaving } = this.props;
|
||||
const { plugins, isSaving, pluginImages } = this.props;
|
||||
|
||||
return (
|
||||
<DatasourceHomePage>
|
||||
|
|
@ -175,7 +157,7 @@ class DatasourceHomeScreen extends React.Component<Props> {
|
|||
onClick={() => this.goToCreateDatasource(plugin.id)}
|
||||
>
|
||||
<img
|
||||
src={this.getImageSrc(plugin.packageName)}
|
||||
src={pluginImages[plugin.id]}
|
||||
className="dataSourceImage"
|
||||
alt="Datasource"
|
||||
/>
|
||||
|
|
@ -193,6 +175,7 @@ class DatasourceHomeScreen extends React.Component<Props> {
|
|||
|
||||
const mapStateToProps = (state: AppState): ReduxStateProps => {
|
||||
return {
|
||||
pluginImages: getPluginImages(state),
|
||||
plugins: getDatasourcePlugins(state),
|
||||
currentApplication: getCurrentApplication(state),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2,7 +2,12 @@ import React from "react";
|
|||
import { connect } from "react-redux";
|
||||
import { getFormValues, submit } from "redux-form";
|
||||
import { AppState } from "reducers";
|
||||
import { getPluginPackageFromId } from "selectors/entitiesSelector";
|
||||
import _ from "lodash";
|
||||
import {
|
||||
getPluginPackageFromId,
|
||||
getPluginImages,
|
||||
getDatasource,
|
||||
} from "selectors/entitiesSelector";
|
||||
import {
|
||||
updateDatasource,
|
||||
testDatasource,
|
||||
|
|
@ -19,7 +24,6 @@ import { RouteComponentProps } from "react-router";
|
|||
interface ReduxStateProps {
|
||||
formData: Datasource;
|
||||
selectedPluginPackage: string;
|
||||
currentPluginId: string;
|
||||
isSaving: boolean;
|
||||
currentApplication: UserApplication;
|
||||
isTesting: boolean;
|
||||
|
|
@ -27,6 +31,8 @@ interface ReduxStateProps {
|
|||
loadingFormConfigs: boolean;
|
||||
isDeleting: boolean;
|
||||
newDatasource: string;
|
||||
pluginImages: Record<string, string>;
|
||||
pluginId: string;
|
||||
}
|
||||
|
||||
type Props = ReduxStateProps &
|
||||
|
|
@ -60,12 +66,15 @@ class DataSourceEditor extends React.Component<Props> {
|
|||
isDeleting,
|
||||
deleteDatasource,
|
||||
newDatasource,
|
||||
pluginImages,
|
||||
pluginId,
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
{datasourceId ? (
|
||||
<DataSourceEditorForm
|
||||
pluginImage={pluginImages[pluginId]}
|
||||
applicationId={this.props.match.params.applicationId}
|
||||
pageId={this.props.match.params.pageId}
|
||||
isSaving={isSaving}
|
||||
|
|
@ -96,21 +105,23 @@ class DataSourceEditor extends React.Component<Props> {
|
|||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state: AppState): ReduxStateProps => {
|
||||
const mapStateToProps = (state: AppState, props: any): ReduxStateProps => {
|
||||
const { datasourcePane } = state.ui;
|
||||
const { datasources, plugins } = state.entities;
|
||||
const datasource = getDatasource(state, props.match.params.datasourceId);
|
||||
const { formConfigs, loadingFormConfigs } = plugins;
|
||||
const formData = getFormValues(DATASOURCE_DB_FORM)(state) as Datasource;
|
||||
|
||||
return {
|
||||
pluginImages: getPluginImages(state),
|
||||
formData,
|
||||
pluginId: _.get(datasource, "pluginId", ""),
|
||||
selectedPluginPackage: getPluginPackageFromId(
|
||||
state,
|
||||
datasourcePane.selectedPlugin,
|
||||
),
|
||||
isSaving: datasources.loading,
|
||||
isDeleting: datasources.isDeleting,
|
||||
currentPluginId: datasourcePane.selectedPlugin,
|
||||
currentApplication: getCurrentApplication(state),
|
||||
isTesting: datasources.isTesting,
|
||||
formConfig: formConfigs[datasourcePane.selectedPlugin] || [],
|
||||
|
|
|
|||
|
|
@ -10,8 +10,7 @@ import { Colors } from "constants/Colors";
|
|||
import TreeDropdown from "components/editorComponents/actioncreator/TreeDropdown";
|
||||
import { BaseTextInput } from "components/designSystems/appsmith/TextInputComponent";
|
||||
import { getDataSources } from "selectors/editorSelectors";
|
||||
import { getPlugins } from "selectors/entitiesSelector";
|
||||
import { Plugin } from "api/PluginApi";
|
||||
import { getPluginImages } from "selectors/entitiesSelector";
|
||||
import {
|
||||
initDatasourcePane,
|
||||
storeDatastoreRefs,
|
||||
|
|
@ -22,16 +21,7 @@ import { ControlIcons } from "icons/ControlIcons";
|
|||
import { theme } from "constants/DefaultTheme";
|
||||
import { selectPlugin } from "actions/datasourceActions";
|
||||
import { fetchPluginForm } from "actions/pluginActions";
|
||||
import ImageAlt from "assets/images/placeholder-image.svg";
|
||||
import Postgres from "assets/images/Postgress.png";
|
||||
import MongoDB from "assets/images/MongoDB.png";
|
||||
import RestTemplateImage from "assets/images/RestAPI.png";
|
||||
import { DATA_SOURCES_EDITOR_URL } from "constants/routes";
|
||||
import { REST_PLUGIN_PACKAGE_NAME } from "constants/ApiEditorConstants";
|
||||
import {
|
||||
PLUGIN_PACKAGE_POSTGRES,
|
||||
PLUGIN_PACKAGE_MONGO,
|
||||
} from "constants/QueryEditorConstants";
|
||||
import { AppState } from "reducers";
|
||||
import { Datasource } from "api/DatasourcesApi";
|
||||
import Fuse from "fuse.js";
|
||||
|
|
@ -48,7 +38,7 @@ interface ReduxDispatchProps {
|
|||
|
||||
interface ReduxStateProps {
|
||||
dataSources: Datasource[];
|
||||
plugins: Plugin[];
|
||||
pluginImages: Record<string, string>;
|
||||
datastoreRefs: Record<string, any>;
|
||||
formConfigs: Record<string, []>;
|
||||
drafts: Record<string, Datasource>;
|
||||
|
|
@ -253,22 +243,6 @@ class DataSourceSidebar extends React.Component<Props, State> {
|
|||
return search ? fuse.search(search) : dataSources;
|
||||
};
|
||||
|
||||
getImageSource = (pluginId: string) => {
|
||||
const { plugins } = this.props;
|
||||
const plugin = plugins.find(plugin => plugin.id === pluginId);
|
||||
|
||||
switch (plugin?.packageName) {
|
||||
case REST_PLUGIN_PACKAGE_NAME:
|
||||
return RestTemplateImage;
|
||||
case PLUGIN_PACKAGE_MONGO:
|
||||
return MongoDB;
|
||||
case PLUGIN_PACKAGE_POSTGRES:
|
||||
return Postgres;
|
||||
default:
|
||||
return ImageAlt;
|
||||
}
|
||||
};
|
||||
|
||||
renderItem = () => {
|
||||
const {
|
||||
match: {
|
||||
|
|
@ -277,6 +251,7 @@ class DataSourceSidebar extends React.Component<Props, State> {
|
|||
datastoreRefs,
|
||||
deleteDatasource,
|
||||
drafts,
|
||||
pluginImages,
|
||||
} = this.props;
|
||||
|
||||
const filteredList = this.getSearchFilteredList();
|
||||
|
|
@ -292,7 +267,7 @@ class DataSourceSidebar extends React.Component<Props, State> {
|
|||
>
|
||||
<ActionItem>
|
||||
<StyledImage
|
||||
src={this.getImageSource(datasource.pluginId)}
|
||||
src={pluginImages[datasource.pluginId]}
|
||||
className="pluginImage"
|
||||
alt="Plugin Image"
|
||||
/>
|
||||
|
|
@ -365,7 +340,7 @@ const mapStateToProps = (state: AppState): ReduxStateProps => {
|
|||
return {
|
||||
formConfigs: state.entities.plugins.formConfigs,
|
||||
dataSources: getDataSources(state),
|
||||
plugins: getPlugins(state),
|
||||
pluginImages: getPluginImages(state),
|
||||
datastoreRefs: state.ui.datasourcePane.datasourceRefs,
|
||||
drafts,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useEffect, useRef, useState } from "react";
|
||||
import React, { useState } from "react";
|
||||
import { formValueSelector, InjectedFormProps, reduxForm } from "redux-form";
|
||||
import CheckboxField from "components/editorComponents/form/fields/CheckboxField";
|
||||
import styled, { createGlobalStyle } from "styled-components";
|
||||
|
|
@ -10,6 +10,7 @@ import {
|
|||
OptionTypeBase,
|
||||
SingleValueProps,
|
||||
} from "react-select";
|
||||
import _ from "lodash";
|
||||
import history from "utils/history";
|
||||
import { DATA_SOURCES_EDITOR_URL } from "constants/routes";
|
||||
import TemplateMenu from "./TemplateMenu";
|
||||
|
|
@ -19,7 +20,6 @@ import DropdownField from "components/editorComponents/form/fields/DropdownField
|
|||
import { BaseButton } from "components/designSystems/blueprint/ButtonComponent";
|
||||
import { Datasource } from "api/DatasourcesApi";
|
||||
import { QUERY_EDITOR_FORM_NAME } from "constants/forms";
|
||||
import { PLUGIN_PACKAGE_POSTGRES } from "constants/QueryEditorConstants";
|
||||
import { Colors } from "constants/Colors";
|
||||
import JSONViewer from "./JSONViewer";
|
||||
import Table from "./Table";
|
||||
|
|
@ -28,13 +28,23 @@ import { connect } from "react-redux";
|
|||
import { AppState } from "reducers";
|
||||
import ActionNameEditor from "components/editorComponents/ActionNameEditor";
|
||||
import DynamicTextField from "components/editorComponents/form/fields/DynamicTextField";
|
||||
import { EditorModes } from "components/editorComponents/CodeEditor/EditorConfig";
|
||||
import {
|
||||
EditorModes,
|
||||
EditorSize,
|
||||
} from "components/editorComponents/CodeEditor/EditorConfig";
|
||||
import CollapsibleHelp from "components/designSystems/appsmith/help/CollapsibleHelp";
|
||||
import { HelpBaseURL, HelpMap } from "constants/HelpConstants";
|
||||
import {
|
||||
getPluginResponseTypes,
|
||||
getPluginDocumentationLinks,
|
||||
} from "selectors/entitiesSelector";
|
||||
|
||||
const QueryFormContainer = styled.div`
|
||||
font-size: 20px;
|
||||
padding: 20px 32px;
|
||||
width: 100%;
|
||||
max-height: 93vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: calc(100vh - ${props => props.theme.headerHeight});
|
||||
a {
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
|
|
@ -45,7 +55,7 @@ const QueryFormContainer = styled.div`
|
|||
border-radius: 4px;
|
||||
border: 1px solid #d0d7dd;
|
||||
font-size: 14px;
|
||||
height: calc(100vh / 3);
|
||||
height: calc(100vh / 4);
|
||||
}
|
||||
.statementTextArea {
|
||||
font-size: 14px;
|
||||
|
|
@ -82,17 +92,6 @@ const ActionButton = styled(BaseButton)`
|
|||
}
|
||||
`;
|
||||
|
||||
const ResponseContainer = styled.div`
|
||||
margin-top: 20px;
|
||||
`;
|
||||
|
||||
const ResponseContent = styled.div`
|
||||
height: calc(
|
||||
100vh - (100vh / 3) - 175px - ${props => props.theme.headerHeight}
|
||||
);
|
||||
overflow: auto;
|
||||
`;
|
||||
|
||||
const DropdownSelect = styled.div`
|
||||
font-size: 14px;
|
||||
`;
|
||||
|
|
@ -194,6 +193,27 @@ const StyledCheckbox = styled(CheckboxField)`
|
|||
}
|
||||
`;
|
||||
|
||||
const StyledOpenDocsIcon = styled(Icon)`
|
||||
svg {
|
||||
width: 12px;
|
||||
height: 18px;
|
||||
}
|
||||
`;
|
||||
|
||||
const NameWrapper = styled.div`
|
||||
width: 39%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
input {
|
||||
margin: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
`;
|
||||
|
||||
const CollapsibleWrapper = styled.div`
|
||||
width: 200px;
|
||||
`;
|
||||
|
||||
type QueryFormProps = {
|
||||
onDeleteClick: () => void;
|
||||
onRunClick: () => void;
|
||||
|
|
@ -203,10 +223,9 @@ type QueryFormProps = {
|
|||
dataSources: Datasource[];
|
||||
DATASOURCES_OPTIONS: any;
|
||||
executedQueryData: {
|
||||
body: Record<string, any>[];
|
||||
body: Record<string, any>[] | string;
|
||||
};
|
||||
applicationId: string;
|
||||
selectedPluginPackage: string | undefined;
|
||||
runErrorMessage: string | undefined;
|
||||
pageId: string;
|
||||
location: {
|
||||
|
|
@ -216,6 +235,9 @@ type QueryFormProps = {
|
|||
|
||||
type ReduxProps = {
|
||||
actionName: string;
|
||||
responseType: string | undefined;
|
||||
pluginId: string;
|
||||
documentationLink: string | undefined;
|
||||
};
|
||||
|
||||
export type StateAndRouteProps = QueryFormProps & ReduxProps;
|
||||
|
|
@ -235,32 +257,28 @@ const QueryEditorForm: React.FC<Props> = (props: Props) => {
|
|||
applicationId,
|
||||
dataSources,
|
||||
executedQueryData,
|
||||
selectedPluginPackage,
|
||||
createTemplate,
|
||||
runErrorMessage,
|
||||
pluginId,
|
||||
responseType,
|
||||
documentationLink,
|
||||
} = props;
|
||||
|
||||
const [showTemplateMenu, setMenuVisibility] = useState(true);
|
||||
|
||||
const isSQL = selectedPluginPackage === PLUGIN_PACKAGE_POSTGRES;
|
||||
const isNewQuery =
|
||||
new URLSearchParams(window.location.search).get("new") === "true";
|
||||
let queryOutput: {
|
||||
body: Record<string, any>[];
|
||||
} = { body: [] };
|
||||
const inputEl = useRef<HTMLInputElement>();
|
||||
let error = runErrorMessage;
|
||||
let output: Record<string, any>[] | null = null;
|
||||
|
||||
if (executedQueryData) {
|
||||
if (isSQL && executedQueryData.body.length) {
|
||||
queryOutput = executedQueryData;
|
||||
if (_.isString(executedQueryData.body)) {
|
||||
error = executedQueryData.body;
|
||||
} else {
|
||||
output = executedQueryData.body;
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (isNewQuery) {
|
||||
inputEl.current?.select();
|
||||
}
|
||||
}, [isNewQuery]);
|
||||
const isSQL = responseType === "TABLE";
|
||||
const isNewQuery =
|
||||
new URLSearchParams(window.location.search).get("new") === "true";
|
||||
|
||||
const MenuList = (props: MenuListComponentProps<{ children: Node }>) => {
|
||||
return (
|
||||
|
|
@ -316,7 +334,9 @@ const QueryEditorForm: React.FC<Props> = (props: Props) => {
|
|||
<QueryFormContainer>
|
||||
<form onSubmit={handleSubmit}>
|
||||
<FormRow>
|
||||
<ActionNameEditor />
|
||||
<NameWrapper>
|
||||
<ActionNameEditor />
|
||||
</NameWrapper>
|
||||
<DropdownSelect>
|
||||
<DropdownField
|
||||
placeholder="Datasource"
|
||||
|
|
@ -350,8 +370,10 @@ const QueryEditorForm: React.FC<Props> = (props: Props) => {
|
|||
<ActionButton
|
||||
className="t--run-query"
|
||||
text="Run"
|
||||
accent="primary"
|
||||
filled
|
||||
loading={isRunning}
|
||||
accent="primary"
|
||||
onClick={onRunClick}
|
||||
/>
|
||||
<div>
|
||||
<p className="popuptext">
|
||||
|
|
@ -376,55 +398,68 @@ const QueryEditorForm: React.FC<Props> = (props: Props) => {
|
|||
<ActionButton
|
||||
className="t--run-query"
|
||||
text="Run"
|
||||
filled
|
||||
loading={isRunning}
|
||||
accent="secondary"
|
||||
accent="primary"
|
||||
onClick={onRunClick}
|
||||
/>
|
||||
)}
|
||||
</ActionButtons>
|
||||
</FormRow>
|
||||
<div style={{ display: "flex", justifyContent: "space-between" }}>
|
||||
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "flex-end",
|
||||
}}
|
||||
>
|
||||
<p className="statementTextArea">Query Statement</p>
|
||||
{isSQL ? (
|
||||
<a
|
||||
href="https://www.postgresql.org/docs/12/index.html"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
PostgreSQL docs
|
||||
</a>
|
||||
) : (
|
||||
<a
|
||||
href="https://docs.mongodb.com/manual/reference/command/nav-crud/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Mongo docs
|
||||
</a>
|
||||
|
||||
{documentationLink && (
|
||||
<CollapsibleWrapper>
|
||||
<CollapsibleHelp>
|
||||
<a
|
||||
href={documentationLink}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{"Documentation "}
|
||||
<StyledOpenDocsIcon icon="document-open" />
|
||||
</a>
|
||||
</CollapsibleHelp>
|
||||
</CollapsibleWrapper>
|
||||
)}
|
||||
</div>
|
||||
{isNewQuery && showTemplateMenu && selectedPluginPackage ? (
|
||||
|
||||
{isNewQuery && showTemplateMenu && pluginId ? (
|
||||
<TemplateMenu
|
||||
createTemplate={templateString => {
|
||||
setMenuVisibility(false);
|
||||
createTemplate(templateString);
|
||||
}}
|
||||
selectedPluginPackage={selectedPluginPackage}
|
||||
pluginId={pluginId}
|
||||
/>
|
||||
) : isSQL ? (
|
||||
<DynamicTextField
|
||||
name="actionConfiguration.body"
|
||||
dataTreePath={`${props.actionName}.config.body`}
|
||||
className="textAreaStyles"
|
||||
mode={EditorModes.SQL_WITH_BINDING}
|
||||
/>
|
||||
<div>
|
||||
<DynamicTextField
|
||||
size={EditorSize.EXTENDED}
|
||||
name="actionConfiguration.body"
|
||||
dataTreePath={`${props.actionName}.config.body`}
|
||||
className="textAreaStyles"
|
||||
mode={EditorModes.SQL_WITH_BINDING}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<DynamicTextField
|
||||
name="actionConfiguration.body"
|
||||
dataTreePath={`${props.actionName}.config.body`}
|
||||
className="textAreaStyles"
|
||||
mode={EditorModes.JSON_WITH_BINDING}
|
||||
/>
|
||||
<div>
|
||||
<DynamicTextField
|
||||
size={EditorSize.EXTENDED}
|
||||
name="actionConfiguration.body"
|
||||
dataTreePath={`${props.actionName}.config.body`}
|
||||
className="textAreaStyles"
|
||||
mode={EditorModes.JSON_WITH_BINDING}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<StyledCheckbox
|
||||
intent="primary"
|
||||
|
|
@ -452,29 +487,20 @@ const QueryEditorForm: React.FC<Props> = (props: Props) => {
|
|||
</NoDataSourceContainer>
|
||||
)}
|
||||
|
||||
{runErrorMessage && (
|
||||
{error && (
|
||||
<>
|
||||
<p className="statementTextArea">Query error</p>
|
||||
<ErrorMessage>{runErrorMessage}</ErrorMessage>
|
||||
<ErrorMessage>{error}</ErrorMessage>
|
||||
</>
|
||||
)}
|
||||
|
||||
{executedQueryData && dataSources.length && (
|
||||
<ResponseContainer>
|
||||
{!error && output && dataSources.length && (
|
||||
<>
|
||||
<p className="statementTextArea">
|
||||
{executedQueryData.body.length
|
||||
? "Query response"
|
||||
: "No data records to display"}
|
||||
{output.length ? "Query response" : "No data records to display"}
|
||||
</p>
|
||||
|
||||
{isSQL ? (
|
||||
<Table data={queryOutput.body} />
|
||||
) : (
|
||||
<ResponseContent>
|
||||
<JSONViewer src={executedQueryData.body} />
|
||||
</ResponseContent>
|
||||
)}
|
||||
</ResponseContainer>
|
||||
{isSQL ? <Table data={output} /> : <JSONViewer src={output} />}
|
||||
</>
|
||||
)}
|
||||
</QueryFormContainer>
|
||||
);
|
||||
|
|
@ -483,8 +509,15 @@ const QueryEditorForm: React.FC<Props> = (props: Props) => {
|
|||
const valueSelector = formValueSelector(QUERY_EDITOR_FORM_NAME);
|
||||
const mapStateToProps = (state: AppState) => {
|
||||
const actionName = valueSelector(state, "name");
|
||||
const pluginId = valueSelector(state, "datasource.pluginId");
|
||||
const responseTypes = getPluginResponseTypes(state);
|
||||
const documentationLinks = getPluginDocumentationLinks(state);
|
||||
|
||||
return {
|
||||
actionName,
|
||||
pluginId,
|
||||
responseType: responseTypes[pluginId],
|
||||
documentationLink: documentationLinks[pluginId],
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,10 @@ const OutputContainer = styled.div`
|
|||
padding: 6px;
|
||||
`;
|
||||
|
||||
const ResponseContent = styled.div`
|
||||
overflow: auto;
|
||||
`;
|
||||
|
||||
const Record = styled(Card)`
|
||||
margin: 5px;
|
||||
`;
|
||||
|
|
@ -41,24 +45,28 @@ class JSONOutput extends React.Component<Props> {
|
|||
|
||||
if (!src.length) {
|
||||
return (
|
||||
<OutputContainer>
|
||||
<Record>
|
||||
<ReactJson src={src} {...reactJsonProps} />
|
||||
</Record>
|
||||
</OutputContainer>
|
||||
<ResponseContent>
|
||||
<OutputContainer>
|
||||
<Record>
|
||||
<ReactJson src={src} {...reactJsonProps} />
|
||||
</Record>
|
||||
</OutputContainer>
|
||||
</ResponseContent>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<OutputContainer>
|
||||
{src.map((record, index) => {
|
||||
return (
|
||||
<Record key={index}>
|
||||
<ReactJson src={record} {...reactJsonProps} />
|
||||
</Record>
|
||||
);
|
||||
})}
|
||||
</OutputContainer>
|
||||
<ResponseContent>
|
||||
<OutputContainer>
|
||||
{src.map((record, index) => {
|
||||
return (
|
||||
<Record key={index}>
|
||||
<ReactJson src={record} {...reactJsonProps} />
|
||||
</Record>
|
||||
);
|
||||
})}
|
||||
</OutputContainer>
|
||||
</ResponseContent>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,24 +3,16 @@ import styled from "styled-components";
|
|||
import { Icon, Card, Spinner } from "@blueprintjs/core";
|
||||
import { connect } from "react-redux";
|
||||
import { AppState } from "reducers";
|
||||
import ImageAlt from "assets/images/placeholder-image.svg";
|
||||
import Postgres from "assets/images/Postgress.png";
|
||||
import MongoDB from "assets/images/MongoDB.png";
|
||||
import { createNewQueryName } from "utils/AppsmithUtils";
|
||||
import { Plugin } from "api/PluginApi";
|
||||
import {
|
||||
getPlugins,
|
||||
getPluginIdsOfPackageNames,
|
||||
getPluginImages,
|
||||
} from "selectors/entitiesSelector";
|
||||
import { ActionDataState } from "reducers/entityReducers/actionsReducer";
|
||||
import { Datasource } from "api/DatasourcesApi";
|
||||
import history from "utils/history";
|
||||
import { createActionRequest } from "actions/actionActions";
|
||||
import {
|
||||
PLUGIN_PACKAGE_MONGO,
|
||||
PLUGIN_PACKAGE_POSTGRES,
|
||||
PLUGIN_PACKAGE_DBS,
|
||||
} from "constants/QueryEditorConstants";
|
||||
import { PLUGIN_PACKAGE_DBS } from "constants/QueryEditorConstants";
|
||||
import { Page } from "constants/ReduxActionConstants";
|
||||
import {
|
||||
QUERY_EDITOR_URL_WITH_SELECTED_PAGE_ID,
|
||||
|
|
@ -131,8 +123,8 @@ type QueryHomeScreenProps = {
|
|||
replace: (data: string) => void;
|
||||
push: (data: string) => void;
|
||||
};
|
||||
plugins: Plugin[];
|
||||
pages: Page[];
|
||||
pluginImages: Record<string, string>;
|
||||
};
|
||||
|
||||
class QueryHomeScreen extends React.Component<QueryHomeScreenProps> {
|
||||
|
|
@ -161,23 +153,6 @@ class QueryHomeScreen extends React.Component<QueryHomeScreenProps> {
|
|||
}
|
||||
};
|
||||
|
||||
getImageSrc = (dataSource: Datasource) => {
|
||||
const { plugins } = this.props;
|
||||
const { pluginId } = dataSource;
|
||||
const plugin = plugins.find(
|
||||
(plugin: { id: string }) => plugin.id === pluginId,
|
||||
);
|
||||
|
||||
switch (plugin?.packageName) {
|
||||
case PLUGIN_PACKAGE_MONGO:
|
||||
return MongoDB;
|
||||
case PLUGIN_PACKAGE_POSTGRES:
|
||||
return Postgres;
|
||||
default:
|
||||
return ImageAlt;
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
dataSources,
|
||||
|
|
@ -187,15 +162,9 @@ class QueryHomeScreen extends React.Component<QueryHomeScreenProps> {
|
|||
history,
|
||||
location,
|
||||
isCreating,
|
||||
pluginImages,
|
||||
} = this.props;
|
||||
|
||||
const validDataSources: Array<Datasource> = [];
|
||||
dataSources.forEach(dataSource => {
|
||||
if (pluginIds?.includes(dataSource.pluginId)) {
|
||||
validDataSources.push(dataSource);
|
||||
}
|
||||
});
|
||||
|
||||
const queryParams: string = location.search;
|
||||
const destinationPageId = new URLSearchParams(location.search).get(
|
||||
"importTo",
|
||||
|
|
@ -224,11 +193,8 @@ class QueryHomeScreen extends React.Component<QueryHomeScreenProps> {
|
|||
interactive={false}
|
||||
className="eachDatasourceCard"
|
||||
onClick={() => {
|
||||
if (validDataSources.length) {
|
||||
this.handleCreateNewQuery(
|
||||
validDataSources[0].id,
|
||||
queryParams,
|
||||
);
|
||||
if (dataSources.length) {
|
||||
this.handleCreateNewQuery(dataSources[0].id, queryParams);
|
||||
} else {
|
||||
history.push(DATA_SOURCES_EDITOR_URL(applicationId, pageId));
|
||||
}
|
||||
|
|
@ -237,7 +203,7 @@ class QueryHomeScreen extends React.Component<QueryHomeScreenProps> {
|
|||
<Icon icon="plus" iconSize={25} className="addIcon" />
|
||||
<p className="createText">Blank Query</p>
|
||||
</Card>
|
||||
{validDataSources.map(dataSource => {
|
||||
{dataSources.map(dataSource => {
|
||||
return (
|
||||
<Card
|
||||
interactive={false}
|
||||
|
|
@ -248,7 +214,7 @@ class QueryHomeScreen extends React.Component<QueryHomeScreenProps> {
|
|||
}
|
||||
>
|
||||
<img
|
||||
src={this.getImageSrc(dataSource)}
|
||||
src={pluginImages[dataSource.pluginId]}
|
||||
className="dataSourceImage"
|
||||
alt="Datasource"
|
||||
/>
|
||||
|
|
@ -271,7 +237,7 @@ class QueryHomeScreen extends React.Component<QueryHomeScreenProps> {
|
|||
|
||||
const mapStateToProps = (state: AppState) => ({
|
||||
pluginIds: getPluginIdsOfPackageNames(state, PLUGIN_PACKAGE_DBS),
|
||||
plugins: getPlugins(state),
|
||||
pluginImages: getPluginImages(state),
|
||||
actions: state.entities.actions,
|
||||
pages: state.entities.pageList.pages,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
import React from "react";
|
||||
import { TableWrapper } from "components/designSystems/appsmith/TableStyledWrappers";
|
||||
import {
|
||||
TableWrapper,
|
||||
CellWrapper,
|
||||
} from "components/designSystems/appsmith/TableStyledWrappers";
|
||||
import { useTable, useFlexLayout } from "react-table";
|
||||
import styled from "styled-components";
|
||||
|
||||
|
|
@ -7,6 +10,10 @@ interface TableProps {
|
|||
data: Record<string, any>[];
|
||||
}
|
||||
|
||||
/*
|
||||
* 310 = height of the table header + rest of the items (excluding editor height)
|
||||
* 100vh /4 = height of the editor
|
||||
*/
|
||||
const StyledTableWrapped = styled(TableWrapper)`
|
||||
width: 100%;
|
||||
height: auto;
|
||||
|
|
@ -16,7 +23,7 @@ const StyledTableWrapped = styled(TableWrapper)`
|
|||
overflow: auto;
|
||||
height: auto;
|
||||
max-height: calc(
|
||||
100vh - (100vh / 3) - 230px - ${props => props.theme.headerHeight}
|
||||
100vh - (100vh / 4) - 310px - ${props => props.theme.headerHeight}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -94,7 +101,9 @@ const Table = (props: TableProps) => {
|
|||
data-rowindex={index}
|
||||
data-colindex={cellIndex}
|
||||
>
|
||||
{cell.render("Cell")}
|
||||
<CellWrapper isHidden={false}>
|
||||
{cell.render("Cell")}
|
||||
</CellWrapper>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
import React from "react";
|
||||
import styled from "styled-components";
|
||||
import Templates from "./Templates";
|
||||
import { connect } from "react-redux";
|
||||
import { AppState } from "reducers";
|
||||
import { getPluginTemplates } from "selectors/entitiesSelector";
|
||||
|
||||
const Container = styled.div`
|
||||
display: flex;
|
||||
|
|
@ -42,10 +44,14 @@ const Row = styled.div`
|
|||
|
||||
interface TemplateMenuProps {
|
||||
createTemplate: (template: any) => void;
|
||||
selectedPluginPackage: string;
|
||||
pluginId: string;
|
||||
}
|
||||
|
||||
type Props = TemplateMenuProps;
|
||||
type ReduxProps = {
|
||||
allPluginTemplates: Record<string, any>;
|
||||
};
|
||||
|
||||
type Props = TemplateMenuProps & ReduxProps;
|
||||
|
||||
class TemplateMenu extends React.Component<Props> {
|
||||
nameInput!: HTMLDivElement | null;
|
||||
|
|
@ -54,17 +60,18 @@ class TemplateMenu extends React.Component<Props> {
|
|||
this.nameInput?.focus();
|
||||
}
|
||||
|
||||
fetchTemplate = (queryType: React.ReactText) => {
|
||||
const { selectedPluginPackage } = this.props;
|
||||
const allTemplates = Templates[selectedPluginPackage];
|
||||
fetchTemplate = (queryType: string) => {
|
||||
const { pluginId, allPluginTemplates } = this.props;
|
||||
const pluginTemplates = allPluginTemplates[pluginId];
|
||||
|
||||
if (allTemplates) {
|
||||
return allTemplates[queryType];
|
||||
if (pluginTemplates) {
|
||||
return pluginTemplates[queryType];
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const { createTemplate } = this.props;
|
||||
const { createTemplate, allPluginTemplates, pluginId } = this.props;
|
||||
const pluginTemplates = allPluginTemplates[pluginId];
|
||||
|
||||
return (
|
||||
<Container
|
||||
|
|
@ -86,50 +93,36 @@ class TemplateMenu extends React.Component<Props> {
|
|||
Press enter to start with a blank state or select a template.
|
||||
</div>
|
||||
<div style={{ marginTop: "6px" }}>
|
||||
<Row
|
||||
onClick={e => {
|
||||
const template = this.fetchTemplate("create");
|
||||
createTemplate(template);
|
||||
e.stopPropagation();
|
||||
}}
|
||||
>
|
||||
<BulletPoint />
|
||||
<Item>Create</Item>
|
||||
</Row>
|
||||
<Row
|
||||
onClick={e => {
|
||||
const template = this.fetchTemplate("read");
|
||||
createTemplate(template);
|
||||
e.stopPropagation();
|
||||
}}
|
||||
>
|
||||
<BulletPoint />
|
||||
<Item>Read</Item>
|
||||
</Row>
|
||||
<Row
|
||||
onClick={e => {
|
||||
const template = this.fetchTemplate("delete");
|
||||
createTemplate(template);
|
||||
e.stopPropagation();
|
||||
}}
|
||||
>
|
||||
<BulletPoint />
|
||||
<Item>Delete</Item>
|
||||
</Row>
|
||||
<Row
|
||||
onClick={e => {
|
||||
const template = this.fetchTemplate("update");
|
||||
createTemplate(template);
|
||||
e.stopPropagation();
|
||||
}}
|
||||
>
|
||||
<BulletPoint />
|
||||
<Item>Update</Item>
|
||||
</Row>
|
||||
{Object.entries(pluginTemplates).map(template => {
|
||||
const templateKey = template[0];
|
||||
|
||||
return (
|
||||
<Row
|
||||
key={templateKey}
|
||||
onClick={e => {
|
||||
const template = this.fetchTemplate(templateKey);
|
||||
createTemplate(template);
|
||||
e.stopPropagation();
|
||||
}}
|
||||
>
|
||||
<BulletPoint />
|
||||
<Item>
|
||||
{templateKey.charAt(0).toUpperCase() +
|
||||
templateKey.slice(1).toLowerCase()}
|
||||
</Item>
|
||||
</Row>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default TemplateMenu;
|
||||
const mapStateToProps = (state: AppState) => {
|
||||
return {
|
||||
allPluginTemplates: getPluginTemplates(state),
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps)(TemplateMenu);
|
||||
|
|
|
|||
|
|
@ -1,53 +0,0 @@
|
|||
import {
|
||||
PLUGIN_PACKAGE_MONGO,
|
||||
PLUGIN_PACKAGE_POSTGRES,
|
||||
} from "constants/QueryEditorConstants";
|
||||
|
||||
const Templates: Record<string, any> = {
|
||||
[PLUGIN_PACKAGE_MONGO]: {
|
||||
create: {
|
||||
insert: "users",
|
||||
documents: [
|
||||
{
|
||||
name: "{{Input1.text}}",
|
||||
email: "{{Input2.text}}",
|
||||
gender: "{{Dropdown2.selectedOptionValue}}",
|
||||
},
|
||||
],
|
||||
},
|
||||
read: {
|
||||
find: "users",
|
||||
filter: { id: { $gte: "{{Input1.text}}" } },
|
||||
sort: { id: 1 },
|
||||
limit: 10,
|
||||
},
|
||||
delete: {
|
||||
delete: "users",
|
||||
deletes: [{ q: { id: "{{Table1.selectedRow.id}}" } }],
|
||||
},
|
||||
update: {
|
||||
update: "users",
|
||||
updates: [
|
||||
{
|
||||
q: { id: "{{Table1.selectedRow.id}}" },
|
||||
u: {
|
||||
name: "{{Input1.text}}",
|
||||
email: "{{Input2.text}}",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
[PLUGIN_PACKAGE_POSTGRES]: {
|
||||
create: `INSERT INTO users(name, gender)
|
||||
VALUES ('{{Dropdown1.selectedOptionValue}}', '{{Input2.text}}');`,
|
||||
read:
|
||||
"SELECT * FROM users where name like '%{{Input1.text}}%' ORDER BY id LIMIT 10",
|
||||
delete: `DELETE FROM users WHERE id={{Table1.selectedRow.id}}`,
|
||||
update: `UPDATE users
|
||||
Set status='{{Dropdown1.selectedOptionValue}}'
|
||||
WHERE id={{Table1.selectedRow.id}};`,
|
||||
},
|
||||
};
|
||||
|
||||
export default Templates;
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
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;
|
||||
}
|
||||
};
|
||||
|
|
@ -2,7 +2,6 @@ import React from "react";
|
|||
import { RouteComponentProps } from "react-router";
|
||||
import { connect } from "react-redux";
|
||||
import { getFormValues, change } from "redux-form";
|
||||
import _ from "lodash";
|
||||
import styled from "styled-components";
|
||||
import { QueryEditorRouteParams } from "constants/routes";
|
||||
import QueryEditorForm from "./Form";
|
||||
|
|
@ -16,15 +15,15 @@ import { Datasource } from "api/DatasourcesApi";
|
|||
import { QueryPaneReduxState } from "reducers/uiReducers/queryPaneReducer";
|
||||
import {
|
||||
getPluginIdsOfPackageNames,
|
||||
getPluginPackageFromDatasourceId,
|
||||
getPlugins,
|
||||
getPluginImages,
|
||||
getDBDatasources,
|
||||
} from "selectors/entitiesSelector";
|
||||
import {
|
||||
PLUGIN_PACKAGE_DBS,
|
||||
QUERY_BODY_FIELD,
|
||||
} from "constants/QueryEditorConstants";
|
||||
import { QueryAction } from "entities/Action";
|
||||
import { getPluginImage } from "pages/Editor/QueryEditor/helpers";
|
||||
import Spinner from "components/editorComponents/Spinner";
|
||||
import CenteredWrapper from "components/designSystems/appsmith/CenteredWrapper";
|
||||
|
||||
|
|
@ -52,10 +51,10 @@ type ReduxStateProps = {
|
|||
runErrorMessage: Record<string, string>;
|
||||
pluginIds: Array<string> | undefined;
|
||||
executedQueryData: any;
|
||||
selectedPluginPackage: string | undefined;
|
||||
isCreating: boolean;
|
||||
isMoving: boolean;
|
||||
isCopying: boolean;
|
||||
pluginImages: Record<string, string>;
|
||||
};
|
||||
|
||||
type StateAndRouteProps = RouteComponentProps<QueryEditorRouteParams>;
|
||||
|
|
@ -82,9 +81,9 @@ class QueryEditor extends React.Component<Props> {
|
|||
match: {
|
||||
params: { queryId },
|
||||
},
|
||||
pluginImages,
|
||||
pluginIds,
|
||||
executedQueryData,
|
||||
selectedPluginPackage,
|
||||
isCreating,
|
||||
isMoving,
|
||||
isCopying,
|
||||
|
|
@ -107,17 +106,10 @@ class QueryEditor extends React.Component<Props> {
|
|||
}
|
||||
const { isRunning, isDeleting } = queryPane;
|
||||
|
||||
const validDataSources: Array<Datasource> = [];
|
||||
dataSources.forEach(dataSource => {
|
||||
if (pluginIds?.includes(dataSource.pluginId)) {
|
||||
validDataSources.push(dataSource);
|
||||
}
|
||||
});
|
||||
|
||||
const DATASOURCES_OPTIONS = validDataSources.map(dataSource => ({
|
||||
const DATASOURCES_OPTIONS = dataSources.map(dataSource => ({
|
||||
label: dataSource.name,
|
||||
value: dataSource.id,
|
||||
image: getPluginImage(this.props.plugins, dataSource.pluginId),
|
||||
image: pluginImages[dataSource.pluginId],
|
||||
}));
|
||||
|
||||
return (
|
||||
|
|
@ -134,7 +126,6 @@ class QueryEditor extends React.Component<Props> {
|
|||
dataSources={dataSources}
|
||||
createTemplate={createTemplate}
|
||||
DATASOURCES_OPTIONS={DATASOURCES_OPTIONS}
|
||||
selectedPluginPackage={selectedPluginPackage}
|
||||
executedQueryData={executedQueryData[queryId]}
|
||||
runErrorMessage={runErrorMessage[queryId]}
|
||||
/>
|
||||
|
|
@ -156,21 +147,16 @@ class QueryEditor extends React.Component<Props> {
|
|||
const mapStateToProps = (state: AppState): ReduxStateProps => {
|
||||
const { runErrorMessage } = state.ui.queryPane;
|
||||
const formData = getFormValues(QUERY_EDITOR_FORM_NAME)(state) as QueryAction;
|
||||
const datasourceId = _.get(formData, "datasource.id");
|
||||
const selectedPluginPackage = getPluginPackageFromDatasourceId(
|
||||
state,
|
||||
datasourceId,
|
||||
);
|
||||
|
||||
return {
|
||||
pluginImages: getPluginImages(state),
|
||||
plugins: getPlugins(state),
|
||||
runErrorMessage,
|
||||
pluginIds: getPluginIdsOfPackageNames(state, PLUGIN_PACKAGE_DBS),
|
||||
dataSources: getDataSources(state),
|
||||
dataSources: getDBDatasources(state),
|
||||
executedQueryData: state.ui.queryPane.runQuerySuccessData,
|
||||
queryPane: state.ui.queryPane,
|
||||
formData,
|
||||
selectedPluginPackage,
|
||||
isCreating: state.ui.apiPane.isCreating,
|
||||
isMoving: state.ui.apiPane.isMoving,
|
||||
isCopying: state.ui.apiPane.isCopying,
|
||||
|
|
|
|||
|
|
@ -9,8 +9,6 @@ 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,
|
||||
|
|
@ -18,7 +16,7 @@ import {
|
|||
deleteAction,
|
||||
} from "actions/actionActions";
|
||||
import { changeQuery, initQueryPane } from "actions/queryPaneActions";
|
||||
import { getQueryActions, getPlugins } from "selectors/entitiesSelector";
|
||||
import { getQueryActions, getPluginImages } from "selectors/entitiesSelector";
|
||||
import { getNextEntityName } from "utils/AppsmithUtils";
|
||||
import { getDataSources } from "selectors/editorSelectors";
|
||||
import { QUERY_EDITOR_URL_WITH_SELECTED_PAGE_ID } from "constants/routes";
|
||||
|
|
@ -53,7 +51,7 @@ const StyledImage = styled.img`
|
|||
`;
|
||||
|
||||
interface ReduxStateProps {
|
||||
plugins: Plugin[];
|
||||
pluginImages: Record<string, string>;
|
||||
queries: ActionDataState;
|
||||
apiPane: ApiPaneReduxState;
|
||||
actions: ActionDataState;
|
||||
|
|
@ -128,10 +126,12 @@ class QuerySidebar extends React.Component<Props> {
|
|||
};
|
||||
|
||||
renderItem = (query: RestAction) => {
|
||||
const { pluginImages } = this.props;
|
||||
|
||||
return (
|
||||
<ActionItem>
|
||||
<StyledImage
|
||||
src={getPluginImage(this.props.plugins, query.datasource.pluginId)}
|
||||
src={pluginImages[query.datasource?.pluginId ?? ""]}
|
||||
className="pluginImage"
|
||||
alt="Plugin Image"
|
||||
/>
|
||||
|
|
@ -168,7 +168,7 @@ class QuerySidebar extends React.Component<Props> {
|
|||
}
|
||||
|
||||
const mapStateToProps = (state: AppState): ReduxStateProps => ({
|
||||
plugins: getPlugins(state),
|
||||
pluginImages: getPluginImages(state),
|
||||
queries: getQueryActions(state),
|
||||
apiPane: state.ui.apiPane,
|
||||
actions: state.entities.actions,
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ import {
|
|||
} from "selectors/editorSelectors";
|
||||
import { initialize } from "redux-form";
|
||||
import { AppState } from "reducers";
|
||||
import { QUERY_CONSTANT } from "constants/QueryEditorConstants";
|
||||
import { changeQuery } from "actions/queryPaneActions";
|
||||
import { getAction } from "selectors/entitiesSelector";
|
||||
import { RestAction } from "entities/Action";
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import { createSelector } from "reselect";
|
|||
import { Datasource } from "api/DatasourcesApi";
|
||||
import { Action } from "entities/Action";
|
||||
import { find } from "lodash";
|
||||
import ImageAlt from "assets/images/placeholder-image.svg";
|
||||
|
||||
export const getEntities = (state: AppState): AppState["entities"] =>
|
||||
state.entities;
|
||||
|
|
@ -124,6 +125,23 @@ export const getDatasourceDraft = (state: AppState, id: string) => {
|
|||
|
||||
export const getPlugins = (state: AppState) => state.entities.plugins.list;
|
||||
|
||||
export const getDBPlugins = createSelector(getPlugins, plugins =>
|
||||
plugins.filter(plugin => plugin.type === QUERY_CONSTANT),
|
||||
);
|
||||
|
||||
export const getDBDatasources = createSelector(
|
||||
getDBPlugins,
|
||||
getEntities,
|
||||
(dbPlugins, entities) => {
|
||||
const datasources = entities.datasources.list;
|
||||
const dbPluginIds = dbPlugins.map(plugin => plugin.id);
|
||||
|
||||
return datasources.filter(datasource =>
|
||||
dbPluginIds.includes(datasource.pluginId),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
export const getQueryName = (state: AppState, actionId: string): string => {
|
||||
const action = state.entities.actions.find((action: ActionData) => {
|
||||
return action.config.id === actionId;
|
||||
|
|
@ -137,6 +155,7 @@ export const getQueryActions = (state: AppState): ActionDataState => {
|
|||
return action.config.pluginType === QUERY_CONSTANT;
|
||||
});
|
||||
};
|
||||
|
||||
const getCurrentPageId = (state: AppState) =>
|
||||
state.entities.pageList.currentPageId;
|
||||
|
||||
|
|
@ -144,6 +163,49 @@ export const getDatasourcePlugins = createSelector(getPlugins, plugins => {
|
|||
return plugins.filter(plugin => plugin?.allowUserDatasources ?? true);
|
||||
});
|
||||
|
||||
export const getPluginImages = createSelector(getPlugins, plugins => {
|
||||
const pluginImages: Record<string, string> = {};
|
||||
|
||||
plugins.forEach(plugin => {
|
||||
pluginImages[plugin.id] = plugin?.iconLocation ?? ImageAlt;
|
||||
});
|
||||
|
||||
return pluginImages;
|
||||
});
|
||||
|
||||
export const getPluginTemplates = createSelector(getPlugins, plugins => {
|
||||
const pluginTemplates: Record<string, any> = {};
|
||||
|
||||
plugins.forEach(plugin => {
|
||||
pluginTemplates[plugin.id] = plugin.templates;
|
||||
});
|
||||
|
||||
return pluginTemplates;
|
||||
});
|
||||
|
||||
export const getPluginResponseTypes = createSelector(getPlugins, plugins => {
|
||||
const pluginResponseTypes: Record<string, any> = {};
|
||||
|
||||
plugins.forEach(plugin => {
|
||||
pluginResponseTypes[plugin.id] = plugin.responseType;
|
||||
});
|
||||
|
||||
return pluginResponseTypes;
|
||||
});
|
||||
|
||||
export const getPluginDocumentationLinks = createSelector(
|
||||
getPlugins,
|
||||
plugins => {
|
||||
const pluginDocumentationLinks: Record<string, string | undefined> = {};
|
||||
|
||||
plugins.forEach(plugin => {
|
||||
pluginDocumentationLinks[plugin.id] = plugin.documentationLink;
|
||||
});
|
||||
|
||||
return pluginDocumentationLinks;
|
||||
},
|
||||
);
|
||||
|
||||
export const getActionsForCurrentPage = createSelector(
|
||||
getCurrentPageId,
|
||||
getActions,
|
||||
|
|
@ -162,6 +224,7 @@ export const getActionResponses = createSelector(getActions, actions => {
|
|||
|
||||
return responses;
|
||||
});
|
||||
|
||||
export const getAction = (
|
||||
state: AppState,
|
||||
actionId: string,
|
||||
|
|
|
|||
58
deploy/aws/base-install.sh
Executable file
|
|
@ -0,0 +1,58 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -o errexit
|
||||
|
||||
if [[ $EUID > 0 ]]; then
|
||||
echo "Please run with sudo." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
install_package() {
|
||||
sudo apt-get -y update --quiet
|
||||
sudo apt-get install -y ntp bc python3-pip --quiet
|
||||
pip3 install boto3
|
||||
sudo apt-get install -y apt-transport-https ca-certificates curl software-properties-common virtualenv python3-setuptools --quiet
|
||||
|
||||
# Installing docker
|
||||
sudo apt-get -y --quiet install gnupg-agent
|
||||
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
|
||||
sudo add-apt-repository \
|
||||
"deb [arch=amd64] https://download.docker.com/linux/ubuntu \
|
||||
$(lsb_release -cs) \
|
||||
stable"
|
||||
|
||||
sudo apt-get -y update --quiet
|
||||
sudo apt-get -y install docker-ce docker-ce-cli containerd.io --quiet
|
||||
|
||||
# Installing docker compose
|
||||
if [ ! -f /usr/bin/docker-compose ];then
|
||||
echo "Installing docker-compose"
|
||||
sudo curl -L "https://github.com/docker/compose/releases/download/1.26.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
|
||||
sudo chmod +x /usr/local/bin/docker-compose
|
||||
sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
install_package
|
||||
|
||||
#Download boot.sh and schedule at boot time.
|
||||
app_path="/home/ubuntu/appsmith"
|
||||
script_path="script"
|
||||
boot_script_path=$app_path/$script_path
|
||||
boot_file_name="boot.sh"
|
||||
config_ssl_file_name="configure-ssl.sh"
|
||||
mkdir -p $boot_script_path
|
||||
sudo chown -R ubuntu:ubuntu $app_path
|
||||
cd $boot_script_path
|
||||
|
||||
sudo curl -O https://raw.githubusercontent.com/appsmithorg/appsmith/release/deploy/configure-ssl.sh
|
||||
sudo chown ubuntu:ubuntu $boot_script_path/$config_ssl_file_name && sudo chmod +x $boot_script_path/$config_ssl_file_name
|
||||
|
||||
sudo curl -O https://raw.githubusercontent.com/appsmithorg/appsmith/feature/deploy-script/deploy/aws/boot.sh
|
||||
sudo chown ubuntu:ubuntu $boot_script_path/$boot_file_name && sudo chmod +x $boot_script_path/$boot_file_name
|
||||
|
||||
USER="ubuntu"
|
||||
CRON_FILE="/var/spool/cron/crontabs/$USER"
|
||||
echo "@reboot /bin/bash $boot_script_path/$boot_file_name" >> $CRON_FILE
|
||||
sudo chmod 0600 $CRON_FILE
|
||||
96
deploy/aws/boot.sh
Executable file
|
|
@ -0,0 +1,96 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -o errexit
|
||||
# Check if Lock File exists, if not create it and set trap on exit
|
||||
if { set -C; 2>/dev/null >/home/ubuntu/.appsmith.lock; }; then
|
||||
trap "rm -f /home/ubuntu/.appsmith.lock" EXIT
|
||||
else
|
||||
exit
|
||||
fi
|
||||
|
||||
start_docker() {
|
||||
if [ `sudo systemctl is-active docker.service` == "inactive" ];then
|
||||
echo "Starting docker"
|
||||
sudo systemctl start docker.service
|
||||
fi
|
||||
}
|
||||
|
||||
# generate random string
|
||||
generate_random_string() {
|
||||
value=`cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 10 | head -n 1`
|
||||
echo $value
|
||||
}
|
||||
|
||||
start_docker
|
||||
|
||||
install_dir="/home/ubuntu/appsmith"
|
||||
|
||||
if [ ! -d $install_dir ];then
|
||||
mkdir -p $install_dir
|
||||
fi
|
||||
chown -R ubuntu:ubuntu $install_dir
|
||||
|
||||
mongo_host="mongo"
|
||||
mongo_database="appsmith"
|
||||
mongo_root_user=$( generate_random_string )
|
||||
mongo_root_password=$( generate_random_string )
|
||||
user_encryption_password=$( generate_random_string )
|
||||
user_encryption_salt=$( generate_random_string )
|
||||
|
||||
custom_domain=""
|
||||
NGINX_SSL_CMNT=""
|
||||
if [[ -z $custom_domain ]]; then
|
||||
NGINX_SSL_CMNT="#"
|
||||
fi
|
||||
|
||||
script_dir="/script"
|
||||
mkdir -p "$install_dir/$script_dir"
|
||||
chown -R ubuntu:ubuntu "$install_dir/$script_dir"
|
||||
|
||||
cd $install_dir/$script_dir
|
||||
mkdir -p template
|
||||
cd template
|
||||
echo $PWD
|
||||
curl -O https://raw.githubusercontent.com/appsmithorg/appsmith/release/deploy/template/docker-compose.yml.sh
|
||||
curl -O https://raw.githubusercontent.com/appsmithorg/appsmith/release/deploy/template/init-letsencrypt.sh.sh
|
||||
curl -O https://raw.githubusercontent.com/appsmithorg/appsmith/release/deploy/template/mongo-init.js.sh
|
||||
curl -O https://raw.githubusercontent.com/appsmithorg/appsmith/release/deploy/template/docker.env.sh
|
||||
curl -O https://raw.githubusercontent.com/appsmithorg/appsmith/release/deploy/template/nginx_app.conf.sh
|
||||
curl -O https://raw.githubusercontent.com/appsmithorg/appsmith/release/deploy/template/encryption.env.sh
|
||||
cd ..
|
||||
echo $PWD
|
||||
|
||||
# Role - Folder
|
||||
for directory_name in nginx certbot mongo/db opa/config
|
||||
do
|
||||
if [[ ! -d "$install_dir/data/$directory_name" ]];then
|
||||
mkdir -p "$install_dir/data/$directory_name"
|
||||
fi
|
||||
done
|
||||
|
||||
echo "Generating the configuration files from the templates"
|
||||
. ./template/nginx_app.conf.sh
|
||||
. ./template/docker-compose.yml.sh
|
||||
. ./template/mongo-init.js.sh
|
||||
. ./template/docker.env.sh
|
||||
. ./template/encryption.env.sh
|
||||
|
||||
declare -A fileInfo
|
||||
|
||||
fileInfo[/data/nginx/app.conf.template]="nginx_app.conf"
|
||||
fileInfo[/docker-compose.yml]="docker-compose.yml"
|
||||
fileInfo[/data/mongo/init.js]="mongo-init.js"
|
||||
fileInfo[/docker.env]="docker.env"
|
||||
fileInfo[/encryption.env]="encryption.env"
|
||||
|
||||
for f in ${!fileInfo[@]}
|
||||
do
|
||||
mv -f ${fileInfo[$f]} $install_dir/$f
|
||||
done
|
||||
|
||||
cd $install_dir
|
||||
echo "Pull Images: $PWD"
|
||||
sudo docker-compose pull
|
||||
|
||||
echo "docker compose $PWD"
|
||||
sudo docker-compose -f docker-compose.yml up -d --remove-orphans
|
||||
19
deploy/aws/configure-ssl.sh
Executable file
|
|
@ -0,0 +1,19 @@
|
|||
#!/bin/bash
|
||||
set -o errexit
|
||||
|
||||
read -p 'Enter your domain / subdomain name (example.com / app.example.com): ' custom_domain
|
||||
|
||||
NGINX_SSL_CMNT=""
|
||||
install_dir="/home/ubuntu/appsmith"
|
||||
TEMPLATE_PATH="$install_dir/script/template"
|
||||
|
||||
. $TEMPLATE_PATH/nginx_app.conf.sh
|
||||
. $TEMPLATE_PATH/init-letsencrypt.sh.sh
|
||||
|
||||
chmod 0755 init-letsencrypt.sh
|
||||
|
||||
mv -f app.conf $install_dir/data/nginx/app.conf
|
||||
mv -f init-letsencrypt.sh $install_dir/init-letsencrypt.sh
|
||||
|
||||
cd $install_dir
|
||||
sudo ./init-letsencrypt.sh
|
||||
|
|
@ -4,7 +4,7 @@ if [ ! -f docker-compose.yml ]; then
|
|||
touch docker-compose.yml
|
||||
fi
|
||||
|
||||
cat > docker-compose.yml << EOF
|
||||
cat >| docker-compose.yml << EOF
|
||||
version: "3.7"
|
||||
|
||||
services:
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ if [ ! -f docker-compose.yml ]; then
|
|||
touch docker-compose.yml
|
||||
fi
|
||||
|
||||
cat > docker.env << EOF
|
||||
cat >| docker.env << EOF
|
||||
# Read our documentation on how to configure these features
|
||||
# https://docs.appsmith.com/v/v1.1/enabling-3p-services
|
||||
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@ if [ ! -f encryption.env ]; then
|
|||
touch encryption.env
|
||||
fi
|
||||
|
||||
cat > encryption.env << EOF
|
||||
cat >| encryption.env << EOF
|
||||
APPSMITH_ENCRYPTION_PASSWORD=$user_encryption_password
|
||||
APPSMITH_ENCRYPTION_SALT=$user_encryption_salt
|
||||
|
||||
EOF
|
||||
EOF
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ fi
|
|||
|
||||
|
||||
|
||||
cat > init-letsencrypt.sh << EOF
|
||||
cat >| init-letsencrypt.sh << EOF
|
||||
#!/bin/bash
|
||||
|
||||
if ! [ -x "\$(command -v docker-compose)" ]; then
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ fi
|
|||
|
||||
|
||||
|
||||
cat > mongo-init.js << EOF
|
||||
cat >| mongo-init.js << EOF
|
||||
let error = false
|
||||
print("**** Going to start Mongo seed ****")
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ if [ ! -f nginx_app.conf ]; then
|
|||
fi
|
||||
|
||||
# This template file is different from the others because of the sub_filter commands in the Nginx configuration
|
||||
# Those variables are substituted inside the Docker container for appsmith-editor during bootup.
|
||||
# Those variables are substituted inside the Docker container for appsmith-editor during bootup.
|
||||
# Hence we wish to prevent environment substitution here.
|
||||
# Relevant variables will be replaced at the end of this file via sed command
|
||||
|
||||
|
|
@ -26,7 +26,7 @@ $NGINX_SSL_CMNT server_name $custom_domain ;
|
|||
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Host $host;
|
||||
|
||||
|
||||
location / {
|
||||
try_files $uri /index.html =404;
|
||||
|
||||
|
|
@ -49,7 +49,7 @@ $NGINX_SSL_CMNT server_name $custom_domain ;
|
|||
location /f {
|
||||
proxy_pass https://cdn.optimizely.com/;
|
||||
}
|
||||
|
||||
|
||||
location /api {
|
||||
proxy_pass http://appsmith-internal-server:8080;
|
||||
}
|
||||
|
|
@ -101,7 +101,7 @@ $NGINX_SSL_CMNT
|
|||
$NGINX_SSL_CMNT location /f {
|
||||
$NGINX_SSL_CMNT proxy_pass https://cdn.optimizely.com/;
|
||||
$NGINX_SSL_CMNT }
|
||||
$NGINX_SSL_CMNT
|
||||
$NGINX_SSL_CMNT
|
||||
$NGINX_SSL_CMNT location /api {
|
||||
$NGINX_SSL_CMNT proxy_pass http://appsmith-internal-server:8080;
|
||||
$NGINX_SSL_CMNT }
|
||||
|
|
@ -115,7 +115,7 @@ $NGINX_SSL_CMNT proxy_pass http://appsmith-internal-server:8080;
|
|||
$NGINX_SSL_CMNT }
|
||||
$NGINX_SSL_CMNT
|
||||
$NGINX_SSL_CMNT }
|
||||
' > nginx_app.conf
|
||||
' >| nginx_app.conf
|
||||
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
sed -i '' "s/\$NGINX_SSL_CMNT/$NGINX_SSL_CMNT/g" nginx_app.conf
|
||||
|
|
@ -123,4 +123,4 @@ if [[ "$OSTYPE" == "darwin"* ]]; then
|
|||
else
|
||||
sed -i "s/\$NGINX_SSL_CMNT/$NGINX_SSL_CMNT/g" nginx_app.conf
|
||||
sed -i "s/\$custom_domain/$custom_domain/g" nginx_app.conf
|
||||
fi
|
||||
fi
|
||||
|
|
|
|||