mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-08-18 18:41:52 +08:00
feat(server): synthetic root doc (#14794)
This commit is contained in:
@@ -32,6 +32,7 @@ import { FrameworkScope, useLiveData, useService } from '@toeverything/infra';
|
||||
import clsx from 'clsx';
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import { filter, firstValueFrom, timeout } from 'rxjs';
|
||||
|
||||
import { PageNotFound } from '../../404';
|
||||
import { ShareFooter } from './share-footer';
|
||||
@@ -40,9 +41,24 @@ import * as styles from './share-page.css';
|
||||
import {
|
||||
fetchSharedPublishMode,
|
||||
getResolvedPublishMode,
|
||||
isSharePagePermissionError,
|
||||
isSharePageTimeoutError,
|
||||
} from './share-page.utils';
|
||||
import { useSharedModeQuerySync } from './use-shared-mode-query-sync';
|
||||
|
||||
const waitForSharedDocRecord = async (
|
||||
docsService: DocsService,
|
||||
docId: string
|
||||
): Promise<void> => {
|
||||
if (docsService.list.doc$(docId).value) {
|
||||
return;
|
||||
}
|
||||
|
||||
await firstValueFrom(
|
||||
docsService.list.doc$(docId).pipe(filter(Boolean), timeout(3000))
|
||||
);
|
||||
};
|
||||
|
||||
const useUpdateBasename = (workspace: Workspace | null) => {
|
||||
const location = useLocation();
|
||||
const basename = location.pathname.match(/\/workspace\/[^/]+/g)?.[0] ?? '/';
|
||||
@@ -131,6 +147,7 @@ const SharePageInner = ({
|
||||
const [page, setPage] = useState<Doc | null>(null);
|
||||
const [editor, setEditor] = useState<Editor | null>(null);
|
||||
const [noPermission, setNoPermission] = useState(false);
|
||||
const [loadFailed, setLoadFailed] = useState(false);
|
||||
const [fetchedPublishMode, setFetchedPublishMode] = useState<
|
||||
DocMode | null | undefined
|
||||
>(() => (publishMode === undefined ? undefined : null));
|
||||
@@ -198,6 +215,7 @@ const SharePageInner = ({
|
||||
name: 'StaticCloudDocStorage',
|
||||
opts: {
|
||||
id: workspaceId,
|
||||
publicRootDocId: docId,
|
||||
serverBaseUrl: serverService.server.baseUrl,
|
||||
},
|
||||
},
|
||||
@@ -218,7 +236,10 @@ const SharePageInner = ({
|
||||
sharedWorkspace.engine.doc
|
||||
.waitForDocLoaded(sharedWorkspace.id)
|
||||
.then(async () => {
|
||||
const { doc } = sharedWorkspace.scope.get(DocsService).open(docId);
|
||||
const docsService = sharedWorkspace.scope.get(DocsService);
|
||||
await waitForSharedDocRecord(docsService, docId);
|
||||
|
||||
const { doc } = docsService.open(docId);
|
||||
doc.blockSuiteDoc.load();
|
||||
doc.blockSuiteDoc.readonly = true;
|
||||
|
||||
@@ -241,7 +262,17 @@ const SharePageInner = ({
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
setNoPermission(true);
|
||||
if (isSharePagePermissionError(err)) {
|
||||
setNoPermission(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isSharePageTimeoutError(err)) {
|
||||
setLoadFailed(true);
|
||||
return;
|
||||
}
|
||||
|
||||
setLoadFailed(true);
|
||||
});
|
||||
}, [
|
||||
docId,
|
||||
@@ -308,6 +339,10 @@ const SharePageInner = ({
|
||||
return <PageNotFound noPermission />;
|
||||
}
|
||||
|
||||
if (loadFailed) {
|
||||
return <PageNotFound />;
|
||||
}
|
||||
|
||||
if (!workspace || !page || !editor || !currentPublishMode) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { UserFriendlyError } from '@affine/error';
|
||||
import { type DocMode, DocModes } from '@blocksuite/affine/model';
|
||||
import { TimeoutError } from 'rxjs';
|
||||
|
||||
export const getResolvedPublishMode = (
|
||||
queryMode: DocMode | null,
|
||||
@@ -35,7 +37,7 @@ export const fetchSharedPublishMode = async ({
|
||||
signal?: AbortSignal;
|
||||
}): Promise<DocMode | null> => {
|
||||
const url = new URL(
|
||||
`/api/workspaces/${encodeURIComponent(workspaceId)}/docs/${encodeURIComponent(docId)}`,
|
||||
`/api/workspaces/${encodeURIComponent(workspaceId)}/public-docs/${encodeURIComponent(docId)}`,
|
||||
serverBaseUrl
|
||||
);
|
||||
const headers = {
|
||||
@@ -71,3 +73,12 @@ export const getSearchWithMode = (search: string, mode: DocMode) => {
|
||||
const nextSearch = searchParams.toString();
|
||||
return nextSearch ? `?${nextSearch}` : '';
|
||||
};
|
||||
|
||||
export const isSharePagePermissionError = (error: unknown) =>
|
||||
error instanceof UserFriendlyError &&
|
||||
(error.isStatus(403) ||
|
||||
error.name === 'DOC_ACTION_DENIED' ||
|
||||
error.name === 'SPACE_ACCESS_DENIED');
|
||||
|
||||
export const isSharePageTimeoutError = (error: unknown) =>
|
||||
error instanceof TimeoutError;
|
||||
|
||||
Reference in New Issue
Block a user