From 584aaad004bd2e8fdca096c13569e2f1df329732 Mon Sep 17 00:00:00 2001 From: Aditya Pachauri Date: Fri, 18 Jul 2025 16:38:52 +0530 Subject: [PATCH 1/5] chore(E-6750/redirect ion-url-without-query-string-vb): logic for redirection improved --- src/visualBuilder/utils/getVisualBuilderRedirectionUrl.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/visualBuilder/utils/getVisualBuilderRedirectionUrl.ts b/src/visualBuilder/utils/getVisualBuilderRedirectionUrl.ts index 955e466c..81d0e3e6 100644 --- a/src/visualBuilder/utils/getVisualBuilderRedirectionUrl.ts +++ b/src/visualBuilder/utils/getVisualBuilderRedirectionUrl.ts @@ -18,7 +18,11 @@ export default function getVisualBuilderRedirectionUrl(): URL { searchParams.set("environment", environment); } - searchParams.set("target-url", window.location.href); + // Set the current page (without query string) as the target URL + searchParams.set( + "target-url", + window.location.origin + window.location.pathname + ); // get the locale from the data cslp attribute const elementWithDataCslp = document.querySelector(`[data-cslp]`); From 8c9394078f9c139107e311047f5a42766a51d9a8 Mon Sep 17 00:00:00 2001 From: Aditya Pachauri Date: Mon, 21 Jul 2025 10:36:59 +0530 Subject: [PATCH 2/5] chore(VE-6750): test cases added --- .talismanrc | 2 + .../getVisualBuilderRedirectionUrl.test.ts | 121 +++++++++++------- 2 files changed, 79 insertions(+), 44 deletions(-) diff --git a/.talismanrc b/.talismanrc index 97637673..7d715eb6 100644 --- a/.talismanrc +++ b/.talismanrc @@ -10,4 +10,6 @@ fileignoreconfig: checksum: 3badd6a142456b6a361569e6fc546349a38ac6b366bef7fd5255d1e93220444e - filename: src/visualBuilder/components/Collab/ThreadPopup/__test__/CommentTextArea.test.tsx checksum: d0ef271ee5381d9feab06bda6e7e89bd0a882fee87495627bd811c1f0a5459c7 + - filename: src/visualBuilder/utils/__test__/getVisualBuilderRedirectionUrl.test.ts + checksum: 5a4ec2ca7f5cc6342b1d74c954637f6bab0b4a55f46696ea0a7f57f7f4b16457 version: "1.0" diff --git a/src/visualBuilder/utils/__test__/getVisualBuilderRedirectionUrl.test.ts b/src/visualBuilder/utils/__test__/getVisualBuilderRedirectionUrl.test.ts index e7232ad6..df9b9807 100644 --- a/src/visualBuilder/utils/__test__/getVisualBuilderRedirectionUrl.test.ts +++ b/src/visualBuilder/utils/__test__/getVisualBuilderRedirectionUrl.test.ts @@ -1,87 +1,120 @@ -import { describe, it, expect, vi } from 'vitest'; -import getVisualBuilderRedirectionUrl from '../getVisualBuilderRedirectionUrl'; -import Config from '../../../configManager/configManager'; -import { extractDetailsFromCslp } from '../../../cslp'; +import { describe, it, expect, vi } from "vitest"; +import getVisualBuilderRedirectionUrl from "../getVisualBuilderRedirectionUrl"; +import Config from "../../../configManager/configManager"; +import { extractDetailsFromCslp } from "../../../cslp"; -vi.mock('../../../configManager/configManager'); -vi.mock('../../../cslp'); +vi.mock("../../../configManager/configManager"); +vi.mock("../../../cslp"); -describe('getVisualBuilderRedirectionUrl', () => { +describe("getVisualBuilderRedirectionUrl", () => { beforeEach(() => { vi.clearAllMocks(); - delete window.location - window.location = new URL('https://example.com') + delete window.location; + window.location = new URL("https://example.com"); }); - it('should return the correct URL with branch and environment', () => { + it("should return the correct URL with branch and environment", () => { Config.get.mockReturnValue({ stackDetails: { - branch: 'main', - apiKey: '12345', - environment: 'production', - locale: 'en-US' + branch: "main", + apiKey: "12345", + environment: "production", + locale: "en-US", }, clientUrlParams: { - url: 'https://app.example.com' - } + url: "https://app.example.com", + }, }); const result = getVisualBuilderRedirectionUrl(); - expect(result.toString()).toBe('https://app.example.com/#!/stack/12345/visual-builder?branch=main&environment=production&target-url=https%3A%2F%2Fexample.com%2F&locale=en-US'); + expect(result.toString()).toBe( + "https://app.example.com/#!/stack/12345/visual-builder?branch=main&environment=production&target-url=https%3A%2F%2Fexample.com%2F&locale=en-US" + ); }); - it('should return the correct URL without branch and environment', () => { + it("should return the correct URL without branch and environment", () => { Config.get.mockReturnValue({ stackDetails: { - branch: '', - apiKey: '12345', - environment: '', - locale: 'en-US' + branch: "", + apiKey: "12345", + environment: "", + locale: "en-US", }, clientUrlParams: { - url: 'https://app.example.com' - } + url: "https://app.example.com", + }, }); const result = getVisualBuilderRedirectionUrl(); - expect(result.toString()).toBe('https://app.example.com/#!/stack/12345/visual-builder?target-url=https%3A%2F%2Fexample.com%2F&locale=en-US'); + expect(result.toString()).toBe( + "https://app.example.com/#!/stack/12345/visual-builder?target-url=https%3A%2F%2Fexample.com%2F&locale=en-US" + ); }); - it('should use locale from data-cslp attribute if present', () => { + it("should use locale from data-cslp attribute if present", () => { document.body.innerHTML = '
'; Config.get.mockReturnValue({ stackDetails: { - branch: 'main', - apiKey: '12345', - environment: 'production', - locale: 'en-US' + branch: "main", + apiKey: "12345", + environment: "production", + locale: "en-US", }, clientUrlParams: { - url: 'https://app.example.com' - } + url: "https://app.example.com", + }, }); - extractDetailsFromCslp.mockReturnValue({ locale: 'fr-FR' }); + extractDetailsFromCslp.mockReturnValue({ locale: "fr-FR" }); + + const result = getVisualBuilderRedirectionUrl(); + expect(result.toString()).toBe( + "https://app.example.com/#!/stack/12345/visual-builder?branch=main&environment=production&target-url=https%3A%2F%2Fexample.com%2F&locale=fr-FR" + ); + }); + + it("should return the correct URL without locale", () => { + document.body.innerHTML = ""; + Config.get.mockReturnValue({ + stackDetails: { + branch: "main", + apiKey: "12345", + environment: "production", + locale: "", + }, + clientUrlParams: { + url: "https://app.example.com", + }, + }); const result = getVisualBuilderRedirectionUrl(); - expect(result.toString()).toBe('https://app.example.com/#!/stack/12345/visual-builder?branch=main&environment=production&target-url=https%3A%2F%2Fexample.com%2F&locale=fr-FR'); + expect(result.toString()).toBe( + "https://app.example.com/#!/stack/12345/visual-builder?branch=main&environment=production&target-url=https%3A%2F%2Fexample.com%2F" + ); }); - it('should return the correct URL without locale', () => { - document.body.innerHTML = ''; + it("should return the correct URL without query parameters in target-url", () => { + Object.defineProperty(window, "location", { + writable: true, + value: new URL("https://example.com/page?query=test"), + }); + Config.get.mockReturnValue({ stackDetails: { - branch: 'main', - apiKey: '12345', - environment: 'production', - locale: '' + branch: "main", + apiKey: "12345", + environment: "production", + locale: "en-US", }, clientUrlParams: { - url: 'https://app.example.com' - } + url: "https://app.example.com", + }, }); const result = getVisualBuilderRedirectionUrl(); - expect(result.toString()).toBe('https://app.example.com/#!/stack/12345/visual-builder?branch=main&environment=production&target-url=https%3A%2F%2Fexample.com%2F'); + expect(result.toString()).toContain( + "target-url=https%3A%2F%2Fexample.com%2Fpage" + ); + expect(result.toString()).not.toContain("?query=test"); }); -}); \ No newline at end of file +}); From 804e48760ab6b71752691ab0f61e092f664a9678 Mon Sep 17 00:00:00 2001 From: Aditya Pachauri Date: Mon, 21 Jul 2025 12:42:44 +0530 Subject: [PATCH 3/5] chore(VE-6750/redirection-url-without-query-string-vb): hash routing logic added --- .../utils/getVisualBuilderRedirectionUrl.ts | 35 +++++++++++++++---- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/src/visualBuilder/utils/getVisualBuilderRedirectionUrl.ts b/src/visualBuilder/utils/getVisualBuilderRedirectionUrl.ts index 81d0e3e6..49f452be 100644 --- a/src/visualBuilder/utils/getVisualBuilderRedirectionUrl.ts +++ b/src/visualBuilder/utils/getVisualBuilderRedirectionUrl.ts @@ -11,19 +11,40 @@ export default function getVisualBuilderRedirectionUrl(): URL { const { url: appUrl } = clientUrlParams; const searchParams = new URLSearchParams(); + + const hash = window.location.hash; + const isHashSlash = hash.startsWith("#/"); + const isHashBang = hash.startsWith("#!/"); + const isNoSlash = hash.length > 1 && !isHashSlash && !isHashBang; + const isHashRouting = isHashSlash || isHashBang || isNoSlash; + + const url = new URL(window.location.href); + // remove query parameters from the url + url.search = ""; + if (isHashRouting) { + // if the hash is #!/about-us or #/about-us or #about-us, we want /about-us + let pathFromHash; + if (isHashBang) { + pathFromHash = hash.substring(2); + } else if (isHashSlash) { + pathFromHash = hash.substring(1); + } else { + pathFromHash = "/" + hash.substring(1); + } + url.pathname = (url.pathname + pathFromHash).replace(/\/\//g, "/"); + url.hash = ""; + } else { + url.hash = ""; + } + const targetUrl = url.toString().replace(/\/$/, ""); + + searchParams.set("target-url", targetUrl); if (branch) { searchParams.set("branch", branch); } if (environment) { searchParams.set("environment", environment); } - - // Set the current page (without query string) as the target URL - searchParams.set( - "target-url", - window.location.origin + window.location.pathname - ); - // get the locale from the data cslp attribute const elementWithDataCslp = document.querySelector(`[data-cslp]`); From 13647eadb66e1ffcf1e04ff557666c02b1ff8508 Mon Sep 17 00:00:00 2001 From: Aditya Pachauri Date: Mon, 21 Jul 2025 13:05:51 +0530 Subject: [PATCH 4/5] chore(VE-6750/redirection-url-without-query-string-vb): hash routing and query string combined logic and test cases added --- .talismanrc | 2 +- .../getVisualBuilderRedirectionUrl.test.ts | 98 ++++++++++++++++++- .../utils/getVisualBuilderRedirectionUrl.ts | 4 +- 3 files changed, 98 insertions(+), 6 deletions(-) diff --git a/.talismanrc b/.talismanrc index 7d715eb6..7a69294b 100644 --- a/.talismanrc +++ b/.talismanrc @@ -11,5 +11,5 @@ fileignoreconfig: - filename: src/visualBuilder/components/Collab/ThreadPopup/__test__/CommentTextArea.test.tsx checksum: d0ef271ee5381d9feab06bda6e7e89bd0a882fee87495627bd811c1f0a5459c7 - filename: src/visualBuilder/utils/__test__/getVisualBuilderRedirectionUrl.test.ts - checksum: 5a4ec2ca7f5cc6342b1d74c954637f6bab0b4a55f46696ea0a7f57f7f4b16457 + checksum: c50dc0a34b3aeb8ff50ac36af38e4ace9b6ee137522faa3d82ae2309ee285040 version: "1.0" diff --git a/src/visualBuilder/utils/__test__/getVisualBuilderRedirectionUrl.test.ts b/src/visualBuilder/utils/__test__/getVisualBuilderRedirectionUrl.test.ts index df9b9807..a8503245 100644 --- a/src/visualBuilder/utils/__test__/getVisualBuilderRedirectionUrl.test.ts +++ b/src/visualBuilder/utils/__test__/getVisualBuilderRedirectionUrl.test.ts @@ -28,7 +28,7 @@ describe("getVisualBuilderRedirectionUrl", () => { const result = getVisualBuilderRedirectionUrl(); expect(result.toString()).toBe( - "https://app.example.com/#!/stack/12345/visual-builder?branch=main&environment=production&target-url=https%3A%2F%2Fexample.com%2F&locale=en-US" + "https://app.example.com/#!/stack/12345/visual-builder?target-url=https%3A%2F%2Fexample.com&branch=main&environment=production&locale=en-US" ); }); @@ -47,7 +47,7 @@ describe("getVisualBuilderRedirectionUrl", () => { const result = getVisualBuilderRedirectionUrl(); expect(result.toString()).toBe( - "https://app.example.com/#!/stack/12345/visual-builder?target-url=https%3A%2F%2Fexample.com%2F&locale=en-US" + "https://app.example.com/#!/stack/12345/visual-builder?target-url=https%3A%2F%2Fexample.com&locale=en-US" ); }); @@ -69,7 +69,7 @@ describe("getVisualBuilderRedirectionUrl", () => { const result = getVisualBuilderRedirectionUrl(); expect(result.toString()).toBe( - "https://app.example.com/#!/stack/12345/visual-builder?branch=main&environment=production&target-url=https%3A%2F%2Fexample.com%2F&locale=fr-FR" + "https://app.example.com/#!/stack/12345/visual-builder?target-url=https%3A%2F%2Fexample.com&branch=main&environment=production&locale=fr-FR" ); }); @@ -89,7 +89,7 @@ describe("getVisualBuilderRedirectionUrl", () => { const result = getVisualBuilderRedirectionUrl(); expect(result.toString()).toBe( - "https://app.example.com/#!/stack/12345/visual-builder?branch=main&environment=production&target-url=https%3A%2F%2Fexample.com%2F" + "https://app.example.com/#!/stack/12345/visual-builder?target-url=https%3A%2F%2Fexample.com&branch=main&environment=production" ); }); @@ -117,4 +117,94 @@ describe("getVisualBuilderRedirectionUrl", () => { ); expect(result.toString()).not.toContain("?query=test"); }); + it("should return the correct URL with slash type hash routing", () => { + Object.defineProperty(window, "location", { + writable: true, + value: new URL("https://example.com/#/page"), + }); + Config.get.mockReturnValue({ + stackDetails: { + branch: "main", + apiKey: "12345", + environment: "production", + locale: "en-US", + }, + clientUrlParams: { + url: "https://app.example.com", + }, + }); + + const result = getVisualBuilderRedirectionUrl(); + expect(result.toString()).toBe( + "https://app.example.com/#!/stack/12345/visual-builder?target-url=https%3A%2F%2Fexample.com%2Fpage&branch=main&environment=production&locale=en-US" + ); + }); + + it("should return the correct URL with no slash type hash routing", () => { + Object.defineProperty(window, "location", { + writable: true, + value: new URL("https://example.com/#page"), + }); + Config.get.mockReturnValue({ + stackDetails: { + branch: "main", + apiKey: "12345", + environment: "production", + locale: "en-US", + }, + clientUrlParams: { + url: "https://app.example.com", + }, + }); + + const result = getVisualBuilderRedirectionUrl(); + expect(result.toString()).toBe( + "https://app.example.com/#!/stack/12345/visual-builder?target-url=https%3A%2F%2Fexample.com%2Fpage&branch=main&environment=production&locale=en-US" + ); + }); + it("should return the correct URL with hash bang type hash routing", () => { + Object.defineProperty(window, "location", { + writable: true, + value: new URL("https://example.com/#!/page"), + }); + Config.get.mockReturnValue({ + stackDetails: { + branch: "main", + apiKey: "12345", + environment: "production", + locale: "en-US", + }, + clientUrlParams: { + url: "https://app.example.com", + }, + }); + + const result = getVisualBuilderRedirectionUrl(); + expect(result.toString()).toBe( + "https://app.example.com/#!/stack/12345/visual-builder?target-url=https%3A%2F%2Fexample.com%2Fpage&branch=main&environment=production&locale=en-US" + ); + }); + + it("should return the correct URL with hash bang type hash routing", () => { + Object.defineProperty(window, "location", { + writable: true, + value: new URL("https://example.com/#!/page?query=test"), + }); + Config.get.mockReturnValue({ + stackDetails: { + branch: "main", + apiKey: "12345", + environment: "production", + locale: "en-US", + }, + clientUrlParams: { + url: "https://app.example.com", + }, + }); + + const result = getVisualBuilderRedirectionUrl(); + expect(result.toString()).toBe( + "https://app.example.com/#!/stack/12345/visual-builder?target-url=https%3A%2F%2Fexample.com%2Fpage&branch=main&environment=production&locale=en-US" + ); + }); }); diff --git a/src/visualBuilder/utils/getVisualBuilderRedirectionUrl.ts b/src/visualBuilder/utils/getVisualBuilderRedirectionUrl.ts index 49f452be..17e5b374 100644 --- a/src/visualBuilder/utils/getVisualBuilderRedirectionUrl.ts +++ b/src/visualBuilder/utils/getVisualBuilderRedirectionUrl.ts @@ -31,7 +31,9 @@ export default function getVisualBuilderRedirectionUrl(): URL { } else { pathFromHash = "/" + hash.substring(1); } - url.pathname = (url.pathname + pathFromHash).replace(/\/\//g, "/"); + // remove query parameters from the path if we have both hash routing and query string + let onlyPathname = pathFromHash.split("?")[0]; + url.pathname = (url.pathname + onlyPathname).replace(/\/\//g, "/"); url.hash = ""; } else { url.hash = ""; From c0f6a83b8283fb2cd66e55dbe57e56645a27189e Mon Sep 17 00:00:00 2001 From: Aditya Pachauri Date: Mon, 21 Jul 2025 16:43:59 +0530 Subject: [PATCH 5/5] chore(VE-6750/redirection-query-string): test cases fixed --- .../utils/__test__/generateStartEditingButton.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/visualBuilder/utils/__test__/generateStartEditingButton.test.ts b/src/visualBuilder/utils/__test__/generateStartEditingButton.test.ts index e652fffe..21684dcc 100644 --- a/src/visualBuilder/utils/__test__/generateStartEditingButton.test.ts +++ b/src/visualBuilder/utils/__test__/generateStartEditingButton.test.ts @@ -39,7 +39,7 @@ describe("generateStartEditingButton", () => { button?.click(); expect(button?.getAttribute("href")).toBe( - "https://app.contentstack.com/#!/stack//visual-builder?branch=main&target-url=http%3A%2F%2Flocalhost%3A3000%2F&locale=en-us" + "https://app.contentstack.com/#!/stack//visual-builder?target-url=http%3A%2F%2Flocalhost%3A3000&branch=main&locale=en-us" ); }); @@ -57,7 +57,7 @@ describe("generateStartEditingButton", () => { button?.click(); expect(button?.getAttribute("href")).toBe( - "https://app.contentstack.com/#!/stack//visual-builder?branch=main&target-url=http%3A%2F%2Flocalhost%3A3000%2F&locale=en-us" + "https://app.contentstack.com/#!/stack//visual-builder?target-url=http%3A%2F%2Flocalhost%3A3000&branch=main&locale=en-us" ); }); });