/* vim: set expandtab sw=4 ts=4 sts=4: */ /** * @fileoverview functions used in server status pages * @name Server Status * * @requires jQuery * @requires jQueryUI * @requires jQueryCookie * @requires jQueryTablesorter * @requires Highcharts * @requires canvg * @requires js/functions.js * */ // Add a tablesorter parser to properly handle thousands seperated numbers and SI prefixes $(function() { jQuery.tablesorter.addParser({ id: "fancyNumber", is: function(s) { return /^[0-9]?[0-9,\.]*\s?(k|M|G|T|%)?$/.test(s); }, format: function(s) { var num = jQuery.tablesorter.formatFloat( s.replace(PMA_messages['strThousandsSeperator'],'').replace(PMA_messages['strDecimalSeperator'],'.') ); var factor = 1; switch (s.charAt(s.length-1)) { case '%': factor = -2; break; // Todo: Complete this list (as well as in the regexp a few lines up) case 'k': factor = 3; break; case 'M': factor = 6; break; case 'G': factor = 9; break; case 'T': factor = 12; break; } return num*Math.pow(10,factor); }, type: "numeric" }); }); $(function() { // Filters for status variables var textFilter=null; var alertFilter = false; var categoryFilter=''; var odd_row=false; var text=''; // Holds filter text /* Chart configuration */ // Defines what the tabs are currently displaying (realtime or data) var tabStatus = new Object(); // Holds the current chart instances for each tab var tabChart = new Object(); // Add tabs $('#serverStatusTabs').tabs({ // Tab persistence cookie: { name: 'pma_serverStatusTabs', expires: 1 }, // Fixes line break in the menu bar when the page overflows and scrollbar appears show: function() { menuResize(); } }); // Fixes wrong tab height with floated elements. See also http://bugs.jqueryui.com/ticket/5601 $(".ui-widget-content:not(.ui-tabs):not(.ui-helper-clearfix)").addClass("ui-helper-clearfix"); // Build query statistics chart var cdata = new Array(); $.each(jQuery.parseJSON($('#serverstatusquerieschart').html()),function(key,value) { cdata.push([key,parseInt(value)]); }); PMA_createChart({ chart: { renderTo: 'serverstatusquerieschart' }, title: { text:'', margin:0 }, series: [{ type:'pie', name: 'Query statistics', data: cdata }], plotOptions: { pie: { allowPointSelect: true, cursor: 'pointer', dataLabels: { enabled: true, formatter: function() { return ''+ this.point.name +'
'+ Highcharts.numberFormat(this.percentage, 2) +' %'; } } } }, tooltip: { formatter: function() { return ''+ this.point.name +'
'+Highcharts.numberFormat(this.y, 2)+'
('+Highcharts.numberFormat(this.percentage, 2) +' %)'; } } }); // Table sorting initTableSorter('statustabs_queries'); initTableSorter('statustabs_allvars'); $('.statuslinks select').change(function() { var chart=tabChart[$(this).parents('div.ui-tabs-panel').attr('id')]; chart.options.realtime.refreshRate = 1000*parseInt(this.value); chart.xAxis[0].setExtremes(new Date().getTime() - chart.options.realtime.numMaxPoints * chart.options.realtime.refreshRate, chart.xAxis[0].getExtremes().max, true); clearTimeout(chart_activeTimeouts[chart.options.chart.renderTo]); chart_activeTimeouts[chart.options.chart.renderTo] = setTimeout(chart.options.realtime.timeoutCallBack, chart.options.realtime.refreshRate); }); // Ajax refresh of variables (always the first link in each tab) $('.statuslinks a:nth-child(2)').click(function() { // ui-tabs-panel class is added by the jquery tabs feature var tab=$(this).parents('div.ui-tabs-panel'); var that = this; // Show ajax load icon $(this).find('img').show(); $.get($(this).attr('href'),{ajax_request:1},function(data) { $(that).find('img').hide(); initTab(tab,data); }); tabStatus[tab.attr('id')]='data'; return false; }); /** Realtime charting of variables (always the second link) **/ $('.statuslinks a:nth-child(3)').click(function() { // ui-tabs-panel class is added by the jquery tabs feature var tab=$(this).parents('div.ui-tabs-panel'); if(tabStatus[tab.attr('id')]!='realtime') { var series, title; var settings = new Object(); switch(tab.attr('id')) { case 'statustabs_traffic': settings = { series: [{name:'Connections since last refresh', data:[]},{name:'Processes', data:[]}], title: {text:'Connections / Processes'}, realtime:{ url:'server_status.php?'+url_query, type: 'proc', callback: function(chartObj, curVal, lastVal,numLoadedPoints) { if(lastVal==null) return; chartObj.series[0].addPoint( { x:curVal.x, y:curVal.y_conn-lastVal.y_conn }, false, numLoadedPoints >= chartObj.options.realtime.numMaxPoints ); chartObj.series[1].addPoint( { x:curVal.x, y:curVal.y_proc }, true, numLoadedPoints >= chartObj.options.realtime.numMaxPoints ); } } }; break; case 'statustabs_queries': settings = { series: [{name:'Issued queries since last refresh', data:[]}], title: {text:'Issued queries'}, tooltip: { formatter:function() { return this.point.name; } }, realtime:{ url:'server_status.php?'+url_query, type: 'queries', callback: function(chartObj, curVal, lastVal,numLoadedPoints) { if(lastVal==null) return; chartObj.series[0].addPoint( { x:curVal.x, y:curVal.y-lastVal.y, name:sortedQueriesPointInfo(curVal,lastVal) }, true, numLoadedPoints >= chartObj.options.realtime.numMaxPoints ); } } }; break; default: return; } if(!settings.chart) settings.chart = {}; settings.chart.renderTo=tab.attr('id')+"_chart_cnt"; tab.find('.tabInnerContent') .hide() .after('
'); tabStatus[tab.attr('id')]='realtime'; tabChart[tab.attr('id')]=PMA_createChart(settings); $(this).html(PMA_messages['strStaticData']); tab.find('.statuslinks a:nth-child(2)').hide(); $('.statuslinks select').show(); } else { clearTimeout(chart_activeTimeouts[tab.attr('id')+"_chart_cnt"]); chart_activeTimeouts[tab.attr('id')+"_chart_cnt"]=null; tab.find('.tabInnerContent').show(); tab.find('div#'+tab.attr('id')+'_chart_cnt').remove(); tabStatus[tab.attr('id')]='data'; tabChart[tab.attr('id')].destroy(); $(this).html(PMA_messages['strRealtimeChart']); tab.find('.statuslinks a:nth-child(2)').show(); $('.statuslinks select').hide(); } return false; }); /* 3 Filtering functions */ $('#filterAlert').change(function() { alertFilter = this.checked; filterVariables(); }); $('#filterText').keyup(function(e) { if($(this).val().length==0) textFilter=null; else textFilter = new RegExp("(^|_)"+$(this).val(),'i'); text=$(this).val(); filterVariables(); }); $('#filterCategory').change(function() { categoryFilter = $(this).val(); filterVariables(); }); /* Adjust DOM / Add handlers to the tabs */ function initTab(tab,data) { switch(tab.attr('id')) { case 'statustabs_traffic': tab.find('.tabInnerContent').html(data); initTooltips(); break; case 'statustabs_queries': tab.find('.tabInnerContent').html(data); break; case 'statustabs_allvars': tab.find('.tabInnerContent').html(data); filterVariables(); break; } initTableSorter(tab.attr('id')); } function initTableSorter(tabid) { switch(tabid) { case 'statustabs_queries': $('#serverstatusqueriesdetails').tablesorter({ sortList: [[3,1]], widgets: ['zebra'], headers: { 1: { sorter: 'fancyNumber' }, 2: { sorter: 'fancyNumber' } } }); $('#serverstatusqueriesdetails tr:first th') .append(''); break; case 'statustabs_allvars': $('#serverstatusvariables').tablesorter({ sortList: [[0,0]], widgets: ['zebra'], headers: { 1: { sorter: 'fancyNumber' } } }); $('#serverstatusvariables tr:first th') .append(''); break; } } /* Filters the status variables by name/category/alert in the variables tab */ function filterVariables() { var useful_links=0; var section = text; if(categoryFilter.length>0) section = categoryFilter; if(section.length>1) { $('#linkSuggestions span').each(function() { if($(this).attr('class').indexOf('status_'+section)!=-1) { useful_links++; $(this).css('display',''); } else { $(this).css('display','none'); } }); } if(useful_links>0) $('#linkSuggestions').css('display',''); else $('#linkSuggestions').css('display','none'); odd_row=false; $('#serverstatusvariables th.name').each(function() { if((textFilter==null || textFilter.exec($(this).text())) && (!alertFilter || $(this).next().find('span.attention').length>0) && (categoryFilter.length==0 || $(this).parent().hasClass('s_'+categoryFilter))) { odd_row = !odd_row; $(this).parent().css('display',''); if(odd_row) { $(this).parent().addClass('odd'); $(this).parent().removeClass('even'); } else { $(this).parent().addClass('even'); $(this).parent().removeClass('odd'); } } else { $(this).parent().css('display','none'); } }); } // Provides a nicely formatted and sorted tooltip of each datapoint of the query statistics function sortedQueriesPointInfo(queries, lastQueries){ var max, maxIdx, num=0; var queryKeys = new Array(); var queryValues = new Array(); var sumOther=0; var sumTotal=0; // Separate keys and values, then sort them $.each(queries.pointInfo, function(key,value) { if(value-lastQueries.pointInfo[key] > 0) { queryKeys.push(key); queryValues.push(value-lastQueries.pointInfo[key]); sumTotal+=value-lastQueries.pointInfo[key]; } }); var numQueries = queryKeys.length; var pointInfo = '' + PMA_messages['strTotal'] + ': ' + sumTotal + '
'; while(queryKeys.length > 0) { max=0; for(var i=0; i max) { max = queryValues[i]; maxIdx = i; } } if(numQueries > 8 && num>=6) sumOther+=queryValues[maxIdx]; else pointInfo += queryKeys[maxIdx].substr(4).replace('_',' ') + ': ' + queryValues[maxIdx] + '
'; queryKeys.splice(maxIdx,1); queryValues.splice(maxIdx,1); num++; } if(sumOther>0) pointInfo += PMA_messages['strOther'] + ': ' + sumOther; return pointInfo; } });