From 3eb211ca49e4eb6626477a0fc06d36ff93196ac2 Mon Sep 17 00:00:00 2001 From: Michael Hackstein Date: Fri, 12 Apr 2013 11:11:30 +0200 Subject: [PATCH 1/8] GraphViewer: Error in NodeShaper, labels are not yet collected from _data. Fixed Test for that --- .../specNodeShaper/nodeShaperSpec.js | 123 ++++++++++++++---- 1 file changed, 97 insertions(+), 26 deletions(-) diff --git a/html/admin/js/graphViewer/jasmine_test/specNodeShaper/nodeShaperSpec.js b/html/admin/js/graphViewer/jasmine_test/specNodeShaper/nodeShaperSpec.js index ba8a3f47c7..93f1336df6 100644 --- a/html/admin/js/graphViewer/jasmine_test/specNodeShaper/nodeShaperSpec.js +++ b/html/admin/js/graphViewer/jasmine_test/specNodeShaper/nodeShaperSpec.js @@ -235,7 +235,22 @@ shaper; beforeEach(function() { - nodes = [{_id: 1}, {_id: 2}, {_id: 3}]; + nodes = [{ + _id: 1, + _data: { + + } + }, { + _id: 2, + _data: { + + } + }, { + _id: 3, + _data: { + + } + }]; clicked = []; shaper = new NodeShaper(d3.select("svg")); shaper.drawNodes(nodes); @@ -305,9 +320,9 @@ it('should be able to reshape a single node only', function() { shaper.changeTo({label: "label"}); - nodes[0].label = "false"; - nodes[1].label = "true"; - nodes[2].label = "false_again"; + nodes[0]._data.label = "false"; + nodes[1]._data.label = "true"; + nodes[2]._data.label = "false_again"; expect($("#1 text").length).toEqual(1); expect($("#2 text").length).toEqual(1); expect($("#3 text").length).toEqual(1); @@ -326,8 +341,6 @@ }); }); - - describe('configured for circle', function () { var shaper; @@ -522,8 +535,6 @@ }); }); - - describe('configured for label', function () { var shaper; @@ -534,7 +545,12 @@ }); it('should add a text element', function () { - var node = [{_id: 1, "label": "MyLabel"}]; + var node = [{ + _id: 1, + _data: { + "label": "MyLabel" + } + }]; shaper.drawNodes(node); expect($("svg .node")[0]).toBeDefined(); expect($("svg .node").length).toEqual(1); @@ -550,10 +566,31 @@ it('should ignore other attributes', function () { var nodes = [ - {_id: 1, "label": "correct"}, - {_id: 2, "alt": "incorrect"}, - {_id: 3, "alt": "incorrect"}, - {_id: 4, "label": "correct", "alt": "incorrect"}]; + { + _id: 1, + _data: { + "label": "correct" + } + }, + { + _id: 2, + _data: { + "alt": "incorrect" + } + }, + { + _id: 3, + _data: { + "alt": "incorrect" + } + }, + { + _id: 4, + _data: { + "label": "correct", + "alt": "incorrect" + } + }]; shaper.drawNodes(nodes); expect($("svg #1 text")[0].textContent).toEqual("correct"); expect($("svg #2 text")[0].textContent).toEqual(""); @@ -562,7 +599,12 @@ }); it('should also print "0" as a label', function() { - var node = [{_id: 1, "label": 0}]; + var node = [{ + _id: 1, + _data: { + "label": 0 + } + }]; shaper.drawNodes(node); expect($("svg .node text")[0]).toBeDefined(); expect($("svg .node text").length).toEqual(1); @@ -572,8 +614,10 @@ it('should be able to switch to another label during runtime', function() { var node = [{ _id: 1, - label: "before", - switched: "after" + _data: { + label: "before", + switched: "after" + } }]; shaper.drawNodes(node); expect($("svg .node text")[0].textContent).toEqual("before"); @@ -592,11 +636,11 @@ if (node._id === 4) { return "correct"; } - if (node.label) { - return node.label; + if (node._data.label) { + return node._data.label; } - if (node.alt) { - return node.alt; + if (node._data.alt) { + return node._data.alt; } return "default"; }; @@ -609,11 +653,36 @@ it('should display the correct labels according to the function', function () { var nodes = [ - {_id: 1, "label": "correct"}, - {_id: 2, "alt": "correct"}, - {_id: 3, "label": "correct", "alt": "incorrect"}, - {_id: 4, "label": "incorrect", "alt": "incorrect"}, - {_id: 5} + { + _id: 1, + _data: { + "label": "correct" + } + }, + { + _id: 2, + _data: { + "alt": "correct" + } + }, + { + _id: 3, + _data: { + "label": "correct", + "alt": "incorrect" + } + }, + { + _id: 4, + _data: { + "label": "incorrect", + "alt": "incorrect" + } + }, + { + _id: 5, + _data: {} + } ]; shaper.drawNodes(nodes); expect($("text").length).toEqual(5); @@ -712,7 +781,9 @@ it('should draw circle elements', function () { var node = [{ _id: 1, - "label": "correct" + _data: { + "label": "correct" + } }]; shaper.drawNodes(node); expect($("svg .node").length).toEqual(1); From b2c3b51e3f9fb9c0d903b4bbf3009f79b8edef77 Mon Sep 17 00:00:00 2001 From: Michael Hackstein Date: Fri, 12 Apr 2013 11:23:32 +0200 Subject: [PATCH 2/8] GraphViewer: Fixed bug for nodeshaper --- html/admin/js/graphViewer/graph/nodeShaper.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/html/admin/js/graphViewer/graph/nodeShaper.js b/html/admin/js/graphViewer/graph/nodeShaper.js index ddf3b3106e..46c24bd157 100644 --- a/html/admin/js/graphViewer/graph/nodeShaper.js +++ b/html/admin/js/graphViewer/graph/nodeShaper.js @@ -204,7 +204,7 @@ function NodeShaper(parent, flags, idfunc) { .attr("fill", "black") .attr("stroke", "black") .text(function(d) { - return d[label] !== undefined ? d[label] : ""; // Which value should be used as label + return d._data[label] !== undefined ? d._data[label] : ""; }); }; } From 380a675fe0c13fbf6831326b5a6cf5fc18c22810 Mon Sep 17 00:00:00 2001 From: Michael Hackstein Date: Fri, 12 Apr 2013 11:37:39 +0200 Subject: [PATCH 3/8] GraphViewer: Same Problem with _data as for nodes also in edges. Now fixed --- html/admin/js/graphViewer/graph/edgeShaper.js | 5 +- .../specEdgeShaper/edgeShaperSpec.js | 61 ++++++++++++++----- 2 files changed, 48 insertions(+), 18 deletions(-) diff --git a/html/admin/js/graphViewer/graph/edgeShaper.js b/html/admin/js/graphViewer/graph/edgeShaper.js index 5d3a116b7d..3e7d7dff37 100644 --- a/html/admin/js/graphViewer/graph/edgeShaper.js +++ b/html/admin/js/graphViewer/graph/edgeShaper.js @@ -213,7 +213,8 @@ function EdgeShaper(parent, flags, idfunc) { .attr("text-anchor", "middle") // Define text-anchor .attr("stroke", "black") .text(function(d) { - return d[label] !== undefined ? d[label] : ""; // Which value should be used as label + // Which value should be used as label + return d._data[label] !== undefined ? d._data[label] : ""; }); }; } @@ -274,7 +275,7 @@ function EdgeShaper(parent, flags, idfunc) { case "attribute": addColor = function (line, g) { g.attr("stroke", function(e) { - return colourMapper.getColour(e[color.key]); + return colourMapper.getColour(e._data[color.key]); }); }; break; diff --git a/html/admin/js/graphViewer/jasmine_test/specEdgeShaper/edgeShaperSpec.js b/html/admin/js/graphViewer/jasmine_test/specEdgeShaper/edgeShaperSpec.js index 881469d49b..3c5118f958 100644 --- a/html/admin/js/graphViewer/jasmine_test/specEdgeShaper/edgeShaperSpec.js +++ b/html/admin/js/graphViewer/jasmine_test/specEdgeShaper/edgeShaperSpec.js @@ -355,19 +355,27 @@ edges = [{ source: n1, target: n2, - label: "lbl1" + _data: { + label: "lbl1" + } },{ source: n2, target: n3, - label: "lbl2" + _data: { + label: "lbl2" + } },{ source: n3, target: n4, - label: "lbl3" + _data: { + label: "lbl3" + } },{ source: n4, target: n1, - label: "lbl1" + _data: { + label: "lbl1" + } }], shaper = new EdgeShaper(d3.select("svg"), { @@ -586,22 +594,30 @@ { "source": nodes[0], "target": nodes[1], - "label": "first" + _data: { + label: "first" + } }, { "source": nodes[1], "target": nodes[2], - "label": "second" + _data: { + label: "second" + } }, { "source": nodes[2], "target": nodes[3], - "label": "third" + _data: { + label: "third" + } }, { "source": nodes[3], "target": nodes[0], - "label": "fourth" + _data: { + label: "fourth" + } } ]; shaper.drawEdges(edges); @@ -637,7 +653,9 @@ { "source": nodes[0], "target": nodes[1], - "label": "first" + _data: { + "label": "first" + } } ]; shaper.drawEdges(edges); @@ -651,22 +669,29 @@ { "source": nodes[0], "target": nodes[1], - "label": "correct" + _data: { + "label": "correct" + } }, { "source": nodes[1], "target": nodes[2], - "alt": "incorrect" + _data: { + "alt": "incorrect" + } }, { "source": nodes[2], - "target": nodes[3] + "target": nodes[3], + _data: {} }, { "source": nodes[3], "target": nodes[0], - "label": "correct", - "alt": "incorrect" + _data: { + "label": "correct", + "alt": "incorrect" + } } ]; shaper.drawEdges(edges); @@ -684,12 +709,16 @@ { "source": nodes[0], "target": nodes[1], - "label": "old" + _data: { + "label": "old" + } }, { "source": nodes[1], "target": nodes[0], - "new": "new" + _data: { + "new": "new" + } } ]; shaper.drawEdges(edges); From 135707325ea7a5930543a95902dc5bd8b33f67dd Mon Sep 17 00:00:00 2001 From: Michael Hackstein Date: Fri, 12 Apr 2013 15:24:35 +0200 Subject: [PATCH 4/8] GraphViewer: ArangoAdapter now uses BindParameters --- .../js/graphViewer/graph/arangoAdapter.js | 120 ++++++++++-------- .../specAdapter/arangoAdapterSpec.js | 31 +++++ 2 files changed, 100 insertions(+), 51 deletions(-) diff --git a/html/admin/js/graphViewer/graph/arangoAdapter.js b/html/admin/js/graphViewer/graph/arangoAdapter.js index ff2bfdd32f..9a9e452934 100644 --- a/html/admin/js/graphViewer/graph/arangoAdapter.js +++ b/html/admin/js/graphViewer/graph/arangoAdapter.js @@ -34,6 +34,7 @@ function ArangoAdapter(arangodb, nodes, edges, nodeCollection, edgeCollection, w initialX = {}, initialY = {}, api = {}, + queries = {}, findNode = function(id) { var res = $.grep(nodes, function(e){ @@ -156,8 +157,15 @@ function ArangoAdapter(arangodb, nodes, edges, nodeCollection, edgeCollection, w }, - sendQuery = function(query, onSuccess) { - var data = {query: query}; + sendQuery = function(query, bindVars, onSuccess) { + if (query !== queries.connectedEdges) { + bindVars["@nodes"] = nodeCollection; + } + bindVars["@edges"] = edgeCollection; + var data = { + query: query, + bindVars: bindVars + }; $.ajax({ type: "POST", url: api.cursor, @@ -234,11 +242,9 @@ function ArangoAdapter(arangodb, nodes, edges, nodeCollection, edgeCollection, w }, permanentlyRemoveEdgesOfNode = function (nodeId) { - var query = "FOR e IN " + edgeCollection - + " FILTER e._to == " + JSON.stringify(nodeId) - + " || e._from == " + JSON.stringify(nodeId) - + " RETURN e"; - sendQuery(query, function(res) { + sendQuery(queries.connectedEdges, { + id: nodeId + }, function(res) { _.each(res, self.deleteEdge); }); }; @@ -252,6 +258,50 @@ function ArangoAdapter(arangodb, nodes, edges, nodeCollection, edgeCollection, w api.node = api.base + "document?collection=" + nodeCollection; api.edge = api.base + "edge?collection=" + edgeCollection; + queries.nodeById = "FOR n IN @@nodes" + + " FILTER n._id == @id" + + " LET links = (" + + " FOR l IN @@edges" + + " FILTER n._id == l._from" + + " FOR t IN @@nodes" + + " FILTER t._id == l._to" + + " RETURN t._id" + + " )" + + " RETURN MERGE(n, {\"children\" : links})"; + queries.traversalById = "RETURN TRAVERSAL(" + + "@@nodes, " + + "@@edges, " + + "@id, " + + "\"outbound\", {" + + "strategy: \"depthfirst\"," + + "maxDepth: 1," + + "paths: true" + + "})"; + queries.traversalByAttribute = function(attr) { + return "FOR n IN @@nodes " + + " FILTER n." + attr + + " == @value" + + " RETURN TRAVERSAL(" + + "@@nodes, " + + "@@edges, " + + "n._id, " + + "\"outbound\", {" + + "strategy: \"depthfirst\"," + + "maxDepth: 1," + + "paths: true" + + "})"; + }; + queries.childrenCentrality = "FOR u IN @@nodes" + + " FILTER u._id == @id" + + " LET g = (" + + " FOR l in @@edges" + + " FILTER l._from == u._id" + + " RETURN 1 )" + + " RETURN length(g)"; + queries.connectedEdges = "FOR e IN @@edges" + + " FILTER e._to == @id" + + " || e._from == @id" + + " RETURN e"; initialX.range = width / 2; initialX.start = width / 4; @@ -266,65 +316,33 @@ function ArangoAdapter(arangodb, nodes, edges, nodeCollection, edgeCollection, w }; self.oldLoadNodeFromTreeById = function(nodeId, callback) { - var loadNodeQuery = - "FOR n IN " + nodeCollection - + " FILTER n._id == " + JSON.stringify(nodeId) - + " LET links = (" - + " FOR l IN " + edgeCollection - + " FILTER n._id == l._from" - + " FOR t IN " + nodeCollection - + " FILTER t._id == l._to" - + " RETURN t._id" - + " )" - + " RETURN MERGE(n, {\"children\" : links})"; - sendQuery(loadNodeQuery, function(res) { + sendQuery(queries.nodeById, { + id: nodeId + }, function(res) { parseResultOfQuery(res, callback); }); }; self.loadNodeFromTreeById = function(nodeId, callback) { - var traversal = "RETURN TRAVERSAL(" - + nodeCollection + ", " - + edgeCollection + ", " - + "\"" + nodeId + "\", " - + "\"outbound\", {" - + "strategy: \"depthfirst\"," - + "maxDepth: 1," - + "paths: true" - + "})"; - sendQuery(traversal, function(res) { + sendQuery(queries.traversalById, { + id: nodeId + }, function(res) { parseResultOfTraversal(res, callback); }); }; self.loadNodeFromTreeByAttributeValue = function(attribute, value, callback) { - var traversal = "FOR n in " - + nodeCollection - + " FILTER n." + attribute - + " == " + JSON.stringify(value) - + " RETURN TRAVERSAL(" - + nodeCollection + ", " - + edgeCollection + ", " - + "n._id, " - + "\"outbound\", {" - + "strategy: \"depthfirst\"," - + "maxDepth: 1," - + "paths: true" - + "})"; - sendQuery(traversal, function(res) { + sendQuery(queries.traversalByAttribute(attribute), { + value: value + }, function(res) { parseResultOfTraversal(res, callback); }); }; self.requestCentralityChildren = function(nodeId, callback) { - var requestChildren = "for u in " + nodeCollection - + " filter u._id == " + JSON.stringify(nodeId) - + " let g = (" - + " for l in " + edgeCollection - + " filter l._from == u._id" - + " return 1 )" - + " return length(g)"; - sendQuery(requestChildren, function(res) { + sendQuery(queries.childrenCentrality,{ + id: nodeId + }, function(res) { callback(res[0]); }); }; diff --git a/html/admin/js/graphViewer/jasmine_test/specAdapter/arangoAdapterSpec.js b/html/admin/js/graphViewer/jasmine_test/specAdapter/arangoAdapterSpec.js index a0a25ed768..c3218fb41c 100644 --- a/html/admin/js/graphViewer/jasmine_test/specAdapter/arangoAdapterSpec.js +++ b/html/admin/js/graphViewer/jasmine_test/specAdapter/arangoAdapterSpec.js @@ -247,6 +247,37 @@ }); }); + it('should be able to load a tree node from ArangoDB' + + ' by internal attribute and value', function() { + + var c0, c1, c2, c3, c4; + + runs(function() { + c0 = insertNode(nodesCollection, 0); + c1 = insertNode(nodesCollection, 1); + c2 = insertNode(nodesCollection, 2); + c3 = insertNode(nodesCollection, 3); + c4 = insertNode(nodesCollection, 4); + + insertEdge(edgesCollection, c0, c1); + insertEdge(edgesCollection, c0, c2); + insertEdge(edgesCollection, c0, c3); + insertEdge(edgesCollection, c0, c4); + + callbackCheck = false; + adapter.loadNodeFromTreeByAttributeValue("id", 0, checkCallbackFunction); + }); + + waitsFor(function() { + return callbackCheck; + }); + + runs(function() { + existNodes([c0, c1, c2, c3, c4]); + expect(nodes.length).toEqual(5); + }); + }); + it('should be able to request the number of children centrality', function() { var c0, c1 ,c2 ,c3 ,c4, children; From 84c4da1c923eaec5dcc9322cf24be1f637339411 Mon Sep 17 00:00:00 2001 From: Michael Hackstein Date: Fri, 12 Apr 2013 15:49:35 +0200 Subject: [PATCH 5/8] GraphViewer: ArangoAdapter is now able to switch to other collections --- .../js/graphViewer/graph/arangoAdapter.js | 7 ++ .../specAdapter/arangoAdapterSpec.js | 79 +++++++++++++++++++ 2 files changed, 86 insertions(+) diff --git a/html/admin/js/graphViewer/graph/arangoAdapter.js b/html/admin/js/graphViewer/graph/arangoAdapter.js index 9a9e452934..354730210c 100644 --- a/html/admin/js/graphViewer/graph/arangoAdapter.js +++ b/html/admin/js/graphViewer/graph/arangoAdapter.js @@ -465,5 +465,12 @@ function ArangoAdapter(arangodb, nodes, edges, nodeCollection, edgeCollection, w }); }; + self.changeTo = function (nodesCol, edgesCol ) { + nodeCollection = nodesCol; + edgeCollection = edgesCol; + api.node = api.base + "document?collection=" + nodeCollection; + api.edge = api.base + "edge?collection=" + edgeCollection; + console.log(api.node); + }; } \ No newline at end of file diff --git a/html/admin/js/graphViewer/jasmine_test/specAdapter/arangoAdapterSpec.js b/html/admin/js/graphViewer/jasmine_test/specAdapter/arangoAdapterSpec.js index c3218fb41c..d67581720e 100644 --- a/html/admin/js/graphViewer/jasmine_test/specAdapter/arangoAdapterSpec.js +++ b/html/admin/js/graphViewer/jasmine_test/specAdapter/arangoAdapterSpec.js @@ -48,8 +48,12 @@ arangodb, nodesCollection, nodesCollId, + altNodesCollection, + altNodesCollId, edgesCollection, edgesCollId, + altEdgesCollection, + altEdgesCollId, callbackCheck, checkCallbackFunction = function() { callbackCheck = true; @@ -182,6 +186,8 @@ try { dropCollection(nodesCollection); dropCollection(edgesCollection); + dropCollection(altNodesCollection); + dropCollection(altEdgesCollection); }catch(e){ } @@ -190,11 +196,17 @@ setupArangoContent = function() { nodesCollection = "TestNodes321"; edgesCollection = "TestEdges321"; + altNodesCollection = "TestNodes654"; + altEdgesCollection = "TestEdges654"; + deleteArangoContent(); createCollection(nodesCollection, "Document", function(id) {nodesCollId = id;}); createCollection(edgesCollection, "Edge", function(id) {edgesCollId = id;}); + + createCollection(altNodesCollection, "Document", function(id) {altNodesCollId = id;}); + createCollection(altEdgesCollection, "Edge", function(id) {altEdgesCollId = id;}); }; beforeEach(function() { @@ -355,6 +367,73 @@ }); + it('should be able to switch to different collections', function() { + var c0, c1, e1_2, insertedId; + + runs(function() { + c0 = insertNode(altNodesCollection, 0); + c1 = insertNode(altNodesCollection, 1); + e1_2 = insertEdge(altEdgesCollection, c0, c1); + + adapter.changeTo(altNodesCollection, altEdgesCollection); + + callbackCheck = false; + adapter.loadNodeFromTreeById(c0, checkCallbackFunction); + }); + + waitsFor(function() { + return callbackCheck; + }); + + runs(function() { + existNodes([c0, c1]); + expect(nodes.length).toEqual(2); + + callbackCheck = false; + adapter.createNode({}, function(node) { + insertedId = node._id; + callbackCheck = true; + }); + this.addMatchers({ + toBeStoredPermanently: function() { + var id = this.actual, + res = false; + $.ajax({ + type: "GET", + url: arangodb + "/_api/document/" + id, + contentType: "application/json", + processData: false, + async: false, + success: function(data) { + res = true; + }, + error: function(data) { + try { + var temp = JSON.parse(data); + throw "[" + temp.errorNum + "] " + temp.errorMessage; + } + catch (e) { + throw "Undefined ERROR"; + } + } + }); + return res; + } + }); + + }); + + waitsFor(function() { + return callbackCheck; + }); + + runs(function() { + expect(insertedId).toBeStoredPermanently(); + existNode(insertedId); + }); + + }); + describe('that has already loaded one graph', function() { var c0, c1, c2, c3, c4, c5, c6, c7; From 3d66aac371804e9b083b7b1fcd16c0fef5ab4ca4 Mon Sep 17 00:00:00 2001 From: Michael Hackstein Date: Fri, 12 Apr 2013 16:01:29 +0200 Subject: [PATCH 6/8] GraphViewer: Added Spec for the ArangoAdapterUI to switch collections --- .../specAdapter/arangoAdapterUISpec.js | 92 +++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 html/admin/js/graphViewer/jasmine_test/specAdapter/arangoAdapterUISpec.js diff --git a/html/admin/js/graphViewer/jasmine_test/specAdapter/arangoAdapterUISpec.js b/html/admin/js/graphViewer/jasmine_test/specAdapter/arangoAdapterUISpec.js new file mode 100644 index 0000000000..a28d93882c --- /dev/null +++ b/html/admin/js/graphViewer/jasmine_test/specAdapter/arangoAdapterUISpec.js @@ -0,0 +1,92 @@ +/*jslint indent: 2, nomen: true, maxlen: 100, white: true plusplus: true */ +/*global beforeEach, afterEach */ +/*global describe, it, expect*/ +/*global runs, waitsFor, spyOn */ +/*global window, eb, loadFixtures, document */ +/*global $, _, d3*/ +/*global helper*/ +/*global ArangoAdapterControls */ + +//////////////////////////////////////////////////////////////////////////////// +/// @brief Graph functionality +/// +/// @file +/// +/// DISCLAIMER +/// +/// Copyright 2010-2012 triagens GmbH, Cologne, Germany +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// +/// Copyright holder is triAGENS GmbH, Cologne, Germany +/// +/// @author Michael Hackstein +/// @author Copyright 2011-2013, triAGENS GmbH, Cologne, Germany +//////////////////////////////////////////////////////////////////////////////// + + +(function () { + "use strict"; + + describe('Arango Adapter UI', function () { + var adapter, adapterUI, list; + + beforeEach(function () { + adapter = { + + }; + list = document.createElement("ul"); + document.body.appendChild(list); + list.id = "control_list"; + adapterUI = new ArangoAdapterControls(list, adapter); + spyOn(adapter, 'changeTo'); + + }); + + afterEach(function () { + document.body.removeChild(list); + }); + + it('should throw errors if not setup correctly', function() { + expect(function() { + var e = new ArangoAdapterControls(); + }).toThrow("A list element has to be given."); + expect(function() { + var e = new ArangoAdapterControls(list); + }).toThrow("The ArangoAdapter has to be given."); + }); + + it('should be able to add a change collections control to the list', function() { + runs(function() { + adapterUI.addControlChangeCollections(); + + expect($("#control_list #control_collections").length).toEqual(1); + expect($("#control_list #control_collections")[0]).toConformToListCSS(); + + helper.simulateMouseEvent("click", "control_collections"); + + expect($("#control_collections_modal").length).toEqual(1); + + $("#control_collections_nodes").attr("value", "newNodes"); + $("#control_collections_edges").attr("value", "newEdges"); + + helper.simulateMouseEvent("click", "control_collections_submit"); + + expect(adapter.changeTo).toHaveBeenCalledWith( + "newNodes", + "newEdges" + ); + }); + }); + }); +}()); \ No newline at end of file From 2238f0db0f99da6d711031f46df48494e22de85c Mon Sep 17 00:00:00 2001 From: Michael Hackstein Date: Mon, 15 Apr 2013 11:59:20 +0200 Subject: [PATCH 7/8] Frontend: The Documentation of the Applications can now be accessed per application. And If there is an error useful info is printed --- html/admin/js/routers/router.js | 11 ++++------ html/admin/js/templates/navigationView.ejs | 1 - html/admin/js/views/appDocumentationView.js | 18 +++++++--------- html/admin/js/views/foxxActiveListView.js | 1 - html/admin/js/views/foxxActiveView.js | 8 ++++++- js/apps/aardvark/aardvark.js | 24 +++++++++++++++++---- js/apps/aardvark/manifest.json | 3 ++- js/apps/aardvark/repositories/foxxes.js | 9 ++------ js/apps/aardvark/repositories/swagger.js | 12 +++++++++++ 9 files changed, 55 insertions(+), 32 deletions(-) diff --git a/html/admin/js/routers/router.js b/html/admin/js/routers/router.js index 1dcc7ea595..f3b991ab23 100644 --- a/html/admin/js/routers/router.js +++ b/html/admin/js/routers/router.js @@ -18,7 +18,7 @@ $(document).ready(function() { "application/available/:key" : "applicationInstall", "applications/installed" : "applicationsInstalled", "applications/available" : "applicationsAvailable", - "applications/documentation" : "applicationsDocumentation", + "application/documentation/:key" : "appDocumentation", "graph" : "graph" }, @@ -223,12 +223,9 @@ $(document).ready(function() { }, - - applicationsDocumentation: function() { - if (this.appDocuView === undefined) { - this.appDocuView = new window.AppDocumentationView(); - } - this.appDocuView.render(); + appDocumentation: function(key) { + var docuView = new window.AppDocumentationView({key: key}); + docuView.render(); this.naviView.selectMenuItem('applications-menu'); } diff --git a/html/admin/js/templates/navigationView.ejs b/html/admin/js/templates/navigationView.ejs index 530b87847b..62b2cce877 100644 --- a/html/admin/js/templates/navigationView.ejs +++ b/html/admin/js/templates/navigationView.ejs @@ -14,7 +14,6 @@
  • Collections
  • AQL Editor
  • diff --git a/html/admin/js/views/appDocumentationView.js b/html/admin/js/views/appDocumentationView.js index f2d8d96295..d67af3406c 100644 --- a/html/admin/js/views/appDocumentationView.js +++ b/html/admin/js/views/appDocumentationView.js @@ -5,25 +5,23 @@ window.AppDocumentationView = Backbone.View.extend({ initialize: function() { this.swaggerUi = new SwaggerUi({ - discoveryUrl:"../aardvark/docus", + discoveryUrl:"../aardvark/docu/" + this.options.key, apiKey: false, dom_id:"swagger-ui-container", supportHeaderParams: true, supportedSubmitMethods: ['get', 'post', 'put', 'delete', 'patch', 'head'], onComplete: function(swaggerApi, swaggerUi){ - if(console) { - console.log("Loaded SwaggerUI") - console.log(swaggerApi); - console.log(swaggerUi); - } $('pre code').each(function(i, e) {hljs.highlightBlock(e)}); }, onFailure: function(data) { - if(console) { - console.log("Unable to Load SwaggerUI"); - console.log(data); - } + var div = document.createElement("div"), + strong = document.createElement("strong"); + strong.appendChild(document.createTextNode("Sorry the code is not documented properly")); + div.appendChild(strong); + div.appendChild(document.createElement("br")); + div.appendChild(document.createTextNode(JSON.stringify(data))); + $("#swagger-ui-container").append(div); }, docExpansion: "none" }); diff --git a/html/admin/js/views/foxxActiveListView.js b/html/admin/js/views/foxxActiveListView.js index 018446064f..ba326335e8 100644 --- a/html/admin/js/views/foxxActiveListView.js +++ b/html/admin/js/views/foxxActiveListView.js @@ -18,7 +18,6 @@ var FoxxActiveListView = Backbone.View.extend({ self.render(); }, error: function() { - console.log("Erroreoror!!"); } }); this.render(); diff --git a/html/admin/js/views/foxxActiveView.js b/html/admin/js/views/foxxActiveView.js index e4d62224eb..34c738de62 100644 --- a/html/admin/js/views/foxxActiveView.js +++ b/html/admin/js/views/foxxActiveView.js @@ -4,7 +4,8 @@ window.FoxxActiveView = Backbone.View.extend({ template: new EJS({url: 'js/templates/foxxActiveView.ejs'}), events: { - 'click .icon-edit': 'editFoxx' + 'click .icon-edit': 'editFoxx', + 'click' : 'showDocu' }, initialize: function(){ @@ -15,6 +16,11 @@ window.FoxxActiveView = Backbone.View.extend({ event.stopPropagation(); window.App.navigate("application/installed/" + encodeURIComponent(this.model.get("_key")), {trigger: true}); }, + + showDocu: function(event) { + event.stopPropagation(); + window.App.navigate("application/documentation/" + encodeURIComponent(this.model.get("_key")), {trigger: true}); + }, render: function(){ $(this.el).html(this.template.render(this.model)); diff --git a/js/apps/aardvark/aardvark.js b/js/apps/aardvark/aardvark.js index 5670888cd5..d5c66bce22 100644 --- a/js/apps/aardvark/aardvark.js +++ b/js/apps/aardvark/aardvark.js @@ -93,7 +93,14 @@ app.get("/foxxes/thumbnail/:app", function (req, res) { res.transformations = [ "base64decode" ]; res.body = repositories.foxxes.thumbnail(req.params("app")); - }); + }).pathParam("app", { + description: "The appname which is used to identify the foxx in the list of available foxxes.", + dataType: "string", + required: true, + allowMultiple: false + }).nickname("thumbnails") + .summary("Get the thumbnail of a foxx.") + .notes("Used to request the thumbnail of the given Foxx in order to display it on the screen."); app.get('/foxxes', function (req, res) { @@ -109,13 +116,22 @@ .notes("This function simply returns the list of all running" + " foxxes and supplies the paths for the swagger documentation"); - app.get('/docus/*', function(req, res) { + app.get("/docu/:key",function (req, res) { + var subPath = req.path.substr(0,req.path.lastIndexOf("[")-1), + key = req.params("key"), + path = "http://" + req.headers.host + subPath + "/" + key + "/"; + res.json(repositories.docus.listOne(path, key)); + }).nickname("swaggers") + .summary("List documentation of all foxxes.") + .notes("This function simply returns one specific" + + " foxx and supplies the paths for the swagger documentation"); + + + app.get('/docu/:key/*', function(req, res) { var mountPoint = ""; require("underscore").each(req.suffix, function(part) { mountPoint += "/" + part; }); - - //require("console").log(JSON.stringify(req)); res.json(repositories.docus.show(mountPoint)) }).pathParam("appname", { description: "The mount point of the App the documentation should be requested for", diff --git a/js/apps/aardvark/manifest.json b/js/apps/aardvark/manifest.json index a410cdec09..19b0013294 100644 --- a/js/apps/aardvark/manifest.json +++ b/js/apps/aardvark/manifest.json @@ -4,5 +4,6 @@ "apps": { "/": "aardvark.js" - } + }, + "lib": "." } diff --git a/js/apps/aardvark/repositories/foxxes.js b/js/apps/aardvark/repositories/foxxes.js index 53f54a5a3d..963945b698 100644 --- a/js/apps/aardvark/repositories/foxxes.js +++ b/js/apps/aardvark/repositories/foxxes.js @@ -66,18 +66,13 @@ return thumb; }, - install: function (name, mount, version) { - require("console").log(name); - require("console").log(mount); - require("console").log(version); - - + install: function (name, mount, version) { return foxxmanager.installApp(name, mount, version); }, // Define the functionality to uninstall an installed foxx uninstall: function (key) { - return Foxx.uninstallApp(key); + return foxxmanager.uninstallApp(key); }, // Define the functionality to deactivate an installed foxx. diff --git a/js/apps/aardvark/repositories/swagger.js b/js/apps/aardvark/repositories/swagger.js index 7b94cf51fa..9163866220 100644 --- a/js/apps/aardvark/repositories/swagger.js +++ b/js/apps/aardvark/repositories/swagger.js @@ -62,8 +62,20 @@ return result; }, + listOne: function(basePath, key) { + var result = {}, + res = db._collection("_aal").document(key); + result.swaggerVersion = "1.1"; + result.basePath = basePath; + result.apis = [ + {path: res.mount} + ]; + return result; + }, + // Get details of one specific installed foxx. show: function(appname) { + require("console").log(appname); var result = {}, apis = [], pathes, From 810d2ad83fb9ce7fd48577fdda69474793fcfd9e Mon Sep 17 00:00:00 2001 From: Michael Hackstein Date: Mon, 15 Apr 2013 12:00:15 +0200 Subject: [PATCH 8/8] GraphViewer: It is now possible to switch collections on the fly --- .../js/graphViewer/graph/arangoAdapter.js | 3 +- .../jasmine_test/runnerArangoAdapter.html | 6 ++ .../specAdapter/arangoAdapterUISpec.js | 31 +++++++-- .../graphViewer/ui/arangoAdapterControls.js | 66 +++++++++++++++++++ 4 files changed, 100 insertions(+), 6 deletions(-) create mode 100644 html/admin/js/graphViewer/ui/arangoAdapterControls.js diff --git a/html/admin/js/graphViewer/graph/arangoAdapter.js b/html/admin/js/graphViewer/graph/arangoAdapter.js index 354730210c..00fe1fb8af 100644 --- a/html/admin/js/graphViewer/graph/arangoAdapter.js +++ b/html/admin/js/graphViewer/graph/arangoAdapter.js @@ -469,8 +469,7 @@ function ArangoAdapter(arangodb, nodes, edges, nodeCollection, edgeCollection, w nodeCollection = nodesCol; edgeCollection = edgesCol; api.node = api.base + "document?collection=" + nodeCollection; - api.edge = api.base + "edge?collection=" + edgeCollection; - console.log(api.node); + api.edge = api.base + "edge?collection=" + edgeCollection; }; } \ No newline at end of file diff --git a/html/admin/js/graphViewer/jasmine_test/runnerArangoAdapter.html b/html/admin/js/graphViewer/jasmine_test/runnerArangoAdapter.html index 2ff8107728..087559bd42 100644 --- a/html/admin/js/graphViewer/jasmine_test/runnerArangoAdapter.html +++ b/html/admin/js/graphViewer/jasmine_test/runnerArangoAdapter.html @@ -6,6 +6,7 @@ + @@ -14,16 +15,21 @@ + + + + + diff --git a/html/admin/js/graphViewer/jasmine_test/specAdapter/arangoAdapterUISpec.js b/html/admin/js/graphViewer/jasmine_test/specAdapter/arangoAdapterUISpec.js index a28d93882c..8955aa2244 100644 --- a/html/admin/js/graphViewer/jasmine_test/specAdapter/arangoAdapterUISpec.js +++ b/html/admin/js/graphViewer/jasmine_test/specAdapter/arangoAdapterUISpec.js @@ -43,14 +43,32 @@ beforeEach(function () { adapter = { - + changeTo: function(){} }; list = document.createElement("ul"); document.body.appendChild(list); list.id = "control_list"; adapterUI = new ArangoAdapterControls(list, adapter); spyOn(adapter, 'changeTo'); - + this.addMatchers({ + toBeTag: function(name) { + var el = this.actual; + this.message = function() { + return "Expected " + el.tagName.toLowerCase() + " to be a " + name; + }; + return el.tagName.toLowerCase() === name; + }, + + toConformToListCSS: function() { + var li = this.actual, + a = li.firstChild, + lbl = a.firstChild; + expect(li).toBeTag("li"); + expect(a).toBeTag("a"); + expect(lbl).toBeTag("label"); + return true; + } + }); }); afterEach(function () { @@ -77,8 +95,8 @@ expect($("#control_collections_modal").length).toEqual(1); - $("#control_collections_nodes").attr("value", "newNodes"); - $("#control_collections_edges").attr("value", "newEdges"); + $("#control_collections_nodecollection").attr("value", "newNodes"); + $("#control_collections_edgecollection").attr("value", "newEdges"); helper.simulateMouseEvent("click", "control_collections_submit"); @@ -88,5 +106,10 @@ ); }); }); + + it('should be able to add all controls to the list', function() { + adapterUI.addAll(); + expect($("#control_list #control_collections").length).toEqual(1); + }); }); }()); \ No newline at end of file diff --git a/html/admin/js/graphViewer/ui/arangoAdapterControls.js b/html/admin/js/graphViewer/ui/arangoAdapterControls.js new file mode 100644 index 0000000000..8d16e1fafb --- /dev/null +++ b/html/admin/js/graphViewer/ui/arangoAdapterControls.js @@ -0,0 +1,66 @@ +/*jslint indent: 2, nomen: true, maxlen: 100, white: true plusplus: true */ +/*global $, _, d3*/ +/*global document*/ +/*global modalDialogHelper, uiComponentsHelper*/ +//////////////////////////////////////////////////////////////////////////////// +/// @brief Graph functionality +/// +/// @file +/// +/// DISCLAIMER +/// +/// Copyright 2010-2012 triagens GmbH, Cologne, Germany +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// +/// Copyright holder is triAGENS GmbH, Cologne, Germany +/// +/// @author Michael Hackstein +/// @author Copyright 2011-2013, triAGENS GmbH, Cologne, Germany +//////////////////////////////////////////////////////////////////////////////// +function ArangoAdapterControls(list, adapter) { + "use strict"; + + if (list === undefined) { + throw "A list element has to be given."; + } + if (adapter === undefined) { + throw "The ArangoAdapter has to be given."; + } + var self = this, + baseClass = "adapter"; + + this.addControlChangeCollections = function() { + var prefix = "control_collections", + idprefix = prefix + "_"; + uiComponentsHelper.createButton(baseClass, list, "Collections", prefix, function() { + modalDialogHelper.createModalDialog("Switch Collections", + idprefix, [{ + type: "text", + id: "nodecollection" + },{ + type: "text", + id: "edgecollection" + }], function () { + var nodes = $("#" + idprefix + "nodecollection").attr("value"), + edges = $("#" + idprefix + "edgecollection").attr("value"); + adapter.changeTo(nodes, edges); + } + ); + }); + }; + + this.addAll = function() { + this.addControlChangeCollections(); + }; +} \ No newline at end of file