mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-21 20:16:26 +08:00
fix(core): shared page mode syncing (#14756)
### Summary This fixes a few inconsistencies in shared page behavior: fixes https://github.com/toeverything/AFFiNE/issues/14751 - shared pages now open in the correct published mode when the URL does not already include ?mode=... - switching between page and edgeless in shared mode now keeps the URL query param in sync - the default Copy Link action now follows the current editor mode - shared viewers can toggle between page and edgeless mode in readonly share pages --- ### What Changed - updated shared page mode resolution to prefer URL mode, with backend publish mode as fallback - added query-param syncing for shared page mode changes - made the default share link copy use: - page link in page mode - edgeless link in edgeless mode - allowed EditorModeSwitch to toggle both ways in shared mode - extracted shared-mode behavior into small hooks to keep share-page.tsx cleaner --- ### Demo https://www.loom.com/share/a287172321fb4fc5b94f7c67a39298a9 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Mode switching between page and edgeless no longer blocked by shared gating; shared pages initialize and respect the resolved editor mode. * Shared page URLs stay in sync with editor mode and copy-link actions include/preserve the selected mode. * **Tests** * Added tests for publish-mode resolution, query-string mode handling, and default share-mode behavior. * **Bug Fixes** * Updated shared-page “not found” UI text to match new messaging. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: DarkSky <25152247+darkskygit@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,40 @@
|
|||||||
|
import { PublicDocMode } from '@affine/graphql';
|
||||||
|
import { describe, expect, test } from 'vitest';
|
||||||
|
|
||||||
|
import {
|
||||||
|
getResolvedPublishMode,
|
||||||
|
getSearchWithMode,
|
||||||
|
} from '../desktop/pages/workspace/share/share-page.utils';
|
||||||
|
|
||||||
|
describe('getResolvedPublishMode', () => {
|
||||||
|
test('prefers the query mode when it is present', () => {
|
||||||
|
expect(getResolvedPublishMode('edgeless', PublicDocMode.Page)).toBe(
|
||||||
|
'edgeless'
|
||||||
|
);
|
||||||
|
expect(getResolvedPublishMode('page', PublicDocMode.Edgeless)).toBe('page');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('falls back to the published public mode for shared docs', () => {
|
||||||
|
expect(getResolvedPublishMode(null, PublicDocMode.Edgeless)).toBe(
|
||||||
|
'edgeless'
|
||||||
|
);
|
||||||
|
expect(getResolvedPublishMode(null, PublicDocMode.Page)).toBe('page');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('defaults to page when no mode is available', () => {
|
||||||
|
expect(getResolvedPublishMode(null, null)).toBe('page');
|
||||||
|
expect(getResolvedPublishMode(null, undefined)).toBe('page');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getSearchWithMode', () => {
|
||||||
|
test('adds mode to an empty search string', () => {
|
||||||
|
expect(getSearchWithMode('', 'edgeless')).toBe('?mode=edgeless');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('replaces an existing mode and preserves other params', () => {
|
||||||
|
expect(getSearchWithMode('?foo=1&mode=page&bar=2', 'edgeless')).toBe(
|
||||||
|
'?foo=1&mode=edgeless&bar=2'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import { describe, expect, test } from 'vitest';
|
||||||
|
|
||||||
|
import { getDefaultShareMode } from '../components/hooks/affine/use-share-url.utils';
|
||||||
|
|
||||||
|
describe('getDefaultShareMode', () => {
|
||||||
|
test('returns edgeless when the current mode is edgeless', () => {
|
||||||
|
expect(getDefaultShareMode('edgeless')).toBe('edgeless');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('returns undefined for page mode or an unset mode', () => {
|
||||||
|
expect(getDefaultShareMode('page')).toBeUndefined();
|
||||||
|
expect(getDefaultShareMode(undefined)).toBeUndefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -39,7 +39,6 @@ export const EditorModeSwitch = () => {
|
|||||||
const t = useI18n();
|
const t = useI18n();
|
||||||
const editor = useService(EditorService).editor;
|
const editor = useService(EditorService).editor;
|
||||||
const trash = useLiveData(editor.doc.trash$);
|
const trash = useLiveData(editor.doc.trash$);
|
||||||
const isSharedMode = editor.isSharedMode;
|
|
||||||
const currentMode = useLiveData(editor.mode$);
|
const currentMode = useLiveData(editor.mode$);
|
||||||
const view = useServiceOptional(ViewService)?.view;
|
const view = useServiceOptional(ViewService)?.view;
|
||||||
const workbench = useServiceOptional(WorkbenchService)?.workbench;
|
const workbench = useServiceOptional(WorkbenchService)?.workbench;
|
||||||
@@ -47,18 +46,18 @@ export const EditorModeSwitch = () => {
|
|||||||
const isActiveView = activeView?.id && activeView?.id === view?.id;
|
const isActiveView = activeView?.id && activeView?.id === view?.id;
|
||||||
|
|
||||||
const togglePage = useCallback(() => {
|
const togglePage = useCallback(() => {
|
||||||
if (currentMode === 'page' || isSharedMode || trash) return;
|
if (currentMode === 'page' || trash) return;
|
||||||
editor.setMode('page');
|
editor.setMode('page');
|
||||||
editor.setSelector(undefined);
|
editor.setSelector(undefined);
|
||||||
track.$.header.actions.switchPageMode({ mode: 'page' });
|
track.$.header.actions.switchPageMode({ mode: 'page' });
|
||||||
}, [currentMode, editor, isSharedMode, trash]);
|
}, [currentMode, editor, trash]);
|
||||||
|
|
||||||
const toggleEdgeless = useCallback(() => {
|
const toggleEdgeless = useCallback(() => {
|
||||||
if (currentMode === 'edgeless' || isSharedMode || trash) return;
|
if (currentMode === 'edgeless' || trash) return;
|
||||||
editor.setMode('edgeless');
|
editor.setMode('edgeless');
|
||||||
editor.setSelector(undefined);
|
editor.setSelector(undefined);
|
||||||
track.$.header.actions.switchPageMode({ mode: 'edgeless' });
|
track.$.header.actions.switchPageMode({ mode: 'edgeless' });
|
||||||
}, [currentMode, editor, isSharedMode, trash]);
|
}, [currentMode, editor, trash]);
|
||||||
|
|
||||||
const onModeChange = useCallback(
|
const onModeChange = useCallback(
|
||||||
(mode: DocMode) => {
|
(mode: DocMode) => {
|
||||||
@@ -68,13 +67,12 @@ export const EditorModeSwitch = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const shouldHide = useCallback(
|
const shouldHide = useCallback(
|
||||||
(mode: DocMode) => (trash || isSharedMode) && currentMode !== mode,
|
(mode: DocMode) => trash && currentMode !== mode,
|
||||||
[currentMode, isSharedMode, trash]
|
[currentMode, trash]
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (trash || isSharedMode || currentMode === undefined || !isActiveView)
|
if (trash || currentMode === undefined || !isActiveView) return;
|
||||||
return;
|
|
||||||
return registerAffineCommand({
|
return registerAffineCommand({
|
||||||
id: 'affine:doc-mode-switch',
|
id: 'affine:doc-mode-switch',
|
||||||
category: 'editor:page',
|
category: 'editor:page',
|
||||||
@@ -89,7 +87,7 @@ export const EditorModeSwitch = () => {
|
|||||||
},
|
},
|
||||||
run: () => onModeChange(currentMode === 'edgeless' ? 'page' : 'edgeless'),
|
run: () => onModeChange(currentMode === 'edgeless' ? 'page' : 'edgeless'),
|
||||||
});
|
});
|
||||||
}, [currentMode, isActiveView, isSharedMode, onModeChange, t, trash]);
|
}, [currentMode, isActiveView, onModeChange, t, trash]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PureEditorModeSwitch
|
<PureEditorModeSwitch
|
||||||
|
|||||||
+8
-2
@@ -3,9 +3,12 @@ import {
|
|||||||
registerAffineCommand,
|
registerAffineCommand,
|
||||||
} from '@affine/core/commands';
|
} from '@affine/core/commands';
|
||||||
import { useSharingUrl } from '@affine/core/components/hooks/affine/use-share-url';
|
import { useSharingUrl } from '@affine/core/components/hooks/affine/use-share-url';
|
||||||
|
import { getDefaultShareMode } from '@affine/core/components/hooks/affine/use-share-url.utils';
|
||||||
|
import { EditorService } from '@affine/core/modules/editor';
|
||||||
import { useIsActiveView } from '@affine/core/modules/workbench';
|
import { useIsActiveView } from '@affine/core/modules/workbench';
|
||||||
import type { WorkspaceMetadata } from '@affine/core/modules/workspace';
|
import type { WorkspaceMetadata } from '@affine/core/modules/workspace';
|
||||||
import { track } from '@affine/track';
|
import { track } from '@affine/track';
|
||||||
|
import { useLiveData, useService } from '@toeverything/infra';
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
export function useRegisterCopyLinkCommands({
|
export function useRegisterCopyLinkCommands({
|
||||||
@@ -18,6 +21,7 @@ export function useRegisterCopyLinkCommands({
|
|||||||
const isActiveView = useIsActiveView();
|
const isActiveView = useIsActiveView();
|
||||||
const workspaceId = workspaceMeta.id;
|
const workspaceId = workspaceMeta.id;
|
||||||
const isCloud = workspaceMeta.flavour !== 'local';
|
const isCloud = workspaceMeta.flavour !== 'local';
|
||||||
|
const currentMode = useLiveData(useService(EditorService).editor.mode$);
|
||||||
|
|
||||||
const { onClickCopyLink } = useSharingUrl({
|
const { onClickCopyLink } = useSharingUrl({
|
||||||
workspaceId,
|
workspaceId,
|
||||||
@@ -42,12 +46,14 @@ export function useRegisterCopyLinkCommands({
|
|||||||
icon: null,
|
icon: null,
|
||||||
run() {
|
run() {
|
||||||
track.$.cmdk.general.copyShareLink();
|
track.$.cmdk.general.copyShareLink();
|
||||||
isActiveView && isCloud && onClickCopyLink();
|
isActiveView &&
|
||||||
|
isCloud &&
|
||||||
|
onClickCopyLink(getDefaultShareMode(currentMode));
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
return () => {
|
return () => {
|
||||||
unsubs.forEach(unsub => unsub());
|
unsubs.forEach(unsub => unsub());
|
||||||
};
|
};
|
||||||
}, [docId, isActiveView, isCloud, onClickCopyLink]);
|
}, [currentMode, docId, isActiveView, isCloud, onClickCopyLink]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
import type { DocMode } from '@blocksuite/affine/model';
|
||||||
|
|
||||||
|
export const getDefaultShareMode = (
|
||||||
|
currentMode?: DocMode
|
||||||
|
): DocMode | undefined => {
|
||||||
|
return currentMode === 'edgeless' ? 'edgeless' : undefined;
|
||||||
|
};
|
||||||
@@ -37,6 +37,7 @@ import { PageNotFound } from '../../404';
|
|||||||
import { ShareFooter } from './share-footer';
|
import { ShareFooter } from './share-footer';
|
||||||
import { ShareHeader } from './share-header';
|
import { ShareHeader } from './share-header';
|
||||||
import * as styles from './share-page.css';
|
import * as styles from './share-page.css';
|
||||||
|
import { useSharedModeQuerySync } from './use-shared-mode-query-sync';
|
||||||
|
|
||||||
const useUpdateBasename = (workspace: Workspace | null) => {
|
const useUpdateBasename = (workspace: Workspace | null) => {
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
@@ -106,7 +107,7 @@ export const SharePage = ({
|
|||||||
const SharePageInner = ({
|
const SharePageInner = ({
|
||||||
workspaceId,
|
workspaceId,
|
||||||
docId,
|
docId,
|
||||||
publishMode = 'page',
|
publishMode,
|
||||||
selector,
|
selector,
|
||||||
isTemplate,
|
isTemplate,
|
||||||
templateName,
|
templateName,
|
||||||
@@ -128,10 +129,19 @@ const SharePageInner = ({
|
|||||||
const [noPermission, setNoPermission] = useState(false);
|
const [noPermission, setNoPermission] = useState(false);
|
||||||
const [editorContainer, setActiveBlocksuiteEditor] =
|
const [editorContainer, setActiveBlocksuiteEditor] =
|
||||||
useActiveBlocksuiteEditor();
|
useActiveBlocksuiteEditor();
|
||||||
|
const resolvedPublishMode = publishMode ?? null;
|
||||||
|
const currentPublishMode = useSharedModeQuerySync({
|
||||||
|
editor,
|
||||||
|
resolvedPublishMode,
|
||||||
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (editor || workspace || page) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// create a workspace for share page
|
// create a workspace for share page
|
||||||
const { workspace } = workspacesService.open(
|
const { workspace: sharedWorkspace } = workspacesService.open(
|
||||||
{
|
{
|
||||||
metadata: {
|
metadata: {
|
||||||
id: workspaceId,
|
id: workspaceId,
|
||||||
@@ -160,16 +170,16 @@ const SharePageInner = ({
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
setWorkspace(workspace);
|
setWorkspace(sharedWorkspace);
|
||||||
|
|
||||||
workspace.engine.doc
|
sharedWorkspace.engine.doc
|
||||||
.waitForDocLoaded(workspace.id)
|
.waitForDocLoaded(sharedWorkspace.id)
|
||||||
.then(async () => {
|
.then(async () => {
|
||||||
const { doc } = workspace.scope.get(DocsService).open(docId);
|
const { doc } = sharedWorkspace.scope.get(DocsService).open(docId);
|
||||||
doc.blockSuiteDoc.load();
|
doc.blockSuiteDoc.load();
|
||||||
doc.blockSuiteDoc.readonly = true;
|
doc.blockSuiteDoc.readonly = true;
|
||||||
|
|
||||||
await workspace.engine.doc.waitForDocLoaded(docId);
|
await sharedWorkspace.engine.doc.waitForDocLoaded(docId);
|
||||||
|
|
||||||
if (!doc.blockSuiteDoc.root) {
|
if (!doc.blockSuiteDoc.root) {
|
||||||
throw new Error('Doc is empty');
|
throw new Error('Doc is empty');
|
||||||
@@ -178,7 +188,7 @@ const SharePageInner = ({
|
|||||||
setPage(doc);
|
setPage(doc);
|
||||||
|
|
||||||
const editor = doc.scope.get(EditorsService).createEditor();
|
const editor = doc.scope.get(EditorsService).createEditor();
|
||||||
editor.setMode(publishMode);
|
editor.setMode(resolvedPublishMode ?? doc.getPrimaryMode() ?? 'page');
|
||||||
|
|
||||||
if (selector) {
|
if (selector) {
|
||||||
editor.setSelector(selector);
|
editor.setSelector(selector);
|
||||||
@@ -192,13 +202,24 @@ const SharePageInner = ({
|
|||||||
});
|
});
|
||||||
}, [
|
}, [
|
||||||
docId,
|
docId,
|
||||||
workspaceId,
|
editor,
|
||||||
workspacesService,
|
page,
|
||||||
publishMode,
|
resolvedPublishMode,
|
||||||
selector,
|
selector,
|
||||||
|
workspaceId,
|
||||||
|
workspace,
|
||||||
|
workspacesService,
|
||||||
serverService.server.baseUrl,
|
serverService.server.baseUrl,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!editor) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
editor.setSelector(selector);
|
||||||
|
}, [editor, selector]);
|
||||||
|
|
||||||
const t = useI18n();
|
const t = useI18n();
|
||||||
const pageTitle = useLiveData(page?.title$);
|
const pageTitle = useLiveData(page?.title$);
|
||||||
const { jumpToPageBlock, openPage } = useNavigateHelper();
|
const { jumpToPageBlock, openPage } = useNavigateHelper();
|
||||||
@@ -244,7 +265,7 @@ const SharePageInner = ({
|
|||||||
return <PageNotFound noPermission />;
|
return <PageNotFound noPermission />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!workspace || !page || !editor) {
|
if (!workspace || !page || !editor || !currentPublishMode) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -252,13 +273,13 @@ const SharePageInner = ({
|
|||||||
<FrameworkScope scope={workspace.scope}>
|
<FrameworkScope scope={workspace.scope}>
|
||||||
<FrameworkScope scope={page.scope}>
|
<FrameworkScope scope={page.scope}>
|
||||||
<FrameworkScope scope={editor.scope}>
|
<FrameworkScope scope={editor.scope}>
|
||||||
<ViewIcon icon={publishMode === 'page' ? 'doc' : 'edgeless'} />
|
<ViewIcon icon={currentPublishMode === 'page' ? 'doc' : 'edgeless'} />
|
||||||
<ViewTitle title={pageTitle ?? t['unnamed']()} />
|
<ViewTitle title={pageTitle ?? t['unnamed']()} />
|
||||||
<div className={styles.root}>
|
<div className={styles.root}>
|
||||||
<div className={styles.mainContainer}>
|
<div className={styles.mainContainer}>
|
||||||
<ShareHeader
|
<ShareHeader
|
||||||
pageId={page.id}
|
pageId={page.id}
|
||||||
publishMode={publishMode}
|
publishMode={currentPublishMode}
|
||||||
isTemplate={isTemplate}
|
isTemplate={isTemplate}
|
||||||
templateName={templateName}
|
templateName={templateName}
|
||||||
snapshotUrl={templateSnapshotUrl}
|
snapshotUrl={templateSnapshotUrl}
|
||||||
@@ -271,7 +292,7 @@ const SharePageInner = ({
|
|||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<PageDetailEditor onLoad={onEditorLoad} readonly />
|
<PageDetailEditor onLoad={onEditorLoad} readonly />
|
||||||
{publishMode === 'page' && !BUILD_CONFIG.isElectron ? (
|
{currentPublishMode === 'page' && !BUILD_CONFIG.isElectron ? (
|
||||||
<ShareFooter />
|
<ShareFooter />
|
||||||
) : null}
|
) : null}
|
||||||
</Scrollable.Viewport>
|
</Scrollable.Viewport>
|
||||||
@@ -279,7 +300,7 @@ const SharePageInner = ({
|
|||||||
</Scrollable.Root>
|
</Scrollable.Root>
|
||||||
<EditorOutlineViewer
|
<EditorOutlineViewer
|
||||||
editor={editorContainer?.host ?? null}
|
editor={editorContainer?.host ?? null}
|
||||||
show={publishMode === 'page'}
|
show={currentPublishMode === 'page'}
|
||||||
/>
|
/>
|
||||||
{!BUILD_CONFIG.isElectron && <SharePageFooter />}
|
{!BUILD_CONFIG.isElectron && <SharePageFooter />}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import { PublicDocMode } from '@affine/graphql';
|
||||||
|
import { type DocMode, DocModes } from '@blocksuite/affine/model';
|
||||||
|
|
||||||
|
export const getResolvedPublishMode = (
|
||||||
|
queryMode: DocMode | null,
|
||||||
|
publicMode?: PublicDocMode | null
|
||||||
|
): DocMode => {
|
||||||
|
if (queryMode && DocModes.includes(queryMode)) {
|
||||||
|
return queryMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
return publicMode === PublicDocMode.Edgeless ? 'edgeless' : 'page';
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getSearchWithMode = (search: string, mode: DocMode) => {
|
||||||
|
const searchParams = new URLSearchParams(search);
|
||||||
|
searchParams.set('mode', mode);
|
||||||
|
|
||||||
|
const nextSearch = searchParams.toString();
|
||||||
|
return nextSearch ? `?${nextSearch}` : '';
|
||||||
|
};
|
||||||
+60
@@ -0,0 +1,60 @@
|
|||||||
|
import type { Editor } from '@affine/core/modules/editor';
|
||||||
|
import type { DocMode } from '@blocksuite/affine/model';
|
||||||
|
import { useLiveData } from '@toeverything/infra';
|
||||||
|
import { useEffect, useRef } from 'react';
|
||||||
|
import { useLocation, useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
|
import { getSearchWithMode } from './share-page.utils';
|
||||||
|
|
||||||
|
export const useSharedModeQuerySync = ({
|
||||||
|
editor,
|
||||||
|
resolvedPublishMode,
|
||||||
|
}: {
|
||||||
|
editor: Editor | null;
|
||||||
|
resolvedPublishMode: DocMode | null;
|
||||||
|
}) => {
|
||||||
|
const location = useLocation();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const currentPublishMode = useLiveData(editor?.mode$) ?? resolvedPublishMode;
|
||||||
|
const previousPublishModeRef = useRef<DocMode | null>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!editor || !resolvedPublishMode) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (editor.mode$.value !== resolvedPublishMode) {
|
||||||
|
editor.setMode(resolvedPublishMode);
|
||||||
|
}
|
||||||
|
}, [editor, resolvedPublishMode]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!currentPublishMode) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (previousPublishModeRef.current === null) {
|
||||||
|
previousPublishModeRef.current = currentPublishMode;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (previousPublishModeRef.current === currentPublishMode) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
previousPublishModeRef.current = currentPublishMode;
|
||||||
|
|
||||||
|
const nextSearch = getSearchWithMode(location.search, currentPublishMode);
|
||||||
|
if (nextSearch !== location.search) {
|
||||||
|
navigate(
|
||||||
|
{
|
||||||
|
pathname: location.pathname,
|
||||||
|
search: nextSearch,
|
||||||
|
},
|
||||||
|
{ replace: true }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}, [currentPublishMode, location.pathname, location.search, navigate]);
|
||||||
|
|
||||||
|
return currentPublishMode;
|
||||||
|
};
|
||||||
@@ -3,6 +3,7 @@ import {
|
|||||||
getSelectedNodes,
|
getSelectedNodes,
|
||||||
useSharingUrl,
|
useSharingUrl,
|
||||||
} from '@affine/core/components/hooks/affine/use-share-url';
|
} from '@affine/core/components/hooks/affine/use-share-url';
|
||||||
|
import { getDefaultShareMode } from '@affine/core/components/hooks/affine/use-share-url.utils';
|
||||||
import { EditorService } from '@affine/core/modules/editor';
|
import { EditorService } from '@affine/core/modules/editor';
|
||||||
import { useI18n } from '@affine/i18n';
|
import { useI18n } from '@affine/i18n';
|
||||||
import type { DocMode } from '@blocksuite/affine/model';
|
import type { DocMode } from '@blocksuite/affine/model';
|
||||||
@@ -46,8 +47,8 @@ export const CopyLinkButton = ({
|
|||||||
}, [onClickCopyLink, currentMode, blockIds, elementIds]);
|
}, [onClickCopyLink, currentMode, blockIds, elementIds]);
|
||||||
|
|
||||||
const onCopyLink = useCallback(() => {
|
const onCopyLink = useCallback(() => {
|
||||||
onClickCopyLink();
|
onClickCopyLink(getDefaultShareMode(currentMode));
|
||||||
}, [onClickCopyLink]);
|
}, [currentMode, onClickCopyLink]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -117,7 +117,9 @@ test('Should show no permission page when the share page is not found', async ({
|
|||||||
await page.goto('http://localhost:8080/workspace/abc/123');
|
await page.goto('http://localhost:8080/workspace/abc/123');
|
||||||
|
|
||||||
await expect(
|
await expect(
|
||||||
page.getByText('You do not have access or this content does not exist.')
|
page.getByText(
|
||||||
|
'Sorry, you do not have access or this content does not exist...'
|
||||||
|
)
|
||||||
).toBeVisible();
|
).toBeVisible();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user