mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 10:26:08 +01:00 
			
		
		
		
	fixes for relation handling + visual design restyled into gray colors
This commit is contained in:
		| @@ -42,8 +42,7 @@ const biDirectionalOverlays = [ | |||||||
| function loadMapData() { | function loadMapData() { | ||||||
|     const currentNote = noteDetailService.getCurrentNote(); |     const currentNote = noteDetailService.getCurrentNote(); | ||||||
|     mapData = { |     mapData = { | ||||||
|         notes: [], |         notes: [] | ||||||
|         relations: [] |  | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     if (currentNote.content) { |     if (currentNote.content) { | ||||||
| @@ -115,7 +114,7 @@ async function loadNotesAndRelations() { | |||||||
|             } |             } | ||||||
|  |  | ||||||
|             const connection = instance.connect({ |             const connection = instance.connect({ | ||||||
|                 id: `${relation.sourceNoteId}${relation.targetNoteId}`, |                 id: relation.attributeIds, | ||||||
|                 source: relation.sourceNoteId, |                 source: relation.sourceNoteId, | ||||||
|                 target: relation.targetNoteId, |                 target: relation.targetNoteId, | ||||||
|                 type: relation.type |                 type: relation.type | ||||||
| @@ -155,8 +154,8 @@ function initPanZoom() { | |||||||
| async function initJsPlumb () { | async function initJsPlumb () { | ||||||
|     instance = jsPlumb.getInstance({ |     instance = jsPlumb.getInstance({ | ||||||
|         Endpoint: ["Dot", {radius: 2}], |         Endpoint: ["Dot", {radius: 2}], | ||||||
|         Connector: "StateMachine", |         Connector: "Straight", | ||||||
|         HoverPaintStyle: {stroke: "#1e8151", strokeWidth: 2 }, |         HoverPaintStyle: {stroke: "#777", strokeWidth: 1 }, | ||||||
|         Container: "relation-map-canvas" |         Container: "relation-map-canvas" | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
| @@ -181,8 +180,7 @@ async function initJsPlumb () { | |||||||
|         delegate: ".connection-label,.jtk-connector", |         delegate: ".connection-label,.jtk-connector", | ||||||
|         autoTrigger: false, // it doesn't open automatically, needs to be triggered explicitly by .open() call |         autoTrigger: false, // it doesn't open automatically, needs to be triggered explicitly by .open() call | ||||||
|         menu: [ |         menu: [ | ||||||
|             {title: "Remove relation", cmd: "remove", uiIcon: "ui-icon-trash"}, |             {title: "Remove relation", cmd: "remove", uiIcon: "ui-icon-trash"} | ||||||
|             {title: "Edit relation name", cmd: "edit-name", uiIcon: "ui-icon-pencil"}, |  | ||||||
|         ], |         ], | ||||||
|         select: relationContextMenuHandler |         select: relationContextMenuHandler | ||||||
|     }); |     }); | ||||||
| @@ -222,12 +220,12 @@ async function connectionCreatedHandler(info, originalEvent) { | |||||||
|     const targetNoteId = connection.target.id; |     const targetNoteId = connection.target.id; | ||||||
|     const sourceNoteId = connection.source.id; |     const sourceNoteId = connection.source.id; | ||||||
|  |  | ||||||
|     const existing = relations.some(rel => |     const relationExists = relations.some(rel => | ||||||
|         rel.targetNoteId === targetNoteId |         rel.targetNoteId === targetNoteId | ||||||
|         && rel.sourceNoteId === sourceNoteId |         && rel.sourceNoteId === sourceNoteId | ||||||
|         && rel.name === name); |         && rel.name === name); | ||||||
|  |  | ||||||
|     if (existing) { |     if (relationExists) { | ||||||
|         alert("Connection '" + name + "' between these notes already exists."); |         alert("Connection '" + name + "' between these notes already exists."); | ||||||
|  |  | ||||||
|         instance.deleteConnection(connection); |         instance.deleteConnection(connection); | ||||||
| @@ -235,15 +233,15 @@ async function connectionCreatedHandler(info, originalEvent) { | |||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     await server.put(`notes/${sourceNoteId}/relations/${name}/to/${targetNoteId}`); |     const attribute = await server.put(`notes/${sourceNoteId}/relations/${name}/to/${targetNoteId}`); | ||||||
|  |  | ||||||
|     relations.push({ targetNoteId, sourceNoteId, name }); |     relations.push({ attributeId: attribute.attributeId , targetNoteId, sourceNoteId, name }); | ||||||
|  |  | ||||||
|     connection.setType("uniDirectional"); |     connection.setType("uniDirectional"); | ||||||
|     connection.getOverlay("label").setLabel(name); |     connection.getOverlay("label").setLabel(name); | ||||||
| } | } | ||||||
|  |  | ||||||
| function relationContextMenuHandler(event, ui) { | async function relationContextMenuHandler(event, ui) { | ||||||
|     const {connection} = ui.extraData; |     const {connection} = ui.extraData; | ||||||
|  |  | ||||||
|     if (ui.cmd === 'remove') { |     if (ui.cmd === 'remove') { | ||||||
| @@ -251,36 +249,30 @@ function relationContextMenuHandler(event, ui) { | |||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         const relation = relations.find(rel => rel.attributeId === connection.id); | ||||||
|  |  | ||||||
|  |         await server.remove(`notes/${relation.sourceNoteId}/relations/${relation.name}/to/${relation.targetNoteId}`); | ||||||
|  |  | ||||||
|         instance.deleteConnection(connection); |         instance.deleteConnection(connection); | ||||||
|  |  | ||||||
|         mapData.relations = mapData.relations.filter(relation => relation.connectionId !== connection.id); |         relations = relations.filter(relation => relation.attributeId !== connection.id); | ||||||
|         saveData(); |  | ||||||
|     } |  | ||||||
|     else if (ui.cmd === 'edit-name') { |  | ||||||
|         const relationName = prompt("Specify new relation name:"); |  | ||||||
|  |  | ||||||
|         connection.getOverlay("label").setLabel(relationName); |  | ||||||
|  |  | ||||||
|         const relation = mapData.relations.find(relation => relation.connectionId === connection.id); |  | ||||||
|         relation.name = relationName; |  | ||||||
|  |  | ||||||
|         saveData(); |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| function noteContextMenuHandler(event, ui) { | async function noteContextMenuHandler(event, ui) { | ||||||
|     const $noteBox = ui.target.closest(".note-box"); |     const $noteBox = ui.target.closest(".note-box"); | ||||||
|     const noteId = $noteBox.prop("id"); |     const noteId = $noteBox.prop("id"); | ||||||
|  |  | ||||||
|     if (ui.cmd === "remove") { |     if (ui.cmd === "remove") { | ||||||
|         if (!confirm("Are you sure you want to remove the note?")) { |         if (!confirm("Are you sure you want to remove the note from this diagram?")) { | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         instance.remove(noteId); |         instance.remove(noteId); | ||||||
|  |  | ||||||
|         mapData.notes = mapData.notes.filter(note => note.id !== noteId); |         mapData.notes = mapData.notes.filter(note => note.id !== noteId); | ||||||
|         mapData.relations = mapData.relations.filter(relation => relation.source !== noteId && relation.target !== noteId); |  | ||||||
|  |         relations = relations.filter(relation => relation.sourceNoteId !== noteId && relation.targetNoteId !== noteId); | ||||||
|  |  | ||||||
|         saveData(); |         saveData(); | ||||||
|     } |     } | ||||||
| @@ -329,12 +321,7 @@ function initNode(el) { | |||||||
|     instance.makeSource(el, { |     instance.makeSource(el, { | ||||||
|         filter: ".endpoint", |         filter: ".endpoint", | ||||||
|         anchor: "Continuous", |         anchor: "Continuous", | ||||||
|         connectorStyle: { |         connectorStyle: { stroke: "#000", strokeWidth: 1 }, | ||||||
|             stroke: "#5c96bc", |  | ||||||
|             strokeWidth: 2, |  | ||||||
|             outlineStroke: "transparent", |  | ||||||
|             outlineWidth: 4 |  | ||||||
|         }, |  | ||||||
|         connectionType: "basic", |         connectionType: "basic", | ||||||
|         extract:{ |         extract:{ | ||||||
|             "action": "the-action" |             "action": "the-action" | ||||||
| @@ -409,12 +396,6 @@ $addChildNotesButton.click(async () => { | |||||||
|                 continue; |                 continue; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             mapData.relations.push({ |  | ||||||
|                 source: child.noteId, |  | ||||||
|                 target: relation.targetNoteId, |  | ||||||
|                 name: relation.name |  | ||||||
|             }); |  | ||||||
|  |  | ||||||
|             relation.connectionId = connection.id; |             relation.connectionId = connection.id; | ||||||
|  |  | ||||||
|             connection.getOverlay("label").setLabel(relation.name); |             connection.getOverlay("label").setLabel(relation.name); | ||||||
|   | |||||||
| @@ -16,13 +16,12 @@ | |||||||
|     padding: 16px; |     padding: 16px; | ||||||
|     position: absolute !important; |     position: absolute !important; | ||||||
|     z-index: 4; |     z-index: 4; | ||||||
|     border: 1px solid #2e6f9a; |     border: 1px solid #666; | ||||||
|     box-shadow: 2px 2px 19px #e0e0e0; |     box-shadow: 2px 2px 19px #999; | ||||||
|     border-radius: 8px; |     border-radius: 8px; | ||||||
|     opacity: 0.8; |     opacity: 0.8; | ||||||
|     background-color: white; |     background-color: white; | ||||||
|     font-size: 11px; |     font-size: 11px; | ||||||
|     transition: background-color 0.25s ease-in; |  | ||||||
|     width: auto; |     width: auto; | ||||||
|     height: auto; |     height: auto; | ||||||
|     max-width: 200px; |     max-width: 200px; | ||||||
| @@ -32,8 +31,7 @@ | |||||||
| } | } | ||||||
|  |  | ||||||
| .note-box:hover { | .note-box:hover { | ||||||
|     background-color: #5c96bc; |     background-color: #ddd; | ||||||
|     color: white; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| .note-box .title { | .note-box .title { | ||||||
| @@ -41,13 +39,8 @@ | |||||||
|     font-weight: 600; |     font-weight: 600; | ||||||
| } | } | ||||||
|  |  | ||||||
| .connection-label { |  | ||||||
|     transition: background-color 0.25s ease-in; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| .connection-label.jtk-hover, .jtk-source-hover, .jtk-target-hover { | .connection-label.jtk-hover, .jtk-source-hover, .jtk-target-hover { | ||||||
|     background-color: #1e8151; |     background-color: #ddd; | ||||||
|     color: white; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| .connection-label { | .connection-label { | ||||||
| @@ -55,7 +48,7 @@ | |||||||
|     opacity: 0.8; |     opacity: 0.8; | ||||||
|     padding: 0.3em; |     padding: 0.3em; | ||||||
|     border-radius: 0.5em; |     border-radius: 0.5em; | ||||||
|     border: 1px solid #346789; |     border: 1px solid #666; | ||||||
|     cursor: pointer; |     cursor: pointer; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -65,10 +58,9 @@ | |||||||
|     right: 5px; |     right: 5px; | ||||||
|     width: 1em; |     width: 1em; | ||||||
|     height: 1em; |     height: 1em; | ||||||
|     background-color: orange; |     background-color: #333; | ||||||
|     cursor: pointer; |     cursor: pointer; | ||||||
|     box-shadow: 0 0 2px black; |     box-shadow: 0 0 2px black; | ||||||
|     transition: box-shadow 0.25s ease-in; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| .endpoint:hover { | .endpoint:hover { | ||||||
|   | |||||||
| @@ -123,8 +123,31 @@ async function createRelation(req) { | |||||||
|  |  | ||||||
|         await attribute.save(); |         await attribute.save(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     return attribute; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | async function deleteRelation(req) { | ||||||
|  |     const sourceNoteId = req.params.noteId; | ||||||
|  |     const targetNoteId = req.params.targetNoteId; | ||||||
|  |     const name = req.params.name; | ||||||
|  |  | ||||||
|  |     let attribute = await repository.getEntity(`SELECT * FROM attributes WHERE isDeleted = 0 AND noteId = ? AND type = 'relation' AND name = ? AND value = ?`, [sourceNoteId, name, targetNoteId]); | ||||||
|  |  | ||||||
|  |     if (!attribute) { | ||||||
|  |         attribute = new Attribute(); | ||||||
|  |         attribute.noteId = sourceNoteId; | ||||||
|  |         attribute.name = name; | ||||||
|  |         attribute.type = 'relation'; | ||||||
|  |         attribute.value = targetNoteId; | ||||||
|  |  | ||||||
|  |         await attribute.save(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return attribute; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
| module.exports = { | module.exports = { | ||||||
|     updateNoteAttributes, |     updateNoteAttributes, | ||||||
|     updateNoteAttribute, |     updateNoteAttribute, | ||||||
| @@ -132,5 +155,6 @@ module.exports = { | |||||||
|     getAttributeNames, |     getAttributeNames, | ||||||
|     getValuesForAttribute, |     getValuesForAttribute, | ||||||
|     getEffectiveNoteAttributes, |     getEffectiveNoteAttributes, | ||||||
|     createRelation |     createRelation, | ||||||
|  |     deleteRelation | ||||||
| }; | }; | ||||||
| @@ -111,6 +111,7 @@ async function getRelationMap(req) { | |||||||
|     // FIXME: this actually doesn't take into account inherited relations! But maybe it is better this way? |     // 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)) |     resp.relations = (await repository.getEntities(`SELECT * FROM attributes WHERE isDeleted = 0 AND type = 'relation' AND noteId IN (${questionMarks})`, noteIds)) | ||||||
|         .map(relation => { return { |         .map(relation => { return { | ||||||
|  |             attributeId: relation.attributeId, | ||||||
|             sourceNoteId: relation.noteId, |             sourceNoteId: relation.noteId, | ||||||
|             targetNoteId: relation.value, |             targetNoteId: relation.value, | ||||||
|             name: relation.name |             name: relation.name | ||||||
|   | |||||||
| @@ -138,6 +138,7 @@ function register(app) { | |||||||
|     apiRoute(PUT, '/api/notes/:noteId/attributes', attributesRoute.updateNoteAttributes); |     apiRoute(PUT, '/api/notes/:noteId/attributes', attributesRoute.updateNoteAttributes); | ||||||
|     apiRoute(PUT, '/api/notes/:noteId/attribute', attributesRoute.updateNoteAttribute); |     apiRoute(PUT, '/api/notes/:noteId/attribute', attributesRoute.updateNoteAttribute); | ||||||
|     apiRoute(PUT, '/api/notes/:noteId/relations/:name/to/:targetNoteId', attributesRoute.createRelation); |     apiRoute(PUT, '/api/notes/:noteId/relations/:name/to/:targetNoteId', attributesRoute.createRelation); | ||||||
|  |     apiRoute(DELETE, '/api/notes/:noteId/relations/:name/to/:targetNoteId', attributesRoute.deleteRelation); | ||||||
|     apiRoute(DELETE, '/api/notes/:noteId/attributes/:attributeId', attributesRoute.deleteNoteAttribute); |     apiRoute(DELETE, '/api/notes/:noteId/attributes/:attributeId', attributesRoute.deleteNoteAttribute); | ||||||
|     apiRoute(GET, '/api/attributes/names', attributesRoute.getAttributeNames); |     apiRoute(GET, '/api/attributes/names', attributesRoute.getAttributeNames); | ||||||
|     apiRoute(GET, '/api/attributes/values/:attributeName', attributesRoute.getValuesForAttribute); |     apiRoute(GET, '/api/attributes/values/:attributeName', attributesRoute.getValuesForAttribute); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user