From 188af0df78b86927320a9ee483bfe87e6a7c230c Mon Sep 17 00:00:00 2001 From: Ashit Rath Date: Fri, 30 Aug 2024 16:44:55 +0530 Subject: [PATCH 01/22] perf: JSONForm infinite re-rendering when field validation is set (#35994) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description The setError function updates the state and the effect is also dependant on the state which triggers re-render. This is a classic case of re-rendering due to self state dependency and is fixed with a check if the error is present for a particular field then it doesn't need to set again Fixes https://github.com/appsmithorg/appsmith/issues/35995 ## Automation /ok-to-test tags="@tag.JSONForm" ### :mag: Cypress test results > [!TIP] > 🟒 🟒 🟒 All cypress tests have passed! πŸŽ‰ πŸŽ‰ πŸŽ‰ > Workflow run: > Commit: 1d5dec675abd788931aab462832455fbce250df3 > Cypress dashboard. > Tags: `@tag.JSONForm` > Spec: >
Fri, 30 Aug 2024 06:50:40 UTC ## Communication Should the DevRel and Marketing teams inform users about this change? - [ ] Yes - [ ] No ## Summary by CodeRabbit - **New Features** - Enhanced error handling logic in the form validation process to improve efficiency and correctness. - **Tests** - Added a new test case to validate the behavior of the form validation hook when encountering invalid field states. --- .../fields/useRegisterFieldValidity.test.tsx | 50 +++++++++++++++++++ .../fields/useRegisterFieldValidity.ts | 12 +++-- 2 files changed, 57 insertions(+), 5 deletions(-) diff --git a/app/client/src/widgets/JSONFormWidget/fields/useRegisterFieldValidity.test.tsx b/app/client/src/widgets/JSONFormWidget/fields/useRegisterFieldValidity.test.tsx index fe4e132855e9..29e26a100b3d 100644 --- a/app/client/src/widgets/JSONFormWidget/fields/useRegisterFieldValidity.test.tsx +++ b/app/client/src/widgets/JSONFormWidget/fields/useRegisterFieldValidity.test.tsx @@ -193,6 +193,56 @@ describe("useRegisterFieldInvalid - setMetaInternalFieldState", () => { expect(mockSetError).not.toBeCalled(); }); + it("calls setError when isValid is false and error is not present", () => { + const mocksetMetaInternalFieldState = jest.fn(); + const mockClearErrors = jest.fn(); + const mockSetError = jest.fn(); + + function Wrapper({ children }: { children: React.ReactNode }) { + const methods = useForm(); + + return ( + + + {children} + + + ); + } + + const fieldName = "testField"; + + act(() => { + renderHook( + () => + useRegisterFieldValidity({ + isValid: false, + fieldName, + fieldType: FieldType.TEXT_INPUT, + }), + { + wrapper: Wrapper, + }, + ); + }); + + jest.runAllTimers(); + + expect(mockSetError).toBeCalledTimes(1); + expect(mockClearErrors).not.toBeCalledWith(fieldName); + }); + it("updates fieldState and error state with the updated isValid value", () => { const mocksetMetaInternalFieldState = jest.fn(); // TODO: Fix this the next time the file is edited diff --git a/app/client/src/widgets/JSONFormWidget/fields/useRegisterFieldValidity.ts b/app/client/src/widgets/JSONFormWidget/fields/useRegisterFieldValidity.ts index 58c2811ebd0c..de3bb915af83 100644 --- a/app/client/src/widgets/JSONFormWidget/fields/useRegisterFieldValidity.ts +++ b/app/client/src/widgets/JSONFormWidget/fields/useRegisterFieldValidity.ts @@ -42,12 +42,14 @@ function useRegisterFieldValidity({ }); } } else { - startAndEndSpanForFn("JSONFormWidget.setError", {}, () => { - setError(fieldName, { - type: fieldType, - message: "Invalid field", + if (!error) { + startAndEndSpanForFn("JSONFormWidget.setError", {}, () => { + setError(fieldName, { + type: fieldType, + message: "Invalid field", + }); }); - }); + } } } catch (e) { Sentry.captureException(e); From 863c36ce7cd58dea25bbae71238e5980f6ead3df Mon Sep 17 00:00:00 2001 From: Aman Agarwal Date: Wed, 28 Aug 2024 17:47:44 +0530 Subject: [PATCH 02/22] fix: API multipart spec flakiness (#35927) --- .../ServerSide/ApiTests/API_MultiPart_Spec.ts | 47 +++---------------- .../cypress/support/Objects/DataManager.ts | 4 ++ app/client/cypress/support/Pages/ApiPage.ts | 2 +- 3 files changed, 12 insertions(+), 41 deletions(-) diff --git a/app/client/cypress/e2e/Regression/ServerSide/ApiTests/API_MultiPart_Spec.ts b/app/client/cypress/e2e/Regression/ServerSide/ApiTests/API_MultiPart_Spec.ts index ec7e2ab5801e..e2007f6b0c95 100644 --- a/app/client/cypress/e2e/Regression/ServerSide/ApiTests/API_MultiPart_Spec.ts +++ b/app/client/cypress/e2e/Regression/ServerSide/ApiTests/API_MultiPart_Spec.ts @@ -2,6 +2,7 @@ import { agHelper, apiPage, assertHelper, + dataManager, deployMode, entityItems, jsEditor, @@ -128,8 +129,8 @@ describe( agHelper.AddDsl("multiPartFormDataDsl"); apiPage.CreateAndFillApi( - "https://api.cloudinary.com/v1_1/appsmithautomationcloud/image/upload?upload_preset=fbbhg4xu", - "CloudinaryUploadApi", + dataManager.dsValues[dataManager.defaultEnviorment].multipartAPI, + "MultipartAPI", 30000, "POST", ); @@ -145,7 +146,7 @@ describe( myVar1: [], myVar2: {}, upload: async () => { - await CloudinaryUploadApi.run().then(()=> showAlert('Image uploaded to Cloudinary successfully', 'success')).catch(err => showAlert(err.message, 'error')); + await MultipartAPI.run().then(()=> showAlert('Image uploaded to multipart successfully', 'success')).catch(err => showAlert(err.message, 'error')); await resetWidget('FilePicker1', true); } }`, @@ -161,15 +162,9 @@ describe( propPane.EnterJSContext("onFilesSelected", `{{JSObject1.upload()}}`); EditorNavigation.SelectEntityByName("Image1", EntityType.Widget); - propPane.UpdatePropertyFieldValue( - "Image", - "{{CloudinaryUploadApi.data.url}}", - ); + propPane.UpdatePropertyFieldValue("Image", "{{MultipartAPI.data.url}}"); - EditorNavigation.SelectEntityByName( - "CloudinaryUploadApi", - EntityType.Api, - ); + EditorNavigation.SelectEntityByName("MultipartAPI", EntityType.Api); apiPage.ToggleOnPageLoadRun(false); //Bug 12476 EditorNavigation.SelectEntityByName("Page1", EntityType.Page); @@ -177,9 +172,7 @@ describe( agHelper.ClickButton("Select Files"); agHelper.UploadFile(imageNameToUpload); assertHelper.AssertNetworkExecutionSuccess("@postExecute"); //validating Cloudinary api call - agHelper.ValidateToastMessage( - "Image uploaded to Cloudinary successfully", - ); + agHelper.ValidateToastMessage("Image uploaded to multipart successfully"); agHelper.Sleep(); cy.xpath(apiPage._imageSrc) .find("img") @@ -192,31 +185,5 @@ describe( agHelper.AssertElementVisibility(locators._buttonByText("Select Files")); //verifying if reset! deployMode.NavigateBacktoEditor(); }); - - it("8. Checks MultiPart form data for a Array Type upload results in API error", () => { - const imageNameToUpload = "AAAFlowerVase.jpeg"; - EditorNavigation.SelectEntityByName( - "CloudinaryUploadApi", - EntityType.Api, - ); - apiPage.EnterBodyFormData( - "MULTIPART_FORM_DATA", - "file", - "{{FilePicker1.files[0]}}", - "Array", - true, - ); - EditorNavigation.SelectEntityByName("FilePicker1", EntityType.Widget); - agHelper.ClickButton("Select Files"); - agHelper.UploadFile(imageNameToUpload); - assertHelper.AssertNetworkExecutionSuccess("@postExecute", false); - - deployMode.DeployApp(locators._buttonByText("Select Files")); - agHelper.ClickButton("Select Files"); - agHelper.UploadFile(imageNameToUpload); - assertHelper.AssertNetworkExecutionSuccess("@postExecute", false); - agHelper.ValidateToastMessage("CloudinaryUploadApi failed to execute"); - agHelper.AssertElementVisibility(locators._buttonByText("Select Files")); //verifying if reset in case of failure! - }); }, ); diff --git a/app/client/cypress/support/Objects/DataManager.ts b/app/client/cypress/support/Objects/DataManager.ts index 515b3f050327..a54e1162eb30 100644 --- a/app/client/cypress/support/Objects/DataManager.ts +++ b/app/client/cypress/support/Objects/DataManager.ts @@ -80,6 +80,8 @@ export class DataManager { "http://host.docker.internal:5001/v1/mock-api-object?records=10", echoApiUrl: "http://host.docker.internal:5001/v1/mock-api/echo", randomCatfactUrl: "http://host.docker.internal:5001/v1/catfact/random", + multipartAPI: + "http://host.docker.internal:5001/v1/mock-api/echo-multipart", randomTrumpApi: "http://host.docker.internal:5001/v1/whatdoestrumpthink/random", mockHttpCodeUrl: "http://host.docker.internal:5001/v1/mock-http-codes/", @@ -179,6 +181,8 @@ export class DataManager { mockApiUrl: "http://host.docker.internal:5001/v1/mock-api?records=10", echoApiUrl: "http://host.docker.internal:5001/v1/mock-api/echo", randomCatfactUrl: "http://host.docker.internal:5001/v1/catfact/random", + multipartAPI: + "http://host.docker.internal:5001/v1/mock-api/echo-multipart", mockHttpCodeUrl: "http://host.docker.internal:5001/v1/mock-http-codes/", AirtableBaseForME: "appubHrVbovcudwN6", AirtableTableForME: "tblsFCQSskVFf7xNd", diff --git a/app/client/cypress/support/Pages/ApiPage.ts b/app/client/cypress/support/Pages/ApiPage.ts index 793a6d03c102..8804ae793dde 100644 --- a/app/client/cypress/support/Pages/ApiPage.ts +++ b/app/client/cypress/support/Pages/ApiPage.ts @@ -303,7 +303,7 @@ export class ApiPage { | "RAW", ) { this.agHelper.GetNClick(this._bodyTypeSelect); - cy.xpath(this._bodyTypeToSelect(subTabName)).should("be.visible").click(); + this.agHelper.GetNClick(this._bodyTypeToSelect(subTabName)); } AssertRightPaneSelectedTab(tabName: RightPaneTabs) { From 1968ec70a31a926171519b2aa53e4bb6bbbbcad5 Mon Sep 17 00:00:00 2001 From: Aman Agarwal Date: Wed, 28 Aug 2024 19:16:12 +0530 Subject: [PATCH 03/22] fix: mysql2 spec flakiness (#35950) --- .../ServerSide/GenerateCRUD/MySQL2_Spec.ts | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/app/client/cypress/e2e/Regression/ServerSide/GenerateCRUD/MySQL2_Spec.ts b/app/client/cypress/e2e/Regression/ServerSide/GenerateCRUD/MySQL2_Spec.ts index aee98caa858b..3271e32094da 100644 --- a/app/client/cypress/e2e/Regression/ServerSide/GenerateCRUD/MySQL2_Spec.ts +++ b/app/client/cypress/e2e/Regression/ServerSide/GenerateCRUD/MySQL2_Spec.ts @@ -82,10 +82,11 @@ describe( dataSources.RunQueryNVerifyResponseViews(10); dataSources.AssertQueryTableResponse(5, "2112"); dataSources.AssertQueryTableResponse(6, "Mike's Liquors"); - agHelper.ActionContextMenuWithInPane({ - action: "Delete", - entityType: entityItems.Query, - }); + // Commenting this deletion of query to make the generate crud work on the new page instead of the current page + // agHelper.ActionContextMenuWithInPane({ + // action: "Delete", + // entityType: entityItems.Query, + // }); }); it("3. Verify Generate CRUD for the new table & Verify Deploy mode for table - Stores", () => { @@ -129,13 +130,13 @@ describe( updateNVerify(6, 4, newStoreSecret as string); }); - table.SelectTableRow(17, 0, true, "v2"); - dataSources.AssertJSONFormHeader(17, 0, "store_id"); - generateStoresSecretInfo(17); + table.SelectTableRow(12, 0, true, "v2"); + dataSources.AssertJSONFormHeader(12, 0, "store_id"); + generateStoresSecretInfo(12); cy.get("@secretInfo").then(($secretInfo) => { newStoreSecret = $secretInfo; cy.log("newStoreSecret is : " + newStoreSecret); - updateNVerify(17, 4, newStoreSecret as string); + updateNVerify(12, 4, newStoreSecret as string); }); //Hidden field bug - to add here aft secret codes are updated for some fields! From b21124679a1d5eb444944ec90d49ea77861a9da6 Mon Sep 17 00:00:00 2001 From: Rahul Barwal Date: Thu, 29 Aug 2024 10:08:45 +0530 Subject: [PATCH 04/22] test: fix flaky binary spec (#35861) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description EE PR: https://github.com/appsmithorg/appsmith-ee/pull/4954 This spec relied on retries and was asserting on wrong table cols Fixes #35877 _or_ Fixes `Issue URL` > [!WARNING] > _If no issue exists, please create an issue first, and check with the maintainers if the issue is valid._ ## Automation /ok-to-test tags="@tag.Sanity" ### :mag: Cypress test results > [!TIP] > 🟒 🟒 🟒 All cypress tests have passed! πŸŽ‰ πŸŽ‰ πŸŽ‰ > Workflow run: > Commit: 93d0502c49b6e6b714236b8ea693f5ade0eacdb5 > Cypress dashboard. > Tags: `@tag.Sanity` > Spec: >
Wed, 28 Aug 2024 10:48:41 UTC ## Communication Should the DevRel and Marketing teams inform users about this change? - [ ] Yes - [x] No ## Summary by CodeRabbit - **Bug Fixes** - Removed a previously skipped test for inserting binary type records to ensure accurate functionality checks. - **Refactor** - Improved readability and maintainability of test cases by replacing hardcoded row indices with dynamic variables. - Cleaned up the test suite by removing commented-out code and adjusting sleep durations. - **Documentation** - Updated assertions to reflect changes in expected values and the sequence of operations in the tests. --- .../Postgres_DataTypes/Binary_Spec.ts | 98 ++++++------------- 1 file changed, 28 insertions(+), 70 deletions(-) diff --git a/app/client/cypress/e2e/Regression/ServerSide/Postgres_DataTypes/Binary_Spec.ts b/app/client/cypress/e2e/Regression/ServerSide/Postgres_DataTypes/Binary_Spec.ts index bd1f3d80f405..bb8ad38cb77b 100644 --- a/app/client/cypress/e2e/Regression/ServerSide/Postgres_DataTypes/Binary_Spec.ts +++ b/app/client/cypress/e2e/Regression/ServerSide/Postgres_DataTypes/Binary_Spec.ts @@ -8,7 +8,6 @@ import { locators, table, } from "../../../../support/Objects/ObjectsCore"; -import { featureFlagIntercept } from "../../../../support/Objects/FeatureFlags"; import EditorNavigation, { AppSidebar, AppSidebarButton, @@ -76,38 +75,7 @@ describe("Binary Datatype tests", { tags: ["@tag.Datasource"] }, function () { table.WaitForTableEmpty(); //asserting table is empty before inserting! }); - //Timing out a lot in CI, hence skipped, Insert verified also in next case - // it.skip("3. Inserting record - binarytype", () => { - // imageNameToUpload = "Datatypes/Bridge.jpg"; - // // entityExplorer.SelectEntityByName("Page1"); - // // deployMode.DeployApp(); - // // table.WaitForTableEmpty(); //asserting table is empty before inserting! - // agHelper.ClickButton("Run InsertQuery"); - // agHelper.AssertElementVisibility(locators._modal); - - // agHelper.ClickButton("Select New Image"); - // agHelper.UploadFile(imageNameToUpload); - - // agHelper.ClickButton("Insert"); - // agHelper.AssertElementAbsence(locators._toastMsg); //Assert that Insert did not fail - // agHelper.AssertElementVisibility(locators._buttonByText("Run InsertQuery")); - // agHelper.AssertElementAbsence(locators._btnSpinner, 10000); //for the update row to appear at last - // table.WaitUntilTableLoad(); - // agHelper.Sleep(3000); //some more time for all rows with images to be populated - // table.ReadTableRowColumnData(0, 0).then(($cellData) => { - // expect($cellData).to.eq("1"); //asserting serial column is inserting fine in sequence - // }); - // table.ReadTableRowColumnData(0, 1, "v1", 200).then(($cellData) => { - // expect($cellData).to.eq("Bridge.jpg"); - // }); - // table.AssertTableRowImageColumnIsLoaded(0, 2).then(($oldimage) => { - // table.AssertTableRowImageColumnIsLoaded(0, 3).then(($newimage) => { - // expect($oldimage).to.eq($newimage); - // }); - // }); - // }); - - it("4. Inserting another record - binarytype", () => { + it("3. Inserting another record - binarytype", () => { imageNameToUpload = "Datatypes/Georgia.jpeg"; agHelper.ClickButton("Run InsertQuery"); @@ -121,21 +89,21 @@ describe("Binary Datatype tests", { tags: ["@tag.Datasource"] }, function () { agHelper.AssertElementVisibility(locators._buttonByText("Run InsertQuery")); agHelper.AssertElementAbsence(locators._btnSpinner, 20000); //for the update row to appear at last table.WaitUntilTableLoad(); - agHelper.Sleep(2000); //some more time for all rows with images to be populated - table.ReadTableRowColumnData(1, 0).then(($cellData) => { - expect($cellData).to.eq("2"); //asserting serial column is inserting fine in sequence + const rowIndex = 0; + table.ReadTableRowColumnData(rowIndex, 0).then(($cellData) => { + expect($cellData).to.eq("1"); //asserting serial column is inserting fine in sequence }); - table.ReadTableRowColumnData(1, 1, "v1", 200).then(($cellData) => { + table.ReadTableRowColumnData(rowIndex, 1, "v1", 200).then(($cellData) => { expect($cellData).to.eq("Georgia.jpeg"); }); - table.AssertTableRowImageColumnIsLoaded(1, 2).then(($oldimage) => { - table.AssertTableRowImageColumnIsLoaded(1, 3).then(($newimage) => { + table.AssertTableRowImageColumnIsLoaded(rowIndex, 2).then(($oldimage) => { + table.AssertTableRowImageColumnIsLoaded(rowIndex, 3).then(($newimage) => { expect($oldimage).to.eq($newimage); }); }); }); - it("5. Inserting another record - binarytype", () => { + it("4. Inserting another record - binarytype", () => { imageNameToUpload = "Datatypes/Maine.jpeg"; agHelper.ClickButton("Run InsertQuery"); @@ -149,21 +117,21 @@ describe("Binary Datatype tests", { tags: ["@tag.Datasource"] }, function () { agHelper.AssertElementVisibility(locators._buttonByText("Run InsertQuery")); agHelper.AssertElementAbsence(locators._btnSpinner, 20000); //for the update row to appear at last table.WaitUntilTableLoad(); - agHelper.Sleep(2000); //some more time for all rows with images to be populated - table.ReadTableRowColumnData(2, 0).then(($cellData) => { - expect($cellData).to.eq("3"); //asserting serial column is inserting fine in sequence + const rowIndex = 1; + table.ReadTableRowColumnData(rowIndex, 0).then(($cellData) => { + expect($cellData).to.eq("2"); //asserting serial column is inserting fine in sequence }); - table.ReadTableRowColumnData(2, 1, "v1", 200).then(($cellData) => { + table.ReadTableRowColumnData(rowIndex, 1, "v1", 200).then(($cellData) => { expect($cellData).to.eq("Maine.jpeg"); }); - table.AssertTableRowImageColumnIsLoaded(2, 2).then(($oldimage) => { - table.AssertTableRowImageColumnIsLoaded(2, 3).then(($newimage) => { + table.AssertTableRowImageColumnIsLoaded(rowIndex, 2).then(($oldimage) => { + table.AssertTableRowImageColumnIsLoaded(rowIndex, 3).then(($newimage) => { expect($oldimage).to.eq($newimage); }); }); }); - it("6. Updating record - binarytype", () => { + it("5. Updating record - binarytype", () => { imageNameToUpload = "Datatypes/NewJersey.jpeg"; table.SelectTableRow(1); @@ -178,45 +146,38 @@ describe("Binary Datatype tests", { tags: ["@tag.Datasource"] }, function () { agHelper.AssertElementVisibility(locators._buttonByText("Run UpdateQuery")); agHelper.AssertElementAbsence(locators._btnSpinner, 20000); //for the update row to appear at last table.WaitUntilTableLoad(); - agHelper.Sleep(14000); //some more time for rows to rearrange! - table.ReadTableRowColumnData(2, 0, "v1", 2000).then(($cellData) => { + const rowIndex = 1; + table.ReadTableRowColumnData(rowIndex, 0, "v1", 2000).then(($cellData) => { expect($cellData).to.eq("2"); //asserting serial column is inserting fine in sequence }); - table.ReadTableRowColumnData(2, 1, "v1", 200).then(($cellData) => { + table.ReadTableRowColumnData(rowIndex, 1, "v1", 200).then(($cellData) => { expect($cellData).to.eq("NewJersey.jpeg"); }); - table.AssertTableRowImageColumnIsLoaded(2, 2).then(($oldimage) => { - table.AssertTableRowImageColumnIsLoaded(2, 3).then(($newimage) => { + table.AssertTableRowImageColumnIsLoaded(rowIndex, 2).then(($oldimage) => { + table.AssertTableRowImageColumnIsLoaded(rowIndex, 3).then(($newimage) => { expect($oldimage).to.not.eq($newimage); }); }); }); - it("7. Deleting records - binarytype", () => { - //entityExplorer.SelectEntityByName("Page1");//commenting 2 lines since case 6th is skipped! - //deployMode.DeployApp(); + it("6. Deleting records - binarytype", () => { table.WaitUntilTableLoad(); table.SelectTableRow(1); agHelper.ClickButton("DeleteQuery", 1); assertHelper.AssertNetworkStatus("@postExecute", 200); assertHelper.AssertNetworkStatus("@postExecute", 200); - agHelper.AssertElementAbsence(locators._btnSpinner, 20000); //Allowing time for delete to be success - agHelper.Sleep(6000); //Allwowing time for delete to be success - table.ReadTableRowColumnData(1, 0).then(($cellData) => { - expect($cellData).not.to.eq("3"); //asserting 2nd record is deleted - }); - table.ReadTableRowColumnData(1, 0, "v1", 200).then(($cellData) => { - expect($cellData).to.eq("2"); + agHelper.WaitUntilEleDisappear(locators._btnSpinner); //Allowing time for delete to be success + table.ReadTableRowColumnData(0, 0).then(($cellData) => { + expect($cellData).to.eq("1"); }); //Deleting all records from .table agHelper.GetNClick(locators._deleteIcon); agHelper.AssertElementVisibility(locators._buttonByText("Run InsertQuery")); - agHelper.Sleep(2000); table.WaitForTableEmpty(); }); - it("8. Inserting another record (to check serial column) - binarytype", () => { + it("7. Inserting another record (to check serial column) - binarytype", () => { imageNameToUpload = "Datatypes/Massachusetts.jpeg"; agHelper.ClickButton("Run InsertQuery"); @@ -230,9 +191,8 @@ describe("Binary Datatype tests", { tags: ["@tag.Datasource"] }, function () { agHelper.AssertElementAbsence(locators._toastMsg); //Assert that Insert did not fail agHelper.AssertElementVisibility(locators._buttonByText("Run InsertQuery")); table.WaitUntilTableLoad(); - agHelper.Sleep(2000); //for all rows with images to be populated table.ReadTableRowColumnData(0, 0, "v1", 2000).then(($cellData) => { - expect($cellData).to.eq("4"); //asserting serial column is inserting fine in sequence + expect($cellData).to.eq("3"); //asserting serial column is inserting fine in sequence }); table.ReadTableRowColumnData(0, 1, "v1", 200).then(($cellData) => { expect($cellData).to.eq("Massachusetts.jpeg"); @@ -244,7 +204,7 @@ describe("Binary Datatype tests", { tags: ["@tag.Datasource"] }, function () { }); }); - it("9. Validating Binary (bytea) - escape, hex, base64 functions", () => { + it("8. Validating Binary (bytea) - escape, hex, base64 functions", () => { deployMode.NavigateBacktoEditor(); table.WaitUntilTableLoad(); PageLeftPane.switchSegment(PagePaneSegment.Queries); @@ -291,7 +251,7 @@ describe("Binary Datatype tests", { tags: ["@tag.Datasource"] }, function () { }); }); - it("10. Validating Binary (bytea) - escape, hex, base64 functions, conts", () => { + it("9. Validating Binary (bytea) - escape, hex, base64 functions, conts", () => { //Validating backslash query = `select encode('\\\\'::bytea, 'escape') as "backslash Escape1", encode('\\134'::bytea, 'escape') as "backslash Escape2", encode('\\\\'::bytea, 'hex') as "backslash Hex1", encode('\\134'::bytea, 'hex') as "backslash Hex2", encode('\\\\'::bytea, 'base64') as "backslash Base64";`; dataSources.EnterQuery(query); @@ -375,8 +335,6 @@ describe("Binary Datatype tests", { tags: ["@tag.Datasource"] }, function () { }); AppSidebar.navigate(AppSidebarButton.Editor); }); - - //Since query delete & Postgress DS delete is covered in other specs, commenting below code // after( // "Validate Drop of the Newly Created - binarytype - Table & Verify Deletion of all created queries", // () => { From ffdcaedcf13094c2df959063f5e38b602f189c98 Mon Sep 17 00:00:00 2001 From: NandanAnantharamu <67676905+NandanAnantharamu@users.noreply.github.com> Date: Thu, 29 Aug 2024 22:55:33 +0530 Subject: [PATCH 05/22] test: updated tests for checkboxgroup (#35945) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RCA: Test was failing after removing retry, the issue was it was clicking on a checkbox which was not required. the retry actually was bringing back the system to right state by clicking again. Solution: We removed the step that was unnecessary in this case which resolved the issue EE: https://github.com/appsmithorg/appsmith-ee/pull/4992 /ok-to-test tags="@tag.Sanity" > [!TIP] > 🟒 🟒 🟒 All cypress tests have passed! πŸŽ‰ πŸŽ‰ πŸŽ‰ > Workflow run: > Commit: e599c6d0149814c38049aaba7828465361d8f43b > Cypress dashboard. > Tags: `@tag.Sanity` > Spec: >
Thu, 29 Aug 2024 14:33:59 UTC --------- Co-authored-by: karthik --- .../ClientSide/Widgets/Checkbox/CheckboxGroup2_spec.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Checkbox/CheckboxGroup2_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Checkbox/CheckboxGroup2_spec.js index cbdab81e2ce3..10c00970efb8 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Checkbox/CheckboxGroup2_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Checkbox/CheckboxGroup2_spec.js @@ -77,8 +77,6 @@ describe( it("3. handleSelectAllChange: unchecked", function () { const selectAllSelector = formWidgetsPage.selectAllCheckboxControl; const uncheckedOptionInputs = `${formWidgetsPage.checkboxGroupOptionInputs} input:not(:checked)`; - // Deselect all - cy.get(selectAllSelector).click(); // Should get 2 unchecked option inputs cy.get(uncheckedOptionInputs).should("have.length", 2); //handleSelectAllChange: checked", function () { From 4a8fb690ed080ab56d6fcd4dba68a7d6efbc8464 Mon Sep 17 00:00:00 2001 From: Nidhi Date: Wed, 4 Sep 2024 09:59:19 +0530 Subject: [PATCH 06/22] chore: Enable netty metrics (#36104) --- .../configurations/ReactorNettyConfiguration.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/ReactorNettyConfiguration.java diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/ReactorNettyConfiguration.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/ReactorNettyConfiguration.java new file mode 100644 index 000000000000..430ea5c3992f --- /dev/null +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/ReactorNettyConfiguration.java @@ -0,0 +1,15 @@ +package com.appsmith.server.configurations; + +import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory; +import org.springframework.boot.web.server.WebServerFactoryCustomizer; +import org.springframework.stereotype.Component; + +import java.util.function.Function; + +@Component +public class ReactorNettyConfiguration implements WebServerFactoryCustomizer { + @Override + public void customize(NettyReactiveWebServerFactory factory) { + factory.addServerCustomizers(httpServer -> httpServer.metrics(true, Function.identity())); + } +} From f68f325a536f4eaf5ae0a2e6d9eb9425cc8d58a2 Mon Sep 17 00:00:00 2001 From: Nidhi Date: Wed, 4 Sep 2024 12:28:47 +0530 Subject: [PATCH 07/22] chore: Enable netty metrics based on env var (#36108) --- .../com/appsmith/server/configurations/CommonConfig.java | 3 +++ .../server/configurations/ReactorNettyConfiguration.java | 9 ++++++++- .../src/main/resources/application.properties | 1 + 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/CommonConfig.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/CommonConfig.java index aedf383937d4..9109397ee3da 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/CommonConfig.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/CommonConfig.java @@ -67,6 +67,9 @@ public class CommonConfig { @Value("${appsmith.micrometer.tracing.detail.enabled:false}") private boolean tracingDetail; + @Value("${appsmith.micrometer.metrics.detail.enabled:false}") + private boolean metricsDetail; + private List allowedDomains; private String mongoDBVersion; diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/ReactorNettyConfiguration.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/ReactorNettyConfiguration.java index 430ea5c3992f..1a55dd8a08af 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/ReactorNettyConfiguration.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/ReactorNettyConfiguration.java @@ -1,15 +1,22 @@ package com.appsmith.server.configurations; +import lombok.RequiredArgsConstructor; import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory; import org.springframework.boot.web.server.WebServerFactoryCustomizer; import org.springframework.stereotype.Component; import java.util.function.Function; +@RequiredArgsConstructor @Component public class ReactorNettyConfiguration implements WebServerFactoryCustomizer { + + private final CommonConfig commonConfig; + @Override public void customize(NettyReactiveWebServerFactory factory) { - factory.addServerCustomizers(httpServer -> httpServer.metrics(true, Function.identity())); + if (commonConfig.isMetricsDetail()) { + factory.addServerCustomizers(httpServer -> httpServer.metrics(true, Function.identity())); + } } } diff --git a/app/server/appsmith-server/src/main/resources/application.properties b/app/server/appsmith-server/src/main/resources/application.properties index d524ae9e32ff..ea425501e9f4 100644 --- a/app/server/appsmith-server/src/main/resources/application.properties +++ b/app/server/appsmith-server/src/main/resources/application.properties @@ -123,6 +123,7 @@ appsmith.newrelic.micrometer.metrics.application.name=${APPSMITH_NEWRELIC_MICROM spring.application.name=${OTEL_SERVICE_NAME:appsmith-anonymous} appsmith.micrometer.metrics.enabled=${APPSMITH_MICROMETER_METRICS_ENABLED:false} appsmith.micrometer.tracing.detail.enabled=${APPSMITH_ENABLE_TRACING_DETAIL:false} +appsmith.micrometer.metrics.detail.enabled=${APPSMITH_ENABLE_METRICS_DETAIL:false} springdoc.api-docs.path=/v3/docs springdoc.swagger-ui.path=/v3/swagger From e7730394678cdd3ce065178467df9d65be1a3961 Mon Sep 17 00:00:00 2001 From: Manish Kumar <107841575+sondermanish@users.noreply.github.com> Date: Wed, 4 Sep 2024 13:45:01 +0530 Subject: [PATCH 08/22] fix: Embedded datasource persistence changes for git. (#36109) --- .../java/com/appsmith/external/models/Datasource.java | 2 +- .../external/models/DatasourceConfiguration.java | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/models/Datasource.java b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/models/Datasource.java index e2b41d1c8076..e067733a8094 100644 --- a/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/models/Datasource.java +++ b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/models/Datasource.java @@ -54,7 +54,7 @@ public class Datasource extends GitSyncedDomain { String templateName; // This is only kept public for embedded datasource - @JsonView({Views.Public.class, FromRequest.class}) + @JsonView({Views.Public.class, FromRequest.class, Git.class}) DatasourceConfiguration datasourceConfiguration; @Transient diff --git a/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/models/DatasourceConfiguration.java b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/models/DatasourceConfiguration.java index ee6c0097cf42..5a81b66b730c 100644 --- a/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/models/DatasourceConfiguration.java +++ b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/models/DatasourceConfiguration.java @@ -1,6 +1,7 @@ package com.appsmith.external.models; import com.appsmith.external.views.FromRequest; +import com.appsmith.external.views.Git; import com.appsmith.external.views.Views; import com.fasterxml.jackson.annotation.JsonView; import lombok.AllArgsConstructor; @@ -37,17 +38,17 @@ public class DatasourceConfiguration implements AppsmithDomain { Boolean sshProxyEnabled; - @JsonView({Views.Public.class, FromRequest.class}) + @JsonView({Views.Public.class, FromRequest.class, Git.class}) List properties; // For REST API. - @JsonView({Views.Public.class, FromRequest.class}) + @JsonView({Views.Public.class, FromRequest.class, Git.class}) String url; - @JsonView({Views.Public.class, FromRequest.class}) + @JsonView({Views.Public.class, FromRequest.class, Git.class}) List headers; - @JsonView({Views.Public.class, FromRequest.class}) + @JsonView({Views.Public.class, FromRequest.class, Git.class}) List queryParameters; public boolean isSshProxyEnabled() { From 78b012d196c13cf898bbbb5999f2637f2d548cd0 Mon Sep 17 00:00:00 2001 From: Manish Kumar <107841575+sondermanish@users.noreply.github.com> Date: Wed, 4 Sep 2024 15:56:48 +0530 Subject: [PATCH 09/22] fix: removed conditional to check for jslib files (#36115) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description - Modified file writing logic for custom js lib writing logic Fixes https://github.com/appsmithorg/appsmith/issues/32734 > [!WARNING] > _If no issue exists, please create an issue first, and check with the maintainers if the issue is valid._ ## Automation /ok-to-test tags="@tag.Git" ### :mag: Cypress test results > [!TIP] > 🟒 🟒 🟒 All cypress tests have passed! πŸŽ‰ πŸŽ‰ πŸŽ‰ > Workflow run: > Commit: fe25da5225956128505e31e443e6a4033215089c > Cypress dashboard. > Tags: `@tag.Git` > Spec: >
Wed, 04 Sep 2024 09:58:48 UTC ## Communication Should the DevRel and Marketing teams inform users about this change? - [ ] Yes - [ ] No ## Summary by CodeRabbit - **Bug Fixes** - Simplified the logic for saving JavaScript libraries, which may improve performance but could affect when libraries are saved after modifications. - **Chores** - Removed unnecessary import statement, streamlining the codebase. --- .../com/appsmith/git/files/FileUtilsCEImpl.java | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/app/server/appsmith-git/src/main/java/com/appsmith/git/files/FileUtilsCEImpl.java b/app/server/appsmith-git/src/main/java/com/appsmith/git/files/FileUtilsCEImpl.java index bc5778813737..23891664b741 100644 --- a/app/server/appsmith-git/src/main/java/com/appsmith/git/files/FileUtilsCEImpl.java +++ b/app/server/appsmith-git/src/main/java/com/appsmith/git/files/FileUtilsCEImpl.java @@ -23,7 +23,6 @@ import org.json.JSONObject; import org.springframework.context.annotation.Import; import org.springframework.stereotype.Component; -import org.springframework.util.CollectionUtils; import org.springframework.util.FileSystemUtils; import org.springframework.util.StringUtils; import reactor.core.publisher.Mono; @@ -279,12 +278,16 @@ protected Set updateEntitiesInRepo(ApplicationGitReference applicationGi fileOperations.scanAndDeleteDirectoryForDeletedResources(validPages, baseRepo.resolve(PAGE_DIRECTORY)); - // Save JS Libs if there's at least one change - if (modifiedResources != null - && (modifiedResources.isAllModified() - || !CollectionUtils.isEmpty( - modifiedResources.getModifiedResourceMap().get(CUSTOM_JS_LIB_LIST)))) { + // Earlier this condition included that modified resource not be null, and + // it should either have allModified flag turned as true or CUSTOM_JS_LIB_LIST resource map is not empty + // Save JS Libs if there's at least one change. + // What are the possible caveats of making this change? + // Since each resource in the entry needs to be present in the Modified resource map to be written + // There won't be any differences in writing files. + // In terms of performance, we would need to access the customJSLib directory every time to + // compare with the valid js libs. + if (modifiedResources != null) { Path jsLibDirectory = baseRepo.resolve(JS_LIB_DIRECTORY); Set> jsLibEntries = applicationGitReference.getJsLibraries().entrySet(); From 7713482003fb9eb73536066507ea4ed21b8c41a7 Mon Sep 17 00:00:00 2001 From: Manish Kumar <107841575+sondermanish@users.noreply.github.com> Date: Tue, 10 Sep 2024 16:53:34 +0530 Subject: [PATCH 10/22] chore: Migration for missing datasource configuration on default rest datasources for git connected app. (#36203) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description Fixes #`Issue Number` _or_ Fixes `Issue URL` > [!WARNING] > _If no issue exists, please create an issue first, and check with the maintainers if the issue is valid._ ## Automation /ok-to-test tags="@tag.Git, @tag.ImportExport" ### :mag: Cypress test results > [!TIP] > 🟒 🟒 🟒 All cypress tests have passed! πŸŽ‰ πŸŽ‰ πŸŽ‰ > Workflow run: > Commit: 69729ce5e51ee6127f292a1dce468c492db9e413 > Cypress dashboard. > Tags: `@tag.Git, @tag.ImportExport` > Spec: >
Tue, 10 Sep 2024 10:07:42 UTC ## Communication Should the DevRel and Marketing teams inform users about this change? - [ ] Yes - [ ] No ## Summary by CodeRabbit - **New Features** - Enhanced application JSON migration process to support additional contextual parameters, improving accuracy and relevance. - Introduced a new helper class to facilitate datasource configuration during migrations. - **Bug Fixes** - Improved handling of incompatible schemas during migration, ensuring robust error management. - **Tests** - Adjusted test cases to accommodate changes in method signatures for migration processes, ensuring continued functionality. --- .../git/ApplicationGitFileUtilsCEImpl.java | 3 +- .../migrations/JsonSchemaMigration.java | 99 ++++++++++++----- .../JsonSchemaVersionsFallback.java | 2 +- .../migrations/MigrationHelperMethods.java | 105 ++++++++++++++++++ .../utils/JsonSchemaMigrationHelper.java | 75 +++++++++++++ .../AutoCommitEventHandlerImplTest.java | 7 +- .../git/autocommit/AutoCommitServiceTest.java | 9 +- .../migrations/JsonSchemaMigrationTest.java | 4 +- 8 files changed, 269 insertions(+), 35 deletions(-) create mode 100644 app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/utils/JsonSchemaMigrationHelper.java diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/applications/git/ApplicationGitFileUtilsCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/applications/git/ApplicationGitFileUtilsCEImpl.java index 39a87d72fac6..99333df7b92c 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/applications/git/ApplicationGitFileUtilsCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/applications/git/ApplicationGitFileUtilsCEImpl.java @@ -362,7 +362,8 @@ public Mono reconstructArtifactExchangeJsonFromFilesInRepo getApplicationResource(applicationReference.getMetadata(), ApplicationJson.class); ApplicationJson applicationJson = getApplicationJsonFromGitReference(applicationReference); copyNestedNonNullProperties(metadata, applicationJson); - return jsonSchemaMigration.migrateApplicationJsonToLatestSchema(applicationJson); + return jsonSchemaMigration.migrateApplicationJsonToLatestSchema( + applicationJson, baseArtifactId, branchName); }); } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/JsonSchemaMigration.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/JsonSchemaMigration.java index 047c037e6c4f..03d543dd3d05 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/JsonSchemaMigration.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/JsonSchemaMigration.java @@ -6,35 +6,27 @@ import com.appsmith.server.exceptions.AppsmithError; import com.appsmith.server.exceptions.AppsmithException; import com.appsmith.server.helpers.CollectionUtils; +import com.appsmith.server.migrations.utils.JsonSchemaMigrationHelper; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import reactor.core.publisher.Mono; +import java.util.Map; + @Slf4j @Component @RequiredArgsConstructor public class JsonSchemaMigration { private final JsonSchemaVersions jsonSchemaVersions; + private final JsonSchemaMigrationHelper jsonSchemaMigrationHelper; private boolean isCompatible(ApplicationJson applicationJson) { return (applicationJson.getClientSchemaVersion() <= jsonSchemaVersions.getClientVersion()) && (applicationJson.getServerSchemaVersion() <= jsonSchemaVersions.getServerVersion()); } - /** - * This is a temporary check which is being placed for the compatibility of server versions in scenarios - * where user is moving a json from an instance which has - * release_autocommit_feature_enabled true to an instance which has the flag as false. In that case the server - * version number of json would be 8 and in new instance it would be not compatible. - * @param applicationJson - * @return - */ - private boolean isAutocommitVersionBump(ApplicationJson applicationJson) { - return jsonSchemaVersions.getServerVersion() == 7 && applicationJson.getServerSchemaVersion() == 8; - } - private void setSchemaVersions(ApplicationJson applicationJson) { applicationJson.setServerSchemaVersion(getCorrectSchemaVersion(applicationJson.getServerSchemaVersion())); applicationJson.setClientSchemaVersion(getCorrectSchemaVersion(applicationJson.getClientSchemaVersion())); @@ -53,24 +45,53 @@ public Mono migrateArtifactExchangeJsonToLatestS ArtifactExchangeJson artifactExchangeJson) { if (ArtifactType.APPLICATION.equals(artifactExchangeJson.getArtifactJsonType())) { - return migrateApplicationJsonToLatestSchema((ApplicationJson) artifactExchangeJson); + return migrateApplicationJsonToLatestSchema((ApplicationJson) artifactExchangeJson, null, null); } return Mono.fromCallable(() -> artifactExchangeJson); } - public Mono migrateApplicationJsonToLatestSchema(ApplicationJson applicationJson) { + public Mono migrateApplicationJsonToLatestSchema( + ApplicationJson applicationJson, String baseApplicationId, String branchName) { return Mono.fromCallable(() -> { setSchemaVersions(applicationJson); - if (isCompatible(applicationJson)) { - return migrateServerSchema(applicationJson); - } - - if (isAutocommitVersionBump(applicationJson)) { - return migrateServerSchema(applicationJson); + return applicationJson; + }) + .flatMap(appJson -> { + if (!isCompatible(appJson)) { + return Mono.empty(); } - return null; + // Taking a tech debt over here for import of file application. + // All migration above version 9 is reactive + // TODO: make import flow migration reactive + return Mono.just(migrateServerSchema(appJson)) + .flatMap(migratedApplicationJson -> { + if (migratedApplicationJson.getServerSchemaVersion() == 9 + && Boolean.TRUE.equals(MigrationHelperMethods.doesRestApiRequireMigration( + migratedApplicationJson))) { + return jsonSchemaMigrationHelper + .addDatasourceConfigurationToDefaultRestApiActions( + baseApplicationId, branchName, migratedApplicationJson) + .map(applicationJsonWithMigration10 -> { + applicationJsonWithMigration10.setServerSchemaVersion(10); + return applicationJsonWithMigration10; + }); + } + + migratedApplicationJson.setServerSchemaVersion(10); + return Mono.just(migratedApplicationJson); + }) + .map(migratedAppJson -> { + if (applicationJson + .getServerSchemaVersion() + .equals(jsonSchemaVersions.getServerVersion())) { + return applicationJson; + } + + applicationJson.setServerSchemaVersion(jsonSchemaVersions.getServerVersion()); + return applicationJson; + }); }) .switchIfEmpty(Mono.error(new AppsmithException(AppsmithError.INCOMPATIBLE_IMPORTED_JSON))); } @@ -81,7 +102,7 @@ public Mono migrateApplicationJsonToLatestSchema(ApplicationJso * @param artifactExchangeJson : the json to be imported * @return transformed artifact exchange json */ - @Deprecated + @Deprecated(forRemoval = true, since = "Use migrateArtifactJsonToLatestSchema") public ArtifactExchangeJson migrateArtifactToLatestSchema(ArtifactExchangeJson artifactExchangeJson) { if (!ArtifactType.APPLICATION.equals(artifactExchangeJson.getArtifactJsonType())) { @@ -91,11 +112,11 @@ public ArtifactExchangeJson migrateArtifactToLatestSchema(ArtifactExchangeJson a ApplicationJson applicationJson = (ApplicationJson) artifactExchangeJson; setSchemaVersions(applicationJson); if (!isCompatible(applicationJson)) { - if (!isAutocommitVersionBump(applicationJson)) { - throw new AppsmithException(AppsmithError.INCOMPATIBLE_IMPORTED_JSON); - } + throw new AppsmithException(AppsmithError.INCOMPATIBLE_IMPORTED_JSON); } - return migrateServerSchema(applicationJson); + + applicationJson = migrateServerSchema(applicationJson); + return nonReactiveServerMigrationForImport(applicationJson); } /** @@ -145,11 +166,37 @@ private ApplicationJson migrateServerSchema(ApplicationJson applicationJson) { MigrationHelperMethods.ensureXmlParserPresenceInCustomJsLibList(applicationJson); applicationJson.setServerSchemaVersion(7); case 7: + applicationJson.setServerSchemaVersion(8); case 8: MigrationHelperMethods.migrateThemeSettingsForAnvil(applicationJson); applicationJson.setServerSchemaVersion(9); + + // This is not supposed to have anymore additions to the schema. default: // Unable to detect the serverSchema + + } + + return applicationJson; + } + + /** + * This method is an alternative to reactive way of adding migrations to application json. + * this is getting used by flows which haven't implemented the reactive way yet. + * @param applicationJson : application json for which migration has to be done. + * @return return application json after migration + */ + private ApplicationJson nonReactiveServerMigrationForImport(ApplicationJson applicationJson) { + if (jsonSchemaVersions.getServerVersion().equals(applicationJson.getServerSchemaVersion())) { + return applicationJson; + } + + switch (applicationJson.getServerSchemaVersion()) { + case 9: + // this if for cases where we have empty datasource configs + MigrationHelperMethods.migrateApplicationJsonToVersionTen(applicationJson, Map.of()); + applicationJson.setServerSchemaVersion(10); + default: } if (applicationJson.getServerSchemaVersion().equals(jsonSchemaVersions.getServerVersion())) { diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/JsonSchemaVersionsFallback.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/JsonSchemaVersionsFallback.java index 63b6c7e7d4e3..06518c18b4e1 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/JsonSchemaVersionsFallback.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/JsonSchemaVersionsFallback.java @@ -4,7 +4,7 @@ @Component public class JsonSchemaVersionsFallback { - private static final Integer serverVersion = 9; + private static final Integer serverVersion = 10; public static final Integer clientVersion = 1; public Integer getServerVersion() { diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/MigrationHelperMethods.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/MigrationHelperMethods.java index cf18759a867a..87e3d93e6ff6 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/MigrationHelperMethods.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/MigrationHelperMethods.java @@ -1,8 +1,11 @@ package com.appsmith.server.migrations; +import com.appsmith.external.constants.PluginConstants; import com.appsmith.external.helpers.MustacheHelper; import com.appsmith.external.models.ActionDTO; import com.appsmith.external.models.BaseDomain; +import com.appsmith.external.models.Datasource; +import com.appsmith.external.models.DatasourceConfiguration; import com.appsmith.external.models.InvisibleActionFields; import com.appsmith.external.models.Property; import com.appsmith.server.constants.ApplicationConstants; @@ -1231,4 +1234,106 @@ public static void setThemeSettings(Application.ThemeSetting themeSetting) { themeSetting.setSizing(1); } } + + private static boolean conditionForDefaultRestDatasourceMigration(NewAction action) { + Datasource actionDatasource = action.getUnpublishedAction().getDatasource(); + + // condition to check if the action is default rest datasource. + // it has no datasource id and name is equal to DEFAULT_REST_DATASOURCE + boolean isActionDefaultRestDatasource = !org.springframework.util.StringUtils.hasText(actionDatasource.getId()) + && PluginConstants.DEFAULT_REST_DATASOURCE.equals(actionDatasource.getName()); + + // condition to check if the action has missing url or has no config at all + boolean isDatasourceConfigurationOrUrlMissing = actionDatasource.getDatasourceConfiguration() == null + || !org.springframework.util.StringUtils.hasText( + actionDatasource.getDatasourceConfiguration().getUrl()); + + return isActionDefaultRestDatasource && isDatasourceConfigurationOrUrlMissing; + } + + /** + * Adds datasource configuration and relevant url to the embedded datasource actions. + * @param applicationJson: ApplicationJson for which the migration has to be performed + * @param defaultDatasourceActionMap: gitSyncId to actions with default rest datasource map + */ + public static void migrateApplicationJsonToVersionTen( + ApplicationJson applicationJson, Map defaultDatasourceActionMap) { + List actionList = applicationJson.getActionList(); + if (CollectionUtils.isNullOrEmpty(actionList)) { + return; + } + + for (NewAction action : actionList) { + if (action.getUnpublishedAction() == null + || action.getUnpublishedAction().getDatasource() == null) { + continue; + } + + Datasource actionDatasource = action.getUnpublishedAction().getDatasource(); + if (conditionForDefaultRestDatasourceMigration(action)) { + // Idea is to add datasourceConfiguration to existing DEFAULT_REST_DATASOURCE apis, + // for which the datasource configuration is missing + // the url would be set to empty string as right url is not present over here. + setDatasourceConfigDetailsInDefaultRestDatasourceForActions(action, defaultDatasourceActionMap); + } + } + } + + /** + * Finds if the applicationJson has any default rest datasource which has a null datasource configuration + * or an unset url. + * @param applicationJson : Application Json for which requirement is to be checked. + * @return true if the application has a rest api which doesn't have a valid datasource configuration. + */ + public static Boolean doesRestApiRequireMigration(ApplicationJson applicationJson) { + List actionList = applicationJson.getActionList(); + if (CollectionUtils.isNullOrEmpty(actionList)) { + return Boolean.FALSE; + } + + for (NewAction action : actionList) { + if (action.getUnpublishedAction() == null + || action.getUnpublishedAction().getDatasource() == null) { + continue; + } + + Datasource actionDatasource = action.getUnpublishedAction().getDatasource(); + if (conditionForDefaultRestDatasourceMigration(action)) { + return Boolean.TRUE; + } + } + + return Boolean.FALSE; + } + + /** + * Adds the relevant url in the default rest datasource for the given action from an action in the db + * otherwise sets the url to empty + * it's established that action doesn't have the datasource. + * @param action : default rest datasource actions which doesn't have valid datasource configuration. + * @param defaultDatasourceActionMap : gitSyncId to actions with default rest datasource map + */ + public static void setDatasourceConfigDetailsInDefaultRestDatasourceForActions( + NewAction action, Map defaultDatasourceActionMap) { + + ActionDTO actionDTO = action.getUnpublishedAction(); + Datasource actionDatasource = actionDTO.getDatasource(); + DatasourceConfiguration datasourceConfiguration = new DatasourceConfiguration(); + + if (defaultDatasourceActionMap.containsKey(action.getGitSyncId())) { + NewAction actionFromMap = defaultDatasourceActionMap.get(action.getGitSyncId()); + DatasourceConfiguration datasourceConfigurationFromDBAction = + actionFromMap.getUnpublishedAction().getDatasource().getDatasourceConfiguration(); + + if (datasourceConfigurationFromDBAction != null) { + datasourceConfiguration.setUrl(datasourceConfigurationFromDBAction.getUrl()); + } + } + + if (!org.springframework.util.StringUtils.hasText(datasourceConfiguration.getUrl())) { + datasourceConfiguration.setUrl(""); + } + + actionDatasource.setDatasourceConfiguration(datasourceConfiguration); + } } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/utils/JsonSchemaMigrationHelper.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/utils/JsonSchemaMigrationHelper.java new file mode 100644 index 000000000000..934bf79c6ed5 --- /dev/null +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/utils/JsonSchemaMigrationHelper.java @@ -0,0 +1,75 @@ +package com.appsmith.server.migrations.utils; + +import com.appsmith.external.constants.PluginConstants; +import com.appsmith.server.applications.base.ApplicationService; +import com.appsmith.server.domains.Application; +import com.appsmith.server.domains.NewAction; +import com.appsmith.server.dtos.ApplicationJson; +import com.appsmith.server.migrations.MigrationHelperMethods; +import com.appsmith.server.newactions.base.NewActionService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; +import reactor.core.publisher.Mono; + +import java.util.Map; +import java.util.Optional; + +@Component +@Slf4j +@RequiredArgsConstructor +public class JsonSchemaMigrationHelper { + + private final ApplicationService applicationService; + private final NewActionService newActionService; + + public Mono addDatasourceConfigurationToDefaultRestApiActions( + String baseApplicationId, String branchName, ApplicationJson applicationJson) { + + Mono contingencyMigrationJson = Mono.defer(() -> Mono.fromCallable(() -> { + MigrationHelperMethods.migrateApplicationJsonToVersionTen(applicationJson, Map.of()); + return applicationJson; + })); + + if (!StringUtils.hasText(baseApplicationId) || !StringUtils.hasText(branchName)) { + return contingencyMigrationJson; + } + + Mono applicationMono = applicationService + .findByBranchNameAndBaseApplicationId(branchName, baseApplicationId, null) + .cache(); + + return applicationMono + .flatMap(branchedApplication -> { + return newActionService + .findAllByApplicationIdAndViewMode( + branchedApplication.getId(), Boolean.FALSE, Optional.empty(), Optional.empty()) + .filter(action -> { + if (action.getUnpublishedAction() == null + || action.getUnpublishedAction().getDatasource() == null) { + return false; + } + + boolean reverseFlag = StringUtils.hasText(action.getUnpublishedAction() + .getDatasource() + .getId()) + || !PluginConstants.DEFAULT_REST_DATASOURCE.equals(action.getUnpublishedAction() + .getDatasource() + .getName()); + + return !reverseFlag; + }) + .collectMap(NewAction::getGitSyncId); + }) + .map(newActionMap -> { + MigrationHelperMethods.migrateApplicationJsonToVersionTen(applicationJson, newActionMap); + return applicationJson; + }) + .switchIfEmpty(contingencyMigrationJson) + .onErrorResume(error -> { + log.error("Error occurred while migrating actions of application json. {}", error.getMessage()); + return contingencyMigrationJson; + }); + } +} diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/git/autocommit/AutoCommitEventHandlerImplTest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/git/autocommit/AutoCommitEventHandlerImplTest.java index bf49502f0596..29265607ffd1 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/git/autocommit/AutoCommitEventHandlerImplTest.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/git/autocommit/AutoCommitEventHandlerImplTest.java @@ -442,7 +442,8 @@ public void autoCommitServerMigration_WhenServerHasNoChanges_NoCommitMade() thro doReturn(Mono.just(applicationJson1)) .when(jsonSchemaMigration) - .migrateApplicationJsonToLatestSchema(applicationJson); + .migrateApplicationJsonToLatestSchema( + Mockito.eq(applicationJson), Mockito.anyString(), Mockito.anyString()); doReturn(Mono.just("success")) .when(gitExecutor) @@ -574,7 +575,9 @@ public void autocommitServerMigration_WhenJsonSchemaMigrationPresent_CommitSucce AppsmithBeanUtils.copyNewFieldValuesIntoOldObject(applicationJson, applicationJson1); applicationJson1.setServerSchemaVersion(jsonSchemaVersions.getServerVersion() + 1); - doReturn(Mono.just(applicationJson1)).when(jsonSchemaMigration).migrateApplicationJsonToLatestSchema(any()); + doReturn(Mono.just(applicationJson1)) + .when(jsonSchemaMigration) + .migrateApplicationJsonToLatestSchema(any(), Mockito.anyString(), Mockito.anyString()); gitFileSystemTestHelper.setupGitRepository(autoCommitEvent, applicationJson); diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/git/autocommit/AutoCommitServiceTest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/git/autocommit/AutoCommitServiceTest.java index 1c53aa243bb9..e18f8e66fe9b 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/git/autocommit/AutoCommitServiceTest.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/git/autocommit/AutoCommitServiceTest.java @@ -284,7 +284,8 @@ public void testAutoCommit_whenOnlyServerIsEligibleForMigration_commitSuccess() doReturn(Mono.just(applicationJson1)) .when(jsonSchemaMigration) - .migrateApplicationJsonToLatestSchema(any(ApplicationJson.class)); + .migrateApplicationJsonToLatestSchema( + any(ApplicationJson.class), Mockito.anyString(), Mockito.anyString()); gitFileSystemTestHelper.setupGitRepository( WORKSPACE_ID, DEFAULT_APP_ID, BRANCH_NAME, REPO_NAME, applicationJson); @@ -571,7 +572,8 @@ public void testAutoCommit_whenAutoCommitEligibleButPrerequisiteNotComplete_retu doReturn(Mono.just(applicationJson1)) .when(jsonSchemaMigration) - .migrateApplicationJsonToLatestSchema(any(ApplicationJson.class)); + .migrateApplicationJsonToLatestSchema( + any(ApplicationJson.class), Mockito.anyString(), Mockito.anyString()); gitFileSystemTestHelper.setupGitRepository( WORKSPACE_ID, DEFAULT_APP_ID, BRANCH_NAME, REPO_NAME, applicationJson); @@ -644,7 +646,8 @@ public void testAutoCommit_whenServerIsRunningMigrationCallsAutocommitAgainOnDif doReturn(Mono.just(applicationJson1)) .when(jsonSchemaMigration) - .migrateApplicationJsonToLatestSchema(any(ApplicationJson.class)); + .migrateApplicationJsonToLatestSchema( + any(ApplicationJson.class), Mockito.anyString(), Mockito.anyString()); gitFileSystemTestHelper.setupGitRepository( WORKSPACE_ID, DEFAULT_APP_ID, BRANCH_NAME, REPO_NAME, applicationJson); diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/migrations/JsonSchemaMigrationTest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/migrations/JsonSchemaMigrationTest.java index d31c18fcdcbd..9fbbfbe61200 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/migrations/JsonSchemaMigrationTest.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/migrations/JsonSchemaMigrationTest.java @@ -97,7 +97,7 @@ public void migrateApplicationJsonToLatestSchema_whenFeatureFlagIsOn_returnsIncr gitFileSystemTestHelper.getApplicationJson(this.getClass().getResource("application.json")); Mono applicationJsonMono = - jsonSchemaMigration.migrateApplicationJsonToLatestSchema(applicationJson); + jsonSchemaMigration.migrateApplicationJsonToLatestSchema(applicationJson, null, null); StepVerifier.create(applicationJsonMono) .assertNext(appJson -> { assertThat(appJson.getServerSchemaVersion()).isEqualTo(jsonSchemaVersions.getServerVersion()); @@ -121,7 +121,7 @@ public void migrateApplicationJsonToLatestSchema_whenFeatureFlagIsOff_returnsFal gitFileSystemTestHelper.getApplicationJson(this.getClass().getResource("application.json")); Mono applicationJsonMono = - jsonSchemaMigration.migrateApplicationJsonToLatestSchema(applicationJson); + jsonSchemaMigration.migrateApplicationJsonToLatestSchema(applicationJson, null, null); StepVerifier.create(applicationJsonMono) .assertNext(appJson -> { assertThat(appJson.getClientSchemaVersion()).isEqualTo(jsonSchemaVersions.getClientVersion()); From 05adea7553ec118fe6f17151912326a60641688e Mon Sep 17 00:00:00 2001 From: Hetu Nandu Date: Wed, 11 Sep 2024 14:06:28 +0530 Subject: [PATCH 11/22] fix: RBAC errors not showing toasts (#36244) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description Updates the error handling for Access Control scenarios to show toasts when correct permissions are not present Fixes #36229 ## Automation /ok-to-test tags="@tag.AccessControl" ### :mag: Cypress test results > [!CAUTION] > πŸ”΄ πŸ”΄ πŸ”΄ Some tests have failed. > Workflow run: > Commit: 08edaeefb87d02f8951a38cef2ac0c608d8fe8f8 > Cypress dashboard. > Tags: @tag.AccessControl > Spec: > The following are new failures, please fix them before merging the PR:
    >
  1. cypress/e2e/Regression/ServerSide/GenerateCRUD/MySQL2_Spec.ts
> List of identified flaky tests. >
Wed, 11 Sep 2024 08:28:37 UTC ## Communication Should the DevRel and Marketing teams inform users about this change? - [ ] Yes - [ ] No ## Summary by CodeRabbit - **New Features** - Enhanced error handling with structured Redux actions for better state management. - Improved clarity in error message construction based on error types. - **Bug Fixes** - Refined logic for displaying toast notifications based on the `show` parameter. - **Documentation** - Updated comments for better understanding of error handling logic. --- app/client/src/sagas/ActionSagas.ts | 10 ++++++++-- app/client/src/sagas/ErrorSagas.tsx | 27 +++++++++++++++++---------- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/app/client/src/sagas/ActionSagas.ts b/app/client/src/sagas/ActionSagas.ts index a5f88ef14e0d..94f7cfe44d63 100644 --- a/app/client/src/sagas/ActionSagas.ts +++ b/app/client/src/sagas/ActionSagas.ts @@ -795,13 +795,19 @@ function* copyActionSaga( // @ts-expect-error: type mismatch Action vs ActionCreateUpdateResponse yield put(copyActionSuccess(payload)); - } catch (e) { + } catch (e: unknown) { const actionName = actionObject ? actionObject.name : ""; + const errorMessage = + e instanceof Error + ? e.message + : createMessage(ERROR_ACTION_COPY_FAIL, actionName); yield put( copyActionError({ ...action.payload, show: true, - error: { message: createMessage(ERROR_ACTION_COPY_FAIL, actionName) }, + error: { + message: errorMessage, + }, }), ); } diff --git a/app/client/src/sagas/ErrorSagas.tsx b/app/client/src/sagas/ErrorSagas.tsx index 3a690ce17ebe..559c0b9d6e9b 100644 --- a/app/client/src/sagas/ErrorSagas.tsx +++ b/app/client/src/sagas/ErrorSagas.tsx @@ -112,7 +112,16 @@ export function* validateResponse( } if (!response.responseMeta && response.status) { - throw Error(getErrorMessage(response.status, response.resourceType)); + yield put({ + type: ReduxActionErrorTypes.API_ERROR, + payload: { + error: new Error( + getErrorMessage(response.status, response.resourceType), + ), + logToSentry, + show, + }, + }); } if (response.responseMeta.success) { @@ -218,22 +227,20 @@ export interface ErrorActionPayload { export function* errorSaga(errorAction: ReduxAction) { const effects = [ErrorEffectTypes.LOG_TO_CONSOLE]; const { payload, type } = errorAction; - const { - error, - logToDebugger, - logToSentry, - show = true, - sourceEntity, - } = payload || {}; + const { error, logToDebugger, logToSentry, show, sourceEntity } = + payload || {}; const appMode: APP_MODE = yield select(getAppMode); // "show" means show a toast. We check if the error has been asked to not been shown - // By making the default behaviour "true" we are ensuring undefined actions still pass through this check - if (show) { + // By checking undefined, undecided actions still pass through this check + if (show === undefined) { // We want to show toasts for certain actions only so we avoid issues or if it is outside edit mode if (shouldShowToast(type) || appMode !== APP_MODE.EDIT) { effects.push(ErrorEffectTypes.SHOW_ALERT); } + // If true is passed, show the error no matter what + } else if (show) { + effects.push(ErrorEffectTypes.SHOW_ALERT); } if (logToDebugger) { From df3bfa2831a77818d1f06b9f968624b1bdea6675 Mon Sep 17 00:00:00 2001 From: Abhijeet <41686026+abhvsn@users.noreply.github.com> Date: Tue, 24 Sep 2024 18:19:12 +0530 Subject: [PATCH 12/22] chore: Add step to place server artifacts for `package-master` stage (#36513) ## Description > [!TIP] > _Add a TL;DR when the description is longer than 500 words or extremely technical (helps the content, marketing, and DevRel team)._ > > _Please also include relevant motivation and context. List any dependencies that are required for this change. Add links to Notion, Figma or any other documents that might be relevant to the PR._ Fixes #`Issue Number` _or_ Fixes `Issue URL` > [!WARNING] > _If no issue exists, please create an issue first, and check with the maintainers if the issue is valid._ ## Automation /ok-to-test tags="" ### :mag: Cypress test results > [!CAUTION] > If you modify the content in this section, you are likely to disrupt the CI result for your PR. ## Communication Should the DevRel and Marketing teams inform users about this change? - [ ] Yes - [ ] No (cherry picked from commit 368fdac46438b14514f7ed1f5b8bbefdeb2591ef) --- .github/workflows/test-build-docker-image.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/test-build-docker-image.yml b/.github/workflows/test-build-docker-image.yml index 71fe51a5cb84..f14c565e210a 100644 --- a/.github/workflows/test-build-docker-image.yml +++ b/.github/workflows/test-build-docker-image.yml @@ -435,6 +435,12 @@ jobs: scripts/generate_info_json.sh fi + - name: Place server artifacts-es + run: | + if [[ -f scripts/prepare_server_artifacts.sh ]]; then + scripts/prepare_server_artifacts.sh + fi + - name: Set up Depot CLI uses: depot/setup-action@v1 From 289040dbda765f3ae5692571a9a603038624bad8 Mon Sep 17 00:00:00 2001 From: Abhijeet <41686026+abhvsn@users.noreply.github.com> Date: Tue, 24 Sep 2024 19:20:13 +0530 Subject: [PATCH 13/22] chore: Add server artifacts for pg and mongodb for github release workflow (#36516) ## Description > [!TIP] > _Add a TL;DR when the description is longer than 500 words or extremely technical (helps the content, marketing, and DevRel team)._ > > _Please also include relevant motivation and context. List any dependencies that are required for this change. Add links to Notion, Figma or any other documents that might be relevant to the PR._ Fixes #`Issue Number` _or_ Fixes `Issue URL` > [!WARNING] > _If no issue exists, please create an issue first, and check with the maintainers if the issue is valid._ ## Automation /ok-to-test tags="" ### :mag: Cypress test results > [!CAUTION] > If you modify the content in this section, you are likely to disrupt the CI result for your PR. ## Communication Should the DevRel and Marketing teams inform users about this change? - [ ] Yes - [ ] No ## Summary by CodeRabbit - **New Features** - Enhanced GitHub Actions workflow to conditionally prepare server artifacts based on the presence of a specific script. - **Chores** - Added a new job step in the GitHub Actions workflow for improved artifact management. (cherry picked from commit 4ea280311aecc40349e14dff643db9b9790b2577) --- .github/workflows/github-release.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/github-release.yml b/.github/workflows/github-release.yml index bf230d050ecf..c4dd4001beb8 100644 --- a/.github/workflows/github-release.yml +++ b/.github/workflows/github-release.yml @@ -247,6 +247,12 @@ jobs: run: | scripts/generate_info_json.sh + - name: Place server artifacts-es + run: | + if [[ -f scripts/prepare_server_artifacts.sh ]]; then + scripts/prepare_server_artifacts.sh + fi + - name: Login to DockerHub uses: docker/login-action@v1 with: From 69ba8b57e9ceb2945e99140543220c3d0fe420aa Mon Sep 17 00:00:00 2001 From: Anagh Hegde Date: Mon, 30 Sep 2024 23:42:56 +0530 Subject: [PATCH 14/22] chore: create appsmith schema for postgres (#36591) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description The current state is default schema or public schema. This schema is accessible by default when user connects to the pg database. Hence create `appsmith` schema for Appsmith server to use. This is to avoid anyone accidentally modifying the appsmith data. ## Automation /ok-to-test tags="@tag.Sanity" ### :mag: Cypress test results > [!IMPORTANT] > 🟣 🟣 🟣 Your tests are running. > Tests running at: > Commit: 32f91e8d7ce750e4a088996aff4abe6905aa982f > Workflow: `PR Automation test suite` > Tags: `@tag.Sanity` > Spec: `` >
Mon, 30 Sep 2024 18:08:23 UTC ## Communication Should the DevRel and Marketing teams inform users about this change? - [ ] Yes - [ ] No ## Summary by CodeRabbit ## Summary by CodeRabbit - **New Features** - Introduced a script to initialize the PostgreSQL database schema for Appsmith. - Added utilities for managing PostgreSQL database connections, including availability checks and parameter extraction. - Enhanced scripts for managing PostgreSQL connections and initialization. - Improved environment configuration for PostgreSQL database connections, including automatic password generation for local setups. - Updated JDBC URL handling to include schema parameters for PostgreSQL connections. - Added support for proxy configuration in the application setup. - **Bug Fixes** - Improved error handling and connection retry mechanisms for PostgreSQL setup. - **Documentation** - Updated comments and logging for better clarity on database operations. --------- Co-authored-by: Abhijeet --- .../server/configurations/CommonDBConfig.java | 19 +++++-- .../configurations/CommonDBConfigTest.java | 33 ++++++++++-- deploy/docker/fs/opt/appsmith/entrypoint.sh | 3 +- deploy/docker/fs/opt/appsmith/pg-utils.sh | 50 ++++++++++++++++++- deploy/docker/fs/opt/appsmith/run-java.sh | 1 + .../fs/opt/appsmith/templates/docker.env.sh | 7 +-- 6 files changed, 102 insertions(+), 11 deletions(-) diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/CommonDBConfig.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/CommonDBConfig.java index b7bd7a52f11d..417cb3de2bdd 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/CommonDBConfig.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/CommonDBConfig.java @@ -69,10 +69,23 @@ public DataSourceProperties extractJdbcProperties(String dbUrl) { ds.setUsername(userDetails[0]); ds.setPassword(userDetails[1]); } - // If the port is not mentioned default it to standard 5432 + // If the port is not mentioned, default it to the standard PostgreSQL port 5432 int port = uri.getPort() == -1 ? 5432 : uri.getPort(); - String updatedUrl = - String.format("%s%s://%s:%s%s", JDBC_PREFIX, uri.getScheme(), uri.getHost(), port, uri.getPath()); + + // Check if the URL already has query parameters + String query = uri.getQuery(); + String updatedUrl; + if (StringUtils.hasLength(query)) { + // Append currentSchema=appsmith if there are already parameters + updatedUrl = String.format( + "%s%s://%s:%s%s?%s¤tSchema=appsmith", + JDBC_PREFIX, uri.getScheme(), uri.getHost(), port, uri.getPath(), query); + } else { + // No parameters, just append currentSchema + updatedUrl = String.format( + "%s%s://%s:%s%s?currentSchema=appsmith", + JDBC_PREFIX, uri.getScheme(), uri.getHost(), port, uri.getPath()); + } ds.setUrl(updatedUrl); return ds; } catch (URISyntaxException e) { diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/configurations/CommonDBConfigTest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/configurations/CommonDBConfigTest.java index 1332b7241deb..eb8591786374 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/configurations/CommonDBConfigTest.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/configurations/CommonDBConfigTest.java @@ -16,13 +16,13 @@ public void testExtractAndSaveJdbcParams_validDbUrlWithUsernameAndPassword() { DataSourceProperties ds = commonDBConfig.extractJdbcProperties(dbUrl); assertEquals("postgres", ds.getUsername()); assertEquals("password", ds.getPassword()); - assertEquals("jdbc:postgresql://localhost:5432/postgres", ds.getUrl()); + assertEquals("jdbc:postgresql://localhost:5432/postgres?currentSchema=appsmith", ds.getUrl()); String dbUrlWithPort = "postgresql://postgres:password@localhost:1234/postgres"; ds = commonDBConfig.extractJdbcProperties(dbUrlWithPort); assertEquals("postgres", ds.getUsername()); assertEquals("password", ds.getPassword()); - assertEquals("jdbc:postgresql://localhost:1234/postgres", ds.getUrl()); + assertEquals("jdbc:postgresql://localhost:1234/postgres?currentSchema=appsmith", ds.getUrl()); } @Test @@ -32,7 +32,7 @@ public void testExtractAndSaveJdbcParams_validDbUrlWithoutUsernameAndPassword() DataSourceProperties ds = commonDBConfig.extractJdbcProperties(dbUrl); assertNull(ds.getUsername()); assertNull(ds.getPassword()); - assertEquals("jdbc:postgresql://localhost:5432/postgres", ds.getUrl()); + assertEquals("jdbc:postgresql://localhost:5432/postgres?currentSchema=appsmith", ds.getUrl()); } @Test @@ -44,4 +44,31 @@ public void testExtractAndSaveJdbcParams_invalidDbUrl() { dbUrl); assertThrows(IllegalArgumentException.class, () -> commonDBConfig.extractJdbcProperties(dbUrl), errorString); } + + @Test + void testExtractJdbcPropertiesWithQueryParams() { + CommonDBConfig commonDBConfig = new CommonDBConfig(); + String dbUrl = "postgresql://user:password@localhost:5432/mydb?sslmode=require"; + + DataSourceProperties dataSourceProperties = commonDBConfig.extractJdbcProperties(dbUrl); + + String expectedUrl = "jdbc:postgresql://localhost:5432/mydb?sslmode=require¤tSchema=appsmith"; + assertEquals( + expectedUrl, + dataSourceProperties.getUrl(), + "URL with existing query params should append the currentSchema correctly."); + } + + @Test + void testExtractJdbcPropertiesWithoutQueryParams() { + CommonDBConfig commonDBConfig = new CommonDBConfig(); + String dbUrl = "postgresql://user:password@localhost:5432/mydb"; + DataSourceProperties dataSourceProperties = commonDBConfig.extractJdbcProperties(dbUrl); + + String expectedUrl = "jdbc:postgresql://localhost:5432/mydb?currentSchema=appsmith"; + assertEquals( + expectedUrl, + dataSourceProperties.getUrl(), + "URL without query params should append the currentSchema correctly."); + } } diff --git a/deploy/docker/fs/opt/appsmith/entrypoint.sh b/deploy/docker/fs/opt/appsmith/entrypoint.sh index 3d73af5b391a..5e42418d92aa 100644 --- a/deploy/docker/fs/opt/appsmith/entrypoint.sh +++ b/deploy/docker/fs/opt/appsmith/entrypoint.sh @@ -58,6 +58,7 @@ init_env_file() { # Generate new docker.env file when initializing container for first time or in Heroku which does not have persistent volume tlog "Generating default configuration file" mkdir -p "$CONF_PATH" + local default_appsmith_mongodb_user="appsmith" local generated_appsmith_mongodb_password=$( tr -dc A-Za-z0-9 "$ENV_PATH" fi - tlog "Load environment configuration" # Load the ones in `docker.env` in the stacks folder. diff --git a/deploy/docker/fs/opt/appsmith/pg-utils.sh b/deploy/docker/fs/opt/appsmith/pg-utils.sh index 315446f552d7..7c37c8c4ebe2 100755 --- a/deploy/docker/fs/opt/appsmith/pg-utils.sh +++ b/deploy/docker/fs/opt/appsmith/pg-utils.sh @@ -87,6 +87,54 @@ extract_postgres_db_params() { export PG_DB_NAME="$DB" } +init_pg_db() { + # Create the appsmith schema + echo "Initializing PostgreSQL with schema..." + + # Check if APPSMITH_DB_URL is a PostgreSQL URL + if [[ -n "$APPSMITH_DB_URL" && "$APPSMITH_DB_URL" == postgres*://* ]]; then + echo "APPSMITH_DB_URL is a valid PostgreSQL URL." + + # Check if the DB_HOST is local (localhost or 127.0.0.1) + if [[ "$PG_DB_HOST" == "localhost" || "$PG_DB_HOST" == "127.0.0.1" ]]; then + + # Check if the database exists + DB_CHECK=$(psql -h "$PG_DB_HOST" -p "$PG_DB_PORT" -U postgres -d "postgres" -tAc "SELECT 1 FROM pg_database WHERE datname='$PG_DB_NAME'") + + if [ "$DB_CHECK" != "1" ]; then + echo "Database $PG_DB_NAME does not exist. Creating database..." + psql -h "$PG_DB_HOST" -p "$PG_DB_PORT" -U postgres -d "postgres" -c "CREATE DATABASE $PG_DB_NAME;" + else + echo "Database $PG_DB_NAME already exists." + fi + + # Check if the schema exists + SCHEMA_CHECK=$(psql -h "$PG_DB_HOST" -p "$PG_DB_PORT" -U postgres -d "$PG_DB_NAME" -tAc "SELECT 1 FROM information_schema.schemata WHERE schema_name='appsmith'") + + # Create schema and user if not exists + if [ "$SCHEMA_CHECK" != "1" ]; then + echo "Creating user '$PG_DB_USER' with password " + psql -h "$PG_DB_HOST" -p "$PG_DB_PORT" -U postgres -d "$PG_DB_NAME" -c "CREATE USER \"$PG_DB_USER\" WITH PASSWORD '$PG_DB_PASSWORD';" + + echo "Schema 'appsmith' does not exist. Creating schema..." + psql -h "$PG_DB_HOST" -p "$PG_DB_PORT" -U postgres -d "$PG_DB_NAME" -c "CREATE SCHEMA appsmith;" + fi + else + echo "Remote PostgreSQL detected, running as current user." + PGPASSWORD=$PG_DB_PASSWORD psql -h "$PG_DB_HOST" -p "$PG_DB_PORT" -U "$PG_DB_USER" -d "$PG_DB_NAME" -c "CREATE SCHEMA IF NOT EXISTS appsmith;" + fi + + # Check if the schema creation was successful + if [ $? -eq 0 ]; then + echo "Schema 'appsmith' created or already exists." + else + echo "Failed to create schema 'appsmith'." + exit 1 + fi + echo "PostgreSQL initialization completed." + fi +} + # Example usage of the functions # waitForPostgresAvailability -# extract_postgres_db_params "postgresql://user:password@localhost:5432/dbname" \ No newline at end of file +# extract_postgres_db_params "postgresql://user:password@localhost:5432/dbname" diff --git a/deploy/docker/fs/opt/appsmith/run-java.sh b/deploy/docker/fs/opt/appsmith/run-java.sh index ed88e26e1191..77d5ccfe7442 100755 --- a/deploy/docker/fs/opt/appsmith/run-java.sh +++ b/deploy/docker/fs/opt/appsmith/run-java.sh @@ -36,6 +36,7 @@ match-proxy-url() { if [[ "$mode" == "pg" ]]; then extract_postgres_db_params "$APPSMITH_DB_URL" waitForPostgresAvailability + init_pg_db fi if match-proxy-url "${HTTP_PROXY-}"; then diff --git a/deploy/docker/fs/opt/appsmith/templates/docker.env.sh b/deploy/docker/fs/opt/appsmith/templates/docker.env.sh index e80133242808..9a826d4dfb6b 100644 --- a/deploy/docker/fs/opt/appsmith/templates/docker.env.sh +++ b/deploy/docker/fs/opt/appsmith/templates/docker.env.sh @@ -2,7 +2,7 @@ set -o nounset MONGO_USER="$1" -MONGO_PASSWORD="$2" +DB_PASSWORD="$2" ENCRYPTION_PASSWORD="$3" ENCRYPTION_SALT="$4" SUPERVISOR_PASSWORD="$5" @@ -63,9 +63,10 @@ APPSMITH_RECAPTCHA_SITE_KEY= APPSMITH_RECAPTCHA_SECRET_KEY= APPSMITH_RECAPTCHA_ENABLED= -APPSMITH_DB_URL=mongodb://$MONGO_USER:$MONGO_PASSWORD@localhost:27017/appsmith +APPSMITH_DB_URL=mongodb://$MONGO_USER:$DB_PASSWORD@localhost:27017/appsmith +APPSMITH_POSTGRES_DB_URL=postgresql://appsmith:$DB_PASSWORD@localhost:5432/appsmith APPSMITH_MONGODB_USER=$MONGO_USER -APPSMITH_MONGODB_PASSWORD=$MONGO_PASSWORD +APPSMITH_MONGODB_PASSWORD=$DB_PASSWORD APPSMITH_API_BASE_URL=http://localhost:8080/api/v1 APPSMITH_REDIS_URL=redis://127.0.0.1:6379 From 67c9ae2a27823358c4349a0326d799d388ebb4fe Mon Sep 17 00:00:00 2001 From: Nidhi Date: Mon, 7 Oct 2024 10:31:11 +0530 Subject: [PATCH 15/22] fix: Clear all session for Spring upgrade (#36695) --- .../Migration063CacheBustSpringBoot3_3.java | 31 ++++++------------- 1 file changed, 10 insertions(+), 21 deletions(-) diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/db/ce/Migration063CacheBustSpringBoot3_3.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/db/ce/Migration063CacheBustSpringBoot3_3.java index 61936af057f5..7ca5077babad 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/db/ce/Migration063CacheBustSpringBoot3_3.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/db/ce/Migration063CacheBustSpringBoot3_3.java @@ -3,36 +3,25 @@ import io.mongock.api.annotations.ChangeUnit; import io.mongock.api.annotations.Execution; import io.mongock.api.annotations.RollbackExecution; -import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.data.redis.core.ReactiveRedisOperations; -import org.springframework.data.redis.core.script.RedisScript; -import reactor.core.publisher.Flux; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.data.redis.core.ReactiveRedisTemplate; -@RequiredArgsConstructor @Slf4j @ChangeUnit(order = "063", id = "reset_session_oauth2_spring_3_3") public class Migration063CacheBustSpringBoot3_3 { - private final ReactiveRedisOperations reactiveRedisOperations; - @RollbackExecution public void rollbackExecution() {} @Execution - public void execute() { - doClearRedisOAuth2AuthClientKeys(reactiveRedisOperations); - } - - public static void doClearRedisOAuth2AuthClientKeys( - ReactiveRedisOperations reactiveRedisOperations) { - final String authorizedClientsKey = - "sessionAttr:org.springframework.security.oauth2.client.web.server.WebSessionServerOAuth2AuthorizedClientRepository.AUTHORIZED_CLIENTS"; - final String script = - "for _,k in ipairs(redis.call('keys','spring:session:sessions:*')) do local fieldExists = redis.call('hexists', k, '" - + authorizedClientsKey + "'); if fieldExists == 1 then redis.call('del', k) end end"; - final Flux flushdb = reactiveRedisOperations.execute(RedisScript.of(script)); - - flushdb.blockLast(); + public void execute( + @Qualifier("reactiveRedisTemplate") final ReactiveRedisTemplate reactiveRedisTemplate) { + reactiveRedisTemplate + .getConnectionFactory() + .getReactiveConnection() + .serverCommands() + .flushDb() + .block(); } } From 28e54fe10d92b28c54092babcd7fad77ccb766d9 Mon Sep 17 00:00:00 2001 From: Apeksha Bhosale <7846888+ApekshaBhosale@users.noreply.github.com> Date: Mon, 7 Oct 2024 11:21:55 +0530 Subject: [PATCH 16/22] chore: span push and sentry logs (#36682) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description > [!TIP] > _Add a TL;DR when the description is longer than 500 words or extremely technical (helps the content, marketing, and DevRel team)._ > > _Please also include relevant motivation and context. List any dependencies that are required for this change. Add links to Notion, Figma or any other documents that might be relevant to the PR._ Fixes #`Issue Number` _or_ Fixes `Issue URL` > [!WARNING] > _If no issue exists, please create an issue first, and check with the maintainers if the issue is valid._ ## Automation /ok-to-test tags="@tag.All" ### :mag: Cypress test results > [!TIP] > 🟒 🟒 🟒 All cypress tests have passed! πŸŽ‰ πŸŽ‰ πŸŽ‰ > Workflow run: > Commit: c93c9dc7ad26a81f08ab99061e77c9a1b85bfc9e > Cypress dashboard. > Tags: `@tag.All` > Spec: >
Fri, 04 Oct 2024 16:45:18 UTC ## Communication Should the DevRel and Marketing teams inform users about this change? - [ ] Yes - [ ] No ## Summary by CodeRabbit ## Summary by CodeRabbit - **New Features** - Enhanced error tracking for user creation, login, and sign-up processes with Sentry integration. - Added new constants for authentication and authorization processes to improve logging and tracing. - **Bug Fixes** - Improved error handling for user sign-up failures. - **Documentation** - Updated tracing configuration to include additional criteria for Appsmith-specific spans, enhancing logging for login and signup activities. --- app/client/src/ce/sagas/userSagas.tsx | 9 ++++++++- app/client/src/pages/UserAuth/Login.tsx | 9 ++++++++- app/client/src/pages/UserAuth/SignUp.tsx | 8 ++++++++ .../com/appsmith/external/constants/spans/BaseSpan.java | 4 ++++ .../appsmith/server/configurations/TracingConfig.java | 8 ++++++-- 5 files changed, 34 insertions(+), 4 deletions(-) diff --git a/app/client/src/ce/sagas/userSagas.tsx b/app/client/src/ce/sagas/userSagas.tsx index cbf80d702d57..4e881be6fc5e 100644 --- a/app/client/src/ce/sagas/userSagas.tsx +++ b/app/client/src/ce/sagas/userSagas.tsx @@ -88,7 +88,8 @@ import type { } from "reducers/uiReducers/usersReducer"; import { selectFeatureFlags } from "ee/selectors/featureFlagsSelectors"; import { getFromServerWhenNoPrefetchedResult } from "sagas/helper"; - +import * as Sentry from "@sentry/react"; +import { Severity } from "@sentry/react"; export function* createUserSaga( action: ReduxActionWithPromise, ) { @@ -129,6 +130,12 @@ export function* createUserSaga( error, }, }); + Sentry.captureException("Sign up failed", { + level: Severity.Error, + extra: { + error: error, + }, + }); } } diff --git a/app/client/src/pages/UserAuth/Login.tsx b/app/client/src/pages/UserAuth/Login.tsx index 2dde2eff9ce4..76f59aa5a50e 100644 --- a/app/client/src/pages/UserAuth/Login.tsx +++ b/app/client/src/pages/UserAuth/Login.tsx @@ -51,7 +51,8 @@ import Helmet from "react-helmet"; import { useFeatureFlag } from "utils/hooks/useFeatureFlag"; import { FEATURE_FLAG } from "ee/entities/FeatureFlag"; import { getHTMLPageTitle } from "ee/utils/BusinessFeatures/brandingPageHelpers"; - +import * as Sentry from "@sentry/react"; +import { Severity } from "@sentry/react"; const validate = (values: LoginFormValues, props: ValidateProps) => { const errors: LoginFormValues = {}; const email = values[LOGIN_FORM_EMAIL_FIELD_NAME] || ""; @@ -113,6 +114,12 @@ export function Login(props: LoginFormProps) { if (queryParams.get("error")) { errorMessage = queryParams.get("message") || queryParams.get("error") || ""; showError = true; + Sentry.captureException("Login failed", { + level: Severity.Error, + extra: { + error: new Error(errorMessage), + }, + }); } let loginURL = "/api/v1/" + LOGIN_SUBMIT_PATH; diff --git a/app/client/src/pages/UserAuth/SignUp.tsx b/app/client/src/pages/UserAuth/SignUp.tsx index fccce68f5e1f..0d5db6e3eec5 100644 --- a/app/client/src/pages/UserAuth/SignUp.tsx +++ b/app/client/src/pages/UserAuth/SignUp.tsx @@ -57,6 +57,8 @@ import { FEATURE_FLAG } from "ee/entities/FeatureFlag"; import { getHTMLPageTitle } from "ee/utils/BusinessFeatures/brandingPageHelpers"; import log from "loglevel"; import { SELF_HOSTING_DOC } from "constants/ThirdPartyConstants"; +import * as Sentry from "@sentry/react"; +import { Severity } from "@sentry/react"; declare global { interface Window { @@ -133,6 +135,12 @@ export function SignUp(props: SignUpFormProps) { if (queryParams.get("error")) { errorMessage = queryParams.get("error") || ""; showError = true; + Sentry.captureException("Sign up failed", { + level: Severity.Error, + extra: { + error: new Error(errorMessage), + }, + }); } const signupURL = new URL( diff --git a/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/constants/spans/BaseSpan.java b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/constants/spans/BaseSpan.java index b654c4847947..d6612827ce58 100644 --- a/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/constants/spans/BaseSpan.java +++ b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/constants/spans/BaseSpan.java @@ -9,4 +9,8 @@ public class BaseSpan { public static final String GIT_SPAN_PREFIX = "git."; public static final String APPLICATION_SPAN_PREFIX = "application."; + + public static final String AUTHENTICATE = "authenticate"; + + public static final String AUTHORIZE = "authorize"; } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/TracingConfig.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/TracingConfig.java index a6cb5092d50d..fc22c4af4790 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/TracingConfig.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/TracingConfig.java @@ -10,6 +10,8 @@ import org.springframework.http.server.reactive.observation.ServerRequestObservationContext; import static com.appsmith.external.constants.spans.BaseSpan.APPSMITH_SPAN_PREFIX; +import static com.appsmith.external.constants.spans.BaseSpan.AUTHENTICATE; +import static com.appsmith.external.constants.spans.BaseSpan.AUTHORIZE; /** * This configuration file creates beans that are required to filter just Appsmith specific spans @@ -45,8 +47,10 @@ ObservationPredicate noActuatorServerObservations() { SpanExportingPredicate onlyAppsmithSpans() { return (finishedSpan) -> { if ((finishedSpan.getKind() != null && finishedSpan.getKind().equals(Span.Kind.SERVER)) - || finishedSpan.getName().startsWith(APPSMITH_SPAN_PREFIX)) { - // A span is either an http server request root or Appsmith specific + || finishedSpan.getName().startsWith(APPSMITH_SPAN_PREFIX) + || finishedSpan.getName().startsWith(AUTHENTICATE) + || finishedSpan.getName().startsWith(AUTHORIZE)) { + // A span is either an http server request root or Appsmith specific or login related or signup related return true; } else { return false; From 95010fd0f8ceac11c4a0c04121d0cde6208e5061 Mon Sep 17 00:00:00 2001 From: Diljit Date: Mon, 7 Oct 2024 13:59:29 +0530 Subject: [PATCH 17/22] fix: remove cache control headers for requests handled with an error in Caddy (#36590) --- deploy/docker/fs/opt/appsmith/caddy-reconfigure.mjs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/deploy/docker/fs/opt/appsmith/caddy-reconfigure.mjs b/deploy/docker/fs/opt/appsmith/caddy-reconfigure.mjs index 75d5e9296f95..b4cc80762aed 100644 --- a/deploy/docker/fs/opt/appsmith/caddy-reconfigure.mjs +++ b/deploy/docker/fs/opt/appsmith/caddy-reconfigure.mjs @@ -74,13 +74,13 @@ parts.push(` } # skip logs for health check - skip_log /api/v1/health + log_skip /api/v1/health # skip logs for sourcemap files @source-map-files { path_regexp ^.*\.(js|css)\.map$ } - skip_log @source-map-files + log_skip @source-map-files # The internal request ID header should never be accepted from an incoming request. request_header -X-Appsmith-Request-Id @@ -154,7 +154,12 @@ parts.push(` handle_errors { respond "{err.status_code} {err.status_text}" {err.status_code} - header -Server + header { + # Remove the Server header from the response. + -Server + # Remove Cache-Control header from the response. + -Cache-Control + } } } From 3ff67d31a65e504bc046a9dbed7b566e762b8ee5 Mon Sep 17 00:00:00 2001 From: Rahul Barwal Date: Mon, 7 Oct 2024 15:01:10 +0530 Subject: [PATCH 18/22] test: Update Inline_editing_3_spec.js to include expected JSON parsing (#36721) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description Root cause This spec was failing because it was string comparing the values, whereas the source was a JS Object. This sometimes caused spec to fail. Solution This pull request updates the `Inline_editing_3_spec.js` file to include the expected JSON parsing. The changes ensure that the correct JSON parsing is performed when editing a table cell and saving the changes. Fixes #36720 _or_ Fixes `Issue URL` > [!WARNING] > _If no issue exists, please create an issue first, and check with the maintainers if the issue is valid._ ## Automation /ok-to-test tags="@tag.Table" ### :mag: Cypress test results > [!TIP] > 🟒 🟒 🟒 All cypress tests have passed! πŸŽ‰ πŸŽ‰ πŸŽ‰ > Workflow run: > Commit: 0cf810ba36f9947f9aff6c85c6c8d64bc7f1dbf3 > Cypress dashboard. > Tags: `@tag.Table` > Spec: >
Mon, 07 Oct 2024 09:27:17 UTC ## Communication Should the DevRel and Marketing teams inform users about this change? - [ ] Yes - [x] No ## Summary by CodeRabbit - **Bug Fixes** - Improved validation for inline editing functionality in table widget tests. - Enhanced assertions for save/discard operations to ensure accuracy after changes. - Added checks for various column types in the `onsubmit` event tests. - **Tests** - Expanded end-to-end tests for inline editing, ensuring thorough validation across scenarios. - Incorporated additional checks for the display and retention of values during editing operations. --- .../Widgets/TableV2/Inline_editing_3_spec.js | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/Inline_editing_3_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/Inline_editing_3_spec.js index 40da3f138e35..5a27f59e1e0f 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/Inline_editing_3_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/Inline_editing_3_spec.js @@ -4,6 +4,7 @@ import { agHelper, table as tableHelper, propPane, + locators, } from "../../../../../support/Objects/ObjectsCore"; import { PROPERTY_SELECTOR } from "../../../../../locators/WidgetLocators"; @@ -148,10 +149,16 @@ describe( cy.editTableCell(0, 0); cy.enterTableCellValue(0, 0, "newValue"); cy.saveTableCellValue(0, 0); - cy.get(".t--widget-textwidget .bp3-ui-text").should( - "contain", - `[ { "index": 0, "updatedFields": { "step": "newValue" }, "allFields": { "step": "newValue", "task": "Drop a table", "status": "βœ…" } }]`, - ); + const exected = [ + { + index: 0, + updatedFields: { step: "newValue" }, + allFields: { step: "newValue", task: "Drop a table", status: "βœ…" }, + }, + ]; + agHelper + .GetText(locators._textWidget, "text") + .should((text) => expect(JSON.parse(text)).to.deep.equal(exected)); cy.openPropertyPane("textwidget"); cy.updateCodeInput( ".t--property-control-text", From 56e7f894023939d65dfb72af615196f465d30b29 Mon Sep 17 00:00:00 2001 From: Aman Agarwal Date: Mon, 7 Oct 2024 15:26:25 +0530 Subject: [PATCH 19/22] chore: removed old flags for airgap instances (#36609) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description Removed all the occurrences of listed flags in the codebase: 1. ab_ds_binding_enabled 2. ab_ds_schema_enabled 3. ab_gsheet_schema_enabled 4. ab_learnability_discoverability_collapse_all_except_data_enabled 5. ab_learnability_ease_of_initial_use_enabled 6. ab_mock_mongo_schema_enabled 7. ab_start_with_data_default_enabled 8. rollout_js_enabled_one_click_binding_enabled Fixes #36256 _or_ Fixes `Issue URL` > [!WARNING] > _If no issue exists, please create an issue first, and check with the maintainers if the issue is valid._ ## Automation /ok-to-test tags="@tag.All" ### :mag: Cypress test results > [!TIP] > 🟒 🟒 🟒 All cypress tests have passed! πŸŽ‰ πŸŽ‰ πŸŽ‰ > Workflow run: > Commit: bfbf6bbe77b963c5d257c29cf5bac35139417a07 > Cypress dashboard. > Tags: `@tag.All` > Spec: >
Fri, 04 Oct 2024 10:31:10 UTC ## Communication Should the DevRel and Marketing teams inform users about this change? - [ ] Yes - [ ] No ## Summary by CodeRabbit ## Summary by CodeRabbit - **New Features** - Enhanced test coverage for the Community Issues page, focusing on pagination, search, filtering, and issue management. - Improved functionality for adding new rows to table widgets, including visibility controls and state validations. - **Bug Fixes** - Resolved issues related to the visibility of UI elements when adding new rows and ensured accurate data reflection in the table. - **Tests** - Expanded tests for pagination, row selection, search functionality, and filtering logic in table widgets. - Added comprehensive assertions for client-side search and filtering scenarios, including checks for modal visibility during issue management. - **Chores** - Removed obsolete feature flags and streamlined logic for managing feature flags across components. --- .../Regression/Apps/CommunityIssues_Spec.ts | 13 +++++++++++++ .../PropertyPaneSlashCommand_spec.ts | 11 ----------- .../InputWidget_TableV2_Sorting_spec.js | 7 ++----- .../Binding/TableV2TextPagination_spec.js | 2 +- ...leV2Widget_selectedRow_Input_widget_spec.js | 1 + .../Binding/TableV2_ClientSide_Search_spec.js | 1 + .../TableV2_DefaultSearch_Input_spec.js | 1 + .../TableV2_Widget_API_Pagination_spec.js | 1 + .../ClientSide/Binding/TextTableV2_spec.js | 2 +- .../ClientSide/DynamicHeight/JsonForm_spec.ts | 2 +- .../JSEnabledByDefaultExperiment_spec.ts | 5 ----- .../Widgets/TableV2/AddNewRow1_spec.js | 9 +++++++++ .../Widgets/TableV2/Edge_case_spec.js | 2 +- .../Widgets/TableV2/TableV2Filter1_1_Spec.ts | 1 + .../Widgets/TableV2/TableV2Filter1_2_Spec.ts | 1 + .../Widgets/TableV2/TableV2Filter2_1_Spec.ts | 1 + .../Widgets/TableV2/TableV2Filter2_2_Spec.ts | 1 + .../TableV2/TableV2_DisplayText_spec.ts | 1 + .../TableV2/TableV2_MultiRowSelect_spec.js | 1 + .../TableV2/TableV2_PropertyPane_2_spec.js | 1 + .../ClientSide/Widgets/TableV2/TableV2_spec.js | 4 ++++ .../TableV2/columnTypes/checkboxCell_spec.js | 1 + .../TableV2/columnTypes/switchCell_spec.js | 1 + .../TableV2/server_side_filtering_spec_1.ts | 1 + .../cypress/support/Objects/FeatureFlags.ts | 1 - .../cypress/support/Pages/PropertyPane.ts | 16 ++++++++++++++++ app/client/cypress/support/e2e.js | 2 -- app/client/src/ce/entities/FeatureFlag.ts | 9 --------- .../CodeEditor/codeEditorUtils.ts | 9 --------- .../PartialExportModal/unitTestUtils.ts | 4 ---- .../useSource/useConnectToOptions.tsx | 15 +-------------- .../src/constants/WalkthroughConstants.ts | 2 -- .../Editor/DatasourceInfo/QueryTemplates.tsx | 18 +----------------- .../PropertyPane/PropertyControlsGenerator.tsx | 8 +------- .../MultiSelectWidgetV2/widget/index.tsx | 7 +------ .../src/widgets/SelectWidget/widget/index.tsx | 7 +------ .../src/widgets/TableWidgetV2/widget/index.tsx | 8 +------- 37 files changed, 68 insertions(+), 109 deletions(-) diff --git a/app/client/cypress/e2e/Regression/Apps/CommunityIssues_Spec.ts b/app/client/cypress/e2e/Regression/Apps/CommunityIssues_Spec.ts index 97f2d07f675d..4b178cfd0c02 100644 --- a/app/client/cypress/e2e/Regression/Apps/CommunityIssues_Spec.ts +++ b/app/client/cypress/e2e/Regression/Apps/CommunityIssues_Spec.ts @@ -74,8 +74,10 @@ describe( it("2. Validate table navigation with Server Side pagination enabled with Default selected row", () => { EditorNavigation.SelectEntityByName("Table1", EntityType.Widget); + propPane.ExpandIfCollapsedSection("pagination"); agHelper.AssertExistingToggleState("Server side pagination", "true"); + propPane.ExpandIfCollapsedSection("rowselection"); propPane .ValidatePropertyFieldValue("Default selected row", "0") .then(($selectedRow: any) => { @@ -114,6 +116,7 @@ describe( deployMode.NavigateBacktoEditor(); table.WaitUntilTableLoad(0, 0, "v2"); EditorNavigation.SelectEntityByName("Table1", EntityType.Widget); + propPane.ExpandIfCollapsedSection("pagination"); propPane.TogglePropertyState("Server side pagination", "Off"); deployMode.DeployApp(); table.WaitUntilTableLoad(0, 0, "v2"); @@ -122,10 +125,12 @@ describe( deployMode.NavigateBacktoEditor(); table.WaitUntilTableLoad(0, 0, "v2"); EditorNavigation.SelectEntityByName("Table1", EntityType.Widget); + propPane.ExpandIfCollapsedSection("pagination"); propPane.TogglePropertyState("Server side pagination", "On"); }); it("4. Change Default selected row in table and verify", () => { + propPane.ExpandIfCollapsedSection("rowselection"); propPane.UpdatePropertyFieldValue("Default selected row", "1"); deployMode.DeployApp(); table.WaitUntilTableLoad(0, 0, "v2"); @@ -140,6 +145,7 @@ describe( it("5. Verify Default search text in table as per 'Default search text' property set + Bug 12228", () => { EditorNavigation.SelectEntityByName("Table1", EntityType.Widget); + propPane.ExpandIfCollapsedSection("search\\&filters"); propPane.TypeTextIntoField("Default search text", "Bug"); deployMode.DeployApp(); table.AssertSearchText("Bug"); @@ -148,6 +154,7 @@ describe( deployMode.NavigateBacktoEditor(); EditorNavigation.SelectEntityByName("Table1", EntityType.Widget); + propPane.ExpandIfCollapsedSection("search\\&filters"); propPane.TypeTextIntoField("Default search text", "Quest", true, false); deployMode.DeployApp(); @@ -157,6 +164,7 @@ describe( table.WaitUntilTableLoad(0, 0, "v2"); EditorNavigation.SelectEntityByName("Table1", EntityType.Widget); + propPane.ExpandIfCollapsedSection("search\\&filters"); propPane.TypeTextIntoField("Default search text", "Epic"); //Bug 12228 - Searching based on hidden column value should not be allowed deployMode.DeployApp(); table.AssertSearchText("Epic"); @@ -164,6 +172,7 @@ describe( deployMode.NavigateBacktoEditor(); EditorNavigation.SelectEntityByName("Table1", EntityType.Widget); + propPane.ExpandIfCollapsedSection("search\\&filters"); propPane.RemoveText("defaultsearchtext"); agHelper.GetNClick(dataSources._refreshIcon, 0, true); table.WaitUntilTableLoad(0, 0, "v2"); @@ -171,6 +180,7 @@ describe( it("6. Validate Search table with Client Side Search enabled & disabled & onSearchTextChanged is set", () => { EditorNavigation.SelectEntityByName("Table1", EntityType.Widget); + propPane.ExpandIfCollapsedSection("search\\&filters"); agHelper.AssertExistingToggleState("Client side search", "true"); deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.TABLE)); @@ -188,6 +198,7 @@ describe( table.WaitUntilTableLoad(0, 1, "v2"); EditorNavigation.SelectEntityByName("Table1", EntityType.Widget); + propPane.ExpandIfCollapsedSection("search\\&filters"); propPane.TogglePropertyState("Client side search", "Off"); deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.TABLE)); @@ -205,6 +216,7 @@ describe( deployMode.NavigateBacktoEditor(); table.WaitUntilTableLoad(0, 1, "v2"); EditorNavigation.SelectEntityByName("Table1", EntityType.Widget); + propPane.ExpandIfCollapsedSection("search\\&filters"); propPane.TogglePropertyState("Client side search", "On"); propPane.EnterJSContext("onSearchTextChanged", ""); propPane.ToggleJSMode("onSearchTextChanged", false); @@ -224,6 +236,7 @@ describe( deployMode.NavigateBacktoEditor(); table.WaitUntilTableLoad(0, 1, "v2"); EditorNavigation.SelectEntityByName("Table1", EntityType.Widget); + propPane.ExpandIfCollapsedSection("search\\&filters"); propPane.TogglePropertyState("Client side search", "Off"); deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.TABLE)); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Autocomplete/PropertyPaneSlashCommand_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Autocomplete/PropertyPaneSlashCommand_spec.ts index 31f4b1c7feb1..4271fef029d3 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Autocomplete/PropertyPaneSlashCommand_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Autocomplete/PropertyPaneSlashCommand_spec.ts @@ -1,12 +1,7 @@ -import { featureFlagIntercept } from "../../../../support/Objects/FeatureFlags"; import { agHelper, locators, - entityExplorer, propPane, - draggableWidgets, - apiPage, - entityItems, homePage, assertHelper, } from "../../../../support/Objects/ObjectsCore"; @@ -15,12 +10,6 @@ import EditorNavigation, { } from "../../../../support/Pages/EditorNavigation"; describe("Property Pane Suggestions", { tags: ["@tag.JS"] }, () => { - before(() => { - featureFlagIntercept({ - ab_learnability_ease_of_initial_use_enabled: true, - }); - }); - before(function () { agHelper.ClearLocalStorageCache(); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Binding/InputWidget_TableV2_Sorting_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Binding/InputWidget_TableV2_Sorting_spec.js index ba5b040609b1..7fad7eb5d0f8 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Binding/InputWidget_TableV2_Sorting_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Binding/InputWidget_TableV2_Sorting_spec.js @@ -4,10 +4,7 @@ import EditorNavigation, { const publish = require("../../../../locators/publishWidgetspage.json"); const testdata = require("../../../../fixtures/testdata.json"); -import { - agHelper, - entityExplorer, -} from "../../../../support/Objects/ObjectsCore"; +import { agHelper, propPane } from "../../../../support/Objects/ObjectsCore"; describe( "Binding the Table and input Widget", @@ -32,7 +29,7 @@ describe( it("2. validation of data displayed in input widgets based on sorting", function () { EditorNavigation.SelectEntityByName("Table1", EntityType.Widget); - + propPane.ExpandIfCollapsedSection("rowselection"); cy.testJsontext("defaultselectedrow", "0"); cy.get(".draggable-header").contains("id").click({ force: true }); cy.wait(1000); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Binding/TableV2TextPagination_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Binding/TableV2TextPagination_spec.js index d8d0a262ff30..490e40de6f97 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Binding/TableV2TextPagination_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Binding/TableV2TextPagination_spec.js @@ -6,7 +6,6 @@ const commonlocators = require("../../../../locators/commonlocators.json"); const testdata = require("../../../../fixtures/testdata.json"); import apiPageLocators from "../../../../locators/ApiEditor"; import { - entityExplorer, apiPage, deployMode, propPane, @@ -91,6 +90,7 @@ describe( it("3. Table-Text, Validate Server Side Pagination of Paginate with Total v2 Records Count", function () { deployMode.NavigateBacktoEditor(); EditorNavigation.SelectEntityByName("Table1", EntityType.Widget); + propPane.ExpandIfCollapsedSection("pagination"); propPane.UpdatePropertyFieldValue("Total Records", "20"); deployMode.DeployApp(); cy.wait("@postExecute"); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Binding/TableV2Widget_selectedRow_Input_widget_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Binding/TableV2Widget_selectedRow_Input_widget_spec.js index 5bec54443d47..6ba248fe1a63 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Binding/TableV2Widget_selectedRow_Input_widget_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Binding/TableV2Widget_selectedRow_Input_widget_spec.js @@ -30,6 +30,7 @@ describe( it("2. validation of data displayed in input widgets based on selected row", function () { EditorNavigation.SelectEntityByName("Table1", EntityType.Widget); + _.propPane.ExpandIfCollapsedSection("rowselection"); cy.testJsontext("defaultselectedrow", "2"); cy.readTableV2dataPublish("2", "0").then((tabData) => { const tabValue = tabData; diff --git a/app/client/cypress/e2e/Regression/ClientSide/Binding/TableV2_ClientSide_Search_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Binding/TableV2_ClientSide_Search_spec.js index e3b110fbc9d6..322323850394 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Binding/TableV2_ClientSide_Search_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Binding/TableV2_ClientSide_Search_spec.js @@ -20,6 +20,7 @@ describe( cy.readTableV2dataPublish("0", "0").then((tabData) => { expect(tabData).to.eq("#2"); }); + _.propPane.ExpandIfCollapsedSection("search\\&filters"); // Input onsearchtextchanged control cy.get(".t--property-control-onsearchtextchanged .t--js-toggle") .first() diff --git a/app/client/cypress/e2e/Regression/ClientSide/Binding/TableV2_DefaultSearch_Input_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Binding/TableV2_DefaultSearch_Input_spec.js index 457593fec0f3..c21342e793f0 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Binding/TableV2_DefaultSearch_Input_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Binding/TableV2_DefaultSearch_Input_spec.js @@ -27,6 +27,7 @@ describe( ); // validation of data displayed in input widgets based on search value set EditorNavigation.SelectEntityByName("Table1", EntityType.Widget); + _.propPane.ExpandIfCollapsedSection("search\\&filters"); cy.get(".t--property-control-allowsearching input").click({ force: true, }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Binding/TableV2_Widget_API_Pagination_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Binding/TableV2_Widget_API_Pagination_spec.js index 03a7d1e93afe..ef31811f782f 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Binding/TableV2_Widget_API_Pagination_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Binding/TableV2_Widget_API_Pagination_spec.js @@ -30,6 +30,7 @@ describe( //Validate Table V2 with API data and then add a column EditorNavigation.SelectEntityByName("Table1", EntityType.Widget); propPane.UpdatePropertyFieldValue("Table data", "{{Api1.data}}"); + propPane.ExpandIfCollapsedSection("pagination"); cy.CheckWidgetProperties(commonlocators.serverSidePaginationCheckbox); cy.get(`.t--widget-tablewidgetv2 .page-item`) .first() diff --git a/app/client/cypress/e2e/Regression/ClientSide/Binding/TextTableV2_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Binding/TextTableV2_spec.js index e30b11a03156..b42f2840c89e 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Binding/TextTableV2_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Binding/TextTableV2_spec.js @@ -5,7 +5,6 @@ import EditorNavigation, { const commonlocators = require("../../../../locators/commonlocators.json"); const publish = require("../../../../locators/publishWidgetspage.json"); import { - entityExplorer, agHelper, deployMode, propPane, @@ -113,6 +112,7 @@ describe( EditorNavigation.SelectEntityByName("Table1", EntityType.Widget, {}, [ "Container3", ]); + propPane.ExpandIfCollapsedSection("rowselection"); cy.testJsontext("defaultselectedrow", "2"); cy.wait("@updateLayout"); cy.get(commonlocators.TableV2Row) diff --git a/app/client/cypress/e2e/Regression/ClientSide/DynamicHeight/JsonForm_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/DynamicHeight/JsonForm_spec.ts index 6ecade613423..c20df368d0e2 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/DynamicHeight/JsonForm_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/DynamicHeight/JsonForm_spec.ts @@ -1,5 +1,4 @@ import { - entityExplorer, locators, agHelper, propPane, @@ -17,6 +16,7 @@ describe( agHelper.AddDsl("jsonFormDynamicHeightDsl"); EditorNavigation.SelectEntityByName("JSONForm1", EntityType.Widget); + propPane.ExpandIfCollapsedSection("general"); agHelper .GetWidgetCSSHeight( locators._widgetInDeployed(draggableWidgets.JSONFORM), diff --git a/app/client/cypress/e2e/Regression/ClientSide/OneClickBinding/JSEnabledByDefaultExperiment_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/OneClickBinding/JSEnabledByDefaultExperiment_spec.ts index b1da841ffe3d..45a89965b271 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/OneClickBinding/JSEnabledByDefaultExperiment_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/OneClickBinding/JSEnabledByDefaultExperiment_spec.ts @@ -1,5 +1,4 @@ import OneClickBindingLocator from "../../../../locators/OneClickBindingLocator"; -import { featureFlagIntercept } from "../../../../support/Objects/FeatureFlags"; import { agHelper, apiPage, @@ -23,10 +22,6 @@ describe( () => { let datasourceName: string; before(() => { - featureFlagIntercept({ - rollout_js_enabled_one_click_binding_enabled: true, - }); - dataSources.CreateDataSource("Postgres"); cy.get("@dsName").then((dsName) => { diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/AddNewRow1_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/AddNewRow1_spec.js index d3e05b789db0..6d641951891a 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/AddNewRow1_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/AddNewRow1_spec.js @@ -3,6 +3,9 @@ import { propPane, table, } from "../../../../../support/Objects/ObjectsCore"; +import EditorNavigation, { + EntityType, +} from "../../../../../support/Pages/EditorNavigation"; const commonlocators = require("../../../../../locators/commonlocators.json"); describe( @@ -16,6 +19,7 @@ describe( it("1.1. should test that allow Add new row property is present", () => { cy.openPropertyPane("tablewidgetv2"); + propPane.ExpandIfCollapsedSection("addingarow"); cy.get(".t--property-control-allowaddingarow").should("exist"); cy.get(".t--property-control-allowaddingarow input").should("exist"); cy.get(".t--add-new-row").should("not.exist"); @@ -150,7 +154,12 @@ describe( it("1.7. should not hide the header section when add new row button is enabled and another header element is disabled", () => { cy.get(".t--discard-new-row").click({ force: true }); + EditorNavigation.SelectEntityByName("Table1", EntityType.Widget); //disable all header widgets for the table + propPane.ExpandIfCollapsedSection("general"); + propPane.ExpandIfCollapsedSection("addingarow"); + propPane.ExpandIfCollapsedSection("search\\&filters"); + propPane.ExpandIfCollapsedSection("pagination"); [ "Show pagination", "Allow searching", diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/Edge_case_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/Edge_case_spec.js index 7a5d288e3b4c..5431495adc5c 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/Edge_case_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/Edge_case_spec.js @@ -6,7 +6,6 @@ const widgetsPage = require("../../../../../locators/Widgets.json"); const commonlocators = require("../../../../../locators/commonlocators.json"); import { agHelper, - entityExplorer, propPane, table, } from "../../../../../support/Objects/ObjectsCore"; @@ -26,6 +25,7 @@ describe( it("1. Check if the selectedRowIndices does not contain 2d array", function () { EditorNavigation.SelectEntityByName("Table1", EntityType.Widget); + propPane.ExpandIfCollapsedSection("rowselection"); propPane.TogglePropertyState("Enable multi-row selection", "On"); //Enable Multi row select propPane.UpdatePropertyFieldValue("Default selected rows", "[1]"); //Change the value of default selected row diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2Filter1_1_Spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2Filter1_1_Spec.ts index 142401c067c9..72c7b2939666 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2Filter1_1_Spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2Filter1_1_Spec.ts @@ -22,6 +22,7 @@ describe( entityExplorer.DragDropWidgetNVerify("tablewidgetv2", 650, 250); //propPane.EnterJSContext("Table data", JSON.stringify(this.dataSet.TableInput)); // turn on filtering for the table - it is disabled by default in this PR(#34593) + propPane.ExpandIfCollapsedSection("search\\&filters"); agHelper.GetNClick(".t--property-control-allowfiltering input"); table.AddSampleTableData(); //propPane.EnterJSContext("Table Data", JSON.stringify(this.dataSet.TableInput)); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2Filter1_2_Spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2Filter1_2_Spec.ts index c9a9ea98b721..91360c4cd24a 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2Filter1_2_Spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2Filter1_2_Spec.ts @@ -16,6 +16,7 @@ describe( it("1. Verify Table Filter for 'empty'", function () { entityExplorer.DragDropWidgetNVerify("tablewidgetv2", 650, 250); // turn on filtering for the table - it is disabled by default in this PR(#34593) + propPane.ExpandIfCollapsedSection("search\\&filters"); agHelper.GetNClick(".t--property-control-allowfiltering input"); table.AddSampleTableData(); propPane.UpdatePropertyFieldValue( diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2Filter2_1_Spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2Filter2_1_Spec.ts index 1c733733fd7e..552bdc4b1e50 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2Filter2_1_Spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2Filter2_1_Spec.ts @@ -17,6 +17,7 @@ describe( entityExplorer.DragDropWidgetNVerify("tablewidgetv2", 650, 250); //propPane.EnterJSContext("Table data", JSON.stringify(this.dataSet.TableInput)); // turn on filtering for the table - it is disabled by default in this PR(#34593) + propPane.ExpandIfCollapsedSection("search\\&filters"); agHelper.GetNClick(".t--property-control-allowfiltering input"); table.AddSampleTableData(); //propPane.EnterJSContext("Table Data", JSON.stringify(this.dataSet.TableInput)); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2Filter2_2_Spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2Filter2_2_Spec.ts index c431157de632..76bef07b7b0d 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2Filter2_2_Spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2Filter2_2_Spec.ts @@ -17,6 +17,7 @@ describe( it("1. Verify Full table data - download csv and download Excel", function () { entityExplorer.DragDropWidgetNVerify("tablewidgetv2", 650, 250); // turn on filtering for the table - it is disabled by default in this PR(#34593) + propPane.ExpandIfCollapsedSection("search\\&filters"); agHelper.GetNClick(".t--property-control-allowfiltering input"); table.AddSampleTableData(); propPane.UpdatePropertyFieldValue( diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_DisplayText_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_DisplayText_spec.ts index 4bd11a80cd2e..a62b58935c71 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_DisplayText_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_DisplayText_spec.ts @@ -28,6 +28,7 @@ describe( before(() => { entityExplorer.DragDropWidgetNVerify("tablewidgetv2", 650, 250); // turn on filtering for the table - it is disabled by default in this PR(#34593) + propPane.ExpandIfCollapsedSection("search\\&filters"); agHelper.GetNClick(".t--property-control-allowfiltering input"); propPane.EnterJSContext("Table data", JSON.stringify(data)); assertHelper.AssertNetworkStatus("@updateLayout"); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_MultiRowSelect_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_MultiRowSelect_spec.js index a0ae9da141d5..bf59c5bb5ba0 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_MultiRowSelect_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_MultiRowSelect_spec.js @@ -12,6 +12,7 @@ describe( it("1. Test multi select column shows when enable Multirowselection is true", function () { cy.openPropertyPane("tablewidgetv2"); + _.propPane.ExpandIfCollapsedSection("rowselection"); cy.get(widgetsPage.toggleEnableMultirowselection) .first() .click({ force: true }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_PropertyPane_2_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_PropertyPane_2_spec.js index 0c73fae21be2..13694c0c9e40 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_PropertyPane_2_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_PropertyPane_2_spec.js @@ -62,6 +62,7 @@ describe( cy.moveToContentTab(); // Chage deat search text value to "data" cy.backFromPropertyPanel(); + propPane.ExpandIfCollapsedSection("search\\&filters"); cy.testJsontext("defaultsearchtext", "data"); deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.TABLE)); table.WaitForTableEmpty("v2"); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_spec.js index 3e58e093fa52..afe576f7b451 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_spec.js @@ -53,6 +53,8 @@ describe( cy.get(commonlocators.editPropBackButton).click(); cy.openPropertyPane("tablewidgetv2"); // Confirm if isSortable is true + _.propPane.ExpandIfCollapsedSection("sorting"); + cy.get(commonlocators.isSortable).should("be.checked"); // Publish App _.deployMode.DeployApp(); @@ -124,6 +126,7 @@ describe( "Table data", `{{[{step: 1, task: 1}]}}`, ); + _.propPane.ExpandIfCollapsedSection("search\\&filters"); cy.get(".t--property-control-allowfiltering input").click(); cy.editColumn("step"); cy.get(".t--table-filter-toggle-btn").click(); @@ -237,6 +240,7 @@ describe( it("7. should check that adding cyclic dependency in the table doesn't crash the app", () => { //_.deployMode.NavigateBacktoEditor(); cy.openPropertyPane("tablewidgetv2"); + _.propPane.ExpandIfCollapsedSection("rowselection"); cy.updateCodeInput( ".t--property-control-defaultselectedrow", diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/columnTypes/checkboxCell_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/columnTypes/checkboxCell_spec.js index 252617d0ab5a..1a1b9e6aa83b 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/columnTypes/checkboxCell_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/columnTypes/checkboxCell_spec.js @@ -35,6 +35,7 @@ describe( before(() => { _.entityExplorer.DragDropWidgetNVerify(_.draggableWidgets.TABLE); // turn on filtering for the table - it is disabled by default in this PR(#34593) + _.propPane.ExpandIfCollapsedSection("search\\&filters"); _.agHelper.GetNClick(".t--property-control-allowfiltering input"); _.propPane.EnterJSContext("Table data", tableData); cy.editColumn("completed"); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/columnTypes/switchCell_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/columnTypes/switchCell_spec.js index 56a0f6cf12e9..bec3425f26c2 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/columnTypes/switchCell_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/columnTypes/switchCell_spec.js @@ -41,6 +41,7 @@ describe( before(() => { entityExplorer.DragDropWidgetNVerify(draggableWidgets.TABLE); // turn on filtering for the table - it is disabled by default in this PR(#34593) + propPane.ExpandIfCollapsedSection("search\\&filters"); agHelper.GetNClick(".t--property-control-allowfiltering input"); propPane.EnterJSContext("Table data", tableData); cy.editColumn("completed"); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/server_side_filtering_spec_1.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/server_side_filtering_spec_1.ts index 674f56e06e32..1d4f6fad6166 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/server_side_filtering_spec_1.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/server_side_filtering_spec_1.ts @@ -35,6 +35,7 @@ describe( entityExplorer.DragDropWidgetNVerify(draggableWidgets.TABLE, 300, 300); // turn on filtering for the table - it is disabled by default in this PR(#34593) + propPane.ExpandIfCollapsedSection("search\\&filters"); agHelper.GetNClick(".t--property-control-allowfiltering input"); // Create SQL data-source diff --git a/app/client/cypress/support/Objects/FeatureFlags.ts b/app/client/cypress/support/Objects/FeatureFlags.ts index c7f4b58bdf65..7fdc78d1d580 100644 --- a/app/client/cypress/support/Objects/FeatureFlags.ts +++ b/app/client/cypress/support/Objects/FeatureFlags.ts @@ -4,7 +4,6 @@ import produce from "immer"; const defaultFlags = { release_side_by_side_ide_enabled: true, - ab_learnability_discoverability_collapse_all_except_data_enabled: false, // remove this flag from here when it's removed from code rollout_remove_feature_walkthrough_enabled: false, // remove this flag from here when it's removed from code }; diff --git a/app/client/cypress/support/Pages/PropertyPane.ts b/app/client/cypress/support/Pages/PropertyPane.ts index daf36e185d6d..f826f788d267 100644 --- a/app/client/cypress/support/Pages/PropertyPane.ts +++ b/app/client/cypress/support/Pages/PropertyPane.ts @@ -686,4 +686,20 @@ export class PropertyPane { .GetElement(this._propertyToggle(propertyName)) .should(state === "enabled" ? "be.checked" : "not.be.checked"); } + + public ExpandIfCollapsedSection(sectionName: string) { + cy.get(`.t--property-pane-section-collapse-${sectionName}`) + .scrollIntoView() + .then(($element) => { + cy.wrap($element) + .siblings(".bp3-collapse") + .then(($sibling) => { + const siblingHeight = $sibling.height(); // Get the height of the sibling element + + if (!siblingHeight) { + $element.click(); + } + }); + }); + } } diff --git a/app/client/cypress/support/e2e.js b/app/client/cypress/support/e2e.js index 166329ed8e0c..a27600f20a20 100644 --- a/app/client/cypress/support/e2e.js +++ b/app/client/cypress/support/e2e.js @@ -141,8 +141,6 @@ before(function () { if (!Cypress.currentTest.titlePath[0].includes(WALKTHROUGH_TEST_PAGE)) { // Adding key FEATURE_WALKTHROUGH (which is used to check if the walkthrough is already shown to the user or not) for non walkthrough cypress tests (to not show walkthrough) addIndexedDBKey(FEATURE_WALKTHROUGH_INDEX_KEY, { - ab_ds_binding_enabled: true, - ab_ds_schema_enabled: true, binding_widget: true, }); } diff --git a/app/client/src/ce/entities/FeatureFlag.ts b/app/client/src/ce/entities/FeatureFlag.ts index 63d49c89f77f..311a1b2037e5 100644 --- a/app/client/src/ce/entities/FeatureFlag.ts +++ b/app/client/src/ce/entities/FeatureFlag.ts @@ -34,13 +34,7 @@ export const FEATURE_FLAG = { "release_drag_drop_building_blocks_enabled", release_table_cell_label_value_enabled: "release_table_cell_label_value_enabled", - rollout_js_enabled_one_click_binding_enabled: - "rollout_js_enabled_one_click_binding_enabled", rollout_side_by_side_enabled: "rollout_side_by_side_enabled", - ab_learnability_ease_of_initial_use_enabled: - "ab_learnability_ease_of_initial_use_enabled", - ab_learnability_discoverability_collapse_all_except_data_enabled: - "ab_learnability_discoverability_collapse_all_except_data_enabled", release_layout_conversion_enabled: "release_layout_conversion_enabled", release_anvil_toggle_enabled: "release_anvil_toggle_enabled", release_ide_animations_enabled: "release_ide_animations_enabled", @@ -74,10 +68,7 @@ export const DEFAULT_FEATURE_FLAG_VALUE: FeatureFlags = { ab_appsmith_ai_query: false, release_actions_redesign_enabled: false, rollout_remove_feature_walkthrough_enabled: true, - rollout_js_enabled_one_click_binding_enabled: true, rollout_side_by_side_enabled: false, - ab_learnability_ease_of_initial_use_enabled: true, - ab_learnability_discoverability_collapse_all_except_data_enabled: true, release_layout_conversion_enabled: false, release_anvil_toggle_enabled: false, release_ide_animations_enabled: false, diff --git a/app/client/src/components/editorComponents/CodeEditor/codeEditorUtils.ts b/app/client/src/components/editorComponents/CodeEditor/codeEditorUtils.ts index 4df9bd20fdee..8f9ff477825a 100644 --- a/app/client/src/components/editorComponents/CodeEditor/codeEditorUtils.ts +++ b/app/client/src/components/editorComponents/CodeEditor/codeEditorUtils.ts @@ -4,9 +4,6 @@ import type { WidgetEntity, ActionEntity } from "ee/entities/DataTree/types"; import { trim } from "lodash"; import { getDynamicStringSegments } from "utils/DynamicBindingUtils"; import { EditorSize } from "./EditorConfig"; -import { selectFeatureFlagCheck } from "ee/selectors/featureFlagsSelectors"; -import store from "store"; -import { FEATURE_FLAG } from "ee/entities/FeatureFlag"; import { SlashCommandMenuOnFocusWidgetProps } from "./constants"; // TODO: Fix this the next time the file is edited @@ -168,13 +165,7 @@ export function shouldShowSlashCommandMenu( widgetType: string = "", propertyPath: string = "", ) { - const isEaseOfUseFlagEnabled = selectFeatureFlagCheck( - store.getState(), - FEATURE_FLAG.ab_learnability_ease_of_initial_use_enabled, - ); - return ( - !!isEaseOfUseFlagEnabled && !!SlashCommandMenuOnFocusWidgetProps[widgetType] && SlashCommandMenuOnFocusWidgetProps[widgetType].includes(propertyPath) ); diff --git a/app/client/src/components/editorComponents/PartialImportExport/PartialExportModal/unitTestUtils.ts b/app/client/src/components/editorComponents/PartialImportExport/PartialExportModal/unitTestUtils.ts index a43305d93bd5..84def36f6bf9 100644 --- a/app/client/src/components/editorComponents/PartialImportExport/PartialExportModal/unitTestUtils.ts +++ b/app/client/src/components/editorComponents/PartialImportExport/PartialExportModal/unitTestUtils.ts @@ -12757,12 +12757,10 @@ export const defaultAppState = { release_datasource_environments_enabled: false, release_appnavigationlogoupload_enabled: false, release_embed_hide_share_settings_enabled: false, - ab_gsheet_schema_enabled: true, release_table_serverside_filtering_enabled: false, license_branding_enabled: false, license_sso_saml_enabled: false, license_sso_oidc_enabled: false, - ab_mock_mongo_schema_enabled: true, license_private_embeds_enabled: false, release_show_publish_app_to_community_enabled: false, license_gac_enabled: false, @@ -12776,7 +12774,6 @@ export const defaultAppState = { release_side_by_side_ide_enabled: false, release_global_add_pane_enabled: false, license_git_unlimited_repo_enabled: false, - ab_ds_binding_enabled: true, ask_ai_js: false, license_connection_pool_size_enabled: false, ab_ai_js_function_completion_enabled: true, @@ -12786,7 +12783,6 @@ export const defaultAppState = { license_audit_logs_enabled: false, ask_ai_sql: false, release_query_module_enabled: false, - ab_ds_schema_enabled: true, ab_onboarding_flow_start_with_data_dev_only_enabled: false, license_session_limit_enabled: false, rollout_datasource_test_rate_limit_enabled: false, diff --git a/app/client/src/components/editorComponents/WidgetQueryGeneratorForm/CommonControls/DatasourceDropdown/useSource/useConnectToOptions.tsx b/app/client/src/components/editorComponents/WidgetQueryGeneratorForm/CommonControls/DatasourceDropdown/useSource/useConnectToOptions.tsx index 01460af48a52..9b6385402092 100644 --- a/app/client/src/components/editorComponents/WidgetQueryGeneratorForm/CommonControls/DatasourceDropdown/useSource/useConnectToOptions.tsx +++ b/app/client/src/components/editorComponents/WidgetQueryGeneratorForm/CommonControls/DatasourceDropdown/useSource/useConnectToOptions.tsx @@ -22,9 +22,6 @@ import type { ModuleInstanceData, ModuleInstanceDataState, } from "ee/constants/ModuleInstanceConstants"; -import { selectFeatureFlagCheck } from "ee/selectors/featureFlagsSelectors"; -import { FEATURE_FLAG } from "ee/entities/FeatureFlag"; -import type { AppState } from "ee/reducers"; import type { Module } from "ee/constants/ModuleConstants"; import { getAllModules } from "ee/selectors/modulesSelector"; import { getModuleIcon } from "pages/Editor/utils"; @@ -168,13 +165,6 @@ function useConnectToOptions(props: ConnectToOptionsProps) { const queries = useSelector(getCurrentActions); const pluginsPackageNamesMap = useSelector(getPluginIdPackageNamesMap); - const isJSEnabledByDefaultOnForOneClickBinding = useSelector( - (state: AppState) => - selectFeatureFlagCheck( - state, - FEATURE_FLAG.rollout_js_enabled_one_click_binding_enabled, - ), - ); const { pluginImages, widget } = props; @@ -203,10 +193,7 @@ function useConnectToOptions(props: ConnectToOptionsProps) { value: getBindingValue(widget, query), icon: getQueryIcon(query, pluginImages, modules), onSelect: function (value?: string, valueOption?: DropdownOptionType) { - addBinding( - valueOption?.value, - !!isJSEnabledByDefaultOnForOneClickBinding, - ); + addBinding(valueOption?.value, true); updateConfig({ datasource: "", diff --git a/app/client/src/constants/WalkthroughConstants.ts b/app/client/src/constants/WalkthroughConstants.ts index 9c6460392412..7adfdc3645cc 100644 --- a/app/client/src/constants/WalkthroughConstants.ts +++ b/app/client/src/constants/WalkthroughConstants.ts @@ -1,6 +1,4 @@ export const FEATURE_WALKTHROUGH_KEYS = { - ds_binding: "ab_ds_binding_enabled", - ds_schema: "ab_ds_schema_enabled", binding_widget: "binding_widget", env_walkthrough: "ab_env_walkthrough_enabled", // Signposting keys diff --git a/app/client/src/pages/Editor/DatasourceInfo/QueryTemplates.tsx b/app/client/src/pages/Editor/DatasourceInfo/QueryTemplates.tsx index 71c1ad6c1e79..f28e38b74f2d 100644 --- a/app/client/src/pages/Editor/DatasourceInfo/QueryTemplates.tsx +++ b/app/client/src/pages/Editor/DatasourceInfo/QueryTemplates.tsx @@ -1,4 +1,4 @@ -import React, { useCallback, useContext } from "react"; +import React, { useCallback } from "react"; import { useDispatch, useSelector } from "react-redux"; import { createActionRequest } from "actions/pluginActionActions"; import type { AppState } from "ee/reducers"; @@ -21,15 +21,12 @@ import { integrationEditorURL } from "ee/RouteBuilder"; import { MenuItem, Tag } from "@appsmith/ads"; import type { Plugin } from "api/PluginApi"; -import WalkthroughContext from "components/featureWalkthrough/walkthroughContext"; -import { setFeatureWalkthroughShown } from "utils/storage"; import styled from "styled-components"; import { change, getFormValues } from "redux-form"; import { QUERY_EDITOR_FORM_NAME } from "ee/constants/forms"; import { diff } from "deep-diff"; import { UndoRedoToastContext, showUndoRedoToast } from "utils/replayHelpers"; import AnalyticsUtil from "ee/utils/AnalyticsUtil"; -import { FEATURE_WALKTHROUGH_KEYS } from "constants/WalkthroughConstants"; import { SUGGESTED_TAG, createMessage } from "ee/constants/messages"; import { transformTextToSentenceCase } from "pages/Editor/utils"; @@ -59,8 +56,6 @@ const TemplateMenuItem = styled(MenuItem)` export function QueryTemplates(props: QueryTemplatesProps) { const dispatch = useDispatch(); - const { isOpened: isWalkthroughOpened, popFeature } = - useContext(WalkthroughContext) || {}; const applicationId = useSelector(getCurrentApplicationId); const actions = useSelector((state: AppState) => state.entities.actions); const basePageId = useSelector(getCurrentBasePageId); @@ -109,11 +104,6 @@ export function QueryTemplates(props: QueryTemplatesProps) { }), ); - if (isWalkthroughOpened) { - popFeature && popFeature("SCHEMA_QUERY_CREATE"); - setFeatureWalkthroughShown(FEATURE_WALKTHROUGH_KEYS.ds_schema, true); - } - history.push( integrationEditorURL({ basePageId, @@ -166,14 +156,8 @@ export function QueryTemplates(props: QueryTemplatesProps) { datasourceId: props.datasourceId, pluginName: plugin?.name || "", templateCommand: template?.title, - isWalkthroughOpened, }); - if (isWalkthroughOpened) { - popFeature && popFeature("SCHEMA_QUERY_UPDATE"); - setFeatureWalkthroughShown(FEATURE_WALKTHROUGH_KEYS.ds_schema, true); - } - showUndoRedoToast( currentAction.name, false, diff --git a/app/client/src/pages/Editor/PropertyPane/PropertyControlsGenerator.tsx b/app/client/src/pages/Editor/PropertyPane/PropertyControlsGenerator.tsx index 6e5a7c02be46..fa7450d33a2e 100644 --- a/app/client/src/pages/Editor/PropertyPane/PropertyControlsGenerator.tsx +++ b/app/client/src/pages/Editor/PropertyPane/PropertyControlsGenerator.tsx @@ -17,8 +17,6 @@ import { evaluateHiddenProperty } from "./helpers"; import type { EnhancementFns } from "selectors/widgetEnhancementSelectors"; import { getWidgetEnhancementSelector } from "selectors/widgetEnhancementSelectors"; import equal from "fast-deep-equal/es6"; -import { FEATURE_FLAG } from "ee/entities/FeatureFlag"; -import { useFeatureFlag } from "utils/hooks/useFeatureFlag"; export interface PropertyControlsGeneratorProps { id: string; @@ -106,10 +104,6 @@ function PropertyControlsGenerator(props: PropertyControlsGeneratorProps) { // eslint-disable-next-line @typescript-eslint/no-explicit-any const widgetProps: any = useSelector(getWidgetPropsForPropertyPane); - const isCollapseAllExceptDataEnabled: boolean = useFeatureFlag( - FEATURE_FLAG.ab_learnability_discoverability_collapse_all_except_data_enabled, - ); - const enhancementSelector = getWidgetEnhancementSelector( widgetProps?.widgetId, ); @@ -140,7 +134,7 @@ function PropertyControlsGenerator(props: PropertyControlsGeneratorProps) { props, isSearchResult, enhancements, - isCollapseAllExceptDataEnabled, + true, )} ); diff --git a/app/client/src/widgets/MultiSelectWidgetV2/widget/index.tsx b/app/client/src/widgets/MultiSelectWidgetV2/widget/index.tsx index 829ad1700e51..e604d111beaf 100644 --- a/app/client/src/widgets/MultiSelectWidgetV2/widget/index.tsx +++ b/app/client/src/widgets/MultiSelectWidgetV2/widget/index.tsx @@ -180,12 +180,7 @@ class MultiSelectWidget extends BaseWidget< onFilterUpdate: queryConfig.select.run, }; - if ( - !!MultiSelectWidget.getFeatureFlag( - FEATURE_FLAG.rollout_js_enabled_one_click_binding_enabled, - ) - ) - dynamicPropertyPathList.push({ key: "sourceData" }); + dynamicPropertyPathList.push({ key: "sourceData" }); } return { diff --git a/app/client/src/widgets/SelectWidget/widget/index.tsx b/app/client/src/widgets/SelectWidget/widget/index.tsx index e98e78ed2c50..8bf1cf42ef96 100644 --- a/app/client/src/widgets/SelectWidget/widget/index.tsx +++ b/app/client/src/widgets/SelectWidget/widget/index.tsx @@ -162,12 +162,7 @@ class SelectWidget extends BaseWidget { onFilterUpdate: queryConfig.select.run, }; - if ( - !!SelectWidget.getFeatureFlag( - FEATURE_FLAG.rollout_js_enabled_one_click_binding_enabled, - ) - ) - dynamicPropertyPathList.push({ key: "sourceData" }); + dynamicPropertyPathList.push({ key: "sourceData" }); } return { diff --git a/app/client/src/widgets/TableWidgetV2/widget/index.tsx b/app/client/src/widgets/TableWidgetV2/widget/index.tsx index 046366812074..b83902333947 100644 --- a/app/client/src/widgets/TableWidgetV2/widget/index.tsx +++ b/app/client/src/widgets/TableWidgetV2/widget/index.tsx @@ -138,7 +138,6 @@ import { } from "layoutSystems/common/utils/constants"; import IconSVG from "../icon.svg"; import ThumbnailSVG from "../thumbnail.svg"; -import { FEATURE_FLAG } from "ee/entities/FeatureFlag"; import { klonaRegularWithTelemetry } from "utils/helpers"; const ReactTableComponent = lazy(async () => @@ -275,12 +274,7 @@ class TableWidgetV2 extends BaseWidget { isVisibleDownload: false, }); - if ( - !!TableWidgetV2.getFeatureFlag( - FEATURE_FLAG.rollout_js_enabled_one_click_binding_enabled, - ) - ) - dynamicPropertyPathList.push({ key: "tableData" }); + dynamicPropertyPathList.push({ key: "tableData" }); } if (queryConfig.create) { From 8e9b843644055a8f87fca5cc76d9ceb61d17f1e9 Mon Sep 17 00:00:00 2001 From: NandanAnantharamu <67676905+NandanAnantharamu@users.noreply.github.com> Date: Mon, 7 Oct 2024 16:00:43 +0530 Subject: [PATCH 20/22] test: udpated files by removing un-used APIs (#36705) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Removed APIs that are not in use /ok-to-test tags="@tag.All" > [!TIP] > 🟒 🟒 🟒 All cypress tests have passed! πŸŽ‰ πŸŽ‰ πŸŽ‰ > Workflow run: > Commit: ce672b5ff1f3976034fd91b1c1ffe7eb9efbf925 > Cypress dashboard. > Tags: `@tag.All` > Spec: >
Fri, 04 Oct 2024 13:50:12 UTC ## Summary by CodeRabbit - **New Features** - Updated the authenticated API URL for improved connectivity. - **Bug Fixes** - Removed outdated properties (`restapi_url` and `connection_type`) from environment configurations to streamline the data model. Co-authored-by: β€œNandanAnantharamu” <β€œnandan@thinkify.io”> --- app/client/cypress/fixtures/datasources.json | 2 +- app/client/cypress/support/Objects/DataManager.ts | 10 ++-------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/app/client/cypress/fixtures/datasources.json b/app/client/cypress/fixtures/datasources.json index e9a76ef161d0..040f7503a697 100644 --- a/app/client/cypress/fixtures/datasources.json +++ b/app/client/cypress/fixtures/datasources.json @@ -83,7 +83,7 @@ "mockDatabaseUsername": "fakeapi", "mockDatabasePassword": "LimitedAccess123#", "readonly": "readonly", - "authenticatedApiUrl": "https://fakeapi.com", + "authenticatedApiUrl": "http://host.docker.internal:5001", "GraphqlApiUrl_TED": "http://host.docker.internal:4200/graphql", "GITEA_API_BASE_TED": "localhost", diff --git a/app/client/cypress/support/Objects/DataManager.ts b/app/client/cypress/support/Objects/DataManager.ts index a54e1162eb30..c4a27a021fb2 100644 --- a/app/client/cypress/support/Objects/DataManager.ts +++ b/app/client/cypress/support/Objects/DataManager.ts @@ -97,15 +97,12 @@ export class DataManager { firestore_projectID: "appsmith-22e8b", firestore_serviceaccountkey: Cypress.env("FIRESTORE_PRIVATE_KEY"), - restapi_url: "https://my-json-server.typicode.com/typicode/demo/posts", - connection_type: "Replica set", - mockHostAddress: "fake_api.cvuydmurdlas.us-east-1.rds.amazonaws.com", mockDatabaseName: "fakeapi", mockDatabaseUsername: "fakeapi", mockDatabasePassword: "LimitedAccess123#", readonly: "readonly", - authenticatedApiUrl: "https://fakeapi.com", + authenticatedApiUrl: "http://host.docker.internal:5001", GraphqlApiUrl_TED: "http://host.docker.internal:4200/graphql", @@ -192,15 +189,12 @@ export class DataManager { firestore_projectID: "appsmith-dummy", firestore_serviceaccountkey: "dummy_service_creds_key", - restapi_url: "https://my-json-server.typicode.com/typicode/demo/posts", - connection_type: "Replica set", - mockHostAddress: "fake_api.cvuydmurdlas.us-east-1.rds.amazonaws.com", mockDatabaseName: "fakeapi", mockDatabaseUsername: "fakeapi", mockDatabasePassword: "LimitedAccess123#", readonly: "readonly", - authenticatedApiUrl: "https://fakeapi.com", + authenticatedApiUrl: "http://host.docker.internal:5001", GraphqlApiUrl_TED: "http://host.docker.internal:4200/graphql", From d49ec24c08940f2c3001fd00aa5650607c9a7a16 Mon Sep 17 00:00:00 2001 From: Anagh Hegde Date: Mon, 7 Oct 2024 16:23:09 +0530 Subject: [PATCH 21/22] chore: create pg_trm extension for the GIN index creation (#36722) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description Due to the size limit on the BTree index we are creating GIN index for a permission group. To support this we need to create a pg_trm extension. ## Automation /ok-to-test tags="@tag.Sanity" ### :mag: Cypress test results > [!TIP] > 🟒 🟒 🟒 All cypress tests have passed! πŸŽ‰ πŸŽ‰ πŸŽ‰ > Workflow run: > Commit: d62be8f46ad45b1190bf5c014c0a8ea0c50cf284 > Cypress dashboard. > Tags: `@tag.Sanity` > Spec: >
Mon, 07 Oct 2024 10:46:39 UTC ## Communication Should the DevRel and Marketing teams inform users about this change? - [ ] Yes - [ ] No ## Summary by CodeRabbit - **New Features** - Enhanced database initialization by adding the creation of the `pg_trgm` extension for PostgreSQL, improving text search capabilities. - **Bug Fixes** - Ensured the extension is created only if it does not already exist, preventing unnecessary errors during setup. --- deploy/docker/fs/opt/appsmith/pg-utils.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/deploy/docker/fs/opt/appsmith/pg-utils.sh b/deploy/docker/fs/opt/appsmith/pg-utils.sh index 1c9626551117..175deb9a174e 100755 --- a/deploy/docker/fs/opt/appsmith/pg-utils.sh +++ b/deploy/docker/fs/opt/appsmith/pg-utils.sh @@ -127,11 +127,16 @@ init_pg_db() { echo "Schema 'appsmith' does not exist. Creating schema..." psql -h "$PG_DB_HOST" -p "$PG_DB_PORT" -U postgres -d "$PG_DB_NAME" -c "CREATE SCHEMA appsmith;" fi - USER=$PG_DB_USER SCHEMA="appsmith" DB=$PG_DB_NAME HOST=$PG_DB_HOST PORT=$PG_DB_PORT grant_permissions_for_schema + + echo "Creating pg_trgm extension..." + psql -h "$PG_DB_HOST" -p "$PG_DB_PORT" -U postgres -d "$PG_DB_NAME" -c "CREATE EXTENSION IF NOT EXISTS pg_trgm;" else echo "Remote PostgreSQL detected, running as current user." PGPASSWORD=$PG_DB_PASSWORD psql -h "$PG_DB_HOST" -p "$PG_DB_PORT" -U "$PG_DB_USER" -d "$PG_DB_NAME" -c "CREATE SCHEMA IF NOT EXISTS appsmith;" + + echo "Creating pg_trgm extension..." + psql -h "$PG_DB_HOST" -p "$PG_DB_PORT" -U "$PG_DB_USER" -d "$PG_DB_NAME" -c "CREATE EXTENSION IF NOT EXISTS pg_trgm;" fi # Check if the schema creation was successful From d15eea3e1ed5cf2b3c0b9314248cf4318e9a66c5 Mon Sep 17 00:00:00 2001 From: Rahul Barwal Date: Mon, 7 Oct 2024 17:22:02 +0530 Subject: [PATCH 22/22] fix: widget icon in Connect To options in oneclick binding menu (#36703) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description This pull request fixes the issue with the widget icon not displaying correctly in the Connect To options. The `useConnectToOptions` function now correctly retrieves the widget config for the current widget and uses the `iconSVG` property from the config to display the widget icon. Fixes #`Issue Number` _or_ Fixes https://github.com/appsmithorg/appsmith/issues/36353 > [!WARNING] > _If no issue exists, please create an issue first, and check with the maintainers if the issue is valid._ ## Automation /ok-to-test tags="@tag.All" ### :mag: Cypress test results > [!TIP] > 🟒 🟒 🟒 All cypress tests have passed! πŸŽ‰ πŸŽ‰ πŸŽ‰ > Workflow run: > Commit: 80a63553ab8f1d77695d3261095a90acdb4b5a4d > Cypress dashboard. > Tags: `@tag.All` > Spec: >
Mon, 07 Oct 2024 09:25:24 UTC ## Communication Should the DevRel and Marketing teams inform users about this change? - [ ] Yes - [x] No ## Summary by CodeRabbit - **New Features** - Enhanced datasource selection validation by ensuring images associated with queried items are present and valid. - Improved icon retrieval for connectable widgets in the dropdown, allowing for more accurate icon displays based on widget types. - **Bug Fixes** - Fixed icon rendering issues in dropdown options to ensure the correct icons are displayed. --------- Co-authored-by: Jacques Ikot --- .../ClientSide/OneClickBinding/spec_utility.ts | 17 ++++++++++++++++- .../useSource/useConnectToOptions.tsx | 5 ++++- .../OtherFields/Field/Dropdown/useDropdown.tsx | 5 ++++- 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/app/client/cypress/e2e/Regression/ClientSide/OneClickBinding/spec_utility.ts b/app/client/cypress/e2e/Regression/ClientSide/OneClickBinding/spec_utility.ts index 91b52c0d116c..ba218d46f170 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/OneClickBinding/spec_utility.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/OneClickBinding/spec_utility.ts @@ -12,7 +12,22 @@ export class OneClickBinding { column: Record = {}, ) { agHelper.GetNClick(oneClickBindingLocator.datasourceDropdownSelector); - + agHelper.GetElement("[role='menu']").then(($menu) => { + if ( + $menu.find(oneClickBindingLocator.datasourceQuerySelector()).length > 0 + ) { + cy.wrap($menu) + .find(oneClickBindingLocator.datasourceQuerySelector()) + .should("have.length.greaterThan", 0) + .each(($item) => { + cy.wrap($item) + .find("img") + .should(($img) => { + expect($img).to.have.attr("src").and.not.be.empty; + }); + }); + } + }); expandLoadMoreOptions(); agHelper.AssertElementAbsence(oneClickBindingLocator.connectData); diff --git a/app/client/src/components/editorComponents/WidgetQueryGeneratorForm/CommonControls/DatasourceDropdown/useSource/useConnectToOptions.tsx b/app/client/src/components/editorComponents/WidgetQueryGeneratorForm/CommonControls/DatasourceDropdown/useSource/useConnectToOptions.tsx index 9b6385402092..ceedd1fda2b5 100644 --- a/app/client/src/components/editorComponents/WidgetQueryGeneratorForm/CommonControls/DatasourceDropdown/useSource/useConnectToOptions.tsx +++ b/app/client/src/components/editorComponents/WidgetQueryGeneratorForm/CommonControls/DatasourceDropdown/useSource/useConnectToOptions.tsx @@ -227,6 +227,9 @@ function useConnectToOptions(props: ConnectToOptionsProps) { // This is the path we bind to the sourceData field Ex: `{{Table1.selectedRow}}` const { widgetBindPath } = getOneClickBindingConnectableWidgetConfig(currWidget); + const iconSVG = + WidgetFactory.getConfig(currWidget.type)?.iconSVG || + currWidget.iconSVG; return { id: widgetId, @@ -237,7 +240,7 @@ function useConnectToOptions(props: ConnectToOptionsProps) { ), diff --git a/app/client/src/components/editorComponents/WidgetQueryGeneratorForm/WidgetSpecificControls/OtherFields/Field/Dropdown/useDropdown.tsx b/app/client/src/components/editorComponents/WidgetQueryGeneratorForm/WidgetSpecificControls/OtherFields/Field/Dropdown/useDropdown.tsx index efac989bf96f..e5143135f270 100644 --- a/app/client/src/components/editorComponents/WidgetQueryGeneratorForm/WidgetSpecificControls/OtherFields/Field/Dropdown/useDropdown.tsx +++ b/app/client/src/components/editorComponents/WidgetQueryGeneratorForm/WidgetSpecificControls/OtherFields/Field/Dropdown/useDropdown.tsx @@ -81,12 +81,15 @@ export function useDropdown(props: OneClickDropdownFieldProps) { if (getOneClickBindingConnectableWidgetConfig) { const { message, widgetBindPath } = getOneClickBindingConnectableWidgetConfig(currWidget); + const iconSVG = + WidgetFactory.getConfig(currWidget.type)?.iconSVG || + currWidget.iconSVG; return { id: currWidgetId, value: widgetBindPath, label: currWidget.widgetName, - icon: , + icon: , data: { widgetType: currWidget.type, widgetName: currWidget.widgetName,