AFFiNE icon indicating copy to clipboard operation
AFFiNE copied to clipboard

Design & Implement Electron provider in AFFiNE

Open pengx17 opened this issue 2 years ago • 3 comments

Per client PRD, the desktop data provider should be able to do this:

  • CRUD workspaces and sync data into local db (SQLite db files)
  • this workspace can opt in with AFFiNE cloud

After the refactor of AFFiNE, there are two main data abstraction layers: WorkspacePlugin and blocksuite Provider. To add a Electron datasource we need to add one Electron workspace plugin & provider as well.

Some findings so far: There are two WorkspacePlugin flavours for now: local and affine, and it will be picked based on current active workspace. Each plugin will be responsible for managing workspaces.

export interface WorkspacePlugin<Flavour extends WorkspaceFlavour> {
  flavour: Flavour;
  // Plugin will be loaded according to the priority
  loadPriority: LoadPriority;
  // fixme: this is a hack
  cleanup?: () => void;
  // Fetch necessary data for the first render
  CRUD: WorkspaceCRUD<Flavour>;
  UI: WorkspaceUISchema<Flavour>;
}

Each WorkspacePlugin have a list of providers. The providers are mainly for initializing connections for collaboration.


For the Electron app, the local type may refer to Electron instead, and we may not need IDB provider. In this case, the provider will call the Electron commands instead. The required electron commands are pending for design.

Also, the commands will also invoke the octobase-node bindings. We need another ticket for this one.

pengx17 avatar Mar 28 '23 06:03 pengx17

For this case, you should implement a new workspace called desktop workspace or something else. And use the onTransformWorkspace function to trans data from affine or local to desktop.

Dynamic mount or unmount provider(s) will add extra logic for each workspace. Which makes test, UI/UX harder

The design of this infra is to remind you that each workspace type should have its logic and UI. not suggest you make flywire or re-use old workspace

himself65 avatar Apr 14 '23 19:04 himself65

The implementation workflow should be

  1. implement a LocalDatabaseProvider(id, yDoc) using octobase-node, and test it in vitest
  2. implement DesktopWorkspaceCRUD using octobase-node, and test it in vitest
  3. implement DesktopWorkspaceUI and test it in storybook
  4. combine them all into a new workspace plugin
  5. add transformWorkspace(from=Local/Affine, to=Desktop) and test it in playwright, vitest
  6. test case for all parts

himself65 avatar Apr 14 '23 19:04 himself65

@Himself65 Thanks for your suggestions! I think the general requirements for a desktop (provider) are:

  • every workspace will be saved locally, which could replace IDB on desktop
  • a workspace can be prompted to cloud
  • a workspace can also be de-synced and make it offline again by logging off. We should keep it locally other than removing it
  • be able to load workspace offline even if user logs in
    • as a sub requirement: loading local provider (let's call it SQLite provider?) & cloud provider simultaneously. Cloud provider should not block loading

I believe that these rules can also be applied to IDB. In my opinion, IDB should work similarly to IDB in many aspects that they do not need to watch for DB changes and only need to write to it after first download, with the exception that the user could choose where to save the database file in the filesystem for SQLite.

By the way, I think that the design of the onTransformWorkspace function does not fit well with YJS's philosophy of plug-and-play providers. I guess the reason of having it is because when prompting a workspace to cloud we will always create a new workspace with different ID?

pengx17 avatar Apr 15 '23 01:04 pengx17