view.html revision 6e3ee3339c9f8869015085e470c6d5930b494411
1<!DOCTYPE html> 2 3<html ng-app="Loader" ng-controller="Loader.Controller"> 4 5<head> 6 <title ng-bind="windowTitle"></title> 7 <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.1.5/angular.js"></script> 8 <script src="constants.js"></script> 9 <script src="loader.js"></script> 10 <link rel="stylesheet" href="view.css"> 11</head> 12 13<body> 14 <h2> 15 Instructions, roadmap, etc. are at 16 <a href="http://tinyurl.com/SkiaRebaselineServer"> 17 http://tinyurl.com/SkiaRebaselineServer 18 </a> 19 </h2> 20 21 <em> 22 {{loadingMessage}} 23 </em> 24 25 <div ng-show="extraColumnHeaders"><!-- everything: hide until data is loaded --> 26 27 <div class="warning-div" 28 ng-show="header[constants.KEY__HEADER__IS_EDITABLE] && header[constants.KEY__HEADER__IS_EXPORTED]"> 29 WARNING! These results are editable and exported, so any user 30 who can connect to this server over the network can modify them. 31 </div> 32 33 <div ng-show="header[constants.KEY__HEADER__TIME_UPDATED]"> 34 Results current as of {{localTimeString(header[constants.KEY__HEADER__TIME_UPDATED])}} 35 </div> 36 37 <div><!-- tabs --> 38 <div class="tab-spacer" ng-repeat="tab in tabs"> 39 <div class="tab-{{tab == viewingTab}}" 40 ng-click="setViewingTab(tab)"> 41 {{tab}} ({{numResultsPerTab[tab]}}) 42 </div> 43 <div class="tab-spacer"> 44 45 </div> 46 </div> 47 </div><!-- tabs --> 48 49 <div class="tab-main"><!-- main display area of selected tab --> 50 51 <br> 52 <!-- We only show the filters/settings table on the Unfiled tab. --> 53 <table ng-show="viewingTab == defaultTab" border="1"> 54 <tr> 55 <th colspan="4"> 56 Filters 57 </th> 58 <th> 59 Settings 60 </th> 61 </tr> 62 <tr valign="top"> 63 <td> 64 resultType<br> 65 <label ng-repeat="(resultType, count) in extraColumnHeaders[constants.KEY__EXTRACOLUMN__RESULT_TYPE][constants.KEY__VALUES_AND_COUNTS] track by $index"> 66 <input type="checkbox" 67 name="resultTypes" 68 value="{{resultType}}" 69 ng-checked="!isValueInSet(resultType, hiddenResultTypes)" 70 ng-click="toggleValueInSet(resultType, hiddenResultTypes); setUpdatesPending(true)"> 71 {{resultType}} ({{count}})<br> 72 </label> 73 <button ng-click="hiddenResultTypes = {}; updateResults()"> 74 all 75 </button> 76 <button ng-click="hiddenResultTypes = {}; toggleValuesInSet(allResultTypes, hiddenResultTypes); updateResults()"> 77 none 78 </button> 79 <button ng-click="toggleValuesInSet(allResultTypes, hiddenResultTypes); updateResults()"> 80 toggle 81 </button> 82 </td> 83 <td ng-repeat="category in [constants.KEY__EXTRACOLUMN__BUILDER, constants.KEY__EXTRACOLUMN__TEST]"> 84 {{category}} 85 <br> 86 <input type="text" 87 ng-model="categoryValueMatch[category]" 88 ng-change="setUpdatesPending(true)"/> 89 <br> 90 <button ng-click="setCategoryValueMatch(category, '')" 91 ng-disabled="('' == categoryValueMatch[category])"> 92 clear (show all) 93 </button> 94 </td> 95 <td> 96 config<br> 97 <label ng-repeat="(config, count) in extraColumnHeaders[constants.KEY__EXTRACOLUMN__CONFIG][constants.KEY__VALUES_AND_COUNTS] track by $index"> 98 <input type="checkbox" 99 name="configs" 100 value="{{config}}" 101 ng-checked="!isValueInSet(config, hiddenConfigs)" 102 ng-click="toggleValueInSet(config, hiddenConfigs); setUpdatesPending(true)"> 103 {{config}} ({{count}})<br> 104 </label> 105 <button ng-click="hiddenConfigs = {}; updateResults()"> 106 all 107 </button> 108 <button ng-click="hiddenConfigs = {}; toggleValuesInSet(allConfigs, hiddenConfigs); updateResults()"> 109 none 110 </button> 111 <button ng-click="toggleValuesInSet(allConfigs, hiddenConfigs); updateResults()"> 112 toggle 113 </button> 114 </td> 115 <td><table> 116 <tr><td> 117 <input type="checkbox" ng-model="showThumbnailsPending" 118 ng-init="showThumbnailsPending = true" 119 ng-change="areUpdatesPending = true"/> 120 Show thumbnails 121 </td></tr> 122 <tr><td> 123 Image width 124 <input type="text" ng-model="imageSizePending" 125 ng-init="imageSizePending=100" 126 ng-change="areUpdatesPending = true" 127 maxlength="4"/> 128 </td></tr> 129 <tr><td> 130 Max records to display 131 <input type="text" ng-model="displayLimitPending" 132 ng-init="displayLimitPending=50" 133 ng-change="areUpdatesPending = true" 134 maxlength="4"/> 135 </td></tr> 136 <tr><td> 137 <button class="update-results-button" 138 ng-click="updateResults()" 139 ng-disabled="!areUpdatesPending"> 140 Update Results 141 </button> 142 </td></tr> 143 </tr></table></td> 144 </tr> 145 </table> 146 147 <p> 148 149 <!-- Submission UI that we only show in the Pending Approval tab. --> 150 <div ng-show="'Pending Approval' == viewingTab"> 151 <div style="display:inline-block"> 152 <button style="font-size:20px" 153 ng-click="submitApprovals(filteredImagePairs)" 154 ng-disabled="submitPending || (filteredImagePairs.length == 0)"> 155 Update these {{filteredImagePairs.length}} expectations on the server 156 </button> 157 </div> 158 <div style="display:inline-block"> 159 <div style="font-size:20px" 160 ng-show="submitPending"> 161 Submitting, please wait... 162 </div> 163 </div> 164 <div> 165 Advanced settings... 166 <input type="checkbox" ng-model="showSubmitAdvancedSettings"> 167 show 168 <ul ng-show="showSubmitAdvancedSettings"> 169 <li ng-repeat="setting in [constants.KEY__EXPECTATIONS__REVIEWED, constants.KEY__EXPECTATIONS__IGNOREFAILURE]"> 170 {{setting}} 171 <input type="checkbox" ng-model="submitAdvancedSettings[setting]"> 172 </li> 173 <li ng-repeat="setting in ['bug']"> 174 {{setting}} 175 <input type="text" ng-model="submitAdvancedSettings[setting]"> 176 </li> 177 </ul> 178 </div> 179 </div> 180 181 <p> 182 183 <table border="0"><tr><td> <!-- table holding results header + results table --> 184 <table border="0" width="100%"> <!-- results header --> 185 <tr> 186 <td> 187 Found {{filteredImagePairs.length}} matches; 188 <span ng-show="filteredImagePairs.length > limitedImagePairs.length"> 189 displaying the first {{limitedImagePairs.length}}. 190 </span> 191 <span ng-show="filteredImagePairs.length <= limitedImagePairs.length"> 192 displaying them all. 193 </span> 194 <span ng-show="renderEndTime > renderStartTime"> 195 Rendered in {{(renderEndTime - renderStartTime).toFixed(0)}} ms. 196 </span> 197 <br> 198 (click on the column header radio buttons to re-sort by that column) 199 </td> 200 <td align="right"> 201 <div> 202 all tests shown: 203 <button ng-click="selectAllImagePairs()"> 204 select 205 </button> 206 <button ng-click="clearAllImagePairs()"> 207 clear 208 </button> 209 <button ng-click="toggleAllImagePairs()"> 210 toggle 211 </button> 212 </div> 213 <div ng-repeat="otherTab in tabs"> 214 <button ng-click="moveSelectedImagePairsToTab(otherTab)" 215 ng-disabled="selectedImagePairs.length == 0" 216 ng-show="otherTab != viewingTab"> 217 move {{selectedImagePairs.length}} selected tests to {{otherTab}} tab 218 </button> 219 </div> 220 </td> 221 </tr> 222 </table> <!-- results header --> 223 </td></tr><tr><td> 224 <table border="1" ng-app="diff_viewer"> <!-- results --> 225 <tr> 226 <!-- Most column headers are displayed in a common fashion... --> 227 <th ng-repeat="categoryName in [constants.KEY__EXTRACOLUMN__RESULT_TYPE, constants.KEY__EXTRACOLUMN__BUILDER, constants.KEY__EXTRACOLUMN__TEST, constants.KEY__EXTRACOLUMN__CONFIG]"> 228 <input type="radio" 229 name="sortColumnRadio" 230 value="{{categoryName}}" 231 ng-checked="(sortColumnKey == categoryName)" 232 ng-click="sortResultsBy(constants.KEY__EXTRA_COLUMN_VALUES, categoryName)"> 233 {{categoryName}} 234 </th> 235 <!-- ... but there are a few columns where we display things differently. --> 236 <th> 237 <input type="radio" 238 name="sortColumnRadio" 239 value="bugs" 240 ng-checked="(sortColumnKey == constants.KEY__EXPECTATIONS__BUGS)" 241 ng-click="sortResultsBy(constants.KEY__EXPECTATIONS_DATA, constants.KEY__EXPECTATIONS__BUGS)"> 242 bugs 243 </th> 244 <th width="{{imageSize}}"> 245 {{imageSets[0][constants.KEY__IMAGESETS__DESCRIPTION]}} 246 </th> 247 <th width="{{imageSize}}"> 248 {{imageSets[1][constants.KEY__IMAGESETS__DESCRIPTION]}} 249 </th> 250 <th width="{{imageSize}}"> 251 <input type="radio" 252 name="sortColumnRadio" 253 value="percentDifferingPixels" 254 ng-checked="(sortColumnKey == constants.KEY__DIFFERENCE_DATA__PERCENT_DIFF_PIXELS)" 255 ng-click="sortResultsBy(constants.KEY__DIFFERENCE_DATA, constants.KEY__DIFFERENCE_DATA__PERCENT_DIFF_PIXELS)"> 256 differing pixels in white 257 </th> 258 <th width="{{imageSize}}"> 259 <input type="radio" 260 name="sortColumnRadio" 261 value="weightedDiffMeasure" 262 ng-checked="(sortColumnKey == constants.KEY__DIFFERENCE_DATA__WEIGHTED_DIFF)" 263 ng-click="sortResultsBy(constants.KEY__DIFFERENCE_DATA, constants.KEY__DIFFERENCE_DATA__WEIGHTED_DIFF)"> 264 perceptual difference 265 <br> 266 <input type="range" ng-model="pixelDiffBgColorBrightness" 267 ng-init="pixelDiffBgColorBrightness=64; pixelDiffBgColor=brightnessStringToHexColor(pixelDiffBgColorBrightness)" 268 ng-change="pixelDiffBgColor=brightnessStringToHexColor(pixelDiffBgColorBrightness)" 269 title="image background brightness" 270 min="0" max="255"/> 271 </th> 272 <th> 273 <!-- imagepair-selection checkbox column --> 274 </th> 275 </tr> 276 277 <tr ng-repeat="imagePair in limitedImagePairs" results-updated-callback-directive> 278 <td> 279 {{imagePair[constants.KEY__EXTRA_COLUMN_VALUES][constants.KEY__EXTRACOLUMN__RESULT_TYPE]}} 280 <br> 281 <button class="show-only-button" 282 ng-show="viewingTab == defaultTab" 283 ng-click="showOnlyResultType(imagePair[constants.KEY__EXTRA_COLUMN_VALUES][constants.KEY__EXTRACOLUMN__RESULT_TYPE])" 284 title="show only results of type {{imagePair[constants.KEY__EXTRA_COLUMN_VALUES][constants.KEY__EXTRACOLUMN__RESULT_TYPE]}}"> 285 show only 286 </button> 287 <br> 288 <button class="show-all-button" 289 ng-show="viewingTab == defaultTab" 290 ng-disabled="0 == setSize(hiddenResultTypes)" 291 ng-click="showAllResultTypes()" 292 title="show results of all types"> 293 show all 294 </button> 295 </td> 296 <td ng-repeat="categoryName in [constants.KEY__EXTRACOLUMN__BUILDER, constants.KEY__EXTRACOLUMN__TEST]"> 297 {{imagePair[constants.KEY__EXTRA_COLUMN_VALUES][categoryName]}} 298 <br> 299 <button class="show-only-button" 300 ng-show="viewingTab == defaultTab" 301 ng-disabled="imagePair[constants.KEY__EXTRA_COLUMN_VALUES][categoryName] == categoryValueMatch[categoryName]" 302 ng-click="setCategoryValueMatch(categoryName, imagePair[constants.KEY__EXTRA_COLUMN_VALUES][categoryName])" 303 title="show only results of {{categoryName}} {{imagePair[constants.KEY__EXTRA_COLUMN_VALUES][categoryName]}}"> 304 show only 305 </button> 306 <br> 307 <button class="show-all-button" 308 ng-show="viewingTab == defaultTab" 309 ng-disabled="'' == categoryValueMatch[categoryName]" 310 ng-click="setCategoryValueMatch(categoryName, '')" 311 title="show results of all {{categoryName}}s"> 312 show all 313 </button> 314 </td> 315 <td> 316 {{imagePair[constants.KEY__EXTRA_COLUMN_VALUES][constants.KEY__EXTRACOLUMN__CONFIG]}} 317 <br> 318 <button class="show-only-button" 319 ng-show="viewingTab == defaultTab" 320 ng-click="showOnlyConfig(imagePair[constants.KEY__EXTRA_COLUMN_VALUES][constants.KEY__EXTRACOLUMN__CONFIG])" 321 title="show only results of config {{imagePair[constants.KEY__EXTRA_COLUMN_VALUES][constants.KEY__EXTRACOLUMN__CONFIG]}}"> 322 show only 323 </button> 324 <br> 325 <button class="show-all-button" 326 ng-show="viewingTab == defaultTab" 327 ng-disabled="0 == setSize(hiddenConfigs)" 328 ng-click="showAllConfigs()" 329 title="show results of all configs"> 330 show all 331 </button> 332 </td> 333 <td> 334 <a ng-repeat="bug in imagePair[constants.KEY__EXPECTATIONS_DATA][constants.KEY__EXPECTATIONS__BUGS]" 335 href="https://code.google.com/p/skia/issues/detail?id={{bug}}" 336 target="_blank"> 337 {{bug}} 338 </a> 339 </td> 340 341 <!-- image A --> 342 <td valign="bottom" width="{{imageSize}}"> 343 <div ng-if="imagePair[constants.KEY__IMAGE_A_URL] != null"> 344 <a href="{{imageSets[0][constants.KEY__IMAGESETS__BASE_URL]}}/{{imagePair[constants.KEY__IMAGE_A_URL]}}" target="_blank">View Image</a><br/> 345 <img ng-if="showThumbnails" 346 width="{{imageSize}}" 347 src="{{imageSets[0][constants.KEY__IMAGESETS__BASE_URL]}}/{{imagePair[constants.KEY__IMAGE_A_URL]}}" /> 348 </div> 349 <div ng-show="imagePair[constants.KEY__IMAGE_A_URL] == null" 350 style="text-align:center"> 351 –none– 352 </div> 353 </td> 354 355 <!-- image B --> 356 <td valign="bottom" width="{{imageSize}}"> 357 <div ng-if="imagePair[constants.KEY__IMAGE_B_URL] != null"> 358 <a href="{{imageSets[1][constants.KEY__IMAGESETS__BASE_URL]}}/{{imagePair[constants.KEY__IMAGE_B_URL]}}" target="_blank">View Image</a><br/> 359 <img ng-if="showThumbnails" 360 width="{{imageSize}}" 361 src="{{imageSets[1][constants.KEY__IMAGESETS__BASE_URL]}}/{{imagePair[constants.KEY__IMAGE_B_URL]}}" /> 362 </div> 363 <div ng-show="imagePair[constants.KEY__IMAGE_B_URL] == null" 364 style="text-align:center"> 365 –none– 366 </div> 367 </td> 368 369 <!-- whitediffs: every differing pixel shown in white --> 370 <td valign="bottom" width="{{imageSize}}"> 371 <div ng-if="imagePair[constants.KEY__IS_DIFFERENT]" 372 title="{{imagePair[constants.KEY__DIFFERENCE_DATA][constants.KEY__DIFFERENCE_DATA__NUM_DIFF_PIXELS] | number:0}} of {{(100 * imagePair[constants.KEY__DIFFERENCE_DATA][constants.KEY__DIFFERENCE_DATA__NUM_DIFF_PIXELS] / imagePair[constants.KEY__DIFFERENCE_DATA][constants.KEY__DIFFERENCE_DATA__PERCENT_DIFF_PIXELS]) | number:0}} pixels ({{imagePair[constants.KEY__DIFFERENCE_DATA][constants.KEY__DIFFERENCE_DATA__PERCENT_DIFF_PIXELS].toFixed(4)}}%) differ from expectation."> 373 374 {{imagePair[constants.KEY__DIFFERENCE_DATA][constants.KEY__DIFFERENCE_DATA__PERCENT_DIFF_PIXELS].toFixed(4)}}% 375 ({{imagePair[constants.KEY__DIFFERENCE_DATA][constants.KEY__DIFFERENCE_DATA__NUM_DIFF_PIXELS]}}) 376 <br/> 377 <a href="/static/generated-images/whitediffs/{{getImageDiffRelativeUrl(imagePair)}}" target="_blank">View Image</a><br/> 378 <img ng-if="showThumbnails" 379 width="{{imageSize}}" 380 src="/static/generated-images/whitediffs/{{getImageDiffRelativeUrl(imagePair)}}" /> 381 </div> 382 <div ng-show="!imagePair[constants.KEY__IS_DIFFERENT]" 383 style="text-align:center"> 384 –none– 385 </div> 386 </td> 387 388 <!-- diffs: per-channel RGB deltas --> 389 <td valign="bottom" width="{{imageSize}}"> 390 <div ng-if="imagePair[constants.KEY__IS_DIFFERENT]" 391 title="Perceptual difference measure is {{imagePair[constants.KEY__DIFFERENCE_DATA][constants.KEY__DIFFERENCE_DATA__PERCEPTUAL_DIFF].toFixed(4)}}%. Maximum difference per channel: R={{imagePair[constants.KEY__DIFFERENCE_DATA][constants.KEY__DIFFERENCE_DATA__MAX_DIFF_PER_CHANNEL][0]}}, G={{imagePair[constants.KEY__DIFFERENCE_DATA][constants.KEY__DIFFERENCE_DATA__MAX_DIFF_PER_CHANNEL][1]}}, B={{imagePair[constants.KEY__DIFFERENCE_DATA][constants.KEY__DIFFERENCE_DATA__MAX_DIFF_PER_CHANNEL][2]}}"> 392 393 {{imagePair[constants.KEY__DIFFERENCE_DATA][constants.KEY__DIFFERENCE_DATA__PERCEPTUAL_DIFF].toFixed(4)}}% 394 {{imagePair[constants.KEY__DIFFERENCE_DATA][constants.KEY__DIFFERENCE_DATA__MAX_DIFF_PER_CHANNEL]}} 395 <br/> 396 <a href="/static/generated-images/diffs/{{getImageDiffRelativeUrl(imagePair)}}" target="_blank">View Image</a><br/> 397 <img ng-if="showThumbnails" 398 ng-style="{backgroundColor: pixelDiffBgColor}" 399 width="{{imageSize}}" 400 src="/static/generated-images/diffs/{{getImageDiffRelativeUrl(imagePair)}}"/> 401 </div> 402 <div ng-show="!imagePair[constants.KEY__IS_DIFFERENT]" 403 style="text-align:center"> 404 –none– 405 </div> 406 </td> 407 408 <td> 409 <input type="checkbox" 410 name="rowSelect" 411 value="{{imagePair.index}}" 412 ng-checked="isValueInArray(imagePair.index, selectedImagePairs)" 413 ng-click="toggleValueInArray(imagePair.index, selectedImagePairs)"> 414 </tr> 415 </table> <!-- imagePairs --> 416 </td></tr></table> <!-- table holding results header + imagePairs table --> 417 418 </div><!-- main display area of selected tab --> 419 </div><!-- everything: hide until data is loaded --> 420 421</body> 422</html> 423