diff --git a/package.json b/package.json
index 934e386dc..a8e1d69a1 100644
--- a/package.json
+++ b/package.json
@@ -56,7 +56,7 @@
"jimp": "0.16.1",
"joplin-turndown-plugin-gfm": "1.0.12",
"jsdom": "16.6.0",
- "mime-types": "2.1.30",
+ "mime-types": "2.1.31",
"multer": "1.4.2",
"node-abi": "2.30.0",
"open": "8.2.0",
@@ -89,7 +89,7 @@
"jsdoc": "3.6.7",
"lorem-ipsum": "2.0.3",
"rcedit": "3.0.0",
- "webpack": "5.37.1",
+ "webpack": "5.38.1",
"webpack-cli": "4.7.0"
},
"optionalDependencies": {
diff --git a/src/public/app/widgets/containers/collapsible_section_container.js b/src/public/app/widgets/containers/collapsible_section_container.js
index d47436630..47b5f40bc 100644
--- a/src/public/app/widgets/containers/collapsible_section_container.js
+++ b/src/public/app/widgets/containers/collapsible_section_container.js
@@ -175,6 +175,8 @@ export default class CollapsibleSectionContainer extends NoteContextAwareWidget
}
async refreshWithNote(note, noExplicitActivation = false) {
+ this.lastNoteType = note.type;
+
let $sectionToActivate, $lastActiveSection;
this.$titleContainer.empty();
diff --git a/src/public/app/widgets/section_widgets/link_map.js b/src/public/app/widgets/section_widgets/link_map.js
index 08bc59ac9..51a037d21 100644
--- a/src/public/app/widgets/section_widgets/link_map.js
+++ b/src/public/app/widgets/section_widgets/link_map.js
@@ -2,6 +2,7 @@ import NoteContextAwareWidget from "../note_context_aware_widget.js";
import froca from "../../services/froca.js";
import libraryLoader from "../../services/library_loader.js";
import server from "../../services/server.js";
+import appContext from "../../services/app_context.js";
const TPL = `
@@ -117,6 +118,9 @@ export default class LinkMapWidget extends NoteContextAwareWidget {
}
async refreshWithNote(note) {
+ this.linkIdToLinkMap = {};
+ this.noteIdToLinkCountMap = {};
+
this.$container.empty();
await libraryLoader.requireLibrary(libraryLoader.FORCE_GRAPH);
@@ -153,7 +157,7 @@ export default class LinkMapWidget extends NoteContextAwareWidget {
this.graph.d3Force('charge').strength(-30);
this.graph.d3Force('charge').distanceMax(400);
- this.renderData(await this.loadNotesAndRelations());
+ this.renderData(await this.loadNotesAndRelations(this.noteId,1));
}
renderData(data, zoomToFit = true, zoomPadding = 10) {
@@ -164,61 +168,72 @@ export default class LinkMapWidget extends NoteContextAwareWidget {
}
}
- centerOnNode(node) {
- this.nodeClicked(node);
-
- this.graph.centerAt(node.x, node.y, 1000);
- this.graph.zoom(6, 2000);
- }
-
async nodeClicked(node) {
if (!node.expanded) {
- const neighborGraph = await fetchNeighborGraph(node.id);
-
- addToTasGraph(neighborGraph);
-
- renderData(getTasGraph(), false);
+ this.renderData(
+ await this.loadNotesAndRelations(node.id,1),
+ false
+ );
+ }
+ else {
+ await appContext.tabManager.getActiveContext().setNote(node.id);
}
}
- async loadNotesAndRelations(options = {}) {
- const {noteIdToLinkCountMap, links} = await server.post(`notes/${this.note.noteId}/link-map`, {
- maxNotes: 30,
- maxDepth: 1
+ async loadNotesAndRelations(noteId, maxDepth) {
+ const resp = await server.post(`notes/${noteId}/link-map`, {
+ maxNotes: 1000,
+ maxDepth
});
- // preload all notes
- const notes = await froca.getNotes(Object.keys(noteIdToLinkCountMap), true);
+ this.noteIdToLinkCountMap = {...this.noteIdToLinkCountMap, ...resp.noteIdToLinkCountMap};
- const noteIdToLinkMap = {};
-
- for (const link of links) {
- noteIdToLinkMap[link.sourceNoteId] = noteIdToLinkMap[link.sourceNoteId] || [];
- noteIdToLinkMap[link.sourceNoteId].push(link);
-
- noteIdToLinkMap[link.targetNoteId] = noteIdToLinkMap[link.targetNoteId] || [];
- noteIdToLinkMap[link.targetNoteId].push(link);
+ for (const link of resp.links) {
+ this.linkIdToLinkMap[link.id] = link;
}
- console.log(notes.map(note => ({
- id: note.noteId,
- name: note.title,
- type: note.type,
- expanded: noteIdToLinkCountMap[note.noteId] === noteIdToLinkMap[note.noteId].length
- })))
+ // preload all notes
+ const notes = await froca.getNotes(Object.keys(this.noteIdToLinkCountMap), true);
+
+ const noteIdToLinkIdMap = {};
+ const linksGroupedBySourceTarget = {};
+
+ for (const link of Object.values(this.linkIdToLinkMap)) {
+ noteIdToLinkIdMap[link.sourceNoteId] = noteIdToLinkIdMap[link.sourceNoteId] || new Set();
+ noteIdToLinkIdMap[link.sourceNoteId].add(link.id);
+
+ noteIdToLinkIdMap[link.targetNoteId] = noteIdToLinkIdMap[link.targetNoteId] || new Set();
+ noteIdToLinkIdMap[link.targetNoteId].add(link.id);
+
+ const key = `${link.sourceNoteId}-${link.targetNoteId}`;
+
+ if (key in linksGroupedBySourceTarget) {
+ if (!linksGroupedBySourceTarget[key].names.includes(link.name)) {
+ linksGroupedBySourceTarget[key].names.push(link.name);
+ }
+ }
+ else {
+ linksGroupedBySourceTarget[key] = {
+ id: key,
+ sourceNoteId: link.sourceNoteId,
+ targetNoteId: link.targetNoteId,
+ names: [link.name]
+ }
+ }
+ }
return {
nodes: notes.map(note => ({
id: note.noteId,
name: note.title,
type: note.type,
- expanded: noteIdToLinkCountMap[note.noteId] === noteIdToLinkMap[note.noteId].length
+ expanded: this.noteIdToLinkCountMap[note.noteId] === noteIdToLinkIdMap[note.noteId].size
})),
- links: links.map(link => ({
- id: link.sourceNoteId + "-" + link.name + "-" + link.targetNoteId,
+ links: Object.values(linksGroupedBySourceTarget).map(link => ({
+ id: link.id,
source: link.sourceNoteId,
target: link.targetNoteId,
- name: link.name
+ name: link.names.join(", ")
}))
};
}
@@ -260,9 +275,9 @@ export default class LinkMapWidget extends NoteContextAwareWidget {
paintNode(node, color, ctx) {
const {x, y} = node;
- ctx.fillStyle = color;
+ ctx.fillStyle = node.id === this.noteId ? 'red' : color;
ctx.beginPath();
- ctx.arc(x, y, 4, 0, 2 * Math.PI, false);
+ ctx.arc(x, y, node.id === this.noteId ? 8 : 4, 0, 2 * Math.PI, false);
ctx.fill();
if (this.zoomLevel < 2) {
@@ -288,7 +303,7 @@ export default class LinkMapWidget extends NoteContextAwareWidget {
title = title.substr(0, 15) + "...";
}
- ctx.fillText(title, x, y + 7);
+ ctx.fillText(title, x, y + (node.id === this.noteId ? 11 : 7));
}
stringToColor(str) {
@@ -306,21 +321,7 @@ export default class LinkMapWidget extends NoteContextAwareWidget {
entitiesReloadedEvent({loadResults}) {
if (loadResults.getAttributes().find(attr => attr.type === 'relation' && (attr.noteId === this.noteId || attr.value === this.noteId))) {
- this.noteSwitched();
- }
-
- const changedNoteIds = loadResults.getNoteIds();
-
- if (changedNoteIds.length > 0) {
- const $linkMapContainer = this.$widget.find('.link-map-container');
-
- for (const noteId of changedNoteIds) {
- const note = froca.notes[noteId];
-
- if (note) {
- $linkMapContainer.find(`a[data-note-path="${noteId}"]`).text(note.title);
- }
- }
+ this.refresh();
}
}
}
diff --git a/src/routes/api/link_map.js b/src/routes/api/link_map.js
index 94331c879..f6cf85037 100644
--- a/src/routes/api/link_map.js
+++ b/src/routes/api/link_map.js
@@ -40,9 +40,9 @@ function collectRelations(noteId, relations, depth) {
relations.add(relation);
if (relation.noteId !== noteId) {
- collectRelations(relation.noteId, relations, depth--);
+ collectRelations(relation.noteId, relations, depth - 1);
} else if (relation.value !== noteId) {
- collectRelations(relation.value, relations, depth--);
+ collectRelations(relation.value, relations, depth - 1);
}
}
}
@@ -71,6 +71,7 @@ function getLinkMap(req) {
return {
noteIdToLinkCountMap,
links: Array.from(relations).map(rel => ({
+ id: rel.noteId + "-" + rel.name + "-" + rel.value,
sourceNoteId: rel.noteId,
targetNoteId: rel.value,
name: rel.name