From c18ea98abaa1af2d2a3f1f68cb445d62a5ac500e Mon Sep 17 00:00:00 2001 From: Alexander Onnikov Date: Fri, 23 Aug 2024 13:44:19 +0700 Subject: [PATCH] UBERF-7931 Get rid of file collab provider Signed-off-by: Alexander Onnikov --- common/config/rush/pnpm-lock.yaml | 21 ++++-- plugins/text-editor-resources/package.json | 3 +- .../components/CollaborativeTextEditor.svelte | 8 +-- .../src/provider/indexeddb.ts | 32 +++++++++ .../src/provider/storage.ts | 71 ------------------- 5 files changed, 54 insertions(+), 81 deletions(-) create mode 100644 plugins/text-editor-resources/src/provider/indexeddb.ts delete mode 100644 plugins/text-editor-resources/src/provider/storage.ts diff --git a/common/config/rush/pnpm-lock.yaml b/common/config/rush/pnpm-lock.yaml index d9bfcfe71a9..3dcb5d67f30 100644 --- a/common/config/rush/pnpm-lock.yaml +++ b/common/config/rush/pnpm-lock.yaml @@ -23686,6 +23686,16 @@ packages: engines: {node: '>=0.4'} dev: false + /y-indexeddb@9.0.12(yjs@13.6.12): + resolution: {integrity: sha512-9oCFRSPPzBK7/w5vOkJBaVCQZKHXB/v6SIT+WYhnJxlEC61juqG0hBrAf+y3gmSMLFLwICNH9nQ53uscuse6Hg==} + engines: {node: '>=16.0.0', npm: '>=8.0.0'} + peerDependencies: + yjs: ^13.0.0 + dependencies: + lib0: 0.2.89 + yjs: 13.6.12 + dev: false + /y-prosemirror@1.2.2(prosemirror-model@1.19.4)(y-protocols@1.0.6)(yjs@13.6.12): resolution: {integrity: sha512-hHdnIAhfa8mIoLWtTkMDb6RBzN3lye1QVkaZwVm58sledAA1zTl+yyEtgkrY/sdH6SaQL0rsLj61zHjgr5D0HQ==} engines: {node: '>=16.0.0', npm: '>=8.0.0'} @@ -25018,7 +25028,7 @@ packages: dev: false file:projects/collaborator.tgz(@tiptap/pm@2.2.4)(bufferutil@4.0.8)(prosemirror-model@1.19.4)(utf-8-validate@6.0.4)(y-protocols@1.0.6): - resolution: {integrity: sha512-2kBYCHIIHeDD99Oj4ViM3+h4CPlelHbpP+HOtuYXSxNeM+hsIhmqdQJrSBoLA3u5LGTsHHapjg94S4sgaMz60Q==, tarball: file:projects/collaborator.tgz} + resolution: {integrity: sha512-svaotn6ykOZH+tModYWz/Y3hct1yHDm/enwC9NCpH17VVNALvRIqUx8F2DWvQV5mUwJYxLcKgdsBqNPB4MjMag==, tarball: file:projects/collaborator.tgz} id: file:projects/collaborator.tgz name: '@rush-temp/collaborator' version: 0.0.0 @@ -25113,7 +25123,7 @@ packages: dev: false file:projects/contact-resources.tgz(@types/node@20.11.19)(esbuild@0.20.1)(postcss-load-config@4.0.2)(postcss@8.4.35)(ts-node@10.9.2): - resolution: {integrity: sha512-Vlw7yfM/X0ViZ1mzmcJFVPAZk/2hp4l768lxErLF/sA2HKsRUCAvkjbzfHmImsK5e2WycFWOWwnUJu9p1irQWQ==, tarball: file:projects/contact-resources.tgz} + resolution: {integrity: sha512-MzZXj700B09rHWIeXhV8qKlv9OTeZvERBG/Clv+H6OyU9CR03EZpiYEYM725EjYKMTvso1XWsYbjEBfwBi0LYg==, tarball: file:projects/contact-resources.tgz} id: file:projects/contact-resources.tgz name: '@rush-temp/contact-resources' version: 0.0.0 @@ -27302,7 +27312,7 @@ packages: dev: false file:projects/model-controlled-documents.tgz: - resolution: {integrity: sha512-Fg2GDNEA/E5UucxJtuVYq9G9aPq2BTBbo5HYwk64AzpWOfYEI0mzv+FAeAeTMPRKwZR8TDKxKgNCmmMXsmo/PQ==, tarball: file:projects/model-controlled-documents.tgz} + resolution: {integrity: sha512-mBRvO5kEuPrWKHjTZdQFnzV5CyVAysglTX/XFVp7Hlx8lEbRcWI91ZnU/BhOn2vTw7B3ZFCiVRDd8lgh8fAJJA==, tarball: file:projects/model-controlled-documents.tgz} name: '@rush-temp/model-controlled-documents' version: 0.0.0 dependencies: @@ -27321,7 +27331,7 @@ packages: dev: false file:projects/model-core.tgz: - resolution: {integrity: sha512-CbejItmOqGGWqUDIH8lag6srILkEB4ydxks6y/nKZdcQ5z+I3RWW7td/P1nPbsccIyYg+9AIgd1R7N8LSPh8DA==, tarball: file:projects/model-core.tgz} + resolution: {integrity: sha512-zEK+S8loxsZcxXH31h/0nAbjHb8XwgZ4t7wCgVb6SdHMFZ4Ysqt/ttLE3mT1vJXlYYpb4wWNGAPjq1HVK2Da+Q==, tarball: file:projects/model-core.tgz} name: '@rush-temp/model-core' version: 0.0.0 dependencies: @@ -33852,7 +33862,7 @@ packages: dev: false file:projects/text-editor-resources.tgz(@types/node@20.11.19)(bufferutil@4.0.8)(esbuild@0.20.1)(postcss-load-config@4.0.2)(postcss@8.4.35)(prosemirror-model@1.19.4)(ts-node@10.9.2)(utf-8-validate@6.0.4): - resolution: {integrity: sha512-piHhMfwGIkFR7VYjYWS1lGTwg5zIQaKJmKSSAY7gpRGM4BA88RagpPmx8eT/hXvFv83a+4CzkMUK/atGHWRZcQ==, tarball: file:projects/text-editor-resources.tgz} + resolution: {integrity: sha512-PNeHw/vqYgLq6arghBnAisN4GlvA0DWANKiXTvjahoXM0EhEz6SVX2bh6Fd9xrDqYKWVdfVc2X5o5Zk1dI4qEw==, tarball: file:projects/text-editor-resources.tgz} id: file:projects/text-editor-resources.tgz name: '@rush-temp/text-editor-resources' version: 0.0.0 @@ -33905,6 +33915,7 @@ packages: svelte-preprocess: 5.1.3(postcss-load-config@4.0.2)(postcss@8.4.35)(sass@1.71.1)(svelte@4.2.12)(typescript@5.3.3) ts-jest: 29.1.2(esbuild@0.20.1)(jest@29.7.0)(typescript@5.3.3) typescript: 5.3.3 + y-indexeddb: 9.0.12(yjs@13.6.12) y-prosemirror: 1.2.2(prosemirror-model@1.19.4)(y-protocols@1.0.6)(yjs@13.6.12) y-protocols: 1.0.6(yjs@13.6.12) yjs: 13.6.12 diff --git a/plugins/text-editor-resources/package.json b/plugins/text-editor-resources/package.json index 5f597ae2fca..b176d934717 100644 --- a/plugins/text-editor-resources/package.json +++ b/plugins/text-editor-resources/package.json @@ -77,6 +77,7 @@ "rfc6902": "^5.0.1", "diff": "^5.1.0", "slugify": "^1.6.6", - "lib0": "^0.2.88" + "lib0": "^0.2.88", + "y-indexeddb": "^9.0.12" } } diff --git a/plugins/text-editor-resources/src/components/CollaborativeTextEditor.svelte b/plugins/text-editor-resources/src/components/CollaborativeTextEditor.svelte index 88f5273226a..c5344212644 100644 --- a/plugins/text-editor-resources/src/components/CollaborativeTextEditor.svelte +++ b/plugins/text-editor-resources/src/components/CollaborativeTextEditor.svelte @@ -43,7 +43,7 @@ import { deleteAttachment } from '../command/deleteAttachment' import { textEditorCommandHandler } from '../commands' import { EditorKitOptions, getEditorKit } from '../../src/kits/editor-kit' - import { DirectStorageProvider } from '../provider/storage' + import { IndexeddbProvider } from '../provider/indexeddb' import { TiptapCollabProvider } from '../provider/tiptap' import { formatCollaborativeDocumentId, formatPlatformDocumentId } from '../provider/utils' import textEditor, { @@ -121,7 +121,7 @@ const ydoc = getContext(CollaborationIds.Doc) ?? new YDoc() const contextProvider = getContext(CollaborationIds.Provider) - const localProvider = contextProvider === undefined ? new DirectStorageProvider(collaborativeDoc, ydoc) : undefined + const localProvider = new IndexeddbProvider(collaborativeDoc, ydoc) const remoteProvider: TiptapCollabProvider = contextProvider ?? @@ -142,7 +142,7 @@ $: loading = !localSynced && !remoteSynced $: editable = !readonly && remoteSynced - void localProvider?.loaded.then(() => (localSynced = true)) + void localProvider.loaded.then(() => (localSynced = true)) void remoteProvider.loaded.then(() => (remoteSynced = true)) let editor: Editor @@ -480,7 +480,7 @@ if (contextProvider === undefined) { remoteProvider.destroy() } - localProvider?.destroy() + void localProvider.destroy() }) diff --git a/plugins/text-editor-resources/src/provider/indexeddb.ts b/plugins/text-editor-resources/src/provider/indexeddb.ts new file mode 100644 index 00000000000..14b342ac81b --- /dev/null +++ b/plugins/text-editor-resources/src/provider/indexeddb.ts @@ -0,0 +1,32 @@ +// +// Copyright © 2024 Hardcore Engineering Inc. +// +// Licensed under the Eclipse Public License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. You may +// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// +// See the License for the specific language governing permissions and +// limitations under the License. +// +import { collaborativeDocParse, type CollaborativeDoc } from '@hcengineering/core' +import { type Doc as YDoc } from 'yjs' +import { IndexeddbPersistence } from 'y-indexeddb' + +export class IndexeddbProvider extends IndexeddbPersistence { + loaded: Promise + + constructor (collaborativeDoc: CollaborativeDoc, doc: YDoc) { + const { documentId, versionId } = collaborativeDocParse(collaborativeDoc) + const name = `${documentId}/${versionId}` + + super(name, doc) + + this.loaded = new Promise((resolve) => { + this.on('synced', resolve) + }) + } +} diff --git a/plugins/text-editor-resources/src/provider/storage.ts b/plugins/text-editor-resources/src/provider/storage.ts deleted file mode 100644 index fcd4cd31656..00000000000 --- a/plugins/text-editor-resources/src/provider/storage.ts +++ /dev/null @@ -1,71 +0,0 @@ -// -// Copyright © 2023, 2024 Hardcore Engineering Inc. -// -// Licensed under the Eclipse Public License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. You may -// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// -// See the License for the specific language governing permissions and -// limitations under the License. -// -import { collaborativeDocParse, type Blob, type CollaborativeDoc, type Ref } from '@hcengineering/core' -import { getFileUrl } from '@hcengineering/presentation' -import { ObservableV2 as Observable } from 'lib0/observable' -import { applyUpdate, type Doc as YDoc } from 'yjs' - -interface EVENTS { - synced: (...args: any[]) => void -} - -async function fetchContent (blob: Ref, doc: YDoc): Promise { - const update = await fetchBlobContent(blob) - if (update !== undefined) { - applyUpdate(doc, update) - return true - } - - return false -} - -async function fetchBlobContent (_id: Ref): Promise { - try { - const href = getFileUrl(_id) - const res = await fetch(href) - - if (res.ok) { - const blob = await res.blob() - const buffer = await blob.arrayBuffer() - return new Uint8Array(buffer) - } - } catch (err: any) { - console.error(err) - } - - return undefined -} - -export class DirectStorageProvider extends Observable { - loaded: Promise - - constructor (collaborativeDoc: CollaborativeDoc, doc: YDoc) { - super() - - this.loaded = new Promise((resolve) => { - this.on('synced', resolve) - }) - - const { documentId, versionId } = collaborativeDocParse(collaborativeDoc) - - if (versionId === 'HEAD') { - void fetchContent(documentId as Ref, doc).then((synced) => { - if (synced) { - this.emit('synced', [this]) - } - }) - } - } -}