| <%-- |
| ~ Copyright (c) 2016 Google Inc. All Rights Reserved. |
| ~ |
| ~ 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. |
| --%> |
| <%@ page contentType='text/html;charset=UTF-8' language='java' %> |
| <%@ taglib prefix='fn' uri='http://java.sun.com/jsp/jstl/functions' %> |
| <%@ taglib prefix='c' uri='http://java.sun.com/jsp/jstl/core'%> |
| |
| <html> |
| <%@ include file="header.jsp" %> |
| <link type='text/css' href='/css/show_table.css' rel='stylesheet'> |
| <link type='text/css' href='/css/show_test_runs_common.css' rel='stylesheet'> |
| <link type='text/css' href='/css/search_header.css' rel='stylesheet'> |
| <script type='text/javascript' src='https://www.gstatic.com/charts/loader.js'></script> |
| <script src='https://www.gstatic.com/external_hosted/moment/min/moment-with-locales.min.js'></script> |
| <script src='js/search_header.js'></script> |
| <script type='text/javascript'> |
| google.charts.load('current', {'packages':['table', 'corechart']}); |
| google.charts.setOnLoadCallback(drawGridTable); |
| google.charts.setOnLoadCallback(activateLogLinks); |
| google.charts.setOnLoadCallback(drawPieChart); |
| google.charts.setOnLoadCallback(function() { |
| $('.gradient').removeClass('gradient'); |
| }); |
| |
| var search; |
| |
| $(document).ready(function() { |
| search = $('#filter-bar').createSearchHeader('Module: ', '${testName}', refresh); |
| search.addFilter('Branch', 'branch', { |
| corpus: ${branches} |
| }, ${branch}); |
| search.addFilter('Device', 'device', { |
| corpus: ${devices} |
| }, ${device}); |
| search.addFilter('Device Build ID', 'deviceBuildId', {}, ${deviceBuildId}); |
| search.addFilter('Test Build ID', 'testBuildId', {}, ${testBuildId}); |
| search.addFilter('Host', 'hostname', {}, ${hostname}); |
| search.addFilter('Passing Count', 'passing', { |
| type: 'number', |
| width: 's2' |
| }, ${passing}); |
| search.addFilter('Non-Passing Count', 'nonpassing', { |
| type: 'number', |
| width: 's2' |
| }, ${nonpassing}); |
| search.addRunTypeCheckboxes(${showPresubmit}, ${showPostsubmit}); |
| search.display(); |
| |
| // disable buttons on load |
| if (!${hasNewer}) { |
| $('#newer-button').toggleClass('disabled'); |
| } |
| if (!${hasOlder}) { |
| $('#older-button').toggleClass('disabled'); |
| } |
| $('#treeLink').click(function() { |
| window.open('/show_tree?testName=${testName}', '_self'); |
| }); |
| $('#newer-button').click(prev); |
| $('#older-button').click(next); |
| }); |
| |
| // Actives the log links to display the log info modal when clicked. |
| function activateLogLinks() { |
| $('.info-btn').click(function(e) { |
| showLog(${logInfoMap}[$(this).data('col')]); |
| }); |
| } |
| |
| /** Displays a modal window with the specified log entries. |
| * |
| * @param logEntries Array of string arrays. Each entry in the outer array |
| * must contain (1) name string, and (2) url string. |
| */ |
| function showLog(logEntries) { |
| if (!logEntries || logEntries.length == 0) return; |
| |
| var logList = $('<ul class="collection"></ul>'); |
| var entries = logEntries.reduce(function(acc, entry) { |
| if (!entry || entry.length == 0) return acc; |
| var link = '<a href="' + entry[1] + '"'; |
| link += 'class="collection-item">' + entry[0] + '</li>'; |
| return acc + link; |
| }, ''); |
| logList.html(entries); |
| var infoContainer = $('#info-modal>.modal-content>.info-container'); |
| infoContainer.empty(); |
| logList.appendTo(infoContainer); |
| $('#info-modal').openModal(); |
| } |
| |
| // refresh the page to see the selected test types (pre-/post-submit) |
| function refresh() { |
| if($(this).hasClass('disabled')) return; |
| var link = '${pageContext.request.contextPath}' + |
| '/show_table?testName=${testName}' + search.args(); |
| if (${unfiltered}) { |
| link += '&unfiltered='; |
| } |
| window.open(link,'_self'); |
| } |
| |
| // view older data |
| function next() { |
| if($(this).hasClass('disabled')) return; |
| var endTime = ${startTime}; |
| var link = '${pageContext.request.contextPath}' + |
| '/show_table?testName=${testName}&endTime=' + endTime + |
| search.args(); |
| if (${unfiltered}) { |
| link += '&unfiltered='; |
| } |
| window.open(link,'_self'); |
| } |
| |
| // view newer data |
| function prev() { |
| if($(this).hasClass('disabled')) return; |
| var startTime = ${endTime}; |
| var link = '${pageContext.request.contextPath}' + |
| '/show_table?testName=${testName}&startTime=' + startTime + |
| search.args(); |
| if (${unfiltered}) { |
| link += '&unfiltered='; |
| } |
| window.open(link,'_self'); |
| } |
| |
| // to draw pie chart |
| function drawPieChart() { |
| var topBuildResultCounts = ${topBuildResultCounts}; |
| if (topBuildResultCounts.length < 1) { |
| return; |
| } |
| var resultNames = ${resultNamesJson}; |
| var rows = resultNames.map(function(res, i) { |
| nickname = res.replace('TEST_CASE_RESULT_', '').replace('_', ' ') |
| .trim().toLowerCase(); |
| return [nickname, parseInt(topBuildResultCounts[i])]; |
| }); |
| rows.unshift(['Result', 'Count']); |
| |
| // Get CSS color definitions (or default to white) |
| var colors = resultNames.map(function(res) { |
| return $('.' + res).css('background-color') || 'white'; |
| }); |
| |
| var data = google.visualization.arrayToDataTable(rows); |
| var options = { |
| is3D: false, |
| colors: colors, |
| fontName: 'Roboto', |
| fontSize: '14px', |
| legend: 'none', |
| tooltip: {showColorCode: true, ignoreBounds: true}, |
| chartArea: {height: '90%'} |
| }; |
| |
| var chart = new google.visualization.PieChart(document.getElementById('pie-chart-div')); |
| chart.draw(data, options); |
| } |
| |
| // table for grid data |
| function drawGridTable() { |
| var data = new google.visualization.DataTable(); |
| |
| // Add column headers. |
| headerRow = ${headerRow}; |
| headerRow.forEach(function(d, i) { |
| var classNames = 'table-header-content'; |
| if (i == 0) classNames += ' table-header-legend'; |
| data.addColumn('string', '<span class="' + classNames + '">' + |
| d + '</span>'); |
| }); |
| |
| var timeGrid = ${timeGrid}; |
| var durationGrid = ${durationGrid}; |
| var summaryGrid = ${summaryGrid}; |
| var resultsGrid = ${resultsGrid}; |
| |
| // Format time grid to a formatted date |
| timeGrid = timeGrid.map(function(row) { |
| return row.map(function(cell, j) { |
| if (j == 0) return cell; |
| var time = moment(cell/1000); |
| // If today, don't display the date |
| if (time.isSame(moment(), 'd')) { |
| return time.format('H:mm:ssZZ'); |
| } else { |
| return time.format('M/D/YY H:mm:ssZZ'); |
| } |
| }); |
| }); |
| |
| // Format duration grid to HH:mm:ss.SSS |
| durationGrid = durationGrid.map(function(row) { |
| return row.map(function(cell, j) { |
| if (j == 0) return cell; |
| return moment.utc(cell/1000).format("HH:mm:ss.SSS"); |
| }); |
| }); |
| |
| // add rows to the data. |
| data.addRows(timeGrid); |
| data.addRows(durationGrid); |
| data.addRows(summaryGrid); |
| data.addRows(resultsGrid); |
| |
| var table = new google.visualization.Table(document.getElementById('grid-table-div')); |
| var classNames = { |
| headerRow : 'table-header', |
| headerCell : 'table-header-cell' |
| }; |
| var options = { |
| showRowNumber: false, |
| alternatingRowStyle: true, |
| allowHtml: true, |
| frozenColumns: 1, |
| cssClassNames: classNames, |
| sort: 'disable' |
| }; |
| table.draw(data, options); |
| } |
| </script> |
| |
| <body> |
| <div class='wide container'> |
| <div class='row'> |
| <div class='col s12'> |
| <div class='card'> |
| <ul class='tabs'> |
| <li class='tab col s6'><a class='active'>Table</a></li> |
| <li class='tab col s6' id='treeLink'><a>Tree</a></li> |
| </ul> |
| </div> |
| <div id='filter-bar'></div> |
| </div> |
| <div class='col s7'> |
| <div class='col s12 card center-align'> |
| <div id='legend-wrapper'> |
| <c:forEach items='${resultNames}' var='res'> |
| <div class='center-align legend-entry'> |
| <c:set var='trimmed' value='${fn:replace(res, "TEST_CASE_RESULT_", "")}'/> |
| <c:set var='nickname' value='${fn:replace(trimmed, "_", " ")}'/> |
| <label for='${res}'>${nickname}</label> |
| <div id='${res}' class='${res} legend-bubble'></div> |
| </div> |
| </c:forEach> |
| </div> |
| </div> |
| <div id='profiling-container' class='col s12'> |
| <c:choose> |
| <c:when test='${empty profilingPointNames}'> |
| <div id='error-div' class='center-align card'><h5>${error}</h5></div> |
| </c:when> |
| <c:otherwise> |
| <ul id='profiling-body' class='collapsible' data-collapsible='accordion'> |
| <li> |
| <div class='collapsible-header'><i class='material-icons'>timeline</i>Profiling Graphs</div> |
| <div class='collapsible-body'> |
| <ul id='profiling-list' class='collection'> |
| <c:forEach items='${profilingPointNames}' var='pt'> |
| <c:set var='profPointArgs' value='testName=${testName}&profilingPoint=${pt}'/> |
| <c:set var='timeArgs' value='endTime=${endTime}'/> |
| <a href='/show_graph?${profPointArgs}&${timeArgs}' |
| class='collection-item profiling-point-name'>${pt} |
| </a> |
| </c:forEach> |
| </ul> |
| </div> |
| </li> |
| <li> |
| <a class='collapsible-link' href='/show_performance_digest?testName=${testName}'> |
| <div class='collapsible-header'><i class='material-icons'>toc</i>Performance Digest</div> |
| </a> |
| </li> |
| </ul> |
| </c:otherwise> |
| </c:choose> |
| </div> |
| </div> |
| <div class='col s5 valign-wrapper'> |
| <!-- pie chart --> |
| <div id='pie-chart-wrapper' class='col s12 valign center-align card'> |
| <h6 class='pie-chart-title'>Test Status for Device Build ID: ${topBuildId}</h6> |
| <div id='pie-chart-div'></div> |
| </div> |
| </div> |
| </div> |
| |
| <div class='col s12'> |
| <div id='chart-holder' class='col s12 card'> |
| <!-- Grid tables--> |
| <div id='grid-table-div'></div> |
| </div> |
| </div> |
| <div id='newer-wrapper' class='page-button-wrapper fixed-action-btn'> |
| <a id='newer-button' class='btn-floating btn red waves-effect'> |
| <i class='large material-icons'>keyboard_arrow_left</i> |
| </a> |
| </div> |
| <div id='older-wrapper' class='page-button-wrapper fixed-action-btn'> |
| <a id='older-button' class='btn-floating btn red waves-effect'> |
| <i class='large material-icons'>keyboard_arrow_right</i> |
| </a> |
| </div> |
| </div> |
| <div id="help-modal" class="modal"> |
| <div class="modal-content"> |
| <h4>${searchHelpHeader}</h4> |
| <p>${searchHelpBody}</p> |
| </div> |
| <div class="modal-footer"> |
| <a href="#!" class="modal-action modal-close waves-effect btn-flat">Close</a> |
| </div> |
| </div> |
| <div id="info-modal" class="modal"> |
| <div class="modal-content"> |
| <h4>Logs</h4> |
| <div class="info-container"></div> |
| </div> |
| <div class="modal-footer"> |
| <a href="#!" class="modal-action modal-close waves-effect btn-flat">Close</a> |
| </div> |
| </div> |
| <%@ include file="footer.jsp" %> |
| </body> |
| </html> |