Merge branch 'release' of https://github.com/appsmithorg/appsmith into release

This commit is contained in:
Automated Github Action 2020-09-02 07:06:16 +00:00
commit af24f95ca9
51 changed files with 494 additions and 294 deletions

View File

@ -9,12 +9,9 @@ describe("Moustache test Functionality", function() {
cy.addDsl(dsl);
});
it("Moustache test Functionality", function() {
//cy.get(pages.widgetsEditor).click();
cy.openPropertyPane("textwidget");
cy.widgetText("Api", widgetsPage.textWidget, widgetsPage.textInputval);
cy.testCodeMirror("/api/users/2");
cy.NavigateToEntityExplorer();
cy.wait(10000);
cy.NavigateToAPI_Panel();
cy.log("Navigation to API Panel screen successful");
cy.CreateAPI("TestAPINew");

View File

@ -23,7 +23,6 @@ describe("Duplicate application", function() {
.contains("Duplicate")
.click({ force: true });
cy.get(explorerlocators.entityExplorer).should("be.visible");
cy.wait("@getPage").should(
"have.nested.property",
"response.body.responseMeta.status",

View File

@ -16,7 +16,6 @@ describe("Binding the Datepicker and Text Widget", function() {
/**
* Bind DatePicker1 to Text for "selectedDate"
*/
cy.get(pages.widgetsEditor).click();
cy.openPropertyPane("textwidget");
cy.testJsontext("text", "{{DatePicker1.selectedDate}}");
cy.get(commonlocators.editPropCrossButton).click();
@ -50,7 +49,6 @@ describe("Binding the Datepicker and Text Widget", function() {
});
it("DatePicker1-text: Change the date in DatePicker1 and Validate the same in text widget", function() {
cy.get(pages.widgetsEditor).click();
cy.openPropertyPane("textwidget");
/**
@ -108,7 +106,6 @@ describe("Binding the Datepicker and Text Widget", function() {
/**
* Bind the DatePicker1 and DatePicker2 along with hard coded text to Text widget
*/
cy.get(pages.widgetsEditor).click();
cy.openPropertyPane("textwidget");
cy.testJsontext(
"text",

View File

@ -16,15 +16,14 @@ describe("Test Create Api and Bind to Table widget", function() {
});
it("Table-Text, Validate Server Side Pagination of Paginate with Table Page No", function() {
cy.get(pages.widgetsEditor).click();
cy.openPropertyPane("tablewidget");
cy.SearchEntityandOpen("Table1");
/**Bind Api1 with Table widget */
cy.testJsontext("tabledata", "{{Api1.data.users}}");
cy.CheckWidgetProperties(commonlocators.serverSidePaginationCheckbox);
/**Bind Table with Textwidget with selected row */
cy.get(pages.widgetsEditor).click();
cy.openPropertyPane("textwidget");
cy.SearchEntityandOpen("Text1");
cy.testJsontext("text", "{{Table1.selectedRow.url}}");
cy.SearchEntityandOpen("Table1");
cy.readTabledata("0", "0").then(tabData => {
const tableData = tabData;
localStorage.setItem("tableDataPage1", tableData);
@ -43,7 +42,6 @@ describe("Test Create Api and Bind to Table widget", function() {
cy.get(commonlocators.rightArrowBtn).click({ force: true });
cy.validateToastMessage("done");
cy.ValidatePublishTableData("11");
cy.get(publishPage.backToEditor).click({ force: true });
});
@ -59,13 +57,12 @@ describe("Test Create Api and Bind to Table widget", function() {
parseSpecialCharSequences: false,
});
cy.WaitAutoSave();
cy.get(pages.widgetsEditor).click();
cy.openPropertyPane("textwidget");
cy.SearchEntityandOpen("Text1");
//cy.openPropertyPane("textwidget");
/** Bind the Table widget with Text widget*/
cy.testJsontext("text", "{{Table1.selectedRow.url}}");
cy.get(commonlocators.editPropCrossButton).click();
cy.get(pages.widgetsEditor).click();
cy.openPropertyPane("tablewidget");
cy.SearchEntityandOpen("Table1");
cy.testJsontext("tabledata", "{{Api2.data.users}}");
cy.callApi("Api2");
});

View File

@ -27,9 +27,8 @@ describe("Test Create Api and Bind to Table widget", function() {
});
it("Test_Validate the Api data is updated on Table widget", function() {
//cy.get(pages.pagesIcon).click({ force: true });
cy.get(pages.widgetsEditor).click();
cy.openPropertyPane("tablewidget");
cy.SearchEntityandOpen("Table1");
//cy.openPropertyPane("tablewidget");
cy.testJsontext("tabledata", "{{Api1.data}}");
cy.get(commonlocators.editPropCrossButton).click();

View File

@ -9,7 +9,6 @@ describe("Text-Chart Binding Functionality", function() {
cy.addDsl(dsl);
});
it("Text-Chart Binding Functionality View", function() {
cy.get(pages.widgetsEditor).click();
cy.openPropertyPane("textwidget");
cy.testJsontext("text", JSON.stringify(this.data.chartInputValidate));
cy.get(commonlocators.TextInside).should(
@ -17,7 +16,6 @@ describe("Text-Chart Binding Functionality", function() {
JSON.stringify(this.data.chartInputValidate),
);
cy.closePropertyPane();
cy.get(pages.widgetsEditor).click();
cy.openPropertyPane("chartwidget");
cy.get(viewWidgetsPage.chartType)
.find(commonlocators.dropdownbuttonclick)

View File

@ -14,7 +14,6 @@ describe("Text-Table Binding Functionality", function() {
cy.addDsl(dsl);
});
it("Text-Table Binding Functionality For Id", function() {
cy.get(pages.widgetsEditor).click();
cy.openPropertyPane("tablewidget");
/**
* @param(Index) Provide index value to select the row.
@ -43,7 +42,6 @@ describe("Text-Table Binding Functionality", function() {
cy.get(publish.backToEditor)
.first()
.click();
cy.get(pages.widgetsEditor).click();
cy.isSelectRow(2);
cy.openPropertyPane("textwidget");
cy.testJsontext("text", "{{Table1.selectedRow.email}}");
@ -68,7 +66,6 @@ describe("Text-Table Binding Functionality", function() {
cy.get(publish.backToEditor)
.first()
.click();
cy.get(pages.widgetsEditor).click();
cy.openPropertyPane("textwidget");
cy.testJsontext("text", "{{Table1.pageSize}}");
cy.get(commonlocators.TableRow)
@ -95,7 +92,6 @@ describe("Text-Table Binding Functionality", function() {
* @param(Index) Provide index value to select the row.
*/
cy.isSelectRow(1);
cy.get(pages.widgetsEditor).click();
cy.openPropertyPane("textwidget");
cy.testJsontext("text", JSON.stringify(this.data.textfun));
/**

View File

@ -10,7 +10,6 @@ describe("Chart Widget Functionality", function() {
});
beforeEach(() => {
cy.get(pages.widgetsEditor).click();
cy.openPropertyPane("chartwidget");
});

View File

@ -10,7 +10,6 @@ describe("Image Widget Functionality", function() {
});
it("Image Widget Functionality", function() {
cy.get(pages.widgetsEditor).click();
cy.openPropertyPane("imagewidget");
/**
* @param{Text} Random Text
@ -43,7 +42,6 @@ describe("Image Widget Functionality", function() {
});
it("Image Widget Functionality To Unchecked Visible Widget", function() {
cy.get(publish.backToEditor).click();
cy.get(pages.widgetsEditor).click();
cy.openPropertyPane("imagewidget");
cy.togglebarDisable(commonlocators.visibleCheckbox);
cy.PublishtheApp();
@ -51,7 +49,6 @@ describe("Image Widget Functionality", function() {
cy.get(publish.backToEditor).click();
});
it("Image Widget Functionality To Check Visible Widget", function() {
cy.get(pages.widgetsEditor).click();
cy.openPropertyPane("imagewidget");
cy.togglebar(commonlocators.visibleCheckbox);
cy.PublishtheApp();

View File

@ -10,7 +10,6 @@ describe("Table Widget Functionality", function() {
});
it("Table Widget Functionality", function() {
cy.get(pages.widgetsEditor).click();
cy.openPropertyPane("tablewidget");
/**

View File

@ -10,7 +10,6 @@ describe("Text Widget Functionality", function() {
});
beforeEach(() => {
cy.get(pages.widgetsEditor).click();
cy.openPropertyPane("textwidget");
});

View File

@ -10,7 +10,6 @@ describe("Dynamic input autocomplete", () => {
cy.addDsl(dsl);
});
it("opens autocomplete for bindings", () => {
cy.get(pages.widgetsEditor).click();
cy.openPropertyPane("buttonwidget");
cy.get(dynamicInputLocators.input)
.first()
@ -57,14 +56,11 @@ describe("Dynamic input autocomplete", () => {
});
it("opens current value popup", () => {
// Test on widgets pane
cy.get(pages.widgetsEditor).click();
cy.openPropertyPane("buttonwidget");
cy.get(dynamicInputLocators.input)
.first()
.focus();
cy.assertEvaluatedValuePopup("string");
cy.NavigateToEntityExplorer();
// Test on api pane
cy.NavigateToAPI_Panel();
cy.get(apiwidget.createapi).click({ force: true });

View File

@ -8,7 +8,6 @@ describe("Entity explorer tests related to widgets and validation", function() {
});
it("Widget edit/delete/copy to clipboard validation", function() {
cy.NavigateToEntityExplorer();
cy.SearchEntityandOpen("Text1");
cy.get(explorer.collapse)
.last()

View File

@ -12,7 +12,6 @@ describe("Button Widget Functionality", function() {
});
beforeEach(() => {
cy.get(pages.widgetsEditor).click();
cy.openPropertyPane("buttonwidget");
});

View File

@ -10,7 +10,6 @@ describe("Checkbox Widget Functionality", function() {
cy.addDsl(dsl);
});
it("Checkbox Widget Functionality", function() {
cy.get(pages.widgetsEditor).click();
cy.openPropertyPane("checkboxwidget");
/**
* @param{Text} Random Text
@ -45,7 +44,6 @@ describe("Checkbox Widget Functionality", function() {
cy.get(publish.backToEditor).click();
});
it("Checkbox Functionality To Check Disabled Widget", function() {
cy.get(pages.widgetsEditor).click();
cy.openPropertyPane("checkboxwidget");
cy.togglebar(commonlocators.Disablejs + " " + "input");
cy.PublishtheApp();
@ -53,7 +51,6 @@ describe("Checkbox Widget Functionality", function() {
cy.get(publish.backToEditor).click();
});
it("Checkbox Functionality To Check Enabled Widget", function() {
cy.get(pages.widgetsEditor).click();
cy.openPropertyPane("checkboxwidget");
cy.togglebarDisable(commonlocators.Disablejs + " " + "input");
cy.PublishtheApp();
@ -61,7 +58,6 @@ describe("Checkbox Widget Functionality", function() {
cy.get(publish.backToEditor).click();
});
it("Checkbox Functionality To Unchecked Visible Widget", function() {
cy.get(pages.widgetsEditor).click();
cy.openPropertyPane("checkboxwidget");
cy.togglebarDisable(commonlocators.visibleCheckbox);
cy.PublishtheApp();
@ -69,7 +65,6 @@ describe("Checkbox Widget Functionality", function() {
cy.get(publish.backToEditor).click();
});
it("Checkbox Functionality To Check Visible Widget", function() {
cy.get(pages.widgetsEditor).click();
cy.openPropertyPane("checkboxwidget");
cy.togglebar(commonlocators.visibleCheckbox);
cy.PublishtheApp();

View File

@ -10,7 +10,6 @@ describe("DatePicker Widget Functionality", function() {
});
beforeEach(() => {
cy.get(pages.widgetsEditor).click();
cy.openPropertyPane("datepickerwidget");
});

View File

@ -9,7 +9,6 @@ describe("Dropdown Widget Functionality", function() {
cy.addDsl(dsl);
});
it("Dropdown Widget Functionality", function() {
cy.get(pages.widgetsEditor).click();
cy.openPropertyPane("dropdownwidget");
/**
* @param{Text} Random Text
@ -48,7 +47,6 @@ describe("Dropdown Widget Functionality", function() {
cy.get(publish.backToEditor).click();
});
it("Dropdown Functionality To Unchecked Visible Widget", function() {
cy.get(pages.widgetsEditor).click();
cy.openPropertyPane("dropdownwidget");
cy.togglebarDisable(commonlocators.visibleCheckbox);
cy.PublishtheApp();
@ -56,7 +54,6 @@ describe("Dropdown Widget Functionality", function() {
cy.get(publish.backToEditor).click();
});
it("Dropdown Functionality To Check Visible Widget", function() {
cy.get(pages.widgetsEditor).click();
cy.openPropertyPane("dropdownwidget");
cy.togglebar(commonlocators.visibleCheckbox);
cy.PublishtheApp();

View File

@ -7,7 +7,6 @@ describe("FilePicker Widget Functionality", function() {
cy.addDsl(dsl);
});
it("FilePicker Widget Functionality", function() {
cy.get(pages.widgetsEditor).click();
cy.openPropertyPane("filepickerwidget");
//Checking the edit props for FilePicker and also the properties of FilePicker widget

View File

@ -9,7 +9,6 @@ describe("Form Widget Functionality", function() {
cy.addDsl(dsl);
});
it("Form Widget Functionality", function() {
cy.get(pages.widgetsEditor).click();
cy.openPropertyPane("formwidget");
/**
* @param{Text} Random Text
@ -45,7 +44,6 @@ describe("Form Widget Functionality", function() {
});
it("Form Widget Functionality To Unchecked Visible Widget", function() {
cy.get(publish.backToEditor).click();
cy.get(pages.widgetsEditor).click();
cy.openPropertyPane("formwidget");
cy.togglebarDisable(commonlocators.visibleCheckbox);
cy.PublishtheApp();

View File

@ -9,7 +9,6 @@ describe("Input Widget Functionality", function() {
cy.addDsl(dsl);
});
it("Input Widget Functionality", function() {
cy.get(pages.widgetsEditor).click();
cy.openPropertyPane("inputwidget");
/**
* @param{Text} Random Text
@ -65,7 +64,6 @@ describe("Input Widget Functionality", function() {
cy.get(publish.backToEditor).click({ force: true });
});
it("Input Widget Functionality To Check Disabled Widget", function() {
cy.get(pages.widgetsEditor).click();
cy.openPropertyPane("inputwidget");
cy.togglebar(commonlocators.Disablejs + " " + "input");
cy.PublishtheApp();
@ -73,7 +71,6 @@ describe("Input Widget Functionality", function() {
cy.get(publish.backToEditor).click({ force: true });
});
it("Input Widget Functionality To Check Enabled Widget", function() {
cy.get(pages.widgetsEditor).click();
cy.openPropertyPane("inputwidget");
cy.togglebarDisable(commonlocators.Disablejs + " " + "input");
cy.PublishtheApp();
@ -81,7 +78,6 @@ describe("Input Widget Functionality", function() {
cy.get(publish.backToEditor).click({ force: true });
});
it("Input Functionality To Unchecked Visible Widget", function() {
cy.get(pages.widgetsEditor).click();
cy.openPropertyPane("inputwidget");
cy.togglebarDisable(commonlocators.visibleCheckbox);
cy.PublishtheApp();
@ -89,7 +85,6 @@ describe("Input Widget Functionality", function() {
cy.get(publish.backToEditor).click({ force: true });
});
it("Input Functionality To Check Visible Widget", function() {
cy.get(pages.widgetsEditor).click();
cy.openPropertyPane("inputwidget");
cy.togglebar(commonlocators.visibleCheckbox);
cy.PublishtheApp();

View File

@ -9,7 +9,6 @@ describe("Radio Widget Functionality", function() {
cy.addDsl(dsl);
});
it("Radio Widget Functionality", function() {
cy.get(pages.widgetsEditor).click();
cy.openPropertyPane("radiogroupwidget");
/**
* @param{Text} Random Text
@ -59,7 +58,6 @@ describe("Radio Widget Functionality", function() {
});
it("Radio Functionality To Unchecked Visible Widget", function() {
cy.get(publish.backToEditor).click();
cy.get(pages.widgetsEditor).click();
cy.openPropertyPane("radiogroupwidget");
cy.togglebarDisable(commonlocators.visibleCheckbox);
cy.PublishtheApp();
@ -67,7 +65,6 @@ describe("Radio Widget Functionality", function() {
cy.get(publish.backToEditor).click();
});
it("Radio Functionality To Check Visible Widget", function() {
cy.get(pages.widgetsEditor).click();
cy.openPropertyPane("radiogroupwidget");
cy.togglebar(commonlocators.visibleCheckbox);
cy.PublishtheApp();

View File

@ -10,7 +10,6 @@ describe("RichTextEditor Widget Functionality", function() {
});
beforeEach(() => {
cy.get(pages.widgetsEditor).click();
cy.openPropertyPane("richtexteditorwidget");
});

View File

@ -10,7 +10,6 @@ describe("Tab widget test", function() {
cy.addDsl(dsl);
});
it("Tab Widget Functionality Test", function() {
cy.get(pages.widgetsEditor).click();
cy.openPropertyPane("tabswidget");
/**
* @param{Text} Random Text
@ -60,7 +59,6 @@ describe("Tab widget test", function() {
});
it("Tab Widget Functionality To Unchecked Visible Widget", function() {
cy.get(publish.backToEditor).click();
cy.get(pages.widgetsEditor).click();
cy.openPropertyPane("tabswidget");
cy.togglebarDisable(commonlocators.visibleCheckbox);
cy.PublishtheApp();
@ -68,7 +66,6 @@ describe("Tab widget test", function() {
cy.get(publish.backToEditor).click();
});
it("Tab Widget Functionality To Check Visible Widget", function() {
cy.get(pages.widgetsEditor).click();
cy.openPropertyPane("tabswidget");
cy.togglebar(commonlocators.visibleCheckbox);
cy.PublishtheApp();

View File

@ -1554,8 +1554,6 @@ Cypress.Commands.add("ValidatePublishTableData", value => {
});
Cypress.Commands.add("ValidatePaginateResponseUrlData", runTestCss => {
cy.NavigateToEntityExplorer();
cy.NavigateToApiEditor();
cy.SearchEntityandOpen("Api2");
cy.NavigateToPaginationTab();
cy.RunAPI();
@ -1573,7 +1571,7 @@ Cypress.Commands.add("ValidatePaginateResponseUrlData", runTestCss => {
const respBody = tabData.match(/"(.*)"/)[0];
localStorage.setItem("respBody", respBody);
cy.log(respBody);
cy.get(pages.widgetsEditor).click({ force: true });
cy.SearchEntityandOpen("Table1");
// cy.openPropertyPane("tablewidget");
// cy.testJsontext("tabledata", "{{Api2.data.results}}");
cy.isSelectRow(0);

View File

@ -15,13 +15,10 @@ export const createDatasourceFromForm = (payload: CreateDatasourceConfig) => {
};
};
export const updateDatasource = (
payload: Datasource,
reinitializeForm?: boolean,
) => {
export const updateDatasource = (payload: Datasource) => {
return {
type: ReduxActionTypes.UPDATE_DATASOURCE_INIT,
payload: { datasource: payload, reinitializeForm: !!reinitializeForm },
payload,
};
};

View File

@ -1,36 +1,169 @@
import { ReactNode } from "react";
import { IconName } from "./Icon";
import { CommonComponentProps } from "./common";
import React, { useState, useEffect, useCallback } from "react";
import Icon, { IconName, IconSize } from "./Icon";
import { CommonComponentProps, Classes } from "./common";
import styled from "styled-components";
import Text, { TextType } from "./Text";
type DropdownOption = {
label: string;
label?: string;
value: string;
id?: string;
icon: IconName; // Create an icon library
icon?: IconName;
onSelect?: (option: DropdownOption) => void;
children?: DropdownOption[];
};
export enum DropdownDisplayType {
TAGS = "TAGS",
CHECKBOXES = "CHECKBOXES",
}
type DropdownProps = CommonComponentProps & {
options: DropdownOption[];
selectHandler: (selectedValue: string) => void;
selected?: DropdownOption;
multiselectDisplayType?: DropdownDisplayType;
checked?: boolean;
multi?: boolean;
autocomplete?: boolean;
addItem?: {
displayText: string;
addItemHandler: (name: string) => void;
};
toggle?: ReactNode;
selected: DropdownOption;
};
export default function Button(props: DropdownProps) {
return null;
const DropdownContainer = styled.div`
width: 260px;
`;
const Selected = styled.div<{ isOpen: boolean; disabled?: boolean }>`
padding: ${props => props.theme.spaces[4]}px
${props => props.theme.spaces[6]}px;
background: ${props =>
props.disabled
? props.theme.colors.blackShades[2]
: props.theme.colors.blackShades[0]};
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
cursor: pointer;
${props =>
props.isOpen && !props.disabled
? `border: 1.2px solid ${props.theme.colors.info.main}`
: null};
${props =>
props.isOpen && !props.disabled ? "box-sizing: border-box" : null};
${props =>
props.isOpen && !props.disabled
? "box-shadow: 0px 0px 4px 4px rgba(203, 72, 16, 0.18)"
: null};
.${Classes.TEXT} {
${props =>
props.disabled
? `color: ${props.theme.colors.blackShades[6]}`
: `color: ${props.theme.colors.blackShades[7]}`};
}
`;
const DropdownWrapper = styled.div`
margin-top: ${props => props.theme.spaces[2] - 1}px;
background: ${props => props.theme.colors.blackShades[3]};
box-shadow: 0px 12px 28px rgba(0, 0, 0, 0.6);
width: 100%;
`;
const OptionWrapper = styled.div<{ selected: boolean }>`
padding: ${props => props.theme.spaces[4]}px
${props => props.theme.spaces[6]}px;
cursor: pointer;
display: flex;
align-items: center;
${props =>
props.selected ? `background: ${props.theme.colors.blackShades[4]}` : null};
.${Classes.TEXT} {
${props =>
props.selected ? `color: ${props.theme.colors.blackShades[9]}` : null};
}
.${Classes.ICON} {
margin-right: ${props => props.theme.spaces[5]}px;
svg {
path {
${props =>
props.selected
? `fill: ${props.theme.colors.blackShades[8]}`
: `fill: ${props.theme.colors.blackShades[6]}`};
}
}
}
&:hover {
.${Classes.TEXT} {
color: ${props => props.theme.colors.blackShades[9]};
}
.${Classes.ICON} {
svg {
path {
fill: ${props => props.theme.colors.blackShades[8]};
}
}
}
}
`;
const LabelWrapper = styled.div<{ label?: string }>`
display: flex;
flex-direction: column;
align-item: flex-start;
${props =>
props.label
? `
.${Classes.TEXT}:last-child {
margin-top: ${props.theme.spaces[2] - 1}px;
}
`
: null}
`;
export default function Dropdown(props: DropdownProps) {
const [isOpen, setIsOpen] = useState<boolean>(false);
const [selected, setSelected] = useState<DropdownOption>(props.selected);
useEffect(() => {
setSelected(props.selected);
}, [props.selected]);
const optionClickHandler = useCallback((option: DropdownOption) => {
setSelected(option);
setIsOpen(false);
option.onSelect && option.onSelect(option);
}, []);
return (
<DropdownContainer tabIndex={0} onBlur={() => setIsOpen(false)}>
<Selected
isOpen={isOpen}
disabled={props.disabled}
onClick={() => setIsOpen(!isOpen)}
>
<Text type={TextType.P1}>{selected.value}</Text>
<Icon name="downArrow" size={IconSize.SMALL} />
</Selected>
{isOpen && !props.disabled ? (
<DropdownWrapper>
{props.options.map((option: DropdownOption, index: number) => {
return (
<OptionWrapper
key={index}
selected={selected.value === option.value}
onClick={() => optionClickHandler(option)}
>
{option.icon ? (
<Icon name={option.icon} size={IconSize.LARGE} />
) : null}
<LabelWrapper label={option.label}>
{option.label ? (
<Text type={TextType.H5}>{option.value}</Text>
) : (
<Text type={TextType.P1}>{option.value}</Text>
)}
{option.label ? (
<Text type={TextType.P3}>{option.label}</Text>
) : null}
</LabelWrapper>
</OptionWrapper>
);
})}
</DropdownWrapper>
) : null}
</DropdownContainer>
);
}

View File

@ -8,6 +8,7 @@ import { ReactComponent as ErrorIcon } from "assets/icons/ads/error.svg";
import { ReactComponent as SuccessIcon } from "assets/icons/ads/success.svg";
import { ReactComponent as SearchIcon } from "assets/icons/ads/search.svg";
import { ReactComponent as CloseIcon } from "assets/icons/ads/close.svg";
import { ReactComponent as DownArrow } from "assets/icons/ads/down_arrow.svg";
import { ReactComponent as ShareIcon } from "assets/icons/ads/share.svg";
import { ReactComponent as RocketIcon } from "assets/icons/ads/launch.svg";
import { ReactComponent as WorkspaceIcon } from "assets/icons/ads/workspace.svg";
@ -72,6 +73,7 @@ export const IconCollection = [
"plus",
"invite-user",
"view-all",
"downArrow",
] as const;
export type IconName = typeof IconCollection[number];
@ -143,6 +145,9 @@ const Icon = (props: IconProps & CommonComponentProps) => {
case "close":
returnIcon = <CloseIcon />;
break;
case "downArrow":
returnIcon = <DownArrow />;
break;
case "share":
returnIcon = <ShareIcon />;
break;

View File

@ -1,28 +1,30 @@
import React, { memo } from "react";
import { Switch, Route } from "react-router";
import styled from "styled-components";
import { WIDGETS_URL } from "constants/routes";
import WidgetSidebar from "pages/Editor/WidgetSidebar";
import ExplorerSidebar from "pages/Editor/Explorer";
import { PanelStack, Classes } from "@blueprintjs/core";
import { Colors } from "constants/Colors";
const SidebarWrapper = styled.div`
background-color: ${Colors.MINE_SHAFT};
padding: 0px 0 0 6px;
width: ${props => props.theme.sidebarWidth};
color: ${props => props.theme.colors.textOnDarkBG};
overflow-y: auto;
& .${Classes.PANEL_STACK} {
height: 100%;
.${Classes.PANEL_STACK_VIEW} {
background: none;
}
}
`;
const initialPanel = { component: ExplorerSidebar };
export const Sidebar = memo(() => {
return (
<SidebarWrapper className="t--sidebar">
<Switch>
<Route
exact
path={WIDGETS_URL()}
component={WidgetSidebar}
name={"WidgetSidebar"}
/>
<Route component={ExplorerSidebar} name={"ExplorerSidebar"} />
</Switch>
<PanelStack initialPanel={initialPanel} showPanelHeader={false} />
</SidebarWrapper>
);
});

View File

@ -0,0 +1,112 @@
import React from "react";
import { withKnobs, select, boolean, text } from "@storybook/addon-knobs";
import { withDesign } from "storybook-addon-designs";
import Dropdown from "components/ads/Dropdown";
import { action } from "@storybook/addon-actions";
import { IconCollection } from "components/ads/Icon";
import { StoryWrapper } from "./Tabs.stories";
export default {
title: "Dropdown",
component: Dropdown,
decorators: [withKnobs, withDesign],
};
export const Text = () => (
<StoryWrapper>
<Dropdown
options={[
{
id: "111abc",
value: text("1st Option", "First option"),
onSelect: action("selected-option"),
},
{
id: "222abc",
value: text("2nd Option", "Second option"),
onSelect: action("selected-option"),
},
{
id: "322abc",
value: text("3rd Option", "Third option"),
onSelect: action("selected-option"),
},
]}
selected={{
id: select("Selected id", ["111abc", "222abc", "333abc"], "111abc"),
value: text("Selected value", "First option"),
}}
disabled={boolean("disabled", false)}
></Dropdown>
</StoryWrapper>
);
export const IconAndText = () => (
<StoryWrapper>
<Dropdown
options={[
{
id: "111abc",
value: text("1st Option", "Delete"),
icon: select("1st Icon", IconCollection, "delete"),
onSelect: action("selected-option"),
},
{
id: "222abc",
value: text("2nd Option", "User"),
icon: select("2nd Icon", IconCollection, "user"),
onSelect: action("selected-option"),
},
{
id: "322abc",
value: text("3rd Option", "General"),
icon: select("3rd Icon", IconCollection, "general"),
onSelect: action("selected-option"),
},
]}
selected={{
id: select("Selected id", ["111abc", "222abc", "333abc"], "111abc"),
value: text("Selected value", "Delete"),
}}
disabled={boolean("disabled", false)}
></Dropdown>
</StoryWrapper>
);
export const LabelAndText = () => (
<StoryWrapper>
<Dropdown
options={[
{
id: "111abc",
value: text("1st Option", "Admin"),
label: text(
"1st label",
"Can edit, view and invite other user to an app",
),
onSelect: action("selected-option"),
},
{
id: "222abc",
value: text("2nd Option", "Developer"),
label: text("2nd label", "Can view and invite other user to an app"),
onSelect: action("selected-option"),
},
{
id: "322abc",
value: text("3rd Option", "User"),
label: text(
"3rd label",
"Can view and invite other user to an app and…",
),
onSelect: action("selected-option"),
},
]}
selected={{
id: select("Selected id", ["111abc", "222abc", "333abc"], "111abc"),
value: text("Selected value", "Developer"),
}}
disabled={boolean("disabled", false)}
></Dropdown>
</StoryWrapper>
);

View File

@ -645,7 +645,7 @@ export const theme: Theme = {
},
],
sidebarWidth: "320px",
headerHeight: "50px",
headerHeight: "48px",
canvasPadding: "20px 0 200px 0",
sideNav: {
maxWidth: 220,

View File

@ -1,2 +1,2 @@
export const ENTITY_EXPLORER_SEARCH_ID = "entity-explorer-search";
export const ENTITY_EXPLORER_SEARCH_LOCATION_HASH = "#search";
export const WIDGETS_SEARCH_ID = "#widgets-search";

View File

@ -157,3 +157,7 @@ export const SHOW_REQUEST = "Show Request";
export const TABLE_FILTER_COLUMN_TYPE_CALLOUT =
"Change column datatype to see filter operators";
export const WIDGET_SIDEBAR_TITLE = "Widgets";
export const WIDGET_SIDEBAR_CAPTION =
"To add a widget, please drag and drop a widget on the canvas to the right";

View File

@ -50,19 +50,6 @@ export const BUILDER_PAGE_URL = (
);
};
export const WIDGETS_URL = (
applicationId = ":applicationId",
pageId = ":pageId",
params?: Record<string, string>,
): string => {
if (!pageId) return APPLICATIONS_URL;
const queryParams = convertToQueryParams(params);
return (
`${BUILDER_BASE_URL(applicationId)}/pages/${pageId}/edit/widgets` +
queryParams
);
};
export const API_EDITOR_URL = (
applicationId = ":applicationId",
pageId = ":pageId",

View File

@ -5,6 +5,8 @@ import history from "utils/history";
import { saveActionName } from "actions/actionActions";
import EntityProperties from "../Entity/EntityProperties";
import { ENTITY_TYPE } from "entities/DataTree/dataTreeFactory";
import { ExplorerURLParams } from "../helpers";
import { useParams } from "react-router";
const getUpdateActionNameReduxAction = (id: string, name: string) => {
return saveActionName({ id, name });
@ -21,6 +23,7 @@ type ExplorerActionEntityProps = {
};
export const ExplorerActionEntity = memo((props: ExplorerActionEntityProps) => {
const { pageId } = useParams<ExplorerURLParams>();
const switchToAction = useCallback(() => {
props.url && history.push(props.url);
}, [props.url]);
@ -51,7 +54,9 @@ export const ExplorerActionEntity = memo((props: ExplorerActionEntityProps) => {
<EntityProperties
entityName={props.action.config.name}
entityType={ENTITY_TYPE.ACTION}
isCurrentPage={props.pageId === pageId}
step={props.step + 1}
entity={props.action}
/>
</Entity>
);

View File

@ -71,7 +71,7 @@ export const ExplorerActionsGroup = memo((props: ExplorerActionsGroupProps) => {
entityId={props.page.pageId + "_" + props.config?.type}
step={props.step}
disabled={!!props.searchKeyword && (!childNode || !props.actions.length)}
createFn={switchToCreateActionPage}
onCreate={switchToCreateActionPage}
isDefaultExpanded={
props.config?.isGroupExpanded(params, props.page.pageId) ||
!!props.searchKeyword

View File

@ -7,7 +7,7 @@ import { ExplorerURLParams, getDatasourceIdFromURL } from "../helpers";
import Entity, { EntityClassNames } from "../Entity";
import { DATA_SOURCES_EDITOR_ID_URL } from "constants/routes";
import history from "utils/history";
import { updateDatasource } from "actions/datasourceActions";
import { saveDatasourceName } from "actions/datasourceActions";
type ExplorerDatasourceEntityProps = {
datasource: Datasource;
@ -32,12 +32,9 @@ export const ExplorerDatasourceEntity = (
const datasourceIdFromURL = getDatasourceIdFromURL();
const active = datasourceIdFromURL === props.datasource.id;
const updateDatasourceName = useCallback(
(id: string, name: string) => {
return updateDatasource({ ...props.datasource, name: name }, active);
},
[props.datasource, active],
);
const updateDatasourceName = (id: string, name: string) =>
saveDatasourceName({ id, name });
return (
<Entity
entityId={props.datasource.id}

View File

@ -66,7 +66,7 @@ export const ExplorerDatasourcesGroup = (
) > -1 || !!props.searchKeyword
}
disabled={disableDatasourceGroup}
createFn={() => {
onCreate={() => {
history.push(
DATA_SOURCES_EDITOR_URL(params.applicationId, params.pageId),
);

View File

@ -14,11 +14,19 @@ import { evaluateDataTreeWithoutFunctions } from "selectors/dataTreeSelectors";
export const EntityProperties = (props: {
entityType: ENTITY_TYPE;
entityName: string;
isCurrentPage: boolean;
step: number;
entity?: any;
}) => {
let entity: any;
const dataTree: DataTree = useSelector(evaluateDataTreeWithoutFunctions);
const entity: any = dataTree[props.entityName];
if (!entity) return null;
if (props.isCurrentPage && dataTree[props.entityName]) {
entity = dataTree[props.entityName];
} else if (props.entity) {
entity = props.entity;
} else {
return null;
}
let config: any;
let entityProperties: Array<EntityPropertyProps> = [];
@ -42,7 +50,7 @@ export const EntityProperties = (props: {
}
return {
propertyName: actionProperty,
entityName: entity.name,
entityName: props.entityName,
value,
step: props.step,
};

View File

@ -82,13 +82,13 @@ export type EntityProps = {
action?: () => void;
active?: boolean;
isDefaultExpanded?: boolean;
createFn?: () => void;
onCreate?: () => void;
contextMenu?: ReactNode;
searchKeyword?: string;
step: number;
updateEntityName?: (id: string, name: string) => any;
runActionOnExpand?: boolean;
nameTransformFn?: (input: string, limit?: number) => string;
onNameEdit?: (input: string, limit?: number) => string;
};
export const Entity = forwardRef(
@ -155,13 +155,13 @@ export const Entity = forwardRef(
className={`${EntityClassNames.NAME}`}
ref={itemRef}
name={props.name}
nameTransformFn={props.nameTransformFn}
nameTransformFn={props.onNameEdit}
isEditing={!!props.updateEntityName && isEditing}
updateEntityName={updateNameCallback}
searchKeyword={props.searchKeyword}
/>
<AddButton
onClick={props.createFn}
onClick={props.onCreate}
className={`${EntityClassNames.ADD_BUTTON}`}
/>
{props.contextMenu}

View File

@ -63,15 +63,19 @@ const Underline = styled.div`
`;
/*eslint-disable react/display-name */
export const ExplorerSearch = forwardRef(
(props: { clear: () => void }, ref: Ref<HTMLInputElement>) => {
(
props: { clear: () => void; placeholder?: string },
ref: Ref<HTMLInputElement>,
) => {
return (
<ExplorerSearchWrapper>
<Icon icon="search" iconSize={12} />
<input
id={ENTITY_EXPLORER_SEARCH_ID}
type="text"
placeholder="Search entities..."
placeholder={props.placeholder || "Search entities..."}
ref={ref}
autoComplete="off"
/>
<Icon icon="cross" iconSize={12} onClick={props.clear} />
<Underline className="underline" />

View File

@ -22,6 +22,7 @@ type ExplorerPageEntityProps = {
actions: any[];
step: number;
searchKeyword?: string;
showWidgetsSidebar: () => void;
};
export const ExplorerPageEntity = (props: ExplorerPageEntityProps) => {
const params = useParams<ExplorerURLParams>();
@ -50,6 +51,9 @@ export const ExplorerPageEntity = (props: ExplorerPageEntityProps) => {
const icon = props.page.isDefault ? homePageIcon : pageIcon;
let addWidgetsFn;
if (isCurrentPage) addWidgetsFn = props.showWidgetsSidebar;
return (
<Entity
icon={icon}
@ -62,13 +66,14 @@ export const ExplorerPageEntity = (props: ExplorerPageEntityProps) => {
isDefaultExpanded={isCurrentPage || !!props.searchKeyword}
updateEntityName={updatePage}
contextMenu={contextMenu}
nameTransformFn={resolveAsSpaceChar}
onNameEdit={resolveAsSpaceChar}
>
<ExplorerWidgetGroup
step={props.step + 1}
searchKeyword={props.searchKeyword}
widgets={props.widgets}
pageId={props.page.pageId}
addWidgetsFn={addWidgetsFn}
/>
{getActionGroups(

View File

@ -17,6 +17,7 @@ type ExplorerPageGroupProps = {
step: number;
widgets?: Record<string, WidgetProps>;
actions: Record<string, any[]>;
showWidgetsSidebar: () => void;
};
export const ExplorerPageGroup = (props: ExplorerPageGroupProps) => {
@ -46,6 +47,7 @@ export const ExplorerPageGroup = (props: ExplorerPageGroupProps) => {
actions={pageActions}
searchKeyword={props.searchKeyword}
page={page}
showWidgetsSidebar={props.showWidgetsSidebar}
/>
);
});
@ -61,7 +63,7 @@ export const ExplorerPageGroup = (props: ExplorerPageGroupProps) => {
action={noop}
entityId="Pages"
step={props.step}
createFn={createPageCallback}
onCreate={createPageCallback}
>
{pageEntities}
</Entity>

View File

@ -122,7 +122,8 @@ export type WidgetEntityProps = {
};
export const WidgetEntity = memo((props: WidgetEntityProps) => {
const params = useParams<ExplorerURLParams>();
const { pageId } = useParams<ExplorerURLParams>();
const { navigateToWidget, isWidgetSelected } = useWidget(
props.widgetProps.widgetId,
props.widgetProps.type,
@ -139,7 +140,9 @@ export const WidgetEntity = memo((props: WidgetEntityProps) => {
<EntityProperties
entityType={ENTITY_TYPE.WIDGET}
entityName={props.widgetProps.widgetName}
isCurrentPage={pageId === props.pageId}
step={props.step + 1}
entity={props.widgetProps}
/>
);
}
@ -162,15 +165,13 @@ export const WidgetEntity = memo((props: WidgetEntityProps) => {
active={isWidgetSelected}
entityId={props.widgetProps.widgetId}
step={props.step}
updateEntityName={
props.pageId === params?.pageId ? updateWidgetName : noop
}
updateEntityName={props.pageId === pageId ? updateWidgetName : noop}
searchKeyword={props.searchKeyword}
isDefaultExpanded={
(!!props.searchKeyword && !!props.widgetProps.children) ||
!!props.isDefaultExpanded
}
contextMenu={props.pageId === params?.pageId && contextMenu}
contextMenu={props.pageId === pageId && contextMenu}
>
{children}
</Entity>

View File

@ -10,7 +10,7 @@ import {
} from "constants/WidgetConstants";
import { useParams } from "react-router";
import { ExplorerURLParams } from "../helpers";
import { BUILDER_PAGE_URL, WIDGETS_URL } from "constants/routes";
import { BUILDER_PAGE_URL } from "constants/routes";
import { Link } from "react-router-dom";
import styled from "styled-components";
import { AppState } from "reducers";
@ -108,6 +108,7 @@ type ExplorerWidgetGroupProps = {
step: number;
widgets?: WidgetTree;
searchKeyword?: string;
addWidgetsFn?: () => void;
};
const StyledLink = styled(Link)`
@ -155,13 +156,8 @@ export const ExplorerWidgetGroup = memo((props: ExplorerWidgetGroupProps) => {
) : (
" "
)}
click the{" "}
<React.Fragment>
<StyledLink to={WIDGETS_URL(params.applicationId, props.pageId)}>
Widgets
</StyledLink>
</React.Fragment>{" "}
navigation menu icon on the left to drag and drop widgets
click the <strong>+</strong> icon on the <strong>Widgets</strong> group
to drag and drop widgets
</EntityPlaceholder>
);
} else if (!childNode && props.searchKeyword) return null;
@ -170,7 +166,7 @@ export const ExplorerWidgetGroup = memo((props: ExplorerWidgetGroupProps) => {
<Entity
key={props.pageId + "_widgets"}
icon={widgetIcon}
className="group widgets"
className={`group widgets ${props.addWidgetsFn ? "current" : ""}`}
step={props.step}
name="Widgets"
disabled={!props.widgets && !!props.searchKeyword}
@ -179,6 +175,7 @@ export const ExplorerWidgetGroup = memo((props: ExplorerWidgetGroupProps) => {
!!props.searchKeyword ||
(params.pageId === props.pageId && !!selectedWidget)
}
onCreate={props.addWidgetsFn}
>
{childNode}
</Entity>

View File

@ -1,4 +1,4 @@
import React, { useRef, MutableRefObject } from "react";
import React, { useRef, MutableRefObject, useCallback } from "react";
import styled from "styled-components";
import Divider from "components/editorComponents/Divider";
import {
@ -11,8 +11,12 @@ import Search from "./ExplorerSearch";
import ExplorerPageGroup from "./Pages/PageGroup";
import ExplorerDatasourcesGroup from "./Datasources/DatasourcesGroup";
import { scrollbarDark } from "constants/DefaultTheme";
import { NonIdealState, Classes } from "@blueprintjs/core";
import { NonIdealState, Classes, IPanelProps } from "@blueprintjs/core";
import WidgetSidebar from "../WidgetSidebar";
import { BUILDER_PAGE_URL } from "constants/routes";
import history from "utils/history";
import { useParams } from "react-router";
import { ExplorerURLParams } from "./helpers";
const Wrapper = styled.div`
height: 100%;
overflow-y: scroll;
@ -29,7 +33,8 @@ const StyledDivider = styled(Divider)`
border-bottom-color: rgba(255, 255, 255, 0.1);
`;
const EntityExplorer = () => {
const EntityExplorer = (props: IPanelProps) => {
const { applicationId, pageId } = useParams<ExplorerURLParams>();
const searchInputRef: MutableRefObject<HTMLInputElement | null> = useRef(
null,
);
@ -51,6 +56,11 @@ const EntityExplorer = () => {
const noDatasource = !datasources || datasources.length === 0;
noResults = noWidgets && noActions && noDatasource;
}
const { openPanel } = props;
const showWidgetsSidebar = useCallback(() => {
history.push(BUILDER_PAGE_URL(applicationId, pageId));
openPanel({ component: WidgetSidebar });
}, [openPanel, applicationId, pageId]);
return (
<Wrapper ref={explorerRef}>
@ -60,6 +70,7 @@ const EntityExplorer = () => {
step={0}
widgets={widgets}
actions={actions}
showWidgetsSidebar={showWidgetsSidebar}
/>
{noResults && (
<NoResult

View File

@ -1,8 +1,8 @@
import React from "react";
import EditorsRouter from "./routes";
import Navbar from "./Navbar";
import WidgetsEditor from "./WidgetsEditor";
import styled from "styled-components";
import Sidebar from "components/editorComponents/Sidebar";
const Container = styled.div`
display: flex;
@ -17,7 +17,7 @@ const EditorContainer = styled.div`
const MainContainer = () => {
return (
<Container>
<Navbar />
<Sidebar />
<EditorContainer>
<EditorsRouter />
<WidgetsEditor />

View File

@ -1,85 +0,0 @@
import React from "react";
import { useParams } from "react-router-dom";
import styled from "styled-components";
import SidebarComponent from "components/editorComponents/Sidebar";
import NavBarItem from "components/editorComponents/NavBarItem";
import {
BuilderRouteParams,
BUILDER_PAGE_URL,
WIDGETS_URL,
} from "constants/routes";
import { Colors } from "constants/Colors";
import { MenuIcons } from "icons/MenuIcons";
const Wrapper = styled.div`
display: grid;
grid-template-columns: 1fr 5fr;
width: ${props => props.theme.sidebarWidth};
box-shadow: 0px 1px 3px ${Colors.MINE_SHAFT};
background-color: ${Colors.MINE_SHAFT};
z-index: 3;
`;
const NavBar = styled.div`
background-color: ${Colors.MINE_SHAFT};
color: ${props => props.theme.colors.textOnDarkBG};
display: flex;
flex-direction: column;
box-shadow: 0px 0px 4px ${Colors.CODE_GRAY};
`;
const Navbar = () => {
const params = useParams<BuilderRouteParams>();
return (
<Wrapper>
<NavBar>
<NavBarItem
icon={MenuIcons.EXPLORER_ICON}
path={BUILDER_PAGE_URL(params.applicationId, params.pageId)}
width={16}
height={16}
className="t--nav-link-entity-explorer"
title="Explorer"
isActive={(expected: string, current: string) => {
// Currently, the explorer shows on all paths except for the
// WIDGETS_URL path
// get the applicationId and pageId from the current location pathname
const found = current.match(
/^\/applications\/(?<applicationId>\w+)\/pages\/(?<pageId>\w+)\//,
);
// In this case: expected = BUILDER_PAGE_URL(applicationId, pageId)
// If current url begins with expected url AND
// If the current url isn't the WIDGETS_URL THEN
// this is an explorer sidebar path
return (
current.indexOf(expected) === 0 &&
current !==
WIDGETS_URL(found?.groups?.applicationId, found?.groups?.pageId)
);
}}
/>
<NavBarItem
icon={MenuIcons.WIDGETS_ICON}
path={WIDGETS_URL(params.applicationId, params.pageId)}
width={16}
height={16}
className="t--nav-link-widgets-editor"
title="Widgets"
exact
isActive={(expected: string, current: string) => expected === current}
/>
</NavBar>
<SidebarComponent />
</Wrapper>
);
};
Navbar.displayName = "Navbar";
Navbar.whyDidYouRender = {
logOnDifferentValues: false,
customName: "MainSidebar",
};
export default Navbar;

View File

@ -1,14 +1,16 @@
import React from "react";
import React, { useRef, useEffect, useState } from "react";
import { useSelector } from "react-redux";
import WidgetCard from "./WidgetCard";
import styled from "styled-components";
import { WidgetCardProps } from "widgets/BaseWidget";
import { getWidgetCards } from "selectors/editorSelectors";
import { getColorWithOpacity } from "constants/DefaultTheme";
type WidgetSidebarProps = {
cards: { [id: string]: WidgetCardProps[] };
};
import { IPanelProps, Icon, Classes } from "@blueprintjs/core";
import { Colors } from "constants/Colors";
import ExplorerSearch from "./Explorer/ExplorerSearch";
import { debounce } from "lodash";
import produce from "immer";
import { WIDGET_SIDEBAR_CAPTION } from "constants/messages";
const MainWrapper = styled.div`
text-transform: capitalize;
@ -43,22 +45,108 @@ const CardsWrapper = styled.div`
align-items: stretch;
`;
const WidgetSidebar = () => {
const CloseIcon = styled(Icon)`
&&.${Classes.ICON} {
cursor: pointer;
display: flex;
justify-content: center;
opacity: 0.6;
&:hover {
opacity: 1;
}
}
`;
const Header = styled.div`
display: grid;
grid-template-columns: 7fr 1fr;
`;
const Info = styled.div`
display: flex;
flex-direction: column;
justify-content: center;
align-items: space-around;
text-transform: none;
h4 {
margin-top: 0px;
}
p {
opacity: 0.6;
}
`;
const WidgetSidebar = (props: IPanelProps) => {
const cards = useSelector(getWidgetCards);
const groups = Object.keys(cards);
const [filteredCards, setFilteredCards] = useState(cards);
const searchInputRef = useRef<HTMLInputElement | null>(null);
const clearSearchInput = () => {
if (searchInputRef.current) searchInputRef.current.value = "";
};
const search = debounce((e: any) => {
const keyword = e.target.value.toLowerCase();
let filteredCards = cards;
if (keyword.trim().length > 0) {
filteredCards = produce(cards, draft => {
for (const [key, value] of Object.entries(cards)) {
value.forEach((card, index) => {
if (card.widgetCardName.toLowerCase().indexOf(keyword) === -1) {
delete draft[key][index];
}
});
draft[key] = draft[key].filter(Boolean);
if (draft[key].length === 0) {
delete draft[key];
}
}
});
}
setFilteredCards(filteredCards);
}, 300);
useEffect(() => {
const el: HTMLInputElement | null = searchInputRef.current;
el?.addEventListener("keydown", search);
el?.addEventListener("cleared", search);
return () => {
el?.removeEventListener("keydown", search);
el?.removeEventListener("cleared", search);
};
}, [searchInputRef, search]);
const groups = Object.keys(filteredCards);
return (
<MainWrapper>
{groups.map((group: string) => (
<React.Fragment key={group}>
<h5>{group}</h5>
<CardsWrapper>
{cards[group].map((card: WidgetCardProps) => (
<WidgetCard details={card} key={card.key} />
))}
</CardsWrapper>
</React.Fragment>
))}
</MainWrapper>
<>
<ExplorerSearch
ref={searchInputRef}
clear={clearSearchInput}
placeholder="Search widgets..."
/>
<MainWrapper>
<Header>
<Info>
<p>{WIDGET_SIDEBAR_CAPTION}</p>
</Info>
<CloseIcon
className="t--close-widgets-sidebar"
icon="cross"
iconSize={16}
color={Colors.WHITE}
onClick={props.closePanel}
/>
</Header>
{groups.map((group: string) => (
<React.Fragment key={group}>
<h5>{group}</h5>
<CardsWrapper>
{filteredCards[group].map((card: WidgetCardProps) => (
<WidgetCard details={card} key={card.key} />
))}
</CardsWrapper>
</React.Fragment>
))}
</MainWrapper>
</>
);
};

View File

@ -5,7 +5,6 @@ import { withRouter, RouteComponentProps } from "react-router-dom";
import {
BuilderRouteParams,
getApplicationViewerPageURL,
BUILDER_PAGE_URL,
} from "constants/routes";
import { AppState } from "reducers";
import MainContainer from "./MainContainer";
@ -32,9 +31,8 @@ import { initEditor } from "actions/initActions";
import { editorInitializer } from "utils/EditorUtils";
import {
ENTITY_EXPLORER_SEARCH_ID,
ENTITY_EXPLORER_SEARCH_LOCATION_HASH,
WIDGETS_SEARCH_ID,
} from "constants/Explorer";
import history from "utils/history";
import CenteredWrapper from "components/designSystems/appsmith/CenteredWrapper";
import { getAppsmithConfigs } from "configs";
import { getCurrentUser } from "selectors/usersSelectors";
@ -66,19 +64,14 @@ class Editor extends Component<Props> {
combo="meta + f"
label="Search entities"
onKeyDown={(e: any) => {
//TODO(abhinav): make this id into a constant.
const el = document.getElementById(ENTITY_EXPLORER_SEARCH_ID);
if (!el) {
history.push(
`${BUILDER_PAGE_URL(
this.props.currentApplicationId,
this.props.currentPageId,
)}${ENTITY_EXPLORER_SEARCH_LOCATION_HASH}`,
);
} else {
el?.focus();
}
const entitySearchInput = document.getElementById(
ENTITY_EXPLORER_SEARCH_ID,
);
const widgetSearchInput = document.getElementById(
WIDGETS_SEARCH_ID,
);
if (entitySearchInput) entitySearchInput.focus();
if (widgetSearchInput) widgetSearchInput.focus();
e.preventDefault();
e.stopPropagation();
}}

View File

@ -19,7 +19,6 @@ import {
getCurlImportPageURL,
API_EDITOR_URL_WITH_SELECTED_PAGE_ID,
getProviderTemplatesURL,
WIDGETS_URL,
} from "constants/routes";
import styled from "styled-components";
import AppRoute from "pages/common/AppRoute";
@ -63,8 +62,7 @@ class EditorsRouter extends React.Component<
this.state = {
isVisible:
this.props.location.pathname !==
BUILDER_PAGE_URL(applicationId, pageId) &&
this.props.location.pathname !== WIDGETS_URL(applicationId, pageId),
BUILDER_PAGE_URL(applicationId, pageId),
};
}
@ -74,8 +72,7 @@ class EditorsRouter extends React.Component<
this.setState({
isVisible:
this.props.location.pathname !==
BUILDER_PAGE_URL(applicationId, pageId) &&
this.props.location.pathname !== WIDGETS_URL(applicationId, pageId),
BUILDER_PAGE_URL(applicationId, pageId),
});
}
}

View File

@ -155,14 +155,9 @@ export function* deleteDatasourceSaga(
}
}
function* updateDatasourceSaga(
actionPayload: ReduxAction<{
datasource: Datasource;
reinitializeForm: boolean;
}>,
) {
function* updateDatasourceSaga(actionPayload: ReduxAction<Datasource>) {
try {
const datasourcePayload = _.omit(actionPayload.payload.datasource, "name");
const datasourcePayload = _.omit(actionPayload.payload, "name");
const response: GenericApiResponse<Datasource> = yield DatasourcesApi.updateDatasource(
datasourcePayload,
@ -184,9 +179,6 @@ function* updateDatasourceSaga(
id: response.data.id,
},
});
if (actionPayload.payload.reinitializeForm) {
yield put(initialize(DATASOURCE_DB_FORM, datasourcePayload));
}
}
} catch (error) {
yield put({