1<%-- 2 ~ Copyright (c) 2016 Google Inc. All Rights Reserved. 3 ~ 4 ~ Licensed under the Apache License, Version 2.0 (the "License"); you 5 ~ may not use this file except in compliance with the License. You may 6 ~ obtain a copy of the License at 7 ~ 8 ~ http://www.apache.org/licenses/LICENSE-2.0 9 ~ 10 ~ Unless required by applicable law or agreed to in writing, software 11 ~ distributed under the License is distributed on an "AS IS" BASIS, 12 ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 13 ~ implied. See the License for the specific language governing 14 ~ permissions and limitations under the License. 15 --%> 16<%@ page contentType='text/html;charset=UTF-8' language='java' %> 17<%@ taglib prefix='fn' uri='http://java.sun.com/jsp/jstl/functions' %> 18<%@ taglib prefix='c' uri='http://java.sun.com/jsp/jstl/core'%> 19 20<html> 21 <%@ include file="header.jsp" %> 22 <link rel="stylesheet" href="/css/show_coverage.css"> 23 <script async defer src="https://apis.google.com/js/api.js" 24 onload="this.onload=function(){};handleClientLoad()" 25 onreadystatechange="if (this.readyState === 'complete') this.onload()"> 26 </script> 27 <body> 28 <script type="text/javascript"> 29 $(document).ready(function() { 30 // Initialize AJAX for CORS 31 $.ajaxSetup({ 32 xhrFields : { 33 withCredentials: true 34 } 35 }); 36 37 $('.collapsible.popout').collapsible({ 38 accordion : true 39 }).find('.collapsible-header').click(onClick); 40 41 42 $("div.collapsible-header > span.indicator.waves-effect").click(function(evt) { 43 evt.preventDefault(); 44 45 $("#loader-indicator").show(); 46 47 var cmd = $(evt.target).text(); 48 var testRunId = $(evt.target).data("id"); 49 var postData = { coverageId: testRunId, testName: "${testName}", testRunId: "${startTime}", cmd: cmd}; 50 $.post("/api/coverage/data", postData, function() { 51 // success 52 console.log("success"); 53 var detachedLi = $(evt.target).parent().parent().detach(); 54 if (cmd == "enable") { 55 $(evt.target).text("disable"); 56 $(evt.target).parent().removeClass("grey"); 57 $('ul.collapsible.popout').prepend(detachedLi); 58 } else { 59 $(evt.target).text("enable"); 60 $(evt.target).parent().addClass("grey"); 61 $('ul.collapsible.popout').append(detachedLi); 62 } 63 }) 64 .done(function() { 65 // Done 66 $("#loader-indicator").fadeOut("slow"); 67 }) 68 .fail(function() { 69 alert( "Error occurred during changing the status" ); 70 }); 71 }); 72 }); 73 74 function handleClientLoad() { 75 // Load the API client and auth2 library 76 gapi.load('client:auth2', initClient); 77 } 78 79 function initClient() { 80 gapi.client.init({ 81 client_id: ${clientId}, 82 scope: ${gerritScope} 83 }).then(function () { 84 // displayEntries(); 85 }); 86 } 87 88 /* Open a window to Gerrit so that user can login. 89 Minimize the previously clicked entry. 90 */ 91 var gerritLogin = function(element) { 92 window.open(${gerritURI}, "Ratting", "toolbar=0,status=0"); 93 element.click(); 94 } 95 96 /* Loads source code for a particular entry and displays it with 97 coverage information as the accordion entry expands. 98 */ 99 var onClick = function() { 100 // Remove source code from the accordion entry that was open before 101 var self = $(this); 102 var prev = self.parent().siblings('li.active'); 103 if (prev.length > 0) { 104 prev.find('.table-container').empty(); 105 } 106 var url = self.parent().data('url'); 107 var container = self.parent().find('.table-container'); 108 container.html('<div class="center-align">Loading...</div>'); 109 var coverageVectors = self.parent().data('coverage'); 110 if (self.parent().hasClass('active')) { 111 // Remove the code from display 112 container.empty(); 113 } else { 114 /* Fetch and display the code. 115 Note: a coverageVector may be shorter than sourceContents due 116 to non-executable (i.e. comments or language-specific syntax) 117 lines in the code. Trailing source lines that have no 118 coverage information are assumed to be non-executable. 119 */ 120 $.ajax({ 121 url: url, 122 dataType: 'text' 123 }).promise().done(function(src) { 124 src = atob(src); 125 if (!src) return; 126 srcLines = src.split('\n'); 127 covered = 0; 128 total = 0; 129 var table = $('<table class="table"></table>'); 130 var rows = srcLines.forEach(function(line, j) { 131 var count = coverageVectors[j]; 132 var row = $('<tr></tr>'); 133 if (typeof count == 'undefined' || count < 0) { 134 count = "--"; 135 } else if (count == 0) { 136 row.addClass('uncovered'); 137 total += 1; 138 } else { 139 row.addClass('covered'); 140 total += 1; 141 } 142 row.append('<td class="count">' + String(count) + '</td>'); 143 row.append('<td class="line_no">' + String(j+1) + '</td>'); 144 code = $('<td class="code"></td>'); 145 code.text(String(line)); 146 code.appendTo(row); 147 row.appendTo(table); 148 }); 149 container.empty(); 150 container.append(table); 151 }).fail(function(error) { 152 if (error.status == 0) { // origin error, refresh cookie 153 container.empty(); 154 container.html('<div class="center-align">' + 155 '<span class="login-button">' + 156 'Click to authorize Gerrit access' + 157 '</span></div>'); 158 container.find('.login-button').click(function() { 159 gerritLogin(self); 160 }); 161 } else { 162 container.html('<div class="center-align">' + 163 'Not found.</div>'); 164 } 165 }); 166 } 167 } 168 </script> 169 <div id='coverage-container' class='wide container'> 170 <h4 class="section-title"><b>Coverage:</b> </h4> 171 <ul class="collapsible popout" data-collapsible="accordion"> 172 <c:forEach var="coverageEntity" items="${coverageEntityList}" varStatus="loop"> 173 <li data-url="<c:url value="${coverageEntity.gerritUrl}"/>" data-index="${loop.index}" data-coverage="${coverageEntity.lineCoverage}"> 174 <div class="collapsible-header <c:out value='${coverageEntity.isIgnored ? "grey" : ""}'/>"> 175 <i class="material-icons">library_books</i> 176 <div class="truncate"><b>${coverageEntity.projectName}</b>/${coverageEntity.filePath}</div> 177 <div class="right total-count">${coverageEntity.coveredCount}/${coverageEntity.totalCount}</div> 178 <div class="indicator ${coverageEntity.percentage >= 70 ? "green" : "red"}">${coverageEntity.percentage}%</div> 179 <c:if test="${isModerator}"> 180 <span data-id="${coverageEntity.id}" class="indicator waves-effect blue lighten-1" style="margin-left: 5px;"><c:out value='${coverageEntity.isIgnored ? "enable" : "disable"}'/></span> 181 </c:if> 182 </div> 183 <div class="collapsible-body row"> 184 <div class="html-container"> 185 <div class="table-container"></div> 186 </div> 187 </div> 188 </li> 189 </c:forEach> 190 </ul> 191 </div> 192 193 <div id="loader-indicator" class="loader-background" style="display: none"> 194 <div class="preloader-wrapper big active"> 195 <div class="spinner-layer spinner-blue-only"> 196 <div class="circle-clipper left"> 197 <div class="circle"></div> 198 </div> 199 <div class="gap-patch"> 200 <div class="circle"></div> 201 </div> 202 <div class="circle-clipper right"> 203 <div class="circle"></div> 204 </div> 205 </div> 206 </div> 207 </div> 208 <%@ include file="footer.jsp" %> 209 </body> 210</html> 211