mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-16 09:36:17 +08:00
Merge branch 'feat/filesystem_and_search' of github.com:toeverything/AFFiNE into feat/filesystem_and_search
This commit is contained in:
@@ -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
|
||||
: ''
|
||||
}
|
||||
>
|
||||
|
||||
+5
-3
@@ -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={
|
||||
|
||||
+10
-4
@@ -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 <></>;
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user