blob: 36da9ee2b79322fd7cca8af732652ea3704b8975 [file] [log] [blame]
epoger@google.comf9d134d2013-09-27 15:02:44 +00001<!DOCTYPE html>
2
epoger@google.com542b65f2013-10-15 20:10:33 +00003<html ng-app="Loader" ng-controller="Loader.Controller">
epoger@google.comf9d134d2013-09-27 15:02:44 +00004
5<head>
epoger@google.com542b65f2013-10-15 20:10:33 +00006 <title ng-bind="windowTitle"></title>
epoger@google.comf9d134d2013-09-27 15:02:44 +00007 <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.1.5/angular.js"></script>
8 <script src="loader.js"></script>
epoger@google.comeb832592013-10-23 15:07:26 +00009 <link rel="stylesheet" href="view.css">
epoger@google.comf9d134d2013-09-27 15:02:44 +000010</head>
11
12<body>
epoger@google.comdcb4e652013-10-11 18:45:33 +000013 <em>
14 {{loadingMessage}}
epoger@google.com5f2bb002013-10-02 18:57:48 +000015 </em>
epoger@google.comafaad3d2013-09-30 15:06:25 +000016
epoger@google.comeb832592013-10-23 15:07:26 +000017 <div ng-hide="!categories"><!-- everything: hide until data is loaded -->
18
epoger@google.comad0e5522013-10-24 15:38:27 +000019 <div class="warning-div"
20 ng-hide="!(header.isEditable && header.isExported)">
epoger@google.com9fb6c8a2013-10-09 18:05:58 +000021 WARNING! These results are editable and exported, so any user
22 who can connect to this server over the network can modify them.
23 </div>
epoger@google.comeb832592013-10-23 15:07:26 +000024
epoger@google.comad0e5522013-10-24 15:38:27 +000025 <div class="todo-div"><!-- TODOs -->
epoger@google.comeb832592013-10-23 15:07:26 +000026 <p>
27 TODO(epoger):
epoger@google.com055e3b52013-10-26 14:31:11 +000028 <input type="checkbox" ng-model="showTodos">
epoger@google.comeb832592013-10-23 15:07:26 +000029 show
30 <ul ng-hide="!showTodos">
31 <li>
32 If server was run with --reload flag, automatically check for
33 new results and tell the user when new results are available
34 (the user can reload the page if he wants to see them).
35 </li><li>
36 Add ability to filter builder and test names
37 (using a free-form text field, with partial string match)
38 </li><li>
epoger@google.com055e3b52013-10-26 14:31:11 +000039 Add pixel diffs, and sorting by percentage of different pixels
40 </li><li>
41 Add ability to sort/filter by reviewed-by-human. Depends on
42 <a href="https://code.google.com/p/skia/issues/detail?id=1758">
43 bug 1758
44 </a>
45 ('rebaseline_server: make the "categories" struct passed from server to client a list instead of a dict')
epoger@google.comeb832592013-10-23 15:07:26 +000046 </li><li>
47 Improve the column sorting, as per
48 <a href="http://jsfiddle.net/vojtajina/js64b/14/">
49 http://jsfiddle.net/vojtajina/js64b/14/
50 </a>
51 </li><li>
52 Right now, if you change which column is used to
53 sort the data, the column widths may fluctuate based on the
54 longest string <i>currently visible</i> within the top {{displayLimit}}
55 results. Can we fix the column widths to be wide enough to hold
56 any result, even the currently hidden results?
57 </li>
58 </ul>
59 </div><!-- TODOs -->
60
epoger@google.com542b65f2013-10-15 20:10:33 +000061 <div ng-hide="!(header.timeUpdated)">
62 Results current as of {{localTimeString(header.timeUpdated)}}
63 </div>
epoger@google.comeb832592013-10-23 15:07:26 +000064
epoger@google.comad0e5522013-10-24 15:38:27 +000065 <div><!-- tabs -->
66 <div class="tab-spacer" ng-repeat="tab in tabs">
epoger@google.comeb832592013-10-23 15:07:26 +000067 <div class="tab-{{tab == viewingTab}}"
epoger@google.comeb832592013-10-23 15:07:26 +000068 ng-click="setViewingTab(tab)">
69 &nbsp;{{tab}} ({{numResultsPerTab[tab]}})&nbsp;
70 </div>
epoger@google.comad0e5522013-10-24 15:38:27 +000071 <div class="tab-spacer">
epoger@google.comeb832592013-10-23 15:07:26 +000072 &nbsp;
73 </div>
74 </div>
75 </div><!-- tabs -->
76
epoger@google.comad0e5522013-10-24 15:38:27 +000077 <div class="tab-main"><!-- main display area of selected tab -->
epoger@google.comeb832592013-10-23 15:07:26 +000078
79 <br>
epoger@google.comad0e5522013-10-24 15:38:27 +000080 <!-- We only show the filters/settings table on the Unfiled tab. -->
epoger@google.comeb832592013-10-23 15:07:26 +000081 <table ng-hide="viewingTab != defaultTab" border="1">
epoger@google.com5f2bb002013-10-02 18:57:48 +000082 <tr>
83 <th colspan="2">
84 Filters
85 </th>
86 <th>
87 Settings
88 </th>
89 </tr>
90 <tr valign="top">
epoger@google.com055e3b52013-10-26 14:31:11 +000091 <!-- TODO(epoger): make this an ng-repeat over resultType, config, etc? -->
epoger@google.com5f2bb002013-10-02 18:57:48 +000092 <td>
93 resultType<br>
94 <label ng-repeat="(resultType, count) in categories['resultType']">
95 <input type="checkbox"
96 name="resultTypes"
97 value="{{resultType}}"
epoger@google.comad0e5522013-10-24 15:38:27 +000098 ng-checked="!isValueInSet(resultType, hiddenResultTypes)"
99 ng-click="toggleValueInSet(resultType, hiddenResultTypes); setUpdatesPending(true)">
epoger@google.com5f2bb002013-10-02 18:57:48 +0000100 {{resultType}} ({{count}})<br>
101 </label>
102 </td>
103 <td>
104 config<br>
105 <label ng-repeat="(config, count) in categories['config']">
106 <input type="checkbox"
107 name="configs"
108 value="{{config}}"
epoger@google.comad0e5522013-10-24 15:38:27 +0000109 ng-checked="!isValueInSet(config, hiddenConfigs)"
110 ng-click="toggleValueInSet(config, hiddenConfigs); setUpdatesPending(true)">
epoger@google.com5f2bb002013-10-02 18:57:48 +0000111 {{config}} ({{count}})<br>
112 </label>
113 </td>
114 <td><table>
115 <tr><td>
116 Image size
117 <input type="text" ng-model="imageSizePending"
118 ng-init="imageSizePending=100"
119 ng-change="areUpdatesPending = true"
120 maxlength="4"/>
121 </td></tr>
122 <tr><td>
123 Max records to display
124 <input type="text" ng-model="displayLimitPending"
125 ng-init="displayLimitPending=50"
126 ng-change="areUpdatesPending = true"
127 maxlength="4"/>
128 </td></tr>
129 <tr><td>
epoger@google.comad0e5522013-10-24 15:38:27 +0000130 <button class="update-results-button"
epoger@google.com5f2bb002013-10-02 18:57:48 +0000131 ng-click="updateResults()"
132 ng-disabled="!areUpdatesPending">
133 Update Results
134 </button>
135 </td></tr>
136 </tr></table></td>
137 </tr>
138 </table>
epoger@google.comf9d134d2013-09-27 15:02:44 +0000139
epoger@google.com5f2bb002013-10-02 18:57:48 +0000140 <p>
epoger@google.comeb832592013-10-23 15:07:26 +0000141
epoger@google.comad0e5522013-10-24 15:38:27 +0000142 <!-- Submission UI that we only show in the Pending Approval tab. -->
epoger@google.comeb832592013-10-23 15:07:26 +0000143 <div ng-hide="'Pending Approval' != viewingTab">
144 <div style="display:inline-block">
145 <button style="font-size:20px"
146 ng-click="submitApprovals(filteredTestData)"
147 ng-disabled="submitPending || (filteredTestData.length == 0)">
148 Update these {{filteredTestData.length}} expectations on the server
149 </button>
150 </div>
151 <div style="display:inline-block">
152 <div style="font-size:20px"
153 ng-hide="!submitPending">
154 Submitting, please wait...
155 </div>
156 </div>
epoger@google.com055e3b52013-10-26 14:31:11 +0000157 <div>
158 Advanced settings...
159 <input type="checkbox" ng-model="showSubmitAdvancedSettings">
160 show
161 <ul ng-hide="!showSubmitAdvancedSettings">
162 <li ng-repeat="setting in ['reviewed-by-human', 'ignore-failures']">
163 {{setting}}
164 <input type="checkbox" ng-model="submitAdvancedSettings[setting]">
165 </li>
166 <li ng-repeat="setting in ['bug']">
167 {{setting}}
168 <input type="text" ng-model="submitAdvancedSettings[setting]">
169 </li>
170 </ul>
171 </div>
epoger@google.comeb832592013-10-23 15:07:26 +0000172 </div>
173
174 <p>
175
176 <div>
177 <div style="float:left">
178 Found {{filteredTestData.length}} matches;
179 <span ng-hide="filteredTestData.length <= limitedTestData.length">
180 displaying the first {{limitedTestData.length}}
181 </span>
182 <span ng-hide="filteredTestData.length > limitedTestData.length">
183 displaying them all
184 </span>
185 <br>
186 (click on the column header radio buttons to re-sort by that column)
187 </div>
188 <div style="float:right">
epoger@google.com055e3b52013-10-26 14:31:11 +0000189 <div>
190 all tests shown:
191 <button ng-click="selectAllItems()">
192 select
193 </button>
194 <button ng-click="clearAllItems()">
195 clear
196 </button>
197 <button ng-click="toggleAllItems()">
198 toggle
199 </button>
200 </div>
epoger@google.comeb832592013-10-23 15:07:26 +0000201 <div ng-repeat="otherTab in tabs">
202 <button ng-click="moveSelectedItemsToTab(otherTab)"
203 ng-disabled="selectedItems.length == 0"
204 ng-hide="otherTab == viewingTab">
epoger@google.com055e3b52013-10-26 14:31:11 +0000205 move {{selectedItems.length}} selected tests to {{otherTab}} tab
epoger@google.comeb832592013-10-23 15:07:26 +0000206 </button>
207 </div>
208 </div>
209 <div style="clear:both">
210 </div>
211 </div>
epoger@google.com5f2bb002013-10-02 18:57:48 +0000212 <br>
epoger@google.comeb832592013-10-23 15:07:26 +0000213
epoger@google.comf9d134d2013-09-27 15:02:44 +0000214 <table border="1">
215 <tr>
epoger@google.comad0e5522013-10-24 15:38:27 +0000216 <!-- Most column headers are displayed in a common fashion... -->
epoger@google.com5f2bb002013-10-02 18:57:48 +0000217 <th ng-repeat="categoryName in ['resultType', 'builder', 'test', 'config']">
218 <input type="radio"
219 name="sortColumnRadio"
220 value="{{categoryName}}"
221 ng-checked="(sortColumn == categoryName)"
222 ng-click="sortResultsBy(categoryName)">
223 {{categoryName}}
224 </th>
epoger@google.comad0e5522013-10-24 15:38:27 +0000225 <!-- ... but there are a few columns where we display things differently. -->
epoger@google.com5f2bb002013-10-02 18:57:48 +0000226 <th>
227 <input type="radio"
228 name="sortColumnRadio"
epoger@google.com055e3b52013-10-26 14:31:11 +0000229 value="bugs"
230 ng-checked="(sortColumn == 'bugs')"
231 ng-click="sortResultsBy('bugs')">
232 bugs
233 </th>
234 <th>
235 <input type="radio"
236 name="sortColumnRadio"
epoger@google.com5f2bb002013-10-02 18:57:48 +0000237 value="expectedHashDigest"
238 ng-checked="(sortColumn == 'expectedHashDigest')"
239 ng-click="sortResultsBy('expectedHashDigest')">
240 expected image
241 </th>
242 <th>
243 <input type="radio"
244 name="sortColumnRadio"
245 value="actualHashDigest"
246 ng-checked="(sortColumn == 'actualHashDigest')"
247 ng-click="sortResultsBy('actualHashDigest')">
248 actual image
249 </th>
epoger@google.comeb832592013-10-23 15:07:26 +0000250 <th>
epoger@google.com9fb6c8a2013-10-09 18:05:58 +0000251 <!-- item-selection checkbox column -->
epoger@google.com9fb6c8a2013-10-09 18:05:58 +0000252 </th>
epoger@google.comf9d134d2013-09-27 15:02:44 +0000253 </tr>
epoger@google.com5f2bb002013-10-02 18:57:48 +0000254 <tr ng-repeat="result in limitedTestData">
epoger@google.com055e3b52013-10-26 14:31:11 +0000255 <td ng-repeat="categoryName in ['resultType', 'builder', 'test', 'config']">
256 {{result[categoryName]}}
257 </td>
258 <td>
259 <a ng-repeat="bug in result['bugs']"
260 href="https://code.google.com/p/skia/issues/detail?id={{bug}}"
261 target="_blank">
262 {{bug}}
263 </a>
264 </td>
epoger@google.comf9d134d2013-09-27 15:02:44 +0000265 <td>
epoger@google.comdcb4e652013-10-11 18:45:33 +0000266 <a target="_blank" href="http://chromium-skia-gm.commondatastorage.googleapis.com/gm/{{result.expectedHashType}}/{{result.test}}/{{result.expectedHashDigest}}.png">
epoger@google.comf9d134d2013-09-27 15:02:44 +0000267 <img width="{{imageSize}}" src="http://chromium-skia-gm.commondatastorage.googleapis.com/gm/{{result.expectedHashType}}/{{result.test}}/{{result.expectedHashDigest}}.png"/>
268 </a>
269 </td>
270 <td>
epoger@google.comdcb4e652013-10-11 18:45:33 +0000271 <a target="_blank" href="http://chromium-skia-gm.commondatastorage.googleapis.com/gm/{{result.actualHashType}}/{{result.test}}/{{result.actualHashDigest}}.png">
272 <img width="{{imageSize}}" src="http://chromium-skia-gm.commondatastorage.googleapis.com/gm/{{result.actualHashType}}/{{result.test}}/{{result.actualHashDigest}}.png"/>
epoger@google.comf9d134d2013-09-27 15:02:44 +0000273 </a>
274 </td>
epoger@google.comeb832592013-10-23 15:07:26 +0000275 <td>
epoger@google.com9fb6c8a2013-10-09 18:05:58 +0000276 <input type="checkbox"
277 name="rowSelect"
278 value="{{result.index}}"
epoger@google.comad0e5522013-10-24 15:38:27 +0000279 ng-checked="isValueInArray(result.index, selectedItems)"
280 ng-click="toggleValueInArray(result.index, selectedItems)">
epoger@google.comf9d134d2013-09-27 15:02:44 +0000281 </tr>
282 </table>
epoger@google.comad0e5522013-10-24 15:38:27 +0000283 </div><!-- main display area of selected tab -->
epoger@google.comeb832592013-10-23 15:07:26 +0000284 </div><!-- everything: hide until data is loaded -->
epoger@google.comf9d134d2013-09-27 15:02:44 +0000285
286 <!-- TODO(epoger): Can we get the base URLs (commondatastorage and
287 issues list) from
288 http://skia.googlecode.com/svn/buildbot/site_config/global_variables.json
289 ? I tried importing the
290 http://skia.googlecode.com/svn/buildbot/skia_tools.js script and using
291 that to do so, but I got Access-Control-Allow-Origin errors.
292 -->
293
294</body>
295</html>