mirror of
https://github.com/docmost/docmost.git
synced 2026-08-31 02:46:27 +08:00
feat: page content update and output
This commit is contained in:
@@ -1,5 +1,12 @@
|
|||||||
import { Injectable, Logger } from '@nestjs/common';
|
import { Injectable, Logger } from '@nestjs/common';
|
||||||
import { Hocuspocus, Document } from '@hocuspocus/server';
|
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<
|
export type CollabEventHandlers = ReturnType<
|
||||||
CollaborationHandler['getHandlers']
|
CollaborationHandler['getHandlers']
|
||||||
@@ -20,6 +27,47 @@ export class CollaborationHandler {
|
|||||||
// const fragment = doc.getXmlFragment('default');
|
// 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);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ export class PageController {
|
|||||||
throw new ForbiddenException();
|
throw new ForbiddenException();
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.pageService.update(page, updatePageDto, user.id);
|
return this.pageService.update(page, updatePageDto, user);
|
||||||
}
|
}
|
||||||
|
|
||||||
@HttpCode(HttpStatus.OK)
|
@HttpCode(HttpStatus.OK)
|
||||||
|
|||||||
@@ -32,8 +32,6 @@ import {
|
|||||||
htmlToJson,
|
htmlToJson,
|
||||||
jsonToNode,
|
jsonToNode,
|
||||||
jsonToText,
|
jsonToText,
|
||||||
prosemirrorNodeToYElement,
|
|
||||||
tiptapExtensions,
|
|
||||||
} from 'src/collaboration/collaboration.util';
|
} from 'src/collaboration/collaboration.util';
|
||||||
import {
|
import {
|
||||||
CopyPageMapEntry,
|
CopyPageMapEntry,
|
||||||
@@ -48,8 +46,6 @@ import { EventName } from '../../../common/events/event.contants';
|
|||||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||||
import { CollaborationGateway } from '../../../collaboration/collaboration.gateway';
|
import { CollaborationGateway } from '../../../collaboration/collaboration.gateway';
|
||||||
import { markdownToHtml } from '@docmost/editor-ext';
|
import { markdownToHtml } from '@docmost/editor-ext';
|
||||||
import { TiptapTransformer } from '@hocuspocus/transformer';
|
|
||||||
import * as Y from 'yjs';
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class PageService {
|
export class PageService {
|
||||||
@@ -197,17 +193,17 @@ export class PageService {
|
|||||||
async update(
|
async update(
|
||||||
page: Page,
|
page: Page,
|
||||||
updatePageDto: UpdatePageDto,
|
updatePageDto: UpdatePageDto,
|
||||||
userId: string,
|
user: User,
|
||||||
): Promise<Page> {
|
): Promise<Page> {
|
||||||
const contributors = new Set<string>(page.contributorIds);
|
const contributors = new Set<string>(page.contributorIds);
|
||||||
contributors.add(userId);
|
contributors.add(user.id);
|
||||||
const contributorIds = Array.from(contributors);
|
const contributorIds = Array.from(contributors);
|
||||||
|
|
||||||
await this.pageRepo.updatePage(
|
await this.pageRepo.updatePage(
|
||||||
{
|
{
|
||||||
title: updatePageDto.title,
|
title: updatePageDto.title,
|
||||||
icon: updatePageDto.icon,
|
icon: updatePageDto.icon,
|
||||||
lastUpdatedById: userId,
|
lastUpdatedById: user.id,
|
||||||
updatedAt: new Date(),
|
updatedAt: new Date(),
|
||||||
contributorIds: contributorIds,
|
contributorIds: contributorIds,
|
||||||
},
|
},
|
||||||
@@ -224,7 +220,7 @@ export class PageService {
|
|||||||
updatePageDto.content,
|
updatePageDto.content,
|
||||||
updatePageDto.operation,
|
updatePageDto.operation,
|
||||||
updatePageDto.input,
|
updatePageDto.input,
|
||||||
userId,
|
user,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -242,7 +238,7 @@ export class PageService {
|
|||||||
content: string | object,
|
content: string | object,
|
||||||
operation: ContentOperation,
|
operation: ContentOperation,
|
||||||
input: InputFormat,
|
input: InputFormat,
|
||||||
userId: string,
|
user: User,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
let prosemirrorJson: any;
|
let prosemirrorJson: any;
|
||||||
|
|
||||||
@@ -270,35 +266,11 @@ export class PageService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const documentName = `page.${pageId}`;
|
const documentName = `page.${pageId}`;
|
||||||
const connection = await this.collaborationGateway.openDirectConnection(
|
await this.collaborationGateway.handleYjsEvent(
|
||||||
|
'updatePageContent',
|
||||||
documentName,
|
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(
|
async getSidebarPages(
|
||||||
@@ -334,7 +306,11 @@ export class PageService {
|
|||||||
cursor: pagination.cursor,
|
cursor: pagination.cursor,
|
||||||
beforeCursor: pagination.beforeCursor,
|
beforeCursor: pagination.beforeCursor,
|
||||||
fields: [
|
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' },
|
{ expression: 'id', direction: 'asc' },
|
||||||
],
|
],
|
||||||
parseCursor: (cursor) => ({
|
parseCursor: (cursor) => ({
|
||||||
|
|||||||
Reference in New Issue
Block a user