From 9d99da14e1a70e022097447e88a80b251fbdd38d Mon Sep 17 00:00:00 2001 From: Kieran Date: Fri, 27 Jun 2025 20:15:59 +0100 Subject: [PATCH] feat(map): add `mapIncludeRelation` and `mapExcludeRelation` to include only or exclude specific relation types --- apps/client/src/widgets/note_map.ts | 14 +++++++++++--- apps/server/src/routes/api/note_map.ts | 9 +++++++++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/apps/client/src/widgets/note_map.ts b/apps/client/src/widgets/note_map.ts index d7fb10af4..d0274fc86 100644 --- a/apps/client/src/widgets/note_map.ts +++ b/apps/client/src/widgets/note_map.ts @@ -324,7 +324,13 @@ export default class NoteMapWidget extends NoteContextAwareWidget { } const mapRootNoteId = this.getMapRootNoteId(); - const data = await this.loadNotesAndRelations(mapRootNoteId); + + const labelValues = (name: string) => this.note?.getLabels(name).map(l => l.value) ?? []; + + const excludeRelations = labelValues("mapExcludeRelation"); + const includeRelations = labelValues("mapIncludeRelation"); + + const data = await this.loadNotesAndRelations(mapRootNoteId, excludeRelations, includeRelations); const nodeLinkRatio = data.nodes.length / data.links.length; const magnifiedRatio = Math.pow(nodeLinkRatio, 1.5); @@ -473,8 +479,10 @@ export default class NoteMapWidget extends NoteContextAwareWidget { ctx.restore(); } - async loadNotesAndRelations(mapRootNoteId: string): Promise { - const resp = await server.post(`note-map/${mapRootNoteId}/${this.mapType}`); + async loadNotesAndRelations(mapRootNoteId: string, excludeRelations: string[], includeRelations: string[]): Promise { + const resp = await server.post(`note-map/${mapRootNoteId}/${this.mapType}`, { + excludeRelations, includeRelations + }); this.calculateNodeSizes(resp); diff --git a/apps/server/src/routes/api/note_map.ts b/apps/server/src/routes/api/note_map.ts index 470152bd6..b77c634c2 100644 --- a/apps/server/src/routes/api/note_map.ts +++ b/apps/server/src/routes/api/note_map.ts @@ -110,6 +110,11 @@ function getLinkMap(req: Request) { const ignoreExcludeFromNoteMap = mapRootNote.isLabelTruthy("excludeFromNoteMap"); let unfilteredNotes; + const toSet = (data: unknown) => new Set(data instanceof Array ? data : []); + + const excludeRelations = toSet(req.body.excludeRelations); + const includeRelations = toSet(req.body.includeRelations); + if (mapRootNote.type === "search") { // for search notes, we want to consider the direct search results only without the descendants unfilteredNotes = mapRootNote.getSearchResultNotes(); @@ -152,6 +157,10 @@ function getLinkMap(req: Request) { } return !parentNote.getChildNotes().find((childNote) => childNote.noteId === rel.value); + } else if (includeRelations.size != 0 && !includeRelations.has(rel.name)) { + return false; + } else if (excludeRelations.has(rel.name)) { + return false; } else { return true; }