The branch, master has been updated via 0829162550764de8890bb0e24ec53f89b480c1ef (commit) via 5caaf0ed2998377c3b9df2016b87fd9baa9adf90 (commit) via ad99bc70e5acf149b34a4c330918b7e2bbaf14e0 (commit) via 19469fb44f155d5e5ba54f10a952a4d1ddd106c6 (commit) via f677136ef90cb6ecd34ce1a0323396df42aeac40 (commit) via e4924833c71a8cc4e55d7291fa826653d7d4504f (commit) via 03a76e2c74aba8964e9541ee436e77549a3afe21 (commit) via f10a0bd1ca60030bb922342d8814ea0b89ab90a5 (commit) via 82a1f9c033e49bd7e00d006ae0b74289b5907ad5 (commit) via 0466ac320b284f98678b416a4aa2e14e9a1db27d (commit) via 949bd599dcde04871e5bd6dd496dd29ba6d8563f (commit) via d257c39339005c3cdf93df949c815149e672782f (commit) via 44eac8a5a9a75f32b09ed07c03d04a2cec0a2c64 (commit) via ce8b3cbda059a1ea4648c5b80917b3852fcd02a9 (commit) via 8cdfa37d461770a9605a6d37cf07733bb7ae1bc0 (commit) via cf95fbdcb5ceeab4a916f087967a798b76001b31 (commit) via 09fdda813176f660be9971fe4cb584cec7e1cd16 (commit) via 7e22620ec2a55673ac71184754284df0a98fc57f (commit) via 666732baf2a77178f90497ce77db5ba68b7f2c69 (commit) via e6e7e893bd2ca56c2eb756351e54e00f1b44bb1f (commit) via 81d7a95f7428ae3eb1c5a52ec0d32e6cc6e067c0 (commit) via 8906aab33f69fde22dea02d734c3a7b377ed99c0 (commit) via f4afe963b6407c6815d4511ae7e3f06f367778d6 (commit) from f09b391bfdee6da14328d129187fe3dbf3147995 (commit)
- Log ----------------------------------------------------------------- commit 0829162550764de8890bb0e24ec53f89b480c1ef Merge: f09b391 5caaf0e Author: Michal Čihař mcihar@suse.cz Date: Thu Aug 11 11:25:18 2011 +0200
Merge remote-tracking branch 'tyron/master' into integration
Conflicts: js/functions.js
commit 5caaf0ed2998377c3b9df2016b87fd9baa9adf90 Author: Tyron Madlener tyronx@gmail.com Date: Wed Aug 10 13:01:00 2011 +0300
more code cleanup
commit ad99bc70e5acf149b34a4c330918b7e2bbaf14e0 Author: Tyron Madlener tyronx@gmail.com Date: Wed Aug 10 11:26:38 2011 +0300
code style improvements
commit 19469fb44f155d5e5ba54f10a952a4d1ddd106c6 Author: Tyron Madlener tyronx@gmail.com Date: Wed Aug 10 11:26:07 2011 +0300
added system_ memory variable
commit f677136ef90cb6ecd34ce1a0323396df42aeac40 Author: Tyron Madlener tyronx@gmail.com Date: Wed Aug 10 10:52:14 2011 +0300
Fixes IE gradients being in every single row
commit e4924833c71a8cc4e55d7291fa826653d7d4504f Author: Tyron Madlener tyronx@gmail.com Date: Wed Aug 10 10:51:42 2011 +0300
Load flashcanvas.js only for IE version below 9
commit 03a76e2c74aba8964e9541ee436e77549a3afe21 Author: Tyron Madlener tyronx@gmail.com Date: Tue Aug 9 22:51:17 2011 +0300
Lots of codestyle cleanup + 1 bugfix for query analyzer
commit f10a0bd1ca60030bb922342d8814ea0b89ab90a5 Author: Tyron Madlener tyronx@gmail.com Date: Tue Aug 9 10:36:18 2011 +0300
adjusted to PMA_AddJSCode()
commit 82a1f9c033e49bd7e00d006ae0b74289b5907ad5 Author: Tyron Madlener tyronx@gmail.com Date: Tue Aug 9 10:35:53 2011 +0300
addded PMA_AddJSCode() to load js code into the page header
commit 0466ac320b284f98678b416a4aa2e14e9a1db27d Author: Tyron Madlener tyronx@gmail.com Date: Mon Aug 8 17:11:22 2011 +0300
fix on dynamic monitor loading
commit 949bd599dcde04871e5bd6dd496dd29ba6d8563f Author: Tyron Madlener tyronx@gmail.com Date: Mon Aug 8 17:01:52 2011 +0300
Merge l10n string
commit d257c39339005c3cdf93df949c815149e672782f Merge: 44eac8a f16efa1 Author: Tyron Madlener tyronx@gmail.com Date: Mon Aug 8 16:58:35 2011 +0300
Merge remote-tracking branch 'origin/master'
commit 44eac8a5a9a75f32b09ed07c03d04a2cec0a2c64 Author: Tyron Madlener tyronx@gmail.com Date: Mon Aug 8 16:38:41 2011 +0300
change overwritten by previous merge
commit ce8b3cbda059a1ea4648c5b80917b3852fcd02a9 Author: Tyron Madlener tyronx@gmail.com Date: Mon Aug 8 16:35:33 2011 +0300
removed trailing commas from arrays
commit 8cdfa37d461770a9605a6d37cf07733bb7ae1bc0 Merge: cf95fbd 79df749 Author: Tyron Madlener tyronx@gmail.com Date: Mon Aug 8 16:35:10 2011 +0300
Merge remote-tracking branch 'origin/master'
Conflicts: js/functions.js js/server_status.js js/server_variables.js libraries/advisory_rules.txt server_status.php
commit cf95fbdcb5ceeab4a916f087967a798b76001b31 Author: Tyron Madlener tyronx@gmail.com Date: Mon Aug 8 16:16:53 2011 +0300
server status page using new qtip function
commit 09fdda813176f660be9971fe4cb584cec7e1cd16 Author: Tyron Madlener tyronx@gmail.com Date: Mon Aug 8 16:15:35 2011 +0300
- Moved style info from PMA_createQtip() into theme_right.css.php - Adjusted style to look more like the tooltips we had originally - Removed dHint class
commit 7e22620ec2a55673ac71184754284df0a98fc57f Author: Tyron Madlener tyronx@gmail.com Date: Mon Aug 8 14:13:50 2011 +0300
added mysql < 5.5.8 check
commit 666732baf2a77178f90497ce77db5ba68b7f2c69 Author: Tyron Madlener tyronx@gmail.com Date: Mon Aug 8 14:05:55 2011 +0300
- Merged rgbcolor.js into canvg.js - Status monitor now loads on demand (when tab is clicked)
commit e6e7e893bd2ca56c2eb756351e54e00f1b44bb1f Author: Tyron Madlener tyronx@gmail.com Date: Fri Aug 5 18:44:20 2011 +0300
Fixed version checks better
commit 81d7a95f7428ae3eb1c5a52ec0d32e6cc6e067c0 Author: Tyron Madlener tyronx@gmail.com Date: Fri Aug 5 18:41:11 2011 +0300
Fixed db version checks
commit 8906aab33f69fde22dea02d734c3a7b377ed99c0 Author: Tyron Madlener tyronx@gmail.com Date: Fri Aug 5 18:18:18 2011 +0300
Advisor: Variable names redirect to the variable on the variables page
commit f4afe963b6407c6815d4511ae7e3f06f367778d6 Author: Tyron Madlener tyronx@gmail.com Date: Fri Aug 5 15:50:06 2011 +0300
Advisor: - l10n in php/js code - code style improvements - ui style improvements - syntax/run errors in advisory_rules.txt are now displayed in advisor tab
-----------------------------------------------------------------------
Summary of changes: js/canvg/canvg.js | 288 +++ js/canvg/rgbcolor.js | 288 --- js/functions.js | 28 +- js/messages.php | 15 +- js/server_status.js | 1986 +++------------------ js/{server_status.js => server_status_monitor.js} | 1669 ++++++----------- js/server_variables.js | 199 ++- libraries/{advisor.lib.php => advisor.class.php} | 64 +- libraries/advisory_rules.txt | 30 +- libraries/common.inc.php | 7 + libraries/core.lib.php | 11 + libraries/header_scripts.inc.php | 7 +- server_status.php | 113 +- server_variables.php | 47 +- sql.php | 5 +- tbl_chart.php | 5 +- themes/original/css/theme_right.css.php | 42 +- themes/pmahomme/css/theme_right.css.php | 43 +- 18 files changed, 1455 insertions(+), 3392 deletions(-) delete mode 100644 js/canvg/rgbcolor.js copy js/{server_status.js => server_status_monitor.js} (52%) rename libraries/{advisor.lib.php => advisor.class.php} (77%)
diff --git a/js/canvg/canvg.js b/js/canvg/canvg.js index 7b7e963..19a47a7 100644 --- a/js/canvg/canvg.js +++ b/js/canvg/canvg.js @@ -2414,4 +2414,292 @@ if (CanvasRenderingContext2D) { scaleHeight: dh }); } +} + +/** + * A class to parse color values + * @author Stoyan Stefanov sstoo@gmail.com + * @link http://www.phpied.com/rgb-color-parser-in-javascript/ + * @license Use it if you like it + */ +function RGBColor(color_string) +{ + this.ok = false; + + // strip any leading # + if (color_string.charAt(0) == '#') { // remove # if any + color_string = color_string.substr(1,6); + } + + color_string = color_string.replace(/ /g,''); + color_string = color_string.toLowerCase(); + + // before getting into regexps, try simple matches + // and overwrite the input + var simple_colors = { + aliceblue: 'f0f8ff', + antiquewhite: 'faebd7', + aqua: '00ffff', + aquamarine: '7fffd4', + azure: 'f0ffff', + beige: 'f5f5dc', + bisque: 'ffe4c4', + black: '000000', + blanchedalmond: 'ffebcd', + blue: '0000ff', + blueviolet: '8a2be2', + brown: 'a52a2a', + burlywood: 'deb887', + cadetblue: '5f9ea0', + chartreuse: '7fff00', + chocolate: 'd2691e', + coral: 'ff7f50', + cornflowerblue: '6495ed', + cornsilk: 'fff8dc', + crimson: 'dc143c', + cyan: '00ffff', + darkblue: '00008b', + darkcyan: '008b8b', + darkgoldenrod: 'b8860b', + darkgray: 'a9a9a9', + darkgreen: '006400', + darkkhaki: 'bdb76b', + darkmagenta: '8b008b', + darkolivegreen: '556b2f', + darkorange: 'ff8c00', + darkorchid: '9932cc', + darkred: '8b0000', + darksalmon: 'e9967a', + darkseagreen: '8fbc8f', + darkslateblue: '483d8b', + darkslategray: '2f4f4f', + darkturquoise: '00ced1', + darkviolet: '9400d3', + deeppink: 'ff1493', + deepskyblue: '00bfff', + dimgray: '696969', + dodgerblue: '1e90ff', + feldspar: 'd19275', + firebrick: 'b22222', + floralwhite: 'fffaf0', + forestgreen: '228b22', + fuchsia: 'ff00ff', + gainsboro: 'dcdcdc', + ghostwhite: 'f8f8ff', + gold: 'ffd700', + goldenrod: 'daa520', + gray: '808080', + green: '008000', + greenyellow: 'adff2f', + honeydew: 'f0fff0', + hotpink: 'ff69b4', + indianred : 'cd5c5c', + indigo : '4b0082', + ivory: 'fffff0', + khaki: 'f0e68c', + lavender: 'e6e6fa', + lavenderblush: 'fff0f5', + lawngreen: '7cfc00', + lemonchiffon: 'fffacd', + lightblue: 'add8e6', + lightcoral: 'f08080', + lightcyan: 'e0ffff', + lightgoldenrodyellow: 'fafad2', + lightgrey: 'd3d3d3', + lightgreen: '90ee90', + lightpink: 'ffb6c1', + lightsalmon: 'ffa07a', + lightseagreen: '20b2aa', + lightskyblue: '87cefa', + lightslateblue: '8470ff', + lightslategray: '778899', + lightsteelblue: 'b0c4de', + lightyellow: 'ffffe0', + lime: '00ff00', + limegreen: '32cd32', + linen: 'faf0e6', + magenta: 'ff00ff', + maroon: '800000', + mediumaquamarine: '66cdaa', + mediumblue: '0000cd', + mediumorchid: 'ba55d3', + mediumpurple: '9370d8', + mediumseagreen: '3cb371', + mediumslateblue: '7b68ee', + mediumspringgreen: '00fa9a', + mediumturquoise: '48d1cc', + mediumvioletred: 'c71585', + midnightblue: '191970', + mintcream: 'f5fffa', + mistyrose: 'ffe4e1', + moccasin: 'ffe4b5', + navajowhite: 'ffdead', + navy: '000080', + oldlace: 'fdf5e6', + olive: '808000', + olivedrab: '6b8e23', + orange: 'ffa500', + orangered: 'ff4500', + orchid: 'da70d6', + palegoldenrod: 'eee8aa', + palegreen: '98fb98', + paleturquoise: 'afeeee', + palevioletred: 'd87093', + papayawhip: 'ffefd5', + peachpuff: 'ffdab9', + peru: 'cd853f', + pink: 'ffc0cb', + plum: 'dda0dd', + powderblue: 'b0e0e6', + purple: '800080', + red: 'ff0000', + rosybrown: 'bc8f8f', + royalblue: '4169e1', + saddlebrown: '8b4513', + salmon: 'fa8072', + sandybrown: 'f4a460', + seagreen: '2e8b57', + seashell: 'fff5ee', + sienna: 'a0522d', + silver: 'c0c0c0', + skyblue: '87ceeb', + slateblue: '6a5acd', + slategray: '708090', + snow: 'fffafa', + springgreen: '00ff7f', + steelblue: '4682b4', + tan: 'd2b48c', + teal: '008080', + thistle: 'd8bfd8', + tomato: 'ff6347', + turquoise: '40e0d0', + violet: 'ee82ee', + violetred: 'd02090', + wheat: 'f5deb3', + white: 'ffffff', + whitesmoke: 'f5f5f5', + yellow: 'ffff00', + yellowgreen: '9acd32' + }; + for (var key in simple_colors) { + if (color_string == key) { + color_string = simple_colors[key]; + } + } + // emd of simple type-in colors + + // array of color definition objects + var color_defs = [ + { + re: /^rgb((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3}))$/, + example: ['rgb(123, 234, 45)', 'rgb(255,234,245)'], + process: function (bits){ + return [ + parseInt(bits[1]), + parseInt(bits[2]), + parseInt(bits[3]) + ]; + } + }, + { + re: /^(\w{2})(\w{2})(\w{2})$/, + example: ['#00ff00', '336699'], + process: function (bits){ + return [ + parseInt(bits[1], 16), + parseInt(bits[2], 16), + parseInt(bits[3], 16) + ]; + } + }, + { + re: /^(\w{1})(\w{1})(\w{1})$/, + example: ['#fb0', 'f0f'], + process: function (bits){ + return [ + parseInt(bits[1] + bits[1], 16), + parseInt(bits[2] + bits[2], 16), + parseInt(bits[3] + bits[3], 16) + ]; + } + } + ]; + + // search through the definitions to find a match + for (var i = 0; i < color_defs.length; i++) { + var re = color_defs[i].re; + var processor = color_defs[i].process; + var bits = re.exec(color_string); + if (bits) { + channels = processor(bits); + this.r = channels[0]; + this.g = channels[1]; + this.b = channels[2]; + this.ok = true; + } + + } + + // validate/cleanup values + this.r = (this.r < 0 || isNaN(this.r)) ? 0 : ((this.r > 255) ? 255 : this.r); + this.g = (this.g < 0 || isNaN(this.g)) ? 0 : ((this.g > 255) ? 255 : this.g); + this.b = (this.b < 0 || isNaN(this.b)) ? 0 : ((this.b > 255) ? 255 : this.b); + + // some getters + this.toRGB = function () { + return 'rgb(' + this.r + ', ' + this.g + ', ' + this.b + ')'; + } + this.toHex = function () { + var r = this.r.toString(16); + var g = this.g.toString(16); + var b = this.b.toString(16); + if (r.length == 1) r = '0' + r; + if (g.length == 1) g = '0' + g; + if (b.length == 1) b = '0' + b; + return '#' + r + g + b; + } + + // help + this.getHelpXML = function () { + + var examples = new Array(); + // add regexps + for (var i = 0; i < color_defs.length; i++) { + var example = color_defs[i].example; + for (var j = 0; j < example.length; j++) { + examples[examples.length] = example[j]; + } + } + // add type-in colors + for (var sc in simple_colors) { + examples[examples.length] = sc; + } + + var xml = document.createElement('ul'); + xml.setAttribute('id', 'rgbcolor-examples'); + for (var i = 0; i < examples.length; i++) { + try { + var list_item = document.createElement('li'); + var list_color = new RGBColor(examples[i]); + var example_div = document.createElement('div'); + example_div.style.cssText = + 'margin: 3px; ' + + 'border: 1px solid black; ' + + 'background:' + list_color.toHex() + '; ' + + 'color:' + list_color.toHex() + ; + example_div.appendChild(document.createTextNode('test')); + var list_item_value = document.createTextNode( + ' ' + examples[i] + ' -> ' + list_color.toRGB() + ' -> ' + list_color.toHex() + ); + list_item.appendChild(example_div); + list_item.appendChild(list_item_value); + xml.appendChild(list_item); + + } catch(e){} + } + return xml; + + } + } \ No newline at end of file diff --git a/js/canvg/rgbcolor.js b/js/canvg/rgbcolor.js deleted file mode 100644 index 0338a16..0000000 --- a/js/canvg/rgbcolor.js +++ /dev/null @@ -1,288 +0,0 @@ -/** - * A class to parse color values - * @author Stoyan Stefanov sstoo@gmail.com - * @link http://www.phpied.com/rgb-color-parser-in-javascript/ - * @license Use it if you like it - */ -function RGBColor(color_string) -{ - this.ok = false; - - // strip any leading # - if (color_string.charAt(0) == '#') { // remove # if any - color_string = color_string.substr(1,6); - } - - color_string = color_string.replace(/ /g,''); - color_string = color_string.toLowerCase(); - - // before getting into regexps, try simple matches - // and overwrite the input - var simple_colors = { - aliceblue: 'f0f8ff', - antiquewhite: 'faebd7', - aqua: '00ffff', - aquamarine: '7fffd4', - azure: 'f0ffff', - beige: 'f5f5dc', - bisque: 'ffe4c4', - black: '000000', - blanchedalmond: 'ffebcd', - blue: '0000ff', - blueviolet: '8a2be2', - brown: 'a52a2a', - burlywood: 'deb887', - cadetblue: '5f9ea0', - chartreuse: '7fff00', - chocolate: 'd2691e', - coral: 'ff7f50', - cornflowerblue: '6495ed', - cornsilk: 'fff8dc', - crimson: 'dc143c', - cyan: '00ffff', - darkblue: '00008b', - darkcyan: '008b8b', - darkgoldenrod: 'b8860b', - darkgray: 'a9a9a9', - darkgreen: '006400', - darkkhaki: 'bdb76b', - darkmagenta: '8b008b', - darkolivegreen: '556b2f', - darkorange: 'ff8c00', - darkorchid: '9932cc', - darkred: '8b0000', - darksalmon: 'e9967a', - darkseagreen: '8fbc8f', - darkslateblue: '483d8b', - darkslategray: '2f4f4f', - darkturquoise: '00ced1', - darkviolet: '9400d3', - deeppink: 'ff1493', - deepskyblue: '00bfff', - dimgray: '696969', - dodgerblue: '1e90ff', - feldspar: 'd19275', - firebrick: 'b22222', - floralwhite: 'fffaf0', - forestgreen: '228b22', - fuchsia: 'ff00ff', - gainsboro: 'dcdcdc', - ghostwhite: 'f8f8ff', - gold: 'ffd700', - goldenrod: 'daa520', - gray: '808080', - green: '008000', - greenyellow: 'adff2f', - honeydew: 'f0fff0', - hotpink: 'ff69b4', - indianred : 'cd5c5c', - indigo : '4b0082', - ivory: 'fffff0', - khaki: 'f0e68c', - lavender: 'e6e6fa', - lavenderblush: 'fff0f5', - lawngreen: '7cfc00', - lemonchiffon: 'fffacd', - lightblue: 'add8e6', - lightcoral: 'f08080', - lightcyan: 'e0ffff', - lightgoldenrodyellow: 'fafad2', - lightgrey: 'd3d3d3', - lightgreen: '90ee90', - lightpink: 'ffb6c1', - lightsalmon: 'ffa07a', - lightseagreen: '20b2aa', - lightskyblue: '87cefa', - lightslateblue: '8470ff', - lightslategray: '778899', - lightsteelblue: 'b0c4de', - lightyellow: 'ffffe0', - lime: '00ff00', - limegreen: '32cd32', - linen: 'faf0e6', - magenta: 'ff00ff', - maroon: '800000', - mediumaquamarine: '66cdaa', - mediumblue: '0000cd', - mediumorchid: 'ba55d3', - mediumpurple: '9370d8', - mediumseagreen: '3cb371', - mediumslateblue: '7b68ee', - mediumspringgreen: '00fa9a', - mediumturquoise: '48d1cc', - mediumvioletred: 'c71585', - midnightblue: '191970', - mintcream: 'f5fffa', - mistyrose: 'ffe4e1', - moccasin: 'ffe4b5', - navajowhite: 'ffdead', - navy: '000080', - oldlace: 'fdf5e6', - olive: '808000', - olivedrab: '6b8e23', - orange: 'ffa500', - orangered: 'ff4500', - orchid: 'da70d6', - palegoldenrod: 'eee8aa', - palegreen: '98fb98', - paleturquoise: 'afeeee', - palevioletred: 'd87093', - papayawhip: 'ffefd5', - peachpuff: 'ffdab9', - peru: 'cd853f', - pink: 'ffc0cb', - plum: 'dda0dd', - powderblue: 'b0e0e6', - purple: '800080', - red: 'ff0000', - rosybrown: 'bc8f8f', - royalblue: '4169e1', - saddlebrown: '8b4513', - salmon: 'fa8072', - sandybrown: 'f4a460', - seagreen: '2e8b57', - seashell: 'fff5ee', - sienna: 'a0522d', - silver: 'c0c0c0', - skyblue: '87ceeb', - slateblue: '6a5acd', - slategray: '708090', - snow: 'fffafa', - springgreen: '00ff7f', - steelblue: '4682b4', - tan: 'd2b48c', - teal: '008080', - thistle: 'd8bfd8', - tomato: 'ff6347', - turquoise: '40e0d0', - violet: 'ee82ee', - violetred: 'd02090', - wheat: 'f5deb3', - white: 'ffffff', - whitesmoke: 'f5f5f5', - yellow: 'ffff00', - yellowgreen: '9acd32' - }; - for (var key in simple_colors) { - if (color_string == key) { - color_string = simple_colors[key]; - } - } - // emd of simple type-in colors - - // array of color definition objects - var color_defs = [ - { - re: /^rgb((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3}))$/, - example: ['rgb(123, 234, 45)', 'rgb(255,234,245)'], - process: function (bits){ - return [ - parseInt(bits[1]), - parseInt(bits[2]), - parseInt(bits[3]) - ]; - } - }, - { - re: /^(\w{2})(\w{2})(\w{2})$/, - example: ['#00ff00', '336699'], - process: function (bits){ - return [ - parseInt(bits[1], 16), - parseInt(bits[2], 16), - parseInt(bits[3], 16) - ]; - } - }, - { - re: /^(\w{1})(\w{1})(\w{1})$/, - example: ['#fb0', 'f0f'], - process: function (bits){ - return [ - parseInt(bits[1] + bits[1], 16), - parseInt(bits[2] + bits[2], 16), - parseInt(bits[3] + bits[3], 16) - ]; - } - } - ]; - - // search through the definitions to find a match - for (var i = 0; i < color_defs.length; i++) { - var re = color_defs[i].re; - var processor = color_defs[i].process; - var bits = re.exec(color_string); - if (bits) { - channels = processor(bits); - this.r = channels[0]; - this.g = channels[1]; - this.b = channels[2]; - this.ok = true; - } - - } - - // validate/cleanup values - this.r = (this.r < 0 || isNaN(this.r)) ? 0 : ((this.r > 255) ? 255 : this.r); - this.g = (this.g < 0 || isNaN(this.g)) ? 0 : ((this.g > 255) ? 255 : this.g); - this.b = (this.b < 0 || isNaN(this.b)) ? 0 : ((this.b > 255) ? 255 : this.b); - - // some getters - this.toRGB = function () { - return 'rgb(' + this.r + ', ' + this.g + ', ' + this.b + ')'; - } - this.toHex = function () { - var r = this.r.toString(16); - var g = this.g.toString(16); - var b = this.b.toString(16); - if (r.length == 1) r = '0' + r; - if (g.length == 1) g = '0' + g; - if (b.length == 1) b = '0' + b; - return '#' + r + g + b; - } - - // help - this.getHelpXML = function () { - - var examples = new Array(); - // add regexps - for (var i = 0; i < color_defs.length; i++) { - var example = color_defs[i].example; - for (var j = 0; j < example.length; j++) { - examples[examples.length] = example[j]; - } - } - // add type-in colors - for (var sc in simple_colors) { - examples[examples.length] = sc; - } - - var xml = document.createElement('ul'); - xml.setAttribute('id', 'rgbcolor-examples'); - for (var i = 0; i < examples.length; i++) { - try { - var list_item = document.createElement('li'); - var list_color = new RGBColor(examples[i]); - var example_div = document.createElement('div'); - example_div.style.cssText = - 'margin: 3px; ' - + 'border: 1px solid black; ' - + 'background:' + list_color.toHex() + '; ' - + 'color:' + list_color.toHex() - ; - example_div.appendChild(document.createTextNode('test')); - var list_item_value = document.createTextNode( - ' ' + examples[i] + ' -> ' + list_color.toRGB() + ' -> ' + list_color.toHex() - ); - list_item.appendChild(example_div); - list_item.appendChild(list_item_value); - xml.appendChild(list_item); - - } catch(e){} - } - return xml; - - } - -} - diff --git a/js/functions.js b/js/functions.js index 4447a4b..58ad805 100644 --- a/js/functions.js +++ b/js/functions.js @@ -3037,7 +3037,7 @@ $(document).ready(function() { */ $(document).ready(function() { var elm = $('#sqlquery'); - if (elm.length > 0) { + if (elm.length > 0 && typeof CodeMirror != 'undefined') { codemirror_editor = CodeMirror.fromTextArea(elm[0], {lineNumbers: true, matchBrackets: true, indentUnit: 4, mode: "text/x-mysql"}); } }); @@ -3081,33 +3081,32 @@ function PMA_createqTip($elements, content, options) if ($('#no_hint').length > 0) { return; } + var o = { content: content, style: { - background: '#333', - border: { - radius: 5 + classes: { + tooltip: 'normalqTip', + content: 'normalqTipContent' }, - fontSize: '0.8em', - padding: '0 0.5em', name: 'dark' }, position: { target: 'mouse', corner: { target: 'rightMiddle', tooltip: 'leftMiddle' }, - adjust: { x: 20 } + adjust: { x: 10, y: 20 } }, show: { delay: 0, effect: { type: 'grow', - length: 100 + length: 150 } }, hide: { effect: { type: 'grow', - length: 150 + length: 200 } } } @@ -3130,6 +3129,17 @@ function PMA_getCellValue(td) { } }
+/* Loads a js file, an array may be passed as well */ +loadJavascript=function(file) { + if($.isArray(file)) { + for(var i=0; i<file.length; i++) { + $('head').append('<script type="text/javascript" src="'+file[i]+'"></script>'); + } + } else { + $('head').append('<script type="text/javascript" src="'+file+'"></script>'); + } +} + $(document).ready(function() { /** * Theme selector. diff --git a/js/messages.php b/js/messages.php index c941b1c..62950be 100644 --- a/js/messages.php +++ b/js/messages.php @@ -62,7 +62,6 @@ $js_messages['strClose'] = __('Close');
/* for server_status.js */ $js_messages['strEdit'] = __('Edit'); - $js_messages['strLiveTrafficChart'] = __('Live traffic chart'); $js_messages['strLiveConnChart'] = __('Live conn./process chart'); $js_messages['strLiveQueryChart'] = __('Live query chart'); @@ -183,6 +182,20 @@ $js_messages['strFailedParsingConfig'] = __('Failed parsing config file. It does $js_messages['strFailedBuildingGrid'] = __('Failed building chart grid with imported config. Resetting to default config...'); $js_messages['strImport'] = __('Import');
+$js_messages['strAnalyzeQuery'] = __('Analyse Query'); + +/* Server status advisor */ + +$js_messages['strAdvisorSystem'] = __('Advisor system'); +$js_messages['strPerformanceIssues'] = __('Possible performance issues'); +$js_messages['strIssuse'] = __('Issue'); +$js_messages['strRecommendation'] = __('Recommendation'); +$js_messages['strRuleDetails'] = __('Rule details'); +$js_messages['strJustification'] = __('Justification'); +$js_messages['strFormula'] = __('Used variable / formula'); +$js_messages['strTest'] = __('Test'); + + /* For inline query editing */ $js_messages['strGo'] = __('Go'); $js_messages['strCancel'] = __('Cancel'); diff --git a/js/server_status.js b/js/server_status.js index 5abb5df..d10c097 100644 --- a/js/server_status.js +++ b/js/server_status.js @@ -22,8 +22,8 @@ $(function() { }, format: function(s) { var num = jQuery.tablesorter.formatFloat( - s.replace(PMA_messages['strThousandsSeperator'],'') - .replace(PMA_messages['strDecimalSeperator'],'.') + s.replace(PMA_messages['strThousandsSeperator'], '') + .replace(PMA_messages['strDecimalSeperator'], '.') );
var factor = 1; @@ -36,7 +36,7 @@ $(function() { case 'T': factor = 12; break; }
- return num * Math.pow(10,factor); + return num * Math.pow(10, factor); }, type: "numeric" }); @@ -60,20 +60,26 @@ $(function() { var pos = $(this).offset();
// Hide if the mouseclick is outside the popupcontent - if(event.pageX < pos.left || event.pageY < pos.top || event.pageX > pos.left + $cnt.outerWidth() || event.pageY > pos.top + $cnt.outerHeight()) + if (event.pageX < pos.left + || event.pageY < pos.top + || event.pageX > pos.left + $cnt.outerWidth() + || event.pageY > pos.top + $cnt.outerHeight() + ) { $cnt.hide().removeClass('openedPopup'); + } }); }); });
$(function() { // Filters for status variables - var textFilter=null; + var textFilter = null; var alertFilter = false; - var categoryFilter=''; - var odd_row=false; - var text=''; // Holds filter text + var categoryFilter = ''; + var odd_row = false; + var text = ''; // Holds filter text var queryPieChart = null; + var monitorLoaded = false;
/* Chart configuration */ // Defines what the tabs are currently displaying (realtime or data) @@ -81,39 +87,8 @@ $(function() { // Holds the current chart instances for each tab var tabChart = new Object();
- /*** Table sort tooltip ***/ - - var $tableSortHint = $('<div class="dHint" style="display:none;">' + 'Click to sort' + '</div>'); - $('body').append($tableSortHint); - - $('table.sortable thead th').live('mouseover mouseout',function(e) { - if(e.type == 'mouseover') { - $tableSortHint - .stop(true, true) - .css({ - top: e.clientY + 15, - left: e.clientX + 15 - }) - .show('fast') - .data('shown',true); - } else { - $tableSortHint - .stop(true, true) - .hide(300,function() { - $(this).data('shown',false); - }); - } - }); - - $(document).mousemove(function(e) { - if($tableSortHint.data('shown') == true) - $tableSortHint.css({ - top: e.clientY + 15, - left: e.clientX + 15 - }) - }); - + PMA_createqTip($('table.sortable thead th'), PMA_messages['strSortHint']);
// Tell highcarts not to use UTC dates (global setting) Highcharts.setOptions({ @@ -123,15 +98,33 @@ $(function() { });
$.ajaxSetup({ - cache:false + cache: false });
// 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(); } + show: function(event, ui) { + // Fixes line break in the menu bar when the page overflows and scrollbar appears + menuResize(); + // Load Server status monitor + if (ui.tab.hash == '#statustabs_charting' && ! monitorLoaded) { + $('div#statustabs_charting').append( + '<img class="ajaxIcon" id="loadingMonitorIcon" src="' + + pmaThemeImage + 'ajax_clock_small.gif" alt="">' + ); + // Delay loading a bit so the tab loads and the user gets to see a ajax loading icon + setTimeout(function() { + loadJavascript(['js/jquery/timepicker.js', 'js/jquery/jquery.json-2.2.js', + 'js/jquery/jquery.sprintf.js', 'js/jquery/jquery.sortableTable.js', + 'js/codemirror/lib/codemirror.js', 'js/codemirror/mode/mysql/mysql.js', + 'js/server_status_monitor.js']); + }, 50); + + monitorLoaded = true; + } + } });
// Fixes wrong tab height with floated elements. See also http://bugs.jqueryui.com/ticket/5601 @@ -139,7 +132,7 @@ $(function() {
// Initialize each tab $('div.ui-tabs-panel').each(function() { - initTab($(this),null); + initTab($(this), null); tabStatus[$(this).attr('id')] = 'static'; });
@@ -148,12 +141,13 @@ $(function() {
// Handles refresh rate changing $('.buttonlinks select').change(function() { - var chart=tabChart[$(this).parents('div.ui-tabs-panel').attr('id')]; + var chart = tabChart[$(this).parents('div.ui-tabs-panel').attr('id')];
// Clear current timeout and set timeout with the new refresh rate clearTimeout(chart_activeTimeouts[chart.options.chart.renderTo]); - if(chart.options.realtime.postRequest) + if (chart.options.realtime.postRequest) { chart.options.realtime.postRequest.abort(); + }
chart.options.realtime.refreshRate = 1000*parseInt(this.value);
@@ -172,18 +166,18 @@ $(function() { // Ajax refresh of variables (always the first element in each tab) $('.buttonlinks a.tabRefresh').click(function() { // ui-tabs-panel class is added by the jquery tabs feature - var tab=$(this).parents('div.ui-tabs-panel'); + 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) { + $.get($(this).attr('href'), { ajax_request: 1 }, function(data) { $(that).find('img').hide(); - initTab(tab,data); + initTab(tab, data); });
- tabStatus[tab.attr('id')]='data'; + tabStatus[tab.attr('id')] = 'data';
return false; }); @@ -194,20 +188,22 @@ $(function() { // Live traffic charting $('.buttonlinks a.livetrafficLink').click(function() { // ui-tabs-panel class is added by the jquery tabs feature - var $tab=$(this).parents('div.ui-tabs-panel'); + var $tab = $(this).parents('div.ui-tabs-panel'); var tabstat = tabStatus[$tab.attr('id')];
- if(tabstat=='static' || tabstat=='liveconnections') { + if (tabstat == 'static' || tabstat == 'liveconnections') { var settings = { series: [ { name: PMA_messages['strChartKBSent'], data: [] }, { name: PMA_messages['strChartKBReceived'], data: [] } ], title: { text: PMA_messages['strChartServerTraffic'] }, - realtime: { url:'server_status.php?' + url_query, + realtime: { url: 'server_status.php?' + url_query, type: 'traffic', callback: function(chartObj, curVal, lastVal, numLoadedPoints) { - if(lastVal==null) return; + if (lastVal == null) { + return; + } chartObj.series[0].addPoint( { x: curVal.x, y: (curVal.y_sent - lastVal.y_sent) / 1024 }, false, @@ -223,13 +219,14 @@ $(function() { } }
- setupLiveChart($tab,this,settings); - if(tabstat == 'liveconnections') + setupLiveChart($tab, this, settings); + if (tabstat == 'liveconnections') { $tab.find('.buttonlinks a.liveconnectionsLink').html(PMA_messages['strLiveConnChart']); - tabStatus[$tab.attr('id')]='livetraffic'; + } + tabStatus[$tab.attr('id')] = 'livetraffic'; } else { $(this).html(PMA_messages['strLiveTrafficChart']); - setupLiveChart($tab,this,null); + setupLiveChart($tab, this, null); }
return false; @@ -237,20 +234,22 @@ $(function() {
// Live connection/process charting $('.buttonlinks a.liveconnectionsLink').click(function() { - var $tab=$(this).parents('div.ui-tabs-panel'); + var $tab = $(this).parents('div.ui-tabs-panel'); var tabstat = tabStatus[$tab.attr('id')];
- if(tabstat == 'static' || tabstat == 'livetraffic') { + if (tabstat == 'static' || tabstat == 'livetraffic') { var settings = { series: [ { name: PMA_messages['strChartConnections'], data: [] }, { name: PMA_messages['strChartProcesses'], data: [] } ], title: { text: PMA_messages['strChartConnectionsTitle'] }, - realtime: { url:'server_status.php?'+url_query, + realtime: { url: 'server_status.php?' + url_query, type: 'proc', - callback: function(chartObj, curVal, lastVal,numLoadedPoints) { - if(lastVal==null) return; + 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, @@ -266,13 +265,14 @@ $(function() { } };
- setupLiveChart($tab,this,settings); - if(tabstat == 'livetraffic') + setupLiveChart($tab, this, settings); + if (tabstat == 'livetraffic') { $tab.find('.buttonlinks a.livetrafficLink').html(PMA_messages['strLiveTrafficChart']); - tabStatus[$tab.attr('id')]='liveconnections'; + } + tabStatus[$tab.attr('id')] = 'liveconnections'; } else { $(this).html(PMA_messages['strLiveConnChart']); - setupLiveChart($tab,this,null); + setupLiveChart($tab, this, null); }
return false; @@ -283,17 +283,20 @@ $(function() { var $tab = $(this).parents('div.ui-tabs-panel'); var settings = null;
- if(tabStatus[$tab.attr('id')] == 'static') { + if (tabStatus[$tab.attr('id')] == 'static') { settings = { series: [ { name: PMA_messages['strChartIssuedQueries'], data: [] } ], title: { text: PMA_messages['strChartIssuedQueriesTitle'] }, - tooltip: { formatter:function() { return this.point.name; } }, - realtime: { url:'server_status.php?'+url_query, + 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) }, + 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 ); @@ -305,23 +308,23 @@ $(function() { $(this).html(PMA_messages['strLiveQueryChart']); }
- setupLiveChart($tab,this,settings); + setupLiveChart($tab, this, settings); tabStatus[$tab.attr('id')] = 'livequeries'; return false; });
- function setupLiveChart($tab,link,settings) { - if(settings != null) { + function setupLiveChart($tab, link, settings) { + if (settings != null) { // Loading a chart with existing chart => remove old chart first - if(tabStatus[$tab.attr('id')] != 'static') { + if (tabStatus[$tab.attr('id')] != 'static') { clearTimeout(chart_activeTimeouts[$tab.attr('id') + "_chart_cnt"]); - chart_activeTimeouts[$tab.attr('id')+"_chart_cnt"] = null; + chart_activeTimeouts[$tab.attr('id') + "_chart_cnt"] = null; tabChart[$tab.attr('id')].destroy(); // Also reset the select list $tab.find('.buttonlinks select').get(0).selectedIndex = 2; }
- if(! settings.chart) settings.chart = {}; + if (! settings.chart) settings.chart = {}; settings.chart.renderTo = $tab.attr('id') + "_chart_cnt";
$tab.find('.tabInnerContent') @@ -333,13 +336,13 @@ $(function() { $tab.find('.buttonlinks .refreshList').show(); } else { clearTimeout(chart_activeTimeouts[$tab.attr('id') + "_chart_cnt"]); - chart_activeTimeouts[$tab.attr('id') + "_chart_cnt"]=null; + 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')]='static'; + $tab.find('div#' + $tab.attr('id') + '_chart_cnt').remove(); + tabStatus[$tab.attr('id')] = 'static'; tabChart[$tab.attr('id')].destroy(); $tab.find('.buttonlinks a.tabRefresh').show(); - $tab.find('.buttonlinks select').get(0).selectedIndex=2; + $tab.find('.buttonlinks select').get(0).selectedIndex = 2; $tab.find('.buttonlinks .refreshList').hide(); } } @@ -351,10 +354,12 @@ $(function() { });
$('#filterText').keyup(function(e) { - word = $(this).val().replace(/_/g,' '); + word = $(this).val().replace(/_/g, ' ');
- if(word.length == 0) textFilter = null; - else textFilter = new RegExp("(^|_)" + word,'i'); + if (word.length == 0) { + textFilter = null; + } + else textFilter = new RegExp("(^|_)" + word, 'i');
text = word;
@@ -367,27 +372,32 @@ $(function() { });
$('input#dontFormat').change(function() { + // Hiding the table while changing values speeds up the process a lot + $('#serverstatusvariables').hide(); $('#serverstatusvariables td.value span.original').toggle(this.checked); $('#serverstatusvariables td.value span.formatted').toggle(! this.checked); + $('#serverstatusvariables').show(); });
/* Adjust DOM / Add handlers to the tabs */ - function initTab(tab,data) { + function initTab(tab, data) { switch(tab.attr('id')) { case 'statustabs_traffic': - if(data != null) tab.find('.tabInnerContent').html(data); + if (data != null) { + tab.find('.tabInnerContent').html(data); + } PMA_convertFootnotesToTooltips(); break; case 'statustabs_queries': - if(data != null) { + if (data != null) { queryPieChart.destroy(); tab.find('.tabInnerContent').html(data); }
// Build query statistics chart var cdata = new Array(); - $.each(jQuery.parseJSON($('#serverstatusquerieschart span').html()),function(key,value) { - cdata.push([key,parseInt(value)]); + $.each(jQuery.parseJSON($('#serverstatusquerieschart span').html()), function(key, value) { + cdata.push([key, parseInt(value)]); });
queryPieChart = PMA_createChart({ @@ -395,11 +405,11 @@ $(function() { renderTo: 'serverstatusquerieschart' }, title: { - text:'', - margin:0 + text: '', + margin: 0 }, series: [{ - type:'pie', + type: 'pie', name: PMA_messages['strChartQueryPie'], data: cdata }], @@ -410,21 +420,24 @@ $(function() { dataLabels: { enabled: true, formatter: function() { - return '<b>'+ this.point.name +'</b><br/> ' + Highcharts.numberFormat(this.percentage, 2) + ' %'; + return '<b>' + this.point.name +'</b><br/> ' + + Highcharts.numberFormat(this.percentage, 2) + ' %'; } } } }, tooltip: { formatter: function() { - return '<b>' + this.point.name + '</b><br/>' + Highcharts.numberFormat(this.y, 2) + '<br/>(' + Highcharts.numberFormat(this.percentage, 2) + ' %)'; + return '<b>' + this.point.name + '</b><br/>' + + Highcharts.numberFormat(this.y, 2) + '<br/>(' + + Highcharts.numberFormat(this.percentage, 2) + ' %)'; } } }); break;
case 'statustabs_allvars': - if(data != null) { + if (data != null) { tab.find('.tabInnerContent').html(data); filterVariables(); } @@ -438,7 +451,7 @@ $(function() { switch(tabid) { case 'statustabs_queries': $('#serverstatusqueriesdetails').tablesorter({ - sortList: [[3,1]], + sortList: [[3, 1]], widgets: ['zebra'], headers: { 1: { sorter: 'fancyNumber' }, @@ -453,7 +466,7 @@ $(function() {
case 'statustabs_allvars': $('#serverstatusvariables').tablesorter({ - sortList: [[0,0]], + sortList: [[0, 0]], widgets: ['zebra'], headers: { 1: { sorter: 'fancyNumber' } @@ -472,33 +485,38 @@ $(function() { var useful_links = 0; var section = text;
- if(categoryFilter.length > 0) section = categoryFilter; + if (categoryFilter.length > 0) { + section = categoryFilter; + }
- if(section.length > 1) { + if (section.length > 1) { $('#linkSuggestions span').each(function() { - if($(this).attr('class').indexOf('status_'+section) != -1) { + if ($(this).attr('class').indexOf('status_' + section) != -1) { useful_links++; - $(this).css('display',''); + $(this).css('display', ''); } else { - $(this).css('display','none'); + $(this).css('display', 'none'); }
}); }
- if(useful_links > 0) - $('#linkSuggestions').css('display',''); - else $('#linkSuggestions').css('display','none'); + if (useful_links > 0) { + $('#linkSuggestions').css('display', ''); + } else { + $('#linkSuggestions').css('display', 'none'); + }
- odd_row=false; + odd_row = false; $('#serverstatusvariables th.name').each(function() { - if((textFilter == null || textFilter.exec($(this).text())) + if ((textFilter == null || textFilter.exec($(this).text())) && (! alertFilter || $(this).next().find('span.attention').length>0) - && (categoryFilter.length == 0 || $(this).parent().hasClass('s_'+categoryFilter))) { + && (categoryFilter.length == 0 || $(this).parent().hasClass('s_' + categoryFilter)) + ) { odd_row = ! odd_row; - $(this).parent().css('display',''); - if(odd_row) { + $(this).parent().css('display', ''); + if (odd_row) { $(this).parent().addClass('odd'); $(this).parent().removeClass('even'); } else { @@ -506,22 +524,22 @@ $(function() { $(this).parent().removeClass('odd'); } } else { - $(this).parent().css('display','none'); + $(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 max, maxIdx, num = 0; var queryKeys = new Array(); var queryValues = new Array(); - var sumOther=0; - var sumTotal=0; + 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) { + $.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]; @@ -532,1705 +550,121 @@ $(function() {
while(queryKeys.length > 0) { max = 0; - for(var i=0; i < queryKeys.length; i++) { - if(queryValues[i] > max) { + for (var i = 0; i < queryKeys.length; i++) { + if (queryValues[i] > max) { max = queryValues[i]; maxIdx = i; } } - if(numQueries > 8 && num >= 6) + if (numQueries > 8 && num >= 6) { sumOther += queryValues[maxIdx]; - else pointInfo += queryKeys[maxIdx].substr(4).replace('_',' ') + ': ' + queryValues[maxIdx] + '<br>'; + } else { + pointInfo += queryKeys[maxIdx].substr(4).replace('_', ' ') + ': ' + queryValues[maxIdx] + '<br>'; + }
- queryKeys.splice(maxIdx,1); - queryValues.splice(maxIdx,1); + queryKeys.splice(maxIdx, 1); + queryValues.splice(maxIdx, 1); num++; }
- if(sumOther>0) + if (sumOther>0) { pointInfo += PMA_messages['strOther'] + ': ' + sumOther; - + } + return pointInfo; }
/**** Server config advisor ****/
$('a[href="#openAdvisorInstructions"]').click(function() { - $('#advisorInstructionsDialog').dialog(); + var dlgBtns = {}; + + dlgBtns[PMA_messages['strClose']] = function() { + $(this).dialog('close'); + } + + $('#advisorInstructionsDialog').attr('title', PMA_messages['strAdvisorSystem']); + $('#advisorInstructionsDialog').dialog({ + width: 700, + buttons: dlgBtns + }); });
$('a[href="#startAnalyzer"]').click(function() { var $cnt = $('#statustabs_advisor .tabInnerContent'); $cnt.html('<img class="ajaxIcon" src="' + pmaThemeImage + 'ajax_clock_small.gif" alt="">'); - - $.get('server_status.php?'+url_query, { ajax_request: true, advisor: true },function(data) { + + $.get('server_status.php?' + url_query, { ajax_request: true, advisor: true }, function(data) { var $tbody, $tr, str, even = true;
data = $.parseJSON(data); - $cnt.html('<p><b>Possible performance issues</b></p>'); - if(data.fired.length > 0) { - $cnt.append('<table class="data" id="rulesFired" border="0"><thead><tr><th>Issue</th><th>Recommendation</th></tr></thead><tbody></tbody></table>'); + + $cnt.html(''); + + if (data.parse.errors.length > 0) { + $cnt.append('<b>Rules file not well formed, following errors were found:</b><br />- '); + $cnt.append(data.parse.errors.join('<br/>- ')); + $cnt.append('<p></p>'); + } + + if (data.run.errors.length > 0) { + $cnt.append('<b>Errors occured while executing rule expressions:</b><br />- '); + $cnt.append(data.run.errors.join('<br/>- ')); + $cnt.append('<p></p>'); + } + + if (data.run.fired.length > 0) { + $cnt.append('<p><b>' + PMA_messages['strPerformanceIssues'] + '</b></p>'); + $cnt.append('<table class="data" id="rulesFired" border="0"><thead><tr>' + + '<th>' + PMA_messages['strIssuse'] + '</th><th>' + PMA_messages['strRecommendation'] + + '</th></tr></thead><tbody></tbody></table>'); $tbody = $cnt.find('table#rulesFired'); - $.each(data.fired, function(key,value) { - $tbody.append($tr = $('<tr class="linkElem noclick ' + (even ? 'even' : 'odd') + '"><td>' + value.issue + '</td>' + - '<td>' + value.recommendation + ' </td></tr>')); + + var rc_stripped; + + $.each(data.run.fired, function(key, value) { + // recommendation may contain links, don't show those in overview table (clicking on them redirects the user) + rc_stripped = $.trim($('<div>').html(value.recommendation).text()) + $tbody.append($tr = $('<tr class="linkElem noclick ' + (even ? 'even' : 'odd') + '"><td>' + + value.issue + '</td><td>' + rc_stripped + ' </td></tr>')); even = !even; - - $tr.data('rule',value); + $tr.data('rule', value); + $tr.click(function() { var rule = $(this).data('rule'); - $('div#emptyDialog').attr('title','Rule details'); + $('div#emptyDialog').attr('title', PMA_messages['strRuleDetails']); $('div#emptyDialog').html( - '<p><b>Issue:</b><br />' + rule.issue + '</p>' + - '<p><b>Recommendation:</b><br />' + rule.recommendation + '</p>' + - '<p><b>Justification:</b><br />' + rule.justification + '</p>' + - '<p><b>Used variable / formula:</b><br />' + rule.formula + '</p>' + - '<p><b>Test:</b><br />' + rule.test + '</p>' + '<p><b>' + PMA_messages['strIssuse'] + ':</b><br />' + rule.issue + '</p>' + + '<p><b>' + PMA_messages['strRecommendation'] + ':</b><br />' + rule.recommendation + '</p>' + + '<p><b>' + PMA_messages['strJustification'] + ':</b><br />' + rule.justification + '</p>' + + '<p><b>' + PMA_messages['strFormula'] + ':</b><br />' + rule.formula + '</p>' + + '<p><b>' + PMA_messages['strTest'] + ':</b><br />' + rule.test + '</p>' ); - $('div#emptyDialog').dialog({ - width: 600, - buttons: { - 'Close' : function() { - $(this).dialog('close'); - } - } - }); + + var dlgBtns = {}; + dlgBtns[PMA_messages['strClose']] = function() { + $(this).dialog('close'); + }; + + $('div#emptyDialog').dialog({ width: 600, buttons: dlgBtns }); }); }); } }); - - return false; - }); - - - /**** Monitor charting implementation ****/ - /* Saves the previous ajax response for differential values */ - var oldChartData = null; - // Holds about to created chart - var newChart = null; - var chartSpacing; - - // Runtime parameter of the monitor, is being fully set in initGrid() - var runtime = { - // Holds all visible charts in the grid - charts: null, - // Stores the timeout handler so it can be cleared - refreshTimeout: null, - // Stores the GET request to refresh the charts - refreshRequest: null, - // Chart auto increment - chartAI: 0, - // To play/pause the monitor - redrawCharts: false, - // Object that contains a list of nodes that need to be retrieved from the server for chart updates - dataList: [], - // Current max points per chart (needed for auto calculation) - gridMaxPoints: 20, - // displayed time frame - xmin: -1, - xmax: -1 - }; - - var monitorSettings = null; - - var defaultMonitorSettings = { - columns: 3, - chartSize: { width: 295, height: 250 }, - // Max points in each chart. Settings it to 'auto' sets gridMaxPoints to (chartwidth - 40) / 12 - gridMaxPoints: 'auto', - /* Refresh rate of all grid charts in ms */ - gridRefresh: 5000 - }; - - // Allows drag and drop rearrange and print/edit icons on charts - var editMode = false; - - var presetCharts = { - 'cpu-WINNT': { - title: PMA_messages['strSystemCPUUsage'], - nodes: [{ dataType: 'cpu', name: PMA_messages['strAverageLoad'], dataPoint: 'loadavg', unit: '%'}] - }, - 'memory-WINNT': { - title: PMA_messages['strSystemMemory'], - nodes: [ - { dataType: 'memory', name: PMA_messages['strTotalMemory'], dataPoint: 'MemTotal', valueDivisor: 1024, unit: PMA_messages['strMiB'] }, - { dataType: 'memory', name: PMA_messages['strUsedMemory'], dataPoint: 'MemUsed', valueDivisor: 1024, unit: PMA_messages['strMiB'] } - ] - }, - 'swap-WINNT': { - title: PMA_messages['strSystemSwap'], - nodes: [ - { dataType: 'memory', name: PMA_messages['strTotalSwap'], dataPoint: 'SwapTotal', valueDivisor: 1024, unit: PMA_messages['strMiB'] }, - { dataType: 'memory', name: PMA_messages['strUsedSwap'], dataPoint: 'SwapUsed', valueDivisor: 1024, unit: PMA_messages['strMiB'] } - ] - }, - 'cpu-Linux': { - title: PMA_messages['strSystemCPUUsage'], - nodes: [ - { dataType: 'cpu', - name: PMA_messages['strAverageLoad'], - unit: '%', - transformFn: 'cpu-linux' - } - ] - }, - 'memory-Linux': { - title: PMA_messages['strSystemMemory'], - nodes: [ - { dataType: 'memory', name: PMA_messages['strUsedMemory'], dataPoint: 'MemUsed', valueDivisor: 1024, unit: PMA_messages['strMiB'] }, - { dataType: 'memory', name: PMA_messages['strCachedMemory'], dataPoint: 'Cached', valueDivisor: 1024, unit: PMA_messages['strMiB'] }, - { dataType: 'memory', name: PMA_messages['strBufferedMemory'], dataPoint: 'Buffers', valueDivisor: 1024, unit: PMA_messages['strMiB'] }, - { dataType: 'memory', name: PMA_messages['strFreeMemory'], dataPoint:'MemFree', valueDivisor: 1024, unit: PMA_messages['strMiB'] } - ], - settings: { - chart: { - type: 'area', - animation: false - }, - plotOptions: { - area: { - stacking: 'percent' - } - } - } - }, - 'swap-Linux': { - title: PMA_messages['strSystemSwap'], - nodes: [ - { dataType: 'memory', name: PMA_messages['strTotalSwap'], dataPoint: 'SwapUsed', valueDivisor: 1024, unit: PMA_messages['strMiB'] }, - { dataType: 'memory', name: PMA_messages['strCachedSwap'], dataPoint: 'SwapCached', valueDivisor: 1024, unit: PMA_messages['strMiB'] }, - { dataType: 'memory', name: PMA_messages['strFreeSwap'], dataPoint: 'SwapFree', valueDivisor: 1024, unit: PMA_messages['strMiB'] } - ], - settings: { - chart: { - type: 'area', - animation: false - }, - plotOptions: { - area: { - stacking: 'percent' - } - } - } - } - }; - - // Default setting - defaultChartGrid = { - 'c0': { title: PMA_messages['strQuestions'], - nodes: [{ dataType: 'statusvar', name: PMA_messages['strQuestions'], dataPoint: 'Questions', display: 'differential' }] - }, - 'c1': { - title: PMA_messages['strChartConnectionsTitle'], - nodes: [ { dataType: 'statusvar', name: PMA_messages['strConnections'], dataPoint: 'Connections', display: 'differential' }, - { dataType: 'proc', name: PMA_messages['strProcesses'], dataPoint: 'processes'} ] - }, - 'c2': { - title: PMA_messages['strTraffic'], - nodes: [ - { dataType: 'statusvar', name: PMA_messages['strBytesSent'], dataPoint: 'Bytes_sent', display: 'differential', valueDivisor: 1024, unit: PMA_messages['strKiB'] }, - { dataType: 'statusvar', name: PMA_messages['strBytesReceived'], dataPoint: 'Bytes_received', display: 'differential', valueDivisor: 1024, unit: PMA_messages['strKiB'] } - ] - } - }; - - // Server is localhost => We can add cpu/memory/swap - if(server_db_isLocal) { - defaultChartGrid['c3'] = presetCharts['cpu-' + server_os]; - defaultChartGrid['c4'] = presetCharts['memory-' + server_os]; - defaultChartGrid['c5'] = presetCharts['swap-' + server_os]; - } - - var gridbuttons = { - cogButton: { - //enabled: true, - symbol: 'url(' + pmaThemeImage + 's_cog.png)', - x: -36, - symbolFill: '#B5C9DF', - hoverSymbolFill: '#779ABF', - _titleKey: 'settings', - menuName: 'gridsettings', - menuItems: [{ - textKey: 'editChart', - onclick: function() { - editChart(this); - } - }, { - textKey: 'removeChart', - onclick: function() { - removeChart(this); - } - }] - } - }; - - Highcharts.setOptions({ - lang: { - settings: PMA_messages['strSettings'], - removeChart: PMA_messages['strRemoveChart'], - editChart: PMA_messages['strEditChart'] - } - }); - - $('a[href="#rearrangeCharts"], a[href="#endChartEditMode"]').click(function() { - editMode = !editMode; - if($(this).attr('href') == '#endChartEditMode') editMode = false; - - // Icon graphics have zIndex 19,20 and 21. Let's just hope nothing else has the same zIndex - $('table#chartGrid div svg').find('*[zIndex=20], *[zIndex=21], *[zIndex=19]').toggle(editMode) - - $('a[href="#endChartEditMode"]').toggle(editMode); - - if(editMode) { - // Close the settings popup - $('#statustabs_charting .popupContent').hide().removeClass('openedPopup'); - - $("#chartGrid").sortableTable({ - ignoreRect: { - top: 8, - left: chartSize().width - 63, - width: 54, - height: 24 - }, - events: { - // Drop event. The drag child element is moved into the drop element - // and vice versa. So the parameters are switched. - drop: function(drag, drop, pos) { - var dragKey, dropKey, dropRender; - var dragRender = $(drag).children().first().attr('id'); - - if($(drop).children().length > 0) - dropRender = $(drop).children().first().attr('id'); - - // Find the charts in the array - $.each(runtime.charts, function(key, value) { - if(value.chart.options.chart.renderTo == dragRender) - dragKey = key; - if(dropRender && value.chart.options.chart.renderTo == dropRender) - dropKey = key; - }); - - // Case 1: drag and drop are charts -> Switch keys - if(dropKey) { - if(dragKey) { - dragChart = runtime.charts[dragKey]; - runtime.charts[dragKey] = runtime.charts[dropKey]; - runtime.charts[dropKey] = dragChart; - } else { - // Case 2: drop is a empty cell => just completely rebuild the ids - var keys = []; - var dropKeyNum = parseInt(dropKey.substr(1)); - var insertBefore = pos.col + pos.row * monitorSettings.columns; - var values = []; - var newChartList = {}; - var c = 0; - - $.each(runtime.charts, function(key, value) { - if(key != dropKey) - keys.push(key); - }); - - keys.sort(); - - // Rebuilds all ids, with the dragged chart correctly inserted - for(var i=0; i<keys.length; i++) { - if(keys[i] == insertBefore) { - newChartList['c' + (c++)] = runtime.charts[dropKey]; - insertBefore = -1; // Insert ok - } - newChartList['c' + (c++)] = runtime.charts[keys[i]]; - } - - // Not inserted => put at the end - if(insertBefore != -1) - newChartList['c' + (c++)] = runtime.charts[dropKey]; - - runtime.charts = newChartList; - } - - saveMonitor(); - } - } - } - }); - - } else { - $("#chartGrid").sortableTable('destroy'); - saveMonitor(); // Save settings - } - - return false; - }); - - // global settings - $('div#statustabs_charting div.popupContent select[name="chartColumns"]').change(function() { - monitorSettings.columns = parseInt(this.value); - - var newSize = chartSize(); - - // Empty cells should keep their size so you can drop onto them - $('table#chartGrid tr td').css('width',newSize.width + 'px'); - - /* Reorder all charts that it fills all column cells */ - var numColumns; - var $tr = $('table#chartGrid tr:first'); - var row=0; - while($tr.length != 0) { - numColumns = 1; - // To many cells in one row => put into next row - $tr.find('td').each(function() { - if(numColumns > monitorSettings.columns) { - if($tr.next().length == 0) $tr.after('<tr></tr>'); - $tr.next().prepend($(this)); - } - numColumns++; - }); - - // To little cells in one row => for each cell to little, move all cells backwards by 1 - if($tr.next().length > 0) { - var cnt = monitorSettings.columns - $tr.find('td').length; - for(var i=0; i < cnt; i++) { - $tr.append($tr.next().find('td:first')); - $tr.nextAll().each(function() { - if($(this).next().length != 0) - $(this).append($(this).next().find('td:first')); - }); - } - } - - $tr = $tr.next(); - row++; - } - - /* Apply new chart size to all charts */ - $.each(runtime.charts, function(key, value) { - value.chart.setSize( - newSize.width, - newSize.height, - false - ); - }); - - if(monitorSettings.gridMaxPoints == 'auto') - runtime.gridMaxPoints = Math.round((newSize.width - 40) / 12); - - runtime.xmin = new Date().getTime() - server_time_diff - runtime.gridMaxPoints * monitorSettings.gridRefresh; - runtime.xmax = new Date().getTime() - server_time_diff + monitorSettings.gridRefresh; - - if(editMode) - $("#chartGrid").sortableTable('refresh'); - - saveMonitor(); // Save settings - }); - - $('div#statustabs_charting div.popupContent select[name="gridChartRefresh"]').change(function() { - monitorSettings.gridRefresh = parseInt(this.value) * 1000; - clearTimeout(runtime.refreshTimeout); - - if(runtime.refreshRequest) - runtime.refreshRequest.abort(); - - runtime.xmin = new Date().getTime() - server_time_diff - runtime.gridMaxPoints * monitorSettings.gridRefresh; - runtime.xmax = new Date().getTime() - server_time_diff + monitorSettings.gridRefresh; - - $.each(runtime.charts, function(key, value) { - value.chart.xAxis[0].setExtremes(runtime.xmin, runtime.xmax, false); - }); - - runtime.refreshTimeout = setTimeout(refreshChartGrid, monitorSettings.gridRefresh); - - saveMonitor(); // Save settings - }); - - $('a[href="#addNewChart"]').click(function() { - var dlgButtons = { }; - - dlgButtons[PMA_messages['strAddChart']] = function() { - var type = $('input[name="chartType"]:checked').val(); - - if(type == 'cpu' || type == 'memory' || type=='swap') - newChart = presetCharts[type + '-' + server_os]; - else { - if(! newChart || ! newChart.nodes || newChart.nodes.length == 0) { - alert(PMA_messages['strAddOneSeriesWarning']); - return; - } - } - - newChart.title = $('input[name="chartTitle"]').attr('value'); - // Add a cloned object to the chart grid - addChart($.extend(true, {}, newChart)); - - newChart = null; - - saveMonitor(); // Save settings - - $(this).dialog("close"); - }; - - dlgButtons[PMA_messages['strClose']] = function() { - newChart = null; - $('span#clearSeriesLink').hide(); - $('#seriesPreview').html(''); - $(this).dialog("close"); - }; - - $('div#addChartDialog').dialog({ - width:'auto', - height:'auto', - buttons: dlgButtons - }); - - $('div#addChartDialog #seriesPreview').html('<i>' + PMA_messages['strNone'] + '</i>'); - + return false; });
- $('a[href="#exportMonitorConfig"]').click(function() { - var gridCopy = {}; - - $.each(runtime.charts, function(key, elem) { - gridCopy[key] = {}; - gridCopy[key].nodes = elem.nodes; - gridCopy[key].settings = elem.settings; - gridCopy[key].title = elem.title; - }); - - var exportData = { - monitorCharts: gridCopy, - monitorSettings: monitorSettings - }; - var $form; - - $('body').append($form = $('<form method="post" action="file_echo.php?'+url_query+'&filename=1" style="display:none;"></form>')); - - $form.append('<input type="hidden" name="monitorconfig" value="' + encodeURI($.toJSON(exportData)) + '">'); - $form.submit(); - $form.remove(); - }); - - $('a[href="#importMonitorConfig"]').click(function() { - $('div#emptyDialog').attr('title','Import monitor configuration'); - $('div#emptyDialog').html('Please select the file you want to import:<br/><form action="file_echo.php?'+url_query+'&import=1" method="post" enctype="multipart/form-data">'+ - '<input type="file" name="file"> <input type="hidden" name="import" value="1"> </form>'); - - var dlgBtns = {}; - - dlgBtns[PMA_messages['strImport']] = function() { - var $iframe, $form; - $('body').append($iframe = $('<iframe id="monitorConfigUpload" style="display:none;"></iframe>')); - var d = $iframe[0].contentWindow.document; - d.open(); d.close(); - mew = d; - - $iframe.load(function() { - var json; - - // Try loading config - try { - var data = $('body',$('iframe#monitorConfigUpload')[0].contentWindow.document).html(); - // Chrome wraps around '<pre style="word-wrap: break-word; white-space: pre-wrap;">' to any text content -.- - json = $.secureEvalJSON(data.substring(data.indexOf("{"), data.lastIndexOf("}") + 1)); - } catch (err) { - alert(PMA_messages['strFailedParsingConfig']); - $('div#emptyDialog').dialog('close'); - return; - } - - // Basic check, is this a monitor config json? - if(!json || ! json.monitorCharts || ! json.monitorCharts) { - alert(PMA_messages['strFailedParsingConfig']); - $('div#emptyDialog').dialog('close'); - return; - } - - // If json ok, try applying config - try { - window.localStorage['monitorCharts'] = $.toJSON(json.monitorCharts); - window.localStorage['monitorSettings'] = $.toJSON(json.monitorSettings); - rebuildGrid(); - } catch(err) { - alert(PMA_messages['strFailedBuildingGrid']); - // If an exception is thrown, load default again - window.localStorage.removeItem('monitorCharts'); - window.localStorage.removeItem('monitorSettings'); - rebuildGrid(); - } - - $('div#emptyDialog').dialog('close'); - }); - - $("body", d).append($form=$('div#emptyDialog').find('form')); - $form.submit(); - $('div#emptyDialog').append('<img class="ajaxIcon" src="' + pmaThemeImage + 'ajax_clock_small.gif" alt="">'); - }; - - dlgBtns[PMA_messages['strCancel']] = function() { - $(this).dialog('close'); - } - - - $('div#emptyDialog').dialog({ - width: 'auto', - height: 'auto', - buttons: dlgBtns - }); - }); - - $('a[href="#clearMonitorConfig"]').click(function() { - window.localStorage.removeItem('monitorCharts'); - window.localStorage.removeItem('monitorSettings'); - $(this).hide(); - rebuildGrid(); - }); - - $('a[href="#pauseCharts"]').click(function() { - runtime.redrawCharts = ! runtime.redrawCharts; - if(! runtime.redrawCharts) - $(this).html('<img src="themes/dot.gif" class="icon ic_play" alt="" /> ' + PMA_messages['strResumeMonitor']); - else { - $(this).html('<img src="themes/dot.gif" class="icon ic_pause" alt="" /> ' + PMA_messages['strPauseMonitor']); - if(! runtime.charts) { - initGrid(); - $('a[href="#settingsPopup"]').show(); - } - } - return false; - }); - - $('a[href="#monitorInstructionsDialog"]').click(function() { - var $dialog = $('div#monitorInstructionsDialog'); - - $dialog.dialog({ - width: 595, - height: 'auto' - }).find('img.ajaxIcon').show(); - - var loadLogVars = function(getvars) { - vars = { ajax_request: true, logging_vars: true }; - if(getvars) $.extend(vars,getvars); - - $.get('server_status.php?' + url_query, vars, - function(data) { - var logVars = $.parseJSON(data), - icon = 'ic_s_success', msg='', str=''; - - if(logVars['general_log'] == 'ON') { - if(logVars['slow_query_log'] == 'ON') - msg = PMA_messages['strBothLogOn']; - else - msg = PMA_messages['strGenLogOn']; - } - - if(msg.length == 0 && logVars['slow_query_log'] == 'ON') { - msg = PMA_messages['strSlowLogOn']; - } - - if(msg.length == 0) { - icon = 'ic_s_error'; - msg = PMA_messages['strBothLogOff']; - } - - str = '<b>' + PMA_messages['strCurrentSettings'] + '</b><br><div class="smallIndent">'; - str += '<img src="themes/dot.gif" class="icon ' + icon + '" alt=""/> ' + msg + '<br />'; - - if(logVars['log_output'] != 'TABLE') - str += '<img src="themes/dot.gif" class="icon ic_s_error" alt=""/> ' + PMA_messages['strLogOutNotTable'] + '<br />'; - else - str += '<img src="themes/dot.gif" class="icon ic_s_success" alt=""/> ' + PMA_messages['strLogOutIsTable'] + '<br />'; - - if(logVars['slow_query_log'] == 'ON') { - if(logVars['long_query_time'] > 2) - str += '<img src="themes/dot.gif" class="icon ic_s_attention" alt=""/> ' - + $.sprintf(PMA_messages['strSmallerLongQueryTimeAdvice'], logVars['long_query_time']) - + '<br />'; - - if(logVars['long_query_time'] < 2) - str += '<img src="themes/dot.gif" class="icon ic_s_success" alt=""/> ' - + $.sprintf(PMA_messages['strLongQueryTimeSet'], logVars['long_query_time']) - + '<br />'; - } - - str += '</div>'; - - if(is_superuser) { - str += '<p></p><b>Change settings</b>'; - str += '<div class="smallIndent">'; - str += PMA_messages['strSettingsAppliedGlobal'] + '<br/>'; - - var varValue = 'TABLE'; - if(logVars['log_output'] == 'TABLE') varValue = 'FILE'; - - str += '- <a class="set" href="#log_output-' + varValue + '">' - + $.sprintf(PMA_messages['strSetLogOutput'], varValue) - + ' </a><br />'; - - if(logVars['general_log'] != 'ON') - str += '- <a class="set" href="#general_log-ON">' - + $.sprintf(PMA_messages['strEnableVar'], 'general_log') - + ' </a><br />'; - else - str += '- <a class="set" href="#general_log-OFF">' - + $.sprintf(PMA_messages['strDisableVar'], 'general_log') - + ' </a><br />'; - - if(logVars['slow_query_log'] != 'ON') - str += '- <a class="set" href="#slow_query_log-ON">' - + $.sprintf(PMA_messages['strEnableVar'], 'slow_query_log') - + ' </a><br />'; - else - str += '- <a class="set" href="#slow_query_log-OFF">' - + $.sprintf(PMA_messages['strDisableVar'], 'slow_query_log') - + ' </a><br />'; - - - varValue = 5; - if(logVars['long_query_time'] > 2) varValue = 1; - - str += '- <a class="set" href="#long_query_time-' + varValue + '">' - + $.sprintf(PMA_messages['setSetLongQueryTime'], varValue) - + ' </a><br />'; - - } else - str += PMA_messages['strNoSuperUser'] + '<br/>'; - - str += '</div>'; - - $dialog.find('div.monitorUse').toggle( - logVars['log_output'] == 'TABLE' && (logVars['slow_query_log'] == 'ON' || logVars['general_log'] == 'ON') - ); - - $dialog.find('div.ajaxContent').html(str); - $dialog.find('img.ajaxIcon').hide(); - $dialog.find('a.set').click(function() { - var nameValue = $(this).attr('href').split('-'); - loadLogVars({ varName: nameValue[0].substr(1), varValue: nameValue[1]}); - $dialog.find('img.ajaxIcon').show(); - }); - } - ); - }; - - - loadLogVars(); - - return false; - }); - - $('input[name="chartType"]').change(function() { - $('#chartVariableSettings').toggle(this.checked && this.value == 'variable'); - var title = $('input[name="chartTitle"]').attr('value'); - if(title == PMA_messages['strChartTitle'] || title == $('label[for="'+$('input[name="chartTitle"]').data('lastRadio')+'"]').text()) { - $('input[name="chartTitle"]').data('lastRadio',$(this).attr('id')); - $('input[name="chartTitle"]').attr('value',$('label[for="'+$(this).attr('id')+'"]').text()); - } - - }); - - $('input[name="useDivisor"]').change(function() { - $('span.divisorInput').toggle(this.checked); - }); - $('input[name="useUnit"]').change(function() { - $('span.unitInput').toggle(this.checked); - }); - - $('select[name="varChartList"]').change(function () { - if(this.selectedIndex!=0) - $('#variableInput').attr('value',this.value); - }); - - $('a[href="#kibDivisor"]').click(function() { - $('input[name="valueDivisor"]').attr('value',1024); - $('input[name="valueUnit"]').attr('value',PMA_messages['strKiB']); - $('span.unitInput').toggle(true); - $('input[name="useUnit"]').prop('checked',true); - return false; - }); - - $('a[href="#mibDivisor"]').click(function() { - $('input[name="valueDivisor"]').attr('value',1024*1024); - $('input[name="valueUnit"]').attr('value',PMA_messages['strMiB']); - $('span.unitInput').toggle(true); - $('input[name="useUnit"]').prop('checked',true); - return false; - }); - - $('a[href="#submitClearSeries"]').click(function() { - $('#seriesPreview').html('<i>' + PMA_messages['strNone'] + '</i>'); - newChart = null; - $('span#clearSeriesLink').hide(); - }); - - $('a[href="#submitAddSeries"]').click(function() { - if($('input#variableInput').attr('value').length == 0) return false; - - if(newChart == null) { - $('#seriesPreview').html(''); - - newChart = { - title: $('input[name="chartTitle"]').attr('value'), - nodes: [] - } - } - - var serie = { - dataType:'statusvar', - dataPoint: $('input#variableInput').attr('value'), - name: $('input#variableInput').attr('value'), - display: $('input[name="differentialValue"]').attr('checked') ? 'differential' : '' - }; - - if(serie.dataPoint == 'Processes') serie.dataType='proc'; - - if($('input[name="useDivisor"]').attr('checked')) - serie.valueDivisor = parseInt($('input[name="valueDivisor"]').attr('value')); - - if($('input[name="useUnit"]').attr('checked')) - serie.unit = $('input[name="valueUnit"]').attr('value'); - - - - var str = serie.display == 'differential' ? ', ' + PMA_messages['strDifferential'] : ''; - str += serie.valueDivisor ? (', ' + $.sprintf(PMA_messages['strDividedBy'], serie.valueDivisor)) : ''; - - $('#seriesPreview').append('- ' + serie.dataPoint + str + '<br>'); - - newChart.nodes.push(serie); - - $('input#variableInput').attr('value',''); - $('input[name="differentialValue"]').attr('checked',true); - $('input[name="useDivisor"]').attr('checked',false); - $('input[name="useUnit"]').attr('checked',false); - $('input[name="useDivisor"]').trigger('change'); - $('input[name="useUnit"]').trigger('change'); - $('select[name="varChartList"]').get(0).selectedIndex=0; - - $('span#clearSeriesLink').show(); - - return false; - }); - - $("input#variableInput").autocomplete({ - source: variableNames - }); - - - function initGrid() { - var settings; - var series; - - /* Apply default values & config */ - if(window.localStorage) { - if(window.localStorage['monitorCharts']) - runtime.charts = $.parseJSON(window.localStorage['monitorCharts']); - if(window.localStorage['monitorSettings']) - monitorSettings = $.parseJSON(window.localStorage['monitorSettings']); - - $('a[href="#clearMonitorConfig"]').toggle(runtime.charts != null); - } - - if(runtime.charts == null) - runtime.charts = defaultChartGrid; - if(monitorSettings == null) - monitorSettings = defaultMonitorSettings; - - $('select[name="gridChartRefresh"]').attr('value',monitorSettings.gridRefresh / 1000); - $('select[name="chartColumns"]').attr('value',monitorSettings.columns); - - if(monitorSettings.gridMaxPoints == 'auto') - runtime.gridMaxPoints = Math.round((monitorSettings.chartSize.width - 40) / 12); - else - runtime.gridMaxPoints = monitorSettings.gridMaxPoints; - - runtime.xmin = new Date().getTime() - server_time_diff - runtime.gridMaxPoints * monitorSettings.gridRefresh; - runtime.xmax = new Date().getTime() - server_time_diff + monitorSettings.gridRefresh; - - /* Calculate how much spacing there is between each chart */ - $('table#chartGrid').html('<tr><td></td><td></td></tr><tr><td></td><td></td></tr>'); - chartSpacing = { - width: $('table#chartGrid td:nth-child(2)').offset().left - $('table#chartGrid td:nth-child(1)').offset().left, - height: $('table#chartGrid tr:nth-child(2) td:nth-child(2)').offset().top - $('table#chartGrid tr:nth-child(1) td:nth-child(1)').offset().top - } - $('table#chartGrid').html(''); - - /* Add all charts - in correct order */ - var keys = []; - $.each(runtime.charts, function(key, value) { - keys.push(key); - }); - keys.sort(); - for(var i=0; i<keys.length; i++) - addChart(runtime.charts[keys[i]],true); - - /* Fill in missing cells */ - var numCharts = $('table#chartGrid .monitorChart').length; - var numMissingCells = (monitorSettings.columns - numCharts % monitorSettings.columns) % monitorSettings.columns; - for(var i=0; i < numMissingCells; i++) { - $('table#chartGrid tr:last').append('<td></td>'); - } - - // Empty cells should keep their size so you can drop onto them - $('table#chartGrid tr td').css('width',chartSize().width + 'px'); - - buildRequiredDataList(); - refreshChartGrid(); - } - - function destroyGrid() { - if(runtime.charts) - $.each(runtime.charts, function(key, value) { - try { - value.chart.destroy(); - } catch(err) {} - }); - try { - runtime.refreshRequest.abort(); - } catch(err) {} - try { - clearTimeout(runtime.refreshTimeout); - } catch(err) {} - - $('table#chartGrid').html(''); - - runtime.charts = null; - runtime.chartAI = 0; - monitorSettings = null; - } - - function rebuildGrid() { - var oldData = null; - if(runtime.charts) { - oldData = {}; - $.each(runtime.charts, function(key, chartObj) { - for(var i=0; i < chartObj.nodes.length; i++) { - oldData[chartObj.nodes[i].dataPoint] = []; - for(var j=0; j < chartObj.chart.series[i].data.length; j++) - oldData[chartObj.nodes[i].dataPoint].push([chartObj.chart.series[i].data[j].x, chartObj.chart.series[i].data[j].y]); - } - }); - } - - destroyGrid(); - initGrid(); - - if(oldData) { - $.each(runtime.charts, function(key, chartObj) { - for(var j=0; j < chartObj.nodes.length; j++) { - if(oldData[chartObj.nodes[j].dataPoint]) - chartObj.chart.series[j].setData(oldData[chartObj.nodes[j].dataPoint]); - } - }); - } - } - - function chartSize() { - var wdt = $('div#logTable').innerWidth() / monitorSettings.columns - (monitorSettings.columns - 1) * chartSpacing.width; - return { - width: wdt, - height: 0.75 * wdt - } - } - - function addChart(chartObj, initialize) { - series = []; - for(var j=0; j<chartObj.nodes.length; j++) - series.push(chartObj.nodes[j]); - - settings = { - chart: { - renderTo: 'gridchart' + runtime.chartAI, - width: chartSize().width, - height: chartSize().height, - marginRight: 5, - zoomType: 'x', - events: { - selection: function(event) { - if(editMode) return false; - - var extremesObject = event.xAxis[0], - min = extremesObject.min, - max = extremesObject.max; - - $('#logAnalyseDialog input[name="dateStart"]') - .attr('value', Highcharts.dateFormat('%Y-%m-%d %H:%M:%S', new Date(min))); - $('#logAnalyseDialog input[name="dateEnd"]') - .attr('value', Highcharts.dateFormat('%Y-%m-%d %H:%M:%S', new Date(max))); - - var dlgBtns = { }; - - dlgBtns[PMA_messages['strFromSlowLog']] = function() { - var dateStart = Date.parse($('#logAnalyseDialog input[name="dateStart"]').attr('value')) || min; - var dateEnd = Date.parse($('#logAnalyseDialog input[name="dateEnd"]').attr('value')) || max; - - loadLogStatistics({ - src: 'slow', - start: dateStart, - end: dateEnd, - removeVariables: $('input#removeVariables').prop('checked'), - limitTypes: $('input#limitTypes').prop('checked') - }); - - $('#logAnalyseDialog').find('dateStart,dateEnd').datepicker('destroy'); - - $(this).dialog("close"); - }; - - dlgBtns[PMA_messages['strFromGeneralLog']] = function() { - var dateStart = Date.parse($('#logAnalyseDialog input[name="dateStart"]').attr('value')) || min; - var dateEnd = Date.parse($('#logAnalyseDialog input[name="dateEnd"]').attr('value')) || max; - - loadLogStatistics({ - src: 'general', - start: dateStart, - end: dateEnd, - removeVariables: $('input#removeVariables').prop('checked'), - limitTypes: $('input#limitTypes').prop('checked') - }); - - $('#logAnalyseDialog').find('dateStart,dateEnd').datepicker('destroy'); - - $(this).dialog("close"); - }; - - $('#logAnalyseDialog').dialog({ - width: 'auto', - height: 'auto', - buttons: dlgBtns - }); - - return false; - } - } - }, - xAxis: { - min: runtime.xmin, - max: runtime.xmax - }, - - yAxis: { - title: { - text: '' - } - }, - tooltip: { - formatter: function() { - var s = '<b>'+Highcharts.dateFormat('%H:%M:%S', this.x)+'</b>'; - - $.each(this.points, function(i, point) { - s += '<br/><span style="color:'+point.series.color+'">'+ point.series.name +':</span> '+ - ((parseInt(point.y) == point.y) ? point.y : Highcharts.numberFormat(this.y, 2)) + ' ' + (point.series.options.unit || ''); - }); - - return s; - }, - shared: true - }, - legend: { - enabled: false - }, - series: series, - buttons: gridbuttons, - title: { text: chartObj.title } - }; - - if(chartObj.settings) - $.extend(true,settings,chartObj.settings); - - if($('#'+settings.chart.renderTo).length==0) { - var numCharts = $('table#chartGrid .monitorChart').length; - - if(numCharts == 0 || !( numCharts % monitorSettings.columns)) - $('table#chartGrid').append('<tr></tr>'); - - $('table#chartGrid tr:last').append('<td><div class="ui-state-default monitorChart" id="'+settings.chart.renderTo+'"></div></td>'); - } - - chartObj.chart = PMA_createChart(settings); - chartObj.numPoints = 0; - - if(initialize != true) { - runtime.charts['c'+runtime.chartAI] = chartObj; - buildRequiredDataList(); - } - - // Edit,Print icon only in edit mode - $('table#chartGrid div svg').find('*[zIndex=20], *[zIndex=21], *[zIndex=19]').toggle(editMode) - - runtime.chartAI++; - } - - function editChart(chartObj) { - var htmlnode = chartObj.options.chart.renderTo; - if(! htmlnode ) return; - - var chart=null; - var chartKey=null; - $.each(runtime.charts, function(key, value) { - if(value.chart.options.chart.renderTo == htmlnode) { - chart = value; - chartKey = key; - return false; - } - }); - - if(chart == null) return; - - var htmlStr = '<p><b>Chart title: </b> <br/> <input type="text" size="35" name="chartTitle" value="' + chart.title + '" />'; - htmlStr += '</p><p><b>Series:</b> </p><ol>'; - for(var i=0; i<chart.nodes.length; i++) { - htmlStr += '<li><i>' + chart.nodes[i].dataPoint +': </i><br/><input type="text" name="chartSerie-' + i + '" value=" ' + chart.nodes[i].name + '" /></li>'; - } - - dlgBtns = {}; - dlgBtns['Save'] = function() { - runtime.charts[chartKey].title = $('div#emptyDialog input[name="chartTitle"]').attr('value'); - runtime.charts[chartKey].chart.setTitle({ text: runtime.charts[chartKey].title }); - - $('div#emptyDialog input[name*="chartSerie"]').each(function() { - var idx = $(this).attr('name').split('-')[1]; - runtime.charts[chartKey].nodes[idx].name = $(this).attr('value'); - runtime.charts[chartKey].chart.series[idx].name = $(this).attr('value'); - }); - - $(this).dialog('close'); - saveMonitor(); - }; - dlgBtns['Cancel'] = function() { - $(this).dialog('close'); - }; - - $('div#emptyDialog').attr('title','Edit chart'); - $('div#emptyDialog').html(htmlStr+'</ol>'); - $('div#emptyDialog').dialog({ - width: 'auto', - height: 'auto', - buttons: dlgBtns - }); - } - - function removeChart(chartObj) { - var htmlnode = chartObj.options.chart.renderTo; - if(! htmlnode ) return; - - $.each(runtime.charts, function(key, value) { - if(value.chart.options.chart.renderTo == htmlnode) { - delete runtime.charts[key]; - return false; - } - }); - - buildRequiredDataList(); - - // Using settimeout() because clicking the remove link fires an onclick event - // which throws an error when the chart is destroyed - setTimeout(function() { - chartObj.destroy(); - $('div#' + htmlnode).remove(); - },10); - - saveMonitor(); // Save settings - } - - function refreshChartGrid() { - /* Send to server */ - runtime.refreshRequest = $.post('server_status.php?'+url_query, { ajax_request: true, chart_data: 1, type: 'chartgrid', requiredData: $.toJSON(runtime.dataList) },function(data) { - var chartData; - try { - chartData = $.parseJSON(data); - } catch(err) { - return serverResponseError(); - } - var value, i=0; - var diff; - - /* Update values in each graph */ - $.each(runtime.charts, function(orderKey, elem) { - var key = elem.chartID; - // If newly added chart, we have no data for it yet - if(! chartData[key]) return; - // Draw all points - for(var j=0; j < elem.nodes.length; j++) { - value = chartData[key][j].y; - - if(i==0 && j==0) { - if(oldChartData==null) diff = chartData.x - runtime.xmax; - else diff = parseInt(chartData.x - oldChartData.x); - - runtime.xmin+= diff; - runtime.xmax+= diff; - } - - elem.chart.xAxis[0].setExtremes(runtime.xmin, runtime.xmax, false); - - if(elem.nodes[j].display == 'differential') { - if(oldChartData == null || oldChartData[key] == null) continue; - value -= oldChartData[key][j].y; - } - - if(elem.nodes[j].valueDivisor) - value = value / elem.nodes[j].valueDivisor; - - if(elem.nodes[j].transformFn) { - value = chartValueTransform( - elem.nodes[j].transformFn, - chartData[key][j], - (oldChartData == null ? null : oldChartData[key][j]) - ); - } - - if(value != undefined) - elem.chart.series[j].addPoint( - { x: chartData.x, y: value }, - false, - elem.numPoints >= runtime.gridMaxPoints - ); - } - - i++; - - runtime.charts[orderKey].numPoints++; - if(runtime.redrawCharts) - elem.chart.redraw(); - }); - - oldChartData = chartData; - - runtime.refreshTimeout = setTimeout(refreshChartGrid, monitorSettings.gridRefresh); - }); - } - - function chartValueTransform(name,cur,prev) { - switch(name) { - case 'cpu-linux': - if(prev == null) return undefined; - var diff_total = cur.busy + cur.idle - (prev.busy + prev.idle); - var diff_idle = cur.idle - prev.idle; - return 100*(diff_total - diff_idle) / diff_total; - } - return undefined; - } - - /* Build list of nodes that need to be retrieved */ - function buildRequiredDataList() { - runtime.dataList = {}; - // Store an own id, because the property name is subject of reordering, thus destroying our mapping with runtime.charts <=> runtime.dataList - var chartID = 0; - $.each(runtime.charts, function(key, chart) { - runtime.dataList[chartID] = chart.nodes; - runtime.charts[key].chartID = chartID; - chartID++; - }); - } - - function loadLogStatistics(opts) { - var tableStr = ''; - var logRequest = null; - - if(! opts.removeVariables) - opts.removeVariables = false; - if(! opts.limitTypes) - opts.limitTypes = false; - - $('#emptyDialog').html(PMA_messages['strAnalysingLogs'] + ' <img class="ajaxIcon" src="' + pmaThemeImage + 'ajax_clock_small.gif" alt="">'); - - $('#emptyDialog').dialog({ - width: 'auto', - height: 'auto', - buttons: { - 'Cancel request': function() { - if(logRequest != null) - logRequest.abort(); - - $(this).dialog("close"); - } - } - }); - - - logRequest = $.get('server_status.php?'+url_query, - { ajax_request: true, - log_data: 1, - type: opts.src, - time_start: Math.round(opts.start / 1000), - time_end: Math.round(opts.end / 1000), - removeVariables: opts.removeVariables, - limitTypes: opts.limitTypes - }, - function(data) { - var logData; - try { - logData = $.parseJSON(data); - } catch(err) { - return serverResponseError(); - } - - if(logData.rows.length != 0) { - runtime.logDataCols = buildLogTable(logData); - - /* Show some stats in the dialog */ - $('#emptyDialog').attr('title', PMA_messages['strLoadingLogs']); - $('#emptyDialog').html('<p>' + PMA_messages['strLogDataLoaded'] + '</p>'); - $.each(logData.sum, function(key, value) { - key = key.charAt(0).toUpperCase() + key.slice(1).toLowerCase(); - if(key == 'Total') key = '<b>' + key + '</b>'; - $('#emptyDialog').append(key + ': ' + value + '<br/>'); - }); - - /* Add filter options if more than a bunch of rows there to filter */ - if(logData.numRows > 12) { - $('div#logTable').prepend( - '<fieldset id="logDataFilter">' + - ' <legend>' + PMA_messages['strFilters'] + '</legend>' + - ' <div class="formelement">' + - ' <label for="filterQueryText">' + PMA_messages['strFilterByWordRegexp'] + '</label>' + - ' <input name="filterQueryText" type="text" id="filterQueryText" style="vertical-align: baseline;" />' + - ' </div>' + - ((logData.numRows > 250) ? ' <div class="formelement"><button name="startFilterQueryText" id="startFilterQueryText">' + PMA_messages['strFilter'] + '</button></div>' : '') + - ' <div class="formelement">' + - ' <input type="checkbox" id="noWHEREData" name="noWHEREData" value="1" /> ' + - ' <label for="noWHEREData"> ' + PMA_messages['strIgnoreWhereAndGroup'] + '</label>' + - ' </div' + - '</fieldset>' - ); - - $('div#logTable input#noWHEREData').change(function() { - filterQueries(true); - }); - - //preg_replace('/\s+([^=]+)=(\d+|(('|"|)(?U)(.+)(?<!\)\4(\s+|$)))/i',' $1={} ',$str); - - if(logData.numRows > 250) { - $('div#logTable button#startFilterQueryText').click(filterQueries); - } else { - $('div#logTable input#filterQueryText').keyup(filterQueries); - } - - } - - var dlgBtns = {}; - dlgBtns[PMA_messages['strJumpToTable']] = function() { - $(this).dialog("close"); - $(document).scrollTop($('div#logTable').offset().top); - }; - - $('#emptyDialog').dialog( "option", "buttons", dlgBtns); - - } else { - $('#emptyDialog').html('<p>' + PMA_messages['strNoDataFound'] + '</p>'); - - var dlgBtns = {}; - dlgBtns[PMA_messages['strClose']] = function() { - $(this).dialog("close"); - }; - - $('#emptyDialog').dialog( "option", "buttons", dlgBtns ); - } - } - ); - - function filterQueries(varFilterChange) { - var odd_row=false, cell, textFilter; - var val = $('div#logTable input#filterQueryText').val(); - - if(val.length == 0) textFilter = null; - else textFilter = new RegExp(val, 'i'); - - var rowSum = 0, totalSum = 0, i=0, q; - var noVars = $('div#logTable input#noWHEREData').attr('checked'); - var equalsFilter = /([^=]+)=(\d+|(('|"|).*?[^\])\4((\s+)|$))/gi; - var functionFilter = /([a-z0-9_]+)(.+?)/gi; - var filteredQueries = {}; - var filteredQueriesLines = {}; - var hide = false, rowData; - var queryColumnName = runtime.logDataCols[runtime.logDataCols.length - 2]; - var sumColumnName = runtime.logDataCols[runtime.logDataCols.length - 1]; - - var isSlowLog = opts.src == 'slow'; - var columnSums = {}; - - var countRow = function(query, row) { - var cells = row.match(/<td>(.*?)</td>/gi); - if(!columnSums[query]) columnSums[query] = [0,0,0,0]; - - columnSums[query][0] += timeToSec(cells[2].replace(/(<td>|</td>)/gi,'')); - columnSums[query][1] += timeToSec(cells[3].replace(/(<td>|</td>)/gi,'')); - columnSums[query][2] += parseInt(cells[4].replace(/(<td>|</td>)/gi,'')); - columnSums[query][3] += parseInt(cells[5].replace(/(<td>|</td>)/gi,'')); - }; - - // We just assume the sql text is always in the second last column, and that the total count is right of it - $('div#logTable table tbody tr td:nth-child(' + (runtime.logDataCols.length - 1) + ')').each(function() { - if(varFilterChange && $(this).html().match(/^SELECT/i)) { - if(noVars) { - q = $(this).text().replace(equalsFilter, '$1=...$6').trim(); - q = q.replace(functionFilter, ' $1(...)'); - - // Js does not specify a limit on property name length, so we can abuse it as index :-) - if(filteredQueries[q]) { - filteredQueries[q] += parseInt($(this).next().text()); - totalSum += parseInt($(this).next().text()); - hide = true; - } else { - filteredQueries[q] = parseInt($(this).next().text());; - filteredQueriesLines[q] = i; - $(this).text(q); - } - if(isSlowLog) countRow(q, $(this).parent().html()); - - // Restore original columns - } else { - rowData = $(this).parent().data('query'); - - // SQL Text - $(this).text(rowData[queryColumnName]); - // # - $(this).next().text(rowData[sumColumnName]); - // Slow log columns - if(isSlowLog) { - $(this).parent().children('td:nth-child(3)').text(rowData['query_time']); - $(this).parent().children('td:nth-child(4)').text(rowData['lock_time']); - $(this).parent().children('td:nth-child(5)').text(rowData['rows_sent']); - $(this).parent().children('td:nth-child(6)').text(rowData['rows_examined']); - } - } - } - - if(! hide && (textFilter != null && ! textFilter.exec($(this).text()))) hide = true; - - if(hide) { - $(this).parent().css('display','none'); - } else { - totalSum += parseInt($(this).next().text()); - rowSum ++; - - 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'); - } - } - - hide = false; - i++; - }); - - // Update count values of grouped entries - if(varFilterChange) { - if(noVars) { - var numCol, row, $table = $('div#logTable table tbody'); - $.each(filteredQueriesLines, function(key,value) { - if(filteredQueries[key] <= 1) return; - - row = $table.children('tr:nth-child(' + (value+1) + ')'); - numCol = row.children(':nth-child(' + (runtime.logDataCols.length) + ')'); - numCol.text(filteredQueries[key]); - - if(isSlowLog) { - row.children('td:nth-child(3)').text(secToTime(columnSums[key][0])); - row.children('td:nth-child(4)').text(secToTime(columnSums[key][1])); - row.children('td:nth-child(5)').text(columnSums[key][2]); - row.children('td:nth-child(6)').text(columnSums[key][3]); - } - }); - } - - $('div#logTable table').trigger("update"); - setTimeout(function() { - $('div#logTable table').trigger('sorton',[[[runtime.logDataCols.length - 1,1]]]); - }, 0); - } - - $('div#logTable table tfoot tr') - .html('<th colspan="' + (runtime.logDataCols.length - 1) + '">' + - PMA_messages['strSumRows'] + ' '+ rowSum +'<span style="float:right">' + - PMA_messages['strTotal'] + '</span></th><th align="right">' + totalSum + '</th>'); - } - } - - /*loadLogStatistics({ - src: 'general', - start:1311076210*1000, - end:1311162689*1000, - removeVariables: true, - limitTypes: true - });*/ - - function timeToSec(timeStr) { - var time = timeStr.split(':'); - return parseInt(time[0]*3600) + parseInt(time[1]*60) + parseInt(time[2]); - } - - function secToTime(timeInt) { - hours = Math.floor(timeInt / 3600); - timeInt -= hours*3600; - minutes = Math.floor(timeInt / 60); - timeInt -= minutes*60; - - if(hours < 10) hours = '0' + hours; - if(minutes < 10) minutes = '0' + minutes; - if(timeInt < 10) timeInt = '0' + timeInt; - - return hours + ':' + minutes + ':' + timeInt; - } - - function buildLogTable(data) { - var rows = data.rows; - var cols = new Array(); - var $table = $('<table border="0" class="sortable"></table>'); - var $tBody, $tRow, $tCell; - - $('#logTable').html($table); - - var formatValue = function(name, value) { - switch(name) { - case 'user_host': - return value.replace(/([.*?])+/g,''); - } - return value; - }; - - for(var i=0; i < rows.length; i++) { - if(i == 0) { - $.each(rows[0],function(key, value) { - cols.push(key); - }); - $table.append( '<thead>' + - '<tr><th class="nowrap">' + cols.join('</th><th class="nowrap">') + '</th></tr>' + - '</thead>'); - - $table.append($tBody = $('<tbody></tbody>')); - } - - $tBody.append($tRow = $('<tr class="noclick"></tr>')); - var cl='' - for(var j=0; j < cols.length; j++) { - // Assuming the query column is the second last - if(j == cols.length - 2 && rows[i][cols[j]].match(/^SELECT/i)) { - $tRow.append($tCell=$('<td class="linkElem">' + formatValue(cols[j], rows[i][cols[j]]) + '</td>')); - $tCell.click(queryAnalyzer); - } else - $tRow.append('<td>' + formatValue(cols[j], rows[i][cols[j]]) + '</td>'); - - - $tRow.data('query',rows[i]); - } - } - - $table.append('<tfoot>' + - '<tr><th colspan="' + (cols.length - 1) + '">' + PMA_messages['strSumRows'] + - ' '+ data.numRows +'<span style="float:right">' + PMA_messages['strTotal'] + - '</span></th><th align="right">' + data.sum.TOTAL + '</th></tr></tfoot>'); - - - function queryAnalyzer() { - var query = $(this).parent().data('query').argument || $(this).parent().data('query').sql_text; - var db = $(this).parent().data('query').db || ''; - - /* A very basic SQL Formatter. Totally fails in the cases of - - Any string appearance containing a MySQL Keyword, surrounded by whitespaces, e.g. WHERE bar = "This where the formatter fails" - - Subqueries too probably - */ - - // Matches the columns to be selected - // .* selector doesn't include whitespace and we have no PCRE_DOTALL modifier, (.|\s)+ crashes Chrome (reported and confirmed), - // [^]+ results in JS error in IE8, thus we use [^\0]+ for matching each column since the zero-byte char (hopefully) doesn't appear in column names ;) - var sLists = query.match(/SELECT\s+[^\0]+\s+FROM\s+/gi); - if(sLists) { - for(var i=0; i < sLists.length; i++) { - query = query.replace(sLists[i],sLists[i].replace(/\s*((`|'|"|).*?\1,)\s*/gi,'$1\n\t')); - } - query = query - .replace(/(\s+|^)(SELECT|FROM|WHERE|GROUP BY|HAVING|ORDER BY|LIMIT)(\s+|$)/gi,'\n$2\n\t') - .replace(/\s+UNION\s+/gi,'\n\nUNION\n\n') - .replace(/\s+(AND)\s+/gi,' $1\n\t') - .trim(); - } - - codemirror_editor.setValue(query); - - var profilingChart = null; - - $('div#queryAnalyzerDialog').dialog({ - width: 'auto', - height: 'auto', - resizable: false, - buttons: { - 'Analyse Query' : function() { - $('div#queryAnalyzerDialog div.placeHolder').html('Analyzing... ' + '<img class="ajaxIcon" src="' + pmaThemeImage + 'ajax_clock_small.gif" alt="">'); - - $.post('server_status.php?'+url_query, { - ajax_request: true, - query_analyzer: true, - query: codemirror_editor.getValue(), - database: db - }, function(data) { - data = $.parseJSON(data); - var totalTime = 0; - - if(data.error) { - $('div#queryAnalyzerDialog div.placeHolder').html('<div class="error">' + data.error + '</div>'); - return; - } - - // Float sux, I'll use table :( - $('div#queryAnalyzerDialog div.placeHolder') - .html('<table width="100%" border="0"><tr><td class="explain"></td><td class="chart"></td></tr></table>'); - - var explain = '<b>Explain output</b> '+explain_docu; - if(data.explain.length > 1) { - explain += ' ('; - for(var i=0; i < data.explain.length; i++) { - if(i > 0) explain += ', '; - explain += '<a href="#showExplain-' + i + '">' + i + '</a>'; - } - explain += ')'; - } - explain +='<p></p>'; - for(var i=0; i < data.explain.length; i++) { - explain += '<div class="explain-' + i + '"' + (i>0? 'style="display:none;"' : '' ) + '>'; - $.each(data.explain[i], function(key,value) { - value = (value==null)?'null':value; - - if(key == 'type' && value.toLowerCase() == 'all') value = '<span class="attention">' + value +'</span>'; - if(key == 'Extra') value = value.replace(/(using (temporary|filesort))/gi,'<span class="attention">$1</span>'); - explain += key+': ' + value + '<br />'; - }); - explain += '</div>'; - } - - // Since there is such a nice free space below the explain, lets put it here for now - explain += '<p><b>' + PMA_messages['strAffectedRows'] + '</b> ' + data.affectedRows; - - $('div#queryAnalyzerDialog div.placeHolder td.explain').append(explain); - - $('div#queryAnalyzerDialog div.placeHolder a[href*="#showExplain"]').click(function() { - var id = $(this).attr('href').split('-')[1]; - $(this).parent().find('div[class*="explain"]').hide(); - $(this).parent().find('div[class*="explain-' + id + '"]').show(); - }); - - if(data.profiling) { - var chartData = []; - var numberTable = '<table class="queryNums"><thead><tr><th>Status</th><th>Time</th></tr></thead><tbody>'; - var duration; - - for(var i=0; i < data.profiling.length; i++) { - duration = parseFloat(data.profiling[i].duration); - - chartData.push([data.profiling[i].state, duration]); - totalTime+=duration; - - numberTable += '<tr><td>' + data.profiling[i].state + ' </td><td> ' + PMA_prettyProfilingNum(duration,2) + '</td></tr>'; - } - numberTable += '<tr><td><b>Total time:</b></td><td>' + PMA_prettyProfilingNum(totalTime,2) + '</td></tr>'; - numberTable += '</tbody></table>'; - - $('div#queryAnalyzerDialog div.placeHolder td.chart').append('<b>Profiling results ' + profiling_docu + '</b> (<a href="#showNums">Table</a>, <a href="#showChart">Chart</a>)<br/>' + numberTable + ' <div id="queryProfiling"></div>'); - - $('div#queryAnalyzerDialog div.placeHolder a[href="#showNums"]').click(function() { - $('div#queryAnalyzerDialog div#queryProfiling').hide(); - $('div#queryAnalyzerDialog table.queryNums').show(); - return false; - }); - - $('div#queryAnalyzerDialog div.placeHolder a[href="#showChart"]').click(function() { - $('div#queryAnalyzerDialog div#queryProfiling').show(); - $('div#queryAnalyzerDialog table.queryNums').hide(); - return false; - }); - - profilingChart = PMA_createProfilingChart(chartData, { - chart: { - renderTo: 'queryProfiling' - }, - plotOptions: { - pie: { - size: '50%' - } - } - }); - - - $('div#queryProfiling').resizable(); - } - - }); - }, - 'Close' : function() { - if(profilingChart != null) { - profilingChart.destroy(); - } - $('div#queryAnalyzerDialog div.placeHolder').html(''); - codemirror_editor.setValue(''); - - $(this).dialog("close"); - } - } - }); - } - - // Append a tooltip to the count column, if there exist one - if($('#logTable th:last').html() == '#') { - $('#logTable th:last').append(' <img class="qroupedQueryInfoIcon icon ic_b_docs" src="themes/dot.gif" alt="" />'); - - var qtipContent = PMA_messages['strCountColumnExplanation']; - if(groupInserts) qtipContent += '<p>' + PMA_messages['strMoreCountColumnExplanation'] + '</p>'; - - $('img.qroupedQueryInfoIcon').qtip({ - content: qtipContent, - position: { - corner: { - target: 'bottomMiddle', - tooltip: 'topRight' - } - - }, - hide: { delay: 1000 } - }) - } - - $('div#logTable table').tablesorter({ - sortList: [[cols.length - 1,1]], - widgets: ['zebra'] - }); - - $('div#logTable table thead th') - .append('<img class="icon sortableIcon" src="themes/dot.gif" alt="">'); - - return cols; - } - - function saveMonitor() { - var gridCopy = {}; - - $.each(runtime.charts, function(key, elem) { - gridCopy[key] = {}; - gridCopy[key].nodes = elem.nodes; - gridCopy[key].settings = elem.settings; - gridCopy[key].title = elem.title; - }); - - if(window.localStorage) { - window.localStorage['monitorCharts'] = $.toJSON(gridCopy); - window.localStorage['monitorSettings'] = $.toJSON(monitorSettings); - } - - $('a[href="#clearMonitorConfig"]').show(); - } - function serverResponseError() { var btns = {}; btns[PMA_messages['strReloadPage']] = function() { window.location.reload(); }; - $('#emptyDialog').attr('title',PMA_messages['strRefreshFailed']); - $('#emptyDialog').html('<img class="icon ic_s_attention" src="themes/dot.gif" alt=""> ' + PMA_messages['strInvalidResponseExplanation']) + $('#emptyDialog').attr('title', PMA_messages['strRefreshFailed']); + $('#emptyDialog').html( + '<img class="icon ic_s_attention" src="themes/dot.gif" alt=""> ' + + PMA_messages['strInvalidResponseExplanation'] + ); $('#emptyDialog').dialog({ buttons: btns }); } - }); diff --git a/js/server_status.js b/js/server_status_monitor.js similarity index 52% copy from js/server_status.js copy to js/server_status_monitor.js index 5abb5df..cb01ca7 100644 --- a/js/server_status.js +++ b/js/server_status_monitor.js @@ -1,609 +1,15 @@ -/* 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" - }); - - - // Popup behaviour - $('a[rel="popupLink"]').click( function() { - var $link = $(this); - - $('.' + $link.attr('href').substr(1)) - .show() - .offset({ top: $link.offset().top + $link.height() + 5, left: $link.offset().left }) - .addClass('openedPopup'); - - return false; - }); - - $(document).click( function(event) { - $('.openedPopup').each(function() { - var $cnt = $(this); - var pos = $(this).offset(); - - // Hide if the mouseclick is outside the popupcontent - if(event.pageX < pos.left || event.pageY < pos.top || event.pageX > pos.left + $cnt.outerWidth() || event.pageY > pos.top + $cnt.outerHeight()) - $cnt.hide().removeClass('openedPopup'); - }); - }); -}); - -$(function() { - // Filters for status variables - var textFilter=null; - var alertFilter = false; - var categoryFilter=''; - var odd_row=false; - var text=''; // Holds filter text - var queryPieChart = null; - - /* 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(); - - - /*** Table sort tooltip ***/ - - var $tableSortHint = $('<div class="dHint" style="display:none;">' + 'Click to sort' + '</div>'); - $('body').append($tableSortHint); - - $('table.sortable thead th').live('mouseover mouseout',function(e) { - if(e.type == 'mouseover') { - $tableSortHint - .stop(true, true) - .css({ - top: e.clientY + 15, - left: e.clientX + 15 - }) - .show('fast') - .data('shown',true); - } else { - $tableSortHint - .stop(true, true) - .hide(300,function() { - $(this).data('shown',false); - }); - } - }); - - $(document).mousemove(function(e) { - if($tableSortHint.data('shown') == true) - $tableSortHint.css({ - top: e.clientY + 15, - left: e.clientX + 15 - }) - }); - - - // Tell highcarts not to use UTC dates (global setting) - Highcharts.setOptions({ - global: { - useUTC: false - } - }); - - $.ajaxSetup({ - cache:false - }); - - // 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"); - - // Initialize each tab - $('div.ui-tabs-panel').each(function() { - initTab($(this),null); - tabStatus[$(this).attr('id')] = 'static'; - }); - - // Display button links - $('div.buttonlinks').show(); - - // Handles refresh rate changing - $('.buttonlinks select').change(function() { - var chart=tabChart[$(this).parents('div.ui-tabs-panel').attr('id')]; - - // Clear current timeout and set timeout with the new refresh rate - clearTimeout(chart_activeTimeouts[chart.options.chart.renderTo]); - if(chart.options.realtime.postRequest) - chart.options.realtime.postRequest.abort(); - - chart.options.realtime.refreshRate = 1000*parseInt(this.value); - - chart.xAxis[0].setExtremes( - new Date().getTime() - server_time_diff - chart.options.realtime.numMaxPoints * chart.options.realtime.refreshRate, - new Date().getTime() - server_time_diff, - true - ); - - chart_activeTimeouts[chart.options.chart.renderTo] = setTimeout( - chart.options.realtime.timeoutCallBack, - chart.options.realtime.refreshRate - ); - }); - - // Ajax refresh of variables (always the first element in each tab) - $('.buttonlinks a.tabRefresh').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 **/ - - // Live traffic charting - $('.buttonlinks a.livetrafficLink').click(function() { - // ui-tabs-panel class is added by the jquery tabs feature - var $tab=$(this).parents('div.ui-tabs-panel'); - var tabstat = tabStatus[$tab.attr('id')]; - - if(tabstat=='static' || tabstat=='liveconnections') { - var settings = { - series: [ - { name: PMA_messages['strChartKBSent'], data: [] }, - { name: PMA_messages['strChartKBReceived'], data: [] } - ], - title: { text: PMA_messages['strChartServerTraffic'] }, - realtime: { url:'server_status.php?' + url_query, - type: 'traffic', - callback: function(chartObj, curVal, lastVal, numLoadedPoints) { - if(lastVal==null) return; - chartObj.series[0].addPoint( - { x: curVal.x, y: (curVal.y_sent - lastVal.y_sent) / 1024 }, - false, - numLoadedPoints >= chartObj.options.realtime.numMaxPoints - ); - chartObj.series[1].addPoint( - { x: curVal.x, y: (curVal.y_received - lastVal.y_received) / 1024 }, - true, - numLoadedPoints >= chartObj.options.realtime.numMaxPoints - ); - }, - error: function() { serverResponseError(); } - } - } - - setupLiveChart($tab,this,settings); - if(tabstat == 'liveconnections') - $tab.find('.buttonlinks a.liveconnectionsLink').html(PMA_messages['strLiveConnChart']); - tabStatus[$tab.attr('id')]='livetraffic'; - } else { - $(this).html(PMA_messages['strLiveTrafficChart']); - setupLiveChart($tab,this,null); - } - - return false; - }); - - // Live connection/process charting - $('.buttonlinks a.liveconnectionsLink').click(function() { - var $tab=$(this).parents('div.ui-tabs-panel'); - var tabstat = tabStatus[$tab.attr('id')]; - - if(tabstat == 'static' || tabstat == 'livetraffic') { - var settings = { - series: [ - { name: PMA_messages['strChartConnections'], data: [] }, - { name: PMA_messages['strChartProcesses'], data: [] } - ], - title: { text: PMA_messages['strChartConnectionsTitle'] }, - 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 - ); - }, - error: function() { serverResponseError(); } - } - }; - - setupLiveChart($tab,this,settings); - if(tabstat == 'livetraffic') - $tab.find('.buttonlinks a.livetrafficLink').html(PMA_messages['strLiveTrafficChart']); - tabStatus[$tab.attr('id')]='liveconnections'; - } else { - $(this).html(PMA_messages['strLiveConnChart']); - setupLiveChart($tab,this,null); - } - - return false; - }); - - // Live query statistics - $('.buttonlinks a.livequeriesLink').click(function() { - var $tab = $(this).parents('div.ui-tabs-panel'); - var settings = null; - - if(tabStatus[$tab.attr('id')] == 'static') { - settings = { - series: [ { name: PMA_messages['strChartIssuedQueries'], data: [] } ], - title: { text: PMA_messages['strChartIssuedQueriesTitle'] }, - 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 - ); - }, - error: function() { serverResponseError(); } - } - }; - } else { - $(this).html(PMA_messages['strLiveQueryChart']); - } - - setupLiveChart($tab,this,settings); - tabStatus[$tab.attr('id')] = 'livequeries'; - return false; - }); - - function setupLiveChart($tab,link,settings) { - if(settings != null) { - // Loading a chart with existing chart => remove old chart first - if(tabStatus[$tab.attr('id')] != 'static') { - clearTimeout(chart_activeTimeouts[$tab.attr('id') + "_chart_cnt"]); - chart_activeTimeouts[$tab.attr('id')+"_chart_cnt"] = null; - tabChart[$tab.attr('id')].destroy(); - // Also reset the select list - $tab.find('.buttonlinks select').get(0).selectedIndex = 2; - } - - if(! settings.chart) settings.chart = {}; - settings.chart.renderTo = $tab.attr('id') + "_chart_cnt"; - - $tab.find('.tabInnerContent') - .hide() - .after('<div class="liveChart" id="' + $tab.attr('id') + '_chart_cnt"></div>'); - tabChart[$tab.attr('id')] = PMA_createChart(settings); - $(link).html(PMA_messages['strStaticData']); - $tab.find('.buttonlinks a.tabRefresh').hide(); - $tab.find('.buttonlinks .refreshList').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')]='static'; - tabChart[$tab.attr('id')].destroy(); - $tab.find('.buttonlinks a.tabRefresh').show(); - $tab.find('.buttonlinks select').get(0).selectedIndex=2; - $tab.find('.buttonlinks .refreshList').hide(); + // Show tab links + $('div#statustabs_charting div.tabLinks').show(); + $('div#statustabs_charting img#loadingMonitorIcon').remove(); + // Codemirror is loaded on demand so we might need to initialize it + if (! codemirror_editor) { + var elm = $('#sqlquery'); + if (elm.length > 0 && typeof CodeMirror != 'undefined') { + codemirror_editor = CodeMirror.fromTextArea(elm[0], { lineNumbers: true, matchBrackets: true, indentUnit: 4, mode: "text/x-mysql" }); } } - - /* 3 Filtering functions */ - $('#filterAlert').change(function() { - alertFilter = this.checked; - filterVariables(); - }); - - $('#filterText').keyup(function(e) { - word = $(this).val().replace(/_/g,' '); - - if(word.length == 0) textFilter = null; - else textFilter = new RegExp("(^|_)" + word,'i'); - - text = word; - - filterVariables(); - }); - - $('#filterCategory').change(function() { - categoryFilter = $(this).val(); - filterVariables(); - }); - - $('input#dontFormat').change(function() { - $('#serverstatusvariables td.value span.original').toggle(this.checked); - $('#serverstatusvariables td.value span.formatted').toggle(! this.checked); - }); - - /* Adjust DOM / Add handlers to the tabs */ - function initTab(tab,data) { - switch(tab.attr('id')) { - case 'statustabs_traffic': - if(data != null) tab.find('.tabInnerContent').html(data); - PMA_convertFootnotesToTooltips(); - break; - case 'statustabs_queries': - if(data != null) { - queryPieChart.destroy(); - tab.find('.tabInnerContent').html(data); - } - - // Build query statistics chart - var cdata = new Array(); - $.each(jQuery.parseJSON($('#serverstatusquerieschart span').html()),function(key,value) { - cdata.push([key,parseInt(value)]); - }); - - queryPieChart = PMA_createChart({ - chart: { - renderTo: 'serverstatusquerieschart' - }, - title: { - text:'', - margin:0 - }, - series: [{ - type:'pie', - name: PMA_messages['strChartQueryPie'], - data: cdata - }], - plotOptions: { - pie: { - allowPointSelect: true, - cursor: 'pointer', - dataLabels: { - enabled: true, - formatter: function() { - return '<b>'+ this.point.name +'</b><br/> ' + Highcharts.numberFormat(this.percentage, 2) + ' %'; - } - } - } - }, - tooltip: { - formatter: function() { - return '<b>' + this.point.name + '</b><br/>' + Highcharts.numberFormat(this.y, 2) + '<br/>(' + Highcharts.numberFormat(this.percentage, 2) + ' %)'; - } - } - }); - break; - - case 'statustabs_allvars': - if(data != null) { - 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('<img class="icon sortableIcon" src="themes/dot.gif" alt="">'); - - break; - - case 'statustabs_allvars': - $('#serverstatusvariables').tablesorter({ - sortList: [[0,0]], - widgets: ['zebra'], - headers: { - 1: { sorter: 'fancyNumber' } - } - }); - - $('#serverstatusvariables tr:first th') - .append('<img class="icon sortableIcon" src="themes/dot.gif" alt="">'); - - 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 = '<b>' + PMA_messages['strTotal'] + ': ' + sumTotal + '</b><br>'; - - while(queryKeys.length > 0) { - max = 0; - for(var i=0; i < queryKeys.length; i++) { - if(queryValues[i] > max) { - max = queryValues[i]; - maxIdx = i; - } - } - if(numQueries > 8 && num >= 6) - sumOther += queryValues[maxIdx]; - else pointInfo += queryKeys[maxIdx].substr(4).replace('_',' ') + ': ' + queryValues[maxIdx] + '<br>'; - - queryKeys.splice(maxIdx,1); - queryValues.splice(maxIdx,1); - num++; - } - - if(sumOther>0) - pointInfo += PMA_messages['strOther'] + ': ' + sumOther; - - return pointInfo; - } - - /**** Server config advisor ****/ - - $('a[href="#openAdvisorInstructions"]').click(function() { - $('#advisorInstructionsDialog').dialog(); - }); - - $('a[href="#startAnalyzer"]').click(function() { - var $cnt = $('#statustabs_advisor .tabInnerContent'); - $cnt.html('<img class="ajaxIcon" src="' + pmaThemeImage + 'ajax_clock_small.gif" alt="">'); - - $.get('server_status.php?'+url_query, { ajax_request: true, advisor: true },function(data) { - var $tbody, $tr, str, even = true; - - data = $.parseJSON(data); - $cnt.html('<p><b>Possible performance issues</b></p>'); - if(data.fired.length > 0) { - $cnt.append('<table class="data" id="rulesFired" border="0"><thead><tr><th>Issue</th><th>Recommendation</th></tr></thead><tbody></tbody></table>'); - $tbody = $cnt.find('table#rulesFired'); - $.each(data.fired, function(key,value) { - $tbody.append($tr = $('<tr class="linkElem noclick ' + (even ? 'even' : 'odd') + '"><td>' + value.issue + '</td>' + - '<td>' + value.recommendation + ' </td></tr>')); - even = !even; - - $tr.data('rule',value); - $tr.click(function() { - var rule = $(this).data('rule'); - $('div#emptyDialog').attr('title','Rule details'); - $('div#emptyDialog').html( - '<p><b>Issue:</b><br />' + rule.issue + '</p>' + - '<p><b>Recommendation:</b><br />' + rule.recommendation + '</p>' + - '<p><b>Justification:</b><br />' + rule.justification + '</p>' + - '<p><b>Used variable / formula:</b><br />' + rule.formula + '</p>' + - '<p><b>Test:</b><br />' + rule.test + '</p>' - ); - $('div#emptyDialog').dialog({ - width: 600, - buttons: { - 'Close' : function() { - $(this).dialog('close'); - } - } - }); - }); - }); - } - }); - - return false; - }); - - + /**** Monitor charting implementation ****/ /* Saves the previous ajax response for differential values */ var oldChartData = null; @@ -631,7 +37,7 @@ $(function() { xmin: -1, xmax: -1 }; - + var monitorSettings = null;
var defaultMonitorSettings = { @@ -681,7 +87,7 @@ $(function() { { dataType: 'memory', name: PMA_messages['strUsedMemory'], dataPoint: 'MemUsed', valueDivisor: 1024, unit: PMA_messages['strMiB'] }, { dataType: 'memory', name: PMA_messages['strCachedMemory'], dataPoint: 'Cached', valueDivisor: 1024, unit: PMA_messages['strMiB'] }, { dataType: 'memory', name: PMA_messages['strBufferedMemory'], dataPoint: 'Buffers', valueDivisor: 1024, unit: PMA_messages['strMiB'] }, - { dataType: 'memory', name: PMA_messages['strFreeMemory'], dataPoint:'MemFree', valueDivisor: 1024, unit: PMA_messages['strMiB'] } + { dataType: 'memory', name: PMA_messages['strFreeMemory'], dataPoint: 'MemFree', valueDivisor: 1024, unit: PMA_messages['strMiB'] } ], settings: { chart: { @@ -736,7 +142,7 @@ $(function() { };
// Server is localhost => We can add cpu/memory/swap - if(server_db_isLocal) { + if (server_db_isLocal) { defaultChartGrid['c3'] = presetCharts['cpu-' + server_os]; defaultChartGrid['c4'] = presetCharts['memory-' + server_os]; defaultChartGrid['c5'] = presetCharts['swap-' + server_os]; @@ -775,14 +181,16 @@ $(function() {
$('a[href="#rearrangeCharts"], a[href="#endChartEditMode"]').click(function() { editMode = !editMode; - if($(this).attr('href') == '#endChartEditMode') editMode = false; + if ($(this).attr('href') == '#endChartEditMode') { + editMode = false; + }
- // Icon graphics have zIndex 19,20 and 21. Let's just hope nothing else has the same zIndex + // Icon graphics have zIndex 19, 20 and 21. Let's just hope nothing else has the same zIndex $('table#chartGrid div svg').find('*[zIndex=20], *[zIndex=21], *[zIndex=19]').toggle(editMode)
$('a[href="#endChartEditMode"]').toggle(editMode);
- if(editMode) { + if (editMode) { // Close the settings popup $('#statustabs_charting .popupContent').hide().removeClass('openedPopup');
@@ -800,20 +208,23 @@ $(function() { var dragKey, dropKey, dropRender; var dragRender = $(drag).children().first().attr('id');
- if($(drop).children().length > 0) + if ($(drop).children().length > 0) { dropRender = $(drop).children().first().attr('id'); + }
// Find the charts in the array $.each(runtime.charts, function(key, value) { - if(value.chart.options.chart.renderTo == dragRender) + if (value.chart.options.chart.renderTo == dragRender) { dragKey = key; - if(dropRender && value.chart.options.chart.renderTo == dropRender) + } + if (dropRender && value.chart.options.chart.renderTo == dropRender) { dropKey = key; + } });
// Case 1: drag and drop are charts -> Switch keys - if(dropKey) { - if(dragKey) { + if (dropKey) { + if (dragKey) { dragChart = runtime.charts[dragKey]; runtime.charts[dragKey] = runtime.charts[dropKey]; runtime.charts[dropKey] = dragChart; @@ -827,15 +238,16 @@ $(function() { var c = 0;
$.each(runtime.charts, function(key, value) { - if(key != dropKey) + if (key != dropKey) { keys.push(key); + } });
keys.sort();
// Rebuilds all ids, with the dragged chart correctly inserted - for(var i=0; i<keys.length; i++) { - if(keys[i] == insertBefore) { + for (var i = 0; i<keys.length; i++) { + if (keys[i] == insertBefore) { newChartList['c' + (c++)] = runtime.charts[dropKey]; insertBefore = -1; // Insert ok } @@ -843,8 +255,9 @@ $(function() { }
// Not inserted => put at the end - if(insertBefore != -1) + if (insertBefore != -1) { newChartList['c' + (c++)] = runtime.charts[dropKey]; + }
runtime.charts = newChartList; } @@ -870,31 +283,34 @@ $(function() { var newSize = chartSize();
// Empty cells should keep their size so you can drop onto them - $('table#chartGrid tr td').css('width',newSize.width + 'px'); + $('table#chartGrid tr td').css('width', newSize.width + 'px');
/* Reorder all charts that it fills all column cells */ var numColumns; var $tr = $('table#chartGrid tr:first'); - var row=0; + var row = 0; while($tr.length != 0) { numColumns = 1; // To many cells in one row => put into next row $tr.find('td').each(function() { - if(numColumns > monitorSettings.columns) { - if($tr.next().length == 0) $tr.after('<tr></tr>'); + if (numColumns > monitorSettings.columns) { + if ($tr.next().length == 0) { + $tr.after('<tr></tr>'); + } $tr.next().prepend($(this)); } numColumns++; });
// To little cells in one row => for each cell to little, move all cells backwards by 1 - if($tr.next().length > 0) { + if ($tr.next().length > 0) { var cnt = monitorSettings.columns - $tr.find('td').length; - for(var i=0; i < cnt; i++) { + for (var i = 0; i < cnt; i++) { $tr.append($tr.next().find('td:first')); $tr.nextAll().each(function() { - if($(this).next().length != 0) + if ($(this).next().length != 0) { $(this).append($(this).next().find('td:first')); + } }); } } @@ -912,14 +328,16 @@ $(function() { ); });
- if(monitorSettings.gridMaxPoints == 'auto') + if (monitorSettings.gridMaxPoints == 'auto') { runtime.gridMaxPoints = Math.round((newSize.width - 40) / 12); + }
runtime.xmin = new Date().getTime() - server_time_diff - runtime.gridMaxPoints * monitorSettings.gridRefresh; runtime.xmax = new Date().getTime() - server_time_diff + monitorSettings.gridRefresh;
- if(editMode) + if (editMode) { $("#chartGrid").sortableTable('refresh'); + }
saveMonitor(); // Save settings }); @@ -928,8 +346,9 @@ $(function() { monitorSettings.gridRefresh = parseInt(this.value) * 1000; clearTimeout(runtime.refreshTimeout);
- if(runtime.refreshRequest) + if (runtime.refreshRequest) { runtime.refreshRequest.abort(); + }
runtime.xmin = new Date().getTime() - server_time_diff - runtime.gridMaxPoints * monitorSettings.gridRefresh; runtime.xmax = new Date().getTime() - server_time_diff + monitorSettings.gridRefresh; @@ -949,10 +368,10 @@ $(function() { dlgButtons[PMA_messages['strAddChart']] = function() { var type = $('input[name="chartType"]:checked').val();
- if(type == 'cpu' || type == 'memory' || type=='swap') + if (type == 'cpu' || type == 'memory' || type == 'swap') { newChart = presetCharts[type + '-' + server_os]; - else { - if(! newChart || ! newChart.nodes || newChart.nodes.length == 0) { + } else { + if (! newChart || ! newChart.nodes || newChart.nodes.length == 0) { alert(PMA_messages['strAddOneSeriesWarning']); return; } @@ -968,17 +387,17 @@ $(function() {
$(this).dialog("close"); }; - + dlgButtons[PMA_messages['strClose']] = function() { newChart = null; $('span#clearSeriesLink').hide(); $('#seriesPreview').html(''); $(this).dialog("close"); }; - + $('div#addChartDialog').dialog({ - width:'auto', - height:'auto', + width: 'auto', + height: 'auto', buttons: dlgButtons });
@@ -986,7 +405,7 @@ $(function() {
return false; }); - + $('a[href="#exportMonitorConfig"]').click(function() { var gridCopy = {};
@@ -996,40 +415,40 @@ $(function() { gridCopy[key].settings = elem.settings; gridCopy[key].title = elem.title; }); - + var exportData = { monitorCharts: gridCopy, monitorSettings: monitorSettings }; var $form; - - $('body').append($form = $('<form method="post" action="file_echo.php?'+url_query+'&filename=1" style="display:none;"></form>')); - + + $('body').append($form = $('<form method="post" action="file_echo.php?' + url_query + '&filename=1" style="display:none;"></form>')); + $form.append('<input type="hidden" name="monitorconfig" value="' + encodeURI($.toJSON(exportData)) + '">'); $form.submit(); $form.remove(); });
$('a[href="#importMonitorConfig"]').click(function() { - $('div#emptyDialog').attr('title','Import monitor configuration'); - $('div#emptyDialog').html('Please select the file you want to import:<br/><form action="file_echo.php?'+url_query+'&import=1" method="post" enctype="multipart/form-data">'+ + $('div#emptyDialog').attr('title', 'Import monitor configuration'); + $('div#emptyDialog').html('Please select the file you want to import:<br/><form action="file_echo.php?' + url_query + '&import=1" method="post" enctype="multipart/form-data">' + '<input type="file" name="file"> <input type="hidden" name="import" value="1"> </form>'); - + var dlgBtns = {}; - + dlgBtns[PMA_messages['strImport']] = function() { var $iframe, $form; $('body').append($iframe = $('<iframe id="monitorConfigUpload" style="display:none;"></iframe>')); var d = $iframe[0].contentWindow.document; d.open(); d.close(); mew = d; - + $iframe.load(function() { var json;
// Try loading config try { - var data = $('body',$('iframe#monitorConfigUpload')[0].contentWindow.document).html(); + var data = $('body', $('iframe#monitorConfigUpload')[0].contentWindow.document).html(); // Chrome wraps around '<pre style="word-wrap: break-word; white-space: pre-wrap;">' to any text content -.- json = $.secureEvalJSON(data.substring(data.indexOf("{"), data.lastIndexOf("}") + 1)); } catch (err) { @@ -1037,14 +456,14 @@ $(function() { $('div#emptyDialog').dialog('close'); return; } - + // Basic check, is this a monitor config json? - if(!json || ! json.monitorCharts || ! json.monitorCharts) { + if (!json || ! json.monitorCharts || ! json.monitorCharts) { alert(PMA_messages['strFailedParsingConfig']); $('div#emptyDialog').dialog('close'); return; } - + // If json ok, try applying config try { window.localStorage['monitorCharts'] = $.toJSON(json.monitorCharts); @@ -1057,20 +476,20 @@ $(function() { window.localStorage.removeItem('monitorSettings'); rebuildGrid(); } - + $('div#emptyDialog').dialog('close'); }); - - $("body", d).append($form=$('div#emptyDialog').find('form')); + + $("body", d).append($form = $('div#emptyDialog').find('form')); $form.submit(); $('div#emptyDialog').append('<img class="ajaxIcon" src="' + pmaThemeImage + 'ajax_clock_small.gif" alt="">'); }; - + dlgBtns[PMA_messages['strCancel']] = function() { $(this).dialog('close'); } - - + + $('div#emptyDialog').dialog({ width: 'auto', height: 'auto', @@ -1087,18 +506,18 @@ $(function() {
$('a[href="#pauseCharts"]').click(function() { runtime.redrawCharts = ! runtime.redrawCharts; - if(! runtime.redrawCharts) + if (! runtime.redrawCharts) { $(this).html('<img src="themes/dot.gif" class="icon ic_play" alt="" /> ' + PMA_messages['strResumeMonitor']); - else { + } else { $(this).html('<img src="themes/dot.gif" class="icon ic_pause" alt="" /> ' + PMA_messages['strPauseMonitor']); - if(! runtime.charts) { + if (! runtime.charts) { initGrid(); $('a[href="#settingsPopup"]').show(); } } return false; }); - + $('a[href="#monitorInstructionsDialog"]').click(function() { var $dialog = $('div#monitorInstructionsDialog');
@@ -1109,25 +528,28 @@ $(function() {
var loadLogVars = function(getvars) { vars = { ajax_request: true, logging_vars: true }; - if(getvars) $.extend(vars,getvars); + if (getvars) { + $.extend(vars, getvars); + }
$.get('server_status.php?' + url_query, vars, function(data) { var logVars = $.parseJSON(data), icon = 'ic_s_success', msg='', str='';
- if(logVars['general_log'] == 'ON') { - if(logVars['slow_query_log'] == 'ON') + if (logVars['general_log'] == 'ON') { + if (logVars['slow_query_log'] == 'ON') { msg = PMA_messages['strBothLogOn']; - else + } else { msg = PMA_messages['strGenLogOn']; + } }
- if(msg.length == 0 && logVars['slow_query_log'] == 'ON') { + if (msg.length == 0 && logVars['slow_query_log'] == 'ON') { msg = PMA_messages['strSlowLogOn']; }
- if(msg.length == 0) { + if (msg.length == 0) { icon = 'ic_s_error'; msg = PMA_messages['strBothLogOff']; } @@ -1135,65 +557,74 @@ $(function() { str = '<b>' + PMA_messages['strCurrentSettings'] + '</b><br><div class="smallIndent">'; str += '<img src="themes/dot.gif" class="icon ' + icon + '" alt=""/> ' + msg + '<br />';
- if(logVars['log_output'] != 'TABLE') + if (logVars['log_output'] != 'TABLE') { str += '<img src="themes/dot.gif" class="icon ic_s_error" alt=""/> ' + PMA_messages['strLogOutNotTable'] + '<br />'; - else + } else { str += '<img src="themes/dot.gif" class="icon ic_s_success" alt=""/> ' + PMA_messages['strLogOutIsTable'] + '<br />'; + }
- if(logVars['slow_query_log'] == 'ON') { - if(logVars['long_query_time'] > 2) + if (logVars['slow_query_log'] == 'ON') { + if (logVars['long_query_time'] > 2) { str += '<img src="themes/dot.gif" class="icon ic_s_attention" alt=""/> ' + $.sprintf(PMA_messages['strSmallerLongQueryTimeAdvice'], logVars['long_query_time']) + '<br />'; - - if(logVars['long_query_time'] < 2) + } + + if (logVars['long_query_time'] < 2) { str += '<img src="themes/dot.gif" class="icon ic_s_success" alt=""/> ' + $.sprintf(PMA_messages['strLongQueryTimeSet'], logVars['long_query_time']) + '<br />'; + } }
str += '</div>';
- if(is_superuser) { + if (is_superuser) { str += '<p></p><b>Change settings</b>'; str += '<div class="smallIndent">'; str += PMA_messages['strSettingsAppliedGlobal'] + '<br/>';
var varValue = 'TABLE'; - if(logVars['log_output'] == 'TABLE') varValue = 'FILE'; - + if (logVars['log_output'] == 'TABLE') { + varValue = 'FILE'; + } + str += '- <a class="set" href="#log_output-' + varValue + '">' + $.sprintf(PMA_messages['strSetLogOutput'], varValue) + ' </a><br />';
- if(logVars['general_log'] != 'ON') + if (logVars['general_log'] != 'ON') { str += '- <a class="set" href="#general_log-ON">' + $.sprintf(PMA_messages['strEnableVar'], 'general_log') + ' </a><br />'; - else + } else { str += '- <a class="set" href="#general_log-OFF">' + $.sprintf(PMA_messages['strDisableVar'], 'general_log') + ' </a><br />'; + }
- if(logVars['slow_query_log'] != 'ON') + if (logVars['slow_query_log'] != 'ON') { str += '- <a class="set" href="#slow_query_log-ON">' + $.sprintf(PMA_messages['strEnableVar'], 'slow_query_log') + ' </a><br />'; - else + } else { str += '- <a class="set" href="#slow_query_log-OFF">' + $.sprintf(PMA_messages['strDisableVar'], 'slow_query_log') + ' </a><br />'; - + }
varValue = 5; - if(logVars['long_query_time'] > 2) varValue = 1; + if (logVars['long_query_time'] > 2) { + varValue = 1; + }
str += '- <a class="set" href="#long_query_time-' + varValue + '">' + $.sprintf(PMA_messages['setSetLongQueryTime'], varValue) + ' </a><br />';
- } else + } else { str += PMA_messages['strNoSuperUser'] + '<br/>'; + }
str += '</div>';
@@ -1211,8 +642,8 @@ $(function() { } ); }; - - + + loadLogVars();
return false; @@ -1221,9 +652,12 @@ $(function() { $('input[name="chartType"]').change(function() { $('#chartVariableSettings').toggle(this.checked && this.value == 'variable'); var title = $('input[name="chartTitle"]').attr('value'); - if(title == PMA_messages['strChartTitle'] || title == $('label[for="'+$('input[name="chartTitle"]').data('lastRadio')+'"]').text()) { - $('input[name="chartTitle"]').data('lastRadio',$(this).attr('id')); - $('input[name="chartTitle"]').attr('value',$('label[for="'+$(this).attr('id')+'"]').text()); + if (title == PMA_messages['strChartTitle'] + || title == $('label[for="' + $('input[name="chartTitle"]').data('lastRadio') + '"]').text() + ) { + $('input[name="chartTitle"]') + .data('lastRadio', $(this).attr('id')) + .attr('value', $('label[for="' + $(this).attr('id') + '"]').text()); }
}); @@ -1236,23 +670,24 @@ $(function() { });
$('select[name="varChartList"]').change(function () { - if(this.selectedIndex!=0) - $('#variableInput').attr('value',this.value); + if (this.selectedIndex != 0) { + $('#variableInput').attr('value', this.value); + } });
$('a[href="#kibDivisor"]').click(function() { - $('input[name="valueDivisor"]').attr('value',1024); - $('input[name="valueUnit"]').attr('value',PMA_messages['strKiB']); + $('input[name="valueDivisor"]').attr('value', 1024); + $('input[name="valueUnit"]').attr('value', PMA_messages['strKiB']); $('span.unitInput').toggle(true); - $('input[name="useUnit"]').prop('checked',true); + $('input[name="useUnit"]').prop('checked', true); return false; });
$('a[href="#mibDivisor"]').click(function() { - $('input[name="valueDivisor"]').attr('value',1024*1024); - $('input[name="valueUnit"]').attr('value',PMA_messages['strMiB']); + $('input[name="valueDivisor"]').attr('value', 1024*1024); + $('input[name="valueUnit"]').attr('value', PMA_messages['strMiB']); $('span.unitInput').toggle(true); - $('input[name="useUnit"]').prop('checked',true); + $('input[name="useUnit"]').prop('checked', true); return false; });
@@ -1263,33 +698,37 @@ $(function() { });
$('a[href="#submitAddSeries"]').click(function() { - if($('input#variableInput').attr('value').length == 0) return false; - - if(newChart == null) { + if ($('input#variableInput').attr('value').length == 0) { + return false; + } + + if (newChart == null) { $('#seriesPreview').html('');
newChart = { title: $('input[name="chartTitle"]').attr('value'), nodes: [] - } + }; }
var serie = { - dataType:'statusvar', + dataType: 'statusvar', dataPoint: $('input#variableInput').attr('value'), name: $('input#variableInput').attr('value'), display: $('input[name="differentialValue"]').attr('checked') ? 'differential' : '' };
- if(serie.dataPoint == 'Processes') serie.dataType='proc'; + if (serie.dataPoint == 'Processes') { + serie.dataType='proc'; + }
- if($('input[name="useDivisor"]').attr('checked')) + if ($('input[name="useDivisor"]').attr('checked')) { serie.valueDivisor = parseInt($('input[name="valueDivisor"]').attr('value')); + }
- if($('input[name="useUnit"]').attr('checked')) + if ($('input[name="useUnit"]').attr('checked')) { serie.unit = $('input[name="valueUnit"]').attr('value'); - - + }
var str = serie.display == 'differential' ? ', ' + PMA_messages['strDifferential'] : ''; str += serie.valueDivisor ? (', ' + $.sprintf(PMA_messages['strDividedBy'], serie.valueDivisor)) : ''; @@ -1298,13 +737,13 @@ $(function() {
newChart.nodes.push(serie);
- $('input#variableInput').attr('value',''); - $('input[name="differentialValue"]').attr('checked',true); - $('input[name="useDivisor"]').attr('checked',false); - $('input[name="useUnit"]').attr('checked',false); + $('input#variableInput').attr('value', ''); + $('input[name="differentialValue"]').attr('checked', true); + $('input[name="useDivisor"]').attr('checked', false); + $('input[name="useUnit"]').attr('checked', false); $('input[name="useDivisor"]').trigger('change'); $('input[name="useUnit"]').trigger('change'); - $('select[name="varChartList"]').get(0).selectedIndex=0; + $('select[name="varChartList"]').get(0).selectedIndex = 0;
$('span#clearSeriesLink').show();
@@ -1315,33 +754,38 @@ $(function() { source: variableNames });
- + /* Initializes the monitor, called only once */ function initGrid() { var settings; var series;
/* Apply default values & config */ - if(window.localStorage) { - if(window.localStorage['monitorCharts']) + if (window.localStorage) { + if (window.localStorage['monitorCharts']) { runtime.charts = $.parseJSON(window.localStorage['monitorCharts']); - if(window.localStorage['monitorSettings']) + } + if (window.localStorage['monitorSettings']) { monitorSettings = $.parseJSON(window.localStorage['monitorSettings']); + }
$('a[href="#clearMonitorConfig"]').toggle(runtime.charts != null); }
- if(runtime.charts == null) + if (runtime.charts == null) { runtime.charts = defaultChartGrid; - if(monitorSettings == null) + } + if (monitorSettings == null) { monitorSettings = defaultMonitorSettings; + }
- $('select[name="gridChartRefresh"]').attr('value',monitorSettings.gridRefresh / 1000); - $('select[name="chartColumns"]').attr('value',monitorSettings.columns); + $('select[name="gridChartRefresh"]').attr('value', monitorSettings.gridRefresh / 1000); + $('select[name="chartColumns"]').attr('value', monitorSettings.columns);
- if(monitorSettings.gridMaxPoints == 'auto') + if (monitorSettings.gridMaxPoints == 'auto') { runtime.gridMaxPoints = Math.round((monitorSettings.chartSize.width - 40) / 12); - else + } else { runtime.gridMaxPoints = monitorSettings.gridMaxPoints; + }
runtime.xmin = new Date().getTime() - server_time_diff - runtime.gridMaxPoints * monitorSettings.gridRefresh; runtime.xmax = new Date().getTime() - server_time_diff + monitorSettings.gridRefresh; @@ -1349,81 +793,90 @@ $(function() { /* Calculate how much spacing there is between each chart */ $('table#chartGrid').html('<tr><td></td><td></td></tr><tr><td></td><td></td></tr>'); chartSpacing = { - width: $('table#chartGrid td:nth-child(2)').offset().left - $('table#chartGrid td:nth-child(1)').offset().left, - height: $('table#chartGrid tr:nth-child(2) td:nth-child(2)').offset().top - $('table#chartGrid tr:nth-child(1) td:nth-child(1)').offset().top + width: $('table#chartGrid td:nth-child(2)').offset().left + - $('table#chartGrid td:nth-child(1)').offset().left, + height: $('table#chartGrid tr:nth-child(2) td:nth-child(2)').offset().top + - $('table#chartGrid tr:nth-child(1) td:nth-child(1)').offset().top } $('table#chartGrid').html(''); - + /* Add all charts - in correct order */ var keys = []; $.each(runtime.charts, function(key, value) { keys.push(key); }); keys.sort(); - for(var i=0; i<keys.length; i++) - addChart(runtime.charts[keys[i]],true); + for (var i = 0; i<keys.length; i++) + addChart(runtime.charts[keys[i]], true);
/* Fill in missing cells */ var numCharts = $('table#chartGrid .monitorChart').length; var numMissingCells = (monitorSettings.columns - numCharts % monitorSettings.columns) % monitorSettings.columns; - for(var i=0; i < numMissingCells; i++) { + for (var i = 0; i < numMissingCells; i++) { $('table#chartGrid tr:last').append('<td></td>'); }
// Empty cells should keep their size so you can drop onto them - $('table#chartGrid tr td').css('width',chartSize().width + 'px'); - + $('table#chartGrid tr td').css('width', chartSize().width + 'px'); + buildRequiredDataList(); refreshChartGrid(); } - + + /* Destroys all monitor related resources */ function destroyGrid() { - if(runtime.charts) + if (runtime.charts) { $.each(runtime.charts, function(key, value) { try { value.chart.destroy(); } catch(err) {} }); + } + try { runtime.refreshRequest.abort(); } catch(err) {} - try { + try { clearTimeout(runtime.refreshTimeout); } catch(err) {} - + $('table#chartGrid').html('');
runtime.charts = null; runtime.chartAI = 0; monitorSettings = null; } - + + /* Calls destroyGrid() and initGrid(), but before doing so it saves the chart + * data from each chart and restores it after the monitor is initialized again */ function rebuildGrid() { var oldData = null; - if(runtime.charts) { + if (runtime.charts) { oldData = {}; $.each(runtime.charts, function(key, chartObj) { - for(var i=0; i < chartObj.nodes.length; i++) { + for (var i = 0; i < chartObj.nodes.length; i++) { oldData[chartObj.nodes[i].dataPoint] = []; - for(var j=0; j < chartObj.chart.series[i].data.length; j++) + for (var j = 0; j < chartObj.chart.series[i].data.length; j++) oldData[chartObj.nodes[i].dataPoint].push([chartObj.chart.series[i].data[j].x, chartObj.chart.series[i].data[j].y]); } }); } - + destroyGrid(); initGrid(); - - if(oldData) { + + if (oldData) { $.each(runtime.charts, function(key, chartObj) { - for(var j=0; j < chartObj.nodes.length; j++) { - if(oldData[chartObj.nodes[j].dataPoint]) + for (var j = 0; j < chartObj.nodes.length; j++) { + if (oldData[chartObj.nodes[j].dataPoint]) { chartObj.chart.series[j].setData(oldData[chartObj.nodes[j].dataPoint]); + } } }); - } + } }
+ /* Calculactes the dynamic chart size that depends on the column width */ function chartSize() { var wdt = $('div#logTable').innerWidth() / monitorSettings.columns - (monitorSettings.columns - 1) * chartSpacing.width; return { @@ -1432,9 +885,10 @@ $(function() { } }
+ /* Adds a chart to the chart grid */ function addChart(chartObj, initialize) { series = []; - for(var j=0; j<chartObj.nodes.length; j++) + for (var j = 0; j<chartObj.nodes.length; j++) series.push(chartObj.nodes[j]);
settings = { @@ -1446,7 +900,9 @@ $(function() { zoomType: 'x', events: { selection: function(event) { - if(editMode) return false; + if (editMode) { + return false; + }
var extremesObject = event.xAxis[0], min = extremesObject.min, @@ -1460,28 +916,21 @@ $(function() { var dlgBtns = { };
dlgBtns[PMA_messages['strFromSlowLog']] = function() { - var dateStart = Date.parse($('#logAnalyseDialog input[name="dateStart"]').attr('value')) || min; - var dateEnd = Date.parse($('#logAnalyseDialog input[name="dateEnd"]').attr('value')) || max; - - loadLogStatistics({ - src: 'slow', - start: dateStart, - end: dateEnd, - removeVariables: $('input#removeVariables').prop('checked'), - limitTypes: $('input#limitTypes').prop('checked') - }); - - $('#logAnalyseDialog').find('dateStart,dateEnd').datepicker('destroy'); - + loadLog('slow'); $(this).dialog("close"); }; - + dlgBtns[PMA_messages['strFromGeneralLog']] = function() { - var dateStart = Date.parse($('#logAnalyseDialog input[name="dateStart"]').attr('value')) || min; - var dateEnd = Date.parse($('#logAnalyseDialog input[name="dateEnd"]').attr('value')) || max; + loadLog('general'); + $(this).dialog("close"); + }; + + function loadLog(type) { + var dateStart = Date.parse($('#logAnalyseDialog input[name="dateStart"]').prop('value')) || min; + var dateEnd = Date.parse($('#logAnalyseDialog input[name="dateEnd"]').prop('value')) || max;
loadLogStatistics({ - src: 'general', + src: type, start: dateStart, end: dateEnd, removeVariables: $('input#removeVariables').prop('checked'), @@ -1489,10 +938,8 @@ $(function() { });
$('#logAnalyseDialog').find('dateStart,dateEnd').datepicker('destroy'); - - $(this).dialog("close"); - }; - + } + $('#logAnalyseDialog').dialog({ width: 'auto', height: 'auto', @@ -1515,10 +962,10 @@ $(function() { }, tooltip: { formatter: function() { - var s = '<b>'+Highcharts.dateFormat('%H:%M:%S', this.x)+'</b>'; + var s = '<b>' + Highcharts.dateFormat('%H:%M:%S', this.x) + '</b>';
$.each(this.points, function(i, point) { - s += '<br/><span style="color:'+point.series.color+'">'+ point.series.name +':</span> '+ + s += '<br/><span style="color:' + point.series.color + '">' + point.series.name + ':</span> ' + ((parseInt(point.y) == point.y) ? point.y : Highcharts.numberFormat(this.y, 2)) + ' ' + (point.series.options.unit || ''); });
@@ -1534,87 +981,97 @@ $(function() { title: { text: chartObj.title } };
- if(chartObj.settings) - $.extend(true,settings,chartObj.settings); + if (chartObj.settings) { + $.extend(true, settings, chartObj.settings); + }
- if($('#'+settings.chart.renderTo).length==0) { + if ($('#' + settings.chart.renderTo).length == 0) { var numCharts = $('table#chartGrid .monitorChart').length;
- if(numCharts == 0 || !( numCharts % monitorSettings.columns)) + if (numCharts == 0 || !( numCharts % monitorSettings.columns)) { $('table#chartGrid').append('<tr></tr>'); + }
- $('table#chartGrid tr:last').append('<td><div class="ui-state-default monitorChart" id="'+settings.chart.renderTo+'"></div></td>'); + $('table#chartGrid tr:last').append('<td><div class="ui-state-default monitorChart" id="' + settings.chart.renderTo + '"></div></td>'); }
chartObj.chart = PMA_createChart(settings); chartObj.numPoints = 0; - - if(initialize != true) { - runtime.charts['c'+runtime.chartAI] = chartObj; + + if (initialize != true) { + runtime.charts['c' + runtime.chartAI] = chartObj; buildRequiredDataList(); }
- // Edit,Print icon only in edit mode + // Edit, Print icon only in edit mode $('table#chartGrid div svg').find('*[zIndex=20], *[zIndex=21], *[zIndex=19]').toggle(editMode)
runtime.chartAI++; }
+ /* Opens a dialog that allows one to edit the title and series labels of the supplied chart */ function editChart(chartObj) { var htmlnode = chartObj.options.chart.renderTo; - if(! htmlnode ) return; - - var chart=null; - var chartKey=null; + if (! htmlnode ) { + return; + } + + var chart = null; + var chartKey = null; $.each(runtime.charts, function(key, value) { - if(value.chart.options.chart.renderTo == htmlnode) { + if (value.chart.options.chart.renderTo == htmlnode) { chart = value; chartKey = key; return false; } }); - - if(chart == null) return; + + if (chart == null) { + return; + }
var htmlStr = '<p><b>Chart title: </b> <br/> <input type="text" size="35" name="chartTitle" value="' + chart.title + '" />'; htmlStr += '</p><p><b>Series:</b> </p><ol>'; - for(var i=0; i<chart.nodes.length; i++) { - htmlStr += '<li><i>' + chart.nodes[i].dataPoint +': </i><br/><input type="text" name="chartSerie-' + i + '" value=" ' + chart.nodes[i].name + '" /></li>'; + for (var i = 0; i<chart.nodes.length; i++) { + htmlStr += '<li><i>' + chart.nodes[i].dataPoint + ': </i><br/><input type="text" name="chartSerie-' + i + '" value=" ' + chart.nodes[i].name + '" /></li>'; } - + dlgBtns = {}; dlgBtns['Save'] = function() { runtime.charts[chartKey].title = $('div#emptyDialog input[name="chartTitle"]').attr('value'); runtime.charts[chartKey].chart.setTitle({ text: runtime.charts[chartKey].title }); - + $('div#emptyDialog input[name*="chartSerie"]').each(function() { var idx = $(this).attr('name').split('-')[1]; runtime.charts[chartKey].nodes[idx].name = $(this).attr('value'); runtime.charts[chartKey].chart.series[idx].name = $(this).attr('value'); }); - + $(this).dialog('close'); saveMonitor(); }; dlgBtns['Cancel'] = function() { $(this).dialog('close'); }; - - $('div#emptyDialog').attr('title','Edit chart'); - $('div#emptyDialog').html(htmlStr+'</ol>'); + + $('div#emptyDialog').attr('title', 'Edit chart'); + $('div#emptyDialog').html(htmlStr + '</ol>'); $('div#emptyDialog').dialog({ width: 'auto', height: 'auto', buttons: dlgBtns }); } - + + /* Removes a chart from the grid */ function removeChart(chartObj) { var htmlnode = chartObj.options.chart.renderTo; - if(! htmlnode ) return; - + if (! htmlnode ) { + return; + } + $.each(runtime.charts, function(key, value) { - if(value.chart.options.chart.renderTo == htmlnode) { + if (value.chart.options.chart.renderTo == htmlnode) { delete runtime.charts[key]; return false; } @@ -1627,71 +1084,90 @@ $(function() { setTimeout(function() { chartObj.destroy(); $('div#' + htmlnode).remove(); - },10); + }, 10);
saveMonitor(); // Save settings }
+ /* Called in regular intervalls, this function updates the values of each chart in the grid */ function refreshChartGrid() { /* Send to server */ - runtime.refreshRequest = $.post('server_status.php?'+url_query, { ajax_request: true, chart_data: 1, type: 'chartgrid', requiredData: $.toJSON(runtime.dataList) },function(data) { + runtime.refreshRequest = $.post('server_status.php?' + url_query, { + ajax_request: true, + chart_data: 1, + type: 'chartgrid', + requiredData: $.toJSON(runtime.dataList) + }, function(data) { var chartData; try { chartData = $.parseJSON(data); } catch(err) { return serverResponseError(); } - var value, i=0; + var value, i = 0; var diff; - + /* Update values in each graph */ $.each(runtime.charts, function(orderKey, elem) { var key = elem.chartID; // If newly added chart, we have no data for it yet - if(! chartData[key]) return; + if (! chartData[key]) { + return; + } // Draw all points - for(var j=0; j < elem.nodes.length; j++) { + for (var j = 0; j < elem.nodes.length; j++) { value = chartData[key][j].y; + + // Update x-axis + if (i == 0 && j == 0) { + if (oldChartData == null) { + diff = chartData.x - runtime.xmax; + } else { + diff = parseInt(chartData.x - oldChartData.x); + }
- if(i==0 && j==0) { - if(oldChartData==null) diff = chartData.x - runtime.xmax; - else diff = parseInt(chartData.x - oldChartData.x); - - runtime.xmin+= diff; - runtime.xmax+= diff; + runtime.xmin += diff; + runtime.xmax += diff; }
elem.chart.xAxis[0].setExtremes(runtime.xmin, runtime.xmax, false);
- if(elem.nodes[j].display == 'differential') { - if(oldChartData == null || oldChartData[key] == null) continue; + // Calculate y value + if (elem.nodes[j].display == 'differential') { + if (oldChartData == null || oldChartData[key] == null) { + continue; + } value -= oldChartData[key][j].y; }
- if(elem.nodes[j].valueDivisor) + if (elem.nodes[j].valueDivisor) { value = value / elem.nodes[j].valueDivisor; + }
- if(elem.nodes[j].transformFn) { + if (elem.nodes[j].transformFn) { value = chartValueTransform( elem.nodes[j].transformFn, chartData[key][j], (oldChartData == null ? null : oldChartData[key][j]) ); } - - if(value != undefined) + + // Set y value, if defined + if (value != undefined) { elem.chart.series[j].addPoint( - { x: chartData.x, y: value }, + { x: chartData.x, y: value }, false, elem.numPoints >= runtime.gridMaxPoints ); + } }
i++;
runtime.charts[orderKey].numPoints++; - if(runtime.redrawCharts) + if (runtime.redrawCharts) { elem.chart.redraw(); + } });
oldChartData = chartData; @@ -1699,11 +1175,15 @@ $(function() { runtime.refreshTimeout = setTimeout(refreshChartGrid, monitorSettings.gridRefresh); }); } - - function chartValueTransform(name,cur,prev) { + + /* Function that supplies special value transform functions for chart values */ + function chartValueTransform(name, cur, prev) { switch(name) { case 'cpu-linux': - if(prev == null) return undefined; + if (prev == null) { + return undefined; + } + var diff_total = cur.busy + cur.idle - (prev.busy + prev.idle); var diff_idle = cur.idle - prev.idle; return 100*(diff_total - diff_idle) / diff_total; @@ -1711,10 +1191,11 @@ $(function() { return undefined; }
- /* Build list of nodes that need to be retrieved */ + /* Build list of nodes that need to be retrieved from server */ function buildRequiredDataList() { runtime.dataList = {}; - // Store an own id, because the property name is subject of reordering, thus destroying our mapping with runtime.charts <=> runtime.dataList + // Store an own id, because the property name is subject of reordering, + // thus destroying our mapping with runtime.charts <=> runtime.dataList var chartID = 0; $.each(runtime.charts, function(key, chart) { runtime.dataList[chartID] = chart.nodes; @@ -1723,24 +1204,30 @@ $(function() { }); }
+ /* Loads the log table data, generates the table and handles the filters */ function loadLogStatistics(opts) { var tableStr = ''; var logRequest = null;
- if(! opts.removeVariables) + if (! opts.removeVariables) { opts.removeVariables = false; - if(! opts.limitTypes) + } + if (! opts.limitTypes) { opts.limitTypes = false; - - $('#emptyDialog').html(PMA_messages['strAnalysingLogs'] + ' <img class="ajaxIcon" src="' + pmaThemeImage + 'ajax_clock_small.gif" alt="">'); + } + + $('#emptyDialog').html(PMA_messages['strAnalysingLogs'] + + ' <img class="ajaxIcon" src="' + pmaThemeImage + + 'ajax_clock_small.gif" alt="">');
$('#emptyDialog').dialog({ width: 'auto', height: 'auto', buttons: { 'Cancel request': function() { - if(logRequest != null) + if (logRequest != null) { logRequest.abort(); + }
$(this).dialog("close"); } @@ -1748,7 +1235,7 @@ $(function() { });
- logRequest = $.get('server_status.php?'+url_query, + logRequest = $.get('server_status.php?' + url_query, { ajax_request: true, log_data: 1, type: opts.src, @@ -1757,15 +1244,15 @@ $(function() { removeVariables: opts.removeVariables, limitTypes: opts.limitTypes }, - function(data) { + function(data) { var logData; try { logData = $.parseJSON(data); } catch(err) { return serverResponseError(); } - - if(logData.rows.length != 0) { + + if (logData.rows.length != 0) { runtime.logDataCols = buildLogTable(logData);
/* Show some stats in the dialog */ @@ -1773,12 +1260,14 @@ $(function() { $('#emptyDialog').html('<p>' + PMA_messages['strLogDataLoaded'] + '</p>'); $.each(logData.sum, function(key, value) { key = key.charAt(0).toUpperCase() + key.slice(1).toLowerCase(); - if(key == 'Total') key = '<b>' + key + '</b>'; + if (key == 'Total') { + key = '<b>' + key + '</b>'; + } $('#emptyDialog').append(key + ': ' + value + '<br/>'); });
/* Add filter options if more than a bunch of rows there to filter */ - if(logData.numRows > 12) { + if (logData.numRows > 12) { $('div#logTable').prepend( '<fieldset id="logDataFilter">' + ' <legend>' + PMA_messages['strFilters'] + '</legend>' + @@ -1798,9 +1287,7 @@ $(function() { filterQueries(true); });
- //preg_replace('/\s+([^=]+)=(\d+|(('|"|)(?U)(.+)(?<!\)\4(\s+|$)))/i',' $1={} ',$str); - - if(logData.numRows > 250) { + if (logData.numRows > 250) { $('div#logTable button#startFilterQueryText').click(filterQueries); } else { $('div#logTable input#filterQueryText').keyup(filterQueries); @@ -1813,61 +1300,76 @@ $(function() { $(this).dialog("close"); $(document).scrollTop($('div#logTable').offset().top); }; - + $('#emptyDialog').dialog( "option", "buttons", dlgBtns); - + } else { $('#emptyDialog').html('<p>' + PMA_messages['strNoDataFound'] + '</p>'); - + var dlgBtns = {}; - dlgBtns[PMA_messages['strClose']] = function() { - $(this).dialog("close"); + dlgBtns[PMA_messages['strClose']] = function() { + $(this).dialog("close"); }; - + $('#emptyDialog').dialog( "option", "buttons", dlgBtns ); } } );
+ /* Handles the actions performed when the user uses any of the log table filters + * which are the filter by name and grouping with ignoring data in WHERE clauses + * + * @param boolean Should be true when the users enabled or disabled to group queries ignoring data in WHERE clauses + */ function filterQueries(varFilterChange) { - var odd_row=false, cell, textFilter; + var odd_row = false, cell, textFilter; var val = $('div#logTable input#filterQueryText').val();
- if(val.length == 0) textFilter = null; - else textFilter = new RegExp(val, 'i'); - - var rowSum = 0, totalSum = 0, i=0, q; + if (val.length == 0) { + textFilter = null; + } else { + textFilter = new RegExp(val, 'i'); + } + + var rowSum = 0, totalSum = 0, i = 0, q; var noVars = $('div#logTable input#noWHEREData').attr('checked'); var equalsFilter = /([^=]+)=(\d+|(('|"|).*?[^\])\4((\s+)|$))/gi; var functionFilter = /([a-z0-9_]+)(.+?)/gi; - var filteredQueries = {}; - var filteredQueriesLines = {}; + var filteredQueries = {}, filteredQueriesLines = {}; var hide = false, rowData; var queryColumnName = runtime.logDataCols[runtime.logDataCols.length - 2]; var sumColumnName = runtime.logDataCols[runtime.logDataCols.length - 1]; - var isSlowLog = opts.src == 'slow'; var columnSums = {}; - + + // For the slow log we have to count many columns (query_time, lock_time, rows_examined, rows_sent, etc.) var countRow = function(query, row) { var cells = row.match(/<td>(.*?)</td>/gi); - if(!columnSums[query]) columnSums[query] = [0,0,0,0]; + if (!columnSums[query]) { + columnSums[query] = [0, 0, 0, 0]; + }
- columnSums[query][0] += timeToSec(cells[2].replace(/(<td>|</td>)/gi,'')); - columnSums[query][1] += timeToSec(cells[3].replace(/(<td>|</td>)/gi,'')); - columnSums[query][2] += parseInt(cells[4].replace(/(<td>|</td>)/gi,'')); - columnSums[query][3] += parseInt(cells[5].replace(/(<td>|</td>)/gi,'')); + // lock_time and query_time and displayed in timespan format + columnSums[query][0] += timeToSec(cells[2].replace(/(<td>|</td>)/gi, '')); + columnSums[query][1] += timeToSec(cells[3].replace(/(<td>|</td>)/gi, '')); + // rows_examind and rows_sent are just numbers + columnSums[query][2] += parseInt(cells[4].replace(/(<td>|</td>)/gi, '')); + columnSums[query][3] += parseInt(cells[5].replace(/(<td>|</td>)/gi, '')); }; - + // We just assume the sql text is always in the second last column, and that the total count is right of it $('div#logTable table tbody tr td:nth-child(' + (runtime.logDataCols.length - 1) + ')').each(function() { - if(varFilterChange && $(this).html().match(/^SELECT/i)) { - if(noVars) { + // If query is a SELECT and user enabled or disabled to group queries ignoring data in where statements, we + // need to re-calculate the sums of each row + if (varFilterChange && $(this).html().match(/^SELECT/i)) { + if (noVars) { + // Group on => Sum up identical columns, and hide all but 1 + q = $(this).text().replace(equalsFilter, '$1=...$6').trim(); q = q.replace(functionFilter, ' $1(...)');
// Js does not specify a limit on property name length, so we can abuse it as index :-) - if(filteredQueries[q]) { + if (filteredQueries[q]) { filteredQueries[q] += parseInt($(this).next().text()); totalSum += parseInt($(this).next().text()); hide = true; @@ -1876,18 +1378,20 @@ $(function() { filteredQueriesLines[q] = i; $(this).text(q); } - if(isSlowLog) countRow(q, $(this).parent().html()); + if (isSlowLog) { + countRow(q, $(this).parent().html()); + }
- // Restore original columns } else { - rowData = $(this).parent().data('query'); + // Group off: Restore original columns
- // SQL Text + rowData = $(this).parent().data('query'); + // Restore SQL text $(this).text(rowData[queryColumnName]); - // # + // Restore total count $(this).next().text(rowData[sumColumnName]); - // Slow log columns - if(isSlowLog) { + // Restore slow log columns + if (isSlowLog) { $(this).parent().children('td:nth-child(3)').text(rowData['query_time']); $(this).parent().children('td:nth-child(4)').text(rowData['lock_time']); $(this).parent().children('td:nth-child(5)').text(rowData['rows_sent']); @@ -1896,17 +1400,21 @@ $(function() { } }
- if(! hide && (textFilter != null && ! textFilter.exec($(this).text()))) hide = true; + // If not required to be hidden, do we need to hide because of a not matching text filter? + if (! hide && (textFilter != null && ! textFilter.exec($(this).text()))) { + hide = true; + }
- if(hide) { - $(this).parent().css('display','none'); + // Now display or hide this column + if (hide) { + $(this).parent().css('display', 'none'); } else { totalSum += parseInt($(this).next().text()); - rowSum ++; + rowSum++;
odd_row = ! odd_row; - $(this).parent().css('display',''); - if(odd_row) { + $(this).parent().css('display', ''); + if (odd_row) { $(this).parent().addClass('odd'); $(this).parent().removeClass('even'); } else { @@ -1918,19 +1426,21 @@ $(function() { hide = false; i++; }); - - // Update count values of grouped entries - if(varFilterChange) { - if(noVars) { + + // We finished summarizing counts => Update count values of all grouped entries + if (varFilterChange) { + if (noVars) { var numCol, row, $table = $('div#logTable table tbody'); - $.each(filteredQueriesLines, function(key,value) { - if(filteredQueries[key] <= 1) return; - - row = $table.children('tr:nth-child(' + (value+1) + ')'); + $.each(filteredQueriesLines, function(key, value) { + if (filteredQueries[key] <= 1) { + return; + } + + row = $table.children('tr:nth-child(' + (value + 1) + ')'); numCol = row.children(':nth-child(' + (runtime.logDataCols.length) + ')'); numCol.text(filteredQueries[key]); - - if(isSlowLog) { + + if (isSlowLog) { row.children('td:nth-child(3)').text(secToTime(columnSums[key][0])); row.children('td:nth-child(4)').text(secToTime(columnSums[key][1])); row.children('td:nth-child(5)').text(columnSums[key][2]); @@ -1938,46 +1448,48 @@ $(function() { } }); } - - $('div#logTable table').trigger("update"); - setTimeout(function() { - $('div#logTable table').trigger('sorton',[[[runtime.logDataCols.length - 1,1]]]); + + $('div#logTable table').trigger("update"); + setTimeout(function() { + $('div#logTable table').trigger('sorton', [[[runtime.logDataCols.length - 1, 1]]]); }, 0); }
+ // Display some stats at the bottom of the table $('div#logTable table tfoot tr') .html('<th colspan="' + (runtime.logDataCols.length - 1) + '">' + - PMA_messages['strSumRows'] + ' '+ rowSum +'<span style="float:right">' + + PMA_messages['strSumRows'] + ' ' + rowSum + '<span style="float:right">' + PMA_messages['strTotal'] + '</span></th><th align="right">' + totalSum + '</th>'); } }
- /*loadLogStatistics({ - src: 'general', - start:1311076210*1000, - end:1311162689*1000, - removeVariables: true, - limitTypes: true - });*/ - + /* Turns a timespan (12:12:12) into a number */ function timeToSec(timeStr) { var time = timeStr.split(':'); return parseInt(time[0]*3600) + parseInt(time[1]*60) + parseInt(time[2]); } - + + /* Turns a number into a timespan (100 into 00:01:40) */ function secToTime(timeInt) { hours = Math.floor(timeInt / 3600); timeInt -= hours*3600; minutes = Math.floor(timeInt / 60); timeInt -= minutes*60; - - if(hours < 10) hours = '0' + hours; - if(minutes < 10) minutes = '0' + minutes; - if(timeInt < 10) timeInt = '0' + timeInt; - + + if (hours < 10) { + hours = '0' + hours; + } + if (minutes < 10) { + minutes = '0' + minutes; + } + if (timeInt < 10) { + timeInt = '0' + timeInt; + } + return hours + ':' + minutes + ':' + timeInt; } - + + /* Constructs the log table out of the retrieved server data */ function buildLogTable(data) { var rows = data.rows; var cols = new Array(); @@ -1989,14 +1501,14 @@ $(function() { var formatValue = function(name, value) { switch(name) { case 'user_host': - return value.replace(/([.*?])+/g,''); + return value.replace(/([.*?])+/g, ''); } return value; }; - - for(var i=0; i < rows.length; i++) { - if(i == 0) { - $.each(rows[0],function(key, value) { + + for (var i = 0; i < rows.length; i++) { + if (i == 0) { + $.each(rows[0], function(key, value) { cols.push(key); }); $table.append( '<thead>' + @@ -2007,179 +1519,33 @@ $(function() { }
$tBody.append($tRow = $('<tr class="noclick"></tr>')); - var cl='' - for(var j=0; j < cols.length; j++) { + var cl = ''; + for (var j = 0; j < cols.length; j++) { // Assuming the query column is the second last - if(j == cols.length - 2 && rows[i][cols[j]].match(/^SELECT/i)) { - $tRow.append($tCell=$('<td class="linkElem">' + formatValue(cols[j], rows[i][cols[j]]) + '</td>')); - $tCell.click(queryAnalyzer); + if (j == cols.length - 2 && rows[i][cols[j]].match(/^SELECT/i)) { + $tRow.append($tCell = $('<td class="linkElem">' + formatValue(cols[j], rows[i][cols[j]]) + '</td>')); + $tCell.click(openQueryAnalyzer); } else $tRow.append('<td>' + formatValue(cols[j], rows[i][cols[j]]) + '</td>');
- $tRow.data('query',rows[i]); + $tRow.data('query', rows[i]); } }
$table.append('<tfoot>' + '<tr><th colspan="' + (cols.length - 1) + '">' + PMA_messages['strSumRows'] + - ' '+ data.numRows +'<span style="float:right">' + PMA_messages['strTotal'] + + ' ' + data.numRows + '<span style="float:right">' + PMA_messages['strTotal'] + '</span></th><th align="right">' + data.sum.TOTAL + '</th></tr></tfoot>');
- - function queryAnalyzer() { - var query = $(this).parent().data('query').argument || $(this).parent().data('query').sql_text; - var db = $(this).parent().data('query').db || ''; - - /* A very basic SQL Formatter. Totally fails in the cases of - - Any string appearance containing a MySQL Keyword, surrounded by whitespaces, e.g. WHERE bar = "This where the formatter fails" - - Subqueries too probably - */ - - // Matches the columns to be selected - // .* selector doesn't include whitespace and we have no PCRE_DOTALL modifier, (.|\s)+ crashes Chrome (reported and confirmed), - // [^]+ results in JS error in IE8, thus we use [^\0]+ for matching each column since the zero-byte char (hopefully) doesn't appear in column names ;) - var sLists = query.match(/SELECT\s+[^\0]+\s+FROM\s+/gi); - if(sLists) { - for(var i=0; i < sLists.length; i++) { - query = query.replace(sLists[i],sLists[i].replace(/\s*((`|'|"|).*?\1,)\s*/gi,'$1\n\t')); - } - query = query - .replace(/(\s+|^)(SELECT|FROM|WHERE|GROUP BY|HAVING|ORDER BY|LIMIT)(\s+|$)/gi,'\n$2\n\t') - .replace(/\s+UNION\s+/gi,'\n\nUNION\n\n') - .replace(/\s+(AND)\s+/gi,' $1\n\t') - .trim(); - } - - codemirror_editor.setValue(query); - - var profilingChart = null; - - $('div#queryAnalyzerDialog').dialog({ - width: 'auto', - height: 'auto', - resizable: false, - buttons: { - 'Analyse Query' : function() { - $('div#queryAnalyzerDialog div.placeHolder').html('Analyzing... ' + '<img class="ajaxIcon" src="' + pmaThemeImage + 'ajax_clock_small.gif" alt="">'); - - $.post('server_status.php?'+url_query, { - ajax_request: true, - query_analyzer: true, - query: codemirror_editor.getValue(), - database: db - }, function(data) { - data = $.parseJSON(data); - var totalTime = 0; - - if(data.error) { - $('div#queryAnalyzerDialog div.placeHolder').html('<div class="error">' + data.error + '</div>'); - return; - } - - // Float sux, I'll use table :( - $('div#queryAnalyzerDialog div.placeHolder') - .html('<table width="100%" border="0"><tr><td class="explain"></td><td class="chart"></td></tr></table>'); - - var explain = '<b>Explain output</b> '+explain_docu; - if(data.explain.length > 1) { - explain += ' ('; - for(var i=0; i < data.explain.length; i++) { - if(i > 0) explain += ', '; - explain += '<a href="#showExplain-' + i + '">' + i + '</a>'; - } - explain += ')'; - } - explain +='<p></p>'; - for(var i=0; i < data.explain.length; i++) { - explain += '<div class="explain-' + i + '"' + (i>0? 'style="display:none;"' : '' ) + '>'; - $.each(data.explain[i], function(key,value) { - value = (value==null)?'null':value; - - if(key == 'type' && value.toLowerCase() == 'all') value = '<span class="attention">' + value +'</span>'; - if(key == 'Extra') value = value.replace(/(using (temporary|filesort))/gi,'<span class="attention">$1</span>'); - explain += key+': ' + value + '<br />'; - }); - explain += '</div>'; - } - - // Since there is such a nice free space below the explain, lets put it here for now - explain += '<p><b>' + PMA_messages['strAffectedRows'] + '</b> ' + data.affectedRows; - - $('div#queryAnalyzerDialog div.placeHolder td.explain').append(explain); - - $('div#queryAnalyzerDialog div.placeHolder a[href*="#showExplain"]').click(function() { - var id = $(this).attr('href').split('-')[1]; - $(this).parent().find('div[class*="explain"]').hide(); - $(this).parent().find('div[class*="explain-' + id + '"]').show(); - }); - - if(data.profiling) { - var chartData = []; - var numberTable = '<table class="queryNums"><thead><tr><th>Status</th><th>Time</th></tr></thead><tbody>'; - var duration; - - for(var i=0; i < data.profiling.length; i++) { - duration = parseFloat(data.profiling[i].duration); - - chartData.push([data.profiling[i].state, duration]); - totalTime+=duration; - - numberTable += '<tr><td>' + data.profiling[i].state + ' </td><td> ' + PMA_prettyProfilingNum(duration,2) + '</td></tr>'; - } - numberTable += '<tr><td><b>Total time:</b></td><td>' + PMA_prettyProfilingNum(totalTime,2) + '</td></tr>'; - numberTable += '</tbody></table>'; - - $('div#queryAnalyzerDialog div.placeHolder td.chart').append('<b>Profiling results ' + profiling_docu + '</b> (<a href="#showNums">Table</a>, <a href="#showChart">Chart</a>)<br/>' + numberTable + ' <div id="queryProfiling"></div>'); - - $('div#queryAnalyzerDialog div.placeHolder a[href="#showNums"]').click(function() { - $('div#queryAnalyzerDialog div#queryProfiling').hide(); - $('div#queryAnalyzerDialog table.queryNums').show(); - return false; - }); - - $('div#queryAnalyzerDialog div.placeHolder a[href="#showChart"]').click(function() { - $('div#queryAnalyzerDialog div#queryProfiling').show(); - $('div#queryAnalyzerDialog table.queryNums').hide(); - return false; - }); - - profilingChart = PMA_createProfilingChart(chartData, { - chart: { - renderTo: 'queryProfiling' - }, - plotOptions: { - pie: { - size: '50%' - } - } - }); - - - $('div#queryProfiling').resizable(); - } - - }); - }, - 'Close' : function() { - if(profilingChart != null) { - profilingChart.destroy(); - } - $('div#queryAnalyzerDialog div.placeHolder').html(''); - codemirror_editor.setValue(''); - - $(this).dialog("close"); - } - } - }); - } - // Append a tooltip to the count column, if there exist one - if($('#logTable th:last').html() == '#') { + if ($('#logTable th:last').html() == '#') { $('#logTable th:last').append(' <img class="qroupedQueryInfoIcon icon ic_b_docs" src="themes/dot.gif" alt="" />');
var qtipContent = PMA_messages['strCountColumnExplanation']; - if(groupInserts) qtipContent += '<p>' + PMA_messages['strMoreCountColumnExplanation'] + '</p>'; + if (groupInserts) { + qtipContent += '<p>' + PMA_messages['strMoreCountColumnExplanation'] + '</p>'; + }
$('img.qroupedQueryInfoIcon').qtip({ content: qtipContent, @@ -2195,7 +1561,7 @@ $(function() { }
$('div#logTable table').tablesorter({ - sortList: [[cols.length - 1,1]], + sortList: [[cols.length - 1, 1]], widgets: ['zebra'] });
@@ -2204,7 +1570,169 @@ $(function() {
return cols; } + + /* Opens the query analyzer dialog */ + function openQueryAnalyzer() { + var rowData = $(this).parent().data('query'); + var query = rowData.argument || rowData.sql_text; + + /* A very basic SQL Formatter. Totally fails in the cases of + - Any string appearance containing a MySQL Keyword, surrounded by whitespaces, e.g. WHERE bar = "This where the formatter fails" + - Subqueries too probably + */ + + // Matches the columns to be selected + // .* selector doesn't include whitespace and we have no PCRE_DOTALL modifier, (.|\s)+ crashes Chrome (reported and confirmed), + // [^]+ results in JS error in IE8, thus we use [^\0]+ for matching each column since the zero-byte char (hopefully) doesn't appear in column names ;) + var sLists = query.match(/SELECT\s+[^\0]+\s+FROM\s+/gi); + if (sLists) { + for (var i = 0; i < sLists.length; i++) { + query = query.replace(sLists[i], sLists[i].replace(/\s*((`|'|"|).*?\1,)\s*/gi, '$1\n\t')); + } + query = query + .replace(/(\s+|^)(SELECT|FROM|WHERE|GROUP BY|HAVING|ORDER BY|LIMIT)(\s+|$)/gi, '\n$2\n\t') + .replace(/\s+UNION\s+/gi, '\n\nUNION\n\n') + .replace(/\s+(AND)\s+/gi, ' $1\n\t') + .trim(); + } + + codemirror_editor.setValue(query); + + var profilingChart = null; + var dlgBtns = {}; + + dlgBtns[PMA_messages['strAnalyzeQuery']] = function() { + loadQueryAnalysis(rowData); + }; + dlgBtns[PMA_messages['strClose']] = function() { + if (profilingChart != null) { + profilingChart.destroy(); + } + $('div#queryAnalyzerDialog div.placeHolder').html(''); + codemirror_editor.setValue(''); + $(this).dialog("close"); + }; + + $('div#queryAnalyzerDialog').dialog({ + width: 'auto', + height: 'auto', + resizable: false, + buttons: dlgBtns + }); + } + + /* Loads and displays the analyzed query data */ + function loadQueryAnalysis(rowData) { + var db = rowData.db || ''; + + $('div#queryAnalyzerDialog div.placeHolder').html( + 'Analyzing... ' + '<img class="ajaxIcon" src="' + + pmaThemeImage + 'ajax_clock_small.gif" alt="">'); + + $.post('server_status.php?' + url_query, { + ajax_request: true, + query_analyzer: true, + query: codemirror_editor.getValue(), + database: db + }, function(data) { + data = $.parseJSON(data); + var totalTime = 0; + + if (data.error) { + $('div#queryAnalyzerDialog div.placeHolder').html('<div class="error">' + data.error + '</div>'); + return; + } + + // Float sux, I'll use table :( + $('div#queryAnalyzerDialog div.placeHolder') + .html('<table width="100%" border="0"><tr><td class="explain"></td><td class="chart"></td></tr></table>'); + + var explain = '<b>Explain output</b> ' + explain_docu; + if (data.explain.length > 1) { + explain += ' ('; + for (var i = 0; i < data.explain.length; i++) { + if (i > 0) { + explain += ', '; + } + explain += '<a href="#showExplain-' + i + '">' + i + '</a>'; + } + explain += ')'; + } + explain += '<p></p>'; + for (var i = 0; i < data.explain.length; i++) { + explain += '<div class="explain-' + i + '"' + (i>0? 'style="display:none;"' : '' ) + '>'; + $.each(data.explain[i], function(key, value) { + value = (value == null)?'null':value; + + if (key == 'type' && value.toLowerCase() == 'all') { + value = '<span class="attention">' + value + '</span>'; + } + if (key == 'Extra') { + value = value.replace(/(using (temporary|filesort))/gi, '<span class="attention">$1</span>'); + } + explain += key + ': ' + value + '<br />'; + }); + explain += '</div>'; + } + + explain += '<p><b>' + PMA_messages['strAffectedRows'] + '</b> ' + data.affectedRows; + + $('div#queryAnalyzerDialog div.placeHolder td.explain').append(explain); + + $('div#queryAnalyzerDialog div.placeHolder a[href*="#showExplain"]').click(function() { + var id = $(this).attr('href').split('-')[1]; + $(this).parent().find('div[class*="explain"]').hide(); + $(this).parent().find('div[class*="explain-' + id + '"]').show(); + }); + + if (data.profiling) { + var chartData = []; + var numberTable = '<table class="queryNums"><thead><tr><th>Status</th><th>Time</th></tr></thead><tbody>'; + var duration; + + for (var i = 0; i < data.profiling.length; i++) { + duration = parseFloat(data.profiling[i].duration); + + chartData.push([data.profiling[i].state, duration]); + totalTime += duration; + + numberTable += '<tr><td>' + data.profiling[i].state + ' </td><td> ' + PMA_prettyProfilingNum(duration, 2) + '</td></tr>'; + } + numberTable += '<tr><td><b>Total time:</b></td><td>' + PMA_prettyProfilingNum(totalTime, 2) + '</td></tr>'; + numberTable += '</tbody></table>'; + + $('div#queryAnalyzerDialog div.placeHolder td.chart').append('<b>Profiling results ' + profiling_docu + '</b> (<a href="#showNums">Table</a>, <a href="#showChart">Chart</a>)<br/>' + numberTable + ' <div id="queryProfiling"></div>'); + + $('div#queryAnalyzerDialog div.placeHolder a[href="#showNums"]').click(function() { + $('div#queryAnalyzerDialog div#queryProfiling').hide(); + $('div#queryAnalyzerDialog table.queryNums').show(); + return false; + }); + + $('div#queryAnalyzerDialog div.placeHolder a[href="#showChart"]').click(function() { + $('div#queryAnalyzerDialog div#queryProfiling').show(); + $('div#queryAnalyzerDialog table.queryNums').hide(); + return false; + }); + + profilingChart = PMA_createProfilingChart(chartData, { + chart: { + renderTo: 'queryProfiling' + }, + plotOptions: { + pie: { + size: '50%' + } + } + }); + + + $('div#queryProfiling').resizable(); + } + }); + }
+ /* Saves the monitor to localstorage */ function saveMonitor() { var gridCopy = {};
@@ -2215,22 +1743,11 @@ $(function() { gridCopy[key].title = elem.title; });
- if(window.localStorage) { + if (window.localStorage) { window.localStorage['monitorCharts'] = $.toJSON(gridCopy); window.localStorage['monitorSettings'] = $.toJSON(monitorSettings); }
$('a[href="#clearMonitorConfig"]').show(); } - - function serverResponseError() { - var btns = {}; - btns[PMA_messages['strReloadPage']] = function() { - window.location.reload(); - }; - $('#emptyDialog').attr('title',PMA_messages['strRefreshFailed']); - $('#emptyDialog').html('<img class="icon ic_s_attention" src="themes/dot.gif" alt=""> ' + PMA_messages['strInvalidResponseExplanation']) - $('#emptyDialog').dialog({ buttons: btns }); - } - -}); +}); \ No newline at end of file diff --git a/js/server_variables.js b/js/server_variables.js index 1aded3b..0ca5304 100644 --- a/js/server_variables.js +++ b/js/server_variables.js @@ -1,76 +1,25 @@ -function editVariable(link) -{ - var varName = $(link).parent().parent().find('th:first').first().text().replace(/ /g,'_'); - var mySaveLink = $(saveLink); - var myCancelLink = $(cancelLink); - var $cell = $(link).parent(); - - $cell.addClass('edit'); - // remove edit link - $cell.find('a.editLink').remove(); - - mySaveLink.click(function() { - $.get('server_variables.php?' + url_query, - { ajax_request: true, type: 'setval', varName: varName, varValue: $cell.find('input').attr('value') }, - function(data) { - if(data.success) $cell.html(data.variable); - else { - PMA_ajaxShowMessage(data.error); - $cell.html($cell.find('span.oldContent').html()); - } - $cell.removeClass('edit'); - }, - 'json' - ); - return false; - }); - - myCancelLink.click(function() { - $cell.html($cell.find('span.oldContent').html()); - $cell.removeClass('edit'); - return false; - }); - - - $.get('server_variables.php?' + url_query, - { ajax_request: true, type: 'getval', varName: varName }, - function(data) { - // hide original content - $cell.html('<span class="oldContent" style="display:none;">' + $cell.html() + '</span>'); - // put edit field and save/cancel link - $cell.prepend('<table class="serverVariableEditTable" border="0"><tr><td></td><td style="width:100%;"><input type="text" value="' + data + '"/></td></tr</table>'); - $cell.find('table td:first').append(mySaveLink); - $cell.find('table td:first').append(myCancelLink); - } - ); - - return false; -} - $(function() { - var textFilter=null; - var odd_row=false; + var textFilter = null, odd_row = false; var testString = 'abcdefghijklmnopqrstuvwxyz0123456789,ABCEFGHIJKLMOPQRSTUVWXYZ'; - var $tmpDiv; - var charWidth; + var $tmpDiv, charWidth;
// Global vars editLink = '<a href="#" class="editLink" onclick="return editVariable(this);"><img class="icon ic_b_edit" src="themes/dot.gif" alt=""> '+PMA_messages['strEdit']+'</a>'; saveLink = '<a href="#" class="saveLink"><img class="icon ic_b_save" src="themes/dot.gif" alt=""> '+PMA_messages['strSave']+'</a> '; cancelLink = '<a href="#" class="cancelLink"><img class="icon ic_b_close" src="themes/dot.gif" alt=""> '+PMA_messages['strCancel']+'</a> ';
- $.ajaxSetup({ cache:false });
/* Variable editing */ - if(isSuperuser) { + if (is_superuser) { $('table.data tbody tr td:nth-child(2)').hover( function() { // Only add edit element if it is the global value, not session value and not when the element is being edited - if($(this).parent().children('th').length > 0 && ! $(this).hasClass('edit')) + if ($(this).parent().children('th').length > 0 && ! $(this).hasClass('edit')) { $(this).prepend(editLink); + } }, function() { $(this).find('a.editLink').remove(); @@ -78,79 +27,94 @@ $(function() { ); }
- /*** This code snippet takes care that the table stays readable. It cuts off long strings the table overlaps the window size ***/ + // Filter options are invisible for disabled js users + $('fieldset#tableFilter').css('display',''); + + $('#filterText').keyup(function(e) { + if ($(this).val().length == 0) { + textFilter=null; + } else { + textFilter = new RegExp("(^| )"+$(this).val().replace(/_/g,' '),'i'); + } + filterVariables(); + }); + + if (location.hash.substr(1).split('=')[0] == 'filter') { + var name = location.hash.substr(1).split('=')[1]; + // Only allow variable names + if (! name.match(/[^0-9a-zA-Z_]+/)) { + $('#filterText').attr('value',name).trigger('keyup'); + } + } + + /* Table width limiting */ $('table.data').after($tmpDiv=$('<span>'+testString+'</span>')); charWidth = $tmpDiv.width() / testString.length; $tmpDiv.remove();
$(window).resize(limitTableWidth); limitTableWidth(); - + + /* This function chops of long variable values to keep the table from overflowing horizontally + * It does so by taking a test string and calculating an average font width and removing 'excess width / average font width' + * chars, so it is not very accurate. + */ function limitTableWidth() { var fulltext; var charDiff; var maxTableWidth; var $tmpTable;
- $('table.data').after($tmpTable=$('<table id="testTable" style="width:100%;"><tr><td>'+testString+'</td></tr></table>')); + $('table.data').after($tmpTable = $('<table id="testTable" style="width:100%;"><tr><td>' + testString + '</td></tr></table>')); maxTableWidth = $('#testTable').width(); $tmpTable.remove(); - charDiff = ($('table.data').width()-maxTableWidth) / charWidth; + charDiff = ($('table.data').width() - maxTableWidth) / charWidth;
- if($('body').innerWidth() < $('table.data').width()+10 || $('body').innerWidth() > $('table.data').width()+20) { - var maxChars=0; + if ($('body').innerWidth() < $('table.data').width() + 10 || $('body').innerWidth() > $('table.data').width() + 20) { + var maxChars = 0;
$('table.data tbody tr td:nth-child(2)').each(function() { - maxChars=Math.max($(this).text().length,maxChars); + maxChars = Math.max($(this).text().length, maxChars); });
// Do not resize smaller if there's only 50 chars displayed already - if(charDiff > 0 && maxChars < 50) return; + if (charDiff > 0 && maxChars < 50) { return; }
$('table.data tbody tr td:nth-child(2)').each(function() { - if((charDiff>0 && $(this).text().length > maxChars-charDiff) || (charDiff<0 && $(this).find('abbr.cutoff').length>0)) { - if($(this).find('abbr.cutoff').length > 0) + if ((charDiff > 0 && $(this).text().length > maxChars - charDiff) || (charDiff < 0 && $(this).find('abbr.cutoff').length > 0)) { + if ($(this).find('abbr.cutoff').length > 0) { fulltext = $(this).find('abbr.cutoff').attr('title'); - else { + } else { fulltext = $(this).text(); // Do not cut off elements with html in it and hope they are not too long - if(fulltext.length != $(this).html().length) return 0; + if (fulltext.length != $(this).html().length) { return 0; } }
- if(fulltext.length < maxChars-charDiff) + if (fulltext.length < maxChars - charDiff) { $(this).html(fulltext); - else $(this).html('<abbr class="cutoff" title="'+fulltext+'">'+fulltext.substr(0,maxChars-charDiff-3)+'...</abbr>'); + } else { + $(this).html('<abbr class="cutoff" title="' + fulltext + '">' + fulltext.substr(0, maxChars - charDiff - 3) + '...</abbr>'); + } } }); } } - - // Filter options are invisible for disabled js users - $('fieldset#tableFilter').css('display',''); - - $('#filterText').keyup(function(e) { - if($(this).val().length==0) textFilter=null; - else textFilter = new RegExp("(^| )"+$(this).val().replace(/_/g,' '),'i'); - filterVariables(); - }); - + + /* Filters the rows by the user given regexp */ function filterVariables() { - odd_row=false; - var mark_next=false; - var firstCell; - + var mark_next = false, firstCell; + odd_row = false; + $('table.filteredData tbody tr').each(function() { firstCell = $(this).children(':first');
- if(mark_next || textFilter==null || textFilter.exec(firstCell.text())) { - // If current row is 'marked', also display next row - if($(this).hasClass('marked') && !mark_next) - mark_next=true; - else mark_next=false; + if (mark_next || textFilter == null || textFilter.exec(firstCell.text())) { + // If current global value is different from session value (=has class diffSession), then display that one too + mark_next = $(this).hasClass('diffSession') && ! mark_next;
- odd_row = !odd_row; + odd_row = ! odd_row; $(this).css('display',''); - if(odd_row) { + if (odd_row) { $(this).addClass('odd'); $(this).removeClass('even'); } else { @@ -163,3 +127,56 @@ $(function() { }); } }); + +/* Called by inline js. Allows the user to edit a server variable */ +function editVariable(link) +{ + var varName = $(link).parent().parent().find('th:first').first().text().replace(/ /g,'_'); + var mySaveLink = $(saveLink); + var myCancelLink = $(cancelLink); + var $cell = $(link).parent(); + + $cell.addClass('edit'); + // remove edit link + $cell.find('a.editLink').remove(); + + mySaveLink.click(function() { + $.get('server_variables.php?' + url_query, { + ajax_request: true, + type: 'setval', + varName: varName, + varValue: $cell.find('input').attr('value') + }, function(data) { + if (data.success) { + $cell.html(data.variable); + } else { + PMA_ajaxShowMessage(data.error); + $cell.html($cell.find('span.oldContent').html()); + } + $cell.removeClass('edit'); + }, 'json'); + + return false; + }); + + myCancelLink.click(function() { + $cell.html($cell.find('span.oldContent').html()); + $cell.removeClass('edit'); + return false; + }); + + $.get('server_variables.php?' + url_query, { + ajax_request: true, + type: 'getval', + varName: varName + }, function(data) { + // hide original content + $cell.html('<span class="oldContent" style="display:none;">' + $cell.html() + '</span>'); + // put edit field and save/cancel link + $cell.prepend('<table class="serverVariableEditTable" border="0"><tr><td></td><td style="width:100%;"><input type="text" value="' + data + '"/></td></tr</table>'); + $cell.find('table td:first').append(mySaveLink); + $cell.find('table td:first').append(myCancelLink); + }); + + return false; +} \ No newline at end of file diff --git a/libraries/advisor.lib.php b/libraries/advisor.class.php similarity index 77% rename from libraries/advisor.lib.php rename to libraries/advisor.class.php index f453097..df7178e 100644 --- a/libraries/advisor.lib.php +++ b/libraries/advisor.class.php @@ -1,4 +1,11 @@ <?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * A simple rules engine, that parses and executes the rules in advisory_rules.txt. Adjusted to phpMyAdmin + * + * + * @package phpMyAdmin + */
class Advisor { @@ -10,35 +17,31 @@ class Advisor // HowTo: A simple Advisory system in 3 easy steps.
// Step 1: Get some variables to evaluate on - $this->variables = array_merge(PMA_DBI_fetch_result('SHOW GLOBAL STATUS', 0, 1), PMA_DBI_fetch_result('SHOW GLOBAL VARIABLES', 0, 1)); + $this->variables = array_merge( + PMA_DBI_fetch_result('SHOW GLOBAL STATUS', 0, 1), + PMA_DBI_fetch_result('SHOW GLOBAL VARIABLES', 0, 1) + ); + // Add total memory to variables as well + require_once('libraries/sysinfo.lib.php'); + $sysinfo = getSysInfo(); + $memory = $sysinfo->memory(); + $this->variables['system_memory'] = $memory['MemTotal']; + // Step 2: Read and parse the list of rules $this->parseResult = $this->parseRulesFile(); // Step 3: Feed the variables to the rules and let them fire. Sets $runResult $this->runRules();
- /* echo '<br/><hr>'; - echo 'Total rules: '.count($this->parseResult['rules']).' <br><br>'; - echo '<b>Possible performance issues</b><br/>'; - foreach($this->runResult['fired'] as $rule) { - echo $rule['issue'].'<br />'; - } - echo '<br/><b>Rules not checked due to unmet preconditions</b><br/>'; - foreach($this->runResult['unchecked'] as $rule) { - echo $rule['name'].'<br />'; - } - echo '<br/><b>Rules that didn't fire</b><br/>'; - foreach($this->runResult['notfired'] as $rule) { - echo $rule['name'].'<br />'; - } - - if($this->runResult['errors']) - echo 'There were errors while testing the rules.'; - */ - return $this->runResult; + return array('parse' => array('errors' => $this->parseResult['errors']), 'run' => $this->runResult); }
function runRules() { - $this->runResult = array( 'fired' => array(), 'notfired' => array(), 'unchecked'=> array(), 'errors' => array() ); + $this->runResult = array( + 'fired' => array(), + 'notfired' => array(), + 'unchecked'=> array(), + 'errors' => array() + );
foreach($this->parseResult['rules'] as $rule) { $this->variables['value'] = 0; @@ -78,6 +81,7 @@ class Advisor return true; }
+ // Adds a rule to the result list function addRule($type, $rule) { switch($type) { case 'notfired': @@ -86,7 +90,10 @@ class Advisor if(count($jst) > 1) { $jst[0] = preg_replace('/%( |,|.|$)/','%%\1',$jst[0]); try { - $str = $this->ruleExprEvaluate('sprintf("'.$jst[0].'",'.$jst[1].')',strlen('sprintf("'.$jst[0].'"')); + $str = $this->ruleExprEvaluate( + 'sprintf("'.$jst[0].'",'.$jst[1].')', + strlen('sprintf("'.$jst[0].'"') + ); } catch (Exception $e) { $this->runResult['errors'][] = 'Failed formattingstring for rule ''.$rule['name'].''. PHP threw following error: '.$e->getMessage(); return; @@ -94,6 +101,9 @@ class Advisor
$rule['justification'] = $str; } + + $rule['recommendation'] = preg_replace('/{([a-z_0-9]+)}/Ui','<a href="server_variables.php?'.$GLOBALS['url_query'].'#filter=\1">\1</a>',$rule['recommendation']); + break; }
@@ -121,7 +131,8 @@ class Advisor if($err) throw new Exception(strip_tags($err) . '<br />Executed code: $value = '.$expr.';'); return $value; } - + + // Reads the rule file into an array, throwing errors messages on syntax errors function parseRulesFile() { $file = file('libraries/advisory_rules.txt'); $errors = array(); @@ -138,9 +149,12 @@ class Advisor
// Reading new rule if(substr($line, 0, 4) == 'rule') { - if($ruleLine > 0) { $errors[] = 'Invalid rule declaration on line '.($i+1). ', expected line '.$ruleSyntax[$ruleLine++].' of previous rule' ; continue; } - $ruleLine = 1; + if($ruleLine > 0) { + $errors[] = 'Invalid rule declaration on line '.($i+1). ', expected line '.$ruleSyntax[$ruleLine++].' of previous rule' ; + continue; + } if(preg_match("/rule\s'(.*)'( [(.*)])?$/",$line,$match)) { + $ruleLine = 1; $j++; $rules[$j] = array( 'name' => $match[1]); if(isset($match[3])) $rules[$j]['precondition'] = $match[3]; diff --git a/libraries/advisory_rules.txt b/libraries/advisory_rules.txt index c193f85..dbfa6f0 100644 --- a/libraries/advisory_rules.txt +++ b/libraries/advisory_rules.txt @@ -1,6 +1,6 @@ # phpMyAdmin Advisory rules file # Use only UNIX style newlines -# This file is being parsed by advisor.lib.php, which should handle syntax errors correctly. +# This file is being parsed by advisor.class.php, which should handle syntax errors correctly. # However, PHP Warnings and the like are being consumed by the phpMyAdmin error handler, so those won't show up # E.g.: Justification line is empty because you used an unescape percent sign, sprintf() returns an empty string and no warning/error is shown # @@ -28,7 +28,6 @@ # Comments start with # #
- # Queries
rule 'Uptime below one day' @@ -77,23 +76,30 @@ rule 'Slow query logging' # versions rule 'Release Series' version - !PMA_DRIZZLE && substr(value,0,3) != "5.1" - The MySQL server version is less than 5.1. + !PMA_DRIZZLE && substr(value,0,1) <= 5 && substr(value,2,1) < 1 + The MySQL server version less then 5.1. You should upgrade, as MySQL 5.1 has improved performance, and MySQL 5.5 even more so. Current version: %s | value
-rule 'Minor Version' +rule 'Minor Version' [! fired('Release Series')] version - !PMA_DRIZZLE && substr(value,4,2) < 30 + substr(value,0,1) <= 5 && substr(value,2,1) < 1 && substr(value,4,2) < 30 Version less than 5.1.30 (the first GA release of 5.1). You should upgrade, as recent versions of MySQL 5.1 have improved performance and MySQL 5.5 even more so. Current version: %s | value
+rule 'Minor Version' [! fired('Release Series')] + version + substr(value,0,1) == 5 && substr(value,2,1) == 5 && substr(value,4,2) < 8 + Version less than 5.5.8 (the first GA release of 5.5). + You should upgrade, to a stable version of MySQL 5.5 + Current version: %s | value + rule 'Distribution' version_comment preg_match('/source/i',value) - Version is compiled from source, not a MySQL official binary. If you did not compile from source, you may be using a package modified by a distribution. - The MySQL manual only is accurate for official MySQL binaries, not any package distributions (such as RedHat, Debian/Ubuntu etc). + Version is compiled from source, not a MySQL official binary. + If you did not compile from source, you may be using a package modified by a distribution. The MySQL manual only is accurate for official MySQL binaries, not any package distributions (such as RedHat, Debian/Ubuntu etc). 'source' found in version_comment
rule 'Distribution' @@ -105,10 +111,10 @@ rule 'Distribution'
rule 'MySQL Architect ule 'Distribution' ay be using a package modified by a distribution. The MySQL manual only is accurate for official MySQL binaries, not any package distributions (such as RedHat, Debian/Ubuntu etc). queryProfiling"></div>'); ing"></div>'); � �! �! @,�Q� �,�Q� x4n�+ �"�Q� �bQ�+ ��Q�+ @,�Q� `bQ�+ ,�Q� �/��+ ujQ�+ ��+ �$��+ �)��+ ��R�+ x4n�+ �"�Q� p!�Q� k�Q�+ �! �! @,�Q� �,�Q� H�M�+ �#�Q� �bQ�+ ��Q�+ @,�Q� `bQ�+ ,�Q� p,�Q� h,�Q� 8�r�+ �p� �,�Q� ujQ�+ ��R�+ �#�Q� P"�Q� k�Q�+ G H I J K M N O P @,�Q� �,�Q� H�$�+ %�Q� �bQ�+ ��Q�+ @,�Q� 0/��+ ujQ�+ @n�+ ���+ ��+ �$��+ �)��+ ��R�+ H�$�+ %�Q� `#�Q� k�Q�+ 8�$�+ %�Q� �#�Q� k�Q�+ (�$�+ %�Q� �#�Q� k�Q�+ �$�+ %�Q� �#�Q� k�Q�+ �.��+ ujQ�+ �)��+ p�Q� �8�+ eiQ�+ �$��+ �$�Q� y8�+ eiQ�+ ��+ �$�Q� Z8�+ eiQ�+ ���+ @n�+ ���+ ��+ �Dn�+ �$��+ �)��+ ��R�+ 8�r�+ ���+ �,�Q� p{�+ p&�Q� @%�Q� k�Q�+ 5 6 7 8 : <