diff --git a/.eslintrc b/.eslintrc index 6d47e92..7122395 100644 --- a/.eslintrc +++ b/.eslintrc @@ -6,7 +6,7 @@ "parserOptions": { "ecmaVersion": 6 }, "rules": { "eqeqeq": "off", - "no-unused-vars": ["error", { "varsIgnorePattern": "update\\w*Data|updateHeader|TextTable|TreeNode|(?:clear|refresh|resize)FlameGraph|populateLocalizedStrings|formatTemplate|clearProfilingData|Top5|HttpSummary", + "no-unused-vars": ["error", { "varsIgnorePattern": "update\\w*Data|updateHeader|TextTable|TreeNode|(?:clear|refresh|resize)FlameGraph|populateLocalizedStrings|formatTemplate|clearProfilingData|Top5|HttpSummary|MysqlSummary", "argsIgnorePattern": "^_" }], "max-len": ["error", 120, 8, {"ignoreComments": true}], "comma-dangle": "off", diff --git a/css/style2.css b/css/style2.css index 54751b7..07893c0 100644 --- a/css/style2.css +++ b/css/style2.css @@ -477,3 +477,50 @@ transform: rotate(45deg); -webkit-transform: rotate(45deg); } + +/* HTTP SUMMARY STYLES */ +.mysqlSummaryContent table>tr { + display: list-item; + list-style-type: none; + border-bottom: 1px solid #dde4ee; +} + +.mysqlSummaryContent table>tr>td { + /*font-size: 14px;*/ + text-align: center; + vertical-align:top; + white-space: normal; + overflow: hidden; + font-size:80%; +} + +.mysqlSummaryContent table>tr>td:first-child { + text-align: left; + width: 83%; +} + +.mysqlSummaryContent table>tr>td:nth-child(2) { + width: 17%; +} + +.mysqlSummaryTableHeader { + cursor: pointer; + border-radius: 3px; + -webkit-touch-callout: none; /* iOS Safari */ + -webkit-user-select: none; /* Safari */ + -khtml-user-select: none; /* Konqueror HTML */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* Internet Explorer/Edge */ + user-select: none; /* Non-prefixed version, currently + supported by Chrome and Opera */ +} + +.mysqlSummaryTableHeader { + background-color: #dde4ee; + font-weight: bold; +} + +.mysqlSummaryContentDiv { + overflow-y: scroll; + padding: 7px 0px 0px 1px; +} diff --git a/index.html b/index.html index 06faba4..76a26ae 100644 --- a/index.html +++ b/index.html @@ -163,6 +163,7 @@ jQuery.loadScript('js/httpTop5.js'); jQuery.loadScript('js/httpOutboundRequestsChart.js'); jQuery.loadScript('js/httpSummary.js'); + jQuery.loadScript('js/mysqlSummary.js'); jQuery.loadScript('js/memChart.js'); jQuery.loadScript('js/gcChart.js'); diff --git a/js/mysqlSummary.js b/js/mysqlSummary.js new file mode 100644 index 0000000..375ab24 --- /dev/null +++ b/js/mysqlSummary.js @@ -0,0 +1,253 @@ +/******************************************************************************* +* Copyright 2017 IBM Corp. +* +* Licensed under the Apache License, Version 2.0 (the "License"); you may not +* use this file except in compliance with the License. You may obtain a copy of +* the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +* License for the specific language governing permissions and limitations under +* the License. +******************************************************************************/ + +// divName - the div where this should insert itself. +// parentName - the parent containing everything else on the page/tab +// that should be minimised when this is maximised. +// title - A string title for this text table. +function MysqlSummary(divName, parentName, title) { + let mysqlData = []; + let height = 250; + let minHeight = height; + + // Functions that don't need to be in the httpSummary object + function fillScreenHeight(minHeight) { + // Set height to the rest of the page + let body = document.getElementsByTagName('BODY')[0].offsetHeight; + let nav = document.getElementsByClassName('nav')[0].offsetHeight; + let header = document.getElementsByClassName('headerDiv')[0].offsetHeight; + let height = body - (nav + header) - 20; + if (height < minHeight) { + return minHeight; + } + return height; + } + + function calculateTableHeight() { + // TODO - This should probably be a parameter to the constructor + // or an argument to resizeTable(). + height = 250; + // If the div has class of 'height-2' (Double height div) change tableHeight + if ($(divName).hasClass('height-2')) { + // TODO - This should be dynamic, at the moment it isn't + // as other heights are not dynamic either + height = 510; + } else if ($(divName).hasClass('height-fill')) { + minHeight = 510; // Height of two divs - needs to be dynamic when above is + height = fillScreenHeight(minHeight); + } + return height; + } + + + const normalTableHeight = calculateTableHeight(); + let tableHeight = normalTableHeight; + + // -8 for margin and border, min 100 in case this is on a hidden tab. + let canvasWidth = Math.max($(divName).width() - 8, 100); + let graphWidth = canvasWidth - margin.left - margin.right; + let graphHeight = tableHeight - margin.top - margin.bottom; + + let mysqlSummarySVG = d3.select(divName) + .append('svg') + .attr('class', 'mysqlSummaryChart'); + + // Set titleBoxHeight here as we use it for the graph div below + let titleBoxHeight = 30; + let mysqlSummaryTitleBox = mysqlSummarySVG.append('rect') + .attr('height', titleBoxHeight) + .attr('class', 'titlebox'); + + let mysqlSummaryChart = mysqlSummarySVG.append('g') + .attr('transform', + 'translate(' + margin.left + ',' + margin.top + ')'); + + // Add the title + mysqlSummaryChart.append('text') + .attr('x', 7 - margin.left) + .attr('y', 15 - margin.top) + .attr('dominant-baseline', 'central') + .style('font-size', '18px') + .text(title); + + // Add the placeholder text + let mysqlSummaryChartPlaceholder = mysqlSummaryChart.append('text') + .attr('text-anchor', 'middle') + .style('font-size', '18px') + .text(localizedStrings.NoDataMsg); + + let mysqlSummaryIsFullScreen = false; + + // Add the maximise button + let summaryResize = mysqlSummarySVG.append('image') + .attr('width', 24) + .attr('height', 24) + .attr('xlink:href', 'graphmetrics/images/maximize_24_grey.png') + .attr('class', 'maximize') + .on('click', function(){ + mysqlSummaryIsFullScreen = !mysqlSummaryIsFullScreen; + d3.select(parentName).selectAll('.hideable').classed('invisible', mysqlSummaryIsFullScreen); + d3.select(divName) + .classed('fullscreen', mysqlSummaryIsFullScreen) + .classed('invisible', false); // remove invisible from this chart + if (mysqlSummaryIsFullScreen) { + summaryResize.attr('xlink:href', 'graphmetrics/images/minimize_24_grey.png'); + // Redraw this chart only + resizeTable(); + } else { + canvasWidth = $(divName).width() - 8; // -8 for margins and borders + graphWidth = canvasWidth - margin.left - margin.right; + summaryResize.attr('xlink:href', 'graphmetrics/images/maximize_24_grey.png'); + tableHeight = normalTableHeight; + $(divName).parent().attr('style', 'position: relative'); + graphHeight = tableHeight - margin.top - margin.bottom; + // Redraw all + resize(); + } + }) + .on('mouseover', function() { + if (mysqlSummaryIsFullScreen) { + summaryResize.attr('xlink:href', 'graphmetrics/images/minimize_24.png'); + } else { + summaryResize.attr('xlink:href', 'graphmetrics/images/maximize_24.png'); + } + }) + .on('mouseout', function() { + if (mysqlSummaryIsFullScreen) { + summaryResize.attr('xlink:href', 'graphmetrics/images/minimize_24_grey.png'); + } else { + summaryResize.attr('xlink:href', 'graphmetrics/images/maximize_24_grey.png'); + } + }); + + // Attempt to add foreign object to http summary for list + // summarydiv + let mysqlSummaryContent = mysqlSummarySVG.append('foreignObject') + .attr('width', graphWidth) + .attr('height', (tableHeight - titleBoxHeight)) + .attr('x', '0') + .attr('y', titleBoxHeight) + .attr('class', 'mysqlSummaryContent'); + + let mysqlSummaryDiv = mysqlSummaryContent + .append('xhtml:body') + .append('xhtml:div') + .attr('class', 'mysqlSummaryDiv'); + + let mysqlSummaryTableTitles = mysqlSummaryDiv.append('xhtml:div') + .attr('class', 'mysqlSummaryTableHeaderDiv') + .append('xhtml:table'); + + // Set titles for table + let mysqlSummaryTableTitlesRow = mysqlSummaryTableTitles.append('xhtml:tr'); + mysqlSummaryTableTitlesRow.append('xhtml:td').attr('class', 'mysqlSummaryTableHeader active') + .text('Query').attr('id', 'url'); + mysqlSummaryTableTitlesRow.append('xhtml:td').attr('class', 'mysqlSummaryTableHeader') + .text('Duration').attr('id', 'hits').append('xhtml:span'); + + let mysqlSummaryContentDivHeight = tableHeight - (40 + titleBoxHeight + $('.mysqlSummaryTableHeaderDiv').height()); + let mysqlSummaryContentDiv = mysqlSummaryDiv.append('xhtml:div') + .attr('class', 'mysqlSummaryContentDiv') + .attr('cellspacing', '0') + .attr('cellpadding', '0') + .attr('style', 'height: ' + mysqlSummaryContentDivHeight + 'px'); + + let mysqlSummaryContentTable = mysqlSummaryContentDiv.append('xhtml:table'); + + function updateChart() { + mysqlSummaryContentTable.html(''); + for (var i = mysqlData.length - 1; i >= 0; i--) { + let innerQuery = mysqlData[i].query; + if (innerQuery.indexOf('{"sql":"') === 0){ + innerQuery = JSON.parse(innerQuery); + innerQuery = innerQuery.sql; + } + let row = mysqlSummaryContentTable.append('xhtml:tr'); + row.append('xhtml:td').text(innerQuery).on('click', function(){ + alert(innerQuery); + }); + row.append('xhtml:td').text(Number(mysqlData[i].duration).toFixed(2)); + } + } + + function updateData(data) { + mysqlData = JSON.parse(data); + updateChart(); + } + + function resizeTable() { + if (mysqlSummaryIsFullScreen) { + // Make sure that the height doesn't change if its already full + if (!($(divName).hasClass('height-fill'))) { + tableHeight = $(divName).height() - 100; + if ($(divName).hasClass('height-2')) { + $(divName).parent().attr('style', 'position: absolute'); + } + } + } + if ($(divName).hasClass('height-fill')) { + tableHeight = fillScreenHeight(minHeight); + } + canvasWidth = Math.max($(divName).width() - 8, 100); + graphWidth = canvasWidth - margin.left - margin.right; + summaryResize + .attr('x', canvasWidth - 30) + .attr('y', 4); + mysqlSummaryChartPlaceholder + .attr('x', graphWidth / 2) + .attr('y', graphHeight / 2); + mysqlSummarySVG + .attr('width', canvasWidth) + .attr('height', tableHeight); + mysqlSummaryTitleBox + .attr('width', canvasWidth); + mysqlSummaryContent + .attr('width', canvasWidth) + .attr('height', (tableHeight - titleBoxHeight)); + mysqlSummaryContentDivHeight = tableHeight - (40 + titleBoxHeight + $('.mysqlSummaryTableHeaderDiv').height()); + mysqlSummaryContentDiv + .attr('style', 'height: ' + mysqlSummaryContentDivHeight + 'px'); + scrollBarCorrection(); + } + + // Correct the size of the table titles + // by adding padding-right to its div based + // on the width of the scroll bar on screen + function scrollBarCorrection() { + let outerWidth = $('.mysqlSummaryContentDiv:eq(0)').outerWidth(); + let innerWidth = $('.mysqlSummaryContentDiv:eq(0) table').outerWidth(); + let padding = outerWidth - innerWidth; + // Add padding to mysqlSummaryTableHeaderDiv + // mysqlSummaryContentDiv has a padding-left of 1 + if (padding > 1) { + $('.mysqlSummaryTableHeaderDiv').css('padding-right', padding + 'px'); + } else { + // If no scroll bar add 10px to the padding right + $('.mysqlSummaryDiv').css('padding-right', '10px'); + } + } + + // Resize at the end of setup. + resizeTable(); + updateChart(); + + + let exports = {}; + exports.resizeTable = resizeTable; + exports.updateData = updateData; + + return exports; +} diff --git a/locales/en.properties b/locales/en.properties index abacc08..f49a98d 100644 --- a/locales/en.properties +++ b/locales/en.properties @@ -35,4 +35,5 @@ flamegraphDetailsTotals=Self+Children {total_percent}% (Self: {current_percent}% # Summary page envTitle=Environment httpSummaryTitle=HTTP Requests +mysqlSummaryTitle=Mysql Queries summaryTitle=Resource Usage