fix: page validation logic (#3626)
This commit is contained in:
@@ -76,7 +76,6 @@ const EditorWrapper = memo(function EditorWrapper({
|
|||||||
'--affine-font-family': value,
|
'--affine-font-family': value,
|
||||||
} as CSSProperties
|
} as CSSProperties
|
||||||
}
|
}
|
||||||
key={`${workspace.id}-${pageId}`}
|
|
||||||
mode={isPublic ? 'page' : currentMode}
|
mode={isPublic ? 'page' : currentMode}
|
||||||
page={page}
|
page={page}
|
||||||
onInit={useCallback(
|
onInit={useCallback(
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ export const RootAppSidebar = ({
|
|||||||
|
|
||||||
const [sidebarOpen, setSidebarOpen] = useAtom(appSidebarOpenAtom);
|
const [sidebarOpen, setSidebarOpen] = useAtom(appSidebarOpenAtom);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isDesktop && typeof sidebarOpen === 'boolean') {
|
if (isDesktop) {
|
||||||
window.apis?.ui.handleSidebarVisibilityChange(sidebarOpen).catch(err => {
|
window.apis?.ui.handleSidebarVisibilityChange(sidebarOpen).catch(err => {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,9 +1,4 @@
|
|||||||
import type { WorkspaceSubPath } from '@affine/env/workspace';
|
import type { WorkspaceSubPath } from '@affine/env/workspace';
|
||||||
import {
|
|
||||||
currentPageIdAtom,
|
|
||||||
currentWorkspaceIdAtom,
|
|
||||||
} from '@toeverything/infra/atom';
|
|
||||||
import { useSetAtom } from 'jotai';
|
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
// eslint-disable-next-line @typescript-eslint/no-restricted-imports
|
// eslint-disable-next-line @typescript-eslint/no-restricted-imports
|
||||||
import { useLocation, useNavigate } from 'react-router-dom';
|
import { useLocation, useNavigate } from 'react-router-dom';
|
||||||
@@ -16,8 +11,6 @@ export enum RouteLogic {
|
|||||||
export function useNavigateHelper() {
|
export function useNavigateHelper() {
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const setWorkspaceId = useSetAtom(currentWorkspaceIdAtom);
|
|
||||||
const setCurrentPageId = useSetAtom(currentPageIdAtom);
|
|
||||||
|
|
||||||
const jumpToPage = useCallback(
|
const jumpToPage = useCallback(
|
||||||
(
|
(
|
||||||
@@ -25,13 +18,11 @@ export function useNavigateHelper() {
|
|||||||
pageId: string,
|
pageId: string,
|
||||||
logic: RouteLogic = RouteLogic.PUSH
|
logic: RouteLogic = RouteLogic.PUSH
|
||||||
) => {
|
) => {
|
||||||
setWorkspaceId(workspaceId);
|
|
||||||
setCurrentPageId(pageId);
|
|
||||||
return navigate(`/workspace/${workspaceId}/${pageId}`, {
|
return navigate(`/workspace/${workspaceId}/${pageId}`, {
|
||||||
replace: logic === RouteLogic.REPLACE,
|
replace: logic === RouteLogic.REPLACE,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[navigate, setCurrentPageId, setWorkspaceId]
|
[navigate]
|
||||||
);
|
);
|
||||||
const jumpToPublicWorkspacePage = useCallback(
|
const jumpToPublicWorkspacePage = useCallback(
|
||||||
(
|
(
|
||||||
@@ -39,13 +30,11 @@ export function useNavigateHelper() {
|
|||||||
pageId: string,
|
pageId: string,
|
||||||
logic: RouteLogic = RouteLogic.PUSH
|
logic: RouteLogic = RouteLogic.PUSH
|
||||||
) => {
|
) => {
|
||||||
setWorkspaceId(workspaceId);
|
|
||||||
setCurrentPageId(pageId);
|
|
||||||
return navigate(`/public-workspace/${workspaceId}/${pageId}`, {
|
return navigate(`/public-workspace/${workspaceId}/${pageId}`, {
|
||||||
replace: logic === RouteLogic.REPLACE,
|
replace: logic === RouteLogic.REPLACE,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[navigate, setCurrentPageId, setWorkspaceId]
|
[navigate]
|
||||||
);
|
);
|
||||||
const jumpToSubPath = useCallback(
|
const jumpToSubPath = useCallback(
|
||||||
(
|
(
|
||||||
@@ -53,18 +42,14 @@ export function useNavigateHelper() {
|
|||||||
subPath: WorkspaceSubPath,
|
subPath: WorkspaceSubPath,
|
||||||
logic: RouteLogic = RouteLogic.PUSH
|
logic: RouteLogic = RouteLogic.PUSH
|
||||||
) => {
|
) => {
|
||||||
setWorkspaceId(workspaceId);
|
|
||||||
setCurrentPageId(null);
|
|
||||||
return navigate(`/workspace/${workspaceId}/${subPath}`, {
|
return navigate(`/workspace/${workspaceId}/${subPath}`, {
|
||||||
replace: logic === RouteLogic.REPLACE,
|
replace: logic === RouteLogic.REPLACE,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[navigate, setCurrentPageId, setWorkspaceId]
|
[navigate]
|
||||||
);
|
);
|
||||||
const openPage = useCallback(
|
const openPage = useCallback(
|
||||||
(workspaceId: string, pageId: string) => {
|
(workspaceId: string, pageId: string) => {
|
||||||
setWorkspaceId(workspaceId);
|
|
||||||
setCurrentPageId(pageId);
|
|
||||||
const isPublicWorkspace =
|
const isPublicWorkspace =
|
||||||
location.pathname.indexOf('/public-workspace') === 0;
|
location.pathname.indexOf('/public-workspace') === 0;
|
||||||
if (isPublicWorkspace) {
|
if (isPublicWorkspace) {
|
||||||
@@ -73,35 +58,25 @@ export function useNavigateHelper() {
|
|||||||
return jumpToPage(workspaceId, pageId);
|
return jumpToPage(workspaceId, pageId);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[
|
[jumpToPage, jumpToPublicWorkspacePage, location.pathname]
|
||||||
jumpToPage,
|
|
||||||
jumpToPublicWorkspacePage,
|
|
||||||
location.pathname,
|
|
||||||
setCurrentPageId,
|
|
||||||
setWorkspaceId,
|
|
||||||
]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const jumpToIndex = useCallback(
|
const jumpToIndex = useCallback(
|
||||||
(logic: RouteLogic = RouteLogic.PUSH) => {
|
(logic: RouteLogic = RouteLogic.PUSH) => {
|
||||||
setWorkspaceId(null);
|
|
||||||
setCurrentPageId(null);
|
|
||||||
return navigate('/', {
|
return navigate('/', {
|
||||||
replace: logic === RouteLogic.REPLACE,
|
replace: logic === RouteLogic.REPLACE,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[navigate, setCurrentPageId, setWorkspaceId]
|
[navigate]
|
||||||
);
|
);
|
||||||
|
|
||||||
const jumpTo404 = useCallback(
|
const jumpTo404 = useCallback(
|
||||||
(logic: RouteLogic = RouteLogic.PUSH) => {
|
(logic: RouteLogic = RouteLogic.PUSH) => {
|
||||||
setWorkspaceId(null);
|
|
||||||
setCurrentPageId(null);
|
|
||||||
return navigate('/404', {
|
return navigate('/404', {
|
||||||
replace: logic === RouteLogic.REPLACE,
|
replace: logic === RouteLogic.REPLACE,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[navigate, setCurrentPageId, setWorkspaceId]
|
[navigate]
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -89,15 +89,6 @@ export const QuickSearch = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
declare global {
|
|
||||||
// eslint-disable-next-line no-var
|
|
||||||
var HALTING_PROBLEM_TIMEOUT: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (globalThis.HALTING_PROBLEM_TIMEOUT === undefined) {
|
|
||||||
globalThis.HALTING_PROBLEM_TIMEOUT = 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
const showList: IslandItemNames[] = environment.isDesktop
|
const showList: IslandItemNames[] = environment.isDesktop
|
||||||
? ['whatNew', 'contact', 'guide']
|
? ['whatNew', 'contact', 'guide']
|
||||||
: ['whatNew', 'contact'];
|
: ['whatNew', 'contact'];
|
||||||
|
|||||||
@@ -7,12 +7,16 @@ import { WorkspaceSubPath } from '@affine/env/workspace';
|
|||||||
import type { EditorContainer } from '@blocksuite/editor';
|
import type { EditorContainer } from '@blocksuite/editor';
|
||||||
import { assertExists } from '@blocksuite/global/utils';
|
import { assertExists } from '@blocksuite/global/utils';
|
||||||
import type { Page } from '@blocksuite/store';
|
import type { Page } from '@blocksuite/store';
|
||||||
import { currentPageIdAtom, rootStore } from '@toeverything/infra/atom';
|
import {
|
||||||
|
currentPageIdAtom,
|
||||||
|
currentWorkspaceAtom,
|
||||||
|
currentWorkspaceIdAtom,
|
||||||
|
rootStore,
|
||||||
|
} from '@toeverything/infra/atom';
|
||||||
import { useAtomValue } from 'jotai';
|
import { useAtomValue } from 'jotai';
|
||||||
import { useAtom } from 'jotai/react';
|
import { type ReactElement, useCallback } from 'react';
|
||||||
import { type ReactElement, useCallback, useEffect } from 'react';
|
|
||||||
import type { LoaderFunction } from 'react-router-dom';
|
import type { LoaderFunction } from 'react-router-dom';
|
||||||
import { useLocation, useParams } from 'react-router-dom';
|
import { redirect } from 'react-router-dom';
|
||||||
|
|
||||||
import { getUIAdapter } from '../../adapters/workspace';
|
import { getUIAdapter } from '../../adapters/workspace';
|
||||||
import { useCurrentWorkspace } from '../../hooks/current/use-current-workspace';
|
import { useCurrentWorkspace } from '../../hooks/current/use-current-workspace';
|
||||||
@@ -32,7 +36,7 @@ const DetailPageImpl = (): ReactElement => {
|
|||||||
return openPage(blockSuiteWorkspace.id, pageId);
|
return openPage(blockSuiteWorkspace.id, pageId);
|
||||||
});
|
});
|
||||||
const disposeTagClick = editor.slots.tagClicked.on(async ({ tagId }) => {
|
const disposeTagClick = editor.slots.tagClicked.on(async ({ tagId }) => {
|
||||||
await jumpToSubPath(currentWorkspace.id, WorkspaceSubPath.ALL);
|
jumpToSubPath(currentWorkspace.id, WorkspaceSubPath.ALL);
|
||||||
collectionManager.backToAll();
|
collectionManager.backToAll();
|
||||||
collectionManager.setTemporaryFilter([createTagFilter(tagId)]);
|
collectionManager.setTemporaryFilter([createTagFilter(tagId)]);
|
||||||
});
|
});
|
||||||
@@ -69,61 +73,39 @@ const DetailPageImpl = (): ReactElement => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const DetailPage = (): ReactElement => {
|
export const DetailPage = (): ReactElement => {
|
||||||
const { workspaceId, pageId } = useParams();
|
|
||||||
const location = useLocation();
|
|
||||||
const { jumpTo404 } = useNavigateHelper();
|
|
||||||
const [currentWorkspace] = useCurrentWorkspace();
|
const [currentWorkspace] = useCurrentWorkspace();
|
||||||
const [currentPageId, setCurrentPageId] = useAtom(currentPageIdAtom);
|
const currentPageId = useAtomValue(currentPageIdAtom);
|
||||||
const page = currentPageId
|
const page = currentPageId
|
||||||
? currentWorkspace.blockSuiteWorkspace.getPage(currentPageId)
|
? currentWorkspace.blockSuiteWorkspace.getPage(currentPageId)
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
//#region check if page is valid
|
|
||||||
useEffect(() => {
|
|
||||||
// if the workspace changed, ignore the page check
|
|
||||||
if (currentWorkspace.id !== workspaceId) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (typeof pageId === 'string' && currentPageId) {
|
|
||||||
if (currentPageId !== pageId) {
|
|
||||||
setCurrentPageId(pageId);
|
|
||||||
} else {
|
|
||||||
const page =
|
|
||||||
currentWorkspace.blockSuiteWorkspace.getPage(currentPageId);
|
|
||||||
if (!page) {
|
|
||||||
jumpTo404();
|
|
||||||
} else {
|
|
||||||
// fixme: cleanup jumpOnce in the right time
|
|
||||||
if (page.meta.jumpOnce) {
|
|
||||||
currentWorkspace.blockSuiteWorkspace.setPageMeta(currentPageId, {
|
|
||||||
jumpOnce: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, [
|
|
||||||
currentPageId,
|
|
||||||
currentWorkspace.blockSuiteWorkspace,
|
|
||||||
currentWorkspace.id,
|
|
||||||
jumpTo404,
|
|
||||||
location.pathname,
|
|
||||||
pageId,
|
|
||||||
setCurrentPageId,
|
|
||||||
workspaceId,
|
|
||||||
]);
|
|
||||||
//#endregion
|
|
||||||
|
|
||||||
if (!currentPageId || !page) {
|
if (!currentPageId || !page) {
|
||||||
return <PageDetailSkeleton key="current-page-is-null" />;
|
return <PageDetailSkeleton key="current-page-is-null" />;
|
||||||
}
|
}
|
||||||
return <DetailPageImpl />;
|
return <DetailPageImpl />;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const loader: LoaderFunction = args => {
|
export const loader: LoaderFunction = async args => {
|
||||||
|
if (args.params.workspaceId) {
|
||||||
|
localStorage.setItem('last_workspace_id', args.params.workspaceId);
|
||||||
|
rootStore.set(currentWorkspaceIdAtom, args.params.workspaceId);
|
||||||
|
}
|
||||||
if (args.params.pageId) {
|
if (args.params.pageId) {
|
||||||
localStorage.setItem('last_page_id', args.params.pageId);
|
const pageId = args.params.pageId;
|
||||||
rootStore.set(currentPageIdAtom, args.params.pageId);
|
localStorage.setItem('last_page_id', pageId);
|
||||||
|
const currentWorkspace = await rootStore.get(currentWorkspaceAtom);
|
||||||
|
const page = currentWorkspace.getPage(pageId);
|
||||||
|
if (!page) {
|
||||||
|
return redirect('/404');
|
||||||
|
}
|
||||||
|
if (page.meta.jumpOnce) {
|
||||||
|
currentWorkspace.setPageMeta(page.id, {
|
||||||
|
jumpOnce: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
rootStore.set(currentPageIdAtom, pageId);
|
||||||
|
} else {
|
||||||
|
return redirect('/404');
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
import { rootWorkspacesMetadataAtom } from '@affine/workspace/atom';
|
import { rootWorkspacesMetadataAtom } from '@affine/workspace/atom';
|
||||||
import { currentWorkspaceIdAtom, rootStore } from '@toeverything/infra/atom';
|
import {
|
||||||
|
currentPageIdAtom,
|
||||||
|
currentWorkspaceIdAtom,
|
||||||
|
rootStore,
|
||||||
|
} from '@toeverything/infra/atom';
|
||||||
import type { ReactElement } from 'react';
|
import type { ReactElement } from 'react';
|
||||||
import { type LoaderFunction, Outlet, redirect } from 'react-router-dom';
|
import { type LoaderFunction, Outlet, redirect } from 'react-router-dom';
|
||||||
|
|
||||||
@@ -14,6 +18,9 @@ export const loader: LoaderFunction = async args => {
|
|||||||
localStorage.setItem('last_workspace_id', args.params.workspaceId);
|
localStorage.setItem('last_workspace_id', args.params.workspaceId);
|
||||||
rootStore.set(currentWorkspaceIdAtom, args.params.workspaceId);
|
rootStore.set(currentWorkspaceIdAtom, args.params.workspaceId);
|
||||||
}
|
}
|
||||||
|
if (!args.params.pageId) {
|
||||||
|
rootStore.set(currentPageIdAtom, null);
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -95,7 +95,13 @@ const BlockSuiteEditorImpl = (props: EditorProps): ReactElement => {
|
|||||||
if (!container) {
|
if (!container) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (page.awarenessStore.getFlag('enable_block_hub')) {
|
container.appendChild(editor);
|
||||||
|
return () => {
|
||||||
|
container.removeChild(editor);
|
||||||
|
};
|
||||||
|
}, [editor]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
editor
|
editor
|
||||||
.createBlockHub()
|
.createBlockHub()
|
||||||
.then(blockHub => {
|
.then(blockHub => {
|
||||||
@@ -110,17 +116,13 @@ const BlockSuiteEditorImpl = (props: EditorProps): ReactElement => {
|
|||||||
.catch(err => {
|
.catch(err => {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
container.appendChild(editor);
|
|
||||||
return () => {
|
return () => {
|
||||||
if (setBlockHub) {
|
if (setBlockHub) {
|
||||||
setBlockHub(null);
|
setBlockHub(null);
|
||||||
}
|
}
|
||||||
blockHubRef.current?.remove();
|
blockHubRef.current?.remove();
|
||||||
container.removeChild(editor);
|
|
||||||
};
|
};
|
||||||
}, [editor, setBlockHub, page]);
|
}, [editor, page.awarenessStore, setBlockHub]);
|
||||||
|
|
||||||
// issue: https://github.com/toeverything/AFFiNE/issues/2004
|
// issue: https://github.com/toeverything/AFFiNE/issues/2004
|
||||||
const className = `editor-wrapper ${editor.mode}-mode ${
|
const className = `editor-wrapper ${editor.mode}-mode ${
|
||||||
|
|||||||
@@ -1,13 +1,10 @@
|
|||||||
import { test } from '@affine-test/kit/playwright';
|
import { test } from '@affine-test/kit/playwright';
|
||||||
import { checkBlockHub } from '@affine-test/kit/utils/editor';
|
import { checkBlockHub } from '@affine-test/kit/utils/editor';
|
||||||
import { openHomePage } from '@affine-test/kit/utils/load-page';
|
import { openHomePage } from '@affine-test/kit/utils/load-page';
|
||||||
import { newPage, waitEditorLoad } from '@affine-test/kit/utils/page-logic';
|
import { waitEditorLoad } from '@affine-test/kit/utils/page-logic';
|
||||||
|
|
||||||
test('block-hub should work', async ({ page }) => {
|
test('block-hub should work', async ({ page }) => {
|
||||||
await openHomePage(page);
|
await openHomePage(page);
|
||||||
await waitEditorLoad(page);
|
await waitEditorLoad(page);
|
||||||
await checkBlockHub(page);
|
await checkBlockHub(page);
|
||||||
await newPage(page);
|
|
||||||
await page.waitForTimeout(500);
|
|
||||||
await checkBlockHub(page);
|
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user