mirror of
https://github.com/docmost/docmost.git
synced 2025-11-17 15:21:09 +10:00
feat: internal page links and mentions (#604)
* Work on mentions * fix: properly parse page slug * fix editor suggestion bugs * mentions must start with whitespace * add icon to page mention render * feat: backlinks - WIP * UI - WIP * permissions check * use FTS for page suggestion * cleanup * WIP * page title fallback * feat: handle internal link paste * link styling * WIP * Switch back to LIKE operator for search suggestion * WIP * scope to workspaceId * still create link for pages not found * select necessary columns * cleanups
This commit is contained in:
@ -12,6 +12,16 @@ import { InjectKysely } from 'nestjs-kysely';
|
||||
import { KyselyDB } from '@docmost/db/types/kysely.types';
|
||||
import { executeTx } from '@docmost/db/utils';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { InjectQueue } from '@nestjs/bullmq';
|
||||
import { QueueJob, QueueName } from '../../integrations/queue/constants';
|
||||
import { Queue } from 'bullmq';
|
||||
import {
|
||||
extractMentions,
|
||||
extractPageMentions,
|
||||
} from '../../common/helpers/prosemirror/utils';
|
||||
import { isDeepStrictEqual } from 'node:util';
|
||||
import { IPageBacklinkJob } from '../../integrations/queue/constants/queue.interface';
|
||||
import { Page } from '@docmost/db/types/entity.types';
|
||||
|
||||
@Injectable()
|
||||
export class PersistenceExtension implements Extension {
|
||||
@ -21,6 +31,7 @@ export class PersistenceExtension implements Extension {
|
||||
private readonly pageRepo: PageRepo,
|
||||
@InjectKysely() private readonly db: KyselyDB,
|
||||
private eventEmitter: EventEmitter2,
|
||||
@InjectQueue(QueueName.GENERAL_QUEUE) private generalQueue: Queue,
|
||||
) {}
|
||||
|
||||
async onLoadDocument(data: onLoadDocumentPayload) {
|
||||
@ -85,12 +96,13 @@ export class PersistenceExtension implements Extension {
|
||||
this.logger.warn('jsonToText' + err?.['message']);
|
||||
}
|
||||
|
||||
try {
|
||||
let page = null;
|
||||
let page: Page = null;
|
||||
|
||||
try {
|
||||
await executeTx(this.db, async (trx) => {
|
||||
page = await this.pageRepo.findById(pageId, {
|
||||
withLock: true,
|
||||
includeContent: true,
|
||||
trx,
|
||||
});
|
||||
|
||||
@ -99,6 +111,11 @@ export class PersistenceExtension implements Extension {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isDeepStrictEqual(tiptapJson, page.content)) {
|
||||
page = null;
|
||||
return;
|
||||
}
|
||||
|
||||
await this.pageRepo.updatePage(
|
||||
{
|
||||
content: tiptapJson,
|
||||
@ -109,18 +126,30 @@ export class PersistenceExtension implements Extension {
|
||||
pageId,
|
||||
trx,
|
||||
);
|
||||
});
|
||||
|
||||
this.eventEmitter.emit('collab.page.updated', {
|
||||
page: {
|
||||
...page,
|
||||
lastUpdatedById: context.user.id,
|
||||
content: tiptapJson,
|
||||
textContent: textContent,
|
||||
},
|
||||
this.logger.debug(`Page updated: ${pageId} - SlugId: ${page.slugId}`);
|
||||
});
|
||||
} catch (err) {
|
||||
this.logger.error(`Failed to update page ${pageId}`, err);
|
||||
}
|
||||
|
||||
if (page) {
|
||||
this.eventEmitter.emit('collab.page.updated', {
|
||||
page: {
|
||||
...page,
|
||||
content: tiptapJson,
|
||||
lastUpdatedById: context.user.id,
|
||||
},
|
||||
});
|
||||
|
||||
const mentions = extractMentions(tiptapJson);
|
||||
const pageMentions = extractPageMentions(mentions);
|
||||
|
||||
await this.generalQueue.add(QueueJob.PAGE_BACKLINKS, {
|
||||
pageId: pageId,
|
||||
workspaceId: page.workspaceId,
|
||||
mentions: pageMentions,
|
||||
} as IPageBacklinkJob);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user