diff --git a/code/core/src/manager-api/modules/url.ts b/code/core/src/manager-api/modules/url.ts index 67b94017b0bf..ff5f5efc3031 100644 --- a/code/core/src/manager-api/modules/url.ts +++ b/code/core/src/manager-api/modules/url.ts @@ -261,7 +261,21 @@ export const init: ModuleFn = (moduleArgs) => { : global.PREVIEW_URL || `${managerBase.replace(/\/[^/]*\.html$/, '').replace(/\/?$/, '/')}iframe.html`; - const refParam = refId ? `&refId=${encodeURIComponent(refId)}` : ''; + const isAbsolutePreviewUrl = /^[a-zA-Z][a-zA-Z\d+\-.]*:/.test(previewBase); + const resolvedPreviewHref = isAbsolutePreviewUrl + ? previewBase + : new URL(previewBase, global.window.location.href).href; + const previewUrlObject = new URL(resolvedPreviewHref); + previewUrlObject.searchParams.set('id', storyId); + previewUrlObject.searchParams.set('viewMode', viewMode); + if (refId) { + previewUrlObject.searchParams.set('refId', refId); + } + + const previewPathQuery = `${previewUrlObject.pathname}${previewUrlObject.search}`; + const previewHash = previewUrlObject.hash; + const previewHrefPrefix = isAbsolutePreviewUrl ? previewUrlObject.origin : ''; + const { args = '', globals = '', ...otherParams } = queryParams; let argsParam = inheritArgs ? mergeSerializedParams(customQueryParams?.args ?? '', args) @@ -283,9 +297,11 @@ export const init: ModuleFn = (moduleArgs) => { customManagerParams = customManagerParams && `&${customManagerParams}`; customPreviewParams = customPreviewParams && `&${customPreviewParams}`; + const previewSuffix = `${argsParam}${refId ? '' : globalsParam}${customPreviewParams}`; + return { managerHref: `${managerBase}?path=/${viewMode}/${refId ? `${refId}_` : ''}${storyId}${argsParam}${globalsParam}${customManagerParams}`, - previewHref: `${previewBase}?id=${storyId}&viewMode=${viewMode}${refParam}${argsParam}${refId ? '' : globalsParam}${customPreviewParams}`, + previewHref: `${previewHrefPrefix}${previewPathQuery}${previewSuffix}${previewHash}`, }; }, getQueryParam(key) { diff --git a/code/core/src/manager-api/tests/url.test.js b/code/core/src/manager-api/tests/url.test.js index 30485a43c7a6..234b6dce20ef 100644 --- a/code/core/src/manager-api/tests/url.test.js +++ b/code/core/src/manager-api/tests/url.test.js @@ -504,6 +504,26 @@ describe('getStoryHrefs', () => { delete global.PREVIEW_URL; }); + it('supports PREVIEW_URL override when the URL already has query parameters', () => { + global.PREVIEW_URL = 'http://localhost:6007/?custom=true'; + const { api, state } = initURL({ + store, + provider: { channel: new EventEmitter() }, + state: { location: { pathname: '/', search: '' } }, + navigate: vi.fn(), + fullAPI: { getCurrentStoryData: () => ({ id: 'test--story' }) }, + }); + store.setState(state); + + const { previewHref } = api.getStoryHrefs('test--story'); + const parsed = new URL(previewHref); + expect(parsed.searchParams.get('custom')).toBe('true'); + expect(parsed.searchParams.get('id')).toBe('test--story'); + expect(parsed.searchParams.get('viewMode')).toBe('story'); + expect(/\?[^\s#]*\?/.test(previewHref)).toBe(false); + delete global.PREVIEW_URL; + }); + it('correctly links from /index.html', () => { const { api, state } = initURL({ store,