diff --git a/.github/workflows/ci-test-limited-with-count.yml b/.github/workflows/ci-test-limited-with-count.yml index 7179819b2fd..68f544ffaf7 100644 --- a/.github/workflows/ci-test-limited-with-count.yml +++ b/.github/workflows/ci-test-limited-with-count.yml @@ -141,7 +141,7 @@ jobs: # Get specs to run - name: Get specs to run - if: ${{ (inputs.specs_to_run == '' || inputs.specs_to_run == null) && steps.run_result.outputs.run_result != 'success' && steps.run_result.outputs.run_result != 'failedtest' }} + if: ${{ (inputs.specs_to_run == '' || inputs.specs_to_run == null || !inputs.specs_to_run) && steps.run_result.outputs.run_result != 'success' && steps.run_result.outputs.run_result != 'failedtest' }} run: | specs_to_run="" while IFS= read -r line diff --git a/app/client/cypress/e2e/Regression/ClientSide/Anvil/AppTheming/AnvilAppThemingSnapshot_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Anvil/AppTheming/AnvilAppThemingSnapshot_spec.ts index 5b9bad823b3..6493c3eb3d4 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Anvil/AppTheming/AnvilAppThemingSnapshot_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Anvil/AppTheming/AnvilAppThemingSnapshot_spec.ts @@ -5,7 +5,7 @@ import { } from "../../../../../support/Objects/ObjectsCore"; // TODO: Enable when issue(github.com/appsmithorg/appsmith/issues/36419) is solved. -describe.skip( +describe( `${ANVIL_EDITOR_TEST}: Anvil tests for App Theming`, { tags: ["@tag.Anvil"] }, () => { diff --git a/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilButtonWidgetSnapshot_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilButtonWidgetSnapshot_spec.ts index a78e7ef5d47..74e3c855ae4 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.skip( +describe( `${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 66b66d583e7..d2113759c83 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.skip( +describe( `${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 5ad568bf5a2..fe143dcab12 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.skip( +describe( `${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 82ae69d9a07..c58a6eff6cd 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.skip( +describe( `${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 5adb9bde936..9c0b7ec7552 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.skip( +describe( `${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 9899b8ce2f7..67015f2c3e2 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.skip( +describe( `${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 eac9c2178ef..81cbbbac879 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.skip( +describe( `${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 7b90dbce28a..1634c2ae7e8 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.skip( +describe( `${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 51da8ac2395..0449dc62d6f 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.skip( +describe( `${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 2ffed43ba43..a36b4d2c0b1 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.skip( +describe( `${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 aec145739a2..a6eb434fe48 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.skip( +describe( `${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 ef99aeab293..1ed021c8127 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.skip( +describe( `${ANVIL_EDITOR_TEST}: Anvil tests for Toolbar Button Widget`, { tags: ["@tag.Anvil", "@tag.Visual"] }, () => { diff --git a/app/client/cypress/e2e/Regression/ClientSide/Autocomplete/JS_AC1_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Autocomplete/JS_AC1_spec.ts index f8190d48f01..d37b4389a20 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Autocomplete/JS_AC1_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Autocomplete/JS_AC1_spec.ts @@ -298,7 +298,7 @@ describe("Autocomplete tests", { tags: ["@tag.JS", "@tag.Binding"] }, () => { ) .type("."); - agHelper.GetNAssertElementText(locators._hints, "geolocation"); + agHelper.GetNAssertElementText(locators._hints, "appName"); }); }); @@ -313,6 +313,6 @@ describe("Autocomplete tests", { tags: ["@tag.JS", "@tag.Binding"] }, () => { .type("{downArrow}{leftArrow}{leftArrow}"); agHelper.TypeText(locators._codeMirrorTextArea, "."); - agHelper.GetNAssertElementText(locators._hints, "geolocation"); + agHelper.GetNAssertElementText(locators._hints, "appName"); }); }); diff --git a/app/client/cypress/e2e/Regression/ClientSide/IDE/Tabs_Navigation_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/IDE/Tabs_Navigation_spec.ts new file mode 100644 index 00000000000..1e56f501e1b --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/IDE/Tabs_Navigation_spec.ts @@ -0,0 +1,148 @@ +import { ObjectsRegistry } from "../../../../support/Objects/Registry"; +import { + agHelper, + dataSources, + locators, + jsEditor, +} from "../../../../support/Objects/ObjectsCore"; +import PageList from "../../../../support/Pages/PageList"; +import EditorNavigation, { + editorTabSelector, + PageLeftPane, + PagePaneSegment, +} from "../../../../support/Pages/EditorNavigation"; + +let dsName = "MongoDB"; + +describe("Tabs Navigation", { tags: ["@tag.IDE"] }, () => { + before(() => { + dataSources.CreateDataSource("Mongo"); + cy.renameDatasource(dsName); + }); + + it("should create and switch between JS files", () => { + // Create first JS file + jsEditor.CreateJSObject("", { prettify: false, toRun: false }); + jsEditor.RenameJSObjFromPane("Page1_JS1"); + + // Create second JS file + jsEditor.CreateJSObject("", { prettify: false, toRun: false }); + jsEditor.RenameJSObjFromPane("Page1_JS2"); + + agHelper.GetNClick(editorTabSelector("page1_js1")); + + jsEditor.currentJSObjectName().then((jsObjName) => { + expect(jsObjName).equal("Page1_JS1"); + }); + + agHelper.GetNClick(editorTabSelector("page1_js2")); + + jsEditor.currentJSObjectName().then((jsObjName) => { + expect(jsObjName).equal("Page1_JS2"); + }); + }); + + it("should create and switch between queries", () => { + dataSources.CreateQueryFromOverlay(dsName, "", "Page1_Query1"); + agHelper + .GetElement("[data-testid='t--ide-tab-page1_query1']") + .should("be.visible"); + dataSources.CreateQueryFromOverlay(dsName, "", "Page1_Query2"); + + // Switch between tabs + agHelper.GetNClick(editorTabSelector("page1_query1")); + + agHelper + .GetElement(locators._queryName) + .should("have.text", "Page1_Query1"); + + agHelper.GetNClick(editorTabSelector("page1_query2")); + + agHelper + .GetElement(locators._queryName) + .should("have.text", "Page1_Query2"); + }); + + it("should create items in the next page and navigate", () => { + // Create first page + PageList.AddNewPage("New blank page"); + + // Create first JS file + jsEditor.CreateJSObject("", { prettify: false, toRun: false }); + jsEditor.RenameJSObjFromPane("Page2_JS1"); + + // Create second JS file + jsEditor.CreateJSObject("", { prettify: false, toRun: false }); + jsEditor.RenameJSObjFromPane("Page2_JS2"); + + agHelper.GetNClick(editorTabSelector("page2_js1")); + + jsEditor.currentJSObjectName().then((jsObjName) => { + expect(jsObjName).equal("Page2_JS1"); + }); + + agHelper.GetNClick(editorTabSelector("page2_js2")); + + jsEditor.currentJSObjectName().then((jsObjName) => { + expect(jsObjName).equal("Page2_JS2"); + }); + + dataSources.CreateQueryFromOverlay(dsName, "", "Page2_Query1"); + dataSources.CreateQueryFromOverlay(dsName, "", "Page2_Query2"); + + agHelper.GetNClick(editorTabSelector("page2_query1")); + + agHelper + .GetElement(locators._queryName) + .should("have.text", "Page2_Query1"); + + agHelper.GetNClick(editorTabSelector("page2_query2")); + + agHelper + .GetElement(locators._queryName) + .should("have.text", "Page2_Query2"); + }); + + it("Use tabs navigation with multiple pages", () => { + EditorNavigation.NavigateToPage("Page1"); + agHelper.GetNClick(editorTabSelector("page1_query1")); + + agHelper + .GetElement(locators._queryName) + .should("have.text", "Page1_Query1"); + + agHelper.GetNClick(editorTabSelector("page1_query2")); + + agHelper + .GetElement(locators._queryName) + .should("have.text", "Page1_Query2"); + + PageLeftPane.switchSegment(PagePaneSegment.JS); + + agHelper.GetNClick(editorTabSelector("page1_js1")); + + jsEditor.currentJSObjectName().then((jsObjName) => { + expect(jsObjName).equal("Page1_JS1"); + }); + + agHelper.GetNClick(editorTabSelector("page1_js2")); + + jsEditor.currentJSObjectName().then((jsObjName) => { + expect(jsObjName).equal("Page1_JS2"); + }); + + EditorNavigation.NavigateToPage("Page2"); + PageLeftPane.switchSegment(PagePaneSegment.JS); + agHelper.GetNClick(editorTabSelector("page2_js1")); + + jsEditor.currentJSObjectName().then((jsObjName) => { + expect(jsObjName).equal("Page2_JS1"); + }); + + agHelper.GetNClick(editorTabSelector("page2_js2")); + + jsEditor.currentJSObjectName().then((jsObjName) => { + expect(jsObjName).equal("Page2_JS2"); + }); + }); +}); diff --git a/app/client/cypress/locators/QueryEditor.json b/app/client/cypress/locators/QueryEditor.json index 5bdc0186a1c..0c0cf32811e 100644 --- a/app/client/cypress/locators/QueryEditor.json +++ b/app/client/cypress/locators/QueryEditor.json @@ -9,7 +9,7 @@ "addDatasource": ".t--add-datasource", "editDatasourceButton": ".t--edit-datasource", "switch": ".t--form-control-SWITCH input", - "queryResponse": "(//div[@class='table']//div[@class='tr'])[3]//div[@class='td']", + "queryResponse": "(//div[@class='table']//div[@class='tr'])[3]//div[@class='td mp-mask']", "querySelect": "//div[contains(@class, 't--template-menu')]//div[text()='Select']", "queryCreate": "//div[contains(@class, 't--template-menu')]//div[text()='Create']", "queryUpdate": "//div[contains(@class, 't--template-menu')]//div[text()='Update']", diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilButtonWidgetSnapshot_spec.ts/anvilButtonWidgetCanvas.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilButtonWidgetSnapshot_spec.ts/anvilButtonWidgetCanvas.snap.png index 25023e98beb..1dd1c50194c 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilButtonWidgetSnapshot_spec.ts/anvilButtonWidgetCanvas.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilButtonWidgetSnapshot_spec.ts/anvilButtonWidgetCanvas.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilButtonWidgetSnapshot_spec.ts/anvilButtonWidgetCanvasDark.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilButtonWidgetSnapshot_spec.ts/anvilButtonWidgetCanvasDark.snap.png index 66edaec229f..af51a4b4950 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilButtonWidgetSnapshot_spec.ts/anvilButtonWidgetCanvasDark.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilButtonWidgetSnapshot_spec.ts/anvilButtonWidgetCanvasDark.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilButtonWidgetSnapshot_spec.ts/anvilButtonWidgetDeploy.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilButtonWidgetSnapshot_spec.ts/anvilButtonWidgetDeploy.snap.png index 934fdb11e4d..cd45182f3bd 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilButtonWidgetSnapshot_spec.ts/anvilButtonWidgetDeploy.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilButtonWidgetSnapshot_spec.ts/anvilButtonWidgetDeploy.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilButtonWidgetSnapshot_spec.ts/anvilButtonWidgetDeployIpad2.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilButtonWidgetSnapshot_spec.ts/anvilButtonWidgetDeployIpad2.snap.png index 121be741e38..54b3ac53755 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilButtonWidgetSnapshot_spec.ts/anvilButtonWidgetDeployIpad2.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilButtonWidgetSnapshot_spec.ts/anvilButtonWidgetDeployIpad2.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilButtonWidgetSnapshot_spec.ts/anvilButtonWidgetDeployIphone6.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilButtonWidgetSnapshot_spec.ts/anvilButtonWidgetDeployIphone6.snap.png index 9118ba24c50..7fb33dc3e85 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilButtonWidgetSnapshot_spec.ts/anvilButtonWidgetDeployIphone6.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilButtonWidgetSnapshot_spec.ts/anvilButtonWidgetDeployIphone6.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilButtonWidgetSnapshot_spec.ts/anvilButtonWidgetDeployMacbook13.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilButtonWidgetSnapshot_spec.ts/anvilButtonWidgetDeployMacbook13.snap.png index 98e938085d1..9429834e171 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilButtonWidgetSnapshot_spec.ts/anvilButtonWidgetDeployMacbook13.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilButtonWidgetSnapshot_spec.ts/anvilButtonWidgetDeployMacbook13.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilButtonWidgetSnapshot_spec.ts/anvilButtonWidgetPreview.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilButtonWidgetSnapshot_spec.ts/anvilButtonWidgetPreview.snap.png index 4b779afa39d..c915a79b047 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilButtonWidgetSnapshot_spec.ts/anvilButtonWidgetPreview.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilButtonWidgetSnapshot_spec.ts/anvilButtonWidgetPreview.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCheckboxGroupWidgetSnapshot_spec.ts/anvilCheckboxGroupWidgetCanvas.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCheckboxGroupWidgetSnapshot_spec.ts/anvilCheckboxGroupWidgetCanvas.snap.png index 5dc2f386149..79ae3998d23 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCheckboxGroupWidgetSnapshot_spec.ts/anvilCheckboxGroupWidgetCanvas.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCheckboxGroupWidgetSnapshot_spec.ts/anvilCheckboxGroupWidgetCanvas.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCheckboxGroupWidgetSnapshot_spec.ts/anvilCheckboxGroupWidgetCanvasDark.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCheckboxGroupWidgetSnapshot_spec.ts/anvilCheckboxGroupWidgetCanvasDark.snap.png index 85ef8f915a8..825e2ac8c67 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCheckboxGroupWidgetSnapshot_spec.ts/anvilCheckboxGroupWidgetCanvasDark.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCheckboxGroupWidgetSnapshot_spec.ts/anvilCheckboxGroupWidgetCanvasDark.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCheckboxGroupWidgetSnapshot_spec.ts/anvilCheckboxGroupWidgetDeploy.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCheckboxGroupWidgetSnapshot_spec.ts/anvilCheckboxGroupWidgetDeploy.snap.png index a9adb76bfc9..ae325b628bf 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCheckboxGroupWidgetSnapshot_spec.ts/anvilCheckboxGroupWidgetDeploy.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCheckboxGroupWidgetSnapshot_spec.ts/anvilCheckboxGroupWidgetDeploy.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCheckboxGroupWidgetSnapshot_spec.ts/anvilCheckboxGroupWidgetDeployIpad2.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCheckboxGroupWidgetSnapshot_spec.ts/anvilCheckboxGroupWidgetDeployIpad2.snap.png index ce552cb5928..3dfe6ca64c6 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCheckboxGroupWidgetSnapshot_spec.ts/anvilCheckboxGroupWidgetDeployIpad2.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCheckboxGroupWidgetSnapshot_spec.ts/anvilCheckboxGroupWidgetDeployIpad2.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCheckboxGroupWidgetSnapshot_spec.ts/anvilCheckboxGroupWidgetDeployIphone6.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCheckboxGroupWidgetSnapshot_spec.ts/anvilCheckboxGroupWidgetDeployIphone6.snap.png index 0fe8d596c38..d95f9a5ccfd 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCheckboxGroupWidgetSnapshot_spec.ts/anvilCheckboxGroupWidgetDeployIphone6.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCheckboxGroupWidgetSnapshot_spec.ts/anvilCheckboxGroupWidgetDeployIphone6.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCheckboxGroupWidgetSnapshot_spec.ts/anvilCheckboxGroupWidgetDeployMacbook13.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCheckboxGroupWidgetSnapshot_spec.ts/anvilCheckboxGroupWidgetDeployMacbook13.snap.png index aaf91616a9a..9f24d453890 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCheckboxGroupWidgetSnapshot_spec.ts/anvilCheckboxGroupWidgetDeployMacbook13.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCheckboxGroupWidgetSnapshot_spec.ts/anvilCheckboxGroupWidgetDeployMacbook13.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCheckboxWidgetSnapshot_spec.ts/anvilCheckboxWidgetCanvas.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCheckboxWidgetSnapshot_spec.ts/anvilCheckboxWidgetCanvas.snap.png index 0f05f8d0974..052c8f4a1b0 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCheckboxWidgetSnapshot_spec.ts/anvilCheckboxWidgetCanvas.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCheckboxWidgetSnapshot_spec.ts/anvilCheckboxWidgetCanvas.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCheckboxWidgetSnapshot_spec.ts/anvilCheckboxWidgetCanvasDark.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCheckboxWidgetSnapshot_spec.ts/anvilCheckboxWidgetCanvasDark.snap.png index cf32059a4cb..be3cc5f9635 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCheckboxWidgetSnapshot_spec.ts/anvilCheckboxWidgetCanvasDark.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCheckboxWidgetSnapshot_spec.ts/anvilCheckboxWidgetCanvasDark.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCheckboxWidgetSnapshot_spec.ts/anvilCheckboxWidgetDeploy.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCheckboxWidgetSnapshot_spec.ts/anvilCheckboxWidgetDeploy.snap.png index 99bfed718b4..6579561009b 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCheckboxWidgetSnapshot_spec.ts/anvilCheckboxWidgetDeploy.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCheckboxWidgetSnapshot_spec.ts/anvilCheckboxWidgetDeploy.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCheckboxWidgetSnapshot_spec.ts/anvilCheckboxWidgetDeployIpad2.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCheckboxWidgetSnapshot_spec.ts/anvilCheckboxWidgetDeployIpad2.snap.png index 71e0170835e..c50d7325935 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCheckboxWidgetSnapshot_spec.ts/anvilCheckboxWidgetDeployIpad2.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCheckboxWidgetSnapshot_spec.ts/anvilCheckboxWidgetDeployIpad2.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCheckboxWidgetSnapshot_spec.ts/anvilCheckboxWidgetDeployIphone6.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCheckboxWidgetSnapshot_spec.ts/anvilCheckboxWidgetDeployIphone6.snap.png index 35f2bde97ca..e603856b884 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCheckboxWidgetSnapshot_spec.ts/anvilCheckboxWidgetDeployIphone6.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCheckboxWidgetSnapshot_spec.ts/anvilCheckboxWidgetDeployIphone6.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCheckboxWidgetSnapshot_spec.ts/anvilCheckboxWidgetDeployMacbook13.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCheckboxWidgetSnapshot_spec.ts/anvilCheckboxWidgetDeployMacbook13.snap.png index 567798ad701..be2e6eee2ef 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCheckboxWidgetSnapshot_spec.ts/anvilCheckboxWidgetDeployMacbook13.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCheckboxWidgetSnapshot_spec.ts/anvilCheckboxWidgetDeployMacbook13.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCheckboxWidgetSnapshot_spec.ts/anvilCheckboxWidgetPreview.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCheckboxWidgetSnapshot_spec.ts/anvilCheckboxWidgetPreview.snap.png index f5fa0e7cf41..8ca7cb43097 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCheckboxWidgetSnapshot_spec.ts/anvilCheckboxWidgetPreview.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCheckboxWidgetSnapshot_spec.ts/anvilCheckboxWidgetPreview.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCurrencyInputWidgetSnapshot_spec.ts/anvilCurrencyInputWidgetDeploy.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCurrencyInputWidgetSnapshot_spec.ts/anvilCurrencyInputWidgetDeploy.snap.png index 30e68c9f54e..14304a95813 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCurrencyInputWidgetSnapshot_spec.ts/anvilCurrencyInputWidgetDeploy.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCurrencyInputWidgetSnapshot_spec.ts/anvilCurrencyInputWidgetDeploy.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCurrencyInputWidgetSnapshot_spec.ts/anvilCurrencyInputWidgetDeployIpad2.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCurrencyInputWidgetSnapshot_spec.ts/anvilCurrencyInputWidgetDeployIpad2.snap.png index f2a2277ef8c..e6ab69e57f9 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCurrencyInputWidgetSnapshot_spec.ts/anvilCurrencyInputWidgetDeployIpad2.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCurrencyInputWidgetSnapshot_spec.ts/anvilCurrencyInputWidgetDeployIpad2.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCurrencyInputWidgetSnapshot_spec.ts/anvilCurrencyInputWidgetDeployIphone6.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCurrencyInputWidgetSnapshot_spec.ts/anvilCurrencyInputWidgetDeployIphone6.snap.png index d13f6a5d69a..c9c07ca109f 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCurrencyInputWidgetSnapshot_spec.ts/anvilCurrencyInputWidgetDeployIphone6.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCurrencyInputWidgetSnapshot_spec.ts/anvilCurrencyInputWidgetDeployIphone6.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCurrencyInputWidgetSnapshot_spec.ts/anvilCurrencyInputWidgetDeployMacbook13.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCurrencyInputWidgetSnapshot_spec.ts/anvilCurrencyInputWidgetDeployMacbook13.snap.png index 1156fec3cd6..ec8b7dd985a 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCurrencyInputWidgetSnapshot_spec.ts/anvilCurrencyInputWidgetDeployMacbook13.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilCurrencyInputWidgetSnapshot_spec.ts/anvilCurrencyInputWidgetDeployMacbook13.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilHeadingWidgetSnapshot_spec.ts/anvilHeadingWidgetCanvas.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilHeadingWidgetSnapshot_spec.ts/anvilHeadingWidgetCanvas.snap.png index 2240a03aa2d..f19ea797600 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilHeadingWidgetSnapshot_spec.ts/anvilHeadingWidgetCanvas.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilHeadingWidgetSnapshot_spec.ts/anvilHeadingWidgetCanvas.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilHeadingWidgetSnapshot_spec.ts/anvilHeadingWidgetCanvasDark.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilHeadingWidgetSnapshot_spec.ts/anvilHeadingWidgetCanvasDark.snap.png index 9a35eee05e4..7cd35bca984 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilHeadingWidgetSnapshot_spec.ts/anvilHeadingWidgetCanvasDark.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilHeadingWidgetSnapshot_spec.ts/anvilHeadingWidgetCanvasDark.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilHeadingWidgetSnapshot_spec.ts/anvilHeadingWidgetDeploy.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilHeadingWidgetSnapshot_spec.ts/anvilHeadingWidgetDeploy.snap.png index 36b635e4574..8194943b7b0 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilHeadingWidgetSnapshot_spec.ts/anvilHeadingWidgetDeploy.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilHeadingWidgetSnapshot_spec.ts/anvilHeadingWidgetDeploy.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilHeadingWidgetSnapshot_spec.ts/anvilHeadingWidgetDeployIpad2.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilHeadingWidgetSnapshot_spec.ts/anvilHeadingWidgetDeployIpad2.snap.png index 42de4531cdc..fab4ae3b67d 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilHeadingWidgetSnapshot_spec.ts/anvilHeadingWidgetDeployIpad2.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilHeadingWidgetSnapshot_spec.ts/anvilHeadingWidgetDeployIpad2.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilHeadingWidgetSnapshot_spec.ts/anvilHeadingWidgetDeployIphone6.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilHeadingWidgetSnapshot_spec.ts/anvilHeadingWidgetDeployIphone6.snap.png index 09eea5aff62..5054bcefd9c 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilHeadingWidgetSnapshot_spec.ts/anvilHeadingWidgetDeployIphone6.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilHeadingWidgetSnapshot_spec.ts/anvilHeadingWidgetDeployIphone6.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilHeadingWidgetSnapshot_spec.ts/anvilHeadingWidgetDeployMacbook13.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilHeadingWidgetSnapshot_spec.ts/anvilHeadingWidgetDeployMacbook13.snap.png index 2c6b1c81f92..e224fe55e15 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilHeadingWidgetSnapshot_spec.ts/anvilHeadingWidgetDeployMacbook13.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilHeadingWidgetSnapshot_spec.ts/anvilHeadingWidgetDeployMacbook13.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilHeadingWidgetSnapshot_spec.ts/anvilHeadingWidgetPreview.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilHeadingWidgetSnapshot_spec.ts/anvilHeadingWidgetPreview.snap.png index 20221f9f8ca..a87fea2a2b2 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilHeadingWidgetSnapshot_spec.ts/anvilHeadingWidgetPreview.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilHeadingWidgetSnapshot_spec.ts/anvilHeadingWidgetPreview.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilIconButtonWidgetSnapshot_spec.ts/anvilIconButtonWidgetCanvas.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilIconButtonWidgetSnapshot_spec.ts/anvilIconButtonWidgetCanvas.snap.png index 4883384e723..e82784efcf4 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilIconButtonWidgetSnapshot_spec.ts/anvilIconButtonWidgetCanvas.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilIconButtonWidgetSnapshot_spec.ts/anvilIconButtonWidgetCanvas.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilIconButtonWidgetSnapshot_spec.ts/anvilIconButtonWidgetCanvasDark.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilIconButtonWidgetSnapshot_spec.ts/anvilIconButtonWidgetCanvasDark.snap.png index 7dca08d168e..24dc5bee739 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilIconButtonWidgetSnapshot_spec.ts/anvilIconButtonWidgetCanvasDark.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilIconButtonWidgetSnapshot_spec.ts/anvilIconButtonWidgetCanvasDark.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilIconButtonWidgetSnapshot_spec.ts/anvilIconButtonWidgetDeploy.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilIconButtonWidgetSnapshot_spec.ts/anvilIconButtonWidgetDeploy.snap.png index c149c2d5a27..bf9f46adc31 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilIconButtonWidgetSnapshot_spec.ts/anvilIconButtonWidgetDeploy.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilIconButtonWidgetSnapshot_spec.ts/anvilIconButtonWidgetDeploy.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilIconButtonWidgetSnapshot_spec.ts/anvilIconButtonWidgetDeployIpad2.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilIconButtonWidgetSnapshot_spec.ts/anvilIconButtonWidgetDeployIpad2.snap.png index 7ba16ef5bea..abdae2b1503 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilIconButtonWidgetSnapshot_spec.ts/anvilIconButtonWidgetDeployIpad2.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilIconButtonWidgetSnapshot_spec.ts/anvilIconButtonWidgetDeployIpad2.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilIconButtonWidgetSnapshot_spec.ts/anvilIconButtonWidgetDeployIphone6.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilIconButtonWidgetSnapshot_spec.ts/anvilIconButtonWidgetDeployIphone6.snap.png index 612fc773e6e..65cfd302bca 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilIconButtonWidgetSnapshot_spec.ts/anvilIconButtonWidgetDeployIphone6.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilIconButtonWidgetSnapshot_spec.ts/anvilIconButtonWidgetDeployIphone6.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilIconButtonWidgetSnapshot_spec.ts/anvilIconButtonWidgetDeployMacbook13.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilIconButtonWidgetSnapshot_spec.ts/anvilIconButtonWidgetDeployMacbook13.snap.png index dfbd6cc8b02..b4c93edacbe 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilIconButtonWidgetSnapshot_spec.ts/anvilIconButtonWidgetDeployMacbook13.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilIconButtonWidgetSnapshot_spec.ts/anvilIconButtonWidgetDeployMacbook13.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilIconButtonWidgetSnapshot_spec.ts/anvilIconButtonWidgetPreview.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilIconButtonWidgetSnapshot_spec.ts/anvilIconButtonWidgetPreview.snap.png index 60b8dcb85a1..be56c47d0ce 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilIconButtonWidgetSnapshot_spec.ts/anvilIconButtonWidgetPreview.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilIconButtonWidgetSnapshot_spec.ts/anvilIconButtonWidgetPreview.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilInlineButtonWidgetSnapshot_spec.ts/anvilInlineButtonWidgetCanvas.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilInlineButtonWidgetSnapshot_spec.ts/anvilInlineButtonWidgetCanvas.snap.png index 209fb85f801..69e5cb30483 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilInlineButtonWidgetSnapshot_spec.ts/anvilInlineButtonWidgetCanvas.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilInlineButtonWidgetSnapshot_spec.ts/anvilInlineButtonWidgetCanvas.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilInlineButtonWidgetSnapshot_spec.ts/anvilInlineButtonWidgetCanvasDark.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilInlineButtonWidgetSnapshot_spec.ts/anvilInlineButtonWidgetCanvasDark.snap.png index afb5e42c632..b80fb3a8dd0 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilInlineButtonWidgetSnapshot_spec.ts/anvilInlineButtonWidgetCanvasDark.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilInlineButtonWidgetSnapshot_spec.ts/anvilInlineButtonWidgetCanvasDark.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilInlineButtonWidgetSnapshot_spec.ts/anvilInlineButtonWidgetDeploy.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilInlineButtonWidgetSnapshot_spec.ts/anvilInlineButtonWidgetDeploy.snap.png index 6dcb85b2467..eba0c920395 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilInlineButtonWidgetSnapshot_spec.ts/anvilInlineButtonWidgetDeploy.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilInlineButtonWidgetSnapshot_spec.ts/anvilInlineButtonWidgetDeploy.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilInlineButtonWidgetSnapshot_spec.ts/anvilInlineButtonWidgetDeployIpad2.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilInlineButtonWidgetSnapshot_spec.ts/anvilInlineButtonWidgetDeployIpad2.snap.png index 1b36e211edd..05f1b5e764a 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilInlineButtonWidgetSnapshot_spec.ts/anvilInlineButtonWidgetDeployIpad2.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilInlineButtonWidgetSnapshot_spec.ts/anvilInlineButtonWidgetDeployIpad2.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilInlineButtonWidgetSnapshot_spec.ts/anvilInlineButtonWidgetDeployIphone6.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilInlineButtonWidgetSnapshot_spec.ts/anvilInlineButtonWidgetDeployIphone6.snap.png index d5fbb6086f6..f520544c5d5 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilInlineButtonWidgetSnapshot_spec.ts/anvilInlineButtonWidgetDeployIphone6.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilInlineButtonWidgetSnapshot_spec.ts/anvilInlineButtonWidgetDeployIphone6.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilInlineButtonWidgetSnapshot_spec.ts/anvilInlineButtonWidgetDeployMacbook13.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilInlineButtonWidgetSnapshot_spec.ts/anvilInlineButtonWidgetDeployMacbook13.snap.png index 9cfd79f79af..f371aec728d 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilInlineButtonWidgetSnapshot_spec.ts/anvilInlineButtonWidgetDeployMacbook13.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilInlineButtonWidgetSnapshot_spec.ts/anvilInlineButtonWidgetDeployMacbook13.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilInlineButtonWidgetSnapshot_spec.ts/anvilInlineButtonWidgetPreview.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilInlineButtonWidgetSnapshot_spec.ts/anvilInlineButtonWidgetPreview.snap.png index 5263cb3cb8b..187139de211 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilInlineButtonWidgetSnapshot_spec.ts/anvilInlineButtonWidgetPreview.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilInlineButtonWidgetSnapshot_spec.ts/anvilInlineButtonWidgetPreview.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilInputWidgetSnapshot_spec.ts/anvilInputWidgetDeploy.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilInputWidgetSnapshot_spec.ts/anvilInputWidgetDeploy.snap.png index fbfaa33d91c..c8f53e43246 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilInputWidgetSnapshot_spec.ts/anvilInputWidgetDeploy.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilInputWidgetSnapshot_spec.ts/anvilInputWidgetDeploy.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilInputWidgetSnapshot_spec.ts/anvilInputWidgetDeployIpad2.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilInputWidgetSnapshot_spec.ts/anvilInputWidgetDeployIpad2.snap.png index 7492788cbc0..2c0aaa949f5 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilInputWidgetSnapshot_spec.ts/anvilInputWidgetDeployIpad2.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilInputWidgetSnapshot_spec.ts/anvilInputWidgetDeployIpad2.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilInputWidgetSnapshot_spec.ts/anvilInputWidgetDeployIphone6.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilInputWidgetSnapshot_spec.ts/anvilInputWidgetDeployIphone6.snap.png index 22d96e7b18e..24fd98200ca 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilInputWidgetSnapshot_spec.ts/anvilInputWidgetDeployIphone6.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilInputWidgetSnapshot_spec.ts/anvilInputWidgetDeployIphone6.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilInputWidgetSnapshot_spec.ts/anvilInputWidgetDeployMacbook13.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilInputWidgetSnapshot_spec.ts/anvilInputWidgetDeployMacbook13.snap.png index 5000bea12a5..046201afc36 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilInputWidgetSnapshot_spec.ts/anvilInputWidgetDeployMacbook13.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilInputWidgetSnapshot_spec.ts/anvilInputWidgetDeployMacbook13.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilParagraphWidgetSnapshot_spec.ts/anvilParagraphWidgetCanvas.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilParagraphWidgetSnapshot_spec.ts/anvilParagraphWidgetCanvas.snap.png index 2a4b7c8f83b..e7a896cab2d 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilParagraphWidgetSnapshot_spec.ts/anvilParagraphWidgetCanvas.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilParagraphWidgetSnapshot_spec.ts/anvilParagraphWidgetCanvas.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilParagraphWidgetSnapshot_spec.ts/anvilParagraphWidgetCanvasDark.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilParagraphWidgetSnapshot_spec.ts/anvilParagraphWidgetCanvasDark.snap.png index 7da01788fbc..f2ceb8e9c9b 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilParagraphWidgetSnapshot_spec.ts/anvilParagraphWidgetCanvasDark.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilParagraphWidgetSnapshot_spec.ts/anvilParagraphWidgetCanvasDark.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilParagraphWidgetSnapshot_spec.ts/anvilParagraphWidgetDeploy.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilParagraphWidgetSnapshot_spec.ts/anvilParagraphWidgetDeploy.snap.png index 3660687c1ae..570578e858b 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilParagraphWidgetSnapshot_spec.ts/anvilParagraphWidgetDeploy.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilParagraphWidgetSnapshot_spec.ts/anvilParagraphWidgetDeploy.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilParagraphWidgetSnapshot_spec.ts/anvilParagraphWidgetDeployIpad2.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilParagraphWidgetSnapshot_spec.ts/anvilParagraphWidgetDeployIpad2.snap.png index c8fd50be0da..dd7f944fa8d 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilParagraphWidgetSnapshot_spec.ts/anvilParagraphWidgetDeployIpad2.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilParagraphWidgetSnapshot_spec.ts/anvilParagraphWidgetDeployIpad2.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilParagraphWidgetSnapshot_spec.ts/anvilParagraphWidgetDeployIphone6.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilParagraphWidgetSnapshot_spec.ts/anvilParagraphWidgetDeployIphone6.snap.png index 811631dab37..40d85449657 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilParagraphWidgetSnapshot_spec.ts/anvilParagraphWidgetDeployIphone6.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilParagraphWidgetSnapshot_spec.ts/anvilParagraphWidgetDeployIphone6.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilParagraphWidgetSnapshot_spec.ts/anvilParagraphWidgetDeployMacbook13.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilParagraphWidgetSnapshot_spec.ts/anvilParagraphWidgetDeployMacbook13.snap.png index dcc48513512..bb599f3ce9a 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilParagraphWidgetSnapshot_spec.ts/anvilParagraphWidgetDeployMacbook13.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilParagraphWidgetSnapshot_spec.ts/anvilParagraphWidgetDeployMacbook13.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilParagraphWidgetSnapshot_spec.ts/anvilParagraphWidgetPreview.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilParagraphWidgetSnapshot_spec.ts/anvilParagraphWidgetPreview.snap.png index d085c85040c..7eb9f900305 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilParagraphWidgetSnapshot_spec.ts/anvilParagraphWidgetPreview.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilParagraphWidgetSnapshot_spec.ts/anvilParagraphWidgetPreview.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilPhoneInputWidgetSnapshot_spec.ts/anvilPhoneInputWidgetDeploy.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilPhoneInputWidgetSnapshot_spec.ts/anvilPhoneInputWidgetDeploy.snap.png index cf6755af898..57844230e64 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilPhoneInputWidgetSnapshot_spec.ts/anvilPhoneInputWidgetDeploy.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilPhoneInputWidgetSnapshot_spec.ts/anvilPhoneInputWidgetDeploy.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilPhoneInputWidgetSnapshot_spec.ts/anvilPhoneInputWidgetDeployIpad2.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilPhoneInputWidgetSnapshot_spec.ts/anvilPhoneInputWidgetDeployIpad2.snap.png index 15937f55bcc..82b2dbca970 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilPhoneInputWidgetSnapshot_spec.ts/anvilPhoneInputWidgetDeployIpad2.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilPhoneInputWidgetSnapshot_spec.ts/anvilPhoneInputWidgetDeployIpad2.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilPhoneInputWidgetSnapshot_spec.ts/anvilPhoneInputWidgetDeployIphone6.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilPhoneInputWidgetSnapshot_spec.ts/anvilPhoneInputWidgetDeployIphone6.snap.png index 335ff2294b0..ce6e27a176b 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilPhoneInputWidgetSnapshot_spec.ts/anvilPhoneInputWidgetDeployIphone6.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilPhoneInputWidgetSnapshot_spec.ts/anvilPhoneInputWidgetDeployIphone6.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilPhoneInputWidgetSnapshot_spec.ts/anvilPhoneInputWidgetDeployMacbook13.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilPhoneInputWidgetSnapshot_spec.ts/anvilPhoneInputWidgetDeployMacbook13.snap.png index 1a8ccfc73e1..5fb57829dd3 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilPhoneInputWidgetSnapshot_spec.ts/anvilPhoneInputWidgetDeployMacbook13.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilPhoneInputWidgetSnapshot_spec.ts/anvilPhoneInputWidgetDeployMacbook13.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilRadioGroupWidgetSnapshot_spec.ts/anvilRadioGroupWidgetCanvas.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilRadioGroupWidgetSnapshot_spec.ts/anvilRadioGroupWidgetCanvas.snap.png index be703ef9925..ae7a28fa7b1 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilRadioGroupWidgetSnapshot_spec.ts/anvilRadioGroupWidgetCanvas.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilRadioGroupWidgetSnapshot_spec.ts/anvilRadioGroupWidgetCanvas.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilRadioGroupWidgetSnapshot_spec.ts/anvilRadioGroupWidgetCanvasDark.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilRadioGroupWidgetSnapshot_spec.ts/anvilRadioGroupWidgetCanvasDark.snap.png index 7d37c87759a..be5d3df06f9 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilRadioGroupWidgetSnapshot_spec.ts/anvilRadioGroupWidgetCanvasDark.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilRadioGroupWidgetSnapshot_spec.ts/anvilRadioGroupWidgetCanvasDark.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilRadioGroupWidgetSnapshot_spec.ts/anvilRadioGroupWidgetDeploy.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilRadioGroupWidgetSnapshot_spec.ts/anvilRadioGroupWidgetDeploy.snap.png index f2d5f5f15c7..f58d6a76529 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilRadioGroupWidgetSnapshot_spec.ts/anvilRadioGroupWidgetDeploy.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilRadioGroupWidgetSnapshot_spec.ts/anvilRadioGroupWidgetDeploy.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilRadioGroupWidgetSnapshot_spec.ts/anvilRadioGroupWidgetDeployIpad2.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilRadioGroupWidgetSnapshot_spec.ts/anvilRadioGroupWidgetDeployIpad2.snap.png index 86b317d742d..952fc71400f 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilRadioGroupWidgetSnapshot_spec.ts/anvilRadioGroupWidgetDeployIpad2.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilRadioGroupWidgetSnapshot_spec.ts/anvilRadioGroupWidgetDeployIpad2.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilRadioGroupWidgetSnapshot_spec.ts/anvilRadioGroupWidgetDeployIphone6.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilRadioGroupWidgetSnapshot_spec.ts/anvilRadioGroupWidgetDeployIphone6.snap.png index 3d3b2104872..a5ae226c24b 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilRadioGroupWidgetSnapshot_spec.ts/anvilRadioGroupWidgetDeployIphone6.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilRadioGroupWidgetSnapshot_spec.ts/anvilRadioGroupWidgetDeployIphone6.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilRadioGroupWidgetSnapshot_spec.ts/anvilRadioGroupWidgetDeployMacbook13.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilRadioGroupWidgetSnapshot_spec.ts/anvilRadioGroupWidgetDeployMacbook13.snap.png index afe9cee6820..eee2e7797d6 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilRadioGroupWidgetSnapshot_spec.ts/anvilRadioGroupWidgetDeployMacbook13.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilRadioGroupWidgetSnapshot_spec.ts/anvilRadioGroupWidgetDeployMacbook13.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilRadioGroupWidgetSnapshot_spec.ts/anvilRadioGroupWidgetPreview.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilRadioGroupWidgetSnapshot_spec.ts/anvilRadioGroupWidgetPreview.snap.png index e6559802ce6..f11372a0765 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilRadioGroupWidgetSnapshot_spec.ts/anvilRadioGroupWidgetPreview.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilRadioGroupWidgetSnapshot_spec.ts/anvilRadioGroupWidgetPreview.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilStatsWidgetSnapshot_spec.ts/anvilStatsWidgetCanvas.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilStatsWidgetSnapshot_spec.ts/anvilStatsWidgetCanvas.snap.png index ce9ca7be2e6..74a81795152 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilStatsWidgetSnapshot_spec.ts/anvilStatsWidgetCanvas.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilStatsWidgetSnapshot_spec.ts/anvilStatsWidgetCanvas.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilStatsWidgetSnapshot_spec.ts/anvilStatsWidgetCanvasDark.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilStatsWidgetSnapshot_spec.ts/anvilStatsWidgetCanvasDark.snap.png index 228508d8f16..71a8bb4b5d9 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilStatsWidgetSnapshot_spec.ts/anvilStatsWidgetCanvasDark.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilStatsWidgetSnapshot_spec.ts/anvilStatsWidgetCanvasDark.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilStatsWidgetSnapshot_spec.ts/anvilStatsWidgetDeploy.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilStatsWidgetSnapshot_spec.ts/anvilStatsWidgetDeploy.snap.png index 60d986fc3d2..0f6e343858c 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilStatsWidgetSnapshot_spec.ts/anvilStatsWidgetDeploy.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilStatsWidgetSnapshot_spec.ts/anvilStatsWidgetDeploy.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilStatsWidgetSnapshot_spec.ts/anvilStatsWidgetDeployIpad2.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilStatsWidgetSnapshot_spec.ts/anvilStatsWidgetDeployIpad2.snap.png index d0be224e5a4..b086a96e13e 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilStatsWidgetSnapshot_spec.ts/anvilStatsWidgetDeployIpad2.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilStatsWidgetSnapshot_spec.ts/anvilStatsWidgetDeployIpad2.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilStatsWidgetSnapshot_spec.ts/anvilStatsWidgetDeployIphone6.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilStatsWidgetSnapshot_spec.ts/anvilStatsWidgetDeployIphone6.snap.png index 41c2f86bf27..41a060335ad 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilStatsWidgetSnapshot_spec.ts/anvilStatsWidgetDeployIphone6.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilStatsWidgetSnapshot_spec.ts/anvilStatsWidgetDeployIphone6.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilStatsWidgetSnapshot_spec.ts/anvilStatsWidgetDeployMacbook13.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilStatsWidgetSnapshot_spec.ts/anvilStatsWidgetDeployMacbook13.snap.png index 1b7c113b65c..d956bf007bc 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilStatsWidgetSnapshot_spec.ts/anvilStatsWidgetDeployMacbook13.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilStatsWidgetSnapshot_spec.ts/anvilStatsWidgetDeployMacbook13.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilSwitchGroupWidgetSnapshot_spec.ts/anvilSwitchGroupWidgetCanvas.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilSwitchGroupWidgetSnapshot_spec.ts/anvilSwitchGroupWidgetCanvas.snap.png index f0881060a3e..c1b5e55504b 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilSwitchGroupWidgetSnapshot_spec.ts/anvilSwitchGroupWidgetCanvas.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilSwitchGroupWidgetSnapshot_spec.ts/anvilSwitchGroupWidgetCanvas.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilSwitchGroupWidgetSnapshot_spec.ts/anvilSwitchGroupWidgetCanvasDark.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilSwitchGroupWidgetSnapshot_spec.ts/anvilSwitchGroupWidgetCanvasDark.snap.png index f4216611960..0cf9c7052a1 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilSwitchGroupWidgetSnapshot_spec.ts/anvilSwitchGroupWidgetCanvasDark.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilSwitchGroupWidgetSnapshot_spec.ts/anvilSwitchGroupWidgetCanvasDark.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilSwitchGroupWidgetSnapshot_spec.ts/anvilSwitchGroupWidgetDeploy.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilSwitchGroupWidgetSnapshot_spec.ts/anvilSwitchGroupWidgetDeploy.snap.png index 2c135a3b11b..4b85db8b528 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilSwitchGroupWidgetSnapshot_spec.ts/anvilSwitchGroupWidgetDeploy.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilSwitchGroupWidgetSnapshot_spec.ts/anvilSwitchGroupWidgetDeploy.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilSwitchGroupWidgetSnapshot_spec.ts/anvilSwitchGroupWidgetDeployIpad2.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilSwitchGroupWidgetSnapshot_spec.ts/anvilSwitchGroupWidgetDeployIpad2.snap.png index 95f8176ff47..a77750ba28b 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilSwitchGroupWidgetSnapshot_spec.ts/anvilSwitchGroupWidgetDeployIpad2.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilSwitchGroupWidgetSnapshot_spec.ts/anvilSwitchGroupWidgetDeployIpad2.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilSwitchGroupWidgetSnapshot_spec.ts/anvilSwitchGroupWidgetDeployIphone6.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilSwitchGroupWidgetSnapshot_spec.ts/anvilSwitchGroupWidgetDeployIphone6.snap.png index b72580b5b41..2ea1a7a91eb 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilSwitchGroupWidgetSnapshot_spec.ts/anvilSwitchGroupWidgetDeployIphone6.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilSwitchGroupWidgetSnapshot_spec.ts/anvilSwitchGroupWidgetDeployIphone6.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilSwitchGroupWidgetSnapshot_spec.ts/anvilSwitchGroupWidgetDeployMacbook13.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilSwitchGroupWidgetSnapshot_spec.ts/anvilSwitchGroupWidgetDeployMacbook13.snap.png index bb542f34c34..46b1c26f224 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilSwitchGroupWidgetSnapshot_spec.ts/anvilSwitchGroupWidgetDeployMacbook13.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilSwitchGroupWidgetSnapshot_spec.ts/anvilSwitchGroupWidgetDeployMacbook13.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilSwitchGroupWidgetSnapshot_spec.ts/anvilSwitchGroupWidgetPreview.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilSwitchGroupWidgetSnapshot_spec.ts/anvilSwitchGroupWidgetPreview.snap.png index 5861230d4fb..4a5e3fcbf77 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilSwitchGroupWidgetSnapshot_spec.ts/anvilSwitchGroupWidgetPreview.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilSwitchGroupWidgetSnapshot_spec.ts/anvilSwitchGroupWidgetPreview.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilSwitchWidgetSnapshot_spec.ts/anvilSwitchWidgetCanvas.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilSwitchWidgetSnapshot_spec.ts/anvilSwitchWidgetCanvas.snap.png index 6ba6ce0809e..f547452af57 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilSwitchWidgetSnapshot_spec.ts/anvilSwitchWidgetCanvas.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilSwitchWidgetSnapshot_spec.ts/anvilSwitchWidgetCanvas.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilSwitchWidgetSnapshot_spec.ts/anvilSwitchWidgetCanvasDark.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilSwitchWidgetSnapshot_spec.ts/anvilSwitchWidgetCanvasDark.snap.png index 727b9d824e9..faa4ff5f27d 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilSwitchWidgetSnapshot_spec.ts/anvilSwitchWidgetCanvasDark.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilSwitchWidgetSnapshot_spec.ts/anvilSwitchWidgetCanvasDark.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilSwitchWidgetSnapshot_spec.ts/anvilSwitchWidgetDeploy.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilSwitchWidgetSnapshot_spec.ts/anvilSwitchWidgetDeploy.snap.png index 3e9db0f7361..63bb516bb43 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilSwitchWidgetSnapshot_spec.ts/anvilSwitchWidgetDeploy.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilSwitchWidgetSnapshot_spec.ts/anvilSwitchWidgetDeploy.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilSwitchWidgetSnapshot_spec.ts/anvilSwitchWidgetDeployIpad2.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilSwitchWidgetSnapshot_spec.ts/anvilSwitchWidgetDeployIpad2.snap.png index 33cb60aaabb..3dc45f5ede5 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilSwitchWidgetSnapshot_spec.ts/anvilSwitchWidgetDeployIpad2.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilSwitchWidgetSnapshot_spec.ts/anvilSwitchWidgetDeployIpad2.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilSwitchWidgetSnapshot_spec.ts/anvilSwitchWidgetDeployIphone6.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilSwitchWidgetSnapshot_spec.ts/anvilSwitchWidgetDeployIphone6.snap.png index 42940debaff..d9d1b249626 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilSwitchWidgetSnapshot_spec.ts/anvilSwitchWidgetDeployIphone6.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilSwitchWidgetSnapshot_spec.ts/anvilSwitchWidgetDeployIphone6.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilSwitchWidgetSnapshot_spec.ts/anvilSwitchWidgetDeployMacbook13.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilSwitchWidgetSnapshot_spec.ts/anvilSwitchWidgetDeployMacbook13.snap.png index b40fcb197bb..d241efcbc9e 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilSwitchWidgetSnapshot_spec.ts/anvilSwitchWidgetDeployMacbook13.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilSwitchWidgetSnapshot_spec.ts/anvilSwitchWidgetDeployMacbook13.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilSwitchWidgetSnapshot_spec.ts/anvilSwitchWidgetPreview.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilSwitchWidgetSnapshot_spec.ts/anvilSwitchWidgetPreview.snap.png index f50b7d7f9cc..e290b747f9f 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilSwitchWidgetSnapshot_spec.ts/anvilSwitchWidgetPreview.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilSwitchWidgetSnapshot_spec.ts/anvilSwitchWidgetPreview.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilTableWidgetSnapshot_spec.ts/anvilTableWidgetCanvas.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilTableWidgetSnapshot_spec.ts/anvilTableWidgetCanvas.snap.png index 00676699313..49eac54e3ea 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilTableWidgetSnapshot_spec.ts/anvilTableWidgetCanvas.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilTableWidgetSnapshot_spec.ts/anvilTableWidgetCanvas.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilTableWidgetSnapshot_spec.ts/anvilTableWidgetCanvasDark.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilTableWidgetSnapshot_spec.ts/anvilTableWidgetCanvasDark.snap.png index 217db7725be..93f200ccb8d 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilTableWidgetSnapshot_spec.ts/anvilTableWidgetCanvasDark.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilTableWidgetSnapshot_spec.ts/anvilTableWidgetCanvasDark.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilTableWidgetSnapshot_spec.ts/anvilTableWidgetDeploy.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilTableWidgetSnapshot_spec.ts/anvilTableWidgetDeploy.snap.png index 0a4be317be6..15f9e5581e6 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilTableWidgetSnapshot_spec.ts/anvilTableWidgetDeploy.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilTableWidgetSnapshot_spec.ts/anvilTableWidgetDeploy.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilTableWidgetSnapshot_spec.ts/anvilTableWidgetDeployIpad2.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilTableWidgetSnapshot_spec.ts/anvilTableWidgetDeployIpad2.snap.png index 9ddee401539..058697a5418 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilTableWidgetSnapshot_spec.ts/anvilTableWidgetDeployIpad2.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilTableWidgetSnapshot_spec.ts/anvilTableWidgetDeployIpad2.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilTableWidgetSnapshot_spec.ts/anvilTableWidgetDeployIphone6.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilTableWidgetSnapshot_spec.ts/anvilTableWidgetDeployIphone6.snap.png index 13c71918e4b..02062784acb 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilTableWidgetSnapshot_spec.ts/anvilTableWidgetDeployIphone6.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilTableWidgetSnapshot_spec.ts/anvilTableWidgetDeployIphone6.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilTableWidgetSnapshot_spec.ts/anvilTableWidgetDeployMacbook13.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilTableWidgetSnapshot_spec.ts/anvilTableWidgetDeployMacbook13.snap.png index 14ce290b579..a515323fbf6 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilTableWidgetSnapshot_spec.ts/anvilTableWidgetDeployMacbook13.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilTableWidgetSnapshot_spec.ts/anvilTableWidgetDeployMacbook13.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilTableWidgetSnapshot_spec.ts/anvilTableWidgetPreview.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilTableWidgetSnapshot_spec.ts/anvilTableWidgetPreview.snap.png index 5f8695cff52..59f04927dd3 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilTableWidgetSnapshot_spec.ts/anvilTableWidgetPreview.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilTableWidgetSnapshot_spec.ts/anvilTableWidgetPreview.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilToolbarButtonWidgetSnapshot_spec.ts/anvilToolbarButtonWidgetCanvas.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilToolbarButtonWidgetSnapshot_spec.ts/anvilToolbarButtonWidgetCanvas.snap.png index cd7137bbf69..2c88f16c538 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilToolbarButtonWidgetSnapshot_spec.ts/anvilToolbarButtonWidgetCanvas.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilToolbarButtonWidgetSnapshot_spec.ts/anvilToolbarButtonWidgetCanvas.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilToolbarButtonWidgetSnapshot_spec.ts/anvilToolbarButtonWidgetCanvasDark.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilToolbarButtonWidgetSnapshot_spec.ts/anvilToolbarButtonWidgetCanvasDark.snap.png index db030580e11..e53c61d34e1 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilToolbarButtonWidgetSnapshot_spec.ts/anvilToolbarButtonWidgetCanvasDark.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilToolbarButtonWidgetSnapshot_spec.ts/anvilToolbarButtonWidgetCanvasDark.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilToolbarButtonWidgetSnapshot_spec.ts/anvilToolbarButtonWidgetDeploy.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilToolbarButtonWidgetSnapshot_spec.ts/anvilToolbarButtonWidgetDeploy.snap.png index f9e5ce37ea2..151d615fc2e 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilToolbarButtonWidgetSnapshot_spec.ts/anvilToolbarButtonWidgetDeploy.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilToolbarButtonWidgetSnapshot_spec.ts/anvilToolbarButtonWidgetDeploy.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilToolbarButtonWidgetSnapshot_spec.ts/anvilToolbarButtonWidgetDeployIpad2.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilToolbarButtonWidgetSnapshot_spec.ts/anvilToolbarButtonWidgetDeployIpad2.snap.png index 2eec1d8dddf..5eb51a533ba 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilToolbarButtonWidgetSnapshot_spec.ts/anvilToolbarButtonWidgetDeployIpad2.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilToolbarButtonWidgetSnapshot_spec.ts/anvilToolbarButtonWidgetDeployIpad2.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilToolbarButtonWidgetSnapshot_spec.ts/anvilToolbarButtonWidgetDeployIphone6.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilToolbarButtonWidgetSnapshot_spec.ts/anvilToolbarButtonWidgetDeployIphone6.snap.png index a9ca428802f..52bd793cac9 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilToolbarButtonWidgetSnapshot_spec.ts/anvilToolbarButtonWidgetDeployIphone6.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilToolbarButtonWidgetSnapshot_spec.ts/anvilToolbarButtonWidgetDeployIphone6.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilToolbarButtonWidgetSnapshot_spec.ts/anvilToolbarButtonWidgetDeployMacbook13.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilToolbarButtonWidgetSnapshot_spec.ts/anvilToolbarButtonWidgetDeployMacbook13.snap.png index 18ff6ccb1c2..fd138e3e867 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilToolbarButtonWidgetSnapshot_spec.ts/anvilToolbarButtonWidgetDeployMacbook13.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilToolbarButtonWidgetSnapshot_spec.ts/anvilToolbarButtonWidgetDeployMacbook13.snap.png differ diff --git a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilToolbarButtonWidgetSnapshot_spec.ts/anvilToolbarButtonWidgetPreview.snap.png b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilToolbarButtonWidgetSnapshot_spec.ts/anvilToolbarButtonWidgetPreview.snap.png index c1a2674a2fe..d760f3c013e 100644 Binary files a/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilToolbarButtonWidgetSnapshot_spec.ts/anvilToolbarButtonWidgetPreview.snap.png and b/app/client/cypress/snapshots/Regression/ClientSide/Anvil/Widgets/AnvilToolbarButtonWidgetSnapshot_spec.ts/anvilToolbarButtonWidgetPreview.snap.png differ diff --git a/app/client/cypress/support/Pages/DataSources.ts b/app/client/cypress/support/Pages/DataSources.ts index 83c00124374..ff559f6e478 100644 --- a/app/client/cypress/support/Pages/DataSources.ts +++ b/app/client/cypress/support/Pages/DataSources.ts @@ -147,7 +147,7 @@ export class DataSources { option + "']"; _queryTableResponse = - "//div[@data-guided-tour-id='query-table-response']//div[@class='tbody']//div[@class ='td']"; + "//div[@data-guided-tour-id='query-table-response']//div[@class='tbody']//div[@class ='td mp-mask']"; _queryResponseHeader = (header: string) => "//div[@data-guided-tour-id='query-table-response']//div[@class='table']//div[@role ='columnheader']//span[text()='" + header + diff --git a/app/client/cypress/support/Pages/EditorNavigation.ts b/app/client/cypress/support/Pages/EditorNavigation.ts index 971b607b196..38fc48ad3ff 100644 --- a/app/client/cypress/support/Pages/EditorNavigation.ts +++ b/app/client/cypress/support/Pages/EditorNavigation.ts @@ -20,6 +20,9 @@ export enum PagePaneSegment { JS = "JS", } +export const editorTabSelector = (name: string) => + `[data-testid='t--ide-tab-${name.toLowerCase()}']`; + export enum EditorViewMode { FullScreen = "FullScreen", SplitScreen = "SplitScreen", diff --git a/app/client/cypress/support/commands.js b/app/client/cypress/support/commands.js index 4de96346ecd..75dab161159 100644 --- a/app/client/cypress/support/commands.js +++ b/app/client/cypress/support/commands.js @@ -814,7 +814,7 @@ Cypress.Commands.add("ValidatePaginateResponseUrlData", (runTestCss) => { cy.wait(2000); cy.get(runTestCss).click(); cy.wait(2000); - cy.xpath("//div[@class='tr'][1]//div[@class='td'][6]//span") + cy.xpath("//div[@class='tr'][1]//div[@class='td mp-mask'][6]//span") .invoke("text") .then((valueToTest) => { // eslint-disable-next-line cypress/no-unnecessary-waiting @@ -839,7 +839,7 @@ Cypress.Commands.add("ValidatePaginateResponseUrlDataV2", (runTestCss) => { cy.wait(2000); cy.get(runTestCss).click(); cy.wait(2000); - cy.xpath("//div[@class='tr'][1]//div[@class='td'][6]//span") + cy.xpath("//div[@class='tr'][1]//div[@class='td mp-mask'][6]//span") .invoke("text") .then((valueToTest) => { // eslint-disable-next-line cypress/no-unnecessary-waiting 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 d0faca4f3a6..63a0d04a895 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 @@ -8,8 +8,6 @@ .inputGroup { max-inline-size: 100%; - padding-block: var(--inner-spacing-1); - padding-inline: var(--inner-spacing-2); gap: var(--inner-spacing-1); border: 0; border-radius: var(--border-radius-elevation-3); @@ -26,6 +24,17 @@ background-color: transparent; flex: 1; padding: 0; + padding-block: var(--inner-spacing-1); + padding-inline: var(--inner-spacing-2); + box-sizing: content-box; +} + +.inputGroup:has([data-input-prefix]) .input { + padding-inline-start: 0; +} + +.inputGroup:has([data-input-suffix]) .input { + padding-inline-end: 0; } .input:is(textarea) { @@ -50,6 +59,14 @@ * SUFFIX and PREFIX * ---------------------------------------------------------------------------- */ +.inputGroup [data-input-prefix] { + margin-inline-start: var(--inner-spacing-2); +} + +.inputGroup [data-input-suffix] { + margin-inline-end: var(--inner-spacing-2); +} + .inputGroup :is([data-input-suffix], [data-input-prefix]) button { border-radius: calc( var(--border-radius-elevation-3) - var(--inner-spacing-1) @@ -60,7 +77,6 @@ display: flex; justify-content: center; align-items: center; - height: 0; } /** @@ -88,9 +104,12 @@ * READONLY * ---------------------------------------------------------------------------- */ -.input[data-readonly] { +.inputGroup:has(> .input[data-readonly]) { background-color: transparent; box-shadow: none; +} + +.inputGroup input[data-readonly] { padding-inline: 0; } @@ -164,17 +183,17 @@ * SIZE * ---------------------------------------------------------------------------- */ -.inputGroup:has(> .input[data-size="small"]) { - block-size: calc( - var(--body-line-height) + var(--body-margin-start) + var(--body-margin-end) + - var(--inner-spacing-2) * 2 - ); +.inputGroup .input { + block-size: var(--body-line-height); } -.inputGroup:has(> .input[data-size="large"]) { +.inputGroup .input[data-size="small"] { block-size: calc( var(--body-line-height) + var(--body-margin-start) + var(--body-margin-end) ); - padding-block: var(--inner-spacing-3); - padding-inline: var(--inner-spacing-3); + padding: var(--inner-spacing-2); +} + +.inputGroup .input[data-size="large"] { + padding: var(--inner-spacing-3); } diff --git a/app/client/packages/design-system/widgets/src/components/TextArea/src/TextArea.tsx b/app/client/packages/design-system/widgets/src/components/TextArea/src/TextArea.tsx index 042e54a1c35..d004f2d7975 100644 --- a/app/client/packages/design-system/widgets/src/components/TextArea/src/TextArea.tsx +++ b/app/client/packages/design-system/widgets/src/components/TextArea/src/TextArea.tsx @@ -76,16 +76,12 @@ export function TextArea(props: TextAreaProps) { input.style.height = `${ // subtract comptued padding and border to get the actual content height - input.scrollHeight - - paddingTop - - paddingBottom + - // Also, adding 1px to fix a bug in browser where there is a scrolllbar on certain heights - 1 + input.scrollHeight - paddingTop - paddingBottom }px`; input.style.overflow = prevOverflow; input.style.alignSelf = prevAlignment; } - }, [inputRef.current, props.height]); + }, [props.height]); useLayoutEffect(() => { if (inputRef.current) { diff --git a/app/client/src/PluginActionEditor/components/PluginActionResponse/components/Table.tsx b/app/client/src/PluginActionEditor/components/PluginActionResponse/components/Table.tsx index d833e5b43e0..3eb85a11b4f 100644 --- a/app/client/src/PluginActionEditor/components/PluginActionResponse/components/Table.tsx +++ b/app/client/src/PluginActionEditor/components/PluginActionResponse/components/Table.tsx @@ -311,7 +311,11 @@ function Table(props: TableProps) { {/* eslint-disable-next-line @typescript-eslint/no-explicit-any */} {row.cells.map((cell: any, cellIndex: number) => { return ( -
+
{cell.render("Cell")}
); @@ -344,7 +348,7 @@ function Table(props: TableProps) { {headerGroups.map((headerGroup: any, index: number) => (
{headerGroup.headers.map( diff --git a/app/client/src/ce/components/BottomBar/GitActionsWrapper.tsx b/app/client/src/ce/components/BottomBar/GitActionsWrapper.tsx new file mode 100644 index 00000000000..6a917ffe645 --- /dev/null +++ b/app/client/src/ce/components/BottomBar/GitActionsWrapper.tsx @@ -0,0 +1,7 @@ +// This function is used to wrap the children in a disabled container if the package is upgrading +// It's implemented in EE, but not in CE +function GitActionsWrapper({ children }: { children: React.ReactElement }) { + return children; +} + +export default GitActionsWrapper; diff --git a/app/client/src/ce/constants/messages.ts b/app/client/src/ce/constants/messages.ts index d284e9e393d..9b7a7647538 100644 --- a/app/client/src/ce/constants/messages.ts +++ b/app/client/src/ce/constants/messages.ts @@ -477,6 +477,8 @@ export const PAGE_SERVER_UNAVAILABLE_ERROR_CODE = () => "503"; // Modules export const CONVERT_MODULE_CTA_TEXT = () => "Create module"; export const CONVERT_MODULE_TO_NEW_PKG_OPTION = () => "Add to a new package"; +export const PACKAGE_UPGRADING_ACTION_STATUS = (action: string) => + `You're not able to ${action} while package references are updating. Please wait until the update is complete.`; // cloudHosting used in EE // eslint-disable-next-line @typescript-eslint/no-unused-vars diff --git a/app/client/src/ce/entities/DataTree/types.ts b/app/client/src/ce/entities/DataTree/types.ts index a2fcbcbc9d2..42652009b95 100644 --- a/app/client/src/ce/entities/DataTree/types.ts +++ b/app/client/src/ce/entities/DataTree/types.ts @@ -190,6 +190,9 @@ export interface AppsmithEntity extends Omit { ENTITY_TYPE: typeof ENTITY_TYPE.APPSMITH; store: Record; theme: AppTheme["properties"]; + currentPageName: string; + workspaceName: string; + appName: string; } export interface DataTreeSeed { diff --git a/app/client/src/ce/entities/FeatureFlag.ts b/app/client/src/ce/entities/FeatureFlag.ts index eb124bcebf5..d3048a86f9f 100644 --- a/app/client/src/ce/entities/FeatureFlag.ts +++ b/app/client/src/ce/entities/FeatureFlag.ts @@ -49,6 +49,11 @@ export const FEATURE_FLAG = { release_gs_all_sheets_options_enabled: "release_gs_all_sheets_options_enabled", ab_premium_datasources_view_enabled: "ab_premium_datasources_view_enabled", + kill_session_recordings_enabled: "kill_session_recordings_enabled", + config_mask_session_recordings_enabled: + "config_mask_session_recordings_enabled", + config_user_session_recordings_enabled: + "config_user_session_recordings_enabled", } as const; export type FeatureFlag = keyof typeof FEATURE_FLAG; @@ -91,6 +96,9 @@ export const DEFAULT_FEATURE_FLAG_VALUE: FeatureFlags = { release_table_html_column_type_enabled: false, release_gs_all_sheets_options_enabled: false, ab_premium_datasources_view_enabled: false, + kill_session_recordings_enabled: false, + config_user_session_recordings_enabled: true, + config_mask_session_recordings_enabled: true, }; export const AB_TESTING_EVENT_KEYS = { diff --git a/app/client/src/ce/sagas/userSagas.tsx b/app/client/src/ce/sagas/userSagas.tsx index ff8409ef4fd..7da583fe343 100644 --- a/app/client/src/ce/sagas/userSagas.tsx +++ b/app/client/src/ce/sagas/userSagas.tsx @@ -74,6 +74,7 @@ import type { } from "reducers/uiReducers/usersReducer"; import { selectFeatureFlags } from "ee/selectors/featureFlagsSelectors"; import { getFromServerWhenNoPrefetchedResult } from "sagas/helper"; +import type { SessionRecordingConfig } from "utils/Analytics/mixpanel"; export function* getCurrentUserSaga(action?: { payload?: { userProfile?: ApiResponse }; @@ -107,9 +108,42 @@ export function* getCurrentUserSaga(action?: { } } +function* getSessionRecordingConfig() { + const featureFlags: FeatureFlags = yield select(selectFeatureFlags); + + // This is a tenant level flag to kill session recordings + // If this is true, we do not do any session recordings + if (featureFlags.kill_session_recordings_enabled) { + return { + enabled: false, + mask: false, + }; + } + + // This is a user level flag to control session recordings for a user + // If this is false, we do not do any session recordings + if (!featureFlags.config_user_session_recordings_enabled) { + return { + enabled: false, + mask: false, + }; + } + + // Now we know that both tenant and user level flags are not blocking session recordings + return { + enabled: true, + // Check if we need to mask the session recordings from feature flags + mask: featureFlags.config_mask_session_recordings_enabled, + }; +} + function* initTrackers(currentUser: User) { try { - yield call(AnalyticsUtil.initialize, currentUser); + const sessionRecordingConfig: SessionRecordingConfig = yield call( + getSessionRecordingConfig, + ); + + yield call(AnalyticsUtil.initialize, currentUser, sessionRecordingConfig); } catch (e) { log.error(e); } diff --git a/app/client/src/ce/selectors/packageSelectors.ts b/app/client/src/ce/selectors/packageSelectors.ts index 56b5a10e485..994228866ac 100644 --- a/app/client/src/ce/selectors/packageSelectors.ts +++ b/app/client/src/ce/selectors/packageSelectors.ts @@ -16,3 +16,6 @@ export const getPackagesList = (state: AppState): PackageMetadata[] => // eslint-disable-next-line @typescript-eslint/no-unused-vars export const getPackagesOfWorkspace = (state: AppState) => []; + +// eslint-disable-next-line @typescript-eslint/no-unused-vars +export const getIsPackageUpgrading = (state: AppState): boolean => false; diff --git a/app/client/src/ce/utils/AnalyticsUtil.tsx b/app/client/src/ce/utils/AnalyticsUtil.tsx index 622ad9c59c2..f7ea262255a 100644 --- a/app/client/src/ce/utils/AnalyticsUtil.tsx +++ b/app/client/src/ce/utils/AnalyticsUtil.tsx @@ -6,7 +6,9 @@ import type { EventName } from "ee/utils/analyticsUtilTypes"; import type { EventProperties } from "@segment/analytics-next"; import SegmentSingleton from "utils/Analytics/segment"; -import MixpanelSingleton from "utils/Analytics/mixpanel"; +import MixpanelSingleton, { + type SessionRecordingConfig, +} from "utils/Analytics/mixpanel"; import SentryUtil from "utils/Analytics/sentry"; import SmartlookUtil from "utils/Analytics/smartlook"; import TrackedUser from "ee/utils/Analytics/trackedUser"; @@ -25,7 +27,10 @@ export enum AnalyticsEventType { let blockErrorLogs = false; let segmentAnalytics: SegmentSingleton | null = null; -async function initialize(user: User) { +async function initialize( + user: User, + sessionRecordingConfig: SessionRecordingConfig, +) { SentryUtil.init(); await SmartlookUtil.init(); @@ -34,7 +39,7 @@ async function initialize(user: User) { await segmentAnalytics.init(); // Mixpanel needs to be initialized after Segment - await MixpanelSingleton.getInstance().init(); + await MixpanelSingleton.getInstance().init(sessionRecordingConfig); // Identify the user after all services are initialized await identifyUser(user); diff --git a/app/client/src/components/editorComponents/CodeEditor/PeekOverlayPopup/PeekOverlayPopup.tsx b/app/client/src/components/editorComponents/CodeEditor/PeekOverlayPopup/PeekOverlayPopup.tsx index 7b0f0bd55c0..80ba7bbf007 100644 --- a/app/client/src/components/editorComponents/CodeEditor/PeekOverlayPopup/PeekOverlayPopup.tsx +++ b/app/client/src/components/editorComponents/CodeEditor/PeekOverlayPopup/PeekOverlayPopup.tsx @@ -157,6 +157,7 @@ export function PeekOverlayPopUpContent( > {(dataType === "object" || dataType === "array") && jsData !== null && ( e.stopPropagation()} > @@ -325,7 +325,7 @@ export function LogItem(props: LogItemProps) { if (typeof logDatum === "object") { return ( e.stopPropagation()} > @@ -334,7 +334,7 @@ export function LogItem(props: LogItemProps) { ); } else { return ( - + {`${logDatum} `} ); diff --git a/app/client/src/components/editorComponents/ReadOnlyEditor.tsx b/app/client/src/components/editorComponents/ReadOnlyEditor.tsx index de707a0923b..7817c6109fe 100644 --- a/app/client/src/components/editorComponents/ReadOnlyEditor.tsx +++ b/app/client/src/components/editorComponents/ReadOnlyEditor.tsx @@ -40,6 +40,7 @@ function ReadOnlyEditor(props: Props) { isReadOnly: true, isRawView: props.isRawView, border: CodeEditorBorder.NONE, + className: "mp-mask", }; return ; diff --git a/app/client/src/ee/components/BottomBar/GitActionsWrapper.tsx b/app/client/src/ee/components/BottomBar/GitActionsWrapper.tsx new file mode 100644 index 00000000000..8f45572b54e --- /dev/null +++ b/app/client/src/ee/components/BottomBar/GitActionsWrapper.tsx @@ -0,0 +1,3 @@ +export * from "ce/components/BottomBar/GitActionsWrapper"; +import { default as CE_GitActionsWrapper } from "ce/components/BottomBar/GitActionsWrapper"; +export default CE_GitActionsWrapper; diff --git a/app/client/src/git/ce/components/ContinuousDelivery/index.tsx b/app/client/src/git/ce/components/ContinuousDelivery/index.tsx index 90e2fd68c1a..0246dbc180c 100644 --- a/app/client/src/git/ce/components/ContinuousDelivery/index.tsx +++ b/app/client/src/git/ce/components/ContinuousDelivery/index.tsx @@ -1,8 +1,8 @@ import React from "react"; -import CDUnLicnesed from "./CDUnLicensed"; +import CDUnLicensed from "./CDUnLicensed"; function ContinuousDelivery() { - return ; + return ; } export default ContinuousDelivery; diff --git a/app/client/src/git/ce/components/DefaultBranch/index.tsx b/app/client/src/git/ce/components/DefaultBranch/index.tsx index 1c18109e64f..60235b9c0e0 100644 --- a/app/client/src/git/ce/components/DefaultBranch/index.tsx +++ b/app/client/src/git/ce/components/DefaultBranch/index.tsx @@ -1,9 +1,9 @@ import React from "react"; -import { useGitContext } from "git/components/GitContextProvider"; import DefaultBranchView from "./DefaultBranchView"; +import useBranches from "git/hooks/useBranches"; export default function DefaultBranch() { - const { branches } = useGitContext(); + const { branches } = useBranches(); return ( + diff --git a/app/client/src/git/components/BranchList/BranchListHotKeys.tsx b/app/client/src/git/components/BranchList/BranchListHotKeys.tsx new file mode 100644 index 00000000000..65055ebf326 --- /dev/null +++ b/app/client/src/git/components/BranchList/BranchListHotKeys.tsx @@ -0,0 +1,86 @@ +import React from "react"; +import { Hotkey, Hotkeys, HotkeysTarget } from "@blueprintjs/core"; + +interface Props { + handleUpKey: () => void; + handleDownKey: () => void; + handleSubmitKey: () => void; + handleEscKey: () => void; + children: React.ReactNode; +} + +@HotkeysTarget +class GlobalSearchHotKeys extends React.Component { + get hotKeysConfig() { + return [ + { + combo: "up", + onKeyDown: () => { + this.props.handleUpKey(); + }, + allowInInput: true, + group: "Branches", + label: "Move up the list", + }, + { + combo: "down", + onKeyDown: this.props.handleDownKey, + allowInInput: true, + group: "Branches", + label: "Move down the list", + }, + { + combo: "return", + onKeyDown: this.props.handleSubmitKey, + allowInInput: true, + group: "Branches", + label: "Submit", + }, + { + combo: "ESC", + onKeyDown: this.props.handleEscKey, + allowInInput: true, + group: "Branches", + label: "ESC", + }, + ]; + } + + renderHotkeys() { + return ( + + {this.hotKeysConfig.map( + ({ allowInInput, combo, group, label, onKeyDown }, index) => ( + + ), + )} + + ); + } + + render() { + return ( +
+ {this.props.children} +
+ ); + } +} + +export default GlobalSearchHotKeys; diff --git a/app/client/src/git/components/BranchList/BranchListItemContainer.tsx b/app/client/src/git/components/BranchList/BranchListItemContainer.tsx new file mode 100644 index 00000000000..510e834e7bb --- /dev/null +++ b/app/client/src/git/components/BranchList/BranchListItemContainer.tsx @@ -0,0 +1,37 @@ +import styled from "styled-components"; + +const BranchListItemContainer = styled.div<{ + isSelected?: boolean; + isActive?: boolean; + isDefault?: boolean; +}>` + padding: ${(props) => `${props.theme.spaces[4]}px`}; + margin: ${(props) => `${props.theme.spaces[1]}px 0`}; + color: var(--ads-v2-color-fg-emphasis); + cursor: pointer; + width: 100%; + height: 36px; + border-radius: var(--ads-v2-border-radius); + background-color: ${(props) => + props.isSelected || props.isActive ? "var(--ads-v2-color-bg-muted)" : ""}; + ${(props) => + !props.isActive && + `&:hover { + background-color: var(--ads-v2-color-bg-subtle); + }`} + + display: flex; + align-items: center; + + .branch-list-item-text { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + display: flex; + align-items: center; + gap: 4px; + flex: 1; + } +`; + +export default BranchListItemContainer; diff --git a/app/client/src/git/components/BranchList/BranchListView.tsx b/app/client/src/git/components/BranchList/BranchListView.tsx new file mode 100644 index 00000000000..53064528888 --- /dev/null +++ b/app/client/src/git/components/BranchList/BranchListView.tsx @@ -0,0 +1,427 @@ +import React, { useCallback, useEffect, useMemo, useState } from "react"; +import { getTypographyByKey } from "@appsmith/ads-old"; +import styled, { useTheme } from "styled-components"; +import Skeleton from "components/utils/Skeleton"; +import scrollIntoView from "scroll-into-view-if-needed"; +import BranchListHotkeys from "./BranchListHotKeys"; +import { + createMessage, + FIND_OR_CREATE_A_BRANCH, + SWITCH_BRANCHES, + SYNC_BRANCHES, +} from "ee/constants/messages"; +import { + Icon, + Spinner, + Tooltip, + Button, + SearchInput, + Text, +} from "@appsmith/ads"; +import get from "lodash/get"; +import noop from "lodash/noop"; +import { + isLocalBranch, + isRemoteBranch, + removeSpecialChars, +} from "pages/Editor/gitSync/utils"; +import AnalyticsUtil from "ee/utils/AnalyticsUtil"; +import RemoteBranchList from "./RemoteBranchList"; +import type { Theme } from "constants/DefaultTheme"; +import BranchListItemContainer from "./BranchListItemContainer"; +import LocalBranchList from "./LocalBranchList"; +import { useFilteredBranches } from "./hooks/useFilteredBranches"; +import useActiveHoverIndex from "./hooks/useActiveHoverIndex"; +import { Space } from "pages/Editor/gitSync/components/StyledComponents"; +import type { FetchBranchesResponseData } from "git/requests/fetchBranchesRequest.types"; +import type { FetchProtectedBranchesResponseData } from "git/requests/fetchProtectedBranchesRequest.types"; + +const ListContainer = styled.div` + flex: 1; + overflow: auto; + width: calc(300px + 5px); + margin-right: -5px; + position: relative; +`; + +const BranchDropdownContainer = styled.div` + height: 45vh; + display: flex; + flex-direction: column; + + padding: ${(props) => props.theme.spaces[5]}px; + min-height: 0; +`; + +// used for skeletons +const textInputHeight = 38; +const textHeight = 18; + +const CreateNewBranchContainer = styled.div` + display: -webkit-box; + -webkit-line-clamp: 3; + -webkit-box-orient: vertical; + overflow: hidden; + margin-right: 4px; + + & div { + margin-left: ${(props) => props.theme.spaces[4]}px; + display: block; + word-break: break-all; + } + + & .large-text { + ${getTypographyByKey("p1")}; + color: var(--ads-v2-color-fg); + } + + & .small-text { + ${getTypographyByKey("p3")}; + color: var(--ads-v2-color-fg-muted); + } +`; + +const SpinnerContainer = styled.div<{ isCreateBranchLoading: boolean }>` + align-self: center; + width: 12px; + visibility: ${(props) => + props.isCreateBranchLoading ? "visible" : "hidden"}; +`; + +interface CreateNewBranchProps { + branch: string; + className: string; + currentBranch: string | null; + hovered: boolean; + isCreateBranchLoading: boolean; + onClick: () => void; + shouldScrollIntoView: boolean; +} + +function CreateNewBranch({ + branch, + className, + currentBranch, + hovered, + isCreateBranchLoading, + onClick, + shouldScrollIntoView, +}: CreateNewBranchProps) { + useEffect( + function onInitEffect() { + if (itemRef.current && shouldScrollIntoView) + scrollIntoView(itemRef.current, { + scrollMode: "if-needed", + block: "nearest", + inline: "nearest", + }); + }, + [shouldScrollIntoView], + ); + const itemRef = React.useRef(null); + const theme = useTheme() as Theme; + + return ( +
+
+ + +
{`Create branch: ${branch} `}
+
{`from '${currentBranch}'`}
+
+
+ + + + +
+ ); +} + +export function LoadingRow() { + return ( + +
+ +
+
+ ); +} + +export function BranchesLoading() { + return ( + <> + + + + + ); +} + +interface BranchListHeaderProps { + onClickClose: () => void; + onClickRefresh: () => void; +} + +export function Header({ + onClickClose = noop, + onClickRefresh = noop, +}: BranchListHeaderProps) { + const title = createMessage(SWITCH_BRANCHES); + const theme = useTheme() as Theme; + + return ( +
+
+ + {title} + + + +
+
+ ); +} + +interface BranchListViewProps { + branches: FetchBranchesResponseData | null; + checkoutBranch: (branch: string) => void; + checkoutDestBranch: string | null; + createBranch: (branch: string) => void; + currentBranch: string | null; + defaultBranch: string | null; + deleteBranch: (branch: string) => void; + fetchBranches: () => void; + fetchProtectedBranches: () => void; + isCreateBranchLoading: boolean; + isCheckoutBranchLoading: boolean; + isFetchBranchesLoading: boolean; + isFetchProtectedBranchesLoading: boolean; + protectedBranches: FetchProtectedBranchesResponseData | null; + toggleBranchPopup: (isOpen: boolean) => void; +} + +export default function BranchListView({ + branches = null, + checkoutBranch = noop, + checkoutDestBranch = null, + createBranch = noop, + currentBranch = null, + defaultBranch = null, + deleteBranch = noop, + fetchBranches = noop, + fetchProtectedBranches = noop, + isCheckoutBranchLoading = false, + isCreateBranchLoading = false, + isFetchBranchesLoading = false, + isFetchProtectedBranchesLoading = false, + protectedBranches = null, + toggleBranchPopup = noop, +}: BranchListViewProps) { + const [searchText, changeSearchTextInState] = useState(""); + const changeSearchText = useCallback((text: string) => { + changeSearchTextInState(removeSpecialChars(text)); + }, []); + const branchNames = useMemo( + () => branches?.map((branch) => branch.branchName), + [branches], + ); + + const isCreateNewBranchInputValid = useMemo( + () => + !!( + searchText && + branchNames && + !branchNames.find((branch: string) => branch === searchText) + ), + [searchText, branchNames], + ); + + const filteredBranches = useFilteredBranches(branches ?? [], searchText); + + const localBranches = filteredBranches.filter((b: string) => + isLocalBranch(b), + ); + const remoteBranches = filteredBranches.filter((b: string) => + isRemoteBranch(b), + ); + const { activeHoverIndex, setActiveHoverIndex } = useActiveHoverIndex( + currentBranch ?? "", + filteredBranches, + isCreateNewBranchInputValid, + ); + + const handleClickOnRefresh = useCallback(() => { + AnalyticsUtil.logEvent("GS_SYNC_BRANCHES", { + source: "BRANCH_LIST_POPUP_FROM_BOTTOM_BAR", + }); + fetchBranches(); + fetchProtectedBranches(); + }, [fetchBranches, fetchProtectedBranches]); + + const handleCreateNewBranch = useCallback(() => { + if (isCreateBranchLoading) return; + + AnalyticsUtil.logEvent("GS_CREATE_NEW_BRANCH", { + source: "BRANCH_LIST_POPUP_FROM_BOTTOM_BAR", + }); + const branch = searchText; + + createBranch(branch); + }, [createBranch, isCreateBranchLoading, searchText]); + + const handleUpKey = useCallback( + () => setActiveHoverIndex(activeHoverIndex - 1), + [activeHoverIndex, setActiveHoverIndex], + ); + + const handleDownKey = useCallback( + () => setActiveHoverIndex(activeHoverIndex + 1), + [activeHoverIndex, setActiveHoverIndex], + ); + + const handleSubmitKey = useCallback(() => { + if (isCreateNewBranchInputValid) { + handleCreateNewBranch(); + } else { + checkoutBranch(filteredBranches[activeHoverIndex]); + AnalyticsUtil.logEvent("GS_SWITCH_BRANCH", { + source: "BRANCH_LIST_POPUP_FROM_BOTTOM_BAR", + }); + } + }, [ + activeHoverIndex, + filteredBranches, + handleCreateNewBranch, + isCreateNewBranchInputValid, + checkoutBranch, + ]); + + const handleEscKey = useCallback(() => { + toggleBranchPopup(false); + }, [toggleBranchPopup]); + + const handleClickOnClose = useCallback(() => { + toggleBranchPopup(false); + }, [toggleBranchPopup]); + + const isLoading = isFetchBranchesLoading || isFetchProtectedBranchesLoading; + + return ( + + +
+ +
+ {isLoading && ( +
+ +
+ )} + {!isLoading && ( + + )} +
+ + + {isLoading && } + {!isLoading && ( + + + {isCreateNewBranchInputValid && ( + + )} + + + + + )} + + + ); +} diff --git a/app/client/src/git/components/BranchList/BranchMoreMenu.tsx b/app/client/src/git/components/BranchList/BranchMoreMenu.tsx new file mode 100644 index 00000000000..d035549526a --- /dev/null +++ b/app/client/src/git/components/BranchList/BranchMoreMenu.tsx @@ -0,0 +1,132 @@ +import React, { useCallback } from "react"; +import AnalyticsUtil from "ee/utils/AnalyticsUtil"; +import { + createMessage, + DELETE, + DELETE_BRANCH_WARNING_CHECKED_OUT, + DELETE_BRANCH_WARNING_DEFAULT, +} from "ee/constants/messages"; +import { + Button, + Menu, + MenuContent, + MenuItem, + MenuTrigger, + toast, +} from "@appsmith/ads"; +import noop from "lodash/noop"; + +interface DeleteButtonProps { + branch: string | null; + currentBranch: string | null; + defaultBranch: string | null; + deleteBranch: (branch: string) => void; +} + +function DeleteButton({ + branch = null, + currentBranch = null, + defaultBranch = null, + deleteBranch = noop, +}: DeleteButtonProps) { + const saneDelete = useCallback(() => { + if (branch) { + if (defaultBranch === branch) { + toast.show(createMessage(DELETE_BRANCH_WARNING_DEFAULT, branch), { + kind: "error", + }); + } else if (currentBranch === branch) { + toast.show(createMessage(DELETE_BRANCH_WARNING_CHECKED_OUT, branch), { + kind: "error", + }); + } else { + deleteBranch(branch); + } + } + }, [branch, currentBranch, defaultBranch, deleteBranch]); + + const handleClick = useCallback( + (e) => { + e.stopPropagation(); + saneDelete(); + }, + [saneDelete], + ); + + return ( + + {createMessage(DELETE)} + + ); +} + +interface BranchMoreMenuProps { + branch: string | null; + currentBranch: string | null; + defaultBranch: string | null; + deleteBranch: (branch: string) => void; + open: boolean; + setOpen: (open: boolean) => void; +} + +export default function BranchMoreMenu({ + branch = null, + currentBranch = null, + defaultBranch = null, + deleteBranch = noop, + open, + setOpen, +}: BranchMoreMenuProps) { + const buttons = [ + , + ]; + + const handleMenuClose = useCallback(() => { + setOpen(false); + }, [setOpen]); + + const handleClickOnMenu = useCallback( + (e) => { + e.stopPropagation(); + setOpen(true); + AnalyticsUtil.logEvent("GS_BRANCH_MORE_MENU_OPEN", { + source: "GS_OPEN_BRANCH_LIST_POPUP", + }); + }, + [setOpen], + ); + + return ( + + + + ); +} diff --git a/app/client/src/git/components/BranchList/LocalBranchList.tsx b/app/client/src/git/components/BranchList/LocalBranchList.tsx new file mode 100644 index 00000000000..7fa293b236e --- /dev/null +++ b/app/client/src/git/components/BranchList/LocalBranchList.tsx @@ -0,0 +1,75 @@ +import LocalBranchListItem from "./LocalBranchListItem"; +import React from "react"; +import { createMessage, LOCAL_BRANCHES } from "ee/constants/messages"; +import { Text } from "@appsmith/ads"; +import type { FetchProtectedBranchesResponseData } from "git/requests/fetchProtectedBranchesRequest.types"; +import noop from "lodash/noop"; +import styled from "styled-components"; + +const Heading = styled(Text)` + font-weight: 600; +`; + +interface LocalBranchListProps { + activeHoverIndex: number; + checkoutBranch: (branch: string) => void; + checkoutDestBranch: string | null; + currentBranch: string | null; + defaultBranch: string | null; + deleteBranch: (branch: string) => void; + isCreateNewBranchInputValid: boolean; + isCheckoutBranchLoading: boolean; + localBranches: string[]; + protectedBranches: FetchProtectedBranchesResponseData | null; +} + +export default function LocalBranchList({ + activeHoverIndex = 0, + checkoutBranch = noop, + checkoutDestBranch = null, + currentBranch = null, + defaultBranch = null, + deleteBranch = noop, + isCheckoutBranchLoading = false, + isCreateNewBranchInputValid = false, + localBranches = [], + protectedBranches = null, +}: LocalBranchListProps) { + return ( +
+ {localBranches?.length > 0 && ( + + {createMessage(LOCAL_BRANCHES)} + + )} + {localBranches.map((branch: string, index: number) => { + const isActive = + (isCreateNewBranchInputValid + ? activeHoverIndex - 1 + : activeHoverIndex) === index; + + return ( + + ); + })} +
+ ); +} diff --git a/app/client/src/git/components/BranchList/LocalBranchListItem.tsx b/app/client/src/git/components/BranchList/LocalBranchListItem.tsx new file mode 100644 index 00000000000..c1bcd093793 --- /dev/null +++ b/app/client/src/git/components/BranchList/LocalBranchListItem.tsx @@ -0,0 +1,135 @@ +import React, { useCallback, useEffect } from "react"; +import scrollIntoView from "scroll-into-view-if-needed"; +import BranchListItemContainer from "./BranchListItemContainer"; +import useHover from "./hooks/useHover"; +import BranchMoreMenu from "./BranchMoreMenu"; +import { Tooltip, Text, Spinner, Tag, Icon } from "@appsmith/ads"; +import { isEllipsisActive } from "utils/helpers"; +import styled from "styled-components"; +import noop from "lodash/noop"; +import AnalyticsUtil from "ee/utils/AnalyticsUtil"; + +const StyledIcon = styled(Icon)` + margin-right: 8px; + width: 14px; + height: 14px; + margin-top: 1px; +`; + +const OptionsContainer = styled.div` + display: flex; + align-items: center; + justify-content: flex-end; + height: 100%; +`; + +const BranchText = styled(Text)` + width: 100%; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +`; + +interface LocalBranchListItemProps { + branch: string; + checkoutBranch: (branch: string) => void; + checkoutDestBranch: string | null; + className?: string; + currentBranch: string | null; + defaultBranch: string | null; + deleteBranch: (branch: string) => void; + isActive: boolean; + isCheckoutBranchLoading: boolean; + isDefault: boolean; + isProtected: boolean; + isSelected: boolean; + shouldScrollIntoView: boolean; +} + +export default function LocalBranchListItem({ + branch, + checkoutBranch = noop, + checkoutDestBranch = null, + className, + currentBranch = null, + defaultBranch = null, + deleteBranch = noop, + isActive = false, + isCheckoutBranchLoading = false, + isDefault = false, + isProtected = false, + isSelected = false, + shouldScrollIntoView = false, +}: LocalBranchListItemProps) { + const itemRef = React.useRef(null); + const [hover] = useHover(itemRef); + const textRef = React.useRef(null); + const [isMoreMenuOpen, setIsMoreMenuOpen] = React.useState(false); + + useEffect( + function scrollIntoViewOnInitEffect() { + if (itemRef.current && shouldScrollIntoView) { + scrollIntoView(itemRef.current, { + scrollMode: "if-needed", + block: "nearest", + inline: "nearest", + }); + } + }, + [shouldScrollIntoView], + ); + + const handleClickOnBranch = useCallback(() => { + checkoutBranch(branch); + AnalyticsUtil.logEvent("GS_SWITCH_BRANCH", { + source: "BRANCH_LIST_POPUP_FROM_BOTTOM_BAR", + }); + }, [branch, checkoutBranch]); + + return ( + + {isProtected && } + + + + {branch} + + {isDefault && ( + + Default + + )} + + + + {checkoutDestBranch === branch && isCheckoutBranchLoading && ( + + )} + {(hover || isMoreMenuOpen) && ( + + )} + + + ); +} diff --git a/app/client/src/git/components/BranchList/RemoteBranchList.tsx b/app/client/src/git/components/BranchList/RemoteBranchList.tsx new file mode 100644 index 00000000000..1d8b7ab865b --- /dev/null +++ b/app/client/src/git/components/BranchList/RemoteBranchList.tsx @@ -0,0 +1,47 @@ +import RemoteBranchListItem from "./RemoteBranchListItem"; +import React from "react"; +import { createMessage, REMOTE_BRANCHES } from "ee/constants/messages"; +import { Text } from "@appsmith/ads"; +import styled from "styled-components"; +import noop from "lodash/noop"; + +const Heading = styled(Text)` + font-weight: 600; +`; + +interface RemoteBranchListProps { + remoteBranches: string[]; + checkoutBranch: (branch: string) => void; + checkoutDestBranch: string | null; + isCheckoutBranchLoading: boolean; +} + +export default function RemoteBranchList({ + checkoutBranch = noop, + checkoutDestBranch = null, + isCheckoutBranchLoading = false, + remoteBranches = [], +}: RemoteBranchListProps) { + return ( +
+ {remoteBranches?.length > 0 && ( + + {createMessage(REMOTE_BRANCHES)} + + )} + {remoteBranches.map((branch: string) => ( + + ))} +
+ ); +} diff --git a/app/client/src/git/components/BranchList/RemoteBranchListItem.tsx b/app/client/src/git/components/BranchList/RemoteBranchListItem.tsx new file mode 100644 index 00000000000..10546a7b97a --- /dev/null +++ b/app/client/src/git/components/BranchList/RemoteBranchListItem.tsx @@ -0,0 +1,74 @@ +import React, { useCallback } from "react"; +import { Spinner, Tooltip } from "@appsmith/ads"; +import { isEllipsisActive } from "utils/helpers"; +import { Text, TextType } from "@appsmith/ads-old"; +import BranchListItemContainer from "./BranchListItemContainer"; +import styled from "styled-components"; +import AnalyticsUtil from "ee/utils/AnalyticsUtil"; +import noop from "lodash/noop"; + +const OptionsContainer = styled.div` + display: flex; + align-items: center; + justify-content: flex-end; + height: 100%; +`; + +const BranchText = styled(Text)` + width: 100%; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +`; + +interface RemoteBranchListItemProps { + branch: string; + checkoutBranch: (branch: string) => void; + checkoutDestBranch: string | null; + className?: string; + isCheckoutBranchLoading: boolean; +} + +export default function RemoteBranchListItem({ + branch, + checkoutBranch = noop, + checkoutDestBranch = null, + className, + isCheckoutBranchLoading = false, +}: RemoteBranchListItemProps) { + const textRef = React.useRef(null); + + const handleClickOnBranch = useCallback(() => { + checkoutBranch(branch); + AnalyticsUtil.logEvent("GS_SWITCH_BRANCH", { + source: "BRANCH_LIST_POPUP_FROM_BOTTOM_BAR", + }); + }, [branch, checkoutBranch]); + + return ( + + + + {branch} + + + + {checkoutDestBranch === branch && isCheckoutBranchLoading && ( + + )} + + + ); +} diff --git a/app/client/src/git/components/BranchList/hooks/useActiveHoverIndex.ts b/app/client/src/git/components/BranchList/hooks/useActiveHoverIndex.ts new file mode 100644 index 00000000000..96244af0dab --- /dev/null +++ b/app/client/src/git/components/BranchList/hooks/useActiveHoverIndex.ts @@ -0,0 +1,43 @@ +import { useCallback, useEffect, useState } from "react"; + +export default function useActiveHoverIndex( + currentBranch: string | undefined, + filteredBranches: Array, + isCreateNewBranchInputValid: boolean, +) { + const effectiveLength = isCreateNewBranchInputValid + ? filteredBranches.length + : filteredBranches.length - 1; + + const [activeHoverIndex, setActiveHoverIndexInState] = useState(0); + const setActiveHoverIndex = useCallback( + (index: number) => { + if (index < 0) setActiveHoverIndexInState(effectiveLength); + else if (index > effectiveLength) setActiveHoverIndexInState(0); + else setActiveHoverIndexInState(index); + }, + [effectiveLength], + ); + + useEffect( + function activeHoverIndexEffect() { + const activeBranchIdx = filteredBranches.indexOf(currentBranch || ""); + + if (activeBranchIdx !== -1) { + setActiveHoverIndex( + isCreateNewBranchInputValid ? activeBranchIdx + 1 : activeBranchIdx, + ); + } else { + setActiveHoverIndex(0); + } + }, + [ + currentBranch, + filteredBranches, + isCreateNewBranchInputValid, + setActiveHoverIndex, + ], + ); + + return { activeHoverIndex, setActiveHoverIndex }; +} diff --git a/app/client/src/git/components/BranchList/hooks/useFilteredBranches.ts b/app/client/src/git/components/BranchList/hooks/useFilteredBranches.ts new file mode 100644 index 00000000000..0674ad81bde --- /dev/null +++ b/app/client/src/git/components/BranchList/hooks/useFilteredBranches.ts @@ -0,0 +1,29 @@ +import type { Branch } from "entities/GitSync"; +import { useEffect, useState } from "react"; + +export function useFilteredBranches( + branches: Array, + searchText: string, +) { + const lowercaseSearchText = searchText.toLowerCase(); + const [filteredBranches, setFilteredBranches] = useState>([]); + + useEffect( + function setFilteredBranchesEffect() { + const matched = branches.filter((b: Branch) => + lowercaseSearchText + ? b.branchName.toLowerCase().includes(lowercaseSearchText) + : true, + ); + const branchNames = [ + ...matched.filter((b: Branch) => b.default), + ...matched.filter((b: Branch) => !b.default), + ].map((b: Branch) => b.branchName); + + setFilteredBranches(branchNames); + }, + [branches, lowercaseSearchText], + ); + + return filteredBranches; +} diff --git a/app/client/src/git/components/BranchList/hooks/useHover.ts b/app/client/src/git/components/BranchList/hooks/useHover.ts new file mode 100644 index 00000000000..bcd6475f152 --- /dev/null +++ b/app/client/src/git/components/BranchList/hooks/useHover.ts @@ -0,0 +1,24 @@ +import { useEffect, useState } from "react"; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export default function useHover(ref: any) { + const [hover, setHover] = useState(false); + const onMouseEnter = () => setHover(true); + const onMouseLeave = () => setHover(false); + + useEffect(function onInitEffect() { + const target = ref.current; + + if (target) { + target.addEventListener("mouseenter", onMouseEnter); + target.addEventListener("mouseleave", onMouseLeave); + + return () => { + target.removeEventListener("mouseenter", onMouseEnter); + target.removeEventListener("mouseleave", onMouseLeave); + }; + } + }); + + return [hover]; +} diff --git a/app/client/src/git/components/BranchList/index.tsx b/app/client/src/git/components/BranchList/index.tsx new file mode 100644 index 00000000000..ee81302ee09 --- /dev/null +++ b/app/client/src/git/components/BranchList/index.tsx @@ -0,0 +1,49 @@ +import React from "react"; +import BranchListView from "./BranchListView"; +import useBranches from "git/hooks/useBranches"; +import useDefaultBranch from "git/ee/hooks/useDefaultBranch"; +import useProtectedBranches from "git/hooks/useProtectedBranches"; + +function BranchList() { + const { + branches, + checkoutBranch, + checkoutDestBranch, + createBranch, + currentBranch, + deleteBranch, + fetchBranches, + isCheckoutBranchLoading, + isCreateBranchLoading, + isFetchBranchesLoading, + toggleBranchPopup, + } = useBranches(); + const { defaultBranch } = useDefaultBranch(); + const { + fetchProtectedBranches, + isFetchProtectedBranchesLoading, + protectedBranches, + } = useProtectedBranches(); + + return ( + + ); +} + +export default BranchList; diff --git a/app/client/src/git/components/ConflictErrorModal/index.tsx b/app/client/src/git/components/ConflictErrorModal/index.tsx index 0de96380c6d..db956883603 100644 --- a/app/client/src/git/components/ConflictErrorModal/index.tsx +++ b/app/client/src/git/components/ConflictErrorModal/index.tsx @@ -1,9 +1,9 @@ import React from "react"; import ConflictErrorModalView from "./ConflictErrorModalView"; -import { useGitContext } from "../GitContextProvider"; +import useOps from "git/hooks/useOps"; export default function ConflictErrorModal() { - const { conflictErrorModalOpen, toggleConflictErrorModal } = useGitContext(); + const { conflictErrorModalOpen, toggleConflictErrorModal } = useOps(); return ( { @@ -44,25 +45,27 @@ describe("AddDeployKey Component", () => { ).toBeInTheDocument(); expect(screen.getByRole("combobox")).toBeInTheDocument(); // Should show ECDSA by default since sshKeyPair includes "ecdsa" - expect(screen.getByText(defaultProps.sshKeyPair)).toBeInTheDocument(); + 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 fetchSSHKeyPair if modal is open and not importing", () => { + it("calls fetchSSHKey if modal is open and not importing", () => { render(); - expect(defaultProps.fetchSSHKeyPair).toHaveBeenCalledTimes(1); + expect(defaultProps.fetchSSHKey).toHaveBeenCalledTimes(1); }); - it("does not call fetchSSHKeyPair if importing", () => { + it("does not call fetchSSHKey if importing", () => { render(); - expect(defaultProps.fetchSSHKeyPair).not.toHaveBeenCalled(); + 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(); @@ -75,7 +78,7 @@ describe("AddDeployKey Component", () => { , ); @@ -85,46 +88,32 @@ describe("AddDeployKey Component", () => { fireEvent.click(rsaOption); await waitFor(() => { - expect(generateSSHKey).toHaveBeenCalledWith("RSA", expect.any(Object)); + 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 errorData = { - data: {}, - responseMeta: { - success: false, - status: 503, - error: { - code: "GENERIC-ERROR", - errorType: "Some Error", - message: "Something went wrong", - }, - }, + const connectError = { + code: "GENERIC-ERROR", + errorType: "Some Error", + message: "Something went wrong", }; - render(); + 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 errorData = { - data: {}, - responseMeta: { - success: false, - status: 503, - error: { - code: "AE-GIT-4032", - errorType: "SSH Key Error", - message: "SSH Key misconfiguration", - }, - }, + const connectError = { + code: "AE-GIT-4032", + errorType: "SSH Key Error", + message: "SSH Key misconfiguration", }; - render(); + render(); expect(screen.getByText("SSH key misconfiguration")).toBeInTheDocument(); expect( screen.getByText( @@ -154,7 +143,7 @@ describe("AddDeployKey Component", () => { }); it("hides copy button when connectLoading is true", () => { - render(); + render(); expect(screen.queryByTestId("t--copy-generic")).not.toBeInTheDocument(); }); @@ -172,6 +161,7 @@ describe("AddDeployKey Component", () => { render( , ); @@ -217,54 +207,25 @@ describe("AddDeployKey Component", () => { expect(docsLink).toHaveAttribute("href", DEFAULT_DOCS_URL); }); - it("uses custom documentation link if provided", () => { - render( - , - ); - const docsLink = screen.getByRole("link", { name: "Read Docs" }); - - expect(docsLink).toHaveAttribute("href", "https://custom-docs.com"); - }); - - it("does not generate SSH key if modal is closed", () => { - const generateSSHKey = jest.fn(); - - render( - , - ); - // Should not call generateSSHKey since modal is not open - expect(generateSSHKey).not.toHaveBeenCalled(); - }); - it("generates SSH key if none is present and conditions are met", async () => { - const fetchSSHKeyPair = jest.fn((props) => { - props.onSuccessCallback && props.onSuccessCallback(); - }); + const fetchSSHKey = jest.fn(); const generateSSHKey = jest.fn(); render( , ); - expect(fetchSSHKeyPair).toHaveBeenCalledTimes(1); + expect(fetchSSHKey).toHaveBeenCalledTimes(1); await waitFor(() => { - expect(generateSSHKey).toHaveBeenCalledWith("ECDSA", expect.any(Object)); + expect(generateSSHKey).toHaveBeenCalledWith("ECDSA", false); }); }); }); diff --git a/app/client/src/git/components/ConnectModal/AddDeployKey.tsx b/app/client/src/git/components/ConnectModal/ConnectInitialize/AddDeployKey.tsx similarity index 72% rename from app/client/src/git/components/ConnectModal/AddDeployKey.tsx rename to app/client/src/git/components/ConnectModal/ConnectInitialize/AddDeployKey.tsx index fdce026b034..75a4a7a50e8 100644 --- a/app/client/src/git/components/ConnectModal/AddDeployKey.tsx +++ b/app/client/src/git/components/ConnectModal/ConnectInitialize/AddDeployKey.tsx @@ -19,7 +19,6 @@ import { Option, Select, Text, - toast, } from "@appsmith/ads"; import styled from "styled-components"; import AnalyticsUtil from "ee/utils/AnalyticsUtil"; @@ -36,8 +35,9 @@ import { import type { GitProvider } from "./ChooseGitProvider"; import { GIT_DEMO_GIF } from "./constants"; import noop from "lodash/noop"; -import type { ApiResponse } from "api/ApiResponses"; import CopyButton from "./CopyButton"; +import type { GitApiError } from "git/store/types"; +import type { ConnectFormDataState } from "./types"; export const DeployedKeyContainer = styled.div` height: 36px; @@ -131,66 +131,52 @@ const getRepositorySettingsUrl = ( } }; -const DEFAULT_DOCS_URL = +const DEPLOY_DOCS_URL = "https://docs.appsmith.com/advanced-concepts/version-control-with-git/connecting-to-git-repository"; -interface AddDeployKeyState { - gitProvider?: GitProvider; - isAddedDeployKey: boolean; - remoteUrl: string; -} - -interface Callback { - onSuccessCallback?: () => void; - onErrorCallback?: () => void; -} - -export interface FetchSSHKeyPairProps extends Callback {} - export interface AddDeployKeyProps { - isModalOpen: boolean; - onChange: (args: Partial) => void; - value: Partial; + connectError: GitApiError | null; + fetchSSHKey: () => void; + generateSSHKey: (keyType: string, isImport?: boolean) => void; + isFetchSSHKeyLoading: boolean; + isGenerateSSHKeyLoading: boolean; isImport?: boolean; - errorData?: ApiResponse; - connectLoading?: boolean; - deployKeyDocUrl?: string; - isFetchingSSHKeyPair: boolean; - fetchSSHKeyPair: (props: FetchSSHKeyPairProps) => void; - generateSSHKey: (keyType: string, callback: Callback) => void; - isGeneratingSSHKey: boolean; - sshKeyPair: string; + isLoading: boolean; + onChange: (args: Partial) => void; + sshPublicKey: string | null; + value: Partial | null; } function AddDeployKey({ - connectLoading = false, - deployKeyDocUrl, - errorData, - fetchSSHKeyPair, - generateSSHKey, - isFetchingSSHKeyPair, - isGeneratingSSHKey, + connectError = null, + fetchSSHKey = noop, + generateSSHKey = noop, + isFetchSSHKeyLoading = false, + isGenerateSSHKeyLoading = false, isImport = false, - isModalOpen, + isLoading = false, onChange = noop, - sshKeyPair, - value = {}, + sshPublicKey = null, + value = null, }: AddDeployKeyProps) { const [fetched, setFetched] = useState(false); const [sshKeyType, setSshKeyType] = useState(); useEffect( - function fetchKeyPair() { - if (isModalOpen && !isImport) { + function fetchKeyPairOnInitEffect() { + if (!isImport) { if (!fetched) { - fetchSSHKeyPair({ - onSuccessCallback: () => { - setFetched(true); - }, - onErrorCallback: () => { - setFetched(true); - }, - }); + fetchSSHKey(); + setFetched(true); + // doesn't support callback anymore + // fetchSSHKey({ + // onSuccessCallback: () => { + // setFetched(true); + // }, + // onErrorCallback: () => { + // setFetched(true); + // }, + // }); } } else { if (!fetched) { @@ -198,16 +184,16 @@ function AddDeployKey({ } } }, - [isImport, isModalOpen, fetched, fetchSSHKeyPair], + [isImport, fetched, fetchSSHKey], ); useEffect( - function setKeyType() { - if (isModalOpen && fetched && !isFetchingSSHKeyPair) { - if (sshKeyPair && sshKeyPair.includes("rsa")) { + function setSSHKeyTypeonInitEffect() { + if (fetched && !isFetchSSHKeyLoading) { + if (sshPublicKey && sshPublicKey.includes("rsa")) { setSshKeyType("RSA"); } else if ( - !sshKeyPair && + !sshPublicKey && value?.remoteUrl && value.remoteUrl.toString().toLocaleLowerCase().includes("azure") ) { @@ -217,24 +203,25 @@ function AddDeployKey({ } } }, - [isModalOpen, fetched, sshKeyPair, isFetchingSSHKeyPair, value.remoteUrl], + [fetched, sshPublicKey, isFetchSSHKeyLoading, value?.remoteUrl], ); useEffect( - function generateSSH() { + function generateSSHOnInitEffect() { if ( - isModalOpen && - ((sshKeyType && !sshKeyPair) || - (sshKeyType && !sshKeyPair?.includes(sshKeyType.toLowerCase()))) + (sshKeyType && !sshPublicKey) || + (sshKeyType && !sshPublicKey?.includes(sshKeyType.toLowerCase())) ) { - generateSSHKey(sshKeyType, { - onSuccessCallback: () => { - toast.show("SSH Key generated successfully", { kind: "success" }); - }, - }); + generateSSHKey(sshKeyType, isImport); + // doesn't support callback anymore + // generateSSHKey(sshKeyType, { + // onSuccessCallback: () => { + // toast.show("SSH Key generated successfully", { kind: "success" }); + // }, + // }); } }, - [sshKeyType, sshKeyPair, isModalOpen, generateSSHKey], + [sshKeyType, sshPublicKey, generateSSHKey, isImport], ); const repositorySettingsUrl = getRepositorySettingsUrl( @@ -242,13 +229,13 @@ function AddDeployKey({ value?.remoteUrl, ); - const loading = isFetchingSSHKeyPair || isGeneratingSSHKey; + const loading = isFetchSSHKeyLoading || isGenerateSSHKeyLoading; const onCopy = useCallback(() => { AnalyticsUtil.logEvent("GS_COPY_SSH_KEY_BUTTON_CLICK"); }, []); - const onDeployKeyAddedCheckChange = useCallback( + const handleAddedKeyCheck = useCallback( (isAddedDeployKey: boolean) => { onChange({ isAddedDeployKey }); }, @@ -257,19 +244,19 @@ function AddDeployKey({ return ( <> - {errorData && - errorData?.responseMeta?.error?.code !== "AE-GIT-4033" && - errorData?.responseMeta?.error?.code !== "AE-GIT-4032" && ( + {connectError && + connectError.code !== "AE-GIT-4033" && + connectError.code !== "AE-GIT-4032" && ( - {errorData?.responseMeta?.error?.errorType} + {connectError.errorType} - {errorData?.responseMeta?.error?.message} + {connectError.message} )} {/* hardcoding message because server doesn't support feature flag. Will change this later */} - {errorData && errorData?.responseMeta?.error?.code === "AE-GIT-4032" && ( + {connectError && connectError.code === "AE-GIT-4032" && ( {createMessage(ERROR_SSH_KEY_MISCONF_TITLE)} @@ -286,7 +273,7 @@ function AddDeployKey({ {createMessage(ADD_DEPLOY_KEY_STEP_TITLE)} + )} + {possibleSteps.includes(activeStep) && + currentIndex > 0 && + !isLoading && ( + + )} + + + ); +} + +export default ConnectInitialize; diff --git a/app/client/src/git/components/ConnectModal/ConnectInitialize/types.ts b/app/client/src/git/components/ConnectModal/ConnectInitialize/types.ts new file mode 100644 index 00000000000..024375064f3 --- /dev/null +++ b/app/client/src/git/components/ConnectModal/ConnectInitialize/types.ts @@ -0,0 +1,10 @@ +import type { GitProvider } from "./ChooseGitProvider"; + +export interface ConnectFormDataState { + gitProvider?: GitProvider; + gitEmptyRepoExists?: string; + gitExistingRepoExists?: boolean; + remoteUrl?: string; + isAddedDeployKey?: boolean; + sshKeyType?: "RSA" | "ECDSA"; +} diff --git a/app/client/src/git/components/ConnectModal/ConnectModalView.tsx b/app/client/src/git/components/ConnectModal/ConnectModalView.tsx new file mode 100644 index 00000000000..0146a5cf923 --- /dev/null +++ b/app/client/src/git/components/ConnectModal/ConnectModalView.tsx @@ -0,0 +1,103 @@ +import { Modal, ModalContent } from "@appsmith/ads"; +import type { ConnectRequestParams } from "git/requests/connectRequest.types"; +import type { GitImportRequestParams } from "git/requests/gitImportRequest.types"; +import type { GitApiError } from "git/store/types"; +import React, { useCallback } from "react"; +import ConnectInitialize from "./ConnectInitialize"; +import ConnectSuccess from "./ConnectSuccess"; +import { noop } from "lodash"; +import type { GitSettingsTab } from "git/constants/enums"; +import styled from "styled-components"; + +const StyledModalContent = styled(ModalContent)` + &&& { + width: 640px; + transform: none !important; + top: 100px; + left: calc(50% - 320px); + max-height: calc(100vh - 200px); + } +`; + +interface ConnectModalViewProps { + artifactType: string; + connect: (params: ConnectRequestParams) => void; + connectError: GitApiError | null; + fetchSSHKey: () => void; + generateSSHKey: (keyType: string) => void; + gitImport: (params: GitImportRequestParams) => void; + isConnectLoading: boolean; + isConnectModalOpen: boolean; + isFetchSSHKeyLoading: boolean; + isGenerateSSHKeyLoading: boolean; + isGitImportLoading: boolean; + isImport: boolean; + resetFetchSSHKey: () => void; + resetGenerateSSHKey: () => void; + sshPublicKey: string | null; + toggleConnectModal: (open: boolean) => void; + isGitConnected: boolean; + remoteUrl: string | null; + toggleSettingsModal: ( + open: boolean, + tab?: keyof typeof GitSettingsTab, + ) => void; + defaultBranch: string | null; + repoName: string | null; + setImportWorkspaceId: () => void; + isCreateArtifactPermitted: boolean; +} + +function ConnectModalView({ + defaultBranch = null, + isConnectModalOpen = false, + isGitConnected = false, + remoteUrl = null, + repoName = null, + resetFetchSSHKey = noop, + resetGenerateSSHKey = noop, + toggleConnectModal = noop, + toggleSettingsModal = noop, + ...rest +}: ConnectModalViewProps) { + const handleModalOpenChange = useCallback( + (open: boolean) => { + if (!open) { + resetFetchSSHKey(); + resetGenerateSSHKey(); + } + + toggleConnectModal(open); + }, + [resetFetchSSHKey, resetGenerateSSHKey, toggleConnectModal], + ); + + return ( + + + {isConnectModalOpen ? ( + // need fragment to arrange conditions properly + // eslint-disable-next-line react/jsx-no-useless-fragment + <> + {isGitConnected ? ( + + ) : ( + + )} + + ) : null} + + + ); +} + +export default ConnectModalView; diff --git a/app/client/src/git/components/ConnectModal/ConnectSuccess/index.tsx b/app/client/src/git/components/ConnectModal/ConnectSuccess/index.tsx new file mode 100644 index 00000000000..47f762b6bb5 --- /dev/null +++ b/app/client/src/git/components/ConnectModal/ConnectSuccess/index.tsx @@ -0,0 +1,178 @@ +import { + GIT_CONNECT_SUCCESS_PROTECTION_MSG, + GIT_CONNECT_SUCCESS_TITLE, + GIT_CONNECT_SUCCESS_ACTION_SETTINGS, + GIT_CONNECT_SUCCESS_ACTION_CONTINUE, + createMessage, + GIT_CONNECT_SUCCESS_PROTECTION_DOC_CTA, + GIT_CONNECT_SUCCESS_DEFAULT_BRANCH, + GIT_CONNECT_SUCCESS_REPO_NAME, + GIT_CONNECT_SUCCESS_DEFAULT_BRANCH_TOOLTIP, +} from "ee/constants/messages"; +import { + Button, + Icon, + ModalBody, + ModalFooter, + Text, + Link, + Tooltip, +} from "@appsmith/ads"; +import React, { useCallback } from "react"; +import styled from "styled-components"; +import AnalyticsUtil from "ee/utils/AnalyticsUtil"; +import { DOCS_BRANCH_PROTECTION_URL } from "constants/ThirdPartyConstants"; +import noop from "lodash/noop"; +import type { GitSettingsTab } from "git/constants/enums"; + +const TitleText = styled(Text)` + flex: 1; + font-weight: 600; +`; + +const LinkText = styled(Text)` + span { + font-weight: 500; + } +`; + +function ConnectionSuccessTitle() { + return ( +
+ + + {createMessage(GIT_CONNECT_SUCCESS_TITLE)} + +
+ ); +} + +interface ConnectSuccessModalViewProps { + repoName: string | null; + defaultBranch: string | null; +} + +function ConnectSuccessModalView({ + defaultBranch, + repoName, +}: ConnectSuccessModalViewProps) { + return ( + <> +
+
+
+ + + {createMessage(GIT_CONNECT_SUCCESS_REPO_NAME)} + +
+ {repoName || "-"} +
+
+
+ + + {createMessage(GIT_CONNECT_SUCCESS_DEFAULT_BRANCH)} + + + + +
+ {defaultBranch || "-"} +
+
+
+ + {createMessage(GIT_CONNECT_SUCCESS_PROTECTION_MSG)} + +
+ + + {createMessage(GIT_CONNECT_SUCCESS_PROTECTION_DOC_CTA)} + + + + ); +} + +interface ConnectSuccessProps { + defaultBranch: string | null; + remoteUrl: string | null; + repoName: string | null; + toggleConnectModal: (open: boolean) => void; + toggleSettingsModal: ( + open: boolean, + tab?: keyof typeof GitSettingsTab, + ) => void; +} + +function ConnectSuccess({ + defaultBranch, + remoteUrl = null, + repoName, + toggleConnectModal = noop, + toggleSettingsModal = noop, +}: ConnectSuccessProps) { + const handleStartGit = useCallback(() => { + toggleConnectModal(false); + AnalyticsUtil.logEvent("GS_START_USING_GIT", { + repoUrl: remoteUrl, + }); + }, [remoteUrl, toggleConnectModal]); + + const handleOpenSettings = useCallback(() => { + toggleConnectModal(false); + toggleSettingsModal(true); + AnalyticsUtil.logEvent("GS_OPEN_GIT_SETTINGS", { + repoUrl: remoteUrl, + }); + }, [remoteUrl, toggleConnectModal, toggleSettingsModal]); + + return ( + <> + + + + + + + + + + ); +} + +export default ConnectSuccess; diff --git a/app/client/src/git/components/ConnectModal/index.tsx b/app/client/src/git/components/ConnectModal/index.tsx index f7c8d097213..a8f268132d9 100644 --- a/app/client/src/git/components/ConnectModal/index.tsx +++ b/app/client/src/git/components/ConnectModal/index.tsx @@ -1,338 +1,68 @@ -import React, { useCallback, useState } from "react"; -import styled from "styled-components"; +import React from "react"; +import ConnectModalView from "./ConnectModalView"; +import { useGitContext } from "../GitContextProvider"; +import useConnect from "git/hooks/useConnect"; +import useMetadata from "git/hooks/useMetadata"; +import useSettings from "git/hooks/useSettings"; -import AddDeployKey, { type AddDeployKeyProps } from "./AddDeployKey"; -import AnalyticsUtil from "ee/utils/AnalyticsUtil"; -import ChooseGitProvider from "./ChooseGitProvider"; -import GenerateSSH from "./GenerateSSH"; -import Steps from "./Steps"; -import Statusbar from "../Statusbar"; -import { Button, ModalBody, ModalFooter } from "@appsmith/ads"; -import { GIT_CONNECT_STEPS } from "./constants"; -import type { GitProvider } from "./ChooseGitProvider"; -import { - ADD_DEPLOY_KEY_STEP, - CHOOSE_A_GIT_PROVIDER_STEP, - CONFIGURE_GIT, - CONNECT_GIT_TEXT, - GENERATE_SSH_KEY_STEP, - GIT_CONNECT_WAITING, - GIT_IMPORT_WAITING, - IMPORT_APP_CTA, - PREVIOUS_STEP, - createMessage, -} from "ee/constants/messages"; -import { isValidGitRemoteUrl } from "../utils"; -import type { ApiResponse } from "api/ApiResponses"; - -const OFFSET = 200; -const OUTER_PADDING = 32; -const FOOTER = 56; -const HEADER = 44; - -const StyledModalBody = styled(ModalBody)` - flex: 1; - overflow-y: initial; - display: flex; - flex-direction: column; - max-height: calc( - 100vh - ${OFFSET}px - ${OUTER_PADDING}px - ${FOOTER}px - ${HEADER}px - ); -`; - -const StyledModalFooter = styled(ModalFooter)` - justify-content: space-between; - flex-direction: ${(p) => (!p.loading ? "row-reverse" : "row")}; -`; - -const steps = [ - { - key: GIT_CONNECT_STEPS.CHOOSE_PROVIDER, - text: createMessage(CHOOSE_A_GIT_PROVIDER_STEP), - }, - { - key: GIT_CONNECT_STEPS.GENERATE_SSH_KEY, - text: createMessage(GENERATE_SSH_KEY_STEP), - }, - { - key: GIT_CONNECT_STEPS.ADD_DEPLOY_KEY, - text: createMessage(ADD_DEPLOY_KEY_STEP), - }, -]; - -const possibleSteps = steps.map((s) => s.key); - -interface StyledModalFooterProps { - loading?: boolean; -} - -interface FormDataState { - gitProvider?: GitProvider; - gitEmptyRepoExists?: string; - gitExistingRepoExists?: boolean; - remoteUrl?: string; - isAddedDeployKey?: boolean; - sshKeyType?: "RSA" | "ECDSA"; -} - -interface GitProfile { - authorName: string; - authorEmail: string; - useDefaultProfile?: boolean; -} - -interface ConnectOrImportPayload { - remoteUrl: string; - gitProfile: GitProfile; -} - -interface ConnectOrImportProps { - payload: ConnectOrImportPayload; - onErrorCallback: (error: Error, response: ApiResponse) => void; -} - -// Remove comments after integration interface ConnectModalProps { isImport?: boolean; - // It replaces const isImportingViaGit in GitConnectionV2/index.tsx - isImporting?: boolean; - // Replaces dispatch(importAppFromGit) - importFrom: (props: ConnectOrImportProps) => void; - // Replaces connectToGit from useGitConnect hook - connectTo: (props: ConnectOrImportProps) => void; - // Replaces isConnectingToGit - isConnectingTo?: boolean; - isConnecting: boolean; - artifactId: string; - artifactType: string; - // Replaces handleImport in original ChooseGitProvider.tsx - onImportFromCalloutLinkClick: () => void; - // Replaces hasCreateNewApplicationPermission = hasCreateNewAppPermission(workspace.userPermissions) - canCreateNewArtifact: boolean; - isModalOpen: boolean; - deployKeyDocUrl: AddDeployKeyProps["deployKeyDocUrl"]; - isFetchingSSHKeyPair: AddDeployKeyProps["isFetchingSSHKeyPair"]; - fetchSSHKeyPair: AddDeployKeyProps["fetchSSHKeyPair"]; - generateSSHKey: AddDeployKeyProps["generateSSHKey"]; - isGeneratingSSHKey: AddDeployKeyProps["isGeneratingSSHKey"]; - sshKeyPair: AddDeployKeyProps["sshKeyPair"]; } -function ConnectModal({ - artifactId, - artifactType, - canCreateNewArtifact, - connectTo, - deployKeyDocUrl, - fetchSSHKeyPair, - generateSSHKey, - importFrom, - isConnecting = false, - isFetchingSSHKeyPair, - isGeneratingSSHKey, - isImport = false, - isImporting = false, - isModalOpen, - onImportFromCalloutLinkClick, - sshKeyPair, -}: ConnectModalProps) { - const [errorData, setErrorData] = useState>(); - - const nextStepText = { - [GIT_CONNECT_STEPS.CHOOSE_PROVIDER]: createMessage(CONFIGURE_GIT), - [GIT_CONNECT_STEPS.GENERATE_SSH_KEY]: createMessage(GENERATE_SSH_KEY_STEP), - [GIT_CONNECT_STEPS.ADD_DEPLOY_KEY]: createMessage( - isImport ? IMPORT_APP_CTA : CONNECT_GIT_TEXT, - ), - }; - - const [formData, setFormData] = useState({ - gitProvider: undefined, - gitEmptyRepoExists: undefined, - gitExistingRepoExists: false, - remoteUrl: undefined, - isAddedDeployKey: false, - sshKeyType: "ECDSA", - }); - - const handleChange = (partialFormData: Partial) => { - setFormData((s) => ({ ...s, ...partialFormData })); - }; - - const [activeStep, setActiveStep] = useState( - GIT_CONNECT_STEPS.CHOOSE_PROVIDER, - ); - const currentIndex = steps.findIndex((s) => s.key === activeStep); - - const isDisabled = { - [GIT_CONNECT_STEPS.CHOOSE_PROVIDER]: !isImport - ? !formData.gitProvider || - !formData.gitEmptyRepoExists || - formData.gitEmptyRepoExists === "no" - : !formData.gitProvider || !formData.gitExistingRepoExists, - [GIT_CONNECT_STEPS.GENERATE_SSH_KEY]: - typeof formData?.remoteUrl !== "string" || - !isValidGitRemoteUrl(formData?.remoteUrl), - [GIT_CONNECT_STEPS.ADD_DEPLOY_KEY]: !formData.isAddedDeployKey, - }; - - const handlePreviousStep = useCallback(() => { - if (currentIndex > 0) { - setActiveStep(steps[currentIndex - 1].key); - } - }, [currentIndex]); - - const handleNextStep = useCallback(() => { - if (currentIndex < steps.length) { - switch (activeStep) { - case GIT_CONNECT_STEPS.CHOOSE_PROVIDER: { - setActiveStep(GIT_CONNECT_STEPS.GENERATE_SSH_KEY); - AnalyticsUtil.logEvent("GS_CONFIGURE_GIT"); - break; - } - case GIT_CONNECT_STEPS.GENERATE_SSH_KEY: { - setActiveStep(GIT_CONNECT_STEPS.ADD_DEPLOY_KEY); - AnalyticsUtil.logEvent("GS_GENERATE_KEY_BUTTON_CLICK", { - repoUrl: formData?.remoteUrl, - connectFlow: "v2", - }); - break; - } - case GIT_CONNECT_STEPS.ADD_DEPLOY_KEY: { - const gitProfile = { - authorName: "", - authorEmail: "", - useGlobalProfile: true, - }; - - if (formData.remoteUrl) { - if (!isImport) { - connectTo({ - payload: { - remoteUrl: formData.remoteUrl, - gitProfile, - }, - onErrorCallback: (error, response) => { - // AE-GIT-4033 is repo not empty error - if (response?.responseMeta?.error?.code === "AE-GIT-4033") { - setActiveStep(GIT_CONNECT_STEPS.GENERATE_SSH_KEY); - } - - setErrorData(response); - }, - }); - AnalyticsUtil.logEvent( - "GS_CONNECT_BUTTON_ON_GIT_SYNC_MODAL_CLICK", - { repoUrl: formData?.remoteUrl, connectFlow: "v2" }, - ); - } else { - importFrom({ - payload: { - remoteUrl: formData.remoteUrl, - gitProfile, - // isDefaultProfile: true, - }, - onErrorCallback(error, response) { - setErrorData(response); - }, - }); - } - } - - break; - } - } - } - }, [ - activeStep, - connectTo, - currentIndex, - formData.remoteUrl, - importFrom, - isImport, - ]); - - const stepProps = { - onChange: handleChange, - value: formData, - isImport, - errorData, - }; - - const loading = (!isImport && isConnecting) || (isImport && isImporting); +function ConnectModal({ isImport = false }: ConnectModalProps) { + const { artifactDef, isCreateArtifactPermitted, setImportWorkspaceId } = + useGitContext(); + const { + connect, + connectError, + fetchSSHKey, + generateSSHKey, + gitImport, + isConnectLoading, + isConnectModalOpen, + isFetchSSHKeyLoading, + isGenerateSSHKeyLoading, + isGitImportLoading, + resetFetchSSHKey, + resetGenerateSSHKey, + sshKey, + toggleConnectModal, + } = useConnect(); + const { isGitConnected, metadata } = useMetadata(); + const { toggleSettingsModal } = useSettings(); + + const { artifactType } = artifactDef; + const sshPublicKey = sshKey?.publicKey ?? null; + const remoteUrl = metadata?.remoteUrl ?? null; + const repoName = metadata?.repoName ?? null; + const defaultBranch = metadata?.defaultBranchName ?? null; return ( - <> - - {possibleSteps.includes(activeStep) && ( - - )} - {activeStep === GIT_CONNECT_STEPS.CHOOSE_PROVIDER && ( - - )} - {activeStep === GIT_CONNECT_STEPS.GENERATE_SSH_KEY && ( - - )} - {activeStep === GIT_CONNECT_STEPS.ADD_DEPLOY_KEY && ( - - )} - - - {loading && ( - - )} - {!loading && ( - - )} - {possibleSteps.includes(activeStep) && currentIndex > 0 && !loading && ( - - )} - - + ); } diff --git a/app/client/src/git/components/GitContextProvider/hooks/useGitBranches.ts b/app/client/src/git/components/GitContextProvider/hooks/useGitBranches.ts deleted file mode 100644 index 551338860fa..00000000000 --- a/app/client/src/git/components/GitContextProvider/hooks/useGitBranches.ts +++ /dev/null @@ -1,139 +0,0 @@ -import type { GitArtifactType } from "git/constants/enums"; -import type { FetchBranchesResponseData } from "git/requests/fetchBranchesRequest.types"; -import { gitArtifactActions } from "git/store/gitArtifactSlice"; -import { - selectBranches, - selectCheckoutBranch, - selectCreateBranch, - selectCurrentBranch, - selectDeleteBranch, -} from "git/store/selectors/gitSingleArtifactSelectors"; -import type { GitApiError, GitRootState } from "git/store/types"; -import { useCallback, useMemo } from "react"; -import { useDispatch, useSelector } from "react-redux"; - -interface UseGitBranchesParams { - artifactType: keyof typeof GitArtifactType; - baseArtifactId: string; -} - -export interface UseGitBranchesReturnValue { - branches: FetchBranchesResponseData | null; - fetchBranchesLoading: boolean; - fetchBranchesError: GitApiError | null; - fetchBranches: () => void; - createBranchLoading: boolean; - createBranchError: GitApiError | null; - createBranch: (branchName: string) => void; - deleteBranchLoading: boolean; - deleteBranchError: GitApiError | null; - deleteBranch: (branchName: string) => void; - checkoutBranchLoading: boolean; - checkoutBranchError: GitApiError | null; - checkoutBranch: (branchName: string) => void; - currentBranch: string | null; - toggleBranchListPopup: (open: boolean) => void; -} - -export default function useGitBranches({ - artifactType, - baseArtifactId, -}: UseGitBranchesParams): UseGitBranchesReturnValue { - const basePayload = useMemo( - () => ({ artifactType, baseArtifactId }), - [artifactType, baseArtifactId], - ); - const dispatch = useDispatch(); - - // fetch branches - const branchesState = useSelector((state: GitRootState) => - selectBranches(state, basePayload), - ); - const fetchBranches = useCallback(() => { - dispatch( - gitArtifactActions.fetchBranchesInit({ - ...basePayload, - pruneBranches: true, - }), - ); - }, [basePayload, dispatch]); - - // create branch - const createBranchState = useSelector((state: GitRootState) => - selectCreateBranch(state, basePayload), - ); - const createBranch = useCallback( - (branchName: string) => { - dispatch( - gitArtifactActions.createBranchInit({ - ...basePayload, - branchName, - }), - ); - }, - [basePayload, dispatch], - ); - // delete branch - const deleteBranchState = useSelector((state: GitRootState) => - selectDeleteBranch(state, basePayload), - ); - const deleteBranch = useCallback( - (branchName: string) => { - dispatch( - gitArtifactActions.deleteBranchInit({ - ...basePayload, - branchName, - }), - ); - }, - [basePayload, dispatch], - ); - // checkout branch - const checkoutBranchState = useSelector((state: GitRootState) => - selectCheckoutBranch(state, basePayload), - ); - const checkoutBranch = useCallback( - (branchName: string) => { - dispatch( - gitArtifactActions.checkoutBranchInit({ - ...basePayload, - branchName, - }), - ); - }, - [basePayload, dispatch], - ); - - // derived - const currentBranch = useSelector((state: GitRootState) => - selectCurrentBranch(state, basePayload), - ); - - // git branch list popup - const toggleBranchListPopup = (open: boolean) => { - dispatch( - gitArtifactActions.toggleBranchListPopup({ - ...basePayload, - open, - }), - ); - }; - - return { - branches: branchesState?.value, - fetchBranchesLoading: branchesState?.loading ?? false, - fetchBranchesError: branchesState?.error, - fetchBranches, - createBranchLoading: createBranchState?.loading ?? false, - createBranchError: createBranchState?.error, - createBranch, - deleteBranchLoading: deleteBranchState?.loading ?? false, - deleteBranchError: deleteBranchState?.error, - deleteBranch, - checkoutBranchLoading: checkoutBranchState?.loading ?? false, - checkoutBranchError: checkoutBranchState?.error, - checkoutBranch, - currentBranch: currentBranch ?? null, - toggleBranchListPopup, - }; -} diff --git a/app/client/src/git/components/GitContextProvider/hooks/useGitConnect.ts b/app/client/src/git/components/GitContextProvider/hooks/useGitConnect.ts deleted file mode 100644 index 9741a857e7a..00000000000 --- a/app/client/src/git/components/GitContextProvider/hooks/useGitConnect.ts +++ /dev/null @@ -1,37 +0,0 @@ -import type { GitArtifactType } from "git/constants/enums"; -import { gitArtifactActions } from "git/store/gitArtifactSlice"; -import { useMemo } from "react"; -import { useDispatch } from "react-redux"; - -interface UseGitConnectParams { - artifactType: keyof typeof GitArtifactType; - baseArtifactId: string; -} - -export interface UseGitConnectReturnValue { - toggleConnectModal: (open: boolean) => void; -} - -export default function useGitConnect({ - artifactType, - baseArtifactId, -}: UseGitConnectParams): UseGitConnectReturnValue { - const dispatch = useDispatch(); - const basePayload = useMemo( - () => ({ artifactType, baseArtifactId }), - [artifactType, baseArtifactId], - ); - - const toggleConnectModal = (open: boolean) => { - dispatch( - gitArtifactActions.toggleConnectModal({ - ...basePayload, - open, - }), - ); - }; - - return { - toggleConnectModal, - }; -} diff --git a/app/client/src/git/components/GitContextProvider/hooks/useGitContextValue.ts b/app/client/src/git/components/GitContextProvider/hooks/useGitContextValue.ts deleted file mode 100644 index 9b62bc1ba4c..00000000000 --- a/app/client/src/git/components/GitContextProvider/hooks/useGitContextValue.ts +++ /dev/null @@ -1,67 +0,0 @@ -import type { GitArtifactType } from "git/constants/enums"; -import type { UseGitConnectReturnValue } from "./useGitConnect"; -import type { UseGitOpsReturnValue } from "./useGitOps"; -import type { UseGitBranchesReturnValue } from "./useGitBranches"; -import useGitConnect from "./useGitConnect"; -import useGitOps from "./useGitOps"; -import useGitBranches from "./useGitBranches"; -import { useMemo } from "react"; - -// internal dependencies -import type { ApplicationPayload } from "entities/Application"; -import type { FetchStatusResponseData } from "git/requests/fetchStatusRequest.types"; -import type { StatusTreeStruct } from "git/components/StatusChanges/StatusTree"; - -export interface UseGitContextValueParams { - artifactType: keyof typeof GitArtifactType; - baseArtifactId: string; - artifact: ApplicationPayload | null; - statusTransformer: ( - status: FetchStatusResponseData, - ) => StatusTreeStruct[] | null; -} - -export interface GitContextValue - extends UseGitConnectReturnValue, - UseGitOpsReturnValue, - UseGitBranchesReturnValue { - artifactType: keyof typeof GitArtifactType; - baseArtifactId: string; - artifactDef: { - artifactType: keyof typeof GitArtifactType; - baseArtifactId: string; - }; - artifact: ApplicationPayload | null; - statusTransformer: ( - status: FetchStatusResponseData, - ) => StatusTreeStruct[] | null; -} - -export default function useGitContextValue({ - artifact, - artifactType, - baseArtifactId = "", - statusTransformer, -}: UseGitContextValueParams): GitContextValue { - const artifactDef = useMemo( - () => ({ artifactType, baseArtifactId }), - [artifactType, baseArtifactId], - ); - const useGitConnectReturnValue = useGitConnect(artifactDef); - const useGitOpsReturnValue = useGitOps({ - ...artifactDef, - artifactId: artifact?.id ?? null, - }); - const useGitBranchesReturnValue = useGitBranches(artifactDef); - - return { - artifactType, - baseArtifactId, - artifactDef, - statusTransformer, - artifact, - ...useGitOpsReturnValue, - ...useGitBranchesReturnValue, - ...useGitConnectReturnValue, - }; -} diff --git a/app/client/src/git/components/GitContextProvider/hooks/useGitMetadata.ts b/app/client/src/git/components/GitContextProvider/hooks/useGitMetadata.ts deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/app/client/src/git/components/GitContextProvider/hooks/useGitOps.ts b/app/client/src/git/components/GitContextProvider/hooks/useGitOps.ts deleted file mode 100644 index 97b224f3371..00000000000 --- a/app/client/src/git/components/GitContextProvider/hooks/useGitOps.ts +++ /dev/null @@ -1,225 +0,0 @@ -import { GitOpsTab, type GitArtifactType } from "git/constants/enums"; -import type { FetchMergeStatusResponseData } from "git/requests/fetchMergeStatusRequest.types"; -import type { FetchStatusResponseData } from "git/requests/fetchStatusRequest.types"; -import { gitArtifactActions } from "git/store/gitArtifactSlice"; -import { - selectCommit, - selectConflictErrorModalOpen, - selectDiscard, - selectMerge, - selectMergeStatus, - selectOpsModalOpen, - selectOpsModalTab, - selectPull, - selectStatus, -} from "git/store/selectors/gitSingleArtifactSelectors"; -import type { GitApiError, GitRootState } from "git/store/types"; -import { useCallback, useMemo } from "react"; -import { useDispatch, useSelector } from "react-redux"; - -interface UseGitOpsParams { - artifactType: keyof typeof GitArtifactType; - baseArtifactId: string; - artifactId: string | null; -} - -export interface UseGitOpsReturnValue { - commitLoading: boolean; - commitError: GitApiError | null; - commit: (commitMessage: string) => void; - clearCommitError: () => void; - discardLoading: boolean; - discardError: GitApiError | null; - discard: () => void; - clearDiscardError: () => void; - status: FetchStatusResponseData | null; - fetchStatusLoading: boolean; - fetchStatusError: GitApiError | null; - fetchStatus: () => void; - mergeLoading: boolean; - mergeError: GitApiError | null; - merge: () => void; - mergeStatus: FetchMergeStatusResponseData | null; - fetchMergeStatusLoading: boolean; - fetchMergeStatusError: GitApiError | null; - fetchMergeStatus: (sourceBranch: string, destinationBranch: string) => void; - clearMergeStatus: () => void; - pullLoading: boolean; - pullError: GitApiError | null; - pull: () => void; - opsModalTab: keyof typeof GitOpsTab; - opsModalOpen: boolean; - toggleOpsModal: (open: boolean, tab?: keyof typeof GitOpsTab) => void; - conflictErrorModalOpen: boolean; - toggleConflictErrorModal: (open: boolean) => void; -} - -export default function useGitOps({ - artifactId, - artifactType, - baseArtifactId, -}: UseGitOpsParams): UseGitOpsReturnValue { - const dispatch = useDispatch(); - const basePayload = useMemo( - () => ({ artifactType, baseArtifactId }), - [artifactType, baseArtifactId], - ); - - // commit - const commitState = useSelector((state: GitRootState) => - selectCommit(state, basePayload), - ); - - const commit = useCallback( - (commitMessage: string) => { - dispatch( - gitArtifactActions.commitInit({ - ...basePayload, - commitMessage, - doPush: true, - }), - ); - }, - [basePayload, dispatch], - ); - - const clearCommitError = useCallback(() => { - dispatch(gitArtifactActions.clearCommitError(basePayload)); - }, [basePayload, dispatch]); - - // discard - const discardState = useSelector((state: GitRootState) => - selectDiscard(state, basePayload), - ); - - const discard = useCallback(() => { - dispatch(gitArtifactActions.discardInit(basePayload)); - }, [basePayload, dispatch]); - - const clearDiscardError = useCallback(() => { - dispatch(gitArtifactActions.clearDiscardError(basePayload)); - }, [basePayload, dispatch]); - - // status - const statusState = useSelector((state: GitRootState) => - selectStatus(state, basePayload), - ); - - const fetchStatus = useCallback(() => { - dispatch( - gitArtifactActions.fetchStatusInit({ - ...basePayload, - compareRemote: true, - }), - ); - }, [basePayload, dispatch]); - - // merge - const mergeState = useSelector((state: GitRootState) => - selectMerge(state, basePayload), - ); - - const merge = useCallback(() => { - dispatch(gitArtifactActions.mergeInit(basePayload)); - }, [basePayload, dispatch]); - - // merge status - const mergeStatusState = useSelector((state: GitRootState) => - selectMergeStatus(state, basePayload), - ); - - const fetchMergeStatus = useCallback( - (sourceBranch: string, destinationBranch: string) => { - dispatch( - gitArtifactActions.fetchMergeStatusInit({ - ...basePayload, - artifactId: artifactId ?? "", - sourceBranch, - destinationBranch, - }), - ); - }, - [artifactId, basePayload, dispatch], - ); - - const clearMergeStatus = useCallback(() => { - dispatch(gitArtifactActions.clearMergeStatus(basePayload)); - }, [basePayload, dispatch]); - - // pull - const pullState = useSelector((state: GitRootState) => - selectPull(state, basePayload), - ); - - const pull = useCallback(() => { - dispatch( - gitArtifactActions.pullInit({ - ...basePayload, - artifactId: artifactId ?? "", - }), - ); - }, [basePayload, artifactId, dispatch]); - - // ops modal - const opsModalOpen = useSelector((state: GitRootState) => - selectOpsModalOpen(state, basePayload), - ); - - const opsModalTab = useSelector((state: GitRootState) => - selectOpsModalTab(state, basePayload), - ); - - const toggleOpsModal = useCallback( - (open: boolean, tab: keyof typeof GitOpsTab = GitOpsTab.Deploy) => { - dispatch( - gitArtifactActions.toggleOpsModal({ ...basePayload, open, tab }), - ); - }, - [basePayload, dispatch], - ); - - // conflict error modal - const conflictErrorModalOpen = useSelector((state: GitRootState) => - selectConflictErrorModalOpen(state, basePayload), - ); - - const toggleConflictErrorModal = useCallback( - (open: boolean) => { - dispatch( - gitArtifactActions.toggleConflictErrorModal({ ...basePayload, open }), - ); - }, - [basePayload, dispatch], - ); - - return { - commitLoading: commitState?.loading ?? false, - commitError: commitState?.error, - commit, - clearCommitError, - discardLoading: discardState?.loading ?? false, - discardError: discardState?.error, - discard, - clearDiscardError, - status: statusState?.value, - fetchStatusLoading: statusState?.loading ?? false, - fetchStatusError: statusState?.error, - fetchStatus, - mergeLoading: mergeState?.loading ?? false, - mergeError: mergeState?.error, - merge, - mergeStatus: mergeStatusState?.value, - fetchMergeStatusLoading: mergeStatusState?.loading ?? false, - fetchMergeStatusError: mergeStatusState?.error, - fetchMergeStatus, - clearMergeStatus, - pullLoading: pullState?.loading ?? false, - pullError: pullState?.error, - pull, - opsModalTab, - opsModalOpen, - toggleOpsModal, - conflictErrorModalOpen, - toggleConflictErrorModal, - }; -} diff --git a/app/client/src/git/components/GitContextProvider/index.tsx b/app/client/src/git/components/GitContextProvider/index.tsx index 671f3b66a60..4d4b88b4f6a 100644 --- a/app/client/src/git/components/GitContextProvider/index.tsx +++ b/app/client/src/git/components/GitContextProvider/index.tsx @@ -1,7 +1,22 @@ -import React, { createContext, useContext } from "react"; -import useGitContextValue from "./hooks/useGitContextValue"; -import type { UseGitContextValueParams } from "./hooks/useGitContextValue"; -import type { GitContextValue } from "./hooks/useGitContextValue"; +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"; + +export interface GitContextValue { + artifactDef: { + artifactType: keyof typeof GitArtifactType; + baseArtifactId: string; + }; + artifact: ApplicationPayload | null; + statusTransformer: ( + status: FetchStatusResponseData, + ) => StatusTreeStruct[] | null; + setImportWorkspaceId: () => void; + isCreateArtifactPermitted: boolean; +} const gitContextInitialValue = {} as GitContextValue; @@ -11,15 +26,65 @@ export const useGitContext = () => { return useContext(GitContext); }; -interface GitContextProviderProps extends UseGitContextValueParams { +interface GitContextProviderProps { + artifactType: keyof typeof GitArtifactType; + baseArtifactId: string; + artifact: ApplicationPayload | null; + isCreateArtifactPermitted: boolean; + setWorkspaceIdForImport: (params: { + workspaceId: string; + editorId: string; + }) => void; + statusTransformer: ( + status: FetchStatusResponseData, + ) => StatusTreeStruct[] | null; children: React.ReactNode; } export default function GitContextProvider({ + artifact = null, + artifactType, + baseArtifactId, children, - ...useContextValueParams + isCreateArtifactPermitted, + setWorkspaceIdForImport, + statusTransformer, }: GitContextProviderProps) { - const contextValue = useGitContextValue(useContextValueParams); + const artifactDef = useMemo( + () => ({ artifactType, baseArtifactId }), + [artifactType, baseArtifactId], + ); + + const dispatch = useDispatch(); + + const { id: artifactId, workspaceId } = artifact ?? {}; + const setImportWorkspaceId = useCallback(() => { + if (workspaceId) { + dispatch( + setWorkspaceIdForImport({ + workspaceId: workspaceId ?? "", + editorId: artifactId ?? "", + }), + ); + } + }, [artifactId, dispatch, setWorkspaceIdForImport, workspaceId]); + + const contextValue: GitContextValue = useMemo( + () => ({ + artifactDef, + artifact, + statusTransformer, + isCreateArtifactPermitted, + setImportWorkspaceId, + }), + [ + artifactDef, + artifact, + statusTransformer, + isCreateArtifactPermitted, + setImportWorkspaceId, + ], + ); return ( {children} diff --git a/app/client/src/git/components/ImportModal/index.tsx b/app/client/src/git/components/ImportModal/index.tsx new file mode 100644 index 00000000000..f55a468d702 --- /dev/null +++ b/app/client/src/git/components/ImportModal/index.tsx @@ -0,0 +1,8 @@ +import React from "react"; +import ConnectModal from "../ConnectModal"; + +function ImportModal() { + return ; +} + +export default ImportModal; diff --git a/app/client/src/git/components/LocalProfile/LocalProfileView.tsx b/app/client/src/git/components/LocalProfile/LocalProfileView.tsx index beefbb66b29..03c027824cb 100644 --- a/app/client/src/git/components/LocalProfile/LocalProfileView.tsx +++ b/app/client/src/git/components/LocalProfile/LocalProfileView.tsx @@ -277,7 +277,7 @@ function LocalProfileView({ {...register("authorName", { required: createMessage(AUTHOR_NAME_CANNOT_BE_EMPTY), })} - onChange={handleInputChange("authorEmail")} + onChange={handleInputChange("authorName")} /> ) : ( diff --git a/app/client/src/git/components/OpsModal/TabDeploy/index.tsx b/app/client/src/git/components/OpsModal/TabDeploy/index.tsx index 53d1a8f4c6a..44bd8ee91cd 100644 --- a/app/client/src/git/components/OpsModal/TabDeploy/index.tsx +++ b/app/client/src/git/components/OpsModal/TabDeploy/index.tsx @@ -2,25 +2,23 @@ import React from "react"; import TabDeployView from "./TabDeployView"; import { useGitContext } from "git/components/GitContextProvider"; import useMetadata from "git/hooks/useMetadata"; +import useBranches from "git/hooks/useBranches"; +import useCommit from "git/hooks/useCommit"; +import useDiscard from "git/hooks/useDiscard"; +import usePull from "git/hooks/usePull"; +import useStatus from "git/hooks/useStatus"; export default function TabDeploy() { - const { - artifact, - clearCommitError, - clearDiscardError, - commit, - commitError, - commitLoading, - currentBranch, - discard, - discardError, - discardLoading, - fetchStatusLoading, - pull, - pullError, - pullLoading, - status, - } = useGitContext(); + const { artifact } = useGitContext(); + const { clearCommitError, commit, commitError, isCommitLoading } = + useCommit(); + + const { clearDiscardError, discard, discardError, isDiscardLoading } = + useDiscard(); + + const { isPullLoading, pull, pullError } = usePull(); + const { isFetchStatusLoading, status } = useStatus(); + const { currentBranch } = useBranches(); const { metadata } = useMetadata(); const lastDeployedAt = artifact?.lastDeployedAt ?? null; @@ -38,11 +36,11 @@ export default function TabDeploy() { currentBranch={currentBranch} discard={discard} discardError={discardError} - isCommitLoading={commitLoading} - isDiscardLoading={discardLoading} - isFetchStatusLoading={fetchStatusLoading} + isCommitLoading={isCommitLoading} + isDiscardLoading={isDiscardLoading} + isFetchStatusLoading={isFetchStatusLoading} isPullFailing={isPullFailing} - isPullLoading={pullLoading} + isPullLoading={isPullLoading} lastDeployedAt={lastDeployedAt} pull={pull} remoteUrl={remoteUrl} diff --git a/app/client/src/git/components/OpsModal/TabMerge/index.tsx b/app/client/src/git/components/OpsModal/TabMerge/index.tsx index adeb24ee991..a192d93dfcd 100644 --- a/app/client/src/git/components/OpsModal/TabMerge/index.tsx +++ b/app/client/src/git/components/OpsModal/TabMerge/index.tsx @@ -1,24 +1,23 @@ import React from "react"; import TabMergeView from "./TabMergeView"; -import { useGitContext } from "git/components/GitContextProvider"; import useProtectedBranches from "git/hooks/useProtectedBranches"; +import useBranches from "git/hooks/useBranches"; +import useMerge from "git/hooks/useMerge"; +import useStatus from "git/hooks/useStatus"; export default function TabMerge() { const { - branches, clearMergeStatus, - currentBranch, - fetchBranches, - fetchBranchesLoading, fetchMergeStatus, - fetchMergeStatusLoading, - fetchStatusLoading, + isFetchMergeStatusLoading, + isMergeLoading, merge, mergeError, - mergeLoading, mergeStatus, - status, - } = useGitContext(); + } = useMerge(); + const { isFetchStatusLoading, status } = useStatus(); + const { branches, currentBranch, fetchBranches, isFetchBranchesLoading } = + useBranches(); const { protectedBranches } = useProtectedBranches(); const isStatusClean = status?.isClean ?? false; @@ -30,10 +29,10 @@ export default function TabMerge() { currentBranch={currentBranch} fetchBranches={fetchBranches} fetchMergeStatus={fetchMergeStatus} - isFetchBranchesLoading={fetchBranchesLoading} - isFetchMergeStatusLoading={fetchMergeStatusLoading} - isFetchStatusLoading={fetchStatusLoading} - isMergeLoading={mergeLoading} + isFetchBranchesLoading={isFetchBranchesLoading} + isFetchMergeStatusLoading={isFetchMergeStatusLoading} + isFetchStatusLoading={isFetchStatusLoading} + isMergeLoading={isMergeLoading} isStatusClean={isStatusClean} merge={merge} mergeError={mergeError} diff --git a/app/client/src/git/components/OpsModal/index.tsx b/app/client/src/git/components/OpsModal/index.tsx index 1450d74cf7e..114439c2990 100644 --- a/app/client/src/git/components/OpsModal/index.tsx +++ b/app/client/src/git/components/OpsModal/index.tsx @@ -1,12 +1,13 @@ import React from "react"; import OpsModalView from "./OpsModalView"; -import { useGitContext } from "../GitContextProvider"; import useProtectedBranches from "git/hooks/useProtectedBranches"; import useMetadata from "git/hooks/useMetadata"; +import useStatus from "git/hooks/useStatus"; +import useOps from "git/hooks/useOps"; export default function OpsModal() { - const { fetchStatus, opsModalOpen, opsModalTab, toggleOpsModal } = - useGitContext(); + const { opsModalOpen, opsModalTab, toggleOpsModal } = useOps(); + const { fetchStatus } = useStatus(); const { isProtectedMode } = useProtectedBranches(); const { metadata } = useMetadata(); diff --git a/app/client/src/git/components/ProtectedBranches/index.tsx b/app/client/src/git/components/ProtectedBranches/index.tsx index 7da03a947e5..81c98f49aba 100644 --- a/app/client/src/git/components/ProtectedBranches/index.tsx +++ b/app/client/src/git/components/ProtectedBranches/index.tsx @@ -1,12 +1,12 @@ import React from "react"; import ProtectedBranchesView from "./ProtectedBranchesView"; -import { useGitContext } from "../GitContextProvider"; import useProtectedBranches from "git/hooks/useProtectedBranches"; import useGitFeatureFlags from "git/hooks/useGitFeatureFlags"; import useDefaultBranch from "git/ee/hooks/useDefaultBranch"; +import useBranches from "git/hooks/useBranches"; function ProtectedBranches() { - const { branches } = useGitContext(); + const { branches } = useBranches(); const { defaultBranch } = useDefaultBranch(); const { isUpdateProtectedBranchesLoading, diff --git a/app/client/src/git/components/QuickActions/BranchButton/index.tsx b/app/client/src/git/components/QuickActions/BranchButton.tsx similarity index 75% rename from app/client/src/git/components/QuickActions/BranchButton/index.tsx rename to app/client/src/git/components/QuickActions/BranchButton.tsx index d73cba35e40..0f220d97feb 100644 --- a/app/client/src/git/components/QuickActions/BranchButton/index.tsx +++ b/app/client/src/git/components/QuickActions/BranchButton.tsx @@ -1,23 +1,14 @@ import { Button, Icon, Tooltip } from "@appsmith/ads"; -import React, { useCallback, useEffect, useState } from "react"; +import React, { useCallback, useMemo } from "react"; import styled from "styled-components"; import noop from "lodash/noop"; -import BranchList from "./BranchList"; +import BranchList from "../BranchList"; import { Popover2 } from "@blueprintjs/popover2"; // internal dependencies import { isEllipsisActive } from "utils/helpers"; import AnalyticsUtil from "ee/utils/AnalyticsUtil"; -interface BranchButtonProps { - currentBranch?: string; - isOpen?: boolean; - setIsOpen?: (isOpen: boolean) => void; - isDisabled?: boolean; - isProtectedMode?: boolean; - isStatusClean?: boolean; -} - const ButtonContainer = styled(Button)` display: flex; align-items: center; @@ -45,20 +36,32 @@ const popoverModifiers: { offset: Record } = { offset: { enabled: true, options: { offset: [7, 10] } }, }; +interface BranchButtonProps { + currentBranch: string | null; + isAutocommitPolling: boolean; + isBranchPopupOpen: boolean; + isProtectedMode: boolean; + isStatusClean: boolean; + isTriggerAutocommitLoading: boolean; + toggleBranchPopup: (open: boolean) => void; +} + export default function BranchButton({ - currentBranch = "", - isDisabled = false, - isOpen = false, + currentBranch = null, + isAutocommitPolling = false, + isBranchPopupOpen = false, isProtectedMode = false, isStatusClean = false, - setIsOpen = noop, + isTriggerAutocommitLoading = false, + toggleBranchPopup = noop, }: BranchButtonProps) { - const [isEllipsis, setIsEllipsis] = useState(false); const labelTarget = React.useRef(null); + const isDisabled = isTriggerAutocommitLoading || isAutocommitPolling; + const onPopoverInteraction = useCallback( (nextState: boolean) => { - setIsOpen(nextState); + toggleBranchPopup(nextState); if (nextState) { AnalyticsUtil.logEvent("GS_OPEN_BRANCH_LIST_POPUP", { @@ -66,24 +69,20 @@ export default function BranchButton({ }); } }, - [setIsOpen], + [toggleBranchPopup], ); - useEffect(function ellipsisCheck() { - setIsEllipsis(isEllipsisActive(labelTarget.current) ?? false); - }, []); - - const renderContent = useCallback(() => { + const content = useMemo(() => { return ; }, []); return ( Test
; -} diff --git a/app/client/src/git/components/QuickActions/QuickActionsView.test.tsx b/app/client/src/git/components/QuickActions/QuickActionsView.test.tsx index a1d595b923c..6e696ddffe5 100644 --- a/app/client/src/git/components/QuickActions/QuickActionsView.test.tsx +++ b/app/client/src/git/components/QuickActions/QuickActionsView.test.tsx @@ -21,9 +21,11 @@ jest.mock("./../Statusbar", () => () => ( describe("QuickActionsView Component", () => { const defaultProps = { + currentBranch: "main", discard: jest.fn(), isAutocommitEnabled: false, isAutocommitPolling: false, + isBranchPopupOpen: false, isConnectPermitted: true, isDiscardLoading: false, isFetchStatusLoading: false, @@ -32,12 +34,14 @@ describe("QuickActionsView Component", () => { isPullFailing: false, isPullLoading: false, isStatusClean: true, + isTriggerAutocommitLoading: false, pull: jest.fn(), statusBehindCount: 0, statusChangeCount: 0, toggleConnectModal: jest.fn(), toggleOpsModal: jest.fn(), toggleSettingsModal: jest.fn(), + toggleBranchPopup: jest.fn(), }; afterEach(() => { diff --git a/app/client/src/git/components/QuickActions/QuickActionsView.tsx b/app/client/src/git/components/QuickActions/QuickActionsView.tsx index eedb67bf378..39698478801 100644 --- a/app/client/src/git/components/QuickActions/QuickActionsView.tsx +++ b/app/client/src/git/components/QuickActions/QuickActionsView.tsx @@ -16,6 +16,7 @@ import QuickActionButton from "./QuickActionButton"; import AutocommitStatusbar from "../Statusbar"; import getPullBtnStatus from "./helpers/getPullButtonStatus"; import noop from "lodash/noop"; +import BranchButton from "./BranchButton"; const Container = styled.div` height: 100%; @@ -24,9 +25,11 @@ const Container = styled.div` `; interface QuickActionsViewProps { + currentBranch: string | null; discard: () => void; isAutocommitEnabled: boolean; isAutocommitPolling: boolean; + isBranchPopupOpen: boolean; isConnectPermitted: boolean; isDiscardLoading: boolean; isFetchStatusLoading: boolean; @@ -35,6 +38,7 @@ interface QuickActionsViewProps { isPullFailing: boolean; isPullLoading: boolean; isStatusClean: boolean; + isTriggerAutocommitLoading: boolean; pull: () => void; statusBehindCount: number; statusChangeCount: number; @@ -44,12 +48,15 @@ interface QuickActionsViewProps { open: boolean, tab: keyof typeof GitSettingsTab, ) => void; + toggleBranchPopup: (open: boolean) => void; } function QuickActionsView({ + currentBranch = null, discard = noop, isAutocommitEnabled = false, isAutocommitPolling = false, + isBranchPopupOpen = false, isConnectPermitted = false, isDiscardLoading = false, isFetchStatusLoading = false, @@ -58,9 +65,11 @@ function QuickActionsView({ isPullFailing = false, isPullLoading = false, isStatusClean = false, + isTriggerAutocommitLoading = false, pull = noop, statusBehindCount = 0, statusChangeCount = 0, + toggleBranchPopup = noop, toggleConnectModal = noop, toggleOpsModal = noop, toggleSettingsModal = noop, @@ -95,8 +104,6 @@ function QuickActionsView({ if (isProtectedMode) { discard(); } else { - // ! case: why is triggeredFromBottomBar this needed? - // pull({ triggeredFromBottomBar: true }); pull(); } } @@ -126,7 +133,16 @@ function QuickActionsView({ return isGitConnected ? ( - {/* */} + + {isAutocommitEnabled && isAutocommitPolling ? ( ) : ( diff --git a/app/client/src/git/components/QuickActions/index.tsx b/app/client/src/git/components/QuickActions/index.tsx index 88055bc5ccb..2b03ee8bdd1 100644 --- a/app/client/src/git/components/QuickActions/index.tsx +++ b/app/client/src/git/components/QuickActions/index.tsx @@ -1,30 +1,34 @@ import React from "react"; import QuickActionsView from "./QuickActionsView"; -import { useGitContext } from "../GitContextProvider"; import useStatusChangeCount from "./hooks/useStatusChangeCount"; import useProtectedBranches from "git/hooks/useProtectedBranches"; import useGitPermissions from "git/hooks/useGitPermissions"; import useAutocommit from "git/hooks/useAutocommit"; import useSettings from "git/hooks/useSettings"; import useMetadata from "git/hooks/useMetadata"; +import useConnect from "git/hooks/useConnect"; +import useDiscard from "git/hooks/useDiscard"; +import usePull from "git/hooks/usePull"; +import useStatus from "git/hooks/useStatus"; +import useOps from "git/hooks/useOps"; +import useBranches from "git/hooks/useBranches"; function QuickActions() { - const { - discard, - discardLoading, - fetchStatusLoading, - pull, - pullError, - pullLoading, - status, - toggleConnectModal, - toggleOpsModal, - } = useGitContext(); + const { toggleOpsModal } = useOps(); + const { isFetchStatusLoading, status } = useStatus(); + const { isPullLoading, pull, pullError } = usePull(); + const { discard, isDiscardLoading } = useDiscard(); const { isGitConnected } = useMetadata(); const { isProtectedMode } = useProtectedBranches(); const { isConnectPermitted } = useGitPermissions(); - const { isAutocommitEnabled, isAutocommitPolling } = useAutocommit(); + const { + isAutocommitEnabled, + isAutocommitPolling, + isTriggerAutocommitLoading, + } = useAutocommit(); const { toggleSettingsModal } = useSettings(); + const { toggleConnectModal } = useConnect(); + const { currentBranch, isBranchPopupOpen, toggleBranchPopup } = useBranches(); const isPullFailing = !!pullError; const isStatusClean = status?.isClean ?? false; @@ -33,20 +37,24 @@ function QuickActions() { return ( ; } -export default TabContinuosDelivery; +export default TabContinuousDelivery; diff --git a/app/client/src/git/components/StatusChanges/index.tsx b/app/client/src/git/components/StatusChanges/index.tsx index 05b8e280189..fc39867932f 100644 --- a/app/client/src/git/components/StatusChanges/index.tsx +++ b/app/client/src/git/components/StatusChanges/index.tsx @@ -1,13 +1,15 @@ import React from "react"; import { useGitContext } from "../GitContextProvider"; import StatusChangesView from "./StatusChangesView"; +import useStatus from "git/hooks/useStatus"; function StatusChanges() { - const { fetchStatusLoading, status, statusTransformer } = useGitContext(); + const { statusTransformer } = useGitContext(); + const { isFetchStatusLoading, status } = useStatus(); return ( diff --git a/app/client/src/git/components/index.tsx b/app/client/src/git/components/index.tsx index 1de56f66d1e..c3a1640dbd0 100644 --- a/app/client/src/git/components/index.tsx +++ b/app/client/src/git/components/index.tsx @@ -1,2 +1,3 @@ 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/constants/enums.ts b/app/client/src/git/constants/enums.ts index 244f2237a76..b3950c1b2fe 100644 --- a/app/client/src/git/constants/enums.ts +++ b/app/client/src/git/constants/enums.ts @@ -4,18 +4,6 @@ export enum GitArtifactType { Workflow = "Workflow", } -export enum GitConnectStep { - Provider = "Provider", - Remote = "Remote", - SSH = "SSH", -} - -export enum GitImportStep { - Provider = "Provider", - remote = "remote", - SSH = "SSH", -} - export enum GitOpsTab { Deploy = "Deploy", Merge = "Merge", @@ -45,6 +33,7 @@ export enum MergeStatusState { } export enum GitErrorCodes { + REPO_NOT_EMPTY = "AE-GIT-4033", REPO_LIMIT_REACHED = "AE-GIT-4043", PUSH_FAILED_REMOTE_COUNTERPART_IS_AHEAD = "AE-GIT-4048", } diff --git a/app/client/src/git/hooks/useAutocommit.ts b/app/client/src/git/hooks/useAutocommit.ts index b342b7442b2..73d7d955cac 100644 --- a/app/client/src/git/hooks/useAutocommit.ts +++ b/app/client/src/git/hooks/useAutocommit.ts @@ -5,6 +5,7 @@ import { selectAutocommitEnabled, selectAutocommitPolling, selectToggleAutocommitState, + selectTriggerAutocommitState, } from "git/store/selectors/gitSingleArtifactSelectors"; import type { GitRootState } from "git/store/types"; import { useCallback } from "react"; @@ -18,6 +19,10 @@ export default function useAutocommit() { selectToggleAutocommitState(state, artifactDef), ); + const triggerAutocommitState = useSelector((state: GitRootState) => + selectTriggerAutocommitState(state, artifactDef), + ); + const toggleAutocommit = useCallback(() => { dispatch(gitArtifactActions.toggleAutocommitInit(artifactDef)); }, [artifactDef, dispatch]); @@ -50,6 +55,8 @@ export default function useAutocommit() { isToggleAutocommitLoading: toggleAutocommitState?.loading ?? false, toggleAutocommitError: toggleAutocommitState?.error ?? null, toggleAutocommit, + isTriggerAutocommitLoading: triggerAutocommitState?.loading ?? false, + triggerAutocommitError: triggerAutocommitState?.error ?? null, isAutocommitDisableModalOpen, toggleAutocommitDisableModal, isAutocommitEnabled, diff --git a/app/client/src/git/hooks/useBranches.ts b/app/client/src/git/hooks/useBranches.ts new file mode 100644 index 00000000000..4a0ecead44d --- /dev/null +++ b/app/client/src/git/hooks/useBranches.ts @@ -0,0 +1,125 @@ +import { useGitContext } from "git/components/GitContextProvider"; +import { gitArtifactActions } from "git/store/gitArtifactSlice"; +import { + selectFetchBranchesState, + selectBranchPopupOpen, + selectCheckoutBranchState, + selectCheckoutDestBranch, + selectCreateBranchState, + selectDeleteBranchState, + selectCurrentBranch, +} from "git/store/selectors/gitSingleArtifactSelectors"; +import type { GitRootState } from "git/store/types"; +import { useCallback } from "react"; +import { useDispatch, useSelector } from "react-redux"; + +export default function useBranches() { + const { artifactDef } = useGitContext(); + + const dispatch = useDispatch(); + + // fetch branches + const branchesState = useSelector((state: GitRootState) => + selectFetchBranchesState(state, artifactDef), + ); + const fetchBranches = useCallback(() => { + dispatch( + gitArtifactActions.fetchBranchesInit({ + ...artifactDef, + pruneBranches: true, + }), + ); + }, [artifactDef, dispatch]); + + // create branch + const createBranchState = useSelector((state: GitRootState) => + selectCreateBranchState(state, artifactDef), + ); + const createBranch = useCallback( + (branchName: string) => { + dispatch( + gitArtifactActions.createBranchInit({ + ...artifactDef, + branchName, + }), + ); + }, + [artifactDef, dispatch], + ); + // delete branch + const deleteBranchState = useSelector((state: GitRootState) => + selectDeleteBranchState(state, artifactDef), + ); + const deleteBranch = useCallback( + (branchName: string) => { + dispatch( + gitArtifactActions.deleteBranchInit({ + ...artifactDef, + branchName, + }), + ); + }, + [artifactDef, dispatch], + ); + // checkout branch + const checkoutBranchState = useSelector((state: GitRootState) => + selectCheckoutBranchState(state, artifactDef), + ); + const checkoutBranch = useCallback( + (branchName: string) => { + dispatch( + gitArtifactActions.checkoutBranchInit({ + ...artifactDef, + branchName, + }), + ); + }, + [artifactDef, dispatch], + ); + + const checkoutDestBranch = useSelector((state: GitRootState) => + selectCheckoutDestBranch(state, artifactDef), + ); + + // derived + const currentBranch = useSelector((state: GitRootState) => + selectCurrentBranch(state, artifactDef), + ); + + // git branch list popup + const isBranchPopupOpen = useSelector((state: GitRootState) => + selectBranchPopupOpen(state, artifactDef), + ); + + const toggleBranchPopup = useCallback( + (open: boolean) => { + dispatch( + gitArtifactActions.toggleBranchPopup({ + ...artifactDef, + open, + }), + ); + }, + [artifactDef, dispatch], + ); + + return { + branches: branchesState?.value, + isFetchBranchesLoading: branchesState?.loading ?? false, + fetchBranchesError: branchesState?.error ?? null, + fetchBranches, + isCreateBranchLoading: createBranchState?.loading ?? false, + createBranchError: createBranchState?.error ?? null, + createBranch, + isDeleteBranchLoading: deleteBranchState?.loading ?? false, + deleteBranchError: deleteBranchState?.error ?? null, + deleteBranch, + isCheckoutBranchLoading: checkoutBranchState?.loading ?? false, + checkoutBranchError: checkoutBranchState?.error ?? null, + checkoutBranch, + checkoutDestBranch, + currentBranch: currentBranch ?? null, + isBranchPopupOpen, + toggleBranchPopup, + }; +} diff --git a/app/client/src/git/hooks/useCommit.ts b/app/client/src/git/hooks/useCommit.ts new file mode 100644 index 00000000000..56f78cc11bc --- /dev/null +++ b/app/client/src/git/hooks/useCommit.ts @@ -0,0 +1,39 @@ +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 { useCallback } from "react"; +import { useDispatch, useSelector } from "react-redux"; + +export default function useCommit() { + const { artifactDef } = useGitContext(); + const dispatch = useDispatch(); + + const commitState = useSelector((state: GitRootState) => + selectCommitState(state, artifactDef), + ); + + const commit = useCallback( + (commitMessage: string) => { + dispatch( + gitArtifactActions.commitInit({ + ...artifactDef, + commitMessage, + doPush: true, + }), + ); + }, + [artifactDef, dispatch], + ); + + const clearCommitError = useCallback(() => { + dispatch(gitArtifactActions.clearCommitError(artifactDef)); + }, [artifactDef, dispatch]); + + return { + isCommitLoading: commitState?.loading ?? false, + commitError: commitState?.error, + commit, + clearCommitError, + }; +} diff --git a/app/client/src/git/hooks/useConnect.ts b/app/client/src/git/hooks/useConnect.ts new file mode 100644 index 00000000000..1064ce7ff26 --- /dev/null +++ b/app/client/src/git/hooks/useConnect.ts @@ -0,0 +1,106 @@ +import { useGitContext } from "git/components/GitContextProvider"; +import type { ConnectRequestParams } from "git/requests/connectRequest.types"; +import { gitArtifactActions } from "git/store/gitArtifactSlice"; +import { + selectConnectModalOpen, + selectConnectState, + selectFetchSSHKeysState, + selectGenerateSSHKeyState, + selectGitImportState, +} from "git/store/selectors/gitSingleArtifactSelectors"; +import type { GitRootState } from "git/store/types"; +import { useCallback } from "react"; +import { useDispatch } from "react-redux"; +import { useSelector } from "react-redux"; + +export default function useConnect() { + const { artifactDef } = useGitContext(); + + const dispatch = useDispatch(); + + const connectState = useSelector((state: GitRootState) => + selectConnectState(state, artifactDef), + ); + + 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 })); + }, + [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 generateSSHKey = useCallback( + (keyType: string, isImport: boolean = false) => { + dispatch( + gitArtifactActions.generateSSHKeyInit({ + ...artifactDef, + keyType, + isImport, + }), + ); + }, + [artifactDef, dispatch], + ); + + const resetGenerateSSHKey = useCallback(() => { + dispatch(gitArtifactActions.resetGenerateSSHKey(artifactDef)); + }, [artifactDef, dispatch]); + + const isConnectModalOpen = useSelector((state: GitRootState) => + selectConnectModalOpen(state, artifactDef), + ); + + const toggleConnectModal = useCallback( + (open: boolean) => { + dispatch(gitArtifactActions.toggleConnectModal({ ...artifactDef, open })); + }, + [artifactDef, dispatch], + ); + + return { + 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, + toggleConnectModal, + }; +} diff --git a/app/client/src/git/hooks/useDiscard.ts b/app/client/src/git/hooks/useDiscard.ts new file mode 100644 index 00000000000..2f71c11608f --- /dev/null +++ b/app/client/src/git/hooks/useDiscard.ts @@ -0,0 +1,30 @@ +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 { useCallback } from "react"; +import { useDispatch, useSelector } from "react-redux"; + +export default function useDiscard() { + const { artifactDef } = useGitContext(); + const dispatch = useDispatch(); + + const discardState = useSelector((state: GitRootState) => + selectDiscardState(state, artifactDef), + ); + + const discard = useCallback(() => { + dispatch(gitArtifactActions.discardInit(artifactDef)); + }, [artifactDef, dispatch]); + + const clearDiscardError = useCallback(() => { + dispatch(gitArtifactActions.clearDiscardError(artifactDef)); + }, [artifactDef, dispatch]); + + return { + isDiscardLoading: discardState?.loading ?? false, + discardError: discardState?.error ?? null, + discard, + clearDiscardError, + }; +} diff --git a/app/client/src/git/hooks/useMerge.ts b/app/client/src/git/hooks/useMerge.ts new file mode 100644 index 00000000000..f7394601b19 --- /dev/null +++ b/app/client/src/git/hooks/useMerge.ts @@ -0,0 +1,58 @@ +import { useGitContext } from "git/components/GitContextProvider"; +import { gitArtifactActions } from "git/store/gitArtifactSlice"; +import { + selectMergeState, + selectMergeStatusState, +} from "git/store/selectors/gitSingleArtifactSelectors"; +import type { GitRootState } from "git/store/types"; +import { useCallback } from "react"; +import { useDispatch, useSelector } from "react-redux"; + +export default function useMerge() { + const { artifact, artifactDef } = useGitContext(); + const artifactId = artifact?.id; + const dispatch = useDispatch(); + + // merge + const mergeState = useSelector((state: GitRootState) => + selectMergeState(state, artifactDef), + ); + + const merge = useCallback(() => { + dispatch(gitArtifactActions.mergeInit(artifactDef)); + }, [artifactDef, dispatch]); + + // merge status + const mergeStatusState = useSelector((state: GitRootState) => + selectMergeStatusState(state, artifactDef), + ); + + const fetchMergeStatus = useCallback( + (sourceBranch: string, destinationBranch: string) => { + dispatch( + gitArtifactActions.fetchMergeStatusInit({ + ...artifactDef, + artifactId: artifactId ?? "", + sourceBranch, + destinationBranch, + }), + ); + }, + [artifactId, artifactDef, dispatch], + ); + + const clearMergeStatus = useCallback(() => { + dispatch(gitArtifactActions.clearMergeStatus(artifactDef)); + }, [artifactDef, dispatch]); + + return { + isMergeLoading: mergeState?.loading ?? false, + mergeError: mergeState?.error, + merge, + mergeStatus: mergeStatusState?.value, + isFetchMergeStatusLoading: mergeStatusState?.loading ?? false, + fetchMergeStatusError: mergeStatusState?.error, + fetchMergeStatus, + clearMergeStatus, + }; +} diff --git a/app/client/src/git/hooks/useMetadata.ts b/app/client/src/git/hooks/useMetadata.ts index 15ed4346dea..9bd5356ad76 100644 --- a/app/client/src/git/hooks/useMetadata.ts +++ b/app/client/src/git/hooks/useMetadata.ts @@ -18,9 +18,9 @@ export default function useMetadata() { ); return { - metadata: metadataState.value ?? null, - isFetchMetadataLoading: metadataState.loading ?? false, - fetchMetadataError: metadataState.error ?? null, + 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 new file mode 100644 index 00000000000..32eec997cf2 --- /dev/null +++ b/app/client/src/git/hooks/useOps.ts @@ -0,0 +1,57 @@ +import { useGitContext } from "git/components/GitContextProvider"; +import { GitOpsTab } from "git/constants/enums"; +import { gitArtifactActions } from "git/store/gitArtifactSlice"; +import { + selectConflictErrorModalOpen, + selectOpsModalOpen, + selectOpsModalTab, +} from "git/store/selectors/gitSingleArtifactSelectors"; +import type { GitRootState } from "git/store/types"; +import { useCallback } from "react"; +import { useDispatch, useSelector } from "react-redux"; + +export default function useOps() { + const { artifactDef } = useGitContext(); + + const dispatch = useDispatch(); + + // ops modal + const opsModalOpen = useSelector((state: GitRootState) => + selectOpsModalOpen(state, artifactDef), + ); + + const opsModalTab = useSelector((state: GitRootState) => + selectOpsModalTab(state, artifactDef), + ); + + const toggleOpsModal = useCallback( + (open: boolean, tab: keyof typeof GitOpsTab = GitOpsTab.Deploy) => { + dispatch( + gitArtifactActions.toggleOpsModal({ ...artifactDef, open, tab }), + ); + }, + [artifactDef, dispatch], + ); + + // conflict error modal + const conflictErrorModalOpen = useSelector((state: GitRootState) => + selectConflictErrorModalOpen(state, artifactDef), + ); + + const toggleConflictErrorModal = useCallback( + (open: boolean) => { + dispatch( + gitArtifactActions.toggleConflictErrorModal({ ...artifactDef, open }), + ); + }, + [artifactDef, dispatch], + ); + + return { + opsModalTab, + opsModalOpen, + toggleOpsModal, + conflictErrorModalOpen, + toggleConflictErrorModal, + }; +} diff --git a/app/client/src/git/hooks/useProtectedBranches.ts b/app/client/src/git/hooks/useProtectedBranches.ts index 3d26df24066..fa3b2ef8930 100644 --- a/app/client/src/git/hooks/useProtectedBranches.ts +++ b/app/client/src/git/hooks/useProtectedBranches.ts @@ -6,6 +6,7 @@ import { selectUpdateProtectedBranchesState, } from "git/store/selectors/gitSingleArtifactSelectors"; import type { GitRootState } from "git/store/types"; +import { useCallback } from "react"; import { useDispatch, useSelector } from "react-redux"; function useProtectedBranches() { @@ -17,22 +18,25 @@ function useProtectedBranches() { selectFetchProtectedBranchesState(state, artifactDef), ); - const fetchProtectedBranches = () => { + const fetchProtectedBranches = useCallback(() => { dispatch(gitArtifactActions.fetchProtectedBranchesInit(artifactDef)); - }; + }, [dispatch, artifactDef]); const updateProtectedBranchesState = useSelector((state: GitRootState) => selectUpdateProtectedBranchesState(state, artifactDef), ); - const updateProtectedBranches = (branches: string[]) => { - dispatch( - gitArtifactActions.updateProtectedBranchesInit({ - ...artifactDef, - branchNames: branches, - }), - ); - }; + const updateProtectedBranches = useCallback( + (branches: string[]) => { + dispatch( + gitArtifactActions.updateProtectedBranchesInit({ + ...artifactDef, + branchNames: branches, + }), + ); + }, + [dispatch, artifactDef], + ); const isProtectedMode = useSelector((state: GitRootState) => selectProtectedMode(state, artifactDef), diff --git a/app/client/src/git/hooks/usePull.ts b/app/client/src/git/hooks/usePull.ts new file mode 100644 index 00000000000..992866f2c27 --- /dev/null +++ b/app/client/src/git/hooks/usePull.ts @@ -0,0 +1,31 @@ +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 { useCallback } from "react"; +import { useDispatch, useSelector } from "react-redux"; + +export default function usePull() { + const { artifact, artifactDef } = useGitContext(); + const artifactId = artifact?.id; + const dispatch = useDispatch(); + + const pullState = useSelector((state: GitRootState) => + selectPullState(state, artifactDef), + ); + + const pull = useCallback(() => { + dispatch( + gitArtifactActions.pullInit({ + ...artifactDef, + artifactId: artifactId ?? "", + }), + ); + }, [artifactDef, artifactId, dispatch]); + + return { + isPullLoading: pullState?.loading ?? false, + pullError: pullState?.error, + pull, + }; +} diff --git a/app/client/src/git/hooks/useStatus.ts b/app/client/src/git/hooks/useStatus.ts new file mode 100644 index 00000000000..97b09b57498 --- /dev/null +++ b/app/client/src/git/hooks/useStatus.ts @@ -0,0 +1,31 @@ +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 { useCallback } from "react"; +import { useDispatch, useSelector } from "react-redux"; + +export default function useStatus() { + const { artifactDef } = useGitContext(); + const dispatch = useDispatch(); + + const statusState = useSelector((state: GitRootState) => + selectStatusState(state, artifactDef), + ); + + const fetchStatus = useCallback(() => { + dispatch( + gitArtifactActions.fetchStatusInit({ + ...artifactDef, + compareRemote: true, + }), + ); + }, [artifactDef, dispatch]); + + return { + status: statusState?.value, + isFetchStatusLoading: statusState?.loading ?? false, + fetchStatusError: statusState?.error, + fetchStatus, + }; +} diff --git a/app/client/src/git/requests/fetchSSHKeyRequest.types.ts b/app/client/src/git/requests/fetchSSHKeyRequest.types.ts index 55b4f305b66..b507a15c807 100644 --- a/app/client/src/git/requests/fetchSSHKeyRequest.types.ts +++ b/app/client/src/git/requests/fetchSSHKeyRequest.types.ts @@ -1,6 +1,10 @@ -export interface FetchSSHKeyResponse { +import type { ApiResponse } from "api/types"; + +export interface FetchSSHKeyResponseData { publicKey: string; docUrl: string; isRegeneratedKey: boolean; regeneratedKey: boolean; } + +export type FetchSSHKeyResponse = ApiResponse; diff --git a/app/client/src/git/requests/generateSSHKeyRequest.ts b/app/client/src/git/requests/generateSSHKeyRequest.ts index 7c747f94371..896426347f3 100644 --- a/app/client/src/git/requests/generateSSHKeyRequest.ts +++ b/app/client/src/git/requests/generateSSHKeyRequest.ts @@ -10,9 +10,9 @@ export default async function generateSSHKeyRequest( baseApplicationId: string, params: GenerateSSHKeyRequestParams, ): AxiosPromise { - const url = params.isImporting + const url = params.isImport ? `${GIT_BASE_URL}/import/keys?keyType=${params.keyType}` : `${APPLICATION_BASE_URL}/ssh-keypair/${baseApplicationId}?keyType=${params.keyType}`; - return params.isImporting ? Api.get(url) : Api.post(url); + return params.isImport ? Api.get(url) : Api.post(url); } diff --git a/app/client/src/git/requests/generateSSHKeyRequest.types.ts b/app/client/src/git/requests/generateSSHKeyRequest.types.ts index ced29ad6dbc..45374e42d5b 100644 --- a/app/client/src/git/requests/generateSSHKeyRequest.types.ts +++ b/app/client/src/git/requests/generateSSHKeyRequest.types.ts @@ -1,11 +1,15 @@ +import type { ApiResponse } from "api/types"; + export interface GenerateSSHKeyRequestParams { keyType: string; - isImporting: boolean; + isImport: boolean; } -export interface GenerateSSHKeyResponse { +export interface GenerateSSHKeyResponseData { publicKey: string; docUrl: string; isRegeneratedKey: boolean; regeneratedKey: boolean; } + +export type GenerateSSHKeyResponse = ApiResponse; diff --git a/app/client/src/git/requests/importGitRequest.ts b/app/client/src/git/requests/gitImportRequest.ts similarity index 52% rename from app/client/src/git/requests/importGitRequest.ts rename to app/client/src/git/requests/gitImportRequest.ts index 522cd187ebe..94ad9b5d95c 100644 --- a/app/client/src/git/requests/importGitRequest.ts +++ b/app/client/src/git/requests/gitImportRequest.ts @@ -1,14 +1,14 @@ import Api from "api/Api"; import { GIT_BASE_URL } from "./constants"; import type { - ImportGitRequestParams, - ImportGitResponse, -} from "./importGitRequest.types"; + GitImportRequestParams, + GitImportResponse, +} from "./gitImportRequest.types"; import type { AxiosPromise } from "axios"; -export default async function importGitRequest( +export default async function gitImportRequest( workspaceId: string, - params: ImportGitRequestParams, -): AxiosPromise { + params: GitImportRequestParams, +): AxiosPromise { return Api.post(`${GIT_BASE_URL}/import/${workspaceId}`, params); } diff --git a/app/client/src/git/requests/importGitRequest.types.ts b/app/client/src/git/requests/gitImportRequest.types.ts similarity index 69% rename from app/client/src/git/requests/importGitRequest.types.ts rename to app/client/src/git/requests/gitImportRequest.types.ts index b0f3113d7a6..9f76b379c9c 100644 --- a/app/client/src/git/requests/importGitRequest.types.ts +++ b/app/client/src/git/requests/gitImportRequest.types.ts @@ -1,4 +1,6 @@ -export interface ImportGitRequestParams { +import type { ApiResponse } from "api/types"; + +export interface GitImportRequestParams { remoteUrl: string; gitProfile?: { authorName: string; @@ -7,7 +9,7 @@ export interface ImportGitRequestParams { }; } -export interface ImportGitResponse { +export interface GitImportResponseData { id: string; baseId: string; gitApplicationMetadata: { @@ -22,3 +24,5 @@ export interface ImportGitResponse { repoName: string; }; } + +export type GitImportResponse = ApiResponse; diff --git a/app/client/src/git/sagas/checkoutBranchSaga.ts b/app/client/src/git/sagas/checkoutBranchSaga.ts index 18eaea3532a..34e48434626 100644 --- a/app/client/src/git/sagas/checkoutBranchSaga.ts +++ b/app/client/src/git/sagas/checkoutBranchSaga.ts @@ -48,7 +48,7 @@ export default function* checkoutBranchSaga( ); yield put( - gitArtifactActions.toggleBranchListPopup({ + gitArtifactActions.toggleBranchPopup({ ...basePayload, open: false, }), diff --git a/app/client/src/git/sagas/connectSaga.ts b/app/client/src/git/sagas/connectSaga.ts index b1bfa286e77..b13c2f6c2c2 100644 --- a/app/client/src/git/sagas/connectSaga.ts +++ b/app/client/src/git/sagas/connectSaga.ts @@ -53,6 +53,13 @@ export default function* connectSaga( history.replace(newUrl); // ! case for updating lastDeployedAt in application manually? } + + yield put( + gitArtifactActions.initGitForEditor({ + ...basePayload, + artifact: response.data, + }), + ); } } catch (e) { if (response && response.responseMeta.error) { @@ -67,12 +74,7 @@ export default function* connectSaga( ); } - yield put( - gitArtifactActions.connectError({ - ...basePayload, - error, - }), - ); + yield put(gitArtifactActions.connectError({ ...basePayload, 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 99604bd8660..7796f43d74b 100644 --- a/app/client/src/git/sagas/createBranchSaga.ts +++ b/app/client/src/git/sagas/createBranchSaga.ts @@ -30,6 +30,12 @@ export default function* createBranchSaga( if (isValidResponse) { yield put(gitArtifactActions.createBranchSuccess(basePayload)); + yield put( + gitArtifactActions.toggleBranchPopup({ + ...basePayload, + open: false, + }), + ); yield put( gitArtifactActions.fetchBranchesInit({ ...basePayload, diff --git a/app/client/src/git/sagas/fetchSSHKeySaga.ts b/app/client/src/git/sagas/fetchSSHKeySaga.ts new file mode 100644 index 00000000000..02f797edae6 --- /dev/null +++ b/app/client/src/git/sagas/fetchSSHKeySaga.ts @@ -0,0 +1,37 @@ +import { captureException } from "@sentry/react"; +import fetchSSHKeyRequest from "git/requests/fetchSSHKeyRequest"; +import type { FetchSSHKeyResponse } from "git/requests/fetchSSHKeyRequest.types"; +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 function* fetchSSHKeySaga(action: GitArtifactPayloadAction) { + const { artifactType, baseArtifactId } = action.payload; + const artifactDef = { artifactType, baseArtifactId }; + let response: FetchSSHKeyResponse | undefined; + + try { + response = yield call(fetchSSHKeyRequest, baseArtifactId); + const isValidResponse: boolean = yield validateResponse(response, false); + + if (response && isValidResponse) { + yield put( + gitArtifactActions.fetchSSHKeySuccess({ + ...artifactDef, + responseData: response.data, + }), + ); + } + } catch (e) { + if (response && response.responseMeta.error) { + const { error } = response.responseMeta; + + yield put(gitArtifactActions.fetchSSHKeyError({ ...artifactDef, error })); + } else { + log.error(e); + captureException(e); + } + } +} diff --git a/app/client/src/git/sagas/generateSSHKeySaga.ts b/app/client/src/git/sagas/generateSSHKeySaga.ts new file mode 100644 index 00000000000..09773f9dc0d --- /dev/null +++ b/app/client/src/git/sagas/generateSSHKeySaga.ts @@ -0,0 +1,60 @@ +import { captureException } from "@sentry/react"; +import { GitErrorCodes } from "git/constants/enums"; +import generateSSHKeyRequest from "git/requests/generateSSHKeyRequest"; +import type { + GenerateSSHKeyRequestParams, + GenerateSSHKeyResponse, +} from "git/requests/generateSSHKeyRequest.types"; +import type { GenerateSSHKeyInitPayload } from "git/store/actions/generateSSHKeyActions"; +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 function* generateSSHKeySaga( + action: GitArtifactPayloadAction, +) { + const { artifactType, baseArtifactId } = action.payload; + const artifactDef = { artifactType, baseArtifactId }; + let response: GenerateSSHKeyResponse | undefined; + + try { + const params: GenerateSSHKeyRequestParams = { + keyType: action.payload.keyType, + isImport: action.payload.isImport, + }; + + response = yield call(generateSSHKeyRequest, baseArtifactId, params); + const isValidResponse: boolean = yield validateResponse(response); + + if (response && isValidResponse) { + yield put( + gitArtifactActions.generateSSHKeySuccess({ + ...artifactDef, + responseData: response.data, + }), + ); + } + } catch (e) { + if (response && response.responseMeta.error) { + const { error } = response.responseMeta; + + if (GitErrorCodes.REPO_LIMIT_REACHED === error.code) { + yield put( + gitArtifactActions.toggleRepoLimitErrorModal({ + ...artifactDef, + open: true, + }), + ); + } + + yield put( + gitArtifactActions.generateSSHKeyError({ ...artifactDef, 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 4b2ca0720b0..13e19bd4c9f 100644 --- a/app/client/src/git/sagas/index.ts +++ b/app/client/src/git/sagas/index.ts @@ -27,6 +27,11 @@ import updateProtectedBranchesSaga from "./updateProtectedBranchesSaga"; import fetchMetadataSaga from "./fetchMetadataSaga"; import toggleAutocommitSaga from "./toggleAutocommitSaga"; import disconnectSaga from "./disconnectSaga"; +import { fetchSSHKeySaga } from "./fetchSSHKeySaga"; +import { generateSSHKeySaga } from "./generateSSHKeySaga"; +import createBranchSaga from "./createBranchSaga"; +import deleteBranchSaga from "./deleteBranchSaga"; +import checkoutBranchSaga from "./checkoutBranchSaga"; import { blockingActionSagas as blockingActionSagasExtended, @@ -53,6 +58,9 @@ const blockingActionSagas: Record< // branches [gitArtifactActions.fetchBranchesInit.type]: fetchBranchesSaga, + [gitArtifactActions.createBranchInit.type]: createBranchSaga, + [gitArtifactActions.deleteBranchInit.type]: deleteBranchSaga, + [gitArtifactActions.checkoutBranchInit.type]: checkoutBranchSaga, // user profiles [gitArtifactActions.fetchLocalProfileInit.type]: fetchLocalProfileSaga, @@ -82,6 +90,10 @@ const nonBlockingActionSagas: Record< [gitArtifactActions.initGitForEditor.type]: initGitForEditorSaga, [gitArtifactActions.toggleAutocommitInit.type]: toggleAutocommitSaga, + // ssh key + [gitArtifactActions.fetchSSHKeyInit.type]: fetchSSHKeySaga, + [gitArtifactActions.generateSSHKeyInit.type]: generateSSHKeySaga, + // EE ...nonBlockingActionSagasExtended, }; diff --git a/app/client/src/git/sagas/initGitSaga.ts b/app/client/src/git/sagas/initGitSaga.ts index 2c62fd31851..aa50efce17b 100644 --- a/app/client/src/git/sagas/initGitSaga.ts +++ b/app/client/src/git/sagas/initGitSaga.ts @@ -13,7 +13,7 @@ export default function* initGitForEditorSaga( yield put(gitArtifactActions.mount(basePayload)); if (artifactType === GitArtifactType.Application) { - if (!!artifact.gitApplicationMetadata) { + if (!!artifact.gitApplicationMetadata?.remoteUrl) { yield put(gitArtifactActions.fetchMetadataInit(basePayload)); yield take(gitArtifactActions.fetchMetadataSuccess.type); yield put( diff --git a/app/client/src/git/store/actions/checkoutBranchActions.ts b/app/client/src/git/store/actions/checkoutBranchActions.ts index c46edf84baf..c771d1887e3 100644 --- a/app/client/src/git/store/actions/checkoutBranchActions.ts +++ b/app/client/src/git/store/actions/checkoutBranchActions.ts @@ -6,9 +6,10 @@ export interface CheckoutBranchInitPayload extends CheckoutBranchRequestParams {} export const checkoutBranchInitAction = - createSingleArtifactAction((state) => { + createSingleArtifactAction((state, action) => { state.apiResponses.checkoutBranch.loading = true; state.apiResponses.checkoutBranch.error = null; + state.ui.checkoutDestBranch = action.payload.branchName; return state; }); @@ -16,6 +17,8 @@ export const checkoutBranchInitAction = export const checkoutBranchSuccessAction = createSingleArtifactAction( (state) => { state.apiResponses.checkoutBranch.loading = false; + state.apiResponses.checkoutBranch.error = null; + state.ui.checkoutDestBranch = null; return state; }, @@ -27,6 +30,7 @@ export const checkoutBranchErrorAction = state.apiResponses.checkoutBranch.loading = false; state.apiResponses.checkoutBranch.error = error; + state.ui.checkoutDestBranch = null; return state; }); diff --git a/app/client/src/git/store/actions/fetchSSHKeyActions.ts b/app/client/src/git/store/actions/fetchSSHKeyActions.ts index b802160ce0a..828cf6ebcb7 100644 --- a/app/client/src/git/store/actions/fetchSSHKeyActions.ts +++ b/app/client/src/git/store/actions/fetchSSHKeyActions.ts @@ -1,9 +1,6 @@ -import type { - GitArtifactPayloadAction, - GitArtifactErrorPayloadAction, - GitSSHKey, -} from "../types"; +import type { GitAsyncErrorPayload, GitAsyncSuccessPayload } from "../types"; import { createSingleArtifactAction } from "../helpers/createSingleArtifactAction"; +import type { FetchSSHKeyResponseData } from "git/requests/fetchSSHKeyRequest.types"; export const fetchSSHKeyInitAction = createSingleArtifactAction((state) => { state.apiResponses.sshKey.loading = true; @@ -12,22 +9,30 @@ export const fetchSSHKeyInitAction = createSingleArtifactAction((state) => { return state; }); -export const fetchSSHKeySuccessAction = createSingleArtifactAction( - (state, action: GitArtifactPayloadAction<{ sshKey: GitSSHKey }>) => { - state.apiResponses.sshKey.loading = false; - state.apiResponses.sshKey.value = action.payload.sshKey; +export const fetchSSHKeySuccessAction = createSingleArtifactAction< + GitAsyncSuccessPayload +>((state, action) => { + state.apiResponses.sshKey.loading = false; + state.apiResponses.sshKey.error = null; + state.apiResponses.sshKey.value = action.payload.responseData; - return state; - }, -); + return state; +}); -export const fetchSSHKeyErrorAction = createSingleArtifactAction( - (state, action: GitArtifactErrorPayloadAction) => { +export const fetchSSHKeyErrorAction = + createSingleArtifactAction((state, action) => { const { error } = action.payload; state.apiResponses.sshKey.loading = false; state.apiResponses.sshKey.error = error; return state; - }, -); + }); + +export const resetFetchSSHKeyAction = createSingleArtifactAction((state) => { + state.apiResponses.sshKey.loading = false; + state.apiResponses.sshKey.error = null; + state.apiResponses.sshKey.value = null; + + return state; +}); diff --git a/app/client/src/git/store/actions/generateSSHKey.ts b/app/client/src/git/store/actions/generateSSHKey.ts deleted file mode 100644 index 52698c65a8e..00000000000 --- a/app/client/src/git/store/actions/generateSSHKey.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { createSingleArtifactAction } from "../helpers/createSingleArtifactAction"; -import type { GitArtifactErrorPayloadAction } from "../types"; - -export const generateSSHKeyInitAction = createSingleArtifactAction((state) => { - state.apiResponses.generateSSHKey.loading = true; - state.apiResponses.generateSSHKey.error = null; - - return state; -}); - -export const generateSSHKeySuccessAction = createSingleArtifactAction( - (state) => { - state.apiResponses.generateSSHKey.loading = false; - - return state; - }, -); - -export const generateSSHKeyErrorAction = createSingleArtifactAction( - (state, action: GitArtifactErrorPayloadAction) => { - const { error } = action.payload; - - state.apiResponses.generateSSHKey.loading = false; - state.apiResponses.generateSSHKey.error = error; - - return state; - }, -); diff --git a/app/client/src/git/store/actions/generateSSHKeyActions.ts b/app/client/src/git/store/actions/generateSSHKeyActions.ts new file mode 100644 index 00000000000..fa70c3a1ba2 --- /dev/null +++ b/app/client/src/git/store/actions/generateSSHKeyActions.ts @@ -0,0 +1,44 @@ +import type { + GenerateSSHKeyRequestParams, + GenerateSSHKeyResponseData, +} from "git/requests/generateSSHKeyRequest.types"; +import { createSingleArtifactAction } from "../helpers/createSingleArtifactAction"; +import type { GitAsyncErrorPayload, GitAsyncSuccessPayload } from "../types"; + +export interface GenerateSSHKeyInitPayload + extends GenerateSSHKeyRequestParams {} + +export const generateSSHKeyInitAction = + createSingleArtifactAction((state) => { + state.apiResponses.generateSSHKey.loading = true; + state.apiResponses.generateSSHKey.error = null; + + return state; + }); + +export const generateSSHKeySuccessAction = createSingleArtifactAction< + GitAsyncSuccessPayload +>((state, action) => { + state.apiResponses.generateSSHKey.loading = false; + state.apiResponses.generateSSHKey.error = null; + state.apiResponses.sshKey.value = action.payload.responseData; + + return state; +}); + +export const generateSSHKeyErrorAction = + createSingleArtifactAction((state, action) => { + const { error } = action.payload; + + state.apiResponses.generateSSHKey.loading = false; + state.apiResponses.generateSSHKey.error = error; + + return state; + }); + +export const resetGenerateSSHKeyAction = createSingleArtifactAction((state) => { + state.apiResponses.generateSSHKey.loading = false; + state.apiResponses.generateSSHKey.error = null; + + return state; +}); diff --git a/app/client/src/git/store/actions/gitImportActions.ts b/app/client/src/git/store/actions/gitImportActions.ts new file mode 100644 index 00000000000..49411b55dd5 --- /dev/null +++ b/app/client/src/git/store/actions/gitImportActions.ts @@ -0,0 +1,25 @@ +import { createSingleArtifactAction } from "../helpers/createSingleArtifactAction"; +import type { GitAsyncErrorPayload } from "../types"; + +export const gitImportInitAction = createSingleArtifactAction((state) => { + state.apiResponses.gitImport.loading = true; + state.apiResponses.gitImport.error = null; + + return state; +}); + +export const gitImportSuccessAction = createSingleArtifactAction((state) => { + state.apiResponses.gitImport.loading = false; + + return state; +}); + +export const gitImportErrorAction = + createSingleArtifactAction((state, action) => { + const { error } = action.payload; + + state.apiResponses.gitImport.loading = false; + state.apiResponses.gitImport.error = error; + + return state; + }); diff --git a/app/client/src/git/store/actions/repoLimitErrorModalActions.ts b/app/client/src/git/store/actions/repoLimitErrorModalActions.ts index d79b29d61d1..b1867c1d592 100644 --- a/app/client/src/git/store/actions/repoLimitErrorModalActions.ts +++ b/app/client/src/git/store/actions/repoLimitErrorModalActions.ts @@ -9,7 +9,7 @@ export const toggleRepoLimitErrorModalAction = (state, action) => { const { open } = action.payload; - state.ui.repoLimitErrorModal.open = open; + state.ui.repoLimitErrorModalOpen = open; return state; }, diff --git a/app/client/src/git/store/actions/uiActions.ts b/app/client/src/git/store/actions/uiActions.ts index 6780ee64a4b..577d1dfa3d1 100644 --- a/app/client/src/git/store/actions/uiActions.ts +++ b/app/client/src/git/store/actions/uiActions.ts @@ -10,7 +10,7 @@ export const toggleConnectModalAction = createSingleArtifactAction((state, action) => { const { open } = action.payload; - state.ui.connectModal.open = open; + state.ui.connectModalOpen = open; return state; }); @@ -87,15 +87,15 @@ export const toggleAutocommitDisableModalAction = ); // branch popup -interface BranchListPopupPayload { +interface BranchPopupPayload { open: boolean; } -export const toggleBranchListPopupAction = - createSingleArtifactAction((state, action) => { +export const toggleBranchPopupAction = + createSingleArtifactAction((state, action) => { const { open } = action.payload; - state.ui.branchListPopup.open = open; + state.ui.branchPopupOpen = open; return state; }); @@ -109,7 +109,7 @@ export const toggleRepoLimitErrorModalAction = createSingleArtifactAction((state, action) => { const { open } = action.payload; - state.ui.repoLimitErrorModal.open = open; + state.ui.repoLimitErrorModalOpen = open; return state; }); diff --git a/app/client/src/git/store/gitArtifactSlice.ts b/app/client/src/git/store/gitArtifactSlice.ts index 75c3e64403b..924785f80c7 100644 --- a/app/client/src/git/store/gitArtifactSlice.ts +++ b/app/client/src/git/store/gitArtifactSlice.ts @@ -53,7 +53,7 @@ import { deleteBranchSuccessAction, } from "./actions/deleteBranchActions"; import { - toggleBranchListPopupAction, + toggleBranchPopupAction, toggleConnectModalAction, toggleOpsModalAction, toggleSettingsModalAction, @@ -119,6 +119,23 @@ import { disconnectInitAction, disconnectSuccessAction, } from "./actions/disconnectActions"; +import { + gitImportErrorAction, + gitImportInitAction, + gitImportSuccessAction, +} from "./actions/gitImportActions"; +import { + fetchSSHKeyErrorAction, + fetchSSHKeyInitAction, + fetchSSHKeySuccessAction, + resetFetchSSHKeyAction, +} from "./actions/fetchSSHKeyActions"; +import { + generateSSHKeyErrorAction, + generateSSHKeyInitAction, + generateSSHKeySuccessAction, + resetGenerateSSHKeyAction, +} from "./actions/generateSSHKeyActions"; const initialState: GitArtifactReduxState = {}; @@ -139,6 +156,17 @@ export const gitArtifactSlice = createSlice({ connectInit: connectInitAction, connectSuccess: connectSuccessAction, connectError: connectErrorAction, + gitImportInit: gitImportInitAction, + gitImportSuccess: gitImportSuccessAction, + gitImportError: gitImportErrorAction, + fetchSSHKeyInit: fetchSSHKeyInitAction, + fetchSSHKeySuccess: fetchSSHKeySuccessAction, + fetchSSHKeyError: fetchSSHKeyErrorAction, + resetFetchSSHKey: resetFetchSSHKeyAction, + generateSSHKeyInit: generateSSHKeyInitAction, + generateSSHKeySuccess: generateSSHKeySuccessAction, + generateSSHKeyError: generateSSHKeyErrorAction, + resetGenerateSSHKey: resetGenerateSSHKeyAction, disconnectInit: disconnectInitAction, disconnectSuccess: disconnectSuccessAction, disconnectError: disconnectErrorAction, @@ -185,7 +213,7 @@ export const gitArtifactSlice = createSlice({ checkoutBranchInit: checkoutBranchInitAction, checkoutBranchSuccess: checkoutBranchSuccessAction, checkoutBranchError: checkoutBranchErrorAction, - toggleBranchListPopup: toggleBranchListPopupAction, + toggleBranchPopup: toggleBranchPopupAction, // settings toggleSettingsModal: toggleSettingsModalAction, diff --git a/app/client/src/git/store/helpers/gitSingleArtifactInitialState.ts b/app/client/src/git/store/helpers/gitSingleArtifactInitialState.ts index 605ed274866..b17c93a126c 100644 --- a/app/client/src/git/store/helpers/gitSingleArtifactInitialState.ts +++ b/app/client/src/git/store/helpers/gitSingleArtifactInitialState.ts @@ -2,12 +2,7 @@ import { gitArtifactAPIResponsesInitialState as gitArtifactAPIResponsesInitialStateExtended, gitArtifactUIInitialState as gitArtifactUIInitialStateExtended, } from "git/ee/store/helpers/initialState"; -import { - GitConnectStep, - GitImportStep, - GitOpsTab, - GitSettingsTab, -} from "../../constants/enums"; +import { GitOpsTab, GitSettingsTab } from "../../constants/enums"; import type { GitSingleArtifactAPIResponsesReduxState, GitSingleArtifactUIReduxState, @@ -15,19 +10,11 @@ import type { } from "../types"; const gitSingleArtifactInitialUIState: GitSingleArtifactUIReduxState = { - connectModal: { - open: false, - step: GitConnectStep.Provider, - }, + connectModalOpen: false, disconnectBaseArtifactId: null, disconnectArtifactName: null, - importModal: { - open: false, - step: GitImportStep.Provider, - }, - branchListPopup: { - open: false, - }, + branchPopupOpen: false, + checkoutDestBranch: null, opsModalOpen: false, opsModalTab: GitOpsTab.Deploy, settingsModalOpen: false, @@ -35,9 +22,7 @@ const gitSingleArtifactInitialUIState: GitSingleArtifactUIReduxState = { autocommitDisableModalOpen: false, autocommitPolling: false, conflictErrorModalOpen: false, - repoLimitErrorModal: { - open: false, - }, + repoLimitErrorModalOpen: false, // EE ...gitArtifactUIInitialStateExtended, }; @@ -53,6 +38,10 @@ const gitSingleArtifactInitialAPIResponses: GitSingleArtifactAPIResponsesReduxSt loading: false, error: null, }, + gitImport: { + loading: false, + error: null, + }, status: { value: null, loading: false, diff --git a/app/client/src/git/store/selectors/gitSingleArtifactSelectors.ts b/app/client/src/git/store/selectors/gitSingleArtifactSelectors.ts index a42338ee507..845a2cfe41f 100644 --- a/app/client/src/git/store/selectors/gitSingleArtifactSelectors.ts +++ b/app/client/src/git/store/selectors/gitSingleArtifactSelectors.ts @@ -27,6 +27,31 @@ export const selectGitConnected = ( ) => !!selectMetadataState(state, artifactDef)?.value; // CONNECT +export const selectConnectState = ( + state: GitRootState, + 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, +) => selectGitArtifact(state, artifactDef)?.apiResponses.sshKey; + +export const selectGenerateSSHKeyState = ( + state: GitRootState, + artifactDef: GitArtifactDef, +) => selectGitArtifact(state, artifactDef)?.apiResponses.generateSSHKey; + +export const selectConnectModalOpen = ( + state: GitRootState, + artifactDef: GitArtifactDef, +) => selectGitArtifact(state, artifactDef)?.ui.connectModalOpen; + export const selectDisconnectState = ( state: GitRootState, artifactDef: GitArtifactDef, @@ -43,31 +68,35 @@ export const selectDisconnectArtifactName = ( ) => selectGitArtifact(state, artifactDef)?.ui.disconnectArtifactName; // git ops -export const selectCommit = ( +export const selectCommitState = ( state: GitRootState, artifactDef: GitArtifactDef, ) => selectGitArtifact(state, artifactDef)?.apiResponses?.commit; -export const selectDiscard = ( +export const selectDiscardState = ( state: GitRootState, artifactDef: GitArtifactDef, ) => selectGitArtifact(state, artifactDef)?.apiResponses?.discard; -export const selectStatus = ( +export const selectStatusState = ( state: GitRootState, artifactDef: GitArtifactDef, ) => selectGitArtifact(state, artifactDef)?.apiResponses?.status; -export const selectMerge = (state: GitRootState, artifactDef: GitArtifactDef) => - selectGitArtifact(state, artifactDef)?.apiResponses?.merge; +export const selectMergeState = ( + state: GitRootState, + artifactDef: GitArtifactDef, +) => selectGitArtifact(state, artifactDef)?.apiResponses?.merge; -export const selectMergeStatus = ( +export const selectMergeStatusState = ( state: GitRootState, artifactDef: GitArtifactDef, ) => selectGitArtifact(state, artifactDef)?.apiResponses?.mergeStatus; -export const selectPull = (state: GitRootState, artifactDef: GitArtifactDef) => - selectGitArtifact(state, artifactDef)?.apiResponses?.pull; +export const selectPullState = ( + state: GitRootState, + artifactDef: GitArtifactDef, +) => selectGitArtifact(state, artifactDef)?.apiResponses?.pull; export const selectOpsModalOpen = ( state: GitRootState, @@ -95,26 +124,36 @@ export const selectCurrentBranch = ( return gitMetadataState?.branchName; }; -export const selectBranches = ( +export const selectFetchBranchesState = ( state: GitRootState, artifactDef: GitArtifactDef, ) => selectGitArtifact(state, artifactDef)?.apiResponses?.branches; -export const selectCreateBranch = ( +export const selectCreateBranchState = ( state: GitRootState, artifactDef: GitArtifactDef, ) => selectGitArtifact(state, artifactDef)?.apiResponses?.createBranch; -export const selectDeleteBranch = ( +export const selectDeleteBranchState = ( state: GitRootState, artifactDef: GitArtifactDef, ) => selectGitArtifact(state, artifactDef)?.apiResponses?.deleteBranch; -export const selectCheckoutBranch = ( +export const selectCheckoutBranchState = ( state: GitRootState, artifactDef: GitArtifactDef, ) => selectGitArtifact(state, artifactDef)?.apiResponses.checkoutBranch; +export const selectCheckoutDestBranch = ( + state: GitRootState, + artifactDef: GitArtifactDef, +) => selectGitArtifact(state, artifactDef)?.ui.checkoutDestBranch; + +export const selectBranchPopupOpen = ( + state: GitRootState, + artifactDef: GitArtifactDef, +) => selectGitArtifact(state, artifactDef)?.ui.branchPopupOpen; + // SETTINGS // local profile @@ -134,6 +173,11 @@ export const selectToggleAutocommitState = ( artifactDef: GitArtifactDef, ) => selectGitArtifact(state, artifactDef)?.apiResponses.toggleAutocommit; +export const selectTriggerAutocommitState = ( + state: GitRootState, + artifactDef: GitArtifactDef, +) => selectGitArtifact(state, artifactDef)?.apiResponses.triggerAutocommit; + export const selectAutocommitDisableModalOpen = ( state: GitRootState, artifactDef: GitArtifactDef, diff --git a/app/client/src/git/store/types.ts b/app/client/src/git/store/types.ts index 3c439ac128c..ccb67a2e7a8 100644 --- a/app/client/src/git/store/types.ts +++ b/app/client/src/git/store/types.ts @@ -1,8 +1,6 @@ import type { PayloadAction } from "@reduxjs/toolkit"; import type { GitArtifactType, - GitConnectStep, - GitImportStep, GitOpsTab, GitSettingsTab, } from "../constants/enums"; @@ -14,13 +12,12 @@ import type { FetchMergeStatusResponseData } from "git/requests/fetchMergeStatus import type { FetchMetadataResponseData } from "git/requests/fetchMetadataRequest.types"; import type { FetchProtectedBranchesResponseData } from "git/requests/fetchProtectedBranchesRequest.types"; import type { ApiResponseError } from "api/types"; +import type { FetchSSHKeyResponseData } from "git/requests/fetchSSHKeyRequest.types"; import type { GitArtifactAPIResponsesReduxState as GitArtifactAPIResponsesReduxStateExtended, GitArtifactUIReduxState as GitArtifactUIReduxStateExtended, } from "git/ee/store/types"; -export type GitSSHKey = Record; - export interface GitApiError extends ApiResponseError { errorType?: string; referenceDoc?: string; @@ -40,6 +37,7 @@ export interface GitSingleArtifactAPIResponsesReduxState extends GitArtifactAPIResponsesReduxStateExtended { metadata: GitAsyncState; connect: GitAsyncStateWithoutValue; + gitImport: GitAsyncStateWithoutValue; status: GitAsyncState; commit: GitAsyncStateWithoutValue; pull: GitAsyncStateWithoutValue; @@ -58,25 +56,17 @@ export interface GitSingleArtifactAPIResponsesReduxState autocommitProgress: GitAsyncStateWithoutValue; toggleAutocommit: GitAsyncStateWithoutValue; triggerAutocommit: GitAsyncStateWithoutValue; - sshKey: GitAsyncState; + sshKey: GitAsyncState; generateSSHKey: GitAsyncStateWithoutValue; } export interface GitSingleArtifactUIReduxState extends GitArtifactUIReduxStateExtended { - connectModal: { - open: boolean; - step: keyof typeof GitConnectStep; - }; + connectModalOpen: boolean; disconnectBaseArtifactId: string | null; disconnectArtifactName: string | null; - importModal: { - open: boolean; - step: keyof typeof GitImportStep; - }; - branchListPopup: { - open: boolean; - }; + branchPopupOpen: boolean; + checkoutDestBranch: string | null; opsModalOpen: boolean; opsModalTab: keyof typeof GitOpsTab; settingsModalOpen: boolean; @@ -84,9 +74,7 @@ export interface GitSingleArtifactUIReduxState autocommitDisableModalOpen: boolean; autocommitPolling: boolean; conflictErrorModalOpen: boolean; - repoLimitErrorModal: { - open: boolean; - }; + repoLimitErrorModalOpen: boolean; } export interface GitSingleArtifactReduxState { ui: GitSingleArtifactUIReduxState; diff --git a/app/client/src/pages/AppViewer/AppPage/AppPage.tsx b/app/client/src/pages/AppViewer/AppPage/AppPage.tsx index 7b4b3ad3b03..5f9d27d7dc3 100644 --- a/app/client/src/pages/AppViewer/AppPage/AppPage.tsx +++ b/app/client/src/pages/AppViewer/AppPage/AppPage.tsx @@ -53,7 +53,11 @@ export function AppPage(props: AppPageProps) { ref={pageViewWrapperRef} sidebarWidth={sidebarWidth} > - + {widgetsStructure.widgetId && renderAppsmithCanvas(widgetsStructure as WidgetProps)} diff --git a/app/client/src/pages/Editor/Canvas.tsx b/app/client/src/pages/Editor/Canvas.tsx index 66173de99e2..742e6d8a74b 100644 --- a/app/client/src/pages/Editor/Canvas.tsx +++ b/app/client/src/pages/Editor/Canvas.tsx @@ -92,7 +92,7 @@ const Canvas = (props: CanvasProps) => { { }); // TODO: this returns a new function every time, needs to be recomposed - const handleTabClick = useEventCallback((tab: EntityItem) => () => { - dispatch(setListViewActiveState(false)); - tabClickHandler(tab); - }); + const handleTabClick = useCallback( + (tab: EntityItem) => () => { + dispatch(setListViewActiveState(false)); + tabClickHandler(tab); + }, + [dispatch, tabClickHandler], + ); const handleNewTabClick = useEventCallback(() => { dispatch(setListViewActiveState(false)); diff --git a/app/client/src/pages/Editor/IDE/Header/index.tsx b/app/client/src/pages/Editor/IDE/Header/index.tsx index 8a801693970..f8e75cda9db 100644 --- a/app/client/src/pages/Editor/IDE/Header/index.tsx +++ b/app/client/src/pages/Editor/IDE/Header/index.tsx @@ -29,6 +29,7 @@ import { IN_APP_EMBED_SETTING, INVITE_TAB, HEADER_TITLES, + PACKAGE_UPGRADING_ACTION_STATUS, } from "ee/constants/messages"; import EditorName from "pages/Editor/EditorName"; import { @@ -79,6 +80,7 @@ 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"; const StyledDivider = styled(Divider)` height: 50%; @@ -86,6 +88,12 @@ 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 { @@ -130,6 +138,7 @@ const Header = () => { 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; @@ -137,7 +146,10 @@ const Header = () => { 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); @@ -326,23 +338,22 @@ const Header = () => { showModal={showPublishCommunityTemplateModal} />
- - + + + + diff --git a/app/client/src/pages/Editor/IDE/Layout/UnanimatedLayout.tsx b/app/client/src/pages/Editor/IDE/Layout/StaticLayout.tsx similarity index 93% rename from app/client/src/pages/Editor/IDE/Layout/UnanimatedLayout.tsx rename to app/client/src/pages/Editor/IDE/Layout/StaticLayout.tsx index 78d5f079ca6..57e2fd104fe 100644 --- a/app/client/src/pages/Editor/IDE/Layout/UnanimatedLayout.tsx +++ b/app/client/src/pages/Editor/IDE/Layout/StaticLayout.tsx @@ -22,9 +22,10 @@ const GridContainer = styled.div` const LayoutContainer = styled.div<{ name: string }>` position: relative; grid-area: ${(props) => props.name}; + overflow: auto; `; -function UnanimatedLayout() { +export const StaticLayout = React.memo(() => { const isProtectedMode = useSelector(protectedModeSelector); const { areas, columns } = useGridLayoutTemplate(); @@ -60,8 +61,4 @@ function UnanimatedLayout() { ); -} - -const MemoUanimatedLayout = React.memo(UnanimatedLayout); - -export { MemoUanimatedLayout as UnanimatedLayout }; +}); 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 789a3837ebf..b2dc0558af5 100644 --- a/app/client/src/pages/Editor/IDE/Layout/hooks/useGridLayoutTemplate.ts +++ b/app/client/src/pages/Editor/IDE/Layout/hooks/useGridLayoutTemplate.ts @@ -50,17 +50,12 @@ function useGridLayoutTemplate(): ReturnValue { switch (appState) { case EditorState.DATA: if (isPreviewMode || isProtectedMode) { - setColumns([ - "0px", - "0px", - (windowWidth + "px") as AnimatedGridUnit, - "0px", - ]); + setColumns(["0px", "0px", `${windowWidth}px`, "0px"]); } else { setColumns([ SIDEBAR_WIDTH, "300px", - (windowWidth - 300 - 50 + "px") as AnimatedGridUnit, + `${windowWidth - 300 - 50}px`, "0px", ]); } @@ -68,20 +63,12 @@ function useGridLayoutTemplate(): ReturnValue { break; case EditorState.SETTINGS: if (isPreviewMode || isProtectedMode) { - setColumns([ - "0px", - "0px", - (windowWidth + "px") as AnimatedGridUnit, - "0px", - ]); + setColumns(["0px", "0px", `${windowWidth}px`, "0px"]); } else { setColumns([ SIDEBAR_WIDTH, - (APP_SETTINGS_PANE_WIDTH + "px") as AnimatedGridUnit, - (windowWidth - - APP_SIDEBAR_WIDTH - - APP_SETTINGS_PANE_WIDTH + - "px") as AnimatedGridUnit, + `${APP_SETTINGS_PANE_WIDTH}px`, + `${windowWidth - APP_SIDEBAR_WIDTH - APP_SETTINGS_PANE_WIDTH}px`, "0px", ]); } @@ -89,20 +76,12 @@ function useGridLayoutTemplate(): ReturnValue { break; case EditorState.LIBRARIES: if (isPreviewMode || isProtectedMode) { - setColumns([ - "0px", - "0px", - (windowWidth + "px") as AnimatedGridUnit, - "0px", - ]); + setColumns(["0px", "0px", `${windowWidth}px`, "0px"]); } else { setColumns([ SIDEBAR_WIDTH, `${APP_LIBRARIES_PANE_WIDTH}px`, - (windowWidth - - APP_SIDEBAR_WIDTH - - APP_LIBRARIES_PANE_WIDTH + - "px") as AnimatedGridUnit, + `${windowWidth - APP_SIDEBAR_WIDTH - APP_LIBRARIES_PANE_WIDTH}px`, "0px", ]); } @@ -112,25 +91,22 @@ function useGridLayoutTemplate(): ReturnValue { if (isPreviewMode || isProtectedMode) { setColumns([ "0px", - (editorStateLeftPaneWidth + "px") as AnimatedGridUnit, - (windowWidth + "px") as AnimatedGridUnit, + `${editorStateLeftPaneWidth}px`, + `${windowWidth}px`, "0px", ]); } else if (segment !== EditorEntityTab.UI) { if (editorMode === EditorViewMode.SplitScreen) { setColumns([ SIDEBAR_WIDTH, - (editorStateLeftPaneWidth + "px") as AnimatedGridUnit, - (windowWidth - - APP_SIDEBAR_WIDTH - - editorStateLeftPaneWidth + - "px") as AnimatedGridUnit, + `${editorStateLeftPaneWidth}px`, + `${windowWidth - APP_SIDEBAR_WIDTH - editorStateLeftPaneWidth}px`, "0px", ]); } else { setColumns([ SIDEBAR_WIDTH, - (editorStateLeftPaneWidth + "px") as AnimatedGridUnit, + `${editorStateLeftPaneWidth}px`, "0px", "0px", ]); @@ -138,14 +114,9 @@ function useGridLayoutTemplate(): ReturnValue { } else { setColumns([ SIDEBAR_WIDTH, - (editorStateLeftPaneWidth + "px") as AnimatedGridUnit, - (windowWidth - - APP_SIDEBAR_WIDTH - - editorStateLeftPaneWidth - - PropertyPaneWidth + - 1 + - "px") as AnimatedGridUnit, - (PropertyPaneWidth + 1 + "px") as AnimatedGridUnit, + `${editorStateLeftPaneWidth}px`, + `${windowWidth - APP_SIDEBAR_WIDTH - editorStateLeftPaneWidth - PropertyPaneWidth + 1}px`, + `${PropertyPaneWidth + 1}px`, ]); } } diff --git a/app/client/src/pages/Editor/IDE/Layout/index.ts b/app/client/src/pages/Editor/IDE/Layout/index.ts index c00321e5f89..f03b94541f0 100644 --- a/app/client/src/pages/Editor/IDE/Layout/index.ts +++ b/app/client/src/pages/Editor/IDE/Layout/index.ts @@ -1,2 +1,2 @@ export { AnimatedLayout } from "./AnimatedLayout"; -export { UnanimatedLayout } from "./UnanimatedLayout"; +export { StaticLayout } from "./StaticLayout"; diff --git a/app/client/src/pages/Editor/IDE/index.tsx b/app/client/src/pages/Editor/IDE/index.tsx index 40d6acfa8bf..9b806700cfd 100644 --- a/app/client/src/pages/Editor/IDE/index.tsx +++ b/app/client/src/pages/Editor/IDE/index.tsx @@ -1,6 +1,6 @@ import React from "react"; import { selectFeatureFlagCheck } from "ee/selectors/featureFlagsSelectors"; -import { AnimatedLayout, UnanimatedLayout } from "./Layout"; +import { AnimatedLayout, StaticLayout } from "./Layout"; import { useSelector } from "react-redux"; import type { AppState } from "ee/reducers"; import { FEATURE_FLAG } from "ee/entities/FeatureFlag"; @@ -22,7 +22,7 @@ function IDE() { return ; } - return ; + return ; } IDE.displayName = "AppIDE"; diff --git a/app/client/src/pages/common/Disabler.tsx b/app/client/src/pages/common/Disabler.tsx index 8bbbfb978de..3fc3ebf221b 100644 --- a/app/client/src/pages/common/Disabler.tsx +++ b/app/client/src/pages/common/Disabler.tsx @@ -12,6 +12,7 @@ const DisabledContainer = styled.div` width: 100%; display: flex; flex-direction: column; + cursor: not-allowed; & * { pointer-events: none; diff --git a/app/client/src/selectors/dataTreeSelectors.ts b/app/client/src/selectors/dataTreeSelectors.ts index 1babbe0563b..b64f4fbba4f 100644 --- a/app/client/src/selectors/dataTreeSelectors.ts +++ b/app/client/src/selectors/dataTreeSelectors.ts @@ -41,6 +41,9 @@ import { getCurrentWorkflowActions, getCurrentWorkflowJSActions, } from "ee/selectors/workflowSelectors"; +import { getCurrentApplication } from "ee/selectors/applicationSelectors"; +import { getCurrentAppWorkspace } from "ee/selectors/selectedWorkspaceSelectors"; +import type { PageListReduxState } from "reducers/entityReducers/pageListReducer"; export const getLoadingEntities = (state: AppState) => state.evaluations.loadingEntities; @@ -130,6 +133,15 @@ const getMetaWidgetsFromUnevaluatedDataTree = createSelector( DataTreeFactory.metaWidgets(metaWidgets, widgetsMeta, loadingEntities), ); +// * This is only for internal use to avoid cyclic dependency issue +const getPageListState = (state: AppState) => state.entities.pageList; +const getCurrentPageName = createSelector( + getPageListState, + (pageList: PageListReduxState) => + pageList.pages.find((page) => page.pageId === pageList.currentPageId) + ?.pageName, +); + export const getUnevaluatedDataTree = createSelector( getActionsFromUnevaluatedDataTree, getJSActionsFromUnevaluatedDataTree, @@ -137,7 +149,20 @@ export const getUnevaluatedDataTree = createSelector( getMetaWidgetsFromUnevaluatedDataTree, getAppData, getSelectedAppThemeProperties, - (actions, jsActions, widgets, metaWidgets, appData, theme) => { + getCurrentAppWorkspace, + getCurrentApplication, + getCurrentPageName, + ( + actions, + jsActions, + widgets, + metaWidgets, + appData, + theme, + currentWorkspace, + currentApplication, + getCurrentPageName, + ) => { let dataTree: UnEvalTree = { ...actions.dataTree, ...jsActions.dataTree, @@ -155,6 +180,9 @@ export const getUnevaluatedDataTree = createSelector( // taking precedence in case the key is the same store: appData.store, theme, + currentPageName: getCurrentPageName, + workspaceName: currentWorkspace.name, + appName: currentApplication?.name, } as AppsmithEntity; (dataTree.appsmith as AppsmithEntity).ENTITY_TYPE = ENTITY_TYPE.APPSMITH; dataTree = { ...dataTree, ...metaWidgets.dataTree }; diff --git a/app/client/src/utils/Analytics/mixpanel.ts b/app/client/src/utils/Analytics/mixpanel.ts index cc7f6e38288..ce51bf807a8 100644 --- a/app/client/src/utils/Analytics/mixpanel.ts +++ b/app/client/src/utils/Analytics/mixpanel.ts @@ -4,6 +4,11 @@ import { getAppsmithConfigs } from "ee/configs"; import SegmentSingleton from "./segment"; import type { ID } from "@segment/analytics-next"; +export interface SessionRecordingConfig { + enabled: boolean; + mask: boolean; +} + class MixpanelSingleton { private static instance: MixpanelSingleton; private mixpanel: OverridedMixpanel | null = null; @@ -17,13 +22,21 @@ class MixpanelSingleton { } // Segment needs to be initialized before Mixpanel - public async init(): Promise { + public async init({ + enabled, + mask, + }: SessionRecordingConfig): Promise { if (this.mixpanel) { log.warn("Mixpanel is already initialized."); return true; } + // Do not initialize Mixpanel if session recording is disabled + if (!enabled) { + return false; + } + try { const { default: loadedMixpanel } = await import("mixpanel-browser"); const { mixpanel } = getAppsmithConfigs(); @@ -32,6 +45,8 @@ class MixpanelSingleton { this.mixpanel = loadedMixpanel; this.mixpanel.init(mixpanel.apiKey, { record_sessions_percent: 100, + record_block_selector: mask ? ".mp-block" : "", + record_mask_text_selector: mask ? ".mp-mask" : "", }); await this.addSegmentMiddleware(); diff --git a/app/client/src/widgets/TableWidgetV2/widget/__tests__/derived.test/htmlColumns.test.js b/app/client/src/widgets/TableWidgetV2/widget/__tests__/derived.test/htmlColumns.test.js index 7e40f9055e5..bb5a2d551f6 100644 --- a/app/client/src/widgets/TableWidgetV2/widget/__tests__/derived.test/htmlColumns.test.js +++ b/app/client/src/widgets/TableWidgetV2/widget/__tests__/derived.test/htmlColumns.test.js @@ -183,6 +183,46 @@ describe("HTML columns", () => { delete input.searchText; }); + it("validate search works when a javascript object is sent in HTMLcolumn", () => { + const jsObjectInput = _.cloneDeep(input); + + jsObjectInput.processedTableData[0].status = { + color: "yellow", + text: "Adventure", + }; + jsObjectInput.searchText = "Adventure"; + const expected = [ + { + id: 1, + name: "Jim Doe", + status: { + color: "yellow", + text: "Adventure", + }, + __originalIndex__: 0, + }, + ]; + + let result = getFilteredTableData(jsObjectInput, moment, _); + + expect(result).toStrictEqual(expected); + }); + + it("validate search does not filter based on html attributes", () => { + input.searchText = "span"; + const expected = []; + + let result = getFilteredTableData(input, moment, _); + + expect(result).toStrictEqual(expected); + + input.searchText = "color"; + result = getFilteredTableData(input, moment, _); + + expect(result).toStrictEqual(expected); + delete input.searchText; + }); + it("validates filters on table for HTML columns", () => { input.filters = [ { diff --git a/app/client/src/widgets/TableWidgetV2/widget/derived.js b/app/client/src/widgets/TableWidgetV2/widget/derived.js index 14885dbed5f..b4a318dba38 100644 --- a/app/client/src/widgets/TableWidgetV2/widget/derived.js +++ b/app/client/src/widgets/TableWidgetV2/widget/derived.js @@ -284,13 +284,46 @@ export default { const getTextFromHTML = (html) => { if (!html) return ""; - const tempDiv = document.createElement("div"); + if (typeof html === "object") { + html = JSON.stringify(html); + } + + try { + const tempDiv = document.createElement("div"); - tempDiv.innerHTML = html; + tempDiv.innerHTML = html; - return tempDiv.textContent || tempDiv.innerText || ""; + return tempDiv.textContent || tempDiv.innerText || ""; + } catch (e) { + return ""; + } }; + /** + * Since getTextFromHTML is an expensive operation, we need to avoid calling it unnecessarily + * This optimization ensures that getTextFromHTML is only called when required + */ + const columnsWithHTML = Object.values(props.primaryColumns).filter( + (column) => column.columnType === "html", + ); + const htmlColumnAliases = new Set( + columnsWithHTML.map((column) => column.alias), + ); + + const isFilteringByColumnThatHasHTML = props.filters?.some((filter) => + htmlColumnAliases.has(filter.column), + ); + const isSortingByColumnThatHasHTML = + props.sortOrder?.column && htmlColumnAliases.has(props.sortOrder.column); + + const shouldExtractHTMLText = !!( + props.searchText || + isFilteringByColumnThatHasHTML || + isSortingByColumnThatHasHTML + ); + const getKeyForExtractedTextFromHTML = (columnAlias) => + `__htmlExtractedText_${columnAlias}__`; + /* extend processedTableData with values from * - computedValues, in case of normal column * - empty values, in case of derived column @@ -325,6 +358,12 @@ export default { ...processedTableData[index], [column.alias]: computedValue, }; + + if (shouldExtractHTMLText && column.columnType === "html") { + processedTableData[index][ + getKeyForExtractedTextFromHTML(column.alias) + ] = getTextFromHTML(computedValue); + } }); }); } @@ -514,11 +553,23 @@ export default { ); } } - case "html": + case "html": { + const htmlExtractedTextA = + processedA[ + getKeyForExtractedTextFromHTML(sortByColumnOriginalId) + ]; + const htmlExtractedTextB = + processedB[ + getKeyForExtractedTextFromHTML(sortByColumnOriginalId) + ]; + return sortByOrder( - getTextFromHTML(processedA[sortByColumnOriginalId]) > - getTextFromHTML(processedB[sortByColumnOriginalId]), + (htmlExtractedTextA ?? + getTextFromHTML(processedA[sortByColumnOriginalId])) > + (htmlExtractedTextB ?? + getTextFromHTML(processedB[sortByColumnOriginalId])), ); + } default: return sortByOrder( processedA[sortByColumnOriginalId].toString().toLowerCase() > @@ -715,10 +766,6 @@ export default { (column) => column.columnType === "url" && column.displayText, ); - const columnsWithHTML = Object.values(props.primaryColumns).filter( - (column) => column.columnType === "html", - ); - /* * For select columns with label and values, we need to include the label value * in the search and filter data @@ -814,17 +861,23 @@ export default { return acc; }, {}); + let htmlValues = {}; + /* * We don't want html tags and inline styles to match in search */ - const htmlValues = columnsWithHTML.reduce((acc, column) => { - const value = row[column.alias]; + if (shouldExtractHTMLText) { + htmlValues = columnsWithHTML.reduce((acc, column) => { + const value = row[column.alias]; - acc[column.alias] = - value === null || value === undefined ? "" : getTextFromHTML(value); + acc[column.alias] = _.isNil(value) + ? "" + : row[getKeyForExtractedTextFromHTML(column.alias)] ?? + getTextFromHTML(value); - return acc; - }, {}); + return acc; + }, {}); + } const displayedRow = { ...row, @@ -832,13 +885,12 @@ export default { ...displayTextValues, ...htmlValues, }; - const htmlColumns = columnsWithHTML.map((column) => column.alias); if (searchKey) { const combinedRowContent = [ ...Object.values(_.omit(displayedRow, hiddenColumns)), ...Object.values( - _.omit(originalRow, [...hiddenColumns, ...htmlColumns]), + _.omit(originalRow, [...hiddenColumns, ...htmlColumnAliases]), ), ] .join(", ") @@ -875,12 +927,16 @@ export default { /* * We don't want html tags and inline styles to match in filter conditions */ - const isHTMLColumn = htmlColumns.includes(props.filters[i].column); + const isHTMLColumn = htmlColumnAliases.has(props.filters[i].column); const originalColValue = isHTMLColumn - ? getTextFromHTML(originalRow[props.filters[i].column]) + ? originalRow[ + getKeyForExtractedTextFromHTML(props.filters[i].column) + ] ?? getTextFromHTML(originalRow[props.filters[i].column]) : originalRow[props.filters[i].column]; const displayedColValue = isHTMLColumn - ? getTextFromHTML(displayedRow[props.filters[i].column]) + ? displayedRow[ + getKeyForExtractedTextFromHTML(props.filters[i].column) + ] ?? getTextFromHTML(displayedRow[props.filters[i].column]) : displayedRow[props.filters[i].column]; filterResult = diff --git a/app/server/appsmith-plugins/appsmithAiPlugin/src/main/java/com/external/plugins/AppsmithAiPlugin.java b/app/server/appsmith-plugins/appsmithAiPlugin/src/main/java/com/external/plugins/AppsmithAiPlugin.java index 7fd4776a8f4..e756bb7f88d 100644 --- a/app/server/appsmith-plugins/appsmithAiPlugin/src/main/java/com/external/plugins/AppsmithAiPlugin.java +++ b/app/server/appsmith-plugins/appsmithAiPlugin/src/main/java/com/external/plugins/AppsmithAiPlugin.java @@ -26,6 +26,8 @@ import com.external.plugins.services.AiFeatureServiceFactory; import com.external.plugins.services.AiServerService; import com.external.plugins.services.AiServerServiceImpl; +import com.external.plugins.services.TriggerService; +import com.external.plugins.services.TriggerServiceImpl; import com.external.plugins.utils.RequestUtils; import com.google.gson.Gson; import com.google.gson.GsonBuilder; @@ -34,16 +36,10 @@ import reactor.core.publisher.Mono; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; -import static com.appsmith.external.constants.CommonFieldName.VALUE; -import static com.external.plugins.constants.AppsmithAiConstants.DISABLED; -import static com.external.plugins.constants.AppsmithAiConstants.LABEL; -import static com.external.plugins.constants.AppsmithAiConstants.LIST_FILES; -import static com.external.plugins.constants.AppsmithAiConstants.UPLOAD_FILES; import static com.external.plugins.constants.AppsmithAiConstants.USECASE; import static com.external.plugins.utils.FileUtils.getFileIds; import static com.external.plugins.utils.FileUtils.hasFiles; @@ -57,6 +53,8 @@ public AppsmithAiPlugin(PluginWrapper wrapper) { public static class AppsmithAiPluginExecutor extends BaseRestApiPluginExecutor { private static final AiServerService aiServerService = new AiServerServiceImpl(); + + private static final TriggerService triggerService = new TriggerServiceImpl(aiServerService, objectMapper); private static final Gson gson = new GsonBuilder().create(); public AppsmithAiPluginExecutor(SharedConfig config) { @@ -80,54 +78,7 @@ public Mono datasourceCreate(DatasourceConfiguration datasourceCo public Mono trigger( APIConnection connection, DatasourceConfiguration datasourceConfiguration, TriggerRequestDTO request) { log.debug(Thread.currentThread().getName() + ": trigger() called for AppsmithAI plugin."); - SourceDetails sourceDetails = SourceDetails.createSourceDetails(request); - String requestType = request.getRequestType(); - if (UPLOAD_FILES.equals(requestType)) { - return aiServerService - .uploadFiles(request.getFiles(), sourceDetails) - .flatMap(response -> { - TriggerResultDTO triggerResultDTO = new TriggerResultDTO(); - triggerResultDTO.setTrigger(response); - return Mono.just(triggerResultDTO); - }) - .onErrorResume( - error -> handleError("An error has occurred while trying to upload files", error)); - } else if (LIST_FILES.equals(requestType)) { - List fileIds = getFileIds(datasourceConfiguration); - if (fileIds.isEmpty()) { - TriggerResultDTO triggerResultDTO = new TriggerResultDTO(); - triggerResultDTO.setTrigger(List.of(Map.of( - DISABLED, - true, - LABEL, - "No files available in the datasource", - VALUE, - "NO_FILES_AVAILABLE"))); - return Mono.just(triggerResultDTO); - } - return aiServerService - .getFilesStatus(fileIds, sourceDetails) - .flatMap(fileStatusDTO -> { - List> response = new ArrayList<>(); - fileStatusDTO.getFiles().forEach(file -> { - Map dropdownOption = new HashMap<>(); - if (!file.isProcessed()) { - dropdownOption.put(LABEL, "(Processing...) " + file.getName()); - } else { - dropdownOption.put(LABEL, file.getName()); - } - dropdownOption.put(VALUE, file.getId()); - dropdownOption.put(DISABLED, !file.isProcessed()); - response.add(dropdownOption); - }); - TriggerResultDTO triggerResultDTO = new TriggerResultDTO(); - triggerResultDTO.setTrigger(response); - return Mono.just(triggerResultDTO); - }) - .onErrorResume(error -> - handleError("An error has occurred while trying to list uploaded files", error)); - } - return super.trigger(connection, datasourceConfiguration, request); + return triggerService.executeTrigger(connection, datasourceConfiguration, request); } private Mono handleError(String message, Throwable error) { diff --git a/app/server/appsmith-plugins/appsmithAiPlugin/src/main/java/com/external/plugins/services/TriggerService.java b/app/server/appsmith-plugins/appsmithAiPlugin/src/main/java/com/external/plugins/services/TriggerService.java new file mode 100644 index 00000000000..cf3619a3b51 --- /dev/null +++ b/app/server/appsmith-plugins/appsmithAiPlugin/src/main/java/com/external/plugins/services/TriggerService.java @@ -0,0 +1,12 @@ +package com.external.plugins.services; + +import com.appsmith.external.helpers.restApiUtils.connections.APIConnection; +import com.appsmith.external.models.DatasourceConfiguration; +import com.appsmith.external.models.TriggerRequestDTO; +import com.appsmith.external.models.TriggerResultDTO; +import reactor.core.publisher.Mono; + +public interface TriggerService { + Mono executeTrigger( + APIConnection connection, DatasourceConfiguration datasourceConfiguration, TriggerRequestDTO request); +} diff --git a/app/server/appsmith-plugins/appsmithAiPlugin/src/main/java/com/external/plugins/services/TriggerServiceCEImpl.java b/app/server/appsmith-plugins/appsmithAiPlugin/src/main/java/com/external/plugins/services/TriggerServiceCEImpl.java new file mode 100644 index 00000000000..6f3e18ed286 --- /dev/null +++ b/app/server/appsmith-plugins/appsmithAiPlugin/src/main/java/com/external/plugins/services/TriggerServiceCEImpl.java @@ -0,0 +1,100 @@ +package com.external.plugins.services; + +import com.appsmith.external.exceptions.pluginExceptions.AppsmithPluginError; +import com.appsmith.external.exceptions.pluginExceptions.AppsmithPluginException; +import com.appsmith.external.helpers.restApiUtils.connections.APIConnection; +import com.appsmith.external.models.DatasourceConfiguration; +import com.appsmith.external.models.TriggerRequestDTO; +import com.appsmith.external.models.TriggerResultDTO; +import com.external.plugins.dtos.SourceDetails; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import reactor.core.publisher.Mono; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static com.appsmith.external.constants.CommonFieldName.VALUE; +import static com.external.plugins.constants.AppsmithAiConstants.DISABLED; +import static com.external.plugins.constants.AppsmithAiConstants.LABEL; +import static com.external.plugins.constants.AppsmithAiConstants.LIST_FILES; +import static com.external.plugins.constants.AppsmithAiConstants.UPLOAD_FILES; +import static com.external.plugins.utils.FileUtils.getFileIds; + +@Slf4j +public class TriggerServiceCEImpl implements TriggerService { + + private final AiServerService aiServerService; + private final ObjectMapper objectMapper; + + public TriggerServiceCEImpl(AiServerService aiServerService, ObjectMapper objectMapper) { + this.aiServerService = aiServerService; + this.objectMapper = objectMapper; + } + + @Override + public Mono executeTrigger( + APIConnection connection, DatasourceConfiguration datasourceConfiguration, TriggerRequestDTO request) { + String requestType = request.getRequestType(); + return switch (requestType) { + case UPLOAD_FILES -> this.uploadFiles(request); + case LIST_FILES -> this.listFiles(datasourceConfiguration, request); + default -> Mono.empty(); + }; + } + + private Mono uploadFiles(TriggerRequestDTO request) { + SourceDetails sourceDetails = SourceDetails.createSourceDetails(request); + return aiServerService + .uploadFiles(request.getFiles(), sourceDetails) + .flatMap(response -> { + TriggerResultDTO triggerResultDTO = new TriggerResultDTO(); + triggerResultDTO.setTrigger(response); + return Mono.just(triggerResultDTO); + }) + .onErrorResume(error -> handleError("An error has occurred while trying to upload files", error)); + } + + private Mono listFiles( + DatasourceConfiguration datasourceConfiguration, TriggerRequestDTO request) { + SourceDetails sourceDetails = SourceDetails.createSourceDetails(request); + List fileIds = getFileIds(datasourceConfiguration); + if (fileIds.isEmpty()) { + TriggerResultDTO triggerResultDTO = new TriggerResultDTO(); + triggerResultDTO.setTrigger(List.of(Map.of( + DISABLED, true, LABEL, "No files available in the datasource", VALUE, "NO_FILES_AVAILABLE"))); + return Mono.just(triggerResultDTO); + } + return aiServerService + .getFilesStatus(fileIds, sourceDetails) + .flatMap(fileStatusDTO -> { + List> response = new ArrayList<>(); + fileStatusDTO.getFiles().forEach(file -> { + Map dropdownOption = new HashMap<>(); + if (!file.isProcessed()) { + dropdownOption.put(LABEL, "(Processing...) " + file.getName()); + } else { + dropdownOption.put(LABEL, file.getName()); + } + dropdownOption.put(VALUE, file.getId()); + dropdownOption.put(DISABLED, !file.isProcessed()); + response.add(dropdownOption); + }); + TriggerResultDTO triggerResultDTO = new TriggerResultDTO(); + triggerResultDTO.setTrigger(response); + return Mono.just(triggerResultDTO); + }) + .onErrorResume( + error -> handleError("An error has occurred while trying to list uploaded files", error)); + } + + protected Mono handleError(String message, Throwable error) { + log.error("{}. Error: {}", message, error.getMessage()); + if (!(error instanceof AppsmithPluginException)) { + error = new AppsmithPluginException(AppsmithPluginError.PLUGIN_ERROR, error.getMessage(), error); + } + return Mono.error(error); + } +} diff --git a/app/server/appsmith-plugins/appsmithAiPlugin/src/main/java/com/external/plugins/services/TriggerServiceImpl.java b/app/server/appsmith-plugins/appsmithAiPlugin/src/main/java/com/external/plugins/services/TriggerServiceImpl.java new file mode 100644 index 00000000000..e4bd7e3734b --- /dev/null +++ b/app/server/appsmith-plugins/appsmithAiPlugin/src/main/java/com/external/plugins/services/TriggerServiceImpl.java @@ -0,0 +1,21 @@ +package com.external.plugins.services; + +import com.appsmith.external.helpers.restApiUtils.connections.APIConnection; +import com.appsmith.external.models.DatasourceConfiguration; +import com.appsmith.external.models.TriggerRequestDTO; +import com.appsmith.external.models.TriggerResultDTO; +import com.fasterxml.jackson.databind.ObjectMapper; +import reactor.core.publisher.Mono; + +public class TriggerServiceImpl extends TriggerServiceCEImpl { + + public TriggerServiceImpl(AiServerService aiServerService, ObjectMapper objectMapper) { + super(aiServerService, objectMapper); + } + + @Override + public Mono executeTrigger( + APIConnection connection, DatasourceConfiguration datasourceConfiguration, TriggerRequestDTO request) { + return super.executeTrigger(connection, datasourceConfiguration, request); + } +} diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ce/DatasourceTriggerSolutionCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ce/DatasourceTriggerSolutionCEImpl.java index c4a571037d2..b73dc33a26d 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ce/DatasourceTriggerSolutionCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ce/DatasourceTriggerSolutionCEImpl.java @@ -101,11 +101,12 @@ public Mono trigger( // If the plugin has overridden and implemented the same, use the plugin result Mono resultFromPluginMono = Mono.zip( - validatedDatasourceStorageMono, pluginMono, pluginExecutorMono) + validatedDatasourceStorageMono, pluginMono, pluginExecutorMono, datasourceMonoCached) .flatMap(tuple -> { final DatasourceStorage datasourceStorage = tuple.getT1(); final Plugin plugin = tuple.getT2(); final PluginExecutor pluginExecutor = tuple.getT3(); + final Datasource datasource = tuple.getT4(); // TODO: Flags are needed here for google sheets integration to support shared drive behind a flag // Once thoroughly tested, this flag can be removed @@ -118,7 +119,7 @@ public Mono trigger( // Now that we have the context (connection details), execute the action. // datasource remains unevaluated for datasource of DBAuth Type Authentication, // However the context comes from evaluated datasource. - .flatMap(resourceContext -> setTenantAndInstanceId(triggerRequestDTO) + .flatMap(resourceContext -> populateTriggerRequestDto(triggerRequestDTO, datasource) .flatMap(updatedTriggerRequestDTO -> ((PluginExecutor) pluginExecutor) .triggerWithFlags( resourceContext.getConnection(), @@ -161,13 +162,15 @@ public Mono trigger( return resultFromPluginMono.switchIfEmpty(defaultResultMono); } - private Mono setTenantAndInstanceId(TriggerRequestDTO triggerRequestDTO) { + private Mono populateTriggerRequestDto( + TriggerRequestDTO triggerRequestDTO, Datasource datasource) { return tenantService .getDefaultTenantId() .zipWith(configService.getInstanceId()) .map(tuple -> { triggerRequestDTO.setTenantId(tuple.getT1()); triggerRequestDTO.setInstanceId(tuple.getT2()); + triggerRequestDTO.setWorkspaceId(datasource.getWorkspaceId()); return triggerRequestDTO; }); } diff --git a/deploy/docker/fs/opt/appsmith/templates/supervisord/application_process/backend.conf b/deploy/docker/fs/opt/appsmith/templates/supervisord/application_process/backend.conf index a9f4ed00ecd..37674e8dd16 100644 --- a/deploy/docker/fs/opt/appsmith/templates/supervisord/application_process/backend.conf +++ b/deploy/docker/fs/opt/appsmith/templates/supervisord/application_process/backend.conf @@ -1,15 +1,15 @@ [program:backend] command=/opt/appsmith/run-with-env.sh /opt/appsmith/run-java.sh -priority=20 -autostart=true autorestart=true -startsecs=20 +autostart=true +priority=20 startretries=3 -stdout_logfile=%(ENV_APPSMITH_LOG_DIR)s/%(program_name)s/%(program_name)s-%(ENV_HOSTNAME)s.log -redirect_stderr=true -stdout_logfile_maxbytes=10MB -stderr_logfile_maxbytes=10MB -stdout_logfile_backups=10 -stderr_logfile_backups=10 -stdout_events_enabled=true +startsecs=20 stderr_events_enabled=true +stderr_logfile=%(ENV_APPSMITH_LOG_DIR)s/%(program_name)s/%(ENV_HOSTNAME)s-stderr.log +stderr_logfile_backups=0 +stderr_logfile_maxbytes=30MB +stdout_events_enabled=true +stdout_logfile=%(ENV_APPSMITH_LOG_DIR)s/%(program_name)s/%(ENV_HOSTNAME)s-stdout.log +stdout_logfile_backups=0 +stdout_logfile_maxbytes=30MB diff --git a/deploy/docker/fs/opt/appsmith/templates/supervisord/application_process/editor.conf b/deploy/docker/fs/opt/appsmith/templates/supervisord/application_process/editor.conf index 8fa54215d50..0efa5a7b4eb 100644 --- a/deploy/docker/fs/opt/appsmith/templates/supervisord/application_process/editor.conf +++ b/deploy/docker/fs/opt/appsmith/templates/supervisord/application_process/editor.conf @@ -1,16 +1,16 @@ [program:editor] command=/opt/appsmith/run-with-env.sh /opt/appsmith/run-caddy.sh -priority=25 -autostart=true autorestart=true -startsecs=0 +autostart=true +priority=25 startretries=3 -stdout_logfile=%(ENV_APPSMITH_LOG_DIR)s/%(program_name)s/access-%(ENV_HOSTNAME)s.log -stderr_logfile=%(ENV_APPSMITH_LOG_DIR)s/%(program_name)s/error-%(ENV_HOSTNAME)s.log -stdout_logfile_maxbytes=10MB -stderr_logfile_maxbytes=10MB -stdout_logfile_backups=2 -stderr_logfile_backups=2 -stdout_events_enabled=true +startsecs=0 stderr_events_enabled=true +stderr_logfile=%(ENV_APPSMITH_LOG_DIR)s/%(program_name)s/%(ENV_HOSTNAME)s-stderr.log +stderr_logfile_backups=0 +stderr_logfile_maxbytes=30MB +stdout_events_enabled=true +stdout_logfile=%(ENV_APPSMITH_LOG_DIR)s/%(program_name)s/%(ENV_HOSTNAME)s-stdout.log +stdout_logfile_backups=0 +stdout_logfile_maxbytes=30MB stopsignal=QUIT diff --git a/deploy/docker/fs/opt/appsmith/templates/supervisord/application_process/rts.conf b/deploy/docker/fs/opt/appsmith/templates/supervisord/application_process/rts.conf index 6900f17a17f..2ff862db027 100644 --- a/deploy/docker/fs/opt/appsmith/templates/supervisord/application_process/rts.conf +++ b/deploy/docker/fs/opt/appsmith/templates/supervisord/application_process/rts.conf @@ -1,16 +1,16 @@ [program:rts] directory=/opt/appsmith/rts/bundle command=/opt/appsmith/run-with-env.sh node server.js -priority=15 -autostart=true autorestart=true -startsecs=0 +autostart=true +priority=15 startretries=3 -stdout_logfile=%(ENV_APPSMITH_LOG_DIR)s/%(program_name)s/%(program_name)s-%(ENV_HOSTNAME)s.log -redirect_stderr=true -stdout_logfile_maxbytes=10MB -stderr_logfile_maxbytes=10MB -stdout_logfile_backups=2 -stderr_logfile_backups=2 -stdout_events_enabled=true +startsecs=0 stderr_events_enabled=true +stderr_logfile=%(ENV_APPSMITH_LOG_DIR)s/%(program_name)s/%(ENV_HOSTNAME)s-stderr.log +stderr_logfile_backups=0 +stderr_logfile_maxbytes=30MB +stdout_events_enabled=true +stdout_logfile=%(ENV_APPSMITH_LOG_DIR)s/%(program_name)s/%(ENV_HOSTNAME)s-stdout.log +stdout_logfile_backups=0 +stdout_logfile_maxbytes=30MB diff --git a/deploy/docker/fs/opt/appsmith/templates/supervisord/mongodb.conf b/deploy/docker/fs/opt/appsmith/templates/supervisord/mongodb.conf index 7e7b0a7bd39..3072b0fe5f1 100644 --- a/deploy/docker/fs/opt/appsmith/templates/supervisord/mongodb.conf +++ b/deploy/docker/fs/opt/appsmith/templates/supervisord/mongodb.conf @@ -1,16 +1,16 @@ [program:mongodb] directory=/appsmith-stacks/data/mongodb command=mongod --port 27017 --dbpath . --logpath %(ENV_APPSMITH_LOG_DIR)s/%(program_name)s/db.log --replSet mr1 --keyFile %(ENV_MONGODB_TMP_KEY_PATH)s --bind_ip localhost -priority=10 -autostart=true autorestart=true -startsecs=10 +autostart=true +priority=10 startretries=3 -stdout_logfile=%(ENV_APPSMITH_LOG_DIR)s/%(program_name)s/%(program_name)s.log -redirect_stderr=true -stdout_logfile_maxbytes=10MB -stderr_logfile_maxbytes=10MB -stdout_logfile_backups=2 -stderr_logfile_backups=2 -stdout_events_enabled=true +startsecs=10 stderr_events_enabled=true +stderr_logfile=%(ENV_APPSMITH_LOG_DIR)s/%(program_name)s/%(ENV_HOSTNAME)s-stderr.log +stderr_logfile_backups=0 +stderr_logfile_maxbytes=30MB +stdout_events_enabled=true +stdout_logfile=%(ENV_APPSMITH_LOG_DIR)s/%(program_name)s/%(ENV_HOSTNAME)s-stdout.log +stdout_logfile_backups=0 +stdout_logfile_maxbytes=30MB diff --git a/deploy/docker/fs/opt/appsmith/templates/supervisord/postgres.conf b/deploy/docker/fs/opt/appsmith/templates/supervisord/postgres.conf index 2dd1aa8d059..8886239f88e 100644 --- a/deploy/docker/fs/opt/appsmith/templates/supervisord/postgres.conf +++ b/deploy/docker/fs/opt/appsmith/templates/supervisord/postgres.conf @@ -2,15 +2,14 @@ directory=/appsmith-stacks/data/postgres/main user=postgres command=/opt/appsmith/run-postgres.sh -autostart=true autorestart=true +autostart=true startretries=3 -stdout_logfile=%(ENV_APPSMITH_LOG_DIR)s/%(program_name)s/%(program_name)s.log -redirect_stderr=true -stdout_logfile_maxbytes=10MB -stderr_logfile_maxbytes=10MB -stdout_logfile_backups=2 -stderr_logfile_backups=2 -stdout_events_enabled=true stderr_events_enabled=true - +stderr_logfile=%(ENV_APPSMITH_LOG_DIR)s/%(program_name)s/%(ENV_HOSTNAME)s-stderr.log +stderr_logfile_backups=0 +stderr_logfile_maxbytes=30MB +stdout_events_enabled=true +stdout_logfile=%(ENV_APPSMITH_LOG_DIR)s/%(program_name)s/%(ENV_HOSTNAME)s-stdout.log +stdout_logfile_backups=0 +stdout_logfile_maxbytes=30MB diff --git a/deploy/docker/fs/opt/appsmith/templates/supervisord/redis.conf b/deploy/docker/fs/opt/appsmith/templates/supervisord/redis.conf index 5fb91c84fe9..e02ef0a7bec 100644 --- a/deploy/docker/fs/opt/appsmith/templates/supervisord/redis.conf +++ b/deploy/docker/fs/opt/appsmith/templates/supervisord/redis.conf @@ -3,16 +3,16 @@ directory=/etc/redis ; The `--save` is for saving session data to disk more often, so recent sessions aren't cleared on restart. ; The empty string to `--logfile` is for logging to stdout so that supervisor can capture it. command=redis-server --save 15 1 --dir /appsmith-stacks/data/redis --daemonize no --logfile "" -priority=5 -autostart=true autorestart=true -startsecs=0 +autostart=true +priority=5 startretries=3 -stdout_logfile=%(ENV_APPSMITH_LOG_DIR)s/%(program_name)s/%(program_name)s.log -redirect_stderr=true -stdout_logfile_maxbytes=10MB -stderr_logfile_maxbytes=10MB -stdout_logfile_backups=2 -stderr_logfile_backups=2 -stdout_events_enabled=true +startsecs=0 stderr_events_enabled=true +stderr_logfile=%(ENV_APPSMITH_LOG_DIR)s/%(program_name)s/%(ENV_HOSTNAME)s-stderr.log +stderr_logfile_backups=0 +stderr_logfile_maxbytes=30MB +stdout_events_enabled=true +stdout_logfile=%(ENV_APPSMITH_LOG_DIR)s/%(program_name)s/%(ENV_HOSTNAME)s-stdout.log +stdout_logfile_backups=0 +stdout_logfile_maxbytes=30MB