merge 'release' into 'fix/minor-bugs'
This commit is contained in:
parent
16606a45a2
commit
0ffff9db4f
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"baseUrl": "https://mock-api.appsmith.com",
|
||||
"baseUrl": "https://mock-api.appsmith.com/",
|
||||
"methods": "users",
|
||||
"headerKey": "Content-Type",
|
||||
"headerValue": "application/json",
|
||||
|
|
@ -12,14 +12,14 @@
|
|||
"responsetext": "Roger Brickelberry",
|
||||
"pageResponsetext": "Josh M Krantz",
|
||||
"apiname": "SecondAPI",
|
||||
"baseUrl2": "https://reqres.in",
|
||||
"baseUrl2": "https://reqres.in/",
|
||||
"methods1": "api/users/1",
|
||||
"responsetext2": "qui est esse",
|
||||
"baseUrl3": "https://reqres.in",
|
||||
"baseUrl3": "https://reqres.in/",
|
||||
"methods2": "api/users/2",
|
||||
"invalidPath": "api/users/a",
|
||||
"responsetext3": "Josh M Krantz",
|
||||
"postUrl": "https://reqres.in",
|
||||
"postUrl": "https://reqres.in/",
|
||||
"deleteUrl": "",
|
||||
"Post": "POST",
|
||||
"Delete": "DELETE",
|
||||
|
|
|
|||
|
|
@ -1,26 +0,0 @@
|
|||
const ApiEditor = require("../../../locators/ApiEditor.json");
|
||||
|
||||
describe("Test 3P provider API import flow", function() {
|
||||
it("Test 3P provider API import flow", function() {
|
||||
localStorage.setItem("ApiPaneV2", "ApiPaneV2");
|
||||
cy.NavigateToApiEditor();
|
||||
cy.wait("@get3PProviders").should(
|
||||
"have.nested.property",
|
||||
"response.body.responseMeta.status",
|
||||
200,
|
||||
);
|
||||
cy.get(ApiEditor.eachProviderCard)
|
||||
.first()
|
||||
.click({ force: true });
|
||||
cy.wait("@get3PProviderTemplates");
|
||||
cy.url().should("include", "/edit/api/provider/");
|
||||
cy.contains("Add to page").click();
|
||||
cy.wait("@add3PApiToPage").should(
|
||||
"have.nested.property",
|
||||
"response.body.responseMeta.status",
|
||||
201,
|
||||
);
|
||||
cy.get(ApiEditor.addToPageBtn).should("be.disabled");
|
||||
cy.get(ApiEditor.addToPageBtnsId).should("contain", "Added");
|
||||
});
|
||||
});
|
||||
|
|
@ -18,13 +18,10 @@ describe("Test curl import flow", function() {
|
|||
response.response.body.data.name,
|
||||
);
|
||||
});
|
||||
cy.WaitAutoSave();
|
||||
// cy.WaitAutoSave();
|
||||
cy.RunAPI();
|
||||
|
||||
cy.get(ApiEditor.formActionButtons).should("be.visible");
|
||||
cy.get("@postExecute").then(httpResponse => {
|
||||
cy.expect(httpResponse.response.body.responseMeta.success).to.eq(true);
|
||||
});
|
||||
cy.get(ApiEditor.ApiDeleteBtn).click();
|
||||
cy.get(ApiEditor.ApiDeleteBtn).should("be.disabled");
|
||||
cy.testDeleteApi();
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ describe("Test curl import flow", function() {
|
|||
cy.NavigateToApiEditor();
|
||||
cy.get(ApiEditor.curlImage).click({ force: true });
|
||||
cy.get("textarea").type(
|
||||
"curl -d '{'name': 'morpheus','job': 'leader'}' -H 'Content-Type: application/json' “https://reqres.in/api/users”",
|
||||
"curl -d { name : 'morpheus',job : 'leader'} -H Content-Type: application/json https://reqres.in/api/users",
|
||||
{
|
||||
force: true,
|
||||
parseSpecialCharSequences: false,
|
||||
|
|
|
|||
|
|
@ -6,8 +6,10 @@ describe("API Panel Test Functionality ", function() {
|
|||
cy.NavigateToAPI_Panel();
|
||||
cy.log("Navigation to API Panel screen successful");
|
||||
cy.CreateAPI("FirstAPI");
|
||||
cy.RunAPI();
|
||||
cy.log("Creation of FirstAPI Action successful");
|
||||
cy.CreateAPI("SecondAPI");
|
||||
cy.RunAPI();
|
||||
cy.log("Creation of SecondAPI Action successful");
|
||||
cy.SearchAPI("SecondAPI", "FirstAPI");
|
||||
});
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
describe("Name uniqueness test", function() {
|
||||
it("Test api name unique error", () => {
|
||||
cy.log("Login Successful");
|
||||
cy.NavigateToAPI_Panel();
|
||||
cy.log("Navigation to API Panel screen successful");
|
||||
cy.CreateAPI("UniqueName");
|
||||
cy.log("Creation of UniqueName Action successful");
|
||||
cy.CreationOfUniqueAPIcheck("UniqueName");
|
||||
});
|
||||
});
|
||||
|
|
@ -3,11 +3,13 @@ describe("API Panel Test Functionality ", 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.MoveAPIToPage();
|
||||
cy.DeleteAPI("FirstAPI");
|
||||
//cy.MoveAPIToPage();
|
||||
cy.CreateAPI("FirstAPI");
|
||||
cy.log("Creation of FirstAPI Action successful");
|
||||
cy.CreationOfUniqueAPIcheck("FirstAPI");
|
||||
|
|
|
|||
|
|
@ -8,13 +8,11 @@ describe("API Panel Test Functionality ", function() {
|
|||
cy.wait("@getCategories");
|
||||
cy.wait("@getTemplateCollections");
|
||||
cy.wait("@get3PProviders");
|
||||
cy.wait("@getUser");
|
||||
cy.log("Navigation to API Panel screen successful");
|
||||
cy.get(apiwidget.marketPlaceapi)
|
||||
.first()
|
||||
.click();
|
||||
cy.wait("@get3PProviderTemplates");
|
||||
cy.wait("@getUser");
|
||||
cy.get(".apiName")
|
||||
.first()
|
||||
.invoke("text")
|
||||
|
|
@ -24,7 +22,6 @@ describe("API Panel Test Functionality ", function() {
|
|||
.click();
|
||||
const searchApiName = ApiName.replace(/\s/g, "");
|
||||
cy.log(searchApiName);
|
||||
cy.wait("@add3PApiToPage");
|
||||
cy.wait("@getActions");
|
||||
cy.SearchAPIandClick(searchApiName);
|
||||
cy.get(apiwidget.apidocumentaionLink)
|
||||
|
|
|
|||
|
|
@ -1,20 +1,12 @@
|
|||
const datasource = require("../../../locators/DatasourcesEditor.json");
|
||||
let pageid;
|
||||
|
||||
describe("Create, test, save then delete a mongo datasource", function() {
|
||||
it("Create, test, save then delete a mongo datasource", function() {
|
||||
cy.NavigateToDatasourceEditor();
|
||||
cy.get("@getPlugins").then(httpResponse => {
|
||||
const pluginName = httpResponse.response.body.data.find(
|
||||
plugin => plugin.packageName === "mongo-plugin",
|
||||
).name;
|
||||
|
||||
cy.get(".t--plugin-name")
|
||||
.contains(pluginName)
|
||||
.click();
|
||||
});
|
||||
|
||||
cy.get(datasource.MongoDB).click();
|
||||
cy.getPluginFormsAndCreateDatasource();
|
||||
|
||||
cy.fillMongoDatasourceForm();
|
||||
|
||||
cy.testSaveDeleteDatasource();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,20 +1,11 @@
|
|||
const datasource = require("../../../locators/DatasourcesEditor.json");
|
||||
|
||||
describe("Create, test, save then delete a postgres datasource", function() {
|
||||
it("Create, test, save then delete a postgres datasource", function() {
|
||||
cy.NavigateToDatasourceEditor();
|
||||
cy.get("@getPlugins").then(httpResponse => {
|
||||
const pluginName = httpResponse.response.body.data.find(
|
||||
plugin => plugin.packageName === "postgres-plugin",
|
||||
).name;
|
||||
|
||||
cy.get(".t--plugin-name")
|
||||
.contains(pluginName)
|
||||
.click();
|
||||
});
|
||||
|
||||
cy.get(datasource.PostgreSQL).click();
|
||||
cy.getPluginFormsAndCreateDatasource();
|
||||
|
||||
cy.fillPostgresDatasourceForm();
|
||||
|
||||
cy.testSaveDeleteDatasource();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -4,20 +4,9 @@ const datasourceFormData = require("../../../fixtures/datasources.json");
|
|||
describe("Create, test, save then delete a restapi datasource", function() {
|
||||
it("Create, test, save then delete a restapi datasource", function() {
|
||||
cy.NavigateToDatasourceEditor();
|
||||
cy.get("@getPlugins").then(httpResponse => {
|
||||
const pluginName = httpResponse.response.body.data.find(
|
||||
plugin => plugin.packageName === "restapi-plugin",
|
||||
).name;
|
||||
|
||||
cy.get(".t--plugin-name")
|
||||
.contains(pluginName)
|
||||
.click();
|
||||
});
|
||||
|
||||
cy.get(datasourceEditor.RESTAPI).click();
|
||||
cy.getPluginFormsAndCreateDatasource();
|
||||
|
||||
cy.get(datasourceEditor.url).type(datasourceFormData["restapi-url"]);
|
||||
|
||||
cy.testSaveDeleteDatasource();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,18 +1,11 @@
|
|||
const queryLocators = require("../../../locators/QueryEditor.json");
|
||||
const plugins = require("../../../fixtures/plugins.json");
|
||||
const datasource = require("../../../locators/DatasourcesEditor.json");
|
||||
|
||||
describe("Create a query with a mongo datasource, run, save and then delete the query", function() {
|
||||
it("Create a query with a mongo datasource, run, save and then delete the query", function() {
|
||||
cy.NavigateToDatasourceEditor();
|
||||
cy.get("@getPlugins").then(httpResponse => {
|
||||
const pluginName = httpResponse.response.body.data.find(
|
||||
plugin => plugin.packageName === plugins.mongoPackageName,
|
||||
).name;
|
||||
|
||||
cy.get(".t--plugin-name")
|
||||
.contains(pluginName)
|
||||
.click();
|
||||
});
|
||||
cy.get(datasource.MongoDB).click();
|
||||
|
||||
cy.getPluginFormsAndCreateDatasource();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,17 +1,10 @@
|
|||
const queryLocators = require("../../../locators/QueryEditor.json");
|
||||
const datasource = require("../../../locators/DatasourcesEditor.json");
|
||||
|
||||
describe("Create a query with a postgres datasource, run, save and then delete the query", function() {
|
||||
it("Create a query with a postgres datasource, run, save and then delete the query", function() {
|
||||
cy.NavigateToDatasourceEditor();
|
||||
cy.get("@getPlugins").then(httpResponse => {
|
||||
const pluginName = httpResponse.response.body.data.find(
|
||||
plugin => plugin.packageName === "postgres-plugin",
|
||||
).name;
|
||||
|
||||
cy.get(".t--plugin-name")
|
||||
.contains(pluginName)
|
||||
.click();
|
||||
});
|
||||
cy.get(datasource.PostgreSQL).click();
|
||||
|
||||
cy.getPluginFormsAndCreateDatasource();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +0,0 @@
|
|||
describe("Create and Delete App Functionality", function() {
|
||||
it("Delete App Functionality", function() {
|
||||
cy.log("appname: " + localStorage.getItem("AppName"));
|
||||
const appname = localStorage.getItem("AppName");
|
||||
cy.DeleteApp(appname);
|
||||
cy.wait("@deleteApplication");
|
||||
cy.get("@deleteApplication").should("have.property", "status", 200);
|
||||
});
|
||||
});
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
describe("Create and Delete Page Functionality", function() {
|
||||
it("Delete Page Functionality", function() {
|
||||
cy.log("PageName: " + localStorage.getItem("PageName"));
|
||||
const PageName = localStorage.getItem("PageName");
|
||||
cy.Deletepage(PageName);
|
||||
cy.wait("@deletePage");
|
||||
cy.get("@deletePage").should("have.property", "status", 200);
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
const loginData = require("../../../fixtures/user.json");
|
||||
let pageid;
|
||||
let appId;
|
||||
|
||||
describe("Login from UI and check the functionality", function() {
|
||||
it("Login/create page/delete page/delete app from UI", function() {
|
||||
const appname = localStorage.getItem("AppName");
|
||||
cy.LogintoApp(loginData.username, loginData.password);
|
||||
cy.SearchApp(appname);
|
||||
cy.get("#loading").should("not.exist");
|
||||
cy.wait("@getPropertyPane");
|
||||
cy.get("@getPropertyPane").should("have.property", "status", 200);
|
||||
cy.generateUUID().then(uid => {
|
||||
pageid = uid;
|
||||
cy.Createpage(pageid);
|
||||
cy.NavigateToWidgets(pageid);
|
||||
localStorage.setItem("PageName", pageid);
|
||||
cy.Deletepage(pageid);
|
||||
});
|
||||
cy.wait("@deletePage");
|
||||
cy.get("@deletePage").should("have.property", "status", 200);
|
||||
cy.DeleteApp(appname);
|
||||
cy.wait("@deleteApplication");
|
||||
cy.get("@deleteApplication").should("have.property", "status", 200);
|
||||
});
|
||||
});
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
"createBlankApiCard": ".t--createBlankApiCard",
|
||||
"eachProviderCard": ".t--eachProviderCard",
|
||||
"nameOfApi": ".t--nameOfApi",
|
||||
"ApiNameField":"input[name='name']",
|
||||
"ApiNameField": ".t--nameOfApi input",
|
||||
"addToPageBtn": ".t--addToPageBtn",
|
||||
"ApiDeleteBtn": ".t--apiFormDeleteBtn",
|
||||
"ApiRunBtn": ".t--apiFormRunBtn",
|
||||
|
|
@ -20,4 +20,4 @@
|
|||
"apiPaginationNextTest": ".t--apiFormPaginationNextTest",
|
||||
"apiPaginationTab": ".t--apiFormPaginationType",
|
||||
"apiTab": ".react-tabs__tab-list li"
|
||||
}
|
||||
}
|
||||
|
|
@ -8,6 +8,9 @@
|
|||
"authenticationAuthtype": "[data-cy=datasourceConfiguration\\.authentication\\.authType]",
|
||||
"sslAuthtype": "[data-cy=datasourceConfiguration\\.connection\\.ssl\\.authType]",
|
||||
"url": "input[name='datasourceConfiguration.url']",
|
||||
"MongoDB": ".t--plugin-name:contains('MongoDB')",
|
||||
"RESTAPI": ".t--plugin-name:contains('REST API')",
|
||||
"PostgreSQL": ".t--plugin-name:contains('PostgreSQL')",
|
||||
"sectionAuthentication": "[data-cy=section-Authentication]",
|
||||
"sectionSSL": "[data-cy=section-SSL\\ \\(optional\\)]"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,5 +8,8 @@
|
|||
"appMoreIcon":".bp3-popover-wrapper.more .bp3-popover-target",
|
||||
"deleteButton":".bp3-menu-item.bp3-popover-dismiss",
|
||||
"selectAction":"#Base",
|
||||
"deleteApp":".bp3-menu-item"
|
||||
"deleteApp":".bp3-menu-item",
|
||||
"homeIcon": ".bp3-icon-home",
|
||||
"inputAppName": "input[name=applicationName]",
|
||||
"createNew": ".createnew"
|
||||
}
|
||||
|
|
@ -2,11 +2,11 @@
|
|||
"resourceUrl": ".t--dataSourceField",
|
||||
"searchApi": ".t--sidebar input[type=text]",
|
||||
"createapi": ".t--createBlankApiCard",
|
||||
"apiTxt": "input[name=name]",
|
||||
"apiTxt": ".t--nameOfApi input",
|
||||
"popover": ".bp3-popover-target >div>svg",
|
||||
"moveTo": ".single-select >div:contains('Move to')",
|
||||
"copyTo": ".single-select >div:contains('Copy to')",
|
||||
"home": ".single-select >div:contains('Page1')",
|
||||
"home": ".single-select >div:contains('Home')",
|
||||
"delete": ".single-select >div:contains('Delete')",
|
||||
"path": ".t--path >div textarea",
|
||||
"editResourceUrl": ".t--dataSourceField input",
|
||||
|
|
@ -22,7 +22,7 @@
|
|||
"addHeader": ".t--addApiHeader svg",
|
||||
"marketPlaceapi": ".t--eachProviderCard p",
|
||||
"addPageButton": ".t--addToPageBtn",
|
||||
"apidocumentaionLink": ".linkStyles",
|
||||
"apidocumentaionLink": ".t--apiDocumentationLink",
|
||||
"postbody": "(//div[contains(@class,'CodeMirror-wrap')]//textarea)[1]",
|
||||
"paginationTab": "li:contains('Pagination')",
|
||||
"apiInputTab": "li:contains('API Input')",
|
||||
|
|
@ -33,4 +33,4 @@
|
|||
"panigationPrevUrl": ".t--apiFormPaginationPrev div>textarea",
|
||||
"TestNextUrl": ".t--apiFormPaginationNextTest",
|
||||
"TestPreUrl": ".t--apiFormPaginationPrevTest"
|
||||
}
|
||||
}
|
||||
|
|
@ -15,20 +15,16 @@ const dynamicInputLocators = require("../locators/DynamicInput.json");
|
|||
let pageidcopy = " ";
|
||||
|
||||
Cypress.Commands.add("CreateApp", appname => {
|
||||
// cy.get(homePage.CreateApp)
|
||||
cy.contains("Create New").click({ force: true });
|
||||
// .click({ force: true });
|
||||
cy.get("form input").type(appname);
|
||||
cy.get(homePage.createNew)
|
||||
.first()
|
||||
.click({ force: true });
|
||||
cy.get(homePage.inputAppName).type(appname);
|
||||
cy.get(homePage.CreateApp)
|
||||
.contains("Submit")
|
||||
.click({ force: true });
|
||||
cy.get("#loading").should("not.exist");
|
||||
cy.wait("@getPropertyPane");
|
||||
cy.get("@getPropertyPane").should("have.property", "status", 200);
|
||||
cy.wait("@getDataSources");
|
||||
cy.get("@getDataSources").should("have.property", "status", 200);
|
||||
cy.wait("@getUser");
|
||||
cy.get("@getUser").should("have.property", "status", 200);
|
||||
});
|
||||
|
||||
Cypress.Commands.add("DeleteApp", appName => {
|
||||
|
|
@ -66,12 +62,64 @@ Cypress.Commands.add("LogintoApp", (uname, pword) => {
|
|||
200,
|
||||
);
|
||||
});
|
||||
|
||||
Cypress.Commands.add("LoginFromAPI", (uname, pword) => {
|
||||
cy.request({
|
||||
method: "POST",
|
||||
url: "api/v1/login",
|
||||
headers: {
|
||||
"content-type": "application/x-www-form-urlencoded",
|
||||
},
|
||||
followRedirect: false,
|
||||
form: true,
|
||||
body: {
|
||||
username: uname,
|
||||
password: pword,
|
||||
},
|
||||
}).then(response => {
|
||||
expect(response.status).equal(302);
|
||||
cy.log(response.body);
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add("DeleteApp", appName => {
|
||||
cy.get(commonlocators.homeIcon).click({ force: true });
|
||||
cy.get(homePage.searchInput).type(appName);
|
||||
cy.wait(2000);
|
||||
cy.get(homePage.appMoreIcon)
|
||||
.first()
|
||||
.click({ force: true });
|
||||
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 });
|
||||
cy.wait(2000);
|
||||
});
|
||||
|
||||
Cypress.Commands.add("LogOut", () => {
|
||||
cy.request("POST", "/api/v1/logout").then(response => {
|
||||
expect(response.status).equal(200);
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add("NavigateToHome", () => {
|
||||
cy.get(commonlocators.homeIcon).click({ force: true });
|
||||
cy.wait("@applications").should(
|
||||
"have.nested.property",
|
||||
"response.body.responseMeta.status",
|
||||
200,
|
||||
);
|
||||
});
|
||||
|
||||
Cypress.Commands.add("NavigateToWidgets", pageName => {
|
||||
cy.get(pages.pagesIcon).click({ force: true });
|
||||
cy.get(".t--page-sidebar-" + pageName + "")
|
||||
|
|
@ -131,13 +179,18 @@ Cypress.Commands.add("CreateAPI", apiname => {
|
|||
.first()
|
||||
.click({ force: true });
|
||||
cy.get(apiwidget.createapi).click({ force: true });
|
||||
cy.wait("@getUser");
|
||||
cy.wait("@createNewApi");
|
||||
//cy.wait("@getUser");
|
||||
cy.get(apiwidget.resourceUrl).should("be.visible");
|
||||
cy.get(apiwidget.apiTxt)
|
||||
.clear()
|
||||
.type(apiname)
|
||||
.blur()
|
||||
.should("have.value", apiname);
|
||||
cy.WaitAutoSave();
|
||||
// Added because api name edit takes some time to
|
||||
// reflect in api sidebar after the call passes.
|
||||
cy.wait(4000);
|
||||
});
|
||||
|
||||
Cypress.Commands.add("CreateSubsequentAPI", apiname => {
|
||||
|
|
@ -145,6 +198,7 @@ Cypress.Commands.add("CreateSubsequentAPI", apiname => {
|
|||
.first()
|
||||
.click({ force: true });
|
||||
cy.get(apiwidget.resourceUrl).should("be.visible");
|
||||
// cy.get(ApiEditor.nameOfApi)
|
||||
cy.get(apiwidget.apiTxt)
|
||||
.clear()
|
||||
.type(apiname)
|
||||
|
|
@ -153,7 +207,7 @@ Cypress.Commands.add("CreateSubsequentAPI", apiname => {
|
|||
});
|
||||
|
||||
Cypress.Commands.add("EditApiName", apiname => {
|
||||
cy.wait("@getUser");
|
||||
//cy.wait("@getUser");
|
||||
cy.get(apiwidget.apiTxt)
|
||||
.clear()
|
||||
.type(apiname)
|
||||
|
|
@ -162,7 +216,8 @@ Cypress.Commands.add("EditApiName", apiname => {
|
|||
});
|
||||
|
||||
Cypress.Commands.add("WaitAutoSave", () => {
|
||||
cy.wait("@saveQuery");
|
||||
//cy.wait("@saveQuery");
|
||||
// cy.wait("@postExecute");
|
||||
});
|
||||
|
||||
Cypress.Commands.add("RunAPI", () => {
|
||||
|
|
@ -203,9 +258,11 @@ Cypress.Commands.add("enterDatasourceAndPath", (datasource, path) => {
|
|||
.first()
|
||||
.click({ force: true })
|
||||
.type(datasource);
|
||||
/*
|
||||
cy.xpath(apiwidget.autoSuggest)
|
||||
.first()
|
||||
.click({ force: true });
|
||||
*/
|
||||
cy.get(apiwidget.editResourceUrl)
|
||||
.first()
|
||||
.click({ force: true })
|
||||
|
|
@ -325,7 +382,8 @@ Cypress.Commands.add("CreationOfUniqueAPIcheck", apiname => {
|
|||
.first()
|
||||
.click({ force: true });
|
||||
cy.get(apiwidget.createapi).click({ force: true });
|
||||
cy.wait("@getUser");
|
||||
cy.wait("@createNewApi");
|
||||
// cy.wait("@getUser");
|
||||
cy.get(apiwidget.resourceUrl).should("be.visible");
|
||||
cy.get(apiwidget.apiTxt)
|
||||
.clear()
|
||||
|
|
@ -477,7 +535,7 @@ Cypress.Commands.add(
|
|||
Cypress.Commands.add("widgetText", (text, inputcss, innercss) => {
|
||||
cy.get(commonlocators.editWidgetName)
|
||||
.dblclick({ force: true })
|
||||
.type(text)
|
||||
.type(text, { force: true })
|
||||
.type("{enter}");
|
||||
cy.get(inputcss)
|
||||
.first()
|
||||
|
|
@ -1061,7 +1119,7 @@ Cypress.Commands.add("validateHTMLText", (widgetCss, htmlTag, value) => {
|
|||
|
||||
Cypress.Commands.add("startServerAndRoutes", () => {
|
||||
cy.server();
|
||||
cy.route("GET", "/api/v1/applications").as("applications");
|
||||
cy.route("GET", "/api/v1/applications/new").as("applications");
|
||||
cy.route("GET", "/api/v1/users/profile").as("getUser");
|
||||
cy.route("GET", "/api/v1/plugins").as("getPlugins");
|
||||
cy.route("POST", "/api/v1/logout").as("postLogout");
|
||||
|
|
@ -1229,7 +1287,7 @@ Cypress.Commands.add("callApi", apiname => {
|
|||
.first()
|
||||
.click();
|
||||
cy.get(commonlocators.singleSelectMenuItem)
|
||||
.contains("Call API")
|
||||
.contains("Call An API")
|
||||
.click();
|
||||
cy.get(commonlocators.selectMenuItem)
|
||||
.contains(apiname)
|
||||
|
|
|
|||
|
|
@ -20,11 +20,26 @@ let appId;
|
|||
|
||||
// Import commands.js using ES2015 syntax:
|
||||
import "./commands";
|
||||
|
||||
Cypress.on("uncaught:exception", (err, runnable) => {
|
||||
// returning false here prevents Cypress from
|
||||
// failing the test
|
||||
return false;
|
||||
});
|
||||
|
||||
before(function() {
|
||||
console.log("**** Got Cypress base URL as: ", process.env.CYPRESS_BASE_URL);
|
||||
cy.startServerAndRoutes();
|
||||
cy.LogintoApp(loginData.username, loginData.password);
|
||||
// cy.SearchApp(inputData.appname)
|
||||
/*
|
||||
cy.LoginFromAPI(loginData.username, loginData.password);
|
||||
cy.visit("/applications");
|
||||
cy.wait("@applications").should(
|
||||
"have.nested.property",
|
||||
"response.body.responseMeta.status",
|
||||
200,
|
||||
);
|
||||
*/
|
||||
cy.generateUUID().then(id => {
|
||||
appId = id;
|
||||
cy.CreateApp(id);
|
||||
|
|
|
|||
|
|
@ -158,6 +158,30 @@ export const executeApiActionSuccess = (payload: {
|
|||
payload: payload,
|
||||
});
|
||||
|
||||
export const editApiName = (payload: { id: string; value: string }) => ({
|
||||
type: ReduxActionTypes.EDIT_API_NAME,
|
||||
payload: payload,
|
||||
});
|
||||
|
||||
export const saveApiName = (payload: { id: string; name: string }) => ({
|
||||
type: ReduxActionTypes.SAVE_API_NAME,
|
||||
payload: payload,
|
||||
});
|
||||
|
||||
export const updateApiNameDraft = (payload: {
|
||||
id: string;
|
||||
draft?: {
|
||||
value: string;
|
||||
validation: {
|
||||
isValid: boolean;
|
||||
validationMessage: string;
|
||||
};
|
||||
};
|
||||
}) => ({
|
||||
type: ReduxActionTypes.UPDATE_API_NAME_DRAFT,
|
||||
payload: payload,
|
||||
});
|
||||
|
||||
export default {
|
||||
createAction: createActionRequest,
|
||||
fetchActions,
|
||||
|
|
|
|||
|
|
@ -94,6 +94,13 @@ export interface CopyActionRequest {
|
|||
pageId: string;
|
||||
}
|
||||
|
||||
export interface UpdateActionNameRequest {
|
||||
pageId: string;
|
||||
layoutId: string;
|
||||
newName: string;
|
||||
oldName: string;
|
||||
}
|
||||
|
||||
class ActionAPI extends API {
|
||||
static url = "v1/actions";
|
||||
|
||||
|
|
@ -125,6 +132,10 @@ class ActionAPI extends API {
|
|||
return API.put(`${ActionAPI.url}/${apiConfig.id}`, apiConfig);
|
||||
}
|
||||
|
||||
static updateActionName(updateActionNameRequest: UpdateActionNameRequest) {
|
||||
return API.put(ActionAPI.url + "/refactor", updateActionNameRequest);
|
||||
}
|
||||
|
||||
static deleteAction(id: string) {
|
||||
return API.delete(`${ActionAPI.url}/${id}`);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -216,8 +216,10 @@ export class ReactTableComponent extends React.Component<
|
|||
Cell: (props: any) => {
|
||||
return renderCell(
|
||||
props.cell.value,
|
||||
props.cell.row.index,
|
||||
columnType.type,
|
||||
isHidden,
|
||||
this.props.widgetId,
|
||||
columnType.format,
|
||||
);
|
||||
},
|
||||
|
|
@ -232,7 +234,10 @@ export class ReactTableComponent extends React.Component<
|
|||
columns = this.reorderColumns(columns);
|
||||
if (this.props.columnActions?.length) {
|
||||
columns.push({
|
||||
Header: "Actions",
|
||||
Header:
|
||||
this.props.columnNameMap && this.props.columnNameMap["actions"]
|
||||
? this.props.columnNameMap["actions"]
|
||||
: "Actions",
|
||||
accessor: "actions",
|
||||
width: 150,
|
||||
minWidth: 60,
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ export const Table = (props: TableProps) => {
|
|||
}),
|
||||
[],
|
||||
);
|
||||
|
||||
const pageCount = Math.ceil(data.length / props.pageSize);
|
||||
const currentPageIndex = props.pageNo < pageCount ? props.pageNo : 0;
|
||||
const {
|
||||
|
|
@ -171,6 +172,8 @@ export const Table = (props: TableProps) => {
|
|||
})}
|
||||
</div>
|
||||
))}
|
||||
{headerGroups.length === 0 &&
|
||||
renderEmptyRows(1, props.columns, props.width)}
|
||||
</div>
|
||||
<div {...getTableBodyProps()} className="tbody">
|
||||
{subPage.map((row, index) => {
|
||||
|
|
@ -204,6 +207,12 @@ export const Table = (props: TableProps) => {
|
|||
</div>
|
||||
);
|
||||
})}
|
||||
{props.pageSize > subPage.length &&
|
||||
renderEmptyRows(
|
||||
props.pageSize - subPage.length,
|
||||
props.columns,
|
||||
props.width,
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -272,3 +281,44 @@ export const Table = (props: TableProps) => {
|
|||
};
|
||||
|
||||
export default Table;
|
||||
|
||||
const renderEmptyRows = (
|
||||
rowCount: number,
|
||||
columns: any,
|
||||
tableWidth: number,
|
||||
) => {
|
||||
const rows: string[] = new Array(rowCount).fill("");
|
||||
const tableColumns = columns.length
|
||||
? columns
|
||||
: new Array(3).fill({ width: tableWidth / 3 });
|
||||
return (
|
||||
<React.Fragment>
|
||||
{rows.map((row: string, index: number) => {
|
||||
return (
|
||||
<div
|
||||
className="tr"
|
||||
key={index}
|
||||
style={{
|
||||
display: "flex",
|
||||
flex: "1 0 auto",
|
||||
}}
|
||||
>
|
||||
{tableColumns.map((column: any, colIndex: number) => {
|
||||
return (
|
||||
<div
|
||||
key={colIndex}
|
||||
className="td"
|
||||
style={{
|
||||
width: column.width + "px",
|
||||
boxSizing: "border-box",
|
||||
flex: `${column.width} 0 auto`,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</React.Fragment>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -11,10 +11,10 @@ export const TableWrapper = styled.div<{ width: number; height: number }>`
|
|||
justify-content: space-between;
|
||||
flex-direction: column;
|
||||
.tableWrap {
|
||||
height: 100%;
|
||||
display: block;
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
border-bottom: 1px solid ${Colors.GEYSER_LIGHT};
|
||||
}
|
||||
.table {
|
||||
border-spacing: 0;
|
||||
|
|
@ -29,16 +29,11 @@ export const TableWrapper = styled.div<{ width: number; height: number }>`
|
|||
height: ${props => props.height - 5 - 102}px;
|
||||
}
|
||||
.tr {
|
||||
:last-child {
|
||||
.td {
|
||||
border-bottom: 0;
|
||||
}
|
||||
}
|
||||
:nth-child(even) {
|
||||
background: ${Colors.ATHENS_GRAY_DARKER};
|
||||
}
|
||||
&.selected-row {
|
||||
background: ${Colors.ATHENS_GRAY};
|
||||
background: ${Colors.POLAR};
|
||||
}
|
||||
&:hover {
|
||||
background: ${Colors.ATHENS_GRAY};
|
||||
|
|
@ -237,7 +232,7 @@ export const CellWrapper = styled.div<{ isHidden: boolean }>`
|
|||
width: 100%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: normal;
|
||||
white-space: nowrap;
|
||||
opacity: ${props => (props.isHidden ? "0.6" : "1")};
|
||||
.image-cell {
|
||||
width: 40px;
|
||||
|
|
@ -251,4 +246,11 @@ export const CellWrapper = styled.div<{ isHidden: boolean }>`
|
|||
video {
|
||||
border-radius: 4px;
|
||||
}
|
||||
&.video-cell {
|
||||
height: 100%;
|
||||
iframe {
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import {
|
|||
} from "./TableStyledWrappers";
|
||||
import { ColumnAction } from "components/propertyControls/ColumnActionSelectorControl";
|
||||
import { ColumnMenuOptionProps } from "./ReactTableComponent";
|
||||
import { isString } from "lodash";
|
||||
|
||||
interface MenuOptionProps {
|
||||
columnAccessor?: string;
|
||||
|
|
@ -272,8 +273,10 @@ export const getMenuOptions = (props: MenuOptionProps) => {
|
|||
|
||||
export const renderCell = (
|
||||
value: any,
|
||||
rowIndex: number,
|
||||
columnType: string,
|
||||
isHidden: boolean,
|
||||
widgetId: string,
|
||||
format?: string,
|
||||
) => {
|
||||
if (!value) {
|
||||
|
|
@ -281,6 +284,13 @@ export const renderCell = (
|
|||
}
|
||||
switch (columnType) {
|
||||
case "image":
|
||||
if (!isString(value)) {
|
||||
return (
|
||||
<CellWrapper isHidden={isHidden}>
|
||||
<div>Invalid Image </div>
|
||||
</CellWrapper>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<CellWrapper isHidden={isHidden}>
|
||||
{value
|
||||
|
|
@ -302,13 +312,25 @@ export const renderCell = (
|
|||
</CellWrapper>
|
||||
);
|
||||
case "video":
|
||||
return (
|
||||
<CellWrapper isHidden={isHidden}>
|
||||
<video width="56" height="32" autoPlay={false}>
|
||||
<source src={`${value}`} type="video/mp4" />
|
||||
</video>
|
||||
</CellWrapper>
|
||||
const youtubeRegex = new RegExp(
|
||||
"^(https?://)?(www.)?(youtube.com|youtu.?be)/embed/.+$",
|
||||
);
|
||||
if (isString(value) && youtubeRegex.test(value)) {
|
||||
return (
|
||||
<CellWrapper isHidden={isHidden} className="video-cell">
|
||||
<iframe
|
||||
title={`video-${widgetId}-${rowIndex}`}
|
||||
width="56"
|
||||
height="32"
|
||||
src={`${value}`}
|
||||
></iframe>
|
||||
</CellWrapper>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<CellWrapper isHidden={isHidden}>Invalid Video Link</CellWrapper>
|
||||
);
|
||||
}
|
||||
case "currency":
|
||||
if (!isNaN(value)) {
|
||||
return (
|
||||
|
|
@ -352,9 +374,11 @@ export const renderCell = (
|
|||
return <CellWrapper isHidden={isHidden}>Invalid Time</CellWrapper>;
|
||||
}
|
||||
case "text":
|
||||
return <CellWrapper isHidden={isHidden}>{value}</CellWrapper>;
|
||||
const text = isString(value) ? value : JSON.stringify(value);
|
||||
return <CellWrapper isHidden={isHidden}>{text}</CellWrapper>;
|
||||
default:
|
||||
return <CellWrapper isHidden={isHidden}>{value}</CellWrapper>;
|
||||
const data = isString(value) ? value : JSON.stringify(value);
|
||||
return <CellWrapper isHidden={isHidden}>{data}</CellWrapper>;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ const Container = styled.div<{
|
|||
&&& {
|
||||
.${Classes.OVERLAY} {
|
||||
.${Classes.OVERLAY_BACKDROP} {
|
||||
z-index: ${props => props.zIndex};
|
||||
z-index: ${props => props.zIndex || 2 - 1};
|
||||
}
|
||||
position: fixed;
|
||||
top: ${props => props.theme.headerHeight};
|
||||
|
|
@ -32,7 +32,6 @@ const Container = styled.div<{
|
|||
border-radius: ${props => props.theme.radii[1]}px;
|
||||
top: ${props => props.top}px;
|
||||
left: ${props => props.left}px;
|
||||
// z-index: ${props => props.zIndex};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -80,7 +79,7 @@ export const ModalComponent = (props: ModalComponentProps) => {
|
|||
height={props.height}
|
||||
top={props.top}
|
||||
left={props.left}
|
||||
zIndex={props.zIndex !== undefined ? props.zIndex : 3}
|
||||
zIndex={props.zIndex !== undefined ? props.zIndex : 2}
|
||||
>
|
||||
<Overlay
|
||||
isOpen={props.isOpen}
|
||||
|
|
|
|||
130
app/client/src/components/editorComponents/ActionNameEditor.tsx
Normal file
130
app/client/src/components/editorComponents/ActionNameEditor.tsx
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
import React, { useEffect, useState } from "react";
|
||||
import { useSelector, useDispatch } from "react-redux";
|
||||
|
||||
import { useParams } from "react-router-dom";
|
||||
import styled from "styled-components";
|
||||
import EditableText, {
|
||||
EditInteractionKind,
|
||||
} from "components/editorComponents/EditableText";
|
||||
import { convertToCamelCase } from "utils/helpers";
|
||||
import { AppState } from "reducers";
|
||||
import { RestAction } from "entities/Action";
|
||||
import { Page } from "constants/ReduxActionConstants";
|
||||
|
||||
import { saveApiName } from "actions/actionActions";
|
||||
import { Spinner } from "@blueprintjs/core";
|
||||
|
||||
const ApiNameWrapper = styled.div`
|
||||
min-width: 50%;
|
||||
margin-right: 10px;
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-content: center;
|
||||
& > div {
|
||||
max-width: 100%;
|
||||
flex: 0 1 auto;
|
||||
font-size: ${props => props.theme.fontSizes[5]}px;
|
||||
font-weight: ${props => props.theme.fontWeights[2]};
|
||||
}
|
||||
`;
|
||||
|
||||
export const ActionNameEditor = () => {
|
||||
const params = useParams<{ apiId?: string; queryId?: string }>();
|
||||
const [forceUpdate, setForceUpdate] = useState(false);
|
||||
const dispatch = useDispatch();
|
||||
if (!params.apiId && !params.queryId) {
|
||||
console.log("No API id or Query id found in the url.");
|
||||
}
|
||||
|
||||
const actions: RestAction[] = useSelector((state: AppState) =>
|
||||
state.entities.actions.map(action => action.config),
|
||||
);
|
||||
|
||||
const existingPageNames: string[] = useSelector((state: AppState) =>
|
||||
state.entities.pageList.pages.map((page: Page) => page.pageName),
|
||||
);
|
||||
|
||||
const currentActionConfig: RestAction | undefined = actions.find(
|
||||
action => action.id === params.apiId || action.id === params.queryId,
|
||||
);
|
||||
|
||||
const existingWidgetNames: string[] = useSelector((state: AppState) =>
|
||||
Object.values(state.entities.canvasWidgets).map(
|
||||
widget => widget.widgetName,
|
||||
),
|
||||
);
|
||||
|
||||
const saveStatus: {
|
||||
isSaving: boolean;
|
||||
error: boolean;
|
||||
} = useSelector((state: AppState) => {
|
||||
const id = currentActionConfig ? currentActionConfig.id : "";
|
||||
return {
|
||||
isSaving: state.ui.apiName.isSaving[id],
|
||||
error: state.ui.apiName.errors[id],
|
||||
};
|
||||
});
|
||||
|
||||
const hasActionNameConflict = (name: string) =>
|
||||
!(
|
||||
existingPageNames.indexOf(name) === -1 &&
|
||||
actions.findIndex(action => action.name === name) === -1 &&
|
||||
existingWidgetNames.indexOf(name) === -1
|
||||
);
|
||||
|
||||
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 handleAPINameChange = (name: string) => {
|
||||
if (
|
||||
currentActionConfig &&
|
||||
name !== currentActionConfig?.name &&
|
||||
!isInvalidActionName(name)
|
||||
) {
|
||||
dispatch(saveApiName({ id: currentActionConfig.id, name }));
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (saveStatus.isSaving === false && saveStatus.error === true) {
|
||||
setForceUpdate(true);
|
||||
} else if (saveStatus.isSaving === true) {
|
||||
setForceUpdate(false);
|
||||
}
|
||||
}, [saveStatus.isSaving, saveStatus.error]);
|
||||
|
||||
return (
|
||||
<ApiNameWrapper>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
}}
|
||||
>
|
||||
<EditableText
|
||||
className="t--action-name-edit-field"
|
||||
type="text"
|
||||
defaultValue={currentActionConfig ? currentActionConfig.name : ""}
|
||||
placeholder="Name of the API in camelCase"
|
||||
forceDefault={forceUpdate}
|
||||
onTextChanged={handleAPINameChange}
|
||||
isInvalid={isInvalidActionName}
|
||||
valueTransform={convertToCamelCase}
|
||||
updating={saveStatus.isSaving}
|
||||
editInteractionKind={EditInteractionKind.SINGLE}
|
||||
/>
|
||||
{saveStatus.isSaving && <Spinner size={16} />}
|
||||
</div>
|
||||
</ApiNameWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default ActionNameEditor;
|
||||
|
|
@ -50,7 +50,6 @@ const buttonStyles = css<{
|
|||
}
|
||||
&.bp3-button {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
justify-content: ${props =>
|
||||
props.skin === undefined
|
||||
? "center"
|
||||
|
|
|
|||
|
|
@ -4,24 +4,51 @@ import {
|
|||
Classes,
|
||||
} from "@blueprintjs/core";
|
||||
import styled from "styled-components";
|
||||
import _ from "lodash";
|
||||
import Edit from "assets/images/EditPen.svg";
|
||||
import ErrorTooltip from "./ErrorTooltip";
|
||||
|
||||
export enum EditInteractionKind {
|
||||
SINGLE,
|
||||
DOUBLE,
|
||||
}
|
||||
|
||||
type EditableTextProps = {
|
||||
type: "text" | "password" | "email" | "phone" | "date";
|
||||
defaultValue: string;
|
||||
onTextChanged: (value: string) => void;
|
||||
isEditing: boolean;
|
||||
placeholder: string;
|
||||
onChange?: (value: string) => void;
|
||||
value?: string;
|
||||
className?: string;
|
||||
valueTransform?: (value: string) => string;
|
||||
isEditingDefault?: boolean;
|
||||
forceDefault?: boolean;
|
||||
updating?: boolean;
|
||||
isInvalid?: (value: string) => string | boolean;
|
||||
editInteractionKind: EditInteractionKind;
|
||||
hideEditIcon?: boolean;
|
||||
};
|
||||
|
||||
const EditPen = styled.img`
|
||||
width: 14px;
|
||||
: hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
`;
|
||||
|
||||
const EditableTextWrapper = styled.div<{ isEditing: 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")};
|
||||
cursor: pointer;
|
||||
padding: 5px 10px;
|
||||
padding: 5px 5px;
|
||||
text-transform: none;
|
||||
flex: 1 0 100%;
|
||||
max-width: 100%;
|
||||
display: flex;
|
||||
&:before,
|
||||
&:after {
|
||||
display: none;
|
||||
|
|
@ -29,34 +56,83 @@ const EditableTextWrapper = styled.div<{ isEditing: boolean }>`
|
|||
}
|
||||
& div.${Classes.EDITABLE_TEXT_INPUT} {
|
||||
text-transform: none;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const TextContainer = styled.div<{ isValid: boolean }>`
|
||||
display: flex;
|
||||
&&&& .bp3-editable-text {
|
||||
border-radius: 3px;
|
||||
border-color: ${props => (props.isValid ? "hsl(0,0%,80%)" : "red")};
|
||||
}
|
||||
`;
|
||||
|
||||
export const EditableText = (props: EditableTextProps) => {
|
||||
const [isEditing, setIsEditing] = useState(props.isEditing);
|
||||
const [isEditing, setIsEditing] = useState(!!props.isEditingDefault);
|
||||
const [value, setValue] = useState(props.defaultValue);
|
||||
|
||||
useEffect(() => {
|
||||
setIsEditing(props.isEditing);
|
||||
}, [props.isEditing]);
|
||||
setValue(props.defaultValue);
|
||||
}, [props.defaultValue]);
|
||||
|
||||
useEffect(() => {
|
||||
if (props.forceDefault === true) setValue(props.defaultValue);
|
||||
}, [props.forceDefault]);
|
||||
|
||||
const edit = (e: any) => {
|
||||
setIsEditing(true);
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
};
|
||||
const onChange = (value: string) => {
|
||||
props.onTextChanged(value);
|
||||
const onChange = (_value: string) => {
|
||||
const isInvalid = props.isInvalid ? props.isInvalid(_value) : false;
|
||||
if (!isInvalid) {
|
||||
props.onTextChanged(_value);
|
||||
} else {
|
||||
setValue(props.defaultValue);
|
||||
}
|
||||
setIsEditing(false);
|
||||
};
|
||||
|
||||
const onInputchange = (_value: string) => {
|
||||
let finalVal: string = _value;
|
||||
if (props.valueTransform) {
|
||||
finalVal = props.valueTransform(_value);
|
||||
}
|
||||
setValue(finalVal);
|
||||
};
|
||||
|
||||
const errorMessage = props.isInvalid && props.isInvalid(value);
|
||||
const error = errorMessage ? errorMessage : undefined;
|
||||
return (
|
||||
<EditableTextWrapper onDoubleClick={edit} isEditing={isEditing}>
|
||||
<BlueprintEditableText
|
||||
{...props}
|
||||
disabled={!isEditing}
|
||||
isEditing={isEditing}
|
||||
onConfirm={onChange}
|
||||
selectAllOnFocus
|
||||
/>
|
||||
<EditableTextWrapper
|
||||
isEditing={isEditing}
|
||||
onDoubleClick={
|
||||
props.editInteractionKind === EditInteractionKind.DOUBLE ? edit : _.noop
|
||||
}
|
||||
onClick={
|
||||
props.editInteractionKind === EditInteractionKind.SINGLE ? edit : _.noop
|
||||
}
|
||||
>
|
||||
<ErrorTooltip isOpen={!!error} message={errorMessage as string}>
|
||||
<TextContainer isValid={!error}>
|
||||
<BlueprintEditableText
|
||||
disabled={!isEditing}
|
||||
isEditing={isEditing}
|
||||
onChange={onInputchange}
|
||||
onConfirm={onChange}
|
||||
selectAllOnFocus
|
||||
value={value}
|
||||
placeholder={props.placeholder}
|
||||
className={props.className}
|
||||
/>
|
||||
{!props.hideEditIcon && !props.updating && !isEditing && (
|
||||
<EditPen src={Edit} alt="Edit pen" />
|
||||
)}
|
||||
</TextContainer>
|
||||
</ErrorTooltip>
|
||||
</EditableTextWrapper>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,159 @@
|
|||
import styled from "styled-components";
|
||||
import React from "react";
|
||||
|
||||
import Edit from "assets/images/EditPen.svg";
|
||||
import ErrorTooltip from "components/editorComponents/ErrorTooltip";
|
||||
import {
|
||||
FIELD_REQUIRED_ERROR,
|
||||
VALID_FUNCTION_NAME_ERROR,
|
||||
UNIQUE_NAME_ERROR,
|
||||
} from "constants/messages";
|
||||
|
||||
const InputContainer = styled.div<{ focused: boolean; isValid: boolean }>`
|
||||
align-items: center;
|
||||
display: flex;
|
||||
position: relative;
|
||||
width: 250px;
|
||||
input {
|
||||
padding: 3px 6px;
|
||||
margin-left: 10px;
|
||||
transition: font-size 0.2s;
|
||||
font-size: ${props => (props.focused ? "17px" : "18px")};
|
||||
border 1px solid;
|
||||
border-radius: 3px;
|
||||
border-color: ${props => {
|
||||
let color = props.focused ? "hsl(0,0%,80%)" : "white";
|
||||
color = !props.isValid ? "red" : color;
|
||||
return color;
|
||||
}};
|
||||
display: block;
|
||||
width: 100%;
|
||||
font-weight: 200;
|
||||
line-height: 24px;
|
||||
text-overflow: ellipsis;
|
||||
:hover {
|
||||
border-color: hsl(0, 0 %, 80 %);
|
||||
cursor: ${props => (props.focused ? "auto" : "pointer")};
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const EditPen = styled.img`
|
||||
height: 14px;
|
||||
width: 14px;
|
||||
position: absolute;
|
||||
right: 7px;
|
||||
: hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
`;
|
||||
|
||||
export function validateEntityName(name: string, allNames?: string[]) {
|
||||
const validation = {
|
||||
isValid: true,
|
||||
validationMessage: "",
|
||||
};
|
||||
|
||||
if (!/^[a-zA-Z_][0-9a-zA-Z_]*$/.test(name)) {
|
||||
validation.isValid = false;
|
||||
validation.validationMessage += VALID_FUNCTION_NAME_ERROR;
|
||||
}
|
||||
if (!name) {
|
||||
validation.isValid = false;
|
||||
validation.validationMessage += FIELD_REQUIRED_ERROR;
|
||||
}
|
||||
|
||||
if (
|
||||
allNames &&
|
||||
allNames.findIndex(entityName => entityName === name) !== -1
|
||||
) {
|
||||
validation.isValid = false;
|
||||
validation.validationMessage += UNIQUE_NAME_ERROR;
|
||||
}
|
||||
|
||||
return validation;
|
||||
}
|
||||
|
||||
interface EntityNameProps {
|
||||
onBlur: Function;
|
||||
onChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
|
||||
value: string;
|
||||
isValid: boolean;
|
||||
validationMessage?: string;
|
||||
focusOnMount?: boolean;
|
||||
readOnly?: boolean;
|
||||
disabled?: boolean;
|
||||
placeholder: string;
|
||||
}
|
||||
|
||||
interface EntityNameState {
|
||||
focused: boolean;
|
||||
}
|
||||
|
||||
class EntityNameComponent extends React.Component<
|
||||
EntityNameProps,
|
||||
EntityNameState
|
||||
> {
|
||||
nameInput!: HTMLInputElement | null;
|
||||
|
||||
constructor(props: EntityNameProps) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
focused: false,
|
||||
};
|
||||
}
|
||||
|
||||
handleFocus = (event: { target: { select: () => any } }) => {
|
||||
event.target.select();
|
||||
};
|
||||
|
||||
onFocus = () => {
|
||||
this.setState({ focused: true });
|
||||
};
|
||||
|
||||
onBlur = () => {
|
||||
this.setState({ focused: false });
|
||||
this.props.onBlur();
|
||||
};
|
||||
|
||||
onPressEnter = (event: any) => {
|
||||
event.preventDefault();
|
||||
event.target.blur();
|
||||
};
|
||||
|
||||
render() {
|
||||
const { focused } = this.state;
|
||||
const {
|
||||
isValid,
|
||||
validationMessage,
|
||||
value,
|
||||
placeholder,
|
||||
onChange,
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<ErrorTooltip isOpen={!isValid} message={validationMessage || ""}>
|
||||
<InputContainer focused={focused} isValid={isValid}>
|
||||
<input
|
||||
value={value}
|
||||
placeholder={placeholder}
|
||||
onChange={onChange}
|
||||
onKeyPress={e => {
|
||||
if (e.key === "Enter") {
|
||||
this.onPressEnter(e);
|
||||
}
|
||||
}}
|
||||
onFocus={this.onFocus}
|
||||
onBlur={this.onBlur}
|
||||
/>
|
||||
{!focused && (
|
||||
<EditPen onClick={this.onFocus} src={Edit} alt="Edit pen" />
|
||||
)}
|
||||
</InputContainer>
|
||||
</ErrorTooltip>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default EntityNameComponent;
|
||||
|
|
@ -17,11 +17,17 @@ const StyledError = styled.span<{ show: boolean }>`
|
|||
|
||||
type FormFieldErrorProps = {
|
||||
error?: string;
|
||||
className?: string;
|
||||
};
|
||||
|
||||
export const FormFieldError = (props: FormFieldErrorProps) => {
|
||||
return (
|
||||
<StyledError show={!!props.error}>{props.error || " "}</StyledError>
|
||||
<StyledError
|
||||
className={props.className ? props.className : undefined}
|
||||
show={!!props.error}
|
||||
>
|
||||
{props.error || " "}
|
||||
</StyledError>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import {
|
|||
WrappedFieldMetaProps,
|
||||
WrappedFieldInputProps,
|
||||
} from "redux-form";
|
||||
import FormFieldError from "components/editorComponents/form/FieldError";
|
||||
import SelectComponent from "components/editorComponents/SelectComponent";
|
||||
|
||||
const renderComponent = (
|
||||
|
|
|
|||
|
|
@ -50,13 +50,13 @@ export function InputText(props: {
|
|||
class InputTextControl extends BaseControl<InputControlProps> {
|
||||
render() {
|
||||
const {
|
||||
errorMessage,
|
||||
expected,
|
||||
propertyValue,
|
||||
isValid,
|
||||
label,
|
||||
placeholderText,
|
||||
dataTreePath,
|
||||
validationMessage,
|
||||
} = this.props;
|
||||
return (
|
||||
<InputText
|
||||
|
|
@ -64,7 +64,7 @@ class InputTextControl extends BaseControl<InputControlProps> {
|
|||
value={propertyValue}
|
||||
onChange={this.onTextChange}
|
||||
isValid={isValid}
|
||||
errorMessage={errorMessage}
|
||||
errorMessage={validationMessage}
|
||||
expected={expected}
|
||||
placeholder={placeholderText}
|
||||
dataTreePath={dataTreePath}
|
||||
|
|
@ -101,6 +101,7 @@ class InputTextControl extends BaseControl<InputControlProps> {
|
|||
export interface InputControlProps extends ControlProps {
|
||||
placeholderText: string;
|
||||
inputType: InputType;
|
||||
validationMessage?: string;
|
||||
isDisabled?: boolean;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -234,6 +234,10 @@ 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",
|
||||
EDIT_API_NAME: "EDIT_API_NAME",
|
||||
SAVE_API_NAME: "SAVE_API_NAME",
|
||||
SAVE_API_NAME_SUCCESS: "SAVE_API_NAME_SUCCESS",
|
||||
UPDATE_API_NAME_DRAFT: "UPDATE_API_NAME_DRAFT",
|
||||
};
|
||||
|
||||
export type ReduxActionType = typeof ReduxActionTypes[keyof typeof ReduxActionTypes];
|
||||
|
|
@ -314,6 +318,7 @@ 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",
|
||||
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",
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ export const VALIDATION_TYPES = {
|
|||
ARRAY: "ARRAY",
|
||||
TABLE_DATA: "TABLE_DATA",
|
||||
OPTIONS_DATA: "OPTIONS_DATA",
|
||||
SINGLE_CHART_DATA: "SINGLE_CHART_DATA",
|
||||
DATE: "DATE",
|
||||
TABS_DATA: "TABS_DATA",
|
||||
CHART_DATA: "CHART_DATA",
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ export const FIELD_REQUIRED_ERROR = "This field is required";
|
|||
export const VALID_FUNCTION_NAME_ERROR =
|
||||
"Must be a valid variable name (camelCase)";
|
||||
export const UNIQUE_NAME_ERROR = "Name must be unique";
|
||||
export const NAME_SPACE_ERROR = "Name must not have spaces";
|
||||
|
||||
export const FORM_VALIDATION_EMPTY_EMAIL = "Please enter an email";
|
||||
export const FORM_VALIDATION_INVALID_EMAIL =
|
||||
|
|
|
|||
|
|
@ -36,9 +36,7 @@ import {
|
|||
} from "actions/metaActions";
|
||||
import AppRoute from "pages/common/AppRoute";
|
||||
import { editorInitializer } from "utils/EditorUtils";
|
||||
import { getCurrentOrg } from "selectors/organizationSelectors";
|
||||
import { PERMISSION_TYPE } from "pages/Applications/permissionHelpers";
|
||||
import { Organization } from "constants/orgConstants";
|
||||
|
||||
const AppViewWrapper = styled.div`
|
||||
margin-top: ${props => props.theme.headerHeight};
|
||||
|
|
|
|||
|
|
@ -12,6 +12,10 @@ const HeaderWrapper = styled(StyledHeader)`
|
|||
display: flex;
|
||||
justify-content: flex-end;
|
||||
`;
|
||||
|
||||
const StyledButton = styled(Button)`
|
||||
max-width: 200px;
|
||||
`;
|
||||
type AppViewerHeaderProps = {
|
||||
url?: string;
|
||||
permissionRequired: string;
|
||||
|
|
@ -27,7 +31,7 @@ export const AppViewerHeader = (props: AppViewerHeaderProps) => {
|
|||
return (
|
||||
<HeaderWrapper>
|
||||
{props.url && hasPermission && (
|
||||
<Button
|
||||
<StyledButton
|
||||
className="t--back-to-editor"
|
||||
href={props.url}
|
||||
intent="primary"
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import {
|
|||
getApplicationViewerPageURL,
|
||||
BUILDER_PAGE_URL,
|
||||
} from "constants/routes";
|
||||
import { Card, Tooltip, Classes, Icon } from "@blueprintjs/core";
|
||||
import { Card, Tooltip, Icon } from "@blueprintjs/core";
|
||||
import { ApplicationPayload } from "constants/ReduxActionConstants";
|
||||
import Button from "components/editorComponents/Button";
|
||||
import {
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ type Props = InjectedFormProps<
|
|||
// TODO(abhinav): abstract onCancel out.
|
||||
|
||||
export const CreateApplicationForm = (props: Props) => {
|
||||
const { error, handleSubmit, pristine, submitting, orgId } = props;
|
||||
const { error, handleSubmit, pristine, submitting } = props;
|
||||
return (
|
||||
<Form onSubmit={handleSubmit(createApplicationFormSubmitHandler)}>
|
||||
{error && !pristine && <FormMessage intent="danger" message={error} />}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import {
|
|||
getIsCreatingApplication,
|
||||
getCreateApplicationError,
|
||||
getIsDeletingApplication,
|
||||
getUserApplicationsOrgs,
|
||||
getUserApplicationsOrgsList,
|
||||
} from "selectors/applicationSelectors";
|
||||
import {
|
||||
|
|
@ -20,11 +19,9 @@ import {
|
|||
import PageWrapper from "pages/common/PageWrapper";
|
||||
import SubHeader from "pages/common/SubHeader";
|
||||
import PageSectionDivider from "pages/common/PageSectionDivider";
|
||||
import { getApplicationPayloads } from "mockComponentProps/ApplicationPayloads";
|
||||
import ApplicationCard from "./ApplicationCard";
|
||||
import CreateApplicationForm from "./CreateApplicationForm";
|
||||
import InviteUsersFormv2 from "pages/organization/InviteUsersFromv2";
|
||||
import { CREATE_APPLICATION_FORM_NAME } from "constants/forms";
|
||||
import { PERMISSION_TYPE, isPermitted } from "./permissionHelpers";
|
||||
import { MenuIcons } from "icons/MenuIcons";
|
||||
import { DELETING_APPLICATION } from "constants/messages";
|
||||
|
|
@ -141,9 +138,6 @@ class Applications extends Component<
|
|||
}
|
||||
|
||||
public render() {
|
||||
const applicationList = this.props.isFetchingApplications
|
||||
? getApplicationPayloads(8)
|
||||
: this.props.applicationList;
|
||||
const Form: any = InviteUsersFormv2;
|
||||
const DropdownProps = (
|
||||
user: User,
|
||||
|
|
@ -221,7 +215,7 @@ class Applications extends Component<
|
|||
/>
|
||||
<PageSectionDivider />
|
||||
{this.props.userOrgs &&
|
||||
this.props.userOrgs.length != 0 &&
|
||||
this.props.userOrgs.length !== 0 &&
|
||||
this.props.userOrgs.map((organizationObject: any) => {
|
||||
const { organization, applications } = organizationObject;
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ import FormRow from "components/editorComponents/FormRow";
|
|||
import { BaseButton } from "components/designSystems/blueprint/ButtonComponent";
|
||||
import { PaginationField } from "api/ActionAPI";
|
||||
import { ReduxActionTypes } from "constants/ReduxActionConstants";
|
||||
import TextField from "components/editorComponents/form/fields/TextField";
|
||||
import DropdownField from "components/editorComponents/form/fields/DropdownField";
|
||||
import DatasourcesField from "components/editorComponents/form/fields/DatasourcesField";
|
||||
import { API_EDITOR_FORM_NAME } from "constants/forms";
|
||||
|
|
@ -29,6 +28,10 @@ import CollapsibleHelp from "components/designSystems/appsmith/help/CollapsibleH
|
|||
import KeyValueFieldArray from "components/editorComponents/form/fields/KeyValueFieldArray";
|
||||
import PostBodyData from "./PostBodyData";
|
||||
import ApiResponseView from "components/editorComponents/ApiResponseView";
|
||||
import { ApiNameValidation } from "reducers/uiReducers/apiPaneReducer";
|
||||
import { AppState } from "reducers";
|
||||
import { getApiName } from "selectors/formSelectors";
|
||||
import ActionNameEditor from "components/editorComponents/ActionNameEditor";
|
||||
|
||||
const Form = styled.form`
|
||||
display: flex;
|
||||
|
|
@ -128,10 +131,23 @@ interface APIFormProps {
|
|||
};
|
||||
dispatch: any;
|
||||
datasourceFieldText: string;
|
||||
apiName: string;
|
||||
apiNameValidation: ApiNameValidation;
|
||||
}
|
||||
|
||||
type Props = APIFormProps & InjectedFormProps<RestAction, APIFormProps>;
|
||||
|
||||
export const NameWrapper = styled.div`
|
||||
width: 49%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
input {
|
||||
margin: 0;
|
||||
box-sizing: border-box;
|
||||
// border: 0;
|
||||
}
|
||||
`;
|
||||
|
||||
const ApiEditorForm: React.FC<Props> = (props: Props) => {
|
||||
const {
|
||||
pluginId,
|
||||
|
|
@ -163,12 +179,9 @@ const ApiEditorForm: React.FC<Props> = (props: Props) => {
|
|||
<Form onSubmit={handleSubmit}>
|
||||
<MainConfiguration>
|
||||
<FormRow>
|
||||
<TextField
|
||||
name="name"
|
||||
placeholder="nameOfApi (camel case)"
|
||||
showError
|
||||
className="t--nameOfApi"
|
||||
/>
|
||||
<NameWrapper className="t--nameOfApi">
|
||||
<ActionNameEditor />
|
||||
</NameWrapper>
|
||||
<ActionButtons className="t--formActionButtons">
|
||||
<ActionButton
|
||||
text="Delete"
|
||||
|
|
@ -276,15 +289,15 @@ const ApiEditorForm: React.FC<Props> = (props: Props) => {
|
|||
|
||||
const selector = formValueSelector(API_EDITOR_FORM_NAME);
|
||||
|
||||
export default connect(state => {
|
||||
export default connect((state: AppState) => {
|
||||
const httpMethodFromForm = selector(state, "actionConfiguration.httpMethod");
|
||||
const actionConfigurationBody = selector(state, "actionConfiguration.body");
|
||||
const actionName = selector(state, "name");
|
||||
const actionConfigurationHeaders = selector(
|
||||
state,
|
||||
"actionConfiguration.headers",
|
||||
);
|
||||
const apiId = selector(state, "id");
|
||||
const actionName = getApiName(state, apiId) || "";
|
||||
|
||||
return {
|
||||
actionName,
|
||||
|
|
|
|||
|
|
@ -22,7 +22,9 @@ import { FormIcons } from "icons/FormIcons";
|
|||
import { BaseTabbedView } from "components/designSystems/appsmith/TabbedView";
|
||||
import Pagination from "./Pagination";
|
||||
import { PaginationType, RestAction } from "entities/Action";
|
||||
|
||||
import { ApiNameValidation } from "reducers/uiReducers/apiPaneReducer";
|
||||
import ActionNameEditor from "components/editorComponents/ActionNameEditor";
|
||||
import { NameWrapper } from "./Form";
|
||||
const Form = styled.form`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
|
@ -114,6 +116,9 @@ interface APIFormProps {
|
|||
location: {
|
||||
pathname: string;
|
||||
};
|
||||
apiName: string;
|
||||
apiId: string;
|
||||
apiNameValidation: ApiNameValidation;
|
||||
dispatch: any;
|
||||
}
|
||||
|
||||
|
|
@ -171,13 +176,21 @@ const RapidApiEditorForm: React.FC<Props> = (props: Props) => {
|
|||
>
|
||||
<MainConfiguration>
|
||||
<FormRow>
|
||||
<DynamicTextField
|
||||
placeholder="Api name"
|
||||
name="name"
|
||||
singleLine
|
||||
setMaxHeight
|
||||
link={providerURL && `http://${providerURL}`}
|
||||
/>
|
||||
<NameWrapper>
|
||||
<ActionNameEditor />
|
||||
<a
|
||||
style={{
|
||||
paddingTop: "7px",
|
||||
}}
|
||||
className="t--apiDocumentationLink"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
href={providerURL && `http://${providerURL}`}
|
||||
>
|
||||
API documentation
|
||||
</a>
|
||||
</NameWrapper>
|
||||
|
||||
<ActionButtons>
|
||||
<ActionButton
|
||||
text="Delete"
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import AnalyticsUtil from "utils/AnalyticsUtil";
|
|||
import { getActionById, getCurrentPageName } from "selectors/editorSelectors";
|
||||
import { Plugin } from "api/PluginApi";
|
||||
import { RapidApiAction, RestAction, PaginationType } from "entities/Action";
|
||||
import { getApiName } from "selectors/formSelectors";
|
||||
|
||||
interface ReduxStateProps {
|
||||
actions: ActionDataState;
|
||||
|
|
@ -32,6 +33,10 @@ interface ReduxStateProps {
|
|||
isDeleting: Record<string, boolean>;
|
||||
allowSave: boolean;
|
||||
apiName: string;
|
||||
apiNameValidation: {
|
||||
isValid: boolean;
|
||||
validationMessage: string;
|
||||
};
|
||||
currentApplication: UserApplication;
|
||||
currentPageName: string | undefined;
|
||||
pages: any;
|
||||
|
|
@ -191,6 +196,8 @@ class ApiEditor extends React.Component<Props> {
|
|||
? this.props.currentApplication.name
|
||||
: ""
|
||||
}
|
||||
apiName={this.props.apiName}
|
||||
apiNameValidation={this.props.apiNameValidation}
|
||||
onChange={this.onChangeHandler}
|
||||
location={this.props.location}
|
||||
/>
|
||||
|
|
@ -198,6 +205,9 @@ class ApiEditor extends React.Component<Props> {
|
|||
|
||||
{formUiComponent === "RapidApiEditorForm" && (
|
||||
<RapidApiEditorForm
|
||||
apiName={this.props.apiName}
|
||||
apiNameValidation={this.props.apiNameValidation}
|
||||
apiId={this.props.match.params.apiId}
|
||||
paginationType={paginationType}
|
||||
isRunning={isRunning[apiId]}
|
||||
isDeleting={isDeleting[apiId]}
|
||||
|
|
@ -225,6 +235,17 @@ class ApiEditor extends React.Component<Props> {
|
|||
const mapStateToProps = (state: AppState, props: any): ReduxStateProps => {
|
||||
const formData = getFormValues(API_EDITOR_FORM_NAME)(state) as RestAction;
|
||||
const apiAction = getActionById(state, props);
|
||||
const apiName = getApiName(state, props.match.params.apiId);
|
||||
const apiNameDraft =
|
||||
state.ui.apiPane.apiName.drafts[props.match.params.apiId];
|
||||
let apiNameValidation = {
|
||||
isValid: true,
|
||||
validationMessage: "",
|
||||
};
|
||||
|
||||
if (apiNameDraft && apiNameDraft.validation) {
|
||||
apiNameValidation = apiNameDraft.validation;
|
||||
}
|
||||
|
||||
const { drafts, isDeleting, isRunning } = state.ui.apiPane;
|
||||
let data: RestAction | ActionData | RapidApiAction | undefined;
|
||||
|
|
@ -245,7 +266,8 @@ const mapStateToProps = (state: AppState, props: any): ReduxStateProps => {
|
|||
currentApplication: getCurrentApplication(state),
|
||||
currentPageName: getCurrentPageName(state),
|
||||
pages: state.entities.pageList.pages,
|
||||
apiName: formData?.name || "",
|
||||
apiName: apiName || "",
|
||||
apiNameValidation: apiNameValidation,
|
||||
plugins: state.entities.plugins.list,
|
||||
pluginId: _.get(data, "pluginId"),
|
||||
paginationType: _.get(data, "actionConfiguration.paginationType"),
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@ class ApiSidebar extends React.Component<Props> {
|
|||
};
|
||||
|
||||
handleCreateNewApiClick = (selectedPageId: string) => {
|
||||
const { history, createNewApiAction } = this.props;
|
||||
const { history } = this.props;
|
||||
const { pageId, applicationId } = this.props.match.params;
|
||||
history.push(
|
||||
API_EDITOR_URL_WITH_SELECTED_PAGE_ID(
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ const PluginImage = styled.img`
|
|||
width: auto;
|
||||
`;
|
||||
|
||||
const FormTitleContainer = styled.div`
|
||||
export const FormTitleContainer = styled.div`
|
||||
flex-direction: row;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
import React, { ReactNode, useState } from "react";
|
||||
import styled from "styled-components";
|
||||
import EditableText from "components/editorComponents/EditableText";
|
||||
import EditableText, {
|
||||
EditInteractionKind,
|
||||
} from "components/editorComponents/EditableText";
|
||||
import { PageListItemCSS } from "./PageListItem";
|
||||
import Button from "components/editorComponents/Button";
|
||||
|
||||
|
|
@ -34,9 +36,10 @@ const CreatePageButton = (props: CreatePageProps) => {
|
|||
className="t--page-name-input"
|
||||
type="text"
|
||||
placeholder="Enter page name"
|
||||
isEditing
|
||||
isEditingDefault
|
||||
defaultValue={props.defaultValue}
|
||||
onTextChanged={onChange}
|
||||
editInteractionKind={EditInteractionKind.SINGLE}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -6,8 +6,11 @@ import ContextDropdown, {
|
|||
} from "components/editorComponents/ContextDropdown";
|
||||
import { MenuIcons } from "icons/MenuIcons";
|
||||
import { Theme } from "constants/DefaultTheme";
|
||||
import EditableText from "components/editorComponents/EditableText";
|
||||
import EditableText, {
|
||||
EditInteractionKind,
|
||||
} from "components/editorComponents/EditableText";
|
||||
import AnalyticsUtil from "utils/AnalyticsUtil";
|
||||
import { Tooltip } from "@blueprintjs/core";
|
||||
|
||||
/** Page List Item */
|
||||
export const PageListItemCSS = css`
|
||||
|
|
@ -89,13 +92,16 @@ const PageListItem = withTheme((props: PageListItemProps) => {
|
|||
>
|
||||
<div>
|
||||
{pageIcon}
|
||||
<EditableText
|
||||
type="text"
|
||||
placeholder="Enter page name"
|
||||
defaultValue={props.name}
|
||||
isEditing={false}
|
||||
onTextChanged={onEditPageName}
|
||||
/>
|
||||
<Tooltip content="Double click to edit">
|
||||
<EditableText
|
||||
type="text"
|
||||
placeholder="Enter page name"
|
||||
defaultValue={props.name}
|
||||
editInteractionKind={EditInteractionKind.DOUBLE}
|
||||
onTextChanged={onEditPageName}
|
||||
hideEditIcon
|
||||
/>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<ContextDropdown
|
||||
options={props.contextActions}
|
||||
|
|
|
|||
|
|
@ -114,7 +114,11 @@ class PropertyPane extends Component<
|
|||
const { widgetProperties } = this.props;
|
||||
if (!widgetProperties) return <PropertyPaneWrapper />;
|
||||
return (
|
||||
<PropertyPaneWrapper>
|
||||
<PropertyPaneWrapper
|
||||
onClick={(e: any) => {
|
||||
e.stopPropagation();
|
||||
}}
|
||||
>
|
||||
<PropertyPaneTitle
|
||||
key={this.props.widgetId}
|
||||
title={widgetProperties.widgetName}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,17 @@
|
|||
import React, { useState, memo, useEffect } from "react";
|
||||
import styled from "styled-components";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import EditableText from "components/editorComponents/EditableText";
|
||||
import EditableText, {
|
||||
EditInteractionKind,
|
||||
} from "components/editorComponents/EditableText";
|
||||
import { updateWidgetName } from "actions/propertyPaneActions";
|
||||
import { AppState } from "reducers";
|
||||
import Spinner from "components/editorComponents/Spinner";
|
||||
import { getExistingWidgetNames } from "sagas/selectors";
|
||||
import { convertToCamelCase } from "utils/helpers";
|
||||
const Wrapper = styled.div`
|
||||
display: inline-flex;
|
||||
justify-content: space-around;
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
`;
|
||||
|
||||
|
|
@ -42,9 +45,6 @@ const PropertyPaneTitle = memo((props: PropertyPaneTitleProps) => {
|
|||
dispatch(updateWidgetName(props.widgetId, value.trim()));
|
||||
}
|
||||
};
|
||||
const textChanged = (value: string) => {
|
||||
setName(value.replace(/\W+/, "_").slice(0, 30));
|
||||
};
|
||||
useEffect(() => {
|
||||
if (updateError) {
|
||||
setName(props.title);
|
||||
|
|
@ -55,12 +55,12 @@ const PropertyPaneTitle = memo((props: PropertyPaneTitleProps) => {
|
|||
<Wrapper>
|
||||
<EditableText
|
||||
type="text"
|
||||
valueTransform={convertToCamelCase}
|
||||
defaultValue={name}
|
||||
onTextChanged={updateTitle}
|
||||
onChange={textChanged}
|
||||
isEditing={isEditing}
|
||||
placeholder={props.title}
|
||||
value={name}
|
||||
updating={updating}
|
||||
editInteractionKind={EditInteractionKind.SINGLE}
|
||||
/>
|
||||
{updating && <Spinner size={16} />}
|
||||
</Wrapper>
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ const Wrapper = styled.div`
|
|||
grid-template-columns: 1fr 4fr;
|
||||
width: ${props => props.theme.sidebarWidth};
|
||||
box-shadow: 0px 1px 3px ${props => props.theme.colors.paneBG};
|
||||
z-index: 2;
|
||||
z-index: 3;
|
||||
`;
|
||||
|
||||
const NavBar = styled.div`
|
||||
|
|
|
|||
|
|
@ -1,12 +1,10 @@
|
|||
import React, { useEffect } from "react";
|
||||
import { Route } from "react-router-dom";
|
||||
import { useDispatch } from "react-redux";
|
||||
import {
|
||||
useShowPropertyPane,
|
||||
useWidgetSelection,
|
||||
} from "utils/hooks/dragResizeHooks";
|
||||
import AnalyticsUtil from "utils/AnalyticsUtil";
|
||||
import { setCurrentUserDetails } from "actions/userActions";
|
||||
|
||||
export const WrappedComponent = (props: any) => {
|
||||
const showPropertyPane = useShowPropertyPane();
|
||||
|
|
@ -31,8 +29,6 @@ const AppRoute = ({
|
|||
name: string;
|
||||
location?: any;
|
||||
}) => {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
useEffect(() => {
|
||||
if (!rest.logDisable) {
|
||||
AnalyticsUtil.logEvent("NAVIGATE_EDITOR", {
|
||||
|
|
|
|||
|
|
@ -1,55 +1,8 @@
|
|||
import React from "react";
|
||||
import Badge from "./Badge";
|
||||
import { Directions } from "utils/helpers";
|
||||
import { ReduxActionTypes } from "constants/ReduxActionConstants";
|
||||
import { getOnSelectAction, DropdownOnSelectActions } from "./dropdownHelpers";
|
||||
import DropdownComponent, { CustomizedDropdownProps } from "./index";
|
||||
import { Org } from "constants/orgConstants";
|
||||
import { CustomizedDropdownProps } from "./index";
|
||||
import { User } from "constants/userConstants";
|
||||
import FormDialogComponent from "components/editorComponents/form/FormDialogComponent";
|
||||
import CreateOrganizationForm from "pages/organization/CreateOrganizationForm";
|
||||
|
||||
const switchdropdown = (
|
||||
orgs: Org[],
|
||||
currentOrg: Org,
|
||||
): CustomizedDropdownProps => ({
|
||||
sections: [
|
||||
{
|
||||
isSticky: true,
|
||||
options: [
|
||||
{
|
||||
content: (
|
||||
<FormDialogComponent
|
||||
trigger="Create Organization"
|
||||
Form={CreateOrganizationForm}
|
||||
title="Create Organization"
|
||||
/>
|
||||
),
|
||||
shouldCloseDropdown: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
options: orgs
|
||||
.filter(org => org.id !== currentOrg.id)
|
||||
.map(org => ({
|
||||
content: org.name,
|
||||
onSelect: () =>
|
||||
getOnSelectAction(DropdownOnSelectActions.DISPATCH, {
|
||||
type: ReduxActionTypes.SWITCH_ORGANIZATION_INIT,
|
||||
payload: {
|
||||
orgId: org.id,
|
||||
},
|
||||
}),
|
||||
})),
|
||||
},
|
||||
],
|
||||
trigger: {
|
||||
text: "Switch Organization",
|
||||
},
|
||||
openDirection: Directions.RIGHT,
|
||||
openOnHover: true,
|
||||
});
|
||||
|
||||
export const options = (
|
||||
user: User,
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ export const PageHeader = (props: PageHeaderProps) => {
|
|||
<StyledPageHeader>
|
||||
<LogoContainer>
|
||||
<a href="/applications">
|
||||
<img className="logoimg" src={Logo} />
|
||||
<img className="logoimg" src={Logo} alt="Appsmith Logo" />
|
||||
</a>
|
||||
</LogoContainer>
|
||||
<StyledDropDownContainer>
|
||||
|
|
|
|||
|
|
@ -1,24 +1,20 @@
|
|||
import React, { useEffect } from "react";
|
||||
import styled from "styled-components";
|
||||
import TagListField from "components/editorComponents/form/fields/TagListField";
|
||||
import FormGroup from "components/editorComponents/form/FormGroup";
|
||||
import { reduxForm } from "redux-form";
|
||||
import SelectField from "components/editorComponents/form/fields/SelectField";
|
||||
import Button from "components/editorComponents/Button";
|
||||
import { connect } from "react-redux";
|
||||
import { AppState } from "reducers";
|
||||
import {
|
||||
getRoles,
|
||||
getDefaultRole,
|
||||
getRolesForField,
|
||||
getAllUsers,
|
||||
} from "selectors/organizationSelectors";
|
||||
import { ReduxActionTypes } from "constants/ReduxActionConstants";
|
||||
import { InviteUsersToOrgFormValues, inviteUsersToOrg } from "./helpers";
|
||||
import { OrgRole } from "constants/orgConstants";
|
||||
import { INVITE_USERS_TO_ORG_FORM } from "constants/forms";
|
||||
import { Classes } from "@blueprintjs/core";
|
||||
import { noop } from "lodash";
|
||||
import FormMessage from "components/editorComponents/form/FormMessage";
|
||||
import {
|
||||
INVITE_USERS_SUBMIT_SUCCESS,
|
||||
|
|
@ -89,11 +85,13 @@ const InviteUsersForm = (props: any) => {
|
|||
submitFailed,
|
||||
submitSucceeded,
|
||||
error,
|
||||
fetchUser,
|
||||
fetchAllRoles,
|
||||
} = props;
|
||||
useEffect(() => {
|
||||
props.fetchUser(props.orgId);
|
||||
props.fetchAllRoles(props.orgId);
|
||||
}, [props.orgId]);
|
||||
fetchUser(props.orgId);
|
||||
fetchAllRoles(props.orgId);
|
||||
}, [props.orgId, fetchUser, fetchAllRoles]);
|
||||
|
||||
return (
|
||||
<StyledForm>
|
||||
|
|
|
|||
|
|
@ -1,27 +1,23 @@
|
|||
import React, { useEffect } from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { Icon } from "@blueprintjs/core";
|
||||
import _ from "lodash";
|
||||
import {
|
||||
GridComponent,
|
||||
ColumnsDirective,
|
||||
ColumnDirective,
|
||||
} from "@syncfusion/ej2-react-grids";
|
||||
import { useHistory } from "react-router-dom";
|
||||
import { AppState } from "reducers";
|
||||
import {
|
||||
getCurrentOrg,
|
||||
getAllUsers,
|
||||
getAllRoles,
|
||||
getOrgs,
|
||||
} from "selectors/organizationSelectors";
|
||||
import { ORG_INVITE_USERS_PAGE_URL } from "constants/routes";
|
||||
import PageSectionDivider from "pages/common/PageSectionDivider";
|
||||
import PageSectionHeader from "pages/common/PageSectionHeader";
|
||||
import { ReduxActionTypes } from "constants/ReduxActionConstants";
|
||||
import InviteUsersFormv2 from "pages/organization/InviteUsersFromv2";
|
||||
import Button from "components/editorComponents/Button";
|
||||
import { Org, OrgUser, Organization } from "constants/orgConstants";
|
||||
import { OrgUser, Organization } from "constants/orgConstants";
|
||||
import { Menu, MenuItem, Popover, Position } from "@blueprintjs/core";
|
||||
import styled from "styled-components";
|
||||
import { FormIcons } from "icons/FormIcons";
|
||||
|
|
@ -87,7 +83,6 @@ const StyledMenu = styled(Menu)`
|
|||
`;
|
||||
|
||||
export const OrgSettings = (props: PageProps) => {
|
||||
const history = useHistory();
|
||||
const {
|
||||
match: {
|
||||
params: { orgId },
|
||||
|
|
@ -95,6 +90,9 @@ export const OrgSettings = (props: PageProps) => {
|
|||
deleteOrgUser,
|
||||
changeOrgUserRole,
|
||||
allOrgs,
|
||||
fetchUser,
|
||||
fetchAllRoles,
|
||||
getAllApplication,
|
||||
} = props;
|
||||
|
||||
const userTableData = props.allUsers.map(user => ({
|
||||
|
|
@ -105,10 +103,10 @@ export const OrgSettings = (props: PageProps) => {
|
|||
const currentOrgName = currentOrg?.organization.name ?? "";
|
||||
|
||||
useEffect(() => {
|
||||
props.fetchUser(orgId);
|
||||
props.fetchAllRoles(orgId);
|
||||
props.getAllApplication();
|
||||
}, [orgId]);
|
||||
fetchUser(orgId);
|
||||
fetchAllRoles(orgId);
|
||||
getAllApplication();
|
||||
}, [orgId, fetchUser, fetchAllRoles, getAllApplication]);
|
||||
|
||||
const Dropdown = (props: DropdownProps) => {
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import { MetaState } from "./entityReducers/metaReducer";
|
|||
import { ImportReduxState } from "reducers/uiReducers/importReducer";
|
||||
import { ActionDraftsState } from "reducers/entityReducers/actionDraftsReducer";
|
||||
import { HelpReduxState } from "./uiReducers/helpReducer";
|
||||
import { ApiNameReduxState } from "./uiReducers/apiNameReducer";
|
||||
|
||||
const appReducer = combineReducers({
|
||||
entities: entityReducer,
|
||||
|
|
@ -57,6 +58,7 @@ export interface AppState {
|
|||
queryPane: QueryPaneReduxState;
|
||||
datasourcePane: DatasourcePaneReduxState;
|
||||
help: HelpReduxState;
|
||||
apiName: ApiNameReduxState;
|
||||
};
|
||||
entities: {
|
||||
canvasWidgets: CanvasWidgetsReduxState;
|
||||
|
|
|
|||
70
app/client/src/reducers/uiReducers/apiNameReducer.ts
Normal file
70
app/client/src/reducers/uiReducers/apiNameReducer.ts
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
import { createReducer } from "utils/AppsmithUtils";
|
||||
import {
|
||||
ReduxAction,
|
||||
ReduxActionTypes,
|
||||
ReduxActionErrorTypes,
|
||||
} from "constants/ReduxActionConstants";
|
||||
|
||||
const initialState: ApiNameReduxState = {
|
||||
isSaving: {},
|
||||
errors: {},
|
||||
};
|
||||
|
||||
const apiNameReducer = createReducer(initialState, {
|
||||
[ReduxActionErrorTypes.SAVE_API_NAME_ERROR]: (
|
||||
state: ApiNameReduxState,
|
||||
action: ReduxAction<{ actionId: string }>,
|
||||
) => {
|
||||
return {
|
||||
...state,
|
||||
isSaving: {
|
||||
...state.isSaving,
|
||||
[action.payload.actionId]: false,
|
||||
},
|
||||
errors: {
|
||||
...state.errors,
|
||||
[action.payload.actionId]: true,
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
[ReduxActionTypes.SAVE_API_NAME]: (
|
||||
state: ApiNameReduxState,
|
||||
action: ReduxAction<{ id: string }>,
|
||||
) => {
|
||||
return {
|
||||
...state,
|
||||
isSaving: {
|
||||
...state.isSaving,
|
||||
[action.payload.id]: true,
|
||||
},
|
||||
errors: {
|
||||
...state.errors,
|
||||
[action.payload.id]: false,
|
||||
},
|
||||
};
|
||||
},
|
||||
[ReduxActionTypes.SAVE_API_NAME_SUCCESS]: (
|
||||
state: ApiNameReduxState,
|
||||
action: ReduxAction<{ actionId: string }>,
|
||||
) => {
|
||||
return {
|
||||
...state,
|
||||
isSaving: {
|
||||
...state.isSaving,
|
||||
[action.payload.actionId]: false,
|
||||
},
|
||||
errors: {
|
||||
...state.errors,
|
||||
[action.payload.actionId]: false,
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export interface ApiNameReduxState {
|
||||
isSaving: Record<string, boolean>;
|
||||
errors: Record<string, boolean>;
|
||||
}
|
||||
|
||||
export default apiNameReducer;
|
||||
|
|
@ -19,8 +19,15 @@ const initialState: ApiPaneReduxState = {
|
|||
lastSelectedPage: "",
|
||||
extraformData: {},
|
||||
datasourceFieldText: {},
|
||||
apiName: {
|
||||
drafts: {},
|
||||
isSaving: {},
|
||||
},
|
||||
};
|
||||
|
||||
export interface ApiNameValidation {
|
||||
isValid: boolean;
|
||||
validationMessage: string;
|
||||
}
|
||||
export interface ApiPaneReduxState {
|
||||
lastUsed: string;
|
||||
isFetching: boolean;
|
||||
|
|
@ -33,6 +40,16 @@ export interface ApiPaneReduxState {
|
|||
datasourceFieldText: Record<string, string>;
|
||||
lastSelectedPage: string;
|
||||
extraformData: Record<string, any>;
|
||||
apiName: {
|
||||
drafts: Record<
|
||||
string,
|
||||
{
|
||||
value: string;
|
||||
validation: ApiNameValidation;
|
||||
}
|
||||
>;
|
||||
isSaving: Record<string, boolean>;
|
||||
};
|
||||
}
|
||||
|
||||
const apiPaneReducer = createReducer(initialState, {
|
||||
|
|
@ -216,6 +233,35 @@ const apiPaneReducer = createReducer(initialState, {
|
|||
},
|
||||
};
|
||||
},
|
||||
|
||||
[ReduxActionTypes.UPDATE_API_NAME_DRAFT]: (
|
||||
state: ApiPaneReduxState,
|
||||
action: ReduxAction<{
|
||||
id: string;
|
||||
draft?: {
|
||||
value: string;
|
||||
validation: {
|
||||
isValid: boolean;
|
||||
validationMessage: string;
|
||||
};
|
||||
};
|
||||
}>,
|
||||
) => {
|
||||
const { id, draft } = action.payload;
|
||||
let nameDrafts = {
|
||||
...state.apiName.drafts,
|
||||
[id]: draft,
|
||||
};
|
||||
if (!draft) {
|
||||
nameDrafts = _.omit(nameDrafts, id);
|
||||
}
|
||||
return {
|
||||
...state,
|
||||
apiName: {
|
||||
drafts: nameDrafts,
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default apiPaneReducer;
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import providersReducer from "./providerReducer";
|
|||
import importReducer from "./importReducer";
|
||||
import queryPaneReducer from "./queryPaneReducer";
|
||||
import helpReducer from "./helpReducer";
|
||||
import apiNameReducer from "./apiNameReducer";
|
||||
|
||||
const uiReducer = combineReducers({
|
||||
widgetSidebar: widgetSidebarReducer,
|
||||
|
|
@ -35,5 +36,6 @@ const uiReducer = combineReducers({
|
|||
queryPane: queryPaneReducer,
|
||||
datasourcePane: datasourcePaneReducer,
|
||||
help: helpReducer,
|
||||
apiName: apiNameReducer,
|
||||
});
|
||||
export default uiReducer;
|
||||
|
|
|
|||
|
|
@ -30,6 +30,8 @@ import _ from "lodash";
|
|||
import { mapToPropList } from "utils/AppsmithUtils";
|
||||
import { AppToaster } from "components/editorComponents/ToastComponent";
|
||||
import { GenericApiResponse } from "api/ApiResponses";
|
||||
import PageApi from "api/PageApi";
|
||||
import { updateCanvasWithDSL } from "sagas/PageSagas";
|
||||
import {
|
||||
copyActionError,
|
||||
copyActionSuccess,
|
||||
|
|
@ -42,6 +44,8 @@ import {
|
|||
moveActionError,
|
||||
moveActionSuccess,
|
||||
updateActionSuccess,
|
||||
updateApiNameDraft,
|
||||
fetchActionsForPage,
|
||||
} from "actions/actionActions";
|
||||
import {
|
||||
getDynamicBindings,
|
||||
|
|
@ -62,6 +66,7 @@ import {
|
|||
import {
|
||||
getCurrentApplicationId,
|
||||
getPageList,
|
||||
getCurrentPageId,
|
||||
} from "selectors/editorSelectors";
|
||||
import history from "utils/history";
|
||||
import {
|
||||
|
|
@ -73,6 +78,9 @@ import AnalyticsUtil from "utils/AnalyticsUtil";
|
|||
import * as log from "loglevel";
|
||||
import { QUERY_CONSTANT } from "constants/QueryEditorConstants";
|
||||
import { RestAction } from "entities/Action";
|
||||
import { validateEntityName } from "components/editorComponents/EntityNameComponent";
|
||||
import { ActionData } from "reducers/entityReducers/actionsReducer";
|
||||
import { getActions } from "selectors/entitiesSelector";
|
||||
|
||||
export const getAction = (
|
||||
state: AppState,
|
||||
|
|
@ -466,6 +474,10 @@ export function* updateActionSaga(
|
|||
if (isApi) {
|
||||
action = transformRestAction(data);
|
||||
}
|
||||
|
||||
action.name = (yield select(getActions)).find(
|
||||
(act: any) => act.config.id === action.id,
|
||||
)?.config.name;
|
||||
const response: GenericApiResponse<RestAction> = yield ActionAPI.updateAPI(
|
||||
action,
|
||||
);
|
||||
|
|
@ -742,6 +754,103 @@ function* copyActionSaga(
|
|||
}
|
||||
}
|
||||
|
||||
function* editApiNameSaga(action: ReduxAction<{ id: string; value: string }>) {
|
||||
const actionNames = yield select(state =>
|
||||
state.entities.actions.map((action: ActionData) => action.config.name),
|
||||
);
|
||||
const draftActionNames = yield select(state =>
|
||||
Object.values(state.ui.apiPane.apiName.drafts),
|
||||
);
|
||||
//TODO: If an api is in saving state, then it should not use that name as well.
|
||||
const validation = validateEntityName(action.payload.value, [
|
||||
...actionNames,
|
||||
...draftActionNames,
|
||||
]);
|
||||
|
||||
yield put(
|
||||
updateApiNameDraft({
|
||||
id: action.payload.id,
|
||||
draft: {
|
||||
value: action.payload.value,
|
||||
validation: validation,
|
||||
},
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
export function* refactorActionName(
|
||||
id: string,
|
||||
pageId: string,
|
||||
oldName: string,
|
||||
newName: string,
|
||||
) {
|
||||
// fetch page of the action
|
||||
const pageResponse = yield call(PageApi.fetchPage, {
|
||||
pageId: pageId,
|
||||
});
|
||||
// check if page request is successful
|
||||
const isPageRequestSuccessful = yield validateResponse(pageResponse);
|
||||
if (isPageRequestSuccessful) {
|
||||
// get the layoutId from the page response
|
||||
const layoutId = pageResponse.data.layouts[0].id;
|
||||
// call to refactor action
|
||||
const refactorResponse = yield ActionAPI.updateActionName({
|
||||
layoutId,
|
||||
pageId: pageId,
|
||||
oldName: oldName,
|
||||
newName: newName,
|
||||
});
|
||||
|
||||
const isRefactorSuccessful = yield validateResponse(refactorResponse);
|
||||
|
||||
const currentPageId = yield select(getCurrentPageId);
|
||||
if (isRefactorSuccessful) {
|
||||
yield put({
|
||||
type: ReduxActionTypes.SAVE_API_NAME_SUCCESS,
|
||||
payload: {
|
||||
actionId: id,
|
||||
},
|
||||
});
|
||||
if (currentPageId === pageId) {
|
||||
yield updateCanvasWithDSL(refactorResponse.data, pageId, layoutId);
|
||||
} else {
|
||||
yield put(fetchActionsForPage(pageId));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function* saveApiNameSaga(action: ReduxAction<{ id: string; name: string }>) {
|
||||
// Takes from drafts, checks if the name isValid, saves
|
||||
try {
|
||||
const apiId = action.payload.id;
|
||||
const api = yield select(state =>
|
||||
state.entities.actions.find(
|
||||
(action: ActionData) => action.config.id === apiId,
|
||||
),
|
||||
);
|
||||
|
||||
yield refactorActionName(
|
||||
api.config.id,
|
||||
api.config.pageId,
|
||||
api.config.name,
|
||||
action.payload.name,
|
||||
);
|
||||
} catch (e) {
|
||||
yield put({
|
||||
type: ReduxActionErrorTypes.SAVE_API_NAME_ERROR,
|
||||
payload: {
|
||||
actionId: action.payload.id,
|
||||
},
|
||||
});
|
||||
AppToaster.show({
|
||||
message: `Unable to update API name`,
|
||||
type: ToastType.ERROR,
|
||||
});
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
export function* watchActionSagas() {
|
||||
yield all([
|
||||
takeEvery(ReduxActionTypes.FETCH_ACTIONS_INIT, fetchActionsSaga),
|
||||
|
|
@ -750,6 +859,8 @@ export function* watchActionSagas() {
|
|||
takeEvery(ReduxActionTypes.CREATE_ACTION_INIT, createActionSaga),
|
||||
takeLatest(ReduxActionTypes.UPDATE_ACTION_INIT, updateActionSaga),
|
||||
takeLatest(ReduxActionTypes.DELETE_ACTION_INIT, deleteActionSaga),
|
||||
takeLatest(ReduxActionTypes.EDIT_API_NAME, editApiNameSaga),
|
||||
takeLatest(ReduxActionTypes.SAVE_API_NAME, saveApiNameSaga),
|
||||
takeLatest(
|
||||
ReduxActionTypes.EXECUTE_PAGE_LOAD_ACTIONS,
|
||||
executePageLoadActionsSaga,
|
||||
|
|
|
|||
|
|
@ -231,7 +231,7 @@ function* changeApiSaga(actionPayload: ReduxAction<{ id: string }>) {
|
|||
data = draft;
|
||||
}
|
||||
|
||||
yield put(initialize(API_EDITOR_FORM_NAME, data));
|
||||
yield put(initialize(API_EDITOR_FORM_NAME, _.omit(data, "name")));
|
||||
history.push(API_EDITOR_ID_URL(applicationId, pageId, id));
|
||||
|
||||
yield call(initializeExtraFormDataSaga);
|
||||
|
|
@ -426,7 +426,7 @@ function* handleActionCreatedSaga(actionPayload: ReduxAction<RestAction>) {
|
|||
const data = { ...action };
|
||||
|
||||
if (pluginType === "API") {
|
||||
yield put(initialize(API_EDITOR_FORM_NAME, data));
|
||||
yield put(initialize(API_EDITOR_FORM_NAME, _.omit(data, "name")));
|
||||
const applicationId = yield select(getCurrentApplicationId);
|
||||
const pageId = yield select(getCurrentPageId);
|
||||
history.push(API_EDITOR_ID_URL(applicationId, pageId, id));
|
||||
|
|
@ -465,7 +465,7 @@ function* handleMoveOrCopySaga(actionPayload: ReduxAction<{ id: string }>) {
|
|||
API_EDITOR_FORM_NAME,
|
||||
);
|
||||
if (values.id === id) {
|
||||
yield put(initialize(API_EDITOR_FORM_NAME, action));
|
||||
yield put(initialize(API_EDITOR_FORM_NAME, _.omit(action, "name")));
|
||||
} else {
|
||||
yield put(changeApi(id));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ import ApplicationApi, {
|
|||
ApplicationPagePayload,
|
||||
SetDefaultPageRequest,
|
||||
DeleteApplicationRequest,
|
||||
GetAllApplicationResponse,
|
||||
FetchUsersApplicationsOrgsResponse,
|
||||
OrganizationApplicationObject,
|
||||
ApplicationObject,
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ import OrgApi, {
|
|||
CreateOrgRequest,
|
||||
FetchAllUsersResponse,
|
||||
FetchAllUsersRequest,
|
||||
FetchAllRolesRequest,
|
||||
FetchAllRolesResponse,
|
||||
DeleteOrgUserRequest,
|
||||
ChangeUserRoleRequest,
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import PageApi, {
|
|||
DeletePageRequest,
|
||||
UpdateWidgetNameRequest,
|
||||
UpdateWidgetNameResponse,
|
||||
PageLayout,
|
||||
} from "api/PageApi";
|
||||
import { FlattenedWidgetProps } from "reducers/entityReducers/canvasWidgetsReducer";
|
||||
import {
|
||||
|
|
@ -369,23 +370,7 @@ export function* updateWidgetNameSaga(
|
|||
);
|
||||
const isValidResponse = yield validateResponse(response);
|
||||
if (isValidResponse) {
|
||||
const normalizedWidgets = CanvasWidgetsNormalizer.normalize(
|
||||
response.data.dsl,
|
||||
);
|
||||
const currentPageName = yield select(getCurrentPageName);
|
||||
const applicationId = yield select(getCurrentApplicationId);
|
||||
const canvasWidgetsPayload: UpdateCanvasPayload = {
|
||||
pageWidgetId: normalizedWidgets.result,
|
||||
currentPageName,
|
||||
currentPageId: pageId,
|
||||
currentLayoutId: layoutId,
|
||||
currentApplicationId: applicationId,
|
||||
pageActions: response.data.layoutOnLoadActions,
|
||||
widgets: normalizedWidgets.entities.canvasWidgets,
|
||||
};
|
||||
|
||||
yield put(updateCanvas(canvasWidgetsPayload));
|
||||
yield put(fetchActionsForPage(pageId));
|
||||
yield updateCanvasWithDSL(response.data, pageId, layoutId);
|
||||
|
||||
yield put(updateWidgetNameSuccess());
|
||||
}
|
||||
|
|
@ -409,6 +394,27 @@ export function* updateWidgetNameSaga(
|
|||
}
|
||||
}
|
||||
|
||||
export function* updateCanvasWithDSL(
|
||||
data: PageLayout,
|
||||
pageId: string,
|
||||
layoutId: string,
|
||||
) {
|
||||
const normalizedWidgets = CanvasWidgetsNormalizer.normalize(data.dsl);
|
||||
const currentPageName = yield select(getCurrentPageName);
|
||||
const applicationId = yield select(getCurrentApplicationId);
|
||||
const canvasWidgetsPayload: UpdateCanvasPayload = {
|
||||
pageWidgetId: normalizedWidgets.result,
|
||||
currentPageName,
|
||||
currentPageId: pageId,
|
||||
currentLayoutId: layoutId,
|
||||
currentApplicationId: applicationId,
|
||||
pageActions: data.layoutOnLoadActions,
|
||||
widgets: normalizedWidgets.entities.canvasWidgets,
|
||||
};
|
||||
yield put(updateCanvas(canvasWidgetsPayload));
|
||||
yield put(fetchActionsForPage(pageId));
|
||||
}
|
||||
|
||||
export default function* pageSagas() {
|
||||
yield all([
|
||||
takeLatest(ReduxActionTypes.FETCH_PAGE_INIT, fetchPageSaga),
|
||||
|
|
|
|||
|
|
@ -12,8 +12,6 @@ import UserApi, {
|
|||
ForgotPasswordRequest,
|
||||
VerifyTokenRequest,
|
||||
TokenPasswordUpdateRequest,
|
||||
FetchUserRequest,
|
||||
FetchUserResponse,
|
||||
SwitchUserOrgRequest,
|
||||
AddUserToOrgRequest,
|
||||
} from "api/UserApi";
|
||||
|
|
@ -25,11 +23,6 @@ import {
|
|||
getResponseErrorMessage,
|
||||
callAPI,
|
||||
} from "./ErrorSagas";
|
||||
import * as Sentry from "@sentry/browser";
|
||||
|
||||
import { fetchOrgsSaga } from "./OrgSagas";
|
||||
|
||||
import { resetAuthExpiration } from "utils/storage";
|
||||
import {
|
||||
logoutUserSuccess,
|
||||
logoutUserError,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { getFormValues, isValid, getFormInitialValues } from "redux-form";
|
||||
import { AppState } from "reducers";
|
||||
import { RestAction } from "entities/Action";
|
||||
import { ActionData } from "reducers/entityReducers/actionsReducer";
|
||||
|
||||
type GetFormData = (
|
||||
state: AppState,
|
||||
|
|
@ -15,3 +16,16 @@ export const getFormData: GetFormData = (state, formName) => {
|
|||
const valid = isValid(formName)(state);
|
||||
return { initialValues, values, dirty, valid };
|
||||
};
|
||||
|
||||
export const getApiName = (state: AppState, id: string) => {
|
||||
const apiNameDraft = state.ui.apiPane.apiName.drafts[id]?.value;
|
||||
|
||||
if (apiNameDraft === undefined) {
|
||||
return state.entities.actions.find(
|
||||
(action: ActionData) => action.config.id === id,
|
||||
)?.config.name;
|
||||
} else {
|
||||
// If there is something in drafts, return draft value.
|
||||
return apiNameDraft;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { createSelector } from "reselect";
|
||||
import { AppState } from "reducers";
|
||||
import { OrgRole, Org, Organization } from "constants/orgConstants";
|
||||
import { OrgRole, Organization } from "constants/orgConstants";
|
||||
|
||||
export const getRolesFromState = (state: AppState) => {
|
||||
return state.ui.orgs.roles;
|
||||
|
|
|
|||
|
|
@ -245,22 +245,24 @@ export const VALIDATORS: Record<ValidationType, Validator> = {
|
|||
if (!isValid) {
|
||||
return {
|
||||
isValid,
|
||||
parsed,
|
||||
message: `${WIDGET_TYPE_VALIDATION_ERROR}: Table Data`,
|
||||
parsed: [],
|
||||
transformed: parsed,
|
||||
message: `${WIDGET_TYPE_VALIDATION_ERROR}: [{ "Col1" : "val1", "Col2" : "val2" }]`,
|
||||
};
|
||||
} else if (
|
||||
!_.every(parsed, datum => {
|
||||
return (
|
||||
_.isObject(datum) &&
|
||||
Object.keys(datum).filter(key => _.isString(key) && key.length === 0)
|
||||
.length === 0
|
||||
);
|
||||
})
|
||||
) {
|
||||
}
|
||||
const isValidTableData = _.every(parsed, datum => {
|
||||
return (
|
||||
_.isObject(datum) &&
|
||||
Object.keys(datum).filter(key => _.isString(key) && key.length === 0)
|
||||
.length === 0
|
||||
);
|
||||
});
|
||||
if (!isValidTableData) {
|
||||
return {
|
||||
isValid: false,
|
||||
parsed: [],
|
||||
message: `${WIDGET_TYPE_VALIDATION_ERROR}: [{ "key1" : "val1", "key2" : "val2" }, { "key1" : "val3", "key2" : "val4" }]`,
|
||||
transformed: parsed,
|
||||
message: `${WIDGET_TYPE_VALIDATION_ERROR}: [{ "Col1" : "val1", "Col2" : "val2" }]`,
|
||||
};
|
||||
}
|
||||
return { isValid, parsed };
|
||||
|
|
@ -326,45 +328,6 @@ export const VALIDATORS: Record<ValidationType, Validator> = {
|
|||
}
|
||||
return { isValid, parsed, transformed: parsed };
|
||||
},
|
||||
[VALIDATION_TYPES.SINGLE_CHART_DATA]: (value, props, dataTree) => {
|
||||
const { isValid, parsed } = VALIDATORS[VALIDATION_TYPES.TABLE_DATA](
|
||||
value,
|
||||
props,
|
||||
dataTree,
|
||||
);
|
||||
if (!isValid) {
|
||||
return {
|
||||
isValid: false,
|
||||
parsed: [],
|
||||
message: `${WIDGET_TYPE_VALIDATION_ERROR}: Chart Data`,
|
||||
};
|
||||
}
|
||||
|
||||
const isValidChartData = _.every(
|
||||
parsed,
|
||||
(chartPoint: { x: string; y: any }) => {
|
||||
return (
|
||||
_.isObject(chartPoint) &&
|
||||
_.isString(chartPoint.x) &&
|
||||
!_.isUndefined(chartPoint.y)
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
if (!isValidChartData) {
|
||||
return {
|
||||
isValid: false,
|
||||
parsed: [],
|
||||
message: `${WIDGET_TYPE_VALIDATION_ERROR}: Chart Data`,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
isValid: true,
|
||||
parsed,
|
||||
message: "",
|
||||
};
|
||||
},
|
||||
[VALIDATION_TYPES.MARKERS]: (
|
||||
value: any,
|
||||
props: WidgetProps,
|
||||
|
|
|
|||
|
|
@ -100,6 +100,37 @@ const chartDataMigration = (currentDSL: ContainerWidgetProps<WidgetProps>) => {
|
|||
return currentDSL;
|
||||
};
|
||||
|
||||
const singleChartDataMigration = (
|
||||
currentDSL: ContainerWidgetProps<WidgetProps>,
|
||||
) => {
|
||||
currentDSL.children = currentDSL.children?.map(child => {
|
||||
if (child.type === WidgetTypes.CHART_WIDGET) {
|
||||
// Check if chart widget has the deprecated singleChartData property
|
||||
if (child.hasOwnProperty("singleChartData")) {
|
||||
// This is to make sure that the format of the chartData is accurate
|
||||
if (
|
||||
Array.isArray(child.singleChartData) &&
|
||||
!child.singleChartData[0].hasOwnProperty("seriesName")
|
||||
) {
|
||||
child.singleChartData = {
|
||||
seriesName: "Series 1",
|
||||
data: child.singleChartData || [],
|
||||
};
|
||||
}
|
||||
//TODO: other possibilities?
|
||||
child.chartData = JSON.stringify([...child.singleChartData]);
|
||||
delete child.singleChartData;
|
||||
}
|
||||
}
|
||||
if (child.children && child.children.length > 0) {
|
||||
child = singleChartDataMigration(child);
|
||||
}
|
||||
return child;
|
||||
});
|
||||
|
||||
return currentDSL;
|
||||
};
|
||||
|
||||
const mapDataMigration = (currentDSL: ContainerWidgetProps<WidgetProps>) => {
|
||||
currentDSL.children = currentDSL.children?.map((children: WidgetProps) => {
|
||||
if (children.type === WidgetTypes.MAP_WIDGET) {
|
||||
|
|
@ -199,6 +230,11 @@ const transformDSL = (currentDSL: ContainerWidgetProps<WidgetProps>) => {
|
|||
currentDSL = mapDataMigration(currentDSL);
|
||||
currentDSL.version = 4;
|
||||
}
|
||||
if (currentDSL.version === 4) {
|
||||
currentDSL = singleChartDataMigration(currentDSL);
|
||||
currentDSL.version = 5;
|
||||
}
|
||||
|
||||
return currentDSL;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -74,3 +74,17 @@ export const scrollElementIntoParentCanvasView = (
|
|||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const convertToCamelCase = (value: string, limit?: number) => {
|
||||
const separatorRegex = /\W+/;
|
||||
return value
|
||||
.split(separatorRegex)
|
||||
.map((token, index) => {
|
||||
if (index > 0) {
|
||||
return token.charAt(0).toLocaleUpperCase() + token.slice(1);
|
||||
}
|
||||
return token;
|
||||
})
|
||||
.join("_")
|
||||
.slice(0, limit || 30);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ class FormWidget extends ContainerWidget {
|
|||
getFormData(formWidget: ContainerWidgetProps<WidgetProps>) {
|
||||
const formData: any = {};
|
||||
if (formWidget.children)
|
||||
formWidget.children.map(widgetData => {
|
||||
formWidget.children.forEach(widgetData => {
|
||||
if (widgetData.value) {
|
||||
formData[widgetData.widgetName] = widgetData.value;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import React, { lazy, Suspense } from "react";
|
||||
import React, { Suspense } from "react";
|
||||
import BaseWidget, { WidgetProps, WidgetState } from "./BaseWidget";
|
||||
import { WidgetType } from "constants/WidgetConstants";
|
||||
import { EventType } from "constants/ActionConstants";
|
||||
import { forIn } from "lodash";
|
||||
// import { forIn } from "lodash";
|
||||
import ReactTableComponent from "components/designSystems/appsmith/ReactTableComponent";
|
||||
|
||||
import { VALIDATION_TYPES } from "constants/WidgetValidation";
|
||||
|
|
@ -10,43 +10,44 @@ import {
|
|||
WidgetPropertyValidationType,
|
||||
BASE_WIDGET_VALIDATION,
|
||||
} from "utils/ValidationFactory";
|
||||
import { ColumnModel } from "@syncfusion/ej2-grids";
|
||||
import { ColumnDirTypecast } from "@syncfusion/ej2-react-grids";
|
||||
// import { ColumnModel } from "@syncfusion/ej2-grids";
|
||||
// import { ColumnDirTypecast } from "@syncfusion/ej2-react-grids";
|
||||
import { ColumnAction } from "components/propertyControls/ColumnActionSelectorControl";
|
||||
import { TriggerPropertiesMap } from "utils/WidgetFactory";
|
||||
import Skeleton from "components/utils/Skeleton";
|
||||
import { Classes } from "@blueprintjs/core";
|
||||
|
||||
const TableComponent = lazy(() =>
|
||||
import(
|
||||
/* webpackPrefetch: true, webpackChunkName: "table" */ "components/designSystems/syncfusion/TableComponent"
|
||||
),
|
||||
);
|
||||
// const TableComponent = React.lazy(() =>
|
||||
// import(
|
||||
// /* webpackPrefetch: true, webpackChunkName: "table" */ "components/designSystems/syncfusion/TableComponent"
|
||||
// ),
|
||||
// );
|
||||
|
||||
const ROW_HEIGHT = 37;
|
||||
const TABLE_HEADER_HEIGHT = 39;
|
||||
const TABLE_FOOTER_HEIGHT = 48;
|
||||
const TABLE_EXPORT_HEIGHT = 43;
|
||||
// const ROW_HEIGHT = 37;
|
||||
// const TABLE_HEADER_HEIGHT = 39;
|
||||
// const TABLE_FOOTER_HEIGHT = 48;
|
||||
// const TABLE_EXPORT_HEIGHT = 43;
|
||||
|
||||
function constructColumns(
|
||||
data: object[],
|
||||
hiddenColumns?: string[],
|
||||
): ColumnModel[] | ColumnDirTypecast[] {
|
||||
let cols: ColumnModel[] | ColumnDirTypecast[] = [];
|
||||
const listItemWithAllProperties = {};
|
||||
data.forEach(dataItem => {
|
||||
Object.assign(listItemWithAllProperties, dataItem);
|
||||
});
|
||||
forIn(listItemWithAllProperties, (value: any, key: string) => {
|
||||
cols.push({
|
||||
field: key,
|
||||
visible: !hiddenColumns?.includes(key),
|
||||
});
|
||||
});
|
||||
cols = (cols as any[]).filter(col => col.field !== "_color") as
|
||||
| ColumnModel[]
|
||||
| ColumnDirTypecast[];
|
||||
return cols;
|
||||
}
|
||||
// function constructColumns(
|
||||
// data: object[],
|
||||
// hiddenColumns?: string[],
|
||||
// ): ColumnModel[] | ColumnDirTypecast[] {
|
||||
// let cols: ColumnModel[] | ColumnDirTypecast[] = [];
|
||||
// const listItemWithAllProperties = {};
|
||||
// data.forEach(dataItem => {
|
||||
// Object.assign(listItemWithAllProperties, dataItem);
|
||||
// });
|
||||
// forIn(listItemWithAllProperties, (value: any, key: string) => {
|
||||
// cols.push({
|
||||
// field: key,
|
||||
// visible: !hiddenColumns?.includes(key),
|
||||
// });
|
||||
// });
|
||||
// cols = (cols as any[]).filter(col => col.field !== "_color") as
|
||||
// | ColumnModel[]
|
||||
// | ColumnDirTypecast[];
|
||||
// return cols;
|
||||
// }
|
||||
|
||||
class TableWidget extends BaseWidget<TableWidgetProps, WidgetState> {
|
||||
static getPropertyValidationMap(): WidgetPropertyValidationType {
|
||||
|
|
@ -85,7 +86,7 @@ class TableWidget extends BaseWidget<TableWidgetProps, WidgetState> {
|
|||
|
||||
getPageView() {
|
||||
const { tableData, hiddenColumns } = this.props;
|
||||
const columns = constructColumns(tableData, hiddenColumns);
|
||||
// const columns = constructColumns(tableData, hiddenColumns);
|
||||
|
||||
const serverSidePaginationEnabled = (this.props
|
||||
.serverSidePaginationEnabled &&
|
||||
|
|
@ -98,14 +99,14 @@ class TableWidget extends BaseWidget<TableWidgetProps, WidgetState> {
|
|||
}
|
||||
const { componentWidth, componentHeight } = this.getComponentDimensions();
|
||||
|
||||
const exportHeight =
|
||||
this.props.exportCsv || this.props.exportPDF || this.props.exportCsv
|
||||
? TABLE_EXPORT_HEIGHT
|
||||
: 0;
|
||||
const tableHeaderHeight =
|
||||
this.props.tableData.length === 0 ? 2 : TABLE_HEADER_HEIGHT;
|
||||
const tableContentHeight =
|
||||
componentHeight - TABLE_FOOTER_HEIGHT - tableHeaderHeight - exportHeight;
|
||||
// const exportHeight =
|
||||
// this.props.exportCsv || this.props.exportPDF || this.props.exportCsv
|
||||
// ? TABLE_EXPORT_HEIGHT
|
||||
// : 0;
|
||||
// const tableHeaderHeight =
|
||||
// this.props.tableData.length === 0 ? 2 : TABLE_HEADER_HEIGHT;
|
||||
// const tableContentHeight =
|
||||
// componentHeight - TABLE_FOOTER_HEIGHT - tableHeaderHeight - exportHeight;
|
||||
// Use below code to calculate page size for old table component
|
||||
// const pageSize = Math.floor(tableContentHeight / ROW_HEIGHT);
|
||||
const pageSize = Math.floor((componentHeight - 104) / 52);
|
||||
|
|
@ -113,59 +114,60 @@ class TableWidget extends BaseWidget<TableWidgetProps, WidgetState> {
|
|||
if (pageSize !== this.props.pageSize) {
|
||||
super.updateWidgetMetaProperty("pageSize", pageSize);
|
||||
}
|
||||
|
||||
// /*
|
||||
return (
|
||||
<Suspense fallback={<Skeleton />}>
|
||||
<ReactTableComponent
|
||||
height={componentHeight}
|
||||
width={componentWidth}
|
||||
tableData={tableData}
|
||||
widgetId={this.props.widgetId}
|
||||
renderMode={this.props.renderMode}
|
||||
hiddenColumns={hiddenColumns}
|
||||
columnActions={this.props.columnActions}
|
||||
columnNameMap={this.props.columnNameMap}
|
||||
columnTypeMap={this.props.columnTypeMap}
|
||||
columnOrder={this.props.columnOrder}
|
||||
pageSize={pageSize}
|
||||
onCommandClick={this.onCommandClick}
|
||||
selectedRowIndex={
|
||||
this.props.selectedRowIndex === undefined
|
||||
? -1
|
||||
: this.props.selectedRowIndex
|
||||
}
|
||||
serverSidePaginationEnabled={serverSidePaginationEnabled}
|
||||
onRowClick={this.handleRowClick}
|
||||
pageNo={pageNo}
|
||||
nextPageClick={this.handleNextPageClick}
|
||||
prevPageClick={this.handlePrevPageClick}
|
||||
updatePageNo={(pageNo: number) => {
|
||||
super.updateWidgetMetaProperty("pageNo", pageNo);
|
||||
}}
|
||||
updateHiddenColumns={(hiddenColumns?: string[]) => {
|
||||
super.updateWidgetProperty("hiddenColumns", hiddenColumns);
|
||||
}}
|
||||
updateColumnType={(columnTypeMap: {
|
||||
[key: string]: { type: string; format: string };
|
||||
}) => {
|
||||
super.updateWidgetProperty("columnTypeMap", columnTypeMap);
|
||||
}}
|
||||
updateColumnName={(columnNameMap: { [key: string]: string }) => {
|
||||
super.updateWidgetProperty("columnNameMap", columnNameMap);
|
||||
}}
|
||||
handleResizeColumn={(columnSizeMap: { [key: string]: number }) => {
|
||||
super.updateWidgetProperty("columnSizeMap", columnSizeMap);
|
||||
}}
|
||||
handleReorderColumn={(columnOrder: string[]) => {
|
||||
super.updateWidgetProperty("columnOrder", columnOrder);
|
||||
}}
|
||||
columnSizeMap={this.props.columnSizeMap}
|
||||
resetSelectedRowIndex={this.resetSelectedRowIndex}
|
||||
disableDrag={(disable: boolean) => {
|
||||
this.disableDrag(disable);
|
||||
}}
|
||||
/>
|
||||
<div className={this.props.isLoading ? Classes.SKELETON : ""}>
|
||||
<ReactTableComponent
|
||||
height={componentHeight}
|
||||
width={componentWidth}
|
||||
tableData={tableData}
|
||||
widgetId={this.props.widgetId}
|
||||
renderMode={this.props.renderMode}
|
||||
hiddenColumns={hiddenColumns}
|
||||
columnActions={this.props.columnActions}
|
||||
columnNameMap={this.props.columnNameMap}
|
||||
columnTypeMap={this.props.columnTypeMap}
|
||||
columnOrder={this.props.columnOrder}
|
||||
pageSize={pageSize}
|
||||
onCommandClick={this.onCommandClick}
|
||||
selectedRowIndex={
|
||||
this.props.selectedRowIndex === undefined
|
||||
? -1
|
||||
: this.props.selectedRowIndex
|
||||
}
|
||||
serverSidePaginationEnabled={serverSidePaginationEnabled}
|
||||
onRowClick={this.handleRowClick}
|
||||
pageNo={pageNo}
|
||||
nextPageClick={this.handleNextPageClick}
|
||||
prevPageClick={this.handlePrevPageClick}
|
||||
updatePageNo={(pageNo: number) => {
|
||||
super.updateWidgetMetaProperty("pageNo", pageNo);
|
||||
}}
|
||||
updateHiddenColumns={(hiddenColumns?: string[]) => {
|
||||
super.updateWidgetProperty("hiddenColumns", hiddenColumns);
|
||||
}}
|
||||
updateColumnType={(columnTypeMap: {
|
||||
[key: string]: { type: string; format: string };
|
||||
}) => {
|
||||
super.updateWidgetProperty("columnTypeMap", columnTypeMap);
|
||||
}}
|
||||
updateColumnName={(columnNameMap: { [key: string]: string }) => {
|
||||
super.updateWidgetProperty("columnNameMap", columnNameMap);
|
||||
}}
|
||||
handleResizeColumn={(columnSizeMap: { [key: string]: number }) => {
|
||||
super.updateWidgetProperty("columnSizeMap", columnSizeMap);
|
||||
}}
|
||||
handleReorderColumn={(columnOrder: string[]) => {
|
||||
super.updateWidgetProperty("columnOrder", columnOrder);
|
||||
}}
|
||||
columnSizeMap={this.props.columnSizeMap}
|
||||
resetSelectedRowIndex={this.resetSelectedRowIndex}
|
||||
disableDrag={(disable: boolean) => {
|
||||
this.disableDrag(disable);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</Suspense>
|
||||
);
|
||||
// */
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user