diff --git a/apps/web/src/atoms/public-workspace/index.ts b/apps/web/src/atoms/public-workspace/index.ts index 21ee4dafea..f2f45c6cdd 100644 --- a/apps/web/src/atoms/public-workspace/index.ts +++ b/apps/web/src/atoms/public-workspace/index.ts @@ -5,7 +5,42 @@ import { atom } from 'jotai'; import { BlockSuiteWorkspace } from '../../shared'; import { affineApis } from '../../shared/apis'; +function createPublicWorkspace(workspaceId: string, binary: ArrayBuffer) { + const blockSuiteWorkspace = createEmptyBlockSuiteWorkspace( + workspaceId, + (k: string) => + // fixme: token could be expired + ({ api: `api/workspace`, token: getLoginStorage()?.token }[k]) + ); + BlockSuiteWorkspace.Y.applyUpdate( + blockSuiteWorkspace.doc, + new Uint8Array(binary) + ); + blockSuiteWorkspace.awarenessStore.setFlag('enable_block_hub', false); + blockSuiteWorkspace.awarenessStore.setFlag('enable_set_remote_flag', false); + blockSuiteWorkspace.awarenessStore.setFlag('enable_database', false); + blockSuiteWorkspace.awarenessStore.setFlag('enable_edgeless_toolbar', false); + blockSuiteWorkspace.awarenessStore.setFlag('enable_slash_menu', false); + blockSuiteWorkspace.awarenessStore.setFlag('enable_drag_handle', false); + return blockSuiteWorkspace; +} + export const publicWorkspaceIdAtom = atom(null); +export const publicWorkspacePageIdAtom = atom(null); +export const publicPageBlockSuiteAtom = atom>( + async get => { + const workspaceId = get(publicWorkspaceIdAtom); + const pageId = get(publicWorkspacePageIdAtom); + if (!workspaceId || !pageId) { + throw new Error('No workspace id or page id'); + } + const binary = await affineApis.downloadPublicWorkspacePage( + workspaceId, + pageId + ); + return createPublicWorkspace(workspaceId, binary); + } +); export const publicBlockSuiteAtom = atom>( async get => { const workspaceId = get(publicWorkspaceIdAtom); @@ -13,25 +48,6 @@ export const publicBlockSuiteAtom = atom>( throw new Error('No workspace id'); } const binary = await affineApis.downloadWorkspace(workspaceId, true); - const blockSuiteWorkspace = createEmptyBlockSuiteWorkspace( - workspaceId, - (k: string) => - // fixme: token could be expired - ({ api: `api/workspace`, token: getLoginStorage()?.token }[k]) - ); - BlockSuiteWorkspace.Y.applyUpdate( - blockSuiteWorkspace.doc, - new Uint8Array(binary) - ); - blockSuiteWorkspace.awarenessStore.setFlag('enable_block_hub', false); - blockSuiteWorkspace.awarenessStore.setFlag('enable_set_remote_flag', false); - blockSuiteWorkspace.awarenessStore.setFlag('enable_database', false); - blockSuiteWorkspace.awarenessStore.setFlag( - 'enable_edgeless_toolbar', - false - ); - blockSuiteWorkspace.awarenessStore.setFlag('enable_slash_menu', false); - blockSuiteWorkspace.awarenessStore.setFlag('enable_drag_handle', false); - return blockSuiteWorkspace; + return createPublicWorkspace(workspaceId, binary); } ); diff --git a/apps/web/src/pages/public-workspace/[workspaceId]/[pageId].tsx b/apps/web/src/pages/public-workspace/[workspaceId]/[pageId].tsx index de70ddb2c6..abcae19af3 100644 --- a/apps/web/src/pages/public-workspace/[workspaceId]/[pageId].tsx +++ b/apps/web/src/pages/public-workspace/[workspaceId]/[pageId].tsx @@ -10,8 +10,9 @@ import type React from 'react'; import { Suspense, useEffect } from 'react'; import { - publicBlockSuiteAtom, + publicPageBlockSuiteAtom, publicWorkspaceIdAtom, + publicWorkspacePageIdAtom, } from '../../../atoms/public-workspace'; import { QueryParamError } from '../../../components/affine/affine-error-eoundary'; import { PageDetailEditor } from '../../../components/page-detail-editor'; @@ -51,7 +52,7 @@ export const StyledBreadcrumbs = styled(Link)(({ theme }) => { const PublicWorkspaceDetailPageInner: React.FC<{ pageId: string; }> = ({ pageId }) => { - const blockSuiteWorkspace = useAtomValue(publicBlockSuiteAtom); + const blockSuiteWorkspace = useAtomValue(publicPageBlockSuiteAtom); if (!blockSuiteWorkspace) { throw new Error('cannot find workspace'); } @@ -101,6 +102,7 @@ export const PublicWorkspaceDetailPage: NextPageWithLayout = () => { const workspaceId = router.query.workspaceId; const pageId = router.query.pageId; const setWorkspaceId = useSetAtom(publicWorkspaceIdAtom); + const setPageId = useSetAtom(publicWorkspacePageIdAtom); useEffect(() => { if (!router.isReady) { return; @@ -108,7 +110,10 @@ export const PublicWorkspaceDetailPage: NextPageWithLayout = () => { if (typeof workspaceId === 'string') { setWorkspaceId(workspaceId); } - }, [router.isReady, setWorkspaceId, workspaceId]); + if (typeof pageId === 'string') { + setPageId(pageId); + } + }, [pageId, router.isReady, setPageId, setWorkspaceId, workspaceId]); const value = useAtomValue(publicWorkspaceIdAtom); if (!router.isReady || !value) { return ; diff --git a/packages/component/src/components/block-suite-editor/index.tsx b/packages/component/src/components/block-suite-editor/index.tsx index 8095c7ab57..4d91985ff6 100644 --- a/packages/component/src/components/block-suite-editor/index.tsx +++ b/packages/component/src/components/block-suite-editor/index.tsx @@ -28,6 +28,8 @@ export const BlockSuiteEditor = (props: EditorProps) => { const blockHubRef = useRef(null); if (editorRef.current === null) { editorRef.current = new EditorContainer(); + editorRef.current.page = props.page; + editorRef.current.mode = props.mode; globalThis.currentEditor = editorRef.current; } const ref = useRef(null); diff --git a/tests/libs/utils.ts b/tests/libs/utils.ts index 59a323816f..10641bdb26 100644 --- a/tests/libs/utils.ts +++ b/tests/libs/utils.ts @@ -1,10 +1,6 @@ +import { faker } from '@faker-js/faker'; import type { Page } from '@playwright/test'; -// eslint-disable-next-line @typescript-eslint/no-var-requires -const userA = require('../fixtures/userA.json'); -// eslint-disable-next-line @typescript-eslint/no-var-requires -const userB = require('../fixtures/userB.json'); - // eslint-disable-next-line @typescript-eslint/no-var-requires const user1 = require('@affine-test/fixtures/built-in-user1.json'); // eslint-disable-next-line @typescript-eslint/no-var-requires @@ -37,7 +33,18 @@ export async function getBuiltInUser() { ]); } -export async function createFakeUser() { +export async function createFakeUser( + userA = { + name: faker.name.fullName(), + email: faker.internet.email(), + password: faker.internet.password(), + }, + userB = { + name: faker.name.fullName(), + email: faker.internet.email(), + password: faker.internet.password(), + } +) { try { const response = await Promise.all([ fetch('http://127.0.0.1:3000/api/user/token', { diff --git a/tests/parallels/affine/affine-public-workspace.spec.ts b/tests/parallels/affine/affine-public-workspace.spec.ts index 14e43d5025..3981f2b592 100644 --- a/tests/parallels/affine/affine-public-workspace.spec.ts +++ b/tests/parallels/affine/affine-public-workspace.spec.ts @@ -3,7 +3,10 @@ import { expect } from '@playwright/test'; import { waitMarkdownImported } from '../../libs/page-logic'; import { test } from '../../libs/playwright'; import { clickPublishPanel } from '../../libs/setting'; -import { clickSideBarSettingButton } from '../../libs/sidebar'; +import { + clickSideBarAllPageButton, + clickSideBarSettingButton, +} from '../../libs/sidebar'; import { createFakeUser, loginUser, openHomePage } from '../../libs/utils'; import { createWorkspace } from '../../libs/workspace'; @@ -39,4 +42,33 @@ test.describe('affine public workspace', () => { }); await page2.getByText('Welcome to AFFiNE').click(); }); + + test('access public workspace page', async ({ page, browser }) => { + await openHomePage(page); + const [a] = await createFakeUser(); + await loginUser(page, a); + await waitMarkdownImported(page); + const name = `test-${Date.now()}`; + await createWorkspace({ name }, page); + await waitMarkdownImported(page); + await clickSideBarSettingButton(page); + await page.waitForTimeout(50); + await clickPublishPanel(page); + await page.getByTestId('publish-enable-affine-cloud-button').click(); + await page.getByTestId('confirm-enable-affine-cloud-button').click(); + await page.getByTestId('publish-to-web-button').waitFor({ + timeout: 10000, + }); + await page.getByTestId('publish-to-web-button').click(); + await page.getByTestId('share-url').waitFor({ + timeout: 10000, + }); + await clickSideBarAllPageButton(page); + await page.locator('tr').nth(1).click(); + const url = page.url(); + const context = await browser.newContext(); + const page2 = await context.newPage(); + await page2.goto(url.replace('workspace', 'public-workspace')); + await page2.waitForSelector('v-line'); + }); }); diff --git a/tests/parallels/affine/affine-workspace.spec.ts b/tests/parallels/affine/affine-workspace.spec.ts index fe4f50fc86..143329dcd9 100644 --- a/tests/parallels/affine/affine-workspace.spec.ts +++ b/tests/parallels/affine/affine-workspace.spec.ts @@ -4,6 +4,8 @@ import { waitMarkdownImported } from '../../libs/page-logic'; // eslint-disable-next-line @typescript-eslint/no-var-requires const userA = require('../../fixtures/userA.json'); +// eslint-disable-next-line @typescript-eslint/no-var-requires +const userB = require('../../fixtures/userB.json'); import { test } from '../../libs/playwright'; import { clickCollaborationPanel } from '../../libs/setting'; import { @@ -22,7 +24,7 @@ test.describe('affine workspace', () => { test('should login with user A', async ({ page }) => { await openHomePage(page); await waitMarkdownImported(page); - const [a] = await createFakeUser(); + const [a] = await createFakeUser(userA, userB); await loginUser(page, a); await clickSideBarCurrentWorkspaceBanner(page); const footer = page.locator('[data-testid="workspace-list-modal-footer"]');