mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-23 21:38:44 +08:00
fix: add router defend
This commit is contained in:
@@ -1,20 +1,3 @@
|
|||||||
import {
|
import Loading from './loading';
|
||||||
StyledLoadingWrapper,
|
export * from './page-loading';
|
||||||
StyledLoading,
|
|
||||||
StyledLoadingItem,
|
|
||||||
} from './styled';
|
|
||||||
|
|
||||||
export const Loading = ({ size = 40 }: { size?: number }) => {
|
|
||||||
return (
|
|
||||||
<StyledLoadingWrapper size={size}>
|
|
||||||
<StyledLoading>
|
|
||||||
<StyledLoadingItem size={size} />
|
|
||||||
<StyledLoadingItem size={size} />
|
|
||||||
<StyledLoadingItem size={size} />
|
|
||||||
<StyledLoadingItem size={size} />
|
|
||||||
</StyledLoading>
|
|
||||||
</StyledLoadingWrapper>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Loading;
|
export default Loading;
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import {
|
||||||
|
StyledLoadingWrapper,
|
||||||
|
StyledLoading,
|
||||||
|
StyledLoadingItem,
|
||||||
|
} from './styled';
|
||||||
|
|
||||||
|
export const Loading = ({ size = 40 }: { size?: number }) => {
|
||||||
|
return (
|
||||||
|
<StyledLoadingWrapper size={size}>
|
||||||
|
<StyledLoading>
|
||||||
|
<StyledLoadingItem size={size} />
|
||||||
|
<StyledLoadingItem size={size} />
|
||||||
|
<StyledLoadingItem size={size} />
|
||||||
|
<StyledLoadingItem size={size} />
|
||||||
|
</StyledLoading>
|
||||||
|
</StyledLoadingWrapper>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Loading;
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
import { styled } from '@/styles';
|
||||||
|
import Loading from './loading';
|
||||||
|
|
||||||
|
// Used for the full page loading
|
||||||
|
const StyledLoadingContainer = styled('div')(({ theme }) => {
|
||||||
|
return {
|
||||||
|
height: '100vh',
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
color: '#6880FF',
|
||||||
|
h1: {
|
||||||
|
fontSize: '2em',
|
||||||
|
marginTop: '15px',
|
||||||
|
fontWeight: '600',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
export const PageLoading = ({ text = 'Loading...' }: { text?: string }) => {
|
||||||
|
return (
|
||||||
|
<StyledLoadingContainer>
|
||||||
|
<div className="wrapper">
|
||||||
|
<Loading />
|
||||||
|
<h1>{text}</h1>
|
||||||
|
</div>
|
||||||
|
</StyledLoadingContainer>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default PageLoading;
|
||||||
@@ -2,10 +2,43 @@ import HelpIsland from '@/components/help-island';
|
|||||||
import { WorkSpaceSliderBar } from '@/components/workspace-slider-bar';
|
import { WorkSpaceSliderBar } from '@/components/workspace-slider-bar';
|
||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
import { StyledPage, StyledWrapper } from './styles';
|
import { StyledPage, StyledWrapper } from './styles';
|
||||||
import { PropsWithChildren } from 'react';
|
import { PropsWithChildren, useEffect, useState } from 'react';
|
||||||
|
import { useAppState } from '@/providers/app-state-provider';
|
||||||
|
|
||||||
|
export const WorkspaceDefender = ({ children }: PropsWithChildren) => {
|
||||||
|
const router = useRouter();
|
||||||
|
const [workspaceLoaded, setWorkspaceLoaded] = useState(false);
|
||||||
|
const { synced, loadWorkspace, workspacesMeta } = useAppState();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const initWorkspace = async () => {
|
||||||
|
const workspaceId =
|
||||||
|
(router.query.workspaceId as string) ||
|
||||||
|
workspacesMeta?.[0]?.id ||
|
||||||
|
new Date().getTime().toString();
|
||||||
|
|
||||||
|
await loadWorkspace(workspaceId);
|
||||||
|
setWorkspaceLoaded(true);
|
||||||
|
};
|
||||||
|
if (!synced) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
initWorkspace();
|
||||||
|
}, [
|
||||||
|
loadWorkspace,
|
||||||
|
router.pathname,
|
||||||
|
router.query.workspaceId,
|
||||||
|
synced,
|
||||||
|
workspaceLoaded,
|
||||||
|
workspacesMeta,
|
||||||
|
]);
|
||||||
|
return <>{workspaceLoaded ? children : null}</>;
|
||||||
|
};
|
||||||
|
|
||||||
export const WorkspaceLayout = ({ children }: PropsWithChildren) => {
|
export const WorkspaceLayout = ({ children }: PropsWithChildren) => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledPage>
|
<StyledPage>
|
||||||
<WorkSpaceSliderBar />
|
<WorkSpaceSliderBar />
|
||||||
@@ -17,4 +50,11 @@ export const WorkspaceLayout = ({ children }: PropsWithChildren) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default WorkspaceLayout;
|
export const Layout = ({ children }: PropsWithChildren) => {
|
||||||
|
return (
|
||||||
|
<WorkspaceDefender>
|
||||||
|
<WorkspaceLayout>{children}</WorkspaceLayout>
|
||||||
|
</WorkspaceDefender>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
export default Layout;
|
||||||
|
|||||||
@@ -140,7 +140,7 @@ export const WorkSpaceSliderBar = () => {
|
|||||||
</Link>
|
</Link>
|
||||||
<StyledNewPageButton
|
<StyledNewPageButton
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
const pageId = await createPage?.current?.();
|
const pageId = await createPage?.();
|
||||||
if (pageId) {
|
if (pageId) {
|
||||||
openPage(pageId);
|
openPage(pageId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,12 +8,15 @@ import '@fontsource/space-mono';
|
|||||||
import '@fontsource/poppins';
|
import '@fontsource/poppins';
|
||||||
import '../utils/print-build-info';
|
import '../utils/print-build-info';
|
||||||
import ProviderComposer from '@/components/provider-composer';
|
import ProviderComposer from '@/components/provider-composer';
|
||||||
import type { ReactElement, ReactNode } from 'react';
|
import type { PropsWithChildren, ReactElement, ReactNode } from 'react';
|
||||||
import type { NextPage } from 'next';
|
import type { NextPage } from 'next';
|
||||||
import { AppStateProvider } from '@/providers/app-state-provider/provider';
|
import { AppStateProvider } from '@/providers/app-state-provider/provider';
|
||||||
import ConfirmProvider from '@/providers/confirm-provider';
|
import ConfirmProvider from '@/providers/confirm-provider';
|
||||||
import { ModalProvider } from '@/providers/global-modal-provider';
|
import { ModalProvider } from '@/providers/global-modal-provider';
|
||||||
|
import { useRouter } from 'next/router';
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
import { useAppState } from '@/providers/app-state-provider';
|
||||||
|
import { PageLoading } from '@/components/loading';
|
||||||
const ThemeProvider = dynamic(() => import('@/providers/themeProvider'), {
|
const ThemeProvider = dynamic(() => import('@/providers/themeProvider'), {
|
||||||
ssr: false,
|
ssr: false,
|
||||||
});
|
});
|
||||||
@@ -26,7 +29,7 @@ type AppPropsWithLayout = AppProps & {
|
|||||||
Component: NextPageWithLayout;
|
Component: NextPageWithLayout;
|
||||||
};
|
};
|
||||||
|
|
||||||
function MyApp({ Component, pageProps }: AppPropsWithLayout) {
|
const App = ({ Component, pageProps }: AppPropsWithLayout) => {
|
||||||
const getLayout = Component.getLayout || (page => page);
|
const getLayout = Component.getLayout || (page => page);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -40,10 +43,24 @@ function MyApp({ Component, pageProps }: AppPropsWithLayout) {
|
|||||||
<ConfirmProvider key="ConfirmProvider" />,
|
<ConfirmProvider key="ConfirmProvider" />,
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
{getLayout(<Component {...pageProps} />)}
|
<AppDefender>{getLayout(<Component {...pageProps} />)}</AppDefender>
|
||||||
</ProviderComposer>
|
</ProviderComposer>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default MyApp;
|
const AppDefender = ({ children }: PropsWithChildren) => {
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
const { synced } = useAppState();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (router.pathname === '/') {
|
||||||
|
router.replace('/workspace');
|
||||||
|
}
|
||||||
|
}, [router]);
|
||||||
|
|
||||||
|
return <div>{synced ? children : <PageLoading />}</div>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default App;
|
||||||
|
|||||||
@@ -1,16 +1,19 @@
|
|||||||
import { useRef, useEffect, ReactElement } from 'react';
|
import {
|
||||||
|
useRef,
|
||||||
|
useEffect,
|
||||||
|
useState,
|
||||||
|
ReactElement,
|
||||||
|
PropsWithChildren,
|
||||||
|
} from 'react';
|
||||||
import { styled } from '@/styles';
|
import { styled } from '@/styles';
|
||||||
import { EditorHeader } from '@/components/header';
|
import { EditorHeader } from '@/components/header';
|
||||||
import EdgelessToolbar from '@/components/edgeless-toolbar';
|
import EdgelessToolbar from '@/components/edgeless-toolbar';
|
||||||
import MobileModal from '@/components/mobile-modal';
|
import MobileModal from '@/components/mobile-modal';
|
||||||
import {
|
|
||||||
useLoadWorkspace,
|
|
||||||
useLoadPage,
|
|
||||||
} from '@/providers/app-state-provider/hooks';
|
|
||||||
import { useAppState } from '@/providers/app-state-provider/context';
|
import { useAppState } from '@/providers/app-state-provider/context';
|
||||||
import exampleMarkdown from '@/static/example-markdown';
|
import exampleMarkdown from '@/static/example-markdown';
|
||||||
import type { NextPageWithLayout } from '../..//_app';
|
import type { NextPageWithLayout } from '../..//_app';
|
||||||
import WorkspaceLayout from '@/components/workspace-layout';
|
import WorkspaceLayout from '@/components/workspace-layout';
|
||||||
|
import { useRouter } from 'next/router';
|
||||||
|
|
||||||
const StyledEditorContainer = styled('div')(({ theme }) => {
|
const StyledEditorContainer = styled('div')(({ theme }) => {
|
||||||
return {
|
return {
|
||||||
@@ -20,9 +23,8 @@ const StyledEditorContainer = styled('div')(({ theme }) => {
|
|||||||
|
|
||||||
const Page: NextPageWithLayout = () => {
|
const Page: NextPageWithLayout = () => {
|
||||||
const editorContainer = useRef<HTMLDivElement>(null);
|
const editorContainer = useRef<HTMLDivElement>(null);
|
||||||
const workspace = useLoadWorkspace();
|
const { createEditor, setEditor, currentPage, currentWorkspace } =
|
||||||
const page = useLoadPage();
|
useAppState();
|
||||||
const { createEditor, setEditor } = useAppState();
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const ret = () => {
|
const ret = () => {
|
||||||
@@ -32,29 +34,29 @@ const Page: NextPageWithLayout = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!workspace || !page) {
|
const editor = createEditor?.current?.(currentPage!);
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
const editor = createEditor?.current?.(page);
|
|
||||||
if (editor) {
|
if (editor) {
|
||||||
editorContainer.current?.appendChild(editor);
|
editorContainer.current?.appendChild(editor);
|
||||||
setEditor?.current?.(editor);
|
setEditor?.current?.(editor);
|
||||||
if (page.isEmpty) {
|
if (currentPage!.isEmpty) {
|
||||||
const title = 'Welcome to the AFFiNE Alpha';
|
const title = 'Welcome to the AFFiNE Alpha';
|
||||||
const pageId = page.addBlock({
|
const pageId = currentPage!.addBlock({
|
||||||
flavour: 'affine:page',
|
flavour: 'affine:page',
|
||||||
title,
|
title,
|
||||||
});
|
});
|
||||||
const groupId = page.addBlock({ flavour: 'affine:group' }, pageId);
|
const groupId = currentPage!.addBlock(
|
||||||
|
{ flavour: 'affine:group' },
|
||||||
|
pageId
|
||||||
|
);
|
||||||
editor.clipboard.importMarkdown(exampleMarkdown, `${groupId}`);
|
editor.clipboard.importMarkdown(exampleMarkdown, `${groupId}`);
|
||||||
workspace.setPageMeta(page.id, { title });
|
|
||||||
page.resetHistory();
|
currentWorkspace!.setPageMeta(currentPage!.id, { title });
|
||||||
|
currentPage!.resetHistory();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}, [workspace, page, createEditor, setEditor]);
|
}, [currentWorkspace, currentPage, createEditor, setEditor]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -66,8 +68,34 @@ const Page: NextPageWithLayout = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const PageDefender = ({ children }: PropsWithChildren) => {
|
||||||
|
const router = useRouter();
|
||||||
|
const [pageLoaded, setPageLoaded] = useState(false);
|
||||||
|
const { currentWorkspace, createPage, loadPage } = useAppState();
|
||||||
|
useEffect(() => {
|
||||||
|
const initPage = async () => {
|
||||||
|
const pageId = router.query.pageId as string;
|
||||||
|
const isPageExist = !!currentWorkspace!.meta.pageMetas.find(
|
||||||
|
p => p.id === pageId
|
||||||
|
);
|
||||||
|
if (!isPageExist) {
|
||||||
|
await createPage(pageId);
|
||||||
|
}
|
||||||
|
await loadPage(pageId);
|
||||||
|
setPageLoaded(true);
|
||||||
|
};
|
||||||
|
initPage();
|
||||||
|
}, [createPage, currentWorkspace, loadPage, router.query.pageId]);
|
||||||
|
|
||||||
|
return <>{pageLoaded ? children : null}</>;
|
||||||
|
};
|
||||||
|
|
||||||
Page.getLayout = function getLayout(page: ReactElement) {
|
Page.getLayout = function getLayout(page: ReactElement) {
|
||||||
return <WorkspaceLayout>{page}</WorkspaceLayout>;
|
return (
|
||||||
|
<WorkspaceLayout>
|
||||||
|
<PageDefender>{page}</PageDefender>
|
||||||
|
</WorkspaceLayout>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Page;
|
export default Page;
|
||||||
|
|||||||
@@ -1,17 +1,14 @@
|
|||||||
import { useLoadWorkspace } from '@/providers/app-state-provider/hooks';
|
|
||||||
import { PageList } from '@/components/page-list';
|
import { PageList } from '@/components/page-list';
|
||||||
import { AllPagesIcon } from '@blocksuite/icons';
|
import { AllPagesIcon } from '@blocksuite/icons';
|
||||||
import usePageMetaList from '@/hooks/use-page-meta-list';
|
import usePageMetaList from '@/hooks/use-page-meta-list';
|
||||||
import { PageListHeader } from '@/components/header';
|
import { PageListHeader } from '@/components/header';
|
||||||
import { NextPageWithLayout } from '@/pages/_app';
|
|
||||||
import { ReactElement } from 'react';
|
import { ReactElement } from 'react';
|
||||||
import WorkspaceLayout from '@/components/workspace-layout';
|
import WorkspaceLayout from '@/components/workspace-layout';
|
||||||
|
|
||||||
const All: NextPageWithLayout = () => {
|
const All = () => {
|
||||||
const workspace = useLoadWorkspace();
|
|
||||||
const pageMetaList = usePageMetaList();
|
const pageMetaList = usePageMetaList();
|
||||||
|
|
||||||
return workspace ? (
|
return (
|
||||||
<>
|
<>
|
||||||
<PageListHeader icon={<AllPagesIcon />}>All Page</PageListHeader>
|
<PageListHeader icon={<AllPagesIcon />}>All Page</PageListHeader>
|
||||||
<PageList
|
<PageList
|
||||||
@@ -19,7 +16,7 @@ const All: NextPageWithLayout = () => {
|
|||||||
showFavoriteTag={true}
|
showFavoriteTag={true}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
) : null;
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
All.getLayout = function getLayout(page: ReactElement) {
|
All.getLayout = function getLayout(page: ReactElement) {
|
||||||
|
|||||||
@@ -1,21 +1,18 @@
|
|||||||
import { useLoadWorkspace } from '@/providers/app-state-provider/hooks';
|
|
||||||
import { PageListHeader } from '@/components/header';
|
import { PageListHeader } from '@/components/header';
|
||||||
import { PageList } from '@/components/page-list';
|
import { PageList } from '@/components/page-list';
|
||||||
import { FavouritesIcon } from '@blocksuite/icons';
|
import { FavouritesIcon } from '@blocksuite/icons';
|
||||||
import usePageMetaList from '@/hooks/use-page-meta-list';
|
import usePageMetaList from '@/hooks/use-page-meta-list';
|
||||||
import { NextPageWithLayout } from '@/pages/_app';
|
|
||||||
import { ReactElement } from 'react';
|
import { ReactElement } from 'react';
|
||||||
import WorkspaceLayout from '@/components/workspace-layout';
|
import WorkspaceLayout from '@/components/workspace-layout';
|
||||||
|
|
||||||
export const Favorite: NextPageWithLayout = () => {
|
export const Favorite = () => {
|
||||||
const workspace = useLoadWorkspace();
|
|
||||||
const pageMetaList = usePageMetaList();
|
const pageMetaList = usePageMetaList();
|
||||||
return workspace ? (
|
return (
|
||||||
<>
|
<>
|
||||||
<PageListHeader icon={<FavouritesIcon />}>Favourites</PageListHeader>
|
<PageListHeader icon={<FavouritesIcon />}>Favourites</PageListHeader>
|
||||||
<PageList pageList={pageMetaList.filter(p => p.favorite && !p.trash)} />
|
<PageList pageList={pageMetaList.filter(p => p.favorite && !p.trash)} />
|
||||||
</>
|
</>
|
||||||
) : null;
|
);
|
||||||
};
|
};
|
||||||
Favorite.getLayout = function getLayout(page: ReactElement) {
|
Favorite.getLayout = function getLayout(page: ReactElement) {
|
||||||
return <WorkspaceLayout>{page}</WorkspaceLayout>;
|
return <WorkspaceLayout>{page}</WorkspaceLayout>;
|
||||||
|
|||||||
@@ -1,13 +1,31 @@
|
|||||||
import {
|
import React, { ReactElement, useEffect } from 'react';
|
||||||
useLoadWorkspace,
|
import { useRouter } from 'next/router';
|
||||||
useLoadPage,
|
import { useAppState } from '@/providers/app-state-provider/context';
|
||||||
} from '@/providers/app-state-provider/hooks';
|
import WorkspaceLayout from '@/components/workspace-layout';
|
||||||
|
|
||||||
const Page = () => {
|
const WorkspaceIndex = () => {
|
||||||
useLoadWorkspace();
|
const router = useRouter();
|
||||||
useLoadPage();
|
const { createPage, currentWorkspaceId, currentWorkspace } = useAppState();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const initPage = async () => {
|
||||||
|
const savedPageId = currentWorkspace!.meta.pageMetas[0]?.id;
|
||||||
|
if (savedPageId) {
|
||||||
|
router.replace(`/workspace/${currentWorkspaceId}/${savedPageId}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const pageId = await createPage();
|
||||||
|
router.replace(`/workspace/${currentWorkspaceId}/${pageId}`);
|
||||||
|
};
|
||||||
|
initPage();
|
||||||
|
}, [currentWorkspace, currentWorkspaceId, createPage, router]);
|
||||||
|
|
||||||
return <></>;
|
return <></>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Page;
|
WorkspaceIndex.getLayout = function getLayout(page: ReactElement) {
|
||||||
|
return <WorkspaceLayout>{page}</WorkspaceLayout>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default WorkspaceIndex;
|
||||||
|
|||||||
@@ -1,21 +1,18 @@
|
|||||||
import { useLoadWorkspace } from '@/providers/app-state-provider/hooks';
|
|
||||||
import { PageListHeader } from '@/components/header';
|
import { PageListHeader } from '@/components/header';
|
||||||
import { PageList } from '@/components/page-list';
|
import { PageList } from '@/components/page-list';
|
||||||
import { TrashIcon } from '@blocksuite/icons';
|
import { TrashIcon } from '@blocksuite/icons';
|
||||||
import usePageMetaList from '@/hooks/use-page-meta-list';
|
import usePageMetaList from '@/hooks/use-page-meta-list';
|
||||||
import { NextPageWithLayout } from '@/pages/_app';
|
|
||||||
import { ReactElement } from 'react';
|
import { ReactElement } from 'react';
|
||||||
import WorkspaceLayout from '@/components/workspace-layout';
|
import WorkspaceLayout from '@/components/workspace-layout';
|
||||||
|
|
||||||
export const Trash: NextPageWithLayout = () => {
|
export const Trash = () => {
|
||||||
const workspace = useLoadWorkspace();
|
|
||||||
const pageMetaList = usePageMetaList();
|
const pageMetaList = usePageMetaList();
|
||||||
return workspace ? (
|
return (
|
||||||
<>
|
<>
|
||||||
<PageListHeader icon={<TrashIcon />}>Trash</PageListHeader>
|
<PageListHeader icon={<TrashIcon />}>Trash</PageListHeader>
|
||||||
<PageList pageList={pageMetaList.filter(p => p.trash)} isTrash={true} />
|
<PageList pageList={pageMetaList.filter(p => p.trash)} isTrash={true} />
|
||||||
</>
|
</>
|
||||||
) : null;
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
Trash.getLayout = function getLayout(page: ReactElement) {
|
Trash.getLayout = function getLayout(page: ReactElement) {
|
||||||
|
|||||||
@@ -1,5 +1,21 @@
|
|||||||
const Page = () => {
|
import React, { ReactElement, useEffect } from 'react';
|
||||||
return <div>Hello, there is [workspace]/index.</div>;
|
import WorkspaceLayout from '@/components/workspace-layout';
|
||||||
|
import { useAppState } from '@/providers/app-state-provider';
|
||||||
|
import { useRouter } from 'next/router';
|
||||||
|
|
||||||
|
export const WorkspaceIndex = () => {
|
||||||
|
const router = useRouter();
|
||||||
|
const { currentWorkspaceId } = useAppState();
|
||||||
|
useEffect(() => {
|
||||||
|
if (currentWorkspaceId) {
|
||||||
|
router.replace(`/workspace/${currentWorkspaceId}`);
|
||||||
|
}
|
||||||
|
}, [currentWorkspaceId, router]);
|
||||||
|
return <></>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Page;
|
WorkspaceIndex.getLayout = function getLayout(page: ReactElement) {
|
||||||
|
return <WorkspaceLayout>{page}</WorkspaceLayout>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default WorkspaceIndex;
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ export interface AppStateValue {
|
|||||||
currentPage: StorePage | null;
|
currentPage: StorePage | null;
|
||||||
|
|
||||||
editor: EditorContainer | null;
|
editor: EditorContainer | null;
|
||||||
|
synced: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AppStateContext extends AppStateValue {
|
export interface AppStateContext extends AppStateValue {
|
||||||
@@ -31,15 +32,9 @@ export interface AppStateContext extends AppStateValue {
|
|||||||
((page: StorePage) => EditorContainer | null) | undefined
|
((page: StorePage) => EditorContainer | null) | undefined
|
||||||
>;
|
>;
|
||||||
setEditor?: MutableRefObject<((page: EditorContainer) => void) | undefined>;
|
setEditor?: MutableRefObject<((page: EditorContainer) => void) | undefined>;
|
||||||
loadWorkspace?: MutableRefObject<
|
loadWorkspace: (workspaceId: string) => Promise<StoreWorkspace | null>;
|
||||||
((workspaceId: string) => Promise<StoreWorkspace | null> | null) | undefined
|
loadPage: (pageId: string) => Promise<StorePage | null>;
|
||||||
>;
|
createPage: (pageId?: string) => Promise<string | null>;
|
||||||
loadPage?: MutableRefObject<
|
|
||||||
((pageId: string) => Promise<StorePage | null> | null) | undefined
|
|
||||||
>;
|
|
||||||
createPage?: MutableRefObject<
|
|
||||||
((pageId?: string) => Promise<string | null>) | undefined
|
|
||||||
>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const AppState = createContext<AppStateContext>({
|
export const AppState = createContext<AppStateContext>({
|
||||||
@@ -56,9 +51,10 @@ export const AppState = createContext<AppStateContext>({
|
|||||||
setState: () => {},
|
setState: () => {},
|
||||||
createEditor: undefined,
|
createEditor: undefined,
|
||||||
setEditor: undefined,
|
setEditor: undefined,
|
||||||
loadWorkspace: undefined,
|
loadWorkspace: () => Promise.resolve(null),
|
||||||
loadPage: undefined,
|
loadPage: () => Promise.resolve(null),
|
||||||
createPage: undefined,
|
createPage: () => Promise.resolve(null),
|
||||||
|
synced: false,
|
||||||
workspaces: {},
|
workspaces: {},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -89,15 +89,12 @@ const DynamicBlocksuite = ({
|
|||||||
p => p instanceof IndexedDBDocProvider
|
p => p instanceof IndexedDBDocProvider
|
||||||
);
|
);
|
||||||
if (indexDBProvider) {
|
if (indexDBProvider) {
|
||||||
(indexDBProvider as IndexedDBDocProvider).on('synced', async () => {
|
(indexDBProvider as IndexedDBDocProvider)?.on('synced', async () => {
|
||||||
const updates = await downloadWorkspace({ workspaceId });
|
// const updates = await downloadWorkspace({ workspaceId });
|
||||||
|
// updates &&
|
||||||
if (updates && updates.byteLength) {
|
// Workspace.Y.applyUpdate(workspace.doc, new Uint8Array(updates));
|
||||||
Workspace.Y.applyUpdate(workspace.doc, new Uint8Array(updates));
|
// if after update, the space:meta is empty, then we need to get map with doc
|
||||||
// if after update, the space:meta is empty, then we need to get map with doc
|
workspace.doc.getMap('space:meta');
|
||||||
workspace.doc.getMap('space:meta');
|
|
||||||
}
|
|
||||||
|
|
||||||
resolve(workspace);
|
resolve(workspace);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ export const useLoadWorkspace = () => {
|
|||||||
const workspaceId = router.query.workspaceId as string;
|
const workspaceId = router.query.workspaceId as string;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
loadWorkspace?.current?.(workspaceId);
|
loadWorkspace?.(workspaceId);
|
||||||
}, [workspaceId, loadWorkspace]);
|
}, [workspaceId, loadWorkspace]);
|
||||||
|
|
||||||
return currentWorkspaceId === workspaceId ? currentWorkspace : null;
|
return currentWorkspaceId === workspaceId ? currentWorkspace : null;
|
||||||
@@ -29,7 +29,7 @@ export const useLoadPage = () => {
|
|||||||
}
|
}
|
||||||
const page = pageId ? workspace?.getPage(pageId) : null;
|
const page = pageId ? workspace?.getPage(pageId) : null;
|
||||||
if (page) {
|
if (page) {
|
||||||
loadPage?.current?.(pageId);
|
loadPage?.(pageId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,7 +39,7 @@ export const useLoadPage = () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
createPage?.current?.()?.then(async pageId => {
|
createPage?.()?.then(async pageId => {
|
||||||
if (!pageId) {
|
if (!pageId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import {
|
|||||||
WorkspaceType,
|
WorkspaceType,
|
||||||
getWorkspaceDetail,
|
getWorkspaceDetail,
|
||||||
} from '@pathfinder/data-services';
|
} from '@pathfinder/data-services';
|
||||||
import { AppState } from './context';
|
import { AppState, AppStateContext } from './context';
|
||||||
import type {
|
import type {
|
||||||
AppStateValue,
|
AppStateValue,
|
||||||
CreateEditorHandler,
|
CreateEditorHandler,
|
||||||
@@ -29,6 +29,9 @@ export const AppStateProvider = ({ children }: { children?: ReactNode }) => {
|
|||||||
currentPage: null,
|
currentPage: null,
|
||||||
editor: null,
|
editor: null,
|
||||||
workspaces: {},
|
workspaces: {},
|
||||||
|
// Synced is used to ensure that the provider has synced with the server,
|
||||||
|
// So after Synced set to true, the other state is sure to be set.
|
||||||
|
synced: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
const [loadWorkspaceHandler, _setLoadWorkspaceHandler] =
|
const [loadWorkspaceHandler, _setLoadWorkspaceHandler] =
|
||||||
@@ -50,12 +53,14 @@ export const AppStateProvider = ({ children }: { children?: ReactNode }) => {
|
|||||||
[_setCreateEditorHandler]
|
[_setCreateEditorHandler]
|
||||||
);
|
);
|
||||||
|
|
||||||
const loadWorkspace =
|
const loadWorkspace = useRef<AppStateContext['loadWorkspace']>(() =>
|
||||||
useRef<(workspaceId: string) => Promise<Workspace | null> | null>();
|
Promise.resolve(null)
|
||||||
|
);
|
||||||
loadWorkspace.current = async (workspaceId: string) => {
|
loadWorkspace.current = async (workspaceId: string) => {
|
||||||
if (state.currentWorkspaceId === workspaceId) {
|
if (state.currentWorkspaceId === workspaceId) {
|
||||||
return state.currentWorkspace;
|
return state.currentWorkspace;
|
||||||
}
|
}
|
||||||
|
|
||||||
const workspace = (await loadWorkspaceHandler?.(workspaceId, true)) || null;
|
const workspace = (await loadWorkspaceHandler?.(workspaceId, true)) || null;
|
||||||
|
|
||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
@@ -72,7 +77,9 @@ export const AppStateProvider = ({ children }: { children?: ReactNode }) => {
|
|||||||
}));
|
}));
|
||||||
return workspace;
|
return workspace;
|
||||||
};
|
};
|
||||||
const loadPage = useRef<(pageId: string) => Promise<Page | null> | null>();
|
const loadPage = useRef<AppStateContext['loadPage']>(() =>
|
||||||
|
Promise.resolve(null)
|
||||||
|
);
|
||||||
loadPage.current = async (pageId: string) => {
|
loadPage.current = async (pageId: string) => {
|
||||||
const { currentWorkspace, currentPage } = state;
|
const { currentWorkspace, currentPage } = state;
|
||||||
if (pageId === currentPage?.pageId) {
|
if (pageId === currentPage?.pageId) {
|
||||||
@@ -114,7 +121,9 @@ export const AppStateProvider = ({ children }: { children?: ReactNode }) => {
|
|||||||
setState(state => ({ ...state, editor }));
|
setState(state => ({ ...state, editor }));
|
||||||
};
|
};
|
||||||
|
|
||||||
const createPage = useRef<(pageId?: string) => Promise<string | null>>();
|
const createPage = useRef<AppStateContext['createPage']>(() =>
|
||||||
|
Promise.resolve(null)
|
||||||
|
);
|
||||||
|
|
||||||
createPage.current = (pageId: string = Date.now().toString()) =>
|
createPage.current = (pageId: string = Date.now().toString()) =>
|
||||||
new Promise<string | null>(resolve => {
|
new Promise<string | null>(resolve => {
|
||||||
@@ -130,8 +139,16 @@ export const AppStateProvider = ({ children }: { children?: ReactNode }) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (!loadWorkspaceHandler) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const callback = async (user: AccessTokenMessage | null) => {
|
const callback = async (user: AccessTokenMessage | null) => {
|
||||||
const workspacesMeta = user ? await getWorkspaces() : [];
|
const workspacesMeta = user
|
||||||
|
? await getWorkspaces().catch(() => {
|
||||||
|
return [];
|
||||||
|
})
|
||||||
|
: [];
|
||||||
|
|
||||||
const workspacesList = await Promise.all(
|
const workspacesList = await Promise.all(
|
||||||
workspacesMeta.map(async ({ id }) => {
|
workspacesMeta.map(async ({ id }) => {
|
||||||
const workspace = (await loadWorkspaceHandler?.(id)) || null;
|
const workspace = (await loadWorkspaceHandler?.(id)) || null;
|
||||||
@@ -146,7 +163,13 @@ export const AppStateProvider = ({ children }: { children?: ReactNode }) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// TODO: add meta info to workspace meta
|
// TODO: add meta info to workspace meta
|
||||||
setState(state => ({ ...state, user: user, workspacesMeta, workspaces }));
|
setState(state => ({
|
||||||
|
...state,
|
||||||
|
user: user,
|
||||||
|
workspacesMeta,
|
||||||
|
workspaces,
|
||||||
|
synced: true,
|
||||||
|
}));
|
||||||
};
|
};
|
||||||
authorizationEvent.onChange(callback);
|
authorizationEvent.onChange(callback);
|
||||||
|
|
||||||
@@ -161,9 +184,9 @@ export const AppStateProvider = ({ children }: { children?: ReactNode }) => {
|
|||||||
setState,
|
setState,
|
||||||
createEditor,
|
createEditor,
|
||||||
setEditor,
|
setEditor,
|
||||||
loadWorkspace,
|
loadWorkspace: loadWorkspace.current,
|
||||||
loadPage,
|
loadPage: loadPage.current,
|
||||||
createPage,
|
createPage: createPage.current,
|
||||||
}),
|
}),
|
||||||
[state, setState, loadPage, loadWorkspace]
|
[state, setState, loadPage, loadWorkspace]
|
||||||
);
|
);
|
||||||
@@ -174,7 +197,7 @@ export const AppStateProvider = ({ children }: { children?: ReactNode }) => {
|
|||||||
setLoadWorkspaceHandler={setLoadWorkspaceHandler}
|
setLoadWorkspaceHandler={setLoadWorkspaceHandler}
|
||||||
setCreateEditorHandler={setCreateEditorHandler}
|
setCreateEditorHandler={setCreateEditorHandler}
|
||||||
/>
|
/>
|
||||||
{loadWorkspaceHandler ? children : null}
|
{children}
|
||||||
</AppState.Provider>
|
</AppState.Provider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { createContext, useContext, useState } from 'react';
|
import { createContext, useContext, useEffect, useState } from 'react';
|
||||||
import type { PropsWithChildren } from 'react';
|
import type { PropsWithChildren } from 'react';
|
||||||
import ShortcutsModal from '@/components/shortcuts-modal';
|
import ShortcutsModal from '@/components/shortcuts-modal';
|
||||||
import ContactModal from '@/components/contact-modal';
|
import ContactModal from '@/components/contact-modal';
|
||||||
@@ -49,6 +49,10 @@ export const ModalProvider = ({
|
|||||||
[key]: visible ?? !modalMap[key],
|
[key]: visible ?? !modalMap[key],
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
useEffect(() => {
|
||||||
|
// @ts-ignore
|
||||||
|
window.triggerHandler = () => triggerHandler('login');
|
||||||
|
}, [triggerHandler]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ModalContext.Provider
|
<ModalContext.Provider
|
||||||
|
|||||||
Generated
+7
-7
@@ -122,7 +122,7 @@ importers:
|
|||||||
swr: ^2.0.0
|
swr: ^2.0.0
|
||||||
typescript: ^4.8.4
|
typescript: ^4.8.4
|
||||||
dependencies:
|
dependencies:
|
||||||
axios: 1.2.1
|
axios: 1.2.0
|
||||||
encoding: 0.1.13
|
encoding: 0.1.13
|
||||||
firebase: 9.13.0_encoding@0.1.13
|
firebase: 9.13.0_encoding@0.1.13
|
||||||
ky: 0.33.0
|
ky: 0.33.0
|
||||||
@@ -1241,7 +1241,7 @@ packages:
|
|||||||
engines: {node: ^8.13.0 || >=10.10.0}
|
engines: {node: ^8.13.0 || >=10.10.0}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@grpc/proto-loader': 0.7.3
|
'@grpc/proto-loader': 0.7.3
|
||||||
'@types/node': 18.11.17
|
'@types/node': 18.7.18
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@grpc/proto-loader/0.6.13:
|
/@grpc/proto-loader/0.6.13:
|
||||||
@@ -2375,10 +2375,10 @@ packages:
|
|||||||
|
|
||||||
/@types/node/18.11.17:
|
/@types/node/18.11.17:
|
||||||
resolution: {integrity: sha512-HJSUJmni4BeDHhfzn6nF0sVmd1SMezP7/4F0Lq+aXzmp2xm9O7WXrUtHW/CHlYVtZUbByEvWidHqRtcJXGF2Ng==}
|
resolution: {integrity: sha512-HJSUJmni4BeDHhfzn6nF0sVmd1SMezP7/4F0Lq+aXzmp2xm9O7WXrUtHW/CHlYVtZUbByEvWidHqRtcJXGF2Ng==}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/@types/node/18.7.18:
|
/@types/node/18.7.18:
|
||||||
resolution: {integrity: sha512-m+6nTEOadJZuTPkKR/SYK3A2d7FZrgElol9UP1Kae90VVU4a6mxnPuLiIW1m4Cq4gZ/nWb9GrdVXJCoCazDAbg==}
|
resolution: {integrity: sha512-m+6nTEOadJZuTPkKR/SYK3A2d7FZrgElol9UP1Kae90VVU4a6mxnPuLiIW1m4Cq4gZ/nWb9GrdVXJCoCazDAbg==}
|
||||||
dev: true
|
|
||||||
|
|
||||||
/@types/parse-json/4.0.0:
|
/@types/parse-json/4.0.0:
|
||||||
resolution: {integrity: sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==}
|
resolution: {integrity: sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==}
|
||||||
@@ -2765,8 +2765,8 @@ packages:
|
|||||||
engines: {node: '>=4'}
|
engines: {node: '>=4'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/axios/1.2.1:
|
/axios/1.2.0:
|
||||||
resolution: {integrity: sha512-I88cFiGu9ryt/tfVEi4kX2SITsvDddTajXTOFmt2uK1ZVA8LytjtdeyefdQWEf5PU8w+4SSJDoYnggflB5tW4A==}
|
resolution: {integrity: sha512-zT7wZyNYu3N5Bu0wuZ6QccIf93Qk1eV8LOewxgjOZFd2DenOs98cJ7+Y6703d0wkaXGY6/nZd4EweJaHz9uzQw==}
|
||||||
dependencies:
|
dependencies:
|
||||||
follow-redirects: 1.15.2
|
follow-redirects: 1.15.2
|
||||||
form-data: 4.0.0
|
form-data: 4.0.0
|
||||||
@@ -5659,7 +5659,7 @@ packages:
|
|||||||
'@protobufjs/pool': 1.1.0
|
'@protobufjs/pool': 1.1.0
|
||||||
'@protobufjs/utf8': 1.1.0
|
'@protobufjs/utf8': 1.1.0
|
||||||
'@types/long': 4.0.2
|
'@types/long': 4.0.2
|
||||||
'@types/node': 18.11.17
|
'@types/node': 18.7.18
|
||||||
long: 4.0.0
|
long: 4.0.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
@@ -5678,7 +5678,7 @@ packages:
|
|||||||
'@protobufjs/path': 1.1.2
|
'@protobufjs/path': 1.1.2
|
||||||
'@protobufjs/pool': 1.1.0
|
'@protobufjs/pool': 1.1.0
|
||||||
'@protobufjs/utf8': 1.1.0
|
'@protobufjs/utf8': 1.1.0
|
||||||
'@types/node': 18.11.17
|
'@types/node': 18.7.18
|
||||||
long: 5.2.0
|
long: 5.2.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user