mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-19 02:56:23 +08:00
refactor: rootWorkspacesMetadataAtom loading logic (#2882)
This commit is contained in:
@@ -4,11 +4,15 @@
|
||||
import 'fake-indexeddb/auto';
|
||||
|
||||
import { initEmptyPage } from '@affine/env/blocksuite';
|
||||
import type { LocalIndexedDBBackgroundProvider } from '@affine/env/workspace';
|
||||
import type {
|
||||
LocalIndexedDBBackgroundProvider,
|
||||
WorkspaceAdapter,
|
||||
} from '@affine/env/workspace';
|
||||
import { WorkspaceFlavour, WorkspaceVersion } from '@affine/env/workspace';
|
||||
import {
|
||||
rootCurrentWorkspaceIdAtom,
|
||||
rootWorkspacesMetadataAtom,
|
||||
workspaceAdaptersAtom,
|
||||
} from '@affine/workspace/atom';
|
||||
import { createIndexedDBBackgroundProvider } from '@affine/workspace/providers';
|
||||
import {
|
||||
@@ -63,6 +67,13 @@ describe('page mode atom', () => {
|
||||
describe('currentWorkspace atom', () => {
|
||||
test('should be defined', async () => {
|
||||
const store = createStore();
|
||||
store.set(
|
||||
workspaceAdaptersAtom,
|
||||
WorkspaceAdapters as Record<
|
||||
WorkspaceFlavour,
|
||||
WorkspaceAdapter<WorkspaceFlavour>
|
||||
>
|
||||
);
|
||||
let id: string;
|
||||
{
|
||||
const workspace = createEmptyBlockSuiteWorkspace(
|
||||
@@ -92,7 +103,7 @@ describe('currentWorkspace atom', () => {
|
||||
const workspaceId = await WorkspaceAdapters[
|
||||
WorkspaceFlavour.LOCAL
|
||||
].CRUD.create(workspace);
|
||||
store.set(rootWorkspacesMetadataAtom, [
|
||||
await store.set(rootWorkspacesMetadataAtom, [
|
||||
{
|
||||
id: workspaceId,
|
||||
flavour: WorkspaceFlavour.LOCAL,
|
||||
@@ -103,7 +114,7 @@ describe('currentWorkspace atom', () => {
|
||||
}
|
||||
store.set(
|
||||
rootCurrentWorkspaceIdAtom,
|
||||
store.get(rootWorkspacesMetadataAtom)[0].id
|
||||
(await store.get(rootWorkspacesMetadataAtom))[0].id
|
||||
);
|
||||
const workspace = await store.get(rootCurrentWorkspaceAtom);
|
||||
expect(workspace).toBeDefined();
|
||||
|
||||
@@ -1,84 +1,8 @@
|
||||
import { DebugLogger } from '@affine/debug';
|
||||
import { WorkspaceFlavour, WorkspaceVersion } from '@affine/env/workspace';
|
||||
import type { RootWorkspaceMetadataV2 } from '@affine/workspace/atom';
|
||||
import { rootWorkspacesMetadataAtom } from '@affine/workspace/atom';
|
||||
import { atom } from 'jotai';
|
||||
import { atomFamily, atomWithStorage } from 'jotai/utils';
|
||||
|
||||
import { WorkspaceAdapters } from '../adapters/workspace';
|
||||
import type { CreateWorkspaceMode } from '../components/affine/create-workspace-modal';
|
||||
|
||||
const logger = new DebugLogger('web:atoms');
|
||||
|
||||
// workspace necessary atoms
|
||||
// todo(himself65): move this to the workspace package
|
||||
rootWorkspacesMetadataAtom.onMount = setAtom => {
|
||||
function createFirst(): RootWorkspaceMetadataV2[] {
|
||||
const Plugins = Object.values(WorkspaceAdapters).sort(
|
||||
(a, b) => a.loadPriority - b.loadPriority
|
||||
);
|
||||
|
||||
return Plugins.flatMap(Plugin => {
|
||||
return Plugin.Events['app:init']?.().map(
|
||||
id =>
|
||||
({
|
||||
id,
|
||||
flavour: Plugin.flavour,
|
||||
// new workspace should all support sub-doc feature
|
||||
version: WorkspaceVersion.SubDoc,
|
||||
} satisfies RootWorkspaceMetadataV2)
|
||||
);
|
||||
}).filter((ids): ids is RootWorkspaceMetadataV2 => !!ids);
|
||||
}
|
||||
|
||||
const abortController = new AbortController();
|
||||
|
||||
if (!environment.isServer) {
|
||||
// next tick to make sure the hydration is correct
|
||||
setTimeout(() => {
|
||||
setAtom(metadata => {
|
||||
if (abortController.signal.aborted) return metadata;
|
||||
if (
|
||||
metadata.length === 0 &&
|
||||
localStorage.getItem('is-first-open') === null
|
||||
) {
|
||||
localStorage.setItem('is-first-open', 'false');
|
||||
const newMetadata = createFirst();
|
||||
logger.info('create first workspace', newMetadata);
|
||||
return newMetadata;
|
||||
}
|
||||
return metadata;
|
||||
});
|
||||
}, 0);
|
||||
}
|
||||
|
||||
if (environment.isDesktop && runtimeConfig.enableSQLiteProvider) {
|
||||
window.apis?.workspace
|
||||
.list()
|
||||
.then(workspaceIDs => {
|
||||
if (abortController.signal.aborted) return;
|
||||
const newMetadata = workspaceIDs.map(w => ({
|
||||
id: w[0],
|
||||
flavour: WorkspaceFlavour.LOCAL,
|
||||
version: undefined,
|
||||
}));
|
||||
setAtom(metadata => {
|
||||
return [
|
||||
...metadata,
|
||||
...newMetadata.filter(m => !metadata.find(m2 => m2.id === m.id)),
|
||||
];
|
||||
});
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
});
|
||||
}
|
||||
|
||||
return () => {
|
||||
abortController.abort();
|
||||
};
|
||||
};
|
||||
|
||||
// modal atoms
|
||||
export const openWorkspacesModalAtom = atom(false);
|
||||
export const openCreateWorkspaceModalAtom = atom<CreateWorkspaceMode>(false);
|
||||
|
||||
+19
-14
@@ -1,6 +1,9 @@
|
||||
//#region async atoms that to load the real workspace data
|
||||
import { DebugLogger } from '@affine/debug';
|
||||
import type { WorkspaceRegistry } from '@affine/env/workspace';
|
||||
import type {
|
||||
WorkspaceAdapter,
|
||||
WorkspaceRegistry,
|
||||
} from '@affine/env/workspace';
|
||||
import { WorkspaceFlavour } from '@affine/env/workspace';
|
||||
import {
|
||||
rootCurrentWorkspaceIdAtom,
|
||||
@@ -23,7 +26,7 @@ export const workspacesAtom = atom<Promise<AllWorkspace[]>>(
|
||||
const flavours: string[] = Object.values(WorkspaceAdapters).map(
|
||||
plugin => plugin.flavour
|
||||
);
|
||||
const jotaiWorkspaces = get(rootWorkspacesMetadataAtom)
|
||||
const jotaiWorkspaces = (await get(rootWorkspacesMetadataAtom))
|
||||
.filter(
|
||||
workspace => flavours.includes(workspace.flavour)
|
||||
// TODO: remove this when we remove the legacy cloud
|
||||
@@ -33,7 +36,7 @@ export const workspacesAtom = atom<Promise<AllWorkspace[]>>(
|
||||
? workspace.flavour !== WorkspaceFlavour.AFFINE
|
||||
: true
|
||||
);
|
||||
if (jotaiWorkspaces.some(meta => meta.version === undefined)) {
|
||||
if (jotaiWorkspaces.some(meta => !('version' in meta))) {
|
||||
// wait until all workspaces have migrated to v2
|
||||
await new Promise((resolve, reject) => {
|
||||
signal.addEventListener('abort', reject);
|
||||
@@ -44,12 +47,11 @@ export const workspacesAtom = atom<Promise<AllWorkspace[]>>(
|
||||
}
|
||||
const workspaces = await Promise.all(
|
||||
jotaiWorkspaces.map(workspace => {
|
||||
const plugin =
|
||||
WorkspaceAdapters[
|
||||
workspace.flavour as keyof typeof WorkspaceAdapters
|
||||
];
|
||||
assertExists(plugin);
|
||||
const { CRUD } = plugin;
|
||||
const adapter = WorkspaceAdapters[
|
||||
workspace.flavour
|
||||
] as WorkspaceAdapter<WorkspaceFlavour>;
|
||||
assertExists(adapter);
|
||||
const { CRUD } = adapter;
|
||||
return CRUD.get(workspace.id).then(workspace => {
|
||||
if (workspace === null) {
|
||||
console.warn(
|
||||
@@ -93,7 +95,7 @@ export const workspacesAtom = atom<Promise<AllWorkspace[]>>(
|
||||
export const rootCurrentWorkspaceAtom = atom<Promise<AllWorkspace>>(
|
||||
async (get, { signal }) => {
|
||||
const { WorkspaceAdapters } = await import('../adapters/workspace');
|
||||
const metadata = get(rootWorkspacesMetadataAtom);
|
||||
const metadata = await get(rootWorkspacesMetadataAtom);
|
||||
const targetId = get(rootCurrentWorkspaceIdAtom);
|
||||
if (targetId === null) {
|
||||
throw new Error(
|
||||
@@ -105,7 +107,7 @@ export const rootCurrentWorkspaceAtom = atom<Promise<AllWorkspace>>(
|
||||
throw new Error(`cannot find the workspace with id ${targetId}.`);
|
||||
}
|
||||
|
||||
if (!targetWorkspace.version) {
|
||||
if (!('version' in targetWorkspace)) {
|
||||
// wait until the workspace has migrated to v2
|
||||
await new Promise((resolve, reject) => {
|
||||
signal.addEventListener('abort', reject);
|
||||
@@ -115,9 +117,12 @@ export const rootCurrentWorkspaceAtom = atom<Promise<AllWorkspace>>(
|
||||
});
|
||||
}
|
||||
|
||||
const workspace = await WorkspaceAdapters[targetWorkspace.flavour].CRUD.get(
|
||||
targetWorkspace.id
|
||||
);
|
||||
const adapter = WorkspaceAdapters[
|
||||
targetWorkspace.flavour
|
||||
] as WorkspaceAdapter<WorkspaceFlavour>;
|
||||
assertExists(adapter);
|
||||
|
||||
const workspace = await adapter.CRUD.get(targetWorkspace.id);
|
||||
if (!workspace) {
|
||||
throw new Error(
|
||||
`cannot find the workspace with id ${targetId} in the plugin ${targetWorkspace.flavour}.`
|
||||
|
||||
Reference in New Issue
Block a user