mirror of
https://github.com/toeverything/AFFiNE.git
synced 2024-12-23 21:55:02 +03:00
refactor(store): extract workspace out of AppState
(#1037)
This commit is contained in:
parent
a4d0813354
commit
cdc2b449a9
@ -1,7 +1,6 @@
|
||||
import { Modal, ModalWrapper } from '@affine/component';
|
||||
import { IconButton } from '@affine/component';
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useAppState } from '@/providers/app-state-provider';
|
||||
import { useState } from 'react';
|
||||
import router from 'next/router';
|
||||
import { toast } from '@affine/component';
|
||||
@ -22,7 +21,9 @@ export const EnableWorkspaceModal = ({
|
||||
const login = useGlobalState(store => store.login);
|
||||
const user = useGlobalState(store => store.user);
|
||||
const dataCenter = useGlobalState(store => store.dataCenter);
|
||||
const { currentWorkspace } = useAppState();
|
||||
const currentWorkspace = useGlobalState(
|
||||
useCallback(store => store.currentDataCenterWorkspace, [])
|
||||
);
|
||||
const [loading, setLoading] = useState(false);
|
||||
return (
|
||||
<Modal open={open} onClose={onClose} data-testid="logout-modal">
|
||||
|
@ -14,6 +14,7 @@
|
||||
"@affine/i18n": "workspace:*",
|
||||
"@blocksuite/blocks": "0.4.0-20230216011811-2776d93",
|
||||
"@blocksuite/editor": "0.4.0-20230216011811-2776d93",
|
||||
"@blocksuite/global": "0.4.0-20230216011811-2776d93",
|
||||
"@blocksuite/icons": "^2.0.14",
|
||||
"@blocksuite/store": "0.4.0-20230216011811-2776d93",
|
||||
"@emotion/css": "^11.10.5",
|
||||
|
@ -1,9 +1,8 @@
|
||||
import { useAppState } from '@/providers/app-state-provider';
|
||||
import { IconButton, Modal, ModalWrapper, toast } from '@affine/component';
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { CloseIcon } from '@blocksuite/icons';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useState } from 'react';
|
||||
import { useCallback, useState } from 'react';
|
||||
import { Content, ContentTitle, Header, StyleButton, StyleTips } from './style';
|
||||
import { useGlobalState } from '@/store/app';
|
||||
|
||||
@ -20,7 +19,9 @@ export const EnableWorkspaceModal = ({
|
||||
const login = useGlobalState(store => store.login);
|
||||
const user = useGlobalState(store => store.user);
|
||||
const dataCenter = useGlobalState(store => store.dataCenter);
|
||||
const { currentWorkspace } = useAppState();
|
||||
const currentWorkspace = useGlobalState(
|
||||
useCallback(store => store.currentDataCenterWorkspace, [])
|
||||
);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const router = useRouter();
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { LocalWorkspaceIcon, CloudWorkspaceIcon } from '@blocksuite/icons';
|
||||
import { useAppState } from '@/providers/app-state-provider';
|
||||
import { displayFlex, styled, Tooltip, IconButton } from '@affine/component';
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useModal } from '@/store/globalModal';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { WorkspaceUnit } from '@affine/datacenter';
|
||||
import { useGlobalState } from '@/store/app';
|
||||
|
||||
const NoNetWorkIcon = () => {
|
||||
return (
|
||||
@ -43,7 +43,9 @@ const getStatus = (workspace: WorkspaceUnit | null) => {
|
||||
return 'cloud';
|
||||
};
|
||||
export const SyncUser = () => {
|
||||
const { currentWorkspace } = useAppState();
|
||||
const currentWorkspace = useGlobalState(
|
||||
useCallback(store => store.currentDataCenterWorkspace, [])
|
||||
);
|
||||
const { triggerEnableWorkspaceModal } = useModal();
|
||||
|
||||
const [status, setStatus] = useState<'offline' | 'local' | 'cloud'>(
|
||||
|
@ -1,14 +1,17 @@
|
||||
import { Button } from '@affine/component';
|
||||
import { usePageHelper } from '@/hooks/use-page-helper';
|
||||
import { useAppState } from '@/providers/app-state-provider';
|
||||
import { useConfirm } from '@/providers/ConfirmProvider';
|
||||
import { useRouter } from 'next/router';
|
||||
import useCurrentPageMeta from '@/hooks/use-current-page-meta';
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useGlobalState } from '@/store/app';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
export const TrashButtonGroup = () => {
|
||||
const { permanentlyDeletePage } = usePageHelper();
|
||||
const { currentWorkspace } = useAppState();
|
||||
const currentWorkspace = useGlobalState(
|
||||
useCallback(store => store.currentDataCenterWorkspace, [])
|
||||
);
|
||||
const { toggleDeletePage } = usePageHelper();
|
||||
const confirm = useConfirm(store => store.confirm);
|
||||
const router = useRouter();
|
||||
|
@ -4,9 +4,9 @@ import { Button } from '@affine/component';
|
||||
import { Content, FlexWrapper } from '@affine/component';
|
||||
import Loading from '@/components/loading';
|
||||
import { usePageHelper } from '@/hooks/use-page-helper';
|
||||
import { useAppState } from '@/providers/app-state-provider';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useGlobalState } from '@/store/app';
|
||||
// import { Tooltip } from '@affine/component';
|
||||
type ImportModalProps = {
|
||||
open: boolean;
|
||||
@ -19,7 +19,9 @@ type Template = {
|
||||
export const ImportModal = ({ open, onClose }: ImportModalProps) => {
|
||||
const [status, setStatus] = useState<'unImported' | 'importing'>('importing');
|
||||
const { openPage, createPage } = usePageHelper();
|
||||
const { currentWorkspace } = useAppState();
|
||||
const currentWorkspace = useGlobalState(
|
||||
useCallback(store => store.currentDataCenterWorkspace, [])
|
||||
);
|
||||
const { t } = useTranslation();
|
||||
const _applyTemplate = function (pageId: string, template: Template) {
|
||||
const page = currentWorkspace?.blocksuiteWorkspace?.getPage(pageId);
|
||||
|
@ -21,16 +21,16 @@ import {
|
||||
import { OperationCell, TrashOperationCell } from './OperationCell';
|
||||
import Empty from './Empty';
|
||||
import { Content } from '@affine/component';
|
||||
import React from 'react';
|
||||
import React, { useCallback } from 'react';
|
||||
import DateCell from '@/components/page-list/DateCell';
|
||||
import { IconButton } from '@affine/component';
|
||||
import { Tooltip } from '@affine/component';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useAppState } from '@/providers/app-state-provider';
|
||||
import { toast } from '@affine/component';
|
||||
import { usePageHelper } from '@/hooks/use-page-helper';
|
||||
import { useTheme } from '@/providers/ThemeProvider';
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useGlobalState } from '@/store/app';
|
||||
const FavoriteTag = ({
|
||||
pageMeta: { favorite, id },
|
||||
}: {
|
||||
@ -83,7 +83,9 @@ export const PageList = ({
|
||||
listType?: 'all' | 'trash' | 'favorite';
|
||||
}) => {
|
||||
const router = useRouter();
|
||||
const { currentWorkspace } = useAppState();
|
||||
const currentWorkspace = useGlobalState(
|
||||
useCallback(store => store.currentDataCenterWorkspace, [])
|
||||
);
|
||||
const { t } = useTranslation();
|
||||
if (pageList.length === 0) {
|
||||
return <Empty listType={listType} />;
|
||||
|
@ -1,13 +1,19 @@
|
||||
import { Command } from 'cmdk';
|
||||
import { StyledListItem, StyledNotFound } from './style';
|
||||
import { PaperIcon, EdgelessIcon } from '@blocksuite/icons';
|
||||
import { Dispatch, SetStateAction, useEffect, useState } from 'react';
|
||||
import { useAppState } from '@/providers/app-state-provider';
|
||||
import {
|
||||
Dispatch,
|
||||
SetStateAction,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useState,
|
||||
} from 'react';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useSwitchToConfig } from './config';
|
||||
import { NoResultSVG } from './NoResultSVG';
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import usePageHelper from '@/hooks/use-page-helper';
|
||||
import { useGlobalState } from '@/store/app';
|
||||
export const Results = (props: {
|
||||
query: string;
|
||||
loading: boolean;
|
||||
@ -18,7 +24,12 @@ export const Results = (props: {
|
||||
const { query, loading, setLoading, setShowCreatePage, onClose } = props;
|
||||
const { openPage } = usePageHelper();
|
||||
const router = useRouter();
|
||||
const { currentWorkspace, pageList } = useAppState();
|
||||
const currentWorkspace = useGlobalState(
|
||||
useCallback(store => store.currentDataCenterWorkspace, [])
|
||||
);
|
||||
const pageList = useGlobalState(
|
||||
useCallback(store => store.dataCenterPageList, [])
|
||||
);
|
||||
const { search } = usePageHelper();
|
||||
const List = useSwitchToConfig(currentWorkspace?.id);
|
||||
const [results, setResults] = useState(new Map<string, string | undefined>());
|
||||
|
@ -7,10 +7,10 @@ import {
|
||||
PublishIcon,
|
||||
} from '@/components/icons';
|
||||
import { WorkspaceUnit } from '@affine/datacenter';
|
||||
import { useAppState } from '@/providers/app-state-provider';
|
||||
import { StyleWorkspaceInfo, StyleWorkspaceTitle, StyledCard } from './styles';
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useGlobalState } from '@/store/app';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
const WorkspaceType = ({ workspaceData }: { workspaceData: WorkspaceUnit }) => {
|
||||
const user = useGlobalState(store => store.user);
|
||||
@ -46,7 +46,9 @@ export const WorkspaceCard = ({
|
||||
workspaceData: WorkspaceUnit;
|
||||
onClick: (data: WorkspaceUnit) => void;
|
||||
}) => {
|
||||
const { currentWorkspace } = useAppState();
|
||||
const currentWorkspace = useGlobalState(
|
||||
useCallback(store => store.currentDataCenterWorkspace, [])
|
||||
);
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<StyledCard
|
||||
|
@ -7,9 +7,8 @@ import {
|
||||
import { StyledSettingKey, StyledRow } from '../style';
|
||||
import { FlexWrapper } from '@affine/component';
|
||||
|
||||
import { useState } from 'react';
|
||||
import { useCallback, useState } from 'react';
|
||||
import { Button } from '@affine/component';
|
||||
import { useAppState } from '@/providers/app-state-provider';
|
||||
import { WorkspaceDelete } from './delete';
|
||||
import { WorkspaceLeave } from './leave';
|
||||
import {
|
||||
@ -31,7 +30,9 @@ export const GeneralPage = ({ workspace }: { workspace: WorkspaceUnit }) => {
|
||||
const [workspaceName, setWorkspaceName] = useState<string>(workspace?.name);
|
||||
const [showEditInput, setShowEditInput] = useState(false);
|
||||
const isOwner = useGlobalState(store => store.isOwner);
|
||||
const { currentWorkspace } = useAppState();
|
||||
const currentWorkspace = useGlobalState(
|
||||
useCallback(store => store.currentDataCenterWorkspace, [])
|
||||
);
|
||||
const { updateWorkspace } = useWorkspaceHelper();
|
||||
const { t } = useTranslation();
|
||||
|
||||
|
@ -1,17 +1,19 @@
|
||||
import { WorkspaceName, SelectorWrapper } from './styles';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useCallback, useState } from 'react';
|
||||
import { WorkspaceModal } from '@/components/workspace-modal';
|
||||
import { WorkspaceUnitAvatar } from '@/components/workspace-avatar';
|
||||
import { useAppState } from '@/providers/app-state-provider';
|
||||
import { useGlobalState } from '@/store/app';
|
||||
|
||||
export const WorkspaceSelector = () => {
|
||||
const [workspaceListShow, setWorkspaceListShow] = useState(false);
|
||||
const { currentWorkspace, workspaceList } = useAppState();
|
||||
const currentWorkspace = useGlobalState(
|
||||
useCallback(store => store.currentDataCenterWorkspace, [])
|
||||
);
|
||||
const dataCenter = useGlobalState(useCallback(store => store.dataCenter, []));
|
||||
|
||||
useEffect(() => {
|
||||
if (workspaceList.length === 0) {
|
||||
setWorkspaceListShow(true);
|
||||
}
|
||||
}, [workspaceList]);
|
||||
if (dataCenter.workspaces.length === 0) {
|
||||
setWorkspaceListShow(true);
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<SelectorWrapper
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { useState } from 'react';
|
||||
import React, { useCallback, useState } from 'react';
|
||||
import { useRouter } from 'next/router';
|
||||
import {
|
||||
StyledArrowButton,
|
||||
@ -24,16 +24,16 @@ import Link from 'next/link';
|
||||
import { MuiCollapse } from '@affine/component';
|
||||
import { Tooltip } from '@affine/component';
|
||||
import { useModal } from '@/store/globalModal';
|
||||
import { useAppState } from '@/providers/app-state-provider';
|
||||
import { IconButton } from '@affine/component';
|
||||
import useLocalStorage from '@/hooks/use-local-storage';
|
||||
import { usePageHelper } from '@/hooks/use-page-helper';
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { WorkspaceSelector } from './WorkspaceSelector/WorkspaceSelector';
|
||||
import { useGlobalState } from '@/store/app';
|
||||
|
||||
const FavoriteList = ({ showList }: { showList: boolean }) => {
|
||||
const { openPage } = usePageHelper();
|
||||
const { pageList } = useAppState();
|
||||
const pageList = useGlobalState(store => store.dataCenterPageList);
|
||||
const router = useRouter();
|
||||
const { t } = useTranslation();
|
||||
const favoriteList = pageList.filter(p => p.favorite && !p.trash);
|
||||
@ -66,7 +66,9 @@ const FavoriteList = ({ showList }: { showList: boolean }) => {
|
||||
export const WorkSpaceSliderBar = () => {
|
||||
const { triggerQuickSearchModal } = useModal();
|
||||
const [showSubFavorite, setShowSubFavorite] = useState(true);
|
||||
const { currentWorkspace } = useAppState();
|
||||
const currentWorkspace = useGlobalState(
|
||||
useCallback(store => store.currentDataCenterWorkspace, [])
|
||||
);
|
||||
const { openPage, createPage } = usePageHelper();
|
||||
const router = useRouter();
|
||||
const { t } = useTranslation();
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { useCallback } from 'react';
|
||||
import { useAppState, PageMeta } from '@/providers/app-state-provider';
|
||||
import { PageMeta } from '@/providers/app-state-provider';
|
||||
import { useGlobalState } from '@/store/app';
|
||||
|
||||
export type ChangePageMeta = (
|
||||
pageId: string,
|
||||
@ -7,7 +8,9 @@ export type ChangePageMeta = (
|
||||
) => void;
|
||||
|
||||
export const useChangePageMeta = () => {
|
||||
const { currentWorkspace } = useAppState();
|
||||
const currentWorkspace = useGlobalState(
|
||||
useCallback(store => store.currentDataCenterWorkspace, [])
|
||||
);
|
||||
|
||||
return useCallback<ChangePageMeta>(
|
||||
(pageId, pageMeta) => {
|
||||
|
@ -1,35 +1,42 @@
|
||||
import { useAppState } from '@/providers/app-state-provider';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { useGlobalState } from '@/store/app';
|
||||
import { assertEquals } from '@blocksuite/global/utils';
|
||||
|
||||
// todo: refactor with suspense mode
|
||||
// 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 dataCenter = useGlobalState(store => store.dataCenter);
|
||||
const { loadWorkspace } = useAppState();
|
||||
const dataCenter = useGlobalState(useCallback(store => store.dataCenter, []));
|
||||
const currentWorkspace = useGlobalState(
|
||||
useCallback(store => store.currentDataCenterWorkspace, [])
|
||||
);
|
||||
const loadWorkspace = useGlobalState(
|
||||
useCallback(store => store.loadWorkspace, [])
|
||||
);
|
||||
const router = useRouter();
|
||||
const [activeWorkspaceId, setActiveWorkspaceId] = useState(
|
||||
router.query.workspaceId as string
|
||||
const [currentWorkspaceId, setCurrentWorkspaceId] = useState<string | null>(
|
||||
typeof router.query.workspaceId === 'string'
|
||||
? router.query.workspaceId
|
||||
: null
|
||||
);
|
||||
|
||||
// const defaultOutLineWorkspaceId = '99ce7eb7';
|
||||
// console.log(defaultOutLineWorkspaceId);
|
||||
useEffect(() => {
|
||||
setWorkspaceLoaded(false);
|
||||
let aborted = false;
|
||||
const abortController = new AbortController();
|
||||
|
||||
const workspaceList = dataCenter.workspaces;
|
||||
const workspaceId =
|
||||
(router.query.workspaceId as string) || workspaceList[0]?.id;
|
||||
(router.query.workspaceId as string) || dataCenter.workspaces[0]?.id;
|
||||
|
||||
// If router.query.workspaceId is not in workspace list, jump to 404 page
|
||||
// If workspaceList is empty, we need to create a default workspace but not jump to 404
|
||||
if (
|
||||
workspaceId &&
|
||||
workspaceList.length &&
|
||||
workspaceList.findIndex(meta => meta.id.toString() === workspaceId) === -1
|
||||
dataCenter.workspaces.length &&
|
||||
dataCenter.workspaces.findIndex(
|
||||
meta => meta.id.toString() === workspaceId
|
||||
) === -1
|
||||
) {
|
||||
router.push('/404');
|
||||
return;
|
||||
@ -44,22 +51,21 @@ export const useEnsureWorkspace = () => {
|
||||
// return;
|
||||
// }
|
||||
|
||||
loadWorkspace.current(workspaceId, abortController.signal).then(unit => {
|
||||
if (!aborted && unit) {
|
||||
setWorkspaceLoaded(true);
|
||||
setActiveWorkspaceId(workspaceId);
|
||||
loadWorkspace(workspaceId, abortController.signal).then(unit => {
|
||||
if (!abortController.signal.aborted && unit) {
|
||||
setCurrentWorkspaceId(unit.id);
|
||||
assertEquals(unit.id, workspaceId);
|
||||
}
|
||||
});
|
||||
|
||||
return () => {
|
||||
aborted = true;
|
||||
abortController.abort();
|
||||
};
|
||||
}, [dataCenter, loadWorkspace, router]);
|
||||
|
||||
return {
|
||||
workspaceLoaded,
|
||||
activeWorkspaceId,
|
||||
workspaceLoaded: currentWorkspace?.id === currentWorkspaceId,
|
||||
activeWorkspaceId: currentWorkspace?.id ?? router.query.workspaceId,
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -1,10 +1,11 @@
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { Member } from '@affine/datacenter';
|
||||
import { useAppState } from '@/providers/app-state-provider';
|
||||
import { useGlobalState } from '@/store/app';
|
||||
export const useMembers = () => {
|
||||
const dataCenter = useGlobalState(store => store.dataCenter);
|
||||
const { currentWorkspace } = useAppState();
|
||||
const currentWorkspace = useGlobalState(
|
||||
useCallback(store => store.currentDataCenterWorkspace, [])
|
||||
);
|
||||
const [members, setMembers] = useState<Member[]>([]);
|
||||
const [loaded, setLoaded] = useState(false);
|
||||
const refreshMembers = useCallback(async () => {
|
||||
|
@ -1,11 +1,12 @@
|
||||
import { uuidv4, Workspace } from '@blocksuite/store';
|
||||
import { QueryContent } from '@blocksuite/store/dist/workspace/search';
|
||||
import { PageMeta, useAppState } from '@/providers/app-state-provider';
|
||||
import { PageMeta } from '@/providers/app-state-provider';
|
||||
import { EditorContainer } from '@blocksuite/editor';
|
||||
import { useChangePageMeta } from '@/hooks/use-change-page-meta';
|
||||
import { useRouter } from 'next/router';
|
||||
import { WorkspaceUnit } from '@affine/datacenter';
|
||||
import { useGlobalState } from '@/store/app';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
export type EditorHandlers = {
|
||||
createPage: (params?: {
|
||||
@ -41,7 +42,9 @@ export const usePageHelper = (): EditorHandlers => {
|
||||
const router = useRouter();
|
||||
const changePageMeta = useChangePageMeta();
|
||||
const editor = useGlobalState(store => store.editor);
|
||||
const { currentWorkspace } = useAppState();
|
||||
const currentWorkspace = useGlobalState(
|
||||
useCallback(store => store.currentDataCenterWorkspace, [])
|
||||
);
|
||||
|
||||
return {
|
||||
createPage: ({
|
||||
|
@ -1,16 +1,19 @@
|
||||
import { useAppState } from '@/providers/app-state-provider';
|
||||
import { WorkspaceUnit } from '@affine/datacenter';
|
||||
import { useGlobalState } from '@/store/app';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
export const useWorkspaceHelper = () => {
|
||||
const dataCenter = useGlobalState(store => store.dataCenter);
|
||||
const { currentWorkspace } = useAppState();
|
||||
const currentWorkspace = useGlobalState(
|
||||
useCallback(store => store.currentDataCenterWorkspace, [])
|
||||
);
|
||||
const loadWorkspace = useGlobalState(store => store.loadWorkspace);
|
||||
const createWorkspace = async (name: string) => {
|
||||
const workspaceInfo = await dataCenter.createWorkspace({
|
||||
name: name,
|
||||
});
|
||||
if (workspaceInfo && workspaceInfo.id) {
|
||||
return await dataCenter.loadWorkspace(workspaceInfo.id);
|
||||
return loadWorkspace(workspaceInfo.id);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
@ -22,7 +22,8 @@ import Head from 'next/head';
|
||||
import '@affine/i18n';
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import React from 'react';
|
||||
import { DataCenterLoader, GlobalAppProvider } from '@/store/app';
|
||||
import { GlobalAppProvider } from '@/store/app';
|
||||
import { DataCenterLoader } from '@/store/app/datacenter';
|
||||
|
||||
const ThemeProvider = dynamic(() => import('@/providers/ThemeProvider'), {
|
||||
ssr: false,
|
||||
|
@ -1,7 +1,12 @@
|
||||
import { PropsWithChildren, ReactElement, useEffect, useState } from 'react';
|
||||
import {
|
||||
PropsWithChildren,
|
||||
ReactElement,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useState,
|
||||
} from 'react';
|
||||
import { EditorHeader } from '@/components/header';
|
||||
import MobileModal from '@/components/mobile-modal';
|
||||
import { useAppState } from '@/providers/app-state-provider';
|
||||
import type { NextPageWithLayout } from '../..//_app';
|
||||
import WorkspaceLayout from '@/components/workspace-layout';
|
||||
import { useRouter } from 'next/router';
|
||||
@ -53,7 +58,9 @@ const BlockHubAppender = () => {
|
||||
const Page: NextPageWithLayout = () => {
|
||||
const currentPage = useGlobalState(store => store.currentPage);
|
||||
const setEditor = useGlobalState(store => store.setEditor);
|
||||
const { currentWorkspace } = useAppState();
|
||||
const currentWorkspace = useGlobalState(
|
||||
useCallback(store => store.currentDataCenterWorkspace, [])
|
||||
);
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
@ -95,7 +102,9 @@ const PageDefender = ({ children }: PropsWithChildren) => {
|
||||
const router = useRouter();
|
||||
const [pageLoaded, setPageLoaded] = useState(false);
|
||||
const loadPage = useGlobalState(store => store.loadPage);
|
||||
const { currentWorkspace } = useAppState();
|
||||
const currentWorkspace = useGlobalState(
|
||||
useCallback(store => store.currentDataCenterWorkspace, [])
|
||||
);
|
||||
const { createPage } = usePageHelper();
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -1,14 +1,17 @@
|
||||
import { PageList } from '@/components/page-list';
|
||||
import { AllPagesIcon } from '@blocksuite/icons';
|
||||
import { PageListHeader } from '@/components/header';
|
||||
import { ReactElement } from 'react';
|
||||
import { ReactElement, useCallback } from 'react';
|
||||
import WorkspaceLayout from '@/components/workspace-layout';
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { PageMeta, useAppState } from '@/providers/app-state-provider';
|
||||
import { PageMeta } from '@/providers/app-state-provider';
|
||||
import Head from 'next/head';
|
||||
import { useGlobalState } from '@/store/app';
|
||||
|
||||
const All = () => {
|
||||
const { currentWorkspace } = useAppState();
|
||||
const currentWorkspace = useGlobalState(
|
||||
useCallback(store => store.currentDataCenterWorkspace, [])
|
||||
);
|
||||
const pageList = (currentWorkspace?.blocksuiteWorkspace?.meta.pageMetas ||
|
||||
[]) as PageMeta[];
|
||||
const { t } = useTranslation();
|
||||
|
@ -4,10 +4,11 @@ import { FavouritesIcon } from '@blocksuite/icons';
|
||||
import { ReactElement } from 'react';
|
||||
import WorkspaceLayout from '@/components/workspace-layout';
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useAppState } from '@/providers/app-state-provider';
|
||||
import Head from 'next/head';
|
||||
import { useGlobalState } from '@/store/app';
|
||||
|
||||
export const Favorite = () => {
|
||||
const { pageList } = useAppState();
|
||||
const pageList = useGlobalState(store => store.dataCenterPageList);
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<>
|
||||
|
@ -1,13 +1,15 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useCallback, useEffect } from 'react';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useAppState } from '@/providers/app-state-provider';
|
||||
import useEnsureWorkspace from '@/hooks/use-ensure-workspace';
|
||||
import { PageLoading } from '@/components/loading';
|
||||
import usePageHelper from '@/hooks/use-page-helper';
|
||||
import { useGlobalState } from '@/store/app';
|
||||
|
||||
const WorkspaceIndex = () => {
|
||||
const router = useRouter();
|
||||
const { currentWorkspace } = useAppState();
|
||||
const currentWorkspace = useGlobalState(
|
||||
useCallback(store => store.currentDataCenterWorkspace, [])
|
||||
);
|
||||
const { createPage } = usePageHelper();
|
||||
const { workspaceLoaded, activeWorkspaceId } = useEnsureWorkspace();
|
||||
|
||||
|
@ -10,6 +10,7 @@ import {
|
||||
CSSProperties,
|
||||
useEffect,
|
||||
startTransition,
|
||||
useCallback,
|
||||
} from 'react';
|
||||
import {
|
||||
GeneralPage,
|
||||
@ -18,7 +19,6 @@ import {
|
||||
ExportPage,
|
||||
} from '@/components/workspace-setting';
|
||||
import { SettingsIcon } from '@blocksuite/icons';
|
||||
import { useAppState } from '@/providers/app-state-provider';
|
||||
import WorkspaceLayout from '@/components/workspace-layout';
|
||||
import { WorkspaceUnit } from '@affine/datacenter';
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
@ -98,7 +98,9 @@ const StyledTabButtonWrapper = styled.div(() => {
|
||||
});
|
||||
const WorkspaceSetting = () => {
|
||||
const { t } = useTranslation();
|
||||
const { currentWorkspace } = useAppState();
|
||||
const currentWorkspace = useGlobalState(
|
||||
useCallback(store => store.currentDataCenterWorkspace, [])
|
||||
);
|
||||
const { activeTabPanelRender, tableArr, handleTabChange, activeTab } =
|
||||
useTabMap();
|
||||
const [indicatorState, setIndicatorState] = useState<
|
||||
|
@ -4,10 +4,10 @@ import { TrashIcon } from '@blocksuite/icons';
|
||||
import { ReactElement } from 'react';
|
||||
import WorkspaceLayout from '@/components/workspace-layout';
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { useAppState } from '@/providers/app-state-provider';
|
||||
import Head from 'next/head';
|
||||
import { useGlobalState } from '@/store/app';
|
||||
export const Trash = () => {
|
||||
const { pageList } = useAppState();
|
||||
const pageList = useGlobalState(store => store.dataCenterPageList);
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<>
|
||||
|
@ -1,12 +1,14 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useCallback, useEffect } from 'react';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useAppState } from '@/providers/app-state-provider';
|
||||
import useEnsureWorkspace from '@/hooks/use-ensure-workspace';
|
||||
import { PageLoading } from '@/components/loading';
|
||||
import { useGlobalState } from '@/store/app';
|
||||
|
||||
export const WorkspaceIndex = () => {
|
||||
const router = useRouter();
|
||||
const { currentWorkspace } = useAppState();
|
||||
const currentWorkspace = useGlobalState(
|
||||
useCallback(store => store.currentDataCenterWorkspace, [])
|
||||
);
|
||||
const { workspaceLoaded } = useEnsureWorkspace();
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -1,16 +1,8 @@
|
||||
import { createContext, useContext, useEffect, useState, useRef } from 'react';
|
||||
import { createContext, useContext, useEffect, useState } from 'react';
|
||||
import type { PropsWithChildren } from 'react';
|
||||
import {
|
||||
AppStateContext,
|
||||
AppStateFunction,
|
||||
AppStateValue,
|
||||
PageMeta,
|
||||
} from './interface';
|
||||
import { useGlobalState, useGlobalStateApi } from '@/store/app';
|
||||
|
||||
export interface Disposable {
|
||||
dispose(): void;
|
||||
}
|
||||
import { AppStateContext } from './interface';
|
||||
import type { Disposable } from '@blocksuite/global/utils';
|
||||
import { useGlobalState } from '@/store/app';
|
||||
|
||||
type AppStateContextProps = PropsWithChildren<Record<string, unknown>>;
|
||||
|
||||
@ -20,113 +12,14 @@ export const useAppState = () => useContext(AppState);
|
||||
export const AppStateProvider = ({
|
||||
children,
|
||||
}: PropsWithChildren<AppStateContextProps>) => {
|
||||
const globalStateApi = useGlobalStateApi();
|
||||
const [appState, setAppState] = useState<AppStateValue>({} as AppStateValue);
|
||||
const currentDataCenterWorkspace = useGlobalState(
|
||||
store => store.currentDataCenterWorkspace
|
||||
);
|
||||
const [blobState, setBlobState] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (!appState?.currentWorkspace?.blocksuiteWorkspace) {
|
||||
return;
|
||||
}
|
||||
const currentWorkspace = appState.currentWorkspace;
|
||||
const dispose = currentWorkspace?.blocksuiteWorkspace?.meta.pagesUpdated.on(
|
||||
() => {
|
||||
setAppState({
|
||||
...appState,
|
||||
pageList: currentWorkspace.blocksuiteWorkspace?.meta
|
||||
.pageMetas as PageMeta[],
|
||||
});
|
||||
}
|
||||
).dispose;
|
||||
return () => {
|
||||
dispose && dispose();
|
||||
};
|
||||
}, [appState]);
|
||||
|
||||
const onceRef = useRef(true);
|
||||
const dataCenter = useGlobalState(store => store.dataCenter);
|
||||
if (onceRef.current && dataCenter) {
|
||||
setAppState({
|
||||
workspaceList: dataCenter.workspaces,
|
||||
currentWorkspace: null,
|
||||
pageList: [],
|
||||
});
|
||||
onceRef.current = false;
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
// FIXME: onWorkspacesChange should have dispose function
|
||||
return dataCenter?.onWorkspacesChange(
|
||||
() => {
|
||||
setAppState(_appState => ({
|
||||
..._appState,
|
||||
workspaceList: dataCenter.workspaces,
|
||||
}));
|
||||
},
|
||||
{ immediate: false }
|
||||
);
|
||||
}, [dataCenter]);
|
||||
|
||||
const loadWorkspace: AppStateFunction['loadWorkspace'] =
|
||||
useRef() as AppStateFunction['loadWorkspace'];
|
||||
loadWorkspace.current = async (workspaceId, abort) => {
|
||||
const { dataCenter } = globalStateApi.getState();
|
||||
const { workspaceList, currentWorkspace } = appState;
|
||||
if (!workspaceList.find(v => v.id.toString() === workspaceId)) {
|
||||
return null;
|
||||
}
|
||||
if (workspaceId === currentWorkspace?.id) {
|
||||
return currentWorkspace;
|
||||
}
|
||||
|
||||
let aborted = false;
|
||||
|
||||
const onAbort = () => {
|
||||
aborted = true;
|
||||
};
|
||||
|
||||
abort?.addEventListener('abort', onAbort);
|
||||
|
||||
const workspace = (await dataCenter.loadWorkspace(workspaceId)) ?? null;
|
||||
|
||||
if (aborted) {
|
||||
// do not update state if aborted
|
||||
return null;
|
||||
}
|
||||
|
||||
let isOwner;
|
||||
if (workspace?.provider === 'local') {
|
||||
// isOwner is useful only in the cloud
|
||||
isOwner = true;
|
||||
} else {
|
||||
const userInfo = globalStateApi.getState().user;
|
||||
// We must ensure workspace.owner exists, then ensure id same.
|
||||
isOwner = workspace?.owner && userInfo?.id === workspace.owner.id;
|
||||
}
|
||||
|
||||
const pageList =
|
||||
(workspace?.blocksuiteWorkspace?.meta.pageMetas as PageMeta[]) ?? [];
|
||||
if (workspace?.blocksuiteWorkspace) {
|
||||
globalStateApi.getState().setWorkspace(workspace.blocksuiteWorkspace);
|
||||
}
|
||||
globalStateApi.setState({
|
||||
isOwner,
|
||||
});
|
||||
|
||||
setAppState({
|
||||
...appState,
|
||||
currentWorkspace: workspace,
|
||||
pageList: pageList,
|
||||
});
|
||||
|
||||
abort?.removeEventListener('abort', onAbort);
|
||||
|
||||
return workspace;
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
let syncChangeDisposable: Disposable | undefined;
|
||||
const currentWorkspace = appState.currentWorkspace;
|
||||
const currentWorkspace = currentDataCenterWorkspace;
|
||||
if (!currentWorkspace) {
|
||||
return;
|
||||
}
|
||||
@ -142,13 +35,11 @@ export const AppStateProvider = ({
|
||||
return () => {
|
||||
syncChangeDisposable?.dispose();
|
||||
};
|
||||
}, [appState.currentWorkspace]);
|
||||
}, [currentDataCenterWorkspace]);
|
||||
|
||||
return (
|
||||
<AppState.Provider
|
||||
value={{
|
||||
...appState,
|
||||
loadWorkspace: loadWorkspace,
|
||||
blobDataSynced: blobState,
|
||||
}}
|
||||
>
|
||||
|
@ -1,11 +1,10 @@
|
||||
import { WorkspaceUnit } from '@affine/datacenter';
|
||||
import type { EditorContainer } from '@blocksuite/editor';
|
||||
|
||||
import type {
|
||||
Page as StorePage,
|
||||
PageMeta as StorePageMeta,
|
||||
} from '@blocksuite/store';
|
||||
import { MutableRefObject } from 'react';
|
||||
|
||||
export interface PageMeta extends StorePageMeta {
|
||||
favorite: boolean;
|
||||
trash: boolean;
|
||||
@ -15,16 +14,14 @@ export interface PageMeta extends StorePageMeta {
|
||||
}
|
||||
|
||||
export type AppStateValue = {
|
||||
workspaceList: WorkspaceUnit[];
|
||||
currentWorkspace: WorkspaceUnit | null;
|
||||
pageList: PageMeta[];
|
||||
blobDataSynced?: boolean;
|
||||
blobDataSynced: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
export type AppStateFunction = {
|
||||
loadWorkspace: MutableRefObject<
|
||||
(workspaceId: string, abort?: AbortSignal) => Promise<WorkspaceUnit | null>
|
||||
>;
|
||||
// todo: remove this in the future
|
||||
};
|
||||
|
||||
export type AppStateContext = AppStateValue & AppStateFunction;
|
||||
|
139
apps/web/src/store/app/datacenter/index.ts
Normal file
139
apps/web/src/store/app/datacenter/index.ts
Normal file
@ -0,0 +1,139 @@
|
||||
import {
|
||||
GlobalActionsCreator,
|
||||
useGlobalState,
|
||||
useGlobalStateApi,
|
||||
} from '@/store/app';
|
||||
import type { DataCenter } from '@affine/datacenter';
|
||||
import { PageMeta } from '@/providers/app-state-provider';
|
||||
import { getDataCenter, WorkspaceUnit } from '@affine/datacenter';
|
||||
import { createDefaultWorkspace } from '@/providers/app-state-provider/utils';
|
||||
import { useCallback, useEffect } from 'react';
|
||||
import { DisposableGroup } from '@blocksuite/global/utils';
|
||||
|
||||
export type DataCenterState = {
|
||||
readonly dataCenter: DataCenter;
|
||||
readonly dataCenterPromise: Promise<DataCenter>;
|
||||
currentDataCenterWorkspace: WorkspaceUnit | null;
|
||||
dataCenterPageList: PageMeta[];
|
||||
};
|
||||
|
||||
export type DataCenterActions = {
|
||||
loadWorkspace: (
|
||||
workspaceId: string,
|
||||
signal?: AbortSignal
|
||||
) => Promise<WorkspaceUnit | null>;
|
||||
};
|
||||
|
||||
export const createDataCenterState = (): DataCenterState => ({
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
dataCenter: null!,
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
dataCenterPromise: null!,
|
||||
currentDataCenterWorkspace: null,
|
||||
dataCenterPageList: [],
|
||||
});
|
||||
export const createDataCenterActions: GlobalActionsCreator<
|
||||
DataCenterActions
|
||||
> = (set, get) => ({
|
||||
loadWorkspace: async (workspaceId, signal) => {
|
||||
const { dataCenter, currentDataCenterWorkspace } = get();
|
||||
if (!dataCenter.workspaces.find(v => v.id.toString() === workspaceId)) {
|
||||
return null;
|
||||
}
|
||||
if (workspaceId === currentDataCenterWorkspace?.id) {
|
||||
return currentDataCenterWorkspace;
|
||||
}
|
||||
const workspace = (await dataCenter.loadWorkspace(workspaceId)) ?? null;
|
||||
|
||||
if (signal?.aborted) {
|
||||
// do not update state if aborted
|
||||
return null;
|
||||
}
|
||||
|
||||
let isOwner;
|
||||
if (workspace?.provider === 'local') {
|
||||
// isOwner is useful only in the cloud
|
||||
isOwner = true;
|
||||
} else {
|
||||
const userInfo = get().user;
|
||||
// We must ensure workspace.owner exists, then ensure id same.
|
||||
isOwner = workspace?.owner && userInfo?.id === workspace.owner.id;
|
||||
}
|
||||
|
||||
const pageList =
|
||||
(workspace?.blocksuiteWorkspace?.meta.pageMetas as PageMeta[]) ?? [];
|
||||
if (workspace?.blocksuiteWorkspace) {
|
||||
set({
|
||||
currentWorkspace: workspace.blocksuiteWorkspace,
|
||||
});
|
||||
}
|
||||
set({
|
||||
isOwner,
|
||||
});
|
||||
|
||||
set({
|
||||
currentDataCenterWorkspace: workspace,
|
||||
dataCenterPageList: pageList,
|
||||
});
|
||||
|
||||
return workspace;
|
||||
},
|
||||
});
|
||||
|
||||
export function DataCenterLoader() {
|
||||
const dataCenter = useGlobalState(useCallback(store => store.dataCenter, []));
|
||||
const dataCenterPromise = useGlobalState(
|
||||
useCallback(store => store.dataCenterPromise, [])
|
||||
);
|
||||
const api = useGlobalStateApi();
|
||||
//# region effect for updating workspace page list
|
||||
useEffect(() => {
|
||||
return api.subscribe(
|
||||
store => store.currentDataCenterWorkspace,
|
||||
currentWorkspace => {
|
||||
const disposableGroup = new DisposableGroup();
|
||||
disposableGroup.add(
|
||||
currentWorkspace?.blocksuiteWorkspace?.meta.pagesUpdated.on(() => {
|
||||
if (
|
||||
Array.isArray(
|
||||
currentWorkspace.blocksuiteWorkspace?.meta.pageMetas
|
||||
)
|
||||
) {
|
||||
api.setState({
|
||||
dataCenterPageList: currentWorkspace.blocksuiteWorkspace?.meta
|
||||
.pageMetas as PageMeta[],
|
||||
});
|
||||
}
|
||||
})
|
||||
);
|
||||
return () => {
|
||||
disposableGroup.dispose();
|
||||
};
|
||||
}
|
||||
);
|
||||
}, [api]);
|
||||
//# endregion
|
||||
|
||||
if (!dataCenter && !dataCenterPromise) {
|
||||
const promise = getDataCenter();
|
||||
api.setState({ dataCenterPromise: promise });
|
||||
promise.then(async dataCenter => {
|
||||
// Ensure datacenter has at least one workspace
|
||||
if (dataCenter.workspaces.length === 0) {
|
||||
await createDefaultWorkspace(dataCenter);
|
||||
}
|
||||
// set initial state
|
||||
api.setState({
|
||||
dataCenter,
|
||||
currentWorkspace: null,
|
||||
currentDataCenterWorkspace: null,
|
||||
dataCenterPageList: [],
|
||||
});
|
||||
});
|
||||
throw promise;
|
||||
}
|
||||
if (!dataCenter) {
|
||||
throw dataCenterPromise;
|
||||
}
|
||||
return null;
|
||||
}
|
@ -15,8 +15,12 @@ import {
|
||||
UserActions,
|
||||
UserState,
|
||||
} from '@/store/app/user';
|
||||
import { DataCenter, getDataCenter } from '@affine/datacenter';
|
||||
import { createDefaultWorkspace } from '@/providers/app-state-provider/utils';
|
||||
import {
|
||||
createDataCenterActions,
|
||||
createDataCenterState,
|
||||
DataCenterActions,
|
||||
DataCenterState,
|
||||
} from '@/store/app/datacenter';
|
||||
|
||||
export type GlobalActionsCreator<Actions, Store = GlobalState> = StateCreator<
|
||||
Store,
|
||||
@ -25,12 +29,15 @@ export type GlobalActionsCreator<Actions, Store = GlobalState> = StateCreator<
|
||||
Actions
|
||||
>;
|
||||
|
||||
export interface GlobalState extends BlockSuiteState, UserState {
|
||||
readonly dataCenter: DataCenter;
|
||||
readonly dataCenterPromise: Promise<DataCenter>;
|
||||
}
|
||||
export interface GlobalState
|
||||
extends BlockSuiteState,
|
||||
UserState,
|
||||
DataCenterState {}
|
||||
|
||||
export interface GlobalActions extends BlockSuiteActions, UserActions {}
|
||||
export interface GlobalActions
|
||||
extends BlockSuiteActions,
|
||||
UserActions,
|
||||
DataCenterActions {}
|
||||
|
||||
const create = () =>
|
||||
createStore(
|
||||
@ -39,15 +46,13 @@ const create = () =>
|
||||
{
|
||||
...createBlockSuiteState(),
|
||||
...createUserState(),
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
dataCenter: null!,
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
dataCenterPromise: null!,
|
||||
...createDataCenterState(),
|
||||
},
|
||||
/* deepscan-disable TOO_MANY_ARGS */
|
||||
(set, get, api) => ({
|
||||
...createBlockSuiteActions(set, get, api),
|
||||
...createUserActions(set, get, api),
|
||||
...createDataCenterActions(set, get, api),
|
||||
})
|
||||
/* deepscan-enable TOO_MANY_ARGS */
|
||||
)
|
||||
@ -74,28 +79,6 @@ export const useGlobalState: UseBoundStore<Store> = ((
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
}) as any;
|
||||
|
||||
export function DataCenterLoader() {
|
||||
const dataCenter = useGlobalState(store => store.dataCenter);
|
||||
const dataCenterPromise = useGlobalState(store => store.dataCenterPromise);
|
||||
const api = useGlobalStateApi();
|
||||
if (!dataCenter && !dataCenterPromise) {
|
||||
const promise = getDataCenter();
|
||||
api.setState({ dataCenterPromise: promise });
|
||||
promise.then(async dataCenter => {
|
||||
// Ensure datacenter has at least one workspace
|
||||
if (dataCenter.workspaces.length === 0) {
|
||||
await createDefaultWorkspace(dataCenter);
|
||||
}
|
||||
api.setState({ dataCenter });
|
||||
});
|
||||
throw promise;
|
||||
}
|
||||
if (!dataCenter) {
|
||||
throw dataCenterPromise;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export const GlobalAppProvider: React.FC<React.PropsWithChildren> =
|
||||
function ModelProvider({ children }) {
|
||||
return (
|
||||
|
@ -164,6 +164,7 @@ importers:
|
||||
'@affine/i18n': workspace:*
|
||||
'@blocksuite/blocks': 0.4.0-20230216011811-2776d93
|
||||
'@blocksuite/editor': 0.4.0-20230216011811-2776d93
|
||||
'@blocksuite/global': 0.4.0-20230216011811-2776d93
|
||||
'@blocksuite/icons': ^2.0.14
|
||||
'@blocksuite/store': 0.4.0-20230216011811-2776d93
|
||||
'@emotion/css': ^11.10.5
|
||||
@ -207,6 +208,7 @@ importers:
|
||||
'@affine/i18n': link:../../packages/i18n
|
||||
'@blocksuite/blocks': 0.4.0-20230216011811-2776d93_trq6tjva7swiv4fhloorah5nty
|
||||
'@blocksuite/editor': 0.4.0-20230216011811-2776d93_6yfgczikbxxddpvfspgrnx2z2q
|
||||
'@blocksuite/global': 0.4.0-20230216011811-2776d93_lit@2.6.1
|
||||
'@blocksuite/icons': 2.0.14_w5j4k42lgipnm43s3brx6h3c34
|
||||
'@blocksuite/store': 0.4.0-20230216011811-2776d93_lit@2.6.1+yjs@13.5.45
|
||||
'@emotion/css': 11.10.5
|
||||
|
Loading…
Reference in New Issue
Block a user