diff --git a/.editorconfig b/.editorconfig index 18d3ed3cc28..690c003b3e6 100644 --- a/.editorconfig +++ b/.editorconfig @@ -9,5 +9,5 @@ indent_size = 2 insert_final_newline = true trim_trailing_whitespace = true -[{*.java,pom.xml,*.py}] +[{*.java,pom.xml,*.py,*.sql}] indent_size = 4 diff --git a/.github/workflows/build-docker-image.yml b/.github/workflows/build-docker-image.yml index 7dbab8525fb..012bad87a22 100644 --- a/.github/workflows/build-docker-image.yml +++ b/.github/workflows/build-docker-image.yml @@ -9,11 +9,6 @@ on: description: "This is the PR number in case the workflow is being called in a pull request" required: false type: number - is-pg-build: - description: "This is a boolean value in case the workflow is being called for a PG build" - required: false - type: string - default: "false" jobs: build-docker: @@ -79,6 +74,12 @@ jobs: if [[ -f scripts/generate_info_json.sh ]]; then scripts/generate_info_json.sh fi + + - name: Place server artifacts-es + env: + EDITION: ${{ vars.EDITION }} + run: | + scripts/prepare_server_artifacts.sh - name: Set base image tag id: set_base_tag diff --git a/.github/workflows/pr-cypress.yml b/.github/workflows/pr-cypress.yml index f3fba4a9820..b64c4c6cf19 100644 --- a/.github/workflows/pr-cypress.yml +++ b/.github/workflows/pr-cypress.yml @@ -62,7 +62,6 @@ jobs: secrets: inherit with: pr: ${{ github.event.number }} - is-pg-build: ${{ inputs.is-pg-build }} ci-test: needs: [build-docker-image] diff --git a/.github/workflows/test-build-docker-image.yml b/.github/workflows/test-build-docker-image.yml index 9384df2101e..71fe51a5cb8 100644 --- a/.github/workflows/test-build-docker-image.yml +++ b/.github/workflows/test-build-docker-image.yml @@ -23,7 +23,7 @@ on: # trigger for pushes to master and pg push: - branches: [master, pg] + branches: [master] paths: - "app/client/**" - "app/server/**" @@ -59,6 +59,18 @@ jobs: echo "matrix=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59]" >> $GITHUB_OUTPUT fi + invoke-tbp-workflow-for-pg: + needs: [setup] + if: github.event_name != 'push' && github.ref == 'refs/heads/release' + runs-on: ubuntu-latest + steps: + - name: Trigger TBP on pg branch + uses: benc-uk/workflow-dispatch@v1 + with: + workflow: test-build-docker-image.yml + inputs: '{ "tags": "${{needs.setup.outputs.tags}}", "ted_tag": "${{inputs.ted_tag}}" }' + ref: refs/heads/pg + server-build: needs: [setup] if: success() @@ -100,7 +112,7 @@ jobs: ci-test: needs: [setup, build-docker-image] # Only run if the build step is successful - if: success() && ( github.event_name != 'push' || github.ref == 'refs/heads/master' || github.ref == 'refs/heads/pg' ) + if: success() && ( github.event_name != 'push' || github.ref == 'refs/heads/master') name: ci-test uses: ./.github/workflows/ci-test-custom-script.yml secrets: inherit @@ -113,17 +125,18 @@ jobs: server-unit-tests: name: server-unit-tests needs: [build-docker-image] - if: success() && ( github.event_name != 'push' || github.ref == 'refs/heads/master' || github.ref == 'refs/heads/pg' ) + if: success() && ( github.event_name != 'push' || github.ref == 'refs/heads/master') uses: ./.github/workflows/server-build.yml secrets: inherit with: pr: 0 skip-tests: false + is-pg-build: ${{ github.ref == 'refs/heads/pg' }} client-unit-tests: name: client-unit-tests needs: [build-docker-image] - if: success() && ( github.event_name != 'push' || github.ref == 'refs/heads/master' || github.ref == 'refs/heads/pg' ) + if: success() && ( github.event_name != 'push' || github.ref == 'refs/heads/master') uses: ./.github/workflows/client-unit-tests.yml secrets: inherit with: diff --git a/.gitignore b/.gitignore index 2015eb221fc..8d9bcfba452 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,9 @@ stacks /deploy/docker/fs/opt/appsmith/info.json +# Server artifacts +/deploy/docker/fs/opt/appsmith/server + # to ignore the node_modeules folder node_modules # to ignore the package-lock.json file @@ -36,3 +39,5 @@ app/client/.fleet/* # Observability related local storage utils/observability/tempo-data/* +# Ignore the mongo data backup directory for Mongo to PG migrations +mongo-data** \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 51c91bc5427..a9d4b233719 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,10 +3,6 @@ FROM ${BASE} ENV IN_DOCKER=1 -# Add backend server - Application Layer -ARG JAR_FILE=./app/server/dist/server-*.jar -ARG PLUGIN_JARS=./app/server/dist/plugins/*.jar - ARG APPSMITH_CLOUD_SERVICES_BASE_URL ENV APPSMITH_CLOUD_SERVICES_BASE_URL=${APPSMITH_CLOUD_SERVICES_BASE_URL} @@ -16,7 +12,17 @@ ENV APPSMITH_SEGMENT_CE_KEY=${APPSMITH_SEGMENT_CE_KEY} COPY deploy/docker/fs / RUN <&2 + exit 1 + fi + + if ! [ -f server/mongo/server.jar && -f server/pg/server.jar ]; then + echo "Missing one or both server.jar files in the right place. Are you using the build script?" >&2 + exit 1 + fi + + mkdir -p ./editor ./rts # Ensure all *.sh scripts are executable. find . -name node_modules -prune -or -type f -name '*.sh' -print -exec chmod +x '{}' ';' @@ -25,10 +31,6 @@ RUN < { - agHelper.AddDsl("mongoAppdsl"); - dataSources.CreateDataSource("Mongo"); - cy.get("@saveDatasource").then((httpResponse: any) => { - datasourceName = httpResponse.response.body.data.name; + before(() => { + agHelper.AddDsl("mongoAppdsl"); + dataSources.CreateDataSource("Mongo"); + cy.get("@saveDatasource").then((httpResponse: any) => { + datasourceName = httpResponse.response.body.data.name; + }); }); - }); - it("1. Create MongoDB datasource and add Insert, Find, Update and Delete queries", function () { - dataSources.CreateQueryAfterDSSaved("", "GetProduct"); - dataSources.EnterJSContext({ - fieldLabel: "Collection", - fieldValue: "Productnames", - }); - // GetProduct query to fetch all products - agHelper.AssertAutoSave(); - // EditProducts query to update the cart - dataSources.CreateQueryFromOverlay(datasourceName, "", "EditProducts"); - dataSources.ValidateNSelectDropdown( - "Command", - "Find document(s)", - "Update document(s)", - ); - dataSources.EnterJSContext({ - fieldLabel: "Collection", - fieldValue: "Productnames", - }); - agHelper.EnterValue('{"title": "{{Table1.selectedRow.title}}"}', { - propFieldName: "", - directInput: false, - inputFieldName: "Query", - }); - agHelper.EnterValue( - `{"title" : "{{title.text}}", + it("1. Create MongoDB datasource and add Insert, Find, Update and Delete queries", function () { + dataSources.CreateQueryAfterDSSaved("", "GetProduct"); + dataSources.EnterJSContext({ + fieldLabel: "Collection", + fieldValue: "Productnames", + }); + // GetProduct query to fetch all products + agHelper.AssertAutoSave(); + // EditProducts query to update the cart + dataSources.CreateQueryFromOverlay(datasourceName, "", "EditProducts"); + dataSources.ValidateNSelectDropdown( + "Command", + "Find document(s)", + "Update document(s)", + ); + dataSources.EnterJSContext({ + fieldLabel: "Collection", + fieldValue: "Productnames", + }); + agHelper.EnterValue('{"title": "{{Table1.selectedRow.title}}"}', { + propFieldName: "", + directInput: false, + inputFieldName: "Query", + }); + agHelper.EnterValue( + `{"title" : "{{title.text}}", "description" :"{{description.text}}", "price" : {{price.text}}, "quantity":{{quantity.text}}}`, - { + { + propFieldName: "", + directInput: false, + inputFieldName: "Update", + }, + ); + + agHelper.AssertAutoSave(); + + // AddProducts query to add to cart + dataSources.CreateQueryFromOverlay(datasourceName, "", "AddProduct"); + dataSources.ValidateNSelectDropdown( + "Command", + "Find document(s)", + "Insert document(s)", + ); + dataSources.EnterJSContext({ + fieldLabel: "Collection", + fieldValue: "Productnames", + }); + const documentText = [ + { + title: "{{Title.text}}", + description: "{{Description.text}}", + price: "{{Price.text}}", + quantity: "{{Quantity.text}}", + }, + ]; + agHelper.EnterValue(JSON.stringify(documentText), { propFieldName: "", directInput: false, - inputFieldName: "Update", - }, - ); - - agHelper.AssertAutoSave(); + inputFieldName: "Documents", + }); - // AddProducts query to add to cart - dataSources.CreateQueryFromOverlay(datasourceName, "", "AddProduct"); - dataSources.ValidateNSelectDropdown( - "Command", - "Find document(s)", - "Insert document(s)", - ); - dataSources.EnterJSContext({ - fieldLabel: "Collection", - fieldValue: "Productnames", - }); - const documentText = [ - { - title: "{{Title.text}}", - description: "{{Description.text}}", - price: "{{Price.text}}", - quantity: "{{Quantity.text}}", - }, - ]; - agHelper.EnterValue(JSON.stringify(documentText), { - propFieldName: "", - directInput: false, - inputFieldName: "Documents", - }); + agHelper.AssertAutoSave(); - agHelper.AssertAutoSave(); + // Delete product + dataSources.CreateQueryFromOverlay(datasourceName, "", "DeleteProduct"); + dataSources.ValidateNSelectDropdown( + "Command", + "Find document(s)", + "Delete document(s)", + ); + dataSources.EnterJSContext({ + fieldLabel: "Collection", + fieldValue: "Productnames", + }); + agHelper.EnterValue('{"title":"{{Table1.selectedRow.title}}"}', { + propFieldName: "", + directInput: false, + inputFieldName: "Query", + }); - // Delete product - dataSources.CreateQueryFromOverlay(datasourceName, "", "DeleteProduct"); - dataSources.ValidateNSelectDropdown( - "Command", - "Find document(s)", - "Delete document(s)", - ); - dataSources.EnterJSContext({ - fieldLabel: "Collection", - fieldValue: "Productnames", + agHelper.AssertAutoSave(); + deployMode.DeployApp(appPage.bookname); }); - agHelper.EnterValue('{"title":"{{Table1.selectedRow.title}}"}', { - propFieldName: "", - directInput: false, - inputFieldName: "Query", - }); - - agHelper.AssertAutoSave(); - deployMode.DeployApp(appPage.bookname); - }); - it("2. Perform CRUD operations and validate data", function () { - // Adding the books to the Add cart form - agHelper.GetNClick(appPage.bookname); - //Wait for element to be in DOM - agHelper.AssertElementLength(appPage.inputValues, 9); - agHelper.ClearNType( - appPage.bookname + "//" + locators._inputField, - "Atomic habits", - 0, - true, - ); - agHelper.ClearNType( - appPage.bookgenre + "//" + locators._inputField, - "Self help", - 0, - true, - ); - agHelper.ClearNType( - appPage.bookprice + "//" + locators._inputField, - "200", - 0, - true, - ); - agHelper.ClearNType( - appPage.bookquantity + "//" + locators._inputField, - "2", - 0, - true, - ); - agHelper.GetNClick(appPage.addButton, 0, true); - assertHelper.AssertNetworkStatus("@postExecute"); - agHelper.GetNClick(appPage.bookname); - agHelper.ClearNType( - appPage.bookname + "//" + locators._inputField, - "A man called ove", - 0, - true, - ); - agHelper.ClearNType( - appPage.bookgenre + "//" + locators._inputField, - "Fiction", - 0, - true, - ); - agHelper.ClearNType( - appPage.bookprice + "//" + locators._inputField, - "100", - 0, - true, - ); - agHelper.ClearNType( - appPage.bookquantity + "//" + locators._inputField, - "1", - 0, - true, - ); - agHelper.GetNClick(appPage.addButton, 0, true); - assertHelper.AssertNetworkStatus("@postExecute"); - // Select the table row & Deleting the book from the cart - table.SelectTableRow(1); - agHelper.GetNClick(appPage.deleteButton, 1, false); - assertHelper.AssertNetworkStatus("@postExecute"); - assertHelper.AssertNetworkStatus("@postExecute"); + it("2. Perform CRUD operations and validate data", function () { + // Adding the books to the Add cart form + agHelper.GetNClick(appPage.bookname); + //Wait for element to be in DOM + agHelper.AssertElementLength(appPage.inputValues, 9); + agHelper.ClearNType( + appPage.bookname + "//" + locators._inputField, + "Atomic habits", + 0, + true, + ); + agHelper.ClearNType( + appPage.bookgenre + "//" + locators._inputField, + "Self help", + 0, + true, + ); + agHelper.ClearNType( + appPage.bookprice + "//" + locators._inputField, + "200", + 0, + true, + ); + agHelper.ClearNType( + appPage.bookquantity + "//" + locators._inputField, + "2", + 0, + true, + ); + agHelper.GetNClick(appPage.addButton, 0, true); + assertHelper.AssertNetworkStatus("@postExecute"); + agHelper.GetNClick(appPage.bookname); + agHelper.ClearNType( + appPage.bookname + "//" + locators._inputField, + "A man called ove", + 0, + true, + ); + agHelper.ClearNType( + appPage.bookgenre + "//" + locators._inputField, + "Fiction", + 0, + true, + ); + agHelper.ClearNType( + appPage.bookprice + "//" + locators._inputField, + "100", + 0, + true, + ); + agHelper.ClearNType( + appPage.bookquantity + "//" + locators._inputField, + "1", + 0, + true, + ); + agHelper.GetNClick(appPage.addButton, 0, true); + assertHelper.AssertNetworkStatus("@postExecute"); + // Select the table row & Deleting the book from the cart + table.SelectTableRow(1); + agHelper.GetNClick(appPage.deleteButton, 1, false); + assertHelper.AssertNetworkStatus("@postExecute"); + assertHelper.AssertNetworkStatus("@postExecute"); - // validating that the book is deleted - agHelper.AssertElementLength(appPage.deleteButton + "/parent::div", 1); - // Updating the book quantity from edit cart - agHelper.ClearNType( - appPage.editbookquantity + "//" + locators._inputField, - "3", - 0, - true, - ); - agHelper.GetNClick(appPage.editButton, 0, true); + // validating that the book is deleted + agHelper.AssertElementLength(appPage.deleteButton + "/parent::div", 1); + // Updating the book quantity from edit cart + agHelper.ClearNType( + appPage.editbookquantity + "//" + locators._inputField, + "3", + 0, + true, + ); + agHelper.GetNClick(appPage.editButton, 0, true); - //Wait for all post execute calls to finish - assertHelper.AssertNetworkExecutionSuccess("@postExecute"); - // validating updated value in the cart - agHelper - .GetElement(dataSources._selectedRow) - .children() - .eq(3) - .should("have.text", "3"); - }); + //Wait for all post execute calls to finish + assertHelper.AssertNetworkExecutionSuccess("@postExecute"); + // validating updated value in the cart + agHelper + .GetElement(dataSources._selectedRow) + .children() + .eq(3) + .should("have.text", "3"); + }); - it("3. Connect the application to git and validate data in deploy mode and edit mode", function () { - deployMode.NavigateBacktoEditor(); - gitSync.CreateNConnectToGit(repoName); - cy.get("@gitRepoName").then((repName) => { - repoName = repName; + it("3. Connect the application to git and validate data in deploy mode and edit mode", function () { + deployMode.NavigateBacktoEditor(); + gitSync.CreateNConnectToGit(repoName); + cy.get("@gitRepoName").then((repName) => { + repoName = repName; + }); + cy.latestDeployPreview(); + agHelper + .GetElement(dataSources._selectedRow) + .children() + .eq(0) + .should("have.text", "A man called ove"); + deployMode.NavigateBacktoEditor(); + agHelper + .GetElement(dataSources._selectedRow) + .children() + .eq(0) + .should("have.text", "A man called ove"); }); - cy.latestDeployPreview(); - agHelper - .GetElement(dataSources._selectedRow) - .children() - .eq(0) - .should("have.text", "A man called ove"); - deployMode.NavigateBacktoEditor(); - agHelper - .GetElement(dataSources._selectedRow) - .children() - .eq(0) - .should("have.text", "A man called ove"); - }); - after(() => { - //clean up - gitSync.DeleteTestGithubRepo(repoName); - }); -}); + after(() => { + //clean up + gitSync.DeleteTestGithubRepo(repoName); + }); + }, +); diff --git a/app/client/cypress/e2e/Regression/ClientSide/ActionExecution/NavigateTo_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/ActionExecution/NavigateTo_spec.ts index 443512bbd98..827cb3f9614 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/ActionExecution/NavigateTo_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/ActionExecution/NavigateTo_spec.ts @@ -13,7 +13,7 @@ import EditorNavigation, { } from "../../../../support/Pages/EditorNavigation"; import PageList from "../../../../support/Pages/PageList"; -describe("Navigate To feature", { tags: ["@tag.JS"] }, () => { +describe("Navigate To feature", { tags: ["@tag.JS", "@tag.Sanity"] }, () => { it("1. Navigates to page name clicked from the page name tab of navigate to", () => { EditorNavigation.SelectEntityByName("Page1", EntityType.Page); entityExplorer.DragDropWidgetNVerify(draggableWidgets.TEXT, 500, 600); diff --git a/app/client/cypress/e2e/Regression/ClientSide/ActionExecution/PostWindowMessage_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/ActionExecution/PostWindowMessage_spec.ts index 8b074f21c39..87ee86ff315 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/ActionExecution/PostWindowMessage_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/ActionExecution/PostWindowMessage_spec.ts @@ -10,7 +10,7 @@ import EditorNavigation, { EntityType, } from "../../../../support/Pages/EditorNavigation"; -describe("Post window message", { tags: ["@tag.JS"] }, () => { +describe("Post window message", { tags: ["@tag.JS", "@tag.Sanity"] }, () => { it("1. Posts message to an iframe within Appsmith", () => { entityExplorer.DragDropWidgetNVerify(draggableWidgets.BUTTON, 200, 200); entityExplorer.DragDropWidgetNVerify(draggableWidgets.IFRAME, 200, 300); diff --git a/app/client/cypress/e2e/Regression/ClientSide/ActionExecution/StoreValue_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/ActionExecution/StoreValue_spec.ts index e13c374025a..683fcc7bd66 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/ActionExecution/StoreValue_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/ActionExecution/StoreValue_spec.ts @@ -14,7 +14,7 @@ import EditorNavigation, { PagePaneSegment, } from "../../../../support/Pages/EditorNavigation"; -describe("storeValue Action test", { tags: ["@tag.JS"] }, () => { +describe("storeValue Action test", { tags: ["@tag.JS", "@tag.Sanity"] }, () => { before(() => { entityExplorer.DragDropWidgetNVerify("buttonwidget", 100, 100); PageLeftPane.switchSegment(PagePaneSegment.JS); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Anvil/AnvilModal_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Anvil/AnvilModal_spec.ts index c253987eb48..84b5d5e3b91 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Anvil/AnvilModal_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Anvil/AnvilModal_spec.ts @@ -134,7 +134,8 @@ describe( anvilLocators.anvilWidgetNameSelector("Button2"), ); }); - it("8. Verify different modal sizes", () => { + // TODO: Enable when issue(github.com/appsmithorg/appsmith/issues/36419) is solved. + it.skip("8. Verify different modal sizes", () => { // select all widgets and delete agHelper.PressEscape(); agHelper.SelectAllWidgets(); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Anvil/AppTheming/AnvilAppThemingSnapshot_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Anvil/AppTheming/AnvilAppThemingSnapshot_spec.ts index 6f2bb3ff6e6..5b9bad823b3 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Anvil/AppTheming/AnvilAppThemingSnapshot_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Anvil/AppTheming/AnvilAppThemingSnapshot_spec.ts @@ -4,7 +4,8 @@ import { anvilSnapshot, } from "../../../../../support/Objects/ObjectsCore"; -describe( +// TODO: Enable when issue(github.com/appsmithorg/appsmith/issues/36419) is solved. +describe.skip( `${ANVIL_EDITOR_TEST}: Anvil tests for App Theming`, { tags: ["@tag.Anvil"] }, () => { diff --git a/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilButtonWidgetSnapshot_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilButtonWidgetSnapshot_spec.ts index 210fdf47b57..a78e7ef5d47 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilButtonWidgetSnapshot_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilButtonWidgetSnapshot_spec.ts @@ -4,7 +4,8 @@ import { anvilSnapshot, } from "../../../../../support/Objects/ObjectsCore"; -describe( +// TODO: Enable when issue(github.com/appsmithorg/appsmith/issues/36419) is solved. +describe.skip( `${ANVIL_EDITOR_TEST}: Anvil tests for Button Widget`, { tags: ["@tag.Anvil", "@tag.Visual"] }, () => { diff --git a/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilCheckboxGroupWidgetSnapshot_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilCheckboxGroupWidgetSnapshot_spec.ts index 98e24b1e0b2..66b66d583e7 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilCheckboxGroupWidgetSnapshot_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilCheckboxGroupWidgetSnapshot_spec.ts @@ -4,7 +4,8 @@ import { anvilSnapshot, } from "../../../../../support/Objects/ObjectsCore"; -describe( +// TODO: Enable when issue(github.com/appsmithorg/appsmith/issues/36419) is solved. +describe.skip( `${ANVIL_EDITOR_TEST}: Anvil tests for Checkbox Group Widget`, { tags: ["@tag.Anvil", "@tag.Visual"] }, () => { diff --git a/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilCheckboxWidgetSnapshot_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilCheckboxWidgetSnapshot_spec.ts index 3cd3bd49848..5ad568bf5a2 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilCheckboxWidgetSnapshot_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilCheckboxWidgetSnapshot_spec.ts @@ -4,7 +4,8 @@ import { anvilSnapshot, } from "../../../../../support/Objects/ObjectsCore"; -describe( +// TODO: Enable when issue(github.com/appsmithorg/appsmith/issues/36419) is solved. +describe.skip( `${ANVIL_EDITOR_TEST}: Anvil tests for Checkbox Widget`, { tags: ["@tag.Anvil", "@tag.Visual"] }, () => { diff --git a/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilCurrencyInputWidgetSnapshot_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilCurrencyInputWidgetSnapshot_spec.ts index 3e41473ebfe..5300cb6c565 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilCurrencyInputWidgetSnapshot_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilCurrencyInputWidgetSnapshot_spec.ts @@ -4,7 +4,8 @@ import { anvilSnapshot, } from "../../../../../support/Objects/ObjectsCore"; -describe( +// TODO: Enable when issue(github.com/appsmithorg/appsmith/issues/36419) is solved. +describe.skip( `${ANVIL_EDITOR_TEST}: Anvil tests for Currency Input Widget`, { tags: ["@tag.Anvil", "@tag.Visual"] }, () => { diff --git a/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilHeadingWidgetSnapshot_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilHeadingWidgetSnapshot_spec.ts index 89991dabaf3..82ae69d9a07 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilHeadingWidgetSnapshot_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilHeadingWidgetSnapshot_spec.ts @@ -4,7 +4,8 @@ import { anvilSnapshot, } from "../../../../../support/Objects/ObjectsCore"; -describe( +// TODO: Enable when issue(github.com/appsmithorg/appsmith/issues/36419) is solved. +describe.skip( `${ANVIL_EDITOR_TEST}: Anvil tests for Heading Widget`, { tags: ["@tag.Anvil", "@tag.Visual"] }, () => { diff --git a/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilIconButtonWidgetSnapshot_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilIconButtonWidgetSnapshot_spec.ts index b73f2486036..5adb9bde936 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilIconButtonWidgetSnapshot_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilIconButtonWidgetSnapshot_spec.ts @@ -4,7 +4,8 @@ import { anvilSnapshot, } from "../../../../../support/Objects/ObjectsCore"; -describe( +// TODO: Enable when issue(github.com/appsmithorg/appsmith/issues/36419) is solved. +describe.skip( `${ANVIL_EDITOR_TEST}: Anvil tests for Icon Button Widget`, { tags: ["@tag.Anvil", "@tag.Visual"] }, () => { diff --git a/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilInlineButtonWidgetSnapshot_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilInlineButtonWidgetSnapshot_spec.ts index a75a3048216..9899b8ce2f7 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilInlineButtonWidgetSnapshot_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilInlineButtonWidgetSnapshot_spec.ts @@ -4,7 +4,8 @@ import { anvilSnapshot, } from "../../../../../support/Objects/ObjectsCore"; -describe( +// TODO: Enable when issue(github.com/appsmithorg/appsmith/issues/36419) is solved. +describe.skip( `${ANVIL_EDITOR_TEST}: Anvil tests for Inline Button Widget`, { tags: ["@tag.Anvil", "@tag.Visual"] }, () => { diff --git a/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilInputWidgetSnapshot_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilInputWidgetSnapshot_spec.ts index 0ed3244be5c..5751a4d3a86 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilInputWidgetSnapshot_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilInputWidgetSnapshot_spec.ts @@ -4,7 +4,8 @@ import { anvilSnapshot, } from "../../../../../support/Objects/ObjectsCore"; -describe( +// TODO: Enable when issue(github.com/appsmithorg/appsmith/issues/36419) is solved. +describe.skip( `${ANVIL_EDITOR_TEST}: Anvil tests for Input Widget`, { tags: ["@tag.Anvil", "@tag.Visual"] }, () => { diff --git a/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilParagraphWidgetSnapshot_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilParagraphWidgetSnapshot_spec.ts index 009f63dad63..eac9c2178ef 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilParagraphWidgetSnapshot_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilParagraphWidgetSnapshot_spec.ts @@ -4,7 +4,8 @@ import { anvilSnapshot, } from "../../../../../support/Objects/ObjectsCore"; -describe( +// TODO: Enable when issue(github.com/appsmithorg/appsmith/issues/36419) is solved. +describe.skip( `${ANVIL_EDITOR_TEST}: Anvil tests for Paragraph Widget`, { tags: ["@tag.Anvil", "@tag.Visual"] }, () => { diff --git a/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilPhoneInputWidgetSnapshot_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilPhoneInputWidgetSnapshot_spec.ts index 653df4d7871..634a4154f84 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilPhoneInputWidgetSnapshot_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilPhoneInputWidgetSnapshot_spec.ts @@ -4,7 +4,8 @@ import { anvilSnapshot, } from "../../../../../support/Objects/ObjectsCore"; -describe( +// TODO: Enable when issue(github.com/appsmithorg/appsmith/issues/36419) is solved. +describe.skip( `${ANVIL_EDITOR_TEST}: Anvil tests for Phone Input Widget`, { tags: ["@tag.Anvil", "@tag.Visual"] }, () => { diff --git a/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilRadioGroupWidgetSnapshot_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilRadioGroupWidgetSnapshot_spec.ts index dfa3d796373..7b90dbce28a 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilRadioGroupWidgetSnapshot_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilRadioGroupWidgetSnapshot_spec.ts @@ -4,7 +4,8 @@ import { anvilSnapshot, } from "../../../../../support/Objects/ObjectsCore"; -describe( +// TODO: Enable when issue(github.com/appsmithorg/appsmith/issues/36419) is solved. +describe.skip( `${ANVIL_EDITOR_TEST}: Anvil tests for Radio Group Widget`, { tags: ["@tag.Anvil", "@tag.Visual"] }, () => { diff --git a/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilStatsWidgetSnapshot_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilStatsWidgetSnapshot_spec.ts index 87af914cbde..51da8ac2395 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilStatsWidgetSnapshot_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilStatsWidgetSnapshot_spec.ts @@ -4,7 +4,8 @@ import { anvilSnapshot, } from "../../../../../support/Objects/ObjectsCore"; -describe( +// TODO: Enable when issue(github.com/appsmithorg/appsmith/issues/36419) is solved. +describe.skip( `${ANVIL_EDITOR_TEST}: Anvil tests for Stats Widget`, { tags: ["@tag.Anvil", "@tag.Visual"] }, () => { @@ -20,7 +21,7 @@ describe( }); it("2. Preview Mode", () => { - anvilSnapshot.enterPreviewMode("StatsWidget"); + anvilSnapshot.enterPreviewMode(); }); it("3. Deploy Mode", () => { diff --git a/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilSwitchGroupWidgetSnapshot_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilSwitchGroupWidgetSnapshot_spec.ts index 8e183efadc0..2ffed43ba43 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilSwitchGroupWidgetSnapshot_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilSwitchGroupWidgetSnapshot_spec.ts @@ -4,7 +4,8 @@ import { anvilSnapshot, } from "../../../../../support/Objects/ObjectsCore"; -describe( +// TODO: Enable when issue(github.com/appsmithorg/appsmith/issues/36419) is solved. +describe.skip( `${ANVIL_EDITOR_TEST}: Anvil tests for Switch Group Widget`, { tags: ["@tag.Anvil", "@tag.Visual"] }, () => { diff --git a/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilSwitchWidgetSnapshot_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilSwitchWidgetSnapshot_spec.ts index c8bdf612496..aec145739a2 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilSwitchWidgetSnapshot_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilSwitchWidgetSnapshot_spec.ts @@ -4,7 +4,8 @@ import { anvilSnapshot, } from "../../../../../support/Objects/ObjectsCore"; -describe( +// TODO: Enable when issue(github.com/appsmithorg/appsmith/issues/36419) is solved. +describe.skip( `${ANVIL_EDITOR_TEST}: Anvil tests for Switch Widget`, { tags: ["@tag.Anvil", "@tag.Visual"] }, () => { diff --git a/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilTableWidgetSnapshot_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilTableWidgetSnapshot_spec.ts index e5edcb37d91..87e1c2a6b4e 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilTableWidgetSnapshot_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilTableWidgetSnapshot_spec.ts @@ -4,7 +4,8 @@ import { anvilSnapshot, } from "../../../../../support/Objects/ObjectsCore"; -describe( +// TODO: Enable when issue(github.com/appsmithorg/appsmith/issues/36419) is solved. +describe.skip( `${ANVIL_EDITOR_TEST}: Anvil tests for Table Widget`, { tags: ["@tag.Anvil", "@tag.Visual"] }, () => { diff --git a/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilToolbarButtonWidgetSnapshot_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilToolbarButtonWidgetSnapshot_spec.ts index ecf7a60d051..ef99aeab293 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilToolbarButtonWidgetSnapshot_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilToolbarButtonWidgetSnapshot_spec.ts @@ -4,7 +4,8 @@ import { anvilSnapshot, } from "../../../../../support/Objects/ObjectsCore"; -describe( +// TODO: Enable when issue(github.com/appsmithorg/appsmith/issues/36419) is solved. +describe.skip( `${ANVIL_EDITOR_TEST}: Anvil tests for Toolbar Button Widget`, { tags: ["@tag.Anvil", "@tag.Visual"] }, () => { diff --git a/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilZoneSectionWidgetSnapshot_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilZoneSectionWidgetSnapshot_spec.ts index 336d17180eb..bd1bcf0d243 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilZoneSectionWidgetSnapshot_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilZoneSectionWidgetSnapshot_spec.ts @@ -4,7 +4,8 @@ import { anvilSnapshot, } from "../../../../../support/Objects/ObjectsCore"; -describe( +// TODO: Enable when issue(github.com/appsmithorg/appsmith/issues/36419) is solved. +describe.skip( `${ANVIL_EDITOR_TEST}: Anvil tests for Zone and Section Widget`, { tags: ["@tag.Anvil", "@tag.Visual"] }, () => { diff --git a/app/client/cypress/e2e/Regression/ClientSide/AppNavigation/AppNavigationWithGit_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/AppNavigation/AppNavigationWithGit_spec.ts index 036ac24618f..477cc3c87dd 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/AppNavigation/AppNavigationWithGit_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/AppNavigation/AppNavigationWithGit_spec.ts @@ -12,7 +12,7 @@ import PageList from "../../../../support/Pages/PageList"; describe( "General checks for app navigation with Git", - { tags: ["@tag.IDE", "@tag.Git"] }, + { tags: ["@tag.IDE", "@tag.Git", "@tag.Sanity"] }, function () { it("Issue #32050 - Branch parameter should not be removed when navigating from the inline nav more dropdown", () => { gitSync.CreateNConnectToGit(); diff --git a/app/client/cypress/e2e/Regression/ClientSide/AppNavigation/AppNavigationWithMultiplePages_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/AppNavigation/AppNavigationWithMultiplePages_spec.ts index 74584f5303c..d3e11d7f5d7 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/AppNavigation/AppNavigationWithMultiplePages_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/AppNavigation/AppNavigationWithMultiplePages_spec.ts @@ -18,7 +18,7 @@ let currentUrl: string; describe( "Page orientation and navigation related usecases ", - { tags: ["@tag.IDE"] }, + { tags: ["@tag.IDE", "@tag.Sanity"] }, function () { it("1. Change 'Orientation' to 'Side', sidebar should appear", () => { AppSidebar.navigate(AppSidebarButton.Settings); diff --git a/app/client/cypress/e2e/Regression/ClientSide/AppNavigation/NavigationSettings_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/AppNavigation/NavigationSettings_spec.ts index 5be9194171b..b1abc8d29f1 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/AppNavigation/NavigationSettings_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/AppNavigation/NavigationSettings_spec.ts @@ -10,71 +10,79 @@ import { } from "../../../../support/Pages/EditorNavigation"; import PageList from "../../../../support/Pages/PageList"; -describe("Test app's navigation settings", { tags: ["@tag.IDE"] }, function () { - it("1. Open app settings and navigation tab should be there and when the navigation tab is selected, navigation preview should be visible", () => { - AppSidebar.navigate(AppSidebarButton.Settings); - agHelper.AssertElementVisibility( - appSettings.locators._navigationSettingsTab, - ); +describe( + "Test app's navigation settings", + { tags: ["@tag.IDE", "@tag.Sanity"] }, + function () { + it("1. Open app settings and navigation tab should be there and when the navigation tab is selected, navigation preview should be visible", () => { + AppSidebar.navigate(AppSidebarButton.Settings); + agHelper.AssertElementVisibility( + appSettings.locators._navigationSettingsTab, + ); - // Should not exist when the tab is not selected - agHelper.AssertElementAbsence(appSettings.locators._navigationPreview); - agHelper.GetNClick(appSettings.locators._navigationSettingsTab); + // Should not exist when the tab is not selected + agHelper.AssertElementAbsence(appSettings.locators._navigationPreview); + agHelper.GetNClick(appSettings.locators._navigationSettingsTab); - // Should exist when the tab is selected - agHelper.AssertElementVisibility(appSettings.locators._navigationPreview); - }); + // Should exist when the tab is selected + agHelper.AssertElementVisibility(appSettings.locators._navigationPreview); + }); - it("2. Toggle 'Show navbar' to off, the app header and navigation should not appear when deployed", () => { - // Toggle show navbar to off - agHelper.GetNClick( - appSettings.locators._navigationSettings._showNavbar, - 0, - true, - ); - deployMode.DeployApp(locators._emptyPageTxt); - agHelper.AssertElementAbsence(appSettings.locators._header); - agHelper.AssertElementAbsence(appSettings.locators._topStacked); - //Browser back is used as the Navbar is off and there wont be option to come back to editor - agHelper.BrowserNavigation(-1); - // Wait for the app to load - AppSidebar.navigate(AppSidebarButton.Settings); - agHelper.GetNClick(appSettings.locators._navigationSettingsTab); - // Toggle show navbar back to on - agHelper.GetNClick( - appSettings.locators._navigationSettings._showNavbar, - 0, - true, - ); - }); + it("2. Toggle 'Show navbar' to off, the app header and navigation should not appear when deployed", () => { + // Toggle show navbar to off + agHelper.GetNClick( + appSettings.locators._navigationSettings._showNavbar, + 0, + true, + ); + deployMode.DeployApp(locators._emptyPageTxt); + agHelper.AssertElementAbsence(appSettings.locators._header); + agHelper.AssertElementAbsence(appSettings.locators._topStacked); + //Browser back is used as the Navbar is off and there wont be option to come back to editor + agHelper.BrowserNavigation(-1); + // Wait for the app to load + AppSidebar.navigate(AppSidebarButton.Settings); + agHelper.GetNClick(appSettings.locators._navigationSettingsTab); + // Toggle show navbar back to on + agHelper.GetNClick( + appSettings.locators._navigationSettings._showNavbar, + 0, + true, + ); + }); - it("3. Change 'Orientation' to 'Side', deploy, and the sidebar should appear", () => { - agHelper.GetNClick( - appSettings.locators._navigationSettings._orientationOptions._side, - 0, - true, - ); - agHelper.AssertElementVisibility(appSettings.locators._sideNavbar); - deployMode.DeployApp(); - agHelper.AssertElementAbsence(appSettings.locators._header); - agHelper.AssertElementAbsence(appSettings.locators._topStacked); - agHelper.AssertElementVisibility(appSettings.locators._sideNavbar); - deployMode.NavigateBacktoEditor(); - }); + it("3. Change 'Orientation' to 'Side', deploy, and the sidebar should appear", () => { + agHelper.GetNClick( + appSettings.locators._navigationSettings._orientationOptions._side, + 0, + true, + ); + agHelper.AssertElementVisibility(appSettings.locators._sideNavbar); + deployMode.DeployApp(); + agHelper.AssertElementAbsence(appSettings.locators._header); + agHelper.AssertElementAbsence(appSettings.locators._topStacked); + agHelper.AssertElementVisibility(appSettings.locators._sideNavbar); + deployMode.NavigateBacktoEditor(); + }); - it("4. Change 'Orientation' back to 'Top', and 'Nav style' to 'Inline', page navigation items should appear inline", () => { - PageList.AddNewPage(); - AppSidebar.navigate(AppSidebarButton.Settings); - agHelper.GetNClick(appSettings.locators._navigationSettingsTab); - agHelper.GetNClick( - appSettings.locators._navigationSettings._orientationOptions._top, - 0, - true, - ); - agHelper.GetNClick(appSettings.locators._navStyleOptions._inline, 0, true); - deployMode.DeployApp(); - agHelper.AssertElementVisibility(appSettings.locators._header); - agHelper.AssertElementAbsence(appSettings.locators._topStacked); - agHelper.AssertElementVisibility(appSettings.locators._topInline); - }); -}); + it("4. Change 'Orientation' back to 'Top', and 'Nav style' to 'Inline', page navigation items should appear inline", () => { + PageList.AddNewPage(); + AppSidebar.navigate(AppSidebarButton.Settings); + agHelper.GetNClick(appSettings.locators._navigationSettingsTab); + agHelper.GetNClick( + appSettings.locators._navigationSettings._orientationOptions._top, + 0, + true, + ); + agHelper.GetNClick( + appSettings.locators._navStyleOptions._inline, + 0, + true, + ); + deployMode.DeployApp(); + agHelper.AssertElementVisibility(appSettings.locators._header); + agHelper.AssertElementAbsence(appSettings.locators._topStacked); + agHelper.AssertElementVisibility(appSettings.locators._topInline); + }); + }, +); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Autocomplete/autocomplete_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Autocomplete/autocomplete_spec.ts index 9fa5a84008a..d5525d2dc54 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Autocomplete/autocomplete_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Autocomplete/autocomplete_spec.ts @@ -5,56 +5,60 @@ import { agHelper } from "../../../../support/Objects/ObjectsCore"; const dynamicInputLocators = require("../../../../locators/DynamicInput.json"); -describe("Dynamic input autocomplete", { tags: ["@tag.JS"] }, () => { - before(() => { - agHelper.AddDsl("autocomp"); - }); - - it("1. Opens autocomplete for bindings", () => { - EditorNavigation.SelectEntityByName("Aditya", EntityType.Widget); - EditorNavigation.SelectEntityByName("Button2", EntityType.Widget, {}, [ - "TestModal", - ]); - cy.testJsontext("label", "", { - parseSpecialCharSequences: true, +describe( + "Dynamic input autocomplete", + { tags: ["@tag.JS", "@tag.Sanity"] }, + () => { + before(() => { + agHelper.AddDsl("autocomp"); }); - cy.get(dynamicInputLocators.input) - .first() - .click({ force: true }) - .type("{uparrow}", { parseSpecialCharSequences: true }) - .type("{ctrl}{shift}{downarrow}", { parseSpecialCharSequences: true }) - .type("{backspace}", { parseSpecialCharSequences: true }) - .then(() => { - cy.get(dynamicInputLocators.input) - .first() - .click({ force: true }) - .type("{{", { + + it("1. Opens autocomplete for bindings", () => { + EditorNavigation.SelectEntityByName("Aditya", EntityType.Widget); + EditorNavigation.SelectEntityByName("Button2", EntityType.Widget, {}, [ + "TestModal", + ]); + cy.testJsontext("label", "", { + parseSpecialCharSequences: true, + }); + cy.get(dynamicInputLocators.input) + .first() + .click({ force: true }) + .type("{uparrow}", { parseSpecialCharSequences: true }) + .type("{ctrl}{shift}{downarrow}", { parseSpecialCharSequences: true }) + .type("{backspace}", { parseSpecialCharSequences: true }) + .then(() => { + cy.get(dynamicInputLocators.input) + .first() + .click({ force: true }) + .type("{{", { + parseSpecialCharSequences: true, + }); + + // Tests if autocomplete will open + cy.get(dynamicInputLocators.hints).should("exist"); + // Tests if data tree entities are sorted + cy.get(`${dynamicInputLocators.hints} li`) + .eq(1) + .should("have.text", "Button1.text"); + cy.testJsontext("label", "", { parseSpecialCharSequences: true, }); - - // Tests if autocomplete will open - cy.get(dynamicInputLocators.hints).should("exist"); - // Tests if data tree entities are sorted - cy.get(`${dynamicInputLocators.hints} li`) - .eq(1) - .should("have.text", "Button1.text"); - cy.testJsontext("label", "", { - parseSpecialCharSequences: true, }); - }); - }); + }); - it("2. Test if action inside non event field throws error & open current value popup", () => { - cy.get(dynamicInputLocators.input) - .first() - .click({ force: true }) - .type("{backspace}".repeat(12)) - .type("{{storeValue()}}", { parseSpecialCharSequences: false }); - cy.evaluateErrorMessage( - "Please remove any direct/indirect references to {{actionName}} and try again. Data fields cannot execute framework actions.".replaceAll( - "{{actionName}}", - "storeValue()", - ), - ); - }); -}); + it("2. Test if action inside non event field throws error & open current value popup", () => { + cy.get(dynamicInputLocators.input) + .first() + .click({ force: true }) + .type("{backspace}".repeat(12)) + .type("{{storeValue()}}", { parseSpecialCharSequences: false }); + cy.evaluateErrorMessage( + "Please remove any direct/indirect references to {{actionName}} and try again. Data fields cannot execute framework actions.".replaceAll( + "{{actionName}}", + "storeValue()", + ), + ); + }); + }, +); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Binding/JSObject_Postgress_Table_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Binding/JSObject_Postgress_Table_spec.js index 7e75ad2fa70..edd3c88533f 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Binding/JSObject_Postgress_Table_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Binding/JSObject_Postgress_Table_spec.js @@ -10,7 +10,7 @@ let currentUrl; describe( "Addwidget from Query and bind with other widgets", - { tags: ["@tag.Binding"] }, + { tags: ["@tag.Binding", "@tag.Sanity"] }, function () { beforeEach(() => { _.dataSources.StartDataSourceRoutes(); 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 c67cbd6cc53..03a7d1e93af 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 @@ -13,7 +13,7 @@ import { describe( "Test Create Api and Bind to Table widget V2", - { tags: ["@tag.Binding"] }, + { tags: ["@tag.Binding", "@tag.Sanity"] }, function () { before(() => { agHelper.AddDsl("tableV2TextPaginationDsl"); diff --git a/app/client/cypress/e2e/Regression/ClientSide/BugTests/AllWidgets_Reset_Spec.ts b/app/client/cypress/e2e/Regression/ClientSide/BugTests/AllWidgets_Reset_Spec.ts index 0945e34aea5..523dd65efee 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/BugTests/AllWidgets_Reset_Spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/BugTests/AllWidgets_Reset_Spec.ts @@ -414,7 +414,7 @@ function filePickerWidgetAndReset() { Object.entries(widgetsToTest).forEach(([widgetSelector, testConfig]) => { describe( `${testConfig.widgetName} widget test for validating reset assertWidgetReset`, - { tags: ["@tag.Widget"] }, + { tags: ["@tag.Widget", "@tag.Sanity"] }, () => { beforeEach(() => { _.agHelper.RestoreLocalStorageCache(); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Debugger/JSObjects_navigation_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Debugger/JSObjects_navigation_spec.ts index 6d00f9aecd6..4852cd6ba58 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Debugger/JSObjects_navigation_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Debugger/JSObjects_navigation_spec.ts @@ -7,7 +7,7 @@ import { } from "../../../../support/Objects/ObjectsCore"; import EditorNavigation from "../../../../support/Pages/EditorNavigation"; -describe("JSObjects", () => { +describe("JSObjects", { tags: ["@tag.JS"] }, () => { it("1. Focus and position cursor on the ch,line having an error", () => { const JS_OBJECT_BODY = `export default { myVar1: [], diff --git a/app/client/cypress/e2e/Regression/ClientSide/DynamicHeight/Auto_Height_Limit_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/DynamicHeight/Auto_Height_Limit_spec.ts index ecd442fdb89..333a0fd34fd 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/DynamicHeight/Auto_Height_Limit_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/DynamicHeight/Auto_Height_Limit_spec.ts @@ -5,7 +5,7 @@ import EditorNavigation, { describe( "Dynamic Height Width validation with limits", - { tags: ["@tag.AutoHeight"] }, + { tags: ["@tag.AutoHeight", "@tag.Sanity"] }, function () { it("1. Validate change in auto height with limits width for widgets and highlight section validation", function () { agHelper.AddDsl("dynamicHeightContainerdsl"); diff --git a/app/client/cypress/e2e/Regression/ClientSide/DynamicHeight/Auto_Height_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/DynamicHeight/Auto_Height_spec.ts index 4ba99b83f1c..08b53f1fcfe 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/DynamicHeight/Auto_Height_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/DynamicHeight/Auto_Height_spec.ts @@ -11,7 +11,7 @@ import EditorNavigation, { describe( "Dynamic Height Width validation", - { tags: ["@tag.AutoHeight"] }, + { tags: ["@tag.AutoHeight", "@tag.Sanity"] }, function () { afterEach(() => { agHelper.SaveLocalStorageCache(); diff --git a/app/client/cypress/e2e/Regression/ClientSide/ExplorerTests/Widgets_Copy_Delete_Undo_spec.js b/app/client/cypress/e2e/Regression/ClientSide/ExplorerTests/Widgets_Copy_Delete_Undo_spec.js index 38e1ebd5ee1..9c8d981cda5 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/ExplorerTests/Widgets_Copy_Delete_Undo_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/ExplorerTests/Widgets_Copy_Delete_Undo_spec.js @@ -17,7 +17,7 @@ before(() => { describe( "Test Suite to validate copy/delete/undo functionalites", - { tags: ["@tag.IDE"] }, + { tags: ["@tag.IDE", "@tag.Sanity"] }, function () { const modifierKey = Cypress.platform === "darwin" ? "meta" : "ctrl"; diff --git a/app/client/cypress/e2e/Regression/ClientSide/Fork/ForkApplicationReconnectModal_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Fork/ForkApplicationReconnectModal_spec.ts index b95fe225fef..3495f3942d8 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Fork/ForkApplicationReconnectModal_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Fork/ForkApplicationReconnectModal_spec.ts @@ -8,7 +8,7 @@ let currentWorkspace: string, currentAppName: string, forkWorkspaceName: string; describe( "Fork application across workspaces", - { tags: ["@tag.Fork"] }, + { tags: ["@tag.Fork", "@tag.Sanity"] }, function () { it("Bug 24702: Signed user should be able to fork a public forkable app & Check if the forked application has the same dsl as the original", function () { // Create new workspace to create App in diff --git a/app/client/cypress/e2e/Regression/ClientSide/Git/ExistingApps/v1.9.24/DSCrudAndBindings_Spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Git/ExistingApps/v1.9.24/DSCrudAndBindings_Spec.ts index 3882701471f..85eb6edf6ec 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Git/ExistingApps/v1.9.24/DSCrudAndBindings_Spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Git/ExistingApps/v1.9.24/DSCrudAndBindings_Spec.ts @@ -19,7 +19,7 @@ import EditorNavigation, { describe( "Import and validate older app (app created in older versions of Appsmith) from Gitea", - { tags: ["@tag.Git"] }, + { tags: ["@tag.Git", "@tag.Sanity"] }, function () { let appRepoName = "TestMigration", appName = "UpgradeAppToLatestVersion", diff --git a/app/client/cypress/e2e/Regression/ClientSide/Git/GitAutocommit_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Git/GitAutocommit_spec.ts index 83ea4255df9..9d38aa357dc 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Git/GitAutocommit_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Git/GitAutocommit_spec.ts @@ -11,7 +11,14 @@ let repoName: string = "TED-testrepo1"; describe( "Git Autocommit", - { tags: ["@tag.Git", "@tag.GitAutocommit", "@tag.excludeForAirgap"] }, + { + tags: [ + "@tag.Git", + "@tag.GitAutocommit", + "@tag.excludeForAirgap", + "@tag.Sanity", + ], + }, function () { it("Check if autocommit progress bar is visible and network requests are properly called", function () { agHelper.GenerateUUID(); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Git/GitDiscardChange/DiscardChanges_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Git/GitDiscardChange/DiscardChanges_spec.js index df7a398ff8b..fd1877ce5c2 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Git/GitDiscardChange/DiscardChanges_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Git/GitDiscardChange/DiscardChanges_spec.js @@ -17,203 +17,209 @@ import EditorNavigation, { } from "../../../../../support/Pages/EditorNavigation"; import PageList from "../../../../../support/Pages/PageList"; -describe("Git discard changes:", { tags: ["@tag.Git"] }, function () { - let datasourceName; - let repoName; - const query1 = "get_employees"; - const query2 = "get_category"; - const jsObject = "JSObject1"; - const page2 = "Page2"; - const page3 = "Page3"; - - it("1. Create an app with Query1 and JSObject1, connect it to git", () => { - // Create new postgres datasource - dataSources.CreateDataSource("Postgres"); - cy.get("@dsName").then(($dsName) => { - datasourceName = $dsName; - dataSources.CreateQueryAfterDSSaved( - `SELECT * FROM public."employees" where employee_id=1`, - query1, +describe( + "Git discard changes:", + { tags: ["@tag.Git", "@tag.Sanity"] }, + function () { + let datasourceName; + let repoName; + const query1 = "get_employees"; + const query2 = "get_category"; + const jsObject = "JSObject1"; + const page2 = "Page2"; + const page3 = "Page3"; + + it("1. Create an app with Query1 and JSObject1, connect it to git", () => { + // Create new postgres datasource + dataSources.CreateDataSource("Postgres"); + cy.get("@dsName").then(($dsName) => { + datasourceName = $dsName; + dataSources.CreateQueryAfterDSSaved( + `SELECT * FROM public."employees" where employee_id=1`, + query1, + ); + dataSources.RunQuery(); + }); + + EditorNavigation.SelectEntityByName("Page1", EntityType.Page); + cy.wait("@getPage"); + // bind input widget to postgres query on page1 + entityExplorer.DragDropWidgetNVerify(draggableWidgets.INPUT_V2); + propPane.UpdatePropertyFieldValue( + "Default value", + `{{${query1}.data[0].first_name}}`, + ); + PageList.AddNewPage(); + EditorNavigation.SelectEntityByName(page2, EntityType.Page); + cy.wait("@getPage"); + jsEditor.CreateJSObject('return "Success";'); + entityExplorer.DragDropWidgetNVerify(draggableWidgets.INPUT_V2); + propPane.UpdatePropertyFieldValue( + "Default value", + `{{JSObject1.myFun1()}}`, + ); + PageLeftPane.switchSegment(PagePaneSegment.UI); + // connect app to git + gitSync.CreateNConnectToGit(); + gitSync.CreateGitBranch(); + cy.get("@gitRepoName").then((repName) => { + repoName = repName; + }); + }); + + it("2. Add new datasource query, discard changes, verify query is deleted", () => { + EditorNavigation.SelectEntityByName("Page1", EntityType.Page); + cy.wait("@getPage"); + // create new postgres query + dataSources.CreateQueryForDS( + datasourceName, + `SELECT * FROM public."category" LIMIT 10;`, + query2, ); dataSources.RunQuery(); + // navigate to Page1 + EditorNavigation.SelectEntityByName("Page1", EntityType.Page); + cy.wait("@getPage"); + // discard changes + gitSync.DiscardChanges(); + PageLeftPane.switchSegment(PagePaneSegment.Queries); + // verify query2 is not present + PageLeftPane.assertAbsence(query2); + }); + + it("3. Add new JSObject , discard changes verify JSObject is deleted", () => { + jsEditor.CreateJSObject('return "Success";'); + PageLeftPane.switchSegment(PagePaneSegment.JS); + PageLeftPane.assertPresence(jsObject); + gitSync.DiscardChanges(); + PageLeftPane.switchSegment(PagePaneSegment.JS); + // verify jsObject2 is deleted after discarding changes + PageLeftPane.assertAbsence(jsObject); }); - EditorNavigation.SelectEntityByName("Page1", EntityType.Page); - cy.wait("@getPage"); - // bind input widget to postgres query on page1 - entityExplorer.DragDropWidgetNVerify(draggableWidgets.INPUT_V2); - propPane.UpdatePropertyFieldValue( - "Default value", - `{{${query1}.data[0].first_name}}`, - ); - PageList.AddNewPage(); - EditorNavigation.SelectEntityByName(page2, EntityType.Page); - cy.wait("@getPage"); - jsEditor.CreateJSObject('return "Success";'); - entityExplorer.DragDropWidgetNVerify(draggableWidgets.INPUT_V2); - propPane.UpdatePropertyFieldValue( - "Default value", - `{{JSObject1.myFun1()}}`, - ); - PageLeftPane.switchSegment(PagePaneSegment.UI); - // connect app to git - gitSync.CreateNConnectToGit(); - gitSync.CreateGitBranch(); - cy.get("@gitRepoName").then((repName) => { - repoName = repName; + it("4. Delete page2 and trigger discard flow, page2 should be available again", () => { + PageList.DeletePage(page2); + // verify page is deleted + PageList.assertAbsence(page2); + gitSync.DiscardChanges(); + // verify page2 is recovered back + PageList.assertPresence(page2); + EditorNavigation.SelectEntityByName(page2, EntityType.Page); + cy.wait("@getPage"); + // verify data binding on page2 + cy.get(".bp3-input").should("have.value", "Success"); }); - }); - - it("2. Add new datasource query, discard changes, verify query is deleted", () => { - EditorNavigation.SelectEntityByName("Page1", EntityType.Page); - cy.wait("@getPage"); - // create new postgres query - dataSources.CreateQueryForDS( - datasourceName, - `SELECT * FROM public."category" LIMIT 10;`, - query2, - ); - dataSources.RunQuery(); - // navigate to Page1 - EditorNavigation.SelectEntityByName("Page1", EntityType.Page); - cy.wait("@getPage"); - // discard changes - gitSync.DiscardChanges(); - PageLeftPane.switchSegment(PagePaneSegment.Queries); - // verify query2 is not present - PageLeftPane.assertAbsence(query2); - }); - - it("3. Add new JSObject , discard changes verify JSObject is deleted", () => { - jsEditor.CreateJSObject('return "Success";'); - PageLeftPane.switchSegment(PagePaneSegment.JS); - PageLeftPane.assertPresence(jsObject); - gitSync.DiscardChanges(); - PageLeftPane.switchSegment(PagePaneSegment.JS); - // verify jsObject2 is deleted after discarding changes - PageLeftPane.assertAbsence(jsObject); - }); - - it("4. Delete page2 and trigger discard flow, page2 should be available again", () => { - PageList.DeletePage(page2); - // verify page is deleted - PageList.assertAbsence(page2); - gitSync.DiscardChanges(); - // verify page2 is recovered back - PageList.assertPresence(page2); - EditorNavigation.SelectEntityByName(page2, EntityType.Page); - cy.wait("@getPage"); - // verify data binding on page2 - cy.get(".bp3-input").should("have.value", "Success"); - }); - - it("5. Delete Query1 and trigger discard flow, Query1 will be recovered", () => { - // navigate to Page1 - EditorNavigation.SelectEntityByName("Page1", EntityType.Page); - // delete query1 - EditorNavigation.SelectEntityByName(query1, EntityType.Query); - entityExplorer.ActionContextMenuByEntityName({ - entityNameinLeftSidebar: query1, - action: "Delete", - entityType: entityItems.Query, + + it("5. Delete Query1 and trigger discard flow, Query1 will be recovered", () => { + // navigate to Page1 + EditorNavigation.SelectEntityByName("Page1", EntityType.Page); + // delete query1 + EditorNavigation.SelectEntityByName(query1, EntityType.Query); + entityExplorer.ActionContextMenuByEntityName({ + entityNameinLeftSidebar: query1, + action: "Delete", + entityType: entityItems.Query, + }); + // verify Query1 is deleted + PageLeftPane.assertAbsence(query1); + // discard changes + gitSync.DiscardChanges(); + //verify query1 is recovered + PageLeftPane.switchSegment(PagePaneSegment.Queries); + PageLeftPane.assertPresence(query1); + PageLeftPane.switchSegment(PagePaneSegment.UI); + cy.get(".bp3-input").should("have.value", "Nancy"); }); - // verify Query1 is deleted - PageLeftPane.assertAbsence(query1); - // discard changes - gitSync.DiscardChanges(); - //verify query1 is recovered - PageLeftPane.switchSegment(PagePaneSegment.Queries); - PageLeftPane.assertPresence(query1); - PageLeftPane.switchSegment(PagePaneSegment.UI); - cy.get(".bp3-input").should("have.value", "Nancy"); - }); - - it("6. Delete JSObject1 and trigger discard flow, JSObject1 should be active again", () => { - // navigate to page2 - EditorNavigation.SelectEntityByName(page2, EntityType.Page); - cy.wait("@getPage"); - cy.wait(3000); - /* create and save jsObject */ - // jsEditor.CreateJSObject('return "Success";'); - // delete jsObject1 - EditorNavigation.SelectEntityByName(jsObject, EntityType.JSObject); - agHelper.ActionContextMenuWithInPane({ - action: "Delete", + + it("6. Delete JSObject1 and trigger discard flow, JSObject1 should be active again", () => { + // navigate to page2 + EditorNavigation.SelectEntityByName(page2, EntityType.Page); + cy.wait("@getPage"); + cy.wait(3000); + /* create and save jsObject */ + // jsEditor.CreateJSObject('return "Success";'); + // delete jsObject1 + EditorNavigation.SelectEntityByName(jsObject, EntityType.JSObject); + agHelper.ActionContextMenuWithInPane({ + action: "Delete", + }); + PageLeftPane.assertAbsence(jsObject); + // discard changes + gitSync.DiscardChanges(); + EditorNavigation.SelectEntityByName(page2, EntityType.Page); + cy.wait("@getPage"); + cy.wait(3000); + //verify JSObject is recovered + PageLeftPane.switchSegment(PagePaneSegment.JS); + PageLeftPane.assertPresence(jsObject); + PageLeftPane.switchSegment(PagePaneSegment.UI); + cy.get(".bp3-input").should("have.value", "Success"); + }); + + it("7. Add new page i.e page3, go to page2 & discard changes, verify page3 is removed", () => { + // create new page page3 and move to page2 + cy.Createpage(page3); + EditorNavigation.SelectEntityByName(page2, EntityType.Page); + // discard changes + gitSync.DiscardChanges(); + // verify page3 is removed + PageList.assertAbsence(page3); }); - PageLeftPane.assertAbsence(jsObject); - // discard changes - gitSync.DiscardChanges(); - EditorNavigation.SelectEntityByName(page2, EntityType.Page); - cy.wait("@getPage"); - cy.wait(3000); - //verify JSObject is recovered - PageLeftPane.switchSegment(PagePaneSegment.JS); - PageLeftPane.assertPresence(jsObject); - PageLeftPane.switchSegment(PagePaneSegment.UI); - cy.get(".bp3-input").should("have.value", "Success"); - }); - - it("7. Add new page i.e page3, go to page2 & discard changes, verify page3 is removed", () => { - // create new page page3 and move to page2 - cy.Createpage(page3); - EditorNavigation.SelectEntityByName(page2, EntityType.Page); - // discard changes - gitSync.DiscardChanges(); - // verify page3 is removed - PageList.assertAbsence(page3); - }); - - it(`8. Add new page i.e page3, discard changes should not throw error: "resource not found"`, () => { - cy.Createpage(page3); - gitSync.DiscardChanges(); - PageList.assertAbsence(page3); - }); - - it("9. On discard failure an error message should be show and user should be able to discard again", () => { - cy.Createpage(page3); - - agHelper.GetNClick(gitSyncLocators.bottomBarCommitButton); - agHelper.AssertElementVisibility(gitSyncLocators.discardChanges); - cy.intercept("PUT", "/api/v1/git/discard/app/*", { - body: { - responseMeta: { - status: 500, - success: false, - error: { - code: 5000, - message: - "Provided file format is incompatible, please upgrade your instance to resolve this conflict.", - errorType: "INTERNAL_ERROR", + + it(`8. Add new page i.e page3, discard changes should not throw error: "resource not found"`, () => { + cy.Createpage(page3); + gitSync.DiscardChanges(); + PageList.assertAbsence(page3); + }); + + it("9. On discard failure an error message should be show and user should be able to discard again", () => { + cy.Createpage(page3); + + agHelper.GetNClick(gitSyncLocators.bottomBarCommitButton); + agHelper.AssertElementVisibility(gitSyncLocators.discardChanges); + cy.intercept("PUT", "/api/v1/git/discard/app/*", { + body: { + responseMeta: { + status: 500, + success: false, + error: { + code: 5000, + message: + "Provided file format is incompatible, please upgrade your instance to resolve this conflict.", + errorType: "INTERNAL_ERROR", + }, }, }, - }, - delay: 1000, + delay: 1000, + }); + + agHelper + .GetElement(gitSyncLocators.discardChanges) + .children() + .should("have.text", "Discard & pull"); + + agHelper.GetNClick(gitSyncLocators.discardChanges); + agHelper.AssertContains( + Cypress.env("MESSAGES").DISCARD_CHANGES_WARNING(), + ); + agHelper + .GetElement(gitSyncLocators.discardChanges) + .children() + .should("have.text", "Are you sure?"); + agHelper.GetNClick(gitSyncLocators.discardChanges); + agHelper.AssertContains( + Cypress.env("MESSAGES").DISCARDING_AND_PULLING_CHANGES(), + ); + cy.contains(Cypress.env("MESSAGES").DISCARDING_AND_PULLING_CHANGES()); + agHelper.Sleep(2000); + + agHelper.AssertElementVisibility(".ads-v2-callout__children"); + agHelper.AssertElementVisibility(gitSyncLocators.discardChanges); }); - agHelper - .GetElement(gitSyncLocators.discardChanges) - .children() - .should("have.text", "Discard & pull"); - - agHelper.GetNClick(gitSyncLocators.discardChanges); - agHelper.AssertContains(Cypress.env("MESSAGES").DISCARD_CHANGES_WARNING()); - agHelper - .GetElement(gitSyncLocators.discardChanges) - .children() - .should("have.text", "Are you sure?"); - agHelper.GetNClick(gitSyncLocators.discardChanges); - agHelper.AssertContains( - Cypress.env("MESSAGES").DISCARDING_AND_PULLING_CHANGES(), - ); - cy.contains(Cypress.env("MESSAGES").DISCARDING_AND_PULLING_CHANGES()); - agHelper.Sleep(2000); - - agHelper.AssertElementVisibility(".ads-v2-callout__children"); - agHelper.AssertElementVisibility(gitSyncLocators.discardChanges); - }); - - after(() => { - //clean up - //gitSync.DeleteTestGithubRepo(repoName); - }); -}); + after(() => { + //clean up + //gitSync.DeleteTestGithubRepo(repoName); + }); + }, +); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Git/GitImport/GitImport_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Git/GitImport/GitImport_spec.js index 80f564b873e..0c64032af71 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Git/GitImport/GitImport_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Git/GitImport/GitImport_spec.js @@ -21,205 +21,213 @@ import EditorNavigation, { } from "../../../../../support/Pages/EditorNavigation"; import PageList from "../../../../../support/Pages/PageList"; -describe("Git import flow ", { tags: ["@tag.Git"] }, function () { - it("1. Import an app from JSON with Postgres, MySQL, Mongo db & then connect it to Git", () => { - homePage.NavigateToHome(); - agHelper.GetNClick(homePageLocators.createNew, 0); - cy.get(homePageLocators.workspaceImportAppOption).click({ force: true }); - cy.get(homePageLocators.workspaceImportAppModal).should("be.visible"); - cy.wait(1000); - cy.xpath(homePageLocators.uploadLogo).selectFile( - "cypress/fixtures/gitImport.json", - { force: true }, - ); - cy.wait(4000); - cy.wait("@importNewApplication").then((interception) => { - cy.log(interception.response.body.data); +describe( + "Git import flow ", + { tags: ["@tag.Git", "@tag.Sanity"] }, + function () { + it("1. Import an app from JSON with Postgres, MySQL, Mongo db & then connect it to Git", () => { + homePage.NavigateToHome(); + agHelper.GetNClick(homePageLocators.createNew, 0); + cy.get(homePageLocators.workspaceImportAppOption).click({ force: true }); + cy.get(homePageLocators.workspaceImportAppModal).should("be.visible"); cy.wait(1000); - // should check reconnect modal opening + cy.xpath(homePageLocators.uploadLogo).selectFile( + "cypress/fixtures/gitImport.json", + { force: true }, + ); + cy.wait(4000); + cy.wait("@importNewApplication").then((interception) => { + cy.log(interception.response.body.data); + cy.wait(1000); + // should check reconnect modal opening + cy.get(reconnectDatasourceModal.Modal).should("be.visible"); + cy.ReconnectDatasource("TEDPostgres"); + cy.wait(1000); + dataSources.FillPostgresDSForm(); + cy.testDatasource(true); + agHelper.GetNClick(dataSources._saveDs); + cy.wait(1000); + cy.ReconnectDatasource("TEDMySQL"); + cy.wait(500); + dataSources.FillMySqlDSForm(); + cy.testDatasource(true); + agHelper.GetNClick(dataSources._saveDs); + cy.wait(1000); + cy.ReconnectDatasource("TEDMongo"); + cy.wait(1000); + dataSources.FillMongoDSForm(); + cy.testDatasource(true); + dataSources.SaveDatasource(true); + cy.wait("@getWorkspace"); + cy.get(reconnectDatasourceModal.ImportSuccessModal).should( + "be.visible", + ); + cy.get(reconnectDatasourceModal.ImportSuccessModalCloseBtn).click({ + force: true, + }); + cy.wait(1000); + + gitSync.CreateNConnectToGit(); + cy.get("@gitRepoName").then((repName) => { + repoName = repName; + gitSync.CreateGitBranch(repoName); + }); + + agHelper.AssertElementExist(gitSync._bottomBarPull); + }); + }); + + it("2. Import the previous app connected to Git and reconnect Postgres, MySQL and Mongo db ", () => { + homePage.NavigateToHome(); + cy.createWorkspace(); + let newWorkspaceName; + cy.wait("@createWorkspace").then((interception) => { + newWorkspaceName = interception.response.body.data.name; + cy.CreateAppForWorkspace(newWorkspaceName, "gitImport"); + }); + gitSync.ImportAppFromGit(newWorkspaceName, repoName); + cy.wait(5000); cy.get(reconnectDatasourceModal.Modal).should("be.visible"); cy.ReconnectDatasource("TEDPostgres"); - cy.wait(1000); - dataSources.FillPostgresDSForm(); + cy.wait(500); + cy.fillPostgresDatasourceForm(); + cy.get(datasourceEditor.sectionAuthentication).click(); cy.testDatasource(true); agHelper.GetNClick(dataSources._saveDs); - cy.wait(1000); + cy.wait(500); cy.ReconnectDatasource("TEDMySQL"); cy.wait(500); - dataSources.FillMySqlDSForm(); + cy.fillMySQLDatasourceForm(); + cy.get(datasourceEditor.sectionAuthentication).click(); cy.testDatasource(true); agHelper.GetNClick(dataSources._saveDs); - cy.wait(1000); + cy.wait(500); cy.ReconnectDatasource("TEDMongo"); - cy.wait(1000); + cy.wait(500); dataSources.FillMongoDSForm(); + cy.get(datasourceEditor.sectionAuthentication).click(); cy.testDatasource(true); - dataSources.SaveDatasource(true); - cy.wait("@getWorkspace"); + agHelper.GetNClick(dataSources._saveDs); + cy.wait(2000); cy.get(reconnectDatasourceModal.ImportSuccessModal).should("be.visible"); cy.get(reconnectDatasourceModal.ImportSuccessModalCloseBtn).click({ force: true, }); - cy.wait(1000); - - gitSync.CreateNConnectToGit(); - cy.get("@gitRepoName").then((repName) => { - repoName = repName; - gitSync.CreateGitBranch(repoName); + cy.wait("@gitStatus").then((interception) => { + cy.log(interception.response.body.data); + cy.wait(1000); }); - agHelper.AssertElementExist(gitSync._bottomBarPull); - }); - }); - it("2. Import the previous app connected to Git and reconnect Postgres, MySQL and Mongo db ", () => { - homePage.NavigateToHome(); - cy.createWorkspace(); - let newWorkspaceName; - cy.wait("@createWorkspace").then((interception) => { - newWorkspaceName = interception.response.body.data.name; - cy.CreateAppForWorkspace(newWorkspaceName, "gitImport"); - }); - gitSync.ImportAppFromGit(newWorkspaceName, repoName); - cy.wait(5000); - cy.get(reconnectDatasourceModal.Modal).should("be.visible"); - cy.ReconnectDatasource("TEDPostgres"); - cy.wait(500); - cy.fillPostgresDatasourceForm(); - cy.get(datasourceEditor.sectionAuthentication).click(); - cy.testDatasource(true); - agHelper.GetNClick(dataSources._saveDs); - cy.wait(500); - cy.ReconnectDatasource("TEDMySQL"); - cy.wait(500); - cy.fillMySQLDatasourceForm(); - cy.get(datasourceEditor.sectionAuthentication).click(); - cy.testDatasource(true); - agHelper.GetNClick(dataSources._saveDs); - cy.wait(500); - cy.ReconnectDatasource("TEDMongo"); - cy.wait(500); - dataSources.FillMongoDSForm(); - cy.get(datasourceEditor.sectionAuthentication).click(); - cy.testDatasource(true); - agHelper.GetNClick(dataSources._saveDs); - cy.wait(2000); - cy.get(reconnectDatasourceModal.ImportSuccessModal).should("be.visible"); - cy.get(reconnectDatasourceModal.ImportSuccessModalCloseBtn).click({ - force: true, - }); - cy.wait("@gitStatus").then((interception) => { - cy.log(interception.response.body.data); - cy.wait(1000); + cy.wait(3000); //for uncommited changes to appear if any! + cy.get("body").then(($body) => { + if ($body.find(gitSyncLocators.gitPullCount).length > 0) { + gitSync.CommitAndPush(); + } + }); }); - agHelper.AssertElementExist(gitSync._bottomBarPull); - cy.wait(3000); //for uncommited changes to appear if any! - cy.get("body").then(($body) => { - if ($body.find(gitSyncLocators.gitPullCount).length > 0) { - gitSync.CommitAndPush(); - } + it("3. Verfiy imported app should have all the data binding visible in view and edit mode", () => { + // verify postgres data binded to table + cy.get(".tbody").should("contain.text", "Test user 7"); + //verify MySQL data binded to table + cy.get(".tbody").should("contain.text", "New Config"); + // verify api response binded to input widget + cy.xpath("//input[@value='this is a test']").should("be.visible"); + // verify js object binded to input widget + cy.xpath("//input[@value='Success']").should("be.visible"); }); - }); - - it("3. Verfiy imported app should have all the data binding visible in view and edit mode", () => { - // verify postgres data binded to table - cy.get(".tbody").should("contain.text", "Test user 7"); - //verify MySQL data binded to table - cy.get(".tbody").should("contain.text", "New Config"); - // verify api response binded to input widget - cy.xpath("//input[@value='this is a test']").should("be.visible"); - // verify js object binded to input widget - cy.xpath("//input[@value='Success']").should("be.visible"); - }); - it("4. Create a new branch, clone page and validate data on that branch in view and edit mode", () => { - //cy.createGitBranch(newBranch); - gitSync.CreateGitBranch(newBranch, true); + it("4. Create a new branch, clone page and validate data on that branch in view and edit mode", () => { + //cy.createGitBranch(newBranch); + gitSync.CreateGitBranch(newBranch, true); - cy.get("@gitbranchName").then((branName) => { - newBranch = branName; - cy.log("newBranch is " + newBranch); - }); - cy.get(".tbody").should("contain.text", "Test user 7"); - // verify MySQL data binded to table - cy.get(".tbody").should("contain.text", "New Config"); - // verify api response binded to input widget - cy.xpath("//input[@value='this is a test']"); - // verify js object binded to input widget - cy.xpath("//input[@value='Success']"); + cy.get("@gitbranchName").then((branName) => { + newBranch = branName; + cy.log("newBranch is " + newBranch); + }); + cy.get(".tbody").should("contain.text", "Test user 7"); + // verify MySQL data binded to table + cy.get(".tbody").should("contain.text", "New Config"); + // verify api response binded to input widget + cy.xpath("//input[@value='this is a test']"); + // verify js object binded to input widget + cy.xpath("//input[@value='Success']"); - PageList.ClonePage(); + PageList.ClonePage(); - // verify jsObject is not duplicated - agHelper.Sleep(2000); //for cloning of table data to finish - EditorNavigation.SelectEntityByName(jsObject, EntityType.JSObject); //Also checking jsobject exists after cloning the page - PageLeftPane.switchSegment(PagePaneSegment.UI); - cy.xpath("//input[@class='bp3-input' and @value='Success']").should( - "be.visible", - ); + // verify jsObject is not duplicated + agHelper.Sleep(2000); //for cloning of table data to finish + EditorNavigation.SelectEntityByName(jsObject, EntityType.JSObject); //Also checking jsobject exists after cloning the page + PageLeftPane.switchSegment(PagePaneSegment.UI); + cy.xpath("//input[@class='bp3-input' and @value='Success']").should( + "be.visible", + ); - // deploy the app and validate data binding - cy.wait(2000); - cy.get(homePageLocators.publishButton).click(); - agHelper.AssertElementExist(gitSync._bottomBarPull); - cy.get(gitSyncLocators.commitCommentInput).type("Initial Commit"); - cy.get(gitSyncLocators.commitButton).click(); - cy.intercept("POST", "api/v1/git/commit/app/*").as("commit"); - agHelper.AssertElementExist(gitSync._bottomBarPull); - cy.get(gitSyncLocators.closeGitSyncModal).click(); - cy.wait(2000); - gitSync.MergeToMaster(); - cy.wait(2000); - cy.latestDeployPreview(); - table.AssertTableLoaded(); - // verify api response binded to input widget - cy.xpath("//input[@value='this is a test']"); - // verify js object binded to input widget - cy.xpath("//input[@value='Success']"); - // navigate to Page1 and verify data - cy.get(".t--page-switch-tab").contains("Page1").click({ force: true }); - table.AssertTableLoaded(); - // verify api response binded to input widget - cy.xpath("//input[@value='this is a test']"); - // verify js object binded to input widget - cy.xpath("//input[@value='Success']"); - deployMode.NavigateBacktoEditor(); - }); + // deploy the app and validate data binding + cy.wait(2000); + cy.get(homePageLocators.publishButton).click(); + agHelper.AssertElementExist(gitSync._bottomBarPull); + cy.get(gitSyncLocators.commitCommentInput).type("Initial Commit"); + cy.get(gitSyncLocators.commitButton).click(); + cy.intercept("POST", "api/v1/git/commit/app/*").as("commit"); + agHelper.AssertElementExist(gitSync._bottomBarPull); + cy.get(gitSyncLocators.closeGitSyncModal).click(); + cy.wait(2000); + gitSync.MergeToMaster(); + cy.wait(2000); + cy.latestDeployPreview(); + table.AssertTableLoaded(); + // verify api response binded to input widget + cy.xpath("//input[@value='this is a test']"); + // verify js object binded to input widget + cy.xpath("//input[@value='Success']"); + // navigate to Page1 and verify data + cy.get(".t--page-switch-tab").contains("Page1").click({ force: true }); + table.AssertTableLoaded(); + // verify api response binded to input widget + cy.xpath("//input[@value='this is a test']"); + // verify js object binded to input widget + cy.xpath("//input[@value='Success']"); + deployMode.NavigateBacktoEditor(); + }); - it("5. Switch to master and verify data in edit and view mode", () => { - cy.switchGitBranch("master"); - cy.wait(2000); - // validate data binding in edit and deploy mode - cy.latestDeployPreview(); - cy.get(".tbody").should("have.length", 2); - table.AssertTableLoaded(0, 1, "v1"); - cy.xpath("//input[@value='this is a test']"); - cy.xpath("//input[@value='Success']"); - // navigate to Page1 and verify data - cy.get(".t--page-switch-tab").contains("Page1 Copy").click({ force: true }); - table.AssertTableLoaded(0, 1, "v1"); - cy.xpath("//input[@value='this is a test']"); - cy.xpath("//input[@value='Success']"); - deployMode.NavigateBacktoEditor(); - }); + it("5. Switch to master and verify data in edit and view mode", () => { + cy.switchGitBranch("master"); + cy.wait(2000); + // validate data binding in edit and deploy mode + cy.latestDeployPreview(); + cy.get(".tbody").should("have.length", 2); + table.AssertTableLoaded(0, 1, "v1"); + cy.xpath("//input[@value='this is a test']"); + cy.xpath("//input[@value='Success']"); + // navigate to Page1 and verify data + cy.get(".t--page-switch-tab") + .contains("Page1 Copy") + .click({ force: true }); + table.AssertTableLoaded(0, 1, "v1"); + cy.xpath("//input[@value='this is a test']"); + cy.xpath("//input[@value='Success']"); + deployMode.NavigateBacktoEditor(); + }); - it("6. Add widget to master, merge then checkout to child branch and verify data", () => { - PageLeftPane.switchSegment(PagePaneSegment.UI); - cy.wait(2000); // wait for transition - cy.dragAndDropToCanvas("buttonwidget", { x: 300, y: 600 }); - cy.wait(3000); - gitSync.CommitAndPush(); - cy.merge(newBranch); - cy.get(gitSyncLocators.closeGitSyncModal).click(); - cy.wait(2000); - cy.switchGitBranch(newBranch); - cy.wait(4000); - // verify button widget is visible on child branch - cy.get(".t--widget-buttonwidget").should("be.visible"); - }); + it("6. Add widget to master, merge then checkout to child branch and verify data", () => { + PageLeftPane.switchSegment(PagePaneSegment.UI); + cy.wait(2000); // wait for transition + cy.dragAndDropToCanvas("buttonwidget", { x: 300, y: 600 }); + cy.wait(3000); + gitSync.CommitAndPush(); + cy.merge(newBranch); + cy.get(gitSyncLocators.closeGitSyncModal).click(); + cy.wait(2000); + cy.switchGitBranch(newBranch); + cy.wait(4000); + // verify button widget is visible on child branch + cy.get(".t--widget-buttonwidget").should("be.visible"); + }); - after(() => { - gitSync.DeleteTestGithubRepo(repoName); - }); -}); + after(() => { + gitSync.DeleteTestGithubRepo(repoName); + }); + }, +); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/DeleteBranch_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/DeleteBranch_spec.js index ec41b6a83e8..f1259df417d 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/DeleteBranch_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/DeleteBranch_spec.js @@ -7,7 +7,7 @@ import { } from "../../../../../support/Pages/EditorNavigation"; let repoName, branchName; -describe("Delete branch flow", { tags: ["@tag.Git"] }, () => { +describe("Delete branch flow", { tags: ["@tag.Git", "@tag.Sanity"] }, () => { it("1. Connect app to git, create new branch and delete it", () => { // create git repo and connect app to git gitSync.CreateNConnectToGit(); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/Deploy_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/Deploy_spec.js index 14f34e78313..e2d3411a371 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/Deploy_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/Deploy_spec.js @@ -3,57 +3,61 @@ import homePage from "../../../../../locators/HomePage"; import * as _ from "../../../../../support/Objects/ObjectsCore"; let repoName; -describe("Git sync modal: deploy tab", { tags: ["@tag.Git"] }, function () { - before(() => { - _.homePage.NavigateToHome(); - cy.createWorkspace(); - //_.homePage.CreateNewWorkspace("DeployGitTest"); - cy.wait("@createWorkspace").then((interception) => { - const newWorkspaceName = interception.response.body.data.name; - cy.CreateAppForWorkspace(newWorkspaceName, newWorkspaceName); +describe( + "Git sync modal: deploy tab", + { tags: ["@tag.Git", "@tag.Sanity"] }, + function () { + before(() => { + _.homePage.NavigateToHome(); + cy.createWorkspace(); + //_.homePage.CreateNewWorkspace("DeployGitTest"); + cy.wait("@createWorkspace").then((interception) => { + const newWorkspaceName = interception.response.body.data.name; + cy.CreateAppForWorkspace(newWorkspaceName, newWorkspaceName); + }); + _.gitSync.CreateNConnectToGit("Test"); + cy.get("@gitRepoName").then((repName) => { + repoName = repName; + }); }); - _.gitSync.CreateNConnectToGit("Test"); - cy.get("@gitRepoName").then((repName) => { - repoName = repName; + + it("1. Validate commit comment inputbox and last deployed preview", function () { + // last deployed preview + // The deploy preview Link should be displayed only after the first commit done + cy.get(gitSyncLocators.bottomBarCommitButton).click(); + + cy.get(gitSyncLocators.commitCommentInput).should("be.disabled"); + cy.get(gitSyncLocators.commitButton).should("be.disabled"); + cy.get(gitSyncLocators.closeGitSyncModal).click(); }); - }); - - it("1. Validate commit comment inputbox and last deployed preview", function () { - // last deployed preview - // The deploy preview Link should be displayed only after the first commit done - cy.get(gitSyncLocators.bottomBarCommitButton).click(); - - cy.get(gitSyncLocators.commitCommentInput).should("be.disabled"); - cy.get(gitSyncLocators.commitButton).should("be.disabled"); - cy.get(gitSyncLocators.closeGitSyncModal).click(); - }); - - it("2. Post connection app name deploy menu", function () { - // deploy - _.agHelper.GetNClick(_.locators._publishButton); - - cy.get(gitSyncLocators.gitSyncModal); - cy.get(gitSyncLocators.gitSyncModalDeployTab) - .should("have.attr", "aria-selected", "true") - .and("not.be.empty"); - cy.window().then((window) => { - cy.stub(window, "open").callsFake((url) => { - expect(url.indexOf("branch=master")).to.be.at.least(0); - expect(!!url).to.be.true; + + it("2. Post connection app name deploy menu", function () { + // deploy + _.agHelper.GetNClick(_.locators._publishButton); + + cy.get(gitSyncLocators.gitSyncModal); + cy.get(gitSyncLocators.gitSyncModalDeployTab) + .should("have.attr", "aria-selected", "true") + .and("not.be.empty"); + cy.window().then((window) => { + cy.stub(window, "open").callsFake((url) => { + expect(url.indexOf("branch=master")).to.be.at.least(0); + expect(!!url).to.be.true; + }); }); - }); - cy.get(gitSyncLocators.closeGitSyncModal).click(); + cy.get(gitSyncLocators.closeGitSyncModal).click(); - // current deployed version - _.agHelper.GetNClick(homePage.deployPopupOptionTrigger); - _.agHelper.AssertElementExist(homePage.currentDeployedPreviewBtn); + // current deployed version + _.agHelper.GetNClick(homePage.deployPopupOptionTrigger); + _.agHelper.AssertElementExist(homePage.currentDeployedPreviewBtn); - // connect to git - _.agHelper.AssertElementAbsence(homePage.connectToGitBtn); - }); + // connect to git + _.agHelper.AssertElementAbsence(homePage.connectToGitBtn); + }); - after(() => { - _.gitSync.DeleteTestGithubRepo(repoName); - }); -}); + after(() => { + _.gitSync.DeleteTestGithubRepo(repoName); + }); + }, +); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/GitConnectV2_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/GitConnectV2_spec.ts index 1deae827594..26cbff86c2a 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/GitConnectV2_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/GitConnectV2_spec.ts @@ -10,7 +10,7 @@ let app1Name: string; let repoName: any; let branchName: any; -describe("Git Connect V2", { tags: ["@tag.Git"] }, function () { +describe("Git Connect V2", { tags: ["@tag.Git", "@tag.Sanity"] }, function () { before(() => { _.agHelper.GenerateUUID(); cy.get("@guid").then((uid) => { diff --git a/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/GitSyncGitBugs_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/GitSyncGitBugs_spec.js index 65c3ebb47a5..e803036ac36 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/GitSyncGitBugs_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/GitSyncGitBugs_spec.js @@ -25,217 +25,90 @@ const mainBranch = "master"; const jsObject = "JSObject1"; let repoName; -describe("Git sync Bug #10773", { tags: ["@tag.Git"] }, function () { - beforeEach(() => { - agHelper.RestoreLocalStorageCache(); - }); - - afterEach(() => { - agHelper.SaveLocalStorageCache(); - }); - - it("1. Bug:10773 When user delete a resource form the child branch and merge it back to parent branch, still the deleted resource will show up in the newly created branch", () => { - homePage.NavigateToHome(); - cy.createWorkspace(); - cy.wait("@createWorkspace").then((interception) => { - const newWorkspaceName = interception.response.body.data.name; - cy.CreateAppForWorkspace(newWorkspaceName, "app-1"); - gitSync.CreateNConnectToGit(); - cy.get("@gitRepoName").then((repName) => { - repoName = repName; - // adding a new page "ChildPage" to master - cy.Createpage(pagename); - EditorNavigation.SelectEntityByName("Page1", EntityType.Page); - cy.commitAndPush(); - cy.wait(2000); - gitSync.CreateGitBranch(tempBranch, false); - //cy.createGitBranch(tempBranch); - // verify tempBranch should contain this page - EditorNavigation.SelectEntityByName(pagename, EntityType.Page); - // delete page from tempBranch and merge to master - PageList.DeletePage(pagename); - cy.get(homePageLocators.publishButton).click(); - cy.get(gitSyncLocators.commitCommentInput).type("Initial Commit"); - cy.get(gitSyncLocators.commitButton).click(); - cy.wait(8000); - cy.get(gitSyncLocators.closeGitSyncModal).click(); - cy.merge(mainBranch); - cy.get(gitSyncLocators.closeGitSyncModal).click(); - // verify ChildPage is not on master - cy.switchGitBranch(mainBranch); - PageList.ShowList(); - PageLeftPane.assertAbsence(pagename); - // create another branch and verify deleted page doesn't exist on it - //cy.createGitBranch(tempBranch0); - gitSync.CreateGitBranch(tempBranch0, false); - PageList.ShowList(); - PageLeftPane.assertAbsence(pagename); - gitSync.DeleteTestGithubRepo(repoName); - }); +describe( + "Git sync Bug #10773", + { tags: ["@tag.Git", "@tag.Sanity"] }, + function () { + beforeEach(() => { + agHelper.RestoreLocalStorageCache(); }); - }); - it("2. Connect app to git, clone the Page ,verify JSobject duplication should not happen and validate data binding in deploy mode and edit mode", () => { - homePage.NavigateToHome(); - cy.createWorkspace(); - cy.wait("@createWorkspace").then((interception) => { - const newWorkspaceName = interception.response.body.data.name; - cy.CreateAppForWorkspace(newWorkspaceName, "app-2"); - agHelper.AddDsl("JsObjecWithGitdsl"); - // connect app to git - gitSync.CreateNConnectToGit(); - cy.get("@gitRepoName").then((repName) => { - repoName = repName; + afterEach(() => { + agHelper.SaveLocalStorageCache(); + }); - // create JS Object and validate its data on Page1 - jsEditor.CreateJSObject('return "Success";'); - EditorNavigation.SelectEntityByName("Page1", EntityType.Page); - cy.wait(1000); - EditorNavigation.ShowCanvas(); - cy.xpath("//input[@class='bp3-input' and @value='Success']").should( - "be.visible", - ); - // clone the page1 and validate data binding - entityExplorer.ActionContextMenuByEntityName({ - entityNameinLeftSidebar: "Page1", - action: "Clone", - entityType: EntityItems.Page, + it("1. Bug:10773 When user delete a resource form the child branch and merge it back to parent branch, still the deleted resource will show up in the newly created branch", () => { + homePage.NavigateToHome(); + cy.createWorkspace(); + cy.wait("@createWorkspace").then((interception) => { + const newWorkspaceName = interception.response.body.data.name; + cy.CreateAppForWorkspace(newWorkspaceName, "app-1"); + gitSync.CreateNConnectToGit(); + cy.get("@gitRepoName").then((repName) => { + repoName = repName; + // adding a new page "ChildPage" to master + cy.Createpage(pagename); + EditorNavigation.SelectEntityByName("Page1", EntityType.Page); + cy.commitAndPush(); + cy.wait(2000); + gitSync.CreateGitBranch(tempBranch, false); + //cy.createGitBranch(tempBranch); + // verify tempBranch should contain this page + EditorNavigation.SelectEntityByName(pagename, EntityType.Page); + // delete page from tempBranch and merge to master + PageList.DeletePage(pagename); + cy.get(homePageLocators.publishButton).click(); + cy.get(gitSyncLocators.commitCommentInput).type("Initial Commit"); + cy.get(gitSyncLocators.commitButton).click(); + cy.wait(8000); + cy.get(gitSyncLocators.closeGitSyncModal).click(); + cy.merge(mainBranch); + cy.get(gitSyncLocators.closeGitSyncModal).click(); + // verify ChildPage is not on master + cy.switchGitBranch(mainBranch); + PageList.ShowList(); + PageLeftPane.assertAbsence(pagename); + // create another branch and verify deleted page doesn't exist on it + //cy.createGitBranch(tempBranch0); + gitSync.CreateGitBranch(tempBranch0, false); + PageList.ShowList(); + PageLeftPane.assertAbsence(pagename); + gitSync.DeleteTestGithubRepo(repoName); }); - cy.wait("@clonePage").should( - "have.nested.property", - "response.body.responseMeta.status", - 201, - ); - PageLeftPane.switchSegment(PagePaneSegment.JS); - // verify jsObject is not duplicated - PageLeftPane.assertPresence(jsObject); - EditorNavigation.ShowCanvas(); - cy.xpath("//input[@class='bp3-input' and @value='Success']").should( - "be.visible", - ); - // deploy the app and validate data binding - cy.get(homePageLocators.publishButton).click(); - agHelper.AssertElementExist(gitSync._bottomBarPull); - cy.get(gitSyncLocators.commitCommentInput).type("Initial Commit"); - cy.get(gitSyncLocators.commitButton).click(); - cy.wait(8000); - cy.get(gitSyncLocators.closeGitSyncModal).click(); - cy.latestDeployPreview(); - cy.wait(2000); - cy.xpath("//input[@class='bp3-input' and @value='Success']").should( - "be.visible", - ); - // switch to Page1 and validate data binding - cy.get(".t--page-switch-tab").contains("Page1").click({ force: true }); - cy.xpath("//input[@class='bp3-input' and @value='Success']").should( - "be.visible", - ); - deployMode.NavigateBacktoEditor(); }); }); - }); - it("3. Bug:12724 Js objects are merged to single page when user creates a new branch", () => { - // create a new branch, clone page and validate jsObject data binding - //cy.createGitBranch(tempBranch); - cy.wait(3000); - - gitSync.CreateGitBranch(tempBranch, true); - cy.wait(2000); - EditorNavigation.SelectEntityByName("Page1", EntityType.Page); - PageLeftPane.switchSegment(PagePaneSegment.JS); - // verify jsObject is not duplicated - PageLeftPane.assertPresence(jsObject); - EditorNavigation.ShowCanvas(); - cy.xpath("//input[@class='bp3-input' and @value='Success']").should( - "be.visible", - ); - entityExplorer.ActionContextMenuByEntityName({ - entityNameinLeftSidebar: "Page1", - action: "Clone", - entityType: EntityItems.Page, - }); - cy.wait("@clonePage").should( - "have.nested.property", - "response.body.responseMeta.status", - 201, - ); - gitSync.DeleteTestGithubRepo(repoName); - }); - - it("4. Create an app with JSObject, connect it to git and verify its data in edit and deploy mode", function () { - homePage.NavigateToHome(); - cy.createWorkspace(); - cy.wait("@createWorkspace").then((interception) => { - const newWorkspaceName = interception.response.body.data.name; - cy.CreateAppForWorkspace(newWorkspaceName, newWorkspaceName); - agHelper.AddDsl("JsObjecWithGitdsl"); - }); - // create JS Object and validate its data on Page1 - jsEditor.CreateJSObject('return "Success";'); - EditorNavigation.SelectEntityByName("Page1", EntityType.Page); - cy.wait(1000); - EditorNavigation.ShowCanvas(); - cy.xpath("//input[@class='bp3-input' and @value='Success']").should( - "be.visible", - ); - // clone the page1 and validate data binding - entityExplorer.ActionContextMenuByEntityName({ - entityNameinLeftSidebar: "Page1", - action: "Clone", - entityType: EntityItems.Page, - }); - cy.wait("@clonePage").should( - "have.nested.property", - "response.body.responseMeta.status", - 201, - ); - // connect app to git and deploy - gitSync.CreateNConnectToGit(); - cy.get("@gitRepoName").then((repName) => { - repoName = repName; - cy.wait(2000); - - cy.window() - .its("store") - .invoke("getState") - .then((state) => { - const commitInputDisabled = - state.ui.gitSync.gitStatus?.isClean || - state.ui.gitSync.isCommitting; - - if (!commitInputDisabled) { - cy.commitAndPush(); - } - - // check last deploy preview - if (state.ui.applications.currentApplication?.lastDeployedAt) { - cy.latestDeployPreview(); - cy.wait(1000); - cy.xpath("//input[@class='bp3-input' and @value='Success']").should( - "be.visible", - ); - // switch to Page1 and validate data binding - cy.get(".t--page-switch-tab") - .contains("Page1") - .click({ force: true }); - cy.xpath("//input[@class='bp3-input' and @value='Success']").should( - "be.visible", - ); - cy.get(commonlocators.backToEditor).click(); - } else if (state.ui.gitSync.isGitSyncModalOpen) { - cy.get(gitSyncLocators.closeGitSyncModal).click({ force: true }); - } + it("2. Connect app to git, clone the Page ,verify JSobject duplication should not happen and validate data binding in deploy mode and edit mode", () => { + homePage.NavigateToHome(); + cy.createWorkspace(); + cy.wait("@createWorkspace").then((interception) => { + const newWorkspaceName = interception.response.body.data.name; + cy.CreateAppForWorkspace(newWorkspaceName, "app-2"); + agHelper.AddDsl("JsObjecWithGitdsl"); + // connect app to git + gitSync.CreateNConnectToGit(); + cy.get("@gitRepoName").then((repName) => { + repoName = repName; - // verify jsObject data binding on Page 1 - PageLeftPane.switchSegment(PagePaneSegment.JS); - PageLeftPane.assertPresence(jsObject); + // create JS Object and validate its data on Page1 + jsEditor.CreateJSObject('return "Success";'); + EditorNavigation.SelectEntityByName("Page1", EntityType.Page); + cy.wait(1000); EditorNavigation.ShowCanvas(); cy.xpath("//input[@class='bp3-input' and @value='Success']").should( "be.visible", ); - // switch to Page1 copy and verify jsObject data binding - EditorNavigation.SelectEntityByName("Page1", EntityType.Page); + // clone the page1 and validate data binding + entityExplorer.ActionContextMenuByEntityName({ + entityNameinLeftSidebar: "Page1", + action: "Clone", + entityType: EntityItems.Page, + }); + cy.wait("@clonePage").should( + "have.nested.property", + "response.body.responseMeta.status", + 201, + ); PageLeftPane.switchSegment(PagePaneSegment.JS); // verify jsObject is not duplicated PageLeftPane.assertPresence(jsObject); @@ -243,40 +116,173 @@ describe("Git sync Bug #10773", { tags: ["@tag.Git"] }, function () { cy.xpath("//input[@class='bp3-input' and @value='Success']").should( "be.visible", ); + // deploy the app and validate data binding + cy.get(homePageLocators.publishButton).click(); + agHelper.AssertElementExist(gitSync._bottomBarPull); + cy.get(gitSyncLocators.commitCommentInput).type("Initial Commit"); + cy.get(gitSyncLocators.commitButton).click(); + cy.wait(8000); + cy.get(gitSyncLocators.closeGitSyncModal).click(); + cy.latestDeployPreview(); + cy.wait(2000); + cy.xpath("//input[@class='bp3-input' and @value='Success']").should( + "be.visible", + ); + // switch to Page1 and validate data binding + cy.get(".t--page-switch-tab") + .contains("Page1") + .click({ force: true }); + cy.xpath("//input[@class='bp3-input' and @value='Success']").should( + "be.visible", + ); + deployMode.NavigateBacktoEditor(); }); + }); + }); + + it("3. Bug:12724 Js objects are merged to single page when user creates a new branch", () => { + // create a new branch, clone page and validate jsObject data binding + //cy.createGitBranch(tempBranch); + cy.wait(3000); + + gitSync.CreateGitBranch(tempBranch, true); + cy.wait(2000); + EditorNavigation.SelectEntityByName("Page1", EntityType.Page); + PageLeftPane.switchSegment(PagePaneSegment.JS); + // verify jsObject is not duplicated + PageLeftPane.assertPresence(jsObject); + EditorNavigation.ShowCanvas(); + cy.xpath("//input[@class='bp3-input' and @value='Success']").should( + "be.visible", + ); + entityExplorer.ActionContextMenuByEntityName({ + entityNameinLeftSidebar: "Page1", + action: "Clone", + entityType: EntityItems.Page, + }); + cy.wait("@clonePage").should( + "have.nested.property", + "response.body.responseMeta.status", + 201, + ); gitSync.DeleteTestGithubRepo(repoName); }); - }); - it("5. Bug:13385 : Unable to see application in home page after the git connect flow is aborted in middle", () => { - homePage.NavigateToHome(); - cy.createWorkspace(); - cy.wait("@createWorkspace").then((interception) => { - const newWorkspaceName = interception.response.body.data.name; - cy.CreateAppForWorkspace(newWorkspaceName, `${newWorkspaceName}app`); + it("4. Create an app with JSObject, connect it to git and verify its data in edit and deploy mode", function () { + homePage.NavigateToHome(); + cy.createWorkspace(); + cy.wait("@createWorkspace").then((interception) => { + const newWorkspaceName = interception.response.body.data.name; + cy.CreateAppForWorkspace(newWorkspaceName, newWorkspaceName); + agHelper.AddDsl("JsObjecWithGitdsl"); + }); + // create JS Object and validate its data on Page1 + jsEditor.CreateJSObject('return "Success";'); + EditorNavigation.SelectEntityByName("Page1", EntityType.Page); + cy.wait(1000); + EditorNavigation.ShowCanvas(); + cy.xpath("//input[@class='bp3-input' and @value='Success']").should( + "be.visible", + ); + // clone the page1 and validate data binding + entityExplorer.ActionContextMenuByEntityName({ + entityNameinLeftSidebar: "Page1", + action: "Clone", + entityType: EntityItems.Page, + }); + cy.wait("@clonePage").should( + "have.nested.property", + "response.body.responseMeta.status", + 201, + ); + // connect app to git and deploy + gitSync.CreateNConnectToGit(); + cy.get("@gitRepoName").then((repName) => { + repoName = repName; + cy.wait(2000); + + cy.window() + .its("store") + .invoke("getState") + .then((state) => { + const commitInputDisabled = + state.ui.gitSync.gitStatus?.isClean || + state.ui.gitSync.isCommitting; - cy.generateUUID().then((uid) => { - repoName = uid; - gitSync.CreateTestGiteaRepo(repoName); - gitSync.OpenGitSyncModal(); + if (!commitInputDisabled) { + cy.commitAndPush(); + } - agHelper.GetNClick(gitSync.providerRadioOthers); - agHelper.GetNClick(gitSync.existingEmptyRepoYes); - agHelper.GetNClick(gitSync.gitConnectNextBtn); - agHelper.TypeText( - gitSync.remoteUrlInput, - `${dataManager.GIT_CLONE_URL}/${repoName}.git`, - ); - agHelper.GetNClick(gitSync.gitConnectNextBtn); + // check last deploy preview + if (state.ui.applications.currentApplication?.lastDeployedAt) { + cy.latestDeployPreview(); + cy.wait(1000); + cy.xpath( + "//input[@class='bp3-input' and @value='Success']", + ).should("be.visible"); + // switch to Page1 and validate data binding + cy.get(".t--page-switch-tab") + .contains("Page1") + .click({ force: true }); + cy.xpath( + "//input[@class='bp3-input' and @value='Success']", + ).should("be.visible"); + cy.get(commonlocators.backToEditor).click(); + } else if (state.ui.gitSync.isGitSyncModalOpen) { + cy.get(gitSyncLocators.closeGitSyncModal).click({ force: true }); + } - // abort git flow after generating key - cy.get(gitSyncLocators.closeGitSyncModal).click(); + // verify jsObject data binding on Page 1 + PageLeftPane.switchSegment(PagePaneSegment.JS); + PageLeftPane.assertPresence(jsObject); + EditorNavigation.ShowCanvas(); + cy.xpath("//input[@class='bp3-input' and @value='Success']").should( + "be.visible", + ); + // switch to Page1 copy and verify jsObject data binding + EditorNavigation.SelectEntityByName("Page1", EntityType.Page); + PageLeftPane.switchSegment(PagePaneSegment.JS); + // verify jsObject is not duplicated + PageLeftPane.assertPresence(jsObject); + EditorNavigation.ShowCanvas(); + cy.xpath("//input[@class='bp3-input' and @value='Success']").should( + "be.visible", + ); + }); + gitSync.DeleteTestGithubRepo(repoName); }); - // verify app is visible and open + }); + + it("5. Bug:13385 : Unable to see application in home page after the git connect flow is aborted in middle", () => { homePage.NavigateToHome(); - cy.reload(); - cy.wait(3000); - cy.SearchApp(`${newWorkspaceName}app`); + cy.createWorkspace(); + cy.wait("@createWorkspace").then((interception) => { + const newWorkspaceName = interception.response.body.data.name; + cy.CreateAppForWorkspace(newWorkspaceName, `${newWorkspaceName}app`); + + cy.generateUUID().then((uid) => { + repoName = uid; + gitSync.CreateTestGiteaRepo(repoName); + gitSync.OpenGitSyncModal(); + + agHelper.GetNClick(gitSync.providerRadioOthers); + agHelper.GetNClick(gitSync.existingEmptyRepoYes); + agHelper.GetNClick(gitSync.gitConnectNextBtn); + agHelper.TypeText( + gitSync.remoteUrlInput, + `${dataManager.GIT_CLONE_URL}/${repoName}.git`, + ); + agHelper.GetNClick(gitSync.gitConnectNextBtn); + + // abort git flow after generating key + cy.get(gitSyncLocators.closeGitSyncModal).click(); + }); + // verify app is visible and open + homePage.NavigateToHome(); + cy.reload(); + cy.wait(3000); + cy.SearchApp(`${newWorkspaceName}app`); + }); }); - }); -}); + }, +); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/Merge_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/Merge_spec.js index 2a532eec8b5..59e70823498 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/Merge_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/Merge_spec.js @@ -7,7 +7,7 @@ let childBranchKey = "ChildBranch"; let mainBranch = "master"; describe( "Git sync modal: merge tab", - { tags: ["@tag.Git", "@tag.Git"] }, + { tags: ["@tag.Git", "@tag.Git", "@tag.Sanity"] }, function () { before(() => { _.homePage.NavigateToHome(); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/SwitchBranches_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/SwitchBranches_spec.js index 93f24e1e272..b411c8b7919 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/SwitchBranches_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Git/GitSync/SwitchBranches_spec.js @@ -23,7 +23,7 @@ let parentBranchKey = "ParentBranch", branchQueryKey = "branch"; let repoName; -describe("Git sync:", { tags: ["@tag.Git"] }, function () { +describe("Git sync:", { tags: ["@tag.Git", "@tag.Sanity"] }, function () { before(() => { gitSync.CreateNConnectToGit(); cy.get("@gitRepoName").then((repName) => { diff --git a/app/client/cypress/e2e/Regression/ClientSide/Git/GitWithJSLibrary/GitwithCustomJSLibrary_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Git/GitWithJSLibrary/GitwithCustomJSLibrary_spec.js index 531da3883b7..269e4c51558 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Git/GitWithJSLibrary/GitwithCustomJSLibrary_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Git/GitWithJSLibrary/GitwithCustomJSLibrary_spec.js @@ -17,7 +17,7 @@ let repoName; describe( "Tests JS Library with Git", - { tags: ["@tag.Git", "@tag.excludeForAirgap"] }, + { tags: ["@tag.Git", "@tag.excludeForAirgap", "@tag.Sanity"] }, () => { before(() => { homePage.NavigateToHome(); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Git/GitWithTheming/GitWithTheming_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Git/GitWithTheming/GitWithTheming_spec.js index 2e1378a967b..874af31e989 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Git/GitWithTheming/GitWithTheming_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Git/GitWithTheming/GitWithTheming_spec.js @@ -2,102 +2,105 @@ import * as _ from "../../../../../support/Objects/ObjectsCore"; const widgetsPage = require("../../../../../locators/Widgets.json"); const commonlocators = require("../../../../../locators/commonlocators.json"); -describe("Git with Theming:", { tags: ["@tag.Git"] }, function () { - const backgroudColorMaster = "rgb(22, 163, 74)"; - const backgroudColorChildBranch = "rgb(100, 116, 139)"; - const tempBranch = "tempBranch"; - let repoName; - let applicationId = null; - let applicationName = null; - before(() => { - _.homePage.NavigateToHome(); - cy.createWorkspace(); - cy.wait("@createWorkspace").then((interception) => { - const newWorkspaceName = interception.response.body.data.name; - cy.generateUUID().then((uid) => { - cy.CreateAppForWorkspace(newWorkspaceName, uid); - applicationName = uid; - cy.get("@currentApplicationId").then( - (currentAppId) => (applicationId = currentAppId), - ); +describe( + "Git with Theming:", + { tags: ["@tag.Git", "@tag.Sanity"] }, + function () { + const backgroudColorMaster = "rgb(22, 163, 74)"; + const backgroudColorChildBranch = "rgb(100, 116, 139)"; + const tempBranch = "tempBranch"; + let repoName; + let applicationId = null; + let applicationName = null; + before(() => { + _.homePage.NavigateToHome(); + cy.createWorkspace(); + cy.wait("@createWorkspace").then((interception) => { + const newWorkspaceName = interception.response.body.data.name; + cy.generateUUID().then((uid) => { + cy.CreateAppForWorkspace(newWorkspaceName, uid); + applicationName = uid; + cy.get("@currentApplicationId").then( + (currentAppId) => (applicationId = currentAppId), + ); + }); }); - }); - _.gitSync.CreateNConnectToGit(); - cy.get("@gitRepoName").then((repName) => { - repoName = repName; - _.gitSync.CreateGitBranch(repoName); + _.gitSync.CreateNConnectToGit(); + cy.get("@gitRepoName").then((repName) => { + repoName = repName; + _.gitSync.CreateGitBranch(repoName); + }); }); - }); - it("1. Bug #13860 Theming is not getting applied on view mode when the app is connected to Git", function () { - _.appSettings.OpenAppSettings(); - _.appSettings.GoToThemeSettings(); - // apply theme on master branch and deploy - cy.get(commonlocators.changeThemeBtn).click({ force: true }); + it("1. Bug #13860 Theming is not getting applied on view mode when the app is connected to Git", function () { + _.appSettings.OpenAppSettings(); + _.appSettings.GoToThemeSettings(); + // apply theme on master branch and deploy + cy.get(commonlocators.changeThemeBtn).click({ force: true }); - cy.get(commonlocators.themeCard).eq(1).click({ force: true }); + cy.get(commonlocators.themeCard).eq(1).click({ force: true }); - // check for alert - cy.get(`${commonlocators.themeCard}`) - .eq(1) - .siblings("div") - .first() - .invoke("text") - .then((text) => { - cy.get(commonlocators.toastmsg).contains(`Theme ${text} applied`); - }); - _.appSettings.ClosePane(); - // drag a widget and assert theme is applied - cy.dragAndDropToCanvas("buttonwidget", { x: 300, y: 700 }); - //cy.get('.t--draggable-buttonwidget').closest("div").should('have.css' , 'background-color', backgroudColorChildBranch) - cy.get(widgetsPage.widgetBtn).should( - "have.css", - "background-color", - backgroudColorMaster, - ); //Widget Color - cy.commitAndPush(); - cy.wait(2000); - _.gitSync.CreateGitBranch(tempBranch); - //cy.createGitBranch(tempBranch); - cy.wait(1000); - cy.get(".canvas").click(0, 0, { force: true }); - // change theme on tempBranch - _.appSettings.OpenAppSettings(); - _.appSettings.GoToThemeSettings(); - cy.get(commonlocators.changeThemeBtn).click({ force: true }); + // check for alert + cy.get(`${commonlocators.themeCard}`) + .eq(1) + .siblings("div") + .first() + .invoke("text") + .then((text) => { + cy.get(commonlocators.toastmsg).contains(`Theme ${text} applied`); + }); + _.appSettings.ClosePane(); + // drag a widget and assert theme is applied + cy.dragAndDropToCanvas("buttonwidget", { x: 300, y: 700 }); + //cy.get('.t--draggable-buttonwidget').closest("div").should('have.css' , 'background-color', backgroudColorChildBranch) + cy.get(widgetsPage.widgetBtn).should( + "have.css", + "background-color", + backgroudColorMaster, + ); //Widget Color + cy.commitAndPush(); + cy.wait(2000); + _.gitSync.CreateGitBranch(tempBranch); + //cy.createGitBranch(tempBranch); + cy.wait(1000); + cy.get(".canvas").click(0, 0, { force: true }); + // change theme on tempBranch + _.appSettings.OpenAppSettings(); + _.appSettings.GoToThemeSettings(); + cy.get(commonlocators.changeThemeBtn).click({ force: true }); - // select a theme - cy.get(commonlocators.themeCard).last().click({ force: true }); + // select a theme + cy.get(commonlocators.themeCard).last().click({ force: true }); - // check for alert - cy.get(`${commonlocators.themeCard}`) - .last() - .siblings("div") - .first() - .invoke("text") - .then((text) => { - cy.get(commonlocators.toastmsg).contains(`Theme ${text} applied`); - }); - _.appSettings.ClosePane(); + // check for alert + cy.get(`${commonlocators.themeCard}`) + .last() + .siblings("div") + .first() + .invoke("text") + .then((text) => { + cy.get(commonlocators.toastmsg).contains(`Theme ${text} applied`); + }); + _.appSettings.ClosePane(); - cy.get(widgetsPage.widgetBtn).should( - "have.css", - "background-color", - backgroudColorChildBranch, - ); //Widget Color - cy.commitAndPush(); - //assert theme is applied in view mode - cy.latestDeployPreview(); - cy.get(widgetsPage.widgetBtn).should( - "have.css", - "background-color", - backgroudColorChildBranch, - ); //Widget Color - cy.get(commonlocators.backToEditor).click(); - cy.wait(2000); - }); - // commenting test until bug is closed - /*it("Bug #14645 Custom themes are not getting copied for create branch", function() { + cy.get(widgetsPage.widgetBtn).should( + "have.css", + "background-color", + backgroudColorChildBranch, + ); //Widget Color + cy.commitAndPush(); + //assert theme is applied in view mode + cy.latestDeployPreview(); + cy.get(widgetsPage.widgetBtn).should( + "have.css", + "background-color", + backgroudColorChildBranch, + ); //Widget Color + cy.get(commonlocators.backToEditor).click(); + cy.wait(2000); + }); + // commenting test until bug is closed + /*it("Bug #14645 Custom themes are not getting copied for create branch", function() { cy.xpath("(//button[@type='button'])").should( "have.css", "background-color", @@ -132,8 +135,9 @@ describe("Git with Theming:", { tags: ["@tag.Git"] }, function () { ); }); */ - after(() => { - //clean up - _.gitSync.DeleteTestGithubRepo(repoName); - }); -}); + after(() => { + //clean up + _.gitSync.DeleteTestGithubRepo(repoName); + }); + }, +); diff --git a/app/client/cypress/e2e/Regression/ClientSide/OneClickBinding/JSONFormWidget/JSONForm_mongoDB_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/OneClickBinding/JSONFormWidget/JSONForm_mongoDB_spec.ts index 1c9184f7f8b..8672687d16e 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/OneClickBinding/JSONFormWidget/JSONForm_mongoDB_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/OneClickBinding/JSONFormWidget/JSONForm_mongoDB_spec.ts @@ -18,7 +18,7 @@ const oneClickBinding = new OneClickBinding(); describe( "JSONForm widget one click binding feature", - { tags: ["@tag.Binding"] }, + { tags: ["@tag.Binding", "@tag.Sanity"] }, () => { let datasourceName: string; it("1.Create flow: should check that queries are created and bound to jsonform widget properly", () => { diff --git a/app/client/cypress/e2e/Regression/ClientSide/OneClickBinding/SelectWidget/mongoDB_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/OneClickBinding/SelectWidget/mongoDB_spec.ts index e60d5cebc10..c98992a6918 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/OneClickBinding/SelectWidget/mongoDB_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/OneClickBinding/SelectWidget/mongoDB_spec.ts @@ -19,7 +19,7 @@ const oneClickBinding = new OneClickBinding(); describe( "Table widget one click binding feature", - { tags: ["@tag.Binding"] }, + { tags: ["@tag.Binding", "@tag.Sanity"] }, () => { it("should check that queries are created and bound to table widget properly", () => { entityExplorer.DragDropWidgetNVerify(draggableWidgets.SELECT, 450, 200); diff --git a/app/client/cypress/e2e/Regression/ClientSide/OneClickBinding/SelectWidget/postgres_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/OneClickBinding/SelectWidget/postgres_spec.ts index d3418f256af..19c32a3ce65 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/OneClickBinding/SelectWidget/postgres_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/OneClickBinding/SelectWidget/postgres_spec.ts @@ -19,7 +19,7 @@ const oneClickBinding = new OneClickBinding(); describe( "Table widget one click binding feature", - { tags: ["@tag.Binding"] }, + { tags: ["@tag.Binding", "@tag.Sanity"] }, () => { it("should check that queries are created and bound to table widget properly", () => { entityExplorer.DragDropWidgetNVerify(draggableWidgets.SELECT, 450, 200); diff --git a/app/client/cypress/e2e/Regression/ClientSide/OneClickBinding/TableWidget/Table_postgres_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/OneClickBinding/TableWidget/Table_postgres_spec.ts index 456de842c93..2afc1985b6d 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/OneClickBinding/TableWidget/Table_postgres_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/OneClickBinding/TableWidget/Table_postgres_spec.ts @@ -16,7 +16,7 @@ const oneClickBinding = new OneClickBinding(); describe( "Table widget one click binding feature", - { tags: ["@tag.Binding"] }, + { tags: ["@tag.Binding", "@tag.Sanity"] }, () => { it("should check that queries are created and bound to table widget properly", () => { entityExplorer.DragDropWidgetNVerify(draggableWidgets.TABLE, 450, 200); diff --git a/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/ErrorMessages_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/ErrorMessages_spec.ts index 6bc10f52d43..673fda46d38 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/ErrorMessages_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/ErrorMessages_spec.ts @@ -3,7 +3,7 @@ import EditorNavigation, { EntityType, } from "../../../../support/Pages/EditorNavigation"; -describe("Sanitise toast error messages", () => { +describe("Sanitise toast error messages", { tags: ["@tag.JS"] }, () => { before(() => { _.jsEditor.CreateJSObject( `export default { diff --git a/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/GlobalSearch_spec.js b/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/GlobalSearch_spec.js index 80ed386debd..d719772fe1c 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/GlobalSearch_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/GlobalSearch_spec.js @@ -13,7 +13,7 @@ const datasourceHomeLocators = require("../../../../locators/apiWidgetslocator.j const datasourceLocators = require("../../../../locators/DatasourcesEditor.json"); import * as _ from "../../../../support/Objects/ObjectsCore"; -describe("GlobalSearch", function () { +describe("GlobalSearch", { tags: ["@tag.Sanity"] }, function () { before(() => { _.agHelper.AddDsl("MultipleWidgetDsl"); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/Inspect_Element_spec.js b/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/Inspect_Element_spec.js index b4f51bc7282..5e5adb4afa4 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/Inspect_Element_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/Inspect_Element_spec.js @@ -1,15 +1,19 @@ import * as _ from "../../../../support/Objects/ObjectsCore"; -describe("Inspect Entity", function () { - before(() => { - _.agHelper.AddDsl("debuggerDependencyDsl"); - }); - it("1. Check whether depedencies and references are shown correctly", function () { - cy.openPropertyPane("inputwidgetv2"); - cy.testJsontext("defaultvalue", "{{Button1.text}}"); - _.debuggerHelper.OpenDebugger(); - cy.contains(".ads-v2-tabs__list-tab", "Inspect entity").click(); - cy.contains(".t--dependencies-item", "Button1").click(); - cy.contains(".t--dependencies-item", "Input1"); - }); -}); +describe( + "Inspect Entity", + { tags: ["@tag.Widget", "@tag.PropertyPane"] }, + function () { + before(() => { + _.agHelper.AddDsl("debuggerDependencyDsl"); + }); + it("1. Check whether depedencies and references are shown correctly", function () { + cy.openPropertyPane("inputwidgetv2"); + cy.testJsontext("defaultvalue", "{{Button1.text}}"); + _.debuggerHelper.OpenDebugger(); + cy.contains(".ads-v2-tabs__list-tab", "Inspect entity").click(); + cy.contains(".t--dependencies-item", "Button1").click(); + cy.contains(".t--dependencies-item", "Input1"); + }); + }, +); diff --git a/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/Logs1_spec.js b/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/Logs1_spec.js index 42b84b43474..a6aa206e83a 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/Logs1_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/Logs1_spec.js @@ -19,7 +19,7 @@ const generateTestLogString = () => { return logString; }; -describe("Debugger logs", function () { +describe("Debugger logs", { tags: ["@tag.Widget", "@tag.IDE"] }, function () { this.beforeEach(() => { logString = generateTestLogString(); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/PageOnLoad_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/PageOnLoad_spec.ts index 30f17147ebe..7a0ddf08e3e 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/PageOnLoad_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/PageOnLoad_spec.ts @@ -8,21 +8,25 @@ import { } from "../../../../support/Objects/ObjectsCore"; const testdata = require("../../../../fixtures/testdata.json"); -describe("Check debugger logs state when there are onPageLoad actions", function () { - before(() => { - agHelper.AddDsl("debuggerTableDsl"); - }); +describe( + "Check debugger logs state when there are onPageLoad actions", + { tags: ["@tag.IDE", "@tag.Datasource"] }, + function () { + before(() => { + agHelper.AddDsl("debuggerTableDsl"); + }); - it("1. Check debugger logs state when there are onPageLoad actions", function () { - EditorNavigation.SelectEntityByName("Table1", EntityType.Widget); - apiPage.CreateAndFillApi(testdata.baseUrl + testdata.methods, "TestApi"); - apiPage.RunAPI(); - EditorNavigation.ShowCanvas(); - agHelper.RefreshPage(); - // Wait for the debugger icon to be visible - agHelper.AssertElementVisibility(".t--debugger-count"); - // debuggerHelper.isErrorCount(0); - cy.wait("@postExecute"); - debuggerHelper.AssertErrorCount(1); - }); -}); + it("1. Check debugger logs state when there are onPageLoad actions", function () { + EditorNavigation.SelectEntityByName("Table1", EntityType.Widget); + apiPage.CreateAndFillApi(testdata.baseUrl + testdata.methods, "TestApi"); + apiPage.RunAPI(); + EditorNavigation.ShowCanvas(); + agHelper.RefreshPage(); + // Wait for the debugger icon to be visible + agHelper.AssertElementVisibility(".t--debugger-count"); + // debuggerHelper.isErrorCount(0); + cy.wait("@postExecute"); + debuggerHelper.AssertErrorCount(1); + }); + }, +); diff --git a/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/PreviewMode_spec.js b/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/PreviewMode_spec.js index 4d6b64fe5bf..6370ecf2866 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/PreviewMode_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/PreviewMode_spec.js @@ -4,43 +4,47 @@ const commonlocators = require("../../../../locators/commonlocators.json"); const publishPage = require("../../../../locators/publishWidgetspage.json"); import * as _ from "../../../../support/Objects/ObjectsCore"; -describe("Preview mode functionality", { tags: ["@tag.IDE"] }, function () { - before(() => { - _.agHelper.AddDsl("previewMode"); - }); - - it("1. Checks entity explorer and property pane visiblity", function () { - _.agHelper.GetNClick(_.locators._previewModeToggle("edit")); - // in preview mode, entity explorer and property pane are not visible - cy.get(PageLeftPane.locators.selector).should("not.be.visible"); - cy.get(".t--property-pane-sidebar").should("not.be.visible"); - - //checks if widgets can be selected or not - // in preview mode, entity explorer and property pane are not visible - // Also, draggable and resizable components are not available. - const selector = `.t--draggable-buttonwidget`; - cy.wait(500); - cy.get(selector).first().trigger("mouseover", { force: true }).wait(500); - - cy.get( - `${selector}:first-of-type .t--widget-propertypane-toggle > .t--widget-name`, - ).should("not.exist"); - }); - - it("2. Check invisible widget should not show in proview mode and should show in edit mode", function () { - _.agHelper.GetNClick(_.locators._previewModeToggle("preview")); - cy.openPropertyPane("buttonwidget"); - cy.UncheckWidgetProperties(commonlocators.visibleCheckbox); - - // button should not show in preview mode - _.agHelper.GetNClick(_.locators._previewModeToggle("edit")); - cy.get(`${publishPage.buttonWidget} button`).should("not.exist"); - - // Text widget should show - cy.get(`${publishPage.textWidget} .bp3-ui-text`).should("exist"); - - // button should show in edit mode - _.agHelper.GetNClick(_.locators._previewModeToggle("preview")); - cy.get(`${publishPage.buttonWidget} button`).should("exist"); - }); -}); +describe( + "Preview mode functionality", + { tags: ["@tag.IDE", "@tag.Sanity"] }, + function () { + before(() => { + _.agHelper.AddDsl("previewMode"); + }); + + it("1. Checks entity explorer and property pane visiblity", function () { + _.agHelper.GetNClick(_.locators._previewModeToggle("edit")); + // in preview mode, entity explorer and property pane are not visible + cy.get(PageLeftPane.locators.selector).should("not.be.visible"); + cy.get(".t--property-pane-sidebar").should("not.be.visible"); + + //checks if widgets can be selected or not + // in preview mode, entity explorer and property pane are not visible + // Also, draggable and resizable components are not available. + const selector = `.t--draggable-buttonwidget`; + cy.wait(500); + cy.get(selector).first().trigger("mouseover", { force: true }).wait(500); + + cy.get( + `${selector}:first-of-type .t--widget-propertypane-toggle > .t--widget-name`, + ).should("not.exist"); + }); + + it("2. Check invisible widget should not show in proview mode and should show in edit mode", function () { + _.agHelper.GetNClick(_.locators._previewModeToggle("preview")); + cy.openPropertyPane("buttonwidget"); + cy.UncheckWidgetProperties(commonlocators.visibleCheckbox); + + // button should not show in preview mode + _.agHelper.GetNClick(_.locators._previewModeToggle("edit")); + cy.get(`${publishPage.buttonWidget} button`).should("not.exist"); + + // Text widget should show + cy.get(`${publishPage.textWidget} .bp3-ui-text`).should("exist"); + + // button should show in edit mode + _.agHelper.GetNClick(_.locators._previewModeToggle("preview")); + cy.get(`${publishPage.buttonWidget} button`).should("exist"); + }); + }, +); diff --git a/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/Replay_Editor_spec.js b/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/Replay_Editor_spec.js index 872c252556a..dd5b11c69ed 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/Replay_Editor_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/Replay_Editor_spec.js @@ -9,142 +9,151 @@ import { dataSources, } from "../../../../support/Objects/ObjectsCore"; -describe("Undo/Redo functionality", function () { - const modifierKey = Cypress.platform === "darwin" ? "meta" : "ctrl"; - let postgresDatasourceName; +describe( + "Undo/Redo functionality", + { tags: ["@tag.JS", "@tag.Datasource"] }, + function () { + const modifierKey = Cypress.platform === "darwin" ? "meta" : "ctrl"; + let postgresDatasourceName; - it("1. Checks undo/redo in datasource forms", () => { - dataSources.NavigateToDSCreateNew(); - agHelper.GetNClick(datasource.PostgreSQL); - cy.generateUUID().then((uid) => { - postgresDatasourceName = uid; + it("1. Checks undo/redo in datasource forms", () => { + dataSources.NavigateToDSCreateNew(); + agHelper.GetNClick(datasource.PostgreSQL); + cy.generateUUID().then((uid) => { + postgresDatasourceName = uid; - cy.get(".t--edit-datasource-name").click(); - cy.get(".t--edit-datasource-name input") - .clear() - .type(postgresDatasourceName, { force: true }) - .should("have.value", postgresDatasourceName) - .blur(); + cy.get(".t--edit-datasource-name").click(); + cy.get(".t--edit-datasource-name input") + .clear() + .type(postgresDatasourceName, { force: true }) + .should("have.value", postgresDatasourceName) + .blur(); - cy.get(datasourceEditor.sectionAuthentication).click(); - cy.get(datasourceEditor.username).type( - datasourceFormData["postgres-username"], + cy.get(datasourceEditor.sectionAuthentication).click(); + cy.get(datasourceEditor.username).type( + datasourceFormData["postgres-username"], + ); + cy.wait(500); + cy.get(datasourceEditor.password).type( + datasourceFormData["postgres-password"], + ); + //cy.get(datasourceEditor.sectionAuthentication).trigger("click").wait(1000); + + cy.get("body").type(`{${modifierKey}}z`); + cy.get("body").type(`{${modifierKey}}{shift}z`); + cy.get(datasourceEditor.saveBtn).click({ force: true }); + dataSources.AssertDSInActiveList(postgresDatasourceName); + }); + }); + + it("2. Checks undo/redo for Api pane", function () { + cy.CreateAPI("FirstAPI"); + cy.get(`${apiwidget.resourceUrl} .CodeMirror-placeholder`).should( + "have.text", + "https://mock-api.appsmith.com/users", //testing placeholder! ); - cy.wait(500); - cy.get(datasourceEditor.password).type( - datasourceFormData["postgres-password"], + cy.enterDatasourceAndPath(testdata.baseUrl, testdata.methods); + agHelper.RemoveUIElement( + "Tooltip", + Cypress.env("MESSAGES").ADD_QUERY_JS_TOOLTIP(), ); - //cy.get(datasourceEditor.sectionAuthentication).trigger("click").wait(1000); - + cy.get(`${apiwidget.headerKey}`).type("Authorization"); + cy.get("body").click(0, 0); + cy.get(apiwidget.settings).click({ force: true }); + //cy.get(apiwidget.onPageLoad).click({ force: true }); + cy.get("body").click(0, 0); cy.get("body").type(`{${modifierKey}}z`); + // cy.wait(2000); + // cy.get("body").type(`{${modifierKey}}z`); + cy.wait(2000); + cy.get("body").click(0, 0); + cy.get("body").type(`{${modifierKey}}z`); + cy.get(apiwidget.headers) + .parent() + .should("have.attr", "aria-selected", "true"); + cy.get("body").type(`{${modifierKey}}z`); + + cy.get(`${apiwidget.resourceUrl} .CodeMirror-placeholder`).should( + "have.text", + "https://mock-api.appsmith.com/users", + ); + cy.get(`${apiwidget.headerKey} .CodeMirror-placeholder`).should( + "have.text", + "Key 1", + ); cy.get("body").type(`{${modifierKey}}{shift}z`); - cy.get(datasourceEditor.saveBtn).click({ force: true }); - dataSources.AssertDSInActiveList(postgresDatasourceName); + cy.get("body").type(`{${modifierKey}}{shift}z`); + cy.get(`${apiwidget.headerKey} .cm-m-null`).should( + "have.text", + "Authorization", + ); }); - }); - it("2. Checks undo/redo for Api pane", function () { - cy.CreateAPI("FirstAPI"); - cy.get(`${apiwidget.resourceUrl} .CodeMirror-placeholder`).should( - "have.text", - "https://mock-api.appsmith.com/users", //testing placeholder! - ); - cy.enterDatasourceAndPath(testdata.baseUrl, testdata.methods); - agHelper.RemoveUIElement( - "Tooltip", - Cypress.env("MESSAGES").ADD_QUERY_JS_TOOLTIP(), - ); - cy.get(`${apiwidget.headerKey}`).type("Authorization"); - cy.get("body").click(0, 0); - cy.get(apiwidget.settings).click({ force: true }); - //cy.get(apiwidget.onPageLoad).click({ force: true }); - cy.get("body").click(0, 0); - cy.get("body").type(`{${modifierKey}}z`); - // cy.wait(2000); - // cy.get("body").type(`{${modifierKey}}z`); - cy.wait(2000); - cy.get("body").click(0, 0); - cy.get("body").type(`{${modifierKey}}z`); - cy.get(apiwidget.headers) - .parent() - .should("have.attr", "aria-selected", "true"); - cy.get("body").type(`{${modifierKey}}z`); + it("3. Checks undo/redo in query editor", () => { + dataSources.CreateQueryForDS(postgresDatasourceName); + cy.get(".CodeMirror textarea").first().focus().type("{{FirstAPI}}", { + force: true, + parseSpecialCharSequences: false, + }); + cy.get("body").click(0, 0); - cy.get(`${apiwidget.resourceUrl} .CodeMirror-placeholder`).should( - "have.text", - "https://mock-api.appsmith.com/users", - ); - cy.get(`${apiwidget.headerKey} .CodeMirror-placeholder`).should( - "have.text", - "Key 1", - ); - cy.get("body").type(`{${modifierKey}}{shift}z`); - cy.get("body").type(`{${modifierKey}}{shift}z`); - cy.get(`${apiwidget.headerKey} .cm-m-null`).should( - "have.text", - "Authorization", - ); - }); + // Removed the verification of relationships as we have removed the `Relationships` element from the new bindings UI - it("3. Checks undo/redo in query editor", () => { - dataSources.CreateQueryForDS(postgresDatasourceName); - cy.get(".CodeMirror textarea").first().focus().type("{{FirstAPI}}", { - force: true, - parseSpecialCharSequences: false, + cy.get("body").type(`{${modifierKey}}z`); + cy.get(".CodeEditorTarget textarea").should( + "not.have.text", + "{{FirstAPI}}", + ); + cy.get("body").type(`{${modifierKey}}{shift}z`); + cy.get(".CodeMirror-code span").contains("{{FirstAPI}}"); + cy.get("body").type(`{${modifierKey}}z`); + cy.get(".CodeMirror-code span") + .last() + .should("not.have.text", "{{FirstAPI}}"); }); - cy.get("body").click(0, 0); - - // Removed the verification of relationships as we have removed the `Relationships` element from the new bindings UI - cy.get("body").type(`{${modifierKey}}z`); - cy.get(".CodeEditorTarget textarea").should( - "not.have.text", - "{{FirstAPI}}", - ); - cy.get("body").type(`{${modifierKey}}{shift}z`); - cy.get(".CodeMirror-code span").contains("{{FirstAPI}}"); - cy.get("body").type(`{${modifierKey}}z`); - cy.get(".CodeMirror-code span") - .last() - .should("not.have.text", "{{FirstAPI}}"); - }); - - it("4. Checks undo/redo in JS Objects", () => { - jsEditor.NavigateToNewJSEditor(); - cy.wait(1000); - cy.get(".CodeMirror textarea") - .first() - .focus() - .type("{downarrow}{downarrow}{downarrow} ") - .type("testJSFunction:()=>{},"); - cy.get("body").type(`{${modifierKey}}z{${modifierKey}}z{${modifierKey}}z`); - // verifying testJSFunction is not visible on page after undo - cy.contains("testJSFunction").should("not.exist"); - cy.get("body").type( - `{${modifierKey}}{shift}z{${modifierKey}}{shift}z{${modifierKey}}{shift}z`, - ); - // verifying testJSFunction is visible on page after redo - cy.contains("testJSFunction").should("exist"); - cy.get("body").type(`{${modifierKey}}z`); - // cy.get(".function-name").should("not.contain.text", "test"); - }); + it("4. Checks undo/redo in JS Objects", () => { + jsEditor.NavigateToNewJSEditor(); + cy.wait(1000); + cy.get(".CodeMirror textarea") + .first() + .focus() + .type("{downarrow}{downarrow}{downarrow} ") + .type("testJSFunction:()=>{},"); + cy.get("body").type( + `{${modifierKey}}z{${modifierKey}}z{${modifierKey}}z`, + ); + // verifying testJSFunction is not visible on page after undo + cy.contains("testJSFunction").should("not.exist"); + cy.get("body").type( + `{${modifierKey}}{shift}z{${modifierKey}}{shift}z{${modifierKey}}{shift}z`, + ); + // verifying testJSFunction is visible on page after redo + cy.contains("testJSFunction").should("exist"); + cy.get("body").type(`{${modifierKey}}z`); + // cy.get(".function-name").should("not.contain.text", "test"); + }); - it("5. Checks undo/redo for Authenticated APIs", () => { - cy.NavigateToAPI_Panel(); - cy.get(apiwidget.createAuthApiDatasource).click({ force: true }); - cy.wait(2000); - agHelper.TypeText(dataSources._headerKey, testdata.headerKey); - agHelper.TypeText(dataSources._urlInputControl, testdata.baseUrl); - agHelper.Sleep(1000); - cy.get("body").click(0, 0); - cy.get("body").type(`{${modifierKey}}z`); - cy.get("input[name='url']").should("have.value", ""); - cy.get("body").type(`{${modifierKey}}z`); - cy.get("input[name='headers[0].key']").should("have.value", ""); - cy.get("body").click(0, 0); - cy.get("body").type(`{${modifierKey}}{shift}z`); - cy.get("body").type(`{${modifierKey}}{shift}z`); - cy.get("input[name='url']").should("have.value", testdata.baseUrl); - cy.get("input[name='headers[0].key']").should("have.value", "Content-Type"); - }); -}); + it("5. Checks undo/redo for Authenticated APIs", () => { + cy.NavigateToAPI_Panel(); + cy.get(apiwidget.createAuthApiDatasource).click({ force: true }); + cy.wait(2000); + agHelper.TypeText(dataSources._headerKey, testdata.headerKey); + agHelper.TypeText(dataSources._urlInputControl, testdata.baseUrl); + agHelper.Sleep(1000); + cy.get("body").click(0, 0); + cy.get("body").type(`{${modifierKey}}z`); + cy.get("input[name='url']").should("have.value", ""); + cy.get("body").type(`{${modifierKey}}z`); + cy.get("input[name='headers[0].key']").should("have.value", ""); + cy.get("body").click(0, 0); + cy.get("body").type(`{${modifierKey}}{shift}z`); + cy.get("body").type(`{${modifierKey}}{shift}z`); + cy.get("input[name='url']").should("have.value", testdata.baseUrl); + cy.get("input[name='headers[0].key']").should( + "have.value", + "Content-Type", + ); + }); + }, +); diff --git a/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/Replay_spec.js b/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/Replay_spec.js index b5709cf3db8..f4c9e6fec7e 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/Replay_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/Replay_spec.js @@ -12,208 +12,214 @@ import EditorNavigation, { EntityType, } from "../../../../support/Pages/EditorNavigation"; -describe("Undo/Redo functionality", function () { - const modifierKey = Cypress.platform === "darwin" ? "meta" : "ctrl"; - - before(() => { - agHelper.AddDsl("replay"); - }); - - it("1. checks undo/redo for new widgets", function () { - entityExplorer.DragDropWidgetNVerify(draggableWidgets.CHECKBOX, 200, 200); - cy.focused().blur(); - - cy.get(widgetsPage.checkboxWidget).should("exist"); - - cy.get("body").type(`{${modifierKey}}z`); - cy.wait(100); - cy.get(widgetsPage.checkboxWidget).should("not.exist"); - - cy.get("body").type(`{${modifierKey}}{shift}z`); - cy.wait(100); - cy.get(widgetsPage.checkboxWidget).should("exist"); - }); - - // it("checks moving of widgets", function() { - // cy.document().then((doc) => { - // const initialPosition = doc - // .querySelector(widgetsPage.checkboxWidget) - // .getBoundingClientRect(); - - // cy.get(commonlocators.editIcon) - // .trigger("mousedown", { which: 1 }) - // .trigger("dragstart", { force: true }); - - // cy.get(explorer.dropHere) - // .trigger("mousemove", 200, 300, { eventConstructor: "MouseEvent" }) - // .trigger("mousemove", 200, 300, { eventConstructor: "MouseEvent" }) - // .trigger("mouseup", 200, 300, { eventConstructor: "MouseEvent" }); - - // cy.wait(1000).then(() => { - // const positionAfterChange = doc - // .querySelector(widgetsPage.checkboxWidget) - // .getBoundingClientRect(); - - // expect(positionAfterChange.top).to.not.equal(initialPosition.top); - // }); - - // cy.get("body").type(`{${modifierKey}}z`); - - // cy.wait(1000).then(() => { - // const positionAfterUndo = doc - // .querySelector(widgetsPage.checkboxWidget) - // .getBoundingClientRect(); - - // expect(positionAfterUndo.top).to.equal(initialPosition.top); - // }); - - // cy.get("body").type(`{${modifierKey}}{shift}z`); - - // cy.wait(1000).then(() => { - // const positionAfterRedo = doc - // .querySelector(widgetsPage.checkboxWidget) - // .getBoundingClientRect(); - - // expect(positionAfterRedo.top).to.equal(initialPosition.top); - // }); - // }); - // }); - - it("2. checks undo/redo for toggle control in property pane", function () { - cy.openPropertyPane("checkboxwidget"); - cy.CheckWidgetProperties(commonlocators.disableCheckbox); - - cy.get("body").type(`{${modifierKey}}z`); - cy.wait(100); - cy.get(`${widgetsPage.disable} input`).should("not.be.checked"); - cy.get(widgetLocators.checkboxWidget + " " + "input").should( - "not.be.disabled", - ); - - cy.get("body").type(`{${modifierKey}}{shift}z`); - cy.wait(100); - - cy.get(`${widgetsPage.disable} input`).should("be.checked"); - cy.get(widgetLocators.checkboxWidget + " " + "input").should("be.disabled"); - }); - - it("3. checks undo/redo for input control in property pane", function () { - cy.get(widgetsPage.inputLabelControl).type("1"); - cy.get(widgetsPage.inputLabelControl).contains("Label1"); - - cy.get("body").type(`{${modifierKey}}z`); - cy.wait(100); - cy.get(widgetsPage.inputLabelControl).contains("Label"); - cy.get(`${publish.checkboxWidget} label`).should("have.text", "Label"); - - cy.get("body").type(`{${modifierKey}}{shift}z`); - cy.wait(100); - cy.get(widgetsPage.inputLabelControl).contains("Label1"); - cy.get(`${publish.checkboxWidget} label`).should("have.text", "Label1"); - }); - - it("4. checks undo/redo for deletion of widgets", function () { - cy.deleteWidget(widgetsPage.checkboxWidget); - cy.get(widgetsPage.checkboxWidget).should("not.exist"); - - cy.get("body").type(`{${modifierKey}}z`); - cy.wait(100); - cy.get(widgetsPage.checkboxWidget).should("exist"); - - // cy.get("body").type(`{${modifierKey}}{shift}z`); - // cy.wait(100); - // cy.get(widgetsPage.checkboxWidget).should("not.exist"); - }); - - it("5. checks if property Pane is open on undo/redo property changes", function () { - cy.dragAndDropToCanvas("textwidget", { x: 400, y: 400 }); - - cy.wait(100); - propPane.UpdatePropertyFieldValue("Text", "Label"); - - cy.closePropertyPane(); - - cy.get("body").type(`{${modifierKey}}z`); - cy.wait(100); - cy.get(widgetsPage.propertypaneText).should("exist"); - cy.get(widgetsPage.inputTextControl).contains( - "Hello {{appsmith.user.name || appsmith.user.email}}", - ); - - cy.closePropertyPane(); - - cy.get("body").type(`{${modifierKey}}{shift}z`); - cy.wait(100); - cy.get(widgetsPage.propertypaneText).should("exist"); - cy.get(widgetsPage.inputTextControl).contains("Label"); - cy.deleteWidget(widgetsPage.textWidget); - }); - - it("6. checks if toast is shown while undo/redo widget deletion or creation only the first time", function () { - cy.dragAndDropToCanvas("textwidget", { x: 400, y: 400 }); - localStorage.removeItem("undoToastShown"); - localStorage.removeItem("redoToastShown"); - - cy.get("body").type(`{${modifierKey}}z`); - cy.get(commonlocators.toastmsg).contains("is removed"); - cy.get(commonlocators.toastmsg).contains("redo"); - cy.get(commonlocators.toastBody).first().click({ force: true }); - - cy.wait(100); - cy.get("body").type(`{${modifierKey}}{shift}z`); - cy.get(commonlocators.toastmsg).contains("is added back"); - cy.get(commonlocators.toastmsg).contains("undo"); - cy.deleteWidget(widgetsPage.textWidget); - }); - - it("7. checks undo/redo for color picker", function () { - cy.dragAndDropToCanvas("textwidget", { x: 100, y: 100 }); - cy.moveToStyleTab(); - cy.selectColor("textcolor"); - cy.get("body").click({ force: true }); - // eslint-disable-next-line cypress/no-unnecessary-waiting - cy.wait(500); - cy.wait("@updateLayout"); - cy.readTextDataValidateCSS("color", "rgb(219, 234, 254)"); - cy.get("body").click({ force: true }).type(`{${modifierKey}}z`); - EditorNavigation.SelectEntityByName("Text1", EntityType.Widget); - propPane.MoveToTab("Style"); - cy.get(widgetsPage.textColor) - .first() - .invoke("attr", "value") - .should("contain", "#231F20"); - - cy.get("body").type(`{${modifierKey}}{shift}z`); - EditorNavigation.SelectEntityByName("Text1", EntityType.Widget); - propPane.MoveToTab("Style"); - cy.get(widgetsPage.textColor) - .first() - .invoke("attr", "value") - .should("contain", "#dbeafe"); - }); - - it("8. checks undo/redo for option control for radio button", function () { - cy.dragAndDropToCanvas("radiogroupwidget", { x: 200, y: 600 }); - - cy.get(widgetsPage.RadioInput).first().type("1"); - - cy.get(widgetsPage.RadioInput).first().blur(); - - // eslint-disable-next-line cypress/no-unnecessary-waiting - cy.wait(200); - - cy.get("body").type(`{${modifierKey}}z`); - EditorNavigation.SelectEntityByName("RadioGroup1", EntityType.Widget); - cy.get(widgetsPage.RadioInput) - .first() - .invoke("attr", "value") - .should("contain", "Yes"); - - cy.get("body").type(`{${modifierKey}}{shift}z`); - EditorNavigation.SelectEntityByName("RadioGroup1", EntityType.Widget); - cy.get(widgetsPage.RadioInput) - .first() - .invoke("attr", "value") - .should("contain", "Yes1"); - }); -}); +describe( + "Undo/Redo functionality", + { tags: ["@tag.Widget", "@tag.PropertyPane"] }, + function () { + const modifierKey = Cypress.platform === "darwin" ? "meta" : "ctrl"; + + before(() => { + agHelper.AddDsl("replay"); + }); + + it("1. checks undo/redo for new widgets", function () { + entityExplorer.DragDropWidgetNVerify(draggableWidgets.CHECKBOX, 200, 200); + cy.focused().blur(); + + cy.get(widgetsPage.checkboxWidget).should("exist"); + + cy.get("body").type(`{${modifierKey}}z`); + cy.wait(100); + cy.get(widgetsPage.checkboxWidget).should("not.exist"); + + cy.get("body").type(`{${modifierKey}}{shift}z`); + cy.wait(100); + cy.get(widgetsPage.checkboxWidget).should("exist"); + }); + + // it("checks moving of widgets", function() { + // cy.document().then((doc) => { + // const initialPosition = doc + // .querySelector(widgetsPage.checkboxWidget) + // .getBoundingClientRect(); + + // cy.get(commonlocators.editIcon) + // .trigger("mousedown", { which: 1 }) + // .trigger("dragstart", { force: true }); + + // cy.get(explorer.dropHere) + // .trigger("mousemove", 200, 300, { eventConstructor: "MouseEvent" }) + // .trigger("mousemove", 200, 300, { eventConstructor: "MouseEvent" }) + // .trigger("mouseup", 200, 300, { eventConstructor: "MouseEvent" }); + + // cy.wait(1000).then(() => { + // const positionAfterChange = doc + // .querySelector(widgetsPage.checkboxWidget) + // .getBoundingClientRect(); + + // expect(positionAfterChange.top).to.not.equal(initialPosition.top); + // }); + + // cy.get("body").type(`{${modifierKey}}z`); + + // cy.wait(1000).then(() => { + // const positionAfterUndo = doc + // .querySelector(widgetsPage.checkboxWidget) + // .getBoundingClientRect(); + + // expect(positionAfterUndo.top).to.equal(initialPosition.top); + // }); + + // cy.get("body").type(`{${modifierKey}}{shift}z`); + + // cy.wait(1000).then(() => { + // const positionAfterRedo = doc + // .querySelector(widgetsPage.checkboxWidget) + // .getBoundingClientRect(); + + // expect(positionAfterRedo.top).to.equal(initialPosition.top); + // }); + // }); + // }); + + it("2. checks undo/redo for toggle control in property pane", function () { + cy.openPropertyPane("checkboxwidget"); + cy.CheckWidgetProperties(commonlocators.disableCheckbox); + + cy.get("body").type(`{${modifierKey}}z`); + cy.wait(100); + cy.get(`${widgetsPage.disable} input`).should("not.be.checked"); + cy.get(widgetLocators.checkboxWidget + " " + "input").should( + "not.be.disabled", + ); + + cy.get("body").type(`{${modifierKey}}{shift}z`); + cy.wait(100); + + cy.get(`${widgetsPage.disable} input`).should("be.checked"); + cy.get(widgetLocators.checkboxWidget + " " + "input").should( + "be.disabled", + ); + }); + + it("3. checks undo/redo for input control in property pane", function () { + cy.get(widgetsPage.inputLabelControl).type("1"); + cy.get(widgetsPage.inputLabelControl).contains("Label1"); + + cy.get("body").type(`{${modifierKey}}z`); + cy.wait(100); + cy.get(widgetsPage.inputLabelControl).contains("Label"); + cy.get(`${publish.checkboxWidget} label`).should("have.text", "Label"); + + cy.get("body").type(`{${modifierKey}}{shift}z`); + cy.wait(100); + cy.get(widgetsPage.inputLabelControl).contains("Label1"); + cy.get(`${publish.checkboxWidget} label`).should("have.text", "Label1"); + }); + + it("4. checks undo/redo for deletion of widgets", function () { + cy.deleteWidget(widgetsPage.checkboxWidget); + cy.get(widgetsPage.checkboxWidget).should("not.exist"); + + cy.get("body").type(`{${modifierKey}}z`); + cy.wait(100); + cy.get(widgetsPage.checkboxWidget).should("exist"); + + // cy.get("body").type(`{${modifierKey}}{shift}z`); + // cy.wait(100); + // cy.get(widgetsPage.checkboxWidget).should("not.exist"); + }); + + it("5. checks if property Pane is open on undo/redo property changes", function () { + cy.dragAndDropToCanvas("textwidget", { x: 400, y: 400 }); + + cy.wait(100); + propPane.UpdatePropertyFieldValue("Text", "Label"); + + cy.closePropertyPane(); + + cy.get("body").type(`{${modifierKey}}z`); + cy.wait(100); + cy.get(widgetsPage.propertypaneText).should("exist"); + cy.get(widgetsPage.inputTextControl).contains( + "Hello {{appsmith.user.name || appsmith.user.email}}", + ); + + cy.closePropertyPane(); + + cy.get("body").type(`{${modifierKey}}{shift}z`); + cy.wait(100); + cy.get(widgetsPage.propertypaneText).should("exist"); + cy.get(widgetsPage.inputTextControl).contains("Label"); + cy.deleteWidget(widgetsPage.textWidget); + }); + + it("6. checks if toast is shown while undo/redo widget deletion or creation only the first time", function () { + cy.dragAndDropToCanvas("textwidget", { x: 400, y: 400 }); + localStorage.removeItem("undoToastShown"); + localStorage.removeItem("redoToastShown"); + + cy.get("body").type(`{${modifierKey}}z`); + cy.get(commonlocators.toastmsg).contains("is removed"); + cy.get(commonlocators.toastmsg).contains("redo"); + cy.get(commonlocators.toastBody).first().click({ force: true }); + + cy.wait(100); + cy.get("body").type(`{${modifierKey}}{shift}z`); + cy.get(commonlocators.toastmsg).contains("is added back"); + cy.get(commonlocators.toastmsg).contains("undo"); + cy.deleteWidget(widgetsPage.textWidget); + }); + + it("7. checks undo/redo for color picker", function () { + cy.dragAndDropToCanvas("textwidget", { x: 100, y: 100 }); + cy.moveToStyleTab(); + cy.selectColor("textcolor"); + cy.get("body").click({ force: true }); + // eslint-disable-next-line cypress/no-unnecessary-waiting + cy.wait(500); + cy.wait("@updateLayout"); + cy.readTextDataValidateCSS("color", "rgb(219, 234, 254)"); + cy.get("body").click({ force: true }).type(`{${modifierKey}}z`); + EditorNavigation.SelectEntityByName("Text1", EntityType.Widget); + propPane.MoveToTab("Style"); + cy.get(widgetsPage.textColor) + .first() + .invoke("attr", "value") + .should("contain", "#231F20"); + + cy.get("body").type(`{${modifierKey}}{shift}z`); + EditorNavigation.SelectEntityByName("Text1", EntityType.Widget); + propPane.MoveToTab("Style"); + cy.get(widgetsPage.textColor) + .first() + .invoke("attr", "value") + .should("contain", "#dbeafe"); + }); + + it("8. checks undo/redo for option control for radio button", function () { + cy.dragAndDropToCanvas("radiogroupwidget", { x: 200, y: 600 }); + + cy.get(widgetsPage.RadioInput).first().type("1"); + + cy.get(widgetsPage.RadioInput).first().blur(); + + // eslint-disable-next-line cypress/no-unnecessary-waiting + cy.wait(200); + + cy.get("body").type(`{${modifierKey}}z`); + EditorNavigation.SelectEntityByName("RadioGroup1", EntityType.Widget); + cy.get(widgetsPage.RadioInput) + .first() + .invoke("attr", "value") + .should("contain", "Yes"); + + cy.get("body").type(`{${modifierKey}}{shift}z`); + EditorNavigation.SelectEntityByName("RadioGroup1", EntityType.Widget); + cy.get(widgetsPage.RadioInput) + .first() + .invoke("attr", "value") + .should("contain", "Yes1"); + }); + }, +); diff --git a/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/Resize_spec.js b/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/Resize_spec.js index 4673b3ff24a..0f56a228f4f 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/Resize_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/Resize_spec.js @@ -1,23 +1,31 @@ const commonlocators = require("../../../../locators/commonlocators.json"); import { agHelper, propPane } from "../../../../support/Objects/ObjectsCore"; -describe("Canvas Resize", function () { - before(() => { - agHelper.AddDsl("CanvasResizeDsl"); - }); - it("1. Deleting bottom widget should resize canvas", function () { - const InitHeight = "2950px"; - cy.get(commonlocators.dropTarget).should("have.css", "height", InitHeight); - //cy.openPropertyPane("textwidget"); - cy.intercept("PUT", "/api/v1/layouts/*/pages/*").as("deleteUpdate"); - propPane.DeleteWidgetFromPropertyPane("Text2"); - cy.wait("@deleteUpdate").then((response) => { - const dsl = response.response.body.data.dsl; +describe( + "Canvas Resize", + { tags: ["@tag.Widget", "@tag.AutoHeight"] }, + function () { + before(() => { + agHelper.AddDsl("CanvasResizeDsl"); + }); + it("1. Deleting bottom widget should resize canvas", function () { + const InitHeight = "2950px"; cy.get(commonlocators.dropTarget).should( "have.css", "height", - `${dsl.minHeight - 12}px`, // Reducing 12 px for container padding. + InitHeight, ); + //cy.openPropertyPane("textwidget"); + cy.intercept("PUT", "/api/v1/layouts/*/pages/*").as("deleteUpdate"); + propPane.DeleteWidgetFromPropertyPane("Text2"); + cy.wait("@deleteUpdate").then((response) => { + const dsl = response.response.body.data.dsl; + cy.get(commonlocators.dropTarget).should( + "have.css", + "height", + `${dsl.minHeight - 12}px`, // Reducing 12 px for container padding. + ); + }); }); - }); -}); + }, +); diff --git a/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/Unique_key_spec.js b/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/Unique_key_spec.js index 94fadcf674f..581acca07d8 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/Unique_key_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/Unique_key_spec.js @@ -4,7 +4,7 @@ import * as _ from "../../../../support/Objects/ObjectsCore"; // Since we cannot test the root cause as it does not show up on the DOM, we are testing the sideEffects // the root cause is when widget has same keys, which are not visible in DOM but confuses React when the list is modified. // please refer to issue, https://github.com/appsmithorg/appsmith/issues/7415 for more details. -describe("Unique react keys", function () { +describe("Unique react keys", { tags: ["@tag.Widget"] }, function () { afterEach(() => { _.agHelper.SaveLocalStorageCache(); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/UpdateApplication_spec.js b/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/UpdateApplication_spec.js index 706334ea084..d3d2940cc8c 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/UpdateApplication_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/UpdateApplication_spec.js @@ -2,7 +2,7 @@ import homePage from "../../../../locators/HomePage"; import { agHelper } from "../../../../support/Objects/ObjectsCore"; const commonlocators = require("../../../../locators/commonlocators.json"); -describe("Update Application", () => { +describe("Update Application", { tags: ["@tag.Workspace"] }, () => { let appname, workspaceName; let iconname; let veryLongAppName = `gnerwihnireongionihgnerwihnireongionihgnerwihnireongionihgnerwihnireongionihgnerwihnireongionihgnerwihnireongionih1gnerwihnireongionihgnerwihnireongionihgnerwihnireongionihgnerwihnireongionihgnerwihnireongionihgnerwihnireongionih1${Math.random() diff --git a/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/ViewMode_spec.js b/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/ViewMode_spec.js index b7da0c5c6a2..1b3c7b6c0d1 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/ViewMode_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/ViewMode_spec.js @@ -14,7 +14,7 @@ Cypress.Commands.add("getSharedUrl", () => { return Cypress.sharedStore.url; }); -describe("Preview mode functionality", function () { +describe("Preview mode functionality", { tags: ["@tag.IDE"] }, () => { before(() => { agHelper.AddDsl("previewMode"); deployMode.DeployApp(); diff --git a/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/Widget_Error_spec.js b/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/Widget_Error_spec.js index 5b35f24d796..2f35d8795cb 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/Widget_Error_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/Widget_Error_spec.js @@ -6,7 +6,7 @@ const widgetLocators = require("../../../../locators/Widgets.json"); import * as _ from "../../../../support/Objects/ObjectsCore"; import { WIDGET } from "../../../../locators/WidgetLocators"; -describe("Widget error state", function () { +describe("Widget error state", { tags: ["@tag.Widget"] }, function () { const modifierKey = Cypress.platform === "darwin" ? "meta" : "ctrl"; before(() => { diff --git a/app/client/cypress/e2e/Regression/ClientSide/SettingsPane/PageSettings_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/SettingsPane/PageSettings_spec.ts index ccaecba8962..4ae4eaf7a19 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/SettingsPane/PageSettings_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/SettingsPane/PageSettings_spec.ts @@ -1,7 +1,7 @@ import * as _ from "../../../../support/Objects/ObjectsCore"; import PageList from "../../../../support/Pages/PageList"; -describe("Page Settings", { tags: ["@tag.Settings"] }, () => { +describe("Page Settings", { tags: ["@tag.Settings", "@tag.Sanity"] }, () => { it("1. Page name change updates URL", () => { _.appSettings.OpenAppSettings(); _.appSettings.GoToPageSettings("Page1"); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Templates/CreateNewAppFromTemplates_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Templates/CreateNewAppFromTemplates_spec.ts index 4f548e55068..291512d7c45 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Templates/CreateNewAppFromTemplates_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Templates/CreateNewAppFromTemplates_spec.ts @@ -8,7 +8,14 @@ import reconnectDatasourceLocators from "../../../../locators/ReconnectLocators. describe( "Create new application from template", - { tags: ["@tag.excludeForAirgap", "@tag.Workspace", "@tag.Templates"] }, + { + tags: [ + "@tag.excludeForAirgap", + "@tag.Workspace", + "@tag.Templates", + "@tag.Sanity", + ], + }, function () { beforeEach(() => { homePage.NavigateToHome(); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Templates/Fork_Template_Existing_app_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Templates/Fork_Template_Existing_app_spec.js index 95f4246c88d..7cc1d638ed5 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Templates/Fork_Template_Existing_app_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Templates/Fork_Template_Existing_app_spec.js @@ -23,7 +23,7 @@ beforeEach(() => { describe( "Fork a template to the current app from new page popover", - { tags: ["@tag.Templates", "@tag.excludeForAirgap"] }, + { tags: ["@tag.Templates", "@tag.excludeForAirgap", "@tag.Sanity"] }, () => { it("1. Fork template from page section", () => { //Fork template button to be visible always diff --git a/app/client/cypress/e2e/Regression/ClientSide/Templates/TemplatesPage_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Templates/TemplatesPage_spec.ts index bd1858a86f8..63fff9dfdc8 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Templates/TemplatesPage_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Templates/TemplatesPage_spec.ts @@ -3,7 +3,7 @@ import PageList from "../../../../support/Pages/PageList"; describe( "Templates page", - { tags: ["@tag.Templates", "@tag.excludeForAirgap"] }, + { tags: ["@tag.Templates", "@tag.excludeForAirgap", "@tag.Sanity"] }, () => { it("1. Templates Modal should have show only 'allowPageImport:true' templates", () => { cy.fixture("Templates/AllowPageImportTemplates.json").then((data) => { diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Button/Button_onClickAction_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Button/Button_onClickAction_spec.js index 56080c5d115..703cfc151a1 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Button/Button_onClickAction_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Button/Button_onClickAction_spec.js @@ -16,7 +16,7 @@ import { describe( "Button Widget Functionality", - { tags: ["@tag.Widget", "@tag.Button"] }, + { tags: ["@tag.Widget", "@tag.Button", "@tag.Sanity"] }, function () { before(() => { agHelper.AddDsl("newFormDsl"); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Chart/ChartDataPoint_Spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Chart/ChartDataPoint_Spec.ts index f007ed8ebce..3f12e9eb6f7 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Chart/ChartDataPoint_Spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Chart/ChartDataPoint_Spec.ts @@ -16,7 +16,7 @@ let dataSet: any, dsl: any; describe( "Input widget test with default value from chart datapoint", - { tags: ["@tag.Widget", "@tag.Chart"] }, + { tags: ["@tag.Widget", "@tag.Chart", "@tag.Sanity"] }, () => { //beforeEach - to enable re-attempt passing! beforeEach(() => { diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_AutoGenerateFormDisabled_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_AutoGenerateFormDisabled_spec.js index 3e7e83aae5b..23894738bcb 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_AutoGenerateFormDisabled_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_AutoGenerateFormDisabled_spec.js @@ -13,7 +13,7 @@ import { describe( "JSON Form Widget AutoGenerate Disabled", - { tags: ["@tag.Widget", "@tag.JSONForm"] }, + { tags: ["@tag.Widget", "@tag.JSONForm", "@tag.Sanity"] }, () => { before(() => { agHelper.AddDsl("jsonFormDslWithSchemaAndWithoutSourceData"); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_AutoGenerateFormEnabled_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_AutoGenerateFormEnabled_spec.js index f6b2870a46f..11a286f7a22 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_AutoGenerateFormEnabled_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_AutoGenerateFormEnabled_spec.js @@ -16,7 +16,7 @@ let locators = ObjectsRegistry.CommonLocators; describe( "JSON Form Widget AutoGenerate Enabled", - { tags: ["@tag.Widget", "@tag.JSONForm"] }, + { tags: ["@tag.Widget", "@tag.JSONForm", "@tag.Sanity"] }, () => { beforeEach(() => { agHelper.RestoreLocalStorageCache(); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_Basic_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_Basic_spec.js index d9a8cf6d709..c2f299b7b88 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_Basic_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/JSONForm/JSONForm_Basic_spec.js @@ -11,7 +11,7 @@ const { describe( "JsonForm widget basis c usecases", - { tags: ["@tag.Widget", "@tag.JSONForm"] }, + { tags: ["@tag.Widget", "@tag.JSONForm", "@tag.Sanity"] }, function () { before(() => { cy.dragAndDropToCanvas("jsonformwidget", { x: 200, y: 200 }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/ListV2/ListV2_PageNo_PageSize_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/ListV2/ListV2_PageNo_PageSize_spec.js index 26ec43b37f7..00e3059cd5a 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/ListV2/ListV2_PageNo_PageSize_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/ListV2/ListV2_PageNo_PageSize_spec.js @@ -88,7 +88,7 @@ const listData = [ describe( "List widget V2 page number and page size", - { tags: ["@tag.Widget", "@tag.List"] }, + { tags: ["@tag.Widget", "@tag.List", "@tag.Sanity"] }, () => { before(() => { _.agHelper.AddDsl("listv2PaginationDsl"); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/ListV2/ListV2_SerververSide_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/ListV2/ListV2_SerververSide_spec.js index d655cdab6ba..061e83a4c9e 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/ListV2/ListV2_SerververSide_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/ListV2/ListV2_SerververSide_spec.js @@ -15,7 +15,7 @@ const widgetSelector = (name) => `[data-widgetname-cy="${name}"]`; describe( "List widget V2 Serverside Pagination", - { tags: ["@tag.Widget", "@tag.List"] }, + { tags: ["@tag.Widget", "@tag.List", "@tag.Sanity"] }, () => { before(() => { agHelper.AddDsl("Listv2/Listv2JSObjects"); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/ListV2/ListV2_nested_List_widget_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/ListV2/ListV2_nested_List_widget_spec.js index 4d6a2525baa..0aafd27f8e5 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/ListV2/ListV2_nested_List_widget_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/ListV2/ListV2_nested_List_widget_spec.js @@ -27,7 +27,7 @@ function checkAutosuggestion(label, type) { } describe( " Nested List Widgets ", - { tags: ["@tag.Widget", "@tag.List"] }, + { tags: ["@tag.Widget", "@tag.List", "@tag.Sanity"] }, function () { const modifierKey = Cypress.platform === "darwin" ? "meta" : "ctrl"; beforeEach(() => { diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/ListV2/Listv2_BasicChildWidgetInteraction_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/ListV2/Listv2_BasicChildWidgetInteraction_spec.js index e1b24950bd0..1bdbef59b94 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/ListV2/Listv2_BasicChildWidgetInteraction_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/ListV2/Listv2_BasicChildWidgetInteraction_spec.js @@ -51,7 +51,7 @@ function checkSelectedRadioValue(selector, value) { describe( "List widget v2 - Basic Child Widget Interaction", - { tags: ["@tag.Widget", "@tag.List"] }, + { tags: ["@tag.Widget", "@tag.List", "@tag.Sanity"] }, () => { before(() => { _.agHelper.AddDsl("Listv2/emptyList"); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/ListV2/Listv2_BasicClientSideData_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/ListV2/Listv2_BasicClientSideData_spec.js index f6c14c63db3..59ebf8744cd 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/ListV2/Listv2_BasicClientSideData_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/ListV2/Listv2_BasicClientSideData_spec.js @@ -26,7 +26,7 @@ const simpleListData1 = [ describe( "List widget v2 - Basic client side data tests", - { tags: ["@tag.Widget", "@tag.List"] }, + { tags: ["@tag.Widget", "@tag.List", "@tag.Sanity"] }, () => { beforeEach(() => { _.agHelper.RestoreLocalStorageCache(); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/ListV2/Listv2_Nested_EventBindings_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/ListV2/Listv2_Nested_EventBindings_spec.js index 046260141a2..344b4116035 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/ListV2/Listv2_Nested_EventBindings_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/ListV2/Listv2_Nested_EventBindings_spec.js @@ -6,7 +6,7 @@ const widgetSelector = (name) => `[data-widgetname-cy="${name}"]`; describe( "Listv2 - Event bindings spec", - { tags: ["@tag.Widget", "@tag.List"] }, + { tags: ["@tag.Widget", "@tag.List", "@tag.Sanity"] }, () => { it("1. nested list - inner widget should have access to currentItem, currentIndex, currentView and level_1", () => { cy.addDsl(nestedListDSL); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/ListV2/Listv2_onItemClick_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/ListV2/Listv2_onItemClick_spec.js index 647f5a6e031..7d3e5f1d4e9 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/ListV2/Listv2_onItemClick_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/ListV2/Listv2_onItemClick_spec.js @@ -30,7 +30,7 @@ function deleteAllWidgetsInContainer() { describe( "List widget v2 onItemClick", - { tags: ["@tag.Widget", "@tag.List"] }, + { tags: ["@tag.Widget", "@tag.List", "@tag.Sanity"] }, () => { it("1. List widget V2 with onItemClick", () => { cy.dragAndDropToCanvas("listwidgetv2", { diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Multiselect/MultiSelect1_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Multiselect/MultiSelect1_spec.js index e9793d48382..90dce2f693b 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Multiselect/MultiSelect1_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Multiselect/MultiSelect1_spec.js @@ -3,7 +3,7 @@ import * as _ from "../../../../../support/Objects/ObjectsCore"; describe( "MultiSelect Widget Functionality", - { tags: ["@tag.Widget", "@tag.Multiselect"] }, + { tags: ["@tag.Widget", "@tag.Multiselect", "@tag.Sanity"] }, function () { before(() => { _.agHelper.AddDsl("emptyDSL"); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Select/Select_Validation_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Select/Select_Validation_spec.js index bf3d44f067c..7924ea4e9ec 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Select/Select_Validation_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Select/Select_Validation_spec.js @@ -8,7 +8,7 @@ import * as _ from "../../../../../support/Objects/ObjectsCore"; describe( "Select Widget Functionality", - { tags: ["@tag.Widget", "@tag.Select"] }, + { tags: ["@tag.Widget", "@tag.Select", "@tag.Sanity"] }, function () { before(() => { _.entityExplorer.DragDropWidgetNVerify(_.draggableWidgets.SELECT); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Select/Select_widget1_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Select/Select_widget1_spec.js index 843c76e50c1..4dc40ede6cf 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Select/Select_widget1_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Select/Select_widget1_spec.js @@ -9,7 +9,7 @@ const defaultValue = ` describe( "Select Widget Functionality", - { tags: ["@tag.Widget", "@tag.Select"] }, + { tags: ["@tag.Widget", "@tag.Select", "@tag.Sanity"] }, function () { before(() => { _.agHelper.AddDsl("emptyDSL"); 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 cc0c32b1d9c..d3e05b789db 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 @@ -5,172 +5,176 @@ import { } from "../../../../../support/Objects/ObjectsCore"; const commonlocators = require("../../../../../locators/commonlocators.json"); -describe("Basic flow ", { tags: ["@tag.Widget", "@tag.Table"] }, () => { - before(() => { - agHelper.RestoreLocalStorageCache(); - agHelper.AddDsl("Table/InlineEditingDSL"); - }); - - it("1.1. should test that allow Add new row property is present", () => { - cy.openPropertyPane("tablewidgetv2"); - 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"); - propPane.TogglePropertyState("Allow adding a row", "Off", null); - cy.get(".t--add-new-row").should("not.exist"); - cy.get(".t--property-control-onsave").should("not.exist"); - cy.get(".t--property-control-ondiscard").should("not.exist"); - cy.get(".t--property-control-defaultvalues").should("not.exist"); - // onSave, onDiscard and default row are showing up only when the allow add new property is enabled - propPane.TogglePropertyState("Allow adding a row", "On"); - cy.get(".t--add-new-row").should("exist"); - cy.get(".t--property-control-onsave").should("exist"); - cy.get(".t--property-control-ondiscard").should("exist"); - cy.get(".t--property-control-defaultvalues").should("exist"); - cy.get(".t--add-new-row.disabled").should("not.exist"); - // add new row link is disabled during the inline editing flow - table.toggleColumnEditableViaColSettingsPane("step"); - cy.editTableCell(0, 0); - cy.get(".t--add-new-row.disabled").should("exist"); - cy.openPropertyPane("tablewidgetv2"); - cy.get(".tableWrap .new-row").should("not.exist"); - // clicking on add new row link adds an empty row at the top of the table - cy.get(".t--add-new-row").click(); - cy.get(".tableWrap .new-row").should("exist"); - cy.get(".t--discard-new-row").click({ force: true }); - }); +describe( + "Basic flow ", + { tags: ["@tag.Widget", "@tag.Table", "@tag.Sanity"] }, + () => { + before(() => { + agHelper.RestoreLocalStorageCache(); + agHelper.AddDsl("Table/InlineEditingDSL"); + }); - it("1.2. should test that new row is getting populated with the default row property value", () => { - cy.updateCodeInput( - ".t--property-control-defaultvalues", - "{{{step: 'newStepCell'}}}", - ); - cy.get(".t--add-new-row").click(); - cy.get(".tableWrap .new-row").should("exist"); - cy.readTableV2data(0, 0).then((val) => { - expect(val).to.equal("newStepCell"); + it("1.1. should test that allow Add new row property is present", () => { + cy.openPropertyPane("tablewidgetv2"); + 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"); + propPane.TogglePropertyState("Allow adding a row", "Off", null); + cy.get(".t--add-new-row").should("not.exist"); + cy.get(".t--property-control-onsave").should("not.exist"); + cy.get(".t--property-control-ondiscard").should("not.exist"); + cy.get(".t--property-control-defaultvalues").should("not.exist"); + // onSave, onDiscard and default row are showing up only when the allow add new property is enabled + propPane.TogglePropertyState("Allow adding a row", "On"); + cy.get(".t--add-new-row").should("exist"); + cy.get(".t--property-control-onsave").should("exist"); + cy.get(".t--property-control-ondiscard").should("exist"); + cy.get(".t--property-control-defaultvalues").should("exist"); + cy.get(".t--add-new-row.disabled").should("not.exist"); + // add new row link is disabled during the inline editing flow + table.toggleColumnEditableViaColSettingsPane("step"); + cy.editTableCell(0, 0); + cy.get(".t--add-new-row.disabled").should("exist"); + cy.openPropertyPane("tablewidgetv2"); + cy.get(".tableWrap .new-row").should("not.exist"); + // clicking on add new row link adds an empty row at the top of the table + cy.get(".t--add-new-row").click(); + cy.get(".tableWrap .new-row").should("exist"); + cy.get(".t--discard-new-row").click({ force: true }); }); - cy.get(".t--discard-new-row").click({ force: true }); - }); - it("1.3. should test that inline editing, row selection, pagination, search, filters are actions cannot be performed while in add new row feature", () => { - cy.get(".t--widget-tablewidgetv2 .t--search-input").should("exist"); - cy.get(".t--widget-tablewidgetv2 .t--table-filter-toggle-btn").should( - "exist", - ); - cy.get(".t--widget-tablewidgetv2 .t--table-download-btn").should("exist"); - cy.get(".t--widget-tablewidgetv2 .t--add-new-row").should("exist"); - cy.get(".t--widget-tablewidgetv2 .show-page-items").should("exist"); - cy.get(".t--widget-tablewidgetv2 .t--table-widget-prev-page").should( - "exist", - ); - cy.get(".t--widget-tablewidgetv2 .t--table-widget-page-input").should( - "exist", - ); - cy.get(".t--widget-tablewidgetv2 .t--table-widget-next-page").should( - "exist", - ); + it("1.2. should test that new row is getting populated with the default row property value", () => { + cy.updateCodeInput( + ".t--property-control-defaultvalues", + "{{{step: 'newStepCell'}}}", + ); + cy.get(".t--add-new-row").click(); + cy.get(".tableWrap .new-row").should("exist"); + cy.readTableV2data(0, 0).then((val) => { + expect(val).to.equal("newStepCell"); + }); + cy.get(".t--discard-new-row").click({ force: true }); + }); - cy.get(".t--add-new-row").click(); + it("1.3. should test that inline editing, row selection, pagination, search, filters are actions cannot be performed while in add new row feature", () => { + cy.get(".t--widget-tablewidgetv2 .t--search-input").should("exist"); + cy.get(".t--widget-tablewidgetv2 .t--table-filter-toggle-btn").should( + "exist", + ); + cy.get(".t--widget-tablewidgetv2 .t--table-download-btn").should("exist"); + cy.get(".t--widget-tablewidgetv2 .t--add-new-row").should("exist"); + cy.get(".t--widget-tablewidgetv2 .show-page-items").should("exist"); + cy.get(".t--widget-tablewidgetv2 .t--table-widget-prev-page").should( + "exist", + ); + cy.get(".t--widget-tablewidgetv2 .t--table-widget-page-input").should( + "exist", + ); + cy.get(".t--widget-tablewidgetv2 .t--table-widget-next-page").should( + "exist", + ); - cy.get(".t--widget-tablewidgetv2 .t--search-input").should("not.exist"); - cy.get(".t--widget-tablewidgetv2 .t--table-filter-toggle-btn").should( - "not.exist", - ); - cy.get(".t--widget-tablewidgetv2 .t--table-download-btn").should( - "not.exist", - ); - cy.get(".t--widget-tablewidgetv2 .t--add-new-row").should("not.exist"); - cy.get(".t--widget-tablewidgetv2 .show-page-items").should("not.exist"); - cy.get(".t--widget-tablewidgetv2 .t--table-widget-prev-page").should( - "not.exist", - ); - cy.get(".t--widget-tablewidgetv2 .t--table-widget-page-input").should( - "not.exist", - ); - cy.get(".t--widget-tablewidgetv2 .t--table-widget-next-page").should( - "not.exist", - ); - cy.get(".t--discard-new-row").click({ force: true }); - }); + cy.get(".t--add-new-row").click(); - it("1.4. should test that only editable column cells are in editmode in the new row", () => { - cy.get(".t--add-new-row").click(); - cy.get(`[data-colindex=0][data-rowindex=0] .t--inlined-cell-editor`).should( - "exist", - ); - cy.get(`[data-colindex=1][data-rowindex=0] .t--inlined-cell-editor`).should( - "not.exist", - ); - table.toggleColumnEditableViaColSettingsPane("task"); - cy.get(`[data-colindex=0][data-rowindex=0] .t--inlined-cell-editor`).should( - "exist", - ); - cy.get(`[data-colindex=1][data-rowindex=0] .t--inlined-cell-editor`).should( - "exist", - ); - table.toggleColumnEditableViaColSettingsPane("step", "v2", false); - table.toggleColumnEditableViaColSettingsPane("task", "v2", false); - cy.get(`[data-colindex=0][data-rowindex=0] .t--inlined-cell-editor`).should( - "not.exist", - ); - cy.get(`[data-colindex=1][data-rowindex=0] .t--inlined-cell-editor`).should( - "not.exist", - ); - }); + cy.get(".t--widget-tablewidgetv2 .t--search-input").should("not.exist"); + cy.get(".t--widget-tablewidgetv2 .t--table-filter-toggle-btn").should( + "not.exist", + ); + cy.get(".t--widget-tablewidgetv2 .t--table-download-btn").should( + "not.exist", + ); + cy.get(".t--widget-tablewidgetv2 .t--add-new-row").should("not.exist"); + cy.get(".t--widget-tablewidgetv2 .show-page-items").should("not.exist"); + cy.get(".t--widget-tablewidgetv2 .t--table-widget-prev-page").should( + "not.exist", + ); + cy.get(".t--widget-tablewidgetv2 .t--table-widget-page-input").should( + "not.exist", + ); + cy.get(".t--widget-tablewidgetv2 .t--table-widget-next-page").should( + "not.exist", + ); + cy.get(".t--discard-new-row").click({ force: true }); + }); - it("1.5. should test that newRow property holds the entered data", () => { - table.toggleColumnEditableViaColSettingsPane("step"); - table.toggleColumnEditableViaColSettingsPane("task"); - cy.enterTableCellValue(0, 0, "22"); - cy.enterTableCellValue(1, 0, "21"); - cy.dragAndDropToCanvas("textwidget", { x: 300, y: 600 }); - cy.openPropertyPane("textwidget"); - cy.updateCodeInput(".t--property-control-text", `{{Table1.newRow}}`); - cy.get(".t--widget-textwidget .bp3-ui-text").should( - "contain", - `{ "step": "22", "task": "21"}`, - ); - }); + it("1.4. should test that only editable column cells are in editmode in the new row", () => { + cy.get(".t--add-new-row").click(); + cy.get( + `[data-colindex=0][data-rowindex=0] .t--inlined-cell-editor`, + ).should("exist"); + cy.get( + `[data-colindex=1][data-rowindex=0] .t--inlined-cell-editor`, + ).should("not.exist"); + table.toggleColumnEditableViaColSettingsPane("task"); + cy.get( + `[data-colindex=0][data-rowindex=0] .t--inlined-cell-editor`, + ).should("exist"); + cy.get( + `[data-colindex=1][data-rowindex=0] .t--inlined-cell-editor`, + ).should("exist"); + table.toggleColumnEditableViaColSettingsPane("step", "v2", false); + table.toggleColumnEditableViaColSettingsPane("task", "v2", false); + cy.get( + `[data-colindex=0][data-rowindex=0] .t--inlined-cell-editor`, + ).should("not.exist"); + cy.get( + `[data-colindex=1][data-rowindex=0] .t--inlined-cell-editor`, + ).should("not.exist"); + }); - it("1.6. should test that non data (iconBitton, button, menubutton) column cells are not showing up", () => { - cy.openPropertyPane("tablewidgetv2"); - table.toggleColumnEditableViaColSettingsPane("step", "v2", false, false); - ["Button", "Menu button", "Icon button"].forEach((columnType) => { - cy.get(commonlocators.changeColType).last().click(); - cy.get(".t--dropdown-option").children().contains(columnType).click(); - cy.wait("@updateLayout"); - cy.get(`[data-colindex=0][data-rowindex=0] button`).should("not.exist"); + it("1.5. should test that newRow property holds the entered data", () => { + table.toggleColumnEditableViaColSettingsPane("step"); + table.toggleColumnEditableViaColSettingsPane("task"); + cy.enterTableCellValue(0, 0, "22"); + cy.enterTableCellValue(1, 0, "21"); + cy.dragAndDropToCanvas("textwidget", { x: 300, y: 600 }); + cy.openPropertyPane("textwidget"); + cy.updateCodeInput(".t--property-control-text", `{{Table1.newRow}}`); + cy.get(".t--widget-textwidget .bp3-ui-text").should( + "contain", + `{ "step": "22", "task": "21"}`, + ); }); - cy.get("[data-testid='t--property-pane-back-btn']").click(); - }); - 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 }); - //disable all header widgets for the table - [ - "Show pagination", - "Allow searching", - "Allow download", - "Allow filtering", - "Allow adding a row", - ].forEach((val) => { - propPane.TogglePropertyState(val, "Off"); + it("1.6. should test that non data (iconBitton, button, menubutton) column cells are not showing up", () => { + cy.openPropertyPane("tablewidgetv2"); + table.toggleColumnEditableViaColSettingsPane("step", "v2", false, false); + ["Button", "Menu button", "Icon button"].forEach((columnType) => { + cy.get(commonlocators.changeColType).last().click(); + cy.get(".t--dropdown-option").children().contains(columnType).click(); + cy.wait("@updateLayout"); + cy.get(`[data-colindex=0][data-rowindex=0] button`).should("not.exist"); + }); + cy.get("[data-testid='t--property-pane-back-btn']").click(); }); - cy.wait(1000); - //intially enable 2 sections to show pagination and "add new row" button to the header section - propPane.TogglePropertyState("Show pagination", "On"); - propPane.TogglePropertyState("Allow adding a row", "On"); + 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 }); + //disable all header widgets for the table + [ + "Show pagination", + "Allow searching", + "Allow download", + "Allow filtering", + "Allow adding a row", + ].forEach((val) => { + propPane.TogglePropertyState(val, "Off"); + }); + cy.wait(1000); + + //intially enable 2 sections to show pagination and "add new row" button to the header section + propPane.TogglePropertyState("Show pagination", "On"); + propPane.TogglePropertyState("Allow adding a row", "On"); - //"add new row" button should be present - cy.get(".t--add-new-row").should("exist"); - //turn off pagination and now the "add new row" button should be the only component left in the header section - propPane.TogglePropertyState("Show pagination", "Off"); - //"add new row" should continue to be present - cy.get(".t--add-new-row").should("exist"); - //finally turn off allow adding a row then the "add new row" button should be removed from the header section - propPane.TogglePropertyState("Allow adding a row", "Off"); - cy.get(".t--add-new-row").should("not.exist"); - }); -}); + //"add new row" button should be present + cy.get(".t--add-new-row").should("exist"); + //turn off pagination and now the "add new row" button should be the only component left in the header section + propPane.TogglePropertyState("Show pagination", "Off"); + //"add new row" should continue to be present + cy.get(".t--add-new-row").should("exist"); + //finally turn off allow adding a row then the "add new row" button should be removed from the header section + propPane.TogglePropertyState("Allow adding a row", "Off"); + cy.get(".t--add-new-row").should("not.exist"); + }); + }, +); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/AddNewRow2_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/AddNewRow2_spec.js index ac43df3ec57..23508651c00 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/AddNewRow2_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/AddNewRow2_spec.js @@ -1,167 +1,171 @@ import * as _ from "../../../../../support/Objects/ObjectsCore"; const commonlocators = require("../../../../../locators/commonlocators.json"); -describe("Validation flow", { tags: ["@tag.Widget", "@tag.Table"] }, () => { - before(() => { - cy.startServerAndRoutes(); - _.agHelper.RestoreLocalStorageCache(); - _.agHelper.AddDsl("Table/InlineEditingDSL"); - }); +describe( + "Validation flow", + { tags: ["@tag.Widget", "@tag.Table", "@tag.Sanity"] }, + () => { + before(() => { + cy.startServerAndRoutes(); + _.agHelper.RestoreLocalStorageCache(); + _.agHelper.AddDsl("Table/InlineEditingDSL"); + }); - it("2.1. should test that validation is working for a new row cell", () => { - cy.openPropertyPane("tablewidgetv2"); - _.propPane.TogglePropertyState("Allow adding a row", "On"); - cy.get(".t--add-new-row").click(); - _.table.toggleColumnEditableViaColSettingsPane("step", "v2", true, false); + it("2.1. should test that validation is working for a new row cell", () => { + cy.openPropertyPane("tablewidgetv2"); + _.propPane.TogglePropertyState("Allow adding a row", "On"); + cy.get(".t--add-new-row").click(); + _.table.toggleColumnEditableViaColSettingsPane("step", "v2", true, false); - _.propPane.UpdatePropertyFieldValue("Valid", "{{editedValue === '#1'}}"); - cy.wait(500); - cy.get(`.t--inlined-cell-editor-has-error`).should("not.exist"); - cy.enterTableCellValue(0, 0, "22"); - cy.wait(500); - cy.get(`.t--inlined-cell-editor-has-error`).should("exist"); - cy.enterTableCellValue(0, 0, "#1"); - cy.wait(500); - cy.get(`.t--inlined-cell-editor-has-error`).should("not.exist"); - _.propPane.UpdatePropertyFieldValue("Valid", ""); + _.propPane.UpdatePropertyFieldValue("Valid", "{{editedValue === '#1'}}"); + cy.wait(500); + cy.get(`.t--inlined-cell-editor-has-error`).should("not.exist"); + cy.enterTableCellValue(0, 0, "22"); + cy.wait(500); + cy.get(`.t--inlined-cell-editor-has-error`).should("exist"); + cy.enterTableCellValue(0, 0, "#1"); + cy.wait(500); + cy.get(`.t--inlined-cell-editor-has-error`).should("not.exist"); + _.propPane.UpdatePropertyFieldValue("Valid", ""); - _.propPane.UpdatePropertyFieldValue("Regex", "^#1$"); - cy.wait(500); - cy.get(`.t--inlined-cell-editor-has-error`).should("not.exist"); - cy.enterTableCellValue(0, 0, "22"); - cy.wait(500); - cy.get(`.t--inlined-cell-editor-has-error`).should("exist"); - cy.enterTableCellValue(0, 0, "#1"); - cy.wait(500); - cy.get(`.t--inlined-cell-editor-has-error`).should("not.exist"); - _.propPane.UpdatePropertyFieldValue("Regex", ""); + _.propPane.UpdatePropertyFieldValue("Regex", "^#1$"); + cy.wait(500); + cy.get(`.t--inlined-cell-editor-has-error`).should("not.exist"); + cy.enterTableCellValue(0, 0, "22"); + cy.wait(500); + cy.get(`.t--inlined-cell-editor-has-error`).should("exist"); + cy.enterTableCellValue(0, 0, "#1"); + cy.wait(500); + cy.get(`.t--inlined-cell-editor-has-error`).should("not.exist"); + _.propPane.UpdatePropertyFieldValue("Regex", ""); - _.propPane.TogglePropertyState("Required", "On"); - cy.enterTableCellValue(0, 0, "22"); - cy.wait(500); - cy.get(`.t--inlined-cell-editor-has-error`).should("not.exist"); - cy.enterTableCellValue(0, 0, "#1"); - cy.wait(500); - cy.get(`.t--inlined-cell-editor-has-error`).should("not.exist"); - cy.enterTableCellValue(0, 0, ""); - cy.wait(500); - cy.get(`.t--inlined-cell-editor-has-error`).should("exist"); + _.propPane.TogglePropertyState("Required", "On"); + cy.enterTableCellValue(0, 0, "22"); + cy.wait(500); + cy.get(`.t--inlined-cell-editor-has-error`).should("not.exist"); + cy.enterTableCellValue(0, 0, "#1"); + cy.wait(500); + cy.get(`.t--inlined-cell-editor-has-error`).should("not.exist"); + cy.enterTableCellValue(0, 0, ""); + cy.wait(500); + cy.get(`.t--inlined-cell-editor-has-error`).should("exist"); - cy.get(commonlocators.changeColType).last().click(); - cy.get(".t--dropdown-option").children().contains("Number").click(); - cy.wait("@updateLayout"); + cy.get(commonlocators.changeColType).last().click(); + cy.get(".t--dropdown-option").children().contains("Number").click(); + cy.wait("@updateLayout"); - _.propPane.UpdatePropertyFieldValue("Min", "5"); - cy.enterTableCellValue(0, 0, "6"); - cy.wait(500); - cy.get(`.t--inlined-cell-editor-has-error`).should("not.exist"); - cy.enterTableCellValue(0, 0, "7"); - cy.wait(500); - cy.get(`.t--inlined-cell-editor-has-error`).should("not.exist"); - cy.enterTableCellValue(0, 0, "4"); - cy.wait(500); - cy.get(`.t--inlined-cell-editor-has-error`).should("exist"); - cy.enterTableCellValue(0, 0, "3"); - cy.wait(500); - cy.get(`.t--inlined-cell-editor-has-error`).should("exist"); - cy.enterTableCellValue(0, 0, "8"); - cy.wait(500); - cy.get(`.t--inlined-cell-editor-has-error`).should("not.exist"); - _.propPane.UpdatePropertyFieldValue("Min", ""); + _.propPane.UpdatePropertyFieldValue("Min", "5"); + cy.enterTableCellValue(0, 0, "6"); + cy.wait(500); + cy.get(`.t--inlined-cell-editor-has-error`).should("not.exist"); + cy.enterTableCellValue(0, 0, "7"); + cy.wait(500); + cy.get(`.t--inlined-cell-editor-has-error`).should("not.exist"); + cy.enterTableCellValue(0, 0, "4"); + cy.wait(500); + cy.get(`.t--inlined-cell-editor-has-error`).should("exist"); + cy.enterTableCellValue(0, 0, "3"); + cy.wait(500); + cy.get(`.t--inlined-cell-editor-has-error`).should("exist"); + cy.enterTableCellValue(0, 0, "8"); + cy.wait(500); + cy.get(`.t--inlined-cell-editor-has-error`).should("not.exist"); + _.propPane.UpdatePropertyFieldValue("Min", ""); - _.propPane.UpdatePropertyFieldValue("Max", "5"); - cy.enterTableCellValue(0, 0, "6"); - cy.wait(500); - cy.get(`.t--inlined-cell-editor-has-error`).should("exist"); - cy.enterTableCellValue(0, 0, "7"); - cy.wait(500); - cy.get(`.t--inlined-cell-editor-has-error`).should("exist"); - cy.enterTableCellValue(0, 0, "4"); - cy.wait(500); - cy.get(`.t--inlined-cell-editor-has-error`).should("not.exist"); - cy.enterTableCellValue(0, 0, "3"); - cy.wait(500); - cy.get(`.t--inlined-cell-editor-has-error`).should("not.exist"); - cy.enterTableCellValue(0, 0, "8"); - cy.wait(500); - cy.get(`.t--inlined-cell-editor-has-error`).should("exist"); - _.propPane.UpdatePropertyFieldValue("Max", ""); + _.propPane.UpdatePropertyFieldValue("Max", "5"); + cy.enterTableCellValue(0, 0, "6"); + cy.wait(500); + cy.get(`.t--inlined-cell-editor-has-error`).should("exist"); + cy.enterTableCellValue(0, 0, "7"); + cy.wait(500); + cy.get(`.t--inlined-cell-editor-has-error`).should("exist"); + cy.enterTableCellValue(0, 0, "4"); + cy.wait(500); + cy.get(`.t--inlined-cell-editor-has-error`).should("not.exist"); + cy.enterTableCellValue(0, 0, "3"); + cy.wait(500); + cy.get(`.t--inlined-cell-editor-has-error`).should("not.exist"); + cy.enterTableCellValue(0, 0, "8"); + cy.wait(500); + cy.get(`.t--inlined-cell-editor-has-error`).should("exist"); + _.propPane.UpdatePropertyFieldValue("Max", ""); - // check that date isRequired validation is working - cy.get(commonlocators.changeColType).last().click(); - cy.get(".t--dropdown-option").children().contains("Date").click(); - cy.wait("@updateLayout"); - cy.enterTableCellValue(0, 0, ""); - cy.get(`.t--inlined-cell-editor-has-error`).should("exist"); + // check that date isRequired validation is working + cy.get(commonlocators.changeColType).last().click(); + cy.get(".t--dropdown-option").children().contains("Date").click(); + cy.wait("@updateLayout"); + cy.enterTableCellValue(0, 0, ""); + cy.get(`.t--inlined-cell-editor-has-error`).should("exist"); - // revert to Number for remainder of tests - cy.get(commonlocators.changeColType).last().click(); - cy.get(".t--dropdown-option").children().contains("Number").click(); - cy.wait("@updateLayout"); + // revert to Number for remainder of tests + cy.get(commonlocators.changeColType).last().click(); + cy.get(".t--dropdown-option").children().contains("Number").click(); + cy.wait("@updateLayout"); - cy.get(".t--discard-new-row").click({ force: true }); - }); + cy.get(".t--discard-new-row").click({ force: true }); + }); - it("2.2. should test that validation variable isNewRow is working", () => { - _.propPane.UpdatePropertyFieldValue( - "Valid", - "{{isNewRow ? (editedValue === 1) : (editedValue === 2)}}", - ); + it("2.2. should test that validation variable isNewRow is working", () => { + _.propPane.UpdatePropertyFieldValue( + "Valid", + "{{isNewRow ? (editedValue === 1) : (editedValue === 2)}}", + ); - cy.editTableCell(0, 0); - cy.enterTableCellValue(0, 0, "3"); - cy.wait(500); - cy.get(`.t--inlined-cell-editor-has-error`).should("exist"); - cy.enterTableCellValue(0, 0, "2"); - cy.wait(500); - cy.get(`.t--inlined-cell-editor-has-error`).should("not.exist"); - cy.discardTableCellValue(0, 0); - cy.wait(500); - cy.get(".t--add-new-row").click(); - cy.wait(1000); - cy.enterTableCellValue(0, 0, "3"); - cy.wait(500); - cy.get(`.t--inlined-cell-editor-has-error`).should("exist"); - cy.enterTableCellValue(0, 0, "2"); - cy.wait(500); - cy.get(`.t--inlined-cell-editor-has-error`).should("exist"); - cy.enterTableCellValue(0, 0, "1"); - cy.wait(500); - cy.get(`.t--inlined-cell-editor-has-error`).should("not.exist"); - cy.get(".t--discard-new-row").click({ force: true }); - }); + cy.editTableCell(0, 0); + cy.enterTableCellValue(0, 0, "3"); + cy.wait(500); + cy.get(`.t--inlined-cell-editor-has-error`).should("exist"); + cy.enterTableCellValue(0, 0, "2"); + cy.wait(500); + cy.get(`.t--inlined-cell-editor-has-error`).should("not.exist"); + cy.discardTableCellValue(0, 0); + cy.wait(500); + cy.get(".t--add-new-row").click(); + cy.wait(1000); + cy.enterTableCellValue(0, 0, "3"); + cy.wait(500); + cy.get(`.t--inlined-cell-editor-has-error`).should("exist"); + cy.enterTableCellValue(0, 0, "2"); + cy.wait(500); + cy.get(`.t--inlined-cell-editor-has-error`).should("exist"); + cy.enterTableCellValue(0, 0, "1"); + cy.wait(500); + cy.get(`.t--inlined-cell-editor-has-error`).should("not.exist"); + cy.get(".t--discard-new-row").click({ force: true }); + }); - it("2.3. should test that validation is working for more than one add new row cell at a time", () => { - _.propPane.UpdatePropertyFieldValue("Valid", "{{editedValue === 1}}"); - cy.get("[data-testid='t--property-pane-back-btn']").click(); - cy.wait(500); - _.table.toggleColumnEditableViaColSettingsPane("task", "v2", true, false); - _.propPane.UpdatePropertyFieldValue( - "Valid", - "{{editedValue === 'invalid'}}", - ); - _.propPane.TogglePropertyState("Required", "On"); - cy.get(".t--add-new-row").click(); - cy.get(`.t--inlined-cell-editor-has-error`).should("have.length", 2); - }); + it("2.3. should test that validation is working for more than one add new row cell at a time", () => { + _.propPane.UpdatePropertyFieldValue("Valid", "{{editedValue === 1}}"); + cy.get("[data-testid='t--property-pane-back-btn']").click(); + cy.wait(500); + _.table.toggleColumnEditableViaColSettingsPane("task", "v2", true, false); + _.propPane.UpdatePropertyFieldValue( + "Valid", + "{{editedValue === 'invalid'}}", + ); + _.propPane.TogglePropertyState("Required", "On"); + cy.get(".t--add-new-row").click(); + cy.get(`.t--inlined-cell-editor-has-error`).should("have.length", 2); + }); - it("2.4. should test that validation error message only appears when a cell is in focus", () => { - cy.get(".error-tooltip .bp3-popover-content").should("not.exist"); - cy.get(`[data-colindex=1][data-rowindex=0] input`).focus(); - cy.get(".error-tooltip .bp3-popover-content").should("have.length", 1); - cy.openPropertyPane("tablewidgetv2"); - cy.get(".error-tooltip .bp3-popover-content").should("not.exist"); - cy.get(`[data-colindex=0][data-rowindex=0] input`).focus(); - cy.get(".error-tooltip .bp3-popover-content").should("have.length", 1); - // save button is disabled when there is an error - cy.get(".t--save-new-row").should("be.disabled"); - cy.get(`.t--inlined-cell-editor-has-error`).should("have.length", 2); - cy.enterTableCellValue(0, 0, "1"); - cy.wait(1000); - cy.get(`.t--inlined-cell-editor-has-error`).should("have.length", 1); - cy.enterTableCellValue(1, 0, "invalid"); - cy.wait(1000); - cy.get(`.t--inlined-cell-editor-has-error`).should("have.length", 0); - cy.get(".t--save-new-row").should("not.be.disabled"); - }); -}); + it("2.4. should test that validation error message only appears when a cell is in focus", () => { + cy.get(".error-tooltip .bp3-popover-content").should("not.exist"); + cy.get(`[data-colindex=1][data-rowindex=0] input`).focus(); + cy.get(".error-tooltip .bp3-popover-content").should("have.length", 1); + cy.openPropertyPane("tablewidgetv2"); + cy.get(".error-tooltip .bp3-popover-content").should("not.exist"); + cy.get(`[data-colindex=0][data-rowindex=0] input`).focus(); + cy.get(".error-tooltip .bp3-popover-content").should("have.length", 1); + // save button is disabled when there is an error + cy.get(".t--save-new-row").should("be.disabled"); + cy.get(`.t--inlined-cell-editor-has-error`).should("have.length", 2); + cy.enterTableCellValue(0, 0, "1"); + cy.wait(1000); + cy.get(`.t--inlined-cell-editor-has-error`).should("have.length", 1); + cy.enterTableCellValue(1, 0, "invalid"); + cy.wait(1000); + cy.get(`.t--inlined-cell-editor-has-error`).should("have.length", 0); + cy.get(".t--save-new-row").should("not.be.disabled"); + }); + }, +); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/AddNewRow3_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/AddNewRow3_spec.js index d5632632983..e6a161c1bb2 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/AddNewRow3_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/AddNewRow3_spec.js @@ -3,7 +3,7 @@ const widgetsPage = require("../../../../../locators/Widgets.json"); describe( "Actions flow (save, discard)", - { tags: ["@tag.Widget", "@tag.Table"] }, + { tags: ["@tag.Widget", "@tag.Table", "@tag.Sanity"] }, () => { before(() => { cy.startServerAndRoutes(); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/Inline_editing_2_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/Inline_editing_2_spec.js index b8ab5ef942e..6336b7f58b0 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/Inline_editing_2_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/Inline_editing_2_spec.js @@ -6,12 +6,12 @@ const commonlocators = require("../../../../../locators/commonlocators.json"); const widgetsPage = require("../../../../../locators/Widgets.json"); import { agHelper, - entityExplorer, propPane, table, - draggableWidgets, } from "../../../../../support/Objects/ObjectsCore"; import { PROPERTY_SELECTOR } from "../../../../../locators/WidgetLocators"; +import PageList from "../../../../../support/Pages/PageList"; +const publish = require("../../../../../locators/publishWidgetspage.json"); describe( "Table widget inline editing functionality", @@ -30,8 +30,7 @@ describe( cy.openPropertyPane("tablewidgetv2"); table.toggleColumnEditableViaColSettingsPane("step", "v2", true, true); cy.editColumn("EditActions1"); - cy.get(".t--property-pane-section-collapse-savebutton").click(); - //cy.get(".t--property-pane-section-collapse-discardbutton").click(); + cy.get(widgetsPage.propertyPaneSaveButton).click(); cy.getAlert("onDiscard", "discarded!!"); cy.editTableCell(0, 0); cy.enterTableCellValue(0, 0, "NewValue"); @@ -51,22 +50,16 @@ describe( cy.openPropertyPane("tablewidgetv2"); table.toggleColumnEditableViaColSettingsPane("step", "v2", true, true); cy.editTableCell(0, 0); - cy.get( - "[data-colindex=0][data-rowindex=0] .t--inlined-cell-editor input.bp3-input", - ).should("not.be.disabled"); + cy.get(widgetsPage.firstEditInput).should("not.be.disabled"); }); it("3. should check that inline editing works with text wrapping enabled", () => { cy.openPropertyPane("tablewidgetv2"); table.toggleColumnEditableViaColSettingsPane("step", "v2", true, true); cy.editColumn("step"); - cy.get(".t--property-control-cellwrapping .ads-v2-switch") - .first() - .click({ force: true }); + cy.get(widgetsPage.cellControlSwitch).first().click({ force: true }); cy.editTableCell(0, 0); - cy.get( - "[data-colindex=0][data-rowindex=0] .t--inlined-cell-editor input.bp3-input", - ).should("not.be.disabled"); + cy.get(widgetsPage.firstEditInput).should("not.be.disabled"); }); it("4. should check that cell column height doesn't grow taller when text wrapping is disabled", () => { @@ -114,16 +107,15 @@ describe( it("6. should check if updatedRowIndex is getting updated for single row update mode", () => { cy.dragAndDropToCanvas("textwidget", { x: 400, y: 400 }); - cy.get(".t--widget-textwidget").should("exist"); - cy.updateCodeInput( - ".t--property-control-text", - `{{Table1.updatedRowIndex}}`, - ); + cy.get(publish.textWidget).should("exist"); + cy.updateCodeInput(PROPERTY_SELECTOR.text, `{{Table1.updatedRowIndex}}`); cy.dragAndDropToCanvas("buttonwidget", { x: 300, y: 300 }); - cy.get(".t--widget-buttonwidget").should("exist"); - cy.get(PROPERTY_SELECTOR.onClick).find(".t--js-toggle").click(); - cy.updateCodeInput(".t--property-control-label", "Reset"); + cy.get(widgetsPage.widgetBtn).should("exist"); + cy.get(PROPERTY_SELECTOR.onClick) + .find(PROPERTY_SELECTOR.jsToggle) + .click(); + cy.updateCodeInput(widgetsPage.propertyControlLabel, "Reset"); cy.updateCodeInput( PROPERTY_SELECTOR.onClick, `{{resetWidget("Table1",true)}}`, @@ -161,19 +153,23 @@ describe( }); it("7. should check if updatedRowIndex is getting updated for multi row update mode", () => { + PageList.AddNewPage("New blank page"); + cy.dragAndDropToCanvas("tablewidgetv2", { x: 350, y: 500 }); + table.AddSampleTableData(); cy.dragAndDropToCanvas("textwidget", { x: 400, y: 400 }); - cy.get(".t--widget-textwidget").should("exist"); - cy.updateCodeInput( - ".t--property-control-text", - `{{Table1.updatedRowIndex}}`, - ); + cy.get(publish.textWidget).should("exist"); + cy.updateCodeInput(PROPERTY_SELECTOR.text, `{{Table1.updatedRowIndex}}`); cy.dragAndDropToCanvas("buttonwidget", { x: 300, y: 300 }); - cy.get(".t--widget-buttonwidget").should("exist"); - cy.get(PROPERTY_SELECTOR.onClick).find(".t--js-toggle").click(); - cy.updateCodeInput(".t--property-control-label", "Reset"); - cy.updateCodeInput( - PROPERTY_SELECTOR.onClick, - `{{resetWidget("Table1",true)}}`, + cy.get(widgetsPage.widgetBtn).should("exist"); + cy.get(PROPERTY_SELECTOR.onClick) + .find(PROPERTY_SELECTOR.jsToggle) + .click(); + cy.updateCodeInput(widgetsPage.propertyControlLabel, "Reset"); + propPane.EnterJSContext( + "onClick", + '{{resetWidget("Table1",true)}}', + true, + false, ); EditorNavigation.SelectEntityByName("Table1", EntityType.Widget); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_FilteredTableData_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_FilteredTableData_spec.js deleted file mode 100644 index 572d38337ca..00000000000 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_FilteredTableData_spec.js +++ /dev/null @@ -1,55 +0,0 @@ -import EditorNavigation, { - EntityType, -} from "../../../../../support/Pages/EditorNavigation"; - -const widgetsPage = require("../../../../../locators/Widgets.json"); -const commonlocators = require("../../../../../locators/commonlocators.json"); -const publish = require("../../../../../locators/publishWidgetspage.json"); -const dsl = require("../../../../../fixtures/tableV2AndTextDsl.json"); - -import * as _ from "../../../../../support/Objects/ObjectsCore"; - -describe( - "Table Widget V2 Filtered Table data in autocomplete", - { tags: ["@tag.Widget", "@tag.Table"] }, - function () { - before("Table Widget V2 Functionality", () => { - _.agHelper.AddDsl("tableV2AndTextDsl"); - cy.openPropertyPane("tablewidgetv2"); - }); - - it("1. Table Widget V2 Functionality To Filter and search data", function () { - cy.get(publish.searchInput).first().type("query"); - cy.get(publish.filterBtn).click({ force: true }); - cy.get(publish.attributeDropdown).click({ force: true }); - cy.get(publish.attributeValue).contains("task").click({ force: true }); - cy.get(publish.conditionDropdown).click({ force: true }); - cy.get(publish.attributeValue) - .contains("contains") - .click({ force: true }); - cy.get(publish.tableFilterInputValue).type("bind", { force: true }); - cy.wait(500); - cy.get(widgetsPage.filterApplyBtn).click({ force: true }); - cy.wait(500); - cy.get(".t--close-filter-btn").click({ force: true }); - }); - - it("2. Table Widget V2 Functionality to validate filtered table data", function () { - EditorNavigation.SelectEntityByName("Text1", EntityType.Widget); - cy.testJsontext("text", "{{Table1.filteredTableData[0].task}}"); - cy.readTableV2data("0", "1").then((tabData) => { - const tableData = tabData; - cy.get(commonlocators.labelTextStyle).should("have.text", tableData); - }); - - //Table Widget V2 Functionality to validate filtered table data with actual table data - cy.readTableV2data("0", "1").then((tabData) => { - const tableData = JSON.parse(dsl.dsl.children[0].tableData); - cy.get(commonlocators.labelTextStyle).should( - "have.text", - tableData[2].task, - ); - }); - }); - }, -); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_FilteredTableData_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_FilteredTableData_spec.ts new file mode 100644 index 00000000000..8a0a2cdaba0 --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_FilteredTableData_spec.ts @@ -0,0 +1,114 @@ +import EditorNavigation, { + EntityType, + PageLeftPane, + PagePaneSegment, +} from "../../../../../support/Pages/EditorNavigation"; + +import dsl from "../../../../../fixtures/tableV2AndTextDsl.json"; +import widgetsPage from "../../../../../locators/Widgets.json"; +import commonlocators from "../../../../../locators/commonlocators.json"; +import publish from "../../../../../locators/publishWidgetspage.json"; + +import { tableDataJSObject } from "../../../../../fixtures/tableV2FilteringWithPrimaryColumnJSObjectWidthData"; +import { + agHelper, + jsEditor, + locators, + table, +} from "../../../../../support/Objects/ObjectsCore"; + +describe( + "Table Widget V2 Filtered Table data in autocomplete", + { tags: ["@tag.Widget", "@tag.Table", "@tag.Sanity"] }, + function () { + before("Table Widget V2 Functionality", () => { + agHelper.AddDsl("tableV2AndTextDsl"); + agHelper.GetNClick(locators._widgetInCanvas("tablewidgetv2")); + }); + + it("1. Table Widget V2 Functionality To Filter and search data", function () { + table.SearchTable("query"); + agHelper.GetNClick(publish.filterBtn, 0, true); + agHelper.GetNClick(publish.attributeDropdown, 0, true); + + agHelper + .GetElement(publish.attributeValue) + .contains("task") + .click({ force: true }); + agHelper.GetNClick(publish.conditionDropdown, 0, true); + agHelper + .GetElement(publish.attributeValue) + .contains("contains") + .click({ force: true }); + agHelper.TypeText(publish.tableFilterInputValue, "bind"); + + agHelper.GetNClick(widgetsPage.filterApplyBtn, 0, true); + table.CloseFilter(); + }); + + it("2. Table Widget V2 Functionality to validate filtered table data", function () { + EditorNavigation.SelectEntityByName("Text1", EntityType.Widget); + (cy as any).testJsontext("text", "{{Table1.filteredTableData[0].task}}"); + table.ReadTableRowColumnData(0, 1, "v2").then((tabData: string) => { + agHelper.AssertText( + commonlocators.labelTextStyle, + "text", + tabData as string, + ); + }); + + //Table Widget V2 Functionality to validate filtered table data with actual table data + const tableData = JSON.parse(dsl.dsl.children[0].tableData as string); + agHelper.AssertText( + commonlocators.labelTextStyle, + "text", + tableData[1].task as string, + ); + }); + + it("3. When primary key is set, selectedRowIndex should not updated after data update", function () { + // https://github.com/appsmithorg/appsmith/issues/36080 + jsEditor.CreateJSObject(tableDataJSObject, { + paste: true, + completeReplace: true, + toRun: false, + shouldCreateNewJSObj: true, + prettify: true, + }); + jsEditor.CreateJSObject(manipulateDataJSObject, { + paste: true, + completeReplace: true, + toRun: true, + shouldCreateNewJSObj: true, + prettify: true, + }); + PageLeftPane.switchSegment(PagePaneSegment.UI); + + agHelper.AddDsl("tableV2FilteringWithPrimaryColumn"); + table.SearchTable("Engineering"); + table.ReadTableRowColumnData(2, 0, "v2").then((text) => { + expect(text).to.equal("Michael Wilson"); + }); + + table.SelectTableRow(2, 0, true, "v2"); + + agHelper.GetText(locators._textWidget, "text").then((text) => { + agHelper.ClickButton("Submit"); + + table.ReadTableRowColumnData(2, 0, "v2").then((text) => { + expect(text).to.equal("Michael Wilson1"); + }); + agHelper.AssertText(locators._textWidget, "text", text as string); + }); + }); + }, +); + +export const manipulateDataJSObject = `export default { + data: JSObject1.initData, + makeNewCopy() { + const my = _.cloneDeep(this.data); + my[5].name =my[5].name+"1"; + this.data = my; + } +}`; diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_pagination_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_pagination_spec.js index e666fced118..d55d58c2124 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_pagination_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2_pagination_spec.js @@ -3,7 +3,7 @@ import * as _ from "../../../../../support/Objects/ObjectsCore"; describe( "Table Widget property pane feature validation", - { tags: ["@tag.Widget", "@tag.Table"] }, + { tags: ["@tag.Widget", "@tag.Table", "@tag.Sanity"] }, function () { before(() => { _.agHelper.AddDsl("tableV2NewDslWithPagination"); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Workspace/MemberRoles_Spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Workspace/MemberRoles_Spec.ts index 5154a056401..f747ffc96d2 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Workspace/MemberRoles_Spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Workspace/MemberRoles_Spec.ts @@ -5,7 +5,7 @@ let workspaceId: any, appid: any; describe( "Create new workspace and invite user & validate all roles", - { tags: ["@tag.Workspace"] }, + { tags: ["@tag.Workspace", "@tag.Sanity"] }, () => { it("1. Create new Workspace, Share with a user from UI & verify", () => { if (CURRENT_REPO === REPO.EE) _.adminSettings.EnableGAC(true, false); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Workspace/ShareAppTests_Spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Workspace/ShareAppTests_Spec.ts index ee6b2466475..54ea1884ee1 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Workspace/ShareAppTests_Spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Workspace/ShareAppTests_Spec.ts @@ -13,7 +13,7 @@ const appNavigationLocators = require("../../../../locators/AppNavigation.json") describe( "Create new workspace and share with a user", - { tags: ["@tag.Workspace"] }, + { tags: ["@tag.Workspace", "@tag.Sanity"] }, function () { let workspaceId: string, appid: string, currentUrl: any; diff --git a/app/client/cypress/e2e/Regression/ClientSide/Workspace/WorkspaceImportApplication_spec.js b/app/client/cypress/e2e/Regression/ClientSide/Workspace/WorkspaceImportApplication_spec.js index 9123f3b6698..ba5a8f83d1d 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Workspace/WorkspaceImportApplication_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Workspace/WorkspaceImportApplication_spec.js @@ -3,7 +3,7 @@ import { agHelper, homePage } from "../../../../support/Objects/ObjectsCore"; describe( "Workspace Import Application", - { tags: ["@tag.Workspace"] }, + { tags: ["@tag.Workspace", "@tag.Sanity"] }, function () { let workspaceId; let newWorkspaceName; diff --git a/app/client/cypress/e2e/Regression/ServerSide/ApiTests/API_TestExecuteWithDynamicBindingInUrl_spec.ts b/app/client/cypress/e2e/Regression/ServerSide/ApiTests/API_TestExecuteWithDynamicBindingInUrl_spec.ts index 964de8a7983..36df01ae346 100644 --- a/app/client/cypress/e2e/Regression/ServerSide/ApiTests/API_TestExecuteWithDynamicBindingInUrl_spec.ts +++ b/app/client/cypress/e2e/Regression/ServerSide/ApiTests/API_TestExecuteWithDynamicBindingInUrl_spec.ts @@ -8,7 +8,7 @@ import { describe( "Test API execution with dynamic binding in URL - Bug #24218", - { tags: ["@tag.Datasource"] }, + { tags: ["@tag.Datasource", "@tag.Sanity"] }, () => { it("1. Test API execution with dynamic binding in URL", () => { // Create JS Object to set Appsmith store variable to mockApiUrl diff --git a/app/client/cypress/e2e/Regression/ServerSide/GenerateCRUD/Mongo_Spec.ts b/app/client/cypress/e2e/Regression/ServerSide/GenerateCRUD/Mongo_Spec.ts index 94cf82fc284..c6fbdd13f5b 100644 --- a/app/client/cypress/e2e/Regression/ServerSide/GenerateCRUD/Mongo_Spec.ts +++ b/app/client/cypress/e2e/Regression/ServerSide/GenerateCRUD/Mongo_Spec.ts @@ -16,7 +16,7 @@ import PageList from "../../../../support/Pages/PageList"; describe( "Validate Mongo CRUD with JSON Form", - { tags: ["@tag.Datasource"] }, + { tags: ["@tag.Datasource", "@tag.Sanity"] }, () => { let dsName: any; diff --git a/app/client/cypress/e2e/Regression/ServerSide/JsFunctionExecution/JSFunctionExecution_spec.ts b/app/client/cypress/e2e/Regression/ServerSide/JsFunctionExecution/JSFunctionExecution_spec.ts index 201b69d0e61..71c7ac4762c 100644 --- a/app/client/cypress/e2e/Regression/ServerSide/JsFunctionExecution/JSFunctionExecution_spec.ts +++ b/app/client/cypress/e2e/Regression/ServerSide/JsFunctionExecution/JSFunctionExecution_spec.ts @@ -28,493 +28,500 @@ let onPageLoadAndConfirmExecuteFunctionsLength: number, functionsLength: number, jsObj: string; -describe("JS Function Execution", { tags: ["@tag.JS"] }, function () { - const FUNCTIONS_SETTINGS_DEFAULT_DATA: IFunctionSettingData[] = [ - { - name: "getId", - onPageLoad: true, - confirmBeforeExecute: false, - isMarkedAsync: true, - }, - { - name: "zip", - onPageLoad: true, - confirmBeforeExecute: true, - isMarkedAsync: false, - }, - { - name: "base", - onPageLoad: false, - confirmBeforeExecute: false, - isMarkedAsync: true, - }, - { - name: "assert", - onPageLoad: false, - confirmBeforeExecute: false, - isMarkedAsync: false, - }, - { - name: "test", - onPageLoad: true, - confirmBeforeExecute: true, - isMarkedAsync: true, - }, - ]; - - before(() => { - agHelper.AddDsl("tablev1NewDsl"); - }); - - function assertAsyncFunctionsOrder(data: IFunctionSettingData[]) { - // sorts functions alphabetically - const sortFunctions = (data: IFunctionSettingData[]) => - data.sort((a, b) => a.name.localeCompare(b.name)); - cy.get(jsEditor._asyncJSFunctionSettings).then(function ($lis) { - const asyncFunctionLength = $lis.length; - // Assert number of functions - expect(asyncFunctionLength).to.equal(functionsLength); - Object.values(sortFunctions(data)).forEach((functionSetting, idx) => { - // Assert alphabetical order - expect($lis.eq(idx)).to.have.id( - jsEditor._getJSFunctionSettingsId(functionSetting.name), - ); - }); +describe( + "JS Function Execution", + { tags: ["@tag.JS", "@tag.Sanity"] }, + function () { + const FUNCTIONS_SETTINGS_DEFAULT_DATA: IFunctionSettingData[] = [ + { + name: "getId", + onPageLoad: true, + confirmBeforeExecute: false, + isMarkedAsync: true, + }, + { + name: "zip", + onPageLoad: true, + confirmBeforeExecute: true, + isMarkedAsync: false, + }, + { + name: "base", + onPageLoad: false, + confirmBeforeExecute: false, + isMarkedAsync: true, + }, + { + name: "assert", + onPageLoad: false, + confirmBeforeExecute: false, + isMarkedAsync: false, + }, + { + name: "test", + onPageLoad: true, + confirmBeforeExecute: true, + isMarkedAsync: true, + }, + ]; + + before(() => { + agHelper.AddDsl("tablev1NewDsl"); }); - } - it("1. Allows execution of js function when lint warnings(not errors) are present in code", function () { - jsEditor.CreateJSObject( - `export default { + function assertAsyncFunctionsOrder(data: IFunctionSettingData[]) { + // sorts functions alphabetically + const sortFunctions = (data: IFunctionSettingData[]) => + data.sort((a, b) => a.name.localeCompare(b.name)); + cy.get(jsEditor._asyncJSFunctionSettings).then(function ($lis) { + const asyncFunctionLength = $lis.length; + // Assert number of functions + expect(asyncFunctionLength).to.equal(functionsLength); + Object.values(sortFunctions(data)).forEach((functionSetting, idx) => { + // Assert alphabetical order + expect($lis.eq(idx)).to.have.id( + jsEditor._getJSFunctionSettingsId(functionSetting.name), + ); + }); + }); + } + + it("1. Allows execution of js function when lint warnings(not errors) are present in code", function () { + jsEditor.CreateJSObject( + `export default { myFun1: ()=>{ f; return "yes" } }`, - { - paste: true, - completeReplace: true, - toRun: false, - shouldCreateNewJSObj: true, - prettify: false, - }, - ); + { + paste: true, + completeReplace: true, + toRun: false, + shouldCreateNewJSObj: true, + prettify: false, + }, + ); - jsEditor.AssertParseError(false); - agHelper.ActionContextMenuWithInPane({ - action: "Delete", - entityType: entityItems.JSObject, + jsEditor.AssertParseError(false); + agHelper.ActionContextMenuWithInPane({ + action: "Delete", + entityType: entityItems.JSObject, + }); }); - }); - it("2. Prevents execution of js function when parse errors are present in code", function () { - jsEditor.CreateJSObject( - `export default { + it("2. Prevents execution of js function when parse errors are present in code", function () { + jsEditor.CreateJSObject( + `export default { myFun1: ()=>>{ return "yes" } }`, - { - paste: true, - completeReplace: true, - toRun: false, - shouldCreateNewJSObj: true, - prettify: false, - }, - ); - //Debugger shouldn't open when there is a parse error. - //It should open only in case of execution error. - debuggerHelper.AssertClosed(); - //Verify there is no error shown in the response tab. - debuggerHelper.OpenDebugger(); - debuggerHelper.ClickResponseTab(); - jsEditor.AssertParseError(false); - agHelper.ActionContextMenuWithInPane({ - action: "Delete", - entityType: entityItems.JSObject, + { + paste: true, + completeReplace: true, + toRun: false, + shouldCreateNewJSObj: true, + prettify: false, + }, + ); + //Debugger shouldn't open when there is a parse error. + //It should open only in case of execution error. + debuggerHelper.AssertClosed(); + //Verify there is no error shown in the response tab. + debuggerHelper.OpenDebugger(); + debuggerHelper.ClickResponseTab(); + jsEditor.AssertParseError(false); + agHelper.ActionContextMenuWithInPane({ + action: "Delete", + entityType: entityItems.JSObject, + }); }); - }); - it("3. Prioritizes parse errors that render JS Object invalid over function execution parse errors in debugger callouts", function () { - const JSObjectWithFunctionExecutionParseErrors = `export default { + it("3. Prioritizes parse errors that render JS Object invalid over function execution parse errors in debugger callouts", function () { + const JSObjectWithFunctionExecutionParseErrors = `export default { myFun1 :()=>{ return f } }`; - const JSObjectWithParseErrors = `export default { + const JSObjectWithParseErrors = `export default { myFun1: (a ,b)=>>{ return "yes" } }`; - // create jsObject with parse error (that doesn't render JS Object invalid) - jsEditor.CreateJSObject(JSObjectWithFunctionExecutionParseErrors, { - paste: true, - completeReplace: true, - toRun: true, - shouldCreateNewJSObj: true, - prettify: false, - }); + // create jsObject with parse error (that doesn't render JS Object invalid) + jsEditor.CreateJSObject(JSObjectWithFunctionExecutionParseErrors, { + paste: true, + completeReplace: true, + toRun: true, + shouldCreateNewJSObj: true, + prettify: false, + }); - // Assert presence of function execution parse error callout - jsEditor.AssertParseError(true); + // Assert presence of function execution parse error callout + jsEditor.AssertParseError(true); - // Add parse error that renders JS Object invalid in code - jsEditor.CreateJSObject(JSObjectWithParseErrors, { - paste: true, - completeReplace: true, - toRun: false, - shouldCreateNewJSObj: false, - prettify: false, - }); + // Add parse error that renders JS Object invalid in code + jsEditor.CreateJSObject(JSObjectWithParseErrors, { + paste: true, + completeReplace: true, + toRun: false, + shouldCreateNewJSObj: false, + prettify: false, + }); - agHelper.Sleep(2000); // Giving more time for parsing to reduce flakiness! + agHelper.Sleep(2000); // Giving more time for parsing to reduce flakiness! - // Assert presence of parse error callout (entire JS Object is invalid) - jsEditor.AssertParseError(true); - agHelper.ActionContextMenuWithInPane({ - action: "Delete", - entityType: entityItems.JSObject, + // Assert presence of parse error callout (entire JS Object is invalid) + jsEditor.AssertParseError(true); + agHelper.ActionContextMenuWithInPane({ + action: "Delete", + entityType: entityItems.JSObject, + }); }); - }); - - it("4. Shows lint error and toast modal when JS Object doesn't start with 'export default'", () => { - const invalidJSObjectStartToastMessage = "Start object with export default"; - const jsComment = "// This is a comment"; - const jsObjectStartLine = `export default{`; - const jsObjectStartLineWithSpace = `export  default{`; - const jsObjectStartingWithAComment = `${jsComment} + + it("4. Shows lint error and toast modal when JS Object doesn't start with 'export default'", () => { + const invalidJSObjectStartToastMessage = + "Start object with export default"; + const jsComment = "// This is a comment"; + const jsObjectStartLine = `export default{`; + const jsObjectStartLineWithSpace = `export  default{`; + const jsObjectStartingWithAComment = `${jsComment} ${jsObjectStartLine} fun1:()=>true }`; - const jsObjectStartingWithASpace = `${jsObjectStartLineWithSpace} + const jsObjectStartingWithASpace = `${jsObjectStartLineWithSpace} fun1:()=>true }`; - const jsObjectStartingWithANewLine = ` + const jsObjectStartingWithANewLine = ` ${jsObjectStartLine} fun1:()=>true }`; - const assertInvalidJSObjectStart = ( - jsCode: string, - highlightedLintText: string, - ) => { - // create jsObject that doesn't start with 'export default' - jsEditor.CreateJSObject(jsCode, { + const assertInvalidJSObjectStart = ( + jsCode: string, + highlightedLintText: string, + ) => { + // create jsObject that doesn't start with 'export default' + jsEditor.CreateJSObject(jsCode, { + paste: true, + completeReplace: true, + toRun: false, + shouldCreateNewJSObj: true, + }); + + // Assert presence of toast message + agHelper.AssertContains(invalidJSObjectStartToastMessage); + + // Assert presence of lint error at the start line + agHelper.GetNAssertElementText( + locators._lintErrorElement, + highlightedLintText, + "contain.text", + -1, + ); + agHelper.WaitUntilAllToastsDisappear(); + agHelper.ActionContextMenuWithInPane({ + action: "Delete", + entityType: entityItems.JSObject, + }); + }; + assertInvalidJSObjectStart(jsObjectStartingWithAComment, jsComment); + assertInvalidJSObjectStart( + jsObjectStartingWithANewLine, + jsObjectStartLine, + ); + assertInvalidJSObjectStart( + jsObjectStartingWithASpace, + jsObjectStartLineWithSpace, + ); + }); + + it("5. Supports the use of large JSON data (doesn't crash)", () => { + const jsObjectWithLargeJSONData = `export default{ + largeData: ${JSON.stringify(largeJSONData)}, + myfun1: ()=> this.largeData + }`; + const crashMessage = "Oops! Something went wrong"; + // create jsObject with large json data and run + jsEditor.CreateJSObject(jsObjectWithLargeJSONData, { paste: true, completeReplace: true, toRun: false, shouldCreateNewJSObj: true, }); - // Assert presence of toast message - agHelper.AssertContains(invalidJSObjectStartToastMessage); + // wait for 3 secs and assert that App doesn't crash + agHelper.Sleep(3000); + agHelper.AssertContains(crashMessage, "not.exist"); - // Assert presence of lint error at the start line - agHelper.GetNAssertElementText( - locators._lintErrorElement, - highlightedLintText, - "contain.text", - -1, - ); - agHelper.WaitUntilAllToastsDisappear(); - agHelper.ActionContextMenuWithInPane({ - action: "Delete", - entityType: entityItems.JSObject, + // Edit JSObject and run + jsEditor.CreateJSObject(" ", { + paste: true, + completeReplace: false, + toRun: true, + shouldCreateNewJSObj: false, }); - }; - assertInvalidJSObjectStart(jsObjectStartingWithAComment, jsComment); - assertInvalidJSObjectStart(jsObjectStartingWithANewLine, jsObjectStartLine); - assertInvalidJSObjectStart( - jsObjectStartingWithASpace, - jsObjectStartLineWithSpace, - ); - }); - - it("5. Supports the use of large JSON data (doesn't crash)", () => { - const jsObjectWithLargeJSONData = `export default{ - largeData: ${JSON.stringify(largeJSONData)}, - myfun1: ()=> this.largeData - }`; - const crashMessage = "Oops! Something went wrong"; - // create jsObject with large json data and run - jsEditor.CreateJSObject(jsObjectWithLargeJSONData, { - paste: true, - completeReplace: true, - toRun: false, - shouldCreateNewJSObj: true, - }); - // wait for 3 secs and assert that App doesn't crash - agHelper.Sleep(3000); - agHelper.AssertContains(crashMessage, "not.exist"); - - // Edit JSObject and run - jsEditor.CreateJSObject(" ", { - paste: true, - completeReplace: false, - toRun: true, - shouldCreateNewJSObj: false, - }); - - cy.get("@jsObjName").then((jsObjName) => { - EditorNavigation.SelectEntityByName("Table1", EntityType.Widget); - propPane.UpdatePropertyFieldValue( - "Table data", - `{{${jsObjName}.largeData}}`, - ); - }); + cy.get("@jsObjName").then((jsObjName) => { + EditorNavigation.SelectEntityByName("Table1", EntityType.Widget); + propPane.UpdatePropertyFieldValue( + "Table data", + `{{${jsObjName}.largeData}}`, + ); + }); - // Deploy App and test that table loads properly - deployMode.DeployApp(); - table.WaitUntilTableLoad(); - table.ReadTableRowColumnData(0, 1, "v1", 2000).then(($cellData) => { - expect($cellData).to.eq("1"); //validating id column value - row 0 - deployMode.NavigateBacktoEditor(); - }); - EditorNavigation.SelectEntityByName("JSObject1", EntityType.JSObject); - entityExplorer.ActionContextMenuByEntityName({ - entityNameinLeftSidebar: "JSObject1", - action: "Delete", - entityType: entityItems.JSObject, + // Deploy App and test that table loads properly + deployMode.DeployApp(); + table.WaitUntilTableLoad(); + table.ReadTableRowColumnData(0, 1, "v1", 2000).then(($cellData) => { + expect($cellData).to.eq("1"); //validating id column value - row 0 + deployMode.NavigateBacktoEditor(); + }); + EditorNavigation.SelectEntityByName("JSObject1", EntityType.JSObject); + entityExplorer.ActionContextMenuByEntityName({ + entityNameinLeftSidebar: "JSObject1", + action: "Delete", + entityType: entityItems.JSObject, + }); }); - }); - it("6. Doesn't cause cyclic dependency when function name is edited", () => { - const syncJSCode = `export default { + it("6. Doesn't cause cyclic dependency when function name is edited", () => { + const syncJSCode = `export default { myFun1 :()=>{ return "yes"`; - const syncJSCodeWithRenamedFunction1 = `export default { + const syncJSCodeWithRenamedFunction1 = `export default { myFun2 :()=>{ return "yes" } }`; - const syncJSCodeWithRenamedFunction2 = `export default { + const syncJSCodeWithRenamedFunction2 = `export default { myFun3 :()=>{ return "yes" } }`; - const asyncJSCode = `export default { + const asyncJSCode = `export default { myFun1 :async ()=>{ return "yes"`; - const asyncJSCodeWithRenamedFunction1 = `export default { + const asyncJSCodeWithRenamedFunction1 = `export default { myFun2 :async ()=>{ return "yes" } }`; - const asyncJSCodeWithRenamedFunction2 = `export default { + const asyncJSCodeWithRenamedFunction2 = `export default { myFun3 :async ()=>{ return "yes" } }`; - jsEditor.CreateJSObject(syncJSCode, { - paste: false, - completeReplace: true, - toRun: false, - shouldCreateNewJSObj: true, - prettify: false, - }); + jsEditor.CreateJSObject(syncJSCode, { + paste: false, + completeReplace: true, + toRun: false, + shouldCreateNewJSObj: true, + prettify: false, + }); - // change sync function name and test that cyclic dependency is not created - jsEditor.EditJSObj(syncJSCodeWithRenamedFunction1, false); - agHelper.AssertContains("Cyclic dependency", "not.exist"); - jsEditor.EditJSObj(syncJSCodeWithRenamedFunction2, false); - agHelper.AssertContains("Cyclic dependency", "not.exist"); - - jsEditor.CreateJSObject(asyncJSCode, { - paste: false, - completeReplace: true, - toRun: false, - shouldCreateNewJSObj: true, - prettify: false, - }); - // change function name and test that cyclic dependency is not created - jsEditor.EditJSObj(asyncJSCodeWithRenamedFunction1, false); - agHelper.AssertContains("Cyclic dependency", "not.exist"); - jsEditor.EditJSObj(asyncJSCodeWithRenamedFunction2, false); - agHelper.AssertContains("Cyclic dependency", "not.exist"); - agHelper.ActionContextMenuWithInPane({ - action: "Delete", - entityType: entityItems.JSObject, + // change sync function name and test that cyclic dependency is not created + jsEditor.EditJSObj(syncJSCodeWithRenamedFunction1, false); + agHelper.AssertContains("Cyclic dependency", "not.exist"); + jsEditor.EditJSObj(syncJSCodeWithRenamedFunction2, false); + agHelper.AssertContains("Cyclic dependency", "not.exist"); + + jsEditor.CreateJSObject(asyncJSCode, { + paste: false, + completeReplace: true, + toRun: false, + shouldCreateNewJSObj: true, + prettify: false, + }); + // change function name and test that cyclic dependency is not created + jsEditor.EditJSObj(asyncJSCodeWithRenamedFunction1, false); + agHelper.AssertContains("Cyclic dependency", "not.exist"); + jsEditor.EditJSObj(asyncJSCodeWithRenamedFunction2, false); + agHelper.AssertContains("Cyclic dependency", "not.exist"); + agHelper.ActionContextMenuWithInPane({ + action: "Delete", + entityType: entityItems.JSObject, + }); }); - }); - - it("7. Maintains order of functions in settings tab alphabetically at all times", function () { - functionsLength = FUNCTIONS_SETTINGS_DEFAULT_DATA.length; - // Number of functions set to run on page load and should also confirm before execute - onPageLoadAndConfirmExecuteFunctionsLength = - FUNCTIONS_SETTINGS_DEFAULT_DATA.filter( - (func) => func.onPageLoad && func.confirmBeforeExecute, - ).length; - - getJSObject = (data: IFunctionSettingData[]) => { - let JS_OBJECT_BODY = `export default`; - for (let i = 0; i < functionsLength; i++) { - const functionName = data[i].name; - const isMarkedAsync = data[i].isMarkedAsync; - JS_OBJECT_BODY += - i === 0 - ? `{ + + it("7. Maintains order of functions in settings tab alphabetically at all times", function () { + functionsLength = FUNCTIONS_SETTINGS_DEFAULT_DATA.length; + // Number of functions set to run on page load and should also confirm before execute + onPageLoadAndConfirmExecuteFunctionsLength = + FUNCTIONS_SETTINGS_DEFAULT_DATA.filter( + (func) => func.onPageLoad && func.confirmBeforeExecute, + ).length; + + getJSObject = (data: IFunctionSettingData[]) => { + let JS_OBJECT_BODY = `export default`; + for (let i = 0; i < functionsLength; i++) { + const functionName = data[i].name; + const isMarkedAsync = data[i].isMarkedAsync; + JS_OBJECT_BODY += + i === 0 + ? `{ ${functionName}: ${ isMarkedAsync ? "async" : "" } ()=>"${functionName}",` - : i === functionsLength - 1 - ? ` + : i === functionsLength - 1 + ? ` ${functionName}: ${ isMarkedAsync ? "async" : "" } ()=>"${functionName}", }` - : ` + : ` ${functionName}: ${ isMarkedAsync ? "async" : "" } ()=> "${functionName}",`; - } - return JS_OBJECT_BODY; - }; - - // Create js object - jsEditor.CreateJSObject(getJSObject(FUNCTIONS_SETTINGS_DEFAULT_DATA), { - paste: true, - completeReplace: true, - toRun: false, - shouldCreateNewJSObj: true, - prettify: false, - }); + } + return JS_OBJECT_BODY; + }; - cy.get("@jsObjName").then((jsObjName: any) => { - jsObj = jsObjName; + // Create js object + jsEditor.CreateJSObject(getJSObject(FUNCTIONS_SETTINGS_DEFAULT_DATA), { + paste: true, + completeReplace: true, + toRun: false, + shouldCreateNewJSObj: true, + prettify: false, + }); + + cy.get("@jsObjName").then((jsObjName: any) => { + jsObj = jsObjName; + }); + // Switch to settings tab + agHelper.GetNClick(jsEditor._settingsTab); + // Add settings for each function (according to data) + Object.values(FUNCTIONS_SETTINGS_DEFAULT_DATA).forEach( + (functionSetting) => { + jsEditor.EnableDisableAsyncFuncSettings( + functionSetting.name, + functionSetting.onPageLoad, + ); + }, + ); + // Switch to settings tab + agHelper.GetNClick(jsEditor._settingsTab); + //After JSObj is created - check methods are in alphabetical order + assertAsyncFunctionsOrder(FUNCTIONS_SETTINGS_DEFAULT_DATA); + + agHelper.RefreshPage(); + agHelper.Sleep(2000); //for confirmatiom modal to appear before clicking on "Yes" button for CI runs + // Switch to settings tab and assert order + agHelper.GetNClick(jsEditor._settingsTab); + assertAsyncFunctionsOrder(FUNCTIONS_SETTINGS_DEFAULT_DATA); }); - // Switch to settings tab - agHelper.GetNClick(jsEditor._settingsTab); - // Add settings for each function (according to data) - Object.values(FUNCTIONS_SETTINGS_DEFAULT_DATA).forEach( - (functionSetting) => { - jsEditor.EnableDisableAsyncFuncSettings( - functionSetting.name, - functionSetting.onPageLoad, - ); - }, - ); - // Switch to settings tab - agHelper.GetNClick(jsEditor._settingsTab); - //After JSObj is created - check methods are in alphabetical order - assertAsyncFunctionsOrder(FUNCTIONS_SETTINGS_DEFAULT_DATA); - - agHelper.RefreshPage(); - agHelper.Sleep(2000); //for confirmatiom modal to appear before clicking on "Yes" button for CI runs - // Switch to settings tab and assert order - agHelper.GetNClick(jsEditor._settingsTab); - assertAsyncFunctionsOrder(FUNCTIONS_SETTINGS_DEFAULT_DATA); - }); - - it("8. Verify Async methods have alphabetical order after cloning page and renaming it", () => { - const FUNCTIONS_SETTINGS_RENAMED_DATA: IFunctionSettingData[] = [ - { - name: "newGetId", - onPageLoad: true, - confirmBeforeExecute: false, - isMarkedAsync: false, - }, - { - name: "zip1", - onPageLoad: true, - confirmBeforeExecute: true, - isMarkedAsync: true, - }, - { - name: "base", - onPageLoad: false, - confirmBeforeExecute: false, - isMarkedAsync: true, - }, - { - name: "newAssert", - onPageLoad: true, - confirmBeforeExecute: false, - isMarkedAsync: false, - }, - { - name: "test", - onPageLoad: true, - confirmBeforeExecute: true, - isMarkedAsync: true, - }, - ]; - // clone page and assert order of functions - PageList.ClonePage(); - agHelper.Sleep(); - agHelper.WaitUntilAllToastsDisappear(); - agHelper.Sleep(); - - EditorNavigation.SelectEntityByName(jsObj, EntityType.JSObject); - agHelper.GetNClick(jsEditor._settingsTab); - assertAsyncFunctionsOrder(FUNCTIONS_SETTINGS_DEFAULT_DATA); - - // rename functions and assert order - agHelper.GetNClick(jsEditor._codeTab); - jsEditor.EditJSObj(getJSObject(FUNCTIONS_SETTINGS_RENAMED_DATA), false); - agHelper.Sleep(3000); - agHelper.GetNClick(jsEditor._settingsTab); - assertAsyncFunctionsOrder(FUNCTIONS_SETTINGS_RENAMED_DATA); - agHelper.ActionContextMenuWithInPane({ - action: "Delete", - entityType: entityItems.JSObject, + it("8. Verify Async methods have alphabetical order after cloning page and renaming it", () => { + const FUNCTIONS_SETTINGS_RENAMED_DATA: IFunctionSettingData[] = [ + { + name: "newGetId", + onPageLoad: true, + confirmBeforeExecute: false, + isMarkedAsync: false, + }, + { + name: "zip1", + onPageLoad: true, + confirmBeforeExecute: true, + isMarkedAsync: true, + }, + { + name: "base", + onPageLoad: false, + confirmBeforeExecute: false, + isMarkedAsync: true, + }, + { + name: "newAssert", + onPageLoad: true, + confirmBeforeExecute: false, + isMarkedAsync: false, + }, + { + name: "test", + onPageLoad: true, + confirmBeforeExecute: true, + isMarkedAsync: true, + }, + ]; + + // clone page and assert order of functions + PageList.ClonePage(); + agHelper.Sleep(); + agHelper.WaitUntilAllToastsDisappear(); + agHelper.Sleep(); + + EditorNavigation.SelectEntityByName(jsObj, EntityType.JSObject); + agHelper.GetNClick(jsEditor._settingsTab); + assertAsyncFunctionsOrder(FUNCTIONS_SETTINGS_DEFAULT_DATA); + + // rename functions and assert order + agHelper.GetNClick(jsEditor._codeTab); + jsEditor.EditJSObj(getJSObject(FUNCTIONS_SETTINGS_RENAMED_DATA), false); + agHelper.Sleep(3000); + agHelper.GetNClick(jsEditor._settingsTab); + assertAsyncFunctionsOrder(FUNCTIONS_SETTINGS_RENAMED_DATA); + agHelper.ActionContextMenuWithInPane({ + action: "Delete", + entityType: entityItems.JSObject, + }); }); - }); - it("9. Bug 13197: Verify converting async functions to sync doesn't reset all settings", () => { - const asyncJSCode = `export default { + it("9. Bug 13197: Verify converting async functions to sync doesn't reset all settings", () => { + const asyncJSCode = `export default { name: "Appsmith", asyncToSync : async ()=>{ return "yes";`; - const syncJSCode = `export default { + const syncJSCode = `export default { name: "Appsmith", asyncToSync : ()=>{ return "yes"; }, }`; - jsEditor.CreateJSObject(asyncJSCode, { - paste: false, - completeReplace: true, - toRun: false, - shouldCreateNewJSObj: true, - prettify: false, - }); + jsEditor.CreateJSObject(asyncJSCode, { + paste: false, + completeReplace: true, + toRun: false, + shouldCreateNewJSObj: true, + prettify: false, + }); + + // Switch to settings tab + agHelper.GetNClick(jsEditor._settingsTab); + // Enable all settings + jsEditor.EnableDisableAsyncFuncSettings("asyncToSync", true); - // Switch to settings tab - agHelper.GetNClick(jsEditor._settingsTab); - // Enable all settings - jsEditor.EnableDisableAsyncFuncSettings("asyncToSync", true); - - // Modify js object - jsEditor.EditJSObj(syncJSCode, false); - agHelper.RefreshPage(); - jsEditor.VerifyAsyncFuncSettings("asyncToSync", true); - agHelper.ActionContextMenuWithInPane({ - action: "Delete", - entityType: entityItems.JSObject, + // Modify js object + jsEditor.EditJSObj(syncJSCode, false); + agHelper.RefreshPage(); + jsEditor.VerifyAsyncFuncSettings("asyncToSync", true); + agHelper.ActionContextMenuWithInPane({ + action: "Delete", + entityType: entityItems.JSObject, + }); }); - }); - it("10. Verify that js function execution errors are logged in debugger and removed when function is deleted", () => { - const JS_OBJECT_WITH_PARSE_ERROR = `export default { + it("10. Verify that js function execution errors are logged in debugger and removed when function is deleted", () => { + const JS_OBJECT_WITH_PARSE_ERROR = `export default { myVar1: [], myVar2: {}, myFun1: () => { return Table1.unknown.id`; - const JS_OBJECT_WITHOUT_PARSE_ERROR = `export default { + const JS_OBJECT_WITHOUT_PARSE_ERROR = `export default { myVar1: [], myVar2: {}, myFun1: () => { @@ -522,60 +529,61 @@ return "yes";`; } }`; - const JS_OBJECT_WITH_DELETED_FUNCTION = `export default { + const JS_OBJECT_WITH_DELETED_FUNCTION = `export default { myVar1: [], myVar2: {} }`; - // Create js object - jsEditor.CreateJSObject(JS_OBJECT_WITH_PARSE_ERROR, { - paste: false, - completeReplace: true, - toRun: true, - shouldCreateNewJSObj: true, - }); + // Create js object + jsEditor.CreateJSObject(JS_OBJECT_WITH_PARSE_ERROR, { + paste: false, + completeReplace: true, + toRun: true, + shouldCreateNewJSObj: true, + }); - // Assert that there is a function execution parse error - jsEditor.AssertParseError(true); - // Assert that response tab is not empty - agHelper.AssertContains("No signs of trouble here!", "not.exist"); - // Assert presence of typeError in response tab - agHelper.AssertContains('"Table1.unknown" is undefined', "exist"); - agHelper.AssertContains("TypeError", "exist"); - - // click the error tab - agHelper.GetNClick(locators._errorTab); - // Assert that errors tab is not empty - agHelper.AssertContains("No signs of trouble here!", "not.exist"); - // Assert presence of typeError in error tab - agHelper.AssertContains('"Table1.unknown" is undefined', "exist"); - agHelper.AssertContains("TypeError", "exist"); - - // Fix parse error and assert that debugger error is removed - jsEditor.EditJSObj(JS_OBJECT_WITHOUT_PARSE_ERROR, true, false); - agHelper.RefreshPage(); - jsEditor.RunJSObj(); - //agHelper.AssertContains("ran successfully"); //commenting since 'Resource not found' comes sometimes due to fast parsing - agHelper.AssertElementAbsence(locators._btnSpinner, 10000); - agHelper.GetNClick(locators._errorTab); - agHelper.AssertContains('"Table1.unknown" is undefined', "not.exist"); - - // Switch back to response tab - agHelper.GetNClick(locators._responseTab); - // Re-introduce parse errors - jsEditor.EditJSObj(JS_OBJECT_WITH_PARSE_ERROR + "}}", false, false); - jsEditor.RunJSObj(); - // Assert that there is a function execution parse error - jsEditor.AssertParseError(true); - - // Delete function - jsEditor.EditJSObj(JS_OBJECT_WITH_DELETED_FUNCTION, true, false); - // Assert that parse error is removed from debugger when function is deleted - agHelper.GetNClick(locators._errorTab); - agHelper.AssertContains('"Table1.unknown" is undefined.', "not.exist"); - agHelper.ActionContextMenuWithInPane({ - action: "Delete", - entityType: entityItems.JSObject, + // Assert that there is a function execution parse error + jsEditor.AssertParseError(true); + // Assert that response tab is not empty + agHelper.AssertContains("No signs of trouble here!", "not.exist"); + // Assert presence of typeError in response tab + agHelper.AssertContains('"Table1.unknown" is undefined', "exist"); + agHelper.AssertContains("TypeError", "exist"); + + // click the error tab + agHelper.GetNClick(locators._errorTab); + // Assert that errors tab is not empty + agHelper.AssertContains("No signs of trouble here!", "not.exist"); + // Assert presence of typeError in error tab + agHelper.AssertContains('"Table1.unknown" is undefined', "exist"); + agHelper.AssertContains("TypeError", "exist"); + + // Fix parse error and assert that debugger error is removed + jsEditor.EditJSObj(JS_OBJECT_WITHOUT_PARSE_ERROR, true, false); + agHelper.RefreshPage(); + jsEditor.RunJSObj(); + //agHelper.AssertContains("ran successfully"); //commenting since 'Resource not found' comes sometimes due to fast parsing + agHelper.AssertElementAbsence(locators._btnSpinner, 10000); + agHelper.GetNClick(locators._errorTab); + agHelper.AssertContains('"Table1.unknown" is undefined', "not.exist"); + + // Switch back to response tab + agHelper.GetNClick(locators._responseTab); + // Re-introduce parse errors + jsEditor.EditJSObj(JS_OBJECT_WITH_PARSE_ERROR + "}}", false, false); + jsEditor.RunJSObj(); + // Assert that there is a function execution parse error + jsEditor.AssertParseError(true); + + // Delete function + jsEditor.EditJSObj(JS_OBJECT_WITH_DELETED_FUNCTION, true, false); + // Assert that parse error is removed from debugger when function is deleted + agHelper.GetNClick(locators._errorTab); + agHelper.AssertContains('"Table1.unknown" is undefined.', "not.exist"); + agHelper.ActionContextMenuWithInPane({ + action: "Delete", + entityType: entityItems.JSObject, + }); }); - }); -}); + }, +); diff --git a/app/client/cypress/e2e/Regression/ServerSide/LoginTests/LoginFailure_spec.js b/app/client/cypress/e2e/Regression/ServerSide/LoginTests/LoginFailure_spec.js index b12ea55aa77..df2411164d6 100644 --- a/app/client/cypress/e2e/Regression/ServerSide/LoginTests/LoginFailure_spec.js +++ b/app/client/cypress/e2e/Regression/ServerSide/LoginTests/LoginFailure_spec.js @@ -5,7 +5,7 @@ import { locators, } from "../../../../support/Objects/ObjectsCore"; -describe("Login failure", function () { +describe("Login failure", { tags: ["@tag.Authentication"] }, function () { it("1. Preserves redirectUrl param on login failure", function () { let urlWithoutQueryParams; deployMode.DeployApp(locators._emptyPageTxt, true, false); diff --git a/app/client/cypress/e2e/Regression/ServerSide/OnLoadTests/OnLoadActions_Spec.ts b/app/client/cypress/e2e/Regression/ServerSide/OnLoadTests/OnLoadActions_Spec.ts index 302bc1c1c13..8da531365f6 100644 --- a/app/client/cypress/e2e/Regression/ServerSide/OnLoadTests/OnLoadActions_Spec.ts +++ b/app/client/cypress/e2e/Regression/ServerSide/OnLoadTests/OnLoadActions_Spec.ts @@ -15,7 +15,7 @@ import EditorNavigation, { describe( "Layout OnLoad Actions tests", - { tags: ["@tag.PropertyPane", "@tag.JS"] }, + { tags: ["@tag.PropertyPane", "@tag.JS", "@tag.Sanity"] }, function () { beforeEach(() => { agHelper.RestoreLocalStorageCache(); diff --git a/app/client/cypress/e2e/Regression/ServerSide/OnLoadTests/PostgresConnections_spec.ts b/app/client/cypress/e2e/Regression/ServerSide/OnLoadTests/PostgresConnections_spec.ts index 1dd6b2e1f01..62d096a0f37 100644 --- a/app/client/cypress/e2e/Regression/ServerSide/OnLoadTests/PostgresConnections_spec.ts +++ b/app/client/cypress/e2e/Regression/ServerSide/OnLoadTests/PostgresConnections_spec.ts @@ -17,7 +17,7 @@ let guid: any, dsName_1: any, dsName_2: any; describe( "Test Postgres number of connections on page load + Bug 11572, Bug 11202", - { tags: ["@tag.PropertyPane", "@tag.JS"] }, + { tags: ["@tag.PropertyPane", "@tag.JS", "@tag.Sanity"] }, function () { before(() => { agHelper.GenerateUUID(); diff --git a/app/client/cypress/e2e/Regression/ServerSide/QueryPane/Mongo1_spec.ts b/app/client/cypress/e2e/Regression/ServerSide/QueryPane/Mongo1_spec.ts index 267cbc080e5..d6f16abe1e2 100644 --- a/app/client/cypress/e2e/Regression/ServerSide/QueryPane/Mongo1_spec.ts +++ b/app/client/cypress/e2e/Regression/ServerSide/QueryPane/Mongo1_spec.ts @@ -21,7 +21,7 @@ let dsName: any; describe( "Validate Mongo Query Pane Validations", - { tags: ["@tag.Datasource"] }, + { tags: ["@tag.Datasource", "@tag.Sanity"] }, () => { before(() => { //dataSources.StartDataSourceRoutes(); //already started in index.js beforeeach diff --git a/app/client/cypress/e2e/Regression/ServerSide/QueryPane/Querypane_Mongo_Spec.js b/app/client/cypress/e2e/Regression/ServerSide/QueryPane/Querypane_Mongo_Spec.js index 44d559645eb..8a5f313c449 100644 --- a/app/client/cypress/e2e/Regression/ServerSide/QueryPane/Querypane_Mongo_Spec.js +++ b/app/client/cypress/e2e/Regression/ServerSide/QueryPane/Querypane_Mongo_Spec.js @@ -22,7 +22,7 @@ let datasourceName; describe( "Validate Mongo query commands", - { tags: ["@tag.Datasource"] }, + { tags: ["@tag.Datasource", "@tag.Sanity"] }, function () { // afterEach(function() { // if (this.currentTest.state === "failed") { diff --git a/app/client/cypress/e2e/Smoke/GenerateCRUD/Generate_Crud_New_Page_spec.ts b/app/client/cypress/e2e/Smoke/GenerateCRUD/Generate_Crud_New_Page_spec.ts index 603cb0b4e5c..a361763aa9b 100644 --- a/app/client/cypress/e2e/Smoke/GenerateCRUD/Generate_Crud_New_Page_spec.ts +++ b/app/client/cypress/e2e/Smoke/GenerateCRUD/Generate_Crud_New_Page_spec.ts @@ -3,7 +3,7 @@ import PageList from "../../../support/Pages/PageList"; describe( "Validate generate CRUD operation by creating a datasource from generate CRUD form", - { tags: ["@tag.Datasource"] }, + { tags: ["@tag.Datasource", "@tag.Sanity"] }, () => { it( "1. Generated CRUD app should work when there are no entities in the page & when there are entities in the current page", diff --git a/app/client/cypress/fixtures/tableV2FilteringWithPrimaryColumn.json b/app/client/cypress/fixtures/tableV2FilteringWithPrimaryColumn.json new file mode 100644 index 00000000000..68abd3e8474 --- /dev/null +++ b/app/client/cypress/fixtures/tableV2FilteringWithPrimaryColumn.json @@ -0,0 +1,449 @@ +{ + "dsl": { + "widgetName": "MainContainer", + "backgroundColor": "none", + "rightColumn": 4896, + "snapColumns": 64, + "detachFromLayout": true, + "widgetId": "0", + "topRow": 0, + "bottomRow": 1282, + "containerStyle": "none", + "snapRows": 124, + "parentRowSpace": 1, + "type": "CANVAS_WIDGET", + "canExtend": true, + "version": 90, + "minHeight": 1292, + "dynamicTriggerPathList": [], + "parentColumnSpace": 1, + "dynamicBindingPathList": [], + "leftColumn": 0, + "children": [ + { + "boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}", + "borderColor": "#E0DEDE", + "isVisibleDownload": true, + "topRow": 1, + "isSortable": true, + "type": "TABLE_WIDGET_V2", + "inlineEditingSaveOption": "ROW_LEVEL", + "animateLoading": true, + "dynamicBindingPathList": [ + { + "key": "accentColor" + }, + { + "key": "borderRadius" + }, + { + "key": "boxShadow" + }, + { + "key": "primaryColumns.name.computedValue" + }, + { + "key": "primaryColumns.department.computedValue" + }, + { + "key": "primaryColumns.location.computedValue" + }, + { + "key": "tableData" + }, + { + "key": "primaryColumns.employeeId.computedValue" + }, + { + "key": "primaryColumns.position.computedValue" + }, + { + "key": "primaryColumns.salary.computedValue" + } + ], + "leftColumn": 0, + "delimiter": ",", + "defaultSelectedRowIndex": 0, + "flexVerticalAlignment": "start", + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "isVisibleFilters": true, + "isVisible": true, + "enableClientSideSearch": true, + "version": 2, + "totalRecordsCount": 0, + "isLoading": false, + "childStylesheet": { + "button": { + "buttonColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none" + }, + "menuButton": { + "menuColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none" + }, + "iconButton": { + "buttonColor": "{{appsmith.theme.colors.primaryColor}}", + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "boxShadow": "none" + }, + "editActions": { + "saveButtonColor": "{{appsmith.theme.colors.primaryColor}}", + "saveBorderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "discardButtonColor": "{{appsmith.theme.colors.primaryColor}}", + "discardBorderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}" + } + }, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "columnUpdatedAt": 1726719516718, + "primaryColumnId": "employeeId", + "defaultSelectedRowIndices": [0], + "needsErrorInfo": false, + "mobileBottomRow": 35, + "widgetName": "Table1", + "defaultPageSize": 0, + "columnOrder": [ + "name", + "department", + "location", + "employeeId", + "position", + "salary" + ], + "dynamicPropertyPathList": [ + { + "key": "tableData" + } + ], + "bottomRow": 29, + "columnWidthMap": {}, + "parentRowSpace": 10, + "mobileRightColumn": 46, + "parentColumnSpace": 10.546875, + "dynamicTriggerPathList": [], + "borderWidth": "1", + "primaryColumns": { + "name": { + "allowCellWrapping": false, + "allowSameOptionsInNewRow": true, + "index": 1, + "width": 150, + "originalId": "name", + "id": "name", + "alias": "name", + "horizontalAlignment": "LEFT", + "verticalAlignment": "CENTER", + "columnType": "text", + "textSize": "0.875rem", + "enableFilter": true, + "enableSort": true, + "isVisible": true, + "isDisabled": false, + "isCellEditable": false, + "isEditable": false, + "isCellVisible": true, + "isDerived": false, + "label": "name", + "isSaveVisible": true, + "isDiscardVisible": true, + "computedValue": "{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"name\"]))}}", + "sticky": "", + "validation": {}, + "currencyCode": "USD", + "decimals": 0, + "thousandSeparator": true, + "notation": "standard" + }, + "department": { + "allowCellWrapping": false, + "allowSameOptionsInNewRow": true, + "index": 4, + "width": 150, + "originalId": "department", + "id": "department", + "alias": "department", + "horizontalAlignment": "LEFT", + "verticalAlignment": "CENTER", + "columnType": "text", + "textSize": "0.875rem", + "enableFilter": true, + "enableSort": true, + "isVisible": true, + "isDisabled": false, + "isCellEditable": false, + "isEditable": false, + "isCellVisible": true, + "isDerived": false, + "label": "department", + "isSaveVisible": true, + "isDiscardVisible": true, + "computedValue": "{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"department\"]))}}", + "sticky": "", + "validation": {}, + "currencyCode": "USD", + "decimals": 0, + "thousandSeparator": true, + "notation": "standard" + }, + "location": { + "allowCellWrapping": false, + "allowSameOptionsInNewRow": true, + "index": 5, + "width": 150, + "originalId": "location", + "id": "location", + "alias": "location", + "horizontalAlignment": "LEFT", + "verticalAlignment": "CENTER", + "columnType": "text", + "textSize": "0.875rem", + "enableFilter": true, + "enableSort": true, + "isVisible": true, + "isDisabled": false, + "isCellEditable": false, + "isEditable": false, + "isCellVisible": true, + "isDerived": false, + "label": "location", + "isSaveVisible": true, + "isDiscardVisible": true, + "computedValue": "{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"location\"]))}}", + "sticky": "", + "validation": {}, + "currencyCode": "USD", + "decimals": 0, + "thousandSeparator": true, + "notation": "standard" + }, + "employeeId": { + "allowCellWrapping": false, + "allowSameOptionsInNewRow": true, + "index": 0, + "width": 150, + "originalId": "employeeId", + "id": "employeeId", + "alias": "employeeId", + "horizontalAlignment": "LEFT", + "verticalAlignment": "CENTER", + "columnType": "number", + "textColor": "", + "textSize": "0.875rem", + "fontStyle": "", + "enableFilter": true, + "enableSort": true, + "isVisible": true, + "isDisabled": false, + "isCellEditable": false, + "isEditable": false, + "isCellVisible": true, + "isDerived": false, + "label": "employeeId", + "isSaveVisible": true, + "isDiscardVisible": true, + "computedValue": "{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"employeeId\"]))}}", + "sticky": "", + "validation": {}, + "currencyCode": "USD", + "decimals": 0, + "thousandSeparator": true, + "notation": "standard", + "cellBackground": "" + }, + "position": { + "allowCellWrapping": false, + "allowSameOptionsInNewRow": true, + "index": 3, + "width": 150, + "originalId": "position", + "id": "position", + "alias": "position", + "horizontalAlignment": "LEFT", + "verticalAlignment": "CENTER", + "columnType": "text", + "textColor": "", + "textSize": "0.875rem", + "fontStyle": "", + "enableFilter": true, + "enableSort": true, + "isVisible": true, + "isDisabled": false, + "isCellEditable": false, + "isEditable": false, + "isCellVisible": true, + "isDerived": false, + "label": "position", + "isSaveVisible": true, + "isDiscardVisible": true, + "computedValue": "{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"position\"]))}}", + "sticky": "", + "validation": {}, + "currencyCode": "USD", + "decimals": 0, + "thousandSeparator": true, + "notation": "standard", + "cellBackground": "" + }, + "salary": { + "allowCellWrapping": false, + "allowSameOptionsInNewRow": true, + "index": 5, + "width": 150, + "originalId": "salary", + "id": "salary", + "alias": "salary", + "horizontalAlignment": "LEFT", + "verticalAlignment": "CENTER", + "columnType": "number", + "textColor": "", + "textSize": "0.875rem", + "fontStyle": "", + "enableFilter": true, + "enableSort": true, + "isVisible": true, + "isDisabled": false, + "isCellEditable": false, + "isEditable": false, + "isCellVisible": true, + "isDerived": false, + "label": "salary", + "isSaveVisible": true, + "isDiscardVisible": true, + "computedValue": "{{Table1.processedTableData.map((currentRow, currentIndex) => ( currentRow[\"salary\"]))}}", + "sticky": "", + "validation": {}, + "currencyCode": "USD", + "decimals": 0, + "thousandSeparator": true, + "notation": "standard", + "cellBackground": "" + } + }, + "key": "1vnt7cehmt", + "canFreezeColumn": true, + "rightColumn": 64, + "textSize": "0.875rem", + "widgetId": "gt19wbzlit", + "minWidth": 450, + "tableData": "{{JSObject2.data}}", + "label": "Data", + "searchKey": "", + "parentId": "0", + "renderMode": "CANVAS", + "mobileTopRow": 7, + "horizontalAlignment": "LEFT", + "isVisibleSearch": true, + "responsiveBehavior": "fill", + "mobileLeftColumn": 12, + "isVisiblePagination": true, + "verticalAlignment": "CENTER" + }, + { + "needsErrorInfo": false, + "mobileBottomRow": 44, + "widgetName": "Text1", + "topRow": 34, + "bottomRow": 38, + "parentRowSpace": 10, + "type": "TEXT_WIDGET", + "mobileRightColumn": 18, + "animateLoading": true, + "overflow": "NONE", + "fontFamily": "{{appsmith.theme.fontFamily.appFont}}", + "parentColumnSpace": 10.546875, + "dynamicTriggerPathList": [], + "leftColumn": 2, + "dynamicBindingPathList": [ + { + "key": "truncateButtonColor" + }, + { + "key": "fontFamily" + }, + { + "key": "borderRadius" + }, + { + "key": "text" + } + ], + "shouldTruncate": false, + "truncateButtonColor": "{{appsmith.theme.colors.primaryColor}}", + "text": "{{Table1.selectedRowIndex}}", + "key": "dlet8mfjip", + "rightColumn": 18, + "textAlign": "LEFT", + "dynamicHeight": "AUTO_HEIGHT", + "widgetId": "irgoh659po", + "minWidth": 450, + "isVisible": true, + "fontStyle": "BOLD", + "textColor": "#231F20", + "version": 1, + "parentId": "0", + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 40, + "responsiveBehavior": "fill", + "originalTopRow": 40, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 2, + "maxDynamicHeight": 9000, + "originalBottomRow": 44, + "fontSize": "1rem", + "minDynamicHeight": 4 + }, + { + "resetFormOnClick": false, + "needsErrorInfo": false, + "boxShadow": "none", + "mobileBottomRow": 44, + "widgetName": "Button1", + "onClick": "{{JSObject2.makeNewCopy();}}", + "buttonColor": "{{appsmith.theme.colors.primaryColor}}", + "topRow": 34, + "bottomRow": 38, + "parentRowSpace": 10, + "type": "BUTTON_WIDGET", + "mobileRightColumn": 55, + "animateLoading": true, + "parentColumnSpace": 10.546875, + "dynamicTriggerPathList": [ + { + "key": "onClick" + } + ], + "leftColumn": 39, + "dynamicBindingPathList": [ + { + "key": "buttonColor" + }, + { + "key": "borderRadius" + } + ], + "text": "Submit", + "isDisabled": false, + "key": "mzyu2305os", + "rightColumn": 55, + "isDefaultClickDisabled": true, + "widgetId": "q29byryymd", + "minWidth": 120, + "isVisible": true, + "recaptchaType": "V3", + "version": 1, + "parentId": "0", + "renderMode": "CANVAS", + "isLoading": false, + "mobileTopRow": 40, + "responsiveBehavior": "hug", + "disabledWhenInvalid": false, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "mobileLeftColumn": 39, + "buttonVariant": "PRIMARY", + "placement": "CENTER" + } + ] + } +} diff --git a/app/client/cypress/fixtures/tableV2FilteringWithPrimaryColumnJSObjectWidthData.ts b/app/client/cypress/fixtures/tableV2FilteringWithPrimaryColumnJSObjectWidthData.ts new file mode 100644 index 00000000000..67bd37f395d --- /dev/null +++ b/app/client/cypress/fixtures/tableV2FilteringWithPrimaryColumnJSObjectWidthData.ts @@ -0,0 +1,84 @@ +export const tableDataJSObject = `export default { + initData :[ + { + "employeeId": 101, + "name": "John Doe", + "department": "Engineering", + "position": "Software Engineer", + "location": "San Francisco", + "salary": 120000 + }, + { + "employeeId": 102, + "name": "Jane Smith", + "department": "Engineering", + "position": "DevOps Engineer", + "location": "New York", + "salary": 115000 + }, + { + "employeeId": 103, + "name": "Alice Johnson", + "department": "Marketing", + "position": "Marketing Manager", + "location": "Chicago", + "salary": 90000 + }, + { + "employeeId": 104, + "name": "Robert Brown", + "department": "Sales", + "position": "Sales Executive", + "location": "Los Angeles", + "salary": 95000 + }, + { + "employeeId": 105, + "name": "Linda Davis", + "department": "HR", + "position": "HR Manager", + "location": "San Francisco", + "salary": 85000 + }, + { + "employeeId": 106, + "name": "Michael Wilson", + "department": "Engineering", + "position": "Frontend Developer", + "location": "San Francisco", + "salary": 105000 + }, + { + "employeeId": 107, + "name": "Emily Clark", + "department": "Marketing", + "position": "Content Specialist", + "location": "Chicago", + "salary": 75000 + }, + { + "employeeId": 108, + "name": "David Martinez", + "department": "Sales", + "position": "Sales Manager", + "location": "New York", + "salary": 110000 + }, + { + "employeeId": 109, + "name": "Sarah Lee", + "department": "HR", + "position": "Recruiter", + "location": "Los Angeles", + "salary": 70000 + }, + { + "employeeId": 110, + "name": "James Anderson", + "department": "Engineering", + "position": "Backend Developer", + "location": "New York", + "salary": 118000 + } +] +}`; diff --git a/app/client/cypress/locators/WidgetLocators.ts b/app/client/cypress/locators/WidgetLocators.ts index 3f841874987..d60513acf5e 100644 --- a/app/client/cypress/locators/WidgetLocators.ts +++ b/app/client/cypress/locators/WidgetLocators.ts @@ -61,6 +61,7 @@ export const PROPERTY_SELECTOR = { TextFieldName: "Text", tableData: ".t--property-control-tabledata", tableColumnNames: '[data-rbd-draggable-id] input[type="text"]', + jsToggle : '.t--js-toggle', }; export const WIDGETSKIT = { diff --git a/app/client/cypress/locators/Widgets.json b/app/client/cypress/locators/Widgets.json index 090de4f8a90..92b161d141b 100644 --- a/app/client/cypress/locators/Widgets.json +++ b/app/client/cypress/locators/Widgets.json @@ -230,5 +230,9 @@ "showResult": ".t--property-control-showresult input[type='checkbox']", "infiniteLoading": ".t--property-control-infiniteloading input[type='checkbox']", "counterclockwise": ".t--property-control-counterclockwise input[type='checkbox']", - "serversideFilteringInput": ".t--property-control-serversidefiltering input[type='checkbox']" + "serversideFilteringInput": ".t--property-control-serversidefiltering input[type='checkbox']", + "propertyPaneSaveButton": ".t--property-pane-section-collapse-savebutton", + "firstEditInput":"[data-colindex=0][data-rowindex=0] .t--inlined-cell-editor input.bp3-input", + "cellControlSwitch" : ".t--property-control-cellwrapping .ads-v2-switch", + "propertyControlLabel" : ".t--property-control-label" } diff --git a/app/client/knip.json b/app/client/knip.json new file mode 100644 index 00000000000..be642c7e057 --- /dev/null +++ b/app/client/knip.json @@ -0,0 +1,14 @@ +{ + "entry": ["src/index.tsx"], + "project": ["src/**/*.tsx"], + "ignore": [ + "packages/**/stories/**", + "packages/**/chromatic/**", + "packages/design-system/widgets/src/testing/**", + "**/*.stories.tsx", + "packages/rts/build.js", + "packages/design-system/ads/src/Documentation/**", + "src/components/designSystems/blueprintjs/**", + "packages/design-system/ads/plopfile.mjs" + ] +} diff --git a/app/client/package.json b/app/client/package.json index 500d3c2a328..6a6e80842c8 100644 --- a/app/client/package.json +++ b/app/client/package.json @@ -354,6 +354,7 @@ "jest-environment-jsdom": "^27.4.1", "jest-styled-components": "^7.0.8", "json5": "^2.2.3", + "knip": "^5.30.2", "lint-staged": "^14.0.1", "msw": "^0.28.0", "pg": "^8.11.3", diff --git a/app/client/packages/design-system/ads-old/src/ListSegmentHeader/index.tsx b/app/client/packages/design-system/ads-old/src/ListSegmentHeader/index.tsx deleted file mode 100644 index 37883db317a..00000000000 --- a/app/client/packages/design-system/ads-old/src/ListSegmentHeader/index.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import type { CSSProperties } from "react"; -import React from "react"; -import styled from "styled-components"; -import { typography } from "../constants/typography"; - -const StyledSegmentHeader = styled.div` - padding: var(--ads-spaces-3) var(--ads-spaces-5); - padding-right: 0; - font-weight: ${typography["u2"].fontWeight}; - font-size: ${typography["u2"].fontSize}px; - line-height: ${typography["u2"].lineHeight}px; - letter-spacing: ${typography["u2"].letterSpacing}px; - color: var(--ads-old-color-gray-10); - display: flex; - align-items: center; -`; - -const StyledHr = styled.div` - flex: 1; - height: 1px; - background-color: var(--ads-old-color-gray-10); - margin-left: var(--ads-spaces-3); -`; - -export interface SegmentHeaderProps { - title: string; - style?: CSSProperties; - hideStyledHr?: boolean; -} - -export default function SegmentHeader(props: SegmentHeaderProps) { - return ( - - {props.title} - {!props.hideStyledHr && ( - - )} - - ); -} diff --git a/app/client/packages/design-system/ads-old/src/hooks/index.tsx b/app/client/packages/design-system/ads-old/src/hooks/index.tsx deleted file mode 100644 index eec6f5c1c30..00000000000 --- a/app/client/packages/design-system/ads-old/src/hooks/index.tsx +++ /dev/null @@ -1,2 +0,0 @@ -export { default as useDSEvent } from "./useDSEvent"; -export { default as useResizeObserver } from "./useResizeObserver"; diff --git a/app/client/packages/design-system/ads-old/src/hooks/useResizeObserver.ts b/app/client/packages/design-system/ads-old/src/hooks/useResizeObserver.ts deleted file mode 100644 index b7f2b512110..00000000000 --- a/app/client/packages/design-system/ads-old/src/hooks/useResizeObserver.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { useEffect } from "react"; -import ResizeObserver from "resize-observer-polyfill"; - -const useResizeObserver = ( - ref: HTMLDivElement | null, - callback: (entries: any) => void, -) => { - useEffect(() => { - if (ref) { - const resizeObserver = new ResizeObserver((entries: any) => { - callback(entries); - }); - - resizeObserver.observe(ref); - - return () => resizeObserver.unobserve(ref); - } - }, [ref, callback]); -}; - -export default useResizeObserver; diff --git a/app/client/packages/design-system/headless/src/components/Field/HelpText.tsx b/app/client/packages/design-system/headless/src/components/Field/HelpText.tsx deleted file mode 100644 index bedc4e7e688..00000000000 --- a/app/client/packages/design-system/headless/src/components/Field/HelpText.tsx +++ /dev/null @@ -1,45 +0,0 @@ -import React, { forwardRef } from "react"; -import type { HTMLAttributes } from "react"; -import { useDOMRef } from "@react-spectrum/utils"; -import type { - DOMRef, - SpectrumHelpTextProps, - ValidationState, -} from "@react-types/shared"; - -interface HelpTextProps extends Omit { - /** Props for the help text description element. */ - descriptionProps?: HTMLAttributes; - /** Props for the help text error message element. */ - errorMessageProps?: HTMLAttributes; - /** validation state for help text */ - validationState: ValidationState; -} - -function _HelpText(props: HelpTextProps, ref: DOMRef) { - const { - description, - descriptionProps, - errorMessage, - errorMessageProps, - validationState, - } = props; - const domRef = useDOMRef(ref); - const isErrorMessage = Boolean(errorMessage) && validationState === "invalid"; - - return ( -
- {isErrorMessage ? ( -
- {errorMessage} -
- ) : ( -
- {description} -
- )} -
- ); -} - -export const HelpText = forwardRef(_HelpText); diff --git a/app/client/packages/design-system/widgets-old/src/constants/messages.tsx b/app/client/packages/design-system/widgets-old/src/constants/messages.tsx deleted file mode 100644 index 4093556d602..00000000000 --- a/app/client/packages/design-system/widgets-old/src/constants/messages.tsx +++ /dev/null @@ -1,38 +0,0 @@ -export function createMessage( - format: (...strArgs: any[]) => string, - ...args: any[] -) { - return format(...args); -} - -export const ERROR_MESSAGE_NAME_EMPTY = () => `Please select a name`; - -export const FORM_VALIDATION_INVALID_EMAIL = () => - `Please provide a valid email address`; - -export const INVITE_USERS_VALIDATION_EMAIL_LIST = () => - `Invalid email address(es) found`; - -export const REMOVE = () => "Remove"; - -export const DISPLAY_IMAGE_UPLOAD_LABEL = () => "Upload Display Picture"; - -export const ADD_REACTION = () => "Add reaction"; - -export const EMOJI = () => "Emoji"; - -// Showcase Carousel -export const NEXT = () => "NEXT"; -export const BACK = () => "BACK"; -export const SKIP = () => "SKIP"; - -export const LEARN_MORE = () => "Learn more"; - -export const SNIPPET_TOOLTIP = () => "Search code snippets"; - -export const ERROR_EMPTY_APPLICATION_NAME = () => - `Application name can't be empty`; - -export const ERROR_FILE_TOO_LARGE = (fileSize: string) => - `File size should be less than ${fileSize}!`; -export const REMOVE_FILE_TOOL_TIP = () => "Remove upload"; diff --git a/app/client/packages/dsl/src/migrate/migrations/047-SKIP.ts b/app/client/packages/dsl/src/migrate/migrations/047-SKIP.ts deleted file mode 100644 index 695c7acc8ad..00000000000 --- a/app/client/packages/dsl/src/migrate/migrations/047-SKIP.ts +++ /dev/null @@ -1,3 +0,0 @@ -// We're skipping this to fix a bad table migration. -// skipped migration is added as version 51 -export {}; diff --git a/app/client/packages/dsl/src/migrate/migrations/050-SKIP.ts b/app/client/packages/dsl/src/migrate/migrations/050-SKIP.ts deleted file mode 100644 index fb9b9bb0877..00000000000 --- a/app/client/packages/dsl/src/migrate/migrations/050-SKIP.ts +++ /dev/null @@ -1,5 +0,0 @@ -/* - * We're skipping this to fix a bad table migration - migrateTableWidgetNumericColumnName - * it overwrites the computedValue of the table columns - */ -export {}; diff --git a/app/client/packages/dsl/src/migrate/migrations/061-migrate-chart-widget-reskinning-data.ts b/app/client/packages/dsl/src/migrate/migrations/061-migrate-chart-widget-reskinning-data.ts deleted file mode 100644 index 5005036a28e..00000000000 --- a/app/client/packages/dsl/src/migrate/migrations/061-migrate-chart-widget-reskinning-data.ts +++ /dev/null @@ -1,3 +0,0 @@ -// this is a repeat of the migration 059-migrate-chart-widget-reskinning-data - -export {}; diff --git a/app/client/packages/dsl/src/migrate/tests/TableWidgetV2/DSLs/ParentRowSpaceUpdateDSLs.ts b/app/client/packages/dsl/src/migrate/tests/TableWidgetV2/DSLs/ParentRowSpaceUpdateDSLs.ts deleted file mode 100644 index 22d58afc8d7..00000000000 --- a/app/client/packages/dsl/src/migrate/tests/TableWidgetV2/DSLs/ParentRowSpaceUpdateDSLs.ts +++ /dev/null @@ -1,274 +0,0 @@ -import type { DSLWidget } from "../../../types"; - -export const inputDsl: DSLWidget = { - widgetName: "MainContainer", - backgroundColor: "none", - rightColumn: 1224, - snapColumns: 16, - detachFromLayout: true, - widgetId: "0", - topRow: 0, - bottomRow: 1840, - containerStyle: "none", - snapRows: 33, - parentRowSpace: 1, - type: "CANVAS_WIDGET", - canExtend: true, - version: 7, - minHeight: 1292, - parentColumnSpace: 1, - dynamicBindingPathList: [], - leftColumn: 0, - isLoading: false, - parentId: "", - renderMode: "CANVAS", - children: [ - { - isVisible: true, - label: "Data", - widgetName: "Table1", - searchKey: "", - tableData: - '[\n {\n "id": 2381224,\n "email": "michael.lawson@reqres.in",\n "userName": "Michael Lawson",\n "productName": "Chicken Sandwich",\n "orderAmount": 4.99\n },\n {\n "id": 2736212,\n "email": "lindsay.ferguson@reqres.in",\n "userName": "Lindsay Ferguson",\n "productName": "Tuna Salad",\n "orderAmount": 9.99\n },\n {\n "id": 6788734,\n "email": "tobias.funke@reqres.in",\n "userName": "Tobias Funke",\n "productName": "Beef steak",\n "orderAmount": 19.99\n }\n]', - type: "TABLE_WIDGET", - isLoading: false, - parentColumnSpace: 74, - parentRowSpace: 40, - leftColumn: 0, - rightColumn: 8, - topRow: 19, - bottomRow: 26, - parentId: "0", - widgetId: "fs785w9gcy", - dynamicBindingPathList: [], - primaryColumns: { - id: { - index: 0, - width: 150, - id: "id", - horizontalAlignment: "LEFT", - verticalAlignment: "CENTER", - columnType: "text", - textColor: "#231F20", - textSize: "PARAGRAPH", - fontStyle: "REGULAR", - enableFilter: true, - enableSort: true, - isVisible: true, - isDerived: false, - label: "id", - computedValue: "", - }, - email: { - index: 1, - width: 150, - id: "email", - horizontalAlignment: "LEFT", - verticalAlignment: "CENTER", - columnType: "text", - textColor: "#231F20", - textSize: "PARAGRAPH", - fontStyle: "REGULAR", - enableFilter: true, - enableSort: true, - isVisible: true, - isDerived: false, - label: "email", - computedValue: "", - }, - userName: { - index: 2, - width: 150, - id: "userName", - horizontalAlignment: "LEFT", - verticalAlignment: "CENTER", - columnType: "text", - textColor: "#231F20", - textSize: "PARAGRAPH", - fontStyle: "REGULAR", - enableFilter: true, - enableSort: true, - isVisible: true, - isDerived: false, - label: "userName", - computedValue: "", - }, - productName: { - index: 3, - width: 150, - id: "productName", - horizontalAlignment: "LEFT", - verticalAlignment: "CENTER", - columnType: "text", - textColor: "#231F20", - textSize: "PARAGRAPH", - fontStyle: "REGULAR", - enableFilter: true, - enableSort: true, - isVisible: true, - isDerived: false, - label: "productName", - computedValue: "", - }, - orderAmount: { - index: 4, - width: 150, - id: "orderAmount", - horizontalAlignment: "LEFT", - verticalAlignment: "CENTER", - columnType: "text", - textColor: "#231F20", - textSize: "PARAGRAPH", - fontStyle: "REGULAR", - enableFilter: true, - enableSort: true, - isVisible: true, - isDerived: false, - label: "orderAmount", - computedValue: "", - }, - }, - textSize: "PARAGRAPH", - horizontalAlignment: "LEFT", - verticalAlignment: "CENTER", - renderMode: "CANVAS", - version: 1, - }, - ], -}; -export const outputDsl: DSLWidget = { - widgetName: "MainContainer", - backgroundColor: "none", - rightColumn: 1224, - snapColumns: 16, - detachFromLayout: true, - widgetId: "0", - topRow: 0, - bottomRow: 1840, - containerStyle: "none", - snapRows: 33, - parentRowSpace: 1, - type: "CANVAS_WIDGET", - canExtend: true, - version: 7, - minHeight: 1292, - parentColumnSpace: 1, - dynamicBindingPathList: [], - leftColumn: 0, - isLoading: false, - parentId: "", - renderMode: "CANVAS", - children: [ - { - isVisible: true, - label: "Data", - widgetName: "Table1", - searchKey: "", - tableData: - '[\n {\n "id": 2381224,\n "email": "michael.lawson@reqres.in",\n "userName": "Michael Lawson",\n "productName": "Chicken Sandwich",\n "orderAmount": 4.99\n },\n {\n "id": 2736212,\n "email": "lindsay.ferguson@reqres.in",\n "userName": "Lindsay Ferguson",\n "productName": "Tuna Salad",\n "orderAmount": 9.99\n },\n {\n "id": 6788734,\n "email": "tobias.funke@reqres.in",\n "userName": "Tobias Funke",\n "productName": "Beef steak",\n "orderAmount": 19.99\n }\n]', - type: "TABLE_WIDGET", - isLoading: false, - parentColumnSpace: 74, - parentRowSpace: 10, - leftColumn: 0, - rightColumn: 8, - topRow: 19, - bottomRow: 26, - parentId: "0", - widgetId: "fs785w9gcy", - dynamicBindingPathList: [], - primaryColumns: { - id: { - index: 0, - width: 150, - id: "id", - horizontalAlignment: "LEFT", - verticalAlignment: "CENTER", - columnType: "text", - textColor: "#231F20", - textSize: "PARAGRAPH", - fontStyle: "REGULAR", - enableFilter: true, - enableSort: true, - isVisible: true, - isDerived: false, - label: "id", - computedValue: "", - }, - email: { - index: 1, - width: 150, - id: "email", - horizontalAlignment: "LEFT", - verticalAlignment: "CENTER", - columnType: "text", - textColor: "#231F20", - textSize: "PARAGRAPH", - fontStyle: "REGULAR", - enableFilter: true, - enableSort: true, - isVisible: true, - isDerived: false, - label: "email", - computedValue: "", - }, - userName: { - index: 2, - width: 150, - id: "userName", - horizontalAlignment: "LEFT", - verticalAlignment: "CENTER", - columnType: "text", - textColor: "#231F20", - textSize: "PARAGRAPH", - fontStyle: "REGULAR", - enableFilter: true, - enableSort: true, - isVisible: true, - isDerived: false, - label: "userName", - computedValue: "", - }, - productName: { - index: 3, - width: 150, - id: "productName", - horizontalAlignment: "LEFT", - verticalAlignment: "CENTER", - columnType: "text", - textColor: "#231F20", - textSize: "PARAGRAPH", - fontStyle: "REGULAR", - enableFilter: true, - enableSort: true, - isVisible: true, - isDerived: false, - label: "productName", - computedValue: "", - }, - orderAmount: { - index: 4, - width: 150, - id: "orderAmount", - horizontalAlignment: "LEFT", - verticalAlignment: "CENTER", - columnType: "text", - textColor: "#231F20", - textSize: "PARAGRAPH", - fontStyle: "REGULAR", - enableFilter: true, - enableSort: true, - isVisible: true, - isDerived: false, - label: "orderAmount", - computedValue: "", - }, - }, - textSize: "PARAGRAPH", - horizontalAlignment: "LEFT", - verticalAlignment: "CENTER", - renderMode: "CANVAS", - version: 1, - }, - ], -}; diff --git a/app/client/public/index.html b/app/client/public/index.html index 2009c6e672f..2618fe294e4 100755 --- a/app/client/public/index.html +++ b/app/client/public/index.html @@ -41,6 +41,7 @@ const CLOUD_HOSTING = parseConfig('{{env "APPSMITH_CLOUD_HOSTING"}}'); const ZIPY_KEY = parseConfig('{{env "APPSMITH_ZIPY_SDK_KEY"}}'); const AIRGAPPED = parseConfig('{{env "APPSMITH_AIRGAP_ENABLED"}}'); + const REO_CLIENT_ID = parseConfig('{{env "APPSMITH_REO_CLIENT_ID"}}'); + + + + diff --git a/app/client/src/PluginActionEditor/components/PluginActionForm/PluginActionForm.tsx b/app/client/src/PluginActionEditor/components/PluginActionForm/PluginActionForm.tsx index 17db33e698a..db91b29b3a2 100644 --- a/app/client/src/PluginActionEditor/components/PluginActionForm/PluginActionForm.tsx +++ b/app/client/src/PluginActionEditor/components/PluginActionForm/PluginActionForm.tsx @@ -1,7 +1,16 @@ import React from "react"; +import APIEditorForm from "./components/APIEditorForm"; +import { Flex } from "@appsmith/ads"; +import { useChangeActionCall } from "./hooks/useChangeActionCall"; const PluginActionForm = () => { - return
; + useChangeActionCall(); + + return ( + + + + ); }; export default PluginActionForm; diff --git a/app/client/src/PluginActionEditor/components/PluginActionForm/components/APIEditorForm.tsx b/app/client/src/PluginActionEditor/components/PluginActionForm/components/APIEditorForm.tsx new file mode 100644 index 00000000000..f3a8d8ffd62 --- /dev/null +++ b/app/client/src/PluginActionEditor/components/PluginActionForm/components/APIEditorForm.tsx @@ -0,0 +1,55 @@ +import React from "react"; +import CommonEditorForm from "./CommonEditorForm"; +import { usePluginActionContext } from "PluginActionEditor"; +import { EditorTheme } from "components/editorComponents/CodeEditor/EditorConfig"; +import { API_EDITOR_FORM_NAME } from "ee/constants/forms"; +import { HTTP_METHOD_OPTIONS } from "constants/ApiEditorConstants/CommonApiConstants"; +import PostBodyData from "pages/Editor/APIEditor/PostBodyData"; +import { useFeatureFlag } from "utils/hooks/useFeatureFlag"; +import { FEATURE_FLAG } from "ee/entities/FeatureFlag"; +import { getHasManageActionPermission } from "ee/utils/BusinessFeatures/permissionPageHelpers"; +import Pagination from "pages/Editor/APIEditor/Pagination"; +import { noop } from "lodash"; +import { reduxForm } from "redux-form"; + +const FORM_NAME = API_EDITOR_FORM_NAME; + +const APIEditorForm = () => { + const { action } = usePluginActionContext(); + const theme = EditorTheme.LIGHT; + + const isFeatureEnabled = useFeatureFlag(FEATURE_FLAG.license_gac_enabled); + const isChangePermitted = getHasManageActionPermission( + isFeatureEnabled, + action.userPermissions, + ); + + return ( + + } + formName={FORM_NAME} + headersCount={0} + httpMethodOptions={HTTP_METHOD_OPTIONS} + isChangePermitted={isChangePermitted} + paginationUiComponent={ + + } + paramsCount={0} + /> + ); +}; + +export default reduxForm({ form: FORM_NAME, enableReinitialize: true })( + APIEditorForm, +); diff --git a/app/client/src/PluginActionEditor/components/PluginActionForm/components/CommonEditorForm/CommonEditorForm.tsx b/app/client/src/PluginActionEditor/components/PluginActionForm/components/CommonEditorForm/CommonEditorForm.tsx new file mode 100644 index 00000000000..881fdc56147 --- /dev/null +++ b/app/client/src/PluginActionEditor/components/PluginActionForm/components/CommonEditorForm/CommonEditorForm.tsx @@ -0,0 +1,70 @@ +import React from "react"; +import { type Action } from "entities/Action"; +import { EditorTheme } from "components/editorComponents/CodeEditor/EditorConfig"; +import type { AutoGeneratedHeader } from "pages/Editor/APIEditor/helpers"; +import { InfoFields } from "./InfoFields"; +import { RequestTabs } from "./RequestTabs"; +import { HintMessages } from "./HintMessages"; +import { Flex } from "@appsmith/ads"; + +interface Props { + httpMethodOptions: { value: string }[]; + action: Action; + formName: string; + isChangePermitted: boolean; + bodyUIComponent: React.ReactNode; + paginationUiComponent: React.ReactNode; + headersCount: number; + paramsCount: number; + // TODO: Fix this the next time the file is edited + // eslint-disable-next-line @typescript-eslint/no-explicit-any + datasourceHeaders?: any; + // TODO: Fix this the next time the file is edited + // eslint-disable-next-line @typescript-eslint/no-explicit-any + datasourceParams?: any; + // TODO: Fix this the next time the file is edited + // eslint-disable-next-line @typescript-eslint/no-explicit-any + actionConfigurationHeaders?: any; + // TODO: Fix this the next time the file is edited + // eslint-disable-next-line @typescript-eslint/no-explicit-any + actionConfigurationParams?: any; + autoGeneratedActionConfigHeaders?: AutoGeneratedHeader[]; +} + +const CommonEditorForm = (props: Props) => { + const { action } = props; + const hintMessages = action.messages || []; + const theme = EditorTheme.LIGHT; + + return ( + + + + + + ); +}; + +export default CommonEditorForm; diff --git a/app/client/src/PluginActionEditor/components/PluginActionForm/components/CommonEditorForm/HintMessages.tsx b/app/client/src/PluginActionEditor/components/PluginActionForm/components/CommonEditorForm/HintMessages.tsx new file mode 100644 index 00000000000..3909ea66ff3 --- /dev/null +++ b/app/client/src/PluginActionEditor/components/PluginActionForm/components/CommonEditorForm/HintMessages.tsx @@ -0,0 +1,18 @@ +import React from "react"; +import { Callout } from "@appsmith/ads"; + +export function HintMessages(props: { hintMessages: string[] }) { + if (props.hintMessages.length === 0) { + return null; + } + + return ( + <> + {props.hintMessages.map((msg, i) => ( + + {msg} + + ))} + + ); +} diff --git a/app/client/src/PluginActionEditor/components/PluginActionForm/components/CommonEditorForm/InfoFields.tsx b/app/client/src/PluginActionEditor/components/PluginActionForm/components/CommonEditorForm/InfoFields.tsx new file mode 100644 index 00000000000..a2f1f7b7fc1 --- /dev/null +++ b/app/client/src/PluginActionEditor/components/PluginActionForm/components/CommonEditorForm/InfoFields.tsx @@ -0,0 +1,50 @@ +import React from "react"; +import type { EditorTheme } from "components/editorComponents/CodeEditor/EditorConfig"; +import RequestDropdownField from "components/editorComponents/form/fields/RequestDropdownField"; +import { replayHighlightClass } from "globalStyles/portals"; +import EmbeddedDatasourcePathField from "components/editorComponents/form/fields/EmbeddedDatasourcePathField"; +import styled from "styled-components"; +import { Flex } from "@appsmith/ads"; + +const DatasourceWrapper = styled.div` + margin-left: 8px; + width: 100%; +`; + +export function InfoFields(props: { + changePermitted: boolean; + options: { value: string }[]; + actionName: string; + pluginId: string; + formName: string; + theme: EditorTheme.LIGHT; +}) { + return ( + +
+ +
+ +
+ + + + + ); +} diff --git a/app/client/src/PluginActionEditor/components/PluginActionForm/components/CommonEditorForm/RequestTabs.tsx b/app/client/src/PluginActionEditor/components/PluginActionForm/components/CommonEditorForm/RequestTabs.tsx new file mode 100644 index 00000000000..3783ba5f919 --- /dev/null +++ b/app/client/src/PluginActionEditor/components/PluginActionForm/components/CommonEditorForm/RequestTabs.tsx @@ -0,0 +1,137 @@ +import styled from "styled-components"; +import { Tab, TabPanel, Tabs, TabsList } from "@appsmith/ads"; +import FormLabel from "components/editorComponents/FormLabel"; +import type { AutoGeneratedHeader } from "pages/Editor/APIEditor/helpers"; +import type { EditorTheme } from "components/editorComponents/CodeEditor/EditorConfig"; +import React from "react"; +import { API_EDITOR_TABS } from "constants/ApiEditorConstants/CommonApiConstants"; +import { DatasourceConfig } from "./components/DatasourceConfig"; +import KeyValueFieldArray from "components/editorComponents/form/fields/KeyValueFieldArray"; +import ApiAuthentication from "pages/Editor/APIEditor/ApiAuthentication"; +import ActionSettings from "pages/Editor/ActionSettings"; +import { API_EDITOR_TAB_TITLES, createMessage } from "ee/constants/messages"; +import { useSelectedFormTab } from "./hooks/useSelectedFormTab"; + +const SettingsWrapper = styled.div` + padding: var(--ads-v2-spaces-4) 0; + height: 100%; + + ${FormLabel} { + padding: 0; + } +`; +const TabsListWrapper = styled.div` + padding: 0 var(--ads-v2-spaces-7); +`; +const StyledTabPanel = styled(TabPanel)` + height: calc(100% - 50px); + overflow: auto; + padding: 0 var(--ads-v2-spaces-7); +`; + +export function RequestTabs(props: { + autogeneratedHeaders: AutoGeneratedHeader[] | undefined; + // TODO: Fix this the next time the file is edited + // eslint-disable-next-line @typescript-eslint/no-explicit-any + datasourceHeaders: any; + // TODO: Fix this the next time the file is edited + // eslint-disable-next-line @typescript-eslint/no-explicit-any + actionConfigurationHeaders: any; + headersCount: number; + actionName: string; + pushFields: boolean; + theme: EditorTheme.LIGHT; + // TODO: Fix this the next time the file is edited + // eslint-disable-next-line @typescript-eslint/no-explicit-any + datasourceParams: any; + // TODO: Fix this the next time the file is edited + // eslint-disable-next-line @typescript-eslint/no-explicit-any + actionConfigurationParams: any; + paramsCount: number; + bodyUIComponent: React.ReactNode; + paginationUiComponent: React.ReactNode; + formName: string; + showSettings: boolean; + // TODO: Fix this the next time the file is edited + // eslint-disable-next-line @typescript-eslint/no-explicit-any + actionSettingsConfig?: any; +}) { + const [value, onValueChange] = useSelectedFormTab(); + + return ( + + + + {Object.values(API_EDITOR_TABS).map((tab) => ( + + {createMessage(API_EDITOR_TAB_TITLES[tab])} + + ))} + + + + + + + + + + + + {props.bodyUIComponent} + + + {props.paginationUiComponent} + + + + + {props.showSettings ? ( + + + + + + ) : null} + + ); +} diff --git a/app/client/src/PluginActionEditor/components/PluginActionForm/components/CommonEditorForm/components/DatasourceConfig.tsx b/app/client/src/PluginActionEditor/components/PluginActionForm/components/CommonEditorForm/components/DatasourceConfig.tsx new file mode 100644 index 00000000000..a6b89e29191 --- /dev/null +++ b/app/client/src/PluginActionEditor/components/PluginActionForm/components/CommonEditorForm/components/DatasourceConfig.tsx @@ -0,0 +1,284 @@ +import styled from "styled-components"; +import FormRow from "../../../../../../components/editorComponents/FormRow"; +import FormLabel from "../../../../../../components/editorComponents/FormLabel"; +import { Button, Icon, Text, Tooltip } from "@appsmith/ads"; +import { + API_PANE_AUTO_GENERATED_HEADER, + API_PANE_DUPLICATE_HEADER, + createMessage, +} from "ee/constants/messages"; +import React, { useState } from "react"; +import { Classes } from "@appsmith/ads-old"; + +const Flex = styled.div<{ + size: number; + isInvalid?: boolean; +}>` + flex: ${(props) => props.size}; + width: 100%; + position: relative; + min-height: 36px; + height: auto; + border-color: var(--ads-v2-color-border); + border-bottom: 1px solid var(--ads-v2-color-border); + border-radius: var(--ads-v2-border-radius); + color: var(--ads-v2-color-fg); + display: flex; + align-items: center; + justify-content: space-between; + + &.possible-overflow-key, + &.possible-overflow { + overflow: hidden; + text-overflow: ellipsis; + width: fit-content; + max-width: 100%; + + div { + padding: 0 6px; + } + } + + &.possible-overflow { + width: 0; + max-height: 36px; + + & > span.cs-text { + width: 100%; + } + } + + & span { + ${(props) => + props?.isInvalid + ? "text-decoration: line-through;" + : "text-decoration: none;"} + } +`; +const FlexContainer = styled.div` + display: flex; + align-items: center; + width: calc(100% - 42px); + + .key-value { + .${Classes.TEXT} { + color: var(--ads-v2-color-fg); + padding: ${(props) => props.theme.spaces[2]}px 0px + ${(props) => props.theme.spaces[2]}px + ${(props) => props.theme.spaces[5]}px; + } + + border-bottom: 0px; + } + + .key-value-header { + color: var(--ads-v2-color-fg); + border-bottom: 0px; + + &:nth-child(2) { + margin-left: 5px; + } + } + + .key-value:nth-child(2) { + margin-left: 5px; + } + + .disabled { + background: var(--ads-v2-color-bg-subtle); + border: 1px solid var(--ads-v2-color-border-muted); + margin-bottom: ${(props) => props.theme.spaces[2] - 1}px; + } +`; +const KeyValueStackContainer = styled.div` + padding: 0; +`; +const KeyValueFlexContainer = styled.div` + padding: ${(props) => props.theme.spaces[4]}px + ${(props) => props.theme.spaces[14]}px 0 0; +`; +const FormRowWithLabel = styled(FormRow)` + flex-wrap: wrap; + + ${FormLabel} { + width: 100%; + } +`; +const CenteredIcon = styled(Icon)` + align-self: center; + margin-right: 5px; +`; + +function ImportedKeyValue(props: { + datas: { key: string; value: string; isInvalid?: boolean }[]; + keyValueName: string; +}) { + return ( + <> + {/* TODO: Fix this the next time the file is edited */} + {/* eslint-disable-next-line @typescript-eslint/no-explicit-any */} + {props.datas.map((data: any, index: number) => { + let tooltipContentValue = data?.value; + let tooltipContentKey = data?.key; + + if ("isInvalid" in data) { + if (data?.isInvalid) { + tooltipContentValue = createMessage( + API_PANE_DUPLICATE_HEADER, + data?.key, + ); + tooltipContentKey = createMessage( + API_PANE_DUPLICATE_HEADER, + data?.key, + ); + } else { + tooltipContentValue = ""; + tooltipContentKey = ""; + } + } + + return ( + + + + + +
{data.key}
+
+
+ {"isInvalid" in data && !data?.isInvalid && ( + + + + )} +
+ + + +
{data.value}
+
+
+
+
+
+ ); + })} + + ); +} + +function renderImportedDatasButton( + dataCount: number, + // TODO: Fix this the next time the file is edited + // eslint-disable-next-line @typescript-eslint/no-explicit-any + onClick: any, + showInheritedAttributes: boolean, + attributeName: string, +) { + return ( + // TODO: Maybe this should be a Toggle Button? ̦ + + ); +} + +export function DatasourceConfig(props: { + // TODO: Fix this the next time the file is edited + // eslint-disable-next-line @typescript-eslint/no-explicit-any + data: any; + // TODO: Fix this the next time the file is edited + // eslint-disable-next-line @typescript-eslint/no-explicit-any + autogeneratedHeaders?: any; + attributeName: string; +}) { + const [showDatas, toggleDatas] = useState(false); + + // commenting this out for whenever we decide to add a button to toggle auto-generated headers + // const [showAutoGeneratedHeader, toggleAutoGeneratedHeaders] = useState(true); + return ( + <> + + {props?.data && + props.data.length > 0 && + renderImportedDatasButton( + props.data.length, + toggleDatas, + showDatas, + `Inherited ${props.attributeName}${ + props.data.length > 1 ? "s" : "" + }`, + )} + + {/* commenting this out for whenever we decide to add a button to toggle auto-generated headers */} + {/* {props?.autogeneratedHeaders && + props?.autogeneratedHeaders?.length > 0 && + renderImportedDatasButton( + props?.autogeneratedHeaders?.length, + toggleAutoGeneratedHeaders, + showAutoGeneratedHeader, + `Auto Generated Header${ + props?.autogeneratedHeaders?.length > 1 ? "s" : "" + }`, + )} */} + + + + + + Key + + + Value + + + + {props?.data && props?.data?.length > 0 && showDatas && ( + + )} + {props?.autogeneratedHeaders && + props?.autogeneratedHeaders?.length > 0 && ( + + )} + + + ); +} diff --git a/app/client/src/PluginActionEditor/components/PluginActionForm/components/CommonEditorForm/hooks/useSelectedFormTab.ts b/app/client/src/PluginActionEditor/components/PluginActionForm/components/CommonEditorForm/hooks/useSelectedFormTab.ts new file mode 100644 index 00000000000..b7421a6dfc5 --- /dev/null +++ b/app/client/src/PluginActionEditor/components/PluginActionForm/components/CommonEditorForm/hooks/useSelectedFormTab.ts @@ -0,0 +1,25 @@ +import { useCallback } from "react"; +import { useDispatch, useSelector } from "react-redux"; +import { getApiPaneConfigSelectedTabIndex } from "selectors/apiPaneSelectors"; +import { API_EDITOR_TABS } from "constants/ApiEditorConstants/CommonApiConstants"; +import { setApiPaneConfigSelectedTabIndex } from "actions/apiPaneActions"; + +export function useSelectedFormTab(): [string, (id: string) => void] { + const dispatch = useDispatch(); + // the redux form has been configured with indexes, but the new ads components need strings to work. + // these functions convert them back and forth as needed. + const selectedIndex = useSelector(getApiPaneConfigSelectedTabIndex); + const selectedValue = Object.values(API_EDITOR_TABS)[selectedIndex]; + const setSelectedIndex = useCallback( + (value: string) => { + const index = Object.values(API_EDITOR_TABS).indexOf( + value as API_EDITOR_TABS, + ); + + dispatch(setApiPaneConfigSelectedTabIndex(index)); + }, + [dispatch], + ); + + return [selectedValue, setSelectedIndex]; +} diff --git a/app/client/src/PluginActionEditor/components/PluginActionForm/components/CommonEditorForm/index.ts b/app/client/src/PluginActionEditor/components/PluginActionForm/components/CommonEditorForm/index.ts new file mode 100644 index 00000000000..46cb3624cb0 --- /dev/null +++ b/app/client/src/PluginActionEditor/components/PluginActionForm/components/CommonEditorForm/index.ts @@ -0,0 +1,5 @@ +export { default } from "./CommonEditorForm"; + +export { HintMessages } from "./HintMessages"; +export { InfoFields } from "./InfoFields"; +export { RequestTabs } from "./RequestTabs"; diff --git a/app/client/src/PluginActionEditor/components/PluginActionForm/hooks/useChangeActionCall.test.tsx b/app/client/src/PluginActionEditor/components/PluginActionForm/hooks/useChangeActionCall.test.tsx new file mode 100644 index 00000000000..c7af1a52bbb --- /dev/null +++ b/app/client/src/PluginActionEditor/components/PluginActionForm/hooks/useChangeActionCall.test.tsx @@ -0,0 +1,108 @@ +import { renderHook } from "@testing-library/react-hooks/dom"; +import { useDispatch } from "react-redux"; +import { PluginType } from "entities/Action"; +import { usePluginActionContext } from "PluginActionEditor"; +import { changeApi } from "actions/apiPaneActions"; +import { changeQuery } from "actions/queryPaneActions"; +import { useChangeActionCall } from "./useChangeActionCall"; + +jest.mock("react-redux", () => ({ + useDispatch: jest.fn(), +})); + +jest.mock("actions/apiPaneActions", () => ({ + changeApi: jest.fn(), +})); + +jest.mock("actions/queryPaneActions", () => ({ + changeQuery: jest.fn(), +})); + +jest.mock("PluginActionEditor", () => ({ + usePluginActionContext: jest.fn(), +})); + +describe("useChangeActionCall hook", () => { + const dispatchMock = jest.fn(); + + beforeEach(() => { + (useDispatch as jest.Mock).mockReturnValue(dispatchMock); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it("should dispatch changeApi when plugin type is API", () => { + const actionMock = { id: "actionId" }; + const pluginMock = { id: "pluginId", type: PluginType.API }; + + // Mock the return values of usePluginActionContext + (usePluginActionContext as jest.Mock).mockReturnValue({ + action: actionMock, + plugin: pluginMock, + }); + + // Render the hook + renderHook(() => useChangeActionCall()); + + // Expect changeApi to be called with the correct parameters + expect(changeApi).toHaveBeenCalledWith(actionMock.id, false); + expect(dispatchMock).toHaveBeenCalledWith(changeApi(actionMock.id, false)); + }); + + it("should dispatch changeQuery when plugin type is not API", () => { + const actionMock = { + id: "actionId", + pageId: "pageId", + applicationId: "applicationId", + packageId: "packageId", + moduleId: "moduleId", + workflowId: "workflowId", + }; + const pluginMock = { id: "pluginId", type: "OTHER_PLUGIN_TYPE" }; + + // Mock the return values of usePluginActionContext + (usePluginActionContext as jest.Mock).mockReturnValue({ + action: actionMock, + plugin: pluginMock, + }); + + // Render the hook + renderHook(() => useChangeActionCall()); + + // Expect changeQuery to be called with the correct parameters + expect(changeQuery).toHaveBeenCalledWith({ + baseQueryId: actionMock.id, + basePageId: actionMock.pageId, + applicationId: actionMock.applicationId, + packageId: actionMock.packageId, + moduleId: actionMock.moduleId, + workflowId: actionMock.workflowId, + }); + expect(dispatchMock).toHaveBeenCalledWith( + changeQuery({ + baseQueryId: actionMock.id, + basePageId: actionMock.pageId, + applicationId: actionMock.applicationId, + packageId: actionMock.packageId, + moduleId: actionMock.moduleId, + workflowId: actionMock.workflowId, + }), + ); + }); + + it("should not dispatch any action if plugin id or action is not available", () => { + // Mock the return values of usePluginActionContext without plugin or action + (usePluginActionContext as jest.Mock).mockReturnValue({ + action: null, + plugin: { id: null, type: PluginType.API }, + }); + + // Render the hook + renderHook(() => useChangeActionCall()); + + // Expect no action to be dispatched + expect(dispatchMock).not.toHaveBeenCalled(); + }); +}); diff --git a/app/client/src/PluginActionEditor/components/PluginActionForm/hooks/useChangeActionCall.ts b/app/client/src/PluginActionEditor/components/PluginActionForm/hooks/useChangeActionCall.ts new file mode 100644 index 00000000000..562bbad8679 --- /dev/null +++ b/app/client/src/PluginActionEditor/components/PluginActionForm/hooks/useChangeActionCall.ts @@ -0,0 +1,33 @@ +import { useEffect } from "react"; +import { useDispatch } from "react-redux"; +import { changeApi } from "actions/apiPaneActions"; +import { changeQuery } from "actions/queryPaneActions"; +import { PluginType } from "entities/Action"; +import { usePluginActionContext } from "PluginActionEditor"; + +export const useChangeActionCall = () => { + const { action, plugin } = usePluginActionContext(); + const dispatch = useDispatch(); + + useEffect(() => { + if (!plugin?.id || !action) return; + + switch (plugin?.type) { + case PluginType.API: + dispatch(changeApi(action?.id, false)); + break; + default: + dispatch( + changeQuery({ + baseQueryId: action?.id, + basePageId: action.pageId, + applicationId: action.applicationId, + packageId: action.packageId, + moduleId: action.moduleId, + workflowId: action.workflowId, + }), + ); + break; + } + }, [action, plugin, dispatch]); +}; diff --git a/app/client/src/PluginActionEditor/components/PluginActionForm/utils/getDatasourceInfo.ts b/app/client/src/PluginActionEditor/components/PluginActionForm/utils/getDatasourceInfo.ts new file mode 100644 index 00000000000..a9ceb031848 --- /dev/null +++ b/app/client/src/PluginActionEditor/components/PluginActionForm/utils/getDatasourceInfo.ts @@ -0,0 +1,31 @@ +import get from "lodash/get"; +import type { Datasource } from "entities/Datasource"; + +export const getDatasourceInfo = (datasource: Datasource): string => { + const info = []; + const headers = get(datasource, "datasourceConfiguration.headers", []); + const queryParameters = get( + datasource, + "datasourceConfiguration.queryParameters", + [], + ); + const authType = get( + datasource, + "datasourceConfiguration.authentication.authenticationType", + "", + ).toUpperCase(); + + if (headers.length) + info.push(`${headers.length} Header${headers.length > 1 ? "s" : ""}`); + + if (queryParameters.length) + info.push( + `${queryParameters.length} query parameters${ + queryParameters.length > 1 ? "s" : "" + }`, + ); + + if (authType.length) info.push(authType); + + return info.join(" | "); +}; diff --git a/app/client/src/PluginActionEditor/components/PluginActionToolbar.tsx b/app/client/src/PluginActionEditor/components/PluginActionToolbar.tsx index 2192109be83..4a3563f9e4f 100644 --- a/app/client/src/PluginActionEditor/components/PluginActionToolbar.tsx +++ b/app/client/src/PluginActionEditor/components/PluginActionToolbar.tsx @@ -5,7 +5,7 @@ import { modText } from "utils/helpers"; import { usePluginActionContext } from "../PluginActionContext"; import { useDispatch } from "react-redux"; import AnalyticsUtil from "ee/utils/AnalyticsUtil"; -import { runAction } from "../../actions/pluginActionActions"; +import { runAction } from "actions/pluginActionActions"; interface PluginActionToolbarProps { runOptions?: React.ReactNode; diff --git a/app/client/src/actions/apiPaneActions.ts b/app/client/src/actions/apiPaneActions.ts index a17753391eb..30c2ee87751 100644 --- a/app/client/src/actions/apiPaneActions.ts +++ b/app/client/src/actions/apiPaneActions.ts @@ -59,13 +59,6 @@ export const setApiPaneConfigSelectedTabIndex: ( payload: { selectedTabIndex: payload }, }); -export const setApiRightPaneSelectedTab: ( - payload: string, -) => ReduxAction<{ selectedTab: string }> = (payload: string) => ({ - type: ReduxActionTypes.SET_API_RIGHT_PANE_SELECTED_TAB, - payload: { selectedTab: payload }, -}); - export const setApiPaneDebuggerState = ( payload: Partial, ) => ({ diff --git a/app/client/src/api/WidgetConfigsApi.tsx b/app/client/src/api/WidgetConfigsApi.tsx deleted file mode 100644 index 2006d130556..00000000000 --- a/app/client/src/api/WidgetConfigsApi.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import Api from "api/Api"; -import type { WidgetType } from "constants/WidgetConstants"; -import type { WidgetProps } from "widgets/BaseWidget"; -import type { AxiosPromise } from "axios"; -import type { WidgetConfigProps } from "WidgetProvider/constants"; - -export interface WidgetConfigsResponse { - config: Record & WidgetConfigProps>; -} - -class WidgetConfigsApi extends Api { - static url = "/widgetConfigs"; - static async fetchWidgetConfigs(): Promise< - AxiosPromise - > { - return Api.get(WidgetConfigsApi.url); - } -} - -export default WidgetConfigsApi; diff --git a/app/client/src/ce/constants/ReduxActionConstants.tsx b/app/client/src/ce/constants/ReduxActionConstants.tsx index 0fc6287c4c4..133cf9a420e 100644 --- a/app/client/src/ce/constants/ReduxActionConstants.tsx +++ b/app/client/src/ce/constants/ReduxActionConstants.tsx @@ -453,7 +453,6 @@ const IDEActionTypes = { SET_FOCUSABLE_PROPERTY_FIELD: "SET_FOCUSABLE_PROPERTY_FIELD", ROUTE_CHANGED: "ROUTE_CHANGED", SET_API_PANE_CONFIG_SELECTED_TAB: "SET_API_PANE_CONFIG_SELECTED_TAB", - SET_API_RIGHT_PANE_SELECTED_TAB: "SET_API_RIGHT_PANE_SELECTED_TAB", SET_EDITOR_FIELD_FOCUS: "SET_EDITOR_FIELD_FOCUS", SET_FOCUSABLE_INPUT_FIELD: "SET_FOCUSABLE_INPUT_FIELD", SET_CODE_EDITOR_CURSOR: "SET_CODE_EDITOR_CURSOR", diff --git a/app/client/src/ce/navigation/FocusElements/AppIDE.ts b/app/client/src/ce/navigation/FocusElements/AppIDE.ts index 9d75e82e912..d179e44d22c 100644 --- a/app/client/src/ce/navigation/FocusElements/AppIDE.ts +++ b/app/client/src/ce/navigation/FocusElements/AppIDE.ts @@ -1,7 +1,6 @@ import { setApiPaneConfigSelectedTabIndex, setApiPaneDebuggerState, - setApiRightPaneSelectedTab, } from "actions/apiPaneActions"; import { setAllEntityCollapsibleStates, @@ -15,7 +14,6 @@ import { import { getApiPaneConfigSelectedTabIndex, getApiPaneDebuggerState, - getApiRightPaneSelectedTab, } from "selectors/apiPaneSelectors"; import { getAllEntityCollapsibleStates, @@ -170,12 +168,6 @@ export const AppIDEFocusElements: FocusElementsConfigList = { selector: getFocusableInputField, setter: setFocusableInputField, }, - { - type: FocusElementConfigType.Redux, - name: FocusElement.ApiRightPaneTabs, - selector: getApiRightPaneSelectedTab, - setter: setApiRightPaneSelectedTab, - }, { type: FocusElementConfigType.Redux, name: FocusElement.QueryDebugger, diff --git a/app/client/src/ce/pages/AdminSettings/BreadcrumbCategories.tsx b/app/client/src/ce/pages/AdminSettings/BreadcrumbCategories.tsx deleted file mode 100644 index 054d0afed22..00000000000 --- a/app/client/src/ce/pages/AdminSettings/BreadcrumbCategories.tsx +++ /dev/null @@ -1,59 +0,0 @@ -import { APPLICATIONS_URL } from "constants/routes"; -import { SettingCategories } from "ee/pages/AdminSettings/config/types"; -import { adminSettingsCategoryUrl } from "ee/RouteBuilder"; - -export const BreadcrumbCategories = { - HOMEPAGE: { - href: APPLICATIONS_URL, - text: "Homepage", - }, - [SettingCategories.GENERAL]: { - href: adminSettingsCategoryUrl({ category: SettingCategories.GENERAL }), - text: "General", - }, - [SettingCategories.EMAIL]: { - href: adminSettingsCategoryUrl({ category: SettingCategories.EMAIL }), - text: "Email", - }, - [SettingCategories.DEVELOPER_SETTINGS]: { - href: adminSettingsCategoryUrl({ - category: SettingCategories.DEVELOPER_SETTINGS, - }), - text: "Developer settings", - }, - [SettingCategories.VERSION]: { - href: adminSettingsCategoryUrl({ category: SettingCategories.VERSION }), - text: "Version", - }, - [SettingCategories.ADVANCED]: { - href: adminSettingsCategoryUrl({ category: SettingCategories.ADVANCED }), - text: "Advanced", - }, - [SettingCategories.AUTHENTICATION]: { - href: adminSettingsCategoryUrl({ - category: SettingCategories.AUTHENTICATION, - }), - text: "Authentication", - }, - [SettingCategories.FORM_AUTH]: { - href: adminSettingsCategoryUrl({ - category: SettingCategories.AUTHENTICATION, - selected: SettingCategories.FORM_AUTH, - }), - text: "Form Login", - }, - [SettingCategories.GOOGLE_AUTH]: { - href: adminSettingsCategoryUrl({ - category: SettingCategories.AUTHENTICATION, - selected: SettingCategories.GOOGLE_AUTH, - }), - text: "Google Authentication", - }, - [SettingCategories.GITHUB_AUTH]: { - href: adminSettingsCategoryUrl({ - category: SettingCategories.AUTHENTICATION, - selected: SettingCategories.GITHUB_AUTH, - }), - text: "Github Authentication", - }, -}; diff --git a/app/client/src/ce/pages/Editor/routes.tsx b/app/client/src/ce/pages/Editor/routes.tsx deleted file mode 100644 index 4ad107d5a56..00000000000 --- a/app/client/src/ce/pages/Editor/routes.tsx +++ /dev/null @@ -1,79 +0,0 @@ -import React from "react"; -import { Route, Switch } from "react-router-dom"; -import { useRouteMatch } from "react-router"; -import ApiEditor from "pages/Editor/APIEditor"; -import QueryEditor from "pages/Editor/QueryEditor"; -import JSEditor from "pages/Editor/JSEditor"; -import GeneratePage from "pages/Editor/GeneratePage"; -import { - API_EDITOR_ID_PATH, - BUILDER_CHECKLIST_PATH, - GENERATE_TEMPLATE_FORM_PATH, - INTEGRATION_EDITOR_PATH, - JS_COLLECTION_ID_PATH, - QUERIES_EDITOR_ID_PATH, -} from "constants/routes"; -import * as Sentry from "@sentry/react"; -import { SaaSEditorRoutes } from "pages/Editor/SaaSEditor/routes"; -import OnboardingChecklist from "pages/Editor/FirstTimeUserOnboarding/Checklist"; -import { DatasourceEditorRoutes } from "pages/routes"; -import CreateNewDatasourceTab from "pages/Editor/IntegrationEditor/CreateNewDatasourceTab"; - -const SentryRoute = Sentry.withSentryRouting(Route); - -function EditorRoutes() { - const { path } = useRouteMatch(); - - return ( - - - - - - - {SaaSEditorRoutes.map(({ component, path: childPath }) => ( - - ))} - {DatasourceEditorRoutes.map(({ component, path: childPath }) => ( - - ))} - - - ); -} - -export default EditorRoutes; diff --git a/app/client/src/ce/pages/Upgrade/businessEdition/UpgradeToBEPage.tsx b/app/client/src/ce/pages/Upgrade/businessEdition/UpgradeToBEPage.tsx deleted file mode 100644 index c295878f13e..00000000000 --- a/app/client/src/ce/pages/Upgrade/businessEdition/UpgradeToBEPage.tsx +++ /dev/null @@ -1,114 +0,0 @@ -import React from "react"; -import styled from "styled-components"; -import { createMessage, MOVE_TO_BUSINESS_EDITION } from "ee/constants/messages"; -import { FooterComponent } from "../Footer"; -import useOnUpgrade from "utils/hooks/useOnUpgrade"; -import { Colors } from "constants/Colors"; -import { ASSETS_CDN_URL } from "constants/ThirdPartyConstants"; -import { getAssetUrl } from "ee/utils/airgapHelpers"; - -export const UpgradeToBEPageWrapper = styled.div` - width: 100%; - height: 100%; - background: - linear-gradient(90deg, #fff 20px, transparent 1%) center, - linear-gradient(#fff 20px, transparent 1%) center, - #d2ddec; - background-size: 22px 22px; - position: relative; - - .upgrade-page-footer-container { - height: 90px; - z-index: 2; - .left { - min-width: 100px; - } - } -`; - -export const ImageContainer = styled.div` - margin-right: 32px; - img { - height: calc(100vh - 400px); - object-fit: contain; - } -`; - -export const Overlay = styled.div` - width: 100%; - height: 100%; - background: linear-gradient( - 70deg, - ${Colors.APPSMITH_BEIGE} 40%, - transparent 60% - ); - z-index: 1; -`; - -export const FlexContainer = styled.div` - display: flex; - align-items: center; - width: 100%; - height: calc(100% - 96px); - justify-content: center; -`; - -export const LeftWrapper = styled.div` - margin-left: 32px; - img { - object-fit: contain; - height: calc(100vh - 200px); - } -`; - -export const ContentWrapper = styled.div` - display: flex; - height: 100%; - flex-direction: row; - align-items: center; - justify-content: center; - overflow: hidden; -`; - -const BUSINESS_FEATURES_IMAGE = getAssetUrl( - `${ASSETS_CDN_URL}/business-features.svg`, -); - -const UPGRADE_BOX_IMAGE = getAssetUrl(`${ASSETS_CDN_URL}/upgrade-box.svg`); - -export const UpgradeToBEPage = () => { - const { onUpgrade } = useOnUpgrade({ - logEventName: "BILLING_UPGRADE_ADMIN_SETTINGS", - logEventData: { source: "Upgrade" }, - }); - - return ( - - - - - - Upgrade to business plan - - - Upgrade to business plan - - - - - onUpgrade()} - showHeading={false} - /> - - ); -}; diff --git a/app/client/src/ce/reducers/uiReducers/apiPaneReducer.ts b/app/client/src/ce/reducers/uiReducers/apiPaneReducer.ts index 228d6f340ce..61bbf458ba1 100644 --- a/app/client/src/ce/reducers/uiReducers/apiPaneReducer.ts +++ b/app/client/src/ce/reducers/uiReducers/apiPaneReducer.ts @@ -38,7 +38,6 @@ export interface ApiPaneReduxState { // eslint-disable-next-line @typescript-eslint/no-explicit-any extraformData: Record; selectedConfigTabIndex: number; - selectedRightPaneTab?: string; debugger: ApiPaneDebuggerState; } @@ -210,7 +209,7 @@ export const handlers = { [ReduxActionTypes.SET_EXTRA_FORMDATA]: ( state: ApiPaneReduxState, action: ReduxAction<{ id: string; values: Record }>, - ) => { + ): ApiPaneReduxState => { const { id, values } = action.payload; return { @@ -232,17 +231,6 @@ export const handlers = { selectedConfigTabIndex: selectedTabIndex, }; }, - [ReduxActionTypes.SET_API_RIGHT_PANE_SELECTED_TAB]: ( - state: ApiPaneReduxState, - action: ReduxAction<{ selectedTab: number }>, - ) => { - const { selectedTab } = action.payload; - - return { - ...state, - selectedRightPaneTab: selectedTab, - }; - }, [ReduxActionTypes.SET_API_PANE_DEBUGGER_STATE]: ( state: ApiPaneReduxState, action: ReduxAction>, diff --git a/app/client/src/components/TabItemBackgroundFill.tsx b/app/client/src/components/TabItemBackgroundFill.tsx deleted file mode 100644 index 03d15bf8ba8..00000000000 --- a/app/client/src/components/TabItemBackgroundFill.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import React from "react"; -import styled from "styled-components"; -import { getTypographyByKey } from "@appsmith/ads-old"; -import type { Theme } from "constants/DefaultTheme"; - -interface WrapperProps { - selected: boolean; - vertical: boolean; - theme: Theme; -} - -const getFocusedStyles = (props: WrapperProps) => ` - background-color: ${props.theme.colors.tabItemBackgroundFill.highlightBackground}; - color: ${props.theme.colors.tabItemBackgroundFill.highlightTextColor}; - font-weight: 500; -`; - -const Wrapper = styled.div` - display: flex; - ${getTypographyByKey("p1")} - - ${(props) => - props.selected - ? getFocusedStyles(props) - : ` - color: ${props.theme.colors.tabItemBackgroundFill.textColor}; - `}; - - &:hover, - &:focus { - color: ${(props) => - props.theme.colors.tabItemBackgroundFill.highlightTextColor};} - } - - padding: ${(props) => - `${props.theme.spaces[5] - 1}px ${props.theme.spaces[11]}px`}; - - width: 100%; -`; - -export default function TabItemBackgroundFill(props: { - tab: { - title: string; - }; - selected: boolean; - vertical: boolean; -}) { - const { selected, tab, vertical } = props; - - return ( - - {tab.title} - - ); -} diff --git a/app/client/src/components/designSystems/appsmith/CloseButton.tsx b/app/client/src/components/designSystems/appsmith/CloseButton.tsx deleted file mode 100644 index e46fa635317..00000000000 --- a/app/client/src/components/designSystems/appsmith/CloseButton.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import React from "react"; -import styled from "styled-components"; -import type { Color } from "constants/Colors"; -import { Button } from "@blueprintjs/core"; - -interface CloseButtonProps { - color: Color; - size: number; - onClick: React.MouseEventHandler; - className?: string; -} - -const StyledButton = styled(Button)` - position: absolute; - top: 0; - right: 3px; - justify-content: center; - padding: 0; - color: ${(props) => props.color}; - - & svg { - width: ${(props) => props.size}; - height: ${(props) => props.size}; - - & path { - fill: ${(props) => props.color}; - } - } -`; - -export function CloseButton(props: CloseButtonProps) { - return ( - - ); -} diff --git a/app/client/src/components/designSystems/appsmith/CreatableDropdown.tsx b/app/client/src/components/designSystems/appsmith/CreatableDropdown.tsx deleted file mode 100644 index a1e53ab28db..00000000000 --- a/app/client/src/components/designSystems/appsmith/CreatableDropdown.tsx +++ /dev/null @@ -1,141 +0,0 @@ -import React from "react"; -import type { InputActionMeta } from "react-select"; -import Select from "react-select"; -import type { WrappedFieldInputProps, WrappedFieldMetaProps } from "redux-form"; - -import { theme } from "constants/DefaultTheme"; -import type { SelectComponents } from "react-select/src/components"; - -interface DropdownProps { - options: Array<{ - value: string; - label: string; - }>; - placeholder: string; - isLoading?: boolean; - input: WrappedFieldInputProps; - meta: WrappedFieldMetaProps; - // TODO: Fix this the next time the file is edited - // eslint-disable-next-line @typescript-eslint/no-explicit-any - components: SelectComponents; - onCreateOption: (inputValue: string) => void; - formatCreateLabel?: (value: string) => React.ReactNode; - noOptionsMessage?: (obj: { inputValue: string }) => string; - inputValue?: string; - onInputChange: (value: string, actionMeta: InputActionMeta) => void; -} - -const selectStyles = { - // TODO: Fix this the next time the file is edited - // eslint-disable-next-line @typescript-eslint/no-explicit-any - placeholder: (provided: any) => ({ - ...provided, - color: "#a3b3bf", - }), - // TODO: Fix this the next time the file is edited - // eslint-disable-next-line @typescript-eslint/no-explicit-any - multiValue: (provided: any) => ({ - ...provided, - backgroundColor: "rgba(104,113,239,0.1)", - border: "1px solid rgba(104, 113, 239, 0.5)", - borderRadius: `${theme.radii[1]}px`, - padding: "2px 5px", - fontSize: "14px", - maxWidth: "95%", - position: "relative", - display: "inline-block", - transform: "none", - }), - multiValueRemove: () => { - return { - display: "none", - }; - }, - // TODO: Fix this the next time the file is edited - // eslint-disable-next-line @typescript-eslint/no-explicit-any - container: (styles: any) => ({ - ...styles, - flex: 1, - zIndex: "5", - }), - // TODO: Fix this the next time the file is edited - // eslint-disable-next-line @typescript-eslint/no-explicit-any - control: (styles: any, state: any) => ({ - ...styles, - minHeight: "32px", - border: state.isFocused - ? `${theme.colors.secondary} solid 1px` - : `${theme.colors.inputInactiveBorders} solid 1px`, - boxShadow: state.isFocused ? "none" : "none", - "&:hover": { - border: `${theme.colors.secondary} solid 1px`, - }, - }), - // TODO: Fix this the next time the file is edited - // eslint-disable-next-line @typescript-eslint/no-explicit-any - indicatorsContainer: (provided: any) => ({ - ...provided, - height: "30px", - }), - // TODO: Fix this the next time the file is edited - // eslint-disable-next-line @typescript-eslint/no-explicit-any - clearIndicator: (provided: any) => ({ - ...provided, - padding: "5px", - }), - // TODO: Fix this the next time the file is edited - // eslint-disable-next-line @typescript-eslint/no-explicit-any - dropdownIndicator: (provided: any) => ({ - ...provided, - padding: "5px", - }), -}; - -class CreatableDropdown extends React.Component { - render() { - const { - components, - input, - inputValue, - isLoading, - noOptionsMessage, - onInputChange, - options, - placeholder, - } = this.props; - const optionalProps: Partial = {}; - - if (noOptionsMessage) optionalProps.noOptionsMessage = noOptionsMessage; - - if (components) optionalProps.components = components; - - if (inputValue) optionalProps.inputValue = inputValue; - - if (onInputChange) optionalProps.onInputChange = onInputChange; - - return ( - input.onChange(value)} - width={props.width} - {...props} - classNamePrefix="appsmith-select" - menuPlacement="auto" - placeholder={placeholder} - /> - ); -} - -function Dropdown(props: DropdownProps) { - return ; -} - -export default Dropdown; diff --git a/app/client/src/components/designSystems/appsmith/SignPostingBanner.tsx b/app/client/src/components/designSystems/appsmith/SignPostingBanner.tsx deleted file mode 100644 index d5f185e8507..00000000000 --- a/app/client/src/components/designSystems/appsmith/SignPostingBanner.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import React from "react"; -import type { ReactNode } from "react"; -import styled from "styled-components"; -import { Icon } from "@appsmith/ads"; - -export interface SignPostingBannerProps { - iconName: string; - content: ReactNode; -} - -export const Container = styled.div` - background-color: var(--ads-v2-color-blue-100); - width: 100%; - display: flex; -`; - -function SignPostingBanner(props: SignPostingBannerProps) { - return ( - -
- -
- {props.content} -
- ); -} - -export default SignPostingBanner; diff --git a/app/client/src/components/designSystems/appsmith/StepComponent.tsx b/app/client/src/components/designSystems/appsmith/StepComponent.tsx deleted file mode 100644 index c2df9a16328..00000000000 --- a/app/client/src/components/designSystems/appsmith/StepComponent.tsx +++ /dev/null @@ -1,90 +0,0 @@ -import { Icon } from "@appsmith/ads"; -import React from "react"; -import styled from "styled-components"; - -const StyledIncreaseIcon = styled(Icon)` - display: flex; - justify-content: center; - align-items: center; - position: relative; - cursor: pointer; -`; - -const StyledDecreaseIcon = styled(Icon)` - display: flex; - justify-content: center; - align-items: center; - position: relative; - cursor: pointer; -`; - -const StepWrapper = styled.div` - display: flex; - align-items: center; - justify-content: center; - width: 100%; - background: #121518; - border-radius: 4px; - height: 32px; - line-height: 32px; -`; - -const InputWrapper = styled.div` - width: calc(100% - 80px); - height: 32px; - line-height: 32px; - background: #23292e; - font-size: 14px; - color: ${(props) => props.theme.colors.textOnDarkBG}; - text-align: center; - letter-spacing: 1.44px; -`; - -interface StepComponentProps { - value: number; - min: number; - max: number; - steps: number; - displayFormat: (value: number) => string; - onChange: (value: number) => void; -} - -export function StepComponent(props: StepComponentProps) { - function decrease() { - if (props.value < props.min) { - return; - } - - const value = props.value - props.steps; - - props.onChange(value); - } - - function increase() { - if (props.value > props.max) { - return; - } - - const value = props.value + props.steps; - - props.onChange(value); - } - - return ( - - - {props.displayFormat(props.value)} - - - ); -} - -export default StepComponent; diff --git a/app/client/src/components/designSystems/appsmith/TabbedView.tsx b/app/client/src/components/designSystems/appsmith/TabbedView.tsx deleted file mode 100644 index 7e3ccf26c9f..00000000000 --- a/app/client/src/components/designSystems/appsmith/TabbedView.tsx +++ /dev/null @@ -1,72 +0,0 @@ -import React from "react"; -import { Tab, Tabs, TabList, TabPanel } from "react-tabs"; -import "react-tabs/style/react-tabs.css"; -import styled from "styled-components"; - -const TabsWrapper = styled.div<{ shouldOverflow?: boolean }>` - height: 100%; - .react-tabs { - height: 100%; - } - .react-tabs__tab-panel { - height: calc(100% - 46px); - scrollbar-width: none; - } - .react-tabs__tab-list { - border-bottom-color: #d0d7dd; - color: #a3b3bf; - ${(props) => - props.shouldOverflow && - ` - overflow-y: hidden; - overflow-x: auto; - white-space: nowrap; - `} - } - .react-tabs__tab { - padding: 6px 9px; - } - .react-tabs__tab:focus { - box-shadow: none; - border-color: ${(props) => props.theme.colors.primaryOld}; - } - .react-tabs__tab--selected { - color: ${(props) => props.theme.colors.primaryOld}; - border-color: #d0d7dd; - border-top: ${(props) => props.theme.colors.primaryOld} 5px solid; - border-radius: 0; - } -`; - -interface TabbedViewComponentType { - tabs: Array<{ - key: string; - title: string; - panelComponent: JSX.Element; - }>; - selectedIndex?: number; - setSelectedIndex?: (selectedIndex: number) => void; - overflow?: boolean; -} - -export function BaseTabbedView(props: TabbedViewComponentType) { - return ( - - { - props.setSelectedIndex && props.setSelectedIndex(index); - }} - selectedIndex={props.selectedIndex} - > - - {props.tabs.map((tab) => ( - {tab.title} - ))} - - {props.tabs.map((tab) => ( - {tab.panelComponent} - ))} - - - ); -} diff --git a/app/client/src/components/designSystems/appsmith/header/ThreeDotsLoading.tsx b/app/client/src/components/designSystems/appsmith/header/ThreeDotsLoading.tsx deleted file mode 100644 index dea0d2ab7c4..00000000000 --- a/app/client/src/components/designSystems/appsmith/header/ThreeDotsLoading.tsx +++ /dev/null @@ -1,69 +0,0 @@ -/*Huge thanks to @tobiasahlin at http://tobiasahlin.com/spinkit/ */ - -import React from "react"; -import styled from "styled-components"; - -const Spinner = styled.div` - width: 30px; - text-align: center; - && > div { - width: 4px; - height: 4px; - background-color: #4b4848; - - border-radius: 100%; - display: inline-block; - -webkit-animation: sk-bouncedelay 1.4s infinite ease-in-out both; - animation: sk-bouncedelay 1.4s infinite ease-in-out both; - } - - && .bounce1 { - -webkit-animation-delay: -0.32s; - animation-delay: -0.32s; - } - - && .bounce2 { - -webkit-animation-delay: -0.16s; - animation-delay: -0.16s; - } - - @-webkit-keyframes sk-bouncedelay { - 0%, - 80%, - 100% { - -webkit-transform: scale(0); - } - 40% { - -webkit-transform: scale(1); - } - } - - @keyframes sk-bouncedelay { - 0%, - 80%, - 100% { - -webkit-transform: scale(0); - transform: scale(0); - } - 40% { - -webkit-transform: scale(1); - transform: scale(1); - } - } -`; - -interface Props { - className?: string; -} - -function ThreeDotLoading(props: Props) { - return ( - -
-
-
- - ); -} - -export default ThreeDotLoading; diff --git a/app/client/src/components/editorComponents/ActionRightPane/Connections.tsx b/app/client/src/components/editorComponents/ActionRightPane/Connections.tsx deleted file mode 100644 index 713341cb107..00000000000 --- a/app/client/src/components/editorComponents/ActionRightPane/Connections.tsx +++ /dev/null @@ -1,132 +0,0 @@ -import React from "react"; -import { Text, TextType } from "@appsmith/ads-old"; -import styled from "styled-components"; -import LongArrowSVG from "assets/images/long-arrow-bottom.svg"; -import { useEntityLink } from "../Debugger/hooks/debuggerHooks"; -import AnalyticsUtil from "ee/utils/AnalyticsUtil"; -import { - createMessage, - INCOMING_ENTITIES, - NO_INCOMING_ENTITIES, - NO_OUTGOING_ENTITIES, - OUTGOING_ENTITIES, -} from "ee/constants/messages"; -import { Connection } from "../Debugger/EntityDependecies"; -import { Icon } from "@appsmith/ads"; -import Collapsible from "components/common/Collapsible"; - -const ConnectionType = styled.span` - span:nth-child(2) { - padding-left: ${(props) => props.theme.spaces[2] - 1}px; - } - padding-bottom: ${(props) => props.theme.spaces[2]}px; -`; - -const NoConnections = styled.div` - width: 100%; - padding: ${(props) => props.theme.spaces[4] + 1}px - ${(props) => props.theme.spaces[3]}px; - background-color: var(--ads-v2-color-bg); - border-radius: var(--ads-v2-border-radius); - border: 1px solid var(--ads-v2-color-border); - color: var(--ads-v2-color-fg); -`; - -const ConnectionFlow = styled.div` - display: flex; - align-items: center; - flex-direction: column; - - img { - padding-top: ${(props) => props.theme.spaces[1]}px; - padding-bottom: ${(props) => props.theme.spaces[2] + 1}px; - } -`; - -const ConnectionsContainer = styled.span` - width: 100%; - display: flex; - flex-wrap: wrap; - padding: ${(props) => props.theme.spaces[2] + 1}px; - - background-color: var(--ads-v2-color-bg); - border-radius: var(--ads-v2-border-radius); - border: 1px solid var(--ads-v2-color-border); - color: var(--ads-v2-color-fg); -`; - -// TODO: Fix this the next time the file is edited -// eslint-disable-next-line @typescript-eslint/no-explicit-any -function Dependencies(props: any) { - const { navigateToEntity } = useEntityLink(); - - const onClick = (entityName: string, entityType: string) => { - navigateToEntity(entityName); - AnalyticsUtil.logEvent("ASSOCIATED_ENTITY_CLICK", { - source: "INTEGRATION", - entityType: entityType, - }); - }; - - return props.dependencies.length ? ( - - {props.dependencies.map((entityName: string) => { - return ( - - ); - })} - - ) : ( - - {props.placeholder} - - ); -} - -interface ConnectionsProps { - actionName: string; - entityDependencies: { - inverseDependencies: string[]; - directDependencies: string[]; - } | null; -} - -function Connections(props: ConnectionsProps) { - return ( - - - - - {createMessage(INCOMING_ENTITIES)} - - - {/* Direct Dependencies */} - - - - {props.actionName} - - - - - {createMessage(OUTGOING_ENTITIES)} - - - - {/* Inverse dependencies */} - - - ); -} - -export default Connections; diff --git a/app/client/src/components/editorComponents/ActionRightPane/index.tsx b/app/client/src/components/editorComponents/ActionRightPane/index.tsx index bd8c6cfae7a..456484c3035 100644 --- a/app/client/src/components/editorComponents/ActionRightPane/index.tsx +++ b/app/client/src/components/editorComponents/ActionRightPane/index.tsx @@ -91,11 +91,9 @@ export function useEntityDependencies(actionName: string) { } function ActionSidebar({ - actionRightPaneBackLink, additionalSections, }: { additionalSections?: React.ReactNode; - actionRightPaneBackLink: React.ReactNode; }) { if (!additionalSections) { return null; @@ -104,7 +102,6 @@ function ActionSidebar({ return ( - {actionRightPaneBackLink} {additionalSections && ( diff --git a/app/client/src/components/editorComponents/Checkbox.tsx b/app/client/src/components/editorComponents/Checkbox.tsx deleted file mode 100644 index 21d6ba32256..00000000000 --- a/app/client/src/components/editorComponents/Checkbox.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import React from "react"; -import styled from "styled-components"; -import type { ICheckboxProps } from "@blueprintjs/core"; -import { Checkbox as BlueprintCheckbox } from "@blueprintjs/core"; -import type { Intent } from "constants/DefaultTheme"; -import { IntentColors, getBorderCSSShorthand } from "constants/DefaultTheme"; - -export type CheckboxProps = ICheckboxProps & { - intent: Intent; - align: "left" | "right"; - input?: { - onChange?: (value: boolean) => void; - value?: boolean; - checked?: boolean; - }; - label: string; -}; - -export const StyledCheckbox = styled(BlueprintCheckbox)` - &&&& { - span.bp3-control-indicator { - outline: none; - box-shadow: none; - border-radius: ${(props) => props.theme.radii[1]}px; - border: ${(props) => getBorderCSSShorthand(props.theme.borders[3])}; - height: ${(props) => props.theme.fontSizes[5]}px; - width: ${(props) => props.theme.fontSizes[5]}px; - } - input:checked ~ span.bp3-control-indicator { - background: ${(props) => IntentColors[props.intent]}; - box-shadow: none; - outline: none; - } - } -`; - -export function Checkbox(props: CheckboxProps) { - // TODO: Fix this the next time the file is edited - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const handleChange = (e: any) => { - props.input && - props.input.onChange && - props.input.onChange(e.target.checked); - }; - - return ( - - ); -} - -export default Checkbox; diff --git a/app/client/src/components/editorComponents/CloseEditor.tsx b/app/client/src/components/editorComponents/CloseEditor.tsx deleted file mode 100644 index c3d8881fb80..00000000000 --- a/app/client/src/components/editorComponents/CloseEditor.tsx +++ /dev/null @@ -1,78 +0,0 @@ -import React from "react"; -import { INTEGRATION_TABS } from "constants/routes"; -import { getQueryParams } from "utils/URLUtils"; -import { getIsGeneratePageInitiator } from "utils/GenerateCrudUtil"; -import { - generateTemplateFormURL, - integrationEditorURL, - widgetListURL, -} from "ee/RouteBuilder"; -import { useSelector } from "react-redux"; -import { getCurrentBasePageId } from "selectors/editorSelectors"; -import AnalyticsUtil from "ee/utils/AnalyticsUtil"; -import { Link } from "@appsmith/ads"; -import styled from "styled-components"; -import type { AppsmithLocationState } from "../../utils/history"; -import { NavigationMethod } from "../../utils/history"; -import { useHistory } from "react-router-dom"; - -const StyledLink = styled(Link)` - margin: var(--ads-v2-spaces-7) 0 0 var(--ads-v2-spaces-7); - width: fit-content; -`; - -function CloseEditor() { - const history = useHistory(); - const params: string = location.search; - const searchParamsInstance = new URLSearchParams(params); - const redirectTo = searchParamsInstance.get("from"); - const basePageId = useSelector(getCurrentBasePageId); - - const isGeneratePageInitiator = getIsGeneratePageInitiator(); - let integrationTab = INTEGRATION_TABS.ACTIVE; - - if (isGeneratePageInitiator) { - // When users routes to Integrations page via generate CRUD page form - // the INTEGRATION_TABS.ACTIVE is hidden and - // hence when routing back, user should go back to INTEGRATION_TABS.NEW tab. - integrationTab = INTEGRATION_TABS.NEW; - } - - const handleClose = () => { - // if it is a generate CRUD page flow from which user came here - // then route user back to `/generate-page/form` - // else go back to BUILDER_PAGE - const redirectURL = isGeneratePageInitiator - ? generateTemplateFormURL({ basePageId }) - : widgetListURL({ basePageId }); - - const URL = - redirectTo === "datasources" - ? integrationEditorURL({ - basePageId, - selectedTab: integrationTab, - params: getQueryParams(), - }) - : redirectURL; - - AnalyticsUtil.logEvent("BACK_BUTTON_CLICK", { - type: "BACK_BUTTON", - fromUrl: location.pathname, - toUrl: URL, - }); - history.push(URL, { invokedBy: NavigationMethod.ActionBackButton }); - }; - - return ( - - Back - - ); -} - -export default CloseEditor; diff --git a/app/client/src/components/editorComponents/ContextDropdown.tsx b/app/client/src/components/editorComponents/ContextDropdown.tsx deleted file mode 100644 index dc54ae78aad..00000000000 --- a/app/client/src/components/editorComponents/ContextDropdown.tsx +++ /dev/null @@ -1,105 +0,0 @@ -import type { ReactNode } from "react"; -import React from "react"; -import styled from "styled-components"; -import type { ItemRenderer } from "@blueprintjs/select"; -import { Select } from "@blueprintjs/select"; -import type { Intent as BlueprintIntent } from "@blueprintjs/core"; -import { - Button, - MenuItem, - PopoverPosition, - PopoverInteractionKind, -} from "@blueprintjs/core"; -import { noop } from "utils/AppsmithUtils"; -import type { Intent } from "constants/DefaultTheme"; -import type { DropdownOption } from "components/constants"; -import { Icon } from "@appsmith/ads"; - -export type ContextDropdownOption = DropdownOption & { - onSelect: (event: React.MouseEvent) => void; - intent?: Intent; - children?: ContextDropdownOption[]; -}; -const Dropdown = Select.ofType(); - -const StyledMenuItem = styled(MenuItem)` - &&&&.bp3-menu-item:hover { - background: ${(props) => props.theme.colors.primaryOld}; - color: ${(props) => props.theme.colors.textOnDarkBG}; - } - &&&.bp3-menu-item.bp3-intent-danger:hover { - background: ${(props) => props.theme.colors.error}; - } -`; - -interface ContextDropdownProps { - options: ContextDropdownOption[]; - className: string; - toggle: { - type: "icon" | "button"; - icon: string; - iconSize?: number; - text?: string; - placeholder?: string; - color?: string; - }; -} - -function DropdownItem(option: ContextDropdownOption) { - return ( - - {option.children && option.children.map(DropdownItem)} - - ); -} - -export function ContextDropdown(props: ContextDropdownProps) { - let trigger: ReactNode; - - if (props.toggle.type === "icon" && props.toggle.icon) { - trigger = ; - } - - if (props.toggle.type === "button" && props.toggle.text) - trigger =
- - ); -} - -export default HelperTooltip; diff --git a/app/client/src/components/editorComponents/form/FieldError.tsx b/app/client/src/components/editorComponents/form/FieldError.tsx deleted file mode 100644 index 4e617c3fb59..00000000000 --- a/app/client/src/components/editorComponents/form/FieldError.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import React from "react"; -import styled from "styled-components"; -import { IntentColors } from "constants/DefaultTheme"; -// Note: This component is only for the input fields which donot have the -// popover error tooltip. This is also only for Appsmith components -// Not to be used in widgets / canvas - -const StyledError = styled.span<{ show: boolean }>` - text-align: left; - color: ${IntentColors.danger}; - font-size: ${(props) => props.theme.fontSizes[3]}px; - opacity: ${(props) => (props.show ? 1 : 0)}; - display: block; - position: relative; - margin-top: ${(props) => props.theme.spaces[1]}px; -`; - -interface FormFieldErrorProps { - error?: string; - className?: string; -} - -export function FormFieldError(props: FormFieldErrorProps) { - return ( - - {props.error || " "} - - ); -} - -export default FormFieldError; diff --git a/app/client/src/components/editorComponents/form/FormActionButton.tsx b/app/client/src/components/editorComponents/form/FormActionButton.tsx deleted file mode 100644 index e76b36ac39e..00000000000 --- a/app/client/src/components/editorComponents/form/FormActionButton.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import styled from "styled-components"; -import { Button } from "@blueprintjs/core"; -import type { Intent } from "constants/DefaultTheme"; -import { BlueprintButtonIntentsCSS } from "constants/DefaultTheme"; - -interface FormActionButtonProps { - intent?: Intent; - large?: boolean; -} - -export default styled(Button)` - ${BlueprintButtonIntentsCSS} -`; diff --git a/app/client/src/components/editorComponents/form/FormFooter.tsx b/app/client/src/components/editorComponents/form/FormFooter.tsx deleted file mode 100644 index 062e120f8da..00000000000 --- a/app/client/src/components/editorComponents/form/FormFooter.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import React from "react"; -import styled from "styled-components"; -import Button from "components/editorComponents/Button"; -import Divider from "components/editorComponents/Divider"; - -interface FormFooterProps { - onCancel?: () => void; - onSubmit?: () => void; - divider?: boolean; - submitting: boolean; - submitText?: string; - cancelText?: string; - submitOnEnter?: boolean; - canSubmit?: boolean; - size?: "large" | "small"; -} - -const FooterActions = styled.div` - margin: 1em; - display: flex; - justify-content: flex-end; - align-items: center; - & > button { - margin-left: 1em; - } - &&&& > .bp3-button { - color: ${(props) => props.theme.colors.formFooter.cancelBtn}; - } -`; - -const FormFooterContainer = styled.div``; - -export function FormFooter(props: FormFooterProps) { - return ( - - {props.divider && } - - {props.onCancel && ( - - ); -} - -function ImportedDatas(props: { - // TODO: Fix this the next time the file is edited - // eslint-disable-next-line @typescript-eslint/no-explicit-any - data: any; - // TODO: Fix this the next time the file is edited - // eslint-disable-next-line @typescript-eslint/no-explicit-any - autogeneratedHeaders?: any; - attributeName: string; -}) { - const [showDatas, toggleDatas] = useState(false); - - // commenting this out for whenever we decide to add a button to toggle auto-generated headers - // const [showAutoGeneratedHeader, toggleAutoGeneratedHeaders] = useState(true); - return ( - <> - - {props?.data && - props.data.length > 0 && - renderImportedDatasButton( - props.data.length, - toggleDatas, - showDatas, - `Inherited ${props.attributeName}${ - props.data.length > 1 ? "s" : "" - }`, - )} - - {/* commenting this out for whenever we decide to add a button to toggle auto-generated headers */} - {/* {props?.autogeneratedHeaders && - props?.autogeneratedHeaders?.length > 0 && - renderImportedDatasButton( - props?.autogeneratedHeaders?.length, - toggleAutoGeneratedHeaders, - showAutoGeneratedHeader, - `Auto Generated Header${ - props?.autogeneratedHeaders?.length > 1 ? "s" : "" - }`, - )} */} - - - - - - Key - - - Value - - - - {props?.data && props?.data?.length > 0 && showDatas && ( - - )} - {props?.autogeneratedHeaders && - props?.autogeneratedHeaders?.length > 0 && ( - - )} - - - ); -} - /** * Commons editor form which is being used by API and GraphQL. Since most of the things were common to both so picking out the common part was a better option. For now Body and Pagination component are being passed on by the using component. * @param props type CommonFormPropsWithExtraParams * @returns Editor with respect to which type is using it */ function CommonEditorForm(props: CommonFormPropsWithExtraParams) { - // the redux form has been configured with indexes, but the new ads components need strings to work. - // these functions convert them back and forth as needed. - const selectedIndex = useSelector(getApiPaneConfigSelectedTabIndex); - const selectedValue = Object.values(API_EDITOR_TABS)[selectedIndex]; - const setSelectedIndex = (value: API_EDITOR_TABS) => { - const index = Object.values(API_EDITOR_TABS).indexOf(value); - - dispatch(setApiPaneConfigSelectedTabIndex(index)); - }; const { actionRightPaneAdditionSections, - actionRightPaneBackLink, moreActionsMenu, notification, saveActionName, @@ -557,7 +228,6 @@ function CommonEditorForm(props: CommonFormPropsWithExtraParams) { responseDisplayFormat, settingsConfig, } = props; - const dispatch = useDispatch(); const params = useParams<{ baseApiId?: string; baseQueryId?: string }>(); @@ -603,8 +273,6 @@ function CommonEditorForm(props: CommonFormPropsWithExtraParams) { actionDatasourceName === DEFAULT_DATASOURCE_NAME) || !isExecutePermitted; - const isGraphql = isGraphqlPlugin(plugin); - const theme = EditorTheme.LIGHT; return ( @@ -644,131 +312,42 @@ function CommonEditorForm(props: CommonFormPropsWithExtraParams) { )} -
- {/* eslint-disable-next-line */} - {/* @ts-ignore*/} - -
- - - +
{hintMessages && ( - {hintMessages.map((msg, i) => ( - - {msg} - - ))} + )}
- - - - {Object.values(API_EDITOR_TABS).map((tab) => ( - - {createMessage(API_EDITOR_TAB_TITLES[tab])} - - ))} - - - - - - - - - - - - {props.bodyUIComponent} - - - {props.paginationUIComponent} - - - - - - - - - - +
diff --git a/app/client/src/pages/Editor/APIEditor/GraphQL/GraphQLEditorForm.tsx b/app/client/src/pages/Editor/APIEditor/GraphQL/GraphQLEditorForm.tsx index 639ef20f6d4..91ee9aeb719 100644 --- a/app/client/src/pages/Editor/APIEditor/GraphQL/GraphQLEditorForm.tsx +++ b/app/client/src/pages/Editor/APIEditor/GraphQL/GraphQLEditorForm.tsx @@ -24,6 +24,7 @@ import VariableEditor from "./VariableEditor"; import Pagination from "./Pagination"; import { ApiEditorContext } from "../ApiEditorContext"; import { actionResponseDisplayDataFormats } from "pages/Editor/utils"; +import { GRAPHQL_HTTP_METHOD_OPTIONS } from "constants/ApiEditorConstants/GraphQLEditorConstants"; const ResizeableDiv = styled.div` display: flex; @@ -139,6 +140,7 @@ function GraphQLEditorForm(props: Props) { closeEditorLink={closeEditorLink} defaultTabSelected={2} formName={API_EDITOR_FORM_NAME} + httpsMethods={GRAPHQL_HTTP_METHOD_OPTIONS} paginationUIComponent={ props.theme.colors.apiPane.body.text}; - } -`; +import { HTTP_METHOD_OPTIONS } from "constants/ApiEditorConstants/CommonApiConstants"; type APIFormProps = { httpMethodFromForm: string; @@ -44,24 +32,18 @@ type Props = APIFormProps & InjectedFormProps; function ApiEditorForm(props: Props) { const { closeEditorLink } = useContext(ApiEditorContext); - const { actionName, httpMethodFromForm } = props; - const allowPostBody = httpMethodFromForm; + const { actionName } = props; const theme = EditorTheme.LIGHT; return ( - ) : ( - - {createMessage(API_PANE_NO_BODY)} - - ) + } closeEditorLink={closeEditorLink} formName={API_EDITOR_FORM_NAME} + httpsMethods={HTTP_METHOD_OPTIONS} paginationUIComponent={ - -

Providers

- - ); - } -} - -export default Search; diff --git a/app/client/src/pages/Editor/AppSettingsPane/AppSettings/PageSettings.tsx b/app/client/src/pages/Editor/AppSettingsPane/AppSettings/PageSettings.tsx index 5354d3d9fa8..0f55e54b684 100644 --- a/app/client/src/pages/Editor/AppSettingsPane/AppSettings/PageSettings.tsx +++ b/app/client/src/pages/Editor/AppSettingsPane/AppSettings/PageSettings.tsx @@ -71,9 +71,7 @@ function PageSettings(props: { page: Page }) { const [pageName, setPageName] = useState(page.pageName); const [isPageNameSaving, setIsPageNameSaving] = useState(false); - const [isPageNameValid, setIsPageNameValid] = useState( - undefined, - ); + const [pageNameError, setPageNameError] = useState(null); const [customSlug, setCustomSlug] = useState(page.customSlug); const [isCustomSlugSaving, setIsCustomSlugSaving] = useState(false); @@ -126,8 +124,12 @@ function PageSettings(props: { page: Page }) { } }, [isUpdatingEntity]); + useEffect(() => { + setPageNameError(null); + }, [page]); + const savePageName = useCallback(() => { - if (!canManagePages || !!isPageNameValid || page.pageName === pageName) + if (!canManagePages || pageNameError !== null || page.pageName === pageName) return; const payload: UpdatePageActionPayload = { @@ -137,7 +139,7 @@ function PageSettings(props: { page: Page }) { setIsPageNameSaving(true); dispatch(updatePageAction(payload)); - }, [page.pageId, page.pageName, pageName, isPageNameValid]); + }, [page.pageId, page.pageName, pageName, pageNameError]); const saveCustomSlug = useCallback(() => { if (!canManagePages || page.customSlug === customSlug) return; @@ -167,15 +169,15 @@ function PageSettings(props: { page: Page }) { ); const onPageNameChange = (value: string) => { - let isValid = undefined; + let errorMessage = null; if (!value || value.trim().length === 0) { - isValid = PAGE_SETTINGS_NAME_EMPTY_MESSAGE(); + errorMessage = PAGE_SETTINGS_NAME_EMPTY_MESSAGE(); } else if (value !== page.pageName && hasActionNameConflict(value)) { - isValid = PAGE_SETTINGS_ACTION_NAME_CONFLICT_ERROR(value); + errorMessage = PAGE_SETTINGS_ACTION_NAME_CONFLICT_ERROR(value); } - setIsPageNameValid(isValid); + setPageNameError(errorMessage); setPageName(toValidPageName(value)); }; @@ -190,13 +192,13 @@ function PageSettings(props: { page: Page }) {
{isPageNameSaving && } - {APP_SETTINGS_PANE_HEADER()} - - ); -} - -export default PaneHeader; diff --git a/app/client/src/pages/Editor/AppSettingsPane/index.tsx b/app/client/src/pages/Editor/AppSettingsPane/index.tsx deleted file mode 100644 index 2938c98a710..00000000000 --- a/app/client/src/pages/Editor/AppSettingsPane/index.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import React, { useRef } from "react"; -import AppSettings from "./AppSettings"; -import PaneHeader from "./PaneHeader"; - -function AppSettingsPane() { - const paneRef = useRef(null); - const portalRef = useRef(null); - - return ( -
-
- - -
- ); -} - -export default AppSettingsPane; diff --git a/app/client/src/pages/Editor/CommunityTemplates/Modals/PublishCommunityTemplate/components/TemplateCardPreview.tsx b/app/client/src/pages/Editor/CommunityTemplates/Modals/PublishCommunityTemplate/components/TemplateCardPreview.tsx deleted file mode 100644 index 6ec500a1f06..00000000000 --- a/app/client/src/pages/Editor/CommunityTemplates/Modals/PublishCommunityTemplate/components/TemplateCardPreview.tsx +++ /dev/null @@ -1,71 +0,0 @@ -import { COMMUNITY_TEMPLATES, createMessage } from "ee/constants/messages"; -import { Text } from "@appsmith/ads"; -import ProfileImage from "pages/common/ProfileImage"; -import React from "react"; -import { useSelector } from "react-redux"; -import { getCurrentUser } from "selectors/usersSelectors"; -import { - TemplatePreviewCardContainer, - TemplatePreviewImgPreviewContainer, - TemplatePreviewProfileContainer, -} from "../StyledComponents"; - -interface Props { - excerpt: string; - templateName: string; - useCases: string[]; -} - -const TemplateCardPreview = ({ excerpt, templateName, useCases }: Props) => { - return ( - - - - {createMessage(COMMUNITY_TEMPLATES.publishFormPage.preview.thumbnail)} - - - - {templateName} - - - {useCases.join(" • ")} - - - {excerpt} - - - - ); -}; - -export default TemplateCardPreview; - -const UserProfile = () => { - const currentUser = useSelector(getCurrentUser); - - return ( - - - - {currentUser?.name || currentUser?.email} - - - ); -}; diff --git a/app/client/src/pages/Editor/DataSourceEditor/BackButton.tsx b/app/client/src/pages/Editor/DataSourceEditor/BackButton.tsx deleted file mode 100644 index 37aa986b674..00000000000 --- a/app/client/src/pages/Editor/DataSourceEditor/BackButton.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import React from "react"; -import styled from "styled-components"; -import { getIsGeneratePageInitiator } from "utils/GenerateCrudUtil"; -import { builderURL, generateTemplateFormURL } from "ee/RouteBuilder"; -import AnalyticsUtil from "ee/utils/AnalyticsUtil"; -import { useSelector } from "react-redux"; -import { getCurrentBasePageId } from "selectors/editorSelectors"; -import { Link } from "@appsmith/ads"; -import type { AppsmithLocationState } from "utils/history"; -import { NavigationMethod } from "utils/history"; -import { useHistory } from "react-router-dom"; - -const Back = styled(Link)` - display: flex; - align-items: center; - margin: var(--ads-v2-spaces-7) 0 0 var(--ads-v2-spaces-7); -`; - -function BackButton() { - const history = useHistory(); - const basePageId = useSelector(getCurrentBasePageId); - const goBack = () => { - const isGeneratePageInitiator = getIsGeneratePageInitiator(); - const redirectURL = isGeneratePageInitiator - ? generateTemplateFormURL({ basePageId }) - : builderURL({ basePageId }); - - AnalyticsUtil.logEvent("BACK_BUTTON_CLICK", { - type: "BACK_BUTTON", - fromUrl: location.pathname, - toUrl: redirectURL, - }); - history.push(redirectURL, { invokedBy: NavigationMethod.ActionBackButton }); - }; - - return ( - - Back - - ); -} - -export default BackButton; diff --git a/app/client/src/pages/Editor/DatasourceInfo/DatasourceEntity.tsx b/app/client/src/pages/Editor/DatasourceInfo/DatasourceEntity.tsx deleted file mode 100644 index 6c1f344ccc3..00000000000 --- a/app/client/src/pages/Editor/DatasourceInfo/DatasourceEntity.tsx +++ /dev/null @@ -1,125 +0,0 @@ -import React, { useCallback } from "react"; -import type { Datasource } from "entities/Datasource"; -import type { Plugin } from "api/PluginApi"; -import DataSourceContextMenu from "../Explorer/Datasources/DataSourceContextMenu"; -import { getPluginIcon } from "../Explorer/ExplorerIcons"; -import { getQueryIdFromURL } from "ee/pages/Editor/Explorer/helpers"; -import Entity, { EntityClassNames } from "../Explorer/Entity"; -import history, { NavigationMethod } from "utils/history"; -import { updateDatasourceName } from "actions/datasourceActions"; -import { useSelector } from "react-redux"; -import type { AppState } from "ee/reducers"; -import { isStoredDatasource, PluginType } from "entities/Action"; -import { getAction } from "ee/selectors/entitiesSelector"; -import { - datasourcesEditorIdURL, - saasEditorDatasourceIdURL, -} from "ee/RouteBuilder"; -import AnalyticsUtil from "ee/utils/AnalyticsUtil"; -import { useLocation } from "react-router"; -import omit from "lodash/omit"; -import { getQueryParams } from "utils/URLUtils"; - -interface ExplorerDatasourceEntityProps { - plugin: Plugin; - datasource: Datasource; - step: number; - searchKeyword?: string; - entityId: string; - isActive: boolean; - canManageDatasource?: boolean; -} - -const ExplorerDatasourceEntity = React.memo( - (props: ExplorerDatasourceEntityProps) => { - const { entityId } = props; - const icon = getPluginIcon(props.plugin); - const location = useLocation(); - const switchDatasource = useCallback(() => { - let url; - - if (props.plugin && props.plugin.type === PluginType.SAAS) { - url = saasEditorDatasourceIdURL({ - basePageId: entityId, - pluginPackageName: props.plugin.packageName, - datasourceId: props.datasource.id, - params: { - viewMode: true, - }, - }); - } else { - url = datasourcesEditorIdURL({ - basePageId: entityId, - datasourceId: props.datasource.id, - params: omit(getQueryParams(), "viewMode"), - }); - } - - AnalyticsUtil.logEvent("ENTITY_EXPLORER_CLICK", { - type: "DATASOURCES", - fromUrl: location.pathname, - toUrl: url, - name: props.datasource.name, - }); - history.push(url, { invokedBy: NavigationMethod.EntityExplorer }); - }, [ - props.datasource.id, - props.datasource.name, - location.pathname, - entityId, - ]); - - const queryId = getQueryIdFromURL(); - const queryAction = useSelector((state: AppState) => - getAction(state, queryId || ""), - ); - - const updateDatasourceNameCall = (id: string, name: string) => - updateDatasourceName({ id: props.datasource.id, name }); - - const expandDatasourceId = useSelector((state: AppState) => { - return state.ui.datasourcePane.expandDatasourceId; - }); - - const nameTransformFn = useCallback( - (input: string) => input.slice(0, 30), - [], - ); - - let isDefaultExpanded = false; - - if (expandDatasourceId === props.datasource.id) { - isDefaultExpanded = true; - } else if (queryAction && isStoredDatasource(queryAction.datasource)) { - isDefaultExpanded = queryAction.datasource.id === props.datasource.id; - } - - return ( - - } - entityId={`${props.datasource.id}`} - icon={icon} - isDefaultExpanded={isDefaultExpanded} - key={props.datasource.id} - name={props.datasource.name} - onNameEdit={nameTransformFn} - searchKeyword={props.searchKeyword} - step={props.step} - updateEntityName={updateDatasourceNameCall} - /> - ); - }, -); - -ExplorerDatasourceEntity.displayName = "ExplorerDatasourceEntity"; -export default ExplorerDatasourceEntity; diff --git a/app/client/src/pages/Editor/EditorHeader.tsx b/app/client/src/pages/Editor/EditorHeader.tsx deleted file mode 100644 index e378d7e0e51..00000000000 --- a/app/client/src/pages/Editor/EditorHeader.tsx +++ /dev/null @@ -1,328 +0,0 @@ -import React, { useCallback, useEffect, useState } from "react"; -import { ThemeProvider } from "styled-components"; -import AppInviteUsersForm from "pages/workspace/AppInviteUsersForm"; -import AnalyticsUtil from "ee/utils/AnalyticsUtil"; -import { - getCurrentApplicationId, - getCurrentBasePageId, - getIsPageSaving, - getIsPublishingApplication, - getPageSavingError, -} from "selectors/editorSelectors"; -import { - getCurrentWorkspaceId, - getCurrentAppWorkspace, -} from "ee/selectors/selectedWorkspaceSelectors"; -import { useDispatch, useSelector } from "react-redux"; -import DeployLinkButtonDialog from "components/designSystems/appsmith/header/DeployLinkButton"; -import { - publishApplication, - updateApplication, -} from "ee/actions/applicationActions"; -import { - getApplicationList, - getIsSavingAppName, - getIsErroredSavingAppName, - getCurrentApplication, -} from "ee/selectors/applicationSelectors"; -import EditorName from "./EditorName"; -import { EditInteractionKind, SavingState } from "@appsmith/ads-old"; -import { - Button, - Tooltip, - Modal, - ModalHeader, - ModalContent, - ModalBody, - Tabs, - TabsList, - Tab, - TabPanel, -} from "@appsmith/ads"; -import { getTheme, ThemeMode } from "selectors/themeSelectors"; -import ToggleModeButton from "pages/Editor/ToggleModeButton"; -import { showConnectGitModal } from "actions/gitSyncActions"; -import RealtimeAppEditors from "./RealtimeAppEditors"; -import { EditorSaveIndicator } from "./EditorSaveIndicator"; -import { selectFeatureFlags } from "ee/selectors/featureFlagsSelectors"; -import { fetchUsersForWorkspace } from "ee/actions/workspaceActions"; -import { useNavigationMenuData } from "./EditorName/useNavigationMenuData"; - -import { - getIsGitConnected, - protectedModeSelector, -} from "selectors/gitSyncSelectors"; -import { - createMessage, - DEPLOY_BUTTON_TOOLTIP, - DEPLOY_MENU_OPTION, - INVITE_TAB, - IN_APP_EMBED_SETTING, - RENAME_APPLICATION_TOOLTIP, - COMMUNITY_TEMPLATES, - APPLICATION_INVITE, -} from "ee/constants/messages"; -import { viewerURL } from "ee/RouteBuilder"; -import { useHref } from "./utils"; -import { getAppsmithConfigs } from "ee/configs"; -import type { NavigationSetting } from "constants/AppConstants"; -import CommunityTemplatesPublishInfo from "./CommunityTemplates/Modals/CommunityTemplatesPublishInfo"; -import PublishCommunityTemplateModal from "./CommunityTemplates/Modals/PublishCommunityTemplate"; -import { useFeatureFlag } from "utils/hooks/useFeatureFlag"; -import { FEATURE_FLAG } from "ee/entities/FeatureFlag"; -import { getEmbedSnippetForm } from "ee/utils/BusinessFeatures/privateEmbedHelpers"; -import { HeaderSection, HeaderWrapper } from "./commons/EditorHeaderComponents"; -import { Omnibar } from "./commons/Omnibar"; -import { EditorShareButton } from "./EditorShareButton"; -import { HelperBarInHeader } from "./HelpBarInHeader"; -import { AppsmithLink } from "./AppsmithLink"; - -const { cloudHosting } = getAppsmithConfigs(); - -const theme = getTheme(ThemeMode.LIGHT); - -export function EditorHeader() { - const [activeTab, setActiveTab] = useState("invite"); - const dispatch = useDispatch(); - const isSavingName = useSelector(getIsSavingAppName); - const isGitConnected = useSelector(getIsGitConnected); - const isErroredSavingName = useSelector(getIsErroredSavingAppName); - const applicationList = useSelector(getApplicationList); - const workspaceId = useSelector(getCurrentWorkspaceId); - const currentWorkspace = useSelector(getCurrentAppWorkspace); - const applicationId = useSelector(getCurrentApplicationId); - const currentApplication = useSelector(getCurrentApplication); - const isPublishing = useSelector(getIsPublishingApplication); - const basePageId = useSelector(getCurrentBasePageId) as string; - const featureFlags = useSelector(selectFeatureFlags); - const isSaving = useSelector(getIsPageSaving); - const pageSaveError = useSelector(getPageSavingError); - const isProtectedMode = useSelector(protectedModeSelector); - - const deployLink = useHref(viewerURL, { basePageId }); - - const [isPopoverOpen, setIsPopoverOpen] = useState(false); - const [showModal, setShowModal] = useState(false); - const [ - showPublishCommunityTemplateModal, - setShowPublishCommunityTemplateModal, - ] = useState(false); - - const handlePublish = () => { - if (applicationId) { - dispatch(publishApplication(applicationId)); - - const appName = currentApplication ? currentApplication.name : ""; - const pageCount = currentApplication?.pages?.length; - const navigationSettingsWithPrefix: Record< - string, - NavigationSetting[keyof NavigationSetting] - > = {}; - - if (currentApplication?.applicationDetail?.navigationSetting) { - const settingKeys = Object.keys( - currentApplication.applicationDetail.navigationSetting, - ) as Array; - - settingKeys.map((key: keyof NavigationSetting) => { - if (currentApplication?.applicationDetail?.navigationSetting?.[key]) { - const value: NavigationSetting[keyof NavigationSetting] = - currentApplication.applicationDetail.navigationSetting[key]; - - navigationSettingsWithPrefix[`navigationSetting_${key}`] = value; - } - }); - } - - AnalyticsUtil.logEvent("PUBLISH_APP", { - appId: applicationId, - appName, - pageCount, - ...navigationSettingsWithPrefix, - isPublic: !!currentApplication?.isPublic, - templateTitle: currentApplication?.forkedFromTemplateTitle, - }); - } - }; - - const updateApplicationDispatch = ( - id: string, - data: { name: string; currentApp: boolean }, - ) => { - dispatch(updateApplication(id, data)); - }; - - const handleClickDeploy = useCallback( - (fromDeploy?: boolean) => { - if (isGitConnected) { - dispatch(showConnectGitModal()); - AnalyticsUtil.logEvent("GS_DEPLOY_GIT_CLICK", { - source: fromDeploy - ? "Deploy button" - : "Application name menu (top left)", - }); - } else { - handlePublish(); - } - }, - [dispatch, handlePublish], - ); - - //Fetch all users for the application to show the share button tooltip - useEffect(() => { - if (workspaceId) { - dispatch(fetchUsersForWorkspace(workspaceId)); - } - }, [workspaceId]); - - const isPrivateEmbedEnabled = useFeatureFlag( - FEATURE_FLAG.license_private_embeds_enabled, - ); - - const isGACEnabled = useFeatureFlag(FEATURE_FLAG.license_gac_enabled); - - return ( - - - -
- - - - -
- el.id === applicationId) - .length > 0 - } - isPopoverOpen={isPopoverOpen} - onBlur={(value: string) => - updateApplicationDispatch(applicationId || "", { - name: value, - currentApp: true, - }) - } - setIsPopoverOpen={setIsPopoverOpen} - /> -
-
- - - - - - - - - {applicationId && } - setShowModal(isOpen)} - open={showModal} - > - - - {createMessage( - APPLICATION_INVITE, - currentWorkspace.name, - !isGACEnabled, - )} - - - setActiveTab(value)} - value={activeTab} - > - - - {createMessage(INVITE_TAB)} - - - {createMessage(IN_APP_EMBED_SETTING.embed)} - - {featureFlags.release_show_publish_app_to_community_enabled && - cloudHosting && ( - - {createMessage(COMMUNITY_TEMPLATES.tabTitle)} - - )} - - - - - - {getEmbedSnippetForm(isPrivateEmbedEnabled, setActiveTab)} - - {cloudHosting && ( - - - setShowPublishCommunityTemplateModal(true) - } - setShowHostModal={setShowModal} - /> - - )} - - - - - { - setShowPublishCommunityTemplateModal(false); - setShowModal(true); - }} - setShowModal={setShowPublishCommunityTemplateModal} - showModal={showPublishCommunityTemplateModal} - /> -
- - - - - -
-
- - - - ); -} - -export default EditorHeader; diff --git a/app/client/src/pages/Editor/Explorer/Datasources.tsx b/app/client/src/pages/Editor/Explorer/Datasources.tsx deleted file mode 100644 index 1cbeb06416d..00000000000 --- a/app/client/src/pages/Editor/Explorer/Datasources.tsx +++ /dev/null @@ -1,159 +0,0 @@ -import React from "react"; -import { useSelector } from "react-redux"; -import Entity from "./Entity"; -import { - ADD_DATASOURCE_BUTTON, - createMessage, - CREATE_DATASOURCE_TOOLTIP, - EMPTY_DATASOURCE_BUTTON_TEXT, - EMPTY_DATASOURCE_MAIN_TEXT, -} from "ee/constants/messages"; -import styled from "styled-components"; -import { Icon, Button } from "@appsmith/ads"; -import { AddEntity, EmptyComponent } from "./common"; -import { getCurrentAppWorkspace } from "ee/selectors/selectedWorkspaceSelectors"; - -import type { AppState } from "ee/reducers"; -import { DatasourceCreateEntryPoints } from "constants/Datasource"; -import { FEATURE_FLAG } from "ee/entities/FeatureFlag"; -import { useFeatureFlag } from "utils/hooks/useFeatureFlag"; -import { - getHasCreateDatasourcePermission, - getHasManageDatasourcePermission, -} from "ee/utils/BusinessFeatures/permissionPageHelpers"; -import { - useAppWideAndOtherDatasource, - useDatasourceSuggestions, -} from "ee/pages/Editor/Explorer/hooks"; -import { getPlugins } from "ee/selectors/entitiesSelector"; -import { keyBy } from "lodash"; -import { useDatasourceIdFromURL } from "ee/pages/Editor/Explorer/helpers"; -import type { Datasource } from "entities/Datasource"; -import ExplorerDatasourceEntity from "../DatasourceInfo/DatasourceEntity"; - -interface DatasourcesProps { - isDatasourcesOpen: boolean | null; - addDatasource: (source: string) => void; - onDatasourcesToggle: (isOpen: boolean) => void; - listDatasource: () => void; - entityId: string; -} - -const ShowAllButton = styled(Button)` - margin: 0.25rem 1.5rem; -`; - -const Datasources = React.memo((props: DatasourcesProps) => { - const { appWideDS, otherDS } = useAppWideAndOtherDatasource(); - const { - addDatasource, - isDatasourcesOpen, - listDatasource, - onDatasourcesToggle, - } = props; - const userWorkspacePermissions = useSelector( - (state: AppState) => getCurrentAppWorkspace(state).userPermissions ?? [], - ); - const plugins = useSelector(getPlugins); - const pluginGroups = React.useMemo(() => keyBy(plugins, "id"), [plugins]); - const isFeatureEnabled = useFeatureFlag(FEATURE_FLAG.license_gac_enabled); - - const canCreateDatasource = getHasCreateDatasourcePermission( - isFeatureEnabled, - userWorkspacePermissions, - ); - - const activeDatasourceId = useDatasourceIdFromURL(); - const datasourceSuggestions = useDatasourceSuggestions(); - - const datasourceElements = React.useMemo( - () => - appWideDS.concat(datasourceSuggestions).map((datasource: Datasource) => { - const datasourcePermissions = datasource.userPermissions || []; - - const canManageDatasource = getHasManageDatasourcePermission( - isFeatureEnabled, - datasourcePermissions, - ); - - return ( - - ); - }), - [appWideDS, props.entityId, activeDatasourceId], - ); - - return ( - - addDatasource(DatasourceCreateEntryPoints.ENTITY_EXPLORER_ADD_DS) - } - onToggle={onDatasourcesToggle} - searchKeyword={""} - showAddButton={canCreateDatasource} - step={0} - > - {datasourceElements.length ? ( - datasourceElements - ) : ( - - addDatasource( - DatasourceCreateEntryPoints.ENTITY_EXPLORER_NEW_DATASOURCE, - ), - })} - /> - )} - {datasourceElements.length > 0 && canCreateDatasource && ( - - addDatasource( - DatasourceCreateEntryPoints.ENTITY_EXPLORER_ADD_DS_CTA, - ) - } - entityId="add_new_datasource" - icon={} - name={createMessage(ADD_DATASOURCE_BUTTON)} - step={1} - /> - )} - {otherDS.length ? ( - - Show all datasources - - ) : null} - - ); -}); - -Datasources.displayName = "Datasources"; - -export default Datasources; diff --git a/app/client/src/pages/Editor/Explorer/Datasources/DataSourceContextMenu.tsx b/app/client/src/pages/Editor/Explorer/Datasources/DataSourceContextMenu.tsx deleted file mode 100644 index 583a7dbb22f..00000000000 --- a/app/client/src/pages/Editor/Explorer/Datasources/DataSourceContextMenu.tsx +++ /dev/null @@ -1,88 +0,0 @@ -import React, { useCallback, useState } from "react"; -import { useDispatch, useSelector } from "react-redux"; -import { deleteDatasource } from "actions/datasourceActions"; -import { initExplorerEntityNameEdit } from "actions/explorerActions"; -import { - CONTEXT_RENAME, - CONTEXT_DELETE, - CONFIRM_CONTEXT_DELETE, - createMessage, -} from "ee/constants/messages"; -import type { AppState } from "ee/reducers"; - -import { getDatasource } from "ee/selectors/entitiesSelector"; -import type { TreeDropdownOption } from "pages/Editor/Explorer/ContextMenu"; -import ContextMenu from "pages/Editor/Explorer/ContextMenu"; -import { useFeatureFlag } from "utils/hooks/useFeatureFlag"; -import { FEATURE_FLAG } from "ee/entities/FeatureFlag"; -import { - getHasDeleteDatasourcePermission, - getHasManageDatasourcePermission, -} from "ee/utils/BusinessFeatures/permissionPageHelpers"; - -export function DataSourceContextMenu(props: { - datasourceId: string; - entityId: string; - className?: string; -}) { - const dispatch = useDispatch(); - const dispatchDelete = useCallback(() => { - dispatch(deleteDatasource({ id: props.datasourceId })); - }, [dispatch, props.datasourceId]); - const editDatasourceName = useCallback( - () => dispatch(initExplorerEntityNameEdit(props.entityId)), - [dispatch, props.entityId], - ); - - const [confirmDelete, setConfirmDelete] = useState(false); - - const datasource = useSelector((state: AppState) => - getDatasource(state, props.datasourceId), - ); - - const isFeatureEnabled = useFeatureFlag(FEATURE_FLAG.license_gac_enabled); - - const datasourcePermissions = datasource?.userPermissions || []; - - const canDeleteDatasource = getHasDeleteDatasourcePermission( - isFeatureEnabled, - datasourcePermissions, - ); - - const canManageDatasource = getHasManageDatasourcePermission( - isFeatureEnabled, - datasourcePermissions, - ); - - const treeOptions = [ - canManageDatasource && { - value: "rename", - className: "single-select t--datasource-rename", - onSelect: editDatasourceName, - label: createMessage(CONTEXT_RENAME), - }, - canDeleteDatasource && { - confirmDelete: confirmDelete, - className: "t--apiFormDeleteBtn single-select t--datasource-delete", - value: "delete", - onSelect: () => { - confirmDelete ? dispatchDelete() : setConfirmDelete(true); - }, - label: confirmDelete - ? createMessage(CONFIRM_CONTEXT_DELETE) - : createMessage(CONTEXT_DELETE), - intent: "danger", - }, - ].filter(Boolean); - - return treeOptions.length > 0 ? ( - - ) : null; -} - -export default DataSourceContextMenu; diff --git a/app/client/src/pages/Editor/Explorer/Entity/Placeholder.tsx b/app/client/src/pages/Editor/Explorer/Entity/Placeholder.tsx deleted file mode 100644 index aedf8e6412e..00000000000 --- a/app/client/src/pages/Editor/Explorer/Entity/Placeholder.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import type { ReactNode } from "react"; -import React from "react"; -import styled from "styled-components"; -const Wrapper = styled.div<{ step: number }>` - margin-left: ${(props) => props.step * props.theme.spaces[2]}px; - width: calc(100% - ${(props) => props.step * props.theme.spaces[2]}px); - font-size: ${(props) => props.theme.fontSizes[2]}px; - padding: 5px 20px; - text-align: left; - display: flex; - justify-content: flex-start; - align-items: center; - word-wrap: break-word; - width: 100%; -`; - -export function EntityPlaceholder(props: { - step: number; - children: ReactNode; -}) { - return ( - -

{props.children}

-
- ); -} - -export default EntityPlaceholder; diff --git a/app/client/src/pages/Editor/Explorer/ExplorerTitle.tsx b/app/client/src/pages/Editor/Explorer/ExplorerTitle.tsx deleted file mode 100644 index 21a0a7a0fe6..00000000000 --- a/app/client/src/pages/Editor/Explorer/ExplorerTitle.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import React from "react"; -import styled from "styled-components"; - -const Wrapper = styled.div` - display: flex; - align-items: center; - justify-content: space-between; - & h1 { - font-size: ${(props) => props.theme.fontSizes[3]}px; - letter-spacing: 3px; - font-weight: ${(props) => props.theme.fontWeights[2]}; - } -`; - -export function ExplorerTitle() { - return ( - -

EXPLORER

-
- ); -} - -export default ExplorerTitle; diff --git a/app/client/src/pages/Editor/Explorer/Files/SubmenuHotkeys.tsx b/app/client/src/pages/Editor/Explorer/Files/SubmenuHotkeys.tsx deleted file mode 100644 index 3d1f0751cd8..00000000000 --- a/app/client/src/pages/Editor/Explorer/Files/SubmenuHotkeys.tsx +++ /dev/null @@ -1,63 +0,0 @@ -import React from "react"; -import { Hotkey, Hotkeys, HotkeysTarget } from "@blueprintjs/core"; -import type { SelectEvent } from "components/editorComponents/GlobalSearch/utils"; - -interface Props { - handleUpKey: () => void; - handleDownKey: () => void; - handleSubmitKey: (e: SelectEvent) => void; - children: React.ReactNode; -} - -@HotkeysTarget -class SubmenuHotKeys extends React.Component { - get hotKeysConfig() { - return [ - { - combo: "up", - onKeyDown: () => { - this.props.handleUpKey(); - }, - allowInInput: true, - label: "Move up the list", - }, - { - combo: "down", - onKeyDown: this.props.handleDownKey, - allowInInput: true, - label: "Move down the list", - }, - { - combo: "return", - onKeyDown: this.props.handleSubmitKey, - allowInInput: true, - label: "Submit", - }, - ]; - } - - renderHotkeys() { - return ( - - {this.hotKeysConfig.map( - ({ allowInInput, combo, label, onKeyDown }, index) => ( - - ), - )} - - ); - } - - render() { - return
{this.props.children}
; - } -} - -export default SubmenuHotKeys; diff --git a/app/client/src/pages/Editor/Explorer/Pages/PageEntity.tsx b/app/client/src/pages/Editor/Explorer/Pages/PageEntity.tsx deleted file mode 100644 index 30278059b6f..00000000000 --- a/app/client/src/pages/Editor/Explorer/Pages/PageEntity.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import React from "react"; -import ExplorerWidgetGroup from "../Widgets/WidgetGroup"; -import Files from "../Files"; - -interface ExplorerPageEntityProps { - step: number; - searchKeyword?: string; - showWidgetsSidebar: () => void; -} - -export function ExplorerPageEntity(props: ExplorerPageEntityProps) { - return ( -
- - - -
- ); -} - -ExplorerPageEntity.displayName = "ExplorerPageEntity"; - -export default ExplorerPageEntity; diff --git a/app/client/src/pages/Editor/Explorer/TreeDropdown.tsx b/app/client/src/pages/Editor/Explorer/TreeDropdown.tsx deleted file mode 100644 index 6a4745da1ee..00000000000 --- a/app/client/src/pages/Editor/Explorer/TreeDropdown.tsx +++ /dev/null @@ -1,254 +0,0 @@ -import React, { useState } from "react"; -import styled from "styled-components"; -import { find, noop } from "lodash"; -import type { DropdownOption } from "components/constants"; -import { StyledMenu } from "@appsmith/ads-old"; -import type { IPopoverSharedProps, Position } from "@blueprintjs/core"; -import { - Button as BlueprintButton, - PopoverInteractionKind, - PopoverPosition, - Popover, - Classes, - MenuItem, -} from "@blueprintjs/core"; -import { IconNames } from "@blueprintjs/icons"; -import { Colors } from "constants/Colors"; -import { - EntityClassNames, - entityTooltipCSS, -} from "pages/Editor/Explorer/Entity"; -import { useCloseMenuOnScroll } from "ee/pages/Editor/Explorer/hooks"; -import { SIDEBAR_ID } from "constants/Explorer"; - -export type TreeDropdownOption = DropdownOption & { - onSelect?: (value: TreeDropdownOption, setter?: Setter) => void; - children?: TreeDropdownOption[]; - className?: string; - type?: string; - confirmDelete?: boolean; - disabled?: boolean; -}; - -type Setter = (value: TreeDropdownOption, defaultVal?: string) => void; - -interface TreeDropdownProps { - optionTree: TreeDropdownOption[]; - selectedValue: string; - // TODO: Fix this the next time the file is edited - // eslint-disable-next-line @typescript-eslint/no-explicit-any - getDefaults?: (value: any) => any; - defaultText: string; - onSelect: Setter; - selectedLabelModifier?: ( - option: TreeDropdownOption, - displayValue?: string, - ) => React.ReactNode; - displayValue?: string; - toggle?: React.ReactNode; - className?: string; - modifiers?: IPopoverSharedProps["modifiers"]; - setConfirmDelete?: (val: boolean) => void; - onMenuToggle?: (isOpen: boolean) => void; - position?: Position; - icon?: React.ReactNode; - editorPage?: boolean; - menuWidth?: number; -} - -export const StyledPopover = styled(Popover)<{ - children?: React.ReactNode; -}>` - .${Classes.POPOVER_TARGET} { - ${entityTooltipCSS} - } - div { - flex: 1 1 auto; - } - span { - width: 100%; - position: relative; - } - .${Classes.BUTTON} { - display: flex; - width: 100%; - align-items: center; - justify-content: space-between; - } - .${Classes.BUTTON_TEXT} { - text-overflow: ellipsis; - text-align: left; - overflow: hidden; - display: -webkit-box; - -webkit-line-clamp: 1; - -webkit-box-orient: vertical; - } - && { - .${Classes.ICON} { - width: fit-content; - color: ${Colors.SLATE_GRAY}; - } - } -`; - -function getSelectedOption( - selectedValue: string, - defaultText: string, - options: TreeDropdownOption[], -) { - let selectedOption: TreeDropdownOption = { - label: defaultText, - value: "", - }; - - options.length > 0 && - options.forEach((option) => { - // Find the selected option in the OptionsTree - if (option.value === selectedValue) { - selectedOption = option; - } else { - const childOption = find(option.children, { - value: selectedValue, - }); - - if (childOption) { - selectedOption = childOption; - } - } - }); - - return selectedOption; -} - -export default function TreeDropdown(props: TreeDropdownProps) { - const { - defaultText, - displayValue, - getDefaults, - menuWidth, - onSelect, - optionTree, - selectedLabelModifier, - selectedValue, - setConfirmDelete, - toggle, - } = props; - const selectedOption = getSelectedOption( - selectedValue, - defaultText, - optionTree, - ); - - const [isOpen, setIsOpen] = useState(false); - - useCloseMenuOnScroll(SIDEBAR_ID, isOpen, () => setIsOpen(false)); - - const handleSelect = (option: TreeDropdownOption) => { - if (option.onSelect) { - option.onSelect(option, props.onSelect); - - if (option.value === "delete" && !option.confirmDelete) { - setIsOpen(true); - } else { - setIsOpen(false); - } - } else { - const defaultVal = getDefaults ? getDefaults(option.value) : undefined; - - onSelect(option, defaultVal); - } - }; - - function renderTreeOption(option: TreeDropdownOption) { - const isSelected = - selectedOption.value === option.value || - selectedOption.type === option.value; - - return ( - { - handleSelect(option); - e.stopPropagation(); - } - } - popoverProps={{ - minimal: true, - interactionKind: PopoverInteractionKind.CLICK, - position: PopoverPosition.RIGHT, - // TODO: Fix this the next time the file is edited - // eslint-disable-next-line @typescript-eslint/no-explicit-any - targetProps: { onClick: (e: any) => e.stopPropagation() }, - }} - text={option.label} - > - {option.children && option.children.map(renderTreeOption)} - - ); - } - - const list = optionTree.map(renderTreeOption); - - const menuItems = ( - - {list} - - ); - - const defaultToggle = ( -
- -
- ); - - return ( - { - setIsOpen(false); - setConfirmDelete ? setConfirmDelete(false) : null; - }} - position={props.position || PopoverPosition.RIGHT_TOP} - targetProps={{ - // TODO: Fix this the next time the file is edited - // eslint-disable-next-line @typescript-eslint/no-explicit-any - onClick: (e: any) => { - setIsOpen(true); - e.stopPropagation(); - }, - }} - > - {toggle ? toggle : defaultToggle} - - ); -} diff --git a/app/client/src/pages/Editor/HelpBarInHeader.tsx b/app/client/src/pages/Editor/HelpBarInHeader.tsx deleted file mode 100644 index de0348dd8ad..00000000000 --- a/app/client/src/pages/Editor/HelpBarInHeader.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import React from "react"; -import classNames from "classnames"; -import HelpBar from "components/editorComponents/GlobalSearch/HelpBar"; -import { HeaderSection } from "./commons/EditorHeaderComponents"; - -export const HelperBarInHeader = ({ - isPreview = false, -}: { - isPreview?: boolean; -}) => { - return ( - - - - ); -}; diff --git a/app/client/src/pages/Editor/IDE/EditorPane/GlobalAdd.tsx b/app/client/src/pages/Editor/IDE/EditorPane/GlobalAdd.tsx deleted file mode 100644 index 2c5e93b09dd..00000000000 --- a/app/client/src/pages/Editor/IDE/EditorPane/GlobalAdd.tsx +++ /dev/null @@ -1,127 +0,0 @@ -import UIEntitySidebar from "pages/Editor/widgetSidebar/UIEntitySidebar"; -import React, { useCallback } from "react"; -import styled from "styled-components"; -import { Button, Flex, Icon, Text } from "@appsmith/ads"; -import { useDispatch, useSelector } from "react-redux"; -import { getCurrentBasePageId } from "selectors/editorSelectors"; -import history from "utils/history"; -import { queryAddURL } from "ee/RouteBuilder"; -import { createNewJSCollection } from "actions/jsPaneActions"; -import PaneHeader from "../LeftPane/PaneHeader"; - -const CTABox = styled.div` - height: 62px; - width: 100%; - padding: var(--ads-v2-spaces-3); - border-radius: 4px; - gap: var(--ads-v2-spaces-3); - border: 1px solid var(--ads-v2-color-border); - display: flex; - align-items: flex-start; - flex-direction: column; - cursor: pointer; - &:hover { - background-color: var(--ads-v2-color-bg-subtle); - } -`; - -const CTAIcon = styled.div<{ bgColor: string; color: string }>` - .ads-v2-icon { - padding: var(--ads-v2-spaces-2); - background-color: ${(props) => props.bgColor}; - border-radius: var(--ads-v2-spaces-1); - } - svg { - & path { - fill: ${(props) => props.color}; - } - } -`; - -const CreateCTA = (props: { - title: string; - icon: { - name: string; - bgColor: string; - color: string; - }; - onClick: () => void; -}) => { - return ( - - - - - {props.title} - - ); -}; - -const GlobalAdd = () => { - const basePageId = useSelector(getCurrentBasePageId); - const dispatch = useDispatch(); - const onCreateNewQuery = useCallback(() => { - history.push(queryAddURL({ basePageId })); - }, [basePageId]); - const onCreateJS = useCallback(() => { - dispatch(createNewJSCollection(basePageId, "ADD_PANE")); - }, [basePageId]); - - return ( - - history.goBack()} - size="sm" - startIcon={"close-line"} - /> - } - title="Add" - /> - - Create new.. - - - - - - - - Drag & drop widgets - - - - - ); -}; - -export default GlobalAdd; diff --git a/app/client/src/pages/Editor/IDE/EditorPane/components/MinimalTab.tsx b/app/client/src/pages/Editor/IDE/EditorPane/components/MinimalTab.tsx deleted file mode 100644 index 897508925f2..00000000000 --- a/app/client/src/pages/Editor/IDE/EditorPane/components/MinimalTab.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import React from "react"; -import type { FlexProps } from "@appsmith/ads"; -import { Flex } from "@appsmith/ads"; - -const MinimalTab = ({ children, ...rest }: FlexProps) => { - return ( - - {children} - - ); -}; - -export { MinimalTab }; diff --git a/app/client/src/pages/Editor/IDE/EditorTabs/ListButton.tsx b/app/client/src/pages/Editor/IDE/EditorTabs/ListButton.tsx deleted file mode 100644 index 06db8ea027d..00000000000 --- a/app/client/src/pages/Editor/IDE/EditorTabs/ListButton.tsx +++ /dev/null @@ -1,63 +0,0 @@ -import React, { useState } from "react"; -import type { EntityItem } from "ee/entities/IDE/constants"; -import { - Button, - Flex, - Menu, - MenuContent, - MenuItem, - MenuTrigger, - Text, -} from "@appsmith/ads"; -import { ListIconContainer, ListTitle } from "./StyledComponents"; - -interface Props { - items: EntityItem[]; - navigateToTab: (item: EntityItem) => void; -} - -const ListButton = (props: Props) => { - const { items, navigateToTab } = props; - const [isOpen, setOpen] = useState(false); - - if (items.length === 0) { - return null; - } - - return ( - - - - - - {items.map((item) => ( - navigateToTab(item)}> - - {item.icon} - {item.title} - - - ))} - - - ); -}; - -export default ListButton; diff --git a/app/client/src/pages/Editor/IDE/EditorTabs/StyledComponents.tsx b/app/client/src/pages/Editor/IDE/EditorTabs/StyledComponents.tsx deleted file mode 100644 index d396860bfde..00000000000 --- a/app/client/src/pages/Editor/IDE/EditorTabs/StyledComponents.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import styled from "styled-components"; - -export const ListIconContainer = styled.div` - height: 18px; - width: 18px; - display: flex; - align-items: center; - justify-content: center; - flex-shrink: 0; - img { - width: 18px; - } -`; - -export const ListTitle = styled.span` - width: 100%; - text-overflow: ellipsis; - white-space: nowrap; - overflow: hidden; -`; diff --git a/app/client/src/pages/Editor/IntegrationEditor/ActiveDataSources.tsx b/app/client/src/pages/Editor/IntegrationEditor/ActiveDataSources.tsx deleted file mode 100644 index 298161f7418..00000000000 --- a/app/client/src/pages/Editor/IntegrationEditor/ActiveDataSources.tsx +++ /dev/null @@ -1,106 +0,0 @@ -import React, { useMemo } from "react"; -import styled from "styled-components"; -import { useSelector } from "react-redux"; -import type { AppState } from "ee/reducers"; -import type { Datasource } from "entities/Datasource"; -import DatasourceCard from "./DatasourceCard"; -import { Text, TextType } from "@appsmith/ads-old"; -import { Button } from "@appsmith/ads"; -import { thinScrollbar } from "constants/DefaultTheme"; -import { keyBy } from "lodash"; -import { - createMessage, - EMPTY_ACTIVE_DATA_SOURCES, -} from "ee/constants/messages"; -import { getCurrentAppWorkspace } from "ee/selectors/selectedWorkspaceSelectors"; -import { useFeatureFlag } from "utils/hooks/useFeatureFlag"; -import { FEATURE_FLAG } from "ee/entities/FeatureFlag"; -import { getHasCreateDatasourcePermission } from "ee/utils/BusinessFeatures/permissionPageHelpers"; - -const QueryHomePage = styled.div` - ${thinScrollbar}; - overflow: auto; - display: flex; - flex-direction: column; - flex: 1; - - .sectionHeader { - font-weight: ${(props) => props.theme.fontWeights[2]}; - font-size: ${(props) => props.theme.fontSizes[4]}px; - margin-top: 10px; - } -`; - -const EmptyActiveDatasource = styled.div` - display: flex; - flex-direction: column; - flex: 1; - align-items: center; - justify-content: center; - gap: 1rem; -`; - -interface ActiveDataSourcesProps { - dataSources: Datasource[]; - basePageId: string; - location: { - search: string; - }; - history: { - replace: (data: string) => void; - push: (data: string) => void; - }; - onCreateNew: () => void; -} - -function ActiveDataSources(props: ActiveDataSourcesProps) { - const { dataSources } = props; - const plugins = useSelector((state: AppState) => { - return state.entities.plugins.list; - }); - const pluginGroups = useMemo(() => keyBy(plugins, "id"), [plugins]); - - const userWorkspacePermissions = useSelector( - (state: AppState) => getCurrentAppWorkspace(state).userPermissions ?? [], - ); - - const isFeatureEnabled = useFeatureFlag(FEATURE_FLAG.license_gac_enabled); - - const canCreateDatasource = getHasCreateDatasourcePermission( - isFeatureEnabled, - userWorkspacePermissions, - ); - - if (dataSources.length === 0) { - return ( - - - {createMessage(EMPTY_ACTIVE_DATA_SOURCES)} - - - - ); - } - - return ( - - {dataSources.map((datasource, idx) => { - return ( - - ); - })} - - ); -} - -export default ActiveDataSources; diff --git a/app/client/src/pages/Editor/IntegrationEditor/UnsupportedPluginDialog.tsx b/app/client/src/pages/Editor/IntegrationEditor/UnsupportedPluginDialog.tsx deleted file mode 100644 index ef7b267e229..00000000000 --- a/app/client/src/pages/Editor/IntegrationEditor/UnsupportedPluginDialog.tsx +++ /dev/null @@ -1,70 +0,0 @@ -import React from "react"; -import { Text, TextType } from "@appsmith/ads-old"; -import { - Button, - Modal, - ModalBody, - ModalContent, - ModalHeader, - ModalFooter, -} from "@appsmith/ads"; -import { UNSUPPORTED_PLUGIN_DIALOG_MAIN_HEADING } from "ee/constants/messages"; -import AnalyticsUtil from "ee/utils/AnalyticsUtil"; -import { - UNSUPPORTED_PLUGIN_DIALOG_TITLE, - UNSUPPORTED_PLUGIN_DIALOG_SUBTITLE, -} from "ee/constants/messages"; - -interface Props { - isModalOpen: boolean; - onClose: () => void; - onContinue: () => void; -} - -// Unsupported Plugin for gen CRUD page -function UnsupportedPluginDialog(props: Props) { - const { isModalOpen, onContinue } = props; - const handleClose = () => { - props.onClose(); - }; - - return ( - - - {UNSUPPORTED_PLUGIN_DIALOG_MAIN_HEADING()} - - {UNSUPPORTED_PLUGIN_DIALOG_TITLE()} -
- {UNSUPPORTED_PLUGIN_DIALOG_SUBTITLE()} -
- - - - -
-
- ); -} - -export default UnsupportedPluginDialog; diff --git a/app/client/src/pages/Editor/PropertyPaneHelpButton.tsx b/app/client/src/pages/Editor/PropertyPaneHelpButton.tsx deleted file mode 100644 index ded7f93f3e9..00000000000 --- a/app/client/src/pages/Editor/PropertyPaneHelpButton.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import React, { useCallback } from "react"; -import { useSelector, useDispatch } from "react-redux"; - -import { - setGlobalSearchQuery, - toggleShowGlobalSearchModal, -} from "actions/globalSearchActions"; -import AnalyticsUtil from "ee/utils/AnalyticsUtil"; -import WidgetFactory from "WidgetProvider/factory"; -import { getSelectedWidget } from "sagas/selectors"; -import { Icon } from "@appsmith/ads"; - -function PropertyPaneHelpButton() { - const selectedWidget = useSelector(getSelectedWidget); - const selectedWidgetType = selectedWidget?.type || ""; - const dispatch = useDispatch(); - const displayName = - WidgetFactory.widgetConfigMap.get(selectedWidgetType)?.displayName || ""; - - /** - * on click open the omnibar and toggle global search - */ - const onClick = useCallback(() => { - dispatch(setGlobalSearchQuery(displayName)); - dispatch(toggleShowGlobalSearchModal()); - AnalyticsUtil.logEvent("OPEN_OMNIBAR", { - source: "PROPERTY_PANE_HELP_BUTTON", - }); - }, [selectedWidgetType]); - - return ( - - ); -} - -export default PropertyPaneHelpButton; diff --git a/app/client/src/pages/Editor/QueryEditor/EditorJSONtoForm.tsx b/app/client/src/pages/Editor/QueryEditor/EditorJSONtoForm.tsx index 0721f3ae295..85b6d565118 100644 --- a/app/client/src/pages/Editor/QueryEditor/EditorJSONtoForm.tsx +++ b/app/client/src/pages/Editor/QueryEditor/EditorJSONtoForm.tsx @@ -197,12 +197,8 @@ export function EditorJSONtoForm(props: Props) { uiComponent, } = props; - const { - actionRightPaneAdditionSections, - actionRightPaneBackLink, - closeEditorLink, - notification, - } = useContext(QueryEditorContext); + const { actionRightPaneAdditionSections, closeEditorLink, notification } = + useContext(QueryEditorContext); const params = useParams<{ baseApiId?: string; baseQueryId?: string }>(); // fetch the error count from the store. @@ -344,7 +340,6 @@ export function EditorJSONtoForm(props: Props) {
diff --git a/app/client/src/pages/Editor/QueryEditor/JSONViewer.tsx b/app/client/src/pages/Editor/QueryEditor/JSONViewer.tsx deleted file mode 100644 index 91a5287869c..00000000000 --- a/app/client/src/pages/Editor/QueryEditor/JSONViewer.tsx +++ /dev/null @@ -1,87 +0,0 @@ -import React from "react"; -import ReactJson from "react-json-view"; -import styled from "styled-components"; -import { Card } from "@blueprintjs/core"; - -const OutputContainer = styled.div` - background: #f5f6f7; - border: 1px solid #d0d7dd; - box-sizing: border-box; - padding: 6px; -`; - -const ResponseContent = styled.div` - overflow: auto; -`; - -const Record = styled(Card)` - margin: 5px; - border-radius: 0; - span.string-value { - overflow-wrap: anywhere; - } -`; - -interface JSONOutputProps { - // TODO: Fix this the next time the file is edited - // eslint-disable-next-line @typescript-eslint/no-explicit-any - src: Record[]; -} - -type Props = JSONOutputProps; - -class JSONOutput extends React.Component { - render() { - const { src } = this.props; - const reactJsonProps = { - name: null, - enableClipboard: false, - displayObjectSize: false, - displayDataTypes: false, - style: { - fontSize: "14px", - }, - collapsed: 2, - collapseStringsAfterLength: 20, - // TODO: Fix this the next time the file is edited - // eslint-disable-next-line @typescript-eslint/no-explicit-any - shouldCollapse: (field: any) => { - const index = field.name * 1; - - return index >= 2; - }, - }; - - if (typeof src !== "object") { - return {src}; - } - - if (!src.length) { - return ( - - - - - - - - ); - } - - return ( - - - {src.map((record, index) => { - return ( - - - - ); - })} - - - ); - } -} - -export default JSONOutput; diff --git a/app/client/src/pages/Editor/RealtimeAppEditors.tsx b/app/client/src/pages/Editor/RealtimeAppEditors.tsx deleted file mode 100644 index 6e4866f8250..00000000000 --- a/app/client/src/pages/Editor/RealtimeAppEditors.tsx +++ /dev/null @@ -1,107 +0,0 @@ -import React, { useEffect } from "react"; -import { useDispatch, useSelector } from "react-redux"; -import { getRealtimeAppEditors } from "selectors/appCollabSelectors"; -import { getTypographyByKey } from "@appsmith/ads-old"; -import ProfileImage from "pages/common/ProfileImage"; -import UserApi from "ee/api/UserApi"; -import styled from "styled-components"; -import { - collabStartEditingAppEvent, - collabStopEditingAppEvent, - collabResetAppEditors, -} from "actions/appCollabActions"; -import { getCurrentPageId } from "selectors/editorSelectors"; -import { getIsAppLevelSocketConnected } from "selectors/websocketSelectors"; -import { Tooltip } from "@appsmith/ads"; - -const UserImageContainer = styled.div` - display: flex; - margin-right: ${(props) => props.theme.spaces[3]}px; - - div { - cursor: default; - margin-left: ${(props) => props.theme.spaces[1]}px; - width: 24px; - height: 24px; - margin-left: 0px; - } - - .profile-image { - margin-right: -6px; - border: 1px solid var(--ads-v2-color-white); - span { - color: var(--ads-v2-color-fg); - font-weight: normal; - ${getTypographyByKey("btnSmall")}; - } - } - - .more { - z-index: 1; - } -`; - -interface RealtimeAppEditorsProps { - applicationId?: string; -} - -export function useEditAppCollabEvents(applicationId?: string) { - const dispatch = useDispatch(); - - const isWebsocketConnected = useSelector(getIsAppLevelSocketConnected); - - const currentPageId = useSelector(getCurrentPageId); - - useEffect(() => { - // websocket has to be connected as we only fire this event once. - isWebsocketConnected && - applicationId && - dispatch(collabStartEditingAppEvent(applicationId)); - - return () => { - dispatch(collabResetAppEditors()); - isWebsocketConnected && - applicationId && - dispatch(collabStopEditingAppEvent(applicationId)); - }; - }, [applicationId, currentPageId, isWebsocketConnected]); -} - -function RealtimeAppEditors(props: RealtimeAppEditorsProps) { - const { applicationId } = props; - const realtimeAppEditors = useSelector(getRealtimeAppEditors); - - useEditAppCollabEvents(applicationId); - - return realtimeAppEditors.length > 0 ? ( - - {realtimeAppEditors.slice(0, 3).map((el) => ( - - - {el.name || el.email} - - Editing - - } - key={el.email} - > - - - ))} - {realtimeAppEditors.length > 3 ? ( - - ) : null} - - ) : null; -} - -export default RealtimeAppEditors; diff --git a/app/client/src/pages/Editor/SaaSEditor/DatasourceCard.tsx b/app/client/src/pages/Editor/SaaSEditor/DatasourceCard.tsx deleted file mode 100644 index d309a9f135d..00000000000 --- a/app/client/src/pages/Editor/SaaSEditor/DatasourceCard.tsx +++ /dev/null @@ -1,169 +0,0 @@ -import type { Datasource } from "entities/Datasource"; -import { isStoredDatasource } from "entities/Action"; -import React from "react"; -import { isEmpty } from "lodash"; -import { useSelector } from "react-redux"; -import { Colors } from "constants/Colors"; -import { useParams } from "react-router"; - -import { - getCurrentActions, - getPluginImages, -} from "ee/selectors/entitiesSelector"; -import styled from "styled-components"; -import type { AppState } from "ee/reducers"; -import history from "utils/history"; - -import RenderDatasourceInformation from "pages/Editor/DataSourceEditor/DatasourceSection"; -import { BaseButton } from "components/designSystems/appsmith/BaseButton"; -import { saasEditorDatasourceIdURL } from "ee/RouteBuilder"; -import { getAssetUrl } from "ee/utils/airgapHelpers"; -import { Button } from "@appsmith/ads"; - -const Wrapper = styled.div` - border: 2px solid #d6d6d6; - padding: 18px; - margin-top: 18px; -`; - -const ActionButton = styled(BaseButton)` - &&&& { - height: 36px; - max-width: 120px; - width: auto; - } - - span > svg > path { - stroke: white; - } -`; - -const DatasourceImage = styled.img` - height: 24px; - width: auto; -`; - -const EditDatasourceButton = styled(Button)` - &&&& { - height: 36px; - max-width: 160px; - border: 1px solid var(--ads-v2-color-border); - width: auto; - } -`; - -const DatasourceName = styled.span` - margin-left: 10px; - font-size: 16px; - font-weight: 500; -`; - -const DatasourceCardHeader = styled.div` - justify-content: space-between; - display: flex; -`; - -const DatasourceNameWrapper = styled.div` - flex-direction: row; - align-items: center; - display: flex; -`; - -const Queries = styled.div` - color: ${Colors.DOVE_GRAY}; - font-size: 14px; - display: inline-block; - margin-top: 11px; -`; - -const ButtonsWrapper = styled.div` - display: flex; - gap: 10px; -`; - -interface DatasourceCardProps { - datasource: Datasource; - onCreate: (datasource: Datasource) => void; -} - -// TODO: This is largely a quick copy pasta and edit of QueryEditor/DatasourceCard.tsx -// When we move Google Sheets over to regular oauth2 integrations, we will need to refactor this. -function DatasourceCard(props: DatasourceCardProps) { - const pluginImages = useSelector(getPluginImages); - const params = useParams<{ - pageId: string; - pluginPackageName: string; - }>(); - const { datasource } = props; - const datasourceFormConfigs = useSelector( - (state: AppState) => state.entities.plugins.formConfigs, - ); - const queryActions = useSelector(getCurrentActions); - const queriesWithThisDatasource = queryActions.filter( - (action) => - isStoredDatasource(action.config.datasource) && - action.config.datasource.id === datasource.id, - ).length; - - // TODO: Fix this the next time the file is edited - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const currentFormConfig: Array = - datasourceFormConfigs[datasource?.pluginId ?? ""]; - const QUERY = queriesWithThisDatasource > 1 ? "APIs" : "API"; - - const editDatasource = () => { - history.push( - saasEditorDatasourceIdURL({ - ...params, - datasourceId: datasource.id, - }), - ); - }; - - return ( - - -
- - - {datasource.name} - - - {queriesWithThisDatasource - ? `${queriesWithThisDatasource} ${QUERY} on this page` - : "No API is using this datasource"} - -
- - - Edit Datasource - - props.onCreate(datasource)} - text="New API" - /> - -
- {!isEmpty(currentFormConfig) ? ( - - ) : undefined} -
- ); -} - -export default DatasourceCard; diff --git a/app/client/src/pages/Editor/SaaSEditor/ListView.tsx b/app/client/src/pages/Editor/SaaSEditor/ListView.tsx deleted file mode 100644 index f674534551c..00000000000 --- a/app/client/src/pages/Editor/SaaSEditor/ListView.tsx +++ /dev/null @@ -1,236 +0,0 @@ -import React from "react"; -import { connect } from "react-redux"; -import type { RouteComponentProps } from "react-router"; -import type { Plugin } from "api/PluginApi"; -import { - getDatasourcesByPluginId, - getPluginByPackageName, -} from "ee/selectors/entitiesSelector"; -import NotFound from "pages/common/NotFound"; -import type { AppState } from "ee/reducers"; -import { createDatasourceFromForm } from "actions/datasourceActions"; -import type { SaaSAction } from "entities/Action"; -import { createActionRequest } from "actions/pluginActionActions"; -import type { Datasource } from "entities/Datasource"; -import type { ActionDataState } from "ee/reducers/entityReducers/actionsReducer"; - -// Design -import CenteredWrapper from "components/designSystems/appsmith/CenteredWrapper"; -import styled from "styled-components"; -import { Spinner, Button } from "@blueprintjs/core"; -import DatasourceCard from "pages/Editor/SaaSEditor/DatasourceCard"; -import { - getCurrentApplicationId, - getIsEditorInitialized, - selectURLSlugs, -} from "selectors/editorSelectors"; -import { INTEGRATION_TABS } from "constants/routes"; -import { integrationEditorURL } from "ee/RouteBuilder"; - -const IntegrationHomePage = styled.div` - padding: 20px; - padding-top: 30px; - overflow: auto; - display: flex; - flex-direction: column; - flex: 1; - - .sectionHeader { - font-weight: ${(props) => props.theme.fontWeights[2]}; - font-size: ${(props) => props.theme.fontSizes[4]}px; - } -`; - -const LoadingContainer = styled(CenteredWrapper)` - height: 50%; -`; - -const AddDatasource = styled(Button)` - padding: 23px; - border: 2px solid #d6d6d6; - justify-content: flex-start; - font-size: 16px; - font-weight: 500; -`; - -const Boundary = styled.hr` - border: 1px solid #d0d7dd; - margin-top: 16px; -`; - -interface StateProps { - plugin?: Plugin; - actions: ActionDataState; - datasources: Datasource[]; - isCreating: boolean; - isEditorInitialized: boolean; - applicationId: string; - applicationSlug: string; - pageSlug: string; -} - -interface DispatchFunctions { - // TODO: Fix this the next time the file is edited - // eslint-disable-next-line @typescript-eslint/no-explicit-any - createDatasource: (data: any) => void; - createAction: (data: Partial) => void; -} - -type RouteProps = RouteComponentProps<{ - basePageId: string; - pluginPackageName: string; -}>; - -type Props = StateProps & DispatchFunctions & RouteProps; -class ListView extends React.Component { - handleCreateNewDatasource = (pluginId: string) => { - this.props.createDatasource({ pluginId }); - }; - - handleCreateNewAPI = (datasource: Datasource) => { - const { - location, - match: { - params: { basePageId }, - }, - } = this.props; - const params: string = location.search; - let pgId = new URLSearchParams(params).get("importTo"); - - if (!pgId) { - pgId = basePageId; - } - - if (pgId) { - this.props.createAction({ - pageId: pgId, - pluginId: datasource.pluginId, - datasource: { - id: datasource.id, - }, - }); - } - }; - - render() { - const { isCreating, isEditorInitialized, plugin } = this.props; - - if (!plugin) { - return this.renderNotFound(); - } - - if (isCreating || !isEditorInitialized) { - return this.renderLoading(); - } - - return this.renderPage(); - } - - renderPage() { - const { datasources, plugin } = this.props; - - if (!plugin) { - return this.renderNotFound(); - } - - return ( - -

Select a datasource or create a new one

- - - this.handleCreateNewDatasource(plugin.id)} - text="New datasource" - /> - - {datasources.map((datasource) => { - return ( - - ); - })} -
- ); - } - - renderLoading() { - return ( - - - - ); - } - - renderNotFound() { - const { - history, - match: { - params: { basePageId }, - }, - } = this.props; - - return ( - - - history.push( - integrationEditorURL({ - basePageId, - selectedTab: INTEGRATION_TABS.ACTIVE, - }), - ) - } - title="Datasources/Queries Not found" - /> - - ); - } -} - -const mapStateToProps = (state: AppState, props: RouteProps): StateProps => { - const plugin = getPluginByPackageName( - state, - props.match.params.pluginPackageName, - ); - let datasources: Datasource[] = []; - - if (plugin) { - datasources = getDatasourcesByPluginId(state, plugin.id); - } - - const { applicationSlug, pageSlug } = selectURLSlugs(state); - - return { - plugin, - actions: state.entities.actions, - isCreating: state.ui.apiPane.isCreating, - isEditorInitialized: getIsEditorInitialized(state), - datasources: datasources, - applicationId: getCurrentApplicationId(state), - applicationSlug, - pageSlug, - }; -}; - -// TODO: Fix this the next time the file is edited -// eslint-disable-next-line @typescript-eslint/no-explicit-any -const mapDispatchToProps = (dispatch: any): DispatchFunctions => { - return { - // TODO: Fix this the next time the file is edited - // eslint-disable-next-line @typescript-eslint/no-explicit-any - createDatasource: (data: any) => dispatch(createDatasourceFromForm(data)), - createAction: (data: Partial) => { - dispatch(createActionRequest(data)); - }, - }; -}; - -export default connect(mapStateToProps, mapDispatchToProps)(ListView); diff --git a/app/client/src/pages/Editor/SaaSEditor/routes.ts b/app/client/src/pages/Editor/SaaSEditor/routes.ts deleted file mode 100644 index 4aa2c6316e3..00000000000 --- a/app/client/src/pages/Editor/SaaSEditor/routes.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { - SAAS_EDITOR_PATH, - SAAS_EDITOR_DATASOURCE_ID_PATH, - SAAS_EDITOR_API_ID_PATH, -} from "pages/Editor/SaaSEditor/constants"; -import ListView from "pages/Editor/SaaSEditor/ListView"; -import DatasourceForm from "pages/Editor/SaaSEditor/DatasourceForm"; -import QueryEditor from "../QueryEditor"; - -export const SaaSEditorRoutes = [ - { - path: SAAS_EDITOR_PATH, - component: ListView, - }, - { - path: SAAS_EDITOR_DATASOURCE_ID_PATH, - component: DatasourceForm, - }, - { - path: SAAS_EDITOR_API_ID_PATH, - component: QueryEditor, - }, -]; diff --git a/app/client/src/pages/Editor/ShareApplicationForm.tsx b/app/client/src/pages/Editor/ShareApplicationForm.tsx deleted file mode 100644 index 4a157746f84..00000000000 --- a/app/client/src/pages/Editor/ShareApplicationForm.tsx +++ /dev/null @@ -1,89 +0,0 @@ -import React from "react"; -import styled from "styled-components"; -import { withRouter } from "react-router"; -import { connect } from "react-redux"; -import type { AppState } from "ee/reducers"; -import { Switch } from "@appsmith/ads-old"; -import Spinner from "components/editorComponents/Spinner"; -import { ReduxActionTypes } from "ee/constants/ReduxActionConstants"; -import { getCurrentApplicationId } from "selectors/editorSelectors"; - -const ShareWithPublicOption = styled.div` - { - display: flex; - padding-top: 20px; - justify-content: space-between; - } -`; - -const ShareToggle = styled.div` - { - &&& label { - margin-bottom: 0px; - } - &&& div { - margin-right: 5px; - } - display: flex; - } -`; - -// TODO: Fix this the next time the file is edited -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export function ShareApplicationForm(props: any) { - const { - applicationId, - changeAppViewAccess, - currentApplicationDetails, - isChangingViewAccess, - isFetchingApplication, - } = props; - - return ( - - Share the application with anyone - - {(isChangingViewAccess || isFetchingApplication) && ( - - )} - {currentApplicationDetails && ( - { - changeAppViewAccess( - applicationId, - !currentApplicationDetails.isPublic, - ); - }} - /> - )} - - - ); -} - -const mapStateToProps = (state: AppState) => ({ - currentApplicationDetails: state.ui.applications.currentApplication, - isFetchingApplication: state.ui.applications.isFetchingApplication, - isChangingViewAccess: state.ui.applications.isChangingViewAccess, - applicationId: getCurrentApplicationId(state), -}); - -// TODO: Fix this the next time the file is edited -// eslint-disable-next-line @typescript-eslint/no-explicit-any -const mapDispatchToProps = (dispatch: any) => ({ - changeAppViewAccess: (applicationId: string, publicAccess: boolean) => - dispatch({ - type: ReduxActionTypes.CHANGE_APPVIEW_ACCESS_INIT, - payload: { - applicationId, - publicAccess, - }, - }), -}); - -export default withRouter( - connect(mapStateToProps, mapDispatchToProps)(ShareApplicationForm), -); diff --git a/app/client/src/pages/Editor/ThemePropertyPane/ThemeBetaCard.tsx b/app/client/src/pages/Editor/ThemePropertyPane/ThemeBetaCard.tsx deleted file mode 100644 index e318055ddb0..00000000000 --- a/app/client/src/pages/Editor/ThemePropertyPane/ThemeBetaCard.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import React from "react"; -import { useDispatch } from "react-redux"; - -import { closeAppThemingBetaCard } from "actions/appThemingActions"; -import { - createMessage, - APP_THEME_BETA_CARD_HEADING, - APP_THEME_BETA_CARD_CONTENT, -} from "ee/constants/messages"; -import { Button } from "@appsmith/ads"; - -export function ThemeBetaCard() { - const dispatch = useDispatch(); - - const closeThemeBetaCard = () => { - dispatch(closeAppThemingBetaCard()); - }; - - return ( -
- {createMessage(APP_THEME_BETA_CARD_HEADING)} -
{createMessage(APP_THEME_BETA_CARD_CONTENT)}
-
- - -
-
- ); -} diff --git a/app/client/src/pages/Editor/WidgetsEditor/components/Toolbar.tsx b/app/client/src/pages/Editor/WidgetsEditor/components/Toolbar.tsx deleted file mode 100644 index 663a52ede38..00000000000 --- a/app/client/src/pages/Editor/WidgetsEditor/components/Toolbar.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import React from "react"; - -function Toolbar() { - return ( -
- ); -} - -export default Toolbar; diff --git a/app/client/src/pages/Editor/commons/EditorWrapperBody.tsx b/app/client/src/pages/Editor/commons/EditorWrapperBody.tsx deleted file mode 100644 index cc3b1c982b3..00000000000 --- a/app/client/src/pages/Editor/commons/EditorWrapperBody.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import React from "react"; - -interface EditorWrapperBodyProps { - children: React.ReactNode; - id: string; -} - -function EditorWrapperBody({ children, id }: EditorWrapperBodyProps) { - return ( -
- {children} -
- ); -} - -export default EditorWrapperBody; diff --git a/app/client/src/pages/Editor/commons/LockEntityExplorer.tsx b/app/client/src/pages/Editor/commons/LockEntityExplorer.tsx deleted file mode 100644 index 214c3a1b48e..00000000000 --- a/app/client/src/pages/Editor/commons/LockEntityExplorer.tsx +++ /dev/null @@ -1,107 +0,0 @@ -import React, { useCallback } from "react"; -import { Button, Icon, Tooltip } from "@appsmith/ads"; -import { - CLOSE_ENTITY_EXPLORER_MESSAGE, - LOCK_ENTITY_EXPLORER_MESSAGE, - createMessage, -} from "ee/constants/messages"; -import { modText } from "utils/helpers"; -import classNames from "classnames"; -import { - setExplorerActiveAction, - setExplorerPinnedAction, -} from "actions/explorerActions"; -import { getExplorerPinned } from "selectors/explorerSelector"; -import { useDispatch, useSelector } from "react-redux"; -import styled from "styled-components"; - -export const SidebarNavButton = styled(Button)` - .ads-v2-button__content { - padding: 0; - } - .group { - height: 36px; - width: 36px; - display: flex; - align-items: center; - justify-content: center; - } -`; - -export const LockEntityExplorer = ({ - isPreviewingApp = false, -}: { - isPreviewingApp?: boolean; -}) => { - const pinned = useSelector(getExplorerPinned); - const dispatch = useDispatch(); - - /** - * on hovering the menu, make the explorer active - */ - const onMenuHover = useCallback(() => { - dispatch(setExplorerActiveAction(true)); - }, [setExplorerActiveAction]); - - /** - * toggles the pinned state of sidebar - */ - const onPin = useCallback(() => { - dispatch(setExplorerPinnedAction(!pinned)); - }, [pinned, dispatch, setExplorerPinnedAction]); - - return ( - - - {!pinned - ? createMessage(LOCK_ENTITY_EXPLORER_MESSAGE) - : createMessage(CLOSE_ENTITY_EXPLORER_MESSAGE)} - - {modText()} / -
- } - placement="bottomLeft" - > - -
- - {pinned && ( - - )} - {!pinned && ( - - )} -
-
- - ); -}; diff --git a/app/client/src/pages/Editor/gitSync/GitSyncModal/GitSyncModalV1.tsx b/app/client/src/pages/Editor/gitSync/GitSyncModal/GitSyncModalV1.tsx deleted file mode 100644 index 07295382313..00000000000 --- a/app/client/src/pages/Editor/gitSync/GitSyncModal/GitSyncModalV1.tsx +++ /dev/null @@ -1,184 +0,0 @@ -import React, { useCallback, useEffect } from "react"; -import { - getActiveGitSyncModalTab, - getIsDeploying, - getIsGitConnected, - getIsGitSyncModalOpen, -} from "selectors/gitSyncSelectors"; -import { useDispatch, useSelector } from "react-redux"; -import { setIsGitSyncModalOpen } from "actions/gitSyncActions"; -import { setWorkspaceIdForImport } from "ee/actions/applicationActions"; -import Menu from "../Menu"; -import Deploy from "../Tabs/Deploy"; -import Merge from "../Tabs/Merge"; -import GitConnection from "../Tabs/GitConnection"; - -import GitErrorPopup from "../components/GitErrorPopup"; -import styled from "styled-components"; -import AnalyticsUtil from "ee/utils/AnalyticsUtil"; -import { Modal, ModalContent, ModalHeader } from "@appsmith/ads"; -import { - createMessage, - GIT_CONNECTION, - DEPLOY, - MERGE, - CONNECT_TO_GIT, - DEPLOY_YOUR_APPLICATION, - MERGE_CHANGES, - GIT_IMPORT, - IMPORT_FROM_GIT_REPOSITORY, -} from "ee/constants/messages"; -import { GitSyncModalTab } from "entities/GitSync"; -import { getCurrentApplicationId } from "selectors/editorSelectors"; - -const ModalContentContainer = styled(ModalContent)` - min-height: 650px; -`; - -// TODO: Fix this the next time the file is edited -// eslint-disable-next-line @typescript-eslint/no-explicit-any -const ComponentsByTab: { [K in GitSyncModalTab]?: any } = { - [GitSyncModalTab.GIT_CONNECTION]: GitConnection, - [GitSyncModalTab.DEPLOY]: Deploy, - [GitSyncModalTab.MERGE]: Merge, -}; - -// TODO: Fix this the next time the file is edited -// eslint-disable-next-line @typescript-eslint/no-explicit-any -const MENU_ITEMS_MAP: { [K in GitSyncModalTab]?: any } = { - [GitSyncModalTab.GIT_CONNECTION]: { - key: GitSyncModalTab.GIT_CONNECTION, - title: createMessage(GIT_CONNECTION), - modalTitle: createMessage(CONNECT_TO_GIT), - }, - [GitSyncModalTab.DEPLOY]: { - key: GitSyncModalTab.DEPLOY, - title: createMessage(DEPLOY), - modalTitle: createMessage(DEPLOY_YOUR_APPLICATION), - }, - [GitSyncModalTab.MERGE]: { - key: GitSyncModalTab.MERGE, - title: createMessage(MERGE), - modalTitle: createMessage(MERGE_CHANGES), - }, -}; - -const allMenuOptions = Object.values(MENU_ITEMS_MAP); - -function GitSyncModalV1(props: { isImport?: boolean }) { - const dispatch = useDispatch(); - const isModalOpen = useSelector(getIsGitSyncModalOpen); - const isDeploying = useSelector(getIsDeploying); - const isGitConnected = useSelector(getIsGitConnected); - - const activeTabKey = useSelector(getActiveGitSyncModalTab); - const appId = useSelector(getCurrentApplicationId); - - const handleClose = useCallback(() => { - dispatch(setIsGitSyncModalOpen({ isOpen: false })); - dispatch( - setWorkspaceIdForImport({ editorId: appId || "", workspaceId: "" }), - ); - }, [dispatch, setIsGitSyncModalOpen]); - - const setActiveTabKey = useCallback( - (tabKey: GitSyncModalTab) => { - if (tabKey === GitSyncModalTab.DEPLOY) { - AnalyticsUtil.logEvent("GS_DEPLOY_GIT_MODAL_TRIGGERED", { - source: `${activeTabKey}_TAB`, - }); - } else if (tabKey === GitSyncModalTab.MERGE) { - AnalyticsUtil.logEvent("GS_MERGE_GIT_MODAL_TRIGGERED", { - source: `${activeTabKey}_TAB`, - }); - } - - dispatch( - setIsGitSyncModalOpen({ - isOpen: isModalOpen, - tab: tabKey, - isDeploying, - }), - ); - }, - [dispatch, setIsGitSyncModalOpen, isModalOpen], - ); - - useEffect(() => { - if (!isGitConnected && activeTabKey !== GitSyncModalTab.GIT_CONNECTION) { - setActiveTabKey(GitSyncModalTab.DEPLOY); - } - }, [activeTabKey]); - - useEffect(() => { - // when git connected - if (isGitConnected && activeTabKey === GitSyncModalTab.GIT_CONNECTION) { - setActiveTabKey(GitSyncModalTab.DEPLOY); - } - }, [isGitConnected]); - - let menuOptions = allMenuOptions; - - if (props.isImport) { - menuOptions = [ - { - key: GitSyncModalTab.GIT_CONNECTION, - modalTitle: createMessage(IMPORT_FROM_GIT_REPOSITORY), - title: createMessage(GIT_IMPORT), - }, - ]; - } else { - menuOptions = isGitConnected - ? allMenuOptions - : [MENU_ITEMS_MAP.GIT_CONNECTION]; - } - - useEffect(() => { - // onMount or onChange of activeTabKey - if ( - activeTabKey !== GitSyncModalTab.GIT_CONNECTION && - menuOptions.findIndex((option) => option.key === activeTabKey) === -1 - ) { - setActiveTabKey(GitSyncModalTab.GIT_CONNECTION); - } - }, [activeTabKey]); - - const BodyComponent = - ComponentsByTab[activeTabKey || GitSyncModalTab.GIT_CONNECTION]; - - return ( - <> - { - if (!open) { - handleClose(); - } - }} - open={isModalOpen} - > - - - {MENU_ITEMS_MAP[activeTabKey]?.modalTitle ?? ""} - - - setActiveTabKey(tabKey as GitSyncModalTab) - } - options={menuOptions} - /> - {activeTabKey === GitSyncModalTab.GIT_CONNECTION && ( - - )} - {activeTabKey !== GitSyncModalTab.GIT_CONNECTION && } - - - - - ); -} - -export default GitSyncModalV1; diff --git a/app/client/src/pages/Editor/gitSync/QuickGitActions/index.tsx b/app/client/src/pages/Editor/gitSync/QuickGitActions/index.tsx index c8e6f7189c6..e1285d1011f 100644 --- a/app/client/src/pages/Editor/gitSync/QuickGitActions/index.tsx +++ b/app/client/src/pages/Editor/gitSync/QuickGitActions/index.tsx @@ -36,6 +36,7 @@ import { getIsFetchingGitStatus, getIsGitConnected, getIsPollingAutocommit, + getIsPullingProgress, getPullFailed, protectedModeSelector, } from "selectors/gitSyncSelectors"; @@ -306,9 +307,11 @@ export default function QuickGitActions() { const { disabled: pullDisabled, message: pullTooltipMessage } = getPullBtnStatus(gitStatus, !!pullFailed, isProtectedMode); - const isPullInProgress = useSelector(getIsDiscardInProgress); + const isDiscardInProgress = useSelector(getIsDiscardInProgress); + const isPullInProgress = useSelector(getIsPullingProgress); const isFetchingGitStatus = useSelector(getIsFetchingGitStatus); - const showPullLoadingState = isPullInProgress || isFetchingGitStatus; + const showPullLoadingState = + isDiscardInProgress || isPullInProgress || isFetchingGitStatus; const changesToCommit = useSelector(getCountOfChangesToCommit); const gitMetadata = useSelector(getGitMetadataSelector); diff --git a/app/client/src/pages/Editor/gitSync/Tabs/GitConnection.tsx b/app/client/src/pages/Editor/gitSync/Tabs/GitConnection.tsx deleted file mode 100644 index bfad163e844..00000000000 --- a/app/client/src/pages/Editor/gitSync/Tabs/GitConnection.tsx +++ /dev/null @@ -1,525 +0,0 @@ -import React, { - useCallback, - useEffect, - useMemo, - useRef, - useState, -} from "react"; -import { Container, Space } from "../components/StyledComponents"; -import { - CONNECT_BTN_LABEL, - CONNECT_TO_GIT_SUBTITLE, - CONNECTING_REPO, - createMessage, - GENERATE_KEY, - IMPORT_BTN_LABEL, - IMPORT_URL_INFO, - IMPORTING_APP_FROM_GIT, - LEARN_MORE, - PASTE_SSH_URL_INFO, - REMOTE_URL, - REMOTE_URL_INFO, - REMOTE_URL_INPUT_PLACEHOLDER, - UPDATE_CONFIG, -} from "ee/constants/messages"; -import styled from "styled-components"; -import { emailValidator } from "@appsmith/ads-old"; -import UserGitProfileSettings from "../components/UserGitProfileSettings"; -import { AUTH_TYPE_OPTIONS, Classes } from "../constants"; -import { useDispatch, useSelector } from "react-redux"; -import copy from "copy-to-clipboard"; -import { - getCurrentAppGitMetaData, - getCurrentApplication, -} from "ee/selectors/applicationSelectors"; -import { - fetchGlobalGitConfigInit, - fetchLocalGitConfigInit, - importAppFromGit, - remoteUrlInputValue, - resetSSHKeys, - setDisconnectingGitApplication, - setIsDisconnectGitModalOpen, - setIsGitSyncModalOpen, - updateLocalGitConfigInit, -} from "actions/gitSyncActions"; -import equal from "fast-deep-equal/es6"; -import { - getGitConnectError, - getGlobalGitConfig, - getIsFetchingGlobalGitConfig, - getIsFetchingLocalGitConfig, - getIsImportingApplicationViaGit, - getLocalGitConfig, - getTempRemoteUrl, - getUseGlobalProfile, -} from "selectors/gitSyncSelectors"; -import Statusbar, { - StatusbarWrapper, -} from "pages/Editor/gitSync/components/Statusbar"; -import Keys from "../components/ssh-key"; -import GitConnectError from "../components/GitConnectError"; -import { - Button, - Input, - Text, - Tooltip, - Link, - ModalBody, - ModalFooter, -} from "@appsmith/ads"; -import AnalyticsUtil from "ee/utils/AnalyticsUtil"; -import { GIT_DOC_URLs, isValidGitRemoteUrl } from "../utils"; -import { useGitConnect, useSSHKeyPair } from "../hooks"; - -const UrlContainer = styled.div<{ - isConnected: boolean; -}>` - display: flex; - align-items: flex-end; - gap: 3px; - width: ${({ isConnected }) => (isConnected ? "100%" : "calc(100% - 39px)")}; -`; - -const ButtonContainer = styled.div<{ topMargin: number }>` - margin-top: ${(props) => `${props.theme.spaces[props.topMargin]}px`}; -`; - -const RemoteUrlInfoWrapper = styled.div` - margin-bottom: 4px; - display: flex; - .learn-more-link { - padding-left: 2px; - > span { - font-size: 12px; - } - } -`; - -// v1 only support SSH -const selectedAuthType = AUTH_TYPE_OPTIONS[0]; - -interface AuthorInfo { - authorName: string; - authorEmail: string; -} - -interface Props { - isImport?: boolean; -} - -function GitConnection({ isImport }: Props) { - const placeholderText = createMessage(REMOTE_URL_INPUT_PLACEHOLDER); - - const dispatch = useDispatch(); - const useGlobalProfile = useSelector(getUseGlobalProfile); - const globalGitConfig = useSelector(getGlobalGitConfig); - const localGitConfig = useSelector(getLocalGitConfig); - // TODO: Fix this the next time the file is edited - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const { tempRemoteUrl = "" } = useSelector(getTempRemoteUrl) || ({} as any); - const currentApp = useSelector(getCurrentApplication); - const isFetchingGlobalGitConfig = useSelector(getIsFetchingGlobalGitConfig); - const isFetchingLocalGitConfig = useSelector(getIsFetchingLocalGitConfig); - const { remoteUrl: remoteUrlInStore = "" } = - // TODO: Fix this the next time the file is edited - // eslint-disable-next-line @typescript-eslint/no-explicit-any - useSelector(getCurrentAppGitMetaData) || ({} as any); - const RepoUrlDocumentUrl = isImport - ? GIT_DOC_URLs.import - : GIT_DOC_URLs.connect; - const isImportingApplicationViaGit = useSelector( - getIsImportingApplicationViaGit, - ); - const gitConnectError = useSelector(getGitConnectError); - - const { - deployKeyDocUrl, - fetchingSSHKeyPair, - fetchSSHKeyPair, - generateSSHKey, - generatingSSHKey, - SSHKeyPair, - } = useSSHKeyPair(); - - const { connectToGit, isConnectingToGit } = useGitConnect(); - - const [remoteUrl, setRemoteUrl] = useState(remoteUrlInStore || tempRemoteUrl); - const isGitConnected = !!remoteUrlInStore; - - const [authorInfo, setAuthorInfo] = useState({ - authorName: "", - authorEmail: "", - }); - const [useGlobalConfigInputVal, setUseGlobalConfigInputVal] = useState(false); - - const [triedSubmit, setTriedSubmit] = useState(false); - const [isInvalidRemoteUrl, setIsValidRemoteUrl] = useState(false); - const [showCopied, setShowCopied] = useState(false); - const timerRef = useRef(0); - - useEffect(() => { - // On unmount clear timer to avoid memory leak - return () => { - if (timerRef.current) { - clearTimeout(timerRef.current); - } - }; - }, []); - - useEffect(() => { - // when disconnected remoteURL becomes undefined - if (!remoteUrlInStore) { - setRemoteUrl(tempRemoteUrl || ""); - } - }, [remoteUrlInStore]); - - useEffect(() => { - const initialGlobalConfigInputVal = !isGitConnected - ? true - : useGlobalProfile; - - setUseGlobalConfigInputVal(!!initialGlobalConfigInputVal); - }, [useGlobalProfile, isGitConnected]); - - useEffect(() => { - setAuthorInfo(localGitConfig); - }, [localGitConfig, useGlobalConfigInputVal]); - - useEffect(() => { - // OnMount fetch global and local config - dispatch(fetchGlobalGitConfigInit()); - dispatch(fetchLocalGitConfigInit()); - }, []); - - useEffect(() => { - // On mount check SSHKeyPair is defined, if not fetchSSHKeyPair - if (!SSHKeyPair && !isImport) { - fetchSSHKeyPair(); - } - }, []); - - const stopShowingCopiedAfterDelay = () => { - timerRef.current = setTimeout(() => { - setShowCopied(false); - }, 2000); - }; - - const copyToClipboard = () => { - if (SSHKeyPair) { - copy(SSHKeyPair); - setShowCopied(true); - stopShowingCopiedAfterDelay(); - } - - AnalyticsUtil.logEvent("GS_COPY_SSH_KEY_BUTTON_CLICK"); - }; - - const isAuthorInfoUpdated = useCallback(() => { - return ( - !equal(localGitConfig?.authorEmail, authorInfo.authorEmail) || - !equal(localGitConfig?.authorName, authorInfo.authorName) - ); - }, [authorInfo.authorEmail, authorInfo.authorName, localGitConfig]); - - const remoteUrlChangeHandler = (value: string) => { - const isInvalid = !isValidGitRemoteUrl(value); - - setIsValidRemoteUrl(isInvalid); - setRemoteUrl(value); - dispatch(remoteUrlInputValue({ tempRemoteUrl: value })); - AnalyticsUtil.logEvent("GS_REPO_URL_EDIT", { - repoUrl: value, - }); - }; - - const isUseGlobalProfileFlagUpdated = - useGlobalConfigInputVal !== !!useGlobalProfile; - - const submitButtonDisabled = useMemo(() => { - const isAuthInfoUpdated = isAuthorInfoUpdated(); - let buttonDisabled; - - if (isGitConnected) { - const isFetchingConfig = - isFetchingGlobalGitConfig || isFetchingLocalGitConfig; - - buttonDisabled = - (!isAuthInfoUpdated && !isUseGlobalProfileFlagUpdated) || - isFetchingConfig; - } else { - buttonDisabled = isInvalidRemoteUrl; - } - - return buttonDisabled; - }, [ - isAuthorInfoUpdated, - isGitConnected, - isFetchingGlobalGitConfig, - isFetchingLocalGitConfig, - isInvalidRemoteUrl, - isUseGlobalProfileFlagUpdated, - ]); - - const submitButtonIsLoading = isConnectingToGit; - - const isAuthorInfoValid = useMemo(() => { - return ( - useGlobalConfigInputVal || - (authorInfo.authorName && - authorInfo.authorEmail && - emailValidator(authorInfo.authorEmail).isValid) - ); - }, [useGlobalConfigInputVal, authorInfo.authorName, authorInfo.authorEmail]); - - const onSubmit = useCallback(() => { - if (isConnectingToGit || submitButtonDisabled) return; - - setTriedSubmit(true); - AnalyticsUtil.logEvent("GS_CONNECT_BUTTON_ON_GIT_SYNC_MODAL_CLICK"); - - if (!isAuthorInfoValid) return; - - if (isGitConnected) { - const updatedGitConfig = useGlobalConfigInputVal - ? localGitConfig - : authorInfo; - - dispatch( - updateLocalGitConfigInit({ - ...updatedGitConfig, - useGlobalProfile: useGlobalConfigInputVal, - }), - ); - } else { - isImport - ? dispatch( - importAppFromGit({ - payload: { - remoteUrl, - gitProfile: { - ...authorInfo, - useDefaultProfile: useGlobalConfigInputVal, - }, - }, - }), - ) - : connectToGit({ - remoteUrl, - gitProfile: { - ...authorInfo, - useDefaultProfile: useGlobalConfigInputVal, - }, - }); - } - }, [ - updateLocalGitConfigInit, - isAuthorInfoUpdated, - connectToGit, - useGlobalConfigInputVal, - remoteUrl, - ]); - - const toggleHandler = useCallback(() => { - setUseGlobalConfigInputVal(!useGlobalConfigInputVal); - AnalyticsUtil.logEvent("GS_DEFAULT_CONFIGURATION_CHECKBOX_TOGGLED", { - value: !useGlobalConfigInputVal, - }); - }, [setUseGlobalConfigInputVal, useGlobalConfigInputVal]); - - const scrollWrapperRef = React.createRef(); - - useEffect(() => { - if (gitConnectError && scrollWrapperRef.current) { - setTimeout(() => { - const top = scrollWrapperRef.current?.scrollHeight || 0; - - scrollWrapperRef.current?.scrollTo({ - top: top, - }); - }, 100); - } - }, [scrollWrapperRef, gitConnectError]); - - const openDisconnectGitModal = useCallback(() => { - AnalyticsUtil.logEvent("GS_DISCONNECT_GIT_CLICK", { - source: "GIT_CONNECTION_MODAL", - }); - dispatch(setIsGitSyncModalOpen({ isOpen: false })); - dispatch( - setDisconnectingGitApplication({ - id: currentApp?.id || "", - name: currentApp?.name || "", - }), - ); - dispatch(setIsDisconnectGitModalOpen(true)); - }, []); - - // reset on unmount - useEffect(() => { - return () => { - dispatch(remoteUrlInputValue({ tempRemoteUrl: "" })); - dispatch(resetSSHKeys()); - }; - }, []); - - return ( - <> - {/* @ts-expect-error Figure out how to pass string to constant className */} - - - - {createMessage(CONNECT_TO_GIT_SUBTITLE)} - - - - - - {createMessage( - isImport ? IMPORT_URL_INFO : REMOTE_URL_INFO, - )} - - { - AnalyticsUtil.logEvent( - "GS_GIT_DOCUMENTATION_LINK_CLICK", - { - source: "REMOTE_URL_ON_GIT_CONNECTION_MODAL", - }, - ); - }} - target={"_blank"} - to={RepoUrlDocumentUrl} - > - {createMessage(LEARN_MORE)} - - - ) : null - } - errorMessage={ - isInvalidRemoteUrl ? createMessage(PASTE_SSH_URL_INFO) : "" - } - isDisabled={remoteUrl === remoteUrlInStore && !!remoteUrl} - label={createMessage(REMOTE_URL)} - onChange={remoteUrlChangeHandler} - placeholder={placeholderText} - size="md" - type="url" - value={remoteUrl} - /> - {SSHKeyPair && isGitConnected && ( - - - ) : null} - - {/* Action button to import, update or connect */} - {!(isConnectingToGit || isImportingApplicationViaGit) && SSHKeyPair ? ( - - ) : null} - - - ); -} - -export default GitConnection; diff --git a/app/client/src/pages/Editor/gitSync/components/CredentialMode.tsx b/app/client/src/pages/Editor/gitSync/components/CredentialMode.tsx deleted file mode 100644 index a32476ec343..00000000000 --- a/app/client/src/pages/Editor/gitSync/components/CredentialMode.tsx +++ /dev/null @@ -1,195 +0,0 @@ -import { - Classes as AdsClasses, - Text, - Case, - FontWeight, - TextType, - TooltipComponent, -} from "@appsmith/ads-old"; -import { Colors } from "constants/Colors"; -import React, { useState, useEffect, useCallback } from "react"; -import styled from "styled-components"; -import { CREDENTIAL_MODE } from "../constants"; -import { DOCS_BASE_URL } from "constants/ThirdPartyConstants"; -import { Icon } from "@appsmith/ads"; - -const Container = styled.div` - margin-top: ${(props) => props.theme.spaces[7]}px; - margin-bottom: ${(props) => props.theme.spaces[11]}px; -`; - -export const Radio = styled.label<{ - disabled?: boolean; - columns?: number; - rows?: number; - backgroundColor?: string; -}>` - display: block; - position: relative; - padding-left: ${(props) => props.theme.spaces[12] - 2}px; - cursor: ${(props) => (props.disabled ? "not-allowed" : "pointer")}; - font-size: ${(props) => props.theme.typography.p1.fontSize}px; - font-weight: ${(props) => props.theme.typography.p1.fontWeight}; - line-height: ${(props) => props.theme.typography.p1.lineHeight}px; - letter-spacing: ${(props) => props.theme.typography.p1.letterSpacing}px; - color: ${(props) => props.theme.colors.radio.text}; - margin-bottom: ${(props) => props.theme.spaces[7]}px; - ${(props) => - props.columns && props.columns > 0 - ? ` - flex-basis: calc(100% / ${props.columns}); - ` - : props.rows && props.rows > 0 - ? ` - margin-bottom: ${props.theme.spaces[11] + 1}px;` - : null}; - - input { - position: absolute; - opacity: 0; - cursor: pointer; - } - - .checkbox { - position: absolute; - top: 0; - left: 0; - width: ${(props) => props.theme.spaces[8]}px; - height: ${(props) => props.theme.spaces[8]}px; - background-color: transparent; - border: ${(props) => props.theme.spaces[1] - 2}px solid ${Colors.BLACK}; - border-radius: 50%; - margin-top: ${(props) => props.theme.spaces[0]}px; - } - - .checkbox:after { - content: ""; - position: absolute; - display: none; - } - - input:checked ~ .checkbox:after { - display: block; - } - - input:disabled ~ .checkbox:after { - background-color: ${(props) => props.theme.colors.radio.disabled}; - } - - .checkbox:after { - content: ""; - position: absolute; - width: ${(props) => props.theme.spaces[4]}px; - height: ${(props) => props.theme.spaces[4]}px; - ${(props) => - props.disabled - ? `background-color: ${props.theme.colors.radio.disabled}` - : `background-color: ${props.backgroundColor || Colors.BLACK};`}; - top: ${(props) => props.theme.spaces[1] - 2}px; - left: ${(props) => props.theme.spaces[1] - 2}px; - border-radius: 50%; - } -`; - -const LabelWrapper = styled.div``; -const Row = styled.div` - display: flex; - margin-bottom: 5px; - .${AdsClasses.TEXT} { - margin-right: ${(props) => props.theme.spaces[2]}px; - } -`; - -const LinkText = styled.div` - cursor: pointer; - .${AdsClasses.ICON} { - margin-right: ${(props) => props.theme.spaces[3]}px; - display: inline-flex; - } - display: inline-flex; - align-items: center; - justify-content: center; -`; - -function LabelWithHelper(props: { label: string; tooltip: string }) { - return ( - - {props.label} - - - - - ); -} - -export default function CredentialMode(props: { - defaultValue: string; - onSelect?: (value: CREDENTIAL_MODE) => void; -}) { - const [selected, setSelected] = useState(props.defaultValue); - - useEffect(() => { - setSelected(props.defaultValue); - }, [props.defaultValue]); - - const onChangeHandler = (value: CREDENTIAL_MODE) => { - setSelected(value); - props.onSelect && props.onSelect(value); - }; - - const downloadJson = useCallback(() => { - window.open(DOCS_BASE_URL, "_blank"); - }, []); - - return ( - - - - - - - Choose the datasource and add the missing credentials - - - - onChangeHandler(CREDENTIAL_MODE.MANUALLY)} - type="radio" - value={CREDENTIAL_MODE.MANUALLY} - /> - - - - - - - Upload using JSON Block - - - - - - DOWNLOAD SAMPLE JSON - - - - - onChangeHandler(CREDENTIAL_MODE.IMPORT_JSON)} - type="radio" - value={CREDENTIAL_MODE.IMPORT_JSON} - /> - - - - ); -} diff --git a/app/client/src/pages/Editor/gitSync/components/GitConnectError.tsx b/app/client/src/pages/Editor/gitSync/components/GitConnectError.tsx deleted file mode 100644 index e6c3d023625..00000000000 --- a/app/client/src/pages/Editor/gitSync/components/GitConnectError.tsx +++ /dev/null @@ -1,67 +0,0 @@ -import React, { useEffect, useRef } from "react"; -import { useSelector } from "react-redux"; -import { - getConnectingErrorDocUrl, - getGitConnectError, -} from "selectors/gitSyncSelectors"; -import { Callout, Text } from "@appsmith/ads"; -import styled from "styled-components"; - -const Container = styled.div` - width: calc(100% - 39px); - - & .t--git-connection-error > .ads-v2-callout__children { - margin-top: 0; - } -`; - -export default function GitConnectError({ - onClose, - onDisplay, -}: { - onClose?: () => void; - onDisplay?: () => void; -}) { - const containerRef = useRef(null); - const error = useSelector(getGitConnectError); - const connectingErrorDocumentUrl = useSelector(getConnectingErrorDocUrl); - const titleMessage = error?.errorType - ? error.errorType.replaceAll("_", " ") - : ""; - - useEffect(() => { - if (error && onDisplay) { - onDisplay(); - } - - if (containerRef.current) { - containerRef.current.scrollIntoView(); - } - }, [error]); - - return error ? ( - - - - {titleMessage} - -
- - {error?.message} - -
-
- ) : null; -} diff --git a/app/client/src/pages/Editor/gitSync/components/TabItem.tsx b/app/client/src/pages/Editor/gitSync/components/TabItem.tsx deleted file mode 100644 index 1361cb4ad4a..00000000000 --- a/app/client/src/pages/Editor/gitSync/components/TabItem.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import React from "react"; -import styled from "styled-components"; -import type { Theme } from "constants/DefaultTheme"; -import { getTypographyByKey } from "@appsmith/ads-old"; -import { Colors } from "constants/Colors"; - -interface WrapperProps { - selected: boolean; - vertical: boolean; - theme: Theme; -} - -const getSelectedStyles = (props: WrapperProps) => - props.selected - ? `color: ${props.theme.colors.tabItemBackgroundFill.highlightTextColor}; - font-weight: 500; - border-bottom: 2px solid var(--ads-color-brand); - - ` - : `color: ${Colors.GREY_7} - `; - -const Wrapper = styled.div` - display: flex; - ${getTypographyByKey("p0")}; - ${(props) => getSelectedStyles(props)}; - - &:hover, - &:focus { - color: ${(props) => - props.theme.colors.tabItemBackgroundFill.highlightTextColor}; - } - - padding: ${(props) => `${props.theme.spaces[5]}px 0px`}; - - width: 100%; - - align-items: center; -`; - -export default function TabItem(props: { - tab: { - key: string; - title: string; - }; - selected: boolean; - vertical: boolean; -}) { - const { selected, tab, vertical } = props; - - return ( - - {tab.title} - - ); -} diff --git a/app/client/src/pages/Editor/gitSync/components/UserGitProfileSettings.tsx b/app/client/src/pages/Editor/gitSync/components/UserGitProfileSettings.tsx deleted file mode 100644 index e4baad98eac..00000000000 --- a/app/client/src/pages/Editor/gitSync/components/UserGitProfileSettings.tsx +++ /dev/null @@ -1,204 +0,0 @@ -import React, { useCallback, useState, useMemo } from "react"; -import { Space } from "./StyledComponents"; -import { - AUTHOR_EMAIL, - AUTHOR_NAME, - AUTHOR_NAME_CANNOT_BE_EMPTY, - FORM_VALIDATION_INVALID_EMAIL, - USER_PROFILE_SETTINGS_TITLE, - USE_DEFAULT_CONFIGURATION, - createMessage, -} from "ee/constants/messages"; -import styled from "styled-components"; -import { emailValidator } from "@appsmith/ads-old"; -import { useSelector } from "react-redux"; -import { - getIsFetchingGlobalGitConfig, - getIsFetchingLocalGitConfig, -} from "selectors/gitSyncSelectors"; -import { Checkbox, Input, Text } from "@appsmith/ads"; - -const InputContainer = styled.div` - display: flex; - align-items: center; - margin-bottom: ${(props) => props.theme.spaces[5]}px; -`; - -const MainContainer = styled.div` - width: calc(100% - 39px); -`; - -const DefaultConfigContainer = styled.div` - display: flex; - align-items: flex-start; - margin-top: ${(props) => props.theme.spaces[3]}px; - margin-left: 3px; -`; - -interface AuthorInfo { - authorName: string; - authorEmail: string; -} - -const AUTHOR_INFO_LABEL = { - EMAIL: "authorEmail", - NAME: "authorName", -}; - -type SetAuthorInfo = (authorInfo: AuthorInfo) => void; - -const setAuthorState = ({ - authorInfo, - label, - setAuthorInfo, - value, -}: { - authorInfo: AuthorInfo; - label: string; - value: string; - setAuthorInfo: SetAuthorInfo; -}) => { - switch (label) { - case AUTHOR_INFO_LABEL.NAME: - setAuthorInfo({ - authorEmail: authorInfo.authorEmail, - authorName: value, - }); - break; - case AUTHOR_INFO_LABEL.EMAIL: - setAuthorInfo({ - authorEmail: value, - authorName: authorInfo.authorName, - }); - break; - default: - break; - } -}; - -// Component -interface UserGitProfileSettingsProps { - authType: string; - authorInfo: AuthorInfo; - setAuthorInfo: SetAuthorInfo; - useGlobalConfig: boolean; - toggleUseDefaultConfig: (useDefaultConfig: boolean) => void; - triedSubmit: boolean; -} - -function UserGitProfileSettings({ - authorInfo, - setAuthorInfo, - toggleUseDefaultConfig, - triedSubmit, - useGlobalConfig, -}: UserGitProfileSettingsProps) { - // - const [emailInputFocused, setEmailInputFocused] = useState(false); - const [nameInputFocused, setNameInputFocused] = useState(false); - const isFetchingGlobalGitConfig = useSelector(getIsFetchingGlobalGitConfig); - const isFetchingLocalGitConfig = useSelector(getIsFetchingLocalGitConfig); - - const changeHandler = useCallback( - (label: string, value: string) => - setAuthorState({ - label, - value, - authorInfo, - setAuthorInfo, - }), - [authorInfo, setAuthorInfo], - ); - - const disableInput = useGlobalConfig; - - const isValidEmail = useMemo( - () => - authorInfo.authorEmail && emailValidator(authorInfo.authorEmail).isValid, - [authorInfo.authorEmail], - ); - - const isFetchingConfig = - isFetchingGlobalGitConfig || isFetchingLocalGitConfig; - - const showDefaultConfig = !isFetchingConfig; - const nameInvalid = - !isFetchingConfig && - !useGlobalConfig && - !authorInfo.authorName && - !nameInputFocused && - triedSubmit; - - const emailInvalid = - !isFetchingConfig && - !useGlobalConfig && - !isValidEmail && - !emailInputFocused && - triedSubmit; - - return ( - - - {createMessage(USER_PROFILE_SETTINGS_TITLE)} - - {showDefaultConfig ? ( - - - {createMessage(USE_DEFAULT_CONFIGURATION)} - - - ) : null} - - - <> - - setNameInputFocused(false)} - onChange={(value: string) => - changeHandler(AUTHOR_INFO_LABEL.NAME, value) - } - onFocus={() => setNameInputFocused(true)} - // trimValue={false} - size="md" - type="text" - value={authorInfo.authorName} - /> - - - setEmailInputFocused(false)} - onChange={(value: string) => - changeHandler(AUTHOR_INFO_LABEL.EMAIL, value) - } - onFocus={() => setEmailInputFocused(true)} - size="md" - type="email" - value={authorInfo.authorEmail} - /> - - - - ); -} - -export default UserGitProfileSettings; diff --git a/app/client/src/pages/Editor/gitSync/components/ssh-key/CopySSHKey.tsx b/app/client/src/pages/Editor/gitSync/components/ssh-key/CopySSHKey.tsx deleted file mode 100644 index e327b2c5f5c..00000000000 --- a/app/client/src/pages/Editor/gitSync/components/ssh-key/CopySSHKey.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import { TooltipWrapper, IconContainer } from "./StyledComponents"; -import { COPY_SSH_KEY, createMessage } from "ee/constants/messages"; -import React from "react"; -import { Button, Icon, Tooltip } from "@appsmith/ads"; - -function getCopiedSuccessIcon() { - return ( - - - - ); -} - -function getToCopyIcon(copyToClipboard: () => void) { - return ( - - - - - - - ); -} diff --git a/app/client/src/pages/Editor/gitSync/components/ssh-key/getNotificationBanner.tsx b/app/client/src/pages/Editor/gitSync/components/ssh-key/getNotificationBanner.tsx deleted file mode 100644 index 7d2a63efdac..00000000000 --- a/app/client/src/pages/Editor/gitSync/components/ssh-key/getNotificationBanner.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import React from "react"; -import { NotificationBannerContainer } from "./StyledComponents"; -import { - createMessage, - DEPLOY_KEY_USAGE_GUIDE_MESSAGE, -} from "ee/constants/messages"; -import { Callout } from "@appsmith/ads"; - -/** - * getNotificationBanner returns a notification banner about copying the key to repo settings. - * @param learnMoreClickHandler {() => void} link that takes user to documentation - * @param setShowKeyGeneratedMessage {( value: ((prevState: boolean) => boolean) | boolean ) => void} - */ -export default function getNotificationBanner( - deployKeyDocUrl: string, - learnMoreClickHandler: (e: React.MouseEvent) => void, - setShowKeyGeneratedMessage: (value: boolean) => void, -): JSX.Element { - return ( - - setShowKeyGeneratedMessage(false)} - > - {createMessage(DEPLOY_KEY_USAGE_GUIDE_MESSAGE)} - - - ); -} diff --git a/app/client/src/pages/Editor/gitSync/components/ssh-key/index.tsx b/app/client/src/pages/Editor/gitSync/components/ssh-key/index.tsx deleted file mode 100644 index d028c887807..00000000000 --- a/app/client/src/pages/Editor/gitSync/components/ssh-key/index.tsx +++ /dev/null @@ -1,171 +0,0 @@ -import { - createMessage, - SSH_KEY, - SSH_KEY_GENERATED, -} from "ee/constants/messages"; -import React, { useCallback, useState } from "react"; -import { Space } from "pages/Editor/gitSync/components/StyledComponents"; -import AnalyticsUtil from "ee/utils/AnalyticsUtil"; -import { useSSHKeyPair } from "../../hooks"; -import { - DeployedKeyContainer, - FlexRow, - KeyText, - KeyType, - MoreMenuWrapper, -} from "./StyledComponents"; -import { CopySSHKey } from "./CopySSHKey"; -import { supportedKeyTypeList } from "./SupportedKeyTypeList"; -import getNotificationBanner from "./getNotificationBanner"; -import { getConfirmMenuItem } from "./getConfirmMenuItem"; -import type { SSHKeyType } from "actions/gitSyncActions"; -import { - Button, - toast, - Menu, - MenuTrigger, - MenuItem, - MenuContent, - Text, - Icon, - MenuGroupName, -} from "@appsmith/ads"; - -interface KeysProps { - copyToClipboard: () => void; - deployKeyDocUrl: string; - showCopied: boolean; - SSHKeyPair: string; - isImport?: boolean; -} - -const defaultKeyTypes: SSHKeyType[] = [ - { - keySize: 256, - platFormSupported: "", - protocolName: "ECDSA", - }, - { - keySize: 4096, - platFormSupported: "Azure Devops", - protocolName: "RSA", - }, -]; - -function Keys(props: KeysProps) { - const { copyToClipboard, deployKeyDocUrl, showCopied, SSHKeyPair } = props; - const { generateSSHKey } = useSSHKeyPair(); - const [isMenuOpen, setIsMenuOpen] = useState(false); - const [showConfirmation, setShowConfirmation] = useState(false); - const [showKeyGeneratedMessage, setShowKeyGeneratedMessage] = useState(true); - const [newKeyType, setNewKeyType] = useState("ECDSA"); - const [keyType, keyVal, keyName] = SSHKeyPair.split(" "); - const exactKeyType = keyType.startsWith("ecdsa") ? "ECDSA" : "RSA"; - const supportedKeys = supportedKeyTypeList(defaultKeyTypes, exactKeyType); - const keyText = `${keyVal} ${keyName}`; - const learnMoreClickHandler = () => { - AnalyticsUtil.logEvent("GS_GIT_DOCUMENTATION_LINK_CLICK", { - source: "SSH_KEY_ON_GIT_CONNECTION_TAB", - }); - }; - const regenerateKey = useCallback(() => { - AnalyticsUtil.logEvent("GS_REGENERATE_SSH_KEY_CONFIRM_CLICK", { - oldKeyType: keyType, - newKeyType: newKeyType, - }); - generateSSHKey(newKeyType); - setShowConfirmation(false); - setIsMenuOpen(false); - setShowKeyGeneratedMessage(true); - toast.show(createMessage(SSH_KEY_GENERATED), { - kind: "success", - }); - }, [newKeyType]); - - const handleMenuClose = () => { - setShowConfirmation(false); - setIsMenuOpen(false); - }; - - return ( - <> - - - {createMessage(SSH_KEY)} - - - - - - {keyType} - {keyText} - {CopySSHKey(showCopied, copyToClipboard)} - - - - { - if (!open && !showConfirmation) { - setIsMenuOpen(false); - } - }} - open={isMenuOpen} - > - - - - - {showKeyGeneratedMessage && - getNotificationBanner( - deployKeyDocUrl, - learnMoreClickHandler, - setShowKeyGeneratedMessage, - )} - - ); -} - -export default Keys; diff --git a/app/client/src/pages/Templates/LeftPaneTemplateList.tsx b/app/client/src/pages/Templates/LeftPaneTemplateList.tsx deleted file mode 100644 index 11daca2d51d..00000000000 --- a/app/client/src/pages/Templates/LeftPaneTemplateList.tsx +++ /dev/null @@ -1,103 +0,0 @@ -import React from "react"; -import { useSelector } from "react-redux"; -import { useParams } from "react-router"; -import { getTemplatesSelector } from "selectors/templatesSelectors"; -import styled from "styled-components"; -import { Classes, Text, TextType } from "@appsmith/ads-old"; -import history from "utils/history"; -import { thinScrollbar } from "constants/DefaultTheme"; -import { Colors } from "constants/Colors"; -import { createMessage, TEMPLATES } from "ee/constants/messages"; -import { templateIdUrl } from "ee/RouteBuilder"; - -const Wrapper = styled.div` - width: ${(props) => props.theme.homePage.sidebar}px; - height: 100%; - display: flex; - padding-left: ${(props) => props.theme.spaces[7]}px; - padding-top: ${(props) => props.theme.spaces[11]}px; - flex-direction: column; - box-shadow: 1px 0px 0px ${Colors.GALLERY_2}; -`; - -const TempelateListWrapper = styled.div` - .title { - margin-bottom: ${(props) => props.theme.spaces[4]}px; - padding-left: ${(props) => props.theme.spaces[6] + 1}px; - } - - .list-wrapper { - margin-top: ${(props) => props.theme.spaces[4]}px; - overflow: auto; - height: calc(100vh - ${(props) => props.theme.homePage.header + 244}px); - ${thinScrollbar} - } -`; - -const SecondWrapper = styled.div` - height: calc(100vh - ${(props) => props.theme.homePage.header + 24}px); - position: relative; -`; - -const TemplateItem = styled.div<{ selected: boolean }>` - cursor: pointer; - display: flex; - flex-direction: row; - align-items: center; - justify-content: space-between; - padding: ${(props) => - `${props.theme.spaces[2]}px ${props.theme.spaces[6]}px ${props.theme.spaces[2]}px ${props.theme.spaces[11]}px`}; - .${Classes.TEXT} { - color: ${Colors.MIRAGE_2}; - } - ${(props) => - props.selected && - ` - background-color: ${Colors.GALLERY_1}; - .${Classes.TEXT} { - color: ${Colors.EBONY_CLAY_2}; - } - `} - - &:hover { - background-color: ${Colors.GALLERY_1}; - } -`; - -function LeftPaneTemplateList() { - const templates = useSelector(getTemplatesSelector); - const params = useParams<{ templateId: string }>(); - - const onClick = (id: string) => { - history.push(templateIdUrl({ id })); - }; - - return ( - - - - - {createMessage(TEMPLATES)} - -
- {templates.map((template) => { - return ( - onClick(template.id)} - selected={template.id === params.templateId} - > - - {template.title} - - - ); - })} -
-
-
-
- ); -} - -export default LeftPaneTemplateList; diff --git a/app/client/src/pages/Templates/TemplatesModal/TemplateList.tsx b/app/client/src/pages/Templates/TemplatesModal/TemplateList.tsx deleted file mode 100644 index 389f8125494..00000000000 --- a/app/client/src/pages/Templates/TemplatesModal/TemplateList.tsx +++ /dev/null @@ -1,82 +0,0 @@ -import { - FETCHING_TEMPLATE_LIST, - FORKING_TEMPLATE, - createMessage, -} from "ee/constants/messages"; -import type { Template } from "api/TemplatesApi"; -import React from "react"; -import { useSelector } from "react-redux"; -import { - isFetchingTemplatesSelector, - isImportingTemplateToAppSelector, -} from "selectors/templatesSelectors"; -import styled from "styled-components"; -import LoadingScreen from "./LoadingScreen"; -import TemplateFilters from "../TemplateFilters"; -import { TemplateContent } from "../TemplateContent"; - -const Wrapper = styled.div` - display: flex; - height: 85vh; - overflow-y: hidden; - - .templates-search { - background-color: var(--ads-v2-color-bg); - } -`; - -const FilterWrapper = styled.div` - .filter-wrapper { - width: 200px; - margin-right: 10px; - } -`; - -const ListWrapper = styled.div` - height: 79vh; - overflow: auto; - width: 100%; -`; - -interface TemplateListProps { - onTemplateClick: (id: string) => void; - onClose: () => void; -} - -function TemplateList(props: TemplateListProps) { - const onForkTemplateClick = (template: Template) => { - props.onTemplateClick(template.id); - }; - const isImportingTemplateToApp = useSelector( - isImportingTemplateToAppSelector, - ); - const isFetchingTemplates = useSelector(isFetchingTemplatesSelector); - - if (isFetchingTemplates) { - return ; - } - - if (isImportingTemplateToApp) { - return ; - } - - return ( - -
- - - - - - -
-
- ); -} - -export default TemplateList; diff --git a/app/client/src/pages/common/ArtBoard.tsx b/app/client/src/pages/common/ArtBoard.tsx deleted file mode 100644 index 351056630a2..00000000000 --- a/app/client/src/pages/common/ArtBoard.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import styled from "styled-components"; -export default styled.div<{ width: number }>` - width: ${(props) => props.width}px; - margin: 0 auto; - position: relative; - background: ${(props) => { - return props.theme.colors.artboard; - }}; - padding: 0 0 ${(props) => props.theme.canvasBottomPadding}px 0px; -`; diff --git a/app/client/src/pages/common/AvatarComponent.tsx b/app/client/src/pages/common/AvatarComponent.tsx deleted file mode 100644 index 6363615e520..00000000000 --- a/app/client/src/pages/common/AvatarComponent.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import React from "react"; -import { Avatar } from "@appsmith/ads"; - -export interface AvatarProps { - className?: string; - commonName?: string; - userName?: string; - size: string; - source?: string; - label?: string; - isTooltipEnabled?: boolean; -} - -// TODO: Fix this the next time the file is edited -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export function AvatarComponent(props: any) { - const getInitials = (name: string) => { - const names = name.split(" "); - let initials = names[0].substring(0, 1).toUpperCase(); - - if (names.length > 1) { - initials += names[names.length - 1].substring(0, 1).toUpperCase(); - } - - return initials; - }; - - return ( - - ); -} diff --git a/app/client/src/pages/common/CustomizedDropdown/Badge.tsx b/app/client/src/pages/common/CustomizedDropdown/Badge.tsx deleted file mode 100644 index b9dda86ef3c..00000000000 --- a/app/client/src/pages/common/CustomizedDropdown/Badge.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import React from "react"; -import styled from "styled-components"; -const BadgeWrapper = styled.div` - &&&&& { - display: flex; - flex-directition: row; - justify-content: flex-start; - img { - flex-basis: 0 1 auto; - width: 32px; - height: 32px; - border-radius: 50%; - margin-right: 16px; - } - div { - flex-basis: 1 0 auto; - flex-direction: column; - justify-content: space-around; - align-self: center; - & h3, - h5 { - font-weight: ${(props) => props.theme.fontWeights[1]}; - margin: 0; - } - & h5 { - color: ${(props) => props.theme.colors.paneText}; - font-size: ${(props) => props.theme.fontSizes[3]}px; - } - } - } -`; - -interface BadgeProps { - imageURL?: string; - text: string; - subtext?: string; -} - -export function Badge(props: BadgeProps) { - return ( - - {props.text} -
-

{props.text}

- {props.subtext &&
{props.subtext}
} -
-
- ); -} - -export default Badge; diff --git a/app/client/src/pages/common/CustomizedDropdown/HeaderDropdownData.tsx b/app/client/src/pages/common/CustomizedDropdown/HeaderDropdownData.tsx deleted file mode 100644 index 9933422acbf..00000000000 --- a/app/client/src/pages/common/CustomizedDropdown/HeaderDropdownData.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import { Directions } from "utils/helpers"; -import { ReduxActionTypes } from "ee/constants/ReduxActionConstants"; -import { getOnSelectAction, DropdownOnSelectActions } from "./dropdownHelpers"; -import type { CustomizedDropdownProps } from "./index"; -import type { User } from "constants/userConstants"; - -export const options = ( - user: User, - dropdownMainMenuName: string, -): CustomizedDropdownProps => ({ - sections: [ - { - options: [ - { - content: "Sign Out", - onSelect: () => - getOnSelectAction(DropdownOnSelectActions.DISPATCH, { - type: ReduxActionTypes.LOGOUT_USER_INIT, - }), - }, - ], - }, - ], - trigger: { - text: dropdownMainMenuName, - outline: false, - }, - openDirection: Directions.DOWN, -}); - -export default options; diff --git a/app/client/src/pages/common/CustomizedDropdown/WorkspaceDropdownData.tsx b/app/client/src/pages/common/CustomizedDropdown/WorkspaceDropdownData.tsx deleted file mode 100644 index e5c8e773d5e..00000000000 --- a/app/client/src/pages/common/CustomizedDropdown/WorkspaceDropdownData.tsx +++ /dev/null @@ -1,58 +0,0 @@ -import React from "react"; -import Badge from "./Badge"; -import { Directions } from "utils/helpers"; -import { getOnSelectAction, DropdownOnSelectActions } from "./dropdownHelpers"; -import type { CustomizedDropdownProps } from "./index"; -import type { User } from "constants/userConstants"; -import _ from "lodash"; - -export const options = ( - user: User, - workspaceName: string, - workspaceId: string, -): CustomizedDropdownProps => { - return { - sections: [ - { - options: [ - { - content: ( - - ), - disabled: true, - shouldCloseDropdown: false, - }, - { - content: "Workspace Settings", - onSelect: () => - getOnSelectAction(DropdownOnSelectActions.REDIRECT, { - path: `/workspace/${workspaceId}/settings`, - }), - }, - { - content: "Share", - onSelect: () => _.noop("Share option selected"), - }, - { - content: "Members", - onSelect: () => - getOnSelectAction(DropdownOnSelectActions.REDIRECT, { - path: `/workspace/${workspaceId}/settings`, - }), - }, - ], - }, - ], - trigger: { - icon: "WORKSPACE_ICON", - text: workspaceName, - outline: false, - }, - openDirection: Directions.DOWN, - }; -}; - -export default options; diff --git a/app/client/src/pages/common/Loader.tsx b/app/client/src/pages/common/Loader.tsx deleted file mode 100644 index 7f93896b5c7..00000000000 --- a/app/client/src/pages/common/Loader.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import React from "react"; -import styled from "styled-components"; - -const StyledLoader = styled.div``; - -export function Loader() { - return ; -} - -export default Loader; diff --git a/app/client/src/pages/common/LoginHeader.tsx b/app/client/src/pages/common/LoginHeader.tsx deleted file mode 100644 index 08e4dc2e50e..00000000000 --- a/app/client/src/pages/common/LoginHeader.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import React from "react"; -import { Link } from "react-router-dom"; -import { connect } from "react-redux"; -import { getCurrentUser } from "selectors/usersSelectors"; -import styled from "styled-components"; -import StyledHeader from "components/designSystems/appsmith/StyledHeader"; -import type { AppState } from "ee/reducers"; -import { BASE_URL } from "constants/routes"; -import { Colors } from "constants/Colors"; -import { importSvg } from "@appsmith/ads-old"; - -const AppsmithLogo = importSvg( - async () => import("assets/svg/appsmith_logo_primary.svg"), -); - -const StyledPageHeader = styled(StyledHeader)` - width: 100%; - height: 48px; - background: ${Colors.WHITE}; - display: flex; - justify-content: center; - box-shadow: none; - padding: 0px ${(props) => props.theme.spaces[12]}px; -`; - -const LogoContainer = styled.div` - svg { - max-width: 160px; - width: 160px; - } -`; - -export function LoginHeader() { - return ( - - - - - - - - ); -} - -const mapStateToProps = (state: AppState) => ({ - user: getCurrentUser(state), -}); - -export default connect(mapStateToProps)(LoginHeader); diff --git a/app/client/src/pages/common/NotFound.tsx b/app/client/src/pages/common/NotFound.tsx deleted file mode 100644 index c28fc29df7f..00000000000 --- a/app/client/src/pages/common/NotFound.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import React from "react"; -import styled from "styled-components"; -import Button from "components/editorComponents/Button"; -import IntegrationUnavailableImage from "assets/images/404-image.png"; - -const Wrapper = styled.div` - text-align: center; - margin-top: 5%; - .bold-text { - font-weight: ${(props) => props.theme.fontWeights[3]}; - font-size: 24px; - } - .unavailable-img { - width: 35%; - } - .button-position { - margin: auto; - } -`; - -interface Props { - title: string; - subtitle?: string; - buttonText: string; - onBackButton: () => void; -} - -function NotFound(props: Props) { - const { buttonText, onBackButton, subtitle, title } = props; - - return ( - - {title -
-

{title}

- {subtitle &&

{subtitle}

} -
-
- ); -} - -export default NotFound; diff --git a/app/client/src/pages/common/PageSectionDivider.tsx b/app/client/src/pages/common/PageSectionDivider.tsx deleted file mode 100644 index eb8ae63a7ff..00000000000 --- a/app/client/src/pages/common/PageSectionDivider.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import styled from "styled-components"; -import { Divider } from "@blueprintjs/core"; - -export default styled(Divider)` - margin: ${(props) => props.theme.spaces[11]}px auto; - width: 100%; -`; diff --git a/app/client/src/pages/common/PaneWrapper.tsx b/app/client/src/pages/common/PaneWrapper.tsx deleted file mode 100644 index ddf006ca734..00000000000 --- a/app/client/src/pages/common/PaneWrapper.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import type { EditorTheme } from "components/editorComponents/CodeEditor/EditorConfig"; -import styled from "styled-components"; - -export default styled.div<{ themeMode?: EditorTheme }>` - background-color: ${(props) => props.theme.colors.propertyPane.bg}; - border-radius: 0px; - border-color: ${(props) => props.theme.colors.propertyPane.bg} !important; - box-shadow: 12px 0px 28px rgba(0, 0, 0, 0.32) !important; - padding: ${(props) => props.theme.spaces[5]}px - ${(props) => props.theme.spaces[7]}px; - color: ${(props) => props.theme.colors.propertyPane.label}; - text-transform: capitalize; -`; diff --git a/app/client/src/pages/routes.tsx b/app/client/src/pages/routes.tsx deleted file mode 100644 index 8169d11cc3a..00000000000 --- a/app/client/src/pages/routes.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import { - DATA_SOURCES_EDITOR_ID_PATH, - DATA_SOURCES_EDITOR_LIST_PATH, -} from "constants/routes"; -import DataSourceEditor from "pages/Editor/DataSourceEditor"; -import DatasourceBlankState from "pages/Editor/DataSourceEditor/DatasourceBlankState"; - -export const DatasourceEditorRoutes = [ - { - path: DATA_SOURCES_EDITOR_ID_PATH, - component: DataSourceEditor, - }, - { - path: DATA_SOURCES_EDITOR_LIST_PATH, - component: DatasourceBlankState, - }, -]; diff --git a/app/client/src/pages/users/list.tsx b/app/client/src/pages/users/list.tsx deleted file mode 100644 index 0dd0dbd4471..00000000000 --- a/app/client/src/pages/users/list.tsx +++ /dev/null @@ -1 +0,0 @@ -export default "list users"; diff --git a/app/client/src/pages/users/view.tsx b/app/client/src/pages/users/view.tsx deleted file mode 100644 index 1d41523f485..00000000000 --- a/app/client/src/pages/users/view.tsx +++ /dev/null @@ -1 +0,0 @@ -export default "view user"; diff --git a/app/client/src/pages/workspace/CreateWorkspaceForm.tsx b/app/client/src/pages/workspace/CreateWorkspaceForm.tsx deleted file mode 100644 index dbd1ee29610..00000000000 --- a/app/client/src/pages/workspace/CreateWorkspaceForm.tsx +++ /dev/null @@ -1,68 +0,0 @@ -import React, { useCallback } from "react"; -import type { InjectedFormProps } from "redux-form"; -import { Form, reduxForm } from "redux-form"; -import { CREATE_WORKSPACE_FORM_NAME } from "ee/constants/forms"; -import type { CreateWorkspaceFormValues } from "ee/pages/workspace/helpers"; -import { createWorkspaceSubmitHandler } from "ee/pages/workspace/helpers"; -import { noSpaces } from "utils/formhelpers"; -import TextField from "components/editorComponents/form/fields/TextField"; -import FormGroup from "components/editorComponents/form/FormGroup"; -import FormFooter from "components/editorComponents/form/FormFooter"; -import FormMessage from "components/editorComponents/form/FormMessage"; - -// TODO(abhinav): abstract onCancel out. -export function CreateApplicationForm( - props: InjectedFormProps< - CreateWorkspaceFormValues, - { onCancel: () => void } - > & { - onCancel: () => void; - }, -) { - const { error, handleSubmit, invalid, onCancel, pristine, submitting } = - props; - const submitHandler = useCallback( - async (data, dispatch) => { - const result = await createWorkspaceSubmitHandler(data, dispatch); - - if (typeof onCancel === "function") onCancel(); // close after submit - - return result; - }, - [handleSubmit, onCancel], - ); - - return ( -
- {error && !pristine && } - - - - - - ); -} - -export default reduxForm void }>({ - form: CREATE_WORKSPACE_FORM_NAME, -})(CreateApplicationForm); diff --git a/app/client/src/pages/workspace/PartnerProgramCallout.tsx b/app/client/src/pages/workspace/PartnerProgramCallout.tsx deleted file mode 100644 index b4c2555ab0c..00000000000 --- a/app/client/src/pages/workspace/PartnerProgramCallout.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import type { CalloutLinkProps } from "@appsmith/ads"; -import { Callout } from "@appsmith/ads"; -import React from "react"; -import { - PARTNER_PROGRAM_CALLOUT, - PARTNER_PROGRAM_CALLOUT_LINK, - createMessage, -} from "ee/constants/messages"; - -interface PartnerProgramCalloutProps { - email: string; - onClose: () => void; -} - -export default function PartnerProgramCallout( - props: PartnerProgramCalloutProps, -) { - const links: CalloutLinkProps[] = [ - { - children: createMessage(PARTNER_PROGRAM_CALLOUT_LINK), - to: "https://www.appsmith.com/partner-program", - endIcon: "share-box-line", - }, - ]; - - return ( - - {createMessage(PARTNER_PROGRAM_CALLOUT, props.email)} - - ); -} diff --git a/app/client/src/pages/workspace/users.tsx b/app/client/src/pages/workspace/users.tsx deleted file mode 100644 index 9f060d4f6f6..00000000000 --- a/app/client/src/pages/workspace/users.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import React from "react"; -import { useHistory } from "react-router-dom"; -import { WORKSPACE_INVITE_USERS_PAGE_URL } from "constants/routes"; -import PageSectionHeader from "pages/common/PageSectionHeader"; -import Button from "components/editorComponents/Button"; - -export function WorkspaceMembers() { - const history = useHistory(); - - return ( - -

Users

- -
- - - - ); -} diff --git a/app/client/src/widgets/TableWidgetV2/component/TableActionIcon.tsx b/app/client/src/widgets/TableWidgetV2/component/TableActionIcon.tsx deleted file mode 100644 index 44f10d7e79d..00000000000 --- a/app/client/src/widgets/TableWidgetV2/component/TableActionIcon.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import React from "react"; -import { Tooltip } from "@blueprintjs/core"; -import { IconWrapper } from "constants/IconConstants"; -import { Colors } from "constants/Colors"; -import { TableIconWrapper } from "./TableStyledWrappers"; - -interface TableActionIconProps { - tooltip: string; - selected: boolean; - selectMenu: (selected: boolean) => void; - className: string; - children: React.ReactNode; - icon?: React.ReactNode; -} - -function TableActionIcon(props: TableActionIconProps) { - return ( - - { - props.selectMenu(!props.selected); - e.stopPropagation(); - }} - selected={props.selected} - > - - {props.children} - - - - ); -} - -export default TableActionIcon; diff --git a/app/client/src/widgets/TableWidgetV2/widget/utilities.ts b/app/client/src/widgets/TableWidgetV2/widget/utilities.ts index 19bb9dcc8b3..20f5d00561e 100644 --- a/app/client/src/widgets/TableWidgetV2/widget/utilities.ts +++ b/app/client/src/widgets/TableWidgetV2/widget/utilities.ts @@ -19,7 +19,6 @@ import { DEFAULT_BUTTON_COLOR, DEFAULT_COLUMN_WIDTH, TABLE_COLUMN_ORDER_KEY, - ORIGINAL_INDEX_KEY, } from "../constants"; import { SelectColumnOptionsValidations } from "./propertyUtils"; import type { TableWidgetProps } from "../constants"; @@ -65,13 +64,7 @@ export const getOriginalRowIndex = ( } if (!!primaryKey && tableData) { - const selectedRow = tableData.find( - (row) => row[primaryColumnId] === primaryKey, - ); - - if (selectedRow) { - index = selectedRow[ORIGINAL_INDEX_KEY] as number; - } + index = tableData.findIndex((row) => row[primaryColumnId] === primaryKey); } return index; diff --git a/app/client/src/widgets/wds/WDSTableWidget/component/cellComponents/AutoToolTipComponent.tsx b/app/client/src/widgets/wds/WDSTableWidget/component/cellComponents/AutoToolTipComponent.tsx deleted file mode 100644 index a624d61dfea..00000000000 --- a/app/client/src/widgets/wds/WDSTableWidget/component/cellComponents/AutoToolTipComponent.tsx +++ /dev/null @@ -1,191 +0,0 @@ -import React, { createRef, useEffect, useState } from "react"; -import { Tooltip } from "@blueprintjs/core"; -import { CellWrapper, TooltipContentWrapper } from "../TableStyledWrappers"; -import type { CellAlignment, VerticalAlignment } from "../Constants"; -import styled from "styled-components"; -import { ColumnTypes } from "widgets/wds/WDSTableWidget/constants"; -import { importSvg } from "@appsmith/ads-old"; - -const OpenNewTabIcon = importSvg( - async () => import("assets/icons/control/open-new-tab.svg"), -); - -export const OpenNewTabIconWrapper = styled.div` - left: 4px; - top: -2px; - position: relative; -`; - -export const ColumnWrapper = styled.div<{ - textColor?: string; -}>` - display: flex; - align-items: center; - height: 100%; - color: ${(props) => props.textColor}; -`; - -export const Content = styled.span` - overflow: hidden; - text-overflow: ellipsis; - width: 100%; -`; - -const WIDTH_OFFSET = 32; -const MAX_WIDTH = 300; -const TOOLTIP_OPEN_DELAY = 500; - -function useToolTip( - children: React.ReactNode, - tableWidth?: number, - title?: string, -) { - const ref = createRef(); - const [requiresTooltip, setRequiresTooltip] = useState(false); - - useEffect(() => { - let timeout: ReturnType; - - const mouseEnterHandler = () => { - const element = ref.current?.querySelector("div") as HTMLDivElement; - - /* - * Using setTimeout to simulate hoverOpenDelay of the tooltip - * during initial render - */ - timeout = setTimeout(() => { - if (element && element.offsetWidth < element.scrollWidth) { - setRequiresTooltip(true); - } else { - setRequiresTooltip(false); - } - - ref.current?.removeEventListener("mouseenter", mouseEnterHandler); - ref.current?.removeEventListener("mouseleave", mouseLeaveHandler); - }, TOOLTIP_OPEN_DELAY); - }; - - const mouseLeaveHandler = () => { - clearTimeout(timeout); - }; - - ref.current?.addEventListener("mouseenter", mouseEnterHandler); - ref.current?.addEventListener("mouseleave", mouseLeaveHandler); - - return () => { - ref.current?.removeEventListener("mouseenter", mouseEnterHandler); - ref.current?.removeEventListener("mouseleave", mouseLeaveHandler); - clearTimeout(timeout); - }; - }, [children]); - - return requiresTooltip && children ? ( - - {title} - - } - defaultIsOpen - hoverOpenDelay={TOOLTIP_OPEN_DELAY} - position="top" - > - { - - {children} - - } - - ) : ( - - {children} - - ); -} - -interface Props { - isHidden?: boolean; - isCellVisible?: boolean; - children: React.ReactNode; - title: string; - tableWidth?: number; - columnType?: string; - className?: string; - compactMode?: string; - allowCellWrapping?: boolean; - horizontalAlignment?: CellAlignment; - verticalAlignment?: VerticalAlignment; - textColor?: string; - fontStyle?: string; - cellBackground?: string; - textSize?: string; - disablePadding?: boolean; - url?: string; - isCellDisabled?: boolean; -} - -function LinkWrapper(props: Props) { - const content = useToolTip(props.children, props.tableWidth, props.title); - - return ( - ) => { - e.stopPropagation(); - window.open(props.url, "_blank"); - }} - textColor={props.textColor} - textSize={props.textSize} - verticalAlignment={props.verticalAlignment} - > -
{content}
- - - -
- ); -} - -function AutoToolTipComponent(props: Props) { - const content = useToolTip(props.children, props.tableWidth, props.title); - - if (props.columnType === ColumnTypes.URL && props.title) { - return ; - } - - return ( - - - {content} - - - ); -} - -export default AutoToolTipComponent; diff --git a/app/client/src/widgets/wds/WDSTableWidget/component/cellComponents/CheckboxCell.tsx b/app/client/src/widgets/wds/WDSTableWidget/component/cellComponents/CheckboxCell.tsx deleted file mode 100644 index 852eda079e2..00000000000 --- a/app/client/src/widgets/wds/WDSTableWidget/component/cellComponents/CheckboxCell.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import React, { memo } from "react"; -import type { BaseCellComponentProps } from "../Constants"; -import { Checkbox } from "@appsmith/wds"; - -type CheckboxCellProps = BaseCellComponentProps & { - value: boolean; - accentColor: string; - isDisabled?: boolean; - onChange: () => void; - borderRadius: string; - hasUnSavedChanges?: boolean; - disabledCheckbox: boolean; - isCellEditable: boolean; - disabledCheckboxMessage: string; -}; - -const CheckboxCellComponent = (props: CheckboxCellProps) => { - const { disabledCheckbox, isCellEditable, onChange, value } = props; - - return ( - onChange()} - /> - ); -}; - -export const CheckboxCell = memo(CheckboxCellComponent); diff --git a/app/client/yarn.lock b/app/client/yarn.lock index cbd1c58cd4b..0c400dbe84f 100644 --- a/app/client/yarn.lock +++ b/app/client/yarn.lock @@ -4892,7 +4892,7 @@ __metadata: languageName: node linkType: hard -"@nodelib/fs.walk@npm:^1.2.3, @nodelib/fs.walk@npm:^1.2.8": +"@nodelib/fs.walk@npm:1.2.8, @nodelib/fs.walk@npm:^1.2.3, @nodelib/fs.walk@npm:^1.2.8": version: 1.2.8 resolution: "@nodelib/fs.walk@npm:1.2.8" dependencies: @@ -9256,6 +9256,19 @@ __metadata: languageName: node linkType: hard +"@snyk/github-codeowners@npm:1.1.0": + version: 1.1.0 + resolution: "@snyk/github-codeowners@npm:1.1.0" + dependencies: + commander: ^4.1.1 + ignore: ^5.1.8 + p-map: ^4.0.0 + bin: + github-codeowners: dist/cli.js + checksum: 133f867fa968f96229ebce724d8aedaa124218e20add96a3a7d39ea45e52007fee50cc90c39e406c9e662483d003da9326e00dc4d612afa5c2ca069d1cdab9d7 + languageName: node + linkType: hard + "@socket.io/component-emitter@npm:~3.1.0": version: 3.1.0 resolution: "@socket.io/component-emitter@npm:3.1.0" @@ -13370,6 +13383,7 @@ __metadata: jshint: ^2.13.4 json5: ^2.2.3 klona: ^2.0.5 + knip: ^5.30.2 konva: 8.0.1 libphonenumber-js: ^1.9.44 linkedom: ^0.14.20 @@ -15790,7 +15804,7 @@ __metadata: languageName: node linkType: hard -"commander@npm:^4.0.0": +"commander@npm:^4.0.0, commander@npm:^4.1.1": version: 4.1.1 resolution: "commander@npm:4.1.1" checksum: d7b9913ff92cae20cb577a4ac6fcc121bd6223319e54a40f51a14740a681ad5c574fd29a57da478a5f234a6fa6c52cbf0b7c641353e03c648b1ae85ba670b977 @@ -17957,6 +17971,19 @@ __metadata: languageName: node linkType: hard +"easy-table@npm:1.2.0": + version: 1.2.0 + resolution: "easy-table@npm:1.2.0" + dependencies: + ansi-regex: ^5.0.1 + wcwidth: ^1.0.1 + dependenciesMeta: + wcwidth: + optional: true + checksum: 66961b19751a68d2d30ce9b74ef750c374cc3112bbcac3d1ed5a939e43c035ecf6b1954098df2d5b05f1e853ab2b67de893794390dcbf0abe1f157fddeb52174 + languageName: node + linkType: hard + "ecc-jsbn@npm:~0.1.1": version: 0.1.2 resolution: "ecc-jsbn@npm:0.1.2" @@ -18192,13 +18219,13 @@ __metadata: languageName: node linkType: hard -"enhanced-resolve@npm:^5.0.0, enhanced-resolve@npm:^5.10.0, enhanced-resolve@npm:^5.7.0": - version: 5.12.0 - resolution: "enhanced-resolve@npm:5.12.0" +"enhanced-resolve@npm:^5.0.0, enhanced-resolve@npm:^5.10.0, enhanced-resolve@npm:^5.17.1, enhanced-resolve@npm:^5.7.0": + version: 5.17.1 + resolution: "enhanced-resolve@npm:5.17.1" dependencies: graceful-fs: ^4.2.4 tapable: ^2.2.0 - checksum: bf3f787facaf4ce3439bef59d148646344e372bef5557f0d37ea8aa02c51f50a925cd1f07b8d338f18992c29f544ec235a8c64bcdb56030196c48832a5494174 + checksum: 4bc38cf1cea96456f97503db7280394177d1bc46f8f87c267297d04f795ac5efa81e48115a2f5b6273c781027b5b6bfc5f62b54df629e4d25fa7001a86624f59 languageName: node linkType: hard @@ -21500,10 +21527,10 @@ __metadata: languageName: node linkType: hard -"ignore@npm:^5.2.0, ignore@npm:^5.2.4": - version: 5.2.4 - resolution: "ignore@npm:5.2.4" - checksum: 3d4c309c6006e2621659311783eaea7ebcd41fe4ca1d78c91c473157ad6666a57a2df790fe0d07a12300d9aac2888204d7be8d59f9aaf665b1c7fcdb432517ef +"ignore@npm:^5.1.8, ignore@npm:^5.2.0, ignore@npm:^5.2.4": + version: 5.3.2 + resolution: "ignore@npm:5.3.2" + checksum: 2acfd32a573260ea522ea0bfeff880af426d68f6831f973129e2ba7363f422923cf53aab62f8369cbf4667c7b25b6f8a3761b34ecdb284ea18e87a5262a865be languageName: node linkType: hard @@ -23765,12 +23792,12 @@ __metadata: languageName: node linkType: hard -"jiti@npm:^1.18.2": - version: 1.19.3 - resolution: "jiti@npm:1.19.3" +"jiti@npm:^1.18.2, jiti@npm:^1.21.6": + version: 1.21.6 + resolution: "jiti@npm:1.21.6" bin: jiti: bin/jiti.js - checksum: de3dacdfe30948d96b69712b04cc28127c17f43d5233a5aa069933e04ac4c9aaf265bef4cdf2b0c2a6f5af236a58aea9bfea83e8e289e2490802bdff7f99bff7 + checksum: 9ea4a70a7bb950794824683ed1c632e2ede26949fbd348e2ba5ec8dc5efa54dc42022d85ae229cadaa60d4b95012e80ea07d625797199b688cc22ab0e8891d32 languageName: node linkType: hard @@ -24169,6 +24196,36 @@ __metadata: languageName: node linkType: hard +"knip@npm:^5.30.2": + version: 5.30.2 + resolution: "knip@npm:5.30.2" + dependencies: + "@nodelib/fs.walk": 1.2.8 + "@snyk/github-codeowners": 1.1.0 + easy-table: 1.2.0 + enhanced-resolve: ^5.17.1 + fast-glob: ^3.3.2 + jiti: ^1.21.6 + js-yaml: ^4.1.0 + minimist: ^1.2.8 + picocolors: ^1.0.0 + picomatch: ^4.0.1 + pretty-ms: ^9.0.0 + smol-toml: ^1.1.4 + strip-json-comments: 5.0.1 + summary: 2.1.0 + zod: ^3.22.4 + zod-validation-error: ^3.0.3 + peerDependencies: + "@types/node": ">=18" + typescript: ">=5.0.4" + bin: + knip: bin/knip.js + knip-bun: bin/knip-bun.js + checksum: fafb6ee078c1e9f24e83c08c6b97c7ad82ef78d043eff6a064639e08354a4b81cbb132d705acc53874d0f0d02dc690d960f75efe8783ac349fde491bcbf1b742 + languageName: node + linkType: hard + "konva@npm:8.0.1": version: 8.0.1 resolution: "konva@npm:8.0.1" @@ -26976,6 +27033,13 @@ __metadata: languageName: node linkType: hard +"parse-ms@npm:^4.0.0": + version: 4.0.0 + resolution: "parse-ms@npm:4.0.0" + checksum: 673c801d9f957ff79962d71ed5a24850163f4181a90dd30c4e3666b3a804f53b77f1f0556792e8b2adbb5d58757907d1aa51d7d7dc75997c2a56d72937cbc8b7 + languageName: node + linkType: hard + "parse-passwd@npm:^1.0.0": version: 1.0.0 resolution: "parse-passwd@npm:1.0.0" @@ -27286,6 +27350,13 @@ __metadata: languageName: node linkType: hard +"picomatch@npm:^4.0.1": + version: 4.0.2 + resolution: "picomatch@npm:4.0.2" + checksum: a7a5188c954f82c6585720e9143297ccd0e35ad8072231608086ca950bee672d51b0ef676254af0788205e59bd4e4deb4e7708769226bed725bf13370a7d1464 + languageName: node + linkType: hard + "pidtree@npm:0.6.0": version: 0.6.0 resolution: "pidtree@npm:0.6.0" @@ -28818,6 +28889,15 @@ __metadata: languageName: node linkType: hard +"pretty-ms@npm:^9.0.0": + version: 9.1.0 + resolution: "pretty-ms@npm:9.1.0" + dependencies: + parse-ms: ^4.0.0 + checksum: 0f66507467f2005040cccdcb36f35b82674d7809f41c4432009235ed6c920787afa17f621c25b7ccb8ccd80b0840c7b71f7f4a3addb8f0eeef3a033ff1e5cf71 + languageName: node + linkType: hard + "prismjs@npm:^1.27.0, prismjs@npm:~1.27.0": version: 1.27.0 resolution: "prismjs@npm:1.27.0" @@ -32314,6 +32394,13 @@ __metadata: languageName: node linkType: hard +"smol-toml@npm:^1.1.4": + version: 1.3.0 + resolution: "smol-toml@npm:1.3.0" + checksum: 79e1db6b6cd32a13ad7602bfe1a02f20894fe599657a5cc2c8ffab7c3de4ba51f7426b701b513f9b859560918b36a63f7c73f7eaf6def8a1dc73db74ffd9b601 + languageName: node + linkType: hard + "snake-case@npm:^3.0.4": version: 3.0.4 resolution: "snake-case@npm:3.0.4" @@ -33113,6 +33200,13 @@ __metadata: languageName: node linkType: hard +"strip-json-comments@npm:5.0.1": + version: 5.0.1 + resolution: "strip-json-comments@npm:5.0.1" + checksum: b314af70c6666a71133e309a571bdb87687fc878d9fd8b38ebed393a77b89835b92f191aa6b0bc10dfd028ba99eed6b6365985001d64c5aef32a4a82456a156b + languageName: node + linkType: hard + "strip-json-comments@npm:^3.0.1, strip-json-comments@npm:^3.1.1": version: 3.1.1 resolution: "strip-json-comments@npm:3.1.1" @@ -33223,6 +33317,13 @@ __metadata: languageName: node linkType: hard +"summary@npm:2.1.0": + version: 2.1.0 + resolution: "summary@npm:2.1.0" + checksum: 10ac12ce12c013b56ad44c37cfac206961f0993d98867b33b1b03a27b38a1cf8dd2db0b788883356c5335bbbb37d953772ef4a381d6fc8f408faf99f2bc54af5 + languageName: node + linkType: hard + "superagent@npm:^8.0.5": version: 8.0.9 resolution: "superagent@npm:8.0.9" @@ -36367,6 +36468,22 @@ __metadata: languageName: node linkType: hard +"zod-validation-error@npm:^3.0.3": + version: 3.4.0 + resolution: "zod-validation-error@npm:3.4.0" + peerDependencies: + zod: ^3.18.0 + checksum: b07fbfc39582dbdf6972f5f5f0c3bac9e6b5e6d2e55ef3dd891fd08f1966ebf1023a4bc270e9b569eaa48ed1684ac2252c9f260b0bd07b167671596e6e4d0fa8 + languageName: node + linkType: hard + +"zod@npm:^3.22.4": + version: 3.23.8 + resolution: "zod@npm:3.23.8" + checksum: 15949ff82118f59c893dacd9d3c766d02b6fa2e71cf474d5aa888570c469dbf5446ac5ad562bb035bf7ac9650da94f290655c194f4a6de3e766f43febd432c5c + languageName: node + linkType: hard + "zone.js@npm:^0.11.0 || ^0.12.0 || ^0.13.0 || ^0.14.0": version: 0.14.8 resolution: "zone.js@npm:0.14.8" diff --git a/app/server/appsmith-plugins/mssqlPlugin/src/test/java/com/external/plugins/MssqlGetDBSchemaTest.java b/app/server/appsmith-plugins/mssqlPlugin/src/test/java/com/external/plugins/MssqlGetDBSchemaTest.java index 4434a3a1c3f..062fc5aa52d 100644 --- a/app/server/appsmith-plugins/mssqlPlugin/src/test/java/com/external/plugins/MssqlGetDBSchemaTest.java +++ b/app/server/appsmith-plugins/mssqlPlugin/src/test/java/com/external/plugins/MssqlGetDBSchemaTest.java @@ -3,6 +3,7 @@ import com.appsmith.external.models.DatasourceStructure; import com.zaxxer.hikari.HikariDataSource; import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.testcontainers.containers.MSSQLServerContainer; import org.testcontainers.junit.jupiter.Container; @@ -22,6 +23,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; @Testcontainers +@Disabled public class MssqlGetDBSchemaTest { public static final String SQL_QUERY_TO_CREATE_TABLE_WITH_PRIMARY_KEY = "CREATE TABLE supplier\n" + "( supplier_id int not null,\n" diff --git a/app/server/appsmith-plugins/mssqlPlugin/src/test/java/com/external/plugins/MssqlPluginTest.java b/app/server/appsmith-plugins/mssqlPlugin/src/test/java/com/external/plugins/MssqlPluginTest.java index 7be16681867..60abcc3161d 100755 --- a/app/server/appsmith-plugins/mssqlPlugin/src/test/java/com/external/plugins/MssqlPluginTest.java +++ b/app/server/appsmith-plugins/mssqlPlugin/src/test/java/com/external/plugins/MssqlPluginTest.java @@ -23,6 +23,7 @@ import com.zaxxer.hikari.HikariDataSource; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.testcontainers.containers.MSSQLServerContainer; import org.testcontainers.junit.jupiter.Container; @@ -54,6 +55,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; @Testcontainers +@Disabled public class MssqlPluginTest { @SuppressWarnings("rawtypes") // The type parameter for the container type is just itself and is pseudo-optional. diff --git a/app/server/appsmith-plugins/redisPlugin/src/test/java/com/external/plugins/RedisPluginTest.java b/app/server/appsmith-plugins/redisPlugin/src/test/java/com/external/plugins/RedisPluginTest.java index 9cbfbef3716..962e008ae4d 100644 --- a/app/server/appsmith-plugins/redisPlugin/src/test/java/com/external/plugins/RedisPluginTest.java +++ b/app/server/appsmith-plugins/redisPlugin/src/test/java/com/external/plugins/RedisPluginTest.java @@ -15,6 +15,7 @@ import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.testcontainers.containers.GenericContainer; import org.testcontainers.junit.jupiter.Container; @@ -39,6 +40,7 @@ @Slf4j @Testcontainers +@Disabled public class RedisPluginTest { @Container public static final GenericContainer redis = diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/applications/imports/ApplicationImportServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/applications/imports/ApplicationImportServiceCEImpl.java index e00e3db1195..3d0703c8258 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/applications/imports/ApplicationImportServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/applications/imports/ApplicationImportServiceCEImpl.java @@ -27,6 +27,7 @@ import com.appsmith.server.imports.internal.artifactbased.ArtifactBasedImportServiceCE; import com.appsmith.server.layouts.UpdateLayoutService; import com.appsmith.server.migrations.ApplicationVersion; +import com.appsmith.server.migrations.JsonSchemaMigration; import com.appsmith.server.newactions.base.NewActionService; import com.appsmith.server.services.ApplicationPageService; import com.appsmith.server.solutions.ActionPermission; @@ -53,6 +54,7 @@ import static com.appsmith.server.helpers.ImportExportUtils.setPropertiesToExistingApplication; import static com.appsmith.server.helpers.ImportExportUtils.setPublishedApplicationProperties; +import static org.springframework.util.StringUtils.hasText; @RequiredArgsConstructor @Slf4j @@ -69,6 +71,7 @@ public class ApplicationImportServiceCEImpl private final ApplicationPermission applicationPermission; private final PagePermission pagePermission; private final ActionPermission actionPermission; + private final JsonSchemaMigration jsonSchemaMigration; private final ImportableService themeImportableService; private final ImportableService newPageImportableService; private final ImportableService customJSLibImportableService; @@ -639,4 +642,26 @@ public Mono> getDatasourceIdSetConsumedInArtifact(String baseArtifac public Flux getBranchedArtifactIdsByBranchedArtifactId(String branchedArtifactId) { return applicationService.findAllBranchedApplicationIdsByBranchedApplicationId(branchedArtifactId, null); } + + @Override + public Mono migrateArtifactExchangeJson( + String branchedArtifactId, ArtifactExchangeJson artifactExchangeJson) { + ApplicationJson applicationJson = (ApplicationJson) artifactExchangeJson; + + if (!hasText(branchedArtifactId)) { + return jsonSchemaMigration.migrateApplicationJsonToLatestSchema(applicationJson, null, null); + } + + return applicationService.findById(branchedArtifactId).flatMap(application -> { + String baseArtifactId = application.getBaseId(); + String branchName = null; + + if (application.getGitArtifactMetadata() != null) { + branchName = application.getGitArtifactMetadata().getBranchName(); + } + + return jsonSchemaMigration.migrateApplicationJsonToLatestSchema( + applicationJson, baseArtifactId, branchName); + }); + } } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/applications/imports/ApplicationImportServiceImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/applications/imports/ApplicationImportServiceImpl.java index e86f89d66e0..fa5fe049b31 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/applications/imports/ApplicationImportServiceImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/applications/imports/ApplicationImportServiceImpl.java @@ -12,6 +12,7 @@ import com.appsmith.server.imports.importable.ImportableService; import com.appsmith.server.imports.internal.artifactbased.ArtifactBasedImportService; import com.appsmith.server.layouts.UpdateLayoutService; +import com.appsmith.server.migrations.JsonSchemaMigration; import com.appsmith.server.newactions.base.NewActionService; import com.appsmith.server.services.ApplicationPageService; import com.appsmith.server.solutions.ActionPermission; @@ -35,6 +36,7 @@ public ApplicationImportServiceImpl( ApplicationPermission applicationPermission, PagePermission pagePermission, ActionPermission actionPermission, + JsonSchemaMigration jsonSchemaMigration, ImportableService themeImportableService, ImportableService newPageImportableService, ImportableService customJSLibImportableService, @@ -50,6 +52,7 @@ public ApplicationImportServiceImpl( applicationPermission, pagePermission, actionPermission, + jsonSchemaMigration, themeImportableService, newPageImportableService, customJSLibImportableService, diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/imports/internal/ImportServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/imports/internal/ImportServiceCEImpl.java index 0f3c5095fe6..e409f047288 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/imports/internal/ImportServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/imports/internal/ImportServiceCEImpl.java @@ -411,23 +411,32 @@ private Mono importArtifactInWorkspace( String artifactContextString = artifactSpecificConstantsMap.get(FieldName.ARTIFACT_CONTEXT); // step 1: Schema Migration - ArtifactExchangeJson importedDoc = jsonSchemaMigration.migrateArtifactToLatestSchema(artifactExchangeJson); - - // Step 2: Validation of artifact Json - // check for validation error and raise exception if error found - String errorField = validateArtifactExchangeJson(importedDoc); - if (!errorField.isEmpty()) { - log.error("Error in importing {}. Field {} is missing", artifactContextString, errorField); - if (errorField.equals(artifactContextString)) { - return Mono.error( - new AppsmithException( + Mono migratedArtifactJsonMono = artifactBasedImportService + .migrateArtifactExchangeJson(branchedArtifactId, artifactExchangeJson) + .flatMap(importedDoc -> { + // Step 2: Validation of artifact Json + // check for validation error and raise exception if error found + String errorField = validateArtifactExchangeJson(importedDoc); + if (!errorField.isEmpty()) { + log.error("Error in importing {}. Field {} is missing", artifactContextString, errorField); + + if (errorField.equals(artifactContextString)) { + return Mono.error( + new AppsmithException( + AppsmithError.VALIDATION_FAILURE, + "Field '" + artifactContextString + + "'. Sorry! It seems you've imported a page-level JSON instead of an application. Please use the import within the page.")); + } + + return Mono.error(new AppsmithException( AppsmithError.VALIDATION_FAILURE, - "Field '" + artifactContextString - + "' Sorry! Seems like you've imported a page-level json instead of an application. Please use the import within the page.")); - } - return Mono.error(new AppsmithException( - AppsmithError.VALIDATION_FAILURE, "Field '" + errorField + "' is missing in the JSON.")); - } + "Field '" + errorField + "' is missing in the JSON.")); + } + + artifactBasedImportService.syncClientAndSchemaVersion(importedDoc); + return Mono.just(importedDoc); + }) + .cache(); ImportingMetaDTO importingMetaDTO = new ImportingMetaDTO( workspaceId, @@ -441,7 +450,6 @@ private Mono importArtifactInWorkspace( permissionGroups); MappedImportableResourcesDTO mappedImportableResourcesDTO = new MappedImportableResourcesDTO(); - artifactBasedImportService.syncClientAndSchemaVersion(importedDoc); Mono workspaceMono = workspaceService .findById(workspaceId, permissionProvider.getRequiredPermissionOnTargetWorkspace()) @@ -469,56 +477,63 @@ private Mono importArtifactInWorkspace( .switchIfEmpty(Mono.just(List.of())) .doOnNext(importingMetaDTO::setBranchedArtifactIds); - // this would import customJsLibs for all type of artifacts - Mono artifactSpecificImportableEntities = - artifactBasedImportService.generateArtifactSpecificImportableEntities( - importedDoc, importingMetaDTO, mappedImportableResourcesDTO); - - /* - Calling the workspaceMono first to avoid creating multiple mongo transactions. - If the first db call inside a transaction is a Flux, then there's a chance of creating multiple mongo - transactions which will lead to NoSuchTransaction exception. - */ - final Mono importableArtifactMono = workspaceMono - .then(Mono.defer(() -> Mono.when(branchedArtifactIdsMono, artifactSpecificImportableEntities))) - .then(Mono.defer(() -> artifactBasedImportService.updateAndSaveArtifactInContext( - importedDoc.getArtifact(), importingMetaDTO, mappedImportableResourcesDTO, currUserMono))) - .cache(); - - final Mono importMono = importableArtifactMono - .then(Mono.defer(() -> generateImportableEntities( - importingMetaDTO, - mappedImportableResourcesDTO, - workspaceMono, - importableArtifactMono, - importedDoc))) - .then(importableArtifactMono) - .flatMap(importableArtifact -> updateImportableEntities( - artifactBasedImportService, importableArtifact, mappedImportableResourcesDTO, importingMetaDTO)) - .flatMap(importableArtifact -> updateImportableArtifact(artifactBasedImportService, importableArtifact)) - .onErrorResume(throwable -> { - String errorMessage = ImportExportUtils.getErrorMessage(throwable); - log.error("Error importing {}. Error: {}", artifactContextString, errorMessage, throwable); - return Mono.error( - new AppsmithException(AppsmithError.GENERIC_JSON_IMPORT_ERROR, workspaceId, errorMessage)); - }) - // execute dry run for datasource - .flatMap(importableArtifact -> dryOperationRepository - .executeAllDbOps(mappedImportableResourcesDTO) - .thenReturn(importableArtifact)) - .as(transactionalOperator::transactional); - - final Mono resultMono = importMono - .flatMap(importableArtifact -> sendImportedContextAnalyticsEvent( - artifactBasedImportService, importableArtifact, AnalyticsEvents.IMPORT)) - .zipWith(currUserMono) - .flatMap(tuple -> { - Artifact importableArtifact = tuple.getT1(); - User user = tuple.getT2(); - stopwatch.stopTimer(); - stopwatch.stopAndLogTimeInMillis(); - return sendImportRelatedAnalyticsEvent(importedDoc, importableArtifact, stopwatch, user); - }); + final Mono resultMono = migratedArtifactJsonMono.flatMap(importedDoc -> { + + // this would import customJsLibs for all type of artifacts + Mono artifactSpecificImportableEntities = + artifactBasedImportService.generateArtifactSpecificImportableEntities( + importedDoc, importingMetaDTO, mappedImportableResourcesDTO); + + /* + Calling the workspaceMono first to avoid creating multiple mongo transactions. + If the first db call inside a transaction is a Flux, then there's a chance of creating multiple mongo + transactions which will lead to NoSuchTransaction exception. + */ + final Mono importableArtifactMono = workspaceMono + .then(Mono.defer(() -> Mono.when(branchedArtifactIdsMono, artifactSpecificImportableEntities))) + .then(Mono.defer(() -> artifactBasedImportService.updateAndSaveArtifactInContext( + importedDoc.getArtifact(), importingMetaDTO, mappedImportableResourcesDTO, currUserMono))) + .cache(); + + final Mono importMono = importableArtifactMono + .then(Mono.defer(() -> generateImportableEntities( + importingMetaDTO, + mappedImportableResourcesDTO, + workspaceMono, + importableArtifactMono, + importedDoc))) + .then(importableArtifactMono) + .flatMap(importableArtifact -> updateImportableEntities( + artifactBasedImportService, + importableArtifact, + mappedImportableResourcesDTO, + importingMetaDTO)) + .flatMap(importableArtifact -> + updateImportableArtifact(artifactBasedImportService, importableArtifact)) + .onErrorResume(throwable -> { + String errorMessage = ImportExportUtils.getErrorMessage(throwable); + log.error("Error importing {}. Error: {}", artifactContextString, errorMessage, throwable); + return Mono.error(new AppsmithException( + AppsmithError.GENERIC_JSON_IMPORT_ERROR, workspaceId, errorMessage)); + }) + // execute dry run for datasource + .flatMap(importableArtifact -> dryOperationRepository + .executeAllDbOps(mappedImportableResourcesDTO) + .thenReturn(importableArtifact)) + .as(transactionalOperator::transactional); + + return importMono + .flatMap(importableArtifact -> sendImportedContextAnalyticsEvent( + artifactBasedImportService, importableArtifact, AnalyticsEvents.IMPORT)) + .zipWith(currUserMono) + .flatMap(tuple -> { + Artifact importableArtifact = tuple.getT1(); + User user = tuple.getT2(); + stopwatch.stopTimer(); + stopwatch.stopAndLogTimeInMillis(); + return sendImportRelatedAnalyticsEvent(importedDoc, importableArtifact, stopwatch, user); + }); + }); // Import Context is currently a slow API because it needs to import and create context, pages, actions // and action collection. This process may take time and the client may cancel the request. This leads to the diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/imports/internal/artifactbased/ArtifactBasedImportServiceCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/imports/internal/artifactbased/ArtifactBasedImportServiceCE.java index 7dfd1560c6d..7fd0e80d67b 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/imports/internal/artifactbased/ArtifactBasedImportServiceCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/imports/internal/artifactbased/ArtifactBasedImportServiceCE.java @@ -153,4 +153,6 @@ Mono generateArtifactSpecificImportableEntities( Mono> getDatasourceIdSetConsumedInArtifact(String baseArtifactId); Flux getBranchedArtifactIdsByBranchedArtifactId(String branchedArtifactId); + + Mono migrateArtifactExchangeJson(String branchedArtifactId, ArtifactExchangeJson artifactExchangeJson); } 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 badec22d19e..df6caf59bb1 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 @@ -12,8 +12,6 @@ import org.springframework.stereotype.Component; import reactor.core.publisher.Mono; -import java.util.Map; - @Slf4j @Component @RequiredArgsConstructor @@ -37,15 +35,21 @@ private Integer getCorrectSchemaVersion(Integer schemaVersion) { } /** - * This method migrates the server schema of artifactExchangeJson after choosing the right method for migration - * this will likely be overridden in EE codebase for more choices - * @param artifactExchangeJson artifactExchangeJson which is imported + * Migrates the server schema of the given ArtifactExchangeJson by selecting the appropriate migration method. + * This method may be overridden in the EE codebase for additional migration choices. + * + * @param artifactExchangeJson The artifact to be imported. + * @param baseArtifactId The base application ID to which it's being imported, + * if it's a Git-connected artifact; otherwise, null. + * @param branchName The branch name of the artifact being imported, + * if it's a Git-connected application; otherwise, null. */ public Mono migrateArtifactExchangeJsonToLatestSchema( - ArtifactExchangeJson artifactExchangeJson) { + ArtifactExchangeJson artifactExchangeJson, String baseArtifactId, String branchName) { if (ArtifactType.APPLICATION.equals(artifactExchangeJson.getArtifactJsonType())) { - return migrateApplicationJsonToLatestSchema((ApplicationJson) artifactExchangeJson, null, null); + return migrateApplicationJsonToLatestSchema( + (ApplicationJson) artifactExchangeJson, baseArtifactId, branchName); } return Mono.fromCallable(() -> artifactExchangeJson); @@ -62,82 +66,28 @@ public Mono migrateApplicationJsonToLatestSchema( return Mono.empty(); } - // 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 -> { - // In Server version 9, there was a bug where the Embedded REST API datasource URL - // was not being persisted correctly. Once the bug was fixed, - // any previously uncommitted changes started appearing as uncommitted modifications - // in the apps. To automatically commit these changes - // (which were now appearing as uncommitted), a migration process was needed. - // This migration fetches the datasource URL from the database - // and serializes it in Git if the URL exists. - // If the URL is missing, it copies the empty datasource configuration - // if the configuration is present in the database. - // Otherwise, it leaves the configuration unchanged. - // Due to an update in the migration logic after version 10 was shipped, - // the entire migration process was moved to version 11. - // This adjustment ensures that the same operation can be - // performed again for the changes introduced in version 10. - if (migratedApplicationJson.getServerSchemaVersion() == 9) { - migratedApplicationJson.setServerSchemaVersion(10); - } - - if (migratedApplicationJson.getServerSchemaVersion() == 10) { - if (Boolean.TRUE.equals(MigrationHelperMethods.doesRestApiRequireMigration( - migratedApplicationJson))) { - return jsonSchemaMigrationHelper - .addDatasourceConfigurationToDefaultRestApiActions( - baseApplicationId, branchName, migratedApplicationJson); - } - - migratedApplicationJson.setServerSchemaVersion(11); - } - - return Mono.just(migratedApplicationJson); - }) - .map(migratedAppJson -> { - applicationJson.setServerSchemaVersion(jsonSchemaVersions.getServerVersion()); - return applicationJson; - }); + return migrateServerSchema(applicationJson, baseApplicationId, branchName); }) .switchIfEmpty(Mono.error(new AppsmithException(AppsmithError.INCOMPATIBLE_IMPORTED_JSON))); } - /** - * migrate artifacts to latest schema by adding the right DTOs, or any migration. - * This method would be deprecated soon enough - * @param artifactExchangeJson : the json to be imported - * @return transformed artifact exchange json - */ - @Deprecated(forRemoval = true, since = "Use migrateArtifactJsonToLatestSchema") - public ArtifactExchangeJson migrateArtifactToLatestSchema(ArtifactExchangeJson artifactExchangeJson) { - - if (!ArtifactType.APPLICATION.equals(artifactExchangeJson.getArtifactJsonType())) { - return artifactExchangeJson; - } - - ApplicationJson applicationJson = (ApplicationJson) artifactExchangeJson; - setSchemaVersions(applicationJson); - if (!isCompatible(applicationJson)) { - throw new AppsmithException(AppsmithError.INCOMPATIBLE_IMPORTED_JSON); - } - - applicationJson = migrateServerSchema(applicationJson); - return nonReactiveServerMigrationForImport(applicationJson); - } - /** * This method may be moved to the publisher chain itself - * @param applicationJson : applicationJson which needs to be transformed + * + * @param applicationJson : applicationJson which needs to be transformed + * @param baseApplicationId : baseApplicationId of the application to which it's being imported, + * if it's a git connected artifact, otherwise a null value would be passed. + * @param branchName : branch name of the artifact for which application json is getting imported + * if it's a git connected application. Otherwise, the value would be null * @return : transformed applicationJson */ - private ApplicationJson migrateServerSchema(ApplicationJson applicationJson) { + private Mono migrateServerSchema( + ApplicationJson applicationJson, String baseApplicationId, String branchName) { + Mono migrateApplicationJsonMono = Mono.just(applicationJson); + if (jsonSchemaVersions.getServerVersion().equals(applicationJson.getServerSchemaVersion())) { // No need to run server side migration - return applicationJson; + return migrateApplicationJsonMono; } // Run migration linearly // Updating the schema version after each migration is not required as we are not exiting by breaking the switch @@ -180,38 +130,33 @@ private ApplicationJson migrateServerSchema(ApplicationJson applicationJson) { 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()) { + // In Server version 9, there was a bug where the Embedded REST API datasource URL + // was not being persisted correctly. Once the bug was fixed, + // any previously uncommitted changes started appearing as uncommitted modifications + // in the apps. To automatically commit these changes + // (which were now appearing as uncommitted), a migration process was needed. + // This migration fetches the datasource URL from the database + // and serializes it in Git if the URL exists. + // If the URL is missing, it copies the empty datasource configuration + // if the configuration is present in the database. + // Otherwise, it leaves the configuration unchanged. + // Due to an update in the migration logic after version 10 was shipped, + // the entire migration process was moved to version 11. + // This adjustment ensures that the same operation can be + // performed again for the changes introduced in version 10. case 9: applicationJson.setServerSchemaVersion(10); case 10: - // this if for cases where we have empty datasource configs - MigrationHelperMethods.migrateApplicationJsonToVersionTen(applicationJson, Map.of()); + if (Boolean.TRUE.equals(MigrationHelperMethods.doesRestApiRequireMigration(applicationJson))) { + migrateApplicationJsonMono = migrateApplicationJsonMono.flatMap( + migratedJson -> jsonSchemaMigrationHelper.addDatasourceConfigurationToDefaultRestApiActions( + baseApplicationId, branchName, migratedJson)); + } applicationJson.setServerSchemaVersion(11); default: } applicationJson.setServerSchemaVersion(jsonSchemaVersions.getServerVersion()); - return applicationJson; + return migrateApplicationJsonMono; } } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ce/CreateDBTablePageSolutionCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ce/CreateDBTablePageSolutionCEImpl.java index 6f26851a12a..00dba526a9c 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ce/CreateDBTablePageSolutionCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ce/CreateDBTablePageSolutionCEImpl.java @@ -57,6 +57,7 @@ import org.springframework.util.StreamUtils; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; +import reactor.core.scheduler.Schedulers; import java.io.IOException; import java.nio.charset.Charset; @@ -236,28 +237,38 @@ public Mono createPageFromDBTable( .switchIfEmpty(Mono.error( new AppsmithException(AppsmithError.INVALID_DATASOURCE, FieldName.DATASOURCE, datasourceId))); + // Should this be subscribed on a scheduler? + Mono applicationJsonMono = Mono.fromCallable(() -> { + ApplicationJson applicationJson = new ApplicationJson(); + try { + AppsmithBeanUtils.copyNestedNonNullProperties( + fetchTemplateApplication(FILE_PATH), applicationJson); + } catch (IOException e) { + log.error(e.getMessage()); + } + + return applicationJson; + }) + .subscribeOn(Schedulers.boundedElastic()) + .flatMap(applicationJson -> + jsonSchemaMigration.migrateApplicationJsonToLatestSchema(applicationJson, null, null)); + return datasourceStorageMono .zipWhen(datasourceStorage -> Mono.zip( pageMono, pluginService.findById(datasourceStorage.getPluginId()), - datasourceStructureSolution.getStructure(datasourceStorage, false))) + datasourceStructureSolution.getStructure(datasourceStorage, false), + applicationJsonMono)) .flatMap(tuple -> { DatasourceStorage datasourceStorage = tuple.getT1(); NewPage page = tuple.getT2().getT1(); Plugin plugin = tuple.getT2().getT2(); DatasourceStructure datasourceStructure = tuple.getT2().getT3(); + ApplicationJson applicationJson = tuple.getT2().getT4(); final String layoutId = page.getUnpublishedPage().getLayouts().get(0).getId(); final String savedPageId = page.getId(); - - ApplicationJson applicationJson = new ApplicationJson(); - try { - AppsmithBeanUtils.copyNestedNonNullProperties( - fetchTemplateApplication(FILE_PATH), applicationJson); - } catch (IOException e) { - log.error(e.getMessage()); - } List pageList = applicationJson.getPageList(); if (pageList.isEmpty()) { @@ -558,8 +569,7 @@ private ApplicationJson fetchTemplateApplication(String filePath) throws IOExcep final String jsonContent = StreamUtils.copyToString( new DefaultResourceLoader().getResource(filePath).getInputStream(), Charset.defaultCharset()); - ApplicationJson applicationJson = gson.fromJson(jsonContent, ApplicationJson.class); - return (ApplicationJson) jsonSchemaMigration.migrateArtifactToLatestSchema(applicationJson); + return gson.fromJson(jsonContent, ApplicationJson.class); } /** diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/git/CommonGitServiceCETest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/git/CommonGitServiceCETest.java index 570f86e28bd..31d88eaa56b 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/git/CommonGitServiceCETest.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/git/CommonGitServiceCETest.java @@ -291,7 +291,8 @@ private Mono createAppJson(String filePath) { return stringifiedFile .map(data -> gson.fromJson(data, ApplicationJson.class)) - .map(jsonSchemaMigration::migrateArtifactToLatestSchema) + .flatMap(applicationJson -> + jsonSchemaMigration.migrateArtifactExchangeJsonToLatestSchema(applicationJson, null, null)) .map(artifactExchangeJson -> (ApplicationJson) artifactExchangeJson); } diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/git/gac/DefaultBranchGACTest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/git/gac/DefaultBranchGACTest.java deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/git/gac/GitServiceWithRBACTest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/git/gac/GitServiceWithRBACTest.java deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/helpers/GitFileUtilsTest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/helpers/GitFileUtilsTest.java index ed04d083717..c9486d45314 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/helpers/GitFileUtilsTest.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/helpers/GitFileUtilsTest.java @@ -84,7 +84,8 @@ private Mono createAppJson(String filePath) { .map(data -> { return gson.fromJson(data, ApplicationJson.class); }) - .map(jsonSchemaMigration::migrateArtifactToLatestSchema) + .flatMap(applicationJson -> + jsonSchemaMigration.migrateArtifactExchangeJsonToLatestSchema(applicationJson, null, null)) .map(artifactExchangeJson -> (ApplicationJson) artifactExchangeJson); } diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/imports/internal/ImportServiceTests.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/imports/internal/ImportServiceTests.java index efb637ff658..8a742fa911d 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/imports/internal/ImportServiceTests.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/imports/internal/ImportServiceTests.java @@ -357,7 +357,8 @@ private Mono createAppJson(String filePath) { .map(data -> { return gson.fromJson(data, ApplicationJson.class); }) - .map(jsonSchemaMigration::migrateArtifactToLatestSchema) + .flatMap(applicationJson -> + jsonSchemaMigration.migrateArtifactExchangeJsonToLatestSchema(applicationJson, null, null)) .map(artifactExchangeJson -> (ApplicationJson) artifactExchangeJson); } @@ -2718,11 +2719,13 @@ public void applySchemaMigration_jsonFileWithFirstVersion_migratedToLatestVersio }) .cache(); - Mono migratedApplicationMono = v1ApplicationMono.map(applicationJson -> { - ApplicationJson applicationJson1 = new ApplicationJson(); - AppsmithBeanUtils.copyNestedNonNullProperties(applicationJson, applicationJson1); - return (ApplicationJson) jsonSchemaMigration.migrateArtifactToLatestSchema(applicationJson1); - }); + Mono migratedApplicationMono = v1ApplicationMono + .flatMap(applicationJson -> { + ApplicationJson applicationJson1 = new ApplicationJson(); + AppsmithBeanUtils.copyNestedNonNullProperties(applicationJson, applicationJson1); + return jsonSchemaMigration.migrateArtifactExchangeJsonToLatestSchema(applicationJson1, null, null); + }) + .map(applicationJson -> (ApplicationJson) applicationJson); StepVerifier.create(Mono.zip(v1ApplicationMono, migratedApplicationMono)) .assertNext(tuple -> { 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 dff2b338daf..1a08d854560 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 @@ -38,7 +38,9 @@ public void migrateArtifactToLatestSchema_whenFeatureFlagIsOn_returnsIncremented ApplicationJson applicationJson = gitFileSystemTestHelper.getApplicationJson(this.getClass().getResource("application.json")); - ArtifactExchangeJson artifactExchangeJson = jsonSchemaMigration.migrateArtifactToLatestSchema(applicationJson); + ArtifactExchangeJson artifactExchangeJson = jsonSchemaMigration + .migrateArtifactExchangeJsonToLatestSchema(applicationJson, null, null) + .block(); assertThat(artifactExchangeJson.getServerSchemaVersion()).isEqualTo(jsonSchemaVersions.getServerVersion()); assertThat(artifactExchangeJson.getClientSchemaVersion()).isEqualTo(jsonSchemaVersions.getClientVersion()); assertThat(artifactExchangeJson.getClientSchemaVersion()) diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/ee/ImportExportApplicationServiceEETest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/ee/ImportExportApplicationServiceEETest.java deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/ee/ImportExportApplicationServiceGACTest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/ee/ImportExportApplicationServiceGACTest.java deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/transactions/ImportApplicationTransactionServiceTest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/transactions/ImportApplicationTransactionServiceTest.java index 7e46d65bf6a..f5d0c483540 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/transactions/ImportApplicationTransactionServiceTest.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/transactions/ImportApplicationTransactionServiceTest.java @@ -130,7 +130,8 @@ private Mono createAppJson(String filePath) { .map(data -> { return gson.fromJson(data, ApplicationJson.class); }) - .map(jsonSchemaMigration::migrateArtifactToLatestSchema) + .flatMap(applicationJson -> + jsonSchemaMigration.migrateArtifactExchangeJsonToLatestSchema(applicationJson, null, null)) .map(artifactExchangeJson -> (ApplicationJson) artifactExchangeJson); } diff --git a/deploy/docker/fs/opt/appsmith/entrypoint.sh b/deploy/docker/fs/opt/appsmith/entrypoint.sh index 1d5bd59fde6..3d73af5b391 100644 --- a/deploy/docker/fs/opt/appsmith/entrypoint.sh +++ b/deploy/docker/fs/opt/appsmith/entrypoint.sh @@ -372,7 +372,7 @@ configure_supervisord() { # Disable services based on configuration if [[ -z "${DYNO}" ]]; then - if [[ $isUriLocal -eq 0 ]]; then + if [[ $isUriLocal -eq 0 && $isMongoUrl -eq 1 ]]; then cp "$supervisord_conf_source/mongodb.conf" "$SUPERVISORD_CONF_TARGET" fi if [[ $APPSMITH_REDIS_URL == *"localhost"* || $APPSMITH_REDIS_URL == *"127.0.0.1"* ]]; then @@ -508,9 +508,6 @@ if [[ -z "${DYNO}" ]]; then tlog "Initializing MongoDB" init_mongodb init_replica_set - elif [[ $isPostgresUrl -eq 1 ]]; then - tlog "Initializing Postgres" - # init_postgres fi else # These functions are used to limit heap size for Backend process when deployed on Heroku diff --git a/deploy/docker/fs/opt/appsmith/run-java.sh b/deploy/docker/fs/opt/appsmith/run-java.sh index b9255a9293e..675c8e26511 100755 --- a/deploy/docker/fs/opt/appsmith/run-java.sh +++ b/deploy/docker/fs/opt/appsmith/run-java.sh @@ -5,6 +5,14 @@ set -o pipefail set -o nounset set -o noglob +mode=mongo +if [[ "$APPSMITH_DB_URL" = postgresql://* ]]; then + mode=pg +fi + +tlog "Running with $mode." +cd "/opt/appsmith/server/$mode" + declare -a extra_args proxy_configured=0 diff --git a/deploy/docker/fs/opt/appsmith/templates/supervisord/application_process/backend.conf b/deploy/docker/fs/opt/appsmith/templates/supervisord/application_process/backend.conf index be1d8cd57e9..a9f4ed00ecd 100644 --- a/deploy/docker/fs/opt/appsmith/templates/supervisord/application_process/backend.conf +++ b/deploy/docker/fs/opt/appsmith/templates/supervisord/application_process/backend.conf @@ -1,5 +1,4 @@ [program:backend] -directory=/opt/appsmith/backend command=/opt/appsmith/run-with-env.sh /opt/appsmith/run-java.sh priority=20 autostart=true diff --git a/scripts/local_testing.sh b/scripts/local_testing.sh index f9b5f406db6..199d38560f2 100755 --- a/scripts/local_testing.sh +++ b/scripts/local_testing.sh @@ -84,9 +84,10 @@ if ! ./build.sh -DskipTests > /dev/null; then echo Server build failed >&2 exit 1 fi +popd +./scripts/prepare_server_artifacts.sh pretty_print "Server build successful. Starting client build ..." -popd pushd app/client > /dev/null yarn > /dev/null if ! yarn build > /dev/null; then diff --git a/scripts/prepare_server_artifacts.sh b/scripts/prepare_server_artifacts.sh new file mode 100755 index 00000000000..d389508447a --- /dev/null +++ b/scripts/prepare_server_artifacts.sh @@ -0,0 +1,28 @@ +#!/bin/bash -eux + +cd "$(git rev-parse --show-toplevel)" + +if [[ -z "${EDITION-}" ]]; then + export EDITION=ce + if [[ "$(git remote get-url origin)" == *appsmithorg/appsmith-ee* ]]; then + export EDITION=ee + fi +fi + +PG_TAG="${PG_TAG-pg}" +echo "Will be copying pg server artifacts from appsmith-$EDITION:$PG_TAG" + +target="deploy/docker/fs/opt/appsmith/server" +mkdir -p "$target" +rm -rf "$target"/{pg,mongo} + +cp -r "app/server/dist" "$target/mongo" +mv "$target/mongo"/server-*.jar "$target/mongo/server.jar" + +# Grab PostgreSQL server artifacts from Docker image. +image="appsmith/appsmith-$EDITION:$PG_TAG" +docker run --name xx --detach --entrypoint sleep "$image" infinity +docker cp xx:/opt/appsmith/server/pg "$target/pg" +docker cp xx:/opt/appsmith/info.json "$target/pg/source-info.json" +docker rm --force xx +docker image rm "$image" \ No newline at end of file