feat: page content update and output

This commit is contained in:
Philipinho
2026-02-11 23:27:22 -08:00
parent 19806eb060
commit 623182c447
3 changed files with 62 additions and 38 deletions
@@ -1,5 +1,12 @@
import { Injectable, Logger } from '@nestjs/common';
import { Hocuspocus, Document } from '@hocuspocus/server';
import { TiptapTransformer } from '@hocuspocus/transformer';
import {
prosemirrorNodeToYElement,
tiptapExtensions,
} from './collaboration.util';
import * as Y from 'yjs';
import { User } from '@docmost/db/types/entity.types';
export type CollabEventHandlers = ReturnType<
CollaborationHandler['getHandlers']
@@ -20,6 +27,47 @@ export class CollaborationHandler {
// const fragment = doc.getXmlFragment('default');
//});
},
updatePageContent: async (
documentName: string,
payload: {
pageId: string;
prosemirrorJson: any;
operation: string;
user: User;
},
) => {
const { pageId, prosemirrorJson, operation, user } = payload;
this.logger.debug(
'Updating page content via yjs',
documentName,
payload,
);
await this.withYdocConnection(
hocuspocus,
documentName,
{ user },
(doc) => {
const fragment = doc.getXmlFragment('default');
if (operation === 'replace') {
if (fragment.length > 0) {
fragment.delete(0, fragment.length);
}
const newDoc = TiptapTransformer.toYdoc(
prosemirrorJson,
'default',
tiptapExtensions,
);
Y.applyUpdate(doc, Y.encodeStateAsUpdate(newDoc));
} else {
const newContent = prosemirrorJson.content || [];
const yElements = newContent.map(prosemirrorNodeToYElement);
fragment.insert(fragment.length, yElements);
}
},
);
},
};
}
+1 -1
View File
@@ -116,7 +116,7 @@ export class PageController {
throw new ForbiddenException();
}
return this.pageService.update(page, updatePageDto, user.id);
return this.pageService.update(page, updatePageDto, user);
}
@HttpCode(HttpStatus.OK)
@@ -32,8 +32,6 @@ import {
htmlToJson,
jsonToNode,
jsonToText,
prosemirrorNodeToYElement,
tiptapExtensions,
} from 'src/collaboration/collaboration.util';
import {
CopyPageMapEntry,
@@ -48,8 +46,6 @@ import { EventName } from '../../../common/events/event.contants';
import { EventEmitter2 } from '@nestjs/event-emitter';
import { CollaborationGateway } from '../../../collaboration/collaboration.gateway';
import { markdownToHtml } from '@docmost/editor-ext';
import { TiptapTransformer } from '@hocuspocus/transformer';
import * as Y from 'yjs';
@Injectable()
export class PageService {
@@ -197,17 +193,17 @@ export class PageService {
async update(
page: Page,
updatePageDto: UpdatePageDto,
userId: string,
user: User,
): Promise<Page> {
const contributors = new Set<string>(page.contributorIds);
contributors.add(userId);
contributors.add(user.id);
const contributorIds = Array.from(contributors);
await this.pageRepo.updatePage(
{
title: updatePageDto.title,
icon: updatePageDto.icon,
lastUpdatedById: userId,
lastUpdatedById: user.id,
updatedAt: new Date(),
contributorIds: contributorIds,
},
@@ -224,7 +220,7 @@ export class PageService {
updatePageDto.content,
updatePageDto.operation,
updatePageDto.input,
userId,
user,
);
}
@@ -242,7 +238,7 @@ export class PageService {
content: string | object,
operation: ContentOperation,
input: InputFormat,
userId: string,
user: User,
): Promise<void> {
let prosemirrorJson: any;
@@ -270,35 +266,11 @@ export class PageService {
}
const documentName = `page.${pageId}`;
const connection = await this.collaborationGateway.openDirectConnection(
await this.collaborationGateway.handleYjsEvent(
'updatePageContent',
documentName,
{ user: { id: userId } },
{ pageId, operation, prosemirrorJson, user },
);
try {
await connection.transact((doc) => {
const fragment = doc.getXmlFragment('default');
if (operation === 'replace') {
if (fragment.length > 0) {
fragment.delete(0, fragment.length);
}
const newDoc = TiptapTransformer.toYdoc(
prosemirrorJson,
'default',
tiptapExtensions,
);
Y.applyUpdate(doc, Y.encodeStateAsUpdate(newDoc));
} else {
const newContent = prosemirrorJson.content || [];
const yElements = newContent.map(prosemirrorNodeToYElement);
fragment.insert(fragment.length, yElements);
}
});
} finally {
await connection.disconnect();
}
}
async getSidebarPages(
@@ -334,7 +306,11 @@ export class PageService {
cursor: pagination.cursor,
beforeCursor: pagination.beforeCursor,
fields: [
{ expression: 'position', direction: 'asc', orderModifier: (ob) => ob.collate('C').asc() },
{
expression: 'position',
direction: 'asc',
orderModifier: (ob) => ob.collate('C').asc(),
},
{ expression: 'id', direction: 'asc' },
],
parseCursor: (cursor) => ({