From d718437b6a2a89ff9ade5bc4d4ba030745a815e6 Mon Sep 17 00:00:00 2001 From: Nidhi Date: Wed, 1 Jan 2025 15:30:29 +0530 Subject: [PATCH 01/40] chore: Added capability of running ITs using ok-to-test (#38355) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description > [!TIP] > _Add a TL;DR when the description is longer than 500 words or extremely technical (helps the content, marketing, and DevRel team)._ > > _Please also include relevant motivation and context. List any dependencies that are required for this change. Add links to Notion, Figma or any other documents that might be relevant to the PR._ Fixes #`Issue Number` _or_ Fixes `Issue URL` > [!WARNING] > _If no issue exists, please create an issue first, and check with the maintainers if the issue is valid._ ## Automation /ok-to-test tags="@tag.Git" it=true ### :mag: Cypress test results > [!TIP] > 🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉 > Workflow run: > Commit: 28ec34d9b20246ce54b7deab8e9fa8e136bbd7ff > Cypress dashboard. > Tags: `@tag.Git` > Spec: >
Mon, 30 Dec 2024 15:48:17 UTC ## Communication Should the DevRel and Marketing teams inform users about this change? - [ ] Yes - [ ] No ## Summary by CodeRabbit - **New Features** - Added optional integration tests trigger across multiple GitHub Actions workflows - Enhanced test configuration and reporting mechanisms - **Chores** - Updated workflow input parameters and descriptions - Improved test execution and artifact management - **Documentation** - Added clarifying comments in test scripts about test prerequisites --- .github/workflows/pr-automation.yml | 2 + .github/workflows/pr-cypress.yml | 15 ++- .github/workflows/scripts/test-tag-parser.js | 32 ++++-- .github/workflows/server-build.yml | 9 +- .../workflows/server-integration-tests.yml | 108 ++++++++++++++++++ .../appsmith/server/git/GitBranchesIT.java | 2 + 6 files changed, 153 insertions(+), 15 deletions(-) create mode 100644 .github/workflows/server-integration-tests.yml diff --git a/.github/workflows/pr-automation.yml b/.github/workflows/pr-automation.yml index 622274e97451..41d3f8d5e0f5 100644 --- a/.github/workflows/pr-automation.yml +++ b/.github/workflows/pr-automation.yml @@ -71,6 +71,7 @@ jobs: shell: bash outputs: tags: ${{ steps.parseTags.outputs.tags }} + its: ${{ steps.parseTags.outputs.its }} spec: ${{ steps.parseTags.outputs.spec }} matrix: ${{ steps.checkAll.outputs.matrix }} steps: @@ -129,6 +130,7 @@ jobs: uses: ./.github/workflows/pr-cypress.yml secrets: inherit with: + its: ${{ needs.parse-tags.outputs.its}} tags: ${{ needs.parse-tags.outputs.tags}} spec: ${{ needs.parse-tags.outputs.spec}} matrix: ${{ needs.parse-tags.outputs.matrix}} diff --git a/.github/workflows/pr-cypress.yml b/.github/workflows/pr-cypress.yml index 186ca9a63116..f525f54516bc 100644 --- a/.github/workflows/pr-cypress.yml +++ b/.github/workflows/pr-cypress.yml @@ -3,6 +3,10 @@ name: Cypress test suite on: workflow_call: inputs: + its: + required: false + type: string + default: "false" tags: required: true type: string @@ -45,6 +49,15 @@ jobs: with: pr: ${{ github.event.number }} + server-it: + needs: [ server-build, rts-build ] + if: success() && inputs.its == 'true' + uses: ./.github/workflows/server-integration-tests.yml + secrets: inherit + with: + pr: ${{ github.event.number }} + is-pg-build: ${{ github.event.pull_request.base.ref == 'pg' }} + build-docker-image: needs: [client-build, server-build, rts-build] # Only run if the build step is successful @@ -69,7 +82,7 @@ jobs: matrix: ${{ inputs.matrix }} ci-test-result: - needs: [ci-test] + needs: [ci-test, server-it] # Only run if the ci-test with matrices step is successful if: always() runs-on: ubuntu-latest diff --git a/.github/workflows/scripts/test-tag-parser.js b/.github/workflows/scripts/test-tag-parser.js index 2ba8708f810d..f303f3a40f1c 100644 --- a/.github/workflows/scripts/test-tag-parser.js +++ b/.github/workflows/scripts/test-tag-parser.js @@ -21,6 +21,7 @@ module.exports = function ({core, context, github}) { } core.setOutput("tags", parseResult.tags ?? ""); + core.setOutput("its", parseResult.its ?? ""); core.setOutput("spec", parseResult.spec ?? ""); } @@ -28,18 +29,29 @@ function parseTags(body) { const allTags = require(process.env.GITHUB_WORKSPACE + "/app/client/cypress/tags.js").Tag; // "/ok-to-test" matcher. Takes precedence over the "/test" matcher. - const strictMatch = body.match(/^\/ok-to-test tags="(.+?)"/m)?.[1]; - if (strictMatch) { - if (strictMatch === "@tag.All") { - return { tags: strictMatch }; - } - const parts = strictMatch.split(/\s*,\s*/); - for (const part of parts) { - if (!allTags.includes(part)) { - throw new Error("Unknown tag: " + part); + const okToTestPattern = body.match(/^(\/ok-to-test) tags="(.+?)"( it=true)?/m); + + if (okToTestPattern?.[1]) { + var response = {}; + const tagsMatch = okToTestPattern?.[2]; + if (tagsMatch) { + if (tagsMatch === "@tag.All") { + response = { tags: tagsMatch }; + } else { + const parts = tagsMatch.split(/\s*,\s*/); + for (const part of parts) { + if (!allTags.includes(part)) { + throw new Error("Unknown tag: " + part); + } + } + response = { tags: tagsMatch }; } } - return { tags: strictMatch }; + const itsMatch = okToTestPattern?.[3]; + if (itsMatch) { + response = { ...response, its: 'true' }; + } + return response; } // "/test" code-fence matcher. diff --git a/.github/workflows/server-build.yml b/.github/workflows/server-build.yml index df1c1334ccab..55691d6a049e 100644 --- a/.github/workflows/server-build.yml +++ b/.github/workflows/server-build.yml @@ -5,20 +5,20 @@ on: workflow_call: inputs: pr: - description: "This is the PR number in case the workflow is being called in a pull request" + description: "PR number for the workflow" required: false type: number skip-tests: - description: "This is a boolean value in case the workflow is being called in build deploy-preview" + description: "Skip tests flag" required: false type: string default: "false" branch: - description: "This is the branch to be used for the build." + description: "Branch for the build" required: false type: string is-pg-build: - description: "This is a boolean value in case the workflow is being called for a PG build" + description: "Flag for PG build" required: false type: string default: "false" @@ -210,6 +210,7 @@ jobs: fi args=() + if [[ "${{ steps.run_result.outputs.run_result }}" == "failedtest" ]]; then failed_tests="${{ steps.failed_tests.outputs.tests }}" args+=("-DfailIfNoTests=false" "-Dsurefire.failIfNoSpecifiedTests=false" "-Dtest=${failed_tests}") diff --git a/.github/workflows/server-integration-tests.yml b/.github/workflows/server-integration-tests.yml new file mode 100644 index 000000000000..a4c4836ba238 --- /dev/null +++ b/.github/workflows/server-integration-tests.yml @@ -0,0 +1,108 @@ +name: Server Integrations Tests Workflow + +on: + # This line enables manual triggering of this workflow. + workflow_dispatch: + workflow_call: + inputs: + pr: + 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: "Flag for PG build" + required: false + type: string + default: "false" + +jobs: + run-tests: + runs-on: ubuntu-latest-8-cores + if: | + github.event.pull_request.head.repo.full_name == github.repository || + github.event_name == 'workflow_dispatch' + defaults: + run: + shell: bash + # Service containers to run with this job. Required for running tests + services: + # Label used to access the service container + redis: + # Docker Hub image for Redis + image: redis + ports: + # Opens tcp port 6379 on the host and service container + - 6379:6379 + + steps: + # Check out merge commit + - name: Fork based /ok-to-test checkout + if: inputs.pr != 0 + uses: actions/checkout@v4 + with: + ref: "refs/pull/${{ inputs.pr }}/merge" + + # Checkout the code in the current branch in case the workflow is called because of a branch push event + - name: Checkout the head commit of the branch + if: inputs.pr == 0 + uses: actions/checkout@v4 + + # Setup Java + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + distribution: "temurin" + java-version: "17" + + - name: Conditionally start PostgreSQL + if: | + inputs.is-pg-build == 'true' + run: | + docker run --name appsmith-pg -p 5432:5432 -d -e POSTGRES_PASSWORD=password postgres:alpine postgres -N 1500 + + - name: Download the server build artifact + uses: actions/download-artifact@v4 + with: + name: server-build + path: app/server/dist/ + + - name: Download the rts build artifact + uses: actions/download-artifact@v4 + with: + name: rts-dist + path: app/client/packages/rts/dist + + - name: Un-tar the rts folder + run: | + tar -xvf app/client/packages/rts/dist/rts-dist.tar -C app/client/packages/rts/ + echo "Cleaning up the rts tar files" + rm app/client/packages/rts/dist/rts-dist.tar + + - name: Run rts using the untarred files + run: | + nohup -- node app/client/packages/rts/dist/bundle/server.js & + + - name: Run only integration tests on server + env: + ACTIVE_PROFILE: test + APPSMITH_CLOUD_SERVICES_BASE_URL: "https://release-cs.appsmith.com" + APPSMITH_CLOUD_SERVICES_TEMPLATE_UPLOAD_AUTH: ${{ secrets.APPSMITH_CLOUD_SERVICES_TEMPLATE_UPLOAD_AUTH }} + APPSMITH_REDIS_URL: "redis://127.0.0.1:6379" + APPSMITH_ENCRYPTION_PASSWORD: "password" + APPSMITH_ENCRYPTION_SALT: "salt" + APPSMITH_ENVFILE_PATH: /tmp/dummy.env + APPSMITH_VERBOSE_LOGGING_ENABLED: false + run: | + if [[ "${{ inputs.is-pg-build }}" == "true" ]]; then + export APPSMITH_DB_URL="postgresql://postgres:password@localhost:5432/postgres" + else + export APPSMITH_DB_URL="mongodb://localhost:27017/mobtools" + fi + + args=() + + # Run tests and capture logs + cd app/server + mvn verify -DskipUTs=true "${args[@]}" | tee mvn_integration_test.log + + diff --git a/app/server/appsmith-server/src/test/it/com/appsmith/server/git/GitBranchesIT.java b/app/server/appsmith-server/src/test/it/com/appsmith/server/git/GitBranchesIT.java index 02607420a8f6..a20345d049d4 100644 --- a/app/server/appsmith-server/src/test/it/com/appsmith/server/git/GitBranchesIT.java +++ b/app/server/appsmith-server/src/test/it/com/appsmith/server/git/GitBranchesIT.java @@ -212,6 +212,8 @@ void test(GitContext gitContext, ExtensionContext extensionContext) throws IOExc assertThat(autoCommitResponseDTO).isNotNull(); AutoCommitResponseDTO.AutoCommitResponse autoCommitProgress = autoCommitResponseDTO.getAutoCommitResponse(); + // This check requires RTS to be running on your local since client side changes come in from there + // Please make sure to run RTS before triggering this test assertThat(autoCommitProgress).isEqualTo(AutoCommitResponseDTO.AutoCommitResponse.PUBLISHED); // Wait for auto-commit to complete From 463c1199e17c0bf086f85cbd9ad5ccc7ebc64b30 Mon Sep 17 00:00:00 2001 From: Sagar Khalasi Date: Wed, 1 Jan 2025 15:31:30 +0530 Subject: [PATCH 02/40] fix: fix oracle spec (#38435) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description Issue with oracle spec in hosted version of ci. Fixes # https://app.zenhub.com/workspaces/stability-pod-6690c4814e31602e25cab7fd/issues/gh/appsmithorg/appsmith/38434 Success RUN: https://internal.appsmith.com/app/cypress-dashboard/all-runs-65890b3c81d7400d08fa9ede?branch=master ## Automation /ok-to-test tags="@tag.Sanity" ### :mag: Cypress test results > [!TIP] > 🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉 > Workflow run: > Commit: 3283b4d9ea35b290c1a58ab186c4b01fed1e9609 > Cypress dashboard. > Tags: `@tag.Sanity` > Spec: >
Wed, 01 Jan 2025 07:26:18 UTC ## Communication Should the DevRel and Marketing teams inform users about this change? - [ ] Yes - [x] No ## Summary by CodeRabbit - **Tests** - Enhanced Oracle data source test suite with improved query validation - Refined SQL query formatting and test case structure - Simplified application deployment process in test scenarios --- .../ServerSide/Datasources/Oracle_Spec.ts | 196 +++++++++--------- 1 file changed, 102 insertions(+), 94 deletions(-) diff --git a/app/client/cypress/e2e/Regression/ServerSide/Datasources/Oracle_Spec.ts b/app/client/cypress/e2e/Regression/ServerSide/Datasources/Oracle_Spec.ts index 440174aefb6c..5cb3cfb1b071 100644 --- a/app/client/cypress/e2e/Regression/ServerSide/Datasources/Oracle_Spec.ts +++ b/app/client/cypress/e2e/Regression/ServerSide/Datasources/Oracle_Spec.ts @@ -19,6 +19,9 @@ import EditorNavigation, { AppSidebar, } from "../../../../support/Pages/EditorNavigation"; import PageList from "../../../../support/Pages/PageList"; +import { PluginActionForm } from "../../../../support/Pages/PluginActionForm"; + +let pluginActionForm = new PluginActionForm(); describe( "Validate Oracle DS", @@ -145,17 +148,17 @@ describe( propPane.EnterJSContext( "Source Data", `[{ - "name": "Cargo Plane", - "value": "Cargo Plane" - }, - { - "name": "Passenger Plane", - "code": "Passenger Plane" - }, - { - "name": "Helicopter", - "code": "Helicopter" - }]`, + "name": "Cargo Plane", + "value": "Cargo Plane" + }, + { + "name": "Passenger Plane", + "code": "Passenger Plane" + }, + { + "name": "Helicopter", + "code": "Helicopter" + }]`, ); propPane.UpdatePropertyFieldValue( "Default selected value", @@ -183,17 +186,17 @@ describe( true, ); query = `CREATE TABLE ${guid} ( - aircraft_id NUMBER(5) PRIMARY KEY, - aircraft_type VARCHAR2(50) NOT NULL, - registration_number VARCHAR2(20) UNIQUE, - manufacturer VARCHAR2(50), - seating_capacity NUMBER(3), - maximum_speed NUMBER(5, 2), - range NUMBER(7, 2), - purchase_date DATE, - maintenance_last_date DATE, - notes CLOB - );`; + aircraft_id NUMBER(5) PRIMARY KEY, + aircraft_type VARCHAR2(50) NOT NULL, + registration_number VARCHAR2(20) UNIQUE, + manufacturer VARCHAR2(50), + seating_capacity NUMBER(3), + maximum_speed NUMBER(5, 2), + range NUMBER(7, 2), + purchase_date DATE, + maintenance_last_date DATE, + notes CLOB + );`; dataSources.CreateQueryForDS(dataSourceName, query); dataSources.RunQuery(); @@ -244,31 +247,31 @@ describe( dataSources.EnterQuery(query); dataSources.RunQuery(); query = `INSERT INTO ${guid} ( - aircraft_id, - aircraft_type, - registration_number, - manufacturer, - seating_capacity, - maximum_speed, - range, - purchase_date, - maintenance_last_date, - notes, - raw_data, - maintenance_interval) VALUES ( - 4, - 'Passenger Plane', - 'N77777', - 'Airbus', - 100, - 600.67, - 3800.82, - TO_DATE('2017-05-25', 'YYYY-MM-DD'), - TO_DATE('2023-02-18', 'YYYY-MM-DD'), - 'This aircraft is part of the international fleet.', - UTL_RAW.CAST_TO_RAW('raw_value'), - INTERVAL '1' YEAR(3) -- 1 year maintenance interval -);`; + aircraft_id, + aircraft_type, + registration_number, + manufacturer, + seating_capacity, + maximum_speed, + range, + purchase_date, + maintenance_last_date, + notes, + raw_data, + maintenance_interval) VALUES ( + 4, + 'Passenger Plane', + 'N77777', + 'Airbus', + 100, + 600.67, + 3800.82, + TO_DATE('2017-05-25', 'YYYY-MM-DD'), + TO_DATE('2023-02-18', 'YYYY-MM-DD'), + 'This aircraft is part of the international fleet.', + UTL_RAW.CAST_TO_RAW('raw_value'), + INTERVAL '1' YEAR(3) -- 1 year maintenance interval + );`; dataSources.EnterQuery(query); dataSources.RunQuery(); dataSources.EnterQuery(selectQuery); @@ -339,7 +342,11 @@ describe( dataSources.EnterQuery(selectQuery); dataSources.runQueryAndVerifyResponseViews({ count: 2 }); dataSources.AddSuggestedWidget(Widgets.Table); - deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.TABLE)); + deployMode.DeployApp(); + agHelper.AssertElementAbsence(locators._loading); + agHelper.WaitUntilEleAppear( + locators._widgetInDeployed(draggableWidgets.TABLE), + ); table.WaitUntilTableLoad(0, 0, "v2"); table.ReadTableRowColumnData(0, 10, "v2").then(($cellData) => { expect($cellData).to.be.empty; @@ -359,18 +366,18 @@ describe( it("4. Tc #2362 - Update query validation", () => { EditorNavigation.SelectEntityByName("Query1", EntityType.Query); query = `UPDATE ${guid} -SET - maximum_speed = CASE - WHEN seating_capacity <= 100 THEN 400.89 - WHEN seating_capacity > 100 AND seating_capacity <= 200 THEN 500.96 - ELSE 600.00 - END, - maintenance_interval = CASE - WHEN seating_capacity <= 50 THEN INTERVAL '3' MONTH - WHEN seating_capacity > 50 AND seating_capacity <= 150 THEN TO_YMINTERVAL('0-6') - ELSE TO_YMINTERVAL('1-0') - END -WHERE aircraft_type = 'Passenger Plane'`; + SET + maximum_speed = CASE + WHEN seating_capacity <= 100 THEN 400.89 + WHEN seating_capacity > 100 AND seating_capacity <= 200 THEN 500.96 + ELSE 600.00 + END, + maintenance_interval = CASE + WHEN seating_capacity <= 50 THEN INTERVAL '3' MONTH + WHEN seating_capacity > 50 AND seating_capacity <= 150 THEN TO_YMINTERVAL('0-6') + ELSE TO_YMINTERVAL('1-0') + END + WHERE aircraft_type = 'Passenger Plane'`; dataSources.EnterQuery(query); dataSources.RunQuery(); selectQuery = selectQuery + ` or aircraft_type = 'Passenger Plane'`; @@ -380,7 +387,12 @@ WHERE aircraft_type = 'Passenger Plane'`; Widgets.Table, dataSources._addSuggestedExisting, ); - deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.TABLE)); + agHelper.RefreshPage(); + deployMode.DeployApp(); + agHelper.AssertElementAbsence(locators._loading); + agHelper.WaitUntilEleAppear( + locators._widgetInDeployed(draggableWidgets.TABLE), + ); table.WaitUntilTableLoad(0, 0, "v2"); table.ReadTableRowColumnData(1, 5, "v2").then(($cellData) => { expect($cellData).to.eq("400.89"); @@ -394,12 +406,12 @@ WHERE aircraft_type = 'Passenger Plane'`; it("5. Tc #2361 - Delete query validation", () => { EditorNavigation.SelectEntityByName("Query1", EntityType.Query); query = `DELETE FROM ${guid} - WHERE - (aircraft_type = 'Cargo Plane' AND seating_capacity <= 100) - OR - (aircraft_type = 'Passenger Plane' AND purchase_date < TO_DATE('2020-01-01', 'YYYY-MM-DD')) - OR - (aircraft_type = 'Helicopter' AND manufacturer = 'Robinson' AND maintenance_interval = INTERVAL '6' MONTH)`; + WHERE + (aircraft_type = 'Cargo Plane' AND seating_capacity <= 100) + OR + (aircraft_type = 'Passenger Plane' AND purchase_date < TO_DATE('2020-01-01', 'YYYY-MM-DD')) + OR + (aircraft_type = 'Helicopter' AND manufacturer = 'Robinson' AND maintenance_interval = INTERVAL '6' MONTH)`; dataSources.EnterQuery(query); dataSources.RunQuery(); selectQuery = `SELECT * FROM ${guid}`; @@ -409,25 +421,21 @@ WHERE aircraft_type = 'Passenger Plane'`; Widgets.Table, dataSources._addSuggestedExisting, ); - deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.TABLE)); + deployMode.DeployApp(); + agHelper.AssertElementAbsence(locators._loading); + agHelper.WaitUntilEleAppear( + locators._widgetInDeployed(draggableWidgets.TABLE), + ); table.WaitUntilTableLoad(0, 0, "v2"); for (let i = 0; i < 2; i++) { table.ReadTableRowColumnData(i, 1, "v2").then(($cellData) => { expect($cellData).to.eq("Cargo Plane"); }); } - - table.OpenNFilterTable("MAINTENANCE_INTERVAL", "not empty"); - table.ReadTableRowColumnData(0, 0, "v2").then(($cellData) => { + table.ReadTableRowColumnData(1, 0, "v2").then(($cellData) => { expect($cellData).to.eq("5"); }); - agHelper - .GetText(table._showPageItemsCount) - .then(($count) => expect($count).contain("1")); - table.CloseFilter(); - agHelper - .GetText(table._filtersCount) - .then(($count) => expect($count).contain("1")); + deployMode.NavigateBacktoEditor(); }); @@ -459,30 +467,30 @@ WHERE aircraft_type = 'Passenger Plane'`; }); it("7. Tc #2365 - Query settings tab validations", () => { - apiPage.ToggleOnPageLoadRun(false); // ALl above cases validated for onpage load run with confirmation dialog set to false + apiPage.ToggleOnPageLoadRun(false); // All above cases validated for onpage load run with confirmation dialog set to false + pluginActionForm.toolbar.toggleSettings(); apiPage.ToggleConfirmBeforeRunning(true); - deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.TABLE)); + deployMode.DeployApp(); + agHelper.AssertElementAbsence(locators._loading); + agHelper.WaitUntilEleAppear( + locators._widgetInDeployed(draggableWidgets.TABLE), + ); table.WaitForTableEmpty("v2"); deployMode.NavigateBacktoEditor(); entityExplorer.DragDropWidgetNVerify(draggableWidgets.BUTTON, 300, 500); propPane.EnterJSContext("onClick", `{{Query1.run()}}`); - deployMode.DeployApp(locators._widgetInDeployed(draggableWidgets.TABLE)); + deployMode.DeployApp(); + agHelper.AssertElementAbsence(locators._loading); + agHelper.WaitUntilEleAppear( + locators._widgetInDeployed(draggableWidgets.TABLE), + ); agHelper.ClickButton("Submit"); jsEditor.ConfirmationClick("No"); //Handling both No & Yes from confirmation dialog - - table.WaitUntilTableLoad(0, 0, "v2"); + agHelper.AssertElementAbsence(locators._loading); + agHelper.WaitUntilEleAppear( + locators._widgetInDeployed(draggableWidgets.TABLE), + ); deployMode.NavigateBacktoEditor(); }); - - after( - "Verify Deletion of the Oracle datasource after all created queries are deleted", - () => { - dataSources.DeleteDatasourceFromWithinDS(dataSourceName, 409); //Since all queries exists - entityExplorer.DeleteAllQueriesForDB(dataSourceName); - deployMode.DeployApp(); - deployMode.NavigateBacktoEditor(); - dataSources.DeleteDatasourceFromWithinDS(dataSourceName, 200); - }, - ); }, ); From 0b3e188f06e32698a5ff439faf117d7913ca8b55 Mon Sep 17 00:00:00 2001 From: Ayush Pahwa Date: Thu, 2 Jan 2025 15:05:05 +0700 Subject: [PATCH 03/40] chore: flexible return for test payload extraction func (#38443) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description The `getTestPayloadFromCollectionData` extracts the `testPayload` from passed `collectionData` and returns an empty string if no information is present. This PR updates the function definition to allow different default value based on the function call. Fixes #37742 ## Automation /test sanity ### :mag: Cypress test results > [!TIP] > 🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉 > Workflow run: > Commit: 26ea6e2b17c9a31e836ced4e3787a0723db63680 > Cypress dashboard. > Tags: `@tag.Sanity` > Spec: >
Wed, 01 Jan 2025 16:34:44 UTC ## Communication Should the DevRel and Marketing teams inform users about this change? - [ ] Yes - [x] No ## Summary by CodeRabbit - **Bug Fixes** - Enhanced function handling for undefined collection data - Improved key iteration in action execution utilities - **Documentation** - Added JSDoc comment to clarify function behavior --- .../src/ce/utils/actionExecutionUtils.ts | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/app/client/src/ce/utils/actionExecutionUtils.ts b/app/client/src/ce/utils/actionExecutionUtils.ts index ea4a379236a5..675d31ded0ba 100644 --- a/app/client/src/ce/utils/actionExecutionUtils.ts +++ b/app/client/src/ce/utils/actionExecutionUtils.ts @@ -9,6 +9,7 @@ import { getCurrentEnvironmentDetails } from "ee/selectors/environmentSelectors" import type { Plugin } from "api/PluginApi"; import { get, isNil } from "lodash"; import type { JSCollectionData } from "ee/reducers/entityReducers/jsActionsReducer"; +import { objectKeys } from "@appsmith/utils"; export function getPluginActionNameToDisplay(action: Action) { return action.name; @@ -20,7 +21,7 @@ export const getActionProperties = ( ) => { const actionProperties: Record = {}; - Object.keys(keyConfig).forEach((key) => { + objectKeys(keyConfig).forEach((key) => { const value = get(action, key); if (!isNil(value)) { @@ -69,7 +70,7 @@ export function getActionExecutionAnalytics( datasourceId: datasourceId, isMock: !!datasource?.isMock, actionId: action?.id, - inputParams: Object.keys(params).length, + inputParams: objectKeys(params).length, source: ActionExecutionContext.EVALUATION_ACTION_TRIGGER, // Used in analytic events to understand who triggered action execution }; @@ -98,17 +99,24 @@ export function isBrowserExecutionAllowed(..._args: any[]) { return true; } -// Function to extract the test payload from the collection data +/** + * Function to extract the test payload from the collection data + * @param [collectionData] from the js Object + * @param [defaultValue=""] to be returned if no information is found, + * returns an empty string by default + * @returns stored value from the collectionData + * */ export const getTestPayloadFromCollectionData = ( collectionData: JSCollectionData | undefined, + defaultValue = "", ): string => { - if (!collectionData) return ""; + if (!collectionData) return defaultValue; const activeJSActionId = collectionData?.activeJSActionId; const testPayload: Record | undefined = collectionData?.data ?.testPayload as Record; - if (!activeJSActionId || !testPayload) return ""; + if (!activeJSActionId || !testPayload) return defaultValue; - return (testPayload[activeJSActionId] as string) || ""; + return testPayload[activeJSActionId] as string; }; From 51f3d0ebdfb5a67301fdf03acaccd4cbfa9f9bbf Mon Sep 17 00:00:00 2001 From: Nidhi Date: Thu, 2 Jan 2025 14:56:50 +0530 Subject: [PATCH 04/40] chore: Added support for artifact type in git redis utils (#38418) --- .../server/constants/ArtifactType.java | 6 +- .../appsmith/server/git/GitRedisUtils.java | 49 +++++++--- .../git/central/CentralGitServiceCEImpl.java | 96 ++++++++++++------- .../server/git/fs/GitFSServiceCEImpl.java | 63 ++---------- 4 files changed, 109 insertions(+), 105 deletions(-) diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/constants/ArtifactType.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/constants/ArtifactType.java index a9c4df2ce48d..3075ad27e65e 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/constants/ArtifactType.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/constants/ArtifactType.java @@ -7,5 +7,9 @@ public enum ArtifactType { APPLICATION, PACKAGE, - WORKFLOW + WORKFLOW; + + public String lowerCaseName() { + return this.name().toLowerCase(); + } } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/GitRedisUtils.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/GitRedisUtils.java index e0d61cdc192b..40e903568f8c 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/GitRedisUtils.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/GitRedisUtils.java @@ -1,6 +1,7 @@ package com.appsmith.server.git; import com.appsmith.external.git.constants.GitSpan; +import com.appsmith.server.constants.ArtifactType; import com.appsmith.server.exceptions.AppsmithError; import com.appsmith.server.exceptions.AppsmithException; import com.appsmith.server.helpers.RedisUtils; @@ -26,17 +27,18 @@ public class GitRedisUtils { /** * Adds a baseArtifact id as a key in redis, the presence of this key represents a symbolic lock, essentially meaning that no new operations * should be performed till this key remains present. - * @param baseArtifactId : base id of the artifact for which the key is getting added. - * @param commandName : Name of the operation which is trying to acquire the lock, this value will be added against the key + * + * @param key : base id of the artifact for which the key is getting added. + * @param commandName : Name of the operation which is trying to acquire the lock, this value will be added against the key * @param isRetryAllowed : Boolean for whether retries for adding the value is allowed * @return a boolean publisher for the added file locks */ - public Mono addFileLock(String baseArtifactId, String commandName, Boolean isRetryAllowed) { + public Mono addFileLock(String key, String commandName, Boolean isRetryAllowed) { long numberOfRetries = Boolean.TRUE.equals(isRetryAllowed) ? MAX_RETRIES : 0L; - log.info("Git command {} is trying to acquire the lock for application id {}", commandName, baseArtifactId); + log.info("Git command {} is trying to acquire the lock for identity {}", commandName, key); return redisUtils - .addFileLock(baseArtifactId, commandName) + .addFileLock(key, commandName) .retryWhen(Retry.fixedDelay(numberOfRetries, RETRY_DELAY) .onRetryExhaustedThrow((retryBackoffSpec, retrySignal) -> { if (retrySignal.failure() instanceof AppsmithException) { @@ -49,13 +51,16 @@ public Mono addFileLock(String baseArtifactId, String commandName, Bool .tap(Micrometer.observation(observationRegistry)); } - public Mono addFileLock(String defaultApplicationId, String commandName) { - return addFileLock(defaultApplicationId, commandName, true); + public Mono addFileLock(String baseArtifactId, String commandName) { + String key = generateRedisKey(ArtifactType.APPLICATION, baseArtifactId); + return addFileLock(key, commandName, true); } - public Mono releaseFileLock(String defaultApplicationId) { + public Mono releaseFileLock(String baseArtifactId) { + String key = generateRedisKey(ArtifactType.APPLICATION, baseArtifactId); + return redisUtils - .releaseFileLock(defaultApplicationId) + .releaseFileLock(key) .name(GitSpan.RELEASE_FILE_LOCK) .tap(Micrometer.observation(observationRegistry)); } @@ -64,33 +69,47 @@ public Mono releaseFileLock(String defaultApplicationId) { * This is a wrapper method for acquiring git lock, since multiple ops are used in sequence * for a complete composite operation not all ops require to acquire the lock hence a dummy flag is sent back for * operations in that is getting executed in between + * + * @param artifactType * @param baseArtifactId : id of the base artifact for which ops would be locked * @param isLockRequired : is lock really required or is it a proxy function * @return : Boolean for whether the lock is acquired */ - // TODO @Manish add artifactType reference in incoming prs. - public Mono acquireGitLock(String baseArtifactId, String commandName, Boolean isLockRequired) { + public Mono acquireGitLock( + ArtifactType artifactType, String baseArtifactId, String commandName, Boolean isLockRequired) { if (!Boolean.TRUE.equals(isLockRequired)) { return Mono.just(Boolean.TRUE); } - return addFileLock(baseArtifactId, commandName); + String key = generateRedisKey(artifactType, baseArtifactId); + + return addFileLock(key, commandName, true); } /** * This is a wrapper method for releasing git lock, since multiple ops are used in sequence * for a complete composite operation not all ops require to acquire the lock hence a dummy flag is sent back for * operations in that is getting executed in between + * + * @param artifactType * @param baseArtifactId : id of the base artifact for which ops would be locked * @param isLockRequired : is lock really required or is it a proxy function * @return : Boolean for whether the lock is released */ - // TODO @Manish add artifactType reference in incoming prs - public Mono releaseFileLock(String baseArtifactId, boolean isLockRequired) { + public Mono releaseFileLock(ArtifactType artifactType, String baseArtifactId, boolean isLockRequired) { if (!Boolean.TRUE.equals(isLockRequired)) { return Mono.just(Boolean.TRUE); } - return releaseFileLock(baseArtifactId); + String key = generateRedisKey(artifactType, baseArtifactId); + + return redisUtils + .releaseFileLock(key) + .name(GitSpan.RELEASE_FILE_LOCK) + .tap(Micrometer.observation(observationRegistry)); + } + + private String generateRedisKey(ArtifactType artifactType, String artifactId) { + return artifactType.lowerCaseName() + "-" + artifactId; } } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCEImpl.java index 460be19c7813..970860a9b268 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCEImpl.java @@ -394,13 +394,16 @@ protected Mono checkoutReference( String baseArtifactId = baseGitMetadata.getDefaultArtifactId(); final String finalRefName = gitRefDTO.getRefName().replaceFirst(ORIGIN, REMOTE_NAME_REPLACEMENT); + ArtifactType artifactType = baseArtifact.getArtifactType(); - GitArtifactHelper gitArtifactHelper = - gitArtifactHelperResolver.getArtifactHelper(baseArtifact.getArtifactType()); + GitArtifactHelper gitArtifactHelper = gitArtifactHelperResolver.getArtifactHelper(artifactType); GitHandlingService gitHandlingService = gitHandlingServiceResolver.getGitHandlingService(gitType); Mono acquireFileLock = gitRedisUtils.acquireGitLock( - baseArtifactId, GitConstants.GitCommandConstants.CHECKOUT_BRANCH, addFileLock); + baseArtifact.getArtifactType(), + baseArtifactId, + GitConstants.GitCommandConstants.CHECKOUT_BRANCH, + addFileLock); Mono checkedOutArtifactMono; // If the user is trying to check out remote reference, create a new reference if it does not exist already @@ -445,12 +448,12 @@ protected Mono checkoutReference( return acquireFileLock .then(checkedOutArtifactMono) .flatMap(checkedOutArtifact -> gitRedisUtils - .releaseFileLock(baseArtifactId, addFileLock) + .releaseFileLock(artifactType, baseArtifactId, addFileLock) .thenReturn(checkedOutArtifact)) .onErrorResume(error -> { log.error("An error occurred while checking out the reference. error {}", error.getMessage()); return gitRedisUtils - .releaseFileLock(baseArtifactId, addFileLock) + .releaseFileLock(artifactType, baseArtifactId, addFileLock) .then(Mono.error(error)); }) .tag(GitConstants.GitMetricConstants.CHECKOUT_REMOTE, FALSE.toString()) @@ -581,9 +584,9 @@ protected Mono createReference( GitArtifactMetadata baseGitMetadata = baseArtifact.getGitArtifactMetadata(); GitAuth baseGitAuth = baseGitMetadata.getGitAuth(); GitArtifactMetadata sourceGitMetadata = sourceArtifact.getGitArtifactMetadata(); + ArtifactType artifactType = baseArtifact.getArtifactType(); - GitArtifactHelper gitArtifactHelper = - gitArtifactHelperResolver.getArtifactHelper(baseArtifact.getArtifactType()); + GitArtifactHelper gitArtifactHelper = gitArtifactHelperResolver.getArtifactHelper(artifactType); GitHandlingService gitHandlingService = gitHandlingServiceResolver.getGitHandlingService(gitType); ArtifactJsonTransformationDTO jsonTransformationDTO = new ArtifactJsonTransformationDTO(); @@ -604,7 +607,10 @@ protected Mono createReference( } Mono acquireGitLockMono = gitRedisUtils.acquireGitLock( - baseGitMetadata.getDefaultArtifactId(), GitConstants.GitCommandConstants.CREATE_BRANCH, FALSE); + artifactType, + baseGitMetadata.getDefaultArtifactId(), + GitConstants.GitCommandConstants.CREATE_BRANCH, + FALSE); Mono fetchRemoteMono = gitHandlingService.fetchRemoteChanges(jsonTransformationDTO, baseGitAuth, TRUE); Mono createBranchMono = acquireGitLockMono @@ -675,7 +681,9 @@ protected Mono createReference( }) .flatMap(newImportedArtifact -> gitRedisUtils .releaseFileLock( - newImportedArtifact.getGitArtifactMetadata().getDefaultArtifactId(), TRUE) + artifactType, + newImportedArtifact.getGitArtifactMetadata().getDefaultArtifactId(), + TRUE) .then(gitAnalyticsUtils.addAnalyticsForGitOperation( AnalyticsEvents.GIT_CREATE_BRANCH, newImportedArtifact, @@ -683,7 +691,7 @@ protected Mono createReference( .onErrorResume(error -> { log.error("An error occurred while creating reference. error {}", error.getMessage()); return gitRedisUtils - .releaseFileLock(baseGitMetadata.getDefaultArtifactId(), TRUE) + .releaseFileLock(artifactType, baseGitMetadata.getDefaultArtifactId(), TRUE) .then(Mono.error(new AppsmithException(AppsmithError.GIT_ACTION_FAILED, "checkout"))); }) .name(GitSpan.OPS_CREATE_BRANCH) @@ -747,10 +755,10 @@ protected Mono deleteGitReference( GitArtifactMetadata baseGitMetadata = baseArtifact.getGitArtifactMetadata(); GitArtifactMetadata referenceArtifactMetadata = referenceArtifact.getGitArtifactMetadata(); + ArtifactType artifactType = baseArtifact.getArtifactType(); GitHandlingService gitHandlingService = gitHandlingServiceResolver.getGitHandlingService(gitType); - GitArtifactHelper gitArtifactHelper = - gitArtifactHelperResolver.getArtifactHelper(baseArtifact.getArtifactType()); + GitArtifactHelper gitArtifactHelper = gitArtifactHelperResolver.getArtifactHelper(artifactType); // TODO: write a migration to shift everything to refName in gitMetadata final String finalRefName = referenceArtifactMetadata.getRefName(); @@ -766,7 +774,7 @@ protected Mono deleteGitReference( .flatMap(isBranchProtected -> { if (!TRUE.equals(isBranchProtected)) { return gitRedisUtils.acquireGitLock( - baseArtifactId, GitConstants.GitCommandConstants.DELETE, TRUE); + artifactType, baseArtifactId, GitConstants.GitCommandConstants.DELETE, TRUE); } return Mono.error(new AppsmithException( @@ -786,7 +794,7 @@ protected Mono deleteGitReference( return gitHandlingService .deleteGitReference(jsonTransformationDTO) .flatMap(isReferenceDeleted -> gitRedisUtils - .releaseFileLock(baseArtifactId, TRUE) + .releaseFileLock(artifactType, baseArtifactId, TRUE) .thenReturn(isReferenceDeleted)) .flatMap(isReferenceDeleted -> { if (FALSE.equals(isReferenceDeleted)) { @@ -829,7 +837,9 @@ protected Mono deleteGitReference( referenceArtifactMetadata.getRefName(), baseArtifactId); - return gitRedisUtils.releaseFileLock(baseArtifactId, TRUE).then(Mono.error(error)); + return gitRedisUtils + .releaseFileLock(artifactType, baseArtifactId, TRUE) + .then(Mono.error(error)); }) .name(GitSpan.OPS_DELETE_BRANCH) .tap(Micrometer.observation(observationRegistry)); @@ -1190,8 +1200,8 @@ private Mono commitArtifact( boolean isSystemGenerated = commitDTO.getMessage().contains(DEFAULT_COMMIT_MESSAGE); - GitArtifactHelper gitArtifactHelper = - gitArtifactHelperResolver.getArtifactHelper(baseArtifact.getArtifactType()); + ArtifactType artifactType = baseArtifact.getArtifactType(); + GitArtifactHelper gitArtifactHelper = gitArtifactHelperResolver.getArtifactHelper(artifactType); GitHandlingService gitHandlingService = gitHandlingServiceResolver.getGitHandlingService(gitType); GitArtifactMetadata baseGitMetadata = baseArtifact.getGitArtifactMetadata(); GitArtifactMetadata branchedGitMetadata = branchedArtifact.getGitArtifactMetadata(); @@ -1214,6 +1224,7 @@ private Mono commitArtifact( .flatMap(isBranchProtected -> { if (!TRUE.equals(isBranchProtected)) { return gitRedisUtils.acquireGitLock( + artifactType, baseGitMetadata.getDefaultArtifactId(), GitConstants.GitCommandConstants.COMMIT, isFileLock); @@ -1309,7 +1320,7 @@ private Mono commitArtifact( .commitArtifact(updatedBranchedArtifact, commitDTO, jsonTransformationDTO) .onErrorResume(error -> { return gitRedisUtils - .releaseFileLock(baseArtifact.getId(), TRUE) + .releaseFileLock(artifactType, baseArtifact.getId(), TRUE) .then(gitAnalyticsUtils.addAnalyticsForGitOperation( AnalyticsEvents.GIT_COMMIT, updatedBranchedArtifact, @@ -1328,7 +1339,9 @@ private Mono commitArtifact( String status = tuple.getT1(); Artifact artifactFromBranch = tuple.getT2(); Mono releaseFileLockMono = gitRedisUtils.releaseFileLock( - artifactFromBranch.getGitArtifactMetadata().getDefaultArtifactId(), isFileLock); + artifactType, + artifactFromBranch.getGitArtifactMetadata().getDefaultArtifactId(), + isFileLock); Mono updatedArtifactMono = gitArtifactHelper.updateArtifactWithSchemaVersions(artifactFromBranch); @@ -1352,7 +1365,7 @@ private Mono commitArtifact( branchedGitMetadata.getBranchName()); return gitRedisUtils - .releaseFileLock(branchedGitMetadata.getDefaultArtifactId(), TRUE) + .releaseFileLock(artifactType, branchedGitMetadata.getDefaultArtifactId(), TRUE) .then(Mono.error(error)); }); @@ -1514,7 +1527,8 @@ protected Mono getStatus( Mono statusMono = exportedArtifactJsonMono .flatMap(artifactExchangeJson -> { return gitRedisUtils - .acquireGitLock(baseArtifactId, GitConstants.GitCommandConstants.STATUS, isFileLock) + .acquireGitLock( + artifactType, baseArtifactId, GitConstants.GitCommandConstants.STATUS, isFileLock) .thenReturn(artifactExchangeJson); }) .flatMap(artifactExchangeJson -> { @@ -1545,7 +1559,7 @@ protected Mono getStatus( .getStatus(jsonTransformationDTO) .flatMap(gitStatusDTO -> { return gitRedisUtils - .releaseFileLock(baseArtifactId, isFileLock) + .releaseFileLock(artifactType, baseArtifactId, isFileLock) .thenReturn(gitStatusDTO); }); }); @@ -1621,15 +1635,20 @@ protected Mono pullArtifact(Artifact baseArtifact, Artifact branched GitArtifactMetadata branchedGitMetadata = branchedArtifact.getGitArtifactMetadata(); Mono statusMono = getStatus(baseArtifact, branchedArtifact, false, true, gitType); + ArtifactType artifactType = baseArtifact.getArtifactType(); Mono pullDTOMono = gitRedisUtils - .acquireGitLock(branchedGitMetadata.getDefaultArtifactId(), GitConstants.GitCommandConstants.PULL, TRUE) + .acquireGitLock( + artifactType, + branchedGitMetadata.getDefaultArtifactId(), + GitConstants.GitCommandConstants.PULL, + TRUE) .then(Mono.defer(() -> statusMono)) .flatMap(status -> { // Check if the repo is clean if (!CollectionUtils.isEmpty(status.getModified())) { return gitRedisUtils - .releaseFileLock(branchedGitMetadata.getDefaultArtifactId(), TRUE) + .releaseFileLock(artifactType, branchedGitMetadata.getDefaultArtifactId(), TRUE) .then( Mono.error( new AppsmithException( @@ -1641,7 +1660,7 @@ protected Mono pullArtifact(Artifact baseArtifact, Artifact branched return pullAndRehydrateArtifact(baseArtifact, branchedArtifact, gitType) // Release file lock after the pull operation .flatMap(gitPullDTO -> gitRedisUtils - .releaseFileLock(branchedGitMetadata.getDefaultArtifactId(), TRUE) + .releaseFileLock(artifactType, branchedGitMetadata.getDefaultArtifactId(), TRUE) .then(Mono.just(gitPullDTO))); }) .onErrorResume(error -> { @@ -1651,7 +1670,7 @@ protected Mono pullArtifact(Artifact baseArtifact, Artifact branched branchedGitMetadata.getBranchName()); return gitRedisUtils - .releaseFileLock(branchedGitMetadata.getDefaultArtifactId(), TRUE) + .releaseFileLock(artifactType, branchedGitMetadata.getDefaultArtifactId(), TRUE) .then(Mono.error(error)); }) .name(GitSpan.OPS_PULL) @@ -1764,6 +1783,7 @@ public Mono fetchRemoteChanges( GitArtifactMetadata baseArtifactGitData = baseArtifact.getGitArtifactMetadata(); GitArtifactMetadata refArtifactGitData = refArtifact.getGitArtifactMetadata(); + ArtifactType artifactType = baseArtifact.getArtifactType(); String baseArtifactId = baseArtifactGitData.getDefaultArtifactId(); @@ -1773,8 +1793,8 @@ public Mono fetchRemoteChanges( } Mono currUserMono = sessionUserService.getCurrentUser().cache(); // will be used to send analytics event - Mono acquireGitLockMono = - gitRedisUtils.acquireGitLock(baseArtifactId, GitConstants.GitCommandConstants.FETCH_REMOTE, isFileLock); + Mono acquireGitLockMono = gitRedisUtils.acquireGitLock( + artifactType, baseArtifactId, GitConstants.GitCommandConstants.FETCH_REMOTE, isFileLock); ArtifactJsonTransformationDTO jsonTransformationDTO = new ArtifactJsonTransformationDTO(); jsonTransformationDTO.setWorkspaceId(baseArtifact.getWorkspaceId()); @@ -1792,7 +1812,7 @@ public Mono fetchRemoteChanges( jsonTransformationDTO, baseArtifactGitData.getGitAuth(), FALSE))) .flatMap(fetchedRemoteStatusString -> { return gitRedisUtils - .releaseFileLock(baseArtifactId, isFileLock) + .releaseFileLock(artifactType, baseArtifactId, isFileLock) .thenReturn(fetchedRemoteStatusString); }) .onErrorResume(throwable -> { @@ -1964,8 +1984,8 @@ public Mono discardChanges( protected Mono discardChanges(Artifact branchedArtifact, GitType gitType) { - GitArtifactHelper gitArtifactHelper = - gitArtifactHelperResolver.getArtifactHelper(branchedArtifact.getArtifactType()); + ArtifactType artifactType = branchedArtifact.getArtifactType(); + GitArtifactHelper gitArtifactHelper = gitArtifactHelperResolver.getArtifactHelper(artifactType); GitHandlingService gitHandlingService = gitHandlingServiceResolver.getGitHandlingService(gitType); GitArtifactMetadata branchedGitData = branchedArtifact.getGitArtifactMetadata(); @@ -1983,13 +2003,17 @@ protected Mono discardChanges(Artifact branchedArtifact, Git jsonTransformationDTO.setRepoName(branchedGitData.getRepoName()); Mono recreatedArtifactFromLastCommit = gitRedisUtils - .acquireGitLock(branchedGitData.getDefaultArtifactId(), GitConstants.GitCommandConstants.DISCARD, TRUE) + .acquireGitLock( + artifactType, + branchedGitData.getDefaultArtifactId(), + GitConstants.GitCommandConstants.DISCARD, + TRUE) .then(gitHandlingService .recreateArtifactJsonFromLastCommit(jsonTransformationDTO) .onErrorResume(throwable -> { log.error("Git recreate ArtifactJsonFailed : {}", throwable.getMessage()); return gitRedisUtils - .releaseFileLock(branchedGitData.getDefaultArtifactId(), TRUE) + .releaseFileLock(artifactType, branchedGitData.getDefaultArtifactId(), TRUE) .then( Mono.error( new AppsmithException( @@ -2007,7 +2031,9 @@ protected Mono discardChanges(Artifact branchedArtifact, Git .flatMap(publishedArtifact -> { return gitRedisUtils .releaseFileLock( - publishedArtifact.getGitArtifactMetadata().getDefaultArtifactId(), TRUE) + artifactType, + publishedArtifact.getGitArtifactMetadata().getDefaultArtifactId(), + TRUE) .then(gitAnalyticsUtils.addAnalyticsForGitOperation( AnalyticsEvents.GIT_DISCARD_CHANGES, publishedArtifact, null)); }) @@ -2017,7 +2043,7 @@ protected Mono discardChanges(Artifact branchedArtifact, Git branchedGitData.getDefaultArtifactId(), error.getMessage()); return gitRedisUtils - .releaseFileLock(branchedGitData.getDefaultArtifactId(), TRUE) + .releaseFileLock(artifactType, branchedGitData.getDefaultArtifactId(), TRUE) .then(Mono.error(new AppsmithException(AppsmithError.GIT_ACTION_FAILED, "checkout"))); }) .name(GitSpan.OPS_DISCARD_CHANGES) diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/fs/GitFSServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/fs/GitFSServiceCEImpl.java index 84f772930dc6..d08152c44eb1 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/fs/GitFSServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/fs/GitFSServiceCEImpl.java @@ -10,7 +10,6 @@ import com.appsmith.external.git.constants.ce.RefType; import com.appsmith.external.git.handler.FSGitHandler; import com.appsmith.git.dto.CommitDTO; -import com.appsmith.server.acl.AclPermission; import com.appsmith.server.configurations.EmailConfig; import com.appsmith.server.constants.ArtifactType; import com.appsmith.server.datasources.base.DatasourceService; @@ -106,33 +105,6 @@ public class GitFSServiceCEImpl implements GitHandlingServiceCE { private static final String ORIGIN = "origin/"; private static final String REMOTE_NAME_REPLACEMENT = ""; - private Mono addFileLock(String baseArtifactId, String commandName, boolean isLockRequired) { - if (!Boolean.TRUE.equals(isLockRequired)) { - return Mono.just(Boolean.TRUE); - } - - return Mono.defer(() -> addFileLock(baseArtifactId, commandName)); - } - - private Mono addFileLock(String baseArtifactId, String commandName) { - return gitRedisUtils.addFileLock(baseArtifactId, commandName); - } - - private Mono releaseFileLock(String baseArtifactId, boolean isLockRequired) { - if (!Boolean.TRUE.equals(isLockRequired)) { - return Mono.just(Boolean.TRUE); - } - - return releaseFileLock(baseArtifactId); - } - - private Mono releaseFileLock(String baseArtifactId) { - return gitRedisUtils - .releaseFileLock(baseArtifactId) - .name(GitSpan.RELEASE_FILE_LOCK) - .tap(Micrometer.observation(observationRegistry)); - } - @Override public Set validateGitConnectDTO(GitConnectDTO gitConnectDTO) { Set errors = new HashSet<>(); @@ -263,9 +235,6 @@ public Mono removeRepository(ArtifactJsonTransformationDTO artifactJson */ @Override public Mono> listBranches(ArtifactJsonTransformationDTO artifactJsonTransformationDTO) { - GitArtifactHelper gitArtifactHelper = - gitArtifactHelperResolver.getArtifactHelper(artifactJsonTransformationDTO.getArtifactType()); - return listBranches(artifactJsonTransformationDTO, Boolean.FALSE); } @@ -433,21 +402,6 @@ public Mono> commitArtifact( }); } - /** - * Used for pushing commits present in the given branched artifact. - * @param branchedArtifactId : id of the branched artifact. - * @param artifactType : type of the artifact - * @return : returns a string which has details of operations - */ - public Mono pushArtifact(String branchedArtifactId, ArtifactType artifactType) { - GitArtifactHelper gitArtifactHelper = gitArtifactHelperResolver.getArtifactHelper(artifactType); - AclPermission artifactEditPermission = gitArtifactHelper.getArtifactEditPermission(); - - return gitArtifactHelper - .getArtifactById(branchedArtifactId, artifactEditPermission) - .flatMap(branchedArtifact -> pushArtifact(branchedArtifact, true)); - } - /** * Push flow for dehydrated apps * @@ -455,8 +409,8 @@ public Mono pushArtifact(String branchedArtifactId, ArtifactType artifac * @return Success message */ protected Mono pushArtifact(Artifact branchedArtifact, boolean isFileLock) { - GitArtifactHelper gitArtifactHelper = - gitArtifactHelperResolver.getArtifactHelper(branchedArtifact.getArtifactType()); + ArtifactType artifactType = branchedArtifact.getArtifactType(); + GitArtifactHelper gitArtifactHelper = gitArtifactHelperResolver.getArtifactHelper(artifactType); Mono gitArtifactMetadataMono = Mono.just(branchedArtifact.getGitArtifactMetadata()); if (!branchedArtifact @@ -478,6 +432,7 @@ protected Mono pushArtifact(Artifact branchedArtifact, boolean isFileLoc .flatMap(gitMetadata -> { return gitRedisUtils .acquireGitLock( + artifactType, gitMetadata.getDefaultArtifactId(), GitConstants.GitCommandConstants.PUSH, isFileLock) @@ -540,8 +495,8 @@ protected Mono pushArtifact(Artifact branchedArtifact, boolean isFileLoc if (!Boolean.TRUE.equals(isFileLock)) { return Mono.just(flag); } - return Mono.defer(() -> releaseFileLock( - artifact.getGitArtifactMetadata().getDefaultArtifactId())); + return Mono.defer(() -> gitRedisUtils.releaseFileLock( + artifactType, artifact.getGitArtifactMetadata().getDefaultArtifactId(), true)); }); return pushArtifactErrorRecovery(pushStatus, artifact) @@ -676,8 +631,8 @@ public Mono createGitReference(ArtifactJsonTransformationDTO jsonTransfo @Override public Mono deleteGitReference(ArtifactJsonTransformationDTO jsonTransformationDTO) { - GitArtifactHelper gitArtifactHelper = - gitArtifactHelperResolver.getArtifactHelper(jsonTransformationDTO.getArtifactType()); + ArtifactType artifactType = jsonTransformationDTO.getArtifactType(); + GitArtifactHelper gitArtifactHelper = gitArtifactHelperResolver.getArtifactHelper(artifactType); Path repoSuffix = gitArtifactHelper.getRepoSuffixPath( jsonTransformationDTO.getWorkspaceId(), @@ -689,8 +644,8 @@ public Mono deleteGitReference(ArtifactJsonTransformationDTO jsonTransf .onErrorResume(throwable -> { log.error("Delete branch failed {}", throwable.getMessage()); - Mono releaseLockMono = - gitRedisUtils.releaseFileLock(jsonTransformationDTO.getBaseArtifactId(), Boolean.TRUE); + Mono releaseLockMono = gitRedisUtils.releaseFileLock( + artifactType, jsonTransformationDTO.getBaseArtifactId(), Boolean.TRUE); if (throwable instanceof CannotDeleteCurrentBranchException) { return releaseLockMono.then(Mono.error(new AppsmithException( From 9c816473ff0d8ffaa6b5f548b0db0065fccd64a0 Mon Sep 17 00:00:00 2001 From: Ayush Pahwa Date: Thu, 2 Jan 2025 19:11:55 +0700 Subject: [PATCH 05/40] feat: custom eslint rule infra (#38345) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description This PR introduces the custom ESLint rule to [handle floating promises](https://typescript-eslint.io/rules/no-floating-promises/) in our JS Objects (using async function calls without await inside async functions). Along with this, some refactors were needed 1) Function to dynamically enable/disable the rules based on context ( using editor type as the context for now, can be updated as per requirements). 2) Generate a list of async functions from the global data input for evaluation. 3) Package added for estree types. Note: This custom rule is only used in our EE codebase for now. We can enable it in CE in case the requirement arises. Fixes https://github.com/appsmithorg/appsmith/issues/37255 ## Automation /test sanity js ### :mag: Cypress test results > [!TIP] > 🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉 > Workflow run: > Commit: 36b66109c7ef70dc1eb97b445661ac69f881775a > Cypress dashboard. > Tags: `@tag.Sanity, @tag.JS` > Spec: >
Tue, 31 Dec 2024 10:54:23 UTC ## Communication Should the DevRel and Marketing teams inform users about this change? - [ ] Yes - [x] No ## Summary by CodeRabbit ## Release Notes - **New Features** - Added a custom ESLint rule to enforce proper Promise handling - Enhanced linting capabilities with more granular error detection - **Improvements** - Updated linting utility functions to support more flexible configuration - Introduced more detailed context-aware linting options - **Development** - Added TypeScript type definitions for ESTree - Expanded test coverage for linting utilities - **Chores** - Refactored linting-related utility functions and constants --- app/client/package.json | 1 + app/client/src/ce/hooks/index.ts | 9 +- app/client/src/ce/utils/lintRulesHelpers.ts | 15 ++ app/client/src/ee/utils/lintRulesHelpers.ts | 1 + app/client/src/plugins/Linting/constants.ts | 36 +++-- .../customRules/no-floating-promises.ts | 138 ++++++++++++++++++ .../tests/generateLintingGlobalData.test.ts | 99 +++++++++++++ .../Linting/tests/getLintingErrors.test.ts | 81 +++++++++- .../plugins/Linting/utils/getLintingErrors.ts | 110 +++++++++++--- app/client/yarn.lock | 16 +- 10 files changed, 468 insertions(+), 38 deletions(-) create mode 100644 app/client/src/ce/utils/lintRulesHelpers.ts create mode 100644 app/client/src/ee/utils/lintRulesHelpers.ts create mode 100644 app/client/src/plugins/Linting/customRules/no-floating-promises.ts create mode 100644 app/client/src/plugins/Linting/tests/generateLintingGlobalData.test.ts diff --git a/app/client/package.json b/app/client/package.json index 8a365d4286b6..1a4652a73863 100644 --- a/app/client/package.json +++ b/app/client/package.json @@ -261,6 +261,7 @@ "@types/deep-diff": "^1.0.0", "@types/dom-view-transitions": "^1.0.5", "@types/downloadjs": "^1.4.2", + "@types/estree": "^1.0.6", "@types/jest": "^29.5.3", "@types/jshint": "^2.12.0", "@types/lodash": "^4.14.120", diff --git a/app/client/src/ce/hooks/index.ts b/app/client/src/ce/hooks/index.ts index cd84f5ca1dfd..07f4b12bcd7c 100644 --- a/app/client/src/ce/hooks/index.ts +++ b/app/client/src/ce/hooks/index.ts @@ -18,7 +18,9 @@ export const editorType: EditorType = { [BUILDER_BASE_PATH_DEPRECATED]: EditorNames.APPLICATION, }; -export const useEditorType = (path: string) => { +// Utility function to get editor type based on path +// to be used in non react functions +export const getEditorType = (path: string) => { const basePath = matchPath(path, { path: [BUILDER_VIEWER_PATH_PREFIX, BUILDER_BASE_PATH_DEPRECATED], }); @@ -28,6 +30,11 @@ export const useEditorType = (path: string) => { : editorType[BUILDER_VIEWER_PATH_PREFIX]; }; +// custom hook to get editor type based on path +export const useEditorType = (path: string) => { + return getEditorType(path); +}; + export function useOutsideClick( ref: RefObject, inputRef: RefObject, diff --git a/app/client/src/ce/utils/lintRulesHelpers.ts b/app/client/src/ce/utils/lintRulesHelpers.ts new file mode 100644 index 000000000000..fc857cad6b1e --- /dev/null +++ b/app/client/src/ce/utils/lintRulesHelpers.ts @@ -0,0 +1,15 @@ +interface ContextType { + editorType: string; +} + +/** + * Function used to conditionally enable/disable custom rules based on context provided + * + * @returns {Record} Object with settings for the rule + * */ +export const getLintRulesBasedOnContext = ({}: ContextType): Record< + string, + "off" | "error" +> => { + return {}; +}; diff --git a/app/client/src/ee/utils/lintRulesHelpers.ts b/app/client/src/ee/utils/lintRulesHelpers.ts new file mode 100644 index 000000000000..9e1547fd3401 --- /dev/null +++ b/app/client/src/ee/utils/lintRulesHelpers.ts @@ -0,0 +1 @@ +export * from "ce/utils/lintRulesHelpers"; diff --git a/app/client/src/plugins/Linting/constants.ts b/app/client/src/plugins/Linting/constants.ts index 433fb0a3b166..40f0ab2d5c7b 100644 --- a/app/client/src/plugins/Linting/constants.ts +++ b/app/client/src/plugins/Linting/constants.ts @@ -1,7 +1,8 @@ import { ECMA_VERSION } from "@shared/ast"; import type { LintOptions } from "jshint"; import isEntityFunction from "./utils/isEntityFunction"; -import type { Linter } from "eslint-linter-browserify"; +import { noFloatingPromisesLintRule } from "./customRules/no-floating-promises"; +import { getLintRulesBasedOnContext } from "ee/utils/lintRulesHelpers"; export enum LINTER_TYPE { "JSHINT" = "JSHint", @@ -9,7 +10,9 @@ export enum LINTER_TYPE { } export const lintOptions = ( - globalData: Record, + globalData: Record, + asyncFunctions: string[], + editorType: string, linterType: LINTER_TYPE = LINTER_TYPE.JSHINT, ) => { if (linterType === LINTER_TYPE.JSHINT) { @@ -39,25 +42,28 @@ export const lintOptions = ( loopfunc: true, } as LintOptions; } else { - const eslintGlobals: Record = { - setTimeout: "readonly", - clearTimeout: "readonly", - console: "readonly", - }; - - for (const key in globalData) { - if (globalData.hasOwnProperty(key)) { - eslintGlobals[key] = "readonly"; - } - } + const extraRules = getLintRulesBasedOnContext({ editorType }); return { languageOptions: { ecmaVersion: ECMA_VERSION, - globals: eslintGlobals, + globals: globalData, sourceType: "script", }, + // Need to pass for custom rules + settings: { + globalData, + asyncFunctions, + }, + plugins: { + customRules: { + rules: { + "no-floating-promises": noFloatingPromisesLintRule, + }, + }, + }, rules: { + ...extraRules, eqeqeq: "off", curly: "off", "no-extend-native": "error", @@ -76,7 +82,7 @@ export const lintOptions = ( "no-unused-expressions": "off", "no-loop-func": "off", }, - } as Linter.Config; + } as const; } }; diff --git a/app/client/src/plugins/Linting/customRules/no-floating-promises.ts b/app/client/src/plugins/Linting/customRules/no-floating-promises.ts new file mode 100644 index 000000000000..df174e3f3733 --- /dev/null +++ b/app/client/src/plugins/Linting/customRules/no-floating-promises.ts @@ -0,0 +1,138 @@ +import type { Rule } from "eslint"; +import type * as ESTree from "estree"; + +export const noFloatingPromisesLintRule: Rule.RuleModule = { + meta: { + type: "problem", + docs: { + description: "Requires handling of Promises (using await or .then())", + category: "Possible Errors", + recommended: false, + }, + messages: { + unhandledPromise: + "Unhandled Promise detected. Handle using await or .then()", + }, + schema: [], // Rule does not accept configuration options + }, + create: function (context: Rule.RuleContext) { + // Access async functions from settings + const asyncFunctions = context.settings?.asyncFunctions || []; + + return { + FunctionDeclaration(node: ESTree.FunctionDeclaration) { + // Start traversal from the function body + traverseNode(node.body, null); + }, + }; + + /** + * Recursively traverses the AST node and its children. + * Processes CallExpressions and continues traversing child nodes. + */ + function traverseNode( + node: ESTree.Node | null, + parent: ESTree.Node | null, + ) { + if (!node) return; + + if (node.type === "CallExpression") { + checkCallExpression(node as ESTree.CallExpression, parent); + } + + // Retrieve keys for child nodes and traverse them + const visitorKeys = context.getSourceCode().visitorKeys[node.type] || []; + + for (const key of visitorKeys) { + const child = (node as any)[key]; // eslint-disable-line @typescript-eslint/no-explicit-any + + if (Array.isArray(child)) { + child.forEach( + (c) => c && typeof c.type === "string" && traverseNode(c, node), + ); + } else if (child && typeof child.type === "string") { + traverseNode(child, node); + } + } + } + + /** + * Determines if a node is inside an async function by traversing its parent chain. + */ + function isInAsyncFunction(node: ESTree.Node | null): boolean { + while (node) { + if ( + (node.type === "FunctionDeclaration" || + node.type === "FunctionExpression") && + node.async + ) { + return true; + } + + // Move to the parent node in the AST + // @ts-expect-error: Types may not always define `parent` + node = node.parent; + } + + return false; + } + + /** + * Checks if a CallExpression represents an unhandled Promise. + * Reports an error if the promise is not awaited or chained with `.then()`, `.catch()`, or `.finally()`. + */ + function checkCallExpression( + node: ESTree.CallExpression, + parent: ESTree.Node | null, + ) { + const callee = node.callee; + let isPotentialAsyncCall = false; + + // Identify async calls by matching against the asyncFunctions list + if (callee.type === "MemberExpression") { + const object = callee.object; + const property = callee.property; + + if ( + property.type === "Identifier" && + object.type === "Identifier" && + asyncFunctions.includes(`${object.name}.${property.name}`) + ) { + isPotentialAsyncCall = true; + } + } + + // Report if the async call is unhandled and not properly awaited + if (isPotentialAsyncCall && isInAsyncFunction(parent)) { + if ( + parent && + parent.type !== "AwaitExpression" && + parent.type !== "ReturnStatement" && + !isHandledWithPromiseMethods(parent) + ) { + context.report({ + node, + messageId: "unhandledPromise", + }); + } + } + } + + /** + * Determines if a CallExpression is handled with `.then()`, `.catch()`, or `.finally()`. + */ + function isHandledWithPromiseMethods(parent: ESTree.Node): boolean { + if ( + parent.type === "MemberExpression" && + parent.property && + ["then", "catch", "finally"].includes( + (parent.property as ESTree.Identifier).name, + ) + ) { + return true; + } + + return false; + } + }, +}; diff --git a/app/client/src/plugins/Linting/tests/generateLintingGlobalData.test.ts b/app/client/src/plugins/Linting/tests/generateLintingGlobalData.test.ts new file mode 100644 index 000000000000..efa9e1f6bc64 --- /dev/null +++ b/app/client/src/plugins/Linting/tests/generateLintingGlobalData.test.ts @@ -0,0 +1,99 @@ +import { ENTITY_TYPE } from "ee/entities/DataTree/types"; +import { LINTER_TYPE } from "../constants"; +import { generateLintingGlobalData } from "../utils/getLintingErrors"; + +jest.mock("ee/hooks", () => { + const actualModule = jest.requireActual("ee/hooks"); + + return { + ...actualModule, // Spread the original module exports + getEditorType: jest.fn(() => "TestEditorType"), // Override `getEditorType` + }; +}); + +describe("generateLintingGlobalData", () => { + it("should generate the correct response type", () => { + const mockData = { + Query1: { + ENTITY_TYPE: ENTITY_TYPE.ACTION, + }, + JSObject1: { + ENTITY_TYPE: ENTITY_TYPE.JSACTION, + myFun1: "function() {}", + myFun2: "async function() {}", + test: "async function() {}", + body: "Some body text", + actionId: "action-id", + }, + appsmith: { + ENTITY_TYPE: ENTITY_TYPE.APPSMITH, + URL: { pathname: "/test/editor/path" }, + }, + }; + + const result = generateLintingGlobalData(mockData, LINTER_TYPE.ESLINT); + + expect(result.globalData).toEqual({ + setTimeout: "readonly", + clearTimeout: "readonly", + console: "readonly", + Query1: "readonly", + JSObject1: "readonly", + appsmith: "readonly", + crypto: "readonly", + forge: "readonly", + moment: "readonly", + _: "readonly", + fetch: "readonly", + }); + + expect(result.asyncFunctions).toEqual([ + "Query1.run", + "JSObject1.myFun2", + "JSObject1.test", + ]); + + expect(result.editorType).toEqual("TestEditorType"); + }); + + it("should handle an empty input and return default values", () => { + const result = generateLintingGlobalData({}, LINTER_TYPE.ESLINT); + + expect(result.globalData).toEqual({ + setTimeout: "readonly", + clearTimeout: "readonly", + console: "readonly", + crypto: "readonly", + forge: "readonly", + moment: "readonly", + _: "readonly", + fetch: "readonly", + }); + + expect(result.asyncFunctions).toEqual([]); + }); + + it("should handle unsupported ENTITY_TYPE gracefully", () => { + const mockData = { + UnknownEntity: { + ENTITY_TYPE: "UNKNOWN", + }, + }; + + const result = generateLintingGlobalData(mockData, LINTER_TYPE.ESLINT); + + expect(result.globalData).toEqual({ + setTimeout: "readonly", + clearTimeout: "readonly", + console: "readonly", + UnknownEntity: "readonly", + crypto: "readonly", + forge: "readonly", + moment: "readonly", + _: "readonly", + fetch: "readonly", + }); + + expect(result.asyncFunctions).toEqual([]); + }); +}); diff --git a/app/client/src/plugins/Linting/tests/getLintingErrors.test.ts b/app/client/src/plugins/Linting/tests/getLintingErrors.test.ts index a488e90dd410..99c883d82ed9 100644 --- a/app/client/src/plugins/Linting/tests/getLintingErrors.test.ts +++ b/app/client/src/plugins/Linting/tests/getLintingErrors.test.ts @@ -1,8 +1,18 @@ -import { getScriptType } from "workers/Evaluation/evaluate"; +import { + EvaluationScriptType, + getScriptType, +} from "workers/Evaluation/evaluate"; import { CustomLintErrorCode, LINTER_TYPE } from "../constants"; import getLintingErrors from "../utils/getLintingErrors"; import { Severity } from "entities/AppsmithConsole"; +// Define all the custom eslint rules you want to test here +jest.mock("ee/utils/lintRulesHelpers", () => ({ + getLintRulesBasedOnContext: jest.fn(() => ({ + "customRules/no-floating-promises": "error", + })), +})); + const webworkerTelemetry = {}; const linterTypes = [ @@ -598,3 +608,72 @@ describe.each(linterTypes)( }); }, ); + +describe("Custom lint checks", () => { + // This is done since all custom lint rules need eslint as linter type + const getLinterTypeFn = () => LINTER_TYPE.ESLINT; + + // Test for 'no floating promises lint rule' + it("1. should show error for unhandled promises", () => { + const data = { + ARGUMENTS: undefined, + Query1: { + actionId: "671b2fcc-e574", + isLoading: false, + responseMeta: { + isExecutionSuccess: false, + }, + config: { + timeoutInMillisecond: 10000, + paginationType: "NONE", + encodeParamsToggle: true, + body: "SELECT * FROM <> LIMIT 10;\n\n-- Please enter a valid table name and hit RUN\n", + pluginSpecifiedTemplates: [ + { + value: true, + }, + ], + }, + ENTITY_TYPE: "ACTION", + datasourceUrl: "", + name: "Query1", + run: async function () {}, + clear: async function () {}, + }, + JSObject1: { + body: "export default {\n\tasync handledAsync() {\n\t\tawait Query1.run(); \n\t},\n\tasync unhandledAsync() {\n\t\tQuery1.run();\n\t}\n}", + ENTITY_TYPE: "JSACTION", + actionId: "d24fc04a-910b", + handledAsync: "async function () {\n await Query1.run();\n}", + "handledAsync.data": {}, + unhandledAsync: "async function () {\n Query1.run();\n}", + "unhandledAsync.data": {}, + }, + THIS_CONTEXT: {}, + }; + + const originalBinding = "async unhandledAsync() {\n\t\tQuery1.run();\n\t}"; + const script = + "\n function $$closedFn () {\n const $$result = {async unhandledAsync() {\n\t\tQuery1.run();\n\t}}\n return $$result\n }\n $$closedFn.call(THIS_CONTEXT)\n "; + const options = { isJsObject: true }; + + const lintErrors = getLintingErrors({ + getLinterTypeFn, + data, + originalBinding, + script, + scriptType: EvaluationScriptType.EXPRESSION, + options, + webworkerTelemetry, + }); + + expect(Array.isArray(lintErrors)).toBe(true); + expect(lintErrors.length).toEqual(1); + //expect(lintErrors[0].code).toEqual( + // CustomLintErrorCode.INVALID_ENTITY_PROPERTY, + //); + expect(lintErrors[0].errorMessage.message).toContain( + "Unhandled Promise detected.", + ); + }); +}); diff --git a/app/client/src/plugins/Linting/utils/getLintingErrors.ts b/app/client/src/plugins/Linting/utils/getLintingErrors.ts index af7e9a41cd6f..a66476af4c34 100644 --- a/app/client/src/plugins/Linting/utils/getLintingErrors.ts +++ b/app/client/src/plugins/Linting/utils/getLintingErrors.ts @@ -42,6 +42,10 @@ import { profileFn } from "instrumentation/generateWebWorkerTraces"; import { WorkerEnv } from "workers/Evaluation/handlers/workerEnv"; import { FEATURE_FLAG } from "ee/entities/FeatureFlag"; import { Linter } from "eslint-linter-browserify"; +import { ENTITY_TYPE } from "entities/DataTree/dataTreeFactory"; +import type { DataTreeEntity } from "entities/DataTree/dataTreeTypes"; +import { EditorNames, getEditorType } from "ee/hooks"; +import type { AppsmithEntity } from "ee/entities/DataTree/types"; const EvaluationScriptPositions: Record = {}; @@ -71,25 +75,88 @@ function getEvaluationScriptPosition(scriptType: EvaluationScriptType) { return EvaluationScriptPositions[scriptType]; } -function generateLintingGlobalData(data: Record) { - const globalData: Record = {}; +export function generateLintingGlobalData( + data: Record, + linterType = LINTER_TYPE.JSHINT, +) { + const asyncFunctions: string[] = []; + let editorType = EditorNames.APPLICATION; + let globalData: Record = {}; - for (const dataKey in data) { - globalData[dataKey] = true; - } + if (linterType === LINTER_TYPE.JSHINT) { + // TODO: cleanup jshint implementation once rollout is complete - // Add all js libraries - const libAccessors = ([] as string[]).concat( - ...JSLibraries.map((lib) => lib.accessor), - ); + for (const dataKey in data) { + globalData[dataKey] = true; + } - libAccessors.forEach((accessor) => (globalData[accessor] = true)); - // Add all supported web apis - objectKeys(SUPPORTED_WEB_APIS).forEach( - (apiName) => (globalData[apiName] = true), - ); + // Add all js libraries + const libAccessors = ([] as string[]).concat( + ...JSLibraries.map((lib) => lib.accessor), + ); + + libAccessors.forEach((accessor) => (globalData[accessor] = true)); + // Add all supported web apis + objectKeys(SUPPORTED_WEB_APIS).forEach( + (apiName) => (globalData[apiName] = true), + ); + } else { + globalData = { + setTimeout: "readonly", + clearTimeout: "readonly", + console: "readonly", + }; + + for (const dataKey in data) { + globalData[dataKey] = "readonly"; + + const dataValue = data[dataKey] as DataTreeEntity; + + if ( + !!dataValue && + dataValue.hasOwnProperty("ENTITY_TYPE") && + !!dataValue["ENTITY_TYPE"] + ) { + const { ENTITY_TYPE: dataValueEntityType } = dataValue; + + if (dataValueEntityType === ENTITY_TYPE.ACTION) { + asyncFunctions.push(`${dataKey}.run`); + } else if (dataValueEntityType === ENTITY_TYPE.JSACTION) { + const ignoreKeys = ["body", "ENTITY_TYPE", "actionId"]; + + for (const key in dataValue) { + if (!ignoreKeys.includes(key)) { + const value = dataValue[key]; + + if ( + typeof value === "string" && + value.startsWith("async function") + ) { + asyncFunctions.push(`${dataKey}.${key}`); + } + } + } + } else if (dataValueEntityType === ENTITY_TYPE.APPSMITH) { + const appsmithEntity: AppsmithEntity = dataValue; + + editorType = getEditorType(appsmithEntity.URL.pathname); + } + } + } - return globalData; + // Add all js libraries + const libAccessors = ([] as string[]).concat( + ...JSLibraries.map((lib) => lib.accessor), + ); + + libAccessors.forEach((accessor) => (globalData[accessor] = "readonly")); + // Add all supported web apis + objectKeys(SUPPORTED_WEB_APIS).forEach( + (apiName) => (globalData[apiName] = "readonly"), + ); + } + + return { globalData, asyncFunctions, editorType }; } function sanitizeESLintErrors( @@ -302,8 +369,17 @@ export default function getLintingErrors({ }: getLintingErrorsProps): LintError[] { const linterType = getLinterTypeFn(); const scriptPos = getEvaluationScriptPosition(scriptType); - const lintingGlobalData = generateLintingGlobalData(data); - const lintingOptions = lintOptions(lintingGlobalData, linterType); + const { + asyncFunctions, + editorType, + globalData: lintingGlobalData, + } = generateLintingGlobalData(data, linterType); + const lintingOptions = lintOptions( + lintingGlobalData, + asyncFunctions, + editorType, + linterType, + ); let messages: Linter.LintMessage[] = []; let lintErrors: LintError[] = []; diff --git a/app/client/yarn.lock b/app/client/yarn.lock index a76a9e99a625..6d3cf69e752f 100644 --- a/app/client/yarn.lock +++ b/app/client/yarn.lock @@ -10749,10 +10749,10 @@ __metadata: languageName: node linkType: hard -"@types/estree@npm:*, @types/estree@npm:1.0.5, @types/estree@npm:^1.0.0": - version: 1.0.5 - resolution: "@types/estree@npm:1.0.5" - checksum: dd8b5bed28e6213b7acd0fb665a84e693554d850b0df423ac8076cc3ad5823a6bc26b0251d080bdc545af83179ede51dd3f6fa78cad2c46ed1f29624ddf3e41a +"@types/estree@npm:*, @types/estree@npm:^1.0.0, @types/estree@npm:^1.0.6": + version: 1.0.6 + resolution: "@types/estree@npm:1.0.6" + checksum: 8825d6e729e16445d9a1dd2fb1db2edc5ed400799064cd4d028150701031af012ba30d6d03fe9df40f4d7a437d0de6d2b256020152b7b09bde9f2e420afdffd9 languageName: node linkType: hard @@ -10763,6 +10763,13 @@ __metadata: languageName: node linkType: hard +"@types/estree@npm:1.0.5": + version: 1.0.5 + resolution: "@types/estree@npm:1.0.5" + checksum: dd8b5bed28e6213b7acd0fb665a84e693554d850b0df423ac8076cc3ad5823a6bc26b0251d080bdc545af83179ede51dd3f6fa78cad2c46ed1f29624ddf3e41a + languageName: node + linkType: hard + "@types/estree@npm:^0.0.51": version: 0.0.51 resolution: "@types/estree@npm:0.0.51" @@ -13179,6 +13186,7 @@ __metadata: "@types/deep-diff": ^1.0.0 "@types/dom-view-transitions": ^1.0.5 "@types/downloadjs": ^1.4.2 + "@types/estree": ^1.0.6 "@types/google.maps": ^3.51.0 "@types/jest": ^29.5.3 "@types/jshint": ^2.12.0 From 49f93625196ee10653f56a6fdcc1761f08e10d13 Mon Sep 17 00:00:00 2001 From: Nidhi Date: Thu, 2 Jan 2025 18:05:39 +0530 Subject: [PATCH 06/40] chore: Switching to ref types and names for git (#38433) --- .../git/handler/ce/FSGitHandlerCEImpl.java | 2 +- .../external/git/constants/ce/RefType.java | 4 +- .../appsmith/external/models/Datasource.java | 2 +- ...chAwareDomain.java => RefAwareDomain.java} | 31 ++- .../external/models/ce/ActionCE_DTO.java | 7 +- .../base/ActionCollectionServiceCE.java | 8 - .../base/ActionCollectionServiceCEImpl.java | 37 +-- ...tionCollectionImportableServiceCEImpl.java | 3 +- ...ionApplicationImportableServiceCEImpl.java | 3 +- .../base/ApplicationServiceCEImpl.java | 4 +- .../git/GitApplicationHelperCEImpl.java | 13 +- .../ApplicationImportServiceCEImpl.java | 13 +- .../ConsolidatedAPIController.java | 37 ++- .../controllers/ce/PageControllerCE.java | 3 +- .../com/appsmith/server/domains/Context.java | 6 +- .../com/appsmith/server/domains/NewPage.java | 6 +- .../server/domains/ce/ActionCollectionCE.java | 8 +- .../server/domains/ce/CustomJSLibCE.java | 4 +- .../domains/ce/GitArtifactMetadataCE.java | 16 +- .../server/domains/ce/NewActionCE.java | 6 +- .../server/dtos/ClonePageMetaDTO.java | 4 +- .../server/dtos/ExportingMetaDTO.java | 2 +- .../server/dtos/ImportingMetaDTO.java | 5 +- .../com/appsmith/server/dtos/PageDTO.java | 7 +- .../server/dtos/ce/IntegrationCE_DTO.java | 5 +- .../exports/internal/ExportServiceCEImpl.java | 2 +- .../partial/PartialExportServiceCEImpl.java | 2 +- .../ApplicationForkingServiceCEImpl.java | 5 +- .../autocommit/AutoCommitServiceCEImpl.java | 18 +- .../AutoCommitEligibilityHelperImpl.java | 14 +- .../git/central/CentralGitServiceCEImpl.java | 50 ++-- .../git/common/CommonGitServiceCEImpl.java | 61 +++-- .../server/git/fs/GitFSServiceCEImpl.java | 12 +- .../server/git/utils/GitAnalyticsUtils.java | 4 +- .../com/appsmith/server/helpers/GitUtils.java | 6 +- .../helpers/ce/CommonGitFileUtilsCE.java | 12 +- .../ArtifactBasedImportableServiceCE.java | 13 +- .../imports/internal/ImportServiceCEImpl.java | 9 + .../partial/PartialImportServiceCEImpl.java | 4 +- .../db/ce/Migration057MoveDRToBaseIds.java | 12 +- .../newactions/base/NewActionServiceCE.java | 31 +-- .../base/NewActionServiceCEImpl.java | 219 +----------------- .../ActionClonePageServiceCEImpl.java | 3 +- .../NewActionImportableServiceCEImpl.java | 17 +- ...ionApplicationImportableServiceCEImpl.java | 3 +- .../newpages/base/NewPageServiceCE.java | 18 +- .../newpages/base/NewPageServiceCEImpl.java | 47 ++-- .../NewPageImportableServiceCEImpl.java | 18 +- .../CustomActionCollectionRepositoryCE.java | 4 - ...ustomActionCollectionRepositoryCEImpl.java | 11 - .../ce/CustomNewActionRepositoryCE.java | 3 - .../ce/CustomNewActionRepositoryCEImpl.java | 15 -- .../ce/CustomNewPageRepositoryCE.java | 9 +- .../ce/CustomNewPageRepositoryCEImpl.java | 36 ++- .../ce/ApplicationPageServiceCEImpl.java | 18 +- .../services/ce/ConsolidatedAPIServiceCE.java | 3 +- .../ce/ConsolidatedAPIServiceCEImpl.java | 37 +-- .../ce/CurlImporterServiceCEImpl.java | 8 - .../ce/LayoutActionServiceCEImpl.java | 3 +- .../ce/LayoutCollectionServiceCEImpl.java | 11 +- .../ce/AuthenticationServiceCEImpl.java | 28 ++- .../ce/CreateDBTablePageSolutionCEImpl.java | 12 +- .../appsmith/server/git/GitBranchesIT.java | 56 ++--- .../exports/internal/ExportServiceTests.java | 16 +- .../fork/ApplicationForkingServiceTests.java | 4 +- .../server/git/CommonGitServiceCETest.java | 60 ++--- .../git/autocommit/AutoCommitServiceTest.java | 4 +- .../AutoCommitEligibilityHelperTest.java | 2 +- .../helpers/GitAutoCommitHelperImplTest.java | 4 +- .../server/git/ops/GitConnectTests.java | 4 +- .../appsmith/server/helpers/GitUtilsTest.java | 8 +- .../imports/internal/ImportServiceTests.java | 36 +-- .../ce/RefactoringServiceCETest.java | 9 +- .../refactors/ce/RefactoringServiceTest.java | 8 +- .../ce/CustomNewPageRepositoryTest.java | 4 +- .../SearchEntitySolutionCETest.java | 2 +- .../ActionCollectionServiceImplTest.java | 17 +- .../services/ApplicationPageServiceTest.java | 4 +- .../ApplicationSnapshotServiceTest.java | 2 +- .../services/CurlImporterServiceTest.java | 15 +- .../services/LayoutActionServiceTest.java | 17 +- .../server/services/NewPageServiceTest.java | 7 +- .../server/services/PageServiceTest.java | 15 +- .../services/ce/ActionServiceCE_Test.java | 19 +- .../services/ce/ApplicationServiceCETest.java | 51 ++-- .../ce/ConsolidatedAPIServiceImplTest.java | 44 ++-- .../solutions/AuthenticationServiceTest.java | 4 +- .../CreateDBTablePageSolutionTests.java | 19 +- .../solutions/PartialExportServiceTest.java | 10 +- .../solutions/PartialImportServiceTest.java | 4 +- .../ce/ActionExecutionSolutionCETest.java | 8 +- 91 files changed, 651 insertions(+), 816 deletions(-) rename app/server/appsmith-interfaces/src/main/java/com/appsmith/external/models/{BranchAwareDomain.java => RefAwareDomain.java} (53%) diff --git a/app/server/appsmith-git/src/main/java/com/appsmith/git/handler/ce/FSGitHandlerCEImpl.java b/app/server/appsmith-git/src/main/java/com/appsmith/git/handler/ce/FSGitHandlerCEImpl.java index c488bd6c9b44..624dabcebab8 100644 --- a/app/server/appsmith-git/src/main/java/com/appsmith/git/handler/ce/FSGitHandlerCEImpl.java +++ b/app/server/appsmith-git/src/main/java/com/appsmith/git/handler/ce/FSGitHandlerCEImpl.java @@ -379,7 +379,7 @@ public Mono createAndCheckoutReference(Path repoSuffix, GitRefDTO gitRef refName, repoSuffix); - if (RefType.TAG.equals(refType)) { + if (RefType.tag.equals(refType)) { return createTag(git, gitRefDTO); } diff --git a/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/git/constants/ce/RefType.java b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/git/constants/ce/RefType.java index 28fb9762f201..4d368e600fb8 100644 --- a/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/git/constants/ce/RefType.java +++ b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/git/constants/ce/RefType.java @@ -1,6 +1,6 @@ package com.appsmith.external.git.constants.ce; public enum RefType { - BRANCH, - TAG + branch, + tag } diff --git a/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/models/Datasource.java b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/models/Datasource.java index e067733a8094..ebd105707146 100644 --- a/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/models/Datasource.java +++ b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/models/Datasource.java @@ -152,5 +152,5 @@ public void nullifyStorageReplicaFields() { this.setMessages(null); } - public static class Fields extends BranchAwareDomain.Fields {} + public static class Fields extends RefAwareDomain.Fields {} } diff --git a/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/models/BranchAwareDomain.java b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/models/RefAwareDomain.java similarity index 53% rename from app/server/appsmith-interfaces/src/main/java/com/appsmith/external/models/BranchAwareDomain.java rename to app/server/appsmith-interfaces/src/main/java/com/appsmith/external/models/RefAwareDomain.java index 8b3a9524a068..16b40bd91f50 100644 --- a/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/models/BranchAwareDomain.java +++ b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/models/RefAwareDomain.java @@ -1,5 +1,6 @@ package com.appsmith.external.models; +import com.appsmith.external.git.constants.ce.RefType; import com.appsmith.external.views.Views; import com.fasterxml.jackson.annotation.JsonView; import lombok.Getter; @@ -9,7 +10,7 @@ @Setter @Getter @FieldNameConstants -public abstract class BranchAwareDomain extends GitSyncedDomain { +public abstract class RefAwareDomain extends GitSyncedDomain { @JsonView(Views.Public.class) String baseId; @@ -17,6 +18,34 @@ public abstract class BranchAwareDomain extends GitSyncedDomain { @JsonView(Views.Internal.class) String branchName; + @JsonView(Views.Internal.class) + RefType refType; + + @JsonView(Views.Internal.class) + String refName; + + public RefType getRefType() { + if (refType == null) { + if (this.getRefName() != null) { + return RefType.branch; + } else { + return null; + } + } + return refType; + } + + public String getRefName() { + return refName == null ? branchName : refName; + } + + public void setRefName(String refName) { + this.refName = refName; + if (this.getRefType() == RefType.branch) { + this.branchName = refName; + } + } + @JsonView(Views.Internal.class) public String getBaseIdOrFallback() { return baseId == null ? this.getId() : baseId; diff --git a/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/models/ce/ActionCE_DTO.java b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/models/ce/ActionCE_DTO.java index dcd2639ec34a..fa6f2c4905a5 100644 --- a/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/models/ce/ActionCE_DTO.java +++ b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/models/ce/ActionCE_DTO.java @@ -4,6 +4,7 @@ import com.appsmith.external.dtos.DslExecutableDTO; import com.appsmith.external.dtos.LayoutExecutableUpdateDTO; import com.appsmith.external.exceptions.ErrorDTO; +import com.appsmith.external.git.constants.ce.RefType; import com.appsmith.external.helpers.Identifiable; import com.appsmith.external.models.ActionConfiguration; import com.appsmith.external.models.CreatorContextType; @@ -172,7 +173,11 @@ public class ActionCE_DTO implements Identifiable, Executable { @Transient @JsonView({Views.Internal.class}) - private String branchName; + private RefType refType; + + @Transient + @JsonView({Views.Internal.class}) + private String refName; // TODO Abhijeet: Remove this method once we have migrated all the usages of policies to policyMap /** diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/actioncollections/base/ActionCollectionServiceCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/actioncollections/base/ActionCollectionServiceCE.java index 7f44a12aea7b..8b70562597f2 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/actioncollections/base/ActionCollectionServiceCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/actioncollections/base/ActionCollectionServiceCE.java @@ -26,14 +26,9 @@ Flux findAllByApplicationIdAndViewMode( Flux saveAll(List collections); - Mono findByBaseIdAndBranchName(String id, String branchName); - Flux getPopulatedActionCollectionsByViewMode( MultiValueMap params, Boolean viewMode); - Flux getPopulatedActionCollectionsByViewMode( - MultiValueMap params, Boolean viewMode, String branchName); - Mono populateActionCollectionByViewMode( ActionCollectionDTO actionCollectionDTO1, Boolean viewMode); @@ -70,9 +65,6 @@ Flux getCollectionsByPageIdAndViewMode( Mono archiveById(String id); - Mono findByBranchNameAndBaseCollectionId( - String branchName, String baseCollectionId, AclPermission permission); - Mono> archiveActionCollectionByApplicationId(String applicationId, AclPermission permission); Flux findAllActionCollectionsByContextIdAndContextTypeAndViewMode( diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/actioncollections/base/ActionCollectionServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/actioncollections/base/ActionCollectionServiceCEImpl.java index f87bc9af4ea1..207a8ff04446 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/actioncollections/base/ActionCollectionServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/actioncollections/base/ActionCollectionServiceCEImpl.java @@ -26,7 +26,6 @@ import org.apache.commons.lang3.ObjectUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Sort; -import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.util.StringUtils; import reactor.core.observability.micrometer.Micrometer; @@ -127,12 +126,6 @@ public Flux saveAll(List collections) { return repository.saveAll(collections); } - @Override - public Mono findByBaseIdAndBranchName(String id, String branchName) { - // TODO sanitise response for default IDs - return this.findByBranchNameAndBaseCollectionId(branchName, id, actionPermission.getReadPermission()); - } - @Override public Flux getPopulatedActionCollectionsByViewMode( MultiValueMap params, Boolean viewMode) { @@ -140,16 +133,6 @@ public Flux getPopulatedActionCollectionsByViewMode( .flatMap(actionCollectionDTO -> this.populateActionCollectionByViewMode(actionCollectionDTO, viewMode)); } - @Override - public Flux getPopulatedActionCollectionsByViewMode( - MultiValueMap params, Boolean viewMode, String branchName) { - MultiValueMap updatedMap = new LinkedMultiValueMap<>(params); - if (StringUtils.hasLength(branchName)) { - updatedMap.add(FieldName.BRANCH_NAME, branchName); - } - return this.getPopulatedActionCollectionsByViewMode(updatedMap, viewMode); - } - @Override public Mono populateActionCollectionByViewMode( ActionCollectionDTO actionCollectionDTO1, Boolean viewMode) { @@ -459,23 +442,6 @@ protected Mono archiveGivenActionCollection(ActionCollection a deletedActionCollection, getAnalyticsProperties(deletedActionCollection))); } - @Override - public Mono findByBranchNameAndBaseCollectionId( - String branchName, String baseCollectionId, AclPermission permission) { - - if (StringUtils.isEmpty(baseCollectionId)) { - return Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, FieldName.COLLECTION_ID)); - } else if (StringUtils.isEmpty(branchName)) { - return this.findById(baseCollectionId, permission) - .switchIfEmpty(Mono.error(new AppsmithException( - AppsmithError.NO_RESOURCE_FOUND, FieldName.ACTION_COLLECTION, baseCollectionId))); - } - return repository - .findByBranchNameAndBaseCollectionId(branchName, baseCollectionId, permission) - .switchIfEmpty(Mono.error(new AppsmithException( - AppsmithError.ACL_NO_RESOURCE_FOUND, FieldName.ACTION_COLLECTION, baseCollectionId))); - } - @Override public Map getAnalyticsProperties(ActionCollection savedActionCollection) { final ActionCollectionDTO unpublishedCollection = savedActionCollection.getUnpublishedCollection(); @@ -546,7 +512,8 @@ protected Mono createJsAction(ActionCollection actionCollection, Acti newAction.setPolicies(actionCollectionPolicies); newActionService.setCommonFieldsFromActionDTOIntoNewAction(action, newAction); - newAction.setBranchName(actionCollection.getBranchName()); + newAction.setRefType(actionCollection.getRefType()); + newAction.setRefName(actionCollection.getRefName()); Mono sendAnalyticsMono = analyticsService.sendCreateEvent(newAction, newActionService.getAnalyticsProperties(newAction)); diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/actioncollections/importable/ActionCollectionImportableServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/actioncollections/importable/ActionCollectionImportableServiceCEImpl.java index 5586e16eb3ad..0fb942013c19 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/actioncollections/importable/ActionCollectionImportableServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/actioncollections/importable/ActionCollectionImportableServiceCEImpl.java @@ -346,7 +346,8 @@ private void updateExistingCollection( populateDomainMappedReferences(mappedImportableResourcesDTO, existingActionCollection); // Update branchName - existingActionCollection.setBranchName(importingMetaDTO.getBranchName()); + existingActionCollection.setRefType(importingMetaDTO.getRefType()); + existingActionCollection.setRefName(importingMetaDTO.getRefName()); // Recover the deleted state present in DB from imported actionCollection existingActionCollection .getUnpublishedCollection() diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/actioncollections/importable/applications/ActionCollectionApplicationImportableServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/actioncollections/importable/applications/ActionCollectionApplicationImportableServiceCEImpl.java index fd077fa62da3..0595b5abee0e 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/actioncollections/importable/applications/ActionCollectionApplicationImportableServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/actioncollections/importable/applications/ActionCollectionApplicationImportableServiceCEImpl.java @@ -102,7 +102,8 @@ public void createNewResource( // create or update base id for the action // values already set to base id are kept unchanged actionCollection.setBaseId(actionCollection.getBaseIdOrFallback()); - actionCollection.setBranchName(importingMetaDTO.getBranchName()); + actionCollection.setRefType(importingMetaDTO.getRefType()); + actionCollection.setRefName(importingMetaDTO.getRefName()); // generate gitSyncId if it's not present if (actionCollection.getGitSyncId() == null) { diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/applications/base/ApplicationServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/applications/base/ApplicationServiceCEImpl.java index afd1ad6335a6..84112ee414ee 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/applications/base/ApplicationServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/applications/base/ApplicationServiceCEImpl.java @@ -308,10 +308,10 @@ public Mono update(String id, Application application) { Mono applicationIdMono; GitArtifactMetadata gitData = application.getGitApplicationMetadata(); if (gitData != null - && !StringUtils.isEmpty(gitData.getBranchName()) + && !StringUtils.isEmpty(gitData.getRefName()) && !StringUtils.isEmpty(gitData.getDefaultArtifactId())) { applicationIdMono = this.findByBranchNameAndBaseApplicationId( - gitData.getBranchName(), + gitData.getRefName(), gitData.getDefaultArtifactId(), applicationPermission.getEditPermission()) .map(Application::getId); diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/applications/git/GitApplicationHelperCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/applications/git/GitApplicationHelperCEImpl.java index 8b15d289ee26..0219547cd849 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/applications/git/GitApplicationHelperCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/applications/git/GitApplicationHelperCEImpl.java @@ -120,7 +120,7 @@ public Mono getSshKeys(String baseArtifactId) { @Override public Mono createNewArtifactForCheckout(Artifact sourceArtifact, String branchName) { GitArtifactMetadata sourceBranchGitData = sourceArtifact.getGitArtifactMetadata(); - sourceBranchGitData.setBranchName(branchName); + sourceBranchGitData.setRefName(branchName); sourceBranchGitData.setIsRepoPrivate(null); // Save new artifact in DB and update from the parent branch application sourceBranchGitData.setGitAuth(null); @@ -260,7 +260,8 @@ public Mono disconnectEntitiesOfBaseArtifact(Artifact baseArtifact) .flatMap(page -> newPageService.findById(page.getId(), null)) .map(newPage -> { newPage.setBaseId(newPage.getId()); - newPage.setBranchName(null); + newPage.setRefType(null); + newPage.setRefName(null); return newPage; }) .collectList() @@ -272,7 +273,8 @@ public Mono disconnectEntitiesOfBaseArtifact(Artifact baseArtifact) .findByPageId(newPage.getId(), Optional.empty()) .map(newAction -> { newAction.setBaseId(newAction.getId()); - newAction.setBranchName(null); + newAction.setRefType(null); + newAction.setRefName(null); return newAction; }) .collectList() @@ -284,7 +286,8 @@ public Mono disconnectEntitiesOfBaseArtifact(Artifact baseArtifact) .findByPageId(newPage.getId()) .map(actionCollection -> { actionCollection.setBaseId(actionCollection.getId()); - actionCollection.setBranchName(null); + actionCollection.setRefType(null); + actionCollection.setRefName(null); return actionCollection; }) .collectList() @@ -334,7 +337,7 @@ public Mono publishArtifactPostRefCreation( Artifact artifact, RefType refType, Boolean isPublishedManually) { // TODO: create publish for ref type creation. Application application = (Application) artifact; - if (RefType.TAG.equals(refType)) { + if (RefType.tag.equals(refType)) { return Mono.just(application); } 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 3d0703c82582..1ab22bc3d8f5 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 @@ -460,12 +460,6 @@ public Mono updateAndSaveArtifactInContext( } } return importApplicationMono - .doOnNext(application -> { - if (application.getGitArtifactMetadata() != null) { - importingMetaDTO.setBranchName( - application.getGitArtifactMetadata().getBranchName()); - } - }) .elapsed() .map(tuples -> { log.debug("time to create or update application object: {}", tuples.getT1()); @@ -654,14 +648,13 @@ public Mono migrateArtifactExchangeJson( return applicationService.findById(branchedArtifactId).flatMap(application -> { String baseArtifactId = application.getBaseId(); - String branchName = null; + String refName = null; if (application.getGitArtifactMetadata() != null) { - branchName = application.getGitArtifactMetadata().getBranchName(); + refName = application.getGitArtifactMetadata().getRefName(); } - return jsonSchemaMigration.migrateApplicationJsonToLatestSchema( - applicationJson, baseArtifactId, branchName); + return jsonSchemaMigration.migrateApplicationJsonToLatestSchema(applicationJson, baseArtifactId, refName); }); } } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/controllers/ConsolidatedAPIController.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/controllers/ConsolidatedAPIController.java index ee2b15db4504..67eea1fc09c0 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/controllers/ConsolidatedAPIController.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/controllers/ConsolidatedAPIController.java @@ -1,5 +1,6 @@ package com.appsmith.server.controllers; +import com.appsmith.external.git.constants.ce.RefType; import com.appsmith.external.views.Views; import com.appsmith.server.constants.FieldName; import com.appsmith.server.constants.Url; @@ -11,6 +12,7 @@ import io.micrometer.observation.ObservationRegistry; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; +import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestMapping; @@ -47,22 +49,30 @@ public ConsolidatedAPIController( public Mono> getAllDataForFirstPageLoadForEditMode( @RequestParam(name = FieldName.APPLICATION_ID, required = false) String baseApplicationId, @RequestParam(name = "defaultPageId", required = false) String basePageId, + @RequestHeader(required = false, defaultValue = "branch") RefType refType, + @RequestHeader(required = false) String refName, @RequestHeader(required = false) String branchName) { + + if (!StringUtils.hasLength(refName)) { + refName = branchName; + } log.debug( - "Going to fetch consolidatedAPI response for baseApplicationId: {}, basePageId: {}, branchName: {}, " + "Going to fetch consolidatedAPI response for baseApplicationId: {}, basePageId: {}, {}: {}, " + "mode: {}", baseApplicationId, basePageId, - branchName, + refType, + refName, ApplicationMode.EDIT); return consolidatedAPIService - .getConsolidatedInfoForPageLoad(basePageId, baseApplicationId, branchName, ApplicationMode.EDIT) + .getConsolidatedInfoForPageLoad(basePageId, baseApplicationId, refType, refName, ApplicationMode.EDIT) .map(consolidatedAPIResponseDTO -> new ResponseDTO<>(HttpStatus.OK.value(), consolidatedAPIResponseDTO, null)) .tag("pageId", Objects.toString(basePageId)) .tag("applicationId", Objects.toString(baseApplicationId)) - .tag("branchName", Objects.toString(branchName)) + .tag("refType", Objects.toString(refType)) + .tag("refName", Objects.toString(refName)) .name(CONSOLIDATED_API_ROOT_EDIT) .tap(Micrometer.observation(observationRegistry)); } @@ -72,22 +82,31 @@ public Mono> getAllDataForFirstPageLoadF public Mono> getAllDataForFirstPageLoadForViewMode( @RequestParam(required = false) String applicationId, @RequestParam(required = false) String defaultPageId, - @RequestHeader(name = FieldName.BRANCH_NAME, required = false) String branchName) { + @RequestHeader(required = false, defaultValue = "branch") RefType refType, + @RequestHeader(required = false) String refName, + @RequestHeader(required = false) String branchName) { + + if (!StringUtils.hasLength(refName)) { + refName = branchName; + } log.debug( - "Going to fetch consolidatedAPI response for applicationId: {}, defaultPageId: {}, branchName: {}, " + "Going to fetch consolidatedAPI response for applicationId: {}, defaultPageId: {}, {}: {}, " + "mode: {}", applicationId, defaultPageId, - branchName, + refType, + refName, ApplicationMode.PUBLISHED); return consolidatedAPIService - .getConsolidatedInfoForPageLoad(defaultPageId, applicationId, branchName, ApplicationMode.PUBLISHED) + .getConsolidatedInfoForPageLoad( + defaultPageId, applicationId, refType, refName, ApplicationMode.PUBLISHED) .map(consolidatedAPIResponseDTO -> new ResponseDTO<>(HttpStatus.OK.value(), consolidatedAPIResponseDTO, null)) .tag("pageId", Objects.toString(defaultPageId)) .tag("applicationId", Objects.toString(applicationId)) - .tag("branchName", Objects.toString(branchName)) + .tag("refType", Objects.toString(refType)) + .tag("refName", Objects.toString(refName)) .name(CONSOLIDATED_API_ROOT_VIEW) .tap(Micrometer.observation(observationRegistry)); } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/controllers/ce/PageControllerCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/controllers/ce/PageControllerCE.java index 16f0f321f5c2..1985ce71d9dc 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/controllers/ce/PageControllerCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/controllers/ce/PageControllerCE.java @@ -1,5 +1,6 @@ package com.appsmith.server.controllers.ce; +import com.appsmith.external.git.constants.ce.RefType; import com.appsmith.external.views.Views; import com.appsmith.server.constants.FieldName; import com.appsmith.server.constants.Url; @@ -189,7 +190,7 @@ public Mono> updateDependencyMap( @RequestBody(required = false) Map> dependencyMap, @RequestHeader(name = FieldName.BRANCH_NAME, required = false) String branchName) { return newPageService - .updateDependencyMap(defaultPageId, dependencyMap, branchName) + .updateDependencyMap(defaultPageId, dependencyMap, RefType.branch, branchName) .map(updatedResource -> new ResponseDTO<>(HttpStatus.OK.value(), updatedResource, null)); } } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/domains/Context.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/domains/Context.java index 7536e1b10102..cffae91dd329 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/domains/Context.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/domains/Context.java @@ -1,5 +1,7 @@ package com.appsmith.server.domains; +import com.appsmith.external.git.constants.ce.RefType; + public interface Context { String getId(); @@ -8,7 +10,9 @@ public interface Context { Layout getLayout(); - String getBranchName(); + RefType getRefType(); + + String getRefName(); String getUnpublishedName(); } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/domains/NewPage.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/domains/NewPage.java index dec5d5239005..8b050a6db5a5 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/domains/NewPage.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/domains/NewPage.java @@ -1,6 +1,6 @@ package com.appsmith.server.domains; -import com.appsmith.external.models.BranchAwareDomain; +import com.appsmith.external.models.RefAwareDomain; import com.appsmith.external.views.Git; import com.appsmith.external.views.Views; import com.appsmith.server.dtos.PageDTO; @@ -18,7 +18,7 @@ @NoArgsConstructor @Document @FieldNameConstants -public class NewPage extends BranchAwareDomain implements Context { +public class NewPage extends RefAwareDomain implements Context { @JsonView(Views.Public.class) String applicationId; @@ -66,7 +66,7 @@ public String getUnpublishedName() { return this.getUnpublishedPage().getName(); } - public static class Fields extends BranchAwareDomain.Fields { + public static class Fields extends RefAwareDomain.Fields { public static String unpublishedPage_layouts = unpublishedPage + "." + PageDTO.Fields.layouts; public static String unpublishedPage_name = unpublishedPage + "." + PageDTO.Fields.name; public static String unpublishedPage_icon = unpublishedPage + "." + PageDTO.Fields.icon; diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/domains/ce/ActionCollectionCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/domains/ce/ActionCollectionCE.java index 7eb005d1efc2..0540f0b937e8 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/domains/ce/ActionCollectionCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/domains/ce/ActionCollectionCE.java @@ -1,7 +1,7 @@ package com.appsmith.server.domains.ce; -import com.appsmith.external.models.BranchAwareDomain; import com.appsmith.external.models.CreatorContextType; +import com.appsmith.external.models.RefAwareDomain; import com.appsmith.external.views.Git; import com.appsmith.external.views.Views; import com.appsmith.server.dtos.ActionCollectionDTO; @@ -21,8 +21,8 @@ @Setter @ToString @FieldNameConstants -public class ActionCollectionCE extends BranchAwareDomain { - // Default resources from BranchAwareDomain will be used to store branchName, defaultApplicationId and +public class ActionCollectionCE extends RefAwareDomain { + // Default resources from RefAwareDomain will be used to store branchName, defaultApplicationId and // defaultActionCollectionId @JsonView(Views.Public.class) String applicationId; @@ -52,7 +52,7 @@ public void sanitiseToExportDBObject() { super.sanitiseToExportDBObject(); } - public static class Fields extends BranchAwareDomain.Fields { + public static class Fields extends RefAwareDomain.Fields { public static final String publishedCollection_name = dotted(publishedCollection, ActionCollectionDTO.Fields.name); public static final String unpublishedCollection_name = diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/domains/ce/CustomJSLibCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/domains/ce/CustomJSLibCE.java index 428f96f1cd87..2b76aabbda79 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/domains/ce/CustomJSLibCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/domains/ce/CustomJSLibCE.java @@ -1,7 +1,7 @@ package com.appsmith.server.domains.ce; import com.appsmith.external.models.BaseDomain; -import com.appsmith.external.models.BranchAwareDomain; +import com.appsmith.external.models.RefAwareDomain; import com.appsmith.external.views.Git; import com.appsmith.external.views.Views; import com.appsmith.server.helpers.CollectionUtils; @@ -124,5 +124,5 @@ public void sanitiseToExportDBObject() { this.setUpdatedAt(null); } - public static class Fields extends BranchAwareDomain.Fields {} + public static class Fields extends RefAwareDomain.Fields {} } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/domains/ce/GitArtifactMetadataCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/domains/ce/GitArtifactMetadataCE.java index f0988e8956c8..546e60d033b5 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/domains/ce/GitArtifactMetadataCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/domains/ce/GitArtifactMetadataCE.java @@ -21,19 +21,16 @@ @Data @FieldNameConstants public class GitArtifactMetadataCE implements AppsmithDomain { + // Git branch corresponding to this application, we have one to one mapping for application in DB with git-branch @JsonView(Views.Public.class) String branchName; - // TODO: make this public view and remove transient annotation once implmentation completes - @Transient @JsonView(Views.Internal.class) - String refName; + RefType refType; - // TODO: make this public view and remove transient annotation once implementation completes - @Transient @JsonView(Views.Internal.class) - RefType refType; + String refName; // Git default branch corresponding to the remote git repo to which the application is connected to @JsonView(Views.Public.class) @@ -130,16 +127,21 @@ public void setDefaultApplicationId(String defaultApplicationId) { this.defaultArtifactId = defaultApplicationId; } + public RefType getRefType() { + return refType == null ? RefType.branch : refType; + } + /** * this returns the branchName instead of reference name * @return returns the ref name. */ public String getRefName() { - return this.getBranchName(); + return this.refName == null ? this.branchName : this.refName; } public void setRefName(String refName) { this.branchName = refName; + this.refName = refName; } public static class Fields {} diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/domains/ce/NewActionCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/domains/ce/NewActionCE.java index 8751c3c335f5..f4dfd4823d23 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/domains/ce/NewActionCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/domains/ce/NewActionCE.java @@ -2,10 +2,10 @@ import com.appsmith.external.models.ActionConfiguration; import com.appsmith.external.models.ActionDTO; -import com.appsmith.external.models.BranchAwareDomain; import com.appsmith.external.models.Datasource; import com.appsmith.external.models.Documentation; import com.appsmith.external.models.PluginType; +import com.appsmith.external.models.RefAwareDomain; import com.appsmith.external.views.Git; import com.appsmith.external.views.Views; import com.fasterxml.jackson.annotation.JsonView; @@ -20,7 +20,7 @@ @Setter @ToString @FieldNameConstants -public class NewActionCE extends BranchAwareDomain { +public class NewActionCE extends RefAwareDomain { // Fields in action that are not allowed to change between published and unpublished versions @JsonView(Views.Public.class) @@ -61,7 +61,7 @@ public void sanitiseToExportDBObject() { super.sanitiseToExportDBObject(); } - public static class Fields extends BranchAwareDomain.Fields { + public static class Fields extends RefAwareDomain.Fields { public static final String unpublishedAction_datasource_id = dotted(unpublishedAction, ActionDTO.Fields.datasource, Datasource.Fields.id); public static final String unpublishedAction_name = dotted(unpublishedAction, ActionDTO.Fields.name); diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/dtos/ClonePageMetaDTO.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/dtos/ClonePageMetaDTO.java index b8d37d15e8f4..fb1fad9ee0ef 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/dtos/ClonePageMetaDTO.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/dtos/ClonePageMetaDTO.java @@ -1,5 +1,6 @@ package com.appsmith.server.dtos; +import com.appsmith.external.git.constants.ce.RefType; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -15,6 +16,7 @@ public class ClonePageMetaDTO { String branchedSourcePageId; PageDTO clonedPageDTO; - String branchName; + RefType refType; + String refName; Map oldToNewCollectionIds = new HashMap<>(); } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/dtos/ExportingMetaDTO.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/dtos/ExportingMetaDTO.java index c37a8ec24f12..84ded5d71d47 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/dtos/ExportingMetaDTO.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/dtos/ExportingMetaDTO.java @@ -15,7 +15,7 @@ public class ExportingMetaDTO { String artifactType; String artifactId; - String branchName; + String refName; Boolean isGitSync; Boolean exportWithConfiguration; diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/dtos/ImportingMetaDTO.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/dtos/ImportingMetaDTO.java index b706e23c0bae..4b231ef5c074 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/dtos/ImportingMetaDTO.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/dtos/ImportingMetaDTO.java @@ -1,5 +1,6 @@ package com.appsmith.server.dtos; +import com.appsmith.external.git.constants.ce.RefType; import com.appsmith.server.helpers.ImportArtifactPermissionProvider; import lombok.AllArgsConstructor; import lombok.Builder; @@ -22,7 +23,9 @@ public class ImportingMetaDTO { */ String artifactId; - String branchName; + RefType refType; + + String refName; List branchedArtifactIds; diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/dtos/PageDTO.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/dtos/PageDTO.java index 816f82b28689..7bd8d3d0f6de 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/dtos/PageDTO.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/dtos/PageDTO.java @@ -1,5 +1,6 @@ package com.appsmith.server.dtos; +import com.appsmith.external.git.constants.ce.RefType; import com.appsmith.external.models.Policy; import com.appsmith.external.views.Git; import com.appsmith.external.views.Views; @@ -78,7 +79,11 @@ public class PageDTO { @Transient @JsonView({Views.Internal.class}) - String branchName; + RefType refType; + + @Transient + @JsonView({Views.Internal.class}) + String refName; @JsonView(Views.Public.class) Map> dependencyMap; diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/dtos/ce/IntegrationCE_DTO.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/dtos/ce/IntegrationCE_DTO.java index 9066ffc268db..5bc8e9a93370 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/dtos/ce/IntegrationCE_DTO.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/dtos/ce/IntegrationCE_DTO.java @@ -1,5 +1,6 @@ package com.appsmith.server.dtos.ce; +import com.appsmith.external.git.constants.ce.RefType; import com.appsmith.external.models.AuthenticationResponse; import com.appsmith.external.models.CreatorContextType; import com.fasterxml.jackson.annotation.JsonProperty; @@ -38,7 +39,9 @@ public class IntegrationCE_DTO { String redirectionDomain; - String branch; + RefType refType; + + String refName; String importForGit; diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/exports/internal/ExportServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/exports/internal/ExportServiceCEImpl.java index b430db8c64f3..7da363b55e5e 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/exports/internal/ExportServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/exports/internal/ExportServiceCEImpl.java @@ -135,7 +135,7 @@ public Mono exportByExportableArtifactIdAndBranc // from here exportingMetaDTO.setArtifactType(artifactContextConstantMap.get(ARTIFACT_CONTEXT)); exportingMetaDTO.setArtifactId(transactionArtifact.getId()); - exportingMetaDTO.setBranchName(null); + exportingMetaDTO.setRefName(null); exportingMetaDTO.setIsGitSync(isGitSync); exportingMetaDTO.setExportWithConfiguration(exportWithConfiguration); diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/exports/internal/partial/PartialExportServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/exports/internal/partial/PartialExportServiceCEImpl.java index 2fd276dc31d8..05325c77e904 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/exports/internal/partial/PartialExportServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/exports/internal/partial/PartialExportServiceCEImpl.java @@ -72,7 +72,7 @@ public Mono getPartialExportResources( exportingMetaDTO.setArtifactType(FieldName.APPLICATION); exportingMetaDTO.setArtifactId(branchedApplicationId); - exportingMetaDTO.setBranchName(null); + exportingMetaDTO.setRefName(null); exportingMetaDTO.setIsGitSync(false); exportingMetaDTO.setExportWithConfiguration(false); diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/fork/internal/ApplicationForkingServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/fork/internal/ApplicationForkingServiceCEImpl.java index 48b66a44e1b8..62fc9d9bdec4 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/fork/internal/ApplicationForkingServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/fork/internal/ApplicationForkingServiceCEImpl.java @@ -268,7 +268,8 @@ public Mono> forkApplications( newAction.getId()); action.setPageId(savedPage.getId()); action.setBaseId(null); - action.setBranchName(null); + action.setRefType(null); + action.setRefName(null); return newAction; }) .flatMap(newAction -> { @@ -505,7 +506,7 @@ public Mono forkApplicationToWorkspace( if ((application.getGitApplicationMetadata() == null) || application .getGitApplicationMetadata() - .getBranchName() + .getRefName() .equals(application .getGitApplicationMetadata() .getDefaultBranchName())) { diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/autocommit/AutoCommitServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/autocommit/AutoCommitServiceCEImpl.java index 5115c99f08fd..4713c8401779 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/autocommit/AutoCommitServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/autocommit/AutoCommitServiceCEImpl.java @@ -82,9 +82,9 @@ public Mono autoCommitApplication(String branchedApplicat String workspaceId = branchedApplication.getWorkspaceId(); GitArtifactMetadata branchedGitMetadata = branchedApplication.getGitArtifactMetadata(); final String baseApplicationId = branchedGitMetadata.getDefaultArtifactId(); - final String branchName = branchedGitMetadata.getBranchName(); + final String refName = branchedGitMetadata.getRefName(); - if (!hasText(branchName)) { + if (!hasText(refName)) { return Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, FieldName.BRANCH_NAME)); } @@ -92,14 +92,14 @@ public Mono autoCommitApplication(String branchedApplicat autoCommitEligibilityHelper.isAutoCommitRequired(workspaceId, branchedGitMetadata, pageDTO); Mono autoCommitProgressDTOMono = - gitAutoCommitHelper.getAutoCommitProgress(baseApplicationId, branchName); + gitAutoCommitHelper.getAutoCommitProgress(baseApplicationId, refName); return autoCommitProgressDTOMono.flatMap(autoCommitProgressDTO -> { if (Set.of(LOCKED, IN_PROGRESS).contains(autoCommitProgressDTO.getAutoCommitResponse())) { log.info( "application with id: {}, has requested auto-commit for branch name: {}, however an event for branch name: {} is already in progress", baseApplicationId, - branchName, + refName, autoCommitProgressDTO.getBranchName()); autoCommitResponseDTO.setAutoCommitResponse(autoCommitProgressDTO.getAutoCommitResponse()); autoCommitResponseDTO.setProgress(autoCommitProgressDTO.getProgress()); @@ -112,7 +112,7 @@ public Mono autoCommitApplication(String branchedApplicat log.info( "application with id: {}, and branch name: {} is not eligible for autocommit", baseApplicationId, - branchName); + refName); autoCommitResponseDTO.setAutoCommitResponse(IDLE); return Mono.just(autoCommitResponseDTO); } @@ -121,15 +121,15 @@ public Mono autoCommitApplication(String branchedApplicat log.info( "application with id: {}, and branch name: {} is eligible for autocommit", baseApplicationId, - branchName); + refName); return gitAutoCommitHelper - .publishAutoCommitEvent(autoCommitTriggerDTO, baseApplicationId, branchName) + .publishAutoCommitEvent(autoCommitTriggerDTO, baseApplicationId, refName) .map(isEventPublished -> { if (TRUE.equals(isEventPublished)) { log.info( "autocommit event for application with id: {}, and branch name: {} is published", baseApplicationId, - branchName); + refName); autoCommitResponseDTO.setAutoCommitResponse(PUBLISHED); return autoCommitResponseDTO; } @@ -137,7 +137,7 @@ public Mono autoCommitApplication(String branchedApplicat log.info( "application with id: {}, and branch name: {} does not fulfil the prerequisite for autocommit", baseApplicationId, - branchName); + refName); autoCommitResponseDTO.setAutoCommitResponse(REQUIRED); return autoCommitResponseDTO; }); diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/autocommit/helpers/AutoCommitEligibilityHelperImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/autocommit/helpers/AutoCommitEligibilityHelperImpl.java index c8958c5c4ae2..2c18be3b1702 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/autocommit/helpers/AutoCommitEligibilityHelperImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/autocommit/helpers/AutoCommitEligibilityHelperImpl.java @@ -36,7 +36,7 @@ public class AutoCommitEligibilityHelperImpl implements AutoCommitEligibilityHel public Mono isServerAutoCommitRequired(String workspaceId, GitArtifactMetadata gitMetadata) { String defaultApplicationId = gitMetadata.getDefaultArtifactId(); - String branchName = gitMetadata.getBranchName(); + String refName = gitMetadata.getRefName(); Mono isServerMigrationRequiredMonoCached = commonGitFileUtils .getMetadataServerSchemaMigrationVersion(workspaceId, gitMetadata, FALSE, APPLICATION) @@ -44,7 +44,7 @@ public Mono isServerAutoCommitRequired(String workspaceId, GitArtifactM log.info( "server schema for application id : {} and branch name : {} is : {}", defaultApplicationId, - branchName, + refName, serverSchemaVersion); return jsonSchemaVersions.getServerVersion() > serverSchemaVersion ? TRUE : FALSE; }) @@ -53,9 +53,9 @@ public Mono isServerAutoCommitRequired(String workspaceId, GitArtifactM return Mono.defer(() -> isServerMigrationRequiredMonoCached).onErrorResume(error -> { log.debug( - "error while retrieving the metadata for defaultApplicationId : {}, branchName : {} error : {}", + "error while retrieving the metadata for defaultApplicationId : {}, refName : {} error : {}", defaultApplicationId, - branchName, + refName, error.getMessage()); return Mono.just(FALSE); }); @@ -93,7 +93,7 @@ public Mono isClientMigrationRequired(PageDTO pageDTO) { public Mono isClientMigrationRequiredFSOps( String workspaceId, GitArtifactMetadata gitMetadata, PageDTO pageDTO) { String defaultApplicationId = gitMetadata.getDefaultArtifactId(); - String branchName = gitMetadata.getBranchName(); + String refName = gitMetadata.getRefName(); Mono latestDslVersionMono = dslMigrationUtils.getLatestDslVersion(); @@ -111,10 +111,10 @@ public Mono isClientMigrationRequiredFSOps( return Mono.defer(() -> isClientMigrationRequired).onErrorResume(error -> { log.debug( - "error while fetching the dsl version for page : {}, defaultApplicationId : {}, branchName : {} error : {}", + "error while fetching the dsl version for page : {}, defaultApplicationId : {}, refName : {} error : {}", pageDTO.getName(), defaultApplicationId, - branchName, + refName, error.getMessage()); return Mono.just(FALSE); }); diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCEImpl.java index 970860a9b268..bfb33678dc7e 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCEImpl.java @@ -208,7 +208,7 @@ public Mono importArtifactFromGit( gitArtifactMetadata.setGitAuth(gitAuth); gitArtifactMetadata.setDefaultArtifactId(artifact.getId()); gitArtifactMetadata.setDefaultBranchName(defaultBranch); - gitArtifactMetadata.setBranchName(defaultBranch); + gitArtifactMetadata.setRefName(defaultBranch); gitArtifactMetadata.setRepoName(repoName); gitArtifactMetadata.setIsRepoPrivate(isRepoPrivate); gitArtifactMetadata.setLastCommittedAt(Instant.now()); @@ -236,7 +236,7 @@ public Mono importArtifactFromGit( jsonMorphDTO.setBaseArtifactId(artifact.getId()); jsonMorphDTO.setArtifactType(artifactType); jsonMorphDTO.setRepoName(gitArtifactMetadata.getRepoName()); - jsonMorphDTO.setRefType(RefType.BRANCH); + jsonMorphDTO.setRefType(RefType.branch); jsonMorphDTO.setRefName(defaultBranch); Mono artifactExchangeJsonMono = gitHandlingService @@ -490,7 +490,7 @@ private Mono checkoutRemoteReference( final String repoName = baseGitMetadata.getRepoName(); final String baseArtifactId = baseGitMetadata.getDefaultArtifactId(); - final String baseBranchName = baseGitMetadata.getBranchName(); + final String baseRefName = baseGitMetadata.getRefName(); final String workspaceId = baseArtifact.getWorkspaceId(); final String finalRemoteRefName = gitRefDTO.getRefName().replaceFirst(ORIGIN, REMOTE_NAME_REPLACEMENT); @@ -503,7 +503,7 @@ private Mono checkoutRemoteReference( jsonTransformationDTO.setArtifactType(baseArtifact.getArtifactType()); Mono artifactMono; - if (baseBranchName.equals(finalRemoteRefName)) { + if (baseRefName.equals(finalRemoteRefName)) { /* in this case, user deleted the initial default branch and now wants to check out to that branch. as we didn't delete the application object but only the branch from git repo, @@ -702,7 +702,7 @@ protected Mono createReference( protected Mono isValidationForRefCreationComplete( Artifact baseArtifact, Artifact parentArtifact, GitType gitType, RefType refType) { - if (RefType.BRANCH.equals(refType)) { + if (RefType.branch.equals(refType)) { return Mono.just(TRUE); } @@ -1016,7 +1016,7 @@ public Mono connectArtifactToGit( GitArtifactMetadata gitArtifactMetadata = artifact.getGitArtifactMetadata(); gitArtifactMetadata.setDefaultArtifactId(artifactId); - gitArtifactMetadata.setBranchName(defaultBranch); + gitArtifactMetadata.setRefName(defaultBranch); gitArtifactMetadata.setDefaultBranchName(defaultBranch); gitArtifactMetadata.setRepoName(repoName); gitArtifactMetadata.setIsRepoPrivate(isRepoPrivate); @@ -1214,7 +1214,7 @@ private Mono commitArtifact( return Mono.error(new AppsmithException(AppsmithError.INVALID_GIT_CONFIGURATION, GIT_CONFIG_ERROR)); } - final String branchName = branchedGitMetadata.getBranchName(); + final String branchName = branchedGitMetadata.getRefName(); if (!hasText(branchName)) { return Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, FieldName.BRANCH_NAME)); } @@ -1275,7 +1275,7 @@ private Mono commitArtifact( }) .flatMap(artifact -> { String errorEntity = ""; - if (!StringUtils.hasText(branchedGitMetadata.getBranchName())) { + if (!StringUtils.hasText(branchedGitMetadata.getRefName())) { errorEntity = "branch name"; } else if (!StringUtils.hasText(branchedGitMetadata.getDefaultArtifactId())) { errorEntity = "default artifact"; @@ -1293,14 +1293,14 @@ private Mono commitArtifact( }) .flatMap(artifactExchangeJson -> { ArtifactJsonTransformationDTO jsonTransformationDTO = new ArtifactJsonTransformationDTO(); - jsonTransformationDTO.setRefType(RefType.BRANCH); + jsonTransformationDTO.setRefType(RefType.branch); jsonTransformationDTO.setWorkspaceId(baseArtifact.getWorkspaceId()); jsonTransformationDTO.setBaseArtifactId(baseArtifact.getId()); jsonTransformationDTO.setRepoName( branchedArtifact.getGitArtifactMetadata().getRepoName()); jsonTransformationDTO.setArtifactType(artifactExchangeJson.getArtifactJsonType()); jsonTransformationDTO.setRefName( - branchedArtifact.getGitArtifactMetadata().getBranchName()); + branchedArtifact.getGitArtifactMetadata().getRefName()); return gitHandlingService .prepareChangesToBeCommitted(jsonTransformationDTO, artifactExchangeJson) @@ -1309,12 +1309,12 @@ private Mono commitArtifact( .flatMap(updatedBranchedArtifact -> { GitArtifactMetadata gitArtifactMetadata = updatedBranchedArtifact.getGitArtifactMetadata(); ArtifactJsonTransformationDTO jsonTransformationDTO = new ArtifactJsonTransformationDTO(); - jsonTransformationDTO.setRefType(RefType.BRANCH); + jsonTransformationDTO.setRefType(RefType.branch); jsonTransformationDTO.setWorkspaceId(updatedBranchedArtifact.getWorkspaceId()); jsonTransformationDTO.setBaseArtifactId(gitArtifactMetadata.getDefaultArtifactId()); jsonTransformationDTO.setRepoName(gitArtifactMetadata.getRepoName()); jsonTransformationDTO.setArtifactType(branchedArtifact.getArtifactType()); - jsonTransformationDTO.setRefName(gitArtifactMetadata.getBranchName()); + jsonTransformationDTO.setRefName(gitArtifactMetadata.getRefName()); return gitHandlingService .commitArtifact(updatedBranchedArtifact, commitDTO, jsonTransformationDTO) @@ -1362,7 +1362,7 @@ private Mono commitArtifact( log.error( "An error occurred while committing changes to artifact with base id: {} and branch: {}", branchedGitMetadata.getDefaultArtifactId(), - branchedGitMetadata.getBranchName()); + branchedGitMetadata.getRefName()); return gitRedisUtils .releaseFileLock(artifactType, branchedGitMetadata.getDefaultArtifactId(), TRUE) @@ -1404,12 +1404,12 @@ public Mono detachRemote( GitArtifactMetadata gitArtifactMetadata = baseArtifact.getGitArtifactMetadata(); ArtifactJsonTransformationDTO jsonTransformationDTO = new ArtifactJsonTransformationDTO(); - jsonTransformationDTO.setRefType(RefType.BRANCH); + jsonTransformationDTO.setRefType(RefType.branch); jsonTransformationDTO.setWorkspaceId(baseArtifact.getWorkspaceId()); jsonTransformationDTO.setBaseArtifactId(gitArtifactMetadata.getDefaultArtifactId()); jsonTransformationDTO.setRepoName(gitArtifactMetadata.getRepoName()); jsonTransformationDTO.setArtifactType(baseArtifact.getArtifactType()); - jsonTransformationDTO.setRefName(gitArtifactMetadata.getBranchName()); + jsonTransformationDTO.setRefName(gitArtifactMetadata.getRefName()); // Remove the git contents from file system return Mono.zip(gitHandlingService.listBranches(jsonTransformationDTO), Mono.just(baseArtifact)); @@ -1423,12 +1423,12 @@ public Mono detachRemote( GitArtifactMetadata gitArtifactMetadata = baseArtifact.getGitArtifactMetadata(); ArtifactJsonTransformationDTO jsonTransformationDTO = new ArtifactJsonTransformationDTO(); - jsonTransformationDTO.setRefType(RefType.BRANCH); + jsonTransformationDTO.setRefType(RefType.branch); jsonTransformationDTO.setWorkspaceId(baseArtifact.getWorkspaceId()); jsonTransformationDTO.setBaseArtifactId(gitArtifactMetadata.getDefaultArtifactId()); jsonTransformationDTO.setRepoName(gitArtifactMetadata.getRepoName()); jsonTransformationDTO.setArtifactType(baseArtifact.getArtifactType()); - jsonTransformationDTO.setRefName(gitArtifactMetadata.getBranchName()); + jsonTransformationDTO.setRefName(gitArtifactMetadata.getRefName()); // Remove the parent application branch name from the list Mono removeRepoMono = gitHandlingService.removeRepository(jsonTransformationDTO); @@ -1515,7 +1515,7 @@ protected Mono getStatus( GitArtifactMetadata branchedGitMetadata = branchedArtifact.getGitArtifactMetadata(); branchedGitMetadata.setGitAuth(baseGitMetadata.getGitAuth()); - final String finalBranchName = branchedGitMetadata.getBranchName(); + final String finalBranchName = branchedGitMetadata.getRefName(); if (!StringUtils.hasText(finalBranchName)) { return Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, FieldName.BRANCH_NAME)); @@ -1533,7 +1533,7 @@ protected Mono getStatus( }) .flatMap(artifactExchangeJson -> { ArtifactJsonTransformationDTO jsonTransformationDTO = new ArtifactJsonTransformationDTO(); - jsonTransformationDTO.setRefType(RefType.BRANCH); + jsonTransformationDTO.setRefType(RefType.branch); jsonTransformationDTO.setWorkspaceId(baseArtifact.getWorkspaceId()); jsonTransformationDTO.setBaseArtifactId(baseArtifact.getId()); jsonTransformationDTO.setRepoName( @@ -1547,7 +1547,7 @@ protected Mono getStatus( if (compareRemote) { fetchRemoteMono = Mono.defer( - () -> fetchRemoteChanges(baseArtifact, branchedArtifact, FALSE, gitType, RefType.BRANCH) + () -> fetchRemoteChanges(baseArtifact, branchedArtifact, FALSE, gitType, RefType.branch) .onErrorResume(error -> Mono.error(new AppsmithException( AppsmithError.GIT_GENERIC_ERROR, error.getMessage())))); } else { @@ -1667,7 +1667,7 @@ protected Mono pullArtifact(Artifact baseArtifact, Artifact branched log.error( "An error occurred while trying to pull the artifact with base id: {} and branchName: {}", branchedGitMetadata.getDefaultArtifactId(), - branchedGitMetadata.getBranchName()); + branchedGitMetadata.getRefName()); return gitRedisUtils .releaseFileLock(artifactType, branchedGitMetadata.getDefaultArtifactId(), TRUE) @@ -1711,11 +1711,11 @@ private Mono pullAndRehydrateArtifact( final String workspaceId = branchedArtifact.getWorkspaceId(); final String baseArtifactId = branchedGitMetadata.getDefaultArtifactId(); final String repoName = branchedGitMetadata.getRepoName(); - final String branchName = branchedGitMetadata.getBranchName(); + final String branchName = branchedGitMetadata.getRefName(); ArtifactJsonTransformationDTO jsonTransformationDTO = new ArtifactJsonTransformationDTO(); jsonTransformationDTO.setRepoName(repoName); - jsonTransformationDTO.setRefType(RefType.BRANCH); + jsonTransformationDTO.setRefType(RefType.branch); jsonTransformationDTO.setRefName(branchName); jsonTransformationDTO.setWorkspaceId(workspaceId); jsonTransformationDTO.setBaseArtifactId(baseArtifactId); @@ -1996,7 +1996,7 @@ protected Mono discardChanges(Artifact branchedArtifact, Git ArtifactJsonTransformationDTO jsonTransformationDTO = new ArtifactJsonTransformationDTO(); jsonTransformationDTO.setArtifactType(branchedArtifact.getArtifactType()); // Because this operation is only valid for branches - jsonTransformationDTO.setRefType(RefType.BRANCH); + jsonTransformationDTO.setRefType(RefType.branch); jsonTransformationDTO.setWorkspaceId(branchedArtifact.getWorkspaceId()); jsonTransformationDTO.setBaseArtifactId(branchedGitData.getDefaultArtifactId()); jsonTransformationDTO.setRefName(branchedGitData.getRefName()); @@ -2025,7 +2025,7 @@ protected Mono discardChanges(Artifact branchedArtifact, Git branchedArtifact.getWorkspaceId(), branchedArtifact.getId(), artifactExchangeJson, - branchedGitData.getBranchName())) + branchedGitData.getRefName())) // Update the last deployed status after the rebase .flatMap(importedArtifact -> gitArtifactHelper.publishArtifact(importedArtifact, true)) .flatMap(publishedArtifact -> { diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/common/CommonGitServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/common/CommonGitServiceCEImpl.java index 4e71a75088a4..e82280ace665 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/common/CommonGitServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/common/CommonGitServiceCEImpl.java @@ -229,7 +229,7 @@ protected Mono> getCommitHistory(Artifact branchedArtifact) { GitArtifactMetadata gitData = branchedArtifact.getGitArtifactMetadata(); if (gitData == null || StringUtils.isEmptyOrNull( - branchedArtifact.getGitArtifactMetadata().getBranchName())) { + branchedArtifact.getGitArtifactMetadata().getRefName())) { return Mono.error(new AppsmithException(AppsmithError.INVALID_GIT_CONFIGURATION, GIT_CONFIG_ERROR)); } @@ -238,7 +238,7 @@ protected Mono> getCommitHistory(Artifact branchedArtifact) { branchedArtifact.getWorkspaceId(), gitData.getDefaultArtifactId(), gitData.getRepoName()); Mono> commitHistoryMono = gitExecutor - .checkoutToBranch(baseRepoSuffix, gitData.getBranchName()) + .checkoutToBranch(baseRepoSuffix, gitData.getRefName()) .onErrorResume(e -> Mono.error(new AppsmithException(AppsmithError.GIT_ACTION_FAILED, "checkout", e.getMessage()))) .then(gitExecutor @@ -272,7 +272,7 @@ protected Mono getStatus( GitArtifactMetadata branchedGitMetadata = branchedArtifact.getGitArtifactMetadata(); branchedGitMetadata.setGitAuth(baseGitMetadata.getGitAuth()); - final String finalBranchName = branchedGitMetadata.getBranchName(); + final String finalBranchName = branchedGitMetadata.getRefName(); if (StringUtils.isEmptyOrNull(finalBranchName)) { return Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, FieldName.BRANCH_NAME)); @@ -393,11 +393,11 @@ public Mono fetchRemoteChanges( String baseArtifactId = baseGitData.getDefaultArtifactId(); - if (branchedGitData == null || !hasText(branchedGitData.getBranchName())) { + if (branchedGitData == null || !hasText(branchedGitData.getRefName())) { return Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, BRANCH_NAME)); } - final String finalBranchName = branchedArtifact.getGitArtifactMetadata().getBranchName(); + final String finalBranchName = branchedArtifact.getGitArtifactMetadata().getRefName(); GitArtifactHelper artifactGitHelper = getArtifactGitService(baseArtifact.getArtifactType()); Mono currUserMono = sessionUserService.getCurrentUser().cache(); // will be used to send analytics event @@ -516,7 +516,7 @@ private Mono sendUnitExecutionTimeAnalyticsEvent( "appId", gitArtifactMetadata.getDefaultArtifactId(), FieldName.BRANCH_NAME, - gitArtifactMetadata.getBranchName(), + gitArtifactMetadata.getRefName(), "organizationId", artifact.getWorkspaceId(), "repoUrl", @@ -723,7 +723,7 @@ public Mono connectArtifactToGit( } else { GitArtifactMetadata gitArtifactMetadata = artifact.getGitArtifactMetadata(); gitArtifactMetadata.setDefaultApplicationId(artifactId); - gitArtifactMetadata.setBranchName(defaultBranch); + gitArtifactMetadata.setRefName(defaultBranch); gitArtifactMetadata.setDefaultBranchName(defaultBranch); gitArtifactMetadata.setRemoteUrl(gitConnectDTO.getRemoteUrl()); gitArtifactMetadata.setRepoName(repoName); @@ -926,7 +926,7 @@ private Mono commitArtifact( return Mono.error(new AppsmithException(AppsmithError.INVALID_GIT_CONFIGURATION, GIT_CONFIG_ERROR)); } - final String branchName = branchedGitMetadata.getBranchName(); + final String branchName = branchedGitMetadata.getRefName(); if (!hasText(branchName)) { return Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, FieldName.BRANCH_NAME)); @@ -989,7 +989,7 @@ private Mono commitArtifact( }) .flatMap(artifact -> { String errorEntity = ""; - if (StringUtils.isEmptyOrNull(branchedGitMetadata.getBranchName())) { + if (StringUtils.isEmptyOrNull(branchedGitMetadata.getRefName())) { errorEntity = "branch name"; } else if (StringUtils.isEmptyOrNull(branchedGitMetadata.getDefaultArtifactId())) { // TODO: make this artifact @@ -1192,7 +1192,7 @@ protected Mono pushArtifact(Artifact branchedArtifact, boolean doPublish GitArtifactMetadata gitData = artifact.getGitArtifactMetadata(); if (gitData == null - || StringUtils.isEmptyOrNull(gitData.getBranchName()) + || StringUtils.isEmptyOrNull(gitData.getRefName()) || StringUtils.isEmptyOrNull(gitData.getDefaultArtifactId()) || StringUtils.isEmptyOrNull(gitData.getGitAuth().getPrivateKey())) { @@ -1207,14 +1207,14 @@ protected Mono pushArtifact(Artifact branchedArtifact, boolean doPublish return gitExecutor .checkoutToBranch( baseRepoSuffix, - artifact.getGitArtifactMetadata().getBranchName()) + artifact.getGitArtifactMetadata().getRefName()) .then(Mono.defer(() -> gitExecutor .pushApplication( baseRepoSuffix, gitData.getRemoteUrl(), gitAuth.getPublicKey(), gitAuth.getPrivateKey(), - gitData.getBranchName()) + gitData.getRefName()) .zipWith(Mono.just(artifact)))) .onErrorResume(error -> addAnalyticsForGitOperation( AnalyticsEvents.GIT_PUSH, @@ -1300,12 +1300,12 @@ private Mono pushArtifactErrorRecovery(String pushResult, Artifact artif artifact.getWorkspaceId(), gitMetadata.getDefaultArtifactId(), gitMetadata.getRepoName()); return gitExecutor - .resetHard(path, gitMetadata.getBranchName()) + .resetHard(path, gitMetadata.getRefName()) .then(Mono.error(new AppsmithException( AppsmithError.GIT_ACTION_FAILED, "push", "Unable to push changes as pre-receive hook declined. Please make sure that you don't have any rules enabled on the branch " - + gitMetadata.getBranchName()))); + + gitMetadata.getRefName()))); } return Mono.just(pushResult); } @@ -1416,7 +1416,7 @@ private Mono checkoutRemoteBranch(Artifact baseArtifact, Str final String repoName = baseGitMetadata.getRepoName(); final String baseArtifactId = baseGitMetadata.getDefaultArtifactId(); - final String baseBranchName = baseGitMetadata.getBranchName(); + final String baseBranchName = baseGitMetadata.getRefName(); final String workspaceId = baseArtifact.getWorkspaceId(); final String finalRemoteBranchName = remoteBranchName.replaceFirst(ORIGIN, REMOTE_NAME_REPLACEMENT); @@ -1540,7 +1540,7 @@ public Mono detachRemote(String branchedArtifactId, Artifact Path repoSuffix = gitArtifactHelper.getRepoSuffixPath( baseArtifact.getWorkspaceId(), baseGitMetadata.getDefaultArtifactId(), repoName); - String baseApplicationBranchName = baseGitMetadata.getBranchName(); + String baseApplicationBranchName = baseGitMetadata.getRefName(); return Mono.zip( gitExecutor.listBranches(repoSuffix), Mono.just(baseArtifact), @@ -1626,19 +1626,18 @@ public Mono createBranch( // Create a new branch from the parent checked out branch return addFileLock(baseGitMetadata.getDefaultArtifactId(), GitCommandConstants.CREATE_BRANCH) - .flatMap(status -> - gitExecutor.checkoutToBranch(repoSuffix, parentGitMetadata.getBranchName())) + .flatMap(status -> gitExecutor.checkoutToBranch(repoSuffix, parentGitMetadata.getRefName())) .onErrorResume(error -> Mono.error(new AppsmithException( AppsmithError.GIT_ACTION_FAILED, "checkout", - "Unable to find " + parentGitMetadata.getBranchName()))) + "Unable to find " + parentGitMetadata.getRefName()))) .zipWhen(isCheckedOut -> gitExecutor .fetchRemote( repoSuffix, baseGitAuth.getPublicKey(), baseGitAuth.getPrivateKey(), false, - parentGitMetadata.getBranchName(), + parentGitMetadata.getRefName(), true) .onErrorResume(error -> Mono.error( new AppsmithException(AppsmithError.GIT_ACTION_FAILED, "fetch", error)))) @@ -1690,7 +1689,7 @@ public Mono createBranch( GitCommitDTO commitDTO = new GitCommitDTO(); commitDTO.setCommitMessage(DEFAULT_COMMIT_MESSAGE + GitDefaultCommitMessage.BRANCH_CREATED.getReason() - + branchedGitMetadata.getBranchName()); + + branchedGitMetadata.getRefName()); commitDTO.setDoPush(true); return commitArtifact( commitDTO, importedBranchedArtifact.getId(), false, false, artifactType) @@ -1802,7 +1801,7 @@ private Mono pullAndRehydrateArtifact(Artifact baseArtifact, Artifac final String workspaceId = branchedArtifact.getWorkspaceId(); final String baseArtifactId = branchedGitMetadata.getDefaultArtifactId(); final String repoName = branchedGitMetadata.getRepoName(); - final String branchName = branchedGitMetadata.getBranchName(); + final String branchName = branchedGitMetadata.getRefName(); Path repoSuffix = gitArtifactHelper.getRepoSuffixPath(workspaceId, baseArtifactId, repoName); @@ -2059,7 +2058,7 @@ private Mono addAnalyticsForGitOperation( Boolean isMergeable) { String branchName = artifact.getGitArtifactMetadata() != null - ? artifact.getGitArtifactMetadata().getBranchName() + ? artifact.getGitArtifactMetadata().getRefName() : null; return addAnalyticsForGitOperation( event, artifact, errorType, errorMessage, isRepoPrivate, isSystemGenerated, isMergeable, branchName); @@ -2147,7 +2146,7 @@ public Mono deleteBranch(String baseArtifactId, String branc GitArtifactMetadata baseGitMetadata = baseArtifact.getGitArtifactMetadata(); GitArtifactMetadata branchedGitMetadata = branchedArtifact.getGitArtifactMetadata(); - final String finalBranchName = branchedGitMetadata.getBranchName(); + final String finalBranchName = branchedGitMetadata.getRefName(); return gitPrivateRepoHelper .isBranchProtected(baseGitMetadata, finalBranchName) @@ -2170,7 +2169,7 @@ public Mono deleteBranch(String baseArtifactId, String branc GitArtifactMetadata baseGitMetadata = baseArtifact.getGitArtifactMetadata(); GitArtifactMetadata branchedGitMetadata = branchedArtifact.getGitArtifactMetadata(); - final String finalBranchName = branchedGitMetadata.getBranchName(); + final String finalBranchName = branchedGitMetadata.getRefName(); Path repoPath = gitArtifactHelper.getRepoSuffixPath( baseArtifact.getWorkspaceId(), @@ -2265,7 +2264,7 @@ public Mono discardChanges(String branchedArtifactId, Artifa }) .flatMap(branchedArtifact -> { GitArtifactMetadata branchedGitData = branchedArtifact.getGitArtifactMetadata(); - final String branchName = branchedGitData.getBranchName(); + final String branchName = branchedGitData.getRefName(); final String defaultArtifactId = branchedGitData.getDefaultArtifactId(); final String repoName = branchedGitData.getRepoName(); final String workspaceId = branchedArtifact.getWorkspaceId(); @@ -2341,7 +2340,7 @@ public Mono mergeBranch( Mono destinationArtifactMono = baseAndBranchedArtifactsMono.flatMap(artifactTuples -> { Artifact baseArtifact = artifactTuples.getT1(); - if (destinationBranch.equals(baseArtifact.getGitArtifactMetadata().getBranchName())) { + if (destinationBranch.equals(baseArtifact.getGitArtifactMetadata().getRefName())) { return Mono.just(baseArtifact); } @@ -2525,7 +2524,7 @@ public Mono isBranchMergeable( Mono destinationArtifactMono = baseAndBranchedArtifactsMono.flatMap(artifactTuples -> { Artifact baseArtifact = artifactTuples.getT1(); - if (destinationBranch.equals(baseArtifact.getGitArtifactMetadata().getBranchName())) { + if (destinationBranch.equals(baseArtifact.getGitArtifactMetadata().getRefName())) { return Mono.just(baseArtifact); } @@ -2779,7 +2778,7 @@ protected Mono> getBranchList( final String workspaceId = baseArtifact.getWorkspaceId(); final String baseArtifactId = baseGitData.getDefaultArtifactId(); final String repoName = baseGitData.getRepoName(); - final String currentBranch = branchedGitData.getBranchName(); + final String currentBranch = branchedGitData.getRefName(); if (!hasText(baseArtifactId) || !hasText(repoName) || !hasText(currentBranch)) { log.error( @@ -2907,7 +2906,7 @@ private Mono> handleRepoNotFoundException(String baseArtifact // remove origin/ prefix from the remote branch name String branchName = gitBranchDTO.getBranchName().replace("origin/", ""); // The root defaultArtifact is always there, no need to check out it again - if (!branchName.equals(gitArtifactMetadata.getBranchName())) { + if (!branchName.equals(gitArtifactMetadata.getRefName())) { branchesToCheckout.add(branchName); } } else if (gitBranchDTO @@ -3267,7 +3266,7 @@ public Mono importArtifactFromGit( GitArtifactMetadata gitArtifactMetadata = new GitArtifactMetadata(); gitArtifactMetadata.setGitAuth(gitAuth); gitArtifactMetadata.setDefaultApplicationId(artifact.getId()); - gitArtifactMetadata.setBranchName(defaultBranch); + gitArtifactMetadata.setRefName(defaultBranch); gitArtifactMetadata.setDefaultBranchName(defaultBranch); gitArtifactMetadata.setRemoteUrl(gitConnectDTO.getRemoteUrl()); gitArtifactMetadata.setRepoName(repoName); diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/fs/GitFSServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/fs/GitFSServiceCEImpl.java index d08152c44eb1..60d834763246 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/fs/GitFSServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/fs/GitFSServiceCEImpl.java @@ -265,7 +265,7 @@ public Mono> listBranches( @Override public Mono> listReferences( ArtifactJsonTransformationDTO artifactJsonTransformationDTO, Boolean checkRemoteReferences) { - if (RefType.BRANCH.equals(artifactJsonTransformationDTO.getRefType())) { + if (RefType.branch.equals(artifactJsonTransformationDTO.getRefType())) { return listBranches(artifactJsonTransformationDTO, checkRemoteReferences); } @@ -442,7 +442,7 @@ protected Mono pushArtifact(Artifact branchedArtifact, boolean isFileLoc GitArtifactMetadata gitData = artifact.getGitArtifactMetadata(); if (gitData == null - || !StringUtils.hasText(gitData.getBranchName()) + || !StringUtils.hasText(gitData.getRefName()) || !StringUtils.hasText(gitData.getDefaultArtifactId()) || !StringUtils.hasText(gitData.getGitAuth().getPrivateKey())) { @@ -457,14 +457,14 @@ protected Mono pushArtifact(Artifact branchedArtifact, boolean isFileLoc return fsGitHandler .checkoutToBranch( baseRepoSuffix, - artifact.getGitArtifactMetadata().getBranchName()) + artifact.getGitArtifactMetadata().getRefName()) .then(Mono.defer(() -> fsGitHandler .pushApplication( baseRepoSuffix, gitData.getRemoteUrl(), gitAuth.getPublicKey(), gitAuth.getPrivateKey(), - gitData.getBranchName()) + gitData.getRefName()) .zipWith(Mono.just(artifact)))) .onErrorResume(error -> gitAnalyticsUtils .addAnalyticsForGitOperation( @@ -544,12 +544,12 @@ private Mono pushArtifactErrorRecovery(String pushResult, Artifact artif artifact.getWorkspaceId(), gitMetadata.getDefaultArtifactId(), gitMetadata.getRepoName()); return fsGitHandler - .resetHard(path, gitMetadata.getBranchName()) + .resetHard(path, gitMetadata.getRefName()) .then(Mono.error(new AppsmithException( AppsmithError.GIT_ACTION_FAILED, "push", "Unable to push changes as pre-receive hook declined. Please make sure that you don't have any rules enabled on the branch " - + gitMetadata.getBranchName()))); + + gitMetadata.getRefName()))); } return Mono.just(pushResult); } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/utils/GitAnalyticsUtils.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/utils/GitAnalyticsUtils.java index a75e8f6a1ded..bc8f8922db3d 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/utils/GitAnalyticsUtils.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/utils/GitAnalyticsUtils.java @@ -73,7 +73,7 @@ public Mono addAnalyticsForGitOperation( Boolean isMergeable) { String branchName = artifact.getGitArtifactMetadata() != null - ? artifact.getGitArtifactMetadata().getBranchName() + ? artifact.getGitArtifactMetadata().getRefName() : null; return addAnalyticsForGitOperation( event, artifact, errorType, errorMessage, isRepoPrivate, isSystemGenerated, isMergeable, branchName); @@ -141,7 +141,7 @@ public Mono sendUnitExecutionTimeAnalyticsEvent( "appId", gitArtifactMetadata.getDefaultArtifactId(), FieldName.BRANCH_NAME, - gitArtifactMetadata.getBranchName(), + gitArtifactMetadata.getRefName(), "organizationId", artifact.getWorkspaceId(), "repoUrl", diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/GitUtils.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/GitUtils.java index ce2d1eac9654..8c6762c13a14 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/GitUtils.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/GitUtils.java @@ -136,7 +136,7 @@ public static String getGitProviderName(String sshUrl) { public static String getDefaultBranchName(GitArtifactMetadata gitArtifactMetadata) { return StringUtils.isEmptyOrNull(gitArtifactMetadata.getDefaultBranchName()) - ? gitArtifactMetadata.getBranchName() + ? gitArtifactMetadata.getRefName() : gitArtifactMetadata.getDefaultBranchName(); } @@ -149,8 +149,8 @@ public static String getDefaultBranchName(GitArtifactMetadata gitArtifactMetadat public static boolean isDefaultBranchedApplication(Application application) { GitArtifactMetadata metadata = application.getGitApplicationMetadata(); return isApplicationConnectedToGit(application) - && !StringUtils.isEmptyOrNull(metadata.getBranchName()) - && metadata.getBranchName().equals(metadata.getDefaultBranchName()); + && !StringUtils.isEmptyOrNull(metadata.getRefName()) + && metadata.getRefName().equals(metadata.getDefaultBranchName()); } /** diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/ce/CommonGitFileUtilsCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/ce/CommonGitFileUtilsCE.java index 486406d6422b..5349f788df6b 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/ce/CommonGitFileUtilsCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/ce/CommonGitFileUtilsCE.java @@ -696,7 +696,7 @@ public Mono getMetadataServerSchemaMigrationVersion( ArtifactType artifactType) { String defaultArtifactId = gitArtifactMetadata.getDefaultArtifactId(); - String branchName = gitArtifactMetadata.getBranchName(); + String refName = gitArtifactMetadata.getRefName(); String repoName = gitArtifactMetadata.getRepoName(); if (!hasText(workspaceId)) { @@ -707,7 +707,7 @@ public Mono getMetadataServerSchemaMigrationVersion( return Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, FieldName.ARTIFACT_ID)); } - if (!hasText(branchName)) { + if (!hasText(refName)) { return Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, FieldName.BRANCH_NAME)); } @@ -716,7 +716,7 @@ public Mono getMetadataServerSchemaMigrationVersion( } Mono serverSchemaNumberMono = reconstructMetadataFromRepo( - workspaceId, defaultArtifactId, repoName, branchName, isResetToLastCommitRequired, artifactType) + workspaceId, defaultArtifactId, repoName, refName, isResetToLastCommitRequired, artifactType) .map(metadataMap -> { return metadataMap.getOrDefault( CommonConstants.SERVER_SCHEMA_VERSION, jsonSchemaVersions.getServerVersion()); @@ -743,7 +743,7 @@ public Mono getPageDslVersionNumber( ArtifactType artifactType) { String defaultArtifactId = gitArtifactMetadata.getDefaultArtifactId(); - String branchName = gitArtifactMetadata.getBranchName(); + String refName = gitArtifactMetadata.getRefName(); String repoName = gitArtifactMetadata.getRepoName(); if (!hasText(workspaceId)) { @@ -754,7 +754,7 @@ public Mono getPageDslVersionNumber( return Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, FieldName.ARTIFACT_ID)); } - if (!hasText(branchName)) { + if (!hasText(refName)) { return Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, FieldName.BRANCH_NAME)); } @@ -770,7 +770,7 @@ public Mono getPageDslVersionNumber( Path baseRepoSuffix = artifactGitFileUtils.getRepoSuffixPath(workspaceId, defaultArtifactId, repoName); Mono jsonObjectMono = fileUtils - .reconstructPageFromGitRepo(pageDTO.getName(), branchName, baseRepoSuffix, isResetToLastCommitRequired) + .reconstructPageFromGitRepo(pageDTO.getName(), refName, baseRepoSuffix, isResetToLastCommitRequired) .onErrorResume(error -> Mono.error( new AppsmithException(AppsmithError.GIT_ACTION_FAILED, RECONSTRUCT_PAGE, error.getMessage()))) .map(pageJson -> { diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/imports/importable/artifactbased/ArtifactBasedImportableServiceCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/imports/importable/artifactbased/ArtifactBasedImportableServiceCE.java index 6d62d19a786a..663fe760ca62 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/imports/importable/artifactbased/ArtifactBasedImportableServiceCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/imports/importable/artifactbased/ArtifactBasedImportableServiceCE.java @@ -1,8 +1,8 @@ package com.appsmith.server.imports.importable.artifactbased; import com.appsmith.external.models.BaseDomain; -import com.appsmith.external.models.BranchAwareDomain; import com.appsmith.external.models.GitSyncedDomain; +import com.appsmith.external.models.RefAwareDomain; import com.appsmith.server.domains.Artifact; import com.appsmith.server.domains.Context; import com.appsmith.server.dtos.ImportingMetaDTO; @@ -27,15 +27,16 @@ Context updateContextInResource( Object dtoObject, Map contextMap, String fallbackBaseContextId); default void populateBaseId(ImportingMetaDTO importingMetaDTO, Artifact artifact, T branchedResource, T resource) { - BranchAwareDomain branchAwareResource = (BranchAwareDomain) resource; - BranchAwareDomain branchAwareBranchedResource = (BranchAwareDomain) branchedResource; + RefAwareDomain refAwareResource = (RefAwareDomain) resource; + RefAwareDomain refAwareRefResource = (RefAwareDomain) branchedResource; - branchAwareResource.setBranchName(importingMetaDTO.getBranchName()); + refAwareResource.setRefType(importingMetaDTO.getRefType()); + refAwareResource.setRefName(importingMetaDTO.getRefName()); if (artifact.getGitArtifactMetadata() != null && branchedResource != null) { - branchAwareResource.setBaseId(branchAwareBranchedResource.getBaseId()); + refAwareResource.setBaseId(refAwareRefResource.getBaseId()); } else { - branchAwareResource.setBaseId(branchAwareResource.getBaseIdOrFallback()); + refAwareResource.setBaseId(refAwareResource.getBaseIdOrFallback()); } } 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 28353b7d1fd7..66a3d8c73e4c 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 @@ -9,6 +9,7 @@ import com.appsmith.server.converters.ArtifactExchangeJsonAdapter; import com.appsmith.server.domains.Application; import com.appsmith.server.domains.Artifact; +import com.appsmith.server.domains.GitArtifactMetadata; import com.appsmith.server.domains.Plugin; import com.appsmith.server.domains.User; import com.appsmith.server.domains.Workspace; @@ -443,6 +444,7 @@ private Mono importArtifactInWorkspace( artifactContextString, branchedArtifactId, null, + null, new ArrayList<>(), appendToArtifact, false, @@ -493,6 +495,13 @@ private Mono importArtifactInWorkspace( .then(Mono.defer(() -> Mono.when(branchedArtifactIdsMono, artifactSpecificImportableEntities))) .then(Mono.defer(() -> artifactBasedImportService.updateAndSaveArtifactInContext( importedDoc.getArtifact(), importingMetaDTO, mappedImportableResourcesDTO, currUserMono))) + .doOnNext(artifact -> { + GitArtifactMetadata gitArtifactMetadata = artifact.getGitArtifactMetadata(); + if (gitArtifactMetadata != null) { + importingMetaDTO.setRefType(gitArtifactMetadata.getRefType()); + importingMetaDTO.setRefName(gitArtifactMetadata.getRefName()); + } + }) .cache(); final Mono importMono = importableArtifactMono diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/imports/internal/partial/PartialImportServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/imports/internal/partial/PartialImportServiceCEImpl.java index c29638d3f2bf..7cdca44ee288 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/imports/internal/partial/PartialImportServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/imports/internal/partial/PartialImportServiceCEImpl.java @@ -177,6 +177,7 @@ private Mono importResourceInPage( FieldName.APPLICATION, branchedApplicationId, null, + null, new ArrayList<>(), false, true, @@ -200,7 +201,8 @@ private Mono importResourceInPage( return newPageService .findById(branchedPageId, AclPermission.MANAGE_PAGES) .flatMap(page -> { - importingMetaDTO.setBranchName(page.getBranchName()); + importingMetaDTO.setRefType(page.getRefType()); + importingMetaDTO.setRefName(page.getRefName()); Layout layout = page.getUnpublishedPage().getLayouts().get(0); return refactoringService.getAllExistingEntitiesMono( diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/db/ce/Migration057MoveDRToBaseIds.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/db/ce/Migration057MoveDRToBaseIds.java index 2a926cd26113..f4cbfc50a399 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/db/ce/Migration057MoveDRToBaseIds.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/db/ce/Migration057MoveDRToBaseIds.java @@ -1,7 +1,7 @@ package com.appsmith.server.migrations.db.ce; import com.appsmith.external.models.BaseDomain; -import com.appsmith.external.models.BranchAwareDomain; +import com.appsmith.external.models.RefAwareDomain; import com.appsmith.server.domains.ActionCollection; import com.appsmith.server.domains.NewAction; import com.appsmith.server.domains.NewPage; @@ -37,10 +37,8 @@ public void rollbackExecution() {} @Execution public void executeMigration() { - Query findQuery = query(where(BaseDomain.Fields.deletedAt) - .isNull() - .and(BranchAwareDomain.Fields.branchName) - .exists(false)); + Query findQuery = query( + where(BaseDomain.Fields.deletedAt).isNull().and("branchName").exists(false)); // NewPage AggregationUpdate moveNewPageDRUpdateQuery = getUpdateDefinition("defaultResources.pageId"); @@ -72,9 +70,9 @@ public void executeMigration() { @NotNull private AggregationUpdate getUpdateDefinition(String oldBaseIdPath) { return AggregationUpdate.update() - .set(BranchAwareDomain.Fields.baseId) + .set(RefAwareDomain.Fields.baseId) .toValueOf(Fields.field(oldBaseIdPath)) - .set(BranchAwareDomain.Fields.branchName) + .set("branchName") .toValueOf(Fields.field("defaultResources.branchName")); } } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/newactions/base/NewActionServiceCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/newactions/base/NewActionServiceCE.java index a2cf04bbd120..662ceac8e451 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/newactions/base/NewActionServiceCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/newactions/base/NewActionServiceCE.java @@ -1,9 +1,8 @@ package com.appsmith.server.newactions.base; +import com.appsmith.external.git.constants.ce.RefType; import com.appsmith.external.models.ActionDTO; import com.appsmith.external.models.CreatorContextType; -import com.appsmith.external.models.Executable; -import com.appsmith.external.models.MustacheBindingToken; import com.appsmith.server.acl.AclPermission; import com.appsmith.server.domains.NewAction; import com.appsmith.server.domains.NewPage; @@ -11,7 +10,6 @@ import com.appsmith.server.dtos.ImportActionCollectionResultDTO; import com.appsmith.server.dtos.ImportActionResultDTO; import com.appsmith.server.dtos.ImportedActionAndCollectionMapsDTO; -import com.appsmith.server.dtos.LayoutExecutableUpdateDTO; import com.appsmith.server.dtos.PluginTypeAndCountDTO; import com.appsmith.server.services.CrudService; import org.springframework.data.domain.Sort; @@ -23,14 +21,11 @@ import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.Set; public interface NewActionServiceCE extends CrudService { void setCommonFieldsFromActionDTOIntoNewAction(ActionDTO action, NewAction newAction); - Mono findByIdAndBranchName(String id, String branchName); - ActionDTO generateActionByViewMode(NewAction newAction, Boolean viewMode); void generateAndSetActionPolicies(NewPage page, NewAction action); @@ -58,8 +53,6 @@ Mono> updateUnpublishedActionWithoutAnalytics( Flux findUnpublishedOnLoadActionsExplicitSetByUserInPage(String pageId); - Flux findUnpublishedActionsInPageByNames(Set names, String pageId); - Mono findById(String id); Flux findAllById(Iterable id); @@ -91,13 +84,13 @@ Flux findAllByApplicationIdAndViewMode( Flux getUnpublishedActions(MultiValueMap params, Boolean includeJsActions); Flux getUnpublishedActions( - MultiValueMap params, String branchName, Boolean includeJsActions); + MultiValueMap params, RefType refType, String refName, Boolean includeJsActions); Flux getUnpublishedActions(MultiValueMap params); Flux getUnpublishedActionsByPageId(String pageId, AclPermission permission); - Flux getUnpublishedActions(MultiValueMap params, String branchName); + Flux getUnpublishedActions(MultiValueMap params, RefType refType, String refName); Mono deleteGivenNewAction(NewAction toDelete); @@ -117,24 +110,8 @@ Flux getUnpublishedActions( Mono> archiveActionsByApplicationId(String applicationId, AclPermission permission); - List extractMustacheKeysInOrder(String query); - - String replaceMustacheWithQuestionMark(String query, List mustacheBindings); - - Mono updateActionsExecuteOnLoad( - List executables, - String pageId, - List actionUpdates, - List messages); - Flux getUnpublishedActionsExceptJs(MultiValueMap params); - Mono findByBranchNameAndBaseActionId( - String branchName, String baseActionId, Boolean viewMode, AclPermission permission); - - Mono findBranchedIdByBranchNameAndBaseActionId( - String branchName, String baseActionId, AclPermission permission); - Mono sanitizeAction(NewAction action); Mono fillSelfReferencingDataPaths(ActionDTO actionDTO); @@ -149,8 +126,6 @@ Mono updateActionsWithImportedCollectionIds( Flux countActionsByPluginType(String applicationId); - Flux findByPageIds(List unpublishedPages, Optional optionalPermission); - Flux findByPageIdsForExport(List unpublishedPages, Optional optionalPermission); Flux findAllActionsByContextIdAndContextTypeAndViewMode( diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/newactions/base/NewActionServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/newactions/base/NewActionServiceCEImpl.java index 12b787c4dfb8..8c8a227f3a2e 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/newactions/base/NewActionServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/newactions/base/NewActionServiceCEImpl.java @@ -2,13 +2,13 @@ import com.appsmith.external.dtos.ExecutePluginDTO; import com.appsmith.external.dtos.RemoteDatasourceDTO; +import com.appsmith.external.git.constants.ce.RefType; import com.appsmith.external.helpers.MustacheHelper; import com.appsmith.external.models.ActionConfiguration; import com.appsmith.external.models.ActionDTO; import com.appsmith.external.models.CreatorContextType; import com.appsmith.external.models.Datasource; import com.appsmith.external.models.DatasourceConfiguration; -import com.appsmith.external.models.Executable; import com.appsmith.external.models.MustacheBindingToken; import com.appsmith.external.models.PluginType; import com.appsmith.external.models.Policy; @@ -55,7 +55,6 @@ import org.apache.commons.lang3.ObjectUtils; import org.springframework.data.domain.Sort; import org.springframework.util.CollectionUtils; -import org.springframework.util.LinkedCaseInsensitiveMap; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.util.StringUtils; @@ -69,13 +68,11 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; -import java.util.Locale; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.UUID; import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Function; import java.util.stream.Collectors; import static com.appsmith.external.constants.spans.ActionSpan.GET_ACTION_REPOSITORY_CALL; @@ -173,7 +170,8 @@ protected void setCommonFieldsFromNewActionIntoAction(NewAction newAction, Actio action.setId(newAction.getId()); action.setBaseId(newAction.getBaseIdOrFallback()); - action.setBranchName(newAction.getBranchName()); + action.setRefType(newAction.getRefType()); + action.setRefName(newAction.getRefName()); action.setUserPermissions(newAction.getUserPermissions()); action.setPolicies(newAction.getPolicies()); /* @@ -197,12 +195,8 @@ public void setCommonFieldsFromActionDTOIntoNewAction(ActionDTO action, NewActio newAction.setDocumentation(action.getDocumentation()); newAction.setApplicationId(action.getApplicationId()); newAction.setBaseId(action.getBaseId()); - newAction.setBranchName(action.getBranchName()); - } - - @Override - public Mono findByIdAndBranchName(String id, String branchName) { - return this.findByBranchNameAndBaseActionId(branchName, id, false, actionPermission.getReadPermission()); + newAction.setRefType(action.getRefType()); + newAction.setRefName(action.getRefName()); } @Override @@ -685,20 +679,6 @@ public Flux findUnpublishedOnLoadActionsExplicitSetByUserInPage(Strin .flatMap(this::sanitizeAction); } - /** - * Given a list of names of actions and pageId, find all the actions matching this criteria of names and pageId - * - * @param names Set of Action names. The returned list of actions will be a subset of the actioned named in this set. - * @param pageId Id of the Page within which to look for Actions. - * @return A Flux of Actions that are identified to be executed on page-load. - */ - @Override - public Flux findUnpublishedActionsInPageByNames(Set names, String pageId) { - return repository - .findUnpublishedActionsByNameInAndPageId(names, pageId, actionPermission.getEditPermission()) - .flatMap(this::sanitizeAction); - } - @Override public Mono findById(String id) { return repository.findById(id).flatMap(this::sanitizeAction); @@ -1005,20 +985,18 @@ protected Flux getUnpublishedActionsFromRepo( @Override public Flux getUnpublishedActions( - MultiValueMap params, String branchName, Boolean includeJsActions) { + MultiValueMap params, RefType refType, String refName, Boolean includeJsActions) { MultiValueMap updatedParams = new LinkedMultiValueMap<>(params); // Get branched applicationId and pageId Mono branchedPageMono = !StringUtils.hasLength(params.getFirst(FieldName.PAGE_ID)) ? Mono.just(new NewPage()) - : newPageService.findByBranchNameAndBasePageId( - branchName, params.getFirst(FieldName.PAGE_ID), pagePermission.getReadPermission(), null); + : newPageService.findByRefTypeAndRefNameAndBasePageId( + refType, refName, params.getFirst(FieldName.PAGE_ID), pagePermission.getReadPermission(), null); Mono branchedApplicationMono = !StringUtils.hasLength(params.getFirst(FieldName.APPLICATION_ID)) ? Mono.just(new Application()) : applicationService.findByBranchNameAndBaseApplicationId( - branchName, - params.getFirst(FieldName.APPLICATION_ID), - applicationPermission.getReadPermission()); + refName, params.getFirst(FieldName.APPLICATION_ID), applicationPermission.getReadPermission()); return Mono.zip(branchedApplicationMono, branchedPageMono).flatMapMany(tuple -> { String applicationId = tuple.getT1().getId(); @@ -1049,8 +1027,9 @@ public Flux getUnpublishedActionsByPageId(String pageId, AclPermissio } @Override - public Flux getUnpublishedActions(MultiValueMap params, String branchName) { - return getUnpublishedActions(params, branchName, TRUE); + public Flux getUnpublishedActions( + MultiValueMap params, RefType refType, String refName) { + return getUnpublishedActions(params, refType, refName, TRUE); } @Override @@ -1271,130 +1250,6 @@ public Flux findByPageId(String pageId) { return repository.findByPageId(pageId).flatMap(this::sanitizeAction); } - /** - * !!!WARNING!!! This function edits the parameters actionUpdates and messages which are eventually returned back to - * the caller with the updates values. - * - * @param onLoadActions : All the actions which have been found to be on page load - * @param pageId - * @param actionUpdates : Empty array list which would be set in this function with all the page actions whose - * execute on load setting has changed (whether flipped from true to false, or vice versa) - * @param messages : Empty array list which would be set in this function with all the messages that should be - * displayed to the developer user communicating the action executeOnLoad changes. - * @return - */ - @Override - public Mono updateActionsExecuteOnLoad( - List onLoadActions, - String pageId, - List actionUpdates, - List messages) { - - List toUpdateActions = new ArrayList<>(); - - MultiValueMap params = - CollectionUtils.toMultiValueMap(new LinkedCaseInsensitiveMap<>(8, Locale.ENGLISH)); - params.add(FieldName.PAGE_ID, pageId); - - // Fetch all the actions which exist in this page. - Flux pageActionsFlux = this.getUnpublishedActions(params).cache(); - - // Before we update the actions, fetch all the actions which are currently set to execute on load. - Mono> existingOnPageLoadActionsMono = pageActionsFlux - .flatMap(action -> { - if (TRUE.equals(action.getExecuteOnLoad())) { - return Mono.just(action); - } - return Mono.empty(); - }) - .collectList(); - - return existingOnPageLoadActionsMono - .zipWith(pageActionsFlux.collectList()) - .flatMap(tuple -> { - List existingOnPageLoadActions = tuple.getT1(); - List pageActions = tuple.getT2(); - - // There are no actions in this page. No need to proceed further since no actions would get updated - if (pageActions.isEmpty()) { - return Mono.just(FALSE); - } - - // No actions require an update if no actions have been found as page load actions as well as - // existing on load page actions are empty - if (existingOnPageLoadActions.isEmpty() && (onLoadActions == null || onLoadActions.isEmpty())) { - return Mono.just(FALSE); - } - - // Extract names of existing page load actions and new page load actions for quick lookup. - Set existingOnPageLoadActionNames = existingOnPageLoadActions.stream() - .map(ActionDTO::getValidName) - .collect(Collectors.toSet()); - - Set newOnLoadActionNames = - onLoadActions.stream().map(Executable::getValidName).collect(Collectors.toSet()); - - // Calculate the actions which would need to be updated from execute on load TRUE to FALSE. - Set turnedOffActionNames = new HashSet<>(); - turnedOffActionNames.addAll(existingOnPageLoadActionNames); - turnedOffActionNames.removeAll(newOnLoadActionNames); - - // Calculate the actions which would need to be updated from execute on load FALSE to TRUE - Set turnedOnActionNames = new HashSet<>(); - turnedOnActionNames.addAll(newOnLoadActionNames); - turnedOnActionNames.removeAll(existingOnPageLoadActionNames); - - for (ActionDTO action : pageActions) { - - String actionName = action.getValidName(); - // If a user has ever set execute on load, this field can not be changed automatically. It has - // to be - // explicitly changed by the user again. Add the action to update only if this condition is - // false. - if (FALSE.equals(action.getUserSetOnLoad())) { - - // If this action is no longer an onload action, turn the execute on load to false - if (turnedOffActionNames.contains(actionName)) { - action.setExecuteOnLoad(FALSE); - toUpdateActions.add(action); - } - - // If this action is newly found to be on load, turn execute on load to true - if (turnedOnActionNames.contains(actionName)) { - action.setExecuteOnLoad(TRUE); - toUpdateActions.add(action); - } - } else { - // Remove the action name from either of the lists (if present) because this action should - // not be updated - turnedOnActionNames.remove(actionName); - turnedOffActionNames.remove(actionName); - } - } - - // Add newly turned on page actions to report back to the caller - actionUpdates.addAll(addActionUpdatesForActionNames(pageActions, turnedOnActionNames)); - - // Add newly turned off page actions to report back to the caller - actionUpdates.addAll(addActionUpdatesForActionNames(pageActions, turnedOffActionNames)); - - // Now add messages that would eventually be displayed to the developer user informing them - // about the action setting change. - if (!turnedOffActionNames.isEmpty()) { - messages.add(turnedOffActionNames.toString() + " will no longer be executed on page load"); - } - - if (!turnedOnActionNames.isEmpty()) { - messages.add(turnedOnActionNames.toString() + " will be executed automatically on page load"); - } - - // Finally update the actions which require an update - return Flux.fromIterable(toUpdateActions) - .flatMap(actionDTO -> updateUnpublishedAction(actionDTO.getId(), actionDTO)) - .then(Mono.just(TRUE)); - }); - } - private List addActionUpdatesForActionNames( List pageActions, Set actionNames) { @@ -1462,23 +1317,6 @@ public Mono> archiveActionsByApplicationId(String applicationId, .collectList(); } - public List extractMustacheKeysInOrder(String query) { - return MustacheHelper.extractMustacheKeysInOrder(query); - } - - @Override - public String replaceMustacheWithQuestionMark(String query, List mustacheBindings) { - - ActionConfiguration actionConfiguration = new ActionConfiguration(); - actionConfiguration.setBody(query); - Map replaceParamsMap = - mustacheBindings.stream().collect(Collectors.toMap(Function.identity(), v -> "?")); - - ActionConfiguration updatedActionConfiguration = - MustacheHelper.renderFieldValues(actionConfiguration, replaceParamsMap); - return updatedActionConfiguration.getBody(); - } - private Mono updateDatasourcePolicyForPublicAction(NewAction action, Datasource datasource) { if (datasource.getId() == null) { // This seems to be a nested datasource. Return as is. @@ -1524,34 +1362,6 @@ private Mono updateDatasourcePolicyForPublicAction(NewAction action, }); } - public Mono findByBranchNameAndBaseActionId( - String branchName, String baseActionId, Boolean viewMode, AclPermission permission) { - log.debug("Going to find action based on branchName and defaultActionId with id: {} ", baseActionId); - if (!StringUtils.hasLength(branchName)) { - return repository - .findById(baseActionId, permission) - .switchIfEmpty(Mono.error( - new AppsmithException(AppsmithError.NO_RESOURCE_FOUND, FieldName.ACTION, baseActionId))); - } - return repository - .findByBranchNameAndBaseActionId(branchName, baseActionId, viewMode, permission) - .switchIfEmpty(Mono.error(new AppsmithException( - AppsmithError.NO_RESOURCE_FOUND, FieldName.ACTION, baseActionId + "," + branchName))) - .flatMap(this::sanitizeAction); - } - - public Mono findBranchedIdByBranchNameAndBaseActionId( - String branchName, String baseActionId, AclPermission permission) { - if (!StringUtils.hasLength(branchName)) { - return Mono.just(baseActionId); - } - return repository - .findByBranchNameAndBaseActionId(branchName, baseActionId, false, permission) - .switchIfEmpty(Mono.error(new AppsmithException( - AppsmithError.ACL_NO_RESOURCE_FOUND, FieldName.ACTION, baseActionId + "," + branchName))) - .map(NewAction::getId); - } - private Map getAnalyticsProperties(NewAction savedAction, Datasource datasource) { final Datasource embeddedDatasource = savedAction.getUnpublishedAction().getDatasource(); embeddedDatasource.setIsMock(datasource.getIsMock()); @@ -1677,11 +1487,6 @@ public Flux countActionsByPluginType(String applicationId return repository.countActionsByPluginType(applicationId); } - @Override - public Flux findByPageIds(List unpublishedPages, Optional optionalPermission) { - return repository.findByPageIds(unpublishedPages, optionalPermission); - } - @Override public Flux findByPageIdsForExport( List unpublishedPages, Optional optionalPermission) { diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/newactions/clonepage/ActionClonePageServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/newactions/clonepage/ActionClonePageServiceCEImpl.java index 91990d715288..0729fda7f9bc 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/newactions/clonepage/ActionClonePageServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/newactions/clonepage/ActionClonePageServiceCEImpl.java @@ -32,7 +32,8 @@ public Mono cloneEntities(ClonePageMetaDTO clonePageMetaDTO) { .flatMap(action -> { // Set new page id in the actionDTO ActionDTO actionDTO = action.getUnpublishedAction(); - actionDTO.setBranchName(clonePageMetaDTO.getBranchName()); + actionDTO.setRefType(clonePageMetaDTO.getRefType()); + actionDTO.setRefName(clonePageMetaDTO.getRefName()); actionDTO.setPageId(clonePageMetaDTO.getClonedPageDTO().getId()); diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/newactions/importable/NewActionImportableServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/newactions/importable/NewActionImportableServiceCEImpl.java index 3755272f84c6..f96d0200e0fc 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/newactions/importable/NewActionImportableServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/newactions/importable/NewActionImportableServiceCEImpl.java @@ -361,11 +361,7 @@ private Mono createImportNewActionsMono( actionsInCurrentArtifact, newAction); - updateExistingAction( - existingAction, - newAction, - importingMetaDTO.getBranchName(), - importingMetaDTO.getPermissionProvider()); + updateExistingAction(existingAction, newAction, importingMetaDTO); // Add it to actions list that'll be updated in bulk existingNewActionList.add(existingAction); @@ -510,10 +506,8 @@ protected void populateDomainMappedReferences( } private void updateExistingAction( - NewAction existingAction, - NewAction actionToImport, - String branchName, - ImportArtifactPermissionProvider permissionProvider) { + NewAction existingAction, NewAction actionToImport, ImportingMetaDTO importingMetaDTO) { + ImportArtifactPermissionProvider permissionProvider = importingMetaDTO.getPermissionProvider(); // Since the resource is already present in DB, just update resource if (!permissionProvider.hasEditPermission(existingAction)) { log.error("User does not have permission to edit action with id: {}", existingAction.getId()); @@ -524,8 +518,9 @@ private void updateExistingAction( updateImportableActionFromExistingAction(existingAction, actionToImport); copyNestedNonNullProperties(actionToImport, existingAction); - // Update branchName - existingAction.setBranchName(branchName); + // Update ref name + existingAction.setRefType(importingMetaDTO.getRefType()); + existingAction.setRefName(importingMetaDTO.getRefName()); // Recover the deleted state present in DB from imported action existingAction .getUnpublishedAction() diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/newactions/importable/applications/NewActionApplicationImportableServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/newactions/importable/applications/NewActionApplicationImportableServiceCEImpl.java index 19212302fa8b..5a36460e3510 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/newactions/importable/applications/NewActionApplicationImportableServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/newactions/importable/applications/NewActionApplicationImportableServiceCEImpl.java @@ -102,7 +102,8 @@ public void createNewResource(ImportingMetaDTO importingMetaDTO, NewAction newAc // create or update base id for the action // values already set to base id are kept unchanged newAction.setBaseId(newAction.getBaseIdOrFallback()); - newAction.setBranchName(importingMetaDTO.getBranchName()); + newAction.setRefType(importingMetaDTO.getRefType()); + newAction.setRefName(importingMetaDTO.getRefName()); // generate gitSyncId if it's not present if (newAction.getGitSyncId() == null) { diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/newpages/base/NewPageServiceCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/newpages/base/NewPageServiceCE.java index b669c91a4142..b981ce2516a1 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/newpages/base/NewPageServiceCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/newpages/base/NewPageServiceCE.java @@ -1,5 +1,6 @@ package com.appsmith.server.newpages.base; +import com.appsmith.external.git.constants.ce.RefType; import com.appsmith.server.acl.AclPermission; import com.appsmith.server.domains.Application; import com.appsmith.server.domains.ApplicationMode; @@ -69,13 +70,17 @@ Mono findByNameAndApplicationIdAndViewMode( Mono getNameByPageId(String pageId, boolean isPublishedName); - Mono findByBranchNameAndBasePageId( - String branchName, String defaultPageId, AclPermission permission, List projectedFieldNames); + Mono findByRefTypeAndRefNameAndBasePageId( + RefType refType, + String refName, + String defaultPageId, + AclPermission permission, + List projectedFieldNames); - Mono findByBranchNameAndBasePageIdAndApplicationMode( - String branchName, String basePageId, ApplicationMode mode); + Mono findByRefTypeAndRefNameAndBasePageIdAndApplicationMode( + RefType refType, String refName, String basePageId, ApplicationMode mode); - Mono findBranchedPageId(String branchName, String basePageId, AclPermission permission); + Mono findRefPageId(RefType refType, String refName, String basePageId, AclPermission permission); Mono publishPages(Collection pageIds, AclPermission permission); @@ -86,7 +91,8 @@ Mono findByBranchNameAndBasePageIdAndApplicationMode( Mono createApplicationPagesDTO( Application branchedApplication, List newPages, boolean viewMode, boolean isRecentlyAccessed); - Mono updateDependencyMap(String pageId, Map> dependencyMap, String branchName); + Mono updateDependencyMap( + String pageId, Map> dependencyMap, RefType refType, String refName); Flux findByApplicationIdAndApplicationMode( String applicationId, AclPermission permission, ApplicationMode applicationMode); diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/newpages/base/NewPageServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/newpages/base/NewPageServiceCEImpl.java index 594e94d033e8..28a291853f2e 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/newpages/base/NewPageServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/newpages/base/NewPageServiceCEImpl.java @@ -1,6 +1,7 @@ package com.appsmith.server.newpages.base; import com.appsmith.external.enums.WorkspaceResourceContext; +import com.appsmith.external.git.constants.ce.RefType; import com.appsmith.server.acl.AclPermission; import com.appsmith.server.applications.base.ApplicationService; import com.appsmith.server.constants.FieldName; @@ -163,7 +164,8 @@ public Mono createDefault(PageDTO object) { newPage.setGitSyncId(newPage.getApplicationId() + "_" + UUID.randomUUID()); } newPage.setBaseId(object.getId()); - newPage.setBranchName(object.getBranchName()); + newPage.setRefType(object.getRefType()); + newPage.setRefName(object.getRefName()); // Save page and update the defaultPageId after insertion return super.create(newPage) @@ -506,12 +508,16 @@ public Mono getNameByPageId(String pageId, boolean isPublishedName) { } @Override - public Mono findByBranchNameAndBasePageId( - String branchName, String basePageId, AclPermission permission, List projectedFieldNames) { + public Mono findByRefTypeAndRefNameAndBasePageId( + RefType refType, + String refName, + String basePageId, + AclPermission permission, + List projectedFieldNames) { if (!StringUtils.hasText(basePageId)) { return Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, FieldName.PAGE_ID)); - } else if (!StringUtils.hasText(branchName)) { + } else if (!StringUtils.hasText(refName)) { return repository .findById(basePageId, permission, projectedFieldNames) .name(GET_PAGE_WITHOUT_BRANCH) @@ -520,16 +526,16 @@ public Mono findByBranchNameAndBasePageId( new AppsmithException(AppsmithError.NO_RESOURCE_FOUND, FieldName.PAGE, basePageId))); } return repository - .findPageByBranchNameAndBasePageId(branchName, basePageId, permission, projectedFieldNames) + .findPageByRefTypeAndRefNameAndBasePageId(refType, refName, basePageId, permission, projectedFieldNames) .name(GET_PAGE_WITH_BRANCH) .tap(Micrometer.observation(observationRegistry)) .switchIfEmpty(Mono.error(new AppsmithException( - AppsmithError.NO_RESOURCE_FOUND, FieldName.PAGE, basePageId + ", " + branchName))); + AppsmithError.NO_RESOURCE_FOUND, FieldName.PAGE, basePageId + ", " + refName))); } @Override - public Mono findByBranchNameAndBasePageIdAndApplicationMode( - String branchName, String basePageId, ApplicationMode mode) { + public Mono findByRefTypeAndRefNameAndBasePageIdAndApplicationMode( + RefType refType, String refName, String basePageId, ApplicationMode mode) { AclPermission permission; if (ApplicationMode.EDIT.equals(mode)) { @@ -538,15 +544,19 @@ public Mono findByBranchNameAndBasePageIdAndApplicationMode( permission = pagePermission.getReadPermission(); } - return this.findByBranchNameAndBasePageId( - branchName, basePageId, permission, List.of(NewPage.Fields.id, NewPage.Fields.applicationId)) + return this.findByRefTypeAndRefNameAndBasePageId( + refType, + refName, + basePageId, + permission, + List.of(NewPage.Fields.id, NewPage.Fields.applicationId)) .name(getQualifiedSpanName(GET_PAGE, mode)) .tap(Micrometer.observation(observationRegistry)); } @Override - public Mono findBranchedPageId(String branchName, String basePageId, AclPermission permission) { - if (!StringUtils.hasText(branchName)) { + public Mono findRefPageId(RefType refType, String refName, String basePageId, AclPermission permission) { + if (!StringUtils.hasText(refName)) { if (!StringUtils.hasText(basePageId)) { return Mono.error( new AppsmithException(AppsmithError.INVALID_PARAMETER, FieldName.PAGE_ID, basePageId)); @@ -554,9 +564,9 @@ public Mono findBranchedPageId(String branchName, String basePageId, Acl return Mono.just(basePageId); } return repository - .findPageByBranchNameAndBasePageId(branchName, basePageId, permission, null) + .findPageByRefTypeAndRefNameAndBasePageId(refType, refName, basePageId, permission, null) .switchIfEmpty(Mono.error(new AppsmithException( - AppsmithError.NO_RESOURCE_FOUND, FieldName.PAGE_ID, basePageId + ", " + branchName))) + AppsmithError.NO_RESOURCE_FOUND, FieldName.PAGE_ID, basePageId + ", " + refName))) .map(NewPage::getId); } @@ -616,11 +626,12 @@ public Flux findAllByApplicationIds(List applicationIds, List updateDependencyMap(String pageId, Map> dependencyMap, String branchName) { + public Mono updateDependencyMap( + String pageId, Map> dependencyMap, RefType refType, String refName) { Mono updateResult; - if (branchName != null) { - updateResult = findBranchedPageId(branchName, pageId, AclPermission.MANAGE_PAGES) - .flatMap(branchPageId -> repository.updateDependencyMap(branchPageId, dependencyMap)); + if (refName != null) { + updateResult = findRefPageId(refType, refName, pageId, AclPermission.MANAGE_PAGES) + .flatMap(refPageId -> repository.updateDependencyMap(refPageId, dependencyMap)); } else { updateResult = repository.updateDependencyMap(pageId, dependencyMap); } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/newpages/importable/NewPageImportableServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/newpages/importable/NewPageImportableServiceCEImpl.java index d49690e2d2a3..eef9bbfe748a 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/newpages/importable/NewPageImportableServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/newpages/importable/NewPageImportableServiceCEImpl.java @@ -126,7 +126,8 @@ public Mono updateImportedEntities( .toList(); return Flux.fromIterable(newPages) .flatMap(newPage -> { - newPage.setBranchName(importingMetaDTO.getBranchName()); + newPage.setRefType(importingMetaDTO.getRefType()); + newPage.setRefName(importingMetaDTO.getRefName()); return mapActionAndCollectionIdWithPageLayout( newPage, importActionResultDTO.getActionIdMap(), @@ -452,7 +453,8 @@ private Flux importAndSavePages( Set existingPagePolicy = existingPage.getPolicies(); copyNestedNonNullProperties(newPage, existingPage); // Update branchName - existingPage.setBranchName(importingMetaDTO.getBranchName()); + existingPage.setRefType(importingMetaDTO.getRefType()); + existingPage.setRefName(importingMetaDTO.getRefName()); // Recover the deleted state present in DB from imported page existingPage .getUnpublishedPage() @@ -474,12 +476,13 @@ private Flux importAndSavePages( if (application.getGitApplicationMetadata() != null) { if (!pagesFromOtherBranches.containsKey(newPage.getGitSyncId())) { - return saveNewPageAndUpdateBaseId(newPage, importingMetaDTO.getBranchName()); + return saveNewPageAndUpdateBaseId(newPage, importingMetaDTO); } NewPage branchedPage = pagesFromOtherBranches.get(newPage.getGitSyncId()); newPage.setBaseId(branchedPage.getBaseId()); - newPage.setBranchName(importingMetaDTO.getBranchName()); + newPage.setRefType(importingMetaDTO.getRefType()); + newPage.setRefName(importingMetaDTO.getRefName()); newPage.getUnpublishedPage() .setDeletedAt(branchedPage .getUnpublishedPage() @@ -489,7 +492,7 @@ private Flux importAndSavePages( newPage.setPolicies(branchedPage.getPolicies()); return newPageService.save(newPage); } - return saveNewPageAndUpdateBaseId(newPage, importingMetaDTO.getBranchName()); + return saveNewPageAndUpdateBaseId(newPage, importingMetaDTO); } }); }) @@ -499,9 +502,10 @@ private Flux importAndSavePages( }); } - private Mono saveNewPageAndUpdateBaseId(NewPage newPage, String branchName) { + private Mono saveNewPageAndUpdateBaseId(NewPage newPage, ImportingMetaDTO importingMetaDTO) { NewPage update = new NewPage(); - newPage.setBranchName(branchName); + newPage.setRefType(importingMetaDTO.getRefType()); + newPage.setRefName(importingMetaDTO.getRefName()); return newPageService.save(newPage).flatMap(page -> { if (StringUtils.isEmpty(page.getBaseId())) { update.setBaseId(page.getId()); diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomActionCollectionRepositoryCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomActionCollectionRepositoryCE.java index 4da3cdc325ab..173ea95a818a 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomActionCollectionRepositoryCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomActionCollectionRepositoryCE.java @@ -6,7 +6,6 @@ import com.appsmith.server.repositories.AppsmithRepository; import org.springframework.data.domain.Sort; import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; import java.util.List; import java.util.Optional; @@ -25,9 +24,6 @@ Flux findNonComposedByApplicationIdAndViewMode( Flux findByPageId(String pageId); - Mono findByBranchNameAndBaseCollectionId( - String branchName, String baseCollectionId, AclPermission permission); - Flux findByPageIds(List pageIds, AclPermission permission); Flux findAllByApplicationIds(List applicationIds, List includeFields); diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomActionCollectionRepositoryCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomActionCollectionRepositoryCEImpl.java index 2c845414323e..10a9d9c9d649 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomActionCollectionRepositoryCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomActionCollectionRepositoryCEImpl.java @@ -9,7 +9,6 @@ import com.appsmith.server.repositories.BaseAppsmithRepositoryImpl; import org.springframework.data.domain.Sort; import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; import java.util.List; import java.util.Optional; @@ -84,16 +83,6 @@ public Flux findByPageId(String pageId) { return this.findByPageId(pageId, null); } - @Override - public Mono findByBranchNameAndBaseCollectionId( - String branchName, String baseCollectionId, AclPermission permission) { - final BridgeQuery bq = Bridge.equal( - ActionCollection.Fields.baseId, baseCollectionId) - .equal(ActionCollection.Fields.branchName, branchName); - - return queryBuilder().criteria(bq).permission(permission).one(); - } - @Override public Flux findByPageIds(List pageIds, AclPermission permission) { BridgeQuery pageIdCriteria = diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomNewActionRepositoryCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomNewActionRepositoryCE.java index debbd0b8b5d9..7076da23aed5 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomNewActionRepositoryCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomNewActionRepositoryCE.java @@ -50,9 +50,6 @@ Flux findByApplicationId( Mono countByDatasourceId(String datasourceId); - Mono findByBranchNameAndBaseActionId( - String branchName, String baseActionId, Boolean viewMode, AclPermission permission); - Flux findByPageIds(List pageIds, AclPermission permission); Flux findByPageIds(List pageIds, Optional permission); diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomNewActionRepositoryCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomNewActionRepositoryCEImpl.java index 33d511dd0990..60ab2e1c0eda 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomNewActionRepositoryCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomNewActionRepositoryCEImpl.java @@ -275,21 +275,6 @@ public Mono countByDatasourceId(String datasourceId) { return queryBuilder().criteria(q).count(); } - @Override - public Mono findByBranchNameAndBaseActionId( - String branchName, String baseActionId, Boolean viewMode, AclPermission permission) { - final BridgeQuery q = Bridge.equal(NewAction.Fields.baseId, baseActionId) - .equal(NewAction.Fields.branchName, branchName); - - if (Boolean.FALSE.equals(viewMode)) { - // In case an action has been deleted in edit mode, but still exists in deployed mode, NewAction object - // would exist. To handle this, only fetch non-deleted actions - q.isNull(NewAction.Fields.unpublishedAction_deletedAt); - } - - return queryBuilder().criteria(q).permission(permission).one(); - } - @Override public Flux findByPageIds(List pageIds, AclPermission permission) { return queryBuilder() diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomNewPageRepositoryCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomNewPageRepositoryCE.java index e2fa493346aa..4f901e9fa30c 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomNewPageRepositoryCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomNewPageRepositoryCE.java @@ -1,5 +1,6 @@ package com.appsmith.server.repositories.ce; +import com.appsmith.external.git.constants.ce.RefType; import com.appsmith.server.acl.AclPermission; import com.appsmith.server.domains.NewPage; import com.appsmith.server.repositories.AppsmithRepository; @@ -32,8 +33,12 @@ Mono findByNameAndApplicationIdAndViewMode( Mono getNameByPageId(String pageId, boolean isPublishedName); - Mono findPageByBranchNameAndBasePageId( - String branchName, String basePageId, AclPermission permission, List projectedFieldNames); + Mono findPageByRefTypeAndRefNameAndBasePageId( + RefType refType, + String refName, + String basePageId, + AclPermission permission, + List projectedFieldNames); Flux findAllByApplicationIds(List branchedArtifactIds, List includedFields); diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomNewPageRepositoryCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomNewPageRepositoryCEImpl.java index 0fd9514d73c9..5f6bec3f82e8 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomNewPageRepositoryCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomNewPageRepositoryCEImpl.java @@ -1,5 +1,6 @@ package com.appsmith.server.repositories.ce; +import com.appsmith.external.git.constants.ce.RefType; import com.appsmith.server.acl.AclPermission; import com.appsmith.server.constants.FieldName; import com.appsmith.server.domains.Layout; @@ -8,7 +9,6 @@ import com.appsmith.server.helpers.ce.bridge.Bridge; import com.appsmith.server.helpers.ce.bridge.BridgeQuery; import com.appsmith.server.helpers.ce.bridge.BridgeUpdate; -import com.appsmith.server.projections.IdOnly; import com.appsmith.server.repositories.BaseAppsmithRepositoryImpl; import io.micrometer.observation.ObservationRegistry; import lombok.RequiredArgsConstructor; @@ -131,6 +131,8 @@ public Flux findAllPageDTOsByIds(List ids, AclPermission aclPer NewPage.Fields.applicationId, NewPage.Fields.baseId, NewPage.Fields.branchName, + NewPage.Fields.refType, + NewPage.Fields.refName, NewPage.Fields.policyMap, NewPage.Fields.unpublishedPage_name, NewPage.Fields.unpublishedPage_icon, @@ -169,18 +171,27 @@ public Mono getNameByPageId(String pageId, boolean isPublishedName) { } @Override - public Mono findPageByBranchNameAndBasePageId( - String branchName, String basePageId, AclPermission permission, List projectedFieldNames) { + public Mono findPageByRefTypeAndRefNameAndBasePageId( + RefType refType, + String refName, + String basePageId, + AclPermission permission, + List projectedFieldNames) { final BridgeQuery q = // defaultPageIdCriteria Bridge.equal(NewPage.Fields.baseId, basePageId); - if (branchName != null) { + if (refName != null) { // branchCriteria - q.equal(NewPage.Fields.branchName, branchName); + BridgeQuery refQuery = Bridge.or( + Bridge.equal(NewPage.Fields.branchName, refName), + Bridge.and( + Bridge.equal(NewPage.Fields.refName, refName), + Bridge.equal(NewPage.Fields.refType, refType))); + q.and(refQuery); } else { - q.isNull(NewPage.Fields.branchName); + q.and(Bridge.and(Bridge.isNull(NewPage.Fields.branchName), Bridge.isNull(NewPage.Fields.refName))); } return queryBuilder() @@ -192,19 +203,6 @@ public Mono findPageByBranchNameAndBasePageId( .tap(Micrometer.observation(observationRegistry)); } - public Mono findBranchedPageId(String branchName, String defaultPageId, AclPermission permission) { - final BridgeQuery q = - // defaultPageIdCriteria - Bridge.equal(NewPage.Fields.baseId, defaultPageId); - q.equal(NewPage.Fields.branchName, branchName); - - return queryBuilder() - .criteria(q) - .permission(permission) - .one(IdOnly.class) - .map(IdOnly::id); - } - @Override public Flux findAllByApplicationIds(List applicationIds, List includedFields) { return queryBuilder() diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/ApplicationPageServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/ApplicationPageServiceCEImpl.java index 1536ba67a357..0ccded931494 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/ApplicationPageServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/ApplicationPageServiceCEImpl.java @@ -1,6 +1,7 @@ package com.appsmith.server.services.ce; import com.appsmith.external.constants.AnalyticsEvents; +import com.appsmith.external.git.constants.ce.RefType; import com.appsmith.external.models.ActionDTO; import com.appsmith.external.models.BaseDomain; import com.appsmith.external.models.Datasource; @@ -166,7 +167,8 @@ public Mono createPage(PageDTO page) { Mono pageMono = applicationMono.map(application -> { generateAndSetPagePolicies(application, page); if (application.getGitArtifactMetadata() != null) { - page.setBranchName(application.getGitArtifactMetadata().getBranchName()); + page.setRefType(application.getGitArtifactMetadata().getRefType()); + page.setRefName(application.getGitArtifactMetadata().getRefName()); } return page; }); @@ -309,11 +311,12 @@ public Mono getPageDTOAfterMigratingDSL(NewPage newPage, boolean viewMo @Override public Mono getPageAndMigrateDslByBranchAndBasePageId( - String defaultPageId, String branchName, boolean viewMode, boolean migrateDsl) { + String defaultPageId, String refName, boolean viewMode, boolean migrateDsl) { ApplicationMode applicationMode = viewMode ? ApplicationMode.PUBLISHED : ApplicationMode.EDIT; // Fetch the page with read permission in both editor and in viewer. return newPageService - .findByBranchNameAndBasePageId(branchName, defaultPageId, pagePermission.getReadPermission(), null) + .findByRefTypeAndRefNameAndBasePageId( + RefType.branch, refName, defaultPageId, pagePermission.getReadPermission(), null) .flatMap(newPage -> getPageDTOAfterMigratingDSL(newPage, viewMode, migrateDsl) .name(getQualifiedSpanName(MIGRATE_DSL, applicationMode)) .tap(Micrometer.observation(observationRegistry))); @@ -576,7 +579,8 @@ public Mono clonePage(String pageId) { .switchIfEmpty(Mono.error(new AppsmithException(AppsmithError.ACTION_IS_NOT_AUTHORIZED, "Clone Page"))) .flatMap(page -> { ClonePageMetaDTO clonePageMetaDTO = new ClonePageMetaDTO(); - clonePageMetaDTO.setBranchName(page.getBranchName()); + clonePageMetaDTO.setRefType(page.getRefType()); + clonePageMetaDTO.setRefName(page.getRefName()); return applicationService .saveLastEditInformation(page.getApplicationId()) .then(clonePageGivenApplicationId( @@ -651,7 +655,7 @@ protected Mono clonePageGivenApplicationId( page.setApplicationId(applicationId); GitArtifactMetadata gitData = application.getGitApplicationMetadata(); if (gitData != null) { - page.setBranchName(gitData.getBranchName()); + page.setRefName(gitData.getRefName()); } return newPageService.createDefault(page); }); @@ -738,7 +742,7 @@ public Mono cloneApplication(String branchedApplicationId) { if (application.getGitApplicationMetadata() == null || application .getGitApplicationMetadata() - .getBranchName() + .getRefName() .equals(application .getGitApplicationMetadata() .getDefaultBranchName())) { @@ -1278,7 +1282,7 @@ public Mono reorderPage(String branchedApplicationId, Strin return applicationRepository .setPages(application.getId(), pages) .flatMap(ignored -> sendPageOrderAnalyticsEvent( - application, branchedPageId, order, branchedPage.getBranchName())) + application, branchedPageId, order, branchedPage.getRefName())) .then(newPageService.findApplicationPagesByBranchedApplicationIdAndViewMode( application.getId(), Boolean.FALSE, false)); }); diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/ConsolidatedAPIServiceCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/ConsolidatedAPIServiceCE.java index 4e7c427fe249..697664f8f01d 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/ConsolidatedAPIServiceCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/ConsolidatedAPIServiceCE.java @@ -1,5 +1,6 @@ package com.appsmith.server.services.ce; +import com.appsmith.external.git.constants.ce.RefType; import com.appsmith.server.domains.ApplicationMode; import com.appsmith.server.dtos.ConsolidatedAPIResponseDTO; import reactor.core.publisher.Mono; @@ -7,5 +8,5 @@ public interface ConsolidatedAPIServiceCE { Mono getConsolidatedInfoForPageLoad( - String defaultPageId, String applicationId, String branchName, ApplicationMode mode); + String defaultPageId, String applicationId, RefType refType, String refName, ApplicationMode mode); } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/ConsolidatedAPIServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/ConsolidatedAPIServiceCEImpl.java index 18e0b23294e0..7872f46995fe 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/ConsolidatedAPIServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/ConsolidatedAPIServiceCEImpl.java @@ -1,6 +1,7 @@ package com.appsmith.server.services.ce; import com.appsmith.external.exceptions.ErrorDTO; +import com.appsmith.external.git.constants.ce.RefType; import com.appsmith.external.models.CreatorContextType; import com.appsmith.external.models.Datasource; import com.appsmith.server.actioncollections.base.ActionCollectionService; @@ -138,7 +139,7 @@ protected Mono> toResponseDTO(Mono mono) { */ @Override public Mono getConsolidatedInfoForPageLoad( - String basePageId, String baseApplicationId, String branchName, ApplicationMode mode) { + String basePageId, String baseApplicationId, RefType refType, String refName, ApplicationMode mode) { /* if either of pageId or defaultApplicationId are provided then application mode must also be provided */ if (mode == null && (!isBlank(basePageId) || !isBlank(baseApplicationId))) { @@ -149,7 +150,7 @@ public Mono getConsolidatedInfoForPageLoad( ConsolidatedAPIResponseDTO consolidatedAPIResponseDTO = new ConsolidatedAPIResponseDTO(); List> fetches = - getAllFetchableMonos(consolidatedAPIResponseDTO, basePageId, baseApplicationId, branchName, mode); + getAllFetchableMonos(consolidatedAPIResponseDTO, basePageId, baseApplicationId, refType, refName, mode); return Mono.when(fetches).thenReturn(consolidatedAPIResponseDTO); } @@ -158,7 +159,8 @@ protected List> getAllFetchableMonos( ConsolidatedAPIResponseDTO consolidatedAPIResponseDTO, String basePageId, String baseApplicationId, - String branchName, + RefType refType, + String refName, ApplicationMode mode) { final List> fetches = new ArrayList<>(); @@ -222,7 +224,7 @@ protected List> getAllFetchableMonos( Mono baseApplicationIdMono = getBaseApplicationIdMono(basePageId, baseApplicationId, mode, isViewMode); Mono> applicationAndPageTupleMono = - getApplicationAndPageTupleMono(basePageId, branchName, mode, baseApplicationIdMono, isViewMode); + getApplicationAndPageTupleMono(basePageId, refType, refName, mode, baseApplicationIdMono, isViewMode); Mono branchedPageMonoCached = applicationAndPageTupleMono.map(Tuple2::getT2).cache(); @@ -499,7 +501,8 @@ protected Mono getBranchedApplicationMono( protected Mono> getApplicationAndPageTupleMono( String basePageId, - String branchName, + RefType refType, + String refName, ApplicationMode mode, Mono baseApplicationIdMono, boolean isViewMode) { @@ -509,13 +512,13 @@ protected Mono> getApplicationAndPageTupleMono( Mono branchedPageMonoCached; branchedPageMonoCached = newPageService - .findByBranchNameAndBasePageIdAndApplicationMode(branchName, basePageId, mode) + .findByRefTypeAndRefNameAndBasePageIdAndApplicationMode(refType, refName, basePageId, mode) .cache(); if (StringUtils.hasText(cachedBaseApplicationId)) { // Handle non-empty baseApplicationId applicationMono = applicationService.findByBaseIdBranchNameAndApplicationMode( - cachedBaseApplicationId, branchName, mode); + cachedBaseApplicationId, refName, mode); } else { // Handle empty or null baseApplicationId applicationMono = branchedPageMonoCached.flatMap(branchedPage -> @@ -538,7 +541,7 @@ protected Mono> getApplicationAndPageTupleMono( })); } - if (StringUtils.hasText(branchName)) { + if (StringUtils.hasText(refName)) { // If in case the application is a non git connected application and the branch name url param // is present, then we must default to the app without any branches. @@ -548,16 +551,16 @@ protected Mono> getApplicationAndPageTupleMono( // called errors out on empty returns. log.info( - "application or page has for base pageId {} and branchName {} has not been found.", + "application or page has for base pageId {} and refName {} has not been found.", basePageId, - branchName); + refName); if (error instanceof AppsmithException) { Mono basePageMono = - newPageService.findByBranchNameAndBasePageIdAndApplicationMode( - null, basePageId, mode); + newPageService.findByRefTypeAndRefNameAndBasePageIdAndApplicationMode( + null, null, basePageId, mode); return basePageMono.flatMap(basePage -> { - if (StringUtils.hasText(basePage.getBranchName())) { + if (StringUtils.hasText(basePage.getRefName())) { // If the branch name is present then the application is git connected // the error should be thrown. // TODO: verify if branch name could be residue from old git connection @@ -571,7 +574,7 @@ protected Mono> getApplicationAndPageTupleMono( .zipWith(basePageMono) .map(tuple2 -> { log.info( - "The branchName url param should not be associated with application {} as this is not a git connected application", + "The refName url param should not be associated with application {} as this is not a git connected application", tuple2.getT1().getId()); return tuple2; }); @@ -592,7 +595,7 @@ protected Mono> getApplicationAndPageTupleMono( boolean isDefaultBranchNameAbsent = isNotAGitApp || !StringUtils.hasText(gitMetadata.getDefaultBranchName()); boolean isBranchDefault = !isDefaultBranchNameAbsent - && gitMetadata.getDefaultBranchName().equals(gitMetadata.getBranchName()); + && gitMetadata.getDefaultBranchName().equals(gitMetadata.getRefName()); // This last check is specially for view mode, when a queried page which is not present // in default branch, and cacheable repository refers to the base application @@ -619,8 +622,8 @@ protected Mono> getApplicationAndPageTupleMono( return applicationService .findByBaseIdBranchNameAndApplicationMode(application.getId(), defaultBranchName, mode) - .zipWith(newPageService.findByBranchNameAndBasePageIdAndApplicationMode( - defaultBranchName, basePageId, mode)); + .zipWith(newPageService.findByRefTypeAndRefNameAndBasePageIdAndApplicationMode( + RefType.branch, defaultBranchName, basePageId, mode)); }); }) .cache(); diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/CurlImporterServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/CurlImporterServiceCEImpl.java index d4a473ae650e..b15c60793b3a 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/CurlImporterServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/CurlImporterServiceCEImpl.java @@ -7,7 +7,6 @@ import com.appsmith.external.models.DatasourceConfiguration; import com.appsmith.external.models.Property; import com.appsmith.server.constants.FieldName; -import com.appsmith.server.domains.NewPage; import com.appsmith.server.domains.Plugin; import com.appsmith.server.exceptions.AppsmithError; import com.appsmith.server.exceptions.AppsmithException; @@ -105,13 +104,6 @@ public Mono importAction( .flatMap(action2 -> layoutActionService.createSingleAction(action2)); } - protected Mono getBranchedContextId(CreatorContextType contextType, String contextId, String branchName) { - return newPageService - .findByBranchNameAndBasePageId( - branchName, contextId, pagePermission.getActionCreatePermission(), List.of(NewPage.Fields.id)) - .map(NewPage::getId); - } - protected Mono associateContextIdToActionDTO( ActionDTO actionDTO, CreatorContextType contextType, String contextId) { actionDTO.setPageId(contextId); diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/LayoutActionServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/LayoutActionServiceCEImpl.java index 6eef236d4def..0539352ff1fc 100755 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/LayoutActionServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/LayoutActionServiceCEImpl.java @@ -347,7 +347,8 @@ public Mono createSingleAction(ActionDTO actionDTO, Boolean isJsActio .switchIfEmpty(Mono.error( new AppsmithException(AppsmithError.NO_RESOURCE_FOUND, FieldName.PAGE, actionDTO.getPageId()))) .flatMap(newPage -> { - actionDTO.setBranchName(newPage.getBranchName()); + actionDTO.setRefType(newPage.getRefType()); + actionDTO.setRefName(newPage.getRefName()); AppsmithEventContext eventContext = new AppsmithEventContext(AppsmithEventContextType.DEFAULT); CreateActionMetaDTO createActionMetaDTO = new CreateActionMetaDTO(); createActionMetaDTO.setIsJsAction(isJsAction); diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/LayoutCollectionServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/LayoutCollectionServiceCEImpl.java index e644b9f7ea64..cc2533c1375c 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/LayoutCollectionServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/LayoutCollectionServiceCEImpl.java @@ -157,7 +157,8 @@ protected Mono validateAndCreateActionCollectionDomain(ActionC return newPageService .findById(collectionDTO.getPageId(), pagePermission.getActionCreatePermission()) .map(branchedPage -> { - actionCollection.setBranchName(branchedPage.getBranchName()); + actionCollection.setRefType(branchedPage.getRefType()); + actionCollection.setRefName(branchedPage.getRefName()); actionCollectionService.generateAndSetPolicies(branchedPage, actionCollection); actionCollection.setUnpublishedCollection(collectionDTO); @@ -342,7 +343,8 @@ public Mono updateUnpublishedActionCollection( actionCollectionDTO.getName() + "." + actionDTO.getName()); actionDTO.setPluginType(actionCollectionDTO.getPluginType()); actionDTO.setPluginId(actionCollectionDTO.getPluginId()); - actionDTO.setBranchName(branchedActionCollection.getBranchName()); + actionDTO.setRefType(branchedActionCollection.getRefType()); + actionDTO.setRefName(branchedActionCollection.getRefName()); // actionCollectionService is a new action, we need to create one if (duplicateNames.contains(actionDTO.getName())) { @@ -380,9 +382,10 @@ public Mono updateUnpublishedActionCollection( // return an empty action so that the filter can remove it from the list .onErrorResume(throwable -> { log.debug( - "Failed to delete action with id {}, branch {} for collection: {}", + "Failed to delete action with id {}, {} {} for collection: {}", x.getBaseId(), - x.getBranchName(), + x.getRefType(), + x.getRefName(), actionCollectionDTO.getName()); log.error(throwable.getMessage()); return Mono.empty(); diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ce/AuthenticationServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ce/AuthenticationServiceCEImpl.java index eec29d9169db..8d4909cc4b8f 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ce/AuthenticationServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ce/AuthenticationServiceCEImpl.java @@ -4,6 +4,7 @@ import com.appsmith.external.exceptions.BaseException; import com.appsmith.external.exceptions.pluginExceptions.AppsmithPluginError; import com.appsmith.external.exceptions.pluginExceptions.AppsmithPluginException; +import com.appsmith.external.git.constants.ce.RefType; import com.appsmith.external.helpers.SSLHelper; import com.appsmith.external.helpers.restApiUtils.helpers.OAuth2Utils; import com.appsmith.external.models.AuthenticationDTO; @@ -147,17 +148,19 @@ public Mono getAuthorizationCodeURLForGenericOAuth2( String workspaceId = tuple2.getT2().getT1(); String trueEnvironmentId = tuple2.getT2().getT2(); NewPage branchedPage = tuple2.getT2().getT3(); - String branchName = null; + String refName = null; + RefType refType = null; - if (hasText(branchedPage.getBranchName())) { - branchName = branchedPage.getBranchName(); + if (hasText(branchedPage.getRefName())) { + refType = branchedPage.getRefType(); + refName = branchedPage.getRefName(); } String basePageId = branchedPage.getBaseIdOrFallback(); OAuth2 oAuth2 = (OAuth2) datasourceStorage.getDatasourceConfiguration().getAuthentication(); final String redirectUri = redirectHelper.getRedirectDomain(httpRequest.getHeaders()); - final String state = StringUtils.hasText(branchName) + final String state = StringUtils.hasText(refName) ? String.join( ",", basePageId, @@ -165,7 +168,8 @@ public Mono getAuthorizationCodeURLForGenericOAuth2( trueEnvironmentId, redirectUri, workspaceId, - branchName) + refType.name(), + refName) : String.join(",", basePageId, datasourceId, trueEnvironmentId, redirectUri, workspaceId); // Adding basic uri components UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromUriString( @@ -354,7 +358,7 @@ private Mono getPageRedirectUrl(String state, String error) { final String environmentId = splitState[2]; final String redirectOrigin = splitState[3]; final String workspaceId = splitState[4]; - final String branchName = splitState.length == 6 ? splitState[5] : null; + final String refName = splitState.length == 7 ? splitState[6] : null; String response = SUCCESS; if (error != null) { response = error; @@ -374,7 +378,7 @@ private Mono getPageRedirectUrl(String state, String error) { + responseStatus + "&view_mode=true" + (StringUtils.hasText(workspaceId) ? "&workspaceId=" + workspaceId : "") - + (StringUtils.hasText(branchName) ? "&branch=" + branchName : ""); + + (StringUtils.hasText(refName) ? "&branch=" + refName : ""); }) .onErrorResume(e -> Mono.just(redirectOrigin + Entity.SLASH + Entity.APPLICATIONS + "?response_status=" @@ -549,8 +553,9 @@ protected Mono getContext(String branchedContextId, Creato pageRedirectionDTO.setId(basePage.getId()); pageRedirectionDTO.setBaseId(basePage.getBaseId()); pageRedirectionDTO.setApplicationId(basePage.getApplicationId()); - // the branch name should come from the branched page as it is required for redirecting - pageRedirectionDTO.setBranchName(branchedPage.getBranchName()); + // the ref name should come from the ref page as it is required for redirecting + pageRedirectionDTO.setRefName(branchedPage.getRefName()); + pageRedirectionDTO.setRefType(branchedPage.getRefType()); return pageRedirectionDTO; }); }); @@ -562,8 +567,9 @@ protected IntegrationDTO associateIntegrationDTOWithContext( integrationDTO.setPageId(pageRedirectionDTO.getBaseIdOrFallback()); integrationDTO.setApplicationId(pageRedirectionDTO.getApplicationId()); - if (hasText(pageRedirectionDTO.getBranchName())) { - integrationDTO.setBranch(pageRedirectionDTO.getBranchName()); + if (hasText(pageRedirectionDTO.getRefName())) { + integrationDTO.setRefType(pageRedirectionDTO.getRefType()); + integrationDTO.setRefName(pageRedirectionDTO.getRefName()); } return integrationDTO; } 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 00dba526a9c8..da73e86a08bc 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 @@ -396,7 +396,10 @@ public Mono createPageFromDBTable( .filter(newAction -> StringUtils.equalsIgnoreCase( newAction.getUnpublishedAction().getPageId(), plugin.getGenerateCRUDPageComponent())) - .peek(newAction -> newAction.setBranchName(page.getBranchName())) + .peek(newAction -> { + newAction.setRefType(page.getRefType()); + newAction.setRefName(page.getRefName()); + }) .collect(Collectors.toList()); List templateUnpublishedActionConfigList = templateActionList.stream() @@ -523,9 +526,9 @@ private Mono getOrCreatePage(String branchedApplicationId, String branc page.setApplicationId(applicationId); page.setName(pageName); if (branchedApplication.getGitArtifactMetadata() != null) { - page.setBranchName(branchedApplication + page.setRefName(branchedApplication .getGitArtifactMetadata() - .getBranchName()); + .getRefName()); } return applicationPageService.createPage(page); })) @@ -610,7 +613,8 @@ private Flux cloneActionsFromTemplateApplication( actionDTO.setDatasource(datasourceService.createDatasourceFromDatasourceStorage(datasourceStorage)); actionDTO.setPageId(pageId); actionDTO.setName(templateAction.getUnpublishedAction().getName()); - actionDTO.setBranchName(templateAction.getBranchName()); + actionDTO.setRefType(templateAction.getRefType()); + actionDTO.setRefName(templateAction.getRefName()); // Indicates that source of action creation is generate-crud-page actionDTO.setSource(ActionCreationSourceTypeEnum.GENERATE_PAGE); diff --git a/app/server/appsmith-server/src/test/it/com/appsmith/server/git/GitBranchesIT.java b/app/server/appsmith-server/src/test/it/com/appsmith/server/git/GitBranchesIT.java index a20345d049d4..cba8496fd85e 100644 --- a/app/server/appsmith-server/src/test/it/com/appsmith/server/git/GitBranchesIT.java +++ b/app/server/appsmith-server/src/test/it/com/appsmith/server/git/GitBranchesIT.java @@ -189,7 +189,7 @@ void test(GitContext gitContext, ExtensionContext extensionContext) throws IOExc try (Git git = Git.open(path.toFile())) { branch = git.log().getRepository().getBranch(); - assertThat(branch).isEqualTo(artifactMetadata.getBranchName()); + assertThat(branch).isEqualTo(artifactMetadata.getRefName()); // Assert only single system generated commit exists on FS Iterable commits = git.log().call(); @@ -231,7 +231,7 @@ void test(GitContext gitContext, ExtensionContext extensionContext) throws IOExc // Now there should be two commits in the git log response try (Git git = Git.open(path.toFile())) { branch = git.log().getRepository().getBranch(); - assertThat(branch).isEqualTo(artifactMetadata.getBranchName()); + assertThat(branch).isEqualTo(artifactMetadata.getRefName()); Iterable commits = git.log().call(); Iterator commitIterator = commits.iterator(); @@ -248,7 +248,7 @@ void test(GitContext gitContext, ExtensionContext extensionContext) throws IOExc } // Assert that the initialized branch is set as default - assertThat(artifactMetadata.getBranchName()).isEqualTo(artifactMetadata.getDefaultBranchName()); + assertThat(artifactMetadata.getRefName()).isEqualTo(artifactMetadata.getDefaultBranchName()); // Assert that the branch is not protected by default assertThat(artifactMetadata.getBranchProtectionRules()).isNullOrEmpty(); @@ -276,7 +276,7 @@ void test(GitContext gitContext, ExtensionContext extensionContext) throws IOExc // Check that the previous attempt didn't actually go through try (Git git = Git.open(path.toFile())) { branch = git.log().getRepository().getBranch(); - assertThat(branch).isEqualTo(artifactMetadata.getBranchName()); + assertThat(branch).isEqualTo(artifactMetadata.getRefName()); Iterable commits = git.log().call(); assertThat(commits.iterator().next().getId()).isEqualTo(topOfCommits); @@ -307,7 +307,7 @@ void test(GitContext gitContext, ExtensionContext extensionContext) throws IOExc try (Git git = Git.open(path.toFile())) { branch = git.log().getRepository().getBranch(); - assertThat(branch).isEqualTo(artifactMetadata.getBranchName()); + assertThat(branch).isEqualTo(artifactMetadata.getRefName()); Iterable commits = git.log().call(); Iterator commitIterator = commits.iterator(); @@ -358,11 +358,11 @@ void test(GitContext gitContext, ExtensionContext extensionContext) throws IOExc String fooArtifactId = fooArtifact.getId(); GitArtifactMetadata fooMetadata = fooArtifact.getGitArtifactMetadata(); - assertThat(fooMetadata.getBranchName()).isEqualTo("foo"); + assertThat(fooMetadata.getRefName()).isEqualTo("foo"); try (Git git = Git.open(path.toFile())) { branch = git.log().getRepository().getBranch(); - assertThat(branch).isEqualTo(fooMetadata.getBranchName()); + assertThat(branch).isEqualTo(fooMetadata.getRefName()); Iterable commits = git.log().call(); Iterator commitIterator = commits.iterator(); @@ -389,11 +389,11 @@ void test(GitContext gitContext, ExtensionContext extensionContext) throws IOExc String barArtifactId = barArtifact.getId(); GitArtifactMetadata barMetadata = barArtifact.getGitArtifactMetadata(); - assertThat(barMetadata.getBranchName()).isEqualTo("bar"); + assertThat(barMetadata.getRefName()).isEqualTo("bar"); try (Git git = Git.open(path.toFile())) { branch = git.log().getRepository().getBranch(); - assertThat(branch).isEqualTo(barMetadata.getBranchName()); + assertThat(branch).isEqualTo(barMetadata.getRefName()); Iterable commits = git.log().call(); Iterator commitIterator = commits.iterator(); @@ -417,12 +417,12 @@ void test(GitContext gitContext, ExtensionContext extensionContext) throws IOExc .collectList() .block(); assertThat(branchList).containsExactlyInAnyOrder( - artifactMetadata.getBranchName(), - "origin/" + artifactMetadata.getBranchName(), - fooMetadata.getBranchName(), - "origin/" + fooMetadata.getBranchName(), - barMetadata.getBranchName(), - "origin/" + barMetadata.getBranchName()); + artifactMetadata.getRefName(), + "origin/" + artifactMetadata.getRefName(), + fooMetadata.getRefName(), + "origin/" + fooMetadata.getRefName(), + barMetadata.getRefName(), + "origin/" + barMetadata.getRefName()); Mono deleteBranchAttemptMono = commonGitService.deleteBranch(artifactId, "foo", artifactType); StepVerifier @@ -445,11 +445,11 @@ void test(GitContext gitContext, ExtensionContext extensionContext) throws IOExc .collectList() .block(); assertThat(branchList2).containsExactlyInAnyOrder( - artifactMetadata.getBranchName(), - "origin/" + artifactMetadata.getBranchName(), - "origin/" + fooMetadata.getBranchName(), - barMetadata.getBranchName(), - "origin/" + barMetadata.getBranchName()); + artifactMetadata.getRefName(), + "origin/" + artifactMetadata.getRefName(), + "origin/" + fooMetadata.getRefName(), + barMetadata.getRefName(), + "origin/" + barMetadata.getRefName()); Artifact checkedOutFooArtifact = commonGitService.checkoutBranch(artifactId, "origin/foo", true, artifactType).block(); @@ -460,17 +460,17 @@ void test(GitContext gitContext, ExtensionContext extensionContext) throws IOExc .collectList() .block(); assertThat(branchList3).containsExactlyInAnyOrder( - artifactMetadata.getBranchName(), - "origin/" + artifactMetadata.getBranchName(), - fooMetadata.getBranchName(), - "origin/" + fooMetadata.getBranchName(), - barMetadata.getBranchName(), - "origin/" + barMetadata.getBranchName()); + artifactMetadata.getRefName(), + "origin/" + artifactMetadata.getRefName(), + fooMetadata.getRefName(), + "origin/" + fooMetadata.getRefName(), + barMetadata.getRefName(), + "origin/" + barMetadata.getRefName()); // Verify latest commit on foo should be same as changes made on foo previously try (Git git = Git.open(path.toFile())) { branch = git.log().getRepository().getBranch(); - assertThat(branch).isEqualTo(fooMetadata.getBranchName()); + assertThat(branch).isEqualTo(fooMetadata.getRefName()); Iterable commits = git.log().call(); Iterator commitIterator = commits.iterator(); @@ -578,7 +578,7 @@ void test(GitContext gitContext, ExtensionContext extensionContext) throws IOExc } private AutoCommitResponseDTO.AutoCommitResponse getAutocommitProgress(String artifactId, Artifact artifact, GitArtifactMetadata artifactMetadata) { - AutoCommitResponseDTO autoCommitProgress = commonGitService.getAutoCommitProgress(artifactId, artifactMetadata.getBranchName(), artifact.getArtifactType()).block(); + AutoCommitResponseDTO autoCommitProgress = commonGitService.getAutoCommitProgress(artifactId, artifactMetadata.getRefName(), artifact.getArtifactType()).block(); assertThat(autoCommitProgress).isNotNull(); return autoCommitProgress.getAutoCommitResponse(); diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/exports/internal/ExportServiceTests.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/exports/internal/ExportServiceTests.java index 025e3d11f9c7..834a4b7e3ade 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/exports/internal/ExportServiceTests.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/exports/internal/ExportServiceTests.java @@ -831,7 +831,7 @@ public void exportImportApplication_importWithBranchName_updateApplicationResour testApplication.setModifiedBy("some-user"); testApplication.setGitApplicationMetadata(new GitArtifactMetadata()); GitArtifactMetadata gitData = new GitArtifactMetadata(); - gitData.setBranchName("testBranch"); + gitData.setRefName("testBranch"); testApplication.setGitApplicationMetadata(gitData); Application savedApplication = applicationPageService @@ -867,7 +867,7 @@ public void exportImportApplication_importWithBranchName_updateApplicationResour ArtifactType.APPLICATION) .map(artifactExchangeJson -> (ApplicationJson) artifactExchangeJson) .flatMap(applicationJson -> importService.importArtifactInWorkspaceFromGit( - workspaceId, savedApplication.getId(), applicationJson, gitData.getBranchName()))) + workspaceId, savedApplication.getId(), applicationJson, gitData.getRefName()))) .map(importableArtifact -> (Application) importableArtifact) .cache(); @@ -886,7 +886,7 @@ public void exportImportApplication_importWithBranchName_updateApplicationResour List actionList = tuple.getT3(); final String branchName = - application.getGitApplicationMetadata().getBranchName(); + application.getGitApplicationMetadata().getRefName(); pageList.forEach(page -> { assertThat(page.getBranchName()).isEqualTo(branchName); }); @@ -939,7 +939,7 @@ public void importUpdatedApplicationIntoWorkspaceFromFile_publicApplication_visi testApplication.setModifiedBy("some-user"); testApplication.setGitApplicationMetadata(new GitArtifactMetadata()); GitArtifactMetadata gitData = new GitArtifactMetadata(); - gitData.setBranchName("master"); + gitData.setRefName("master"); testApplication.setGitApplicationMetadata(gitData); Application application = applicationPageService @@ -1423,7 +1423,7 @@ public void exportApplication_withReadOnlyAccess_exportedWithDecryptedFields() { testApplication.getUnpublishedApplicationDetail().setNavigationSetting(appNavigationSetting); testApplication.setGitApplicationMetadata(new GitArtifactMetadata()); GitArtifactMetadata gitData = new GitArtifactMetadata(); - gitData.setBranchName("testBranch"); + gitData.setRefName("testBranch"); testApplication.setGitApplicationMetadata(gitData); Application savedApplication = applicationPageService .createApplication(testApplication, workspaceId) @@ -1442,7 +1442,7 @@ public void exportApplication_withReadOnlyAccess_exportedWithDecryptedFields() { applicationJson.getExportedApplication().setPublishedApplicationDetail(null); return importService .importArtifactInWorkspaceFromGit( - workspaceId, savedApplication.getId(), applicationJson, gitData.getBranchName()) + workspaceId, savedApplication.getId(), applicationJson, gitData.getRefName()) .map(importableArtifact -> (Application) importableArtifact); }); @@ -1482,7 +1482,7 @@ public void importApplicationInWorkspaceFromGit_WithAppLayoutInEditMode_Imported testApplication.setUnpublishedAppLayout(new Application.AppLayout(Application.AppLayout.Type.DESKTOP)); testApplication.setGitApplicationMetadata(new GitArtifactMetadata()); GitArtifactMetadata gitData = new GitArtifactMetadata(); - gitData.setBranchName("testBranch"); + gitData.setRefName("testBranch"); testApplication.setGitApplicationMetadata(gitData); Application savedApplication = applicationPageService .createApplication(testApplication, workspaceId) @@ -1501,7 +1501,7 @@ public void importApplicationInWorkspaceFromGit_WithAppLayoutInEditMode_Imported applicationJson.getExportedApplication().setPublishedAppLayout(null); return importService .importArtifactInWorkspaceFromGit( - workspaceId, savedApplication.getId(), applicationJson, gitData.getBranchName()) + workspaceId, savedApplication.getId(), applicationJson, gitData.getRefName()) .map(importableArtifact -> (Application) importableArtifact); }); diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/fork/ApplicationForkingServiceTests.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/fork/ApplicationForkingServiceTests.java index e303be7d492c..fb84d7ea6cb1 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/fork/ApplicationForkingServiceTests.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/fork/ApplicationForkingServiceTests.java @@ -1001,7 +1001,7 @@ public void forkGitConnectedApplication_defaultBranchUpdated_forkDefaultBranchAp theme.setDisplayName("theme_" + uniqueString); GitArtifactMetadata gitArtifactMetadata = new GitArtifactMetadata(); gitArtifactMetadata.setDefaultApplicationId(createdSrcApplication.getId()); - gitArtifactMetadata.setBranchName("master"); + gitArtifactMetadata.setRefName("master"); gitArtifactMetadata.setDefaultBranchName("feature1"); gitArtifactMetadata.setIsRepoPrivate(false); gitArtifactMetadata.setRepoName("testRepo"); @@ -1023,7 +1023,7 @@ public void forkGitConnectedApplication_defaultBranchUpdated_forkDefaultBranchAp GitArtifactMetadata gitArtifactMetadata1 = new GitArtifactMetadata(); gitArtifactMetadata1.setDefaultApplicationId(createdSrcApplication.getId()); - gitArtifactMetadata1.setBranchName("feature1"); + gitArtifactMetadata1.setRefName("feature1"); gitArtifactMetadata1.setDefaultBranchName("feature1"); gitArtifactMetadata1.setIsRepoPrivate(false); gitArtifactMetadata1.setRepoName("testRepo"); 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 307014c1735a..8963aba9e620 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 @@ -4,6 +4,7 @@ import com.appsmith.external.dtos.GitStatusDTO; import com.appsmith.external.dtos.MergeStatusDTO; import com.appsmith.external.git.GitExecutor; +import com.appsmith.external.git.constants.ce.RefType; import com.appsmith.external.models.ActionConfiguration; import com.appsmith.external.models.ActionDTO; import com.appsmith.external.models.Datasource; @@ -690,7 +691,7 @@ public void connectArtifactToGit_WithEmptyPublishedPages_CloneSuccess() throws I .assertNext(application -> { GitArtifactMetadata gitArtifactMetadata1 = application.getGitApplicationMetadata(); assertThat(gitArtifactMetadata1.getRemoteUrl()).isEqualTo(gitConnectDTO.getRemoteUrl()); - assertThat(gitArtifactMetadata1.getBranchName()).isEqualTo("defaultBranchName"); + assertThat(gitArtifactMetadata1.getRefName()).isEqualTo("defaultBranchName"); assertThat(gitArtifactMetadata1.getGitAuth().getPrivateKey()) .isNotNull(); assertThat(gitArtifactMetadata1.getGitAuth().getPublicKey()).isNotNull(); @@ -769,7 +770,7 @@ public void connectArtifactToGit_WithoutGitProfileUsingDefaultProfile_CloneSucce .assertNext(application -> { GitArtifactMetadata gitArtifactMetadata1 = application.getGitApplicationMetadata(); assertThat(gitArtifactMetadata1.getRemoteUrl()).isEqualTo(gitConnectDTO.getRemoteUrl()); - assertThat(gitArtifactMetadata1.getBranchName()).isEqualTo("defaultBranchName"); + assertThat(gitArtifactMetadata1.getRefName()).isEqualTo("defaultBranchName"); }) .verifyComplete(); } @@ -792,7 +793,7 @@ public void connectArtifactToGit_WithoutGitProfileUsingLocalProfile_ThrowAuthorN gitAuth.setDocUrl("docUrl"); gitArtifactMetadata.setGitAuth(gitAuth); gitArtifactMetadata.setRemoteUrl("git@github.com:test/testRepo.git"); - gitArtifactMetadata.setBranchName("defaultBranchNameFromRemote"); + gitArtifactMetadata.setRefName("defaultBranchNameFromRemote"); gitArtifactMetadata.setRepoName("testRepo"); testApplication.setGitApplicationMetadata(gitArtifactMetadata); testApplication.setName("localGitProfile"); @@ -880,7 +881,7 @@ public void connectArtifactToGit_WithNonEmptyPublishedPages_CloneSuccess() throw .assertNext(application -> { GitArtifactMetadata gitArtifactMetadata1 = application.getGitApplicationMetadata(); assertThat(gitArtifactMetadata1.getRemoteUrl()).isEqualTo(gitConnectDTO.getRemoteUrl()); - assertThat(gitArtifactMetadata1.getBranchName()).isEqualTo("defaultBranchName"); + assertThat(gitArtifactMetadata1.getRefName()).isEqualTo("defaultBranchName"); assertThat(gitArtifactMetadata1.getGitAuth().getPrivateKey()) .isNotNull(); assertThat(gitArtifactMetadata1.getGitAuth().getPublicKey()).isNotNull(); @@ -1087,7 +1088,7 @@ public void connectArtifactToGit_WithValidCustomGitDomain_CloneSuccess() throws .assertNext(application -> { GitArtifactMetadata gitArtifactMetadata1 = application.getGitApplicationMetadata(); assertThat(gitArtifactMetadata1.getRemoteUrl()).isEqualTo(gitConnectDTO.getRemoteUrl()); - assertThat(gitArtifactMetadata1.getBranchName()).isEqualTo("defaultBranchName"); + assertThat(gitArtifactMetadata1.getRefName()).isEqualTo("defaultBranchName"); assertThat(gitArtifactMetadata1.getGitAuth().getPrivateKey()) .isNotNull(); assertThat(gitArtifactMetadata1.getGitAuth().getPublicKey()).isNotNull(); @@ -1187,7 +1188,7 @@ public void detachRemote_applicationWithActionAndActionCollection_Success() { gitArtifactMetadata.setRepoName("repoName"); gitArtifactMetadata.setDefaultApplicationId("TestId"); gitArtifactMetadata.setDefaultBranchName("defaultBranchFromRemote"); - gitArtifactMetadata.setBranchName("defaultBranch"); + gitArtifactMetadata.setRefName("defaultBranch"); testApplication.setGitApplicationMetadata(gitArtifactMetadata); testApplication.setName("detachRemote_validData"); testApplication.setWorkspaceId(workspaceId); @@ -1224,7 +1225,8 @@ public void detachRemote_applicationWithActionAndActionCollection_Success() { action.setDatasource(datasource); action.setBaseId("branchedActionId"); - action.setBranchName("testBranch"); + action.setRefType(RefType.branch); + action.setRefName("testBranch"); ObjectMapper objectMapper = new ObjectMapper(); JSONObject parentDsl = null; @@ -1489,7 +1491,7 @@ public void listBranchForArtifact_defaultBranchChangesInRemoteExistsInDB_Success .assertNext(application -> { assertThat(application.getGitApplicationMetadata().getDefaultBranchName()) .isEqualTo("feature1"); - assertThat(application.getGitApplicationMetadata().getBranchName()) + assertThat(application.getGitApplicationMetadata().getRefName()) .isEqualTo("defaultBranch"); }) .verifyComplete(); @@ -1555,7 +1557,7 @@ public void listBranchForArtifact_defaultBranchChangesInRemoteDoesNotExistsInDB_ .assertNext(application -> { assertThat(application.getGitApplicationMetadata().getDefaultBranchName()) .isEqualTo("feature1"); - assertThat(application.getGitApplicationMetadata().getBranchName()) + assertThat(application.getGitApplicationMetadata().getRefName()) .isEqualTo("defaultBranch"); }) .verifyComplete(); @@ -1727,8 +1729,8 @@ public void isBranchMergeable_nonConflictingChanges_canBeMerged() throws IOExcep application1 = applicationService.save(application1).block(); GitMergeDTO gitMergeDTO = new GitMergeDTO(); - gitMergeDTO.setSourceBranch(application1.getGitApplicationMetadata().getBranchName()); - gitMergeDTO.setDestinationBranch(application.getGitApplicationMetadata().getBranchName()); + gitMergeDTO.setSourceBranch(application1.getGitApplicationMetadata().getRefName()); + gitMergeDTO.setDestinationBranch(application.getGitApplicationMetadata().getRefName()); MergeStatusDTO mergeStatus = new MergeStatusDTO(); mergeStatus.setMergeAble(true); @@ -1775,7 +1777,7 @@ public void isBranchMergeable_conflictingChanges_canNotBeMerged() throws IOExcep applicationService.save(application).block(); GitMergeDTO gitMergeDTO = new GitMergeDTO(); - gitMergeDTO.setSourceBranch(application.getGitApplicationMetadata().getBranchName()); + gitMergeDTO.setSourceBranch(application.getGitApplicationMetadata().getRefName()); gitMergeDTO.setDestinationBranch(DEFAULT_BRANCH); MergeStatusDTO mergeStatus = new MergeStatusDTO(); @@ -1823,7 +1825,7 @@ public void isBranchMergeable_remoteAhead_remoteAheadErrorMessage() throws IOExc applicationService.save(application1).block(); GitMergeDTO gitMergeDTO = new GitMergeDTO(); - gitMergeDTO.setSourceBranch(application1.getGitApplicationMetadata().getBranchName()); + gitMergeDTO.setSourceBranch(application1.getGitApplicationMetadata().getRefName()); gitMergeDTO.setDestinationBranch(DEFAULT_BRANCH); GitStatusDTO gitStatusDTO = new GitStatusDTO(); @@ -1920,7 +1922,7 @@ public void checkoutRemoteBranch_notPresentInLocal_newApplicationCreated() throw StepVerifier.create(applicationMono) .assertNext(application1 -> { - assertThat(application1.getGitApplicationMetadata().getBranchName()) + assertThat(application1.getGitApplicationMetadata().getRefName()) .isEqualTo("branchNotInLocal"); assertThat(application1.getGitApplicationMetadata().getDefaultArtifactId()) .isEqualTo(gitConnectedApplication.getId()); @@ -2627,7 +2629,7 @@ public void createBranch_validCreateBranchRequest_newApplicationCreated() throws assertThat(application).isNotNull(); assertThat(application.getId()).isNotEqualTo(gitData.getDefaultArtifactId()); assertThat(gitData.getDefaultArtifactId()).isEqualTo(parentApplication.getId()); - assertThat(gitData.getBranchName()).isEqualTo(createGitBranchDTO.getBranchName()); + assertThat(gitData.getRefName()).isEqualTo(createGitBranchDTO.getBranchName()); assertThat(gitData.getDefaultBranchName()).isNotEmpty(); assertThat(gitData.getRemoteUrl()).isNotEmpty(); assertThat(gitData.getBrowserSupportedRemoteUrl()).isNotEmpty(); @@ -2981,9 +2983,9 @@ public void createBranch_BranchDeleteLogo_SrcLogoRemainsUnchanged() throws GitAP Application branchedApplication = applicationTuple.getT1(); Application application = applicationTuple.getT2(); String srcBranchName = - application.getGitApplicationMetadata().getBranchName(); + application.getGitApplicationMetadata().getRefName(); String otherBranchName = - branchedApplication.getGitApplicationMetadata().getBranchName(); + branchedApplication.getGitApplicationMetadata().getRefName(); String defaultApplicationId = branchedApplication.getGitApplicationMetadata().getDefaultArtifactId(); @@ -3062,9 +3064,9 @@ public void createBranch_BranchSetPageIcon_SrcBranchPageIconRemainsNull() throws Application branchedApplication = applicationTuple.getT1(); Application application = applicationTuple.getT2(); String srcBranchName = - application.getGitApplicationMetadata().getBranchName(); + application.getGitApplicationMetadata().getRefName(); String otherBranchName = - branchedApplication.getGitApplicationMetadata().getBranchName(); + branchedApplication.getGitApplicationMetadata().getRefName(); String defaultApplicationId = branchedApplication.getGitApplicationMetadata().getDefaultArtifactId(); @@ -3289,7 +3291,7 @@ public void createBranch_cancelledMidway_newApplicationCreated() throws GitAPIEx assertThat(application).isNotNull(); assertThat(application.getId()).isNotEqualTo(gitData.getDefaultArtifactId()); assertThat(gitData.getDefaultArtifactId()).isEqualTo(application1.getId()); - assertThat(gitData.getBranchName()).isEqualTo(createGitBranchDTO.getBranchName()); + assertThat(gitData.getRefName()).isEqualTo(createGitBranchDTO.getBranchName()); assertThat(gitData.getDefaultBranchName()).isNotEmpty(); assertThat(gitData.getRemoteUrl()).isNotEmpty(); assertThat(gitData.getBrowserSupportedRemoteUrl()).isNotEmpty(); @@ -3480,7 +3482,7 @@ public void importArtifactFromGit_validRequest_Success() { Application application = applicationImportDTO.getApplication(); assertThat(application.getName()).isEqualTo("testRepo"); assertThat(application.getGitApplicationMetadata()).isNotNull(); - assertThat(application.getGitApplicationMetadata().getBranchName()) + assertThat(application.getGitApplicationMetadata().getRefName()) .isEqualTo("defaultBranch"); assertThat(application.getGitApplicationMetadata().getDefaultBranchName()) .isEqualTo("defaultBranch"); @@ -3533,7 +3535,7 @@ public void importArtifactFromGit_validRequestWithDuplicateApplicationName_Succe Application application = applicationImportDTO.getApplication(); assertThat(application.getName()).isEqualTo("testGitRepo (1)"); assertThat(application.getGitApplicationMetadata()).isNotNull(); - assertThat(application.getGitApplicationMetadata().getBranchName()) + assertThat(application.getGitApplicationMetadata().getRefName()) .isEqualTo("defaultBranch"); assertThat(application.getGitApplicationMetadata().getDefaultBranchName()) .isEqualTo("defaultBranch"); @@ -3601,7 +3603,7 @@ public void importArtifactFromGit_validRequestWithDuplicateDatasourceOfSameType_ Application application = applicationImportDTO.getApplication(); assertThat(application.getName()).isEqualTo("testGitImportRepo"); assertThat(application.getGitApplicationMetadata()).isNotNull(); - assertThat(application.getGitApplicationMetadata().getBranchName()) + assertThat(application.getGitApplicationMetadata().getRefName()) .isEqualTo("defaultBranch"); assertThat(application.getGitApplicationMetadata().getDefaultBranchName()) .isEqualTo("defaultBranch"); @@ -3687,7 +3689,7 @@ public void importArtifactFromGit_validRequestWithDuplicateDatasourceOfSameTypeC .assertNext(application -> { assertThat(application.getName()).isEqualTo("testGitImportRepoCancelledMidway"); assertThat(application.getGitApplicationMetadata()).isNotNull(); - assertThat(application.getGitApplicationMetadata().getBranchName()) + assertThat(application.getGitApplicationMetadata().getRefName()) .isEqualTo("defaultBranch"); assertThat(application.getGitApplicationMetadata().getDefaultBranchName()) .isEqualTo("defaultBranch"); @@ -3847,7 +3849,7 @@ public void deleteBranch_branchDoesNotExist_ThrowError() throws IOException, Git Mockito.when(gitExecutor.deleteBranch(any(Path.class), Mockito.anyString())) .thenReturn(Mono.just(false)); - application.getGitApplicationMetadata().setBranchName("not-present-branch"); + application.getGitApplicationMetadata().setRefName("not-present-branch"); Mockito.doReturn(Mono.just(application)) .when(applicationService) .findByBranchNameAndBaseApplicationId(anyString(), anyString(), any(AclPermission.class)); @@ -4067,7 +4069,7 @@ public void deleteBranch_cancelledMidway_success() throws GitAPIException, IOExc .assertNext(applicationList -> { Set branchNames = new HashSet<>(); applicationList.forEach(application1 -> branchNames.add( - application1.getGitApplicationMetadata().getBranchName())); + application1.getGitApplicationMetadata().getRefName())); assertThat(branchNames).doesNotContain(TO_BE_DELETED_BRANCH); }) .verifyComplete(); @@ -4189,7 +4191,7 @@ public void checkoutRemoteBranch_WhenApplicationObjectIsPresent_NewAppNotCreated String appName = "app_" + UUID.randomUUID().toString(); Application application = createApplicationConnectedToGit(appName, "develop"); - assertThat(application.getGitApplicationMetadata().getBranchName()).isEqualTo("develop"); + assertThat(application.getGitApplicationMetadata().getRefName()).isEqualTo("develop"); assertThat(application.getId()) .isEqualTo(application.getGitApplicationMetadata().getDefaultArtifactId()); @@ -4223,7 +4225,7 @@ public void checkoutRemoteBranch_WhenApplicationObjectIsPresent_NewAppNotCreated StepVerifier.create(checkoutBranchMono) .assertNext(app -> { assertThat(app.getId()).isEqualTo(application.getId()); - assertThat(app.getGitApplicationMetadata().getBranchName()).isEqualTo("develop"); + assertThat(app.getGitApplicationMetadata().getRefName()).isEqualTo("develop"); assertThat(app.getGitApplicationMetadata().getGitAuth()).isNotNull(); }) .verifyComplete(); @@ -4366,7 +4368,7 @@ private String createBranchedApplication(List branchList) { // set the git app meta data GitArtifactMetadata gitArtifactMetadata = new GitArtifactMetadata(); - gitArtifactMetadata.setBranchName(s); + gitArtifactMetadata.setRefName(s); gitArtifactMetadata.setDefaultBranchName(defaultBranchName); gitArtifactMetadata.setDefaultApplicationId(defaultAppId); createdApp.setGitApplicationMetadata(gitArtifactMetadata); diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/git/autocommit/AutoCommitServiceTest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/git/autocommit/AutoCommitServiceTest.java index 3a7e5f53c350..39a4287537c5 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/git/autocommit/AutoCommitServiceTest.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/git/autocommit/AutoCommitServiceTest.java @@ -141,7 +141,7 @@ private Application createApplication() { application.setPages(List.of(applicationPage)); GitArtifactMetadata gitArtifactMetadata = new GitArtifactMetadata(); - gitArtifactMetadata.setBranchName(BRANCH_NAME); + gitArtifactMetadata.setRefName(BRANCH_NAME); gitArtifactMetadata.setDefaultBranchName(DEFAULT_BRANCH_NAME); gitArtifactMetadata.setRepoName(REPO_NAME); gitArtifactMetadata.setDefaultApplicationId(DEFAULT_APP_ID); @@ -647,7 +647,7 @@ public void testAutoCommit_whenServerIsRunningMigrationCallsAutocommitAgainOnDif .isEqualTo(AutoCommitResponseDTO.AutoCommitResponse.PUBLISHED)) .verifyComplete(); - testApplication.getGitApplicationMetadata().setBranchName("another-branch-name"); + testApplication.getGitApplicationMetadata().setRefName("another-branch-name"); // redis-utils fixing Mockito.when(redisUtils.getRunningAutoCommitBranchName(DEFAULT_APP_ID)).thenReturn(Mono.just(BRANCH_NAME)); diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/git/autocommit/helpers/AutoCommitEligibilityHelperTest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/git/autocommit/helpers/AutoCommitEligibilityHelperTest.java index c6e08c5bb4a4..c77a12b55028 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/git/autocommit/helpers/AutoCommitEligibilityHelperTest.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/git/autocommit/helpers/AutoCommitEligibilityHelperTest.java @@ -65,7 +65,7 @@ private GitArtifactMetadata createGitMetadata() { GitArtifactMetadata gitArtifactMetadata = new GitArtifactMetadata(); gitArtifactMetadata.setDefaultApplicationId(DEFAULT_APPLICATION_ID); gitArtifactMetadata.setRepoName(REPO_NAME); - gitArtifactMetadata.setBranchName(BRANCH_NAME); + gitArtifactMetadata.setRefName(BRANCH_NAME); return gitArtifactMetadata; } diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/git/autocommit/helpers/GitAutoCommitHelperImplTest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/git/autocommit/helpers/GitAutoCommitHelperImplTest.java index 80f0f122c5ae..f7d10aab1d82 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/git/autocommit/helpers/GitAutoCommitHelperImplTest.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/git/autocommit/helpers/GitAutoCommitHelperImplTest.java @@ -287,7 +287,7 @@ public void autoCommitApplication_WhenServerRequiresMigration_successIfEverythin GitArtifactMetadata metaData = new GitArtifactMetadata(); metaData.setRepoName("test-repo-name"); metaData.setDefaultApplicationId(defaultApplicationId); - metaData.setBranchName(branchName); + metaData.setRefName(branchName); GitAuth gitAuth = new GitAuth(); gitAuth.setPrivateKey("private-key"); @@ -333,7 +333,7 @@ public void autoCommitApplication_WhenServerDoesNotRequireMigration_returnFalse( GitArtifactMetadata metaData = new GitArtifactMetadata(); metaData.setRepoName("test-repo-name"); metaData.setDefaultApplicationId(defaultApplicationId); - metaData.setBranchName(branchName); + metaData.setRefName(branchName); GitAuth gitAuth = new GitAuth(); gitAuth.setPrivateKey("private-key"); diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/git/ops/GitConnectTests.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/git/ops/GitConnectTests.java index d1d576bbcad8..9d848250e358 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/git/ops/GitConnectTests.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/git/ops/GitConnectTests.java @@ -332,7 +332,7 @@ public void connectArtifactToGit_whenUsingGlobalProfile_completesSuccessfully() .assertNext(application -> { GitArtifactMetadata gitArtifactMetadata1 = application.getGitApplicationMetadata(); assertThat(gitArtifactMetadata1.getRemoteUrl()).isEqualTo(gitConnectDTO.getRemoteUrl()); - assertThat(gitArtifactMetadata1.getBranchName()).isEqualTo("defaultBranchName"); + assertThat(gitArtifactMetadata1.getRefName()).isEqualTo("defaultBranchName"); }) .verifyComplete(); } @@ -361,7 +361,7 @@ public void connectArtifactToGit_whenUsingIncompleteLocalProfile_throwsAuthorNam gitAuth.setDocUrl("docUrl"); gitArtifactMetadata.setGitAuth(gitAuth); gitArtifactMetadata.setRemoteUrl("git@github.com:test/testRepo.git"); - gitArtifactMetadata.setBranchName("defaultBranchNameFromRemote"); + gitArtifactMetadata.setRefName("defaultBranchNameFromRemote"); gitArtifactMetadata.setRepoName("testRepo"); testApplication.setGitApplicationMetadata(gitArtifactMetadata); testApplication.setName("localGitProfile"); diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/helpers/GitUtilsTest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/helpers/GitUtilsTest.java index 551253497455..c0fe33b94d1c 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/helpers/GitUtilsTest.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/helpers/GitUtilsTest.java @@ -268,7 +268,7 @@ public void testIsDefaultBranchedApplication_DefaultBranch() { GitArtifactMetadata metadata = new GitArtifactMetadata(); metadata.setDefaultApplicationId(UUID.randomUUID().toString()); metadata.setRemoteUrl("https://git.example.com/repo.git"); - metadata.setBranchName("main"); + metadata.setRefName("main"); metadata.setDefaultBranchName("main"); defaultBranchApplication.setGitApplicationMetadata(metadata); @@ -282,7 +282,7 @@ public void testIsDefaultBranchedApplication_NotDefaultBranch() { GitArtifactMetadata metadata = new GitArtifactMetadata(); metadata.setDefaultApplicationId(UUID.randomUUID().toString()); metadata.setRemoteUrl("https://git.example.com/repo.git"); - metadata.setBranchName("feature-branch"); + metadata.setRefName("feature-branch"); metadata.setDefaultBranchName("main"); nonDefaultBranchApplication.setGitApplicationMetadata(metadata); @@ -313,7 +313,7 @@ public void testIsDefaultBranchedApplication_NullBranchName() { GitArtifactMetadata metadata = new GitArtifactMetadata(); metadata.setDefaultApplicationId(UUID.randomUUID().toString()); metadata.setRemoteUrl("https://git.example.com/repo.git"); - metadata.setBranchName(null); + metadata.setRefName(null); metadata.setDefaultBranchName("main"); nullBranchNameApplication.setGitApplicationMetadata(metadata); @@ -327,7 +327,7 @@ public void testIsDefaultBranchedApplication_NullDefaultBranchName() { GitArtifactMetadata metadata = new GitArtifactMetadata(); metadata.setDefaultApplicationId(UUID.randomUUID().toString()); metadata.setRemoteUrl("https://git.example.com/repo.git"); - metadata.setBranchName("main"); + metadata.setRefName("main"); metadata.setDefaultBranchName(null); nullDefaultBranchNameApplication.setGitApplicationMetadata(metadata); 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 38337a84be5a..cfc76f867793 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 @@ -1,6 +1,7 @@ package com.appsmith.server.imports.internal; import com.appsmith.external.dtos.ModifiedResources; +import com.appsmith.external.git.constants.ce.RefType; import com.appsmith.external.helpers.AppsmithBeanUtils; import com.appsmith.external.models.ActionConfiguration; import com.appsmith.external.models.ActionDTO; @@ -329,6 +330,7 @@ private Flux getActionsInApplication(Application application) { .findByApplicationId(application.getId(), READ_PAGES, false) .flatMap(page -> newActionService.getUnpublishedActions( new LinkedMultiValueMap<>(Map.of(FieldName.PAGE_ID, Collections.singletonList(page.getId()))), + RefType.branch, "")); } @@ -1365,7 +1367,7 @@ public void exportImportApplication_importWithBranchName_updateApplicationResour testApplication.setModifiedBy("some-user"); testApplication.setGitApplicationMetadata(new GitArtifactMetadata()); GitArtifactMetadata gitData = new GitArtifactMetadata(); - gitData.setBranchName("testBranch"); + gitData.setRefName("testBranch"); testApplication.setGitApplicationMetadata(gitData); Application savedApplication = applicationPageService @@ -1398,7 +1400,7 @@ public void exportImportApplication_importWithBranchName_updateApplicationResour .exportByArtifactId(savedApplication.getId(), VERSION_CONTROL, APPLICATION) .map(artifactExchangeJson -> (ApplicationJson) artifactExchangeJson) .flatMap(applicationJson -> importService.importArtifactInWorkspaceFromGit( - workspaceId, savedApplication.getId(), applicationJson, gitData.getBranchName()))) + workspaceId, savedApplication.getId(), applicationJson, gitData.getRefName()))) .map(importableArtifact -> (Application) importableArtifact) .cache(); @@ -1417,7 +1419,7 @@ public void exportImportApplication_importWithBranchName_updateApplicationResour List actionList = tuple.getT3(); final String branchName = - application.getGitApplicationMetadata().getBranchName(); + application.getGitApplicationMetadata().getRefName(); pageList.forEach(page -> { assertThat(page.getBranchName()).isEqualTo(branchName); }); @@ -1581,7 +1583,7 @@ public void importArtifactIntoWorkspace_pageRemovedAndUpdatedDefaultPageNameInBr testApplication.setModifiedBy("some-user"); testApplication.setGitApplicationMetadata(new GitArtifactMetadata()); GitArtifactMetadata gitData = new GitArtifactMetadata(); - gitData.setBranchName("master"); + gitData.setRefName("master"); testApplication.setGitApplicationMetadata(gitData); Application application = applicationPageService @@ -1655,7 +1657,7 @@ public void importArtifactIntoWorkspace_pageAddedInBranchApplication_Success() { testApplication.setModifiedBy("some-user"); testApplication.setGitApplicationMetadata(new GitArtifactMetadata()); GitArtifactMetadata gitData = new GitArtifactMetadata(); - gitData.setBranchName("master"); + gitData.setRefName("master"); testApplication.setGitApplicationMetadata(gitData); Application application = applicationPageService @@ -1753,7 +1755,7 @@ public void importUpdatedApplicationIntoWorkspaceFromFile_publicApplication_visi testApplication.setModifiedBy("some-user"); testApplication.setGitApplicationMetadata(new GitArtifactMetadata()); GitArtifactMetadata gitData = new GitArtifactMetadata(); - gitData.setBranchName("master"); + gitData.setRefName("master"); testApplication.setGitApplicationMetadata(gitData); Application application = applicationPageService @@ -3275,7 +3277,7 @@ public void importApplication_datasourceWithSameNameAndPlugin_importedWithValidA testApplication.getUnpublishedApplicationDetail().setNavigationSetting(appNavigationSetting); testApplication.setGitApplicationMetadata(new GitArtifactMetadata()); GitArtifactMetadata gitData = new GitArtifactMetadata(); - gitData.setBranchName("testBranch"); + gitData.setRefName("testBranch"); testApplication.setGitApplicationMetadata(gitData); Application savedApplication = applicationPageService .createApplication(testApplication, workspaceId) @@ -3293,7 +3295,7 @@ public void importApplication_datasourceWithSameNameAndPlugin_importedWithValidA applicationJson.getExportedApplication().setPublishedApplicationDetail(null); return importService .importArtifactInWorkspaceFromGit( - workspaceId, savedApplication.getId(), applicationJson, gitData.getBranchName()) + workspaceId, savedApplication.getId(), applicationJson, gitData.getRefName()) .map(importableArtifact -> (Application) importableArtifact); }); @@ -3333,7 +3335,7 @@ public void importApplicationInWorkspaceFromGit_WithAppLayoutInEditMode_Imported testApplication.setUnpublishedAppLayout(new Application.AppLayout(Application.AppLayout.Type.DESKTOP)); testApplication.setGitApplicationMetadata(new GitArtifactMetadata()); GitArtifactMetadata gitData = new GitArtifactMetadata(); - gitData.setBranchName("testBranch"); + gitData.setRefName("testBranch"); testApplication.setGitApplicationMetadata(gitData); Application savedApplication = applicationPageService .createApplication(testApplication, workspaceId) @@ -3351,7 +3353,7 @@ public void importApplicationInWorkspaceFromGit_WithAppLayoutInEditMode_Imported applicationJson.getExportedApplication().setPublishedAppLayout(null); return importService .importArtifactInWorkspaceFromGit( - workspaceId, savedApplication.getId(), applicationJson, gitData.getBranchName()) + workspaceId, savedApplication.getId(), applicationJson, gitData.getRefName()) .map(importableArtifact -> (Application) importableArtifact); }); @@ -3841,7 +3843,7 @@ public void mergeApplication_gitConnectedApplication_pageAddedSuccessfully() { testApplication.setModifiedBy("some-user"); testApplication.setGitApplicationMetadata(new GitArtifactMetadata()); GitArtifactMetadata gitData = new GitArtifactMetadata(); - gitData.setBranchName("master"); + gitData.setRefName("master"); gitData.setDefaultBranchName("master"); testApplication.setGitApplicationMetadata(gitData); @@ -3932,7 +3934,7 @@ public void mergeApplication_gitConnectedApplicationChildBranch_pageAddedSuccess testApplication.setModifiedBy("some-user"); testApplication.setGitApplicationMetadata(new GitArtifactMetadata()); GitArtifactMetadata gitData = new GitArtifactMetadata(); - gitData.setBranchName("master"); + gitData.setRefName("master"); gitData.setDefaultBranchName("master"); testApplication.setGitApplicationMetadata(gitData); @@ -3953,7 +3955,7 @@ public void mergeApplication_gitConnectedApplicationChildBranch_pageAddedSuccess testApplication.setModifiedBy("some-user"); testApplication.setGitApplicationMetadata(new GitArtifactMetadata()); GitArtifactMetadata gitData1 = new GitArtifactMetadata(); - gitData1.setBranchName("feature"); + gitData1.setRefName("feature"); gitData1.setDefaultBranchName("master"); testApplication.setGitApplicationMetadata(gitData1); @@ -4042,7 +4044,7 @@ public void mergeApplication_gitConnectedApplicationSelectedSpecificPages_select testApplication.setModifiedBy("some-user"); testApplication.setGitApplicationMetadata(new GitArtifactMetadata()); GitArtifactMetadata gitData = new GitArtifactMetadata(); - gitData.setBranchName("master"); + gitData.setRefName("master"); gitData.setDefaultBranchName("master"); testApplication.setGitApplicationMetadata(gitData); @@ -4064,7 +4066,7 @@ public void mergeApplication_gitConnectedApplicationSelectedSpecificPages_select testApplication.setModifiedBy("some-user"); testApplication.setGitApplicationMetadata(new GitArtifactMetadata()); GitArtifactMetadata gitData1 = new GitArtifactMetadata(); - gitData1.setBranchName("feature"); + gitData1.setRefName("feature"); gitData1.setDefaultBranchName("master"); testApplication.setGitApplicationMetadata(gitData1); @@ -4153,7 +4155,7 @@ public void mergeApplication_gitConnectedApplicationSelectedAllPages_selectedPag testApplication.setModifiedBy("some-user"); testApplication.setGitApplicationMetadata(new GitArtifactMetadata()); GitArtifactMetadata gitData = new GitArtifactMetadata(); - gitData.setBranchName("master"); + gitData.setRefName("master"); gitData.setDefaultBranchName("master"); testApplication.setGitApplicationMetadata(gitData); @@ -4175,7 +4177,7 @@ public void mergeApplication_gitConnectedApplicationSelectedAllPages_selectedPag testApplication.setModifiedBy("some-user"); testApplication.setGitApplicationMetadata(new GitArtifactMetadata()); GitArtifactMetadata gitData1 = new GitArtifactMetadata(); - gitData1.setBranchName("feature"); + gitData1.setRefName("feature"); gitData1.setDefaultBranchName("master"); testApplication.setGitApplicationMetadata(gitData1); diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/refactors/ce/RefactoringServiceCETest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/refactors/ce/RefactoringServiceCETest.java index 739c4b997da8..6570ca2da9ac 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/refactors/ce/RefactoringServiceCETest.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/refactors/ce/RefactoringServiceCETest.java @@ -207,20 +207,19 @@ public void setup() { Application newApp = new Application(); newApp.setName(UUID.randomUUID().toString()); GitArtifactMetadata gitData = new GitArtifactMetadata(); - gitData.setBranchName("actionServiceTest"); + gitData.setRefName("actionServiceTest"); newApp.setGitApplicationMetadata(gitData); gitConnectedApp = applicationPageService .createApplication(newApp, workspaceId) .flatMap(application1 -> { application1.getGitApplicationMetadata().setDefaultApplicationId(application1.getId()); return applicationService.save(application1).zipWhen(application11 -> exportService - .exportByArtifactIdAndBranchName( - application11.getId(), gitData.getBranchName(), APPLICATION) + .exportByArtifactIdAndBranchName(application11.getId(), gitData.getRefName(), APPLICATION) .map(artifactExchangeJson -> (ApplicationJson) artifactExchangeJson)); }) // Assign the branchName to all the resources connected to the application .flatMap(tuple -> importService.importArtifactInWorkspaceFromGit( - workspaceId, tuple.getT1().getId(), tuple.getT2(), gitData.getBranchName())) + workspaceId, tuple.getT1().getId(), tuple.getT2(), gitData.getRefName())) .map(importableArtifact -> (Application) importableArtifact) .block(); @@ -228,7 +227,7 @@ public void setup() { .findPageById(gitConnectedApp.getPages().get(0).getId(), READ_PAGES, false) .block(); - branchName = gitConnectedApp.getGitApplicationMetadata().getBranchName(); + branchName = gitConnectedApp.getGitApplicationMetadata().getRefName(); workspaceId = workspace.getId(); datasource = new Datasource(); diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/refactors/ce/RefactoringServiceTest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/refactors/ce/RefactoringServiceTest.java index 28e8b18141de..9010de1a0e58 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/refactors/ce/RefactoringServiceTest.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/refactors/ce/RefactoringServiceTest.java @@ -187,7 +187,7 @@ public void setup() { Application newApp = new Application(); newApp.setName(UUID.randomUUID().toString()); GitArtifactMetadata gitData = new GitArtifactMetadata(); - gitData.setBranchName("actionServiceTest"); + gitData.setRefName("actionServiceTest"); newApp.setGitApplicationMetadata(gitData); gitConnectedApp = applicationPageService .createApplication(newApp, workspaceId) @@ -196,11 +196,11 @@ public void setup() { return applicationService .save(application1) .zipWhen(application11 -> exportService.exportByArtifactIdAndBranchName( - application11.getId(), gitData.getBranchName(), APPLICATION)); + application11.getId(), gitData.getRefName(), APPLICATION)); }) // Assign the branchName to all the resources connected to the application .flatMap(tuple -> importService.importArtifactInWorkspaceFromGit( - workspaceId, tuple.getT1().getId(), tuple.getT2(), gitData.getBranchName())) + workspaceId, tuple.getT1().getId(), tuple.getT2(), gitData.getRefName())) .map(importableArtifact -> (Application) importableArtifact) .block(); @@ -208,7 +208,7 @@ public void setup() { .findPageById(gitConnectedApp.getPages().get(0).getId(), READ_PAGES, false) .block(); - branchName = gitConnectedApp.getGitApplicationMetadata().getBranchName(); + branchName = gitConnectedApp.getGitApplicationMetadata().getRefName(); workspaceId = workspace.getId(); datasource = new Datasource(); diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/repositories/ce/CustomNewPageRepositoryTest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/repositories/ce/CustomNewPageRepositoryTest.java index 71da2c690722..0f5fadf984ce 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/repositories/ce/CustomNewPageRepositoryTest.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/repositories/ce/CustomNewPageRepositoryTest.java @@ -100,8 +100,8 @@ void publishPages_WhenIdMatches_Published() { @Test void findPageWithoutBranchName() { - StepVerifier.create(newPageRepository.findPageByBranchNameAndBasePageId( - null, "pageId", AclPermission.PAGE_CREATE_PAGE_ACTIONS, null)) + StepVerifier.create(newPageRepository.findPageByRefTypeAndRefNameAndBasePageId( + null, null, "pageId", AclPermission.PAGE_CREATE_PAGE_ACTIONS, null)) .verifyComplete(); } } diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/searchentities/SearchEntitySolutionCETest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/searchentities/SearchEntitySolutionCETest.java index f67e350bd86b..5f7d38a1d223 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/searchentities/SearchEntitySolutionCETest.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/searchentities/SearchEntitySolutionCETest.java @@ -248,7 +248,7 @@ private static Application mockGitConnectedApplication( application.setName(searchString + "_application"); application.setWorkspaceId(workspace.getId()); GitArtifactMetadata gitArtifactMetadata = new GitArtifactMetadata(); - gitArtifactMetadata.setBranchName(branchName); + gitArtifactMetadata.setRefName(branchName); gitArtifactMetadata.setDefaultBranchName(defaultBranchName); gitArtifactMetadata.setRemoteUrl("git@test.com:user/testRepo.git"); application.setGitApplicationMetadata(gitArtifactMetadata); diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ActionCollectionServiceImplTest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ActionCollectionServiceImplTest.java index 43b0d91a0850..41b452a91bce 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ActionCollectionServiceImplTest.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ActionCollectionServiceImplTest.java @@ -52,6 +52,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; @ExtendWith(SpringExtension.class) @Slf4j @@ -200,8 +201,8 @@ public void testCreateCollection_withRepeatedActionName_throwsError() throws IOE final NewPage newPage = objectMapper.convertValue(jsonNode.get("newPage"), NewPage.class); Mockito.when(newPageService.findById(Mockito.any(), Mockito.any())) .thenReturn(Mono.just(newPage)); - Mockito.when(newPageService.findByBranchNameAndBasePageId( - Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any())) + Mockito.when(newPageService.findByRefTypeAndRefNameAndBasePageId( + any(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any())) .thenReturn(Mono.just(newPage)); Mockito.when(refactoringService.isNameAllowed(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any())) .thenReturn(Mono.just(false)); @@ -234,8 +235,8 @@ public void testCreateCollection_createActionFailure_returnsWithIncompleteCollec Mockito.when(newPageService.findById(Mockito.any(), Mockito.any())) .thenReturn(Mono.just(newPage)); - Mockito.when(newPageService.findByBranchNameAndBasePageId( - Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any())) + Mockito.when(newPageService.findByRefTypeAndRefNameAndBasePageId( + any(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any())) .thenReturn(Mono.just(newPage)); Mockito.when(refactoringService.isNameAllowed(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any())) .thenReturn(Mono.just(true)); @@ -292,8 +293,8 @@ public void testCreateCollection_validCollection_returnsPopulatedCollection() th Mockito.when(newPageService.findById(Mockito.any(), Mockito.any())) .thenReturn(Mono.just(newPage)); - Mockito.when(newPageService.findByBranchNameAndBasePageId( - Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any())) + Mockito.when(newPageService.findByRefTypeAndRefNameAndBasePageId( + any(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any())) .thenReturn(Mono.just(newPage)); Mockito.when(refactoringService.isNameAllowed(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any())) .thenReturn(Mono.just(true)); @@ -388,8 +389,8 @@ public void testUpdateUnpublishedActionCollection_withInvalidId_throwsError() th Mockito.when(actionCollectionRepository.findById(Mockito.anyString(), Mockito.any())) .thenReturn(Mono.empty()); - Mockito.when(newPageService.findByBranchNameAndBasePageId( - Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any())) + Mockito.when(newPageService.findByRefTypeAndRefNameAndBasePageId( + any(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any())) .thenReturn(Mono.just(newPage)); Mockito.when(newPageService.findById(Mockito.any(), Mockito.any())) diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ApplicationPageServiceTest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ApplicationPageServiceTest.java index 9260c2672ec1..364e3ee7209c 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ApplicationPageServiceTest.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ApplicationPageServiceTest.java @@ -384,7 +384,7 @@ public void createOrUpdateSuffixedApplication_GitConnectedAppExistsWithSameName_ Application application = new Application(); application.setName(appName); GitArtifactMetadata gitArtifactMetadata = new GitArtifactMetadata(); - gitArtifactMetadata.setBranchName("branch1"); + gitArtifactMetadata.setRefName("branch1"); application.setGitApplicationMetadata(gitArtifactMetadata); Mono importAppMono = applicationPageService @@ -395,7 +395,7 @@ public void createOrUpdateSuffixedApplication_GitConnectedAppExistsWithSameName_ }) .flatMap(createdApp -> { createdApp.setId(null); - createdApp.getGitApplicationMetadata().setBranchName("branch2"); + createdApp.getGitApplicationMetadata().setRefName("branch2"); // just duplicate the app, we're not considering the pages, they remain same in both apps return applicationRepository.save(createdApp); }) diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ApplicationSnapshotServiceTest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ApplicationSnapshotServiceTest.java index 99aaf6bba8c9..6538471c394e 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ApplicationSnapshotServiceTest.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ApplicationSnapshotServiceTest.java @@ -149,7 +149,7 @@ public void createApplicationSnapshot_WhenGitBranchExists_SnapshotCreatedWithBra // this app will have default app id=testDefaultAppId and branch name=test branch name GitArtifactMetadata gitArtifactMetadata = new GitArtifactMetadata(); gitArtifactMetadata.setDefaultApplicationId(testDefaultAppId); - gitArtifactMetadata.setBranchName(testBranchName); + gitArtifactMetadata.setRefName(testBranchName); testApplication.setGitApplicationMetadata(gitArtifactMetadata); Mono> tuple2Mono = applicationPageService .createApplication(testApplication) diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/CurlImporterServiceTest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/CurlImporterServiceTest.java index cf8fdec1cca4..bacca9f82e67 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/CurlImporterServiceTest.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/CurlImporterServiceTest.java @@ -467,17 +467,10 @@ public void importValidCurlCommand() { curlImporterService.importAction(command, null, page.getId(), "actionName", workspaceId)) .cache(); - // As importAction updates the ids with the defaultIds before sending the response to client we have to again - // fetch branched action - Mono branchedSavedActionMono = - branchedResultMono.flatMap(actionDTO -> newActionService.findByBranchNameAndBaseActionId( - "testBranch", actionDTO.getId(), false, AclPermission.MANAGE_ACTIONS)); - - StepVerifier.create(Mono.zip(branchedResultMono, branchedPageMono, branchedSavedActionMono)) + StepVerifier.create(Mono.zip(branchedResultMono, branchedPageMono, branchedResultMono)) .assertNext(tuple -> { ActionDTO action1 = tuple.getT1(); - NewPage newPage = tuple.getT2(); - NewAction newAction = tuple.getT3(); + ActionDTO actionDTO = tuple.getT3(); assertThat(action1).isNotNull(); assertThat(action1.getDatasource()).isNotNull(); @@ -494,9 +487,9 @@ public void importValidCurlCommand() { assertThat(action1.getActionConfiguration().getHttpMethod()).isEqualTo(HttpMethod.GET); assertThat(action1.getActionConfiguration().getBody()).isEqualTo("{someJson}"); - assertThat(newAction.getBaseId()).isEqualTo(newAction.getId()); + assertThat(actionDTO.getBaseId()).isEqualTo(actionDTO.getId()); - assertThat(newAction.getBranchName()).isEqualTo("testBranch"); + assertThat(actionDTO.getRefName()).isEqualTo("testBranch"); }) .verifyComplete(); } diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/LayoutActionServiceTest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/LayoutActionServiceTest.java index ecda5e353fd8..4ad9cf33c936 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/LayoutActionServiceTest.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/LayoutActionServiceTest.java @@ -213,7 +213,7 @@ public void setup() { Application newApp = new Application(); newApp.setName(UUID.randomUUID().toString()); GitArtifactMetadata gitData = new GitArtifactMetadata(); - gitData.setBranchName("actionServiceTest"); + gitData.setRefName("actionServiceTest"); newApp.setGitApplicationMetadata(gitData); gitConnectedApp = applicationPageService .createApplication(newApp, workspaceId) @@ -221,12 +221,12 @@ public void setup() { application1.getGitApplicationMetadata().setDefaultApplicationId(application1.getId()); return applicationService.save(application1).zipWhen(application11 -> exportService .exportByArtifactIdAndBranchName( - application11.getId(), gitData.getBranchName(), ArtifactType.APPLICATION) + application11.getId(), gitData.getRefName(), ArtifactType.APPLICATION) .map(artifactExchangeJson -> (ApplicationJson) artifactExchangeJson)); }) // Assign the branchName to all the resources connected to the application .flatMap(tuple -> importService.importArtifactInWorkspaceFromGit( - workspaceId, tuple.getT1().getId(), tuple.getT2(), gitData.getBranchName())) + workspaceId, tuple.getT1().getId(), tuple.getT2(), gitData.getRefName())) .map(importableArtifact -> (Application) importableArtifact) .block(); @@ -234,7 +234,7 @@ public void setup() { .findPageById(gitConnectedApp.getPages().get(0).getId(), READ_PAGES, false) .block(); - branchName = gitConnectedApp.getGitApplicationMetadata().getBranchName(); + branchName = gitConnectedApp.getGitApplicationMetadata().getRefName(); workspaceId = workspace.getId(); datasource = new Datasource(); @@ -1103,7 +1103,8 @@ void testExecuteOnPageLoadOrderWhenAllActionsAreOnlyExplicitlySetToExecute() thr createdAction1.setExecuteOnLoad(true); // this can only be set to true post action creation. NewAction newAction1 = new NewAction(); newAction1.setUnpublishedAction(createdAction1); - newAction1.setBranchName(createdAction1.getBranchName()); + newAction1.setRefType(createdAction1.getRefType()); + newAction1.setRefName(createdAction1.getRefName()); newAction1.setBaseId(createdAction1.getBaseId()); newAction1.setPluginId(installed_plugin.getId()); newAction1.setPluginType(installed_plugin.getType()); @@ -1114,7 +1115,8 @@ void testExecuteOnPageLoadOrderWhenAllActionsAreOnlyExplicitlySetToExecute() thr createdAction2.setExecuteOnLoad(true); // this can only be set to true post action creation. NewAction newAction2 = new NewAction(); newAction2.setUnpublishedAction(createdAction2); - newAction2.setBranchName(createdAction2.getBranchName()); + newAction2.setRefType(createdAction2.getRefType()); + newAction2.setRefName(createdAction2.getRefName()); newAction2.setBaseId(createdAction2.getBaseId()); newAction2.setPluginId(installed_plugin.getId()); newAction2.setPluginType(installed_plugin.getType()); @@ -1188,7 +1190,8 @@ void updateLayout_WhenPageLoadActionSetBothWaysExplicitlyAndImplicitlyViaWidget_ createdAction1.setUserSetOnLoad(true); NewAction newAction1 = new NewAction(); newAction1.setUnpublishedAction(createdAction1); - newAction1.setBranchName(createdAction1.getBranchName()); + newAction1.setRefType(createdAction1.getRefType()); + newAction1.setRefName(createdAction1.getRefName()); newAction1.setBaseId(createdAction1.getBaseId()); newAction1.setPluginId(installed_plugin.getId()); newAction1.setPluginType(installed_plugin.getType()); diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/NewPageServiceTest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/NewPageServiceTest.java index 11237328ac62..b89277c7012a 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/NewPageServiceTest.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/NewPageServiceTest.java @@ -1,5 +1,6 @@ package com.appsmith.server.services; +import com.appsmith.external.git.constants.ce.RefType; import com.appsmith.external.models.Policy; import com.appsmith.server.applications.base.ApplicationService; import com.appsmith.server.domains.Application; @@ -426,7 +427,7 @@ public void updateDependencyMap_NotNullValue_shouldUpdateDependencyMap() { dependencyMap.put("key2", List.of("val1", "val2")); dependencyMap.put("key3", List.of("val1", "val2")); return newPageService - .updateDependencyMap(pageDTO.getId(), dependencyMap, null) + .updateDependencyMap(pageDTO.getId(), dependencyMap, RefType.branch, null) .then(newPageService.findById(pageDTO.getId(), null)); }); @@ -462,7 +463,7 @@ public void updateDependencyMap_NotNullValueAndPublishApplication_shouldUpdateDe dependencyMap.put("key2", List.of("val1", "val2")); dependencyMap.put("key3", List.of("val1", "val2")); return newPageService - .updateDependencyMap(pageDTO.getId(), dependencyMap, null) + .updateDependencyMap(pageDTO.getId(), dependencyMap, RefType.branch, null) .flatMap(page -> applicationPageService.publish(application.getId(), false)) .then(newPageService.findById(pageDTO.getId(), null)); }); @@ -499,7 +500,7 @@ public void updateDependencyMap_nullValue_shouldUpdateDependencyMap() { return applicationPageService.createPage(pageDTO); }) .flatMap(pageDTO -> newPageService - .updateDependencyMap(pageDTO.getId(), null, null) + .updateDependencyMap(pageDTO.getId(), null, RefType.branch, null) .then(newPageService.findById(pageDTO.getId(), null))); StepVerifier.create(newPageMono) diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/PageServiceTest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/PageServiceTest.java index 3ec766f804c9..0822fc81098c 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/PageServiceTest.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/PageServiceTest.java @@ -1,5 +1,6 @@ package com.appsmith.server.services; +import com.appsmith.external.git.constants.ce.RefType; import com.appsmith.external.models.ActionConfiguration; import com.appsmith.external.models.ActionDTO; import com.appsmith.external.models.Datasource; @@ -174,7 +175,7 @@ private Application setupGitConnectedTestApplication(String uniquePrefix) { Application newApp = new Application(); newApp.setName(UUID.randomUUID().toString()); GitArtifactMetadata gitData = new GitArtifactMetadata(); - gitData.setBranchName(uniquePrefix + "_pageServiceTest"); + gitData.setRefName(uniquePrefix + "_pageServiceTest"); newApp.setGitApplicationMetadata(gitData); return applicationPageService .createApplication(newApp, workspaceId) @@ -182,12 +183,12 @@ private Application setupGitConnectedTestApplication(String uniquePrefix) { application.getGitApplicationMetadata().setDefaultApplicationId(application.getId()); return applicationService.save(application).zipWhen(application1 -> exportService .exportByArtifactIdAndBranchName( - application1.getId(), gitData.getBranchName(), ArtifactType.APPLICATION) + application1.getId(), gitData.getRefName(), ArtifactType.APPLICATION) .map(artifactExchangeJson -> (ApplicationJson) artifactExchangeJson)); }) // Assign the branchName to all the resources connected to the application .flatMap(tuple -> importService.importArtifactInWorkspaceFromGit( - workspaceId, tuple.getT1().getId(), tuple.getT2(), gitData.getBranchName())) + workspaceId, tuple.getT1().getId(), tuple.getT2(), gitData.getRefName())) .map(artifactExchangeJson -> (Application) artifactExchangeJson) .block(); } @@ -790,7 +791,7 @@ public void clonePage_whenPageCloned_defaultIdsRetained() { gitConnectedApplication = setupGitConnectedTestApplication("clonePage"); final String pageId = gitConnectedApplication.getPages().get(0).getId(); final String branchName = - gitConnectedApplication.getGitApplicationMetadata().getBranchName(); + gitConnectedApplication.getGitApplicationMetadata().getRefName(); final PageDTO page = newPageService.findPageById(pageId, READ_PAGES, false).block(); @@ -862,8 +863,8 @@ public void clonePage_whenPageCloned_defaultIdsRetained() { final Mono pageMono = applicationPageService .clonePage(page.getId()) - .flatMap(pageDTO -> - newPageService.findByBranchNameAndBasePageId(branchName, pageDTO.getId(), MANAGE_PAGES, null)) + .flatMap(pageDTO -> newPageService.findByRefTypeAndRefNameAndBasePageId( + RefType.branch, branchName, pageDTO.getId(), MANAGE_PAGES, null)) .cache(); Mono> actionsMono = pageMono.flatMapMany( @@ -1150,7 +1151,7 @@ public void reorderPage_pageReordered_success() { gitConnectedApplication = setupGitConnectedTestApplication("reorderPage"); final String branchName = - gitConnectedApplication.getGitApplicationMetadata().getBranchName(); + gitConnectedApplication.getGitApplicationMetadata().getRefName(); final ApplicationPage[] pageIds = new ApplicationPage[4]; PageDTO testPage1 = new PageDTO(); diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ce/ActionServiceCE_Test.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ce/ActionServiceCE_Test.java index 9b496524358c..3c46097d5755 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ce/ActionServiceCE_Test.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ce/ActionServiceCE_Test.java @@ -250,7 +250,7 @@ public void setup() { Application newApp = new Application(); newApp.setName(UUID.randomUUID().toString()); GitArtifactMetadata gitData = new GitArtifactMetadata(); - gitData.setBranchName("actionServiceTest"); + gitData.setRefName("actionServiceTest"); newApp.setGitApplicationMetadata(gitData); gitConnectedApp = applicationPageService .createApplication(newApp, workspaceId) @@ -258,12 +258,12 @@ public void setup() { application2.getGitApplicationMetadata().setDefaultApplicationId(application2.getId()); return applicationService.save(application2).zipWhen(application1 -> exportService .exportByArtifactIdAndBranchName( - application1.getId(), gitData.getBranchName(), ArtifactType.APPLICATION) + application1.getId(), gitData.getRefName(), ArtifactType.APPLICATION) .map(artifactExchangeJson -> (ApplicationJson) artifactExchangeJson)); }) // Assign the branchName to all the resources connected to the application .flatMap(tuple -> importService.importArtifactInWorkspaceFromGit( - workspaceId, tuple.getT1().getId(), tuple.getT2(), gitData.getBranchName())) + workspaceId, tuple.getT1().getId(), tuple.getT2(), gitData.getRefName())) .map(importableArtifact -> (Application) importableArtifact) .block(); @@ -271,7 +271,7 @@ public void setup() { .findPageById(gitConnectedApp.getPages().get(0).getId(), READ_PAGES, false) .block(); - branchName = gitConnectedApp.getGitApplicationMetadata().getBranchName(); + branchName = gitConnectedApp.getGitApplicationMetadata().getRefName(); datasource = new Datasource(); datasource.setName("Default Database"); @@ -307,15 +307,12 @@ public void findByIdAndBranchName_forGitConnectedAction_getBranchedAction() { action.setActionConfiguration(actionConfiguration); action.setDatasource(datasource); - Mono actionMono = layoutActionService - .createSingleAction(action) - .flatMap(createdAction -> newActionService.findByBranchNameAndBaseActionId( - branchName, createdAction.getId(), false, READ_ACTIONS)); + Mono actionMono = layoutActionService.createSingleAction(action); StepVerifier.create(actionMono) - .assertNext(newAction -> { - assertThat(newAction.getUnpublishedAction().getPageId()).isEqualTo(gitConnectedPage.getId()); - assertThat(newAction.getBaseId()).isEqualTo(newAction.getId()); + .assertNext(actionDTO -> { + assertThat(actionDTO.getPageId()).isEqualTo(gitConnectedPage.getId()); + assertThat(actionDTO.getBaseId()).isEqualTo(actionDTO.getId()); }) .verifyComplete(); } diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ce/ApplicationServiceCETest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ce/ApplicationServiceCETest.java index 89c9a9adabd4..6093222abbb7 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ce/ApplicationServiceCETest.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ce/ApplicationServiceCETest.java @@ -1,5 +1,6 @@ package com.appsmith.server.services.ce; +import com.appsmith.external.git.constants.ce.RefType; import com.appsmith.external.models.ActionConfiguration; import com.appsmith.external.models.ActionDTO; import com.appsmith.external.models.BaseDomain; @@ -339,7 +340,7 @@ public void setup() { Application gitConnectedApp1 = new Application(); gitConnectedApp1.setWorkspaceId(workspaceId); GitArtifactMetadata gitData = new GitArtifactMetadata(); - gitData.setBranchName("testBranch"); + gitData.setRefName("testBranch"); gitData.setDefaultBranchName("testBranch"); gitData.setRepoName("testRepo"); gitData.setRemoteUrl("git@test.com:user/testRepo.git"); @@ -357,12 +358,12 @@ public void setup() { // Assign the branchName to all the resources connected to the application ApplicationJson gitConnectedApplicationJson = exportService - .exportByArtifactIdAndBranchName(newGitConnectedApp.getId(), gitData.getBranchName(), APPLICATION) + .exportByArtifactIdAndBranchName(newGitConnectedApp.getId(), gitData.getRefName(), APPLICATION) .map(artifactExchangeJson -> (ApplicationJson) artifactExchangeJson) .block(); gitConnectedApp = importService .importArtifactInWorkspaceFromGit( - workspaceId, newGitConnectedApp.getId(), gitConnectedApplicationJson, gitData.getBranchName()) + workspaceId, newGitConnectedApp.getId(), gitConnectedApplicationJson, gitData.getRefName()) .map(importableArtifact -> (Application) importableArtifact) .block(); @@ -710,9 +711,9 @@ public void getApplicationsByBranchName_validBranchName_success() { StepVerifier.create(getApplication) .assertNext(t -> { assertThat(t).isNotNull(); - assertThat(t.getGitApplicationMetadata().getBranchName()) + assertThat(t.getGitApplicationMetadata().getRefName()) .isEqualTo( - gitConnectedApp.getGitApplicationMetadata().getBranchName()); + gitConnectedApp.getGitApplicationMetadata().getRefName()); assertThat(t.getId()).isEqualTo(gitConnectedApp.getId()); }) .verifyComplete(); @@ -836,7 +837,7 @@ public void updateApplicationByIdAndBranchName_validBranchName_success() { .flatMap(t -> { GitArtifactMetadata gitData = t.getGitApplicationMetadata(); return applicationService.findByBranchNameAndBaseApplicationId( - gitData.getBranchName(), gitData.getDefaultApplicationId(), READ_APPLICATIONS); + gitData.getRefName(), gitData.getDefaultApplicationId(), READ_APPLICATIONS); }); StepVerifier.create(updateApplication) @@ -1106,7 +1107,7 @@ public void makeApplicationPublic_applicationWithGitMetadata_success() { testApplication.setWorkspaceId(workspaceId); GitArtifactMetadata gitArtifactMetadata = new GitArtifactMetadata(); gitArtifactMetadata.setDefaultApplicationId(gitConnectedApp.getId()); - gitArtifactMetadata.setBranchName("test"); + gitArtifactMetadata.setRefName("test"); testApplication.setGitApplicationMetadata(gitArtifactMetadata); Application application = applicationPageService.createApplication(testApplication).block(); @@ -1253,7 +1254,7 @@ public void makeApplicationPrivate_applicationWithGitMetadata_success() { testApplication.setWorkspaceId(workspaceId); GitArtifactMetadata gitArtifactMetadata = new GitArtifactMetadata(); gitArtifactMetadata.setDefaultApplicationId(gitConnectedApp.getId()); - gitArtifactMetadata.setBranchName("test2"); + gitArtifactMetadata.setRefName("test2"); testApplication.setGitApplicationMetadata(gitArtifactMetadata); Application application = applicationPageService.createApplication(testApplication).block(); @@ -1606,7 +1607,7 @@ public void validMakeApplicationPublicWithActions() { @WithUserDetails(value = "api_user") public void cloneApplication_applicationWithGitMetadata_success() { - final String branchName = gitConnectedApp.getGitApplicationMetadata().getBranchName(); + final String branchName = gitConnectedApp.getGitApplicationMetadata().getRefName(); Mono clonedApplicationMono = applicationPageService.cloneApplication(gitConnectedApp.getId()).cache(); @@ -1720,8 +1721,8 @@ public void cloneApplication_applicationWithGitMetadata_success() { .collectList(); Mono> srcNewPageListMono = Flux.fromIterable(gitConnectedApp.getPages()) - .flatMap(applicationPage -> newPageService.findByBranchNameAndBasePageId( - branchName, applicationPage.getDefaultPageId(), READ_PAGES, null)) + .flatMap(applicationPage -> newPageService.findByRefTypeAndRefNameAndBasePageId( + RefType.branch, branchName, applicationPage.getDefaultPageId(), READ_PAGES, null)) .collectList(); StepVerifier.create(Mono.zip(clonedNewPageListMono, srcNewPageListMono)) @@ -1776,7 +1777,7 @@ public void cloneApplication_applicationWithGitMetadata_success() { @WithUserDetails(value = "api_user") public void cloneApplication_applicationWithGitMetadataAndActions_success() { - final String branchName = gitConnectedApp.getGitApplicationMetadata().getBranchName(); + final String branchName = gitConnectedApp.getGitApplicationMetadata().getRefName(); Mono workspaceResponse = workspaceService.findById(workspaceId, READ_WORKSPACES); @@ -2478,7 +2479,7 @@ public void cloneGitConnectedApplication_withUpdatedDefaultBranch_sucess() { .flatMap(application1 -> { GitArtifactMetadata gitArtifactMetadata = new GitArtifactMetadata(); gitArtifactMetadata.setDefaultApplicationId(application1.getId()); - gitArtifactMetadata.setBranchName("master"); + gitArtifactMetadata.setRefName("master"); gitArtifactMetadata.setDefaultBranchName("feature1"); gitArtifactMetadata.setIsRepoPrivate(false); gitArtifactMetadata.setRepoName("testRepo"); @@ -2500,7 +2501,7 @@ public void cloneGitConnectedApplication_withUpdatedDefaultBranch_sucess() { .flatMap(application1 -> { GitArtifactMetadata gitArtifactMetadata = new GitArtifactMetadata(); gitArtifactMetadata.setDefaultApplicationId(application1.getId()); - gitArtifactMetadata.setBranchName("feature1"); + gitArtifactMetadata.setRefName("feature1"); gitArtifactMetadata.setDefaultBranchName("feature1"); gitArtifactMetadata.setIsRepoPrivate(false); gitArtifactMetadata.setRepoName("testRepo"); @@ -2742,7 +2743,7 @@ public void publishApplication_withGitConnectedApp_success() { .update(gitConnectedApp.getId(), gitConnectedApp) .flatMap(updatedApp -> applicationPageService.publish(updatedApp.getId(), true)) .flatMap(application -> applicationService.findByBranchNameAndBaseApplicationId( - gitData.getBranchName(), gitData.getDefaultApplicationId(), MANAGE_APPLICATIONS)) + gitData.getRefName(), gitData.getDefaultApplicationId(), MANAGE_APPLICATIONS)) .cache(); Mono> applicationPagesMono = applicationMono @@ -2893,7 +2894,7 @@ public void deleteUnpublishedPageFromApplication() { @WithUserDetails(value = "api_user") public void deleteUnpublishedPage_FromApplicationConnectedToGit_success() { - final String branchName = gitConnectedApp.getGitApplicationMetadata().getBranchName(); + final String branchName = gitConnectedApp.getGitApplicationMetadata().getRefName(); PageDTO page = new PageDTO(); page.setName("Test delete unPublish page test"); page.setApplicationId(gitConnectedApp.getId()); @@ -3794,16 +3795,16 @@ public void getApplicationConnectedToGit_defaultBranchUpdated_returnBranchSpecif testApplication.setName("getApplicationConnectedToGit_defaultBranchUpdated_returnBranchSpecificApplication"); testApplication.setWorkspaceId(workspaceId); GitArtifactMetadata gitData = new GitArtifactMetadata(); - gitData.setBranchName("release"); + gitData.setRefName("release"); gitData.setDefaultApplicationId(gitConnectedApp.getId()); testApplication.setGitApplicationMetadata(gitData); Application application = applicationPageService .createApplication(testApplication) .flatMap(application1 -> exportService - .exportByArtifactIdAndBranchName(gitConnectedApp.getId(), gitData.getBranchName(), APPLICATION) + .exportByArtifactIdAndBranchName(gitConnectedApp.getId(), gitData.getRefName(), APPLICATION) .map(artifactExchangeJson -> (ApplicationJson) artifactExchangeJson) .flatMap(applicationJson -> importService.importArtifactInWorkspaceFromGit( - workspaceId, application1.getId(), applicationJson, gitData.getBranchName()))) + workspaceId, application1.getId(), applicationJson, gitData.getRefName()))) .map(importableArtifact -> (Application) importableArtifact) .block(); @@ -3811,11 +3812,11 @@ public void getApplicationConnectedToGit_defaultBranchUpdated_returnBranchSpecif StepVerifier.create(getApplication) .assertNext(application1 -> { assertThat(application1).isNotNull(); - assertThat(application1.getGitApplicationMetadata().getBranchName()) + assertThat(application1.getGitApplicationMetadata().getRefName()) .isNotEqualTo( - gitConnectedApp.getGitApplicationMetadata().getBranchName()); - assertThat(application1.getGitApplicationMetadata().getBranchName()) - .isEqualTo(application.getGitApplicationMetadata().getBranchName()); + gitConnectedApp.getGitApplicationMetadata().getRefName()); + assertThat(application1.getGitApplicationMetadata().getRefName()) + .isEqualTo(application.getGitApplicationMetadata().getRefName()); assertThat(application1.getGitArtifactMetadata().getDefaultArtifactId()) .isEqualTo(gitConnectedApp.getId()); assertThat(application1.getName()).isEqualTo(application.getName()); @@ -4466,7 +4467,7 @@ public void testCacheEviction_whenPagesDeletedInEditModeFollowedByAppPublish_sho // Step 7: Call the consolidated API to force cache update consolidatedAPIService - .getConsolidatedInfoForPageLoad(basePageId1Ref.get(), null, null, ApplicationMode.PUBLISHED) + .getConsolidatedInfoForPageLoad(basePageId1Ref.get(), null, null, null, ApplicationMode.PUBLISHED) .block(); // Step 8: Verify basePageId1 is now cached after the consolidated API call @@ -4483,7 +4484,7 @@ public void testCacheEviction_whenPagesDeletedInEditModeFollowedByAppPublish_sho // Step 10: Call the consolidated API to force cache update for basePageId2 consolidatedAPIService - .getConsolidatedInfoForPageLoad(basePageId2Ref.get(), null, null, ApplicationMode.PUBLISHED) + .getConsolidatedInfoForPageLoad(basePageId2Ref.get(), null, null, null, ApplicationMode.PUBLISHED) .block(); // Step 11: Verify basePageId2 is now cached after the consolidated API call diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ce/ConsolidatedAPIServiceImplTest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ce/ConsolidatedAPIServiceImplTest.java index ccc70eb9315a..bdeea2812344 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ce/ConsolidatedAPIServiceImplTest.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ce/ConsolidatedAPIServiceImplTest.java @@ -1,5 +1,6 @@ package com.appsmith.server.services.ce; +import com.appsmith.external.git.constants.ce.RefType; import com.appsmith.external.models.ActionDTO; import com.appsmith.external.models.Datasource; import com.appsmith.server.acl.AclPermission; @@ -48,6 +49,7 @@ import com.appsmith.server.services.UserService; import com.appsmith.server.themes.base.ThemeService; import org.junit.jupiter.api.Test; +import org.mockito.Mockito; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; @@ -141,7 +143,7 @@ public class ConsolidatedAPIServiceImplTest { @Test public void testErrorWhenModeIsNullAndPageIdAvailable() { Mono consolidatedInfoForPageLoad = - consolidatedAPIService.getConsolidatedInfoForPageLoad("pageId", null, null, null); + consolidatedAPIService.getConsolidatedInfoForPageLoad("pageId", null, null, null, null); StepVerifier.create(consolidatedInfoForPageLoad).verifyErrorSatisfies(error -> { assertThat(error).isInstanceOf(AppsmithException.class); assertEquals("Please enter a valid parameter appMode.", error.getMessage()); @@ -172,7 +174,7 @@ public void testPageLoadResponseWhenPageIdAndApplicationIdMissing() { Mono consolidatedInfoForPageLoad = consolidatedAPIService.getConsolidatedInfoForPageLoad( - "pageId", "appId", "branch", ApplicationMode.PUBLISHED); + "pageId", "appId", RefType.branch, "branch", ApplicationMode.PUBLISHED); StepVerifier.create(consolidatedInfoForPageLoad) .assertNext(consolidatedAPIResponseDTO -> { assertNotNull(consolidatedAPIResponseDTO.getUserProfile()); @@ -245,7 +247,7 @@ public void testPageLoadResponseForViewMode() { mockNewPage.setBranchName("branch"); doReturn(Mono.just(mockNewPage)) .when(spyNewPageService) - .findByBranchNameAndBasePageId(anyString(), anyString(), any(), any()); + .findByRefTypeAndRefNameAndBasePageId(any(), anyString(), anyString(), any(), any()); doReturn(Mono.just(List.of(mockNewPage))) .when(spyApplicationPageService) @@ -284,7 +286,7 @@ public void testPageLoadResponseForViewMode() { Mono consolidatedInfoForPageLoad = consolidatedAPIService.getConsolidatedInfoForPageLoad( - "pageId123", null, "branch", ApplicationMode.PUBLISHED); + "pageId123", null, RefType.branch, "branch", ApplicationMode.PUBLISHED); StepVerifier.create(consolidatedInfoForPageLoad) .assertNext(consolidatedAPIResponseDTO -> { assertNotNull(consolidatedAPIResponseDTO.getPublishedActions()); @@ -432,7 +434,7 @@ public void testPageLoadResponseForEditMode() { mockNewPage.setApplicationId("mockApplicationId"); doReturn(Mono.just(mockNewPage)) .when(spyNewPageService) - .findByBranchNameAndBasePageId(anyString(), anyString(), any(), any()); + .findByRefTypeAndRefNameAndBasePageId(any(), anyString(), anyString(), any(), any()); doReturn(Mono.just(List.of(mockNewPage))) .when(spyApplicationPageService) @@ -524,7 +526,8 @@ public void testPageLoadResponseForEditMode() { when(mockMockDataService.getMockDataSet()).thenReturn(Mono.just(sampleMockDataDTO)); Mono consolidatedInfoForPageLoad = - consolidatedAPIService.getConsolidatedInfoForPageLoad("pageId", null, "branch", ApplicationMode.EDIT); + consolidatedAPIService.getConsolidatedInfoForPageLoad( + "pageId", null, RefType.branch, "branch", ApplicationMode.EDIT); StepVerifier.create(consolidatedInfoForPageLoad) .assertNext(consolidatedAPIResponseDTO -> { assertNotNull(consolidatedAPIResponseDTO.getUserProfile()); @@ -737,15 +740,16 @@ public void testErrorResponseWhenAnonymousUserAccessPrivateApp() { when(mockProductAlertService.getSingleApplicableMessage()) .thenReturn(Mono.just(List.of(sampleProductAlertResponseDTO))); - when(mockNewPageRepository.findPageByBranchNameAndBasePageId(anyString(), anyString(), any(), any())) - .thenReturn(Mono.empty()); + Mockito.doReturn(Mono.empty()) + .when(mockNewPageRepository) + .findPageByRefTypeAndRefNameAndBasePageId(any(), anyString(), anyString(), any(), any()); doReturn(Mono.empty()) .when(spyApplicationRepository) .getApplicationByGitBranchAndBaseApplicationId(anyString(), anyString(), any(AclPermission.class)); Mono consolidatedInfoForPageLoad = consolidatedAPIService.getConsolidatedInfoForPageLoad( - "pageId", "appId", "branch", ApplicationMode.PUBLISHED); + "pageId", "appId", RefType.branch, "branch", ApplicationMode.PUBLISHED); StepVerifier.create(consolidatedInfoForPageLoad) .assertNext(consolidatedAPIResponseDTO -> { assertNotNull(consolidatedAPIResponseDTO.getUserProfile()); @@ -923,7 +927,7 @@ public void testPageLoadResponseForViewMode_whenBranchNameIsPresentInNonGitApp() doReturn(Mono.just(mockNewPage)) .when(spyNewPageService) - .findByBranchNameAndBasePageId(eq(null), eq("mockPageId"), any(), any()); + .findByRefTypeAndRefNameAndBasePageId(any(), eq(null), eq("mockPageId"), any(), any()); doReturn(Mono.just(List.of(mockNewPage))) .when(spyApplicationPageService) @@ -962,7 +966,7 @@ public void testPageLoadResponseForViewMode_whenBranchNameIsPresentInNonGitApp() Mono consolidatedInfoForPageLoad = consolidatedAPIService.getConsolidatedInfoForPageLoad( - "mockPageId", null, "branch", ApplicationMode.PUBLISHED); + "mockPageId", null, RefType.branch, "branch", ApplicationMode.PUBLISHED); StepVerifier.create(consolidatedInfoForPageLoad) .assertNext(consolidatedAPIResponseDTO -> { assertNotNull(consolidatedAPIResponseDTO.getPublishedActions()); @@ -1105,7 +1109,7 @@ public void testPageLoadResponseForEditModeWhenDefaultBranchIsDifferentFromDefau Application mockApplicationBaseBranch = new Application(); GitArtifactMetadata baseMetadata = new GitArtifactMetadata(); - baseMetadata.setBranchName("master"); + baseMetadata.setRefName("master"); baseMetadata.setDefaultBranchName("newDefaultBranch"); baseMetadata.setDefaultApplicationId("mockBaseId"); mockApplicationBaseBranch.setGitArtifactMetadata(baseMetadata); @@ -1121,7 +1125,7 @@ public void testPageLoadResponseForEditModeWhenDefaultBranchIsDifferentFromDefau Application mockDefaultApplication = new Application(); GitArtifactMetadata defaultMetadata = new GitArtifactMetadata(); - defaultMetadata.setBranchName("newDefaultBranch"); + defaultMetadata.setRefName("newDefaultBranch"); defaultMetadata.setDefaultApplicationId("mockBaseId"); mockDefaultApplication.setGitArtifactMetadata(defaultMetadata); mockDefaultApplication.setId("defaultApplicationId"); @@ -1143,11 +1147,11 @@ public void testPageLoadResponseForEditModeWhenDefaultBranchIsDifferentFromDefau doReturn(Mono.just(basePage)) .when(spyNewPageService) - .findByBranchNameAndBasePageId(eq(null), anyString(), any(), any()); + .findByRefTypeAndRefNameAndBasePageId(any(), eq(null), anyString(), any(), any()); doReturn(Mono.just(defaultAppDefaultPage)) .when(spyNewPageService) - .findByBranchNameAndBasePageId(anyString(), anyString(), any(), any()); + .findByRefTypeAndRefNameAndBasePageId(any(), anyString(), anyString(), any(), any()); doReturn(Mono.just(List.of(defaultAppDefaultPage))) .when(spyApplicationPageService) @@ -1235,7 +1239,7 @@ public void testPageLoadResponseForEditModeWhenDefaultBranchIsDifferentFromDefau when(mockMockDataService.getMockDataSet()).thenReturn(Mono.just(sampleMockDataDTO)); Mono consolidatedInfoForPageLoad = - consolidatedAPIService.getConsolidatedInfoForPageLoad("pageId", null, null, ApplicationMode.EDIT); + consolidatedAPIService.getConsolidatedInfoForPageLoad("pageId", null, null, null, ApplicationMode.EDIT); StepVerifier.create(consolidatedInfoForPageLoad) .assertNext(consolidatedAPIResponseDTO -> { assertNotNull(consolidatedAPIResponseDTO.getUserProfile()); @@ -1459,7 +1463,7 @@ public void testPageLoadWhenPageFromFeatureBranchAndCacheableRepositoryReturnsBa // base metadata GitArtifactMetadata baseMetadata = new GitArtifactMetadata(); - baseMetadata.setBranchName(BASE_BRANCH); + baseMetadata.setRefName(BASE_BRANCH); baseMetadata.setDefaultBranchName(DEFAULT_BRANCH); baseMetadata.setDefaultApplicationId(DEFAULT_APPLICATION_ID); @@ -1483,7 +1487,7 @@ public void testPageLoadWhenPageFromFeatureBranchAndCacheableRepositoryReturnsBa // default metadata GitArtifactMetadata defaultMetadata = new GitArtifactMetadata(); - defaultMetadata.setBranchName(DEFAULT_BRANCH); + defaultMetadata.setRefName(DEFAULT_BRANCH); defaultMetadata.setDefaultBranchName(DEFAULT_BRANCH); defaultMetadata.setDefaultApplicationId(DEFAULT_APPLICATION_ID); @@ -1504,7 +1508,7 @@ public void testPageLoadWhenPageFromFeatureBranchAndCacheableRepositoryReturnsBa doReturn(Mono.just(featureBranchPage)) .when(spyNewPageService) - .findByBranchNameAndBasePageIdAndApplicationMode(eq(null), eq(FEATURE_PAGE_ID), any()); + .findByRefTypeAndRefNameAndBasePageIdAndApplicationMode(any(), eq(null), eq(FEATURE_PAGE_ID), any()); doReturn(Mono.just(new PageDTO())) .when(spyApplicationPageService) @@ -1589,7 +1593,7 @@ public void testPageLoadWhenPageFromFeatureBranchAndCacheableRepositoryReturnsBa Mono consolidatedInfoForPageLoad = consolidatedAPIService.getConsolidatedInfoForPageLoad( - FEATURE_PAGE_ID, null, null, ApplicationMode.PUBLISHED); + FEATURE_PAGE_ID, null, null, null, ApplicationMode.PUBLISHED); StepVerifier.create(consolidatedInfoForPageLoad) .assertNext(consolidatedAPIResponseDTO -> { assertNotNull(consolidatedAPIResponseDTO); diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/AuthenticationServiceTest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/AuthenticationServiceTest.java index 2538f7925daa..7e2eb4825594 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/AuthenticationServiceTest.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/AuthenticationServiceTest.java @@ -1,5 +1,6 @@ package com.appsmith.server.solutions; +import com.appsmith.external.git.constants.ce.RefType; import com.appsmith.external.models.BaseDomain; import com.appsmith.external.models.Datasource; import com.appsmith.external.models.DatasourceConfiguration; @@ -288,7 +289,7 @@ public void testGetAuthorizationCodeURL_validDatasourceAndBranchName() { PageDTO testPage = new PageDTO(); testPage.setName("Test-Page-oauth2-git-redirection"); - testPage.setBranchName(branchName); + testPage.setRefName(branchName); Application newApp = new Application(); newApp.setName(UUID.randomUUID().toString()); @@ -355,6 +356,7 @@ public void testGetAuthorizationCodeURL_validDatasourceAndBranchName() { defaultEnvironmentId, "https://mock.origin.com", workspaceId, + RefType.branch.name(), branchName) + "&scope=Scope\\d%20Scope\\d" + "&key=value")); diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/CreateDBTablePageSolutionTests.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/CreateDBTablePageSolutionTests.java index 5ebba1803e6a..f409d5e809f9 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/CreateDBTablePageSolutionTests.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/CreateDBTablePageSolutionTests.java @@ -1,5 +1,6 @@ package com.appsmith.server.solutions; +import com.appsmith.external.git.constants.ce.RefType; import com.appsmith.external.models.ActionConfiguration; import com.appsmith.external.models.ActionDTO; import com.appsmith.external.models.Datasource; @@ -340,7 +341,7 @@ public void createPage_withValidBranch_validDefaultIds() { Application gitConnectedApp = new Application(); gitConnectedApp.setName(UUID.randomUUID().toString()); GitArtifactMetadata gitData = new GitArtifactMetadata(); - gitData.setBranchName("crudTestBranch"); + gitData.setRefName("crudTestBranch"); gitConnectedApp.setGitApplicationMetadata(gitData); applicationPageService .createApplication(gitConnectedApp, testWorkspace.getId()) @@ -348,12 +349,12 @@ public void createPage_withValidBranch_validDefaultIds() { application.getGitApplicationMetadata().setDefaultApplicationId(application.getId()); gitData.setDefaultApplicationId(application.getId()); return applicationService.save(application).zipWhen(application1 -> exportService - .exportByArtifactIdAndBranchName(application1.getId(), gitData.getBranchName(), APPLICATION) + .exportByArtifactIdAndBranchName(application1.getId(), gitData.getRefName(), APPLICATION) .map(artifactExchangeJson -> (ApplicationJson) artifactExchangeJson)); }) // Assign the branchName to all the resources connected to the application .flatMap(tuple -> importService.importArtifactInWorkspaceFromGit( - testWorkspace.getId(), tuple.getT1().getId(), tuple.getT2(), gitData.getBranchName())) + testWorkspace.getId(), tuple.getT1().getId(), tuple.getT2(), gitData.getRefName())) .map(importableArtifact -> (Application) importableArtifact) .block(); @@ -366,8 +367,12 @@ public void createPage_withValidBranch_validDefaultIds() { .createPage(newPage) .flatMap(savedPage -> solution.createPageFromDBTable(savedPage.getId(), resource, testDefaultEnvironmentId)) - .flatMap(crudPageResponseDTO -> newPageService.findByBranchNameAndBasePageId( - gitData.getBranchName(), crudPageResponseDTO.getPage().getId(), READ_PAGES, null)); + .flatMap(crudPageResponseDTO -> newPageService.findByRefTypeAndRefNameAndBasePageId( + RefType.branch, + gitData.getRefName(), + crudPageResponseDTO.getPage().getId(), + READ_PAGES, + null)); StepVerifier.create(resultMono.zipWhen(newPage1 -> getActions(newPage1.getId()))) .assertNext(tuple -> { @@ -378,14 +383,14 @@ public void createPage_withValidBranch_validDefaultIds() { Layout layout = page.getLayouts().get(0); assertThat(page.getName()).isEqualTo("crud-admin-page-with-git-connected-app"); - assertThat(newPage1.getBranchName()).isEqualTo(gitData.getBranchName()); + assertThat(newPage1.getBranchName()).isEqualTo(gitData.getRefName()); assertThat(newPage1.getBaseId()).isEqualTo(newPage1.getId()); assertThat(actionList).hasSize(4); NewAction newAction = actionList.get(0); assertThat(newAction.getBaseId()) .isEqualTo(actionList.get(0).getId()); - assertThat(newAction.getBranchName()).isEqualTo(gitData.getBranchName()); + assertThat(newAction.getBranchName()).isEqualTo(gitData.getRefName()); }) .verifyComplete(); } diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/PartialExportServiceTest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/PartialExportServiceTest.java index 2ff253c45125..0ba451f58822 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/PartialExportServiceTest.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/PartialExportServiceTest.java @@ -1,5 +1,6 @@ package com.appsmith.server.solutions; +import com.appsmith.external.git.constants.ce.RefType; import com.appsmith.external.models.ActionConfiguration; import com.appsmith.external.models.ActionDTO; import com.appsmith.external.models.DBAuth; @@ -220,7 +221,7 @@ private Application createGitConnectedApp(String applicationName) { testApplication.setModifiedBy("some-user"); testApplication.setGitApplicationMetadata(new GitArtifactMetadata()); GitArtifactMetadata gitData = new GitArtifactMetadata(); - gitData.setBranchName("master"); + gitData.setRefName("master"); gitData.setDefaultBranchName("master"); testApplication.setGitApplicationMetadata(gitData); @@ -289,7 +290,7 @@ public void testGetPartialExport_gitConnectedApp_branchResourceExported() { PageDTO savedPage = new PageDTO(); savedPage.setName("Page 2"); savedPage.setApplicationId(application.getId()); - savedPage.setBranchName("master"); + savedPage.setRefName("master"); savedPage = applicationPageService.createPage(savedPage).block(); // Create Action @@ -349,7 +350,7 @@ public void testGetPartialExport_gitConnectedApp_featureBranchResourceExported() PageDTO savedPage = new PageDTO(); savedPage.setName("Page 2"); savedPage.setApplicationId(application.getId()); - savedPage.setBranchName("master"); + savedPage.setRefName("master"); savedPage = applicationPageService.createPage(savedPage).block(); // Create Action @@ -362,7 +363,8 @@ public void testGetPartialExport_gitConnectedApp_featureBranchResourceExported() actionConfiguration.setTimeoutInMillisecond("6000"); action.setActionConfiguration(actionConfiguration); action.setDatasource(datasourceMap.get("DS1")); - action.setBranchName("master"); + action.setRefType(RefType.branch); + action.setRefName("master"); ActionDTO savedAction = layoutActionService.createSingleAction(action, Boolean.FALSE).block(); diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/PartialImportServiceTest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/PartialImportServiceTest.java index 218269a72ec7..1169d8742880 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/PartialImportServiceTest.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/PartialImportServiceTest.java @@ -239,7 +239,7 @@ private Application createGitConnectedApp(String applicationName) { testApplication.setModifiedBy("some-user"); testApplication.setGitApplicationMetadata(new GitArtifactMetadata()); GitArtifactMetadata gitData = new GitArtifactMetadata(); - gitData.setBranchName("master"); + gitData.setRefName("master"); gitData.setDefaultBranchName("master"); testApplication.setGitApplicationMetadata(gitData); @@ -331,7 +331,7 @@ public void testPartialImport_gitConnectedAppDefaultBranch_success() { PageDTO savedPage = new PageDTO(); savedPage.setName("Page 2"); savedPage.setApplicationId(application.getId()); - savedPage.setBranchName("master"); + savedPage.setRefName("master"); savedPage = applicationPageService.createPage(savedPage).block(); Part filePart = createFilePart("test_assets/ImportExportServiceTest/partial-export-valid-without-widget.json"); diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/ce/ActionExecutionSolutionCETest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/ce/ActionExecutionSolutionCETest.java index e8bb6bc39db5..43cf663f943c 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/ce/ActionExecutionSolutionCETest.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/ce/ActionExecutionSolutionCETest.java @@ -252,7 +252,7 @@ public void setup() { Application newApp = new Application(); newApp.setName(UUID.randomUUID().toString()); GitArtifactMetadata gitData = new GitArtifactMetadata(); - gitData.setBranchName("actionServiceTest"); + gitData.setRefName("actionServiceTest"); newApp.setGitApplicationMetadata(gitData); gitConnectedApp = applicationPageService .createApplication(newApp, workspaceId) @@ -260,12 +260,12 @@ public void setup() { application1.getGitApplicationMetadata().setDefaultApplicationId(application1.getId()); return applicationService.save(application1).zipWhen(application11 -> exportService .exportByArtifactIdAndBranchName( - application11.getId(), gitData.getBranchName(), ArtifactType.APPLICATION) + application11.getId(), gitData.getRefName(), ArtifactType.APPLICATION) .map(artifactExchangeJson -> (ApplicationJson) artifactExchangeJson)); }) // Assign the branchName to all the resources connected to the application .flatMap(tuple -> importService.importArtifactInWorkspaceFromGit( - workspaceId, tuple.getT1().getId(), tuple.getT2(), gitData.getBranchName())) + workspaceId, tuple.getT1().getId(), tuple.getT2(), gitData.getRefName())) .map(importableArtifact -> (Application) importableArtifact) .block(); @@ -273,7 +273,7 @@ public void setup() { .findPageById(gitConnectedApp.getPages().get(0).getId(), READ_PAGES, false) .block(); - branchName = gitConnectedApp.getGitApplicationMetadata().getBranchName(); + branchName = gitConnectedApp.getGitApplicationMetadata().getRefName(); datasource = new Datasource(); datasource.setName("Default Database"); From 99a10e46d103d9e3bc9b27082bba9695f8a14118 Mon Sep 17 00:00:00 2001 From: Ankita Kinger Date: Thu, 2 Jan 2025 20:04:07 +0530 Subject: [PATCH 07/40] fix: Updating the click functionalities in list item component (#38453) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description Updating the click functionalities in list item component to fix the partial clickable issue on JS module instance editor in EE. Fixes [#38444](https://github.com/appsmithorg/appsmith/issues/38444) ## Automation /ok-to-test tags="@tag.Sanity, @tag.Datasource, @tag.IDE" ### :mag: Cypress test results > [!TIP] > 🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉 > Workflow run: > Commit: a936b58bcb20706a08d5bd9e6d447737a9956dd6 > Cypress dashboard. > Tags: `@tag.Sanity, @tag.Datasource, @tag.IDE` > Spec: >
Thu, 02 Jan 2025 14:17:45 UTC ## Communication Should the DevRel and Marketing teams inform users about this change? - [ ] Yes - [ ] No ## Summary by CodeRabbit - **Refactor** - Removed `description` and `descriptionType` properties from various `List` component items across multiple components - Simplified keyboard interaction model in `List` component by removing keyboard event handling - Modified click event handling in `ListItem` to focus on mouse interactions - **Bug Fixes** - Prevented event propagation for right control clicks in `ListItem` --- .../design-system/ads/src/List/List.tsx | 25 +++++++------------ .../Templates/IDEHeader/IDEHeader.stories.tsx | 4 --- .../Preview/Debugger/helpDropdown.tsx | 8 ------ .../IDE/EditorPane/components/Group.tsx | 2 -- 4 files changed, 9 insertions(+), 30 deletions(-) diff --git a/app/client/packages/design-system/ads/src/List/List.tsx b/app/client/packages/design-system/ads/src/List/List.tsx index 56fd0ddee37a..85fc97c212ab 100644 --- a/app/client/packages/design-system/ads/src/List/List.tsx +++ b/app/client/packages/design-system/ads/src/List/List.tsx @@ -91,23 +91,16 @@ function ListItem(props: ListItemProps) { } = props; const isBlockDescription = descriptionType === "block"; - const listItemhandleKeyDown = (e: React.KeyboardEvent) => { - if (!props.isDisabled && props.onClick) { - switch (e.key) { - case "Enter": - case " ": - props.onClick(); - break; - } - } - }; - const handleOnClick = () => { if (!props.isDisabled && props.onClick) { props.onClick(); } }; + const handleRightControlClick = (e: React.MouseEvent) => { + e.stopPropagation(); + }; + return ( - + {startIcon} {props.customTitleComponent ? ( props.customTitleComponent @@ -158,7 +149,9 @@ function ListItem(props: ListItemProps) { )} {rightControl && ( - {rightControl} + + {rightControl} + )} ); diff --git a/app/client/packages/design-system/ads/src/Templates/IDEHeader/IDEHeader.stories.tsx b/app/client/packages/design-system/ads/src/Templates/IDEHeader/IDEHeader.stories.tsx index c24b5e8eafda..c58c1d87769f 100644 --- a/app/client/packages/design-system/ads/src/Templates/IDEHeader/IDEHeader.stories.tsx +++ b/app/client/packages/design-system/ads/src/Templates/IDEHeader/IDEHeader.stories.tsx @@ -84,14 +84,10 @@ export const WithHeaderDropdown = () => { { title: "Page1", onClick: noop, - description: "", - descriptionType: "inline", }, { title: "Page2", onClick: noop, - description: "", - descriptionType: "inline", }, ]} /> diff --git a/app/client/src/pages/Editor/CustomWidgetBuilder/Preview/Debugger/helpDropdown.tsx b/app/client/src/pages/Editor/CustomWidgetBuilder/Preview/Debugger/helpDropdown.tsx index 1510b739a1ea..6396ce115af6 100644 --- a/app/client/src/pages/Editor/CustomWidgetBuilder/Preview/Debugger/helpDropdown.tsx +++ b/app/client/src/pages/Editor/CustomWidgetBuilder/Preview/Debugger/helpDropdown.tsx @@ -36,14 +36,10 @@ export default function HelpDropdown(props: DebuggerLog) { onClick: () => { window.open(CUSTOM_WIDGET_DOC_URL, "_blank"); }, - description: "", - descriptionType: "inline", }, // { // startIcon: , // title: "Troubleshoot with AI", - // description: "", - // descriptionType: "inline", // onClick: noop, // }, { @@ -61,14 +57,10 @@ export default function HelpDropdown(props: DebuggerLog) { "_blank", ); }, - description: "", - descriptionType: "inline", }, // { // startIcon: , // title: "Appsmith Support", - // description: "", - // descriptionType: "inline", // onClick: noop, // }, ]} diff --git a/app/client/src/pages/Editor/IDE/EditorPane/components/Group.tsx b/app/client/src/pages/Editor/IDE/EditorPane/components/Group.tsx index 84a551462adb..678b383f3292 100644 --- a/app/client/src/pages/Editor/IDE/EditorPane/components/Group.tsx +++ b/app/client/src/pages/Editor/IDE/EditorPane/components/Group.tsx @@ -41,8 +41,6 @@ const Group: React.FC = ({ group }) => { if (hasMoreItems) { items.push({ title: "Load more...", - description: "", - descriptionType: "inline", onClick: handleLoadMore, className: "ds-load-more", }); From dffabc26c9218ad03135fb2e0b61cfa89590861a Mon Sep 17 00:00:00 2001 From: Nidhi Date: Thu, 2 Jan 2025 20:43:20 +0530 Subject: [PATCH 08/40] chore: Set default reftype in git metadata (#38455) --- .../com/appsmith/server/domains/ce/GitArtifactMetadataCE.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/domains/ce/GitArtifactMetadataCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/domains/ce/GitArtifactMetadataCE.java index 546e60d033b5..caa3653826fe 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/domains/ce/GitArtifactMetadataCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/domains/ce/GitArtifactMetadataCE.java @@ -131,6 +131,10 @@ public RefType getRefType() { return refType == null ? RefType.branch : refType; } + public void setRefType(RefType refType) { + this.refType = refType == null ? RefType.branch : refType; + } + /** * this returns the branchName instead of reference name * @return returns the ref name. From bd116cdbf927ec8bceffd8f590eeee3e210686b8 Mon Sep 17 00:00:00 2001 From: Manish Kumar <107841575+sondermanish@users.noreply.github.com> Date: Thu, 2 Jan 2025 20:59:28 +0530 Subject: [PATCH 09/40] chore: added git controller layer (#38446) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description - Added controller layer for the new git implementation Fixes #`Issue Number` ## Automation /ok-to-test tags="@tag.Git" ### :mag: Cypress test results > [!TIP] > 🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉 > Workflow run: > Commit: 3fa98cdfc1aa8d8950c854fc2a98b90c4f329751 > Cypress dashboard. > Tags: `@tag.Git` > Spec: >
Thu, 02 Jan 2025 15:04:31 UTC ## Communication Should the DevRel and Marketing teams inform users about this change? - [ ] Yes - [ ] No ## Summary by CodeRabbit - **New Features** - Enhanced Git integration with new endpoints for managing Git repositories. - Added support for Git application and artifact operations. - Introduced new methods for branch management, SSH key generation, and metadata retrieval. - Expanded Git-related functionality with new controllers and services. - **Improvements** - Added more comprehensive Git analytics tracking. - Improved Git repository interaction capabilities. - Enhanced support for Git operations across different artifact types. --- .../appsmith/server/constants/ce/UrlCE.java | 2 + .../git/central/CentralGitServiceCE.java | 13 + .../CentralGitServiceCECompatibleImpl.java | 3 + .../git/central/CentralGitServiceCEImpl.java | 425 +++++++++++++++++- .../git/central/CentralGitServiceImpl.java | 3 + .../git/central/GitHandlingServiceCE.java | 5 + .../controllers/GitApplicationController.java | 20 + .../GitApplicationControllerCE.java | 225 ++++++++++ .../controllers/GitArtifactController.java | 18 + .../controllers/GitArtifactControllerCE.java | 74 +++ .../server/git/fs/GitFSServiceCEImpl.java | 35 +- .../server/git/utils/GitAnalyticsUtils.java | 29 ++ 12 files changed, 847 insertions(+), 5 deletions(-) create mode 100644 app/server/appsmith-server/src/main/java/com/appsmith/server/git/controllers/GitApplicationController.java create mode 100644 app/server/appsmith-server/src/main/java/com/appsmith/server/git/controllers/GitApplicationControllerCE.java create mode 100644 app/server/appsmith-server/src/main/java/com/appsmith/server/git/controllers/GitArtifactController.java create mode 100644 app/server/appsmith-server/src/main/java/com/appsmith/server/git/controllers/GitArtifactControllerCE.java diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/constants/ce/UrlCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/constants/ce/UrlCE.java index 08f65c8013db..c070dbeabc2e 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/constants/ce/UrlCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/constants/ce/UrlCE.java @@ -32,6 +32,8 @@ public class UrlCE { public static final String PRODUCT_ALERT = BASE_URL + VERSION + "/product-alert"; public static final String SEARCH_ENTITY_URL = BASE_URL + VERSION + "/search-entities"; public static final String CONSOLIDATED_API_URL = BASE_URL + VERSION + "/consolidated-api"; + public static final String GIT_APPLICATION_URL = BASE_URL + VERSION + "/git/applications"; + public static final String GIT_ARTIFACT_URL = BASE_URL + VERSION + "/git/artifacts"; // Sub-paths public static final String MOCKS = "/mocks"; diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCE.java index 23e668a80ea9..a9fc22f6a066 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCE.java @@ -1,14 +1,18 @@ package com.appsmith.server.git.central; +import com.appsmith.external.dtos.GitBranchDTO; import com.appsmith.external.dtos.GitRefDTO; import com.appsmith.external.dtos.GitStatusDTO; import com.appsmith.external.git.constants.ce.RefType; import com.appsmith.git.dto.CommitDTO; import com.appsmith.server.constants.ArtifactType; import com.appsmith.server.domains.Artifact; +import com.appsmith.server.domains.GitArtifactMetadata; +import com.appsmith.server.domains.GitAuth; import com.appsmith.server.dtos.ArtifactImportDTO; import com.appsmith.server.dtos.AutoCommitResponseDTO; import com.appsmith.server.dtos.GitConnectDTO; +import com.appsmith.server.dtos.GitDocsDTO; import com.appsmith.server.dtos.GitPullDTO; import reactor.core.publisher.Mono; @@ -31,6 +35,9 @@ Mono commitArtifact( Mono detachRemote(String branchedArtifactId, ArtifactType artifactType, GitType gitType); + Mono> listBranchForArtifact( + String branchedArtifactId, Boolean pruneBranches, ArtifactType artifactType, GitType gitType); + Mono fetchRemoteChanges( String referenceArtifactId, boolean isFileLock, @@ -67,4 +74,10 @@ Mono> updateProtectedBranches( Mono getAutoCommitProgress( String baseArtifactId, String branchName, ArtifactType artifactType); + + Mono generateSSHKey(String keyType); + + Mono getGitArtifactMetadata(String baseArtifactId, ArtifactType artifactType); + + Mono> getGitDocUrls(); } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCECompatibleImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCECompatibleImpl.java index 9c80cfa47cd9..c8c44990d8d1 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCECompatibleImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCECompatibleImpl.java @@ -11,6 +11,7 @@ import com.appsmith.server.helpers.GitPrivateRepoHelper; import com.appsmith.server.imports.internal.ImportService; import com.appsmith.server.plugins.base.PluginService; +import com.appsmith.server.repositories.GitDeployKeysRepository; import com.appsmith.server.services.SessionUserService; import com.appsmith.server.services.UserDataService; import com.appsmith.server.services.WorkspaceService; @@ -34,6 +35,7 @@ public CentralGitServiceCECompatibleImpl( GitArtifactHelperResolver gitArtifactHelperResolver, GitHandlingServiceResolver gitHandlingServiceResolver, GitPrivateRepoHelper gitPrivateRepoHelper, + GitDeployKeysRepository gitDeployKeysRepository, DatasourceService datasourceService, DatasourcePermission datasourcePermission, WorkspaceService workspaceService, @@ -52,6 +54,7 @@ public CentralGitServiceCECompatibleImpl( gitArtifactHelperResolver, gitHandlingServiceResolver, gitPrivateRepoHelper, + gitDeployKeysRepository, datasourceService, datasourcePermission, workspaceService, diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCEImpl.java index bfb33678dc7e..bc6c38ebabad 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCEImpl.java @@ -1,6 +1,8 @@ package com.appsmith.server.git.central; import com.appsmith.external.constants.AnalyticsEvents; +import com.appsmith.external.constants.ErrorReferenceDocUrl; +import com.appsmith.external.dtos.GitBranchDTO; import com.appsmith.external.dtos.GitRefDTO; import com.appsmith.external.dtos.GitStatusDTO; import com.appsmith.external.dtos.MergeStatusDTO; @@ -13,6 +15,7 @@ import com.appsmith.git.dto.GitUser; import com.appsmith.server.acl.AclPermission; import com.appsmith.server.constants.ArtifactType; +import com.appsmith.server.constants.Assets; import com.appsmith.server.constants.FieldName; import com.appsmith.server.constants.GitDefaultCommitMessage; import com.appsmith.server.datasources.base.DatasourceService; @@ -20,6 +23,7 @@ import com.appsmith.server.domains.AutoCommitConfig; import com.appsmith.server.domains.GitArtifactMetadata; import com.appsmith.server.domains.GitAuth; +import com.appsmith.server.domains.GitDeployKeys; import com.appsmith.server.domains.GitProfile; import com.appsmith.server.domains.Plugin; import com.appsmith.server.domains.User; @@ -29,6 +33,7 @@ import com.appsmith.server.dtos.ArtifactImportDTO; import com.appsmith.server.dtos.AutoCommitResponseDTO; import com.appsmith.server.dtos.GitConnectDTO; +import com.appsmith.server.dtos.GitDocsDTO; import com.appsmith.server.dtos.GitPullDTO; import com.appsmith.server.exceptions.AppsmithError; import com.appsmith.server.exceptions.AppsmithException; @@ -40,9 +45,12 @@ import com.appsmith.server.git.resolver.GitHandlingServiceResolver; import com.appsmith.server.git.utils.GitAnalyticsUtils; import com.appsmith.server.git.utils.GitProfileUtils; +import com.appsmith.server.helpers.GitDeployKeyGenerator; import com.appsmith.server.helpers.GitPrivateRepoHelper; +import com.appsmith.server.helpers.GitUtils; import com.appsmith.server.imports.internal.ImportService; import com.appsmith.server.plugins.base.PluginService; +import com.appsmith.server.repositories.GitDeployKeysRepository; import com.appsmith.server.services.GitArtifactHelper; import com.appsmith.server.services.SessionUserService; import com.appsmith.server.services.UserDataService; @@ -52,7 +60,9 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.eclipse.jgit.api.errors.InvalidRemoteException; +import org.eclipse.jgit.api.errors.RefNotFoundException; import org.eclipse.jgit.api.errors.TransportException; +import org.eclipse.jgit.errors.RepositoryNotFoundException; import org.eclipse.jgit.lib.BranchTrackingStatus; import org.springframework.stereotype.Service; import org.springframework.transaction.reactive.TransactionalOperator; @@ -68,6 +78,7 @@ import java.nio.file.Path; import java.time.Instant; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; @@ -95,14 +106,15 @@ public class CentralGitServiceCEImpl implements CentralGitServiceCE { private final GitRedisUtils gitRedisUtils; private final GitProfileUtils gitProfileUtils; - private final GitAnalyticsUtils gitAnalyticsUtils; + protected final GitAnalyticsUtils gitAnalyticsUtils; private final UserDataService userDataService; - private final SessionUserService sessionUserService; + protected final SessionUserService sessionUserService; protected final GitArtifactHelperResolver gitArtifactHelperResolver; protected final GitHandlingServiceResolver gitHandlingServiceResolver; private final GitPrivateRepoHelper gitPrivateRepoHelper; + private final GitDeployKeysRepository gitDeployKeysRepository; private final DatasourceService datasourceService; private final DatasourcePermission datasourcePermission; @@ -369,8 +381,8 @@ public Mono checkoutReference( getBaseAndBranchedArtifacts(referenceArtifactId, artifactType); return baseAndBranchedArtifactMono.flatMap(artifactTuples -> { - Artifact sourceArtifact = artifactTuples.getT1(); - return checkoutReference(sourceArtifact, gitRefDTO, addFileLock, gitType); + Artifact baseArtifact = artifactTuples.getT1(); + return checkoutReference(baseArtifact, gitRefDTO, addFileLock, gitType); }); } @@ -2053,6 +2065,330 @@ protected Mono discardChanges(Artifact branchedArtifact, Git recreatedArtifactFromLastCommit.subscribe(sink::success, sink::error, null, sink.currentContext())); } + public Mono> listBranchForArtifact( + String branchedArtifactId, Boolean pruneBranches, ArtifactType artifactType, GitType gitType) { + return getBranchList(branchedArtifactId, pruneBranches, true, artifactType, gitType); + } + + protected Mono> getBranchList( + String branchedArtifactId, + Boolean pruneBranches, + boolean syncDefaultBranchWithRemote, + ArtifactType artifactType, + GitType gitType) { + + GitArtifactHelper gitArtifactHelper = gitArtifactHelperResolver.getArtifactHelper(artifactType); + AclPermission artifactEditPermission = gitArtifactHelper.getArtifactEditPermission(); + + Mono> baseAndBranchedArtifactMono = + getBaseAndBranchedArtifacts(branchedArtifactId, artifactType, artifactEditPermission); + + return baseAndBranchedArtifactMono.flatMap(artifactTuples -> { + return getBranchList( + artifactTuples.getT1(), + artifactTuples.getT2(), + pruneBranches, + syncDefaultBranchWithRemote, + gitType); + }); + } + + protected Mono> getBranchList( + Artifact baseArtifact, + Artifact branchedArtifact, + Boolean pruneBranches, + boolean syncDefaultBranchWithRemote, + GitType gitType) { + + GitArtifactMetadata baseGitData = baseArtifact.getGitArtifactMetadata(); + GitArtifactMetadata branchedGitData = branchedArtifact.getGitArtifactMetadata(); + + if (isBaseGitMetadataInvalid(baseGitData, gitType) || branchedGitData == null) { + return Mono.error(new AppsmithException(AppsmithError.INVALID_GIT_CONFIGURATION, GIT_CONFIG_ERROR)); + } + + final String workspaceId = baseArtifact.getWorkspaceId(); + final String baseArtifactId = baseGitData.getDefaultArtifactId(); + final String repoName = baseGitData.getRepoName(); + final String currentBranch = branchedGitData.getRefName(); + + ArtifactJsonTransformationDTO jsonTransformationDTO = new ArtifactJsonTransformationDTO(); + jsonTransformationDTO.setRepoName(repoName); + jsonTransformationDTO.setWorkspaceId(workspaceId); + jsonTransformationDTO.setBaseArtifactId(baseArtifactId); + jsonTransformationDTO.setRefName(currentBranch); + // not that it matters + jsonTransformationDTO.setRefType(branchedGitData.getRefType()); + jsonTransformationDTO.setArtifactType(baseArtifact.getArtifactType()); + + if (!hasText(baseArtifactId) || !hasText(repoName) || !hasText(currentBranch)) { + log.error( + "Git config is not present for artifact {} of type {}", + baseArtifact.getId(), + baseArtifact.getArtifactType()); + return Mono.error(new AppsmithException(AppsmithError.INVALID_GIT_CONFIGURATION, GIT_CONFIG_ERROR)); + } + + Mono baseBranchMono; + if (TRUE.equals(pruneBranches) && syncDefaultBranchWithRemote) { + baseBranchMono = syncDefaultBranchNameFromRemote(baseGitData, jsonTransformationDTO, gitType); + } else { + baseBranchMono = Mono.just(GitUtils.getDefaultBranchName(baseGitData)); + } + + Mono> branchMono = baseBranchMono + .flatMap(baseBranchName -> { + return getBranchListWithDefaultBranchName( + baseArtifact, baseBranchName, currentBranch, pruneBranches, gitType); + }) + .onErrorResume(throwable -> { + if (throwable instanceof RepositoryNotFoundException) { + return handleRepoNotFoundException(jsonTransformationDTO, gitType); + } + return Mono.error(throwable); + }); + + return Mono.create(sink -> branchMono.subscribe(sink::success, sink::error, null, sink.currentContext())); + } + + private Mono syncDefaultBranchNameFromRemote( + GitArtifactMetadata metadata, ArtifactJsonTransformationDTO jsonTransformationDTO, GitType gitType) { + ArtifactType artifactType = jsonTransformationDTO.getArtifactType(); + GitHandlingService gitHandlingService = gitHandlingServiceResolver.getGitHandlingService(gitType); + + return gitRedisUtils + .acquireGitLock( + jsonTransformationDTO.getArtifactType(), + metadata.getDefaultArtifactId(), + GitConstants.GitCommandConstants.SYNC_BRANCH, + TRUE) + .then(gitHandlingService + .getDefaultBranchFromRepository(jsonTransformationDTO, metadata) + .flatMap(defaultBranchNameInRemote -> { + String defaultBranchInDb = GitUtils.getDefaultBranchName(metadata); + // If the default branch name in remote is empty or same as the one in DB, nothing to do + + if (!hasText(defaultBranchNameInRemote) + || defaultBranchNameInRemote.equals(defaultBranchInDb)) { + return Mono.just(defaultBranchInDb); + } + + // default branch has been changed in remote + return updateDefaultBranchName( + metadata.getDefaultArtifactId(), + defaultBranchNameInRemote, + jsonTransformationDTO, + artifactType, + gitType) + .then() + .thenReturn(defaultBranchNameInRemote); + }) + .flatMap(branchName -> gitRedisUtils + .releaseFileLock( + jsonTransformationDTO.getArtifactType(), metadata.getDefaultArtifactId(), TRUE) + .thenReturn(branchName))); + } + + private Flux updateDefaultBranchName( + String baseArtifactId, + String newDefaultBranchName, + ArtifactJsonTransformationDTO jsonTransformationDTO, + ArtifactType artifactType, + GitType gitType) { + // Get the artifact from DB by new defaultBranchName + GitArtifactHelper gitArtifactHelper = gitArtifactHelperResolver.getArtifactHelper(artifactType); + AclPermission artifactEditPermission = gitArtifactHelper.getArtifactEditPermission(); + + Mono baseArtifactMono = + gitArtifactHelper.getArtifactById(baseArtifactId, artifactEditPermission); + + GitRefDTO gitRefDTO = new GitRefDTO(); + gitRefDTO.setRefName(newDefaultBranchName); + gitRefDTO.setRefType(RefType.branch); + gitRefDTO.setDefault(true); + + // potentially problem in the flow, + // we are checking out to the branch after creation, + // and this is just a remote reference + return baseArtifactMono + .flatMap(baseArtifact -> { + // if the artifact with newDefaultBranch name is present locally then it could be checked out + // since this operation would happen inside a file lock, we don't require it. + return checkoutReference(baseArtifact, gitRefDTO, false, gitType) + .map(newDefaultBranchArtifact -> (Artifact) newDefaultBranchArtifact) + .onErrorResume(error -> { + if (error instanceof RefNotFoundException + || (error instanceof AppsmithException appsmithException + && appsmithException + .getAppErrorCode() + .equals(AppsmithError.NO_RESOURCE_FOUND.getAppErrorCode()))) { + log.error( + "Artifact with base id {} and branch name {} not found locally", + baseArtifactId, + newDefaultBranchName); + return checkoutRemoteReference(baseArtifact, gitRefDTO, gitType); + } + + return Mono.error(error); + }); + }) + .thenMany(Flux.defer( + () -> gitArtifactHelper.getAllArtifactByBaseId(baseArtifactId, artifactEditPermission))) + .flatMap(artifact -> { + artifact.getGitArtifactMetadata().setDefaultBranchName(newDefaultBranchName); + // clear the branch protection rules as the default branch name has been changed + artifact.getGitArtifactMetadata().setBranchProtectionRules(null); + return gitArtifactHelper.saveArtifact(artifact); + }); + } + + private Mono> handleRepoNotFoundException( + ArtifactJsonTransformationDTO jsonTransformationDTO, GitType gitType) { + // clone application to the local filesystem again and update the defaultBranch for the application + // list branch and compare with branch applications and checkout if not exists + + GitHandlingService gitHandlingService = gitHandlingServiceResolver.getGitHandlingService(gitType); + GitArtifactHelper gitArtifactHelper = + gitArtifactHelperResolver.getArtifactHelper(jsonTransformationDTO.getArtifactType()); + AclPermission artifactEditPermission = gitArtifactHelper.getArtifactEditPermission(); + AclPermission artifactReadPermission = gitArtifactHelper.getArtifactReadPermission(); + + Mono baseArtifactMono = + gitArtifactHelper.getArtifactById(jsonTransformationDTO.getBaseArtifactId(), artifactEditPermission); + + return baseArtifactMono.flatMap(baseArtifact -> { + GitArtifactMetadata gitArtifactMetadata = baseArtifact.getGitArtifactMetadata(); + GitAuth gitAuth = gitArtifactMetadata.getGitAuth(); + GitConnectDTO gitConnectDTO = new GitConnectDTO(); + gitConnectDTO.setRemoteUrl(gitArtifactMetadata.getRemoteUrl()); + + return gitHandlingService + .fetchRemoteRepository(gitConnectDTO, gitAuth, baseArtifact, gitArtifactMetadata.getRepoName()) + .flatMap(defaultBranch -> gitHandlingService.listReferences(jsonTransformationDTO, true)) + .flatMap(branches -> { + List branchesToCheckout = new ArrayList<>(); + List gitBranchDTOList = new ArrayList<>(); + for (String branch : branches) { + GitBranchDTO gitBranchDTO = new GitBranchDTO(); + gitBranchDTO.setBranchName(branch); + + if (branch.startsWith(ORIGIN)) { + // remove origin/ prefix from the remote branch name + String branchName = branch.replace(ORIGIN, REMOTE_NAME_REPLACEMENT); + // The root defaultArtifact is always there, no need to check out it again + if (!branchName.equals(gitArtifactMetadata.getBranchName())) { + branchesToCheckout.add(branchName); + } + + } else if (branch.equals(gitArtifactMetadata.getDefaultBranchName())) { + /* + We just cloned from the remote default branch. + Update the isDefault flag If it's also set as default in DB + */ + gitBranchDTO.setDefault(true); + } + } + + ArtifactJsonTransformationDTO branchCheckoutDTO = new ArtifactJsonTransformationDTO(); + branchCheckoutDTO.setWorkspaceId(baseArtifact.getWorkspaceId()); + branchCheckoutDTO.setArtifactType(baseArtifact.getArtifactType()); + branchCheckoutDTO.setRepoName(gitArtifactMetadata.getRepoName()); + + return Flux.fromIterable(branchesToCheckout) + .flatMap(branchName -> gitArtifactHelper + .getArtifactByBaseIdAndBranchName( + gitArtifactMetadata.getDefaultArtifactId(), + branchName, + artifactReadPermission) + // checkout the branch locally + .flatMap(artifact -> { + // Add the locally checked out branch to the branchList + GitBranchDTO gitBranchDTO = new GitBranchDTO(); + gitBranchDTO.setBranchName(branchName); + // set the default branch flag if there's a match. + // This can happen when user has changed the default branch other + // than + // remote + gitBranchDTO.setDefault(gitArtifactMetadata + .getDefaultBranchName() + .equals(branchName)); + gitBranchDTOList.add(gitBranchDTO); + + branchCheckoutDTO.setRefName(branchName); + return gitHandlingService.checkoutRemoteReference(branchCheckoutDTO); + }) + // Return empty mono when the branched defaultArtifact is not in db + .onErrorResume(throwable -> Mono.empty())) + .then(Mono.just(gitBranchDTOList)); + }); + }); + } + + private Mono> getBranchListWithDefaultBranchName( + Artifact baseArtifact, + String defaultBranchName, + String currentBranch, + boolean pruneBranches, + GitType gitType) { + + ArtifactType artifactType = baseArtifact.getArtifactType(); + GitArtifactMetadata baseGitData = baseArtifact.getGitArtifactMetadata(); + GitHandlingService gitHandlingService = gitHandlingServiceResolver.getGitHandlingService(gitType); + + ArtifactJsonTransformationDTO jsonTransformationDTO = new ArtifactJsonTransformationDTO(); + jsonTransformationDTO.setRepoName(baseGitData.getRepoName()); + jsonTransformationDTO.setWorkspaceId(baseArtifact.getWorkspaceId()); + jsonTransformationDTO.setBaseArtifactId(baseGitData.getDefaultArtifactId()); + jsonTransformationDTO.setRefName(currentBranch); + jsonTransformationDTO.setRefType(baseGitData.getRefType()); + jsonTransformationDTO.setArtifactType(baseArtifact.getArtifactType()); + + return gitRedisUtils + .acquireGitLock( + artifactType, + baseGitData.getDefaultArtifactId(), + GitConstants.GitCommandConstants.LIST_BRANCH, + TRUE) + .flatMap(ignoredLock -> { + Mono> listBranchesMono = + Mono.defer(() -> gitHandlingService.listReferences(jsonTransformationDTO, false)); + + if (TRUE.equals(pruneBranches)) { + return gitHandlingService + .fetchRemoteChanges(jsonTransformationDTO, baseGitData.getGitAuth(), TRUE) + .then(listBranchesMono); + } + return listBranchesMono; + }) + .onErrorResume(error -> { + return gitRedisUtils + .releaseFileLock(artifactType, baseGitData.getDefaultArtifactId(), TRUE) + .then(Mono.error(error)); + }) + .flatMap(branches -> { + return gitRedisUtils + .releaseFileLock(artifactType, baseGitData.getDefaultArtifactId(), TRUE) + .thenReturn(branches.stream() + .map(branchName -> { + GitBranchDTO gitBranchDTO = new GitBranchDTO(); + gitBranchDTO.setBranchName(branchName); + if (branchName.equalsIgnoreCase(defaultBranchName)) { + gitBranchDTO.setDefault(true); + } + return gitBranchDTO; + }) + .toList()); + }) + .flatMap(gitBranchDTOList -> FALSE.equals(pruneBranches) + ? Mono.just(gitBranchDTOList) + : gitAnalyticsUtils + .addAnalyticsForGitOperation( + AnalyticsEvents.GIT_PRUNE, + baseArtifact, + baseArtifact.getGitArtifactMetadata().getIsRepoPrivate()) + .thenReturn(gitBranchDTOList)); + } + @Override public Mono> updateProtectedBranches( String baseArtifactId, List branchNames, ArtifactType artifactType) { @@ -2175,4 +2511,85 @@ public Mono getAutoCommitProgress( String artifactId, String branchName, ArtifactType artifactType) { return gitAutoCommitHelper.getAutoCommitProgress(artifactId, branchName); } + + @Override + public Mono generateSSHKey(String keyType) { + GitAuth gitAuth = GitDeployKeyGenerator.generateSSHKey(keyType); + + GitDeployKeys gitDeployKeys = new GitDeployKeys(); + gitDeployKeys.setGitAuth(gitAuth); + + return sessionUserService + .getCurrentUser() + .flatMap(user -> { + gitDeployKeys.setEmail(user.getEmail()); + return gitDeployKeysRepository + .findByEmail(user.getEmail()) + .switchIfEmpty(gitDeployKeysRepository.save(gitDeployKeys)) + .flatMap(gitDeployKeys1 -> { + if (gitDeployKeys.equals(gitDeployKeys1)) { + return Mono.just(gitDeployKeys1); + } + // Overwrite the existing keys + gitDeployKeys1.setGitAuth(gitDeployKeys.getGitAuth()); + return gitDeployKeysRepository.save(gitDeployKeys1); + }); + }) + .thenReturn(gitAuth); + } + + @Override + public Mono getGitArtifactMetadata(String baseArtifactId, ArtifactType artifactType) { + + GitArtifactHelper gitArtifactHelper = gitArtifactHelperResolver.getArtifactHelper(artifactType); + AclPermission artifactEditPermission = gitArtifactHelper.getArtifactEditPermission(); + + Mono baseArtifactMono = + gitArtifactHelper.getArtifactById(baseArtifactId, artifactEditPermission); + + return Mono.zip(baseArtifactMono, userDataService.getForCurrentUser()).map(tuple -> { + Artifact baseArtifact = tuple.getT1(); + UserData userData = tuple.getT2(); + Map gitProfiles = new HashMap<>(); + GitArtifactMetadata baseGitMetadata = baseArtifact.getGitArtifactMetadata(); + + if (!CollectionUtils.isEmpty(userData.getGitProfiles())) { + gitProfiles.put(DEFAULT, userData.getGitProfileByKey(DEFAULT)); + gitProfiles.put(baseArtifactId, userData.getGitProfileByKey(baseArtifactId)); + } + if (baseGitMetadata == null) { + GitArtifactMetadata res = new GitArtifactMetadata(); + res.setGitProfiles(gitProfiles); + return res; + } + + baseGitMetadata.setGitProfiles(gitProfiles); + if (baseGitMetadata.getGitAuth() != null) { + baseGitMetadata.setPublicKey(baseGitMetadata.getGitAuth().getPublicKey()); + } + + baseGitMetadata.setDocUrl(Assets.GIT_DEPLOY_KEY_DOC_URL); + return baseGitMetadata; + }); + } + + /** + * In some scenarios: + * connect: after loading the modal, keyTypes is not available, so a network call has to be made to ssh-keypair. + * import: cannot make a ssh-keypair call because artifact Id doesn’t exist yet, so API fails. + * + * @return Git docs urls for all the scenarios, client will cache this data and use it + */ + @Override + public Mono> getGitDocUrls() { + ErrorReferenceDocUrl[] docSet = ErrorReferenceDocUrl.values(); + List gitDocsDTOList = new ArrayList<>(); + for (ErrorReferenceDocUrl docUrl : docSet) { + GitDocsDTO gitDocsDTO = new GitDocsDTO(); + gitDocsDTO.setDocKey(docUrl); + gitDocsDTO.setDocUrl(docUrl.getDocUrl()); + gitDocsDTOList.add(gitDocsDTO); + } + return Mono.just(gitDocsDTOList); + } } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceImpl.java index 7e1843a4b0ba..2a77924f307e 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceImpl.java @@ -11,6 +11,7 @@ import com.appsmith.server.helpers.GitPrivateRepoHelper; import com.appsmith.server.imports.internal.ImportService; import com.appsmith.server.plugins.base.PluginService; +import com.appsmith.server.repositories.GitDeployKeysRepository; import com.appsmith.server.services.SessionUserService; import com.appsmith.server.services.UserDataService; import com.appsmith.server.services.WorkspaceService; @@ -33,6 +34,7 @@ public CentralGitServiceImpl( GitArtifactHelperResolver gitArtifactHelperResolver, GitHandlingServiceResolver gitHandlingServiceResolver, GitPrivateRepoHelper gitPrivateRepoHelper, + GitDeployKeysRepository gitDeployKeysRepository, DatasourceService datasourceService, DatasourcePermission datasourcePermission, WorkspaceService workspaceService, @@ -51,6 +53,7 @@ public CentralGitServiceImpl( gitArtifactHelperResolver, gitHandlingServiceResolver, gitPrivateRepoHelper, + gitDeployKeysRepository, datasourceService, datasourcePermission, workspaceService, diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/GitHandlingServiceCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/GitHandlingServiceCE.java index 89b3d7d64a0e..43459bd9682a 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/GitHandlingServiceCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/GitHandlingServiceCE.java @@ -50,6 +50,9 @@ Mono> listBranches( Mono> listReferences( ArtifactJsonTransformationDTO artifactJsonTransformationDTO, Boolean checkRemoteReferences); + Mono getDefaultBranchFromRepository( + ArtifactJsonTransformationDTO jsonTransformationDTO, GitArtifactMetadata gitArtifactMetadata); + Mono validateEmptyRepository(ArtifactJsonTransformationDTO artifactJsonTransformationDTO); Mono initialiseReadMe( @@ -77,6 +80,8 @@ Mono recreateArtifactJsonFromLastCommit( Mono createGitReference(ArtifactJsonTransformationDTO artifactJsonTransformationDTO, GitRefDTO gitRefDTO); + Mono checkoutRemoteReference(ArtifactJsonTransformationDTO jsonTransformationDTO); + Mono deleteGitReference(ArtifactJsonTransformationDTO jsonTransformationDTO); Mono checkoutArtifact(ArtifactJsonTransformationDTO jsonTransformationDTO); diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/controllers/GitApplicationController.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/controllers/GitApplicationController.java new file mode 100644 index 000000000000..ccff87e094cf --- /dev/null +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/controllers/GitApplicationController.java @@ -0,0 +1,20 @@ +package com.appsmith.server.git.controllers; + +import com.appsmith.server.constants.Url; +import com.appsmith.server.git.autocommit.AutoCommitService; +import com.appsmith.server.git.central.CentralGitService; +import com.appsmith.server.git.utils.GitProfileUtils; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@Slf4j +@RestController +@RequestMapping(Url.GIT_APPLICATION_URL) +public class GitApplicationController extends GitApplicationControllerCE { + + public GitApplicationController( + CentralGitService centralGitService, GitProfileUtils gitProfileUtils, AutoCommitService autoCommitService) { + super(centralGitService, gitProfileUtils, autoCommitService); + } +} diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/controllers/GitApplicationControllerCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/controllers/GitApplicationControllerCE.java new file mode 100644 index 000000000000..e08e5716fb3b --- /dev/null +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/controllers/GitApplicationControllerCE.java @@ -0,0 +1,225 @@ +package com.appsmith.server.git.controllers; + +import com.appsmith.external.dtos.GitBranchDTO; +import com.appsmith.external.dtos.GitRefDTO; +import com.appsmith.external.dtos.GitStatusDTO; +import com.appsmith.external.git.constants.ce.RefType; +import com.appsmith.external.views.Views; +import com.appsmith.git.dto.CommitDTO; +import com.appsmith.server.constants.ArtifactType; +import com.appsmith.server.constants.FieldName; +import com.appsmith.server.constants.Url; +import com.appsmith.server.domains.Artifact; +import com.appsmith.server.domains.GitArtifactMetadata; +import com.appsmith.server.dtos.AutoCommitResponseDTO; +import com.appsmith.server.dtos.BranchProtectionRequestDTO; +import com.appsmith.server.dtos.GitConnectDTO; +import com.appsmith.server.dtos.GitPullDTO; +import com.appsmith.server.dtos.ResponseDTO; +import com.appsmith.server.git.autocommit.AutoCommitService; +import com.appsmith.server.git.central.CentralGitService; +import com.appsmith.server.git.central.GitType; +import com.appsmith.server.git.utils.GitProfileUtils; +import com.fasterxml.jackson.annotation.JsonView; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.BooleanUtils; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PatchMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseStatus; +import reactor.core.publisher.Mono; + +import java.util.List; + +@Slf4j +@RequestMapping(Url.GIT_APPLICATION_URL) +@RequiredArgsConstructor +public class GitApplicationControllerCE { + + protected final CentralGitService centralGitService; + protected final GitProfileUtils gitProfileUtils; + protected final AutoCommitService autoCommitService; + + protected static final ArtifactType ARTIFACT_TYPE = ArtifactType.APPLICATION; + protected static final GitType GIT_TYPE = GitType.FILE_SYSTEM; + + @JsonView({Views.Metadata.class}) + @GetMapping("/{baseApplicationId}/metadata") + public Mono> getGitMetadata(@PathVariable String baseApplicationId) { + return centralGitService + .getGitArtifactMetadata(baseApplicationId, ARTIFACT_TYPE) + .map(metadata -> new ResponseDTO<>(HttpStatus.OK.value(), metadata, null)); + } + + @JsonView(Views.Public.class) + @PostMapping("/{applicationId}/connect") + public Mono> connectApplicationToRemoteRepo( + @PathVariable String applicationId, + @RequestBody GitConnectDTO gitConnectDTO, + @RequestHeader("Origin") String originHeader) { + return centralGitService + .connectArtifactToGit(applicationId, gitConnectDTO, originHeader, ARTIFACT_TYPE, GIT_TYPE) + .map(application -> new ResponseDTO<>(HttpStatus.OK.value(), application, null)); + } + + @JsonView(Views.Public.class) + @PostMapping("/{branchedApplicationId}/commit") + @ResponseStatus(HttpStatus.CREATED) + public Mono> commit( + @RequestBody CommitDTO commitDTO, @PathVariable String branchedApplicationId) { + log.info("Going to commit branchedApplicationId {}", branchedApplicationId); + return centralGitService + .commitArtifact(commitDTO, branchedApplicationId, ARTIFACT_TYPE, GIT_TYPE) + .map(result -> new ResponseDTO<>(HttpStatus.CREATED.value(), result, null)); + } + + @JsonView(Views.Public.class) + @PostMapping("/{referencedApplicationId}/create-ref") + @ResponseStatus(HttpStatus.CREATED) + public Mono> createReference( + @PathVariable String referencedApplicationId, + @RequestHeader(name = FieldName.BRANCH_NAME, required = false) String srcBranch, + @RequestBody GitRefDTO gitRefDTO) { + log.info( + "Going to create a reference from referencedApplicationId {}, srcBranch {}", + referencedApplicationId, + srcBranch); + return centralGitService + .createReference(referencedApplicationId, gitRefDTO, ArtifactType.APPLICATION, GIT_TYPE) + .map(result -> new ResponseDTO<>(HttpStatus.CREATED.value(), result, null)); + } + + @JsonView(Views.Public.class) + @PostMapping("/{referencedApplicationId}/checkout-ref") + public Mono> checkoutReference( + @PathVariable String referencedApplicationId, @RequestBody GitRefDTO gitRefDTO) { + return centralGitService + .checkoutReference(referencedApplicationId, gitRefDTO, true, ARTIFACT_TYPE, GIT_TYPE) + .map(result -> new ResponseDTO<>(HttpStatus.OK.value(), result, null)); + } + + @JsonView(Views.Public.class) + @PostMapping("/{branchedApplicationId}/disconnect") + public Mono> disconnectFromRemote(@PathVariable String branchedApplicationId) { + log.info("Going to remove the remoteUrl for application {}", branchedApplicationId); + return centralGitService + .detachRemote(branchedApplicationId, ARTIFACT_TYPE, GIT_TYPE) + .map(result -> new ResponseDTO<>(HttpStatus.OK.value(), result, null)); + } + + @JsonView(Views.Public.class) + @GetMapping("/{branchedApplicationId}/pull") + public Mono> pull(@PathVariable String branchedApplicationId) { + log.info("Going to pull the latest for branchedApplicationId {}", branchedApplicationId); + return centralGitService + .pullArtifact(branchedApplicationId, ARTIFACT_TYPE, GIT_TYPE) + .map(result -> new ResponseDTO<>(HttpStatus.OK.value(), result, null)); + } + + @JsonView(Views.Public.class) + @GetMapping("/{branchedApplicationId}/status") + public Mono> getStatus( + @PathVariable String branchedApplicationId, + @RequestParam(required = false, defaultValue = "true") Boolean compareRemote) { + log.info("Going to get status for branchedApplicationId {}", branchedApplicationId); + return centralGitService + .getStatus(branchedApplicationId, compareRemote, ARTIFACT_TYPE, GIT_TYPE) + .map(result -> new ResponseDTO<>(HttpStatus.OK.value(), result, null)); + } + + @JsonView(Views.Public.class) + @GetMapping("/{referencedApplicationId}/fetch/remote") + public Mono> fetchRemoteChanges( + @PathVariable String referencedApplicationId, + @RequestHeader(required = false, defaultValue = "branch") RefType refType) { + log.info("Going to compare with remote for default referencedApplicationId {}", referencedApplicationId); + return centralGitService + .fetchRemoteChanges(referencedApplicationId, true, ARTIFACT_TYPE, GIT_TYPE, refType) + .map(result -> new ResponseDTO<>(HttpStatus.OK.value(), result, null)); + } + + @JsonView(Views.Public.class) + @DeleteMapping("/{baseArtifactId}/ref") + public Mono> deleteBranch( + @PathVariable String baseArtifactId, @RequestBody GitRefDTO gitRefDTO) { + log.info("Going to delete ref {} for baseApplicationId {}", gitRefDTO.getRefName(), baseArtifactId); + return centralGitService + .deleteGitReference(baseArtifactId, gitRefDTO, ARTIFACT_TYPE, GIT_TYPE) + .map(application -> new ResponseDTO<>(HttpStatus.OK.value(), application, null)); + } + + @JsonView(Views.Public.class) + @PutMapping("/{branchedApplicationId}/discard") + public Mono> discardChanges(@PathVariable String branchedApplicationId) { + log.info("Going to discard changes for branchedApplicationId {}", branchedApplicationId); + return centralGitService + .discardChanges(branchedApplicationId, ARTIFACT_TYPE, GIT_TYPE) + .map(result -> new ResponseDTO<>((HttpStatus.OK.value()), result, null)); + } + + @JsonView(Views.Public.class) + @PostMapping("/{baseArtifactId}/branch/protected") + public Mono>> updateProtectedBranches( + @PathVariable String baseArtifactId, + @RequestBody @Valid BranchProtectionRequestDTO branchProtectionRequestDTO) { + return centralGitService + .updateProtectedBranches(baseArtifactId, branchProtectionRequestDTO.getBranchNames(), ARTIFACT_TYPE) + .map(data -> new ResponseDTO<>(HttpStatus.OK.value(), data, null)); + } + + @JsonView(Views.Public.class) + @GetMapping("/{baseArtifactId}/branch/protected") + public Mono>> getProtectedBranches(@PathVariable String baseArtifactId) { + return centralGitService + .getProtectedBranches(baseArtifactId, ARTIFACT_TYPE) + .map(list -> new ResponseDTO<>(HttpStatus.OK.value(), list, null)); + } + + @JsonView(Views.Public.class) + @PostMapping("/{branchedApplicationId}/auto-commit") + public Mono> autoCommitApplication(@PathVariable String branchedApplicationId) { + return autoCommitService + .autoCommitApplication(branchedApplicationId) + .map(data -> new ResponseDTO<>(HttpStatus.OK.value(), data, null)); + } + + @JsonView(Views.Public.class) + @GetMapping("/{baseApplicationId}/auto-commit/progress") + public Mono> getAutoCommitProgress( + @PathVariable String baseApplicationId, + @RequestHeader(name = FieldName.BRANCH_NAME, required = false) String branchName) { + return centralGitService + .getAutoCommitProgress(baseApplicationId, branchName, ARTIFACT_TYPE) + .map(data -> new ResponseDTO<>(HttpStatus.OK.value(), data, null)); + } + + @JsonView(Views.Public.class) + @PatchMapping("/{baseArtifactId}/auto-commit/toggle") + public Mono> toggleAutoCommitEnabled(@PathVariable String baseArtifactId) { + return centralGitService + .toggleAutoCommitEnabled(baseArtifactId, ARTIFACT_TYPE) + .map(data -> new ResponseDTO<>(HttpStatus.OK.value(), data, null)); + } + + @JsonView(Views.Public.class) + @GetMapping("/{branchedApplicationId}/branches") + public Mono>> branch( + @PathVariable String branchedApplicationId, + @RequestParam(required = false, defaultValue = "false") Boolean pruneBranches) { + log.debug("Going to get branch list for application {}", branchedApplicationId); + return centralGitService + .listBranchForArtifact( + branchedApplicationId, BooleanUtils.isTrue(pruneBranches), ARTIFACT_TYPE, GIT_TYPE) + .map(result -> new ResponseDTO<>(HttpStatus.OK.value(), result, null)); + } +} diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/controllers/GitArtifactController.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/controllers/GitArtifactController.java new file mode 100644 index 000000000000..e607a0dd151a --- /dev/null +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/controllers/GitArtifactController.java @@ -0,0 +1,18 @@ +package com.appsmith.server.git.controllers; + +import com.appsmith.server.constants.Url; +import com.appsmith.server.git.central.CentralGitService; +import com.appsmith.server.git.utils.GitProfileUtils; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@Slf4j +@RestController +@RequestMapping(Url.GIT_ARTIFACT_URL) +public class GitArtifactController extends GitArtifactControllerCE { + + public GitArtifactController(CentralGitService centralGitService, GitProfileUtils gitProfileUtils) { + super(centralGitService, gitProfileUtils); + } +} diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/controllers/GitArtifactControllerCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/controllers/GitArtifactControllerCE.java new file mode 100644 index 000000000000..71215783c16e --- /dev/null +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/controllers/GitArtifactControllerCE.java @@ -0,0 +1,74 @@ +package com.appsmith.server.git.controllers; + +import com.appsmith.external.views.Views; +import com.appsmith.server.constants.ArtifactType; +import com.appsmith.server.constants.Url; +import com.appsmith.server.domains.GitAuth; +import com.appsmith.server.dtos.ApplicationImportDTO; +import com.appsmith.server.dtos.GitConnectDTO; +import com.appsmith.server.dtos.GitDeployKeyDTO; +import com.appsmith.server.dtos.GitDocsDTO; +import com.appsmith.server.dtos.ResponseDTO; +import com.appsmith.server.git.central.CentralGitService; +import com.appsmith.server.git.central.GitType; +import com.appsmith.server.git.utils.GitProfileUtils; +import com.appsmith.server.helpers.GitDeployKeyGenerator; +import com.fasterxml.jackson.annotation.JsonView; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import reactor.core.publisher.Mono; + +import java.util.List; + +@Slf4j +@RequestMapping(Url.GIT_ARTIFACT_URL) +@RequiredArgsConstructor +public class GitArtifactControllerCE { + + protected final CentralGitService centralGitService; + protected final GitProfileUtils gitProfileUtils; + + protected static final GitType GIT_TYPE = GitType.FILE_SYSTEM; + + @JsonView(Views.Public.class) + @PostMapping("/import") + public Mono> importApplicationFromGit( + @RequestParam String workspaceId, @RequestBody GitConnectDTO gitConnectDTO) { + + // TODO: remove artifact type from methods. + return centralGitService + .importArtifactFromGit(workspaceId, gitConnectDTO, ArtifactType.APPLICATION, GIT_TYPE) + .map(artifactImportDTO -> (ApplicationImportDTO) artifactImportDTO) + .map(result -> new ResponseDTO<>(HttpStatus.CREATED.value(), result, null)); + } + + @JsonView(Views.Public.class) + @GetMapping("/doc-urls") + public Mono>> getGitDocs() { + return centralGitService + .getGitDocUrls() + .map(gitDocDTO -> new ResponseDTO<>(HttpStatus.OK.value(), gitDocDTO, null)); + } + + @JsonView(Views.Public.class) + @GetMapping("/protocol/key-types") + public Mono>> getSupportedKeys() { + log.info("Going to list the list of supported keys"); + return Mono.just(GitDeployKeyGenerator.getSupportedProtocols()) + .map(gitDeployKeyDTOS -> new ResponseDTO<>(HttpStatus.OK.value(), gitDeployKeyDTOS, null)); + } + + @JsonView(Views.Public.class) + @GetMapping("/import/keys") + public Mono> generateKeyForGitImport(@RequestParam(required = false) String keyType) { + return centralGitService + .generateSSHKey(keyType) + .map(result -> new ResponseDTO<>(HttpStatus.OK.value(), result, null)); + } +} diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/fs/GitFSServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/fs/GitFSServiceCEImpl.java index 60d834763246..eafd070e04fe 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/fs/GitFSServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/fs/GitFSServiceCEImpl.java @@ -273,6 +273,27 @@ public Mono> listReferences( return Mono.just(List.of()); } + @Override + public Mono getDefaultBranchFromRepository( + ArtifactJsonTransformationDTO jsonTransformationDTO, GitArtifactMetadata baseGitData) { + if (isGitAuthInvalid(baseGitData.getGitAuth())) { + return Mono.error(new AppsmithException(AppsmithError.INVALID_GIT_CONFIGURATION, GIT_CONFIG_ERROR)); + } + + String publicKey = baseGitData.getGitAuth().getPublicKey(); + String privateKey = baseGitData.getGitAuth().getPrivateKey(); + + GitArtifactHelper gitArtifactHelper = + gitArtifactHelperResolver.getArtifactHelper(jsonTransformationDTO.getArtifactType()); + + Path repoSuffixPath = gitArtifactHelper.getRepoSuffixPath( + jsonTransformationDTO.getWorkspaceId(), + jsonTransformationDTO.getBaseArtifactId(), + jsonTransformationDTO.getRepoName()); + + return fsGitHandler.getRemoteDefaultBranch(repoSuffixPath, baseGitData.getRemoteUrl(), privateKey, publicKey); + } + @Override public Mono validateEmptyRepository(ArtifactJsonTransformationDTO artifactJsonTransformationDTO) { GitArtifactHelper gitArtifactHelper = @@ -629,6 +650,19 @@ public Mono createGitReference(ArtifactJsonTransformationDTO jsonTransfo return fsGitHandler.createAndCheckoutReference(repoSuffix, gitRefDTO); } + @Override + public Mono checkoutRemoteReference(ArtifactJsonTransformationDTO jsonTransformationDTO) { + GitArtifactHelper gitArtifactHelper = + gitArtifactHelperResolver.getArtifactHelper(jsonTransformationDTO.getArtifactType()); + + Path repoSuffix = gitArtifactHelper.getRepoSuffixPath( + jsonTransformationDTO.getWorkspaceId(), + jsonTransformationDTO.getBaseArtifactId(), + jsonTransformationDTO.getRepoName()); + + return fsGitHandler.checkoutRemoteBranch(repoSuffix, jsonTransformationDTO.getRefName()); + } + @Override public Mono deleteGitReference(ArtifactJsonTransformationDTO jsonTransformationDTO) { ArtifactType artifactType = jsonTransformationDTO.getArtifactType(); @@ -661,7 +695,6 @@ public Mono deleteGitReference(ArtifactJsonTransformationDTO jsonTransf @Override public Mono checkoutArtifact(ArtifactJsonTransformationDTO jsonTransformationDTO) { - GitArtifactHelper gitArtifactHelper = gitArtifactHelperResolver.getArtifactHelper(jsonTransformationDTO.getArtifactType()); diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/utils/GitAnalyticsUtils.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/utils/GitAnalyticsUtils.java index bc8f8922db3d..171f201dba6f 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/utils/GitAnalyticsUtils.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/utils/GitAnalyticsUtils.java @@ -187,4 +187,33 @@ public Mono sendBranchProtectionAnalytics( return Flux.merge(eventSenderMonos).then(); } + + /** + * Generic method to send analytics for git operations. + * + * @param analyticsEvents Name of the event + * @param artifact Application object + * @param extraProps Extra properties that need to be passed along with default ones. + * @return A void mono + */ + public Mono sendGitAnalyticsEvent( + AnalyticsEvents analyticsEvents, Artifact artifact, Map extraProps) { + GitArtifactMetadata gitData = artifact.getGitArtifactMetadata(); + Map analyticsProps = new HashMap<>(); + + // TODO: analytics generalisation + analyticsProps.put("appId", gitData.getDefaultArtifactId()); + analyticsProps.put("orgId", artifact.getWorkspaceId()); + analyticsProps.put(FieldName.GIT_HOSTING_PROVIDER, GitUtils.getGitProviderName(gitData.getRemoteUrl())); + analyticsProps.put(FieldName.REPO_URL, gitData.getRemoteUrl()); + + if (extraProps != null) { + analyticsProps.putAll(extraProps); + } + + return sessionUserService + .getCurrentUser() + .flatMap(user -> + analyticsService.sendEvent(analyticsEvents.getEventName(), user.getUsername(), analyticsProps)); + } } From 74cd364aeadd09fc5342570239f8375d299caa2d Mon Sep 17 00:00:00 2001 From: NandanAnantharamu <67676905+NandanAnantharamu@users.noreply.github.com> Date: Fri, 3 Jan 2025 09:33:59 +0530 Subject: [PATCH 10/40] test: flaky check for Abort spec (#38428) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit /ok-to-test tags="@tag.Sanity" > [!TIP] > 🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉 > Workflow run: > Commit: f1b695a07ddb1f486bc809a5b175af6f35342875 > Cypress dashboard. > Tags: `@tag.Sanity` > Spec: >
Fri, 03 Jan 2025 03:43:49 UTC ## Summary by CodeRabbit - **Tests** - Temporarily disabled test suite for Abort Action Execution due to an open bug - Skipped specific test cases related to action cancellation --------- Co-authored-by: “NandanAnantharamu” <“nandan@thinkify.io”> --- .../e2e/Regression/ClientSide/BugTests/AbortAction_Spec.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/client/cypress/e2e/Regression/ClientSide/BugTests/AbortAction_Spec.ts b/app/client/cypress/e2e/Regression/ClientSide/BugTests/AbortAction_Spec.ts index 244efea2281e..55aca6b57885 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/BugTests/AbortAction_Spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/BugTests/AbortAction_Spec.ts @@ -7,10 +7,11 @@ import { entityItems, } from "../../../../support/Objects/ObjectsCore"; -describe( +describe.skip( "Abort Action Execution", { tags: ["@tag.Datasource", "@tag.Git", "@tag.AccessControl"] }, function () { + //Open Bug: https://github.com/appsmithorg/appsmith/issues/38165 it("1. Bug #14006, #16093 - Cancel request button should abort API action execution", function () { apiPage.CreateAndFillApi( dataManager.dsValues[dataManager.defaultEnviorment].mockApiUrl + "00", @@ -31,8 +32,9 @@ describe( // Queries were resolving quicker than we could cancel them // Commenting this out till we can find a query that resolves slow enough for us to cancel its execution. + //Open Bug: https://github.com/appsmithorg/appsmith/issues/38165 - it("2. Bug #14006, #16093 Cancel request button should abort Query action execution", function () { + it.skip("2. Bug #14006, #16093 Cancel request button should abort Query action execution", function () { dataSources.CreateDataSource("MySql"); cy.get("@dsName").then(($dsName) => { dataSources.CreateQueryAfterDSSaved( From 0198ad854e09dbaeca2b160450bdac09ff40833b Mon Sep 17 00:00:00 2001 From: NandanAnantharamu <67676905+NandanAnantharamu@users.noreply.github.com> Date: Fri, 3 Jan 2025 09:34:30 +0530 Subject: [PATCH 11/40] test: flaky check for onload spec (#38429) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit /ok-to-test tags="@tag.Sanity" > [!TIP] > 🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉 > Workflow run: > Commit: 92ca095e01d4ec7c2ffd3382129df66e7c6dce6d > Cypress dashboard. > Tags: `@tag.Sanity` > Spec: >
Fri, 03 Jan 2025 03:37:24 UTC --------- Co-authored-by: “NandanAnantharamu” <“nandan@thinkify.io”> --- .../Regression/ServerSide/OnLoadTests/OnLoadActions_Spec.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) 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 5d2b8c7a6941..d5b496ce2e61 100644 --- a/app/client/cypress/e2e/Regression/ServerSide/OnLoadTests/OnLoadActions_Spec.ts +++ b/app/client/cypress/e2e/Regression/ServerSide/OnLoadTests/OnLoadActions_Spec.ts @@ -43,7 +43,8 @@ describe( }); }); - it("2. Bug 8595: OnPageLoad execution - when Query Parmas added via Params tab", function () { + //Open Bug: https://github.com/appsmithorg/appsmith/issues/38165 + it.skip("2. Bug 8595: OnPageLoad execution - when Query Parmas added via Params tab", function () { agHelper.AddDsl("onPageLoadActionsDsl", locators._imageWidget); apiPage.CreateAndFillApi( dataManager.dsValues[dataManager.defaultEnviorment].flowerImageUrl1, @@ -142,7 +143,8 @@ describe( agHelper.AssertElementAbsence(locators._errorTab); }); - it("3. Bug 10049, 10055: Dependency not executed in expected order in layoutOnLoadActions when dependency added via URL", function () { + //Open Bug: https://github.com/appsmithorg/appsmith/issues/38165 + it.skip("3. Bug 10049, 10055: Dependency not executed in expected order in layoutOnLoadActions when dependency added via URL", function () { EditorNavigation.SelectEntityByName("Genderize", EntityType.Api); entityExplorer.ActionContextMenuByEntityName({ entityNameinLeftSidebar: "Genderize", From 9dba1f24c6abaf6fde6a616b913f9e7d2d65fb19 Mon Sep 17 00:00:00 2001 From: Nikhil Nandagopal Date: Fri, 3 Jan 2025 13:34:18 +0700 Subject: [PATCH 12/40] Updated Label Config --- .github/config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/config.json b/.github/config.json index 1e1f5d41415d..9a292106f958 100644 --- a/.github/config.json +++ b/.github/config.json @@ -1 +1 @@ -{"runners":[{"versioning":{"source":"milestones","type":"SemVer"},"prereleaseName":"alpha","issue":{"labels":{"Widgets Product":{"conditions":[{"label":"Button Widget","type":"hasLabel","value":true},{"label":"Chart Widget","type":"hasLabel","value":true},{"label":"Container Widget","type":"hasLabel","value":true},{"label":"Date Picker Widget","type":"hasLabel","value":true},{"label":"Select Widget","type":"hasLabel","value":true},{"label":"File Picker Widget","type":"hasLabel","value":true},{"label":"Form Widget","type":"hasLabel","value":true},{"label":"Image Widget","type":"hasLabel","value":true},{"label":"Input Widget","type":"hasLabel","value":true},{"label":"List Widget","type":"hasLabel","value":true},{"label":"MultiSelect Widget","type":"hasLabel","value":true},{"label":"Map Widget","type":"hasLabel","value":true},{"label":"Modal Widget","type":"hasLabel","value":true},{"label":"Radio Widget","type":"hasLabel","value":true},{"label":"Rich Text Editor Widget","type":"hasLabel","value":true},{"label":"Tab Widget","type":"hasLabel","value":true},{"label":"Table Widget","type":"hasLabel","value":true},{"label":"Text Widget","type":"hasLabel","value":true},{"label":"Video Widget","type":"hasLabel","value":true},{"label":"iFrame","type":"hasLabel","value":true},{"label":"Menu Button","type":"hasLabel","value":true},{"label":"Rating","type":"hasLabel","value":true},{"label":"Widget Validation","type":"hasLabel","value":true},{"label":"New Widget","type":"hasLabel","value":true},{"label":"Switch widget","type":"hasLabel","value":true},{"label":"Audio Widget","type":"hasLabel","value":true},{"label":"Icon Button Widget","type":"hasLabel","value":true},{"label":"Stat Box Widget","type":"hasLabel","value":true},{"label":"Voice Recorder Widget","type":"hasLabel","value":true},{"label":"Calendar Widget","type":"hasLabel","value":true},{"label":"Menu Button Widget","type":"hasLabel","value":true},{"label":"Divider Widget","type":"hasLabel","value":true},{"label":"Rating Widget","type":"hasLabel","value":true},{"label":"View Mode","type":"hasLabel","value":true},{"label":"Widget Property","type":"hasLabel","value":true},{"label":"Document Viewer Widget","type":"hasLabel","value":true},{"label":"Radio Group Widget","type":"hasLabel","value":true},{"label":"Currency Input Widget","type":"hasLabel","value":true},{"label":"TreeSelect","type":"hasLabel","value":true},{"label":"MultiTree Select Widget","type":"hasLabel","value":true},{"label":"Phone Input Widget","type":"hasLabel","value":true},{"label":"JSON Form","type":"hasLabel","value":true},{"label":"All Widgets","type":"hasLabel","value":true},{"label":"Button Group widget","type":"hasLabel","value":true},{"label":"Progress bar widget","type":"hasLabel","value":true},{"label":"Audio Recorder Widget","type":"hasLabel","value":true},{"label":"Camera Widget","type":"hasLabel","value":true},{"label":"Table Widget V2","type":"hasLabel","value":true},{"label":"Map Chart Widget","type":"hasLabel","value":true},{"label":"Code Scanner Widget","type":"hasLabel","value":true},{"label":"Widget keyboard accessibility","type":"hasLabel","value":true},{"label":"List Widget V2","type":"hasLabel","value":true},{"label":"Slider Widget","type":"hasLabel","value":true},{"label":"One-click Binding","type":"hasLabel","value":true},{"label":"Old widget version","type":"hasLabel","value":true},{"label":"Widget Discoverability","type":"hasLabel","value":true},{"label":"Switch Group Widget","type":"hasLabel","value":true},{"label":"Checkbox Group widget","type":"hasLabel","value":true},{"label":"Checkbox Widget","type":"hasLabel","value":true},{"label":"Table Inline Edit","type":"hasLabel","value":true},{"label":"Custom Widgets","type":"hasLabel","value":true}],"requires":1},"Javascript Product":{"conditions":[{"label":"JS Linting & Errors","type":"hasLabel","value":true},{"label":"Autocomplete","type":"hasLabel","value":true},{"label":"Evaluated Value","type":"hasLabel","value":true},{"label":"Slash Command","type":"hasLabel","value":true},{"label":"New JS Function","type":"hasLabel","value":true},{"label":"JS Usability","type":"hasLabel","value":true},{"label":"Framework Functions","type":"hasLabel","value":true},{"label":"JS Objects","type":"hasLabel","value":true},{"label":"JS Evaluation","type":"hasLabel","value":true},{"label":"Custom JS Libraries","type":"hasLabel","value":true},{"label":"Action Selector","type":"hasLabel","value":true},{"label":"Widget setter method","type":"hasLabel","value":true},{"label":"Entity Refactor","type":"hasLabel","value":true},{"label":"AST-frontend","type":"hasLabel","value":true},{"label":"Sniping Mode","type":"hasLabel","value":true},{"label":"AST-backend","type":"hasLabel","value":true}],"requires":1},"IDE Product":{"conditions":[{"label":"IDE Product","type":"hasLabel","value":true},{"label":"IDE Infra","type":"hasLabel","value":true},{"label":"IDE Navigation","type":"hasLabel","value":true},{"label":"IDE tabs","type":"hasLabel","value":true},{"label":"Omnibar","type":"hasLabel","value":true},{"label":"Entity Explorer","type":"hasLabel","value":true},{"label":"Page Management","type":"hasLabel","value":true},{"label":"Preview mode","type":"hasLabel","value":true},{"label":"Entity Management","type":"hasLabel","value":true}],"requires":1},"Accelerators Product":{"conditions":[{"label":"Generate Page","type":"hasLabel","value":true},{"label":"Building blocks","type":"hasLabel","value":true}],"requires":1},"Templates Product":{"conditions":[{"label":"Partial-import-export","type":"hasLabel","value":true},{"label":"Templates Product","type":"hasLabel","value":true}],"requires":1},"Design System Product":{"conditions":[{"label":"Design System Product","type":"hasLabel","value":true},{"label":"ADS Component Issue","type":"hasLabel","value":true},{"label":"Keyboard accessibility ","type":"hasLabel","value":true},{"label":"Toggle button","type":"hasLabel","value":true},{"label":"ADS Category Token","type":"hasLabel","value":true},{"label":"ADS Component Documentation","type":"hasLabel","value":true},{"label":"ADS Migration","type":"hasLabel","value":true},{"label":"ADS Deduplication ","type":"hasLabel","value":true},{"label":"ADS Revamp","type":"hasLabel","value":true},{"label":"ADS Deduplication","type":"hasLabel","value":true},{"label":"ADS Unit Test","type":"hasLabel","value":true},{"label":"ADS Components","type":"hasLabel","value":true},{"label":"ADS Grayscale","type":"hasLabel","value":true},{"label":"Design System","type":"hasLabel","value":true},{"label":"ADS Typography","type":"hasLabel","value":true},{"label":"ADS Visual Styles","type":"hasLabel","value":true},{"label":"ADS Component Design","type":"hasLabel","value":true},{"label":"Modal Component","type":"hasLabel","value":true},{"label":"ADS Spacing","type":"hasLabel","value":true},{"label":"ads unit test","type":"hasLabel","value":true},{"label":"ads revamp","type":"hasLabel","value":true},{"label":"ads deduplication","type":"hasLabel","value":true}],"requires":1},"RBAC Product":{"conditions":[{"label":"Invite users","type":"hasLabel","value":true},{"label":"RBAC Product","type":"hasLabel","value":true}],"requires":1},"Workspace Product":{"conditions":[{"label":"Home Page","type":"hasLabel","value":true},{"label":"Workspace Product","type":"hasLabel","value":true}],"requires":1},"Billing & Licensing Product":{"conditions":[{"label":"Customer Portal","type":"hasLabel","value":true},{"label":"Cloud Services","type":"hasLabel","value":true},{"label":"Billing","type":"hasLabel","value":true},{"label":"Self Serve","type":"hasLabel","value":true},{"label":"Enterprise Billing","type":"hasLabel","value":true},{"label":"Analytics Improvements","type":"hasLabel","value":true},{"label":"Self Serve 1.0","type":"hasLabel","value":true},{"label":"License","type":"hasLabel","value":true},{"label":"BE instance","type":"hasLabel","value":true},{"label":"Invite flow","type":"hasLabel","value":true},{"label":"CE Instance Usage","type":"hasLabel","value":true},{"label":"Feature Flagging","type":"hasLabel","value":true}],"requires":1},"Packages Product":{"conditions":[{"label":"Packages Product","type":"hasLabel","value":true}],"requires":1},"Environments Product":{"conditions":[{"label":"Environments Product","type":"hasLabel","value":true}],"requires":1},"UI Building Product":{"conditions":[{"label":"Property Pane","type":"hasLabel","value":true},{"label":"Copy Paste","type":"hasLabel","value":true},{"label":"Drag & Drop","type":"hasLabel","value":true},{"label":"Undo/Redo","type":"hasLabel","value":true},{"label":"Widgets Pane","type":"hasLabel","value":true},{"label":"UI Performance","type":"hasLabel","value":true},{"label":"Widget Grouping","type":"hasLabel","value":true},{"label":"Reflow & Resize","type":"hasLabel","value":true},{"label":"Canvas / Grid","type":"hasLabel","value":true},{"label":"Auto Height","type":"hasLabel","value":true},{"label":"Browser specific","type":"hasLabel","value":true},{"label":"Auto Layout","type":"hasLabel","value":true},{"label":"Fixed layout","type":"hasLabel","value":true},{"label":"App Navigation","type":"hasLabel","value":true}],"requires":1},"Onboarding Product":{"conditions":[{"label":"Welcome Screen","type":"hasLabel","value":true}],"requires":1},"Git Product":{"conditions":[{"label":"Git Product","type":"hasLabel","value":true},{"label":"Git Auto-commit","type":"hasLabel","value":true},{"label":"Auto-commit","type":"hasLabel","value":true},{"label":"Continuous Deployment","type":"hasLabel","value":true},{"label":"Default branch","type":"hasLabel","value":true},{"label":"Git status","type":"hasLabel","value":true},{"label":"Git performance","type":"hasLabel","value":true},{"label":"SDLC","type":"hasLabel","value":true},{"label":"Git IA","type":"hasLabel","value":true},{"label":"Branch management","type":"hasLabel","value":true}],"requires":1},"Embedding Apps Product":{"conditions":[{"label":"Embedding Apps Product","type":"hasLabel","value":true}],"requires":1},"Integrations Product":{"conditions":[{"label":"New Datasource","type":"hasLabel","value":true},{"label":"Firestore","type":"hasLabel","value":true},{"label":"Google Sheets","type":"hasLabel","value":true},{"label":"Mongo","type":"hasLabel","value":true},{"label":"Redshift","type":"hasLabel","value":true},{"label":"snowflake","type":"hasLabel","value":true},{"label":"S3","type":"hasLabel","value":true},{"label":"Redis","type":"hasLabel","value":true},{"label":"Postgres","type":"hasLabel","value":true},{"label":"GraphQL Plugin","type":"hasLabel","value":true},{"label":"ArangoDB","type":"hasLabel","value":true},{"label":"MsSQL","type":"hasLabel","value":true},{"label":"Elastic Search","type":"hasLabel","value":true},{"label":"OAuth","type":"hasLabel","value":true},{"label":"Airtable","type":"hasLabel","value":true},{"label":"CURL","type":"hasLabel","value":true},{"label":"DynamoDB","type":"hasLabel","value":true},{"label":"Zendesk","type":"hasLabel","value":true},{"label":"Hubspot","type":"hasLabel","value":true},{"label":"Query Forms","type":"hasLabel","value":true},{"label":"Twilio","type":"hasLabel","value":true},{"label":"MySQL","type":"hasLabel","value":true},{"label":"Connection pool","type":"hasLabel","value":true},{"label":"MariaDB","type":"hasLabel","value":true},{"label":"Integrations Pod General","type":"hasLabel","value":true},{"label":"SMTP plugin","type":"hasLabel","value":true},{"label":"Oracle SQL DB","type":"hasLabel","value":true},{"label":"Query filter","type":"hasLabel","value":true},{"label":"Activation - datasources","type":"hasLabel","value":true},{"label":"REST API","type":"hasLabel","value":true},{"label":"REST API","type":"hasLabel","value":true},{"label":"Datasources","type":"hasLabel","value":true},{"label":"REST API plugin","type":"hasLabel","value":true},{"label":"Prepared statements","type":"hasLabel","value":true},{"label":"Query Generation","type":"hasLabel","value":true},{"label":"Core Query Execution","type":"hasLabel","value":true},{"label":"Query Management","type":"hasLabel","value":true},{"label":"Query Settings","type":"hasLabel","value":true},{"label":"Query performance","type":"hasLabel","value":true},{"label":"Datatype issue","type":"hasLabel","value":true},{"label":"SmartSubstitution","type":"hasLabel","value":true},{"label":"Suggested Widgets","type":"hasLabel","value":true},{"label":"SAAS Plugins","type":"hasLabel","value":true},{"label":"Reconnect DS modal","type":"hasLabel","value":true},{"label":"OnPageLoad","type":"hasLabel","value":true},{"label":"File upload issues","type":"hasLabel","value":true},{"label":"AI","type":"hasLabel","value":true},{"label":"Appsmith AI","type":"hasLabel","value":true},{"label":"Database Schema","type":"hasLabel","value":true}],"requires":1},"Identity & Authentication Product":{"conditions":[{"label":"Login / Signup","type":"hasLabel","value":true},{"label":"SSO","type":"hasLabel","value":true},{"label":"SCIM","type":"hasLabel","value":true},{"label":"Email verification","type":"hasLabel","value":true}],"requires":1},"Artifact Platform Product":{"conditions":[{"label":"Fork App","type":"hasLabel","value":true},{"label":"Publish App","type":"hasLabel","value":true},{"label":"Secret Management","type":"hasLabel","value":true},{"label":"Import-Export-App","type":"hasLabel","value":true}],"requires":1},"DevOps Pod":{"conditions":[{"label":"Docker","type":"hasLabel","value":true},{"label":"Super Admin","type":"hasLabel","value":true},{"label":"Deployment","type":"hasLabel","value":true},{"label":"K8s","type":"hasLabel","value":true},{"label":"Email Config","type":"hasLabel","value":true},{"label":"Backup & Restore","type":"hasLabel","value":true},{"label":"AWS AMI","type":"hasLabel","value":true},{"label":"Observability","type":"hasLabel","value":true},{"label":"Heroku","type":"hasLabel","value":true},{"label":"New Deployment Mode","type":"hasLabel","value":true},{"label":"Supervisor","type":"hasLabel","value":true},{"label":"Deployment Certificates","type":"hasLabel","value":true},{"label":"Mock Data","type":"hasLabel","value":true},{"label":"AWS ECS","type":"hasLabel","value":true},{"label":"Ingress","type":"hasLabel","value":true},{"label":"Nginx","type":"hasLabel","value":true},{"label":"Setup Issues","type":"hasLabel","value":true}],"requires":1},"Performance Pod":{"conditions":[{"label":"Performance","type":"hasLabel","value":true},{"label":"Performance infra","type":"hasLabel","value":true}],"requires":1},"IDE Pod":{"conditions":[{"label":"Telemetry","type":"hasLabel","value":true},{"label":"i18n","type":"hasLabel","value":true},{"label":"IDE Product","type":"hasLabel","value":true},{"label":"App setting","type":"hasLabel","value":true},{"label":"Debugger Product","type":"hasLabel","value":true},{"label":"Embedding Apps Product","type":"hasLabel","value":true}],"requires":1},"Platform Administration Pod":{"conditions":[{"label":"Airgap","type":"hasLabel","value":true},{"label":"Enterprise Edition","type":"hasLabel","value":true},{"label":"Invite flow","type":"hasLabel","value":true},{"label":"User Profile","type":"hasLabel","value":true},{"label":"User Session ","type":"hasLabel","value":true},{"label":"User Session","type":"hasLabel","value":true},{"label":"Admin Settings Product","type":"hasLabel","value":true},{"label":"RBAC Product","type":"hasLabel","value":true},{"label":"Workspace Product","type":"hasLabel","value":true},{"label":"Branding Product","type":"hasLabel","value":true},{"label":"Audit Logs Product","type":"hasLabel","value":true},{"label":"Identity & Authentication Product","type":"hasLabel","value":true},{"label":"Billing & Licensing Product","type":"hasLabel","value":true},{"label":"Move to Postgres","type":"hasLabel","value":true}],"requires":1},"DB Infrastructure Pod":{"conditions":[],"requires":1},"Widgets & Accelerators Pod":{"conditions":[{"label":"Accelerators Product","type":"hasLabel","value":true},{"label":"Templates Product","type":"hasLabel","value":true},{"label":"Widgets Product","type":"hasLabel","value":true},{"label":"App Theming Product","type":"hasLabel","value":true}],"requires":1},"Packages Pod":{"conditions":[{"label":"Module creator","type":"hasLabel","value":true},{"label":"Module consumer","type":"hasLabel","value":true},{"label":"Package versioning","type":"hasLabel","value":true},{"label":"Convert to module","type":"hasLabel","value":true},{"label":"Query module","type":"hasLabel","value":true},{"label":"JS module","type":"hasLabel","value":true},{"label":"UI module","type":"hasLabel","value":true},{"label":"Packages Pod","type":"hasLabel","value":true}],"requires":1},"Workflows Pod":{"conditions":[{"label":"Workflows Product","type":"hasLabel","value":true}],"requires":1},"Query & JS Pod":{"conditions":[{"label":"Javascript Product","type":"hasLabel","value":true},{"label":"Onboarding Product","type":"hasLabel","value":true},{"label":"Integrations Product","type":"hasLabel","value":true},{"label":"Reconfigure Datasource Modal","type":"hasLabel","value":true}],"requires":1},"QA Pod":{"conditions":[{"label":"QA","type":"hasLabel","value":true},{"label":"Automation Test","type":"hasLabel","value":true},{"label":"TestGap","type":"hasLabel","value":true},{"label":"Automation failures","type":"hasLabel","value":true},{"label":"Needs automation","type":"hasLabel","value":true}],"requires":1},"Anvil POD":{"conditions":[{"label":"Checkbox Component","type":"hasLabel","value":true},{"label":"WDS team","type":"hasLabel","value":true},{"label":"Anvil POD","type":"hasLabel","value":true},{"label":"WDS - all widgets","type":"hasLabel","value":true},{"label":"WDS - input widget","type":"hasLabel","value":true},{"label":"WDS - paragraph widget","type":"hasLabel","value":true},{"label":"WDS - statbox widget","type":"hasLabel","value":true},{"label":"WDS - modal widget","type":"hasLabel","value":true},{"label":"WDS - icon widget","type":"hasLabel","value":true},{"label":"WDS - checkbox widget","type":"hasLabel","value":true},{"label":"WDS - table widget","type":"hasLabel","value":true},{"label":"WDS - keyValue widget","type":"hasLabel","value":true},{"label":"WDS - switch group widget","type":"hasLabel","value":true},{"label":"WDS - theming","type":"hasLabel","value":true},{"label":"Anvil layout","type":"hasLabel","value":true},{"label":"Anvil - theming","type":"hasLabel","value":true},{"label":"Anvil - vertical alignment","type":"hasLabel","value":true},{"label":"Anvil - layout component","type":"hasLabel","value":true},{"label":"Anvil - drag & drop","type":"hasLabel","value":true},{"label":"Anvil - zones & sections","type":"hasLabel","value":true},{"label":"Anvil - copy paste experience","type":"hasLabel","value":true},{"label":"WDS - phone widget","type":"hasLabel","value":true},{"label":"WDS - responsive widget","type":"hasLabel","value":true},{"label":"Anvil - responsive viewport","type":"hasLabel","value":true},{"label":"WDS - widget styling","type":"hasLabel","value":true},{"label":"Anvil - spacing","type":"hasLabel","value":true},{"label":"Anvil - responsive canvas","type":"hasLabel","value":true},{"label":"WDS - inline button widget","type":"hasLabel","value":true},{"label":"Anvil team","type":"hasLabel","value":true}],"requires":1},"Activation Pod":{"conditions":[{"label":"Activation","type":"hasLabel","value":true}],"requires":1},"Stability Pod":{"conditions":[{"label":"Stability Issue","type":"hasLabel","value":true},{"label":"cypress-flaky-fix","type":"hasLabel","value":true},{"label":"Cypress flaky tests","type":"hasLabel","value":true}],"requires":1},"Documentation Pod":{"conditions":[{"label":"Documentation","type":"hasLabel","value":true}],"requires":1},"Packages & Git Pod":{"conditions":[{"label":"Packages Pod","type":"hasLabel","value":true},{"label":"Git Product","type":"hasLabel","value":true},{"label":"Packages Product","type":"hasLabel","value":true},{"label":"Git Platform","type":"hasLabel","value":true}],"requires":1},"Git Platform":{"conditions":[{"label":"Environments Product","type":"hasLabel","value":true},{"label":"Artifact Platform Product","type":"hasLabel","value":true}],"requires":1}}},"root":"."}],"labels":{"Tab Widget":{"color":"e2c76c","name":"Tab Widget","description":""},"Dont merge":{"color":"ADB39C","name":"Dont merge","description":""},"Epic":{"color":"3E4B9E","name":"Epic","description":"A zenhub epic that describes a project"},"Menu Button Widget":{"color":"235708","name":"Menu Button Widget","description":"Issues related to Menu Button widget"},"Checkbox Group widget":{"color":"bbeecd","name":"Checkbox Group widget","description":"Issues related to Checkbox Group Widget"},"Input Widget":{"color":"ae65d8","name":"Input Widget","description":""},"Security":{"color":"99139C","name":"Security","description":""},"QA":{"color":"","name":"QA","description":"Needs QA attention"},"Verified":{"color":"9bf416","name":"Verified","description":""},"Wont Fix":{"color":"ffffff","name":"Wont Fix","description":"This will not be worked on"},"MySQL":{"color":"c9ddc6","name":"MySQL","description":"Issues related to MySQL plugin"},"Development":{"color":"9F8A02","name":"Development","description":""},"Help Wanted":{"color":"008672","name":"Help Wanted","description":"Extra attention is needed"},"Home Page":{"color":"","name":"Home Page","description":"Issues related to the application home page"},"Rating Widget":{"color":"235708","name":"Rating Widget","description":"Issues related to the rating widget"},"Stat Box Widget":{"color":"f1c9ce","name":"Stat Box Widget","description":"Issues related to stat box"},"Enhancement":{"color":"a2eeef","name":"Enhancement","description":"New feature or request"},"Fork App":{"color":"af87c7","name":"Fork App","description":"Issues related to forking apps"},"Container Widget":{"color":"19AD0D","name":"Container Widget","description":"Container widget"},"Papercut":{"color":"B562F6","name":"Papercut","description":""},"Needs Design":{"color":"bfd4f2","name":"Needs Design","description":"needs design or changes to design"},"i18n":{"color":"1799b0","name":"i18n","description":"Represents issues that need to be tackled to handle internationalization"},"Rich Text Editor Widget":{"color":"f72cac","name":"Rich Text Editor Widget","description":""},"skip-changelog":{"color":"06086F","name":"skip-changelog","description":"Adding this label to a PR prevents it from being listed in the changelog"},"Low":{"color":"79e53b","name":"Low","description":"An issue that is neither critical nor breaks a user flow"},"potential-duplicate":{"color":"d3cb2e","name":"potential-duplicate","description":"This label marks issues that are potential duplicates of already open issues"},"Audio Widget":{"color":"447B9A","name":"Audio Widget","description":"Issues related to Audio Widget"},"Firestore":{"color":"8078b0","name":"Firestore","description":"Issues related to the firestore Integration"},"New Widget":{"color":"be4cf2","name":"New Widget","description":"A request for a new widget"},"Modal Widget":{"color":"03846f","name":"Modal Widget","description":""},"UX Improvement":{"color":"f4a089","name":"UX Improvement","description":""},"S3":{"color":"8078b0","name":"S3","description":"Issues related to the S3 plugin"},"Release Blocker":{"color":"5756bf","name":"Release Blocker","description":"This issue must be resolved before the release"},"safari":{"color":"51C6AA","name":"safari","description":"Bugs seen on safari browser"},"Example Apps":{"color":"1799b0","name":"Example Apps","description":"Example apps created for new signups"},"MultiSelect Widget":{"color":"AB62D4","name":"MultiSelect Widget","description":"Issues related to MultiSelect Widget"},"Calendar Widget":{"color":"8c6644","name":"Calendar Widget","description":""},"Website":{"color":"151720","name":"Website","description":"Related to www.appsmith.com website"},"Low effort":{"color":"8B59F0","name":"Low effort","description":"Something that'll take a few days to build"},"Checkbox Widget":{"color":"bbeecd","name":"Checkbox Widget","description":""},"Spam":{"color":"620faf","name":"Spam","description":""},"Voice Recorder Widget":{"color":"85bc87","name":"Voice Recorder Widget","description":""},"Select Widget":{"color":"0c669e","name":"Select Widget","description":"Select or dropdown widget"},"Bug":{"color":"8ba6fd","name":"Bug","description":"Something isn't right"},"Widget Validation":{"color":"6990BC","name":"Widget Validation","description":"Issues related to widget property validation"},"Generate Page":{"color":"2b4664","name":"Generate Page","description":"Issures related to page generation"},"File Picker Widget":{"color":"6ae4f2","name":"File Picker Widget","description":""},"snowflake":{"color":"8078b0","name":"snowflake","description":"Issues related to the snowflake Integration"},"Automation":{"color":"CCAF60","name":"Automation","description":""},"hotfix":{"color":"BA3F1D","name":"hotfix","description":""},"Import-Export-App":{"color":"48883f","name":"Import-Export-App","description":"Issues related to importing and exporting apps"},"High effort":{"color":"A7E87B","name":"High effort","description":"Something that'll take more than a month to build"},"Telemetry":{"color":"bc70f9","name":"Telemetry","description":"Issues related to instrumenting appsmith"},"Radio Widget":{"color":"91ef15","name":"Radio Widget","description":""},"Omnibar":{"color":"1bb96a","name":"Omnibar","description":"Issues related to the omnibar for navigation"},"Button Widget":{"color":"34efae","name":"Button Widget","description":""},"Switch widget":{"color":"33A8CE","name":"Switch widget","description":"The switch widget"},"Map Widget":{"color":"7eef7a","name":"Map Widget","description":""},"Task":{"color":"085630","name":"Task","description":"A simple Todo"},"Design System":{"color":"2958a4","name":"Design System","description":"Design system"},"opera":{"color":"C63F5B","name":"opera","description":"Any issues identified on the opera browser"},"Login / Signup":{"color":"","name":"Login / Signup","description":"Authentication flows"},"Image Widget":{"color":"8de8ad","name":"Image Widget","description":""},"firefox":{"color":"6d56e2","name":"firefox","description":""},"Property Pane":{"color":"b356ff","name":"Property Pane","description":"Issues related to the behaviour of the property pane"},"Deployment":{"color":"93491f","name":"Deployment","description":"Installation process of appsmith"},"Production":{"color":"b60205","name":"Production","description":""},"Dependencies":{"color":"0366d6","name":"Dependencies","description":"Pull requests that update a dependency file"},"Google Sheets":{"color":"8078b0","name":"Google Sheets","description":"Issues related to Google Sheets"},"Icon Button Widget":{"color":"D319CE","name":"Icon Button Widget","description":"Issues related to the icon button widget"},"Mongo":{"color":"8078b0","name":"Mongo","description":"Issues related to Mongo DB plugin"},"Documentation":{"color":"a8dff7","name":"Documentation","description":"Improvements or additions to documentation"},"TestGap":{"color":"","name":"TestGap","description":"Issues identified for test plan improvement"},"keyboard shortcut":{"color":"0688B6","name":"keyboard shortcut","description":""},"Reopen":{"color":"897548","name":"Reopen","description":""},"Redshift":{"color":"8078b0","name":"Redshift","description":"Issues related to the redshift integration"},"Date Picker Widget":{"color":"ef1ce1","name":"Date Picker Widget","description":""},"Entity Explorer":{"color":"1bb96a","name":"Entity Explorer","description":"Issues related to navigation using the entity explorer"},"JS Linting & Errors":{"color":"E56AA5","name":"JS Linting & Errors","description":"Issues related to JS Linting and errors"},"iFrame":{"color":"3CD1DB","name":"iFrame","description":"Issues related to iFrame"},"Stale":{"color":"ededed","name":"Stale","description":null},"Text Widget":{"color":"d130d1","name":"Text Widget","description":""},"Video Widget":{"color":"23dd4b","name":"Video Widget","description":""},"Datasources":{"color":"3d590f","name":"Datasources","description":"Issues related to configuring datasource on appsmith"},"error":{"color":"B66773","name":"error","description":"All issues connected to error messages"},"Form Widget":{"color":"09ed77","name":"Form Widget","description":""},"Needs Triaging":{"color":"e8b851","name":"Needs Triaging","description":"Needs attention from maintainers to triage"},"Autocomplete":{"color":"235708","name":"Autocomplete","description":"Issues related to the autocomplete"},"hacktoberfest":{"color":"0052cc","name":"hacktoberfest","description":"All issues that can be solved by the community during Hacktoberfest"},"Medium effort":{"color":"D31156","name":"Medium effort","description":"Something that'll take more than a week but less than a month to build"},"Release":{"color":"57e5e0","name":"Release","description":""},"High":{"color":"c94d14","name":"High","description":"This issue blocks a user from building or impacts a lot of users"},"UI Performance":{"color":"1799b0","name":"UI Performance","description":"Issues related to UI performance"},"Deploy Preview":{"color":"bfdadc","name":"Deploy Preview","description":"Issues found in Deploy Preview"},"Needs Tests":{"color":"8ee263","name":"Needs Tests","description":"Needs automated tests to assert a feature/bug fix"},"Refactor":{"color":"B96662","name":"Refactor","description":"needs refactoring of code"},"Divider Widget":{"color":"235708","name":"Divider Widget","description":"Issues related to the divider widget"},"Table Widget":{"color":"2eead1","name":"Table Widget","description":""},"Needs More Info":{"color":"e54c10","name":"Needs More Info","description":"Needs additional information"},"Good First Issue":{"color":"7057ff","name":"Good First Issue","description":"Good for newcomers"},"UI Improvement":{"color":"9aeef4","name":"UI Improvement","description":""},"Backend":{"color":"d4c5f9","name":"Backend","description":"This marks the issue or pull request to reference server code"},"Frontend":{"color":"87c7f2","name":"Frontend","description":"This label marks the issue or pull request to reference client code"},"Chart Widget":{"color":"616ecc","name":"Chart Widget","description":""},"List Widget":{"color":"8508A0","name":"List Widget","description":"Issues related to the list widget"},"Duplicate":{"color":"cfd3d7","name":"Duplicate","description":"This issue or pull request already exists"},"JS Snippets":{"color":"8d62d2","name":"JS Snippets","description":"issues related to JS Snippets"},"Copy Paste":{"name":"Copy Paste","description":"Issues related to copy paste","color":"b4f0a9"},"Drag & Drop":{"name":"Drag & Drop","description":"Issues related to the drag & drop experience","color":"92115a"},"Sniping Mode":{"name":"Sniping Mode","description":"Issues related to sniping mode","color":"48883f"},"Redis":{"name":"Redis","description":"Issues related to Redis","color":"8078b0"},"New Datasource":{"color":"60b14c","name":"New Datasource","description":"Requests for new datasources"},"Evaluated Value":{"name":"Evaluated Value","description":"Issues related to evaluated values","color":"39f6e7"},"Undo/Redo":{"name":"Undo/Redo","description":"Issues related to undo/redo","color":"f25880"},"App Navigation":{"name":"App Navigation","description":"Issues related to the topbar navigation and configuring it","color":"4773ab"},"Widgets Pane":{"name":"Widgets Pane","description":"Issues related to the discovery and organisation of widgets","color":"ad5d78"},"View Mode":{"color":"1799b0","name":"View Mode","description":"Issues related to the view mode"},"Content":{"name":"Content","description":"For content related topics i.e blogs, templates, videos","color":"a8dff7"},"Slash Command":{"name":"Slash Command","description":"Issues related to the slash command","color":"a0608e"},"Widget Property":{"name":"Widget Property","description":"Issues related to adding / modifying widget properties across widgets","color":"5e92cb"},"Windows":{"name":"Windows","description":"Issues related exclusively to Windows systems","color":"b4cb8a"},"Old App Issues":{"name":"Old App Issues","description":"Issues related to apps old apps a few weeks old and app issues in stale browser session","color":"87ab18"},"Document Viewer Widget":{"name":"Document Viewer Widget","description":"Issues related to Document Viewer Widget","color":"899d4b"},"Radio Group Widget":{"name":"Radio Group Widget","description":"Issues related to radio group widget","color":"b68495"},"Super Admin":{"name":"Super Admin","description":"Issues related to the super admin page","color":"aa95cf"},"Postgres":{"name":"Postgres","description":"Postgres related issues","color":"8078b0"},"New JS Function":{"name":"New JS Function","description":"Issues related to adding a JS Function","color":"8e8aa4"},"Cannot Reproduce Issue":{"color":"93c9cc","name":"Cannot Reproduce Issue","description":"Issues that cannot be reproduced"},"Widget Grouping":{"name":"Widget Grouping","description":"Issues related to Widget Grouping","color":"a49951"},"K8s":{"name":"K8s","description":"Kubernetes related issues","color":"5f318a"},"Docker":{"name":"Docker","description":"Issues related to docker","color":"89b808"},"Camera Widget":{"name":"Camera Widget","description":"Issues and enhancements related to camera widget","color":"e6038e"},"SAAS Plugins":{"name":"SAAS Plugins","description":"Issues related to SAAS Plugins","color":"80e18f"},"JS Promises":{"name":"JS Promises","description":"Issues related to promises","color":"d7771f"},"OnPageLoad":{"name":"OnPageLoad","description":"OnPageLoad issues on functions and queries","color":"2b4664"},"JS Usability":{"name":"JS Usability","description":"usability issues with JS editor and JS elsewhere","color":"a302b0"},"Currency Input Widget":{"name":"Currency Input Widget","description":"Issues related to currency input widget","color":"b2164f"},"TreeSelect":{"name":"TreeSelect","description":"Issues related to TreeSelect Widget","color":"a1633e"},"MultiTree Select Widget":{"name":"MultiTree Select Widget","description":"Issues related to MultiTree Select Widget","color":"a1633e"},"Welcome Screen":{"name":"Welcome Screen","description":"Issues related to the welcome screen","color":"48883f"},"Realtime Commenting":{"color":"a70b86","name":"Realtime Commenting","description":"In-app communication between teams"},"Phone Input Widget":{"name":"Phone Input Widget","description":"Issues related to the Phone Input widget","color":"a70b86"},"JSON Form":{"name":"JSON Form","description":"Issue / features related to the JSON form wiget","color":"46b209"},"All Widgets":{"name":"All Widgets","description":"Issues related to all widgets","color":"972b36"},"V1":{"name":"V1","description":"V1","color":"67ab2e"},"Reflow & Resize":{"name":"Reflow & Resize","description":"All issues related to reflow and resize experience","color":"748a13"},"SSO":{"name":"SSO","description":"Issues, requests and enhancements around Single sign-on.","color":""},"Multi User Realtime":{"name":"Multi User Realtime","description":"Issues related to multiple users using or editing an application","color":"e7b6ce"},"Ready for design":{"name":"Ready for design","description":"this issue is ready for design: it contains clear problem statements and other required information","color":"ebf442"},"Support":{"name":"Support","description":"Issues created by the A-force team to address user queries","color":"1740f3"},"Button Group widget":{"name":"Button Group widget","description":"Issue and enhancements related to the button group widget","color":"f17025"},"GraphQL Plugin":{"name":"GraphQL Plugin","description":"Issues related to GraphQL plugin","color":"8078b0"},"DevOps Pod":{"name":"DevOps Pod","description":"Issues related to devops","color":"d956c7"},"medium":{"name":"medium","description":"Issues that frustrate users due to poor UX","color":"23dfd9"},"ArangoDB":{"name":"ArangoDB","description":"Issues related to arangoDB","color":"8078b0"},"Code Refactoring":{"name":"Code Refactoring","description":"Issues related to code refactoring","color":"76310e"},"Progress bar widget":{"name":"Progress bar widget","description":"To track issues related to progress bar","color":"2d7abf"},"Audio Recorder Widget":{"name":"Audio Recorder Widget","description":"Issues related to Audio Recorder Widget","color":"9accef"},"Airtable":{"name":"Airtable","description":"Issues for Airtable","color":"60885f"},"Canvas / Grid":{"name":"Canvas / Grid","description":"Issues related to the canvas","color":"16b092"},"Email Config":{"name":"Email Config","description":"Issues related to configuring the email service","color":"2a21d1"},"CURL":{"name":"CURL","description":"Issues related to CURL impor","color":"60885f"},"Canvas Zooms":{"name":"Canvas Zooms","description":"Issues related to zooming the canvas","color":"e6038e"},"business":{"name":"business","description":"Features that will be a part of our business edition","color":"cd59eb"},"Action Pod":{"name":"Action Pod","description":"","color":"ee2e36"},"AutomationGap1":{"color":"a5e07c","name":"AutomationGap1","description":"Issues that needs automated tests"},"A-Force11":{"name":"A-Force11","description":"Issues raised by A-Force team","color":"d667b6"},"Business Edition":{"name":"Business Edition","description":"Features that will be a part of our business edition","color":"89bb6c"},"storeValue":{"name":"storeValue","description":"Issues related to the store value function","color":"5d3e66"},"DynamoDB":{"name":"DynamoDB","description":"Issues that are related to DynamoDB should have this label","color":"60885f"},"Backup & Restore":{"name":"Backup & Restore","description":"Issues related to backup and restore","color":"86874d"},"Billing":{"name":"Billing","description":"Billing infrastructure and flows for Business Edition and Trial users","color":"d2bc40"},"Datatype issue":{"name":"Datatype issue","description":"Issues that have risen because data types weren't handled","color":"cef66b"},"OAuth":{"name":"OAuth","description":"OAuth related bugs or features","color":"60885f"},"Table Widget V2":{"name":"Table Widget V2","description":"Issues related to Table Widget V2","color":"3a7192"},"IDE Navigation":{"name":"IDE Navigation","description":"Issues/feature requests related to IDE navigation, and context switching","color":"1bb96a"},"Query performance":{"name":"Query performance","description":"Issues that have to do with lack in performance of query execution","color":"cef66b"},"SAAS Manager App":{"name":"SAAS Manager App","description":"Issues with the SAAS manager app","color":"d427db"},"Twilio":{"name":"Twilio","description":"Issues related to Twilio integration","color":"23ba8d"},"Hubspot":{"name":"Hubspot","description":"Issues related to Hubspot integration","color":"60885f"},"Zendesk":{"name":"Zendesk","description":"Issues related to Zendesk integration","color":"60885f"},"Entity Refactor":{"name":"Entity Refactor","description":"Issues related to refactor logic","color":"705a2c"},"Map Chart Widget":{"name":"Map Chart Widget","description":"Issues related to Map Chart Widgets","color":"c8397f"},"Product Catchup":{"name":"Product Catchup","description":"Issues created in the product catchup","color":"29cd2c"},"Framework Functions":{"name":"Framework Functions","description":"Issues related to internal functions like showAlert(), navigateTo() etc...","color":"c25a09"},"Frontend Libraries Upgrade":{"name":"Frontend Libraries Upgrade","description":"Issues related to frontend libraries upgrade","color":"ede1fc"},"MsSQL":{"name":"MsSQL","description":"Issues related to MsSQL plugin","color":"8078b0"},"Elastic Search":{"name":"Elastic Search","description":"Issues related to the elastic search datasource","color":"8078b0"},"Core Query Execution":{"color":"cef66b","name":"Core Query Execution","description":"Issues related to the execution of all queries"},"Query Management":{"name":"Query Management","description":"Issues related to the CRUD of actions or queries","color":"cef66b"},"Query Settings":{"name":"Query Settings","description":"Issues related to the settings of all queries","color":"cef66b"},"Code Editor":{"name":"Code Editor","description":"Issues related to the code editor","color":"4ca16e"},"Query Forms":{"color":"12b253","name":"Query Forms","description":"Isuses related to the query forms"},"JS Objects":{"color":"22962c","name":"JS Objects","description":"Issues related to JS Objects"},"JS Evaluation":{"color":"22962c","name":"JS Evaluation","description":"Issues related to JS evaluation on the platform"},"SmartSubstitution":{"name":"SmartSubstitution","description":"Issues related to Smart substitution of mustache bindings in queries","color":"bae511"},"Query Generation":{"name":"Query Generation","description":"Issues related to query generation","color":"cef66b"},"Suggested Widgets":{"name":"Suggested Widgets","description":"Issues related to suggesting widgets based on query response","color":"6ac063"},"Code Scanner Widget":{"name":"Code Scanner Widget","description":"Issues related to code scanner widget","color":"9bc1a0"},"Clean URLs":{"name":"Clean URLs","description":"Issues related to clean URLs epic","color":"112623"},"Widget keyboard accessibility":{"name":"Widget keyboard accessibility","description":"All issues related to keyboard accessibility in widgets","color":"b626fd"},"Connection pool":{"name":"Connection pool","description":"issues to do with connection pooling of various plugins","color":"94fe36"},"List Widget V2":{"name":"List Widget V2","description":"Issues related to the list widget v2","color":"adaaf7"},"Auto Height":{"name":"Auto Height","description":"Issues related to dynamic height of widgets","color":"5149cf"},"cypress_failed_test":{"name":"cypress_failed_test","description":"Cypress failed tests","color":"4745d5"},"Needs validation":{"name":"Needs validation","description":"Needs problem validation before being picked up","color":"66673d"},"Slider Widget":{"name":"Slider Widget","description":"Issues raised for slider widgets.","color":"2eef5f"},"Multitenancy":{"name":"Multitenancy","description":"Support multitenancy within single appsmith instance","color":"8c49a9"},"Conversion Algorithm":{"name":"Conversion Algorithm","description":"All issue related to converting app from fixed to flex mode & vice versa","color":"d12d2e"},"Browser specific":{"name":"Browser specific","description":"All issue related to browser","color":"d12d2e"},"Performance infra":{"name":"Performance infra","description":"all issue related to the performance infra","color":"8a60f6"},"DSL Update":{"name":"DSL Update","description":"Issues related to storing and updating the DSL","color":"e16cf3"},"AST-frontend":{"name":"AST-frontend","description":"Issues related to maintaining AST logic","color":"2b4664"},"AST-backend":{"name":"AST-backend","description":"Backend issues related to AST parsing","color":"48883f"},"MariaDB":{"name":"MariaDB","description":"MariaDB datasource","color":"8428c3"},"ADS Component Issue":{"name":"ADS Component Issue","description":"Issues which are caused due to ADS components","color":"d89119"},"Regressed":{"color":"723fd0","name":"Regressed","description":"Scenarios that were working before but have now regressed"},"Needs RCA":{"name":"Needs RCA","description":"a critical or high priority issue that needs an RCA","color":"2cc68f"},"Custom JS Libraries":{"name":"Custom JS Libraries","description":"Issues related to adding custom JS library","color":"bacb6d"},"Integrations Pod General":{"name":"Integrations Pod General","description":"Issues related to the Integrations Pod that don't fit into other tags.","color":"287823"},"Performance Pod":{"name":"Performance Pod","description":"All things related to Appsmith performance","color":"b5a25d"},"Performance":{"name":"Performance","description":"Issues related to performance","color":"9a18d7"},"File upload issues":{"name":"File upload issues","description":"Issues related to uploading any type of files from within Appsmith","color":"2b4664"},"Action Selector":{"name":"Action Selector","description":"Issues related to action selector on the property pane","color":"2f9e20"},"Community Reported":{"name":"Community Reported","description":"issues reported by community members","color":"1402e5"},"JS Function execution":{"name":"JS Function execution","description":"JS function execution","color":"7c2de1"},"Self Serve":{"name":"Self Serve","description":"For all issues related to self-serve flow for business edition","color":"4dacfc"},"Self Serve 1.0":{"name":"Self Serve 1.0","description":"For all issues related to v1 of the self serve project","color":"ae839e"},"Customer Portal":{"name":"Customer Portal","description":"For all tasks/issues pertaining to customer.appsmith.com","color":"d2bc40"},"Cloud Services":{"name":"Cloud Services","description":"For all tasks/issues on Appsmith cloud-services relating to licensing, usage and billing","color":"d2bc40"},"One-click Binding":{"name":"One-click Binding","description":"Issues related to the One click binding epic","color":"f1661c"},"Airgap":{"name":"Airgap","description":"Tickets related to supporting air-gapped Appsmith instances","color":"1cb294"},"SMTP plugin":{"name":"SMTP plugin","description":"Issues related to SMTP plugin","color":"541457"},"AWS AMI":{"name":"AWS AMI","description":"Issues Related to AWS AMI","color":"b44680"},"Old widget version":{"name":"Old widget version","description":"Use this label to raise issue specific only to an older version of a widget","color":"ff3814"},"Enterprise Billing":{"name":"Enterprise Billing","description":"To track all tasks/issues related to licensing & billing for enterprise customers","color":"14c156"},"Oracle SQL DB":{"name":"Oracle SQL DB","description":"Issues related to the Oracle plugin","color":"cbabcb"},"Community Contributor":{"name":"Community Contributor","description":"Meant to track issues that are assigned to external contributors","color":"149ab6"},"widget vertical alignment":{"name":"widget vertical alignment","description":"All issue related widget vertical alignment on the auto layout canvas","color":"d12d2e"},"Observability":{"name":"Observability","description":"Issues related to observability on the Appsmith instance","color":"dff913"},"Checkbox Component":{"name":"Checkbox Component","description":"This labels deals with checkbox component in wds package","color":"75a401"},"Analytics Improvements":{"name":"Analytics Improvements","description":"For all tasks focused on improving our overall analytics and fixing any issues ","color":"29b8ed"},"WDS team":{"name":"WDS team","description":"","color":"8d675a"},"Enterprise Edition":{"name":"Enterprise Edition","description":"Features that will be supported in Enterprise Edition only","color":"984f5e"},"Query filter":{"name":"Query filter","description":"Issues related to query filtering, e.g., WHERE clause","color":"a15134"},"Keyboard accessibility ":{"name":"Keyboard accessibility ","description":"All issue related to ADS component keyboard accessibility","color":"2ba696"},"Toggle button":{"name":"Toggle button","description":"All issue related to ADS toggle button","color":"edc47f"},"SCIM":{"name":"SCIM","description":"Label to collate our SCIM issues","color":"48883f"},"ADS Category Token":{"name":"ADS Category Token","description":"All issues related appsmith design system category tokens","color":"920961"},"ADS Component Documentation":{"name":"ADS Component Documentation","description":"All issues Appsmith design system component documentation","color":"64c46a"},"ADS Migration":{"name":"ADS Migration","description":"All issues related to Appsmith design system migration","color":"b082d6"},"ADS Deduplication ":{"name":"ADS Deduplication ","description":"Replacing component with ADS components","color":"b082d6"},"ADS Revamp":{"name":"ADS Revamp","description":"All issues related to ads revamp. ","color":"b082d6"},"ADS Deduplication":{"name":"ADS Deduplication","description":"Replacing component with ADS components","color":"b082d6"},"ADS Grayscale":{"name":"ADS Grayscale","description":"Support grayscale color changes","color":"b03577"},"ADS Unit Test":{"name":"ADS Unit Test","description":"All issue related ads unit cases ","color":"b082d6"},"ADS Components":{"name":"ADS Components","description":"All issues related ADS components","color":"b082d6"},"Widget Discoverability":{"name":"Widget Discoverability","description":"Issues related to Widget Discoverability","color":"7b55ce"},"Widget setter method":{"name":"Widget setter method","description":"Issues with widget property setters","color":"8dce87"},"License":{"name":"License","description":"For all issues/tasks related to licensing of appsmith-ee edition","color":"90ee98"},"Platformization":{"name":"Platformization","description":"Issues or tasks related to platformization of Appsmith codebase","color":"4e972b"},"Activation - datasources":{"name":"Activation - datasources","description":"issues related to activation projects","color":"7c7ace"},"Partial-import-export":{"name":"Partial-import-export","description":"Label for granular reusability.","color":"717732"},"AI":{"name":"AI","description":"All tasks related to AI","color":"2b4664"},"ADS Typography":{"name":"ADS Typography","description":"All issue related typographical changes","color":"2dbe8d"},"Auto Layout":{"name":"Auto Layout","description":"Issues relates to auto layout","color":"92cf8c"},"Heroku":{"name":"Heroku","description":"Issues related to Heroku","color":"a81b69"},"ADS Visual Styles":{"name":"ADS Visual Styles","description":"All issues related to ADS visual styles","color":"d3da89"},"ADS Component Design":{"name":"ADS Component Design","description":"All issue related to component design","color":"5cc91e"},"Modal Component":{"name":"Modal Component","description":"All issue related to ads modal component","color":"ee63f3"},"App setting":{"name":"App setting","description":"Related to app settings panel within the app","color":"174f98"},"BE instance":{"name":"BE instance","description":"For all issues related to license, billing on BE instance","color":"ae8f98"},"Fixed layout":{"name":"Fixed layout","description":"issues related to fixed layout","color":"b66681"},"Anvil layout":{"name":"Anvil layout","description":"issues related to the new layout system anvil","color":"5e0904"},"New Deployment Mode":{"name":"New Deployment Mode","description":"Support a new mode of deployment","color":"108033"},"Custom widgets":{"name":"Custom widgets","description":"For all issues related to the custom widget project","color":"c9db9c"},"Homepage Experience V2":{"name":"Homepage Experience V2","description":"Label for reporting new tasks and bug fixes related to revamped homepage experience","color":"c55d54"},"Customer Success":{"name":"Customer Success","description":"Issues that the success team cares about","color":"6ccabd"},"Invite flow":{"name":"Invite flow","description":"Invite users flow and any associated actions","color":"881b35"},"Invite users":{"name":"Invite users","description":"Invite users flow and any associated actions","color":""},"Workflows Pod":{"name":"Workflows Pod","description":"Issues that the workflows team owns","color":"446925"},"DailyPromotionBlocker":{"name":"DailyPromotionBlocker","description":"DailyPromotion Blocker","color":"9b2280"},"JS Binding":{"name":"JS Binding","description":"All issues related to the JS Binding experience","color":"422fed"},"REST API":{"name":"REST API","description":"REST API plugin related issues","color":"e3ede5"},"Critical":{"color":"a1e3db","name":"Critical","description":"This issue breaks existing apps. Drop everything else to resolve"},"Module creator":{"name":"Module creator","description":"Issues related to the module creator side","color":"bb2c05"},"Module consumer":{"name":"Module consumer","description":"Issues related to the module consumer side","color":"83d3c5"},"Package versioning":{"name":"Package versioning","description":"ISsues related to how we manage versions for packages","color":"4c5218"},"Convert to module":{"name":"Convert to module","description":"Issues related to the module creation flow using conversion","color":"4c5218"},"Query module":{"name":"Query module","description":"Issues affecting query modules or its instances","color":"b11a7e"},"JS module":{"name":"JS module","description":"Issues affecting JS modules or its instances","color":"bf76f6"},"Secret Management":{"name":"Secret Management","description":"Issues related to secret management","color":"2b4664"},"REST API plugin":{"name":"REST API plugin","description":"REST API plugin related issues","color":"b5948a"},"UI module":{"name":"UI module","description":"Issues affecting UI modules or its instances","color":"d2acee"},"Preview mode":{"name":"Preview mode","description":"Issues related to app previews","color":"48883f"},"Git Auto-commit":{"name":"Git Auto-commit","description":"Issues related to autocommit","color":"717732"},"QA Pod":{"name":"QA Pod","description":"Issues under the QA Pod","color":"717732"},"Automation Test":{"name":"Automation Test","description":"","color":""},"Automation failures":{"name":"Automation failures","description":"","color":""},"Needs automation":{"name":"Needs automation","description":"Issues that needs automated tests","color":""},"Prepared statements":{"name":"Prepared statements","description":"Issues related to prepared statement flow","color":""},"Switch Group Widget":{"name":"Switch Group Widget","description":"Issues related to Switch group Widget","color":""},"Supervisor":{"name":"Supervisor","description":"Issues related to supervisor","color":"2c5813"},"Deployment Certificates":{"name":"Deployment Certificates","description":"Issues related to lets encrypt","color":"e148aa"},"Mock Data":{"name":"Mock Data","description":"Issues related to mock databases","color":"ebf251"},"AWS ECS":{"name":"AWS ECS","description":"Issues related to ECS Fargate","color":"e506ff"},"Publish App":{"name":"Publish App","description":"Issues related to app deployment","color":"2b4664"},"IDE Infra":{"name":"IDE Infra","description":"Issues related to the IDE infrastructure like saving changes","color":"1bb96a"},"User Profile":{"name":"User Profile","description":"Issues related to a user profile","color":"a60d34"},"Page Management":{"color":"1bb96a","name":"Page Management","description":"Issues related to configuring pages"},"Ingress":{"name":"Ingress","description":"Ingress Controller","color":"a86802"},"Nginx":{"name":"Nginx","description":"Issues related to Nginx","color":"e54195"},"Building blocks":{"name":"Building blocks","description":"Building blocks on cavas, on templates listing or drag and drop of building blocks.","color":"48883f"},"Table Inline Edit":{"name":"Table Inline Edit","description":"Issues related to inline editing","color":"60895a"},"User Session ":{"name":"User Session ","description":"For all issues/tasks related to user sessions","color":"65a3f5"},"WDS - all widgets":{"name":"WDS - all widgets","description":"all widget present in WDS","color":"2670ae"},"WDS - input widget":{"name":"WDS - input widget","description":"Issues related to input widget on WDS","color":"2670ae"},"WDS - paragraph widget":{"name":"WDS - paragraph widget","description":"issues related to paragraph widget on WDS","color":"2670ae"},"WDS - statbox widget":{"name":"WDS - statbox widget","description":"issues related to statbox widget on WDS","color":"2670ae"},"WDS - modal widget":{"name":"WDS - modal widget","description":"Issues related to modal widget on WDS","color":"2670ae"},"WDS - icon widget":{"name":"WDS - icon widget","description":"Issues related to icon widget on WDS","color":"2670ae"},"WDS - checkbox widget":{"name":"WDS - checkbox widget","description":"Issues related to checkbox widget on WDS","color":"2670ae"},"WDS - table widget":{"name":"WDS - table widget","description":"Issues related to table widget on WDS","color":"2670ae"},"WDS - keyValue widget":{"name":"WDS - keyValue widget","description":"Issues related to key-value widget on WDS","color":"2670ae"},"WDS - switch group widget":{"name":"WDS - switch group widget","description":"Issues related to switch group widget on WDS","color":"2670ae"},"WDS - theming":{"name":"WDS - theming","description":"Issues related to theming on the Anvil instance","color":"2670ae"},"Anvil POD":{"name":"Anvil POD","description":"Issue related to Anvil project","color":"5e0904"},"Anvil - theming":{"name":"Anvil - theming","description":"Issues related to theming on the Anvil instance","color":"c28de5"},"Anvil - vertical alignment":{"name":"Anvil - vertical alignment","description":"Issues related to vertical alignment on the Anvil layout","color":"c28de5"},"Anvil - layout component":{"name":"Anvil - layout component","description":"Issues related to layout component on the Anvil layout","color":"c28de5"},"Anvil - drag & drop":{"name":"Anvil - drag & drop","description":"Issues related to drag & drop experience on Anvil","color":"c28de5"},"Anvil - zones & sections":{"name":"Anvil - zones & sections","description":"Issues related to zones and sections on the Anvil layout","color":"c28de5"},"Anvil - copy paste experience":{"name":"Anvil - copy paste experience","description":"Issues related to copy paste experience on the Anvil layout","color":"c28de5"},"WDS - phone widget":{"name":"WDS - phone widget","description":"Issues related to phone widget on WDS","color":"c28de5"},"WDS - responsive widget":{"name":"WDS - responsive widget","description":"All issues related to widget responsiveness","color":"11ee05"},"Anvil - responsive viewport":{"color":"11ee05","name":"Anvil - responsive viewport","description":"Issues seen on different viewports like mobile"},"WDS - widget styling":{"color":"11ee05","name":"WDS - widget styling","description":"all about widget styling"},"Anvil - spacing":{"name":"Anvil - spacing","description":"Related to spacing between widgets in auto layout","color":"11ee05"},"Anvil - responsive canvas":{"name":"Anvil - responsive canvas","description":"All issues related to canvas responsiveness","color":"11ee05"},"WDS - inline button widget":{"name":"WDS - inline button widget","description":"Issues related to inline button widget on WDS","color":"7cef83"},"Activation Pod":{"name":"Activation Pod","description":"for Activation group","color":"d67d00"},"Activation":{"name":"Activation","description":"for Activation group","color":"d67d00"},"Tests":{"name":"Tests","description":"Test issues","color":"4fc7b6"},"Ballpark: XXS":{"name":"Ballpark: XXS","description":"~1xDev in 1/2xSprint","color":""},"Ballpark: XS":{"name":"Ballpark: XS","description":"~1xDev in 1xSprint","color":"53bf71"},"Ballpark: S":{"name":"Ballpark: S","description":"~2xDev in 1xSprint","color":"6e9e65"},"Ballpark: M":{"name":"Ballpark: M","description":"~1xPOD in 1xSprint","color":"2229e6"},"Ballpark: L":{"name":"Ballpark: L","description":"~1xPOD in 3xSprint or 2xPODs in 1xSprint","color":"49962f"},"Ballpark: XL":{"name":"Ballpark: XL","description":"~1xPOD in 1xQuarter or 2xPODs in 2xSprint","color":"b524c9"},"Ballpark: XXL":{"name":"Ballpark: XXL","description":"~2xPODs in 1xQuarter","color":"22092c"},"Auto-commit":{"name":"Auto-commit","description":"Issues related to auto-generated commits showing up on git ","color":"e25b89"},"Continuous Deployment":{"name":"Continuous Deployment","description":"Issues related to CD pipeline on git","color":"aea47c"},"Default branch":{"name":"Default branch","description":"Issues related to using a default branch on git","color":"195737"},"Git status":{"name":"Git status","description":"Issues related to information shown on git status modal or number of changes appearing in a branch","color":"c851b8"},"Git performance":{"name":"Git performance","description":"Issues related to perceived performance on any git operation","color":"189af6"},"Anvil team":{"name":"Anvil team","description":"issues related to the new layout system anvil","color":"798200"},"SDLC":{"name":"SDLC","description":"Issues related to software development lifecycle experiences","color":"bae511"},"Reconnect DS modal":{"name":"Reconnect DS modal","description":"Issues related to reconnect datasource modal post app import","color":"2e398b"},"Stability Pod":{"name":"Stability Pod","description":"For all issues/tasks to be prioritized under Stability pod","color":"86ddf6"},"Stability Issue":{"name":"Stability Issue","description":"Every issue handle by Stability Pod","color":"4d024a"},"Move to Postgres":{"name":"Move to Postgres","description":"Issues required to be solved for the move to Postgres as repository layer","color":"466ab1"},"User Session":{"name":"User Session","description":"Issues related to user sessions","color":"8255e5"},"IDE tabs":{"name":"IDE tabs","description":"query and js tabs","color":"1bb96a"},"Inviting Contribution":{"name":"Inviting Contribution","description":"Issues that we would like contributions to","color":""},"cypress-flaky-fix":{"name":"cypress-flaky-fix","description":"This label is auto-added when a PR which only has Cypress fixes are merged to release","color":"722cbc"},"Cypress flaky tests":{"name":"Cypress flaky tests","description":"Test scripts that need to be fixed on Cypress by dev or SDET","color":"722cbc"},"Help enterprise":{"name":"Help enterprise","description":"Requested by Appsmith customers or prospects","color":"FF8C00"},"Learnability":{"name":"Learnability","description":"Issues affecting the product learnability, making the product harder for new users.","color":"800c2f"},"ADS Spacing":{"name":"ADS Spacing","description":"","color":"686ebb"},"ads unit test":{"name":"ads unit test","description":"All issue related ads unit cases","color":"686ebb"},"ads revamp":{"name":"ads revamp","description":"All issues related to ads revamp.","color":"686ebb"},"Javascript Product":{"color":"709a21","name":"Javascript Product","description":"Issues related to users writing javascript in appsmith"},"IDE Product":{"color":"1bb96a","name":"IDE Product","description":"Issues related to the IDE Product"},"IDE Pod":{"color":"1bb96a","name":"IDE Pod","description":"Issues that new developers face while exploring the IDE"},"Accelerators Product":{"name":"Accelerators Product","description":"Issues related to app building accelerators","color":"f3fce6"},"Templates Product":{"name":"Templates Product","description":"Issues related to Templates","color":"f3fce6"},"Design System Product":{"name":"Design System Product","description":"Appsmith design system related issues","color":"2b4664"},"ads deduplication":{"name":"ads deduplication","description":"Replacing component with ADS components","color":"708943"},"Admin Settings Product":{"color":"708943","name":"Admin Settings Product","description":"Issues in admin settings pages"},"Appsmith AI":{"name":"Appsmith AI","description":"All issues related to the Appsmith AI datasource","color":"708943"},"Query & JS Pod":{"color":"709a21","name":"Query & JS Pod","description":"Issues related to the query & JS Pod"},"RBAC Product":{"name":"RBAC Product","description":"Issues, requests and enhancements around RBAC.","color":""},"Workspace Product":{"name":"Workspace Product","description":"Issues related to workspaces","color":""},"CE Instance Usage":{"name":"CE Instance Usage","description":"For all issues relating to usage, licensing or billing on the CE instance","color":""},"Billing & Licensing Product":{"name":"Billing & Licensing Product","description":"Issues pertaining to licensing, billing and usage across self serve and enterprise customers","color":"466ab1"},"Platform Administration Pod":{"color":"446925","name":"Platform Administration Pod","description":"Issues related to platform administration & management"},"DB Infrastructure Pod":{"name":"DB Infrastructure Pod","description":"Pod to handle database infrastructure","color":"446925"},"Packages Product":{"name":"Packages Product","description":"Issues related to packages","color":"7e018f"},"Workflows Product":{"name":"Workflows Product","description":"Issues related to the workflows product","color":"446925"},"Debugger Product":{"color":"857f58","name":"Debugger Product","description":"Issues related to the debugger"},"Packages Pod":{"name":"Packages Pod","description":"issues that belong to the packages pod","color":"53742c"},"Environments Product":{"name":"Environments Product","description":"Issues related to datasource environments","color":"857f58"},"Custom Widgets":{"name":"Custom Widgets","description":"For all issues related to the custom widget project","color":"857f58"},"Branding Product":{"name":"Branding Product","description":"All issues under branding and whitelabelling appsmith ecosystem","color":"857f58"},"Widgets & Accelerators Pod":{"name":"Widgets & Accelerators Pod","description":"Issues related to widgets & Accelerators","color":"27496a"},"Widgets Product":{"name":"Widgets Product","description":"This label groups issues related to widgets","color":"f3fce6"},"App Theming Product":{"name":"App Theming Product","description":"Items that are related to the App level theming controls epic","color":"48883f"},"UI Building Product":{"color":"48883f","name":"UI Building Product","description":"Issues related to the UI Building experience"},"Onboarding Product":{"color":"48883f","name":"Onboarding Product","description":"Issues related to onboarding new developers"},"Database Schema":{"name":"Database Schema","description":"Issues related to database schema","color":"48883f"},"Git Product":{"color":"7e018f","name":"Git Product","description":"Issues related to version control product"},"Embedding Apps Product":{"name":"Embedding Apps Product","description":"Issues related to embedding","color":"48883f"},"Integrations Product":{"name":"Integrations Product","description":"Issues related to a specific integration","color":"b9f21c"},"Feature Flagging":{"name":"Feature Flagging","description":"Anything related feature flagging","color":"4574ae"},"Audit Logs Product":{"name":"Audit Logs Product","description":"Audit trails to ensure data security","color":"4574ae"},"Identity & Authentication Product":{"name":"Identity & Authentication Product","description":"Issues related to user identity & authentication","color":"4574ae"},"Email verification":{"name":"Email verification","description":"Email verification issues","color":"4574ae"},"Artifact Platform Product":{"name":"Artifact Platform Product","description":"Issues related to the application platform","color":"4574ae"},"Git IA":{"name":"Git IA","description":"Issues related to Git IA changes","color":"df8bd6"},"Documentation Pod":{"name":"Documentation Pod","description":"Issues related to user education","color":"8c8c02"},"Branch management":{"name":"Branch management","description":"Issues related to using a branch management on git","color":"ebe6af"},"Reconfigure Datasource Modal":{"name":"Reconfigure Datasource Modal","description":"Issues related to reconfigure DS modal that comes after importing applications","color":"5ac17b"},"Setup Issues":{"name":"Setup Issues","description":"Issues related to setting up appsmith","color":"3fc837"},"Packages & Git Pod":{"name":"Packages & Git Pod","description":"All issues belonging to Packages and Git","color":"46ac0e"},"Git Platform":{"name":"Git Platform","description":"Issues related to the git & the app platform","color":"c9ab80"},"Entity Management":{"name":"Entity Management","description":"Copy / Move / Delete widgets / queries / datasources","color":"74c33c"}},"success":true} \ No newline at end of file +{"runners":[{"versioning":{"source":"milestones","type":"SemVer"},"prereleaseName":"alpha","issue":{"labels":{"Widgets Product":{"conditions":[{"label":"Button Widget","type":"hasLabel","value":true},{"label":"Chart Widget","type":"hasLabel","value":true},{"label":"Container Widget","type":"hasLabel","value":true},{"label":"Date Picker Widget","type":"hasLabel","value":true},{"label":"Select Widget","type":"hasLabel","value":true},{"label":"File Picker Widget","type":"hasLabel","value":true},{"label":"Form Widget","type":"hasLabel","value":true},{"label":"Image Widget","type":"hasLabel","value":true},{"label":"Input Widget","type":"hasLabel","value":true},{"label":"List Widget","type":"hasLabel","value":true},{"label":"MultiSelect Widget","type":"hasLabel","value":true},{"label":"Map Widget","type":"hasLabel","value":true},{"label":"Modal Widget","type":"hasLabel","value":true},{"label":"Radio Widget","type":"hasLabel","value":true},{"label":"Rich Text Editor Widget","type":"hasLabel","value":true},{"label":"Tab Widget","type":"hasLabel","value":true},{"label":"Table Widget","type":"hasLabel","value":true},{"label":"Text Widget","type":"hasLabel","value":true},{"label":"Video Widget","type":"hasLabel","value":true},{"label":"iFrame","type":"hasLabel","value":true},{"label":"Menu Button","type":"hasLabel","value":true},{"label":"Rating","type":"hasLabel","value":true},{"label":"Widget Validation","type":"hasLabel","value":true},{"label":"New Widget","type":"hasLabel","value":true},{"label":"Switch widget","type":"hasLabel","value":true},{"label":"Audio Widget","type":"hasLabel","value":true},{"label":"Icon Button Widget","type":"hasLabel","value":true},{"label":"Stat Box Widget","type":"hasLabel","value":true},{"label":"Voice Recorder Widget","type":"hasLabel","value":true},{"label":"Calendar Widget","type":"hasLabel","value":true},{"label":"Menu Button Widget","type":"hasLabel","value":true},{"label":"Divider Widget","type":"hasLabel","value":true},{"label":"Rating Widget","type":"hasLabel","value":true},{"label":"View Mode","type":"hasLabel","value":true},{"label":"Widget Property","type":"hasLabel","value":true},{"label":"Document Viewer Widget","type":"hasLabel","value":true},{"label":"Radio Group Widget","type":"hasLabel","value":true},{"label":"Currency Input Widget","type":"hasLabel","value":true},{"label":"TreeSelect","type":"hasLabel","value":true},{"label":"MultiTree Select Widget","type":"hasLabel","value":true},{"label":"Phone Input Widget","type":"hasLabel","value":true},{"label":"JSON Form","type":"hasLabel","value":true},{"label":"All Widgets","type":"hasLabel","value":true},{"label":"Button Group widget","type":"hasLabel","value":true},{"label":"Progress bar widget","type":"hasLabel","value":true},{"label":"Audio Recorder Widget","type":"hasLabel","value":true},{"label":"Camera Widget","type":"hasLabel","value":true},{"label":"Table Widget V2","type":"hasLabel","value":true},{"label":"Map Chart Widget","type":"hasLabel","value":true},{"label":"Code Scanner Widget","type":"hasLabel","value":true},{"label":"Widget keyboard accessibility","type":"hasLabel","value":true},{"label":"List Widget V2","type":"hasLabel","value":true},{"label":"Slider Widget","type":"hasLabel","value":true},{"label":"One-click Binding","type":"hasLabel","value":true},{"label":"Old widget version","type":"hasLabel","value":true},{"label":"Widget Discoverability","type":"hasLabel","value":true},{"label":"Switch Group Widget","type":"hasLabel","value":true},{"label":"Checkbox Group widget","type":"hasLabel","value":true},{"label":"Checkbox Widget","type":"hasLabel","value":true},{"label":"Table Inline Edit","type":"hasLabel","value":true},{"label":"Custom Widgets","type":"hasLabel","value":true}],"requires":1},"Javascript Product":{"conditions":[{"label":"JS Linting & Errors","type":"hasLabel","value":true},{"label":"Autocomplete","type":"hasLabel","value":true},{"label":"Evaluated Value","type":"hasLabel","value":true},{"label":"Slash Command","type":"hasLabel","value":true},{"label":"New JS Function","type":"hasLabel","value":true},{"label":"JS Usability","type":"hasLabel","value":true},{"label":"Framework Functions","type":"hasLabel","value":true},{"label":"JS Objects","type":"hasLabel","value":true},{"label":"JS Evaluation","type":"hasLabel","value":true},{"label":"Custom JS Libraries","type":"hasLabel","value":true},{"label":"Action Selector","type":"hasLabel","value":true},{"label":"Widget setter method","type":"hasLabel","value":true},{"label":"Entity Refactor","type":"hasLabel","value":true},{"label":"AST-frontend","type":"hasLabel","value":true},{"label":"Sniping Mode","type":"hasLabel","value":true},{"label":"AST-backend","type":"hasLabel","value":true}],"requires":1},"IDE Product":{"conditions":[{"label":"IDE Product","type":"hasLabel","value":true},{"label":"IDE Infra","type":"hasLabel","value":true},{"label":"IDE Navigation","type":"hasLabel","value":true},{"label":"IDE tabs","type":"hasLabel","value":true},{"label":"Omnibar","type":"hasLabel","value":true},{"label":"Entity Explorer","type":"hasLabel","value":true},{"label":"Page Management","type":"hasLabel","value":true},{"label":"Preview mode","type":"hasLabel","value":true},{"label":"Entity Management","type":"hasLabel","value":true}],"requires":1},"Accelerators Product":{"conditions":[{"label":"Generate Page","type":"hasLabel","value":true},{"label":"Building blocks","type":"hasLabel","value":true}],"requires":1},"Templates Product":{"conditions":[{"label":"Partial-import-export","type":"hasLabel","value":true},{"label":"Templates Product","type":"hasLabel","value":true}],"requires":1},"Design System Product":{"conditions":[{"label":"Design System Product","type":"hasLabel","value":true},{"label":"ADS Component Issue","type":"hasLabel","value":true},{"label":"Keyboard accessibility ","type":"hasLabel","value":true},{"label":"Toggle button","type":"hasLabel","value":true},{"label":"ADS Category Token","type":"hasLabel","value":true},{"label":"ADS Component Documentation","type":"hasLabel","value":true},{"label":"ADS Migration","type":"hasLabel","value":true},{"label":"ADS Deduplication ","type":"hasLabel","value":true},{"label":"ADS Revamp","type":"hasLabel","value":true},{"label":"ADS Deduplication","type":"hasLabel","value":true},{"label":"ADS Unit Test","type":"hasLabel","value":true},{"label":"ADS Components","type":"hasLabel","value":true},{"label":"ADS Grayscale","type":"hasLabel","value":true},{"label":"Design System","type":"hasLabel","value":true},{"label":"ADS Typography","type":"hasLabel","value":true},{"label":"ADS Visual Styles","type":"hasLabel","value":true},{"label":"ADS Component Design","type":"hasLabel","value":true},{"label":"Modal Component","type":"hasLabel","value":true},{"label":"ADS Spacing","type":"hasLabel","value":true},{"label":"ads unit test","type":"hasLabel","value":true},{"label":"ads revamp","type":"hasLabel","value":true},{"label":"ads deduplication","type":"hasLabel","value":true}],"requires":1},"RBAC Product":{"conditions":[{"label":"Invite users","type":"hasLabel","value":true},{"label":"RBAC Product","type":"hasLabel","value":true}],"requires":1},"Workspace Product":{"conditions":[{"label":"Home Page","type":"hasLabel","value":true},{"label":"Workspace Product","type":"hasLabel","value":true}],"requires":1},"Billing & Licensing Product":{"conditions":[{"label":"Customer Portal","type":"hasLabel","value":true},{"label":"Cloud Services","type":"hasLabel","value":true},{"label":"Billing","type":"hasLabel","value":true},{"label":"Self Serve","type":"hasLabel","value":true},{"label":"Enterprise Billing","type":"hasLabel","value":true},{"label":"Analytics Improvements","type":"hasLabel","value":true},{"label":"Self Serve 1.0","type":"hasLabel","value":true},{"label":"License","type":"hasLabel","value":true},{"label":"BE instance","type":"hasLabel","value":true},{"label":"Invite flow","type":"hasLabel","value":true},{"label":"CE Instance Usage","type":"hasLabel","value":true},{"label":"Feature Flagging","type":"hasLabel","value":true}],"requires":1},"Packages Product":{"conditions":[{"label":"Packages Product","type":"hasLabel","value":true}],"requires":1},"Environments Product":{"conditions":[{"label":"Environments Product","type":"hasLabel","value":true}],"requires":1},"UI Building Product":{"conditions":[{"label":"Property Pane","type":"hasLabel","value":true},{"label":"Copy Paste","type":"hasLabel","value":true},{"label":"Drag & Drop","type":"hasLabel","value":true},{"label":"Undo/Redo","type":"hasLabel","value":true},{"label":"Widgets Pane","type":"hasLabel","value":true},{"label":"UI Performance","type":"hasLabel","value":true},{"label":"Widget Grouping","type":"hasLabel","value":true},{"label":"Reflow & Resize","type":"hasLabel","value":true},{"label":"Canvas / Grid","type":"hasLabel","value":true},{"label":"Auto Height","type":"hasLabel","value":true},{"label":"Browser specific","type":"hasLabel","value":true},{"label":"Auto Layout","type":"hasLabel","value":true},{"label":"Fixed layout","type":"hasLabel","value":true},{"label":"App Navigation","type":"hasLabel","value":true}],"requires":1},"Onboarding Product":{"conditions":[{"label":"Welcome Screen","type":"hasLabel","value":true}],"requires":1},"Git Product":{"conditions":[{"label":"Git Product","type":"hasLabel","value":true},{"label":"Git Auto-commit","type":"hasLabel","value":true},{"label":"Auto-commit","type":"hasLabel","value":true},{"label":"Continuous Deployment","type":"hasLabel","value":true},{"label":"Default branch","type":"hasLabel","value":true},{"label":"Git status","type":"hasLabel","value":true},{"label":"Git performance","type":"hasLabel","value":true},{"label":"SDLC","type":"hasLabel","value":true},{"label":"Git IA","type":"hasLabel","value":true},{"label":"Branch management","type":"hasLabel","value":true}],"requires":1},"Embedding Apps Product":{"conditions":[{"label":"Embedding Apps Product","type":"hasLabel","value":true}],"requires":1},"Integrations Product":{"conditions":[{"label":"New Datasource","type":"hasLabel","value":true},{"label":"Firestore","type":"hasLabel","value":true},{"label":"Google Sheets","type":"hasLabel","value":true},{"label":"Mongo","type":"hasLabel","value":true},{"label":"Redshift","type":"hasLabel","value":true},{"label":"snowflake","type":"hasLabel","value":true},{"label":"S3","type":"hasLabel","value":true},{"label":"Redis","type":"hasLabel","value":true},{"label":"Postgres","type":"hasLabel","value":true},{"label":"GraphQL Plugin","type":"hasLabel","value":true},{"label":"ArangoDB","type":"hasLabel","value":true},{"label":"MsSQL","type":"hasLabel","value":true},{"label":"Elastic Search","type":"hasLabel","value":true},{"label":"OAuth","type":"hasLabel","value":true},{"label":"Airtable","type":"hasLabel","value":true},{"label":"CURL","type":"hasLabel","value":true},{"label":"DynamoDB","type":"hasLabel","value":true},{"label":"Zendesk","type":"hasLabel","value":true},{"label":"Hubspot","type":"hasLabel","value":true},{"label":"Query Forms","type":"hasLabel","value":true},{"label":"Twilio","type":"hasLabel","value":true},{"label":"MySQL","type":"hasLabel","value":true},{"label":"Connection pool","type":"hasLabel","value":true},{"label":"MariaDB","type":"hasLabel","value":true},{"label":"Integrations Pod General","type":"hasLabel","value":true},{"label":"SMTP plugin","type":"hasLabel","value":true},{"label":"Oracle SQL DB","type":"hasLabel","value":true},{"label":"Query filter","type":"hasLabel","value":true},{"label":"Activation - datasources","type":"hasLabel","value":true},{"label":"REST API","type":"hasLabel","value":true},{"label":"REST API","type":"hasLabel","value":true},{"label":"Datasources","type":"hasLabel","value":true},{"label":"REST API plugin","type":"hasLabel","value":true},{"label":"Prepared statements","type":"hasLabel","value":true},{"label":"Query Generation","type":"hasLabel","value":true},{"label":"Core Query Execution","type":"hasLabel","value":true},{"label":"Query Management","type":"hasLabel","value":true},{"label":"Query Settings","type":"hasLabel","value":true},{"label":"Query performance","type":"hasLabel","value":true},{"label":"Datatype issue","type":"hasLabel","value":true},{"label":"SmartSubstitution","type":"hasLabel","value":true},{"label":"Suggested Widgets","type":"hasLabel","value":true},{"label":"SAAS Plugins","type":"hasLabel","value":true},{"label":"Reconnect DS modal","type":"hasLabel","value":true},{"label":"OnPageLoad","type":"hasLabel","value":true},{"label":"File upload issues","type":"hasLabel","value":true},{"label":"AI","type":"hasLabel","value":true},{"label":"Appsmith AI","type":"hasLabel","value":true},{"label":"Database Schema","type":"hasLabel","value":true}],"requires":1},"Identity & Authentication Product":{"conditions":[{"label":"Login / Signup","type":"hasLabel","value":true},{"label":"SSO","type":"hasLabel","value":true},{"label":"SCIM","type":"hasLabel","value":true},{"label":"Email verification","type":"hasLabel","value":true}],"requires":1},"Artifact Platform Product":{"conditions":[{"label":"Fork App","type":"hasLabel","value":true},{"label":"Publish App","type":"hasLabel","value":true},{"label":"Secret Management","type":"hasLabel","value":true},{"label":"Import-Export-App","type":"hasLabel","value":true}],"requires":1},"DevOps Pod":{"conditions":[{"label":"Docker","type":"hasLabel","value":true},{"label":"Super Admin","type":"hasLabel","value":true},{"label":"Deployment","type":"hasLabel","value":true},{"label":"K8s","type":"hasLabel","value":true},{"label":"Email Config","type":"hasLabel","value":true},{"label":"Backup & Restore","type":"hasLabel","value":true},{"label":"AWS AMI","type":"hasLabel","value":true},{"label":"Observability","type":"hasLabel","value":true},{"label":"Heroku","type":"hasLabel","value":true},{"label":"New Deployment Mode","type":"hasLabel","value":true},{"label":"Supervisor","type":"hasLabel","value":true},{"label":"Deployment Certificates","type":"hasLabel","value":true},{"label":"Mock Data","type":"hasLabel","value":true},{"label":"AWS ECS","type":"hasLabel","value":true},{"label":"Ingress","type":"hasLabel","value":true},{"label":"Nginx","type":"hasLabel","value":true},{"label":"Setup Issues","type":"hasLabel","value":true}],"requires":1},"Performance Pod":{"conditions":[{"label":"Performance","type":"hasLabel","value":true},{"label":"Performance infra","type":"hasLabel","value":true}],"requires":1},"IDE Pod":{"conditions":[{"label":"Telemetry","type":"hasLabel","value":true},{"label":"i18n","type":"hasLabel","value":true},{"label":"IDE Product","type":"hasLabel","value":true},{"label":"App setting","type":"hasLabel","value":true},{"label":"Debugger Product","type":"hasLabel","value":true},{"label":"Embedding Apps Product","type":"hasLabel","value":true}],"requires":1},"Platform Administration Pod":{"conditions":[{"label":"Airgap","type":"hasLabel","value":true},{"label":"Enterprise Edition","type":"hasLabel","value":true},{"label":"Invite flow","type":"hasLabel","value":true},{"label":"User Profile","type":"hasLabel","value":true},{"label":"User Session ","type":"hasLabel","value":true},{"label":"User Session","type":"hasLabel","value":true},{"label":"Admin Settings Product","type":"hasLabel","value":true},{"label":"RBAC Product","type":"hasLabel","value":true},{"label":"Workspace Product","type":"hasLabel","value":true},{"label":"Branding Product","type":"hasLabel","value":true},{"label":"Audit Logs Product","type":"hasLabel","value":true},{"label":"Identity & Authentication Product","type":"hasLabel","value":true},{"label":"Billing & Licensing Product","type":"hasLabel","value":true},{"label":"Move to Postgres","type":"hasLabel","value":true}],"requires":1},"DB Infrastructure Pod":{"conditions":[],"requires":1},"Widgets & Accelerators Pod":{"conditions":[{"label":"Accelerators Product","type":"hasLabel","value":true},{"label":"Templates Product","type":"hasLabel","value":true},{"label":"Widgets Product","type":"hasLabel","value":true},{"label":"App Theming Product","type":"hasLabel","value":true}],"requires":1},"Packages Pod":{"conditions":[{"label":"Module creator","type":"hasLabel","value":true},{"label":"Module consumer","type":"hasLabel","value":true},{"label":"Package versioning","type":"hasLabel","value":true},{"label":"Convert to module","type":"hasLabel","value":true},{"label":"Query module","type":"hasLabel","value":true},{"label":"JS module","type":"hasLabel","value":true},{"label":"UI module","type":"hasLabel","value":true},{"label":"Packages Pod","type":"hasLabel","value":true}],"requires":1},"Workflows Pod":{"conditions":[{"label":"Workflows Product","type":"hasLabel","value":true}],"requires":1},"Query & JS Pod":{"conditions":[{"label":"Javascript Product","type":"hasLabel","value":true},{"label":"Onboarding Product","type":"hasLabel","value":true},{"label":"Integrations Product","type":"hasLabel","value":true},{"label":"Reconfigure Datasource Modal","type":"hasLabel","value":true}],"requires":1},"QA Pod":{"conditions":[{"label":"QA","type":"hasLabel","value":true},{"label":"Automation Test","type":"hasLabel","value":true},{"label":"TestGap","type":"hasLabel","value":true},{"label":"Automation failures","type":"hasLabel","value":true},{"label":"Needs automation","type":"hasLabel","value":true},{"label":"cypress-flaky-fix","type":"hasLabel","value":true}],"requires":1},"Anvil POD":{"conditions":[{"label":"Checkbox Component","type":"hasLabel","value":true},{"label":"WDS team","type":"hasLabel","value":true},{"label":"Anvil POD","type":"hasLabel","value":true},{"label":"WDS - all widgets","type":"hasLabel","value":true},{"label":"WDS - input widget","type":"hasLabel","value":true},{"label":"WDS - paragraph widget","type":"hasLabel","value":true},{"label":"WDS - statbox widget","type":"hasLabel","value":true},{"label":"WDS - modal widget","type":"hasLabel","value":true},{"label":"WDS - icon widget","type":"hasLabel","value":true},{"label":"WDS - checkbox widget","type":"hasLabel","value":true},{"label":"WDS - table widget","type":"hasLabel","value":true},{"label":"WDS - keyValue widget","type":"hasLabel","value":true},{"label":"WDS - switch group widget","type":"hasLabel","value":true},{"label":"WDS - theming","type":"hasLabel","value":true},{"label":"Anvil layout","type":"hasLabel","value":true},{"label":"Anvil - theming","type":"hasLabel","value":true},{"label":"Anvil - vertical alignment","type":"hasLabel","value":true},{"label":"Anvil - layout component","type":"hasLabel","value":true},{"label":"Anvil - drag & drop","type":"hasLabel","value":true},{"label":"Anvil - zones & sections","type":"hasLabel","value":true},{"label":"Anvil - copy paste experience","type":"hasLabel","value":true},{"label":"WDS - phone widget","type":"hasLabel","value":true},{"label":"WDS - responsive widget","type":"hasLabel","value":true},{"label":"Anvil - responsive viewport","type":"hasLabel","value":true},{"label":"WDS - widget styling","type":"hasLabel","value":true},{"label":"Anvil - spacing","type":"hasLabel","value":true},{"label":"Anvil - responsive canvas","type":"hasLabel","value":true},{"label":"WDS - inline button widget","type":"hasLabel","value":true},{"label":"Anvil team","type":"hasLabel","value":true}],"requires":1},"Activation Pod":{"conditions":[{"label":"Activation","type":"hasLabel","value":true}],"requires":1},"Stability Pod":{"conditions":[{"label":"Stability Issue","type":"hasLabel","value":true},{"label":"Cypress flaky tests","type":"hasLabel","value":true}],"requires":1},"Documentation Pod":{"conditions":[{"label":"Documentation","type":"hasLabel","value":true}],"requires":1},"Packages & Git Pod":{"conditions":[{"label":"Packages Pod","type":"hasLabel","value":true},{"label":"Git Product","type":"hasLabel","value":true},{"label":"Packages Product","type":"hasLabel","value":true},{"label":"Git Platform","type":"hasLabel","value":true}],"requires":1},"Git Platform":{"conditions":[{"label":"Environments Product","type":"hasLabel","value":true},{"label":"Artifact Platform Product","type":"hasLabel","value":true}],"requires":1}}},"root":"."}],"labels":{"Tab Widget":{"color":"e2c76c","name":"Tab Widget","description":""},"Dont merge":{"color":"ADB39C","name":"Dont merge","description":""},"Epic":{"color":"3E4B9E","name":"Epic","description":"A zenhub epic that describes a project"},"Menu Button Widget":{"color":"235708","name":"Menu Button Widget","description":"Issues related to Menu Button widget"},"Checkbox Group widget":{"color":"bbeecd","name":"Checkbox Group widget","description":"Issues related to Checkbox Group Widget"},"Input Widget":{"color":"ae65d8","name":"Input Widget","description":""},"Security":{"color":"99139C","name":"Security","description":""},"QA":{"color":"","name":"QA","description":"Needs QA attention"},"Verified":{"color":"9bf416","name":"Verified","description":""},"Wont Fix":{"color":"ffffff","name":"Wont Fix","description":"This will not be worked on"},"MySQL":{"color":"c9ddc6","name":"MySQL","description":"Issues related to MySQL plugin"},"Development":{"color":"9F8A02","name":"Development","description":""},"Help Wanted":{"color":"008672","name":"Help Wanted","description":"Extra attention is needed"},"Home Page":{"color":"","name":"Home Page","description":"Issues related to the application home page"},"Rating Widget":{"color":"235708","name":"Rating Widget","description":"Issues related to the rating widget"},"Stat Box Widget":{"color":"f1c9ce","name":"Stat Box Widget","description":"Issues related to stat box"},"Enhancement":{"color":"a2eeef","name":"Enhancement","description":"New feature or request"},"Fork App":{"color":"af87c7","name":"Fork App","description":"Issues related to forking apps"},"Container Widget":{"color":"19AD0D","name":"Container Widget","description":"Container widget"},"Papercut":{"color":"B562F6","name":"Papercut","description":""},"Needs Design":{"color":"bfd4f2","name":"Needs Design","description":"needs design or changes to design"},"i18n":{"color":"1799b0","name":"i18n","description":"Represents issues that need to be tackled to handle internationalization"},"Rich Text Editor Widget":{"color":"f72cac","name":"Rich Text Editor Widget","description":""},"skip-changelog":{"color":"06086F","name":"skip-changelog","description":"Adding this label to a PR prevents it from being listed in the changelog"},"Low":{"color":"79e53b","name":"Low","description":"An issue that is neither critical nor breaks a user flow"},"potential-duplicate":{"color":"d3cb2e","name":"potential-duplicate","description":"This label marks issues that are potential duplicates of already open issues"},"Audio Widget":{"color":"447B9A","name":"Audio Widget","description":"Issues related to Audio Widget"},"Firestore":{"color":"8078b0","name":"Firestore","description":"Issues related to the firestore Integration"},"New Widget":{"color":"be4cf2","name":"New Widget","description":"A request for a new widget"},"Modal Widget":{"color":"03846f","name":"Modal Widget","description":""},"UX Improvement":{"color":"f4a089","name":"UX Improvement","description":""},"S3":{"color":"8078b0","name":"S3","description":"Issues related to the S3 plugin"},"Release Blocker":{"color":"5756bf","name":"Release Blocker","description":"This issue must be resolved before the release"},"safari":{"color":"51C6AA","name":"safari","description":"Bugs seen on safari browser"},"Example Apps":{"color":"1799b0","name":"Example Apps","description":"Example apps created for new signups"},"MultiSelect Widget":{"color":"AB62D4","name":"MultiSelect Widget","description":"Issues related to MultiSelect Widget"},"Calendar Widget":{"color":"8c6644","name":"Calendar Widget","description":""},"Website":{"color":"151720","name":"Website","description":"Related to www.appsmith.com website"},"Low effort":{"color":"8B59F0","name":"Low effort","description":"Something that'll take a few days to build"},"Checkbox Widget":{"color":"bbeecd","name":"Checkbox Widget","description":""},"Spam":{"color":"620faf","name":"Spam","description":""},"Voice Recorder Widget":{"color":"85bc87","name":"Voice Recorder Widget","description":""},"Select Widget":{"color":"0c669e","name":"Select Widget","description":"Select or dropdown widget"},"Bug":{"color":"8ba6fd","name":"Bug","description":"Something isn't right"},"Widget Validation":{"color":"6990BC","name":"Widget Validation","description":"Issues related to widget property validation"},"Generate Page":{"color":"2b4664","name":"Generate Page","description":"Issures related to page generation"},"File Picker Widget":{"color":"6ae4f2","name":"File Picker Widget","description":""},"snowflake":{"color":"8078b0","name":"snowflake","description":"Issues related to the snowflake Integration"},"Automation":{"color":"CCAF60","name":"Automation","description":""},"hotfix":{"color":"BA3F1D","name":"hotfix","description":""},"Import-Export-App":{"color":"48883f","name":"Import-Export-App","description":"Issues related to importing and exporting apps"},"High effort":{"color":"A7E87B","name":"High effort","description":"Something that'll take more than a month to build"},"Telemetry":{"color":"bc70f9","name":"Telemetry","description":"Issues related to instrumenting appsmith"},"Radio Widget":{"color":"91ef15","name":"Radio Widget","description":""},"Omnibar":{"color":"1bb96a","name":"Omnibar","description":"Issues related to the omnibar for navigation"},"Button Widget":{"color":"34efae","name":"Button Widget","description":""},"Switch widget":{"color":"33A8CE","name":"Switch widget","description":"The switch widget"},"Map Widget":{"color":"7eef7a","name":"Map Widget","description":""},"Task":{"color":"085630","name":"Task","description":"A simple Todo"},"Design System":{"color":"2958a4","name":"Design System","description":"Design system"},"opera":{"color":"C63F5B","name":"opera","description":"Any issues identified on the opera browser"},"Login / Signup":{"color":"","name":"Login / Signup","description":"Authentication flows"},"Image Widget":{"color":"8de8ad","name":"Image Widget","description":""},"firefox":{"color":"6d56e2","name":"firefox","description":""},"Property Pane":{"color":"b356ff","name":"Property Pane","description":"Issues related to the behaviour of the property pane"},"Deployment":{"color":"93491f","name":"Deployment","description":"Installation process of appsmith"},"Production":{"color":"b60205","name":"Production","description":""},"Dependencies":{"color":"0366d6","name":"Dependencies","description":"Pull requests that update a dependency file"},"Google Sheets":{"color":"8078b0","name":"Google Sheets","description":"Issues related to Google Sheets"},"Icon Button Widget":{"color":"D319CE","name":"Icon Button Widget","description":"Issues related to the icon button widget"},"Mongo":{"color":"8078b0","name":"Mongo","description":"Issues related to Mongo DB plugin"},"Documentation":{"color":"a8dff7","name":"Documentation","description":"Improvements or additions to documentation"},"TestGap":{"color":"","name":"TestGap","description":"Issues identified for test plan improvement"},"keyboard shortcut":{"color":"0688B6","name":"keyboard shortcut","description":""},"Reopen":{"color":"897548","name":"Reopen","description":""},"Redshift":{"color":"8078b0","name":"Redshift","description":"Issues related to the redshift integration"},"Date Picker Widget":{"color":"ef1ce1","name":"Date Picker Widget","description":""},"Entity Explorer":{"color":"1bb96a","name":"Entity Explorer","description":"Issues related to navigation using the entity explorer"},"JS Linting & Errors":{"color":"E56AA5","name":"JS Linting & Errors","description":"Issues related to JS Linting and errors"},"iFrame":{"color":"3CD1DB","name":"iFrame","description":"Issues related to iFrame"},"Stale":{"color":"ededed","name":"Stale","description":null},"Text Widget":{"color":"d130d1","name":"Text Widget","description":""},"Video Widget":{"color":"23dd4b","name":"Video Widget","description":""},"Datasources":{"color":"3d590f","name":"Datasources","description":"Issues related to configuring datasource on appsmith"},"error":{"color":"B66773","name":"error","description":"All issues connected to error messages"},"Form Widget":{"color":"09ed77","name":"Form Widget","description":""},"Needs Triaging":{"color":"e8b851","name":"Needs Triaging","description":"Needs attention from maintainers to triage"},"Autocomplete":{"color":"235708","name":"Autocomplete","description":"Issues related to the autocomplete"},"hacktoberfest":{"color":"0052cc","name":"hacktoberfest","description":"All issues that can be solved by the community during Hacktoberfest"},"Medium effort":{"color":"D31156","name":"Medium effort","description":"Something that'll take more than a week but less than a month to build"},"Release":{"color":"57e5e0","name":"Release","description":""},"High":{"color":"c94d14","name":"High","description":"This issue blocks a user from building or impacts a lot of users"},"UI Performance":{"color":"1799b0","name":"UI Performance","description":"Issues related to UI performance"},"Deploy Preview":{"color":"bfdadc","name":"Deploy Preview","description":"Issues found in Deploy Preview"},"Needs Tests":{"color":"8ee263","name":"Needs Tests","description":"Needs automated tests to assert a feature/bug fix"},"Refactor":{"color":"B96662","name":"Refactor","description":"needs refactoring of code"},"Divider Widget":{"color":"235708","name":"Divider Widget","description":"Issues related to the divider widget"},"Table Widget":{"color":"2eead1","name":"Table Widget","description":""},"Needs More Info":{"color":"e54c10","name":"Needs More Info","description":"Needs additional information"},"Good First Issue":{"color":"7057ff","name":"Good First Issue","description":"Good for newcomers"},"UI Improvement":{"color":"9aeef4","name":"UI Improvement","description":""},"Backend":{"color":"d4c5f9","name":"Backend","description":"This marks the issue or pull request to reference server code"},"Frontend":{"color":"87c7f2","name":"Frontend","description":"This label marks the issue or pull request to reference client code"},"Chart Widget":{"color":"616ecc","name":"Chart Widget","description":""},"List Widget":{"color":"8508A0","name":"List Widget","description":"Issues related to the list widget"},"Duplicate":{"color":"cfd3d7","name":"Duplicate","description":"This issue or pull request already exists"},"JS Snippets":{"color":"8d62d2","name":"JS Snippets","description":"issues related to JS Snippets"},"Copy Paste":{"name":"Copy Paste","description":"Issues related to copy paste","color":"b4f0a9"},"Drag & Drop":{"name":"Drag & Drop","description":"Issues related to the drag & drop experience","color":"92115a"},"Sniping Mode":{"name":"Sniping Mode","description":"Issues related to sniping mode","color":"48883f"},"Redis":{"name":"Redis","description":"Issues related to Redis","color":"8078b0"},"New Datasource":{"color":"60b14c","name":"New Datasource","description":"Requests for new datasources"},"Evaluated Value":{"name":"Evaluated Value","description":"Issues related to evaluated values","color":"39f6e7"},"Undo/Redo":{"name":"Undo/Redo","description":"Issues related to undo/redo","color":"f25880"},"App Navigation":{"name":"App Navigation","description":"Issues related to the topbar navigation and configuring it","color":"4773ab"},"Widgets Pane":{"name":"Widgets Pane","description":"Issues related to the discovery and organisation of widgets","color":"ad5d78"},"View Mode":{"color":"1799b0","name":"View Mode","description":"Issues related to the view mode"},"Content":{"name":"Content","description":"For content related topics i.e blogs, templates, videos","color":"a8dff7"},"Slash Command":{"name":"Slash Command","description":"Issues related to the slash command","color":"a0608e"},"Widget Property":{"name":"Widget Property","description":"Issues related to adding / modifying widget properties across widgets","color":"5e92cb"},"Windows":{"name":"Windows","description":"Issues related exclusively to Windows systems","color":"b4cb8a"},"Old App Issues":{"name":"Old App Issues","description":"Issues related to apps old apps a few weeks old and app issues in stale browser session","color":"87ab18"},"Document Viewer Widget":{"name":"Document Viewer Widget","description":"Issues related to Document Viewer Widget","color":"899d4b"},"Radio Group Widget":{"name":"Radio Group Widget","description":"Issues related to radio group widget","color":"b68495"},"Super Admin":{"name":"Super Admin","description":"Issues related to the super admin page","color":"aa95cf"},"Postgres":{"name":"Postgres","description":"Postgres related issues","color":"8078b0"},"New JS Function":{"name":"New JS Function","description":"Issues related to adding a JS Function","color":"8e8aa4"},"Cannot Reproduce Issue":{"color":"93c9cc","name":"Cannot Reproduce Issue","description":"Issues that cannot be reproduced"},"Widget Grouping":{"name":"Widget Grouping","description":"Issues related to Widget Grouping","color":"a49951"},"K8s":{"name":"K8s","description":"Kubernetes related issues","color":"5f318a"},"Docker":{"name":"Docker","description":"Issues related to docker","color":"89b808"},"Camera Widget":{"name":"Camera Widget","description":"Issues and enhancements related to camera widget","color":"e6038e"},"SAAS Plugins":{"name":"SAAS Plugins","description":"Issues related to SAAS Plugins","color":"80e18f"},"JS Promises":{"name":"JS Promises","description":"Issues related to promises","color":"d7771f"},"OnPageLoad":{"name":"OnPageLoad","description":"OnPageLoad issues on functions and queries","color":"2b4664"},"JS Usability":{"name":"JS Usability","description":"usability issues with JS editor and JS elsewhere","color":"a302b0"},"Currency Input Widget":{"name":"Currency Input Widget","description":"Issues related to currency input widget","color":"b2164f"},"TreeSelect":{"name":"TreeSelect","description":"Issues related to TreeSelect Widget","color":"a1633e"},"MultiTree Select Widget":{"name":"MultiTree Select Widget","description":"Issues related to MultiTree Select Widget","color":"a1633e"},"Welcome Screen":{"name":"Welcome Screen","description":"Issues related to the welcome screen","color":"48883f"},"Realtime Commenting":{"color":"a70b86","name":"Realtime Commenting","description":"In-app communication between teams"},"Phone Input Widget":{"name":"Phone Input Widget","description":"Issues related to the Phone Input widget","color":"a70b86"},"JSON Form":{"name":"JSON Form","description":"Issue / features related to the JSON form wiget","color":"46b209"},"All Widgets":{"name":"All Widgets","description":"Issues related to all widgets","color":"972b36"},"V1":{"name":"V1","description":"V1","color":"67ab2e"},"Reflow & Resize":{"name":"Reflow & Resize","description":"All issues related to reflow and resize experience","color":"748a13"},"SSO":{"name":"SSO","description":"Issues, requests and enhancements around Single sign-on.","color":""},"Multi User Realtime":{"name":"Multi User Realtime","description":"Issues related to multiple users using or editing an application","color":"e7b6ce"},"Ready for design":{"name":"Ready for design","description":"this issue is ready for design: it contains clear problem statements and other required information","color":"ebf442"},"Support":{"name":"Support","description":"Issues created by the A-force team to address user queries","color":"1740f3"},"Button Group widget":{"name":"Button Group widget","description":"Issue and enhancements related to the button group widget","color":"f17025"},"GraphQL Plugin":{"name":"GraphQL Plugin","description":"Issues related to GraphQL plugin","color":"8078b0"},"DevOps Pod":{"name":"DevOps Pod","description":"Issues related to devops","color":"d956c7"},"medium":{"name":"medium","description":"Issues that frustrate users due to poor UX","color":"23dfd9"},"ArangoDB":{"name":"ArangoDB","description":"Issues related to arangoDB","color":"8078b0"},"Code Refactoring":{"name":"Code Refactoring","description":"Issues related to code refactoring","color":"76310e"},"Progress bar widget":{"name":"Progress bar widget","description":"To track issues related to progress bar","color":"2d7abf"},"Audio Recorder Widget":{"name":"Audio Recorder Widget","description":"Issues related to Audio Recorder Widget","color":"9accef"},"Airtable":{"name":"Airtable","description":"Issues for Airtable","color":"60885f"},"Canvas / Grid":{"name":"Canvas / Grid","description":"Issues related to the canvas","color":"16b092"},"Email Config":{"name":"Email Config","description":"Issues related to configuring the email service","color":"2a21d1"},"CURL":{"name":"CURL","description":"Issues related to CURL impor","color":"60885f"},"Canvas Zooms":{"name":"Canvas Zooms","description":"Issues related to zooming the canvas","color":"e6038e"},"business":{"name":"business","description":"Features that will be a part of our business edition","color":"cd59eb"},"Action Pod":{"name":"Action Pod","description":"","color":"ee2e36"},"AutomationGap1":{"color":"a5e07c","name":"AutomationGap1","description":"Issues that needs automated tests"},"A-Force11":{"name":"A-Force11","description":"Issues raised by A-Force team","color":"d667b6"},"Business Edition":{"name":"Business Edition","description":"Features that will be a part of our business edition","color":"89bb6c"},"storeValue":{"name":"storeValue","description":"Issues related to the store value function","color":"5d3e66"},"DynamoDB":{"name":"DynamoDB","description":"Issues that are related to DynamoDB should have this label","color":"60885f"},"Backup & Restore":{"name":"Backup & Restore","description":"Issues related to backup and restore","color":"86874d"},"Billing":{"name":"Billing","description":"Billing infrastructure and flows for Business Edition and Trial users","color":"d2bc40"},"Datatype issue":{"name":"Datatype issue","description":"Issues that have risen because data types weren't handled","color":"cef66b"},"OAuth":{"name":"OAuth","description":"OAuth related bugs or features","color":"60885f"},"Table Widget V2":{"name":"Table Widget V2","description":"Issues related to Table Widget V2","color":"3a7192"},"IDE Navigation":{"name":"IDE Navigation","description":"Issues/feature requests related to IDE navigation, and context switching","color":"1bb96a"},"Query performance":{"name":"Query performance","description":"Issues that have to do with lack in performance of query execution","color":"cef66b"},"SAAS Manager App":{"name":"SAAS Manager App","description":"Issues with the SAAS manager app","color":"d427db"},"Twilio":{"name":"Twilio","description":"Issues related to Twilio integration","color":"23ba8d"},"Hubspot":{"name":"Hubspot","description":"Issues related to Hubspot integration","color":"60885f"},"Zendesk":{"name":"Zendesk","description":"Issues related to Zendesk integration","color":"60885f"},"Entity Refactor":{"name":"Entity Refactor","description":"Issues related to refactor logic","color":"705a2c"},"Map Chart Widget":{"name":"Map Chart Widget","description":"Issues related to Map Chart Widgets","color":"c8397f"},"Product Catchup":{"name":"Product Catchup","description":"Issues created in the product catchup","color":"29cd2c"},"Framework Functions":{"name":"Framework Functions","description":"Issues related to internal functions like showAlert(), navigateTo() etc...","color":"c25a09"},"Frontend Libraries Upgrade":{"name":"Frontend Libraries Upgrade","description":"Issues related to frontend libraries upgrade","color":"ede1fc"},"MsSQL":{"name":"MsSQL","description":"Issues related to MsSQL plugin","color":"8078b0"},"Elastic Search":{"name":"Elastic Search","description":"Issues related to the elastic search datasource","color":"8078b0"},"Core Query Execution":{"color":"cef66b","name":"Core Query Execution","description":"Issues related to the execution of all queries"},"Query Management":{"name":"Query Management","description":"Issues related to the CRUD of actions or queries","color":"cef66b"},"Query Settings":{"name":"Query Settings","description":"Issues related to the settings of all queries","color":"cef66b"},"Code Editor":{"name":"Code Editor","description":"Issues related to the code editor","color":"4ca16e"},"Query Forms":{"color":"12b253","name":"Query Forms","description":"Isuses related to the query forms"},"JS Objects":{"color":"22962c","name":"JS Objects","description":"Issues related to JS Objects"},"JS Evaluation":{"color":"22962c","name":"JS Evaluation","description":"Issues related to JS evaluation on the platform"},"SmartSubstitution":{"name":"SmartSubstitution","description":"Issues related to Smart substitution of mustache bindings in queries","color":"bae511"},"Query Generation":{"name":"Query Generation","description":"Issues related to query generation","color":"cef66b"},"Suggested Widgets":{"name":"Suggested Widgets","description":"Issues related to suggesting widgets based on query response","color":"6ac063"},"Code Scanner Widget":{"name":"Code Scanner Widget","description":"Issues related to code scanner widget","color":"9bc1a0"},"Clean URLs":{"name":"Clean URLs","description":"Issues related to clean URLs epic","color":"112623"},"Widget keyboard accessibility":{"name":"Widget keyboard accessibility","description":"All issues related to keyboard accessibility in widgets","color":"b626fd"},"Connection pool":{"name":"Connection pool","description":"issues to do with connection pooling of various plugins","color":"94fe36"},"List Widget V2":{"name":"List Widget V2","description":"Issues related to the list widget v2","color":"adaaf7"},"Auto Height":{"name":"Auto Height","description":"Issues related to dynamic height of widgets","color":"5149cf"},"cypress_failed_test":{"name":"cypress_failed_test","description":"Cypress failed tests","color":"4745d5"},"Needs validation":{"name":"Needs validation","description":"Needs problem validation before being picked up","color":"66673d"},"Slider Widget":{"name":"Slider Widget","description":"Issues raised for slider widgets.","color":"2eef5f"},"Multitenancy":{"name":"Multitenancy","description":"Support multitenancy within single appsmith instance","color":"8c49a9"},"Conversion Algorithm":{"name":"Conversion Algorithm","description":"All issue related to converting app from fixed to flex mode & vice versa","color":"d12d2e"},"Browser specific":{"name":"Browser specific","description":"All issue related to browser","color":"d12d2e"},"Performance infra":{"name":"Performance infra","description":"all issue related to the performance infra","color":"8a60f6"},"DSL Update":{"name":"DSL Update","description":"Issues related to storing and updating the DSL","color":"e16cf3"},"AST-frontend":{"name":"AST-frontend","description":"Issues related to maintaining AST logic","color":"2b4664"},"AST-backend":{"name":"AST-backend","description":"Backend issues related to AST parsing","color":"48883f"},"MariaDB":{"name":"MariaDB","description":"MariaDB datasource","color":"8428c3"},"ADS Component Issue":{"name":"ADS Component Issue","description":"Issues which are caused due to ADS components","color":"d89119"},"Regressed":{"color":"723fd0","name":"Regressed","description":"Scenarios that were working before but have now regressed"},"Needs RCA":{"name":"Needs RCA","description":"a critical or high priority issue that needs an RCA","color":"2cc68f"},"Custom JS Libraries":{"name":"Custom JS Libraries","description":"Issues related to adding custom JS library","color":"bacb6d"},"Integrations Pod General":{"name":"Integrations Pod General","description":"Issues related to the Integrations Pod that don't fit into other tags.","color":"287823"},"Performance Pod":{"name":"Performance Pod","description":"All things related to Appsmith performance","color":"b5a25d"},"Performance":{"name":"Performance","description":"Issues related to performance","color":"9a18d7"},"File upload issues":{"name":"File upload issues","description":"Issues related to uploading any type of files from within Appsmith","color":"2b4664"},"Action Selector":{"name":"Action Selector","description":"Issues related to action selector on the property pane","color":"2f9e20"},"Community Reported":{"name":"Community Reported","description":"issues reported by community members","color":"1402e5"},"JS Function execution":{"name":"JS Function execution","description":"JS function execution","color":"7c2de1"},"Self Serve":{"name":"Self Serve","description":"For all issues related to self-serve flow for business edition","color":"4dacfc"},"Self Serve 1.0":{"name":"Self Serve 1.0","description":"For all issues related to v1 of the self serve project","color":"ae839e"},"Customer Portal":{"name":"Customer Portal","description":"For all tasks/issues pertaining to customer.appsmith.com","color":"d2bc40"},"Cloud Services":{"name":"Cloud Services","description":"For all tasks/issues on Appsmith cloud-services relating to licensing, usage and billing","color":"d2bc40"},"One-click Binding":{"name":"One-click Binding","description":"Issues related to the One click binding epic","color":"f1661c"},"Airgap":{"name":"Airgap","description":"Tickets related to supporting air-gapped Appsmith instances","color":"1cb294"},"SMTP plugin":{"name":"SMTP plugin","description":"Issues related to SMTP plugin","color":"541457"},"AWS AMI":{"name":"AWS AMI","description":"Issues Related to AWS AMI","color":"b44680"},"Old widget version":{"name":"Old widget version","description":"Use this label to raise issue specific only to an older version of a widget","color":"ff3814"},"Enterprise Billing":{"name":"Enterprise Billing","description":"To track all tasks/issues related to licensing & billing for enterprise customers","color":"14c156"},"Oracle SQL DB":{"name":"Oracle SQL DB","description":"Issues related to the Oracle plugin","color":"cbabcb"},"Community Contributor":{"name":"Community Contributor","description":"Meant to track issues that are assigned to external contributors","color":"149ab6"},"widget vertical alignment":{"name":"widget vertical alignment","description":"All issue related widget vertical alignment on the auto layout canvas","color":"d12d2e"},"Observability":{"name":"Observability","description":"Issues related to observability on the Appsmith instance","color":"dff913"},"Checkbox Component":{"name":"Checkbox Component","description":"This labels deals with checkbox component in wds package","color":"75a401"},"Analytics Improvements":{"name":"Analytics Improvements","description":"For all tasks focused on improving our overall analytics and fixing any issues ","color":"29b8ed"},"WDS team":{"name":"WDS team","description":"","color":"8d675a"},"Enterprise Edition":{"name":"Enterprise Edition","description":"Features that will be supported in Enterprise Edition only","color":"984f5e"},"Query filter":{"name":"Query filter","description":"Issues related to query filtering, e.g., WHERE clause","color":"a15134"},"Keyboard accessibility ":{"name":"Keyboard accessibility ","description":"All issue related to ADS component keyboard accessibility","color":"2ba696"},"Toggle button":{"name":"Toggle button","description":"All issue related to ADS toggle button","color":"edc47f"},"SCIM":{"name":"SCIM","description":"Label to collate our SCIM issues","color":"48883f"},"ADS Category Token":{"name":"ADS Category Token","description":"All issues related appsmith design system category tokens","color":"920961"},"ADS Component Documentation":{"name":"ADS Component Documentation","description":"All issues Appsmith design system component documentation","color":"64c46a"},"ADS Migration":{"name":"ADS Migration","description":"All issues related to Appsmith design system migration","color":"b082d6"},"ADS Deduplication ":{"name":"ADS Deduplication ","description":"Replacing component with ADS components","color":"b082d6"},"ADS Revamp":{"name":"ADS Revamp","description":"All issues related to ads revamp. ","color":"b082d6"},"ADS Deduplication":{"name":"ADS Deduplication","description":"Replacing component with ADS components","color":"b082d6"},"ADS Grayscale":{"name":"ADS Grayscale","description":"Support grayscale color changes","color":"b03577"},"ADS Unit Test":{"name":"ADS Unit Test","description":"All issue related ads unit cases ","color":"b082d6"},"ADS Components":{"name":"ADS Components","description":"All issues related ADS components","color":"b082d6"},"Widget Discoverability":{"name":"Widget Discoverability","description":"Issues related to Widget Discoverability","color":"7b55ce"},"Widget setter method":{"name":"Widget setter method","description":"Issues with widget property setters","color":"8dce87"},"License":{"name":"License","description":"For all issues/tasks related to licensing of appsmith-ee edition","color":"90ee98"},"Platformization":{"name":"Platformization","description":"Issues or tasks related to platformization of Appsmith codebase","color":"4e972b"},"Activation - datasources":{"name":"Activation - datasources","description":"issues related to activation projects","color":"7c7ace"},"Partial-import-export":{"name":"Partial-import-export","description":"Label for granular reusability.","color":"717732"},"AI":{"name":"AI","description":"All tasks related to AI","color":"2b4664"},"ADS Typography":{"name":"ADS Typography","description":"All issue related typographical changes","color":"2dbe8d"},"Auto Layout":{"name":"Auto Layout","description":"Issues relates to auto layout","color":"92cf8c"},"Heroku":{"name":"Heroku","description":"Issues related to Heroku","color":"a81b69"},"ADS Visual Styles":{"name":"ADS Visual Styles","description":"All issues related to ADS visual styles","color":"d3da89"},"ADS Component Design":{"name":"ADS Component Design","description":"All issue related to component design","color":"5cc91e"},"Modal Component":{"name":"Modal Component","description":"All issue related to ads modal component","color":"ee63f3"},"App setting":{"name":"App setting","description":"Related to app settings panel within the app","color":"174f98"},"BE instance":{"name":"BE instance","description":"For all issues related to license, billing on BE instance","color":"ae8f98"},"Fixed layout":{"name":"Fixed layout","description":"issues related to fixed layout","color":"b66681"},"Anvil layout":{"name":"Anvil layout","description":"issues related to the new layout system anvil","color":"5e0904"},"New Deployment Mode":{"name":"New Deployment Mode","description":"Support a new mode of deployment","color":"108033"},"Custom widgets":{"name":"Custom widgets","description":"For all issues related to the custom widget project","color":"c9db9c"},"Homepage Experience V2":{"name":"Homepage Experience V2","description":"Label for reporting new tasks and bug fixes related to revamped homepage experience","color":"c55d54"},"Customer Success":{"name":"Customer Success","description":"Issues that the success team cares about","color":"6ccabd"},"Invite flow":{"name":"Invite flow","description":"Invite users flow and any associated actions","color":"881b35"},"Invite users":{"name":"Invite users","description":"Invite users flow and any associated actions","color":""},"Workflows Pod":{"name":"Workflows Pod","description":"Issues that the workflows team owns","color":"446925"},"DailyPromotionBlocker":{"name":"DailyPromotionBlocker","description":"DailyPromotion Blocker","color":"9b2280"},"JS Binding":{"name":"JS Binding","description":"All issues related to the JS Binding experience","color":"422fed"},"REST API":{"name":"REST API","description":"REST API plugin related issues","color":"e3ede5"},"Critical":{"color":"a1e3db","name":"Critical","description":"This issue breaks existing apps. Drop everything else to resolve"},"Module creator":{"name":"Module creator","description":"Issues related to the module creator side","color":"bb2c05"},"Module consumer":{"name":"Module consumer","description":"Issues related to the module consumer side","color":"83d3c5"},"Package versioning":{"name":"Package versioning","description":"ISsues related to how we manage versions for packages","color":"4c5218"},"Convert to module":{"name":"Convert to module","description":"Issues related to the module creation flow using conversion","color":"4c5218"},"Query module":{"name":"Query module","description":"Issues affecting query modules or its instances","color":"b11a7e"},"JS module":{"name":"JS module","description":"Issues affecting JS modules or its instances","color":"bf76f6"},"Secret Management":{"name":"Secret Management","description":"Issues related to secret management","color":"2b4664"},"REST API plugin":{"name":"REST API plugin","description":"REST API plugin related issues","color":"b5948a"},"UI module":{"name":"UI module","description":"Issues affecting UI modules or its instances","color":"d2acee"},"Preview mode":{"name":"Preview mode","description":"Issues related to app previews","color":"48883f"},"Git Auto-commit":{"name":"Git Auto-commit","description":"Issues related to autocommit","color":"717732"},"QA Pod":{"name":"QA Pod","description":"Issues under the QA Pod","color":"717732"},"Automation Test":{"name":"Automation Test","description":"","color":""},"Automation failures":{"name":"Automation failures","description":"","color":""},"Needs automation":{"name":"Needs automation","description":"Issues that needs automated tests","color":""},"Prepared statements":{"name":"Prepared statements","description":"Issues related to prepared statement flow","color":""},"Switch Group Widget":{"name":"Switch Group Widget","description":"Issues related to Switch group Widget","color":""},"Supervisor":{"name":"Supervisor","description":"Issues related to supervisor","color":"2c5813"},"Deployment Certificates":{"name":"Deployment Certificates","description":"Issues related to lets encrypt","color":"e148aa"},"Mock Data":{"name":"Mock Data","description":"Issues related to mock databases","color":"ebf251"},"AWS ECS":{"name":"AWS ECS","description":"Issues related to ECS Fargate","color":"e506ff"},"Publish App":{"name":"Publish App","description":"Issues related to app deployment","color":"2b4664"},"IDE Infra":{"name":"IDE Infra","description":"Issues related to the IDE infrastructure like saving changes","color":"1bb96a"},"User Profile":{"name":"User Profile","description":"Issues related to a user profile","color":"a60d34"},"Page Management":{"color":"1bb96a","name":"Page Management","description":"Issues related to configuring pages"},"Ingress":{"name":"Ingress","description":"Ingress Controller","color":"a86802"},"Nginx":{"name":"Nginx","description":"Issues related to Nginx","color":"e54195"},"Building blocks":{"name":"Building blocks","description":"Building blocks on cavas, on templates listing or drag and drop of building blocks.","color":"48883f"},"Table Inline Edit":{"name":"Table Inline Edit","description":"Issues related to inline editing","color":"60895a"},"User Session ":{"name":"User Session ","description":"For all issues/tasks related to user sessions","color":"65a3f5"},"WDS - all widgets":{"name":"WDS - all widgets","description":"all widget present in WDS","color":"2670ae"},"WDS - input widget":{"name":"WDS - input widget","description":"Issues related to input widget on WDS","color":"2670ae"},"WDS - paragraph widget":{"name":"WDS - paragraph widget","description":"issues related to paragraph widget on WDS","color":"2670ae"},"WDS - statbox widget":{"name":"WDS - statbox widget","description":"issues related to statbox widget on WDS","color":"2670ae"},"WDS - modal widget":{"name":"WDS - modal widget","description":"Issues related to modal widget on WDS","color":"2670ae"},"WDS - icon widget":{"name":"WDS - icon widget","description":"Issues related to icon widget on WDS","color":"2670ae"},"WDS - checkbox widget":{"name":"WDS - checkbox widget","description":"Issues related to checkbox widget on WDS","color":"2670ae"},"WDS - table widget":{"name":"WDS - table widget","description":"Issues related to table widget on WDS","color":"2670ae"},"WDS - keyValue widget":{"name":"WDS - keyValue widget","description":"Issues related to key-value widget on WDS","color":"2670ae"},"WDS - switch group widget":{"name":"WDS - switch group widget","description":"Issues related to switch group widget on WDS","color":"2670ae"},"WDS - theming":{"name":"WDS - theming","description":"Issues related to theming on the Anvil instance","color":"2670ae"},"Anvil POD":{"name":"Anvil POD","description":"Issue related to Anvil project","color":"5e0904"},"Anvil - theming":{"name":"Anvil - theming","description":"Issues related to theming on the Anvil instance","color":"c28de5"},"Anvil - vertical alignment":{"name":"Anvil - vertical alignment","description":"Issues related to vertical alignment on the Anvil layout","color":"c28de5"},"Anvil - layout component":{"name":"Anvil - layout component","description":"Issues related to layout component on the Anvil layout","color":"c28de5"},"Anvil - drag & drop":{"name":"Anvil - drag & drop","description":"Issues related to drag & drop experience on Anvil","color":"c28de5"},"Anvil - zones & sections":{"name":"Anvil - zones & sections","description":"Issues related to zones and sections on the Anvil layout","color":"c28de5"},"Anvil - copy paste experience":{"name":"Anvil - copy paste experience","description":"Issues related to copy paste experience on the Anvil layout","color":"c28de5"},"WDS - phone widget":{"name":"WDS - phone widget","description":"Issues related to phone widget on WDS","color":"c28de5"},"WDS - responsive widget":{"name":"WDS - responsive widget","description":"All issues related to widget responsiveness","color":"11ee05"},"Anvil - responsive viewport":{"color":"11ee05","name":"Anvil - responsive viewport","description":"Issues seen on different viewports like mobile"},"WDS - widget styling":{"color":"11ee05","name":"WDS - widget styling","description":"all about widget styling"},"Anvil - spacing":{"name":"Anvil - spacing","description":"Related to spacing between widgets in auto layout","color":"11ee05"},"Anvil - responsive canvas":{"name":"Anvil - responsive canvas","description":"All issues related to canvas responsiveness","color":"11ee05"},"WDS - inline button widget":{"name":"WDS - inline button widget","description":"Issues related to inline button widget on WDS","color":"7cef83"},"Activation Pod":{"name":"Activation Pod","description":"for Activation group","color":"d67d00"},"Activation":{"name":"Activation","description":"for Activation group","color":"d67d00"},"Tests":{"name":"Tests","description":"Test issues","color":"4fc7b6"},"Ballpark: XXS":{"name":"Ballpark: XXS","description":"~1xDev in 1/2xSprint","color":""},"Ballpark: XS":{"name":"Ballpark: XS","description":"~1xDev in 1xSprint","color":"53bf71"},"Ballpark: S":{"name":"Ballpark: S","description":"~2xDev in 1xSprint","color":"6e9e65"},"Ballpark: M":{"name":"Ballpark: M","description":"~1xPOD in 1xSprint","color":"2229e6"},"Ballpark: L":{"name":"Ballpark: L","description":"~1xPOD in 3xSprint or 2xPODs in 1xSprint","color":"49962f"},"Ballpark: XL":{"name":"Ballpark: XL","description":"~1xPOD in 1xQuarter or 2xPODs in 2xSprint","color":"b524c9"},"Ballpark: XXL":{"name":"Ballpark: XXL","description":"~2xPODs in 1xQuarter","color":"22092c"},"Auto-commit":{"name":"Auto-commit","description":"Issues related to auto-generated commits showing up on git ","color":"e25b89"},"Continuous Deployment":{"name":"Continuous Deployment","description":"Issues related to CD pipeline on git","color":"aea47c"},"Default branch":{"name":"Default branch","description":"Issues related to using a default branch on git","color":"195737"},"Git status":{"name":"Git status","description":"Issues related to information shown on git status modal or number of changes appearing in a branch","color":"c851b8"},"Git performance":{"name":"Git performance","description":"Issues related to perceived performance on any git operation","color":"189af6"},"Anvil team":{"name":"Anvil team","description":"issues related to the new layout system anvil","color":"798200"},"SDLC":{"name":"SDLC","description":"Issues related to software development lifecycle experiences","color":"bae511"},"Reconnect DS modal":{"name":"Reconnect DS modal","description":"Issues related to reconnect datasource modal post app import","color":"2e398b"},"Stability Pod":{"name":"Stability Pod","description":"For all issues/tasks to be prioritized under Stability pod","color":"86ddf6"},"Stability Issue":{"name":"Stability Issue","description":"Every issue handle by Stability Pod","color":"4d024a"},"Move to Postgres":{"name":"Move to Postgres","description":"Issues required to be solved for the move to Postgres as repository layer","color":"466ab1"},"User Session":{"name":"User Session","description":"Issues related to user sessions","color":"8255e5"},"IDE tabs":{"name":"IDE tabs","description":"query and js tabs","color":"1bb96a"},"Inviting Contribution":{"name":"Inviting Contribution","description":"Issues that we would like contributions to","color":""},"cypress-flaky-fix":{"name":"cypress-flaky-fix","description":"This label is auto-added when a PR which only has Cypress fixes are merged to release","color":"cd8bb6"},"Cypress flaky tests":{"name":"Cypress flaky tests","description":"Test scripts that need to be fixed on Cypress by dev or SDET","color":"722cbc"},"Help enterprise":{"name":"Help enterprise","description":"Requested by Appsmith customers or prospects","color":"FF8C00"},"Learnability":{"name":"Learnability","description":"Issues affecting the product learnability, making the product harder for new users.","color":"800c2f"},"ADS Spacing":{"name":"ADS Spacing","description":"","color":"686ebb"},"ads unit test":{"name":"ads unit test","description":"All issue related ads unit cases","color":"686ebb"},"ads revamp":{"name":"ads revamp","description":"All issues related to ads revamp.","color":"686ebb"},"Javascript Product":{"color":"709a21","name":"Javascript Product","description":"Issues related to users writing javascript in appsmith"},"IDE Product":{"color":"1bb96a","name":"IDE Product","description":"Issues related to the IDE Product"},"IDE Pod":{"color":"1bb96a","name":"IDE Pod","description":"Issues that new developers face while exploring the IDE"},"Accelerators Product":{"name":"Accelerators Product","description":"Issues related to app building accelerators","color":"f3fce6"},"Templates Product":{"name":"Templates Product","description":"Issues related to Templates","color":"f3fce6"},"Design System Product":{"name":"Design System Product","description":"Appsmith design system related issues","color":"2b4664"},"ads deduplication":{"name":"ads deduplication","description":"Replacing component with ADS components","color":"708943"},"Admin Settings Product":{"color":"708943","name":"Admin Settings Product","description":"Issues in admin settings pages"},"Appsmith AI":{"name":"Appsmith AI","description":"All issues related to the Appsmith AI datasource","color":"708943"},"Query & JS Pod":{"color":"709a21","name":"Query & JS Pod","description":"Issues related to the query & JS Pod"},"RBAC Product":{"name":"RBAC Product","description":"Issues, requests and enhancements around RBAC.","color":""},"Workspace Product":{"name":"Workspace Product","description":"Issues related to workspaces","color":""},"CE Instance Usage":{"name":"CE Instance Usage","description":"For all issues relating to usage, licensing or billing on the CE instance","color":""},"Billing & Licensing Product":{"name":"Billing & Licensing Product","description":"Issues pertaining to licensing, billing and usage across self serve and enterprise customers","color":"466ab1"},"Platform Administration Pod":{"color":"446925","name":"Platform Administration Pod","description":"Issues related to platform administration & management"},"DB Infrastructure Pod":{"name":"DB Infrastructure Pod","description":"Pod to handle database infrastructure","color":"446925"},"Packages Product":{"name":"Packages Product","description":"Issues related to packages","color":"7e018f"},"Workflows Product":{"name":"Workflows Product","description":"Issues related to the workflows product","color":"446925"},"Debugger Product":{"color":"857f58","name":"Debugger Product","description":"Issues related to the debugger"},"Packages Pod":{"name":"Packages Pod","description":"issues that belong to the packages pod","color":"53742c"},"Environments Product":{"name":"Environments Product","description":"Issues related to datasource environments","color":"857f58"},"Custom Widgets":{"name":"Custom Widgets","description":"For all issues related to the custom widget project","color":"857f58"},"Branding Product":{"name":"Branding Product","description":"All issues under branding and whitelabelling appsmith ecosystem","color":"857f58"},"Widgets & Accelerators Pod":{"name":"Widgets & Accelerators Pod","description":"Issues related to widgets & Accelerators","color":"27496a"},"Widgets Product":{"name":"Widgets Product","description":"This label groups issues related to widgets","color":"f3fce6"},"App Theming Product":{"name":"App Theming Product","description":"Items that are related to the App level theming controls epic","color":"48883f"},"UI Building Product":{"color":"48883f","name":"UI Building Product","description":"Issues related to the UI Building experience"},"Onboarding Product":{"color":"48883f","name":"Onboarding Product","description":"Issues related to onboarding new developers"},"Database Schema":{"name":"Database Schema","description":"Issues related to database schema","color":"48883f"},"Git Product":{"color":"7e018f","name":"Git Product","description":"Issues related to version control product"},"Embedding Apps Product":{"name":"Embedding Apps Product","description":"Issues related to embedding","color":"48883f"},"Integrations Product":{"name":"Integrations Product","description":"Issues related to a specific integration","color":"b9f21c"},"Feature Flagging":{"name":"Feature Flagging","description":"Anything related feature flagging","color":"4574ae"},"Audit Logs Product":{"name":"Audit Logs Product","description":"Audit trails to ensure data security","color":"4574ae"},"Identity & Authentication Product":{"name":"Identity & Authentication Product","description":"Issues related to user identity & authentication","color":"4574ae"},"Email verification":{"name":"Email verification","description":"Email verification issues","color":"4574ae"},"Artifact Platform Product":{"name":"Artifact Platform Product","description":"Issues related to the application platform","color":"4574ae"},"Git IA":{"name":"Git IA","description":"Issues related to Git IA changes","color":"df8bd6"},"Documentation Pod":{"name":"Documentation Pod","description":"Issues related to user education","color":"8c8c02"},"Branch management":{"name":"Branch management","description":"Issues related to using a branch management on git","color":"ebe6af"},"Reconfigure Datasource Modal":{"name":"Reconfigure Datasource Modal","description":"Issues related to reconfigure DS modal that comes after importing applications","color":"5ac17b"},"Setup Issues":{"name":"Setup Issues","description":"Issues related to setting up appsmith","color":"3fc837"},"Packages & Git Pod":{"name":"Packages & Git Pod","description":"All issues belonging to Packages and Git","color":"46ac0e"},"Git Platform":{"name":"Git Platform","description":"Issues related to the git & the app platform","color":"c9ab80"},"Entity Management":{"name":"Entity Management","description":"Copy / Move / Delete widgets / queries / datasources","color":"74c33c"}},"success":true} \ No newline at end of file From 909bcff5ab9687ab78ae110da275ca993d0eced7 Mon Sep 17 00:00:00 2001 From: Nikhil Nandagopal Date: Fri, 3 Jan 2025 13:34:31 +0700 Subject: [PATCH 13/40] Updated Label Config --- .github/config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/config.json b/.github/config.json index 9a292106f958..4f23778798e7 100644 --- a/.github/config.json +++ b/.github/config.json @@ -1 +1 @@ -{"runners":[{"versioning":{"source":"milestones","type":"SemVer"},"prereleaseName":"alpha","issue":{"labels":{"Widgets Product":{"conditions":[{"label":"Button Widget","type":"hasLabel","value":true},{"label":"Chart Widget","type":"hasLabel","value":true},{"label":"Container Widget","type":"hasLabel","value":true},{"label":"Date Picker Widget","type":"hasLabel","value":true},{"label":"Select Widget","type":"hasLabel","value":true},{"label":"File Picker Widget","type":"hasLabel","value":true},{"label":"Form Widget","type":"hasLabel","value":true},{"label":"Image Widget","type":"hasLabel","value":true},{"label":"Input Widget","type":"hasLabel","value":true},{"label":"List Widget","type":"hasLabel","value":true},{"label":"MultiSelect Widget","type":"hasLabel","value":true},{"label":"Map Widget","type":"hasLabel","value":true},{"label":"Modal Widget","type":"hasLabel","value":true},{"label":"Radio Widget","type":"hasLabel","value":true},{"label":"Rich Text Editor Widget","type":"hasLabel","value":true},{"label":"Tab Widget","type":"hasLabel","value":true},{"label":"Table Widget","type":"hasLabel","value":true},{"label":"Text Widget","type":"hasLabel","value":true},{"label":"Video Widget","type":"hasLabel","value":true},{"label":"iFrame","type":"hasLabel","value":true},{"label":"Menu Button","type":"hasLabel","value":true},{"label":"Rating","type":"hasLabel","value":true},{"label":"Widget Validation","type":"hasLabel","value":true},{"label":"New Widget","type":"hasLabel","value":true},{"label":"Switch widget","type":"hasLabel","value":true},{"label":"Audio Widget","type":"hasLabel","value":true},{"label":"Icon Button Widget","type":"hasLabel","value":true},{"label":"Stat Box Widget","type":"hasLabel","value":true},{"label":"Voice Recorder Widget","type":"hasLabel","value":true},{"label":"Calendar Widget","type":"hasLabel","value":true},{"label":"Menu Button Widget","type":"hasLabel","value":true},{"label":"Divider Widget","type":"hasLabel","value":true},{"label":"Rating Widget","type":"hasLabel","value":true},{"label":"View Mode","type":"hasLabel","value":true},{"label":"Widget Property","type":"hasLabel","value":true},{"label":"Document Viewer Widget","type":"hasLabel","value":true},{"label":"Radio Group Widget","type":"hasLabel","value":true},{"label":"Currency Input Widget","type":"hasLabel","value":true},{"label":"TreeSelect","type":"hasLabel","value":true},{"label":"MultiTree Select Widget","type":"hasLabel","value":true},{"label":"Phone Input Widget","type":"hasLabel","value":true},{"label":"JSON Form","type":"hasLabel","value":true},{"label":"All Widgets","type":"hasLabel","value":true},{"label":"Button Group widget","type":"hasLabel","value":true},{"label":"Progress bar widget","type":"hasLabel","value":true},{"label":"Audio Recorder Widget","type":"hasLabel","value":true},{"label":"Camera Widget","type":"hasLabel","value":true},{"label":"Table Widget V2","type":"hasLabel","value":true},{"label":"Map Chart Widget","type":"hasLabel","value":true},{"label":"Code Scanner Widget","type":"hasLabel","value":true},{"label":"Widget keyboard accessibility","type":"hasLabel","value":true},{"label":"List Widget V2","type":"hasLabel","value":true},{"label":"Slider Widget","type":"hasLabel","value":true},{"label":"One-click Binding","type":"hasLabel","value":true},{"label":"Old widget version","type":"hasLabel","value":true},{"label":"Widget Discoverability","type":"hasLabel","value":true},{"label":"Switch Group Widget","type":"hasLabel","value":true},{"label":"Checkbox Group widget","type":"hasLabel","value":true},{"label":"Checkbox Widget","type":"hasLabel","value":true},{"label":"Table Inline Edit","type":"hasLabel","value":true},{"label":"Custom Widgets","type":"hasLabel","value":true}],"requires":1},"Javascript Product":{"conditions":[{"label":"JS Linting & Errors","type":"hasLabel","value":true},{"label":"Autocomplete","type":"hasLabel","value":true},{"label":"Evaluated Value","type":"hasLabel","value":true},{"label":"Slash Command","type":"hasLabel","value":true},{"label":"New JS Function","type":"hasLabel","value":true},{"label":"JS Usability","type":"hasLabel","value":true},{"label":"Framework Functions","type":"hasLabel","value":true},{"label":"JS Objects","type":"hasLabel","value":true},{"label":"JS Evaluation","type":"hasLabel","value":true},{"label":"Custom JS Libraries","type":"hasLabel","value":true},{"label":"Action Selector","type":"hasLabel","value":true},{"label":"Widget setter method","type":"hasLabel","value":true},{"label":"Entity Refactor","type":"hasLabel","value":true},{"label":"AST-frontend","type":"hasLabel","value":true},{"label":"Sniping Mode","type":"hasLabel","value":true},{"label":"AST-backend","type":"hasLabel","value":true}],"requires":1},"IDE Product":{"conditions":[{"label":"IDE Product","type":"hasLabel","value":true},{"label":"IDE Infra","type":"hasLabel","value":true},{"label":"IDE Navigation","type":"hasLabel","value":true},{"label":"IDE tabs","type":"hasLabel","value":true},{"label":"Omnibar","type":"hasLabel","value":true},{"label":"Entity Explorer","type":"hasLabel","value":true},{"label":"Page Management","type":"hasLabel","value":true},{"label":"Preview mode","type":"hasLabel","value":true},{"label":"Entity Management","type":"hasLabel","value":true}],"requires":1},"Accelerators Product":{"conditions":[{"label":"Generate Page","type":"hasLabel","value":true},{"label":"Building blocks","type":"hasLabel","value":true}],"requires":1},"Templates Product":{"conditions":[{"label":"Partial-import-export","type":"hasLabel","value":true},{"label":"Templates Product","type":"hasLabel","value":true}],"requires":1},"Design System Product":{"conditions":[{"label":"Design System Product","type":"hasLabel","value":true},{"label":"ADS Component Issue","type":"hasLabel","value":true},{"label":"Keyboard accessibility ","type":"hasLabel","value":true},{"label":"Toggle button","type":"hasLabel","value":true},{"label":"ADS Category Token","type":"hasLabel","value":true},{"label":"ADS Component Documentation","type":"hasLabel","value":true},{"label":"ADS Migration","type":"hasLabel","value":true},{"label":"ADS Deduplication ","type":"hasLabel","value":true},{"label":"ADS Revamp","type":"hasLabel","value":true},{"label":"ADS Deduplication","type":"hasLabel","value":true},{"label":"ADS Unit Test","type":"hasLabel","value":true},{"label":"ADS Components","type":"hasLabel","value":true},{"label":"ADS Grayscale","type":"hasLabel","value":true},{"label":"Design System","type":"hasLabel","value":true},{"label":"ADS Typography","type":"hasLabel","value":true},{"label":"ADS Visual Styles","type":"hasLabel","value":true},{"label":"ADS Component Design","type":"hasLabel","value":true},{"label":"Modal Component","type":"hasLabel","value":true},{"label":"ADS Spacing","type":"hasLabel","value":true},{"label":"ads unit test","type":"hasLabel","value":true},{"label":"ads revamp","type":"hasLabel","value":true},{"label":"ads deduplication","type":"hasLabel","value":true}],"requires":1},"RBAC Product":{"conditions":[{"label":"Invite users","type":"hasLabel","value":true},{"label":"RBAC Product","type":"hasLabel","value":true}],"requires":1},"Workspace Product":{"conditions":[{"label":"Home Page","type":"hasLabel","value":true},{"label":"Workspace Product","type":"hasLabel","value":true}],"requires":1},"Billing & Licensing Product":{"conditions":[{"label":"Customer Portal","type":"hasLabel","value":true},{"label":"Cloud Services","type":"hasLabel","value":true},{"label":"Billing","type":"hasLabel","value":true},{"label":"Self Serve","type":"hasLabel","value":true},{"label":"Enterprise Billing","type":"hasLabel","value":true},{"label":"Analytics Improvements","type":"hasLabel","value":true},{"label":"Self Serve 1.0","type":"hasLabel","value":true},{"label":"License","type":"hasLabel","value":true},{"label":"BE instance","type":"hasLabel","value":true},{"label":"Invite flow","type":"hasLabel","value":true},{"label":"CE Instance Usage","type":"hasLabel","value":true},{"label":"Feature Flagging","type":"hasLabel","value":true}],"requires":1},"Packages Product":{"conditions":[{"label":"Packages Product","type":"hasLabel","value":true}],"requires":1},"Environments Product":{"conditions":[{"label":"Environments Product","type":"hasLabel","value":true}],"requires":1},"UI Building Product":{"conditions":[{"label":"Property Pane","type":"hasLabel","value":true},{"label":"Copy Paste","type":"hasLabel","value":true},{"label":"Drag & Drop","type":"hasLabel","value":true},{"label":"Undo/Redo","type":"hasLabel","value":true},{"label":"Widgets Pane","type":"hasLabel","value":true},{"label":"UI Performance","type":"hasLabel","value":true},{"label":"Widget Grouping","type":"hasLabel","value":true},{"label":"Reflow & Resize","type":"hasLabel","value":true},{"label":"Canvas / Grid","type":"hasLabel","value":true},{"label":"Auto Height","type":"hasLabel","value":true},{"label":"Browser specific","type":"hasLabel","value":true},{"label":"Auto Layout","type":"hasLabel","value":true},{"label":"Fixed layout","type":"hasLabel","value":true},{"label":"App Navigation","type":"hasLabel","value":true}],"requires":1},"Onboarding Product":{"conditions":[{"label":"Welcome Screen","type":"hasLabel","value":true}],"requires":1},"Git Product":{"conditions":[{"label":"Git Product","type":"hasLabel","value":true},{"label":"Git Auto-commit","type":"hasLabel","value":true},{"label":"Auto-commit","type":"hasLabel","value":true},{"label":"Continuous Deployment","type":"hasLabel","value":true},{"label":"Default branch","type":"hasLabel","value":true},{"label":"Git status","type":"hasLabel","value":true},{"label":"Git performance","type":"hasLabel","value":true},{"label":"SDLC","type":"hasLabel","value":true},{"label":"Git IA","type":"hasLabel","value":true},{"label":"Branch management","type":"hasLabel","value":true}],"requires":1},"Embedding Apps Product":{"conditions":[{"label":"Embedding Apps Product","type":"hasLabel","value":true}],"requires":1},"Integrations Product":{"conditions":[{"label":"New Datasource","type":"hasLabel","value":true},{"label":"Firestore","type":"hasLabel","value":true},{"label":"Google Sheets","type":"hasLabel","value":true},{"label":"Mongo","type":"hasLabel","value":true},{"label":"Redshift","type":"hasLabel","value":true},{"label":"snowflake","type":"hasLabel","value":true},{"label":"S3","type":"hasLabel","value":true},{"label":"Redis","type":"hasLabel","value":true},{"label":"Postgres","type":"hasLabel","value":true},{"label":"GraphQL Plugin","type":"hasLabel","value":true},{"label":"ArangoDB","type":"hasLabel","value":true},{"label":"MsSQL","type":"hasLabel","value":true},{"label":"Elastic Search","type":"hasLabel","value":true},{"label":"OAuth","type":"hasLabel","value":true},{"label":"Airtable","type":"hasLabel","value":true},{"label":"CURL","type":"hasLabel","value":true},{"label":"DynamoDB","type":"hasLabel","value":true},{"label":"Zendesk","type":"hasLabel","value":true},{"label":"Hubspot","type":"hasLabel","value":true},{"label":"Query Forms","type":"hasLabel","value":true},{"label":"Twilio","type":"hasLabel","value":true},{"label":"MySQL","type":"hasLabel","value":true},{"label":"Connection pool","type":"hasLabel","value":true},{"label":"MariaDB","type":"hasLabel","value":true},{"label":"Integrations Pod General","type":"hasLabel","value":true},{"label":"SMTP plugin","type":"hasLabel","value":true},{"label":"Oracle SQL DB","type":"hasLabel","value":true},{"label":"Query filter","type":"hasLabel","value":true},{"label":"Activation - datasources","type":"hasLabel","value":true},{"label":"REST API","type":"hasLabel","value":true},{"label":"REST API","type":"hasLabel","value":true},{"label":"Datasources","type":"hasLabel","value":true},{"label":"REST API plugin","type":"hasLabel","value":true},{"label":"Prepared statements","type":"hasLabel","value":true},{"label":"Query Generation","type":"hasLabel","value":true},{"label":"Core Query Execution","type":"hasLabel","value":true},{"label":"Query Management","type":"hasLabel","value":true},{"label":"Query Settings","type":"hasLabel","value":true},{"label":"Query performance","type":"hasLabel","value":true},{"label":"Datatype issue","type":"hasLabel","value":true},{"label":"SmartSubstitution","type":"hasLabel","value":true},{"label":"Suggested Widgets","type":"hasLabel","value":true},{"label":"SAAS Plugins","type":"hasLabel","value":true},{"label":"Reconnect DS modal","type":"hasLabel","value":true},{"label":"OnPageLoad","type":"hasLabel","value":true},{"label":"File upload issues","type":"hasLabel","value":true},{"label":"AI","type":"hasLabel","value":true},{"label":"Appsmith AI","type":"hasLabel","value":true},{"label":"Database Schema","type":"hasLabel","value":true}],"requires":1},"Identity & Authentication Product":{"conditions":[{"label":"Login / Signup","type":"hasLabel","value":true},{"label":"SSO","type":"hasLabel","value":true},{"label":"SCIM","type":"hasLabel","value":true},{"label":"Email verification","type":"hasLabel","value":true}],"requires":1},"Artifact Platform Product":{"conditions":[{"label":"Fork App","type":"hasLabel","value":true},{"label":"Publish App","type":"hasLabel","value":true},{"label":"Secret Management","type":"hasLabel","value":true},{"label":"Import-Export-App","type":"hasLabel","value":true}],"requires":1},"DevOps Pod":{"conditions":[{"label":"Docker","type":"hasLabel","value":true},{"label":"Super Admin","type":"hasLabel","value":true},{"label":"Deployment","type":"hasLabel","value":true},{"label":"K8s","type":"hasLabel","value":true},{"label":"Email Config","type":"hasLabel","value":true},{"label":"Backup & Restore","type":"hasLabel","value":true},{"label":"AWS AMI","type":"hasLabel","value":true},{"label":"Observability","type":"hasLabel","value":true},{"label":"Heroku","type":"hasLabel","value":true},{"label":"New Deployment Mode","type":"hasLabel","value":true},{"label":"Supervisor","type":"hasLabel","value":true},{"label":"Deployment Certificates","type":"hasLabel","value":true},{"label":"Mock Data","type":"hasLabel","value":true},{"label":"AWS ECS","type":"hasLabel","value":true},{"label":"Ingress","type":"hasLabel","value":true},{"label":"Nginx","type":"hasLabel","value":true},{"label":"Setup Issues","type":"hasLabel","value":true}],"requires":1},"Performance Pod":{"conditions":[{"label":"Performance","type":"hasLabel","value":true},{"label":"Performance infra","type":"hasLabel","value":true}],"requires":1},"IDE Pod":{"conditions":[{"label":"Telemetry","type":"hasLabel","value":true},{"label":"i18n","type":"hasLabel","value":true},{"label":"IDE Product","type":"hasLabel","value":true},{"label":"App setting","type":"hasLabel","value":true},{"label":"Debugger Product","type":"hasLabel","value":true},{"label":"Embedding Apps Product","type":"hasLabel","value":true}],"requires":1},"Platform Administration Pod":{"conditions":[{"label":"Airgap","type":"hasLabel","value":true},{"label":"Enterprise Edition","type":"hasLabel","value":true},{"label":"Invite flow","type":"hasLabel","value":true},{"label":"User Profile","type":"hasLabel","value":true},{"label":"User Session ","type":"hasLabel","value":true},{"label":"User Session","type":"hasLabel","value":true},{"label":"Admin Settings Product","type":"hasLabel","value":true},{"label":"RBAC Product","type":"hasLabel","value":true},{"label":"Workspace Product","type":"hasLabel","value":true},{"label":"Branding Product","type":"hasLabel","value":true},{"label":"Audit Logs Product","type":"hasLabel","value":true},{"label":"Identity & Authentication Product","type":"hasLabel","value":true},{"label":"Billing & Licensing Product","type":"hasLabel","value":true},{"label":"Move to Postgres","type":"hasLabel","value":true}],"requires":1},"DB Infrastructure Pod":{"conditions":[],"requires":1},"Widgets & Accelerators Pod":{"conditions":[{"label":"Accelerators Product","type":"hasLabel","value":true},{"label":"Templates Product","type":"hasLabel","value":true},{"label":"Widgets Product","type":"hasLabel","value":true},{"label":"App Theming Product","type":"hasLabel","value":true}],"requires":1},"Packages Pod":{"conditions":[{"label":"Module creator","type":"hasLabel","value":true},{"label":"Module consumer","type":"hasLabel","value":true},{"label":"Package versioning","type":"hasLabel","value":true},{"label":"Convert to module","type":"hasLabel","value":true},{"label":"Query module","type":"hasLabel","value":true},{"label":"JS module","type":"hasLabel","value":true},{"label":"UI module","type":"hasLabel","value":true},{"label":"Packages Pod","type":"hasLabel","value":true}],"requires":1},"Workflows Pod":{"conditions":[{"label":"Workflows Product","type":"hasLabel","value":true}],"requires":1},"Query & JS Pod":{"conditions":[{"label":"Javascript Product","type":"hasLabel","value":true},{"label":"Onboarding Product","type":"hasLabel","value":true},{"label":"Integrations Product","type":"hasLabel","value":true},{"label":"Reconfigure Datasource Modal","type":"hasLabel","value":true}],"requires":1},"QA Pod":{"conditions":[{"label":"QA","type":"hasLabel","value":true},{"label":"Automation Test","type":"hasLabel","value":true},{"label":"TestGap","type":"hasLabel","value":true},{"label":"Automation failures","type":"hasLabel","value":true},{"label":"Needs automation","type":"hasLabel","value":true},{"label":"cypress-flaky-fix","type":"hasLabel","value":true}],"requires":1},"Anvil POD":{"conditions":[{"label":"Checkbox Component","type":"hasLabel","value":true},{"label":"WDS team","type":"hasLabel","value":true},{"label":"Anvil POD","type":"hasLabel","value":true},{"label":"WDS - all widgets","type":"hasLabel","value":true},{"label":"WDS - input widget","type":"hasLabel","value":true},{"label":"WDS - paragraph widget","type":"hasLabel","value":true},{"label":"WDS - statbox widget","type":"hasLabel","value":true},{"label":"WDS - modal widget","type":"hasLabel","value":true},{"label":"WDS - icon widget","type":"hasLabel","value":true},{"label":"WDS - checkbox widget","type":"hasLabel","value":true},{"label":"WDS - table widget","type":"hasLabel","value":true},{"label":"WDS - keyValue widget","type":"hasLabel","value":true},{"label":"WDS - switch group widget","type":"hasLabel","value":true},{"label":"WDS - theming","type":"hasLabel","value":true},{"label":"Anvil layout","type":"hasLabel","value":true},{"label":"Anvil - theming","type":"hasLabel","value":true},{"label":"Anvil - vertical alignment","type":"hasLabel","value":true},{"label":"Anvil - layout component","type":"hasLabel","value":true},{"label":"Anvil - drag & drop","type":"hasLabel","value":true},{"label":"Anvil - zones & sections","type":"hasLabel","value":true},{"label":"Anvil - copy paste experience","type":"hasLabel","value":true},{"label":"WDS - phone widget","type":"hasLabel","value":true},{"label":"WDS - responsive widget","type":"hasLabel","value":true},{"label":"Anvil - responsive viewport","type":"hasLabel","value":true},{"label":"WDS - widget styling","type":"hasLabel","value":true},{"label":"Anvil - spacing","type":"hasLabel","value":true},{"label":"Anvil - responsive canvas","type":"hasLabel","value":true},{"label":"WDS - inline button widget","type":"hasLabel","value":true},{"label":"Anvil team","type":"hasLabel","value":true}],"requires":1},"Activation Pod":{"conditions":[{"label":"Activation","type":"hasLabel","value":true}],"requires":1},"Stability Pod":{"conditions":[{"label":"Stability Issue","type":"hasLabel","value":true},{"label":"Cypress flaky tests","type":"hasLabel","value":true}],"requires":1},"Documentation Pod":{"conditions":[{"label":"Documentation","type":"hasLabel","value":true}],"requires":1},"Packages & Git Pod":{"conditions":[{"label":"Packages Pod","type":"hasLabel","value":true},{"label":"Git Product","type":"hasLabel","value":true},{"label":"Packages Product","type":"hasLabel","value":true},{"label":"Git Platform","type":"hasLabel","value":true}],"requires":1},"Git Platform":{"conditions":[{"label":"Environments Product","type":"hasLabel","value":true},{"label":"Artifact Platform Product","type":"hasLabel","value":true}],"requires":1}}},"root":"."}],"labels":{"Tab Widget":{"color":"e2c76c","name":"Tab Widget","description":""},"Dont merge":{"color":"ADB39C","name":"Dont merge","description":""},"Epic":{"color":"3E4B9E","name":"Epic","description":"A zenhub epic that describes a project"},"Menu Button Widget":{"color":"235708","name":"Menu Button Widget","description":"Issues related to Menu Button widget"},"Checkbox Group widget":{"color":"bbeecd","name":"Checkbox Group widget","description":"Issues related to Checkbox Group Widget"},"Input Widget":{"color":"ae65d8","name":"Input Widget","description":""},"Security":{"color":"99139C","name":"Security","description":""},"QA":{"color":"","name":"QA","description":"Needs QA attention"},"Verified":{"color":"9bf416","name":"Verified","description":""},"Wont Fix":{"color":"ffffff","name":"Wont Fix","description":"This will not be worked on"},"MySQL":{"color":"c9ddc6","name":"MySQL","description":"Issues related to MySQL plugin"},"Development":{"color":"9F8A02","name":"Development","description":""},"Help Wanted":{"color":"008672","name":"Help Wanted","description":"Extra attention is needed"},"Home Page":{"color":"","name":"Home Page","description":"Issues related to the application home page"},"Rating Widget":{"color":"235708","name":"Rating Widget","description":"Issues related to the rating widget"},"Stat Box Widget":{"color":"f1c9ce","name":"Stat Box Widget","description":"Issues related to stat box"},"Enhancement":{"color":"a2eeef","name":"Enhancement","description":"New feature or request"},"Fork App":{"color":"af87c7","name":"Fork App","description":"Issues related to forking apps"},"Container Widget":{"color":"19AD0D","name":"Container Widget","description":"Container widget"},"Papercut":{"color":"B562F6","name":"Papercut","description":""},"Needs Design":{"color":"bfd4f2","name":"Needs Design","description":"needs design or changes to design"},"i18n":{"color":"1799b0","name":"i18n","description":"Represents issues that need to be tackled to handle internationalization"},"Rich Text Editor Widget":{"color":"f72cac","name":"Rich Text Editor Widget","description":""},"skip-changelog":{"color":"06086F","name":"skip-changelog","description":"Adding this label to a PR prevents it from being listed in the changelog"},"Low":{"color":"79e53b","name":"Low","description":"An issue that is neither critical nor breaks a user flow"},"potential-duplicate":{"color":"d3cb2e","name":"potential-duplicate","description":"This label marks issues that are potential duplicates of already open issues"},"Audio Widget":{"color":"447B9A","name":"Audio Widget","description":"Issues related to Audio Widget"},"Firestore":{"color":"8078b0","name":"Firestore","description":"Issues related to the firestore Integration"},"New Widget":{"color":"be4cf2","name":"New Widget","description":"A request for a new widget"},"Modal Widget":{"color":"03846f","name":"Modal Widget","description":""},"UX Improvement":{"color":"f4a089","name":"UX Improvement","description":""},"S3":{"color":"8078b0","name":"S3","description":"Issues related to the S3 plugin"},"Release Blocker":{"color":"5756bf","name":"Release Blocker","description":"This issue must be resolved before the release"},"safari":{"color":"51C6AA","name":"safari","description":"Bugs seen on safari browser"},"Example Apps":{"color":"1799b0","name":"Example Apps","description":"Example apps created for new signups"},"MultiSelect Widget":{"color":"AB62D4","name":"MultiSelect Widget","description":"Issues related to MultiSelect Widget"},"Calendar Widget":{"color":"8c6644","name":"Calendar Widget","description":""},"Website":{"color":"151720","name":"Website","description":"Related to www.appsmith.com website"},"Low effort":{"color":"8B59F0","name":"Low effort","description":"Something that'll take a few days to build"},"Checkbox Widget":{"color":"bbeecd","name":"Checkbox Widget","description":""},"Spam":{"color":"620faf","name":"Spam","description":""},"Voice Recorder Widget":{"color":"85bc87","name":"Voice Recorder Widget","description":""},"Select Widget":{"color":"0c669e","name":"Select Widget","description":"Select or dropdown widget"},"Bug":{"color":"8ba6fd","name":"Bug","description":"Something isn't right"},"Widget Validation":{"color":"6990BC","name":"Widget Validation","description":"Issues related to widget property validation"},"Generate Page":{"color":"2b4664","name":"Generate Page","description":"Issures related to page generation"},"File Picker Widget":{"color":"6ae4f2","name":"File Picker Widget","description":""},"snowflake":{"color":"8078b0","name":"snowflake","description":"Issues related to the snowflake Integration"},"Automation":{"color":"CCAF60","name":"Automation","description":""},"hotfix":{"color":"BA3F1D","name":"hotfix","description":""},"Import-Export-App":{"color":"48883f","name":"Import-Export-App","description":"Issues related to importing and exporting apps"},"High effort":{"color":"A7E87B","name":"High effort","description":"Something that'll take more than a month to build"},"Telemetry":{"color":"bc70f9","name":"Telemetry","description":"Issues related to instrumenting appsmith"},"Radio Widget":{"color":"91ef15","name":"Radio Widget","description":""},"Omnibar":{"color":"1bb96a","name":"Omnibar","description":"Issues related to the omnibar for navigation"},"Button Widget":{"color":"34efae","name":"Button Widget","description":""},"Switch widget":{"color":"33A8CE","name":"Switch widget","description":"The switch widget"},"Map Widget":{"color":"7eef7a","name":"Map Widget","description":""},"Task":{"color":"085630","name":"Task","description":"A simple Todo"},"Design System":{"color":"2958a4","name":"Design System","description":"Design system"},"opera":{"color":"C63F5B","name":"opera","description":"Any issues identified on the opera browser"},"Login / Signup":{"color":"","name":"Login / Signup","description":"Authentication flows"},"Image Widget":{"color":"8de8ad","name":"Image Widget","description":""},"firefox":{"color":"6d56e2","name":"firefox","description":""},"Property Pane":{"color":"b356ff","name":"Property Pane","description":"Issues related to the behaviour of the property pane"},"Deployment":{"color":"93491f","name":"Deployment","description":"Installation process of appsmith"},"Production":{"color":"b60205","name":"Production","description":""},"Dependencies":{"color":"0366d6","name":"Dependencies","description":"Pull requests that update a dependency file"},"Google Sheets":{"color":"8078b0","name":"Google Sheets","description":"Issues related to Google Sheets"},"Icon Button Widget":{"color":"D319CE","name":"Icon Button Widget","description":"Issues related to the icon button widget"},"Mongo":{"color":"8078b0","name":"Mongo","description":"Issues related to Mongo DB plugin"},"Documentation":{"color":"a8dff7","name":"Documentation","description":"Improvements or additions to documentation"},"TestGap":{"color":"","name":"TestGap","description":"Issues identified for test plan improvement"},"keyboard shortcut":{"color":"0688B6","name":"keyboard shortcut","description":""},"Reopen":{"color":"897548","name":"Reopen","description":""},"Redshift":{"color":"8078b0","name":"Redshift","description":"Issues related to the redshift integration"},"Date Picker Widget":{"color":"ef1ce1","name":"Date Picker Widget","description":""},"Entity Explorer":{"color":"1bb96a","name":"Entity Explorer","description":"Issues related to navigation using the entity explorer"},"JS Linting & Errors":{"color":"E56AA5","name":"JS Linting & Errors","description":"Issues related to JS Linting and errors"},"iFrame":{"color":"3CD1DB","name":"iFrame","description":"Issues related to iFrame"},"Stale":{"color":"ededed","name":"Stale","description":null},"Text Widget":{"color":"d130d1","name":"Text Widget","description":""},"Video Widget":{"color":"23dd4b","name":"Video Widget","description":""},"Datasources":{"color":"3d590f","name":"Datasources","description":"Issues related to configuring datasource on appsmith"},"error":{"color":"B66773","name":"error","description":"All issues connected to error messages"},"Form Widget":{"color":"09ed77","name":"Form Widget","description":""},"Needs Triaging":{"color":"e8b851","name":"Needs Triaging","description":"Needs attention from maintainers to triage"},"Autocomplete":{"color":"235708","name":"Autocomplete","description":"Issues related to the autocomplete"},"hacktoberfest":{"color":"0052cc","name":"hacktoberfest","description":"All issues that can be solved by the community during Hacktoberfest"},"Medium effort":{"color":"D31156","name":"Medium effort","description":"Something that'll take more than a week but less than a month to build"},"Release":{"color":"57e5e0","name":"Release","description":""},"High":{"color":"c94d14","name":"High","description":"This issue blocks a user from building or impacts a lot of users"},"UI Performance":{"color":"1799b0","name":"UI Performance","description":"Issues related to UI performance"},"Deploy Preview":{"color":"bfdadc","name":"Deploy Preview","description":"Issues found in Deploy Preview"},"Needs Tests":{"color":"8ee263","name":"Needs Tests","description":"Needs automated tests to assert a feature/bug fix"},"Refactor":{"color":"B96662","name":"Refactor","description":"needs refactoring of code"},"Divider Widget":{"color":"235708","name":"Divider Widget","description":"Issues related to the divider widget"},"Table Widget":{"color":"2eead1","name":"Table Widget","description":""},"Needs More Info":{"color":"e54c10","name":"Needs More Info","description":"Needs additional information"},"Good First Issue":{"color":"7057ff","name":"Good First Issue","description":"Good for newcomers"},"UI Improvement":{"color":"9aeef4","name":"UI Improvement","description":""},"Backend":{"color":"d4c5f9","name":"Backend","description":"This marks the issue or pull request to reference server code"},"Frontend":{"color":"87c7f2","name":"Frontend","description":"This label marks the issue or pull request to reference client code"},"Chart Widget":{"color":"616ecc","name":"Chart Widget","description":""},"List Widget":{"color":"8508A0","name":"List Widget","description":"Issues related to the list widget"},"Duplicate":{"color":"cfd3d7","name":"Duplicate","description":"This issue or pull request already exists"},"JS Snippets":{"color":"8d62d2","name":"JS Snippets","description":"issues related to JS Snippets"},"Copy Paste":{"name":"Copy Paste","description":"Issues related to copy paste","color":"b4f0a9"},"Drag & Drop":{"name":"Drag & Drop","description":"Issues related to the drag & drop experience","color":"92115a"},"Sniping Mode":{"name":"Sniping Mode","description":"Issues related to sniping mode","color":"48883f"},"Redis":{"name":"Redis","description":"Issues related to Redis","color":"8078b0"},"New Datasource":{"color":"60b14c","name":"New Datasource","description":"Requests for new datasources"},"Evaluated Value":{"name":"Evaluated Value","description":"Issues related to evaluated values","color":"39f6e7"},"Undo/Redo":{"name":"Undo/Redo","description":"Issues related to undo/redo","color":"f25880"},"App Navigation":{"name":"App Navigation","description":"Issues related to the topbar navigation and configuring it","color":"4773ab"},"Widgets Pane":{"name":"Widgets Pane","description":"Issues related to the discovery and organisation of widgets","color":"ad5d78"},"View Mode":{"color":"1799b0","name":"View Mode","description":"Issues related to the view mode"},"Content":{"name":"Content","description":"For content related topics i.e blogs, templates, videos","color":"a8dff7"},"Slash Command":{"name":"Slash Command","description":"Issues related to the slash command","color":"a0608e"},"Widget Property":{"name":"Widget Property","description":"Issues related to adding / modifying widget properties across widgets","color":"5e92cb"},"Windows":{"name":"Windows","description":"Issues related exclusively to Windows systems","color":"b4cb8a"},"Old App Issues":{"name":"Old App Issues","description":"Issues related to apps old apps a few weeks old and app issues in stale browser session","color":"87ab18"},"Document Viewer Widget":{"name":"Document Viewer Widget","description":"Issues related to Document Viewer Widget","color":"899d4b"},"Radio Group Widget":{"name":"Radio Group Widget","description":"Issues related to radio group widget","color":"b68495"},"Super Admin":{"name":"Super Admin","description":"Issues related to the super admin page","color":"aa95cf"},"Postgres":{"name":"Postgres","description":"Postgres related issues","color":"8078b0"},"New JS Function":{"name":"New JS Function","description":"Issues related to adding a JS Function","color":"8e8aa4"},"Cannot Reproduce Issue":{"color":"93c9cc","name":"Cannot Reproduce Issue","description":"Issues that cannot be reproduced"},"Widget Grouping":{"name":"Widget Grouping","description":"Issues related to Widget Grouping","color":"a49951"},"K8s":{"name":"K8s","description":"Kubernetes related issues","color":"5f318a"},"Docker":{"name":"Docker","description":"Issues related to docker","color":"89b808"},"Camera Widget":{"name":"Camera Widget","description":"Issues and enhancements related to camera widget","color":"e6038e"},"SAAS Plugins":{"name":"SAAS Plugins","description":"Issues related to SAAS Plugins","color":"80e18f"},"JS Promises":{"name":"JS Promises","description":"Issues related to promises","color":"d7771f"},"OnPageLoad":{"name":"OnPageLoad","description":"OnPageLoad issues on functions and queries","color":"2b4664"},"JS Usability":{"name":"JS Usability","description":"usability issues with JS editor and JS elsewhere","color":"a302b0"},"Currency Input Widget":{"name":"Currency Input Widget","description":"Issues related to currency input widget","color":"b2164f"},"TreeSelect":{"name":"TreeSelect","description":"Issues related to TreeSelect Widget","color":"a1633e"},"MultiTree Select Widget":{"name":"MultiTree Select Widget","description":"Issues related to MultiTree Select Widget","color":"a1633e"},"Welcome Screen":{"name":"Welcome Screen","description":"Issues related to the welcome screen","color":"48883f"},"Realtime Commenting":{"color":"a70b86","name":"Realtime Commenting","description":"In-app communication between teams"},"Phone Input Widget":{"name":"Phone Input Widget","description":"Issues related to the Phone Input widget","color":"a70b86"},"JSON Form":{"name":"JSON Form","description":"Issue / features related to the JSON form wiget","color":"46b209"},"All Widgets":{"name":"All Widgets","description":"Issues related to all widgets","color":"972b36"},"V1":{"name":"V1","description":"V1","color":"67ab2e"},"Reflow & Resize":{"name":"Reflow & Resize","description":"All issues related to reflow and resize experience","color":"748a13"},"SSO":{"name":"SSO","description":"Issues, requests and enhancements around Single sign-on.","color":""},"Multi User Realtime":{"name":"Multi User Realtime","description":"Issues related to multiple users using or editing an application","color":"e7b6ce"},"Ready for design":{"name":"Ready for design","description":"this issue is ready for design: it contains clear problem statements and other required information","color":"ebf442"},"Support":{"name":"Support","description":"Issues created by the A-force team to address user queries","color":"1740f3"},"Button Group widget":{"name":"Button Group widget","description":"Issue and enhancements related to the button group widget","color":"f17025"},"GraphQL Plugin":{"name":"GraphQL Plugin","description":"Issues related to GraphQL plugin","color":"8078b0"},"DevOps Pod":{"name":"DevOps Pod","description":"Issues related to devops","color":"d956c7"},"medium":{"name":"medium","description":"Issues that frustrate users due to poor UX","color":"23dfd9"},"ArangoDB":{"name":"ArangoDB","description":"Issues related to arangoDB","color":"8078b0"},"Code Refactoring":{"name":"Code Refactoring","description":"Issues related to code refactoring","color":"76310e"},"Progress bar widget":{"name":"Progress bar widget","description":"To track issues related to progress bar","color":"2d7abf"},"Audio Recorder Widget":{"name":"Audio Recorder Widget","description":"Issues related to Audio Recorder Widget","color":"9accef"},"Airtable":{"name":"Airtable","description":"Issues for Airtable","color":"60885f"},"Canvas / Grid":{"name":"Canvas / Grid","description":"Issues related to the canvas","color":"16b092"},"Email Config":{"name":"Email Config","description":"Issues related to configuring the email service","color":"2a21d1"},"CURL":{"name":"CURL","description":"Issues related to CURL impor","color":"60885f"},"Canvas Zooms":{"name":"Canvas Zooms","description":"Issues related to zooming the canvas","color":"e6038e"},"business":{"name":"business","description":"Features that will be a part of our business edition","color":"cd59eb"},"Action Pod":{"name":"Action Pod","description":"","color":"ee2e36"},"AutomationGap1":{"color":"a5e07c","name":"AutomationGap1","description":"Issues that needs automated tests"},"A-Force11":{"name":"A-Force11","description":"Issues raised by A-Force team","color":"d667b6"},"Business Edition":{"name":"Business Edition","description":"Features that will be a part of our business edition","color":"89bb6c"},"storeValue":{"name":"storeValue","description":"Issues related to the store value function","color":"5d3e66"},"DynamoDB":{"name":"DynamoDB","description":"Issues that are related to DynamoDB should have this label","color":"60885f"},"Backup & Restore":{"name":"Backup & Restore","description":"Issues related to backup and restore","color":"86874d"},"Billing":{"name":"Billing","description":"Billing infrastructure and flows for Business Edition and Trial users","color":"d2bc40"},"Datatype issue":{"name":"Datatype issue","description":"Issues that have risen because data types weren't handled","color":"cef66b"},"OAuth":{"name":"OAuth","description":"OAuth related bugs or features","color":"60885f"},"Table Widget V2":{"name":"Table Widget V2","description":"Issues related to Table Widget V2","color":"3a7192"},"IDE Navigation":{"name":"IDE Navigation","description":"Issues/feature requests related to IDE navigation, and context switching","color":"1bb96a"},"Query performance":{"name":"Query performance","description":"Issues that have to do with lack in performance of query execution","color":"cef66b"},"SAAS Manager App":{"name":"SAAS Manager App","description":"Issues with the SAAS manager app","color":"d427db"},"Twilio":{"name":"Twilio","description":"Issues related to Twilio integration","color":"23ba8d"},"Hubspot":{"name":"Hubspot","description":"Issues related to Hubspot integration","color":"60885f"},"Zendesk":{"name":"Zendesk","description":"Issues related to Zendesk integration","color":"60885f"},"Entity Refactor":{"name":"Entity Refactor","description":"Issues related to refactor logic","color":"705a2c"},"Map Chart Widget":{"name":"Map Chart Widget","description":"Issues related to Map Chart Widgets","color":"c8397f"},"Product Catchup":{"name":"Product Catchup","description":"Issues created in the product catchup","color":"29cd2c"},"Framework Functions":{"name":"Framework Functions","description":"Issues related to internal functions like showAlert(), navigateTo() etc...","color":"c25a09"},"Frontend Libraries Upgrade":{"name":"Frontend Libraries Upgrade","description":"Issues related to frontend libraries upgrade","color":"ede1fc"},"MsSQL":{"name":"MsSQL","description":"Issues related to MsSQL plugin","color":"8078b0"},"Elastic Search":{"name":"Elastic Search","description":"Issues related to the elastic search datasource","color":"8078b0"},"Core Query Execution":{"color":"cef66b","name":"Core Query Execution","description":"Issues related to the execution of all queries"},"Query Management":{"name":"Query Management","description":"Issues related to the CRUD of actions or queries","color":"cef66b"},"Query Settings":{"name":"Query Settings","description":"Issues related to the settings of all queries","color":"cef66b"},"Code Editor":{"name":"Code Editor","description":"Issues related to the code editor","color":"4ca16e"},"Query Forms":{"color":"12b253","name":"Query Forms","description":"Isuses related to the query forms"},"JS Objects":{"color":"22962c","name":"JS Objects","description":"Issues related to JS Objects"},"JS Evaluation":{"color":"22962c","name":"JS Evaluation","description":"Issues related to JS evaluation on the platform"},"SmartSubstitution":{"name":"SmartSubstitution","description":"Issues related to Smart substitution of mustache bindings in queries","color":"bae511"},"Query Generation":{"name":"Query Generation","description":"Issues related to query generation","color":"cef66b"},"Suggested Widgets":{"name":"Suggested Widgets","description":"Issues related to suggesting widgets based on query response","color":"6ac063"},"Code Scanner Widget":{"name":"Code Scanner Widget","description":"Issues related to code scanner widget","color":"9bc1a0"},"Clean URLs":{"name":"Clean URLs","description":"Issues related to clean URLs epic","color":"112623"},"Widget keyboard accessibility":{"name":"Widget keyboard accessibility","description":"All issues related to keyboard accessibility in widgets","color":"b626fd"},"Connection pool":{"name":"Connection pool","description":"issues to do with connection pooling of various plugins","color":"94fe36"},"List Widget V2":{"name":"List Widget V2","description":"Issues related to the list widget v2","color":"adaaf7"},"Auto Height":{"name":"Auto Height","description":"Issues related to dynamic height of widgets","color":"5149cf"},"cypress_failed_test":{"name":"cypress_failed_test","description":"Cypress failed tests","color":"4745d5"},"Needs validation":{"name":"Needs validation","description":"Needs problem validation before being picked up","color":"66673d"},"Slider Widget":{"name":"Slider Widget","description":"Issues raised for slider widgets.","color":"2eef5f"},"Multitenancy":{"name":"Multitenancy","description":"Support multitenancy within single appsmith instance","color":"8c49a9"},"Conversion Algorithm":{"name":"Conversion Algorithm","description":"All issue related to converting app from fixed to flex mode & vice versa","color":"d12d2e"},"Browser specific":{"name":"Browser specific","description":"All issue related to browser","color":"d12d2e"},"Performance infra":{"name":"Performance infra","description":"all issue related to the performance infra","color":"8a60f6"},"DSL Update":{"name":"DSL Update","description":"Issues related to storing and updating the DSL","color":"e16cf3"},"AST-frontend":{"name":"AST-frontend","description":"Issues related to maintaining AST logic","color":"2b4664"},"AST-backend":{"name":"AST-backend","description":"Backend issues related to AST parsing","color":"48883f"},"MariaDB":{"name":"MariaDB","description":"MariaDB datasource","color":"8428c3"},"ADS Component Issue":{"name":"ADS Component Issue","description":"Issues which are caused due to ADS components","color":"d89119"},"Regressed":{"color":"723fd0","name":"Regressed","description":"Scenarios that were working before but have now regressed"},"Needs RCA":{"name":"Needs RCA","description":"a critical or high priority issue that needs an RCA","color":"2cc68f"},"Custom JS Libraries":{"name":"Custom JS Libraries","description":"Issues related to adding custom JS library","color":"bacb6d"},"Integrations Pod General":{"name":"Integrations Pod General","description":"Issues related to the Integrations Pod that don't fit into other tags.","color":"287823"},"Performance Pod":{"name":"Performance Pod","description":"All things related to Appsmith performance","color":"b5a25d"},"Performance":{"name":"Performance","description":"Issues related to performance","color":"9a18d7"},"File upload issues":{"name":"File upload issues","description":"Issues related to uploading any type of files from within Appsmith","color":"2b4664"},"Action Selector":{"name":"Action Selector","description":"Issues related to action selector on the property pane","color":"2f9e20"},"Community Reported":{"name":"Community Reported","description":"issues reported by community members","color":"1402e5"},"JS Function execution":{"name":"JS Function execution","description":"JS function execution","color":"7c2de1"},"Self Serve":{"name":"Self Serve","description":"For all issues related to self-serve flow for business edition","color":"4dacfc"},"Self Serve 1.0":{"name":"Self Serve 1.0","description":"For all issues related to v1 of the self serve project","color":"ae839e"},"Customer Portal":{"name":"Customer Portal","description":"For all tasks/issues pertaining to customer.appsmith.com","color":"d2bc40"},"Cloud Services":{"name":"Cloud Services","description":"For all tasks/issues on Appsmith cloud-services relating to licensing, usage and billing","color":"d2bc40"},"One-click Binding":{"name":"One-click Binding","description":"Issues related to the One click binding epic","color":"f1661c"},"Airgap":{"name":"Airgap","description":"Tickets related to supporting air-gapped Appsmith instances","color":"1cb294"},"SMTP plugin":{"name":"SMTP plugin","description":"Issues related to SMTP plugin","color":"541457"},"AWS AMI":{"name":"AWS AMI","description":"Issues Related to AWS AMI","color":"b44680"},"Old widget version":{"name":"Old widget version","description":"Use this label to raise issue specific only to an older version of a widget","color":"ff3814"},"Enterprise Billing":{"name":"Enterprise Billing","description":"To track all tasks/issues related to licensing & billing for enterprise customers","color":"14c156"},"Oracle SQL DB":{"name":"Oracle SQL DB","description":"Issues related to the Oracle plugin","color":"cbabcb"},"Community Contributor":{"name":"Community Contributor","description":"Meant to track issues that are assigned to external contributors","color":"149ab6"},"widget vertical alignment":{"name":"widget vertical alignment","description":"All issue related widget vertical alignment on the auto layout canvas","color":"d12d2e"},"Observability":{"name":"Observability","description":"Issues related to observability on the Appsmith instance","color":"dff913"},"Checkbox Component":{"name":"Checkbox Component","description":"This labels deals with checkbox component in wds package","color":"75a401"},"Analytics Improvements":{"name":"Analytics Improvements","description":"For all tasks focused on improving our overall analytics and fixing any issues ","color":"29b8ed"},"WDS team":{"name":"WDS team","description":"","color":"8d675a"},"Enterprise Edition":{"name":"Enterprise Edition","description":"Features that will be supported in Enterprise Edition only","color":"984f5e"},"Query filter":{"name":"Query filter","description":"Issues related to query filtering, e.g., WHERE clause","color":"a15134"},"Keyboard accessibility ":{"name":"Keyboard accessibility ","description":"All issue related to ADS component keyboard accessibility","color":"2ba696"},"Toggle button":{"name":"Toggle button","description":"All issue related to ADS toggle button","color":"edc47f"},"SCIM":{"name":"SCIM","description":"Label to collate our SCIM issues","color":"48883f"},"ADS Category Token":{"name":"ADS Category Token","description":"All issues related appsmith design system category tokens","color":"920961"},"ADS Component Documentation":{"name":"ADS Component Documentation","description":"All issues Appsmith design system component documentation","color":"64c46a"},"ADS Migration":{"name":"ADS Migration","description":"All issues related to Appsmith design system migration","color":"b082d6"},"ADS Deduplication ":{"name":"ADS Deduplication ","description":"Replacing component with ADS components","color":"b082d6"},"ADS Revamp":{"name":"ADS Revamp","description":"All issues related to ads revamp. ","color":"b082d6"},"ADS Deduplication":{"name":"ADS Deduplication","description":"Replacing component with ADS components","color":"b082d6"},"ADS Grayscale":{"name":"ADS Grayscale","description":"Support grayscale color changes","color":"b03577"},"ADS Unit Test":{"name":"ADS Unit Test","description":"All issue related ads unit cases ","color":"b082d6"},"ADS Components":{"name":"ADS Components","description":"All issues related ADS components","color":"b082d6"},"Widget Discoverability":{"name":"Widget Discoverability","description":"Issues related to Widget Discoverability","color":"7b55ce"},"Widget setter method":{"name":"Widget setter method","description":"Issues with widget property setters","color":"8dce87"},"License":{"name":"License","description":"For all issues/tasks related to licensing of appsmith-ee edition","color":"90ee98"},"Platformization":{"name":"Platformization","description":"Issues or tasks related to platformization of Appsmith codebase","color":"4e972b"},"Activation - datasources":{"name":"Activation - datasources","description":"issues related to activation projects","color":"7c7ace"},"Partial-import-export":{"name":"Partial-import-export","description":"Label for granular reusability.","color":"717732"},"AI":{"name":"AI","description":"All tasks related to AI","color":"2b4664"},"ADS Typography":{"name":"ADS Typography","description":"All issue related typographical changes","color":"2dbe8d"},"Auto Layout":{"name":"Auto Layout","description":"Issues relates to auto layout","color":"92cf8c"},"Heroku":{"name":"Heroku","description":"Issues related to Heroku","color":"a81b69"},"ADS Visual Styles":{"name":"ADS Visual Styles","description":"All issues related to ADS visual styles","color":"d3da89"},"ADS Component Design":{"name":"ADS Component Design","description":"All issue related to component design","color":"5cc91e"},"Modal Component":{"name":"Modal Component","description":"All issue related to ads modal component","color":"ee63f3"},"App setting":{"name":"App setting","description":"Related to app settings panel within the app","color":"174f98"},"BE instance":{"name":"BE instance","description":"For all issues related to license, billing on BE instance","color":"ae8f98"},"Fixed layout":{"name":"Fixed layout","description":"issues related to fixed layout","color":"b66681"},"Anvil layout":{"name":"Anvil layout","description":"issues related to the new layout system anvil","color":"5e0904"},"New Deployment Mode":{"name":"New Deployment Mode","description":"Support a new mode of deployment","color":"108033"},"Custom widgets":{"name":"Custom widgets","description":"For all issues related to the custom widget project","color":"c9db9c"},"Homepage Experience V2":{"name":"Homepage Experience V2","description":"Label for reporting new tasks and bug fixes related to revamped homepage experience","color":"c55d54"},"Customer Success":{"name":"Customer Success","description":"Issues that the success team cares about","color":"6ccabd"},"Invite flow":{"name":"Invite flow","description":"Invite users flow and any associated actions","color":"881b35"},"Invite users":{"name":"Invite users","description":"Invite users flow and any associated actions","color":""},"Workflows Pod":{"name":"Workflows Pod","description":"Issues that the workflows team owns","color":"446925"},"DailyPromotionBlocker":{"name":"DailyPromotionBlocker","description":"DailyPromotion Blocker","color":"9b2280"},"JS Binding":{"name":"JS Binding","description":"All issues related to the JS Binding experience","color":"422fed"},"REST API":{"name":"REST API","description":"REST API plugin related issues","color":"e3ede5"},"Critical":{"color":"a1e3db","name":"Critical","description":"This issue breaks existing apps. Drop everything else to resolve"},"Module creator":{"name":"Module creator","description":"Issues related to the module creator side","color":"bb2c05"},"Module consumer":{"name":"Module consumer","description":"Issues related to the module consumer side","color":"83d3c5"},"Package versioning":{"name":"Package versioning","description":"ISsues related to how we manage versions for packages","color":"4c5218"},"Convert to module":{"name":"Convert to module","description":"Issues related to the module creation flow using conversion","color":"4c5218"},"Query module":{"name":"Query module","description":"Issues affecting query modules or its instances","color":"b11a7e"},"JS module":{"name":"JS module","description":"Issues affecting JS modules or its instances","color":"bf76f6"},"Secret Management":{"name":"Secret Management","description":"Issues related to secret management","color":"2b4664"},"REST API plugin":{"name":"REST API plugin","description":"REST API plugin related issues","color":"b5948a"},"UI module":{"name":"UI module","description":"Issues affecting UI modules or its instances","color":"d2acee"},"Preview mode":{"name":"Preview mode","description":"Issues related to app previews","color":"48883f"},"Git Auto-commit":{"name":"Git Auto-commit","description":"Issues related to autocommit","color":"717732"},"QA Pod":{"name":"QA Pod","description":"Issues under the QA Pod","color":"717732"},"Automation Test":{"name":"Automation Test","description":"","color":""},"Automation failures":{"name":"Automation failures","description":"","color":""},"Needs automation":{"name":"Needs automation","description":"Issues that needs automated tests","color":""},"Prepared statements":{"name":"Prepared statements","description":"Issues related to prepared statement flow","color":""},"Switch Group Widget":{"name":"Switch Group Widget","description":"Issues related to Switch group Widget","color":""},"Supervisor":{"name":"Supervisor","description":"Issues related to supervisor","color":"2c5813"},"Deployment Certificates":{"name":"Deployment Certificates","description":"Issues related to lets encrypt","color":"e148aa"},"Mock Data":{"name":"Mock Data","description":"Issues related to mock databases","color":"ebf251"},"AWS ECS":{"name":"AWS ECS","description":"Issues related to ECS Fargate","color":"e506ff"},"Publish App":{"name":"Publish App","description":"Issues related to app deployment","color":"2b4664"},"IDE Infra":{"name":"IDE Infra","description":"Issues related to the IDE infrastructure like saving changes","color":"1bb96a"},"User Profile":{"name":"User Profile","description":"Issues related to a user profile","color":"a60d34"},"Page Management":{"color":"1bb96a","name":"Page Management","description":"Issues related to configuring pages"},"Ingress":{"name":"Ingress","description":"Ingress Controller","color":"a86802"},"Nginx":{"name":"Nginx","description":"Issues related to Nginx","color":"e54195"},"Building blocks":{"name":"Building blocks","description":"Building blocks on cavas, on templates listing or drag and drop of building blocks.","color":"48883f"},"Table Inline Edit":{"name":"Table Inline Edit","description":"Issues related to inline editing","color":"60895a"},"User Session ":{"name":"User Session ","description":"For all issues/tasks related to user sessions","color":"65a3f5"},"WDS - all widgets":{"name":"WDS - all widgets","description":"all widget present in WDS","color":"2670ae"},"WDS - input widget":{"name":"WDS - input widget","description":"Issues related to input widget on WDS","color":"2670ae"},"WDS - paragraph widget":{"name":"WDS - paragraph widget","description":"issues related to paragraph widget on WDS","color":"2670ae"},"WDS - statbox widget":{"name":"WDS - statbox widget","description":"issues related to statbox widget on WDS","color":"2670ae"},"WDS - modal widget":{"name":"WDS - modal widget","description":"Issues related to modal widget on WDS","color":"2670ae"},"WDS - icon widget":{"name":"WDS - icon widget","description":"Issues related to icon widget on WDS","color":"2670ae"},"WDS - checkbox widget":{"name":"WDS - checkbox widget","description":"Issues related to checkbox widget on WDS","color":"2670ae"},"WDS - table widget":{"name":"WDS - table widget","description":"Issues related to table widget on WDS","color":"2670ae"},"WDS - keyValue widget":{"name":"WDS - keyValue widget","description":"Issues related to key-value widget on WDS","color":"2670ae"},"WDS - switch group widget":{"name":"WDS - switch group widget","description":"Issues related to switch group widget on WDS","color":"2670ae"},"WDS - theming":{"name":"WDS - theming","description":"Issues related to theming on the Anvil instance","color":"2670ae"},"Anvil POD":{"name":"Anvil POD","description":"Issue related to Anvil project","color":"5e0904"},"Anvil - theming":{"name":"Anvil - theming","description":"Issues related to theming on the Anvil instance","color":"c28de5"},"Anvil - vertical alignment":{"name":"Anvil - vertical alignment","description":"Issues related to vertical alignment on the Anvil layout","color":"c28de5"},"Anvil - layout component":{"name":"Anvil - layout component","description":"Issues related to layout component on the Anvil layout","color":"c28de5"},"Anvil - drag & drop":{"name":"Anvil - drag & drop","description":"Issues related to drag & drop experience on Anvil","color":"c28de5"},"Anvil - zones & sections":{"name":"Anvil - zones & sections","description":"Issues related to zones and sections on the Anvil layout","color":"c28de5"},"Anvil - copy paste experience":{"name":"Anvil - copy paste experience","description":"Issues related to copy paste experience on the Anvil layout","color":"c28de5"},"WDS - phone widget":{"name":"WDS - phone widget","description":"Issues related to phone widget on WDS","color":"c28de5"},"WDS - responsive widget":{"name":"WDS - responsive widget","description":"All issues related to widget responsiveness","color":"11ee05"},"Anvil - responsive viewport":{"color":"11ee05","name":"Anvil - responsive viewport","description":"Issues seen on different viewports like mobile"},"WDS - widget styling":{"color":"11ee05","name":"WDS - widget styling","description":"all about widget styling"},"Anvil - spacing":{"name":"Anvil - spacing","description":"Related to spacing between widgets in auto layout","color":"11ee05"},"Anvil - responsive canvas":{"name":"Anvil - responsive canvas","description":"All issues related to canvas responsiveness","color":"11ee05"},"WDS - inline button widget":{"name":"WDS - inline button widget","description":"Issues related to inline button widget on WDS","color":"7cef83"},"Activation Pod":{"name":"Activation Pod","description":"for Activation group","color":"d67d00"},"Activation":{"name":"Activation","description":"for Activation group","color":"d67d00"},"Tests":{"name":"Tests","description":"Test issues","color":"4fc7b6"},"Ballpark: XXS":{"name":"Ballpark: XXS","description":"~1xDev in 1/2xSprint","color":""},"Ballpark: XS":{"name":"Ballpark: XS","description":"~1xDev in 1xSprint","color":"53bf71"},"Ballpark: S":{"name":"Ballpark: S","description":"~2xDev in 1xSprint","color":"6e9e65"},"Ballpark: M":{"name":"Ballpark: M","description":"~1xPOD in 1xSprint","color":"2229e6"},"Ballpark: L":{"name":"Ballpark: L","description":"~1xPOD in 3xSprint or 2xPODs in 1xSprint","color":"49962f"},"Ballpark: XL":{"name":"Ballpark: XL","description":"~1xPOD in 1xQuarter or 2xPODs in 2xSprint","color":"b524c9"},"Ballpark: XXL":{"name":"Ballpark: XXL","description":"~2xPODs in 1xQuarter","color":"22092c"},"Auto-commit":{"name":"Auto-commit","description":"Issues related to auto-generated commits showing up on git ","color":"e25b89"},"Continuous Deployment":{"name":"Continuous Deployment","description":"Issues related to CD pipeline on git","color":"aea47c"},"Default branch":{"name":"Default branch","description":"Issues related to using a default branch on git","color":"195737"},"Git status":{"name":"Git status","description":"Issues related to information shown on git status modal or number of changes appearing in a branch","color":"c851b8"},"Git performance":{"name":"Git performance","description":"Issues related to perceived performance on any git operation","color":"189af6"},"Anvil team":{"name":"Anvil team","description":"issues related to the new layout system anvil","color":"798200"},"SDLC":{"name":"SDLC","description":"Issues related to software development lifecycle experiences","color":"bae511"},"Reconnect DS modal":{"name":"Reconnect DS modal","description":"Issues related to reconnect datasource modal post app import","color":"2e398b"},"Stability Pod":{"name":"Stability Pod","description":"For all issues/tasks to be prioritized under Stability pod","color":"86ddf6"},"Stability Issue":{"name":"Stability Issue","description":"Every issue handle by Stability Pod","color":"4d024a"},"Move to Postgres":{"name":"Move to Postgres","description":"Issues required to be solved for the move to Postgres as repository layer","color":"466ab1"},"User Session":{"name":"User Session","description":"Issues related to user sessions","color":"8255e5"},"IDE tabs":{"name":"IDE tabs","description":"query and js tabs","color":"1bb96a"},"Inviting Contribution":{"name":"Inviting Contribution","description":"Issues that we would like contributions to","color":""},"cypress-flaky-fix":{"name":"cypress-flaky-fix","description":"This label is auto-added when a PR which only has Cypress fixes are merged to release","color":"cd8bb6"},"Cypress flaky tests":{"name":"Cypress flaky tests","description":"Test scripts that need to be fixed on Cypress by dev or SDET","color":"722cbc"},"Help enterprise":{"name":"Help enterprise","description":"Requested by Appsmith customers or prospects","color":"FF8C00"},"Learnability":{"name":"Learnability","description":"Issues affecting the product learnability, making the product harder for new users.","color":"800c2f"},"ADS Spacing":{"name":"ADS Spacing","description":"","color":"686ebb"},"ads unit test":{"name":"ads unit test","description":"All issue related ads unit cases","color":"686ebb"},"ads revamp":{"name":"ads revamp","description":"All issues related to ads revamp.","color":"686ebb"},"Javascript Product":{"color":"709a21","name":"Javascript Product","description":"Issues related to users writing javascript in appsmith"},"IDE Product":{"color":"1bb96a","name":"IDE Product","description":"Issues related to the IDE Product"},"IDE Pod":{"color":"1bb96a","name":"IDE Pod","description":"Issues that new developers face while exploring the IDE"},"Accelerators Product":{"name":"Accelerators Product","description":"Issues related to app building accelerators","color":"f3fce6"},"Templates Product":{"name":"Templates Product","description":"Issues related to Templates","color":"f3fce6"},"Design System Product":{"name":"Design System Product","description":"Appsmith design system related issues","color":"2b4664"},"ads deduplication":{"name":"ads deduplication","description":"Replacing component with ADS components","color":"708943"},"Admin Settings Product":{"color":"708943","name":"Admin Settings Product","description":"Issues in admin settings pages"},"Appsmith AI":{"name":"Appsmith AI","description":"All issues related to the Appsmith AI datasource","color":"708943"},"Query & JS Pod":{"color":"709a21","name":"Query & JS Pod","description":"Issues related to the query & JS Pod"},"RBAC Product":{"name":"RBAC Product","description":"Issues, requests and enhancements around RBAC.","color":""},"Workspace Product":{"name":"Workspace Product","description":"Issues related to workspaces","color":""},"CE Instance Usage":{"name":"CE Instance Usage","description":"For all issues relating to usage, licensing or billing on the CE instance","color":""},"Billing & Licensing Product":{"name":"Billing & Licensing Product","description":"Issues pertaining to licensing, billing and usage across self serve and enterprise customers","color":"466ab1"},"Platform Administration Pod":{"color":"446925","name":"Platform Administration Pod","description":"Issues related to platform administration & management"},"DB Infrastructure Pod":{"name":"DB Infrastructure Pod","description":"Pod to handle database infrastructure","color":"446925"},"Packages Product":{"name":"Packages Product","description":"Issues related to packages","color":"7e018f"},"Workflows Product":{"name":"Workflows Product","description":"Issues related to the workflows product","color":"446925"},"Debugger Product":{"color":"857f58","name":"Debugger Product","description":"Issues related to the debugger"},"Packages Pod":{"name":"Packages Pod","description":"issues that belong to the packages pod","color":"53742c"},"Environments Product":{"name":"Environments Product","description":"Issues related to datasource environments","color":"857f58"},"Custom Widgets":{"name":"Custom Widgets","description":"For all issues related to the custom widget project","color":"857f58"},"Branding Product":{"name":"Branding Product","description":"All issues under branding and whitelabelling appsmith ecosystem","color":"857f58"},"Widgets & Accelerators Pod":{"name":"Widgets & Accelerators Pod","description":"Issues related to widgets & Accelerators","color":"27496a"},"Widgets Product":{"name":"Widgets Product","description":"This label groups issues related to widgets","color":"f3fce6"},"App Theming Product":{"name":"App Theming Product","description":"Items that are related to the App level theming controls epic","color":"48883f"},"UI Building Product":{"color":"48883f","name":"UI Building Product","description":"Issues related to the UI Building experience"},"Onboarding Product":{"color":"48883f","name":"Onboarding Product","description":"Issues related to onboarding new developers"},"Database Schema":{"name":"Database Schema","description":"Issues related to database schema","color":"48883f"},"Git Product":{"color":"7e018f","name":"Git Product","description":"Issues related to version control product"},"Embedding Apps Product":{"name":"Embedding Apps Product","description":"Issues related to embedding","color":"48883f"},"Integrations Product":{"name":"Integrations Product","description":"Issues related to a specific integration","color":"b9f21c"},"Feature Flagging":{"name":"Feature Flagging","description":"Anything related feature flagging","color":"4574ae"},"Audit Logs Product":{"name":"Audit Logs Product","description":"Audit trails to ensure data security","color":"4574ae"},"Identity & Authentication Product":{"name":"Identity & Authentication Product","description":"Issues related to user identity & authentication","color":"4574ae"},"Email verification":{"name":"Email verification","description":"Email verification issues","color":"4574ae"},"Artifact Platform Product":{"name":"Artifact Platform Product","description":"Issues related to the application platform","color":"4574ae"},"Git IA":{"name":"Git IA","description":"Issues related to Git IA changes","color":"df8bd6"},"Documentation Pod":{"name":"Documentation Pod","description":"Issues related to user education","color":"8c8c02"},"Branch management":{"name":"Branch management","description":"Issues related to using a branch management on git","color":"ebe6af"},"Reconfigure Datasource Modal":{"name":"Reconfigure Datasource Modal","description":"Issues related to reconfigure DS modal that comes after importing applications","color":"5ac17b"},"Setup Issues":{"name":"Setup Issues","description":"Issues related to setting up appsmith","color":"3fc837"},"Packages & Git Pod":{"name":"Packages & Git Pod","description":"All issues belonging to Packages and Git","color":"46ac0e"},"Git Platform":{"name":"Git Platform","description":"Issues related to the git & the app platform","color":"c9ab80"},"Entity Management":{"name":"Entity Management","description":"Copy / Move / Delete widgets / queries / datasources","color":"74c33c"}},"success":true} \ No newline at end of file +{"runners":[{"versioning":{"source":"milestones","type":"SemVer"},"prereleaseName":"alpha","issue":{"labels":{"Widgets Product":{"conditions":[{"label":"Button Widget","type":"hasLabel","value":true},{"label":"Chart Widget","type":"hasLabel","value":true},{"label":"Container Widget","type":"hasLabel","value":true},{"label":"Date Picker Widget","type":"hasLabel","value":true},{"label":"Select Widget","type":"hasLabel","value":true},{"label":"File Picker Widget","type":"hasLabel","value":true},{"label":"Form Widget","type":"hasLabel","value":true},{"label":"Image Widget","type":"hasLabel","value":true},{"label":"Input Widget","type":"hasLabel","value":true},{"label":"List Widget","type":"hasLabel","value":true},{"label":"MultiSelect Widget","type":"hasLabel","value":true},{"label":"Map Widget","type":"hasLabel","value":true},{"label":"Modal Widget","type":"hasLabel","value":true},{"label":"Radio Widget","type":"hasLabel","value":true},{"label":"Rich Text Editor Widget","type":"hasLabel","value":true},{"label":"Tab Widget","type":"hasLabel","value":true},{"label":"Table Widget","type":"hasLabel","value":true},{"label":"Text Widget","type":"hasLabel","value":true},{"label":"Video Widget","type":"hasLabel","value":true},{"label":"iFrame","type":"hasLabel","value":true},{"label":"Menu Button","type":"hasLabel","value":true},{"label":"Rating","type":"hasLabel","value":true},{"label":"Widget Validation","type":"hasLabel","value":true},{"label":"New Widget","type":"hasLabel","value":true},{"label":"Switch widget","type":"hasLabel","value":true},{"label":"Audio Widget","type":"hasLabel","value":true},{"label":"Icon Button Widget","type":"hasLabel","value":true},{"label":"Stat Box Widget","type":"hasLabel","value":true},{"label":"Voice Recorder Widget","type":"hasLabel","value":true},{"label":"Calendar Widget","type":"hasLabel","value":true},{"label":"Menu Button Widget","type":"hasLabel","value":true},{"label":"Divider Widget","type":"hasLabel","value":true},{"label":"Rating Widget","type":"hasLabel","value":true},{"label":"View Mode","type":"hasLabel","value":true},{"label":"Widget Property","type":"hasLabel","value":true},{"label":"Document Viewer Widget","type":"hasLabel","value":true},{"label":"Radio Group Widget","type":"hasLabel","value":true},{"label":"Currency Input Widget","type":"hasLabel","value":true},{"label":"TreeSelect","type":"hasLabel","value":true},{"label":"MultiTree Select Widget","type":"hasLabel","value":true},{"label":"Phone Input Widget","type":"hasLabel","value":true},{"label":"JSON Form","type":"hasLabel","value":true},{"label":"All Widgets","type":"hasLabel","value":true},{"label":"Button Group widget","type":"hasLabel","value":true},{"label":"Progress bar widget","type":"hasLabel","value":true},{"label":"Audio Recorder Widget","type":"hasLabel","value":true},{"label":"Camera Widget","type":"hasLabel","value":true},{"label":"Table Widget V2","type":"hasLabel","value":true},{"label":"Map Chart Widget","type":"hasLabel","value":true},{"label":"Code Scanner Widget","type":"hasLabel","value":true},{"label":"Widget keyboard accessibility","type":"hasLabel","value":true},{"label":"List Widget V2","type":"hasLabel","value":true},{"label":"Slider Widget","type":"hasLabel","value":true},{"label":"One-click Binding","type":"hasLabel","value":true},{"label":"Old widget version","type":"hasLabel","value":true},{"label":"Widget Discoverability","type":"hasLabel","value":true},{"label":"Switch Group Widget","type":"hasLabel","value":true},{"label":"Checkbox Group widget","type":"hasLabel","value":true},{"label":"Checkbox Widget","type":"hasLabel","value":true},{"label":"Table Inline Edit","type":"hasLabel","value":true},{"label":"Custom Widgets","type":"hasLabel","value":true}],"requires":1},"Javascript Product":{"conditions":[{"label":"JS Linting & Errors","type":"hasLabel","value":true},{"label":"Autocomplete","type":"hasLabel","value":true},{"label":"Evaluated Value","type":"hasLabel","value":true},{"label":"Slash Command","type":"hasLabel","value":true},{"label":"New JS Function","type":"hasLabel","value":true},{"label":"JS Usability","type":"hasLabel","value":true},{"label":"Framework Functions","type":"hasLabel","value":true},{"label":"JS Objects","type":"hasLabel","value":true},{"label":"JS Evaluation","type":"hasLabel","value":true},{"label":"Custom JS Libraries","type":"hasLabel","value":true},{"label":"Action Selector","type":"hasLabel","value":true},{"label":"Widget setter method","type":"hasLabel","value":true},{"label":"Entity Refactor","type":"hasLabel","value":true},{"label":"AST-frontend","type":"hasLabel","value":true},{"label":"Sniping Mode","type":"hasLabel","value":true},{"label":"AST-backend","type":"hasLabel","value":true}],"requires":1},"IDE Product":{"conditions":[{"label":"IDE Product","type":"hasLabel","value":true},{"label":"IDE Infra","type":"hasLabel","value":true},{"label":"IDE Navigation","type":"hasLabel","value":true},{"label":"IDE tabs","type":"hasLabel","value":true},{"label":"Omnibar","type":"hasLabel","value":true},{"label":"Entity Explorer","type":"hasLabel","value":true},{"label":"Page Management","type":"hasLabel","value":true},{"label":"Preview mode","type":"hasLabel","value":true},{"label":"Entity Management","type":"hasLabel","value":true}],"requires":1},"Accelerators Product":{"conditions":[{"label":"Generate Page","type":"hasLabel","value":true},{"label":"Building blocks","type":"hasLabel","value":true}],"requires":1},"Templates Product":{"conditions":[{"label":"Partial-import-export","type":"hasLabel","value":true},{"label":"Templates Product","type":"hasLabel","value":true}],"requires":1},"Design System Product":{"conditions":[{"label":"Design System Product","type":"hasLabel","value":true},{"label":"ADS Component Issue","type":"hasLabel","value":true},{"label":"Keyboard accessibility ","type":"hasLabel","value":true},{"label":"Toggle button","type":"hasLabel","value":true},{"label":"ADS Category Token","type":"hasLabel","value":true},{"label":"ADS Component Documentation","type":"hasLabel","value":true},{"label":"ADS Migration","type":"hasLabel","value":true},{"label":"ADS Deduplication ","type":"hasLabel","value":true},{"label":"ADS Revamp","type":"hasLabel","value":true},{"label":"ADS Deduplication","type":"hasLabel","value":true},{"label":"ADS Unit Test","type":"hasLabel","value":true},{"label":"ADS Components","type":"hasLabel","value":true},{"label":"ADS Grayscale","type":"hasLabel","value":true},{"label":"Design System","type":"hasLabel","value":true},{"label":"ADS Typography","type":"hasLabel","value":true},{"label":"ADS Visual Styles","type":"hasLabel","value":true},{"label":"ADS Component Design","type":"hasLabel","value":true},{"label":"Modal Component","type":"hasLabel","value":true},{"label":"ADS Spacing","type":"hasLabel","value":true},{"label":"ads unit test","type":"hasLabel","value":true},{"label":"ads revamp","type":"hasLabel","value":true},{"label":"ads deduplication","type":"hasLabel","value":true}],"requires":1},"RBAC Product":{"conditions":[{"label":"Invite users","type":"hasLabel","value":true},{"label":"RBAC Product","type":"hasLabel","value":true}],"requires":1},"Workspace Product":{"conditions":[{"label":"Home Page","type":"hasLabel","value":true},{"label":"Workspace Product","type":"hasLabel","value":true}],"requires":1},"Billing & Licensing Product":{"conditions":[{"label":"Customer Portal","type":"hasLabel","value":true},{"label":"Cloud Services","type":"hasLabel","value":true},{"label":"Billing","type":"hasLabel","value":true},{"label":"Self Serve","type":"hasLabel","value":true},{"label":"Enterprise Billing","type":"hasLabel","value":true},{"label":"Analytics Improvements","type":"hasLabel","value":true},{"label":"Self Serve 1.0","type":"hasLabel","value":true},{"label":"License","type":"hasLabel","value":true},{"label":"BE instance","type":"hasLabel","value":true},{"label":"Invite flow","type":"hasLabel","value":true},{"label":"CE Instance Usage","type":"hasLabel","value":true},{"label":"Feature Flagging","type":"hasLabel","value":true}],"requires":1},"Packages Product":{"conditions":[{"label":"Packages Product","type":"hasLabel","value":true}],"requires":1},"Environments Product":{"conditions":[{"label":"Environments Product","type":"hasLabel","value":true}],"requires":1},"UI Building Product":{"conditions":[{"label":"Property Pane","type":"hasLabel","value":true},{"label":"Copy Paste","type":"hasLabel","value":true},{"label":"Drag & Drop","type":"hasLabel","value":true},{"label":"Undo/Redo","type":"hasLabel","value":true},{"label":"Widgets Pane","type":"hasLabel","value":true},{"label":"UI Performance","type":"hasLabel","value":true},{"label":"Widget Grouping","type":"hasLabel","value":true},{"label":"Reflow & Resize","type":"hasLabel","value":true},{"label":"Canvas / Grid","type":"hasLabel","value":true},{"label":"Auto Height","type":"hasLabel","value":true},{"label":"Browser specific","type":"hasLabel","value":true},{"label":"Auto Layout","type":"hasLabel","value":true},{"label":"Fixed layout","type":"hasLabel","value":true},{"label":"App Navigation","type":"hasLabel","value":true}],"requires":1},"Onboarding Product":{"conditions":[{"label":"Welcome Screen","type":"hasLabel","value":true}],"requires":1},"Git Product":{"conditions":[{"label":"Git Product","type":"hasLabel","value":true},{"label":"Git Auto-commit","type":"hasLabel","value":true},{"label":"Auto-commit","type":"hasLabel","value":true},{"label":"Continuous Deployment","type":"hasLabel","value":true},{"label":"Default branch","type":"hasLabel","value":true},{"label":"Git status","type":"hasLabel","value":true},{"label":"Git performance","type":"hasLabel","value":true},{"label":"SDLC","type":"hasLabel","value":true},{"label":"Git IA","type":"hasLabel","value":true},{"label":"Branch management","type":"hasLabel","value":true}],"requires":1},"Embedding Apps Product":{"conditions":[{"label":"Embedding Apps Product","type":"hasLabel","value":true}],"requires":1},"Integrations Product":{"conditions":[{"label":"New Datasource","type":"hasLabel","value":true},{"label":"Firestore","type":"hasLabel","value":true},{"label":"Google Sheets","type":"hasLabel","value":true},{"label":"Mongo","type":"hasLabel","value":true},{"label":"Redshift","type":"hasLabel","value":true},{"label":"snowflake","type":"hasLabel","value":true},{"label":"S3","type":"hasLabel","value":true},{"label":"Redis","type":"hasLabel","value":true},{"label":"Postgres","type":"hasLabel","value":true},{"label":"GraphQL Plugin","type":"hasLabel","value":true},{"label":"ArangoDB","type":"hasLabel","value":true},{"label":"MsSQL","type":"hasLabel","value":true},{"label":"Elastic Search","type":"hasLabel","value":true},{"label":"OAuth","type":"hasLabel","value":true},{"label":"Airtable","type":"hasLabel","value":true},{"label":"CURL","type":"hasLabel","value":true},{"label":"DynamoDB","type":"hasLabel","value":true},{"label":"Zendesk","type":"hasLabel","value":true},{"label":"Hubspot","type":"hasLabel","value":true},{"label":"Query Forms","type":"hasLabel","value":true},{"label":"Twilio","type":"hasLabel","value":true},{"label":"MySQL","type":"hasLabel","value":true},{"label":"Connection pool","type":"hasLabel","value":true},{"label":"MariaDB","type":"hasLabel","value":true},{"label":"Integrations Pod General","type":"hasLabel","value":true},{"label":"SMTP plugin","type":"hasLabel","value":true},{"label":"Oracle SQL DB","type":"hasLabel","value":true},{"label":"Query filter","type":"hasLabel","value":true},{"label":"Activation - datasources","type":"hasLabel","value":true},{"label":"REST API","type":"hasLabel","value":true},{"label":"REST API","type":"hasLabel","value":true},{"label":"Datasources","type":"hasLabel","value":true},{"label":"REST API plugin","type":"hasLabel","value":true},{"label":"Prepared statements","type":"hasLabel","value":true},{"label":"Query Generation","type":"hasLabel","value":true},{"label":"Core Query Execution","type":"hasLabel","value":true},{"label":"Query Management","type":"hasLabel","value":true},{"label":"Query Settings","type":"hasLabel","value":true},{"label":"Query performance","type":"hasLabel","value":true},{"label":"Datatype issue","type":"hasLabel","value":true},{"label":"SmartSubstitution","type":"hasLabel","value":true},{"label":"Suggested Widgets","type":"hasLabel","value":true},{"label":"SAAS Plugins","type":"hasLabel","value":true},{"label":"Reconnect DS modal","type":"hasLabel","value":true},{"label":"OnPageLoad","type":"hasLabel","value":true},{"label":"File upload issues","type":"hasLabel","value":true},{"label":"AI","type":"hasLabel","value":true},{"label":"Appsmith AI","type":"hasLabel","value":true},{"label":"Database Schema","type":"hasLabel","value":true}],"requires":1},"Identity & Authentication Product":{"conditions":[{"label":"Login / Signup","type":"hasLabel","value":true},{"label":"SSO","type":"hasLabel","value":true},{"label":"SCIM","type":"hasLabel","value":true},{"label":"Email verification","type":"hasLabel","value":true}],"requires":1},"Artifact Platform Product":{"conditions":[{"label":"Fork App","type":"hasLabel","value":true},{"label":"Publish App","type":"hasLabel","value":true},{"label":"Secret Management","type":"hasLabel","value":true},{"label":"Import-Export-App","type":"hasLabel","value":true}],"requires":1},"DevOps Pod":{"conditions":[{"label":"Docker","type":"hasLabel","value":true},{"label":"Super Admin","type":"hasLabel","value":true},{"label":"Deployment","type":"hasLabel","value":true},{"label":"K8s","type":"hasLabel","value":true},{"label":"Email Config","type":"hasLabel","value":true},{"label":"Backup & Restore","type":"hasLabel","value":true},{"label":"AWS AMI","type":"hasLabel","value":true},{"label":"Observability","type":"hasLabel","value":true},{"label":"Heroku","type":"hasLabel","value":true},{"label":"New Deployment Mode","type":"hasLabel","value":true},{"label":"Supervisor","type":"hasLabel","value":true},{"label":"Deployment Certificates","type":"hasLabel","value":true},{"label":"Mock Data","type":"hasLabel","value":true},{"label":"AWS ECS","type":"hasLabel","value":true},{"label":"Ingress","type":"hasLabel","value":true},{"label":"Nginx","type":"hasLabel","value":true},{"label":"Setup Issues","type":"hasLabel","value":true}],"requires":1},"Performance Pod":{"conditions":[{"label":"Performance","type":"hasLabel","value":true},{"label":"Performance infra","type":"hasLabel","value":true}],"requires":1},"IDE Pod":{"conditions":[{"label":"Telemetry","type":"hasLabel","value":true},{"label":"i18n","type":"hasLabel","value":true},{"label":"IDE Product","type":"hasLabel","value":true},{"label":"App setting","type":"hasLabel","value":true},{"label":"Debugger Product","type":"hasLabel","value":true},{"label":"Embedding Apps Product","type":"hasLabel","value":true}],"requires":1},"Platform Administration Pod":{"conditions":[{"label":"Airgap","type":"hasLabel","value":true},{"label":"Enterprise Edition","type":"hasLabel","value":true},{"label":"Invite flow","type":"hasLabel","value":true},{"label":"User Profile","type":"hasLabel","value":true},{"label":"User Session ","type":"hasLabel","value":true},{"label":"User Session","type":"hasLabel","value":true},{"label":"Admin Settings Product","type":"hasLabel","value":true},{"label":"RBAC Product","type":"hasLabel","value":true},{"label":"Workspace Product","type":"hasLabel","value":true},{"label":"Branding Product","type":"hasLabel","value":true},{"label":"Audit Logs Product","type":"hasLabel","value":true},{"label":"Identity & Authentication Product","type":"hasLabel","value":true},{"label":"Billing & Licensing Product","type":"hasLabel","value":true},{"label":"Move to Postgres","type":"hasLabel","value":true}],"requires":1},"DB Infrastructure Pod":{"conditions":[],"requires":1},"Widgets & Accelerators Pod":{"conditions":[{"label":"Accelerators Product","type":"hasLabel","value":true},{"label":"Templates Product","type":"hasLabel","value":true},{"label":"Widgets Product","type":"hasLabel","value":true},{"label":"App Theming Product","type":"hasLabel","value":true}],"requires":1},"Packages Pod":{"conditions":[{"label":"Module creator","type":"hasLabel","value":true},{"label":"Module consumer","type":"hasLabel","value":true},{"label":"Package versioning","type":"hasLabel","value":true},{"label":"Convert to module","type":"hasLabel","value":true},{"label":"Query module","type":"hasLabel","value":true},{"label":"JS module","type":"hasLabel","value":true},{"label":"UI module","type":"hasLabel","value":true},{"label":"Packages Pod","type":"hasLabel","value":true}],"requires":1},"Workflows Pod":{"conditions":[{"label":"Workflows Product","type":"hasLabel","value":true}],"requires":1},"Query & JS Pod":{"conditions":[{"label":"Javascript Product","type":"hasLabel","value":true},{"label":"Onboarding Product","type":"hasLabel","value":true},{"label":"Integrations Product","type":"hasLabel","value":true},{"label":"Reconfigure Datasource Modal","type":"hasLabel","value":true}],"requires":1},"QA Pod":{"conditions":[{"label":"QA","type":"hasLabel","value":true},{"label":"Automation Test","type":"hasLabel","value":true},{"label":"TestGap","type":"hasLabel","value":true},{"label":"Automation failures","type":"hasLabel","value":true},{"label":"Needs automation","type":"hasLabel","value":true},{"label":"cypress-flaky-fix","type":"hasLabel","value":true},{"label":"Cypress flaky tests","type":"hasLabel","value":true}],"requires":1},"Anvil POD":{"conditions":[{"label":"Checkbox Component","type":"hasLabel","value":true},{"label":"WDS team","type":"hasLabel","value":true},{"label":"Anvil POD","type":"hasLabel","value":true},{"label":"WDS - all widgets","type":"hasLabel","value":true},{"label":"WDS - input widget","type":"hasLabel","value":true},{"label":"WDS - paragraph widget","type":"hasLabel","value":true},{"label":"WDS - statbox widget","type":"hasLabel","value":true},{"label":"WDS - modal widget","type":"hasLabel","value":true},{"label":"WDS - icon widget","type":"hasLabel","value":true},{"label":"WDS - checkbox widget","type":"hasLabel","value":true},{"label":"WDS - table widget","type":"hasLabel","value":true},{"label":"WDS - keyValue widget","type":"hasLabel","value":true},{"label":"WDS - switch group widget","type":"hasLabel","value":true},{"label":"WDS - theming","type":"hasLabel","value":true},{"label":"Anvil layout","type":"hasLabel","value":true},{"label":"Anvil - theming","type":"hasLabel","value":true},{"label":"Anvil - vertical alignment","type":"hasLabel","value":true},{"label":"Anvil - layout component","type":"hasLabel","value":true},{"label":"Anvil - drag & drop","type":"hasLabel","value":true},{"label":"Anvil - zones & sections","type":"hasLabel","value":true},{"label":"Anvil - copy paste experience","type":"hasLabel","value":true},{"label":"WDS - phone widget","type":"hasLabel","value":true},{"label":"WDS - responsive widget","type":"hasLabel","value":true},{"label":"Anvil - responsive viewport","type":"hasLabel","value":true},{"label":"WDS - widget styling","type":"hasLabel","value":true},{"label":"Anvil - spacing","type":"hasLabel","value":true},{"label":"Anvil - responsive canvas","type":"hasLabel","value":true},{"label":"WDS - inline button widget","type":"hasLabel","value":true},{"label":"Anvil team","type":"hasLabel","value":true}],"requires":1},"Activation Pod":{"conditions":[{"label":"Activation","type":"hasLabel","value":true}],"requires":1},"Stability Pod":{"conditions":[{"label":"Stability Issue","type":"hasLabel","value":true}],"requires":1},"Documentation Pod":{"conditions":[{"label":"Documentation","type":"hasLabel","value":true}],"requires":1},"Packages & Git Pod":{"conditions":[{"label":"Packages Pod","type":"hasLabel","value":true},{"label":"Git Product","type":"hasLabel","value":true},{"label":"Packages Product","type":"hasLabel","value":true},{"label":"Git Platform","type":"hasLabel","value":true}],"requires":1},"Git Platform":{"conditions":[{"label":"Environments Product","type":"hasLabel","value":true},{"label":"Artifact Platform Product","type":"hasLabel","value":true}],"requires":1}}},"root":"."}],"labels":{"Tab Widget":{"color":"e2c76c","name":"Tab Widget","description":""},"Dont merge":{"color":"ADB39C","name":"Dont merge","description":""},"Epic":{"color":"3E4B9E","name":"Epic","description":"A zenhub epic that describes a project"},"Menu Button Widget":{"color":"235708","name":"Menu Button Widget","description":"Issues related to Menu Button widget"},"Checkbox Group widget":{"color":"bbeecd","name":"Checkbox Group widget","description":"Issues related to Checkbox Group Widget"},"Input Widget":{"color":"ae65d8","name":"Input Widget","description":""},"Security":{"color":"99139C","name":"Security","description":""},"QA":{"color":"","name":"QA","description":"Needs QA attention"},"Verified":{"color":"9bf416","name":"Verified","description":""},"Wont Fix":{"color":"ffffff","name":"Wont Fix","description":"This will not be worked on"},"MySQL":{"color":"c9ddc6","name":"MySQL","description":"Issues related to MySQL plugin"},"Development":{"color":"9F8A02","name":"Development","description":""},"Help Wanted":{"color":"008672","name":"Help Wanted","description":"Extra attention is needed"},"Home Page":{"color":"","name":"Home Page","description":"Issues related to the application home page"},"Rating Widget":{"color":"235708","name":"Rating Widget","description":"Issues related to the rating widget"},"Stat Box Widget":{"color":"f1c9ce","name":"Stat Box Widget","description":"Issues related to stat box"},"Enhancement":{"color":"a2eeef","name":"Enhancement","description":"New feature or request"},"Fork App":{"color":"af87c7","name":"Fork App","description":"Issues related to forking apps"},"Container Widget":{"color":"19AD0D","name":"Container Widget","description":"Container widget"},"Papercut":{"color":"B562F6","name":"Papercut","description":""},"Needs Design":{"color":"bfd4f2","name":"Needs Design","description":"needs design or changes to design"},"i18n":{"color":"1799b0","name":"i18n","description":"Represents issues that need to be tackled to handle internationalization"},"Rich Text Editor Widget":{"color":"f72cac","name":"Rich Text Editor Widget","description":""},"skip-changelog":{"color":"06086F","name":"skip-changelog","description":"Adding this label to a PR prevents it from being listed in the changelog"},"Low":{"color":"79e53b","name":"Low","description":"An issue that is neither critical nor breaks a user flow"},"potential-duplicate":{"color":"d3cb2e","name":"potential-duplicate","description":"This label marks issues that are potential duplicates of already open issues"},"Audio Widget":{"color":"447B9A","name":"Audio Widget","description":"Issues related to Audio Widget"},"Firestore":{"color":"8078b0","name":"Firestore","description":"Issues related to the firestore Integration"},"New Widget":{"color":"be4cf2","name":"New Widget","description":"A request for a new widget"},"Modal Widget":{"color":"03846f","name":"Modal Widget","description":""},"UX Improvement":{"color":"f4a089","name":"UX Improvement","description":""},"S3":{"color":"8078b0","name":"S3","description":"Issues related to the S3 plugin"},"Release Blocker":{"color":"5756bf","name":"Release Blocker","description":"This issue must be resolved before the release"},"safari":{"color":"51C6AA","name":"safari","description":"Bugs seen on safari browser"},"Example Apps":{"color":"1799b0","name":"Example Apps","description":"Example apps created for new signups"},"MultiSelect Widget":{"color":"AB62D4","name":"MultiSelect Widget","description":"Issues related to MultiSelect Widget"},"Calendar Widget":{"color":"8c6644","name":"Calendar Widget","description":""},"Website":{"color":"151720","name":"Website","description":"Related to www.appsmith.com website"},"Low effort":{"color":"8B59F0","name":"Low effort","description":"Something that'll take a few days to build"},"Checkbox Widget":{"color":"bbeecd","name":"Checkbox Widget","description":""},"Spam":{"color":"620faf","name":"Spam","description":""},"Voice Recorder Widget":{"color":"85bc87","name":"Voice Recorder Widget","description":""},"Select Widget":{"color":"0c669e","name":"Select Widget","description":"Select or dropdown widget"},"Bug":{"color":"8ba6fd","name":"Bug","description":"Something isn't right"},"Widget Validation":{"color":"6990BC","name":"Widget Validation","description":"Issues related to widget property validation"},"Generate Page":{"color":"2b4664","name":"Generate Page","description":"Issures related to page generation"},"File Picker Widget":{"color":"6ae4f2","name":"File Picker Widget","description":""},"snowflake":{"color":"8078b0","name":"snowflake","description":"Issues related to the snowflake Integration"},"Automation":{"color":"CCAF60","name":"Automation","description":""},"hotfix":{"color":"BA3F1D","name":"hotfix","description":""},"Import-Export-App":{"color":"48883f","name":"Import-Export-App","description":"Issues related to importing and exporting apps"},"High effort":{"color":"A7E87B","name":"High effort","description":"Something that'll take more than a month to build"},"Telemetry":{"color":"bc70f9","name":"Telemetry","description":"Issues related to instrumenting appsmith"},"Radio Widget":{"color":"91ef15","name":"Radio Widget","description":""},"Omnibar":{"color":"1bb96a","name":"Omnibar","description":"Issues related to the omnibar for navigation"},"Button Widget":{"color":"34efae","name":"Button Widget","description":""},"Switch widget":{"color":"33A8CE","name":"Switch widget","description":"The switch widget"},"Map Widget":{"color":"7eef7a","name":"Map Widget","description":""},"Task":{"color":"085630","name":"Task","description":"A simple Todo"},"Design System":{"color":"2958a4","name":"Design System","description":"Design system"},"opera":{"color":"C63F5B","name":"opera","description":"Any issues identified on the opera browser"},"Login / Signup":{"color":"","name":"Login / Signup","description":"Authentication flows"},"Image Widget":{"color":"8de8ad","name":"Image Widget","description":""},"firefox":{"color":"6d56e2","name":"firefox","description":""},"Property Pane":{"color":"b356ff","name":"Property Pane","description":"Issues related to the behaviour of the property pane"},"Deployment":{"color":"93491f","name":"Deployment","description":"Installation process of appsmith"},"Production":{"color":"b60205","name":"Production","description":""},"Dependencies":{"color":"0366d6","name":"Dependencies","description":"Pull requests that update a dependency file"},"Google Sheets":{"color":"8078b0","name":"Google Sheets","description":"Issues related to Google Sheets"},"Icon Button Widget":{"color":"D319CE","name":"Icon Button Widget","description":"Issues related to the icon button widget"},"Mongo":{"color":"8078b0","name":"Mongo","description":"Issues related to Mongo DB plugin"},"Documentation":{"color":"a8dff7","name":"Documentation","description":"Improvements or additions to documentation"},"TestGap":{"color":"","name":"TestGap","description":"Issues identified for test plan improvement"},"keyboard shortcut":{"color":"0688B6","name":"keyboard shortcut","description":""},"Reopen":{"color":"897548","name":"Reopen","description":""},"Redshift":{"color":"8078b0","name":"Redshift","description":"Issues related to the redshift integration"},"Date Picker Widget":{"color":"ef1ce1","name":"Date Picker Widget","description":""},"Entity Explorer":{"color":"1bb96a","name":"Entity Explorer","description":"Issues related to navigation using the entity explorer"},"JS Linting & Errors":{"color":"E56AA5","name":"JS Linting & Errors","description":"Issues related to JS Linting and errors"},"iFrame":{"color":"3CD1DB","name":"iFrame","description":"Issues related to iFrame"},"Stale":{"color":"ededed","name":"Stale","description":null},"Text Widget":{"color":"d130d1","name":"Text Widget","description":""},"Video Widget":{"color":"23dd4b","name":"Video Widget","description":""},"Datasources":{"color":"3d590f","name":"Datasources","description":"Issues related to configuring datasource on appsmith"},"error":{"color":"B66773","name":"error","description":"All issues connected to error messages"},"Form Widget":{"color":"09ed77","name":"Form Widget","description":""},"Needs Triaging":{"color":"e8b851","name":"Needs Triaging","description":"Needs attention from maintainers to triage"},"Autocomplete":{"color":"235708","name":"Autocomplete","description":"Issues related to the autocomplete"},"hacktoberfest":{"color":"0052cc","name":"hacktoberfest","description":"All issues that can be solved by the community during Hacktoberfest"},"Medium effort":{"color":"D31156","name":"Medium effort","description":"Something that'll take more than a week but less than a month to build"},"Release":{"color":"57e5e0","name":"Release","description":""},"High":{"color":"c94d14","name":"High","description":"This issue blocks a user from building or impacts a lot of users"},"UI Performance":{"color":"1799b0","name":"UI Performance","description":"Issues related to UI performance"},"Deploy Preview":{"color":"bfdadc","name":"Deploy Preview","description":"Issues found in Deploy Preview"},"Needs Tests":{"color":"8ee263","name":"Needs Tests","description":"Needs automated tests to assert a feature/bug fix"},"Refactor":{"color":"B96662","name":"Refactor","description":"needs refactoring of code"},"Divider Widget":{"color":"235708","name":"Divider Widget","description":"Issues related to the divider widget"},"Table Widget":{"color":"2eead1","name":"Table Widget","description":""},"Needs More Info":{"color":"e54c10","name":"Needs More Info","description":"Needs additional information"},"Good First Issue":{"color":"7057ff","name":"Good First Issue","description":"Good for newcomers"},"UI Improvement":{"color":"9aeef4","name":"UI Improvement","description":""},"Backend":{"color":"d4c5f9","name":"Backend","description":"This marks the issue or pull request to reference server code"},"Frontend":{"color":"87c7f2","name":"Frontend","description":"This label marks the issue or pull request to reference client code"},"Chart Widget":{"color":"616ecc","name":"Chart Widget","description":""},"List Widget":{"color":"8508A0","name":"List Widget","description":"Issues related to the list widget"},"Duplicate":{"color":"cfd3d7","name":"Duplicate","description":"This issue or pull request already exists"},"JS Snippets":{"color":"8d62d2","name":"JS Snippets","description":"issues related to JS Snippets"},"Copy Paste":{"name":"Copy Paste","description":"Issues related to copy paste","color":"b4f0a9"},"Drag & Drop":{"name":"Drag & Drop","description":"Issues related to the drag & drop experience","color":"92115a"},"Sniping Mode":{"name":"Sniping Mode","description":"Issues related to sniping mode","color":"48883f"},"Redis":{"name":"Redis","description":"Issues related to Redis","color":"8078b0"},"New Datasource":{"color":"60b14c","name":"New Datasource","description":"Requests for new datasources"},"Evaluated Value":{"name":"Evaluated Value","description":"Issues related to evaluated values","color":"39f6e7"},"Undo/Redo":{"name":"Undo/Redo","description":"Issues related to undo/redo","color":"f25880"},"App Navigation":{"name":"App Navigation","description":"Issues related to the topbar navigation and configuring it","color":"4773ab"},"Widgets Pane":{"name":"Widgets Pane","description":"Issues related to the discovery and organisation of widgets","color":"ad5d78"},"View Mode":{"color":"1799b0","name":"View Mode","description":"Issues related to the view mode"},"Content":{"name":"Content","description":"For content related topics i.e blogs, templates, videos","color":"a8dff7"},"Slash Command":{"name":"Slash Command","description":"Issues related to the slash command","color":"a0608e"},"Widget Property":{"name":"Widget Property","description":"Issues related to adding / modifying widget properties across widgets","color":"5e92cb"},"Windows":{"name":"Windows","description":"Issues related exclusively to Windows systems","color":"b4cb8a"},"Old App Issues":{"name":"Old App Issues","description":"Issues related to apps old apps a few weeks old and app issues in stale browser session","color":"87ab18"},"Document Viewer Widget":{"name":"Document Viewer Widget","description":"Issues related to Document Viewer Widget","color":"899d4b"},"Radio Group Widget":{"name":"Radio Group Widget","description":"Issues related to radio group widget","color":"b68495"},"Super Admin":{"name":"Super Admin","description":"Issues related to the super admin page","color":"aa95cf"},"Postgres":{"name":"Postgres","description":"Postgres related issues","color":"8078b0"},"New JS Function":{"name":"New JS Function","description":"Issues related to adding a JS Function","color":"8e8aa4"},"Cannot Reproduce Issue":{"color":"93c9cc","name":"Cannot Reproduce Issue","description":"Issues that cannot be reproduced"},"Widget Grouping":{"name":"Widget Grouping","description":"Issues related to Widget Grouping","color":"a49951"},"K8s":{"name":"K8s","description":"Kubernetes related issues","color":"5f318a"},"Docker":{"name":"Docker","description":"Issues related to docker","color":"89b808"},"Camera Widget":{"name":"Camera Widget","description":"Issues and enhancements related to camera widget","color":"e6038e"},"SAAS Plugins":{"name":"SAAS Plugins","description":"Issues related to SAAS Plugins","color":"80e18f"},"JS Promises":{"name":"JS Promises","description":"Issues related to promises","color":"d7771f"},"OnPageLoad":{"name":"OnPageLoad","description":"OnPageLoad issues on functions and queries","color":"2b4664"},"JS Usability":{"name":"JS Usability","description":"usability issues with JS editor and JS elsewhere","color":"a302b0"},"Currency Input Widget":{"name":"Currency Input Widget","description":"Issues related to currency input widget","color":"b2164f"},"TreeSelect":{"name":"TreeSelect","description":"Issues related to TreeSelect Widget","color":"a1633e"},"MultiTree Select Widget":{"name":"MultiTree Select Widget","description":"Issues related to MultiTree Select Widget","color":"a1633e"},"Welcome Screen":{"name":"Welcome Screen","description":"Issues related to the welcome screen","color":"48883f"},"Realtime Commenting":{"color":"a70b86","name":"Realtime Commenting","description":"In-app communication between teams"},"Phone Input Widget":{"name":"Phone Input Widget","description":"Issues related to the Phone Input widget","color":"a70b86"},"JSON Form":{"name":"JSON Form","description":"Issue / features related to the JSON form wiget","color":"46b209"},"All Widgets":{"name":"All Widgets","description":"Issues related to all widgets","color":"972b36"},"V1":{"name":"V1","description":"V1","color":"67ab2e"},"Reflow & Resize":{"name":"Reflow & Resize","description":"All issues related to reflow and resize experience","color":"748a13"},"SSO":{"name":"SSO","description":"Issues, requests and enhancements around Single sign-on.","color":""},"Multi User Realtime":{"name":"Multi User Realtime","description":"Issues related to multiple users using or editing an application","color":"e7b6ce"},"Ready for design":{"name":"Ready for design","description":"this issue is ready for design: it contains clear problem statements and other required information","color":"ebf442"},"Support":{"name":"Support","description":"Issues created by the A-force team to address user queries","color":"1740f3"},"Button Group widget":{"name":"Button Group widget","description":"Issue and enhancements related to the button group widget","color":"f17025"},"GraphQL Plugin":{"name":"GraphQL Plugin","description":"Issues related to GraphQL plugin","color":"8078b0"},"DevOps Pod":{"name":"DevOps Pod","description":"Issues related to devops","color":"d956c7"},"medium":{"name":"medium","description":"Issues that frustrate users due to poor UX","color":"23dfd9"},"ArangoDB":{"name":"ArangoDB","description":"Issues related to arangoDB","color":"8078b0"},"Code Refactoring":{"name":"Code Refactoring","description":"Issues related to code refactoring","color":"76310e"},"Progress bar widget":{"name":"Progress bar widget","description":"To track issues related to progress bar","color":"2d7abf"},"Audio Recorder Widget":{"name":"Audio Recorder Widget","description":"Issues related to Audio Recorder Widget","color":"9accef"},"Airtable":{"name":"Airtable","description":"Issues for Airtable","color":"60885f"},"Canvas / Grid":{"name":"Canvas / Grid","description":"Issues related to the canvas","color":"16b092"},"Email Config":{"name":"Email Config","description":"Issues related to configuring the email service","color":"2a21d1"},"CURL":{"name":"CURL","description":"Issues related to CURL impor","color":"60885f"},"Canvas Zooms":{"name":"Canvas Zooms","description":"Issues related to zooming the canvas","color":"e6038e"},"business":{"name":"business","description":"Features that will be a part of our business edition","color":"cd59eb"},"Action Pod":{"name":"Action Pod","description":"","color":"ee2e36"},"AutomationGap1":{"color":"a5e07c","name":"AutomationGap1","description":"Issues that needs automated tests"},"A-Force11":{"name":"A-Force11","description":"Issues raised by A-Force team","color":"d667b6"},"Business Edition":{"name":"Business Edition","description":"Features that will be a part of our business edition","color":"89bb6c"},"storeValue":{"name":"storeValue","description":"Issues related to the store value function","color":"5d3e66"},"DynamoDB":{"name":"DynamoDB","description":"Issues that are related to DynamoDB should have this label","color":"60885f"},"Backup & Restore":{"name":"Backup & Restore","description":"Issues related to backup and restore","color":"86874d"},"Billing":{"name":"Billing","description":"Billing infrastructure and flows for Business Edition and Trial users","color":"d2bc40"},"Datatype issue":{"name":"Datatype issue","description":"Issues that have risen because data types weren't handled","color":"cef66b"},"OAuth":{"name":"OAuth","description":"OAuth related bugs or features","color":"60885f"},"Table Widget V2":{"name":"Table Widget V2","description":"Issues related to Table Widget V2","color":"3a7192"},"IDE Navigation":{"name":"IDE Navigation","description":"Issues/feature requests related to IDE navigation, and context switching","color":"1bb96a"},"Query performance":{"name":"Query performance","description":"Issues that have to do with lack in performance of query execution","color":"cef66b"},"SAAS Manager App":{"name":"SAAS Manager App","description":"Issues with the SAAS manager app","color":"d427db"},"Twilio":{"name":"Twilio","description":"Issues related to Twilio integration","color":"23ba8d"},"Hubspot":{"name":"Hubspot","description":"Issues related to Hubspot integration","color":"60885f"},"Zendesk":{"name":"Zendesk","description":"Issues related to Zendesk integration","color":"60885f"},"Entity Refactor":{"name":"Entity Refactor","description":"Issues related to refactor logic","color":"705a2c"},"Map Chart Widget":{"name":"Map Chart Widget","description":"Issues related to Map Chart Widgets","color":"c8397f"},"Product Catchup":{"name":"Product Catchup","description":"Issues created in the product catchup","color":"29cd2c"},"Framework Functions":{"name":"Framework Functions","description":"Issues related to internal functions like showAlert(), navigateTo() etc...","color":"c25a09"},"Frontend Libraries Upgrade":{"name":"Frontend Libraries Upgrade","description":"Issues related to frontend libraries upgrade","color":"ede1fc"},"MsSQL":{"name":"MsSQL","description":"Issues related to MsSQL plugin","color":"8078b0"},"Elastic Search":{"name":"Elastic Search","description":"Issues related to the elastic search datasource","color":"8078b0"},"Core Query Execution":{"color":"cef66b","name":"Core Query Execution","description":"Issues related to the execution of all queries"},"Query Management":{"name":"Query Management","description":"Issues related to the CRUD of actions or queries","color":"cef66b"},"Query Settings":{"name":"Query Settings","description":"Issues related to the settings of all queries","color":"cef66b"},"Code Editor":{"name":"Code Editor","description":"Issues related to the code editor","color":"4ca16e"},"Query Forms":{"color":"12b253","name":"Query Forms","description":"Isuses related to the query forms"},"JS Objects":{"color":"22962c","name":"JS Objects","description":"Issues related to JS Objects"},"JS Evaluation":{"color":"22962c","name":"JS Evaluation","description":"Issues related to JS evaluation on the platform"},"SmartSubstitution":{"name":"SmartSubstitution","description":"Issues related to Smart substitution of mustache bindings in queries","color":"bae511"},"Query Generation":{"name":"Query Generation","description":"Issues related to query generation","color":"cef66b"},"Suggested Widgets":{"name":"Suggested Widgets","description":"Issues related to suggesting widgets based on query response","color":"6ac063"},"Code Scanner Widget":{"name":"Code Scanner Widget","description":"Issues related to code scanner widget","color":"9bc1a0"},"Clean URLs":{"name":"Clean URLs","description":"Issues related to clean URLs epic","color":"112623"},"Widget keyboard accessibility":{"name":"Widget keyboard accessibility","description":"All issues related to keyboard accessibility in widgets","color":"b626fd"},"Connection pool":{"name":"Connection pool","description":"issues to do with connection pooling of various plugins","color":"94fe36"},"List Widget V2":{"name":"List Widget V2","description":"Issues related to the list widget v2","color":"adaaf7"},"Auto Height":{"name":"Auto Height","description":"Issues related to dynamic height of widgets","color":"5149cf"},"cypress_failed_test":{"name":"cypress_failed_test","description":"Cypress failed tests","color":"4745d5"},"Needs validation":{"name":"Needs validation","description":"Needs problem validation before being picked up","color":"66673d"},"Slider Widget":{"name":"Slider Widget","description":"Issues raised for slider widgets.","color":"2eef5f"},"Multitenancy":{"name":"Multitenancy","description":"Support multitenancy within single appsmith instance","color":"8c49a9"},"Conversion Algorithm":{"name":"Conversion Algorithm","description":"All issue related to converting app from fixed to flex mode & vice versa","color":"d12d2e"},"Browser specific":{"name":"Browser specific","description":"All issue related to browser","color":"d12d2e"},"Performance infra":{"name":"Performance infra","description":"all issue related to the performance infra","color":"8a60f6"},"DSL Update":{"name":"DSL Update","description":"Issues related to storing and updating the DSL","color":"e16cf3"},"AST-frontend":{"name":"AST-frontend","description":"Issues related to maintaining AST logic","color":"2b4664"},"AST-backend":{"name":"AST-backend","description":"Backend issues related to AST parsing","color":"48883f"},"MariaDB":{"name":"MariaDB","description":"MariaDB datasource","color":"8428c3"},"ADS Component Issue":{"name":"ADS Component Issue","description":"Issues which are caused due to ADS components","color":"d89119"},"Regressed":{"color":"723fd0","name":"Regressed","description":"Scenarios that were working before but have now regressed"},"Needs RCA":{"name":"Needs RCA","description":"a critical or high priority issue that needs an RCA","color":"2cc68f"},"Custom JS Libraries":{"name":"Custom JS Libraries","description":"Issues related to adding custom JS library","color":"bacb6d"},"Integrations Pod General":{"name":"Integrations Pod General","description":"Issues related to the Integrations Pod that don't fit into other tags.","color":"287823"},"Performance Pod":{"name":"Performance Pod","description":"All things related to Appsmith performance","color":"b5a25d"},"Performance":{"name":"Performance","description":"Issues related to performance","color":"9a18d7"},"File upload issues":{"name":"File upload issues","description":"Issues related to uploading any type of files from within Appsmith","color":"2b4664"},"Action Selector":{"name":"Action Selector","description":"Issues related to action selector on the property pane","color":"2f9e20"},"Community Reported":{"name":"Community Reported","description":"issues reported by community members","color":"1402e5"},"JS Function execution":{"name":"JS Function execution","description":"JS function execution","color":"7c2de1"},"Self Serve":{"name":"Self Serve","description":"For all issues related to self-serve flow for business edition","color":"4dacfc"},"Self Serve 1.0":{"name":"Self Serve 1.0","description":"For all issues related to v1 of the self serve project","color":"ae839e"},"Customer Portal":{"name":"Customer Portal","description":"For all tasks/issues pertaining to customer.appsmith.com","color":"d2bc40"},"Cloud Services":{"name":"Cloud Services","description":"For all tasks/issues on Appsmith cloud-services relating to licensing, usage and billing","color":"d2bc40"},"One-click Binding":{"name":"One-click Binding","description":"Issues related to the One click binding epic","color":"f1661c"},"Airgap":{"name":"Airgap","description":"Tickets related to supporting air-gapped Appsmith instances","color":"1cb294"},"SMTP plugin":{"name":"SMTP plugin","description":"Issues related to SMTP plugin","color":"541457"},"AWS AMI":{"name":"AWS AMI","description":"Issues Related to AWS AMI","color":"b44680"},"Old widget version":{"name":"Old widget version","description":"Use this label to raise issue specific only to an older version of a widget","color":"ff3814"},"Enterprise Billing":{"name":"Enterprise Billing","description":"To track all tasks/issues related to licensing & billing for enterprise customers","color":"14c156"},"Oracle SQL DB":{"name":"Oracle SQL DB","description":"Issues related to the Oracle plugin","color":"cbabcb"},"Community Contributor":{"name":"Community Contributor","description":"Meant to track issues that are assigned to external contributors","color":"149ab6"},"widget vertical alignment":{"name":"widget vertical alignment","description":"All issue related widget vertical alignment on the auto layout canvas","color":"d12d2e"},"Observability":{"name":"Observability","description":"Issues related to observability on the Appsmith instance","color":"dff913"},"Checkbox Component":{"name":"Checkbox Component","description":"This labels deals with checkbox component in wds package","color":"75a401"},"Analytics Improvements":{"name":"Analytics Improvements","description":"For all tasks focused on improving our overall analytics and fixing any issues ","color":"29b8ed"},"WDS team":{"name":"WDS team","description":"","color":"8d675a"},"Enterprise Edition":{"name":"Enterprise Edition","description":"Features that will be supported in Enterprise Edition only","color":"984f5e"},"Query filter":{"name":"Query filter","description":"Issues related to query filtering, e.g., WHERE clause","color":"a15134"},"Keyboard accessibility ":{"name":"Keyboard accessibility ","description":"All issue related to ADS component keyboard accessibility","color":"2ba696"},"Toggle button":{"name":"Toggle button","description":"All issue related to ADS toggle button","color":"edc47f"},"SCIM":{"name":"SCIM","description":"Label to collate our SCIM issues","color":"48883f"},"ADS Category Token":{"name":"ADS Category Token","description":"All issues related appsmith design system category tokens","color":"920961"},"ADS Component Documentation":{"name":"ADS Component Documentation","description":"All issues Appsmith design system component documentation","color":"64c46a"},"ADS Migration":{"name":"ADS Migration","description":"All issues related to Appsmith design system migration","color":"b082d6"},"ADS Deduplication ":{"name":"ADS Deduplication ","description":"Replacing component with ADS components","color":"b082d6"},"ADS Revamp":{"name":"ADS Revamp","description":"All issues related to ads revamp. ","color":"b082d6"},"ADS Deduplication":{"name":"ADS Deduplication","description":"Replacing component with ADS components","color":"b082d6"},"ADS Grayscale":{"name":"ADS Grayscale","description":"Support grayscale color changes","color":"b03577"},"ADS Unit Test":{"name":"ADS Unit Test","description":"All issue related ads unit cases ","color":"b082d6"},"ADS Components":{"name":"ADS Components","description":"All issues related ADS components","color":"b082d6"},"Widget Discoverability":{"name":"Widget Discoverability","description":"Issues related to Widget Discoverability","color":"7b55ce"},"Widget setter method":{"name":"Widget setter method","description":"Issues with widget property setters","color":"8dce87"},"License":{"name":"License","description":"For all issues/tasks related to licensing of appsmith-ee edition","color":"90ee98"},"Platformization":{"name":"Platformization","description":"Issues or tasks related to platformization of Appsmith codebase","color":"4e972b"},"Activation - datasources":{"name":"Activation - datasources","description":"issues related to activation projects","color":"7c7ace"},"Partial-import-export":{"name":"Partial-import-export","description":"Label for granular reusability.","color":"717732"},"AI":{"name":"AI","description":"All tasks related to AI","color":"2b4664"},"ADS Typography":{"name":"ADS Typography","description":"All issue related typographical changes","color":"2dbe8d"},"Auto Layout":{"name":"Auto Layout","description":"Issues relates to auto layout","color":"92cf8c"},"Heroku":{"name":"Heroku","description":"Issues related to Heroku","color":"a81b69"},"ADS Visual Styles":{"name":"ADS Visual Styles","description":"All issues related to ADS visual styles","color":"d3da89"},"ADS Component Design":{"name":"ADS Component Design","description":"All issue related to component design","color":"5cc91e"},"Modal Component":{"name":"Modal Component","description":"All issue related to ads modal component","color":"ee63f3"},"App setting":{"name":"App setting","description":"Related to app settings panel within the app","color":"174f98"},"BE instance":{"name":"BE instance","description":"For all issues related to license, billing on BE instance","color":"ae8f98"},"Fixed layout":{"name":"Fixed layout","description":"issues related to fixed layout","color":"b66681"},"Anvil layout":{"name":"Anvil layout","description":"issues related to the new layout system anvil","color":"5e0904"},"New Deployment Mode":{"name":"New Deployment Mode","description":"Support a new mode of deployment","color":"108033"},"Custom widgets":{"name":"Custom widgets","description":"For all issues related to the custom widget project","color":"c9db9c"},"Homepage Experience V2":{"name":"Homepage Experience V2","description":"Label for reporting new tasks and bug fixes related to revamped homepage experience","color":"c55d54"},"Customer Success":{"name":"Customer Success","description":"Issues that the success team cares about","color":"6ccabd"},"Invite flow":{"name":"Invite flow","description":"Invite users flow and any associated actions","color":"881b35"},"Invite users":{"name":"Invite users","description":"Invite users flow and any associated actions","color":""},"Workflows Pod":{"name":"Workflows Pod","description":"Issues that the workflows team owns","color":"446925"},"DailyPromotionBlocker":{"name":"DailyPromotionBlocker","description":"DailyPromotion Blocker","color":"9b2280"},"JS Binding":{"name":"JS Binding","description":"All issues related to the JS Binding experience","color":"422fed"},"REST API":{"name":"REST API","description":"REST API plugin related issues","color":"e3ede5"},"Critical":{"color":"a1e3db","name":"Critical","description":"This issue breaks existing apps. Drop everything else to resolve"},"Module creator":{"name":"Module creator","description":"Issues related to the module creator side","color":"bb2c05"},"Module consumer":{"name":"Module consumer","description":"Issues related to the module consumer side","color":"83d3c5"},"Package versioning":{"name":"Package versioning","description":"ISsues related to how we manage versions for packages","color":"4c5218"},"Convert to module":{"name":"Convert to module","description":"Issues related to the module creation flow using conversion","color":"4c5218"},"Query module":{"name":"Query module","description":"Issues affecting query modules or its instances","color":"b11a7e"},"JS module":{"name":"JS module","description":"Issues affecting JS modules or its instances","color":"bf76f6"},"Secret Management":{"name":"Secret Management","description":"Issues related to secret management","color":"2b4664"},"REST API plugin":{"name":"REST API plugin","description":"REST API plugin related issues","color":"b5948a"},"UI module":{"name":"UI module","description":"Issues affecting UI modules or its instances","color":"d2acee"},"Preview mode":{"name":"Preview mode","description":"Issues related to app previews","color":"48883f"},"Git Auto-commit":{"name":"Git Auto-commit","description":"Issues related to autocommit","color":"717732"},"QA Pod":{"name":"QA Pod","description":"Issues under the QA Pod","color":"717732"},"Automation Test":{"name":"Automation Test","description":"","color":""},"Automation failures":{"name":"Automation failures","description":"","color":""},"Needs automation":{"name":"Needs automation","description":"Issues that needs automated tests","color":""},"Prepared statements":{"name":"Prepared statements","description":"Issues related to prepared statement flow","color":""},"Switch Group Widget":{"name":"Switch Group Widget","description":"Issues related to Switch group Widget","color":""},"Supervisor":{"name":"Supervisor","description":"Issues related to supervisor","color":"2c5813"},"Deployment Certificates":{"name":"Deployment Certificates","description":"Issues related to lets encrypt","color":"e148aa"},"Mock Data":{"name":"Mock Data","description":"Issues related to mock databases","color":"ebf251"},"AWS ECS":{"name":"AWS ECS","description":"Issues related to ECS Fargate","color":"e506ff"},"Publish App":{"name":"Publish App","description":"Issues related to app deployment","color":"2b4664"},"IDE Infra":{"name":"IDE Infra","description":"Issues related to the IDE infrastructure like saving changes","color":"1bb96a"},"User Profile":{"name":"User Profile","description":"Issues related to a user profile","color":"a60d34"},"Page Management":{"color":"1bb96a","name":"Page Management","description":"Issues related to configuring pages"},"Ingress":{"name":"Ingress","description":"Ingress Controller","color":"a86802"},"Nginx":{"name":"Nginx","description":"Issues related to Nginx","color":"e54195"},"Building blocks":{"name":"Building blocks","description":"Building blocks on cavas, on templates listing or drag and drop of building blocks.","color":"48883f"},"Table Inline Edit":{"name":"Table Inline Edit","description":"Issues related to inline editing","color":"60895a"},"User Session ":{"name":"User Session ","description":"For all issues/tasks related to user sessions","color":"65a3f5"},"WDS - all widgets":{"name":"WDS - all widgets","description":"all widget present in WDS","color":"2670ae"},"WDS - input widget":{"name":"WDS - input widget","description":"Issues related to input widget on WDS","color":"2670ae"},"WDS - paragraph widget":{"name":"WDS - paragraph widget","description":"issues related to paragraph widget on WDS","color":"2670ae"},"WDS - statbox widget":{"name":"WDS - statbox widget","description":"issues related to statbox widget on WDS","color":"2670ae"},"WDS - modal widget":{"name":"WDS - modal widget","description":"Issues related to modal widget on WDS","color":"2670ae"},"WDS - icon widget":{"name":"WDS - icon widget","description":"Issues related to icon widget on WDS","color":"2670ae"},"WDS - checkbox widget":{"name":"WDS - checkbox widget","description":"Issues related to checkbox widget on WDS","color":"2670ae"},"WDS - table widget":{"name":"WDS - table widget","description":"Issues related to table widget on WDS","color":"2670ae"},"WDS - keyValue widget":{"name":"WDS - keyValue widget","description":"Issues related to key-value widget on WDS","color":"2670ae"},"WDS - switch group widget":{"name":"WDS - switch group widget","description":"Issues related to switch group widget on WDS","color":"2670ae"},"WDS - theming":{"name":"WDS - theming","description":"Issues related to theming on the Anvil instance","color":"2670ae"},"Anvil POD":{"name":"Anvil POD","description":"Issue related to Anvil project","color":"5e0904"},"Anvil - theming":{"name":"Anvil - theming","description":"Issues related to theming on the Anvil instance","color":"c28de5"},"Anvil - vertical alignment":{"name":"Anvil - vertical alignment","description":"Issues related to vertical alignment on the Anvil layout","color":"c28de5"},"Anvil - layout component":{"name":"Anvil - layout component","description":"Issues related to layout component on the Anvil layout","color":"c28de5"},"Anvil - drag & drop":{"name":"Anvil - drag & drop","description":"Issues related to drag & drop experience on Anvil","color":"c28de5"},"Anvil - zones & sections":{"name":"Anvil - zones & sections","description":"Issues related to zones and sections on the Anvil layout","color":"c28de5"},"Anvil - copy paste experience":{"name":"Anvil - copy paste experience","description":"Issues related to copy paste experience on the Anvil layout","color":"c28de5"},"WDS - phone widget":{"name":"WDS - phone widget","description":"Issues related to phone widget on WDS","color":"c28de5"},"WDS - responsive widget":{"name":"WDS - responsive widget","description":"All issues related to widget responsiveness","color":"11ee05"},"Anvil - responsive viewport":{"color":"11ee05","name":"Anvil - responsive viewport","description":"Issues seen on different viewports like mobile"},"WDS - widget styling":{"color":"11ee05","name":"WDS - widget styling","description":"all about widget styling"},"Anvil - spacing":{"name":"Anvil - spacing","description":"Related to spacing between widgets in auto layout","color":"11ee05"},"Anvil - responsive canvas":{"name":"Anvil - responsive canvas","description":"All issues related to canvas responsiveness","color":"11ee05"},"WDS - inline button widget":{"name":"WDS - inline button widget","description":"Issues related to inline button widget on WDS","color":"7cef83"},"Activation Pod":{"name":"Activation Pod","description":"for Activation group","color":"d67d00"},"Activation":{"name":"Activation","description":"for Activation group","color":"d67d00"},"Tests":{"name":"Tests","description":"Test issues","color":"4fc7b6"},"Ballpark: XXS":{"name":"Ballpark: XXS","description":"~1xDev in 1/2xSprint","color":""},"Ballpark: XS":{"name":"Ballpark: XS","description":"~1xDev in 1xSprint","color":"53bf71"},"Ballpark: S":{"name":"Ballpark: S","description":"~2xDev in 1xSprint","color":"6e9e65"},"Ballpark: M":{"name":"Ballpark: M","description":"~1xPOD in 1xSprint","color":"2229e6"},"Ballpark: L":{"name":"Ballpark: L","description":"~1xPOD in 3xSprint or 2xPODs in 1xSprint","color":"49962f"},"Ballpark: XL":{"name":"Ballpark: XL","description":"~1xPOD in 1xQuarter or 2xPODs in 2xSprint","color":"b524c9"},"Ballpark: XXL":{"name":"Ballpark: XXL","description":"~2xPODs in 1xQuarter","color":"22092c"},"Auto-commit":{"name":"Auto-commit","description":"Issues related to auto-generated commits showing up on git ","color":"e25b89"},"Continuous Deployment":{"name":"Continuous Deployment","description":"Issues related to CD pipeline on git","color":"aea47c"},"Default branch":{"name":"Default branch","description":"Issues related to using a default branch on git","color":"195737"},"Git status":{"name":"Git status","description":"Issues related to information shown on git status modal or number of changes appearing in a branch","color":"c851b8"},"Git performance":{"name":"Git performance","description":"Issues related to perceived performance on any git operation","color":"189af6"},"Anvil team":{"name":"Anvil team","description":"issues related to the new layout system anvil","color":"798200"},"SDLC":{"name":"SDLC","description":"Issues related to software development lifecycle experiences","color":"bae511"},"Reconnect DS modal":{"name":"Reconnect DS modal","description":"Issues related to reconnect datasource modal post app import","color":"2e398b"},"Stability Pod":{"name":"Stability Pod","description":"For all issues/tasks to be prioritized under Stability pod","color":"86ddf6"},"Stability Issue":{"name":"Stability Issue","description":"Every issue handle by Stability Pod","color":"4d024a"},"Move to Postgres":{"name":"Move to Postgres","description":"Issues required to be solved for the move to Postgres as repository layer","color":"466ab1"},"User Session":{"name":"User Session","description":"Issues related to user sessions","color":"8255e5"},"IDE tabs":{"name":"IDE tabs","description":"query and js tabs","color":"1bb96a"},"Inviting Contribution":{"name":"Inviting Contribution","description":"Issues that we would like contributions to","color":""},"cypress-flaky-fix":{"name":"cypress-flaky-fix","description":"This label is auto-added when a PR which only has Cypress fixes are merged to release","color":"cd8bb6"},"Cypress flaky tests":{"name":"Cypress flaky tests","description":"Test scripts that need to be fixed on Cypress by dev or SDET","color":"cd8bb6"},"Help enterprise":{"name":"Help enterprise","description":"Requested by Appsmith customers or prospects","color":"FF8C00"},"Learnability":{"name":"Learnability","description":"Issues affecting the product learnability, making the product harder for new users.","color":"800c2f"},"ADS Spacing":{"name":"ADS Spacing","description":"","color":"686ebb"},"ads unit test":{"name":"ads unit test","description":"All issue related ads unit cases","color":"686ebb"},"ads revamp":{"name":"ads revamp","description":"All issues related to ads revamp.","color":"686ebb"},"Javascript Product":{"color":"709a21","name":"Javascript Product","description":"Issues related to users writing javascript in appsmith"},"IDE Product":{"color":"1bb96a","name":"IDE Product","description":"Issues related to the IDE Product"},"IDE Pod":{"color":"1bb96a","name":"IDE Pod","description":"Issues that new developers face while exploring the IDE"},"Accelerators Product":{"name":"Accelerators Product","description":"Issues related to app building accelerators","color":"f3fce6"},"Templates Product":{"name":"Templates Product","description":"Issues related to Templates","color":"f3fce6"},"Design System Product":{"name":"Design System Product","description":"Appsmith design system related issues","color":"2b4664"},"ads deduplication":{"name":"ads deduplication","description":"Replacing component with ADS components","color":"708943"},"Admin Settings Product":{"color":"708943","name":"Admin Settings Product","description":"Issues in admin settings pages"},"Appsmith AI":{"name":"Appsmith AI","description":"All issues related to the Appsmith AI datasource","color":"708943"},"Query & JS Pod":{"color":"709a21","name":"Query & JS Pod","description":"Issues related to the query & JS Pod"},"RBAC Product":{"name":"RBAC Product","description":"Issues, requests and enhancements around RBAC.","color":""},"Workspace Product":{"name":"Workspace Product","description":"Issues related to workspaces","color":""},"CE Instance Usage":{"name":"CE Instance Usage","description":"For all issues relating to usage, licensing or billing on the CE instance","color":""},"Billing & Licensing Product":{"name":"Billing & Licensing Product","description":"Issues pertaining to licensing, billing and usage across self serve and enterprise customers","color":"466ab1"},"Platform Administration Pod":{"color":"446925","name":"Platform Administration Pod","description":"Issues related to platform administration & management"},"DB Infrastructure Pod":{"name":"DB Infrastructure Pod","description":"Pod to handle database infrastructure","color":"446925"},"Packages Product":{"name":"Packages Product","description":"Issues related to packages","color":"7e018f"},"Workflows Product":{"name":"Workflows Product","description":"Issues related to the workflows product","color":"446925"},"Debugger Product":{"color":"857f58","name":"Debugger Product","description":"Issues related to the debugger"},"Packages Pod":{"name":"Packages Pod","description":"issues that belong to the packages pod","color":"53742c"},"Environments Product":{"name":"Environments Product","description":"Issues related to datasource environments","color":"857f58"},"Custom Widgets":{"name":"Custom Widgets","description":"For all issues related to the custom widget project","color":"857f58"},"Branding Product":{"name":"Branding Product","description":"All issues under branding and whitelabelling appsmith ecosystem","color":"857f58"},"Widgets & Accelerators Pod":{"name":"Widgets & Accelerators Pod","description":"Issues related to widgets & Accelerators","color":"27496a"},"Widgets Product":{"name":"Widgets Product","description":"This label groups issues related to widgets","color":"f3fce6"},"App Theming Product":{"name":"App Theming Product","description":"Items that are related to the App level theming controls epic","color":"48883f"},"UI Building Product":{"color":"48883f","name":"UI Building Product","description":"Issues related to the UI Building experience"},"Onboarding Product":{"color":"48883f","name":"Onboarding Product","description":"Issues related to onboarding new developers"},"Database Schema":{"name":"Database Schema","description":"Issues related to database schema","color":"48883f"},"Git Product":{"color":"7e018f","name":"Git Product","description":"Issues related to version control product"},"Embedding Apps Product":{"name":"Embedding Apps Product","description":"Issues related to embedding","color":"48883f"},"Integrations Product":{"name":"Integrations Product","description":"Issues related to a specific integration","color":"b9f21c"},"Feature Flagging":{"name":"Feature Flagging","description":"Anything related feature flagging","color":"4574ae"},"Audit Logs Product":{"name":"Audit Logs Product","description":"Audit trails to ensure data security","color":"4574ae"},"Identity & Authentication Product":{"name":"Identity & Authentication Product","description":"Issues related to user identity & authentication","color":"4574ae"},"Email verification":{"name":"Email verification","description":"Email verification issues","color":"4574ae"},"Artifact Platform Product":{"name":"Artifact Platform Product","description":"Issues related to the application platform","color":"4574ae"},"Git IA":{"name":"Git IA","description":"Issues related to Git IA changes","color":"df8bd6"},"Documentation Pod":{"name":"Documentation Pod","description":"Issues related to user education","color":"8c8c02"},"Branch management":{"name":"Branch management","description":"Issues related to using a branch management on git","color":"ebe6af"},"Reconfigure Datasource Modal":{"name":"Reconfigure Datasource Modal","description":"Issues related to reconfigure DS modal that comes after importing applications","color":"5ac17b"},"Setup Issues":{"name":"Setup Issues","description":"Issues related to setting up appsmith","color":"3fc837"},"Packages & Git Pod":{"name":"Packages & Git Pod","description":"All issues belonging to Packages and Git","color":"46ac0e"},"Git Platform":{"name":"Git Platform","description":"Issues related to the git & the app platform","color":"c9ab80"},"Entity Management":{"name":"Entity Management","description":"Copy / Move / Delete widgets / queries / datasources","color":"74c33c"}},"success":true} \ No newline at end of file From 78df400bf4a321c3dca3c4aebd38b9f5282ef44e Mon Sep 17 00:00:00 2001 From: Nikhil Nandagopal Date: Fri, 3 Jan 2025 13:36:22 +0700 Subject: [PATCH 14/40] Updated Label Config --- .github/config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/config.json b/.github/config.json index 4f23778798e7..e5d466df074c 100644 --- a/.github/config.json +++ b/.github/config.json @@ -1 +1 @@ -{"runners":[{"versioning":{"source":"milestones","type":"SemVer"},"prereleaseName":"alpha","issue":{"labels":{"Widgets Product":{"conditions":[{"label":"Button Widget","type":"hasLabel","value":true},{"label":"Chart Widget","type":"hasLabel","value":true},{"label":"Container Widget","type":"hasLabel","value":true},{"label":"Date Picker Widget","type":"hasLabel","value":true},{"label":"Select Widget","type":"hasLabel","value":true},{"label":"File Picker Widget","type":"hasLabel","value":true},{"label":"Form Widget","type":"hasLabel","value":true},{"label":"Image Widget","type":"hasLabel","value":true},{"label":"Input Widget","type":"hasLabel","value":true},{"label":"List Widget","type":"hasLabel","value":true},{"label":"MultiSelect Widget","type":"hasLabel","value":true},{"label":"Map Widget","type":"hasLabel","value":true},{"label":"Modal Widget","type":"hasLabel","value":true},{"label":"Radio Widget","type":"hasLabel","value":true},{"label":"Rich Text Editor Widget","type":"hasLabel","value":true},{"label":"Tab Widget","type":"hasLabel","value":true},{"label":"Table Widget","type":"hasLabel","value":true},{"label":"Text Widget","type":"hasLabel","value":true},{"label":"Video Widget","type":"hasLabel","value":true},{"label":"iFrame","type":"hasLabel","value":true},{"label":"Menu Button","type":"hasLabel","value":true},{"label":"Rating","type":"hasLabel","value":true},{"label":"Widget Validation","type":"hasLabel","value":true},{"label":"New Widget","type":"hasLabel","value":true},{"label":"Switch widget","type":"hasLabel","value":true},{"label":"Audio Widget","type":"hasLabel","value":true},{"label":"Icon Button Widget","type":"hasLabel","value":true},{"label":"Stat Box Widget","type":"hasLabel","value":true},{"label":"Voice Recorder Widget","type":"hasLabel","value":true},{"label":"Calendar Widget","type":"hasLabel","value":true},{"label":"Menu Button Widget","type":"hasLabel","value":true},{"label":"Divider Widget","type":"hasLabel","value":true},{"label":"Rating Widget","type":"hasLabel","value":true},{"label":"View Mode","type":"hasLabel","value":true},{"label":"Widget Property","type":"hasLabel","value":true},{"label":"Document Viewer Widget","type":"hasLabel","value":true},{"label":"Radio Group Widget","type":"hasLabel","value":true},{"label":"Currency Input Widget","type":"hasLabel","value":true},{"label":"TreeSelect","type":"hasLabel","value":true},{"label":"MultiTree Select Widget","type":"hasLabel","value":true},{"label":"Phone Input Widget","type":"hasLabel","value":true},{"label":"JSON Form","type":"hasLabel","value":true},{"label":"All Widgets","type":"hasLabel","value":true},{"label":"Button Group widget","type":"hasLabel","value":true},{"label":"Progress bar widget","type":"hasLabel","value":true},{"label":"Audio Recorder Widget","type":"hasLabel","value":true},{"label":"Camera Widget","type":"hasLabel","value":true},{"label":"Table Widget V2","type":"hasLabel","value":true},{"label":"Map Chart Widget","type":"hasLabel","value":true},{"label":"Code Scanner Widget","type":"hasLabel","value":true},{"label":"Widget keyboard accessibility","type":"hasLabel","value":true},{"label":"List Widget V2","type":"hasLabel","value":true},{"label":"Slider Widget","type":"hasLabel","value":true},{"label":"One-click Binding","type":"hasLabel","value":true},{"label":"Old widget version","type":"hasLabel","value":true},{"label":"Widget Discoverability","type":"hasLabel","value":true},{"label":"Switch Group Widget","type":"hasLabel","value":true},{"label":"Checkbox Group widget","type":"hasLabel","value":true},{"label":"Checkbox Widget","type":"hasLabel","value":true},{"label":"Table Inline Edit","type":"hasLabel","value":true},{"label":"Custom Widgets","type":"hasLabel","value":true}],"requires":1},"Javascript Product":{"conditions":[{"label":"JS Linting & Errors","type":"hasLabel","value":true},{"label":"Autocomplete","type":"hasLabel","value":true},{"label":"Evaluated Value","type":"hasLabel","value":true},{"label":"Slash Command","type":"hasLabel","value":true},{"label":"New JS Function","type":"hasLabel","value":true},{"label":"JS Usability","type":"hasLabel","value":true},{"label":"Framework Functions","type":"hasLabel","value":true},{"label":"JS Objects","type":"hasLabel","value":true},{"label":"JS Evaluation","type":"hasLabel","value":true},{"label":"Custom JS Libraries","type":"hasLabel","value":true},{"label":"Action Selector","type":"hasLabel","value":true},{"label":"Widget setter method","type":"hasLabel","value":true},{"label":"Entity Refactor","type":"hasLabel","value":true},{"label":"AST-frontend","type":"hasLabel","value":true},{"label":"Sniping Mode","type":"hasLabel","value":true},{"label":"AST-backend","type":"hasLabel","value":true}],"requires":1},"IDE Product":{"conditions":[{"label":"IDE Product","type":"hasLabel","value":true},{"label":"IDE Infra","type":"hasLabel","value":true},{"label":"IDE Navigation","type":"hasLabel","value":true},{"label":"IDE tabs","type":"hasLabel","value":true},{"label":"Omnibar","type":"hasLabel","value":true},{"label":"Entity Explorer","type":"hasLabel","value":true},{"label":"Page Management","type":"hasLabel","value":true},{"label":"Preview mode","type":"hasLabel","value":true},{"label":"Entity Management","type":"hasLabel","value":true}],"requires":1},"Accelerators Product":{"conditions":[{"label":"Generate Page","type":"hasLabel","value":true},{"label":"Building blocks","type":"hasLabel","value":true}],"requires":1},"Templates Product":{"conditions":[{"label":"Partial-import-export","type":"hasLabel","value":true},{"label":"Templates Product","type":"hasLabel","value":true}],"requires":1},"Design System Product":{"conditions":[{"label":"Design System Product","type":"hasLabel","value":true},{"label":"ADS Component Issue","type":"hasLabel","value":true},{"label":"Keyboard accessibility ","type":"hasLabel","value":true},{"label":"Toggle button","type":"hasLabel","value":true},{"label":"ADS Category Token","type":"hasLabel","value":true},{"label":"ADS Component Documentation","type":"hasLabel","value":true},{"label":"ADS Migration","type":"hasLabel","value":true},{"label":"ADS Deduplication ","type":"hasLabel","value":true},{"label":"ADS Revamp","type":"hasLabel","value":true},{"label":"ADS Deduplication","type":"hasLabel","value":true},{"label":"ADS Unit Test","type":"hasLabel","value":true},{"label":"ADS Components","type":"hasLabel","value":true},{"label":"ADS Grayscale","type":"hasLabel","value":true},{"label":"Design System","type":"hasLabel","value":true},{"label":"ADS Typography","type":"hasLabel","value":true},{"label":"ADS Visual Styles","type":"hasLabel","value":true},{"label":"ADS Component Design","type":"hasLabel","value":true},{"label":"Modal Component","type":"hasLabel","value":true},{"label":"ADS Spacing","type":"hasLabel","value":true},{"label":"ads unit test","type":"hasLabel","value":true},{"label":"ads revamp","type":"hasLabel","value":true},{"label":"ads deduplication","type":"hasLabel","value":true}],"requires":1},"RBAC Product":{"conditions":[{"label":"Invite users","type":"hasLabel","value":true},{"label":"RBAC Product","type":"hasLabel","value":true}],"requires":1},"Workspace Product":{"conditions":[{"label":"Home Page","type":"hasLabel","value":true},{"label":"Workspace Product","type":"hasLabel","value":true}],"requires":1},"Billing & Licensing Product":{"conditions":[{"label":"Customer Portal","type":"hasLabel","value":true},{"label":"Cloud Services","type":"hasLabel","value":true},{"label":"Billing","type":"hasLabel","value":true},{"label":"Self Serve","type":"hasLabel","value":true},{"label":"Enterprise Billing","type":"hasLabel","value":true},{"label":"Analytics Improvements","type":"hasLabel","value":true},{"label":"Self Serve 1.0","type":"hasLabel","value":true},{"label":"License","type":"hasLabel","value":true},{"label":"BE instance","type":"hasLabel","value":true},{"label":"Invite flow","type":"hasLabel","value":true},{"label":"CE Instance Usage","type":"hasLabel","value":true},{"label":"Feature Flagging","type":"hasLabel","value":true}],"requires":1},"Packages Product":{"conditions":[{"label":"Packages Product","type":"hasLabel","value":true}],"requires":1},"Environments Product":{"conditions":[{"label":"Environments Product","type":"hasLabel","value":true}],"requires":1},"UI Building Product":{"conditions":[{"label":"Property Pane","type":"hasLabel","value":true},{"label":"Copy Paste","type":"hasLabel","value":true},{"label":"Drag & Drop","type":"hasLabel","value":true},{"label":"Undo/Redo","type":"hasLabel","value":true},{"label":"Widgets Pane","type":"hasLabel","value":true},{"label":"UI Performance","type":"hasLabel","value":true},{"label":"Widget Grouping","type":"hasLabel","value":true},{"label":"Reflow & Resize","type":"hasLabel","value":true},{"label":"Canvas / Grid","type":"hasLabel","value":true},{"label":"Auto Height","type":"hasLabel","value":true},{"label":"Browser specific","type":"hasLabel","value":true},{"label":"Auto Layout","type":"hasLabel","value":true},{"label":"Fixed layout","type":"hasLabel","value":true},{"label":"App Navigation","type":"hasLabel","value":true}],"requires":1},"Onboarding Product":{"conditions":[{"label":"Welcome Screen","type":"hasLabel","value":true}],"requires":1},"Git Product":{"conditions":[{"label":"Git Product","type":"hasLabel","value":true},{"label":"Git Auto-commit","type":"hasLabel","value":true},{"label":"Auto-commit","type":"hasLabel","value":true},{"label":"Continuous Deployment","type":"hasLabel","value":true},{"label":"Default branch","type":"hasLabel","value":true},{"label":"Git status","type":"hasLabel","value":true},{"label":"Git performance","type":"hasLabel","value":true},{"label":"SDLC","type":"hasLabel","value":true},{"label":"Git IA","type":"hasLabel","value":true},{"label":"Branch management","type":"hasLabel","value":true}],"requires":1},"Embedding Apps Product":{"conditions":[{"label":"Embedding Apps Product","type":"hasLabel","value":true}],"requires":1},"Integrations Product":{"conditions":[{"label":"New Datasource","type":"hasLabel","value":true},{"label":"Firestore","type":"hasLabel","value":true},{"label":"Google Sheets","type":"hasLabel","value":true},{"label":"Mongo","type":"hasLabel","value":true},{"label":"Redshift","type":"hasLabel","value":true},{"label":"snowflake","type":"hasLabel","value":true},{"label":"S3","type":"hasLabel","value":true},{"label":"Redis","type":"hasLabel","value":true},{"label":"Postgres","type":"hasLabel","value":true},{"label":"GraphQL Plugin","type":"hasLabel","value":true},{"label":"ArangoDB","type":"hasLabel","value":true},{"label":"MsSQL","type":"hasLabel","value":true},{"label":"Elastic Search","type":"hasLabel","value":true},{"label":"OAuth","type":"hasLabel","value":true},{"label":"Airtable","type":"hasLabel","value":true},{"label":"CURL","type":"hasLabel","value":true},{"label":"DynamoDB","type":"hasLabel","value":true},{"label":"Zendesk","type":"hasLabel","value":true},{"label":"Hubspot","type":"hasLabel","value":true},{"label":"Query Forms","type":"hasLabel","value":true},{"label":"Twilio","type":"hasLabel","value":true},{"label":"MySQL","type":"hasLabel","value":true},{"label":"Connection pool","type":"hasLabel","value":true},{"label":"MariaDB","type":"hasLabel","value":true},{"label":"Integrations Pod General","type":"hasLabel","value":true},{"label":"SMTP plugin","type":"hasLabel","value":true},{"label":"Oracle SQL DB","type":"hasLabel","value":true},{"label":"Query filter","type":"hasLabel","value":true},{"label":"Activation - datasources","type":"hasLabel","value":true},{"label":"REST API","type":"hasLabel","value":true},{"label":"REST API","type":"hasLabel","value":true},{"label":"Datasources","type":"hasLabel","value":true},{"label":"REST API plugin","type":"hasLabel","value":true},{"label":"Prepared statements","type":"hasLabel","value":true},{"label":"Query Generation","type":"hasLabel","value":true},{"label":"Core Query Execution","type":"hasLabel","value":true},{"label":"Query Management","type":"hasLabel","value":true},{"label":"Query Settings","type":"hasLabel","value":true},{"label":"Query performance","type":"hasLabel","value":true},{"label":"Datatype issue","type":"hasLabel","value":true},{"label":"SmartSubstitution","type":"hasLabel","value":true},{"label":"Suggested Widgets","type":"hasLabel","value":true},{"label":"SAAS Plugins","type":"hasLabel","value":true},{"label":"Reconnect DS modal","type":"hasLabel","value":true},{"label":"OnPageLoad","type":"hasLabel","value":true},{"label":"File upload issues","type":"hasLabel","value":true},{"label":"AI","type":"hasLabel","value":true},{"label":"Appsmith AI","type":"hasLabel","value":true},{"label":"Database Schema","type":"hasLabel","value":true}],"requires":1},"Identity & Authentication Product":{"conditions":[{"label":"Login / Signup","type":"hasLabel","value":true},{"label":"SSO","type":"hasLabel","value":true},{"label":"SCIM","type":"hasLabel","value":true},{"label":"Email verification","type":"hasLabel","value":true}],"requires":1},"Artifact Platform Product":{"conditions":[{"label":"Fork App","type":"hasLabel","value":true},{"label":"Publish App","type":"hasLabel","value":true},{"label":"Secret Management","type":"hasLabel","value":true},{"label":"Import-Export-App","type":"hasLabel","value":true}],"requires":1},"DevOps Pod":{"conditions":[{"label":"Docker","type":"hasLabel","value":true},{"label":"Super Admin","type":"hasLabel","value":true},{"label":"Deployment","type":"hasLabel","value":true},{"label":"K8s","type":"hasLabel","value":true},{"label":"Email Config","type":"hasLabel","value":true},{"label":"Backup & Restore","type":"hasLabel","value":true},{"label":"AWS AMI","type":"hasLabel","value":true},{"label":"Observability","type":"hasLabel","value":true},{"label":"Heroku","type":"hasLabel","value":true},{"label":"New Deployment Mode","type":"hasLabel","value":true},{"label":"Supervisor","type":"hasLabel","value":true},{"label":"Deployment Certificates","type":"hasLabel","value":true},{"label":"Mock Data","type":"hasLabel","value":true},{"label":"AWS ECS","type":"hasLabel","value":true},{"label":"Ingress","type":"hasLabel","value":true},{"label":"Nginx","type":"hasLabel","value":true},{"label":"Setup Issues","type":"hasLabel","value":true}],"requires":1},"Performance Pod":{"conditions":[{"label":"Performance","type":"hasLabel","value":true},{"label":"Performance infra","type":"hasLabel","value":true}],"requires":1},"IDE Pod":{"conditions":[{"label":"Telemetry","type":"hasLabel","value":true},{"label":"i18n","type":"hasLabel","value":true},{"label":"IDE Product","type":"hasLabel","value":true},{"label":"App setting","type":"hasLabel","value":true},{"label":"Debugger Product","type":"hasLabel","value":true},{"label":"Embedding Apps Product","type":"hasLabel","value":true}],"requires":1},"Platform Administration Pod":{"conditions":[{"label":"Airgap","type":"hasLabel","value":true},{"label":"Enterprise Edition","type":"hasLabel","value":true},{"label":"Invite flow","type":"hasLabel","value":true},{"label":"User Profile","type":"hasLabel","value":true},{"label":"User Session ","type":"hasLabel","value":true},{"label":"User Session","type":"hasLabel","value":true},{"label":"Admin Settings Product","type":"hasLabel","value":true},{"label":"RBAC Product","type":"hasLabel","value":true},{"label":"Workspace Product","type":"hasLabel","value":true},{"label":"Branding Product","type":"hasLabel","value":true},{"label":"Audit Logs Product","type":"hasLabel","value":true},{"label":"Identity & Authentication Product","type":"hasLabel","value":true},{"label":"Billing & Licensing Product","type":"hasLabel","value":true},{"label":"Move to Postgres","type":"hasLabel","value":true}],"requires":1},"DB Infrastructure Pod":{"conditions":[],"requires":1},"Widgets & Accelerators Pod":{"conditions":[{"label":"Accelerators Product","type":"hasLabel","value":true},{"label":"Templates Product","type":"hasLabel","value":true},{"label":"Widgets Product","type":"hasLabel","value":true},{"label":"App Theming Product","type":"hasLabel","value":true}],"requires":1},"Packages Pod":{"conditions":[{"label":"Module creator","type":"hasLabel","value":true},{"label":"Module consumer","type":"hasLabel","value":true},{"label":"Package versioning","type":"hasLabel","value":true},{"label":"Convert to module","type":"hasLabel","value":true},{"label":"Query module","type":"hasLabel","value":true},{"label":"JS module","type":"hasLabel","value":true},{"label":"UI module","type":"hasLabel","value":true},{"label":"Packages Pod","type":"hasLabel","value":true}],"requires":1},"Workflows Pod":{"conditions":[{"label":"Workflows Product","type":"hasLabel","value":true}],"requires":1},"Query & JS Pod":{"conditions":[{"label":"Javascript Product","type":"hasLabel","value":true},{"label":"Onboarding Product","type":"hasLabel","value":true},{"label":"Integrations Product","type":"hasLabel","value":true},{"label":"Reconfigure Datasource Modal","type":"hasLabel","value":true}],"requires":1},"QA Pod":{"conditions":[{"label":"QA","type":"hasLabel","value":true},{"label":"Automation Test","type":"hasLabel","value":true},{"label":"TestGap","type":"hasLabel","value":true},{"label":"Automation failures","type":"hasLabel","value":true},{"label":"Needs automation","type":"hasLabel","value":true},{"label":"cypress-flaky-fix","type":"hasLabel","value":true},{"label":"Cypress flaky tests","type":"hasLabel","value":true}],"requires":1},"Anvil POD":{"conditions":[{"label":"Checkbox Component","type":"hasLabel","value":true},{"label":"WDS team","type":"hasLabel","value":true},{"label":"Anvil POD","type":"hasLabel","value":true},{"label":"WDS - all widgets","type":"hasLabel","value":true},{"label":"WDS - input widget","type":"hasLabel","value":true},{"label":"WDS - paragraph widget","type":"hasLabel","value":true},{"label":"WDS - statbox widget","type":"hasLabel","value":true},{"label":"WDS - modal widget","type":"hasLabel","value":true},{"label":"WDS - icon widget","type":"hasLabel","value":true},{"label":"WDS - checkbox widget","type":"hasLabel","value":true},{"label":"WDS - table widget","type":"hasLabel","value":true},{"label":"WDS - keyValue widget","type":"hasLabel","value":true},{"label":"WDS - switch group widget","type":"hasLabel","value":true},{"label":"WDS - theming","type":"hasLabel","value":true},{"label":"Anvil layout","type":"hasLabel","value":true},{"label":"Anvil - theming","type":"hasLabel","value":true},{"label":"Anvil - vertical alignment","type":"hasLabel","value":true},{"label":"Anvil - layout component","type":"hasLabel","value":true},{"label":"Anvil - drag & drop","type":"hasLabel","value":true},{"label":"Anvil - zones & sections","type":"hasLabel","value":true},{"label":"Anvil - copy paste experience","type":"hasLabel","value":true},{"label":"WDS - phone widget","type":"hasLabel","value":true},{"label":"WDS - responsive widget","type":"hasLabel","value":true},{"label":"Anvil - responsive viewport","type":"hasLabel","value":true},{"label":"WDS - widget styling","type":"hasLabel","value":true},{"label":"Anvil - spacing","type":"hasLabel","value":true},{"label":"Anvil - responsive canvas","type":"hasLabel","value":true},{"label":"WDS - inline button widget","type":"hasLabel","value":true},{"label":"Anvil team","type":"hasLabel","value":true}],"requires":1},"Activation Pod":{"conditions":[{"label":"Activation","type":"hasLabel","value":true}],"requires":1},"Stability Pod":{"conditions":[{"label":"Stability Issue","type":"hasLabel","value":true}],"requires":1},"Documentation Pod":{"conditions":[{"label":"Documentation","type":"hasLabel","value":true}],"requires":1},"Packages & Git Pod":{"conditions":[{"label":"Packages Pod","type":"hasLabel","value":true},{"label":"Git Product","type":"hasLabel","value":true},{"label":"Packages Product","type":"hasLabel","value":true},{"label":"Git Platform","type":"hasLabel","value":true}],"requires":1},"Git Platform":{"conditions":[{"label":"Environments Product","type":"hasLabel","value":true},{"label":"Artifact Platform Product","type":"hasLabel","value":true}],"requires":1}}},"root":"."}],"labels":{"Tab Widget":{"color":"e2c76c","name":"Tab Widget","description":""},"Dont merge":{"color":"ADB39C","name":"Dont merge","description":""},"Epic":{"color":"3E4B9E","name":"Epic","description":"A zenhub epic that describes a project"},"Menu Button Widget":{"color":"235708","name":"Menu Button Widget","description":"Issues related to Menu Button widget"},"Checkbox Group widget":{"color":"bbeecd","name":"Checkbox Group widget","description":"Issues related to Checkbox Group Widget"},"Input Widget":{"color":"ae65d8","name":"Input Widget","description":""},"Security":{"color":"99139C","name":"Security","description":""},"QA":{"color":"","name":"QA","description":"Needs QA attention"},"Verified":{"color":"9bf416","name":"Verified","description":""},"Wont Fix":{"color":"ffffff","name":"Wont Fix","description":"This will not be worked on"},"MySQL":{"color":"c9ddc6","name":"MySQL","description":"Issues related to MySQL plugin"},"Development":{"color":"9F8A02","name":"Development","description":""},"Help Wanted":{"color":"008672","name":"Help Wanted","description":"Extra attention is needed"},"Home Page":{"color":"","name":"Home Page","description":"Issues related to the application home page"},"Rating Widget":{"color":"235708","name":"Rating Widget","description":"Issues related to the rating widget"},"Stat Box Widget":{"color":"f1c9ce","name":"Stat Box Widget","description":"Issues related to stat box"},"Enhancement":{"color":"a2eeef","name":"Enhancement","description":"New feature or request"},"Fork App":{"color":"af87c7","name":"Fork App","description":"Issues related to forking apps"},"Container Widget":{"color":"19AD0D","name":"Container Widget","description":"Container widget"},"Papercut":{"color":"B562F6","name":"Papercut","description":""},"Needs Design":{"color":"bfd4f2","name":"Needs Design","description":"needs design or changes to design"},"i18n":{"color":"1799b0","name":"i18n","description":"Represents issues that need to be tackled to handle internationalization"},"Rich Text Editor Widget":{"color":"f72cac","name":"Rich Text Editor Widget","description":""},"skip-changelog":{"color":"06086F","name":"skip-changelog","description":"Adding this label to a PR prevents it from being listed in the changelog"},"Low":{"color":"79e53b","name":"Low","description":"An issue that is neither critical nor breaks a user flow"},"potential-duplicate":{"color":"d3cb2e","name":"potential-duplicate","description":"This label marks issues that are potential duplicates of already open issues"},"Audio Widget":{"color":"447B9A","name":"Audio Widget","description":"Issues related to Audio Widget"},"Firestore":{"color":"8078b0","name":"Firestore","description":"Issues related to the firestore Integration"},"New Widget":{"color":"be4cf2","name":"New Widget","description":"A request for a new widget"},"Modal Widget":{"color":"03846f","name":"Modal Widget","description":""},"UX Improvement":{"color":"f4a089","name":"UX Improvement","description":""},"S3":{"color":"8078b0","name":"S3","description":"Issues related to the S3 plugin"},"Release Blocker":{"color":"5756bf","name":"Release Blocker","description":"This issue must be resolved before the release"},"safari":{"color":"51C6AA","name":"safari","description":"Bugs seen on safari browser"},"Example Apps":{"color":"1799b0","name":"Example Apps","description":"Example apps created for new signups"},"MultiSelect Widget":{"color":"AB62D4","name":"MultiSelect Widget","description":"Issues related to MultiSelect Widget"},"Calendar Widget":{"color":"8c6644","name":"Calendar Widget","description":""},"Website":{"color":"151720","name":"Website","description":"Related to www.appsmith.com website"},"Low effort":{"color":"8B59F0","name":"Low effort","description":"Something that'll take a few days to build"},"Checkbox Widget":{"color":"bbeecd","name":"Checkbox Widget","description":""},"Spam":{"color":"620faf","name":"Spam","description":""},"Voice Recorder Widget":{"color":"85bc87","name":"Voice Recorder Widget","description":""},"Select Widget":{"color":"0c669e","name":"Select Widget","description":"Select or dropdown widget"},"Bug":{"color":"8ba6fd","name":"Bug","description":"Something isn't right"},"Widget Validation":{"color":"6990BC","name":"Widget Validation","description":"Issues related to widget property validation"},"Generate Page":{"color":"2b4664","name":"Generate Page","description":"Issures related to page generation"},"File Picker Widget":{"color":"6ae4f2","name":"File Picker Widget","description":""},"snowflake":{"color":"8078b0","name":"snowflake","description":"Issues related to the snowflake Integration"},"Automation":{"color":"CCAF60","name":"Automation","description":""},"hotfix":{"color":"BA3F1D","name":"hotfix","description":""},"Import-Export-App":{"color":"48883f","name":"Import-Export-App","description":"Issues related to importing and exporting apps"},"High effort":{"color":"A7E87B","name":"High effort","description":"Something that'll take more than a month to build"},"Telemetry":{"color":"bc70f9","name":"Telemetry","description":"Issues related to instrumenting appsmith"},"Radio Widget":{"color":"91ef15","name":"Radio Widget","description":""},"Omnibar":{"color":"1bb96a","name":"Omnibar","description":"Issues related to the omnibar for navigation"},"Button Widget":{"color":"34efae","name":"Button Widget","description":""},"Switch widget":{"color":"33A8CE","name":"Switch widget","description":"The switch widget"},"Map Widget":{"color":"7eef7a","name":"Map Widget","description":""},"Task":{"color":"085630","name":"Task","description":"A simple Todo"},"Design System":{"color":"2958a4","name":"Design System","description":"Design system"},"opera":{"color":"C63F5B","name":"opera","description":"Any issues identified on the opera browser"},"Login / Signup":{"color":"","name":"Login / Signup","description":"Authentication flows"},"Image Widget":{"color":"8de8ad","name":"Image Widget","description":""},"firefox":{"color":"6d56e2","name":"firefox","description":""},"Property Pane":{"color":"b356ff","name":"Property Pane","description":"Issues related to the behaviour of the property pane"},"Deployment":{"color":"93491f","name":"Deployment","description":"Installation process of appsmith"},"Production":{"color":"b60205","name":"Production","description":""},"Dependencies":{"color":"0366d6","name":"Dependencies","description":"Pull requests that update a dependency file"},"Google Sheets":{"color":"8078b0","name":"Google Sheets","description":"Issues related to Google Sheets"},"Icon Button Widget":{"color":"D319CE","name":"Icon Button Widget","description":"Issues related to the icon button widget"},"Mongo":{"color":"8078b0","name":"Mongo","description":"Issues related to Mongo DB plugin"},"Documentation":{"color":"a8dff7","name":"Documentation","description":"Improvements or additions to documentation"},"TestGap":{"color":"","name":"TestGap","description":"Issues identified for test plan improvement"},"keyboard shortcut":{"color":"0688B6","name":"keyboard shortcut","description":""},"Reopen":{"color":"897548","name":"Reopen","description":""},"Redshift":{"color":"8078b0","name":"Redshift","description":"Issues related to the redshift integration"},"Date Picker Widget":{"color":"ef1ce1","name":"Date Picker Widget","description":""},"Entity Explorer":{"color":"1bb96a","name":"Entity Explorer","description":"Issues related to navigation using the entity explorer"},"JS Linting & Errors":{"color":"E56AA5","name":"JS Linting & Errors","description":"Issues related to JS Linting and errors"},"iFrame":{"color":"3CD1DB","name":"iFrame","description":"Issues related to iFrame"},"Stale":{"color":"ededed","name":"Stale","description":null},"Text Widget":{"color":"d130d1","name":"Text Widget","description":""},"Video Widget":{"color":"23dd4b","name":"Video Widget","description":""},"Datasources":{"color":"3d590f","name":"Datasources","description":"Issues related to configuring datasource on appsmith"},"error":{"color":"B66773","name":"error","description":"All issues connected to error messages"},"Form Widget":{"color":"09ed77","name":"Form Widget","description":""},"Needs Triaging":{"color":"e8b851","name":"Needs Triaging","description":"Needs attention from maintainers to triage"},"Autocomplete":{"color":"235708","name":"Autocomplete","description":"Issues related to the autocomplete"},"hacktoberfest":{"color":"0052cc","name":"hacktoberfest","description":"All issues that can be solved by the community during Hacktoberfest"},"Medium effort":{"color":"D31156","name":"Medium effort","description":"Something that'll take more than a week but less than a month to build"},"Release":{"color":"57e5e0","name":"Release","description":""},"High":{"color":"c94d14","name":"High","description":"This issue blocks a user from building or impacts a lot of users"},"UI Performance":{"color":"1799b0","name":"UI Performance","description":"Issues related to UI performance"},"Deploy Preview":{"color":"bfdadc","name":"Deploy Preview","description":"Issues found in Deploy Preview"},"Needs Tests":{"color":"8ee263","name":"Needs Tests","description":"Needs automated tests to assert a feature/bug fix"},"Refactor":{"color":"B96662","name":"Refactor","description":"needs refactoring of code"},"Divider Widget":{"color":"235708","name":"Divider Widget","description":"Issues related to the divider widget"},"Table Widget":{"color":"2eead1","name":"Table Widget","description":""},"Needs More Info":{"color":"e54c10","name":"Needs More Info","description":"Needs additional information"},"Good First Issue":{"color":"7057ff","name":"Good First Issue","description":"Good for newcomers"},"UI Improvement":{"color":"9aeef4","name":"UI Improvement","description":""},"Backend":{"color":"d4c5f9","name":"Backend","description":"This marks the issue or pull request to reference server code"},"Frontend":{"color":"87c7f2","name":"Frontend","description":"This label marks the issue or pull request to reference client code"},"Chart Widget":{"color":"616ecc","name":"Chart Widget","description":""},"List Widget":{"color":"8508A0","name":"List Widget","description":"Issues related to the list widget"},"Duplicate":{"color":"cfd3d7","name":"Duplicate","description":"This issue or pull request already exists"},"JS Snippets":{"color":"8d62d2","name":"JS Snippets","description":"issues related to JS Snippets"},"Copy Paste":{"name":"Copy Paste","description":"Issues related to copy paste","color":"b4f0a9"},"Drag & Drop":{"name":"Drag & Drop","description":"Issues related to the drag & drop experience","color":"92115a"},"Sniping Mode":{"name":"Sniping Mode","description":"Issues related to sniping mode","color":"48883f"},"Redis":{"name":"Redis","description":"Issues related to Redis","color":"8078b0"},"New Datasource":{"color":"60b14c","name":"New Datasource","description":"Requests for new datasources"},"Evaluated Value":{"name":"Evaluated Value","description":"Issues related to evaluated values","color":"39f6e7"},"Undo/Redo":{"name":"Undo/Redo","description":"Issues related to undo/redo","color":"f25880"},"App Navigation":{"name":"App Navigation","description":"Issues related to the topbar navigation and configuring it","color":"4773ab"},"Widgets Pane":{"name":"Widgets Pane","description":"Issues related to the discovery and organisation of widgets","color":"ad5d78"},"View Mode":{"color":"1799b0","name":"View Mode","description":"Issues related to the view mode"},"Content":{"name":"Content","description":"For content related topics i.e blogs, templates, videos","color":"a8dff7"},"Slash Command":{"name":"Slash Command","description":"Issues related to the slash command","color":"a0608e"},"Widget Property":{"name":"Widget Property","description":"Issues related to adding / modifying widget properties across widgets","color":"5e92cb"},"Windows":{"name":"Windows","description":"Issues related exclusively to Windows systems","color":"b4cb8a"},"Old App Issues":{"name":"Old App Issues","description":"Issues related to apps old apps a few weeks old and app issues in stale browser session","color":"87ab18"},"Document Viewer Widget":{"name":"Document Viewer Widget","description":"Issues related to Document Viewer Widget","color":"899d4b"},"Radio Group Widget":{"name":"Radio Group Widget","description":"Issues related to radio group widget","color":"b68495"},"Super Admin":{"name":"Super Admin","description":"Issues related to the super admin page","color":"aa95cf"},"Postgres":{"name":"Postgres","description":"Postgres related issues","color":"8078b0"},"New JS Function":{"name":"New JS Function","description":"Issues related to adding a JS Function","color":"8e8aa4"},"Cannot Reproduce Issue":{"color":"93c9cc","name":"Cannot Reproduce Issue","description":"Issues that cannot be reproduced"},"Widget Grouping":{"name":"Widget Grouping","description":"Issues related to Widget Grouping","color":"a49951"},"K8s":{"name":"K8s","description":"Kubernetes related issues","color":"5f318a"},"Docker":{"name":"Docker","description":"Issues related to docker","color":"89b808"},"Camera Widget":{"name":"Camera Widget","description":"Issues and enhancements related to camera widget","color":"e6038e"},"SAAS Plugins":{"name":"SAAS Plugins","description":"Issues related to SAAS Plugins","color":"80e18f"},"JS Promises":{"name":"JS Promises","description":"Issues related to promises","color":"d7771f"},"OnPageLoad":{"name":"OnPageLoad","description":"OnPageLoad issues on functions and queries","color":"2b4664"},"JS Usability":{"name":"JS Usability","description":"usability issues with JS editor and JS elsewhere","color":"a302b0"},"Currency Input Widget":{"name":"Currency Input Widget","description":"Issues related to currency input widget","color":"b2164f"},"TreeSelect":{"name":"TreeSelect","description":"Issues related to TreeSelect Widget","color":"a1633e"},"MultiTree Select Widget":{"name":"MultiTree Select Widget","description":"Issues related to MultiTree Select Widget","color":"a1633e"},"Welcome Screen":{"name":"Welcome Screen","description":"Issues related to the welcome screen","color":"48883f"},"Realtime Commenting":{"color":"a70b86","name":"Realtime Commenting","description":"In-app communication between teams"},"Phone Input Widget":{"name":"Phone Input Widget","description":"Issues related to the Phone Input widget","color":"a70b86"},"JSON Form":{"name":"JSON Form","description":"Issue / features related to the JSON form wiget","color":"46b209"},"All Widgets":{"name":"All Widgets","description":"Issues related to all widgets","color":"972b36"},"V1":{"name":"V1","description":"V1","color":"67ab2e"},"Reflow & Resize":{"name":"Reflow & Resize","description":"All issues related to reflow and resize experience","color":"748a13"},"SSO":{"name":"SSO","description":"Issues, requests and enhancements around Single sign-on.","color":""},"Multi User Realtime":{"name":"Multi User Realtime","description":"Issues related to multiple users using or editing an application","color":"e7b6ce"},"Ready for design":{"name":"Ready for design","description":"this issue is ready for design: it contains clear problem statements and other required information","color":"ebf442"},"Support":{"name":"Support","description":"Issues created by the A-force team to address user queries","color":"1740f3"},"Button Group widget":{"name":"Button Group widget","description":"Issue and enhancements related to the button group widget","color":"f17025"},"GraphQL Plugin":{"name":"GraphQL Plugin","description":"Issues related to GraphQL plugin","color":"8078b0"},"DevOps Pod":{"name":"DevOps Pod","description":"Issues related to devops","color":"d956c7"},"medium":{"name":"medium","description":"Issues that frustrate users due to poor UX","color":"23dfd9"},"ArangoDB":{"name":"ArangoDB","description":"Issues related to arangoDB","color":"8078b0"},"Code Refactoring":{"name":"Code Refactoring","description":"Issues related to code refactoring","color":"76310e"},"Progress bar widget":{"name":"Progress bar widget","description":"To track issues related to progress bar","color":"2d7abf"},"Audio Recorder Widget":{"name":"Audio Recorder Widget","description":"Issues related to Audio Recorder Widget","color":"9accef"},"Airtable":{"name":"Airtable","description":"Issues for Airtable","color":"60885f"},"Canvas / Grid":{"name":"Canvas / Grid","description":"Issues related to the canvas","color":"16b092"},"Email Config":{"name":"Email Config","description":"Issues related to configuring the email service","color":"2a21d1"},"CURL":{"name":"CURL","description":"Issues related to CURL impor","color":"60885f"},"Canvas Zooms":{"name":"Canvas Zooms","description":"Issues related to zooming the canvas","color":"e6038e"},"business":{"name":"business","description":"Features that will be a part of our business edition","color":"cd59eb"},"Action Pod":{"name":"Action Pod","description":"","color":"ee2e36"},"AutomationGap1":{"color":"a5e07c","name":"AutomationGap1","description":"Issues that needs automated tests"},"A-Force11":{"name":"A-Force11","description":"Issues raised by A-Force team","color":"d667b6"},"Business Edition":{"name":"Business Edition","description":"Features that will be a part of our business edition","color":"89bb6c"},"storeValue":{"name":"storeValue","description":"Issues related to the store value function","color":"5d3e66"},"DynamoDB":{"name":"DynamoDB","description":"Issues that are related to DynamoDB should have this label","color":"60885f"},"Backup & Restore":{"name":"Backup & Restore","description":"Issues related to backup and restore","color":"86874d"},"Billing":{"name":"Billing","description":"Billing infrastructure and flows for Business Edition and Trial users","color":"d2bc40"},"Datatype issue":{"name":"Datatype issue","description":"Issues that have risen because data types weren't handled","color":"cef66b"},"OAuth":{"name":"OAuth","description":"OAuth related bugs or features","color":"60885f"},"Table Widget V2":{"name":"Table Widget V2","description":"Issues related to Table Widget V2","color":"3a7192"},"IDE Navigation":{"name":"IDE Navigation","description":"Issues/feature requests related to IDE navigation, and context switching","color":"1bb96a"},"Query performance":{"name":"Query performance","description":"Issues that have to do with lack in performance of query execution","color":"cef66b"},"SAAS Manager App":{"name":"SAAS Manager App","description":"Issues with the SAAS manager app","color":"d427db"},"Twilio":{"name":"Twilio","description":"Issues related to Twilio integration","color":"23ba8d"},"Hubspot":{"name":"Hubspot","description":"Issues related to Hubspot integration","color":"60885f"},"Zendesk":{"name":"Zendesk","description":"Issues related to Zendesk integration","color":"60885f"},"Entity Refactor":{"name":"Entity Refactor","description":"Issues related to refactor logic","color":"705a2c"},"Map Chart Widget":{"name":"Map Chart Widget","description":"Issues related to Map Chart Widgets","color":"c8397f"},"Product Catchup":{"name":"Product Catchup","description":"Issues created in the product catchup","color":"29cd2c"},"Framework Functions":{"name":"Framework Functions","description":"Issues related to internal functions like showAlert(), navigateTo() etc...","color":"c25a09"},"Frontend Libraries Upgrade":{"name":"Frontend Libraries Upgrade","description":"Issues related to frontend libraries upgrade","color":"ede1fc"},"MsSQL":{"name":"MsSQL","description":"Issues related to MsSQL plugin","color":"8078b0"},"Elastic Search":{"name":"Elastic Search","description":"Issues related to the elastic search datasource","color":"8078b0"},"Core Query Execution":{"color":"cef66b","name":"Core Query Execution","description":"Issues related to the execution of all queries"},"Query Management":{"name":"Query Management","description":"Issues related to the CRUD of actions or queries","color":"cef66b"},"Query Settings":{"name":"Query Settings","description":"Issues related to the settings of all queries","color":"cef66b"},"Code Editor":{"name":"Code Editor","description":"Issues related to the code editor","color":"4ca16e"},"Query Forms":{"color":"12b253","name":"Query Forms","description":"Isuses related to the query forms"},"JS Objects":{"color":"22962c","name":"JS Objects","description":"Issues related to JS Objects"},"JS Evaluation":{"color":"22962c","name":"JS Evaluation","description":"Issues related to JS evaluation on the platform"},"SmartSubstitution":{"name":"SmartSubstitution","description":"Issues related to Smart substitution of mustache bindings in queries","color":"bae511"},"Query Generation":{"name":"Query Generation","description":"Issues related to query generation","color":"cef66b"},"Suggested Widgets":{"name":"Suggested Widgets","description":"Issues related to suggesting widgets based on query response","color":"6ac063"},"Code Scanner Widget":{"name":"Code Scanner Widget","description":"Issues related to code scanner widget","color":"9bc1a0"},"Clean URLs":{"name":"Clean URLs","description":"Issues related to clean URLs epic","color":"112623"},"Widget keyboard accessibility":{"name":"Widget keyboard accessibility","description":"All issues related to keyboard accessibility in widgets","color":"b626fd"},"Connection pool":{"name":"Connection pool","description":"issues to do with connection pooling of various plugins","color":"94fe36"},"List Widget V2":{"name":"List Widget V2","description":"Issues related to the list widget v2","color":"adaaf7"},"Auto Height":{"name":"Auto Height","description":"Issues related to dynamic height of widgets","color":"5149cf"},"cypress_failed_test":{"name":"cypress_failed_test","description":"Cypress failed tests","color":"4745d5"},"Needs validation":{"name":"Needs validation","description":"Needs problem validation before being picked up","color":"66673d"},"Slider Widget":{"name":"Slider Widget","description":"Issues raised for slider widgets.","color":"2eef5f"},"Multitenancy":{"name":"Multitenancy","description":"Support multitenancy within single appsmith instance","color":"8c49a9"},"Conversion Algorithm":{"name":"Conversion Algorithm","description":"All issue related to converting app from fixed to flex mode & vice versa","color":"d12d2e"},"Browser specific":{"name":"Browser specific","description":"All issue related to browser","color":"d12d2e"},"Performance infra":{"name":"Performance infra","description":"all issue related to the performance infra","color":"8a60f6"},"DSL Update":{"name":"DSL Update","description":"Issues related to storing and updating the DSL","color":"e16cf3"},"AST-frontend":{"name":"AST-frontend","description":"Issues related to maintaining AST logic","color":"2b4664"},"AST-backend":{"name":"AST-backend","description":"Backend issues related to AST parsing","color":"48883f"},"MariaDB":{"name":"MariaDB","description":"MariaDB datasource","color":"8428c3"},"ADS Component Issue":{"name":"ADS Component Issue","description":"Issues which are caused due to ADS components","color":"d89119"},"Regressed":{"color":"723fd0","name":"Regressed","description":"Scenarios that were working before but have now regressed"},"Needs RCA":{"name":"Needs RCA","description":"a critical or high priority issue that needs an RCA","color":"2cc68f"},"Custom JS Libraries":{"name":"Custom JS Libraries","description":"Issues related to adding custom JS library","color":"bacb6d"},"Integrations Pod General":{"name":"Integrations Pod General","description":"Issues related to the Integrations Pod that don't fit into other tags.","color":"287823"},"Performance Pod":{"name":"Performance Pod","description":"All things related to Appsmith performance","color":"b5a25d"},"Performance":{"name":"Performance","description":"Issues related to performance","color":"9a18d7"},"File upload issues":{"name":"File upload issues","description":"Issues related to uploading any type of files from within Appsmith","color":"2b4664"},"Action Selector":{"name":"Action Selector","description":"Issues related to action selector on the property pane","color":"2f9e20"},"Community Reported":{"name":"Community Reported","description":"issues reported by community members","color":"1402e5"},"JS Function execution":{"name":"JS Function execution","description":"JS function execution","color":"7c2de1"},"Self Serve":{"name":"Self Serve","description":"For all issues related to self-serve flow for business edition","color":"4dacfc"},"Self Serve 1.0":{"name":"Self Serve 1.0","description":"For all issues related to v1 of the self serve project","color":"ae839e"},"Customer Portal":{"name":"Customer Portal","description":"For all tasks/issues pertaining to customer.appsmith.com","color":"d2bc40"},"Cloud Services":{"name":"Cloud Services","description":"For all tasks/issues on Appsmith cloud-services relating to licensing, usage and billing","color":"d2bc40"},"One-click Binding":{"name":"One-click Binding","description":"Issues related to the One click binding epic","color":"f1661c"},"Airgap":{"name":"Airgap","description":"Tickets related to supporting air-gapped Appsmith instances","color":"1cb294"},"SMTP plugin":{"name":"SMTP plugin","description":"Issues related to SMTP plugin","color":"541457"},"AWS AMI":{"name":"AWS AMI","description":"Issues Related to AWS AMI","color":"b44680"},"Old widget version":{"name":"Old widget version","description":"Use this label to raise issue specific only to an older version of a widget","color":"ff3814"},"Enterprise Billing":{"name":"Enterprise Billing","description":"To track all tasks/issues related to licensing & billing for enterprise customers","color":"14c156"},"Oracle SQL DB":{"name":"Oracle SQL DB","description":"Issues related to the Oracle plugin","color":"cbabcb"},"Community Contributor":{"name":"Community Contributor","description":"Meant to track issues that are assigned to external contributors","color":"149ab6"},"widget vertical alignment":{"name":"widget vertical alignment","description":"All issue related widget vertical alignment on the auto layout canvas","color":"d12d2e"},"Observability":{"name":"Observability","description":"Issues related to observability on the Appsmith instance","color":"dff913"},"Checkbox Component":{"name":"Checkbox Component","description":"This labels deals with checkbox component in wds package","color":"75a401"},"Analytics Improvements":{"name":"Analytics Improvements","description":"For all tasks focused on improving our overall analytics and fixing any issues ","color":"29b8ed"},"WDS team":{"name":"WDS team","description":"","color":"8d675a"},"Enterprise Edition":{"name":"Enterprise Edition","description":"Features that will be supported in Enterprise Edition only","color":"984f5e"},"Query filter":{"name":"Query filter","description":"Issues related to query filtering, e.g., WHERE clause","color":"a15134"},"Keyboard accessibility ":{"name":"Keyboard accessibility ","description":"All issue related to ADS component keyboard accessibility","color":"2ba696"},"Toggle button":{"name":"Toggle button","description":"All issue related to ADS toggle button","color":"edc47f"},"SCIM":{"name":"SCIM","description":"Label to collate our SCIM issues","color":"48883f"},"ADS Category Token":{"name":"ADS Category Token","description":"All issues related appsmith design system category tokens","color":"920961"},"ADS Component Documentation":{"name":"ADS Component Documentation","description":"All issues Appsmith design system component documentation","color":"64c46a"},"ADS Migration":{"name":"ADS Migration","description":"All issues related to Appsmith design system migration","color":"b082d6"},"ADS Deduplication ":{"name":"ADS Deduplication ","description":"Replacing component with ADS components","color":"b082d6"},"ADS Revamp":{"name":"ADS Revamp","description":"All issues related to ads revamp. ","color":"b082d6"},"ADS Deduplication":{"name":"ADS Deduplication","description":"Replacing component with ADS components","color":"b082d6"},"ADS Grayscale":{"name":"ADS Grayscale","description":"Support grayscale color changes","color":"b03577"},"ADS Unit Test":{"name":"ADS Unit Test","description":"All issue related ads unit cases ","color":"b082d6"},"ADS Components":{"name":"ADS Components","description":"All issues related ADS components","color":"b082d6"},"Widget Discoverability":{"name":"Widget Discoverability","description":"Issues related to Widget Discoverability","color":"7b55ce"},"Widget setter method":{"name":"Widget setter method","description":"Issues with widget property setters","color":"8dce87"},"License":{"name":"License","description":"For all issues/tasks related to licensing of appsmith-ee edition","color":"90ee98"},"Platformization":{"name":"Platformization","description":"Issues or tasks related to platformization of Appsmith codebase","color":"4e972b"},"Activation - datasources":{"name":"Activation - datasources","description":"issues related to activation projects","color":"7c7ace"},"Partial-import-export":{"name":"Partial-import-export","description":"Label for granular reusability.","color":"717732"},"AI":{"name":"AI","description":"All tasks related to AI","color":"2b4664"},"ADS Typography":{"name":"ADS Typography","description":"All issue related typographical changes","color":"2dbe8d"},"Auto Layout":{"name":"Auto Layout","description":"Issues relates to auto layout","color":"92cf8c"},"Heroku":{"name":"Heroku","description":"Issues related to Heroku","color":"a81b69"},"ADS Visual Styles":{"name":"ADS Visual Styles","description":"All issues related to ADS visual styles","color":"d3da89"},"ADS Component Design":{"name":"ADS Component Design","description":"All issue related to component design","color":"5cc91e"},"Modal Component":{"name":"Modal Component","description":"All issue related to ads modal component","color":"ee63f3"},"App setting":{"name":"App setting","description":"Related to app settings panel within the app","color":"174f98"},"BE instance":{"name":"BE instance","description":"For all issues related to license, billing on BE instance","color":"ae8f98"},"Fixed layout":{"name":"Fixed layout","description":"issues related to fixed layout","color":"b66681"},"Anvil layout":{"name":"Anvil layout","description":"issues related to the new layout system anvil","color":"5e0904"},"New Deployment Mode":{"name":"New Deployment Mode","description":"Support a new mode of deployment","color":"108033"},"Custom widgets":{"name":"Custom widgets","description":"For all issues related to the custom widget project","color":"c9db9c"},"Homepage Experience V2":{"name":"Homepage Experience V2","description":"Label for reporting new tasks and bug fixes related to revamped homepage experience","color":"c55d54"},"Customer Success":{"name":"Customer Success","description":"Issues that the success team cares about","color":"6ccabd"},"Invite flow":{"name":"Invite flow","description":"Invite users flow and any associated actions","color":"881b35"},"Invite users":{"name":"Invite users","description":"Invite users flow and any associated actions","color":""},"Workflows Pod":{"name":"Workflows Pod","description":"Issues that the workflows team owns","color":"446925"},"DailyPromotionBlocker":{"name":"DailyPromotionBlocker","description":"DailyPromotion Blocker","color":"9b2280"},"JS Binding":{"name":"JS Binding","description":"All issues related to the JS Binding experience","color":"422fed"},"REST API":{"name":"REST API","description":"REST API plugin related issues","color":"e3ede5"},"Critical":{"color":"a1e3db","name":"Critical","description":"This issue breaks existing apps. Drop everything else to resolve"},"Module creator":{"name":"Module creator","description":"Issues related to the module creator side","color":"bb2c05"},"Module consumer":{"name":"Module consumer","description":"Issues related to the module consumer side","color":"83d3c5"},"Package versioning":{"name":"Package versioning","description":"ISsues related to how we manage versions for packages","color":"4c5218"},"Convert to module":{"name":"Convert to module","description":"Issues related to the module creation flow using conversion","color":"4c5218"},"Query module":{"name":"Query module","description":"Issues affecting query modules or its instances","color":"b11a7e"},"JS module":{"name":"JS module","description":"Issues affecting JS modules or its instances","color":"bf76f6"},"Secret Management":{"name":"Secret Management","description":"Issues related to secret management","color":"2b4664"},"REST API plugin":{"name":"REST API plugin","description":"REST API plugin related issues","color":"b5948a"},"UI module":{"name":"UI module","description":"Issues affecting UI modules or its instances","color":"d2acee"},"Preview mode":{"name":"Preview mode","description":"Issues related to app previews","color":"48883f"},"Git Auto-commit":{"name":"Git Auto-commit","description":"Issues related to autocommit","color":"717732"},"QA Pod":{"name":"QA Pod","description":"Issues under the QA Pod","color":"717732"},"Automation Test":{"name":"Automation Test","description":"","color":""},"Automation failures":{"name":"Automation failures","description":"","color":""},"Needs automation":{"name":"Needs automation","description":"Issues that needs automated tests","color":""},"Prepared statements":{"name":"Prepared statements","description":"Issues related to prepared statement flow","color":""},"Switch Group Widget":{"name":"Switch Group Widget","description":"Issues related to Switch group Widget","color":""},"Supervisor":{"name":"Supervisor","description":"Issues related to supervisor","color":"2c5813"},"Deployment Certificates":{"name":"Deployment Certificates","description":"Issues related to lets encrypt","color":"e148aa"},"Mock Data":{"name":"Mock Data","description":"Issues related to mock databases","color":"ebf251"},"AWS ECS":{"name":"AWS ECS","description":"Issues related to ECS Fargate","color":"e506ff"},"Publish App":{"name":"Publish App","description":"Issues related to app deployment","color":"2b4664"},"IDE Infra":{"name":"IDE Infra","description":"Issues related to the IDE infrastructure like saving changes","color":"1bb96a"},"User Profile":{"name":"User Profile","description":"Issues related to a user profile","color":"a60d34"},"Page Management":{"color":"1bb96a","name":"Page Management","description":"Issues related to configuring pages"},"Ingress":{"name":"Ingress","description":"Ingress Controller","color":"a86802"},"Nginx":{"name":"Nginx","description":"Issues related to Nginx","color":"e54195"},"Building blocks":{"name":"Building blocks","description":"Building blocks on cavas, on templates listing or drag and drop of building blocks.","color":"48883f"},"Table Inline Edit":{"name":"Table Inline Edit","description":"Issues related to inline editing","color":"60895a"},"User Session ":{"name":"User Session ","description":"For all issues/tasks related to user sessions","color":"65a3f5"},"WDS - all widgets":{"name":"WDS - all widgets","description":"all widget present in WDS","color":"2670ae"},"WDS - input widget":{"name":"WDS - input widget","description":"Issues related to input widget on WDS","color":"2670ae"},"WDS - paragraph widget":{"name":"WDS - paragraph widget","description":"issues related to paragraph widget on WDS","color":"2670ae"},"WDS - statbox widget":{"name":"WDS - statbox widget","description":"issues related to statbox widget on WDS","color":"2670ae"},"WDS - modal widget":{"name":"WDS - modal widget","description":"Issues related to modal widget on WDS","color":"2670ae"},"WDS - icon widget":{"name":"WDS - icon widget","description":"Issues related to icon widget on WDS","color":"2670ae"},"WDS - checkbox widget":{"name":"WDS - checkbox widget","description":"Issues related to checkbox widget on WDS","color":"2670ae"},"WDS - table widget":{"name":"WDS - table widget","description":"Issues related to table widget on WDS","color":"2670ae"},"WDS - keyValue widget":{"name":"WDS - keyValue widget","description":"Issues related to key-value widget on WDS","color":"2670ae"},"WDS - switch group widget":{"name":"WDS - switch group widget","description":"Issues related to switch group widget on WDS","color":"2670ae"},"WDS - theming":{"name":"WDS - theming","description":"Issues related to theming on the Anvil instance","color":"2670ae"},"Anvil POD":{"name":"Anvil POD","description":"Issue related to Anvil project","color":"5e0904"},"Anvil - theming":{"name":"Anvil - theming","description":"Issues related to theming on the Anvil instance","color":"c28de5"},"Anvil - vertical alignment":{"name":"Anvil - vertical alignment","description":"Issues related to vertical alignment on the Anvil layout","color":"c28de5"},"Anvil - layout component":{"name":"Anvil - layout component","description":"Issues related to layout component on the Anvil layout","color":"c28de5"},"Anvil - drag & drop":{"name":"Anvil - drag & drop","description":"Issues related to drag & drop experience on Anvil","color":"c28de5"},"Anvil - zones & sections":{"name":"Anvil - zones & sections","description":"Issues related to zones and sections on the Anvil layout","color":"c28de5"},"Anvil - copy paste experience":{"name":"Anvil - copy paste experience","description":"Issues related to copy paste experience on the Anvil layout","color":"c28de5"},"WDS - phone widget":{"name":"WDS - phone widget","description":"Issues related to phone widget on WDS","color":"c28de5"},"WDS - responsive widget":{"name":"WDS - responsive widget","description":"All issues related to widget responsiveness","color":"11ee05"},"Anvil - responsive viewport":{"color":"11ee05","name":"Anvil - responsive viewport","description":"Issues seen on different viewports like mobile"},"WDS - widget styling":{"color":"11ee05","name":"WDS - widget styling","description":"all about widget styling"},"Anvil - spacing":{"name":"Anvil - spacing","description":"Related to spacing between widgets in auto layout","color":"11ee05"},"Anvil - responsive canvas":{"name":"Anvil - responsive canvas","description":"All issues related to canvas responsiveness","color":"11ee05"},"WDS - inline button widget":{"name":"WDS - inline button widget","description":"Issues related to inline button widget on WDS","color":"7cef83"},"Activation Pod":{"name":"Activation Pod","description":"for Activation group","color":"d67d00"},"Activation":{"name":"Activation","description":"for Activation group","color":"d67d00"},"Tests":{"name":"Tests","description":"Test issues","color":"4fc7b6"},"Ballpark: XXS":{"name":"Ballpark: XXS","description":"~1xDev in 1/2xSprint","color":""},"Ballpark: XS":{"name":"Ballpark: XS","description":"~1xDev in 1xSprint","color":"53bf71"},"Ballpark: S":{"name":"Ballpark: S","description":"~2xDev in 1xSprint","color":"6e9e65"},"Ballpark: M":{"name":"Ballpark: M","description":"~1xPOD in 1xSprint","color":"2229e6"},"Ballpark: L":{"name":"Ballpark: L","description":"~1xPOD in 3xSprint or 2xPODs in 1xSprint","color":"49962f"},"Ballpark: XL":{"name":"Ballpark: XL","description":"~1xPOD in 1xQuarter or 2xPODs in 2xSprint","color":"b524c9"},"Ballpark: XXL":{"name":"Ballpark: XXL","description":"~2xPODs in 1xQuarter","color":"22092c"},"Auto-commit":{"name":"Auto-commit","description":"Issues related to auto-generated commits showing up on git ","color":"e25b89"},"Continuous Deployment":{"name":"Continuous Deployment","description":"Issues related to CD pipeline on git","color":"aea47c"},"Default branch":{"name":"Default branch","description":"Issues related to using a default branch on git","color":"195737"},"Git status":{"name":"Git status","description":"Issues related to information shown on git status modal or number of changes appearing in a branch","color":"c851b8"},"Git performance":{"name":"Git performance","description":"Issues related to perceived performance on any git operation","color":"189af6"},"Anvil team":{"name":"Anvil team","description":"issues related to the new layout system anvil","color":"798200"},"SDLC":{"name":"SDLC","description":"Issues related to software development lifecycle experiences","color":"bae511"},"Reconnect DS modal":{"name":"Reconnect DS modal","description":"Issues related to reconnect datasource modal post app import","color":"2e398b"},"Stability Pod":{"name":"Stability Pod","description":"For all issues/tasks to be prioritized under Stability pod","color":"86ddf6"},"Stability Issue":{"name":"Stability Issue","description":"Every issue handle by Stability Pod","color":"4d024a"},"Move to Postgres":{"name":"Move to Postgres","description":"Issues required to be solved for the move to Postgres as repository layer","color":"466ab1"},"User Session":{"name":"User Session","description":"Issues related to user sessions","color":"8255e5"},"IDE tabs":{"name":"IDE tabs","description":"query and js tabs","color":"1bb96a"},"Inviting Contribution":{"name":"Inviting Contribution","description":"Issues that we would like contributions to","color":""},"cypress-flaky-fix":{"name":"cypress-flaky-fix","description":"This label is auto-added when a PR which only has Cypress fixes are merged to release","color":"cd8bb6"},"Cypress flaky tests":{"name":"Cypress flaky tests","description":"Test scripts that need to be fixed on Cypress by dev or SDET","color":"cd8bb6"},"Help enterprise":{"name":"Help enterprise","description":"Requested by Appsmith customers or prospects","color":"FF8C00"},"Learnability":{"name":"Learnability","description":"Issues affecting the product learnability, making the product harder for new users.","color":"800c2f"},"ADS Spacing":{"name":"ADS Spacing","description":"","color":"686ebb"},"ads unit test":{"name":"ads unit test","description":"All issue related ads unit cases","color":"686ebb"},"ads revamp":{"name":"ads revamp","description":"All issues related to ads revamp.","color":"686ebb"},"Javascript Product":{"color":"709a21","name":"Javascript Product","description":"Issues related to users writing javascript in appsmith"},"IDE Product":{"color":"1bb96a","name":"IDE Product","description":"Issues related to the IDE Product"},"IDE Pod":{"color":"1bb96a","name":"IDE Pod","description":"Issues that new developers face while exploring the IDE"},"Accelerators Product":{"name":"Accelerators Product","description":"Issues related to app building accelerators","color":"f3fce6"},"Templates Product":{"name":"Templates Product","description":"Issues related to Templates","color":"f3fce6"},"Design System Product":{"name":"Design System Product","description":"Appsmith design system related issues","color":"2b4664"},"ads deduplication":{"name":"ads deduplication","description":"Replacing component with ADS components","color":"708943"},"Admin Settings Product":{"color":"708943","name":"Admin Settings Product","description":"Issues in admin settings pages"},"Appsmith AI":{"name":"Appsmith AI","description":"All issues related to the Appsmith AI datasource","color":"708943"},"Query & JS Pod":{"color":"709a21","name":"Query & JS Pod","description":"Issues related to the query & JS Pod"},"RBAC Product":{"name":"RBAC Product","description":"Issues, requests and enhancements around RBAC.","color":""},"Workspace Product":{"name":"Workspace Product","description":"Issues related to workspaces","color":""},"CE Instance Usage":{"name":"CE Instance Usage","description":"For all issues relating to usage, licensing or billing on the CE instance","color":""},"Billing & Licensing Product":{"name":"Billing & Licensing Product","description":"Issues pertaining to licensing, billing and usage across self serve and enterprise customers","color":"466ab1"},"Platform Administration Pod":{"color":"446925","name":"Platform Administration Pod","description":"Issues related to platform administration & management"},"DB Infrastructure Pod":{"name":"DB Infrastructure Pod","description":"Pod to handle database infrastructure","color":"446925"},"Packages Product":{"name":"Packages Product","description":"Issues related to packages","color":"7e018f"},"Workflows Product":{"name":"Workflows Product","description":"Issues related to the workflows product","color":"446925"},"Debugger Product":{"color":"857f58","name":"Debugger Product","description":"Issues related to the debugger"},"Packages Pod":{"name":"Packages Pod","description":"issues that belong to the packages pod","color":"53742c"},"Environments Product":{"name":"Environments Product","description":"Issues related to datasource environments","color":"857f58"},"Custom Widgets":{"name":"Custom Widgets","description":"For all issues related to the custom widget project","color":"857f58"},"Branding Product":{"name":"Branding Product","description":"All issues under branding and whitelabelling appsmith ecosystem","color":"857f58"},"Widgets & Accelerators Pod":{"name":"Widgets & Accelerators Pod","description":"Issues related to widgets & Accelerators","color":"27496a"},"Widgets Product":{"name":"Widgets Product","description":"This label groups issues related to widgets","color":"f3fce6"},"App Theming Product":{"name":"App Theming Product","description":"Items that are related to the App level theming controls epic","color":"48883f"},"UI Building Product":{"color":"48883f","name":"UI Building Product","description":"Issues related to the UI Building experience"},"Onboarding Product":{"color":"48883f","name":"Onboarding Product","description":"Issues related to onboarding new developers"},"Database Schema":{"name":"Database Schema","description":"Issues related to database schema","color":"48883f"},"Git Product":{"color":"7e018f","name":"Git Product","description":"Issues related to version control product"},"Embedding Apps Product":{"name":"Embedding Apps Product","description":"Issues related to embedding","color":"48883f"},"Integrations Product":{"name":"Integrations Product","description":"Issues related to a specific integration","color":"b9f21c"},"Feature Flagging":{"name":"Feature Flagging","description":"Anything related feature flagging","color":"4574ae"},"Audit Logs Product":{"name":"Audit Logs Product","description":"Audit trails to ensure data security","color":"4574ae"},"Identity & Authentication Product":{"name":"Identity & Authentication Product","description":"Issues related to user identity & authentication","color":"4574ae"},"Email verification":{"name":"Email verification","description":"Email verification issues","color":"4574ae"},"Artifact Platform Product":{"name":"Artifact Platform Product","description":"Issues related to the application platform","color":"4574ae"},"Git IA":{"name":"Git IA","description":"Issues related to Git IA changes","color":"df8bd6"},"Documentation Pod":{"name":"Documentation Pod","description":"Issues related to user education","color":"8c8c02"},"Branch management":{"name":"Branch management","description":"Issues related to using a branch management on git","color":"ebe6af"},"Reconfigure Datasource Modal":{"name":"Reconfigure Datasource Modal","description":"Issues related to reconfigure DS modal that comes after importing applications","color":"5ac17b"},"Setup Issues":{"name":"Setup Issues","description":"Issues related to setting up appsmith","color":"3fc837"},"Packages & Git Pod":{"name":"Packages & Git Pod","description":"All issues belonging to Packages and Git","color":"46ac0e"},"Git Platform":{"name":"Git Platform","description":"Issues related to the git & the app platform","color":"c9ab80"},"Entity Management":{"name":"Entity Management","description":"Copy / Move / Delete widgets / queries / datasources","color":"74c33c"}},"success":true} \ No newline at end of file +{"runners":[{"versioning":{"source":"milestones","type":"SemVer"},"prereleaseName":"alpha","issue":{"labels":{"Widgets Product":{"conditions":[{"label":"Button Widget","type":"hasLabel","value":true},{"label":"Chart Widget","type":"hasLabel","value":true},{"label":"Container Widget","type":"hasLabel","value":true},{"label":"Date Picker Widget","type":"hasLabel","value":true},{"label":"Select Widget","type":"hasLabel","value":true},{"label":"File Picker Widget","type":"hasLabel","value":true},{"label":"Form Widget","type":"hasLabel","value":true},{"label":"Image Widget","type":"hasLabel","value":true},{"label":"Input Widget","type":"hasLabel","value":true},{"label":"List Widget","type":"hasLabel","value":true},{"label":"MultiSelect Widget","type":"hasLabel","value":true},{"label":"Map Widget","type":"hasLabel","value":true},{"label":"Modal Widget","type":"hasLabel","value":true},{"label":"Radio Widget","type":"hasLabel","value":true},{"label":"Rich Text Editor Widget","type":"hasLabel","value":true},{"label":"Tab Widget","type":"hasLabel","value":true},{"label":"Table Widget","type":"hasLabel","value":true},{"label":"Text Widget","type":"hasLabel","value":true},{"label":"Video Widget","type":"hasLabel","value":true},{"label":"iFrame","type":"hasLabel","value":true},{"label":"Menu Button","type":"hasLabel","value":true},{"label":"Rating","type":"hasLabel","value":true},{"label":"Widget Validation","type":"hasLabel","value":true},{"label":"New Widget","type":"hasLabel","value":true},{"label":"Switch widget","type":"hasLabel","value":true},{"label":"Audio Widget","type":"hasLabel","value":true},{"label":"Icon Button Widget","type":"hasLabel","value":true},{"label":"Stat Box Widget","type":"hasLabel","value":true},{"label":"Voice Recorder Widget","type":"hasLabel","value":true},{"label":"Calendar Widget","type":"hasLabel","value":true},{"label":"Menu Button Widget","type":"hasLabel","value":true},{"label":"Divider Widget","type":"hasLabel","value":true},{"label":"Rating Widget","type":"hasLabel","value":true},{"label":"View Mode","type":"hasLabel","value":true},{"label":"Widget Property","type":"hasLabel","value":true},{"label":"Document Viewer Widget","type":"hasLabel","value":true},{"label":"Radio Group Widget","type":"hasLabel","value":true},{"label":"Currency Input Widget","type":"hasLabel","value":true},{"label":"TreeSelect","type":"hasLabel","value":true},{"label":"MultiTree Select Widget","type":"hasLabel","value":true},{"label":"Phone Input Widget","type":"hasLabel","value":true},{"label":"JSON Form","type":"hasLabel","value":true},{"label":"All Widgets","type":"hasLabel","value":true},{"label":"Button Group widget","type":"hasLabel","value":true},{"label":"Progress bar widget","type":"hasLabel","value":true},{"label":"Audio Recorder Widget","type":"hasLabel","value":true},{"label":"Camera Widget","type":"hasLabel","value":true},{"label":"Table Widget V2","type":"hasLabel","value":true},{"label":"Map Chart Widget","type":"hasLabel","value":true},{"label":"Code Scanner Widget","type":"hasLabel","value":true},{"label":"Widget keyboard accessibility","type":"hasLabel","value":true},{"label":"List Widget V2","type":"hasLabel","value":true},{"label":"Slider Widget","type":"hasLabel","value":true},{"label":"One-click Binding","type":"hasLabel","value":true},{"label":"Old widget version","type":"hasLabel","value":true},{"label":"Widget Discoverability","type":"hasLabel","value":true},{"label":"Switch Group Widget","type":"hasLabel","value":true},{"label":"Checkbox Group widget","type":"hasLabel","value":true},{"label":"Checkbox Widget","type":"hasLabel","value":true},{"label":"Table Inline Edit","type":"hasLabel","value":true},{"label":"Custom Widgets","type":"hasLabel","value":true}],"requires":1},"Javascript Product":{"conditions":[{"label":"JS Linting & Errors","type":"hasLabel","value":true},{"label":"Autocomplete","type":"hasLabel","value":true},{"label":"Evaluated Value","type":"hasLabel","value":true},{"label":"Slash Command","type":"hasLabel","value":true},{"label":"New JS Function","type":"hasLabel","value":true},{"label":"JS Usability","type":"hasLabel","value":true},{"label":"Framework Functions","type":"hasLabel","value":true},{"label":"JS Objects","type":"hasLabel","value":true},{"label":"JS Evaluation","type":"hasLabel","value":true},{"label":"Custom JS Libraries","type":"hasLabel","value":true},{"label":"Action Selector","type":"hasLabel","value":true},{"label":"Widget setter method","type":"hasLabel","value":true},{"label":"Entity Refactor","type":"hasLabel","value":true},{"label":"AST-frontend","type":"hasLabel","value":true},{"label":"Sniping Mode","type":"hasLabel","value":true},{"label":"AST-backend","type":"hasLabel","value":true}],"requires":1},"IDE Product":{"conditions":[{"label":"IDE Product","type":"hasLabel","value":true},{"label":"IDE Infra","type":"hasLabel","value":true},{"label":"IDE Navigation","type":"hasLabel","value":true},{"label":"IDE tabs","type":"hasLabel","value":true},{"label":"Omnibar","type":"hasLabel","value":true},{"label":"Entity Explorer","type":"hasLabel","value":true},{"label":"Page Management","type":"hasLabel","value":true},{"label":"Preview mode","type":"hasLabel","value":true},{"label":"Entity Management","type":"hasLabel","value":true}],"requires":1},"Accelerators Product":{"conditions":[{"label":"Generate Page","type":"hasLabel","value":true},{"label":"Building blocks","type":"hasLabel","value":true}],"requires":1},"Templates Product":{"conditions":[{"label":"Partial-import-export","type":"hasLabel","value":true},{"label":"Templates Product","type":"hasLabel","value":true}],"requires":1},"Design System Product":{"conditions":[{"label":"Design System Product","type":"hasLabel","value":true},{"label":"ADS Component Issue","type":"hasLabel","value":true},{"label":"Keyboard accessibility ","type":"hasLabel","value":true},{"label":"Toggle button","type":"hasLabel","value":true},{"label":"ADS Category Token","type":"hasLabel","value":true},{"label":"ADS Component Documentation","type":"hasLabel","value":true},{"label":"ADS Migration","type":"hasLabel","value":true},{"label":"ADS Deduplication ","type":"hasLabel","value":true},{"label":"ADS Revamp","type":"hasLabel","value":true},{"label":"ADS Deduplication","type":"hasLabel","value":true},{"label":"ADS Unit Test","type":"hasLabel","value":true},{"label":"ADS Components","type":"hasLabel","value":true},{"label":"ADS Grayscale","type":"hasLabel","value":true},{"label":"Design System","type":"hasLabel","value":true},{"label":"ADS Typography","type":"hasLabel","value":true},{"label":"ADS Visual Styles","type":"hasLabel","value":true},{"label":"ADS Component Design","type":"hasLabel","value":true},{"label":"Modal Component","type":"hasLabel","value":true},{"label":"ADS Spacing","type":"hasLabel","value":true},{"label":"ads unit test","type":"hasLabel","value":true},{"label":"ads revamp","type":"hasLabel","value":true},{"label":"ads deduplication","type":"hasLabel","value":true}],"requires":1},"RBAC Product":{"conditions":[{"label":"Invite users","type":"hasLabel","value":true},{"label":"RBAC Product","type":"hasLabel","value":true}],"requires":1},"Workspace Product":{"conditions":[{"label":"Home Page","type":"hasLabel","value":true},{"label":"Workspace Product","type":"hasLabel","value":true}],"requires":1},"Billing & Licensing Product":{"conditions":[{"label":"Customer Portal","type":"hasLabel","value":true},{"label":"Cloud Services","type":"hasLabel","value":true},{"label":"Billing","type":"hasLabel","value":true},{"label":"Self Serve","type":"hasLabel","value":true},{"label":"Enterprise Billing","type":"hasLabel","value":true},{"label":"Analytics Improvements","type":"hasLabel","value":true},{"label":"Self Serve 1.0","type":"hasLabel","value":true},{"label":"License","type":"hasLabel","value":true},{"label":"BE instance","type":"hasLabel","value":true},{"label":"Invite flow","type":"hasLabel","value":true},{"label":"CE Instance Usage","type":"hasLabel","value":true},{"label":"Feature Flagging","type":"hasLabel","value":true}],"requires":1},"Packages Product":{"conditions":[{"label":"Packages Product","type":"hasLabel","value":true}],"requires":1},"Environments Product":{"conditions":[{"label":"Environments Product","type":"hasLabel","value":true}],"requires":1},"UI Building Product":{"conditions":[{"label":"Property Pane","type":"hasLabel","value":true},{"label":"Copy Paste","type":"hasLabel","value":true},{"label":"Drag & Drop","type":"hasLabel","value":true},{"label":"Undo/Redo","type":"hasLabel","value":true},{"label":"Widgets Pane","type":"hasLabel","value":true},{"label":"UI Performance","type":"hasLabel","value":true},{"label":"Widget Grouping","type":"hasLabel","value":true},{"label":"Reflow & Resize","type":"hasLabel","value":true},{"label":"Canvas / Grid","type":"hasLabel","value":true},{"label":"Auto Height","type":"hasLabel","value":true},{"label":"Browser specific","type":"hasLabel","value":true},{"label":"Auto Layout","type":"hasLabel","value":true},{"label":"Fixed layout","type":"hasLabel","value":true},{"label":"App Navigation","type":"hasLabel","value":true}],"requires":1},"Onboarding Product":{"conditions":[{"label":"Welcome Screen","type":"hasLabel","value":true}],"requires":1},"Git Product":{"conditions":[{"label":"Git Product","type":"hasLabel","value":true},{"label":"Git Auto-commit","type":"hasLabel","value":true},{"label":"Auto-commit","type":"hasLabel","value":true},{"label":"Continuous Deployment","type":"hasLabel","value":true},{"label":"Default branch","type":"hasLabel","value":true},{"label":"Git status","type":"hasLabel","value":true},{"label":"Git performance","type":"hasLabel","value":true},{"label":"SDLC","type":"hasLabel","value":true},{"label":"Git IA","type":"hasLabel","value":true},{"label":"Branch management","type":"hasLabel","value":true}],"requires":1},"Embedding Apps Product":{"conditions":[{"label":"Embedding Apps Product","type":"hasLabel","value":true}],"requires":1},"Integrations Product":{"conditions":[{"label":"New Datasource","type":"hasLabel","value":true},{"label":"Firestore","type":"hasLabel","value":true},{"label":"Google Sheets","type":"hasLabel","value":true},{"label":"Mongo","type":"hasLabel","value":true},{"label":"Redshift","type":"hasLabel","value":true},{"label":"snowflake","type":"hasLabel","value":true},{"label":"S3","type":"hasLabel","value":true},{"label":"Redis","type":"hasLabel","value":true},{"label":"Postgres","type":"hasLabel","value":true},{"label":"GraphQL Plugin","type":"hasLabel","value":true},{"label":"ArangoDB","type":"hasLabel","value":true},{"label":"MsSQL","type":"hasLabel","value":true},{"label":"Elastic Search","type":"hasLabel","value":true},{"label":"OAuth","type":"hasLabel","value":true},{"label":"Airtable","type":"hasLabel","value":true},{"label":"CURL","type":"hasLabel","value":true},{"label":"DynamoDB","type":"hasLabel","value":true},{"label":"Zendesk","type":"hasLabel","value":true},{"label":"Hubspot","type":"hasLabel","value":true},{"label":"Query Forms","type":"hasLabel","value":true},{"label":"Twilio","type":"hasLabel","value":true},{"label":"MySQL","type":"hasLabel","value":true},{"label":"Connection pool","type":"hasLabel","value":true},{"label":"MariaDB","type":"hasLabel","value":true},{"label":"Integrations Pod General","type":"hasLabel","value":true},{"label":"SMTP plugin","type":"hasLabel","value":true},{"label":"Oracle SQL DB","type":"hasLabel","value":true},{"label":"Query filter","type":"hasLabel","value":true},{"label":"Activation - datasources","type":"hasLabel","value":true},{"label":"REST API","type":"hasLabel","value":true},{"label":"REST API","type":"hasLabel","value":true},{"label":"Datasources","type":"hasLabel","value":true},{"label":"REST API plugin","type":"hasLabel","value":true},{"label":"Prepared statements","type":"hasLabel","value":true},{"label":"Query Generation","type":"hasLabel","value":true},{"label":"Core Query Execution","type":"hasLabel","value":true},{"label":"Query Management","type":"hasLabel","value":true},{"label":"Query Settings","type":"hasLabel","value":true},{"label":"Query performance","type":"hasLabel","value":true},{"label":"Datatype issue","type":"hasLabel","value":true},{"label":"SmartSubstitution","type":"hasLabel","value":true},{"label":"Suggested Widgets","type":"hasLabel","value":true},{"label":"SAAS Plugins","type":"hasLabel","value":true},{"label":"Reconnect DS modal","type":"hasLabel","value":true},{"label":"OnPageLoad","type":"hasLabel","value":true},{"label":"File upload issues","type":"hasLabel","value":true},{"label":"AI","type":"hasLabel","value":true},{"label":"Appsmith AI","type":"hasLabel","value":true},{"label":"Database Schema","type":"hasLabel","value":true}],"requires":1},"Identity & Authentication Product":{"conditions":[{"label":"Login / Signup","type":"hasLabel","value":true},{"label":"SSO","type":"hasLabel","value":true},{"label":"SCIM","type":"hasLabel","value":true},{"label":"Email verification","type":"hasLabel","value":true}],"requires":1},"Artifact Platform Product":{"conditions":[{"label":"Fork App","type":"hasLabel","value":true},{"label":"Publish App","type":"hasLabel","value":true},{"label":"Secret Management","type":"hasLabel","value":true},{"label":"Import-Export-App","type":"hasLabel","value":true}],"requires":1},"DevOps Pod":{"conditions":[{"label":"Docker","type":"hasLabel","value":true},{"label":"Super Admin","type":"hasLabel","value":true},{"label":"Deployment","type":"hasLabel","value":true},{"label":"K8s","type":"hasLabel","value":true},{"label":"Email Config","type":"hasLabel","value":true},{"label":"Backup & Restore","type":"hasLabel","value":true},{"label":"AWS AMI","type":"hasLabel","value":true},{"label":"Observability","type":"hasLabel","value":true},{"label":"Heroku","type":"hasLabel","value":true},{"label":"New Deployment Mode","type":"hasLabel","value":true},{"label":"Supervisor","type":"hasLabel","value":true},{"label":"Deployment Certificates","type":"hasLabel","value":true},{"label":"Mock Data","type":"hasLabel","value":true},{"label":"AWS ECS","type":"hasLabel","value":true},{"label":"Ingress","type":"hasLabel","value":true},{"label":"Nginx","type":"hasLabel","value":true},{"label":"Setup Issues","type":"hasLabel","value":true}],"requires":1},"Performance Pod":{"conditions":[{"label":"Performance","type":"hasLabel","value":true},{"label":"Performance infra","type":"hasLabel","value":true}],"requires":1},"IDE Pod":{"conditions":[{"label":"Telemetry","type":"hasLabel","value":true},{"label":"i18n","type":"hasLabel","value":true},{"label":"IDE Product","type":"hasLabel","value":true},{"label":"App setting","type":"hasLabel","value":true},{"label":"Debugger Product","type":"hasLabel","value":true},{"label":"Embedding Apps Product","type":"hasLabel","value":true}],"requires":1},"Platform Administration Pod":{"conditions":[{"label":"Airgap","type":"hasLabel","value":true},{"label":"Enterprise Edition","type":"hasLabel","value":true},{"label":"Invite flow","type":"hasLabel","value":true},{"label":"User Profile","type":"hasLabel","value":true},{"label":"User Session ","type":"hasLabel","value":true},{"label":"User Session","type":"hasLabel","value":true},{"label":"Admin Settings Product","type":"hasLabel","value":true},{"label":"RBAC Product","type":"hasLabel","value":true},{"label":"Workspace Product","type":"hasLabel","value":true},{"label":"Branding Product","type":"hasLabel","value":true},{"label":"Audit Logs Product","type":"hasLabel","value":true},{"label":"Identity & Authentication Product","type":"hasLabel","value":true},{"label":"Billing & Licensing Product","type":"hasLabel","value":true},{"label":"Move to Postgres","type":"hasLabel","value":true}],"requires":1},"DB Infrastructure Pod":{"conditions":[],"requires":1},"Widgets & Accelerators Pod":{"conditions":[{"label":"Accelerators Product","type":"hasLabel","value":true},{"label":"Templates Product","type":"hasLabel","value":true},{"label":"Widgets Product","type":"hasLabel","value":true},{"label":"App Theming Product","type":"hasLabel","value":true}],"requires":1},"Packages Pod":{"conditions":[{"label":"Module creator","type":"hasLabel","value":true},{"label":"Module consumer","type":"hasLabel","value":true},{"label":"Package versioning","type":"hasLabel","value":true},{"label":"Convert to module","type":"hasLabel","value":true},{"label":"Query module","type":"hasLabel","value":true},{"label":"JS module","type":"hasLabel","value":true},{"label":"UI module","type":"hasLabel","value":true},{"label":"Packages Pod","type":"hasLabel","value":true}],"requires":1},"Workflows Pod":{"conditions":[{"label":"Workflows Product","type":"hasLabel","value":true}],"requires":1},"Query & JS Pod":{"conditions":[{"label":"Javascript Product","type":"hasLabel","value":true},{"label":"Onboarding Product","type":"hasLabel","value":true},{"label":"Integrations Product","type":"hasLabel","value":true},{"label":"Reconfigure Datasource Modal","type":"hasLabel","value":true}],"requires":1},"QA Pod":{"conditions":[{"label":"QA","type":"hasLabel","value":true},{"label":"Automation Test","type":"hasLabel","value":true},{"label":"TestGap","type":"hasLabel","value":true},{"label":"Automation failures","type":"hasLabel","value":true},{"label":"Needs automation","type":"hasLabel","value":true},{"label":"cypress-flaky-fix","type":"hasLabel","value":true},{"label":"Cypress flaky tests","type":"hasLabel","value":true},{"label":"Cypress","type":"hasLabel","value":true}],"requires":1},"Anvil POD":{"conditions":[{"label":"Checkbox Component","type":"hasLabel","value":true},{"label":"WDS team","type":"hasLabel","value":true},{"label":"Anvil POD","type":"hasLabel","value":true},{"label":"WDS - all widgets","type":"hasLabel","value":true},{"label":"WDS - input widget","type":"hasLabel","value":true},{"label":"WDS - paragraph widget","type":"hasLabel","value":true},{"label":"WDS - statbox widget","type":"hasLabel","value":true},{"label":"WDS - modal widget","type":"hasLabel","value":true},{"label":"WDS - icon widget","type":"hasLabel","value":true},{"label":"WDS - checkbox widget","type":"hasLabel","value":true},{"label":"WDS - table widget","type":"hasLabel","value":true},{"label":"WDS - keyValue widget","type":"hasLabel","value":true},{"label":"WDS - switch group widget","type":"hasLabel","value":true},{"label":"WDS - theming","type":"hasLabel","value":true},{"label":"Anvil layout","type":"hasLabel","value":true},{"label":"Anvil - theming","type":"hasLabel","value":true},{"label":"Anvil - vertical alignment","type":"hasLabel","value":true},{"label":"Anvil - layout component","type":"hasLabel","value":true},{"label":"Anvil - drag & drop","type":"hasLabel","value":true},{"label":"Anvil - zones & sections","type":"hasLabel","value":true},{"label":"Anvil - copy paste experience","type":"hasLabel","value":true},{"label":"WDS - phone widget","type":"hasLabel","value":true},{"label":"WDS - responsive widget","type":"hasLabel","value":true},{"label":"Anvil - responsive viewport","type":"hasLabel","value":true},{"label":"WDS - widget styling","type":"hasLabel","value":true},{"label":"Anvil - spacing","type":"hasLabel","value":true},{"label":"Anvil - responsive canvas","type":"hasLabel","value":true},{"label":"WDS - inline button widget","type":"hasLabel","value":true},{"label":"Anvil team","type":"hasLabel","value":true}],"requires":1},"Activation Pod":{"conditions":[{"label":"Activation","type":"hasLabel","value":true}],"requires":1},"Stability Pod":{"conditions":[{"label":"Stability Issue","type":"hasLabel","value":true}],"requires":1},"Documentation Pod":{"conditions":[{"label":"Documentation","type":"hasLabel","value":true}],"requires":1},"Packages & Git Pod":{"conditions":[{"label":"Packages Pod","type":"hasLabel","value":true},{"label":"Git Product","type":"hasLabel","value":true},{"label":"Packages Product","type":"hasLabel","value":true},{"label":"Git Platform","type":"hasLabel","value":true}],"requires":1},"Git Platform":{"conditions":[{"label":"Environments Product","type":"hasLabel","value":true},{"label":"Artifact Platform Product","type":"hasLabel","value":true}],"requires":1}}},"root":"."}],"labels":{"Tab Widget":{"color":"e2c76c","name":"Tab Widget","description":""},"Dont merge":{"color":"ADB39C","name":"Dont merge","description":""},"Epic":{"color":"3E4B9E","name":"Epic","description":"A zenhub epic that describes a project"},"Menu Button Widget":{"color":"235708","name":"Menu Button Widget","description":"Issues related to Menu Button widget"},"Checkbox Group widget":{"color":"bbeecd","name":"Checkbox Group widget","description":"Issues related to Checkbox Group Widget"},"Input Widget":{"color":"ae65d8","name":"Input Widget","description":""},"Security":{"color":"99139C","name":"Security","description":""},"QA":{"color":"","name":"QA","description":"Needs QA attention"},"Verified":{"color":"9bf416","name":"Verified","description":""},"Wont Fix":{"color":"ffffff","name":"Wont Fix","description":"This will not be worked on"},"MySQL":{"color":"c9ddc6","name":"MySQL","description":"Issues related to MySQL plugin"},"Development":{"color":"9F8A02","name":"Development","description":""},"Help Wanted":{"color":"008672","name":"Help Wanted","description":"Extra attention is needed"},"Home Page":{"color":"","name":"Home Page","description":"Issues related to the application home page"},"Rating Widget":{"color":"235708","name":"Rating Widget","description":"Issues related to the rating widget"},"Stat Box Widget":{"color":"f1c9ce","name":"Stat Box Widget","description":"Issues related to stat box"},"Enhancement":{"color":"a2eeef","name":"Enhancement","description":"New feature or request"},"Fork App":{"color":"af87c7","name":"Fork App","description":"Issues related to forking apps"},"Container Widget":{"color":"19AD0D","name":"Container Widget","description":"Container widget"},"Papercut":{"color":"B562F6","name":"Papercut","description":""},"Needs Design":{"color":"bfd4f2","name":"Needs Design","description":"needs design or changes to design"},"i18n":{"color":"1799b0","name":"i18n","description":"Represents issues that need to be tackled to handle internationalization"},"Rich Text Editor Widget":{"color":"f72cac","name":"Rich Text Editor Widget","description":""},"skip-changelog":{"color":"06086F","name":"skip-changelog","description":"Adding this label to a PR prevents it from being listed in the changelog"},"Low":{"color":"79e53b","name":"Low","description":"An issue that is neither critical nor breaks a user flow"},"potential-duplicate":{"color":"d3cb2e","name":"potential-duplicate","description":"This label marks issues that are potential duplicates of already open issues"},"Audio Widget":{"color":"447B9A","name":"Audio Widget","description":"Issues related to Audio Widget"},"Firestore":{"color":"8078b0","name":"Firestore","description":"Issues related to the firestore Integration"},"New Widget":{"color":"be4cf2","name":"New Widget","description":"A request for a new widget"},"Modal Widget":{"color":"03846f","name":"Modal Widget","description":""},"UX Improvement":{"color":"f4a089","name":"UX Improvement","description":""},"S3":{"color":"8078b0","name":"S3","description":"Issues related to the S3 plugin"},"Release Blocker":{"color":"5756bf","name":"Release Blocker","description":"This issue must be resolved before the release"},"safari":{"color":"51C6AA","name":"safari","description":"Bugs seen on safari browser"},"Example Apps":{"color":"1799b0","name":"Example Apps","description":"Example apps created for new signups"},"MultiSelect Widget":{"color":"AB62D4","name":"MultiSelect Widget","description":"Issues related to MultiSelect Widget"},"Calendar Widget":{"color":"8c6644","name":"Calendar Widget","description":""},"Website":{"color":"151720","name":"Website","description":"Related to www.appsmith.com website"},"Low effort":{"color":"8B59F0","name":"Low effort","description":"Something that'll take a few days to build"},"Checkbox Widget":{"color":"bbeecd","name":"Checkbox Widget","description":""},"Spam":{"color":"620faf","name":"Spam","description":""},"Voice Recorder Widget":{"color":"85bc87","name":"Voice Recorder Widget","description":""},"Select Widget":{"color":"0c669e","name":"Select Widget","description":"Select or dropdown widget"},"Bug":{"color":"8ba6fd","name":"Bug","description":"Something isn't right"},"Widget Validation":{"color":"6990BC","name":"Widget Validation","description":"Issues related to widget property validation"},"Generate Page":{"color":"2b4664","name":"Generate Page","description":"Issures related to page generation"},"File Picker Widget":{"color":"6ae4f2","name":"File Picker Widget","description":""},"snowflake":{"color":"8078b0","name":"snowflake","description":"Issues related to the snowflake Integration"},"Automation":{"color":"CCAF60","name":"Automation","description":""},"hotfix":{"color":"BA3F1D","name":"hotfix","description":""},"Import-Export-App":{"color":"48883f","name":"Import-Export-App","description":"Issues related to importing and exporting apps"},"High effort":{"color":"A7E87B","name":"High effort","description":"Something that'll take more than a month to build"},"Telemetry":{"color":"bc70f9","name":"Telemetry","description":"Issues related to instrumenting appsmith"},"Radio Widget":{"color":"91ef15","name":"Radio Widget","description":""},"Omnibar":{"color":"1bb96a","name":"Omnibar","description":"Issues related to the omnibar for navigation"},"Button Widget":{"color":"34efae","name":"Button Widget","description":""},"Switch widget":{"color":"33A8CE","name":"Switch widget","description":"The switch widget"},"Map Widget":{"color":"7eef7a","name":"Map Widget","description":""},"Task":{"color":"085630","name":"Task","description":"A simple Todo"},"Design System":{"color":"2958a4","name":"Design System","description":"Design system"},"opera":{"color":"C63F5B","name":"opera","description":"Any issues identified on the opera browser"},"Login / Signup":{"color":"","name":"Login / Signup","description":"Authentication flows"},"Image Widget":{"color":"8de8ad","name":"Image Widget","description":""},"firefox":{"color":"6d56e2","name":"firefox","description":""},"Property Pane":{"color":"b356ff","name":"Property Pane","description":"Issues related to the behaviour of the property pane"},"Deployment":{"color":"93491f","name":"Deployment","description":"Installation process of appsmith"},"Production":{"color":"b60205","name":"Production","description":""},"Dependencies":{"color":"0366d6","name":"Dependencies","description":"Pull requests that update a dependency file"},"Google Sheets":{"color":"8078b0","name":"Google Sheets","description":"Issues related to Google Sheets"},"Icon Button Widget":{"color":"D319CE","name":"Icon Button Widget","description":"Issues related to the icon button widget"},"Mongo":{"color":"8078b0","name":"Mongo","description":"Issues related to Mongo DB plugin"},"Documentation":{"color":"a8dff7","name":"Documentation","description":"Improvements or additions to documentation"},"TestGap":{"color":"","name":"TestGap","description":"Issues identified for test plan improvement"},"keyboard shortcut":{"color":"0688B6","name":"keyboard shortcut","description":""},"Reopen":{"color":"897548","name":"Reopen","description":""},"Redshift":{"color":"8078b0","name":"Redshift","description":"Issues related to the redshift integration"},"Date Picker Widget":{"color":"ef1ce1","name":"Date Picker Widget","description":""},"Entity Explorer":{"color":"1bb96a","name":"Entity Explorer","description":"Issues related to navigation using the entity explorer"},"JS Linting & Errors":{"color":"E56AA5","name":"JS Linting & Errors","description":"Issues related to JS Linting and errors"},"iFrame":{"color":"3CD1DB","name":"iFrame","description":"Issues related to iFrame"},"Stale":{"color":"ededed","name":"Stale","description":null},"Text Widget":{"color":"d130d1","name":"Text Widget","description":""},"Video Widget":{"color":"23dd4b","name":"Video Widget","description":""},"Datasources":{"color":"3d590f","name":"Datasources","description":"Issues related to configuring datasource on appsmith"},"error":{"color":"B66773","name":"error","description":"All issues connected to error messages"},"Form Widget":{"color":"09ed77","name":"Form Widget","description":""},"Needs Triaging":{"color":"e8b851","name":"Needs Triaging","description":"Needs attention from maintainers to triage"},"Autocomplete":{"color":"235708","name":"Autocomplete","description":"Issues related to the autocomplete"},"hacktoberfest":{"color":"0052cc","name":"hacktoberfest","description":"All issues that can be solved by the community during Hacktoberfest"},"Medium effort":{"color":"D31156","name":"Medium effort","description":"Something that'll take more than a week but less than a month to build"},"Release":{"color":"57e5e0","name":"Release","description":""},"High":{"color":"c94d14","name":"High","description":"This issue blocks a user from building or impacts a lot of users"},"UI Performance":{"color":"1799b0","name":"UI Performance","description":"Issues related to UI performance"},"Deploy Preview":{"color":"bfdadc","name":"Deploy Preview","description":"Issues found in Deploy Preview"},"Needs Tests":{"color":"8ee263","name":"Needs Tests","description":"Needs automated tests to assert a feature/bug fix"},"Refactor":{"color":"B96662","name":"Refactor","description":"needs refactoring of code"},"Divider Widget":{"color":"235708","name":"Divider Widget","description":"Issues related to the divider widget"},"Table Widget":{"color":"2eead1","name":"Table Widget","description":""},"Needs More Info":{"color":"e54c10","name":"Needs More Info","description":"Needs additional information"},"Good First Issue":{"color":"7057ff","name":"Good First Issue","description":"Good for newcomers"},"UI Improvement":{"color":"9aeef4","name":"UI Improvement","description":""},"Backend":{"color":"d4c5f9","name":"Backend","description":"This marks the issue or pull request to reference server code"},"Frontend":{"color":"87c7f2","name":"Frontend","description":"This label marks the issue or pull request to reference client code"},"Chart Widget":{"color":"616ecc","name":"Chart Widget","description":""},"List Widget":{"color":"8508A0","name":"List Widget","description":"Issues related to the list widget"},"Duplicate":{"color":"cfd3d7","name":"Duplicate","description":"This issue or pull request already exists"},"JS Snippets":{"color":"8d62d2","name":"JS Snippets","description":"issues related to JS Snippets"},"Copy Paste":{"name":"Copy Paste","description":"Issues related to copy paste","color":"b4f0a9"},"Drag & Drop":{"name":"Drag & Drop","description":"Issues related to the drag & drop experience","color":"92115a"},"Sniping Mode":{"name":"Sniping Mode","description":"Issues related to sniping mode","color":"48883f"},"Redis":{"name":"Redis","description":"Issues related to Redis","color":"8078b0"},"New Datasource":{"color":"60b14c","name":"New Datasource","description":"Requests for new datasources"},"Evaluated Value":{"name":"Evaluated Value","description":"Issues related to evaluated values","color":"39f6e7"},"Undo/Redo":{"name":"Undo/Redo","description":"Issues related to undo/redo","color":"f25880"},"App Navigation":{"name":"App Navigation","description":"Issues related to the topbar navigation and configuring it","color":"4773ab"},"Widgets Pane":{"name":"Widgets Pane","description":"Issues related to the discovery and organisation of widgets","color":"ad5d78"},"View Mode":{"color":"1799b0","name":"View Mode","description":"Issues related to the view mode"},"Content":{"name":"Content","description":"For content related topics i.e blogs, templates, videos","color":"a8dff7"},"Slash Command":{"name":"Slash Command","description":"Issues related to the slash command","color":"a0608e"},"Widget Property":{"name":"Widget Property","description":"Issues related to adding / modifying widget properties across widgets","color":"5e92cb"},"Windows":{"name":"Windows","description":"Issues related exclusively to Windows systems","color":"b4cb8a"},"Old App Issues":{"name":"Old App Issues","description":"Issues related to apps old apps a few weeks old and app issues in stale browser session","color":"87ab18"},"Document Viewer Widget":{"name":"Document Viewer Widget","description":"Issues related to Document Viewer Widget","color":"899d4b"},"Radio Group Widget":{"name":"Radio Group Widget","description":"Issues related to radio group widget","color":"b68495"},"Super Admin":{"name":"Super Admin","description":"Issues related to the super admin page","color":"aa95cf"},"Postgres":{"name":"Postgres","description":"Postgres related issues","color":"8078b0"},"New JS Function":{"name":"New JS Function","description":"Issues related to adding a JS Function","color":"8e8aa4"},"Cannot Reproduce Issue":{"color":"93c9cc","name":"Cannot Reproduce Issue","description":"Issues that cannot be reproduced"},"Widget Grouping":{"name":"Widget Grouping","description":"Issues related to Widget Grouping","color":"a49951"},"K8s":{"name":"K8s","description":"Kubernetes related issues","color":"5f318a"},"Docker":{"name":"Docker","description":"Issues related to docker","color":"89b808"},"Camera Widget":{"name":"Camera Widget","description":"Issues and enhancements related to camera widget","color":"e6038e"},"SAAS Plugins":{"name":"SAAS Plugins","description":"Issues related to SAAS Plugins","color":"80e18f"},"JS Promises":{"name":"JS Promises","description":"Issues related to promises","color":"d7771f"},"OnPageLoad":{"name":"OnPageLoad","description":"OnPageLoad issues on functions and queries","color":"2b4664"},"JS Usability":{"name":"JS Usability","description":"usability issues with JS editor and JS elsewhere","color":"a302b0"},"Currency Input Widget":{"name":"Currency Input Widget","description":"Issues related to currency input widget","color":"b2164f"},"TreeSelect":{"name":"TreeSelect","description":"Issues related to TreeSelect Widget","color":"a1633e"},"MultiTree Select Widget":{"name":"MultiTree Select Widget","description":"Issues related to MultiTree Select Widget","color":"a1633e"},"Welcome Screen":{"name":"Welcome Screen","description":"Issues related to the welcome screen","color":"48883f"},"Realtime Commenting":{"color":"a70b86","name":"Realtime Commenting","description":"In-app communication between teams"},"Phone Input Widget":{"name":"Phone Input Widget","description":"Issues related to the Phone Input widget","color":"a70b86"},"JSON Form":{"name":"JSON Form","description":"Issue / features related to the JSON form wiget","color":"46b209"},"All Widgets":{"name":"All Widgets","description":"Issues related to all widgets","color":"972b36"},"V1":{"name":"V1","description":"V1","color":"67ab2e"},"Reflow & Resize":{"name":"Reflow & Resize","description":"All issues related to reflow and resize experience","color":"748a13"},"SSO":{"name":"SSO","description":"Issues, requests and enhancements around Single sign-on.","color":""},"Multi User Realtime":{"name":"Multi User Realtime","description":"Issues related to multiple users using or editing an application","color":"e7b6ce"},"Ready for design":{"name":"Ready for design","description":"this issue is ready for design: it contains clear problem statements and other required information","color":"ebf442"},"Support":{"name":"Support","description":"Issues created by the A-force team to address user queries","color":"1740f3"},"Button Group widget":{"name":"Button Group widget","description":"Issue and enhancements related to the button group widget","color":"f17025"},"GraphQL Plugin":{"name":"GraphQL Plugin","description":"Issues related to GraphQL plugin","color":"8078b0"},"DevOps Pod":{"name":"DevOps Pod","description":"Issues related to devops","color":"d956c7"},"medium":{"name":"medium","description":"Issues that frustrate users due to poor UX","color":"23dfd9"},"ArangoDB":{"name":"ArangoDB","description":"Issues related to arangoDB","color":"8078b0"},"Code Refactoring":{"name":"Code Refactoring","description":"Issues related to code refactoring","color":"76310e"},"Progress bar widget":{"name":"Progress bar widget","description":"To track issues related to progress bar","color":"2d7abf"},"Audio Recorder Widget":{"name":"Audio Recorder Widget","description":"Issues related to Audio Recorder Widget","color":"9accef"},"Airtable":{"name":"Airtable","description":"Issues for Airtable","color":"60885f"},"Canvas / Grid":{"name":"Canvas / Grid","description":"Issues related to the canvas","color":"16b092"},"Email Config":{"name":"Email Config","description":"Issues related to configuring the email service","color":"2a21d1"},"CURL":{"name":"CURL","description":"Issues related to CURL impor","color":"60885f"},"Canvas Zooms":{"name":"Canvas Zooms","description":"Issues related to zooming the canvas","color":"e6038e"},"business":{"name":"business","description":"Features that will be a part of our business edition","color":"cd59eb"},"Action Pod":{"name":"Action Pod","description":"","color":"ee2e36"},"AutomationGap1":{"color":"a5e07c","name":"AutomationGap1","description":"Issues that needs automated tests"},"A-Force11":{"name":"A-Force11","description":"Issues raised by A-Force team","color":"d667b6"},"Business Edition":{"name":"Business Edition","description":"Features that will be a part of our business edition","color":"89bb6c"},"storeValue":{"name":"storeValue","description":"Issues related to the store value function","color":"5d3e66"},"DynamoDB":{"name":"DynamoDB","description":"Issues that are related to DynamoDB should have this label","color":"60885f"},"Backup & Restore":{"name":"Backup & Restore","description":"Issues related to backup and restore","color":"86874d"},"Billing":{"name":"Billing","description":"Billing infrastructure and flows for Business Edition and Trial users","color":"d2bc40"},"Datatype issue":{"name":"Datatype issue","description":"Issues that have risen because data types weren't handled","color":"cef66b"},"OAuth":{"name":"OAuth","description":"OAuth related bugs or features","color":"60885f"},"Table Widget V2":{"name":"Table Widget V2","description":"Issues related to Table Widget V2","color":"3a7192"},"IDE Navigation":{"name":"IDE Navigation","description":"Issues/feature requests related to IDE navigation, and context switching","color":"1bb96a"},"Query performance":{"name":"Query performance","description":"Issues that have to do with lack in performance of query execution","color":"cef66b"},"SAAS Manager App":{"name":"SAAS Manager App","description":"Issues with the SAAS manager app","color":"d427db"},"Twilio":{"name":"Twilio","description":"Issues related to Twilio integration","color":"23ba8d"},"Hubspot":{"name":"Hubspot","description":"Issues related to Hubspot integration","color":"60885f"},"Zendesk":{"name":"Zendesk","description":"Issues related to Zendesk integration","color":"60885f"},"Entity Refactor":{"name":"Entity Refactor","description":"Issues related to refactor logic","color":"705a2c"},"Map Chart Widget":{"name":"Map Chart Widget","description":"Issues related to Map Chart Widgets","color":"c8397f"},"Product Catchup":{"name":"Product Catchup","description":"Issues created in the product catchup","color":"29cd2c"},"Framework Functions":{"name":"Framework Functions","description":"Issues related to internal functions like showAlert(), navigateTo() etc...","color":"c25a09"},"Frontend Libraries Upgrade":{"name":"Frontend Libraries Upgrade","description":"Issues related to frontend libraries upgrade","color":"ede1fc"},"MsSQL":{"name":"MsSQL","description":"Issues related to MsSQL plugin","color":"8078b0"},"Elastic Search":{"name":"Elastic Search","description":"Issues related to the elastic search datasource","color":"8078b0"},"Core Query Execution":{"color":"cef66b","name":"Core Query Execution","description":"Issues related to the execution of all queries"},"Query Management":{"name":"Query Management","description":"Issues related to the CRUD of actions or queries","color":"cef66b"},"Query Settings":{"name":"Query Settings","description":"Issues related to the settings of all queries","color":"cef66b"},"Code Editor":{"name":"Code Editor","description":"Issues related to the code editor","color":"4ca16e"},"Query Forms":{"color":"12b253","name":"Query Forms","description":"Isuses related to the query forms"},"JS Objects":{"color":"22962c","name":"JS Objects","description":"Issues related to JS Objects"},"JS Evaluation":{"color":"22962c","name":"JS Evaluation","description":"Issues related to JS evaluation on the platform"},"SmartSubstitution":{"name":"SmartSubstitution","description":"Issues related to Smart substitution of mustache bindings in queries","color":"bae511"},"Query Generation":{"name":"Query Generation","description":"Issues related to query generation","color":"cef66b"},"Suggested Widgets":{"name":"Suggested Widgets","description":"Issues related to suggesting widgets based on query response","color":"6ac063"},"Code Scanner Widget":{"name":"Code Scanner Widget","description":"Issues related to code scanner widget","color":"9bc1a0"},"Clean URLs":{"name":"Clean URLs","description":"Issues related to clean URLs epic","color":"112623"},"Widget keyboard accessibility":{"name":"Widget keyboard accessibility","description":"All issues related to keyboard accessibility in widgets","color":"b626fd"},"Connection pool":{"name":"Connection pool","description":"issues to do with connection pooling of various plugins","color":"94fe36"},"List Widget V2":{"name":"List Widget V2","description":"Issues related to the list widget v2","color":"adaaf7"},"Auto Height":{"name":"Auto Height","description":"Issues related to dynamic height of widgets","color":"5149cf"},"cypress_failed_test":{"name":"cypress_failed_test","description":"Cypress failed tests","color":"4745d5"},"Needs validation":{"name":"Needs validation","description":"Needs problem validation before being picked up","color":"66673d"},"Slider Widget":{"name":"Slider Widget","description":"Issues raised for slider widgets.","color":"2eef5f"},"Multitenancy":{"name":"Multitenancy","description":"Support multitenancy within single appsmith instance","color":"8c49a9"},"Conversion Algorithm":{"name":"Conversion Algorithm","description":"All issue related to converting app from fixed to flex mode & vice versa","color":"d12d2e"},"Browser specific":{"name":"Browser specific","description":"All issue related to browser","color":"d12d2e"},"Performance infra":{"name":"Performance infra","description":"all issue related to the performance infra","color":"8a60f6"},"DSL Update":{"name":"DSL Update","description":"Issues related to storing and updating the DSL","color":"e16cf3"},"AST-frontend":{"name":"AST-frontend","description":"Issues related to maintaining AST logic","color":"2b4664"},"AST-backend":{"name":"AST-backend","description":"Backend issues related to AST parsing","color":"48883f"},"MariaDB":{"name":"MariaDB","description":"MariaDB datasource","color":"8428c3"},"ADS Component Issue":{"name":"ADS Component Issue","description":"Issues which are caused due to ADS components","color":"d89119"},"Regressed":{"color":"723fd0","name":"Regressed","description":"Scenarios that were working before but have now regressed"},"Needs RCA":{"name":"Needs RCA","description":"a critical or high priority issue that needs an RCA","color":"2cc68f"},"Custom JS Libraries":{"name":"Custom JS Libraries","description":"Issues related to adding custom JS library","color":"bacb6d"},"Integrations Pod General":{"name":"Integrations Pod General","description":"Issues related to the Integrations Pod that don't fit into other tags.","color":"287823"},"Performance Pod":{"name":"Performance Pod","description":"All things related to Appsmith performance","color":"b5a25d"},"Performance":{"name":"Performance","description":"Issues related to performance","color":"9a18d7"},"File upload issues":{"name":"File upload issues","description":"Issues related to uploading any type of files from within Appsmith","color":"2b4664"},"Action Selector":{"name":"Action Selector","description":"Issues related to action selector on the property pane","color":"2f9e20"},"Community Reported":{"name":"Community Reported","description":"issues reported by community members","color":"1402e5"},"JS Function execution":{"name":"JS Function execution","description":"JS function execution","color":"7c2de1"},"Self Serve":{"name":"Self Serve","description":"For all issues related to self-serve flow for business edition","color":"4dacfc"},"Self Serve 1.0":{"name":"Self Serve 1.0","description":"For all issues related to v1 of the self serve project","color":"ae839e"},"Customer Portal":{"name":"Customer Portal","description":"For all tasks/issues pertaining to customer.appsmith.com","color":"d2bc40"},"Cloud Services":{"name":"Cloud Services","description":"For all tasks/issues on Appsmith cloud-services relating to licensing, usage and billing","color":"d2bc40"},"One-click Binding":{"name":"One-click Binding","description":"Issues related to the One click binding epic","color":"f1661c"},"Airgap":{"name":"Airgap","description":"Tickets related to supporting air-gapped Appsmith instances","color":"1cb294"},"SMTP plugin":{"name":"SMTP plugin","description":"Issues related to SMTP plugin","color":"541457"},"AWS AMI":{"name":"AWS AMI","description":"Issues Related to AWS AMI","color":"b44680"},"Old widget version":{"name":"Old widget version","description":"Use this label to raise issue specific only to an older version of a widget","color":"ff3814"},"Enterprise Billing":{"name":"Enterprise Billing","description":"To track all tasks/issues related to licensing & billing for enterprise customers","color":"14c156"},"Oracle SQL DB":{"name":"Oracle SQL DB","description":"Issues related to the Oracle plugin","color":"cbabcb"},"Community Contributor":{"name":"Community Contributor","description":"Meant to track issues that are assigned to external contributors","color":"149ab6"},"widget vertical alignment":{"name":"widget vertical alignment","description":"All issue related widget vertical alignment on the auto layout canvas","color":"d12d2e"},"Observability":{"name":"Observability","description":"Issues related to observability on the Appsmith instance","color":"dff913"},"Checkbox Component":{"name":"Checkbox Component","description":"This labels deals with checkbox component in wds package","color":"75a401"},"Analytics Improvements":{"name":"Analytics Improvements","description":"For all tasks focused on improving our overall analytics and fixing any issues ","color":"29b8ed"},"WDS team":{"name":"WDS team","description":"","color":"8d675a"},"Enterprise Edition":{"name":"Enterprise Edition","description":"Features that will be supported in Enterprise Edition only","color":"984f5e"},"Query filter":{"name":"Query filter","description":"Issues related to query filtering, e.g., WHERE clause","color":"a15134"},"Keyboard accessibility ":{"name":"Keyboard accessibility ","description":"All issue related to ADS component keyboard accessibility","color":"2ba696"},"Toggle button":{"name":"Toggle button","description":"All issue related to ADS toggle button","color":"edc47f"},"SCIM":{"name":"SCIM","description":"Label to collate our SCIM issues","color":"48883f"},"ADS Category Token":{"name":"ADS Category Token","description":"All issues related appsmith design system category tokens","color":"920961"},"ADS Component Documentation":{"name":"ADS Component Documentation","description":"All issues Appsmith design system component documentation","color":"64c46a"},"ADS Migration":{"name":"ADS Migration","description":"All issues related to Appsmith design system migration","color":"b082d6"},"ADS Deduplication ":{"name":"ADS Deduplication ","description":"Replacing component with ADS components","color":"b082d6"},"ADS Revamp":{"name":"ADS Revamp","description":"All issues related to ads revamp. ","color":"b082d6"},"ADS Deduplication":{"name":"ADS Deduplication","description":"Replacing component with ADS components","color":"b082d6"},"ADS Grayscale":{"name":"ADS Grayscale","description":"Support grayscale color changes","color":"b03577"},"ADS Unit Test":{"name":"ADS Unit Test","description":"All issue related ads unit cases ","color":"b082d6"},"ADS Components":{"name":"ADS Components","description":"All issues related ADS components","color":"b082d6"},"Widget Discoverability":{"name":"Widget Discoverability","description":"Issues related to Widget Discoverability","color":"7b55ce"},"Widget setter method":{"name":"Widget setter method","description":"Issues with widget property setters","color":"8dce87"},"License":{"name":"License","description":"For all issues/tasks related to licensing of appsmith-ee edition","color":"90ee98"},"Platformization":{"name":"Platformization","description":"Issues or tasks related to platformization of Appsmith codebase","color":"4e972b"},"Activation - datasources":{"name":"Activation - datasources","description":"issues related to activation projects","color":"7c7ace"},"Partial-import-export":{"name":"Partial-import-export","description":"Label for granular reusability.","color":"717732"},"AI":{"name":"AI","description":"All tasks related to AI","color":"2b4664"},"ADS Typography":{"name":"ADS Typography","description":"All issue related typographical changes","color":"2dbe8d"},"Auto Layout":{"name":"Auto Layout","description":"Issues relates to auto layout","color":"92cf8c"},"Heroku":{"name":"Heroku","description":"Issues related to Heroku","color":"a81b69"},"ADS Visual Styles":{"name":"ADS Visual Styles","description":"All issues related to ADS visual styles","color":"d3da89"},"ADS Component Design":{"name":"ADS Component Design","description":"All issue related to component design","color":"5cc91e"},"Modal Component":{"name":"Modal Component","description":"All issue related to ads modal component","color":"ee63f3"},"App setting":{"name":"App setting","description":"Related to app settings panel within the app","color":"174f98"},"BE instance":{"name":"BE instance","description":"For all issues related to license, billing on BE instance","color":"ae8f98"},"Fixed layout":{"name":"Fixed layout","description":"issues related to fixed layout","color":"b66681"},"Anvil layout":{"name":"Anvil layout","description":"issues related to the new layout system anvil","color":"5e0904"},"New Deployment Mode":{"name":"New Deployment Mode","description":"Support a new mode of deployment","color":"108033"},"Custom widgets":{"name":"Custom widgets","description":"For all issues related to the custom widget project","color":"c9db9c"},"Homepage Experience V2":{"name":"Homepage Experience V2","description":"Label for reporting new tasks and bug fixes related to revamped homepage experience","color":"c55d54"},"Customer Success":{"name":"Customer Success","description":"Issues that the success team cares about","color":"6ccabd"},"Invite flow":{"name":"Invite flow","description":"Invite users flow and any associated actions","color":"881b35"},"Invite users":{"name":"Invite users","description":"Invite users flow and any associated actions","color":""},"Workflows Pod":{"name":"Workflows Pod","description":"Issues that the workflows team owns","color":"446925"},"DailyPromotionBlocker":{"name":"DailyPromotionBlocker","description":"DailyPromotion Blocker","color":"9b2280"},"JS Binding":{"name":"JS Binding","description":"All issues related to the JS Binding experience","color":"422fed"},"REST API":{"name":"REST API","description":"REST API plugin related issues","color":"e3ede5"},"Critical":{"color":"a1e3db","name":"Critical","description":"This issue breaks existing apps. Drop everything else to resolve"},"Module creator":{"name":"Module creator","description":"Issues related to the module creator side","color":"bb2c05"},"Module consumer":{"name":"Module consumer","description":"Issues related to the module consumer side","color":"83d3c5"},"Package versioning":{"name":"Package versioning","description":"ISsues related to how we manage versions for packages","color":"4c5218"},"Convert to module":{"name":"Convert to module","description":"Issues related to the module creation flow using conversion","color":"4c5218"},"Query module":{"name":"Query module","description":"Issues affecting query modules or its instances","color":"b11a7e"},"JS module":{"name":"JS module","description":"Issues affecting JS modules or its instances","color":"bf76f6"},"Secret Management":{"name":"Secret Management","description":"Issues related to secret management","color":"2b4664"},"REST API plugin":{"name":"REST API plugin","description":"REST API plugin related issues","color":"b5948a"},"UI module":{"name":"UI module","description":"Issues affecting UI modules or its instances","color":"d2acee"},"Preview mode":{"name":"Preview mode","description":"Issues related to app previews","color":"48883f"},"Git Auto-commit":{"name":"Git Auto-commit","description":"Issues related to autocommit","color":"717732"},"QA Pod":{"name":"QA Pod","description":"Issues under the QA Pod","color":"717732"},"Automation Test":{"name":"Automation Test","description":"","color":""},"Automation failures":{"name":"Automation failures","description":"","color":""},"Needs automation":{"name":"Needs automation","description":"Issues that needs automated tests","color":""},"Prepared statements":{"name":"Prepared statements","description":"Issues related to prepared statement flow","color":""},"Switch Group Widget":{"name":"Switch Group Widget","description":"Issues related to Switch group Widget","color":""},"Supervisor":{"name":"Supervisor","description":"Issues related to supervisor","color":"2c5813"},"Deployment Certificates":{"name":"Deployment Certificates","description":"Issues related to lets encrypt","color":"e148aa"},"Mock Data":{"name":"Mock Data","description":"Issues related to mock databases","color":"ebf251"},"AWS ECS":{"name":"AWS ECS","description":"Issues related to ECS Fargate","color":"e506ff"},"Publish App":{"name":"Publish App","description":"Issues related to app deployment","color":"2b4664"},"IDE Infra":{"name":"IDE Infra","description":"Issues related to the IDE infrastructure like saving changes","color":"1bb96a"},"User Profile":{"name":"User Profile","description":"Issues related to a user profile","color":"a60d34"},"Page Management":{"color":"1bb96a","name":"Page Management","description":"Issues related to configuring pages"},"Ingress":{"name":"Ingress","description":"Ingress Controller","color":"a86802"},"Nginx":{"name":"Nginx","description":"Issues related to Nginx","color":"e54195"},"Building blocks":{"name":"Building blocks","description":"Building blocks on cavas, on templates listing or drag and drop of building blocks.","color":"48883f"},"Table Inline Edit":{"name":"Table Inline Edit","description":"Issues related to inline editing","color":"60895a"},"User Session ":{"name":"User Session ","description":"For all issues/tasks related to user sessions","color":"65a3f5"},"WDS - all widgets":{"name":"WDS - all widgets","description":"all widget present in WDS","color":"2670ae"},"WDS - input widget":{"name":"WDS - input widget","description":"Issues related to input widget on WDS","color":"2670ae"},"WDS - paragraph widget":{"name":"WDS - paragraph widget","description":"issues related to paragraph widget on WDS","color":"2670ae"},"WDS - statbox widget":{"name":"WDS - statbox widget","description":"issues related to statbox widget on WDS","color":"2670ae"},"WDS - modal widget":{"name":"WDS - modal widget","description":"Issues related to modal widget on WDS","color":"2670ae"},"WDS - icon widget":{"name":"WDS - icon widget","description":"Issues related to icon widget on WDS","color":"2670ae"},"WDS - checkbox widget":{"name":"WDS - checkbox widget","description":"Issues related to checkbox widget on WDS","color":"2670ae"},"WDS - table widget":{"name":"WDS - table widget","description":"Issues related to table widget on WDS","color":"2670ae"},"WDS - keyValue widget":{"name":"WDS - keyValue widget","description":"Issues related to key-value widget on WDS","color":"2670ae"},"WDS - switch group widget":{"name":"WDS - switch group widget","description":"Issues related to switch group widget on WDS","color":"2670ae"},"WDS - theming":{"name":"WDS - theming","description":"Issues related to theming on the Anvil instance","color":"2670ae"},"Anvil POD":{"name":"Anvil POD","description":"Issue related to Anvil project","color":"5e0904"},"Anvil - theming":{"name":"Anvil - theming","description":"Issues related to theming on the Anvil instance","color":"c28de5"},"Anvil - vertical alignment":{"name":"Anvil - vertical alignment","description":"Issues related to vertical alignment on the Anvil layout","color":"c28de5"},"Anvil - layout component":{"name":"Anvil - layout component","description":"Issues related to layout component on the Anvil layout","color":"c28de5"},"Anvil - drag & drop":{"name":"Anvil - drag & drop","description":"Issues related to drag & drop experience on Anvil","color":"c28de5"},"Anvil - zones & sections":{"name":"Anvil - zones & sections","description":"Issues related to zones and sections on the Anvil layout","color":"c28de5"},"Anvil - copy paste experience":{"name":"Anvil - copy paste experience","description":"Issues related to copy paste experience on the Anvil layout","color":"c28de5"},"WDS - phone widget":{"name":"WDS - phone widget","description":"Issues related to phone widget on WDS","color":"c28de5"},"WDS - responsive widget":{"name":"WDS - responsive widget","description":"All issues related to widget responsiveness","color":"11ee05"},"Anvil - responsive viewport":{"color":"11ee05","name":"Anvil - responsive viewport","description":"Issues seen on different viewports like mobile"},"WDS - widget styling":{"color":"11ee05","name":"WDS - widget styling","description":"all about widget styling"},"Anvil - spacing":{"name":"Anvil - spacing","description":"Related to spacing between widgets in auto layout","color":"11ee05"},"Anvil - responsive canvas":{"name":"Anvil - responsive canvas","description":"All issues related to canvas responsiveness","color":"11ee05"},"WDS - inline button widget":{"name":"WDS - inline button widget","description":"Issues related to inline button widget on WDS","color":"7cef83"},"Activation Pod":{"name":"Activation Pod","description":"for Activation group","color":"d67d00"},"Activation":{"name":"Activation","description":"for Activation group","color":"d67d00"},"Tests":{"name":"Tests","description":"Test issues","color":"4fc7b6"},"Ballpark: XXS":{"name":"Ballpark: XXS","description":"~1xDev in 1/2xSprint","color":""},"Ballpark: XS":{"name":"Ballpark: XS","description":"~1xDev in 1xSprint","color":"53bf71"},"Ballpark: S":{"name":"Ballpark: S","description":"~2xDev in 1xSprint","color":"6e9e65"},"Ballpark: M":{"name":"Ballpark: M","description":"~1xPOD in 1xSprint","color":"2229e6"},"Ballpark: L":{"name":"Ballpark: L","description":"~1xPOD in 3xSprint or 2xPODs in 1xSprint","color":"49962f"},"Ballpark: XL":{"name":"Ballpark: XL","description":"~1xPOD in 1xQuarter or 2xPODs in 2xSprint","color":"b524c9"},"Ballpark: XXL":{"name":"Ballpark: XXL","description":"~2xPODs in 1xQuarter","color":"22092c"},"Auto-commit":{"name":"Auto-commit","description":"Issues related to auto-generated commits showing up on git ","color":"e25b89"},"Continuous Deployment":{"name":"Continuous Deployment","description":"Issues related to CD pipeline on git","color":"aea47c"},"Default branch":{"name":"Default branch","description":"Issues related to using a default branch on git","color":"195737"},"Git status":{"name":"Git status","description":"Issues related to information shown on git status modal or number of changes appearing in a branch","color":"c851b8"},"Git performance":{"name":"Git performance","description":"Issues related to perceived performance on any git operation","color":"189af6"},"Anvil team":{"name":"Anvil team","description":"issues related to the new layout system anvil","color":"798200"},"SDLC":{"name":"SDLC","description":"Issues related to software development lifecycle experiences","color":"bae511"},"Reconnect DS modal":{"name":"Reconnect DS modal","description":"Issues related to reconnect datasource modal post app import","color":"2e398b"},"Stability Pod":{"name":"Stability Pod","description":"For all issues/tasks to be prioritized under Stability pod","color":"86ddf6"},"Stability Issue":{"name":"Stability Issue","description":"Every issue handle by Stability Pod","color":"4d024a"},"Move to Postgres":{"name":"Move to Postgres","description":"Issues required to be solved for the move to Postgres as repository layer","color":"466ab1"},"User Session":{"name":"User Session","description":"Issues related to user sessions","color":"8255e5"},"IDE tabs":{"name":"IDE tabs","description":"query and js tabs","color":"1bb96a"},"Inviting Contribution":{"name":"Inviting Contribution","description":"Issues that we would like contributions to","color":""},"cypress-flaky-fix":{"name":"cypress-flaky-fix","description":"This label is auto-added when a PR which only has Cypress fixes are merged to release","color":"cd8bb6"},"Cypress flaky tests":{"name":"Cypress flaky tests","description":"Test scripts that need to be fixed on Cypress by dev or SDET","color":"cd8bb6"},"Help enterprise":{"name":"Help enterprise","description":"Requested by Appsmith customers or prospects","color":"FF8C00"},"Learnability":{"name":"Learnability","description":"Issues affecting the product learnability, making the product harder for new users.","color":"800c2f"},"ADS Spacing":{"name":"ADS Spacing","description":"","color":"686ebb"},"ads unit test":{"name":"ads unit test","description":"All issue related ads unit cases","color":"686ebb"},"ads revamp":{"name":"ads revamp","description":"All issues related to ads revamp.","color":"686ebb"},"Javascript Product":{"color":"709a21","name":"Javascript Product","description":"Issues related to users writing javascript in appsmith"},"IDE Product":{"color":"1bb96a","name":"IDE Product","description":"Issues related to the IDE Product"},"IDE Pod":{"color":"1bb96a","name":"IDE Pod","description":"Issues that new developers face while exploring the IDE"},"Accelerators Product":{"name":"Accelerators Product","description":"Issues related to app building accelerators","color":"f3fce6"},"Templates Product":{"name":"Templates Product","description":"Issues related to Templates","color":"f3fce6"},"Design System Product":{"name":"Design System Product","description":"Appsmith design system related issues","color":"2b4664"},"ads deduplication":{"name":"ads deduplication","description":"Replacing component with ADS components","color":"708943"},"Admin Settings Product":{"color":"708943","name":"Admin Settings Product","description":"Issues in admin settings pages"},"Appsmith AI":{"name":"Appsmith AI","description":"All issues related to the Appsmith AI datasource","color":"708943"},"Query & JS Pod":{"color":"709a21","name":"Query & JS Pod","description":"Issues related to the query & JS Pod"},"RBAC Product":{"name":"RBAC Product","description":"Issues, requests and enhancements around RBAC.","color":""},"Workspace Product":{"name":"Workspace Product","description":"Issues related to workspaces","color":""},"CE Instance Usage":{"name":"CE Instance Usage","description":"For all issues relating to usage, licensing or billing on the CE instance","color":""},"Billing & Licensing Product":{"name":"Billing & Licensing Product","description":"Issues pertaining to licensing, billing and usage across self serve and enterprise customers","color":"466ab1"},"Platform Administration Pod":{"color":"446925","name":"Platform Administration Pod","description":"Issues related to platform administration & management"},"DB Infrastructure Pod":{"name":"DB Infrastructure Pod","description":"Pod to handle database infrastructure","color":"446925"},"Packages Product":{"name":"Packages Product","description":"Issues related to packages","color":"7e018f"},"Workflows Product":{"name":"Workflows Product","description":"Issues related to the workflows product","color":"446925"},"Debugger Product":{"color":"857f58","name":"Debugger Product","description":"Issues related to the debugger"},"Packages Pod":{"name":"Packages Pod","description":"issues that belong to the packages pod","color":"53742c"},"Environments Product":{"name":"Environments Product","description":"Issues related to datasource environments","color":"857f58"},"Custom Widgets":{"name":"Custom Widgets","description":"For all issues related to the custom widget project","color":"857f58"},"Branding Product":{"name":"Branding Product","description":"All issues under branding and whitelabelling appsmith ecosystem","color":"857f58"},"Widgets & Accelerators Pod":{"name":"Widgets & Accelerators Pod","description":"Issues related to widgets & Accelerators","color":"27496a"},"Widgets Product":{"name":"Widgets Product","description":"This label groups issues related to widgets","color":"f3fce6"},"App Theming Product":{"name":"App Theming Product","description":"Items that are related to the App level theming controls epic","color":"48883f"},"UI Building Product":{"color":"48883f","name":"UI Building Product","description":"Issues related to the UI Building experience"},"Onboarding Product":{"color":"48883f","name":"Onboarding Product","description":"Issues related to onboarding new developers"},"Database Schema":{"name":"Database Schema","description":"Issues related to database schema","color":"48883f"},"Git Product":{"color":"7e018f","name":"Git Product","description":"Issues related to version control product"},"Embedding Apps Product":{"name":"Embedding Apps Product","description":"Issues related to embedding","color":"48883f"},"Integrations Product":{"name":"Integrations Product","description":"Issues related to a specific integration","color":"b9f21c"},"Feature Flagging":{"name":"Feature Flagging","description":"Anything related feature flagging","color":"4574ae"},"Audit Logs Product":{"name":"Audit Logs Product","description":"Audit trails to ensure data security","color":"4574ae"},"Identity & Authentication Product":{"name":"Identity & Authentication Product","description":"Issues related to user identity & authentication","color":"4574ae"},"Email verification":{"name":"Email verification","description":"Email verification issues","color":"4574ae"},"Artifact Platform Product":{"name":"Artifact Platform Product","description":"Issues related to the application platform","color":"4574ae"},"Git IA":{"name":"Git IA","description":"Issues related to Git IA changes","color":"df8bd6"},"Documentation Pod":{"name":"Documentation Pod","description":"Issues related to user education","color":"8c8c02"},"Branch management":{"name":"Branch management","description":"Issues related to using a branch management on git","color":"ebe6af"},"Reconfigure Datasource Modal":{"name":"Reconfigure Datasource Modal","description":"Issues related to reconfigure DS modal that comes after importing applications","color":"5ac17b"},"Setup Issues":{"name":"Setup Issues","description":"Issues related to setting up appsmith","color":"3fc837"},"Packages & Git Pod":{"name":"Packages & Git Pod","description":"All issues belonging to Packages and Git","color":"46ac0e"},"Git Platform":{"name":"Git Platform","description":"Issues related to the git & the app platform","color":"c9ab80"},"Entity Management":{"name":"Entity Management","description":"Copy / Move / Delete widgets / queries / datasources","color":"74c33c"},"Cypress":{"name":"Cypress","description":"Tasks related to Cypress automation","color":"67b83c"}},"success":true} \ No newline at end of file From c43f84d7d58d3a057fb8fa389bfe18cb42662259 Mon Sep 17 00:00:00 2001 From: NandanAnantharamu <67676905+NandanAnantharamu@users.noreply.github.com> Date: Fri, 3 Jan 2025 12:08:10 +0530 Subject: [PATCH 15/40] test: flaky check for published Spec (#38427) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit /ok-to-test tags="@tag.Sanity" > [!TIP] > 🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉 > Workflow run: > Commit: a174b8a1167c5da3851af49999956edd0e9ff251 > Cypress dashboard. > Tags: `@tag.Sanity` > Spec: >
Fri, 03 Jan 2025 06:17:34 UTC --------- Co-authored-by: “NandanAnantharamu” <“nandan@thinkify.io”> --- .../PublishedApps/PublishedModeToastToggle_Spec.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/app/client/cypress/e2e/Regression/ClientSide/PublishedApps/PublishedModeToastToggle_Spec.ts b/app/client/cypress/e2e/Regression/ClientSide/PublishedApps/PublishedModeToastToggle_Spec.ts index 67c1ff0d9d78..5272f297bdea 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/PublishedApps/PublishedModeToastToggle_Spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/PublishedApps/PublishedModeToastToggle_Spec.ts @@ -9,15 +9,15 @@ const RUN_JS_OBJECT_MSG = "Incorrect_users failed to execute"; const PAGE_LOAD_MSG = `The action "Incorrect_users" has failed.`; -describe( +describe.skip( "Published mode toggle toast with debug flag in the url", { tags: ["@tag.JS", "@tag.Binding"] }, function () { before(() => { _.agHelper.AddDsl("publishedModeToastToggleDsl"); }); - - it("1. Should not show any application related toasts", function () { + //open bug: https://github.com/appsmithorg/appsmith/issues/38165 + it.skip("1. Should not show any application related toasts", function () { _.apiPage.CreateAndFillApi( _.dataManager.dsValues[_.dataManager.defaultEnviorment].mockApiUrl, "Correct_users", @@ -72,7 +72,8 @@ describe( ); }); - it("2. Should show all application related toasts with debug flag true in url", function () { + //open bug: https://github.com/appsmithorg/appsmith/issues/38165 + it.skip("2. Should show all application related toasts with debug flag true in url", function () { cy.url().then((url) => { cy.visit({ url, From 1405aa60364bdf4c0f356a3c6ed9634ff4a2f9f1 Mon Sep 17 00:00:00 2001 From: Rahul Barwal Date: Fri, 3 Jan 2025 12:57:57 +0530 Subject: [PATCH 16/40] fix: update client version in JsonSchemaVersionsFallback (#38390) (#38391) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description Updated the client version from 1 to 2 in the JsonSchemaVersionsFallback class to align with the latest schema changes. With introduction fo HTML column type in appsmith table, we don't want, apps exported from a newer version to be importable in the older version. Fixes #38311 _or_ Fixes `Issue URL` > [!WARNING] > _If no issue exists, please create an issue first, and check with the maintainers if the issue is valid._ ## Automation /ok-to-test tags="@tag.Sanity" ### :mag: Cypress test results > [!TIP] > 🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉 > Workflow run: > Commit: 51523c9179b6ca63602b72dd1e230dfa693e2a95 > Cypress dashboard. > Tags: `@tag.Sanity` > Spec: >
Thu, 02 Jan 2025 11:33:56 UTC ## Communication Should the DevRel and Marketing teams inform users about this change? - [ ] Yes - [x] No ## Summary by CodeRabbit - **New Features** - Updated client version to reflect changes in the application. - Incremented client schema version to align with application updates. - **Bug Fixes** - Corrected the static client version to ensure accurate version reporting. - **Tests** - Enhanced test setup to initialize the application with the current client schema version. - Updated expected values in tests to reflect the new client schema version. --- .../appsmith/server/migrations/JsonSchemaVersionsFallback.java | 2 +- .../appsmith/server/imports/internal/ImportServiceTests.java | 3 ++- .../resources/com/appsmith/server/migrations/application.json | 2 +- .../test_assets/ImportExportServiceTest/file-with-v1.json | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/JsonSchemaVersionsFallback.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/JsonSchemaVersionsFallback.java index c85b95bed5de..14a273555034 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/JsonSchemaVersionsFallback.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/JsonSchemaVersionsFallback.java @@ -5,7 +5,7 @@ @Component public class JsonSchemaVersionsFallback { private static final Integer serverVersion = 11; - public static final Integer clientVersion = 1; + public static final Integer clientVersion = 2; public Integer getServerVersion() { return serverVersion; 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 cfc76f867793..e6fe0159535b 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 @@ -273,6 +273,7 @@ public void setup() { testApplication.setLastDeployedAt(Instant.now()); testApplication.setModifiedBy("some-user"); testApplication.setGitApplicationMetadata(new GitArtifactMetadata()); + testApplication.setClientSchemaVersion(jsonSchemaVersions.getClientVersion()); Application.ThemeSetting themeSettings = getThemeSetting(); testApplication.setUnpublishedApplicationDetail(new ApplicationDetail()); @@ -2733,7 +2734,7 @@ public void applySchemaMigration_jsonFileWithFirstVersion_migratedToLatestVersio ApplicationJson latestApplicationJson = tuple.getT2(); assertThat(v1ApplicationJson.getServerSchemaVersion()).isEqualTo(1); - assertThat(v1ApplicationJson.getClientSchemaVersion()).isEqualTo(1); + assertThat(v1ApplicationJson.getClientSchemaVersion()).isEqualTo(2); assertThat(latestApplicationJson.getServerSchemaVersion()) .isEqualTo(jsonSchemaVersions.getServerVersion()); diff --git a/app/server/appsmith-server/src/test/resources/com/appsmith/server/migrations/application.json b/app/server/appsmith-server/src/test/resources/com/appsmith/server/migrations/application.json index def16682e2bc..c7e9785ecd98 100644 --- a/app/server/appsmith-server/src/test/resources/com/appsmith/server/migrations/application.json +++ b/app/server/appsmith-server/src/test/resources/com/appsmith/server/migrations/application.json @@ -1,6 +1,6 @@ { "artifactJsonType": "APPLICATION", - "clientSchemaVersion": 1.0, + "clientSchemaVersion": 2.0, "serverSchemaVersion": 7.0, "exportedApplication": { "name": "json-schema-migration", diff --git a/app/server/appsmith-server/src/test/resources/test_assets/ImportExportServiceTest/file-with-v1.json b/app/server/appsmith-server/src/test/resources/test_assets/ImportExportServiceTest/file-with-v1.json index c9b595ecacee..21b237c8143d 100644 --- a/app/server/appsmith-server/src/test/resources/test_assets/ImportExportServiceTest/file-with-v1.json +++ b/app/server/appsmith-server/src/test/resources/test_assets/ImportExportServiceTest/file-with-v1.json @@ -1,4 +1,4 @@ { "serverSchemaVersion": 1, - "clientSchemaVersion": 1 + "clientSchemaVersion": 2 } From 28d35ad903e42b49465cf45e6192b551a7c9f9eb Mon Sep 17 00:00:00 2001 From: Sagar Khalasi Date: Fri, 3 Jan 2025 17:59:13 +0530 Subject: [PATCH 17/40] test: Added branding related test for the community user (#38460) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description Admin setting Test case for branding Fixes # https://app.zenhub.com/workspaces/stability-pod-6690c4814e31602e25cab7fd/issues/gh/appsmithorg/appsmith/38459 ## Automation /ok-to-test tags="@tag.Settings,@tag.Sanity" ### :mag: Cypress test results > [!TIP] > 🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉 > Workflow run: > Commit: 7e053395ee581021db07aca61543a879d3a0abbd > Cypress dashboard. > Tags: `@tag.Settings,@tag.Sanity` > Spec: >
Fri, 03 Jan 2025 08:28:02 UTC ## Communication Should the DevRel and Marketing teams inform users about this change? - [ ] Yes - [x] No ## Summary by CodeRabbit - **Tests** - Added a new Cypress test suite for validating Admin Branding Page settings - Implemented test case for verifying branding data updates for community users - Tested logo and favicon uploads in various image formats - **Locators** - Added multiple new locators for Admin Settings UI elements - Introduced locators for branding, authentication, and application management interfaces --- .../AdminSettings/Branding_settings_Spec.ts | 108 ++++++++++++++++++ .../fixtures/appsmith-community-logo.svg | 13 +++ .../cypress/fixtures/branding_sample.png | Bin 0 -> 97 bytes .../cypress/fixtures/branding_sampleICO.ico | Bin 0 -> 320 bytes .../cypress/fixtures/branding_samplejpg.jpg | Bin 0 -> 645 bytes app/client/cypress/locators/AdminsSettings.js | 23 ++++ 6 files changed, 144 insertions(+) create mode 100644 app/client/cypress/e2e/Regression/ClientSide/AdminSettings/Branding_settings_Spec.ts create mode 100644 app/client/cypress/fixtures/appsmith-community-logo.svg create mode 100644 app/client/cypress/fixtures/branding_sample.png create mode 100644 app/client/cypress/fixtures/branding_sampleICO.ico create mode 100644 app/client/cypress/fixtures/branding_samplejpg.jpg diff --git a/app/client/cypress/e2e/Regression/ClientSide/AdminSettings/Branding_settings_Spec.ts b/app/client/cypress/e2e/Regression/ClientSide/AdminSettings/Branding_settings_Spec.ts new file mode 100644 index 000000000000..dfb61e890cf2 --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/AdminSettings/Branding_settings_Spec.ts @@ -0,0 +1,108 @@ +import { + agHelper, + adminSettings, + locators, +} from "../../../../support/Objects/ObjectsCore"; +import AdminsSettings from "../../../../locators/AdminsSettings"; + +describe( + "Admin Branding Page - Branding page validations", + { tags: ["@tag.Settings"] }, + () => { + it("1. Verify branding data update for community user", () => { + adminSettings.NavigateToAdminSettings(); + agHelper.AssertElementVisibility(AdminsSettings.LeftPaneBrandingLink); + agHelper.GetNClick(AdminsSettings.LeftPaneBrandingLink); + + // branding logo PNG + cy.get(AdminsSettings.AdmingSettingsLogoInput).selectFile( + "cypress/fixtures/appsmithlogo.png", + { force: true }, + ); + agHelper.AssertElementAbsence(locators._toastMsg); + agHelper.AssertElementVisibility( + AdminsSettings.AdmingSettingsLogoInputImage, + ); + agHelper.WaitForCondition(() => { + cy.get(AdminsSettings.BrandingLogo) + .invoke("attr", "src") + .then((src) => { + cy.get(AdminsSettings.AdmingSettingsLogoInputImage) + .invoke("attr", "src") + .should("equal", src); + }); + }); + + // branding logo jpg + cy.get(AdminsSettings.AdmingSettingsLogoInput).selectFile( + "cypress/fixtures/AAAFlowerVase.jpeg", + { force: true }, + ); + agHelper.AssertElementAbsence(locators._toastMsg); + agHelper.AssertElementVisibility( + AdminsSettings.AdmingSettingsLogoInputImage, + ); + agHelper.WaitForCondition(() => { + cy.get(AdminsSettings.BrandingLogo) + .invoke("attr", "src") + .then((src) => { + cy.get(AdminsSettings.AdmingSettingsLogoInputImage) + .invoke("attr", "src") + .should("equal", src); + }); + }); + + // branding logo svg + // comment due to bug: https://github.com/appsmithorg/appsmith/issues/34329 + // cy.get(AdminsSettings.AdmingSettingsLogoInput).selectFile( + // "cypress/fixtures/appsmith-community-logo.svg", + // { force: true }, + // ); + // agHelper.AssertElementAbsence(locators._toastMsg); + + // agHelper.AssertElementVisibility( + // AdminsSettings.AdmingSettingsLogoInputImage, + // ); + // agHelper.WaitForCondition(() => { + // cy.get(AdminsSettings.BrandingLogo) + // .invoke("attr", "src") + // .then((src) => { + // cy.get(AdminsSettings.AdmingSettingsLogoInputImage) + // .invoke("attr", "src") + // .should("equal", src); + // }); + // }); + + // branding favicon png + cy.get(AdminsSettings.AdmingSettingsFaviconInput).selectFile( + "cypress/fixtures/branding_sample.png", + { force: true }, + ); + agHelper.AssertElementAbsence(locators._toastMsg); + agHelper.AssertElementVisibility( + AdminsSettings.AdmingSettingsFaviconInputImage, + ); + cy.get(AdminsSettings.BrandingFavicon) + .invoke("attr", "src") + .then((src) => { + cy.get(AdminsSettings.AdmingSettingsFaviconInputImage) + .invoke("attr", "src") + .should("equal", src); + }); + + // branding favicon jpg + cy.get(AdminsSettings.AdmingSettingsFaviconInput).selectFile( + "cypress/fixtures/branding_samplejpg.jpg", + { force: true }, + ); + agHelper.AssertElementAbsence(locators._toastMsg); + + // branding favicon ico + cy.get(AdminsSettings.AdmingSettingsFaviconInput).selectFile( + "cypress/fixtures/branding_sampleICO.ico", + { force: true }, + ); + agHelper.AssertElementAbsence(locators._toastMsg); + }); + }, +); diff --git a/app/client/cypress/fixtures/appsmith-community-logo.svg b/app/client/cypress/fixtures/appsmith-community-logo.svg new file mode 100644 index 000000000000..d15878da9ffa --- /dev/null +++ b/app/client/cypress/fixtures/appsmith-community-logo.svg @@ -0,0 +1,13 @@ + + + + + + + + + COMMUNITY + \ No newline at end of file diff --git a/app/client/cypress/fixtures/branding_sample.png b/app/client/cypress/fixtures/branding_sample.png new file mode 100644 index 0000000000000000000000000000000000000000..b5e8e02c8700a7edc2c5ff726c17424216c17522 GIT binary patch literal 97 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1SJ1Ryj={WG(24#Ln`LHJ!{Cwz`$|X;K2TL ngM<4*94<%SRQtmYQ~&|_vWt%}+IJ@?TY>nVu6{1-oD!Mr34 literal 0 HcmV?d00001 diff --git a/app/client/cypress/fixtures/branding_sampleICO.ico b/app/client/cypress/fixtures/branding_sampleICO.ico new file mode 100644 index 0000000000000000000000000000000000000000..4b47ac6e45985f89d57006877258e04a328ca381 GIT binary patch literal 320 zcmZQzU}Rus5D;Jh0tJQuAZZ4~5)u%8B#>$YVg&^VKM_dX2jb2EKX+a(DJ~$B*VDr# z2uOoW5a3_}k`pFofXop0ba4!+n3MeHyn|GNQsCbeZGpVb9?T35dW`aEkKKxaN*Fv{ z{an^LB{X3%599&~uzC5StJVWK3JCLL54flnyYWhyW?Wei*bHKH04=Uw#i(B$`eQKx zgB3t#ferp6@fM_517h&ovxbZe3>=3I4(v}iIJhsw;d1m%wLk12)4(8KcJUEL`|bo~ JD-ajvasZ$@Mi>A9 literal 0 HcmV?d00001 diff --git a/app/client/cypress/fixtures/branding_samplejpg.jpg b/app/client/cypress/fixtures/branding_samplejpg.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9a0de0af656dd666ee70dfd7b2ed16dd20a16cc9 GIT binary patch literal 645 zcmex=^(PF6}rMnOeST|r4lSw=>~TvNxu(8R<c1}I=;VrF4wW9Q)H;sz?% zD!{d!pzFb!U9xX3zTPI5o8roG<0MW4oqZMDikqloVbuf*=gfJ(V&YTRE(2~ znmD<{#3dx9RMpfqG__1j&CD$#!=o3Ax_(anF0iOeg8_<}|K9`v*JISr literal 0 HcmV?d00001 diff --git a/app/client/cypress/locators/AdminsSettings.js b/app/client/cypress/locators/AdminsSettings.js index fab7f3a511d3..a93d245b98a8 100644 --- a/app/client/cypress/locators/AdminsSettings.js +++ b/app/client/cypress/locators/AdminsSettings.js @@ -47,4 +47,27 @@ export default { sessionTimeoutWrapper: ".t--admin-settings-userSessionTimeoutInMinutes", sessionTimeoutInput: "[name='userSessionTimeoutInMinutes']", adminEmailsData: ".t--admin-settings-APPSMITH_ADMIN_EMAILS span > span", + LeftPaneBrandingLink: ".t--settings-category-branding", + AdminSettingsColorInput: ".t--settings-brand-color-input input[type=text]", + AdmingSettingsLogoInput: ".t--settings-brand-logo-input input[type=file]", + AdmingSettingsLogoInputImage: ".t--settings-brand-logo-input img", + AdmingSettingsFaviconInput: + ".t--settings-brand-favicon-input input[type=file]", + AdmingSettingsFaviconInputImage: ".t--settings-brand-favicon-input img", + BrandingBg: ".t--branding-bg", + BrandingLogo: ".t--branding-logo", + BrandingFavicon: "img.t--branding-favicon", + BrandingFaviconHead: "link.t--branding-favicon", + dashboardAppTab: ".t--apps-tab", + createNewAppButton: ".t--new-button", + loginContainer: ".t--login-container", + signupLink: ".t--signup-link", + authContainer: ".t--auth-container", + submitButton: "button[type='submit']", + appsmithLogo: ".t--appsmith-logo", + appsmithLogoImg: ".t--appsmith-logo img", + AdminSettingsColorInputShades: ".t--color-input-shades", + businessTag: ".business-tag", + upgradeBanner: ".upgrade-banner", + upgradeButton: "[data-testid='t--button-upgrade']", }; From c2e4e11eb3b08b64fa5a51736cbe703af6f45716 Mon Sep 17 00:00:00 2001 From: Hetu Nandu Date: Fri, 3 Jan 2025 18:05:09 +0530 Subject: [PATCH 18/40] feat: State Inspector (#38368) --- .../ads/src/Icon/Icon.provider.tsx | 4 +- .../src/__assets__/icons/ads/globe-simple.svg | 5 + app/client/src/IDE/Components/BottomView.tsx | 2 + app/client/src/actions/debuggerActions.ts | 10 + app/client/src/actions/jsPaneActions.ts | 16 +- app/client/src/actions/pluginActionActions.ts | 9 +- .../hooks/usePluginActionResponseTabs.tsx | 19 +- .../src/ce/constants/ReduxActionConstants.tsx | 2 + app/client/src/ce/constants/messages.ts | 1 + app/client/src/ce/entities/IDE/constants.ts | 2 + .../Editor/IDE/EditorPane/JS/ListItem.tsx | 1 - .../src/ce/selectors/entitiesSelector.ts | 24 +- .../Debugger/DebuggerTabs.tsx | 81 +++-- .../StateInspector/StateInspector.test.tsx | 143 +++++++++ .../StateInspector/StateInspector.tsx | 101 ++++++ .../Debugger/StateInspector/hooks/index.ts | 1 + .../useGetGlobalItemsForStateInspector.ts | 20 ++ .../hooks/useGetJSItemsForStateInspector.ts | 15 + .../useGetQueryItemsForStateInspector.ts | 16 + .../hooks/useGetUIItemsForStateInspector.ts | 15 + .../hooks/useStateInspectorItems.ts | 100 ++++++ .../hooks/useStateInspectorState.ts | 19 ++ .../Debugger/StateInspector/index.ts | 1 + .../Debugger/StateInspector/styles.ts | 23 ++ .../Debugger/StateInspector/types.ts | 15 + .../Debugger/StateInspector/utils.ts | 21 ++ .../editorComponents/Debugger/constants.ts | 1 + .../editorComponents/JSResponseView.tsx | 293 ++++++++++-------- .../pages/Editor/Explorer/ExplorerIcons.tsx | 14 + .../src/pages/Editor/Explorer/Files/index.tsx | 1 - .../Explorer/JSActions/JSActionEntity.tsx | 2 - .../reducers/uiReducers/debuggerReducer.ts | 16 + .../sagas/ActionExecution/PluginActionSaga.ts | 7 +- app/client/src/sagas/EvaluationsSaga.ts | 3 +- app/client/src/sagas/JSPaneSagas.ts | 1 + .../src/selectors/debuggerSelectors.tsx | 3 + 36 files changed, 825 insertions(+), 182 deletions(-) create mode 100644 app/client/packages/design-system/ads/src/__assets__/icons/ads/globe-simple.svg create mode 100644 app/client/src/components/editorComponents/Debugger/StateInspector/StateInspector.test.tsx create mode 100644 app/client/src/components/editorComponents/Debugger/StateInspector/StateInspector.tsx create mode 100644 app/client/src/components/editorComponents/Debugger/StateInspector/hooks/index.ts create mode 100644 app/client/src/components/editorComponents/Debugger/StateInspector/hooks/useGetGlobalItemsForStateInspector.ts create mode 100644 app/client/src/components/editorComponents/Debugger/StateInspector/hooks/useGetJSItemsForStateInspector.ts create mode 100644 app/client/src/components/editorComponents/Debugger/StateInspector/hooks/useGetQueryItemsForStateInspector.ts create mode 100644 app/client/src/components/editorComponents/Debugger/StateInspector/hooks/useGetUIItemsForStateInspector.ts create mode 100644 app/client/src/components/editorComponents/Debugger/StateInspector/hooks/useStateInspectorItems.ts create mode 100644 app/client/src/components/editorComponents/Debugger/StateInspector/hooks/useStateInspectorState.ts create mode 100644 app/client/src/components/editorComponents/Debugger/StateInspector/index.ts create mode 100644 app/client/src/components/editorComponents/Debugger/StateInspector/styles.ts create mode 100644 app/client/src/components/editorComponents/Debugger/StateInspector/types.ts create mode 100644 app/client/src/components/editorComponents/Debugger/StateInspector/utils.ts diff --git a/app/client/packages/design-system/ads/src/Icon/Icon.provider.tsx b/app/client/packages/design-system/ads/src/Icon/Icon.provider.tsx index d12bc1f519d5..47e819cb8aae 100644 --- a/app/client/packages/design-system/ads/src/Icon/Icon.provider.tsx +++ b/app/client/packages/design-system/ads/src/Icon/Icon.provider.tsx @@ -137,8 +137,8 @@ const GitPullRequest = importRemixIcon( const GitRepository = importRemixIcon( async () => import("remixicon-react/GitRepositoryLineIcon"), ); -const GlobalLineIcon = importRemixIcon( - async () => import("remixicon-react/GlobalLineIcon"), +const GlobalLineIcon = importSvg( + async () => import("../__assets__/icons/ads/globe-simple.svg"), ); const GuideIcon = importRemixIcon( async () => import("remixicon-react/GuideFillIcon"), diff --git a/app/client/packages/design-system/ads/src/__assets__/icons/ads/globe-simple.svg b/app/client/packages/design-system/ads/src/__assets__/icons/ads/globe-simple.svg new file mode 100644 index 000000000000..73cc64e05831 --- /dev/null +++ b/app/client/packages/design-system/ads/src/__assets__/icons/ads/globe-simple.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/client/src/IDE/Components/BottomView.tsx b/app/client/src/IDE/Components/BottomView.tsx index 0d5b7028c406..29f8e6f84587 100644 --- a/app/client/src/IDE/Components/BottomView.tsx +++ b/app/client/src/IDE/Components/BottomView.tsx @@ -28,6 +28,7 @@ const Container = styled.div<{ displayMode: ViewDisplayMode }>` const ViewWrapper = styled.div` height: 100%; + &&& { ul.ads-v2-tabs__list { margin: 0 var(--ads-v2-spaces-8); @@ -39,6 +40,7 @@ const ViewWrapper = styled.div` .ads-v2-tabs__list { padding: var(--ads-v2-spaces-1) var(--ads-v2-spaces-7); padding-left: var(--ads-v2-spaces-3); + user-select: none; } } diff --git a/app/client/src/actions/debuggerActions.ts b/app/client/src/actions/debuggerActions.ts index be2052a4e16f..c33075972c6d 100644 --- a/app/client/src/actions/debuggerActions.ts +++ b/app/client/src/actions/debuggerActions.ts @@ -7,6 +7,7 @@ import type { } from "reducers/uiReducers/debuggerReducer"; import type { EventName } from "ee/utils/analyticsUtilTypes"; import type { APP_MODE } from "entities/App"; +import type { GenericEntityItem } from "ee/entities/IDE/constants"; export interface LogDebuggerErrorAnalyticsPayload { entityName: string; @@ -147,3 +148,12 @@ export const showDebuggerLogs = () => { type: ReduxActionTypes.SHOW_DEBUGGER_LOGS, }; }; + +export const setDebuggerStateInspectorSelectedItem = ( + payload: GenericEntityItem, +) => { + return { + type: ReduxActionTypes.SET_DEBUGGER_STATE_INSPECTOR_SELECTED_ITEM, + payload, + }; +}; diff --git a/app/client/src/actions/jsPaneActions.ts b/app/client/src/actions/jsPaneActions.ts index 030f0e2e9698..70a01db6ec7e 100644 --- a/app/client/src/actions/jsPaneActions.ts +++ b/app/client/src/actions/jsPaneActions.ts @@ -1,6 +1,8 @@ -import type { ReduxAction } from "ee/constants/ReduxActionConstants"; -import { ReduxActionTypes } from "ee/constants/ReduxActionConstants"; -import type { JSCollection, JSAction } from "entities/JSCollection"; +import { + type ReduxAction, + ReduxActionTypes, +} from "ee/constants/ReduxActionConstants"; +import type { JSAction, JSCollection } from "entities/JSCollection"; import type { RefactorAction, SetFunctionPropertyPayload, @@ -10,6 +12,7 @@ import type { JSEditorTab, JSPaneDebuggerState, } from "reducers/uiReducers/jsPaneReducer"; +import type { JSUpdate } from "../utils/JSPaneUtils"; export const createNewJSCollection = ( pageId: string, @@ -132,3 +135,10 @@ export const setJsPaneDebuggerState = ( type: ReduxActionTypes.SET_JS_PANE_DEBUGGER_STATE, payload, }); + +export const executeJSUpdates = ( + payload: Record, +): ReduxAction => ({ + type: ReduxActionTypes.EXECUTE_JS_UPDATES, + payload, +}); diff --git a/app/client/src/actions/pluginActionActions.ts b/app/client/src/actions/pluginActionActions.ts index a2b309d507ee..f953c45c000c 100644 --- a/app/client/src/actions/pluginActionActions.ts +++ b/app/client/src/actions/pluginActionActions.ts @@ -6,7 +6,6 @@ import { ReduxActionErrorTypes, ReduxActionTypes, } from "ee/constants/ReduxActionConstants"; -import type { JSUpdate } from "utils/JSPaneUtils"; import type { Action, ActionViewMode, @@ -343,13 +342,6 @@ export const executePageLoadActions = ( }; }; -export const executeJSUpdates = ( - payload: Record, -): ReduxAction => ({ - type: ReduxActionTypes.EXECUTE_JS_UPDATES, - payload, -}); - export const setActionsToExecuteOnPageLoad = ( actions: Array<{ executeOnLoad: boolean; @@ -399,6 +391,7 @@ export interface updateActionDataPayloadType { actionDataPayload: actionDataPayload; parentSpan?: Span; } + export const updateActionData = ( payload: actionDataPayload, parentSpan?: Span, diff --git a/app/client/src/ce/PluginActionEditor/components/PluginActionResponse/hooks/usePluginActionResponseTabs.tsx b/app/client/src/ce/PluginActionEditor/components/PluginActionResponse/hooks/usePluginActionResponseTabs.tsx index a6825dabbd5b..a4d7a0165cef 100644 --- a/app/client/src/ce/PluginActionEditor/components/PluginActionResponse/hooks/usePluginActionResponseTabs.tsx +++ b/app/client/src/ce/PluginActionEditor/components/PluginActionResponse/hooks/usePluginActionResponseTabs.tsx @@ -3,7 +3,7 @@ import { usePluginActionContext } from "PluginActionEditor/PluginActionContext"; import type { BottomTab } from "components/editorComponents/EntityBottomTabs"; import { getIDEViewMode } from "selectors/ideSelectors"; import { useSelector } from "react-redux"; -import { EditorViewMode } from "ee/entities/IDE/constants"; +import { EditorViewMode, IDE_TYPE } from "ee/entities/IDE/constants"; import { DEBUGGER_TAB_KEYS } from "components/editorComponents/Debugger/constants"; import { createMessage, @@ -11,6 +11,7 @@ import { DEBUGGER_HEADERS, DEBUGGER_LOGS, DEBUGGER_RESPONSE, + DEBUGGER_STATE, } from "ee/constants/messages"; import ErrorLogs from "components/editorComponents/Debugger/Errors"; import DebuggerLogs from "components/editorComponents/Debugger/DebuggerLogs"; @@ -32,6 +33,9 @@ import { } from "PluginActionEditor/hooks"; import useDebuggerTriggerClick from "components/editorComponents/Debugger/hooks/useDebuggerTriggerClick"; import { Response } from "PluginActionEditor/components/PluginActionResponse/components/Response"; +import { StateInspector } from "components/editorComponents/Debugger/StateInspector"; +import { useLocation } from "react-router"; +import { getIDETypeByUrl } from "ee/entities/IDE/utils"; function usePluginActionResponseTabs() { const { action, actionResponse, datasource, plugin } = @@ -108,7 +112,6 @@ function usePluginActionResponseTabs() { if ( [ PluginType.DB, - PluginType.AI, PluginType.REMOTE, PluginType.SAAS, PluginType.INTERNAL, @@ -145,6 +148,10 @@ function usePluginActionResponseTabs() { }); } + const location = useLocation(); + + const ideType = getIDETypeByUrl(location.pathname); + if (IDEViewMode === EditorViewMode.FullScreen) { tabs.push( { @@ -159,6 +166,14 @@ function usePluginActionResponseTabs() { panelComponent: , }, ); + + if (ideType === IDE_TYPE.App) { + tabs.push({ + key: DEBUGGER_TAB_KEYS.STATE_TAB, + title: createMessage(DEBUGGER_STATE), + panelComponent: , + }); + } } return tabs; diff --git a/app/client/src/ce/constants/ReduxActionConstants.tsx b/app/client/src/ce/constants/ReduxActionConstants.tsx index faf894223afc..8c31dda88009 100644 --- a/app/client/src/ce/constants/ReduxActionConstants.tsx +++ b/app/client/src/ce/constants/ReduxActionConstants.tsx @@ -697,6 +697,8 @@ const IDEDebuggerActionTypes = { SET_JS_PANE_DEBUGGER_STATE: "SET_JS_PANE_DEBUGGER_STATE", SET_CANVAS_DEBUGGER_STATE: "SET_CANVAS_DEBUGGER_STATE", SHOW_DEBUGGER_LOGS: "SHOW_DEBUGGER_LOGS", + SET_DEBUGGER_STATE_INSPECTOR_SELECTED_ITEM: + "SET_DEBUGGER_STATE_INSPECTOR_SELECTED_ITEM", }; const ThemeActionTypes = { diff --git a/app/client/src/ce/constants/messages.ts b/app/client/src/ce/constants/messages.ts index a209a97714b4..28c616798ee6 100644 --- a/app/client/src/ce/constants/messages.ts +++ b/app/client/src/ce/constants/messages.ts @@ -564,6 +564,7 @@ export const DEBUGGER_ERRORS = () => "Linter"; export const DEBUGGER_RESPONSE = () => "Response"; export const DEBUGGER_HEADERS = () => "Headers"; export const DEBUGGER_LOGS = () => "Logs"; +export const DEBUGGER_STATE = () => "State"; export const INSPECT_ENTITY = () => "Inspect entity"; export const INSPECT_ENTITY_BLANK_STATE = () => "Select an entity to inspect"; diff --git a/app/client/src/ce/entities/IDE/constants.ts b/app/client/src/ce/entities/IDE/constants.ts index c16c9b826f49..e7fa7a230b18 100644 --- a/app/client/src/ce/entities/IDE/constants.ts +++ b/app/client/src/ce/entities/IDE/constants.ts @@ -129,6 +129,8 @@ export interface EntityItem { userPermissions?: string[]; } +export interface GenericEntityItem extends Omit {} + export type UseRoutes = Array<{ key: string; // TODO: Fix this the next time the file is edited diff --git a/app/client/src/ce/pages/Editor/IDE/EditorPane/JS/ListItem.tsx b/app/client/src/ce/pages/Editor/IDE/EditorPane/JS/ListItem.tsx index f99283114d9c..cf79cc6e9748 100644 --- a/app/client/src/ce/pages/Editor/IDE/EditorPane/JS/ListItem.tsx +++ b/app/client/src/ce/pages/Editor/IDE/EditorPane/JS/ListItem.tsx @@ -24,7 +24,6 @@ export const JSListItem = (props: JSListItemProps) => { parentEntityType={parentEntityType} searchKeyword={""} step={1} - type={item.type} /> ); diff --git a/app/client/src/ce/selectors/entitiesSelector.ts b/app/client/src/ce/selectors/entitiesSelector.ts index a020e93ad13a..d744e14e773b 100644 --- a/app/client/src/ce/selectors/entitiesSelector.ts +++ b/app/client/src/ce/selectors/entitiesSelector.ts @@ -23,7 +23,10 @@ import { import { countBy, find, get, groupBy, keyBy, sortBy } from "lodash"; import ImageAlt from "assets/images/placeholder-image.svg"; import type { CanvasWidgetsReduxState } from "reducers/entityReducers/canvasWidgetsReducer"; -import { MAIN_CONTAINER_WIDGET_ID } from "constants/WidgetConstants"; +import { + MAIN_CONTAINER_WIDGET_ID, + MAIN_CONTAINER_WIDGET_NAME, +} from "constants/WidgetConstants"; import type { AppStoreState } from "reducers/entityReducers/appReducer"; import type { JSCollectionData, @@ -59,10 +62,15 @@ import { import { MAX_DATASOURCE_SUGGESTIONS } from "constants/DatasourceEditorConstants"; import type { CreateNewActionKeyInterface } from "ee/entities/Engine/actionHelpers"; import { getNextEntityName } from "utils/AppsmithUtils"; -import { EditorEntityTab, type EntityItem } from "ee/entities/IDE/constants"; +import { + EditorEntityTab, + type EntityItem, + type GenericEntityItem, +} from "ee/entities/IDE/constants"; import { ActionUrlIcon, JsFileIconV2, + WidgetIconByType, } from "pages/Editor/Explorer/ExplorerIcons"; import { getAssetUrl } from "ee/utils/airgapHelpers"; import { @@ -979,6 +987,18 @@ export const getAllPageWidgets = createSelector( }, ); +export const getUISegmentItems = createSelector(getCanvasWidgets, (widgets) => { + const items: GenericEntityItem[] = Object.values(widgets) + .filter((widget) => widget.widgetName !== MAIN_CONTAINER_WIDGET_NAME) + .map((widget) => ({ + icon: WidgetIconByType(widget.type), + title: widget.widgetName, + key: widget.widgetId, + })); + + return items; +}); + export const getPageList = createSelector( (state: AppState) => state.entities.pageList.pages, (pages) => pages, diff --git a/app/client/src/components/editorComponents/Debugger/DebuggerTabs.tsx b/app/client/src/components/editorComponents/Debugger/DebuggerTabs.tsx index e44b7f1005e9..514423108f63 100644 --- a/app/client/src/components/editorComponents/Debugger/DebuggerTabs.tsx +++ b/app/client/src/components/editorComponents/Debugger/DebuggerTabs.tsx @@ -1,4 +1,4 @@ -import React, { useCallback } from "react"; +import React, { useCallback, useMemo } from "react"; import DebuggerLogs from "./DebuggerLogs"; import { useDispatch, useSelector } from "react-redux"; import { @@ -17,11 +17,16 @@ import { createMessage, DEBUGGER_ERRORS, DEBUGGER_LOGS, + DEBUGGER_STATE, } from "ee/constants/messages"; import { DEBUGGER_TAB_KEYS } from "./constants"; import EntityBottomTabs from "../EntityBottomTabs"; import { ActionExecutionResizerHeight } from "PluginActionEditor/components/PluginActionResponse/constants"; import { IDEBottomView, ViewHideBehaviour, ViewDisplayMode } from "IDE"; +import { StateInspector } from "./StateInspector"; +import { getIDETypeByUrl } from "ee/entities/IDE/utils"; +import { useLocation } from "react-router"; +import { IDE_TYPE } from "ee/entities/IDE/constants"; function DebuggerTabs() { const dispatch = useDispatch(); @@ -31,33 +36,59 @@ function DebuggerTabs() { // get the height of the response pane. const responsePaneHeight = useSelector(getResponsePaneHeight); // set the height of the response pane. - const updateResponsePaneHeight = useCallback((height: number) => { - dispatch(setResponsePaneHeight(height)); - }, []); - const setSelectedTab = (tabKey: string) => { - if (tabKey === DEBUGGER_TAB_KEYS.ERROR_TAB) { - AnalyticsUtil.logEvent("OPEN_DEBUGGER", { - source: "WIDGET_EDITOR", - }); - } + const updateResponsePaneHeight = useCallback( + (height: number) => { + dispatch(setResponsePaneHeight(height)); + }, + [dispatch], + ); - dispatch(setDebuggerSelectedTab(tabKey)); - }; - const onClose = () => dispatch(showDebugger(false)); + const setSelectedTab = useCallback( + (tabKey: string) => { + if (tabKey === DEBUGGER_TAB_KEYS.ERROR_TAB) { + AnalyticsUtil.logEvent("OPEN_DEBUGGER", { + source: "WIDGET_EDITOR", + }); + } - const DEBUGGER_TABS = [ - { - key: DEBUGGER_TAB_KEYS.LOGS_TAB, - title: createMessage(DEBUGGER_LOGS), - panelComponent: , + dispatch(setDebuggerSelectedTab(tabKey)); }, - { - key: DEBUGGER_TAB_KEYS.ERROR_TAB, - title: createMessage(DEBUGGER_ERRORS), - count: errorCount, - panelComponent: , - }, - ]; + [dispatch], + ); + + const onClose = useCallback(() => { + dispatch(showDebugger(false)); + }, [dispatch]); + + const location = useLocation(); + + const ideType = getIDETypeByUrl(location.pathname); + + const DEBUGGER_TABS = useMemo(() => { + const tabs = [ + { + key: DEBUGGER_TAB_KEYS.LOGS_TAB, + title: createMessage(DEBUGGER_LOGS), + panelComponent: , + }, + { + key: DEBUGGER_TAB_KEYS.ERROR_TAB, + title: createMessage(DEBUGGER_ERRORS), + count: errorCount, + panelComponent: , + }, + ]; + + if (ideType === IDE_TYPE.App) { + tabs.push({ + key: DEBUGGER_TAB_KEYS.STATE_TAB, + title: createMessage(DEBUGGER_STATE), + panelComponent: , + }); + } + + return tabs; + }, [errorCount, ideType]); // Do not render if response, header or schema tab is selected in the bottom bar. const shouldRender = !( diff --git a/app/client/src/components/editorComponents/Debugger/StateInspector/StateInspector.test.tsx b/app/client/src/components/editorComponents/Debugger/StateInspector/StateInspector.test.tsx new file mode 100644 index 000000000000..bdf75dabde09 --- /dev/null +++ b/app/client/src/components/editorComponents/Debugger/StateInspector/StateInspector.test.tsx @@ -0,0 +1,143 @@ +import React from "react"; +import { render, screen, fireEvent } from "@testing-library/react"; +import "@testing-library/jest-dom"; +import { StateInspector } from "./StateInspector"; +import { useStateInspectorItems } from "./hooks"; +import { filterEntityGroupsBySearchTerm } from "IDE/utils"; + +jest.mock("./hooks"); +jest.mock("IDE/utils"); + +const mockedUseStateInspectorItems = useStateInspectorItems as jest.Mock; +const mockedFilterEntityGroupsBySearchTerm = + filterEntityGroupsBySearchTerm as jest.Mock; + +describe("StateInspector", () => { + beforeEach(() => { + mockedFilterEntityGroupsBySearchTerm.mockImplementation( + (searchTerm, items) => + items.filter((item: { group: string }) => + item.group.toLowerCase().includes(searchTerm.toLowerCase()), + ), + ); + }); + + it("renders search input and filters items based on search term", () => { + mockedUseStateInspectorItems.mockReturnValue([ + { title: "Item 1", icon: "icon1", code: { key: "value1" } }, + [ + { group: "Group 1", items: [{ title: "Item 1" }] }, + { group: "Group 2", items: [{ title: "Item 2" }] }, + ], + { key: "value1" }, + ]); + render(); + const searchInput = screen.getByPlaceholderText("Search entities"); + + fireEvent.change(searchInput, { target: { value: "Group 1" } }); + expect(screen.getByText("Group 1")).toBeInTheDocument(); + expect(screen.queryByText("Group 2")).not.toBeInTheDocument(); + }); + + it("Calls the onClick of the item", () => { + const mockOnClick = jest.fn(); + + mockedUseStateInspectorItems.mockReturnValue([ + { title: "Item 1", icon: "icon1", code: { key: "value1" } }, + [ + { group: "Group 1", items: [{ title: "Item 1" }] }, + { + group: "Group 2", + items: [{ title: "Item 2", onClick: mockOnClick }], + }, + ], + { key: "value1" }, + ]); + render(); + fireEvent.click(screen.getByText("Item 2")); + + expect(mockOnClick).toHaveBeenCalled(); + }); + + it("Renders the selected item details", () => { + mockedUseStateInspectorItems.mockReturnValue([ + { title: "Item 1", icon: "icon1", code: { key: "value1" } }, + [ + { group: "Group 1", items: [{ title: "Item 1" }] }, + { + group: "Group 2", + items: [{ title: "Item 2" }], + }, + ], + { key: "Value1" }, + ]); + render(); + + expect( + screen.getByTestId("t--selected-entity-details").textContent, + ).toContain("Item 1"); + + expect( + screen.getByTestId("t--selected-entity-details").textContent, + ).toContain("Value1"); + }); + + it("does not render selected item details when no item is selected", () => { + mockedUseStateInspectorItems.mockReturnValue([null, [], null]); + render(); + expect(screen.queryByText("Item 1")).not.toBeInTheDocument(); + }); + + it("renders all items when search term is empty", () => { + mockedUseStateInspectorItems.mockReturnValue([ + { title: "Item 1", icon: "icon1", code: { key: "value1" } }, + [ + { group: "Group 1", items: [{ title: "Item 1" }] }, + { + group: "Group 2", + items: [{ title: "Item 2" }], + }, + ], + { key: "value1" }, + ]); + + render(); + expect(screen.getByText("Group 1")).toBeInTheDocument(); + expect(screen.getByText("Group 2")).toBeInTheDocument(); + }); + it("renders no items when search term does not match any group", () => { + render(); + const searchInput = screen.getByPlaceholderText("Search entities"); + + fireEvent.change(searchInput, { target: { value: "Nonexistent Group" } }); + expect(screen.queryByText("Group 1")).not.toBeInTheDocument(); + expect(screen.queryByText("Group 2")).not.toBeInTheDocument(); + }); + + it("renders no items when items list is empty", () => { + mockedUseStateInspectorItems.mockReturnValue([null, [], null]); + render(); + expect(screen.queryByText("Group 1")).not.toBeInTheDocument(); + expect(screen.queryByText("Group 2")).not.toBeInTheDocument(); + }); + + it("renders correctly when selected item has no code", () => { + mockedUseStateInspectorItems.mockReturnValue([ + { title: "Item 1", icon: "icon1", code: null }, + [ + { group: "Group 1", items: [{ title: "Item 1" }] }, + { group: "Group 2", items: [{ title: "Item 2" }] }, + ], + {}, + ]); + render(); + + expect( + screen.getByTestId("t--selected-entity-details").textContent, + ).toContain("Item 1"); + + expect( + screen.getByTestId("t--selected-entity-details").textContent, + ).toContain("0 items"); + }); +}); diff --git a/app/client/src/components/editorComponents/Debugger/StateInspector/StateInspector.tsx b/app/client/src/components/editorComponents/Debugger/StateInspector/StateInspector.tsx new file mode 100644 index 000000000000..9586104e53e2 --- /dev/null +++ b/app/client/src/components/editorComponents/Debugger/StateInspector/StateInspector.tsx @@ -0,0 +1,101 @@ +import React, { useState } from "react"; +import ReactJson from "react-json-view"; +import { + Flex, + List, + type ListItemProps, + SearchInput, + Text, +} from "@appsmith/ads"; +import { filterEntityGroupsBySearchTerm } from "IDE/utils"; +import { useStateInspectorItems } from "./hooks"; +import * as Styled from "./styles"; + +export const reactJsonProps = { + name: null, + enableClipboard: false, + displayDataTypes: false, + displayArrayKey: true, + quotesOnKeys: false, + style: { + fontSize: "12px", + }, + collapsed: 1, + indentWidth: 2, + collapseStringsAfterLength: 30, +}; + +export const StateInspector = () => { + const [selectedItem, items, selectedItemCode] = useStateInspectorItems(); + const [searchTerm, setSearchTerm] = useState(""); + + const filteredItemGroups = filterEntityGroupsBySearchTerm< + { group: string }, + ListItemProps + >(searchTerm, items); + + return ( + + + + + + + {filteredItemGroups.map((item) => ( + + + {item.group} + + + + ))} + + + {selectedItem ? ( + + + {selectedItem.icon} + {selectedItem.title} + + + + + + ) : null} + + ); +}; diff --git a/app/client/src/components/editorComponents/Debugger/StateInspector/hooks/index.ts b/app/client/src/components/editorComponents/Debugger/StateInspector/hooks/index.ts new file mode 100644 index 000000000000..b17fab687ee0 --- /dev/null +++ b/app/client/src/components/editorComponents/Debugger/StateInspector/hooks/index.ts @@ -0,0 +1 @@ +export { useStateInspectorItems } from "./useStateInspectorItems"; diff --git a/app/client/src/components/editorComponents/Debugger/StateInspector/hooks/useGetGlobalItemsForStateInspector.ts b/app/client/src/components/editorComponents/Debugger/StateInspector/hooks/useGetGlobalItemsForStateInspector.ts new file mode 100644 index 000000000000..24319407e68d --- /dev/null +++ b/app/client/src/components/editorComponents/Debugger/StateInspector/hooks/useGetGlobalItemsForStateInspector.ts @@ -0,0 +1,20 @@ +import { GlobeIcon } from "pages/Editor/Explorer/ExplorerIcons"; +import type { GetGroupHookType } from "../types"; + +export const useGetGlobalItemsForStateInspector: GetGroupHookType = () => { + const appsmithObj = { + key: "appsmith", + title: "appsmith", + icon: GlobeIcon(), + }; + + const appsmithItems = [ + { + id: appsmithObj.key, + title: appsmithObj.title, + startIcon: appsmithObj.icon, + }, + ]; + + return { group: "Globals", items: appsmithItems }; +}; diff --git a/app/client/src/components/editorComponents/Debugger/StateInspector/hooks/useGetJSItemsForStateInspector.ts b/app/client/src/components/editorComponents/Debugger/StateInspector/hooks/useGetJSItemsForStateInspector.ts new file mode 100644 index 000000000000..0d273ee76a02 --- /dev/null +++ b/app/client/src/components/editorComponents/Debugger/StateInspector/hooks/useGetJSItemsForStateInspector.ts @@ -0,0 +1,15 @@ +import { useSelector } from "react-redux"; +import { getJSSegmentItems } from "ee/selectors/entitiesSelector"; +import type { GetGroupHookType } from "../types"; + +export const useGetJSItemsForStateInspector: GetGroupHookType = () => { + const jsObjects = useSelector(getJSSegmentItems); + + const jsItems = jsObjects.map((jsObject) => ({ + id: jsObject.key, + title: jsObject.title, + startIcon: jsObject.icon, + })); + + return { group: "JS objects", items: jsItems }; +}; diff --git a/app/client/src/components/editorComponents/Debugger/StateInspector/hooks/useGetQueryItemsForStateInspector.ts b/app/client/src/components/editorComponents/Debugger/StateInspector/hooks/useGetQueryItemsForStateInspector.ts new file mode 100644 index 000000000000..c27121760944 --- /dev/null +++ b/app/client/src/components/editorComponents/Debugger/StateInspector/hooks/useGetQueryItemsForStateInspector.ts @@ -0,0 +1,16 @@ +import { useSelector } from "react-redux"; +import { getQuerySegmentItems } from "ee/selectors/entitiesSelector"; +import type { GetGroupHookType } from "../types"; + +export const useGetQueryItemsForStateInspector: GetGroupHookType = () => { + const queries = useSelector(getQuerySegmentItems); + + const queryItems = queries.map((query) => ({ + id: query.key, + title: query.title, + startIcon: query.icon, + className: "query-item", + })); + + return { group: "Queries", items: queryItems }; +}; diff --git a/app/client/src/components/editorComponents/Debugger/StateInspector/hooks/useGetUIItemsForStateInspector.ts b/app/client/src/components/editorComponents/Debugger/StateInspector/hooks/useGetUIItemsForStateInspector.ts new file mode 100644 index 000000000000..a89c2a111f35 --- /dev/null +++ b/app/client/src/components/editorComponents/Debugger/StateInspector/hooks/useGetUIItemsForStateInspector.ts @@ -0,0 +1,15 @@ +import { useSelector } from "react-redux"; +import { getUISegmentItems } from "ee/selectors/entitiesSelector"; +import type { GetGroupHookType } from "../types"; + +export const useGetUIItemsForStateInspector: GetGroupHookType = () => { + const widgets = useSelector(getUISegmentItems); + + const widgetItems = widgets.map((widget) => ({ + id: widget.key, + title: widget.title, + startIcon: widget.icon, + })); + + return { group: "UI elements", items: widgetItems }; +}; diff --git a/app/client/src/components/editorComponents/Debugger/StateInspector/hooks/useStateInspectorItems.ts b/app/client/src/components/editorComponents/Debugger/StateInspector/hooks/useStateInspectorItems.ts new file mode 100644 index 000000000000..98909808200c --- /dev/null +++ b/app/client/src/components/editorComponents/Debugger/StateInspector/hooks/useStateInspectorItems.ts @@ -0,0 +1,100 @@ +import { useEffect, useMemo } from "react"; +import { useStateInspectorState } from "./useStateInspectorState"; +import { useGetGlobalItemsForStateInspector } from "./useGetGlobalItemsForStateInspector"; +import { useGetQueryItemsForStateInspector } from "./useGetQueryItemsForStateInspector"; +import { useGetJSItemsForStateInspector } from "./useGetJSItemsForStateInspector"; +import { useGetUIItemsForStateInspector } from "./useGetUIItemsForStateInspector"; +import type { GroupedItems } from "../types"; +import { enhanceItemForListItem } from "../utils"; +import type { GenericEntityItem } from "ee/entities/IDE/constants"; +import { filterInternalProperties } from "utils/FilterInternalProperties"; +import { getConfigTree, getDataTree } from "selectors/dataTreeSelectors"; +import { getJSCollections } from "ee/selectors/entitiesSelector"; +import { useSelector } from "react-redux"; + +export const useStateInspectorItems: () => [ + GenericEntityItem | undefined, + GroupedItems[], + unknown, +] = () => { + const [selectedItem, setSelectedItem] = useStateInspectorState(); + + const queries = useGetQueryItemsForStateInspector(); + const jsItems = useGetJSItemsForStateInspector(); + const uiItems = useGetUIItemsForStateInspector(); + const globalItems = useGetGlobalItemsForStateInspector(); + + const groups = useMemo(() => { + const returnValue: GroupedItems[] = []; + + if (queries.items.length) { + returnValue.push({ + ...queries, + items: queries.items.map((query) => + enhanceItemForListItem(query, selectedItem, setSelectedItem), + ), + }); + } + + if (jsItems.items.length) { + returnValue.push({ + ...jsItems, + items: jsItems.items.map((jsItem) => + enhanceItemForListItem(jsItem, selectedItem, setSelectedItem), + ), + }); + } + + if (uiItems.items.length) { + returnValue.push({ + ...uiItems, + items: uiItems.items.map((uiItem) => + enhanceItemForListItem(uiItem, selectedItem, setSelectedItem), + ), + }); + } + + if (globalItems.items.length) { + returnValue.push({ + ...globalItems, + items: globalItems.items.map((globalItem) => + enhanceItemForListItem(globalItem, selectedItem, setSelectedItem), + ), + }); + } + + return returnValue; + }, [globalItems, jsItems, queries, selectedItem, setSelectedItem, uiItems]); + + const dataTree = useSelector(getDataTree); + const configTree = useSelector(getConfigTree); + const jsActions = useSelector(getJSCollections); + let filteredData: unknown = ""; + + if (selectedItem && selectedItem.title in dataTree) { + filteredData = filterInternalProperties( + selectedItem.title, + dataTree[selectedItem.title], + jsActions, + dataTree, + configTree, + ); + } + + useEffect( + function handleNoItemSelected() { + if (!selectedItem || !(selectedItem.title in dataTree)) { + const firstItem = groups[0].items[0]; + + setSelectedItem({ + key: firstItem.id as string, + icon: firstItem.startIcon, + title: firstItem.title, + }); + } + }, + [dataTree, groups, selectedItem, setSelectedItem], + ); + + return [selectedItem, groups, filteredData]; +}; diff --git a/app/client/src/components/editorComponents/Debugger/StateInspector/hooks/useStateInspectorState.ts b/app/client/src/components/editorComponents/Debugger/StateInspector/hooks/useStateInspectorState.ts new file mode 100644 index 000000000000..c39d6dd74122 --- /dev/null +++ b/app/client/src/components/editorComponents/Debugger/StateInspector/hooks/useStateInspectorState.ts @@ -0,0 +1,19 @@ +import { useDispatch, useSelector } from "react-redux"; +import type { GenericEntityItem } from "ee/entities/IDE/constants"; +import { setDebuggerStateInspectorSelectedItem } from "actions/debuggerActions"; +import { getDebuggerStateInspectorSelectedItem } from "selectors/debuggerSelectors"; + +export const useStateInspectorState: () => [ + GenericEntityItem | undefined, + (item: GenericEntityItem) => void, +] = () => { + const dispatch = useDispatch(); + + const setSelectedItem = (item: GenericEntityItem) => { + dispatch(setDebuggerStateInspectorSelectedItem(item)); + }; + + const selectedItem = useSelector(getDebuggerStateInspectorSelectedItem); + + return [selectedItem, setSelectedItem]; +}; diff --git a/app/client/src/components/editorComponents/Debugger/StateInspector/index.ts b/app/client/src/components/editorComponents/Debugger/StateInspector/index.ts new file mode 100644 index 000000000000..e912e429d8aa --- /dev/null +++ b/app/client/src/components/editorComponents/Debugger/StateInspector/index.ts @@ -0,0 +1 @@ +export { StateInspector } from "./StateInspector"; diff --git a/app/client/src/components/editorComponents/Debugger/StateInspector/styles.ts b/app/client/src/components/editorComponents/Debugger/StateInspector/styles.ts new file mode 100644 index 000000000000..d7f9c0fdb135 --- /dev/null +++ b/app/client/src/components/editorComponents/Debugger/StateInspector/styles.ts @@ -0,0 +1,23 @@ +import styled, { css } from "styled-components"; +import { Flex, Text } from "@appsmith/ads"; + +const imgSizer = css` + img { + height: 16px; + width: 16px; + } +`; + +export const Group = styled(Flex)` + .query-item { + ${imgSizer} + } +`; + +export const GroupName = styled(Text)` + padding: var(--ads-v2-spaces-1) var(--ads-v2-spaces-3); +`; + +export const SelectedItem = styled(Flex)` + ${imgSizer} +`; diff --git a/app/client/src/components/editorComponents/Debugger/StateInspector/types.ts b/app/client/src/components/editorComponents/Debugger/StateInspector/types.ts new file mode 100644 index 000000000000..fe8e908dbb29 --- /dev/null +++ b/app/client/src/components/editorComponents/Debugger/StateInspector/types.ts @@ -0,0 +1,15 @@ +import type { ListItemProps } from "@appsmith/ads"; + +export interface GroupedItems { + group: string; + items: ListItemProps[]; +} + +export interface ListItemWithoutOnClick extends Omit { + id: string; +} + +export type GetGroupHookType = () => { + group: string; + items: ListItemWithoutOnClick[]; +}; diff --git a/app/client/src/components/editorComponents/Debugger/StateInspector/utils.ts b/app/client/src/components/editorComponents/Debugger/StateInspector/utils.ts new file mode 100644 index 000000000000..3812b5d0557d --- /dev/null +++ b/app/client/src/components/editorComponents/Debugger/StateInspector/utils.ts @@ -0,0 +1,21 @@ +import type { ListItemWithoutOnClick } from "./types"; +import type { ListItemProps } from "@appsmith/ads"; +import type { GenericEntityItem } from "ee/entities/IDE/constants"; + +export const enhanceItemForListItem = ( + item: ListItemWithoutOnClick, + selectedItem: GenericEntityItem | undefined, + setSelectedItem: (item: GenericEntityItem) => void, +): ListItemProps => { + return { + ...item, + isSelected: selectedItem ? selectedItem.key === item.id : false, + onClick: () => + setSelectedItem({ + key: item.id, + title: item.title, + icon: item.startIcon, + }), + size: "md", + }; +}; diff --git a/app/client/src/components/editorComponents/Debugger/constants.ts b/app/client/src/components/editorComponents/Debugger/constants.ts index 86dda1d56040..44f4cf57febc 100644 --- a/app/client/src/components/editorComponents/Debugger/constants.ts +++ b/app/client/src/components/editorComponents/Debugger/constants.ts @@ -5,4 +5,5 @@ export enum DEBUGGER_TAB_KEYS { HEADER_TAB = "HEADERS_TAB", ERROR_TAB = "ERROR_TAB", LOGS_TAB = "LOGS_TAB", + STATE_TAB = "STATE_TAB", } diff --git a/app/client/src/components/editorComponents/JSResponseView.tsx b/app/client/src/components/editorComponents/JSResponseView.tsx index 8266e70b6202..185d45408f9b 100644 --- a/app/client/src/components/editorComponents/JSResponseView.tsx +++ b/app/client/src/components/editorComponents/JSResponseView.tsx @@ -1,15 +1,12 @@ import React, { useCallback, useEffect, useMemo, useState } from "react"; -import { connect, useDispatch, useSelector } from "react-redux"; -import type { RouteComponentProps } from "react-router"; -import { withRouter } from "react-router"; +import { useDispatch, useSelector } from "react-redux"; import styled from "styled-components"; -import type { AppState } from "ee/reducers"; -import type { JSEditorRouteParams } from "constants/routes"; import { createMessage, DEBUGGER_ERRORS, DEBUGGER_LOGS, DEBUGGER_RESPONSE, + DEBUGGER_STATE, EXECUTING_FUNCTION, NO_JS_FUNCTION_RETURN_VALUE, UPDATING_JS_COLLECTION, @@ -35,11 +32,15 @@ import { import { getJsPaneDebuggerState } from "selectors/jsPaneSelectors"; import { setJsPaneDebuggerState } from "actions/jsPaneActions"; import { getIDEViewMode } from "selectors/ideSelectors"; -import { EditorViewMode } from "ee/entities/IDE/constants"; +import { EditorViewMode, IDE_TYPE } from "ee/entities/IDE/constants"; import ErrorLogs from "./Debugger/Errors"; import { isBrowserExecutionAllowed } from "ee/utils/actionExecutionUtils"; import JSRemoteExecutionView from "ee/components/JSRemoteExecutionView"; import { IDEBottomView, ViewHideBehaviour } from "IDE"; +import { StateInspector } from "./Debugger/StateInspector"; +import { getErrorCount } from "selectors/debuggerSelectors"; +import { getIDETypeByUrl } from "ee/entities/IDE/utils"; +import { useLocation } from "react-router"; const ResponseTabWrapper = styled.div` display: flex; @@ -61,43 +62,54 @@ const NoReturnValueWrapper = styled.div` padding-top: ${(props) => props.theme.spaces[6]}px; `; -interface ReduxStateProps { - errorCount: number; +interface Props { + currentFunction: JSAction | null; + theme?: EditorTheme; + errors: Array; + disabled: boolean; + isLoading: boolean; + onButtonClick: (e: React.MouseEvent) => void; + jsCollectionData: JSCollectionData | undefined; + debuggerLogsDefaultName?: string; } -type Props = ReduxStateProps & - RouteComponentProps & { - currentFunction: JSAction | null; - theme?: EditorTheme; - errors: Array; - disabled: boolean; - isLoading: boolean; - onButtonClick: (e: React.MouseEvent) => void; - jsCollectionData: JSCollectionData | undefined; - debuggerLogsDefaultName?: string; - }; - function JSResponseView(props: Props) { const { currentFunction, disabled, - errorCount, errors, isLoading, jsCollectionData, onButtonClick, + theme, } = props; const [responseStatus, setResponseStatus] = useState( JSResponseState.NoResponse, ); - const responses = (jsCollectionData && jsCollectionData.data) || {}; - const isDirty = (jsCollectionData && jsCollectionData.isDirty) || {}; - const isExecuting = (jsCollectionData && jsCollectionData.isExecuting) || {}; + const errorCount = useSelector(getErrorCount); + + const { isDirty, isExecuting, responses } = useMemo(() => { + return { + responses: (jsCollectionData && jsCollectionData.data) || {}, + isDirty: (jsCollectionData && jsCollectionData.isDirty) || {}, + isExecuting: (jsCollectionData && jsCollectionData.isExecuting) || {}, + }; + }, [jsCollectionData]); + const dispatch = useDispatch(); - const response = - currentFunction && currentFunction.id && currentFunction.id in responses - ? responses[currentFunction.id] - : ""; + + const response = useMemo(() => { + if ( + !currentFunction || + !currentFunction.id || + !(currentFunction.id in responses) + ) { + return { value: "" }; + } + + return { value: responses[currentFunction.id] as string }; + }, [currentFunction, responses]); + // parse error found while trying to execute function const hasExecutionParseErrors = responseStatus === JSResponseState.IsDirty; // error found while trying to parse JS Object @@ -122,94 +134,119 @@ function JSResponseView(props: Props) { ); }, [jsCollectionData?.config, currentFunction]); + const JSResponseTab = useMemo(() => { + return ( + <> + {localExecutionAllowed && hasExecutionParseErrors && ( + + +
+ Function failed to execute. Check logs for more information. +
+
+
+ )} + + + <> + {localExecutionAllowed && ( + <> + {responseStatus === JSResponseState.NoResponse && ( + + )} + {responseStatus === JSResponseState.IsExecuting && ( + + {createMessage(EXECUTING_FUNCTION)} + + )} + {responseStatus === JSResponseState.NoReturnValue && ( + + + {createMessage( + NO_JS_FUNCTION_RETURN_VALUE, + currentFunction?.name, + )} + + + )} + {responseStatus === JSResponseState.ShowResponse && ( + + )} + + )} + {!localExecutionAllowed && ( + + )} + {responseStatus === JSResponseState.IsUpdating && ( + + {createMessage(UPDATING_JS_COLLECTION)} + + )} + + + + + ); + }, [ + currentFunction?.name, + disabled, + errors.length, + hasExecutionParseErrors, + isLoading, + jsCollectionData, + localExecutionAllowed, + onButtonClick, + theme, + response, + responseStatus, + ]); + const ideViewMode = useSelector(getIDEViewMode); + const location = useLocation(); - const tabs: BottomTab[] = [ - { - key: DEBUGGER_TAB_KEYS.RESPONSE_TAB, - title: createMessage(DEBUGGER_RESPONSE), - panelComponent: ( - <> - {localExecutionAllowed && hasExecutionParseErrors && ( - - -
- Function failed to execute. Check logs for more information. -
-
-
- )} - - - <> - {localExecutionAllowed && ( - <> - {responseStatus === JSResponseState.NoResponse && ( - - )} - {responseStatus === JSResponseState.IsExecuting && ( - - {createMessage(EXECUTING_FUNCTION)} - - )} - {responseStatus === JSResponseState.NoReturnValue && ( - - - {createMessage( - NO_JS_FUNCTION_RETURN_VALUE, - currentFunction?.name, - )} - - - )} - {responseStatus === JSResponseState.ShowResponse && ( - - )} - - )} - {!localExecutionAllowed && ( - - )} - {responseStatus === JSResponseState.IsUpdating && ( - - {createMessage(UPDATING_JS_COLLECTION)} - - )} - - - - - ), - }, - { - key: DEBUGGER_TAB_KEYS.LOGS_TAB, - title: createMessage(DEBUGGER_LOGS), - panelComponent: , - }, - ]; + const ideType = getIDETypeByUrl(location.pathname); - if (ideViewMode === EditorViewMode.FullScreen) { - tabs.push({ - key: DEBUGGER_TAB_KEYS.ERROR_TAB, - title: createMessage(DEBUGGER_ERRORS), - count: errorCount, - panelComponent: , - }); - } + const tabs = useMemo(() => { + const jsTabs: BottomTab[] = [ + { + key: DEBUGGER_TAB_KEYS.RESPONSE_TAB, + title: createMessage(DEBUGGER_RESPONSE), + panelComponent: JSResponseTab, + }, + { + key: DEBUGGER_TAB_KEYS.LOGS_TAB, + title: createMessage(DEBUGGER_LOGS), + panelComponent: , + }, + ]; + + if (ideViewMode === EditorViewMode.FullScreen) { + jsTabs.push({ + key: DEBUGGER_TAB_KEYS.ERROR_TAB, + title: createMessage(DEBUGGER_ERRORS), + count: errorCount, + panelComponent: , + }); + + if (ideType === IDE_TYPE.App) { + jsTabs.push({ + key: DEBUGGER_TAB_KEYS.STATE_TAB, + title: createMessage(DEBUGGER_STATE), + panelComponent: , + }); + } + } + + return jsTabs; + }, [JSResponseTab, errorCount, ideType, ideViewMode]); // get the selected tab from the store. const { open, responseTabHeight, selectedTab } = useSelector( @@ -217,18 +254,24 @@ function JSResponseView(props: Props) { ); // set the selected tab in the store. - const setSelectedResponseTab = useCallback((selectedTab: string) => { - dispatch(setJsPaneDebuggerState({ open: true, selectedTab })); - }, []); + const setSelectedResponseTab = useCallback( + (selectedTab: string) => { + dispatch(setJsPaneDebuggerState({ open: true, selectedTab })); + }, + [dispatch], + ); // set the height of the response pane on resize. - const setResponseHeight = useCallback((height: number) => { - dispatch(setJsPaneDebuggerState({ responseTabHeight: height })); - }, []); + const setResponseHeight = useCallback( + (height: number) => { + dispatch(setJsPaneDebuggerState({ responseTabHeight: height })); + }, + [dispatch], + ); // close the debugger const onToggle = useCallback( () => dispatch(setJsPaneDebuggerState({ open: !open })), - [open], + [dispatch, open], ); // Do not render if header tab is selected in the bottom bar. @@ -251,12 +294,4 @@ function JSResponseView(props: Props) { ); } -const mapStateToProps = (state: AppState) => { - const errorCount = state.ui.debugger.context.errorCount; - - return { - errorCount, - }; -}; - -export default connect(mapStateToProps)(withRouter(JSResponseView)); +export default JSResponseView; diff --git a/app/client/src/pages/Editor/Explorer/ExplorerIcons.tsx b/app/client/src/pages/Editor/Explorer/ExplorerIcons.tsx index 589a2667fcda..d4e02619c832 100644 --- a/app/client/src/pages/Editor/Explorer/ExplorerIcons.tsx +++ b/app/client/src/pages/Editor/Explorer/ExplorerIcons.tsx @@ -12,6 +12,9 @@ import { PRIMARY_KEY, FOREIGN_KEY } from "constants/DatasourceEditorConstants"; import { Icon } from "@appsmith/ads"; import { getAssetUrl } from "ee/utils/airgapHelpers"; import { importSvg } from "@appsmith/ads-old"; +import WidgetFactory from "WidgetProvider/factory"; +import WidgetTypeIcon from "pages/Editor/Explorer/Widgets/WidgetIcon"; +import type { WidgetType } from "constants/WidgetConstants"; const ApiIcon = importSvg( async () => import("assets/icons/menu/api-colored.svg"), @@ -225,6 +228,7 @@ const EntityIconWrapper = styled.div<{ justify-content: center; text-align: center; border-radius: var(--ads-v2-border-radius); + svg, img { height: 100% !important; @@ -357,3 +361,13 @@ export function DefaultModuleIcon() { ); } + +export function WidgetIconByType(widgetType: WidgetType) { + const { IconCmp } = WidgetFactory.getWidgetMethods(widgetType); + + return IconCmp ? : ; +} + +export function GlobeIcon() { + return ; +} diff --git a/app/client/src/pages/Editor/Explorer/Files/index.tsx b/app/client/src/pages/Editor/Explorer/Files/index.tsx index 171dee03305f..9f4aa303c066 100644 --- a/app/client/src/pages/Editor/Explorer/Files/index.tsx +++ b/app/client/src/pages/Editor/Explorer/Files/index.tsx @@ -125,7 +125,6 @@ function Files() { parentEntityType={parentEntityType} searchKeyword={""} step={2} - type={type} /> ); } else { diff --git a/app/client/src/pages/Editor/Explorer/JSActions/JSActionEntity.tsx b/app/client/src/pages/Editor/Explorer/JSActions/JSActionEntity.tsx index e1c1c20e2b42..117c9b71b211 100644 --- a/app/client/src/pages/Editor/Explorer/JSActions/JSActionEntity.tsx +++ b/app/client/src/pages/Editor/Explorer/JSActions/JSActionEntity.tsx @@ -7,7 +7,6 @@ import { getJsCollectionByBaseId } from "ee/selectors/entitiesSelector"; import type { AppState } from "ee/reducers"; import type { JSCollection } from "entities/JSCollection"; import { JsFileIconV2 } from "../ExplorerIcons"; -import type { PluginType } from "entities/Action"; import { jsCollectionIdURL } from "ee/RouteBuilder"; import AnalyticsUtil from "ee/utils/AnalyticsUtil"; import { useLocation } from "react-router"; @@ -26,7 +25,6 @@ interface ExplorerJSCollectionEntityProps { searchKeyword?: string; baseCollectionId: string; isActive: boolean; - type: PluginType; parentEntityId: string; parentEntityType: ActionParentEntityTypeInterface; } diff --git a/app/client/src/reducers/uiReducers/debuggerReducer.ts b/app/client/src/reducers/uiReducers/debuggerReducer.ts index 8523a5ddb239..e86f1b6d61e0 100644 --- a/app/client/src/reducers/uiReducers/debuggerReducer.ts +++ b/app/client/src/reducers/uiReducers/debuggerReducer.ts @@ -6,6 +6,7 @@ import { omit, isUndefined, isEmpty } from "lodash"; import equal from "fast-deep-equal"; import { ActionExecutionResizerHeight } from "PluginActionEditor/components/PluginActionResponse/constants"; import { klona } from "klona"; +import type { GenericEntityItem } from "ee/entities/IDE/constants"; export const DefaultDebuggerContext = { scrollPosition: 0, @@ -22,6 +23,7 @@ const initialState: DebuggerReduxState = { expandId: "", hideErrors: true, context: DefaultDebuggerContext, + stateInspector: {}, }; // check the last message from the current log and update the occurrence count @@ -185,6 +187,17 @@ const debuggerReducer = createImmerReducer(initialState, { }, }; }, + [ReduxActionTypes.SET_DEBUGGER_STATE_INSPECTOR_SELECTED_ITEM]: ( + state: DebuggerReduxState, + action: ReduxAction, + ): DebuggerReduxState => { + return { + ...state, + stateInspector: { + selectedItem: action.payload, + }, + }; + }, // Resetting debugger state after env switch [ReduxActionTypes.SWITCH_ENVIRONMENT_SUCCESS]: () => { return klona(initialState); @@ -198,6 +211,9 @@ export interface DebuggerReduxState { expandId: string; hideErrors: boolean; context: DebuggerContext; + stateInspector: { + selectedItem?: GenericEntityItem; + }; } export interface DebuggerContext { diff --git a/app/client/src/sagas/ActionExecution/PluginActionSaga.ts b/app/client/src/sagas/ActionExecution/PluginActionSaga.ts index 49affe4244a9..af55b7ae0f1f 100644 --- a/app/client/src/sagas/ActionExecution/PluginActionSaga.ts +++ b/app/client/src/sagas/ActionExecution/PluginActionSaga.ts @@ -5,7 +5,6 @@ import { put, select, take, - takeEvery, takeLatest, } from "redux-saga/effects"; import * as Sentry from "@sentry/react"; @@ -19,10 +18,7 @@ import { updateAction, updateActionData, } from "actions/pluginActionActions"; -import { - handleExecuteJSFunctionSaga, - makeUpdateJSCollection, -} from "sagas/JSPaneSagas"; +import { handleExecuteJSFunctionSaga } from "sagas/JSPaneSagas"; import type { ApplicationPayload } from "entities/Application"; import type { ReduxAction } from "ee/constants/ReduxActionConstants"; @@ -1665,6 +1661,5 @@ export function* watchPluginActionExecutionSagas() { executePageLoadActionsSaga, ), takeLatest(ReduxActionTypes.PLUGIN_SOFT_REFRESH, softRefreshActionsSaga), - takeEvery(ReduxActionTypes.EXECUTE_JS_UPDATES, makeUpdateJSCollection), ]); } diff --git a/app/client/src/sagas/EvaluationsSaga.ts b/app/client/src/sagas/EvaluationsSaga.ts index 17f8b40246fa..8c3c497ed5ce 100644 --- a/app/client/src/sagas/EvaluationsSaga.ts +++ b/app/client/src/sagas/EvaluationsSaga.ts @@ -95,10 +95,10 @@ import type { ActionDescription } from "ee/workers/Evaluation/fns"; import { handleEvalWorkerRequestSaga } from "./EvalWorkerActionSagas"; import { getAppsmithConfigs } from "ee/configs"; import { - executeJSUpdates, type actionDataPayload, type updateActionDataPayloadType, } from "actions/pluginActionActions"; +import { executeJSUpdates } from "actions/jsPaneActions"; import { setEvaluatedActionSelectorField } from "actions/actionSelectorActions"; import { waitForWidgetConfigBuild } from "./InitSagas"; import { logDynamicTriggerExecution } from "ee/sagas/analyticsSaga"; @@ -545,6 +545,7 @@ interface BUFFERED_ACTION { hasBufferedAction: boolean; actionDataPayloadConsolidated: actionDataPayload[]; } + export function evalQueueBuffer() { let canTake = false; let hasDebouncedHandleUpdate = false; diff --git a/app/client/src/sagas/JSPaneSagas.ts b/app/client/src/sagas/JSPaneSagas.ts index 6f4f1f7a2290..f9f96f59c059 100644 --- a/app/client/src/sagas/JSPaneSagas.ts +++ b/app/client/src/sagas/JSPaneSagas.ts @@ -928,5 +928,6 @@ export default function* root() { ReduxActionTypes.CREATE_NEW_JS_FROM_ACTION_CREATOR, handleCreateNewJSFromActionCreator, ), + takeEvery(ReduxActionTypes.EXECUTE_JS_UPDATES, makeUpdateJSCollection), ]); } diff --git a/app/client/src/selectors/debuggerSelectors.tsx b/app/client/src/selectors/debuggerSelectors.tsx index 89c2c46df479..a827b65b3a0e 100644 --- a/app/client/src/selectors/debuggerSelectors.tsx +++ b/app/client/src/selectors/debuggerSelectors.tsx @@ -184,3 +184,6 @@ export const getCanvasDebuggerState = createSelector( }; }, ); + +export const getDebuggerStateInspectorSelectedItem = (state: AppState) => + state.ui.debugger.stateInspector.selectedItem; From 9ce2598e76b5d360dfcb8b1d33c7ad3f661a7a8f Mon Sep 17 00:00:00 2001 From: Rudraprasad Das Date: Sun, 5 Jan 2025 15:51:23 +0530 Subject: [PATCH 19/40] chore: git mod - integration with applications (#38439) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description - Git mod integration with applications behind feature flag Fixes #37815 Fixes #37816 Fixes #37817 Fixes #37818 Fixes #37819 Fixes #37820 ## Automation /ok-to-test tags="@tag.All" ### :mag: Cypress test results > [!TIP] > 🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉 > Workflow run: > Commit: 7d2f1a7013bc2fc6c960699ee0b6e06800cd21f9 > Cypress dashboard. > Tags: `@tag.All` > Spec: >
Wed, 01 Jan 2025 14:35:46 UTC ## Communication Should the DevRel and Marketing teams inform users about this change? - [ ] Yes - [ ] No --- .../ads/src/Icon/Icon.provider.tsx | 5 + .../request/apiRequestInterceptor.ts | 1 + app/client/src/ce/entities/FeatureFlag.ts | 2 + .../FocusStrategy/AppIDEFocusStrategy.ts | 27 +- .../Applications/CreateNewAppsOption.test.tsx | 4 + .../src/ce/pages/Applications/index.tsx | 12 +- .../pages/Editor/IDE/MainPane/useRoutes.tsx | 4 +- app/client/src/ce/reducers/index.tsx | 7 + .../uiReducers/applicationsReducer.tsx | 16 ++ app/client/src/ce/sagas/PageSagas.tsx | 14 +- app/client/src/ce/sagas/index.tsx | 2 + .../src/ce/selectors/entitiesSelector.ts | 79 +++--- app/client/src/components/BottomBar/index.tsx | 24 +- .../appsmith/header/DeployLinkButton.tsx | 61 +++-- .../editorComponents/ApiResponseView.test.tsx | 4 + .../editorComponents/GlobalSearch/HelpBar.tsx | 40 ++- .../GitApplicationContextProvider.tsx | 36 +++ .../src/entities/Engine/AppEditorEngine.ts | 86 ++++--- app/client/src/entities/Engine/index.ts | 9 +- .../application/applicationArtifact.ts | 11 + .../applicationStatusTransformer.ts} | 143 ++++++++++- .../git/artifact-helpers/application/index.ts | 2 + .../src/git/ce/components/GitModals/index.tsx | 2 + .../src/git/ce/hooks/useDefaultBranch.ts | 14 +- .../ConflictErrorModalView.tsx | 16 +- .../components/ConflictErrorModal/index.tsx | 4 +- .../ConnectInitialize/AddDeployKey.test.tsx | 231 ------------------ .../ConnectInitialize/AddDeployKey.tsx | 100 ++++---- .../ChooseGitProvider.test.tsx | 13 +- .../ConnectInitialize/ChooseGitProvider.tsx | 32 +-- .../ConnectInitialize/GenerateSSH.test.tsx | 6 +- .../ConnectInitialize/GenerateSSH.tsx | 10 +- .../ConnectInitialize/index.test.tsx | 32 +-- .../ConnectModal/ConnectInitialize/index.tsx | 126 ++++------ .../ConnectModal/ConnectModalView.tsx | 82 ++----- .../src/git/components/ConnectModal/index.tsx | 93 +++---- .../ConnectSuccessModalView.tsx} | 105 ++++---- .../components/ConnectSuccessModal/index.tsx | 29 +++ .../DeployMenuItems/DeployMenuItemsView.tsx | 32 +++ .../git/components/DeployMenuItems/index.tsx | 11 + .../components/GitContextProvider/index.tsx | 23 +- .../GlobalProfile/GlobalProfileView.tsx | 148 +++++++++++ .../git/components/GlobalProfile/index.tsx | 23 ++ .../src/git/components/ImportModal/index.tsx | 49 +++- .../OpsModal/TabDeploy/DeployPreview.tsx | 47 ++-- .../OpsModal/TabDeploy/TabDeployView.tsx | 10 +- .../src/git/components/OpsModal/index.tsx | 11 +- .../ProtectedBranchCalloutView.tsx | 85 +++++++ .../ProtectedBranchCallout/index.tsx | 33 +++ .../QuickActions/QuickActionsView.test.tsx | 30 +-- .../QuickActions/QuickActionsView.tsx | 6 +- .../src/git/components/QuickActions/index.tsx | 10 +- .../git/components/SettingsModal/index.tsx | 3 +- .../StatusChanges/StatusChangesView.tsx | 16 +- .../components/StatusChanges/StatusLoader.tsx | 10 +- .../components/StatusChanges/StatusTree.tsx | 29 ++- .../src/git/components/StatusChanges/types.ts | 5 + app/client/src/git/components/index.tsx | 3 - .../src/git/hooks/useArtifactSelector.ts | 29 +++ app/client/src/git/hooks/useAutocommit.ts | 50 ++-- app/client/src/git/hooks/useBranches.ts | 124 +++++----- app/client/src/git/hooks/useCommit.ts | 39 +-- app/client/src/git/hooks/useConnect.ts | 93 ++----- app/client/src/git/hooks/useConnected.ts | 8 + app/client/src/git/hooks/useCurrentBranch.ts | 8 + app/client/src/git/hooks/useDiscard.ts | 18 +- app/client/src/git/hooks/useDisconnect.ts | 38 +-- app/client/src/git/hooks/useGitPermissions.ts | 17 +- app/client/src/git/hooks/useGlobalProfile.ts | 8 +- app/client/src/git/hooks/useGlobalSSHKey.ts | 29 +++ app/client/src/git/hooks/useImport.ts | 38 +++ app/client/src/git/hooks/useLocalProfile.ts | 32 +-- app/client/src/git/hooks/useMerge.ts | 46 ++-- app/client/src/git/hooks/useMetadata.ts | 20 +- app/client/src/git/hooks/useOps.ts | 36 ++- .../src/git/hooks/useProtectedBranches.ts | 50 ++-- app/client/src/git/hooks/useProtectedMode.ts | 8 + app/client/src/git/hooks/usePull.ts | 24 +- app/client/src/git/hooks/useSSHKey.ts | 63 +++++ app/client/src/git/hooks/useSettings.ts | 24 +- app/client/src/git/hooks/useStatus.ts | 34 +-- app/client/src/git/index.ts | 39 +++ .../src/git/requests/connectRequest.types.ts | 17 +- .../git/requests/disconnectRequest.types.ts | 5 +- .../git/requests/fetchGlobalSSHKeyRequest.ts | 15 ++ .../fetchGlobalSSHKeyRequest.types.ts | 15 ++ .../git/requests/fetchStatusRequest.types.ts | 1 + .../src/git/requests/generateSSHKeyRequest.ts | 8 +- .../requests/generateSSHKeyRequest.types.ts | 1 - .../git/requests/gitImportRequest.types.ts | 18 +- .../src/git/sagas/checkoutBranchSaga.ts | 13 +- app/client/src/git/sagas/commitSaga.ts | 16 +- app/client/src/git/sagas/connectSaga.ts | 48 ++-- app/client/src/git/sagas/createBranchSaga.ts | 16 +- app/client/src/git/sagas/deleteBranchSaga.ts | 21 +- app/client/src/git/sagas/disconnectSaga.ts | 24 +- app/client/src/git/sagas/fetchBranchesSaga.ts | 9 +- .../src/git/sagas/fetchGlobalProfileSaga.ts | 6 +- .../src/git/sagas/fetchGlobalSSHKeySaga.ts | 44 ++++ .../src/git/sagas/fetchLocalProfileSaga.ts | 9 +- .../src/git/sagas/fetchMergeStatusSaga.ts | 10 +- app/client/src/git/sagas/fetchMetadataSaga.ts | 9 +- .../git/sagas/fetchProtectedBranchesSaga.ts | 12 +- app/client/src/git/sagas/fetchSSHKeySaga.ts | 9 +- app/client/src/git/sagas/fetchStatusSaga.ts | 9 +- .../src/git/sagas/generateSSHKeySaga.ts | 18 +- app/client/src/git/sagas/gitImportSaga.ts | 92 +++++++ app/client/src/git/sagas/index.ts | 12 +- app/client/src/git/sagas/initGitSaga.ts | 27 +- app/client/src/git/sagas/pullSaga.ts | 11 +- .../src/git/sagas/toggleAutocommitSaga.ts | 11 +- .../src/git/sagas/triggerAutocommitSaga.ts | 50 ++-- .../src/git/sagas/updateGlobalProfileSaga.ts | 8 +- .../src/git/sagas/updateLocalProfileSaga.ts | 15 +- .../git/sagas/updateProtectedBranchesSaga.ts | 13 +- .../store/actions/checkoutBranchActions.ts | 25 +- .../src/git/store/actions/commitActions.ts | 19 +- .../src/git/store/actions/connectActions.ts | 35 +-- .../git/store/actions/createBranchActions.ts | 12 +- .../git/store/actions/deleteBranchActions.ts | 12 +- .../src/git/store/actions/discardActions.ts | 10 +- .../git/store/actions/disconnectActions.ts | 8 +- .../actions/fetchAutocommitProgressActions.ts | 8 +- .../git/store/actions/fetchBranchesActions.ts | 12 +- .../actions/fetchGlobalProfileActions.ts | 8 +- .../store/actions/fetchGlobalSSHKeyActions.ts | 55 +++++ .../store/actions/fetchLocalProfileActions.ts | 18 +- .../store/actions/fetchMergeStatusActions.ts | 10 +- .../git/store/actions/fetchMetadataActions.ts | 8 +- .../actions/fetchProtectedBranchesActions.ts | 8 +- .../git/store/actions/fetchSSHKeyActions.ts | 10 +- .../git/store/actions/fetchStatusActions.ts | 12 +- .../store/actions/generateSSHKeyActions.ts | 10 +- .../src/git/store/actions/gitImportActions.ts | 42 ++-- .../src/git/store/actions/initGitActions.ts | 12 +- .../src/git/store/actions/mergeActions.ts | 8 +- .../src/git/store/actions/mountActions.ts | 19 +- .../src/git/store/actions/pullActions.ts | 18 +- .../actions/repoLimitErrorModalActions.ts | 14 +- .../store/actions/toggleAutocommitActions.ts | 26 +- .../store/actions/triggerAutocommitActions.ts | 20 +- app/client/src/git/store/actions/uiActions.ts | 93 ++++--- .../actions/updateGlobalProfileActions.ts | 10 +- .../actions/updateLocalProfileActions.ts | 16 +- .../actions/updateProtectedBranchesActions.ts | 8 +- app/client/src/git/store/gitArtifactSlice.ts | 14 +- app/client/src/git/store/gitConfigSlice.ts | 29 --- app/client/src/git/store/gitGlobalSlice.ts | 49 ++++ .../git/store/helpers/createArtifactAction.ts | 35 +++ .../helpers/createSingleArtifactAction.ts | 35 --- .../store/helpers/gitConfigInitialState.ts | 13 - .../helpers/gitSingleArtifactInitialState.ts | 138 ----------- .../src/git/store/helpers/initialState.ts | 157 ++++++++++++ app/client/src/git/store/index.ts | 4 +- ...ctSelectors.ts => gitArtifactSelectors.ts} | 35 ++- .../git/store/selectors/gitConfigSelectors.ts | 12 - .../git/store/selectors/gitGlobalSelectors.ts | 21 ++ app/client/src/git/store/types.ts | 50 ++-- .../anvil/common/hooks/detachedWidgetHooks.ts | 4 +- .../common/hooks/useWidgetBorderStyles.ts | 4 +- .../anvil/editor/AnvilEditorWidgetOnion.tsx | 4 +- .../anvil/editor/hooks/useAnvilWidgetHover.ts | 4 +- .../sagas/LayoutElementPositionsSaga.ts | 4 +- .../components/zone/useZoneMinWidth.ts | 8 +- .../SectionSpaceDistributor.tsx | 4 +- .../anvil/viewer/AnvilViewerWidgetOnion.tsx | 4 +- .../autolayout/common/FlexComponent.tsx | 8 +- .../common/dropTarget/DropTargetComponent.tsx | 8 +- .../common/resizer/ModalResizableLayer.tsx | 8 +- .../common/resizer/ResizableComponent.tsx | 8 +- .../usePositionObserver.ts | 6 +- .../layoutSystems/common/widgetName/index.tsx | 4 +- .../common/autoHeightOverlay/index.tsx | 4 +- .../CanvasSelectionArena.tsx | 4 +- .../pages/AppViewer/Navigation/Sidebar.tsx | 8 +- .../pages/AppViewer/Navigation/TopInline.tsx | 8 +- .../src/pages/AppViewer/PrimaryCTA.test.tsx | 5 + app/client/src/pages/AppViewer/PrimaryCTA.tsx | 4 +- .../AppSettings/ImportAppSettings.tsx | 4 +- app/client/src/pages/Editor/Canvas.tsx | 4 +- .../Editor/GlobalHotKeys/GlobalHotKeys.tsx | 22 +- .../pages/Editor/IDE/Header/DeployButton.tsx | 131 ++++++++++ .../src/pages/Editor/IDE/Header/index.tsx | 108 +------- .../Editor/IDE/Layout/AnimatedLayout.tsx | 25 +- .../pages/Editor/IDE/Layout/StaticLayout.tsx | 25 +- .../hooks/useEditorStateLeftPaneWidth.ts | 4 +- .../IDE/Layout/hooks/useGridLayoutTemplate.ts | 4 +- .../Editor/IDE/ProtectedCallout.test.tsx | 33 +-- .../src/pages/Editor/IDE/hooks.test.tsx | 10 + app/client/src/pages/Editor/IDE/hooks.ts | 5 +- .../LayoutSystemBasedPageViewer.tsx | 4 +- .../NavigationAdjustedPageViewer.tsx | 4 +- .../components/NavigationPreview.tsx | 4 +- .../components/WidgetEditorContentWrapper.tsx | 8 +- .../components/WidgetEditorNavigation.tsx | 6 +- .../Editor/commons/EditorWrapperContainer.tsx | 8 +- .../gitSync/components/DeployPreview.tsx | 1 - .../pages/Editor/gitSync/hooks/modHooks.ts | 44 ++++ app/client/src/pages/Editor/index.tsx | 67 +++-- app/client/src/pages/UserProfile/index.tsx | 30 ++- app/client/src/pages/common/ImportModal.tsx | 27 +- .../sagas/ActionExecution/StoreActionSaga.ts | 6 +- app/client/src/sagas/DatasourcesSagas.ts | 1 + app/client/src/sagas/FocusRetentionSaga.ts | 6 +- app/client/src/sagas/GlobalSearchSagas.ts | 8 +- .../src/sagas/autoHeightSagas/helpers.ts | 4 +- .../src/selectors/debuggerSelectors.tsx | 4 +- app/client/src/selectors/editorSelectors.tsx | 6 - app/client/src/selectors/gitModSelectors.ts | 50 ++++ .../src/selectors/widgetDragSelectors.ts | 8 +- app/client/src/selectors/widgetSelectors.ts | 4 +- .../utils/hooks/useAllowEditorDragToSelect.ts | 8 +- .../src/utils/hooks/useHoverToFocusWidget.ts | 4 +- .../ChartWidget/component/index.test.tsx | 5 + .../widgets/ChartWidget/component/index.tsx | 4 +- .../widgets/CustomWidget/component/index.tsx | 4 +- .../widgets/IframeWidget/component/index.tsx | 4 +- app/client/src/widgets/withWidgetProps.tsx | 4 +- app/client/test/testUtils.tsx | 7 + 219 files changed, 3319 insertions(+), 2200 deletions(-) create mode 100644 app/client/src/components/gitContexts/GitApplicationContextProvider.tsx create mode 100644 app/client/src/git/artifact-helpers/application/applicationArtifact.ts rename app/client/src/git/{artifactHelpers/application/statusTransformer.ts => artifact-helpers/application/applicationStatusTransformer.ts} (62%) create mode 100644 app/client/src/git/artifact-helpers/application/index.ts delete mode 100644 app/client/src/git/components/ConnectModal/ConnectInitialize/AddDeployKey.test.tsx rename app/client/src/git/components/{ConnectModal/ConnectSuccess/index.tsx => ConnectSuccessModal/ConnectSuccessModalView.tsx} (64%) create mode 100644 app/client/src/git/components/ConnectSuccessModal/index.tsx create mode 100644 app/client/src/git/components/DeployMenuItems/DeployMenuItemsView.tsx create mode 100644 app/client/src/git/components/DeployMenuItems/index.tsx create mode 100644 app/client/src/git/components/GlobalProfile/GlobalProfileView.tsx create mode 100644 app/client/src/git/components/GlobalProfile/index.tsx create mode 100644 app/client/src/git/components/ProtectedBranchCallout/ProtectedBranchCalloutView.tsx create mode 100644 app/client/src/git/components/ProtectedBranchCallout/index.tsx create mode 100644 app/client/src/git/components/StatusChanges/types.ts delete mode 100644 app/client/src/git/components/index.tsx create mode 100644 app/client/src/git/hooks/useArtifactSelector.ts create mode 100644 app/client/src/git/hooks/useConnected.ts create mode 100644 app/client/src/git/hooks/useCurrentBranch.ts create mode 100644 app/client/src/git/hooks/useGlobalSSHKey.ts create mode 100644 app/client/src/git/hooks/useImport.ts create mode 100644 app/client/src/git/hooks/useProtectedMode.ts create mode 100644 app/client/src/git/hooks/useSSHKey.ts create mode 100644 app/client/src/git/index.ts create mode 100644 app/client/src/git/requests/fetchGlobalSSHKeyRequest.ts create mode 100644 app/client/src/git/requests/fetchGlobalSSHKeyRequest.types.ts create mode 100644 app/client/src/git/sagas/fetchGlobalSSHKeySaga.ts create mode 100644 app/client/src/git/sagas/gitImportSaga.ts create mode 100644 app/client/src/git/store/actions/fetchGlobalSSHKeyActions.ts delete mode 100644 app/client/src/git/store/gitConfigSlice.ts create mode 100644 app/client/src/git/store/gitGlobalSlice.ts create mode 100644 app/client/src/git/store/helpers/createArtifactAction.ts delete mode 100644 app/client/src/git/store/helpers/createSingleArtifactAction.ts delete mode 100644 app/client/src/git/store/helpers/gitConfigInitialState.ts delete mode 100644 app/client/src/git/store/helpers/gitSingleArtifactInitialState.ts create mode 100644 app/client/src/git/store/helpers/initialState.ts rename app/client/src/git/store/selectors/{gitSingleArtifactSelectors.ts => gitArtifactSelectors.ts} (92%) delete mode 100644 app/client/src/git/store/selectors/gitConfigSelectors.ts create mode 100644 app/client/src/git/store/selectors/gitGlobalSelectors.ts create mode 100644 app/client/src/pages/Editor/IDE/Header/DeployButton.tsx create mode 100644 app/client/src/pages/Editor/gitSync/hooks/modHooks.ts create mode 100644 app/client/src/selectors/gitModSelectors.ts diff --git a/app/client/packages/design-system/ads/src/Icon/Icon.provider.tsx b/app/client/packages/design-system/ads/src/Icon/Icon.provider.tsx index 47e819cb8aae..30170ae254ec 100644 --- a/app/client/packages/design-system/ads/src/Icon/Icon.provider.tsx +++ b/app/client/packages/design-system/ads/src/Icon/Icon.provider.tsx @@ -1103,6 +1103,10 @@ const ContentTypeRaw = importSvg( async () => import("../__assets__/icons/ads/content-type-raw.svg"), ); +const CloudIconV2 = importSvg( + async () => import("../__assets__/icons/ads/cloudy-line.svg"), +); + const NotionIcon = importSvg( async () => import("../__assets__/icons/ads/notion.svg"), ); @@ -1225,6 +1229,7 @@ const ICON_LOOKUP = { "close-modal": CloseLineIcon, "close-x": CloseLineIcon, "cloud-off-line": CloudOfflineIcon, + "cloud-v2": CloudIconV2, "collapse-control": CollapseIcon, "column-freeze": ColumnFreeze, "column-unfreeze": SubtractIcon, diff --git a/app/client/src/api/interceptors/request/apiRequestInterceptor.ts b/app/client/src/api/interceptors/request/apiRequestInterceptor.ts index 5371cbbcf23c..4a9d2ed633cc 100644 --- a/app/client/src/api/interceptors/request/apiRequestInterceptor.ts +++ b/app/client/src/api/interceptors/request/apiRequestInterceptor.ts @@ -30,6 +30,7 @@ const blockAirgappedRoutes = (config: InternalAxiosRequestConfig) => { const addGitBranchHeader = (config: InternalAxiosRequestConfig) => { const state = store.getState(); + // ! git mod - not sure how to replace this, we could directly read state if required const branch = getCurrentGitBranch(state) || getQueryParamsObject().branch; return _addGitBranchHeader(config, { branch }); diff --git a/app/client/src/ce/entities/FeatureFlag.ts b/app/client/src/ce/entities/FeatureFlag.ts index d3048a86f9f1..4e3020fd98e2 100644 --- a/app/client/src/ce/entities/FeatureFlag.ts +++ b/app/client/src/ce/entities/FeatureFlag.ts @@ -48,6 +48,7 @@ export const FEATURE_FLAG = { "release_table_html_column_type_enabled", release_gs_all_sheets_options_enabled: "release_gs_all_sheets_options_enabled", + release_git_modularisation_enabled: "release_git_modularisation_enabled", ab_premium_datasources_view_enabled: "ab_premium_datasources_view_enabled", kill_session_recordings_enabled: "kill_session_recordings_enabled", config_mask_session_recordings_enabled: @@ -95,6 +96,7 @@ export const DEFAULT_FEATURE_FLAG_VALUE: FeatureFlags = { release_evaluation_scope_cache: false, release_table_html_column_type_enabled: false, release_gs_all_sheets_options_enabled: false, + release_git_modularisation_enabled: false, ab_premium_datasources_view_enabled: false, kill_session_recordings_enabled: false, config_user_session_recordings_enabled: true, diff --git a/app/client/src/ce/navigation/FocusStrategy/AppIDEFocusStrategy.ts b/app/client/src/ce/navigation/FocusStrategy/AppIDEFocusStrategy.ts index 5729a7e8c59d..fe5440f22f27 100644 --- a/app/client/src/ce/navigation/FocusStrategy/AppIDEFocusStrategy.ts +++ b/app/client/src/ce/navigation/FocusStrategy/AppIDEFocusStrategy.ts @@ -2,7 +2,6 @@ import { all, select, take } from "redux-saga/effects"; import type { FocusPath, FocusStrategy } from "sagas/FocusRetentionSaga"; import type { AppsmithLocationState } from "utils/history"; import { NavigationMethod } from "utils/history"; -import { getCurrentGitBranch } from "selectors/gitSyncSelectors"; import type { FocusEntityInfo } from "navigation/FocusEntity"; import { FocusEntity, @@ -18,6 +17,7 @@ import { widgetListURL, } from "ee/RouteBuilder"; import AppIDEFocusElements from "../FocusElements/AppIDE"; +import { selectGitApplicationCurrentBranch } from "selectors/gitModSelectors"; function shouldSetState( prevPath: string, @@ -86,8 +86,17 @@ const isPageChange = (prevPath: string, currentPath: string) => { ); }; -export const createEditorFocusInfoKey = (basePageId: string, branch?: string) => - `EDITOR_STATE.${basePageId}#${branch}`; +export const createEditorFocusInfoKey = ( + basePageId: string, + branch: string | null = null, +) => { + const r = branch + ? `EDITOR_STATE.${basePageId}#${branch}` + : `EDITOR_STATE.${basePageId}`; + + return r; +}; + export const createEditorFocusInfo = (basePageId: string, branch?: string) => ({ key: createEditorFocusInfoKey(basePageId, branch), entityInfo: { @@ -109,7 +118,9 @@ export const AppIDEFocusStrategy: FocusStrategy = { return []; } - const branch: string | undefined = yield select(getCurrentGitBranch); + const branch: string | undefined = yield select( + selectGitApplicationCurrentBranch, + ); const entities: Array<{ entityInfo: FocusEntityInfo; key: string }> = []; const prevEntityInfo = identifyEntityFromPath(previousPath); const currentEntityInfo = identifyEntityFromPath(currentPath); @@ -136,7 +147,9 @@ export const AppIDEFocusStrategy: FocusStrategy = { return entities; }, *getEntitiesForStore(path: string, currentPath: string) { - const branch: string | undefined = yield select(getCurrentGitBranch); + const branch: string | undefined = yield select( + selectGitApplicationCurrentBranch, + ); const entities: Array = []; const currentFocusEntityInfo = identifyEntityFromPath(currentPath); const prevFocusEntityInfo = identifyEntityFromPath(path); @@ -179,7 +192,9 @@ export const AppIDEFocusStrategy: FocusStrategy = { appState: EditorState.EDITOR, params: prevFocusEntityInfo.params, }, - key: `EDITOR_STATE.${prevFocusEntityInfo.params.basePageId}#${branch}`, + key: branch + ? `EDITOR_STATE.${prevFocusEntityInfo.params.basePageId}#${branch}` + : `EDITOR_STATE.${prevFocusEntityInfo.params.basePageId}`, }); } diff --git a/app/client/src/ce/pages/Applications/CreateNewAppsOption.test.tsx b/app/client/src/ce/pages/Applications/CreateNewAppsOption.test.tsx index 180268afb6a9..06940dc36fcc 100644 --- a/app/client/src/ce/pages/Applications/CreateNewAppsOption.test.tsx +++ b/app/client/src/ce/pages/Applications/CreateNewAppsOption.test.tsx @@ -9,6 +9,10 @@ import CreateNewAppsOption from "./CreateNewAppsOption"; import { BrowserRouter as Router } from "react-router-dom"; import { unitTestBaseMockStore } from "layoutSystems/common/dropTarget/unitTestUtils"; +jest.mock("selectors/gitModSelectors", () => ({ + selectCombinedPreviewMode: jest.fn(() => false), +})); + const defaultStoreState = { ...unitTestBaseMockStore, tenant: { diff --git a/app/client/src/ce/pages/Applications/index.tsx b/app/client/src/ce/pages/Applications/index.tsx index edd2b60af280..19b45abd74e1 100644 --- a/app/client/src/ce/pages/Applications/index.tsx +++ b/app/client/src/ce/pages/Applications/index.tsx @@ -122,7 +122,6 @@ import { MOBILE_MAX_WIDTH } from "constants/AppConstants"; import { Indices } from "constants/Layers"; import ImportModal from "pages/common/ImportModal"; import SharedUserList from "pages/common/SharedUserList"; -import GitSyncModal from "pages/Editor/gitSync/GitSyncModal"; import ReconnectDatasourceModal from "pages/Editor/gitSync/ReconnectDatasourceModal"; import RepoLimitExceededErrorModal from "pages/Editor/gitSync/RepoLimitExceededErrorModal"; import AnalyticsUtil from "ee/utils/AnalyticsUtil"; @@ -133,6 +132,15 @@ import { getAssetUrl } from "ee/utils/airgapHelpers"; import { ASSETS_CDN_URL } from "constants/ThirdPartyConstants"; import { LayoutSystemTypes } from "layoutSystems/types"; import { getIsAnvilLayoutEnabled } from "layoutSystems/anvil/integrations/selectors"; +import OldGitSyncModal from "pages/Editor/gitSync/GitSyncModal"; +import { useGitModEnabled } from "pages/Editor/gitSync/hooks/modHooks"; +import { GitImportModal as NewGitImportModal } from "git"; + +function GitImportModal() { + const isGitModEnabled = useGitModEnabled(); + + return isGitModEnabled ? : ; +} export const { cloudHosting } = getAppsmithConfigs(); @@ -955,7 +963,7 @@ export function ApplicationsSection(props: any) { isMobile={isMobile} > {workspacesListComponent} - + ); diff --git a/app/client/src/ce/pages/Editor/IDE/MainPane/useRoutes.tsx b/app/client/src/ce/pages/Editor/IDE/MainPane/useRoutes.tsx index cac3ae6f84a8..8f16afc63327 100644 --- a/app/client/src/ce/pages/Editor/IDE/MainPane/useRoutes.tsx +++ b/app/client/src/ce/pages/Editor/IDE/MainPane/useRoutes.tsx @@ -34,12 +34,12 @@ import DataSourceEditor from "pages/Editor/DataSourceEditor"; import DatasourceBlankState from "pages/Editor/DataSourceEditor/DatasourceBlankState"; import type { RouteProps } from "react-router"; import { useSelector } from "react-redux"; -import { combinedPreviewModeSelector } from "selectors/editorSelectors"; import { lazy, Suspense } from "react"; import React from "react"; import { retryPromise } from "utils/AppsmithUtils"; import Skeleton from "widgets/Skeleton"; +import { selectCombinedPreviewMode } from "selectors/gitModSelectors"; const FirstTimeUserOnboardingChecklist = lazy(async () => retryPromise( @@ -67,7 +67,7 @@ export interface RouteReturnType extends RouteProps { */ function useRoutes(path: string): RouteReturnType[] { - const isPreviewMode = useSelector(combinedPreviewModeSelector); + const isPreviewMode = useSelector(selectCombinedPreviewMode); return [ { diff --git a/app/client/src/ce/reducers/index.tsx b/app/client/src/ce/reducers/index.tsx index f6bb8801940e..73842c65b5df 100644 --- a/app/client/src/ce/reducers/index.tsx +++ b/app/client/src/ce/reducers/index.tsx @@ -77,6 +77,8 @@ import type { ActiveField } from "reducers/uiReducers/activeFieldEditorReducer"; import type { SelectedWorkspaceReduxState } from "ee/reducers/uiReducers/selectedWorkspaceReducer"; import type { ConsolidatedPageLoadState } from "reducers/uiReducers/consolidatedPageLoadReducer"; import type { BuildingBlocksReduxState } from "reducers/uiReducers/buildingBlockReducer"; +import type { GitArtifactRootReduxState, GitGlobalReduxState } from "git"; +import { gitReducer } from "git/store"; export const reducerObject = { entities: entityReducer, @@ -86,6 +88,7 @@ export const reducerObject = { settings: SettingsReducer, tenant: tenantReducer, linting: lintErrorReducer, + git: gitReducer, }; export interface AppState { @@ -176,4 +179,8 @@ export interface AppState { // TODO: Fix this the next time the file is edited // eslint-disable-next-line @typescript-eslint/no-explicit-any tenant: TenantReduxState; + git: { + global: GitGlobalReduxState; + artifacts: GitArtifactRootReduxState; + }; } diff --git a/app/client/src/ce/reducers/uiReducers/applicationsReducer.tsx b/app/client/src/ce/reducers/uiReducers/applicationsReducer.tsx index dd2f5b5c4060..97830da22ff3 100644 --- a/app/client/src/ce/reducers/uiReducers/applicationsReducer.tsx +++ b/app/client/src/ce/reducers/uiReducers/applicationsReducer.tsx @@ -25,6 +25,8 @@ import { import produce from "immer"; import { isEmpty } from "lodash"; import type { ApplicationPayload } from "entities/Application"; +import { gitConnectSuccess, type GitConnectSuccessPayload } from "git"; +import type { PayloadAction } from "@reduxjs/toolkit"; export const initialState: ApplicationsReduxState = { isSavingAppName: false, @@ -744,6 +746,20 @@ export const handlers = { isSavingNavigationSetting: false, }; }, + // git + [gitConnectSuccess.type]: ( + state: ApplicationsReduxState, + action: PayloadAction, + ) => { + return { + ...state, + currentApplication: { + ...state.currentApplication, + gitApplicationMetadata: + action.payload.responseData.gitApplicationMetadata, + }, + }; + }, }; const applicationsReducer = createReducer(initialState, handlers); diff --git a/app/client/src/ce/sagas/PageSagas.tsx b/app/client/src/ce/sagas/PageSagas.tsx index d1c8e1e86837..aad81e9f8720 100644 --- a/app/client/src/ce/sagas/PageSagas.tsx +++ b/app/client/src/ce/sagas/PageSagas.tsx @@ -75,7 +75,6 @@ import { import { IncorrectBindingError, validateResponse } from "sagas/ErrorSagas"; import type { ApiResponse } from "api/ApiResponses"; import { - combinedPreviewModeSelector, getCurrentApplicationId, getCurrentLayoutId, getCurrentPageId, @@ -128,7 +127,6 @@ import { getPageList } from "ee/selectors/entitiesSelector"; import { setPreviewModeAction } from "actions/editorActions"; import { SelectionRequestType } from "sagas/WidgetSelectUtils"; import { toast } from "@appsmith/ads"; -import { getCurrentGitBranch } from "selectors/gitSyncSelectors"; import type { MainCanvasReduxState } from "reducers/uiReducers/mainCanvasReducer"; import { UserCancelledActionExecutionError } from "sagas/ActionExecution/errorUtils"; import { getInstanceId } from "ee/selectors/tenantSelectors"; @@ -150,6 +148,10 @@ import { getIsAnvilLayout } from "layoutSystems/anvil/integrations/selectors"; import { convertToBasePageIdSelector } from "selectors/pageListSelectors"; import type { Page } from "entities/Page"; import { ConsolidatedPageLoadApi } from "api"; +import { + selectCombinedPreviewMode, + selectGitApplicationCurrentBranch, +} from "selectors/gitModSelectors"; export const checkIfMigrationIsNeeded = ( fetchPageResponse?: FetchPageResponse, @@ -172,7 +174,9 @@ export function* refreshTheApp() { const currentPageId: string = yield select(getCurrentPageId); const defaultBasePageId: string = yield select(getDefaultBasePageId); const pagesList: Page[] = yield select(getPageList); - const gitBranch: string = yield select(getCurrentGitBranch); + const gitBranch: string | undefined = yield select( + selectGitApplicationCurrentBranch, + ); const isCurrentPageIdInList = pagesList.filter((page) => page.pageId === currentPageId).length > 0; @@ -637,7 +641,7 @@ export function* saveLayoutSaga(action: ReduxAction<{ isRetry?: boolean }>) { try { const currentPageId: string = yield select(getCurrentPageId); const currentPage: Page = yield select(getPageById(currentPageId)); - const isPreviewMode: boolean = yield select(combinedPreviewModeSelector); + const isPreviewMode: boolean = yield select(selectCombinedPreviewMode); const appMode: APP_MODE | undefined = yield select(getAppMode); @@ -1401,7 +1405,7 @@ export function* setCanvasCardsStateSaga(action: ReduxAction) { } export function* setPreviewModeInitSaga(action: ReduxAction) { - const isPreviewMode: boolean = yield select(combinedPreviewModeSelector); + const isPreviewMode: boolean = yield select(selectCombinedPreviewMode); if (action.payload) { // we animate out elements and then move to the canvas diff --git a/app/client/src/ce/sagas/index.tsx b/app/client/src/ce/sagas/index.tsx index 844f9406af82..af60e7dc4b93 100644 --- a/app/client/src/ce/sagas/index.tsx +++ b/app/client/src/ce/sagas/index.tsx @@ -52,6 +52,7 @@ import sendSideBySideWidgetHoverAnalyticsEventSaga from "sagas/AnalyticsSaga"; /* Sagas that are registered by a module that is designed to be independent of the core platform */ import ternSagas from "sagas/TernSaga"; +import gitSagas from "git/sagas"; export const sagas = [ initSagas, @@ -106,4 +107,5 @@ export const sagas = [ ternSagas, ideSagas, sendSideBySideWidgetHoverAnalyticsEventSaga, + gitSagas, ]; diff --git a/app/client/src/ce/selectors/entitiesSelector.ts b/app/client/src/ce/selectors/entitiesSelector.ts index d744e14e773b..5cc97210bc54 100644 --- a/app/client/src/ce/selectors/entitiesSelector.ts +++ b/app/client/src/ce/selectors/entitiesSelector.ts @@ -54,7 +54,7 @@ import { getEntityNameAndPropertyPath } from "ee/workers/Evaluation/evaluationUt import { getFormValues } from "redux-form"; import { TEMP_DATASOURCE_ID } from "constants/Datasource"; import type { Module } from "ee/constants/ModuleConstants"; -import { getAnvilSpaceDistributionStatus } from "layoutSystems/anvil/integrations/selectors"; +// import { getAnvilSpaceDistributionStatus } from "layoutSystems/anvil/integrations/selectors"; import { getCurrentWorkflowActions, getCurrentWorkflowJSActions, @@ -167,47 +167,48 @@ export const getDatasourceStructureById = ( return state.entities.datasources.structure[id]; }; +// ! git mod - the following function is not getting used /** * Selector to indicate if the widget name should be shown/drawn on canvas */ -export const getShouldShowWidgetName = createSelector( - (state: AppState) => state.ui.widgetDragResize.isResizing, - (state: AppState) => state.ui.widgetDragResize.isDragging, - (state: AppState) => state.ui.editor.isPreviewMode, - (state: AppState) => state.ui.widgetDragResize.isAutoCanvasResizing, - getAnvilSpaceDistributionStatus, - // cannot import other selectors, breaks the app - (state) => { - const gitMetaData = - state.ui.applications.currentApplication?.gitApplicationMetadata; - const isGitConnected = !!(gitMetaData && gitMetaData?.remoteUrl); - const currentBranch = gitMetaData?.branchName; - const { protectedBranches = [] } = state.ui.gitSync; - - if (!isGitConnected || !currentBranch) { - return false; - } else { - return protectedBranches.includes(currentBranch); - } - }, - ( - isResizing, - isDragging, - isPreviewMode, - isAutoCanvasResizing, - isDistributingSpace, - isProtectedMode, - ) => { - return ( - !isResizing && - !isDragging && - !isPreviewMode && - !isAutoCanvasResizing && - !isDistributingSpace && - !isProtectedMode - ); - }, -); +// export const getShouldShowWidgetName = createSelector( +// (state: AppState) => state.ui.widgetDragResize.isResizing, +// (state: AppState) => state.ui.widgetDragResize.isDragging, +// (state: AppState) => state.ui.editor.isPreviewMode, +// (state: AppState) => state.ui.widgetDragResize.isAutoCanvasResizing, +// getAnvilSpaceDistributionStatus, +// // cannot import other selectors, breaks the app +// (state) => { +// const gitMetaData = +// state.ui.applications.currentApplication?.gitApplicationMetadata; +// const isGitConnected = !!(gitMetaData && gitMetaData?.remoteUrl); +// const currentBranch = gitMetaData?.branchName; +// const { protectedBranches = [] } = state.ui.gitSync; + +// if (!isGitConnected || !currentBranch) { +// return false; +// } else { +// return protectedBranches.includes(currentBranch); +// } +// }, +// ( +// isResizing, +// isDragging, +// isPreviewMode, +// isAutoCanvasResizing, +// isDistributingSpace, +// isProtectedMode, +// ) => { +// return ( +// !isResizing && +// !isDragging && +// !isPreviewMode && +// !isAutoCanvasResizing && +// !isDistributingSpace && +// !isProtectedMode +// ); +// }, +// ); export const getDatasourceTableColumns = (datasourceId: string, tableName: string) => (state: AppState) => { diff --git a/app/client/src/components/BottomBar/index.tsx b/app/client/src/components/BottomBar/index.tsx index 565844eacfb4..1b7ad839d868 100644 --- a/app/client/src/components/BottomBar/index.tsx +++ b/app/client/src/components/BottomBar/index.tsx @@ -1,5 +1,4 @@ -import React from "react"; -import QuickGitActions from "pages/Editor/gitSync/QuickGitActions"; +import React, { useCallback } from "react"; import { DebuggerTrigger } from "components/editorComponents/Debugger"; import HelpButton from "pages/Editor/HelpButton"; import ManualUpgrades from "./ManualUpgrades"; @@ -16,19 +15,30 @@ import { softRefreshActions } from "actions/pluginActionActions"; import { START_SWITCH_ENVIRONMENT } from "ee/constants/messages"; import { getIsAnvilEnabledInCurrentApplication } from "layoutSystems/anvil/integrations/selectors"; import PackageUpgradeStatus from "ee/components/BottomBar/PackageUpgradeStatus"; +import OldGitQuickActions from "pages/Editor/gitSync/QuickGitActions"; +import { GitQuickActions } from "git"; +import { useGitModEnabled } from "pages/Editor/gitSync/hooks/modHooks"; + +function GitActions() { + const isGitModEnabled = useGitModEnabled(); + + return isGitModEnabled ? : ; +} export default function BottomBar() { const appId = useSelector(getCurrentApplicationId) || ""; - const isPreviewMode = useSelector(previewModeSelector); - const dispatch = useDispatch(); // We check if the current application is an Anvil application. // If it is an Anvil application, we remove the Git features from the bottomBar // as they donot yet work correctly with Anvil. const isAnvilEnabled = useSelector(getIsAnvilEnabledInCurrentApplication); + const isPreviewMode = useSelector(previewModeSelector); + const isGitEnabled = !isAnvilEnabled && !isPreviewMode; + + const dispatch = useDispatch(); - const onChangeEnv = () => { + const onChangeEnv = useCallback(() => { dispatch(softRefreshActions()); - }; + }, [dispatch]); return ( @@ -41,7 +51,7 @@ export default function BottomBar() { viewMode={isPreviewMode} /> )} - {!isPreviewMode && !isAnvilEnabled && } + {isGitEnabled && } {!isPreviewMode && ( diff --git a/app/client/src/components/designSystems/appsmith/header/DeployLinkButton.tsx b/app/client/src/components/designSystems/appsmith/header/DeployLinkButton.tsx index 3257d962223b..91eea09ab4ab 100644 --- a/app/client/src/components/designSystems/appsmith/header/DeployLinkButton.tsx +++ b/app/client/src/components/designSystems/appsmith/header/DeployLinkButton.tsx @@ -1,8 +1,7 @@ import type { ReactNode } from "react"; -import React from "react"; +import React, { useCallback } from "react"; import { Menu, MenuItem, MenuContent, MenuTrigger } from "@appsmith/ads"; import { useSelector, useDispatch } from "react-redux"; -import { getIsGitConnected } from "selectors/gitSyncSelectors"; import { setIsGitSyncModalOpen } from "actions/gitSyncActions"; import { GitSyncModalTab } from "entities/GitSync"; import AnalyticsUtil from "ee/utils/AnalyticsUtil"; @@ -14,32 +13,54 @@ import { Button } from "@appsmith/ads"; import { KBEditorMenuItem } from "ee/pages/Editor/KnowledgeBase/KBEditorMenuItem"; import { useHasConnectToGitPermission } from "pages/Editor/gitSync/hooks/gitPermissionHooks"; import { getIsAnvilEnabledInCurrentApplication } from "layoutSystems/anvil/integrations/selectors"; +import { + useGitConnected, + useGitModEnabled, +} from "pages/Editor/gitSync/hooks/modHooks"; +import { GitDeployMenuItems as GitDeployMenuItemsNew } from "git"; -interface Props { - trigger: ReactNode; - link: string; -} +function GitDeployMenuItems() { + const isGitModEnabled = useGitModEnabled(); -export const DeployLinkButton = (props: Props) => { const dispatch = useDispatch(); - const isGitConnected = useSelector(getIsGitConnected); - const isConnectToGitPermitted = useHasConnectToGitPermission(); - // We check if the current application is an Anvil application. - // If it is an Anvil application, we remove the Git features from the deploy button - // as they donot yet work correctly with Anvil. - const isAnvilEnabled = useSelector(getIsAnvilEnabledInCurrentApplication); - - const goToGitConnectionPopup = () => { + const goToGitConnectionPopup = useCallback(() => { AnalyticsUtil.logEvent("GS_CONNECT_GIT_CLICK", { source: "Deploy button", }); + dispatch( setIsGitSyncModalOpen({ isOpen: true, tab: GitSyncModalTab.GIT_CONNECTION, }), ); - }; + }, [dispatch]); + + return isGitModEnabled ? ( + + ) : ( + + {CONNECT_TO_GIT_OPTION()} + + ); +} + +interface Props { + trigger: ReactNode; + link: string; +} + +export const DeployLinkButton = (props: Props) => { + const isGitConnected = useGitConnected(); + const isConnectToGitPermitted = useHasConnectToGitPermission(); + // We check if the current application is an Anvil application. + // If it is an Anvil application, we remove the Git features from the deploy button + // as they donot yet work correctly with Anvil. + const isAnvilEnabled = useSelector(getIsAnvilEnabledInCurrentApplication); return ( @@ -54,13 +75,7 @@ export const DeployLinkButton = (props: Props) => { {!isGitConnected && isConnectToGitPermitted && !isAnvilEnabled && ( - - {CONNECT_TO_GIT_OPTION()} - + )} ({ default: () =>
, })); +jest.mock("selectors/gitModSelectors", () => ({ + selectCombinedPreviewMode: jest.fn(() => false), +})); + const mockStore = configureStore([]); const storeState = { diff --git a/app/client/src/components/editorComponents/GlobalSearch/HelpBar.tsx b/app/client/src/components/editorComponents/GlobalSearch/HelpBar.tsx index c52eb62c9ef2..0a8fb41ffabe 100644 --- a/app/client/src/components/editorComponents/GlobalSearch/HelpBar.tsx +++ b/app/client/src/components/editorComponents/GlobalSearch/HelpBar.tsx @@ -1,14 +1,13 @@ -import React from "react"; +import React, { useCallback } from "react"; import styled from "styled-components"; -import { connect } from "react-redux"; +import { useDispatch } from "react-redux"; import { getTypographyByKey, Text, TextType } from "@appsmith/ads-old"; import { Icon } from "@appsmith/ads"; import { setGlobalSearchCategory } from "actions/globalSearchActions"; import AnalyticsUtil from "ee/utils/AnalyticsUtil"; import { modText } from "utils/helpers"; import { filterCategories, SEARCH_CATEGORY_ID } from "./utils"; -import { protectedModeSelector } from "selectors/gitSyncSelectors"; -import type { AppState } from "ee/reducers"; +import { useGitProtectedMode } from "pages/Editor/gitSync/hooks/modHooks"; const StyledHelpBar = styled.button` padding: 0 var(--ads-v2-spaces-3); @@ -42,12 +41,18 @@ const StyledHelpBar = styled.button` } `; -interface Props { - toggleShowModal: () => void; - isProtectedMode: boolean; -} +function HelpBar() { + const isProtectedMode = useGitProtectedMode(); + + const dispatch = useDispatch(); + + const toggleShowModal = useCallback(() => { + AnalyticsUtil.logEvent("OPEN_OMNIBAR", { source: "NAVBAR_CLICK" }); + dispatch( + setGlobalSearchCategory(filterCategories[SEARCH_CATEGORY_ID.INIT]), + ); + }, [dispatch]); -function HelpBar({ isProtectedMode, toggleShowModal }: Props) { return ( ({ - isProtectedMode: protectedModeSelector(state), -}); - -// TODO: Fix this the next time the file is edited -// eslint-disable-next-line @typescript-eslint/no-explicit-any -const mapDispatchToProps = (dispatch: any) => ({ - toggleShowModal: () => { - AnalyticsUtil.logEvent("OPEN_OMNIBAR", { source: "NAVBAR_CLICK" }); - dispatch( - setGlobalSearchCategory(filterCategories[SEARCH_CATEGORY_ID.INIT]), - ); - }, -}); - -export default connect(mapStateToProps, mapDispatchToProps)(HelpBar); +export default HelpBar; diff --git a/app/client/src/components/gitContexts/GitApplicationContextProvider.tsx b/app/client/src/components/gitContexts/GitApplicationContextProvider.tsx new file mode 100644 index 000000000000..728636e2f6dd --- /dev/null +++ b/app/client/src/components/gitContexts/GitApplicationContextProvider.tsx @@ -0,0 +1,36 @@ +import React from "react"; +import { useSelector } from "react-redux"; +import { GitArtifactType, GitContextProvider } from "git"; +import { getCurrentApplication } from "ee/selectors/applicationSelectors"; +import { hasCreateNewAppPermission } from "ee/utils/permissionHelpers"; +import { setWorkspaceIdForImport } from "ee/actions/applicationActions"; +import { getCurrentAppWorkspace } from "ee/selectors/selectedWorkspaceSelectors"; +import { applicationStatusTransformer } from "git/artifact-helpers/application"; + +interface GitApplicationContextProviderProps { + children: React.ReactNode; +} + +export default function GitApplicationContextProvider({ + children, +}: GitApplicationContextProviderProps) { + const artifactType = GitArtifactType.Application; + const application = useSelector(getCurrentApplication); + const workspace = useSelector(getCurrentAppWorkspace); + const isCreateNewApplicationPermitted = hasCreateNewAppPermission( + workspace.userPermissions, + ); + + return ( + + {children} + + ); +} diff --git a/app/client/src/entities/Engine/AppEditorEngine.ts b/app/client/src/entities/Engine/AppEditorEngine.ts index f5b0f04b228b..a0bfb5372c20 100644 --- a/app/client/src/entities/Engine/AppEditorEngine.ts +++ b/app/client/src/entities/Engine/AppEditorEngine.ts @@ -1,14 +1,4 @@ import { fetchMockDatasources } from "actions/datasourceActions"; -import { - fetchGitProtectedBranchesInit, - fetchGitStatusInit, - remoteUrlInputValue, - resetPullMergeStatus, - fetchBranchesInit, - triggerAutocommitInitAction, - getGitMetadataInitAction, -} from "actions/gitSyncActions"; -import { restoreRecentEntitiesRequest } from "actions/globalSearchActions"; import { resetEditorSuccess } from "actions/initActions"; import { fetchAllPageEntityCompletion, @@ -24,7 +14,6 @@ import { ReduxActionErrorTypes, ReduxActionTypes, } from "ee/constants/ReduxActionConstants"; -import { addBranchParam } from "constants/routes"; import type { APP_MODE } from "entities/App"; import { call, fork, put, select, spawn } from "redux-saga/effects"; import type { EditConsolidatedApi } from "sagas/InitSagas"; @@ -33,12 +22,9 @@ import { reportSWStatus, waitForWidgetConfigBuild, } from "sagas/InitSagas"; -import { - getCurrentGitBranch, - isGitPersistBranchEnabledSelector, -} from "selectors/gitSyncSelectors"; +import { isGitPersistBranchEnabledSelector } from "selectors/gitSyncSelectors"; import AnalyticsUtil from "ee/utils/AnalyticsUtil"; -import history from "utils/history"; +// import history from "utils/history"; import type { AppEnginePayload } from "."; import AppEngine, { ActionsNotFoundError, @@ -71,6 +57,24 @@ import { endSpan, startNestedSpan } from "instrumentation/generateTraces"; import { getCurrentUser } from "selectors/usersSelectors"; import type { User } from "constants/userConstants"; import log from "loglevel"; +import { gitArtifactActions } from "git/store/gitArtifactSlice"; +import { restoreRecentEntitiesRequest } from "actions/globalSearchActions"; +import { + fetchBranchesInit, + fetchGitProtectedBranchesInit, + fetchGitStatusInit, + getGitMetadataInitAction, + remoteUrlInputValue, + resetPullMergeStatus, + triggerAutocommitInitAction, +} from "actions/gitSyncActions"; +import history from "utils/history"; +import { addBranchParam } from "constants/routes"; +import { + selectGitApplicationCurrentBranch, + selectGitModEnabled, +} from "selectors/gitModSelectors"; +import { applicationArtifact } from "git/artifact-helpers/application"; export default class AppEditorEngine extends AppEngine { constructor(mode: APP_MODE) { @@ -281,6 +285,9 @@ export default class AppEditorEngine extends AppEngine { const currentApplication: ApplicationPayload = yield select( getCurrentApplication, ); + const currentBranch: string | undefined = yield select( + selectGitApplicationCurrentBranch, + ); const isGitPersistBranchEnabled: boolean = yield select( isGitPersistBranchEnabledSelector, @@ -288,7 +295,6 @@ export default class AppEditorEngine extends AppEngine { if (isGitPersistBranchEnabled) { const currentUser: User = yield select(getCurrentUser); - const currentBranch: string = yield select(getCurrentGitBranch); if (currentUser?.email && currentApplication?.baseId && currentBranch) { yield setLatestGitBranchInLocal( @@ -317,6 +323,15 @@ export default class AppEditorEngine extends AppEngine { }); } + if (currentApplication?.id) { + yield put( + restoreRecentEntitiesRequest({ + applicationId: currentApplication.id, + branch: currentBranch, + }), + ); + } + if (isFirstTimeUserOnboardingComplete) { yield put({ type: ReduxActionTypes.SET_FIRST_TIME_USER_ONBOARDING_APPLICATION_IDS, @@ -359,22 +374,32 @@ export default class AppEditorEngine extends AppEngine { public *loadGit(applicationId: string, rootSpan: Span) { const loadGitSpan = startNestedSpan("AppEditorEngine.loadGit", rootSpan); + const isGitModEnabled: boolean = yield select(selectGitModEnabled); - const branchInStore: string = yield select(getCurrentGitBranch); + if (isGitModEnabled) { + const currentApplication: ApplicationPayload = yield select( + getCurrentApplication, + ); - yield put( - restoreRecentEntitiesRequest({ - applicationId, - branch: branchInStore, - }), - ); - // init of temporary remote url from old application - yield put(remoteUrlInputValue({ tempRemoteUrl: "" })); - // add branch query to path and fetch status + yield put( + gitArtifactActions.initGitForEditor({ + artifactDef: applicationArtifact(currentApplication.baseId), + artifact: currentApplication, + }), + ); + } else { + const currentBranch: string = yield select( + selectGitApplicationCurrentBranch, + ); + + // init of temporary remote url from old application + yield put(remoteUrlInputValue({ tempRemoteUrl: "" })); + // add branch query to path and fetch status - if (branchInStore) { - history.replace(addBranchParam(branchInStore)); - yield fork(this.loadGitInBackground); + if (currentBranch) { + history.replace(addBranchParam(currentBranch)); + yield fork(this.loadGitInBackground); + } } endSpan(loadGitSpan); @@ -383,7 +408,6 @@ export default class AppEditorEngine extends AppEngine { private *loadGitInBackground() { yield put(fetchBranchesInit()); yield put(fetchGitProtectedBranchesInit()); - yield put(fetchGitProtectedBranchesInit()); yield put(getGitMetadataInitAction()); yield put(triggerAutocommitInitAction()); yield put(fetchGitStatusInit({ compareRemote: true })); diff --git a/app/client/src/entities/Engine/index.ts b/app/client/src/entities/Engine/index.ts index aadfd66a4316..b4eb39475753 100644 --- a/app/client/src/entities/Engine/index.ts +++ b/app/client/src/entities/Engine/index.ts @@ -17,10 +17,10 @@ import history from "utils/history"; import type URLRedirect from "entities/URLRedirect/index"; import URLGeneratorFactory from "entities/URLRedirect/factory"; import { updateBranchLocally } from "actions/gitSyncActions"; -import { getCurrentGitBranch } from "selectors/gitSyncSelectors"; import { restoreIDEEditorViewMode } from "actions/ideActions"; import type { Span } from "instrumentation/types"; import { endSpan, startNestedSpan } from "instrumentation/generateTraces"; +import { selectGitApplicationCurrentBranch } from "selectors/gitModSelectors"; export interface AppEnginePayload { applicationId?: string; @@ -114,12 +114,13 @@ export default abstract class AppEngine { } const application: ApplicationPayload = yield select(getCurrentApplication); - const currentGitBranch: ReturnType = - yield select(getCurrentGitBranch); + const currentBranch: string | undefined = yield select( + selectGitApplicationCurrentBranch, + ); yield put( updateAppStore( - getPersistentAppStore(application.id, branch || currentGitBranch), + getPersistentAppStore(application.id, branch || currentBranch), ), ); const defaultPageId: string = yield select(getDefaultPageId); diff --git a/app/client/src/git/artifact-helpers/application/applicationArtifact.ts b/app/client/src/git/artifact-helpers/application/applicationArtifact.ts new file mode 100644 index 000000000000..7337db575ac6 --- /dev/null +++ b/app/client/src/git/artifact-helpers/application/applicationArtifact.ts @@ -0,0 +1,11 @@ +import { GitArtifactType } from "git/constants/enums"; +import type { GitArtifactDef } from "git/store/types"; + +export default function applicationArtifact( + baseApplicationId: string, +): GitArtifactDef { + return { + artifactType: GitArtifactType.Application, + baseArtifactId: baseApplicationId, + }; +} diff --git a/app/client/src/git/artifactHelpers/application/statusTransformer.ts b/app/client/src/git/artifact-helpers/application/applicationStatusTransformer.ts similarity index 62% rename from app/client/src/git/artifactHelpers/application/statusTransformer.ts rename to app/client/src/git/artifact-helpers/application/applicationStatusTransformer.ts index 9ac95d9c424e..b803cddfea66 100644 --- a/app/client/src/git/artifactHelpers/application/statusTransformer.ts +++ b/app/client/src/git/artifact-helpers/application/applicationStatusTransformer.ts @@ -1,6 +1,11 @@ import type { FetchStatusResponseData } from "git/requests/fetchStatusRequest.types"; import { objectKeys } from "@appsmith/utils"; -import type { StatusTreeStruct } from "git/components/StatusChanges/StatusTree"; +import { + createMessage, + NOT_PUSHED_YET, + TRY_TO_PULL, +} from "ee/constants/messages"; +import type { StatusTreeStruct } from "git/components/StatusChanges/types"; const ICON_LOOKUP = { query: "query", @@ -8,19 +13,29 @@ const ICON_LOOKUP = { page: "page-line", datasource: "database-2-line", jsLib: "package", + settings: "settings-v3", + theme: "sip-line", + remote: "git-commit", + package: "package", + module: "package", + moduleInstance: "package", }; interface TreeNodeDef { subject: string; verb: string; type: keyof typeof ICON_LOOKUP; + extra?: string; } function createTreeNode(nodeDef: TreeNodeDef) { - return { - icon: ICON_LOOKUP[nodeDef.type], - message: `${nodeDef.subject} ${nodeDef.verb}`, - }; + let message = `${nodeDef.subject} ${nodeDef.verb}`; + + if (nodeDef.extra) { + message += ` ${nodeDef.extra}`; + } + + return { icon: ICON_LOOKUP[nodeDef.type], message }; } function determineVerbForDefs(defs: TreeNodeDef[]) { @@ -45,7 +60,11 @@ function createTreeNodeGroup(nodeDefs: TreeNodeDef[], subject: string) { return { icon: ICON_LOOKUP[nodeDefs[0].type], message: `${nodeDefs.length} ${subject} ${determineVerbForDefs(nodeDefs)}`, - children: nodeDefs.map(createTreeNode), + children: nodeDefs + .sort((a, b) => + a.subject.localeCompare(b.subject, undefined, { sensitivity: "base" }), + ) + .map(createTreeNode), }; } @@ -125,6 +144,10 @@ function statusPageTransformer(status: FetchStatusResponseData) { tree.push({ ...createTreeNode(pageDef), children }); }); + tree.sort((a, b) => + a.message.localeCompare(b.message, undefined, { sensitivity: "base" }), + ); + objectKeys(pageDefLookup).forEach((page) => { if (!pageEntityDefLookup[page]) { tree.push(createTreeNode(pageDefLookup[page])); @@ -186,13 +209,121 @@ function statusJsLibTransformer(status: FetchStatusResponseData) { return tree; } +function statusRemoteCountTransformer(status: FetchStatusResponseData) { + const { aheadCount, behindCount } = status; + const tree = [] as StatusTreeStruct[]; + + if (behindCount > 0) { + tree.push( + createTreeNode({ + subject: `${behindCount} commit${behindCount > 1 ? "s" : ""}`, + verb: "behind", + type: "remote", + extra: createMessage(TRY_TO_PULL), + }), + ); + } + + if (aheadCount > 0) { + tree.push( + createTreeNode({ + subject: `${aheadCount} commit${aheadCount > 1 ? "s" : ""}`, + verb: "ahead", + type: "remote", + extra: createMessage(NOT_PUSHED_YET), + }), + ); + } + + return tree; +} + +function statusSettingsTransformer(status: FetchStatusResponseData) { + const { modified } = status; + const tree = [] as StatusTreeStruct[]; + + if (modified.includes("application.json")) { + tree.push( + createTreeNode({ + subject: "Application settings", + verb: "modified", + type: "settings", + }), + ); + } + + return tree; +} + +function statusThemeTransformer(status: FetchStatusResponseData) { + const { modified } = status; + const tree = [] as StatusTreeStruct[]; + + if (modified.includes("theme.json")) { + tree.push( + createTreeNode({ + subject: "Theme", + verb: "modified", + type: "theme", + }), + ); + } + + return tree; +} + +function statusPackagesTransformer(status: FetchStatusResponseData) { + const { + modifiedModuleInstances = 0, + modifiedModules = 0, + modifiedPackages = 0, + } = status; + const tree = [] as StatusTreeStruct[]; + + if (modifiedPackages > 0) { + tree.push( + createTreeNode({ + subject: `${modifiedPackages} package${modifiedPackages > 1 ? "s" : ""}`, + verb: "modified", + type: "package", + }), + ); + } + + if (modifiedModules > 0) { + tree.push( + createTreeNode({ + subject: `${modifiedModules} module${modifiedModules > 1 ? "s" : ""}`, + verb: "modified", + type: "module", + }), + ); + } + + if (modifiedModuleInstances > 0) { + tree.push( + createTreeNode({ + subject: `${modifiedModuleInstances} module instance${modifiedModuleInstances > 1 ? "s" : ""}`, + verb: "modified", + type: "moduleInstance", + }), + ); + } + + return tree; +} + export default function applicationStatusTransformer( status: FetchStatusResponseData, ) { const tree = [ + ...statusRemoteCountTransformer(status), ...statusPageTransformer(status), ...statusDatasourceTransformer(status), ...statusJsLibTransformer(status), + ...statusSettingsTransformer(status), + ...statusThemeTransformer(status), + ...statusPackagesTransformer(status), ] as StatusTreeStruct[]; return tree; diff --git a/app/client/src/git/artifact-helpers/application/index.ts b/app/client/src/git/artifact-helpers/application/index.ts new file mode 100644 index 000000000000..579a99c7d975 --- /dev/null +++ b/app/client/src/git/artifact-helpers/application/index.ts @@ -0,0 +1,2 @@ +export { default as applicationArtifact } from "./applicationArtifact"; +export { default as applicationStatusTransformer } from "./applicationStatusTransformer"; diff --git a/app/client/src/git/ce/components/GitModals/index.tsx b/app/client/src/git/ce/components/GitModals/index.tsx index a5fcb8c7be36..8bd094fa1ffe 100644 --- a/app/client/src/git/ce/components/GitModals/index.tsx +++ b/app/client/src/git/ce/components/GitModals/index.tsx @@ -1,5 +1,6 @@ import ConflictErrorModal from "git/components/ConflictErrorModal"; import ConnectModal from "git/components/ConnectModal"; +import ConnectSuccessModal from "git/components/ConnectSuccessModal"; import DisableAutocommitModal from "git/components/DisableAutocommitModal"; import DisconnectModal from "git/components/DisconnectModal"; import OpsModal from "git/components/OpsModal"; @@ -10,6 +11,7 @@ function GitModals() { return ( <> + diff --git a/app/client/src/git/ce/hooks/useDefaultBranch.ts b/app/client/src/git/ce/hooks/useDefaultBranch.ts index 6bc27c1c08c0..53a0f4a1fb01 100644 --- a/app/client/src/git/ce/hooks/useDefaultBranch.ts +++ b/app/client/src/git/ce/hooks/useDefaultBranch.ts @@ -1,17 +1,11 @@ -import { useGitContext } from "git/components/GitContextProvider"; -import { selectDefaultBranch } from "git/store/selectors/gitSingleArtifactSelectors"; -import type { GitRootState } from "git/store/types"; -import { useSelector } from "react-redux"; +import useArtifactSelector from "git/hooks/useArtifactSelector"; +import { selectDefaultBranch } from "git/store/selectors/gitArtifactSelectors"; function useDefaultBranch() { - const { artifactDef } = useGitContext(); - - const defaultBranch = useSelector((state: GitRootState) => - selectDefaultBranch(state, artifactDef), - ); + const defaultBranch = useArtifactSelector(selectDefaultBranch); return { - defaultBranch, + defaultBranch: defaultBranch ?? null, }; } diff --git a/app/client/src/git/components/ConflictErrorModal/ConflictErrorModalView.tsx b/app/client/src/git/components/ConflictErrorModal/ConflictErrorModalView.tsx index d59ff023af40..5090e39c7643 100644 --- a/app/client/src/git/components/ConflictErrorModal/ConflictErrorModalView.tsx +++ b/app/client/src/git/components/ConflictErrorModal/ConflictErrorModalView.tsx @@ -6,7 +6,7 @@ import { CONFLICTS_FOUND_WHILE_PULLING_CHANGES, } from "ee/constants/messages"; -import { Button } from "@appsmith/ads"; +import { Button, Flex } from "@appsmith/ads"; import noop from "lodash/noop"; import ConflictError from "../ConflictError"; @@ -62,18 +62,12 @@ function ConflictErrorModalView({ >
-
-
+ + {createMessage(CONFLICTS_FOUND_WHILE_PULLING_CHANGES)} -
+
+
diff --git a/app/client/src/git/components/ConflictErrorModal/index.tsx b/app/client/src/git/components/ConflictErrorModal/index.tsx index db9568836032..a67a429aff35 100644 --- a/app/client/src/git/components/ConflictErrorModal/index.tsx +++ b/app/client/src/git/components/ConflictErrorModal/index.tsx @@ -3,11 +3,11 @@ import ConflictErrorModalView from "./ConflictErrorModalView"; import useOps from "git/hooks/useOps"; export default function ConflictErrorModal() { - const { conflictErrorModalOpen, toggleConflictErrorModal } = useOps(); + const { isConflictErrorModalOpen, toggleConflictErrorModal } = useOps(); return ( ); diff --git a/app/client/src/git/components/ConnectModal/ConnectInitialize/AddDeployKey.test.tsx b/app/client/src/git/components/ConnectModal/ConnectInitialize/AddDeployKey.test.tsx deleted file mode 100644 index 176dc5247887..000000000000 --- a/app/client/src/git/components/ConnectModal/ConnectInitialize/AddDeployKey.test.tsx +++ /dev/null @@ -1,231 +0,0 @@ -import React from "react"; -import { render, screen, fireEvent, waitFor } from "@testing-library/react"; -import type { AddDeployKeyProps } from "./AddDeployKey"; -import AddDeployKey from "./AddDeployKey"; -import AnalyticsUtil from "ee/utils/AnalyticsUtil"; -import "@testing-library/jest-dom"; - -jest.mock("ee/utils/AnalyticsUtil", () => ({ - logEvent: jest.fn(), -})); - -jest.mock("copy-to-clipboard", () => ({ - __esModule: true, - default: () => true, -})); - -const DEFAULT_DOCS_URL = - "https://docs.appsmith.com/advanced-concepts/version-control-with-git/connecting-to-git-repository"; - -const defaultProps: AddDeployKeyProps = { - connectError: null, - isLoading: false, - onChange: jest.fn(), - value: { - gitProvider: "github", - isAddedDeployKey: false, - remoteUrl: "git@github.com:owner/repo.git", - }, - fetchSSHKey: jest.fn(), - generateSSHKey: jest.fn(), - isFetchSSHKeyLoading: false, - isGenerateSSHKeyLoading: false, - sshPublicKey: "ecdsa-sha2-nistp256 AAAAE2VjZHNhAAAIBaj...", -}; - -describe("AddDeployKey Component", () => { - beforeEach(() => { - jest.clearAllMocks(); - }); - - it("renders without crashing and shows default UI", () => { - render(); - expect( - screen.getByText("Add deploy key & give write access"), - ).toBeInTheDocument(); - expect(screen.getByRole("combobox")).toBeInTheDocument(); - // Should show ECDSA by default since sshKeyPair includes "ecdsa" - expect( - screen.getByText(defaultProps.sshPublicKey as string), - ).toBeInTheDocument(); - expect( - screen.getByText("I've added the deploy key and gave it write access"), - ).toBeInTheDocument(); - }); - - it("calls fetchSSHKey if modal is open and not importing", () => { - render(); - expect(defaultProps.fetchSSHKey).toHaveBeenCalledTimes(1); - }); - - it("does not call fetchSSHKey if importing", () => { - render(); - expect(defaultProps.fetchSSHKey).not.toHaveBeenCalled(); - }); - - it("shows dummy key loader if loading keys", () => { - render( - , - ); - // The actual key text should not be displayed - expect(screen.queryByText("ecdsa-sha2-nistp256")).not.toBeInTheDocument(); - }); - - it("changes SSH key type when user selects a different type and triggers generateSSHKey if needed", async () => { - const generateSSHKey = jest.fn(); - - render( - , - ); - - fireEvent.mouseDown(screen.getByRole("combobox")); - const rsaOption = screen.getByText("RSA 4096"); - - fireEvent.click(rsaOption); - - await waitFor(() => { - expect(generateSSHKey).toHaveBeenCalledWith("RSA", false); - }); - }); - - it("displays a generic error when errorData is provided and error code is not AE-GIT-4032 or AE-GIT-4033", () => { - // eslint-disable-next-line react-perf/jsx-no-new-object-as-prop - const connectError = { - code: "GENERIC-ERROR", - errorType: "Some Error", - message: "Something went wrong", - }; - - render(); - expect(screen.getByText("Some Error")).toBeInTheDocument(); - expect(screen.getByText("Something went wrong")).toBeInTheDocument(); - }); - - it("displays a misconfiguration error if error code is AE-GIT-4032", () => { - // eslint-disable-next-line react-perf/jsx-no-new-object-as-prop - const connectError = { - code: "AE-GIT-4032", - errorType: "SSH Key Error", - message: "SSH Key misconfiguration", - }; - - render(); - expect(screen.getByText("SSH key misconfiguration")).toBeInTheDocument(); - expect( - screen.getByText( - "It seems that your SSH key hasn't been added to your repository. To proceed, please revisit the steps below and configure your SSH key correctly.", - ), - ).toBeInTheDocument(); - }); - - it("invokes onChange callback when checkbox is toggled", () => { - const onChange = jest.fn(); - - render(); - const checkbox = screen.getByTestId("t--added-deploy-key-checkbox"); - - fireEvent.click(checkbox); - expect(onChange).toHaveBeenCalledWith({ isAddedDeployKey: true }); - }); - - it("calls AnalyticsUtil on copy button click", () => { - render(); - const copyButton = screen.getByTestId("t--copy-generic"); - - fireEvent.click(copyButton); - expect(AnalyticsUtil.logEvent).toHaveBeenCalledWith( - "GS_COPY_SSH_KEY_BUTTON_CLICK", - ); - }); - - it("hides copy button when connectLoading is true", () => { - render(); - expect(screen.queryByTestId("t--copy-generic")).not.toBeInTheDocument(); - }); - - it("shows repository settings link if gitProvider is known and not 'others'", () => { - render(); - const link = screen.getByRole("link", { name: "repository settings." }); - - expect(link).toHaveAttribute( - "href", - "https://github.com/owner/repo/settings/keys", - ); - }); - - it("does not show repository link if gitProvider = 'others'", () => { - render( - , - ); - expect( - screen.queryByRole("link", { name: "repository settings." }), - ).not.toBeInTheDocument(); - }); - - it("shows collapsible section if gitProvider is not 'others'", () => { - render( - , - ); - expect( - screen.getByText("How to paste SSH Key in repo and give write access?"), - ).toBeInTheDocument(); - expect(screen.getByAltText("Add deploy key in gitlab")).toBeInTheDocument(); - }); - - it("does not display collapsible if gitProvider = 'others'", () => { - render( - , - ); - expect( - screen.queryByText("How to paste SSH Key in repo and give write access?"), - ).not.toBeInTheDocument(); - }); - - it("uses default documentation link if none provided", () => { - render(); - const docsLink = screen.getByRole("link", { name: "Read Docs" }); - - expect(docsLink).toHaveAttribute("href", DEFAULT_DOCS_URL); - }); - - it("generates SSH key if none is present and conditions are met", async () => { - const fetchSSHKey = jest.fn(); - const generateSSHKey = jest.fn(); - - render( - , - ); - - expect(fetchSSHKey).toHaveBeenCalledTimes(1); - - await waitFor(() => { - expect(generateSSHKey).toHaveBeenCalledWith("ECDSA", false); - }); - }); -}); diff --git a/app/client/src/git/components/ConnectModal/ConnectInitialize/AddDeployKey.tsx b/app/client/src/git/components/ConnectModal/ConnectInitialize/AddDeployKey.tsx index 75a4a7a50e86..09dcb7df1122 100644 --- a/app/client/src/git/components/ConnectModal/ConnectInitialize/AddDeployKey.tsx +++ b/app/client/src/git/components/ConnectModal/ConnectInitialize/AddDeployKey.tsx @@ -135,93 +135,83 @@ const DEPLOY_DOCS_URL = "https://docs.appsmith.com/advanced-concepts/version-control-with-git/connecting-to-git-repository"; export interface AddDeployKeyProps { - connectError: GitApiError | null; - fetchSSHKey: () => void; - generateSSHKey: (keyType: string, isImport?: boolean) => void; - isFetchSSHKeyLoading: boolean; - isGenerateSSHKeyLoading: boolean; - isImport?: boolean; - isLoading: boolean; + error: GitApiError | null; + isSubmitLoading: boolean; + isSSHKeyLoading: boolean; onChange: (args: Partial) => void; + onFetchSSHKey?: () => void; + onGenerateSSHKey: (keyType: string) => void; sshPublicKey: string | null; value: Partial | null; } function AddDeployKey({ - connectError = null, - fetchSSHKey = noop, - generateSSHKey = noop, - isFetchSSHKeyLoading = false, - isGenerateSSHKeyLoading = false, - isImport = false, - isLoading = false, + error = null, + isSSHKeyLoading = false, + isSubmitLoading = false, onChange = noop, + onFetchSSHKey = noop, + onGenerateSSHKey = noop, sshPublicKey = null, value = null, }: AddDeployKeyProps) { const [fetched, setFetched] = useState(false); - const [sshKeyType, setSshKeyType] = useState(); + const [keyType, setKeyType] = useState(); useEffect( function fetchKeyPairOnInitEffect() { - if (!isImport) { - if (!fetched) { - fetchSSHKey(); - setFetched(true); - // doesn't support callback anymore - // fetchSSHKey({ - // onSuccessCallback: () => { - // setFetched(true); - // }, - // onErrorCallback: () => { - // setFetched(true); - // }, - // }); - } - } else { - if (!fetched) { - setFetched(true); - } + if (!fetched) { + onFetchSSHKey(); + setFetched(true); + // doesn't support callback anymore + // fetchSSHKey({ + // onSuccessCallback: () => { + // setFetched(true); + // }, + // onErrorCallback: () => { + // setFetched(true); + // }, + // }); } }, - [isImport, fetched, fetchSSHKey], + [fetched, onFetchSSHKey], ); useEffect( function setSSHKeyTypeonInitEffect() { - if (fetched && !isFetchSSHKeyLoading) { + if (fetched && !isSSHKeyLoading) { if (sshPublicKey && sshPublicKey.includes("rsa")) { - setSshKeyType("RSA"); + setKeyType("RSA"); } else if ( !sshPublicKey && value?.remoteUrl && value.remoteUrl.toString().toLocaleLowerCase().includes("azure") ) { - setSshKeyType("RSA"); + setKeyType("RSA"); } else { - setSshKeyType("ECDSA"); + setKeyType("ECDSA"); } } }, - [fetched, sshPublicKey, isFetchSSHKeyLoading, value?.remoteUrl], + [fetched, sshPublicKey, value?.remoteUrl, isSSHKeyLoading], ); useEffect( function generateSSHOnInitEffect() { if ( - (sshKeyType && !sshPublicKey) || - (sshKeyType && !sshPublicKey?.includes(sshKeyType.toLowerCase())) + (keyType && !sshPublicKey) || + (keyType && !sshPublicKey?.includes(keyType.toLowerCase())) ) { - generateSSHKey(sshKeyType, isImport); + onGenerateSSHKey(keyType); // doesn't support callback anymore - // generateSSHKey(sshKeyType, { + // generateSSHKey(keyType, { // onSuccessCallback: () => { // toast.show("SSH Key generated successfully", { kind: "success" }); // }, // }); } }, - [sshKeyType, sshPublicKey, generateSSHKey, isImport], + [keyType, sshPublicKey, onGenerateSSHKey], ); const repositorySettingsUrl = getRepositorySettingsUrl( @@ -229,7 +219,7 @@ function AddDeployKey({ value?.remoteUrl, ); - const loading = isFetchSSHKeyLoading || isGenerateSSHKeyLoading; + // const loading = isFetchSSHKeyLoading || isGenerateSSHKeyLoading; const onCopy = useCallback(() => { AnalyticsUtil.logEvent("GS_COPY_SSH_KEY_BUTTON_CLICK"); @@ -244,19 +234,19 @@ function AddDeployKey({ return ( <> - {connectError && - connectError.code !== "AE-GIT-4033" && - connectError.code !== "AE-GIT-4032" && ( + {error && + error.code !== "AE-GIT-4033" && + error.code !== "AE-GIT-4032" && ( - {connectError.errorType} + {error.errorType} - {connectError.message} + {error.message} )} {/* hardcoding message because server doesn't support feature flag. Will change this later */} - {connectError && connectError.code === "AE-GIT-4032" && ( + {error && error.code === "AE-GIT-4032" && ( {createMessage(ERROR_SSH_KEY_MISCONF_TITLE)} @@ -301,20 +291,20 @@ function AddDeployKey({ Now, give write access to it. - + - {!loading ? ( + {!isSSHKeyLoading ? ( - {sshKeyType} + {keyType} {sshPublicKey} - {!isLoading && ( + {!isSubmitLoading && ( { @@ -169,19 +168,19 @@ describe("ChooseGitProvider Component", () => { }); it("clicking on 'Import via git' link calls onImportFromCalloutLinkClick", () => { - const mockSetImportWorkspaceId = jest.fn(); + const onOpenImport = jest.fn(); render( , ); fireEvent.click(screen.getByText("Import via git")); - expect(mockSetImportWorkspaceId).toHaveBeenCalledTimes(1); + expect(onOpenImport).toHaveBeenCalledTimes(1); }); it("when isImport = true, shows a checkbox for existing repo", () => { @@ -214,11 +213,11 @@ describe("ChooseGitProvider Component", () => { }); it("respects canCreateNewArtifact and device conditions for links", () => { - // If canCreateNewArtifact is false, "Import via git" should not appear even if conditions are met + // If onOpenImport is null, "Import via git" should not appear even if conditions are met render( , ); diff --git a/app/client/src/git/components/ConnectModal/ConnectInitialize/ChooseGitProvider.tsx b/app/client/src/git/components/ConnectModal/ConnectInitialize/ChooseGitProvider.tsx index d24c31de20de..b8aceed5baf4 100644 --- a/app/client/src/git/components/ConnectModal/ConnectInitialize/ChooseGitProvider.tsx +++ b/app/client/src/git/components/ConnectModal/ConnectInitialize/ChooseGitProvider.tsx @@ -34,9 +34,7 @@ import { } from "ee/constants/messages"; import log from "loglevel"; import type { ConnectFormDataState } from "./types"; -import history from "utils/history"; import { useIsMobileDevice } from "utils/hooks/useDeviceDetect"; -import AnalyticsUtil from "ee/utils/AnalyticsUtil"; const WellInnerContainer = styled.div` padding-left: 16px; @@ -53,21 +51,17 @@ export type GitProvider = (typeof GIT_PROVIDERS)[number]; interface ChooseGitProviderProps { artifactType: string; - isCreateArtifactPermitted: boolean; isImport?: boolean; onChange: (args: Partial) => void; - setImportWorkspaceId: () => void; - toggleConnectModal: (open: boolean) => void; + onOpenImport: (() => void) | null; value: Partial; } function ChooseGitProvider({ artifactType, - isCreateArtifactPermitted, isImport = false, onChange = noop, - setImportWorkspaceId = noop, - toggleConnectModal = noop, + onOpenImport = null, value = {}, }: ChooseGitProviderProps) { const isMobile = useIsMobileDevice(); @@ -97,19 +91,19 @@ function ChooseGitProvider({ [onChange], ); - const handleClickOnImport = useCallback(() => { - toggleConnectModal(false); - history.push("/applications"); - setImportWorkspaceId(); - toggleConnectModal(true); - AnalyticsUtil.logEvent("GS_IMPORT_VIA_GIT_DURING_GC"); - }, [setImportWorkspaceId, toggleConnectModal]); + // const handleClickOnImport = useCallback(() => { + // toggleConnectModal(false); + // history.push("/applications"); + // setImportWorkspaceId(); + // toggleConnectModal(true); + // AnalyticsUtil.logEvent("GS_IMPORT_VIA_GIT_DURING_GC"); + // }, [setImportWorkspaceId, toggleConnectModal]); const importCalloutLinks = useMemo(() => { - return !isMobile && isCreateArtifactPermitted - ? [{ children: "Import via git", onClick: handleClickOnImport }] + return !isMobile && onOpenImport && typeof onOpenImport === "function" + ? [{ children: "Import via git", onClick: onOpenImport }] : []; - }, [handleClickOnImport, isCreateArtifactPermitted, isMobile]); + }, [onOpenImport, isMobile]); return ( <> @@ -208,7 +202,7 @@ function ChooseGitProvider({ )} - {!isImport && value?.gitEmptyRepoExists === "no" ? ( + {!isImport && onOpenImport && value?.gitEmptyRepoExists === "no" ? ( {createMessage(IMPORT_ARTIFACT_IF_NOT_EMPTY, artifactType)} diff --git a/app/client/src/git/components/ConnectModal/ConnectInitialize/GenerateSSH.test.tsx b/app/client/src/git/components/ConnectModal/ConnectInitialize/GenerateSSH.test.tsx index d082ee44546d..fc53b8531a4f 100644 --- a/app/client/src/git/components/ConnectModal/ConnectInitialize/GenerateSSH.test.tsx +++ b/app/client/src/git/components/ConnectModal/ConnectInitialize/GenerateSSH.test.tsx @@ -16,7 +16,7 @@ const defaultProps = { gitProvider: "github" as GitProvider, remoteUrl: "", }, - connectError: null, + error: null, }; describe("GenerateSSH Component", () => { @@ -38,7 +38,7 @@ describe("GenerateSSH Component", () => { code: "AE-GIT-4033", }; - render(); + render(); expect( screen.getByText("The repo you added isn't empty"), ).toBeInTheDocument(); @@ -55,7 +55,7 @@ describe("GenerateSSH Component", () => { code: "SOME_OTHER_ERROR", }; - render(); + render(); expect( screen.queryByText("The repo you added isn't empty"), ).not.toBeInTheDocument(); diff --git a/app/client/src/git/components/ConnectModal/ConnectInitialize/GenerateSSH.tsx b/app/client/src/git/components/ConnectModal/ConnectInitialize/GenerateSSH.tsx index 5318b0bd8554..6a8b7536f903 100644 --- a/app/client/src/git/components/ConnectModal/ConnectInitialize/GenerateSSH.tsx +++ b/app/client/src/git/components/ConnectModal/ConnectInitialize/GenerateSSH.tsx @@ -41,17 +41,13 @@ interface GenerateSSHState { interface GenerateSSHProps { onChange: (args: Partial) => void; value: Partial; - connectError: GitApiError | null; + error: GitApiError | null; } const CONNECTING_TO_GIT_DOCS_URL = "https://docs.appsmith.com/advanced-concepts/version-control-with-git/connecting-to-git-repository"; -function GenerateSSH({ - connectError, - onChange = noop, - value = {}, -}: GenerateSSHProps) { +function GenerateSSH({ error, onChange = noop, value = {} }: GenerateSSHProps) { const [isTouched, setIsTouched] = useState(false); const isInvalid = isTouched && @@ -69,7 +65,7 @@ function GenerateSSH({ return ( <> {/* hardcoding messages because server doesn't support feature flag. Will change this later */} - {connectError && connectError?.code === "AE-GIT-4033" && ( + {error && error?.code === "AE-GIT-4033" && ( {createMessage(ERROR_REPO_NOT_EMPTY_TITLE)} diff --git a/app/client/src/git/components/ConnectModal/ConnectInitialize/index.test.tsx b/app/client/src/git/components/ConnectModal/ConnectInitialize/index.test.tsx index 6ac8b83b0761..21f46cf03525 100644 --- a/app/client/src/git/components/ConnectModal/ConnectInitialize/index.test.tsx +++ b/app/client/src/git/components/ConnectModal/ConnectInitialize/index.test.tsx @@ -21,19 +21,15 @@ jest.mock("@appsmith/ads", () => ({ const defaultProps = { artifactType: "Application", - connect: jest.fn(), - connectError: null, - fetchSSHKey: jest.fn(), - generateSSHKey: jest.fn(), - gitImport: jest.fn(), - isConnectLoading: false, - isFetchSSHKeyLoading: false, - isGenerateSSHKeyLoading: false, - isGitImportLoading: false, + error: null, + onFetchSSHKey: jest.fn(), + onGenerateSSHKey: jest.fn(), + isSubmitLoading: false, + isSSHKeyLoading: false, isImport: false, + onSubmit: jest.fn(), + onOpenImport: null, sshPublicKey: "ssh-rsa AAAAB3...", - isCreateArtifactPermitted: true, - setImportWorkspaceId: jest.fn(), toggleConnectModal: jest.fn(), }; @@ -126,7 +122,7 @@ describe("ConnectModal Component", () => { completeAddDeployKeyStep(); await waitFor(() => { - expect(defaultProps.connect).toHaveBeenCalledWith( + expect(defaultProps.onSubmit).toHaveBeenCalledWith( expect.objectContaining({ remoteUrl: "git@example.com:user/repo.git", gitProfile: { @@ -139,14 +135,14 @@ describe("ConnectModal Component", () => { }); }); - it("calls gitImport on completing AddDeployKey step in import mode", async () => { + it("calls onSubmit on completing AddDeployKey step in import mode", async () => { render(); completeChooseProviderStep(true); completeGenerateSSHKeyStep(); completeAddDeployKeyStep(); await waitFor(() => { - expect(defaultProps.gitImport).toHaveBeenCalledWith( + expect(defaultProps.onSubmit).toHaveBeenCalledWith( expect.objectContaining({ remoteUrl: "git@example.com:user/repo.git", gitProfile: { @@ -167,13 +163,11 @@ describe("ConnectModal Component", () => { message: "", }; - rerender( - , - ); + rerender(); }); const { rerender } = render( - , + , ); completeChooseProviderStep(); @@ -216,7 +210,7 @@ describe("ConnectModal Component", () => { }); it("renders loading state and removes buttons when connecting", () => { - render(); + render(); expect( screen.getByText("Please wait while we connect to Git..."), ).toBeInTheDocument(); diff --git a/app/client/src/git/components/ConnectModal/ConnectInitialize/index.tsx b/app/client/src/git/components/ConnectModal/ConnectInitialize/index.tsx index 05046d250d09..72ba9d797c1d 100644 --- a/app/client/src/git/components/ConnectModal/ConnectInitialize/index.tsx +++ b/app/client/src/git/components/ConnectModal/ConnectInitialize/index.tsx @@ -71,41 +71,31 @@ interface StyledModalFooterProps { loading?: boolean; } -interface ConnectModalViewProps { +export interface ConnectInitializeProps { artifactType: string; - connect: (params: ConnectRequestParams) => void; - connectError: GitApiError | null; - fetchSSHKey: () => void; - generateSSHKey: (keyType: string) => void; - gitImport: (params: GitImportRequestParams) => void; - isConnectLoading: boolean; - isCreateArtifactPermitted: boolean; - isFetchSSHKeyLoading: boolean; - isGenerateSSHKeyLoading: boolean; - isGitImportLoading: boolean; + error: GitApiError | null; isImport: boolean; - setImportWorkspaceId: () => void; + isSSHKeyLoading: boolean; + isSubmitLoading: boolean; + onFetchSSHKey: () => void; + onGenerateSSHKey: (keyType: string) => void; + onOpenImport: (() => void) | null; + onSubmit: (params: ConnectRequestParams | GitImportRequestParams) => void; sshPublicKey: string | null; - toggleConnectModal: (open: boolean) => void; } function ConnectInitialize({ artifactType, - connect = noop, - connectError = null, - fetchSSHKey = noop, - generateSSHKey = noop, - gitImport = noop, - isConnectLoading = false, - isCreateArtifactPermitted = false, - isFetchSSHKeyLoading = false, - isGenerateSSHKeyLoading = false, - isGitImportLoading = false, + error = null, isImport = false, - setImportWorkspaceId = noop, + isSSHKeyLoading = false, + isSubmitLoading = false, + onFetchSSHKey = noop, + onGenerateSSHKey = noop, + onOpenImport = null, + onSubmit = noop, sshPublicKey = null, - toggleConnectModal = noop, -}: ConnectModalViewProps) { +}: ConnectInitializeProps) { const nextStepText = { [GIT_CONNECT_STEPS.CHOOSE_PROVIDER]: createMessage(CONFIGURE_GIT), [GIT_CONNECT_STEPS.GENERATE_SSH_KEY]: createMessage(GENERATE_SSH_KEY_STEP), @@ -127,8 +117,8 @@ function ConnectInitialize({ GIT_CONNECT_STEPS.CHOOSE_PROVIDER, ); - const isLoading = - (!isImport && isConnectLoading) || (isImport && isGitImportLoading); + // const isSubmitLoading = + // (!isImport && isConnectLoading) || (isImport && isGitImportLoading); const currentIndex = steps.findIndex((s) => s.key === activeStep); @@ -181,43 +171,40 @@ function ConnectInitialize({ }; if (formData.remoteUrl) { - if (!isImport) { - AnalyticsUtil.logEvent( - "GS_CONNECT_BUTTON_ON_GIT_SYNC_MODAL_CLICK", - { repoUrl: formData?.remoteUrl, connectFlow: "v2" }, - ); - connect({ - remoteUrl: formData.remoteUrl, - gitProfile, - }); - } else { - gitImport({ - remoteUrl: formData.remoteUrl, - gitProfile, - }); - } + onSubmit({ + remoteUrl: formData.remoteUrl, + gitProfile, + }); + // if (!isImport) { + // AnalyticsUtil.logEvent( + // "GS_CONNECT_BUTTON_ON_GIT_SYNC_MODAL_CLICK", + // { repoUrl: formData?.remoteUrl, connectFlow: "v2" }, + // ); + // connect({ + // remoteUrl: formData.remoteUrl, + // gitProfile, + // }); + // } else { + // gitImport({ + // remoteUrl: formData.remoteUrl, + // gitProfile, + // }); + // } } break; } } } - }, [ - activeStep, - connect, - currentIndex, - formData.remoteUrl, - gitImport, - isImport, - ]); + }, [activeStep, currentIndex, formData.remoteUrl, onSubmit]); useEffect( function changeStepOnErrorEffect() { - if (connectError?.code === GitErrorCodes.REPO_NOT_EMPTY) { + if (error?.code === GitErrorCodes.REPO_NOT_EMPTY) { setActiveStep(GIT_CONNECT_STEPS.GENERATE_SSH_KEY); } }, - [connectError?.code], + [error?.code], ); return ( @@ -236,45 +223,38 @@ function ConnectInitialize({ {activeStep === GIT_CONNECT_STEPS.CHOOSE_PROVIDER && ( )} {activeStep === GIT_CONNECT_STEPS.GENERATE_SSH_KEY && ( - + )} {activeStep === GIT_CONNECT_STEPS.ADD_DEPLOY_KEY && ( )} - - {isLoading && ( + + {isSubmitLoading && ( )} - {!isLoading && ( + {!isSubmitLoading && ( - - - + + + + + + + + + + + + ); } -export default ConnectSuccess; +export default ConnectSuccessModalView; diff --git a/app/client/src/git/components/ConnectSuccessModal/index.tsx b/app/client/src/git/components/ConnectSuccessModal/index.tsx new file mode 100644 index 000000000000..c492e5aa4bb3 --- /dev/null +++ b/app/client/src/git/components/ConnectSuccessModal/index.tsx @@ -0,0 +1,29 @@ +import React from "react"; +import ConnectSuccessModalView from "./ConnectSuccessModalView"; +import useMetadata from "git/hooks/useMetadata"; +import useConnect from "git/hooks/useConnect"; +import useSettings from "git/hooks/useSettings"; + +function ConnectSuccessModal() { + const { isConnectSuccessModalOpen, toggleConnectSuccessModal } = useConnect(); + const { toggleSettingsModal } = useSettings(); + + const { metadata } = useMetadata(); + + const remoteUrl = metadata?.remoteUrl ?? null; + const repoName = metadata?.repoName ?? null; + const defaultBranch = metadata?.defaultBranchName ?? null; + + return ( + + ); +} + +export default ConnectSuccessModal; diff --git a/app/client/src/git/components/DeployMenuItems/DeployMenuItemsView.tsx b/app/client/src/git/components/DeployMenuItems/DeployMenuItemsView.tsx new file mode 100644 index 000000000000..09ce5be3178a --- /dev/null +++ b/app/client/src/git/components/DeployMenuItems/DeployMenuItemsView.tsx @@ -0,0 +1,32 @@ +import React, { useCallback } from "react"; +import { MenuItem } from "@appsmith/ads"; +import { CONNECT_TO_GIT_OPTION, createMessage } from "ee/constants/messages"; +import AnalyticsUtil from "ee/utils/AnalyticsUtil"; +import noop from "lodash/noop"; + +interface DeployMenuItemsViewProps { + toggleConnectModal: (open: boolean) => void; +} + +function DeployMenuItemsView({ + toggleConnectModal = noop, +}: DeployMenuItemsViewProps) { + const handleClickOnConnect = useCallback(() => { + AnalyticsUtil.logEvent("GS_CONNECT_GIT_CLICK", { + source: "Deploy button", + }); + toggleConnectModal(true); + }, [toggleConnectModal]); + + return ( + + {createMessage(CONNECT_TO_GIT_OPTION)} + + ); +} + +export default DeployMenuItemsView; diff --git a/app/client/src/git/components/DeployMenuItems/index.tsx b/app/client/src/git/components/DeployMenuItems/index.tsx new file mode 100644 index 000000000000..de6c61f9af9b --- /dev/null +++ b/app/client/src/git/components/DeployMenuItems/index.tsx @@ -0,0 +1,11 @@ +import useConnect from "git/hooks/useConnect"; +import React from "react"; +import DeployMenuItemsView from "./DeployMenuItemsView"; + +function DeployMenuItems() { + const { toggleConnectModal } = useConnect(); + + return ; +} + +export default DeployMenuItems; diff --git a/app/client/src/git/components/GitContextProvider/index.tsx b/app/client/src/git/components/GitContextProvider/index.tsx index 4d4b88b4f6ad..89736de113eb 100644 --- a/app/client/src/git/components/GitContextProvider/index.tsx +++ b/app/client/src/git/components/GitContextProvider/index.tsx @@ -2,14 +2,12 @@ import React, { createContext, useCallback, useContext, useMemo } from "react"; import type { GitArtifactType } from "git/constants/enums"; import type { ApplicationPayload } from "entities/Application"; import type { FetchStatusResponseData } from "git/requests/fetchStatusRequest.types"; -import type { StatusTreeStruct } from "../StatusChanges/StatusTree"; import { useDispatch } from "react-redux"; +import type { GitArtifactDef } from "git/store/types"; +import type { StatusTreeStruct } from "../StatusChanges/types"; export interface GitContextValue { - artifactDef: { - artifactType: keyof typeof GitArtifactType; - baseArtifactId: string; - }; + artifactDef: GitArtifactDef | null; artifact: ApplicationPayload | null; statusTransformer: ( status: FetchStatusResponseData, @@ -27,8 +25,8 @@ export const useGitContext = () => { }; interface GitContextProviderProps { - artifactType: keyof typeof GitArtifactType; - baseArtifactId: string; + artifactType: keyof typeof GitArtifactType | null; + baseArtifactId: string | null; artifact: ApplicationPayload | null; isCreateArtifactPermitted: boolean; setWorkspaceIdForImport: (params: { @@ -50,10 +48,13 @@ export default function GitContextProvider({ setWorkspaceIdForImport, statusTransformer, }: GitContextProviderProps) { - const artifactDef = useMemo( - () => ({ artifactType, baseArtifactId }), - [artifactType, baseArtifactId], - ); + const artifactDef = useMemo(() => { + if (artifactType && baseArtifactId) { + return { artifactType, baseArtifactId }; + } + + return null; + }, [artifactType, baseArtifactId]); const dispatch = useDispatch(); diff --git a/app/client/src/git/components/GlobalProfile/GlobalProfileView.tsx b/app/client/src/git/components/GlobalProfile/GlobalProfileView.tsx new file mode 100644 index 000000000000..ddb2d7935387 --- /dev/null +++ b/app/client/src/git/components/GlobalProfile/GlobalProfileView.tsx @@ -0,0 +1,148 @@ +import React, { useCallback, useEffect, useState } from "react"; +import { + createMessage, + AUTHOR_EMAIL, + AUTHOR_NAME, + SUBMIT, +} from "ee/constants/messages"; +import { Classes } from "@blueprintjs/core"; +import { Button, Input, toast } from "@appsmith/ads"; +import { emailValidator } from "@appsmith/ads-old"; +import styled from "styled-components"; +import type { FetchGlobalProfileResponseData } from "git/requests/fetchGlobalProfileRequest.types"; +import type { UpdateGlobalProfileInitPayload } from "git/store/actions/updateGlobalProfileActions"; +import noop from "lodash/noop"; + +const Wrapper = styled.div` + width: 320px; + & > div { + margin-bottom: 16px; + } +`; + +const FieldWrapper = styled.div` + .user-profile-image-picker { + width: 166px; + margin-top: 4px; + } +`; + +const Loader = styled.div` + height: 38px; + width: 320px; + border-radius: 0; +`; + +interface GlobalProfileViewProps { + globalProfile: FetchGlobalProfileResponseData | null; + isFetchGlobalProfileLoading: boolean; + isUpdateGlobalProfileLoading: boolean; + updateGlobalProfile: (data: UpdateGlobalProfileInitPayload) => void; +} + +export default function GlobalProfileView({ + globalProfile = null, + isFetchGlobalProfileLoading = false, + isUpdateGlobalProfileLoading = false, + updateGlobalProfile = noop, +}: GlobalProfileViewProps) { + const [areFormValuesUpdated, setAreFormValuesUpdated] = useState(false); + + const [authorName, setAuthorNameInState] = useState( + globalProfile?.authorName, + ); + const [authorEmail, setAuthorEmailInState] = useState( + globalProfile?.authorEmail, + ); + + const isSubmitDisabled = !authorName || !authorEmail || !areFormValuesUpdated; + + const isLoading = isFetchGlobalProfileLoading || isUpdateGlobalProfileLoading; + + const setAuthorName = useCallback( + (value: string) => { + setAuthorNameInState(value); + + if (authorName) setAreFormValuesUpdated(true); + }, + [authorName], + ); + + const setAuthorEmail = useCallback( + (value: string) => { + setAuthorEmailInState(value); + + if (authorEmail) setAreFormValuesUpdated(true); + }, + [authorEmail], + ); + + const onClickUpdate = useCallback(() => { + if (authorName && authorEmail && emailValidator(authorEmail).isValid) { + setAreFormValuesUpdated(false); + updateGlobalProfile({ authorName, authorEmail }); + } else { + toast.show("Please enter valid user details"); + } + }, [authorEmail, authorName, updateGlobalProfile]); + + useEffect( + function resetOnInitEffect() { + setAreFormValuesUpdated(false); + setAuthorNameInState(globalProfile?.authorName ?? ""); + setAuthorEmailInState(globalProfile?.authorEmail ?? ""); + }, + [globalProfile], + ); + + return ( + + + {isLoading && } + {!isLoading && ( + + )} + + + {isLoading && } + {!isLoading && ( + + )} + + +
+ +
+
+
+ ); +} diff --git a/app/client/src/git/components/GlobalProfile/index.tsx b/app/client/src/git/components/GlobalProfile/index.tsx new file mode 100644 index 000000000000..5ecc06e70c87 --- /dev/null +++ b/app/client/src/git/components/GlobalProfile/index.tsx @@ -0,0 +1,23 @@ +import useGlobalProfile from "git/hooks/useGlobalProfile"; +import React from "react"; +import GlobalProfileView from "./GlobalProfileView"; + +function GlobalProfile() { + const { + globalProfile, + isFetchGlobalProfileLoading, + isUpdateGlobalProfileLoading, + updateGlobalProfile, + } = useGlobalProfile(); + + return ( + + ); +} + +export default GlobalProfile; diff --git a/app/client/src/git/components/ImportModal/index.tsx b/app/client/src/git/components/ImportModal/index.tsx index f55a468d702b..8192fa9e88a7 100644 --- a/app/client/src/git/components/ImportModal/index.tsx +++ b/app/client/src/git/components/ImportModal/index.tsx @@ -1,8 +1,51 @@ -import React from "react"; -import ConnectModal from "../ConnectModal"; +import React, { useCallback } from "react"; +import ConnectModalView from "../ConnectModal/ConnectModalView"; +import type { GitImportRequestParams } from "git/requests/gitImportRequest.types"; +import useImport from "git/hooks/useImport"; +import useGlobalSSHKey from "git/hooks/useGlobalSSHKey"; +import noop from "lodash/noop"; function ImportModal() { - return ; + const { + gitImport, + gitImportError, + isGitImportLoading, + isImportModalOpen, + toggleImportModal, + } = useImport(); + const { + fetchGlobalSSHKey, + globalSSHKey, + isFetchGlobalSSHKeyLoading, + resetGlobalSSHKey, + } = useGlobalSSHKey(); + + const sshPublicKey = globalSSHKey?.publicKey ?? null; + + const onSubmit = useCallback( + (params: GitImportRequestParams) => { + gitImport(params); + }, + [gitImport], + ); + + return ( + + ); } export default ImportModal; diff --git a/app/client/src/git/components/OpsModal/TabDeploy/DeployPreview.tsx b/app/client/src/git/components/OpsModal/TabDeploy/DeployPreview.tsx index 79abbe1439dc..311019abdc24 100644 --- a/app/client/src/git/components/OpsModal/TabDeploy/DeployPreview.tsx +++ b/app/client/src/git/components/OpsModal/TabDeploy/DeployPreview.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { useCallback, useEffect, useState } from "react"; import styled from "styled-components"; import { useSelector } from "react-redux"; @@ -15,32 +15,47 @@ import SuccessTick from "pages/common/SuccessTick"; import { howMuchTimeBeforeText } from "utils/helpers"; import AnalyticsUtil from "ee/utils/AnalyticsUtil"; import { viewerURL } from "ee/RouteBuilder"; -import { Link, Text } from "@appsmith/ads"; -import { importSvg } from "@appsmith/ads-old"; +import { Icon, Link, Text } from "@appsmith/ads"; -const CloudyIcon = importSvg( - async () => import("assets/icons/ads/cloudy-line.svg"), -); +const StyledIcon = styled(Icon)` + svg { + width: 30px; + height: 30px; + } +`; const Container = styled.div` display: flex; flex: 1; flex-direction: row; gap: ${(props) => props.theme.spaces[6]}px; - - .cloud-icon { - stroke: var(--ads-v2-color-fg); - } `; -export default function DeployPreview() { - // ! case: should reset after timer - const showSuccess = false; +interface DeployPreviewProps { + isCommitSuccess: boolean; +} + +export default function DeployPreview({ isCommitSuccess }: DeployPreviewProps) { + const [showSuccess, setShowSuccess] = useState(false); + + useEffect( + function startTimerForCommitSuccessEffect() { + if (isCommitSuccess) { + setShowSuccess(true); + const timer = setTimeout(() => { + setShowSuccess(false); + }, 5000); + + return () => clearTimeout(timer); + } + }, + [isCommitSuccess], + ); const basePageId = useSelector(getCurrentBasePageId); const lastDeployedAt = useSelector(getApplicationLastDeployedAt); - const showDeployPreview = () => { + const showDeployPreview = useCallback(() => { AnalyticsUtil.logEvent("GS_LAST_DEPLOYED_PREVIEW_LINK_CLICK", { source: "GIT_DEPLOY_MODAL", }); @@ -49,7 +64,7 @@ export default function DeployPreview() { }); window.open(path, "_blank"); - }; + }, [basePageId]); const lastDeployedAtMsg = lastDeployedAt ? `${createMessage(LATEST_DP_SUBTITLE)} ${howMuchTimeBeforeText( @@ -66,7 +81,7 @@ export default function DeployPreview() { {showSuccess ? ( ) : ( - + )}
diff --git a/app/client/src/git/components/OpsModal/TabDeploy/TabDeployView.tsx b/app/client/src/git/components/OpsModal/TabDeploy/TabDeployView.tsx index d22c93f79b97..a2db0f28805d 100644 --- a/app/client/src/git/components/OpsModal/TabDeploy/TabDeployView.tsx +++ b/app/client/src/git/components/OpsModal/TabDeploy/TabDeployView.tsx @@ -108,6 +108,7 @@ function TabDeployView({ statusBehindCount = 0, statusIsClean = false, }: TabDeployViewProps) { + const [hasSubmitted, setHasSubmitted] = useState(false); const hasChangesToCommit = !statusIsClean; const commitInputRef = useRef(null); const [commitMessage, setCommitMessage] = useState( @@ -157,6 +158,10 @@ function TabDeployView({ ((pullRequired && !isConflicting) || (statusBehindCount > 0 && statusIsClean)); + const isCommitSuccess = useMemo(() => { + return hasSubmitted && !isCommitLoading; + }, [isCommitLoading, hasSubmitted]); + useEffect( function focusCommitInputEffect() { if (!commitInputDisabled && commitInputRef.current) { @@ -200,6 +205,7 @@ function TabDeployView({ }); if (currentBranch) { + setHasSubmitted(true); commit(commitMessage.trim()); } }, [commit, commitMessage, currentBranch]); @@ -353,7 +359,9 @@ function TabDeployView({ /> )} - {!pullRequired && !isConflicting && } + {!pullRequired && !isConflicting && ( + + )}
diff --git a/app/client/src/git/components/OpsModal/index.tsx b/app/client/src/git/components/OpsModal/index.tsx index 114439c29902..66ea3ddf0182 100644 --- a/app/client/src/git/components/OpsModal/index.tsx +++ b/app/client/src/git/components/OpsModal/index.tsx @@ -1,14 +1,15 @@ import React from "react"; import OpsModalView from "./OpsModalView"; -import useProtectedBranches from "git/hooks/useProtectedBranches"; import useMetadata from "git/hooks/useMetadata"; import useStatus from "git/hooks/useStatus"; import useOps from "git/hooks/useOps"; +import useProtectedMode from "git/hooks/useProtectedMode"; +import { GitOpsTab } from "git/constants/enums"; export default function OpsModal() { - const { opsModalOpen, opsModalTab, toggleOpsModal } = useOps(); + const { isOpsModalOpen, opsModalTab, toggleOpsModal } = useOps(); const { fetchStatus } = useStatus(); - const { isProtectedMode } = useProtectedBranches(); + const isProtectedMode = useProtectedMode(); const { metadata } = useMetadata(); @@ -17,9 +18,9 @@ export default function OpsModal() { return ( diff --git a/app/client/src/git/components/ProtectedBranchCallout/ProtectedBranchCalloutView.tsx b/app/client/src/git/components/ProtectedBranchCallout/ProtectedBranchCalloutView.tsx new file mode 100644 index 000000000000..89b37bbfa239 --- /dev/null +++ b/app/client/src/git/components/ProtectedBranchCallout/ProtectedBranchCalloutView.tsx @@ -0,0 +1,85 @@ +import React, { useCallback, useMemo } from "react"; +import { Callout } from "@appsmith/ads"; +import styled from "styled-components"; +import { + BRANCH_PROTECTION_CALLOUT_CREATE_BRANCH, + BRANCH_PROTECTION_CALLOUT_MSG, + BRANCH_PROTECTION_CALLOUT_UNPROTECT, + BRANCH_PROTECTION_CALLOUT_UNPROTECT_LOADING, + createMessage, +} from "ee/constants/messages"; +import { noop } from "lodash"; +import type { FetchProtectedBranchesResponseData } from "git/requests/fetchProtectedBranchesRequest.types"; + +export const PROTECTED_CALLOUT_HEIGHT = 70; + +const StyledCallout = styled(Callout)` + height: ${PROTECTED_CALLOUT_HEIGHT}px; + overflow-y: hidden; +`; + +interface ProtectedBranchCalloutViewProps { + currentBranch: string | null; + isUpdateProtectedBranchesLoading: boolean; + protectedBranches: FetchProtectedBranchesResponseData | null; + toggleBranchPopup: (isOpen: boolean) => void; + updateProtectedBranches: (branches: string[]) => void; +} + +function ProtectedBranchCalloutView({ + currentBranch = null, + isUpdateProtectedBranchesLoading = false, + protectedBranches = null, + toggleBranchPopup = noop, + updateProtectedBranches = noop, +}: ProtectedBranchCalloutViewProps) { + const handleClickOnNewBranch = useCallback(() => { + toggleBranchPopup(true); + }, [toggleBranchPopup]); + + const handleClickOnUnprotect = useCallback(() => { + const allBranches = protectedBranches || []; + const remainingBranches = allBranches.filter( + (protectedBranch) => protectedBranch !== currentBranch, + ); + + updateProtectedBranches(remainingBranches); + }, [currentBranch, protectedBranches, updateProtectedBranches]); + + const links = useMemo( + () => [ + { + key: "create-branch", + "data-testid": "t--git-protected-create-branch-cta", + children: createMessage(BRANCH_PROTECTION_CALLOUT_CREATE_BRANCH), + onClick: handleClickOnNewBranch, + }, + { + key: "unprotect", + "data-testid": "t--git-protected-unprotect-branch-cta", + children: isUpdateProtectedBranchesLoading + ? createMessage(BRANCH_PROTECTION_CALLOUT_UNPROTECT_LOADING) + : createMessage(BRANCH_PROTECTION_CALLOUT_UNPROTECT), + onClick: handleClickOnUnprotect, + isDisabled: isUpdateProtectedBranchesLoading, + }, + ], + [ + handleClickOnNewBranch, + handleClickOnUnprotect, + isUpdateProtectedBranchesLoading, + ], + ); + + return ( + + {createMessage(BRANCH_PROTECTION_CALLOUT_MSG)} + + ); +} + +export default ProtectedBranchCalloutView; diff --git a/app/client/src/git/components/ProtectedBranchCallout/index.tsx b/app/client/src/git/components/ProtectedBranchCallout/index.tsx new file mode 100644 index 000000000000..aca08dfc1e87 --- /dev/null +++ b/app/client/src/git/components/ProtectedBranchCallout/index.tsx @@ -0,0 +1,33 @@ +import React from "react"; +import ProtectedBranchCalloutView from "./ProtectedBranchCalloutView"; +import useProtectedBranches from "git/hooks/useProtectedBranches"; +import useCurrentBranch from "git/hooks/useCurrentBranch"; +import useBranches from "git/hooks/useBranches"; +import useProtectedMode from "git/hooks/useProtectedMode"; + +function ProtectedBranchCallout() { + const isProtectedMode = useProtectedMode(); + const currentBranch = useCurrentBranch(); + const { toggleBranchPopup } = useBranches(); + const { + isUpdateProtectedBranchesLoading, + protectedBranches, + updateProtectedBranches, + } = useProtectedBranches(); + + if (!isProtectedMode) { + return null; + } + + return ( + + ); +} + +export default ProtectedBranchCallout; diff --git a/app/client/src/git/components/QuickActions/QuickActionsView.test.tsx b/app/client/src/git/components/QuickActions/QuickActionsView.test.tsx index 6e696ddffe55..f6bc193bfc7e 100644 --- a/app/client/src/git/components/QuickActions/QuickActionsView.test.tsx +++ b/app/client/src/git/components/QuickActions/QuickActionsView.test.tsx @@ -29,7 +29,7 @@ describe("QuickActionsView Component", () => { isConnectPermitted: true, isDiscardLoading: false, isFetchStatusLoading: false, - isGitConnected: false, + isConnected: false, isProtectedMode: false, isPullFailing: false, isPullLoading: false, @@ -48,7 +48,7 @@ describe("QuickActionsView Component", () => { jest.clearAllMocks(); }); - it("should render ConnectButton when isGitConnected is false", () => { + it("should render ConnectButton when isConnected is false", () => { render( @@ -57,10 +57,10 @@ describe("QuickActionsView Component", () => { expect(screen.getByTestId("connect-button")).toBeInTheDocument(); }); - it("should render QuickActionButtons when isGitConnected is true", () => { + it("should render QuickActionButtons when isConnected is true", () => { const props = { ...defaultProps, - isGitConnected: true, + isConnected: true, }; const { container } = render( @@ -86,7 +86,7 @@ describe("QuickActionsView Component", () => { it("should render Statusbar when isAutocommitEnabled and isPollingAutocommit are true", () => { const props = { ...defaultProps, - isGitConnected: true, + isConnected: true, isAutocommitEnabled: true, isAutocommitPolling: true, }; @@ -106,7 +106,7 @@ describe("QuickActionsView Component", () => { it("should call onCommitClick when commit button is clicked", () => { const props = { ...defaultProps, - isGitConnected: true, + isConnected: true, }; const { container } = render( @@ -131,7 +131,7 @@ describe("QuickActionsView Component", () => { it("should call onPullClick when pull button is clicked", () => { const props = { ...defaultProps, - isGitConnected: true, + isConnected: true, isDiscardLoading: false, isPullLoading: false, isFetchStatusLoading: false, @@ -159,7 +159,7 @@ describe("QuickActionsView Component", () => { it("should call onMerge when merge button is clicked", () => { const props = { ...defaultProps, - isGitConnected: true, + isConnected: true, }; const { container } = render( @@ -184,7 +184,7 @@ describe("QuickActionsView Component", () => { it("should call onSettingsClick when settings button is clicked", () => { const props = { ...defaultProps, - isGitConnected: true, + isConnected: true, }; const { container } = render( @@ -209,7 +209,7 @@ describe("QuickActionsView Component", () => { it("should disable commit button when isProtectedMode is true", () => { const props = { ...defaultProps, - isGitConnected: true, + isConnected: true, isProtectedMode: true, }; @@ -228,7 +228,7 @@ describe("QuickActionsView Component", () => { it("should show loading state on pull button when showPullLoadingState is true", () => { const props = { ...defaultProps, - isGitConnected: true, + isConnected: true, isPullLoading: true, }; @@ -250,7 +250,7 @@ describe("QuickActionsView Component", () => { it("should display changesToCommit count on commit button", () => { const props = { ...defaultProps, - isGitConnected: true, + isConnected: true, statusChangeCount: 5, }; @@ -267,7 +267,7 @@ describe("QuickActionsView Component", () => { it("should not display count on commit button when isProtectedMode is true", () => { const props = { ...defaultProps, - isGitConnected: true, + isConnected: true, isProtectedMode: true, statusChangeCount: 5, }; @@ -292,7 +292,7 @@ describe("QuickActionsView Component", () => { const props = { ...defaultProps, - isGitConnected: true, + isConnected: true, }; const { container } = render( @@ -310,7 +310,7 @@ describe("QuickActionsView Component", () => { it("should show behindCount on pull button", () => { const props = { ...defaultProps, - isGitConnected: true, + isConnected: true, statusBehindCount: 3, statusIsClean: true, }; diff --git a/app/client/src/git/components/QuickActions/QuickActionsView.tsx b/app/client/src/git/components/QuickActions/QuickActionsView.tsx index 396984788015..274dd00f3dba 100644 --- a/app/client/src/git/components/QuickActions/QuickActionsView.tsx +++ b/app/client/src/git/components/QuickActions/QuickActionsView.tsx @@ -33,7 +33,7 @@ interface QuickActionsViewProps { isConnectPermitted: boolean; isDiscardLoading: boolean; isFetchStatusLoading: boolean; - isGitConnected: boolean; + isConnected: boolean; isProtectedMode: boolean; isPullFailing: boolean; isPullLoading: boolean; @@ -57,10 +57,10 @@ function QuickActionsView({ isAutocommitEnabled = false, isAutocommitPolling = false, isBranchPopupOpen = false, + isConnected = false, isConnectPermitted = false, isDiscardLoading = false, isFetchStatusLoading = false, - isGitConnected = false, isProtectedMode = false, isPullFailing = false, isPullLoading = false, @@ -131,7 +131,7 @@ function QuickActionsView({ toggleConnectModal(true); }, [toggleConnectModal]); - return isGitConnected ? ( + return isConnected ? ( ); diff --git a/app/client/src/git/components/StatusChanges/StatusChangesView.tsx b/app/client/src/git/components/StatusChanges/StatusChangesView.tsx index c3768c0d866c..f8e6f0c41dfa 100644 --- a/app/client/src/git/components/StatusChanges/StatusChangesView.tsx +++ b/app/client/src/git/components/StatusChanges/StatusChangesView.tsx @@ -1,14 +1,19 @@ import type { FetchStatusResponseData } from "git/requests/fetchStatusRequest.types"; import React, { useMemo } from "react"; -import type { StatusTreeStruct } from "./StatusTree"; import StatusTree from "./StatusTree"; -import { Text } from "@appsmith/ads"; +import { Callout, Text } from "@appsmith/ads"; import { createMessage } from "@appsmith/ads-old"; import { CHANGES_SINCE_LAST_DEPLOYMENT, FETCH_GIT_STATUS, } from "ee/constants/messages"; -import StatusLoader from "pages/Editor/gitSync/components/StatusLoader"; +import StatusLoader from "./StatusLoader"; +import type { StatusTreeStruct } from "./types"; +import styled from "styled-components"; + +const CalloutContainer = styled.div` + margin-top: 16px; +`; const noopStatusTransformer = () => null; @@ -49,6 +54,11 @@ export default function StatusChangesView({ {createMessage(CHANGES_SINCE_LAST_DEPLOYMENT)} + {status.migrationMessage ? ( + + {status.migrationMessage} + + ) : null} ); } diff --git a/app/client/src/git/components/StatusChanges/StatusLoader.tsx b/app/client/src/git/components/StatusChanges/StatusLoader.tsx index bc0427bd6521..9026b75b38fa 100644 --- a/app/client/src/git/components/StatusChanges/StatusLoader.tsx +++ b/app/client/src/git/components/StatusChanges/StatusLoader.tsx @@ -6,16 +6,18 @@ const LoaderWrapper = styled.div` display: flex; flex-direction: row; align-items: center; - margin-top: ${(props) => `${props.theme.spaces[3]}px`}; + margin-bottom: 8px; +`; + +const LoaderText = styled(Text)` + margin-left: 8px; `; function StatusLoader({ loaderMsg }: { loaderMsg: string }) { return ( - - {loaderMsg} - + {loaderMsg} ); } diff --git a/app/client/src/git/components/StatusChanges/StatusTree.tsx b/app/client/src/git/components/StatusChanges/StatusTree.tsx index 289d2d28b796..437163d394df 100644 --- a/app/client/src/git/components/StatusChanges/StatusTree.tsx +++ b/app/client/src/git/components/StatusChanges/StatusTree.tsx @@ -7,12 +7,17 @@ import { Text, } from "@appsmith/ads"; import clsx from "clsx"; +import styled from "styled-components"; +import type { StatusTreeStruct } from "./types"; -export interface StatusTreeStruct { - icon: string; - message: string; - children?: StatusTreeStruct[]; -} +const StyledCollapsible = styled(Collapsible)` + gap: 0; +`; + +const StyledCollapsibleHeader = styled(CollapsibleHeader)` + padding-top: 0; + padding-bottom: 0; +`; interface StatusTreeNodeProps { icon: string; @@ -43,29 +48,31 @@ interface SingleStatusTreeProps { function SingleStatusTree({ depth = 1, tree }: SingleStatusTreeProps) { if (!tree) return null; + const noEmphasis = depth > 1 && !tree.children; + if (!tree.children) { return ( 2} + noEmphasis={noEmphasis} /> ); } return ( - - + + - + {tree.children.map((child, index) => ( ))} - + ); } diff --git a/app/client/src/git/components/StatusChanges/types.ts b/app/client/src/git/components/StatusChanges/types.ts new file mode 100644 index 000000000000..61a8e074714b --- /dev/null +++ b/app/client/src/git/components/StatusChanges/types.ts @@ -0,0 +1,5 @@ +export interface StatusTreeStruct { + icon: string; + message: string; + children?: StatusTreeStruct[]; +} diff --git a/app/client/src/git/components/index.tsx b/app/client/src/git/components/index.tsx deleted file mode 100644 index c3a1640dbd01..000000000000 --- a/app/client/src/git/components/index.tsx +++ /dev/null @@ -1,3 +0,0 @@ -export { default as GitModals } from "git/ee/components/GitModals"; -export { default as GitImportModal } from "./ImportModal"; -export { default as GitQuickActions } from "./QuickActions"; diff --git a/app/client/src/git/hooks/useArtifactSelector.ts b/app/client/src/git/hooks/useArtifactSelector.ts new file mode 100644 index 000000000000..dba2a0808bf3 --- /dev/null +++ b/app/client/src/git/hooks/useArtifactSelector.ts @@ -0,0 +1,29 @@ +import { useGitContext } from "git/components/GitContextProvider"; +import type { GitArtifactDef, GitRootState } from "git/store/types"; +import { useSelector } from "react-redux"; +import type { Tail } from "redux-saga/effects"; + +/** + * This hook is used to select data from the redux store based on the artifactDef. + **/ +export default function useArtifactSelector< + // need any type to properly infer the return type + /* eslint-disable @typescript-eslint/no-explicit-any */ + Fn extends (state: any, artifactDef: GitArtifactDef, ...args: any[]) => any, +>(selector: Fn, ...args: Tail>>): ReturnType | null { + const { artifactDef } = useGitContext(); + + return useSelector((state: GitRootState) => { + if (typeof selector !== "function" || !artifactDef) { + return null; + } + + const { artifactType, baseArtifactId } = artifactDef; + + if (!state.git?.artifacts?.[artifactType]?.[baseArtifactId]) { + return null; + } + + return selector(state, artifactDef, ...args); + }); +} diff --git a/app/client/src/git/hooks/useAutocommit.ts b/app/client/src/git/hooks/useAutocommit.ts index 73d7d955caca..91ad0e8aaae5 100644 --- a/app/client/src/git/hooks/useAutocommit.ts +++ b/app/client/src/git/hooks/useAutocommit.ts @@ -6,50 +6,50 @@ import { selectAutocommitPolling, selectToggleAutocommitState, selectTriggerAutocommitState, -} from "git/store/selectors/gitSingleArtifactSelectors"; -import type { GitRootState } from "git/store/types"; +} from "git/store/selectors/gitArtifactSelectors"; import { useCallback } from "react"; -import { useDispatch, useSelector } from "react-redux"; +import { useDispatch } from "react-redux"; +import useArtifactSelector from "./useArtifactSelector"; export default function useAutocommit() { const { artifactDef } = useGitContext(); const dispatch = useDispatch(); - const toggleAutocommitState = useSelector((state: GitRootState) => - selectToggleAutocommitState(state, artifactDef), + const toggleAutocommitState = useArtifactSelector( + selectToggleAutocommitState, ); - const triggerAutocommitState = useSelector((state: GitRootState) => - selectTriggerAutocommitState(state, artifactDef), + const triggerAutocommitState = useArtifactSelector( + selectTriggerAutocommitState, ); const toggleAutocommit = useCallback(() => { - dispatch(gitArtifactActions.toggleAutocommitInit(artifactDef)); + if (artifactDef) { + dispatch(gitArtifactActions.toggleAutocommitInit({ artifactDef })); + } }, [artifactDef, dispatch]); - const isAutocommitDisableModalOpen = useSelector((state: GitRootState) => - selectAutocommitDisableModalOpen(state, artifactDef), + const isAutocommitDisableModalOpen = useArtifactSelector( + selectAutocommitDisableModalOpen, ); const toggleAutocommitDisableModal = useCallback( (open: boolean) => { - dispatch( - gitArtifactActions.toggleAutocommitDisableModal({ - ...artifactDef, - open, - }), - ); + if (artifactDef) { + dispatch( + gitArtifactActions.toggleAutocommitDisableModal({ + artifactDef, + open, + }), + ); + } }, [artifactDef, dispatch], ); - const isAutocommitEnabled = useSelector((state: GitRootState) => - selectAutocommitEnabled(state, artifactDef), - ); + const isAutocommitEnabled = useArtifactSelector(selectAutocommitEnabled); - const isAutocommitPolling = useSelector((state: GitRootState) => - selectAutocommitPolling(state, artifactDef), - ); + const isAutocommitPolling = useArtifactSelector(selectAutocommitPolling); return { isToggleAutocommitLoading: toggleAutocommitState?.loading ?? false, @@ -57,9 +57,9 @@ export default function useAutocommit() { toggleAutocommit, isTriggerAutocommitLoading: triggerAutocommitState?.loading ?? false, triggerAutocommitError: triggerAutocommitState?.error ?? null, - isAutocommitDisableModalOpen, + isAutocommitDisableModalOpen: isAutocommitDisableModalOpen ?? false, toggleAutocommitDisableModal, - isAutocommitEnabled, - isAutocommitPolling, + isAutocommitEnabled: isAutocommitEnabled ?? false, + isAutocommitPolling: isAutocommitPolling ?? false, }; } diff --git a/app/client/src/git/hooks/useBranches.ts b/app/client/src/git/hooks/useBranches.ts index 4a0ecead44d7..fe85a318b8d4 100644 --- a/app/client/src/git/hooks/useBranches.ts +++ b/app/client/src/git/hooks/useBranches.ts @@ -8,103 +8,105 @@ import { selectCreateBranchState, selectDeleteBranchState, selectCurrentBranch, -} from "git/store/selectors/gitSingleArtifactSelectors"; -import type { GitRootState } from "git/store/types"; +} from "git/store/selectors/gitArtifactSelectors"; import { useCallback } from "react"; -import { useDispatch, useSelector } from "react-redux"; +import { useDispatch } from "react-redux"; +import useArtifactSelector from "./useArtifactSelector"; export default function useBranches() { - const { artifactDef } = useGitContext(); + const { artifact, artifactDef } = useGitContext(); + const artifactId = artifact?.id; const dispatch = useDispatch(); // fetch branches - const branchesState = useSelector((state: GitRootState) => - selectFetchBranchesState(state, artifactDef), - ); + const branchesState = useArtifactSelector(selectFetchBranchesState); + const fetchBranches = useCallback(() => { - dispatch( - gitArtifactActions.fetchBranchesInit({ - ...artifactDef, - pruneBranches: true, - }), - ); - }, [artifactDef, dispatch]); + if (artifactDef && artifactId) { + dispatch( + gitArtifactActions.fetchBranchesInit({ + artifactId, + artifactDef, + pruneBranches: true, + }), + ); + } + }, [artifactDef, artifactId, dispatch]); // create branch - const createBranchState = useSelector((state: GitRootState) => - selectCreateBranchState(state, artifactDef), - ); + const createBranchState = useArtifactSelector(selectCreateBranchState); const createBranch = useCallback( (branchName: string) => { - dispatch( - gitArtifactActions.createBranchInit({ - ...artifactDef, - branchName, - }), - ); + if (artifactDef && artifactId) { + dispatch( + gitArtifactActions.createBranchInit({ + artifactDef, + artifactId, + branchName, + }), + ); + } }, - [artifactDef, dispatch], + [artifactDef, artifactId, dispatch], ); // delete branch - const deleteBranchState = useSelector((state: GitRootState) => - selectDeleteBranchState(state, artifactDef), - ); + const deleteBranchState = useArtifactSelector(selectDeleteBranchState); const deleteBranch = useCallback( (branchName: string) => { - dispatch( - gitArtifactActions.deleteBranchInit({ - ...artifactDef, - branchName, - }), - ); + if (artifactDef && artifactId) { + dispatch( + gitArtifactActions.deleteBranchInit({ + artifactId, + artifactDef, + branchName, + }), + ); + } }, - [artifactDef, dispatch], + [artifactDef, artifactId, dispatch], ); // checkout branch - const checkoutBranchState = useSelector((state: GitRootState) => - selectCheckoutBranchState(state, artifactDef), - ); + const checkoutBranchState = useArtifactSelector(selectCheckoutBranchState); const checkoutBranch = useCallback( (branchName: string) => { - dispatch( - gitArtifactActions.checkoutBranchInit({ - ...artifactDef, - branchName, - }), - ); + if (artifactDef && artifactId) { + dispatch( + gitArtifactActions.checkoutBranchInit({ + artifactDef, + artifactId, + branchName, + }), + ); + } }, - [artifactDef, dispatch], + [artifactDef, artifactId, dispatch], ); - const checkoutDestBranch = useSelector((state: GitRootState) => - selectCheckoutDestBranch(state, artifactDef), - ); + const checkoutDestBranch = useArtifactSelector(selectCheckoutDestBranch); // derived - const currentBranch = useSelector((state: GitRootState) => - selectCurrentBranch(state, artifactDef), - ); + const currentBranch = useArtifactSelector(selectCurrentBranch); // git branch list popup - const isBranchPopupOpen = useSelector((state: GitRootState) => - selectBranchPopupOpen(state, artifactDef), - ); + const isBranchPopupOpen = useArtifactSelector(selectBranchPopupOpen); const toggleBranchPopup = useCallback( (open: boolean) => { - dispatch( - gitArtifactActions.toggleBranchPopup({ - ...artifactDef, - open, - }), - ); + if (artifactDef) { + dispatch( + gitArtifactActions.toggleBranchPopup({ + artifactDef, + open, + }), + ); + } }, [artifactDef, dispatch], ); return { - branches: branchesState?.value, + branches: branchesState?.value ?? null, isFetchBranchesLoading: branchesState?.loading ?? false, fetchBranchesError: branchesState?.error ?? null, fetchBranches, @@ -119,7 +121,7 @@ export default function useBranches() { checkoutBranch, checkoutDestBranch, currentBranch: currentBranch ?? null, - isBranchPopupOpen, + isBranchPopupOpen: isBranchPopupOpen ?? false, toggleBranchPopup, }; } diff --git a/app/client/src/git/hooks/useCommit.ts b/app/client/src/git/hooks/useCommit.ts index 56f78cc11bcd..6a468046a84b 100644 --- a/app/client/src/git/hooks/useCommit.ts +++ b/app/client/src/git/hooks/useCommit.ts @@ -1,38 +1,43 @@ import { useGitContext } from "git/components/GitContextProvider"; import { gitArtifactActions } from "git/store/gitArtifactSlice"; -import { selectCommitState } from "git/store/selectors/gitSingleArtifactSelectors"; -import type { GitRootState } from "git/store/types"; +import { selectCommitState } from "git/store/selectors/gitArtifactSelectors"; import { useCallback } from "react"; -import { useDispatch, useSelector } from "react-redux"; +import { useDispatch } from "react-redux"; +import useArtifactSelector from "./useArtifactSelector"; export default function useCommit() { - const { artifactDef } = useGitContext(); + const { artifact, artifactDef } = useGitContext(); + const artifactId = artifact?.id; + const dispatch = useDispatch(); - const commitState = useSelector((state: GitRootState) => - selectCommitState(state, artifactDef), - ); + const commitState = useArtifactSelector(selectCommitState); const commit = useCallback( (commitMessage: string) => { - dispatch( - gitArtifactActions.commitInit({ - ...artifactDef, - commitMessage, - doPush: true, - }), - ); + if (artifactDef && artifactId) { + dispatch( + gitArtifactActions.commitInit({ + artifactId, + artifactDef, + commitMessage, + doPush: true, + }), + ); + } }, - [artifactDef, dispatch], + [artifactDef, artifactId, dispatch], ); const clearCommitError = useCallback(() => { - dispatch(gitArtifactActions.clearCommitError(artifactDef)); + if (artifactDef) { + dispatch(gitArtifactActions.clearCommitError({ artifactDef })); + } }, [artifactDef, dispatch]); return { isCommitLoading: commitState?.loading ?? false, - commitError: commitState?.error, + commitError: commitState?.error ?? null, commit, clearCommitError, }; diff --git a/app/client/src/git/hooks/useConnect.ts b/app/client/src/git/hooks/useConnect.ts index 1064ce7ff26e..884addac0fd7 100644 --- a/app/client/src/git/hooks/useConnect.ts +++ b/app/client/src/git/hooks/useConnect.ts @@ -4,82 +4,53 @@ import { gitArtifactActions } from "git/store/gitArtifactSlice"; import { selectConnectModalOpen, selectConnectState, - selectFetchSSHKeysState, - selectGenerateSSHKeyState, - selectGitImportState, -} from "git/store/selectors/gitSingleArtifactSelectors"; -import type { GitRootState } from "git/store/types"; + selectConnectSuccessModalOpen, +} from "git/store/selectors/gitArtifactSelectors"; import { useCallback } from "react"; import { useDispatch } from "react-redux"; -import { useSelector } from "react-redux"; +import useArtifactSelector from "./useArtifactSelector"; export default function useConnect() { const { artifactDef } = useGitContext(); const dispatch = useDispatch(); - const connectState = useSelector((state: GitRootState) => - selectConnectState(state, artifactDef), - ); + const connectState = useArtifactSelector(selectConnectState); const connect = useCallback( (params: ConnectRequestParams) => { - dispatch(gitArtifactActions.connectInit({ ...artifactDef, ...params })); - }, - [artifactDef, dispatch], - ); - - const gitImportState = useSelector((state: GitRootState) => - selectGitImportState(state, artifactDef), - ); - - const gitImport = useCallback( - (params) => { - dispatch(gitArtifactActions.gitImportInit({ ...artifactDef, ...params })); + if (artifactDef) { + dispatch(gitArtifactActions.connectInit({ artifactDef, ...params })); + } }, [artifactDef, dispatch], ); - const fetchSSHKeyState = useSelector((state: GitRootState) => - selectFetchSSHKeysState(state, artifactDef), - ); - - const fetchSSHKey = useCallback(() => { - dispatch(gitArtifactActions.fetchSSHKeyInit(artifactDef)); - }, [artifactDef, dispatch]); - - const resetFetchSSHKey = useCallback(() => { - dispatch(gitArtifactActions.resetFetchSSHKey(artifactDef)); - }, [artifactDef, dispatch]); - - const generateSSHKeyState = useSelector((state: GitRootState) => - selectGenerateSSHKeyState(state, artifactDef), - ); + const isConnectModalOpen = useArtifactSelector(selectConnectModalOpen); - const generateSSHKey = useCallback( - (keyType: string, isImport: boolean = false) => { - dispatch( - gitArtifactActions.generateSSHKeyInit({ - ...artifactDef, - keyType, - isImport, - }), - ); + const toggleConnectModal = useCallback( + (open: boolean) => { + if (artifactDef) { + dispatch(gitArtifactActions.toggleConnectModal({ artifactDef, open })); + } }, [artifactDef, dispatch], ); - const resetGenerateSSHKey = useCallback(() => { - dispatch(gitArtifactActions.resetGenerateSSHKey(artifactDef)); - }, [artifactDef, dispatch]); - - const isConnectModalOpen = useSelector((state: GitRootState) => - selectConnectModalOpen(state, artifactDef), + const isConnectSuccessModalOpen = useArtifactSelector( + selectConnectSuccessModalOpen, ); - const toggleConnectModal = useCallback( + const toggleConnectSuccessModal = useCallback( (open: boolean) => { - dispatch(gitArtifactActions.toggleConnectModal({ ...artifactDef, open })); + if (artifactDef) { + dispatch( + gitArtifactActions.toggleConnectSuccessModal({ + artifactDef, + open, + }), + ); + } }, [artifactDef, dispatch], ); @@ -88,19 +59,9 @@ export default function useConnect() { isConnectLoading: connectState?.loading ?? false, connectError: connectState?.error ?? null, connect, - isGitImportLoading: gitImportState?.loading ?? false, - gitImportError: gitImportState?.error ?? null, - gitImport, - sshKey: fetchSSHKeyState?.value ?? null, - isFetchSSHKeyLoading: fetchSSHKeyState?.loading ?? false, - fetchSSHKeyError: fetchSSHKeyState?.error ?? null, - fetchSSHKey, - resetFetchSSHKey, - isGenerateSSHKeyLoading: generateSSHKeyState?.loading ?? false, - generateSSHKeyError: generateSSHKeyState?.error ?? null, - generateSSHKey, - resetGenerateSSHKey, - isConnectModalOpen, + isConnectModalOpen: isConnectModalOpen ?? false, toggleConnectModal, + isConnectSuccessModalOpen: isConnectSuccessModalOpen ?? false, + toggleConnectSuccessModal, }; } diff --git a/app/client/src/git/hooks/useConnected.ts b/app/client/src/git/hooks/useConnected.ts new file mode 100644 index 000000000000..39cfa55ca245 --- /dev/null +++ b/app/client/src/git/hooks/useConnected.ts @@ -0,0 +1,8 @@ +import { selectConnected } from "git/store/selectors/gitArtifactSelectors"; +import useArtifactSelector from "./useArtifactSelector"; + +export default function useConnected() { + const isConnected = useArtifactSelector(selectConnected); + + return isConnected ?? false; +} diff --git a/app/client/src/git/hooks/useCurrentBranch.ts b/app/client/src/git/hooks/useCurrentBranch.ts new file mode 100644 index 000000000000..797d8d598ba5 --- /dev/null +++ b/app/client/src/git/hooks/useCurrentBranch.ts @@ -0,0 +1,8 @@ +import { selectCurrentBranch } from "git/store/selectors/gitArtifactSelectors"; +import useArtifactSelector from "./useArtifactSelector"; + +export default function useCurrentBranch() { + const currentBranch = useArtifactSelector(selectCurrentBranch); + + return currentBranch; +} diff --git a/app/client/src/git/hooks/useDiscard.ts b/app/client/src/git/hooks/useDiscard.ts index 2f71c11608f9..19818cb7f8fa 100644 --- a/app/client/src/git/hooks/useDiscard.ts +++ b/app/client/src/git/hooks/useDiscard.ts @@ -1,24 +1,26 @@ import { useGitContext } from "git/components/GitContextProvider"; import { gitArtifactActions } from "git/store/gitArtifactSlice"; -import { selectDiscardState } from "git/store/selectors/gitSingleArtifactSelectors"; -import type { GitRootState } from "git/store/types"; +import { selectDiscardState } from "git/store/selectors/gitArtifactSelectors"; import { useCallback } from "react"; -import { useDispatch, useSelector } from "react-redux"; +import { useDispatch } from "react-redux"; +import useArtifactSelector from "./useArtifactSelector"; export default function useDiscard() { const { artifactDef } = useGitContext(); const dispatch = useDispatch(); - const discardState = useSelector((state: GitRootState) => - selectDiscardState(state, artifactDef), - ); + const discardState = useArtifactSelector(selectDiscardState); const discard = useCallback(() => { - dispatch(gitArtifactActions.discardInit(artifactDef)); + if (artifactDef) { + dispatch(gitArtifactActions.discardInit({ artifactDef })); + } }, [artifactDef, dispatch]); const clearDiscardError = useCallback(() => { - dispatch(gitArtifactActions.clearDiscardError(artifactDef)); + if (artifactDef) { + dispatch(gitArtifactActions.clearDiscardError({ artifactDef })); + } }, [artifactDef, dispatch]); return { diff --git a/app/client/src/git/hooks/useDisconnect.ts b/app/client/src/git/hooks/useDisconnect.ts index 36dfd2cf8cf9..42fd878319fd 100644 --- a/app/client/src/git/hooks/useDisconnect.ts +++ b/app/client/src/git/hooks/useDisconnect.ts @@ -4,10 +4,10 @@ import { selectDisconnectArtifactName, selectDisconnectBaseArtifactId, selectDisconnectState, -} from "git/store/selectors/gitSingleArtifactSelectors"; -import type { GitRootState } from "git/store/types"; +} from "git/store/selectors/gitArtifactSelectors"; import { useCallback } from "react"; -import { useDispatch, useSelector } from "react-redux"; +import { useDispatch } from "react-redux"; +import useArtifactSelector from "./useArtifactSelector"; export default function useDisconnect() { const { artifact, artifactDef } = useGitContext(); @@ -15,30 +15,38 @@ export default function useDisconnect() { const dispatch = useDispatch(); - const disconnectState = useSelector((state: GitRootState) => - selectDisconnectState(state, artifactDef), - ); + const disconnectState = useArtifactSelector(selectDisconnectState); const disconnect = useCallback(() => { - dispatch(gitArtifactActions.disconnectInit(artifactDef)); + if (artifactDef) { + dispatch( + gitArtifactActions.disconnectInit({ + artifactDef, + }), + ); + } }, [artifactDef, dispatch]); - const disconnectBaseArtifactId = useSelector((state: GitRootState) => - selectDisconnectBaseArtifactId(state, artifactDef), + const disconnectBaseArtifactId = useArtifactSelector( + selectDisconnectBaseArtifactId, ); - const disconnectArtifactName = useSelector((state: GitRootState) => - selectDisconnectArtifactName(state, artifactDef), + const disconnectArtifactName = useArtifactSelector( + selectDisconnectArtifactName, ); const openDisconnectModal = useCallback(() => { - dispatch( - gitArtifactActions.openDisconnectModal({ ...artifactDef, artifactName }), - ); + if (artifactDef) { + dispatch( + gitArtifactActions.openDisconnectModal({ artifactDef, artifactName }), + ); + } }, [artifactDef, artifactName, dispatch]); const closeDisconnectModal = useCallback(() => { - dispatch(gitArtifactActions.closeDisconnectModal(artifactDef)); + if (artifactDef) { + dispatch(gitArtifactActions.closeDisconnectModal({ artifactDef })); + } }, [artifactDef, dispatch]); return { diff --git a/app/client/src/git/hooks/useGitPermissions.ts b/app/client/src/git/hooks/useGitPermissions.ts index 3279dcd3e00e..13ca2404a161 100644 --- a/app/client/src/git/hooks/useGitPermissions.ts +++ b/app/client/src/git/hooks/useGitPermissions.ts @@ -10,47 +10,46 @@ import { useMemo } from "react"; export default function useGitPermissions() { const { artifact, artifactDef } = useGitContext(); - const { artifactType } = artifactDef; const isConnectPermitted = useMemo(() => { if (artifact) { - if (artifactType === GitArtifactType.Application) { + if (artifactDef?.artifactType === GitArtifactType.Application) { return hasConnectToGitPermission(artifact.userPermissions); } } return false; - }, [artifact, artifactType]); + }, [artifact, artifactDef?.artifactType]); const isManageDefaultBranchPermitted = useMemo(() => { if (artifact) { - if (artifactType === GitArtifactType.Application) { + if (artifactDef?.artifactType === GitArtifactType.Application) { return hasManageDefaultBranchPermission(artifact.userPermissions); } } return false; - }, [artifact, artifactType]); + }, [artifact, artifactDef?.artifactType]); const isManageProtectedBranchesPermitted = useMemo(() => { if (artifact) { - if (artifactType === GitArtifactType.Application) { + if (artifactDef?.artifactType === GitArtifactType.Application) { return hasManageProtectedBranchesPermission(artifact.userPermissions); } } return false; - }, [artifact, artifactType]); + }, [artifact, artifactDef?.artifactType]); const isManageAutocommitPermitted = useMemo(() => { if (artifact) { - if (artifactType === GitArtifactType.Application) { + if (artifactDef?.artifactType === GitArtifactType.Application) { return hasManageAutoCommitPermission(artifact.userPermissions); } } return false; - }, [artifact, artifactType]); + }, [artifact, artifactDef?.artifactType]); return { isConnectPermitted, diff --git a/app/client/src/git/hooks/useGlobalProfile.ts b/app/client/src/git/hooks/useGlobalProfile.ts index f319f9c1f5db..3cc3a80aad98 100644 --- a/app/client/src/git/hooks/useGlobalProfile.ts +++ b/app/client/src/git/hooks/useGlobalProfile.ts @@ -1,9 +1,9 @@ import type { UpdateGlobalProfileRequestParams } from "git/requests/updateGlobalProfileRequest.types"; -import { gitConfigActions } from "git/store/gitConfigSlice"; +import { gitGlobalActions } from "git/store/gitGlobalSlice"; import { selectFetchGlobalProfileState, selectUpdateGlobalProfileState, -} from "git/store/selectors/gitConfigSelectors"; +} from "git/store/selectors/gitGlobalSelectors"; import type { GitRootState } from "git/store/types"; import { useCallback } from "react"; @@ -16,7 +16,7 @@ export default function useGlobalProfile() { ); const fetchGlobalProfile = useCallback(() => { - dispatch(gitConfigActions.fetchGlobalProfileInit()); + dispatch(gitGlobalActions.fetchGlobalProfileInit()); }, [dispatch]); const updateGlobalProfileState = useSelector((state: GitRootState) => @@ -25,7 +25,7 @@ export default function useGlobalProfile() { const updateGlobalProfile = useCallback( (params: UpdateGlobalProfileRequestParams) => { - dispatch(gitConfigActions.updateGlobalProfileInit(params)); + dispatch(gitGlobalActions.updateGlobalProfileInit(params)); }, [dispatch], ); diff --git a/app/client/src/git/hooks/useGlobalSSHKey.ts b/app/client/src/git/hooks/useGlobalSSHKey.ts new file mode 100644 index 000000000000..ac7216045a6a --- /dev/null +++ b/app/client/src/git/hooks/useGlobalSSHKey.ts @@ -0,0 +1,29 @@ +import { useCallback } from "react"; +import { useDispatch, useSelector } from "react-redux"; +import { selectFetchGlobalSSHKeyState } from "git/store/selectors/gitGlobalSelectors"; +import { gitGlobalActions } from "git/store/gitGlobalSlice"; + +export default function useGlobalSSHKey() { + const dispatch = useDispatch(); + + const globalSSHKeyState = useSelector(selectFetchGlobalSSHKeyState); + + const fetchGlobalSSHKey = useCallback( + (keyType: string) => { + dispatch(gitGlobalActions.fetchGlobalSSHKeyInit({ keyType })); + }, + [dispatch], + ); + + const resetGlobalSSHKey = useCallback(() => { + dispatch(gitGlobalActions.resetGlobalSSHKey()); + }, [dispatch]); + + return { + globalSSHKey: globalSSHKeyState?.value ?? null, + globalSSHKeyError: globalSSHKeyState?.error ?? null, + isFetchGlobalSSHKeyLoading: globalSSHKeyState?.loading ?? false, + fetchGlobalSSHKey, + resetGlobalSSHKey, + }; +} diff --git a/app/client/src/git/hooks/useImport.ts b/app/client/src/git/hooks/useImport.ts new file mode 100644 index 000000000000..62069b888d68 --- /dev/null +++ b/app/client/src/git/hooks/useImport.ts @@ -0,0 +1,38 @@ +import { useCallback } from "react"; +import { useDispatch, useSelector } from "react-redux"; +import { + selectGitImportState, + selectImportModalOpen, +} from "git/store/selectors/gitGlobalSelectors"; +import { gitGlobalActions } from "git/store/gitGlobalSlice"; +import type { GitImportRequestParams } from "git/requests/gitImportRequest.types"; + +export default function useImport() { + const dispatch = useDispatch(); + + const gitImportState = useSelector(selectGitImportState); + + const gitImport = useCallback( + (params: GitImportRequestParams) => { + dispatch(gitGlobalActions.gitImportInit(params)); + }, + [dispatch], + ); + + const isImportModalOpen = useSelector(selectImportModalOpen); + + const toggleImportModal = useCallback( + (open: boolean) => { + dispatch(gitGlobalActions.toggleImportModal({ open })); + }, + [dispatch], + ); + + return { + isGitImportLoading: gitImportState?.loading ?? false, + gitImportError: gitImportState?.error ?? null, + gitImport, + isImportModalOpen: isImportModalOpen ?? false, + toggleImportModal, + }; +} diff --git a/app/client/src/git/hooks/useLocalProfile.ts b/app/client/src/git/hooks/useLocalProfile.ts index e770ad6356bc..8d77899a7602 100644 --- a/app/client/src/git/hooks/useLocalProfile.ts +++ b/app/client/src/git/hooks/useLocalProfile.ts @@ -4,36 +4,40 @@ import { gitArtifactActions } from "git/store/gitArtifactSlice"; import { selectFetchLocalProfileState, selectUpdateLocalProfileState, -} from "git/store/selectors/gitSingleArtifactSelectors"; -import type { GitRootState } from "git/store/types"; +} from "git/store/selectors/gitArtifactSelectors"; import { useCallback } from "react"; -import { useDispatch, useSelector } from "react-redux"; +import { useDispatch } from "react-redux"; +import useArtifactSelector from "./useArtifactSelector"; export default function useLocalProfile() { const { artifactDef } = useGitContext(); const dispatch = useDispatch(); - const fetchLocalProfileState = useSelector((state: GitRootState) => - selectFetchLocalProfileState(state, artifactDef), + const fetchLocalProfileState = useArtifactSelector( + selectFetchLocalProfileState, ); const fetchLocalProfile = useCallback(() => { - dispatch(gitArtifactActions.fetchLocalProfileInit(artifactDef)); + if (artifactDef) { + dispatch(gitArtifactActions.fetchLocalProfileInit({ artifactDef })); + } }, [artifactDef, dispatch]); - const updateLocalProfileState = useSelector((state: GitRootState) => - selectUpdateLocalProfileState(state, artifactDef), + const updateLocalProfileState = useArtifactSelector( + selectUpdateLocalProfileState, ); const updateLocalProfile = useCallback( (params: UpdateLocalProfileRequestParams) => { - dispatch( - gitArtifactActions.updateLocalProfileInit({ - ...artifactDef, - ...params, - }), - ); + if (artifactDef) { + dispatch( + gitArtifactActions.updateLocalProfileInit({ + artifactDef, + ...params, + }), + ); + } }, [artifactDef, dispatch], ); diff --git a/app/client/src/git/hooks/useMerge.ts b/app/client/src/git/hooks/useMerge.ts index f7394601b191..8fa79b16049f 100644 --- a/app/client/src/git/hooks/useMerge.ts +++ b/app/client/src/git/hooks/useMerge.ts @@ -3,10 +3,10 @@ import { gitArtifactActions } from "git/store/gitArtifactSlice"; import { selectMergeState, selectMergeStatusState, -} from "git/store/selectors/gitSingleArtifactSelectors"; -import type { GitRootState } from "git/store/types"; +} from "git/store/selectors/gitArtifactSelectors"; import { useCallback } from "react"; -import { useDispatch, useSelector } from "react-redux"; +import { useDispatch } from "react-redux"; +import useArtifactSelector from "./useArtifactSelector"; export default function useMerge() { const { artifact, artifactDef } = useGitContext(); @@ -14,44 +14,46 @@ export default function useMerge() { const dispatch = useDispatch(); // merge - const mergeState = useSelector((state: GitRootState) => - selectMergeState(state, artifactDef), - ); + const mergeState = useArtifactSelector(selectMergeState); const merge = useCallback(() => { - dispatch(gitArtifactActions.mergeInit(artifactDef)); + if (artifactDef) { + dispatch(gitArtifactActions.mergeInit({ artifactDef })); + } }, [artifactDef, dispatch]); // merge status - const mergeStatusState = useSelector((state: GitRootState) => - selectMergeStatusState(state, artifactDef), - ); + const mergeStatusState = useArtifactSelector(selectMergeStatusState); const fetchMergeStatus = useCallback( (sourceBranch: string, destinationBranch: string) => { - dispatch( - gitArtifactActions.fetchMergeStatusInit({ - ...artifactDef, - artifactId: artifactId ?? "", - sourceBranch, - destinationBranch, - }), - ); + if (artifactDef) { + dispatch( + gitArtifactActions.fetchMergeStatusInit({ + artifactDef, + artifactId: artifactId ?? "", + sourceBranch, + destinationBranch, + }), + ); + } }, [artifactId, artifactDef, dispatch], ); const clearMergeStatus = useCallback(() => { - dispatch(gitArtifactActions.clearMergeStatus(artifactDef)); + if (artifactDef) { + dispatch(gitArtifactActions.clearMergeStatus({ artifactDef })); + } }, [artifactDef, dispatch]); return { isMergeLoading: mergeState?.loading ?? false, - mergeError: mergeState?.error, + mergeError: mergeState?.error ?? null, merge, - mergeStatus: mergeStatusState?.value, + mergeStatus: mergeStatusState?.value ?? null, isFetchMergeStatusLoading: mergeStatusState?.loading ?? false, - fetchMergeStatusError: mergeStatusState?.error, + fetchMergeStatusError: mergeStatusState?.error ?? null, fetchMergeStatus, clearMergeStatus, }; diff --git a/app/client/src/git/hooks/useMetadata.ts b/app/client/src/git/hooks/useMetadata.ts index 9bd5356ad763..2ccd15d7ec89 100644 --- a/app/client/src/git/hooks/useMetadata.ts +++ b/app/client/src/git/hooks/useMetadata.ts @@ -1,26 +1,12 @@ -import { useGitContext } from "git/components/GitContextProvider"; -import { - selectGitConnected, - selectMetadataState, -} from "git/store/selectors/gitSingleArtifactSelectors"; -import type { GitRootState } from "git/store/types"; -import { useSelector } from "react-redux"; +import { selectMetadataState } from "git/store/selectors/gitArtifactSelectors"; +import useArtifactSelector from "./useArtifactSelector"; export default function useMetadata() { - const { artifactDef } = useGitContext(); - - const metadataState = useSelector((state: GitRootState) => - selectMetadataState(state, artifactDef), - ); - - const isGitConnected = useSelector((state: GitRootState) => - selectGitConnected(state, artifactDef), - ); + const metadataState = useArtifactSelector(selectMetadataState); return { metadata: metadataState?.value ?? null, isFetchMetadataLoading: metadataState?.loading ?? false, fetchMetadataError: metadataState?.error ?? null, - isGitConnected, }; } diff --git a/app/client/src/git/hooks/useOps.ts b/app/client/src/git/hooks/useOps.ts index 32eec997cf25..9b15bd035d85 100644 --- a/app/client/src/git/hooks/useOps.ts +++ b/app/client/src/git/hooks/useOps.ts @@ -5,10 +5,10 @@ import { selectConflictErrorModalOpen, selectOpsModalOpen, selectOpsModalTab, -} from "git/store/selectors/gitSingleArtifactSelectors"; -import type { GitRootState } from "git/store/types"; +} from "git/store/selectors/gitArtifactSelectors"; import { useCallback } from "react"; -import { useDispatch, useSelector } from "react-redux"; +import { useDispatch } from "react-redux"; +import useArtifactSelector from "./useArtifactSelector"; export default function useOps() { const { artifactDef } = useGitContext(); @@ -16,42 +16,40 @@ export default function useOps() { const dispatch = useDispatch(); // ops modal - const opsModalOpen = useSelector((state: GitRootState) => - selectOpsModalOpen(state, artifactDef), - ); + const opsModalOpen = useArtifactSelector(selectOpsModalOpen); - const opsModalTab = useSelector((state: GitRootState) => - selectOpsModalTab(state, artifactDef), - ); + const opsModalTab = useArtifactSelector(selectOpsModalTab); const toggleOpsModal = useCallback( (open: boolean, tab: keyof typeof GitOpsTab = GitOpsTab.Deploy) => { - dispatch( - gitArtifactActions.toggleOpsModal({ ...artifactDef, open, tab }), - ); + if (artifactDef) { + dispatch(gitArtifactActions.toggleOpsModal({ artifactDef, open, tab })); + } }, [artifactDef, dispatch], ); // conflict error modal - const conflictErrorModalOpen = useSelector((state: GitRootState) => - selectConflictErrorModalOpen(state, artifactDef), + const conflictErrorModalOpen = useArtifactSelector( + selectConflictErrorModalOpen, ); const toggleConflictErrorModal = useCallback( (open: boolean) => { - dispatch( - gitArtifactActions.toggleConflictErrorModal({ ...artifactDef, open }), - ); + if (artifactDef) { + dispatch( + gitArtifactActions.toggleConflictErrorModal({ artifactDef, open }), + ); + } }, [artifactDef, dispatch], ); return { opsModalTab, - opsModalOpen, + isOpsModalOpen: opsModalOpen ?? false, toggleOpsModal, - conflictErrorModalOpen, + isConflictErrorModalOpen: conflictErrorModalOpen ?? false, toggleConflictErrorModal, }; } diff --git a/app/client/src/git/hooks/useProtectedBranches.ts b/app/client/src/git/hooks/useProtectedBranches.ts index fa3b2ef89307..6ec68ee23b74 100644 --- a/app/client/src/git/hooks/useProtectedBranches.ts +++ b/app/client/src/git/hooks/useProtectedBranches.ts @@ -2,55 +2,55 @@ import { useGitContext } from "git/components/GitContextProvider"; import { gitArtifactActions } from "git/store/gitArtifactSlice"; import { selectFetchProtectedBranchesState, - selectProtectedMode, selectUpdateProtectedBranchesState, -} from "git/store/selectors/gitSingleArtifactSelectors"; -import type { GitRootState } from "git/store/types"; +} from "git/store/selectors/gitArtifactSelectors"; import { useCallback } from "react"; -import { useDispatch, useSelector } from "react-redux"; +import { useDispatch } from "react-redux"; +import useArtifactSelector from "./useArtifactSelector"; function useProtectedBranches() { const { artifactDef } = useGitContext(); const dispatch = useDispatch(); - const fetchProtectedBranchesState = useSelector((state: GitRootState) => - selectFetchProtectedBranchesState(state, artifactDef), + const fetchProtectedBranchesState = useArtifactSelector( + selectFetchProtectedBranchesState, ); const fetchProtectedBranches = useCallback(() => { - dispatch(gitArtifactActions.fetchProtectedBranchesInit(artifactDef)); + if (artifactDef) { + dispatch(gitArtifactActions.fetchProtectedBranchesInit({ artifactDef })); + } }, [dispatch, artifactDef]); - const updateProtectedBranchesState = useSelector((state: GitRootState) => - selectUpdateProtectedBranchesState(state, artifactDef), + const updateProtectedBranchesState = useArtifactSelector( + selectUpdateProtectedBranchesState, ); const updateProtectedBranches = useCallback( (branches: string[]) => { - dispatch( - gitArtifactActions.updateProtectedBranchesInit({ - ...artifactDef, - branchNames: branches, - }), - ); + if (artifactDef) { + dispatch( + gitArtifactActions.updateProtectedBranchesInit({ + artifactDef, + branchNames: branches, + }), + ); + } }, [dispatch, artifactDef], ); - const isProtectedMode = useSelector((state: GitRootState) => - selectProtectedMode(state, artifactDef), - ); - return { - protectedBranches: fetchProtectedBranchesState.value, - isFetchProtectedBranchesLoading: fetchProtectedBranchesState.loading, - fetchProtectedBranchesError: fetchProtectedBranchesState.error, + protectedBranches: fetchProtectedBranchesState?.value ?? null, + isFetchProtectedBranchesLoading: + fetchProtectedBranchesState?.loading ?? false, + fetchProtectedBranchesError: fetchProtectedBranchesState?.error ?? null, fetchProtectedBranches, - isUpdateProtectedBranchesLoading: updateProtectedBranchesState.loading, - updateProtectedBranchesError: updateProtectedBranchesState.error, + isUpdateProtectedBranchesLoading: + updateProtectedBranchesState?.loading ?? false, + updateProtectedBranchesError: updateProtectedBranchesState?.error ?? null, updateProtectedBranches, - isProtectedMode, }; } diff --git a/app/client/src/git/hooks/useProtectedMode.ts b/app/client/src/git/hooks/useProtectedMode.ts new file mode 100644 index 000000000000..e8e86e9f04a2 --- /dev/null +++ b/app/client/src/git/hooks/useProtectedMode.ts @@ -0,0 +1,8 @@ +import { selectProtectedMode } from "git/store/selectors/gitArtifactSelectors"; +import useArtifactSelector from "./useArtifactSelector"; + +export default function useProtectedMode() { + const isProtectedMode = useArtifactSelector(selectProtectedMode); + + return isProtectedMode ?? false; +} diff --git a/app/client/src/git/hooks/usePull.ts b/app/client/src/git/hooks/usePull.ts index 992866f2c277..19900c98f38e 100644 --- a/app/client/src/git/hooks/usePull.ts +++ b/app/client/src/git/hooks/usePull.ts @@ -1,26 +1,26 @@ import { useGitContext } from "git/components/GitContextProvider"; import { gitArtifactActions } from "git/store/gitArtifactSlice"; -import { selectPullState } from "git/store/selectors/gitSingleArtifactSelectors"; -import type { GitRootState } from "git/store/types"; +import { selectPullState } from "git/store/selectors/gitArtifactSelectors"; import { useCallback } from "react"; -import { useDispatch, useSelector } from "react-redux"; +import { useDispatch } from "react-redux"; +import useArtifactSelector from "./useArtifactSelector"; export default function usePull() { const { artifact, artifactDef } = useGitContext(); const artifactId = artifact?.id; const dispatch = useDispatch(); - const pullState = useSelector((state: GitRootState) => - selectPullState(state, artifactDef), - ); + const pullState = useArtifactSelector(selectPullState); const pull = useCallback(() => { - dispatch( - gitArtifactActions.pullInit({ - ...artifactDef, - artifactId: artifactId ?? "", - }), - ); + if (artifactDef) { + dispatch( + gitArtifactActions.pullInit({ + artifactDef, + artifactId: artifactId ?? "", + }), + ); + } }, [artifactDef, artifactId, dispatch]); return { diff --git a/app/client/src/git/hooks/useSSHKey.ts b/app/client/src/git/hooks/useSSHKey.ts new file mode 100644 index 000000000000..93c95ade8d31 --- /dev/null +++ b/app/client/src/git/hooks/useSSHKey.ts @@ -0,0 +1,63 @@ +import { useGitContext } from "git/components/GitContextProvider"; +import { gitArtifactActions } from "git/store/gitArtifactSlice"; +import { + selectFetchSSHKeysState, + selectGenerateSSHKeyState, +} from "git/store/selectors/gitArtifactSelectors"; +import { useCallback } from "react"; +import { useDispatch } from "react-redux"; +import useArtifactSelector from "./useArtifactSelector"; + +export default function useSSHKey() { + const { artifactDef } = useGitContext(); + + const dispatch = useDispatch(); + + const fetchSSHKeyState = useArtifactSelector(selectFetchSSHKeysState); + + const fetchSSHKey = useCallback(() => { + if (artifactDef) { + dispatch(gitArtifactActions.fetchSSHKeyInit({ artifactDef })); + } + }, [artifactDef, dispatch]); + + const resetFetchSSHKey = useCallback(() => { + if (artifactDef) { + dispatch(gitArtifactActions.resetFetchSSHKey({ artifactDef })); + } + }, [artifactDef, dispatch]); + + const generateSSHKeyState = useArtifactSelector(selectGenerateSSHKeyState); + + const generateSSHKey = useCallback( + (keyType: string) => { + if (artifactDef) { + dispatch( + gitArtifactActions.generateSSHKeyInit({ + artifactDef, + keyType, + }), + ); + } + }, + [artifactDef, dispatch], + ); + + const resetGenerateSSHKey = useCallback(() => { + if (artifactDef) { + dispatch(gitArtifactActions.resetGenerateSSHKey({ artifactDef })); + } + }, [artifactDef, dispatch]); + + return { + sshKey: fetchSSHKeyState?.value ?? null, + isFetchSSHKeyLoading: fetchSSHKeyState?.loading ?? false, + fetchSSHKeyError: fetchSSHKeyState?.error ?? null, + fetchSSHKey, + resetFetchSSHKey, + isGenerateSSHKeyLoading: generateSSHKeyState?.loading ?? false, + generateSSHKeyError: generateSSHKeyState?.error ?? null, + generateSSHKey, + resetGenerateSSHKey, + }; +} diff --git a/app/client/src/git/hooks/useSettings.ts b/app/client/src/git/hooks/useSettings.ts index d94f9c0e530b..0a8b48aa368c 100644 --- a/app/client/src/git/hooks/useSettings.ts +++ b/app/client/src/git/hooks/useSettings.ts @@ -4,39 +4,37 @@ import { gitArtifactActions } from "git/store/gitArtifactSlice"; import { selectSettingsModalOpen, selectSettingsModalTab, -} from "git/store/selectors/gitSingleArtifactSelectors"; -import type { GitRootState } from "git/store/types"; +} from "git/store/selectors/gitArtifactSelectors"; import { useCallback } from "react"; -import { useDispatch, useSelector } from "react-redux"; +import { useDispatch } from "react-redux"; +import useArtifactSelector from "./useArtifactSelector"; export default function useSettings() { const { artifactDef } = useGitContext(); const dispatch = useDispatch(); - const settingsModalOpen = useSelector((state: GitRootState) => - selectSettingsModalOpen(state, artifactDef), - ); + const settingsModalOpen = useArtifactSelector(selectSettingsModalOpen); - const settingsModalTab = useSelector((state: GitRootState) => - selectSettingsModalTab(state, artifactDef), - ); + const settingsModalTab = useArtifactSelector(selectSettingsModalTab); const toggleSettingsModal = useCallback( ( open: boolean, tab: keyof typeof GitSettingsTab = GitSettingsTab.General, ) => { - dispatch( - gitArtifactActions.toggleSettingsModal({ ...artifactDef, open, tab }), - ); + if (artifactDef) { + dispatch( + gitArtifactActions.toggleSettingsModal({ artifactDef, open, tab }), + ); + } }, [artifactDef, dispatch], ); return { isSettingsModalOpen: settingsModalOpen ?? false, - settingsModalTab: settingsModalTab ?? GitSettingsTab.General, + settingsModalTab: settingsModalTab, toggleSettingsModal, }; } diff --git a/app/client/src/git/hooks/useStatus.ts b/app/client/src/git/hooks/useStatus.ts index 97b09b57498a..37a5584911aa 100644 --- a/app/client/src/git/hooks/useStatus.ts +++ b/app/client/src/git/hooks/useStatus.ts @@ -1,31 +1,33 @@ import { useGitContext } from "git/components/GitContextProvider"; import { gitArtifactActions } from "git/store/gitArtifactSlice"; -import { selectStatusState } from "git/store/selectors/gitSingleArtifactSelectors"; -import type { GitRootState } from "git/store/types"; +import { selectStatusState } from "git/store/selectors/gitArtifactSelectors"; import { useCallback } from "react"; -import { useDispatch, useSelector } from "react-redux"; +import { useDispatch } from "react-redux"; +import useArtifactSelector from "./useArtifactSelector"; export default function useStatus() { - const { artifactDef } = useGitContext(); + const { artifact, artifactDef } = useGitContext(); + const artifactId = artifact?.id; const dispatch = useDispatch(); - const statusState = useSelector((state: GitRootState) => - selectStatusState(state, artifactDef), - ); + const statusState = useArtifactSelector(selectStatusState); const fetchStatus = useCallback(() => { - dispatch( - gitArtifactActions.fetchStatusInit({ - ...artifactDef, - compareRemote: true, - }), - ); - }, [artifactDef, dispatch]); + if (artifactDef && artifactId) { + dispatch( + gitArtifactActions.fetchStatusInit({ + artifactId, + artifactDef, + compareRemote: true, + }), + ); + } + }, [artifactDef, artifactId, dispatch]); return { - status: statusState?.value, + status: statusState?.value ?? null, isFetchStatusLoading: statusState?.loading ?? false, - fetchStatusError: statusState?.error, + fetchStatusError: statusState?.error ?? null, fetchStatus, }; } diff --git a/app/client/src/git/index.ts b/app/client/src/git/index.ts new file mode 100644 index 000000000000..892ca77d7f43 --- /dev/null +++ b/app/client/src/git/index.ts @@ -0,0 +1,39 @@ +// enums +export { GitArtifactType, GitOpsTab } from "./constants/enums"; + +// components +export { default as GitContextProvider } from "./components/GitContextProvider"; +export { default as GitModals } from "./ee/components/GitModals"; +export { default as GitImportModal } from "./components/ImportModal"; +export { default as GitQuickActions } from "./components/QuickActions"; +export { default as GitProtectedBranchCallout } from "./components/ProtectedBranchCallout"; +export { default as GitGlobalProfile } from "./components/GlobalProfile"; +export { default as GitDeployMenuItems } from "./components/DeployMenuItems"; + +// hooks +export { default as useGitCurrentBranch } from "./hooks/useCurrentBranch"; +export { default as useGitProtectedMode } from "./hooks/useProtectedMode"; +export { default as useGitConnected } from "./hooks/useConnected"; +export { default as useGitOps } from "./hooks/useOps"; + +// actions +import { gitGlobalActions } from "./store/gitGlobalSlice"; +export const fetchGitGlobalProfile = gitGlobalActions.fetchGlobalProfileInit; +export const toggleGitImportModal = gitGlobalActions.toggleImportModal; + +import { gitArtifactActions } from "./store/gitArtifactSlice"; +export const gitConnectSuccess = gitArtifactActions.connectSuccess; + +// selectors +export { + selectCurrentBranch as selectGitCurrentBranch, + selectProtectedMode as selectGitProtectedMode, +} from "./store/selectors/gitArtifactSelectors"; + +// types +export type { + GitArtifactDef, + GitArtifactRootReduxState, + GitGlobalReduxState, +} from "./store/types"; +export type { ConnectSuccessPayload as GitConnectSuccessPayload } from "./store/actions/connectActions"; diff --git a/app/client/src/git/requests/connectRequest.types.ts b/app/client/src/git/requests/connectRequest.types.ts index 7e31cf32bf82..d47cc4114b21 100644 --- a/app/client/src/git/requests/connectRequest.types.ts +++ b/app/client/src/git/requests/connectRequest.types.ts @@ -1,4 +1,5 @@ import type { ApiResponse } from "api/types"; +import type { ApplicationPayload } from "entities/Application"; export interface ConnectRequestParams { remoteUrl: string; @@ -9,20 +10,6 @@ export interface ConnectRequestParams { }; } -export interface ConnectResponseData { - id: string; - baseId: string; - gitApplicationMetadata: { - branchName: string; - browserSupportedRemoteUrl: string; - defaultApplicationId: string; - defaultArtifactId: string; - defaultBranchName: string; - isRepoPrivate: boolean; - lastCommitedAt: string; - remoteUrl: string; - repoName: string; - }; -} +export interface ConnectResponseData extends ApplicationPayload {} export type ConnectResponse = ApiResponse; diff --git a/app/client/src/git/requests/disconnectRequest.types.ts b/app/client/src/git/requests/disconnectRequest.types.ts index 2cbf5969ccca..b1cd5827d951 100644 --- a/app/client/src/git/requests/disconnectRequest.types.ts +++ b/app/client/src/git/requests/disconnectRequest.types.ts @@ -1,7 +1,6 @@ import type { ApiResponse } from "api/types"; +import type { ApplicationPayload } from "entities/Application"; -export interface DisconnectResponseData { - [key: string]: string; -} +export interface DisconnectResponseData extends ApplicationPayload {} export type DisconnectResponse = ApiResponse; diff --git a/app/client/src/git/requests/fetchGlobalSSHKeyRequest.ts b/app/client/src/git/requests/fetchGlobalSSHKeyRequest.ts new file mode 100644 index 000000000000..00d900637f42 --- /dev/null +++ b/app/client/src/git/requests/fetchGlobalSSHKeyRequest.ts @@ -0,0 +1,15 @@ +import type { AxiosPromise } from "axios"; +import { GIT_BASE_URL } from "./constants"; +import Api from "api/Api"; +import type { + FetchGlobalSSHKeyRequestParams, + FetchGlobalSSHKeyResponse, +} from "./fetchGlobalSSHKeyRequest.types"; + +export default async function fetchGlobalSSHKeyRequest( + params: FetchGlobalSSHKeyRequestParams, +): AxiosPromise { + const url = `${GIT_BASE_URL}/import/keys?keyType=${params.keyType}`; + + return Api.get(url); +} diff --git a/app/client/src/git/requests/fetchGlobalSSHKeyRequest.types.ts b/app/client/src/git/requests/fetchGlobalSSHKeyRequest.types.ts new file mode 100644 index 000000000000..7b092ceccff2 --- /dev/null +++ b/app/client/src/git/requests/fetchGlobalSSHKeyRequest.types.ts @@ -0,0 +1,15 @@ +import type { ApiResponse } from "api/types"; + +export interface FetchGlobalSSHKeyRequestParams { + keyType: string; +} + +export interface FetchGlobalSSHKeyResponseData { + publicKey: string; + docUrl: string; + isRegeneratedKey: boolean; + regeneratedKey: boolean; +} + +export type FetchGlobalSSHKeyResponse = + ApiResponse; diff --git a/app/client/src/git/requests/fetchStatusRequest.types.ts b/app/client/src/git/requests/fetchStatusRequest.types.ts index c4400688b794..feb064d3618d 100644 --- a/app/client/src/git/requests/fetchStatusRequest.types.ts +++ b/app/client/src/git/requests/fetchStatusRequest.types.ts @@ -24,6 +24,7 @@ export interface FetchStatusResponseData { modifiedDatasources: number; modifiedJSLibs: number; modifiedJSObjects: number; + modifiedPackages: number; modifiedModuleInstances: number; modifiedModules: number; modifiedPages: number; diff --git a/app/client/src/git/requests/generateSSHKeyRequest.ts b/app/client/src/git/requests/generateSSHKeyRequest.ts index 896426347f30..b0bea4f20ff8 100644 --- a/app/client/src/git/requests/generateSSHKeyRequest.ts +++ b/app/client/src/git/requests/generateSSHKeyRequest.ts @@ -3,16 +3,14 @@ import type { GenerateSSHKeyRequestParams, GenerateSSHKeyResponse, } from "./generateSSHKeyRequest.types"; -import { APPLICATION_BASE_URL, GIT_BASE_URL } from "./constants"; +import { APPLICATION_BASE_URL } from "./constants"; import Api from "api/Api"; export default async function generateSSHKeyRequest( baseApplicationId: string, params: GenerateSSHKeyRequestParams, ): AxiosPromise { - const url = params.isImport - ? `${GIT_BASE_URL}/import/keys?keyType=${params.keyType}` - : `${APPLICATION_BASE_URL}/ssh-keypair/${baseApplicationId}?keyType=${params.keyType}`; + const url = `${APPLICATION_BASE_URL}/ssh-keypair/${baseApplicationId}?keyType=${params.keyType}`; - return params.isImport ? Api.get(url) : Api.post(url); + return Api.post(url); } diff --git a/app/client/src/git/requests/generateSSHKeyRequest.types.ts b/app/client/src/git/requests/generateSSHKeyRequest.types.ts index 45374e42d5b1..fbc4a4c0e959 100644 --- a/app/client/src/git/requests/generateSSHKeyRequest.types.ts +++ b/app/client/src/git/requests/generateSSHKeyRequest.types.ts @@ -2,7 +2,6 @@ import type { ApiResponse } from "api/types"; export interface GenerateSSHKeyRequestParams { keyType: string; - isImport: boolean; } export interface GenerateSSHKeyResponseData { diff --git a/app/client/src/git/requests/gitImportRequest.types.ts b/app/client/src/git/requests/gitImportRequest.types.ts index 9f76b379c9cc..4eb29b11a88b 100644 --- a/app/client/src/git/requests/gitImportRequest.types.ts +++ b/app/client/src/git/requests/gitImportRequest.types.ts @@ -1,4 +1,6 @@ import type { ApiResponse } from "api/types"; +import type { ApplicationResponsePayload } from "ee/api/ApplicationApi"; +import type { Datasource } from "entities/Datasource"; export interface GitImportRequestParams { remoteUrl: string; @@ -10,19 +12,9 @@ export interface GitImportRequestParams { } export interface GitImportResponseData { - id: string; - baseId: string; - gitApplicationMetadata: { - branchName: string; - browserSupportedRemoteUrl: string; - defaultApplicationId: string; - defaultArtifactId: string; - defaultBranchName: string; - isRepoPrivate: boolean; - lastCommitedAt: string; - remoteUrl: string; - repoName: string; - }; + application: ApplicationResponsePayload; + isPartialImport: boolean; + unconfiguredDatasourceList?: Datasource[]; } export type GitImportResponse = ApiResponse; diff --git a/app/client/src/git/sagas/checkoutBranchSaga.ts b/app/client/src/git/sagas/checkoutBranchSaga.ts index 34e48434626c..7fc454f36bc0 100644 --- a/app/client/src/git/sagas/checkoutBranchSaga.ts +++ b/app/client/src/git/sagas/checkoutBranchSaga.ts @@ -25,8 +25,7 @@ import { captureException } from "@sentry/react"; export default function* checkoutBranchSaga( action: GitArtifactPayloadAction, ) { - const { artifactType, baseArtifactId, branchName } = action.payload; - const basePayload = { artifactType, baseArtifactId }; + const { artifactDef, artifactId, branchName } = action.payload; let response: CheckoutBranchResponse | undefined; try { @@ -34,12 +33,12 @@ export default function* checkoutBranchSaga( branchName, }; - response = yield call(checkoutBranchRequest, baseArtifactId, params); + response = yield call(checkoutBranchRequest, artifactId, params); const isValidResponse: boolean = yield validateResponse(response); if (response && isValidResponse) { - if (artifactType === GitArtifactType.Application) { - yield put(gitArtifactActions.checkoutBranchSuccess(basePayload)); + if (artifactDef.artifactType === GitArtifactType.Application) { + yield put(gitArtifactActions.checkoutBranchSuccess({ artifactDef })); const trimmedBranch = branchName.replace(/^origin\//, ""); const destinationHref = addBranchParam(trimmedBranch); @@ -49,7 +48,7 @@ export default function* checkoutBranchSaga( yield put( gitArtifactActions.toggleBranchPopup({ - ...basePayload, + artifactDef, open: false, }), ); @@ -118,7 +117,7 @@ export default function* checkoutBranchSaga( yield put( gitArtifactActions.checkoutBranchError({ - ...basePayload, + artifactDef, error, }), ); diff --git a/app/client/src/git/sagas/commitSaga.ts b/app/client/src/git/sagas/commitSaga.ts index 159021acc145..7ebcb70b9a71 100644 --- a/app/client/src/git/sagas/commitSaga.ts +++ b/app/client/src/git/sagas/commitSaga.ts @@ -17,8 +17,7 @@ import { validateResponse } from "sagas/ErrorSagas"; export default function* commitSaga( action: GitArtifactPayloadAction, ) { - const { artifactType, baseArtifactId } = action.payload; - const basePayload = { artifactType, baseArtifactId }; + const { artifactDef, artifactId } = action.payload; let response: CommitResponse | undefined; @@ -28,20 +27,21 @@ export default function* commitSaga( doPush: action.payload.doPush, }; - response = yield call(commitRequest, baseArtifactId, params); + response = yield call(commitRequest, artifactId, params); const isValidResponse: boolean = yield validateResponse(response, false); if (isValidResponse) { - yield put(gitArtifactActions.commitSuccess(basePayload)); + yield put(gitArtifactActions.commitSuccess({ artifactDef })); yield put( gitArtifactActions.fetchStatusInit({ - ...basePayload, + artifactDef, + artifactId, compareRemote: true, }), ); - if (artifactType === GitArtifactType.Application) { + if (artifactDef.artifactType === GitArtifactType.Application) { // ! case for updating lastDeployedAt in application manually? } } @@ -52,13 +52,13 @@ export default function* commitSaga( if (error.code === GitErrorCodes.REPO_LIMIT_REACHED) { yield put( gitArtifactActions.toggleRepoLimitErrorModal({ - ...basePayload, + artifactDef, open: true, }), ); } - yield put(gitArtifactActions.commitError({ ...basePayload, error })); + yield put(gitArtifactActions.commitError({ artifactDef, error })); } else { log.error(e); captureException(e); diff --git a/app/client/src/git/sagas/connectSaga.ts b/app/client/src/git/sagas/connectSaga.ts index b13c2f6c2c2a..b6de0cdea53e 100644 --- a/app/client/src/git/sagas/connectSaga.ts +++ b/app/client/src/git/sagas/connectSaga.ts @@ -8,7 +8,7 @@ import { GitArtifactType, GitErrorCodes } from "../constants/enums"; import type { GitArtifactPayloadAction } from "../store/types"; import type { ConnectInitPayload } from "../store/actions/connectActions"; -import { call, put } from "redux-saga/effects"; +import { call, put, select } from "redux-saga/effects"; // Internal dependencies import { validateResponse } from "sagas/ErrorSagas"; @@ -17,12 +17,12 @@ import history from "utils/history"; import { addBranchParam } from "constants/routes"; import log from "loglevel"; import { captureException } from "@sentry/react"; +import { getCurrentPageId } from "selectors/editorSelectors"; export default function* connectSaga( action: GitArtifactPayloadAction, ) { - const { artifactType, baseArtifactId } = action.payload; - const basePayload = { artifactType, baseArtifactId }; + const { artifactDef } = action.payload; let response: ConnectResponse | undefined; @@ -32,34 +32,50 @@ export default function* connectSaga( gitProfile: action.payload.gitProfile, }; - response = yield call(connectRequest, baseArtifactId, params); + response = yield call(connectRequest, artifactDef.baseArtifactId, params); const isValidResponse: boolean = yield validateResponse(response, false); if (response && isValidResponse) { - yield put(gitArtifactActions.connectSuccess(basePayload)); + yield put( + gitArtifactActions.connectSuccess({ + artifactDef, + responseData: response.data, + }), + ); // needs to happen only when artifactType is application - if (artifactType === GitArtifactType.Application) { - const { branchedPageId } = action.payload; + if (artifactDef.artifactType === GitArtifactType.Application) { + const pageId: string = yield select(getCurrentPageId); - if (branchedPageId) { - yield put(fetchPageAction(branchedPageId)); - } + yield put(fetchPageAction(pageId)); + + const branch = response.data?.gitApplicationMetadata?.branchName; + + if (branch) { + const newUrl = addBranchParam(branch); - const branch = response.data.gitApplicationMetadata.branchName; - const newUrl = addBranchParam(branch); + history.replace(newUrl); + } - history.replace(newUrl); // ! case for updating lastDeployedAt in application manually? } yield put( gitArtifactActions.initGitForEditor({ - ...basePayload, + artifactDef, artifact: response.data, }), ); + yield put( + gitArtifactActions.toggleConnectModal({ artifactDef, open: false }), + ); + yield put( + gitArtifactActions.toggleConnectSuccessModal({ + artifactDef, + open: true, + }), + ); } } catch (e) { if (response && response.responseMeta.error) { @@ -68,13 +84,13 @@ export default function* connectSaga( if (GitErrorCodes.REPO_LIMIT_REACHED === error.code) { yield put( gitArtifactActions.toggleRepoLimitErrorModal({ - ...basePayload, + artifactDef, open: true, }), ); } - yield put(gitArtifactActions.connectError({ ...basePayload, error })); + yield put(gitArtifactActions.connectError({ artifactDef, error })); } else { log.error(e); captureException(e); diff --git a/app/client/src/git/sagas/createBranchSaga.ts b/app/client/src/git/sagas/createBranchSaga.ts index 7796f43d74bd..d8aa65418977 100644 --- a/app/client/src/git/sagas/createBranchSaga.ts +++ b/app/client/src/git/sagas/createBranchSaga.ts @@ -16,8 +16,8 @@ import log from "loglevel"; export default function* createBranchSaga( action: GitArtifactPayloadAction, ) { - const { artifactType, baseArtifactId } = action.payload; - const basePayload = { artifactType, baseArtifactId }; + const { artifactDef, artifactId } = action.payload; + const basePayload = { artifactDef }; let response: CreateBranchResponse | undefined; try { @@ -25,27 +25,29 @@ export default function* createBranchSaga( branchName: action.payload.branchName, }; - response = yield call(createBranchRequest, baseArtifactId, params); + response = yield call(createBranchRequest, artifactId, params); const isValidResponse: boolean = yield validateResponse(response); if (isValidResponse) { yield put(gitArtifactActions.createBranchSuccess(basePayload)); yield put( gitArtifactActions.toggleBranchPopup({ - ...basePayload, + artifactDef, open: false, }), ); yield put( gitArtifactActions.fetchBranchesInit({ - ...basePayload, + artifactDef, + artifactId, pruneBranches: true, }), ); yield put( gitArtifactActions.checkoutBranchInit({ - ...basePayload, + artifactDef, + artifactId, branchName: action.payload.branchName, }), ); @@ -56,7 +58,7 @@ export default function* createBranchSaga( yield put( gitArtifactActions.createBranchError({ - ...basePayload, + artifactDef, error, }), ); diff --git a/app/client/src/git/sagas/deleteBranchSaga.ts b/app/client/src/git/sagas/deleteBranchSaga.ts index 4f6bdde2f7fc..ecf560889f1c 100644 --- a/app/client/src/git/sagas/deleteBranchSaga.ts +++ b/app/client/src/git/sagas/deleteBranchSaga.ts @@ -16,8 +16,7 @@ import { captureException } from "@sentry/react"; export default function* deleteBranchSaga( action: GitArtifactPayloadAction, ) { - const { artifactType, baseArtifactId } = action.payload; - const basePayload = { artifactType, baseArtifactId }; + const { artifactDef, artifactId } = action.payload; let response: DeleteBranchResponse | undefined; try { @@ -25,14 +24,19 @@ export default function* deleteBranchSaga( branchName: action.payload.branchName, }; - response = yield call(deleteBranchRequest, baseArtifactId, params); + response = yield call( + deleteBranchRequest, + artifactDef.baseArtifactId, + params, + ); const isValidResponse: boolean = yield validateResponse(response); if (isValidResponse) { - yield put(gitArtifactActions.deleteBranchSuccess(basePayload)); + yield put(gitArtifactActions.deleteBranchSuccess({ artifactDef })); yield put( gitArtifactActions.fetchBranchesInit({ - ...basePayload, + artifactDef, + artifactId, pruneBranches: true, }), ); @@ -41,12 +45,7 @@ export default function* deleteBranchSaga( if (response && response.responseMeta.error) { const { error } = response.responseMeta; - yield put( - gitArtifactActions.deleteBranchError({ - ...basePayload, - error, - }), - ); + yield put(gitArtifactActions.deleteBranchError({ artifactDef, error })); } else { log.error(e); captureException(e); diff --git a/app/client/src/git/sagas/disconnectSaga.ts b/app/client/src/git/sagas/disconnectSaga.ts index 3dc25f1ff079..ef6315c25cd5 100644 --- a/app/client/src/git/sagas/disconnectSaga.ts +++ b/app/client/src/git/sagas/disconnectSaga.ts @@ -12,26 +12,30 @@ import { validateResponse } from "sagas/ErrorSagas"; import history from "utils/history"; export default function* disconnectSaga(action: GitArtifactPayloadAction) { - const { artifactType, baseArtifactId } = action.payload; - const artifactDef = { artifactType, baseArtifactId }; + const { artifactDef } = action.payload; let response: DisconnectResponse | undefined; try { - response = yield call(disconnectRequest, baseArtifactId); + response = yield call(disconnectRequest, artifactDef.baseArtifactId); const isValidResponse: boolean = yield validateResponse(response); if (response && isValidResponse) { - yield put(gitArtifactActions.disconnectSuccess(artifactDef)); + yield put(gitArtifactActions.disconnectSuccess({ artifactDef })); const url = new URL(window.location.href); url.searchParams.delete(GIT_BRANCH_QUERY_KEY); - history.push(url.toString().slice(url.origin.length)); - yield put(gitArtifactActions.closeDisconnectModal(artifactDef)); - // !case: why? - // yield put(importAppViaGitStatusReset()); + history.replace(url.toString().slice(url.origin.length)); + yield put(gitArtifactActions.unmount({ artifactDef })); + yield put( + gitArtifactActions.initGitForEditor({ + artifactDef, + artifact: response.data, + }), + ); + yield put(gitArtifactActions.closeDisconnectModal({ artifactDef })); yield put( gitArtifactActions.toggleOpsModal({ - ...artifactDef, + artifactDef, open: false, tab: GitOpsTab.Deploy, }), @@ -52,7 +56,7 @@ export default function* disconnectSaga(action: GitArtifactPayloadAction) { if (response && response.responseMeta.error) { const { error } = response.responseMeta; - yield put(gitArtifactActions.disconnectError({ ...artifactDef, error })); + yield put(gitArtifactActions.disconnectError({ artifactDef, error })); } else { log.error(e); captureException(e); diff --git a/app/client/src/git/sagas/fetchBranchesSaga.ts b/app/client/src/git/sagas/fetchBranchesSaga.ts index 465310e01a4f..5141db03e34f 100644 --- a/app/client/src/git/sagas/fetchBranchesSaga.ts +++ b/app/client/src/git/sagas/fetchBranchesSaga.ts @@ -14,8 +14,7 @@ import { captureException } from "@sentry/react"; export default function* fetchBranchesSaga( action: GitArtifactPayloadAction, ) { - const { artifactType, baseArtifactId } = action.payload; - const basePayload = { artifactType, baseArtifactId }; + const { artifactDef, artifactId } = action.payload; let response: FetchBranchesResponse | undefined; try { @@ -23,13 +22,13 @@ export default function* fetchBranchesSaga( pruneBranches: action.payload.pruneBranches, }; - response = yield call(fetchBranchesRequest, baseArtifactId, params); + response = yield call(fetchBranchesRequest, artifactId, params); const isValidResponse: boolean = yield validateResponse(response, false); if (response && isValidResponse) { yield put( gitArtifactActions.fetchBranchesSuccess({ - ...basePayload, + artifactDef, responseData: response.data, }), ); @@ -40,7 +39,7 @@ export default function* fetchBranchesSaga( yield put( gitArtifactActions.fetchBranchesError({ - ...basePayload, + artifactDef, error, }), ); diff --git a/app/client/src/git/sagas/fetchGlobalProfileSaga.ts b/app/client/src/git/sagas/fetchGlobalProfileSaga.ts index 71e7ca1a9c29..86713acf8787 100644 --- a/app/client/src/git/sagas/fetchGlobalProfileSaga.ts +++ b/app/client/src/git/sagas/fetchGlobalProfileSaga.ts @@ -1,12 +1,12 @@ import { call, put } from "redux-saga/effects"; import fetchGlobalProfileRequest from "../requests/fetchGlobalProfileRequest"; import type { FetchGlobalProfileResponse } from "../requests/fetchGlobalProfileRequest.types"; -import { gitConfigActions } from "../store/gitConfigSlice"; // internal dependencies import { validateResponse } from "sagas/ErrorSagas"; import log from "loglevel"; import { captureException } from "@sentry/react"; +import { gitGlobalActions } from "git/store/gitGlobalSlice"; export default function* fetchGlobalProfileSaga() { let response: FetchGlobalProfileResponse | undefined; @@ -18,7 +18,7 @@ export default function* fetchGlobalProfileSaga() { if (response && isValidResponse) { yield put( - gitConfigActions.fetchGlobalProfileSuccess({ + gitGlobalActions.fetchGlobalProfileSuccess({ responseData: response.data, }), ); @@ -28,7 +28,7 @@ export default function* fetchGlobalProfileSaga() { const { error } = response.responseMeta; yield put( - gitConfigActions.fetchGlobalProfileError({ + gitGlobalActions.fetchGlobalProfileError({ error, }), ); diff --git a/app/client/src/git/sagas/fetchGlobalSSHKeySaga.ts b/app/client/src/git/sagas/fetchGlobalSSHKeySaga.ts new file mode 100644 index 000000000000..e72711961844 --- /dev/null +++ b/app/client/src/git/sagas/fetchGlobalSSHKeySaga.ts @@ -0,0 +1,44 @@ +import { captureException } from "@sentry/react"; +import fetchGlobalSSHKeyRequest from "git/requests/fetchGlobalSSHKeyRequest"; +import type { + GenerateSSHKeyRequestParams, + GenerateSSHKeyResponse, +} from "git/requests/generateSSHKeyRequest.types"; +import type { FetchGlobalSSHKeyInitPayload } from "git/store/actions/fetchGlobalSSHKeyActions"; +import { gitGlobalActions } from "git/store/gitGlobalSlice"; +import type { GitArtifactPayloadAction } from "git/store/types"; +import log from "loglevel"; +import { call, put } from "redux-saga/effects"; +import { validateResponse } from "sagas/ErrorSagas"; + +export function* fetchGlobalSSHKeySaga( + action: GitArtifactPayloadAction, +) { + let response: GenerateSSHKeyResponse | undefined; + + try { + const params: GenerateSSHKeyRequestParams = { + keyType: action.payload.keyType, + }; + + response = yield call(fetchGlobalSSHKeyRequest, params); + const isValidResponse: boolean = yield validateResponse(response); + + if (response && isValidResponse) { + yield put( + gitGlobalActions.fetchGlobalSSHKeySuccess({ + responseData: response.data, + }), + ); + } + } catch (e) { + if (response && response.responseMeta.error) { + const { error } = response.responseMeta; + + yield put(gitGlobalActions.fetchGlobalSSHKeyError({ error })); + } else { + log.error(e); + captureException(e); + } + } +} diff --git a/app/client/src/git/sagas/fetchLocalProfileSaga.ts b/app/client/src/git/sagas/fetchLocalProfileSaga.ts index c568129beab9..28f24ef2198d 100644 --- a/app/client/src/git/sagas/fetchLocalProfileSaga.ts +++ b/app/client/src/git/sagas/fetchLocalProfileSaga.ts @@ -10,18 +10,17 @@ import { captureException } from "@sentry/react"; export default function* fetchLocalProfileSaga( action: GitArtifactPayloadAction, ) { - const { artifactType, baseArtifactId } = action.payload; - const basePayload = { artifactType, baseArtifactId }; + const { artifactDef } = action.payload; let response: FetchLocalProfileResponse | undefined; try { - response = yield call(fetchLocalProfileRequest, baseArtifactId); + response = yield call(fetchLocalProfileRequest, artifactDef.baseArtifactId); const isValidResponse: boolean = yield validateResponse(response); if (response && isValidResponse) { yield put( gitArtifactActions.fetchLocalProfileSuccess({ - ...basePayload, + artifactDef, responseData: response.data, }), ); @@ -31,7 +30,7 @@ export default function* fetchLocalProfileSaga( const { error } = response.responseMeta; yield put( - gitArtifactActions.fetchLocalProfileError({ ...basePayload, error }), + gitArtifactActions.fetchLocalProfileError({ artifactDef, error }), ); } else { log.error(e); diff --git a/app/client/src/git/sagas/fetchMergeStatusSaga.ts b/app/client/src/git/sagas/fetchMergeStatusSaga.ts index 684233de206d..024954b017c5 100644 --- a/app/client/src/git/sagas/fetchMergeStatusSaga.ts +++ b/app/client/src/git/sagas/fetchMergeStatusSaga.ts @@ -14,8 +14,7 @@ import { validateResponse } from "sagas/ErrorSagas"; export default function* fetchMergeStatusSaga( action: GitArtifactPayloadAction, ) { - const { artifactId, artifactType, baseArtifactId } = action.payload; - const basePayload = { artifactType, baseArtifactId }; + const { artifactDef, artifactId } = action.payload; let response: FetchMergeStatusResponse | undefined; try { @@ -30,7 +29,7 @@ export default function* fetchMergeStatusSaga( if (response && isValidResponse) { yield put( gitArtifactActions.fetchMergeStatusSuccess({ - ...basePayload, + artifactDef, responseData: response.data, }), ); @@ -40,10 +39,7 @@ export default function* fetchMergeStatusSaga( const { error } = response.responseMeta; yield put( - gitArtifactActions.fetchMergeStatusError({ - ...basePayload, - error, - }), + gitArtifactActions.fetchMergeStatusError({ artifactDef, error }), ); } else { log.error(e); diff --git a/app/client/src/git/sagas/fetchMetadataSaga.ts b/app/client/src/git/sagas/fetchMetadataSaga.ts index 3e2029b6c6b8..9f8285847ee7 100644 --- a/app/client/src/git/sagas/fetchMetadataSaga.ts +++ b/app/client/src/git/sagas/fetchMetadataSaga.ts @@ -8,18 +8,17 @@ import { call, put } from "redux-saga/effects"; import { validateResponse } from "sagas/ErrorSagas"; export default function* fetchMetadataSaga(action: GitArtifactPayloadAction) { - const { artifactType, baseArtifactId } = action.payload; - const basePayload = { artifactType, baseArtifactId }; + const { artifactDef } = action.payload; let response: FetchMetadataResponse | undefined; try { - response = yield call(fetchMetadataRequest, baseArtifactId); + response = yield call(fetchMetadataRequest, artifactDef.baseArtifactId); const isValidResponse: boolean = yield validateResponse(response, false); if (response && isValidResponse) { yield put( gitArtifactActions.fetchMetadataSuccess({ - ...basePayload, + artifactDef, responseData: response.data, }), ); @@ -30,7 +29,7 @@ export default function* fetchMetadataSaga(action: GitArtifactPayloadAction) { yield put( gitArtifactActions.fetchMetadataError({ - ...basePayload, + artifactDef, error, }), ); diff --git a/app/client/src/git/sagas/fetchProtectedBranchesSaga.ts b/app/client/src/git/sagas/fetchProtectedBranchesSaga.ts index 9c81123ea26f..62f36f8ce93c 100644 --- a/app/client/src/git/sagas/fetchProtectedBranchesSaga.ts +++ b/app/client/src/git/sagas/fetchProtectedBranchesSaga.ts @@ -10,19 +10,21 @@ import { validateResponse } from "sagas/ErrorSagas"; export default function* fetchProtectedBranchesSaga( action: GitArtifactPayloadAction, ) { - const { artifactType, baseArtifactId } = action.payload; - const basePayload = { artifactType, baseArtifactId }; + const { artifactDef } = action.payload; let response: FetchProtectedBranchesResponse | undefined; try { - response = yield call(fetchProtectedBranchesRequest, baseArtifactId); + response = yield call( + fetchProtectedBranchesRequest, + artifactDef.baseArtifactId, + ); const isValidResponse: boolean = yield validateResponse(response); if (response && isValidResponse) { yield put( gitArtifactActions.fetchProtectedBranchesSuccess({ - ...basePayload, + artifactDef, responseData: response.data, }), ); @@ -33,7 +35,7 @@ export default function* fetchProtectedBranchesSaga( yield put( gitArtifactActions.fetchProtectedBranchesError({ - ...basePayload, + artifactDef, error, }), ); diff --git a/app/client/src/git/sagas/fetchSSHKeySaga.ts b/app/client/src/git/sagas/fetchSSHKeySaga.ts index 02f797edae66..16736e92f5d1 100644 --- a/app/client/src/git/sagas/fetchSSHKeySaga.ts +++ b/app/client/src/git/sagas/fetchSSHKeySaga.ts @@ -8,18 +8,17 @@ import { call, put } from "redux-saga/effects"; import { validateResponse } from "sagas/ErrorSagas"; export function* fetchSSHKeySaga(action: GitArtifactPayloadAction) { - const { artifactType, baseArtifactId } = action.payload; - const artifactDef = { artifactType, baseArtifactId }; + const { artifactDef } = action.payload; let response: FetchSSHKeyResponse | undefined; try { - response = yield call(fetchSSHKeyRequest, baseArtifactId); + response = yield call(fetchSSHKeyRequest, artifactDef.baseArtifactId); const isValidResponse: boolean = yield validateResponse(response, false); if (response && isValidResponse) { yield put( gitArtifactActions.fetchSSHKeySuccess({ - ...artifactDef, + artifactDef, responseData: response.data, }), ); @@ -28,7 +27,7 @@ export function* fetchSSHKeySaga(action: GitArtifactPayloadAction) { if (response && response.responseMeta.error) { const { error } = response.responseMeta; - yield put(gitArtifactActions.fetchSSHKeyError({ ...artifactDef, error })); + yield put(gitArtifactActions.fetchSSHKeyError({ artifactDef, error })); } else { log.error(e); captureException(e); diff --git a/app/client/src/git/sagas/fetchStatusSaga.ts b/app/client/src/git/sagas/fetchStatusSaga.ts index 4c714a22c0da..733f18cce776 100644 --- a/app/client/src/git/sagas/fetchStatusSaga.ts +++ b/app/client/src/git/sagas/fetchStatusSaga.ts @@ -11,18 +11,17 @@ import { validateResponse } from "sagas/ErrorSagas"; export default function* fetchStatusSaga( action: GitArtifactPayloadAction, ) { - const { artifactType, baseArtifactId } = action.payload; - const basePayload = { artifactType, baseArtifactId }; + const { artifactDef, artifactId } = action.payload; let response: FetchStatusResponse | undefined; try { - response = yield call(fetchStatusRequest, baseArtifactId); + response = yield call(fetchStatusRequest, artifactId); const isValidResponse: boolean = yield validateResponse(response); if (response && isValidResponse) { yield put( gitArtifactActions.fetchStatusSuccess({ - ...basePayload, + artifactDef, responseData: response.data, }), ); @@ -33,7 +32,7 @@ export default function* fetchStatusSaga( yield put( gitArtifactActions.fetchStatusError({ - ...basePayload, + artifactDef, error, }), ); diff --git a/app/client/src/git/sagas/generateSSHKeySaga.ts b/app/client/src/git/sagas/generateSSHKeySaga.ts index 09773f9dc0d4..afbccf24b2e6 100644 --- a/app/client/src/git/sagas/generateSSHKeySaga.ts +++ b/app/client/src/git/sagas/generateSSHKeySaga.ts @@ -15,23 +15,25 @@ import { validateResponse } from "sagas/ErrorSagas"; export function* generateSSHKeySaga( action: GitArtifactPayloadAction, ) { - const { artifactType, baseArtifactId } = action.payload; - const artifactDef = { artifactType, baseArtifactId }; + const { artifactDef } = action.payload; let response: GenerateSSHKeyResponse | undefined; try { const params: GenerateSSHKeyRequestParams = { keyType: action.payload.keyType, - isImport: action.payload.isImport, }; - response = yield call(generateSSHKeyRequest, baseArtifactId, params); + response = yield call( + generateSSHKeyRequest, + artifactDef.baseArtifactId, + params, + ); const isValidResponse: boolean = yield validateResponse(response); if (response && isValidResponse) { yield put( gitArtifactActions.generateSSHKeySuccess({ - ...artifactDef, + artifactDef, responseData: response.data, }), ); @@ -43,15 +45,13 @@ export function* generateSSHKeySaga( if (GitErrorCodes.REPO_LIMIT_REACHED === error.code) { yield put( gitArtifactActions.toggleRepoLimitErrorModal({ - ...artifactDef, + artifactDef, open: true, }), ); } - yield put( - gitArtifactActions.generateSSHKeyError({ ...artifactDef, error }), - ); + yield put(gitArtifactActions.generateSSHKeyError({ artifactDef, error })); } else { log.error(e); captureException(e); diff --git a/app/client/src/git/sagas/gitImportSaga.ts b/app/client/src/git/sagas/gitImportSaga.ts new file mode 100644 index 000000000000..ecf3d718ae08 --- /dev/null +++ b/app/client/src/git/sagas/gitImportSaga.ts @@ -0,0 +1,92 @@ +import log from "loglevel"; +import { call, put, select } from "redux-saga/effects"; +import { validateResponse } from "sagas/ErrorSagas"; +import history from "utils/history"; +import { toast } from "@appsmith/ads"; +import type { PayloadAction } from "@reduxjs/toolkit"; +import { captureException } from "@sentry/react"; +import gitImportRequest from "git/requests/gitImportRequest"; +import type { GitImportResponse } from "git/requests/gitImportRequest.types"; +import type { GitImportInitPayload } from "git/store/actions/gitImportActions"; +import { gitGlobalActions } from "git/store/gitGlobalSlice"; +import { createMessage, IMPORT_APP_SUCCESSFUL } from "ee/constants/messages"; +import { builderURL } from "ee/RouteBuilder"; +import { getWorkspaceIdForImport } from "ee/selectors/applicationSelectors"; +import { showReconnectDatasourceModal } from "ee/actions/applicationActions"; +import type { Workspace } from "ee/constants/workspaceConstants"; +import { getFetchedWorkspaces } from "ee/selectors/workspaceSelectors"; + +export default function* gitImportSaga( + action: PayloadAction, +) { + const { ...params } = action.payload; + const workspaceId: string = yield select(getWorkspaceIdForImport); + + let response: GitImportResponse | undefined; + + try { + response = yield call(gitImportRequest, workspaceId, params); + const isValidResponse: boolean = yield validateResponse(response); + + if (response && isValidResponse) { + const allWorkspaces: Workspace[] = yield select(getFetchedWorkspaces); + const currentWorkspace = allWorkspaces.filter( + (el: Workspace) => el.id === workspaceId, + ); + + if (currentWorkspace.length > 0) { + const { application, isPartialImport, unconfiguredDatasourceList } = + response.data; + + yield put(gitGlobalActions.gitImportSuccess()); + yield put(gitGlobalActions.toggleImportModal({ open: false })); + + // there is configuration-missing datasources + if (isPartialImport) { + yield put( + showReconnectDatasourceModal({ + application: application, + unConfiguredDatasourceList: unconfiguredDatasourceList ?? [], + workspaceId, + }), + ); + } else { + let basePageId = ""; + + if (application.pages && application.pages.length > 0) { + const defaultPage = application.pages.find( + (eachPage) => !!eachPage.isDefault, + ); + + basePageId = defaultPage ? defaultPage.baseId : ""; + } + + const pageURL = builderURL({ + basePageId, + }); + + history.push(pageURL); + toast.show(createMessage(IMPORT_APP_SUCCESSFUL), { + kind: "success", + }); + } + } + } + } catch (e) { + // const isRepoLimitReachedError: boolean = yield call( + // handleRepoLimitReachedError, + // response, + // ); + + // if (isRepoLimitReachedError) return; + + if (response?.responseMeta?.error) { + yield put( + gitGlobalActions.gitImportError({ error: response.responseMeta.error }), + ); + } else { + log.error(e); + captureException(e); + } + } +} diff --git a/app/client/src/git/sagas/index.ts b/app/client/src/git/sagas/index.ts index 13e19bd4c9f8..61c0a0747330 100644 --- a/app/client/src/git/sagas/index.ts +++ b/app/client/src/git/sagas/index.ts @@ -8,7 +8,6 @@ import { import type { TakeableChannel } from "redux-saga"; import type { PayloadAction } from "@reduxjs/toolkit"; import { objectKeys } from "@appsmith/utils"; -import { gitConfigActions } from "../store/gitConfigSlice"; import { gitArtifactActions } from "../store/gitArtifactSlice"; import connectSaga from "./connectSaga"; import commitSaga from "./commitSaga"; @@ -37,6 +36,9 @@ import { blockingActionSagas as blockingActionSagasExtended, nonBlockingActionSagas as nonBlockingActionSagasExtended, } from "git/ee/sagas"; +import { gitGlobalActions } from "git/store/gitGlobalSlice"; +import { fetchGlobalSSHKeySaga } from "./fetchGlobalSSHKeySaga"; +import gitImportSaga from "./gitImportSaga"; const blockingActionSagas: Record< string, @@ -50,6 +52,9 @@ const blockingActionSagas: Record< [gitArtifactActions.connectInit.type]: connectSaga, [gitArtifactActions.disconnectInit.type]: disconnectSaga, + // import + [gitGlobalActions.gitImportInit.type]: gitImportSaga, + // ops [gitArtifactActions.commitInit.type]: commitSaga, [gitArtifactActions.fetchStatusInit.type]: fetchStatusSaga, @@ -65,8 +70,8 @@ const blockingActionSagas: Record< // user profiles [gitArtifactActions.fetchLocalProfileInit.type]: fetchLocalProfileSaga, [gitArtifactActions.updateLocalProfileInit.type]: updateLocalProfileSaga, - [gitConfigActions.fetchGlobalProfileInit.type]: fetchGlobalProfileSaga, - [gitConfigActions.updateGlobalProfileInit.type]: updateGlobalProfileSaga, + [gitGlobalActions.fetchGlobalProfileInit.type]: fetchGlobalProfileSaga, + [gitGlobalActions.updateGlobalProfileInit.type]: updateGlobalProfileSaga, // protected branches [gitArtifactActions.fetchProtectedBranchesInit.type]: @@ -93,6 +98,7 @@ const nonBlockingActionSagas: Record< // ssh key [gitArtifactActions.fetchSSHKeyInit.type]: fetchSSHKeySaga, [gitArtifactActions.generateSSHKeyInit.type]: generateSSHKeySaga, + [gitGlobalActions.fetchGlobalSSHKeyInit.type]: fetchGlobalSSHKeySaga, // EE ...nonBlockingActionSagasExtended, diff --git a/app/client/src/git/sagas/initGitSaga.ts b/app/client/src/git/sagas/initGitSaga.ts index aa50efce17b1..b880b1854c41 100644 --- a/app/client/src/git/sagas/initGitSaga.ts +++ b/app/client/src/git/sagas/initGitSaga.ts @@ -7,24 +7,25 @@ import { put, take } from "redux-saga/effects"; export default function* initGitForEditorSaga( action: GitArtifactPayloadAction, ) { - const { artifact, artifactType, baseArtifactId } = action.payload; - const basePayload = { artifactType, baseArtifactId }; + const { artifact, artifactDef } = action.payload; + const artifactId = artifact?.id; - yield put(gitArtifactActions.mount(basePayload)); + yield put(gitArtifactActions.mount({ artifactDef })); - if (artifactType === GitArtifactType.Application) { - if (!!artifact.gitApplicationMetadata?.remoteUrl) { - yield put(gitArtifactActions.fetchMetadataInit(basePayload)); + if (artifactId && artifactDef.artifactType === GitArtifactType.Application) { + if (!!artifact?.gitApplicationMetadata?.remoteUrl) { + yield put(gitArtifactActions.fetchMetadataInit({ artifactDef })); yield take(gitArtifactActions.fetchMetadataSuccess.type); yield put( - gitArtifactActions.triggerAutocommitInit({ - ...basePayload, - artifactId: artifact.id, - }), + gitArtifactActions.triggerAutocommitInit({ artifactDef, artifactId }), + ); + yield put( + gitArtifactActions.fetchBranchesInit({ artifactDef, artifactId }), + ); + yield put(gitArtifactActions.fetchProtectedBranchesInit({ artifactDef })); + yield put( + gitArtifactActions.fetchStatusInit({ artifactDef, artifactId }), ); - yield put(gitArtifactActions.fetchBranchesInit(basePayload)); - yield put(gitArtifactActions.fetchProtectedBranchesInit(basePayload)); - yield put(gitArtifactActions.fetchStatusInit(basePayload)); } } } diff --git a/app/client/src/git/sagas/pullSaga.ts b/app/client/src/git/sagas/pullSaga.ts index eafb4a5c098b..07347326e3e0 100644 --- a/app/client/src/git/sagas/pullSaga.ts +++ b/app/client/src/git/sagas/pullSaga.ts @@ -4,7 +4,7 @@ import type { PullResponse } from "git/requests/pullRequest.types"; import type { PullInitPayload } from "git/store/actions/pullActions"; import { gitArtifactActions } from "git/store/gitArtifactSlice"; import type { GitArtifactPayloadAction } from "git/store/types"; -import { selectCurrentBranch } from "git/store/selectors/gitSingleArtifactSelectors"; +import { selectCurrentBranch } from "git/store/selectors/gitArtifactSelectors"; // internal dependencies import { validateResponse } from "sagas/ErrorSagas"; @@ -17,8 +17,7 @@ import { captureException } from "@sentry/react"; export default function* pullSaga( action: GitArtifactPayloadAction, ) { - const { artifactId, artifactType, baseArtifactId } = action.payload; - const basePayload = { artifactType, baseArtifactId }; + const { artifactDef, artifactId } = action.payload; let response: PullResponse | undefined; try { @@ -26,12 +25,12 @@ export default function* pullSaga( const isValidResponse: boolean = yield validateResponse(response); if (response && isValidResponse) { - yield put(gitArtifactActions.pullSuccess(basePayload)); + yield put(gitArtifactActions.pullSuccess({ artifactDef })); const currentBasePageId: string = yield select(getCurrentBasePageId); const currentBranch: string = yield select( selectCurrentBranch, - basePayload, + artifactDef, ); yield put( @@ -51,7 +50,7 @@ export default function* pullSaga( // yield put(setIsGitErrorPopupVisible({ isVisible: true })); // } - yield put(gitArtifactActions.pullError({ ...basePayload, error })); + yield put(gitArtifactActions.pullError({ artifactDef, error })); } else { log.error(e); captureException(e); diff --git a/app/client/src/git/sagas/toggleAutocommitSaga.ts b/app/client/src/git/sagas/toggleAutocommitSaga.ts index cf8b0e923c67..4f97d0289543 100644 --- a/app/client/src/git/sagas/toggleAutocommitSaga.ts +++ b/app/client/src/git/sagas/toggleAutocommitSaga.ts @@ -10,24 +10,23 @@ import { validateResponse } from "sagas/ErrorSagas"; export default function* toggleAutocommitSaga( action: GitArtifactPayloadAction, ) { - const { artifactType, baseArtifactId } = action.payload; - const artifactDef = { artifactType, baseArtifactId }; + const { artifactDef } = action.payload; let response: ToggleAutocommitResponse | undefined; try { - response = yield call(toggleAutocommitRequest, baseArtifactId); + response = yield call(toggleAutocommitRequest, artifactDef.baseArtifactId); const isValidResponse: boolean = yield validateResponse(response); if (isValidResponse) { - yield put(gitArtifactActions.toggleAutocommitSuccess(artifactDef)); - yield put(gitArtifactActions.fetchMetadataInit(artifactDef)); + yield put(gitArtifactActions.toggleAutocommitSuccess({ artifactDef })); + yield put(gitArtifactActions.fetchMetadataInit({ artifactDef })); } } catch (e) { if (response && response.responseMeta.error) { const { error } = response.responseMeta; yield put( - gitArtifactActions.toggleAutocommitError({ ...artifactDef, error }), + gitArtifactActions.toggleAutocommitError({ artifactDef, error }), ); } else { log.error(e); diff --git a/app/client/src/git/sagas/triggerAutocommitSaga.ts b/app/client/src/git/sagas/triggerAutocommitSaga.ts index d0b316f594ec..6725fb0d59f9 100644 --- a/app/client/src/git/sagas/triggerAutocommitSaga.ts +++ b/app/client/src/git/sagas/triggerAutocommitSaga.ts @@ -1,8 +1,5 @@ import { triggerAutocommitSuccessAction } from "actions/gitSyncActions"; -import { - AutocommitStatusState, - type GitArtifactType, -} from "git/constants/enums"; +import { AutocommitStatusState } from "git/constants/enums"; import fetchAutocommitProgressRequest from "git/requests/fetchAutocommitProgressRequest"; import type { FetchAutocommitProgressResponse, @@ -15,8 +12,8 @@ import type { } from "git/requests/triggerAutocommitRequest.types"; import type { TriggerAutocommitInitPayload } from "git/store/actions/triggerAutocommitActions"; import { gitArtifactActions } from "git/store/gitArtifactSlice"; -import { selectAutocommitEnabled } from "git/store/selectors/gitSingleArtifactSelectors"; -import type { GitArtifactPayloadAction } from "git/store/types"; +import { selectAutocommitEnabled } from "git/store/selectors/gitArtifactSelectors"; +import type { GitArtifactDef, GitArtifactPayloadAction } from "git/store/types"; import { call, cancel, @@ -39,8 +36,7 @@ const AUTOCOMMIT_WHITELISTED_STATES = [ ]; interface PollAutocommitProgressParams { - artifactType: keyof typeof GitArtifactType; - baseArtifactId: string; + artifactDef: GitArtifactDef; artifactId: string; } @@ -57,8 +53,7 @@ function isAutocommitHappening( } function* pollAutocommitProgressSaga(params: PollAutocommitProgressParams) { - const { artifactId, artifactType, baseArtifactId } = params; - const basePayload = { artifactType, baseArtifactId }; + const { artifactDef, artifactId } = params; let triggerResponse: TriggerAutocommitResponse | undefined; try { @@ -66,14 +61,14 @@ function* pollAutocommitProgressSaga(params: PollAutocommitProgressParams) { const isValidResponse: boolean = yield validateResponse(triggerResponse); if (triggerResponse && isValidResponse) { - yield put(gitArtifactActions.triggerAutocommitSuccess(basePayload)); + yield put(gitArtifactActions.triggerAutocommitSuccess({ artifactDef })); } } catch (e) { if (triggerResponse && triggerResponse.responseMeta.error) { const { error } = triggerResponse.responseMeta; yield put( - gitArtifactActions.triggerAutocommitError({ ...basePayload, error }), + gitArtifactActions.triggerAutocommitError({ artifactDef, error }), ); } else { log.error(e); @@ -85,39 +80,47 @@ function* pollAutocommitProgressSaga(params: PollAutocommitProgressParams) { try { if (isAutocommitHappening(triggerResponse?.data)) { - yield put(gitArtifactActions.pollAutocommitProgressStart(basePayload)); + yield put( + gitArtifactActions.pollAutocommitProgressStart({ artifactDef }), + ); while (true) { - yield put(gitArtifactActions.fetchAutocommitProgressInit(basePayload)); + yield put( + gitArtifactActions.fetchAutocommitProgressInit({ artifactDef }), + ); progressResponse = yield call( fetchAutocommitProgressRequest, - baseArtifactId, + artifactDef.baseArtifactId, ); const isValidResponse: boolean = yield validateResponse(progressResponse); if (isValidResponse && !isAutocommitHappening(progressResponse?.data)) { - yield put(gitArtifactActions.pollAutocommitProgressStop(basePayload)); + yield put( + gitArtifactActions.pollAutocommitProgressStop({ artifactDef }), + ); } if (!isValidResponse) { - yield put(gitArtifactActions.pollAutocommitProgressStop(basePayload)); + yield put( + gitArtifactActions.pollAutocommitProgressStop({ artifactDef }), + ); } yield delay(AUTOCOMMIT_POLL_DELAY); } } else { - yield put(gitArtifactActions.pollAutocommitProgressStop(basePayload)); + yield put(gitArtifactActions.pollAutocommitProgressStop({ artifactDef })); } } catch (e) { - yield put(gitArtifactActions.pollAutocommitProgressStop(basePayload)); + yield put(gitArtifactActions.pollAutocommitProgressStop({ artifactDef })); if (progressResponse && progressResponse.responseMeta.error) { const { error } = progressResponse.responseMeta; yield put( gitArtifactActions.fetchAutocommitProgressError({ - ...basePayload, + artifactDef, error, }), ); @@ -131,15 +134,14 @@ function* pollAutocommitProgressSaga(params: PollAutocommitProgressParams) { export default function* triggerAutocommitSaga( action: GitArtifactPayloadAction, ) { - const { artifactId, artifactType, baseArtifactId } = action.payload; - const basePayload = { artifactType, baseArtifactId }; + const { artifactDef, artifactId } = action.payload; const isAutocommitEnabled: boolean = yield select( selectAutocommitEnabled, - basePayload, + artifactDef, ); if (isAutocommitEnabled) { - const params = { artifactType, baseArtifactId, artifactId }; + const params = { artifactDef, artifactId }; const pollTask: Task = yield fork(pollAutocommitProgressSaga, params); yield take(gitArtifactActions.pollAutocommitProgressStop.type); diff --git a/app/client/src/git/sagas/updateGlobalProfileSaga.ts b/app/client/src/git/sagas/updateGlobalProfileSaga.ts index 2ce98fe47fb4..d7466b1ed007 100644 --- a/app/client/src/git/sagas/updateGlobalProfileSaga.ts +++ b/app/client/src/git/sagas/updateGlobalProfileSaga.ts @@ -6,12 +6,12 @@ import type { UpdateGlobalProfileRequestParams, UpdateGlobalProfileResponse, } from "../requests/updateGlobalProfileRequest.types"; -import { gitConfigActions } from "../store/gitConfigSlice"; // internal dependencies import { validateResponse } from "sagas/ErrorSagas"; import log from "loglevel"; import { captureException } from "@sentry/react"; +import { gitGlobalActions } from "git/store/gitGlobalSlice"; export default function* updateGlobalProfileSaga( action: PayloadAction, @@ -29,14 +29,14 @@ export default function* updateGlobalProfileSaga( const isValidResponse: boolean = yield validateResponse(response, true); if (response && isValidResponse) { - yield put(gitConfigActions.updateGlobalProfileSuccess()); - yield put(gitConfigActions.fetchGlobalProfileInit()); + yield put(gitGlobalActions.updateGlobalProfileSuccess()); + yield put(gitGlobalActions.fetchGlobalProfileInit()); } } catch (e) { if (response && response.responseMeta.error) { const { error } = response.responseMeta; - yield put(gitConfigActions.updateGlobalProfileError({ error })); + yield put(gitGlobalActions.updateGlobalProfileError({ error })); } else { log.error(e); captureException(e); diff --git a/app/client/src/git/sagas/updateLocalProfileSaga.ts b/app/client/src/git/sagas/updateLocalProfileSaga.ts index 74579562b058..3b7253a391fe 100644 --- a/app/client/src/git/sagas/updateLocalProfileSaga.ts +++ b/app/client/src/git/sagas/updateLocalProfileSaga.ts @@ -14,8 +14,7 @@ import { captureException } from "@sentry/react"; export default function* updateLocalProfileSaga( action: GitArtifactPayloadAction, ) { - const { artifactType, baseArtifactId } = action.payload; - const basePayload = { artifactType, baseArtifactId }; + const { artifactDef } = action.payload; let response: UpdateLocalProfileResponse | undefined; try { @@ -25,20 +24,24 @@ export default function* updateLocalProfileSaga( useGlobalProfile: action.payload.useGlobalProfile, }; - response = yield call(updateLocalProfileRequest, baseArtifactId, params); + response = yield call( + updateLocalProfileRequest, + artifactDef.baseArtifactId, + params, + ); const isValidResponse: boolean = yield validateResponse(response); if (isValidResponse) { - yield put(gitArtifactActions.updateLocalProfileSuccess(basePayload)); - yield put(gitArtifactActions.fetchLocalProfileInit(basePayload)); + yield put(gitArtifactActions.updateLocalProfileSuccess({ artifactDef })); + yield put(gitArtifactActions.fetchLocalProfileInit({ artifactDef })); } } catch (e) { if (response && response.responseMeta.error) { const { error } = response.responseMeta; yield put( - gitArtifactActions.updateLocalProfileError({ ...basePayload, error }), + gitArtifactActions.updateLocalProfileError({ artifactDef, error }), ); } else { log.error(e); diff --git a/app/client/src/git/sagas/updateProtectedBranchesSaga.ts b/app/client/src/git/sagas/updateProtectedBranchesSaga.ts index 3f7bd121270e..f24b20ee9290 100644 --- a/app/client/src/git/sagas/updateProtectedBranchesSaga.ts +++ b/app/client/src/git/sagas/updateProtectedBranchesSaga.ts @@ -14,8 +14,7 @@ import { validateResponse } from "sagas/ErrorSagas"; export default function* updateProtectedBranchesSaga( action: GitArtifactPayloadAction, ) { - const { artifactType, baseArtifactId } = action.payload; - const artifactDef = { artifactType, baseArtifactId }; + const { artifactDef } = action.payload; let response: UpdateProtectedBranchesResponse | undefined; try { @@ -25,14 +24,16 @@ export default function* updateProtectedBranchesSaga( response = yield call( updateProtectedBranchesRequest, - baseArtifactId, + artifactDef.baseArtifactId, params, ); const isValidResponse: boolean = yield validateResponse(response); if (response && isValidResponse) { - yield put(gitArtifactActions.updateProtectedBranchesSuccess(artifactDef)); - yield put(gitArtifactActions.fetchProtectedBranchesInit(artifactDef)); + yield put( + gitArtifactActions.updateProtectedBranchesSuccess({ artifactDef }), + ); + yield put(gitArtifactActions.fetchProtectedBranchesInit({ artifactDef })); } } catch (e) { if (response && response.responseMeta.error) { @@ -40,7 +41,7 @@ export default function* updateProtectedBranchesSaga( yield put( gitArtifactActions.updateProtectedBranchesError({ - ...artifactDef, + artifactDef, error, }), ); diff --git a/app/client/src/git/store/actions/checkoutBranchActions.ts b/app/client/src/git/store/actions/checkoutBranchActions.ts index c771d1887e34..e9451a614d7f 100644 --- a/app/client/src/git/store/actions/checkoutBranchActions.ts +++ b/app/client/src/git/store/actions/checkoutBranchActions.ts @@ -1,12 +1,13 @@ -import { createSingleArtifactAction } from "../helpers/createSingleArtifactAction"; +import { createArtifactAction } from "../helpers/createArtifactAction"; import type { GitAsyncErrorPayload } from "../types"; import type { CheckoutBranchRequestParams } from "git/requests/checkoutBranchRequest.types"; -export interface CheckoutBranchInitPayload - extends CheckoutBranchRequestParams {} +export interface CheckoutBranchInitPayload extends CheckoutBranchRequestParams { + artifactId: string; +} export const checkoutBranchInitAction = - createSingleArtifactAction((state, action) => { + createArtifactAction((state, action) => { state.apiResponses.checkoutBranch.loading = true; state.apiResponses.checkoutBranch.error = null; state.ui.checkoutDestBranch = action.payload.branchName; @@ -14,18 +15,16 @@ export const checkoutBranchInitAction = return state; }); -export const checkoutBranchSuccessAction = createSingleArtifactAction( - (state) => { - state.apiResponses.checkoutBranch.loading = false; - state.apiResponses.checkoutBranch.error = null; - state.ui.checkoutDestBranch = null; +export const checkoutBranchSuccessAction = createArtifactAction((state) => { + state.apiResponses.checkoutBranch.loading = false; + state.apiResponses.checkoutBranch.error = null; + state.ui.checkoutDestBranch = null; - return state; - }, -); + return state; +}); export const checkoutBranchErrorAction = - createSingleArtifactAction((state, action) => { + createArtifactAction((state, action) => { const { error } = action.payload; state.apiResponses.checkoutBranch.loading = false; diff --git a/app/client/src/git/store/actions/commitActions.ts b/app/client/src/git/store/actions/commitActions.ts index 9ebb8d37db60..876463e803a9 100644 --- a/app/client/src/git/store/actions/commitActions.ts +++ b/app/client/src/git/store/actions/commitActions.ts @@ -1,10 +1,12 @@ -import { createSingleArtifactAction } from "../helpers/createSingleArtifactAction"; +import { createArtifactAction } from "../helpers/createArtifactAction"; import type { GitAsyncErrorPayload } from "../types"; import type { CommitRequestParams } from "git/requests/commitRequest.types"; -export interface CommitInitPayload extends CommitRequestParams {} +export interface CommitInitPayload extends CommitRequestParams { + artifactId: string; +} -export const commitInitAction = createSingleArtifactAction( +export const commitInitAction = createArtifactAction( (state) => { state.apiResponses.commit.loading = true; state.apiResponses.commit.error = null; @@ -13,23 +15,24 @@ export const commitInitAction = createSingleArtifactAction( }, ); -export const commitSuccessAction = createSingleArtifactAction((state) => { +export const commitSuccessAction = createArtifactAction((state) => { state.apiResponses.commit.loading = false; return state; }); -export const commitErrorAction = - createSingleArtifactAction((state, action) => { +export const commitErrorAction = createArtifactAction( + (state, action) => { const { error } = action.payload; state.apiResponses.commit.loading = false; state.apiResponses.commit.error = error; return state; - }); + }, +); -export const clearCommitErrorAction = createSingleArtifactAction((state) => { +export const clearCommitErrorAction = createArtifactAction((state) => { state.apiResponses.commit.error = null; return state; diff --git a/app/client/src/git/store/actions/connectActions.ts b/app/client/src/git/store/actions/connectActions.ts index 7fed98500000..9e5e2bcf10b1 100644 --- a/app/client/src/git/store/actions/connectActions.ts +++ b/app/client/src/git/store/actions/connectActions.ts @@ -1,12 +1,13 @@ -import { createSingleArtifactAction } from "../helpers/createSingleArtifactAction"; -import type { GitAsyncErrorPayload } from "../types"; -import type { ConnectRequestParams } from "git/requests/connectRequest.types"; +import { createArtifactAction } from "../helpers/createArtifactAction"; +import type { GitAsyncErrorPayload, GitAsyncSuccessPayload } from "../types"; +import type { + ConnectRequestParams, + ConnectResponseData, +} from "git/requests/connectRequest.types"; -export interface ConnectInitPayload extends ConnectRequestParams { - branchedPageId?: string; -} +export interface ConnectInitPayload extends ConnectRequestParams {} -export const connectInitAction = createSingleArtifactAction( +export const connectInitAction = createArtifactAction( (state) => { state.apiResponses.connect.loading = true; state.apiResponses.connect.error = null; @@ -15,18 +16,24 @@ export const connectInitAction = createSingleArtifactAction( }, ); -export const connectSuccessAction = createSingleArtifactAction((state) => { - state.apiResponses.connect.loading = false; +export interface ConnectSuccessPayload + extends GitAsyncSuccessPayload {} - return state; -}); +export const connectSuccessAction = createArtifactAction( + (state) => { + state.apiResponses.connect.loading = false; + + return state; + }, +); -export const connectErrorAction = - createSingleArtifactAction((state, action) => { +export const connectErrorAction = createArtifactAction( + (state, action) => { const { error } = action.payload; state.apiResponses.connect.loading = false; state.apiResponses.connect.error = error; return state; - }); + }, +); diff --git a/app/client/src/git/store/actions/createBranchActions.ts b/app/client/src/git/store/actions/createBranchActions.ts index be0e08445de2..010a7550888f 100644 --- a/app/client/src/git/store/actions/createBranchActions.ts +++ b/app/client/src/git/store/actions/createBranchActions.ts @@ -1,25 +1,27 @@ -import { createSingleArtifactAction } from "../helpers/createSingleArtifactAction"; +import { createArtifactAction } from "../helpers/createArtifactAction"; import type { GitAsyncErrorPayload } from "../types"; import type { CreateBranchRequestParams } from "git/requests/createBranchRequest.types"; -export interface CreateBranchInitPayload extends CreateBranchRequestParams {} +export interface CreateBranchInitPayload extends CreateBranchRequestParams { + artifactId: string; +} export const createBranchInitAction = - createSingleArtifactAction((state) => { + createArtifactAction((state) => { state.apiResponses.createBranch.loading = true; state.apiResponses.createBranch.error = null; return state; }); -export const createBranchSuccessAction = createSingleArtifactAction((state) => { +export const createBranchSuccessAction = createArtifactAction((state) => { state.apiResponses.createBranch.loading = false; return state; }); export const createBranchErrorAction = - createSingleArtifactAction((state, action) => { + createArtifactAction((state, action) => { const { error } = action.payload; state.apiResponses.createBranch.loading = false; diff --git a/app/client/src/git/store/actions/deleteBranchActions.ts b/app/client/src/git/store/actions/deleteBranchActions.ts index 09296625f0d6..0656886f39d4 100644 --- a/app/client/src/git/store/actions/deleteBranchActions.ts +++ b/app/client/src/git/store/actions/deleteBranchActions.ts @@ -1,25 +1,27 @@ -import { createSingleArtifactAction } from "../helpers/createSingleArtifactAction"; +import { createArtifactAction } from "../helpers/createArtifactAction"; import type { GitAsyncErrorPayload } from "../types"; import type { DeleteBranchRequestParams } from "../../requests/deleteBranchRequest.types"; -export interface DeleteBranchInitPayload extends DeleteBranchRequestParams {} +export interface DeleteBranchInitPayload extends DeleteBranchRequestParams { + artifactId: string; +} export const deleteBranchInitAction = - createSingleArtifactAction((state) => { + createArtifactAction((state) => { state.apiResponses.deleteBranch.loading = true; state.apiResponses.deleteBranch.error = null; return state; }); -export const deleteBranchSuccessAction = createSingleArtifactAction((state) => { +export const deleteBranchSuccessAction = createArtifactAction((state) => { state.apiResponses.deleteBranch.loading = false; return state; }); export const deleteBranchErrorAction = - createSingleArtifactAction((state, action) => { + createArtifactAction((state, action) => { const { error } = action.payload; state.apiResponses.deleteBranch.loading = false; diff --git a/app/client/src/git/store/actions/discardActions.ts b/app/client/src/git/store/actions/discardActions.ts index 35d37c0a6d0e..0f514cd0e585 100644 --- a/app/client/src/git/store/actions/discardActions.ts +++ b/app/client/src/git/store/actions/discardActions.ts @@ -1,20 +1,20 @@ -import { createSingleArtifactAction } from "../helpers/createSingleArtifactAction"; +import { createArtifactAction } from "../helpers/createArtifactAction"; import type { GitArtifactErrorPayloadAction } from "../types"; -export const discardInitAction = createSingleArtifactAction((state) => { +export const discardInitAction = createArtifactAction((state) => { state.apiResponses.discard.loading = true; state.apiResponses.discard.error = null; return state; }); -export const discardSuccessAction = createSingleArtifactAction((state) => { +export const discardSuccessAction = createArtifactAction((state) => { state.apiResponses.discard.loading = false; return state; }); -export const discardErrorAction = createSingleArtifactAction( +export const discardErrorAction = createArtifactAction( (state, action: GitArtifactErrorPayloadAction) => { const { error } = action.payload; @@ -25,7 +25,7 @@ export const discardErrorAction = createSingleArtifactAction( }, ); -export const clearDiscardErrorAction = createSingleArtifactAction((state) => { +export const clearDiscardErrorAction = createArtifactAction((state) => { state.apiResponses.discard.error = null; return state; diff --git a/app/client/src/git/store/actions/disconnectActions.ts b/app/client/src/git/store/actions/disconnectActions.ts index dba26c0de629..082aa91b7970 100644 --- a/app/client/src/git/store/actions/disconnectActions.ts +++ b/app/client/src/git/store/actions/disconnectActions.ts @@ -1,20 +1,20 @@ -import { createSingleArtifactAction } from "../helpers/createSingleArtifactAction"; +import { createArtifactAction } from "../helpers/createArtifactAction"; import type { GitArtifactErrorPayloadAction } from "../types"; -export const disconnectInitAction = createSingleArtifactAction((state) => { +export const disconnectInitAction = createArtifactAction((state) => { state.apiResponses.disconnect.loading = true; state.apiResponses.disconnect.error = null; return state; }); -export const disconnectSuccessAction = createSingleArtifactAction((state) => { +export const disconnectSuccessAction = createArtifactAction((state) => { state.apiResponses.disconnect.loading = false; return state; }); -export const disconnectErrorAction = createSingleArtifactAction( +export const disconnectErrorAction = createArtifactAction( (state, action: GitArtifactErrorPayloadAction) => { const { error } = action.payload; diff --git a/app/client/src/git/store/actions/fetchAutocommitProgressActions.ts b/app/client/src/git/store/actions/fetchAutocommitProgressActions.ts index a7d92793e4aa..bbde6e4dd649 100644 --- a/app/client/src/git/store/actions/fetchAutocommitProgressActions.ts +++ b/app/client/src/git/store/actions/fetchAutocommitProgressActions.ts @@ -1,7 +1,7 @@ import type { GitAsyncErrorPayload } from "../types"; -import { createSingleArtifactAction } from "../helpers/createSingleArtifactAction"; +import { createArtifactAction } from "../helpers/createArtifactAction"; -export const fetchAutocommitProgressInitAction = createSingleArtifactAction( +export const fetchAutocommitProgressInitAction = createArtifactAction( (state) => { state.apiResponses.autocommitProgress.loading = true; state.apiResponses.autocommitProgress.error = null; @@ -10,7 +10,7 @@ export const fetchAutocommitProgressInitAction = createSingleArtifactAction( }, ); -export const fetchAutocommitProgressSuccessAction = createSingleArtifactAction( +export const fetchAutocommitProgressSuccessAction = createArtifactAction( (state) => { state.apiResponses.autocommitProgress.loading = false; @@ -19,7 +19,7 @@ export const fetchAutocommitProgressSuccessAction = createSingleArtifactAction( ); export const fetchAutocommitProgressErrorAction = - createSingleArtifactAction((state, action) => { + createArtifactAction((state, action) => { const { error } = action.payload; state.apiResponses.autocommitProgress.loading = false; diff --git a/app/client/src/git/store/actions/fetchBranchesActions.ts b/app/client/src/git/store/actions/fetchBranchesActions.ts index e83ce0325e59..6758ad918eb0 100644 --- a/app/client/src/git/store/actions/fetchBranchesActions.ts +++ b/app/client/src/git/store/actions/fetchBranchesActions.ts @@ -3,19 +3,21 @@ import type { FetchBranchesResponseData, } from "../../requests/fetchBranchesRequest.types"; import type { GitAsyncErrorPayload, GitAsyncSuccessPayload } from "../types"; -import { createSingleArtifactAction } from "../helpers/createSingleArtifactAction"; +import { createArtifactAction } from "../helpers/createArtifactAction"; -export interface FetchBranchesInitPayload extends FetchBranchesRequestParams {} +export interface FetchBranchesInitPayload extends FetchBranchesRequestParams { + artifactId: string; +} export const fetchBranchesInitAction = - createSingleArtifactAction((state) => { + createArtifactAction((state) => { state.apiResponses.branches.loading = true; state.apiResponses.branches.error = null; return state; }); -export const fetchBranchesSuccessAction = createSingleArtifactAction< +export const fetchBranchesSuccessAction = createArtifactAction< GitAsyncSuccessPayload >((state, action) => { state.apiResponses.branches.loading = false; @@ -25,7 +27,7 @@ export const fetchBranchesSuccessAction = createSingleArtifactAction< }); export const fetchBranchesErrorAction = - createSingleArtifactAction((state, action) => { + createArtifactAction((state, action) => { const { error } = action.payload; state.apiResponses.branches.loading = false; diff --git a/app/client/src/git/store/actions/fetchGlobalProfileActions.ts b/app/client/src/git/store/actions/fetchGlobalProfileActions.ts index 7cfb2390b021..bc2d0b6b92a3 100644 --- a/app/client/src/git/store/actions/fetchGlobalProfileActions.ts +++ b/app/client/src/git/store/actions/fetchGlobalProfileActions.ts @@ -2,11 +2,11 @@ import type { FetchGlobalProfileResponseData } from "git/requests/fetchGlobalPro import type { GitAsyncSuccessPayload, GitAsyncErrorPayload, - GitConfigReduxState, + GitGlobalReduxState, } from "../types"; import type { PayloadAction } from "@reduxjs/toolkit"; -export const fetchGlobalProfileInitAction = (state: GitConfigReduxState) => { +export const fetchGlobalProfileInitAction = (state: GitGlobalReduxState) => { state.globalProfile.loading = true; state.globalProfile.error = null; @@ -14,7 +14,7 @@ export const fetchGlobalProfileInitAction = (state: GitConfigReduxState) => { }; export const fetchGlobalProfileSuccessAction = ( - state: GitConfigReduxState, + state: GitGlobalReduxState, action: PayloadAction>, ) => { state.globalProfile.loading = false; @@ -24,7 +24,7 @@ export const fetchGlobalProfileSuccessAction = ( }; export const fetchGlobalProfileErrorAction = ( - state: GitConfigReduxState, + state: GitGlobalReduxState, action: PayloadAction, ) => { const { error } = action.payload; diff --git a/app/client/src/git/store/actions/fetchGlobalSSHKeyActions.ts b/app/client/src/git/store/actions/fetchGlobalSSHKeyActions.ts new file mode 100644 index 000000000000..de9add1c5ee0 --- /dev/null +++ b/app/client/src/git/store/actions/fetchGlobalSSHKeyActions.ts @@ -0,0 +1,55 @@ +import type { + FetchGlobalSSHKeyRequestParams, + FetchGlobalSSHKeyResponseData, +} from "git/requests/fetchGlobalSSHKeyRequest.types"; +import type { + GitAsyncSuccessPayload, + GitAsyncErrorPayload, + GitGlobalReduxState, +} from "../types"; +import type { PayloadAction } from "@reduxjs/toolkit"; + +export interface FetchGlobalSSHKeyInitPayload + extends FetchGlobalSSHKeyRequestParams {} + +export const fetchGlobalSSHKeyInitAction = ( + state: GitGlobalReduxState, + // need action to better define action type + // eslint-disable-next-line @typescript-eslint/no-unused-vars + action: PayloadAction, +) => { + state.globalSSHKey.loading = true; + state.globalSSHKey.error = null; + + return state; +}; + +export const fetchGlobalSSHKeySuccessAction = ( + state: GitGlobalReduxState, + action: PayloadAction>, +) => { + state.globalSSHKey.loading = false; + state.globalSSHKey.value = action.payload.responseData; + + return state; +}; + +export const fetchGlobalSSHKeyErrorAction = ( + state: GitGlobalReduxState, + action: PayloadAction, +) => { + const { error } = action.payload; + + state.globalSSHKey.loading = false; + state.globalSSHKey.error = error; + + return state; +}; + +export const resetGlobalSSHKeyAction = (state: GitGlobalReduxState) => { + state.globalSSHKey.loading = false; + state.globalSSHKey.value = null; + state.globalSSHKey.error = null; + + return state; +}; diff --git a/app/client/src/git/store/actions/fetchLocalProfileActions.ts b/app/client/src/git/store/actions/fetchLocalProfileActions.ts index 3559a2814c35..33a62514f44c 100644 --- a/app/client/src/git/store/actions/fetchLocalProfileActions.ts +++ b/app/client/src/git/store/actions/fetchLocalProfileActions.ts @@ -3,18 +3,16 @@ import type { GitArtifactErrorPayloadAction, GitAsyncSuccessPayload, } from "../types"; -import { createSingleArtifactAction } from "../helpers/createSingleArtifactAction"; +import { createArtifactAction } from "../helpers/createArtifactAction"; -export const fetchLocalProfileInitAction = createSingleArtifactAction( - (state) => { - state.apiResponses.localProfile.loading = true; - state.apiResponses.localProfile.error = null; +export const fetchLocalProfileInitAction = createArtifactAction((state) => { + state.apiResponses.localProfile.loading = true; + state.apiResponses.localProfile.error = null; - return state; - }, -); + return state; +}); -export const fetchLocalProfileSuccessAction = createSingleArtifactAction< +export const fetchLocalProfileSuccessAction = createArtifactAction< GitAsyncSuccessPayload >((state, action) => { state.apiResponses.localProfile.loading = false; @@ -23,7 +21,7 @@ export const fetchLocalProfileSuccessAction = createSingleArtifactAction< return state; }); -export const fetchLocalProfileErrorAction = createSingleArtifactAction( +export const fetchLocalProfileErrorAction = createArtifactAction( (state, action: GitArtifactErrorPayloadAction) => { const { error } = action.payload; diff --git a/app/client/src/git/store/actions/fetchMergeStatusActions.ts b/app/client/src/git/store/actions/fetchMergeStatusActions.ts index 65ed313114cb..26b72829fadd 100644 --- a/app/client/src/git/store/actions/fetchMergeStatusActions.ts +++ b/app/client/src/git/store/actions/fetchMergeStatusActions.ts @@ -1,5 +1,5 @@ import type { GitAsyncSuccessPayload, GitAsyncErrorPayload } from "../types"; -import { createSingleArtifactAction } from "../helpers/createSingleArtifactAction"; +import { createArtifactAction } from "../helpers/createArtifactAction"; import type { FetchMergeStatusRequestParams, FetchMergeStatusResponseData, @@ -11,14 +11,14 @@ export interface FetchMergeStatusInitPayload } export const fetchMergeStatusInitAction = - createSingleArtifactAction((state) => { + createArtifactAction((state) => { state.apiResponses.mergeStatus.loading = true; state.apiResponses.mergeStatus.error = null; return state; }); -export const fetchMergeStatusSuccessAction = createSingleArtifactAction< +export const fetchMergeStatusSuccessAction = createArtifactAction< GitAsyncSuccessPayload >((state, action) => { state.apiResponses.mergeStatus.loading = false; @@ -28,7 +28,7 @@ export const fetchMergeStatusSuccessAction = createSingleArtifactAction< }); export const fetchMergeStatusErrorAction = - createSingleArtifactAction((state, action) => { + createArtifactAction((state, action) => { const { error } = action.payload; state.apiResponses.mergeStatus.loading = false; @@ -37,7 +37,7 @@ export const fetchMergeStatusErrorAction = return state; }); -export const clearMergeStatusAction = createSingleArtifactAction((state) => { +export const clearMergeStatusAction = createArtifactAction((state) => { state.apiResponses.mergeStatus.loading = false; state.apiResponses.mergeStatus.error = null; state.apiResponses.mergeStatus.value = null; diff --git a/app/client/src/git/store/actions/fetchMetadataActions.ts b/app/client/src/git/store/actions/fetchMetadataActions.ts index 176413dfbaaa..6e7a9f2f1e3d 100644 --- a/app/client/src/git/store/actions/fetchMetadataActions.ts +++ b/app/client/src/git/store/actions/fetchMetadataActions.ts @@ -1,15 +1,15 @@ import type { GitAsyncErrorPayload, GitAsyncSuccessPayload } from "../types"; -import { createSingleArtifactAction } from "../helpers/createSingleArtifactAction"; +import { createArtifactAction } from "../helpers/createArtifactAction"; import type { FetchMetadataResponseData } from "git/requests/fetchMetadataRequest.types"; -export const fetchMetadataInitAction = createSingleArtifactAction((state) => { +export const fetchMetadataInitAction = createArtifactAction((state) => { state.apiResponses.metadata.loading = true; state.apiResponses.metadata.error = null; return state; }); -export const fetchMetadataSuccessAction = createSingleArtifactAction< +export const fetchMetadataSuccessAction = createArtifactAction< GitAsyncSuccessPayload >((state, action) => { state.apiResponses.metadata.loading = false; @@ -19,7 +19,7 @@ export const fetchMetadataSuccessAction = createSingleArtifactAction< }); export const fetchMetadataErrorAction = - createSingleArtifactAction((state, action) => { + createArtifactAction((state, action) => { const { error } = action.payload; state.apiResponses.metadata.loading = false; diff --git a/app/client/src/git/store/actions/fetchProtectedBranchesActions.ts b/app/client/src/git/store/actions/fetchProtectedBranchesActions.ts index dc66ff2290c0..1ad38bf4096c 100644 --- a/app/client/src/git/store/actions/fetchProtectedBranchesActions.ts +++ b/app/client/src/git/store/actions/fetchProtectedBranchesActions.ts @@ -1,8 +1,8 @@ import type { GitAsyncSuccessPayload, GitAsyncErrorPayload } from "../types"; -import { createSingleArtifactAction } from "../helpers/createSingleArtifactAction"; +import { createArtifactAction } from "../helpers/createArtifactAction"; import type { FetchProtectedBranchesResponseData } from "git/requests/fetchProtectedBranchesRequest.types"; -export const fetchProtectedBranchesInitAction = createSingleArtifactAction( +export const fetchProtectedBranchesInitAction = createArtifactAction( (state) => { state.apiResponses.protectedBranches.loading = true; state.apiResponses.protectedBranches.error = null; @@ -11,7 +11,7 @@ export const fetchProtectedBranchesInitAction = createSingleArtifactAction( }, ); -export const fetchProtectedBranchesSuccessAction = createSingleArtifactAction< +export const fetchProtectedBranchesSuccessAction = createArtifactAction< GitAsyncSuccessPayload >((state, action) => { state.apiResponses.protectedBranches.loading = false; @@ -21,7 +21,7 @@ export const fetchProtectedBranchesSuccessAction = createSingleArtifactAction< }); export const fetchProtectedBranchesErrorAction = - createSingleArtifactAction((state, action) => { + createArtifactAction((state, action) => { const { error } = action.payload; state.apiResponses.protectedBranches.loading = false; diff --git a/app/client/src/git/store/actions/fetchSSHKeyActions.ts b/app/client/src/git/store/actions/fetchSSHKeyActions.ts index 828cf6ebcb75..386dd4643411 100644 --- a/app/client/src/git/store/actions/fetchSSHKeyActions.ts +++ b/app/client/src/git/store/actions/fetchSSHKeyActions.ts @@ -1,15 +1,15 @@ import type { GitAsyncErrorPayload, GitAsyncSuccessPayload } from "../types"; -import { createSingleArtifactAction } from "../helpers/createSingleArtifactAction"; +import { createArtifactAction } from "../helpers/createArtifactAction"; import type { FetchSSHKeyResponseData } from "git/requests/fetchSSHKeyRequest.types"; -export const fetchSSHKeyInitAction = createSingleArtifactAction((state) => { +export const fetchSSHKeyInitAction = createArtifactAction((state) => { state.apiResponses.sshKey.loading = true; state.apiResponses.sshKey.error = null; return state; }); -export const fetchSSHKeySuccessAction = createSingleArtifactAction< +export const fetchSSHKeySuccessAction = createArtifactAction< GitAsyncSuccessPayload >((state, action) => { state.apiResponses.sshKey.loading = false; @@ -20,7 +20,7 @@ export const fetchSSHKeySuccessAction = createSingleArtifactAction< }); export const fetchSSHKeyErrorAction = - createSingleArtifactAction((state, action) => { + createArtifactAction((state, action) => { const { error } = action.payload; state.apiResponses.sshKey.loading = false; @@ -29,7 +29,7 @@ export const fetchSSHKeyErrorAction = return state; }); -export const resetFetchSSHKeyAction = createSingleArtifactAction((state) => { +export const resetFetchSSHKeyAction = createArtifactAction((state) => { state.apiResponses.sshKey.loading = false; state.apiResponses.sshKey.error = null; state.apiResponses.sshKey.value = null; diff --git a/app/client/src/git/store/actions/fetchStatusActions.ts b/app/client/src/git/store/actions/fetchStatusActions.ts index 1121e368d012..47097593260b 100644 --- a/app/client/src/git/store/actions/fetchStatusActions.ts +++ b/app/client/src/git/store/actions/fetchStatusActions.ts @@ -3,19 +3,21 @@ import type { FetchStatusResponseData, } from "git/requests/fetchStatusRequest.types"; import type { GitAsyncErrorPayload, GitAsyncSuccessPayload } from "../types"; -import { createSingleArtifactAction } from "../helpers/createSingleArtifactAction"; +import { createArtifactAction } from "../helpers/createArtifactAction"; -export interface FetchStatusInitPayload extends FetchStatusRequestParams {} +export interface FetchStatusInitPayload extends FetchStatusRequestParams { + artifactId: string; +} export const fetchStatusInitAction = - createSingleArtifactAction((state) => { + createArtifactAction((state) => { state.apiResponses.status.loading = true; state.apiResponses.status.error = null; return state; }); -export const fetchStatusSuccessAction = createSingleArtifactAction< +export const fetchStatusSuccessAction = createArtifactAction< GitAsyncSuccessPayload >((state, action) => { state.apiResponses.status.loading = false; @@ -25,7 +27,7 @@ export const fetchStatusSuccessAction = createSingleArtifactAction< }); export const fetchStatusErrorAction = - createSingleArtifactAction((state, action) => { + createArtifactAction((state, action) => { const { error } = action.payload; state.apiResponses.status.loading = false; diff --git a/app/client/src/git/store/actions/generateSSHKeyActions.ts b/app/client/src/git/store/actions/generateSSHKeyActions.ts index fa70c3a1ba28..569d7d9995c2 100644 --- a/app/client/src/git/store/actions/generateSSHKeyActions.ts +++ b/app/client/src/git/store/actions/generateSSHKeyActions.ts @@ -2,21 +2,21 @@ import type { GenerateSSHKeyRequestParams, GenerateSSHKeyResponseData, } from "git/requests/generateSSHKeyRequest.types"; -import { createSingleArtifactAction } from "../helpers/createSingleArtifactAction"; +import { createArtifactAction } from "../helpers/createArtifactAction"; import type { GitAsyncErrorPayload, GitAsyncSuccessPayload } from "../types"; export interface GenerateSSHKeyInitPayload extends GenerateSSHKeyRequestParams {} export const generateSSHKeyInitAction = - createSingleArtifactAction((state) => { + createArtifactAction((state) => { state.apiResponses.generateSSHKey.loading = true; state.apiResponses.generateSSHKey.error = null; return state; }); -export const generateSSHKeySuccessAction = createSingleArtifactAction< +export const generateSSHKeySuccessAction = createArtifactAction< GitAsyncSuccessPayload >((state, action) => { state.apiResponses.generateSSHKey.loading = false; @@ -27,7 +27,7 @@ export const generateSSHKeySuccessAction = createSingleArtifactAction< }); export const generateSSHKeyErrorAction = - createSingleArtifactAction((state, action) => { + createArtifactAction((state, action) => { const { error } = action.payload; state.apiResponses.generateSSHKey.loading = false; @@ -36,7 +36,7 @@ export const generateSSHKeyErrorAction = return state; }); -export const resetGenerateSSHKeyAction = createSingleArtifactAction((state) => { +export const resetGenerateSSHKeyAction = createArtifactAction((state) => { state.apiResponses.generateSSHKey.loading = false; state.apiResponses.generateSSHKey.error = null; diff --git a/app/client/src/git/store/actions/gitImportActions.ts b/app/client/src/git/store/actions/gitImportActions.ts index 49411b55dd55..30e9c7417b2d 100644 --- a/app/client/src/git/store/actions/gitImportActions.ts +++ b/app/client/src/git/store/actions/gitImportActions.ts @@ -1,25 +1,35 @@ -import { createSingleArtifactAction } from "../helpers/createSingleArtifactAction"; -import type { GitAsyncErrorPayload } from "../types"; +import type { PayloadAction } from "@reduxjs/toolkit"; +import type { GitAsyncErrorPayload, GitGlobalReduxState } from "../types"; +import type { GitImportRequestParams } from "git/requests/gitImportRequest.types"; -export const gitImportInitAction = createSingleArtifactAction((state) => { - state.apiResponses.gitImport.loading = true; - state.apiResponses.gitImport.error = null; +export interface GitImportInitPayload extends GitImportRequestParams {} + +export const gitImportInitAction = ( + state: GitGlobalReduxState, + // need type for better import + // eslint-disable-next-line @typescript-eslint/no-unused-vars + action: PayloadAction, +) => { + state.gitImport.loading = true; + state.gitImport.error = null; return state; -}); +}; -export const gitImportSuccessAction = createSingleArtifactAction((state) => { - state.apiResponses.gitImport.loading = false; +export const gitImportSuccessAction = (state: GitGlobalReduxState) => { + state.gitImport.loading = false; return state; -}); +}; -export const gitImportErrorAction = - createSingleArtifactAction((state, action) => { - const { error } = action.payload; +export const gitImportErrorAction = ( + state: GitGlobalReduxState, + action: PayloadAction, +) => { + const { error } = action.payload; - state.apiResponses.gitImport.loading = false; - state.apiResponses.gitImport.error = error; + state.gitImport.loading = false; + state.gitImport.error = error; - return state; - }); + return state; +}; diff --git a/app/client/src/git/store/actions/initGitActions.ts b/app/client/src/git/store/actions/initGitActions.ts index d93cf955eeec..ebe588555a24 100644 --- a/app/client/src/git/store/actions/initGitActions.ts +++ b/app/client/src/git/store/actions/initGitActions.ts @@ -1,15 +1,11 @@ -import type { FetchMetadataResponseData } from "git/requests/fetchMetadataRequest.types"; -import { createSingleArtifactAction } from "../helpers/createSingleArtifactAction"; +import { createArtifactAction } from "../helpers/createArtifactAction"; +import type { ApplicationPayload } from "entities/Application"; export interface InitGitForEditorPayload { - artifact: { - id: string; - baseId: string; - gitApplicationMetadata?: Partial; - }; + artifact: ApplicationPayload | null; } export const initGitForEditorAction = - createSingleArtifactAction((state) => { + createArtifactAction((state) => { return state; }); diff --git a/app/client/src/git/store/actions/mergeActions.ts b/app/client/src/git/store/actions/mergeActions.ts index 5bb17a351ce6..0d4e67eea8fe 100644 --- a/app/client/src/git/store/actions/mergeActions.ts +++ b/app/client/src/git/store/actions/mergeActions.ts @@ -1,20 +1,20 @@ -import { createSingleArtifactAction } from "../helpers/createSingleArtifactAction"; +import { createArtifactAction } from "../helpers/createArtifactAction"; import type { GitArtifactErrorPayloadAction } from "../types"; -export const mergeInitAction = createSingleArtifactAction((state) => { +export const mergeInitAction = createArtifactAction((state) => { state.apiResponses.merge.loading = true; state.apiResponses.merge.error = null; return state; }); -export const mergeSuccessAction = createSingleArtifactAction((state) => { +export const mergeSuccessAction = createArtifactAction((state) => { state.apiResponses.merge.loading = false; return state; }); -export const mergeErrorAction = createSingleArtifactAction( +export const mergeErrorAction = createArtifactAction( (state, action: GitArtifactErrorPayloadAction) => { const { error } = action.payload; diff --git a/app/client/src/git/store/actions/mountActions.ts b/app/client/src/git/store/actions/mountActions.ts index 07a08ee2b566..8d35126d9502 100644 --- a/app/client/src/git/store/actions/mountActions.ts +++ b/app/client/src/git/store/actions/mountActions.ts @@ -1,26 +1,31 @@ import type { PayloadAction } from "@reduxjs/toolkit"; -import type { GitArtifactBasePayload, GitArtifactReduxState } from "../types"; -import { gitSingleArtifactInitialState } from "../helpers/gitSingleArtifactInitialState"; +import type { + GitArtifactBasePayload, + GitArtifactRootReduxState, +} from "../types"; +import { gitArtifactInitialState } from "../helpers/initialState"; // ! This might be removed later export const mountAction = ( - state: GitArtifactReduxState, + state: GitArtifactRootReduxState, action: PayloadAction, ) => { - const { artifactType, baseArtifactId } = action.payload; + const { artifactDef } = action.payload; + const { artifactType, baseArtifactId } = artifactDef; state[artifactType] ??= {}; - state[artifactType][baseArtifactId] ??= gitSingleArtifactInitialState; + state[artifactType][baseArtifactId] ??= gitArtifactInitialState; return state; }; export const unmountAction = ( - state: GitArtifactReduxState, + state: GitArtifactRootReduxState, action: PayloadAction, ) => { - const { artifactType, baseArtifactId } = action.payload; + const { artifactDef } = action.payload; + const { artifactType, baseArtifactId } = artifactDef; delete state?.[artifactType]?.[baseArtifactId]; diff --git a/app/client/src/git/store/actions/pullActions.ts b/app/client/src/git/store/actions/pullActions.ts index 00a0d00f2033..48d3398e18c6 100644 --- a/app/client/src/git/store/actions/pullActions.ts +++ b/app/client/src/git/store/actions/pullActions.ts @@ -1,26 +1,24 @@ -import { createSingleArtifactAction } from "../helpers/createSingleArtifactAction"; +import { createArtifactAction } from "../helpers/createArtifactAction"; import type { GitAsyncErrorPayload } from "../types"; export interface PullInitPayload { artifactId: string; } -export const pullInitAction = createSingleArtifactAction( - (state) => { - state.apiResponses.pull.loading = true; - state.apiResponses.pull.error = null; +export const pullInitAction = createArtifactAction((state) => { + state.apiResponses.pull.loading = true; + state.apiResponses.pull.error = null; - return state; - }, -); + return state; +}); -export const pullSuccessAction = createSingleArtifactAction((state) => { +export const pullSuccessAction = createArtifactAction((state) => { state.apiResponses.pull.loading = false; return state; }); -export const pullErrorAction = createSingleArtifactAction( +export const pullErrorAction = createArtifactAction( (state, action) => { const { error } = action.payload; diff --git a/app/client/src/git/store/actions/repoLimitErrorModalActions.ts b/app/client/src/git/store/actions/repoLimitErrorModalActions.ts index b1867c1d5926..a2c96bac7721 100644 --- a/app/client/src/git/store/actions/repoLimitErrorModalActions.ts +++ b/app/client/src/git/store/actions/repoLimitErrorModalActions.ts @@ -1,16 +1,14 @@ -import { createSingleArtifactAction } from "../helpers/createSingleArtifactAction"; +import { createArtifactAction } from "../helpers/createArtifactAction"; interface ToggleRepoLimitModalActionPayload { open: boolean; } export const toggleRepoLimitErrorModalAction = - createSingleArtifactAction( - (state, action) => { - const { open } = action.payload; + createArtifactAction((state, action) => { + const { open } = action.payload; - state.ui.repoLimitErrorModalOpen = open; + state.ui.repoLimitErrorModalOpen = open; - return state; - }, - ); + return state; + }); diff --git a/app/client/src/git/store/actions/toggleAutocommitActions.ts b/app/client/src/git/store/actions/toggleAutocommitActions.ts index 96721698196f..d9c700cbb457 100644 --- a/app/client/src/git/store/actions/toggleAutocommitActions.ts +++ b/app/client/src/git/store/actions/toggleAutocommitActions.ts @@ -1,24 +1,20 @@ -import { createSingleArtifactAction } from "../helpers/createSingleArtifactAction"; +import { createArtifactAction } from "../helpers/createArtifactAction"; import type { GitArtifactErrorPayloadAction } from "../types"; -export const toggleAutocommitInitAction = createSingleArtifactAction( - (state) => { - state.apiResponses.toggleAutocommit.loading = true; - state.apiResponses.toggleAutocommit.error = null; +export const toggleAutocommitInitAction = createArtifactAction((state) => { + state.apiResponses.toggleAutocommit.loading = true; + state.apiResponses.toggleAutocommit.error = null; - return state; - }, -); + return state; +}); -export const toggleAutocommitSuccessAction = createSingleArtifactAction( - (state) => { - state.apiResponses.toggleAutocommit.loading = false; +export const toggleAutocommitSuccessAction = createArtifactAction((state) => { + state.apiResponses.toggleAutocommit.loading = false; - return state; - }, -); + return state; +}); -export const toggleAutocommitErrorAction = createSingleArtifactAction( +export const toggleAutocommitErrorAction = createArtifactAction( (state, action: GitArtifactErrorPayloadAction) => { const { error } = action.payload; diff --git a/app/client/src/git/store/actions/triggerAutocommitActions.ts b/app/client/src/git/store/actions/triggerAutocommitActions.ts index 28e88ecd2f16..da8075bc347f 100644 --- a/app/client/src/git/store/actions/triggerAutocommitActions.ts +++ b/app/client/src/git/store/actions/triggerAutocommitActions.ts @@ -1,4 +1,4 @@ -import { createSingleArtifactAction } from "../helpers/createSingleArtifactAction"; +import { createArtifactAction } from "../helpers/createArtifactAction"; import type { GitAsyncErrorPayload } from "../types"; export interface TriggerAutocommitInitPayload { @@ -6,23 +6,21 @@ export interface TriggerAutocommitInitPayload { } export const triggerAutocommitInitAction = - createSingleArtifactAction((state) => { + createArtifactAction((state) => { state.apiResponses.triggerAutocommit.loading = true; state.apiResponses.triggerAutocommit.error = null; return state; }); -export const triggerAutocommitSuccessAction = createSingleArtifactAction( - (state) => { - state.apiResponses.triggerAutocommit.loading = false; +export const triggerAutocommitSuccessAction = createArtifactAction((state) => { + state.apiResponses.triggerAutocommit.loading = false; - return state; - }, -); + return state; +}); export const triggerAutocommitErrorAction = - createSingleArtifactAction((state, action) => { + createArtifactAction((state, action) => { const { error } = action.payload; state.apiResponses.triggerAutocommit.loading = false; @@ -31,7 +29,7 @@ export const triggerAutocommitErrorAction = return state; }); -export const pollAutocommitProgressStartAction = createSingleArtifactAction( +export const pollAutocommitProgressStartAction = createArtifactAction( (state) => { state.ui.autocommitPolling = true; @@ -39,7 +37,7 @@ export const pollAutocommitProgressStartAction = createSingleArtifactAction( }, ); -export const pollAutocommitProgressStopAction = createSingleArtifactAction( +export const pollAutocommitProgressStopAction = createArtifactAction( (state) => { state.ui.autocommitPolling = false; diff --git a/app/client/src/git/store/actions/uiActions.ts b/app/client/src/git/store/actions/uiActions.ts index 577d1dfa3d10..162382c3b876 100644 --- a/app/client/src/git/store/actions/uiActions.ts +++ b/app/client/src/git/store/actions/uiActions.ts @@ -1,5 +1,7 @@ import type { GitOpsTab, GitSettingsTab } from "git/constants/enums"; -import { createSingleArtifactAction } from "../helpers/createSingleArtifactAction"; +import { createArtifactAction } from "../helpers/createArtifactAction"; +import type { GitGlobalReduxState } from "../types"; +import type { PayloadAction } from "@reduxjs/toolkit"; // connect modal export interface ToggleConnectModalPayload { @@ -7,7 +9,7 @@ export interface ToggleConnectModalPayload { } export const toggleConnectModalAction = - createSingleArtifactAction((state, action) => { + createArtifactAction((state, action) => { const { open } = action.payload; state.ui.connectModalOpen = open; @@ -15,27 +17,54 @@ export const toggleConnectModalAction = return state; }); +export interface ToggleConnectSuccessModalPayload { + open: boolean; +} + +export const toggleConnectSuccessModalAction = + createArtifactAction((state, action) => { + const { open } = action.payload; + + state.ui.connectSuccessModalOpen = open; + + return state; + }); + +export interface ToggleImportModalPayload { + open: boolean; +} + +export const toggleImportModalAction = ( + state: GitGlobalReduxState, + action: PayloadAction, +) => { + const { open } = action.payload; + + state.isImportModalOpen = open; + + return state; +}; + // disconnect modal export interface OpenDisconnectModalPayload { artifactName: string; } export const openDisconnectModalAction = - createSingleArtifactAction((state, action) => { - state.ui.disconnectBaseArtifactId = action.payload.baseArtifactId; + createArtifactAction((state, action) => { + state.ui.disconnectBaseArtifactId = + action.payload.artifactDef.baseArtifactId; state.ui.disconnectArtifactName = action.payload.artifactName; return state; }); -export const closeDisconnectModalAction = createSingleArtifactAction( - (state) => { - state.ui.disconnectBaseArtifactId = null; - state.ui.disconnectArtifactName = null; +export const closeDisconnectModalAction = createArtifactAction((state) => { + state.ui.disconnectBaseArtifactId = null; + state.ui.disconnectArtifactName = null; - return state; - }, -); + return state; +}); // ops modal @@ -44,15 +73,16 @@ export interface ToggleOpsModalPayload { tab: keyof typeof GitOpsTab; } -export const toggleOpsModalAction = - createSingleArtifactAction((state, action) => { +export const toggleOpsModalAction = createArtifactAction( + (state, action) => { const { open, tab } = action.payload; state.ui.opsModalOpen = open; state.ui.opsModalTab = tab; return state; - }); + }, +); // settings modal export interface ToggleSettingsModalPayload { @@ -61,7 +91,7 @@ export interface ToggleSettingsModalPayload { } export const toggleSettingsModalAction = - createSingleArtifactAction((state, action) => { + createArtifactAction((state, action) => { const { open, tab } = action.payload; state.ui.settingsModalOpen = open; @@ -76,29 +106,28 @@ interface ToggleAutocommitDisableModalPayload { } export const toggleAutocommitDisableModalAction = - createSingleArtifactAction( - (state, action) => { - const { open } = action.payload; + createArtifactAction((state, action) => { + const { open } = action.payload; - state.ui.autocommitDisableModalOpen = open; + state.ui.autocommitDisableModalOpen = open; - return state; - }, - ); + return state; + }); // branch popup interface BranchPopupPayload { open: boolean; } -export const toggleBranchPopupAction = - createSingleArtifactAction((state, action) => { +export const toggleBranchPopupAction = createArtifactAction( + (state, action) => { const { open } = action.payload; state.ui.branchPopupOpen = open; return state; - }); + }, +); // error modals interface ToggleRepoLimitModalPayload { @@ -106,7 +135,7 @@ interface ToggleRepoLimitModalPayload { } export const toggleRepoLimitErrorModalAction = - createSingleArtifactAction((state, action) => { + createArtifactAction((state, action) => { const { open } = action.payload; state.ui.repoLimitErrorModalOpen = open; @@ -119,12 +148,10 @@ interface ToggleConflictErrorModalPayload { } export const toggleConflictErrorModalAction = - createSingleArtifactAction( - (state, action) => { - const { open } = action.payload; + createArtifactAction((state, action) => { + const { open } = action.payload; - state.ui.conflictErrorModalOpen = open; + state.ui.conflictErrorModalOpen = open; - return state; - }, - ); + return state; + }); diff --git a/app/client/src/git/store/actions/updateGlobalProfileActions.ts b/app/client/src/git/store/actions/updateGlobalProfileActions.ts index b4d25b0b57d7..3549672deb56 100644 --- a/app/client/src/git/store/actions/updateGlobalProfileActions.ts +++ b/app/client/src/git/store/actions/updateGlobalProfileActions.ts @@ -1,14 +1,14 @@ import type { UpdateGlobalProfileRequestParams } from "git/requests/updateGlobalProfileRequest.types"; -import type { GitAsyncErrorPayload, GitConfigReduxState } from "../types"; +import type { GitAsyncErrorPayload, GitGlobalReduxState } from "../types"; import type { PayloadAction } from "@reduxjs/toolkit"; export interface UpdateGlobalProfileInitPayload extends UpdateGlobalProfileRequestParams {} type UpdateGlobalProfileInitAction = ( - state: GitConfigReduxState, + state: GitGlobalReduxState, action: PayloadAction, -) => GitConfigReduxState; +) => GitGlobalReduxState; export const updateGlobalProfileInitAction: UpdateGlobalProfileInitAction = ( state, @@ -20,7 +20,7 @@ export const updateGlobalProfileInitAction: UpdateGlobalProfileInitAction = ( }; export const updateGlobalProfileSuccessAction = ( - state: GitConfigReduxState, + state: GitGlobalReduxState, ) => { state.updateGlobalProfile.loading = false; @@ -28,7 +28,7 @@ export const updateGlobalProfileSuccessAction = ( }; export const updateGlobalProfileErrorAction = ( - state: GitConfigReduxState, + state: GitGlobalReduxState, action: PayloadAction, ) => { const { error } = action.payload; diff --git a/app/client/src/git/store/actions/updateLocalProfileActions.ts b/app/client/src/git/store/actions/updateLocalProfileActions.ts index 717bb388cb9b..84ac561a5026 100644 --- a/app/client/src/git/store/actions/updateLocalProfileActions.ts +++ b/app/client/src/git/store/actions/updateLocalProfileActions.ts @@ -1,4 +1,4 @@ -import { createSingleArtifactAction } from "../helpers/createSingleArtifactAction"; +import { createArtifactAction } from "../helpers/createArtifactAction"; import type { GitAsyncErrorPayload } from "../types"; import type { UpdateLocalProfileRequestParams } from "git/requests/updateLocalProfileRequest.types"; @@ -6,23 +6,21 @@ export interface UpdateLocalProfileInitPayload extends UpdateLocalProfileRequestParams {} export const updateLocalProfileInitAction = - createSingleArtifactAction((state) => { + createArtifactAction((state) => { state.apiResponses.updateLocalProfile.loading = true; state.apiResponses.updateLocalProfile.error = null; return state; }); -export const updateLocalProfileSuccessAction = createSingleArtifactAction( - (state) => { - state.apiResponses.updateLocalProfile.loading = false; +export const updateLocalProfileSuccessAction = createArtifactAction((state) => { + state.apiResponses.updateLocalProfile.loading = false; - return state; - }, -); + return state; +}); export const updateLocalProfileErrorAction = - createSingleArtifactAction((state, action) => { + createArtifactAction((state, action) => { const { error } = action.payload; state.apiResponses.updateLocalProfile.loading = false; diff --git a/app/client/src/git/store/actions/updateProtectedBranchesActions.ts b/app/client/src/git/store/actions/updateProtectedBranchesActions.ts index 6e45bf0dcca5..a19926b673f9 100644 --- a/app/client/src/git/store/actions/updateProtectedBranchesActions.ts +++ b/app/client/src/git/store/actions/updateProtectedBranchesActions.ts @@ -1,19 +1,19 @@ import type { UpdateProtectedBranchesRequestParams } from "git/requests/updateProtectedBranchesRequest.types"; -import { createSingleArtifactAction } from "../helpers/createSingleArtifactAction"; +import { createArtifactAction } from "../helpers/createArtifactAction"; import type { GitArtifactErrorPayloadAction } from "../types"; export interface UpdateProtectedBranchesInitPayload extends UpdateProtectedBranchesRequestParams {} export const updateProtectedBranchesInitAction = - createSingleArtifactAction((state) => { + createArtifactAction((state) => { state.apiResponses.updateProtectedBranches.loading = true; state.apiResponses.updateProtectedBranches.error = null; return state; }); -export const updateProtectedBranchesSuccessAction = createSingleArtifactAction( +export const updateProtectedBranchesSuccessAction = createArtifactAction( (state) => { state.apiResponses.updateProtectedBranches.loading = false; @@ -21,7 +21,7 @@ export const updateProtectedBranchesSuccessAction = createSingleArtifactAction( }, ); -export const updateProtectedBranchesErrorAction = createSingleArtifactAction( +export const updateProtectedBranchesErrorAction = createArtifactAction( (state, action: GitArtifactErrorPayloadAction) => { const { error } = action.payload; diff --git a/app/client/src/git/store/gitArtifactSlice.ts b/app/client/src/git/store/gitArtifactSlice.ts index 924785f80c76..15bbb4de65d2 100644 --- a/app/client/src/git/store/gitArtifactSlice.ts +++ b/app/client/src/git/store/gitArtifactSlice.ts @@ -1,5 +1,5 @@ import { createSlice } from "@reduxjs/toolkit"; -import type { GitArtifactReduxState } from "./types"; +import type { GitArtifactRootReduxState } from "./types"; import { mountAction, unmountAction } from "./actions/mountActions"; import { connectErrorAction, @@ -62,6 +62,7 @@ import { openDisconnectModalAction, closeDisconnectModalAction, toggleAutocommitDisableModalAction, + toggleConnectSuccessModalAction, } from "./actions/uiActions"; import { checkoutBranchErrorAction, @@ -119,11 +120,6 @@ import { disconnectInitAction, disconnectSuccessAction, } from "./actions/disconnectActions"; -import { - gitImportErrorAction, - gitImportInitAction, - gitImportSuccessAction, -} from "./actions/gitImportActions"; import { fetchSSHKeyErrorAction, fetchSSHKeyInitAction, @@ -137,7 +133,7 @@ import { resetGenerateSSHKeyAction, } from "./actions/generateSSHKeyActions"; -const initialState: GitArtifactReduxState = {}; +const initialState: GitArtifactRootReduxState = {}; export const gitArtifactSlice = createSlice({ name: "git/artifact", @@ -156,9 +152,6 @@ export const gitArtifactSlice = createSlice({ connectInit: connectInitAction, connectSuccess: connectSuccessAction, connectError: connectErrorAction, - gitImportInit: gitImportInitAction, - gitImportSuccess: gitImportSuccessAction, - gitImportError: gitImportErrorAction, fetchSSHKeyInit: fetchSSHKeyInitAction, fetchSSHKeySuccess: fetchSSHKeySuccessAction, fetchSSHKeyError: fetchSSHKeyErrorAction, @@ -171,6 +164,7 @@ export const gitArtifactSlice = createSlice({ disconnectSuccess: disconnectSuccessAction, disconnectError: disconnectErrorAction, toggleConnectModal: toggleConnectModalAction, + toggleConnectSuccessModal: toggleConnectSuccessModalAction, openDisconnectModal: openDisconnectModalAction, closeDisconnectModal: closeDisconnectModalAction, toggleRepoLimitErrorModal: toggleRepoLimitErrorModalAction, diff --git a/app/client/src/git/store/gitConfigSlice.ts b/app/client/src/git/store/gitConfigSlice.ts deleted file mode 100644 index a07a45d9730b..000000000000 --- a/app/client/src/git/store/gitConfigSlice.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { createSlice } from "@reduxjs/toolkit"; -import { - fetchGlobalProfileErrorAction, - fetchGlobalProfileInitAction, - fetchGlobalProfileSuccessAction, -} from "./actions/fetchGlobalProfileActions"; -import { - updateGlobalProfileErrorAction, - updateGlobalProfileInitAction, - updateGlobalProfileSuccessAction, -} from "./actions/updateGlobalProfileActions"; -import { gitConfigInitialState } from "./helpers/gitConfigInitialState"; - -export const gitConfigSlice = createSlice({ - name: "git/config", - initialState: gitConfigInitialState, - reducers: { - fetchGlobalProfileInit: fetchGlobalProfileInitAction, - fetchGlobalProfileSuccess: fetchGlobalProfileSuccessAction, - fetchGlobalProfileError: fetchGlobalProfileErrorAction, - updateGlobalProfileInit: updateGlobalProfileInitAction, - updateGlobalProfileSuccess: updateGlobalProfileSuccessAction, - updateGlobalProfileError: updateGlobalProfileErrorAction, - }, -}); - -export const gitConfigActions = gitConfigSlice.actions; - -export const gitConfigReducer = gitConfigSlice.reducer; diff --git a/app/client/src/git/store/gitGlobalSlice.ts b/app/client/src/git/store/gitGlobalSlice.ts new file mode 100644 index 000000000000..4a26f5d6132f --- /dev/null +++ b/app/client/src/git/store/gitGlobalSlice.ts @@ -0,0 +1,49 @@ +import { createSlice } from "@reduxjs/toolkit"; +import { + fetchGlobalProfileErrorAction, + fetchGlobalProfileInitAction, + fetchGlobalProfileSuccessAction, +} from "./actions/fetchGlobalProfileActions"; +import { + updateGlobalProfileErrorAction, + updateGlobalProfileInitAction, + updateGlobalProfileSuccessAction, +} from "./actions/updateGlobalProfileActions"; +import { gitGlobalInitialState } from "./helpers/initialState"; +import { toggleImportModalAction } from "./actions/uiActions"; +import { + gitImportErrorAction, + gitImportInitAction, + gitImportSuccessAction, +} from "./actions/gitImportActions"; +import { + fetchGlobalSSHKeyErrorAction, + fetchGlobalSSHKeyInitAction, + fetchGlobalSSHKeySuccessAction, + resetGlobalSSHKeyAction, +} from "./actions/fetchGlobalSSHKeyActions"; + +export const gitGlobalSlice = createSlice({ + name: "git/config", + initialState: gitGlobalInitialState, + reducers: { + fetchGlobalProfileInit: fetchGlobalProfileInitAction, + fetchGlobalProfileSuccess: fetchGlobalProfileSuccessAction, + fetchGlobalProfileError: fetchGlobalProfileErrorAction, + updateGlobalProfileInit: updateGlobalProfileInitAction, + updateGlobalProfileSuccess: updateGlobalProfileSuccessAction, + updateGlobalProfileError: updateGlobalProfileErrorAction, + fetchGlobalSSHKeyInit: fetchGlobalSSHKeyInitAction, + fetchGlobalSSHKeySuccess: fetchGlobalSSHKeySuccessAction, + fetchGlobalSSHKeyError: fetchGlobalSSHKeyErrorAction, + resetGlobalSSHKey: resetGlobalSSHKeyAction, + gitImportInit: gitImportInitAction, + gitImportSuccess: gitImportSuccessAction, + gitImportError: gitImportErrorAction, + toggleImportModal: toggleImportModalAction, + }, +}); + +export const gitGlobalActions = gitGlobalSlice.actions; + +export const gitGlobalReducer = gitGlobalSlice.reducer; diff --git a/app/client/src/git/store/helpers/createArtifactAction.ts b/app/client/src/git/store/helpers/createArtifactAction.ts new file mode 100644 index 000000000000..c138af710d53 --- /dev/null +++ b/app/client/src/git/store/helpers/createArtifactAction.ts @@ -0,0 +1,35 @@ +import type { + GitArtifactBasePayload, + GitArtifactPayloadAction, + GitArtifactReduxState, + GitArtifactRootReduxState, +} from "../types"; +import { gitArtifactInitialState } from "./initialState"; + +type ArtifactStateCb = ( + artifactState: GitArtifactReduxState, + action: GitArtifactPayloadAction, +) => GitArtifactReduxState; + +export const createArtifactAction = ( + artifactStateCb: ArtifactStateCb, +) => { + return ( + state: GitArtifactRootReduxState, + action: GitArtifactPayloadAction, + ) => { + const { artifactType, baseArtifactId } = action.payload.artifactDef; + + state[artifactType] ??= {}; + state[artifactType][baseArtifactId] ??= gitArtifactInitialState; + + const artifactState = state[artifactType][baseArtifactId]; + + state[artifactType][baseArtifactId] = artifactStateCb( + artifactState, + action, + ); + + return state; + }; +}; diff --git a/app/client/src/git/store/helpers/createSingleArtifactAction.ts b/app/client/src/git/store/helpers/createSingleArtifactAction.ts deleted file mode 100644 index 2e0642959be8..000000000000 --- a/app/client/src/git/store/helpers/createSingleArtifactAction.ts +++ /dev/null @@ -1,35 +0,0 @@ -import type { - GitArtifactBasePayload, - GitArtifactPayloadAction, - GitArtifactReduxState, - GitSingleArtifactReduxState, -} from "../types"; -import { gitSingleArtifactInitialState } from "./gitSingleArtifactInitialState"; - -type SingleArtifactStateCb = ( - singleArtifactState: GitSingleArtifactReduxState, - action: GitArtifactPayloadAction, -) => GitSingleArtifactReduxState; - -export const createSingleArtifactAction = ( - singleArtifactStateCb: SingleArtifactStateCb, -) => { - return ( - state: GitArtifactReduxState, - action: GitArtifactPayloadAction, - ) => { - const { artifactType, baseArtifactId } = action.payload; - - state[artifactType] ??= {}; - state[artifactType][baseArtifactId] ??= gitSingleArtifactInitialState; - - const singleArtifactState = state[artifactType][baseArtifactId]; - - state[artifactType][baseArtifactId] = singleArtifactStateCb( - singleArtifactState, - action, - ); - - return state; - }; -}; diff --git a/app/client/src/git/store/helpers/gitConfigInitialState.ts b/app/client/src/git/store/helpers/gitConfigInitialState.ts deleted file mode 100644 index 7017399dfb16..000000000000 --- a/app/client/src/git/store/helpers/gitConfigInitialState.ts +++ /dev/null @@ -1,13 +0,0 @@ -import type { GitConfigReduxState } from "../types"; - -export const gitConfigInitialState: GitConfigReduxState = { - globalProfile: { - value: null, - loading: false, - error: null, - }, - updateGlobalProfile: { - loading: false, - error: null, - }, -}; diff --git a/app/client/src/git/store/helpers/gitSingleArtifactInitialState.ts b/app/client/src/git/store/helpers/gitSingleArtifactInitialState.ts deleted file mode 100644 index b17c93a126cb..000000000000 --- a/app/client/src/git/store/helpers/gitSingleArtifactInitialState.ts +++ /dev/null @@ -1,138 +0,0 @@ -import { - gitArtifactAPIResponsesInitialState as gitArtifactAPIResponsesInitialStateExtended, - gitArtifactUIInitialState as gitArtifactUIInitialStateExtended, -} from "git/ee/store/helpers/initialState"; -import { GitOpsTab, GitSettingsTab } from "../../constants/enums"; -import type { - GitSingleArtifactAPIResponsesReduxState, - GitSingleArtifactUIReduxState, - GitSingleArtifactReduxState, -} from "../types"; - -const gitSingleArtifactInitialUIState: GitSingleArtifactUIReduxState = { - connectModalOpen: false, - disconnectBaseArtifactId: null, - disconnectArtifactName: null, - branchPopupOpen: false, - checkoutDestBranch: null, - opsModalOpen: false, - opsModalTab: GitOpsTab.Deploy, - settingsModalOpen: false, - settingsModalTab: GitSettingsTab.General, - autocommitDisableModalOpen: false, - autocommitPolling: false, - conflictErrorModalOpen: false, - repoLimitErrorModalOpen: false, - // EE - ...gitArtifactUIInitialStateExtended, -}; - -const gitSingleArtifactInitialAPIResponses: GitSingleArtifactAPIResponsesReduxState = - { - metadata: { - value: null, - loading: false, - error: null, - }, - connect: { - loading: false, - error: null, - }, - gitImport: { - loading: false, - error: null, - }, - status: { - value: null, - loading: false, - error: null, - }, - commit: { - loading: false, - error: null, - }, - pull: { - loading: false, - error: null, - }, - discard: { - loading: false, - error: null, - }, - mergeStatus: { - value: null, - loading: false, - error: null, - }, - merge: { - loading: false, - error: null, - }, - branches: { - value: null, - loading: false, - error: null, - }, - checkoutBranch: { - loading: false, - error: null, - }, - createBranch: { - loading: false, - error: null, - }, - deleteBranch: { - loading: false, - error: null, - }, - localProfile: { - value: null, - loading: false, - error: null, - }, - updateLocalProfile: { - loading: false, - error: null, - }, - disconnect: { - loading: false, - error: null, - }, - protectedBranches: { - value: null, - loading: false, - error: null, - }, - updateProtectedBranches: { - loading: false, - error: null, - }, - autocommitProgress: { - loading: false, - error: null, - }, - toggleAutocommit: { - loading: false, - error: null, - }, - triggerAutocommit: { - loading: false, - error: null, - }, - generateSSHKey: { - loading: false, - error: null, - }, - sshKey: { - value: null, - loading: false, - error: null, - }, - // EE - ...gitArtifactAPIResponsesInitialStateExtended, - }; - -export const gitSingleArtifactInitialState: GitSingleArtifactReduxState = { - ui: gitSingleArtifactInitialUIState, - apiResponses: gitSingleArtifactInitialAPIResponses, -}; diff --git a/app/client/src/git/store/helpers/initialState.ts b/app/client/src/git/store/helpers/initialState.ts new file mode 100644 index 000000000000..382833be2782 --- /dev/null +++ b/app/client/src/git/store/helpers/initialState.ts @@ -0,0 +1,157 @@ +import { + gitArtifactAPIResponsesInitialState as gitArtifactAPIResponsesInitialStateExtended, + gitArtifactUIInitialState as gitArtifactUIInitialStateExtended, +} from "git/ee/store/helpers/initialState"; +import { GitOpsTab, GitSettingsTab } from "../../constants/enums"; +import type { + GitArtifactAPIResponsesReduxState, + GitArtifactUIReduxState, + GitArtifactReduxState, + GitGlobalReduxState, +} from "../types"; + +const gitArtifactInitialUIState: GitArtifactUIReduxState = { + connectModalOpen: false, + connectSuccessModalOpen: false, + disconnectBaseArtifactId: null, + disconnectArtifactName: null, + branchPopupOpen: false, + checkoutDestBranch: null, + opsModalOpen: false, + opsModalTab: GitOpsTab.Deploy, + settingsModalOpen: false, + settingsModalTab: GitSettingsTab.General, + autocommitDisableModalOpen: false, + autocommitPolling: false, + conflictErrorModalOpen: false, + repoLimitErrorModalOpen: false, + // EE + ...gitArtifactUIInitialStateExtended, +}; + +const gitArtifactInitialAPIResponses: GitArtifactAPIResponsesReduxState = { + metadata: { + value: null, + loading: false, + error: null, + }, + connect: { + loading: false, + error: null, + }, + status: { + value: null, + loading: false, + error: null, + }, + commit: { + loading: false, + error: null, + }, + pull: { + loading: false, + error: null, + }, + discard: { + loading: false, + error: null, + }, + mergeStatus: { + value: null, + loading: false, + error: null, + }, + merge: { + loading: false, + error: null, + }, + branches: { + value: null, + loading: false, + error: null, + }, + checkoutBranch: { + loading: false, + error: null, + }, + createBranch: { + loading: false, + error: null, + }, + deleteBranch: { + loading: false, + error: null, + }, + localProfile: { + value: null, + loading: false, + error: null, + }, + updateLocalProfile: { + loading: false, + error: null, + }, + disconnect: { + loading: false, + error: null, + }, + protectedBranches: { + value: null, + loading: false, + error: null, + }, + updateProtectedBranches: { + loading: false, + error: null, + }, + autocommitProgress: { + loading: false, + error: null, + }, + toggleAutocommit: { + loading: false, + error: null, + }, + triggerAutocommit: { + loading: false, + error: null, + }, + generateSSHKey: { + loading: false, + error: null, + }, + sshKey: { + value: null, + loading: false, + error: null, + }, + // EE + ...gitArtifactAPIResponsesInitialStateExtended, +}; + +export const gitArtifactInitialState: GitArtifactReduxState = { + ui: gitArtifactInitialUIState, + apiResponses: gitArtifactInitialAPIResponses, +}; + +export const gitGlobalInitialState: GitGlobalReduxState = { + globalProfile: { + value: null, + loading: false, + error: null, + }, + updateGlobalProfile: { + loading: false, + error: null, + }, + globalSSHKey: { + value: null, + loading: false, + error: null, + }, + gitImport: { + loading: false, + error: null, + }, + isImportModalOpen: false, +}; diff --git a/app/client/src/git/store/index.ts b/app/client/src/git/store/index.ts index f5337e564f97..6d210139ada4 100644 --- a/app/client/src/git/store/index.ts +++ b/app/client/src/git/store/index.ts @@ -1,8 +1,8 @@ import { combineReducers } from "@reduxjs/toolkit"; import { gitArtifactReducer } from "./gitArtifactSlice"; -import { gitConfigReducer } from "./gitConfigSlice"; +import { gitGlobalReducer } from "./gitGlobalSlice"; export const gitReducer = combineReducers({ artifacts: gitArtifactReducer, - config: gitConfigReducer, + global: gitGlobalReducer, }); diff --git a/app/client/src/git/store/selectors/gitSingleArtifactSelectors.ts b/app/client/src/git/store/selectors/gitArtifactSelectors.ts similarity index 92% rename from app/client/src/git/store/selectors/gitSingleArtifactSelectors.ts rename to app/client/src/git/store/selectors/gitArtifactSelectors.ts index 845a2cfe41fe..5bf8267df889 100644 --- a/app/client/src/git/store/selectors/gitSingleArtifactSelectors.ts +++ b/app/client/src/git/store/selectors/gitArtifactSelectors.ts @@ -1,10 +1,4 @@ -import type { GitArtifactType } from "git/constants/enums"; -import type { GitRootState } from "../types"; - -export interface GitArtifactDef { - artifactType: keyof typeof GitArtifactType; - baseArtifactId: string; -} +import type { GitArtifactDef, GitRootState } from "../types"; export const selectGitArtifact = ( state: GitRootState, @@ -21,7 +15,7 @@ export const selectMetadataState = ( artifactDef: GitArtifactDef, ) => selectGitArtifact(state, artifactDef)?.apiResponses.metadata; -export const selectGitConnected = ( +export const selectConnected = ( state: GitRootState, artifactDef: GitArtifactDef, ) => !!selectMetadataState(state, artifactDef)?.value; @@ -32,11 +26,6 @@ export const selectConnectState = ( artifactDef: GitArtifactDef, ) => selectGitArtifact(state, artifactDef)?.apiResponses.connect; -export const selectGitImportState = ( - state: GitRootState, - artifactDef: GitArtifactDef, -) => selectGitArtifact(state, artifactDef)?.apiResponses.gitImport; - export const selectFetchSSHKeysState = ( state: GitRootState, artifactDef: GitArtifactDef, @@ -52,6 +41,11 @@ export const selectConnectModalOpen = ( artifactDef: GitArtifactDef, ) => selectGitArtifact(state, artifactDef)?.ui.connectModalOpen; +export const selectConnectSuccessModalOpen = ( + state: GitRootState, + artifactDef: GitArtifactDef, +) => selectGitArtifact(state, artifactDef)?.ui.connectSuccessModalOpen; + export const selectDisconnectState = ( state: GitRootState, artifactDef: GitArtifactDef, @@ -117,11 +111,14 @@ export const selectConflictErrorModalOpen = ( export const selectCurrentBranch = ( state: GitRootState, + // need this to preserve interface + // eslint-disable-next-line @typescript-eslint/no-unused-vars artifactDef: GitArtifactDef, ) => { - const gitMetadataState = selectMetadataState(state, artifactDef).value; - - return gitMetadataState?.branchName; + return ( + state?.ui?.applications?.currentApplication?.gitApplicationMetadata + ?.branchName ?? null + ); }; export const selectFetchBranchesState = ( @@ -220,10 +217,8 @@ export const selectProtectedMode = ( artifactDef: GitArtifactDef, ) => { const currentBranch = selectCurrentBranch(state, artifactDef); - const protectedBranches = selectFetchProtectedBranchesState( - state, - artifactDef, - ).value; + const protectedBranches = + selectFetchProtectedBranchesState(state, artifactDef)?.value ?? []; return protectedBranches?.includes(currentBranch ?? "") ?? false; }; diff --git a/app/client/src/git/store/selectors/gitConfigSelectors.ts b/app/client/src/git/store/selectors/gitConfigSelectors.ts deleted file mode 100644 index be31a23cda5e..000000000000 --- a/app/client/src/git/store/selectors/gitConfigSelectors.ts +++ /dev/null @@ -1,12 +0,0 @@ -import type { GitRootState } from "../types"; - -export const selectGitConfig = (state: GitRootState) => { - return state.git.config; -}; - -// global profile -export const selectFetchGlobalProfileState = (state: GitRootState) => - selectGitConfig(state).globalProfile; - -export const selectUpdateGlobalProfileState = (state: GitRootState) => - selectGitConfig(state).updateGlobalProfile; diff --git a/app/client/src/git/store/selectors/gitGlobalSelectors.ts b/app/client/src/git/store/selectors/gitGlobalSelectors.ts new file mode 100644 index 000000000000..1d1fdb555d0c --- /dev/null +++ b/app/client/src/git/store/selectors/gitGlobalSelectors.ts @@ -0,0 +1,21 @@ +import type { GitRootState } from "../types"; + +export const selectGitGlobal = (state: GitRootState) => { + return state.git.global; +}; + +// global profile +export const selectFetchGlobalProfileState = (state: GitRootState) => + selectGitGlobal(state).globalProfile; + +export const selectUpdateGlobalProfileState = (state: GitRootState) => + selectGitGlobal(state).updateGlobalProfile; + +export const selectImportModalOpen = (state: GitRootState) => + selectGitGlobal(state).isImportModalOpen; + +export const selectGitImportState = (state: GitRootState) => + selectGitGlobal(state).gitImport; + +export const selectFetchGlobalSSHKeyState = (state: GitRootState) => + selectGitGlobal(state).globalSSHKey; diff --git a/app/client/src/git/store/types.ts b/app/client/src/git/store/types.ts index ccb67a2e7a8b..90a2e72998a5 100644 --- a/app/client/src/git/store/types.ts +++ b/app/client/src/git/store/types.ts @@ -17,6 +17,7 @@ import type { GitArtifactAPIResponsesReduxState as GitArtifactAPIResponsesReduxStateExtended, GitArtifactUIReduxState as GitArtifactUIReduxStateExtended, } from "git/ee/store/types"; +import type { FetchGlobalSSHKeyResponseData } from "git/requests/fetchGlobalSSHKeyRequest.types"; export interface GitApiError extends ApiResponseError { errorType?: string; @@ -33,11 +34,10 @@ export interface GitAsyncStateWithoutValue { loading: boolean; error: GitApiError | null; } -export interface GitSingleArtifactAPIResponsesReduxState +export interface GitArtifactAPIResponsesReduxState extends GitArtifactAPIResponsesReduxStateExtended { metadata: GitAsyncState; connect: GitAsyncStateWithoutValue; - gitImport: GitAsyncStateWithoutValue; status: GitAsyncState; commit: GitAsyncStateWithoutValue; pull: GitAsyncStateWithoutValue; @@ -60,9 +60,10 @@ export interface GitSingleArtifactAPIResponsesReduxState generateSSHKey: GitAsyncStateWithoutValue; } -export interface GitSingleArtifactUIReduxState +export interface GitArtifactUIReduxState extends GitArtifactUIReduxStateExtended { connectModalOpen: boolean; + connectSuccessModalOpen: boolean; disconnectBaseArtifactId: string | null; disconnectArtifactName: string | null; branchPopupOpen: boolean; @@ -76,30 +77,51 @@ export interface GitSingleArtifactUIReduxState conflictErrorModalOpen: boolean; repoLimitErrorModalOpen: boolean; } -export interface GitSingleArtifactReduxState { - ui: GitSingleArtifactUIReduxState; - apiResponses: GitSingleArtifactAPIResponsesReduxState; -} +export interface GitArtifactDef { + artifactType: keyof typeof GitArtifactType; + baseArtifactId: string; +} export interface GitArtifactReduxState { - [key: string]: Record; + ui: GitArtifactUIReduxState; + apiResponses: GitArtifactAPIResponsesReduxState; } -export interface GitConfigReduxState { +export interface GitGlobalReduxState { globalProfile: GitAsyncState; updateGlobalProfile: GitAsyncStateWithoutValue; + gitImport: GitAsyncStateWithoutValue; + globalSSHKey: GitAsyncState; + // ui + isImportModalOpen: boolean; +} + +export type GitArtifactRootReduxState = Record< + string, + Record +>; + +export interface GitReduxState { + artifacts: GitArtifactRootReduxState; + global: GitGlobalReduxState; } export interface GitRootState { - git: { - artifacts: GitArtifactReduxState; - config: GitConfigReduxState; + // will have to remove this later, once metadata is fixed + ui: { + applications: { + currentApplication?: { + gitApplicationMetadata?: { + branchName: string; + }; + }; + }; }; + git: GitReduxState; } export interface GitArtifactBasePayload { - artifactType: keyof typeof GitArtifactType; - baseArtifactId: string; + artifactDef: GitArtifactDef; } export interface GitAsyncErrorPayload { diff --git a/app/client/src/layoutSystems/anvil/common/hooks/detachedWidgetHooks.ts b/app/client/src/layoutSystems/anvil/common/hooks/detachedWidgetHooks.ts index c3ad4a82bd8d..6bf86d26a55d 100644 --- a/app/client/src/layoutSystems/anvil/common/hooks/detachedWidgetHooks.ts +++ b/app/client/src/layoutSystems/anvil/common/hooks/detachedWidgetHooks.ts @@ -1,7 +1,6 @@ import { useWidgetBorderStyles } from "./useWidgetBorderStyles"; import { useDispatch, useSelector } from "react-redux"; import { useWidgetSelection } from "utils/hooks/useWidgetSelection"; -import { combinedPreviewModeSelector } from "selectors/editorSelectors"; import { SELECT_ANVIL_WIDGET_CUSTOM_EVENT } from "layoutSystems/anvil/utils/constants"; import log from "loglevel"; import { useEffect, useMemo } from "react"; @@ -9,6 +8,7 @@ import { getAnvilWidgetDOMId } from "layoutSystems/common/utils/LayoutElementPos import { getCurrentlyOpenAnvilDetachedWidgets } from "layoutSystems/anvil/integrations/modalSelectors"; import { getCanvasWidgetsStructure } from "ee/selectors/entitiesSelector"; import type { CanvasWidgetStructure } from "WidgetProvider/constants"; +import { selectCombinedPreviewMode } from "selectors/gitModSelectors"; /** * This hook is used to select and focus on a detached widget * As detached widgets are outside of the layout flow, we need to access the correct element in the DOM @@ -17,7 +17,7 @@ import type { CanvasWidgetStructure } from "WidgetProvider/constants"; */ export function useHandleDetachedWidgetSelect(widgetId: string) { const dispatch = useDispatch(); - const isPreviewMode = useSelector(combinedPreviewModeSelector); + const isPreviewMode = useSelector(selectCombinedPreviewMode); const className = getAnvilWidgetDOMId(widgetId); const element = document.querySelector(`.${className}`); diff --git a/app/client/src/layoutSystems/anvil/common/hooks/useWidgetBorderStyles.ts b/app/client/src/layoutSystems/anvil/common/hooks/useWidgetBorderStyles.ts index fea0cc19424c..1213f9134b3a 100644 --- a/app/client/src/layoutSystems/anvil/common/hooks/useWidgetBorderStyles.ts +++ b/app/client/src/layoutSystems/anvil/common/hooks/useWidgetBorderStyles.ts @@ -7,8 +7,8 @@ import { getWidgetsDistributingSpace, } from "layoutSystems/anvil/integrations/selectors"; import { useSelector } from "react-redux"; -import { combinedPreviewModeSelector } from "selectors/editorSelectors"; import { isWidgetFocused, isWidgetSelected } from "selectors/widgetSelectors"; +import { selectCombinedPreviewMode } from "selectors/gitModSelectors"; export function useWidgetBorderStyles(widgetId: string, widgetType: string) { /** Selectors */ @@ -32,7 +32,7 @@ export function useWidgetBorderStyles(widgetId: string, widgetType: string) { const widgetsEffectedBySpaceDistribution = useSelector( getWidgetsDistributingSpace, ); - const isPreviewMode = useSelector(combinedPreviewModeSelector); + const isPreviewMode = useSelector(selectCombinedPreviewMode); /** EO selectors */ diff --git a/app/client/src/layoutSystems/anvil/editor/AnvilEditorWidgetOnion.tsx b/app/client/src/layoutSystems/anvil/editor/AnvilEditorWidgetOnion.tsx index f5a6505a2be2..839c055f0f40 100644 --- a/app/client/src/layoutSystems/anvil/editor/AnvilEditorWidgetOnion.tsx +++ b/app/client/src/layoutSystems/anvil/editor/AnvilEditorWidgetOnion.tsx @@ -4,7 +4,7 @@ import type { BaseWidgetProps } from "widgets/BaseWidgetHOC/withBaseWidgetHOC"; import { AnvilWidgetComponent } from "../common/widgetComponent/AnvilWidgetComponent"; import { getWidgetSizeConfiguration } from "../utils/widgetUtils"; import { useSelector } from "react-redux"; -import { combinedPreviewModeSelector } from "selectors/editorSelectors"; +import { selectCombinedPreviewMode } from "selectors/gitModSelectors"; import { AnvilEditorFlexComponent } from "./AnvilEditorFlexComponent"; import { AnvilFlexComponent } from "../common/AnvilFlexComponent"; import { SKELETON_WIDGET_TYPE } from "constants/WidgetConstants"; @@ -25,7 +25,7 @@ import { SKELETON_WIDGET_TYPE } from "constants/WidgetConstants"; * @returns Enhanced Widget */ export const AnvilEditorWidgetOnion = (props: BaseWidgetProps) => { - const isPreviewMode = useSelector(combinedPreviewModeSelector); + const isPreviewMode = useSelector(selectCombinedPreviewMode); const { widgetSize, WidgetWrapper } = useMemo(() => { return { widgetSize: getWidgetSizeConfiguration(props.type, props, isPreviewMode), diff --git a/app/client/src/layoutSystems/anvil/editor/hooks/useAnvilWidgetHover.ts b/app/client/src/layoutSystems/anvil/editor/hooks/useAnvilWidgetHover.ts index abdb88561f68..e51d921bf1bd 100644 --- a/app/client/src/layoutSystems/anvil/editor/hooks/useAnvilWidgetHover.ts +++ b/app/client/src/layoutSystems/anvil/editor/hooks/useAnvilWidgetHover.ts @@ -2,7 +2,7 @@ import type { AppState } from "ee/reducers"; import { getAnvilSpaceDistributionStatus } from "layoutSystems/anvil/integrations/selectors"; import { useCallback, useEffect } from "react"; import { useSelector } from "react-redux"; -import { combinedPreviewModeSelector } from "selectors/editorSelectors"; +import { selectCombinedPreviewMode } from "selectors/gitModSelectors"; import { isWidgetFocused } from "selectors/widgetSelectors"; import { useWidgetSelection } from "utils/hooks/useWidgetSelection"; @@ -12,7 +12,7 @@ export const useAnvilWidgetHover = ( ) => { // Retrieve state from the Redux store const isFocused = useSelector(isWidgetFocused(widgetId)); - const isPreviewMode = useSelector(combinedPreviewModeSelector); + const isPreviewMode = useSelector(selectCombinedPreviewMode); const isDistributingSpace = useSelector(getAnvilSpaceDistributionStatus); const isDragging = useSelector( (state: AppState) => state.ui.widgetDragResize.isDragging, diff --git a/app/client/src/layoutSystems/anvil/integrations/sagas/LayoutElementPositionsSaga.ts b/app/client/src/layoutSystems/anvil/integrations/sagas/LayoutElementPositionsSaga.ts index a882919710b1..2cddcc974bc8 100644 --- a/app/client/src/layoutSystems/anvil/integrations/sagas/LayoutElementPositionsSaga.ts +++ b/app/client/src/layoutSystems/anvil/integrations/sagas/LayoutElementPositionsSaga.ts @@ -8,7 +8,7 @@ import log from "loglevel"; import type { AppState } from "ee/reducers"; import { ReduxActionTypes } from "ee/constants/ReduxActionConstants"; import { APP_MODE } from "entities/App"; -import { combinedPreviewModeSelector } from "selectors/editorSelectors"; +import { selectCombinedPreviewMode } from "selectors/gitModSelectors"; import { getAppMode } from "ee/selectors/entitiesSelector"; import type { RefObject } from "react"; import { getAnvilSpaceDistributionStatus } from "../selectors"; @@ -87,7 +87,7 @@ function* readAndUpdateLayoutElementPositions() { // The positions are used only in the editor, so we should not be running this saga // in the viewer or the preview mode. - const isPreviewMode: boolean = yield select(combinedPreviewModeSelector); + const isPreviewMode: boolean = yield select(selectCombinedPreviewMode); const appMode: APP_MODE = yield select(getAppMode); if (isPreviewMode || appMode === APP_MODE.PUBLISHED) { diff --git a/app/client/src/layoutSystems/anvil/layoutComponents/components/zone/useZoneMinWidth.ts b/app/client/src/layoutSystems/anvil/layoutComponents/components/zone/useZoneMinWidth.ts index fe49ee655230..c8ba600c5fb6 100644 --- a/app/client/src/layoutSystems/anvil/layoutComponents/components/zone/useZoneMinWidth.ts +++ b/app/client/src/layoutSystems/anvil/layoutComponents/components/zone/useZoneMinWidth.ts @@ -3,22 +3,20 @@ import { ChildrenMapContext } from "layoutSystems/anvil/context/childrenMapConte import type { WidgetProps } from "widgets/BaseWidget"; import { RenderModes } from "constants/WidgetConstants"; import { useSelector } from "react-redux"; -import { - combinedPreviewModeSelector, - getRenderMode, -} from "selectors/editorSelectors"; +import { getRenderMode } from "selectors/editorSelectors"; import type { SizeConfig } from "WidgetProvider/constants"; import { getWidgetSizeConfiguration } from "layoutSystems/anvil/utils/widgetUtils"; import type { CanvasWidgetsReduxState } from "reducers/entityReducers/canvasWidgetsReducer"; import { getWidgets } from "sagas/selectors"; import isObject from "lodash/isObject"; +import { selectCombinedPreviewMode } from "selectors/gitModSelectors"; export function useZoneMinWidth() { const childrenMap: Record = useContext(ChildrenMapContext); const widgets: CanvasWidgetsReduxState = useSelector(getWidgets); const renderMode: RenderModes = useSelector(getRenderMode); - const isPreviewMode: boolean = useSelector(combinedPreviewModeSelector); + const isPreviewMode: boolean = useSelector(selectCombinedPreviewMode); if (renderMode === RenderModes.CANVAS && !isPreviewMode) return "auto"; diff --git a/app/client/src/layoutSystems/anvil/sectionSpaceDistributor/SectionSpaceDistributor.tsx b/app/client/src/layoutSystems/anvil/sectionSpaceDistributor/SectionSpaceDistributor.tsx index fd719bfd1f6f..25e94d38d9e8 100644 --- a/app/client/src/layoutSystems/anvil/sectionSpaceDistributor/SectionSpaceDistributor.tsx +++ b/app/client/src/layoutSystems/anvil/sectionSpaceDistributor/SectionSpaceDistributor.tsx @@ -2,7 +2,7 @@ import { getLayoutElementPositions } from "layoutSystems/common/selectors"; import type { LayoutElementPosition } from "layoutSystems/common/types"; import React, { useMemo } from "react"; import { useSelector } from "react-redux"; -import { combinedPreviewModeSelector } from "selectors/editorSelectors"; +import { selectCombinedPreviewMode } from "selectors/gitModSelectors"; import type { WidgetLayoutProps } from "../utils/anvilTypes"; import { getWidgetByID } from "sagas/selectors"; import { getDefaultSpaceDistributed } from "./utils/spaceRedistributionSagaUtils"; @@ -113,7 +113,7 @@ export const SectionSpaceDistributor = ( props: SectionSpaceDistributorProps, ) => { const { zones } = props; - const isPreviewMode = useSelector(combinedPreviewModeSelector); + const isPreviewMode = useSelector(selectCombinedPreviewMode); const isWidgetSelectionBlocked = useSelector(getWidgetSelectionBlock); const isDragging = useSelector( (state) => state.ui.widgetDragResize.isDragging, diff --git a/app/client/src/layoutSystems/anvil/viewer/AnvilViewerWidgetOnion.tsx b/app/client/src/layoutSystems/anvil/viewer/AnvilViewerWidgetOnion.tsx index 99ca7dddf492..763785755918 100644 --- a/app/client/src/layoutSystems/anvil/viewer/AnvilViewerWidgetOnion.tsx +++ b/app/client/src/layoutSystems/anvil/viewer/AnvilViewerWidgetOnion.tsx @@ -5,7 +5,7 @@ import { AnvilWidgetComponent } from "../common/widgetComponent/AnvilWidgetCompo import type { SizeConfig } from "WidgetProvider/constants"; import { getWidgetSizeConfiguration } from "../utils/widgetUtils"; import { useSelector } from "react-redux"; -import { combinedPreviewModeSelector } from "selectors/editorSelectors"; +import { selectCombinedPreviewMode } from "selectors/gitModSelectors"; /** * AnvilViewerWidgetOnion @@ -20,7 +20,7 @@ import { combinedPreviewModeSelector } from "selectors/editorSelectors"; * @returns Enhanced Widget */ export const AnvilViewerWidgetOnion = (props: BaseWidgetProps) => { - const isPreviewMode = useSelector(combinedPreviewModeSelector); + const isPreviewMode = useSelector(selectCombinedPreviewMode); const widgetSize: SizeConfig = useMemo( () => getWidgetSizeConfiguration(props.type, props, isPreviewMode), [isPreviewMode, props.type], diff --git a/app/client/src/layoutSystems/autolayout/common/FlexComponent.tsx b/app/client/src/layoutSystems/autolayout/common/FlexComponent.tsx index 20edbf4ce0d8..334ca9fd95ec 100644 --- a/app/client/src/layoutSystems/autolayout/common/FlexComponent.tsx +++ b/app/client/src/layoutSystems/autolayout/common/FlexComponent.tsx @@ -4,10 +4,7 @@ import styled from "styled-components"; import { WIDGET_PADDING } from "constants/WidgetConstants"; import { useSelector } from "react-redux"; -import { - combinedPreviewModeSelector, - snipingModeSelector, -} from "selectors/editorSelectors"; +import { snipingModeSelector } from "selectors/editorSelectors"; import { getIsResizing } from "selectors/widgetSelectors"; import { useClickToSelectWidget } from "utils/hooks/useClickToSelectWidget"; import { usePositionedContainerZIndex } from "utils/hooks/usePositionedContainerZIndex"; @@ -16,6 +13,7 @@ import { RESIZE_BORDER_BUFFER } from "layoutSystems/common/resizer/common"; import { checkIsDropTarget } from "WidgetProvider/factory/helpers"; import type { FlexComponentProps } from "../../autolayout/utils/types"; import { useHoverToFocusWidget } from "utils/hooks/useHoverToFocusWidget"; +import { selectCombinedPreviewMode } from "selectors/gitModSelectors"; const FlexWidget = styled.div` position: relative; @@ -58,7 +56,7 @@ export function FlexComponent(props: FlexComponentProps) { )} t--widget-${props.widgetName.toLowerCase()}`, [props.parentId, props.widgetId, props.widgetType, props.widgetName], ); - const isPreviewMode = useSelector(combinedPreviewModeSelector); + const isPreviewMode = useSelector(selectCombinedPreviewMode); const isResizing = useSelector(getIsResizing); const widgetDimensionsViewCss = { diff --git a/app/client/src/layoutSystems/common/dropTarget/DropTargetComponent.tsx b/app/client/src/layoutSystems/common/dropTarget/DropTargetComponent.tsx index d1df63825448..fcb93c9205a6 100644 --- a/app/client/src/layoutSystems/common/dropTarget/DropTargetComponent.tsx +++ b/app/client/src/layoutSystems/common/dropTarget/DropTargetComponent.tsx @@ -21,10 +21,7 @@ import { } from "actions/autoHeightActions"; import { useDispatch } from "react-redux"; import { getDragDetails } from "sagas/selectors"; -import { - combinedPreviewModeSelector, - getOccupiedSpacesSelectorForContainer, -} from "selectors/editorSelectors"; +import { getOccupiedSpacesSelectorForContainer } from "selectors/editorSelectors"; import { getCanvasSnapRows } from "utils/WidgetPropsUtils"; import { useAutoHeightUIState } from "utils/hooks/autoHeightUIHooks"; import { useShowPropertyPane } from "utils/hooks/dragResizeHooks"; @@ -42,6 +39,7 @@ import { import DragLayerComponent from "./DragLayerComponent"; import Onboarding from "./OnBoarding"; import { isDraggingBuildingBlockToCanvas } from "selectors/buildingBlocksSelectors"; +import { selectCombinedPreviewMode } from "selectors/gitModSelectors"; export type DropTargetComponentProps = PropsWithChildren<{ snapColumnSpace: number; @@ -196,7 +194,7 @@ function useUpdateRows( export function DropTargetComponent(props: DropTargetComponentProps) { // Get if this is in preview mode. - const isPreviewMode = useSelector(combinedPreviewModeSelector); + const isPreviewMode = useSelector(selectCombinedPreviewMode); const isAppSettingsPaneWithNavigationTabOpen = useSelector( getIsAppSettingsPaneWithNavigationTabOpen, ); diff --git a/app/client/src/layoutSystems/common/resizer/ModalResizableLayer.tsx b/app/client/src/layoutSystems/common/resizer/ModalResizableLayer.tsx index 559556bbbf42..1a516b9623fe 100644 --- a/app/client/src/layoutSystems/common/resizer/ModalResizableLayer.tsx +++ b/app/client/src/layoutSystems/common/resizer/ModalResizableLayer.tsx @@ -19,11 +19,9 @@ import { } from "./ResizeStyledComponents"; import type { UIElementSize } from "./ResizableUtils"; import { useModalWidth } from "widgets/ModalWidget/component/useModalWidth"; -import { - combinedPreviewModeSelector, - snipingModeSelector, -} from "selectors/editorSelectors"; +import { snipingModeSelector } from "selectors/editorSelectors"; import { getWidgetSelectionBlock } from "../../../selectors/ui"; +import { selectCombinedPreviewMode } from "selectors/gitModSelectors"; const minSize = 100; /** @@ -101,7 +99,7 @@ export const ModalResizableLayer = ({ widgetType: "MODAL_WIDGET", }); }; - const isPreviewMode = useSelector(combinedPreviewModeSelector); + const isPreviewMode = useSelector(selectCombinedPreviewMode); const isSnipingMode = useSelector(snipingModeSelector); const isWidgetSelectionBlocked = useSelector(getWidgetSelectionBlock); const enableResizing = diff --git a/app/client/src/layoutSystems/common/resizer/ResizableComponent.tsx b/app/client/src/layoutSystems/common/resizer/ResizableComponent.tsx index f0336f382b87..fb5aca05d16f 100644 --- a/app/client/src/layoutSystems/common/resizer/ResizableComponent.tsx +++ b/app/client/src/layoutSystems/common/resizer/ResizableComponent.tsx @@ -17,10 +17,7 @@ import { FixedLayoutResizable } from "layoutSystems/fixedlayout/common/resizer/F import { SelectionRequestType } from "sagas/WidgetSelectUtils"; import { getIsAutoLayout } from "selectors/canvasSelectors"; import { getIsAppSettingsPaneWithNavigationTabOpen } from "selectors/appSettingsPaneSelectors"; -import { - combinedPreviewModeSelector, - snipingModeSelector, -} from "selectors/editorSelectors"; +import { snipingModeSelector } from "selectors/editorSelectors"; import { getParentToOpenSelector, isWidgetFocused, @@ -69,6 +66,7 @@ import { getAltBlockWidgetSelection, getWidgetSelectionBlock, } from "selectors/ui"; +import { selectCombinedPreviewMode } from "selectors/gitModSelectors"; export type ResizableComponentProps = WidgetProps & { paddingOffset: number; @@ -83,7 +81,7 @@ export const ResizableComponent = memo(function ResizableComponent( const isAutoLayout = useSelector(getIsAutoLayout); const Resizable = isAutoLayout ? AutoLayoutResizable : FixedLayoutResizable; const isSnipingMode = useSelector(snipingModeSelector); - const isPreviewMode = useSelector(combinedPreviewModeSelector); + const isPreviewMode = useSelector(selectCombinedPreviewMode); const isWidgetSelectionBlock = useSelector(getWidgetSelectionBlock); const isAltWidgetSelectionBlock = useSelector(getAltBlockWidgetSelection); const isAppSettingsPaneWithNavigationTabOpen: boolean = useSelector( diff --git a/app/client/src/layoutSystems/common/utils/LayoutElementPositionsObserver/usePositionObserver.ts b/app/client/src/layoutSystems/common/utils/LayoutElementPositionsObserver/usePositionObserver.ts index 1d5a9c38f354..9c981c66f397 100644 --- a/app/client/src/layoutSystems/common/utils/LayoutElementPositionsObserver/usePositionObserver.ts +++ b/app/client/src/layoutSystems/common/utils/LayoutElementPositionsObserver/usePositionObserver.ts @@ -3,7 +3,7 @@ import { useEffect } from "react"; import { positionObserver } from "."; import { APP_MODE } from "entities/App"; import { useSelector } from "react-redux"; -import { combinedPreviewModeSelector } from "selectors/editorSelectors"; +import { selectCombinedPreviewMode } from "selectors/gitModSelectors"; import { getAppMode } from "ee/selectors/entitiesSelector"; import { getAnvilLayoutDOMId, getAnvilWidgetDOMId } from "./utils"; import { LayoutComponentTypes } from "layoutSystems/anvil/utils/anvilTypes"; @@ -13,7 +13,7 @@ export function useObserveDetachedWidget(widgetId: string) { // We don't need the observer in preview mode or the published app // This is because the positions need to be observed only to enable // editor features - const isPreviewMode = useSelector(combinedPreviewModeSelector); + const isPreviewMode = useSelector(selectCombinedPreviewMode); const appMode = useSelector(getAppMode); if (isPreviewMode || appMode === APP_MODE.PUBLISHED) { @@ -54,7 +54,7 @@ export function usePositionObserver( }, ref: RefObject, ) { - const isPreviewMode = useSelector(combinedPreviewModeSelector); + const isPreviewMode = useSelector(selectCombinedPreviewMode); const appMode = useSelector(getAppMode); useEffect(() => { diff --git a/app/client/src/layoutSystems/common/widgetName/index.tsx b/app/client/src/layoutSystems/common/widgetName/index.tsx index bb8c265946e5..8d5770b995a0 100644 --- a/app/client/src/layoutSystems/common/widgetName/index.tsx +++ b/app/client/src/layoutSystems/common/widgetName/index.tsx @@ -8,7 +8,6 @@ import { SelectionRequestType } from "sagas/WidgetSelectUtils"; import { getIsAppSettingsPaneWithNavigationTabOpen } from "selectors/appSettingsPaneSelectors"; import { hideErrors } from "selectors/debuggerSelectors"; import { - combinedPreviewModeSelector, getIsAutoLayout, snipingModeSelector, } from "selectors/editorSelectors"; @@ -31,6 +30,7 @@ import { RESIZE_BORDER_BUFFER } from "layoutSystems/common/resizer/common"; import { Layers } from "constants/Layers"; import memoize from "micro-memoize"; import { NavigationMethod } from "utils/history"; +import { selectCombinedPreviewMode } from "selectors/gitModSelectors"; const WidgetTypes = WidgetFactory.widgetTypes; @@ -78,7 +78,7 @@ interface WidgetNameComponentProps { export function WidgetNameComponent(props: WidgetNameComponentProps) { const dispatch = useDispatch(); const isSnipingMode = useSelector(snipingModeSelector); - const isPreviewMode = useSelector(combinedPreviewModeSelector); + const isPreviewMode = useSelector(selectCombinedPreviewMode); const isAppSettingsPaneWithNavigationTabOpen = useSelector( getIsAppSettingsPaneWithNavigationTabOpen, ); diff --git a/app/client/src/layoutSystems/fixedlayout/common/autoHeightOverlay/index.tsx b/app/client/src/layoutSystems/fixedlayout/common/autoHeightOverlay/index.tsx index 89519283f7cb..48015d2efff1 100644 --- a/app/client/src/layoutSystems/fixedlayout/common/autoHeightOverlay/index.tsx +++ b/app/client/src/layoutSystems/fixedlayout/common/autoHeightOverlay/index.tsx @@ -3,7 +3,7 @@ import type { CSSProperties } from "react"; import React, { memo } from "react"; import { useSelector } from "react-redux"; import { getIsAppSettingsPaneWithNavigationTabOpen } from "selectors/appSettingsPaneSelectors"; -import { combinedPreviewModeSelector } from "selectors/editorSelectors"; +import { selectCombinedPreviewMode } from "selectors/gitModSelectors"; import type { WidgetProps } from "widgets/BaseWidget"; import AutoHeightOverlayWithStateContext from "./AutoHeightOverlayWithStateContext"; @@ -31,7 +31,7 @@ const AutoHeightOverlayContainer: React.FC = selectedWidgets, } = useSelector((state: AppState) => state.ui.widgetDragResize); - const isPreviewMode = useSelector(combinedPreviewModeSelector); + const isPreviewMode = useSelector(selectCombinedPreviewMode); const isAppSettingsPaneWithNavigationTabOpen = useSelector( getIsAppSettingsPaneWithNavigationTabOpen, ); diff --git a/app/client/src/layoutSystems/fixedlayout/editor/FixedLayoutCanvasArenas/CanvasSelectionArena.tsx b/app/client/src/layoutSystems/fixedlayout/editor/FixedLayoutCanvasArenas/CanvasSelectionArena.tsx index c0cf29167981..c299eaef18db 100644 --- a/app/client/src/layoutSystems/fixedlayout/editor/FixedLayoutCanvasArenas/CanvasSelectionArena.tsx +++ b/app/client/src/layoutSystems/fixedlayout/editor/FixedLayoutCanvasArenas/CanvasSelectionArena.tsx @@ -21,7 +21,6 @@ import { getIsDraggingForSelection, } from "selectors/canvasSelectors"; import { - combinedPreviewModeSelector, getCurrentApplicationLayout, getCurrentPageId, } from "selectors/editorSelectors"; @@ -31,6 +30,7 @@ import type { XYCord } from "layoutSystems/common/canvasArenas/ArenaTypes"; import { useCanvasDragToScroll } from "layoutSystems/common/canvasArenas/useCanvasDragToScroll"; import { StickyCanvasArena } from "layoutSystems/common/canvasArenas/StickyCanvasArena"; import { getWidgetSelectionBlock } from "../../../../selectors/ui"; +import { selectCombinedPreviewMode } from "selectors/gitModSelectors"; export interface SelectedArenaDimensions { top: number; @@ -71,7 +71,7 @@ export function CanvasSelectionArena({ (parentWidget && parentWidget.detachFromLayout) ); const appMode = useSelector(getAppMode); - const isPreviewMode = useSelector(combinedPreviewModeSelector); + const isPreviewMode = useSelector(selectCombinedPreviewMode); const isWidgetSelectionBlocked = useSelector(getWidgetSelectionBlock); const isAppSettingsPaneWithNavigationTabOpen = useSelector( getIsAppSettingsPaneWithNavigationTabOpen, diff --git a/app/client/src/pages/AppViewer/Navigation/Sidebar.tsx b/app/client/src/pages/AppViewer/Navigation/Sidebar.tsx index 3b6b80aa7328..5ad23ff2e567 100644 --- a/app/client/src/pages/AppViewer/Navigation/Sidebar.tsx +++ b/app/client/src/pages/AppViewer/Navigation/Sidebar.tsx @@ -12,10 +12,7 @@ import ShareButton from "./components/ShareButton"; import PrimaryCTA from "../PrimaryCTA"; import { useHref } from "pages/Editor/utils"; import { builderURL } from "ee/RouteBuilder"; -import { - combinedPreviewModeSelector, - getCurrentBasePageId, -} from "selectors/editorSelectors"; +import { getCurrentBasePageId } from "selectors/editorSelectors"; import type { User } from "constants/userConstants"; import SidebarProfileComponent from "./components/SidebarProfileComponent"; import CollapseButton from "./components/CollapseButton"; @@ -36,6 +33,7 @@ import MenuItemContainer from "./components/MenuItemContainer"; import BackToAppsButton from "./components/BackToAppsButton"; import { IDE_HEADER_HEIGHT } from "@appsmith/ads"; import { BOTTOM_BAR_HEIGHT } from "components/BottomBar/constants"; +import { selectCombinedPreviewMode } from "selectors/gitModSelectors"; interface SidebarProps { currentApplicationDetails?: ApplicationPayload; @@ -81,7 +79,7 @@ export function Sidebar(props: SidebarProps) { const isPinned = useSelector(getAppSidebarPinned); const [isOpen, setIsOpen] = useState(true); const { x } = useMouse(); - const isPreviewMode = useSelector(combinedPreviewModeSelector); + const isPreviewMode = useSelector(selectCombinedPreviewMode); const isAppSettingsPaneWithNavigationTabOpen = useSelector( getIsAppSettingsPaneWithNavigationTabOpen, ); diff --git a/app/client/src/pages/AppViewer/Navigation/TopInline.tsx b/app/client/src/pages/AppViewer/Navigation/TopInline.tsx index f15dd093ff21..af09e8497fd1 100644 --- a/app/client/src/pages/AppViewer/Navigation/TopInline.tsx +++ b/app/client/src/pages/AppViewer/Navigation/TopInline.tsx @@ -5,14 +5,12 @@ import MenuItem from "./components/MenuItem"; import { Container } from "./TopInline.styled"; import MenuItemContainer from "./components/MenuItemContainer"; import MoreDropdownButton from "./components/MoreDropdownButton"; -import { - combinedPreviewModeSelector, - getCanvasWidth, -} from "selectors/editorSelectors"; +import { getCanvasWidth } from "selectors/editorSelectors"; import { useSelector } from "react-redux"; import { getIsAppSettingsPaneWithNavigationTabOpen } from "selectors/appSettingsPaneSelectors"; import { throttle } from "lodash"; import type { NavigationProps } from "./constants"; +import { selectCombinedPreviewMode } from "selectors/gitModSelectors"; export function TopInline(props: NavigationProps) { const { currentApplicationDetails, pages } = props; @@ -23,7 +21,7 @@ export function TopInline(props: NavigationProps) { const maxMenuItemWidth = 220; const [maxMenuItemsThatCanFit, setMaxMenuItemsThatCanFit] = useState(0); const { width: screenWidth } = useWindowSizeHooks(); - const isPreviewMode = useSelector(combinedPreviewModeSelector); + const isPreviewMode = useSelector(selectCombinedPreviewMode); const isAppSettingsPaneWithNavigationTabOpen = useSelector( getIsAppSettingsPaneWithNavigationTabOpen, ); diff --git a/app/client/src/pages/AppViewer/PrimaryCTA.test.tsx b/app/client/src/pages/AppViewer/PrimaryCTA.test.tsx index 3b03a559fbfb..63b76d0e0fcc 100644 --- a/app/client/src/pages/AppViewer/PrimaryCTA.test.tsx +++ b/app/client/src/pages/AppViewer/PrimaryCTA.test.tsx @@ -7,6 +7,11 @@ import { lightTheme } from "selectors/themeSelectors"; import PrimaryCTA from "./PrimaryCTA"; import configureStore from "redux-mock-store"; +jest.mock("pages/Editor/gitSync/hooks/modHooks", () => ({ + ...jest.requireActual("pages/Editor/gitSync/hooks/modHooks"), + useGitProtectedMode: jest.fn(() => false), +})); + jest.mock("react-router", () => ({ ...jest.requireActual("react-router"), useHistory: () => ({ push: jest.fn() }), diff --git a/app/client/src/pages/AppViewer/PrimaryCTA.tsx b/app/client/src/pages/AppViewer/PrimaryCTA.tsx index 9e2816166454..97d0363bbf5f 100644 --- a/app/client/src/pages/AppViewer/PrimaryCTA.tsx +++ b/app/client/src/pages/AppViewer/PrimaryCTA.tsx @@ -25,8 +25,8 @@ import { Icon, Tooltip } from "@appsmith/ads"; import { getApplicationNameTextColor } from "./utils"; import { ButtonVariantTypes } from "components/constants"; import { setPreviewModeInitAction } from "actions/editorActions"; -import { protectedModeSelector } from "selectors/gitSyncSelectors"; import { getCurrentApplication } from "ee/selectors/applicationSelectors"; +import { useGitProtectedMode } from "pages/Editor/gitSync/hooks/modHooks"; /** * --------------------------------------------------------------------------------------------------- @@ -67,7 +67,7 @@ function PrimaryCTA(props: Props) { const canEdit = isPermitted(userPermissions, permissionRequired); const [isForkModalOpen, setIsForkModalOpen] = useState(false); const isPreviewMode = useSelector(previewModeSelector); - const isProtectedMode = useSelector(protectedModeSelector); + const isProtectedMode = useGitProtectedMode(); const dispatch = useDispatch(); const location = useLocation(); const queryParams = new URLSearchParams(location.search); diff --git a/app/client/src/pages/Editor/AppSettingsPane/AppSettings/ImportAppSettings.tsx b/app/client/src/pages/Editor/AppSettingsPane/AppSettings/ImportAppSettings.tsx index 8da3b25343c3..b721e7c5c7af 100644 --- a/app/client/src/pages/Editor/AppSettingsPane/AppSettings/ImportAppSettings.tsx +++ b/app/client/src/pages/Editor/AppSettingsPane/AppSettings/ImportAppSettings.tsx @@ -8,8 +8,8 @@ import ImportModal from "pages/common/ImportModal"; import React from "react"; import { useSelector } from "react-redux"; import { getCurrentApplicationId } from "selectors/editorSelectors"; -import { getIsGitConnected } from "selectors/gitSyncSelectors"; import styled from "styled-components"; +import { useGitConnected } from "pages/Editor/gitSync/hooks/modHooks"; const SettingWrapper = styled.div` display: flex; @@ -21,7 +21,7 @@ const SettingWrapper = styled.div` export function ImportAppSettings() { const appId = useSelector(getCurrentApplicationId); const workspace = useSelector(getCurrentAppWorkspace); - const isGitConnected = useSelector(getIsGitConnected); + const isGitConnected = useGitConnected(); const [isModalOpen, setIsModalOpen] = React.useState(false); function handleClose() { diff --git a/app/client/src/pages/Editor/Canvas.tsx b/app/client/src/pages/Editor/Canvas.tsx index 742e6d8a74b1..c34f2fc358c8 100644 --- a/app/client/src/pages/Editor/Canvas.tsx +++ b/app/client/src/pages/Editor/Canvas.tsx @@ -5,7 +5,7 @@ import * as Sentry from "@sentry/react"; import { useDispatch, useSelector } from "react-redux"; import type { CanvasWidgetStructure } from "WidgetProvider/constants"; import useWidgetFocus from "utils/hooks/useWidgetFocus"; -import { combinedPreviewModeSelector } from "selectors/editorSelectors"; +import { selectCombinedPreviewMode } from "selectors/gitModSelectors"; import { getSelectedAppTheme } from "selectors/appThemingSelectors"; import { getViewportClassName } from "layoutSystems/autolayout/utils/AutoLayoutUtils"; import { @@ -44,7 +44,7 @@ const Wrapper = styled.section<{ `; const Canvas = (props: CanvasProps) => { const { canvasWidth } = props; - const isPreviewMode = useSelector(combinedPreviewModeSelector); + const isPreviewMode = useSelector(selectCombinedPreviewMode); const isAppSettingsPaneWithNavigationTabOpen = useSelector( getIsAppSettingsPaneWithNavigationTabOpen, ); diff --git a/app/client/src/pages/Editor/GlobalHotKeys/GlobalHotKeys.tsx b/app/client/src/pages/Editor/GlobalHotKeys/GlobalHotKeys.tsx index 651f57e792c0..1e01349df831 100644 --- a/app/client/src/pages/Editor/GlobalHotKeys/GlobalHotKeys.tsx +++ b/app/client/src/pages/Editor/GlobalHotKeys/GlobalHotKeys.tsx @@ -45,8 +45,8 @@ import { toast } from "@appsmith/ads"; import { showDebuggerFlag } from "selectors/debuggerSelectors"; import { getIsFirstTimeUserOnboardingEnabled } from "selectors/onboardingSelectors"; import WalkthroughContext from "components/featureWalkthrough/walkthroughContext"; -import { protectedModeSelector } from "selectors/gitSyncSelectors"; import { setPreviewModeInitAction } from "actions/editorActions"; +import { selectGitApplicationProtectedMode } from "selectors/gitModSelectors"; interface Props { copySelectedWidget: () => void; @@ -372,15 +372,17 @@ class GlobalHotKeys extends React.Component { } } -const mapStateToProps = (state: AppState) => ({ - selectedWidget: getLastSelectedWidget(state), - selectedWidgets: getSelectedWidgets(state), - isDebuggerOpen: showDebuggerFlag(state), - appMode: getAppMode(state), - isPreviewMode: previewModeSelector(state), - isProtectedMode: protectedModeSelector(state), - isSignpostingEnabled: getIsFirstTimeUserOnboardingEnabled(state), -}); +const mapStateToProps = (state: AppState) => { + return { + selectedWidget: getLastSelectedWidget(state), + selectedWidgets: getSelectedWidgets(state), + isDebuggerOpen: showDebuggerFlag(state), + appMode: getAppMode(state), + isPreviewMode: previewModeSelector(state), + isProtectedMode: selectGitApplicationProtectedMode(state), + isSignpostingEnabled: getIsFirstTimeUserOnboardingEnabled(state), + }; +}; // TODO: Fix this the next time the file is edited // eslint-disable-next-line @typescript-eslint/no-explicit-any diff --git a/app/client/src/pages/Editor/IDE/Header/DeployButton.tsx b/app/client/src/pages/Editor/IDE/Header/DeployButton.tsx new file mode 100644 index 000000000000..843da728dddf --- /dev/null +++ b/app/client/src/pages/Editor/IDE/Header/DeployButton.tsx @@ -0,0 +1,131 @@ +import { Button, Tooltip } from "@appsmith/ads"; +import { objectKeys } from "@appsmith/utils"; +import { showConnectGitModal } from "actions/gitSyncActions"; +import { publishApplication } from "ee/actions/applicationActions"; +import { getCurrentApplication } from "ee/selectors/applicationSelectors"; +import type { NavigationSetting } from "constants/AppConstants"; +import { + createMessage, + DEPLOY_BUTTON_TOOLTIP, + DEPLOY_MENU_OPTION, + PACKAGE_UPGRADING_ACTION_STATUS, +} from "ee/constants/messages"; +import { getIsPackageUpgrading } from "ee/selectors/packageSelectors"; +import AnalyticsUtil from "ee/utils/AnalyticsUtil"; +import { useGitOps, useGitProtectedMode } from "git"; +import { + useGitConnected, + useGitModEnabled, +} from "pages/Editor/gitSync/hooks/modHooks"; +import React, { useCallback } from "react"; +import { useDispatch, useSelector } from "react-redux"; +import { + getCurrentApplicationId, + getIsPublishingApplication, +} from "selectors/editorSelectors"; +import styled from "styled-components"; + +// This wrapper maintains pointer events for tooltips when the child button is disabled. +// Without this, disabled buttons won't trigger tooltips because they have pointer-events: none +const StyledTooltipTarget = styled.span` + display: inline-block; +`; + +function DeployButton() { + const applicationId = useSelector(getCurrentApplicationId); + const currentApplication = useSelector(getCurrentApplication); + const isPackageUpgrading = useSelector(getIsPackageUpgrading); + const isProtectedMode = useGitProtectedMode(); + const isDeployDisabled = isPackageUpgrading || isProtectedMode; + const isPublishing = useSelector(getIsPublishingApplication); + const isGitConnected = useGitConnected(); + const isGitModEnabled = useGitModEnabled(); + const { toggleOpsModal } = useGitOps(); + + const deployTooltipText = isPackageUpgrading + ? createMessage(PACKAGE_UPGRADING_ACTION_STATUS, "deploy this app") + : createMessage(DEPLOY_BUTTON_TOOLTIP); + + const dispatch = useDispatch(); + + const handlePublish = useCallback(() => { + 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 = objectKeys( + 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, + }); + } + }, [applicationId, currentApplication, dispatch]); + + const handleClickDeploy = useCallback(() => { + if (isGitConnected) { + if (isGitModEnabled) { + toggleOpsModal(true); + } else { + dispatch(showConnectGitModal()); + } + + AnalyticsUtil.logEvent("GS_DEPLOY_GIT_CLICK", { + source: "Deploy button", + }); + } else { + handlePublish(); + } + }, [ + dispatch, + handlePublish, + isGitConnected, + isGitModEnabled, + toggleOpsModal, + ]); + + return ( + + + + + + ); +} + +export default DeployButton; diff --git a/app/client/src/pages/Editor/IDE/Header/index.tsx b/app/client/src/pages/Editor/IDE/Header/index.tsx index f8e75cda9db7..c26b641ba40d 100644 --- a/app/client/src/pages/Editor/IDE/Header/index.tsx +++ b/app/client/src/pages/Editor/IDE/Header/index.tsx @@ -1,7 +1,6 @@ -import React, { useCallback, useState } from "react"; +import React, { useState } from "react"; import { Flex, - Tooltip, Divider, Modal, ModalContent, @@ -11,7 +10,6 @@ import { TabsList, Tab, TabPanel, - Button, Link, IDEHeader, IDEHeaderTitle, @@ -24,19 +22,15 @@ import { APPLICATION_INVITE, COMMUNITY_TEMPLATES, createMessage, - DEPLOY_BUTTON_TOOLTIP, - DEPLOY_MENU_OPTION, IN_APP_EMBED_SETTING, INVITE_TAB, HEADER_TITLES, - PACKAGE_UPGRADING_ACTION_STATUS, } from "ee/constants/messages"; import EditorName from "pages/Editor/EditorName"; import { getCurrentApplicationId, getCurrentPageId, getIsPageSaving, - getIsPublishingApplication, getPageById, getPageSavingError, } from "selectors/editorSelectors"; @@ -46,10 +40,7 @@ import { getIsErroredSavingAppName, getIsSavingAppName, } from "ee/selectors/applicationSelectors"; -import { - publishApplication, - updateApplication, -} from "ee/actions/applicationActions"; +import { updateApplication } from "ee/actions/applicationActions"; import { getCurrentAppWorkspace } from "ee/selectors/selectedWorkspaceSelectors"; import { Omnibar } from "pages/Editor/commons/Omnibar"; import ToggleModeButton from "pages/Editor/ToggleModeButton"; @@ -62,13 +53,6 @@ import DeployLinkButtonDialog from "components/designSystems/appsmith/header/Dep import { useFeatureFlag } from "utils/hooks/useFeatureFlag"; import { FEATURE_FLAG } from "ee/entities/FeatureFlag"; import { getAppsmithConfigs } from "ee/configs"; -import { - getIsGitConnected, - protectedModeSelector, -} from "selectors/gitSyncSelectors"; -import { showConnectGitModal } from "actions/gitSyncActions"; -import AnalyticsUtil from "ee/utils/AnalyticsUtil"; -import type { NavigationSetting } from "constants/AppConstants"; import { useHref } from "pages/Editor/utils"; import { viewerURL } from "ee/RouteBuilder"; import HelpBar from "components/editorComponents/GlobalSearch/HelpBar"; @@ -80,7 +64,8 @@ import { APPLICATIONS_URL } from "constants/routes"; import { useNavigationMenuData } from "../../EditorName/useNavigationMenuData"; import useLibraryHeaderTitle from "ee/pages/Editor/IDE/Header/useLibraryHeaderTitle"; import { AppsmithLink } from "pages/Editor/AppsmithLink"; -import { getIsPackageUpgrading } from "ee/selectors/packageSelectors"; +import DeployButton from "./DeployButton"; +import GitApplicationContextProvider from "components/gitContexts/GitApplicationContextProvider"; const StyledDivider = styled(Divider)` height: 50%; @@ -88,12 +73,6 @@ const StyledDivider = styled(Divider)` margin-right: 8px; `; -// This wrapper maintains pointer events for tooltips when the child button is disabled. -// Without this, disabled buttons won't trigger tooltips because they have pointer-events: none -const StyledTooltipTarget = styled.span` - display: inline-block; -`; - const { cloudHosting } = getAppsmithConfigs(); interface HeaderTitleProps { @@ -137,19 +116,11 @@ const Header = () => { const currentApplication = useSelector(getCurrentApplication); const isErroredSavingName = useSelector(getIsErroredSavingAppName); const applicationList = useSelector(getApplicationList); - const isProtectedMode = useSelector(protectedModeSelector); - const isPackageUpgrading = useSelector(getIsPackageUpgrading); - const isPublishing = useSelector(getIsPublishingApplication); - const isGitConnected = useSelector(getIsGitConnected); const pageId = useSelector(getCurrentPageId) as string; const currentPage = useSelector(getPageById(pageId)); const appState = useCurrentAppState(); const isSaving = useSelector(getIsPageSaving); const pageSaveError = useSelector(getPageSavingError); - const isDeployDisabled = isPackageUpgrading || isProtectedMode; - const deployTooltipText = isPackageUpgrading - ? createMessage(PACKAGE_UPGRADING_ACTION_STATUS, "deploy this app") - : createMessage(DEPLOY_BUTTON_TOOLTIP); // states const [isPopoverOpen, setIsPopoverOpen] = useState(false); const [showModal, setShowModal] = useState(false); @@ -179,56 +150,8 @@ const Header = () => { dispatch(updateApplication(id, data)); }; - const handlePublish = useCallback(() => { - 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, - }); - } - }, [applicationId, currentApplication, dispatch]); - - const handleClickDeploy = useCallback(() => { - if (isGitConnected) { - dispatch(showConnectGitModal()); - AnalyticsUtil.logEvent("GS_DEPLOY_GIT_CLICK", { - source: "Deploy button", - }); - } else { - handlePublish(); - } - }, [dispatch, handlePublish, isGitConnected]); - return ( - <> + }> @@ -338,30 +261,13 @@ const Header = () => { showModal={showPublishCommunityTemplateModal} />
- - - - - - +
- +
); }; diff --git a/app/client/src/pages/Editor/IDE/Layout/AnimatedLayout.tsx b/app/client/src/pages/Editor/IDE/Layout/AnimatedLayout.tsx index 952b3542c3f8..bc6d2970d014 100644 --- a/app/client/src/pages/Editor/IDE/Layout/AnimatedLayout.tsx +++ b/app/client/src/pages/Editor/IDE/Layout/AnimatedLayout.tsx @@ -2,7 +2,6 @@ import React from "react"; import { useGridLayoutTemplate } from "./hooks/useGridLayoutTemplate"; import EditorWrapperContainer from "pages/Editor/commons/EditorWrapperContainer"; import { AnimatedGridLayout, LayoutArea } from "components/AnimatedGridLayout"; -import { useSelector } from "react-redux"; import BottomBar from "components/BottomBar"; import Sidebar from "../Sidebar"; import LeftPane from "../LeftPane"; @@ -10,10 +9,28 @@ import MainPane from "../MainPane"; import RightPane from "../RightPane"; import { Areas } from "./constants"; import ProtectedCallout from "../ProtectedCallout"; -import { protectedModeSelector } from "selectors/gitSyncSelectors"; +import { + useGitModEnabled, + useGitProtectedMode, +} from "pages/Editor/gitSync/hooks/modHooks"; +import { GitProtectedBranchCallout as GitProtectedBranchCalloutNew } from "git"; + +function GitProtectedBranchCallout() { + const isGitModEnabled = useGitModEnabled(); + const isProtectedMode = useGitProtectedMode(); + + if (isGitModEnabled) { + return ; + } + + if (isProtectedMode) { + return ; + } + + return null; +} function AnimatedLayout() { - const isProtectedMode = useSelector(protectedModeSelector); const { areas, columns, rows } = useGridLayoutTemplate(); if (columns.length === 0) { @@ -22,7 +39,7 @@ function AnimatedLayout() { return ( <> - {isProtectedMode && } + ; + } + + if (isProtectedMode) { + return ; + } + + return null; +} const GridContainer = styled.div` display: grid; @@ -26,14 +44,13 @@ const LayoutContainer = styled.div<{ name: string }>` `; export const StaticLayout = React.memo(() => { - const isProtectedMode = useSelector(protectedModeSelector); const { areas, columns } = useGridLayoutTemplate(); const isSidebarVisible = columns[0] !== "0px"; return ( <> - {isProtectedMode && } + { const [windowWidth] = useWindowDimensions(); @@ -20,7 +20,7 @@ export const useEditorStateLeftPaneWidth = (): number => { const { segment } = useCurrentEditorState(); const propertyPaneWidth = useSelector(getPropertyPaneWidth); const isPreviewMode = useSelector(previewModeSelector); - const isProtectedMode = useSelector(protectedModeSelector); + const isProtectedMode = useGitProtectedMode(); useEffect( function updateWidth() { diff --git a/app/client/src/pages/Editor/IDE/Layout/hooks/useGridLayoutTemplate.ts b/app/client/src/pages/Editor/IDE/Layout/hooks/useGridLayoutTemplate.ts index b2dc0558af59..bf97ce71790b 100644 --- a/app/client/src/pages/Editor/IDE/Layout/hooks/useGridLayoutTemplate.ts +++ b/app/client/src/pages/Editor/IDE/Layout/hooks/useGridLayoutTemplate.ts @@ -7,7 +7,6 @@ import { useCurrentAppState } from "../../hooks/useCurrentAppState"; import { getPropertyPaneWidth } from "selectors/propertyPaneSelectors"; import { previewModeSelector } from "selectors/editorSelectors"; import { getIDEViewMode } from "selectors/ideSelectors"; -import { protectedModeSelector } from "selectors/gitSyncSelectors"; import { EditorEntityTab, EditorState, @@ -20,6 +19,7 @@ import { } from "constants/AppConstants"; import { useEditorStateLeftPaneWidth } from "./useEditorStateLeftPaneWidth"; import { type Area, Areas, SIDEBAR_WIDTH } from "../constants"; +import { useGitProtectedMode } from "pages/Editor/gitSync/hooks/modHooks"; interface ReturnValue { areas: Area[][]; @@ -43,7 +43,7 @@ function useGridLayoutTemplate(): ReturnValue { const appState = useCurrentAppState(); const isPreviewMode = useSelector(previewModeSelector); const editorMode = useSelector(getIDEViewMode); - const isProtectedMode = useSelector(protectedModeSelector); + const isProtectedMode = useGitProtectedMode(); React.useEffect( function updateIDEColumns() { diff --git a/app/client/src/pages/Editor/IDE/ProtectedCallout.test.tsx b/app/client/src/pages/Editor/IDE/ProtectedCallout.test.tsx index 2a60c70f3f86..d735d5663d88 100644 --- a/app/client/src/pages/Editor/IDE/ProtectedCallout.test.tsx +++ b/app/client/src/pages/Editor/IDE/ProtectedCallout.test.tsx @@ -3,11 +3,11 @@ import { render } from "@testing-library/react"; import { merge } from "lodash"; import { Provider } from "react-redux"; import configureStore from "redux-mock-store"; -import IDE from "."; import { BrowserRouter } from "react-router-dom"; import "@testing-library/jest-dom"; import { ReduxActionTypes } from "ee/constants/ReduxActionConstants"; import store from "store"; +import ProtectedCallout from "./ProtectedCallout"; // TODO: Fix this the next time the file is edited // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -64,7 +64,7 @@ describe("Protected callout test cases", () => { const { getByTestId } = render( - + , ); @@ -72,33 +72,6 @@ describe("Protected callout test cases", () => { expect(getByTestId("t--git-protected-branch-callout")).toBeInTheDocument(); }); - it("should not render the protected view if branch is not protected", () => { - const store = getMockStore({ - ui: { - applications: { - currentApplication: { - gitApplicationMetadata: { - branchName: "branch-1", - }, - }, - }, - gitSync: { - protectedBranches: ["main"], - }, - }, - }); - const { queryByTestId } = render( - - - - - , - ); - - expect( - queryByTestId("t--git-protected-branch-callout"), - ).not.toBeInTheDocument(); - }); it("should unprotect only the current branch if clicked on unprotect cta", () => { const store = getMockStore({ ui: { @@ -117,7 +90,7 @@ describe("Protected callout test cases", () => { const { queryByTestId } = render( - + , ); diff --git a/app/client/src/pages/Editor/IDE/hooks.test.tsx b/app/client/src/pages/Editor/IDE/hooks.test.tsx index 0a12538bf260..9e5e40d6e98f 100644 --- a/app/client/src/pages/Editor/IDE/hooks.test.tsx +++ b/app/client/src/pages/Editor/IDE/hooks.test.tsx @@ -6,6 +6,12 @@ import { useGetPageFocusUrl } from "./hooks"; // eslint-disable-next-line @typescript-eslint/no-restricted-imports import { createEditorFocusInfo } from "../../../ce/navigation/FocusStrategy/AppIDEFocusStrategy"; +const mockUseGitCurrentBranch = jest.fn(() => null); + +jest.mock("../gitSync/hooks/modHooks", () => ({ + useGitCurrentBranch: () => mockUseGitCurrentBranch(), +})); + describe("useGetPageFocusUrl", () => { const pages = PageFactory.buildList(4); @@ -42,6 +48,7 @@ describe("useGetPageFocusUrl", () => { const wrapper = hookWrapper({ initialState: state }); it("works for JS focus history", () => { + mockUseGitCurrentBranch.mockReturnValue(null); const { result } = renderHook(() => useGetPageFocusUrl(pages[0].pageId), { wrapper, }); @@ -83,10 +90,13 @@ describe("useGetPageFocusUrl", () => { it("returns correct state when branches exist", () => { const branch = "featureBranch"; + + mockUseGitCurrentBranch.mockReturnValue(branch); const page1FocusHistoryWithBranch = createEditorFocusInfo( pages[0].pageId, branch, ); + const state = getIDETestState({ pages, focusHistory: { diff --git a/app/client/src/pages/Editor/IDE/hooks.ts b/app/client/src/pages/Editor/IDE/hooks.ts index 178a02e94222..6d356af8626b 100644 --- a/app/client/src/pages/Editor/IDE/hooks.ts +++ b/app/client/src/pages/Editor/IDE/hooks.ts @@ -15,7 +15,6 @@ import { widgetListURL, } from "ee/RouteBuilder"; import { getCurrentFocusInfo } from "selectors/focusHistorySelectors"; -import { getCurrentGitBranch } from "selectors/gitSyncSelectors"; import { getIsAltFocusWidget, getWidgetSelectionBlock } from "selectors/ui"; import { altFocusWidget, setWidgetSelectionBlock } from "actions/widgetActions"; import { useJSAdd } from "ee/pages/Editor/IDE/EditorPane/JS/hooks"; @@ -27,6 +26,7 @@ import { closeJSActionTab } from "actions/jsActionActions"; import { closeQueryActionTab } from "actions/pluginActionActions"; import { getCurrentBasePageId } from "selectors/editorSelectors"; import { getCurrentEntityInfo } from "../utils"; +import { useGitCurrentBranch } from "../gitSync/hooks/modHooks"; import { useEditorType } from "ee/hooks"; import { useParentEntityInfo } from "ee/hooks/datasourceEditorHooks"; import { useBoolean } from "usehooks-ts"; @@ -102,7 +102,8 @@ export const useSegmentNavigation = (): { export const useGetPageFocusUrl = (basePageId: string): string => { const [focusPageUrl, setFocusPageUrl] = useState(builderURL({ basePageId })); - const branch = useSelector(getCurrentGitBranch); + const branch = useGitCurrentBranch(); + const editorStateFocusInfo = useSelector((appState) => getCurrentFocusInfo(appState, createEditorFocusInfoKey(basePageId, branch)), ); diff --git a/app/client/src/pages/Editor/WidgetsEditor/components/LayoutSystemBasedPageViewer.tsx b/app/client/src/pages/Editor/WidgetsEditor/components/LayoutSystemBasedPageViewer.tsx index a430ed2fd02e..935e67cd90f0 100644 --- a/app/client/src/pages/Editor/WidgetsEditor/components/LayoutSystemBasedPageViewer.tsx +++ b/app/client/src/pages/Editor/WidgetsEditor/components/LayoutSystemBasedPageViewer.tsx @@ -8,9 +8,9 @@ import { getCurrentPageId, previewModeSelector, } from "selectors/editorSelectors"; -import { protectedModeSelector } from "selectors/gitSyncSelectors"; import { getAppSettingsPaneContext } from "selectors/appSettingsPaneSelectors"; import { useShowSnapShotBanner } from "pages/Editor/CanvasLayoutConversion/hooks/useShowSnapShotBanner"; +import { useGitProtectedMode } from "pages/Editor/gitSync/hooks/modHooks"; /** * LayoutSystemBasedPageViewer @@ -25,7 +25,7 @@ export const LayoutSystemBasedPageViewer = ({ }) => { const currentPageId = useSelector(getCurrentPageId); const isPreviewMode = useSelector(previewModeSelector); - const isProtectedMode = useSelector(protectedModeSelector); + const isProtectedMode = useGitProtectedMode(); const appSettingsPaneContext = useSelector(getAppSettingsPaneContext); const canvasWidth = useSelector(getCanvasWidth); const shouldShowSnapShotBanner = useShowSnapShotBanner( diff --git a/app/client/src/pages/Editor/WidgetsEditor/components/NavigationAdjustedPageViewer.tsx b/app/client/src/pages/Editor/WidgetsEditor/components/NavigationAdjustedPageViewer.tsx index 7ec7cdd62ec4..6eb0f1ff10a6 100644 --- a/app/client/src/pages/Editor/WidgetsEditor/components/NavigationAdjustedPageViewer.tsx +++ b/app/client/src/pages/Editor/WidgetsEditor/components/NavigationAdjustedPageViewer.tsx @@ -4,7 +4,7 @@ import { EditorState } from "ee/entities/IDE/constants"; import { useCurrentAppState } from "pages/Editor/IDE/hooks/useCurrentAppState"; import { getIsAppSettingsPaneWithNavigationTabOpen } from "selectors/appSettingsPaneSelectors"; import { useSelector } from "react-redux"; -import { combinedPreviewModeSelector } from "selectors/editorSelectors"; +import { selectCombinedPreviewMode } from "selectors/gitModSelectors"; import { PageViewWrapper } from "pages/AppViewer/AppPage"; import classNames from "classnames"; import { APP_MODE } from "entities/App"; @@ -27,7 +27,7 @@ import { getIsAnvilLayout } from "layoutSystems/anvil/integrations/selectors"; export const NavigationAdjustedPageViewer = (props: { children: ReactNode; }) => { - const isPreview = useSelector(combinedPreviewModeSelector); + const isPreview = useSelector(selectCombinedPreviewMode); const currentApplicationDetails = useSelector(getCurrentApplication); const isAppSidebarPinned = useSelector(getAppSidebarPinned); const sidebarWidth = useSelector(getSidebarWidth); diff --git a/app/client/src/pages/Editor/WidgetsEditor/components/NavigationPreview.tsx b/app/client/src/pages/Editor/WidgetsEditor/components/NavigationPreview.tsx index 0478d6f63439..8f2aa0e23c24 100644 --- a/app/client/src/pages/Editor/WidgetsEditor/components/NavigationPreview.tsx +++ b/app/client/src/pages/Editor/WidgetsEditor/components/NavigationPreview.tsx @@ -2,7 +2,7 @@ import type { LegacyRef } from "react"; import React, { forwardRef } from "react"; import classNames from "classnames"; import { useSelector } from "react-redux"; -import { combinedPreviewModeSelector } from "selectors/editorSelectors"; +import { selectCombinedPreviewMode } from "selectors/gitModSelectors"; import { Navigation } from "pages/AppViewer/Navigation"; import { useCurrentAppState } from "pages/Editor/IDE/hooks/useCurrentAppState"; import { EditorState } from "ee/entities/IDE/constants"; @@ -22,7 +22,7 @@ const NavigationPreview = forwardRef( const appState = useCurrentAppState(); const isAppSettingsPaneWithNavigationTabOpen = appState === EditorState.SETTINGS && isNavigationSelectedInSettings; - const isPreviewMode = useSelector(combinedPreviewModeSelector); + const isPreviewMode = useSelector(selectCombinedPreviewMode); return (
{ const allowDragToSelect = useAllowEditorDragToSelect(); const { isAutoHeightWithLimitsChanging } = useAutoHeightUIState(); const dispatch = useDispatch(); - const isCombinedPreviewMode = useSelector(combinedPreviewModeSelector); + const isCombinedPreviewMode = useSelector(selectCombinedPreviewMode); const handleWrapperClick = useCallback( (e) => { diff --git a/app/client/src/pages/Editor/WidgetsEditor/components/WidgetEditorNavigation.tsx b/app/client/src/pages/Editor/WidgetsEditor/components/WidgetEditorNavigation.tsx index 852c210685ee..d7b7d2869271 100644 --- a/app/client/src/pages/Editor/WidgetsEditor/components/WidgetEditorNavigation.tsx +++ b/app/client/src/pages/Editor/WidgetsEditor/components/WidgetEditorNavigation.tsx @@ -7,7 +7,7 @@ import { getIsAppSettingsPaneWithNavigationTabOpen, } from "selectors/appSettingsPaneSelectors"; import { useSelector } from "react-redux"; -import { combinedPreviewModeSelector } from "selectors/editorSelectors"; +import { selectCombinedPreviewMode } from "selectors/gitModSelectors"; import { getCurrentApplication } from "ee/selectors/applicationSelectors"; /** @@ -20,7 +20,7 @@ import { getCurrentApplication } from "ee/selectors/applicationSelectors"; export const useNavigationPreviewHeight = () => { const [navigationHeight, setNavigationHeight] = useState(0); const navigationPreviewRef = useRef(null); - const isPreviewMode = useSelector(combinedPreviewModeSelector); + const isPreviewMode = useSelector(selectCombinedPreviewMode); const appSettingsPaneContext = useSelector(getAppSettingsPaneContext); const currentApplicationDetails = useSelector(getCurrentApplication); @@ -54,7 +54,7 @@ type DivRef = React.Ref; */ export const WidgetEditorNavigation = forwardRef( (props, navigationPreviewRef: DivRef) => { - const isPreviewMode = useSelector(combinedPreviewModeSelector); + const isPreviewMode = useSelector(selectCombinedPreviewMode); const isNavigationSelectedInSettings = useSelector( getIsAppSettingsPaneWithNavigationTabOpen, ); diff --git a/app/client/src/pages/Editor/commons/EditorWrapperContainer.tsx b/app/client/src/pages/Editor/commons/EditorWrapperContainer.tsx index 990004cbbec5..3b34d1beecd4 100644 --- a/app/client/src/pages/Editor/commons/EditorWrapperContainer.tsx +++ b/app/client/src/pages/Editor/commons/EditorWrapperContainer.tsx @@ -2,11 +2,11 @@ import React from "react"; import styled from "styled-components"; import classNames from "classnames"; import { useSelector } from "react-redux"; -import { combinedPreviewModeSelector } from "../../../selectors/editorSelectors"; -import { protectedModeSelector } from "selectors/gitSyncSelectors"; import { IDE_HEADER_HEIGHT } from "@appsmith/ads"; import { BOTTOM_BAR_HEIGHT } from "../../../components/BottomBar/constants"; import { PROTECTED_CALLOUT_HEIGHT } from "../IDE/ProtectedCallout"; +import { useGitProtectedMode } from "../gitSync/hooks/modHooks"; +import { selectCombinedPreviewMode } from "selectors/gitModSelectors"; interface EditorWrapperContainerProps { children: React.ReactNode; @@ -25,8 +25,8 @@ const Wrapper = styled.div<{ `; function EditorWrapperContainer({ children }: EditorWrapperContainerProps) { - const isCombinedPreviewMode = useSelector(combinedPreviewModeSelector); - const isProtectedMode = useSelector(protectedModeSelector); + const isCombinedPreviewMode = useSelector(selectCombinedPreviewMode); + const isProtectedMode = useGitProtectedMode(); return (
{props.showSuccess ? ( diff --git a/app/client/src/pages/Editor/gitSync/hooks/modHooks.ts b/app/client/src/pages/Editor/gitSync/hooks/modHooks.ts new file mode 100644 index 000000000000..e4d4b7fb4b7a --- /dev/null +++ b/app/client/src/pages/Editor/gitSync/hooks/modHooks.ts @@ -0,0 +1,44 @@ +// temp file will be removed after git mod is fully rolled out + +import { useSelector } from "react-redux"; +import { + getCurrentGitBranch, + getIsGitConnected, + protectedModeSelector, +} from "selectors/gitSyncSelectors"; +import { + useGitProtectedMode as useGitProtectedModeNew, + useGitCurrentBranch as useGitCurrentBranchNew, + useGitConnected as useGitConnectedNew, +} from "git"; +import { selectGitModEnabled } from "selectors/gitModSelectors"; + +export function useGitModEnabled() { + const isGitModEnabled = useSelector(selectGitModEnabled); + + return isGitModEnabled; +} + +export function useGitCurrentBranch() { + const isGitModEnabled = useGitModEnabled(); + const currentBranchOld = useSelector(getCurrentGitBranch) ?? null; + const currentBranchNew = useGitCurrentBranchNew(); + + return isGitModEnabled ? currentBranchNew : currentBranchOld; +} + +export function useGitProtectedMode() { + const isGitModEnabled = useGitModEnabled(); + const isProtectedModeOld = useSelector(protectedModeSelector); + const isProtectedModeNew = useGitProtectedModeNew(); + + return isGitModEnabled ? isProtectedModeNew : isProtectedModeOld; +} + +export function useGitConnected() { + const isGitModEnabled = useGitModEnabled(); + const isGitConnectedOld = useSelector(getIsGitConnected); + const isGitConnectedNew = useGitConnectedNew(); + + return isGitModEnabled ? isGitConnectedNew : isGitConnectedOld; +} diff --git a/app/client/src/pages/Editor/index.tsx b/app/client/src/pages/Editor/index.tsx index a7bfff34f2cb..746b7ca56733 100644 --- a/app/client/src/pages/Editor/index.tsx +++ b/app/client/src/pages/Editor/index.tsx @@ -25,12 +25,9 @@ import { getTheme, ThemeMode } from "selectors/themeSelectors"; import { ThemeProvider } from "styled-components"; import type { Theme } from "constants/DefaultTheme"; import GlobalHotKeys from "./GlobalHotKeys"; -import GitSyncModal from "pages/Editor/gitSync/GitSyncModal"; -import DisconnectGitModal from "pages/Editor/gitSync/DisconnectGitModal"; import { setupPageAction, updateCurrentPage } from "actions/pageActions"; import { getCurrentPageId } from "selectors/editorSelectors"; import { getSearchQuery } from "utils/helpers"; -import RepoLimitExceededErrorModal from "./gitSync/RepoLimitExceededErrorModal"; import ImportedApplicationSuccessModal from "./gitSync/ImportSuccessModal"; import { getIsBranchUpdated } from "../utils"; import { APP_MODE } from "entities/App"; @@ -42,16 +39,40 @@ import SignpostingOverlay from "pages/Editor/FirstTimeUserOnboarding/Overlay"; import { editorInitializer } from "../../utils/editor/EditorUtils"; import { widgetInitialisationSuccess } from "../../actions/widgetActions"; import urlBuilder from "ee/entities/URLRedirect/URLAssembly"; -import DisableAutocommitModal from "./gitSync/DisableAutocommitModal"; -import GitSettingsModal from "./gitSync/GitSettingsModal"; -import ReconfigureCDKeyModal from "ee/components/gitComponents/ReconfigureCDKeyModal"; -import DisableCDModal from "ee/components/gitComponents/DisableCDModal"; import { PartialExportModal } from "components/editorComponents/PartialImportExport/PartialExportModal"; import { PartialImportModal } from "components/editorComponents/PartialImportExport/PartialImportModal"; import type { Page } from "entities/Page"; import { AppCURLImportModal } from "ee/pages/Editor/CurlImport"; import { IDE_HEADER_HEIGHT } from "@appsmith/ads"; import GeneratePageModal from "./GeneratePage"; +import { GitModals as NewGitModals } from "git"; +import GitSyncModal from "./gitSync/GitSyncModal"; +import GitSettingsModal from "./gitSync/GitSettingsModal"; +import DisconnectGitModal from "./gitSync/DisconnectGitModal"; +import DisableAutocommitModal from "./gitSync/DisableAutocommitModal"; +import ReconfigureCDKeyModal from "ee/components/gitComponents/ReconfigureCDKeyModal"; +import DisableCDModal from "ee/components/gitComponents/DisableCDModal"; +import RepoLimitExceededErrorModal from "./gitSync/RepoLimitExceededErrorModal"; +import { useGitModEnabled } from "./gitSync/hooks/modHooks"; +import GitApplicationContextProvider from "components/gitContexts/GitApplicationContextProvider"; + +function GitModals() { + const isGitModEnabled = useGitModEnabled(); + + return isGitModEnabled ? ( + + ) : ( + <> + + + + + + + + + ); +} interface EditorProps { currentApplicationId?: string; @@ -195,24 +216,20 @@ class Editor extends Component { {`${this.props.currentApplicationName} | Editor | Appsmith`} - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + +
diff --git a/app/client/src/pages/UserProfile/index.tsx b/app/client/src/pages/UserProfile/index.tsx index a715171bc31d..f77d74fedb50 100644 --- a/app/client/src/pages/UserProfile/index.tsx +++ b/app/client/src/pages/UserProfile/index.tsx @@ -3,12 +3,23 @@ import PageWrapper from "pages/common/PageWrapper"; import styled from "styled-components"; import { Tabs, Tab, TabsList, TabPanel } from "@appsmith/ads"; import General from "./General"; -import GitConfig from "./GitConfig"; +import OldGitConfig from "./GitConfig"; import { useLocation } from "react-router"; import { GIT_PROFILE_ROUTE } from "constants/routes"; import { BackButton } from "components/utils/helperComponents"; import { useDispatch } from "react-redux"; import { fetchGlobalGitConfigInit } from "actions/gitSyncActions"; +import { useGitModEnabled } from "pages/Editor/gitSync/hooks/modHooks"; +import { + fetchGitGlobalProfile, + GitGlobalProfile as GitGlobalProfileNew, +} from "git"; + +function GitGlobalProfile() { + const isGitModEnabled = useGitModEnabled(); + + return isGitModEnabled ? : ; +} const ProfileWrapper = styled.div` width: 978px; @@ -25,6 +36,7 @@ const ProfileWrapper = styled.div` function UserProfile() { const location = useLocation(); const dispatch = useDispatch(); + const isGitModEnabled = useGitModEnabled(); let initialTab = "general"; const tabs = [ @@ -39,7 +51,7 @@ function UserProfile() { tabs.push({ key: "gitConfig", title: "Git user config", - panelComponent: , + panelComponent: , icon: "git-branch", }); @@ -49,10 +61,16 @@ function UserProfile() { const [selectedTab, setSelectedTab] = useState(initialTab); - useEffect(() => { - // onMount Fetch Global config - dispatch(fetchGlobalGitConfigInit()); - }, []); + useEffect( + function fetchGlobalGitConfigOnInitEffect() { + if (isGitModEnabled) { + dispatch(fetchGitGlobalProfile()); + } else { + dispatch(fetchGlobalGitConfigInit()); + } + }, + [dispatch, isGitModEnabled], + ); return ( diff --git a/app/client/src/pages/common/ImportModal.tsx b/app/client/src/pages/common/ImportModal.tsx index b19974788529..12cefc5dec8c 100644 --- a/app/client/src/pages/common/ImportModal.tsx +++ b/app/client/src/pages/common/ImportModal.tsx @@ -30,6 +30,8 @@ import { import useMessages from "ee/hooks/importModal/useMessages"; import useMethods from "ee/hooks/importModal/useMethods"; import { getIsAnvilLayoutEnabled } from "layoutSystems/anvil/integrations/selectors"; +import { useGitModEnabled } from "pages/Editor/gitSync/hooks/modHooks"; +import { toggleGitImportModal } from "git"; const TextWrapper = styled.div` padding: 0; @@ -203,6 +205,7 @@ function ImportModal(props: ImportModalProps) { toEditor = false, workspaceId, } = props; + const isGitModEnabled = useGitModEnabled(); const { mainDescription, title } = useMessages(); const { appFileToBeUploaded, @@ -223,15 +226,21 @@ function ImportModal(props: ImportModalProps) { setWorkspaceIdForImport({ editorId: editorId || "", workspaceId }), ); - dispatch( - setIsGitSyncModalOpen({ - isOpen: true, - tab: GitSyncModalTab.GIT_CONNECTION, - }), - ); - - // dispatch(setIsReconnectingDatasourcesModalOpen({ isOpen: true })); - }, []); + if (isGitModEnabled) { + dispatch( + toggleGitImportModal({ + open: true, + }), + ); + } else { + dispatch( + setIsGitSyncModalOpen({ + isOpen: true, + tab: GitSyncModalTab.GIT_CONNECTION, + }), + ); + } + }, [dispatch, editorId, isGitModEnabled, onClose, workspaceId]); useEffect(() => { // finished of importing application diff --git a/app/client/src/sagas/ActionExecution/StoreActionSaga.ts b/app/client/src/sagas/ActionExecution/StoreActionSaga.ts index 4bcd909aabf0..ee6d99630ffd 100644 --- a/app/client/src/sagas/ActionExecution/StoreActionSaga.ts +++ b/app/client/src/sagas/ActionExecution/StoreActionSaga.ts @@ -4,7 +4,6 @@ import localStorage from "utils/localStorage"; import { updateAppStore } from "actions/pageActions"; import AppsmithConsole from "utils/AppsmithConsole"; import { getAppStoreData } from "ee/selectors/entitiesSelector"; -import { getCurrentGitBranch } from "selectors/gitSyncSelectors"; import { getCurrentApplicationId } from "selectors/editorSelectors"; import type { AppStoreState } from "reducers/entityReducers/appReducer"; import { Severity, LOG_CATEGORY } from "entities/AppsmithConsole"; @@ -13,6 +12,7 @@ import type { TRemoveValueDescription, TStoreValueDescription, } from "workers/Evaluation/fns/storeFns"; +import { selectGitApplicationCurrentBranch } from "selectors/gitModSelectors"; type StoreOperation = | TStoreValueDescription @@ -21,7 +21,9 @@ type StoreOperation = export function* handleStoreOperations(triggers: StoreOperation[]) { const applicationId: string = yield select(getCurrentApplicationId); - const branch: string | undefined = yield select(getCurrentGitBranch); + const branch: string | undefined = yield select( + selectGitApplicationCurrentBranch, + ); const appStoreName = getAppStoreName(applicationId, branch); const existingLocalStore = localStorage.getItem(appStoreName) || "{}"; let parsedLocalStore = JSON.parse(existingLocalStore); diff --git a/app/client/src/sagas/DatasourcesSagas.ts b/app/client/src/sagas/DatasourcesSagas.ts index 189fe5b80bc4..841be4eae950 100644 --- a/app/client/src/sagas/DatasourcesSagas.ts +++ b/app/client/src/sagas/DatasourcesSagas.ts @@ -714,6 +714,7 @@ function* redirectAuthorizationCodeSaga( const { contextId, contextType, datasourceId, pluginType } = actionPayload.payload; const isImport: string = yield select(getWorkspaceIdForImport); + // ! git mod - not sure how to handle this, there is no definition for the artifact used here const branchName: string | undefined = yield select(getCurrentGitBranch); if (pluginType === PluginType.API) { diff --git a/app/client/src/sagas/FocusRetentionSaga.ts b/app/client/src/sagas/FocusRetentionSaga.ts index 45232d9560dc..e92be7bae11b 100644 --- a/app/client/src/sagas/FocusRetentionSaga.ts +++ b/app/client/src/sagas/FocusRetentionSaga.ts @@ -18,10 +18,10 @@ import type { AppsmithLocationState } from "utils/history"; import type { Action } from "entities/Action"; import { getAction, getPlugin } from "ee/selectors/entitiesSelector"; import type { Plugin } from "api/PluginApi"; -import { getCurrentGitBranch } from "selectors/gitSyncSelectors"; import { getIDETypeByUrl } from "ee/entities/IDE/utils"; import { getIDEFocusStrategy } from "ee/navigation/FocusStrategy"; import { IDE_TYPE } from "ee/entities/IDE/constants"; +import { selectGitApplicationCurrentBranch } from "selectors/gitModSelectors"; export interface FocusPath { key: string; @@ -123,7 +123,9 @@ class FocusRetention { } public *handleRemoveFocusHistory(url: string) { - const branch: string | undefined = yield select(getCurrentGitBranch); + const branch: string | undefined = yield select( + selectGitApplicationCurrentBranch, + ); const removeKeys: string[] = []; const focusEntityInfo = identifyEntityFromPath(url); diff --git a/app/client/src/sagas/GlobalSearchSagas.ts b/app/client/src/sagas/GlobalSearchSagas.ts index 17cf81e719b3..93e29c0b29dc 100644 --- a/app/client/src/sagas/GlobalSearchSagas.ts +++ b/app/client/src/sagas/GlobalSearchSagas.ts @@ -21,19 +21,21 @@ import { } from "selectors/editorSelectors"; import type { RecentEntity } from "components/editorComponents/GlobalSearch/utils"; import log from "loglevel"; -import { getCurrentGitBranch } from "selectors/gitSyncSelectors"; import type { FocusEntity, FocusEntityInfo } from "navigation/FocusEntity"; import { convertToPageIdSelector } from "selectors/pageListSelectors"; +import { selectGitApplicationCurrentBranch } from "selectors/gitModSelectors"; const getRecentEntitiesKey = (applicationId: string, branch?: string) => branch ? `${applicationId}-${branch}` : applicationId; export function* updateRecentEntitySaga(entityInfo: FocusEntityInfo) { try { - const branch: string | undefined = yield select(getCurrentGitBranch); - const applicationId: string = yield select(getCurrentApplicationId); + const branch: string | undefined = yield select( + selectGitApplicationCurrentBranch, + ); + const recentEntitiesRestored: boolean = yield select( (state: AppState) => state.ui.globalSearch.recentEntitiesRestored, ); diff --git a/app/client/src/sagas/autoHeightSagas/helpers.ts b/app/client/src/sagas/autoHeightSagas/helpers.ts index da276f65d769..3ac3086a9d53 100644 --- a/app/client/src/sagas/autoHeightSagas/helpers.ts +++ b/app/client/src/sagas/autoHeightSagas/helpers.ts @@ -11,7 +11,7 @@ import type { } from "reducers/entityReducers/canvasWidgetsReducer"; import { select } from "redux-saga/effects"; import { getWidgetMetaProps, getWidgets } from "sagas/selectors"; -import { combinedPreviewModeSelector } from "selectors/editorSelectors"; +import { selectCombinedPreviewMode } from "selectors/gitModSelectors"; import { getAppMode } from "ee/selectors/entitiesSelector"; import { isAutoHeightEnabledForWidget } from "widgets/WidgetUtils"; import { getCanvasHeightOffset } from "utils/WidgetSizeUtils"; @@ -20,7 +20,7 @@ import type { DataTree } from "entities/DataTree/dataTreeTypes"; import { getDataTree } from "selectors/dataTreeSelectors"; export function* shouldWidgetsCollapse() { - const isPreviewMode: boolean = yield select(combinedPreviewModeSelector); + const isPreviewMode: boolean = yield select(selectCombinedPreviewMode); const appMode: APP_MODE = yield select(getAppMode); return isPreviewMode || appMode === APP_MODE.PUBLISHED; diff --git a/app/client/src/selectors/debuggerSelectors.tsx b/app/client/src/selectors/debuggerSelectors.tsx index a827b65b3a0e..5c7b42516c29 100644 --- a/app/client/src/selectors/debuggerSelectors.tsx +++ b/app/client/src/selectors/debuggerSelectors.tsx @@ -11,8 +11,8 @@ import { isWidget, } from "ee/workers/Evaluation/evaluationUtils"; import { getDataTree } from "./dataTreeSelectors"; -import { combinedPreviewModeSelector } from "./editorSelectors"; import type { CanvasDebuggerState } from "reducers/uiReducers/debuggerReducer"; +import { selectCombinedPreviewMode } from "./gitModSelectors"; interface ErrorObejct { [k: string]: Log; @@ -169,7 +169,7 @@ export const getDebuggerOpen = (state: AppState) => state.ui.debugger.isOpen; export const showDebuggerFlag = createSelector( getDebuggerOpen, - combinedPreviewModeSelector, + selectCombinedPreviewMode, (isOpen, isPreview) => isOpen && !isPreview, ); diff --git a/app/client/src/selectors/editorSelectors.tsx b/app/client/src/selectors/editorSelectors.tsx index ee3560dd5034..39bd1d46c1b6 100644 --- a/app/client/src/selectors/editorSelectors.tsx +++ b/app/client/src/selectors/editorSelectors.tsx @@ -990,9 +990,3 @@ export const getGsheetToken = (state: AppState) => export const getGsheetProjectID = (state: AppState) => state.entities.datasources.gsheetProjectID; - -export const combinedPreviewModeSelector = createSelector( - previewModeSelector, - protectedModeSelector, - (isPreviewMode, isProtectedMode) => isPreviewMode || isProtectedMode, -); diff --git a/app/client/src/selectors/gitModSelectors.ts b/app/client/src/selectors/gitModSelectors.ts new file mode 100644 index 000000000000..35fe32fbbff7 --- /dev/null +++ b/app/client/src/selectors/gitModSelectors.ts @@ -0,0 +1,50 @@ +// temp file will be removed after git mod is fully rolled out + +import { selectFeatureFlags } from "ee/selectors/featureFlagsSelectors"; +import { createSelector } from "reselect"; +import { getCurrentGitBranch, protectedModeSelector } from "./gitSyncSelectors"; +import { + selectGitCurrentBranch as selectGitCurrentBranchNew, + selectGitProtectedMode as selectGitProtectedModeNew, +} from "git"; +import { + getCurrentBaseApplicationId, + previewModeSelector, +} from "./editorSelectors"; +import { applicationArtifact } from "git/artifact-helpers/application"; + +export const selectGitModEnabled = createSelector( + selectFeatureFlags, + (featureFlags) => featureFlags.release_git_modularisation_enabled ?? false, +); + +export const selectGitApplicationArtifactDef = createSelector( + getCurrentBaseApplicationId, + (baseApplicationId) => applicationArtifact(baseApplicationId), +); + +export const selectGitApplicationCurrentBranch = createSelector( + selectGitModEnabled, + getCurrentGitBranch, + (state) => + selectGitCurrentBranchNew(state, selectGitApplicationArtifactDef(state)), + (isGitModEnabled, currentBranchOld, currentBranchNew) => { + return isGitModEnabled ? currentBranchNew : currentBranchOld; + }, +); + +export const selectGitApplicationProtectedMode = createSelector( + selectGitModEnabled, + protectedModeSelector, + (state) => + selectGitProtectedModeNew(state, selectGitApplicationArtifactDef(state)), + (isGitModEnabled, protectedModeOld, protectedModeNew) => { + return isGitModEnabled ? protectedModeNew : protectedModeOld; + }, +); + +export const selectCombinedPreviewMode = createSelector( + previewModeSelector, + selectGitApplicationProtectedMode, + (isPreviewMode, isProtectedMode) => isPreviewMode || isProtectedMode, +); diff --git a/app/client/src/selectors/widgetDragSelectors.ts b/app/client/src/selectors/widgetDragSelectors.ts index 0a2b35eb7e1f..21d5848d5175 100644 --- a/app/client/src/selectors/widgetDragSelectors.ts +++ b/app/client/src/selectors/widgetDragSelectors.ts @@ -1,11 +1,9 @@ import type { AppState } from "ee/reducers"; import { createSelector } from "reselect"; import { getIsAppSettingsPaneWithNavigationTabOpen } from "./appSettingsPaneSelectors"; -import { - combinedPreviewModeSelector, - snipingModeSelector, -} from "./editorSelectors"; +import { snipingModeSelector } from "./editorSelectors"; import { getWidgetSelectionBlock } from "./ui"; +import { selectCombinedPreviewMode } from "./gitModSelectors"; export const getIsDragging = (state: AppState) => state.ui.widgetDragResize.isDragging; @@ -23,7 +21,7 @@ export const getShouldAllowDrag = createSelector( getIsResizing, getIsDragging, getIsDraggingDisabledInEditor, - combinedPreviewModeSelector, + selectCombinedPreviewMode, snipingModeSelector, getIsAppSettingsPaneWithNavigationTabOpen, getWidgetSelectionBlock, diff --git a/app/client/src/selectors/widgetSelectors.ts b/app/client/src/selectors/widgetSelectors.ts index 4d45777ef4c9..35d648da50bf 100644 --- a/app/client/src/selectors/widgetSelectors.ts +++ b/app/client/src/selectors/widgetSelectors.ts @@ -21,8 +21,8 @@ import { APP_MODE } from "entities/App"; import { getIsTableFilterPaneVisible } from "selectors/tableFilterSelectors"; import { getIsAutoHeightWithLimitsChanging } from "utils/hooks/autoHeightUIHooks"; import { getIsPropertyPaneVisible } from "./propertyPaneSelectors"; -import { combinedPreviewModeSelector } from "./editorSelectors"; import { getIsAnvilLayout } from "layoutSystems/anvil/integrations/selectors"; +import { selectCombinedPreviewMode } from "./gitModSelectors"; export const getIsDraggingOrResizing = (state: AppState) => state.ui.widgetDragResize.isResizing || state.ui.widgetDragResize.isDragging; @@ -186,7 +186,7 @@ export const shouldWidgetIgnoreClicksSelector = (widgetId: string) => { (state: AppState) => state.ui.widgetDragResize.isDragging, (state: AppState) => state.ui.canvasSelection.isDraggingForSelection, getAppMode, - combinedPreviewModeSelector, + selectCombinedPreviewMode, getIsAutoHeightWithLimitsChanging, getAltBlockWidgetSelection, ( diff --git a/app/client/src/utils/hooks/useAllowEditorDragToSelect.ts b/app/client/src/utils/hooks/useAllowEditorDragToSelect.ts index e074a099ac70..a09f5492d648 100644 --- a/app/client/src/utils/hooks/useAllowEditorDragToSelect.ts +++ b/app/client/src/utils/hooks/useAllowEditorDragToSelect.ts @@ -1,13 +1,11 @@ import type { AppState } from "ee/reducers"; -import { - snipingModeSelector, - combinedPreviewModeSelector, -} from "selectors/editorSelectors"; +import { snipingModeSelector } from "selectors/editorSelectors"; import { useSelector } from "react-redux"; import { getIsAppSettingsPaneWithNavigationTabOpen } from "selectors/appSettingsPaneSelectors"; import { getLayoutSystemType } from "selectors/layoutSystemSelectors"; import { LayoutSystemTypes } from "layoutSystems/types"; import { getWidgetSelectionBlock } from "../../selectors/ui"; +import { selectCombinedPreviewMode } from "selectors/gitModSelectors"; export const useAllowEditorDragToSelect = () => { // This state tells us whether a `ResizableComponent` is resizing @@ -42,7 +40,7 @@ export const useAllowEditorDragToSelect = () => { // True when any widget is dragging or resizing, including this one const isResizingOrDragging = !!isResizing || !!isDragging || !!isSelecting; const isSnipingMode = useSelector(snipingModeSelector); - const isPreviewMode = useSelector(combinedPreviewModeSelector); + const isPreviewMode = useSelector(selectCombinedPreviewMode); const isAppSettingsPaneWithNavigationTabOpen = useSelector( getIsAppSettingsPaneWithNavigationTabOpen, ); diff --git a/app/client/src/utils/hooks/useHoverToFocusWidget.ts b/app/client/src/utils/hooks/useHoverToFocusWidget.ts index 10e5f764f06e..a6cf7962de9a 100644 --- a/app/client/src/utils/hooks/useHoverToFocusWidget.ts +++ b/app/client/src/utils/hooks/useHoverToFocusWidget.ts @@ -2,7 +2,7 @@ import { useWidgetSelection } from "./useWidgetSelection"; import { useSelector } from "react-redux"; import { isWidgetFocused } from "selectors/widgetSelectors"; import { getAnvilSpaceDistributionStatus } from "layoutSystems/anvil/integrations/selectors"; -import { combinedPreviewModeSelector } from "selectors/editorSelectors"; +import { selectCombinedPreviewMode } from "selectors/gitModSelectors"; import type { AppState } from "ee/reducers"; import type React from "react"; import { useCurrentAppState } from "pages/Editor/IDE/hooks/useCurrentAppState"; @@ -35,7 +35,7 @@ export const useHoverToFocusWidget = ( const isResizingOrDragging = isResizing || isDragging; // This state tells us whether space redistribution is in process const isDistributingSpace = useSelector(getAnvilSpaceDistributionStatus); - const isPreviewMode = useSelector(combinedPreviewModeSelector); + const isPreviewMode = useSelector(selectCombinedPreviewMode); // When mouse is over this draggable const handleMouseOver = (e: React.MouseEvent) => { focusWidget && diff --git a/app/client/src/widgets/ChartWidget/component/index.test.tsx b/app/client/src/widgets/ChartWidget/component/index.test.tsx index 8c043acb36a3..ee53792993a8 100644 --- a/app/client/src/widgets/ChartWidget/component/index.test.tsx +++ b/app/client/src/widgets/ChartWidget/component/index.test.tsx @@ -22,6 +22,11 @@ import { APP_MODE } from "entities/App"; // eslint-disable-next-line @typescript-eslint/no-explicit-any let container: any; +jest.mock("selectors/gitModSelectors", () => ({ + ...jest.requireActual("selectors/gitModSelectors"), + selectCombinedPreviewMode: jest.fn(() => false), +})); + describe("Chart Widget", () => { const seriesData1: ChartData = { seriesName: "series1", diff --git a/app/client/src/widgets/ChartWidget/component/index.tsx b/app/client/src/widgets/ChartWidget/component/index.tsx index 4ed693b142c3..f2a3280bd7a1 100644 --- a/app/client/src/widgets/ChartWidget/component/index.tsx +++ b/app/client/src/widgets/ChartWidget/component/index.tsx @@ -28,7 +28,7 @@ import { CustomEChartIFrameComponent } from "./CustomEChartIFrameComponent"; import type { AppState } from "ee/reducers"; import { connect } from "react-redux"; import { getWidgetPropsForPropertyPane } from "selectors/propertyPaneSelectors"; -import { combinedPreviewModeSelector } from "selectors/editorSelectors"; +import { selectCombinedPreviewMode } from "selectors/gitModSelectors"; import { getAppMode } from "ee/selectors/applicationSelectors"; import { APP_MODE } from "entities/App"; // Leaving this require here. Ref: https://stackoverflow.com/questions/41292559/could-not-find-a-declaration-file-for-module-module-name-path-to-module-nam/42505940#42505940 @@ -406,7 +406,7 @@ export const mapStateToProps = ( state: AppState, ownProps: ChartComponentProps, ) => { - const isPreviewMode = combinedPreviewModeSelector(state); + const isPreviewMode = selectCombinedPreviewMode(state); const appMode = getAppMode(state); return { diff --git a/app/client/src/widgets/CustomWidget/component/index.tsx b/app/client/src/widgets/CustomWidget/component/index.tsx index eb6740b48cd0..a3cf98d4afbb 100644 --- a/app/client/src/widgets/CustomWidget/component/index.tsx +++ b/app/client/src/widgets/CustomWidget/component/index.tsx @@ -19,7 +19,7 @@ import type { BoxShadow } from "components/designSystems/appsmith/WidgetStyleCon import type { Color } from "constants/Colors"; import { connect } from "react-redux"; import type { AppState } from "ee/reducers"; -import { combinedPreviewModeSelector } from "selectors/editorSelectors"; +import { selectCombinedPreviewMode } from "selectors/gitModSelectors"; import { getWidgetPropsForPropertyPane } from "selectors/propertyPaneSelectors"; import AnalyticsUtil from "ee/utils/AnalyticsUtil"; import { EVENTS } from "./customWidgetscript"; @@ -311,7 +311,7 @@ export const mapStateToProps = ( state: AppState, ownProps: CustomComponentProps, ) => { - const isPreviewMode = combinedPreviewModeSelector(state); + const isPreviewMode = selectCombinedPreviewMode(state); return { needsOverlay: diff --git a/app/client/src/widgets/IframeWidget/component/index.tsx b/app/client/src/widgets/IframeWidget/component/index.tsx index 1958ebd55e36..b16f5bdb2fcb 100644 --- a/app/client/src/widgets/IframeWidget/component/index.tsx +++ b/app/client/src/widgets/IframeWidget/component/index.tsx @@ -9,7 +9,7 @@ import { getAppMode } from "ee/selectors/applicationSelectors"; import { APP_MODE } from "entities/App"; import type { RenderMode } from "constants/WidgetConstants"; import { getAppsmithConfigs } from "ee/configs"; -import { combinedPreviewModeSelector } from "selectors/editorSelectors"; +import { selectCombinedPreviewMode } from "selectors/gitModSelectors"; interface IframeContainerProps { borderColor?: string; @@ -145,7 +145,7 @@ function IframeComponent(props: IframeComponentProps) { }, [srcDoc]); const appMode = useSelector(getAppMode); - const isPreviewMode = useSelector(combinedPreviewModeSelector); + const isPreviewMode = useSelector(selectCombinedPreviewMode); const selectedWidget = useSelector(getWidgetPropsForPropertyPane); return ( diff --git a/app/client/src/widgets/withWidgetProps.tsx b/app/client/src/widgets/withWidgetProps.tsx index 73dfd519687b..5a0f13d6c19d 100644 --- a/app/client/src/widgets/withWidgetProps.tsx +++ b/app/client/src/widgets/withWidgetProps.tsx @@ -25,7 +25,6 @@ import { getMetaWidget, getIsAutoLayoutMobileBreakPoint, getCanvasWidth, - combinedPreviewModeSelector, } from "selectors/editorSelectors"; import { createCanvasWidget, @@ -50,6 +49,7 @@ import { isWidgetSelectedForPropertyPane } from "selectors/propertyPaneSelectors import WidgetFactory from "WidgetProvider/factory"; import { getIsAnvilLayout } from "layoutSystems/anvil/integrations/selectors"; import { endSpan, startRootSpan } from "instrumentation/generateTraces"; +import { selectCombinedPreviewMode } from "selectors/gitModSelectors"; const WIDGETS_WITH_CHILD_WIDGETS = ["LIST_WIDGET", "FORM_WIDGET"]; const WIDGETS_REQUIRING_SELECTED_ANCESTRY = ["MODAL_WIDGET", "TABS_WIDGET"]; @@ -69,7 +69,7 @@ function withWidgetProps(WrappedWidget: typeof BaseWidget) { } = props; const span = startRootSpan("withWidgetProps", { widgetType: type }); - const isPreviewMode = useSelector(combinedPreviewModeSelector); + const isPreviewMode = useSelector(selectCombinedPreviewMode); const canvasWidget = useSelector((state: AppState) => getWidget(state, widgetId), diff --git a/app/client/test/testUtils.tsx b/app/client/test/testUtils.tsx index 9b99d698bb90..0d57bddfc09a 100644 --- a/app/client/test/testUtils.tsx +++ b/app/client/test/testUtils.tsx @@ -49,9 +49,12 @@ interface State { } const setupState = (state?: State) => { let reduxStore = store; + window.history.pushState({}, "Appsmith", state?.url || "/"); + if (state && (state.initialState || state.featureFlags)) { reduxStore = testStore(state.initialState || {}); + if (state.featureFlags) { reduxStore.dispatch( fetchFeatureFlagsSuccess({ @@ -61,10 +64,12 @@ const setupState = (state?: State) => { ); } } + if (state && state.sagasToRun) { reduxStore = testStoreWithTestMiddleWare(reduxStore.getState()); testSagaMiddleware.run(() => rootSaga(state.sagasToRun)); } + const defaultTheme = getCurrentThemeDetails(reduxStore.getState()); return { reduxStore, defaultTheme }; @@ -76,6 +81,7 @@ const customRender = ( options?: Omit, ) => { const { defaultTheme, reduxStore } = setupState(state); + return render( @@ -92,6 +98,7 @@ const customRender = ( const hookWrapper = (state: State) => { return ({ children }: { children: ReactElement }) => { const { defaultTheme, reduxStore } = setupState(state); + return ( From 649338d18850299833bf029c929fb66720565919 Mon Sep 17 00:00:00 2001 From: Manish Kumar <107841575+sondermanish@users.noreply.github.com> Date: Sun, 5 Jan 2025 21:34:36 +0530 Subject: [PATCH 20/40] chore: added git resource map consumption (#38470) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description - Added git resource map consumption Fixes #`Issue Number` _or_ Fixes `Issue URL` > [!WARNING] > _If no issue exists, please create an issue first, and check with the maintainers if the issue is valid._ ## Automation /ok-to-test tags="@tag.Git" it=true ### :mag: Cypress test results > [!TIP] > 🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉 > Workflow run: > Commit: 8877a5b92ae5bcb25b428ed50fe09a8d0b767e35 > Cypress dashboard. > Tags: `@tag.Git` > Spec: >
Fri, 03 Jan 2025 16:35:41 UTC ## Communication Should the DevRel and Marketing teams inform users about this change? - [ ] Yes - [ ] No ## Summary by CodeRabbit Based on the comprehensive summary of changes, here are the release notes: ## Release Notes - **Git Integration Enhancements** - Improved Git reference handling across multiple service methods - Enhanced support for artifact migration and JSON schema transformations - Refined parameter management for Git-related operations - **Method Signature Updates** - Standardized method signatures across Git-related services - Added support for more flexible reference type handling - Improved consistency in method parameter ordering - **Backend Improvements** - Updated JSON migration processes - Enhanced error handling in Git file system operations - Expanded support for different artifact types in Git workflows - **Testing and Validation** - Updated test cases to reflect new method signatures - Improved test coverage for Git-related functionality These changes primarily focus on backend improvements to the Git integration system, providing more robust and flexible handling of artifacts and references. --- .../appsmith/git/files/FileUtilsCEImpl.java | 7 ++ .../appsmith/external/git/FileInterface.java | 2 + .../git/ApplicationGitFileUtilsCEImpl.java | 14 ++- .../ApplicationImportServiceCEImpl.java | 8 +- .../git/central/CentralGitServiceCE.java | 18 +-- .../git/central/CentralGitServiceCEImpl.java | 51 ++++----- .../GitApplicationControllerCE.java | 18 +-- .../server/git/fs/GitFSServiceCEImpl.java | 14 +-- .../helpers/ce/ArtifactGitFileUtilsCE.java | 4 + .../helpers/ce/CommonGitFileUtilsCE.java | 104 +++++++++++++++++- .../migrations/JsonSchemaMigration.java | 12 +- .../ce/CreateDBTablePageSolutionCEImpl.java | 5 +- .../server/git/CommonGitServiceCETest.java | 4 +- .../AutoCommitEventHandlerImplTest.java | 6 +- .../git/autocommit/AutoCommitServiceTest.java | 7 +- .../server/git/ops/GitCommitTests.java | 8 +- .../server/git/ops/GitConnectTests.java | 20 ++-- .../server/git/ops/GitDiscardTests.java | 10 +- .../ExchangeJsonConversionTests.java | 2 +- .../server/helpers/GitFileUtilsTest.java | 4 +- .../imports/internal/ImportServiceTests.java | 7 +- .../migrations/JsonSchemaMigrationTest.java | 4 +- ...portApplicationTransactionServiceTest.java | 4 +- .../server/git/ArtifactBuilderExtension.java | 2 +- 24 files changed, 231 insertions(+), 104 deletions(-) diff --git a/app/server/appsmith-git/src/main/java/com/appsmith/git/files/FileUtilsCEImpl.java b/app/server/appsmith-git/src/main/java/com/appsmith/git/files/FileUtilsCEImpl.java index b7f395022124..7d68aaf19e50 100644 --- a/app/server/appsmith-git/src/main/java/com/appsmith/git/files/FileUtilsCEImpl.java +++ b/app/server/appsmith-git/src/main/java/com/appsmith/git/files/FileUtilsCEImpl.java @@ -674,6 +674,13 @@ public Mono reconstructApplicationReferenceFromGitRepo( .subscribeOn(scheduler); } + @Override + public Mono constructGitResourceMapFromGitRepo(Path repositorySuffix, String refName) { + // TODO: check that we need to checkout to the ref + Path repositoryPath = Paths.get(gitServiceConfig.getGitRootPath()).resolve(repositorySuffix); + return Mono.fromCallable(() -> fetchGitResourceMap(repositoryPath)).subscribeOn(scheduler); + } + /** * This is used to initialize repo with Readme file when the application is connected to remote repo * diff --git a/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/git/FileInterface.java b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/git/FileInterface.java index d5422a24ef48..c655ef2bfbe8 100644 --- a/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/git/FileInterface.java +++ b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/git/FileInterface.java @@ -50,6 +50,8 @@ Mono saveArtifactToGitRepo(Path baseRepoSuffix, GitResourceMap gitResource Mono reconstructApplicationReferenceFromGitRepo( String organisationId, String baseApplicationId, String repoName, String branchName); + Mono constructGitResourceMapFromGitRepo(Path repositorySuffix, String refName); + /** * This method just reconstructs the metdata of the json from git repo. * diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/applications/git/ApplicationGitFileUtilsCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/applications/git/ApplicationGitFileUtilsCEImpl.java index a5628db2df12..79aef2cb351c 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/applications/git/ApplicationGitFileUtilsCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/applications/git/ApplicationGitFileUtilsCEImpl.java @@ -1,6 +1,7 @@ package com.appsmith.server.applications.git; import com.appsmith.external.git.FileInterface; +import com.appsmith.external.git.constants.ce.RefType; import com.appsmith.external.git.models.GitResourceIdentity; import com.appsmith.external.git.models.GitResourceMap; import com.appsmith.external.git.models.GitResourceType; @@ -29,6 +30,7 @@ import com.appsmith.server.dtos.PageDTO; import com.appsmith.server.exceptions.AppsmithError; import com.appsmith.server.exceptions.AppsmithException; +import com.appsmith.server.git.dtos.ArtifactJsonTransformationDTO; import com.appsmith.server.helpers.CollectionUtils; import com.appsmith.server.helpers.ce.ArtifactGitFileUtilsCE; import com.appsmith.server.migrations.JsonSchemaMigration; @@ -467,10 +469,20 @@ public Mono reconstructArtifactExchangeJsonFromFilesInRepo ApplicationJson applicationJson = getApplicationJsonFromGitReference(applicationReference); copyNestedNonNullProperties(metadata, applicationJson); return jsonSchemaMigration.migrateApplicationJsonToLatestSchema( - applicationJson, baseArtifactId, branchName); + applicationJson, baseArtifactId, branchName, RefType.branch); }); } + @Override + public Mono performJsonMigration( + ArtifactJsonTransformationDTO jsonTransformationDTO, ArtifactExchangeJson artifactExchangeJson) { + String baseArtifactId = jsonTransformationDTO.getBaseArtifactId(); + String refName = jsonTransformationDTO.getRefName(); + RefType refType = jsonTransformationDTO.getRefType(); + return jsonSchemaMigration.migrateArtifactExchangeJsonToLatestSchema( + artifactExchangeJson, baseArtifactId, refName, refType); + } + protected List getApplicationResource(Map resources, Type type) { List deserializedResources = new ArrayList<>(); 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 1ab22bc3d8f5..6d876dd96c38 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 @@ -1,5 +1,6 @@ package com.appsmith.server.applications.imports; +import com.appsmith.external.git.constants.ce.RefType; import com.appsmith.external.models.Datasource; import com.appsmith.external.models.DatasourceStorageDTO; import com.appsmith.server.applications.base.ApplicationService; @@ -643,18 +644,21 @@ public Mono migrateArtifactExchangeJson( ApplicationJson applicationJson = (ApplicationJson) artifactExchangeJson; if (!hasText(branchedArtifactId)) { - return jsonSchemaMigration.migrateApplicationJsonToLatestSchema(applicationJson, null, null); + return jsonSchemaMigration.migrateApplicationJsonToLatestSchema(applicationJson, null, null, null); } return applicationService.findById(branchedArtifactId).flatMap(application -> { String baseArtifactId = application.getBaseId(); String refName = null; + RefType refType = null; if (application.getGitArtifactMetadata() != null) { refName = application.getGitArtifactMetadata().getRefName(); + refType = application.getGitArtifactMetadata().getRefType(); } - return jsonSchemaMigration.migrateApplicationJsonToLatestSchema(applicationJson, baseArtifactId, refName); + return jsonSchemaMigration.migrateApplicationJsonToLatestSchema( + applicationJson, baseArtifactId, refName, refType); }); } } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCE.java index a9fc22f6a066..ccadec5b3c63 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCE.java @@ -25,9 +25,9 @@ Mono importArtifactFromGit( Mono connectArtifactToGit( String baseArtifactId, + ArtifactType artifactType, GitConnectDTO gitConnectDTO, String originHeader, - ArtifactType artifactType, GitType gitType); Mono commitArtifact( @@ -36,44 +36,44 @@ Mono commitArtifact( Mono detachRemote(String branchedArtifactId, ArtifactType artifactType, GitType gitType); Mono> listBranchForArtifact( - String branchedArtifactId, Boolean pruneBranches, ArtifactType artifactType, GitType gitType); + String branchedArtifactId, ArtifactType artifactType, Boolean pruneBranches, GitType gitType); Mono fetchRemoteChanges( String referenceArtifactId, - boolean isFileLock, ArtifactType artifactType, + boolean isFileLock, GitType gitType, RefType refType); Mono discardChanges(String branchedArtifactId, ArtifactType artifactType, GitType gitType); Mono getStatus( - String branchedArtifactId, boolean compareRemote, ArtifactType artifactType, GitType gitType); + String branchedArtifactId, ArtifactType artifactType, boolean compareRemote, GitType gitType); Mono pullArtifact(String branchedArtifactId, ArtifactType artifactType, GitType gitType); Mono checkoutReference( String referenceArtifactId, + ArtifactType artifactType, GitRefDTO gitRefDTO, boolean addFileLock, - ArtifactType artifactType, GitType gitType); Mono createReference( - String referencedArtifactId, GitRefDTO refDTO, ArtifactType artifactType, GitType gitType); + String referencedArtifactId, ArtifactType artifactType, GitRefDTO refDTO, GitType gitType); Mono deleteGitReference( - String baseArtifactId, GitRefDTO gitRefDTO, ArtifactType artifactType, GitType gitType); + String baseArtifactId, ArtifactType artifactType, GitRefDTO gitRefDTO, GitType gitType); Mono> updateProtectedBranches( - String baseArtifactId, List branchNames, ArtifactType artifactType); + String baseArtifactId, ArtifactType artifactType, List branchNames); Mono> getProtectedBranches(String baseArtifactId, ArtifactType artifactType); Mono toggleAutoCommitEnabled(String baseArtifactId, ArtifactType artifactType); Mono getAutoCommitProgress( - String baseArtifactId, String branchName, ArtifactType artifactType); + String baseArtifactId, ArtifactType artifactType, String branchName); Mono generateSSHKey(String keyType); diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCEImpl.java index bc6c38ebabad..db895a42bb83 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/central/CentralGitServiceCEImpl.java @@ -364,9 +364,9 @@ private boolean checkIsDatasourceNameConflict( @Override public Mono checkoutReference( String referenceArtifactId, + ArtifactType artifactType, GitRefDTO gitRefDTO, boolean addFileLock, - ArtifactType artifactType, GitType gitType) { if (gitRefDTO == null || !hasText(gitRefDTO.getRefName())) { @@ -423,6 +423,7 @@ protected Mono checkoutReference( ArtifactJsonTransformationDTO jsonTransformationDTO = new ArtifactJsonTransformationDTO(); jsonTransformationDTO.setWorkspaceId(baseArtifact.getWorkspaceId()); jsonTransformationDTO.setBaseArtifactId(baseGitMetadata.getDefaultArtifactId()); + jsonTransformationDTO.setRefName(finalRefName); jsonTransformationDTO.setRefType(refType); jsonTransformationDTO.setArtifactType(baseArtifact.getArtifactType()); jsonTransformationDTO.setRepoName(baseGitMetadata.getRepoName()); @@ -474,7 +475,7 @@ protected Mono checkoutReference( } protected Mono checkoutRemoteReference( - String baseArtifactId, GitRefDTO gitRefDTO, ArtifactType artifactType, GitType gitType) { + String baseArtifactId, ArtifactType artifactType, GitRefDTO gitRefDTO, GitType gitType) { GitArtifactHelper gitArtifactHelper = gitArtifactHelperResolver.getArtifactHelper(artifactType); AclPermission artifactEditPermission = gitArtifactHelper.getArtifactEditPermission(); @@ -559,7 +560,7 @@ private Mono checkoutRemoteReference( @Override public Mono createReference( - String referencedArtifactId, GitRefDTO refDTO, ArtifactType artifactType, GitType gitType) { + String referencedArtifactId, ArtifactType artifactType, GitRefDTO refDTO, GitType gitType) { /* 1. Check if the src artifact is available and user have sufficient permissions @@ -689,7 +690,7 @@ protected Mono createReference( }) // after the branch is created, we need to reset the older branch to the // clean status, i.e. last commit - .doOnSuccess(newImportedArtifact -> discardChanges(sourceArtifact, gitType)); + .flatMap(newImportedArtifact -> discardChanges(sourceArtifact, gitType)); }) .flatMap(newImportedArtifact -> gitRedisUtils .releaseFileLock( @@ -729,7 +730,7 @@ protected Mono isValidationForRefCreationComplete( @Override public Mono deleteGitReference( - String baseArtifactId, GitRefDTO gitRefDTO, ArtifactType artifactType, GitType gitType) { + String baseArtifactId, ArtifactType artifactType, GitRefDTO gitRefDTO, GitType gitType) { String refName = gitRefDTO.getRefName(); RefType refType = gitRefDTO.getRefType(); @@ -867,19 +868,19 @@ protected Mono deleteGitReference( * Each artifact is equal to a repo in the git(and each branch creates a new artifact with default artifact as parent) * * @param baseArtifactId : artifactId of the artifact which is getting connected to git - * @param gitConnectDTO artifactId - this is used to link the local git repo to an artifact - * remoteUrl - used for connecting to remote repo etc - * @param originHeader * @param artifactType + * @param gitConnectDTO artifactId - this is used to link the local git repo to an artifact + * remoteUrl - used for connecting to remote repo etc + * @param originHeader * @param gitType * @return an artifact with git metadata */ @Override public Mono connectArtifactToGit( String baseArtifactId, + ArtifactType artifactType, GitConnectDTO gitConnectDTO, String originHeader, - ArtifactType artifactType, GitType gitType) { /* * Connecting the artifact for the first time @@ -1473,31 +1474,31 @@ private boolean isBaseGitMetadataInvalid(GitArtifactMetadata gitArtifactMetadata } private Mono getStatusAfterComparingWithRemote( - String baseArtifactId, boolean isFileLock, ArtifactType artifactType, GitType gitType) { - return getStatus(baseArtifactId, isFileLock, true, artifactType, gitType); + String baseArtifactId, ArtifactType artifactType, boolean isFileLock, GitType gitType) { + return getStatus(baseArtifactId, artifactType, isFileLock, true, gitType); } @Override public Mono getStatus( - String branchedArtifactId, boolean compareRemote, ArtifactType artifactType, GitType gitType) { - return getStatus(branchedArtifactId, true, compareRemote, artifactType, gitType); + String branchedArtifactId, ArtifactType artifactType, boolean compareRemote, GitType gitType) { + return getStatus(branchedArtifactId, artifactType, true, compareRemote, gitType); } /** * Get the status of the artifact for given branched id * * @param branchedArtifactId branched id of the artifact + * @param artifactType Type of artifact in context * @param isFileLock if the locking is required, since the status API is used in the other flows of git * Only for the direct hits from the client the locking will be added - * @param artifactType Type of artifact in context * @param gitType Type of the service * @return Map of json file names which are added, modified, conflicting, removed and the working tree if this is clean */ private Mono getStatus( String branchedArtifactId, + ArtifactType artifactType, boolean isFileLock, boolean compareRemote, - ArtifactType artifactType, GitType gitType) { Mono> baseAndBranchedArtifacts = @@ -1867,14 +1868,14 @@ public Mono fetchRemoteChanges( * 1. Checkout (if required) to the branch to make sure we are comparing the right branch * 2. Run a git fetch command to fetch the latest changes from the remote * - * @param refArtifactId id of the reference - * @param isFileLock whether to add file lock or not + * @param refArtifactId id of the reference * @param artifactType + * @param isFileLock whether to add file lock or not * @return Mono of {@link BranchTrackingStatus} */ @Override public Mono fetchRemoteChanges( - String refArtifactId, boolean isFileLock, ArtifactType artifactType, GitType gitType, RefType refType) { + String refArtifactId, ArtifactType artifactType, boolean isFileLock, GitType gitType, RefType refType) { GitArtifactHelper artifactGitHelper = gitArtifactHelperResolver.getArtifactHelper(artifactType); AclPermission artifactEditPermission = artifactGitHelper.getArtifactEditPermission(); @@ -2066,15 +2067,15 @@ protected Mono discardChanges(Artifact branchedArtifact, Git } public Mono> listBranchForArtifact( - String branchedArtifactId, Boolean pruneBranches, ArtifactType artifactType, GitType gitType) { - return getBranchList(branchedArtifactId, pruneBranches, true, artifactType, gitType); + String branchedArtifactId, ArtifactType artifactType, Boolean pruneBranches, GitType gitType) { + return getBranchList(branchedArtifactId, artifactType, pruneBranches, true, gitType); } protected Mono> getBranchList( String branchedArtifactId, + ArtifactType artifactType, Boolean pruneBranches, boolean syncDefaultBranchWithRemote, - ArtifactType artifactType, GitType gitType) { GitArtifactHelper gitArtifactHelper = gitArtifactHelperResolver.getArtifactHelper(artifactType); @@ -2176,9 +2177,9 @@ private Mono syncDefaultBranchNameFromRemote( // default branch has been changed in remote return updateDefaultBranchName( metadata.getDefaultArtifactId(), + artifactType, defaultBranchNameInRemote, jsonTransformationDTO, - artifactType, gitType) .then() .thenReturn(defaultBranchNameInRemote); @@ -2191,9 +2192,9 @@ private Mono syncDefaultBranchNameFromRemote( private Flux updateDefaultBranchName( String baseArtifactId, + ArtifactType artifactType, String newDefaultBranchName, ArtifactJsonTransformationDTO jsonTransformationDTO, - ArtifactType artifactType, GitType gitType) { // Get the artifact from DB by new defaultBranchName GitArtifactHelper gitArtifactHelper = gitArtifactHelperResolver.getArtifactHelper(artifactType); @@ -2391,7 +2392,7 @@ private Mono> getBranchListWithDefaultBranchName( @Override public Mono> updateProtectedBranches( - String baseArtifactId, List branchNames, ArtifactType artifactType) { + String baseArtifactId, ArtifactType artifactType, List branchNames) { GitArtifactHelper gitArtifactHelper = gitArtifactHelperResolver.getArtifactHelper(artifactType); AclPermission artifactManageProtectedBranchPermission = @@ -2508,7 +2509,7 @@ public Mono toggleAutoCommitEnabled(String baseArtifactId, ArtifactType @Override public Mono getAutoCommitProgress( - String artifactId, String branchName, ArtifactType artifactType) { + String artifactId, ArtifactType artifactType, String branchName) { return gitAutoCommitHelper.getAutoCommitProgress(artifactId, branchName); } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/controllers/GitApplicationControllerCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/controllers/GitApplicationControllerCE.java index e08e5716fb3b..aefef9970fe6 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/controllers/GitApplicationControllerCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/controllers/GitApplicationControllerCE.java @@ -68,7 +68,7 @@ public Mono> connectApplicationToRemoteRepo( @RequestBody GitConnectDTO gitConnectDTO, @RequestHeader("Origin") String originHeader) { return centralGitService - .connectArtifactToGit(applicationId, gitConnectDTO, originHeader, ARTIFACT_TYPE, GIT_TYPE) + .connectArtifactToGit(applicationId, ARTIFACT_TYPE, gitConnectDTO, originHeader, GIT_TYPE) .map(application -> new ResponseDTO<>(HttpStatus.OK.value(), application, null)); } @@ -95,7 +95,7 @@ public Mono> createReference( referencedApplicationId, srcBranch); return centralGitService - .createReference(referencedApplicationId, gitRefDTO, ArtifactType.APPLICATION, GIT_TYPE) + .createReference(referencedApplicationId, ArtifactType.APPLICATION, gitRefDTO, GIT_TYPE) .map(result -> new ResponseDTO<>(HttpStatus.CREATED.value(), result, null)); } @@ -104,7 +104,7 @@ public Mono> createReference( public Mono> checkoutReference( @PathVariable String referencedApplicationId, @RequestBody GitRefDTO gitRefDTO) { return centralGitService - .checkoutReference(referencedApplicationId, gitRefDTO, true, ARTIFACT_TYPE, GIT_TYPE) + .checkoutReference(referencedApplicationId, ARTIFACT_TYPE, gitRefDTO, true, GIT_TYPE) .map(result -> new ResponseDTO<>(HttpStatus.OK.value(), result, null)); } @@ -133,7 +133,7 @@ public Mono> getStatus( @RequestParam(required = false, defaultValue = "true") Boolean compareRemote) { log.info("Going to get status for branchedApplicationId {}", branchedApplicationId); return centralGitService - .getStatus(branchedApplicationId, compareRemote, ARTIFACT_TYPE, GIT_TYPE) + .getStatus(branchedApplicationId, ARTIFACT_TYPE, compareRemote, GIT_TYPE) .map(result -> new ResponseDTO<>(HttpStatus.OK.value(), result, null)); } @@ -144,7 +144,7 @@ public Mono> fetchRemoteChanges( @RequestHeader(required = false, defaultValue = "branch") RefType refType) { log.info("Going to compare with remote for default referencedApplicationId {}", referencedApplicationId); return centralGitService - .fetchRemoteChanges(referencedApplicationId, true, ARTIFACT_TYPE, GIT_TYPE, refType) + .fetchRemoteChanges(referencedApplicationId, ARTIFACT_TYPE, true, GIT_TYPE, refType) .map(result -> new ResponseDTO<>(HttpStatus.OK.value(), result, null)); } @@ -154,7 +154,7 @@ public Mono> deleteBranch( @PathVariable String baseArtifactId, @RequestBody GitRefDTO gitRefDTO) { log.info("Going to delete ref {} for baseApplicationId {}", gitRefDTO.getRefName(), baseArtifactId); return centralGitService - .deleteGitReference(baseArtifactId, gitRefDTO, ARTIFACT_TYPE, GIT_TYPE) + .deleteGitReference(baseArtifactId, ARTIFACT_TYPE, gitRefDTO, GIT_TYPE) .map(application -> new ResponseDTO<>(HttpStatus.OK.value(), application, null)); } @@ -173,7 +173,7 @@ public Mono>> updateProtectedBranches( @PathVariable String baseArtifactId, @RequestBody @Valid BranchProtectionRequestDTO branchProtectionRequestDTO) { return centralGitService - .updateProtectedBranches(baseArtifactId, branchProtectionRequestDTO.getBranchNames(), ARTIFACT_TYPE) + .updateProtectedBranches(baseArtifactId, ARTIFACT_TYPE, branchProtectionRequestDTO.getBranchNames()) .map(data -> new ResponseDTO<>(HttpStatus.OK.value(), data, null)); } @@ -199,7 +199,7 @@ public Mono> getAutoCommitProgress( @PathVariable String baseApplicationId, @RequestHeader(name = FieldName.BRANCH_NAME, required = false) String branchName) { return centralGitService - .getAutoCommitProgress(baseApplicationId, branchName, ARTIFACT_TYPE) + .getAutoCommitProgress(baseApplicationId, ARTIFACT_TYPE, branchName) .map(data -> new ResponseDTO<>(HttpStatus.OK.value(), data, null)); } @@ -219,7 +219,7 @@ public Mono>> branch( log.debug("Going to get branch list for application {}", branchedApplicationId); return centralGitService .listBranchForArtifact( - branchedApplicationId, BooleanUtils.isTrue(pruneBranches), ARTIFACT_TYPE, GIT_TYPE) + branchedApplicationId, ARTIFACT_TYPE, BooleanUtils.isTrue(pruneBranches), GIT_TYPE) .map(result -> new ResponseDTO<>(HttpStatus.OK.value(), result, null)); } } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/fs/GitFSServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/fs/GitFSServiceCEImpl.java index eafd070e04fe..598147b8f81b 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/git/fs/GitFSServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/git/fs/GitFSServiceCEImpl.java @@ -209,12 +209,8 @@ public void setRepositoryDetailsInGitArtifactMetadata( @Override public Mono reconstructArtifactJsonFromGitRepository( ArtifactJsonTransformationDTO artifactJsonTransformationDTO) { - return commonGitFileUtils.reconstructArtifactExchangeJsonFromGitRepoWithAnalytics( - artifactJsonTransformationDTO.getWorkspaceId(), - artifactJsonTransformationDTO.getBaseArtifactId(), - artifactJsonTransformationDTO.getRepoName(), - artifactJsonTransformationDTO.getRefName(), - artifactJsonTransformationDTO.getArtifactType()); + return commonGitFileUtils.constructArtifactExchangeJsonFromGitRepositoryWithAnalytics( + artifactJsonTransformationDTO); } @Override @@ -367,7 +363,7 @@ public Mono prepareChangesToBeCommitted( Path repoSuffix = gitArtifactHelper.getRepoSuffixPath(workspaceId, baseArtifactId, repoName); return commonGitFileUtils - .saveArtifactToLocalRepoWithAnalytics(repoSuffix, artifactExchangeJson, branchName) + .saveArtifactToLocalRepoNew(repoSuffix, artifactExchangeJson, branchName) .map(ignore -> Boolean.TRUE) .onErrorResume(e -> { log.error("Error in commit flow: ", e); @@ -376,6 +372,7 @@ public Mono prepareChangesToBeCommitted( } else if (e instanceof AppsmithException) { return Mono.error(e); } + return Mono.error(new AppsmithException(AppsmithError.GIT_FILE_SYSTEM_ERROR, e.getMessage())); }); } @@ -617,8 +614,7 @@ public Mono recreateArtifactJsonFromLastCommit( Path repoSuffix = gitArtifactHelper.getRepoSuffixPath(workspaceId, baseArtifactId, repoName); return fsGitHandler.rebaseBranch(repoSuffix, refName).flatMap(rebaseStatus -> { - return commonGitFileUtils.reconstructArtifactExchangeJsonFromGitRepoWithAnalytics( - workspaceId, baseArtifactId, repoName, refName, artifactType); + return commonGitFileUtils.constructArtifactExchangeJsonFromGitRepository(jsonTransformationDTO); }); } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/ce/ArtifactGitFileUtilsCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/ce/ArtifactGitFileUtilsCE.java index f92820c047ac..f20fe5f878db 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/ce/ArtifactGitFileUtilsCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/ce/ArtifactGitFileUtilsCE.java @@ -3,6 +3,7 @@ import com.appsmith.external.git.models.GitResourceMap; import com.appsmith.external.models.ArtifactGitReference; import com.appsmith.server.dtos.ArtifactExchangeJson; +import com.appsmith.server.git.dtos.ArtifactJsonTransformationDTO; import lombok.NonNull; import reactor.core.publisher.Mono; @@ -28,4 +29,7 @@ void addArtifactReferenceFromExportedJson( Path getRepoSuffixPath(String workspaceId, String artifactId, String repoName, @NonNull String... args); void setArtifactDependentPropertiesInJson(GitResourceMap gitResourceMap, ArtifactExchangeJson artifactExchangeJson); + + Mono performJsonMigration( + ArtifactJsonTransformationDTO jsonTransformationDTO, ArtifactExchangeJson artifactExchangeJson); } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/ce/CommonGitFileUtilsCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/ce/CommonGitFileUtilsCE.java index 5349f788df6b..4ce31654b06d 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/ce/CommonGitFileUtilsCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/ce/CommonGitFileUtilsCE.java @@ -30,6 +30,7 @@ import com.appsmith.server.dtos.PageDTO; import com.appsmith.server.exceptions.AppsmithError; import com.appsmith.server.exceptions.AppsmithException; +import com.appsmith.server.git.dtos.ArtifactJsonTransformationDTO; import com.appsmith.server.helpers.ArtifactGitFileUtils; import com.appsmith.server.migrations.JsonSchemaVersions; import com.appsmith.server.newactions.base.NewActionService; @@ -159,16 +160,19 @@ public Mono saveArtifactToLocalRepo( } public Mono saveArtifactToLocalRepoNew( - Path baseRepoSuffix, ArtifactExchangeJson artifactExchangeJson, String branchName) - throws IOException, GitAPIException { + Path baseRepoSuffix, ArtifactExchangeJson artifactExchangeJson, String branchName) { // this should come from the specific files GitResourceMap gitResourceMap = createGitResourceMap(artifactExchangeJson); // Save application to git repo - return fileUtils - .saveArtifactToGitRepo(baseRepoSuffix, gitResourceMap, branchName) - .subscribeOn(Schedulers.boundedElastic()); + try { + return fileUtils + .saveArtifactToGitRepo(baseRepoSuffix, gitResourceMap, branchName) + .subscribeOn(Schedulers.boundedElastic()); + } catch (IOException | GitAPIException exception) { + return Mono.error(exception); + } } public Mono saveArtifactToLocalRepoWithAnalytics( @@ -553,6 +557,96 @@ private void setDatasourcesInArtifactReference( artifactGitReference.setDatasources(resourceMap); } + public Mono constructArtifactExchangeJsonFromGitRepositoryWithAnalytics( + ArtifactJsonTransformationDTO jsonTransformationDTO) { + if (!isJsonTransformationDTOValid(jsonTransformationDTO)) { + return Mono.error(new AppsmithException( + AppsmithError.INVALID_GIT_CONFIGURATION, "ArtifactJSONTransformationDTO is invalid")); + } + + String workspaceId = jsonTransformationDTO.getWorkspaceId(); + String baseArtifactId = jsonTransformationDTO.getBaseArtifactId(); + + ArtifactGitFileUtils artifactGitFileUtils = + getArtifactBasedFileHelper(jsonTransformationDTO.getArtifactType()); + Map constantsMap = artifactGitFileUtils.getConstantsMap(); + + return Mono.zip( + constructArtifactExchangeJsonFromGitRepository(jsonTransformationDTO), + sessionUserService.getCurrentUser()) + .flatMap(tuple -> { + final Map data = Map.of( + constantsMap.get(FieldName.ID), + baseArtifactId, + FieldName.WORKSPACE_ID, + workspaceId, + FieldName.FLOW_NAME, + AnalyticsEvents.GIT_DESERIALIZE_APP_RESOURCES_FROM_FILE.getEventName()); + + return analyticsService + .sendEvent( + AnalyticsEvents.UNIT_EXECUTION_TIME.getEventName(), + tuple.getT2().getUsername(), + data) + .thenReturn(tuple.getT1()); + }); + } + + /** + * Method to reconstruct the application from the local git repo + * @param jsonTransformationDTO : DTO which carries the parameter for transformation + * @return an instance of an object which extends artifact exchange json. + * i.e. Application Json, Package Json + */ + public Mono constructArtifactExchangeJsonFromGitRepository( + ArtifactJsonTransformationDTO jsonTransformationDTO) { + ArtifactType artifactType = jsonTransformationDTO.getArtifactType(); + ArtifactGitFileUtils artifactGitFileUtils = getArtifactBasedFileHelper(artifactType); + + // Type is not required as checkout happens in similar fashion + String refName = jsonTransformationDTO.getRefName(); + String workspaceId = jsonTransformationDTO.getWorkspaceId(); + String baseArtifactId = jsonTransformationDTO.getBaseArtifactId(); + String repoName = jsonTransformationDTO.getRepoName(); + Path repoSuffixPath = artifactGitFileUtils.getRepoSuffixPath(workspaceId, baseArtifactId, repoName); + + Mono gitResourceMapMono = fileUtils.constructGitResourceMapFromGitRepo(repoSuffixPath, refName); + + return gitResourceMapMono.flatMap(gitResourceMap -> { + ArtifactExchangeJson artifactExchangeJson = createArtifactExchangeJson(gitResourceMap, artifactType); + copyMetadataToArtifactExchangeJson(gitResourceMap, artifactExchangeJson); + return artifactGitFileUtils.performJsonMigration(jsonTransformationDTO, artifactExchangeJson); + }); + } + + /** + * This method copies the metadata from git resource map to artifactExchangeJson + * @param gitResourceMap : git resource map generated from file system + * @param artifactExchangeJson : artifact json constructed from git resource map + */ + protected void copyMetadataToArtifactExchangeJson( + GitResourceMap gitResourceMap, ArtifactExchangeJson artifactExchangeJson) { + GitResourceIdentity metadataIdentity = + new GitResourceIdentity(GitResourceType.ROOT_CONFIG, METADATA + JSON_EXTENSION, ""); + Object metadata = gitResourceMap.getGitResourceMap().get(metadataIdentity); + + Gson gson = new Gson(); + JsonObject metadataJsonObject = gson.toJsonTree(metadata, Object.class).getAsJsonObject(); + + Integer serverSchemaVersion = getServerSchemaVersion(metadataJsonObject); + Integer clientSchemaVersion = getClientSchemaVersion(metadataJsonObject); + + artifactExchangeJson.setServerSchemaVersion(serverSchemaVersion); + artifactExchangeJson.setClientSchemaVersion(clientSchemaVersion); + } + + public boolean isJsonTransformationDTOValid(ArtifactJsonTransformationDTO jsonTransformationDTO) { + return jsonTransformationDTO.getArtifactType() != null + && hasText(jsonTransformationDTO.getWorkspaceId()) + && hasText(jsonTransformationDTO.getBaseArtifactId()) + && hasText(jsonTransformationDTO.getRefName()); + } + /** * Method to reconstruct the application from the local git repo * 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 df6caf59bb10..c5cb0f0843fa 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 @@ -1,5 +1,6 @@ package com.appsmith.server.migrations; +import com.appsmith.external.git.constants.ce.RefType; import com.appsmith.server.constants.ArtifactType; import com.appsmith.server.dtos.ApplicationJson; import com.appsmith.server.dtos.ArtifactExchangeJson; @@ -41,22 +42,23 @@ private Integer getCorrectSchemaVersion(Integer schemaVersion) { * @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, + * @param refName The ref name of the artifact being imported, * if it's a Git-connected application; otherwise, null. + * @param refType Type of the reference i.e. branch, tag. */ public Mono migrateArtifactExchangeJsonToLatestSchema( - ArtifactExchangeJson artifactExchangeJson, String baseArtifactId, String branchName) { + ArtifactExchangeJson artifactExchangeJson, String baseArtifactId, String refName, RefType refType) { if (ArtifactType.APPLICATION.equals(artifactExchangeJson.getArtifactJsonType())) { return migrateApplicationJsonToLatestSchema( - (ApplicationJson) artifactExchangeJson, baseArtifactId, branchName); + (ApplicationJson) artifactExchangeJson, baseArtifactId, refName, refType); } return Mono.fromCallable(() -> artifactExchangeJson); } public Mono migrateApplicationJsonToLatestSchema( - ApplicationJson applicationJson, String baseApplicationId, String branchName) { + ApplicationJson applicationJson, String baseApplicationId, String refName, RefType refType) { return Mono.fromCallable(() -> { setSchemaVersions(applicationJson); return applicationJson; @@ -66,7 +68,7 @@ public Mono migrateApplicationJsonToLatestSchema( return Mono.empty(); } - return migrateServerSchema(applicationJson, baseApplicationId, branchName); + return migrateServerSchema(applicationJson, baseApplicationId, refName); }) .switchIfEmpty(Mono.error(new AppsmithException(AppsmithError.INCOMPATIBLE_IMPORTED_JSON))); } 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 da73e86a08bc..1b9d602f5d2f 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 @@ -4,6 +4,7 @@ import com.appsmith.external.constants.AnalyticsEvents; import com.appsmith.external.converters.HttpMethodConverter; import com.appsmith.external.converters.ISOStringToInstantConverter; +import com.appsmith.external.git.constants.ce.RefType; import com.appsmith.external.helpers.AppsmithBeanUtils; import com.appsmith.external.models.ActionConfiguration; import com.appsmith.external.models.ActionDTO; @@ -250,8 +251,8 @@ public Mono createPageFromDBTable( return applicationJson; }) .subscribeOn(Schedulers.boundedElastic()) - .flatMap(applicationJson -> - jsonSchemaMigration.migrateApplicationJsonToLatestSchema(applicationJson, null, null)); + .flatMap(applicationJson -> jsonSchemaMigration.migrateApplicationJsonToLatestSchema( + applicationJson, null, null, RefType.branch)); return datasourceStorageMono .zipWhen(datasourceStorage -> Mono.zip( 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 8963aba9e620..8ce36a1fc29c 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 @@ -292,8 +292,8 @@ private Mono createAppJson(String filePath) { return stringifiedFile .map(data -> gson.fromJson(data, ApplicationJson.class)) - .flatMap(applicationJson -> - jsonSchemaMigration.migrateArtifactExchangeJsonToLatestSchema(applicationJson, null, null)) + .flatMap(applicationJson -> jsonSchemaMigration.migrateArtifactExchangeJsonToLatestSchema( + applicationJson, null, null, null)) .map(artifactExchangeJson -> (ApplicationJson) artifactExchangeJson); } diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/git/autocommit/AutoCommitEventHandlerImplTest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/git/autocommit/AutoCommitEventHandlerImplTest.java index 1afa9d79a013..c437281adc46 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/git/autocommit/AutoCommitEventHandlerImplTest.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/git/autocommit/AutoCommitEventHandlerImplTest.java @@ -3,6 +3,7 @@ import com.appsmith.external.dtos.GitLogDTO; import com.appsmith.external.git.FileInterface; import com.appsmith.external.git.GitExecutor; +import com.appsmith.external.git.constants.ce.RefType; import com.appsmith.external.helpers.AppsmithBeanUtils; import com.appsmith.external.models.ApplicationGitReference; import com.appsmith.server.configurations.ProjectProperties; @@ -435,7 +436,7 @@ public void autoCommitServerMigration_WhenServerHasNoChanges_NoCommitMade() thro doReturn(Mono.just(applicationJson1)) .when(jsonSchemaMigration) .migrateApplicationJsonToLatestSchema( - Mockito.eq(applicationJson), Mockito.anyString(), Mockito.anyString()); + Mockito.eq(applicationJson), Mockito.anyString(), Mockito.anyString(), any(RefType.class)); doReturn(Mono.just("success")) .when(gitExecutor) @@ -514,7 +515,8 @@ public void autocommitServerMigration_WhenJsonSchemaMigrationPresent_CommitSucce doReturn(Mono.just(applicationJson1)) .when(jsonSchemaMigration) - .migrateApplicationJsonToLatestSchema(any(), Mockito.anyString(), Mockito.anyString()); + .migrateApplicationJsonToLatestSchema( + any(), Mockito.anyString(), Mockito.anyString(), any(RefType.class)); gitFileSystemTestHelper.setupGitRepository(autoCommitEvent, applicationJson); diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/git/autocommit/AutoCommitServiceTest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/git/autocommit/AutoCommitServiceTest.java index 39a4287537c5..77bf3e4a0837 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/git/autocommit/AutoCommitServiceTest.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/git/autocommit/AutoCommitServiceTest.java @@ -2,6 +2,7 @@ import com.appsmith.external.dtos.GitLogDTO; import com.appsmith.external.git.GitExecutor; +import com.appsmith.external.git.constants.ce.RefType; import com.appsmith.external.helpers.AppsmithBeanUtils; import com.appsmith.server.acl.AclPermission; import com.appsmith.server.applications.base.ApplicationService; @@ -255,7 +256,7 @@ public void testAutoCommit_whenOnlyServerIsEligibleForMigration_commitSuccess() doReturn(Mono.just(applicationJson1)) .when(jsonSchemaMigration) .migrateApplicationJsonToLatestSchema( - any(ApplicationJson.class), Mockito.anyString(), Mockito.anyString()); + any(ApplicationJson.class), Mockito.anyString(), Mockito.anyString(), any(RefType.class)); gitFileSystemTestHelper.setupGitRepository( WORKSPACE_ID, DEFAULT_APP_ID, BRANCH_NAME, REPO_NAME, applicationJson); @@ -544,7 +545,7 @@ public void testAutoCommit_whenAutoCommitEligibleButPrerequisiteNotComplete_retu doReturn(Mono.just(applicationJson1)) .when(jsonSchemaMigration) .migrateApplicationJsonToLatestSchema( - any(ApplicationJson.class), Mockito.anyString(), Mockito.anyString()); + any(ApplicationJson.class), Mockito.anyString(), Mockito.anyString(), any(RefType.class)); gitFileSystemTestHelper.setupGitRepository( WORKSPACE_ID, DEFAULT_APP_ID, BRANCH_NAME, REPO_NAME, applicationJson); @@ -618,7 +619,7 @@ public void testAutoCommit_whenServerIsRunningMigrationCallsAutocommitAgainOnDif doReturn(Mono.just(applicationJson1)) .when(jsonSchemaMigration) .migrateApplicationJsonToLatestSchema( - any(ApplicationJson.class), Mockito.anyString(), Mockito.anyString()); + any(ApplicationJson.class), Mockito.anyString(), Mockito.anyString(), any(RefType.class)); gitFileSystemTestHelper.setupGitRepository( WORKSPACE_ID, DEFAULT_APP_ID, BRANCH_NAME, REPO_NAME, applicationJson); diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/git/ops/GitCommitTests.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/git/ops/GitCommitTests.java index 7b8b377c6428..39106cb937a7 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/git/ops/GitCommitTests.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/git/ops/GitCommitTests.java @@ -87,7 +87,7 @@ public void commitArtifact_whenNoChangesInLocal_returnsWithEmptyCommitMessage() Mockito.doReturn(Mono.just(Paths.get(""))) .when(commonGitFileUtils) - .saveArtifactToLocalRepoWithAnalytics(any(Path.class), any(), Mockito.anyString()); + .saveArtifactToLocalRepoNew(any(Path.class), any(), Mockito.anyString()); Mockito.doReturn(Mono.error(new EmptyCommitException("nothing to commit"))) .when(fsGitHandler) .commitArtifact( @@ -136,7 +136,7 @@ private Application createApplicationConnectedToGit(String name, String branchNa .initializeReadme(any(Path.class), Mockito.anyString(), Mockito.anyString()); Mockito.doReturn(Mono.just(Paths.get("path"))) .when(commonGitFileUtils) - .saveArtifactToLocalRepoWithAnalytics(any(Path.class), any(), Mockito.anyString()); + .saveArtifactToLocalRepoNew(any(Path.class), any(), Mockito.anyString()); Application testApplication = new Application(); testApplication.setName(name); @@ -167,7 +167,7 @@ private Application createApplicationConnectedToGit(String name, String branchNa gitConnectDTO.setGitProfile(gitProfile); return centralGitService .connectArtifactToGit( - application1.getId(), gitConnectDTO, "baseUrl", ArtifactType.APPLICATION, GitType.FILE_SYSTEM) + application1.getId(), ArtifactType.APPLICATION, gitConnectDTO, "baseUrl", GitType.FILE_SYSTEM) .map(artifact -> (Application) artifact) .block(); } @@ -225,7 +225,7 @@ public void commitArtifact_whenLocalRepoNotAvailable_throwsRepoNotFoundException Mockito.doReturn(Mono.error(new RepositoryNotFoundException(AppsmithError.REPOSITORY_NOT_FOUND.getMessage()))) .when(commonGitFileUtils) - .saveArtifactToLocalRepoWithAnalytics(any(Path.class), any(), Mockito.anyString()); + .saveArtifactToLocalRepoNew(any(Path.class), any(), Mockito.anyString()); StepVerifier.create(commitMono) .expectErrorMatches(throwable -> throwable instanceof AppsmithException diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/git/ops/GitConnectTests.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/git/ops/GitConnectTests.java index 9d848250e358..21a2c17164e0 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/git/ops/GitConnectTests.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/git/ops/GitConnectTests.java @@ -84,7 +84,7 @@ public void connectArtifactToGit_withEmptyRemoteUrl_throwsInvalidParameterExcept gitConnectDTO.setRemoteUrl(null); gitConnectDTO.setGitProfile(new GitProfile()); Mono applicationMono = centralGitService - .connectArtifactToGit("testID", gitConnectDTO, "baseUrl", ArtifactType.APPLICATION, GitType.FILE_SYSTEM) + .connectArtifactToGit("testID", ArtifactType.APPLICATION, gitConnectDTO, "baseUrl", GitType.FILE_SYSTEM) .map(artifact -> (Application) artifact); StepVerifier.create(applicationMono) @@ -108,7 +108,7 @@ public void connectArtifactToGit_withEmptyOriginHeader_throwsInvalidParameterExc gitConnectDTO.setGitProfile(new GitProfile()); Mono applicationMono = centralGitService - .connectArtifactToGit("testID", gitConnectDTO, null, ArtifactType.APPLICATION, GitType.FILE_SYSTEM) + .connectArtifactToGit("testID", ArtifactType.APPLICATION, gitConnectDTO, null, GitType.FILE_SYSTEM) .map(artifact -> (Application) artifact); StepVerifier.create(applicationMono) @@ -151,7 +151,7 @@ public void connectArtifactToGit_whenConnectingMorePrivateReposThanSupported_thr gitConnectDTO.setGitProfile(gitProfile); Mono applicationMono = centralGitService .connectArtifactToGit( - application.getId(), gitConnectDTO, "baseUrl", ArtifactType.APPLICATION, GitType.FILE_SYSTEM) + application.getId(), ArtifactType.APPLICATION, gitConnectDTO, "baseUrl", GitType.FILE_SYSTEM) .map(artifact -> (Application) artifact); StepVerifier.create(applicationMono) @@ -171,7 +171,7 @@ public void connectArtifactToGit_whenUserDoesNotHaveRequiredPermission_operation gitConnectDTO.setGitProfile(new GitProfile()); Mono applicationMono = centralGitService .connectArtifactToGit( - application.getId(), gitConnectDTO, "baseUrl", ArtifactType.APPLICATION, GitType.FILE_SYSTEM) + application.getId(), ArtifactType.APPLICATION, gitConnectDTO, "baseUrl", GitType.FILE_SYSTEM) .map(artifact -> (Application) artifact); StepVerifier.create(applicationMono) @@ -251,7 +251,7 @@ public void connectArtifactToGit_whenCloneOperationFails_throwsGitException() { Mono applicationMono = centralGitService .connectArtifactToGit( - application1.getId(), gitConnectDTO, "baseUrl", ArtifactType.APPLICATION, GitType.FILE_SYSTEM) + application1.getId(), ArtifactType.APPLICATION, gitConnectDTO, "baseUrl", GitType.FILE_SYSTEM) .map(artifact -> (Application) artifact); StepVerifier.create(applicationMono) @@ -289,7 +289,7 @@ public void connectArtifactToGit_whenUsingGlobalProfile_completesSuccessfully() Mockito.anyString()); Mockito.doReturn(Mono.just(Paths.get(""))) .when(commonGitFileUtils) - .saveArtifactToLocalRepoWithAnalytics(any(Path.class), any(), Mockito.anyString()); + .saveArtifactToLocalRepoNew(any(Path.class), any(), Mockito.anyString()); Mockito.doReturn(Mono.just(true)).when(commonGitFileUtils).checkIfDirectoryIsEmpty(any(Path.class)); Mockito.doReturn(Mono.just(Paths.get("textPath"))) .when(commonGitFileUtils) @@ -325,7 +325,7 @@ public void connectArtifactToGit_whenUsingGlobalProfile_completesSuccessfully() gitConnectDTO.setGitProfile(gitProfile); Mono applicationMono = centralGitService .connectArtifactToGit( - application1.getId(), gitConnectDTO, "baseUrl", ArtifactType.APPLICATION, GitType.FILE_SYSTEM) + application1.getId(), ArtifactType.APPLICATION, gitConnectDTO, "baseUrl", GitType.FILE_SYSTEM) .map(artifact -> (Application) artifact); StepVerifier.create(applicationMono) @@ -375,7 +375,7 @@ public void connectArtifactToGit_whenUsingIncompleteLocalProfile_throwsAuthorNam gitConnectDTO.setGitProfile(gitProfile); Mono applicationMono = centralGitService .connectArtifactToGit( - application1.getId(), gitConnectDTO, "baseUrl", ArtifactType.APPLICATION, GitType.FILE_SYSTEM) + application1.getId(), ArtifactType.APPLICATION, gitConnectDTO, "baseUrl", GitType.FILE_SYSTEM) .map(artifact -> (Application) artifact); StepVerifier.create(applicationMono) @@ -421,7 +421,7 @@ public void connectArtifactToGit_whenClonedRepoIsNotEmpty_throwsException() thro gitConnectDTO.setGitProfile(gitProfile); Mono applicationMono = centralGitService .connectArtifactToGit( - application1.getId(), gitConnectDTO, "baseUrl", ArtifactType.APPLICATION, GitType.FILE_SYSTEM) + application1.getId(), ArtifactType.APPLICATION, gitConnectDTO, "baseUrl", GitType.FILE_SYSTEM) .map(artifact -> (Application) artifact); StepVerifier.create(applicationMono) @@ -470,7 +470,7 @@ public void connectArtifactToGit_whenDefaultCommitFails_throwsException() throws gitConnectDTO.setGitProfile(gitProfile); Mono applicationMono = centralGitService .connectArtifactToGit( - application1.getId(), gitConnectDTO, "baseUrl", ArtifactType.APPLICATION, GitType.FILE_SYSTEM) + application1.getId(), ArtifactType.APPLICATION, gitConnectDTO, "baseUrl", GitType.FILE_SYSTEM) .map(artifact -> (Application) artifact); StepVerifier.create(applicationMono) diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/git/ops/GitDiscardTests.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/git/ops/GitDiscardTests.java index 7ca39f4bcb55..d62ff5fc6a52 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/git/ops/GitDiscardTests.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/git/ops/GitDiscardTests.java @@ -120,7 +120,7 @@ private Application createApplicationConnectedToGit(String name, String branchNa .initializeReadme(any(Path.class), Mockito.anyString(), Mockito.anyString()); Mockito.doReturn(Mono.just(Paths.get("path"))) .when(commonGitFileUtils) - .saveArtifactToLocalRepoWithAnalytics(any(Path.class), any(), Mockito.anyString()); + .saveArtifactToLocalRepoNew(any(Path.class), any(), Mockito.anyString()); Application testApplication = new Application(); testApplication.setName(name); @@ -151,7 +151,7 @@ private Application createApplicationConnectedToGit(String name, String branchNa gitConnectDTO.setGitProfile(gitProfile); return centralGitService .connectArtifactToGit( - application1.getId(), gitConnectDTO, "baseUrl", ArtifactType.APPLICATION, GitType.FILE_SYSTEM) + application1.getId(), ArtifactType.APPLICATION, gitConnectDTO, "baseUrl", GitType.FILE_SYSTEM) .map(artifact -> (Application) artifact) .block(); } @@ -167,7 +167,7 @@ private Mono createArtifactJson(String filePath) ArtifactExchangeJson artifactExchangeJson = objectMapper.copy().disable(MapperFeature.USE_ANNOTATIONS).readValue(artifactJson, exchangeJsonType); - return jsonSchemaMigration.migrateArtifactExchangeJsonToLatestSchema(artifactExchangeJson, null, null); + return jsonSchemaMigration.migrateArtifactExchangeJsonToLatestSchema(artifactExchangeJson, null, null, null); } @Test @@ -198,7 +198,7 @@ public void discardChanges_whenUpstreamChangesAvailable_discardsSuccessfully() t Mockito.doReturn(Mono.just(Paths.get("path"))) .when(commonGitFileUtils) - .saveArtifactToLocalRepoWithAnalytics(any(Path.class), any(), Mockito.anyString()); + .saveArtifactToLocalRepoNew(any(Path.class), any(), Mockito.anyString()); Mockito.doReturn(Mono.just(artifactExchangeJson)) .when(gitHandlingService) .recreateArtifactJsonFromLastCommit(Mockito.any()); @@ -243,7 +243,7 @@ public void discardChanges_whenCancelledMidway_discardsSuccessfully() throws IOE Mockito.doReturn(Mono.just(Paths.get("path"))) .when(commonGitFileUtils) - .saveArtifactToLocalRepoWithAnalytics(any(Path.class), any(), Mockito.anyString()); + .saveArtifactToLocalRepoNew(any(Path.class), any(), Mockito.anyString()); Mockito.doReturn(Mono.just(artifactExchangeJson)) .when(gitHandlingService) .recreateArtifactJsonFromLastCommit(Mockito.any()); diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/git/resourcemap/ExchangeJsonConversionTests.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/git/resourcemap/ExchangeJsonConversionTests.java index 56de587dcb81..9dfe3997401d 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/git/resourcemap/ExchangeJsonConversionTests.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/git/resourcemap/ExchangeJsonConversionTests.java @@ -104,7 +104,7 @@ private Mono createArtifactJson(ExchangeJsonCont ArtifactExchangeJson artifactExchangeJson = objectMapper.copy().disable(MapperFeature.USE_ANNOTATIONS).readValue(artifactJson, exchangeJsonType); - return jsonSchemaMigration.migrateArtifactExchangeJsonToLatestSchema(artifactExchangeJson, null, null); + return jsonSchemaMigration.migrateArtifactExchangeJsonToLatestSchema(artifactExchangeJson, null, null, null); } @TestTemplate 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 c9486d45314f..819d4e06de46 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,8 +84,8 @@ private Mono createAppJson(String filePath) { .map(data -> { return gson.fromJson(data, ApplicationJson.class); }) - .flatMap(applicationJson -> - jsonSchemaMigration.migrateArtifactExchangeJsonToLatestSchema(applicationJson, null, null)) + .flatMap(applicationJson -> jsonSchemaMigration.migrateArtifactExchangeJsonToLatestSchema( + applicationJson, null, 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 e6fe0159535b..37fd07110d3f 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 @@ -361,8 +361,8 @@ private Mono createAppJson(String filePath) { .map(data -> { return gson.fromJson(data, ApplicationJson.class); }) - .flatMap(applicationJson -> - jsonSchemaMigration.migrateArtifactExchangeJsonToLatestSchema(applicationJson, null, null)) + .flatMap(applicationJson -> jsonSchemaMigration.migrateArtifactExchangeJsonToLatestSchema( + applicationJson, null, null, null)) .map(artifactExchangeJson -> (ApplicationJson) artifactExchangeJson); } @@ -2724,7 +2724,8 @@ public void applySchemaMigration_jsonFileWithFirstVersion_migratedToLatestVersio .flatMap(applicationJson -> { ApplicationJson applicationJson1 = new ApplicationJson(); AppsmithBeanUtils.copyNestedNonNullProperties(applicationJson, applicationJson1); - return jsonSchemaMigration.migrateArtifactExchangeJsonToLatestSchema(applicationJson1, null, null); + return jsonSchemaMigration.migrateArtifactExchangeJsonToLatestSchema( + applicationJson1, null, null, null); }) .map(applicationJson -> (ApplicationJson) applicationJson); diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/migrations/JsonSchemaMigrationTest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/migrations/JsonSchemaMigrationTest.java index 1a08d854560a..ad9a79fd4b41 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 @@ -39,7 +39,7 @@ public void migrateArtifactToLatestSchema_whenFeatureFlagIsOn_returnsIncremented gitFileSystemTestHelper.getApplicationJson(this.getClass().getResource("application.json")); ArtifactExchangeJson artifactExchangeJson = jsonSchemaMigration - .migrateArtifactExchangeJsonToLatestSchema(applicationJson, null, null) + .migrateArtifactExchangeJsonToLatestSchema(applicationJson, null, null, null) .block(); assertThat(artifactExchangeJson.getServerSchemaVersion()).isEqualTo(jsonSchemaVersions.getServerVersion()); assertThat(artifactExchangeJson.getClientSchemaVersion()).isEqualTo(jsonSchemaVersions.getClientVersion()); @@ -55,7 +55,7 @@ public void migrateApplicationJsonToLatestSchema_whenFeatureFlagIsOn_returnsIncr gitFileSystemTestHelper.getApplicationJson(this.getClass().getResource("application.json")); Mono applicationJsonMono = - jsonSchemaMigration.migrateApplicationJsonToLatestSchema(applicationJson, null, null); + jsonSchemaMigration.migrateApplicationJsonToLatestSchema(applicationJson, null, null, null); StepVerifier.create(applicationJsonMono) .assertNext(appJson -> { assertThat(appJson.getServerSchemaVersion()).isEqualTo(jsonSchemaVersions.getServerVersion()); 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 f5d0c4835408..ffc8dabbe12f 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,8 +130,8 @@ private Mono createAppJson(String filePath) { .map(data -> { return gson.fromJson(data, ApplicationJson.class); }) - .flatMap(applicationJson -> - jsonSchemaMigration.migrateArtifactExchangeJsonToLatestSchema(applicationJson, null, null)) + .flatMap(applicationJson -> jsonSchemaMigration.migrateArtifactExchangeJsonToLatestSchema( + applicationJson, null, null, null)) .map(artifactExchangeJson -> (ApplicationJson) artifactExchangeJson); } diff --git a/app/server/appsmith-server/src/test/utils/com/appsmith/server/git/ArtifactBuilderExtension.java b/app/server/appsmith-server/src/test/utils/com/appsmith/server/git/ArtifactBuilderExtension.java index 941265dbb432..123664de18e6 100644 --- a/app/server/appsmith-server/src/test/utils/com/appsmith/server/git/ArtifactBuilderExtension.java +++ b/app/server/appsmith-server/src/test/utils/com/appsmith/server/git/ArtifactBuilderExtension.java @@ -112,6 +112,6 @@ private Mono createArtifactJson(String filePath, ArtifactExchangeJson artifactExchangeJson = objectMapper.copy().disable(MapperFeature.USE_ANNOTATIONS).readValue(artifactJson, exchangeJsonType); - return jsonSchemaMigration.migrateArtifactExchangeJsonToLatestSchema(artifactExchangeJson, null, null); + return jsonSchemaMigration.migrateArtifactExchangeJsonToLatestSchema(artifactExchangeJson, null, null, null); } } From 625be352f775e8a5929be4a80c1513003f71da6e Mon Sep 17 00:00:00 2001 From: sneha122 Date: Mon, 6 Jan 2025 08:59:34 +0530 Subject: [PATCH 21/40] chore: Automation test cases added for shared drive gsheet (#38341) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description This PR adds automation test cases for Google sheet shared drive support feature. Skipping the cases due to chrome crash. Run success : https://github.com/appsmithorg/appsmith/actions/runs/12599681652/job/35117116909 Fixes #37916 _or_ Fixes `Issue URL` > [!WARNING] > _If no issue exists, please create an issue first, and check with the maintainers if the issue is valid._ ## Automation /ok-to-test tags="@tag.Datasource" ### :mag: Cypress test results > [!TIP] > 🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉 > Workflow run: > Commit: da066427cf3001acf4f273c10ad1fb2781ead800 > Cypress dashboard. > Tags: `@tag.Datasource` > Spec: >
Fri, 03 Jan 2025 17:12:50 UTC ## Communication Should the DevRel and Marketing teams inform users about this change? - [ ] Yes - [x] No ## Summary by CodeRabbit - **Tests** - Skipped multiple Cypress test suites for Google Sheets functionality - Added a new test suite for Google Sheets widget binding with selected sheet access - Disabled existing test suites for GSheet functional tests and widget binding --------- Co-authored-by: “sneha122” <“sneha@appsmith.com”> Co-authored-by: Sagar Khalasi --- .../e2e/GSheet/SelectedSheet_Access_Spec.ts | 2 +- .../SharedDrive_SelectedSheet_Access_Spec.ts | 368 ++++++++++++++++++ .../WidgetBinding_SelectedAccess_Spec.ts | 2 +- ...g_SharedDrive_SelectedSheet_Access_Spec.ts | 112 ++++++ 4 files changed, 482 insertions(+), 2 deletions(-) create mode 100644 app/client/cypress/e2e/GSheet/SharedDrive_SelectedSheet_Access_Spec.ts create mode 100644 app/client/cypress/e2e/GSheet/WidgetBinding_SharedDrive_SelectedSheet_Access_Spec.ts diff --git a/app/client/cypress/e2e/GSheet/SelectedSheet_Access_Spec.ts b/app/client/cypress/e2e/GSheet/SelectedSheet_Access_Spec.ts index 791d9a2cb2b2..7850ac1b2e10 100644 --- a/app/client/cypress/e2e/GSheet/SelectedSheet_Access_Spec.ts +++ b/app/client/cypress/e2e/GSheet/SelectedSheet_Access_Spec.ts @@ -15,7 +15,7 @@ const workspaceName = "gsheet apps"; const dataSourceName = "gsheet-selected"; let appName = "gsheet-app"; let spreadSheetName = "test-sheet-automation-selected"; -describe( +describe.skip( "GSheet-Functional Tests With Selected Access", { tags: ["@tag.Datasource", "@tag.GSheet", "@tag.Git", "@tag.AccessControl"], diff --git a/app/client/cypress/e2e/GSheet/SharedDrive_SelectedSheet_Access_Spec.ts b/app/client/cypress/e2e/GSheet/SharedDrive_SelectedSheet_Access_Spec.ts new file mode 100644 index 000000000000..e54e5bb4b22f --- /dev/null +++ b/app/client/cypress/e2e/GSheet/SharedDrive_SelectedSheet_Access_Spec.ts @@ -0,0 +1,368 @@ +/// +import { GSHEET_DATA } from "../../fixtures/test-data-gsheet"; +import { + homePage, + gsheetHelper, + dataSources, + agHelper, + entityExplorer, + assertHelper, + table, + appSettings, +} from "../../support/Objects/ObjectsCore"; +import BottomTabs from "../../support/Pages/IDE/BottomTabs"; + +const workspaceName = "gsheet apps"; +const dataSourceName = "gsheet-shared-selected"; +let appName = "gsheet-app"; +let spreadSheetName = "test-sheet-automation-selected"; +describe.skip( + "GSheet-Functional Tests With Selected Access", + { + tags: ["@tag.Datasource", "@tag.GSheet", "@tag.Git", "@tag.AccessControl"], + }, + function () { + before("Setup app", function () { + //Setting up app name + const uuid = Cypress._.random(0, 10000); + appName = appName + "-" + uuid; + + //Adding app + homePage.NavigateToHome(); + homePage.SelectWorkspace(workspaceName); + homePage.CreateAppInWorkspace(workspaceName, appName); + }); + + it("1. Add and verify fetch details query", () => { + entityExplorer.CreateNewDsQuery(dataSourceName); + agHelper.RenameQuery("Fetch_Details"); + dataSources.ValidateNSelectDropdown( + "Operation", + "Fetch Many", + "Fetch Details", + ); + dataSources.ValidateNSelectDropdown("Entity", "Spreadsheet"); + agHelper.Sleep(500); + dataSources.ValidateNSelectDropdown("Spreadsheet", "", spreadSheetName); + dataSources.RunQuery(); + cy.get("@postExecute").then((interception: any) => { + expect(interception.response.body.data.body.name).to.deep.equal( + spreadSheetName, + ); + }); + }); + + it("2. Verify Insert One and Insert Many queries", () => { + // add insert one query and verify + gsheetHelper.AddInsertOrUpdateQuery( + "Insert One", + dataSourceName, + spreadSheetName, + JSON.stringify(GSHEET_DATA[0]), + ); + cy.get("@postExecute").then((interception: any) => { + expect(interception.response.body.data.body.message).to.deep.equal( + "Inserted row successfully!", + ); + }); + + // add insert many query and verify + gsheetHelper.AddInsertOrUpdateQuery( + "Insert Many", + dataSourceName, + spreadSheetName, + JSON.stringify(GSHEET_DATA.slice(1, 10)), + ); + cy.get("@postExecute").then((interception: any) => { + expect(interception.response.body.data.body.message).to.deep.equal( + "Inserted rows successfully!", + ); + }); + }); + + it("3. Verify Update one and Update many queries", () => { + // add update one query and verify + gsheetHelper.AddInsertOrUpdateQuery( + "Update One", + dataSourceName, + spreadSheetName, + JSON.stringify(GSHEET_DATA[1]), + ); + cy.get("@postExecute").then((interception: any) => { + expect(interception.response.body.data.body.message).to.deep.equal( + "Updated sheet successfully!", + ); + }); + + // add update many query and verify + gsheetHelper.AddInsertOrUpdateQuery( + "Update Many", + dataSourceName, + spreadSheetName, + JSON.stringify(GSHEET_DATA.slice(2, 4)), + ); + cy.get("@postExecute").then((interception: any) => { + expect(interception.response.body.data.body.message).to.deep.equal( + "Updated sheet successfully!", + ); + }); + }); + + it("4. Verify Fetch many query", () => { + // Add simple Fetch many query and verify + gsheetHelper.EnterBasicQueryValues( + "Fetch Many", + dataSourceName, + spreadSheetName, + ); + dataSources.runQueryAndVerifyResponseViews({ count: GSHEET_DATA.length }); + BottomTabs.response.selectResponseResponseTypeFromMenu("TABLE"); + dataSources.AssertQueryTableResponse(0, GSHEET_DATA[0].uniq_id); + dataSources.AssertQueryTableResponse(1, "ホーンビィ 2014 カタログ"); // Asserting other language + dataSources.AssertQueryTableResponse(2, "₹, $, €, ¥, £"); // Asserting different symbols + dataSources.AssertQueryTableResponse(3, "!@#$%^&*"); // Asserting special chars + + // Update query to fetch only 1 column and verify + gsheetHelper.SelectMultiDropDownValue("Columns", "product_name"); + dataSources.RunQuery(); + dataSources.runQueryAndVerifyResponseViews({ count: GSHEET_DATA.length }); + BottomTabs.response.selectResponseResponseTypeFromMenu("TABLE"); + dataSources.AssertQueryTableResponse(0, GSHEET_DATA[0].product_name); + + //Remove column filter and add Sort By Ascending and verify + gsheetHelper.SelectMultiDropDownValue("Columns", "product_name"); //unselect the Columns dd value + agHelper.EnterValue("price", { + propFieldName: "", + directInput: false, + inputFieldName: "Sort By", + }); + dataSources.runQueryAndVerifyResponseViews({ count: GSHEET_DATA.length }); + BottomTabs.response.selectResponseResponseTypeFromMenu("TABLE"); + dataSources.AssertQueryTableResponse( + 0, + "5afbaf65680c9f378af5b3a3ae22427e", + ); + dataSources.AssertQueryTableResponse( + 1, + "ラーニング カーブ チャギントン インタラクティブ チャッツワース", + ); // Asserting other language + dataSources.AssertQueryTableResponse(2, "₹, $, €, ¥, £"); // Asserting different symbols + dataSources.AssertQueryTableResponse(3, "!@#$%^&*"); // Asserting special chars + + // Sort by descending and verify + dataSources.ClearSortByOption(); //clearing previous sort option + dataSources.EnterSortByValues("price", "Descending"); + dataSources.RunQuery(); + dataSources.runQueryAndVerifyResponseViews({ count: GSHEET_DATA.length }); + BottomTabs.response.selectResponseResponseTypeFromMenu("TABLE"); + dataSources.AssertQueryTableResponse( + 1, + "ホーンビー ゲージ ウェスタン エクスプレス デジタル トレイン セット (eLink および TTS ロコ トレイン セット付き)", + ); // Asserting other language + dataSources.AssertQueryTableResponse( + 4, + "Hornby Gauge Western Express Digital Train Set with eLink and TTS Loco Train Set", + ); + + // Filter by where clause and verify + agHelper.TypeDynamicInputValueNValidate( + "price", + dataSources._nestedWhereClauseKey(0), + ); + agHelper.TypeDynamicInputValueNValidate( + "100", + dataSources._nestedWhereClauseValue(0), + ); + dataSources.RunQuery(); + dataSources.runQueryAndVerifyResponseViews({ count: 8 }); + BottomTabs.response.selectResponseResponseTypeFromMenu("TABLE"); + dataSources.AssertQueryTableResponse( + 0, + "87bbb472ef9d90dcef140a551665c929", + ); + + // Filter by cell range and verify + dataSources.ValidateNSelectDropdown( + "Filter Format", + "Where Clause", + "Cell range", + ); + agHelper.EnterValue("A2:A5", { + propFieldName: "", + directInput: false, + inputFieldName: "Cell range", + }); + dataSources.RunQuery(); + dataSources.runQueryAndVerifyResponseViews({ count: 4 }); + BottomTabs.response.selectResponseResponseTypeFromMenu("TABLE"); + dataSources.AssertQueryTableResponse( + 0, + "eac7efa5dbd3d667f26eb3d3ab504464", + ); + }); + + it("5. Update a record which is not present and verify the error", () => { + //preparing data + const data = GSHEET_DATA[1]; + data.rowIndex = `${Cypress._.random(100, 1031)}`; + + // add update one query and verify + gsheetHelper.EnterBasicQueryValues( + "Update One", + dataSourceName, + spreadSheetName, + false, + ); + agHelper.EnterValue(JSON.stringify(data), { + propFieldName: "", + directInput: false, + inputFieldName: "Update row object", + }); + dataSources.RunQuery({ + expectedStatus: false, + }); + cy.get("@postExecute").then((interception: any) => { + expect(interception.response.body.data.body).to.deep.equal( + "No data found at this row index.", + ); + }); + + //reset the row index + data.rowIndex = "1"; + }); + + it("6. Convert field to JS and verify", () => { + // Switch js on sheet name then run query and verify + gsheetHelper.EnterBasicQueryValues( + "Fetch Many", + dataSourceName, + spreadSheetName, + false, + ); + agHelper.GetNClick( + dataSources._getJSONswitchLocator("Sheet name"), + 0, + true, + ); + dataSources.runQueryAndVerifyResponseViews({ count: 10 }); + BottomTabs.response.selectResponseResponseTypeFromMenu("TABLE"); + dataSources.AssertQueryTableResponse( + 0, + "eac7efa5dbd3d667f26eb3d3ab504464", + ); + + //Enter a wrong sheet name then run query and verify + agHelper.EnterValue("Sheet 2", { + propFieldName: "", + directInput: false, + inputFieldName: "Sheet name", + }); + dataSources.RunQuery({ + expectedStatus: false, + }); + cy.get("@postExecute").then((interception: any) => { + expect(interception.response.body.data.body).to.deep.equal( + "Unable to parse range: 'Sheet 2'!1:1", + ); + }); + + //Covert sheet name field to dropdown then run query and verify + agHelper.HoverElement(dataSources._getJSONswitchLocator("Sheet name")); + agHelper.AssertTooltip("Clear the field to toggle back"); + agHelper.EnterValue("", { + propFieldName: "", + directInput: false, + inputFieldName: "Sheet name", + }); //Clearing the sheet name field + agHelper.GetNClick( + dataSources._getJSONswitchLocator("Sheet name"), + 0, + true, + ); // Converting the field to dropdown + dataSources.ValidateNSelectDropdown("Sheet name", "", "Sheet1"); + dataSources.runQueryAndVerifyResponseViews({ count: 10 }); + BottomTabs.response.selectResponseResponseTypeFromMenu("TABLE"); + dataSources.AssertQueryTableResponse( + 0, + "eac7efa5dbd3d667f26eb3d3ab504464", + ); + }); + + it("7. Verify Delete query", function () { + // Delete data on the basis of row index + gsheetHelper.EnterBasicQueryValues( + "Delete One", + dataSourceName, + spreadSheetName, + ); + GSHEET_DATA.reverse().forEach((d) => { + agHelper.EnterValue(d.rowIndex, { + propFieldName: "", + directInput: false, + inputFieldName: "Row Index", + }); + dataSources.RunQuery(); + cy.get("@postExecute").then((interception: any) => { + expect(interception.response.body.data.body.message).to.deep.equal( + "Deleted row successfully!", + ); + }); + agHelper.Sleep(500); + }); + // Fetch many to verify all the data is deleted + gsheetHelper.EnterBasicQueryValues( + "Fetch Many", + dataSourceName, + spreadSheetName, + false, + ); + dataSources.RunQuery(); + cy.get("@postExecute").then((interception: any) => { + expect(interception.response.body.data.body).to.deep.equal([]); + }); + }); + + it("8. Import an app with selected access sheet", function () { + homePage.NavigateToHome(); + homePage.ImportApp("ImportAppSelectedAccess.json", workspaceName); + assertHelper.WaitForNetworkCall("importNewApplication").then(() => { + agHelper.Sleep(); + //Validate table is not empty! + table.WaitUntilTableLoad(0, 0, "v2"); + }); + // Assert table data + table.ReadTableRowColumnData(0, 0, "v2").then((cellData) => { + expect(cellData).to.eq("eac7efa5dbd3d667f26eb3d3ab504464"); + }); + homePage.NavigateToHome(); + homePage.DeleteApplication("ImportAppSelectedAccess"); + }); + + it("9. App level import of app with Selected sheet access gsheet", function () { + homePage.CreateAppInWorkspace( + workspaceName, + "AppLevelImportSelectedAccess", + ); + appSettings.OpenAppSettings(); + appSettings.GoToImport(); + agHelper.ClickButton("Import"); + homePage.ImportApp("ImportAppSelectedAccess.json", "", true); + cy.wait("@importNewApplication").then(() => { + agHelper.Sleep(); + agHelper.RefreshPage(); + table.WaitUntilTableLoad(0, 0, "v2"); + }); + // Assert table data + table.ReadTableRowColumnData(0, 0, "v2").then((cellData) => { + expect(cellData).to.eq("eac7efa5dbd3d667f26eb3d3ab504464"); + }); + homePage.NavigateToHome(); + homePage.DeleteApplication("AppLevelImportSelectedAccess"); + }); + + after("Delete app", function () { + // Delete app + homePage.DeleteApplication(appName); + }); + }, +); diff --git a/app/client/cypress/e2e/GSheet/WidgetBinding_SelectedAccess_Spec.ts b/app/client/cypress/e2e/GSheet/WidgetBinding_SelectedAccess_Spec.ts index c9bfcf3afd19..9370d98d28c6 100644 --- a/app/client/cypress/e2e/GSheet/WidgetBinding_SelectedAccess_Spec.ts +++ b/app/client/cypress/e2e/GSheet/WidgetBinding_SelectedAccess_Spec.ts @@ -21,7 +21,7 @@ const workspaceName = "gsheet apps"; const dataSourceName = "gsheet-selected"; let appName = "gsheet-app"; let spreadSheetName = "test-sheet-automation-selected"; -describe( +describe.skip( "GSheet-widget binding for selected sheet access", { tags: ["@tag.Datasource", "@tag.GSheet", "@tag.Git", "@tag.AccessControl"], diff --git a/app/client/cypress/e2e/GSheet/WidgetBinding_SharedDrive_SelectedSheet_Access_Spec.ts b/app/client/cypress/e2e/GSheet/WidgetBinding_SharedDrive_SelectedSheet_Access_Spec.ts new file mode 100644 index 000000000000..1aca12dbd627 --- /dev/null +++ b/app/client/cypress/e2e/GSheet/WidgetBinding_SharedDrive_SelectedSheet_Access_Spec.ts @@ -0,0 +1,112 @@ +/// +import { GSHEET_DATA } from "../../fixtures/test-data-gsheet"; +import { + homePage, + gsheetHelper, + dataSources, + agHelper, + entityExplorer, + propPane, + table, + draggableWidgets, +} from "../../support/Objects/ObjectsCore"; +import { Widgets } from "../../support/Pages/DataSources"; +import oneClickBindingLocator from "../../locators/OneClickBindingLocator"; +import { + PageLeftPane, + PagePaneSegment, +} from "../../support/Pages/EditorNavigation"; + +const workspaceName = "gsheet apps"; +const dataSourceName = "gsheet-shared-selected"; +let appName = "gsheet-app"; +let spreadSheetName = "test-sheet-automation-selected"; +describe.skip( + "GSheet-widget binding for selected sheet access", + { + tags: ["@tag.Datasource", "@tag.GSheet", "@tag.Git", "@tag.AccessControl"], + }, + function () { + before("Setup app and spreadsheet", function () { + //Setting up the app name + const uuid = Cypress._.random(0, 10000); + appName = appName + "-" + uuid; + + //Adding app and data to the selected sheet + homePage.NavigateToHome(); + homePage.SelectWorkspace(workspaceName); + homePage.CreateAppInWorkspace(workspaceName); + homePage.RenameApplication(appName); + gsheetHelper.AddInsertOrUpdateQuery( + "Insert Many", + dataSourceName, + spreadSheetName, + JSON.stringify(GSHEET_DATA), + ); + cy.get("@postExecute").then((interception: any) => { + expect(interception.response.body.data.body.message).to.deep.equal( + "Inserted rows successfully!", + ); + }); + }); + + it("1. Verify 'Add to widget [Widget Suggestion]' functionality for selected sheet access - GSheet", () => { + //Adding query + gsheetHelper.EnterBasicQueryValues( + "Fetch Many", + dataSourceName, + spreadSheetName, + ); + dataSources.runQueryAndVerifyResponseViews({ count: 10 }); + + // Adding suggested widgets and verify + dataSources.AddSuggestedWidget(Widgets.Table); + agHelper.RefreshPage(); + table.ReadTableRowColumnData(0, 0, "v2").then((cellData) => { + expect(cellData).to.eq("eac7efa5dbd3d667f26eb3d3ab504464"); + }); + agHelper.GetNClick(propPane._deleteWidget); + }); + + it("2. One click binding to table widget functionality for selected sheet access - GSheet", () => { + //Adding table widget + entityExplorer.DragDropWidgetNVerify(draggableWidgets.TABLE, 450, 200); + agHelper.GetNClick(oneClickBindingLocator.datasourceDropdownSelector); + agHelper.GetNClick( + oneClickBindingLocator.datasourceQuerySelector("fetch_many_query"), + ); + + // Assert table data + table.ReadTableRowColumnData(0, 0, "v2").then((cellData) => { + expect(cellData).to.eq("eac7efa5dbd3d667f26eb3d3ab504464"); + }); + agHelper.GetNClick(propPane._deleteWidget); + }); + + after("Delete app", function () { + // Delete data in spreadsheet and app + PageLeftPane.switchSegment(PagePaneSegment.Queries); + gsheetHelper.EnterBasicQueryValues( + "Delete One", + dataSourceName, + spreadSheetName, + ); + GSHEET_DATA.reverse().forEach((d) => { + agHelper.EnterValue(d.rowIndex, { + propFieldName: "", + directInput: false, + inputFieldName: "Row Index", + }); + dataSources.RunQuery(); + cy.get("@postExecute").then((interception: any) => { + expect(interception.response.body.data.body.message).to.deep.equal( + "Deleted row successfully!", + ); + }); + agHelper.Sleep(500); + }); + homePage.NavigateToHome(); + homePage.DeleteApplication(appName); + }); + }, +); From 5b7bde7430e24451ab30b026d4b49958f0ab69ea Mon Sep 17 00:00:00 2001 From: Nidhi Date: Mon, 6 Jan 2025 09:38:05 +0530 Subject: [PATCH 22/40] chore: CE split for git constants and AGF (#38464) --- .../git/constants/CommonConstants.java | 37 +----------------- .../git/constants/ce/CommonConstantsCE.java | 38 +++++++++++++++++++ .../git/ApplicationGitFileUtilsCEImpl.java | 2 +- .../git/ApplicationGitFileUtilsImpl.java | 4 +- .../server/helpers/ArtifactGitFileUtils.java | 4 +- .../server/helpers/CommonGitFileUtils.java | 4 +- .../helpers/ce/ArtifactGitFileUtilsCE.java | 18 ++++++--- .../helpers/ce/CommonGitFileUtilsCE.java | 7 ++-- 8 files changed, 62 insertions(+), 52 deletions(-) create mode 100644 app/server/appsmith-git/src/main/java/com/appsmith/git/constants/ce/CommonConstantsCE.java diff --git a/app/server/appsmith-git/src/main/java/com/appsmith/git/constants/CommonConstants.java b/app/server/appsmith-git/src/main/java/com/appsmith/git/constants/CommonConstants.java index 626bf6bbeb1a..4368a86061be 100644 --- a/app/server/appsmith-git/src/main/java/com/appsmith/git/constants/CommonConstants.java +++ b/app/server/appsmith-git/src/main/java/com/appsmith/git/constants/CommonConstants.java @@ -1,38 +1,5 @@ package com.appsmith.git.constants; -public class CommonConstants { - // This field will be useful when we migrate fields within JSON files (currently this will be useful for Git - // feature) - public static Integer fileFormatVersion = 5; - public static String FILE_FORMAT_VERSION = "fileFormatVersion"; - public static final String SERVER_SCHEMA_VERSION = "serverSchemaVersion"; - public static final String CLIENT_SCHEMA_VERSION = "clientSchemaVersion"; +import com.appsmith.git.constants.ce.CommonConstantsCE; - public static final String CANVAS = "canvas"; - - public static final String APPLICATION = "application"; - public static final String THEME = "theme"; - public static final String METADATA = "metadata"; - public static final String JSON_EXTENSION = ".json"; - public static final String JS_EXTENSION = ".js"; - public static final String TEXT_FILE_EXTENSION = ".txt"; - public static final String WIDGETS = "widgets"; - public static final String WIDGET_NAME = "widgetName"; - public static final String WIDGET_TYPE = "type"; - public static final String CHILDREN = "children"; - - public static final String CANVAS_WIDGET = "CANVAS_WIDGET"; - public static final String MAIN_CONTAINER = "MainContainer"; - public static final String DELIMITER_POINT = "."; - public static final String DELIMITER_PATH = "/"; - public static final String DELIMITER_HYPHEN = "-"; - public static final String EMPTY_STRING = ""; - public static final String SEPARATOR_UNDERSCORE = "_"; - public static final String FILE_MIGRATION_MESSAGE = - "Some of the changes above are due to an improved file structure. You can safely commit them to your repository."; - - public static final String TABS_WIDGET = "TABS_WIDGET"; - - public static final String WIDGET_ID = "widgetId"; - public static final String PARENT_ID = "parentId"; -} +public class CommonConstants extends CommonConstantsCE {} diff --git a/app/server/appsmith-git/src/main/java/com/appsmith/git/constants/ce/CommonConstantsCE.java b/app/server/appsmith-git/src/main/java/com/appsmith/git/constants/ce/CommonConstantsCE.java new file mode 100644 index 000000000000..e3a07795d8a2 --- /dev/null +++ b/app/server/appsmith-git/src/main/java/com/appsmith/git/constants/ce/CommonConstantsCE.java @@ -0,0 +1,38 @@ +package com.appsmith.git.constants.ce; + +public class CommonConstantsCE { + // This field will be useful when we migrate fields within JSON files (currently this will be useful for Git + // feature) + public static Integer fileFormatVersion = 5; + public static String FILE_FORMAT_VERSION = "fileFormatVersion"; + public static final String SERVER_SCHEMA_VERSION = "serverSchemaVersion"; + public static final String CLIENT_SCHEMA_VERSION = "clientSchemaVersion"; + + public static final String CANVAS = "canvas"; + + public static final String APPLICATION = "application"; + public static final String THEME = "theme"; + public static final String METADATA = "metadata"; + public static final String JSON_EXTENSION = ".json"; + public static final String JS_EXTENSION = ".js"; + public static final String TEXT_FILE_EXTENSION = ".txt"; + public static final String WIDGETS = "widgets"; + public static final String WIDGET_NAME = "widgetName"; + public static final String WIDGET_TYPE = "type"; + public static final String CHILDREN = "children"; + + public static final String CANVAS_WIDGET = "CANVAS_WIDGET"; + public static final String MAIN_CONTAINER = "MainContainer"; + public static final String DELIMITER_POINT = "."; + public static final String DELIMITER_PATH = "/"; + public static final String DELIMITER_HYPHEN = "-"; + public static final String EMPTY_STRING = ""; + public static final String SEPARATOR_UNDERSCORE = "_"; + public static final String FILE_MIGRATION_MESSAGE = + "Some of the changes above are due to an improved file structure. You can safely commit them to your repository."; + + public static final String TABS_WIDGET = "TABS_WIDGET"; + + public static final String WIDGET_ID = "widgetId"; + public static final String PARENT_ID = "parentId"; +} diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/applications/git/ApplicationGitFileUtilsCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/applications/git/ApplicationGitFileUtilsCEImpl.java index 79aef2cb351c..2ba44cc6e66c 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/applications/git/ApplicationGitFileUtilsCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/applications/git/ApplicationGitFileUtilsCEImpl.java @@ -87,7 +87,7 @@ @Slf4j @Component @Import({FileUtilsImpl.class}) -public class ApplicationGitFileUtilsCEImpl implements ArtifactGitFileUtilsCE { +public class ApplicationGitFileUtilsCEImpl implements ArtifactGitFileUtilsCE { private final Gson gson; private final ObjectMapper objectMapper; diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/applications/git/ApplicationGitFileUtilsImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/applications/git/ApplicationGitFileUtilsImpl.java index fcf0b2682ada..4f5ba237ae34 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/applications/git/ApplicationGitFileUtilsImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/applications/git/ApplicationGitFileUtilsImpl.java @@ -1,8 +1,8 @@ package com.appsmith.server.applications.git; import com.appsmith.external.git.FileInterface; -import com.appsmith.external.models.ApplicationGitReference; import com.appsmith.server.actioncollections.base.ActionCollectionService; +import com.appsmith.server.dtos.ApplicationJson; import com.appsmith.server.helpers.ArtifactGitFileUtils; import com.appsmith.server.migrations.JsonSchemaMigration; import com.appsmith.server.newactions.base.NewActionService; @@ -12,7 +12,7 @@ @Component public class ApplicationGitFileUtilsImpl extends ApplicationGitFileUtilsCEImpl - implements ArtifactGitFileUtils { + implements ArtifactGitFileUtils { public ApplicationGitFileUtilsImpl( Gson gson, diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/ArtifactGitFileUtils.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/ArtifactGitFileUtils.java index aeff00155376..84c0035d1bb2 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/ArtifactGitFileUtils.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/ArtifactGitFileUtils.java @@ -1,6 +1,6 @@ package com.appsmith.server.helpers; -import com.appsmith.external.models.ArtifactGitReference; +import com.appsmith.server.dtos.ArtifactExchangeJson; import com.appsmith.server.helpers.ce.ArtifactGitFileUtilsCE; -public interface ArtifactGitFileUtils extends ArtifactGitFileUtilsCE {} +public interface ArtifactGitFileUtils extends ArtifactGitFileUtilsCE {} diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/CommonGitFileUtils.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/CommonGitFileUtils.java index 90c512060d3c..ea9efe296082 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/CommonGitFileUtils.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/CommonGitFileUtils.java @@ -2,9 +2,9 @@ import com.appsmith.external.git.FileInterface; import com.appsmith.external.git.operations.FileOperations; -import com.appsmith.external.models.ApplicationGitReference; import com.appsmith.git.files.FileUtilsImpl; import com.appsmith.server.actioncollections.base.ActionCollectionService; +import com.appsmith.server.dtos.ApplicationJson; import com.appsmith.server.helpers.ce.CommonGitFileUtilsCE; import com.appsmith.server.migrations.JsonSchemaVersions; import com.appsmith.server.newactions.base.NewActionService; @@ -21,7 +21,7 @@ public class CommonGitFileUtils extends CommonGitFileUtilsCE { public CommonGitFileUtils( - ArtifactGitFileUtils applicationGitFileUtils, + ArtifactGitFileUtils applicationGitFileUtils, FileInterface fileUtils, FileOperations fileOperations, AnalyticsService analyticsService, diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/ce/ArtifactGitFileUtilsCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/ce/ArtifactGitFileUtilsCE.java index f20fe5f878db..a4c38c58b1d7 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/ce/ArtifactGitFileUtilsCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/ce/ArtifactGitFileUtilsCE.java @@ -3,6 +3,8 @@ import com.appsmith.external.git.models.GitResourceMap; import com.appsmith.external.models.ArtifactGitReference; import com.appsmith.server.dtos.ArtifactExchangeJson; +import com.appsmith.server.exceptions.AppsmithError; +import com.appsmith.server.exceptions.AppsmithException; import com.appsmith.server.git.dtos.ArtifactJsonTransformationDTO; import lombok.NonNull; import reactor.core.publisher.Mono; @@ -10,19 +12,23 @@ import java.nio.file.Path; import java.util.Map; -public interface ArtifactGitFileUtilsCE { +public interface ArtifactGitFileUtilsCE { - T createArtifactReferenceObject(); + default ArtifactGitReference createArtifactReferenceObject() { + return null; + } ArtifactExchangeJson createArtifactExchangeJsonObject(); void setArtifactDependentResources(ArtifactExchangeJson artifactExchangeJson, GitResourceMap gitResourceMap); - Mono reconstructArtifactExchangeJsonFromFilesInRepository( - String workspaceId, String baseArtifactId, String repoName, String branchName); + default Mono reconstructArtifactExchangeJsonFromFilesInRepository( + String workspaceId, String baseArtifactId, String repoName, String branchName) { + return Mono.error(new AppsmithException(AppsmithError.UNSUPPORTED_OPERATION)); + } - void addArtifactReferenceFromExportedJson( - ArtifactExchangeJson artifactExchangeJson, ArtifactGitReference artifactGitReference); + default void addArtifactReferenceFromExportedJson( + ArtifactExchangeJson artifactExchangeJson, ArtifactGitReference artifactGitReference) {} Map getConstantsMap(); diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/ce/CommonGitFileUtilsCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/ce/CommonGitFileUtilsCE.java index 4ce31654b06d..5ab89e4acf55 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/ce/CommonGitFileUtilsCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/ce/CommonGitFileUtilsCE.java @@ -9,7 +9,6 @@ import com.appsmith.external.helpers.Stopwatch; import com.appsmith.external.models.ActionConfiguration; import com.appsmith.external.models.ActionDTO; -import com.appsmith.external.models.ApplicationGitReference; import com.appsmith.external.models.ArtifactGitReference; import com.appsmith.external.models.BaseDomain; import com.appsmith.external.models.DatasourceStorage; @@ -86,7 +85,7 @@ @Import({FileUtilsImpl.class}) public class CommonGitFileUtilsCE { - protected final ArtifactGitFileUtils applicationGitFileUtils; + protected final ArtifactGitFileUtils applicationGitFileUtils; private final FileInterface fileUtils; private final FileOperations fileOperations; private final AnalyticsService analyticsService; @@ -103,7 +102,7 @@ public class CommonGitFileUtilsCE { protected final ObjectMapper objectMapper; public CommonGitFileUtilsCE( - ArtifactGitFileUtils applicationGitFileUtils, + ArtifactGitFileUtils applicationGitFileUtils, FileInterface fileUtils, FileOperations fileOperations, AnalyticsService analyticsService, @@ -123,7 +122,7 @@ public CommonGitFileUtilsCE( this.objectMapper = objectMapper.copy().disable(MapperFeature.USE_ANNOTATIONS); } - private ArtifactGitFileUtils getArtifactBasedFileHelper(ArtifactType artifactType) { + protected ArtifactGitFileUtils getArtifactBasedFileHelper(ArtifactType artifactType) { if (ArtifactType.APPLICATION.equals(artifactType)) { return applicationGitFileUtils; } From f46fd979d1249c667d4455b1ec84c94be3b4430a Mon Sep 17 00:00:00 2001 From: Nikhil Nandagopal Date: Mon, 6 Jan 2025 11:43:01 +0530 Subject: [PATCH 23/40] Updated Label Config --- .github/config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/config.json b/.github/config.json index e5d466df074c..52d8c65580ba 100644 --- a/.github/config.json +++ b/.github/config.json @@ -1 +1 @@ -{"runners":[{"versioning":{"source":"milestones","type":"SemVer"},"prereleaseName":"alpha","issue":{"labels":{"Widgets Product":{"conditions":[{"label":"Button Widget","type":"hasLabel","value":true},{"label":"Chart Widget","type":"hasLabel","value":true},{"label":"Container Widget","type":"hasLabel","value":true},{"label":"Date Picker Widget","type":"hasLabel","value":true},{"label":"Select Widget","type":"hasLabel","value":true},{"label":"File Picker Widget","type":"hasLabel","value":true},{"label":"Form Widget","type":"hasLabel","value":true},{"label":"Image Widget","type":"hasLabel","value":true},{"label":"Input Widget","type":"hasLabel","value":true},{"label":"List Widget","type":"hasLabel","value":true},{"label":"MultiSelect Widget","type":"hasLabel","value":true},{"label":"Map Widget","type":"hasLabel","value":true},{"label":"Modal Widget","type":"hasLabel","value":true},{"label":"Radio Widget","type":"hasLabel","value":true},{"label":"Rich Text Editor Widget","type":"hasLabel","value":true},{"label":"Tab Widget","type":"hasLabel","value":true},{"label":"Table Widget","type":"hasLabel","value":true},{"label":"Text Widget","type":"hasLabel","value":true},{"label":"Video Widget","type":"hasLabel","value":true},{"label":"iFrame","type":"hasLabel","value":true},{"label":"Menu Button","type":"hasLabel","value":true},{"label":"Rating","type":"hasLabel","value":true},{"label":"Widget Validation","type":"hasLabel","value":true},{"label":"New Widget","type":"hasLabel","value":true},{"label":"Switch widget","type":"hasLabel","value":true},{"label":"Audio Widget","type":"hasLabel","value":true},{"label":"Icon Button Widget","type":"hasLabel","value":true},{"label":"Stat Box Widget","type":"hasLabel","value":true},{"label":"Voice Recorder Widget","type":"hasLabel","value":true},{"label":"Calendar Widget","type":"hasLabel","value":true},{"label":"Menu Button Widget","type":"hasLabel","value":true},{"label":"Divider Widget","type":"hasLabel","value":true},{"label":"Rating Widget","type":"hasLabel","value":true},{"label":"View Mode","type":"hasLabel","value":true},{"label":"Widget Property","type":"hasLabel","value":true},{"label":"Document Viewer Widget","type":"hasLabel","value":true},{"label":"Radio Group Widget","type":"hasLabel","value":true},{"label":"Currency Input Widget","type":"hasLabel","value":true},{"label":"TreeSelect","type":"hasLabel","value":true},{"label":"MultiTree Select Widget","type":"hasLabel","value":true},{"label":"Phone Input Widget","type":"hasLabel","value":true},{"label":"JSON Form","type":"hasLabel","value":true},{"label":"All Widgets","type":"hasLabel","value":true},{"label":"Button Group widget","type":"hasLabel","value":true},{"label":"Progress bar widget","type":"hasLabel","value":true},{"label":"Audio Recorder Widget","type":"hasLabel","value":true},{"label":"Camera Widget","type":"hasLabel","value":true},{"label":"Table Widget V2","type":"hasLabel","value":true},{"label":"Map Chart Widget","type":"hasLabel","value":true},{"label":"Code Scanner Widget","type":"hasLabel","value":true},{"label":"Widget keyboard accessibility","type":"hasLabel","value":true},{"label":"List Widget V2","type":"hasLabel","value":true},{"label":"Slider Widget","type":"hasLabel","value":true},{"label":"One-click Binding","type":"hasLabel","value":true},{"label":"Old widget version","type":"hasLabel","value":true},{"label":"Widget Discoverability","type":"hasLabel","value":true},{"label":"Switch Group Widget","type":"hasLabel","value":true},{"label":"Checkbox Group widget","type":"hasLabel","value":true},{"label":"Checkbox Widget","type":"hasLabel","value":true},{"label":"Table Inline Edit","type":"hasLabel","value":true},{"label":"Custom Widgets","type":"hasLabel","value":true}],"requires":1},"Javascript Product":{"conditions":[{"label":"JS Linting & Errors","type":"hasLabel","value":true},{"label":"Autocomplete","type":"hasLabel","value":true},{"label":"Evaluated Value","type":"hasLabel","value":true},{"label":"Slash Command","type":"hasLabel","value":true},{"label":"New JS Function","type":"hasLabel","value":true},{"label":"JS Usability","type":"hasLabel","value":true},{"label":"Framework Functions","type":"hasLabel","value":true},{"label":"JS Objects","type":"hasLabel","value":true},{"label":"JS Evaluation","type":"hasLabel","value":true},{"label":"Custom JS Libraries","type":"hasLabel","value":true},{"label":"Action Selector","type":"hasLabel","value":true},{"label":"Widget setter method","type":"hasLabel","value":true},{"label":"Entity Refactor","type":"hasLabel","value":true},{"label":"AST-frontend","type":"hasLabel","value":true},{"label":"Sniping Mode","type":"hasLabel","value":true},{"label":"AST-backend","type":"hasLabel","value":true}],"requires":1},"IDE Product":{"conditions":[{"label":"IDE Product","type":"hasLabel","value":true},{"label":"IDE Infra","type":"hasLabel","value":true},{"label":"IDE Navigation","type":"hasLabel","value":true},{"label":"IDE tabs","type":"hasLabel","value":true},{"label":"Omnibar","type":"hasLabel","value":true},{"label":"Entity Explorer","type":"hasLabel","value":true},{"label":"Page Management","type":"hasLabel","value":true},{"label":"Preview mode","type":"hasLabel","value":true},{"label":"Entity Management","type":"hasLabel","value":true}],"requires":1},"Accelerators Product":{"conditions":[{"label":"Generate Page","type":"hasLabel","value":true},{"label":"Building blocks","type":"hasLabel","value":true}],"requires":1},"Templates Product":{"conditions":[{"label":"Partial-import-export","type":"hasLabel","value":true},{"label":"Templates Product","type":"hasLabel","value":true}],"requires":1},"Design System Product":{"conditions":[{"label":"Design System Product","type":"hasLabel","value":true},{"label":"ADS Component Issue","type":"hasLabel","value":true},{"label":"Keyboard accessibility ","type":"hasLabel","value":true},{"label":"Toggle button","type":"hasLabel","value":true},{"label":"ADS Category Token","type":"hasLabel","value":true},{"label":"ADS Component Documentation","type":"hasLabel","value":true},{"label":"ADS Migration","type":"hasLabel","value":true},{"label":"ADS Deduplication ","type":"hasLabel","value":true},{"label":"ADS Revamp","type":"hasLabel","value":true},{"label":"ADS Deduplication","type":"hasLabel","value":true},{"label":"ADS Unit Test","type":"hasLabel","value":true},{"label":"ADS Components","type":"hasLabel","value":true},{"label":"ADS Grayscale","type":"hasLabel","value":true},{"label":"Design System","type":"hasLabel","value":true},{"label":"ADS Typography","type":"hasLabel","value":true},{"label":"ADS Visual Styles","type":"hasLabel","value":true},{"label":"ADS Component Design","type":"hasLabel","value":true},{"label":"Modal Component","type":"hasLabel","value":true},{"label":"ADS Spacing","type":"hasLabel","value":true},{"label":"ads unit test","type":"hasLabel","value":true},{"label":"ads revamp","type":"hasLabel","value":true},{"label":"ads deduplication","type":"hasLabel","value":true}],"requires":1},"RBAC Product":{"conditions":[{"label":"Invite users","type":"hasLabel","value":true},{"label":"RBAC Product","type":"hasLabel","value":true}],"requires":1},"Workspace Product":{"conditions":[{"label":"Home Page","type":"hasLabel","value":true},{"label":"Workspace Product","type":"hasLabel","value":true}],"requires":1},"Billing & Licensing Product":{"conditions":[{"label":"Customer Portal","type":"hasLabel","value":true},{"label":"Cloud Services","type":"hasLabel","value":true},{"label":"Billing","type":"hasLabel","value":true},{"label":"Self Serve","type":"hasLabel","value":true},{"label":"Enterprise Billing","type":"hasLabel","value":true},{"label":"Analytics Improvements","type":"hasLabel","value":true},{"label":"Self Serve 1.0","type":"hasLabel","value":true},{"label":"License","type":"hasLabel","value":true},{"label":"BE instance","type":"hasLabel","value":true},{"label":"Invite flow","type":"hasLabel","value":true},{"label":"CE Instance Usage","type":"hasLabel","value":true},{"label":"Feature Flagging","type":"hasLabel","value":true}],"requires":1},"Packages Product":{"conditions":[{"label":"Packages Product","type":"hasLabel","value":true}],"requires":1},"Environments Product":{"conditions":[{"label":"Environments Product","type":"hasLabel","value":true}],"requires":1},"UI Building Product":{"conditions":[{"label":"Property Pane","type":"hasLabel","value":true},{"label":"Copy Paste","type":"hasLabel","value":true},{"label":"Drag & Drop","type":"hasLabel","value":true},{"label":"Undo/Redo","type":"hasLabel","value":true},{"label":"Widgets Pane","type":"hasLabel","value":true},{"label":"UI Performance","type":"hasLabel","value":true},{"label":"Widget Grouping","type":"hasLabel","value":true},{"label":"Reflow & Resize","type":"hasLabel","value":true},{"label":"Canvas / Grid","type":"hasLabel","value":true},{"label":"Auto Height","type":"hasLabel","value":true},{"label":"Browser specific","type":"hasLabel","value":true},{"label":"Auto Layout","type":"hasLabel","value":true},{"label":"Fixed layout","type":"hasLabel","value":true},{"label":"App Navigation","type":"hasLabel","value":true}],"requires":1},"Onboarding Product":{"conditions":[{"label":"Welcome Screen","type":"hasLabel","value":true}],"requires":1},"Git Product":{"conditions":[{"label":"Git Product","type":"hasLabel","value":true},{"label":"Git Auto-commit","type":"hasLabel","value":true},{"label":"Auto-commit","type":"hasLabel","value":true},{"label":"Continuous Deployment","type":"hasLabel","value":true},{"label":"Default branch","type":"hasLabel","value":true},{"label":"Git status","type":"hasLabel","value":true},{"label":"Git performance","type":"hasLabel","value":true},{"label":"SDLC","type":"hasLabel","value":true},{"label":"Git IA","type":"hasLabel","value":true},{"label":"Branch management","type":"hasLabel","value":true}],"requires":1},"Embedding Apps Product":{"conditions":[{"label":"Embedding Apps Product","type":"hasLabel","value":true}],"requires":1},"Integrations Product":{"conditions":[{"label":"New Datasource","type":"hasLabel","value":true},{"label":"Firestore","type":"hasLabel","value":true},{"label":"Google Sheets","type":"hasLabel","value":true},{"label":"Mongo","type":"hasLabel","value":true},{"label":"Redshift","type":"hasLabel","value":true},{"label":"snowflake","type":"hasLabel","value":true},{"label":"S3","type":"hasLabel","value":true},{"label":"Redis","type":"hasLabel","value":true},{"label":"Postgres","type":"hasLabel","value":true},{"label":"GraphQL Plugin","type":"hasLabel","value":true},{"label":"ArangoDB","type":"hasLabel","value":true},{"label":"MsSQL","type":"hasLabel","value":true},{"label":"Elastic Search","type":"hasLabel","value":true},{"label":"OAuth","type":"hasLabel","value":true},{"label":"Airtable","type":"hasLabel","value":true},{"label":"CURL","type":"hasLabel","value":true},{"label":"DynamoDB","type":"hasLabel","value":true},{"label":"Zendesk","type":"hasLabel","value":true},{"label":"Hubspot","type":"hasLabel","value":true},{"label":"Query Forms","type":"hasLabel","value":true},{"label":"Twilio","type":"hasLabel","value":true},{"label":"MySQL","type":"hasLabel","value":true},{"label":"Connection pool","type":"hasLabel","value":true},{"label":"MariaDB","type":"hasLabel","value":true},{"label":"Integrations Pod General","type":"hasLabel","value":true},{"label":"SMTP plugin","type":"hasLabel","value":true},{"label":"Oracle SQL DB","type":"hasLabel","value":true},{"label":"Query filter","type":"hasLabel","value":true},{"label":"Activation - datasources","type":"hasLabel","value":true},{"label":"REST API","type":"hasLabel","value":true},{"label":"REST API","type":"hasLabel","value":true},{"label":"Datasources","type":"hasLabel","value":true},{"label":"REST API plugin","type":"hasLabel","value":true},{"label":"Prepared statements","type":"hasLabel","value":true},{"label":"Query Generation","type":"hasLabel","value":true},{"label":"Core Query Execution","type":"hasLabel","value":true},{"label":"Query Management","type":"hasLabel","value":true},{"label":"Query Settings","type":"hasLabel","value":true},{"label":"Query performance","type":"hasLabel","value":true},{"label":"Datatype issue","type":"hasLabel","value":true},{"label":"SmartSubstitution","type":"hasLabel","value":true},{"label":"Suggested Widgets","type":"hasLabel","value":true},{"label":"SAAS Plugins","type":"hasLabel","value":true},{"label":"Reconnect DS modal","type":"hasLabel","value":true},{"label":"OnPageLoad","type":"hasLabel","value":true},{"label":"File upload issues","type":"hasLabel","value":true},{"label":"AI","type":"hasLabel","value":true},{"label":"Appsmith AI","type":"hasLabel","value":true},{"label":"Database Schema","type":"hasLabel","value":true}],"requires":1},"Identity & Authentication Product":{"conditions":[{"label":"Login / Signup","type":"hasLabel","value":true},{"label":"SSO","type":"hasLabel","value":true},{"label":"SCIM","type":"hasLabel","value":true},{"label":"Email verification","type":"hasLabel","value":true}],"requires":1},"Artifact Platform Product":{"conditions":[{"label":"Fork App","type":"hasLabel","value":true},{"label":"Publish App","type":"hasLabel","value":true},{"label":"Secret Management","type":"hasLabel","value":true},{"label":"Import-Export-App","type":"hasLabel","value":true}],"requires":1},"DevOps Pod":{"conditions":[{"label":"Docker","type":"hasLabel","value":true},{"label":"Super Admin","type":"hasLabel","value":true},{"label":"Deployment","type":"hasLabel","value":true},{"label":"K8s","type":"hasLabel","value":true},{"label":"Email Config","type":"hasLabel","value":true},{"label":"Backup & Restore","type":"hasLabel","value":true},{"label":"AWS AMI","type":"hasLabel","value":true},{"label":"Observability","type":"hasLabel","value":true},{"label":"Heroku","type":"hasLabel","value":true},{"label":"New Deployment Mode","type":"hasLabel","value":true},{"label":"Supervisor","type":"hasLabel","value":true},{"label":"Deployment Certificates","type":"hasLabel","value":true},{"label":"Mock Data","type":"hasLabel","value":true},{"label":"AWS ECS","type":"hasLabel","value":true},{"label":"Ingress","type":"hasLabel","value":true},{"label":"Nginx","type":"hasLabel","value":true},{"label":"Setup Issues","type":"hasLabel","value":true}],"requires":1},"Performance Pod":{"conditions":[{"label":"Performance","type":"hasLabel","value":true},{"label":"Performance infra","type":"hasLabel","value":true}],"requires":1},"IDE Pod":{"conditions":[{"label":"Telemetry","type":"hasLabel","value":true},{"label":"i18n","type":"hasLabel","value":true},{"label":"IDE Product","type":"hasLabel","value":true},{"label":"App setting","type":"hasLabel","value":true},{"label":"Debugger Product","type":"hasLabel","value":true},{"label":"Embedding Apps Product","type":"hasLabel","value":true}],"requires":1},"Platform Administration Pod":{"conditions":[{"label":"Airgap","type":"hasLabel","value":true},{"label":"Enterprise Edition","type":"hasLabel","value":true},{"label":"Invite flow","type":"hasLabel","value":true},{"label":"User Profile","type":"hasLabel","value":true},{"label":"User Session ","type":"hasLabel","value":true},{"label":"User Session","type":"hasLabel","value":true},{"label":"Admin Settings Product","type":"hasLabel","value":true},{"label":"RBAC Product","type":"hasLabel","value":true},{"label":"Workspace Product","type":"hasLabel","value":true},{"label":"Branding Product","type":"hasLabel","value":true},{"label":"Audit Logs Product","type":"hasLabel","value":true},{"label":"Identity & Authentication Product","type":"hasLabel","value":true},{"label":"Billing & Licensing Product","type":"hasLabel","value":true},{"label":"Move to Postgres","type":"hasLabel","value":true}],"requires":1},"DB Infrastructure Pod":{"conditions":[],"requires":1},"Widgets & Accelerators Pod":{"conditions":[{"label":"Accelerators Product","type":"hasLabel","value":true},{"label":"Templates Product","type":"hasLabel","value":true},{"label":"Widgets Product","type":"hasLabel","value":true},{"label":"App Theming Product","type":"hasLabel","value":true}],"requires":1},"Packages Pod":{"conditions":[{"label":"Module creator","type":"hasLabel","value":true},{"label":"Module consumer","type":"hasLabel","value":true},{"label":"Package versioning","type":"hasLabel","value":true},{"label":"Convert to module","type":"hasLabel","value":true},{"label":"Query module","type":"hasLabel","value":true},{"label":"JS module","type":"hasLabel","value":true},{"label":"UI module","type":"hasLabel","value":true},{"label":"Packages Pod","type":"hasLabel","value":true}],"requires":1},"Workflows Pod":{"conditions":[{"label":"Workflows Product","type":"hasLabel","value":true}],"requires":1},"Query & JS Pod":{"conditions":[{"label":"Javascript Product","type":"hasLabel","value":true},{"label":"Onboarding Product","type":"hasLabel","value":true},{"label":"Integrations Product","type":"hasLabel","value":true},{"label":"Reconfigure Datasource Modal","type":"hasLabel","value":true}],"requires":1},"QA Pod":{"conditions":[{"label":"QA","type":"hasLabel","value":true},{"label":"Automation Test","type":"hasLabel","value":true},{"label":"TestGap","type":"hasLabel","value":true},{"label":"Automation failures","type":"hasLabel","value":true},{"label":"Needs automation","type":"hasLabel","value":true},{"label":"cypress-flaky-fix","type":"hasLabel","value":true},{"label":"Cypress flaky tests","type":"hasLabel","value":true},{"label":"Cypress","type":"hasLabel","value":true}],"requires":1},"Anvil POD":{"conditions":[{"label":"Checkbox Component","type":"hasLabel","value":true},{"label":"WDS team","type":"hasLabel","value":true},{"label":"Anvil POD","type":"hasLabel","value":true},{"label":"WDS - all widgets","type":"hasLabel","value":true},{"label":"WDS - input widget","type":"hasLabel","value":true},{"label":"WDS - paragraph widget","type":"hasLabel","value":true},{"label":"WDS - statbox widget","type":"hasLabel","value":true},{"label":"WDS - modal widget","type":"hasLabel","value":true},{"label":"WDS - icon widget","type":"hasLabel","value":true},{"label":"WDS - checkbox widget","type":"hasLabel","value":true},{"label":"WDS - table widget","type":"hasLabel","value":true},{"label":"WDS - keyValue widget","type":"hasLabel","value":true},{"label":"WDS - switch group widget","type":"hasLabel","value":true},{"label":"WDS - theming","type":"hasLabel","value":true},{"label":"Anvil layout","type":"hasLabel","value":true},{"label":"Anvil - theming","type":"hasLabel","value":true},{"label":"Anvil - vertical alignment","type":"hasLabel","value":true},{"label":"Anvil - layout component","type":"hasLabel","value":true},{"label":"Anvil - drag & drop","type":"hasLabel","value":true},{"label":"Anvil - zones & sections","type":"hasLabel","value":true},{"label":"Anvil - copy paste experience","type":"hasLabel","value":true},{"label":"WDS - phone widget","type":"hasLabel","value":true},{"label":"WDS - responsive widget","type":"hasLabel","value":true},{"label":"Anvil - responsive viewport","type":"hasLabel","value":true},{"label":"WDS - widget styling","type":"hasLabel","value":true},{"label":"Anvil - spacing","type":"hasLabel","value":true},{"label":"Anvil - responsive canvas","type":"hasLabel","value":true},{"label":"WDS - inline button widget","type":"hasLabel","value":true},{"label":"Anvil team","type":"hasLabel","value":true}],"requires":1},"Activation Pod":{"conditions":[{"label":"Activation","type":"hasLabel","value":true}],"requires":1},"Stability Pod":{"conditions":[{"label":"Stability Issue","type":"hasLabel","value":true}],"requires":1},"Documentation Pod":{"conditions":[{"label":"Documentation","type":"hasLabel","value":true}],"requires":1},"Packages & Git Pod":{"conditions":[{"label":"Packages Pod","type":"hasLabel","value":true},{"label":"Git Product","type":"hasLabel","value":true},{"label":"Packages Product","type":"hasLabel","value":true},{"label":"Git Platform","type":"hasLabel","value":true}],"requires":1},"Git Platform":{"conditions":[{"label":"Environments Product","type":"hasLabel","value":true},{"label":"Artifact Platform Product","type":"hasLabel","value":true}],"requires":1}}},"root":"."}],"labels":{"Tab Widget":{"color":"e2c76c","name":"Tab Widget","description":""},"Dont merge":{"color":"ADB39C","name":"Dont merge","description":""},"Epic":{"color":"3E4B9E","name":"Epic","description":"A zenhub epic that describes a project"},"Menu Button Widget":{"color":"235708","name":"Menu Button Widget","description":"Issues related to Menu Button widget"},"Checkbox Group widget":{"color":"bbeecd","name":"Checkbox Group widget","description":"Issues related to Checkbox Group Widget"},"Input Widget":{"color":"ae65d8","name":"Input Widget","description":""},"Security":{"color":"99139C","name":"Security","description":""},"QA":{"color":"","name":"QA","description":"Needs QA attention"},"Verified":{"color":"9bf416","name":"Verified","description":""},"Wont Fix":{"color":"ffffff","name":"Wont Fix","description":"This will not be worked on"},"MySQL":{"color":"c9ddc6","name":"MySQL","description":"Issues related to MySQL plugin"},"Development":{"color":"9F8A02","name":"Development","description":""},"Help Wanted":{"color":"008672","name":"Help Wanted","description":"Extra attention is needed"},"Home Page":{"color":"","name":"Home Page","description":"Issues related to the application home page"},"Rating Widget":{"color":"235708","name":"Rating Widget","description":"Issues related to the rating widget"},"Stat Box Widget":{"color":"f1c9ce","name":"Stat Box Widget","description":"Issues related to stat box"},"Enhancement":{"color":"a2eeef","name":"Enhancement","description":"New feature or request"},"Fork App":{"color":"af87c7","name":"Fork App","description":"Issues related to forking apps"},"Container Widget":{"color":"19AD0D","name":"Container Widget","description":"Container widget"},"Papercut":{"color":"B562F6","name":"Papercut","description":""},"Needs Design":{"color":"bfd4f2","name":"Needs Design","description":"needs design or changes to design"},"i18n":{"color":"1799b0","name":"i18n","description":"Represents issues that need to be tackled to handle internationalization"},"Rich Text Editor Widget":{"color":"f72cac","name":"Rich Text Editor Widget","description":""},"skip-changelog":{"color":"06086F","name":"skip-changelog","description":"Adding this label to a PR prevents it from being listed in the changelog"},"Low":{"color":"79e53b","name":"Low","description":"An issue that is neither critical nor breaks a user flow"},"potential-duplicate":{"color":"d3cb2e","name":"potential-duplicate","description":"This label marks issues that are potential duplicates of already open issues"},"Audio Widget":{"color":"447B9A","name":"Audio Widget","description":"Issues related to Audio Widget"},"Firestore":{"color":"8078b0","name":"Firestore","description":"Issues related to the firestore Integration"},"New Widget":{"color":"be4cf2","name":"New Widget","description":"A request for a new widget"},"Modal Widget":{"color":"03846f","name":"Modal Widget","description":""},"UX Improvement":{"color":"f4a089","name":"UX Improvement","description":""},"S3":{"color":"8078b0","name":"S3","description":"Issues related to the S3 plugin"},"Release Blocker":{"color":"5756bf","name":"Release Blocker","description":"This issue must be resolved before the release"},"safari":{"color":"51C6AA","name":"safari","description":"Bugs seen on safari browser"},"Example Apps":{"color":"1799b0","name":"Example Apps","description":"Example apps created for new signups"},"MultiSelect Widget":{"color":"AB62D4","name":"MultiSelect Widget","description":"Issues related to MultiSelect Widget"},"Calendar Widget":{"color":"8c6644","name":"Calendar Widget","description":""},"Website":{"color":"151720","name":"Website","description":"Related to www.appsmith.com website"},"Low effort":{"color":"8B59F0","name":"Low effort","description":"Something that'll take a few days to build"},"Checkbox Widget":{"color":"bbeecd","name":"Checkbox Widget","description":""},"Spam":{"color":"620faf","name":"Spam","description":""},"Voice Recorder Widget":{"color":"85bc87","name":"Voice Recorder Widget","description":""},"Select Widget":{"color":"0c669e","name":"Select Widget","description":"Select or dropdown widget"},"Bug":{"color":"8ba6fd","name":"Bug","description":"Something isn't right"},"Widget Validation":{"color":"6990BC","name":"Widget Validation","description":"Issues related to widget property validation"},"Generate Page":{"color":"2b4664","name":"Generate Page","description":"Issures related to page generation"},"File Picker Widget":{"color":"6ae4f2","name":"File Picker Widget","description":""},"snowflake":{"color":"8078b0","name":"snowflake","description":"Issues related to the snowflake Integration"},"Automation":{"color":"CCAF60","name":"Automation","description":""},"hotfix":{"color":"BA3F1D","name":"hotfix","description":""},"Import-Export-App":{"color":"48883f","name":"Import-Export-App","description":"Issues related to importing and exporting apps"},"High effort":{"color":"A7E87B","name":"High effort","description":"Something that'll take more than a month to build"},"Telemetry":{"color":"bc70f9","name":"Telemetry","description":"Issues related to instrumenting appsmith"},"Radio Widget":{"color":"91ef15","name":"Radio Widget","description":""},"Omnibar":{"color":"1bb96a","name":"Omnibar","description":"Issues related to the omnibar for navigation"},"Button Widget":{"color":"34efae","name":"Button Widget","description":""},"Switch widget":{"color":"33A8CE","name":"Switch widget","description":"The switch widget"},"Map Widget":{"color":"7eef7a","name":"Map Widget","description":""},"Task":{"color":"085630","name":"Task","description":"A simple Todo"},"Design System":{"color":"2958a4","name":"Design System","description":"Design system"},"opera":{"color":"C63F5B","name":"opera","description":"Any issues identified on the opera browser"},"Login / Signup":{"color":"","name":"Login / Signup","description":"Authentication flows"},"Image Widget":{"color":"8de8ad","name":"Image Widget","description":""},"firefox":{"color":"6d56e2","name":"firefox","description":""},"Property Pane":{"color":"b356ff","name":"Property Pane","description":"Issues related to the behaviour of the property pane"},"Deployment":{"color":"93491f","name":"Deployment","description":"Installation process of appsmith"},"Production":{"color":"b60205","name":"Production","description":""},"Dependencies":{"color":"0366d6","name":"Dependencies","description":"Pull requests that update a dependency file"},"Google Sheets":{"color":"8078b0","name":"Google Sheets","description":"Issues related to Google Sheets"},"Icon Button Widget":{"color":"D319CE","name":"Icon Button Widget","description":"Issues related to the icon button widget"},"Mongo":{"color":"8078b0","name":"Mongo","description":"Issues related to Mongo DB plugin"},"Documentation":{"color":"a8dff7","name":"Documentation","description":"Improvements or additions to documentation"},"TestGap":{"color":"","name":"TestGap","description":"Issues identified for test plan improvement"},"keyboard shortcut":{"color":"0688B6","name":"keyboard shortcut","description":""},"Reopen":{"color":"897548","name":"Reopen","description":""},"Redshift":{"color":"8078b0","name":"Redshift","description":"Issues related to the redshift integration"},"Date Picker Widget":{"color":"ef1ce1","name":"Date Picker Widget","description":""},"Entity Explorer":{"color":"1bb96a","name":"Entity Explorer","description":"Issues related to navigation using the entity explorer"},"JS Linting & Errors":{"color":"E56AA5","name":"JS Linting & Errors","description":"Issues related to JS Linting and errors"},"iFrame":{"color":"3CD1DB","name":"iFrame","description":"Issues related to iFrame"},"Stale":{"color":"ededed","name":"Stale","description":null},"Text Widget":{"color":"d130d1","name":"Text Widget","description":""},"Video Widget":{"color":"23dd4b","name":"Video Widget","description":""},"Datasources":{"color":"3d590f","name":"Datasources","description":"Issues related to configuring datasource on appsmith"},"error":{"color":"B66773","name":"error","description":"All issues connected to error messages"},"Form Widget":{"color":"09ed77","name":"Form Widget","description":""},"Needs Triaging":{"color":"e8b851","name":"Needs Triaging","description":"Needs attention from maintainers to triage"},"Autocomplete":{"color":"235708","name":"Autocomplete","description":"Issues related to the autocomplete"},"hacktoberfest":{"color":"0052cc","name":"hacktoberfest","description":"All issues that can be solved by the community during Hacktoberfest"},"Medium effort":{"color":"D31156","name":"Medium effort","description":"Something that'll take more than a week but less than a month to build"},"Release":{"color":"57e5e0","name":"Release","description":""},"High":{"color":"c94d14","name":"High","description":"This issue blocks a user from building or impacts a lot of users"},"UI Performance":{"color":"1799b0","name":"UI Performance","description":"Issues related to UI performance"},"Deploy Preview":{"color":"bfdadc","name":"Deploy Preview","description":"Issues found in Deploy Preview"},"Needs Tests":{"color":"8ee263","name":"Needs Tests","description":"Needs automated tests to assert a feature/bug fix"},"Refactor":{"color":"B96662","name":"Refactor","description":"needs refactoring of code"},"Divider Widget":{"color":"235708","name":"Divider Widget","description":"Issues related to the divider widget"},"Table Widget":{"color":"2eead1","name":"Table Widget","description":""},"Needs More Info":{"color":"e54c10","name":"Needs More Info","description":"Needs additional information"},"Good First Issue":{"color":"7057ff","name":"Good First Issue","description":"Good for newcomers"},"UI Improvement":{"color":"9aeef4","name":"UI Improvement","description":""},"Backend":{"color":"d4c5f9","name":"Backend","description":"This marks the issue or pull request to reference server code"},"Frontend":{"color":"87c7f2","name":"Frontend","description":"This label marks the issue or pull request to reference client code"},"Chart Widget":{"color":"616ecc","name":"Chart Widget","description":""},"List Widget":{"color":"8508A0","name":"List Widget","description":"Issues related to the list widget"},"Duplicate":{"color":"cfd3d7","name":"Duplicate","description":"This issue or pull request already exists"},"JS Snippets":{"color":"8d62d2","name":"JS Snippets","description":"issues related to JS Snippets"},"Copy Paste":{"name":"Copy Paste","description":"Issues related to copy paste","color":"b4f0a9"},"Drag & Drop":{"name":"Drag & Drop","description":"Issues related to the drag & drop experience","color":"92115a"},"Sniping Mode":{"name":"Sniping Mode","description":"Issues related to sniping mode","color":"48883f"},"Redis":{"name":"Redis","description":"Issues related to Redis","color":"8078b0"},"New Datasource":{"color":"60b14c","name":"New Datasource","description":"Requests for new datasources"},"Evaluated Value":{"name":"Evaluated Value","description":"Issues related to evaluated values","color":"39f6e7"},"Undo/Redo":{"name":"Undo/Redo","description":"Issues related to undo/redo","color":"f25880"},"App Navigation":{"name":"App Navigation","description":"Issues related to the topbar navigation and configuring it","color":"4773ab"},"Widgets Pane":{"name":"Widgets Pane","description":"Issues related to the discovery and organisation of widgets","color":"ad5d78"},"View Mode":{"color":"1799b0","name":"View Mode","description":"Issues related to the view mode"},"Content":{"name":"Content","description":"For content related topics i.e blogs, templates, videos","color":"a8dff7"},"Slash Command":{"name":"Slash Command","description":"Issues related to the slash command","color":"a0608e"},"Widget Property":{"name":"Widget Property","description":"Issues related to adding / modifying widget properties across widgets","color":"5e92cb"},"Windows":{"name":"Windows","description":"Issues related exclusively to Windows systems","color":"b4cb8a"},"Old App Issues":{"name":"Old App Issues","description":"Issues related to apps old apps a few weeks old and app issues in stale browser session","color":"87ab18"},"Document Viewer Widget":{"name":"Document Viewer Widget","description":"Issues related to Document Viewer Widget","color":"899d4b"},"Radio Group Widget":{"name":"Radio Group Widget","description":"Issues related to radio group widget","color":"b68495"},"Super Admin":{"name":"Super Admin","description":"Issues related to the super admin page","color":"aa95cf"},"Postgres":{"name":"Postgres","description":"Postgres related issues","color":"8078b0"},"New JS Function":{"name":"New JS Function","description":"Issues related to adding a JS Function","color":"8e8aa4"},"Cannot Reproduce Issue":{"color":"93c9cc","name":"Cannot Reproduce Issue","description":"Issues that cannot be reproduced"},"Widget Grouping":{"name":"Widget Grouping","description":"Issues related to Widget Grouping","color":"a49951"},"K8s":{"name":"K8s","description":"Kubernetes related issues","color":"5f318a"},"Docker":{"name":"Docker","description":"Issues related to docker","color":"89b808"},"Camera Widget":{"name":"Camera Widget","description":"Issues and enhancements related to camera widget","color":"e6038e"},"SAAS Plugins":{"name":"SAAS Plugins","description":"Issues related to SAAS Plugins","color":"80e18f"},"JS Promises":{"name":"JS Promises","description":"Issues related to promises","color":"d7771f"},"OnPageLoad":{"name":"OnPageLoad","description":"OnPageLoad issues on functions and queries","color":"2b4664"},"JS Usability":{"name":"JS Usability","description":"usability issues with JS editor and JS elsewhere","color":"a302b0"},"Currency Input Widget":{"name":"Currency Input Widget","description":"Issues related to currency input widget","color":"b2164f"},"TreeSelect":{"name":"TreeSelect","description":"Issues related to TreeSelect Widget","color":"a1633e"},"MultiTree Select Widget":{"name":"MultiTree Select Widget","description":"Issues related to MultiTree Select Widget","color":"a1633e"},"Welcome Screen":{"name":"Welcome Screen","description":"Issues related to the welcome screen","color":"48883f"},"Realtime Commenting":{"color":"a70b86","name":"Realtime Commenting","description":"In-app communication between teams"},"Phone Input Widget":{"name":"Phone Input Widget","description":"Issues related to the Phone Input widget","color":"a70b86"},"JSON Form":{"name":"JSON Form","description":"Issue / features related to the JSON form wiget","color":"46b209"},"All Widgets":{"name":"All Widgets","description":"Issues related to all widgets","color":"972b36"},"V1":{"name":"V1","description":"V1","color":"67ab2e"},"Reflow & Resize":{"name":"Reflow & Resize","description":"All issues related to reflow and resize experience","color":"748a13"},"SSO":{"name":"SSO","description":"Issues, requests and enhancements around Single sign-on.","color":""},"Multi User Realtime":{"name":"Multi User Realtime","description":"Issues related to multiple users using or editing an application","color":"e7b6ce"},"Ready for design":{"name":"Ready for design","description":"this issue is ready for design: it contains clear problem statements and other required information","color":"ebf442"},"Support":{"name":"Support","description":"Issues created by the A-force team to address user queries","color":"1740f3"},"Button Group widget":{"name":"Button Group widget","description":"Issue and enhancements related to the button group widget","color":"f17025"},"GraphQL Plugin":{"name":"GraphQL Plugin","description":"Issues related to GraphQL plugin","color":"8078b0"},"DevOps Pod":{"name":"DevOps Pod","description":"Issues related to devops","color":"d956c7"},"medium":{"name":"medium","description":"Issues that frustrate users due to poor UX","color":"23dfd9"},"ArangoDB":{"name":"ArangoDB","description":"Issues related to arangoDB","color":"8078b0"},"Code Refactoring":{"name":"Code Refactoring","description":"Issues related to code refactoring","color":"76310e"},"Progress bar widget":{"name":"Progress bar widget","description":"To track issues related to progress bar","color":"2d7abf"},"Audio Recorder Widget":{"name":"Audio Recorder Widget","description":"Issues related to Audio Recorder Widget","color":"9accef"},"Airtable":{"name":"Airtable","description":"Issues for Airtable","color":"60885f"},"Canvas / Grid":{"name":"Canvas / Grid","description":"Issues related to the canvas","color":"16b092"},"Email Config":{"name":"Email Config","description":"Issues related to configuring the email service","color":"2a21d1"},"CURL":{"name":"CURL","description":"Issues related to CURL impor","color":"60885f"},"Canvas Zooms":{"name":"Canvas Zooms","description":"Issues related to zooming the canvas","color":"e6038e"},"business":{"name":"business","description":"Features that will be a part of our business edition","color":"cd59eb"},"Action Pod":{"name":"Action Pod","description":"","color":"ee2e36"},"AutomationGap1":{"color":"a5e07c","name":"AutomationGap1","description":"Issues that needs automated tests"},"A-Force11":{"name":"A-Force11","description":"Issues raised by A-Force team","color":"d667b6"},"Business Edition":{"name":"Business Edition","description":"Features that will be a part of our business edition","color":"89bb6c"},"storeValue":{"name":"storeValue","description":"Issues related to the store value function","color":"5d3e66"},"DynamoDB":{"name":"DynamoDB","description":"Issues that are related to DynamoDB should have this label","color":"60885f"},"Backup & Restore":{"name":"Backup & Restore","description":"Issues related to backup and restore","color":"86874d"},"Billing":{"name":"Billing","description":"Billing infrastructure and flows for Business Edition and Trial users","color":"d2bc40"},"Datatype issue":{"name":"Datatype issue","description":"Issues that have risen because data types weren't handled","color":"cef66b"},"OAuth":{"name":"OAuth","description":"OAuth related bugs or features","color":"60885f"},"Table Widget V2":{"name":"Table Widget V2","description":"Issues related to Table Widget V2","color":"3a7192"},"IDE Navigation":{"name":"IDE Navigation","description":"Issues/feature requests related to IDE navigation, and context switching","color":"1bb96a"},"Query performance":{"name":"Query performance","description":"Issues that have to do with lack in performance of query execution","color":"cef66b"},"SAAS Manager App":{"name":"SAAS Manager App","description":"Issues with the SAAS manager app","color":"d427db"},"Twilio":{"name":"Twilio","description":"Issues related to Twilio integration","color":"23ba8d"},"Hubspot":{"name":"Hubspot","description":"Issues related to Hubspot integration","color":"60885f"},"Zendesk":{"name":"Zendesk","description":"Issues related to Zendesk integration","color":"60885f"},"Entity Refactor":{"name":"Entity Refactor","description":"Issues related to refactor logic","color":"705a2c"},"Map Chart Widget":{"name":"Map Chart Widget","description":"Issues related to Map Chart Widgets","color":"c8397f"},"Product Catchup":{"name":"Product Catchup","description":"Issues created in the product catchup","color":"29cd2c"},"Framework Functions":{"name":"Framework Functions","description":"Issues related to internal functions like showAlert(), navigateTo() etc...","color":"c25a09"},"Frontend Libraries Upgrade":{"name":"Frontend Libraries Upgrade","description":"Issues related to frontend libraries upgrade","color":"ede1fc"},"MsSQL":{"name":"MsSQL","description":"Issues related to MsSQL plugin","color":"8078b0"},"Elastic Search":{"name":"Elastic Search","description":"Issues related to the elastic search datasource","color":"8078b0"},"Core Query Execution":{"color":"cef66b","name":"Core Query Execution","description":"Issues related to the execution of all queries"},"Query Management":{"name":"Query Management","description":"Issues related to the CRUD of actions or queries","color":"cef66b"},"Query Settings":{"name":"Query Settings","description":"Issues related to the settings of all queries","color":"cef66b"},"Code Editor":{"name":"Code Editor","description":"Issues related to the code editor","color":"4ca16e"},"Query Forms":{"color":"12b253","name":"Query Forms","description":"Isuses related to the query forms"},"JS Objects":{"color":"22962c","name":"JS Objects","description":"Issues related to JS Objects"},"JS Evaluation":{"color":"22962c","name":"JS Evaluation","description":"Issues related to JS evaluation on the platform"},"SmartSubstitution":{"name":"SmartSubstitution","description":"Issues related to Smart substitution of mustache bindings in queries","color":"bae511"},"Query Generation":{"name":"Query Generation","description":"Issues related to query generation","color":"cef66b"},"Suggested Widgets":{"name":"Suggested Widgets","description":"Issues related to suggesting widgets based on query response","color":"6ac063"},"Code Scanner Widget":{"name":"Code Scanner Widget","description":"Issues related to code scanner widget","color":"9bc1a0"},"Clean URLs":{"name":"Clean URLs","description":"Issues related to clean URLs epic","color":"112623"},"Widget keyboard accessibility":{"name":"Widget keyboard accessibility","description":"All issues related to keyboard accessibility in widgets","color":"b626fd"},"Connection pool":{"name":"Connection pool","description":"issues to do with connection pooling of various plugins","color":"94fe36"},"List Widget V2":{"name":"List Widget V2","description":"Issues related to the list widget v2","color":"adaaf7"},"Auto Height":{"name":"Auto Height","description":"Issues related to dynamic height of widgets","color":"5149cf"},"cypress_failed_test":{"name":"cypress_failed_test","description":"Cypress failed tests","color":"4745d5"},"Needs validation":{"name":"Needs validation","description":"Needs problem validation before being picked up","color":"66673d"},"Slider Widget":{"name":"Slider Widget","description":"Issues raised for slider widgets.","color":"2eef5f"},"Multitenancy":{"name":"Multitenancy","description":"Support multitenancy within single appsmith instance","color":"8c49a9"},"Conversion Algorithm":{"name":"Conversion Algorithm","description":"All issue related to converting app from fixed to flex mode & vice versa","color":"d12d2e"},"Browser specific":{"name":"Browser specific","description":"All issue related to browser","color":"d12d2e"},"Performance infra":{"name":"Performance infra","description":"all issue related to the performance infra","color":"8a60f6"},"DSL Update":{"name":"DSL Update","description":"Issues related to storing and updating the DSL","color":"e16cf3"},"AST-frontend":{"name":"AST-frontend","description":"Issues related to maintaining AST logic","color":"2b4664"},"AST-backend":{"name":"AST-backend","description":"Backend issues related to AST parsing","color":"48883f"},"MariaDB":{"name":"MariaDB","description":"MariaDB datasource","color":"8428c3"},"ADS Component Issue":{"name":"ADS Component Issue","description":"Issues which are caused due to ADS components","color":"d89119"},"Regressed":{"color":"723fd0","name":"Regressed","description":"Scenarios that were working before but have now regressed"},"Needs RCA":{"name":"Needs RCA","description":"a critical or high priority issue that needs an RCA","color":"2cc68f"},"Custom JS Libraries":{"name":"Custom JS Libraries","description":"Issues related to adding custom JS library","color":"bacb6d"},"Integrations Pod General":{"name":"Integrations Pod General","description":"Issues related to the Integrations Pod that don't fit into other tags.","color":"287823"},"Performance Pod":{"name":"Performance Pod","description":"All things related to Appsmith performance","color":"b5a25d"},"Performance":{"name":"Performance","description":"Issues related to performance","color":"9a18d7"},"File upload issues":{"name":"File upload issues","description":"Issues related to uploading any type of files from within Appsmith","color":"2b4664"},"Action Selector":{"name":"Action Selector","description":"Issues related to action selector on the property pane","color":"2f9e20"},"Community Reported":{"name":"Community Reported","description":"issues reported by community members","color":"1402e5"},"JS Function execution":{"name":"JS Function execution","description":"JS function execution","color":"7c2de1"},"Self Serve":{"name":"Self Serve","description":"For all issues related to self-serve flow for business edition","color":"4dacfc"},"Self Serve 1.0":{"name":"Self Serve 1.0","description":"For all issues related to v1 of the self serve project","color":"ae839e"},"Customer Portal":{"name":"Customer Portal","description":"For all tasks/issues pertaining to customer.appsmith.com","color":"d2bc40"},"Cloud Services":{"name":"Cloud Services","description":"For all tasks/issues on Appsmith cloud-services relating to licensing, usage and billing","color":"d2bc40"},"One-click Binding":{"name":"One-click Binding","description":"Issues related to the One click binding epic","color":"f1661c"},"Airgap":{"name":"Airgap","description":"Tickets related to supporting air-gapped Appsmith instances","color":"1cb294"},"SMTP plugin":{"name":"SMTP plugin","description":"Issues related to SMTP plugin","color":"541457"},"AWS AMI":{"name":"AWS AMI","description":"Issues Related to AWS AMI","color":"b44680"},"Old widget version":{"name":"Old widget version","description":"Use this label to raise issue specific only to an older version of a widget","color":"ff3814"},"Enterprise Billing":{"name":"Enterprise Billing","description":"To track all tasks/issues related to licensing & billing for enterprise customers","color":"14c156"},"Oracle SQL DB":{"name":"Oracle SQL DB","description":"Issues related to the Oracle plugin","color":"cbabcb"},"Community Contributor":{"name":"Community Contributor","description":"Meant to track issues that are assigned to external contributors","color":"149ab6"},"widget vertical alignment":{"name":"widget vertical alignment","description":"All issue related widget vertical alignment on the auto layout canvas","color":"d12d2e"},"Observability":{"name":"Observability","description":"Issues related to observability on the Appsmith instance","color":"dff913"},"Checkbox Component":{"name":"Checkbox Component","description":"This labels deals with checkbox component in wds package","color":"75a401"},"Analytics Improvements":{"name":"Analytics Improvements","description":"For all tasks focused on improving our overall analytics and fixing any issues ","color":"29b8ed"},"WDS team":{"name":"WDS team","description":"","color":"8d675a"},"Enterprise Edition":{"name":"Enterprise Edition","description":"Features that will be supported in Enterprise Edition only","color":"984f5e"},"Query filter":{"name":"Query filter","description":"Issues related to query filtering, e.g., WHERE clause","color":"a15134"},"Keyboard accessibility ":{"name":"Keyboard accessibility ","description":"All issue related to ADS component keyboard accessibility","color":"2ba696"},"Toggle button":{"name":"Toggle button","description":"All issue related to ADS toggle button","color":"edc47f"},"SCIM":{"name":"SCIM","description":"Label to collate our SCIM issues","color":"48883f"},"ADS Category Token":{"name":"ADS Category Token","description":"All issues related appsmith design system category tokens","color":"920961"},"ADS Component Documentation":{"name":"ADS Component Documentation","description":"All issues Appsmith design system component documentation","color":"64c46a"},"ADS Migration":{"name":"ADS Migration","description":"All issues related to Appsmith design system migration","color":"b082d6"},"ADS Deduplication ":{"name":"ADS Deduplication ","description":"Replacing component with ADS components","color":"b082d6"},"ADS Revamp":{"name":"ADS Revamp","description":"All issues related to ads revamp. ","color":"b082d6"},"ADS Deduplication":{"name":"ADS Deduplication","description":"Replacing component with ADS components","color":"b082d6"},"ADS Grayscale":{"name":"ADS Grayscale","description":"Support grayscale color changes","color":"b03577"},"ADS Unit Test":{"name":"ADS Unit Test","description":"All issue related ads unit cases ","color":"b082d6"},"ADS Components":{"name":"ADS Components","description":"All issues related ADS components","color":"b082d6"},"Widget Discoverability":{"name":"Widget Discoverability","description":"Issues related to Widget Discoverability","color":"7b55ce"},"Widget setter method":{"name":"Widget setter method","description":"Issues with widget property setters","color":"8dce87"},"License":{"name":"License","description":"For all issues/tasks related to licensing of appsmith-ee edition","color":"90ee98"},"Platformization":{"name":"Platformization","description":"Issues or tasks related to platformization of Appsmith codebase","color":"4e972b"},"Activation - datasources":{"name":"Activation - datasources","description":"issues related to activation projects","color":"7c7ace"},"Partial-import-export":{"name":"Partial-import-export","description":"Label for granular reusability.","color":"717732"},"AI":{"name":"AI","description":"All tasks related to AI","color":"2b4664"},"ADS Typography":{"name":"ADS Typography","description":"All issue related typographical changes","color":"2dbe8d"},"Auto Layout":{"name":"Auto Layout","description":"Issues relates to auto layout","color":"92cf8c"},"Heroku":{"name":"Heroku","description":"Issues related to Heroku","color":"a81b69"},"ADS Visual Styles":{"name":"ADS Visual Styles","description":"All issues related to ADS visual styles","color":"d3da89"},"ADS Component Design":{"name":"ADS Component Design","description":"All issue related to component design","color":"5cc91e"},"Modal Component":{"name":"Modal Component","description":"All issue related to ads modal component","color":"ee63f3"},"App setting":{"name":"App setting","description":"Related to app settings panel within the app","color":"174f98"},"BE instance":{"name":"BE instance","description":"For all issues related to license, billing on BE instance","color":"ae8f98"},"Fixed layout":{"name":"Fixed layout","description":"issues related to fixed layout","color":"b66681"},"Anvil layout":{"name":"Anvil layout","description":"issues related to the new layout system anvil","color":"5e0904"},"New Deployment Mode":{"name":"New Deployment Mode","description":"Support a new mode of deployment","color":"108033"},"Custom widgets":{"name":"Custom widgets","description":"For all issues related to the custom widget project","color":"c9db9c"},"Homepage Experience V2":{"name":"Homepage Experience V2","description":"Label for reporting new tasks and bug fixes related to revamped homepage experience","color":"c55d54"},"Customer Success":{"name":"Customer Success","description":"Issues that the success team cares about","color":"6ccabd"},"Invite flow":{"name":"Invite flow","description":"Invite users flow and any associated actions","color":"881b35"},"Invite users":{"name":"Invite users","description":"Invite users flow and any associated actions","color":""},"Workflows Pod":{"name":"Workflows Pod","description":"Issues that the workflows team owns","color":"446925"},"DailyPromotionBlocker":{"name":"DailyPromotionBlocker","description":"DailyPromotion Blocker","color":"9b2280"},"JS Binding":{"name":"JS Binding","description":"All issues related to the JS Binding experience","color":"422fed"},"REST API":{"name":"REST API","description":"REST API plugin related issues","color":"e3ede5"},"Critical":{"color":"a1e3db","name":"Critical","description":"This issue breaks existing apps. Drop everything else to resolve"},"Module creator":{"name":"Module creator","description":"Issues related to the module creator side","color":"bb2c05"},"Module consumer":{"name":"Module consumer","description":"Issues related to the module consumer side","color":"83d3c5"},"Package versioning":{"name":"Package versioning","description":"ISsues related to how we manage versions for packages","color":"4c5218"},"Convert to module":{"name":"Convert to module","description":"Issues related to the module creation flow using conversion","color":"4c5218"},"Query module":{"name":"Query module","description":"Issues affecting query modules or its instances","color":"b11a7e"},"JS module":{"name":"JS module","description":"Issues affecting JS modules or its instances","color":"bf76f6"},"Secret Management":{"name":"Secret Management","description":"Issues related to secret management","color":"2b4664"},"REST API plugin":{"name":"REST API plugin","description":"REST API plugin related issues","color":"b5948a"},"UI module":{"name":"UI module","description":"Issues affecting UI modules or its instances","color":"d2acee"},"Preview mode":{"name":"Preview mode","description":"Issues related to app previews","color":"48883f"},"Git Auto-commit":{"name":"Git Auto-commit","description":"Issues related to autocommit","color":"717732"},"QA Pod":{"name":"QA Pod","description":"Issues under the QA Pod","color":"717732"},"Automation Test":{"name":"Automation Test","description":"","color":""},"Automation failures":{"name":"Automation failures","description":"","color":""},"Needs automation":{"name":"Needs automation","description":"Issues that needs automated tests","color":""},"Prepared statements":{"name":"Prepared statements","description":"Issues related to prepared statement flow","color":""},"Switch Group Widget":{"name":"Switch Group Widget","description":"Issues related to Switch group Widget","color":""},"Supervisor":{"name":"Supervisor","description":"Issues related to supervisor","color":"2c5813"},"Deployment Certificates":{"name":"Deployment Certificates","description":"Issues related to lets encrypt","color":"e148aa"},"Mock Data":{"name":"Mock Data","description":"Issues related to mock databases","color":"ebf251"},"AWS ECS":{"name":"AWS ECS","description":"Issues related to ECS Fargate","color":"e506ff"},"Publish App":{"name":"Publish App","description":"Issues related to app deployment","color":"2b4664"},"IDE Infra":{"name":"IDE Infra","description":"Issues related to the IDE infrastructure like saving changes","color":"1bb96a"},"User Profile":{"name":"User Profile","description":"Issues related to a user profile","color":"a60d34"},"Page Management":{"color":"1bb96a","name":"Page Management","description":"Issues related to configuring pages"},"Ingress":{"name":"Ingress","description":"Ingress Controller","color":"a86802"},"Nginx":{"name":"Nginx","description":"Issues related to Nginx","color":"e54195"},"Building blocks":{"name":"Building blocks","description":"Building blocks on cavas, on templates listing or drag and drop of building blocks.","color":"48883f"},"Table Inline Edit":{"name":"Table Inline Edit","description":"Issues related to inline editing","color":"60895a"},"User Session ":{"name":"User Session ","description":"For all issues/tasks related to user sessions","color":"65a3f5"},"WDS - all widgets":{"name":"WDS - all widgets","description":"all widget present in WDS","color":"2670ae"},"WDS - input widget":{"name":"WDS - input widget","description":"Issues related to input widget on WDS","color":"2670ae"},"WDS - paragraph widget":{"name":"WDS - paragraph widget","description":"issues related to paragraph widget on WDS","color":"2670ae"},"WDS - statbox widget":{"name":"WDS - statbox widget","description":"issues related to statbox widget on WDS","color":"2670ae"},"WDS - modal widget":{"name":"WDS - modal widget","description":"Issues related to modal widget on WDS","color":"2670ae"},"WDS - icon widget":{"name":"WDS - icon widget","description":"Issues related to icon widget on WDS","color":"2670ae"},"WDS - checkbox widget":{"name":"WDS - checkbox widget","description":"Issues related to checkbox widget on WDS","color":"2670ae"},"WDS - table widget":{"name":"WDS - table widget","description":"Issues related to table widget on WDS","color":"2670ae"},"WDS - keyValue widget":{"name":"WDS - keyValue widget","description":"Issues related to key-value widget on WDS","color":"2670ae"},"WDS - switch group widget":{"name":"WDS - switch group widget","description":"Issues related to switch group widget on WDS","color":"2670ae"},"WDS - theming":{"name":"WDS - theming","description":"Issues related to theming on the Anvil instance","color":"2670ae"},"Anvil POD":{"name":"Anvil POD","description":"Issue related to Anvil project","color":"5e0904"},"Anvil - theming":{"name":"Anvil - theming","description":"Issues related to theming on the Anvil instance","color":"c28de5"},"Anvil - vertical alignment":{"name":"Anvil - vertical alignment","description":"Issues related to vertical alignment on the Anvil layout","color":"c28de5"},"Anvil - layout component":{"name":"Anvil - layout component","description":"Issues related to layout component on the Anvil layout","color":"c28de5"},"Anvil - drag & drop":{"name":"Anvil - drag & drop","description":"Issues related to drag & drop experience on Anvil","color":"c28de5"},"Anvil - zones & sections":{"name":"Anvil - zones & sections","description":"Issues related to zones and sections on the Anvil layout","color":"c28de5"},"Anvil - copy paste experience":{"name":"Anvil - copy paste experience","description":"Issues related to copy paste experience on the Anvil layout","color":"c28de5"},"WDS - phone widget":{"name":"WDS - phone widget","description":"Issues related to phone widget on WDS","color":"c28de5"},"WDS - responsive widget":{"name":"WDS - responsive widget","description":"All issues related to widget responsiveness","color":"11ee05"},"Anvil - responsive viewport":{"color":"11ee05","name":"Anvil - responsive viewport","description":"Issues seen on different viewports like mobile"},"WDS - widget styling":{"color":"11ee05","name":"WDS - widget styling","description":"all about widget styling"},"Anvil - spacing":{"name":"Anvil - spacing","description":"Related to spacing between widgets in auto layout","color":"11ee05"},"Anvil - responsive canvas":{"name":"Anvil - responsive canvas","description":"All issues related to canvas responsiveness","color":"11ee05"},"WDS - inline button widget":{"name":"WDS - inline button widget","description":"Issues related to inline button widget on WDS","color":"7cef83"},"Activation Pod":{"name":"Activation Pod","description":"for Activation group","color":"d67d00"},"Activation":{"name":"Activation","description":"for Activation group","color":"d67d00"},"Tests":{"name":"Tests","description":"Test issues","color":"4fc7b6"},"Ballpark: XXS":{"name":"Ballpark: XXS","description":"~1xDev in 1/2xSprint","color":""},"Ballpark: XS":{"name":"Ballpark: XS","description":"~1xDev in 1xSprint","color":"53bf71"},"Ballpark: S":{"name":"Ballpark: S","description":"~2xDev in 1xSprint","color":"6e9e65"},"Ballpark: M":{"name":"Ballpark: M","description":"~1xPOD in 1xSprint","color":"2229e6"},"Ballpark: L":{"name":"Ballpark: L","description":"~1xPOD in 3xSprint or 2xPODs in 1xSprint","color":"49962f"},"Ballpark: XL":{"name":"Ballpark: XL","description":"~1xPOD in 1xQuarter or 2xPODs in 2xSprint","color":"b524c9"},"Ballpark: XXL":{"name":"Ballpark: XXL","description":"~2xPODs in 1xQuarter","color":"22092c"},"Auto-commit":{"name":"Auto-commit","description":"Issues related to auto-generated commits showing up on git ","color":"e25b89"},"Continuous Deployment":{"name":"Continuous Deployment","description":"Issues related to CD pipeline on git","color":"aea47c"},"Default branch":{"name":"Default branch","description":"Issues related to using a default branch on git","color":"195737"},"Git status":{"name":"Git status","description":"Issues related to information shown on git status modal or number of changes appearing in a branch","color":"c851b8"},"Git performance":{"name":"Git performance","description":"Issues related to perceived performance on any git operation","color":"189af6"},"Anvil team":{"name":"Anvil team","description":"issues related to the new layout system anvil","color":"798200"},"SDLC":{"name":"SDLC","description":"Issues related to software development lifecycle experiences","color":"bae511"},"Reconnect DS modal":{"name":"Reconnect DS modal","description":"Issues related to reconnect datasource modal post app import","color":"2e398b"},"Stability Pod":{"name":"Stability Pod","description":"For all issues/tasks to be prioritized under Stability pod","color":"86ddf6"},"Stability Issue":{"name":"Stability Issue","description":"Every issue handle by Stability Pod","color":"4d024a"},"Move to Postgres":{"name":"Move to Postgres","description":"Issues required to be solved for the move to Postgres as repository layer","color":"466ab1"},"User Session":{"name":"User Session","description":"Issues related to user sessions","color":"8255e5"},"IDE tabs":{"name":"IDE tabs","description":"query and js tabs","color":"1bb96a"},"Inviting Contribution":{"name":"Inviting Contribution","description":"Issues that we would like contributions to","color":""},"cypress-flaky-fix":{"name":"cypress-flaky-fix","description":"This label is auto-added when a PR which only has Cypress fixes are merged to release","color":"cd8bb6"},"Cypress flaky tests":{"name":"Cypress flaky tests","description":"Test scripts that need to be fixed on Cypress by dev or SDET","color":"cd8bb6"},"Help enterprise":{"name":"Help enterprise","description":"Requested by Appsmith customers or prospects","color":"FF8C00"},"Learnability":{"name":"Learnability","description":"Issues affecting the product learnability, making the product harder for new users.","color":"800c2f"},"ADS Spacing":{"name":"ADS Spacing","description":"","color":"686ebb"},"ads unit test":{"name":"ads unit test","description":"All issue related ads unit cases","color":"686ebb"},"ads revamp":{"name":"ads revamp","description":"All issues related to ads revamp.","color":"686ebb"},"Javascript Product":{"color":"709a21","name":"Javascript Product","description":"Issues related to users writing javascript in appsmith"},"IDE Product":{"color":"1bb96a","name":"IDE Product","description":"Issues related to the IDE Product"},"IDE Pod":{"color":"1bb96a","name":"IDE Pod","description":"Issues that new developers face while exploring the IDE"},"Accelerators Product":{"name":"Accelerators Product","description":"Issues related to app building accelerators","color":"f3fce6"},"Templates Product":{"name":"Templates Product","description":"Issues related to Templates","color":"f3fce6"},"Design System Product":{"name":"Design System Product","description":"Appsmith design system related issues","color":"2b4664"},"ads deduplication":{"name":"ads deduplication","description":"Replacing component with ADS components","color":"708943"},"Admin Settings Product":{"color":"708943","name":"Admin Settings Product","description":"Issues in admin settings pages"},"Appsmith AI":{"name":"Appsmith AI","description":"All issues related to the Appsmith AI datasource","color":"708943"},"Query & JS Pod":{"color":"709a21","name":"Query & JS Pod","description":"Issues related to the query & JS Pod"},"RBAC Product":{"name":"RBAC Product","description":"Issues, requests and enhancements around RBAC.","color":""},"Workspace Product":{"name":"Workspace Product","description":"Issues related to workspaces","color":""},"CE Instance Usage":{"name":"CE Instance Usage","description":"For all issues relating to usage, licensing or billing on the CE instance","color":""},"Billing & Licensing Product":{"name":"Billing & Licensing Product","description":"Issues pertaining to licensing, billing and usage across self serve and enterprise customers","color":"466ab1"},"Platform Administration Pod":{"color":"446925","name":"Platform Administration Pod","description":"Issues related to platform administration & management"},"DB Infrastructure Pod":{"name":"DB Infrastructure Pod","description":"Pod to handle database infrastructure","color":"446925"},"Packages Product":{"name":"Packages Product","description":"Issues related to packages","color":"7e018f"},"Workflows Product":{"name":"Workflows Product","description":"Issues related to the workflows product","color":"446925"},"Debugger Product":{"color":"857f58","name":"Debugger Product","description":"Issues related to the debugger"},"Packages Pod":{"name":"Packages Pod","description":"issues that belong to the packages pod","color":"53742c"},"Environments Product":{"name":"Environments Product","description":"Issues related to datasource environments","color":"857f58"},"Custom Widgets":{"name":"Custom Widgets","description":"For all issues related to the custom widget project","color":"857f58"},"Branding Product":{"name":"Branding Product","description":"All issues under branding and whitelabelling appsmith ecosystem","color":"857f58"},"Widgets & Accelerators Pod":{"name":"Widgets & Accelerators Pod","description":"Issues related to widgets & Accelerators","color":"27496a"},"Widgets Product":{"name":"Widgets Product","description":"This label groups issues related to widgets","color":"f3fce6"},"App Theming Product":{"name":"App Theming Product","description":"Items that are related to the App level theming controls epic","color":"48883f"},"UI Building Product":{"color":"48883f","name":"UI Building Product","description":"Issues related to the UI Building experience"},"Onboarding Product":{"color":"48883f","name":"Onboarding Product","description":"Issues related to onboarding new developers"},"Database Schema":{"name":"Database Schema","description":"Issues related to database schema","color":"48883f"},"Git Product":{"color":"7e018f","name":"Git Product","description":"Issues related to version control product"},"Embedding Apps Product":{"name":"Embedding Apps Product","description":"Issues related to embedding","color":"48883f"},"Integrations Product":{"name":"Integrations Product","description":"Issues related to a specific integration","color":"b9f21c"},"Feature Flagging":{"name":"Feature Flagging","description":"Anything related feature flagging","color":"4574ae"},"Audit Logs Product":{"name":"Audit Logs Product","description":"Audit trails to ensure data security","color":"4574ae"},"Identity & Authentication Product":{"name":"Identity & Authentication Product","description":"Issues related to user identity & authentication","color":"4574ae"},"Email verification":{"name":"Email verification","description":"Email verification issues","color":"4574ae"},"Artifact Platform Product":{"name":"Artifact Platform Product","description":"Issues related to the application platform","color":"4574ae"},"Git IA":{"name":"Git IA","description":"Issues related to Git IA changes","color":"df8bd6"},"Documentation Pod":{"name":"Documentation Pod","description":"Issues related to user education","color":"8c8c02"},"Branch management":{"name":"Branch management","description":"Issues related to using a branch management on git","color":"ebe6af"},"Reconfigure Datasource Modal":{"name":"Reconfigure Datasource Modal","description":"Issues related to reconfigure DS modal that comes after importing applications","color":"5ac17b"},"Setup Issues":{"name":"Setup Issues","description":"Issues related to setting up appsmith","color":"3fc837"},"Packages & Git Pod":{"name":"Packages & Git Pod","description":"All issues belonging to Packages and Git","color":"46ac0e"},"Git Platform":{"name":"Git Platform","description":"Issues related to the git & the app platform","color":"c9ab80"},"Entity Management":{"name":"Entity Management","description":"Copy / Move / Delete widgets / queries / datasources","color":"74c33c"},"Cypress":{"name":"Cypress","description":"Tasks related to Cypress automation","color":"67b83c"}},"success":true} \ No newline at end of file +{"runners":[{"versioning":{"source":"milestones","type":"SemVer"},"prereleaseName":"alpha","issue":{"labels":{"Widgets Product":{"conditions":[{"label":"Button Widget","type":"hasLabel","value":true},{"label":"Chart Widget","type":"hasLabel","value":true},{"label":"Container Widget","type":"hasLabel","value":true},{"label":"Date Picker Widget","type":"hasLabel","value":true},{"label":"Select Widget","type":"hasLabel","value":true},{"label":"File Picker Widget","type":"hasLabel","value":true},{"label":"Form Widget","type":"hasLabel","value":true},{"label":"Image Widget","type":"hasLabel","value":true},{"label":"Input Widget","type":"hasLabel","value":true},{"label":"List Widget","type":"hasLabel","value":true},{"label":"MultiSelect Widget","type":"hasLabel","value":true},{"label":"Map Widget","type":"hasLabel","value":true},{"label":"Modal Widget","type":"hasLabel","value":true},{"label":"Radio Widget","type":"hasLabel","value":true},{"label":"Rich Text Editor Widget","type":"hasLabel","value":true},{"label":"Tab Widget","type":"hasLabel","value":true},{"label":"Table Widget","type":"hasLabel","value":true},{"label":"Text Widget","type":"hasLabel","value":true},{"label":"Video Widget","type":"hasLabel","value":true},{"label":"iFrame","type":"hasLabel","value":true},{"label":"Menu Button","type":"hasLabel","value":true},{"label":"Rating","type":"hasLabel","value":true},{"label":"Widget Validation","type":"hasLabel","value":true},{"label":"New Widget","type":"hasLabel","value":true},{"label":"Switch widget","type":"hasLabel","value":true},{"label":"Audio Widget","type":"hasLabel","value":true},{"label":"Icon Button Widget","type":"hasLabel","value":true},{"label":"Stat Box Widget","type":"hasLabel","value":true},{"label":"Voice Recorder Widget","type":"hasLabel","value":true},{"label":"Calendar Widget","type":"hasLabel","value":true},{"label":"Menu Button Widget","type":"hasLabel","value":true},{"label":"Divider Widget","type":"hasLabel","value":true},{"label":"Rating Widget","type":"hasLabel","value":true},{"label":"View Mode","type":"hasLabel","value":true},{"label":"Widget Property","type":"hasLabel","value":true},{"label":"Document Viewer Widget","type":"hasLabel","value":true},{"label":"Radio Group Widget","type":"hasLabel","value":true},{"label":"Currency Input Widget","type":"hasLabel","value":true},{"label":"TreeSelect","type":"hasLabel","value":true},{"label":"MultiTree Select Widget","type":"hasLabel","value":true},{"label":"Phone Input Widget","type":"hasLabel","value":true},{"label":"JSON Form","type":"hasLabel","value":true},{"label":"All Widgets","type":"hasLabel","value":true},{"label":"Button Group widget","type":"hasLabel","value":true},{"label":"Progress bar widget","type":"hasLabel","value":true},{"label":"Audio Recorder Widget","type":"hasLabel","value":true},{"label":"Camera Widget","type":"hasLabel","value":true},{"label":"Table Widget V2","type":"hasLabel","value":true},{"label":"Map Chart Widget","type":"hasLabel","value":true},{"label":"Code Scanner Widget","type":"hasLabel","value":true},{"label":"Widget keyboard accessibility","type":"hasLabel","value":true},{"label":"List Widget V2","type":"hasLabel","value":true},{"label":"Slider Widget","type":"hasLabel","value":true},{"label":"One-click Binding","type":"hasLabel","value":true},{"label":"Old widget version","type":"hasLabel","value":true},{"label":"Widget Discoverability","type":"hasLabel","value":true},{"label":"Switch Group Widget","type":"hasLabel","value":true},{"label":"Checkbox Group widget","type":"hasLabel","value":true},{"label":"Checkbox Widget","type":"hasLabel","value":true},{"label":"Table Inline Edit","type":"hasLabel","value":true},{"label":"Custom Widgets","type":"hasLabel","value":true}],"requires":1},"Javascript Product":{"conditions":[{"label":"JS Linting & Errors","type":"hasLabel","value":true},{"label":"Autocomplete","type":"hasLabel","value":true},{"label":"Evaluated Value","type":"hasLabel","value":true},{"label":"Slash Command","type":"hasLabel","value":true},{"label":"New JS Function","type":"hasLabel","value":true},{"label":"JS Usability","type":"hasLabel","value":true},{"label":"Framework Functions","type":"hasLabel","value":true},{"label":"JS Objects","type":"hasLabel","value":true},{"label":"JS Evaluation","type":"hasLabel","value":true},{"label":"Custom JS Libraries","type":"hasLabel","value":true},{"label":"Action Selector","type":"hasLabel","value":true},{"label":"Widget setter method","type":"hasLabel","value":true},{"label":"Entity Refactor","type":"hasLabel","value":true},{"label":"AST-frontend","type":"hasLabel","value":true},{"label":"Sniping Mode","type":"hasLabel","value":true},{"label":"AST-backend","type":"hasLabel","value":true}],"requires":1},"IDE Product":{"conditions":[{"label":"IDE Product","type":"hasLabel","value":true},{"label":"IDE Infra","type":"hasLabel","value":true},{"label":"IDE Navigation","type":"hasLabel","value":true},{"label":"IDE tabs","type":"hasLabel","value":true},{"label":"Omnibar","type":"hasLabel","value":true},{"label":"Entity Explorer","type":"hasLabel","value":true},{"label":"Page Management","type":"hasLabel","value":true},{"label":"Preview mode","type":"hasLabel","value":true},{"label":"Entity Management","type":"hasLabel","value":true}],"requires":1},"Accelerators Product":{"conditions":[{"label":"Generate Page","type":"hasLabel","value":true},{"label":"Building blocks","type":"hasLabel","value":true}],"requires":1},"Templates Product":{"conditions":[{"label":"Partial-import-export","type":"hasLabel","value":true},{"label":"Templates Product","type":"hasLabel","value":true}],"requires":1},"Design System Product":{"conditions":[{"label":"Design System Product","type":"hasLabel","value":true},{"label":"ADS Component Issue","type":"hasLabel","value":true},{"label":"Keyboard accessibility ","type":"hasLabel","value":true},{"label":"Toggle button","type":"hasLabel","value":true},{"label":"ADS Category Token","type":"hasLabel","value":true},{"label":"ADS Component Documentation","type":"hasLabel","value":true},{"label":"ADS Migration","type":"hasLabel","value":true},{"label":"ADS Deduplication ","type":"hasLabel","value":true},{"label":"ADS Revamp","type":"hasLabel","value":true},{"label":"ADS Deduplication","type":"hasLabel","value":true},{"label":"ADS Unit Test","type":"hasLabel","value":true},{"label":"ADS Components","type":"hasLabel","value":true},{"label":"ADS Grayscale","type":"hasLabel","value":true},{"label":"Design System","type":"hasLabel","value":true},{"label":"ADS Typography","type":"hasLabel","value":true},{"label":"ADS Visual Styles","type":"hasLabel","value":true},{"label":"ADS Component Design","type":"hasLabel","value":true},{"label":"Modal Component","type":"hasLabel","value":true},{"label":"ADS Spacing","type":"hasLabel","value":true},{"label":"ads unit test","type":"hasLabel","value":true},{"label":"ads revamp","type":"hasLabel","value":true},{"label":"ads deduplication","type":"hasLabel","value":true}],"requires":1},"RBAC Product":{"conditions":[{"label":"Invite users","type":"hasLabel","value":true},{"label":"RBAC Product","type":"hasLabel","value":true}],"requires":1},"Workspace Product":{"conditions":[{"label":"Home Page","type":"hasLabel","value":true},{"label":"Workspace Product","type":"hasLabel","value":true}],"requires":1},"Billing & Licensing Product":{"conditions":[{"label":"Customer Portal","type":"hasLabel","value":true},{"label":"Cloud Services","type":"hasLabel","value":true},{"label":"Billing","type":"hasLabel","value":true},{"label":"Self Serve","type":"hasLabel","value":true},{"label":"Enterprise Billing","type":"hasLabel","value":true},{"label":"Analytics Improvements","type":"hasLabel","value":true},{"label":"Self Serve 1.0","type":"hasLabel","value":true},{"label":"License","type":"hasLabel","value":true},{"label":"BE instance","type":"hasLabel","value":true},{"label":"Invite flow","type":"hasLabel","value":true},{"label":"CE Instance Usage","type":"hasLabel","value":true},{"label":"Feature Flagging","type":"hasLabel","value":true}],"requires":1},"Packages Product":{"conditions":[{"label":"Packages Product","type":"hasLabel","value":true}],"requires":1},"Environments Product":{"conditions":[{"label":"Environments Product","type":"hasLabel","value":true}],"requires":1},"UI Building Product":{"conditions":[{"label":"Property Pane","type":"hasLabel","value":true},{"label":"Copy Paste","type":"hasLabel","value":true},{"label":"Drag & Drop","type":"hasLabel","value":true},{"label":"Undo/Redo","type":"hasLabel","value":true},{"label":"Widgets Pane","type":"hasLabel","value":true},{"label":"UI Performance","type":"hasLabel","value":true},{"label":"Widget Grouping","type":"hasLabel","value":true},{"label":"Reflow & Resize","type":"hasLabel","value":true},{"label":"Canvas / Grid","type":"hasLabel","value":true},{"label":"Auto Height","type":"hasLabel","value":true},{"label":"Browser specific","type":"hasLabel","value":true},{"label":"Auto Layout","type":"hasLabel","value":true},{"label":"Fixed layout","type":"hasLabel","value":true},{"label":"App Navigation","type":"hasLabel","value":true}],"requires":1},"Onboarding Product":{"conditions":[{"label":"Welcome Screen","type":"hasLabel","value":true}],"requires":1},"Git Product":{"conditions":[{"label":"Git Product","type":"hasLabel","value":true},{"label":"Git Auto-commit","type":"hasLabel","value":true},{"label":"Auto-commit","type":"hasLabel","value":true},{"label":"Continuous Deployment","type":"hasLabel","value":true},{"label":"Default branch","type":"hasLabel","value":true},{"label":"Git status","type":"hasLabel","value":true},{"label":"Git performance","type":"hasLabel","value":true},{"label":"SDLC","type":"hasLabel","value":true},{"label":"Git IA","type":"hasLabel","value":true},{"label":"Branch management","type":"hasLabel","value":true}],"requires":1},"Embedding Apps Product":{"conditions":[{"label":"Embedding Apps Product","type":"hasLabel","value":true}],"requires":1},"Integrations Product":{"conditions":[{"label":"New Datasource","type":"hasLabel","value":true},{"label":"Firestore","type":"hasLabel","value":true},{"label":"Google Sheets","type":"hasLabel","value":true},{"label":"Mongo","type":"hasLabel","value":true},{"label":"Redshift","type":"hasLabel","value":true},{"label":"snowflake","type":"hasLabel","value":true},{"label":"S3","type":"hasLabel","value":true},{"label":"Redis","type":"hasLabel","value":true},{"label":"Postgres","type":"hasLabel","value":true},{"label":"GraphQL Plugin","type":"hasLabel","value":true},{"label":"ArangoDB","type":"hasLabel","value":true},{"label":"MsSQL","type":"hasLabel","value":true},{"label":"Elastic Search","type":"hasLabel","value":true},{"label":"OAuth","type":"hasLabel","value":true},{"label":"Airtable","type":"hasLabel","value":true},{"label":"CURL","type":"hasLabel","value":true},{"label":"DynamoDB","type":"hasLabel","value":true},{"label":"Zendesk","type":"hasLabel","value":true},{"label":"Hubspot","type":"hasLabel","value":true},{"label":"Query Forms","type":"hasLabel","value":true},{"label":"Twilio","type":"hasLabel","value":true},{"label":"MySQL","type":"hasLabel","value":true},{"label":"Connection pool","type":"hasLabel","value":true},{"label":"MariaDB","type":"hasLabel","value":true},{"label":"Integrations Pod General","type":"hasLabel","value":true},{"label":"SMTP plugin","type":"hasLabel","value":true},{"label":"Oracle SQL DB","type":"hasLabel","value":true},{"label":"Query filter","type":"hasLabel","value":true},{"label":"Activation - datasources","type":"hasLabel","value":true},{"label":"REST API","type":"hasLabel","value":true},{"label":"REST API","type":"hasLabel","value":true},{"label":"Datasources","type":"hasLabel","value":true},{"label":"REST API plugin","type":"hasLabel","value":true},{"label":"Prepared statements","type":"hasLabel","value":true},{"label":"Query Generation","type":"hasLabel","value":true},{"label":"Core Query Execution","type":"hasLabel","value":true},{"label":"Query Management","type":"hasLabel","value":true},{"label":"Query Settings","type":"hasLabel","value":true},{"label":"Query performance","type":"hasLabel","value":true},{"label":"Datatype issue","type":"hasLabel","value":true},{"label":"SmartSubstitution","type":"hasLabel","value":true},{"label":"Suggested Widgets","type":"hasLabel","value":true},{"label":"SAAS Plugins","type":"hasLabel","value":true},{"label":"Reconnect DS modal","type":"hasLabel","value":true},{"label":"OnPageLoad","type":"hasLabel","value":true},{"label":"File upload issues","type":"hasLabel","value":true},{"label":"AI","type":"hasLabel","value":true},{"label":"Appsmith AI","type":"hasLabel","value":true},{"label":"Database Schema","type":"hasLabel","value":true}],"requires":1},"Identity & Authentication Product":{"conditions":[{"label":"Login / Signup","type":"hasLabel","value":true},{"label":"SSO","type":"hasLabel","value":true},{"label":"SCIM","type":"hasLabel","value":true},{"label":"Email verification","type":"hasLabel","value":true}],"requires":1},"Artifact Platform Product":{"conditions":[{"label":"Fork App","type":"hasLabel","value":true},{"label":"Publish App","type":"hasLabel","value":true},{"label":"Secret Management","type":"hasLabel","value":true},{"label":"Import-Export-App","type":"hasLabel","value":true}],"requires":1},"DevOps Pod":{"conditions":[{"label":"Docker","type":"hasLabel","value":true},{"label":"Super Admin","type":"hasLabel","value":true},{"label":"Deployment","type":"hasLabel","value":true},{"label":"K8s","type":"hasLabel","value":true},{"label":"Email Config","type":"hasLabel","value":true},{"label":"Backup & Restore","type":"hasLabel","value":true},{"label":"AWS AMI","type":"hasLabel","value":true},{"label":"Observability","type":"hasLabel","value":true},{"label":"Heroku","type":"hasLabel","value":true},{"label":"New Deployment Mode","type":"hasLabel","value":true},{"label":"Supervisor","type":"hasLabel","value":true},{"label":"Deployment Certificates","type":"hasLabel","value":true},{"label":"Mock Data","type":"hasLabel","value":true},{"label":"AWS ECS","type":"hasLabel","value":true},{"label":"Ingress","type":"hasLabel","value":true},{"label":"Nginx","type":"hasLabel","value":true},{"label":"Setup Issues","type":"hasLabel","value":true}],"requires":1},"Performance Pod":{"conditions":[{"label":"Performance","type":"hasLabel","value":true},{"label":"Performance infra","type":"hasLabel","value":true}],"requires":1},"IDE Pod":{"conditions":[{"label":"Telemetry","type":"hasLabel","value":true},{"label":"i18n","type":"hasLabel","value":true},{"label":"IDE Product","type":"hasLabel","value":true},{"label":"App setting","type":"hasLabel","value":true},{"label":"Debugger Product","type":"hasLabel","value":true},{"label":"Embedding Apps Product","type":"hasLabel","value":true}],"requires":1},"Platform Administration Pod":{"conditions":[{"label":"Airgap","type":"hasLabel","value":true},{"label":"Enterprise Edition","type":"hasLabel","value":true},{"label":"Invite flow","type":"hasLabel","value":true},{"label":"User Profile","type":"hasLabel","value":true},{"label":"User Session ","type":"hasLabel","value":true},{"label":"User Session","type":"hasLabel","value":true},{"label":"Admin Settings Product","type":"hasLabel","value":true},{"label":"RBAC Product","type":"hasLabel","value":true},{"label":"Workspace Product","type":"hasLabel","value":true},{"label":"Branding Product","type":"hasLabel","value":true},{"label":"Audit Logs Product","type":"hasLabel","value":true},{"label":"Identity & Authentication Product","type":"hasLabel","value":true},{"label":"Billing & Licensing Product","type":"hasLabel","value":true},{"label":"Move to Postgres","type":"hasLabel","value":true}],"requires":1},"DB Infrastructure Pod":{"conditions":[],"requires":1},"Widgets & Accelerators Pod":{"conditions":[{"label":"Accelerators Product","type":"hasLabel","value":true},{"label":"Templates Product","type":"hasLabel","value":true},{"label":"Widgets Product","type":"hasLabel","value":true},{"label":"App Theming Product","type":"hasLabel","value":true}],"requires":1},"Packages Pod":{"conditions":[{"label":"Module creator","type":"hasLabel","value":true},{"label":"Module consumer","type":"hasLabel","value":true},{"label":"Package versioning","type":"hasLabel","value":true},{"label":"Convert to module","type":"hasLabel","value":true},{"label":"Query module","type":"hasLabel","value":true},{"label":"JS module","type":"hasLabel","value":true},{"label":"UI module","type":"hasLabel","value":true},{"label":"Packages Pod","type":"hasLabel","value":true}],"requires":1},"Workflows Pod":{"conditions":[{"label":"Workflows Product","type":"hasLabel","value":true}],"requires":1},"Query & JS Pod":{"conditions":[{"label":"Javascript Product","type":"hasLabel","value":true},{"label":"Onboarding Product","type":"hasLabel","value":true},{"label":"Integrations Product","type":"hasLabel","value":true},{"label":"Reconfigure Datasource Modal","type":"hasLabel","value":true}],"requires":1},"QA Pod":{"conditions":[{"label":"Automation Test","type":"hasLabel","value":true},{"label":"TestGap","type":"hasLabel","value":true},{"label":"Automation failures","type":"hasLabel","value":true},{"label":"Needs automation","type":"hasLabel","value":true},{"label":"cypress-flaky-fix","type":"hasLabel","value":true},{"label":"Cypress flaky tests","type":"hasLabel","value":true},{"label":"Cypress","type":"hasLabel","value":true}],"requires":1},"Anvil POD":{"conditions":[{"label":"Checkbox Component","type":"hasLabel","value":true},{"label":"WDS team","type":"hasLabel","value":true},{"label":"Anvil POD","type":"hasLabel","value":true},{"label":"WDS - all widgets","type":"hasLabel","value":true},{"label":"WDS - input widget","type":"hasLabel","value":true},{"label":"WDS - paragraph widget","type":"hasLabel","value":true},{"label":"WDS - statbox widget","type":"hasLabel","value":true},{"label":"WDS - modal widget","type":"hasLabel","value":true},{"label":"WDS - icon widget","type":"hasLabel","value":true},{"label":"WDS - checkbox widget","type":"hasLabel","value":true},{"label":"WDS - table widget","type":"hasLabel","value":true},{"label":"WDS - keyValue widget","type":"hasLabel","value":true},{"label":"WDS - switch group widget","type":"hasLabel","value":true},{"label":"WDS - theming","type":"hasLabel","value":true},{"label":"Anvil layout","type":"hasLabel","value":true},{"label":"Anvil - theming","type":"hasLabel","value":true},{"label":"Anvil - vertical alignment","type":"hasLabel","value":true},{"label":"Anvil - layout component","type":"hasLabel","value":true},{"label":"Anvil - drag & drop","type":"hasLabel","value":true},{"label":"Anvil - zones & sections","type":"hasLabel","value":true},{"label":"Anvil - copy paste experience","type":"hasLabel","value":true},{"label":"WDS - phone widget","type":"hasLabel","value":true},{"label":"WDS - responsive widget","type":"hasLabel","value":true},{"label":"Anvil - responsive viewport","type":"hasLabel","value":true},{"label":"WDS - widget styling","type":"hasLabel","value":true},{"label":"Anvil - spacing","type":"hasLabel","value":true},{"label":"Anvil - responsive canvas","type":"hasLabel","value":true},{"label":"WDS - inline button widget","type":"hasLabel","value":true},{"label":"Anvil team","type":"hasLabel","value":true}],"requires":1},"Activation Pod":{"conditions":[{"label":"Activation","type":"hasLabel","value":true}],"requires":1},"Stability Pod":{"conditions":[{"label":"Stability Issue","type":"hasLabel","value":true}],"requires":1},"Documentation Pod":{"conditions":[{"label":"Documentation","type":"hasLabel","value":true}],"requires":1},"Packages & Git Pod":{"conditions":[{"label":"Packages Pod","type":"hasLabel","value":true},{"label":"Git Product","type":"hasLabel","value":true},{"label":"Packages Product","type":"hasLabel","value":true},{"label":"Git Platform","type":"hasLabel","value":true}],"requires":1},"Git Platform":{"conditions":[{"label":"Environments Product","type":"hasLabel","value":true},{"label":"Artifact Platform Product","type":"hasLabel","value":true}],"requires":1}}},"root":"."}],"labels":{"Tab Widget":{"color":"e2c76c","name":"Tab Widget","description":""},"Dont merge":{"color":"ADB39C","name":"Dont merge","description":""},"Epic":{"color":"3E4B9E","name":"Epic","description":"A zenhub epic that describes a project"},"Menu Button Widget":{"color":"235708","name":"Menu Button Widget","description":"Issues related to Menu Button widget"},"Checkbox Group widget":{"color":"bbeecd","name":"Checkbox Group widget","description":"Issues related to Checkbox Group Widget"},"Input Widget":{"color":"ae65d8","name":"Input Widget","description":""},"Security":{"color":"99139C","name":"Security","description":""},"QA":{"color":"748fda","name":"QA","description":"Needs QA attention"},"Verified":{"color":"9bf416","name":"Verified","description":""},"Wont Fix":{"color":"ffffff","name":"Wont Fix","description":"This will not be worked on"},"MySQL":{"color":"c9ddc6","name":"MySQL","description":"Issues related to MySQL plugin"},"Development":{"color":"9F8A02","name":"Development","description":""},"Help Wanted":{"color":"008672","name":"Help Wanted","description":"Extra attention is needed"},"Home Page":{"color":"","name":"Home Page","description":"Issues related to the application home page"},"Rating Widget":{"color":"235708","name":"Rating Widget","description":"Issues related to the rating widget"},"Stat Box Widget":{"color":"f1c9ce","name":"Stat Box Widget","description":"Issues related to stat box"},"Enhancement":{"color":"a2eeef","name":"Enhancement","description":"New feature or request"},"Fork App":{"color":"af87c7","name":"Fork App","description":"Issues related to forking apps"},"Container Widget":{"color":"19AD0D","name":"Container Widget","description":"Container widget"},"Papercut":{"color":"B562F6","name":"Papercut","description":""},"Needs Design":{"color":"bfd4f2","name":"Needs Design","description":"needs design or changes to design"},"i18n":{"color":"1799b0","name":"i18n","description":"Represents issues that need to be tackled to handle internationalization"},"Rich Text Editor Widget":{"color":"f72cac","name":"Rich Text Editor Widget","description":""},"skip-changelog":{"color":"06086F","name":"skip-changelog","description":"Adding this label to a PR prevents it from being listed in the changelog"},"Low":{"color":"79e53b","name":"Low","description":"An issue that is neither critical nor breaks a user flow"},"potential-duplicate":{"color":"d3cb2e","name":"potential-duplicate","description":"This label marks issues that are potential duplicates of already open issues"},"Audio Widget":{"color":"447B9A","name":"Audio Widget","description":"Issues related to Audio Widget"},"Firestore":{"color":"8078b0","name":"Firestore","description":"Issues related to the firestore Integration"},"New Widget":{"color":"be4cf2","name":"New Widget","description":"A request for a new widget"},"Modal Widget":{"color":"03846f","name":"Modal Widget","description":""},"UX Improvement":{"color":"f4a089","name":"UX Improvement","description":""},"S3":{"color":"8078b0","name":"S3","description":"Issues related to the S3 plugin"},"Release Blocker":{"color":"5756bf","name":"Release Blocker","description":"This issue must be resolved before the release"},"safari":{"color":"51C6AA","name":"safari","description":"Bugs seen on safari browser"},"Example Apps":{"color":"1799b0","name":"Example Apps","description":"Example apps created for new signups"},"MultiSelect Widget":{"color":"AB62D4","name":"MultiSelect Widget","description":"Issues related to MultiSelect Widget"},"Calendar Widget":{"color":"8c6644","name":"Calendar Widget","description":""},"Website":{"color":"151720","name":"Website","description":"Related to www.appsmith.com website"},"Low effort":{"color":"8B59F0","name":"Low effort","description":"Something that'll take a few days to build"},"Checkbox Widget":{"color":"bbeecd","name":"Checkbox Widget","description":""},"Spam":{"color":"620faf","name":"Spam","description":""},"Voice Recorder Widget":{"color":"85bc87","name":"Voice Recorder Widget","description":""},"Select Widget":{"color":"0c669e","name":"Select Widget","description":"Select or dropdown widget"},"Bug":{"color":"8ba6fd","name":"Bug","description":"Something isn't right"},"Widget Validation":{"color":"6990BC","name":"Widget Validation","description":"Issues related to widget property validation"},"Generate Page":{"color":"2b4664","name":"Generate Page","description":"Issures related to page generation"},"File Picker Widget":{"color":"6ae4f2","name":"File Picker Widget","description":""},"snowflake":{"color":"8078b0","name":"snowflake","description":"Issues related to the snowflake Integration"},"Automation":{"color":"CCAF60","name":"Automation","description":""},"hotfix":{"color":"BA3F1D","name":"hotfix","description":""},"Import-Export-App":{"color":"48883f","name":"Import-Export-App","description":"Issues related to importing and exporting apps"},"High effort":{"color":"A7E87B","name":"High effort","description":"Something that'll take more than a month to build"},"Telemetry":{"color":"bc70f9","name":"Telemetry","description":"Issues related to instrumenting appsmith"},"Radio Widget":{"color":"91ef15","name":"Radio Widget","description":""},"Omnibar":{"color":"1bb96a","name":"Omnibar","description":"Issues related to the omnibar for navigation"},"Button Widget":{"color":"34efae","name":"Button Widget","description":""},"Switch widget":{"color":"33A8CE","name":"Switch widget","description":"The switch widget"},"Map Widget":{"color":"7eef7a","name":"Map Widget","description":""},"Task":{"color":"085630","name":"Task","description":"A simple Todo"},"Design System":{"color":"2958a4","name":"Design System","description":"Design system"},"opera":{"color":"C63F5B","name":"opera","description":"Any issues identified on the opera browser"},"Login / Signup":{"color":"","name":"Login / Signup","description":"Authentication flows"},"Image Widget":{"color":"8de8ad","name":"Image Widget","description":""},"firefox":{"color":"6d56e2","name":"firefox","description":""},"Property Pane":{"color":"b356ff","name":"Property Pane","description":"Issues related to the behaviour of the property pane"},"Deployment":{"color":"93491f","name":"Deployment","description":"Installation process of appsmith"},"Production":{"color":"b60205","name":"Production","description":""},"Dependencies":{"color":"0366d6","name":"Dependencies","description":"Pull requests that update a dependency file"},"Google Sheets":{"color":"8078b0","name":"Google Sheets","description":"Issues related to Google Sheets"},"Icon Button Widget":{"color":"D319CE","name":"Icon Button Widget","description":"Issues related to the icon button widget"},"Mongo":{"color":"8078b0","name":"Mongo","description":"Issues related to Mongo DB plugin"},"Documentation":{"color":"a8dff7","name":"Documentation","description":"Improvements or additions to documentation"},"TestGap":{"color":"","name":"TestGap","description":"Issues identified for test plan improvement"},"keyboard shortcut":{"color":"0688B6","name":"keyboard shortcut","description":""},"Reopen":{"color":"897548","name":"Reopen","description":""},"Redshift":{"color":"8078b0","name":"Redshift","description":"Issues related to the redshift integration"},"Date Picker Widget":{"color":"ef1ce1","name":"Date Picker Widget","description":""},"Entity Explorer":{"color":"1bb96a","name":"Entity Explorer","description":"Issues related to navigation using the entity explorer"},"JS Linting & Errors":{"color":"E56AA5","name":"JS Linting & Errors","description":"Issues related to JS Linting and errors"},"iFrame":{"color":"3CD1DB","name":"iFrame","description":"Issues related to iFrame"},"Stale":{"color":"ededed","name":"Stale","description":null},"Text Widget":{"color":"d130d1","name":"Text Widget","description":""},"Video Widget":{"color":"23dd4b","name":"Video Widget","description":""},"Datasources":{"color":"3d590f","name":"Datasources","description":"Issues related to configuring datasource on appsmith"},"error":{"color":"B66773","name":"error","description":"All issues connected to error messages"},"Form Widget":{"color":"09ed77","name":"Form Widget","description":""},"Needs Triaging":{"color":"e8b851","name":"Needs Triaging","description":"Needs attention from maintainers to triage"},"Autocomplete":{"color":"235708","name":"Autocomplete","description":"Issues related to the autocomplete"},"hacktoberfest":{"color":"0052cc","name":"hacktoberfest","description":"All issues that can be solved by the community during Hacktoberfest"},"Medium effort":{"color":"D31156","name":"Medium effort","description":"Something that'll take more than a week but less than a month to build"},"Release":{"color":"57e5e0","name":"Release","description":""},"High":{"color":"c94d14","name":"High","description":"This issue blocks a user from building or impacts a lot of users"},"UI Performance":{"color":"1799b0","name":"UI Performance","description":"Issues related to UI performance"},"Deploy Preview":{"color":"bfdadc","name":"Deploy Preview","description":"Issues found in Deploy Preview"},"Needs Tests":{"color":"8ee263","name":"Needs Tests","description":"Needs automated tests to assert a feature/bug fix"},"Refactor":{"color":"B96662","name":"Refactor","description":"needs refactoring of code"},"Divider Widget":{"color":"235708","name":"Divider Widget","description":"Issues related to the divider widget"},"Table Widget":{"color":"2eead1","name":"Table Widget","description":""},"Needs More Info":{"color":"e54c10","name":"Needs More Info","description":"Needs additional information"},"Good First Issue":{"color":"7057ff","name":"Good First Issue","description":"Good for newcomers"},"UI Improvement":{"color":"9aeef4","name":"UI Improvement","description":""},"Backend":{"color":"d4c5f9","name":"Backend","description":"This marks the issue or pull request to reference server code"},"Frontend":{"color":"87c7f2","name":"Frontend","description":"This label marks the issue or pull request to reference client code"},"Chart Widget":{"color":"616ecc","name":"Chart Widget","description":""},"List Widget":{"color":"8508A0","name":"List Widget","description":"Issues related to the list widget"},"Duplicate":{"color":"cfd3d7","name":"Duplicate","description":"This issue or pull request already exists"},"JS Snippets":{"color":"8d62d2","name":"JS Snippets","description":"issues related to JS Snippets"},"Copy Paste":{"name":"Copy Paste","description":"Issues related to copy paste","color":"b4f0a9"},"Drag & Drop":{"name":"Drag & Drop","description":"Issues related to the drag & drop experience","color":"92115a"},"Sniping Mode":{"name":"Sniping Mode","description":"Issues related to sniping mode","color":"48883f"},"Redis":{"name":"Redis","description":"Issues related to Redis","color":"8078b0"},"New Datasource":{"color":"60b14c","name":"New Datasource","description":"Requests for new datasources"},"Evaluated Value":{"name":"Evaluated Value","description":"Issues related to evaluated values","color":"39f6e7"},"Undo/Redo":{"name":"Undo/Redo","description":"Issues related to undo/redo","color":"f25880"},"App Navigation":{"name":"App Navigation","description":"Issues related to the topbar navigation and configuring it","color":"4773ab"},"Widgets Pane":{"name":"Widgets Pane","description":"Issues related to the discovery and organisation of widgets","color":"ad5d78"},"View Mode":{"color":"1799b0","name":"View Mode","description":"Issues related to the view mode"},"Content":{"name":"Content","description":"For content related topics i.e blogs, templates, videos","color":"a8dff7"},"Slash Command":{"name":"Slash Command","description":"Issues related to the slash command","color":"a0608e"},"Widget Property":{"name":"Widget Property","description":"Issues related to adding / modifying widget properties across widgets","color":"5e92cb"},"Windows":{"name":"Windows","description":"Issues related exclusively to Windows systems","color":"b4cb8a"},"Old App Issues":{"name":"Old App Issues","description":"Issues related to apps old apps a few weeks old and app issues in stale browser session","color":"87ab18"},"Document Viewer Widget":{"name":"Document Viewer Widget","description":"Issues related to Document Viewer Widget","color":"899d4b"},"Radio Group Widget":{"name":"Radio Group Widget","description":"Issues related to radio group widget","color":"b68495"},"Super Admin":{"name":"Super Admin","description":"Issues related to the super admin page","color":"aa95cf"},"Postgres":{"name":"Postgres","description":"Postgres related issues","color":"8078b0"},"New JS Function":{"name":"New JS Function","description":"Issues related to adding a JS Function","color":"8e8aa4"},"Cannot Reproduce Issue":{"color":"93c9cc","name":"Cannot Reproduce Issue","description":"Issues that cannot be reproduced"},"Widget Grouping":{"name":"Widget Grouping","description":"Issues related to Widget Grouping","color":"a49951"},"K8s":{"name":"K8s","description":"Kubernetes related issues","color":"5f318a"},"Docker":{"name":"Docker","description":"Issues related to docker","color":"89b808"},"Camera Widget":{"name":"Camera Widget","description":"Issues and enhancements related to camera widget","color":"e6038e"},"SAAS Plugins":{"name":"SAAS Plugins","description":"Issues related to SAAS Plugins","color":"80e18f"},"JS Promises":{"name":"JS Promises","description":"Issues related to promises","color":"d7771f"},"OnPageLoad":{"name":"OnPageLoad","description":"OnPageLoad issues on functions and queries","color":"2b4664"},"JS Usability":{"name":"JS Usability","description":"usability issues with JS editor and JS elsewhere","color":"a302b0"},"Currency Input Widget":{"name":"Currency Input Widget","description":"Issues related to currency input widget","color":"b2164f"},"TreeSelect":{"name":"TreeSelect","description":"Issues related to TreeSelect Widget","color":"a1633e"},"MultiTree Select Widget":{"name":"MultiTree Select Widget","description":"Issues related to MultiTree Select Widget","color":"a1633e"},"Welcome Screen":{"name":"Welcome Screen","description":"Issues related to the welcome screen","color":"48883f"},"Realtime Commenting":{"color":"a70b86","name":"Realtime Commenting","description":"In-app communication between teams"},"Phone Input Widget":{"name":"Phone Input Widget","description":"Issues related to the Phone Input widget","color":"a70b86"},"JSON Form":{"name":"JSON Form","description":"Issue / features related to the JSON form wiget","color":"46b209"},"All Widgets":{"name":"All Widgets","description":"Issues related to all widgets","color":"972b36"},"V1":{"name":"V1","description":"V1","color":"67ab2e"},"Reflow & Resize":{"name":"Reflow & Resize","description":"All issues related to reflow and resize experience","color":"748a13"},"SSO":{"name":"SSO","description":"Issues, requests and enhancements around Single sign-on.","color":""},"Multi User Realtime":{"name":"Multi User Realtime","description":"Issues related to multiple users using or editing an application","color":"e7b6ce"},"Ready for design":{"name":"Ready for design","description":"this issue is ready for design: it contains clear problem statements and other required information","color":"ebf442"},"Support":{"name":"Support","description":"Issues created by the A-force team to address user queries","color":"1740f3"},"Button Group widget":{"name":"Button Group widget","description":"Issue and enhancements related to the button group widget","color":"f17025"},"GraphQL Plugin":{"name":"GraphQL Plugin","description":"Issues related to GraphQL plugin","color":"8078b0"},"DevOps Pod":{"name":"DevOps Pod","description":"Issues related to devops","color":"d956c7"},"medium":{"name":"medium","description":"Issues that frustrate users due to poor UX","color":"23dfd9"},"ArangoDB":{"name":"ArangoDB","description":"Issues related to arangoDB","color":"8078b0"},"Code Refactoring":{"name":"Code Refactoring","description":"Issues related to code refactoring","color":"76310e"},"Progress bar widget":{"name":"Progress bar widget","description":"To track issues related to progress bar","color":"2d7abf"},"Audio Recorder Widget":{"name":"Audio Recorder Widget","description":"Issues related to Audio Recorder Widget","color":"9accef"},"Airtable":{"name":"Airtable","description":"Issues for Airtable","color":"60885f"},"Canvas / Grid":{"name":"Canvas / Grid","description":"Issues related to the canvas","color":"16b092"},"Email Config":{"name":"Email Config","description":"Issues related to configuring the email service","color":"2a21d1"},"CURL":{"name":"CURL","description":"Issues related to CURL impor","color":"60885f"},"Canvas Zooms":{"name":"Canvas Zooms","description":"Issues related to zooming the canvas","color":"e6038e"},"business":{"name":"business","description":"Features that will be a part of our business edition","color":"cd59eb"},"Action Pod":{"name":"Action Pod","description":"","color":"ee2e36"},"AutomationGap1":{"color":"a5e07c","name":"AutomationGap1","description":"Issues that needs automated tests"},"A-Force11":{"name":"A-Force11","description":"Issues raised by A-Force team","color":"d667b6"},"Business Edition":{"name":"Business Edition","description":"Features that will be a part of our business edition","color":"89bb6c"},"storeValue":{"name":"storeValue","description":"Issues related to the store value function","color":"5d3e66"},"DynamoDB":{"name":"DynamoDB","description":"Issues that are related to DynamoDB should have this label","color":"60885f"},"Backup & Restore":{"name":"Backup & Restore","description":"Issues related to backup and restore","color":"86874d"},"Billing":{"name":"Billing","description":"Billing infrastructure and flows for Business Edition and Trial users","color":"d2bc40"},"Datatype issue":{"name":"Datatype issue","description":"Issues that have risen because data types weren't handled","color":"cef66b"},"OAuth":{"name":"OAuth","description":"OAuth related bugs or features","color":"60885f"},"Table Widget V2":{"name":"Table Widget V2","description":"Issues related to Table Widget V2","color":"3a7192"},"IDE Navigation":{"name":"IDE Navigation","description":"Issues/feature requests related to IDE navigation, and context switching","color":"1bb96a"},"Query performance":{"name":"Query performance","description":"Issues that have to do with lack in performance of query execution","color":"cef66b"},"SAAS Manager App":{"name":"SAAS Manager App","description":"Issues with the SAAS manager app","color":"d427db"},"Twilio":{"name":"Twilio","description":"Issues related to Twilio integration","color":"23ba8d"},"Hubspot":{"name":"Hubspot","description":"Issues related to Hubspot integration","color":"60885f"},"Zendesk":{"name":"Zendesk","description":"Issues related to Zendesk integration","color":"60885f"},"Entity Refactor":{"name":"Entity Refactor","description":"Issues related to refactor logic","color":"705a2c"},"Map Chart Widget":{"name":"Map Chart Widget","description":"Issues related to Map Chart Widgets","color":"c8397f"},"Product Catchup":{"name":"Product Catchup","description":"Issues created in the product catchup","color":"29cd2c"},"Framework Functions":{"name":"Framework Functions","description":"Issues related to internal functions like showAlert(), navigateTo() etc...","color":"c25a09"},"Frontend Libraries Upgrade":{"name":"Frontend Libraries Upgrade","description":"Issues related to frontend libraries upgrade","color":"ede1fc"},"MsSQL":{"name":"MsSQL","description":"Issues related to MsSQL plugin","color":"8078b0"},"Elastic Search":{"name":"Elastic Search","description":"Issues related to the elastic search datasource","color":"8078b0"},"Core Query Execution":{"color":"cef66b","name":"Core Query Execution","description":"Issues related to the execution of all queries"},"Query Management":{"name":"Query Management","description":"Issues related to the CRUD of actions or queries","color":"cef66b"},"Query Settings":{"name":"Query Settings","description":"Issues related to the settings of all queries","color":"cef66b"},"Code Editor":{"name":"Code Editor","description":"Issues related to the code editor","color":"4ca16e"},"Query Forms":{"color":"12b253","name":"Query Forms","description":"Isuses related to the query forms"},"JS Objects":{"color":"22962c","name":"JS Objects","description":"Issues related to JS Objects"},"JS Evaluation":{"color":"22962c","name":"JS Evaluation","description":"Issues related to JS evaluation on the platform"},"SmartSubstitution":{"name":"SmartSubstitution","description":"Issues related to Smart substitution of mustache bindings in queries","color":"bae511"},"Query Generation":{"name":"Query Generation","description":"Issues related to query generation","color":"cef66b"},"Suggested Widgets":{"name":"Suggested Widgets","description":"Issues related to suggesting widgets based on query response","color":"6ac063"},"Code Scanner Widget":{"name":"Code Scanner Widget","description":"Issues related to code scanner widget","color":"9bc1a0"},"Clean URLs":{"name":"Clean URLs","description":"Issues related to clean URLs epic","color":"112623"},"Widget keyboard accessibility":{"name":"Widget keyboard accessibility","description":"All issues related to keyboard accessibility in widgets","color":"b626fd"},"Connection pool":{"name":"Connection pool","description":"issues to do with connection pooling of various plugins","color":"94fe36"},"List Widget V2":{"name":"List Widget V2","description":"Issues related to the list widget v2","color":"adaaf7"},"Auto Height":{"name":"Auto Height","description":"Issues related to dynamic height of widgets","color":"5149cf"},"cypress_failed_test":{"name":"cypress_failed_test","description":"Cypress failed tests","color":"4745d5"},"Needs validation":{"name":"Needs validation","description":"Needs problem validation before being picked up","color":"66673d"},"Slider Widget":{"name":"Slider Widget","description":"Issues raised for slider widgets.","color":"2eef5f"},"Multitenancy":{"name":"Multitenancy","description":"Support multitenancy within single appsmith instance","color":"8c49a9"},"Conversion Algorithm":{"name":"Conversion Algorithm","description":"All issue related to converting app from fixed to flex mode & vice versa","color":"d12d2e"},"Browser specific":{"name":"Browser specific","description":"All issue related to browser","color":"d12d2e"},"Performance infra":{"name":"Performance infra","description":"all issue related to the performance infra","color":"8a60f6"},"DSL Update":{"name":"DSL Update","description":"Issues related to storing and updating the DSL","color":"e16cf3"},"AST-frontend":{"name":"AST-frontend","description":"Issues related to maintaining AST logic","color":"2b4664"},"AST-backend":{"name":"AST-backend","description":"Backend issues related to AST parsing","color":"48883f"},"MariaDB":{"name":"MariaDB","description":"MariaDB datasource","color":"8428c3"},"ADS Component Issue":{"name":"ADS Component Issue","description":"Issues which are caused due to ADS components","color":"d89119"},"Regressed":{"color":"723fd0","name":"Regressed","description":"Scenarios that were working before but have now regressed"},"Needs RCA":{"name":"Needs RCA","description":"a critical or high priority issue that needs an RCA","color":"2cc68f"},"Custom JS Libraries":{"name":"Custom JS Libraries","description":"Issues related to adding custom JS library","color":"bacb6d"},"Integrations Pod General":{"name":"Integrations Pod General","description":"Issues related to the Integrations Pod that don't fit into other tags.","color":"287823"},"Performance Pod":{"name":"Performance Pod","description":"All things related to Appsmith performance","color":"b5a25d"},"Performance":{"name":"Performance","description":"Issues related to performance","color":"9a18d7"},"File upload issues":{"name":"File upload issues","description":"Issues related to uploading any type of files from within Appsmith","color":"2b4664"},"Action Selector":{"name":"Action Selector","description":"Issues related to action selector on the property pane","color":"2f9e20"},"Community Reported":{"name":"Community Reported","description":"issues reported by community members","color":"1402e5"},"JS Function execution":{"name":"JS Function execution","description":"JS function execution","color":"7c2de1"},"Self Serve":{"name":"Self Serve","description":"For all issues related to self-serve flow for business edition","color":"4dacfc"},"Self Serve 1.0":{"name":"Self Serve 1.0","description":"For all issues related to v1 of the self serve project","color":"ae839e"},"Customer Portal":{"name":"Customer Portal","description":"For all tasks/issues pertaining to customer.appsmith.com","color":"d2bc40"},"Cloud Services":{"name":"Cloud Services","description":"For all tasks/issues on Appsmith cloud-services relating to licensing, usage and billing","color":"d2bc40"},"One-click Binding":{"name":"One-click Binding","description":"Issues related to the One click binding epic","color":"f1661c"},"Airgap":{"name":"Airgap","description":"Tickets related to supporting air-gapped Appsmith instances","color":"1cb294"},"SMTP plugin":{"name":"SMTP plugin","description":"Issues related to SMTP plugin","color":"541457"},"AWS AMI":{"name":"AWS AMI","description":"Issues Related to AWS AMI","color":"b44680"},"Old widget version":{"name":"Old widget version","description":"Use this label to raise issue specific only to an older version of a widget","color":"ff3814"},"Enterprise Billing":{"name":"Enterprise Billing","description":"To track all tasks/issues related to licensing & billing for enterprise customers","color":"14c156"},"Oracle SQL DB":{"name":"Oracle SQL DB","description":"Issues related to the Oracle plugin","color":"cbabcb"},"Community Contributor":{"name":"Community Contributor","description":"Meant to track issues that are assigned to external contributors","color":"149ab6"},"widget vertical alignment":{"name":"widget vertical alignment","description":"All issue related widget vertical alignment on the auto layout canvas","color":"d12d2e"},"Observability":{"name":"Observability","description":"Issues related to observability on the Appsmith instance","color":"dff913"},"Checkbox Component":{"name":"Checkbox Component","description":"This labels deals with checkbox component in wds package","color":"75a401"},"Analytics Improvements":{"name":"Analytics Improvements","description":"For all tasks focused on improving our overall analytics and fixing any issues ","color":"29b8ed"},"WDS team":{"name":"WDS team","description":"","color":"8d675a"},"Enterprise Edition":{"name":"Enterprise Edition","description":"Features that will be supported in Enterprise Edition only","color":"984f5e"},"Query filter":{"name":"Query filter","description":"Issues related to query filtering, e.g., WHERE clause","color":"a15134"},"Keyboard accessibility ":{"name":"Keyboard accessibility ","description":"All issue related to ADS component keyboard accessibility","color":"2ba696"},"Toggle button":{"name":"Toggle button","description":"All issue related to ADS toggle button","color":"edc47f"},"SCIM":{"name":"SCIM","description":"Label to collate our SCIM issues","color":"48883f"},"ADS Category Token":{"name":"ADS Category Token","description":"All issues related appsmith design system category tokens","color":"920961"},"ADS Component Documentation":{"name":"ADS Component Documentation","description":"All issues Appsmith design system component documentation","color":"64c46a"},"ADS Migration":{"name":"ADS Migration","description":"All issues related to Appsmith design system migration","color":"b082d6"},"ADS Deduplication ":{"name":"ADS Deduplication ","description":"Replacing component with ADS components","color":"b082d6"},"ADS Revamp":{"name":"ADS Revamp","description":"All issues related to ads revamp. ","color":"b082d6"},"ADS Deduplication":{"name":"ADS Deduplication","description":"Replacing component with ADS components","color":"b082d6"},"ADS Grayscale":{"name":"ADS Grayscale","description":"Support grayscale color changes","color":"b03577"},"ADS Unit Test":{"name":"ADS Unit Test","description":"All issue related ads unit cases ","color":"b082d6"},"ADS Components":{"name":"ADS Components","description":"All issues related ADS components","color":"b082d6"},"Widget Discoverability":{"name":"Widget Discoverability","description":"Issues related to Widget Discoverability","color":"7b55ce"},"Widget setter method":{"name":"Widget setter method","description":"Issues with widget property setters","color":"8dce87"},"License":{"name":"License","description":"For all issues/tasks related to licensing of appsmith-ee edition","color":"90ee98"},"Platformization":{"name":"Platformization","description":"Issues or tasks related to platformization of Appsmith codebase","color":"4e972b"},"Activation - datasources":{"name":"Activation - datasources","description":"issues related to activation projects","color":"7c7ace"},"Partial-import-export":{"name":"Partial-import-export","description":"Label for granular reusability.","color":"717732"},"AI":{"name":"AI","description":"All tasks related to AI","color":"2b4664"},"ADS Typography":{"name":"ADS Typography","description":"All issue related typographical changes","color":"2dbe8d"},"Auto Layout":{"name":"Auto Layout","description":"Issues relates to auto layout","color":"92cf8c"},"Heroku":{"name":"Heroku","description":"Issues related to Heroku","color":"a81b69"},"ADS Visual Styles":{"name":"ADS Visual Styles","description":"All issues related to ADS visual styles","color":"d3da89"},"ADS Component Design":{"name":"ADS Component Design","description":"All issue related to component design","color":"5cc91e"},"Modal Component":{"name":"Modal Component","description":"All issue related to ads modal component","color":"ee63f3"},"App setting":{"name":"App setting","description":"Related to app settings panel within the app","color":"174f98"},"BE instance":{"name":"BE instance","description":"For all issues related to license, billing on BE instance","color":"ae8f98"},"Fixed layout":{"name":"Fixed layout","description":"issues related to fixed layout","color":"b66681"},"Anvil layout":{"name":"Anvil layout","description":"issues related to the new layout system anvil","color":"5e0904"},"New Deployment Mode":{"name":"New Deployment Mode","description":"Support a new mode of deployment","color":"108033"},"Custom widgets":{"name":"Custom widgets","description":"For all issues related to the custom widget project","color":"c9db9c"},"Homepage Experience V2":{"name":"Homepage Experience V2","description":"Label for reporting new tasks and bug fixes related to revamped homepage experience","color":"c55d54"},"Customer Success":{"name":"Customer Success","description":"Issues that the success team cares about","color":"6ccabd"},"Invite flow":{"name":"Invite flow","description":"Invite users flow and any associated actions","color":"881b35"},"Invite users":{"name":"Invite users","description":"Invite users flow and any associated actions","color":""},"Workflows Pod":{"name":"Workflows Pod","description":"Issues that the workflows team owns","color":"446925"},"DailyPromotionBlocker":{"name":"DailyPromotionBlocker","description":"DailyPromotion Blocker","color":"9b2280"},"JS Binding":{"name":"JS Binding","description":"All issues related to the JS Binding experience","color":"422fed"},"REST API":{"name":"REST API","description":"REST API plugin related issues","color":"e3ede5"},"Critical":{"color":"a1e3db","name":"Critical","description":"This issue breaks existing apps. Drop everything else to resolve"},"Module creator":{"name":"Module creator","description":"Issues related to the module creator side","color":"bb2c05"},"Module consumer":{"name":"Module consumer","description":"Issues related to the module consumer side","color":"83d3c5"},"Package versioning":{"name":"Package versioning","description":"ISsues related to how we manage versions for packages","color":"4c5218"},"Convert to module":{"name":"Convert to module","description":"Issues related to the module creation flow using conversion","color":"4c5218"},"Query module":{"name":"Query module","description":"Issues affecting query modules or its instances","color":"b11a7e"},"JS module":{"name":"JS module","description":"Issues affecting JS modules or its instances","color":"bf76f6"},"Secret Management":{"name":"Secret Management","description":"Issues related to secret management","color":"2b4664"},"REST API plugin":{"name":"REST API plugin","description":"REST API plugin related issues","color":"b5948a"},"UI module":{"name":"UI module","description":"Issues affecting UI modules or its instances","color":"d2acee"},"Preview mode":{"name":"Preview mode","description":"Issues related to app previews","color":"48883f"},"Git Auto-commit":{"name":"Git Auto-commit","description":"Issues related to autocommit","color":"717732"},"QA Pod":{"name":"QA Pod","description":"Issues under the QA Pod","color":"717732"},"Automation Test":{"name":"Automation Test","description":"","color":""},"Automation failures":{"name":"Automation failures","description":"","color":""},"Needs automation":{"name":"Needs automation","description":"Issues that needs automated tests","color":""},"Prepared statements":{"name":"Prepared statements","description":"Issues related to prepared statement flow","color":""},"Switch Group Widget":{"name":"Switch Group Widget","description":"Issues related to Switch group Widget","color":""},"Supervisor":{"name":"Supervisor","description":"Issues related to supervisor","color":"2c5813"},"Deployment Certificates":{"name":"Deployment Certificates","description":"Issues related to lets encrypt","color":"e148aa"},"Mock Data":{"name":"Mock Data","description":"Issues related to mock databases","color":"ebf251"},"AWS ECS":{"name":"AWS ECS","description":"Issues related to ECS Fargate","color":"e506ff"},"Publish App":{"name":"Publish App","description":"Issues related to app deployment","color":"2b4664"},"IDE Infra":{"name":"IDE Infra","description":"Issues related to the IDE infrastructure like saving changes","color":"1bb96a"},"User Profile":{"name":"User Profile","description":"Issues related to a user profile","color":"a60d34"},"Page Management":{"color":"1bb96a","name":"Page Management","description":"Issues related to configuring pages"},"Ingress":{"name":"Ingress","description":"Ingress Controller","color":"a86802"},"Nginx":{"name":"Nginx","description":"Issues related to Nginx","color":"e54195"},"Building blocks":{"name":"Building blocks","description":"Building blocks on cavas, on templates listing or drag and drop of building blocks.","color":"48883f"},"Table Inline Edit":{"name":"Table Inline Edit","description":"Issues related to inline editing","color":"60895a"},"User Session ":{"name":"User Session ","description":"For all issues/tasks related to user sessions","color":"65a3f5"},"WDS - all widgets":{"name":"WDS - all widgets","description":"all widget present in WDS","color":"2670ae"},"WDS - input widget":{"name":"WDS - input widget","description":"Issues related to input widget on WDS","color":"2670ae"},"WDS - paragraph widget":{"name":"WDS - paragraph widget","description":"issues related to paragraph widget on WDS","color":"2670ae"},"WDS - statbox widget":{"name":"WDS - statbox widget","description":"issues related to statbox widget on WDS","color":"2670ae"},"WDS - modal widget":{"name":"WDS - modal widget","description":"Issues related to modal widget on WDS","color":"2670ae"},"WDS - icon widget":{"name":"WDS - icon widget","description":"Issues related to icon widget on WDS","color":"2670ae"},"WDS - checkbox widget":{"name":"WDS - checkbox widget","description":"Issues related to checkbox widget on WDS","color":"2670ae"},"WDS - table widget":{"name":"WDS - table widget","description":"Issues related to table widget on WDS","color":"2670ae"},"WDS - keyValue widget":{"name":"WDS - keyValue widget","description":"Issues related to key-value widget on WDS","color":"2670ae"},"WDS - switch group widget":{"name":"WDS - switch group widget","description":"Issues related to switch group widget on WDS","color":"2670ae"},"WDS - theming":{"name":"WDS - theming","description":"Issues related to theming on the Anvil instance","color":"2670ae"},"Anvil POD":{"name":"Anvil POD","description":"Issue related to Anvil project","color":"5e0904"},"Anvil - theming":{"name":"Anvil - theming","description":"Issues related to theming on the Anvil instance","color":"c28de5"},"Anvil - vertical alignment":{"name":"Anvil - vertical alignment","description":"Issues related to vertical alignment on the Anvil layout","color":"c28de5"},"Anvil - layout component":{"name":"Anvil - layout component","description":"Issues related to layout component on the Anvil layout","color":"c28de5"},"Anvil - drag & drop":{"name":"Anvil - drag & drop","description":"Issues related to drag & drop experience on Anvil","color":"c28de5"},"Anvil - zones & sections":{"name":"Anvil - zones & sections","description":"Issues related to zones and sections on the Anvil layout","color":"c28de5"},"Anvil - copy paste experience":{"name":"Anvil - copy paste experience","description":"Issues related to copy paste experience on the Anvil layout","color":"c28de5"},"WDS - phone widget":{"name":"WDS - phone widget","description":"Issues related to phone widget on WDS","color":"c28de5"},"WDS - responsive widget":{"name":"WDS - responsive widget","description":"All issues related to widget responsiveness","color":"11ee05"},"Anvil - responsive viewport":{"color":"11ee05","name":"Anvil - responsive viewport","description":"Issues seen on different viewports like mobile"},"WDS - widget styling":{"color":"11ee05","name":"WDS - widget styling","description":"all about widget styling"},"Anvil - spacing":{"name":"Anvil - spacing","description":"Related to spacing between widgets in auto layout","color":"11ee05"},"Anvil - responsive canvas":{"name":"Anvil - responsive canvas","description":"All issues related to canvas responsiveness","color":"11ee05"},"WDS - inline button widget":{"name":"WDS - inline button widget","description":"Issues related to inline button widget on WDS","color":"7cef83"},"Activation Pod":{"name":"Activation Pod","description":"for Activation group","color":"d67d00"},"Activation":{"name":"Activation","description":"for Activation group","color":"d67d00"},"Tests":{"name":"Tests","description":"Test issues","color":"4fc7b6"},"Ballpark: XXS":{"name":"Ballpark: XXS","description":"~1xDev in 1/2xSprint","color":""},"Ballpark: XS":{"name":"Ballpark: XS","description":"~1xDev in 1xSprint","color":"53bf71"},"Ballpark: S":{"name":"Ballpark: S","description":"~2xDev in 1xSprint","color":"6e9e65"},"Ballpark: M":{"name":"Ballpark: M","description":"~1xPOD in 1xSprint","color":"2229e6"},"Ballpark: L":{"name":"Ballpark: L","description":"~1xPOD in 3xSprint or 2xPODs in 1xSprint","color":"49962f"},"Ballpark: XL":{"name":"Ballpark: XL","description":"~1xPOD in 1xQuarter or 2xPODs in 2xSprint","color":"b524c9"},"Ballpark: XXL":{"name":"Ballpark: XXL","description":"~2xPODs in 1xQuarter","color":"22092c"},"Auto-commit":{"name":"Auto-commit","description":"Issues related to auto-generated commits showing up on git ","color":"e25b89"},"Continuous Deployment":{"name":"Continuous Deployment","description":"Issues related to CD pipeline on git","color":"aea47c"},"Default branch":{"name":"Default branch","description":"Issues related to using a default branch on git","color":"195737"},"Git status":{"name":"Git status","description":"Issues related to information shown on git status modal or number of changes appearing in a branch","color":"c851b8"},"Git performance":{"name":"Git performance","description":"Issues related to perceived performance on any git operation","color":"189af6"},"Anvil team":{"name":"Anvil team","description":"issues related to the new layout system anvil","color":"798200"},"SDLC":{"name":"SDLC","description":"Issues related to software development lifecycle experiences","color":"bae511"},"Reconnect DS modal":{"name":"Reconnect DS modal","description":"Issues related to reconnect datasource modal post app import","color":"2e398b"},"Stability Pod":{"name":"Stability Pod","description":"For all issues/tasks to be prioritized under Stability pod","color":"86ddf6"},"Stability Issue":{"name":"Stability Issue","description":"Every issue handle by Stability Pod","color":"4d024a"},"Move to Postgres":{"name":"Move to Postgres","description":"Issues required to be solved for the move to Postgres as repository layer","color":"466ab1"},"User Session":{"name":"User Session","description":"Issues related to user sessions","color":"8255e5"},"IDE tabs":{"name":"IDE tabs","description":"query and js tabs","color":"1bb96a"},"Inviting Contribution":{"name":"Inviting Contribution","description":"Issues that we would like contributions to","color":""},"cypress-flaky-fix":{"name":"cypress-flaky-fix","description":"This label is auto-added when a PR which only has Cypress fixes are merged to release","color":"cd8bb6"},"Cypress flaky tests":{"name":"Cypress flaky tests","description":"Test scripts that need to be fixed on Cypress by dev or SDET","color":"cd8bb6"},"Help enterprise":{"name":"Help enterprise","description":"Requested by Appsmith customers or prospects","color":"FF8C00"},"Learnability":{"name":"Learnability","description":"Issues affecting the product learnability, making the product harder for new users.","color":"800c2f"},"ADS Spacing":{"name":"ADS Spacing","description":"","color":"686ebb"},"ads unit test":{"name":"ads unit test","description":"All issue related ads unit cases","color":"686ebb"},"ads revamp":{"name":"ads revamp","description":"All issues related to ads revamp.","color":"686ebb"},"Javascript Product":{"color":"709a21","name":"Javascript Product","description":"Issues related to users writing javascript in appsmith"},"IDE Product":{"color":"1bb96a","name":"IDE Product","description":"Issues related to the IDE Product"},"IDE Pod":{"color":"1bb96a","name":"IDE Pod","description":"Issues that new developers face while exploring the IDE"},"Accelerators Product":{"name":"Accelerators Product","description":"Issues related to app building accelerators","color":"f3fce6"},"Templates Product":{"name":"Templates Product","description":"Issues related to Templates","color":"f3fce6"},"Design System Product":{"name":"Design System Product","description":"Appsmith design system related issues","color":"2b4664"},"ads deduplication":{"name":"ads deduplication","description":"Replacing component with ADS components","color":"708943"},"Admin Settings Product":{"color":"708943","name":"Admin Settings Product","description":"Issues in admin settings pages"},"Appsmith AI":{"name":"Appsmith AI","description":"All issues related to the Appsmith AI datasource","color":"708943"},"Query & JS Pod":{"color":"709a21","name":"Query & JS Pod","description":"Issues related to the query & JS Pod"},"RBAC Product":{"name":"RBAC Product","description":"Issues, requests and enhancements around RBAC.","color":""},"Workspace Product":{"name":"Workspace Product","description":"Issues related to workspaces","color":""},"CE Instance Usage":{"name":"CE Instance Usage","description":"For all issues relating to usage, licensing or billing on the CE instance","color":""},"Billing & Licensing Product":{"name":"Billing & Licensing Product","description":"Issues pertaining to licensing, billing and usage across self serve and enterprise customers","color":"466ab1"},"Platform Administration Pod":{"color":"446925","name":"Platform Administration Pod","description":"Issues related to platform administration & management"},"DB Infrastructure Pod":{"name":"DB Infrastructure Pod","description":"Pod to handle database infrastructure","color":"446925"},"Packages Product":{"name":"Packages Product","description":"Issues related to packages","color":"7e018f"},"Workflows Product":{"name":"Workflows Product","description":"Issues related to the workflows product","color":"446925"},"Debugger Product":{"color":"857f58","name":"Debugger Product","description":"Issues related to the debugger"},"Packages Pod":{"name":"Packages Pod","description":"issues that belong to the packages pod","color":"53742c"},"Environments Product":{"name":"Environments Product","description":"Issues related to datasource environments","color":"857f58"},"Custom Widgets":{"name":"Custom Widgets","description":"For all issues related to the custom widget project","color":"857f58"},"Branding Product":{"name":"Branding Product","description":"All issues under branding and whitelabelling appsmith ecosystem","color":"857f58"},"Widgets & Accelerators Pod":{"name":"Widgets & Accelerators Pod","description":"Issues related to widgets & Accelerators","color":"27496a"},"Widgets Product":{"name":"Widgets Product","description":"This label groups issues related to widgets","color":"f3fce6"},"App Theming Product":{"name":"App Theming Product","description":"Items that are related to the App level theming controls epic","color":"48883f"},"UI Building Product":{"color":"48883f","name":"UI Building Product","description":"Issues related to the UI Building experience"},"Onboarding Product":{"color":"48883f","name":"Onboarding Product","description":"Issues related to onboarding new developers"},"Database Schema":{"name":"Database Schema","description":"Issues related to database schema","color":"48883f"},"Git Product":{"color":"7e018f","name":"Git Product","description":"Issues related to version control product"},"Embedding Apps Product":{"name":"Embedding Apps Product","description":"Issues related to embedding","color":"48883f"},"Integrations Product":{"name":"Integrations Product","description":"Issues related to a specific integration","color":"b9f21c"},"Feature Flagging":{"name":"Feature Flagging","description":"Anything related feature flagging","color":"4574ae"},"Audit Logs Product":{"name":"Audit Logs Product","description":"Audit trails to ensure data security","color":"4574ae"},"Identity & Authentication Product":{"name":"Identity & Authentication Product","description":"Issues related to user identity & authentication","color":"4574ae"},"Email verification":{"name":"Email verification","description":"Email verification issues","color":"4574ae"},"Artifact Platform Product":{"name":"Artifact Platform Product","description":"Issues related to the application platform","color":"4574ae"},"Git IA":{"name":"Git IA","description":"Issues related to Git IA changes","color":"df8bd6"},"Documentation Pod":{"name":"Documentation Pod","description":"Issues related to user education","color":"8c8c02"},"Branch management":{"name":"Branch management","description":"Issues related to using a branch management on git","color":"ebe6af"},"Reconfigure Datasource Modal":{"name":"Reconfigure Datasource Modal","description":"Issues related to reconfigure DS modal that comes after importing applications","color":"5ac17b"},"Setup Issues":{"name":"Setup Issues","description":"Issues related to setting up appsmith","color":"3fc837"},"Packages & Git Pod":{"name":"Packages & Git Pod","description":"All issues belonging to Packages and Git","color":"46ac0e"},"Git Platform":{"name":"Git Platform","description":"Issues related to the git & the app platform","color":"c9ab80"},"Entity Management":{"name":"Entity Management","description":"Copy / Move / Delete widgets / queries / datasources","color":"74c33c"},"Cypress":{"name":"Cypress","description":"Tasks related to Cypress automation","color":"67b83c"}},"success":true} \ No newline at end of file From c06e38eaa922e25c36b052aac8c123aa09ac202c Mon Sep 17 00:00:00 2001 From: Hetu Nandu Date: Mon, 6 Jan 2025 12:58:34 +0530 Subject: [PATCH 24/40] feat: ADS Entity Item (#38442) Co-authored-by: Ankita Kinger --- .../ads/src/List/List.stories.tsx | 4 +- .../ads/src/List/List.styles.tsx | 103 ++++----- .../design-system/ads/src/List/List.tsx | 67 +++--- .../design-system/ads/src/List/List.types.tsx | 4 +- .../EntityExplorer/Editable/index.ts | 1 + .../Editable/useEditableText.test.tsx | 206 ++++++++++++++++++ .../Editable/useEditableText.ts | 137 ++++++++++++ .../EntityExplorer/Editable/utils.ts | 8 + .../EntityItem/EntityItem.stories.tsx | 126 +++++++++++ .../EntityItem/EntityItem.styles.ts | 16 ++ .../EntityExplorer/EntityItem/EntityItem.tsx | 84 +++++++ .../EntityItem/EntityItem.types.ts | 23 ++ .../EntityExplorer/EntityItem/index.ts | 1 + .../ads/src/Templates/EntityExplorer/index.ts | 2 + .../EditableName/EditableName.test.tsx | 172 ++------------- .../Components/EditableName/EditableName.tsx | 124 +---------- ...NameEditor.ts => useValidateEntityName.ts} | 17 +- .../Editor/IDE/EditorTabs/EditableTab.tsx | 2 +- .../Editor/IDE/LeftPane/DataSidePane.test.tsx | 51 +++-- .../Editor/IDE/LeftPane/DataSidePane.tsx | 1 - 20 files changed, 760 insertions(+), 389 deletions(-) create mode 100644 app/client/packages/design-system/ads/src/Templates/EntityExplorer/Editable/index.ts create mode 100644 app/client/packages/design-system/ads/src/Templates/EntityExplorer/Editable/useEditableText.test.tsx create mode 100644 app/client/packages/design-system/ads/src/Templates/EntityExplorer/Editable/useEditableText.ts create mode 100644 app/client/packages/design-system/ads/src/Templates/EntityExplorer/Editable/utils.ts create mode 100644 app/client/packages/design-system/ads/src/Templates/EntityExplorer/EntityItem/EntityItem.stories.tsx create mode 100644 app/client/packages/design-system/ads/src/Templates/EntityExplorer/EntityItem/EntityItem.styles.ts create mode 100644 app/client/packages/design-system/ads/src/Templates/EntityExplorer/EntityItem/EntityItem.tsx create mode 100644 app/client/packages/design-system/ads/src/Templates/EntityExplorer/EntityItem/EntityItem.types.ts create mode 100644 app/client/packages/design-system/ads/src/Templates/EntityExplorer/EntityItem/index.ts rename app/client/src/IDE/Components/EditableName/{useNameEditor.ts => useValidateEntityName.ts} (74%) diff --git a/app/client/packages/design-system/ads/src/List/List.stories.tsx b/app/client/packages/design-system/ads/src/List/List.stories.tsx index cd1acd256d6b..2b86c011a01b 100644 --- a/app/client/packages/design-system/ads/src/List/List.stories.tsx +++ b/app/client/packages/design-system/ads/src/List/List.stories.tsx @@ -210,6 +210,7 @@ export const ListItemBlockDescStory = ListItemTemplate.bind({}) as StoryObj; ListItemBlockDescStory.storyName = "List item block description"; ListItemBlockDescStory.argTypes = ListItemArgTypes; ListItemBlockDescStory.args = { + startIcon: , title: "Action item 1", description: "block", descriptionType: "block", @@ -219,7 +220,8 @@ export const ListItemOverflowStory = ListItemTemplate.bind({}) as StoryObj; ListItemOverflowStory.storyName = "List item title overflow"; ListItemOverflowStory.argTypes = ListItemArgTypes; ListItemOverflowStory.args = { - title: "Action item 1 Action item 1 Action item 1 Action item 1", + title: + "Action item 1 Action item 1 Action item 1 Action item 1 Action item 1", }; export const ListItemRightControlStory = ListItemTemplate.bind({}) as StoryObj; diff --git a/app/client/packages/design-system/ads/src/List/List.styles.tsx b/app/client/packages/design-system/ads/src/List/List.styles.tsx index db47e6987f99..29653f478bbf 100644 --- a/app/client/packages/design-system/ads/src/List/List.styles.tsx +++ b/app/client/packages/design-system/ads/src/List/List.styles.tsx @@ -31,62 +31,37 @@ export const TooltipTextWrapper = styled.div` min-width: 0; `; -export const DescriptionWrapper = styled.div` - flex-direction: column; - min-width: 0; - gap: var(--ads-v2-spaces-2); +export const RightControlWrapper = styled.div` + height: 100%; + line-height: normal; display: flex; + align-items: center; + + button { + margin-left: -4px; + } `; -export const InlineDescriptionWrapper = styled.div` +export const TopContentWrapper = styled.div` display: flex; - justify-content: space-between; align-items: center; - flex: 1; + gap: var(--ads-v2-spaces-3); min-width: 0; + height: 24px; + width: 100%; `; -export const RightControlWrapper = styled.div` - height: 100%; - line-height: normal; +export const BottomContentWrapper = styled.div` + padding-left: var(--ads-v2-spaces-7); + padding-bottom: var(--ads-v2-spaces-2); `; -export const ContentTextWrapper = styled.div` +export const InlineDescriptionWrapper = styled.div` display: flex; - width: 100%; + justify-content: space-between; align-items: center; - box-sizing: border-box; - gap: var(--ads-v2-spaces-3); - overflow: hidden; flex: 1; min-width: 0; - - & .${ListItemTextOverflowClassName} { - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - } - - & .${ListItemTitleClassName} { - font-size: var(--listitem-title-font-size); - line-height: 16px; - } - - & .${ListItemBDescClassName} { - -webkit-line-clamp: 1; - display: -webkit-box; - -webkit-box-orient: vertical; - text-overflow: initial; - white-space: initial; - font-size: var(--listitem-bdescription-font-size); - line-height: normal; - } - - & .${ListItemIDescClassName} { - font-size: var(--listitem-idescription-font-size); - line-height: 16px; - padding-right: var(--ads-v2-spaces-2); - } `; export const StyledList = styled.div` @@ -106,28 +81,24 @@ export const StyledListItem = styled.div<{ display: flex; width: 100%; - align-items: center; cursor: pointer; box-sizing: border-box; position: relative; border-radius: var(--ads-v2-border-radius); padding: var(--ads-v2-spaces-2); padding-left: var(--ads-v2-spaces-3); + gap: var(--ads-v2-spaces-1); + flex: 1; + flex-shrink: 0; + flex-direction: column; ${({ size }) => Sizes[size]} - &[data-isblockdescription="true"] { - height: 54px; - } - - &[data-isblockdescription="false"] { - height: 32px; - } - &[data-rightcontrolvisibility="hover"] { ${RightControlWrapper} { display: none; } + &:hover ${RightControlWrapper} { display: block; } @@ -138,6 +109,7 @@ export const StyledListItem = styled.div<{ } /* disabled style */ + &[data-disabled="true"] { cursor: not-allowed; opacity: var(--ads-v2-opacity-disabled); @@ -153,9 +125,38 @@ export const StyledListItem = styled.div<{ } /* Focus styles */ + &:focus-visible { outline: var(--ads-v2-border-width-outline) solid var(--ads-v2-color-outline); outline-offset: var(--ads-v2-offset-outline); } + + & .${ListItemTextOverflowClassName} { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + flex: 1; + } + + & .${ListItemTitleClassName} { + font-size: var(--listitem-title-font-size); + line-height: 16px; + } + + & .${ListItemBDescClassName} { + -webkit-line-clamp: 1; + display: -webkit-box; + -webkit-box-orient: vertical; + text-overflow: initial; + white-space: initial; + font-size: var(--listitem-bdescription-font-size); + line-height: normal; + } + + & .${ListItemIDescClassName} { + font-size: var(--listitem-idescription-font-size); + line-height: 16px; + padding-right: var(--ads-v2-spaces-2); + } `; diff --git a/app/client/packages/design-system/ads/src/List/List.tsx b/app/client/packages/design-system/ads/src/List/List.tsx index 85fc97c212ab..a6d74126c84a 100644 --- a/app/client/packages/design-system/ads/src/List/List.tsx +++ b/app/client/packages/design-system/ads/src/List/List.tsx @@ -3,13 +3,13 @@ import clsx from "classnames"; import type { ListItemProps, ListProps } from "./List.types"; import { - ContentTextWrapper, - DescriptionWrapper, + BottomContentWrapper, InlineDescriptionWrapper, RightControlWrapper, StyledList, StyledListItem, TooltipTextWrapper, + TopContentWrapper, } from "./List.styles"; import type { TextProps } from "../Text"; import { Text } from "../Text"; @@ -89,7 +89,8 @@ function ListItem(props: ListItemProps) { startIcon, title, } = props; - const isBlockDescription = descriptionType === "block"; + const isBlockDescription = descriptionType === "block" && description; + const isInlineDescription = descriptionType === "inline" && description; const handleOnClick = () => { if (!props.isDisabled && props.onClick) { @@ -97,6 +98,12 @@ function ListItem(props: ListItemProps) { } }; + const handleDoubleClick = () => { + if (!props.isDisabled && props.onDoubleClick) { + props.onDoubleClick(); + } + }; + const handleRightControlClick = (e: React.MouseEvent) => { e.stopPropagation(); }; @@ -105,38 +112,26 @@ function ListItem(props: ListItemProps) { - + {startIcon} {props.customTitleComponent ? ( props.customTitleComponent ) : ( - - - {title} - - {isBlockDescription && description && ( - - {description} - - )} - - {!isBlockDescription && description && ( + + {title} + + {isInlineDescription && ( )} - - {rightControl && ( - - {rightControl} - + {rightControl && ( + + {rightControl} + + )} + + {isBlockDescription && ( + + + {description} + + )} ); diff --git a/app/client/packages/design-system/ads/src/List/List.types.tsx b/app/client/packages/design-system/ads/src/List/List.types.tsx index a39db8ec5310..ecf63fc6522c 100644 --- a/app/client/packages/design-system/ads/src/List/List.types.tsx +++ b/app/client/packages/design-system/ads/src/List/List.types.tsx @@ -8,10 +8,12 @@ export interface ListItemProps { startIcon?: ReactNode; /** The control to display at the end. */ rightControl?: ReactNode; - /** */ + /** Control the visibility trigger of right control */ rightControlVisibility?: "hover" | "always"; /** callback for when the list item is clicked */ onClick: () => void; + /** callback for when the list item is double-clicked */ + onDoubleClick?: () => void; /** Whether the list item is disabled. */ isDisabled?: boolean; /** Whether the list item is selected. */ diff --git a/app/client/packages/design-system/ads/src/Templates/EntityExplorer/Editable/index.ts b/app/client/packages/design-system/ads/src/Templates/EntityExplorer/Editable/index.ts new file mode 100644 index 000000000000..2a2fbaf6fcf7 --- /dev/null +++ b/app/client/packages/design-system/ads/src/Templates/EntityExplorer/Editable/index.ts @@ -0,0 +1 @@ +export { useEditableText } from "./useEditableText"; diff --git a/app/client/packages/design-system/ads/src/Templates/EntityExplorer/Editable/useEditableText.test.tsx b/app/client/packages/design-system/ads/src/Templates/EntityExplorer/Editable/useEditableText.test.tsx new file mode 100644 index 000000000000..455c3f8cc612 --- /dev/null +++ b/app/client/packages/design-system/ads/src/Templates/EntityExplorer/Editable/useEditableText.test.tsx @@ -0,0 +1,206 @@ +import React from "react"; +import { renderHook, act } from "@testing-library/react-hooks"; +import { useEditableText } from "./useEditableText"; +import { fireEvent, render } from "@testing-library/react"; +import { Text } from "../../.."; + +describe("useEditableText", () => { + const mockExitEditing = jest.fn(); + const mockOnNameSave = jest.fn(); + const mockValidateName = jest.fn(); + + beforeEach(() => { + jest.clearAllMocks(); + }); + + test("initial state", () => { + mockValidateName.mockReturnValueOnce(null); + const { result } = renderHook(() => + useEditableText( + false, + "initial_name", + mockExitEditing, + mockValidateName, + mockOnNameSave, + ), + ); + + const [inputRef, editableName, validationError] = result.current; + + expect(editableName).toBe("initial_name"); + expect(validationError).toBeNull(); + expect(inputRef.current).toBeNull(); + }); + + test("handle name change", () => { + mockValidateName.mockReturnValueOnce(null); + const { result } = renderHook(() => + useEditableText( + true, + "initial_name", + mockExitEditing, + mockValidateName, + mockOnNameSave, + ), + ); + + const [, , , , handleTitleChange] = result.current; + + act(() => { + handleTitleChange({ + target: { value: "new_name" }, + } as React.ChangeEvent); + }); + + const [, editableName, validationError] = result.current; + + expect(editableName).toBe("new_name"); + expect(validationError).toBeNull(); + }); + + test("handle valid name save on Enter key", () => { + mockValidateName.mockReturnValueOnce(null); + + const { result } = renderHook(() => + useEditableText( + true, + "initial_name", + mockExitEditing, + mockValidateName, + mockOnNameSave, + ), + ); + + const [, , , handleKeyUp, handleTitleChange] = result.current; + + act(() => { + handleTitleChange({ + target: { value: "new_name" }, + } as React.ChangeEvent); + }); + + act(() => { + handleKeyUp({ + key: "Enter", + } as unknown as React.KeyboardEvent); + }); + + expect(mockOnNameSave).toHaveBeenCalledWith("new_name"); + expect(mockExitEditing).toHaveBeenCalled(); + }); + + test("handle invalid name save on Enter key", () => { + mockValidateName.mockReturnValue("Invalid"); + + const { result } = renderHook(() => + useEditableText( + true, + "initial_name", + mockExitEditing, + mockValidateName, + mockOnNameSave, + ), + ); + + const [, , , handleKeyUp, handleTitleChange] = result.current; + + act(() => { + handleTitleChange({ + target: { value: "invalid_name" }, + } as React.ChangeEvent); + }); + + act(() => { + handleKeyUp({ + key: "Enter", + } as unknown as React.KeyboardEvent); + }); + + expect(mockOnNameSave).not.toHaveBeenCalled(); + expect(mockExitEditing).toHaveBeenCalled(); + }); + + test("handle exit without saving on Escape key", () => { + const { result } = renderHook(() => + useEditableText( + true, + "initial_name", + mockExitEditing, + mockValidateName, + mockOnNameSave, + ), + ); + + const [, , , handleKeyUp] = result.current; + + act(() => { + handleKeyUp({ key: "Escape" } as React.KeyboardEvent); + }); + + expect(mockExitEditing).toHaveBeenCalled(); + expect(mockOnNameSave).not.toHaveBeenCalled(); + }); + + test("handle exit without saving on no change", () => { + const { result } = renderHook(() => + useEditableText( + true, + "initial_name", + mockExitEditing, + mockValidateName, + mockOnNameSave, + ), + ); + + const [, , , handleKeyUp] = result.current; + + act(() => { + handleKeyUp({ key: "Enter" } as React.KeyboardEvent); + }); + + expect(mockExitEditing).toHaveBeenCalled(); + expect(mockOnNameSave).not.toHaveBeenCalled(); + }); + + test("handle focus out event", () => { + mockValidateName.mockReturnValue(null); + const { result } = renderHook(() => + useEditableText( + true, + "initial_name", + mockExitEditing, + mockValidateName, + mockOnNameSave, + ), + ); + + const [inputRef, , , , handleChange] = result.current; + + const inputProps = { onChange: handleChange }; + + const TestComponent = () => { + return ( + + Text + + ); + }; + + render(); + + act(() => { + handleChange({ + target: { value: "new_name" }, + } as React.ChangeEvent); + }); + + act(() => { + if (inputRef.current) { + fireEvent.focusOut(inputRef.current); + } + }); + + expect(mockOnNameSave).toHaveBeenCalledWith("new_name"); + expect(mockExitEditing).toHaveBeenCalled(); + }); +}); diff --git a/app/client/packages/design-system/ads/src/Templates/EntityExplorer/Editable/useEditableText.ts b/app/client/packages/design-system/ads/src/Templates/EntityExplorer/Editable/useEditableText.ts new file mode 100644 index 000000000000..ac8d6d5e621b --- /dev/null +++ b/app/client/packages/design-system/ads/src/Templates/EntityExplorer/Editable/useEditableText.ts @@ -0,0 +1,137 @@ +import { + useCallback, + useEffect, + useState, + type KeyboardEvent, + type ChangeEvent, + useRef, + type RefObject, +} from "react"; +import { usePrevious } from "@mantine/hooks"; +import { useEventCallback, useEventListener } from "usehooks-ts"; +import { normaliseName } from "./utils"; + +export function useEditableText( + isEditing: boolean, + name: string, + exitEditing: () => void, + validateName: (name: string) => string | null, + onNameSave: (name: string) => void, +): [ + RefObject, + string, + string | null, + (e: KeyboardEvent) => void, + (e: ChangeEvent) => void, +] { + const previousName = usePrevious(name); + const [editableName, setEditableName] = useState(name); + const [validationError, setValidationError] = useState(null); + const inputRef = useRef(null); + + const exitWithoutSaving = useCallback(() => { + exitEditing(); + setEditableName(name); + setValidationError(null); + }, [exitEditing, name]); + + const validate = useCallback( + (name: string) => { + const nameError = validateName(name); + + if (nameError === null) { + setValidationError(null); + } else { + setValidationError(nameError); + } + + return nameError; + }, + [validateName], + ); + + const attemptSave = useCallback(() => { + const nameError = validate(editableName); + + if (editableName === name) { + // No change detected + exitWithoutSaving(); + } else if (nameError === null) { + // Save the new name + exitEditing(); + onNameSave(editableName); + } else { + // Exit edit mode and revert name + exitWithoutSaving(); + } + }, [ + editableName, + exitEditing, + exitWithoutSaving, + name, + onNameSave, + validate, + ]); + + const handleKeyUp = useEventCallback((e: KeyboardEvent) => { + if (e.key === "Enter") { + attemptSave(); + } else if (e.key === "Escape") { + exitWithoutSaving(); + } + }); + + const handleTitleChange = useEventCallback( + (e: ChangeEvent) => { + const value = normaliseName(e.target.value); + + setEditableName(value); + validate(value); + }, + ); + + useEventListener( + "focusout", + function handleFocusOut() { + const input = inputRef.current; + + if (input) { + attemptSave(); + } + }, + inputRef, + ); + + useEffect( + function syncEditableTitle() { + if (!isEditing && previousName !== name) { + setEditableName(name); + } + }, + [name, previousName, isEditing], + ); + + // TODO: This is a temporary fix to focus the input after context retention applies focus to its target + // this is a nasty hack to re-focus the input after context retention applies focus to its target + // this will be addressed in a future task, likely by a focus retention modification + useEffect( + function recaptureFocusInEventOfFocusRetention() { + const input = inputRef.current; + + if (isEditing && input) { + setTimeout(() => { + input.focus(); + }, 200); + } + }, + [isEditing, inputRef], + ); + + return [ + inputRef, + editableName, + validationError, + handleKeyUp, + handleTitleChange, + ]; +} diff --git a/app/client/packages/design-system/ads/src/Templates/EntityExplorer/Editable/utils.ts b/app/client/packages/design-system/ads/src/Templates/EntityExplorer/Editable/utils.ts new file mode 100644 index 000000000000..8f308d38ec8e --- /dev/null +++ b/app/client/packages/design-system/ads/src/Templates/EntityExplorer/Editable/utils.ts @@ -0,0 +1,8 @@ +export const normaliseName = (value: string, limit?: number) => { + const separatorRegex = /\W+/; + + return value + .split(separatorRegex) + .join("_") + .slice(0, limit || 30); +}; diff --git a/app/client/packages/design-system/ads/src/Templates/EntityExplorer/EntityItem/EntityItem.stories.tsx b/app/client/packages/design-system/ads/src/Templates/EntityExplorer/EntityItem/EntityItem.stories.tsx new file mode 100644 index 000000000000..eb4be22a56b6 --- /dev/null +++ b/app/client/packages/design-system/ads/src/Templates/EntityExplorer/EntityItem/EntityItem.stories.tsx @@ -0,0 +1,126 @@ +/* eslint-disable no-console */ +import React from "react"; +import type { Meta, StoryObj } from "@storybook/react"; + +import { EntityItem } from "./EntityItem"; +import type { EntityItemProps } from "./EntityItem.types"; +import { ExplorerContainer } from "../ExplorerContainer"; +import { Flex, Button, Icon, Callout } from "../../.."; + +const meta: Meta = { + title: "ADS/Templates/Entity Explorer/Entity Item", + component: EntityItem, +}; + +export default meta; + +const Template = (props: EntityItemProps) => { + const { hasError, isDisabled, isSelected, nameEditorConfig, title } = props; + const [isEditing, setIsEditing] = React.useState(false); + + const onEditComplete = () => { + setIsEditing(false); + }; + const onNameSave = (name: string) => console.log("Name saved" + name); + + const onClick = () => console.log("Add clicked"); + + const rightControl = ( +
+ + ); + })} + + + + + ); +} + +export default RepoLimitErrorModalView; diff --git a/app/client/src/git/components/RepoLimitErrorModal/index.tsx b/app/client/src/git/components/RepoLimitErrorModal/index.tsx new file mode 100644 index 000000000000..47a3c46f8181 --- /dev/null +++ b/app/client/src/git/components/RepoLimitErrorModal/index.tsx @@ -0,0 +1,27 @@ +import React from "react"; +import RepoLimitErrorModalView from "./RepoLimitErrorModalView"; +import { useGitContext } from "../GitContextProvider"; +import useRepoLimitError from "git/hooks/useRepoLimitError"; +import useDisconnect from "git/hooks/useDisconnect"; + +function RepoLimitErrorModal() { + const { artifacts, fetchArtifacts, workspace } = useGitContext(); + const { isRepoLimitErrorModalOpen, toggleRepoLimitErrorModal } = + useRepoLimitError(); + const { openDisconnectModal } = useDisconnect(); + + const workspaceName = workspace?.name ?? null; + + return ( + + ); +} + +export default RepoLimitErrorModal; diff --git a/app/client/src/git/components/SettingsModal/SettingsModalView.tsx b/app/client/src/git/components/SettingsModal/SettingsModalView.tsx index 84693bcc90a3..b361789b7ded 100644 --- a/app/client/src/git/components/SettingsModal/SettingsModalView.tsx +++ b/app/client/src/git/components/SettingsModal/SettingsModalView.tsx @@ -71,16 +71,22 @@ function SettingsModalView({ {createMessage(SETTINGS_GIT)} - + {createMessage(GENERAL)} {showBranchTab && ( - + {createMessage(BRANCH)} )} {createMessage(CONTINUOUS_DELIVERY)} diff --git a/app/client/src/git/components/StatusChanges/StatusChangesView.tsx b/app/client/src/git/components/StatusChanges/StatusChangesView.tsx index f8e6f0c41dfa..b9ec20edaa2d 100644 --- a/app/client/src/git/components/StatusChanges/StatusChangesView.tsx +++ b/app/client/src/git/components/StatusChanges/StatusChangesView.tsx @@ -45,7 +45,7 @@ export default function StatusChangesView({ } return ( -
+
+ {loaderMsg} diff --git a/app/client/src/git/components/Statusbar/index.tsx b/app/client/src/git/components/Statusbar/index.tsx index a65332643780..8e6c256c69b0 100644 --- a/app/client/src/git/components/Statusbar/index.tsx +++ b/app/client/src/git/components/Statusbar/index.tsx @@ -106,7 +106,7 @@ export default function Statusbar({ ); return ( - + { - if (artifactDef) { - dispatch( - gitArtifactActions.openDisconnectModal({ artifactDef, artifactName }), - ); - } - }, [artifactDef, artifactName, dispatch]); + const openDisconnectModal = useCallback( + (targetArtifactDef: GitArtifactDef, targetArtifactName: string) => { + if (artifactDef) { + dispatch( + gitArtifactActions.openDisconnectModal({ + artifactDef, + targetArtifactDef, + targetArtifactName, + }), + ); + } + }, + [artifactDef, dispatch], + ); const closeDisconnectModal = useCallback(() => { if (artifactDef) { @@ -53,8 +60,8 @@ export default function useDisconnect() { isDisconnectLoading: disconnectState?.loading ?? false, disconnectError: disconnectState?.error ?? null, disconnect, - isDisconnectModalOpen: !!disconnectBaseArtifactId, - disconnectBaseArtifactId, + isDisconnectModalOpen: !!disconnectArtifactDef, + disconnectArtifactDef, disconnectArtifactName, openDisconnectModal, closeDisconnectModal, diff --git a/app/client/src/git/hooks/useMerge.ts b/app/client/src/git/hooks/useMerge.ts index 8fa79b16049f..1cdbadca28cf 100644 --- a/app/client/src/git/hooks/useMerge.ts +++ b/app/client/src/git/hooks/useMerge.ts @@ -3,6 +3,7 @@ import { gitArtifactActions } from "git/store/gitArtifactSlice"; import { selectMergeState, selectMergeStatusState, + selectMergeSuccess, } from "git/store/selectors/gitArtifactSelectors"; import { useCallback } from "react"; import { useDispatch } from "react-redux"; @@ -16,22 +17,32 @@ export default function useMerge() { // merge const mergeState = useArtifactSelector(selectMergeState); - const merge = useCallback(() => { - if (artifactDef) { - dispatch(gitArtifactActions.mergeInit({ artifactDef })); - } - }, [artifactDef, dispatch]); + const merge = useCallback( + (sourceBranch, destinationBranch) => { + if (artifactDef && artifactId) { + dispatch( + gitArtifactActions.mergeInit({ + artifactDef, + artifactId, + sourceBranch, + destinationBranch, + }), + ); + } + }, + [artifactDef, artifactId, dispatch], + ); // merge status const mergeStatusState = useArtifactSelector(selectMergeStatusState); const fetchMergeStatus = useCallback( (sourceBranch: string, destinationBranch: string) => { - if (artifactDef) { + if (artifactDef && artifactId) { dispatch( gitArtifactActions.fetchMergeStatusInit({ artifactDef, - artifactId: artifactId ?? "", + artifactId, sourceBranch, destinationBranch, }), @@ -47,6 +58,14 @@ export default function useMerge() { } }, [artifactDef, dispatch]); + const isMergeSuccess = useArtifactSelector(selectMergeSuccess); + + const resetMergeState = useCallback(() => { + if (artifactDef) { + dispatch(gitArtifactActions.resetMergeState({ artifactDef })); + } + }, [artifactDef, dispatch]); + return { isMergeLoading: mergeState?.loading ?? false, mergeError: mergeState?.error ?? null, @@ -56,5 +75,7 @@ export default function useMerge() { fetchMergeStatusError: mergeStatusState?.error ?? null, fetchMergeStatus, clearMergeStatus, + isMergeSuccess: isMergeSuccess ?? false, + resetMergeState, }; } diff --git a/app/client/src/git/hooks/useRepoLimitError.ts b/app/client/src/git/hooks/useRepoLimitError.ts new file mode 100644 index 000000000000..7f70a55d4582 --- /dev/null +++ b/app/client/src/git/hooks/useRepoLimitError.ts @@ -0,0 +1,18 @@ +import { gitGlobalActions } from "git/store/gitGlobalSlice"; +import { selectRepoLimitErrorModalOpen } from "git/store/selectors/gitGlobalSelectors"; +import { useDispatch, useSelector } from "react-redux"; + +export default function useRepoLimitError() { + const dispatch = useDispatch(); + + const repoLimitErrorModalOpen = useSelector(selectRepoLimitErrorModalOpen); + + const toggleRepoLimitErrorModal = (open: boolean) => { + dispatch(gitGlobalActions.toggleRepoLimitErrorModal({ open })); + }; + + return { + isRepoLimitErrorModalOpen: repoLimitErrorModalOpen ?? false, + toggleRepoLimitErrorModal, + }; +} diff --git a/app/client/src/git/index.ts b/app/client/src/git/index.ts index 892ca77d7f43..193acd088e4e 100644 --- a/app/client/src/git/index.ts +++ b/app/client/src/git/index.ts @@ -5,10 +5,12 @@ export { GitArtifactType, GitOpsTab } from "./constants/enums"; export { default as GitContextProvider } from "./components/GitContextProvider"; export { default as GitModals } from "./ee/components/GitModals"; export { default as GitImportModal } from "./components/ImportModal"; +export { default as GitRepoLimitErrorModal } from "./components/RepoLimitErrorModal"; export { default as GitQuickActions } from "./components/QuickActions"; export { default as GitProtectedBranchCallout } from "./components/ProtectedBranchCallout"; export { default as GitGlobalProfile } from "./components/GlobalProfile"; export { default as GitDeployMenuItems } from "./components/DeployMenuItems"; +export { default as GitHotKeys } from "./components/HotKeys"; // hooks export { default as useGitCurrentBranch } from "./hooks/useCurrentBranch"; @@ -28,6 +30,8 @@ export const gitConnectSuccess = gitArtifactActions.connectSuccess; export { selectCurrentBranch as selectGitCurrentBranch, selectProtectedMode as selectGitProtectedMode, + selectOpsModalOpen as selectGitOpsModalOpen, + selectConnectModalOpen as selectGitConnectModalOpen, } from "./store/selectors/gitArtifactSelectors"; // types diff --git a/app/client/src/git/requests/discardRequest.ts b/app/client/src/git/requests/discardRequest.ts index 6dffe7513caf..18f865b8f232 100644 --- a/app/client/src/git/requests/discardRequest.ts +++ b/app/client/src/git/requests/discardRequest.ts @@ -1,9 +1,10 @@ import Api from "api/Api"; import { GIT_BASE_URL } from "./constants"; import type { AxiosPromise } from "axios"; +import type { DiscardResponse } from "./discardRequest.types"; export default async function discardRequest( branchedApplicationId: string, -): AxiosPromise { +): AxiosPromise { return Api.put(`${GIT_BASE_URL}/discard/app/${branchedApplicationId}`); } diff --git a/app/client/src/git/requests/discardRequest.types.ts b/app/client/src/git/requests/discardRequest.types.ts new file mode 100644 index 000000000000..22b7074b73a7 --- /dev/null +++ b/app/client/src/git/requests/discardRequest.types.ts @@ -0,0 +1,4 @@ +import type { ApiResponse } from "api/types"; +import type { GitArtifact } from "git/store/types"; + +export type DiscardResponse = ApiResponse; diff --git a/app/client/src/git/requests/gitImportRequest.types.ts b/app/client/src/git/requests/gitImportRequest.types.ts index 4eb29b11a88b..034dc7aed402 100644 --- a/app/client/src/git/requests/gitImportRequest.types.ts +++ b/app/client/src/git/requests/gitImportRequest.types.ts @@ -14,7 +14,7 @@ export interface GitImportRequestParams { export interface GitImportResponseData { application: ApplicationResponsePayload; isPartialImport: boolean; - unconfiguredDatasourceList?: Datasource[]; + unConfiguredDatasourceList?: Datasource[]; } export type GitImportResponse = ApiResponse; diff --git a/app/client/src/git/requests/mergeRequest.types.ts b/app/client/src/git/requests/mergeRequest.types.ts index 7ec27500b1ed..ad0576703914 100644 --- a/app/client/src/git/requests/mergeRequest.types.ts +++ b/app/client/src/git/requests/mergeRequest.types.ts @@ -1,9 +1,13 @@ +import type { ApiResponse } from "api/types"; + export interface MergeRequestParams { sourceBranch: string; destinationBranch: string; } -export interface MergeResponse { +export interface MergeResponseData { isMergAble: boolean; status: string; // merge status } + +export type MergeResponse = ApiResponse; diff --git a/app/client/src/git/sagas/checkoutBranchSaga.ts b/app/client/src/git/sagas/checkoutBranchSaga.ts index 7fc454f36bc0..e92b579846b9 100644 --- a/app/client/src/git/sagas/checkoutBranchSaga.ts +++ b/app/client/src/git/sagas/checkoutBranchSaga.ts @@ -38,7 +38,6 @@ export default function* checkoutBranchSaga( if (response && isValidResponse) { if (artifactDef.artifactType === GitArtifactType.Application) { - yield put(gitArtifactActions.checkoutBranchSuccess({ artifactDef })); const trimmedBranch = branchName.replace(/^origin\//, ""); const destinationHref = addBranchParam(trimmedBranch); @@ -47,11 +46,10 @@ export default function* checkoutBranchSaga( ); yield put( - gitArtifactActions.toggleBranchPopup({ - artifactDef, - open: false, - }), + gitArtifactActions.toggleBranchPopup({ artifactDef, open: false }), ); + yield put(gitArtifactActions.checkoutBranchSuccess({ artifactDef })); + // Check if page exists in the branch. If not, instead of 404, take them to // the app home page const existingPage = response.data.pages.find( diff --git a/app/client/src/git/sagas/commitSaga.ts b/app/client/src/git/sagas/commitSaga.ts index 7ebcb70b9a71..1c1d93e3fd2b 100644 --- a/app/client/src/git/sagas/commitSaga.ts +++ b/app/client/src/git/sagas/commitSaga.ts @@ -1,4 +1,4 @@ -import { call, put } from "redux-saga/effects"; +import { call, put, select } from "redux-saga/effects"; import { captureException } from "@sentry/react"; import log from "loglevel"; import type { CommitInitPayload } from "../store/actions/commitActions"; @@ -13,6 +13,10 @@ import type { GitArtifactPayloadAction } from "../store/types"; // internal dependencies import { validateResponse } from "sagas/ErrorSagas"; +import { gitGlobalActions } from "git/store/gitGlobalSlice"; +import type { ApplicationPayload } from "entities/Application"; +import { getCurrentApplication } from "ee/selectors/applicationSelectors"; +import { ReduxActionTypes } from "ee/constants/ReduxActionConstants"; export default function* commitSaga( action: GitArtifactPayloadAction, @@ -42,7 +46,17 @@ export default function* commitSaga( ); if (artifactDef.artifactType === GitArtifactType.Application) { - // ! case for updating lastDeployedAt in application manually? + const currentApplication: ApplicationPayload = yield select( + getCurrentApplication, + ); + + if (currentApplication) { + currentApplication.lastDeployedAt = new Date().toISOString(); + yield put({ + type: ReduxActionTypes.FETCH_APPLICATION_SUCCESS, + payload: currentApplication, + }); + } } } } catch (e) { @@ -51,8 +65,7 @@ export default function* commitSaga( if (error.code === GitErrorCodes.REPO_LIMIT_REACHED) { yield put( - gitArtifactActions.toggleRepoLimitErrorModal({ - artifactDef, + gitGlobalActions.toggleRepoLimitErrorModal({ open: true, }), ); diff --git a/app/client/src/git/sagas/connectSaga.ts b/app/client/src/git/sagas/connectSaga.ts index b6de0cdea53e..0657aec6e5e0 100644 --- a/app/client/src/git/sagas/connectSaga.ts +++ b/app/client/src/git/sagas/connectSaga.ts @@ -18,6 +18,10 @@ import { addBranchParam } from "constants/routes"; import log from "loglevel"; import { captureException } from "@sentry/react"; import { getCurrentPageId } from "selectors/editorSelectors"; +import { gitGlobalActions } from "git/store/gitGlobalSlice"; +import { getCurrentApplication } from "ee/selectors/applicationSelectors"; +import type { ApplicationPayload } from "entities/Application"; +import { ReduxActionTypes } from "ee/constants/ReduxActionConstants"; export default function* connectSaga( action: GitArtifactPayloadAction, @@ -58,7 +62,17 @@ export default function* connectSaga( history.replace(newUrl); } - // ! case for updating lastDeployedAt in application manually? + const currentApplication: ApplicationPayload = yield select( + getCurrentApplication, + ); + + if (currentApplication) { + currentApplication.lastDeployedAt = new Date().toISOString(); + yield put({ + type: ReduxActionTypes.FETCH_APPLICATION_SUCCESS, + payload: currentApplication, + }); + } } yield put( @@ -83,8 +97,13 @@ export default function* connectSaga( if (GitErrorCodes.REPO_LIMIT_REACHED === error.code) { yield put( - gitArtifactActions.toggleRepoLimitErrorModal({ + gitArtifactActions.toggleConnectModal({ artifactDef, + open: false, + }), + ); + yield put( + gitGlobalActions.toggleRepoLimitErrorModal({ open: true, }), ); diff --git a/app/client/src/git/sagas/createBranchSaga.ts b/app/client/src/git/sagas/createBranchSaga.ts index d8aa65418977..af5319087507 100644 --- a/app/client/src/git/sagas/createBranchSaga.ts +++ b/app/client/src/git/sagas/createBranchSaga.ts @@ -17,7 +17,6 @@ export default function* createBranchSaga( action: GitArtifactPayloadAction, ) { const { artifactDef, artifactId } = action.payload; - const basePayload = { artifactDef }; let response: CreateBranchResponse | undefined; try { @@ -29,26 +28,25 @@ export default function* createBranchSaga( const isValidResponse: boolean = yield validateResponse(response); if (isValidResponse) { - yield put(gitArtifactActions.createBranchSuccess(basePayload)); + // yield put( + // gitArtifactActions.fetchBranchesInit({ + // artifactDef, + // artifactId, + // pruneBranches: true, + // }), + // ); yield put( - gitArtifactActions.toggleBranchPopup({ - artifactDef, - open: false, - }), - ); - yield put( - gitArtifactActions.fetchBranchesInit({ + gitArtifactActions.checkoutBranchInit({ artifactDef, artifactId, - pruneBranches: true, + branchName: action.payload.branchName, }), ); - + yield put(gitArtifactActions.createBranchSuccess({ artifactDef })); yield put( - gitArtifactActions.checkoutBranchInit({ + gitArtifactActions.toggleBranchPopup({ artifactDef, - artifactId, - branchName: action.payload.branchName, + open: false, }), ); } diff --git a/app/client/src/git/sagas/deleteBranchSaga.ts b/app/client/src/git/sagas/deleteBranchSaga.ts index ecf560889f1c..0f5126d4d2e5 100644 --- a/app/client/src/git/sagas/deleteBranchSaga.ts +++ b/app/client/src/git/sagas/deleteBranchSaga.ts @@ -12,6 +12,8 @@ import { call, put } from "redux-saga/effects"; import { validateResponse } from "sagas/ErrorSagas"; import log from "loglevel"; import { captureException } from "@sentry/react"; +import { toast } from "@appsmith/ads"; +import { createMessage, DELETE_BRANCH_SUCCESS } from "ee/constants/messages"; export default function* deleteBranchSaga( action: GitArtifactPayloadAction, @@ -32,6 +34,12 @@ export default function* deleteBranchSaga( const isValidResponse: boolean = yield validateResponse(response); if (isValidResponse) { + toast.show( + createMessage(DELETE_BRANCH_SUCCESS, action.payload.branchName), + { + kind: "success", + }, + ); yield put(gitArtifactActions.deleteBranchSuccess({ artifactDef })); yield put( gitArtifactActions.fetchBranchesInit({ diff --git a/app/client/src/git/sagas/discardSaga.ts b/app/client/src/git/sagas/discardSaga.ts new file mode 100644 index 000000000000..7e3cdd4a37e4 --- /dev/null +++ b/app/client/src/git/sagas/discardSaga.ts @@ -0,0 +1,45 @@ +import { toast } from "@appsmith/ads"; +import { captureException } from "@sentry/react"; +import { builderURL } from "ee/RouteBuilder"; +import { createMessage, DISCARD_SUCCESS } from "ee/constants/messages"; +import discardRequest from "git/requests/discardRequest"; +import type { DiscardResponse } from "git/requests/discardRequest.types"; +import { gitArtifactActions } from "git/store/gitArtifactSlice"; +import type { GitArtifactPayloadAction } from "git/store/types"; +import log from "loglevel"; +import { call, delay, put } from "redux-saga/effects"; +import { validateResponse } from "sagas/ErrorSagas"; + +export default function* discardSaga(action: GitArtifactPayloadAction) { + const { artifactDef } = action.payload; + + let response: DiscardResponse | undefined; + + try { + response = yield call(discardRequest, artifactDef.baseArtifactId); + const isValidResponse: boolean = yield validateResponse(response); + + if (response && isValidResponse) { + yield put(gitArtifactActions.discardSuccess({ artifactDef })); + toast.show(createMessage(DISCARD_SUCCESS), { + kind: "success", + }); + // adding delay to show toast animation before reloading + yield delay(500); + const basePageId: string = + response.data?.pages?.find((page) => page.isDefault)?.baseId || ""; + const branch = response.data?.gitApplicationMetadata?.branchName; + + window.open(builderURL({ basePageId, branch }), "_self"); + } + } catch (e) { + if (response?.responseMeta?.error) { + const { error } = response.responseMeta; + + yield put(gitArtifactActions.discardError({ artifactDef, error })); + } else { + log.error(e); + captureException(e); + } + } +} diff --git a/app/client/src/git/sagas/disconnectSaga.ts b/app/client/src/git/sagas/disconnectSaga.ts index ef6315c25cd5..ef6788b9ca11 100644 --- a/app/client/src/git/sagas/disconnectSaga.ts +++ b/app/client/src/git/sagas/disconnectSaga.ts @@ -5,52 +5,57 @@ import { GIT_BRANCH_QUERY_KEY } from "git/constants/misc"; import disconnectRequest from "git/requests/disconnectRequest"; import type { DisconnectResponse } from "git/requests/disconnectRequest.types"; import { gitArtifactActions } from "git/store/gitArtifactSlice"; -import type { GitArtifactPayloadAction } from "git/store/types"; +import { selectDisconnectArtifactDef } from "git/store/selectors/gitArtifactSelectors"; +import type { GitArtifactDef, GitArtifactPayloadAction } from "git/store/types"; import log from "loglevel"; -import { call, put } from "redux-saga/effects"; +import { call, put, select } from "redux-saga/effects"; import { validateResponse } from "sagas/ErrorSagas"; import history from "utils/history"; export default function* disconnectSaga(action: GitArtifactPayloadAction) { const { artifactDef } = action.payload; + const disconnectArtifactDef: GitArtifactDef = yield select( + selectDisconnectArtifactDef, + artifactDef, + ); let response: DisconnectResponse | undefined; try { - response = yield call(disconnectRequest, artifactDef.baseArtifactId); + response = yield call( + disconnectRequest, + disconnectArtifactDef.baseArtifactId, + ); const isValidResponse: boolean = yield validateResponse(response); if (response && isValidResponse) { yield put(gitArtifactActions.disconnectSuccess({ artifactDef })); - const url = new URL(window.location.href); - url.searchParams.delete(GIT_BRANCH_QUERY_KEY); - history.replace(url.toString().slice(url.origin.length)); - yield put(gitArtifactActions.unmount({ artifactDef })); - yield put( - gitArtifactActions.initGitForEditor({ - artifactDef, - artifact: response.data, - }), - ); - yield put(gitArtifactActions.closeDisconnectModal({ artifactDef })); - yield put( - gitArtifactActions.toggleOpsModal({ - artifactDef, - open: false, - tab: GitOpsTab.Deploy, - }), - ); - yield put(fetchAllApplicationsOfWorkspace()); + if (artifactDef.baseArtifactId === disconnectArtifactDef.baseArtifactId) { + const url = new URL(window.location.href); - // ! case: why? - // if (applicationId !== application?.id) { - // yield put( - // setIsGitSyncModalOpen({ - // isOpen: true, - // tab: GitSyncModalTab.GIT_CONNECTION, - // }), - // ); - // } + url.searchParams.delete(GIT_BRANCH_QUERY_KEY); + history.replace(url.toString().slice(url.origin.length)); + yield put(gitArtifactActions.unmount({ artifactDef })); + yield put( + gitArtifactActions.initGitForEditor({ + artifactDef, + artifact: response.data, + }), + ); + yield put(gitArtifactActions.closeDisconnectModal({ artifactDef })); + yield put( + gitArtifactActions.toggleOpsModal({ + artifactDef, + open: false, + tab: GitOpsTab.Deploy, + }), + ); + yield put(fetchAllApplicationsOfWorkspace()); + } else { + yield put( + gitArtifactActions.toggleConnectModal({ artifactDef, open: true }), + ); + } } } catch (e) { if (response && response.responseMeta.error) { diff --git a/app/client/src/git/sagas/generateSSHKeySaga.ts b/app/client/src/git/sagas/generateSSHKeySaga.ts index afbccf24b2e6..2749cada0dd6 100644 --- a/app/client/src/git/sagas/generateSSHKeySaga.ts +++ b/app/client/src/git/sagas/generateSSHKeySaga.ts @@ -7,6 +7,7 @@ import type { } from "git/requests/generateSSHKeyRequest.types"; import type { GenerateSSHKeyInitPayload } from "git/store/actions/generateSSHKeyActions"; import { gitArtifactActions } from "git/store/gitArtifactSlice"; +import { gitGlobalActions } from "git/store/gitGlobalSlice"; import type { GitArtifactPayloadAction } from "git/store/types"; import log from "loglevel"; import { call, put } from "redux-saga/effects"; @@ -44,8 +45,7 @@ export function* generateSSHKeySaga( if (GitErrorCodes.REPO_LIMIT_REACHED === error.code) { yield put( - gitArtifactActions.toggleRepoLimitErrorModal({ - artifactDef, + gitGlobalActions.toggleRepoLimitErrorModal({ open: true, }), ); diff --git a/app/client/src/git/sagas/gitImportSaga.ts b/app/client/src/git/sagas/gitImportSaga.ts index ecf3d718ae08..1991032176fb 100644 --- a/app/client/src/git/sagas/gitImportSaga.ts +++ b/app/client/src/git/sagas/gitImportSaga.ts @@ -15,6 +15,7 @@ import { getWorkspaceIdForImport } from "ee/selectors/applicationSelectors"; import { showReconnectDatasourceModal } from "ee/actions/applicationActions"; import type { Workspace } from "ee/constants/workspaceConstants"; import { getFetchedWorkspaces } from "ee/selectors/workspaceSelectors"; +import { GitErrorCodes } from "git/constants/enums"; export default function* gitImportSaga( action: PayloadAction, @@ -35,7 +36,7 @@ export default function* gitImportSaga( ); if (currentWorkspace.length > 0) { - const { application, isPartialImport, unconfiguredDatasourceList } = + const { application, isPartialImport, unConfiguredDatasourceList } = response.data; yield put(gitGlobalActions.gitImportSuccess()); @@ -46,7 +47,7 @@ export default function* gitImportSaga( yield put( showReconnectDatasourceModal({ application: application, - unConfiguredDatasourceList: unconfiguredDatasourceList ?? [], + unConfiguredDatasourceList: unConfiguredDatasourceList ?? [], workspaceId, }), ); @@ -61,8 +62,12 @@ export default function* gitImportSaga( basePageId = defaultPage ? defaultPage.baseId : ""; } + const branch = + response.data?.application?.gitApplicationMetadata?.branchName; + const pageURL = builderURL({ basePageId, + branch, }); history.push(pageURL); @@ -73,17 +78,23 @@ export default function* gitImportSaga( } } } catch (e) { - // const isRepoLimitReachedError: boolean = yield call( - // handleRepoLimitReachedError, - // response, - // ); + if (response?.responseMeta?.error) { + const { error } = response.responseMeta; - // if (isRepoLimitReachedError) return; + if (GitErrorCodes.REPO_LIMIT_REACHED === error.code) { + yield put( + gitGlobalActions.toggleImportModal({ + open: false, + }), + ); + yield put( + gitGlobalActions.toggleRepoLimitErrorModal({ + open: true, + }), + ); + } - if (response?.responseMeta?.error) { - yield put( - gitGlobalActions.gitImportError({ error: response.responseMeta.error }), - ); + yield put(gitGlobalActions.gitImportError({ error })); } else { log.error(e); captureException(e); diff --git a/app/client/src/git/sagas/index.ts b/app/client/src/git/sagas/index.ts index 61c0a0747330..98532833a03c 100644 --- a/app/client/src/git/sagas/index.ts +++ b/app/client/src/git/sagas/index.ts @@ -39,6 +39,8 @@ import { import { gitGlobalActions } from "git/store/gitGlobalSlice"; import { fetchGlobalSSHKeySaga } from "./fetchGlobalSSHKeySaga"; import gitImportSaga from "./gitImportSaga"; +import mergeSaga from "./mergeSaga"; +import discardSaga from "./discardSaga"; const blockingActionSagas: Record< string, @@ -60,6 +62,8 @@ const blockingActionSagas: Record< [gitArtifactActions.fetchStatusInit.type]: fetchStatusSaga, [gitArtifactActions.pullInit.type]: pullSaga, [gitArtifactActions.fetchMergeStatusInit.type]: fetchMergeStatusSaga, + [gitArtifactActions.mergeInit.type]: mergeSaga, + [gitArtifactActions.discardInit.type]: discardSaga, // branches [gitArtifactActions.fetchBranchesInit.type]: fetchBranchesSaga, diff --git a/app/client/src/git/sagas/initGitSaga.ts b/app/client/src/git/sagas/initGitSaga.ts index b880b1854c41..cf1a823f8ce8 100644 --- a/app/client/src/git/sagas/initGitSaga.ts +++ b/app/client/src/git/sagas/initGitSaga.ts @@ -1,8 +1,10 @@ +import { addBranchParam } from "constants/routes"; import { GitArtifactType } from "git/constants/enums"; import type { InitGitForEditorPayload } from "git/store/actions/initGitActions"; import { gitArtifactActions } from "git/store/gitArtifactSlice"; import type { GitArtifactPayloadAction } from "git/store/types"; import { put, take } from "redux-saga/effects"; +import history from "utils/history"; export default function* initGitForEditorSaga( action: GitArtifactPayloadAction, @@ -14,6 +16,11 @@ export default function* initGitForEditorSaga( if (artifactId && artifactDef.artifactType === GitArtifactType.Application) { if (!!artifact?.gitApplicationMetadata?.remoteUrl) { + const branch: string = artifact?.gitApplicationMetadata?.branchName; + + const urlWithBranch = addBranchParam(branch); + + history.replace(urlWithBranch); yield put(gitArtifactActions.fetchMetadataInit({ artifactDef })); yield take(gitArtifactActions.fetchMetadataSuccess.type); yield put( diff --git a/app/client/src/git/sagas/mergeSaga.ts b/app/client/src/git/sagas/mergeSaga.ts new file mode 100644 index 000000000000..858ad62c4c3a --- /dev/null +++ b/app/client/src/git/sagas/mergeSaga.ts @@ -0,0 +1,40 @@ +import { captureException } from "@sentry/react"; +import mergeRequest from "git/requests/mergeRequest"; +import type { MergeResponse } from "git/requests/mergeRequest.types"; +import type { MergeInitPayload } from "git/store/actions/mergeActions"; +import { gitArtifactActions } from "git/store/gitArtifactSlice"; +import type { GitArtifactPayloadAction } from "git/store/types"; +import log from "loglevel"; +import { call, put } from "redux-saga/effects"; +import { validateResponse } from "sagas/ErrorSagas"; + +export default function* mergeSaga( + action: GitArtifactPayloadAction, +) { + const { artifactDef, artifactId } = action.payload; + let response: MergeResponse | undefined; + + try { + const params = { + sourceBranch: action.payload.sourceBranch, + destinationBranch: action.payload.destinationBranch, + }; + + response = yield call(mergeRequest, artifactId, params); + + const isValidResponse: boolean = yield validateResponse(response); + + if (isValidResponse) { + yield put(gitArtifactActions.mergeSuccess({ artifactDef })); + } + } catch (e) { + if (response?.responseMeta.error) { + const { error } = response.responseMeta; + + yield put(gitArtifactActions.mergeError({ artifactDef, error })); + } else { + log.error(e); + captureException(e); + } + } +} diff --git a/app/client/src/git/store/actions/mergeActions.ts b/app/client/src/git/store/actions/mergeActions.ts index 0d4e67eea8fe..035651c1bd84 100644 --- a/app/client/src/git/store/actions/mergeActions.ts +++ b/app/client/src/git/store/actions/mergeActions.ts @@ -1,21 +1,29 @@ +import type { MergeRequestParams } from "git/requests/mergeRequest.types"; import { createArtifactAction } from "../helpers/createArtifactAction"; -import type { GitArtifactErrorPayloadAction } from "../types"; +import type { GitAsyncErrorPayload } from "../types"; -export const mergeInitAction = createArtifactAction((state) => { - state.apiResponses.merge.loading = true; - state.apiResponses.merge.error = null; +export interface MergeInitPayload extends MergeRequestParams { + artifactId: string; +} - return state; -}); +export const mergeInitAction = createArtifactAction( + (state) => { + state.apiResponses.merge.loading = true; + state.apiResponses.merge.error = null; + + return state; + }, +); export const mergeSuccessAction = createArtifactAction((state) => { state.apiResponses.merge.loading = false; + state.ui.mergeSuccess = true; return state; }); -export const mergeErrorAction = createArtifactAction( - (state, action: GitArtifactErrorPayloadAction) => { +export const mergeErrorAction = createArtifactAction( + (state, action) => { const { error } = action.payload; state.apiResponses.merge.loading = false; @@ -24,3 +32,11 @@ export const mergeErrorAction = createArtifactAction( return state; }, ); + +export const resetMergeStateAction = createArtifactAction((state) => { + state.apiResponses.merge.loading = false; + state.apiResponses.merge.error = null; + state.ui.mergeSuccess = false; + + return state; +}); diff --git a/app/client/src/git/store/actions/repoLimitErrorModalActions.ts b/app/client/src/git/store/actions/repoLimitErrorModalActions.ts index a2c96bac7721..51fd7c3212b9 100644 --- a/app/client/src/git/store/actions/repoLimitErrorModalActions.ts +++ b/app/client/src/git/store/actions/repoLimitErrorModalActions.ts @@ -1,14 +1,17 @@ -import { createArtifactAction } from "../helpers/createArtifactAction"; +import type { PayloadAction } from "@reduxjs/toolkit"; +import type { GitGlobalReduxState } from "../types"; -interface ToggleRepoLimitModalActionPayload { +interface ToggleRepoLimitModalPayload { open: boolean; } -export const toggleRepoLimitErrorModalAction = - createArtifactAction((state, action) => { - const { open } = action.payload; +export const toggleRepoLimitErrorModalAction = ( + state: GitGlobalReduxState, + action: PayloadAction, +) => { + const { open } = action.payload; - state.ui.repoLimitErrorModalOpen = open; + state.repoLimitErrorModalOpen = open; - return state; - }); + return state; +}; diff --git a/app/client/src/git/store/actions/uiActions.ts b/app/client/src/git/store/actions/uiActions.ts index 162382c3b876..486a391f8917 100644 --- a/app/client/src/git/store/actions/uiActions.ts +++ b/app/client/src/git/store/actions/uiActions.ts @@ -1,6 +1,6 @@ import type { GitOpsTab, GitSettingsTab } from "git/constants/enums"; import { createArtifactAction } from "../helpers/createArtifactAction"; -import type { GitGlobalReduxState } from "../types"; +import type { GitArtifactDef, GitGlobalReduxState } from "../types"; import type { PayloadAction } from "@reduxjs/toolkit"; // connect modal @@ -47,20 +47,24 @@ export const toggleImportModalAction = ( // disconnect modal export interface OpenDisconnectModalPayload { - artifactName: string; + targetArtifactDef: GitArtifactDef; + targetArtifactName: string; } export const openDisconnectModalAction = createArtifactAction((state, action) => { state.ui.disconnectBaseArtifactId = - action.payload.artifactDef.baseArtifactId; - state.ui.disconnectArtifactName = action.payload.artifactName; + action.payload.targetArtifactDef.baseArtifactId; + state.ui.disconnectArtifactType = + action.payload.targetArtifactDef.artifactType; + state.ui.disconnectArtifactName = action.payload.targetArtifactName; return state; }); export const closeDisconnectModalAction = createArtifactAction((state) => { state.ui.disconnectBaseArtifactId = null; + state.ui.disconnectArtifactType = null; state.ui.disconnectArtifactName = null; return state; @@ -130,19 +134,6 @@ export const toggleBranchPopupAction = createArtifactAction( ); // error modals -interface ToggleRepoLimitModalPayload { - open: boolean; -} - -export const toggleRepoLimitErrorModalAction = - createArtifactAction((state, action) => { - const { open } = action.payload; - - state.ui.repoLimitErrorModalOpen = open; - - return state; - }); - interface ToggleConflictErrorModalPayload { open: boolean; } diff --git a/app/client/src/git/store/gitArtifactSlice.ts b/app/client/src/git/store/gitArtifactSlice.ts index 15bbb4de65d2..bcb70f89aa60 100644 --- a/app/client/src/git/store/gitArtifactSlice.ts +++ b/app/client/src/git/store/gitArtifactSlice.ts @@ -57,7 +57,6 @@ import { toggleConnectModalAction, toggleOpsModalAction, toggleSettingsModalAction, - toggleRepoLimitErrorModalAction, toggleConflictErrorModalAction, openDisconnectModalAction, closeDisconnectModalAction, @@ -85,6 +84,7 @@ import { mergeErrorAction, mergeInitAction, mergeSuccessAction, + resetMergeStateAction, } from "./actions/mergeActions"; import { pollAutocommitProgressStopAction, @@ -167,7 +167,6 @@ export const gitArtifactSlice = createSlice({ toggleConnectSuccessModal: toggleConnectSuccessModalAction, openDisconnectModal: openDisconnectModalAction, closeDisconnectModal: closeDisconnectModalAction, - toggleRepoLimitErrorModal: toggleRepoLimitErrorModalAction, // git ops commitInit: commitInitAction, @@ -188,6 +187,7 @@ export const gitArtifactSlice = createSlice({ mergeInit: mergeInitAction, mergeSuccess: mergeSuccessAction, mergeError: mergeErrorAction, + resetMergeState: resetMergeStateAction, pullInit: pullInitAction, pullSuccess: pullSuccessAction, pullError: pullErrorAction, diff --git a/app/client/src/git/store/gitGlobalSlice.ts b/app/client/src/git/store/gitGlobalSlice.ts index 4a26f5d6132f..3d38b14aa492 100644 --- a/app/client/src/git/store/gitGlobalSlice.ts +++ b/app/client/src/git/store/gitGlobalSlice.ts @@ -22,6 +22,7 @@ import { fetchGlobalSSHKeySuccessAction, resetGlobalSSHKeyAction, } from "./actions/fetchGlobalSSHKeyActions"; +import { toggleRepoLimitErrorModalAction } from "./actions/repoLimitErrorModalActions"; export const gitGlobalSlice = createSlice({ name: "git/config", @@ -41,6 +42,7 @@ export const gitGlobalSlice = createSlice({ gitImportSuccess: gitImportSuccessAction, gitImportError: gitImportErrorAction, toggleImportModal: toggleImportModalAction, + toggleRepoLimitErrorModal: toggleRepoLimitErrorModalAction, }, }); diff --git a/app/client/src/git/store/helpers/initialState.ts b/app/client/src/git/store/helpers/initialState.ts index 382833be2782..18b6e58ca826 100644 --- a/app/client/src/git/store/helpers/initialState.ts +++ b/app/client/src/git/store/helpers/initialState.ts @@ -14,17 +14,18 @@ const gitArtifactInitialUIState: GitArtifactUIReduxState = { connectModalOpen: false, connectSuccessModalOpen: false, disconnectBaseArtifactId: null, + disconnectArtifactType: null, disconnectArtifactName: null, branchPopupOpen: false, checkoutDestBranch: null, opsModalOpen: false, opsModalTab: GitOpsTab.Deploy, + mergeSuccess: false, settingsModalOpen: false, settingsModalTab: GitSettingsTab.General, autocommitDisableModalOpen: false, autocommitPolling: false, conflictErrorModalOpen: false, - repoLimitErrorModalOpen: false, // EE ...gitArtifactUIInitialStateExtended, }; @@ -154,4 +155,5 @@ export const gitGlobalInitialState: GitGlobalReduxState = { error: null, }, isImportModalOpen: false, + repoLimitErrorModalOpen: false, }; diff --git a/app/client/src/git/store/selectors/gitArtifactSelectors.ts b/app/client/src/git/store/selectors/gitArtifactSelectors.ts index 5bf8267df889..4f5346559367 100644 --- a/app/client/src/git/store/selectors/gitArtifactSelectors.ts +++ b/app/client/src/git/store/selectors/gitArtifactSelectors.ts @@ -51,10 +51,19 @@ export const selectDisconnectState = ( artifactDef: GitArtifactDef, ) => selectGitArtifact(state, artifactDef)?.apiResponses.disconnect; -export const selectDisconnectBaseArtifactId = ( +export const selectDisconnectArtifactDef = ( state: GitRootState, artifactDef: GitArtifactDef, -) => selectGitArtifact(state, artifactDef)?.ui.disconnectBaseArtifactId; +) => { + const baseArtifactId = selectGitArtifact(state, artifactDef)?.ui + .disconnectBaseArtifactId; + const artifactType = selectGitArtifact(state, artifactDef)?.ui + .disconnectArtifactType; + + if (!baseArtifactId || !artifactType) return null; + + return { baseArtifactId, artifactType }; +}; export const selectDisconnectArtifactName = ( state: GitRootState, @@ -82,6 +91,11 @@ export const selectMergeState = ( artifactDef: GitArtifactDef, ) => selectGitArtifact(state, artifactDef)?.apiResponses?.merge; +export const selectMergeSuccess = ( + state: GitRootState, + artifactDef: GitArtifactDef, +) => selectGitArtifact(state, artifactDef)?.ui.mergeSuccess; + export const selectMergeStatusState = ( state: GitRootState, artifactDef: GitArtifactDef, diff --git a/app/client/src/git/store/selectors/gitGlobalSelectors.ts b/app/client/src/git/store/selectors/gitGlobalSelectors.ts index 1d1fdb555d0c..57e5c5123036 100644 --- a/app/client/src/git/store/selectors/gitGlobalSelectors.ts +++ b/app/client/src/git/store/selectors/gitGlobalSelectors.ts @@ -19,3 +19,6 @@ export const selectGitImportState = (state: GitRootState) => export const selectFetchGlobalSSHKeyState = (state: GitRootState) => selectGitGlobal(state).globalSSHKey; + +export const selectRepoLimitErrorModalOpen = (state: GitRootState) => + selectGitGlobal(state).repoLimitErrorModalOpen; diff --git a/app/client/src/git/store/types.ts b/app/client/src/git/store/types.ts index 90a2e72998a5..c23f4d431af1 100644 --- a/app/client/src/git/store/types.ts +++ b/app/client/src/git/store/types.ts @@ -18,6 +18,7 @@ import type { GitArtifactUIReduxState as GitArtifactUIReduxStateExtended, } from "git/ee/store/types"; import type { FetchGlobalSSHKeyResponseData } from "git/requests/fetchGlobalSSHKeyRequest.types"; +import type { ApplicationPayload } from "entities/Application"; export interface GitApiError extends ApiResponseError { errorType?: string; @@ -65,19 +66,22 @@ export interface GitArtifactUIReduxState connectModalOpen: boolean; connectSuccessModalOpen: boolean; disconnectBaseArtifactId: string | null; + disconnectArtifactType: keyof typeof GitArtifactType | null; disconnectArtifactName: string | null; branchPopupOpen: boolean; checkoutDestBranch: string | null; opsModalOpen: boolean; opsModalTab: keyof typeof GitOpsTab; + mergeSuccess: boolean; settingsModalOpen: boolean; settingsModalTab: keyof typeof GitSettingsTab; autocommitDisableModalOpen: boolean; autocommitPolling: boolean; conflictErrorModalOpen: boolean; - repoLimitErrorModalOpen: boolean; } +export type GitArtifact = ApplicationPayload; + export interface GitArtifactDef { artifactType: keyof typeof GitArtifactType; baseArtifactId: string; @@ -94,6 +98,7 @@ export interface GitGlobalReduxState { globalSSHKey: GitAsyncState; // ui isImportModalOpen: boolean; + repoLimitErrorModalOpen: boolean; } export type GitArtifactRootReduxState = Record< diff --git a/app/client/src/pages/Editor/GlobalHotKeys/GlobalHotKeys.tsx b/app/client/src/pages/Editor/GlobalHotKeys/GlobalHotKeys.tsx index 1e01349df831..7fa7196a5336 100644 --- a/app/client/src/pages/Editor/GlobalHotKeys/GlobalHotKeys.tsx +++ b/app/client/src/pages/Editor/GlobalHotKeys/GlobalHotKeys.tsx @@ -1,5 +1,5 @@ -import React from "react"; -import { connect } from "react-redux"; +import React, { useCallback } from "react"; +import { connect, useDispatch, useSelector } from "react-redux"; import type { AppState } from "ee/reducers"; import { Hotkey, Hotkeys, HotkeysTarget } from "@blueprintjs/core"; import { @@ -36,8 +36,6 @@ import { SAVE_HOTKEY_TOASTER_MESSAGE, } from "ee/constants/messages"; import { previewModeSelector } from "selectors/editorSelectors"; -import { setIsGitSyncModalOpen } from "actions/gitSyncActions"; -import { GitSyncModalTab } from "entities/GitSync"; import { matchBuilderPath } from "constants/routes"; import { toggleInstaller } from "actions/JSLibraryActions"; import { SelectionRequestType } from "sagas/WidgetSelectUtils"; @@ -46,7 +44,38 @@ import { showDebuggerFlag } from "selectors/debuggerSelectors"; import { getIsFirstTimeUserOnboardingEnabled } from "selectors/onboardingSelectors"; import WalkthroughContext from "components/featureWalkthrough/walkthroughContext"; import { setPreviewModeInitAction } from "actions/editorActions"; -import { selectGitApplicationProtectedMode } from "selectors/gitModSelectors"; +import { setIsGitSyncModalOpen } from "actions/gitSyncActions"; +import { GitSyncModalTab } from "entities/GitSync"; +import { + selectGitApplicationProtectedMode, + selectGitModEnabled, +} from "selectors/gitModSelectors"; +import { GitHotKeys as GitHotKeysNew } from "git"; + +function GitHotKeys() { + const isGitModEnabled = useSelector(selectGitModEnabled); + const dispatch = useDispatch(); + + const showCommitModal = useCallback(() => { + dispatch( + setIsGitSyncModalOpen({ + isOpen: true, + tab: GitSyncModalTab.DEPLOY, + }), + ); + }, [dispatch]); + + return isGitModEnabled ? ( + + ) : ( + + ); +} interface Props { copySelectedWidget: () => void; @@ -72,7 +101,6 @@ interface Props { isProtectedMode: boolean; setPreviewModeInitAction: (shouldSet: boolean) => void; isSignpostingEnabled: boolean; - showCommitModal: () => void; getMousePosition: () => { x: number; y: number }; hideInstaller: () => void; toggleDebugger: () => void; @@ -355,14 +383,7 @@ class GlobalHotKeys extends React.Component { this.props.setPreviewModeInitAction(!this.props.isPreviewMode); }} /> - { - this.props.showCommitModal(); - }} - /> + ); } @@ -411,13 +432,6 @@ const mapDispatchToProps = (dispatch: any) => { executeAction: () => dispatch(runActionViaShortcut()), undo: () => dispatch(undoAction()), redo: () => dispatch(redoAction()), - showCommitModal: () => - dispatch( - setIsGitSyncModalOpen({ - isOpen: true, - tab: GitSyncModalTab.DEPLOY, - }), - ), hideInstaller: () => dispatch(toggleInstaller(false)), setPreviewModeInitAction: (shouldSet: boolean) => dispatch(setPreviewModeInitAction(shouldSet)), diff --git a/app/client/src/pages/Editor/gitSync/RepoLimitExceededErrorModal.tsx b/app/client/src/pages/Editor/gitSync/RepoLimitExceededErrorModal.tsx index 0547e34da2a9..0df64e983f48 100644 --- a/app/client/src/pages/Editor/gitSync/RepoLimitExceededErrorModal.tsx +++ b/app/client/src/pages/Editor/gitSync/RepoLimitExceededErrorModal.tsx @@ -153,7 +153,7 @@ function RepoLimitExceededErrorModal() { open={isOpen} > diff --git a/app/client/src/sagas/ActionExecution/PluginActionSaga.ts b/app/client/src/sagas/ActionExecution/PluginActionSaga.ts index af55b7ae0f1f..a6dc1fcd9efc 100644 --- a/app/client/src/sagas/ActionExecution/PluginActionSaga.ts +++ b/app/client/src/sagas/ActionExecution/PluginActionSaga.ts @@ -41,7 +41,6 @@ import { getJSCollectionFromAllEntities, getPlugin, } from "ee/selectors/entitiesSelector"; -import { getIsGitSyncModalOpen } from "selectors/gitSyncSelectors"; import { getAppMode, getCurrentApplication, @@ -168,6 +167,10 @@ import { } from "PluginActionEditor/store"; import { objectKeys } from "@appsmith/utils"; import type { Span } from "instrumentation/types"; +import { + selectGitConnectModalOpen, + selectGitOpsModalOpen, +} from "selectors/gitModSelectors"; enum ActionResponseDataTypes { BINARY = "BINARY", @@ -694,10 +697,13 @@ function* runActionShortcutSaga() { if (!baseMatch) return; // get gitSyncModal status - const isGitSyncModalOpen: boolean = yield select(getIsGitSyncModalOpen); + const isGitOpsModalOpen: boolean = yield select(selectGitOpsModalOpen); + const isGitConnectModalOpen: boolean = yield select( + selectGitConnectModalOpen, + ); // if git sync modal is open, prevent action from being executed via shortcut keys. - if (isGitSyncModalOpen) return; + if (isGitOpsModalOpen || isGitConnectModalOpen) return; const { path } = baseMatch; // TODO: Fix this the next time the file is edited diff --git a/app/client/src/sagas/GitSyncSagas.ts b/app/client/src/sagas/GitSyncSagas.ts index caf5ba71b258..8b4d9340aef6 100644 --- a/app/client/src/sagas/GitSyncSagas.ts +++ b/app/client/src/sagas/GitSyncSagas.ts @@ -402,10 +402,12 @@ function* switchBranch(action: ReduxAction) { (page) => page.baseId === entityInfo.params.basePageId, ); - yield put(setShowBranchPopupAction(false)); - yield put({ type: ReduxActionTypes.SWITCH_GIT_BRANCH_SUCCESS }); const defaultPage = response.data.pages.find((page) => page.isDefault); + if (existingPage) { + history.push(destinationHref); + } + if (!existingPage && defaultPage) { history.push( builderURL({ basePageId: defaultPage.baseId, branch: trimmedBranch }), @@ -414,9 +416,6 @@ function* switchBranch(action: ReduxAction) { return; } - // Page exists, so we will try to go to the destination - history.push(destinationHref); - let shouldGoToHomePage = false; // It is possible that the action does not exist in the incoming branch @@ -452,6 +451,9 @@ function* switchBranch(action: ReduxAction) { }), ); } + + yield put(setShowBranchPopupAction(false)); + yield put({ type: ReduxActionTypes.SWITCH_GIT_BRANCH_SUCCESS }); } catch (e) { // non api error yield put({ type: ReduxActionTypes.SWITCH_GIT_BRANCH_ERROR }); diff --git a/app/client/src/selectors/gitModSelectors.ts b/app/client/src/selectors/gitModSelectors.ts index 35fe32fbbff7..5576f5ffe624 100644 --- a/app/client/src/selectors/gitModSelectors.ts +++ b/app/client/src/selectors/gitModSelectors.ts @@ -2,10 +2,16 @@ import { selectFeatureFlags } from "ee/selectors/featureFlagsSelectors"; import { createSelector } from "reselect"; -import { getCurrentGitBranch, protectedModeSelector } from "./gitSyncSelectors"; +import { + getCurrentGitBranch, + getIsGitSyncModalOpen, + protectedModeSelector, +} from "./gitSyncSelectors"; import { selectGitCurrentBranch as selectGitCurrentBranchNew, selectGitProtectedMode as selectGitProtectedModeNew, + selectGitOpsModalOpen as selectGitOpsModalOpenNew, + selectGitConnectModalOpen as selectGitConnectModalOpenNew, } from "git"; import { getCurrentBaseApplicationId, @@ -48,3 +54,23 @@ export const selectCombinedPreviewMode = createSelector( selectGitApplicationProtectedMode, (isPreviewMode, isProtectedMode) => isPreviewMode || isProtectedMode, ); + +export const selectGitOpsModalOpen = createSelector( + selectGitModEnabled, + getIsGitSyncModalOpen, + (state) => + selectGitOpsModalOpenNew(state, selectGitApplicationArtifactDef(state)), + (isGitModEnabled, isOldModalOpen, isNewModalOpen) => { + return isGitModEnabled ? isNewModalOpen : isOldModalOpen; + }, +); + +export const selectGitConnectModalOpen = createSelector( + selectGitModEnabled, + getIsGitSyncModalOpen, + (state) => + selectGitConnectModalOpenNew(state, selectGitApplicationArtifactDef(state)), + (isGitModEnabled, isOldModalOpen, isNewModalOpen) => { + return isGitModEnabled ? isNewModalOpen : isOldModalOpen; + }, +); From a9a0d714c02baecf87fb4fcbfa6ac3d4e9cd5512 Mon Sep 17 00:00:00 2001 From: Pawan Kumar Date: Tue, 7 Jan 2025 17:34:15 +0530 Subject: [PATCH 33/40] chore: fix form widgets bugs (#38492) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit /ok-to-test tags="@tag.Anvil" Fixes #38200 Fixes #38201 Fixes #38409 Fixes #38410 ## Summary by CodeRabbit Based on the comprehensive summary, here are the updated release notes: - **New Features** - Enhanced calendar functionality with month and year dropdown selection. - Improved input and select component styling. - Added text wrapping and line clamping for field labels. - **Bug Fixes** - Refined input validation and error handling across multiple widgets. - Updated text property handling for various input widgets. - **Documentation** - Updated autocomplete configuration for input widgets. - **Chores** - Temporarily disabled several Cypress test suites for Anvil widgets. - Standardized text property naming across input-related components. - **Style** - Improved CSS styling for input groups, dropdowns, and calendar components. - Enhanced text rendering and whitespace handling. These release notes capture the key changes across the design system and widget components, focusing on user-facing improvements and internal refinements. > [!TIP] > 🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉 > Workflow run: > Commit: c41781c32b9fd186b718338556af9a53221eaca7 > Cypress dashboard. > Tags: `@tag.Anvil` > Spec: >
Tue, 07 Jan 2025 11:41:09 UTC --- .../Widgets/AnvilButtonWidgetSnapshot_spec.ts | 2 +- .../AnvilCheckboxGroupWidgetSnapshot_spec.ts | 2 +- .../AnvilCheckboxWidgetSnapshot_spec.ts | 2 +- .../AnvilHeadingWidgetSnapshot_spec.ts | 2 +- .../AnvilIconButtonWidgetSnapshot_spec.ts | 2 +- .../AnvilInlineButtonWidgetSnapshot_spec.ts | 2 +- .../AnvilParagraphWidgetSnapshot_spec.ts | 2 +- .../AnvilRadioGroupWidgetSnapshot_spec.ts | 2 +- .../Widgets/AnvilStatsWidgetSnapshot_spec.ts | 2 +- .../AnvilSwitchGroupWidgetSnapshot_spec.ts | 2 +- .../Widgets/AnvilSwitchWidgetSnapshot_spec.ts | 2 +- .../AnvilToolbarButtonWidgetSnapshot_spec.ts | 2 +- app/client/cypress/limited-tests.txt | 3 +- .../support/Pages/Anvil/AnvilSnapshot.ts | 4 +- .../Calendar/src/CalendarHeading.tsx | 23 +++++--- .../Calendar/src/CalendarMonthDropdown.tsx | 40 ++++++++++++++ .../Calendar/src/CalendarYearDropdown.tsx | 33 ++++++++++++ .../components/Calendar/src/styles.module.css | 9 ++++ .../src/components/Calendar/utils/calendar.ts | 52 +++++++++++++++++++ .../components/Datepicker/src/Datepicker.tsx | 2 +- .../components/FieldLabel/src/FieldLabel.tsx | 7 ++- .../src/components/Input/src/Input.tsx | 6 +-- .../components/Input/src/styles.module.css | 19 +++++-- .../components/Select/src/SelectTrigger.tsx | 8 ++- .../widgets/src/components/Text/src/Text.tsx | 1 + .../wds/WDSBaseInputWidget/widget/index.tsx | 2 +- .../config/autocompleteConfig.ts | 4 +- .../WDSCurrencyInputWidget/widget/index.tsx | 30 +++++------ .../config/autocompleteConfig.ts | 9 +++- .../WDSInputWidget/config/settersConfig.ts | 2 +- .../ui/wds/WDSInputWidget/widget/helper.ts | 12 ++--- .../ui/wds/WDSInputWidget/widget/index.tsx | 14 ++--- .../config/autocompleteConfig.ts | 2 +- .../wds/WDSPhoneInputWidget/widget/helpers.ts | 2 +- .../wds/WDSPhoneInputWidget/widget/index.tsx | 26 +++++----- 35 files changed, 249 insertions(+), 85 deletions(-) create mode 100644 app/client/packages/design-system/widgets/src/components/Calendar/src/CalendarMonthDropdown.tsx create mode 100644 app/client/packages/design-system/widgets/src/components/Calendar/src/CalendarYearDropdown.tsx create mode 100644 app/client/packages/design-system/widgets/src/components/Calendar/utils/calendar.ts 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 74e3c855ae41..a78e7ef5d47e 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 @@ -5,7 +5,7 @@ import { } from "../../../../../support/Objects/ObjectsCore"; // TODO: Enable when issue(github.com/appsmithorg/appsmith/issues/36419) is solved. -describe( +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 d2113759c835..66b66d583e7f 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 @@ -5,7 +5,7 @@ import { } from "../../../../../support/Objects/ObjectsCore"; // TODO: Enable when issue(github.com/appsmithorg/appsmith/issues/36419) is solved. -describe( +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 fe143dcab129..5ad568bf5a20 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 @@ -5,7 +5,7 @@ import { } from "../../../../../support/Objects/ObjectsCore"; // TODO: Enable when issue(github.com/appsmithorg/appsmith/issues/36419) is solved. -describe( +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/AnvilHeadingWidgetSnapshot_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilHeadingWidgetSnapshot_spec.ts index c58a6eff6cd3..82ae69d9a07b 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 @@ -5,7 +5,7 @@ import { } from "../../../../../support/Objects/ObjectsCore"; // TODO: Enable when issue(github.com/appsmithorg/appsmith/issues/36419) is solved. -describe( +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 9c0b7ec75524..5adb9bde9366 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 @@ -5,7 +5,7 @@ import { } from "../../../../../support/Objects/ObjectsCore"; // TODO: Enable when issue(github.com/appsmithorg/appsmith/issues/36419) is solved. -describe( +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 67015f2c3e28..9899b8ce2f79 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 @@ -5,7 +5,7 @@ import { } from "../../../../../support/Objects/ObjectsCore"; // TODO: Enable when issue(github.com/appsmithorg/appsmith/issues/36419) is solved. -describe( +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/AnvilParagraphWidgetSnapshot_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilParagraphWidgetSnapshot_spec.ts index 81cbbbac8790..eac9c2178efb 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 @@ -5,7 +5,7 @@ import { } from "../../../../../support/Objects/ObjectsCore"; // TODO: Enable when issue(github.com/appsmithorg/appsmith/issues/36419) is solved. -describe( +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/AnvilRadioGroupWidgetSnapshot_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilRadioGroupWidgetSnapshot_spec.ts index 1634c2ae7e80..7b90dbce28ab 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 @@ -5,7 +5,7 @@ import { } from "../../../../../support/Objects/ObjectsCore"; // TODO: Enable when issue(github.com/appsmithorg/appsmith/issues/36419) is solved. -describe( +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 0449dc62d6f5..51da8ac23959 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 @@ -5,7 +5,7 @@ import { } from "../../../../../support/Objects/ObjectsCore"; // TODO: Enable when issue(github.com/appsmithorg/appsmith/issues/36419) is solved. -describe( +describe.skip( `${ANVIL_EDITOR_TEST}: Anvil tests for Stats Widget`, { tags: ["@tag.Anvil", "@tag.Visual"] }, () => { 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 a36b4d2c0b12..2ffed43ba435 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 @@ -5,7 +5,7 @@ import { } from "../../../../../support/Objects/ObjectsCore"; // TODO: Enable when issue(github.com/appsmithorg/appsmith/issues/36419) is solved. -describe( +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 a6eb434fe48a..aec145739a22 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 @@ -5,7 +5,7 @@ import { } from "../../../../../support/Objects/ObjectsCore"; // TODO: Enable when issue(github.com/appsmithorg/appsmith/issues/36419) is solved. -describe( +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/AnvilToolbarButtonWidgetSnapshot_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilToolbarButtonWidgetSnapshot_spec.ts index 1ed021c81277..ef99aeab2938 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 @@ -5,7 +5,7 @@ import { } from "../../../../../support/Objects/ObjectsCore"; // TODO: Enable when issue(github.com/appsmithorg/appsmith/issues/36419) is solved. -describe( +describe.skip( `${ANVIL_EDITOR_TEST}: Anvil tests for Toolbar Button Widget`, { tags: ["@tag.Anvil", "@tag.Visual"] }, () => { diff --git a/app/client/cypress/limited-tests.txt b/app/client/cypress/limited-tests.txt index 3a997515912b..00e32a4629d0 100644 --- a/app/client/cypress/limited-tests.txt +++ b/app/client/cypress/limited-tests.txt @@ -1,6 +1,7 @@ # To run only limited tests - give the spec names in below format: -cypress/e2e/Regression/ClientSide/VisualTests/JSEditorIndent_spec.js +#cypress/e2e/Regression/ClientSide/VisualTests/JSEditorIndent_spec.js # For running all specs - uncomment below: #cypress/e2e/**/**/* +cypress/e2e/Regression/ClientSide/Anvil/Widgets/* #ci-test-limit uses this file to run minimum of specs. Do not run entire suite with this command. diff --git a/app/client/cypress/support/Pages/Anvil/AnvilSnapshot.ts b/app/client/cypress/support/Pages/Anvil/AnvilSnapshot.ts index 356e16994c36..a7da8faebe2a 100644 --- a/app/client/cypress/support/Pages/Anvil/AnvilSnapshot.ts +++ b/app/client/cypress/support/Pages/Anvil/AnvilSnapshot.ts @@ -173,8 +173,8 @@ export class AnvilSnapshot { public triggerInputInvalidState = () => { this.enterPreviewMode(); - cy.get("input[aria-required=true]").first().type("123"); - cy.get("input[aria-required=true]").first().clear(); + cy.get("input[required]").first().type("123"); + cy.get("input[required]").first().clear(); this.exitPreviewMode(); this.agHelper.GetNClick(this.locators.propertyPaneSidebar); }; diff --git a/app/client/packages/design-system/widgets/src/components/Calendar/src/CalendarHeading.tsx b/app/client/packages/design-system/widgets/src/components/Calendar/src/CalendarHeading.tsx index ed931b848db9..160265802dff 100644 --- a/app/client/packages/design-system/widgets/src/components/Calendar/src/CalendarHeading.tsx +++ b/app/client/packages/design-system/widgets/src/components/Calendar/src/CalendarHeading.tsx @@ -1,18 +1,27 @@ -import { Text, type TextProps } from "@appsmith/wds"; -import React, { forwardRef, type ForwardedRef } from "react"; -import { HeadingContext, useContextProps } from "react-aria-components"; +import { type TextProps } from "@appsmith/wds"; +import { + CalendarStateContext, + HeadingContext, + useContextProps, +} from "react-aria-components"; +import React, { forwardRef, useContext, type ForwardedRef } from "react"; + +import styles from "./styles.module.css"; +import { CalendarMonthDropdown } from "./CalendarMonthDropdown"; +import { CalendarYearDropdown } from "./CalendarYearDropdown"; function CalendarHeading( props: TextProps, ref: ForwardedRef, ) { [props, ref] = useContextProps(props, ref, HeadingContext); - const { children, ...domProps } = props; + const state = useContext(CalendarStateContext); return ( - - {children} - +
+ + +
); } diff --git a/app/client/packages/design-system/widgets/src/components/Calendar/src/CalendarMonthDropdown.tsx b/app/client/packages/design-system/widgets/src/components/Calendar/src/CalendarMonthDropdown.tsx new file mode 100644 index 000000000000..3f37d5647f8d --- /dev/null +++ b/app/client/packages/design-system/widgets/src/components/Calendar/src/CalendarMonthDropdown.tsx @@ -0,0 +1,40 @@ +import React from "react"; +import type { Key } from "react"; +import { useDateFormatter } from "@react-aria/i18n"; +import { ListBoxItem, Select } from "@appsmith/wds"; +import type { CalendarState } from "@react-stately/calendar"; + +import styles from "./styles.module.css"; +import { useValidMonths } from "../utils/calendar"; + +export function CalendarMonthDropdown({ state }: { state: CalendarState }) { + const formatter = useDateFormatter({ + month: "long", + timeZone: state.timeZone, + }); + + const months = useValidMonths(state, formatter); + + const onChange = (value: Key | null) => { + const date = state.focusedDate.set({ month: Number(value) }); + + state.setFocusedDate(date); + }; + + return ( + + ); +} diff --git a/app/client/packages/design-system/widgets/src/components/Calendar/src/CalendarYearDropdown.tsx b/app/client/packages/design-system/widgets/src/components/Calendar/src/CalendarYearDropdown.tsx new file mode 100644 index 000000000000..289f974099d6 --- /dev/null +++ b/app/client/packages/design-system/widgets/src/components/Calendar/src/CalendarYearDropdown.tsx @@ -0,0 +1,33 @@ +import React from "react"; +import type { Key } from "react"; +import { ListBoxItem, Select } from "@appsmith/wds"; +import type { CalendarState } from "@react-stately/calendar"; + +import { useYearOptions } from "../utils/calendar"; + +export function CalendarYearDropdown({ state }: { state: CalendarState }) { + const years = useYearOptions(state); + + const onChange = (value: Key | null) => { + const index = Number(value); + const date = years[index].value; + + state.setFocusedDate(date); + }; + + return ( + + ); +} diff --git a/app/client/packages/design-system/widgets/src/components/Calendar/src/styles.module.css b/app/client/packages/design-system/widgets/src/components/Calendar/src/styles.module.css index 216afe61510f..950964ce3e46 100644 --- a/app/client/packages/design-system/widgets/src/components/Calendar/src/styles.module.css +++ b/app/client/packages/design-system/widgets/src/components/Calendar/src/styles.module.css @@ -68,3 +68,12 @@ 0 0 0 calc(var(--box-shadow-offset) + var(--border-width-2)) var(--color-bd-focus); } + +.monthYearDropdown { + display: flex; + gap: var(--inner-spacing-1); +} + +.monthDropdown button { + width: 14ch; +} diff --git a/app/client/packages/design-system/widgets/src/components/Calendar/utils/calendar.ts b/app/client/packages/design-system/widgets/src/components/Calendar/utils/calendar.ts new file mode 100644 index 000000000000..cf1b356de043 --- /dev/null +++ b/app/client/packages/design-system/widgets/src/components/Calendar/utils/calendar.ts @@ -0,0 +1,52 @@ +import { useDateFormatter } from "@react-aria/i18n"; +import type { CalendarState } from "@react-stately/calendar"; + +export function useYearOptions(state: CalendarState) { + const formatter = useDateFormatter({ + year: "numeric", + timeZone: state.timeZone, + }); + + const years: { value: CalendarState["focusedDate"]; formatted: string }[] = + []; + + const YEAR_RANGE = 20; + + for (let i = -YEAR_RANGE; i <= YEAR_RANGE; i++) { + const date = state.focusedDate.add({ years: i }); + + years.push({ + value: date, + formatted: formatter.format(date.toDate(state.timeZone)), + }); + } + + return years; +} + +export function useValidMonths( + state: CalendarState, + formatter: Intl.DateTimeFormat, +) { + const months = []; + const numMonths = state.focusedDate.calendar.getMonthsInYear( + state.focusedDate, + ); + + for (let i = 1; i <= numMonths; i++) { + const date = state.focusedDate.set({ month: i }); + + // Skip months outside valid range + if (state.minValue && date.compare(state.minValue) < 0) { + continue; + } + + if (state.maxValue && date.compare(state.maxValue) > 0) { + continue; + } + + months.push(formatter.format(date.toDate(state.timeZone))); + } + + return months; +} diff --git a/app/client/packages/design-system/widgets/src/components/Datepicker/src/Datepicker.tsx b/app/client/packages/design-system/widgets/src/components/Datepicker/src/Datepicker.tsx index f62f5dd69fb7..f57803332474 100644 --- a/app/client/packages/design-system/widgets/src/components/Datepicker/src/Datepicker.tsx +++ b/app/client/packages/design-system/widgets/src/components/Datepicker/src/Datepicker.tsx @@ -79,7 +79,6 @@ export const DatePicker = (props: DatePickerProps) => { isLoading={isLoading} size={size} /> - {errorMessage} (props: DatePickerProps) => { )} + {errorMessage} ); }} diff --git a/app/client/packages/design-system/widgets/src/components/FieldLabel/src/FieldLabel.tsx b/app/client/packages/design-system/widgets/src/components/FieldLabel/src/FieldLabel.tsx index 85126a123b94..6287bcc5c88e 100644 --- a/app/client/packages/design-system/widgets/src/components/FieldLabel/src/FieldLabel.tsx +++ b/app/client/packages/design-system/widgets/src/components/FieldLabel/src/FieldLabel.tsx @@ -22,7 +22,12 @@ export function FieldLabel(props: LabelProps) { className={clsx(styles.label)} elementType="label" > - + {children} {Boolean(isRequired) && ( diff --git a/app/client/packages/design-system/widgets/src/components/Input/src/Input.tsx b/app/client/packages/design-system/widgets/src/components/Input/src/Input.tsx index 64e03bc95d66..f52a38a27093 100644 --- a/app/client/packages/design-system/widgets/src/components/Input/src/Input.tsx +++ b/app/client/packages/design-system/widgets/src/components/Input/src/Input.tsx @@ -3,7 +3,7 @@ import { mergeRefs } from "@react-aria/utils"; import React, { forwardRef, useRef, useState } from "react"; import { getTypographyClassName } from "@appsmith/wds-theming"; import { IconButton, Spinner, type IconProps } from "@appsmith/wds"; -import { Group, Input as HeadlessInput } from "react-aria-components"; +import { Input as HeadlessInput } from "react-aria-components"; import styles from "./styles.module.css"; import type { InputProps } from "./types"; @@ -49,7 +49,7 @@ function _Input(props: InputProps, ref: React.Ref) { })(); return ( - +
{Boolean(prefix) && ( localRef.current?.focus()}> {prefix} @@ -74,7 +74,7 @@ function _Input(props: InputProps, ref: React.Ref) { {suffix} )} - +
); } diff --git a/app/client/packages/design-system/widgets/src/components/Input/src/styles.module.css b/app/client/packages/design-system/widgets/src/components/Input/src/styles.module.css index 63a0d04a895c..821e337af7bf 100644 --- a/app/client/packages/design-system/widgets/src/components/Input/src/styles.module.css +++ b/app/client/packages/design-system/widgets/src/components/Input/src/styles.module.css @@ -27,6 +27,7 @@ padding-block: var(--inner-spacing-1); padding-inline: var(--inner-spacing-2); box-sizing: content-box; + cursor: inherit; } .inputGroup:has([data-input-prefix]) .input { @@ -63,10 +64,18 @@ margin-inline-start: var(--inner-spacing-2); } +.inputGroup:has(.input[data-size="small"]) [data-input-prefix] { + margin-inline-start: 0; +} + .inputGroup [data-input-suffix] { margin-inline-end: var(--inner-spacing-2); } +.inputGroup:has(.input[data-size="small"]) [data-input-suffix] { + margin-inline-end: 0; +} + .inputGroup :is([data-input-suffix], [data-input-prefix]) button { border-radius: calc( var(--border-radius-elevation-3) - var(--inner-spacing-1) @@ -84,7 +93,7 @@ * HOVERED * ---------------------------------------------------------------------------- */ -.inputGroup[data-hovered]:has( +.inputGroup:is([data-hovered], :has([data-hovered])):has( > .input:not( :is( [data-focused], @@ -111,6 +120,9 @@ .inputGroup input[data-readonly] { padding-inline: 0; + text-overflow: ellipsis; + white-space: nowrap; + cursor: text; } /** Reason for doing this is because for readonly inputs, we want focus state to be wider than the component width */ @@ -143,8 +155,9 @@ * DISABLED * ---------------------------------------------------------------------------- */ -.inputGroup:has(> .input[data-disabled]), -.inputGroup:has(> .input:has(~ input[data-disabled])) { +.inputGroup:has( + :is(.input[data-disabled], .input:has(~ input[data-disabled])) + ) { cursor: not-allowed; box-shadow: none; } diff --git a/app/client/packages/design-system/widgets/src/components/Select/src/SelectTrigger.tsx b/app/client/packages/design-system/widgets/src/components/Select/src/SelectTrigger.tsx index 0458df47bacd..91fe6f1c1567 100644 --- a/app/client/packages/design-system/widgets/src/components/Select/src/SelectTrigger.tsx +++ b/app/client/packages/design-system/widgets/src/components/Select/src/SelectTrigger.tsx @@ -2,7 +2,7 @@ import clsx from "clsx"; import React from "react"; import { Icon, Spinner, textInputStyles } from "@appsmith/wds"; import { getTypographyClassName } from "@appsmith/wds-theming"; -import { Button, Group, SelectValue } from "react-aria-components"; +import { Button, SelectValue } from "react-aria-components"; import styles from "./styles.module.css"; import type { SelectProps } from "./types"; @@ -19,9 +19,7 @@ export const SelectTrigger: React.FC = (props) => { const { isDisabled, isInvalid, isLoading, placeholder, size } = props; return ( - +
- +
); }; diff --git a/app/client/packages/design-system/widgets/src/components/Text/src/Text.tsx b/app/client/packages/design-system/widgets/src/components/Text/src/Text.tsx index b3366bf915bc..63a72cf5d329 100644 --- a/app/client/packages/design-system/widgets/src/components/Text/src/Text.tsx +++ b/app/client/packages/design-system/widgets/src/components/Text/src/Text.tsx @@ -45,6 +45,7 @@ const _Text = (props: TextProps, ref: Ref) => { fontStyle: isItalic ? "italic" : "normal", wordBreak, textAlign, + whiteSpace: "pre-wrap", ...style, }} {...rest} diff --git a/app/client/src/modules/ui-builder/ui/wds/WDSBaseInputWidget/widget/index.tsx b/app/client/src/modules/ui-builder/ui/wds/WDSBaseInputWidget/widget/index.tsx index bc8b78063693..0a2e6fa0bc1a 100644 --- a/app/client/src/modules/ui-builder/ui/wds/WDSBaseInputWidget/widget/index.tsx +++ b/app/client/src/modules/ui-builder/ui/wds/WDSBaseInputWidget/widget/index.tsx @@ -56,7 +56,7 @@ class WDSBaseInputWidget< static getMetaPropertiesMap(): Record { return { rawText: undefined, - parsedText: undefined, + text: undefined, isFocused: false, isDirty: false, }; diff --git a/app/client/src/modules/ui-builder/ui/wds/WDSCurrencyInputWidget/config/autocompleteConfig.ts b/app/client/src/modules/ui-builder/ui/wds/WDSCurrencyInputWidget/config/autocompleteConfig.ts index 8796f4c1dc14..15174f781cdb 100644 --- a/app/client/src/modules/ui-builder/ui/wds/WDSCurrencyInputWidget/config/autocompleteConfig.ts +++ b/app/client/src/modules/ui-builder/ui/wds/WDSCurrencyInputWidget/config/autocompleteConfig.ts @@ -4,14 +4,14 @@ export const autocompleteConfig = { "!doc": "An input text field is used to capture a currency value. Inputs are used in forms and can have custom validations.", "!url": "https://docs.appsmith.com/widget-reference/currency-input", - parsedText: { + text: { "!type": "string", "!doc": "The formatted text value of the input", "!url": "https://docs.appsmith.com/widget-reference/currency-input", }, rawText: { "!type": "number", - "!doc": "The value of the input", + "!doc": "The raw text value of the input", "!url": "https://docs.appsmith.com/widget-reference/currency-input", }, isValid: "bool", diff --git a/app/client/src/modules/ui-builder/ui/wds/WDSCurrencyInputWidget/widget/index.tsx b/app/client/src/modules/ui-builder/ui/wds/WDSCurrencyInputWidget/widget/index.tsx index f9087571fc14..fa71e227f114 100644 --- a/app/client/src/modules/ui-builder/ui/wds/WDSCurrencyInputWidget/widget/index.tsx +++ b/app/client/src/modules/ui-builder/ui/wds/WDSCurrencyInputWidget/widget/index.tsx @@ -130,7 +130,7 @@ class WDSCurrencyInputWidget extends WDSBaseInputWidget< static getMetaPropertiesMap(): Record { return _.merge(super.getMetaPropertiesMap(), { rawText: "", - parsedText: "", + text: "", currencyCode: undefined, }); } @@ -139,7 +139,7 @@ class WDSCurrencyInputWidget extends WDSBaseInputWidget< return _.merge(super.getDefaultPropertiesMap(), { currencyCode: "defaultCurrencyCode", rawText: "defaultText", - parsedText: "defaultText", + text: "defaultText", }); } @@ -153,9 +153,9 @@ class WDSCurrencyInputWidget extends WDSBaseInputWidget< componentDidUpdate(prevProps: CurrencyInputWidgetProps) { if ( - prevProps.text !== this.props.parsedText && + prevProps.text !== this.props.text && !this.props.isFocused && - this.props.parsedText === String(this.props.defaultText) + this.props.text === String(this.props.defaultText) ) { this.formatText(); } @@ -192,7 +192,7 @@ class WDSCurrencyInputWidget extends WDSBaseInputWidget< Sentry.captureException(e); } - this.props.updateWidgetMetaProperty("parsedText", String(formattedValue)); + this.props.updateWidgetMetaProperty("text", String(formattedValue)); this.props.updateWidgetMetaProperty("rawText", value, { triggerPropertyName: "onTextChanged", @@ -214,13 +214,13 @@ class WDSCurrencyInputWidget extends WDSBaseInputWidget< try { if (isFocused) { - const text = this.props.parsedText || ""; + const text = this.props.text || ""; const deFormattedValue = text.replace( new RegExp("\\" + getLocaleThousandSeparator(), "g"), "", ); - this.props.updateWidgetMetaProperty("parsedText", deFormattedValue); + this.props.updateWidgetMetaProperty("text", deFormattedValue); this.props.updateWidgetMetaProperty("isFocused", isFocused, { triggerPropertyName: "onFocus", dynamicString: this.props.onFocus, @@ -229,13 +229,13 @@ class WDSCurrencyInputWidget extends WDSBaseInputWidget< }, }); } else { - if (this.props.parsedText) { + if (this.props.text) { const formattedValue = formatCurrencyNumber( this.props.decimals, - this.props.parsedText, + this.props.text, ); - this.props.updateWidgetMetaProperty("parsedText", formattedValue); + this.props.updateWidgetMetaProperty("text", formattedValue); } this.props.updateWidgetMetaProperty("isFocused", isFocused, { @@ -249,7 +249,7 @@ class WDSCurrencyInputWidget extends WDSBaseInputWidget< } catch (e) { log.error(e); Sentry.captureException(e); - this.props.updateWidgetMetaProperty("parsedText", this.props.parsedText); + this.props.updateWidgetMetaProperty("text", this.props.text); } super.onFocusChange(!!isFocused); @@ -294,13 +294,13 @@ class WDSCurrencyInputWidget extends WDSBaseInputWidget< }; isTextFormatted = () => { - return this.props.parsedText.includes(getLocaleThousandSeparator()); + return this.props.text.includes(getLocaleThousandSeparator()); }; formatText() { - if (!!this.props.parsedText && !this.isTextFormatted()) { + if (!!this.props.text && !this.isTextFormatted()) { try { - const floatVal = parseFloat(this.props.parsedText); + const floatVal = parseFloat(this.props.text); const formattedValue = Intl.NumberFormat(getLocale(), { style: "decimal", @@ -308,7 +308,7 @@ class WDSCurrencyInputWidget extends WDSBaseInputWidget< maximumFractionDigits: this.props.decimals, }).format(floatVal); - this.props.updateWidgetMetaProperty("parsedText", formattedValue); + this.props.updateWidgetMetaProperty("text", formattedValue); } catch (e) { log.error(e); Sentry.captureException(e); diff --git a/app/client/src/modules/ui-builder/ui/wds/WDSInputWidget/config/autocompleteConfig.ts b/app/client/src/modules/ui-builder/ui/wds/WDSInputWidget/config/autocompleteConfig.ts index 95fa1b3db712..0bebc6f411a4 100644 --- a/app/client/src/modules/ui-builder/ui/wds/WDSInputWidget/config/autocompleteConfig.ts +++ b/app/client/src/modules/ui-builder/ui/wds/WDSInputWidget/config/autocompleteConfig.ts @@ -4,9 +4,14 @@ export const autocompleteConfig = { "!doc": "An input text field is used to capture a users textual input such as their names, numbers, emails etc. Inputs are used in forms and can have custom validations.", "!url": "https://docs.appsmith.com/widget-reference/input", - parsedText: { + text: { "!type": "string", - "!doc": "The text value of the input", + "!doc": "The parsed text value of the input", + "!url": "https://docs.appsmith.com/widget-reference/input", + }, + rawText: { + "!type": "string", + "!doc": "The raw text value of the input", "!url": "https://docs.appsmith.com/widget-reference/input", }, isValid: "bool", diff --git a/app/client/src/modules/ui-builder/ui/wds/WDSInputWidget/config/settersConfig.ts b/app/client/src/modules/ui-builder/ui/wds/WDSInputWidget/config/settersConfig.ts index 42ad0ccb6ad5..ed0afd5a385b 100644 --- a/app/client/src/modules/ui-builder/ui/wds/WDSInputWidget/config/settersConfig.ts +++ b/app/client/src/modules/ui-builder/ui/wds/WDSInputWidget/config/settersConfig.ts @@ -19,7 +19,7 @@ export const settersConfig = { setValue: { path: "defaultText", type: "string", - accessor: "parsedText", + accessor: "text", }, }, }; diff --git a/app/client/src/modules/ui-builder/ui/wds/WDSInputWidget/widget/helper.ts b/app/client/src/modules/ui-builder/ui/wds/WDSInputWidget/widget/helper.ts index 6d4e6cd3b3a3..2d56ecbf943a 100644 --- a/app/client/src/modules/ui-builder/ui/wds/WDSInputWidget/widget/helper.ts +++ b/app/client/src/modules/ui-builder/ui/wds/WDSInputWidget/widget/helper.ts @@ -69,11 +69,11 @@ export const validateInput = (props: InputWidgetProps): Validation => { maxChars, maxNum, minNum, - parsedText, rawText, + text, } = props; - if (isDirty && isRequired && !isNil(parsedText) && parsedText.length === 0) { + if (isDirty && isRequired && !isNil(text) && text.length === 0) { return { validationStatus: "invalid", errorMessage: createMessage(FIELD_REQUIRED_ERROR), @@ -81,7 +81,7 @@ export const validateInput = (props: InputWidgetProps): Validation => { } if (isInputTypeSingleLineOrMultiLine(inputType) && maxChars) { - if (parsedText && parsedText.toString().length > maxChars) { + if (text && text.toString().length > maxChars) { return { validationStatus: "invalid", errorMessage: createMessage(INPUT_TEXT_MAX_CHAR_ERROR, maxChars), @@ -97,16 +97,16 @@ export const validateInput = (props: InputWidgetProps): Validation => { }; } - if (rawText !== "" && isNumber(parsedText)) { + if (rawText !== "" && isNumber(text)) { // check the default text is neither greater than max nor less than min value. - if (!isNil(minNum) && minNum > parsedText) { + if (!isNil(minNum) && minNum > text) { return { validationStatus: "invalid", errorMessage: createMessage(INPUT_DEFAULT_TEXT_MIN_NUM_ERROR), }; } - if (!isNil(maxNum) && maxNum < parsedText) { + if (!isNil(maxNum) && maxNum < text) { return { validationStatus: "invalid", errorMessage: createMessage(INPUT_DEFAULT_TEXT_MAX_NUM_ERROR), diff --git a/app/client/src/modules/ui-builder/ui/wds/WDSInputWidget/widget/index.tsx b/app/client/src/modules/ui-builder/ui/wds/WDSInputWidget/widget/index.tsx index 5eec9a47efe9..216fe6299996 100644 --- a/app/client/src/modules/ui-builder/ui/wds/WDSInputWidget/widget/index.tsx +++ b/app/client/src/modules/ui-builder/ui/wds/WDSInputWidget/widget/index.tsx @@ -62,14 +62,14 @@ class WDSInputWidget extends WDSBaseInputWidget { static getMetaPropertiesMap(): Record { return merge(super.getMetaPropertiesMap(), { rawText: "", - parsedText: "", + text: "", }); } static getDefaultPropertiesMap(): Record { return { rawText: "defaultText", - parsedText: "defaultText", + text: "defaultText", }; } @@ -157,17 +157,17 @@ class WDSInputWidget extends WDSBaseInputWidget { if ( prevProps.rawText !== this.props.rawText && - this.props.rawText !== toString(this.props.parsedText) + this.props.rawText !== toString(this.props.text) ) { pushBatchMetaUpdates( - "parsedText", + "text", parseText(this.props.rawText, this.props.inputType), ); } if (prevProps.inputType !== this.props.inputType) { pushBatchMetaUpdates( - "parsedText", + "text", parseText(this.props.rawText, this.props.inputType), ); } @@ -190,7 +190,7 @@ class WDSInputWidget extends WDSBaseInputWidget { // derived properties won't work as expected inside a List widget. // TODO(Balaji): Once we refactor the List widget, need to conver // text to a derived property. - pushBatchMetaUpdates("parsedText", parseText(value, this.props.inputType)); + pushBatchMetaUpdates("text", parseText(value, this.props.inputType)); pushBatchMetaUpdates("rawText", value, { triggerPropertyName: "onTextChanged", @@ -211,7 +211,7 @@ class WDSInputWidget extends WDSBaseInputWidget { const { commitBatchMetaUpdates, pushBatchMetaUpdates } = this.props; pushBatchMetaUpdates("rawText", ""); - pushBatchMetaUpdates("parsedText", parseText("", this.props.inputType)); + pushBatchMetaUpdates("text", parseText("", this.props.inputType)); commitBatchMetaUpdates(); }; diff --git a/app/client/src/modules/ui-builder/ui/wds/WDSPhoneInputWidget/config/autocompleteConfig.ts b/app/client/src/modules/ui-builder/ui/wds/WDSPhoneInputWidget/config/autocompleteConfig.ts index b7fb65a6fcff..6882f5daff98 100644 --- a/app/client/src/modules/ui-builder/ui/wds/WDSPhoneInputWidget/config/autocompleteConfig.ts +++ b/app/client/src/modules/ui-builder/ui/wds/WDSPhoneInputWidget/config/autocompleteConfig.ts @@ -4,7 +4,7 @@ export const autocompleteConfig = { "!doc": "An input text field is used to capture a phone number. Inputs are used in forms and can have custom validations.", "!url": "https://docs.appsmith.com/widget-reference/phone-input", - parsedText: { + text: { "!type": "string", "!doc": "The formatted text value of the input", "!url": "https://docs.appsmith.com/widget-reference/phone-input", diff --git a/app/client/src/modules/ui-builder/ui/wds/WDSPhoneInputWidget/widget/helpers.ts b/app/client/src/modules/ui-builder/ui/wds/WDSPhoneInputWidget/widget/helpers.ts index bb68dac08912..63d2a51dfc9f 100644 --- a/app/client/src/modules/ui-builder/ui/wds/WDSPhoneInputWidget/widget/helpers.ts +++ b/app/client/src/modules/ui-builder/ui/wds/WDSPhoneInputWidget/widget/helpers.ts @@ -5,7 +5,7 @@ import { ISDCodeOptions } from "constants/ISDCodes_v2"; // TODO: Fix this the next time the file is edited // eslint-disable-next-line @typescript-eslint/no-explicit-any export function validateInput(props: any) { - const value = props.parsedText ?? ""; + const value = props.text ?? ""; const isInvalid = "isValid" in props && !props.isValid && !!props.isDirty; // TODO: Fix this the next time the file is edited diff --git a/app/client/src/modules/ui-builder/ui/wds/WDSPhoneInputWidget/widget/index.tsx b/app/client/src/modules/ui-builder/ui/wds/WDSPhoneInputWidget/widget/index.tsx index dc39829aee09..b6d73f339e1e 100644 --- a/app/client/src/modules/ui-builder/ui/wds/WDSPhoneInputWidget/widget/index.tsx +++ b/app/client/src/modules/ui-builder/ui/wds/WDSPhoneInputWidget/widget/index.tsx @@ -117,7 +117,7 @@ class WDSPhoneInputWidget extends WDSBaseInputWidget< static getMetaPropertiesMap(): Record { return merge(super.getMetaPropertiesMap(), { rawText: "", - parsedText: "", + text: "", dialCode: undefined, }); } @@ -126,7 +126,7 @@ class WDSPhoneInputWidget extends WDSBaseInputWidget< return merge(super.getDefaultPropertiesMap(), { dialCode: "defaultDialCode", rawText: "defaultText", - parsedText: "defaultText", + text: "defaultText", }); } @@ -160,7 +160,7 @@ class WDSPhoneInputWidget extends WDSBaseInputWidget< const formattedValue = this.getFormattedPhoneNumber(this.props.rawText); this.props.updateWidgetMetaProperty("rawText", this.props.rawText); - this.props.updateWidgetMetaProperty("parsedText", formattedValue); + this.props.updateWidgetMetaProperty("text", formattedValue); } catch (e) { log.error(e); Sentry.captureException(e); @@ -176,24 +176,22 @@ class WDSPhoneInputWidget extends WDSBaseInputWidget< if (prevProps.allowFormatting !== this.props.allowFormatting) { const formattedValue = this.getFormattedPhoneNumber(this.props.rawText); - this.props.updateWidgetMetaProperty("parsedText", formattedValue); + this.props.updateWidgetMetaProperty("text", formattedValue); } // When the default text changes if ( - prevProps.parsedText !== this.props.parsedText && - this.props.parsedText === this.props.defaultText + prevProps.text !== this.props.text && + this.props.text === this.props.defaultText ) { - const formattedValue = this.getFormattedPhoneNumber( - this.props.parsedText, - ); + const formattedValue = this.getFormattedPhoneNumber(this.props.text); if (formattedValue) { this.props.updateWidgetMetaProperty( "rawText", parseIncompletePhoneNumber(formattedValue), ); - this.props.updateWidgetMetaProperty("parsedText", formattedValue); + this.props.updateWidgetMetaProperty("text", formattedValue); } } @@ -214,7 +212,7 @@ class WDSPhoneInputWidget extends WDSBaseInputWidget< if (this.props.rawText && this.props.allowFormatting) { const formattedValue = this.getFormattedPhoneNumber(this.props.rawText); - this.props.updateWidgetMetaProperty("parsedText", formattedValue); + this.props.updateWidgetMetaProperty("text", formattedValue); } }; @@ -222,7 +220,7 @@ class WDSPhoneInputWidget extends WDSBaseInputWidget< let formattedValue; // Don't format, as value is typed, when user is deleting - if (value && value.length > this.props.parsedText?.length) { + if (value && value.length > this.props.text?.length) { formattedValue = this.getFormattedPhoneNumber(value); } else { formattedValue = value; @@ -232,7 +230,7 @@ class WDSPhoneInputWidget extends WDSBaseInputWidget< "rawText", parseIncompletePhoneNumber(formattedValue), ); - this.props.updateWidgetMetaProperty("parsedText", formattedValue, { + this.props.updateWidgetMetaProperty("text", formattedValue, { triggerPropertyName: "onTextChanged", dynamicString: this.props.onTextChanged, event: { @@ -300,7 +298,7 @@ class WDSPhoneInputWidget extends WDSBaseInputWidget< }; getWidgetView() { - const rawText = this.props.parsedText ?? ""; + const rawText = this.props.text ?? ""; const validation = validateInput(this.props); From f7296ef9d2ff5e44bccb1377d2f83f9f71127883 Mon Sep 17 00:00:00 2001 From: Rahul Barwal Date: Tue, 7 Jan 2025 18:43:34 +0530 Subject: [PATCH 34/40] chore: bump DSL version to 91 and update migration logic (#38516) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description This commit updates the LATEST_DSL_VERSION constant to 91 and modifies the migration logic to ensure proper handling of the new version. The change addresses an issue with auto-commit functionality not managing the clientVersion correctly, as detailed in the linked issue. No migrations are introduced with this version bump, ensuring backward compatibility. Fixes #`Issue Number` _or_ Fixes https://github.com/appsmithorg/appsmith/issues/38511 > [!WARNING] > _If no issue exists, please create an issue first, and check with the maintainers if the issue is valid._ ## Automation /ok-to-test tags="@tag.ImportExport, @tag.Git, @tag.Sanity" ### :mag: Cypress test results > [!TIP] > 🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉 > Workflow run: > Commit: 593cba725091749fbe088cdcc6f1efa1f1492a5e > Cypress dashboard. > Tags: `@tag.ImportExport, @tag.Git, @tag.Sanity` > Spec: >
Tue, 07 Jan 2025 13:13:15 UTC ## Communication Should the DevRel and Marketing teams inform users about this change? - [ ] Yes - [x] No ## Summary by CodeRabbit ## Summary by CodeRabbit - **Chores** - Updated DSL version from 90 to 91 to support auto-commit functionality. - Improved version handling mechanism for DSL migrations. - Added a new migration entry for version 90 in the migration tests. - Introduced a new method to handle client schema migrations before server migrations. --------- Co-authored-by: sondermanish --- app/client/packages/dsl/src/migrate/index.ts | 13 +++++++++- .../src/migrate/tests/DSLMigration.test.ts | 4 +++ .../migrations/JsonSchemaMigration.java | 26 ++++++++++++++++++- 3 files changed, 41 insertions(+), 2 deletions(-) diff --git a/app/client/packages/dsl/src/migrate/index.ts b/app/client/packages/dsl/src/migrate/index.ts index 738e4ac3e1c9..75ce6f7b6d5f 100644 --- a/app/client/packages/dsl/src/migrate/index.ts +++ b/app/client/packages/dsl/src/migrate/index.ts @@ -93,7 +93,7 @@ import { migrateCustomWidgetDynamicHeight } from "./migrations/088-migrate-custo import { migrateTableWidgetV2CurrentRowInValidationsBinding } from "./migrations/089-migrage-table-widget-v2-currentRow-binding"; import type { DSLWidget } from "./types"; -export const LATEST_DSL_VERSION = 90; +export const LATEST_DSL_VERSION = 91; export const calculateDynamicHeight = () => { const DEFAULT_GRID_ROW_HEIGHT = 10; @@ -613,6 +613,17 @@ const migrateVersionedDSL = async (currentDSL: DSLWidget, newPage = false) => { if (currentDSL.version === 89) { currentDSL = migrateTableWidgetV2CurrentRowInValidationsBinding(currentDSL); + currentDSL.version = 90; + } + + if (currentDSL.version === 90) { + /** + * This is just a version bump without any migration + * History: With this PR: https://github.com/appsmithorg/appsmith/pull/38391 + * we updated the `clientVersion` to 2. + * What we missed was that, the auto-commit does not handle clientVersion, which lead to this bug: https://github.com/appsmithorg/appsmith/issues/38511 + * We are bumping this version to make sure that the auto-commit will handle this version bump. + */ currentDSL.version = LATEST_DSL_VERSION; } diff --git a/app/client/packages/dsl/src/migrate/tests/DSLMigration.test.ts b/app/client/packages/dsl/src/migrate/tests/DSLMigration.test.ts index 76b4294ab87a..fd03b573d57e 100644 --- a/app/client/packages/dsl/src/migrate/tests/DSLMigration.test.ts +++ b/app/client/packages/dsl/src/migrate/tests/DSLMigration.test.ts @@ -930,6 +930,10 @@ const migrations: Migration[] = [ ], version: 89, }, + { + functionLookup: [], + version: 90, + }, ]; const mockFnObj: Record = {}; 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 c5cb0f0843fa..8d72075c6a41 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 @@ -68,11 +68,35 @@ public Mono migrateApplicationJsonToLatestSchema( return Mono.empty(); } - return migrateServerSchema(applicationJson, baseApplicationId, refName); + return migrateClientSchema(appJson, baseApplicationId, refName) + .flatMap(clientJson -> migrateServerSchema(clientJson, baseApplicationId, refName)); }) .switchIfEmpty(Mono.error(new AppsmithException(AppsmithError.INCOMPATIBLE_IMPORTED_JSON))); } + private Mono migrateClientSchema( + ApplicationJson applicationJson, String baseApplicationId, String branchName) { + + Mono migrateApplicationJsonMono = Mono.just(applicationJson); + if (jsonSchemaVersions.getClientVersion().equals(applicationJson.getClientSchemaVersion())) { + return migrateApplicationJsonMono; + } + + // Run migration linearly + // Updating the schema version after each migration is not required as we are not exiting by breaking the switch + // cases, but this keeps the version number and the migration in sync + switch (applicationJson.getClientSchemaVersion()) { + case 0: + applicationJson.setClientSchemaVersion(1); + case 1: + applicationJson.setClientSchemaVersion(2); + default: + } + + applicationJson.setClientSchemaVersion(jsonSchemaVersions.getClientVersion()); + return migrateApplicationJsonMono; + } + /** * This method may be moved to the publisher chain itself * From 3072d1e6eeffb828cf01e9b1c365ad80e4749005 Mon Sep 17 00:00:00 2001 From: Aman Agarwal Date: Wed, 8 Jan 2025 13:40:04 +0530 Subject: [PATCH 35/40] fix: external saas redirection when api created and navigated (#38518) --- .../hooks/usePluginActionResponseTabs.tsx | 1 + app/client/src/pages/Editor/Explorer/Actions/helpers.tsx | 4 +++- app/client/src/sagas/QueryPaneSagas.ts | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/app/client/src/ce/PluginActionEditor/components/PluginActionResponse/hooks/usePluginActionResponseTabs.tsx b/app/client/src/ce/PluginActionEditor/components/PluginActionResponse/hooks/usePluginActionResponseTabs.tsx index a4d7a0165cef..e36d658e4d6e 100644 --- a/app/client/src/ce/PluginActionEditor/components/PluginActionResponse/hooks/usePluginActionResponseTabs.tsx +++ b/app/client/src/ce/PluginActionEditor/components/PluginActionResponse/hooks/usePluginActionResponseTabs.tsx @@ -115,6 +115,7 @@ function usePluginActionResponseTabs() { PluginType.REMOTE, PluginType.SAAS, PluginType.INTERNAL, + PluginType.EXTERNAL_SAAS, ].includes(plugin.type) ) { if (showSchema) { diff --git a/app/client/src/pages/Editor/Explorer/Actions/helpers.tsx b/app/client/src/pages/Editor/Explorer/Actions/helpers.tsx index dccca134a118..a81027d95ff7 100644 --- a/app/client/src/pages/Editor/Explorer/Actions/helpers.tsx +++ b/app/client/src/pages/Editor/Explorer/Actions/helpers.tsx @@ -62,7 +62,8 @@ export const resolveActionURL = ({ pluginType === PluginType.DB || pluginType === PluginType.REMOTE || pluginType === PluginType.AI || - pluginType === PluginType.INTERNAL + pluginType === PluginType.INTERNAL || + pluginType === PluginType.EXTERNAL_SAAS ) { return queryEditorIdURL({ baseParentEntityId, @@ -86,6 +87,7 @@ export const ACTION_PLUGIN_MAP: Array = [ PluginType.REMOTE, PluginType.AI, PluginType.INTERNAL, + PluginType.EXTERNAL_SAAS, ], icon: dbQueryIcon, key: generateReactKey(), diff --git a/app/client/src/sagas/QueryPaneSagas.ts b/app/client/src/sagas/QueryPaneSagas.ts index 6d98b2ca63ae..8fb02f41bed1 100644 --- a/app/client/src/sagas/QueryPaneSagas.ts +++ b/app/client/src/sagas/QueryPaneSagas.ts @@ -398,6 +398,7 @@ function* handleQueryCreatedSaga(actionPayload: ReduxAction) { PluginType.REMOTE, PluginType.AI, PluginType.INTERNAL, + PluginType.EXTERNAL_SAAS, ].includes(pluginType) ) return; From c7c7625384f035b9b4f85256c80ce984878f3661 Mon Sep 17 00:00:00 2001 From: Ankita Kinger Date: Wed, 8 Jan 2025 13:58:56 +0530 Subject: [PATCH 36/40] fix: Resolving merge conflict (#38528) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description Resolving merge conflict Fixes #`Issue Number` _or_ Fixes `Issue URL` > [!WARNING] > _If no issue exists, please create an issue first, and check with the maintainers if the issue is valid._ ## Automation /ok-to-test tags="@tag.IDE" ### :mag: Cypress test results > [!TIP] > 🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉 > Workflow run: > Commit: 639f92ac62fb0c633099c4ecfdfef514288a3561 > Cypress dashboard. > Tags: `@tag.Sanity` > Spec: >
Wed, 08 Jan 2025 08:25:59 UTC ## Communication Should the DevRel and Marketing teams inform users about this change? - [ ] Yes - [ ] No --------- Co-authored-by: Aparna Ramachandran <101863839+btsgh@users.noreply.github.com> Co-authored-by: Abhijeet <41686026+abhvsn@users.noreply.github.com> Co-authored-by: yatinappsmith <84702014+yatinappsmith@users.noreply.github.com> Co-authored-by: Nidhi Co-authored-by: Shrikant Sharat Kandula Co-authored-by: “sneha122” <“sneha@appsmith.com”> Co-authored-by: Nidhi Co-authored-by: Rudraprasad Das Co-authored-by: Trisha Anand Co-authored-by: Trisha Anand Co-authored-by: Arpit Mohan Co-authored-by: Rahul Barwal --- app/client/packages/design-system/ads/src/List/List.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/client/packages/design-system/ads/src/List/List.tsx b/app/client/packages/design-system/ads/src/List/List.tsx index a6d74126c84a..0a6ab5488c7c 100644 --- a/app/client/packages/design-system/ads/src/List/List.tsx +++ b/app/client/packages/design-system/ads/src/List/List.tsx @@ -11,9 +11,6 @@ import { TooltipTextWrapper, TopContentWrapper, } from "./List.styles"; -import type { TextProps } from "../Text"; -import { Text } from "../Text"; -import { Tooltip } from "../Tooltip"; import { ListClassName, ListItemBDescClassName, @@ -22,6 +19,9 @@ import { ListItemTextOverflowClassName, ListItemTitleClassName, } from "./List.constants"; +import type { TextProps } from "../Text"; +import { Text } from "../Text"; +import { Tooltip } from "../Tooltip"; function List({ className, items, ...rest }: ListProps) { return ( From 469f9df8190842f1d5ff9d63597d2c28597c7467 Mon Sep 17 00:00:00 2001 From: Ankita Kinger Date: Wed, 8 Jan 2025 14:04:34 +0530 Subject: [PATCH 37/40] Revert "fix: Resolving merge conflict" (#38531) --- app/client/packages/design-system/ads/src/List/List.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/client/packages/design-system/ads/src/List/List.tsx b/app/client/packages/design-system/ads/src/List/List.tsx index 0a6ab5488c7c..a6d74126c84a 100644 --- a/app/client/packages/design-system/ads/src/List/List.tsx +++ b/app/client/packages/design-system/ads/src/List/List.tsx @@ -11,6 +11,9 @@ import { TooltipTextWrapper, TopContentWrapper, } from "./List.styles"; +import type { TextProps } from "../Text"; +import { Text } from "../Text"; +import { Tooltip } from "../Tooltip"; import { ListClassName, ListItemBDescClassName, @@ -19,9 +22,6 @@ import { ListItemTextOverflowClassName, ListItemTitleClassName, } from "./List.constants"; -import type { TextProps } from "../Text"; -import { Text } from "../Text"; -import { Tooltip } from "../Tooltip"; function List({ className, items, ...rest }: ListProps) { return ( From 347e7b8e2fe5b5053e35420ad10d2cadc143e1d6 Mon Sep 17 00:00:00 2001 From: Diljit Date: Wed, 8 Jan 2025 14:15:30 +0530 Subject: [PATCH 38/40] chore: disable faro session tracking (#38523) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description This PR disables faro's session tracking. Fixes #`Issue Number` _or_ Fixes `Issue URL` > [!WARNING] > _If no issue exists, please create an issue first, and check with the maintainers if the issue is valid._ ## Automation /ok-to-test tags="@tag.Sanity" ### :mag: Cypress test results > [!TIP] > 🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉 > Workflow run: > Commit: b76a4381580c695e919325330fdcda8cd3f0a2d3 > Cypress dashboard. > Tags: `@tag.Sanity` > Spec: >
Wed, 08 Jan 2025 08:41:17 UTC ## Communication Should the DevRel and Marketing teams inform users about this change? - [ ] Yes - [ ] No ## Summary by CodeRabbit ## Summary by CodeRabbit - **Configuration** - Introduced a new `sessionTracking` option in Faro instrumentation for customizable session ID generation. --- app/client/src/instrumentation/index.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/app/client/src/instrumentation/index.ts b/app/client/src/instrumentation/index.ts index 0dbf4ae4abb4..2eaacdd8701a 100644 --- a/app/client/src/instrumentation/index.ts +++ b/app/client/src/instrumentation/index.ts @@ -51,6 +51,13 @@ if (isTracingEnabled()) { trackResources: true, trackWebVitalsAttribution: true, internalLoggerLevel, + sessionTracking: { + generateSessionId: () => { + // Disabling session tracing will not send any instrumentation data to the grafana backend + // Instead, hardcoding the session id to a constant value to indirecly disable session tracing + return "SESSION_ID"; + }, + }, }); const tracerProvider = new WebTracerProvider({ From 7fd50c54c7676e3b7d0335e6fa853d53dff398d7 Mon Sep 17 00:00:00 2001 From: Hetu Nandu Date: Wed, 8 Jan 2025 15:23:56 +0530 Subject: [PATCH 39/40] chore: Housekeeping of List Item and Entity Item (#38524) --- .../design-system/ads/src/List/List.tsx | 65 +++++++++---------- .../design-system/ads/src/List/List.types.tsx | 4 +- .../Editable/useEditableText.test.tsx | 12 +++- .../Editable/useEditableText.ts | 2 + .../EntityItem/EntityItem.stories.tsx | 1 + .../EntityExplorer/EntityItem/EntityItem.tsx | 4 ++ .../EntityItem/EntityItem.types.ts | 2 + 7 files changed, 52 insertions(+), 38 deletions(-) diff --git a/app/client/packages/design-system/ads/src/List/List.tsx b/app/client/packages/design-system/ads/src/List/List.tsx index a6d74126c84a..95b905e7e61d 100644 --- a/app/client/packages/design-system/ads/src/List/List.tsx +++ b/app/client/packages/design-system/ads/src/List/List.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from "react"; +import React, { useState } from "react"; import clsx from "classnames"; import type { ListItemProps, ListProps } from "./List.types"; @@ -22,6 +22,7 @@ import { ListItemTextOverflowClassName, ListItemTitleClassName, } from "./List.constants"; +import { useEventCallback } from "usehooks-ts"; function List({ className, items, ...rest }: ListProps) { return ( @@ -34,39 +35,30 @@ function List({ className, items, ...rest }: ListProps) { } function TextWithTooltip(props: TextProps & { isMultiline?: boolean }) { - const ref = React.useRef(null); const [disableTooltip, setDisableTooltip] = useState(true); - const isEllipsisActive = () => { - let active = false; - - if (ref.current) { - const text_node = ref.current.children[0]; - - if (props.isMultiline) { - active = text_node && text_node.clientHeight < text_node.scrollHeight; - } else { - active = text_node && text_node.clientWidth < text_node.scrollWidth; + const handleShowFullText = useEventCallback( + (e: React.MouseEvent) => { + let isInEllipsis = false; + const text_node = e.target; + + if (text_node instanceof HTMLElement) { + if (props.isMultiline) { + isInEllipsis = + text_node && text_node.clientHeight < text_node.scrollHeight; + } else { + isInEllipsis = + text_node && text_node.clientWidth < text_node.scrollWidth; + } } - } - setDisableTooltip(!active); - }; - - useEffect(() => { - if (ref.current) { - isEllipsisActive(); - ref.current.addEventListener("mouseover", isEllipsisActive); - - return () => { - ref.current?.removeEventListener("mouseover", isEllipsisActive); - }; - } - }, []); + setDisableTooltip(!isInEllipsis); + }, + ); return ( - + { + const handleOnClick = useEventCallback((e: React.MouseEvent) => { + e.stopPropagation(); + if (!props.isDisabled && props.onClick) { - props.onClick(); + props.onClick(e); } - }; + }); + + const handleDoubleClick = useEventCallback((e: React.MouseEvent) => { + e.stopPropagation(); - const handleDoubleClick = () => { if (!props.isDisabled && props.onDoubleClick) { props.onDoubleClick(); } - }; + }); - const handleRightControlClick = (e: React.MouseEvent) => { + const handleRightControlClick = useEventCallback((e: React.MouseEvent) => { e.stopPropagation(); - }; + }); return ( ; @@ -11,7 +11,7 @@ export interface ListItemProps { /** Control the visibility trigger of right control */ rightControlVisibility?: "hover" | "always"; /** callback for when the list item is clicked */ - onClick: () => void; + onClick: (e: MouseEvent) => void; /** callback for when the list item is double-clicked */ onDoubleClick?: () => void; /** Whether the list item is disabled. */ diff --git a/app/client/packages/design-system/ads/src/Templates/EntityExplorer/Editable/useEditableText.test.tsx b/app/client/packages/design-system/ads/src/Templates/EntityExplorer/Editable/useEditableText.test.tsx index 455c3f8cc612..d314a8e193cb 100644 --- a/app/client/packages/design-system/ads/src/Templates/EntityExplorer/Editable/useEditableText.test.tsx +++ b/app/client/packages/design-system/ads/src/Templates/EntityExplorer/Editable/useEditableText.test.tsx @@ -82,6 +82,7 @@ describe("useEditableText", () => { act(() => { handleKeyUp({ key: "Enter", + stopPropagation: jest.fn(), } as unknown as React.KeyboardEvent); }); @@ -113,6 +114,7 @@ describe("useEditableText", () => { act(() => { handleKeyUp({ key: "Enter", + stopPropagation: jest.fn(), } as unknown as React.KeyboardEvent); }); @@ -134,7 +136,10 @@ describe("useEditableText", () => { const [, , , handleKeyUp] = result.current; act(() => { - handleKeyUp({ key: "Escape" } as React.KeyboardEvent); + handleKeyUp({ + key: "Escape", + stopPropagation: jest.fn(), + } as unknown as React.KeyboardEvent); }); expect(mockExitEditing).toHaveBeenCalled(); @@ -155,7 +160,10 @@ describe("useEditableText", () => { const [, , , handleKeyUp] = result.current; act(() => { - handleKeyUp({ key: "Enter" } as React.KeyboardEvent); + handleKeyUp({ + key: "Enter", + stopPropagation: jest.fn(), + } as unknown as React.KeyboardEvent); }); expect(mockExitEditing).toHaveBeenCalled(); diff --git a/app/client/packages/design-system/ads/src/Templates/EntityExplorer/Editable/useEditableText.ts b/app/client/packages/design-system/ads/src/Templates/EntityExplorer/Editable/useEditableText.ts index ac8d6d5e621b..59b3d4e26784 100644 --- a/app/client/packages/design-system/ads/src/Templates/EntityExplorer/Editable/useEditableText.ts +++ b/app/client/packages/design-system/ads/src/Templates/EntityExplorer/Editable/useEditableText.ts @@ -74,6 +74,8 @@ export function useEditableText( ]); const handleKeyUp = useEventCallback((e: KeyboardEvent) => { + e.stopPropagation(); + if (e.key === "Enter") { attemptSave(); } else if (e.key === "Escape") { diff --git a/app/client/packages/design-system/ads/src/Templates/EntityExplorer/EntityItem/EntityItem.stories.tsx b/app/client/packages/design-system/ads/src/Templates/EntityExplorer/EntityItem/EntityItem.stories.tsx index eb4be22a56b6..7b73e7a8b559 100644 --- a/app/client/packages/design-system/ads/src/Templates/EntityExplorer/EntityItem/EntityItem.stories.tsx +++ b/app/client/packages/design-system/ads/src/Templates/EntityExplorer/EntityItem/EntityItem.stories.tsx @@ -36,6 +36,7 @@ const Template = (props: EntityItemProps) => { { setIsEditing(true); }} diff --git a/app/client/packages/design-system/ads/src/Templates/EntityExplorer/EntityItem/EntityItem.tsx b/app/client/packages/design-system/ads/src/Templates/EntityExplorer/EntityItem/EntityItem.tsx index df92daef4400..dfeb0279eb49 100644 --- a/app/client/packages/design-system/ads/src/Templates/EntityExplorer/EntityItem/EntityItem.tsx +++ b/app/client/packages/design-system/ads/src/Templates/EntityExplorer/EntityItem/EntityItem.tsx @@ -4,6 +4,7 @@ import { ListItem, Spinner, Tooltip } from "../../.."; import type { EntityItemProps } from "./EntityItem.types"; import { EntityEditableName } from "./EntityItem.styles"; import { useEditableText } from "../Editable"; +import clx from "classnames"; export const EntityItem = (props: EntityItemProps) => { const { @@ -77,7 +78,10 @@ export const EntityItem = (props: EntityItemProps) => { return ( ); diff --git a/app/client/packages/design-system/ads/src/Templates/EntityExplorer/EntityItem/EntityItem.types.ts b/app/client/packages/design-system/ads/src/Templates/EntityExplorer/EntityItem/EntityItem.types.ts index 09244c4b3b1f..36873a9f422a 100644 --- a/app/client/packages/design-system/ads/src/Templates/EntityExplorer/EntityItem/EntityItem.types.ts +++ b/app/client/packages/design-system/ads/src/Templates/EntityExplorer/EntityItem/EntityItem.types.ts @@ -5,6 +5,8 @@ export interface EntityItemProps ListItemProps, "customTitleComponent" | "description" | "descriptionType" > { + /** ID of the entity. Will be added to the markup for identification */ + id: string; /** Control the name editing behaviour */ nameEditorConfig: { // Set editable based on user permissions From e0e76d69b47a10c55614ce44668809982cf48749 Mon Sep 17 00:00:00 2001 From: Hetu Nandu Date: Wed, 8 Jan 2025 15:32:41 +0530 Subject: [PATCH 40/40] Revert "chore: Housekeeping of List Item and Entity Item" (#38535) --- .../design-system/ads/src/List/List.tsx | 65 ++++++++++--------- .../design-system/ads/src/List/List.types.tsx | 4 +- .../Editable/useEditableText.test.tsx | 12 +--- .../Editable/useEditableText.ts | 2 - .../EntityItem/EntityItem.stories.tsx | 1 - .../EntityExplorer/EntityItem/EntityItem.tsx | 4 -- .../EntityItem/EntityItem.types.ts | 2 - 7 files changed, 38 insertions(+), 52 deletions(-) diff --git a/app/client/packages/design-system/ads/src/List/List.tsx b/app/client/packages/design-system/ads/src/List/List.tsx index 95b905e7e61d..a6d74126c84a 100644 --- a/app/client/packages/design-system/ads/src/List/List.tsx +++ b/app/client/packages/design-system/ads/src/List/List.tsx @@ -1,4 +1,4 @@ -import React, { useState } from "react"; +import React, { useEffect, useState } from "react"; import clsx from "classnames"; import type { ListItemProps, ListProps } from "./List.types"; @@ -22,7 +22,6 @@ import { ListItemTextOverflowClassName, ListItemTitleClassName, } from "./List.constants"; -import { useEventCallback } from "usehooks-ts"; function List({ className, items, ...rest }: ListProps) { return ( @@ -35,30 +34,39 @@ function List({ className, items, ...rest }: ListProps) { } function TextWithTooltip(props: TextProps & { isMultiline?: boolean }) { + const ref = React.useRef(null); const [disableTooltip, setDisableTooltip] = useState(true); - const handleShowFullText = useEventCallback( - (e: React.MouseEvent) => { - let isInEllipsis = false; - const text_node = e.target; - - if (text_node instanceof HTMLElement) { - if (props.isMultiline) { - isInEllipsis = - text_node && text_node.clientHeight < text_node.scrollHeight; - } else { - isInEllipsis = - text_node && text_node.clientWidth < text_node.scrollWidth; - } + const isEllipsisActive = () => { + let active = false; + + if (ref.current) { + const text_node = ref.current.children[0]; + + if (props.isMultiline) { + active = text_node && text_node.clientHeight < text_node.scrollHeight; + } else { + active = text_node && text_node.clientWidth < text_node.scrollWidth; } + } - setDisableTooltip(!isInEllipsis); - }, - ); + setDisableTooltip(!active); + }; + + useEffect(() => { + if (ref.current) { + isEllipsisActive(); + ref.current.addEventListener("mouseover", isEllipsisActive); + + return () => { + ref.current?.removeEventListener("mouseover", isEllipsisActive); + }; + } + }, []); return ( - + { - e.stopPropagation(); - + const handleOnClick = () => { if (!props.isDisabled && props.onClick) { - props.onClick(e); + props.onClick(); } - }); - - const handleDoubleClick = useEventCallback((e: React.MouseEvent) => { - e.stopPropagation(); + }; + const handleDoubleClick = () => { if (!props.isDisabled && props.onDoubleClick) { props.onDoubleClick(); } - }); + }; - const handleRightControlClick = useEventCallback((e: React.MouseEvent) => { + const handleRightControlClick = (e: React.MouseEvent) => { e.stopPropagation(); - }); + }; return ( ; @@ -11,7 +11,7 @@ export interface ListItemProps { /** Control the visibility trigger of right control */ rightControlVisibility?: "hover" | "always"; /** callback for when the list item is clicked */ - onClick: (e: MouseEvent) => void; + onClick: () => void; /** callback for when the list item is double-clicked */ onDoubleClick?: () => void; /** Whether the list item is disabled. */ diff --git a/app/client/packages/design-system/ads/src/Templates/EntityExplorer/Editable/useEditableText.test.tsx b/app/client/packages/design-system/ads/src/Templates/EntityExplorer/Editable/useEditableText.test.tsx index d314a8e193cb..455c3f8cc612 100644 --- a/app/client/packages/design-system/ads/src/Templates/EntityExplorer/Editable/useEditableText.test.tsx +++ b/app/client/packages/design-system/ads/src/Templates/EntityExplorer/Editable/useEditableText.test.tsx @@ -82,7 +82,6 @@ describe("useEditableText", () => { act(() => { handleKeyUp({ key: "Enter", - stopPropagation: jest.fn(), } as unknown as React.KeyboardEvent); }); @@ -114,7 +113,6 @@ describe("useEditableText", () => { act(() => { handleKeyUp({ key: "Enter", - stopPropagation: jest.fn(), } as unknown as React.KeyboardEvent); }); @@ -136,10 +134,7 @@ describe("useEditableText", () => { const [, , , handleKeyUp] = result.current; act(() => { - handleKeyUp({ - key: "Escape", - stopPropagation: jest.fn(), - } as unknown as React.KeyboardEvent); + handleKeyUp({ key: "Escape" } as React.KeyboardEvent); }); expect(mockExitEditing).toHaveBeenCalled(); @@ -160,10 +155,7 @@ describe("useEditableText", () => { const [, , , handleKeyUp] = result.current; act(() => { - handleKeyUp({ - key: "Enter", - stopPropagation: jest.fn(), - } as unknown as React.KeyboardEvent); + handleKeyUp({ key: "Enter" } as React.KeyboardEvent); }); expect(mockExitEditing).toHaveBeenCalled(); diff --git a/app/client/packages/design-system/ads/src/Templates/EntityExplorer/Editable/useEditableText.ts b/app/client/packages/design-system/ads/src/Templates/EntityExplorer/Editable/useEditableText.ts index 59b3d4e26784..ac8d6d5e621b 100644 --- a/app/client/packages/design-system/ads/src/Templates/EntityExplorer/Editable/useEditableText.ts +++ b/app/client/packages/design-system/ads/src/Templates/EntityExplorer/Editable/useEditableText.ts @@ -74,8 +74,6 @@ export function useEditableText( ]); const handleKeyUp = useEventCallback((e: KeyboardEvent) => { - e.stopPropagation(); - if (e.key === "Enter") { attemptSave(); } else if (e.key === "Escape") { diff --git a/app/client/packages/design-system/ads/src/Templates/EntityExplorer/EntityItem/EntityItem.stories.tsx b/app/client/packages/design-system/ads/src/Templates/EntityExplorer/EntityItem/EntityItem.stories.tsx index 7b73e7a8b559..eb4be22a56b6 100644 --- a/app/client/packages/design-system/ads/src/Templates/EntityExplorer/EntityItem/EntityItem.stories.tsx +++ b/app/client/packages/design-system/ads/src/Templates/EntityExplorer/EntityItem/EntityItem.stories.tsx @@ -36,7 +36,6 @@ const Template = (props: EntityItemProps) => { { setIsEditing(true); }} diff --git a/app/client/packages/design-system/ads/src/Templates/EntityExplorer/EntityItem/EntityItem.tsx b/app/client/packages/design-system/ads/src/Templates/EntityExplorer/EntityItem/EntityItem.tsx index dfeb0279eb49..df92daef4400 100644 --- a/app/client/packages/design-system/ads/src/Templates/EntityExplorer/EntityItem/EntityItem.tsx +++ b/app/client/packages/design-system/ads/src/Templates/EntityExplorer/EntityItem/EntityItem.tsx @@ -4,7 +4,6 @@ import { ListItem, Spinner, Tooltip } from "../../.."; import type { EntityItemProps } from "./EntityItem.types"; import { EntityEditableName } from "./EntityItem.styles"; import { useEditableText } from "../Editable"; -import clx from "classnames"; export const EntityItem = (props: EntityItemProps) => { const { @@ -78,10 +77,7 @@ export const EntityItem = (props: EntityItemProps) => { return ( ); diff --git a/app/client/packages/design-system/ads/src/Templates/EntityExplorer/EntityItem/EntityItem.types.ts b/app/client/packages/design-system/ads/src/Templates/EntityExplorer/EntityItem/EntityItem.types.ts index 36873a9f422a..09244c4b3b1f 100644 --- a/app/client/packages/design-system/ads/src/Templates/EntityExplorer/EntityItem/EntityItem.types.ts +++ b/app/client/packages/design-system/ads/src/Templates/EntityExplorer/EntityItem/EntityItem.types.ts @@ -5,8 +5,6 @@ export interface EntityItemProps ListItemProps, "customTitleComponent" | "description" | "descriptionType" > { - /** ID of the entity. Will be added to the markup for identification */ - id: string; /** Control the name editing behaviour */ nameEditorConfig: { // Set editable based on user permissions