mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-12 12:28:42 +00:00
120 lines
4.0 KiB
TypeScript
120 lines
4.0 KiB
TypeScript
import { DebugLogger } from '@affine/debug';
|
|
import type { LocalWorkspace, WorkspaceCRUD } from '@affine/env/workspace';
|
|
import { WorkspaceFlavour } from '@affine/env/workspace';
|
|
import { nanoid, Workspace as BlockSuiteWorkspace } from '@blocksuite/store';
|
|
import { createIndexedDBProvider } from '@toeverything/y-indexeddb';
|
|
import { createJSONStorage } from 'jotai/utils';
|
|
import { z } from 'zod';
|
|
|
|
import { createLocalProviders } from '../providers';
|
|
import { createEmptyBlockSuiteWorkspace } from '../utils';
|
|
|
|
const getStorage = () => createJSONStorage(() => localStorage);
|
|
|
|
const kStoreKey = 'affine-local-workspace';
|
|
const schema = z.array(z.string());
|
|
|
|
const logger = new DebugLogger('affine:workspace:local:crud');
|
|
|
|
/**
|
|
* @internal
|
|
*/
|
|
export function saveWorkspaceToLocalStorage(workspaceId: string) {
|
|
const storage = getStorage();
|
|
!Array.isArray(storage.getItem(kStoreKey, [])) &&
|
|
storage.setItem(kStoreKey, []);
|
|
const data = storage.getItem(kStoreKey, []) as z.infer<typeof schema>;
|
|
const id = data.find(id => id === workspaceId);
|
|
if (!id) {
|
|
logger.debug('saveWorkspaceToLocalStorage', workspaceId);
|
|
storage.setItem(kStoreKey, [...data, workspaceId]);
|
|
}
|
|
}
|
|
|
|
export const CRUD: WorkspaceCRUD<WorkspaceFlavour.LOCAL> = {
|
|
get: async workspaceId => {
|
|
logger.debug('get', workspaceId);
|
|
const storage = getStorage();
|
|
!Array.isArray(storage.getItem(kStoreKey, [])) &&
|
|
storage.setItem(kStoreKey, []);
|
|
const data = storage.getItem(kStoreKey, []) as z.infer<typeof schema>;
|
|
const id = data.find(id => id === workspaceId);
|
|
if (!id) {
|
|
return null;
|
|
}
|
|
const blockSuiteWorkspace = createEmptyBlockSuiteWorkspace(
|
|
id,
|
|
WorkspaceFlavour.LOCAL
|
|
);
|
|
const workspace: LocalWorkspace = {
|
|
id,
|
|
flavour: WorkspaceFlavour.LOCAL,
|
|
blockSuiteWorkspace: blockSuiteWorkspace,
|
|
providers: [...createLocalProviders(blockSuiteWorkspace)],
|
|
};
|
|
return workspace;
|
|
},
|
|
create: async ({ doc }) => {
|
|
logger.debug('create', doc);
|
|
const storage = getStorage();
|
|
!Array.isArray(storage.getItem(kStoreKey, [])) &&
|
|
storage.setItem(kStoreKey, []);
|
|
const binary = BlockSuiteWorkspace.Y.encodeStateAsUpdateV2(doc);
|
|
const id = nanoid();
|
|
const blockSuiteWorkspace = createEmptyBlockSuiteWorkspace(
|
|
id,
|
|
WorkspaceFlavour.LOCAL
|
|
);
|
|
BlockSuiteWorkspace.Y.applyUpdateV2(blockSuiteWorkspace.doc, binary);
|
|
const persistence = createIndexedDBProvider(blockSuiteWorkspace.doc);
|
|
persistence.connect();
|
|
await persistence.whenSynced.then(() => {
|
|
persistence.disconnect();
|
|
});
|
|
saveWorkspaceToLocalStorage(id);
|
|
return id;
|
|
},
|
|
delete: async workspace => {
|
|
logger.debug('delete', workspace);
|
|
const storage = getStorage();
|
|
!Array.isArray(storage.getItem(kStoreKey, [])) &&
|
|
storage.setItem(kStoreKey, []);
|
|
const data = storage.getItem(kStoreKey, []) as z.infer<typeof schema>;
|
|
const idx = data.findIndex(id => id === workspace.id);
|
|
if (idx === -1) {
|
|
throw new Error('workspace not found');
|
|
}
|
|
data.splice(idx, 1);
|
|
storage.setItem(kStoreKey, [...data]);
|
|
// flywire
|
|
if (window.apis && environment.isDesktop) {
|
|
await window.apis.workspace.delete(workspace.id);
|
|
}
|
|
},
|
|
list: async () => {
|
|
logger.debug('list');
|
|
const storage = getStorage();
|
|
let allWorkspaceIDs: string[] = Array.isArray(
|
|
storage.getItem(kStoreKey, [])
|
|
)
|
|
? (storage.getItem(kStoreKey, []) as z.infer<typeof schema>)
|
|
: [];
|
|
|
|
// workspaces in desktop
|
|
if (window.apis && environment.isDesktop) {
|
|
const desktopIds = (await window.apis.workspace.list()).map(([id]) => id);
|
|
// the ids maybe a subset of the local storage
|
|
const moreWorkspaces = desktopIds.filter(
|
|
id => !allWorkspaceIDs.includes(id)
|
|
);
|
|
allWorkspaceIDs = [...allWorkspaceIDs, ...moreWorkspaces];
|
|
storage.setItem(kStoreKey, allWorkspaceIDs);
|
|
}
|
|
const workspaces = (
|
|
await Promise.all(allWorkspaceIDs.map(id => CRUD.get(id)))
|
|
).filter(item => item !== null) as LocalWorkspace[];
|
|
|
|
return workspaces;
|
|
},
|
|
};
|