refactor(infra): directory structure (#4615)

This commit is contained in:
Joooye_34
2023-10-18 23:30:08 +08:00
committed by GitHub
parent 814d552be8
commit bed9310519
1150 changed files with 539 additions and 584 deletions
@@ -0,0 +1,71 @@
/**
* @vitest-environment happy-dom
*/
import 'fake-indexeddb/auto';
import type { WorkspaceCRUD } from '@affine/env/workspace';
import { WorkspaceFlavour } from '@affine/env/workspace';
import { __unstableSchemas, AffineSchemas } from '@blocksuite/blocks/models';
import { assertExists } from '@blocksuite/global/utils';
import { Schema, Workspace } from '@blocksuite/store';
import { afterEach, assertType, describe, expect, test } from 'vitest';
import { CRUD } from '../crud';
const schema = new Schema();
schema.register(AffineSchemas).register(__unstableSchemas);
afterEach(() => {
localStorage.clear();
});
describe('crud', () => {
test('type', () => {
assertType<WorkspaceCRUD<WorkspaceFlavour.LOCAL>>(CRUD);
});
test('basic', async () => {
const workspace = await CRUD.get('not_exist');
expect(workspace).toBeNull();
expect(await CRUD.list()).toEqual([]);
});
test('delete not exist', async () => {
await expect(async () =>
CRUD.delete(new Workspace({ id: 'test', schema }))
).rejects.toThrowError();
});
test('create & delete', async () => {
const workspace = new Workspace({ id: 'test', schema });
const page = workspace.createPage({ id: 'page0' });
await page.waitForLoaded();
const pageBlockId = page.addBlock('affine:page', {
title: new page.Text(''),
});
page.addBlock('affine:surface', {}, pageBlockId);
const frameId = page.addBlock('affine:note', {}, pageBlockId);
page.addBlock('affine:paragraph', {}, frameId);
const id = await CRUD.create(workspace);
const list = await CRUD.list();
expect(list.length).toBe(1);
expect(list[0].id).toBe(id);
const localWorkspace = list.at(0);
assertExists(localWorkspace);
expect(localWorkspace.id).toBe(id);
expect(localWorkspace.flavour).toBe(WorkspaceFlavour.LOCAL);
expect(localWorkspace.blockSuiteWorkspace.doc.toJSON()).toEqual({
meta: expect.anything(),
spaces: expect.objectContaining({
page0: expect.anything(),
}),
});
await CRUD.delete(localWorkspace.blockSuiteWorkspace);
expect(await CRUD.get(id)).toBeNull();
expect(await CRUD.list()).toEqual([]);
});
});
@@ -0,0 +1,112 @@
import { DebugLogger } from '@affine/debug';
import type { LocalWorkspace, WorkspaceCRUD } from '@affine/env/workspace';
import { WorkspaceFlavour } from '@affine/env/workspace';
import { Workspace as BlockSuiteWorkspace } from '@blocksuite/store';
import { createJSONStorage } from 'jotai/utils';
import { nanoid } from 'nanoid';
import { z } from 'zod';
import { getOrCreateWorkspace } from '../manager';
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 = getOrCreateWorkspace(
id,
WorkspaceFlavour.LOCAL
);
const workspace: LocalWorkspace = {
id,
flavour: WorkspaceFlavour.LOCAL,
blockSuiteWorkspace: 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.encodeStateAsUpdate(doc);
const id = nanoid();
const blockSuiteWorkspace = getOrCreateWorkspace(
id,
WorkspaceFlavour.LOCAL
);
BlockSuiteWorkspace.Y.applyUpdate(blockSuiteWorkspace.doc, binary);
doc.getSubdocs().forEach(subdoc => {
blockSuiteWorkspace.doc.getSubdocs().forEach(newDoc => {
if (subdoc.guid === newDoc.guid) {
BlockSuiteWorkspace.Y.applyUpdate(
newDoc,
BlockSuiteWorkspace.Y.encodeStateAsUpdate(subdoc)
);
}
});
});
// todo: do we need to persist doc to persistence datasource?
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();
const allWorkspaceIDs: string[] = storage.getItem(kStoreKey, []) as z.infer<
typeof schema
>;
const workspaces = (
await Promise.all(allWorkspaceIDs.map(id => CRUD.get(id)))
).filter(item => item !== null) as LocalWorkspace[];
return workspaces;
},
};