mirror of
https://github.com/hcengineering/platform.git
synced 2026-09-27 20:14:57 +02:00
UBERF-4725 Migrate collaborative content (#5717)
Signed-off-by: Alexander Onnikov <Alexander.Onnikov@xored.com>
This commit is contained in:
@@ -13,9 +13,10 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import { yDocCopyXmlField } from '@hcengineering/collaboration'
|
||||
import { type CopyContentRequest, type CopyContentResponse } from '@hcengineering/collaborator-client'
|
||||
import { YDocVersion, takeCollaborativeDocSnapshot, yDocCopyXmlField } from '@hcengineering/collaboration'
|
||||
import { parseDocumentId, type CopyContentRequest, type CopyContentResponse } from '@hcengineering/collaborator-client'
|
||||
import { MeasureContext } from '@hcengineering/core'
|
||||
import { Doc as YDoc } from 'yjs'
|
||||
import { Context } from '../../context'
|
||||
import { RpcMethodParams } from '../rpc'
|
||||
|
||||
@@ -25,17 +26,36 @@ export async function copyContent (
|
||||
payload: CopyContentRequest,
|
||||
params: RpcMethodParams
|
||||
): Promise<CopyContentResponse> {
|
||||
const { documentId, sourceField, targetField } = payload
|
||||
const { hocuspocus } = params
|
||||
const { documentId, sourceField, targetField, snapshot } = payload
|
||||
const { hocuspocus, storageAdapter } = params
|
||||
const { workspaceId } = context
|
||||
|
||||
const connection = await ctx.with('connect', {}, async () => {
|
||||
return await hocuspocus.openDirectConnection(documentId, context)
|
||||
})
|
||||
|
||||
try {
|
||||
await connection.transact((document) => {
|
||||
yDocCopyXmlField(document, sourceField, targetField)
|
||||
await ctx.with('copy', {}, async () => {
|
||||
await connection.transact((document) => {
|
||||
yDocCopyXmlField(document, sourceField, targetField)
|
||||
})
|
||||
})
|
||||
|
||||
if (snapshot !== undefined && snapshot.versionId !== 'HEAD') {
|
||||
const ydoc = connection.document ?? new YDoc()
|
||||
const { collaborativeDoc } = parseDocumentId(documentId)
|
||||
|
||||
const version: YDocVersion = {
|
||||
versionId: snapshot.versionId,
|
||||
name: snapshot.versionName ?? snapshot.versionId,
|
||||
createdBy: snapshot.createdBy,
|
||||
createdOn: Date.now()
|
||||
}
|
||||
|
||||
await ctx.with('snapshot', {}, async () => {
|
||||
await takeCollaborativeDocSnapshot(storageAdapter, workspaceId, collaborativeDoc, ydoc, version, ctx)
|
||||
})
|
||||
}
|
||||
} finally {
|
||||
await connection.disconnect()
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ export async function getContent (
|
||||
payload: GetContentRequest,
|
||||
params: RpcMethodParams
|
||||
): Promise<GetContentResponse> {
|
||||
const { documentId, field } = payload
|
||||
const { documentId } = payload
|
||||
const { hocuspocus, transformer } = params
|
||||
|
||||
const connection = await ctx.with('connect', {}, async () => {
|
||||
@@ -32,15 +32,17 @@ export async function getContent (
|
||||
})
|
||||
|
||||
try {
|
||||
const html = await ctx.with('transform', {}, async () => {
|
||||
let content = ''
|
||||
const content = await ctx.with('transform', {}, async () => {
|
||||
const object: Record<string, string> = {}
|
||||
await connection.transact((document) => {
|
||||
content = transformer.fromYdoc(document, field)
|
||||
document.share.forEach((_, field) => {
|
||||
object[field] = transformer.fromYdoc(document, field)
|
||||
})
|
||||
})
|
||||
return content
|
||||
return object
|
||||
})
|
||||
|
||||
return { html }
|
||||
return { content }
|
||||
} finally {
|
||||
await connection.disconnect()
|
||||
}
|
||||
|
||||
@@ -13,19 +13,13 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import {
|
||||
YDocVersion,
|
||||
collaborativeHistoryDocId,
|
||||
createYdocSnapshot,
|
||||
yDocFromStorage,
|
||||
yDocToStorage
|
||||
} from '@hcengineering/collaboration'
|
||||
import { YDocVersion, takeCollaborativeDocSnapshot } from '@hcengineering/collaboration'
|
||||
import {
|
||||
parseDocumentId,
|
||||
type TakeSnapshotRequest,
|
||||
type TakeSnapshotResponse
|
||||
} from '@hcengineering/collaborator-client'
|
||||
import { CollaborativeDocVersionHead, MeasureContext, collaborativeDocParse, generateId } from '@hcengineering/core'
|
||||
import { CollaborativeDocVersionHead, MeasureContext, collaborativeDocParse } from '@hcengineering/core'
|
||||
import { Doc as YDoc } from 'yjs'
|
||||
import { Context } from '../../context'
|
||||
import { RpcMethodParams } from '../rpc'
|
||||
@@ -36,19 +30,19 @@ export async function takeSnapshot (
|
||||
payload: TakeSnapshotRequest,
|
||||
params: RpcMethodParams
|
||||
): Promise<TakeSnapshotResponse> {
|
||||
const { documentId, snapshotName, createdBy } = payload
|
||||
const { documentId, snapshot } = payload
|
||||
const { hocuspocus, storageAdapter } = params
|
||||
const { workspaceId } = context
|
||||
|
||||
const version: YDocVersion = {
|
||||
versionId: generateId(),
|
||||
name: snapshotName,
|
||||
createdBy,
|
||||
versionId: snapshot.versionId,
|
||||
name: snapshot.versionName ?? snapshot.versionId,
|
||||
createdBy: snapshot.createdBy,
|
||||
createdOn: Date.now()
|
||||
}
|
||||
|
||||
const { collaborativeDoc } = parseDocumentId(documentId)
|
||||
const { documentId: contentDocumentId, versionId } = collaborativeDocParse(collaborativeDoc)
|
||||
const { versionId } = collaborativeDocParse(collaborativeDoc)
|
||||
if (versionId !== CollaborativeDocVersionHead) {
|
||||
throw new Error('invalid document version')
|
||||
}
|
||||
@@ -58,21 +52,10 @@ export async function takeSnapshot (
|
||||
})
|
||||
|
||||
try {
|
||||
// load history document directly from storage
|
||||
const historyDocumentId = collaborativeHistoryDocId(contentDocumentId)
|
||||
const yHistory =
|
||||
(await ctx.with('yDocFromStorage', {}, async () => {
|
||||
return await yDocFromStorage(ctx, storageAdapter, workspaceId, historyDocumentId)
|
||||
})) ?? new YDoc()
|
||||
const ydoc = connection.document ?? new YDoc()
|
||||
|
||||
await ctx.with('createYdocSnapshot', {}, async () => {
|
||||
await connection.transact((yContent) => {
|
||||
createYdocSnapshot(yContent, yHistory, version)
|
||||
})
|
||||
})
|
||||
|
||||
await ctx.with('yDocToStorage', {}, async () => {
|
||||
await yDocToStorage(ctx, storageAdapter, workspaceId, historyDocumentId, yHistory)
|
||||
await ctx.with('snapshot', {}, async () => {
|
||||
await takeCollaborativeDocSnapshot(storageAdapter, workspaceId, collaborativeDoc, ydoc, version, ctx)
|
||||
})
|
||||
|
||||
return { ...version }
|
||||
|
||||
@@ -14,8 +14,13 @@
|
||||
//
|
||||
|
||||
import { MeasureContext } from '@hcengineering/core'
|
||||
import { type UpdateContentRequest, type UpdateContentResponse } from '@hcengineering/collaborator-client'
|
||||
import { applyUpdate, encodeStateAsUpdate } from 'yjs'
|
||||
import {
|
||||
parseDocumentId,
|
||||
type UpdateContentRequest,
|
||||
type UpdateContentResponse
|
||||
} from '@hcengineering/collaborator-client'
|
||||
import { YDocVersion, takeCollaborativeDocSnapshot } from '@hcengineering/collaboration'
|
||||
import { Doc as YDoc, applyUpdate, encodeStateAsUpdate } from 'yjs'
|
||||
import { Context } from '../../context'
|
||||
import { RpcMethodParams } from '../rpc'
|
||||
|
||||
@@ -25,12 +30,18 @@ export async function updateContent (
|
||||
payload: UpdateContentRequest,
|
||||
params: RpcMethodParams
|
||||
): Promise<UpdateContentResponse> {
|
||||
const { documentId, field, html } = payload
|
||||
const { hocuspocus, transformer } = params
|
||||
const { documentId, content, snapshot } = payload
|
||||
const { hocuspocus, transformer, storageAdapter } = params
|
||||
const { workspaceId } = context
|
||||
|
||||
const update = await ctx.with('transform', {}, () => {
|
||||
const ydoc = transformer.toYdoc(html, field)
|
||||
return encodeStateAsUpdate(ydoc)
|
||||
const updates = await ctx.with('transform', {}, () => {
|
||||
const updates: Record<string, Uint8Array> = {}
|
||||
|
||||
Object.entries(content).forEach(([field, markup]) => {
|
||||
const ydoc = transformer.toYdoc(markup, field)
|
||||
updates[field] = encodeStateAsUpdate(ydoc)
|
||||
})
|
||||
return updates
|
||||
})
|
||||
|
||||
const connection = await ctx.with('connect', {}, async () => {
|
||||
@@ -40,13 +51,31 @@ export async function updateContent (
|
||||
try {
|
||||
await ctx.with('update', {}, async () => {
|
||||
await connection.transact((document) => {
|
||||
const fragment = document.getXmlFragment(field)
|
||||
document.transact(() => {
|
||||
fragment.delete(0, fragment.length)
|
||||
applyUpdate(document, update)
|
||||
Object.entries(updates).forEach(([field, update]) => {
|
||||
const fragment = document.getXmlFragment(field)
|
||||
fragment.delete(0, fragment.length)
|
||||
applyUpdate(document, update)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
if (snapshot !== undefined && snapshot.versionId !== 'HEAD') {
|
||||
const ydoc = connection.document ?? new YDoc()
|
||||
const { collaborativeDoc } = parseDocumentId(documentId)
|
||||
|
||||
const version: YDocVersion = {
|
||||
versionId: snapshot.versionId,
|
||||
name: snapshot.versionName ?? snapshot.versionId,
|
||||
createdBy: snapshot.createdBy,
|
||||
createdOn: Date.now()
|
||||
}
|
||||
|
||||
await ctx.with('snapshot', {}, async () => {
|
||||
await takeCollaborativeDocSnapshot(storageAdapter, workspaceId, collaborativeDoc, ydoc, version, ctx)
|
||||
})
|
||||
}
|
||||
} finally {
|
||||
await connection.disconnect()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user