Skip to content

Commit adb8118

Browse files
committed
Merge remote-tracking branch 'upstream/main'
2 parents 0f9bfc7 + 895c181 commit adb8118

12 files changed

Lines changed: 593 additions & 488 deletions

File tree

apps/client/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "client",
33
"private": true,
4-
"version": "0.71.0",
4+
"version": "0.71.1",
55
"scripts": {
66
"dev": "vite",
77
"build": "tsc && vite build",

apps/client/public/locales/en-US/translation.json

Lines changed: 259 additions & 259 deletions
Large diffs are not rendered by default.

apps/client/src/features/comment/queries/comment-query.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,11 @@ export function useCreateCommentMutation() {
6565
) as InfiniteData<IPagination<IComment>> | undefined;
6666

6767
if (cache && cache.pages.length > 0) {
68+
const alreadyExists = cache.pages.some((page) =>
69+
page.items.some((c) => c.id === newComment.id),
70+
);
71+
if (alreadyExists) return;
72+
6873
const lastIdx = cache.pages.length - 1;
6974
queryClient.setQueryData(RQ_KEY(newComment.pageId), {
7075
...cache,

apps/client/src/features/editor/extensions/extensions.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,25 @@ export const mainExtensions = [
142142
}),
143143
];
144144
},
145+
addKeyboardShortcuts() {
146+
return {
147+
Enter: ({ editor }) => {
148+
const { from, to } = editor.state.selection;
149+
if (from !== to) return false;
150+
if (!editor.isActive("code")) return false;
151+
152+
const $from = editor.state.doc.resolve(from);
153+
const codeType = editor.state.schema.marks.code;
154+
const nodeAfter = $from.nodeAfter;
155+
156+
if (nodeAfter && codeType.isInSet(nodeAfter.marks)) {
157+
return false;
158+
}
159+
160+
return editor.chain().unsetCode().splitBlock().run();
161+
},
162+
};
163+
},
145164
}),
146165
SharedStorage,
147166
Heading,

apps/server/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "server",
3-
"version": "0.71.0",
3+
"version": "0.71.1",
44
"description": "",
55
"author": "",
66
"private": true,

apps/server/src/collaboration/processors/history.processor.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
import {
1212
extractMentions,
1313
extractPageMentions,
14+
extractInternalLinkSlugIds,
1415
} from '../../common/helpers/prosemirror/utils';
1516
import { PageHistoryRepo } from '@docmost/db/repos/page/page-history.repo';
1617
import { PageRepo } from '@docmost/db/repos/page/page.repo';
@@ -77,12 +78,14 @@ export class HistoryProcessor extends WorkerHost implements OnModuleDestroy {
7778

7879
const mentions = extractMentions(page.content);
7980
const pageMentions = extractPageMentions(mentions);
81+
const internalLinkSlugIds = extractInternalLinkSlugIds(page.content);
8082

8183
await this.generalQueue
8284
.add(QueueJob.PAGE_BACKLINKS, {
8385
pageId,
8486
workspaceId: page.workspaceId,
8587
mentions: pageMentions,
88+
internalLinkSlugIds,
8689
} as IPageBacklinkJob)
8790
.catch((err) => {
8891
this.logger.error(

apps/server/src/common/helpers/prosemirror/utils.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ import { validate as isValidUUID } from 'uuid';
77
import { Transform } from '@tiptap/pm/transform';
88
import { TiptapTransformer } from '@hocuspocus/transformer';
99
import * as Y from 'yjs';
10+
import {
11+
INTERNAL_LINK_REGEX,
12+
extractPageSlugId,
13+
} from '../../../integrations/export/utils';
1014

1115
export interface MentionNode {
1216
id: string;
@@ -64,6 +68,27 @@ export function extractPageMentions(mentionList: MentionNode[]): MentionNode[] {
6468
return pageMentionList as MentionNode[];
6569
}
6670

71+
export function extractInternalLinkSlugIds(prosemirrorJson: any): string[] {
72+
const slugIds: string[] = [];
73+
const doc = jsonToNode(prosemirrorJson);
74+
75+
doc.descendants((node: Node) => {
76+
for (const mark of node.marks) {
77+
if (mark.type.name === 'link' && mark.attrs.internal && mark.attrs.href) {
78+
const match = mark.attrs.href.match(INTERNAL_LINK_REGEX);
79+
if (match) {
80+
const slugId = extractPageSlugId(match[5]);
81+
if (slugId && !slugIds.includes(slugId)) {
82+
slugIds.push(slugId);
83+
}
84+
}
85+
}
86+
}
87+
});
88+
89+
return slugIds;
90+
}
91+
6792
export function extractUserMentionIdsFromJson(json: any): string[] {
6893
const userIds: string[] = [];
6994

apps/server/src/core/page/services/page.service.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ import { QueueJob, QueueName } from '../../../integrations/queue/constants';
4747
import { EventName } from '../../../common/events/event.contants';
4848
import { EventEmitter2 } from '@nestjs/event-emitter';
4949
import { CollaborationGateway } from '../../../collaboration/collaboration.gateway';
50+
import {
51+
INTERNAL_LINK_REGEX,
52+
extractPageSlugId,
53+
} from '../../../integrations/export/utils';
5054
import { markdownToHtml } from '@docmost/editor-ext';
5155
import { WatcherService } from '../../watcher/watcher.service';
5256
import { sql } from 'kysely';
@@ -510,6 +514,11 @@ export class PageService {
510514
});
511515
});
512516

517+
const slugIdMap = new Map<string, CopyPageMapEntry>();
518+
for (const [, entry] of pageMap) {
519+
slugIdMap.set(entry.oldSlugId, entry);
520+
}
521+
513522
const attachmentMap = new Map<string, ICopyPageAttachment>();
514523

515524
const insertablePages: InsertablePage[] = await Promise.all(
@@ -576,6 +585,28 @@ export class PageService {
576585
node.attrs.slugId = mappedPage.newSlugId;
577586
}
578587
}
588+
589+
// Update internal page links in link marks
590+
for (const mark of node.marks) {
591+
if (
592+
mark.type.name === 'link' &&
593+
mark.attrs.internal &&
594+
mark.attrs.href
595+
) {
596+
const match = mark.attrs.href.match(INTERNAL_LINK_REGEX);
597+
if (match) {
598+
const slugId = extractPageSlugId(match[5]);
599+
if (slugId && slugIdMap.has(slugId)) {
600+
const mappedPage = slugIdMap.get(slugId);
601+
//@ts-ignore
602+
mark.attrs.href = mark.attrs.href.replace(
603+
slugId,
604+
mappedPage.newSlugId,
605+
);
606+
}
607+
}
608+
}
609+
}
579610
});
580611

581612
const prosemirrorJson = prosemirrorDoc.toJSON();

apps/server/src/integrations/queue/constants/queue.interface.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ export interface IPageBacklinkJob {
44
pageId: string;
55
workspaceId: string;
66
mentions: MentionNode[];
7+
internalLinkSlugIds?: string[];
78
}
89

910
export interface IAddPageWatchersJob {

apps/server/src/integrations/queue/tasks/backlinks.task.ts

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ export async function processBacklinks(
1111
backlinkRepo: BacklinkRepo,
1212
data: IPageBacklinkJob,
1313
): Promise<void> {
14-
const { pageId, mentions, workspaceId } = data;
14+
const { pageId, mentions, workspaceId, internalLinkSlugIds = [] } = data;
1515

1616
await executeTx(db, async (trx) => {
1717
const existingBacklinks = await trx
@@ -20,24 +20,41 @@ export async function processBacklinks(
2020
.where('sourcePageId', '=', pageId)
2121
.execute();
2222

23-
if (existingBacklinks.length === 0 && mentions.length === 0) {
23+
const mentionTargetPageIds = mentions
24+
.filter((mention) => mention.entityId !== pageId)
25+
.map((mention) => mention.entityId);
26+
27+
let resolvedLinkPageIds: string[] = [];
28+
if (internalLinkSlugIds.length > 0) {
29+
const resolvedPages = await trx
30+
.selectFrom('pages')
31+
.select('id')
32+
.where('slugId', 'in', internalLinkSlugIds)
33+
.where('workspaceId', '=', workspaceId)
34+
.execute();
35+
resolvedLinkPageIds = resolvedPages
36+
.map((p) => p.id)
37+
.filter((id) => id !== pageId);
38+
}
39+
40+
const allTargetPageIds = [
41+
...new Set([...mentionTargetPageIds, ...resolvedLinkPageIds]),
42+
];
43+
44+
if (existingBacklinks.length === 0 && allTargetPageIds.length === 0) {
2445
return;
2546
}
2647

2748
const existingTargetPageIds = existingBacklinks.map(
2849
(backlink) => backlink.targetPageId,
2950
);
3051

31-
const targetPageIds = mentions
32-
.filter((mention) => mention.entityId !== pageId)
33-
.map((mention) => mention.entityId);
34-
3552
let validTargetPages = [];
36-
if (targetPageIds.length > 0) {
53+
if (allTargetPageIds.length > 0) {
3754
validTargetPages = await trx
3855
.selectFrom('pages')
3956
.select('id')
40-
.where('id', 'in', targetPageIds)
57+
.where('id', 'in', allTargetPageIds)
4158
.where('workspaceId', '=', workspaceId)
4259
.execute();
4360
}

0 commit comments

Comments
 (0)