merge master

This commit is contained in:
tzhangchi
2023-01-03 21:57:33 +08:00
64 changed files with 2171 additions and 1652 deletions

View File

@@ -87,7 +87,7 @@ const PopoverContent = () => {
confirmType: 'danger',
}).then(confirm => {
confirm && toggleDeletePage(id);
toast('Moved to Trash');
confirm && toast('Moved to Trash');
});
}}
icon={<TrashIcon />}

View File

@@ -4,7 +4,7 @@ import { Modal, ModalWrapper, ModalCloseButton } from '@/ui/modal';
import { Button } from '@/ui/button';
import Input from '@/ui/input';
import { useState } from 'react';
import { inviteMember, getUserByEmail } from '@affine/data-services';
import { getDataCenter } from '@affine/datacenter';
import { Avatar } from '@mui/material';
interface LoginModalProps {
open: boolean;
@@ -60,15 +60,19 @@ export const InviteMembers = ({
setShowTip(false);
debounce(
() => {
getUserByEmail({
email: value,
workspace_id: workspaceId,
}).then(data => {
if (data?.name) {
setUserData(data);
setShowTip(false);
}
});
getDataCenter()
.then(dc =>
dc.apis.getUserByEmail({
email: value,
workspace_id: workspaceId,
})
)
.then(data => {
if (data?.name) {
setUserData(data);
setShowTip(false);
}
});
},
300,
true
@@ -130,7 +134,8 @@ export const InviteMembers = ({
shape="circle"
type="primary"
onClick={() => {
inviteMember({ id: workspaceId, email: email })
getDataCenter()
.then(dc => dc.apis.inviteMember({ id: workspaceId, email }))
.then(() => {
onClose();
onInviteSuccess && onInviteSuccess();

View File

@@ -1,4 +1,4 @@
import { signInWithGoogle } from '@affine/data-services';
import { getDataCenter } from '@affine/datacenter';
import { styled } from '@/styles';
import { Button } from '@/ui/button';
import { useModal } from '@/providers/global-modal-provider';
@@ -9,7 +9,8 @@ export const GoogleLoginButton = () => {
return (
<StyledGoogleButton
onClick={() => {
signInWithGoogle()
getDataCenter()
.then(dc => dc.apis.signInWithGoogle?.())
.then(() => {
triggerLoginModal();
})

View File

@@ -11,7 +11,7 @@ import {
import { useState } from 'react';
import { ModalCloseButton } from '@/ui/modal';
import { Button } from '@/ui/button';
import { deleteWorkspace } from '@affine/data-services';
import { getDataCenter } from '@affine/datacenter';
import { useRouter } from 'next/router';
import { useAppState } from '@/providers/app-state-provider';
@@ -39,7 +39,8 @@ export const WorkspaceDelete = ({
};
const handleDelete = async () => {
await deleteWorkspace({ id: workspaceId });
const dc = await getDataCenter();
await dc.apis.deleteWorkspace({ id: workspaceId });
router.push(`/workspace/${nextWorkSpaceId}`);
refreshWorkspacesMeta();
onClose();

View File

@@ -9,7 +9,7 @@ import { StyledSettingH2 } from '../style';
import { useState } from 'react';
import { Button } from '@/ui/button';
import Input from '@/ui/input';
import { uploadBlob, Workspace, WorkspaceType } from '@affine/data-services';
import { getDataCenter, Workspace, WorkspaceType } from '@affine/datacenter';
import { useAppState } from '@/providers/app-state-provider';
import { WorkspaceDetails } from '@/components/workspace-slider-bar/WorkspaceSelector/SelectorPopperContent';
import { WorkspaceDelete } from './delete';
@@ -74,9 +74,11 @@ export const GeneralPage = ({
const fileChange = async (file: File) => {
setUploading(true);
const blob = new Blob([file], { type: file.type });
const blobId = await uploadBlob({ blob }).finally(() => {
setUploading(false);
});
const blobId = await getDataCenter()
.then(dc => dc.apis.uploadBlob({ blob }))
.finally(() => {
setUploading(false);
});
if (blobId) {
currentWorkspace?.meta.setAvatar(blobId);
workspaces[workspace.id]?.meta.setAvatar(blobId);

View File

@@ -7,7 +7,7 @@ import {
} from './style';
import { ModalCloseButton } from '@/ui/modal';
import { Button } from '@/ui/button';
import { leaveWorkspace } from '@affine/data-services';
import { getDataCenter } from '@affine/datacenter';
import { useRouter } from 'next/router';
import { useAppState } from '@/providers/app-state-provider';
@@ -28,7 +28,8 @@ export const WorkspaceLeave = ({
const router = useRouter();
const { refreshWorkspacesMeta } = useAppState();
const handleLeave = async () => {
await leaveWorkspace({ id: workspaceId });
const dc = await getDataCenter();
await dc.apis.leaveWorkspace({ id: workspaceId });
router.push(`/workspace/${nextWorkSpaceId}`);
refreshWorkspacesMeta();
onClose();

View File

@@ -36,13 +36,7 @@ import { useCallback, useEffect, useState } from 'react';
import { Button, IconButton } from '@/ui/button';
import Input from '@/ui/input';
import { InviteMembers } from '../invite-members/index';
import {
getWorkspaceMembers,
Workspace,
Member,
removeMember,
updateWorkspace,
} from '@affine/data-services';
import { Workspace, Member, getDataCenter } from '@affine/datacenter';
import { Avatar } from '@mui/material';
import { Menu, MenuItem } from '@/ui/menu';
import { toast } from '@/ui/toast';
@@ -169,9 +163,12 @@ const MembersPage = ({ workspace }: { workspace: Workspace }) => {
const [isInviteModalShow, setIsInviteModalShow] = useState(false);
const [members, setMembers] = useState<Member[]>([]);
const refreshMembers = useCallback(() => {
getWorkspaceMembers({
id: workspace.id,
})
getDataCenter()
.then(dc =>
dc.apis.getWorkspaceMembers({
id: workspace.id,
})
)
.then(data => {
setMembers(data);
})
@@ -236,13 +233,17 @@ const MembersPage = ({ workspace }: { workspace: Workspace }) => {
// confirmText: 'Delete',
// confirmType: 'danger',
// }).then(confirm => {
removeMember({
permissionId: member.id,
}).then(() => {
// console.log('data: ', data);
toast('Moved to Trash');
refreshMembers();
});
getDataCenter()
.then(dc =>
dc.apis.removeMember({
permissionId: member.id,
})
)
.then(() => {
// console.log('data: ', data);
toast('Moved to Trash');
refreshMembers();
});
// });
}}
icon={<TrashIcon />}
@@ -297,13 +298,17 @@ const PublishPage = ({ workspace }: { workspace: Workspace }) => {
workspace.public
);
const togglePublic = (flag: boolean) => {
updateWorkspace({
id: workspace.id,
public: flag,
}).then(data => {
setPublicStatus(data?.public);
toast('Updated Public Status Success');
});
getDataCenter()
.then(dc =>
dc.apis.updateWorkspace({
id: workspace.id,
public: flag,
})
)
.then(data => {
setPublicStatus(data?.public);
toast('Updated Public Status Success');
});
};
const copyUrl = () => {
navigator.clipboard.writeText(shareUrl);

View File

@@ -12,7 +12,7 @@ import {
} from './WorkspaceItem';
import { WorkspaceSetting } from '@/components/workspace-setting';
import { useCallback, useEffect, useState } from 'react';
import { getWorkspaceDetail, WorkspaceType } from '@affine/data-services';
import { getDataCenter, WorkspaceType } from '@affine/datacenter';
import { useModal } from '@/providers/global-modal-provider';
export type WorkspaceDetails = Record<
@@ -54,7 +54,8 @@ export const SelectorPopperContent = ({
if (type === WorkspaceType.Private) {
return { id, member_count: 1, owner: user };
} else {
const data = await getWorkspaceDetail({ id });
const dc = await getDataCenter();
const data = await dc.apis.getWorkspaceDetail({ id });
return { id, ...data } || { id, member_count: 0, owner: user };
}
}

View File

@@ -1,4 +1,4 @@
import { createWorkspace, uploadBlob } from '@affine/data-services';
import { getDataCenter } from '@affine/datacenter';
import Modal from '@/ui/modal';
import Input from '@/ui/input';
import {
@@ -52,7 +52,9 @@ export const WorkspaceCreate = ({ open, onClose }: WorkspaceCreateProps) => {
ctx.fillText(workspaceName[0], 50, 50);
canvas.toBlob(blob => {
if (blob) {
const blobId = uploadBlob({ blob });
const blobId = getDataCenter().then(dc =>
dc.apis.uploadBlob({ blob })
);
resolve(blobId);
} else {
reject();
@@ -69,7 +71,10 @@ export const WorkspaceCreate = ({ open, onClose }: WorkspaceCreateProps) => {
setCreating(false);
});
if (blobId) {
createWorkspace({ name: workspaceName, avatar: blobId })
getDataCenter()
.then(dc =>
dc.apis.createWorkspace({ name: workspaceName, avatar: blobId })
)
.then(async data => {
await refreshWorkspacesMeta();
// eslint-disable-next-line @typescript-eslint/ban-ts-comment

View File

@@ -7,7 +7,7 @@ import {
} from '../styles';
import { FooterSetting } from './FooterSetting';
import { FooterUsers } from './FooterUsers';
import { WorkspaceType } from '@affine/data-services';
import { WorkspaceType } from '@affine/datacenter';
import { useAppState } from '@/providers/app-state-provider';
interface WorkspaceItemProps {

View File

@@ -3,7 +3,7 @@ import { Avatar, WorkspaceName, SelectorWrapper } from './styles';
import { SelectorPopperContent } from './SelectorPopperContent';
import { useState } from 'react';
import { useAppState } from '@/providers/app-state-provider';
import { WorkspaceType } from '@affine/data-services';
import { WorkspaceType } from '@affine/datacenter';
import { AffineIcon } from '../icons/icons';
export const WorkspaceSelector = () => {

View File

@@ -17,8 +17,8 @@ export const AffineIcon = () => {
fill="#FFF"
/>
<path
fill-rule="evenodd"
clip-rule="evenodd"
fillRule="evenodd"
clipRule="evenodd"
d="M18.6303 8.79688L11.2559 29.8393H15.5752L20.2661 15.2858L24.959 29.8393H29.2637L21.8881 8.79688H18.6303Z"
fill="#6880FF"
/>

View File

@@ -6,7 +6,6 @@ import {
StyledListItem,
StyledListItemForWorkspace,
StyledNewPageButton,
StyledQuickSearch,
StyledSliderBar,
StyledSliderBarWrapper,
StyledSubListItem,
@@ -32,11 +31,7 @@ import { IconButton } from '@/ui/button';
import useLocalStorage from '@/hooks/use-local-storage';
import usePageMetaList from '@/hooks/use-page-meta-list';
import { usePageHelper } from '@/hooks/use-page-helper';
import { getUaHelper } from '@/utils';
const isMac = () => {
return getUaHelper().isMacOs;
};
const FavoriteList = ({ showList }: { showList: boolean }) => {
const { openPage } = usePageHelper();
const pageList = usePageMetaList();
@@ -117,7 +112,7 @@ export const WorkSpaceSliderBar = () => {
<StyledListItemForWorkspace>
<WorkspaceSelector />
</StyledListItemForWorkspace>
<StyledQuickSearch
<StyledListItem
data-testid="sliderBar-quickSearchButton"
style={{ cursor: 'pointer' }}
onClick={() => {
@@ -126,8 +121,7 @@ export const WorkSpaceSliderBar = () => {
>
<SearchIcon />
Quick search
<span>{isMac() ? '⌘ + K' : 'Ctrl + K'}</span>
</StyledQuickSearch>
</StyledListItem>
<Link href={{ pathname: paths.all }}>
<StyledListItem active={router.asPath === paths.all}>
<AllPagesIcon /> <span>All pages</span>

View File

@@ -21,6 +21,7 @@ export const StyledSliderBarWrapper = styled.div(() => {
height: '100%',
overflowX: 'hidden',
overflowY: 'auto',
position: 'relative',
};
});
@@ -141,34 +142,3 @@ export const StyledSubListItem = styled.button<{
},
};
});
export const StyledQuickSearch = styled.div(({ theme }) => {
return {
width: '296px',
height: '32px',
marginTop: '12px',
fontSize: theme.font.sm,
backgroundColor: theme.colors.hoverBackground,
color: theme.colors.popoverColor,
paddingLeft: '12px',
borderRadius: '5px',
...displayFlex('flex-start', 'center'),
'>svg': {
fontSize: '20px',
marginRight: '12px',
},
'>span': {
fontSize: theme.font.xs,
margin: 'auto',
marginRight: '12px',
color: theme.colors.hoverBackground,
transition: 'all .15s',
},
':hover': {
color: theme.colors.popoverColor,
'>span': {
color: theme.colors.popoverColor,
},
},
};
});

View File

@@ -30,18 +30,18 @@ export const useEnsureWorkspace = () => {
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;
}
// 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;
? (router.query.workspaceId as string) || workspacesMeta[0]?.id
: (router.query.workspaceId as string) || defaultOutLineWorkspaceId;
loadWorkspace(workspaceId).finally(() => {
setWorkspaceLoaded(true);

View File

@@ -1,7 +1,7 @@
import { styled } from '@/styles';
import { Empty } from '@/ui/empty';
import { Avatar } from '@mui/material';
import { acceptInviting } from '@affine/data-services';
import { getDataCenter } from '@affine/datacenter';
import { useRouter } from 'next/router';
import { useEffect, useState } from 'react';
@@ -24,7 +24,12 @@ export default function DevPage() {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const [inviteData, setInviteData] = useState<any>(null);
useEffect(() => {
acceptInviting({ invitingCode: router.query.invite_code as string })
getDataCenter()
.then(dc =>
dc.apis.acceptInviting({
invitingCode: router.query.invite_code as string,
})
)
.then(data => {
setSuccessInvited(true);
setInviteData(data);

View File

@@ -68,6 +68,7 @@ const Page: NextPageWithLayout = () => {
}
}
document.title = currentPage?.meta.title || 'Untitled';
return ret;
}, [currentWorkspace, currentPage, createEditor, setEditor]);

View File

@@ -1,6 +1,5 @@
import { createContext, MutableRefObject, useContext } from 'react';
import type { Workspace } from '@affine/data-services';
import { AccessTokenMessage } from '@affine/data-services';
import type { AccessTokenMessage, Workspace } from '@affine/datacenter';
import type {
Page as StorePage,
Workspace as StoreWorkspace,
@@ -8,7 +7,6 @@ import type {
import type { EditorContainer } from '@blocksuite/editor';
export type LoadWorkspaceHandler = (
workspaceId: string,
websocket?: boolean,
user?: AccessTokenMessage | null
) => Promise<StoreWorkspace | null> | null;
export type CreateEditorHandler = (page: StorePage) => EditorContainer | null;

View File

@@ -1,13 +1,9 @@
import { useEffect } from 'react';
import type { Page } from '@blocksuite/store';
import {
IndexedDBDocProvider,
Workspace as StoreWorkspace,
} from '@blocksuite/store';
import '@blocksuite/blocks';
import { EditorContainer } from '@blocksuite/editor';
import { BlockSchema } from '@blocksuite/blocks/models';
import type { LoadWorkspaceHandler, CreateEditorHandler } from './context';
import { getDataCenter } from '@affine/datacenter';
interface Props {
setLoadWorkspaceHandler: (handler: LoadWorkspaceHandler) => void;
@@ -19,66 +15,14 @@ const DynamicBlocksuite = ({
setCreateEditorHandler,
}: Props) => {
useEffect(() => {
const openWorkspace: LoadWorkspaceHandler = (
workspaceId: string,
websocket = false,
user
) =>
// eslint-disable-next-line no-async-promise-executor
new Promise(async resolve => {
const workspace = new StoreWorkspace({
room: workspaceId,
providers: [IndexedDBDocProvider],
}).register(BlockSchema);
console.log('websocket', websocket);
console.log('user', user);
// if (websocket && token.refresh) {
// // FIXME: if add websocket provider, the first page will be blank
// const ws = new WebsocketProvider(
// `ws${window.location.protocol === 'https:' ? 's' : ''}://${
// window.location.host
// }/api/sync/`,
// workspaceId,
// workspace.doc,
// {
// params: {
// token: token.refresh,
// },
// awareness: workspace.meta.awareness.awareness,
// }
// );
//
// ws.shouldConnect = false;
//
// // FIXME: there needs some method to destroy websocket.
// // Or we need a manager to manage websocket.
// // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// // @ts-expect-error
// workspace.__ws__ = ws;
// }
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');
// }
if (indexDBProvider) {
(indexDBProvider as IndexedDBDocProvider).whenSynced.then(() => {
resolve(workspace);
});
} else {
resolve(workspace);
}
});
const openWorkspace: LoadWorkspaceHandler = async (workspaceId: string) => {
if (workspaceId) {
const dc = await getDataCenter();
return dc.load(workspaceId, { providerId: 'affine' });
} else {
return null;
}
};
setLoadWorkspaceHandler(openWorkspace);
}, [setLoadWorkspaceHandler]);

View File

@@ -1,48 +0,0 @@
import { useEffect } from 'react';
import {
AccessTokenMessage,
getWorkspaces,
token,
} from '@affine/data-services';
import { LoadWorkspaceHandler } from '../context';
export const useSyncData = ({
loadWorkspaceHandler,
}: {
loadWorkspaceHandler: LoadWorkspaceHandler;
}) => {
useEffect(() => {
if (!loadWorkspaceHandler) {
return;
}
const start = async () => {
const isLogin = await token.refreshToken().catch(() => false);
return isLogin;
};
start();
const callback = async (user: AccessTokenMessage | null) => {
const workspacesMeta = user
? await getWorkspaces().catch(() => {
return [];
})
: [];
// setState(state => ({
// ...state,
// user: user,
// workspacesMeta,
// synced: true,
// }));
return workspacesMeta;
};
token.onChange(callback);
token.refreshToken().catch(err => {
// FIXME: should resolve invalid refresh token
console.log(err);
});
return () => {
token.offChange(callback);
};
}, [loadWorkspaceHandler]);
};

View File

@@ -1,7 +1,7 @@
import { useMemo, useState, useEffect, useCallback, useRef } from 'react';
import type { ReactNode } from 'react';
import dynamic from 'next/dynamic';
import { getWorkspaces } from '@affine/data-services';
import { getDataCenter } from '@affine/datacenter';
import { AppState, AppStateContext } from './context';
import type {
AppStateValue,
@@ -16,7 +16,8 @@ const DynamicBlocksuite = dynamic(() => import('./dynamic-blocksuite'), {
export const AppStateProvider = ({ children }: { children?: ReactNode }) => {
const refreshWorkspacesMeta = async () => {
const workspacesMeta = await getWorkspaces().catch(() => {
const dc = await getDataCenter();
const workspacesMeta = await dc.apis.getWorkspaces().catch(() => {
return [];
});
setState(state => ({ ...state, workspacesMeta }));
@@ -41,7 +42,7 @@ export const AppStateProvider = ({ children }: { children?: ReactNode }) => {
const workspacesList = await Promise.all(
state.workspacesMeta.map(async ({ id }) => {
const workspace =
(await loadWorkspaceHandler?.(id, false, state.user)) || null;
(await loadWorkspaceHandler?.(id, state.user)) || null;
return { id, workspace };
})
);
@@ -84,7 +85,7 @@ export const AppStateProvider = ({ children }: { children?: ReactNode }) => {
return state.currentWorkspace;
}
const workspace =
(await loadWorkspaceHandler?.(workspaceId, true, state.user)) || null;
(await loadWorkspaceHandler?.(workspaceId, state.user)) || null;
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error