diff --git a/packages/frontend/core/src/components/hooks/affine/use-share-url.ts b/packages/frontend/core/src/components/hooks/affine/use-share-url.ts index 71e1d0e732..787b2b353a 100644 --- a/packages/frontend/core/src/components/hooks/affine/use-share-url.ts +++ b/packages/frontend/core/src/components/hooks/affine/use-share-url.ts @@ -27,7 +27,7 @@ export const generateUrl = ({ pageId, blockIds, elementIds, - shareMode, + shareMode: mode, xywh, // not needed currently }: UseSharingUrl) => { // Base URL construction @@ -36,13 +36,8 @@ export const generateUrl = ({ try { const url = new URL(`/workspace/${workspaceId}/${pageId}`, baseUrl); - const search = toURLSearchParams({ - mode: shareMode, - blockIds, - elementIds, - xywh, - }); - if (search) url.search = search.toString(); + const search = toURLSearchParams({ mode, blockIds, elementIds, xywh }); + if (search?.size) url.search = search.toString(); return url.toString(); } catch { return null; diff --git a/packages/frontend/core/src/desktop/pages/workspace/detail-page/detail-page.tsx b/packages/frontend/core/src/desktop/pages/workspace/detail-page/detail-page.tsx index 3481d61f26..a62b55dabc 100644 --- a/packages/frontend/core/src/desktop/pages/workspace/detail-page/detail-page.tsx +++ b/packages/frontend/core/src/desktop/pages/workspace/detail-page/detail-page.tsx @@ -175,16 +175,21 @@ const DetailPageImpl = memo(function DetailPageImpl() { refNodeSlots.docLinkClicked.on(({ pageId, params }) => { if (params) { const { mode, blockIds, elementIds } = params; - return jumpToPageBlock( + jumpToPageBlock( docCollection.id, pageId, mode, blockIds, elementIds ); + return; } - return openPage(docCollection.id, pageId); + if (editor.doc.id === pageId) { + return; + } + + openPage(docCollection.id, pageId); }) ); } diff --git a/packages/frontend/core/src/desktop/pages/workspace/share/share-page.tsx b/packages/frontend/core/src/desktop/pages/workspace/share/share-page.tsx index 42ad5c7562..40f437eb2f 100644 --- a/packages/frontend/core/src/desktop/pages/workspace/share/share-page.tsx +++ b/packages/frontend/core/src/desktop/pages/workspace/share/share-page.tsx @@ -247,13 +247,12 @@ const SharePageInner = ({ refNodeSlots.docLinkClicked.on(({ pageId, params }) => { if (params) { const { mode, blockIds, elementIds } = params; - return jumpToPageBlock( - workspaceId, - pageId, - mode, - blockIds, - elementIds - ); + jumpToPageBlock(workspaceId, pageId, mode, blockIds, elementIds); + return; + } + + if (editor.doc.id === pageId) { + return; } return openPage(workspaceId, pageId); diff --git a/packages/frontend/core/src/modules/docs-search/services/docs-search.ts b/packages/frontend/core/src/modules/docs-search/services/docs-search.ts index 9436abf8e5..b5fc1c3cf0 100644 --- a/packages/frontend/core/src/modules/docs-search/services/docs-search.ts +++ b/packages/frontend/core/src/modules/docs-search/services/docs-search.ts @@ -1,4 +1,5 @@ import { toURLSearchParams } from '@affine/core/modules/navigation'; +import type { ReferenceParams } from '@blocksuite/blocks'; import type { WorkspaceService } from '@toeverything/infra'; import { fromPromise, @@ -278,17 +279,14 @@ export class DocsSearchService extends Service { } ); - const refs: { - docId: string; - mode?: string; - blockIds?: string[]; - elementIds?: string[]; - }[] = nodes.flatMap(node => { - const { ref } = node.fields; - return typeof ref === 'string' - ? [JSON.parse(ref)] - : ref.map(item => JSON.parse(item)); - }); + const refs: ({ docId: string } & ReferenceParams)[] = nodes.flatMap( + node => { + const { ref } = node.fields; + return typeof ref === 'string' + ? [JSON.parse(ref)] + : ref.map(item => JSON.parse(item)); + } + ); const docData = await this.indexer.docIndex.getAll( Array.from(new Set(refs.map(ref => ref.docId))) @@ -352,17 +350,14 @@ export class DocsSearchService extends Service { .pipe( switchMap(({ nodes }) => { return fromPromise(async () => { - const refs: { - docId: string; - mode?: string; - blockIds?: string[]; - elementIds?: string[]; - }[] = nodes.flatMap(node => { - const { ref } = node.fields; - return typeof ref === 'string' - ? [JSON.parse(ref)] - : ref.map(item => JSON.parse(item)); - }); + const refs: ({ docId: string } & ReferenceParams)[] = nodes.flatMap( + node => { + const { ref } = node.fields; + return typeof ref === 'string' + ? [JSON.parse(ref)] + : ref.map(item => JSON.parse(item)); + } + ); const docData = await this.indexer.docIndex.getAll( Array.from(new Set(refs.map(ref => ref.docId))) diff --git a/packages/frontend/core/src/modules/navigation/__tests__/utils.spec.ts b/packages/frontend/core/src/modules/navigation/__tests__/utils.spec.ts index f6899272f5..092d2c7ae8 100644 --- a/packages/frontend/core/src/modules/navigation/__tests__/utils.spec.ts +++ b/packages/frontend/core/src/modules/navigation/__tests__/utils.spec.ts @@ -1,6 +1,6 @@ import { afterEach } from 'node:test'; -import { beforeEach, expect, test, vi } from 'vitest'; +import { beforeEach, describe, expect, test, vi } from 'vitest'; import { resolveLinkToDoc, toURLSearchParams } from '../utils'; @@ -84,12 +84,64 @@ const testCases: [string, ReturnType][] = [ docId: '-Uge-K6SYcAbcNYfQ5U-j', }, ], + [ + 'http//localhost:8000/workspace/48__RTCSwASvWZxyAk3Jw/-Uge-K6SYcAbcNYfQ5U-j?mode=edgeless&elementIds=,yyyy,', + { + workspaceId: '48__RTCSwASvWZxyAk3Jw', + docId: '-Uge-K6SYcAbcNYfQ5U-j', + mode: 'edgeless', + elementIds: ['yyyy'], + }, + ], ]; for (const [input, expected] of testCases) { defineTest(input, expected); } +// self-hosted +describe('resolveLinkToDoc in self-hosted', () => { + beforeEach(() => { + vi.unstubAllGlobals(); + vi.stubGlobal('location', { origin: 'https://local.first' }); + }); + + const testCases: [string, ReturnType][] = [ + ['http://example.com/', null], + [ + '/workspace/48__RTCSwASvWZxyAk3Jw/-Uge-K6SYcAbcNYfQ5U-j?blockIds=xxxx', + { + workspaceId: '48__RTCSwASvWZxyAk3Jw', + docId: '-Uge-K6SYcAbcNYfQ5U-j', + blockIds: ['xxxx'], + }, + ], + [ + 'http://affine.pro/workspace/48__RTCSwASvWZxyAk3Jw/-Uge-K6SYcAbcNYfQ5U-j?blockIds=xxxx', + { + workspaceId: '48__RTCSwASvWZxyAk3Jw', + docId: '-Uge-K6SYcAbcNYfQ5U-j', + blockIds: ['xxxx'], + }, + ], + [ + 'https://local.first/workspace/48__RTCSwASvWZxyAk3Jw/-Uge-K6SYcAbcNYfQ5U-j?blockIds=xxxx', + { + workspaceId: '48__RTCSwASvWZxyAk3Jw', + docId: '-Uge-K6SYcAbcNYfQ5U-j', + blockIds: ['xxxx'], + }, + ], + ]; + + for (const [input, expected] of testCases) { + test(`resolveLinkToDoc(${input})InSelfHosted`, () => { + const result = resolveLinkToDoc(input); + expect(result).toEqual(expected); + }); + } +}); + function defineTestWithToURLSearchParams( input?: Partial>, expected?: ReturnType diff --git a/packages/frontend/core/src/modules/navigation/utils.ts b/packages/frontend/core/src/modules/navigation/utils.ts index 0700868ec8..c1f7db8ef1 100644 --- a/packages/frontend/core/src/modules/navigation/utils.ts +++ b/packages/frontend/core/src/modules/navigation/utils.ts @@ -3,23 +3,27 @@ import { isNil, pick, pickBy } from 'lodash-es'; import type { ParsedQuery, ParseOptions } from 'query-string'; import queryString from 'query-string'; -function maybeAffineOrigin(origin: string) { +function maybeAffineOrigin(origin: string, baseUrl: string) { return ( origin.startsWith('file://') || origin.startsWith('affine://') || origin.endsWith('affine.pro') || // stable/beta origin.endsWith('affine.fail') || // canary - origin.includes('localhost') // dev + origin === baseUrl // localhost or self-hosted ); } -export const resolveRouteLinkMeta = (href: string) => { +export const resolveRouteLinkMeta = ( + href: string, + baseUrl = location.origin +) => { try { - const url = new URL(href, location.origin); + const url = new URL(href, baseUrl); // check if origin is one of affine's origins + // check if origin is localhost or self-hosted - if (!maybeAffineOrigin(url.origin)) { + if (!maybeAffineOrigin(url.origin, baseUrl)) { return null; }