mirror of
https://github.com/hcengineering/platform.git
synced 2025-04-13 19:58:09 +00:00
UBER-853 Move snapshot creation to collaboration provider (#3807)
Signed-off-by: Alexander Onnikov <alexander.onnikov@xored.com>
This commit is contained in:
parent
c8d569621d
commit
ca0dd235b6
@ -1,6 +1,6 @@
|
|||||||
<!--
|
<!--
|
||||||
//
|
//
|
||||||
// Copyright © 2022 Hardcore Engineering Inc.
|
// Copyright © 2022, 2023 Hardcore Engineering Inc.
|
||||||
//
|
//
|
||||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
// 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
|
// you may not use this file except in compliance with the License. You may
|
||||||
@ -16,9 +16,11 @@
|
|||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { onDestroy, setContext } from 'svelte'
|
import { onDestroy, setContext } from 'svelte'
|
||||||
import { WebsocketProvider } from 'y-websocket'
|
|
||||||
import * as Y from 'yjs'
|
import * as Y from 'yjs'
|
||||||
|
|
||||||
|
import { TiptapCollabProvider } from '../provider'
|
||||||
import { CollaborationIds } from '../types'
|
import { CollaborationIds } from '../types'
|
||||||
|
|
||||||
export let documentId: string
|
export let documentId: string
|
||||||
export let token: string
|
export let token: string
|
||||||
export let collaboratorURL: string
|
export let collaboratorURL: string
|
||||||
@ -27,33 +29,35 @@
|
|||||||
|
|
||||||
let _documentId = ''
|
let _documentId = ''
|
||||||
|
|
||||||
let wsProvider: WebsocketProvider | undefined
|
let provider: TiptapCollabProvider | undefined
|
||||||
|
|
||||||
$: if (_documentId !== documentId) {
|
$: if (_documentId !== documentId) {
|
||||||
_documentId = documentId
|
_documentId = documentId
|
||||||
if (wsProvider !== undefined) {
|
if (provider !== undefined) {
|
||||||
wsProvider.disconnect()
|
provider.disconnect()
|
||||||
}
|
}
|
||||||
const ydoc: Y.Doc = new Y.Doc()
|
const ydoc: Y.Doc = new Y.Doc()
|
||||||
wsProvider = new WebsocketProvider(collaboratorURL, documentId, ydoc, {
|
provider = new TiptapCollabProvider({
|
||||||
params: {
|
url: collaboratorURL,
|
||||||
token,
|
name: documentId,
|
||||||
documentId,
|
document: ydoc,
|
||||||
|
token,
|
||||||
|
parameters: {
|
||||||
initialContentId: initialContentId ?? ''
|
initialContentId: initialContentId ?? ''
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
setContext(CollaborationIds.Doc, ydoc)
|
setContext(CollaborationIds.Doc, ydoc)
|
||||||
setContext(CollaborationIds.Provider, wsProvider)
|
setContext(CollaborationIds.Provider, provider)
|
||||||
wsProvider.on('status', (event: any) => {
|
provider.on('status', (event: any) => {
|
||||||
console.log('Collaboration:', documentId, event.status) // logs "connected" or "disconnected"
|
console.log('Collaboration:', documentId, event.status) // logs "connected" or "disconnected"
|
||||||
})
|
})
|
||||||
wsProvider.on('synched', (event: any) => {
|
provider.on('synced', (event: any) => {
|
||||||
console.log('Collaboration:', event) // logs "connected" or "disconnected"
|
console.log('Collaboration:', event) // logs "connected" or "disconnected"
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
onDestroy(() => {
|
onDestroy(() => {
|
||||||
wsProvider?.disconnect()
|
provider?.destroy()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -19,7 +19,6 @@
|
|||||||
import { DecorationSet } from 'prosemirror-view'
|
import { DecorationSet } from 'prosemirror-view'
|
||||||
import { getContext, createEventDispatcher, onDestroy, onMount } from 'svelte'
|
import { getContext, createEventDispatcher, onDestroy, onMount } from 'svelte'
|
||||||
import * as Y from 'yjs'
|
import * as Y from 'yjs'
|
||||||
import { HocuspocusProvider } from '@hocuspocus/provider'
|
|
||||||
import { AnyExtension, Editor, Extension, HTMLContent, getMarkRange, mergeAttributes } from '@tiptap/core'
|
import { AnyExtension, Editor, Extension, HTMLContent, getMarkRange, mergeAttributes } from '@tiptap/core'
|
||||||
import Collaboration, { isChangeOrigin } from '@tiptap/extension-collaboration'
|
import Collaboration, { isChangeOrigin } from '@tiptap/extension-collaboration'
|
||||||
import CollaborationCursor from '@tiptap/extension-collaboration-cursor'
|
import CollaborationCursor from '@tiptap/extension-collaboration-cursor'
|
||||||
@ -30,15 +29,16 @@
|
|||||||
|
|
||||||
import { Completion } from '../Completion'
|
import { Completion } from '../Completion'
|
||||||
import textEditorPlugin from '../plugin'
|
import textEditorPlugin from '../plugin'
|
||||||
|
import { TiptapCollabProvider } from '../provider'
|
||||||
import { CollaborationIds, TextFormatCategory, TextNodeAction } from '../types'
|
import { CollaborationIds, TextFormatCategory, TextNodeAction } from '../types'
|
||||||
|
|
||||||
import { calculateDecorations } from './diff/decorations'
|
import { calculateDecorations } from './diff/decorations'
|
||||||
|
import { defaultEditorAttributes } from './editor/editorProps'
|
||||||
import { completionConfig, defaultExtensions } from './extensions'
|
import { completionConfig, defaultExtensions } from './extensions'
|
||||||
import { InlineStyleToolbar } from './extension/inlineStyleToolbar'
|
import { InlineStyleToolbar } from './extension/inlineStyleToolbar'
|
||||||
import { NodeUuidExtension } from './extension/nodeUuid'
|
import { NodeUuidExtension } from './extension/nodeUuid'
|
||||||
import StyleButton from './StyleButton.svelte'
|
import StyleButton from './StyleButton.svelte'
|
||||||
import TextEditorStyleToolbar from './TextEditorStyleToolbar.svelte'
|
import TextEditorStyleToolbar from './TextEditorStyleToolbar.svelte'
|
||||||
import { defaultEditorAttributes } from './editor/editorProps'
|
|
||||||
|
|
||||||
export let documentId: string
|
export let documentId: string
|
||||||
export let readonly = false
|
export let readonly = false
|
||||||
@ -66,11 +66,11 @@
|
|||||||
|
|
||||||
const ydoc = (getContext(CollaborationIds.Doc) as Y.Doc | undefined) ?? new Y.Doc()
|
const ydoc = (getContext(CollaborationIds.Doc) as Y.Doc | undefined) ?? new Y.Doc()
|
||||||
|
|
||||||
const contextProvider = getContext(CollaborationIds.Provider) as HocuspocusProvider | undefined
|
const contextProvider = getContext(CollaborationIds.Provider) as TiptapCollabProvider | undefined
|
||||||
|
|
||||||
const provider =
|
const provider =
|
||||||
contextProvider ??
|
contextProvider ??
|
||||||
new HocuspocusProvider({
|
new TiptapCollabProvider({
|
||||||
url: collaboratorURL,
|
url: collaboratorURL,
|
||||||
name: documentId,
|
name: documentId,
|
||||||
document: ydoc,
|
document: ydoc,
|
||||||
@ -142,6 +142,10 @@
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function takeSnapshot (snapshotId: string) {
|
||||||
|
provider.copyContent(documentId, snapshotId)
|
||||||
|
}
|
||||||
|
|
||||||
let needFocus = false
|
let needFocus = false
|
||||||
|
|
||||||
let focused = false
|
let focused = false
|
||||||
@ -274,7 +278,6 @@
|
|||||||
editor.destroy()
|
editor.destroy()
|
||||||
} catch (err: any) {}
|
} catch (err: any) {}
|
||||||
if (contextProvider === undefined) {
|
if (contextProvider === undefined) {
|
||||||
provider.configuration.websocketProvider.disconnect()
|
|
||||||
provider.destroy()
|
provider.destroy()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
38
packages/text-editor/src/provider.ts
Normal file
38
packages/text-editor/src/provider.ts
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
//
|
||||||
|
// Copyright © 2023 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 { HocuspocusProvider, HocuspocusProviderConfiguration } from '@hocuspocus/provider'
|
||||||
|
|
||||||
|
export type TiptapCollabProviderConfiguration = HocuspocusProviderConfiguration &
|
||||||
|
Required<Pick<HocuspocusProviderConfiguration, 'token'>>
|
||||||
|
|
||||||
|
export class TiptapCollabProvider extends HocuspocusProvider {
|
||||||
|
constructor (configuration: TiptapCollabProviderConfiguration) {
|
||||||
|
super(configuration as HocuspocusProviderConfiguration)
|
||||||
|
}
|
||||||
|
|
||||||
|
copyContent (sourceId: string, targetId: string): void {
|
||||||
|
const payload = {
|
||||||
|
action: 'document.copy',
|
||||||
|
params: { sourceId, targetId }
|
||||||
|
}
|
||||||
|
this.sendStateless(JSON.stringify(payload))
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy (): void {
|
||||||
|
this.configuration.websocketProvider.disconnect()
|
||||||
|
super.destroy()
|
||||||
|
}
|
||||||
|
}
|
@ -38,3 +38,31 @@ export function yDocContentToNode (extensions: Extensions, content: ArrayBuffer,
|
|||||||
return schema.node(schema.topNodeType)
|
return schema.node(schema.topNodeType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get ProseMirror nodes from Y.Doc content
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
export function yDocContentToNodes (extensions: Extensions, content: ArrayBuffer): Node[] {
|
||||||
|
const schema = getSchema(extensions)
|
||||||
|
|
||||||
|
const nodes: Node[] = []
|
||||||
|
|
||||||
|
try {
|
||||||
|
const ydoc = new Doc()
|
||||||
|
const uint8arr = new Uint8Array(content)
|
||||||
|
applyUpdate(ydoc, uint8arr)
|
||||||
|
|
||||||
|
for (const field of ydoc.share.keys()) {
|
||||||
|
try {
|
||||||
|
const body = yDocToProsemirrorJSON(ydoc, field)
|
||||||
|
nodes.push(schema.nodeFromJSON(body))
|
||||||
|
} catch {}
|
||||||
|
}
|
||||||
|
} catch (err: any) {
|
||||||
|
console.error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nodes
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user