refactor(store): move datacenter into global (#1118)
This commit is contained in:
@@ -2,6 +2,7 @@ import { Modal, ModalWrapper } from '@affine/component';
|
|||||||
import { IconButton } from '@affine/component';
|
import { IconButton } from '@affine/component';
|
||||||
import { toast } from '@affine/component';
|
import { toast } from '@affine/component';
|
||||||
import { useTranslation } from '@affine/i18n';
|
import { useTranslation } from '@affine/i18n';
|
||||||
|
import { useDataCenter } from '@affine/store';
|
||||||
import { CloseIcon } from '@blocksuite/icons';
|
import { CloseIcon } from '@blocksuite/icons';
|
||||||
import router from 'next/router';
|
import router from 'next/router';
|
||||||
import { useCallback, useState } from 'react';
|
import { useCallback, useState } from 'react';
|
||||||
@@ -21,7 +22,7 @@ export const EnableWorkspaceModal = ({
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const login = useGlobalState(store => store.login);
|
const login = useGlobalState(store => store.login);
|
||||||
const user = useGlobalState(store => store.user);
|
const user = useGlobalState(store => store.user);
|
||||||
const dataCenter = useGlobalState(store => store.dataCenter);
|
const dataCenter = useDataCenter();
|
||||||
const currentWorkspace = useGlobalState(
|
const currentWorkspace = useGlobalState(
|
||||||
useCallback(store => store.currentDataCenterWorkspace, [])
|
useCallback(store => store.currentDataCenterWorkspace, [])
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { CloseIcon } from '@blocksuite/icons';
|
|||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
import { useCallback, useState } from 'react';
|
import { useCallback, useState } from 'react';
|
||||||
|
|
||||||
import { useGlobalState } from '@/store/app';
|
import { useDataCenter, useGlobalState } from '@/store/app';
|
||||||
|
|
||||||
import { Content, ContentTitle, Header, StyleButton, StyleTips } from './style';
|
import { Content, ContentTitle, Header, StyleButton, StyleTips } from './style';
|
||||||
|
|
||||||
@@ -20,7 +20,7 @@ export const EnableWorkspaceModal = ({
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const login = useGlobalState(store => store.login);
|
const login = useGlobalState(store => store.login);
|
||||||
const user = useGlobalState(store => store.user);
|
const user = useGlobalState(store => store.user);
|
||||||
const dataCenter = useGlobalState(store => store.dataCenter);
|
const dataCenter = useDataCenter();
|
||||||
const currentWorkspace = useGlobalState(
|
const currentWorkspace = useGlobalState(
|
||||||
useCallback(store => store.currentDataCenterWorkspace, [])
|
useCallback(store => store.currentDataCenterWorkspace, [])
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -2,13 +2,13 @@ import { toast } from '@affine/component';
|
|||||||
import { MessageCenter } from '@affine/datacenter';
|
import { MessageCenter } from '@affine/datacenter';
|
||||||
import { AffineProvider } from '@affine/datacenter';
|
import { AffineProvider } from '@affine/datacenter';
|
||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
import { ReactNode, useCallback, useEffect } from 'react';
|
import { ReactNode, useEffect } from 'react';
|
||||||
|
|
||||||
import { useGlobalState } from '@/store/app';
|
import { useDataCenter } from '@/store/app';
|
||||||
|
|
||||||
export function MessageCenterHandler({ children }: { children?: ReactNode }) {
|
export function MessageCenterHandler({ children }: { children?: ReactNode }) {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const dataCenter = useGlobalState(useCallback(store => store.dataCenter, []));
|
const dataCenter = useDataCenter();
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const instance = MessageCenter.getInstance();
|
const instance = MessageCenter.getInstance();
|
||||||
if (instance) {
|
if (instance) {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useTranslation } from '@affine/i18n';
|
import { useTranslation } from '@affine/i18n';
|
||||||
import { PageMeta } from '@affine/store';
|
import { PageMeta, useDataCenter } from '@affine/store';
|
||||||
import { EdgelessIcon, PaperIcon } from '@blocksuite/icons';
|
import { EdgelessIcon, PaperIcon } from '@blocksuite/icons';
|
||||||
import { Workspace } from '@blocksuite/store';
|
import { Workspace } from '@blocksuite/store';
|
||||||
import { Command } from 'cmdk';
|
import { Command } from 'cmdk';
|
||||||
@@ -7,7 +7,6 @@ import { useRouter } from 'next/router';
|
|||||||
import { Dispatch, SetStateAction, useEffect, useState } from 'react';
|
import { Dispatch, SetStateAction, useEffect, useState } from 'react';
|
||||||
|
|
||||||
import usePageHelper from '@/hooks/use-page-helper';
|
import usePageHelper from '@/hooks/use-page-helper';
|
||||||
import { useGlobalState } from '@/store/app';
|
|
||||||
|
|
||||||
import { NoResultSVG } from './NoResultSVG';
|
import { NoResultSVG } from './NoResultSVG';
|
||||||
import { StyledListItem, StyledNotFound } from './style';
|
import { StyledListItem, StyledNotFound } from './style';
|
||||||
@@ -24,7 +23,7 @@ export const PublishedResults = (props: {
|
|||||||
props;
|
props;
|
||||||
const { search } = usePageHelper();
|
const { search } = usePageHelper();
|
||||||
const [results, setResults] = useState(new Map<string, string | undefined>());
|
const [results, setResults] = useState(new Map<string, string | undefined>());
|
||||||
const dataCenter = useGlobalState(store => store.dataCenter);
|
const dataCenter = useDataCenter();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const [pageList, setPageList] = useState<PageMeta[]>([]);
|
const [pageList, setPageList] = useState<PageMeta[]>([]);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { HelpIcon, PlusIcon } from '@blocksuite/icons';
|
|||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
|
|
||||||
import { useGlobalState } from '@/store/app';
|
import { useDataCenter, useGlobalState } from '@/store/app';
|
||||||
|
|
||||||
import { CreateWorkspaceModal } from '../create-workspace';
|
import { CreateWorkspaceModal } from '../create-workspace';
|
||||||
import { LoginModal } from '../login-modal';
|
import { LoginModal } from '../login-modal';
|
||||||
@@ -34,7 +34,7 @@ interface WorkspaceModalProps {
|
|||||||
export const WorkspaceModal = ({ open, onClose }: WorkspaceModalProps) => {
|
export const WorkspaceModal = ({ open, onClose }: WorkspaceModalProps) => {
|
||||||
const [createWorkspaceOpen, setCreateWorkspaceOpen] = useState(false);
|
const [createWorkspaceOpen, setCreateWorkspaceOpen] = useState(false);
|
||||||
const logout = useGlobalState(store => store.logout);
|
const logout = useGlobalState(store => store.logout);
|
||||||
const dataCenter = useGlobalState(store => store.dataCenter);
|
const dataCenter = useDataCenter();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [loginOpen, setLoginOpen] = useState(false);
|
const [loginOpen, setLoginOpen] = useState(false);
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { useCallback, useState } from 'react';
|
|||||||
|
|
||||||
import { WorkspaceUnitAvatar } from '@/components/workspace-avatar';
|
import { WorkspaceUnitAvatar } from '@/components/workspace-avatar';
|
||||||
import { WorkspaceModal } from '@/components/workspace-modal';
|
import { WorkspaceModal } from '@/components/workspace-modal';
|
||||||
import { useGlobalState } from '@/store/app';
|
import { useDataCenter, useGlobalState } from '@/store/app';
|
||||||
|
|
||||||
import { SelectorWrapper, WorkspaceName } from './styles';
|
import { SelectorWrapper, WorkspaceName } from './styles';
|
||||||
|
|
||||||
@@ -11,7 +11,7 @@ export const WorkspaceSelector = () => {
|
|||||||
const currentWorkspace = useGlobalState(
|
const currentWorkspace = useGlobalState(
|
||||||
useCallback(store => store.currentDataCenterWorkspace, [])
|
useCallback(store => store.currentDataCenterWorkspace, [])
|
||||||
);
|
);
|
||||||
const dataCenter = useGlobalState(useCallback(store => store.dataCenter, []));
|
const dataCenter = useDataCenter();
|
||||||
|
|
||||||
if (dataCenter.workspaces.length === 0) {
|
if (dataCenter.workspaces.length === 0) {
|
||||||
setWorkspaceListShow(true);
|
setWorkspaceListShow(true);
|
||||||
|
|||||||
@@ -2,13 +2,13 @@ import { assertEquals } from '@blocksuite/global/utils';
|
|||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
import { useCallback, useEffect, useState } from 'react';
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
|
|
||||||
import { useGlobalState } from '@/store/app';
|
import { useDataCenter, useGlobalState } from '@/store/app';
|
||||||
|
|
||||||
// todo: refactor with suspense mode
|
// todo: refactor with suspense mode
|
||||||
// It is a fully effective hook
|
// It is a fully effective hook
|
||||||
// Cause it not just ensure workspace loaded, but also have router change.
|
// Cause it not just ensure workspace loaded, but also have router change.
|
||||||
export const useEnsureWorkspace = () => {
|
export const useEnsureWorkspace = () => {
|
||||||
const dataCenter = useGlobalState(useCallback(store => store.dataCenter, []));
|
const dataCenter = useDataCenter();
|
||||||
const currentWorkspace = useGlobalState(
|
const currentWorkspace = useGlobalState(
|
||||||
useCallback(store => store.currentDataCenterWorkspace, [])
|
useCallback(store => store.currentDataCenterWorkspace, [])
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { getDataCenter, WorkspaceUnit } from '@affine/datacenter';
|
import { WorkspaceUnit } from '@affine/datacenter';
|
||||||
|
import { dataCenterPromise } from '@affine/store';
|
||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
@@ -13,7 +14,7 @@ export function useLoadPublicWorkspace(workspaceId: string) {
|
|||||||
setStatus('loading');
|
setStatus('loading');
|
||||||
|
|
||||||
const init = async () => {
|
const init = async () => {
|
||||||
const dataCenter = await getDataCenter();
|
const dataCenter = await dataCenterPromise;
|
||||||
|
|
||||||
dataCenter
|
dataCenter
|
||||||
.loadPublicWorkspace(workspaceId)
|
.loadPublicWorkspace(workspaceId)
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { Member } from '@affine/datacenter';
|
import { Member } from '@affine/datacenter';
|
||||||
import { useCallback, useEffect, useState } from 'react';
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
|
|
||||||
import { useGlobalState } from '@/store/app';
|
import { useDataCenter, useGlobalState } from '@/store/app';
|
||||||
export const useMembers = () => {
|
export const useMembers = () => {
|
||||||
const dataCenter = useGlobalState(store => store.dataCenter);
|
const dataCenter = useDataCenter();
|
||||||
const currentWorkspace = useGlobalState(
|
const currentWorkspace = useGlobalState(
|
||||||
useCallback(store => store.currentDataCenterWorkspace, [])
|
useCallback(store => store.currentDataCenterWorkspace, [])
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { WorkspaceUnit } from '@affine/datacenter';
|
import { WorkspaceUnit } from '@affine/datacenter';
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
|
|
||||||
import { useGlobalState } from '@/store/app';
|
import { useDataCenter, useGlobalState } from '@/store/app';
|
||||||
|
|
||||||
export const useWorkspaceHelper = () => {
|
export const useWorkspaceHelper = () => {
|
||||||
const dataCenter = useGlobalState(store => store.dataCenter);
|
const dataCenter = useDataCenter();
|
||||||
const currentWorkspace = useGlobalState(
|
const currentWorkspace = useGlobalState(
|
||||||
useCallback(store => store.currentDataCenterWorkspace, [])
|
useCallback(store => store.currentDataCenterWorkspace, [])
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import { useEffect, useState } from 'react';
|
|||||||
|
|
||||||
import { PageLoading } from '@/components/loading';
|
import { PageLoading } from '@/components/loading';
|
||||||
import { useWorkspaceHelper } from '@/hooks/use-workspace-helper';
|
import { useWorkspaceHelper } from '@/hooks/use-workspace-helper';
|
||||||
import { useGlobalState } from '@/store/app';
|
import { useDataCenter } from '@/store/app';
|
||||||
|
|
||||||
import inviteError from '../../../public/imgs/invite-error.svg';
|
import inviteError from '../../../public/imgs/invite-error.svg';
|
||||||
import inviteSuccess from '../../../public/imgs/invite-success.svg';
|
import inviteSuccess from '../../../public/imgs/invite-success.svg';
|
||||||
@@ -21,7 +21,7 @@ export default function DevPage() {
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const [inviteData, setInviteData] = useState<Permission | null>(null);
|
const [inviteData, setInviteData] = useState<Permission | null>(null);
|
||||||
const { acceptInvite } = useWorkspaceHelper();
|
const { acceptInvite } = useWorkspaceHelper();
|
||||||
const dataCenter = useGlobalState(store => store.dataCenter);
|
const dataCenter = useDataCenter();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const init = async () => {
|
const init = async () => {
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import { EditorHeader } from '@/components/header';
|
|||||||
import MobileModal from '@/components/mobile-modal';
|
import MobileModal from '@/components/mobile-modal';
|
||||||
import WorkspaceLayout from '@/components/workspace-layout';
|
import WorkspaceLayout from '@/components/workspace-layout';
|
||||||
import { usePageHelper } from '@/hooks/use-page-helper';
|
import { usePageHelper } from '@/hooks/use-page-helper';
|
||||||
import { useGlobalState, useGlobalStateApi } from '@/store/app';
|
import { useDataCenter, useGlobalState, useGlobalStateApi } from '@/store/app';
|
||||||
import exampleMarkdown from '@/templates/Welcome-to-AFFiNE-Alpha-Downhills.md';
|
import exampleMarkdown from '@/templates/Welcome-to-AFFiNE-Alpha-Downhills.md';
|
||||||
|
|
||||||
import type { NextPageWithLayout } from '../..//_app';
|
import type { NextPageWithLayout } from '../..//_app';
|
||||||
@@ -109,7 +109,7 @@ const PageDefender = ({ children }: PropsWithChildren) => {
|
|||||||
const currentWorkspace = useGlobalState(
|
const currentWorkspace = useGlobalState(
|
||||||
useCallback(store => store.currentDataCenterWorkspace, [])
|
useCallback(store => store.currentDataCenterWorkspace, [])
|
||||||
);
|
);
|
||||||
const dataCenter = useGlobalState(store => store.dataCenter);
|
const dataCenter = useDataCenter();
|
||||||
const { createPage } = usePageHelper();
|
const { createPage } = usePageHelper();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import { createBlocksuiteWorkspace } from './utils';
|
|||||||
import { WorkspaceUnit } from './workspace-unit';
|
import { WorkspaceUnit } from './workspace-unit';
|
||||||
import type { WorkspaceUnitCollectionChangeEvent } from './workspace-unit-collection';
|
import type { WorkspaceUnitCollectionChangeEvent } from './workspace-unit-collection';
|
||||||
import { WorkspaceUnitCollection } from './workspace-unit-collection';
|
import { WorkspaceUnitCollection } from './workspace-unit-collection';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @class DataCenter
|
* @class DataCenter
|
||||||
* @classdesc Data center is made for managing different providers for business
|
* @classdesc Data center is made for managing different providers for business
|
||||||
@@ -36,6 +37,10 @@ export class DataCenter {
|
|||||||
this._logger.enabled = debug;
|
this._logger.enabled = debug;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static initEmpty() {
|
||||||
|
return new DataCenter(false);
|
||||||
|
}
|
||||||
|
|
||||||
static async init(
|
static async init(
|
||||||
debug: boolean,
|
debug: boolean,
|
||||||
exclude: 'affine'[] = []
|
exclude: 'affine'[] = []
|
||||||
|
|||||||
@@ -6,17 +6,6 @@ const _initializeDataCenter = () => {
|
|||||||
return (debug = true) => {
|
return (debug = true) => {
|
||||||
if (!_dataCenterInstance) {
|
if (!_dataCenterInstance) {
|
||||||
_dataCenterInstance = DataCenter.init(debug);
|
_dataCenterInstance = DataCenter.init(debug);
|
||||||
_dataCenterInstance.then(dc => {
|
|
||||||
try {
|
|
||||||
if (window) {
|
|
||||||
(window as any).dc = dc;
|
|
||||||
}
|
|
||||||
} catch (_) {
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
|
|
||||||
return dc;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return _dataCenterInstance;
|
return _dataCenterInstance;
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
"@blocksuite/react": "0.4.1",
|
"@blocksuite/react": "0.4.1",
|
||||||
"@blocksuite/store": "0.4.1",
|
"@blocksuite/store": "0.4.1",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
|
"swr": "^2.0.3",
|
||||||
"zustand": "^4.3.3"
|
"zustand": "^4.3.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -2,7 +2,9 @@ import { getDataCenter, WorkspaceUnit } from '@affine/datacenter';
|
|||||||
import { DataCenter } from '@affine/datacenter';
|
import { DataCenter } from '@affine/datacenter';
|
||||||
import { Disposable, DisposableGroup } from '@blocksuite/global/utils';
|
import { Disposable, DisposableGroup } from '@blocksuite/global/utils';
|
||||||
import type { PageMeta as StorePageMeta } from '@blocksuite/store';
|
import type { PageMeta as StorePageMeta } from '@blocksuite/store';
|
||||||
import React, { useCallback, useEffect } from 'react';
|
import React, { useEffect } from 'react';
|
||||||
|
import useSWR from 'swr';
|
||||||
|
|
||||||
const DEFAULT_WORKSPACE_NAME = 'Demo Workspace';
|
const DEFAULT_WORKSPACE_NAME = 'Demo Workspace';
|
||||||
|
|
||||||
export const createDefaultWorkspace = async (dataCenter: DataCenter) => {
|
export const createDefaultWorkspace = async (dataCenter: DataCenter) => {
|
||||||
@@ -11,6 +13,27 @@ export const createDefaultWorkspace = async (dataCenter: DataCenter) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
// eslint-disable-next-line no-var
|
||||||
|
var dataCenterPromise: Promise<DataCenter>;
|
||||||
|
// eslint-disable-next-line no-var
|
||||||
|
var dc: DataCenter;
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||||
|
let dataCenterPromise: Promise<DataCenter> = null!;
|
||||||
|
if (!globalThis.dataCenterPromise) {
|
||||||
|
dataCenterPromise = getDataCenter();
|
||||||
|
dataCenterPromise.then(dataCenter => {
|
||||||
|
globalThis.dc = dataCenter;
|
||||||
|
return dataCenter;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
dataCenterPromise = globalThis.dataCenterPromise;
|
||||||
|
}
|
||||||
|
|
||||||
|
export { dataCenterPromise };
|
||||||
|
|
||||||
export interface PageMeta extends StorePageMeta {
|
export interface PageMeta extends StorePageMeta {
|
||||||
favorite: boolean;
|
favorite: boolean;
|
||||||
trash: boolean;
|
trash: boolean;
|
||||||
@@ -19,11 +42,9 @@ export interface PageMeta extends StorePageMeta {
|
|||||||
mode: 'edgeless' | 'page';
|
mode: 'edgeless' | 'page';
|
||||||
}
|
}
|
||||||
|
|
||||||
import { GlobalActionsCreator, useGlobalState, useGlobalStateApi } from '..';
|
import { GlobalActionsCreator, useGlobalStateApi } from '..';
|
||||||
|
|
||||||
export type DataCenterState = {
|
export type DataCenterState = {
|
||||||
readonly dataCenter: DataCenter;
|
|
||||||
readonly dataCenterPromise: Promise<DataCenter>;
|
|
||||||
currentDataCenterWorkspace: WorkspaceUnit | null;
|
currentDataCenterWorkspace: WorkspaceUnit | null;
|
||||||
dataCenterPageList: PageMeta[];
|
dataCenterPageList: PageMeta[];
|
||||||
blobDataSynced: boolean;
|
blobDataSynced: boolean;
|
||||||
@@ -37,10 +58,6 @@ export type DataCenterActions = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const createDataCenterState = (): DataCenterState => ({
|
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,
|
currentDataCenterWorkspace: null,
|
||||||
dataCenterPageList: [],
|
dataCenterPageList: [],
|
||||||
blobDataSynced: false,
|
blobDataSynced: false,
|
||||||
@@ -50,7 +67,8 @@ export const createDataCenterActions: GlobalActionsCreator<
|
|||||||
DataCenterActions
|
DataCenterActions
|
||||||
> = (set, get) => ({
|
> = (set, get) => ({
|
||||||
loadWorkspace: async (workspaceId, signal) => {
|
loadWorkspace: async (workspaceId, signal) => {
|
||||||
const { dataCenter, currentDataCenterWorkspace } = get();
|
const dataCenter = await dataCenterPromise;
|
||||||
|
const { currentDataCenterWorkspace } = get();
|
||||||
if (!dataCenter.workspaces.find(v => v.id.toString() === workspaceId)) {
|
if (!dataCenter.workspaces.find(v => v.id.toString() === workspaceId)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -91,11 +109,14 @@ export const createDataCenterActions: GlobalActionsCreator<
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export function useDataCenter() {
|
||||||
|
const { data } = useSWR<DataCenter>(['datacenter'], {
|
||||||
|
fallbackData: DataCenter.initEmpty(),
|
||||||
|
});
|
||||||
|
return data as DataCenter;
|
||||||
|
}
|
||||||
|
|
||||||
export function DataCenterPreloader({ children }: React.PropsWithChildren) {
|
export function DataCenterPreloader({ children }: React.PropsWithChildren) {
|
||||||
const dataCenter = useGlobalState(useCallback(store => store.dataCenter, []));
|
|
||||||
const dataCenterPromise = useGlobalState(
|
|
||||||
useCallback(store => store.dataCenterPromise, [])
|
|
||||||
);
|
|
||||||
const api = useGlobalStateApi();
|
const api = useGlobalStateApi();
|
||||||
//# region effect for updating workspace page list
|
//# region effect for updating workspace page list
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -163,31 +184,5 @@ export function DataCenterPreloader({ children }: React.PropsWithChildren) {
|
|||||||
[api]
|
[api]
|
||||||
);
|
);
|
||||||
//# endregion
|
//# 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: [],
|
|
||||||
user:
|
|
||||||
(await dataCenter.getUserInfo(
|
|
||||||
dataCenter.providers.filter(p => p.id !== 'local')[0]?.id
|
|
||||||
)) || null,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
throw promise;
|
|
||||||
}
|
|
||||||
if (!dataCenter) {
|
|
||||||
throw dataCenterPromise;
|
|
||||||
}
|
|
||||||
return <>{children}</>;
|
return <>{children}</>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
|
import { assertEquals } from '@blocksuite/global/utils';
|
||||||
import type React from 'react';
|
import type React from 'react';
|
||||||
import { createContext, useContext, useMemo } from 'react';
|
import { createContext, useContext, useMemo } from 'react';
|
||||||
|
import { preload, SWRConfig, SWRConfiguration } from 'swr';
|
||||||
import { createStore, StateCreator, useStore } from 'zustand';
|
import { createStore, StateCreator, useStore } from 'zustand';
|
||||||
import { combine, subscribeWithSelector } from 'zustand/middleware';
|
import { combine, subscribeWithSelector } from 'zustand/middleware';
|
||||||
import type { UseBoundStore } from 'zustand/react';
|
import type { UseBoundStore } from 'zustand/react';
|
||||||
@@ -13,7 +15,9 @@ import {
|
|||||||
import {
|
import {
|
||||||
createDataCenterActions,
|
createDataCenterActions,
|
||||||
createDataCenterState,
|
createDataCenterState,
|
||||||
|
createDefaultWorkspace,
|
||||||
DataCenterActions,
|
DataCenterActions,
|
||||||
|
dataCenterPromise,
|
||||||
DataCenterState,
|
DataCenterState,
|
||||||
} from './datacenter';
|
} from './datacenter';
|
||||||
import {
|
import {
|
||||||
@@ -80,11 +84,37 @@ export const useGlobalState: UseBoundStore<Store> = ((
|
|||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
}) as any;
|
}) as any;
|
||||||
|
|
||||||
|
export type DataKey = ['datacenter', string] | ['datacenter'];
|
||||||
|
|
||||||
|
const swrFetcher = async (keys: DataKey) => {
|
||||||
|
assertEquals(keys[0], 'datacenter');
|
||||||
|
if (keys.length === 1) {
|
||||||
|
return await dataCenterPromise.then(async dataCenter => {
|
||||||
|
if (dataCenter.workspaces.length === 0) {
|
||||||
|
await createDefaultWorkspace(dataCenter);
|
||||||
|
}
|
||||||
|
return dataCenter;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const dataCenter = await dataCenterPromise;
|
||||||
|
return dataCenter.loadWorkspace(keys[1]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
preload(['datacenter'], swrFetcher);
|
||||||
|
|
||||||
|
const swrConfig: SWRConfiguration = {
|
||||||
|
fetcher: swrFetcher,
|
||||||
|
suspense: true,
|
||||||
|
};
|
||||||
|
|
||||||
export const GlobalAppProvider: React.FC<React.PropsWithChildren> =
|
export const GlobalAppProvider: React.FC<React.PropsWithChildren> =
|
||||||
function ModelProvider({ children }) {
|
function ModelProvider({ children }) {
|
||||||
return (
|
return (
|
||||||
<GlobalStateContext.Provider value={useMemo(() => create(), [])}>
|
<SWRConfig value={swrConfig}>
|
||||||
{children}
|
<GlobalStateContext.Provider value={useMemo(() => create(), [])}>
|
||||||
</GlobalStateContext.Provider>
|
{children}
|
||||||
|
</GlobalStateContext.Provider>
|
||||||
|
</SWRConfig>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { User } from '@affine/datacenter';
|
import { User } from '@affine/datacenter';
|
||||||
|
|
||||||
import { GlobalActionsCreator } from '..';
|
import { GlobalActionsCreator } from '..';
|
||||||
|
import { dataCenterPromise } from '../datacenter';
|
||||||
|
|
||||||
export interface UserState {
|
export interface UserState {
|
||||||
user: User | null;
|
user: User | null;
|
||||||
@@ -24,7 +25,8 @@ export const createUserActions: GlobalActionsCreator<UserActions> = (
|
|||||||
) => {
|
) => {
|
||||||
return {
|
return {
|
||||||
login: async () => {
|
login: async () => {
|
||||||
const { dataCenter, currentDataCenterWorkspace: workspace } = get();
|
const { currentDataCenterWorkspace: workspace } = get();
|
||||||
|
const dataCenter = await dataCenterPromise;
|
||||||
try {
|
try {
|
||||||
await dataCenter.login();
|
await dataCenter.login();
|
||||||
const user = (await dataCenter.getUserInfo()) as User;
|
const user = (await dataCenter.getUserInfo()) as User;
|
||||||
@@ -49,7 +51,7 @@ export const createUserActions: GlobalActionsCreator<UserActions> = (
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
logout: async () => {
|
logout: async () => {
|
||||||
const { dataCenter } = get();
|
const dataCenter = await dataCenterPromise;
|
||||||
await dataCenter.logout();
|
await dataCenter.logout();
|
||||||
set({ user: null });
|
set({ user: null });
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
export * from './app';
|
export * from './app';
|
||||||
export type { PageMeta } from './app/datacenter';
|
export type { PageMeta } from './app/datacenter';
|
||||||
export { createDefaultWorkspace, DataCenterPreloader } from './app/datacenter';
|
export { createDefaultWorkspace, DataCenterPreloader } from './app/datacenter';
|
||||||
|
export { dataCenterPromise, useDataCenter } from './app/datacenter';
|
||||||
|
|||||||
@@ -7,11 +7,10 @@ import { DataCenter, getDataCenter } from '@affine/datacenter';
|
|||||||
import {
|
import {
|
||||||
createDefaultWorkspace,
|
createDefaultWorkspace,
|
||||||
GlobalAppProvider,
|
GlobalAppProvider,
|
||||||
|
useDataCenter,
|
||||||
useGlobalState,
|
useGlobalState,
|
||||||
useGlobalStateApi,
|
|
||||||
} from '@affine/store';
|
} from '@affine/store';
|
||||||
import { render } from '@testing-library/react';
|
import { render } from '@testing-library/react';
|
||||||
import React from 'react';
|
|
||||||
import { describe, expect, test } from 'vitest';
|
import { describe, expect, test } from 'vitest';
|
||||||
|
|
||||||
describe('App Store', () => {
|
describe('App Store', () => {
|
||||||
@@ -21,29 +20,16 @@ describe('App Store', () => {
|
|||||||
await createDefaultWorkspace(dataCenter);
|
await createDefaultWorkspace(dataCenter);
|
||||||
const Inner = () => {
|
const Inner = () => {
|
||||||
const state = useGlobalState();
|
const state = useGlobalState();
|
||||||
|
const dataCenter = useDataCenter();
|
||||||
expect(state).toBeTypeOf('object');
|
expect(state).toBeTypeOf('object');
|
||||||
expect(state.dataCenter).toBeInstanceOf(DataCenter);
|
expect(dataCenter).toBeInstanceOf(DataCenter);
|
||||||
expect(state.dataCenterPromise).toBeInstanceOf(Promise);
|
|
||||||
state.dataCenterPromise.then(dc => expect(dc).toBe(state.dataCenter));
|
|
||||||
return <div>Test2</div>;
|
return <div>Test2</div>;
|
||||||
};
|
};
|
||||||
|
|
||||||
const Loader = ({ children }: React.PropsWithChildren) => {
|
|
||||||
const api = useGlobalStateApi();
|
|
||||||
if (!api.getState().dataCenter) {
|
|
||||||
api.setState({
|
|
||||||
dataCenter,
|
|
||||||
dataCenterPromise,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return <>{children}</>;
|
|
||||||
};
|
|
||||||
const App = () => (
|
const App = () => (
|
||||||
<GlobalAppProvider>
|
<GlobalAppProvider>
|
||||||
<div>Test1</div>
|
<div>Test1</div>
|
||||||
<Loader>
|
<Inner />
|
||||||
<Inner />
|
|
||||||
</Loader>
|
|
||||||
</GlobalAppProvider>
|
</GlobalAppProvider>
|
||||||
);
|
);
|
||||||
const app = render(<App />);
|
const app = render(<App />);
|
||||||
|
|||||||
12
pnpm-lock.yaml
generated
12
pnpm-lock.yaml
generated
@@ -368,6 +368,7 @@ importers:
|
|||||||
'@blocksuite/store': 0.4.1
|
'@blocksuite/store': 0.4.1
|
||||||
'@types/react': ^18.0.28
|
'@types/react': ^18.0.28
|
||||||
react: ^18.2.0
|
react: ^18.2.0
|
||||||
|
swr: ^2.0.3
|
||||||
zustand: ^4.3.3
|
zustand: ^4.3.3
|
||||||
dependencies:
|
dependencies:
|
||||||
'@affine/datacenter': link:../data-center
|
'@affine/datacenter': link:../data-center
|
||||||
@@ -377,6 +378,7 @@ importers:
|
|||||||
'@blocksuite/react': 0.4.1_6imdqfxdvhtp63fiogxmlqrieq
|
'@blocksuite/react': 0.4.1_6imdqfxdvhtp63fiogxmlqrieq
|
||||||
'@blocksuite/store': 0.4.1
|
'@blocksuite/store': 0.4.1
|
||||||
react: 18.2.0
|
react: 18.2.0
|
||||||
|
swr: 2.0.3_react@18.2.0
|
||||||
zustand: 4.3.3_react@18.2.0
|
zustand: 4.3.3_react@18.2.0
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@types/react': 18.0.28
|
'@types/react': 18.0.28
|
||||||
@@ -13950,6 +13952,16 @@ packages:
|
|||||||
use-sync-external-store: 1.2.0
|
use-sync-external-store: 1.2.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/swr/2.0.3_react@18.2.0:
|
||||||
|
resolution: {integrity: sha512-sGvQDok/AHEWTPfhUWXEHBVEXmgGnuahyhmRQbjl9XBYxT/MSlAzvXEKQpyM++bMPaI52vcWS2HiKNaW7+9OFw==}
|
||||||
|
engines: {pnpm: '7'}
|
||||||
|
peerDependencies:
|
||||||
|
react: ^16.11.0 || ^17.0.0 || ^18.0.0
|
||||||
|
dependencies:
|
||||||
|
react: 18.2.0
|
||||||
|
use-sync-external-store: 1.2.0_react@18.2.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
/synchronous-promise/2.0.17:
|
/synchronous-promise/2.0.17:
|
||||||
resolution: {integrity: sha512-AsS729u2RHUfEra9xJrE39peJcc2stq2+poBXX8bcM08Y6g9j/i/PUzwNQqkaJde7Ntg1TO7bSREbR5sdosQ+g==}
|
resolution: {integrity: sha512-AsS729u2RHUfEra9xJrE39peJcc2stq2+poBXX8bcM08Y6g9j/i/PUzwNQqkaJde7Ntg1TO7bSREbR5sdosQ+g==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|||||||
Reference in New Issue
Block a user