From c399e866805a6f296392c9f442d10821ab2029e4 Mon Sep 17 00:00:00 2001 From: Joseph D'Anna Date: Sun, 9 May 2021 18:07:18 -0400 Subject: [PATCH 1/3] Created new branch for issue e#317 --- applications/graphs/controllers.py | 12 ++++- applications/graphs/dal.py | 4 ++ applications/graphs/views.py | 17 +++++++ static/css/graphspace.css | 17 +++++++ static/js/graphs_page.js | 63 ++++++++++++++++++++++++++ templates/graph/graph_details_tab.html | 17 ++++++- templates/graph/index.html | 51 +++++++++++++++++++++ 7 files changed, 179 insertions(+), 2 deletions(-) diff --git a/applications/graphs/controllers.py b/applications/graphs/controllers.py index 8bea0bcb..fa3b7f2b 100644 --- a/applications/graphs/controllers.py +++ b/applications/graphs/controllers.py @@ -30,6 +30,10 @@ def map_attributes(attributes): if attributes and isinstance(attributes, dict) and DataType.forValue(attributes) == DataType.DICT: for key, value in attributes.items(): value_type = DataType.forValue(value) + #If we are removing tags and left with empty dictionary, just set type to String + if (key == 'tags'): + value_type = DataType.forValue("String") + key_prefix = value_type.prefix() mapped_key = key_prefix + key if not key.startswith(key_prefix) else key if value_type == DataType.DICT: @@ -255,6 +259,12 @@ def update_graph(request, graph_id, name=None, is_public=None, graph_json=None, if name is not None: G.set_name(name) + db.remove_tags_by_graph_id(request.db_session, graph_id=graph_id) + + # Add graph tags + for tag in G.get_tags(): + add_graph_tag(request, graph_id, tag) + db.remove_nodes_by_graph_id(request.db_session, graph_id=graph_id) # Add graph nodes node_name_to_id_map = add_graph_nodes(request, graph_id, G.nodes(data=True)) @@ -263,7 +273,7 @@ def update_graph(request, graph_id, name=None, is_public=None, graph_json=None, graph['graph_json'] = json.dumps(G.get_graph_json()) - body_data.update(map_attributes(G.get_graph_json)) + body_data.update(map_attributes(G.get_graph_json())) updated_graph = db.update_graph(request.db_session, id=graph_id, updated_graph=graph) # If any information in Elasticsearch was changed diff --git a/applications/graphs/dal.py b/applications/graphs/dal.py index 77b0b6ef..e5ce6c4b 100644 --- a/applications/graphs/dal.py +++ b/applications/graphs/dal.py @@ -301,6 +301,10 @@ def add_tag(db_session, name): db_session.add(tag) return tag +@with_session +def remove_tags_by_graph_id(db_session, graph_id): + db_session.query(GraphToTag).filter(GraphToTag.graph_id == graph_id).delete() + @with_session def get_layout(db_session, owner_email, name, graph_id): diff --git a/applications/graphs/views.py b/applications/graphs/views.py index a9b0da35..253a8834 100644 --- a/applications/graphs/views.py +++ b/applications/graphs/views.py @@ -494,10 +494,27 @@ def _update_graph(request, graph_id, graph={}): ------ It will update the owner_email only if user has admin access otherwise user cannot update the owner email. + Fetching graph_json from old graph if the updated graph does not contain 'graph_json' as it's attribute. + Updating title, description, tags in the graph_json if present accordingly. + """ authorization.validate(request, permission='GRAPH_UPDATE', graph_id=graph_id) user_role = authorization.user_role(request) + old_graph = _get_graph(request, graph_id) + + if ('title' in graph) or ('description' in graph) or ('tags' in graph): + if not ('graph_json' in graph): + graph['graph_json'] = old_graph['graph_json'] + + if 'title' in graph: + graph['graph_json']['data']['title'] = graph['title'] + + if 'description' in graph: + graph['graph_json']['data']['description'] = graph['description'] + + if 'tags' in graph: + graph['graph_json']['data']['tags'] = graph['tags'] if 'update_legend_format' in graph: return utils.serializer(graphs.update_graph_with_html_legend(request, graph_id=graph_id, param=graph)) diff --git a/static/css/graphspace.css b/static/css/graphspace.css index b93f9356..7fba3c1f 100644 --- a/static/css/graphspace.css +++ b/static/css/graphspace.css @@ -475,6 +475,23 @@ p.lead { } } +/* Edit Graph metadata UI */ +#edit-graph-table tr { + font-size: 16px; +} + +#edit-graph-table td, th { + padding-left: 10px; +} + +#edit-graph-table button { + height: 40px; + width: 80px; + border-radius: 5px; + font-weight: bold; + font-size: 16px; + } + /* Alerts */ .alert { width: 100%; diff --git a/static/js/graphs_page.js b/static/js/graphs_page.js index 65142ff7..f6805d15 100644 --- a/static/js/graphs_page.js +++ b/static/js/graphs_page.js @@ -462,6 +462,7 @@ var uploadGraphPage = { var graphPage = { cyGraph: undefined, timeout: null, + tagsEditor: null, init: function () { /** * This function is called to setup the graph page. @@ -550,6 +551,19 @@ var graphPage = { $( '#inputSearchEdgesAndNodes' ).val( searchquery ).trigger( 'onkeyup' ); } + graphPage.tagsEditor = $(".add-remove-tags").select2({ + tags: true, + tokenSeparators: [',', ' '], + width: '99%' + }); + + //adding on click event handlers to buttons used for editing graphs. + $('#cancel-edit-btn').click(function () { + $('#edit-tab').css('display','none'); + $('#view-tab').css('display',''); + $('#edit-desc').css('display','none'); + $('#view-desc').css('display',''); + }); graphPage.defaultLayoutWidget.init(); }, @@ -741,6 +755,55 @@ var graphPage = { ) ); }, + + updateGraphAttributesBtn: function (e, graph_id) { + + //takes name,title, description and tags and updates them by sending an ajax request to server. + apis.graphs.update(graph_id, { + 'name': $('#new_name').val(), + 'title': $('#new_title').val(), + 'description': $('#new_description').val(), + 'tags': graphPage.tagsEditor.val() + }, + successCallback = function (response) { + // This method is called when attributes of the graph(name, title, tags...etc) have been successfully updated. + $.notify({message: 'Successfully updated the graph with id=' + graph_id.toString()}, {type: 'success'}); + location.reload(); + }, + errorCallback = function (xhr, status, errorThrown) { + // This method is called when error occurs while trying to update the graph attributes. + $.notify({ + message: xhr.responseJSON.error_message + }, { + type: 'danger' + }); + + }); + }, + graphEditFormatter: function(e, title, name, description) { + + //populating input tags with appropriate values before showing the edit panel. + $('#new_name').val(name); + $('#new_title').val(title); + $('#new_description').val(description); + var hyper_links = $('#Tags').children(); + graphPage.tagsEditor.find('option').remove().end(); + $.each(hyper_links, function(idx) { + var tag = $.trim(hyper_links[idx].text); + graphPage.tagsEditor.append(new Option(tag, tag, true, true)); + } + ); + graphPage.tagsEditor.trigger('change'); + + //hides view tab and displays edit tab. + $('#view-tab').css('display','none'); + $('#edit-tab').css('display',''); + + //hides view description tab and displays edit description tab. + $('#view-desc').css('display','none'); + $('#edit-desc').css('display',''); + }, + onShareGraphWithPublicBtn: function ( e, graph_id ) { apis.graphs.update( graph_id, { diff --git a/templates/graph/graph_details_tab.html b/templates/graph/graph_details_tab.html index b52c3eb2..b48e8dcd 100644 --- a/templates/graph/graph_details_tab.html +++ b/templates/graph/graph_details_tab.html @@ -3,9 +3,20 @@ img { max-width: 200px; } + textarea { + width: 90%; + height: 150px; + padding: 12px 20px; + box-sizing: border-box; + border: 1px solid #ccc; + border-radius: 4px; + resize: none; + font-size: 15px; + }
-
+
+
Description

@@ -184,6 +186,48 @@