Merge "Ensuring that SET_DL_* action with openflowj only uses OFP_ETH_ALEN bytes...
[controller.git] / opendaylight / web / flows / src / main / resources / js / page.js
1
2 /*
3  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
4  *
5  * This program and the accompanying materials are made available under the
6  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
7  * and is available at http://www.eclipse.org/legal/epl-v10.html
8  */
9
10 //PAGE flows
11 one.f = {};
12
13 // specify dashlets and layouts
14 one.f.dashlet = {
15     flows : {
16         id : 'flows',
17         name : 'Flow Entries'
18     },
19     nodes : {
20         id : 'nodes',
21         name : 'Nodes'
22     },
23     detail : {
24         id : 'detail',
25         name : 'Flow Detail'
26     }
27 };
28
29 one.f.menu = {
30     left : {
31         top : [
32             one.f.dashlet.flows
33         ],
34         bottom : [
35             one.f.dashlet.nodes
36         ]
37     },
38     right : {
39         top : [],
40         bottom : [
41             one.f.dashlet.detail
42         ]
43     }
44 };
45
46 one.f.address = {
47     root : "/controller/web/flows",
48     flows : {
49         main : "/main",
50                 flows : "/node-flows",
51         nodes : "/node-ports",
52         flow : "/flow"
53     }
54 }
55
56 /** NODES **/
57 one.f.nodes = {
58     id : {},
59     registry : {},
60     dashlet : function($dashlet) {
61         var $h4 = one.lib.dashlet.header("Nodes");
62         $dashlet.append($h4);
63
64         // load body
65         one.f.nodes.ajax.dashlet(function($table) {
66                         // total nodes count
67                         var nodeCount = $table.find('tbody').find('tr').size();
68                         // prompt output
69                         var nodeText = "node";
70                         var verb = "is";
71                         if (nodeCount != 1) {
72                                 nodeText += "s";
73                                 verb = "are";
74                         }
75                         var out = "There "+verb+" "+nodeCount+" "+nodeText;
76                         $p = $(document.createElement('p'));
77                         $p.append(out);
78                         $dashlet.append($p);
79             // add to dashlet
80             $dashlet.append($table);
81         });
82     },
83     ajax : {
84         dashlet : function(callback) {
85             $.getJSON(one.f.address.root+one.f.address.flows.flows, function(data) {
86                 var body = one.f.nodes.data.dashlet(data);
87                 var $body = one.f.nodes.body.dashlet(body, callback);
88                 callback($body);
89             });
90         }
91     },
92     data : {
93         dashlet : function(data) {
94             var body = [];
95             $.each(data, function(key, value) {
96                 var tr = {};
97                 var entry = [];
98                 entry.push(key);
99                 // parse ports
100                 entry.push(value);
101                 // add entry to tr
102                 tr['entry'] = entry;
103                 body.push(tr);
104             });
105             return body;
106         }
107     },
108     body : {
109         dashlet : function(body, callback) {
110             var attributes = ['table-striped', 'table-bordered', 'table-hover', 'table-condensed'];
111             var $table = one.lib.dashlet.table.table(attributes);
112
113             var headers = ['Node', 'Flows'];
114             var $thead = one.lib.dashlet.table.header(headers);
115             $table.append($thead);
116
117             var $tbody = one.lib.dashlet.table.body(body);
118             $table.append($tbody);
119
120             return $table;
121         }
122     }
123 }
124
125 /** FLOW DETAIL **/
126 one.f.detail = {
127     id : {},
128     registry : {},
129     dashlet : function($dashlet, details) {
130         var $h4 = one.lib.dashlet.header("Flow Details");
131         $dashlet.append($h4);
132
133         // details
134         if (details == undefined) {
135                 var $none = $(document.createElement('div'));
136                 $none.addClass('none');
137             var $p = $(document.createElement('p'));
138             $p.text('Please select a flow');
139             $p.addClass('text-center').addClass('text-info');
140
141             $dashlet.append($none)
142                 .append($p);
143         }
144     },
145     data : {
146                 dashlet : function(data) {
147                         var body = [];
148                         var tr = {};
149                         var entry = [];
150
151                         entry.push(data['name']);
152                         entry.push(data['node']);
153                         entry.push(data['flow']['priority']);
154                         entry.push(data['flow']['hardTimeout']);
155                         entry.push(data['flow']['idleTimeout']);
156
157                         tr.entry = entry;
158                         body.push(tr);
159                         return body;
160                 },
161         description : function(data) {
162                         var body = [];
163                         var tr = {};
164                         var entry = [];
165                         entry.push(data['flow']['ingressPort']);
166                         entry.push(data['flow']['etherType']);
167                         entry.push(data['flow']['vlanId']);
168                         entry.push(data['flow']['vlanPriority']);
169                         entry.push(data['flow']['srcMac']);
170                         entry.push(data['flow']['dstMac']);
171                         entry.push(data['flow']['srcIp']);
172                         entry.push(data['flow']['dstIp']);
173                         entry.push(data['flow']['tosBits']);
174                         entry.push(data['flow']['srcPort']);
175                         entry.push(data['flow']['dstPort']);
176                         entry.push(data['flow']['protocol']);
177                         entry.push(data['flow']['cookie']);
178
179                         tr.entry = entry;
180                         body.push(tr);
181                         return body;
182         },
183                 actions : function(data) {
184                         var body = [];
185                         var tr = {};
186                         var entry = [];
187
188                         var actions = '';
189                         $(data['flow']['actions']).each(function(index, value) {
190                                 actions += value + ', ';
191                         });
192                         actions = actions.slice(0,-2);
193                         entry.push(actions);
194
195                         tr.entry = entry;
196                         body.push(tr);
197                         return body;
198                 }
199     },
200     body : {
201         dashlet : function(body) {
202                         // create table
203                         var header = ['Flow Name', 'Node', 'Priority', 'Hard Timeout', 'Idle Timeout'];
204                         var $thead = one.lib.dashlet.table.header(header);
205                         var attributes = ['table-striped', 'table-bordered', 'table-condensed'];
206                         var $table = one.lib.dashlet.table.table(attributes);
207                         $table.append($thead);
208
209                         var $tbody = one.lib.dashlet.table.body(body);
210                         $table.append($tbody);
211
212             return $table;
213         },
214                 description : function(body) {
215                         var header = ['Input Port', 'Ethernet Type', 'VLAN ID', 'VLAN Priority', 'Source MAC', 'Dest MAC', 'Source IP', 'Dest IP', 'TOS', 'Source Port', 'Dest Port', 'Protocol', 'Cookie'];
216                         var $thead = one.lib.dashlet.table.header(header);
217                         var attributes = ['table-striped', 'table-bordered', 'table-condensed'];
218                         var $table = one.lib.dashlet.table.table(attributes);
219                         $table.append($thead);
220
221                         var $tbody = one.lib.dashlet.table.body(body);
222                         $table.append($tbody);
223
224             return $table;
225                 },
226                 actions : function(body) {
227                         var header = ['Actions'];
228                         var $thead = one.lib.dashlet.table.header(header);
229                         var attributes = ['table-striped', 'table-bordered', 'table-condensed'];
230                         var $table = one.lib.dashlet.table.table(attributes);
231                         $table.append($thead);
232
233                         var $tbody = one.lib.dashlet.table.body(body);
234                         $table.append($tbody);
235
236             return $table;
237                 }
238     }
239 }
240
241 /** FLOW ENTRIES **/
242 one.f.flows = {
243     id : {
244         dashlet : {
245             add : "one_f_flows_id_dashlet_add",
246             remove : "one_f_flows_id_dashlet_remove",
247             toggle : "one_f_flows_id_dashlet_toggle"
248         },
249         modal : {
250                         install : "one_f_flows_id_modal_install",
251             add : "one_f_flows_id_modal_add",
252             close : "one_f_flows_id_modal_close",
253             modal : "one_f_flows_id_modal_modal",
254             dialog : {
255                 modal : "one_f_flows_id_modal_dialog_modal",
256                 remove : "one_f_flows_id_modal_dialog_remove",
257                 close : "one_f_flows_id_modal_dialog_close"
258             },
259             action : {
260                 button : "one_f_flows_id_modal_action_button",
261                 modal : "one_f_flows_id_modal_action_modal",
262                 add : "one_f_flows_id_modal_action_add",
263                 close : "one_f_flows_id_modal_action_close",
264                 table : "one_f_flows_id_modal_action_table",
265                 addOutputPorts : "one_f_flows_id_modal_action_addOutputPorts",
266                 setVlanId : "one_f_flows_id_modal_action_setVlanId",
267                 setVlanPriority : "one_f_flows_id_modal_action_setVlanPriority",
268                 modifyDatalayerSourceAddress : "one_f_flows_id_modal_action_modifyDatalayerSourceAddress",
269                 modifyDatalayerDestinationAddress : "one_f_flows_id_modal_action_modifyDatalayerDestinationAddress",
270                 modifyNetworkSourceAddress : "one_f_flows_modal_action_modifyNetworkSourceAddress",
271                 modifyNetworkDestinationAddress : "one_f_flows_modal_action_modifyNetworkDestinationAddress",
272                 modifyTosBits : "one_f_flows_modal_action_modifyTosBits",
273                 modifyTransportSourcePort : "one_f_flows_modal_action_modifyTransportSourcePort",
274                 modifyTransportDestinationPort : "one_f_flows_modal_action_modifyTransportDestinationPort",
275                                 modal : {
276                                         modal : "one_f_flows_modal_action_modal_modal",
277                                         remove : "one_f_flows_modal_action_modal_remove",
278                                         cancel : "one_f_flows_modal_action_modal_cancel"
279                                 }
280             },
281             form : {
282                 name : "one_f_flows_id_modal_form_name",
283                 nodes : "one_f_flows_id_modal_form_nodes",
284                 port : "one_f_flows_id_modal_form_port",
285                 priority : "one_f_flows_id_modal_form_priority",
286                 hardTimeout : "one_f_flows_id_modal_form_hardTimeout",
287                                 idleTimeout : "one_f_flows_id_modal_form_idleTimeout",
288                                 cookie : "one_f_flows_id_modal_form_cookie",
289                 etherType : "one_f_flows_id_modal_form_etherType",
290                 vlanId : "one_f_flows_id_modal_form_vlanId",
291                 vlanPriority : "one_f_flows_id_modal_form_vlanPriority",
292                 srcMac : "one_f_flows_id_modal_form_srcMac",
293                 dstMac : "one_f_flows_id_modal_form_dstMac",
294                 srcIp : "one_f_flows_id_modal_form_srcIp",
295                 dstIp : "one_f_flows_id_modal_form_dstIp",
296                 tosBits : "one_f_flows_id_modal_form_tosBits",
297                 srcPort : "one_f_flows_id_modal_form_srcPort",
298                 dstPort : "one_f_flows_id_modal_form_dstPort",
299                 protocol : "one_f_flows_id_modal_form_protocol"
300             }
301         }
302     },
303     registry : {},
304     dashlet : function($dashlet, callback) {
305
306         // load body
307         one.f.flows.ajax.dashlet(function($table) {
308
309             var $h4 = one.lib.dashlet.header("Flow Entries");
310
311             $dashlet.append($h4);
312             if (one.f.flows.registry.privilege === 'WRITE') {
313                 var button = one.lib.dashlet.button.single("Add Flow Entry", one.f.flows.id.dashlet.add, "btn-primary", "btn-mini");
314                 var $button = one.lib.dashlet.button.button(button);
315
316                 $button.click(function() {
317                     var $modal = one.f.flows.modal.initialize();
318                     $modal.modal();
319                 });
320                 $dashlet.append($button);
321
322             }
323
324             // table bindings
325             $table.find('tbody').find('tr').click(function() {
326                 var id = $($(this).find('td')[0]).text();
327                 var node = $(this).data('id');
328                 one.f.flows.detail(id, node);
329             });
330
331                         // total flows
332                         var flowCount = $table.find('tbody').find('tr').size();
333                         // prompt output
334                         var flowText = "flow";
335                         var verb = "is";
336                         if (flowCount != 1) {
337                                 flowText += "s";
338                                 verb = "are";
339                         }
340                         var out = "There "+verb+" "+flowCount+" "+flowText;
341                         $p = $(document.createElement('p'));
342                         $p.append(out);
343                         $dashlet.append($p);
344             // add table to dashlet
345             $dashlet.append($table);
346             // details callback
347             if(callback != undefined) callback();
348         });
349     },
350     detail : function(id, node) {
351         // clear flow details
352         var $detailDashlet = one.main.dashlet.right.bottom;
353         $detailDashlet.empty();
354         var $h4 = one.lib.dashlet.header("Flow Overview");
355         $detailDashlet.append($h4);
356
357         // details
358         var flows = one.f.flows.registry.flows;
359         var flow;
360         $(flows).each(function(index, value) {
361             if (value['name'] == id) {
362                 flow = value;
363             }
364         });
365         if (one.f.flows.registry.privilege === 'WRITE') {
366                 // remove button
367                 var button = one.lib.dashlet.button.single("Remove Flow", one.f.flows.id.dashlet.remove, "btn-danger", "btn-mini");
368                 var $button = one.lib.dashlet.button.button(button);
369                 $button.click(function() {
370                     var $modal = one.f.flows.modal.dialog.initialize(id, node);
371                     $modal.modal();
372                 });
373                 // toggle button
374                 var toggle;
375                 if (flow['flow']['installInHw'] == 'true' && flow['flow']['status'] == 'Success') {
376                     toggle = one.lib.dashlet.button.single("Uninstall Flow", one.f.flows.id.dashlet.toggle, "btn-warning", "btn-mini");
377                 } else {
378                     toggle = one.lib.dashlet.button.single("Install Flow", one.f.flows.id.dashlet.toggle, "btn-success", "btn-mini");
379                 }
380                 var $toggle = one.lib.dashlet.button.button(toggle);
381                 $toggle.click(function() {
382                     one.f.flows.modal.ajax.toggleflow(id, node, function(data) {
383                         if(data == "Success") {
384                             one.main.dashlet.right.bottom.empty();
385                             one.f.detail.dashlet(one.main.dashlet.right.bottom);
386                             one.main.dashlet.left.top.empty();
387                                 one.f.flows.dashlet(one.main.dashlet.left.top, function() {
388                                    // checks are backwards due to stale registry
389                                    if(flow['flow']['installInHw'] == 'true') {
390                                        one.lib.alert('Uninstalled Flow');
391                                    } else {
392                                        one.lib.alert('Installed Flow');
393                                    }
394                                    one.f.flows.detail(id, node)
395                                 });
396                         } else {
397                             one.lib.alert('Cannot toggle flow: '+data);
398                         }
399                     });
400                 });
401
402                 $detailDashlet.append($button).append($toggle);
403         }
404         // append details
405         var body = one.f.detail.data.dashlet(flow);
406         var $body = one.f.detail.body.dashlet(body);
407         $detailDashlet.append($body);
408                 var body = one.f.detail.data.description(flow);
409                 var $body = one.f.detail.body.description(body);
410                 $detailDashlet.append($body);
411                 var body = one.f.detail.data.actions(flow);
412                 var $body = one.f.detail.body.actions(body);
413                 $detailDashlet.append($body);
414     },
415     modal : {
416         dialog : {
417             initialize : function(id, node) {
418                 var h3 = "Remove Flow?";
419                 var $p = one.f.flows.modal.dialog.body(id);
420                 var footer = one.f.flows.modal.dialog.footer();
421                 var $modal = one.lib.modal.spawn(one.f.flows.id.modal.dialog.modal, h3, $p, footer);
422                 $('#'+one.f.flows.id.modal.dialog.close, $modal).click(function() {
423                     $modal.modal('hide');
424                 });
425                 $('#'+one.f.flows.id.modal.dialog.remove, $modal).click(function() {
426                     one.f.flows.modal.ajax.removeflow(id, node, function(data) {
427                         if (data == "Success") {
428                             $modal.modal('hide');
429                             one.main.dashlet.right.bottom.empty();
430                             one.f.detail.dashlet(one.main.dashlet.right.bottom);
431                             one.main.dashlet.left.top.empty();
432                             one.f.flows.dashlet(one.main.dashlet.left.top);
433                             one.lib.alert('Flow removed');
434                         } else {
435                             one.lib.alert('Cannot remove flow: '+data);
436                         }
437                     });
438                 });
439                 return $modal;
440             },
441             footer : function() {
442                 var footer = [];
443
444                 var removeButton = one.lib.dashlet.button.single("Remove Flow", one.f.flows.id.modal.dialog.remove, "btn-danger", "");
445                 var $removeButton = one.lib.dashlet.button.button(removeButton);
446                 footer.push($removeButton);
447
448                 var closeButton = one.lib.dashlet.button.single("Cancel", one.f.flows.id.modal.dialog.close, "", "");
449                 var $closeButton = one.lib.dashlet.button.button(closeButton);
450                 footer.push($closeButton);
451
452                 return footer;
453             },
454             body : function(id) {
455                 var $p = $(document.createElement('p'));
456                 $p.append('Remove flow '+id+'?');
457                 return $p;
458             }
459         },
460         initialize : function() {
461             var h3 = "Add Flow Entry";
462             var footer = one.f.flows.modal.footer();
463             var $modal = one.lib.modal.spawn(one.f.flows.id.modal.modal, h3, "", footer);
464
465             // bind close button
466             $('#'+one.f.flows.id.modal.close, $modal).click(function() {
467                 $modal.modal('hide');
468             });
469
470             // bind add flow button
471             $('#'+one.f.flows.id.modal.add, $modal).click(function() {
472                 one.f.flows.modal.add($modal, 'false');
473             });
474
475             // bind install flow button
476             $('#'+one.f.flows.id.modal.install, $modal).click(function() {
477                 one.f.flows.modal.add($modal, 'true');
478             });
479
480             // inject body (nodePorts)
481             one.f.flows.modal.ajax.nodes(function(nodes, nodeports) {
482                 var $body = one.f.flows.modal.body(nodes, nodeports);
483                 one.lib.modal.inject.body($modal, $body);
484             });
485
486             return $modal;
487         },
488         add : function($modal, install) {
489             var result = {};
490
491             result['name'] = $('#'+one.f.flows.id.modal.form.name, $modal).val();
492             result['ingressPort'] = $('#'+one.f.flows.id.modal.form.port, $modal).val();
493             result['priority'] = $('#'+one.f.flows.id.modal.form.priority, $modal).val();
494             result['hardTimeout'] = $('#'+one.f.flows.id.modal.form.hardTimeout, $modal).val();
495                         result['idleTimeout'] = $('#'+one.f.flows.id.modal.form.idleTimeout, $modal).val();
496                         result['cookie'] = $('#'+one.f.flows.id.modal.form.cookie, $modal).val();
497             result['etherType'] = $('#'+one.f.flows.id.modal.form.etherType, $modal).val();
498             result['vlanId'] = $('#'+one.f.flows.id.modal.form.vlanId, $modal).val();
499             result['vlanPriority'] = $('#'+one.f.flows.id.modal.form.vlanPriority, $modal).val();
500             result['dlSrc'] = $('#'+one.f.flows.id.modal.form.srcMac, $modal).val();
501             result['dlDst'] = $('#'+one.f.flows.id.modal.form.dstMac, $modal).val();
502             result['nwSrc'] = $('#'+one.f.flows.id.modal.form.srcIp, $modal).val();
503             result['nwDst'] = $('#'+one.f.flows.id.modal.form.dstIp, $modal).val();
504             result['tosBits'] = $('#'+one.f.flows.id.modal.form.tosBits, $modal).val();
505             result['tpSrc'] = $('#'+one.f.flows.id.modal.form.srcPort, $modal).val();
506             result['tpDst'] = $('#'+one.f.flows.id.modal.form.dstPort, $modal).val();
507             result['protocol'] = $('#'+one.f.flows.id.modal.form.protocol, $modal).val();
508
509                         result['installInHw'] = install;
510
511             var nodeId = $('#'+one.f.flows.id.modal.form.nodes, $modal).val();
512
513             $.each(result, function(key, value) {
514                 if (value == "") delete result[key];
515             });
516
517             var action = [];
518             var $table = $('#'+one.f.flows.id.modal.action.table, $modal);
519             $($table.find('tbody').find('tr')).each(function(index, value) {
520                                 if (!$(this).find('td').hasClass('empty')) {
521                         action.push($(value).data('action'));
522                                 }
523             });
524             result['actions'] = action;
525
526             // frontend validation
527                         if (result['name'] == undefined) {
528                                 alert('Need flow name');
529                                 return;
530                         }
531                         if (nodeId == '') {
532                                 alert('Select node');
533                                 return;
534                         }
535                         if (action.length == 0) {
536                                 alert('Please specify an action');
537                                 return;
538                         }
539
540                         // package for ajax call
541             var resource = {};
542             resource['body'] = JSON.stringify(result);
543             resource['action'] = 'add';
544                         resource['nodeId'] = nodeId;
545
546             one.f.flows.modal.ajax.saveflow(resource, function(data) {
547                 if (data == "Success") {
548                     $modal.modal('hide');
549                     one.lib.alert('Flow added');
550                     one.main.dashlet.left.top.empty();
551                     one.f.flows.dashlet(one.main.dashlet.left.top);
552                 } else {
553                                         alert('Could not add flow: '+data);
554                 }
555             });
556         },
557         ajax : {
558             nodes : function(successCallback) {
559                 $.getJSON(one.f.address.root+one.f.address.flows.nodes, function(data) {
560                     var nodes = one.f.flows.modal.data.nodes(data);
561                     var nodeports = data;
562                     one.f.flows.registry['nodeports'] = nodeports;
563
564                     successCallback(nodes, nodeports);
565                 });
566             },
567             saveflow : function(resource, callback) {
568                 $.post(one.f.address.root+one.f.address.flows.flow, resource, function(data) {
569                     callback(data);
570                 });
571             },
572             removeflow : function(id, node, callback) {
573                 resource = {};
574                 resource['action'] = 'remove';
575                 $.post(one.f.address.root+one.f.address.flows.flow+'/'+node+'/'+id, resource, function(data) {
576                     callback(data);
577                 });
578             },
579             toggleflow : function(id, node, callback) {
580                 resource = {};
581                 resource['action'] = 'toggle';
582                 $.post(one.f.address.root+one.f.address.flows.flow+'/'+node+'/'+id, resource, function(data) {
583                         callback(data);
584                 });
585             }
586         },
587         data : {
588             nodes : function(data) {
589                 result = {};
590                 $.each(data, function(key, value) {
591                     result[key] = value['name'];
592                 });
593                 return result;
594             }
595         },
596         body : function(nodes, nodeports) {
597             var $form = $(document.createElement('form'));
598                         var $fieldset = $(document.createElement('fieldset'));
599                         // flow description
600                         var $legend = one.lib.form.legend("Flow Description");
601                         $fieldset.append($legend);
602                         // name
603                         var $label = one.lib.form.label("Name");
604                         var $input = one.lib.form.input("Flow Name");
605                         $input.attr('id', one.f.flows.id.modal.form.name);
606                         $fieldset.append($label).append($input);
607                         // node
608                         var $label = one.lib.form.label("Node");
609                         var $select = one.lib.form.select.create(nodes);
610                         one.lib.form.select.prepend($select, { '' : 'Please Select a Node' });
611                         $select.val($select.find("option:first").val());
612                         $select.attr('id', one.f.flows.id.modal.form.nodes);
613
614                         // bind onchange
615                         $select.change(function() {
616                             // retrieve port value
617                             var node = $(this).find('option:selected').attr('value');
618                             var $ports = $('#'+one.f.flows.id.modal.form.port);
619                                 if (node == '') {
620                                         one.lib.form.select.inject($ports, {});
621                                         return;
622                                 }
623                             one.f.flows.registry['currentNode'] = node;
624                             var ports = nodeports[node]['ports'];
625                             one.lib.form.select.inject($ports, ports);
626                             one.lib.form.select.prepend($ports, { '' : 'Please Select a Port' });
627                             $ports.val($ports.find("option:first").val());
628                         });
629
630             $fieldset.append($label).append($select);
631                         // input port
632                         var $label = one.lib.form.label("Input Port");
633                         var $select = one.lib.form.select.create();
634                         $select.attr('id', one.f.flows.id.modal.form.port);
635                         $fieldset.append($label).append($select);
636                         // priority
637                         var $label = one.lib.form.label("Priority");
638                         var $input = one.lib.form.input("Priority");
639                         $input.attr('id', one.f.flows.id.modal.form.priority);
640                         $input.val('500');
641                         $fieldset.append($label).append($input);
642                         // hardTimeout
643                         var $label = one.lib.form.label("Hard Timeout");
644                         var $input = one.lib.form.input("Hard Timeout");
645                         $input.attr('id', one.f.flows.id.modal.form.hardTimeout);
646                         $fieldset.append($label).append($input);
647                         // idleTimeout
648                         var $label = one.lib.form.label("Idle Timeout");
649                         var $input = one.lib.form.input("Idle Timeout");
650                         $input.attr('id', one.f.flows.id.modal.form.idleTimeout);
651                         $fieldset.append($label).append($input);
652                         // cookie
653                         var $label = one.lib.form.label("Cookie");
654                         var $input = one.lib.form.input("Cookie");
655                         $input.attr('id', one.f.flows.id.modal.form.cookie);
656                         $fieldset.append($label).append($input);
657                         // layer 2
658                         var $legend = one.lib.form.legend("Layer 2");
659                         $fieldset.append($legend);
660                         // etherType
661                         var $label = one.lib.form.label("Ethernet Type");
662                         var $input = one.lib.form.input("Ethernet Type");
663                         $input.attr('id', one.f.flows.id.modal.form.etherType);
664                         $input.val('0x800');
665                         $fieldset.append($label).append($input);
666                         // vlanId
667                         var $label = one.lib.form.label("VLAN Identification Number");
668                         var $input = one.lib.form.input("VLAN Identification Number");
669                         $input.attr('id', one.f.flows.id.modal.form.vlanId);
670                         var $help = one.lib.form.help("Range: 0 - 4095");
671                         $fieldset.append($label).append($input).append($help);
672                         // vlanPriority
673                         var $label = one.lib.form.label("VLAN Priority");
674                         var $input = one.lib.form.input("VLAN Priority");
675                         $input.attr('id', one.f.flows.id.modal.form.vlanPriority);
676                         var $help = one.lib.form.help("Range: 0 - 7");
677                         $fieldset.append($label).append($input).append($help);
678                         // srcMac
679                         var $label = one.lib.form.label("Source MAC Address");
680                         var $input = one.lib.form.input("Source MAC Address");
681                         $input.attr('id', one.f.flows.id.modal.form.srcMac);
682                         var $help = one.lib.form.help("Example: 00:11:22:aa:bb:cc");
683                         $fieldset.append($label).append($input).append($help);
684                         // dstMac
685                         var $label = one.lib.form.label("Destination MAC Address");
686                         var $input = one.lib.form.input("Destination MAC Address");
687                         $input.attr('id', one.f.flows.id.modal.form.dstMac);
688                         var $help = one.lib.form.help("Example: 00:11:22:aa:bb:cc");
689                         $fieldset.append($label).append($input).append($help);
690                         // layer 3
691                         var $legend = one.lib.form.legend("Layer 3");
692                         $fieldset.append($legend);
693                         // srcIp
694                         var $label = one.lib.form.label("Source IP Address");
695                         var $input = one.lib.form.input("Source IP Address");
696                         $input.attr('id', one.f.flows.id.modal.form.srcIp);
697                         var $help = one.lib.form.help("Example: 127.0.0.1");
698                         $fieldset.append($label).append($input).append($help);
699                         // dstIp
700                         var $label = one.lib.form.label("Destination IP Address");
701                         var $input = one.lib.form.input("Destination IP Address");
702                         $input.attr('id', one.f.flows.id.modal.form.dstIp);
703                         var $help = one.lib.form.help("Example: 127.0.0.1");
704                         $fieldset.append($label).append($input).append($help);
705                         // tosBits
706                         var $label = one.lib.form.label("TOS Bits");
707                         var $input = one.lib.form.input("TOS Bits");
708                         $input.attr('id', one.f.flows.id.modal.form.tosBits);
709                         var $help = one.lib.form.help("Range: 0 - 63");
710                         $fieldset.append($label).append($input).append($help);
711                         // layer 4
712                         var $legend = one.lib.form.legend("Layer 4");
713                         $fieldset.append($legend);
714                         // srcPort
715                         var $label = one.lib.form.label("Source Port");
716                         var $input = one.lib.form.input("Source Port");
717                         $input.attr('id', one.f.flows.id.modal.form.srcPort);
718                         var $help = one.lib.form.help("Range: 1 - 65535");
719                         $fieldset.append($label).append($input).append($help);
720                         // dstPort
721                         var $label = one.lib.form.label("Destination Port");
722                         var $input = one.lib.form.input("Destination Port");
723                         $input.attr('id', one.f.flows.id.modal.form.dstPort);
724                         var $help = one.lib.form.help("Range: 1 - 65535");
725                         $fieldset.append($label).append($input).append($help);
726                         // protocol
727                         var $label = one.lib.form.label("Protocol");
728                         var $input = one.lib.form.input("Protocol");
729                         $input.attr('id', one.f.flows.id.modal.form.protocol);
730                         $fieldset.append($label).append($input);
731                         // actions
732                         var $legend = one.lib.form.label("Actions");
733                         $fieldset.append($legend);
734                         // actions table
735                         var tableAttributes = ["table-striped", "table-bordered", "table-condensed", "table-hover", "table-cursor"];
736                         var $table = one.lib.dashlet.table.table(tableAttributes);
737                         $table.attr('id', one.f.flows.id.modal.action.table);
738                         var tableHeaders = ["Action", "Data", "Type"];
739                     var $thead = one.lib.dashlet.table.header(tableHeaders);
740                         var $tbody = one.lib.dashlet.table.body("", tableHeaders);
741                         $table.append($thead).append($tbody);
742                         // actions
743                         var actions = {
744                             "" : "Please Select an Action",
745                             "drop" : "Drop",
746                             "loopback" : "Loopback",
747                             "flood" : "Flood",
748                             "softwarePath" : "Software Path",
749                             "hardwarePath" : "Hardware Path",
750                             "controller" : "Controller",
751                             "addOutputPorts" : "Add Output Ports",
752                             "setVlanId" : "Set VLAN ID",
753                             "setVlanPriority" : "Set VLAN Priority",
754                             "stripVlanHeader" : "Strip VLAN Header",
755                             "modifyDatalayerSourceAddress" : "Modify Datalayer Source Address",
756                             "modifyDatalayerDestinationAddress" : "Modify Datalayer Destination Address",
757                             "modifyNetworkSourceAddress" : "Modify Network Source Address",
758                             "modifyNetworkDestinationAddress" :"Modify Network Destination Address",
759                             "modifyTosBits" : "Modify TOS Bits",
760                             "modifyTransportSourcePort" : "Modify Transport Source Port",
761                             "modifyTransportDestinationPort" : "Modify Transport Destination Port"
762                         };
763             var $select = one.lib.form.select.create(actions);
764             // when selecting an action
765             $select.change(function() {
766                 var action = $(this).find('option:selected');
767                 one.f.flows.modal.action.parse(action.attr('value'));
768                                 $select[0].selectedIndex = 0;
769             });
770
771                         $fieldset.append($select).append($table);
772
773                         // return
774                         $form.append($fieldset);
775                         return $form;
776         },
777         action : {
778             parse : function(option) {
779                 switch (option) {
780                     case "addOutputPorts" :
781                         var h3 = "Add Output Port";
782                         var $modal = one.f.flows.modal.action.initialize(h3, one.f.flows.modal.action.body.addOutputPorts, one.f.flows.modal.action.add.addOutputPorts);
783                         $modal.modal();
784                         break;
785                     case "setVlanId" :
786                         var h3 = "Set VLAN ID";
787                         var placeholder = "VLAN Identification Number";
788                         var id = one.f.flows.id.modal.action.setVlanId;
789                         var help = "Range: 0 - 4095";
790                         var action = 'SET_VLAN_ID';
791                         var name = "VLAN ID";
792                         var body = function() {
793                             return one.f.flows.modal.action.body.set(h3, placeholder, id, help);
794                         };
795                         var add = function($modal) {
796                             one.f.flows.modal.action.add.set(name, id, action, $modal);
797                         };
798                         var $modal = one.f.flows.modal.action.initialize(h3, body, add);
799                         $modal.modal();
800                         break;
801                     case "setVlanPriority" :
802                         var h3 = "Set VLAN Priority";
803                         var placeholder = "VLAN Priority";
804                         var id = one.f.flows.id.modal.action.setVlanPriority;
805                         var help = "Range: 0 - 7";
806                         var action = 'SET_VLAN_PCP';
807                         var name = "VLAN Priority";
808                         var body = function() {
809                             return one.f.flows.modal.action.body.set(h3, placeholder, id, help);
810                         };
811                         var add = function($modal) {
812                             one.f.flows.modal.action.add.set(name, id, action, $modal);
813                         };
814                         var $modal = one.f.flows.modal.action.initialize(h3, body, add);
815                         $modal.modal();
816                         break;
817                     case "stripVlanHeader" :
818                         var name = "Strip VLAN Header";
819                         var action = 'POP_VLAN';
820                         one.f.flows.modal.action.add.add(name, action);
821                         break;
822                     case "modifyDatalayerSourceAddress" :
823                         var h3 = "Set Source MAC Address";
824                         var placeholder = "Source MAC Address";
825                         var id = one.f.flows.id.modal.action.modifyDatalayerSourceAddress;
826                         var help = "Example: 00:11:22:aa:bb:cc";
827                         var action = 'SET_DL_SRC';
828                         var name = "Source MAC";
829                         var body = function() {
830                             return one.f.flows.modal.action.body.set(h3, placeholder, id, help);
831                         };
832                         var add = function($modal) {
833                             one.f.flows.modal.action.add.set(name, id, action, $modal);
834                         };
835                         var $modal = one.f.flows.modal.action.initialize(h3, body, add);
836                         $modal.modal();
837                         break;
838                     case "modifyDatalayerDestinationAddress" :
839                         var h3 = "Set Destination MAC Address";
840                         var placeholder = "Destination MAC Address";
841                         var id = one.f.flows.id.modal.action.modifyDatalayerDestinationAddress;
842                         var help = "Example: 00:11:22:aa:bb:cc";
843                         var action = 'SET_DL_DST';
844                         var name = "Destination MAC";
845                         var body = function() {
846                             return one.f.flows.modal.action.body.set(h3, placeholder, id, help);
847                         };
848                         var add = function($modal) {
849                             one.f.flows.modal.action.add.set(name, id, action, $modal);
850                         };
851                         var $modal = one.f.flows.modal.action.initialize(h3, body, add);
852                         $modal.modal();
853                         break;
854                     case "modifyNetworkSourceAddress" :
855                         var h3 = "Set IP Source Address";
856                         var placeholder = "Source IP Address";
857                         var id = one.f.flows.id.modal.action.modifyNetworkSourceAddress;
858                         var help = "Example: 127.0.0.1";
859                         var action = 'SET_NW_SRC';
860                         var name = "Source IP";
861                         var body = function() {
862                             return one.f.flows.modal.action.body.set(h3, placeholder, id, help);
863                         };
864                         var add = function($modal) {
865                             one.f.flows.modal.action.add.set(name, id, action, $modal);
866                         };
867                         var $modal = one.f.flows.modal.action.initialize(h3, body, add);
868                         $modal.modal();
869                         break;
870                     case "modifyNetworkDestinationAddress" :
871                         var h3 = "Set IP Destination Address";
872                         var placeholder = "Destination IP Address";
873                         var id = one.f.flows.id.modal.action.modifyNetworkDestinationAddress;
874                         var help = "Example: 127.0.0.1";
875                         var action = 'SET_NW_DST';
876                         var name = "Destination IP";
877                         var body = function() {
878                             return one.f.flows.modal.action.body.set(h3, placeholder, id, help);
879                         };
880                         var add = function($modal) {
881                             one.f.flows.modal.action.add.set(name, id, action, $modal);
882                         };
883                         var $modal = one.f.flows.modal.action.initialize(h3, body, add);
884                         $modal.modal();
885                         break;
886                     case "modifyTosBits" :
887                         var h3 = "Set IPv4 ToS";
888                         var placeholder = "IPv4 ToS";
889                         var id = one.f.flows.id.modal.action.modifyTosBits;
890                         var help = "Range: 0 - 63";
891                         var action = 'SET_NW_TOS';
892                         var name = "TOS Bits";
893                         var body = function() {
894                             return one.f.flows.modal.action.body.set(h3, placeholder, id, help);
895                         };
896                         var add = function($modal) {
897                             one.f.flows.modal.action.add.set(name, id, action, $modal);
898                         };
899                         var $modal = one.f.flows.modal.action.initialize(h3, body, add);
900                         $modal.modal();
901                         break;
902                     case "modifyTransportSourcePort" :
903                         var h3 = "Set Transport Source Port";
904                         var placeholder = "Transport Source Port";
905                         var id = one.f.flows.id.modal.action.modifyTransportSourcePort;
906                         var help = "Range: 1 - 65535";
907                         var action = 'SET_TP_SRC';
908                         var name = "Source Port";
909                         var body = function() {
910                             return one.f.flows.modal.action.body.set(h3, placeholder, id, help);
911                         };
912                         var add = function($modal) {
913                             one.f.flows.modal.action.add.set(name, id, action, $modal);
914                         };
915                         var $modal = one.f.flows.modal.action.initialize(h3, body, add);
916                         $modal.modal();
917                         break;
918                     case "modifyTransportDestinationPort" :
919                         var h3 = "Set Transport Destination Port";
920                         var placeholder = "Transport Destination Port";
921                         var id = one.f.flows.id.modal.action.modifyTransportDestinationPort;
922                         var help = "Range: 1 - 65535";
923                         var action = 'SET_TP_DST';
924                         var name = "Destination Port";
925                         var body = function() {
926                             return one.f.flows.modal.action.body.set(h3, placeholder, id, help);
927                         };
928                         var add = function($modal) {
929                             one.f.flows.modal.action.add.set(name, id, action, $modal);
930                         };
931                         var $modal = one.f.flows.modal.action.initialize(h3, body, add);
932                         $modal.modal();
933                         break;
934                     case "drop" :
935                         var name = "Drop";
936                         var action = 'DROP';
937                         one.f.flows.modal.action.add.add(name, action);
938                         break;
939                     case "loopback" :
940                         var name = "Loopback";
941                         var action = 'LOOPBACK';
942                         one.f.flows.modal.action.add.add(name, action);
943                         break;
944                     case "flood" :
945                         var name = "Flood";
946                         var action = 'FLOOD';
947                         one.f.flows.modal.action.add.add(name, action);
948                         break;
949                     case "softwarePath" :
950                         var name = "Software Path";
951                         var action = 'SW_PATH';
952                         one.f.flows.modal.action.add.add(name, action);
953                         break;
954                     case "hardwarePath" :
955                         var name = "Hardware Path";
956                         var action = 'HW_PATH';
957                         one.f.flows.modal.action.add.add(name, action);
958                         break;
959                     case "controller" :
960                         var name = "Controller";
961                         var action = 'CONTROLLER';
962                         one.f.flows.modal.action.add.add(name, action);
963                         break;
964                 }
965             },
966             initialize : function(h3, bodyCallback, addCallback) {
967                 var footer = one.f.flows.modal.action.footer();
968                 var $body = bodyCallback();
969                 var $modal = one.lib.modal.spawn(one.f.flows.id.modal.action.modal, h3, $body, footer);
970                 // bind close button
971                 $('#'+one.f.flows.id.modal.action.close, $modal).click(function() {
972                     $modal.modal('hide');
973                 });
974                 // bind add flow button
975                 $('#'+one.f.flows.id.modal.action.add, $modal).click(function() {
976                     addCallback($modal);
977                 });
978                 return $modal;
979             },
980             add : {
981                 addOutputPorts : function($modal) {
982                     var $options = $('#'+one.f.flows.id.modal.action.addOutputPorts).find('option:selected');
983                     var ports = '';
984                     var pid = '';
985                     $options.each(function(index, value) {
986                         ports = ports+$(value).text()+", ";
987                         pid = pid+$(value).attr('value')+",";
988                     });
989                     ports = ports.slice(0,-2);
990                     pid = pid.slice(0,-1);
991                     var $tr = one.f.flows.modal.action.table.add("Add Output Ports", ports);
992                     $tr.attr('id', 'addOutputPorts');
993                     $tr.data('action', 'OUTPUT='+pid);
994                                         $tr.click(function() {
995                                                 one.f.flows.modal.action.add.modal.initialize(this);
996                                         });
997                     one.f.flows.modal.action.table.append($tr);
998                     $modal.modal('hide');
999                 },
1000                 add : function(name, action) {
1001                     var $tr = one.f.flows.modal.action.table.add(name);
1002                     $tr.attr('id', action);
1003                     $tr.data('action', action);
1004                                         $tr.click(function() {
1005                                                 one.f.flows.modal.action.add.modal.initialize(this);
1006                                         });
1007                     one.f.flows.modal.action.table.append($tr);
1008                 },
1009                 set : function(name, id, action, $modal) {
1010                     var $input = $('#'+id);
1011                     var value = $input.val();
1012                     var $tr = one.f.flows.modal.action.table.add(name, value);
1013                     $tr.attr('id', action);
1014                     $tr.data('action', action+'='+value);
1015                                         $tr.click(function() {
1016                                                 one.f.flows.modal.action.add.modal.initialize(this);
1017                                         });
1018                     one.f.flows.modal.action.table.append($tr);
1019                     $modal.modal('hide');
1020                 },
1021                                 remove : function(that) {
1022                                         $(that).remove();
1023                                         var $table = $('#'+one.f.flows.id.modal.action.table);
1024                                         if ($table.find('tbody').find('tr').size() == 0) {
1025                                                 var $tr = $(document.createElement('tr'));
1026                                                 var $td = $(document.createElement('td'));
1027                                                 $td.attr('colspan', '3');
1028                                                 $tr.addClass('empty');
1029                                                 $td.text('No data available');
1030                                                 $tr.append($td);
1031                                                 $table.find('tbody').append($tr);
1032                                         }
1033                                 },
1034                                 modal : {
1035                                         initialize : function(that) {
1036                                                 var h3 = "Remove Action";
1037                                                 var footer = one.f.flows.modal.action.add.modal.footer();
1038                                                 var $body = one.f.flows.modal.action.add.modal.body();
1039                                                 var $modal = one.lib.modal.spawn(one.f.flows.id.modal.action.modal.modal, h3, $body, footer);
1040
1041                                                 // bind cancel button
1042                                                 $('#'+one.f.flows.id.modal.action.modal.cancel, $modal).click(function() {
1043                                                         $modal.modal('hide');
1044                                                 });
1045
1046                                                 // bind remove button
1047                                                 $('#'+one.f.flows.id.modal.action.modal.remove, $modal).click(function() {
1048                                                         one.f.flows.modal.action.add.remove(that);
1049                                                         $modal.modal('hide');
1050                                                 });
1051
1052                                                 $modal.modal();
1053                                         },
1054                                         body : function() {
1055                                                 var $p = $(document.createElement('p'));
1056                                                 $p.append("Remove this action?");
1057                                                 return $p;
1058                                         },
1059                                         footer : function() {
1060                                                 var footer = [];
1061
1062                                                 var removeButton = one.lib.dashlet.button.single("Remove Action", one.f.flows.id.modal.action.modal.remove, "btn-danger", "");
1063                                                 var $removeButton = one.lib.dashlet.button.button(removeButton);
1064                                                 footer.push($removeButton);
1065
1066                                                 var cancelButton = one.lib.dashlet.button.single("Cancel", one.f.flows.id.modal.action.modal.cancel, "", "");
1067                                                 var $cancelButton = one.lib.dashlet.button.button(cancelButton);
1068                                                 footer.push($cancelButton);
1069
1070                                                 return footer;
1071                                         }
1072                                 }
1073             },
1074             table : {
1075                 add : function(action, data, type) {
1076                     var $tr = $(document.createElement('tr'));
1077                     var $td = $(document.createElement('td'));
1078                     $td.append(action);
1079                     $tr.append($td);
1080                     var $td = $(document.createElement('td'));
1081                     if (data != undefined) $td.append(data);
1082                     $tr.append($td);
1083                     var $td = $(document.createElement('td'));
1084                     if (type != undefined) $td.append(type);
1085                     $tr.append($td);
1086                     return $tr;
1087                 },
1088                 append : function($tr) {
1089                     var $table = $('#'+one.f.flows.id.modal.action.table);
1090                     var $empty = $table.find('.empty').parent();
1091                     if ($empty.size() > 0) $empty.remove();
1092                     $table.append($tr);
1093                 }
1094             },
1095             body : {
1096                 common : function() {
1097                     var $form = $(document.createElement('form'));
1098                     var $fieldset = $(document.createElement('fieldset'));
1099                     return [$form, $fieldset];
1100                 },
1101                 addOutputPorts : function() {
1102                     var common = one.f.flows.modal.action.body.common();
1103                     var $form = common[0];
1104                     var $fieldset = common[1];
1105                     // output port
1106                     $label = one.lib.form.label("Select Output Ports");
1107                     var ports = one.f.flows.registry.nodeports[one.f.flows.registry.currentNode]['ports'];
1108                     $select = one.lib.form.select.create(ports, true);
1109                     $select.attr('id', one.f.flows.id.modal.action.addOutputPorts);
1110                     one.lib.form.select.prepend($select, {'':'Select a Port'});
1111                     $fieldset.append($label).append($select);
1112                     $form.append($fieldset);
1113                     return $form;
1114                 },
1115                 set : function(label, placeholder, id, help) {
1116                     var common = one.f.flows.modal.action.body.common();
1117                     var $form = common[0];
1118                     var $fieldset = common[1];
1119                     // input
1120                     $label = one.lib.form.label(label);
1121                     $input = one.lib.form.input(placeholder);
1122                     $input.attr('id', id);
1123                     $help = one.lib.form.help(help);
1124                     // append
1125                     $fieldset.append($label).append($input).append($help);
1126                     $form.append($fieldset);
1127                     return $form;
1128                 }
1129             },
1130             footer : function() {
1131                 var footer = [];
1132                 var addButton = one.lib.dashlet.button.single("Add Action", one.f.flows.id.modal.action.add, "btn-primary", "");
1133                 var $addButton = one.lib.dashlet.button.button(addButton);
1134                 footer.push($addButton);
1135
1136                 var closeButton = one.lib.dashlet.button.single("Close", one.f.flows.id.modal.action.close, "", "");
1137                 var $closeButton = one.lib.dashlet.button.button(closeButton);
1138                 footer.push($closeButton);
1139
1140                 return footer;
1141             }
1142         },
1143         footer : function() {
1144             var footer = [];
1145
1146                         var installButton = one.lib.dashlet.button.single("Install Flow", one.f.flows.id.modal.install, "btn-success", "");
1147                         var $installButton = one.lib.dashlet.button.button(installButton);
1148                         footer.push($installButton);
1149
1150             var addButton = one.lib.dashlet.button.single("Save Flow", one.f.flows.id.modal.add, "btn-primary", "");
1151             var $addButton = one.lib.dashlet.button.button(addButton);
1152             footer.push($addButton);
1153
1154             var closeButton = one.lib.dashlet.button.single("Close", one.f.flows.id.modal.close, "", "");
1155             var $closeButton = one.lib.dashlet.button.button(closeButton);
1156             footer.push($closeButton);
1157
1158             return footer;
1159         }
1160     },
1161     ajax : {
1162         dashlet : function(callback) {
1163             $.getJSON(one.f.address.root+one.f.address.flows.main, function(data) {
1164                 one.f.flows.registry['flows'] = data.flows;
1165                 one.f.flows.registry['privilege'] = data.privilege;
1166                 var body = one.f.flows.data.dashlet(data.flows);
1167                 var $body = one.f.flows.body.dashlet(body, callback);
1168                 callback($body);
1169             });
1170         }
1171     },
1172     data : {
1173         dashlet : function(data) {
1174             var body = [];
1175             $(data).each(function(index, value) {
1176                 var tr = {};
1177                 var entry = [];
1178                 entry.push(value['name']);
1179                 entry.push(value['node']);
1180                 if (value['flow']['installInHw'] == 'true' && value['flow']['status'] == 'Success')
1181                         tr['type'] = ['success'];
1182                 else if (value['flow']['installInHw'] == 'false' && value['flow']['status'] == 'Success')
1183                         tr['type'] = ['warning'];
1184                 else 
1185                         tr['type'] = ['warning'];
1186                 tr['entry'] = entry;
1187                 tr['id'] = value['nodeId'];
1188
1189                 body.push(tr);
1190             });
1191             return body;
1192         }
1193     },
1194     body : {
1195         dashlet : function(body, callback) {
1196             var attributes = ['table-striped', 'table-bordered', 'table-hover', 'table-condensed', 'table-cursor'];
1197             var $table = one.lib.dashlet.table.table(attributes);
1198
1199             var headers = ['Flow Name', 'Node'];
1200             var $thead = one.lib.dashlet.table.header(headers);
1201             $table.append($thead);
1202
1203             var $tbody = one.lib.dashlet.table.body(body);
1204             $table.append($tbody);
1205
1206             return $table;
1207         }
1208     }
1209 }
1210
1211 /** INIT **/
1212 // populate nav tabs
1213 $(one.f.menu.left.top).each(function(index, value) {
1214     var $nav = $(".nav", "#left-top");
1215     one.main.page.dashlet($nav, value);
1216 });
1217
1218 $(one.f.menu.left.bottom).each(function(index, value) {
1219     var $nav = $(".nav", "#left-bottom");
1220     one.main.page.dashlet($nav, value);
1221 });
1222
1223 $(one.f.menu.right.bottom).each(function(index, value) {
1224     var $nav = $(".nav", "#right-bottom");
1225     one.main.page.dashlet($nav, value);
1226 });
1227
1228 one.f.populate = function($dashlet, header) {
1229     var $h4 = one.lib.dashlet.header(header);
1230     $dashlet.append($h4);
1231 };
1232
1233 // bind dashlet nav
1234 $('.dash .nav a', '#main').click(function() {
1235     // de/activation
1236     var $li = $(this).parent();
1237     var $ul = $li.parent();
1238     one.lib.nav.unfocus($ul);
1239     $li.addClass('active');
1240     // clear respective dashlet
1241     var $dashlet = $ul.parent().find('.dashlet');
1242     one.lib.dashlet.empty($dashlet);
1243     // callback based on menu
1244     var id = $(this).attr('id');
1245     var menu = one.f.dashlet;
1246     switch (id) {
1247         case menu.flows.id:
1248             one.f.flows.dashlet($dashlet);
1249             break;
1250         case menu.nodes.id:
1251             one.f.nodes.dashlet($dashlet);
1252             break;
1253         case menu.detail.id:
1254             one.f.detail.dashlet($dashlet);
1255             break;
1256     };
1257 });
1258
1259 // activate first tab on each dashlet
1260 $('.dash .nav').each(function(index, value) {
1261     $($(value).find('li')[0]).find('a').click();
1262 });