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 (
+
+ );
+}
+
+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)}
;
-}
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}
/>
-
-
- {DEPLOY_MENU_OPTION()}
-
+
+
+
+ {DEPLOY_MENU_OPTION()}
+
+
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