mirror of
https://github.com/zadam/trilium.git
synced 2025-11-14 01:05:49 +01:00
display mirror relations correctly on relation map
This commit is contained in:
@@ -7,7 +7,9 @@ const repository = require('../services/repository');
|
||||
const dateUtils = require('../services/date_utils');
|
||||
|
||||
const LABEL = 'label';
|
||||
const LABEL_DEFINITION = 'label-definition';
|
||||
const RELATION = 'relation';
|
||||
const RELATION_DEFINITION = 'relation-definition';
|
||||
|
||||
/**
|
||||
* This represents a Note which is a central object in the Trilium Notes project.
|
||||
@@ -136,6 +138,14 @@ class Note extends Entity {
|
||||
return (await this.getAttributes(name)).filter(attr => attr.type === LABEL);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} [name] - label name to filter
|
||||
* @returns {Promise<Attribute[]>} all note's label definitions, including inherited ones
|
||||
*/
|
||||
async getLabelDefinitions(name) {
|
||||
return (await this.getAttributes(name)).filter(attr => attr.type === LABEL_DEFINITION);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} [name] - relation name to filter
|
||||
* @returns {Promise<Attribute[]>} all note's relations (attributes with type relation), including inherited ones
|
||||
@@ -144,6 +154,14 @@ class Note extends Entity {
|
||||
return (await this.getAttributes(name)).filter(attr => attr.type === RELATION);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} [name] - relation name to filter
|
||||
* @returns {Promise<Attribute[]>} all note's relation definitions including inherited ones
|
||||
*/
|
||||
async getRelationDefinitions(name) {
|
||||
return (await this.getAttributes(name)).filter(attr => attr.type === RELATION_DEFINITION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear note's attributes cache to force fresh reload for next attribute request.
|
||||
* Cache is note instance scoped.
|
||||
|
||||
@@ -24,7 +24,7 @@ function initAttributeNameAutocomplete({ $el, attributeType, open }) {
|
||||
});
|
||||
|
||||
if (result.length === 0) {
|
||||
result.push({name: "No results"})
|
||||
result.push({name: "No results"});
|
||||
}
|
||||
|
||||
cb(result);
|
||||
|
||||
@@ -48,6 +48,25 @@ const biDirectionalOverlays = [
|
||||
} ]
|
||||
];
|
||||
|
||||
const mirrorOverlays = [
|
||||
[ "Arrow", {
|
||||
location: 1,
|
||||
id: "arrow",
|
||||
length: 14,
|
||||
foldback: 0.8
|
||||
} ],
|
||||
[ "Label", { label: "", location: 0.2, id: "label-source", cssClass: "connection-label" }],
|
||||
[ "Label", { label: "", location: 0.8, id: "label-target", cssClass: "connection-label" }],
|
||||
[ "Arrow", {
|
||||
location: 0,
|
||||
id: "arrow2",
|
||||
length: 14,
|
||||
direction: -1,
|
||||
foldback: 0.8
|
||||
} ]
|
||||
];
|
||||
|
||||
|
||||
function loadMapData() {
|
||||
const currentNote = noteDetailService.getCurrentNote();
|
||||
mapData = {
|
||||
@@ -88,12 +107,12 @@ async function loadNotesAndRelations() {
|
||||
|
||||
for (const relation of data.relations) {
|
||||
const match = relations.find(rel =>
|
||||
rel.name === relation.name
|
||||
rel.name === data.mirrorRelations[relation.name]
|
||||
&& ((rel.sourceNoteId === relation.sourceNoteId && rel.targetNoteId === relation.targetNoteId)
|
||||
|| (rel.sourceNoteId === relation.targetNoteId && rel.targetNoteId === relation.sourceNoteId)));
|
||||
|
||||
if (match) {
|
||||
match.type = relation.type = 'biDirectional';
|
||||
match.type = relation.type = relation.name === data.mirrorRelations[relation.name] ? 'biDirectional' : 'mirror';
|
||||
relation.render = false; // don't render second relation
|
||||
} else {
|
||||
relation.type = 'uniDirectional';
|
||||
@@ -128,7 +147,15 @@ async function loadNotesAndRelations() {
|
||||
});
|
||||
|
||||
connection.id = relation.attributeId;
|
||||
connection.getOverlay("label").setLabel(relation.name);
|
||||
|
||||
if (relation.type === 'mirror') {
|
||||
connection.getOverlay("label-source").setLabel(relation.name);
|
||||
connection.getOverlay("label-target").setLabel(data.mirrorRelations[relation.name]);
|
||||
}
|
||||
else {
|
||||
connection.getOverlay("label").setLabel(relation.name);
|
||||
}
|
||||
|
||||
connection.canvas.setAttribute("data-connection-id", connection.id);
|
||||
}
|
||||
});
|
||||
@@ -222,6 +249,8 @@ function initJsPlumbInstance () {
|
||||
|
||||
jsPlumbInstance.registerConnectionType("biDirectional", { anchor:"Continuous", connector:"StateMachine", overlays: biDirectionalOverlays });
|
||||
|
||||
jsPlumbInstance.registerConnectionType("mirror", { anchor:"Continuous", connector:"StateMachine", overlays: mirrorOverlays });
|
||||
|
||||
jsPlumbInstance.bind("connection", connectionCreatedHandler);
|
||||
|
||||
// so that canvas is not panned when clicking/dragging note box
|
||||
@@ -330,7 +359,7 @@ async function noteContextMenuHandler(event, cmd) {
|
||||
}
|
||||
else if (cmd === "edit-title") {
|
||||
const $title = $noteBox.find(".title a");
|
||||
const title = await promptDialog.ask("Enter new note title:", $title.text());
|
||||
const title = await promptDialog.ask({ message: "Enter new note title:", defaultValue: $title.text() });
|
||||
|
||||
if (!title) {
|
||||
return;
|
||||
|
||||
@@ -95,8 +95,11 @@ async function setNoteTypeMime(req) {
|
||||
async function getRelationMap(req) {
|
||||
const noteIds = req.body.noteIds;
|
||||
const resp = {
|
||||
// noteId => title
|
||||
noteTitles: {},
|
||||
relations: []
|
||||
relations: [],
|
||||
// relation name => mirror relation name
|
||||
mirrorRelations: {}
|
||||
};
|
||||
|
||||
if (noteIds.length === 0) {
|
||||
@@ -105,19 +108,26 @@ async function getRelationMap(req) {
|
||||
|
||||
const questionMarks = noteIds.map(noteId => '?').join(',');
|
||||
|
||||
(await repository.getEntities(`SELECT * FROM notes WHERE isDeleted = 0 AND noteId IN (${questionMarks})`, noteIds))
|
||||
.forEach(note => resp.noteTitles[note.noteId] = note.title);
|
||||
const notes = await repository.getEntities(`SELECT * FROM notes WHERE isDeleted = 0 AND noteId IN (${questionMarks})`, noteIds);
|
||||
|
||||
// FIXME: this actually doesn't take into account inherited relations! But maybe it is better this way?
|
||||
resp.relations = (await repository.getEntities(`SELECT * FROM attributes WHERE isDeleted = 0 AND type = 'relation' AND noteId IN (${questionMarks})`, noteIds))
|
||||
.map(relation => { return {
|
||||
attributeId: relation.attributeId,
|
||||
sourceNoteId: relation.noteId,
|
||||
targetNoteId: relation.value,
|
||||
name: relation.name
|
||||
}; })
|
||||
// both sourceNoteId and targetNoteId has to be in the included notes, but source was already checked in the SQL query
|
||||
.filter(relation => noteIds.includes(relation.targetNoteId));
|
||||
for (const note of notes) {
|
||||
resp.noteTitles[note.noteId] = note.title;
|
||||
|
||||
resp.relations = resp.relations.concat((await note.getRelations())
|
||||
.filter(relation => noteIds.includes(relation.value))
|
||||
.map(relation => { return {
|
||||
attributeId: relation.attributeId,
|
||||
sourceNoteId: relation.noteId,
|
||||
targetNoteId: relation.value,
|
||||
name: relation.name
|
||||
}; }));
|
||||
|
||||
for (const relationDefinition of await note.getRelationDefinitions()) {
|
||||
if (relationDefinition.value.mirrorRelation) {
|
||||
resp.mirrorRelations[relationDefinition.name] = relationDefinition.value.mirrorRelation;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return resp;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user