merge conflicts resolved
This commit is contained in:
commit
3bf86936b1
|
|
@ -14,6 +14,7 @@ describe("Test Create Api and Bind to Table widget", function() {
|
|||
cy.testCreateApiButton();
|
||||
/**Create an Api1 of Paginate with Table Page No */
|
||||
cy.createApi(this.data.paginationUrl, this.data.paginationParam);
|
||||
cy.RunAPI();
|
||||
});
|
||||
|
||||
it("Table-Text, Validate Server Side Pagination of Paginate with Table Page No", function() {
|
||||
|
|
@ -59,6 +60,7 @@ describe("Test Create Api and Bind to Table widget", function() {
|
|||
cy.testCreateApiButton();
|
||||
/** Create Api2 of Paginate with Response URL*/
|
||||
cy.createApi(this.data.paginationUrl, "pokemon");
|
||||
cy.RunAPI();
|
||||
cy.NavigateToPaginationTab();
|
||||
cy.get(apiPage.apiPaginationNextText).type("{{Api2.data.next}}", {
|
||||
parseSpecialCharSequences: false,
|
||||
|
|
@ -66,7 +68,7 @@ describe("Test Create Api and Bind to Table widget", function() {
|
|||
cy.get(apiPage.apiPaginationPrevText).type("{{Api2.data.previous}}", {
|
||||
parseSpecialCharSequences: false,
|
||||
});
|
||||
cy.SaveAPI();
|
||||
cy.WaitAutoSave();
|
||||
|
||||
cy.get(pages.pagesIcon).click({ force: true });
|
||||
cy.openPropertyPane("textwidget");
|
||||
|
|
@ -74,6 +76,7 @@ describe("Test Create Api and Bind to Table widget", function() {
|
|||
cy.testJsontext("text", "{{Table1.selectedRow.url}}");
|
||||
cy.get(commonlocators.editPropCrossButton).click();
|
||||
cy.openPropertyPane("tablewidget");
|
||||
cy.testJsontext("tabledata", "{{Api2.data.results}}");
|
||||
cy.callApi("Api2");
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -7,5 +7,7 @@
|
|||
"password": "input[name='datasourceConfiguration.authentication.password']",
|
||||
"authenticationAuthtype": "[data-cy=datasourceConfiguration\\.authentication\\.authType]",
|
||||
"sslAuthtype": "[data-cy=datasourceConfiguration\\.connection\\.ssl\\.authType]",
|
||||
"url": "input[name='datasourceConfiguration.url']"
|
||||
"url": "input[name='datasourceConfiguration.url']",
|
||||
"sectionAuthentication": "[data-cy=section-Authentication]",
|
||||
"sectionSSL": "[data-cy=section-SSL\\ \\(optional\\)]"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -827,6 +827,8 @@ Cypress.Commands.add("testSaveDatasource", () => {
|
|||
Cypress.Commands.add("fillMongoDatasourceForm", () => {
|
||||
cy.get(datasourceEditor["host"]).type(datasourceFormData["mongo-host"]);
|
||||
cy.get(datasourceEditor["port"]).type(datasourceFormData["mongo-port"]);
|
||||
|
||||
cy.get(datasourceEditor.sectionAuthentication).click();
|
||||
cy.get(datasourceEditor["databaseName"])
|
||||
.clear()
|
||||
.type(datasourceFormData["mongo-databaseName"]);
|
||||
|
|
@ -837,6 +839,7 @@ Cypress.Commands.add("fillMongoDatasourceForm", () => {
|
|||
datasourceFormData["mongo-password"],
|
||||
);
|
||||
|
||||
cy.get(datasourceEditor.sectionSSL).click();
|
||||
cy.get(datasourceEditor["authenticationAuthtype"]).click();
|
||||
cy.contains(datasourceFormData["mongo-authenticationAuthtype"]).click({
|
||||
force: true,
|
||||
|
|
@ -854,6 +857,8 @@ Cypress.Commands.add("fillPostgresDatasourceForm", () => {
|
|||
cy.get(datasourceEditor.databaseName)
|
||||
.clear()
|
||||
.type(datasourceFormData["postgres-databaseName"]);
|
||||
|
||||
cy.get(datasourceEditor.sectionAuthentication).click();
|
||||
cy.get(datasourceEditor.username).type(
|
||||
datasourceFormData["postgres-username"],
|
||||
);
|
||||
|
|
@ -1125,8 +1130,8 @@ Cypress.Commands.add("ValidatePaginateResponseUrlData", runTestCss => {
|
|||
localStorage.setItem("respBody", respBody);
|
||||
cy.log(respBody);
|
||||
cy.get(pages.pagesIcon).click({ force: true });
|
||||
cy.openPropertyPane("tablewidget");
|
||||
cy.testJsontext("tabledata", "{{Api2.data.results}}");
|
||||
// cy.openPropertyPane("tablewidget");
|
||||
// cy.testJsontext("tabledata", "{{Api2.data.results}}");
|
||||
cy.isSelectRow(0);
|
||||
cy.get(commonlocators.labelTextStyle)
|
||||
.invoke("text")
|
||||
|
|
|
|||
|
|
@ -3,7 +3,4 @@
|
|||
<mask id="mask0" mask-type="alpha" maskUnits="userSpaceOnUse" x="1" y="1" width="18" height="18">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.33341 13.3333C8.33341 13.7916 7.95841 14.1666 7.50008 14.1666C7.04175 14.1666 6.66675 13.7916 6.66675 13.3333V9.99996C6.66675 9.54163 7.04175 9.16663 7.50008 9.16663C7.95841 9.16663 8.33341 9.54163 8.33341 9.99996V13.3333ZM13.3334 13.3333C13.3334 13.7916 12.9584 14.1666 12.5001 14.1666C12.0417 14.1666 11.6667 13.7916 11.6667 13.3333V9.99996C11.6667 9.54163 12.0417 9.16663 12.5001 9.16663C12.9584 9.16663 13.3334 9.54163 13.3334 9.99996V13.3333ZM15.0001 15.8333C15.0001 16.2925 14.6267 16.6666 14.1667 16.6666H5.83341C5.37341 16.6666 5.00008 16.2925 5.00008 15.8333V6.66663H15.0001V15.8333ZM8.33341 3.60663C8.33341 3.47746 8.51175 3.33329 8.75008 3.33329H11.2501C11.4884 3.33329 11.6667 3.47746 11.6667 3.60663V4.99996H8.33341V3.60663ZM17.5001 4.99996H16.6667H13.3334V3.60663C13.3334 2.53663 12.3992 1.66663 11.2501 1.66663H8.75008C7.60091 1.66663 6.66675 2.53663 6.66675 3.60663V4.99996H3.33341H2.50008C2.04175 4.99996 1.66675 5.37496 1.66675 5.83329C1.66675 6.29163 2.04175 6.66663 2.50008 6.66663H3.33341V15.8333C3.33341 17.2116 4.45508 18.3333 5.83342 18.3333H14.1667C15.5451 18.3333 16.6667 17.2116 16.6667 15.8333V6.66663H17.5001C17.9584 6.66663 18.3334 6.29163 18.3334 5.83329C18.3334 5.37496 17.9584 4.99996 17.5001 4.99996Z" fill="white"/>
|
||||
</mask>
|
||||
<g mask="url(#mask0)">
|
||||
<rect width="20" height="20" fill="#A3B3BF"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.8 KiB |
|
|
@ -9,7 +9,8 @@ const TabsWrapper = styled.div<{ overflow?: boolean }>`
|
|||
height: 100%;
|
||||
}
|
||||
.react-tabs__tab-panel {
|
||||
height: 100%;
|
||||
height: calc(100% - 46px);
|
||||
overflow: scroll;
|
||||
}
|
||||
.react-tabs__tab-list {
|
||||
border-bottom-color: #d0d7dd;
|
||||
|
|
|
|||
|
|
@ -103,6 +103,10 @@ const FailedMessageContainer = styled.div`
|
|||
align-items: center;
|
||||
`;
|
||||
|
||||
const TabbedViewWrapper = styled.div`
|
||||
height: calc(100% - 30px);
|
||||
`;
|
||||
|
||||
const ApiResponseView = (props: Props) => {
|
||||
const {
|
||||
match: {
|
||||
|
|
@ -143,7 +147,7 @@ const ApiResponseView = (props: Props) => {
|
|||
? JSON.stringify(response.body, null, 2)
|
||||
: "",
|
||||
}}
|
||||
height={700}
|
||||
height={"100%"}
|
||||
/>
|
||||
</>
|
||||
),
|
||||
|
|
@ -163,12 +167,12 @@ const ApiResponseView = (props: Props) => {
|
|||
title: "Request Body",
|
||||
panelComponent: (
|
||||
<CodeEditor
|
||||
height={"100%"}
|
||||
input={{
|
||||
value: _.isObject(response.requestBody)
|
||||
? JSON.stringify(response.requestBody, null, 2)
|
||||
: response.requestBody || "",
|
||||
}}
|
||||
height={700}
|
||||
/>
|
||||
),
|
||||
},
|
||||
|
|
@ -203,12 +207,14 @@ const ApiResponseView = (props: Props) => {
|
|||
</ResponseMetaInfo>
|
||||
</React.Fragment>
|
||||
</FormRow>
|
||||
<BaseTabbedView
|
||||
overflow
|
||||
tabs={tabs}
|
||||
selectedIndex={selectedIndex}
|
||||
setSelectedIndex={setSelectedIndex}
|
||||
/>
|
||||
<TabbedViewWrapper>
|
||||
<BaseTabbedView
|
||||
overflow
|
||||
tabs={tabs}
|
||||
selectedIndex={selectedIndex}
|
||||
setSelectedIndex={setSelectedIndex}
|
||||
/>
|
||||
</TabbedViewWrapper>
|
||||
</ResponseWrapper>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ export const StyledCheckbox = styled(BlueprintCheckbox)<CheckboxProps>`
|
|||
&&&& {
|
||||
span.bp3-control-indicator {
|
||||
outline: none;
|
||||
background: white;
|
||||
box-shadow: none;
|
||||
border-radius: ${props => props.theme.radii[1]}px;
|
||||
border: ${props => getBorderCSSShorthand(props.theme.borders[3])};
|
||||
|
|
|
|||
|
|
@ -6,9 +6,13 @@ import "codemirror/theme/monokai.css";
|
|||
|
||||
require("codemirror/mode/javascript/javascript");
|
||||
|
||||
const Wrapper = styled.div<{ height: number }>`
|
||||
height: ${props => props.height}px;
|
||||
const Wrapper = styled.div<{ height: number | string }>`
|
||||
height: ${props =>
|
||||
typeof props.height === "number" ? props.height + "px" : props.height};
|
||||
color: white;
|
||||
.CodeMirror {
|
||||
height: 100%;
|
||||
}
|
||||
`;
|
||||
|
||||
interface Props {
|
||||
|
|
@ -16,7 +20,7 @@ interface Props {
|
|||
value: string;
|
||||
onChange?: (event: ChangeEvent<HTMLTextAreaElement>) => void;
|
||||
};
|
||||
height: number;
|
||||
height: number | string;
|
||||
}
|
||||
|
||||
class CodeEditor extends React.Component<Props> {
|
||||
|
|
@ -35,7 +39,6 @@ class CodeEditor extends React.Component<Props> {
|
|||
lineNumbers: true,
|
||||
lineWrapping: true,
|
||||
});
|
||||
this.editor.setSize(null, this.props.height);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -288,6 +288,11 @@ const DynamicAutocompleteInputWrapper = styled.div<{
|
|||
props.isActive && props.skin === Skin.DARK
|
||||
? Colors.ALABASTER
|
||||
: "transparent"};
|
||||
.bp3-popover-wrapper:first-of-type {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
}
|
||||
&:hover {
|
||||
border: ${props =>
|
||||
props.skin === Skin.DARK ? "1px solid " + Colors.ALABASTER : "none"};
|
||||
|
|
|
|||
|
|
@ -224,7 +224,8 @@ const views = {
|
|||
props.set(event);
|
||||
}
|
||||
}}
|
||||
dataTreePath={""}
|
||||
expected={"string"}
|
||||
evaluatedValue={props.get(props.value, false) as string}
|
||||
isValid={props.isValid}
|
||||
errorMessage={props.validationMessage}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ function DataControlComponent(props: RenderComponentProps) {
|
|||
updateOption(index, "seriesName", value);
|
||||
},
|
||||
}}
|
||||
evaluatedValue={evaluated.seriesName}
|
||||
evaluatedValue={evaluated?.seriesName}
|
||||
theme={"DARK"}
|
||||
singleLine={false}
|
||||
placeholder="Series Name"
|
||||
|
|
@ -113,7 +113,7 @@ function DataControlComponent(props: RenderComponentProps) {
|
|||
updateOption(index, "data", value);
|
||||
},
|
||||
}}
|
||||
evaluatedValue={evaluated.data}
|
||||
evaluatedValue={evaluated?.data}
|
||||
meta={{
|
||||
error: isValid ? "" : "There is an error",
|
||||
touched: true,
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ export function InputText(props: {
|
|||
onChange: (event: React.ChangeEvent<HTMLTextAreaElement> | string) => void;
|
||||
isValid: boolean;
|
||||
errorMessage?: string;
|
||||
evaluatedValue?: any;
|
||||
expected?: string;
|
||||
placeholder?: string;
|
||||
dataTreePath?: string;
|
||||
|
|
@ -22,6 +23,7 @@ export function InputText(props: {
|
|||
onChange,
|
||||
placeholder,
|
||||
dataTreePath,
|
||||
evaluatedValue,
|
||||
} = props;
|
||||
return (
|
||||
<StyledDynamicInput>
|
||||
|
|
@ -30,6 +32,7 @@ export function InputText(props: {
|
|||
value: value,
|
||||
onChange: onChange,
|
||||
}}
|
||||
evaluatedValue={evaluatedValue}
|
||||
expected={expected}
|
||||
dataTreePath={dataTreePath}
|
||||
meta={{
|
||||
|
|
|
|||
|
|
@ -6,11 +6,11 @@ const WidgetSidebarResponse: {
|
|||
[id: string]: WidgetCardProps[];
|
||||
} = {
|
||||
["Form Widgets"]: [
|
||||
// {
|
||||
// type: "FORM_WIDGET",
|
||||
// widgetCardName: "Form",
|
||||
// key: generateReactKey(),
|
||||
// },
|
||||
{
|
||||
type: "FORM_WIDGET",
|
||||
widgetCardName: "Form",
|
||||
key: generateReactKey(),
|
||||
},
|
||||
{
|
||||
type: "INPUT_WIDGET",
|
||||
widgetCardName: "Input",
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ const DatasourceWrapper = styled.div`
|
|||
|
||||
const SecondaryWrapper = styled.div`
|
||||
display: flex;
|
||||
height: 100%;
|
||||
height: calc(100% - 120px);
|
||||
border-top: 1px solid #d0d7dd;
|
||||
margin-top: 15px;
|
||||
`;
|
||||
|
|
|
|||
|
|
@ -29,6 +29,10 @@ const PostbodyContainer = styled.div`
|
|||
|
||||
const JSONEditorFieldWrapper = styled.div`
|
||||
margin: 5px;
|
||||
.CodeMirror {
|
||||
height: auto;
|
||||
min-height: 300px;
|
||||
}
|
||||
`;
|
||||
export interface RapidApiAction {
|
||||
editable: boolean;
|
||||
|
|
@ -110,7 +114,6 @@ const PostBodyData = (props: Props) => {
|
|||
<DynamicTextField
|
||||
name="actionConfiguration.body"
|
||||
expected={FIELD_VALUES.API_ACTION.body}
|
||||
height={300}
|
||||
showLineNumbers
|
||||
allowTabIndent
|
||||
singleLine={false}
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ const MainConfiguration = styled.div`
|
|||
|
||||
const SecondaryWrapper = styled.div`
|
||||
display: flex;
|
||||
height: 100%;
|
||||
height: calc(100% - 120px);
|
||||
border-top: 1px solid #d0d7dd;
|
||||
margin-top: 10px;
|
||||
`;
|
||||
|
|
@ -163,7 +163,12 @@ const RapidApiEditorForm: React.FC<Props> = (props: Props) => {
|
|||
// }
|
||||
|
||||
return (
|
||||
<Form onSubmit={handleSubmit}>
|
||||
<Form
|
||||
onSubmit={handleSubmit}
|
||||
style={{
|
||||
height: "100%",
|
||||
}}
|
||||
>
|
||||
<MainConfiguration>
|
||||
<FormRow>
|
||||
<DynamicTextField
|
||||
|
|
|
|||
|
|
@ -188,6 +188,7 @@ class ApiEditor extends React.Component<Props> {
|
|||
<div
|
||||
style={{
|
||||
position: "relative",
|
||||
height: "100%",
|
||||
}}
|
||||
>
|
||||
{apiId ? (
|
||||
|
|
|
|||
|
|
@ -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<Props, ComponentState> {
|
|||
super(props);
|
||||
|
||||
this.state = {
|
||||
isOpen: true,
|
||||
isOpen: props.defaultIsOpen || false,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -54,6 +55,7 @@ class Collapsible extends React.Component<Props, ComponentState> {
|
|||
}}
|
||||
/>
|
||||
<SectionContainer
|
||||
data-cy={`section-${title}`}
|
||||
onClick={() => this.setState({ isOpen: !this.state.isOpen })}
|
||||
>
|
||||
<SectionLabel>{title}</SectionLabel>
|
||||
|
|
|
|||
|
|
@ -332,9 +332,7 @@ class DatasourceDBEditor extends React.Component<
|
|||
/>
|
||||
</FormTitleContainer>
|
||||
{!_.isNil(sections)
|
||||
? _.map(sections, section => {
|
||||
return this.renderMainSection(section);
|
||||
})
|
||||
? _.map(sections, this.renderMainSection)
|
||||
: undefined}
|
||||
<SaveButtonContainer>
|
||||
<ActionButton
|
||||
|
|
@ -367,9 +365,9 @@ class DatasourceDBEditor extends React.Component<
|
|||
);
|
||||
};
|
||||
|
||||
renderMainSection = (section: any) => {
|
||||
renderMainSection = (section: any, index: number) => {
|
||||
return (
|
||||
<Collapsible title={section.sectionName}>
|
||||
<Collapsible title={section.sectionName} defaultIsOpen={index === 0}>
|
||||
{this.renderEachConfig(section)}
|
||||
</Collapsible>
|
||||
);
|
||||
|
|
@ -413,7 +411,7 @@ class DatasourceDBEditor extends React.Component<
|
|||
}
|
||||
|
||||
return (
|
||||
<div style={{ marginTop: "16px" }}>
|
||||
<div key={configProperty} style={{ marginTop: "16px" }}>
|
||||
{controlType !== "KEYVALUE_ARRAY" &&
|
||||
controlType !== "SWITCH" && (
|
||||
<FormLabel>
|
||||
|
|
|
|||
|
|
@ -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: Props) => {
|
|||
);
|
||||
};
|
||||
|
||||
const SingleValue = (props: SingleValueProps<OptionTypeBase>) => {
|
||||
return (
|
||||
<>
|
||||
<components.SingleValue {...props}>
|
||||
<Container>
|
||||
<img
|
||||
className="plugin-image"
|
||||
src={props.data.image}
|
||||
alt="Datasource"
|
||||
/>
|
||||
<div className="selected-value">{props.children}</div>
|
||||
</Container>
|
||||
</components.SingleValue>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const CustomOption = (props: OptionProps<OptionTypeBase>) => {
|
||||
return (
|
||||
<>
|
||||
<components.Option {...props}>
|
||||
<Container>
|
||||
<img
|
||||
className="plugin-image"
|
||||
src={props.data.image}
|
||||
alt="Datasource"
|
||||
/>
|
||||
<div style={{ marginLeft: "6px" }}>{props.children}</div>
|
||||
</Container>
|
||||
</components.Option>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<QueryFormContainer>
|
||||
<form onSubmit={handleSubmit}>
|
||||
|
|
@ -314,9 +380,9 @@ const QueryEditorForm: React.FC<Props> = (props: Props) => {
|
|||
placeholder="Datasource"
|
||||
name="datasource.id"
|
||||
options={DATASOURCES_OPTIONS}
|
||||
width={200}
|
||||
width={232}
|
||||
maxMenuHeight={200}
|
||||
components={{ MenuList }}
|
||||
components={{ MenuList, Option: CustomOption, SingleValue }}
|
||||
/>
|
||||
</DropdownSelect>
|
||||
<ActionButtons>
|
||||
|
|
@ -430,6 +496,12 @@ const QueryEditorForm: React.FC<Props> = (props: Props) => {
|
|||
mode="js-js"
|
||||
/>
|
||||
)}
|
||||
<StyledCheckbox
|
||||
intent="primary"
|
||||
name="executeOnLoad"
|
||||
align="left"
|
||||
label="Run on Page Load"
|
||||
/>
|
||||
</form>
|
||||
|
||||
{dataSources.length === 0 && (
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ class JSONOutput extends React.Component<Props> {
|
|||
style: {
|
||||
fontSize: "14px",
|
||||
},
|
||||
collapsed: 1,
|
||||
};
|
||||
|
||||
if (!src.length) {
|
||||
|
|
|
|||
21
app/client/src/pages/Editor/QueryEditor/helpers.ts
Normal file
21
app/client/src/pages/Editor/QueryEditor/helpers.ts
Normal file
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
|
@ -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<Props> {
|
|||
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),
|
||||
|
|
|
|||
|
|
@ -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<Props> {
|
|||
renderItem = (query: RestAction) => {
|
||||
return (
|
||||
<ActionItem>
|
||||
<StyledImage
|
||||
src={getPluginImage(this.props.plugins, query.pluginId)}
|
||||
className="pluginImage"
|
||||
alt="Plugin Image"
|
||||
/>
|
||||
<ActionName>{query.name}</ActionName>
|
||||
</ActionItem>
|
||||
);
|
||||
|
|
@ -191,6 +216,7 @@ class QuerySidebar extends React.Component<Props> {
|
|||
}
|
||||
|
||||
const mapStateToProps = (state: AppState): ReduxStateProps => ({
|
||||
plugins: getPlugins(state),
|
||||
queries: getQueryActions(state),
|
||||
apiPane: state.ui.apiPane,
|
||||
actions: state.entities.actions,
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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<CheckboxWidgetProps, WidgetState> {
|
||||
static getPropertyValidationMap(): WidgetPropertyValidationType {
|
||||
|
|
@ -32,6 +35,12 @@ class CheckboxWidget extends BaseWidget<CheckboxWidgetProps, WidgetState> {
|
|||
};
|
||||
}
|
||||
|
||||
static getDerivedPropertiesMap(): DerivedPropertiesMap {
|
||||
return {
|
||||
value: `{{this.isChecked}}`,
|
||||
};
|
||||
}
|
||||
|
||||
static getMetaPropertiesMap(): Record<string, any> {
|
||||
return {
|
||||
isChecked: undefined,
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ class DatePickerWidget extends BaseWidget<DatePickerWidgetProps, WidgetState> {
|
|||
static getDerivedPropertiesMap(): DerivedPropertiesMap {
|
||||
return {
|
||||
isValid: `{{ this.isRequired ? !!this.selectedDate : true }}`,
|
||||
value: `{{ this.selectedDate }}`,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ class DropdownWidget extends BaseWidget<DropdownWidgetProps, WidgetState> {
|
|||
},
|
||||
};
|
||||
}
|
||||
|
||||
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<DropdownWidgetProps, WidgetState> {
|
|||
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 }}`,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ class FilePickerWidget extends BaseWidget<
|
|||
static getDerivedPropertiesMap(): DerivedPropertiesMap {
|
||||
return {
|
||||
isValid: `{{ this.isRequired ? this.files.length > 0 : true }}`,
|
||||
value: `{{this.files}}`,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<any>) {
|
||||
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<WidgetProps>) {
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ class InputWidget extends BaseWidget<InputWidgetProps, InputWidgetState> {
|
|||
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}}`,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ class RadioGroupWidget extends BaseWidget<RadioGroupWidgetProps, WidgetState> {
|
|||
selectedOption:
|
||||
"{{_.find(this.options, { value: this.selectedOptionValue })}}",
|
||||
isValid: `{{ this.isRequired ? !!this.selectedOptionValue : true }}`,
|
||||
value: `{{this.selectedOptionValue}}`,
|
||||
};
|
||||
}
|
||||
static getTriggerPropertyMap(): TriggerPropertiesMap {
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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<TextWidgetProps, WidgetState> {
|
|||
);
|
||||
}
|
||||
|
||||
static getDerivedPropertiesMap(): DerivedPropertiesMap {
|
||||
return {
|
||||
value: `{{ this.text }}`,
|
||||
};
|
||||
}
|
||||
|
||||
getWidgetType(): WidgetType {
|
||||
return "TEXT_WIDGET";
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user