blob: 9ce3fae140e7c8e8107c6a6da46534e44798be3c [file] [log] [blame]
<!DOCTYPE html>
<html ng-app="Loader" ng-controller="Loader.Controller">
<head>
<title ng-bind="windowTitle"></title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.1.5/angular.js"></script>
<script src="loader.js"></script>
<script src="diff_viewer.js"></script>
<link rel="stylesheet" href="view.css">
</head>
<body>
<h2>
Instructions, roadmap, etc. are at
<a href="http://tinyurl.com/SkiaRebaselineServer">
http://tinyurl.com/SkiaRebaselineServer
</a>
</h2>
<em>
{{loadingMessage}}
</em>
<div ng-hide="!categories"><!-- everything: hide until data is loaded -->
<div class="warning-div"
ng-hide="!(header.isEditable && header.isExported)">
WARNING! These results are editable and exported, so any user
who can connect to this server over the network can modify them.
</div>
<div ng-hide="!(header.timeUpdated)">
Results current as of {{localTimeString(header.timeUpdated)}}
</div>
<div><!-- tabs -->
<div class="tab-spacer" ng-repeat="tab in tabs">
<div class="tab-{{tab == viewingTab}}"
ng-click="setViewingTab(tab)">
&nbsp;{{tab}} ({{numResultsPerTab[tab]}})&nbsp;
</div>
<div class="tab-spacer">
&nbsp;
</div>
</div>
</div><!-- tabs -->
<div class="tab-main"><!-- main display area of selected tab -->
<br>
<!-- We only show the filters/settings table on the Unfiled tab. -->
<table ng-hide="viewingTab != defaultTab" border="1">
<tr>
<th colspan="4">
Filters
</th>
<th>
Settings
</th>
</tr>
<tr valign="top">
<!-- TODO(epoger): make this an ng-repeat over resultType, config, etc? -->
<td>
resultType<br>
<label ng-repeat="(resultType, count) in categories['resultType'] track by $index">
<input type="checkbox"
name="resultTypes"
value="{{resultType}}"
ng-checked="!isValueInSet(resultType, hiddenResultTypes)"
ng-click="toggleValueInSet(resultType, hiddenResultTypes); setUpdatesPending(true)">
{{resultType}} ({{count}})<br>
</label>
<button ng-click="hiddenResultTypes = {}; updateResults()">
all
</button>
<button ng-click="hiddenResultTypes = {}; toggleValuesInSet(allResultTypes, hiddenResultTypes); updateResults()">
none
</button>
<button ng-click="toggleValuesInSet(allResultTypes, hiddenResultTypes); updateResults()">
toggle
</button>
</td>
<td ng-repeat="category in ['builder', 'test']">
{{category}}
<br>
<input type="text"
ng-model="categoryValueMatch[category]"
ng-change="setUpdatesPending(true)"/>
<br>
<button ng-click="setCategoryValueMatch(category, '')"
ng-disabled="('' == categoryValueMatch[category])">
clear (show all)
</button>
</td>
<td>
config<br>
<label ng-repeat="(config, count) in categories['config'] track by $index">
<input type="checkbox"
name="configs"
value="{{config}}"
ng-checked="!isValueInSet(config, hiddenConfigs)"
ng-click="toggleValueInSet(config, hiddenConfigs); setUpdatesPending(true)">
{{config}} ({{count}})<br>
</label>
<button ng-click="hiddenConfigs = {}; updateResults()">
all
</button>
<button ng-click="hiddenConfigs = {}; toggleValuesInSet(allConfigs, hiddenConfigs); updateResults()">
none
</button>
<button ng-click="toggleValuesInSet(allConfigs, hiddenConfigs); updateResults()">
toggle
</button>
</td>
<td><table>
<tr><td>
Image width
<input type="text" ng-model="imageSizePending"
ng-init="imageSizePending=100"
ng-change="areUpdatesPending = true"
maxlength="4"/>
</td></tr>
<tr><td>
Max records to display
<input type="text" ng-model="displayLimitPending"
ng-init="displayLimitPending=50"
ng-change="areUpdatesPending = true"
maxlength="4"/>
</td></tr>
<tr><td>
<button class="update-results-button"
ng-click="updateResults()"
ng-disabled="!areUpdatesPending">
Update Results
</button>
</td></tr>
</tr></table></td>
</tr>
</table>
<p>
<!-- Submission UI that we only show in the Pending Approval tab. -->
<div ng-hide="'Pending Approval' != viewingTab">
<div style="display:inline-block">
<button style="font-size:20px"
ng-click="submitApprovals(filteredTestData)"
ng-disabled="submitPending || (filteredTestData.length == 0)">
Update these {{filteredTestData.length}} expectations on the server
</button>
</div>
<div style="display:inline-block">
<div style="font-size:20px"
ng-hide="!submitPending">
Submitting, please wait...
</div>
</div>
<div>
Advanced settings...
<input type="checkbox" ng-model="showSubmitAdvancedSettings">
show
<ul ng-hide="!showSubmitAdvancedSettings">
<li ng-repeat="setting in ['reviewed-by-human', 'ignore-failure']">
{{setting}}
<input type="checkbox" ng-model="submitAdvancedSettings[setting]">
</li>
<li ng-repeat="setting in ['bug']">
{{setting}}
<input type="text" ng-model="submitAdvancedSettings[setting]">
</li>
</ul>
</div>
</div>
<p>
<table border="0"><tr><td> <!-- table holding results header + results table -->
<table border="0" width="100%"> <!-- results header -->
<tr>
<td>
Found {{filteredTestData.length}} matches;
<span ng-hide="filteredTestData.length <= limitedTestData.length">
displaying the first {{limitedTestData.length}}
</span>
<span ng-hide="filteredTestData.length > limitedTestData.length">
displaying them all
</span>
<br>
(click on the column header radio buttons to re-sort by that column)
</td>
<td align="right">
<div>
all tests shown:
<button ng-click="selectAllItems()">
select
</button>
<button ng-click="clearAllItems()">
clear
</button>
<button ng-click="toggleAllItems()">
toggle
</button>
</div>
<div ng-repeat="otherTab in tabs">
<button ng-click="moveSelectedItemsToTab(otherTab)"
ng-disabled="selectedItems.length == 0"
ng-hide="otherTab == viewingTab">
move {{selectedItems.length}} selected tests to {{otherTab}} tab
</button>
</div>
</td>
</tr>
</table> <!-- results header -->
</td></tr><tr><td>
<table border="1" ng-app="diff_viewer"> <!-- results -->
<tr>
<!-- Most column headers are displayed in a common fashion... -->
<th ng-repeat="categoryName in ['resultType', 'builder', 'test', 'config']">
<input type="radio"
name="sortColumnRadio"
value="{{categoryName}}"
ng-checked="(sortColumn == categoryName)"
ng-click="sortResultsBy(categoryName)">
{{categoryName}}
</th>
<!-- ... but there are a few columns where we display things differently. -->
<th>
<input type="radio"
name="sortColumnRadio"
value="bugs"
ng-checked="(sortColumn == 'bugs')"
ng-click="sortResultsBy('bugs')">
bugs
</th>
<th width="{{imageSize}}">
<input type="radio"
name="sortColumnRadio"
value="expectedHashDigest"
ng-checked="(sortColumn == 'expectedHashDigest')"
ng-click="sortResultsBy('expectedHashDigest')">
expected image
</th>
<th width="{{imageSize}}">
<input type="radio"
name="sortColumnRadio"
value="actualHashDigest"
ng-checked="(sortColumn == 'actualHashDigest')"
ng-click="sortResultsBy('actualHashDigest')">
actual image
</th>
<th width="{{imageSize}}">
<input type="radio"
name="sortColumnRadio"
value="percentDifferingPixels"
ng-checked="(sortColumn == 'percentDifferingPixels')"
ng-click="sortResultsBy('percentDifferingPixels')">
differing pixels in white
</th>
<th width="{{imageSize}}">
<input type="radio"
name="sortColumnRadio"
value="weightedDiffMeasure"
ng-checked="(sortColumn == 'weightedDiffMeasure')"
ng-click="sortResultsBy('weightedDiffMeasure')">
perceptual difference
<br>
<input type="range" ng-model="pixelDiffBgColorBrightness"
ng-init="pixelDiffBgColorBrightness=64; pixelDiffBgColor=brightnessStringToHexColor(pixelDiffBgColorBrightness)"
ng-change="pixelDiffBgColor=brightnessStringToHexColor(pixelDiffBgColorBrightness)"
title="image background brightness"
min="0" max="255"/>
</th>
<th>
<!-- item-selection checkbox column -->
</th>
</tr>
<tr ng-repeat="result in limitedTestData" ng-controller="ImageController">
<td>
{{result.resultType}}
<br>
<button class="show-only-button"
ng-hide="viewingTab != defaultTab"
ng-click="showOnlyResultType(result.resultType)"
title="show only results of type '{{result.resultType}}'">
show only
</button>
<br>
<button class="show-all-button"
ng-hide="viewingTab != defaultTab"
ng-disabled="0 == setSize(hiddenResultTypes)"
ng-click="showAllResultTypes()"
title="show results of all types">
show all
</button>
</td>
<td ng-repeat="categoryName in ['builder', 'test']">
{{result[categoryName]}}
<br>
<button class="show-only-button"
ng-hide="viewingTab != defaultTab"
ng-disabled="result[categoryName] == categoryValueMatch[categoryName]"
ng-click="setCategoryValueMatch(categoryName, result[categoryName])"
title="show only results of {{categoryName}} '{{result[categoryName]}}'">
show only
</button>
<br>
<button class="show-all-button"
ng-hide="viewingTab != defaultTab"
ng-disabled="'' == categoryValueMatch[categoryName]"
ng-click="setCategoryValueMatch(categoryName, '')"
title="show results of all {{categoryName}}s">
show all
</button>
</td>
<td>
{{result.config}}
<br>
<button class="show-only-button"
ng-hide="viewingTab != defaultTab"
ng-click="showOnlyConfig(result.config)"
title="show only results of config '{{result.config}}'">
show only
</button>
<br>
<button class="show-all-button"
ng-hide="viewingTab != defaultTab"
ng-disabled="0 == setSize(hiddenConfigs)"
ng-click="showAllConfigs()"
title="show results of all configs">
show all
</button>
</td>
<td>
<a ng-repeat="bug in result['bugs']"
href="https://code.google.com/p/skia/issues/detail?id={{bug}}"
target="_blank">
{{bug}}
</a>
</td>
<!-- expected image -->
<td valign="bottom" width="{{imageSize}}">
<a href="http://chromium-skia-gm.commondatastorage.googleapis.com/gm/{{result.expectedHashType}}/{{result.test}}/{{result.expectedHashDigest}}.png" target="_blank">View Image</a><br/>
<img-compare type="baseline" width="{{imageSize}}"
src="http://chromium-skia-gm.commondatastorage.googleapis.com/gm/{{result.expectedHashType}}/{{result.test}}/{{result.expectedHashDigest}}.png" />
</td>
<!-- actual image -->
<td valign="bottom" width="{{imageSize}}">
<a href="http://chromium-skia-gm.commondatastorage.googleapis.com/gm/{{result.actualHashType}}/{{result.test}}/{{result.actualHashDigest}}.png" target="_blank">View Image</a><br/>
<img-compare type="test" width="{{imageSize}}"
src="http://chromium-skia-gm.commondatastorage.googleapis.com/gm/{{result.actualHashType}}/{{result.test}}/{{result.actualHashDigest}}.png" />
</td>
<!-- whitediffs: every differing pixel shown in white -->
<td valign="bottom" width="{{imageSize}}">
<div ng-hide="result.expectedHashDigest == result.actualHashDigest"
title="{{result.numDifferingPixels | number:0}} of {{(100 * result.numDifferingPixels / result.percentDifferingPixels) | number:0}} pixels ({{result.percentDifferingPixels.toFixed(4)}}%) differ from expectation.">
{{result.percentDifferingPixels.toFixed(4)}}%
({{result.numDifferingPixels}})
<br/>
<a href="/static/generated-images/whitediffs/{{result.expectedHashDigest}}-vs-{{result.actualHashDigest}}.png" target="_blank">View Image</a><br/>
<img-compare type="differingPixelsInWhite" width="{{imageSize}}"
src="/static/generated-images/whitediffs/{{result.expectedHashDigest}}-vs-{{result.actualHashDigest}}.png" />
</div>
<div ng-hide="result.expectedHashDigest != result.actualHashDigest"
style="text-align:center">
&ndash;none&ndash;
</div>
</td>
<!-- diffs: per-channel RGB deltas -->
<td valign="bottom" width="{{imageSize}}">
<div ng-hide="result.expectedHashDigest == result.actualHashDigest"
title="Perceptual difference measure is {{result.perceptualDifference.toFixed(4)}}%. Maximum difference per channel: R={{result.maxDiffPerChannel[0]}}, G={{result.maxDiffPerChannel[1]}}, B={{result.maxDiffPerChannel[2]}}">
{{result.perceptualDifference.toFixed(4)}}%
{{result.maxDiffPerChannel}}
<br/>
<a href="/static/generated-images/diffs/{{result.expectedHashDigest}}-vs-{{result.actualHashDigest}}.png" target="_blank">View Image</a><br/>
<img-compare ng-style="{backgroundColor: pixelDiffBgColor}"
type="differencePerPixel" width="{{imageSize}}"
src="/static/generated-images/diffs/{{result.expectedHashDigest}}-vs-{{result.actualHashDigest}}.png"
ng-mousedown="MagnifyDraw($event, true)"
ng-mousemove="MagnifyDraw($event, false)"
ng-mouseup="MagnifyEnd($event)"
ng-mouseleave="MagnifyEnd($event)" />
</div>
<div ng-hide="result.expectedHashDigest != result.actualHashDigest"
style="text-align:center">
&ndash;none&ndash;
</div>
</td>
<td>
<input type="checkbox"
name="rowSelect"
value="{{result.index}}"
ng-checked="isValueInArray(result.index, selectedItems)"
ng-click="toggleValueInArray(result.index, selectedItems)">
</tr>
</table> <!-- results -->
</td></tr></table> <!-- table holding results header + results table -->
</div><!-- main display area of selected tab -->
</div><!-- everything: hide until data is loaded -->
<!-- TODO(epoger): Can we get the base URLs (commondatastorage and
issues list) from
https://skia.googlesource.com/buildbot/+/master/site_config/global_variables.json ?
I tried importing the
http://skia.googlecode.com/svn/buildbot/skia_tools.js script and using
that to do so, but I got Access-Control-Allow-Origin errors.
-->
</body>
</html>