AFFiNE icon indicating copy to clipboard operation
AFFiNE copied to clipboard

Workspace plugin abstraction

Open himself65 opened this issue 2 years ago • 1 comments

Introduction

  • The Workspace plugin is mainly for better maintenance and allows the community to add more workspace types (like connecting with the database on the desktop or other authorized workspace functions).
  • Each part of the workspace plugin should work individually well. UI could run on storybook without real logic, and logic should work fine on vitest.

Code Structure

  • @affine/workspace
    • AFFiNE: affine workspace
    • Local: local workspace
    • ... you self-designed a workspace

Each Workspace Plugin has its state and is isolated from each other workspace.

There are two main parts of the plugin: UI and logic.

Logic

Each workspace plugin should provide basic CRUD API for the upstream calling.

type CRUD = {
  get: (id: string) => Promise<Workspace | null>
  create: (id: string) => Promise<Workspace>
  delete: (id: string) => Promise<Workspace>
  list: () => Promise<Workspace[]>
}

Each workspace CRUD should maintain its persistence state, whether saved in localStorage, indexedDB, remote server, random data, or a combination of them. AFFiNE won't care about it. AFFiNE will only store id and flavor for each workspace on top to make sure each refresh page will keep track of all tracked workspaces in the last time.

UI

UI is highly coupled with its type of workspace. The last data-center code design does not isolate the workspace data but combines all workspace types into a single UI, making tiny code changes that will cause a high maintenance cost.

The new code design requires you to design your UI for the type of workspace; of course, you can reuse the other components, but remember that UI should be combined with logic. Doing this allows you to code much stronger type and data assertion in each component.

Data Structure

For example, the type of local workspace

export interface LocalWorkspace {
  flavour: WorkspaceFlavour.LOCAL;
  id: string;
  blockSuiteWorkspace: BlockSuiteWorkspace;
  providers: Provider[];
}

Provider

The provider is the way to connect a single yDoc (or blocksuite store) to the external world, like persistence with indexeddb or OctoBase server. It should promise to clean up the side effect. For example, when the user switches a workspace, all previous providers should be cleaned up correctly.

There are also two types of providers: background and foreground. This concept is easy to understand that when the user enters the AFFiNE, all of the local data should be loaded on the workspace list.

himself65 avatar Apr 04 '23 04:04 himself65

Related

  • https://github.com/toeverything/AFFiNE/pull/1661
  • https://github.com/toeverything/AFFiNE/pull/1778
  • https://github.com/toeverything/AFFiNE/pull/1809

himself65 avatar Apr 04 '23 04:04 himself65

BTW, we renamed the workspace plugin to workspace adapter

himself65 avatar Jun 30 '23 05:06 himself65