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          &nbsp;{{tab}} ({{numResultsPerTab[tab]}})&nbsp;
42        </div>
43        <div class="tab-spacer">
44          &nbsp;
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              &ndash;none&ndash;
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              &ndash;none&ndash;
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              &ndash;none&ndash;
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              &ndash;none&ndash;
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