From 2a14ea8d0c0b45a1ebaf0e99bd8dddef6fb49f0c Mon Sep 17 00:00:00 2001 From: azivner Date: Tue, 30 Oct 2018 10:36:19 +0100 Subject: [PATCH] fixes for relation handling + visual design restyled into gray colors --- .../services/note_detail_relation_map.js | 59 +++++++------------ src/public/stylesheets/relation-map.css | 20 ++----- src/routes/api/attributes.js | 26 +++++++- src/routes/api/notes.js | 1 + src/routes/routes.js | 1 + 5 files changed, 53 insertions(+), 54 deletions(-) diff --git a/src/public/javascripts/services/note_detail_relation_map.js b/src/public/javascripts/services/note_detail_relation_map.js index 6b632c561..8da8c5b6a 100644 --- a/src/public/javascripts/services/note_detail_relation_map.js +++ b/src/public/javascripts/services/note_detail_relation_map.js @@ -42,8 +42,7 @@ const biDirectionalOverlays = [ function loadMapData() { const currentNote = noteDetailService.getCurrentNote(); mapData = { - notes: [], - relations: [] + notes: [] }; if (currentNote.content) { @@ -115,7 +114,7 @@ async function loadNotesAndRelations() { } const connection = instance.connect({ - id: `${relation.sourceNoteId}${relation.targetNoteId}`, + id: relation.attributeIds, source: relation.sourceNoteId, target: relation.targetNoteId, type: relation.type @@ -155,8 +154,8 @@ function initPanZoom() { async function initJsPlumb () { instance = jsPlumb.getInstance({ Endpoint: ["Dot", {radius: 2}], - Connector: "StateMachine", - HoverPaintStyle: {stroke: "#1e8151", strokeWidth: 2 }, + Connector: "Straight", + HoverPaintStyle: {stroke: "#777", strokeWidth: 1 }, Container: "relation-map-canvas" }); @@ -181,8 +180,7 @@ async function initJsPlumb () { delegate: ".connection-label,.jtk-connector", autoTrigger: false, // it doesn't open automatically, needs to be triggered explicitly by .open() call menu: [ - {title: "Remove relation", cmd: "remove", uiIcon: "ui-icon-trash"}, - {title: "Edit relation name", cmd: "edit-name", uiIcon: "ui-icon-pencil"}, + {title: "Remove relation", cmd: "remove", uiIcon: "ui-icon-trash"} ], select: relationContextMenuHandler }); @@ -222,12 +220,12 @@ async function connectionCreatedHandler(info, originalEvent) { const targetNoteId = connection.target.id; const sourceNoteId = connection.source.id; - const existing = relations.some(rel => + const relationExists = relations.some(rel => rel.targetNoteId === targetNoteId && rel.sourceNoteId === sourceNoteId && rel.name === name); - if (existing) { + if (relationExists) { alert("Connection '" + name + "' between these notes already exists."); instance.deleteConnection(connection); @@ -235,15 +233,15 @@ async function connectionCreatedHandler(info, originalEvent) { 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.getOverlay("label").setLabel(name); } -function relationContextMenuHandler(event, ui) { +async function relationContextMenuHandler(event, ui) { const {connection} = ui.extraData; if (ui.cmd === 'remove') { @@ -251,36 +249,30 @@ function relationContextMenuHandler(event, ui) { 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); - mapData.relations = mapData.relations.filter(relation => relation.connectionId !== 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(); + relations = relations.filter(relation => relation.attributeId !== connection.id); } } -function noteContextMenuHandler(event, ui) { +async function noteContextMenuHandler(event, ui) { const $noteBox = ui.target.closest(".note-box"); const noteId = $noteBox.prop("id"); 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; } instance.remove(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(); } @@ -329,12 +321,7 @@ function initNode(el) { instance.makeSource(el, { filter: ".endpoint", anchor: "Continuous", - connectorStyle: { - stroke: "#5c96bc", - strokeWidth: 2, - outlineStroke: "transparent", - outlineWidth: 4 - }, + connectorStyle: { stroke: "#000", strokeWidth: 1 }, connectionType: "basic", extract:{ "action": "the-action" @@ -409,12 +396,6 @@ $addChildNotesButton.click(async () => { continue; } - mapData.relations.push({ - source: child.noteId, - target: relation.targetNoteId, - name: relation.name - }); - relation.connectionId = connection.id; connection.getOverlay("label").setLabel(relation.name); diff --git a/src/public/stylesheets/relation-map.css b/src/public/stylesheets/relation-map.css index 259314dc6..4e6fa11d0 100644 --- a/src/public/stylesheets/relation-map.css +++ b/src/public/stylesheets/relation-map.css @@ -16,13 +16,12 @@ padding: 16px; position: absolute !important; z-index: 4; - border: 1px solid #2e6f9a; - box-shadow: 2px 2px 19px #e0e0e0; + border: 1px solid #666; + box-shadow: 2px 2px 19px #999; border-radius: 8px; opacity: 0.8; background-color: white; font-size: 11px; - transition: background-color 0.25s ease-in; width: auto; height: auto; max-width: 200px; @@ -32,8 +31,7 @@ } .note-box:hover { - background-color: #5c96bc; - color: white; + background-color: #ddd; } .note-box .title { @@ -41,13 +39,8 @@ font-weight: 600; } -.connection-label { - transition: background-color 0.25s ease-in; -} - .connection-label.jtk-hover, .jtk-source-hover, .jtk-target-hover { - background-color: #1e8151; - color: white; + background-color: #ddd; } .connection-label { @@ -55,7 +48,7 @@ opacity: 0.8; padding: 0.3em; border-radius: 0.5em; - border: 1px solid #346789; + border: 1px solid #666; cursor: pointer; } @@ -65,10 +58,9 @@ right: 5px; width: 1em; height: 1em; - background-color: orange; + background-color: #333; cursor: pointer; box-shadow: 0 0 2px black; - transition: box-shadow 0.25s ease-in; } .endpoint:hover { diff --git a/src/routes/api/attributes.js b/src/routes/api/attributes.js index 4e8da34af..06de88418 100644 --- a/src/routes/api/attributes.js +++ b/src/routes/api/attributes.js @@ -123,8 +123,31 @@ async function createRelation(req) { 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 = { updateNoteAttributes, updateNoteAttribute, @@ -132,5 +155,6 @@ module.exports = { getAttributeNames, getValuesForAttribute, getEffectiveNoteAttributes, - createRelation + createRelation, + deleteRelation }; \ No newline at end of file diff --git a/src/routes/api/notes.js b/src/routes/api/notes.js index bac00d042..60c8f260a 100644 --- a/src/routes/api/notes.js +++ b/src/routes/api/notes.js @@ -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? 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 diff --git a/src/routes/routes.js b/src/routes/routes.js index 2c565c36c..e500202b9 100644 --- a/src/routes/routes.js +++ b/src/routes/routes.js @@ -138,6 +138,7 @@ function register(app) { apiRoute(PUT, '/api/notes/:noteId/attributes', attributesRoute.updateNoteAttributes); apiRoute(PUT, '/api/notes/:noteId/attribute', attributesRoute.updateNoteAttribute); 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(GET, '/api/attributes/names', attributesRoute.getAttributeNames); apiRoute(GET, '/api/attributes/values/:attributeName', attributesRoute.getValuesForAttribute);