feat: single page API in public workspace (#1794)

This commit is contained in:
Himself65
2023-04-06 09:20:36 -05:00
committed by GitHub
parent 0577298344
commit 1ad4b0fc89
6 changed files with 95 additions and 31 deletions
+36 -20
View File
@@ -5,7 +5,42 @@ import { atom } from 'jotai';
import { BlockSuiteWorkspace } from '../../shared'; import { BlockSuiteWorkspace } from '../../shared';
import { affineApis } from '../../shared/apis'; 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<string | null>(null); export const publicWorkspaceIdAtom = atom<string | null>(null);
export const publicWorkspacePageIdAtom = atom<string | null>(null);
export const publicPageBlockSuiteAtom = atom<Promise<BlockSuiteWorkspace>>(
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<Promise<BlockSuiteWorkspace>>( export const publicBlockSuiteAtom = atom<Promise<BlockSuiteWorkspace>>(
async get => { async get => {
const workspaceId = get(publicWorkspaceIdAtom); const workspaceId = get(publicWorkspaceIdAtom);
@@ -13,25 +48,6 @@ export const publicBlockSuiteAtom = atom<Promise<BlockSuiteWorkspace>>(
throw new Error('No workspace id'); throw new Error('No workspace id');
} }
const binary = await affineApis.downloadWorkspace(workspaceId, true); const binary = await affineApis.downloadWorkspace(workspaceId, true);
const blockSuiteWorkspace = createEmptyBlockSuiteWorkspace( return createPublicWorkspace(workspaceId, binary);
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;
} }
); );
@@ -10,8 +10,9 @@ import type React from 'react';
import { Suspense, useEffect } from 'react'; import { Suspense, useEffect } from 'react';
import { import {
publicBlockSuiteAtom, publicPageBlockSuiteAtom,
publicWorkspaceIdAtom, publicWorkspaceIdAtom,
publicWorkspacePageIdAtom,
} from '../../../atoms/public-workspace'; } from '../../../atoms/public-workspace';
import { QueryParamError } from '../../../components/affine/affine-error-eoundary'; import { QueryParamError } from '../../../components/affine/affine-error-eoundary';
import { PageDetailEditor } from '../../../components/page-detail-editor'; import { PageDetailEditor } from '../../../components/page-detail-editor';
@@ -51,7 +52,7 @@ export const StyledBreadcrumbs = styled(Link)(({ theme }) => {
const PublicWorkspaceDetailPageInner: React.FC<{ const PublicWorkspaceDetailPageInner: React.FC<{
pageId: string; pageId: string;
}> = ({ pageId }) => { }> = ({ pageId }) => {
const blockSuiteWorkspace = useAtomValue(publicBlockSuiteAtom); const blockSuiteWorkspace = useAtomValue(publicPageBlockSuiteAtom);
if (!blockSuiteWorkspace) { if (!blockSuiteWorkspace) {
throw new Error('cannot find workspace'); throw new Error('cannot find workspace');
} }
@@ -101,6 +102,7 @@ export const PublicWorkspaceDetailPage: NextPageWithLayout = () => {
const workspaceId = router.query.workspaceId; const workspaceId = router.query.workspaceId;
const pageId = router.query.pageId; const pageId = router.query.pageId;
const setWorkspaceId = useSetAtom(publicWorkspaceIdAtom); const setWorkspaceId = useSetAtom(publicWorkspaceIdAtom);
const setPageId = useSetAtom(publicWorkspacePageIdAtom);
useEffect(() => { useEffect(() => {
if (!router.isReady) { if (!router.isReady) {
return; return;
@@ -108,7 +110,10 @@ export const PublicWorkspaceDetailPage: NextPageWithLayout = () => {
if (typeof workspaceId === 'string') { if (typeof workspaceId === 'string') {
setWorkspaceId(workspaceId); setWorkspaceId(workspaceId);
} }
}, [router.isReady, setWorkspaceId, workspaceId]); if (typeof pageId === 'string') {
setPageId(pageId);
}
}, [pageId, router.isReady, setPageId, setWorkspaceId, workspaceId]);
const value = useAtomValue(publicWorkspaceIdAtom); const value = useAtomValue(publicWorkspaceIdAtom);
if (!router.isReady || !value) { if (!router.isReady || !value) {
return <PageLoading />; return <PageLoading />;
@@ -28,6 +28,8 @@ export const BlockSuiteEditor = (props: EditorProps) => {
const blockHubRef = useRef<BlockHub | null>(null); const blockHubRef = useRef<BlockHub | null>(null);
if (editorRef.current === null) { if (editorRef.current === null) {
editorRef.current = new EditorContainer(); editorRef.current = new EditorContainer();
editorRef.current.page = props.page;
editorRef.current.mode = props.mode;
globalThis.currentEditor = editorRef.current; globalThis.currentEditor = editorRef.current;
} }
const ref = useRef<HTMLDivElement>(null); const ref = useRef<HTMLDivElement>(null);
+13 -6
View File
@@ -1,10 +1,6 @@
import { faker } from '@faker-js/faker';
import type { Page } from '@playwright/test'; 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 // eslint-disable-next-line @typescript-eslint/no-var-requires
const user1 = require('@affine-test/fixtures/built-in-user1.json'); const user1 = require('@affine-test/fixtures/built-in-user1.json');
// eslint-disable-next-line @typescript-eslint/no-var-requires // 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 { try {
const response = await Promise.all([ const response = await Promise.all([
fetch('http://127.0.0.1:3000/api/user/token', { fetch('http://127.0.0.1:3000/api/user/token', {
@@ -3,7 +3,10 @@ import { expect } from '@playwright/test';
import { waitMarkdownImported } from '../../libs/page-logic'; import { waitMarkdownImported } from '../../libs/page-logic';
import { test } from '../../libs/playwright'; import { test } from '../../libs/playwright';
import { clickPublishPanel } from '../../libs/setting'; import { clickPublishPanel } from '../../libs/setting';
import { clickSideBarSettingButton } from '../../libs/sidebar'; import {
clickSideBarAllPageButton,
clickSideBarSettingButton,
} from '../../libs/sidebar';
import { createFakeUser, loginUser, openHomePage } from '../../libs/utils'; import { createFakeUser, loginUser, openHomePage } from '../../libs/utils';
import { createWorkspace } from '../../libs/workspace'; import { createWorkspace } from '../../libs/workspace';
@@ -39,4 +42,33 @@ test.describe('affine public workspace', () => {
}); });
await page2.getByText('Welcome to AFFiNE').click(); 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');
});
}); });
@@ -4,6 +4,8 @@ import { waitMarkdownImported } from '../../libs/page-logic';
// eslint-disable-next-line @typescript-eslint/no-var-requires // eslint-disable-next-line @typescript-eslint/no-var-requires
const userA = require('../../fixtures/userA.json'); 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 { test } from '../../libs/playwright';
import { clickCollaborationPanel } from '../../libs/setting'; import { clickCollaborationPanel } from '../../libs/setting';
import { import {
@@ -22,7 +24,7 @@ test.describe('affine workspace', () => {
test('should login with user A', async ({ page }) => { test('should login with user A', async ({ page }) => {
await openHomePage(page); await openHomePage(page);
await waitMarkdownImported(page); await waitMarkdownImported(page);
const [a] = await createFakeUser(); const [a] = await createFakeUser(userA, userB);
await loginUser(page, a); await loginUser(page, a);
await clickSideBarCurrentWorkspaceBanner(page); await clickSideBarCurrentWorkspaceBanner(page);
const footer = page.locator('[data-testid="workspace-list-modal-footer"]'); const footer = page.locator('[data-testid="workspace-list-modal-footer"]');