mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-09-22 19:53:48 +08:00
feat: single page API in public workspace (#1794)
This commit is contained in:
@@ -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
@@ -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"]');
|
||||||
|
|||||||
Reference in New Issue
Block a user