Files
AFFiNE-Mirror/apps/web/src/atoms/root.ts
2023-06-25 01:16:46 +08:00

139 lines
4.5 KiB
TypeScript

//#region async atoms that to load the real workspace data
import { DebugLogger } from '@affine/debug';
import { config } from '@affine/env';
import type { WorkspaceRegistry } from '@affine/env/workspace';
import { WorkspaceFlavour } from '@affine/env/workspace';
import {
rootCurrentWorkspaceIdAtom,
rootWorkspacesMetadataAtom,
} from '@affine/workspace/atom';
import type { ActiveDocProvider } from '@blocksuite/store';
import { assertExists } from '@blocksuite/store';
import { atom } from 'jotai';
import type { AllWorkspace } from '../shared';
const logger = new DebugLogger('web:atoms:root');
/**
* Fetch all workspaces from the Plugin CRUD
*/
export const workspacesAtom = atom<Promise<AllWorkspace[]>>(async get => {
const { WorkspaceAdapters } = await import('../adapters/workspace');
const flavours: string[] = Object.values(WorkspaceAdapters).map(
plugin => plugin.flavour
);
const jotaiWorkspaces = get(rootWorkspacesMetadataAtom)
.filter(
workspace => flavours.includes(workspace.flavour)
// TODO: remove this when we remove the legacy cloud
)
.filter(workspace =>
!config.enableLegacyCloud
? workspace.flavour !== WorkspaceFlavour.AFFINE
: true
);
const workspaces = await Promise.all(
jotaiWorkspaces.map(workspace => {
const plugin =
WorkspaceAdapters[workspace.flavour as keyof typeof WorkspaceAdapters];
assertExists(plugin);
const { CRUD } = plugin;
return CRUD.get(workspace.id).then(workspace => {
if (workspace === null) {
console.warn(
'workspace is null. this should not happen. If you see this error, please report it to the developer.'
);
}
return workspace;
});
})
).then(workspaces =>
workspaces.filter(
(workspace): workspace is WorkspaceRegistry['affine' | 'local'] =>
workspace !== null
)
);
const workspaceProviders = workspaces.map(workspace =>
workspace.blockSuiteWorkspace.providers.filter(
(provider): provider is ActiveDocProvider =>
'active' in provider && provider.active
)
);
const promises: Promise<void>[] = [];
for (const providers of workspaceProviders) {
for (const provider of providers) {
provider.sync();
promises.push(provider.whenReady);
}
}
// we will wait for all the necessary providers to be ready
await Promise.all(promises);
logger.info('workspaces', workspaces);
return workspaces;
});
/**
* This will throw an error if the workspace is not found,
* should not be used on the root component,
* use `rootCurrentWorkspaceIdAtom` instead
*/
export const rootCurrentWorkspaceAtom = atom<Promise<AllWorkspace>>(
async get => {
const { WorkspaceAdapters } = await import('../adapters/workspace');
const metadata = get(rootWorkspacesMetadataAtom);
const targetId = get(rootCurrentWorkspaceIdAtom);
if (targetId === null) {
throw new Error(
'current workspace id is null. this should not happen. If you see this error, please report it to the developer.'
);
}
const targetWorkspace = metadata.find(meta => meta.id === targetId);
if (!targetWorkspace) {
throw new Error(`cannot find the workspace with id ${targetId}.`);
}
const workspace = await WorkspaceAdapters[targetWorkspace.flavour].CRUD.get(
targetWorkspace.id
);
if (!workspace) {
throw new Error(
`cannot find the workspace with id ${targetId} in the plugin ${targetWorkspace.flavour}.`
);
}
const providers = workspace.blockSuiteWorkspace.providers.filter(
(provider): provider is ActiveDocProvider =>
'active' in provider && provider.active === true
);
for (const provider of providers) {
provider.sync();
// we will wait for the necessary providers to be ready
await provider.whenReady;
}
logger.info('current workspace', workspace);
globalThis.currentWorkspace = workspace;
globalThis.dispatchEvent(
new CustomEvent('affine:workspace:change', {
detail: { id: workspace.id },
})
);
return workspace;
}
);
declare global {
/**
* @internal debug only
*/
// eslint-disable-next-line no-var
var currentWorkspace: AllWorkspace | undefined;
interface WindowEventMap {
'affine:workspace:change': CustomEvent<{ id: string }>;
}
}
// Do not add `rootCurrentWorkspacePageAtom`, this is not needed.
// It can be derived from `rootCurrentWorkspaceAtom` and `rootCurrentPageIdAtom`
//#endregion