Merge branch 'release' of https://github.com/appsmithorg/appsmith into release
|
|
@ -37,6 +37,9 @@ Do all this **without HTML/CSS**, and writing any custom integrations.
|
|||
|
||||
* [Customer Support Dashboard](https://app.appsmith.com/applications/5f2aeb2580ca1f6faaed4e4a/pages/5f2d61b580ca1f6faaed4e79#utm_source=github&utm_medium=homepage)
|
||||
|
||||
## Build & Deploy
|
||||
|
||||
* [Docker](https://docs.appsmith.com/quick-start#docker)
|
||||
|
||||
## Why Appsmith?
|
||||
|
||||
|
|
@ -55,10 +58,6 @@ Appsmith provides a better way of building internal tools by visualising them as
|
|||
* **Fine-grained access control**: Control who can edit / view your applications from a single control panel
|
||||
* **App management**: Build and organise multiple applications on a single platform
|
||||
|
||||
## Build & Deploy
|
||||
|
||||
* [Docker](https://docs.appsmith.com/quick-start#docker)
|
||||
|
||||
## Documentation & Support
|
||||
|
||||
If you have encountered a bug or need to get in touch with us, you can contact us using one of the following channels:
|
||||
|
|
|
|||
|
|
@ -171,13 +171,11 @@ describe("API Panel Test Functionality", function() {
|
|||
it("API check with Invalid Header", function() {
|
||||
cy.CreateAPI("FourthAPI");
|
||||
cy.log("Creation of API Action successful");
|
||||
cy.EnterSourceDetailsWithQueryParam(
|
||||
cy.EnterSourceDetailsWithHeader(
|
||||
testdata.baseUrl,
|
||||
testdata.methods,
|
||||
testdata.headerKey,
|
||||
testdata.invalidValue,
|
||||
testdata.queryKey,
|
||||
testdata.queryValue,
|
||||
);
|
||||
cy.WaitAutoSave();
|
||||
cy.RunAPI();
|
||||
|
|
|
|||
|
|
@ -12,13 +12,10 @@ describe("API Panel Test Functionality", function() {
|
|||
cy.SaveAndRunAPI();
|
||||
cy.validateRequest(testdata.baseUrl, testdata.methods, testdata.Get);
|
||||
cy.ResponseStatusCheck(testdata.successStatusCode);
|
||||
cy.get(apiwidget.createApiOnSideBar)
|
||||
.first()
|
||||
.click({ force: true });
|
||||
cy.SearchAPIandClick("FirstAPI");
|
||||
cy.SearchEntityandOpen("FirstAPI");
|
||||
cy.EditApiName("SecondAPI");
|
||||
cy.ClearSearch();
|
||||
cy.SearchAPIandClick("SecondAPI");
|
||||
cy.SearchEntityandOpen("SecondAPI");
|
||||
cy.DeleteAPI();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -2,15 +2,19 @@ const commonlocators = require("../../../locators/commonlocators.json");
|
|||
const dsl = require("../../../fixtures/commondsl.json");
|
||||
const widgetsPage = require("../../../locators/Widgets.json");
|
||||
const testdata = require("../../../fixtures/testdata.json");
|
||||
const pages = require("../../../locators/Pages.json");
|
||||
|
||||
describe("Moustache test Functionality", function() {
|
||||
beforeEach(() => {
|
||||
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");
|
||||
|
|
|
|||
|
|
@ -8,9 +8,10 @@ describe("API Panel Test Functionality ", function() {
|
|||
cy.CreateAPI("FirstAPI");
|
||||
cy.RunAPI();
|
||||
cy.log("Creation of FirstAPI Action successful");
|
||||
cy.NavigateToAPI_Panel();
|
||||
cy.CreateAPI("SecondAPI");
|
||||
cy.RunAPI();
|
||||
cy.log("Creation of SecondAPI Action successful");
|
||||
cy.SearchAPI("SecondAPI", "FirstAPI");
|
||||
cy.SearchEntity("SecondAPI", "FirstAPI");
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,17 +1,20 @@
|
|||
const commonlocators = require("../../../locators/commonlocators.json");
|
||||
|
||||
describe("API Panel Test Functionality ", function() {
|
||||
it("Test API copy/Move/delete feature", function() {
|
||||
cy.log("Login Successful");
|
||||
cy.NavigateToAPI_Panel();
|
||||
cy.log("Navigation to API Panel screen successful");
|
||||
|
||||
cy.CreateAPI("FirstAPI");
|
||||
cy.log("Creation of FirstAPI Action successful");
|
||||
|
||||
cy.CopyAPIToHome("FirstAPI");
|
||||
cy.DeleteAPI("FirstAPI");
|
||||
//cy.MoveAPIToPage();
|
||||
cy.CreateAPI("SecondApi");
|
||||
cy.log("Creation of FirstAPI Action successful");
|
||||
cy.CreationOfUniqueAPIcheck("SecondApi");
|
||||
cy.GlobalSearchEntity("FirstAPI");
|
||||
cy.xpath('//*[local-name()="g" and @id="Icon/Outline/more-vertical"]')
|
||||
.last()
|
||||
.should("be.hidden")
|
||||
.invoke("show")
|
||||
.click({ force: true });
|
||||
cy.CopyAPIToHome();
|
||||
cy.GlobalSearchEntity("FirstAPICopy");
|
||||
cy.DeleteAPIFromSideBar();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ const commonlocators = require("../../../locators/commonlocators.json");
|
|||
const formWidgetsPage = require("../../../locators/FormWidgets.json");
|
||||
const dsl = require("../../../fixtures/uiBindDsl.json");
|
||||
const publishPage = require("../../../locators/publishWidgetspage.json");
|
||||
const pages = require("../../../locators/Pages.json");
|
||||
|
||||
describe("Binding the Datepicker and Text Widget", function() {
|
||||
let nextDay;
|
||||
|
|
@ -15,6 +16,7 @@ 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();
|
||||
|
|
@ -48,6 +50,7 @@ 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");
|
||||
|
||||
/**
|
||||
|
|
@ -105,6 +108,7 @@ 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",
|
||||
|
|
|
|||
|
|
@ -16,12 +16,13 @@ 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.pagesIcon).click({ force: true });
|
||||
cy.get(pages.widgetsEditor).click();
|
||||
cy.openPropertyPane("tablewidget");
|
||||
/**Bind Api1 with Table widget */
|
||||
cy.testJsontext("tabledata", "{{Api1.data.results}}");
|
||||
cy.CheckWidgetProperties(commonlocators.serverSidePaginationCheckbox);
|
||||
/**Bind Table with Textwidget with selected row */
|
||||
cy.get(pages.widgetsEditor).click();
|
||||
cy.openPropertyPane("textwidget");
|
||||
cy.testJsontext("text", "{{Table1.selectedRow.url}}");
|
||||
cy.readTabledata("0", "1").then(tabData => {
|
||||
|
|
@ -65,12 +66,12 @@ describe("Test Create Api and Bind to Table widget", function() {
|
|||
parseSpecialCharSequences: false,
|
||||
});
|
||||
cy.WaitAutoSave();
|
||||
|
||||
cy.get(pages.pagesIcon).click({ force: true });
|
||||
cy.get(pages.widgetsEditor).click();
|
||||
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.testJsontext("tabledata", "{{Api2.data.results}}");
|
||||
cy.callApi("Api2");
|
||||
|
|
|
|||
|
|
@ -27,7 +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.pagesIcon).click({ force: true });
|
||||
cy.get(pages.widgetsEditor).click();
|
||||
cy.openPropertyPane("tablewidget");
|
||||
cy.testJsontext("tabledata", "{{Api1.data}}");
|
||||
cy.get(commonlocators.editPropCrossButton).click();
|
||||
|
|
|
|||
|
|
@ -2,12 +2,14 @@ const commonlocators = require("../../../locators/commonlocators.json");
|
|||
const viewWidgetsPage = require("../../../locators/ViewWidgets.json");
|
||||
const publish = require("../../../locators/publishWidgetspage.json");
|
||||
const dsl = require("../../../fixtures/ChartTextDsl.json");
|
||||
const pages = require("../../../locators/Pages.json");
|
||||
|
||||
describe("Text-Chart Binding Functionality", function() {
|
||||
before(() => {
|
||||
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(
|
||||
|
|
@ -15,6 +17,7 @@ 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)
|
||||
|
|
|
|||
|
|
@ -1,12 +1,20 @@
|
|||
const commonlocators = require("../../../locators/commonlocators.json");
|
||||
const publish = require("../../../locators/publishWidgetspage.json");
|
||||
const dsl = require("../../../fixtures/TextTabledsl.json");
|
||||
const pages = require("../../../locators/Pages.json");
|
||||
|
||||
describe("Text-Table Binding Functionality", function() {
|
||||
Cypress.on("uncaught:exception", (err, runnable) => {
|
||||
// returning false here prevents Cypress from
|
||||
// failing the test
|
||||
return false;
|
||||
});
|
||||
|
||||
before(() => {
|
||||
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.
|
||||
|
|
@ -35,6 +43,7 @@ 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}}");
|
||||
|
|
@ -59,6 +68,7 @@ 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)
|
||||
|
|
@ -85,6 +95,7 @@ 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));
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -2,14 +2,19 @@ const commonlocators = require("../../../locators/commonlocators.json");
|
|||
const viewWidgetsPage = require("../../../locators/ViewWidgets.json");
|
||||
const publish = require("../../../locators/publishWidgetspage.json");
|
||||
const dsl = require("../../../fixtures/displayWidgetDsl.json");
|
||||
const pages = require("../../../locators/Pages.json");
|
||||
|
||||
describe("Chart Widget Functionality", function() {
|
||||
before(() => {
|
||||
cy.addDsl(dsl);
|
||||
});
|
||||
it("Chart Widget Functionality", function() {
|
||||
cy.openPropertyPane("chartwidget");
|
||||
|
||||
beforeEach(() => {
|
||||
cy.get(pages.widgetsEditor).click();
|
||||
cy.openPropertyPane("chartwidget");
|
||||
});
|
||||
|
||||
it("Chart Widget Functionality", function() {
|
||||
/**
|
||||
* @param{Text} Random Text
|
||||
* @param{ChartWidget}Mouseover
|
||||
|
|
@ -66,28 +71,24 @@ describe("Chart Widget Functionality", function() {
|
|||
cy.get(commonlocators.editPropCrossButton).click();
|
||||
});
|
||||
it("Chart Widget Functionality To Unchecked Visible Widget", function() {
|
||||
cy.openPropertyPane("chartwidget");
|
||||
cy.togglebarDisable(commonlocators.visibleCheckbox);
|
||||
cy.PublishtheApp();
|
||||
cy.get(publish.chartWidget).should("not.be.visible");
|
||||
cy.get(publish.backToEditor).click();
|
||||
});
|
||||
it("Chart Widget Functionality To Check Visible Widget", function() {
|
||||
cy.openPropertyPane("chartwidget");
|
||||
cy.togglebar(commonlocators.visibleCheckbox);
|
||||
cy.PublishtheApp();
|
||||
cy.get(publish.chartWidget).should("be.visible");
|
||||
cy.get(publish.backToEditor).click();
|
||||
});
|
||||
it("Chart Widget Functionality To Uncheck Horizontal Scroll Visible", function() {
|
||||
cy.openPropertyPane("chartwidget");
|
||||
cy.togglebarDisable(commonlocators.horizontalScroll);
|
||||
cy.PublishtheApp();
|
||||
cy.get(publish.horizontalTab).should("not.visible");
|
||||
cy.get(publish.backToEditor).click();
|
||||
});
|
||||
it("Chart Widget Functionality To Check Horizontal Scroll Visible", function() {
|
||||
cy.openPropertyPane("chartwidget");
|
||||
cy.togglebar(commonlocators.horizontalScroll);
|
||||
cy.PublishtheApp();
|
||||
cy.get(publish.horizontalTab)
|
||||
|
|
|
|||
|
|
@ -2,12 +2,15 @@ const commonlocators = require("../../../locators/commonlocators.json");
|
|||
const viewWidgetsPage = require("../../../locators/ViewWidgets.json");
|
||||
const publish = require("../../../locators/publishWidgetspage.json");
|
||||
const dsl = require("../../../fixtures/displayWidgetDsl.json");
|
||||
const pages = require("../../../locators/Pages.json");
|
||||
|
||||
describe("Image Widget Functionality", function() {
|
||||
before(() => {
|
||||
cy.addDsl(dsl);
|
||||
});
|
||||
|
||||
it("Image Widget Functionality", function() {
|
||||
cy.get(pages.widgetsEditor).click();
|
||||
cy.openPropertyPane("imagewidget");
|
||||
/**
|
||||
* @param{Text} Random Text
|
||||
|
|
@ -40,6 +43,7 @@ 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();
|
||||
|
|
@ -47,6 +51,7 @@ 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();
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ const widgetsPage = require("../../../locators/Widgets.json");
|
|||
const commonlocators = require("../../../locators/commonlocators.json");
|
||||
const publish = require("../../../locators/publishWidgetspage.json");
|
||||
const dsl = require("../../../fixtures/tableWidgetDsl.json");
|
||||
const pages = require("../../../locators/Pages.json");
|
||||
|
||||
describe("Table Widget Functionality", function() {
|
||||
before(() => {
|
||||
|
|
@ -9,6 +10,7 @@ describe("Table Widget Functionality", function() {
|
|||
});
|
||||
|
||||
it("Table Widget Functionality", function() {
|
||||
cy.get(pages.widgetsEditor).click();
|
||||
cy.openPropertyPane("tablewidget");
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ const commonlocators = require("../../../locators/commonlocators.json");
|
|||
const widgetsPage = require("../../../locators/Widgets.json");
|
||||
const publishPage = require("../../../locators/publishWidgetspage.json");
|
||||
const dsl = require("../../../fixtures/displayWidgetDsl.json");
|
||||
const pages = require("../../../locators/Pages.json");
|
||||
|
||||
describe("Text Widget Functionality", function() {
|
||||
before(() => {
|
||||
|
|
@ -9,6 +10,7 @@ describe("Text Widget Functionality", function() {
|
|||
});
|
||||
|
||||
beforeEach(() => {
|
||||
cy.get(pages.widgetsEditor).click();
|
||||
cy.openPropertyPane("textwidget");
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ describe("Dynamic input autocomplete", () => {
|
|||
.focus();
|
||||
cy.assertEvaluatedValuePopup("string");
|
||||
|
||||
cy.NavigateToEntityExplorer();
|
||||
// Test on api pane
|
||||
cy.NavigateToAPI_Panel();
|
||||
cy.get(apiwidget.createapi).click({ force: true });
|
||||
|
|
|
|||
|
|
@ -3,12 +3,14 @@ const formWidgetsPage = require("../../../locators/FormWidgets.json");
|
|||
const widgetsPage = require("../../../locators/Widgets.json");
|
||||
const publish = require("../../../locators/publishWidgetspage.json");
|
||||
const dsl = require("../../../fixtures/newFormDsl.json");
|
||||
const pages = require("../../../locators/Pages.json");
|
||||
|
||||
describe("Checkbox Widget Functionality", function() {
|
||||
before(() => {
|
||||
cy.addDsl(dsl);
|
||||
});
|
||||
it("Checkbox Widget Functionality", function() {
|
||||
cy.get(pages.widgetsEditor).click();
|
||||
cy.openPropertyPane("checkboxwidget");
|
||||
/**
|
||||
* @param{Text} Random Text
|
||||
|
|
@ -43,6 +45,7 @@ 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();
|
||||
|
|
@ -50,6 +53,7 @@ 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();
|
||||
|
|
@ -57,6 +61,7 @@ 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();
|
||||
|
|
@ -64,6 +69,7 @@ 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();
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ const commonlocators = require("../../../locators/commonlocators.json");
|
|||
const formWidgetsPage = require("../../../locators/FormWidgets.json");
|
||||
const dsl = require("../../../fixtures/newFormDsl.json");
|
||||
const publishPage = require("../../../locators/publishWidgetspage.json");
|
||||
const pages = require("../../../locators/Pages.json");
|
||||
|
||||
describe("DatePicker Widget Functionality", function() {
|
||||
before(() => {
|
||||
|
|
@ -9,6 +10,7 @@ describe("DatePicker Widget Functionality", function() {
|
|||
});
|
||||
|
||||
beforeEach(() => {
|
||||
cy.get(pages.widgetsEditor).click();
|
||||
cy.openPropertyPane("datepickerwidget");
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -2,12 +2,14 @@ const commonlocators = require("../../../locators/commonlocators.json");
|
|||
const formWidgetsPage = require("../../../locators/FormWidgets.json");
|
||||
const publish = require("../../../locators/publishWidgetspage.json");
|
||||
const dsl = require("../../../fixtures/newFormDsl.json");
|
||||
const pages = require("../../../locators/Pages.json");
|
||||
|
||||
describe("Dropdown Widget Functionality", function() {
|
||||
before(() => {
|
||||
cy.addDsl(dsl);
|
||||
});
|
||||
it("Dropdown Widget Functionality", function() {
|
||||
cy.get(pages.widgetsEditor).click();
|
||||
cy.openPropertyPane("dropdownwidget");
|
||||
/**
|
||||
* @param{Text} Random Text
|
||||
|
|
@ -46,6 +48,7 @@ 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();
|
||||
|
|
@ -53,6 +56,7 @@ 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();
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
const commonlocators = require("../../../locators/commonlocators.json");
|
||||
const dsl = require("../../../fixtures/newFormDsl.json");
|
||||
const pages = require("../../../locators/Pages.json");
|
||||
|
||||
describe("FilePicker Widget Functionality", function() {
|
||||
beforeEach(() => {
|
||||
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
|
||||
|
|
|
|||
|
|
@ -2,12 +2,14 @@ const commonlocators = require("../../../locators/commonlocators.json");
|
|||
const formWidgetsPage = require("../../../locators/FormWidgets.json");
|
||||
const publish = require("../../../locators/publishWidgetspage.json");
|
||||
const dsl = require("../../../fixtures/formdsl.json");
|
||||
const pages = require("../../../locators/Pages.json");
|
||||
|
||||
describe("Form Widget Functionality", function() {
|
||||
before(() => {
|
||||
cy.addDsl(dsl);
|
||||
});
|
||||
it("Form Widget Functionality", function() {
|
||||
cy.get(pages.widgetsEditor).click();
|
||||
cy.openPropertyPane("formwidget");
|
||||
/**
|
||||
* @param{Text} Random Text
|
||||
|
|
@ -43,6 +45,7 @@ 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();
|
||||
|
|
|
|||
|
|
@ -2,12 +2,14 @@ const commonlocators = require("../../../locators/commonlocators.json");
|
|||
const dsl = require("../../../fixtures/newFormDsl.json");
|
||||
const widgetsPage = require("../../../locators/Widgets.json");
|
||||
const publish = require("../../../locators/publishWidgetspage.json");
|
||||
const pages = require("../../../locators/Pages.json");
|
||||
|
||||
describe("Input Widget Functionality", function() {
|
||||
before(() => {
|
||||
cy.addDsl(dsl);
|
||||
});
|
||||
it("Input Widget Functionality", function() {
|
||||
cy.get(pages.widgetsEditor).click();
|
||||
cy.openPropertyPane("inputwidget");
|
||||
/**
|
||||
* @param{Text} Random Text
|
||||
|
|
@ -63,6 +65,7 @@ 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();
|
||||
|
|
@ -70,6 +73,7 @@ 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();
|
||||
|
|
@ -77,6 +81,7 @@ 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();
|
||||
|
|
@ -84,6 +89,7 @@ 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();
|
||||
|
|
|
|||
|
|
@ -2,11 +2,14 @@ const commonlocators = require("../../../locators/commonlocators.json");
|
|||
const formWidgetsPage = require("../../../locators/FormWidgets.json");
|
||||
const publish = require("../../../locators/publishWidgetspage.json");
|
||||
const dsl = require("../../../fixtures/newFormDsl.json");
|
||||
const pages = require("../../../locators/Pages.json");
|
||||
|
||||
describe("Radio Widget Functionality", function() {
|
||||
before(() => {
|
||||
cy.addDsl(dsl);
|
||||
});
|
||||
it("Radio Widget Functionality", function() {
|
||||
cy.get(pages.widgetsEditor).click();
|
||||
cy.openPropertyPane("radiogroupwidget");
|
||||
/**
|
||||
* @param{Text} Random Text
|
||||
|
|
@ -56,6 +59,7 @@ 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();
|
||||
|
|
@ -63,6 +67,7 @@ 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();
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ const commonlocators = require("../../../locators/commonlocators.json");
|
|||
const formWidgetsPage = require("../../../locators/FormWidgets.json");
|
||||
const dsl = require("../../../fixtures/formdsl1.json");
|
||||
const publishPage = require("../../../locators/publishWidgetspage.json");
|
||||
const pages = require("../../../locators/Pages.json");
|
||||
|
||||
describe("RichTextEditor Widget Functionality", function() {
|
||||
before(() => {
|
||||
|
|
@ -9,6 +10,7 @@ describe("RichTextEditor Widget Functionality", function() {
|
|||
});
|
||||
|
||||
beforeEach(() => {
|
||||
cy.get(pages.widgetsEditor).click();
|
||||
cy.openPropertyPane("richtexteditorwidget");
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -3,12 +3,14 @@ const Layoutpage = require("../../../locators/Layout.json");
|
|||
const widgetsPage = require("../../../locators/Widgets.json");
|
||||
const publish = require("../../../locators/publishWidgetspage.json");
|
||||
const dsl = require("../../../fixtures/layoutdsl.json");
|
||||
const pages = require("../../../locators/Pages.json");
|
||||
|
||||
describe("Tab widget test", function() {
|
||||
before(() => {
|
||||
cy.addDsl(dsl);
|
||||
});
|
||||
it("Tab Widget Functionality Test", function() {
|
||||
cy.get(pages.widgetsEditor).click();
|
||||
cy.openPropertyPane("tabswidget");
|
||||
/**
|
||||
* @param{Text} Random Text
|
||||
|
|
@ -58,6 +60,7 @@ 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();
|
||||
|
|
@ -65,6 +68,7 @@ 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();
|
||||
|
|
|
|||
|
|
@ -33,10 +33,11 @@ describe("Create a query with a mongo datasource, run, save and then delete the
|
|||
cy.runAndDeleteQuery();
|
||||
|
||||
cy.NavigateToDatasourceEditor();
|
||||
cy.get(".t--entity-name:contains(MongoDB)").click();
|
||||
cy.get("@createDatasource").then(httpResponse => {
|
||||
const datasourceId = httpResponse.response.body.data.id;
|
||||
const datasourceName = httpResponse.response.body.data.name;
|
||||
|
||||
cy.get(`[data-cy=${datasourceId}]`).click();
|
||||
cy.get(`.t--entity-name:contains(${datasourceName})`).click();
|
||||
});
|
||||
cy.get(".t--delete-datasource").click();
|
||||
cy.wait("@deleteDatasource").should(
|
||||
|
|
|
|||
|
|
@ -32,11 +32,13 @@ describe("Create a query with a postgres datasource, run, save and then delete t
|
|||
cy.runAndDeleteQuery();
|
||||
|
||||
cy.NavigateToDatasourceEditor();
|
||||
cy.get(".t--entity-name:contains(PostgreSQL)").click();
|
||||
cy.get("@createDatasource").then(httpResponse => {
|
||||
const datasourceId = httpResponse.response.body.data.id;
|
||||
const datasourceName = httpResponse.response.body.data.name;
|
||||
|
||||
cy.get(`[data-cy=${datasourceId}]`).click();
|
||||
cy.get(`.t--entity-name:contains(${datasourceName})`).click();
|
||||
});
|
||||
|
||||
cy.get(".t--delete-datasource").click();
|
||||
cy.wait("@deleteDatasource").should(
|
||||
"have.nested.property",
|
||||
|
|
|
|||
|
|
@ -12,9 +12,7 @@ describe("Login from UI and check the functionality", function() {
|
|||
cy.generateUUID().then(uid => {
|
||||
pageid = uid;
|
||||
cy.Createpage(pageid);
|
||||
cy.NavigateToWidgets(pageid);
|
||||
localStorage.setItem("PageName", pageid);
|
||||
cy.Deletepage(pageid);
|
||||
cy.DeletepageFromSideBar();
|
||||
});
|
||||
cy.wait("@deletePage");
|
||||
cy.get("@deletePage").should("have.property", "status", 200);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"datasourceEditorIcon": ".t--nav-link-datasource-editor",
|
||||
"datasourceEditorIcon": ".t--entity-name:contains('DataSources)",
|
||||
"host": "input[name='datasourceConfiguration.endpoints[0].host']",
|
||||
"port": "input[name='datasourceConfiguration.endpoints[0].port']",
|
||||
"databaseName": "input[name='datasourceConfiguration.authentication.databaseName']",
|
||||
|
|
@ -12,5 +12,6 @@
|
|||
"RESTAPI": ".t--plugin-name:contains('REST API')",
|
||||
"PostgreSQL": ".t--plugin-name:contains('PostgreSQL')",
|
||||
"sectionAuthentication": "[data-cy=section-Authentication]",
|
||||
"sectionSSL": "[data-cy=section-SSL\\ \\(optional\\)]"
|
||||
"sectionSSL": "[data-cy=section-SSL\\ \\(optional\\)]",
|
||||
"addDatasourceEntity": "//div[contains(@class,'t--entity group plugins')]//div[contains(@class,'t--entity-add-btn')]"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,20 @@
|
|||
{
|
||||
"pagesIcon": ".t--nav-link-manage-pages",
|
||||
"pagesIcon": ".t--entity-name:contains('Pages')",
|
||||
"commonWidgets": ".t--page-sidebar-CommonWidgets",
|
||||
"formWidgets": ".t--page-sidebar-FormWidgets",
|
||||
"viewWidgets": ".t--page-sidebar-ViewWidgets",
|
||||
"widgetsEditor": ".t--nav-link-widgets-editor",
|
||||
"AddPage": " .t--add-page-btn",
|
||||
"AddPage": "//div[contains(@class,'t--entity group pages')]//div[contains(@class,'t--entity-add-btn')]",
|
||||
"editInput": "input.bp3-editable-text-input",
|
||||
"Menuaction": ".bp3-overlay-open>.bp3-transition-container",
|
||||
"Delete": ":nth-child(2) > .bp3-menu-item",
|
||||
"apiEditorIcon": ".t--nav-link-api-editor"
|
||||
"apiEditorIcon": ".t--nav-link-api-editor",
|
||||
"addEntityAPI": "//div[contains(@class,'t--entity group apis')]//div[contains(@class,'t--entity-add-btn')]",
|
||||
"entityWidget": ".t--entity-name:contains('Widgets')",
|
||||
"entityTable": ".t--entity-name:contains('Table1')",
|
||||
"entityText": ".t--entity-name:contains('Text1')",
|
||||
"entityExplorer": ".t--nav-link-entity-explorer",
|
||||
"popover": "//div[contains(@class,'t--entity page')]//*[local-name()='g' and @id='Icon/Outline/more-vertical']",
|
||||
"editName": ".single-select >div:contains('Edit Name')",
|
||||
"deletePage": ".single-select >div:contains('Delete')"
|
||||
}
|
||||
|
|
@ -3,5 +3,6 @@
|
|||
"templateMenu": ".t--template-menu",
|
||||
"runQuery": ".t--run-query",
|
||||
"saveQuery": ".t--save-query",
|
||||
"deleteQuery": ".t--delete-query"
|
||||
"deleteQuery": ".t--delete-query",
|
||||
"addQueryEntity": ".//div[contains(@class,'t--entity group queries')]//div[contains(@class,'t--entity-add-btn')]"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@
|
|||
"searchApi": ".t--sidebar input[type=text]",
|
||||
"createapi": ".t--createBlankApiCard",
|
||||
"apiTxt": ".t--action-name-edit-field input",
|
||||
"popover": ".bp3-popover-target >div>svg",
|
||||
"popover": "//*[local-name()='g' and @id='Icon/Outline/more-vertical']",
|
||||
"moveTo": ".single-select >div:contains('Move to')",
|
||||
"copyTo": ".single-select >div:contains('Copy to')",
|
||||
"copyTo": ".single-select >div:contains('Copy to page')",
|
||||
"home": ".single-select >div:contains('Page1')",
|
||||
"delete": ".single-select >div:contains('Delete')",
|
||||
"path": ".t--path >div textarea",
|
||||
|
|
@ -41,5 +41,6 @@
|
|||
"content-Type": "(//span[@class='bp3-tree-node-label']/span)[3]",
|
||||
"requestBody": "(//div[contains(@class,'bp3-collapse-body')]//textarea)[1]",
|
||||
"showrequest": "span:contains('Show Request')",
|
||||
"Responsetab": "//li[text()='Response Body']"
|
||||
"Responsetab": "//li[text()='Response Body']",
|
||||
"deleteAPI": ".t--apiFormDeleteBtn"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,6 +58,8 @@
|
|||
"selectMenuItem": ".bp3-menu li>a>div",
|
||||
"evaluatedType": ".t--CodeEditor-evaluatedValue>pre",
|
||||
"evaluatedCurrentValue": ".t--CodeEditor-evaluatedValue div pre",
|
||||
"entityExplorersearch": "#entity-explorer-search",
|
||||
"entitySearchResult": ".t--entity-name:contains('",
|
||||
"saveStatusContainer": ".t--save-status-container",
|
||||
"saveStatusIsSaving": "t--save-status-is-saving",
|
||||
"saveStatusSuccess": ".t--save-status-success",
|
||||
|
|
|
|||
|
|
@ -234,16 +234,13 @@ Cypress.Commands.add("DeleteApp", appName => {
|
|||
cy.get(homePage.deleteButton).click({ force: true });
|
||||
});
|
||||
|
||||
Cypress.Commands.add("Deletepage", Pagename => {
|
||||
cy.get(pages.pagesIcon).click({ force: true });
|
||||
cy.get(".t--page-sidebar-" + Pagename + "");
|
||||
cy.get(
|
||||
".t--page-sidebar-" +
|
||||
Pagename +
|
||||
">.t--page-sidebar-menu-actions>.bp3-popover-target",
|
||||
).click({ force: true });
|
||||
cy.get(pages.Menuaction).click({ force: true });
|
||||
cy.get(pages.Delete).click({ force: true });
|
||||
Cypress.Commands.add("DeletepageFromSideBar", () => {
|
||||
cy.xpath(pages.popover)
|
||||
.last()
|
||||
.click({ force: true });
|
||||
cy.get(pages.deletePage)
|
||||
.first()
|
||||
.click({ force: true });
|
||||
cy.wait(2000);
|
||||
});
|
||||
|
||||
|
|
@ -281,15 +278,27 @@ Cypress.Commands.add("SearchApp", appname => {
|
|||
// Wait added because after opening the application editor, sometimes it takes a little time.
|
||||
});
|
||||
|
||||
Cypress.Commands.add("SearchAPI", (apiname1, apiname2) => {
|
||||
cy.get("span:contains(".concat(apiname2).concat(")")).should("be.visible");
|
||||
cy.get(apiwidget.searchApi)
|
||||
.click({ force: true })
|
||||
.type(apiname1, { force: true });
|
||||
cy.get("span:contains(".concat(apiname1).concat(")")).should("be.visible");
|
||||
cy.get("span:contains(".concat(apiname2).concat(")")).should(
|
||||
"not.be.visible",
|
||||
);
|
||||
Cypress.Commands.add("SearchEntity", (apiname1, apiname2) => {
|
||||
cy.get(commonlocators.entityExplorersearch).should("be.visible");
|
||||
cy.get("#entity-explorer-search")
|
||||
.clear()
|
||||
.type(apiname1);
|
||||
cy.get(
|
||||
commonlocators.entitySearchResult.concat(apiname1).concat("')"),
|
||||
).should("be.visible");
|
||||
cy.get(
|
||||
commonlocators.entitySearchResult.concat(apiname2).concat("')"),
|
||||
).should("not.be.visible");
|
||||
});
|
||||
|
||||
Cypress.Commands.add("GlobalSearchEntity", apiname1 => {
|
||||
cy.get(commonlocators.entityExplorersearch).should("be.visible");
|
||||
cy.get("#entity-explorer-search")
|
||||
.clear()
|
||||
.type(apiname1);
|
||||
cy.get(
|
||||
commonlocators.entitySearchResult.concat(apiname1).concat("')"),
|
||||
).should("be.visible");
|
||||
});
|
||||
|
||||
Cypress.Commands.add("ResponseStatusCheck", statusCode => {
|
||||
|
|
@ -303,23 +312,27 @@ Cypress.Commands.add("ResponseCheck", textTocheck => {
|
|||
});
|
||||
|
||||
Cypress.Commands.add("NavigateToAPI_Panel", () => {
|
||||
cy.get(pages.apiEditorIcon)
|
||||
cy.xpath(pages.addEntityAPI)
|
||||
.should("be.visible")
|
||||
.click({ force: true });
|
||||
cy.get("#loading").should("not.exist");
|
||||
});
|
||||
|
||||
Cypress.Commands.add("NavigateToEntityExplorer", () => {
|
||||
cy.get(pages.entityExplorer)
|
||||
.should("be.visible")
|
||||
.click({ force: true });
|
||||
cy.get("#loading").should("not.exist");
|
||||
});
|
||||
|
||||
Cypress.Commands.add("CreateAPI", apiname => {
|
||||
cy.get(apiwidget.createApiOnSideBar)
|
||||
.first()
|
||||
.click({ force: true });
|
||||
cy.get(apiwidget.createapi).click({ force: true });
|
||||
cy.wait("@createNewApi");
|
||||
cy.get(apiwidget.resourceUrl).should("be.visible");
|
||||
cy.get(apiwidget.apiTxt).click();
|
||||
cy.get(apiwidget.ApiName).click({ force: true });
|
||||
cy.get(apiwidget.apiTxt)
|
||||
.clear()
|
||||
.type(apiname)
|
||||
.type(apiname, { force: true })
|
||||
.should("have.value", apiname)
|
||||
.blur();
|
||||
cy.WaitAutoSave();
|
||||
|
|
@ -343,10 +356,10 @@ Cypress.Commands.add("CreateSubsequentAPI", apiname => {
|
|||
|
||||
Cypress.Commands.add("EditApiName", apiname => {
|
||||
//cy.wait("@getUser");
|
||||
cy.get(apiwidget.EditApiName).click();
|
||||
cy.get(apiwidget.ApiName).click({ force: true });
|
||||
cy.get(apiwidget.apiTxt)
|
||||
.clear()
|
||||
.type(apiname)
|
||||
.type(apiname, { force: true })
|
||||
.should("have.value", apiname);
|
||||
cy.WaitAutoSave();
|
||||
});
|
||||
|
|
@ -389,16 +402,21 @@ Cypress.Commands.add("SelectAction", action => {
|
|||
});
|
||||
|
||||
Cypress.Commands.add("ClearSearch", () => {
|
||||
cy.get(apiwidget.searchApi).clear();
|
||||
cy.get(commonlocators.entityExplorersearch).should("be.visible");
|
||||
cy.get(commonlocators.entityExplorersearch).clear();
|
||||
});
|
||||
|
||||
Cypress.Commands.add("SearchAPIandClick", apiname1 => {
|
||||
cy.get(apiwidget.searchApi)
|
||||
.click({ force: true })
|
||||
.type(apiname1, { force: true });
|
||||
cy.get(".t--sidebar span:contains(".concat(apiname1).concat(")"))
|
||||
.should("be.visible")
|
||||
.click({ force: true });
|
||||
Cypress.Commands.add("SearchEntityandOpen", apiname1 => {
|
||||
cy.get(commonlocators.entityExplorersearch).should("be.visible");
|
||||
cy.get(commonlocators.entityExplorersearch)
|
||||
.clear()
|
||||
.type(apiname1);
|
||||
cy.get(
|
||||
commonlocators.entitySearchResult.concat(apiname1).concat("')"),
|
||||
).should("be.visible");
|
||||
cy.get(
|
||||
commonlocators.entitySearchResult.concat(apiname1).concat("')"),
|
||||
).click({ force: true });
|
||||
});
|
||||
|
||||
Cypress.Commands.add("enterDatasourceAndPath", (datasource, path) => {
|
||||
|
|
@ -529,16 +547,15 @@ Cypress.Commands.add(
|
|||
);
|
||||
|
||||
Cypress.Commands.add("CreationOfUniqueAPIcheck", apiname => {
|
||||
cy.get(apiwidget.createApiOnSideBar)
|
||||
.first()
|
||||
.click({ force: true });
|
||||
cy.xpath(pages.addEntityAPI).click();
|
||||
cy.get(apiwidget.createapi).click({ force: true });
|
||||
cy.wait("@createNewApi");
|
||||
// cy.wait("@getUser");
|
||||
cy.get(apiwidget.resourceUrl).should("be.visible");
|
||||
cy.get(apiwidget.ApiName).click({ force: true });
|
||||
cy.get(apiwidget.apiTxt)
|
||||
.clear()
|
||||
.type(apiname)
|
||||
.type(apiname, { force: true })
|
||||
.should("have.value", apiname)
|
||||
.focus();
|
||||
cy.get(".bp3-popover-content").should($x => {
|
||||
|
|
@ -561,8 +578,8 @@ Cypress.Commands.add("MoveAPIToHome", apiname => {
|
|||
});
|
||||
|
||||
Cypress.Commands.add("MoveAPIToPage", () => {
|
||||
cy.get(apiwidget.popover)
|
||||
.first()
|
||||
cy.xpath(apiwidget.popover)
|
||||
.last()
|
||||
.click({ force: true });
|
||||
cy.get(apiwidget.moveTo).click({ force: true });
|
||||
cy.get(apiwidget.home).click({ force: true });
|
||||
|
|
@ -573,9 +590,9 @@ Cypress.Commands.add("MoveAPIToPage", () => {
|
|||
);
|
||||
});
|
||||
|
||||
Cypress.Commands.add("CopyAPIToHome", apiname => {
|
||||
cy.get(apiwidget.popover)
|
||||
.first()
|
||||
Cypress.Commands.add("CopyAPIToHome", () => {
|
||||
cy.xpath(apiwidget.popover)
|
||||
.last()
|
||||
.click({ force: true });
|
||||
cy.get(apiwidget.copyTo).click({ force: true });
|
||||
cy.get(apiwidget.home).click({ force: true });
|
||||
|
|
@ -586,11 +603,27 @@ Cypress.Commands.add("CopyAPIToHome", apiname => {
|
|||
);
|
||||
});
|
||||
|
||||
Cypress.Commands.add("DeleteAPI", apiname => {
|
||||
cy.get(apiwidget.popover)
|
||||
.first()
|
||||
Cypress.Commands.add("DeleteAPIFromSideBar", () => {
|
||||
cy.xpath(apiwidget.popover)
|
||||
.last()
|
||||
.click({ force: true });
|
||||
cy.get(apiwidget.delete).click({ force: true });
|
||||
cy.wait("@deleteAction").should(
|
||||
"have.nested.property",
|
||||
"response.body.responseMeta.status",
|
||||
200,
|
||||
);
|
||||
});
|
||||
|
||||
Cypress.Commands.add("DeleteAPI", apiname => {
|
||||
cy.get(apiwidget.deleteAPI)
|
||||
.first()
|
||||
.click({ force: true });
|
||||
cy.wait("@deleteAction").should(
|
||||
"have.nested.property",
|
||||
"response.body.responseMeta.status",
|
||||
200,
|
||||
);
|
||||
});
|
||||
|
||||
Cypress.Commands.add("CreateModal", () => {
|
||||
|
|
@ -800,7 +833,19 @@ Cypress.Commands.add("DeleteModal", () => {
|
|||
|
||||
Cypress.Commands.add("Createpage", Pagename => {
|
||||
cy.get(pages.pagesIcon).click({ force: true });
|
||||
cy.get(pages.AddPage).click();
|
||||
cy.xpath(pages.AddPage)
|
||||
.first()
|
||||
.click();
|
||||
cy.wait("@createPage").should(
|
||||
"have.nested.property",
|
||||
"response.body.responseMeta.status",
|
||||
201,
|
||||
);
|
||||
cy.wait(2000);
|
||||
cy.xpath(pages.popover)
|
||||
.last()
|
||||
.click({ force: true });
|
||||
cy.get(pages.editName).click({ force: true });
|
||||
cy.get(pages.editInput)
|
||||
.type(Pagename)
|
||||
.type("{Enter}");
|
||||
|
|
@ -1022,11 +1067,8 @@ Cypress.Commands.add("tabVerify", (index, text) => {
|
|||
.should("be.visible");
|
||||
});
|
||||
|
||||
Cypress.Commands.add("NavigateToDatasourceEditor", () => {
|
||||
cy.get(datasourceEditor.datasourceEditorIcon).click({ force: true });
|
||||
});
|
||||
|
||||
Cypress.Commands.add("getPluginFormsAndCreateDatasource", () => {
|
||||
/*
|
||||
cy.wait("@getPluginForm").should(
|
||||
"have.nested.property",
|
||||
"response.body.responseMeta.status",
|
||||
|
|
@ -1037,10 +1079,11 @@ Cypress.Commands.add("getPluginFormsAndCreateDatasource", () => {
|
|||
"response.body.responseMeta.status",
|
||||
201,
|
||||
);
|
||||
*/
|
||||
});
|
||||
|
||||
Cypress.Commands.add("NavigateToApiEditor", () => {
|
||||
cy.get(pages.apiEditorIcon).click({ force: true });
|
||||
cy.xpath(pages.addEntityAPI).click({ force: true });
|
||||
});
|
||||
|
||||
Cypress.Commands.add("testCreateApiButton", () => {
|
||||
|
|
@ -1085,11 +1128,11 @@ Cypress.Commands.add("importCurl", () => {
|
|||
});
|
||||
|
||||
Cypress.Commands.add("NavigateToDatasourceEditor", () => {
|
||||
cy.get(datasourceEditor.datasourceEditorIcon).click({ force: true });
|
||||
cy.xpath(datasourceEditor.addDatasourceEntity).click({ force: true });
|
||||
});
|
||||
|
||||
Cypress.Commands.add("NavigateToQueryEditor", () => {
|
||||
cy.get(queryEditor.queryEditorIcon).click({ force: true });
|
||||
cy.xpath(queryEditor.addQueryEntity).click({ force: true });
|
||||
});
|
||||
|
||||
Cypress.Commands.add("testSaveDatasource", () => {
|
||||
|
|
@ -1335,6 +1378,7 @@ Cypress.Commands.add("startServerAndRoutes", () => {
|
|||
cy.route("POST", "/api/v1/users/invite").as("postInvite");
|
||||
cy.route("GET", "/api/v1/organizations/roles").as("getRoles");
|
||||
cy.route("GET", "/api/v1/users/me").as("getUser");
|
||||
cy.route("POST", "/api/v1/pages").as("createPage");
|
||||
});
|
||||
|
||||
Cypress.Commands.add("alertValidate", text => {
|
||||
|
|
@ -1400,11 +1444,9 @@ Cypress.Commands.add("ValidatePublishTableData", () => {
|
|||
});
|
||||
|
||||
Cypress.Commands.add("ValidatePaginateResponseUrlData", runTestCss => {
|
||||
cy.NavigateToEntityExplorer();
|
||||
cy.NavigateToApiEditor();
|
||||
cy.get("div[tabindex='0'] >div>span")
|
||||
.contains("Api2")
|
||||
.first()
|
||||
.click();
|
||||
cy.SearchEntityandOpen("Api2");
|
||||
cy.NavigateToPaginationTab();
|
||||
cy.RunAPI();
|
||||
cy.get(ApiEditor.apiPaginationNextTest).click();
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@
|
|||
"@uppy/react": "^1.4.5",
|
||||
"@uppy/url": "^1.3.2",
|
||||
"@uppy/webcam": "^1.3.1",
|
||||
"@welldone-software/why-did-you-render": "^4.2.5",
|
||||
"algoliasearch": "^4.2.0",
|
||||
"axios": "^0.18.0",
|
||||
"chance": "^1.1.3",
|
||||
|
|
|
|||
|
|
@ -48,15 +48,8 @@ class AppRouter extends React.Component<any, any> {
|
|||
path={ORG_URL}
|
||||
component={OrganizationLoader}
|
||||
name={"Organisation"}
|
||||
routeProtected
|
||||
/>
|
||||
<AppRoute
|
||||
exact
|
||||
path={USERS_URL}
|
||||
component={Users}
|
||||
name={"Users"}
|
||||
routeProtected
|
||||
/>
|
||||
<AppRoute exact path={USERS_URL} component={Users} name={"Users"} />
|
||||
<AppRoute
|
||||
path={USER_AUTH_URL}
|
||||
component={UserAuth}
|
||||
|
|
@ -67,19 +60,16 @@ class AppRouter extends React.Component<any, any> {
|
|||
path={APPLICATIONS_URL}
|
||||
component={ApplicationListLoader}
|
||||
name={"Home"}
|
||||
routeProtected
|
||||
/>
|
||||
<AppRoute
|
||||
path={BUILDER_URL}
|
||||
component={EditorLoader}
|
||||
name={"Editor"}
|
||||
routeProtected
|
||||
/>
|
||||
<AppRoute
|
||||
path={APP_VIEW_URL}
|
||||
component={AppViewerLoader}
|
||||
name={"AppViewer"}
|
||||
routeProtected
|
||||
logDisable
|
||||
/>
|
||||
<AppRoute
|
||||
|
|
|
|||
|
|
@ -165,8 +165,8 @@ export const executeApiActionSuccess = (payload: {
|
|||
payload: payload,
|
||||
});
|
||||
|
||||
export const saveApiName = (payload: { id: string; name: string }) => ({
|
||||
type: ReduxActionTypes.SAVE_API_NAME,
|
||||
export const saveActionName = (payload: { id: string; name: string }) => ({
|
||||
type: ReduxActionTypes.SAVE_ACTION_NAME_INIT,
|
||||
payload: payload,
|
||||
});
|
||||
|
||||
|
|
@ -189,11 +189,12 @@ export type UpdateActionPropertyActionPayload = {
|
|||
|
||||
export const updateActionProperty = (
|
||||
payload: UpdateActionPropertyActionPayload,
|
||||
) =>
|
||||
batchAction({
|
||||
) => {
|
||||
return batchAction({
|
||||
type: ReduxActionTypes.UPDATE_ACTION_PROPERTY,
|
||||
payload,
|
||||
});
|
||||
};
|
||||
|
||||
export default {
|
||||
createAction: createActionRequest,
|
||||
|
|
|
|||
|
|
@ -51,7 +51,9 @@ export const createNewApiAction = (
|
|||
payload: { pageId },
|
||||
});
|
||||
|
||||
export const createNewQueryAction = (pageId: string): ReduxAction<{}> => ({
|
||||
export const createNewQueryAction = (
|
||||
pageId: string,
|
||||
): ReduxAction<{ pageId: string }> => ({
|
||||
type: ReduxActionTypes.CREATE_NEW_QUERY_ACTION,
|
||||
payload: { pageId },
|
||||
});
|
||||
|
|
|
|||
|
|
@ -27,3 +27,12 @@ export const fetchApplication = (applicationId: string) => {
|
|||
},
|
||||
};
|
||||
};
|
||||
|
||||
export const publishApplication = (applicationId: string) => {
|
||||
return {
|
||||
type: ReduxActionTypes.PUBLISH_APPLICATION_INIT,
|
||||
payload: {
|
||||
applicationId,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -29,6 +29,13 @@ export const changeDatasource = (payload: Datasource) => {
|
|||
};
|
||||
};
|
||||
|
||||
export const switchDatasource = (id: string) => {
|
||||
return {
|
||||
type: ReduxActionTypes.SWITCH_DATASOURCE,
|
||||
payload: { datasourceId: id },
|
||||
};
|
||||
};
|
||||
|
||||
export const testDatasource = (payload: Partial<Datasource>) => {
|
||||
return {
|
||||
type: ReduxActionTypes.TEST_DATASOURCE_INIT,
|
||||
|
|
|
|||
10
app/client/src/actions/explorerActions.ts
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
import { ReduxActionTypes } from "constants/ReduxActionConstants";
|
||||
|
||||
export const initExplorerEntityNameEdit = (actionId: string) => {
|
||||
return {
|
||||
type: ReduxActionTypes.INIT_EXPLORER_ENTITY_NAME_EDIT,
|
||||
payload: {
|
||||
id: actionId,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
|
@ -10,6 +10,7 @@ import {
|
|||
} from "constants/ReduxActionConstants";
|
||||
import { FlattenedWidgetProps } from "reducers/entityReducers/canvasWidgetsReducer";
|
||||
import { ContainerWidgetProps } from "widgets/ContainerWidget";
|
||||
import AnalyticsUtil from "utils/AnalyticsUtil";
|
||||
import { UrlDataState } from "@appsmith/reducers/entityReducers/urlReducer";
|
||||
|
||||
export const fetchPageList = (
|
||||
|
|
@ -27,7 +28,7 @@ export const fetchPage = (pageId: string): ReduxAction<FetchPageRequest> => {
|
|||
return {
|
||||
type: ReduxActionTypes.FETCH_PAGE_INIT,
|
||||
payload: {
|
||||
pageId,
|
||||
id: pageId,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
|
@ -91,6 +92,29 @@ export const updateAndSaveLayout = (widgets: FlattenedWidgetProps) => {
|
|||
};
|
||||
};
|
||||
|
||||
export const createPage = (applicationId: string, pageName: string) => {
|
||||
AnalyticsUtil.logEvent("CREATE_PAGE", {
|
||||
pageName,
|
||||
});
|
||||
return {
|
||||
type: ReduxActionTypes.CREATE_PAGE_INIT,
|
||||
payload: {
|
||||
applicationId,
|
||||
name: pageName,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export const updatePage = (id: string, name: string) => {
|
||||
return {
|
||||
type: ReduxActionTypes.UPDATE_PAGE_INIT,
|
||||
payload: {
|
||||
id,
|
||||
name,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export type WidgetAddChild = {
|
||||
widgetId: string;
|
||||
widgetName?: string;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ export const updateWidgetName = (widgetId: string, newName: string) => {
|
|||
return {
|
||||
type: ReduxActionTypes.UPDATE_WIDGET_NAME_INIT,
|
||||
payload: {
|
||||
widgetId,
|
||||
id: widgetId,
|
||||
newName,
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -61,3 +61,29 @@ export const focusWidget = (
|
|||
type: ReduxActionTypes.FOCUS_WIDGET,
|
||||
payload: { widgetId },
|
||||
});
|
||||
|
||||
export const showModal = (id: string) => {
|
||||
return {
|
||||
type: ReduxActionTypes.SHOW_MODAL,
|
||||
payload: {
|
||||
modalId: id,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export const closeAllModals = () => {
|
||||
return {
|
||||
type: ReduxActionTypes.CLOSE_MODAL,
|
||||
payload: {},
|
||||
};
|
||||
};
|
||||
|
||||
export const forceOpenPropertyPane = (id: string) => {
|
||||
return {
|
||||
type: ReduxActionTypes.SHOW_PROPERTY_PANE,
|
||||
payload: {
|
||||
widgetId: id,
|
||||
force: true,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ export interface CreateApplicationRequest {
|
|||
}
|
||||
|
||||
export interface SetDefaultPageRequest {
|
||||
pageId: string;
|
||||
id: string;
|
||||
applicationId: string;
|
||||
}
|
||||
|
||||
|
|
@ -87,7 +87,7 @@ class ApplicationApi extends Api {
|
|||
static changeAppViewAccessPath = (applicationId: string) =>
|
||||
`${applicationId}/changeAccess`;
|
||||
static setDefaultPagePath = (request: SetDefaultPageRequest) =>
|
||||
`${ApplicationApi.baseURL}${request.applicationId}/page/${request.pageId}/makeDefault`;
|
||||
`${ApplicationApi.baseURL}${request.applicationId}/page/${request.id}/makeDefault`;
|
||||
static publishApplication(
|
||||
publishApplicationRequest: PublishApplicationRequest,
|
||||
): AxiosPromise<PublishApplicationResponse> {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import { AxiosPromise } from "axios";
|
|||
import { PageAction } from "constants/ActionConstants";
|
||||
|
||||
export interface FetchPageRequest {
|
||||
pageId: string;
|
||||
id: string;
|
||||
}
|
||||
|
||||
export interface FetchPublishedPageRequest {
|
||||
|
|
@ -75,7 +75,7 @@ export interface FetchPageListResponse extends ApiResponse {
|
|||
}
|
||||
|
||||
export interface DeletePageRequest {
|
||||
pageId: string;
|
||||
id: string;
|
||||
}
|
||||
|
||||
export interface UpdateWidgetNameRequest {
|
||||
|
|
@ -106,7 +106,7 @@ class PageApi extends Api {
|
|||
static fetchPage(
|
||||
pageRequest: FetchPageRequest,
|
||||
): AxiosPromise<FetchPageResponse> {
|
||||
return Api.get(PageApi.url + "/" + pageRequest.pageId);
|
||||
return Api.get(PageApi.url + "/" + pageRequest.id);
|
||||
}
|
||||
|
||||
static savePage(
|
||||
|
|
@ -147,7 +147,7 @@ class PageApi extends Api {
|
|||
}
|
||||
|
||||
static deletePage(request: DeletePageRequest): AxiosPromise<ApiResponse> {
|
||||
return Api.delete(PageApi.url + "/" + request.pageId);
|
||||
return Api.delete(PageApi.url + "/" + request.id);
|
||||
}
|
||||
|
||||
static updateWidgetName(
|
||||
|
|
|
|||
3
app/client/src/assets/icons/control/collapse.svg
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
<svg width="12" height="10" viewBox="0 0 12 10" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M12 0H2.5L0 5.00366L2.5 10H12V0ZM4.5 5C4.5 5.55228 4.05228 6 3.5 6C2.94772 6 2.5 5.55228 2.5 5C2.5 4.44772 2.94772 4 3.5 4C4.05228 4 4.5 4.44772 4.5 5ZM6.5 6C7.05228 6 7.5 5.55228 7.5 5C7.5 4.44772 7.05228 4 6.5 4C5.94772 4 5.5 4.44772 5.5 5C5.5 5.55228 5.94772 6 6.5 6ZM9.5 6C10.0523 6 10.5 5.55228 10.5 5C10.5 4.44772 10.0523 4 9.5 4C8.94772 4 8.5 4.44772 8.5 5C8.5 5.55228 8.94772 6 9.5 6Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 561 B |
|
|
@ -4,10 +4,5 @@
|
|||
<mask id="mask0" mask-type="alpha" maskUnits="userSpaceOnUse" x="10" y="3" width="4" height="18">
|
||||
<path id="Mask_2" fill-rule="evenodd" clip-rule="evenodd" d="M12 7C13.104 7 14 6.104 14 5C14 3.896 13.104 3 12 3C10.896 3 10 3.896 10 5C10 6.104 10.896 7 12 7ZM12 10C10.896 10 10 10.896 10 12C10 13.104 10.896 14 12 14C13.104 14 14 13.104 14 12C14 10.896 13.104 10 12 10ZM10 19C10 17.896 10.896 17 12 17C13.104 17 14 17.896 14 19C14 20.104 13.104 21 12 21C10.896 21 10 20.104 10 19Z" fill="white"/>
|
||||
</mask>
|
||||
<g mask="url(#mask0)">
|
||||
<g id="🎨 Color">
|
||||
<rect id="Base" width="24" height="24" fill="#A3B3BF"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.0 KiB |
3
app/client/src/assets/icons/menu/api-colored.svg
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M12 5.00773L10.6039 4.71741L10.1629 3.65083L10.9443 2.45913L9.54088 1.05571L8.34912 1.83716L7.28278 1.39599L6.99246 0H5.00754L4.71722 1.39599L3.65088 1.83716L2.45912 1.05571L1.0557 2.45913L1.83715 3.65083L1.39606 4.71741L0 5.00773V6.99235L1.39606 7.28267L1.83715 8.34925L1.0557 9.54095L2.45912 10.9444L3.65072 10.1629L4.71722 10.6041L5.00754 12H6.99246L7.28278 10.6041L8.34928 10.1629L9.54088 10.9444L10.9443 9.54095L10.1629 8.34925L10.6039 7.28267L12 6.99235V5.00773ZM2.82293 7.63715L3.0443 6.88257H4.16545L4.37969 7.63715H5.33184L4.17736 4.20227H3.10857L1.95647 7.63715H2.82293ZM4.00121 6.25415H3.21093L3.58702 4.97589H3.63225L4.00121 6.25415ZM6.55648 7.63715V6.63025H7.13491C7.89901 6.63025 8.42507 6.15179 8.42507 5.42102C8.42507 4.68311 7.9252 4.20227 7.18728 4.20227H5.68289V7.63715H6.55648ZM6.95162 5.97089H6.55648V4.87354H6.95639C7.32534 4.87354 7.54196 5.06158 7.54196 5.4234C7.54196 5.78046 7.32296 5.97089 6.95162 5.97089ZM9.71399 7.63715V4.20227H8.84039V7.63715H9.71399Z" fill="#D6415F"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
3
app/client/src/assets/icons/menu/datasource-colored.svg
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.9135 0.561055C7.9135 0.870918 6.23457 1.12211 4.1635 1.12211C2.09243 1.12211 0.413498 0.870918 0.413498 0.561055C0.413498 0.251193 2.09243 0 4.1635 0C6.23457 0 7.9135 0.251193 7.9135 0.561055ZM3.03755 3.94381V3.20132H8.24959V1.04044C8.24959 1.04044 7.17068 1.7044 4.1248 1.7044C1.07891 1.7044 0 1.12211 0 1.12211V3.34213C0 3.34213 0.739498 3.62842 1.21327 3.72683C1.73671 3.83556 2.3448 3.90789 3.03755 3.94381ZM3.03618 6.7922C2.42801 6.76073 1.88837 6.70121 1.41063 6.61366C0.850902 6.51107 0 6.19042 0 6.19042V3.9704C0 3.9704 0.897126 4.31392 1.59814 4.41095C2.01645 4.46886 2.49801 4.50902 3.03618 4.53144V6.7922ZM1.41063 9.43546C1.88837 9.52302 2.42801 9.58253 3.03618 9.614V7.35324C2.49801 7.33082 2.01645 7.29066 1.59814 7.23276C0.897126 7.13572 0 6.7922 0 6.7922V9.01222C0 9.01222 0.850902 9.33287 1.41063 9.43546ZM9.71951 3.77119L12 6.01541H9.71951V3.77119ZM9.19505 3.77119H3.75V12H12V6.56804H9.19505V3.77119ZM10.5 7.5H5.25V8.4H10.5V7.5ZM5.25 9.375H9V10.275H5.25V9.375Z" fill="#DEAB41"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
3
app/client/src/assets/icons/menu/explorer.svg
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
<svg width="20" height="18" viewBox="0 0 20 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M20 8V0H13V3H7V0H0V8H7V5H9V15H13V18H20V10H13V13H11V5H13V8H20Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 190 B |
|
|
@ -1,5 +1,4 @@
|
|||
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M0.5 4C0.5 2.067 2.067 0.5 4 0.5H28C29.933 0.5 31.5 2.067 31.5 4V28C31.5 29.933 29.933 31.5 28 31.5H4C2.067 31.5 0.5 29.933 0.5 28V4Z" fill="#29CCA3" stroke="#29CCA3"/>
|
||||
<path d="M18 18H14V25H18V18Z" fill="white"/>
|
||||
<path d="M24.4201 14.18L16.7101 6.30001C16.6172 6.20628 16.5066 6.13189 16.3847 6.08112C16.2628 6.03035 16.1321 6.00421 16.0001 6.00421C15.8681 6.00421 15.7374 6.03035 15.6155 6.08112C15.4937 6.13189 15.3831 6.20628 15.2901 6.30001L7.58012 14.19C7.39355 14.3781 7.24621 14.6013 7.14664 14.8468C7.04708 15.0923 6.99727 15.3551 7.00012 15.62V24C6.99934 24.5119 7.19489 25.0046 7.54649 25.3767C7.89809 25.7488 8.37898 25.9719 8.89012 26H12.0001V17C12.0001 16.7348 12.1055 16.4804 12.293 16.2929C12.4805 16.1054 12.7349 16 13.0001 16H19.0001C19.2653 16 19.5197 16.1054 19.7072 16.2929C19.8948 16.4804 20.0001 16.7348 20.0001 17V26H23.1101C23.6213 25.9719 24.1021 25.7488 24.4537 25.3767C24.8053 25.0046 25.0009 24.5119 25.0001 24V15.62C25.0009 15.0829 24.7929 14.5666 24.4201 14.18Z" fill="white"/>
|
||||
</svg>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 943 B |
3
app/client/src/assets/icons/menu/page.svg
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
<svg width="10" height="12" viewBox="0 0 10 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M0 0H6.78482V3.32332H10V12H0V0ZM1.66667 4.41933H7.33333V5.486H1.66667V4.41933ZM7.33333 8.86378H1.66667V9.93044H7.33333V8.86378ZM1.66667 6.64155H8.33333V7.70822H1.66667V6.64155ZM10 2.65982L7.46613 0V2.65982H10Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 378 B |
3
app/client/src/assets/icons/menu/widgets-colored.svg
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M6 6V0H12V6H6ZM0 6V1H5V6H0ZM1 11V7H5V11H1ZM6 7V12H11V7H6Z" fill="#5BB749"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 228 B |
|
|
@ -1,9 +1,4 @@
|
|||
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M8.5 14.25C8.5 13.8358 8.83579 13.5 9.25 13.5H10.75C11.1642 13.5 11.5 13.8358 11.5 14.25C11.5 14.6642 11.1642 15 10.75 15H9.25C8.83579 15 8.5 14.6642 8.5 14.25Z" fill="#F2FAFF" fill-opacity="0.9"/>
|
||||
<path d="M13 14.25C13 13.8358 13.3358 13.5 13.75 13.5H22.75C23.1642 13.5 23.5 13.8358 23.5 14.25C23.5 14.6642 23.1642 15 22.75 15H13.75C13.3358 15 13 14.6642 13 14.25Z" fill="#F2FAFF" fill-opacity="0.9"/>
|
||||
<path d="M8.5 17.25C8.5 16.8358 8.83579 16.5 9.25 16.5H10.75C11.1642 16.5 11.5 16.8358 11.5 17.25C11.5 17.6642 11.1642 18 10.75 18H9.25C8.83579 18 8.5 17.6642 8.5 17.25Z" fill="#F2FAFF" fill-opacity="0.9"/>
|
||||
<path d="M13 17.25C13 16.8358 13.3358 16.5 13.75 16.5H22.75C23.1642 16.5 23.5 16.8358 23.5 17.25C23.5 17.6642 23.1642 18 22.75 18H13.75C13.3358 18 13 17.6642 13 17.25Z" fill="#F2FAFF" fill-opacity="0.9"/>
|
||||
<path d="M8.5 20.25C8.5 19.8358 8.83579 19.5 9.25 19.5H10.75C11.1642 19.5 11.5 19.8358 11.5 20.25C11.5 20.6642 11.1642 21 10.75 21H9.25C8.83579 21 8.5 20.6642 8.5 20.25Z" fill="#F2FAFF" fill-opacity="0.9"/>
|
||||
<path d="M13 20.25C13 19.8358 13.3358 19.5 13.75 19.5H22.75C23.1642 19.5 23.5 19.8358 23.5 20.25C23.5 20.6642 23.1642 21 22.75 21H13.75C13.3358 21 13 20.6642 13 20.25Z" fill="#F2FAFF" fill-opacity="0.9"/>
|
||||
<path d="M5 6C4.44772 6 4 6.44772 4 7V26C4 26.5523 4.44772 27 5 27H27C27.5523 27 28 26.5523 28 26V7C28 6.44772 27.5523 6 27 6H5ZM26.5 24.5C26.5 25.0523 26.0523 25.5 25.5 25.5H6.5C5.94772 25.5 5.5 25.0523 5.5 24.5V11.5C5.5 10.9477 5.94772 10.5 6.5 10.5H25.5C26.0523 10.5 26.5 10.9477 26.5 11.5V24.5ZM26.5 8.25C26.5 8.66421 26.1642 9 25.75 9C25.3358 9 25 8.66421 25 8.25C25 7.83579 25.3358 7.5 25.75 7.5C26.1642 7.5 26.5 7.83579 26.5 8.25Z" fill="#F2FAFF" fill-opacity="0.9"/>
|
||||
<svg width="18" height="16" viewBox="0 0 18 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M13.5 1.5H1.5V11.5H13.5V1.5Z" stroke="white"/>
|
||||
<path d="M17 4H4V15H17V4Z" fill="white"/>
|
||||
</svg>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 201 B |
|
|
@ -30,6 +30,7 @@ export const PositionedContainer = (props: PositionedContainerProps) => {
|
|||
width: props.style.componentWidth + (props.style.widthUnit || "px"),
|
||||
padding: padding + "px",
|
||||
}}
|
||||
id={props.widgetId}
|
||||
//Before you remove: This is used by property pane to reference the element
|
||||
className={
|
||||
generateClassName(props.widgetId) +
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ export const RichtextEditorComponent = (
|
|||
props: RichtextEditorComponentProps,
|
||||
) => {
|
||||
const [editorInstance, setEditorInstance] = useState(null as any);
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
useEffect(() => {
|
||||
if (editorInstance !== null) {
|
||||
editorInstance.mode.set(
|
||||
|
|
@ -40,7 +41,7 @@ export const RichtextEditorComponent = (
|
|||
const onChange = debounce(props.onValueChange, 200);
|
||||
(window as any).tinyMCE.init({
|
||||
height: "100%",
|
||||
selector: `textarea#${props.widgetId}`,
|
||||
selector: `textarea#rte-${props.widgetId}`,
|
||||
menubar: false,
|
||||
branding: false,
|
||||
resize: false,
|
||||
|
|
@ -81,7 +82,7 @@ export const RichtextEditorComponent = (
|
|||
}, []);
|
||||
return (
|
||||
<StyledRTEditor>
|
||||
<textarea id={props.widgetId}></textarea>
|
||||
<textarea id={`rte-${props.widgetId}`}></textarea>
|
||||
</StyledRTEditor>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ import { getDefaultRefinement } from "selectors/helpSelectors";
|
|||
import { getAppsmithConfigs } from "configs";
|
||||
const { algolia } = getAppsmithConfigs();
|
||||
const searchClient = algoliasearch(algolia.apiId, algolia.apiKey);
|
||||
console.log({ algolia });
|
||||
const OenLinkIcon = HelpIcons.OPEN_LINK;
|
||||
const DocumentIcon = HelpIcons.DOCUMENT;
|
||||
|
||||
|
|
@ -220,7 +219,6 @@ const StyledPoweredBy = styled(PoweredBy)`
|
|||
export default function DocumentationSearch(props: { hitsPerPage: number }) {
|
||||
const dispatch = useDispatch();
|
||||
const defaultRefinement = useSelector(getDefaultRefinement);
|
||||
console.log({ algolia });
|
||||
if (!algolia.enabled) return null;
|
||||
return (
|
||||
<SearchContainer className="ais-InstantSearch t--docSearchModal">
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useEffect, useState } from "react";
|
||||
import React, { useEffect, useState, useCallback } from "react";
|
||||
import { useSelector, useDispatch } from "react-redux";
|
||||
|
||||
import { useParams } from "react-router-dom";
|
||||
|
|
@ -11,7 +11,7 @@ import { AppState } from "reducers";
|
|||
import { RestAction } from "entities/Action";
|
||||
import { Page } from "constants/ReduxActionConstants";
|
||||
|
||||
import { saveApiName } from "actions/actionActions";
|
||||
import { saveActionName } from "actions/actionActions";
|
||||
import { Spinner } from "@blueprintjs/core";
|
||||
|
||||
const ApiNameWrapper = styled.div`
|
||||
|
|
@ -67,34 +67,43 @@ export const ActionNameEditor = () => {
|
|||
};
|
||||
});
|
||||
|
||||
const hasActionNameConflict = (name: string) =>
|
||||
!(
|
||||
existingPageNames.indexOf(name) === -1 &&
|
||||
actions.findIndex(action => action.name === name) === -1 &&
|
||||
existingWidgetNames.indexOf(name) === -1
|
||||
);
|
||||
const hasActionNameConflict = useCallback(
|
||||
(name: string) =>
|
||||
!(
|
||||
existingPageNames.indexOf(name) === -1 &&
|
||||
actions.findIndex(action => action.name === name) === -1 &&
|
||||
existingWidgetNames.indexOf(name) === -1
|
||||
),
|
||||
[existingPageNames, actions, existingWidgetNames],
|
||||
);
|
||||
|
||||
const isInvalidActionName = (name: string): string | boolean => {
|
||||
if (!name || name.trim().length === 0) {
|
||||
return "Please enter a valid name";
|
||||
} else if (
|
||||
name !== currentActionConfig?.name &&
|
||||
hasActionNameConflict(name)
|
||||
) {
|
||||
return `${name} is already being used.`;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
const isInvalidActionName = useCallback(
|
||||
(name: string): string | boolean => {
|
||||
if (!name || name.trim().length === 0) {
|
||||
return "Please enter a valid name";
|
||||
} else if (
|
||||
name !== currentActionConfig?.name &&
|
||||
hasActionNameConflict(name)
|
||||
) {
|
||||
return `${name} is already being used.`;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
[currentActionConfig, hasActionNameConflict],
|
||||
);
|
||||
|
||||
const handleAPINameChange = (name: string) => {
|
||||
if (
|
||||
currentActionConfig &&
|
||||
name !== currentActionConfig?.name &&
|
||||
!isInvalidActionName(name)
|
||||
) {
|
||||
dispatch(saveApiName({ id: currentActionConfig.id, name }));
|
||||
}
|
||||
};
|
||||
const handleAPINameChange = useCallback(
|
||||
(name: string) => {
|
||||
if (
|
||||
currentActionConfig &&
|
||||
name !== currentActionConfig?.name &&
|
||||
!isInvalidActionName(name)
|
||||
) {
|
||||
dispatch(saveActionName({ id: currentActionConfig.id, name }));
|
||||
}
|
||||
},
|
||||
[dispatch, isInvalidActionName, currentActionConfig],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (saveStatus.isSaving === false && saveStatus.error === true) {
|
||||
|
|
|
|||
|
|
@ -11,8 +11,10 @@ import {
|
|||
Intent as BlueprintIntent,
|
||||
IconName,
|
||||
MaybeElement,
|
||||
IButtonProps,
|
||||
} from "@blueprintjs/core";
|
||||
import { Direction, Directions } from "utils/helpers";
|
||||
import { omit } from "lodash";
|
||||
|
||||
const outline = css`
|
||||
&&&&&& {
|
||||
|
|
@ -21,14 +23,7 @@ const outline = css`
|
|||
}
|
||||
`;
|
||||
|
||||
const buttonStyles = css<{
|
||||
outline?: string;
|
||||
intent?: Intent;
|
||||
filled?: string;
|
||||
fluid?: boolean;
|
||||
skin?: Skin;
|
||||
iconAlignment?: Direction;
|
||||
}>`
|
||||
const buttonStyles = css<Partial<ButtonProps>>`
|
||||
${BlueprintButtonIntentsCSS}
|
||||
&&&& {
|
||||
padding: ${props =>
|
||||
|
|
@ -61,22 +56,20 @@ const buttonStyles = css<{
|
|||
}
|
||||
${props => (props.outline ? outline : "")}
|
||||
`;
|
||||
const StyledButton = styled(BlueprintButton)<{
|
||||
outline?: string;
|
||||
intent?: Intent;
|
||||
filled?: string;
|
||||
skin?: Skin;
|
||||
iconAlignment?: Direction;
|
||||
}>`
|
||||
const StyledButton = styled((props: IButtonProps & Partial<ButtonProps>) => (
|
||||
<BlueprintButton
|
||||
{...omit(props, ["iconAlignment", "fluid", "filled", "outline"])}
|
||||
/>
|
||||
))`
|
||||
${buttonStyles}
|
||||
`;
|
||||
const StyledAnchorButton = styled(BlueprintAnchorButton)<{
|
||||
outline?: string;
|
||||
intent?: Intent;
|
||||
filled?: string;
|
||||
skin?: Skin;
|
||||
iconAlignment?: Direction;
|
||||
}>`
|
||||
const StyledAnchorButton = styled(
|
||||
(props: IButtonProps & Partial<ButtonProps>) => (
|
||||
<BlueprintAnchorButton
|
||||
{...omit(props, ["iconAlignment", "fluid", "filled", "outline"])}
|
||||
/>
|
||||
),
|
||||
)`
|
||||
${buttonStyles}
|
||||
`;
|
||||
|
||||
|
|
@ -114,8 +107,8 @@ export const Button = (props: ButtonProps) => {
|
|||
const baseProps = {
|
||||
text: props.text,
|
||||
minimal: !props.filled,
|
||||
outline: props.outline ? props.outline.toString() : undefined,
|
||||
filled: props.filled ? props.filled.toString() : undefined,
|
||||
outline: !!props.outline,
|
||||
filled: !!props.filled,
|
||||
intent: props.intent as BlueprintIntent,
|
||||
large: props.size === "large",
|
||||
small: props.size === "small",
|
||||
|
|
@ -123,7 +116,7 @@ export const Button = (props: ButtonProps) => {
|
|||
disabled: props.disabled,
|
||||
type: props.type,
|
||||
className: props.className,
|
||||
fluid: props.fluid ? props.fluid.toString() : undefined,
|
||||
fluid: !!props.fluid,
|
||||
skin: props.skin,
|
||||
iconAlignment: props.iconAlignment ? props.iconAlignment : undefined,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -119,9 +119,10 @@ interface PopoverContentProps {
|
|||
onMouseLeave: () => void;
|
||||
}
|
||||
|
||||
const CurrentValueViewer = (props: {
|
||||
export const CurrentValueViewer = (props: {
|
||||
theme: EditorTheme;
|
||||
evaluatedValue: any;
|
||||
hideLabel?: boolean;
|
||||
}) => {
|
||||
let content = (
|
||||
<CodeWrapper colorTheme={props.theme}>{"undefined"}</CodeWrapper>
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@ import { DropdownOption } from "widgets/DropdownWidget";
|
|||
import { ControlIconName, ControlIcons } from "icons/ControlIcons";
|
||||
import { noop } from "utils/AppsmithUtils";
|
||||
import { Intent } from "constants/DefaultTheme";
|
||||
import { IconProps } from "constants/IconConstants";
|
||||
import { Colors } from "constants/Colors";
|
||||
|
||||
export type ContextDropdownOption = DropdownOption & {
|
||||
onSelect: (event: React.MouseEvent<HTMLElement, MouseEvent>) => void;
|
||||
|
|
@ -39,6 +41,7 @@ type ContextDropdownProps = {
|
|||
iconSize?: number;
|
||||
text?: string;
|
||||
placeholder?: string;
|
||||
color?: string;
|
||||
};
|
||||
};
|
||||
|
||||
|
|
@ -74,10 +77,10 @@ export const ContextDropdown = (props: ContextDropdownProps) => {
|
|||
let trigger: ReactNode;
|
||||
if (props.toggle.type === "icon" && props.toggle.icon) {
|
||||
const TriggerElement = ControlIcons[props.toggle.icon];
|
||||
const TriggerElementProps = {
|
||||
style: { display: "flex" },
|
||||
const TriggerElementProps: IconProps = {
|
||||
width: props.toggle.iconSize,
|
||||
height: props.toggle.iconSize,
|
||||
color: props.toggle.color || Colors.SLATE_GRAY,
|
||||
};
|
||||
trigger = <TriggerElement {...TriggerElementProps} />;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { Divider } from "@blueprintjs/core";
|
||||
import styled from "styled-components";
|
||||
|
||||
export const StyledDivider = styled(Divider)`
|
||||
export const StyledDivider = styled(Divider)<{ color?: string }>`
|
||||
&& {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,13 +53,13 @@ const DraggableComponent = (props: DraggableComponentProps) => {
|
|||
// This state tells us which widget is selected
|
||||
// The value is the widgetId of the selected widget
|
||||
const selectedWidget = useSelector(
|
||||
(state: AppState) => state.ui.editor.selectedWidget,
|
||||
(state: AppState) => state.ui.widgetDragResize.selectedWidget,
|
||||
);
|
||||
|
||||
// This state tels us which widget is focused
|
||||
// The value is the widgetId of the focused widget.
|
||||
const focusedWidget = useSelector(
|
||||
(state: AppState) => state.ui.editor.focusedWidget,
|
||||
(state: AppState) => state.ui.widgetDragResize.focusedWidget,
|
||||
);
|
||||
|
||||
// This state tells us whether a `ResizableComponent` is resizing
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import React, {
|
|||
Context,
|
||||
createContext,
|
||||
useEffect,
|
||||
memo,
|
||||
} from "react";
|
||||
import styled from "styled-components";
|
||||
import { useDrop, XYCoord, DropTargetMonitor } from "react-dnd";
|
||||
|
|
@ -30,6 +31,7 @@ import {
|
|||
useWidgetSelection,
|
||||
useCanvasSnapRowsUpdateHook,
|
||||
} from "utils/hooks/dragResizeHooks";
|
||||
import { getOccupiedSpaces } from "selectors/editorSelectors";
|
||||
|
||||
type DropTargetComponentProps = WidgetProps & {
|
||||
children?: ReactNode;
|
||||
|
|
@ -70,15 +72,15 @@ export const DropTargetContext: Context<{
|
|||
persistDropTargetRows?: (widgetId: string, row: number) => void;
|
||||
}> = createContext({});
|
||||
|
||||
export const DropTargetComponent = (props: DropTargetComponentProps) => {
|
||||
export const DropTargetComponent = memo((props: DropTargetComponentProps) => {
|
||||
const canDropTargetExtend = props.canExtend;
|
||||
|
||||
const snapRows = getCanvasSnapRows(props.bottomRow, props.canExtend);
|
||||
|
||||
const { updateWidget, occupiedSpaces } = useContext(EditorContext);
|
||||
|
||||
const { updateWidget } = useContext(EditorContext);
|
||||
const occupiedSpaces = useSelector(getOccupiedSpaces);
|
||||
const selectedWidget = useSelector(
|
||||
(state: AppState) => state.ui.editor.selectedWidget,
|
||||
(state: AppState) => state.ui.widgetDragResize.selectedWidget,
|
||||
);
|
||||
const isResizing = useSelector(
|
||||
(state: AppState) => state.ui.widgetDragResize.isResizing,
|
||||
|
|
@ -180,9 +182,14 @@ export const DropTargetComponent = (props: DropTargetComponentProps) => {
|
|||
|
||||
// Only show propertypane if this is a new widget.
|
||||
// If it is not a new widget, then let the DraggableComponent handle it.
|
||||
showPropertyPane &&
|
||||
updateWidgetParams.payload.newWidgetId &&
|
||||
showPropertyPane(updateWidgetParams.payload.newWidgetId);
|
||||
// Give evaluations a second to complete.
|
||||
setTimeout(
|
||||
() =>
|
||||
showPropertyPane &&
|
||||
updateWidgetParams.payload.newWidgetId &&
|
||||
showPropertyPane(updateWidgetParams.payload.newWidgetId),
|
||||
100,
|
||||
);
|
||||
|
||||
// Select the widget if it is a new widget
|
||||
selectWidget && selectWidget(widget.widgetId);
|
||||
|
|
@ -285,6 +292,6 @@ export const DropTargetComponent = (props: DropTargetComponentProps) => {
|
|||
</StyledDropTarget>
|
||||
</DropTargetContext.Provider>
|
||||
);
|
||||
};
|
||||
});
|
||||
|
||||
export default DropTargetComponent;
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import styled from "styled-components";
|
|||
import _ from "lodash";
|
||||
import Edit from "assets/images/EditPen.svg";
|
||||
import ErrorTooltip from "./ErrorTooltip";
|
||||
import { Colors } from "constants/Colors";
|
||||
|
||||
export enum EditInteractionKind {
|
||||
SINGLE,
|
||||
|
|
@ -26,6 +27,8 @@ type EditableTextProps = {
|
|||
isInvalid?: (value: string) => string | boolean;
|
||||
editInteractionKind: EditInteractionKind;
|
||||
hideEditIcon?: boolean;
|
||||
minimal?: boolean;
|
||||
onBlur?: (value?: string) => void;
|
||||
};
|
||||
|
||||
const EditPen = styled.img`
|
||||
|
|
@ -35,19 +38,26 @@ const EditPen = styled.img`
|
|||
}
|
||||
`;
|
||||
|
||||
const EditableTextWrapper = styled.div<{ isEditing: boolean }>`
|
||||
const EditableTextWrapper = styled.div<{
|
||||
isEditing: boolean;
|
||||
minimal: boolean;
|
||||
}>`
|
||||
&& {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
align-items: flex-start;
|
||||
& .${Classes.EDITABLE_TEXT} {
|
||||
border: ${props => (props.isEditing ? "1px solid #ccc" : "none")};
|
||||
border: ${props =>
|
||||
props.isEditing && !props.minimal
|
||||
? `1px solid ${Colors.HIT_GRAY}`
|
||||
: "none"};
|
||||
cursor: pointer;
|
||||
padding: 5px 5px;
|
||||
padding: ${props => (!props.minimal ? "5px 5px" : "0px")};
|
||||
text-transform: none;
|
||||
flex: 1 0 100%;
|
||||
max-width: 100%;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
&:before,
|
||||
&:after {
|
||||
|
|
@ -61,11 +71,16 @@ const EditableTextWrapper = styled.div<{ isEditing: boolean }>`
|
|||
}
|
||||
`;
|
||||
|
||||
const TextContainer = styled.div<{ isValid: boolean }>`
|
||||
const TextContainer = styled.div<{ isValid: boolean; minimal: boolean }>`
|
||||
display: flex;
|
||||
&&&& .bp3-editable-text {
|
||||
border-radius: 3px;
|
||||
border-color: ${props => (props.isValid ? "hsl(0,0%,80%)" : "red")};
|
||||
${props => (!props.minimal ? "border-radius: 3px;" : "")}
|
||||
${props =>
|
||||
!props.minimal
|
||||
? `border-color: ${props.isValid ? Colors.HIT_GRAY : "red"}`
|
||||
: ""};
|
||||
${props =>
|
||||
props.minimal ? `border-bottom: 1px solid ${Colors.HIT_GRAY}` : ""}
|
||||
}
|
||||
`;
|
||||
|
||||
|
|
@ -79,7 +94,7 @@ export const EditableText = (props: EditableTextProps) => {
|
|||
|
||||
useEffect(() => {
|
||||
if (props.forceDefault === true) setValue(props.defaultValue);
|
||||
}, [props.forceDefault]);
|
||||
}, [props.forceDefault, props.defaultValue]);
|
||||
|
||||
const edit = (e: any) => {
|
||||
setIsEditing(true);
|
||||
|
|
@ -87,6 +102,7 @@ export const EditableText = (props: EditableTextProps) => {
|
|||
e.stopPropagation();
|
||||
};
|
||||
const onChange = (_value: string) => {
|
||||
props.onBlur && props.onBlur();
|
||||
const isInvalid = props.isInvalid ? props.isInvalid(_value) : false;
|
||||
if (!isInvalid) {
|
||||
props.onTextChanged(_value);
|
||||
|
|
@ -115,9 +131,10 @@ export const EditableText = (props: EditableTextProps) => {
|
|||
onClick={
|
||||
props.editInteractionKind === EditInteractionKind.SINGLE ? edit : _.noop
|
||||
}
|
||||
minimal={!!props.minimal}
|
||||
>
|
||||
<ErrorTooltip isOpen={!!error} message={errorMessage as string}>
|
||||
<TextContainer isValid={!error}>
|
||||
<TextContainer isValid={!error} minimal={!!props.minimal}>
|
||||
<BlueprintEditableText
|
||||
disabled={!isEditing}
|
||||
isEditing={isEditing}
|
||||
|
|
@ -127,10 +144,12 @@ export const EditableText = (props: EditableTextProps) => {
|
|||
value={value}
|
||||
placeholder={props.placeholder}
|
||||
className={props.className}
|
||||
onCancel={props.onBlur}
|
||||
/>
|
||||
{!props.hideEditIcon && !props.updating && !isEditing && (
|
||||
<EditPen src={Edit} alt="Edit pen" />
|
||||
)}
|
||||
{!props.minimal &&
|
||||
!props.hideEditIcon &&
|
||||
!props.updating &&
|
||||
!isEditing && <EditPen src={Edit} alt="Edit pen" />}
|
||||
</TextContainer>
|
||||
</ErrorTooltip>
|
||||
</EditableTextWrapper>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
import React, { Context, createContext, ReactNode } from "react";
|
||||
import { connect } from "react-redux";
|
||||
|
||||
import { AppState } from "reducers";
|
||||
|
||||
import { WidgetOperation } from "widgets/BaseWidget";
|
||||
|
||||
import { updateWidget } from "actions/pageActions";
|
||||
|
|
@ -13,7 +11,6 @@ import { ExecuteActionPayload } from "constants/ActionConstants";
|
|||
import { RenderModes } from "constants/WidgetConstants";
|
||||
import { OccupiedSpace } from "constants/editorConstants";
|
||||
|
||||
import { getOccupiedSpaces } from "selectors/editorSelectors";
|
||||
import {
|
||||
resetChildrenMetaProperty,
|
||||
updateWidgetMetaProperty,
|
||||
|
|
@ -52,7 +49,6 @@ const EditorContextProvider = (props: EditorContextProviderProps) => {
|
|||
updateWidget,
|
||||
updateWidgetProperty,
|
||||
updateWidgetMetaProperty,
|
||||
occupiedSpaces,
|
||||
disableDrag,
|
||||
children,
|
||||
resetChildrenMetaProperty,
|
||||
|
|
@ -64,7 +60,6 @@ const EditorContextProvider = (props: EditorContextProviderProps) => {
|
|||
updateWidget,
|
||||
updateWidgetProperty,
|
||||
updateWidgetMetaProperty,
|
||||
occupiedSpaces,
|
||||
disableDrag,
|
||||
resetChildrenMetaProperty,
|
||||
}}
|
||||
|
|
@ -74,18 +69,6 @@ const EditorContextProvider = (props: EditorContextProviderProps) => {
|
|||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* TODO<Satbir>: If a property is created here, it is only available
|
||||
* in editor mode. If you need a property in published app, it
|
||||
* has to be copied in src/pages/AppViewer/index.tsx file as well.
|
||||
* Rework to avoid duplicating the property.
|
||||
*/
|
||||
const mapStateToProps = (state: AppState) => {
|
||||
return {
|
||||
occupiedSpaces: getOccupiedSpaces(state),
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = (dispatch: any) => {
|
||||
return {
|
||||
updateWidgetProperty: (
|
||||
|
|
@ -122,7 +105,4 @@ const mapDispatchToProps = (dispatch: any) => {
|
|||
};
|
||||
};
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps,
|
||||
)(EditorContextProvider);
|
||||
export default connect(null, mapDispatchToProps)(EditorContextProvider);
|
||||
|
|
|
|||
|
|
@ -1,54 +1,82 @@
|
|||
import React, { useRef, useEffect, MutableRefObject } from "react";
|
||||
import React, {
|
||||
useRef,
|
||||
useEffect,
|
||||
MutableRefObject,
|
||||
forwardRef,
|
||||
Ref,
|
||||
} from "react";
|
||||
import styled from "styled-components";
|
||||
import Prism from "prismjs";
|
||||
import themes from "./themes";
|
||||
import { Skin } from "constants/DefaultTheme";
|
||||
|
||||
// TODO(abhinav): See if this can be re-used in other places.
|
||||
export enum SKINS {
|
||||
LIGHT = "LIGHT",
|
||||
DARK = "DARK",
|
||||
}
|
||||
// TODO(abhinav): This is rudimentary. Enhance it.
|
||||
Prism.languages["appsmith-binding"] = {
|
||||
punctuation: {
|
||||
pattern: /^{{|}}$/,
|
||||
},
|
||||
property: {
|
||||
pattern: /(\.\w+)/,
|
||||
},
|
||||
};
|
||||
|
||||
const StyledCode = styled.div<{ skin: SKINS }>`
|
||||
${props => (props.skin === SKINS.DARK ? themes.DARK : themes.LIGHT)}
|
||||
const StyledCode = styled.div<{ skin: Skin }>`
|
||||
position: relative;
|
||||
${props => (props.skin === Skin.DARK ? themes.DARK : themes.LIGHT)};
|
||||
padding: 0 0px;
|
||||
|
||||
}
|
||||
`;
|
||||
|
||||
/* When adding an entry please make sure to include it in the craco.common.config.js as well */
|
||||
export enum SYNTAX_HIGHLIGHTING_SUPPORTED_LANGUAGES {
|
||||
JAVASCRIPT = "language-javascript", // Please note that we're using the CSS class name required by prismjs.
|
||||
JAVASCRIPT = "language-javascript",
|
||||
APPSMITH = "language-appsmith-binding", // Please note that we're using the CSS class name required by prismjs.
|
||||
}
|
||||
|
||||
type HighlightedCodeProps = {
|
||||
codeText: string;
|
||||
language?: SYNTAX_HIGHLIGHTING_SUPPORTED_LANGUAGES;
|
||||
skin?: SKINS;
|
||||
skin?: Skin;
|
||||
multiline?: boolean;
|
||||
onClick?: () => void;
|
||||
className?: string;
|
||||
};
|
||||
/* eslint-disable react/display-name */
|
||||
export const HighlightedCode = forwardRef(
|
||||
(props: HighlightedCodeProps, ref: Ref<HTMLDivElement>) => {
|
||||
const codeRef: MutableRefObject<HTMLElement | null> = useRef(null);
|
||||
|
||||
export const HighlightedCode = (props: HighlightedCodeProps) => {
|
||||
const codeBlockRef: MutableRefObject<HTMLElement | null> = useRef(null);
|
||||
// Highlight when component renders with new props.
|
||||
// Skin is irrelevant here, as it only uses css.
|
||||
// Skinning is handled in StyledCode component.
|
||||
useEffect(() => {
|
||||
if (codeRef.current) {
|
||||
// When this is run, the code text is tokenized
|
||||
// into HTML on which the theme CSS is applied
|
||||
Prism.highlightElement(codeRef.current);
|
||||
}
|
||||
}, [props.codeText, props.language, codeRef]);
|
||||
|
||||
// Highlight when component renders with new props.
|
||||
// Skin is irrelevant here, as it only uses css.
|
||||
// Skinning is handled in StyledCode component.
|
||||
useEffect(() => {
|
||||
if (codeBlockRef.current) {
|
||||
// When this is run, the code text is tokenized
|
||||
// into HTML on which the theme CSS is applied
|
||||
Prism.highlightElement(codeBlockRef.current);
|
||||
}
|
||||
}, [props.codeText, props.language]);
|
||||
// Set the default language to javascript if not provided.
|
||||
const language =
|
||||
props.language || SYNTAX_HIGHLIGHTING_SUPPORTED_LANGUAGES.JAVASCRIPT;
|
||||
|
||||
// Set the default language to javascript if not provided.
|
||||
const language =
|
||||
props.language || SYNTAX_HIGHLIGHTING_SUPPORTED_LANGUAGES.JAVASCRIPT;
|
||||
|
||||
return (
|
||||
<StyledCode skin={props.skin || SKINS.DARK}>
|
||||
<code ref={codeBlockRef} className={language}>
|
||||
{props.codeText}
|
||||
</code>
|
||||
</StyledCode>
|
||||
);
|
||||
};
|
||||
return (
|
||||
<StyledCode
|
||||
skin={props.skin || Skin.DARK}
|
||||
onClick={props.onClick}
|
||||
ref={ref}
|
||||
className={props.className}
|
||||
>
|
||||
{!props.multiline && (
|
||||
<code ref={codeRef} className={language}>
|
||||
{props.codeText}
|
||||
</code>
|
||||
)}
|
||||
</StyledCode>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
export default HighlightedCode;
|
||||
|
|
|
|||
|
|
@ -243,7 +243,7 @@ export const DARK = css`
|
|||
.token.constant,
|
||||
.token.symbol,
|
||||
.token.builtin {
|
||||
color: hsl(53, 89%, 79%); /* #F9EE98 */
|
||||
color: #29cca3;
|
||||
}
|
||||
|
||||
.token.attr-name,
|
||||
|
|
|
|||
|
|
@ -2,30 +2,22 @@ import React from "react";
|
|||
import styled from "styled-components";
|
||||
import { NavLink } from "react-router-dom";
|
||||
import AnalyticsUtil from "utils/AnalyticsUtil";
|
||||
import NotificationIcon from "components/designSystems/appsmith/NotificationIcon";
|
||||
import { theme } from "constants/DefaultTheme";
|
||||
import { Colors } from "constants/Colors";
|
||||
|
||||
type MenuBarItemProps = {
|
||||
icon: Function;
|
||||
path: string;
|
||||
title: string;
|
||||
exact: boolean;
|
||||
exact?: boolean;
|
||||
width: number;
|
||||
height: number;
|
||||
external?: boolean;
|
||||
className?: string;
|
||||
highlight?: boolean;
|
||||
onClick?: Function;
|
||||
isActive: (currentPath: string, expectedPath: string) => boolean;
|
||||
};
|
||||
|
||||
// const AnmiatedNotificationIcon = <NotificationIcon pla></NotificationIcon>
|
||||
|
||||
const StyledNotificationIcon = styled(NotificationIcon)`
|
||||
position: absolute;
|
||||
top: -4px;
|
||||
right: -3px;
|
||||
`;
|
||||
|
||||
type Props = MenuBarItemProps;
|
||||
|
||||
const IconContainer = styled.div<{
|
||||
|
|
@ -39,8 +31,8 @@ const IconContainer = styled.div<{
|
|||
margin-bottom: 5px;
|
||||
background-color: ${props => props.theme.colors.menuButtonBGInactive};
|
||||
border-radius: ${props => props.theme.radii[1]}px;
|
||||
height: ${props => props.height}px;
|
||||
width: ${props => props.width}px;
|
||||
width: ${props => props.width + 8}px;
|
||||
height: ${props => props.width + 8}px;
|
||||
svg path {
|
||||
fill: ${props => props.theme.colors.menuIconColorInactive};
|
||||
}
|
||||
|
|
@ -57,16 +49,14 @@ const ItemContainer = styled.div`
|
|||
color: ${props => props.theme.colors.textOnDarkBG};
|
||||
font-size: ${props => props.theme.fontSizes[1]}px;
|
||||
cursor: pointer;
|
||||
background-color: ${props => props.theme.colors.navBG};
|
||||
&:hover {
|
||||
background-color: ${props => props.theme.colors.paneBG};
|
||||
background: ${Colors.TUNDORA};
|
||||
text-decoration: none;
|
||||
}
|
||||
color: ${props => props.theme.colors.menuButtonBGInactive};
|
||||
&.active {
|
||||
background-color: ${props => props.theme.colors.paneBG};
|
||||
background: ${Colors.TUNDORA};
|
||||
color: ${props => props.theme.colors.textOnDarkBG};
|
||||
${IconContainer} {
|
||||
& > div {
|
||||
background-color: ${props => props.theme.colors.primaryOld};
|
||||
svg path {
|
||||
fill: ${props => props.theme.colors.textOnDarkBG};
|
||||
|
|
@ -82,30 +72,6 @@ const ItemContainer = styled.div`
|
|||
}
|
||||
`;
|
||||
|
||||
const Anchor = styled.a`
|
||||
width: 64px;
|
||||
display: inline-block;
|
||||
`;
|
||||
|
||||
const ExternalLink = function(props: any) {
|
||||
return (
|
||||
<Anchor
|
||||
onClick={() => {
|
||||
props.onClick && props.onClick();
|
||||
}}
|
||||
href={props.to}
|
||||
className={props.className}
|
||||
target="_blank"
|
||||
>
|
||||
{props.children}
|
||||
</Anchor>
|
||||
);
|
||||
};
|
||||
|
||||
const DetailsContainer = styled.div`
|
||||
position: relative;
|
||||
`;
|
||||
|
||||
class NavBarItem extends React.Component<Props> {
|
||||
render(): React.ReactNode {
|
||||
const {
|
||||
|
|
@ -115,16 +81,18 @@ class NavBarItem extends React.Component<Props> {
|
|||
exact,
|
||||
width,
|
||||
height,
|
||||
external,
|
||||
highlight,
|
||||
onClick,
|
||||
isActive,
|
||||
} = this.props;
|
||||
const Link = external ? ExternalLink : NavLink;
|
||||
|
||||
return (
|
||||
<ItemContainer>
|
||||
<Link
|
||||
<NavLink
|
||||
exact={exact}
|
||||
to={path}
|
||||
isActive={(match, location) => {
|
||||
return isActive(path, location.pathname);
|
||||
}}
|
||||
className={this.props.className}
|
||||
onClick={() => {
|
||||
onClick && onClick();
|
||||
|
|
@ -133,21 +101,11 @@ class NavBarItem extends React.Component<Props> {
|
|||
});
|
||||
}}
|
||||
>
|
||||
<DetailsContainer>
|
||||
<IconContainer width={width} height={height}>
|
||||
{icon({ width: width - 8, height: height - 8 })}
|
||||
</IconContainer>
|
||||
<span>{title}</span>
|
||||
{highlight && (
|
||||
<StyledNotificationIcon
|
||||
animate
|
||||
width={9}
|
||||
height={9}
|
||||
color={theme.colors.primaryOld}
|
||||
/>
|
||||
)}
|
||||
</DetailsContainer>
|
||||
</Link>
|
||||
<IconContainer width={width} height={height}>
|
||||
{icon({ width, height })}
|
||||
</IconContainer>
|
||||
<span>{title}</span>
|
||||
</NavLink>
|
||||
</ItemContainer>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useContext, useRef } from "react";
|
||||
import React, { useContext, useRef, memo } from "react";
|
||||
import { XYCoord } from "react-dnd";
|
||||
import { ContainerWidgetProps } from "widgets/ContainerWidget";
|
||||
|
||||
|
|
@ -38,16 +38,19 @@ import {
|
|||
import AnalyticsUtil from "utils/AnalyticsUtil";
|
||||
import { scrollElementIntoParentCanvasView } from "utils/helpers";
|
||||
import { getNearestParentCanvas } from "utils/generators";
|
||||
import { getOccupiedSpaces } from "selectors/editorSelectors";
|
||||
|
||||
export type ResizableComponentProps = ContainerWidgetProps<WidgetProps> & {
|
||||
paddingOffset: number;
|
||||
};
|
||||
|
||||
/* eslint-disable react/display-name */
|
||||
export const ResizableComponent = (props: ResizableComponentProps) => {
|
||||
export const ResizableComponent = memo((props: ResizableComponentProps) => {
|
||||
const resizableRef = useRef<HTMLDivElement>(null);
|
||||
// Fetch information from the context
|
||||
const { updateWidget, occupiedSpaces } = useContext(EditorContext);
|
||||
const { updateWidget } = useContext(EditorContext);
|
||||
const occupiedSpaces = useSelector(getOccupiedSpaces);
|
||||
|
||||
const { updateDropTargetRows, persistDropTargetRows } = useContext(
|
||||
DropTargetContext,
|
||||
);
|
||||
|
|
@ -56,10 +59,10 @@ export const ResizableComponent = (props: ResizableComponentProps) => {
|
|||
const { selectWidget } = useWidgetSelection();
|
||||
const { setIsResizing } = useWidgetDragResize();
|
||||
const selectedWidget = useSelector(
|
||||
(state: AppState) => state.ui.editor.selectedWidget,
|
||||
(state: AppState) => state.ui.widgetDragResize.selectedWidget,
|
||||
);
|
||||
const focusedWidget = useSelector(
|
||||
(state: AppState) => state.ui.editor.focusedWidget,
|
||||
(state: AppState) => state.ui.widgetDragResize.focusedWidget,
|
||||
);
|
||||
|
||||
const isDragging = useSelector(
|
||||
|
|
@ -275,6 +278,6 @@ export const ResizableComponent = (props: ResizableComponentProps) => {
|
|||
</VisibilityContainer>
|
||||
</Resizable>
|
||||
);
|
||||
};
|
||||
});
|
||||
|
||||
export default ResizableComponent;
|
||||
|
|
|
|||
|
|
@ -1,108 +1,32 @@
|
|||
import React from "react";
|
||||
import { Switch } from "react-router";
|
||||
import React, { memo } from "react";
|
||||
import { Switch, Route } from "react-router";
|
||||
import styled from "styled-components";
|
||||
import {
|
||||
API_EDITOR_URL,
|
||||
BUILDER_URL,
|
||||
API_EDITOR_ID_URL,
|
||||
PAGE_LIST_EDITOR_URL,
|
||||
DATA_SOURCES_EDITOR_URL,
|
||||
DATA_SOURCES_EDITOR_ID_URL,
|
||||
QUERIES_EDITOR_URL,
|
||||
QUERIES_EDITOR_ID_URL,
|
||||
getCurlImportPageURL,
|
||||
API_EDITOR_URL_WITH_SELECTED_PAGE_ID,
|
||||
getProviderTemplatesURL,
|
||||
} from "constants/routes";
|
||||
|
||||
import { WIDGETS_URL } from "constants/routes";
|
||||
import WidgetSidebar from "pages/Editor/WidgetSidebar";
|
||||
import QuerySidebar from "pages/Editor/QuerySidebar";
|
||||
import DataSourceSidebar from "pages/Editor/DataSourceSidebar";
|
||||
import ApiSidebar from "pages/Editor/ApiSidebar";
|
||||
import PageListSidebar from "pages/Editor/PageListSidebar";
|
||||
import AppRoute from "pages/common/AppRoute";
|
||||
import ExplorerSidebar from "pages/Editor/Explorer";
|
||||
|
||||
const SidebarWrapper = styled.div`
|
||||
background-color: ${props => props.theme.colors.paneBG};
|
||||
padding: 5px 0;
|
||||
padding: 0px 0 0 6px;
|
||||
color: ${props => props.theme.colors.textOnDarkBG};
|
||||
overflow-y: auto;
|
||||
`;
|
||||
|
||||
export const Sidebar = () => {
|
||||
export const Sidebar = memo(() => {
|
||||
return (
|
||||
<SidebarWrapper className="t--sidebar">
|
||||
<Switch>
|
||||
<AppRoute
|
||||
<Route
|
||||
exact
|
||||
path={BUILDER_URL}
|
||||
path={WIDGETS_URL()}
|
||||
component={WidgetSidebar}
|
||||
name={"WidgetSidebar"}
|
||||
/>
|
||||
<AppRoute
|
||||
exact
|
||||
path={API_EDITOR_URL()}
|
||||
component={ApiSidebar}
|
||||
name={"ApiSidebar"}
|
||||
/>
|
||||
<AppRoute
|
||||
exact
|
||||
path={API_EDITOR_ID_URL()}
|
||||
component={ApiSidebar}
|
||||
name={"ApiSidebar"}
|
||||
/>
|
||||
<AppRoute
|
||||
exact
|
||||
path={PAGE_LIST_EDITOR_URL()}
|
||||
component={PageListSidebar}
|
||||
name={"PageListSidebar"}
|
||||
/>
|
||||
<AppRoute
|
||||
exact
|
||||
path={getCurlImportPageURL()}
|
||||
component={ApiSidebar}
|
||||
name={"ApiSidebar"}
|
||||
/>
|
||||
<AppRoute
|
||||
exact
|
||||
path={getProviderTemplatesURL()}
|
||||
component={ApiSidebar}
|
||||
name={"ApiSidebar"}
|
||||
/>
|
||||
|
||||
<AppRoute
|
||||
exact
|
||||
path={API_EDITOR_URL_WITH_SELECTED_PAGE_ID()}
|
||||
component={ApiSidebar}
|
||||
name={"ApiSidebar"}
|
||||
/>
|
||||
<AppRoute
|
||||
exact
|
||||
path={QUERIES_EDITOR_URL()}
|
||||
component={QuerySidebar}
|
||||
name={"QuerySidebar"}
|
||||
/>
|
||||
<AppRoute
|
||||
exact
|
||||
path={QUERIES_EDITOR_ID_URL()}
|
||||
component={QuerySidebar}
|
||||
name={"QuerySidebar"}
|
||||
/>
|
||||
<AppRoute
|
||||
exact
|
||||
path={DATA_SOURCES_EDITOR_URL()}
|
||||
component={DataSourceSidebar}
|
||||
name="DataSourceSidebar"
|
||||
/>
|
||||
<AppRoute
|
||||
exact
|
||||
path={DATA_SOURCES_EDITOR_ID_URL()}
|
||||
component={DataSourceSidebar}
|
||||
name="DataSourceSidebar"
|
||||
/>
|
||||
<Route component={ExplorerSidebar} name={"ExplorerSidebar"} />
|
||||
</Switch>
|
||||
</SidebarWrapper>
|
||||
);
|
||||
};
|
||||
});
|
||||
|
||||
Sidebar.displayName = "Sidebar";
|
||||
|
||||
export default Sidebar;
|
||||
|
|
|
|||
2
app/client/src/components/editorComponents/Tooltip.tsx
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
import { Tooltip } from "@blueprintjs/core";
|
||||
export default Tooltip;
|
||||
|
|
@ -53,10 +53,10 @@ export const WidgetNameComponent = (props: WidgetNameComponentProps) => {
|
|||
(state: AppState) => state.ui.propertyPane,
|
||||
);
|
||||
const selectedWidget = useSelector(
|
||||
(state: AppState) => state.ui.editor.selectedWidget,
|
||||
(state: AppState) => state.ui.widgetDragResize.selectedWidget,
|
||||
);
|
||||
const focusedWidget = useSelector(
|
||||
(state: AppState) => state.ui.editor.focusedWidget,
|
||||
(state: AppState) => state.ui.widgetDragResize.focusedWidget,
|
||||
);
|
||||
|
||||
const isResizing = useSelector(
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import React from "react";
|
||||
import _ from "lodash";
|
||||
import React, { useState } from "react";
|
||||
import { find, noop } from "lodash";
|
||||
import { DropdownOption } from "widgets/DropdownWidget";
|
||||
import {
|
||||
StyledPopover,
|
||||
|
|
@ -11,6 +11,7 @@ import {
|
|||
Button as BlueprintButton,
|
||||
PopoverInteractionKind,
|
||||
PopoverPosition,
|
||||
IPopoverSharedProps,
|
||||
} from "@blueprintjs/core";
|
||||
import { IconNames } from "@blueprintjs/icons";
|
||||
|
||||
|
|
@ -33,6 +34,8 @@ type TreeDropdownProps = {
|
|||
) => React.ReactNode;
|
||||
displayValue?: string;
|
||||
toggle?: React.ReactNode;
|
||||
className?: string;
|
||||
modifiers?: IPopoverSharedProps["modifiers"];
|
||||
};
|
||||
|
||||
function getSelectedOption(
|
||||
|
|
@ -50,7 +53,7 @@ function getSelectedOption(
|
|||
if (option.value === selectedValue) {
|
||||
selectedOption = option;
|
||||
} else {
|
||||
const childOption = _.find(option.children, {
|
||||
const childOption = find(option.children, {
|
||||
value: selectedValue,
|
||||
});
|
||||
if (childOption) {
|
||||
|
|
@ -78,6 +81,8 @@ export default function TreeDropdown(props: TreeDropdownProps) {
|
|||
optionTree,
|
||||
);
|
||||
|
||||
const [isOpen, setIsOpen] = useState<boolean>(false);
|
||||
|
||||
const handleSelect = (option: TreeDropdownOption) => {
|
||||
if (option.onSelect) {
|
||||
option.onSelect(option, props.onSelect);
|
||||
|
|
@ -97,13 +102,22 @@ export default function TreeDropdown(props: TreeDropdownProps) {
|
|||
active={isSelected}
|
||||
key={option.value}
|
||||
icon={option.id === "create" ? "plus" : undefined}
|
||||
onClick={option.children ? _.noop : () => handleSelect(option)}
|
||||
onClick={
|
||||
option.children
|
||||
? noop
|
||||
: (e: any) => {
|
||||
handleSelect(option);
|
||||
setIsOpen(false);
|
||||
e.stopPropagation();
|
||||
}
|
||||
}
|
||||
text={option.label}
|
||||
intent={option.intent}
|
||||
popoverProps={{
|
||||
minimal: true,
|
||||
interactionKind: PopoverInteractionKind.CLICK,
|
||||
position: PopoverPosition.RIGHT,
|
||||
targetProps: { onClick: (e: any) => e.stopPropagation() },
|
||||
}}
|
||||
>
|
||||
{option.children && option.children.map(renderTreeOption)}
|
||||
|
|
@ -130,10 +144,21 @@ export default function TreeDropdown(props: TreeDropdownProps) {
|
|||
);
|
||||
return (
|
||||
<StyledPopover
|
||||
usePortal={true}
|
||||
minimal={true}
|
||||
isOpen={isOpen}
|
||||
minimal
|
||||
content={menuItems}
|
||||
position={PopoverPosition.AUTO_END}
|
||||
className={props.className}
|
||||
modifiers={props.modifiers}
|
||||
onClose={() => {
|
||||
setIsOpen(false);
|
||||
}}
|
||||
targetProps={{
|
||||
onClick: (e: any) => {
|
||||
setIsOpen(true);
|
||||
e.stopPropagation();
|
||||
},
|
||||
}}
|
||||
>
|
||||
{toggle ? toggle : defaultToggle}
|
||||
</StyledPopover>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useEffect } from "react";
|
||||
import React from "react";
|
||||
import { FieldArray, WrappedFieldArrayProps } from "redux-form";
|
||||
import styled from "styled-components";
|
||||
import { Icon } from "@blueprintjs/core";
|
||||
|
|
@ -20,14 +20,6 @@ const FormRowWithLabel = styled(FormRow)`
|
|||
`;
|
||||
|
||||
const KeyValueRow = (props: Props & WrappedFieldArrayProps) => {
|
||||
useEffect(() => {
|
||||
// Always maintain 2 rows
|
||||
if (props.fields.length < 2 && props.pushFields !== false) {
|
||||
for (let i = props.fields.length; i < 2; i += 1) {
|
||||
props.fields.push({ key: "", value: "" });
|
||||
}
|
||||
}
|
||||
}, [props.fields, props.pushFields]);
|
||||
return (
|
||||
<React.Fragment>
|
||||
{props.fields.length && (
|
||||
|
|
@ -152,7 +144,6 @@ type Props = {
|
|||
const KeyValueFieldArray = (props: Props) => {
|
||||
return (
|
||||
<FieldArray
|
||||
name={props.name}
|
||||
component={KeyValueRow}
|
||||
rerenderOnEveryChange={false}
|
||||
{...props}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,20 @@
|
|||
import { RestAction } from "entities/Action";
|
||||
import { DEFAULT_ACTION_TIMEOUT } from "constants/ApiConstants";
|
||||
import { zipObject } from "lodash";
|
||||
|
||||
export const HTTP_METHODS = ["GET", "POST", "PUT", "DELETE", "PATCH"];
|
||||
const HTTP_METHOD_COLORS = [
|
||||
"#457AE6",
|
||||
"#EABB0C",
|
||||
"#5BB749",
|
||||
"#E22C2C",
|
||||
"#6D6D6D",
|
||||
];
|
||||
|
||||
export const HTTP_METHOD_COLOR_MAP = zipObject(
|
||||
HTTP_METHODS,
|
||||
HTTP_METHOD_COLORS,
|
||||
);
|
||||
|
||||
export const HTTP_METHOD_OPTIONS = HTTP_METHODS.map(method => ({
|
||||
label: method,
|
||||
|
|
|
|||
|
|
@ -19,9 +19,14 @@ export const Colors: Record<string, string> = {
|
|||
|
||||
BLACK: "#000000",
|
||||
BLACK_PEARL: "#040627",
|
||||
CODE_GRAY: "#090707",
|
||||
SHARK: "#21282C",
|
||||
SHARK2: "#232324",
|
||||
MINE_SHAFT: "#262626",
|
||||
DEEP_SPACE: "#272E32",
|
||||
OUTER_SPACE: "#363E44",
|
||||
TUNDORA: "#404040",
|
||||
DOVE_GRAY: "#6D6D6D",
|
||||
SLATE_GRAY: "#768896",
|
||||
PORCELAIN: "#EBEEF0",
|
||||
HIT_GRAY: "#A1ACB3",
|
||||
|
|
@ -33,6 +38,7 @@ export const Colors: Record<string, string> = {
|
|||
GREEN: "#29CCA3",
|
||||
JUNGLE_GREEN: "#24BA91",
|
||||
JUNGLE_GREEN_DARKER: "#30A481",
|
||||
EUCALYPTUS: "#218358",
|
||||
RED: "#CE4257",
|
||||
ERROR_RED: "#E22C2C",
|
||||
PURPLE: "#6871EF",
|
||||
|
|
@ -48,6 +54,7 @@ export const Colors: Record<string, string> = {
|
|||
BLUE_CHARCOAL: "#23292E",
|
||||
TROUT: "#4C565E",
|
||||
JAFFA_DARK: "#EF7541",
|
||||
TIA_MARIA: "#CB4810",
|
||||
SOLID_MERCURY: "#E5E5E5",
|
||||
TROUT_DARK: "#535B62",
|
||||
ALABASTER: "#F9F8F8",
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ import * as styledComponents from "styled-components";
|
|||
import { Colors, Color } from "./Colors";
|
||||
import * as FontFamilies from "./Fonts";
|
||||
import tinycolor from "tinycolor2";
|
||||
import _ from "lodash";
|
||||
import { Classes } from "@blueprintjs/core";
|
||||
import { AlertIcons } from "icons/AlertIcons";
|
||||
import { IconProps } from "constants/IconConstants";
|
||||
|
|
@ -42,6 +41,25 @@ export enum Skin {
|
|||
DARK,
|
||||
}
|
||||
|
||||
export const scrollbarDark = css`
|
||||
scrollbar-color: ${props => props.theme.colors.paneCard}
|
||||
${props => props.theme.colors.paneBG};
|
||||
scrollbar-width: thin;
|
||||
&::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-track {
|
||||
box-shadow: inset 0 0 6px
|
||||
${props => getColorWithOpacity(props.theme.colors.paneBG, 0.3)};
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background-color: ${props => props.theme.colors.paneCard};
|
||||
border-radius: ${props => props.theme.radii[1]}px;
|
||||
}
|
||||
`;
|
||||
|
||||
export const BlueprintControlTransform = css`
|
||||
&& {
|
||||
.${Classes.CONTROL} {
|
||||
|
|
@ -366,9 +384,11 @@ export const getColorWithOpacity = (color: Color, opacity: number) => {
|
|||
|
||||
export const getBorderCSSShorthand = (border?: ThemeBorder): string => {
|
||||
const values: string[] = [];
|
||||
_.forIn(border, (value, key) => {
|
||||
values.push(key === "thickness" ? value + "px" : value);
|
||||
});
|
||||
if (border) {
|
||||
for (const [key, value] of Object.entries(border)) {
|
||||
values.push(key === "thickness" ? value + "px" : value.toString());
|
||||
}
|
||||
}
|
||||
return values.join(" ");
|
||||
};
|
||||
|
||||
|
|
@ -570,12 +590,8 @@ export const theme: Theme = {
|
|||
cmBacground: Colors.BLUE_CHARCOAL,
|
||||
lightningborder: Colors.ALABASTER,
|
||||
},
|
||||
lineHeights: [0, 14, 18, 22, 24, 28, 36, 48, 64, 80],
|
||||
fonts: [
|
||||
FontFamilies.DMSans,
|
||||
FontFamilies.AppsmithWidget,
|
||||
FontFamilies.FiraCode,
|
||||
],
|
||||
lineHeights: [0, 14, 16, 18, 22, 24, 28, 36, 48, 64, 80],
|
||||
fonts: [FontFamilies.DMSans, FontFamilies.FiraCode],
|
||||
borders: [
|
||||
{
|
||||
thickness: 1,
|
||||
|
|
|
|||
2
app/client/src/constants/Explorer.ts
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
export const ENTITY_EXPLORER_SEARCH_ID = "entity-explorer-search";
|
||||
export const ENTITY_EXPLORER_SEARCH_LOCATION_HASH = "#search";
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
export const DMSans = "DM Sans";
|
||||
export const AppsmithWidget = "widget-icons";
|
||||
export const FiraCode = '"Fira code", "Fira Mono", monospace';
|
||||
export const HomePageRedesign =
|
||||
'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"';
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ export type IconProps = {
|
|||
background?: Color;
|
||||
onClick?: (e?: any) => void;
|
||||
className?: string;
|
||||
keepColors?: boolean;
|
||||
};
|
||||
|
||||
export const IconWrapper = styled.div<IconProps>`
|
||||
|
|
@ -20,11 +21,13 @@ export const IconWrapper = styled.div<IconProps>`
|
|||
svg {
|
||||
width: ${props => props.width || props.theme.fontSizes[7]}px;
|
||||
height: ${props => props.height || props.theme.fontSizes[7]}px;
|
||||
path {
|
||||
fill: ${props => props.color || props.theme.colors.textOnDarkBG};
|
||||
${props =>
|
||||
!props.keepColors
|
||||
? `path {
|
||||
fill: ${props.color || props.theme.colors.textOnDarkBG};
|
||||
}
|
||||
circle {
|
||||
fill: ${props => props.background || props.theme.colors.paneBG};
|
||||
}
|
||||
}
|
||||
fill: ${props.background || props.theme.colors.paneBG};
|
||||
}`
|
||||
: ""}
|
||||
`;
|
||||
|
|
|
|||
|
|
@ -232,13 +232,20 @@ export const ReduxActionTypes: { [key: string]: string } = {
|
|||
CHANGE_ORG_USER_ROLE_ERROR: "CHANGE_ORG_USER_ROLE_ERROR",
|
||||
SET_DEFAULT_REFINEMENT: "SET_DEFAULT_REFINEMENT",
|
||||
SET_HELP_MODAL_OPEN: "SET_HELP_MODAL_OPEN",
|
||||
SAVE_API_NAME: "SAVE_API_NAME",
|
||||
SAVE_API_NAME_SUCCESS: "SAVE_API_NAME_SUCCESS",
|
||||
SAVE_ACTION_NAME_INIT: "SAVE_ACTION_NAME_INIT",
|
||||
SAVE_ACTION_NAME_SUCCESS: "SAVE_ACTION_NAME_SUCCESS",
|
||||
UPDATE_API_NAME_DRAFT: "UPDATE_API_NAME_DRAFT",
|
||||
SET_ACTION_PROPERTY: "SET_ACTION_PROPERTY",
|
||||
UPDATE_ACTION_PROPERTY: "UPDATE_ACTION_PROPERTY",
|
||||
SWITCH_DATASOURCE: "SWITCH_DATASOURCE",
|
||||
INIT_EXPLORER_ENTITY_NAME_EDIT: "INIT_EXPLORER_ENTITY_NAME_EDIT",
|
||||
FETCH_ACTIONS_VIEW_MODE_INIT: "FETCH_ACTIONS_VIEW_MODE_INIT",
|
||||
FETCH_ACTIONS_VIEW_MODE_SUCCESS: "FETCH_ACTIONS_VIEW_MODE_SUCCESS",
|
||||
END_EXPLORER_ENTITY_NAME_EDIT: "END_EXPLORER_ENTITY_NAME_EDIT",
|
||||
POPULATE_PAGEDSLS_INIT: "POPULATE_PAGEDSLS_INIT",
|
||||
POPULATE_PAGEDSLS_SUCCESS: "POPULATE_PAGEDSLS_SUCCESS",
|
||||
FETCH_PAGE_DSL_INIT: "FETCH_PAGE_DSL_INIT",
|
||||
FETCH_PAGE_DSL_SUCCESS: "FETCH_PAGE_DSL_SUCCESS",
|
||||
SET_URL_DATA: "SET_URL_DATA",
|
||||
};
|
||||
|
||||
|
|
@ -319,11 +326,14 @@ export const ReduxActionErrorTypes: { [key: string]: string } = {
|
|||
CREATE_MODAL_ERROR: "CREATE_MODAL_ERROR",
|
||||
FETCH_PROVIDER_DETAILS_BY_PROVIDER_ID_ERROR:
|
||||
"FETCH_PROVIDER_DETAILS_BY_PROVIDER_ID_ERROR",
|
||||
SAVE_API_NAME_ERROR: "SAVE_API_NAME_ERROR",
|
||||
SAVE_ACTION_NAME_ERROR: "SAVE_ACTION_NAME_ERROR",
|
||||
FETCH_USER_APPLICATIONS_ORGS_ERROR: "FETCH_USER_APPLICATIONS_ORGS_ERROR",
|
||||
FETCH_ALL_USERS_ERROR: "FETCH_ALL_USERS_ERROR",
|
||||
FETCH_ALL_ROLES_ERROR: "FETCH_ALL_ROLES_ERROR",
|
||||
FETCH_ACTIONS_VIEW_MODE_ERROR: "FETCH_ACTION_VIEW_MODE_ERROR",
|
||||
SAVE_API_NAME_ERROR: "SAVE_API_NAME_ERROR",
|
||||
POPULATE_PAGEDSLS_ERROR: "POPULATE_PAGEDSLS_ERROR",
|
||||
FETCH_PAGE_DSL_ERROR: "FETCH_PAGE_DSL_ERROR",
|
||||
};
|
||||
|
||||
export const ReduxFormActionTypes: { [key: string]: string } = {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
import { MenuIcons } from "icons/MenuIcons";
|
||||
|
||||
export const BASE_URL = "/";
|
||||
export const ORG_URL = "/org";
|
||||
export const PAGE_NOT_FOUND_URL = "/404";
|
||||
|
|
@ -51,6 +49,19 @@ 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",
|
||||
|
|
@ -164,45 +175,6 @@ export const QUERY_EDITOR_URL_WITH_SELECTED_PAGE_ID = (
|
|||
)}/queries?importTo=${selectedPageId}`;
|
||||
};
|
||||
|
||||
export const EDITOR_ROUTES = [
|
||||
{
|
||||
icon: MenuIcons.WIDGETS_ICON,
|
||||
path: BUILDER_PAGE_URL,
|
||||
title: "Widgets",
|
||||
className: "t--nav-link-widgets-editor",
|
||||
exact: true,
|
||||
},
|
||||
{
|
||||
icon: MenuIcons.APIS_ICON,
|
||||
path: API_EDITOR_URL,
|
||||
className: "t--nav-link-api-editor",
|
||||
title: "APIs",
|
||||
exact: false,
|
||||
},
|
||||
{
|
||||
icon: MenuIcons.QUERIES_ICON,
|
||||
className: "t--nav-link-query-editor",
|
||||
path: QUERIES_EDITOR_URL,
|
||||
title: "Queries",
|
||||
exact: false,
|
||||
},
|
||||
{
|
||||
icon: MenuIcons.DATASOURCES_ICON,
|
||||
className: "t--nav-link-datasource-editor",
|
||||
path: DATA_SOURCES_EDITOR_URL,
|
||||
title: "Datasources",
|
||||
exact: false,
|
||||
allowed: true,
|
||||
},
|
||||
{
|
||||
icon: MenuIcons.PAGES_ICON,
|
||||
path: PAGE_LIST_EDITOR_URL,
|
||||
className: "t--nav-link-manage-pages",
|
||||
title: "Pages",
|
||||
exact: true,
|
||||
},
|
||||
];
|
||||
|
||||
export const FORGOT_PASSWORD_URL = `${USER_AUTH_URL}/forgotPassword`;
|
||||
export const RESET_PASSWORD_URL = `${USER_AUTH_URL}/resetPassword`;
|
||||
export const BASE_SIGNUP_URL = `/signup`;
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import { CanvasWidgetsReduxState } from "reducers/entityReducers/canvasWidgetsRe
|
|||
import { MetaState } from "reducers/entityReducers/metaReducer";
|
||||
import { PageListPayload } from "constants/ReduxActionConstants";
|
||||
import WidgetFactory from "utils/WidgetFactory";
|
||||
import { ActionConfig, Property } from "entities/Action";
|
||||
import { ActionConfig, Property, PluginType } from "entities/Action";
|
||||
import { AuthUserState } from "@appsmith/reducers/entityReducers/authUserReducer";
|
||||
import { UrlDataState } from "@appsmith/reducers/entityReducers/urlReducer";
|
||||
|
||||
|
|
@ -38,6 +38,8 @@ export interface DataTreeAction extends Omit<ActionData, "data" | "config"> {
|
|||
data: ActionResponse["body"];
|
||||
actionId: string;
|
||||
config: Partial<ActionConfig>;
|
||||
pluginType: PluginType;
|
||||
name: string;
|
||||
run: ActionDispatcher<RunActionPayload, [string, string, string]> | {};
|
||||
dynamicBindingPathList: Property[];
|
||||
ENTITY_TYPE: ENTITY_TYPE.ACTION;
|
||||
|
|
@ -111,6 +113,8 @@ export class DataTreeFactory {
|
|||
dataTree[config.name] = {
|
||||
...a,
|
||||
actionId: config.id,
|
||||
name: config.name,
|
||||
pluginType: config.pluginType,
|
||||
config: config.actionConfiguration,
|
||||
dynamicBindingPathList,
|
||||
data: a.data ? a.data.body : {},
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import { ReactComponent as DecreaseIcon } from "assets/icons/control/decrease.sv
|
|||
import { ReactComponent as DraggableIcon } from "assets/icons/control/draggable.svg";
|
||||
import { ReactComponent as CloseIcon } from "assets/icons/control/close.svg";
|
||||
import { ReactComponent as HelpIcon } from "assets/icons/control/help.svg";
|
||||
|
||||
import { ReactComponent as CollapseIcon } from "assets/icons/control/collapse.svg";
|
||||
import { ReactComponent as PickMyLocationSelectedIcon } from "assets/icons/control/pick-location-selected.svg";
|
||||
import { ReactComponent as SettingsIcon } from "assets/icons/control/settings.svg";
|
||||
import { ReactComponent as DragIcon } from "assets/icons/control/drag.svg";
|
||||
|
|
@ -108,6 +108,11 @@ export const ControlIcons: {
|
|||
<DragIcon />
|
||||
</IconWrapper>
|
||||
),
|
||||
COLLAPSE_CONTROL: (props: IconProps) => (
|
||||
<IconWrapper {...props}>
|
||||
<CollapseIcon />
|
||||
</IconWrapper>
|
||||
),
|
||||
SORT_CONTROL: (props: IconProps) => (
|
||||
<IconWrapper {...props}>
|
||||
<SortIcon />
|
||||
|
|
|
|||
|
|
@ -4,9 +4,14 @@ import { ReactComponent as WidgetsIcon } from "assets/icons/menu/widgets.svg";
|
|||
import { ReactComponent as ApisIcon } from "assets/icons/menu/api.svg";
|
||||
import { ReactComponent as OrgIcon } from "assets/icons/menu/org.svg";
|
||||
import { ReactComponent as PagesIcon } from "assets/icons/menu/pages.svg";
|
||||
import { ReactComponent as PageIcon } from "assets/icons/menu/page.svg";
|
||||
import { ReactComponent as DataSourcesIcon } from "assets/icons/menu/data-sources.svg";
|
||||
import { ReactComponent as QueriesIcon } from "assets/icons/menu/queries.svg";
|
||||
import { ReactComponent as HomepageIcon } from "assets/icons/menu/homepage.svg";
|
||||
import { ReactComponent as ExplorerIcon } from "assets/icons/menu/explorer.svg";
|
||||
import { ReactComponent as ApisColoredIcon } from "assets/icons/menu/api-colored.svg";
|
||||
import { ReactComponent as DataSourcesColoredIcon } from "assets/icons/menu/datasource-colored.svg";
|
||||
import { ReactComponent as WidgetsColoredIcon } from "assets/icons/menu/widgets-colored.svg";
|
||||
import { Icon } from "@blueprintjs/core";
|
||||
/* eslint-disable react/display-name */
|
||||
|
||||
|
|
@ -33,6 +38,11 @@ export const MenuIcons: {
|
|||
<PagesIcon />
|
||||
</IconWrapper>
|
||||
),
|
||||
PAGE_ICON: (props: IconProps) => (
|
||||
<IconWrapper {...props}>
|
||||
<PageIcon />
|
||||
</IconWrapper>
|
||||
),
|
||||
DATASOURCES_ICON: (props: IconProps) => (
|
||||
<IconWrapper {...props}>
|
||||
<DataSourcesIcon />
|
||||
|
|
@ -48,9 +58,29 @@ export const MenuIcons: {
|
|||
<HomepageIcon />
|
||||
</IconWrapper>
|
||||
),
|
||||
EXPLORER_ICON: (props: IconProps) => (
|
||||
<IconWrapper {...props}>
|
||||
<ExplorerIcon />
|
||||
</IconWrapper>
|
||||
),
|
||||
DOCS_ICON: (props: IconProps) => (
|
||||
<IconWrapper {...props}>
|
||||
<Icon icon="help"></Icon>
|
||||
</IconWrapper>
|
||||
),
|
||||
WIDGETS_COLORED_ICON: (props: IconProps) => (
|
||||
<IconWrapper {...props}>
|
||||
<WidgetsColoredIcon />
|
||||
</IconWrapper>
|
||||
),
|
||||
APIS_COLORED_ICON: (props: IconProps) => (
|
||||
<IconWrapper {...props}>
|
||||
<ApisColoredIcon />
|
||||
</IconWrapper>
|
||||
),
|
||||
DATASOURCES_COLORED_ICON: (props: IconProps) => (
|
||||
<IconWrapper {...props}>
|
||||
<DataSourcesColoredIcon />
|
||||
</IconWrapper>
|
||||
),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React from "react";
|
||||
import React, { JSXElementConstructor } from "react";
|
||||
import { IconProps, IconWrapper } from "constants/IconConstants";
|
||||
import { ReactComponent as SpinnerIcon } from "assets/icons/widget/alert.svg";
|
||||
import { ReactComponent as ButtonIcon } from "assets/icons/widget/button.svg";
|
||||
|
|
@ -19,11 +19,11 @@ import { ReactComponent as RichTextEditorIcon } from "assets/icons/widget/rich-t
|
|||
import { ReactComponent as ChartIcon } from "assets/icons/widget/chart.svg";
|
||||
import { ReactComponent as FormIcon } from "assets/icons/widget/form.svg";
|
||||
import { ReactComponent as MapIcon } from "assets/icons/widget/map.svg";
|
||||
|
||||
import { ReactComponent as ModalIcon } from "assets/icons/widget/modal.svg";
|
||||
/* eslint-disable react/display-name */
|
||||
|
||||
export const WidgetIcons: {
|
||||
[id: string]: Function;
|
||||
[id: string]: JSXElementConstructor<IconProps>;
|
||||
} = {
|
||||
SPINNER_WIDGET: (props: IconProps) => (
|
||||
<IconWrapper {...props}>
|
||||
|
|
@ -120,6 +120,11 @@ export const WidgetIcons: {
|
|||
<MapIcon />
|
||||
</IconWrapper>
|
||||
),
|
||||
MODAL_WIDGET: (props: IconProps) => (
|
||||
<IconWrapper {...props}>
|
||||
<ModalIcon />
|
||||
</IconWrapper>
|
||||
),
|
||||
};
|
||||
|
||||
export type WidgetIcon = typeof WidgetIcons[keyof typeof WidgetIcons];
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import React from "react";
|
||||
import "./wdyr";
|
||||
import { Helmet } from "react-helmet";
|
||||
import ReactDOM from "react-dom";
|
||||
import { Provider } from "react-redux";
|
||||
|
|
|
|||
|
|
@ -219,7 +219,6 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
|
|||
detachFromLayout: true,
|
||||
canOutsideClickClose: true,
|
||||
shouldScrollContents: true,
|
||||
isVisible: false,
|
||||
widgetName: "Modal",
|
||||
children: [],
|
||||
blueprint: {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useState } from "react";
|
||||
import React from "react";
|
||||
import styled from "styled-components";
|
||||
import { Menu, Button } from "@blueprintjs/core";
|
||||
import SideNavItem, { SideNavItemProps } from "./SideNavItem";
|
||||
|
|
|
|||
|
|
@ -41,11 +41,7 @@ import Spinner from "components/editorComponents/Spinner";
|
|||
import CurlLogo from "assets/images/Curl-logo.svg";
|
||||
import { FetchProviderWithCategoryRequest } from "api/ProvidersApi";
|
||||
import { Plugin } from "api/PluginApi";
|
||||
import {
|
||||
createNewApiAction,
|
||||
setCurrentCategory,
|
||||
setLastUsedEditorPage,
|
||||
} from "actions/apiPaneActions";
|
||||
import { createNewApiAction, setCurrentCategory } from "actions/apiPaneActions";
|
||||
import { getInitialsAndColorCode } from "utils/AppsmithUtils";
|
||||
import AnalyticsUtil from "utils/AnalyticsUtil";
|
||||
import { CURL } from "constants/ApiConstants";
|
||||
|
|
@ -285,42 +281,6 @@ const CardList = styled.div`
|
|||
}
|
||||
`;
|
||||
|
||||
// const NoCollections = styled.div`
|
||||
// padding-top: 52px;
|
||||
// padding-bottom: 50px;
|
||||
// text-align: center;
|
||||
// width: 438px;
|
||||
// margin: 0 auto;
|
||||
// color: #666666;
|
||||
// font-size: 14px;
|
||||
// line-height: 24px;
|
||||
// `;
|
||||
//
|
||||
// const ImportedApisCard = styled.div`
|
||||
// flex: 1;
|
||||
// display: inline-flex;
|
||||
// flex-wrap: wrap;
|
||||
// margin-left: -10px;
|
||||
// justify-content: flex-start;
|
||||
// text-align: center;
|
||||
// border-radius: 4px;
|
||||
//
|
||||
// .importedApiIcon {
|
||||
// display: flex;
|
||||
// height: 30px;
|
||||
// width: 30px;
|
||||
// margin-right: 15px;
|
||||
// color: ${Colors.OXFORD_BLUE};
|
||||
// }
|
||||
// .eachImportedApiCard {
|
||||
// margin: 10px;
|
||||
// width: 225px;
|
||||
// height: 60px;
|
||||
// display: flex;
|
||||
// flex-wrap: wrap;
|
||||
// }
|
||||
// `;
|
||||
|
||||
const DropdownSelect = styled.div`
|
||||
font-size: 14px;
|
||||
float: right;
|
||||
|
|
@ -376,7 +336,6 @@ type ApiHomeScreenProps = {
|
|||
isSwitchingCategory: boolean;
|
||||
createNewApiAction: (pageId: string) => void;
|
||||
setCurrentCategory: (category: string) => void;
|
||||
setLastUsedEditorPage: (path: string) => void;
|
||||
previouslySetCategory: string;
|
||||
fetchProvidersError: boolean;
|
||||
};
|
||||
|
|
@ -419,7 +378,6 @@ class ApiHomeScreen extends React.Component<Props, ApiHomeScreenState> {
|
|||
page: 1,
|
||||
});
|
||||
}
|
||||
this.props.setLastUsedEditorPage(this.props.match.url);
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps: Props) {
|
||||
|
|
@ -437,8 +395,10 @@ class ApiHomeScreen extends React.Component<Props, ApiHomeScreenState> {
|
|||
}
|
||||
}
|
||||
|
||||
handleCreateNew = (params: string) => {
|
||||
const pageId = new URLSearchParams(params).get("importTo");
|
||||
handleCreateNew = () => {
|
||||
const pageId = new URLSearchParams(this.props.location.search).get(
|
||||
"importTo",
|
||||
);
|
||||
if (pageId) {
|
||||
this.props.createNewApiAction(pageId);
|
||||
}
|
||||
|
|
@ -480,7 +440,6 @@ class ApiHomeScreen extends React.Component<Props, ApiHomeScreenState> {
|
|||
} = this.props;
|
||||
const { showSearchResults } = this.state;
|
||||
|
||||
const queryParams: string = location.search;
|
||||
let destinationPageId = new URLSearchParams(location.search).get(
|
||||
"importTo",
|
||||
);
|
||||
|
|
@ -600,7 +559,7 @@ class ApiHomeScreen extends React.Component<Props, ApiHomeScreenState> {
|
|||
<Card
|
||||
interactive={false}
|
||||
className="eachCard t--createBlankApiCard"
|
||||
onClick={() => this.handleCreateNew(queryParams)}
|
||||
onClick={this.handleCreateNew}
|
||||
>
|
||||
<Icon icon="plus" iconSize={20} className="createIcon" />
|
||||
<p className="textBtn">Create new</p>
|
||||
|
|
@ -852,8 +811,6 @@ const mapDispatchToProps = (dispatch: any) => ({
|
|||
createNewApiAction: (pageId: string) => dispatch(createNewApiAction(pageId)),
|
||||
setCurrentCategory: (category: string) =>
|
||||
dispatch(setCurrentCategory(category)),
|
||||
setLastUsedEditorPage: (path: string) =>
|
||||
dispatch(setLastUsedEditorPage(path)),
|
||||
});
|
||||
|
||||
export default connect(
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import { Colors } from "constants/Colors";
|
|||
import Button from "components/editorComponents/Button";
|
||||
import CurlLogo from "assets/images/Curl-logo.svg";
|
||||
|
||||
const CurlImportFormContainer = styled.form`
|
||||
const CurlImportFormContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
|
|
@ -111,7 +111,6 @@ type Props = StateAndRouteProps &
|
|||
class CurlImportForm extends React.Component<Props> {
|
||||
render() {
|
||||
const { handleSubmit, history, isImportingCurl } = this.props;
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Header>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useEffect } from "react";
|
||||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { reduxForm, InjectedFormProps, formValueSelector } from "redux-form";
|
||||
import {
|
||||
|
|
@ -10,7 +10,6 @@ import FormLabel from "components/editorComponents/FormLabel";
|
|||
import FormRow from "components/editorComponents/FormRow";
|
||||
import { BaseButton } from "components/designSystems/blueprint/ButtonComponent";
|
||||
import { PaginationField } from "api/ActionAPI";
|
||||
import { ReduxActionTypes } from "constants/ReduxActionConstants";
|
||||
import DropdownField from "components/editorComponents/form/fields/DropdownField";
|
||||
import { API_EDITOR_FORM_NAME } from "constants/forms";
|
||||
import { BaseTabbedView } from "components/designSystems/appsmith/TabbedView";
|
||||
|
|
@ -121,10 +120,6 @@ interface APIFormProps {
|
|||
actionConfigurationHeaders?: any;
|
||||
actionName: string;
|
||||
apiId: string;
|
||||
location: {
|
||||
pathname: string;
|
||||
};
|
||||
dispatch: any;
|
||||
apiName: string;
|
||||
}
|
||||
|
||||
|
|
@ -137,7 +132,6 @@ export const NameWrapper = styled.div`
|
|||
input {
|
||||
margin: 0;
|
||||
box-sizing: border-box;
|
||||
// border: 0;
|
||||
}
|
||||
`;
|
||||
|
||||
|
|
@ -153,17 +147,7 @@ const ApiEditorForm: React.FC<Props> = (props: Props) => {
|
|||
actionConfigurationBody,
|
||||
httpMethodFromForm,
|
||||
actionName,
|
||||
location,
|
||||
dispatch,
|
||||
} = props;
|
||||
useEffect(() => {
|
||||
dispatch({
|
||||
type: ReduxActionTypes.SET_LAST_USED_EDITOR_PAGE,
|
||||
payload: {
|
||||
path: location.pathname,
|
||||
},
|
||||
});
|
||||
});
|
||||
const allowPostBody =
|
||||
httpMethodFromForm && httpMethodFromForm !== HTTP_METHODS[0];
|
||||
|
||||
|
|
@ -298,6 +282,5 @@ export default connect((state: AppState) => {
|
|||
})(
|
||||
reduxForm<RestAction, APIFormProps>({
|
||||
form: API_EDITOR_FORM_NAME,
|
||||
destroyOnUnmount: false,
|
||||
})(ApiEditorForm),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useEffect } from "react";
|
||||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { reduxForm, InjectedFormProps, formValueSelector } from "redux-form";
|
||||
import { POST_BODY_FORMAT_OPTIONS } from "constants/ApiEditorConstants";
|
||||
|
|
@ -7,7 +7,6 @@ import FormLabel from "components/editorComponents/FormLabel";
|
|||
import FormRow from "components/editorComponents/FormRow";
|
||||
import { BaseButton } from "components/designSystems/blueprint/ButtonComponent";
|
||||
import { PaginationField, BodyFormData, Property } from "api/ActionAPI";
|
||||
import { ReduxActionTypes } from "constants/ReduxActionConstants";
|
||||
import DynamicTextField from "components/editorComponents/form/fields/DynamicTextField";
|
||||
import KeyValueFieldArray from "components/editorComponents/form/fields/KeyValueFieldArray";
|
||||
import ApiResponseView from "components/editorComponents/ApiResponseView";
|
||||
|
|
@ -130,8 +129,6 @@ const RapidApiEditorForm: React.FC<Props> = (props: Props) => {
|
|||
providerImage,
|
||||
providerURL,
|
||||
providerCredentialSteps,
|
||||
location,
|
||||
dispatch,
|
||||
} = props;
|
||||
|
||||
const postbodyResponsePresent =
|
||||
|
|
@ -140,26 +137,6 @@ const RapidApiEditorForm: React.FC<Props> = (props: Props) => {
|
|||
actionConfigurationBodyFormData &&
|
||||
actionConfigurationBodyFormData.length > 0;
|
||||
|
||||
// let credentialStepsData;
|
||||
// if (providerCredentialSteps.length !== 0) {
|
||||
// credentialStepsData = providerCredentialSteps.split("\\n");
|
||||
// }
|
||||
// console.log(credentialStepsData, "credentialStepsData");
|
||||
|
||||
useEffect(() => {
|
||||
dispatch({
|
||||
type: ReduxActionTypes.SET_LAST_USED_EDITOR_PAGE,
|
||||
payload: {
|
||||
path: location.pathname,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
// const abc = (text: string) => {
|
||||
// console.log(text, "text");
|
||||
|
||||
// }
|
||||
|
||||
return (
|
||||
<Form
|
||||
onSubmit={handleSubmit}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ import { getApiName } from "selectors/formSelectors";
|
|||
import Spinner from "components/editorComponents/Spinner";
|
||||
import styled from "styled-components";
|
||||
import CenteredWrapper from "components/designSystems/appsmith/CenteredWrapper";
|
||||
import { changeApi } from "actions/apiPaneActions";
|
||||
|
||||
const LoadingContainer = styled(CenteredWrapper)`
|
||||
height: 50%;
|
||||
|
|
@ -38,8 +39,6 @@ interface ReduxStateProps {
|
|||
isRunning: Record<string, boolean>;
|
||||
isDeleting: Record<string, boolean>;
|
||||
isCreating: boolean;
|
||||
isMoving: boolean;
|
||||
isCopying: boolean;
|
||||
apiName: string;
|
||||
currentApplication: UserApplication;
|
||||
currentPageName: string | undefined;
|
||||
|
|
@ -54,6 +53,7 @@ interface ReduxActionProps {
|
|||
submitForm: (name: string) => void;
|
||||
runAction: (id: string, paginationField?: PaginationField) => void;
|
||||
deleteAction: (id: string, name: string) => void;
|
||||
changeAPIPage: (apiId: string) => void;
|
||||
}
|
||||
|
||||
function getPageName(pages: any, pageId: string) {
|
||||
|
|
@ -66,6 +66,9 @@ type Props = ReduxActionProps &
|
|||
RouteComponentProps<{ apiId: string; applicationId: string; pageId: string }>;
|
||||
|
||||
class ApiEditor extends React.Component<Props> {
|
||||
componentDidMount() {
|
||||
this.props.changeAPIPage(this.props.match.params.apiId);
|
||||
}
|
||||
handleDeleteClick = () => {
|
||||
const pageName = getPageName(
|
||||
this.props.pages,
|
||||
|
|
@ -79,6 +82,12 @@ class ApiEditor extends React.Component<Props> {
|
|||
this.props.deleteAction(this.props.match.params.apiId, this.props.apiName);
|
||||
};
|
||||
|
||||
componentDidUpdate(prevProps: Props) {
|
||||
if (prevProps.match.params.apiId !== this.props.match.params.apiId) {
|
||||
this.props.changeAPIPage(this.props.match.params.apiId);
|
||||
}
|
||||
}
|
||||
|
||||
handleRunClick = (paginationField?: PaginationField) => {
|
||||
const pageName = getPageName(
|
||||
this.props.pages,
|
||||
|
|
@ -119,12 +128,10 @@ class ApiEditor extends React.Component<Props> {
|
|||
isRunning,
|
||||
isDeleting,
|
||||
isCreating,
|
||||
isCopying,
|
||||
isMoving,
|
||||
paginationType,
|
||||
isEditorInitialized,
|
||||
} = this.props;
|
||||
if (isCreating || isCopying || isMoving || !isEditorInitialized) {
|
||||
if (isCreating || !isEditorInitialized) {
|
||||
return (
|
||||
<LoadingContainer>
|
||||
<Spinner size={30} />
|
||||
|
|
@ -174,7 +181,6 @@ class ApiEditor extends React.Component<Props> {
|
|||
: ""
|
||||
}
|
||||
apiName={this.props.apiName}
|
||||
location={this.props.location}
|
||||
/>
|
||||
)}
|
||||
|
||||
|
|
@ -207,13 +213,7 @@ class ApiEditor extends React.Component<Props> {
|
|||
const mapStateToProps = (state: AppState, props: any): ReduxStateProps => {
|
||||
const apiAction = getActionById(state, props);
|
||||
const apiName = getApiName(state, props.match.params.apiId);
|
||||
const {
|
||||
isDeleting,
|
||||
isRunning,
|
||||
isCreating,
|
||||
isMoving,
|
||||
isCopying,
|
||||
} = state.ui.apiPane;
|
||||
const { isDeleting, isRunning, isCreating } = state.ui.apiPane;
|
||||
return {
|
||||
actions: state.entities.actions,
|
||||
currentApplication: getCurrentApplication(state),
|
||||
|
|
@ -227,8 +227,6 @@ const mapStateToProps = (state: AppState, props: any): ReduxStateProps => {
|
|||
isRunning,
|
||||
isDeleting,
|
||||
isCreating,
|
||||
isMoving,
|
||||
isCopying,
|
||||
isEditorInitialized: getIsEditorInitialized(state),
|
||||
};
|
||||
};
|
||||
|
|
@ -239,6 +237,7 @@ const mapDispatchToProps = (dispatch: any): ReduxActionProps => ({
|
|||
dispatch(runAction(id, paginationField)),
|
||||
deleteAction: (id: string, name: string) =>
|
||||
dispatch(deleteAction({ id, name })),
|
||||
changeAPIPage: (actionId: string) => dispatch(changeApi(actionId)),
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(ApiEditor);
|
||||
|
|
|
|||
|
|
@ -1,239 +0,0 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { RouteComponentProps } from "react-router";
|
||||
import styled from "styled-components";
|
||||
import { AppState } from "reducers";
|
||||
import { ActionDataState } from "reducers/entityReducers/actionsReducer";
|
||||
import {
|
||||
API_EDITOR_URL_WITH_SELECTED_PAGE_ID,
|
||||
APIEditorRouteParams,
|
||||
} from "constants/routes";
|
||||
import { ApiPaneReduxState } from "reducers/uiReducers/apiPaneReducer";
|
||||
import {
|
||||
moveActionRequest,
|
||||
copyActionRequest,
|
||||
deleteAction,
|
||||
} from "actions/actionActions";
|
||||
import {
|
||||
changeApi,
|
||||
createNewApiAction,
|
||||
initApiPane,
|
||||
} from "actions/apiPaneActions";
|
||||
import EditorSidebar from "pages/Editor/EditorSidebar";
|
||||
import { getNextEntityName } from "utils/AppsmithUtils";
|
||||
import AnalyticsUtil from "utils/AnalyticsUtil";
|
||||
import { Page } from "constants/ReduxActionConstants";
|
||||
import { RestAction } from "entities/Action";
|
||||
|
||||
const HTTPMethod = styled.span<{ method?: string }>`
|
||||
flex: 1;
|
||||
font-size: 12px;
|
||||
color: ${props => {
|
||||
switch (props.method) {
|
||||
case "GET":
|
||||
return "#29CCA3";
|
||||
case "POST":
|
||||
return "#F7C75B";
|
||||
case "PUT":
|
||||
return "#30A5E0";
|
||||
case "PATCH":
|
||||
return "#8E8E8E";
|
||||
case "DELETE":
|
||||
return "#CE4257";
|
||||
default:
|
||||
return "#333";
|
||||
}
|
||||
}};
|
||||
`;
|
||||
|
||||
const ActionItem = styled.div`
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
max-width: 90%;
|
||||
`;
|
||||
|
||||
const ActionName = styled.span`
|
||||
flex: 3;
|
||||
padding: 0 2px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
`;
|
||||
|
||||
interface ReduxStateProps {
|
||||
actions: ActionDataState;
|
||||
apiPane: ApiPaneReduxState;
|
||||
pages: Page[];
|
||||
}
|
||||
|
||||
interface ReduxDispatchProps {
|
||||
onApiChange: (id: string) => void;
|
||||
initApiPane: (urlId?: string) => void;
|
||||
moveAction: (
|
||||
id: string,
|
||||
pageId: string,
|
||||
name: string,
|
||||
originalPageId: string,
|
||||
) => void;
|
||||
copyAction: (id: string, pageId: string, name: string) => void;
|
||||
deleteAction: (id: string, name: string) => void;
|
||||
createNewApiAction: (pageId: string) => void;
|
||||
}
|
||||
|
||||
type Props = ReduxStateProps &
|
||||
ReduxDispatchProps &
|
||||
RouteComponentProps<APIEditorRouteParams>;
|
||||
|
||||
class ApiSidebar extends React.Component<Props> {
|
||||
componentDidMount(): void {
|
||||
this.props.initApiPane(this.props.match.params.apiId);
|
||||
}
|
||||
|
||||
handleApiChange = (actionId: string) => {
|
||||
this.props.onApiChange(actionId);
|
||||
};
|
||||
|
||||
handleMove = (itemId: string, destinationPageId: string) => {
|
||||
const { pages } = this.props;
|
||||
const action = this.props.actions.filter(a => a.config.id === itemId)[0];
|
||||
const pageApiNames = this.props.actions
|
||||
.filter(a => a.config.pageId === destinationPageId)
|
||||
.map(a => a.config.name);
|
||||
let name = action.config.name;
|
||||
const page = pages.find(page => page.pageId === destinationPageId);
|
||||
|
||||
AnalyticsUtil.logEvent("MOVE_API_CLICK", {
|
||||
apiId: itemId,
|
||||
apiName: name,
|
||||
pageName: page?.pageName,
|
||||
});
|
||||
if (pageApiNames.indexOf(action.config.name) > -1) {
|
||||
name = getNextEntityName(name, pageApiNames);
|
||||
}
|
||||
this.props.moveAction(
|
||||
itemId,
|
||||
destinationPageId,
|
||||
name,
|
||||
action.config.pageId,
|
||||
);
|
||||
};
|
||||
|
||||
handleCopy = (itemId: string, destinationPageId: string) => {
|
||||
const { pages } = this.props;
|
||||
const action = this.props.actions.filter(a => a.config.id === itemId)[0];
|
||||
const pageApiNames = this.props.actions
|
||||
.filter(a => a.config.pageId === destinationPageId)
|
||||
.map(a => a.config.name);
|
||||
let name = `${action.config.name}Copy`;
|
||||
const page = pages.find(page => page.pageId === destinationPageId);
|
||||
|
||||
AnalyticsUtil.logEvent("DUPLICATE_API_CLICK", {
|
||||
apiId: itemId,
|
||||
apiName: name,
|
||||
pageName: page?.pageName,
|
||||
});
|
||||
|
||||
if (pageApiNames.indexOf(name) > -1) {
|
||||
name = getNextEntityName(name, pageApiNames);
|
||||
}
|
||||
this.props.copyAction(itemId, destinationPageId, name);
|
||||
};
|
||||
|
||||
handleDelete = (itemId: string, itemName: string, pageName: string) => {
|
||||
AnalyticsUtil.logEvent("DELETE_API_CLICK", {
|
||||
apiId: itemId,
|
||||
apiName: itemName,
|
||||
pageName: pageName,
|
||||
});
|
||||
this.props.deleteAction(itemId, itemName);
|
||||
};
|
||||
|
||||
renderItem = (action: RestAction) => {
|
||||
return (
|
||||
<ActionItem
|
||||
onClick={() => {
|
||||
AnalyticsUtil.logEvent("API_SELECT", {
|
||||
apiId: action.id,
|
||||
apiName: action.name,
|
||||
});
|
||||
}}
|
||||
>
|
||||
{action.actionConfiguration ? (
|
||||
<HTTPMethod method={action.actionConfiguration.httpMethod}>
|
||||
{action.actionConfiguration.httpMethod}
|
||||
</HTTPMethod>
|
||||
) : (
|
||||
<HTTPMethod />
|
||||
)}
|
||||
<ActionName>{action.name}</ActionName>
|
||||
</ActionItem>
|
||||
);
|
||||
};
|
||||
|
||||
handleCreateNewApiClick = (selectedPageId: string) => {
|
||||
const { history } = this.props;
|
||||
const { pageId, applicationId } = this.props.match.params;
|
||||
history.push(
|
||||
API_EDITOR_URL_WITH_SELECTED_PAGE_ID(
|
||||
applicationId,
|
||||
pageId,
|
||||
selectedPageId,
|
||||
),
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
apiPane: { isFetching },
|
||||
match: {
|
||||
params: { apiId },
|
||||
},
|
||||
actions,
|
||||
} = this.props;
|
||||
const data = actions
|
||||
.filter(a => a.config?.pluginType === "API")
|
||||
.map(a => a.config);
|
||||
return (
|
||||
<EditorSidebar
|
||||
isLoading={isFetching}
|
||||
list={data}
|
||||
selectedItemId={apiId}
|
||||
itemRender={this.renderItem}
|
||||
onItemCreateClick={this.handleCreateNewApiClick}
|
||||
onItemSelected={this.handleApiChange}
|
||||
moveItem={this.handleMove}
|
||||
copyItem={this.handleCopy}
|
||||
deleteItem={this.handleDelete}
|
||||
createButtonTitle="Create new API"
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state: AppState): ReduxStateProps => ({
|
||||
actions: state.entities.actions,
|
||||
apiPane: state.ui.apiPane,
|
||||
pages: state.entities.pageList.pages,
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch: Function): ReduxDispatchProps => ({
|
||||
onApiChange: (actionId: string) => dispatch(changeApi(actionId)),
|
||||
initApiPane: (urlId?: string) => dispatch(initApiPane(urlId)),
|
||||
moveAction: (
|
||||
id: string,
|
||||
destinationPageId: string,
|
||||
name: string,
|
||||
originalPageId: string,
|
||||
) =>
|
||||
dispatch(
|
||||
moveActionRequest({ id, destinationPageId, originalPageId, name }),
|
||||
),
|
||||
copyAction: (id: string, destinationPageId: string, name: string) =>
|
||||
dispatch(copyActionRequest({ id, destinationPageId, name })),
|
||||
deleteAction: (id: string, name: string) =>
|
||||
dispatch(deleteAction({ id, name })),
|
||||
createNewApiAction: (pageId: string) => dispatch(createNewApiAction(pageId)),
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(ApiSidebar);
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import React from "react";
|
||||
import React, { memo } from "react";
|
||||
import WidgetFactory from "utils/WidgetFactory";
|
||||
import { RenderModes } from "constants/WidgetConstants";
|
||||
import { ContainerWidgetProps } from "widgets/ContainerWidget";
|
||||
|
|
@ -11,7 +11,7 @@ interface CanvasProps {
|
|||
}
|
||||
|
||||
// TODO(abhinav): get the render mode from context
|
||||
const Canvas = (props: CanvasProps) => {
|
||||
const Canvas = memo((props: CanvasProps) => {
|
||||
try {
|
||||
return (
|
||||
<React.Fragment>
|
||||
|
|
@ -26,6 +26,8 @@ const Canvas = (props: CanvasProps) => {
|
|||
console.log("Error rendering DSL", error);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
Canvas.displayName = "Canvas";
|
||||
|
||||
export default Canvas;
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import {
|
|||
updateDatasource,
|
||||
testDatasource,
|
||||
deleteDatasource,
|
||||
switchDatasource,
|
||||
} from "actions/datasourceActions";
|
||||
import { DATASOURCE_DB_FORM } from "constants/forms";
|
||||
import DatasourceHome from "./DatasourceHome";
|
||||
|
|
@ -44,6 +45,20 @@ type Props = ReduxStateProps &
|
|||
}>;
|
||||
|
||||
class DataSourceEditor extends React.Component<Props> {
|
||||
componentDidUpdate(prevProps: Props) {
|
||||
if (
|
||||
this.props.match.params.datasourceId &&
|
||||
this.props.match.params.datasourceId !==
|
||||
prevProps.match.params.datasourceId
|
||||
) {
|
||||
this.props.switchDatasource(this.props.match.params.datasourceId);
|
||||
}
|
||||
}
|
||||
componentDidMount() {
|
||||
if (this.props.match.params.datasourceId) {
|
||||
this.props.switchDatasource(this.props.match.params.datasourceId);
|
||||
}
|
||||
}
|
||||
handleSubmit = () => {
|
||||
this.props.submitForm(DATASOURCE_DB_FORM);
|
||||
};
|
||||
|
|
@ -137,6 +152,7 @@ const mapDispatchToProps = (dispatch: any): DatasourcePaneFunctions => ({
|
|||
},
|
||||
testDatasource: (data: Datasource) => dispatch(testDatasource(data)),
|
||||
deleteDatasource: (id: string) => dispatch(deleteDatasource({ id })),
|
||||
switchDatasource: (id: string) => dispatch(switchDatasource(id)),
|
||||
});
|
||||
|
||||
export interface DatasourcePaneFunctions {
|
||||
|
|
@ -144,6 +160,7 @@ export interface DatasourcePaneFunctions {
|
|||
updateDatasource: (data: Datasource) => void;
|
||||
testDatasource: (data: Datasource) => void;
|
||||
deleteDatasource: (id: string) => void;
|
||||
switchDatasource: (id: string) => void;
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(DataSourceEditor);
|
||||
|
|
|
|||
|
|
@ -1,364 +0,0 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { initialize } from "redux-form";
|
||||
import styled from "styled-components";
|
||||
import { RouteComponentProps } from "react-router";
|
||||
import Button from "components/editorComponents/Button";
|
||||
import { DATASOURCE_DB_FORM } from "constants/forms";
|
||||
import { IIconProps } from "@blueprintjs/core";
|
||||
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 { getPluginImages } from "selectors/entitiesSelector";
|
||||
import {
|
||||
initDatasourcePane,
|
||||
storeDatastoreRefs,
|
||||
deleteDatasource,
|
||||
changeDatasource,
|
||||
} from "actions/datasourceActions";
|
||||
import { ControlIcons } from "icons/ControlIcons";
|
||||
import { theme } from "constants/DefaultTheme";
|
||||
import { selectPlugin } from "actions/datasourceActions";
|
||||
import { fetchPluginForm } from "actions/pluginActions";
|
||||
import { DATA_SOURCES_EDITOR_URL } from "constants/routes";
|
||||
import { AppState } from "reducers";
|
||||
import { Datasource } from "api/DatasourcesApi";
|
||||
import Fuse from "fuse.js";
|
||||
|
||||
interface ReduxDispatchProps {
|
||||
initDatasourcePane: (pluginType: string, urlId?: string) => void;
|
||||
selectPlugin: (pluginType: string) => void;
|
||||
initializeForm: (data: Record<string, any>) => void;
|
||||
storeDatastoreRefs: (refsList: []) => void;
|
||||
fetchFormConfig: (id: string) => void;
|
||||
deleteDatasource: (id: string) => void;
|
||||
onDatasourceChange: (datasource: Datasource) => void;
|
||||
}
|
||||
|
||||
interface ReduxStateProps {
|
||||
dataSources: Datasource[];
|
||||
pluginImages: Record<string, string>;
|
||||
datastoreRefs: Record<string, any>;
|
||||
formConfigs: Record<string, []>;
|
||||
drafts: Record<string, Datasource>;
|
||||
}
|
||||
|
||||
type DataSourceSidebarProps = {};
|
||||
|
||||
type State = {
|
||||
search: string;
|
||||
};
|
||||
|
||||
const ActionItem = styled.div`
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
`;
|
||||
|
||||
const ActionName = styled.span`
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
max-width: 130px;
|
||||
margin-left: 10px;
|
||||
`;
|
||||
|
||||
const SearchBar = styled(BaseTextInput)`
|
||||
margin-bottom: 10px;
|
||||
input {
|
||||
background-color: #23292e;
|
||||
border: none;
|
||||
color: ${props => props.theme.colors.textOnDarkBG}
|
||||
:focus {
|
||||
background-color: #23292e;
|
||||
}
|
||||
}
|
||||
.bp3-icon {
|
||||
background-color: #23292e;
|
||||
}
|
||||
`;
|
||||
|
||||
const ItemContainer = styled.div<{
|
||||
isSelected: boolean;
|
||||
}>`
|
||||
padding: 8px 12px;
|
||||
border-radius: 4px;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
font-size: 14px;
|
||||
margin-bottom: 2px;
|
||||
background-color: ${props =>
|
||||
props.isSelected ? props.theme.colors.paneCard : props.theme.colors.paneBG}
|
||||
:hover {
|
||||
background-color: ${props => props.theme.colors.paneCard};
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledImage = styled.img`
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
|
||||
svg {
|
||||
path {
|
||||
fill: ${Colors.WHITE};
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledAddButton = styled(Button)<IIconProps>`
|
||||
padding: "9px";
|
||||
&&& {
|
||||
outline: none;
|
||||
padding: 10px !important;
|
||||
}
|
||||
span {
|
||||
font-weight: normal !important;
|
||||
}
|
||||
`;
|
||||
|
||||
const Controls = styled.div`
|
||||
padding: 10px;
|
||||
`;
|
||||
|
||||
const Wrapper = styled.div`
|
||||
padding: 5px;
|
||||
`;
|
||||
|
||||
const Container = styled.div`
|
||||
.createBtn {
|
||||
border: none;
|
||||
color: ${Colors.WHITE} !important;
|
||||
width: 100%;
|
||||
display: block !important;
|
||||
font-weight: normal;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
|
||||
&:hover {
|
||||
color: ${Colors.WHITE} !important;
|
||||
background-color: ${Colors.BLUE_CHARCOAL} !important;
|
||||
|
||||
svg {
|
||||
path {
|
||||
fill: ${Colors.WHITE};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.highlightButton {
|
||||
color: ${Colors.WHITE} !important;
|
||||
background-color: ${Colors.BLUE_CHARCOAL} !important;
|
||||
display: block !important;
|
||||
font-weight: normal;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
|
||||
svg {
|
||||
path {
|
||||
fill: ${Colors.WHITE};
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const DraftIconIndicator = styled.span<{ isHidden: boolean }>`
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 8px;
|
||||
background-color: #f2994a;
|
||||
margin: 0 5px;
|
||||
opacity: ${({ isHidden }) => (isHidden ? 0 : 1)};
|
||||
`;
|
||||
|
||||
type Props = DataSourceSidebarProps &
|
||||
RouteComponentProps<{
|
||||
pageId: string;
|
||||
applicationId: string;
|
||||
datasourceId: string;
|
||||
}> &
|
||||
ReduxStateProps &
|
||||
ReduxDispatchProps;
|
||||
|
||||
const FUSE_OPTIONS = {
|
||||
shouldSort: true,
|
||||
threshold: 0.5,
|
||||
location: 0,
|
||||
minMatchCharLength: 3,
|
||||
findAllMatches: true,
|
||||
keys: ["name"],
|
||||
};
|
||||
|
||||
class DataSourceSidebar extends React.Component<Props, State> {
|
||||
refsCollection: any;
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
search: "",
|
||||
};
|
||||
|
||||
this.refsCollection = {};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { dataSources, storeDatastoreRefs } = this.props;
|
||||
this.refsCollection = dataSources.reduce((acc: any, value) => {
|
||||
acc[value.id] = React.createRef();
|
||||
return acc;
|
||||
}, {});
|
||||
storeDatastoreRefs(this.refsCollection);
|
||||
}
|
||||
|
||||
shouldComponentUpdate(nextProps: Readonly<Props>): boolean {
|
||||
if (Object.keys(nextProps.drafts) !== Object.keys(this.props.drafts)) {
|
||||
return true;
|
||||
}
|
||||
return nextProps.dataSources !== this.props.dataSources;
|
||||
}
|
||||
|
||||
handleCreateNewDatasource = () => {
|
||||
const { history } = this.props;
|
||||
const { pageId, applicationId } = this.props.match.params;
|
||||
|
||||
history.push(DATA_SOURCES_EDITOR_URL(applicationId, pageId));
|
||||
};
|
||||
|
||||
handleItemSelected = (datasource: Datasource) => {
|
||||
this.props.onDatasourceChange(datasource);
|
||||
};
|
||||
|
||||
handleSearchChange = (e: React.ChangeEvent<{ value: string }>) => {
|
||||
const value = e.target.value;
|
||||
this.setState({
|
||||
search: value,
|
||||
});
|
||||
};
|
||||
|
||||
getSearchFilteredList = () => {
|
||||
const { search } = this.state;
|
||||
const { dataSources } = this.props;
|
||||
const fuse = new Fuse(dataSources, FUSE_OPTIONS);
|
||||
return search ? fuse.search(search) : dataSources;
|
||||
};
|
||||
|
||||
renderItem = () => {
|
||||
const {
|
||||
match: {
|
||||
params: { datasourceId },
|
||||
},
|
||||
datastoreRefs,
|
||||
deleteDatasource,
|
||||
drafts,
|
||||
pluginImages,
|
||||
} = this.props;
|
||||
|
||||
const filteredList = this.getSearchFilteredList();
|
||||
|
||||
return filteredList.map(datasource => {
|
||||
return (
|
||||
<ItemContainer
|
||||
data-cy={datasource.id}
|
||||
ref={datastoreRefs[datasource.id]}
|
||||
key={datasource.id}
|
||||
isSelected={datasourceId === datasource.id}
|
||||
onClick={() => this.handleItemSelected(datasource)}
|
||||
>
|
||||
<ActionItem>
|
||||
<StyledImage
|
||||
src={pluginImages[datasource.pluginId]}
|
||||
className="pluginImage"
|
||||
alt="Plugin Image"
|
||||
/>
|
||||
<ActionName>{datasource.name}</ActionName>
|
||||
</ActionItem>
|
||||
<DraftIconIndicator isHidden={!(datasource.id in drafts)} />
|
||||
<TreeDropdown
|
||||
defaultText=""
|
||||
onSelect={() => {
|
||||
return null;
|
||||
}}
|
||||
selectedValue=""
|
||||
optionTree={[
|
||||
{
|
||||
value: "delete",
|
||||
onSelect: () => deleteDatasource(datasource.id),
|
||||
label: "Delete",
|
||||
intent: "danger",
|
||||
},
|
||||
]}
|
||||
toggle={
|
||||
<ControlIcons.MORE_HORIZONTAL_CONTROL
|
||||
width={theme.fontSizes[4]}
|
||||
height={theme.fontSizes[4]}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</ItemContainer>
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const { search } = this.state;
|
||||
const {
|
||||
match: {
|
||||
params: { datasourceId },
|
||||
},
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<Wrapper>
|
||||
<Controls>
|
||||
<SearchBar
|
||||
icon="search"
|
||||
input={{
|
||||
value: search,
|
||||
onChange: this.handleSearchChange,
|
||||
}}
|
||||
placeholder="Search"
|
||||
/>
|
||||
</Controls>
|
||||
<Container>
|
||||
<StyledAddButton
|
||||
text={"Create a new Datasource"}
|
||||
icon="plus"
|
||||
fluid
|
||||
className={datasourceId ? "createBtn" : "highlightButton"}
|
||||
onClick={this.handleCreateNewDatasource}
|
||||
/>
|
||||
</Container>
|
||||
{this.renderItem()}
|
||||
</Wrapper>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state: AppState): ReduxStateProps => {
|
||||
const { drafts } = state.ui.datasourcePane;
|
||||
return {
|
||||
formConfigs: state.entities.plugins.formConfigs,
|
||||
dataSources: getDataSources(state),
|
||||
pluginImages: getPluginImages(state),
|
||||
datastoreRefs: state.ui.datasourcePane.datasourceRefs,
|
||||
drafts,
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = (dispatch: Function): ReduxDispatchProps => ({
|
||||
initDatasourcePane: (pluginType: string, urlId?: string) =>
|
||||
dispatch(initDatasourcePane(pluginType, urlId)),
|
||||
onDatasourceChange: (datasource: Datasource) =>
|
||||
dispatch(changeDatasource(datasource)),
|
||||
fetchFormConfig: (id: string) => dispatch(fetchPluginForm({ id })),
|
||||
selectPlugin: (pluginId: string) => dispatch(selectPlugin(pluginId)),
|
||||
initializeForm: (data: Record<string, any>) =>
|
||||
dispatch(initialize(DATASOURCE_DB_FORM, data)),
|
||||
storeDatastoreRefs: (refsList: {}) => {
|
||||
dispatch(storeDatastoreRefs(refsList));
|
||||
},
|
||||
deleteDatasource: (id: string) => dispatch(deleteDatasource({ id })),
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(DataSourceSidebar);
|
||||