diff --git a/dashboards/isp-country-analytics-drilldown/app.css b/dashboards/isp-country-analytics-drilldown/app.css new file mode 100644 index 0000000..7e2c61b --- /dev/null +++ b/dashboards/isp-country-analytics-drilldown/app.css @@ -0,0 +1,27 @@ +.toppers_table_div,.donut_chart_div,.traffic_chart_div,.sankey_chart_div +{ + border:2px solid #eee; + box-shadow: 1px 1px #eee; + min-height: 300px; +} +.ui_data{ + background-color: #eee; +} +.toppers_table_div,.donut_chart_div{ + min-height: 500px; +} + +.panel h3 { + font-size: 20px; + margin-top:10px; +} + +h3 small{ + font-size: 75%; +} +.panel-heading { + padding: 5px 15px; +} +.widget-tool { + float: right; +} diff --git a/dashboards/isp-country-analytics-drilldown/country_analytics_drilldown.js b/dashboards/isp-country-analytics-drilldown/country_analytics_drilldown.js new file mode 100644 index 0000000..a6849d1 --- /dev/null +++ b/dashboards/isp-country-analytics-drilldown/country_analytics_drilldown.js @@ -0,0 +1,404 @@ + class ISPDrilldownMapping{ + constructor(opts) { + let js_file =opts.jsfile; + let file_path = js_file.split("/") + file_path.pop() + file_path = file_path.join("/"); + let css_file = `/plugins/${file_path}/app.css`; + $('head').append(``); + this.dash_params = opts.dash_params; + this.dom = $(opts.divid); + this.time_selector = opts.new_time_selector; + this.rand_id=parseInt(Math.random()*100000); + this.tzadj = window.trisul_tz_offset + (new Date()).getTimezoneOffset()*60 ; + this.meters = this.dash_params.statids.split(","); + this.maxitems=10; + this.probe_id = opts.probe_id; + this.load_meters(opts); + } + + + // load the frame + + async load_meters(opts){ + await this.load_assets(opts); + this.cg_meters = {}; + await get_counters_and_meters_json(this.cg_meters); + var fromTS = this.time_selector.start_time_db + var toTS = this.time_selector.end_time_db + this.tmint = mk_time_interval([fromTS,toTS]); + this.reset_ui(); + + } + + async load_assets(opts) + { + // load app.css file + load_css_file(opts); + // load template.haml file + this.html_str = await get_html_from_hamltemplate(opts); + } + async reset_ui(){ + this.dom.find(".drilldown_data").remove(); + this.data_dom=$(this.html_str) + this.dom.append(this.data_dom); + this.filter_text = this.dash_params.key; + this.agg_flows = []; + for(let i=0;iItemLabelVolume >"); + let cgtoppers = this.cgtoppers_resp.keys.slice(0,this.maxitems); + for(let i= 0 ; i < cgtoppers.length ; i++){ + let topper = cgtoppers[i]; + let link_params =$.param({dash_key:"key", + guid:this.crosskey_cgguid, + key:topper.key, + statid:this.meter}); + let readable = topper.readable.split("\\").pop(); + let label = topper.label.split("\\").pop(); + var anchor = `${readable}`; + var anchor1 = `${label}`; + + var key = topper.key.split("//").pop(); + table.find("tbody").append(` + ${anchor} + ${anchor1} + ${h_fmtvol(topper.metric*this.top_bucket_size)}${this.meter_types[this.meter].units.replace("ps","")} + `); + + } + add_barspark(table); + table.tablesorter(); + + } + + async draw_dount_chart(){ + this.dount_div_id = `country_drilldown_${this.meter_name}_dount`; + this.data_dom.find(`#country_drilldown_${this.meter_name}`).find(".donut_chart").removeClass('animated-background'); + this.data_dom.find(`#country_drilldown_${this.meter_name}`).find(".donut_chart").append($("
",{id:this.dount_div_id})); + let cgtoppers = this.cgtoppers_resp.keys.slice(0,this.maxitems); + var values = []; + var labels = []; + for(let i= 0 ; i < cgtoppers.length ; i++){ + values[i] = cgtoppers[i].metric.toNumber()*this.top_bucket_size; + labels[i] = cgtoppers[i].label.replace(/:0|:1|:2/g,""); + } + var data = [{ + values:values, + labels:labels, + domain: {column: 0}, + hoverinfo: 'label+percent+name', + hole: .4, + type: 'pie' + }]; + + var layout = { + title: 'Toppers', + annotations: [ + { + font: { + size: 20 + }, + showarrow: false, + text: '', + x: 0.17, + y: 0.5 + } + ], + height: 400, + width: $('#'+this.divid).find(".donut_chart").width(), + showlegend: false, + }; + var ploty_options = { modeBarButtonsToRemove: ['hoverClosestCartesian','toggleSpikelines','hoverCompareCartesian', + 'sendDataToCloud'], + showSendToCloud:false, + responsive: true }; + Plotly.newPlot(this.dount_div_id, data, layout,ploty_options); + + var keys = _.map(cgtoppers,function(ai){return ai.key}); + for(let i=0 ; i < keys.length;i++){ + if(keys[i].includes("\\")){ + keys[i]=keys[i].replace(/\\/g,"\\\\") + } + } + } + + draw_aggregate_table(group){ + var table = this.data_dom.find(`.${group}`).find("table"); + this.data_dom.find(`.${group}`).removeClass('animated-background'); + var table_id = "agg_flows_tbl_"+Math.floor(Math.random()*100000); + table.attr("id",table_id) + table.addClass('table table-hover table-sysdata'); + let toppers = []; + if(group=="internal_ip" || group == "external_ip"){ + toppers.push(this.agg_flows[0][group]); + toppers.push(this.agg_flows[1][group]); + }else if(group=="tag_asnumber"){ + if(this.agg_flows[0].tag_group.find(x=>x.group_name=="asn")){ + toppers.push(this.agg_flows[0].tag_group.find(x=>x.group_name=="asn").tag_metrics) + } + if(this.agg_flows[1].tag_group.find(x=>x.group_name=="asn")){ + toppers.push(this.agg_flows[1].tag_group.find(x=>x.group_name=="asn").tag_metrics) + } + } + else if(group=="tag_prefixes"){ + if( this.agg_flows[0].tag_group.find(x=>x.group_name=="prf")){ + toppers.push(this.agg_flows[0].tag_group.find(x=>x.group_name=="prf").tag_metrics); + } + if( this.agg_flows[1].tag_group.find(x=>x.group_name=="prf")){ + toppers.push(this.agg_flows[1].tag_group.find(x=>x.group_name=="prf").tag_metrics); + } + } + toppers =_.flatten(toppers).slice(0,50); + let toppers_obj = {}; + for(let i=0 ; i < toppers.length; i++){ + let t = toppers[i]; + let k = t.key.key + if(toppers_obj[k]){ + let v = toppers_obj[k]; + v.count = parseInt(v.count) + parseInt(t.count) ; + v.metric = v.metric.toNumber() + t.metric.toNumber() ; + }else{ + toppers_obj[k] = t + } + } + toppers = _.sortBy(_.values(toppers_obj),function(k){return -k.metric;}); + let rows = [] + for(let i=0; i< toppers.length;i++){ + var t = toppers[i]; + rows.push(` + ${t.key.readable||t.key.key} + ${t.key.label} + ${t.count} + ${h_fmtvol(t.metric)} + `); + } + + new TrisTablePagination(table_id,{no_of_rows:10,rows:rows}); + table.tablesorter(); + new ExportToCSV({table_id:table_id,filename_prefix:"top_asn_panel",append_to:"panel"}); + + } + + async draw_traffic_chart(){ + let cgtoppers = this.cgtoppers_resp.keys.slice(0,this.maxitems); + let keys = _.map(cgtoppers,function(ai){return ai.key}); + for(let i=0 ; i < keys.length;i++){ + if(keys[i].includes("\\")){ + keys[i]=keys[i].replace(/\\/g,"\\\\") + } + } + this.traf_chart_id = `country_drilldown_${this.meter_name}_traffic_chart` + this.data_dom.find(`#country_drilldown_${this.meter_name}`).find(`.interfaces_traffic_chart`).attr("id",this.traf_chart_id); + let ref_model = [this.dash_params.cgguid,this.dash_params.key,this.meter,"Total"] + var model_data = {cgguid:this.crosskey_cgguid, + meter:this.meter, + key:keys.join(","), + window_fromts:this.time_selector.start_time_db, + window_tots:this.time_selector.end_time_db, + valid_input:1, + ref_model:ref_model + }; + if(keys.length==0){ + $('#'+this.traf_chart_id).html("no data found"); + return + } + $.ajax({ + url:"/trpjs/generate_chart", + data:model_data, + context:this, + success:function(resp){ + $('#'+this.traf_chart_id).html(resp); + + } + }); + + } + async draw_sankey_chart(filter_cgbase){ + + this.sankey_div_id = `country_drilldown_${this.meter_name}_sankey`; + this.data_dom.find(`#country_drilldown_${this.meter_name}`).find(".interfaces_sankey_chart").append($("
",{id:this.sankey_div_id})); + + // Get Bytes Toppers + this.cgtoppers_bytes = this.cgtoppers_resp.keys; + this.cgtoppers_bytes = this.cgtoppers_bytes.slice(0,30); + let keylookup = {}; + let idx=0; + let links = { source : [], target : [], value : [] }; + + for (let i =0 ; i < this.cgtoppers_bytes.length; i++) + { + //change label to :0,:1,:2 + //http host and host has same lable + let k=this.cgtoppers_bytes[i].label; + let parts=k.split("\\"); + if(filter_cgbase == "Interfaces"){ + let router = parts[1].split("_").shift() + parts = [parts[0],router,parts[1]]; + } + + parts = _.map(parts,function(ai,ind){ + return ai.replace(/:0|:1|:2/g,"")+":"+ind; + }); + this.cgtoppers_bytes[i].label=parts.join("\\") + keylookup[parts[0]] = keylookup[parts[0]]==undefined ? idx++ : keylookup[parts[0]]; + keylookup[parts[1]] = keylookup[parts[1]] || idx++; + if (parts[2]) { + keylookup[parts[2]] = keylookup[parts[2]] || idx++; + } + + } + + for (let i =0 ; i < this.cgtoppers_bytes.length; i++) + { + let item=this.cgtoppers_bytes[i]; + let k=item.label; + let parts=k.split("\\"); + if (parts[2]) { + links.source.push(keylookup[parts[0]]) + links.target.push(keylookup[parts[1]]) + links.value.push(parseInt(item.metric*this.top_bucket_size)) + links.source.push(keylookup[parts[1]]) + links.target.push(keylookup[parts[2]]) + links.value.push(parseInt(item.metric*this.top_bucket_size)) + + } else { + links.source.push(keylookup[parts[0]]) + links.target.push(keylookup[parts[1]]) + links.value.push(parseInt(item.metric*this.top_bucket_size)) + } + } + let labels=_.chain(keylookup).pairs().sortBy( (ai) => ai[1]).map( (ai) => ai[0].replace(/:0|:1|:2/g,"")).value() + + Plotly.purge(this.sankey_div_id); + var data = { + type: "sankey", + orientation: "h", + valuesuffix: this.meter_types[this.meter].units.replace("ps",""), + node: { + pad: 15, + thickness: 30, + line: { + color: "black", + width: 0.5 + }, + label: labels, + }, + + link: links + } + + //width of div widht + var width = this.data_dom.find(`#${this.sankey_div_id}`).width(); + width = parseInt(width)-50; + var height = labels.length *25; + if(height < 250){ + height =250; + } + var layout = { + title: `${this.meter_name} Mappings`, + width:width, + height:height, + font: { + size: 10 + }, + + } + + var data = [data] + var ploty_options = { modeBarButtonsToRemove: ['hoverClosestCartesian','toggleSpikelines','hoverCompareCartesian', + 'sendDataToCloud'], + showSendToCloud:false, + responsive: true }; + + Plotly.react(this.sankey_div_id, data, layout, ploty_options) + } + sort_hash(data,key){ + return data.keys.sort(function(a,b){ + let v1 = a["key"]; + let v2 = b["key"]; + if(key=="metric"){ + v1 = - a["metric"].toNumber(); + v2 = - b["metric"].toNumber(); + } + if (v1 < v2) + return -1; + if (v1 > v2) + return 1; + return 0; + }); + } + +}; + + +function run(opts) { + new ISPDrilldownMapping(opts); +} + + + //# sourceURL=ips_drilldown_mappings.js + + \ No newline at end of file diff --git a/dashboards/isp-country-analytics-drilldown/pkg.yaml b/dashboards/isp-country-analytics-drilldown/pkg.yaml new file mode 100644 index 0000000..b9a13af --- /dev/null +++ b/dashboards/isp-country-analytics-drilldown/pkg.yaml @@ -0,0 +1,18 @@ +name: Country Analytics Drilldown + +version: 0.0.2 + +author: trisul + + +description: + short: View country mappings for routers and interfaces + long: | + A breakup of country to router mappings in table and chart format + This plugin is a visualization of that. + +apptype: dashboard_js + +appresources: country_analytics_drilldown.js app.css template.haml + +dependencies: diff --git a/dashboards/isp-country-analytics-drilldown/template.haml b/dashboards/isp-country-analytics-drilldown/template.haml new file mode 100644 index 0000000..61c0c4a --- /dev/null +++ b/dashboards/isp-country-analytics-drilldown/template.haml @@ -0,0 +1,94 @@ +.drilldown_data + .row + .col-xs-12 + %ul.nav.nav-tabs#country_drilldown_tabs + %li.active + %a{href:"#country_drilldown_upload",data-toggle:"tab",role:"tab"} + %i.fa.fa-upload.fa-fw + Upload + %span.upload_volume + %li + %a{href:"#country_drilldown_download",data-toggle:"tab",role:"tab"} + %i.fa.fa-download.fa-fw + Download + %span.download_volume + .tab-content{style:"padding-top:10px"} + .tab-pane.active#country_drilldown_upload{data-use-width:1} + .row + .col-xs-6 + .panel.panel-primary + .panel-heading + %h3 + %i.fa.fa-table.fa-fw + Interface Toppers + .panel-body + .toppers_table.animated-background + %table + %thead + %tbody + .col-xs-6 + .panel.panel-primary + .panel-heading + %h3 + %i.fa.fa-pie-chart.fa-fw + Toppers Chart + .panel-body + .donut_chart.animated-background + .col-xs-12 + .panel.panel-primary + .panel-heading + %h3 + %i.fa.fa-area-chart.fa-fw + Traffic chart for interfaces + .panel-body + .interfaces_traffic_chart + .col-xs-12 + .panel.panel-primary + .panel-heading + %h3 + %i.fa.fa-random.fa-fw + Interfaces Sankey Chart + .panel-body + .interfaces_sankey_chart + + + + .tab-pane#country_drilldown_download{data-use-width:1} + .row + .col-xs-6 + .panel.panel-success + .panel-heading + %h3 + %i.fa.fa-table.fa-fw + Interface Toppers + .panel-body + .toppers_table.animated-background + %table + %thead + %tbody + .col-xs-6 + .panel.panel-success + .panel-heading + %h3 + %i.fa.fa-pie-chart.fa-fw + Toppers Chart + .panel-body + .donut_chart.animated-background + .col-xs-12 + .panel.panel-success + .panel-heading + %h3 + %i.fa.fa-area-chart.fa-fw + Traffic chart for interfaces + .panel-body + .interfaces_traffic_chart + .col-xs-12 + .panel.panel-success + .panel-heading + %h3 + %i.fa.fa-random.fa-fw + Interfaces Sankey Chart + .panel-body + .interfaces_sankey_chart + + \ No newline at end of file diff --git a/dashboards/isp-country-analytics-drilldown/thumbnail.png b/dashboards/isp-country-analytics-drilldown/thumbnail.png new file mode 100644 index 0000000..abc134b Binary files /dev/null and b/dashboards/isp-country-analytics-drilldown/thumbnail.png differ diff --git a/dashboards/isp-prefix-analytics-drilldown/app.css b/dashboards/isp-prefix-analytics-drilldown/app.css new file mode 100644 index 0000000..7e2c61b --- /dev/null +++ b/dashboards/isp-prefix-analytics-drilldown/app.css @@ -0,0 +1,27 @@ +.toppers_table_div,.donut_chart_div,.traffic_chart_div,.sankey_chart_div +{ + border:2px solid #eee; + box-shadow: 1px 1px #eee; + min-height: 300px; +} +.ui_data{ + background-color: #eee; +} +.toppers_table_div,.donut_chart_div{ + min-height: 500px; +} + +.panel h3 { + font-size: 20px; + margin-top:10px; +} + +h3 small{ + font-size: 75%; +} +.panel-heading { + padding: 5px 15px; +} +.widget-tool { + float: right; +} diff --git a/dashboards/isp-prefix-analytics-drilldown/pkg.yaml b/dashboards/isp-prefix-analytics-drilldown/pkg.yaml new file mode 100644 index 0000000..d992a81 --- /dev/null +++ b/dashboards/isp-prefix-analytics-drilldown/pkg.yaml @@ -0,0 +1,18 @@ +name: Prefix Analytics Drilldown + +version: 0.0.2 + +author: trisul + + +description: + short: View prefix mappings for routers and interfaces + long: | + A breakup of prefix to router mappings in table and chart format + This plugin is a visualization of that. + +apptype: dashboard_js + +appresources: peering_analytics_drilldown.js app.css template.haml + +dependencies: diff --git a/dashboards/isp-prefix-analytics-drilldown/prefix_analytics_drilldown.js b/dashboards/isp-prefix-analytics-drilldown/prefix_analytics_drilldown.js new file mode 100644 index 0000000..a6849d1 --- /dev/null +++ b/dashboards/isp-prefix-analytics-drilldown/prefix_analytics_drilldown.js @@ -0,0 +1,404 @@ + class ISPDrilldownMapping{ + constructor(opts) { + let js_file =opts.jsfile; + let file_path = js_file.split("/") + file_path.pop() + file_path = file_path.join("/"); + let css_file = `/plugins/${file_path}/app.css`; + $('head').append(``); + this.dash_params = opts.dash_params; + this.dom = $(opts.divid); + this.time_selector = opts.new_time_selector; + this.rand_id=parseInt(Math.random()*100000); + this.tzadj = window.trisul_tz_offset + (new Date()).getTimezoneOffset()*60 ; + this.meters = this.dash_params.statids.split(","); + this.maxitems=10; + this.probe_id = opts.probe_id; + this.load_meters(opts); + } + + + // load the frame + + async load_meters(opts){ + await this.load_assets(opts); + this.cg_meters = {}; + await get_counters_and_meters_json(this.cg_meters); + var fromTS = this.time_selector.start_time_db + var toTS = this.time_selector.end_time_db + this.tmint = mk_time_interval([fromTS,toTS]); + this.reset_ui(); + + } + + async load_assets(opts) + { + // load app.css file + load_css_file(opts); + // load template.haml file + this.html_str = await get_html_from_hamltemplate(opts); + } + async reset_ui(){ + this.dom.find(".drilldown_data").remove(); + this.data_dom=$(this.html_str) + this.dom.append(this.data_dom); + this.filter_text = this.dash_params.key; + this.agg_flows = []; + for(let i=0;iItemLabelVolume >"); + let cgtoppers = this.cgtoppers_resp.keys.slice(0,this.maxitems); + for(let i= 0 ; i < cgtoppers.length ; i++){ + let topper = cgtoppers[i]; + let link_params =$.param({dash_key:"key", + guid:this.crosskey_cgguid, + key:topper.key, + statid:this.meter}); + let readable = topper.readable.split("\\").pop(); + let label = topper.label.split("\\").pop(); + var anchor = `${readable}`; + var anchor1 = `${label}`; + + var key = topper.key.split("//").pop(); + table.find("tbody").append(` + ${anchor} + ${anchor1} + ${h_fmtvol(topper.metric*this.top_bucket_size)}${this.meter_types[this.meter].units.replace("ps","")} + `); + + } + add_barspark(table); + table.tablesorter(); + + } + + async draw_dount_chart(){ + this.dount_div_id = `country_drilldown_${this.meter_name}_dount`; + this.data_dom.find(`#country_drilldown_${this.meter_name}`).find(".donut_chart").removeClass('animated-background'); + this.data_dom.find(`#country_drilldown_${this.meter_name}`).find(".donut_chart").append($("
",{id:this.dount_div_id})); + let cgtoppers = this.cgtoppers_resp.keys.slice(0,this.maxitems); + var values = []; + var labels = []; + for(let i= 0 ; i < cgtoppers.length ; i++){ + values[i] = cgtoppers[i].metric.toNumber()*this.top_bucket_size; + labels[i] = cgtoppers[i].label.replace(/:0|:1|:2/g,""); + } + var data = [{ + values:values, + labels:labels, + domain: {column: 0}, + hoverinfo: 'label+percent+name', + hole: .4, + type: 'pie' + }]; + + var layout = { + title: 'Toppers', + annotations: [ + { + font: { + size: 20 + }, + showarrow: false, + text: '', + x: 0.17, + y: 0.5 + } + ], + height: 400, + width: $('#'+this.divid).find(".donut_chart").width(), + showlegend: false, + }; + var ploty_options = { modeBarButtonsToRemove: ['hoverClosestCartesian','toggleSpikelines','hoverCompareCartesian', + 'sendDataToCloud'], + showSendToCloud:false, + responsive: true }; + Plotly.newPlot(this.dount_div_id, data, layout,ploty_options); + + var keys = _.map(cgtoppers,function(ai){return ai.key}); + for(let i=0 ; i < keys.length;i++){ + if(keys[i].includes("\\")){ + keys[i]=keys[i].replace(/\\/g,"\\\\") + } + } + } + + draw_aggregate_table(group){ + var table = this.data_dom.find(`.${group}`).find("table"); + this.data_dom.find(`.${group}`).removeClass('animated-background'); + var table_id = "agg_flows_tbl_"+Math.floor(Math.random()*100000); + table.attr("id",table_id) + table.addClass('table table-hover table-sysdata'); + let toppers = []; + if(group=="internal_ip" || group == "external_ip"){ + toppers.push(this.agg_flows[0][group]); + toppers.push(this.agg_flows[1][group]); + }else if(group=="tag_asnumber"){ + if(this.agg_flows[0].tag_group.find(x=>x.group_name=="asn")){ + toppers.push(this.agg_flows[0].tag_group.find(x=>x.group_name=="asn").tag_metrics) + } + if(this.agg_flows[1].tag_group.find(x=>x.group_name=="asn")){ + toppers.push(this.agg_flows[1].tag_group.find(x=>x.group_name=="asn").tag_metrics) + } + } + else if(group=="tag_prefixes"){ + if( this.agg_flows[0].tag_group.find(x=>x.group_name=="prf")){ + toppers.push(this.agg_flows[0].tag_group.find(x=>x.group_name=="prf").tag_metrics); + } + if( this.agg_flows[1].tag_group.find(x=>x.group_name=="prf")){ + toppers.push(this.agg_flows[1].tag_group.find(x=>x.group_name=="prf").tag_metrics); + } + } + toppers =_.flatten(toppers).slice(0,50); + let toppers_obj = {}; + for(let i=0 ; i < toppers.length; i++){ + let t = toppers[i]; + let k = t.key.key + if(toppers_obj[k]){ + let v = toppers_obj[k]; + v.count = parseInt(v.count) + parseInt(t.count) ; + v.metric = v.metric.toNumber() + t.metric.toNumber() ; + }else{ + toppers_obj[k] = t + } + } + toppers = _.sortBy(_.values(toppers_obj),function(k){return -k.metric;}); + let rows = [] + for(let i=0; i< toppers.length;i++){ + var t = toppers[i]; + rows.push(` + ${t.key.readable||t.key.key} + ${t.key.label} + ${t.count} + ${h_fmtvol(t.metric)} + `); + } + + new TrisTablePagination(table_id,{no_of_rows:10,rows:rows}); + table.tablesorter(); + new ExportToCSV({table_id:table_id,filename_prefix:"top_asn_panel",append_to:"panel"}); + + } + + async draw_traffic_chart(){ + let cgtoppers = this.cgtoppers_resp.keys.slice(0,this.maxitems); + let keys = _.map(cgtoppers,function(ai){return ai.key}); + for(let i=0 ; i < keys.length;i++){ + if(keys[i].includes("\\")){ + keys[i]=keys[i].replace(/\\/g,"\\\\") + } + } + this.traf_chart_id = `country_drilldown_${this.meter_name}_traffic_chart` + this.data_dom.find(`#country_drilldown_${this.meter_name}`).find(`.interfaces_traffic_chart`).attr("id",this.traf_chart_id); + let ref_model = [this.dash_params.cgguid,this.dash_params.key,this.meter,"Total"] + var model_data = {cgguid:this.crosskey_cgguid, + meter:this.meter, + key:keys.join(","), + window_fromts:this.time_selector.start_time_db, + window_tots:this.time_selector.end_time_db, + valid_input:1, + ref_model:ref_model + }; + if(keys.length==0){ + $('#'+this.traf_chart_id).html("no data found"); + return + } + $.ajax({ + url:"/trpjs/generate_chart", + data:model_data, + context:this, + success:function(resp){ + $('#'+this.traf_chart_id).html(resp); + + } + }); + + } + async draw_sankey_chart(filter_cgbase){ + + this.sankey_div_id = `country_drilldown_${this.meter_name}_sankey`; + this.data_dom.find(`#country_drilldown_${this.meter_name}`).find(".interfaces_sankey_chart").append($("
",{id:this.sankey_div_id})); + + // Get Bytes Toppers + this.cgtoppers_bytes = this.cgtoppers_resp.keys; + this.cgtoppers_bytes = this.cgtoppers_bytes.slice(0,30); + let keylookup = {}; + let idx=0; + let links = { source : [], target : [], value : [] }; + + for (let i =0 ; i < this.cgtoppers_bytes.length; i++) + { + //change label to :0,:1,:2 + //http host and host has same lable + let k=this.cgtoppers_bytes[i].label; + let parts=k.split("\\"); + if(filter_cgbase == "Interfaces"){ + let router = parts[1].split("_").shift() + parts = [parts[0],router,parts[1]]; + } + + parts = _.map(parts,function(ai,ind){ + return ai.replace(/:0|:1|:2/g,"")+":"+ind; + }); + this.cgtoppers_bytes[i].label=parts.join("\\") + keylookup[parts[0]] = keylookup[parts[0]]==undefined ? idx++ : keylookup[parts[0]]; + keylookup[parts[1]] = keylookup[parts[1]] || idx++; + if (parts[2]) { + keylookup[parts[2]] = keylookup[parts[2]] || idx++; + } + + } + + for (let i =0 ; i < this.cgtoppers_bytes.length; i++) + { + let item=this.cgtoppers_bytes[i]; + let k=item.label; + let parts=k.split("\\"); + if (parts[2]) { + links.source.push(keylookup[parts[0]]) + links.target.push(keylookup[parts[1]]) + links.value.push(parseInt(item.metric*this.top_bucket_size)) + links.source.push(keylookup[parts[1]]) + links.target.push(keylookup[parts[2]]) + links.value.push(parseInt(item.metric*this.top_bucket_size)) + + } else { + links.source.push(keylookup[parts[0]]) + links.target.push(keylookup[parts[1]]) + links.value.push(parseInt(item.metric*this.top_bucket_size)) + } + } + let labels=_.chain(keylookup).pairs().sortBy( (ai) => ai[1]).map( (ai) => ai[0].replace(/:0|:1|:2/g,"")).value() + + Plotly.purge(this.sankey_div_id); + var data = { + type: "sankey", + orientation: "h", + valuesuffix: this.meter_types[this.meter].units.replace("ps",""), + node: { + pad: 15, + thickness: 30, + line: { + color: "black", + width: 0.5 + }, + label: labels, + }, + + link: links + } + + //width of div widht + var width = this.data_dom.find(`#${this.sankey_div_id}`).width(); + width = parseInt(width)-50; + var height = labels.length *25; + if(height < 250){ + height =250; + } + var layout = { + title: `${this.meter_name} Mappings`, + width:width, + height:height, + font: { + size: 10 + }, + + } + + var data = [data] + var ploty_options = { modeBarButtonsToRemove: ['hoverClosestCartesian','toggleSpikelines','hoverCompareCartesian', + 'sendDataToCloud'], + showSendToCloud:false, + responsive: true }; + + Plotly.react(this.sankey_div_id, data, layout, ploty_options) + } + sort_hash(data,key){ + return data.keys.sort(function(a,b){ + let v1 = a["key"]; + let v2 = b["key"]; + if(key=="metric"){ + v1 = - a["metric"].toNumber(); + v2 = - b["metric"].toNumber(); + } + if (v1 < v2) + return -1; + if (v1 > v2) + return 1; + return 0; + }); + } + +}; + + +function run(opts) { + new ISPDrilldownMapping(opts); +} + + + //# sourceURL=ips_drilldown_mappings.js + + \ No newline at end of file diff --git a/dashboards/isp-prefix-analytics-drilldown/template.haml b/dashboards/isp-prefix-analytics-drilldown/template.haml new file mode 100644 index 0000000..61c0c4a --- /dev/null +++ b/dashboards/isp-prefix-analytics-drilldown/template.haml @@ -0,0 +1,94 @@ +.drilldown_data + .row + .col-xs-12 + %ul.nav.nav-tabs#country_drilldown_tabs + %li.active + %a{href:"#country_drilldown_upload",data-toggle:"tab",role:"tab"} + %i.fa.fa-upload.fa-fw + Upload + %span.upload_volume + %li + %a{href:"#country_drilldown_download",data-toggle:"tab",role:"tab"} + %i.fa.fa-download.fa-fw + Download + %span.download_volume + .tab-content{style:"padding-top:10px"} + .tab-pane.active#country_drilldown_upload{data-use-width:1} + .row + .col-xs-6 + .panel.panel-primary + .panel-heading + %h3 + %i.fa.fa-table.fa-fw + Interface Toppers + .panel-body + .toppers_table.animated-background + %table + %thead + %tbody + .col-xs-6 + .panel.panel-primary + .panel-heading + %h3 + %i.fa.fa-pie-chart.fa-fw + Toppers Chart + .panel-body + .donut_chart.animated-background + .col-xs-12 + .panel.panel-primary + .panel-heading + %h3 + %i.fa.fa-area-chart.fa-fw + Traffic chart for interfaces + .panel-body + .interfaces_traffic_chart + .col-xs-12 + .panel.panel-primary + .panel-heading + %h3 + %i.fa.fa-random.fa-fw + Interfaces Sankey Chart + .panel-body + .interfaces_sankey_chart + + + + .tab-pane#country_drilldown_download{data-use-width:1} + .row + .col-xs-6 + .panel.panel-success + .panel-heading + %h3 + %i.fa.fa-table.fa-fw + Interface Toppers + .panel-body + .toppers_table.animated-background + %table + %thead + %tbody + .col-xs-6 + .panel.panel-success + .panel-heading + %h3 + %i.fa.fa-pie-chart.fa-fw + Toppers Chart + .panel-body + .donut_chart.animated-background + .col-xs-12 + .panel.panel-success + .panel-heading + %h3 + %i.fa.fa-area-chart.fa-fw + Traffic chart for interfaces + .panel-body + .interfaces_traffic_chart + .col-xs-12 + .panel.panel-success + .panel-heading + %h3 + %i.fa.fa-random.fa-fw + Interfaces Sankey Chart + .panel-body + .interfaces_sankey_chart + + \ No newline at end of file diff --git a/dashboards/isp-prefix-analytics-drilldown/thumbnail.png b/dashboards/isp-prefix-analytics-drilldown/thumbnail.png new file mode 100644 index 0000000..f586f39 Binary files /dev/null and b/dashboards/isp-prefix-analytics-drilldown/thumbnail.png differ