[wip] composer nsd

Change-Id: Iba2924273ab065c90ce85c5d41de90ff15f915d1
Signed-off-by: lombardofr <lombardo@everyup.it>
diff --git a/static/TopologyComposer/css/composer.css b/static/TopologyComposer/css/composer.css
index e7ecc59..12be9e7 100644
--- a/static/TopologyComposer/css/composer.css
+++ b/static/TopologyComposer/css/composer.css
@@ -221,4 +221,8 @@
     padding-left: 0;
     font-weight: 500;
     text-align: right
+}
+
+.left-tool-bar-monitoring > .btn-default {
+    background-color: transparent!important;
 }
\ No newline at end of file
diff --git a/static/TopologyComposer/js/graph_editor.js b/static/TopologyComposer/js/graph_editor.js
index ff4a21f..50e4f44 100755
--- a/static/TopologyComposer/js/graph_editor.js
+++ b/static/TopologyComposer/js/graph_editor.js
@@ -396,12 +396,13 @@
         //log(data)
         var self = this;
 
-        this.link = this.svg
+        var link = this.svg
             .selectAll()
             .data(self.d3_graph.links
                 .filter(this.link_filter_cb)
-            )
-            .enter().append("g")
+            );
+        link.exit().remove();
+         this.link = link.enter().append("g")
             .attr("class", "link cleanable")
             .append("path")
             .attr("class", "link")
@@ -418,24 +419,26 @@
                 return (d.directed_edge ? "url(#" + marker_url + ")" : '');
             });
 
-        this.nodeContainer = this.svg
+        var nodeContainer = this.svg
             .selectAll()
             .data(self.d3_graph.nodes
-                .filter(this.node_filter_cb))
-            .enter()
+                .filter(this.node_filter_cb));
+        nodeContainer.exit().remove();
+        nodeContainer.enter()
             .append("g")
             // .attr("class", "nodosdads")
             .attr("class", "node cleanable");
 
-        this.svg.selectAll('.node')
+        var nodes_symbols = this.svg.selectAll('.node')
             .data(self.d3_graph.nodes
                 .filter(this.node_filter_cb))
 
             .filter(function (d) {
                 return (d.info.type === undefined) || (self._node_property_by_type(d.info.type, 'image', d) === undefined)
-            })
+            });
+            nodes_symbols.exit().remove();
 
-            .append("svg:path")
+            nodes_symbols.append("svg:path")
             .attr("d", d3.symbol()
                 .size(function (d) {
                     return Math.PI * Math.pow(self._node_property_by_type(d.info.type, 'size', d), 2) / 4;
@@ -471,7 +474,7 @@
             .filter(function (d) {
                 return self._node_property_by_type(d.info.type, 'image', d) != undefined
             });
-
+            figure_node.exit().remove();
         figure_node.append("svg:image")
             .attr("xlink:href", function (d) {
                 return self._node_property_by_type(d.info.type, 'image', d)
diff --git a/static/TopologyComposer/js/model_graph_editor.js b/static/TopologyComposer/js/model_graph_editor.js
index 6cee85d..fd80822 100644
--- a/static/TopologyComposer/js/model_graph_editor.js
+++ b/static/TopologyComposer/js/model_graph_editor.js
@@ -118,23 +118,26 @@
      * @returns {boolean}
      */
     ModelGraphEditor.prototype.updateData = function (args) {
-        this.d3_graph.nodes = args.graph_data.vertices;
-        this.d3_graph.links = args.graph_data.edges;
-        this.d3_graph.graph_parameters = args.graph_data.graph_parameters;
+        this.d3_graph.nodes = args.vertices;
+        this.d3_graph.links = args.edges;
+        this.d3_graph.graph_parameters = args.graph_parameters;
         this.model = args.model;
         this.refreshGraphParameters(this.d3_graph.graph_parameters);
+        this.cleanAll();
         this.refresh();
         this.startForce();
+        this.handleForce(this.forceSimulationActive);
+        //this.force.restart();
         //if(args.filter_base != undefined)
 
-        //if(args.filter_base){
-        var self = this;
-        setTimeout(function () {
-            self.handleForce(true);
-            self.handleFiltersParams(args.filter_base);
-        }, 500);
-        //}
-    }
+        if(args.filter_base){
+            var self = this;
+            setTimeout(function () {
+                self.handleForce(true);
+                self.handleFiltersParams(args.filter_base);
+            }, 500);
+        }
+    };
 
     /**
      * Add a new node to the graph.
@@ -145,13 +148,16 @@
         var self = this;
         var current_layer = self.getCurrentView();
         var node_type = node.info.type;
-
         if (self.model.layer[current_layer] && self.model.layer[current_layer].nodes[node_type] && self.model.layer[current_layer].nodes[node_type].addable) {
             if (self.model.layer[current_layer].nodes[node_type].addable.callback) {
+                console.log(self.model.callback)
                 var c = self.model.callback[self.model.layer[current_layer].nodes[node_type].addable.callback].class;
-                var controller = new TCD3[c]();
-                controller[self.model.layer[current_layer].nodes[node_type].addable.callback](self, node, function () {
-                    self.parent.addNode.call(self, node);
+                var controller = new TCD3.OsmController();
+                controller[self.model.layer[current_layer].nodes[node_type].addable.callback](self, node, function (result) {
+                    console.log(result)
+                    console.log(node)
+                    self.updateData(result);
+                    // self.parent.addNode.call(self, node);
                     success && success();
                 }, error);
 
@@ -173,9 +179,24 @@
      * @param {Object} Required. An object that specifies tha data of the node.
      * @returns {boolean}
      */
-    ModelGraphEditor.prototype.updateDataNode = function (args) {
-        //FIXME updating a node properties need commit to server side!
-        this.parent.updateDataNode.call(this, args);
+    ModelGraphEditor.prototype.updateDataNode = function (node, args, success, error) {
+        console.log(node)
+        var controller = new  TCD3.OsmController();
+        controller.updateNode(this,node, args, function(){
+
+        }, error);
+    };
+
+    /**
+     * Update the data properties of the node
+     * @param {Object} Required. An object that specifies tha data of the node.
+     * @returns {boolean}
+     */
+    ModelGraphEditor.prototype.updateGraphParams = function (args, success, error) {
+        var controller = new  TCD3.OsmController();
+        controller.updateGraphParams(args, function(){
+
+        }, error);
     };
 
     /**
@@ -194,7 +215,7 @@
         if (self.model.layer[current_layer] && self.model.layer[current_layer].nodes[node_type] && self.model.layer[current_layer].nodes[node_type].removable) {
             if (self.model.layer[current_layer].nodes[node_type].removable.callback) {
                 var c = self.model.callback[self.model.layer[current_layer].nodes[node_type].removable.callback].class;
-                var controller = new TCD3[c]();
+                var controller = new  TCD3.OsmController();
                 controller[self.model.layer[current_layer].nodes[node_type].removable.callback](self, node, function () {
                     self.parent.removeNode.call(self, node);
                     success && success();
@@ -239,7 +260,7 @@
                 var direct_edge = 'direct_edge' in self.model.layer[current_layer].allowed_edges[source_type].destination[destination_type] ? self.model.layer[current_layer].allowed_edges[source_type].destination[destination_type]['direct_edge'] : false;
                 link.directed_edge = direct_edge;
                 var c = self.model.callback[callback].class;
-                var controller = new TCD3[c]();
+                var controller = new  TCD3.OsmController();
                 controller[callback](self, link, function () {
                     self._deselectAllNodes();
                     self.parent.addLink.call(self, link);
@@ -270,14 +291,14 @@
         var d = link.target;
         var source_type = s.info.type;
         var destination_type = d.info.type;
-        var current_layer = self.getCurrentView()
+        var current_layer = self.getCurrentView();
         if (self.model.layer[current_layer].allowed_edges && self.model.layer[current_layer].allowed_edges[source_type] && self.model.layer[current_layer].allowed_edges[source_type].destination[destination_type] &&
             self.model.layer[current_layer].allowed_edges[source_type].destination[destination_type].removable
         ) {
             if (self.model.layer[current_layer].allowed_edges[source_type].destination[destination_type].removable.callback) {
                 var callback = self.model.layer[current_layer].allowed_edges[source_type].destination[destination_type].removable.callback;
                 var c = self.model.callback[callback].class;
-                var controller = new TCD3[c]();
+                var controller = new  TCD3.OsmController();
                 controller[callback](self, link, function () {
                     self._deselectAllNodes();
                     self._deselectAllLinks();
@@ -326,16 +347,7 @@
             },
             edit_mode: true
         }];
-        var contextMenuNodesAction = [{
-            title: 'Edit',
-            action: function (elm, d, i) {
-                if (d.info.type != undefined) {
-                    self.eventHandler.fire("edit_descriptor", self.project_id, d);
-                }
-            },
-            nodes: [],
-            edit_mode: true
-        },
+        var contextMenuNodesAction = [
             {
                 title: 'Delete',
                 action: function (elm, d, i) {
@@ -405,7 +417,6 @@
             'links': {
                 'click': function (d) {
                     self._selectLinkExclusive(this, d);
-
                 },
                 'dblclick': function (event) {
 
@@ -448,7 +459,6 @@
 
     ModelGraphEditor.prototype.getCurrentGroup = function () {
         return this.filter_parameters.node.group[0];
-
     };
 
     ModelGraphEditor.prototype.getCurrentView = function () {
diff --git a/static/css/lwui.css b/static/css/lwui.css
index 858666d..1b12db5 100644
--- a/static/css/lwui.css
+++ b/static/css/lwui.css
@@ -1,4 +1,13 @@
 .skin-purple .sidebar-menu > li.menu-open > a {
   color: #b8c7ce !important;
   background: #1e282c;
+}
+
+.help-key {
+    border: 1px solid #ddd;
+    padding: 4px;
+    border-radius: 3px;
+    background: #f6f6f6;
+    font-family: Courier, monospace;
+    box-shadow: #999 1px 1px 1px;
 }
\ No newline at end of file
diff --git a/static/src/descriptorhandler/composer.js b/static/src/descriptorhandler/composer.js
index a21c14f..175f46b 100644
--- a/static/src/descriptorhandler/composer.js
+++ b/static/src/descriptorhandler/composer.js
@@ -22,6 +22,13 @@
     "vnfd": ["vdu", "cp", "vnf_vl", "int_cp"]
 };
 
+var map = {
+    'ip-address': 'IP', 'vnfd-id': 'Vnfd Id', 'vnfd-ref': 'Vnfd Ref', 'vim-account-id': 'Vim Id',
+    'member-vnf-index-ref': 'Member index', 'created-time': 'Created', 'id': 'Id', 'mgmt-network': 'Mgmt network',
+    'name': 'Name', 'type': 'Type', 'vim-network-name': 'Vim network name', 'connection-point-id': 'Cp Id',
+    'vdu-id-ref': 'Vdu Id', 'nsr-id-ref': 'Nsr Id'
+};
+
 var params = {
     node: {
         type: type_view[getUrlParameter('type')],
@@ -47,17 +54,108 @@
         data_url: window.location.href,
         //desc_id: getUrlParameter('id'),
         gui_properties: osm_gui_properties,
-        edit_mode: false,
+        edit_mode: true,
         behaviorsOnEvents: {
             viewBased: false,
             behaviors: buildBehaviorsOnEvents()
         }
     });
     graph_editor.handleFiltersParams(params);
+    initDropOnGraph();
 
+
+    $("#side_form").submit(function (event) {
+        event.preventDefault(); //prevent default action
+        console.log("ON submit")
+        var form_data = new FormData(this); //Encode form elements for submission
+        var formDataJson = {};
+        form_data.forEach(function (value, key) {
+            formDataJson[key] = value;
+        });
+        if (graph_editor._selected_node) {
+            graph_editor.updateDataNode(graph_editor._selected_node, formDataJson, function () {
+
+            }, function (result) {
+                var data = result.responseJSON;
+                var title = "Error " + (data && data.code ? data.code : 'unknown');
+                var message = data && data.detail ? data.detail : 'No detail available.';
+                bootbox.alert({
+                    title: title,
+                    message: message
+                });
+            })
+        } else {
+            graph_editor.updateGraphParams(formDataJson, function () {
+
+            }, function (result) {
+                var data = result.responseJSON;
+                var title = "Error " + (data && data.code ? data.code : 'unknown');
+                var message = data && data.detail ? data.detail : 'No detail available.';
+                bootbox.alert({
+                    title: title,
+                    message: message
+                });
+            })
+        }
+
+    });
 });
 
 
+function initDropOnGraph() {
+
+    var dropZone = document.getElementById('graph_editor_container');
+    dropZone.ondrop = function (e) {
+        var group = graph_editor.getCurrentGroup();
+        e.preventDefault();
+        var elemet_id = e.dataTransfer.getData("text/plain");
+
+        var nodetype = $('#' + elemet_id).attr('type-name');
+        var random_name = nodetype + "_" + generateUID();
+
+        var node_information = {
+            'id': random_name,
+            'info': {
+                'type': nodetype,
+                'property': {
+                    'custom_label': random_name
+                },
+                'group': null,
+                'desc_id': getUrlParameter('id'),
+                'desc_type': getUrlParameter('type'),
+                'osm': {}
+            },
+            'x': e.layerX,
+            'y': e.layerY
+        };
+        if (nodetype === 'ns_vl') {
+
+            graph_editor.addNode(node_information, function () {
+                console.log("OK")
+            }, function (error) {
+                showAlert(error)
+            })
+        } else if (nodetype === 'vnf') {
+            node_information['id'] = $('#' + elemet_id).attr('desc_id');
+            graph_editor.addNode(node_information, function () {
+                console.log("OK")
+            }, function (error) {
+                showAlert(error)
+            })
+        }
+    };
+
+    dropZone.ondragover = function (ev) {
+        console.log("ondragover");
+        return false;
+    };
+
+    dropZone.ondragleave = function () {
+        console.log("ondragleave");
+        return false;
+    };
+}
+
 
 function handleForce(el) {
     graph_editor.handleForce((el.getAttribute('aria-pressed') === "true"));
@@ -66,8 +164,9 @@
 function changeFilter(e, c) {
     if (c && c.link && c.link.view[0]) {
         updateLegend(c.link.view[0]);
+        updatePalette(c.link.view[0]);
     }
-    //layerDetails(graph_editor.getCurrentFilters())
+    layerDetails(graph_editor.getCurrentFilters())
 }
 
 function resetFilters() {
@@ -75,37 +174,7 @@
 }
 
 function buildBehaviorsOnEvents() {
-    var self = this;
-    var contextmenuNodesAction = [
-        {
-            title: 'Explore',
-            action: function (elm, c_node, i) {
-                if (c_node.info.type !== undefined) {
-                    var current_layer_nodes = Object.keys(graph_editor.model.layer[graph_editor.getCurrentView()].nodes);
-                    if (current_layer_nodes.indexOf(c_node.info.type) >= 0) {
-                        if (graph_editor.model.layer[graph_editor.getCurrentView()].nodes[c_node.info.type].expands) {
-                            var new_layer = graph_editor.model.layer[graph_editor.getCurrentView()].nodes[c_node.info.type].expands;
-                            graph_editor.handleFiltersParams({
-                                node: {
-                                    type: Object.keys(graph_editor.model.layer[new_layer].nodes),
-                                    group: [c_node.id]
-                                },
-                                link: {
-                                    group: [c_node.id],
-                                    view: [new_layer]
-                                }
-                            });
-
-                        }
-                        else {
-                            showAlert('This is not an explorable node.')
-                        }
-                    }
-                }
-            },
-            edit_mode: false
-        }];
-
+    var contextmenuNodesAction = [];
     return {
         'nodes': contextmenuNodesAction
     };
@@ -115,7 +184,7 @@
 function refreshElementInfo(event, element) {
     if (event.type === 'node:selected') {
         switch (element.info.type) {
-            case 'vnfd':
+            case 'vnf':
                 vnfDetails(element.info.osm);
                 break;
             case 'vdu':
@@ -137,19 +206,18 @@
 }
 
 function layerDetails(filters) {
-    var side = $('#side');
+    var side = $('#side_form');
     var graph_parameters = graph_editor.getGraphParams();
     var layer_template = '';
-    console.log(graph_parameters)
-    if(graph_parameters['view'] && filters.link.view.length >0 && filters.link.view[0]){
-        if(filters.link.view[0] === 'nsr') {
-            layer_template = getMainSection('NS View');
-            layer_template += getChildrenTable(graph_parameters['view']['nsr']);
+    if (graph_parameters['view'] && filters.link.view.length > 0 && filters.link.view[0]) {
+        if (filters.link.view[0] === 'nsd') {
+            layer_template = getMainSectionWithSubmitButton('NSD');
+            layer_template += getChildrenTable(graph_parameters['view']['nsd']);
         }
-        else if(filters.link.view[0] === 'vnfr') {
-            layer_template = getMainSection('VNF View');
-            var vnfr_id = filters.link.group[0];
-            layer_template += getChildrenTable(graph_parameters['view']['vnfr'][vnfr_id]);
+        else if (filters.link.view[0] === 'vnfd') {
+            layer_template = getMainSectionWithSubmitButton('VNFD');
+
+            layer_template += getChildrenTable(graph_parameters['view']['vnfd']);
         }
     }
 
@@ -162,12 +230,12 @@
     var nodes = type_view[view];
     var legend_template = '';
     var nodes_properties = osm_gui_properties['nodes'];
-    for (var n in nodes){
+    for (var n in nodes) {
         var node = nodes[n];
-        if(nodes_properties[node]){
+        if (nodes_properties[node]) {
             legend_template += '<div class="node">' +
-                '<div class="icon" style="background-color:' + nodes_properties[node].color +'"></div>' +
-                '<div class="name">' +nodes_properties[node].name + '</div></div>';
+                '<div class="icon" style="background-color:' + nodes_properties[node].color + '"></div>' +
+                '<div class="name">' + nodes_properties[node].name + '</div></div>';
         }
     }
 
@@ -176,48 +244,74 @@
 
 }
 
-var map = {
-    'ip-address': 'IP', 'vnfd-id': 'Vnfd Id', 'vnfd-ref': 'Vnfd Ref', 'vim-account-id': 'Vim Id',
-    'member-vnf-index-ref': 'Member index', 'created-time': 'Created', 'id': 'Id', 'mgmt-network': 'Mgmt network',
-    'name': 'Name', 'type': 'Type', 'vim-network-name': 'Vim network name', 'connection-point-id': 'Cp Id',
-    'vdu-id-ref': 'Vdu Id', 'nsr-id-ref': 'Nsr Id'
-};
+function updatePalette(view) {
+    var palette = $('#palette');
+    var palette_template = '';
+    palette.empty();
+    if (view === 'vnfd') {
+        var nodes = type_view[view];
+        var nodes_properties = osm_gui_properties['nodes'];
+        for (var n in nodes) {
+            var node = nodes[n];
+            if (nodes_properties[node]) {
+                palette_template += '<div id="drag_' + n + '" class="node ui-draggable"' +
+                    'type-name="' + n + '" draggable="true" ondragstart="nodeDragStart(event)">' +
+                    '<div class="icon" style="background-color:' + nodes_properties[node].color + '"></div>' +
+                    '<div class="name">' + nodes_properties[node].name + '</div></div>';
+            }
+        }
+
+        palette.append(palette_template)
+    } else if (view === 'nsd') {
+        $.ajax({
+            url: '/projects/descriptors/composer/availablenodes?layer=nsd',
+            type: 'GET',
+            cache: false,
+            success: function (result) {
+                palette_template += '<div id="drag_ns_vl" class="node ui-draggable"' +
+                    'type-name="ns_vl" draggable="true" ondragstart="nodeDragStart(event)">' +
+                    '<div class="icon" style="background-color:' + osm_gui_properties['nodes']['ns_vl'].color + '"></div>' +
+                    '<div class="name">' + osm_gui_properties['nodes']['ns_vl'].name + '</div></div>';
+                palette_template += getSubSection('VNFD');
+                for (var d in result['descriptors']) {
+                    var desc = result['descriptors'][d];
+                    palette_template += '<div id="drag_' + desc.id + '" class="node ui-draggable"' +
+                        'type-name="vnf" desc_id="' + desc.id + '" draggable="true" ondragstart="nodeDragStart(event)">' +
+                        '<div class="icon" style="background-color:#605ca8"></div>' +
+                        '<div class="name">' + desc.name + '</div></div>';
+                }
+                palette.append(palette_template)
+            },
+            error: function (result) {
+                showAlert(result);
+            }
+        });
+    }
+
+}
+
 
 function vnfDetails(vnfr) {
-    var side = $('#side');
+    var side = $('#side_form');
     var vnfr_template = getMainSection('VNF');
 
-    vnfr_template += getChildrenTable(vnfr);
+    vnfr_template += getChildrenTable(vnfr, true);
     side.empty();
     side.append(vnfr_template)
 }
 
 function vduDetails(vdur) {
-    var side = $('#side');
-    var vdur_template = getMainSectionWithStatus('VDU', vdur['status'] === 'ACTIVE');
+    var side = $('#side_form');
+    var vdur_template = getMainSectionWithSubmitButton('VDU');
     vdur_template += getChildrenTable(vdur);
 
-    if (vdur['interface'] && vdur['interface'].length > 0) {
-        vdur_template += getSubSection('Interfaces:');
-        vdur_template += '<table class="children">';
-
-        for (var i = 0; i < vdur['interface'].length; ++i) {
-            var interface = vdur['interface'][i];
-            var interface_template = '<tr><td>' + interface['name'] + '</td>'
-                + '<td>IP:' + interface['ip-address'] + '</td>'
-                + '<td>MAC:' + interface['mac-address'] + '</td>';
-            vdur_template += interface_template;
-        }
-        vdur_template += '</table>';
-    }
-
     side.empty();
     side.append(vdur_template)
 }
 
 function cpDetails(cp) {
-     var side = $('#side');
-    var cp_template = getMainSection('Connection Point');
+    var side = $('#side_form');
+    var cp_template = getMainSectionWithSubmitButton('Connection Point');
 
     cp_template += getChildrenTable(cp);
     side.empty();
@@ -225,8 +319,8 @@
 }
 
 function vlDetails(vl) {
-    var side = $('#side');
-    var vl_template = getMainSection('Virtual Link');
+    var side = $('#side_form');
+    var vl_template = getMainSectionWithSubmitButton('Virtual Link');
 
     vl_template += getChildrenTable(vl);
     side.empty();
@@ -238,6 +332,11 @@
     return '<div class="section"><span style="font-weight: 500;">' + title + '</span></div>';
 }
 
+function getMainSectionWithSubmitButton(title) {
+    return '<div class="section"><span style="font-weight: 500;">' + title + '</span>' +
+        '<div class="status"><button id="update_button" class="btn btn-xs btn-default" ><i class="fa fa-save"></i> SAVE</button></div></div>';
+}
+
 function getSubSection(title) {
     return '<div class="section"><span>' + title + '</span></div>';
 }
@@ -252,15 +351,27 @@
     return template;
 }
 
-function getChildrenTable(data) {
+function getChildrenTable(data, ro) {
     var template = '<table class="children">';
 
     for (var key in data) {
-        if (typeof data[key] === 'string') {
+        if (typeof data[key] !== 'object') {
             var key_map = (map[key]) ? map[key] : key;
-            template += '<tr><td>' + key_map + '</td><td><input name="'+key+'" class="form-control input-sm" type="text"  value="' + data[key] + '"></td></tr>';
+            if (ro)
+                template += '<tr><td>' + key_map + '</td><td>' + data[key] + '</td></tr>';
+            else
+                template += '<tr><td>' + key_map + '</td><td><input name="' + key + '" class="form-control input-sm" type="text"  value="' + data[key] + '"></td></tr>';
+
         }
     }
     template += '</table>';
     return template;
+}
+
+function openHelp() {
+    $('#modalTopologyInfoButton').modal('show');
+}
+
+function openTextedit() {
+    window.location.href = '/projects/descriptors/' + getUrlParameter('type') + '/' + getUrlParameter('id')
 }
\ No newline at end of file
diff --git a/static/src/descriptorhandler/controller.js b/static/src/descriptorhandler/controller.js
new file mode 100644
index 0000000..3a96ea2
--- /dev/null
+++ b/static/src/descriptorhandler/controller.js
@@ -0,0 +1,209 @@
+if (typeof TCD3 === 'undefined') {
+    var TCD3 = {};
+}
+
+TCD3.OsmController = (function (global) {
+    'use strict';
+
+    var DEBUG = true;
+
+    OsmController.prototype.constructor = OsmController;
+
+    /**
+     * Constructor
+     */
+    function OsmController() {
+
+
+    }
+
+
+    OsmController.prototype.addNode = function (graph_editor, node, success, error) {
+        log('addNode');
+        var element_type = node.info.type;
+        var desc_id = node.info.desc_id;
+        var desc_type = node.info.desc_type;
+        var data_form = new FormData();
+        data_form.append('csrfmiddlewaretoken', getCookie('csrftoken'));
+        for (var key in node) {
+            data_form.append(key, node[key]);
+        }
+        $.ajax({
+            url: '/projects/descriptors/' + desc_type + '/' + desc_id + '/addElement/' + element_type,
+            type: 'POST',
+            data: data_form,
+            cache: false,
+            contentType: false,
+            processData: false,
+            success: success,
+            error: error
+        });
+    };
+
+    OsmController.prototype.addLink = function (graph_editor, link, success, error) {
+        log('addLink');
+
+        var data_to_send = {
+            'desc_id': link.desc_id,
+            'source': link.source.id,
+            'source_type': link.source.info.type,
+            'target': link.target.id,
+            'target_type': link.target.info.type,
+            'view': link.view,
+            'group': link.group
+        };
+
+        var desc_id = getUrlParameter('id');
+        var desc_type = getUrlParameter('type');
+        if (desc_type === 'nsd') {
+            var element_type = 'cp';
+            var data_form = new FormData();
+
+            var vnfd_node = (link.source.info.type === 'vnf') ? link.source : link.target;
+            var vld_node = (link.source.info.type === 'ns_vl') ? link.source : link.target;
+
+            data_form.append('csrfmiddlewaretoken', getCookie('csrftoken'));
+            data_form.append('vnfd-connection-point-ref', 'cp_temp');
+            data_form.append('member-vnf-index-ref', vnfd_node.info.osm['member-vnf-index']);
+            data_form.append('vnfd-id-ref', vnfd_node.info.osm['vnfd-id-ref']);
+            data_form.append('vld_id', vld_node.info.osm['id']);
+
+            $.ajax({
+                url: '/projects/descriptors/' + desc_type + '/' + desc_id + '/addElement/' + element_type,
+                type: 'POST',
+                data: data_form,
+                cache: false,
+                contentType: false,
+                processData: false,
+                success: success,
+                error: error
+            });
+        }
+
+    };
+
+    OsmController.prototype.removeNode = function (graph_editor, node, success, error) {
+        log('removeNode');
+        var desc_id = getUrlParameter('id');
+        var desc_type = getUrlParameter('type');
+        var element_type = node['info']['type'];
+        var data_form = new FormData();
+        data_form.append('csrfmiddlewaretoken', getCookie('csrftoken'));
+        for (var key in node.info.osm) {
+            data_form.append(key, node.info.osm[key]);
+        }
+
+        $.ajax({
+            url: '/projects/descriptors/' + desc_type + '/' + desc_id + '/removeElement/' + element_type,
+            type: 'POST',
+            data: data_form,
+            cache: false,
+            contentType: false,
+            processData: false,
+            success: success,
+            error: error
+        });
+
+    };
+
+    OsmController.prototype.updateNode = function (graph_editor, node, args, success, error) {
+        log('updateNode');
+        var desc_id = getUrlParameter('id');
+        var desc_type = getUrlParameter('type');
+        var element_type = node['info']['type'];
+        console.log(args)
+        var data_form = new FormData();
+        data_form.append('csrfmiddlewaretoken', getCookie('csrftoken'));
+        data_form.append('old', JSON.stringify( node.info.osm));
+        data_form.append('update', JSON.stringify(args));
+        /*for (var key in node.info.osm) {
+            data_form.append(key, node.info.osm[key]);
+        }
+        */
+
+        $.ajax({
+            url: '/projects/descriptors/' + desc_type + '/' + desc_id + '/updateElement/' + element_type,
+            type: 'POST',
+            data: data_form,
+            cache: false,
+            contentType: false,
+            processData: false,
+            success: success,
+            error: error
+        });
+
+    };
+
+    OsmController.prototype.updateGraphParams = function(args, success, error){
+        var desc_id = getUrlParameter('id');
+        var desc_type = getUrlParameter('type');
+        var data_form = new FormData();
+        data_form.append('csrfmiddlewaretoken', getCookie('csrftoken'));
+        data_form.append('update', JSON.stringify(args));
+        $.ajax({
+            url: '/projects/descriptors/' + desc_type + '/' + desc_id + '/updateElement/graph_params',
+            type: 'POST',
+            data: data_form,
+            cache: false,
+            contentType: false,
+            processData: false,
+            success: success,
+            error: error
+        });
+    };
+
+    OsmController.prototype.removeLink = function (graph_editor, link, success, error) {
+        log('removeLink');
+        var data_to_send = {
+            'desc_id': link.desc_id,
+            'source': link.source.id,
+            'source_type': link.source.info.type,
+            'target': link.target.id,
+            'target_type': link.target.info.type,
+            'view': link.view,
+            'group': link.group
+        };
+
+        var desc_id = getUrlParameter('id');
+        var desc_type = getUrlParameter('type');
+
+        if (desc_type === 'nsd') {
+            var element_type = 'cp';
+            var data_form = new FormData();
+
+            var vnfd_node = (link.source.info.type === 'vnf') ? link.source : link.target;
+            var vld_node = (link.source.info.type === 'ns_vl') ? link.source : link.target;
+
+            data_form.append('csrfmiddlewaretoken', getCookie('csrftoken'));
+            data_form.append('vnfd-connection-point-ref', 'cp_temp');
+            data_form.append('member-vnf-index-ref', vnfd_node.info.osm['member-vnf-index']);
+            data_form.append('vnfd-id-ref', vnfd_node.info.osm['vnfd-id-ref']);
+            data_form.append('vld_id', vld_node.info.osm['id']);
+
+            $.ajax({
+                url: '/projects/descriptors/' + desc_type + '/' + desc_id + '/removeElement/' + element_type,
+                type: 'POST',
+                data: data_form,
+                cache: false,
+                contentType: false,
+                processData: false,
+                success: success,
+                error: error
+            });
+        }
+    };
+
+    /**
+     * Log utility
+     */
+    function log(text) {
+        if (DEBUG)
+            console.log("::OsmController::", text);
+    }
+
+    return OsmController;
+}(this));
+
+if (typeof module === 'object') {
+    module.exports = TCD3.OsmController;
+}
\ No newline at end of file
diff --git a/static/src/instancehandler/instance_topology_view.js b/static/src/instancehandler/instance_topology_view.js
index 99bb986..95239e3 100644
--- a/static/src/instancehandler/instance_topology_view.js
+++ b/static/src/instancehandler/instance_topology_view.js
@@ -26,7 +26,7 @@
         'config-status': 'Config status',
         'detailed-status': 'Detailed status',
         'create-time': 'Creation date',
-        'instantiate_params' :'Instantiation parameters'
+       // 'instantiate_params' :'Instantiation parameters'
     },
     'vnfr': {
         'id':  'VNF instance id',
@@ -170,6 +170,8 @@
                     var field_value = graph_parameters['view']['nsr'][key];
                     if(key === 'create-time'){
                         field_value = moment.unix(field_value).toISOString();
+                    } else if (key === 'instantiate_params'){
+                        field_value = JSON.stringify(field_value);
                     }
                     layer_template += '<tr><td>' + layer_map['nsr'][key] + '</td><td>' + field_value + '</td></tr>';
                 }