Merge branch 'feat/filesystem_and_search' of github.com:toeverything/AFFiNE into feat/filesystem_and_search

This commit is contained in:
DiamondThree
2022-12-23 19:30:33 +08:00
10 changed files with 127 additions and 69 deletions
@@ -3,14 +3,11 @@ import { WorkSpaceSliderBar } from '@/components/workspace-slider-bar';
import { useRouter } from 'next/router';
import { StyledPage, StyledWrapper } from './styles';
import { PropsWithChildren } from 'react';
import { useAppState } from '@/providers/app-state-provider';
import { useInitWorkspace } from '@/hooks/use-init-workspace';
import useEnsureWorkspace from '@/hooks/use-ensure-workspace';
export const WorkspaceDefender = ({ children }: PropsWithChildren) => {
const { synced } = useAppState();
const { loading } = useInitWorkspace(!synced);
return <>{!loading ? children : null}</>;
const { workspaceLoaded } = useEnsureWorkspace();
return <>{workspaceLoaded ? children : null}</>;
};
export const WorkspaceLayout = ({ children }: PropsWithChildren) => {
@@ -57,7 +57,7 @@ export const GeneralPage = ({
meta => meta.id === workspace.id
);
const nextWorkSpaceId =
currentWorkspaceIndex > workspacesMeta.length - 1
currentWorkspaceIndex === workspacesMeta.length - 1
? workspacesMeta[currentWorkspaceIndex - 1]?.id
: workspacesMeta[currentWorkspaceIndex + 1]?.id;
const handleClickDelete = () => {
@@ -90,7 +90,7 @@ export const GeneralPage = ({
alt="workspace avatar"
src={
workspaces[workspace.id]?.meta.avatar
? 'api/blob/' + workspaces[workspace.id]?.meta.avatar
? '/api/blob/' + workspaces[workspace.id]?.meta.avatar
: ''
}
>
@@ -109,9 +109,11 @@ export const SelectorPopperContent = ({
key={workspace.id}
id={workspace.id}
icon={
workspaces[workspace.id]?.meta.avatar
? 'api/blob/' + workspaces[workspace.id]?.meta.avatar
: ''
(workspaces[workspace.id]?.meta.avatar &&
`/api/blob/${workspaces[workspace.id]?.meta.avatar}`) ||
(workspace.type === WorkspaceType.Private
? user.avatar_url
: `loading...`)
}
onClick={handleClickSettingWorkspace}
name={
@@ -24,12 +24,18 @@ export const WorkspaceSelector = () => {
<Avatar
alt="Affine"
src={
currentWorkspace?.meta.avatar
? `api/blob/${currentWorkspace?.meta.avatar}`
: ''
(currentWorkspace?.meta.avatar &&
`/api/blob/${currentWorkspace?.meta.avatar}`) ||
(workspaceMeta?.type === WorkspaceType.Private && user
? user.avatar_url
: '')
}
>
<AffineIcon />
{workspaceMeta?.type === WorkspaceType.Private && user ? (
user?.name[0]
) : (
<AffineIcon />
)}
</Avatar>
<WorkspaceName>
{currentWorkspace?.meta.name ||
@@ -0,0 +1,54 @@
import { useState, useEffect } from 'react';
import { useAppState } from '@/providers/app-state-provider';
import { useRouter } from 'next/router';
// It is a fully effective hook
// Cause it not just ensure workspace loaded, but also have router change.
export const useEnsureWorkspace = () => {
const [workspaceLoaded, setWorkspaceLoaded] = useState(false);
const { workspacesMeta, loadWorkspace, synced, user } = useAppState();
const router = useRouter();
const defaultOutLineWorkspaceId = '112233';
useEffect(() => {
if (!synced) {
setWorkspaceLoaded(false);
return;
}
// If router.query.workspaceId is not in workspace list, jump to 404 page
// If workspacesMeta is empty, we need to create a default workspace but not jump to 404
if (
workspacesMeta.length &&
router.query.workspaceId &&
workspacesMeta.findIndex(
meta => meta.id.toString() === router.query.workspaceId
) === -1
) {
router.push('/404');
return;
}
// If user is not login and input a custom workspaceId, jump to 404 page
if (
!user &&
router.query.workspaceId &&
router.query.workspaceId !== defaultOutLineWorkspaceId
) {
router.push('/404');
return;
}
const workspaceId = user
? (router.query.workspaceId as string) || workspacesMeta?.[0]?.id
: defaultOutLineWorkspaceId;
loadWorkspace(workspaceId).finally(() => {
setWorkspaceLoaded(true);
});
}, [loadWorkspace, router, synced, user, workspacesMeta]);
return {
workspaceLoaded,
};
};
export default useEnsureWorkspace;
@@ -40,7 +40,8 @@ const Page: NextPageWithLayout = () => {
editorContainer.current?.appendChild(editor);
setEditor?.current?.(editor);
if (currentPage!.isEmpty) {
const title = 'Welcome to the AFFiNE Alpha';
const isFirstPage = currentWorkspace?.meta.pageMetas.length === 1;
const title = isFirstPage ? 'Welcome to the AFFiNE Alpha' : '';
const pageId = currentPage!.addBlock({
flavour: 'affine:page',
title,
@@ -49,9 +50,12 @@ const Page: NextPageWithLayout = () => {
{ flavour: 'affine:group' },
pageId
);
editor.clipboard.importMarkdown(exampleMarkdown, `${groupId}`);
currentWorkspace!.setPageMeta(currentPage!.id, { title });
currentPage!.addBlock({ flavour: 'affine:group' }, pageId);
// If this is a first page in workspace, init an introduction markdown
if (isFirstPage) {
editor.clipboard.importMarkdown(exampleMarkdown, `${groupId}`);
currentWorkspace!.setPageMeta(currentPage!.id, { title });
}
currentPage!.resetHistory();
}
}
@@ -1,19 +1,19 @@
import { useEffect } from 'react';
import { useRouter } from 'next/router';
import { useAppState } from '@/providers/app-state-provider/context';
import { useInitWorkspace } from '@/hooks/use-init-workspace';
import useEnsureWorkspace from '@/hooks/use-ensure-workspace';
const WorkspaceIndex = () => {
const router = useRouter();
const { createPage, currentWorkspaceId } = useAppState();
const { workspace } = useInitWorkspace();
const { createPage, currentWorkspaceId, currentWorkspace } = useAppState();
const { workspaceLoaded } = useEnsureWorkspace();
useEffect(() => {
const initPage = async () => {
if (!workspace) {
if (!workspaceLoaded) {
return;
}
const savedPageId = workspace.meta.pageMetas[0]?.id;
const savedPageId = currentWorkspace?.meta.pageMetas[0]?.id;
if (savedPageId) {
router.replace(`/workspace/${currentWorkspaceId}/${savedPageId}`);
return;
@@ -23,7 +23,13 @@ const WorkspaceIndex = () => {
router.replace(`/workspace/${currentWorkspaceId}/${pageId}`);
};
initPage();
}, [workspace, currentWorkspaceId, createPage, router]);
}, [
currentWorkspace,
currentWorkspaceId,
createPage,
router,
workspaceLoaded,
]);
return <></>;
};
+7 -5
View File
@@ -1,16 +1,18 @@
import { useEffect } from 'react';
import { useRouter } from 'next/router';
import { useInitWorkspace } from '@/hooks/use-init-workspace';
import { useAppState } from '@/providers/app-state-provider';
import useEnsureWorkspace from '@/hooks/use-ensure-workspace';
export const WorkspaceIndex = () => {
const router = useRouter();
const { workspaceId, workspace } = useInitWorkspace();
const { currentWorkspaceId } = useAppState();
const { workspaceLoaded } = useEnsureWorkspace();
useEffect(() => {
if (workspace) {
router.push(`/workspace/${workspaceId}`);
if (workspaceLoaded) {
router.push(`/workspace/${currentWorkspaceId}`);
}
}, [router, workspace, workspaceId]);
}, [currentWorkspaceId, router, workspaceLoaded]);
return <></>;
};
@@ -27,8 +27,7 @@ const DynamicBlocksuite = ({
useEffect(() => {
const openWorkspace: LoadWorkspaceHandler = (
workspaceId: string,
websocket = false,
user
websocket = false
) =>
// eslint-disable-next-line no-async-promise-executor
new Promise(async resolve => {
@@ -64,16 +63,22 @@ const DynamicBlocksuite = ({
const indexDBProvider = workspace.providers.find(
p => p instanceof IndexedDBDocProvider
);
if (user) {
const updates = await downloadWorkspace({ workspaceId });
updates &&
StoreWorkspace.Y.applyUpdate(
workspace.doc,
new Uint8Array(updates)
);
// if after update, the space:meta is empty, then we need to get map with doc
workspace.doc.getMap('space:meta');
}
await new Promise<undefined>(resolve => {
downloadWorkspace({ workspaceId })
.then(async updates => {
updates &&
StoreWorkspace.Y.applyUpdate(
workspace.doc,
new Uint8Array(updates)
);
// if after update, the space:meta is empty, then we need to get map with doc
workspace.doc.getMap('space:meta');
resolve(undefined);
})
.catch(() => {
resolve(undefined);
});
});
if (indexDBProvider) {
(indexDBProvider as IndexedDBDocProvider).on('synced', async () => {
resolve(workspace);
@@ -41,31 +41,11 @@ export const AppStateProvider = ({ children }: { children?: ReactNode }) => {
workspaces: {},
});
const refreshWorkspacesInfo = async (
workspaces: AppStateValue['workspaces']
) => {
return Promise.all(
Object.entries(workspaces).map(async ([workspaceId, workspace]) => {
if (workspace) {
const updates = await downloadWorkspace({ workspaceId });
updates &&
StoreWorkspace.Y.applyUpdate(
workspace.doc,
new Uint8Array(updates)
);
// if after update, the space:meta is empty, then we need to get map with doc
workspace.doc.getMap('space:meta');
}
})
);
};
useEffect(() => {
(async () => {
const workspacesList = await Promise.all(
state.workspacesMeta.map(async ({ id }) => {
const workspace =
(await loadWorkspaceHandler?.(id, false, state.user)) || null;
const workspace = (await loadWorkspaceHandler?.(id, false)) || null;
return { id, workspace };
})
);
@@ -73,7 +53,6 @@ export const AppStateProvider = ({ children }: { children?: ReactNode }) => {
workspacesList.forEach(({ id, workspace }) => {
workspaces[id] = workspace;
});
await refreshWorkspacesInfo(workspaces);
setState(state => ({
...state,
workspaces,
@@ -108,9 +87,7 @@ export const AppStateProvider = ({ children }: { children?: ReactNode }) => {
if (state.currentWorkspaceId === workspaceId) {
return state.currentWorkspace;
}
const workspace =
(await loadWorkspaceHandler?.(workspaceId, true, state.user)) || null;
const workspace = (await loadWorkspaceHandler?.(workspaceId, true)) || null;
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
@@ -194,6 +171,12 @@ export const AppStateProvider = ({ children }: { children?: ReactNode }) => {
return;
}
const callback = async (user: AccessTokenMessage | null) => {
const isLogin = token.isLogin;
setState(state => ({
...state,
user,
}));
const workspacesMeta = user
? await getWorkspaces().catch(() => {
return [];
@@ -202,9 +185,8 @@ export const AppStateProvider = ({ children }: { children?: ReactNode }) => {
setState(state => ({
...state,
user: user,
workspacesMeta,
synced: true,
synced: isLogin ? !!user : true,
}));
};
token.onChange(callback);