diff --git a/apps/core/package.json b/apps/core/package.json index 6efc672624..62ab62fea4 100644 --- a/apps/core/package.json +++ b/apps/core/package.json @@ -10,6 +10,7 @@ }, "dependencies": { "@affine-test/fixtures": "workspace:*", + "@affine/bookmark-block": "workspace:*", "@affine/component": "workspace:*", "@affine/debug": "workspace:*", "@affine/env": "workspace:*", diff --git a/apps/core/src/bootstrap/before-app.ts b/apps/core/src/bootstrap/before-app.ts new file mode 100644 index 0000000000..94b8d401f2 --- /dev/null +++ b/apps/core/src/bootstrap/before-app.ts @@ -0,0 +1,132 @@ +import { migrateToSubdoc } from '@affine/env/blocksuite'; +import { setupGlobal } from '@affine/env/global'; +import type { + LocalIndexedDBDownloadProvider, + WorkspaceAdapter, +} from '@affine/env/workspace'; +import { WorkspaceFlavour, WorkspaceVersion } from '@affine/env/workspace'; +import type { RootWorkspaceMetadata } from '@affine/workspace/atom'; +import { + type RootWorkspaceMetadataV2, + rootWorkspacesMetadataAtom, + workspaceAdaptersAtom, +} from '@affine/workspace/atom'; +import { + migrateLocalBlobStorage, + upgradeV1ToV2, +} from '@affine/workspace/migration'; +import { createIndexedDBDownloadProvider } from '@affine/workspace/providers'; +import { assertExists } from '@blocksuite/global/utils'; +import { rootStore } from '@toeverything/plugin-infra/manager'; + +import { WorkspaceAdapters } from '../adapters/workspace'; + +setupGlobal(); + +rootStore.set( + workspaceAdaptersAtom, + WorkspaceAdapters as Record< + WorkspaceFlavour, + WorkspaceAdapter + > +); + +const value = localStorage.getItem('jotai-workspaces'); +if (value) { + try { + const metadata = JSON.parse(value) as RootWorkspaceMetadata[]; + const promises: Promise[] = []; + const newMetadata = [...metadata]; + metadata.forEach(oldMeta => { + if (!('version' in oldMeta)) { + const adapter = WorkspaceAdapters[oldMeta.flavour]; + assertExists(adapter); + const upgrade = async () => { + const workspace = await adapter.CRUD.get(oldMeta.id); + if (!workspace) { + console.warn('cannot find workspace', oldMeta.id); + return; + } + if (workspace.flavour !== WorkspaceFlavour.LOCAL) { + console.warn('not supported'); + return; + } + const doc = workspace.blockSuiteWorkspace.doc; + const provider = createIndexedDBDownloadProvider(workspace.id, doc, { + awareness: workspace.blockSuiteWorkspace.awarenessStore.awareness, + }) as LocalIndexedDBDownloadProvider; + provider.sync(); + await provider.whenReady; + const newDoc = migrateToSubdoc(doc); + if (doc === newDoc) { + console.log('doc not changed'); + return; + } + const newWorkspace = upgradeV1ToV2(workspace); + + const newId = await adapter.CRUD.create( + newWorkspace.blockSuiteWorkspace + ); + + await adapter.CRUD.delete(workspace as any); + console.log('migrated', oldMeta.id, newId); + const index = newMetadata.findIndex(meta => meta.id === oldMeta.id); + newMetadata[index] = { + ...oldMeta, + id: newId, + version: WorkspaceVersion.SubDoc, + }; + await migrateLocalBlobStorage(workspace.id, newId); + }; + + // create a new workspace and push it to metadata + promises.push(upgrade()); + } + }); + + await Promise.all(promises) + .then(() => { + console.log('migration done'); + }) + .catch(() => { + console.error('migration failed'); + }) + .finally(() => { + localStorage.setItem('jotai-workspaces', JSON.stringify(newMetadata)); + window.dispatchEvent(new CustomEvent('migration-done')); + window.$migrationDone = true; + }); + } catch (e) { + console.error('error when migrating data', e); + } +} + +const createFirst = (): RootWorkspaceMetadataV2[] => { + const Plugins = Object.values(WorkspaceAdapters).sort( + (a, b) => a.loadPriority - b.loadPriority + ); + + return Plugins.flatMap(Plugin => { + return Plugin.Events['app:init']?.().map( + id => + ({ + id, + flavour: Plugin.flavour, + // new workspace should all support sub-doc feature + version: WorkspaceVersion.SubDoc, + }) satisfies RootWorkspaceMetadataV2 + ); + }).filter((ids): ids is RootWorkspaceMetadataV2 => !!ids); +}; + +await rootStore + .get(rootWorkspacesMetadataAtom) + .then(meta => { + if (meta.length === 0 && localStorage.getItem('is-first-open') === null) { + const result = createFirst(); + console.info('create first workspace', result); + localStorage.setItem('is-first-open', 'false'); + rootStore.set(rootWorkspacesMetadataAtom, result).catch(console.error); + } + }) + .catch(console.error); diff --git a/apps/core/src/bootstrap/register-plugins.ts b/apps/core/src/bootstrap/register-plugins.ts new file mode 100644 index 0000000000..4b6da39c2e --- /dev/null +++ b/apps/core/src/bootstrap/register-plugins.ts @@ -0,0 +1,3 @@ +import('@affine/bookmark-block'); + +export {}; diff --git a/apps/core/src/index.tsx b/apps/core/src/index.tsx index 8ac6ece92f..d2ba1cbee0 100644 --- a/apps/core/src/index.tsx +++ b/apps/core/src/index.tsx @@ -1,106 +1,14 @@ -import { migrateToSubdoc } from '@affine/env/blocksuite'; -import { setupGlobal } from '@affine/env/global'; -import type { LocalIndexedDBDownloadProvider } from '@affine/env/workspace'; -import { WorkspaceFlavour, WorkspaceVersion } from '@affine/env/workspace'; -import { type WorkspaceAdapter } from '@affine/env/workspace'; -import type { RootWorkspaceMetadata } from '@affine/workspace/atom'; -import { workspaceAdaptersAtom } from '@affine/workspace/atom'; -import { - migrateLocalBlobStorage, - upgradeV1ToV2, -} from '@affine/workspace/migration'; -import { createIndexedDBDownloadProvider } from '@affine/workspace/providers'; import { assertExists } from '@blocksuite/global/utils'; -import { rootStore } from '@toeverything/plugin-infra/manager'; import { createRoot } from 'react-dom/client'; -import { WorkspaceAdapters } from './adapters/workspace'; - -// bootstrap -setupGlobal(); - -rootStore.set( - workspaceAdaptersAtom, - WorkspaceAdapters as Record< - WorkspaceFlavour, - WorkspaceAdapter - > -); - -const value = localStorage.getItem('jotai-workspaces'); -if (value) { - try { - const metadata = JSON.parse(value) as RootWorkspaceMetadata[]; - const promises: Promise[] = []; - const newMetadata = [...metadata]; - metadata.forEach(oldMeta => { - if (!('version' in oldMeta)) { - const adapter = WorkspaceAdapters[oldMeta.flavour]; - assertExists(adapter); - const upgrade = async () => { - const workspace = await adapter.CRUD.get(oldMeta.id); - if (!workspace) { - console.warn('cannot find workspace', oldMeta.id); - return; - } - if (workspace.flavour !== WorkspaceFlavour.LOCAL) { - console.warn('not supported'); - return; - } - const doc = workspace.blockSuiteWorkspace.doc; - const provider = createIndexedDBDownloadProvider(workspace.id, doc, { - awareness: workspace.blockSuiteWorkspace.awarenessStore.awareness, - }) as LocalIndexedDBDownloadProvider; - provider.sync(); - await provider.whenReady; - const newDoc = migrateToSubdoc(doc); - if (doc === newDoc) { - console.log('doc not changed'); - return; - } - const newWorkspace = upgradeV1ToV2(workspace); - - const newId = await adapter.CRUD.create( - newWorkspace.blockSuiteWorkspace - ); - - await adapter.CRUD.delete(workspace as any); - console.log('migrated', oldMeta.id, newId); - const index = newMetadata.findIndex(meta => meta.id === oldMeta.id); - newMetadata[index] = { - ...oldMeta, - id: newId, - version: WorkspaceVersion.SubDoc, - }; - await migrateLocalBlobStorage(workspace.id, newId); - }; - - // create a new workspace and push it to metadata - promises.push(upgrade()); - } - }); - - Promise.all(promises) - .then(() => { - console.log('migration done'); - }) - .catch(() => { - console.error('migration failed'); - }) - .finally(() => { - localStorage.setItem('jotai-workspaces', JSON.stringify(newMetadata)); - window.dispatchEvent(new CustomEvent('migration-done')); - window.$migrationDone = true; - }); - } catch (e) { - console.error('error when migrating data', e); - } -} - -// start app -import('./app').then(({ App }) => { +async function main() { + await import('./bootstrap/before-app'); + const { App } = await import('./app'); const root = document.getElementById('app'); assertExists(root); createRoot(root).render(); -}); + await import('./bootstrap/register-plugins'); +} + +await main(); diff --git a/apps/core/src/pages/index.tsx b/apps/core/src/pages/index.tsx index 9d8b122a33..a1d5f51694 100644 --- a/apps/core/src/pages/index.tsx +++ b/apps/core/src/pages/index.tsx @@ -1,15 +1,10 @@ import { DebugLogger } from '@affine/debug'; -import { WorkspaceSubPath, WorkspaceVersion } from '@affine/env/workspace'; -import { - type RootWorkspaceMetadataV2, - rootWorkspacesMetadataAtom, -} from '@affine/workspace/atom'; +import { WorkspaceSubPath } from '@affine/env/workspace'; +import { rootWorkspacesMetadataAtom } from '@affine/workspace/atom'; import { getWorkspace } from '@toeverything/plugin-infra/__internal__/workspace'; -import { rootStore } from '@toeverything/plugin-infra/manager'; import { useAtomValue } from 'jotai'; import { lazy, useEffect, useRef } from 'react'; -import { WorkspaceAdapters } from '../adapters/workspace'; import { RouteLogic, useNavigateHelper } from '../hooks/use-navigate-helper'; import { useWorkspace } from '../hooks/use-workspace'; @@ -23,36 +18,6 @@ type WorkspaceLoaderProps = { id: string; }; -const createFirst = (): RootWorkspaceMetadataV2[] => { - const Plugins = Object.values(WorkspaceAdapters).sort( - (a, b) => a.loadPriority - b.loadPriority - ); - - return Plugins.flatMap(Plugin => { - return Plugin.Events['app:init']?.().map( - id => - ({ - id, - flavour: Plugin.flavour, - // new workspace should all support sub-doc feature - version: WorkspaceVersion.SubDoc, - }) satisfies RootWorkspaceMetadataV2 - ); - }).filter((ids): ids is RootWorkspaceMetadataV2 => !!ids); -}; - -rootStore - .get(rootWorkspacesMetadataAtom) - .then(meta => { - if (meta.length === 0 && localStorage.getItem('is-first-open') === null) { - const result = createFirst(); - console.info('create first workspace', result); - localStorage.setItem('is-first-open', 'false'); - rootStore.set(rootWorkspacesMetadataAtom, result).catch(console.error); - } - }) - .catch(console.error); - const WorkspaceLoader = (props: WorkspaceLoaderProps): null => { useWorkspace(props.id); return null; diff --git a/packages/component/package.json b/packages/component/package.json index 36fca3c257..98d165ba34 100644 --- a/packages/component/package.json +++ b/packages/component/package.json @@ -33,6 +33,7 @@ "@radix-ui/react-avatar": "^1.0.3", "@radix-ui/react-collapsible": "^1.0.3", "@radix-ui/react-radio-group": "^1.1.3", + "@radix-ui/react-scroll-area": "^1.0.4", "@radix-ui/react-toast": "^1.1.4", "@toeverything/hooks": "workspace:*", "@toeverything/plugin-infra": "workspace:*", diff --git a/yarn.lock b/yarn.lock index 97efdcfbe0..0300ad1fac 100644 --- a/yarn.lock +++ b/yarn.lock @@ -64,7 +64,7 @@ __metadata: languageName: unknown linkType: soft -"@affine/bookmark-block@workspace:plugins/bookmark-block": +"@affine/bookmark-block@workspace:*, @affine/bookmark-block@workspace:plugins/bookmark-block": version: 0.0.0-use.local resolution: "@affine/bookmark-block@workspace:plugins/bookmark-block" dependencies: @@ -123,6 +123,7 @@ __metadata: "@radix-ui/react-avatar": ^1.0.3 "@radix-ui/react-collapsible": ^1.0.3 "@radix-ui/react-radio-group": ^1.1.3 + "@radix-ui/react-scroll-area": ^1.0.4 "@radix-ui/react-toast": ^1.1.4 "@toeverything/hooks": "workspace:*" "@toeverything/plugin-infra": "workspace:*" @@ -186,6 +187,7 @@ __metadata: resolution: "@affine/core@workspace:apps/core" dependencies: "@affine-test/fixtures": "workspace:*" + "@affine/bookmark-block": "workspace:*" "@affine/component": "workspace:*" "@affine/debug": "workspace:*" "@affine/env": "workspace:*" @@ -8222,6 +8224,15 @@ __metadata: languageName: node linkType: hard +"@radix-ui/number@npm:1.0.1": + version: 1.0.1 + resolution: "@radix-ui/number@npm:1.0.1" + dependencies: + "@babel/runtime": ^7.13.10 + checksum: 621ea8b7d4195d1a65a9c0aee918e8335e7f198088eec91577512c89c2ba3a3bab4a767cfb872a2b9c3092a78ff41cad9a924845a939f6bb87fe9356241ea0ea + languageName: node + linkType: hard + "@radix-ui/primitive@npm:1.0.0": version: 1.0.0 resolution: "@radix-ui/primitive@npm:1.0.0" @@ -8704,6 +8715,34 @@ __metadata: languageName: node linkType: hard +"@radix-ui/react-scroll-area@npm:^1.0.4": + version: 1.0.4 + resolution: "@radix-ui/react-scroll-area@npm:1.0.4" + dependencies: + "@babel/runtime": ^7.13.10 + "@radix-ui/number": 1.0.1 + "@radix-ui/primitive": 1.0.1 + "@radix-ui/react-compose-refs": 1.0.1 + "@radix-ui/react-context": 1.0.1 + "@radix-ui/react-direction": 1.0.1 + "@radix-ui/react-presence": 1.0.1 + "@radix-ui/react-primitive": 1.0.3 + "@radix-ui/react-use-callback-ref": 1.0.1 + "@radix-ui/react-use-layout-effect": 1.0.1 + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + checksum: f959006a731806f3046652b318b9a5dda03c8433832a33c3e29102ec0c9ce84c000060d4b5409a159c203276032cecd34ed88e7250ea70764ad8a67447415bf1 + languageName: node + linkType: hard + "@radix-ui/react-slot@npm:1.0.0": version: 1.0.0 resolution: "@radix-ui/react-slot@npm:1.0.0"