Home | History | Annotate | Download | only in static
      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="loader.js"></script>
      9   <link rel="stylesheet" href="view.css">
     10 </head>
     11 
     12 <body>
     13   <h2>
     14     Instructions, roadmap, etc. are at
     15     <a href="http://tinyurl.com/SkiaRebaselineServer">
     16       http://tinyurl.com/SkiaRebaselineServer
     17     </a>
     18   </h2>
     19 
     20   <em>
     21     {{loadingMessage}}
     22   </em>
     23 
     24   <div ng-hide="!categories"><!-- everything: hide until data is loaded -->
     25 
     26     <div class="warning-div"
     27          ng-hide="!(header.isEditable && header.isExported)">
     28       WARNING!  These results are editable and exported, so any user
     29       who can connect to this server over the network can modify them.
     30     </div>
     31 
     32     <div ng-hide="!(header.timeUpdated)">
     33       Results current as of {{localTimeString(header.timeUpdated)}}
     34     </div>
     35 
     36     <div><!-- tabs -->
     37       <div class="tab-spacer" ng-repeat="tab in tabs">
     38         <div class="tab-{{tab == viewingTab}}"
     39              ng-click="setViewingTab(tab)">
     40           &nbsp;{{tab}} ({{numResultsPerTab[tab]}})&nbsp;
     41         </div>
     42         <div class="tab-spacer">
     43           &nbsp;
     44         </div>
     45       </div>
     46     </div><!-- tabs -->
     47 
     48     <div class="tab-main"><!-- main display area of selected tab -->
     49 
     50     <br>
     51     <!-- We only show the filters/settings table on the Unfiled tab. -->
     52     <table ng-hide="viewingTab != defaultTab" border="1">
     53     <tr>
     54       <th colspan="4">
     55         Filters
     56       </th>
     57       <th>
     58         Settings
     59       </th>
     60     </tr>
     61     <tr valign="top">
     62       <!-- TODO(epoger): make this an ng-repeat over resultType, config, etc? -->
     63       <td>
     64         resultType<br>
     65         <label ng-repeat="(resultType, count) in categories['resultType'] 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 ['builder', '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 categories['config'] 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           Image size
    118           <input type="text" ng-model="imageSizePending"
    119                  ng-init="imageSizePending=100"
    120                  ng-change="areUpdatesPending = true"
    121                  maxlength="4"/>
    122         </td></tr>
    123         <tr><td>
    124           Max records to display
    125           <input type="text" ng-model="displayLimitPending"
    126                  ng-init="displayLimitPending=50"
    127                  ng-change="areUpdatesPending = true"
    128                  maxlength="4"/>
    129         </td></tr>
    130         <tr><td>
    131           <button class="update-results-button"
    132                   ng-click="updateResults()"
    133                   ng-disabled="!areUpdatesPending">
    134             Update Results
    135           </button>
    136         </td></tr>
    137       </tr></table></td>
    138     </tr>
    139   </table>
    140 
    141       <p>
    142 
    143       <!-- Submission UI that we only show in the Pending Approval tab. -->
    144       <div ng-hide="'Pending Approval' != viewingTab">
    145         <div style="display:inline-block">
    146           <button style="font-size:20px"
    147                   ng-click="submitApprovals(filteredTestData)"
    148                   ng-disabled="submitPending || (filteredTestData.length == 0)">
    149             Update these {{filteredTestData.length}} expectations on the server
    150           </button>
    151         </div>
    152         <div style="display:inline-block">
    153           <div style="font-size:20px"
    154                ng-hide="!submitPending">
    155             Submitting, please wait...
    156           </div>
    157         </div>
    158         <div>
    159           Advanced settings...
    160           <input type="checkbox" ng-model="showSubmitAdvancedSettings">
    161           show
    162           <ul ng-hide="!showSubmitAdvancedSettings">
    163             <li ng-repeat="setting in ['reviewed-by-human', 'ignore-failure']">
    164               {{setting}}
    165               <input type="checkbox" ng-model="submitAdvancedSettings[setting]">
    166             </li>
    167             <li ng-repeat="setting in ['bug']">
    168               {{setting}}
    169               <input type="text" ng-model="submitAdvancedSettings[setting]">
    170             </li>
    171           </ul>
    172         </div>
    173       </div>
    174 
    175       <p>
    176 
    177     <table border="0"><tr><td> <!-- table holding results header + results table -->
    178       <table border="0" width="100%"> <!-- results header -->
    179         <tr>
    180           <td>
    181             Found {{filteredTestData.length}} matches;
    182             <span ng-hide="filteredTestData.length <= limitedTestData.length">
    183               displaying the first {{limitedTestData.length}}
    184             </span>
    185             <span ng-hide="filteredTestData.length > limitedTestData.length">
    186               displaying them all
    187             </span>
    188             <br>
    189             (click on the column header radio buttons to re-sort by that column)
    190           </td>
    191           <td align="right">
    192             <div>
    193               all tests shown:
    194               <button ng-click="selectAllItems()">
    195                 select
    196               </button>
    197               <button ng-click="clearAllItems()">
    198                 clear
    199               </button>
    200               <button ng-click="toggleAllItems()">
    201                 toggle
    202               </button>
    203             </div>
    204             <div ng-repeat="otherTab in tabs">
    205               <button ng-click="moveSelectedItemsToTab(otherTab)"
    206                       ng-disabled="selectedItems.length == 0"
    207                       ng-hide="otherTab == viewingTab">
    208                 move {{selectedItems.length}} selected tests to {{otherTab}} tab
    209               </button>
    210             </div>
    211           </td>
    212         </tr>
    213       </table> <!-- results header -->
    214       </td></tr><tr><td>
    215       <table border="1"> <!-- results -->
    216         <tr>
    217           <!-- Most column headers are displayed in a common fashion... -->
    218           <th ng-repeat="categoryName in ['resultType', 'builder', 'test', 'config']">
    219             <input type="radio"
    220                    name="sortColumnRadio"
    221                    value="{{categoryName}}"
    222                    ng-checked="(sortColumn == categoryName)"
    223                    ng-click="sortResultsBy(categoryName)">
    224             {{categoryName}}
    225           </th>
    226           <!-- ... but there are a few columns where we display things differently. -->
    227           <th>
    228             <input type="radio"
    229                    name="sortColumnRadio"
    230                    value="bugs"
    231                    ng-checked="(sortColumn == 'bugs')"
    232                    ng-click="sortResultsBy('bugs')">
    233             bugs
    234           </th>
    235           <th width="{{imageSize}}">
    236             <input type="radio"
    237                    name="sortColumnRadio"
    238                    value="expectedHashDigest"
    239                    ng-checked="(sortColumn == 'expectedHashDigest')"
    240                    ng-click="sortResultsBy('expectedHashDigest')">
    241             expected image
    242           </th>
    243           <th width="{{imageSize}}">
    244             <input type="radio"
    245                    name="sortColumnRadio"
    246                    value="actualHashDigest"
    247                    ng-checked="(sortColumn == 'actualHashDigest')"
    248                    ng-click="sortResultsBy('actualHashDigest')">
    249             actual image
    250           </th>
    251           <th width="{{imageSize}}">
    252             <input type="radio"
    253                    name="sortColumnRadio"
    254                    value="percentDifferingPixels"
    255                    ng-checked="(sortColumn == 'percentDifferingPixels')"
    256                    ng-click="sortResultsBy('percentDifferingPixels')">
    257             differing pixels in white
    258           </th>
    259           <th width="{{imageSize}}">
    260             <input type="radio"
    261                    name="sortColumnRadio"
    262                    value="weightedDiffMeasure"
    263                    ng-checked="(sortColumn == 'weightedDiffMeasure')"
    264                    ng-click="sortResultsBy('weightedDiffMeasure')">
    265             difference per pixel
    266           </th>
    267           <th>
    268             <!-- item-selection checkbox column -->
    269           </th>
    270         </tr>
    271 
    272         <!-- For most columns... if the user clicks on the cell, and we are on
    273              the default tab, update the filter to only show results with the
    274              same value for this category.
    275              This is made a bit tricky by the fact that AngularJS expressions
    276              do not allow control flow statements.  See
    277              http://docs.angularjs.org/guide/expression -->
    278         <tr ng-repeat="result in limitedTestData">
    279           <td ng-click="(viewingTab != defaultTab) || showOnlyResultType(result.resultType)">
    280             {{result.resultType}}
    281           </td>
    282           <td ng-repeat="categoryName in ['builder', 'test']"
    283               ng-click="(viewingTab != defaultTab) || setCategoryValueMatch(categoryName, result[categoryName])">
    284             {{result[categoryName]}}
    285           </td>
    286           <td ng-click="(viewingTab != defaultTab) || showOnlyConfig(result.config)">
    287             {{result.config}}
    288           </td>
    289           <td>
    290             <a ng-repeat="bug in result['bugs']"
    291                href="https://code.google.com/p/skia/issues/detail?id={{bug}}"
    292                target="_blank">
    293               {{bug}}
    294             </a>
    295           </td>
    296 
    297           <!-- expected image -->
    298           <td valign="top" width="{{imageSize}}">
    299             <a class="image-link" target="_blank" href="http://chromium-skia-gm.commondatastorage.googleapis.com/gm/{{result.expectedHashType}}/{{result.test}}/{{result.expectedHashDigest}}.png">
    300               <img width="{{imageSize}}" src="http://chromium-skia-gm.commondatastorage.googleapis.com/gm/{{result.expectedHashType}}/{{result.test}}/{{result.expectedHashDigest}}.png"/>
    301             </a>
    302           </td>
    303 
    304           <!-- actual image -->
    305           <td valign="top" width="{{imageSize}}">
    306             <a class="image-link" target="_blank" href="http://chromium-skia-gm.commondatastorage.googleapis.com/gm/{{result.actualHashType}}/{{result.test}}/{{result.actualHashDigest}}.png">
    307               <img width="{{imageSize}}" src="http://chromium-skia-gm.commondatastorage.googleapis.com/gm/{{result.actualHashType}}/{{result.test}}/{{result.actualHashDigest}}.png"/>
    308             </a>
    309           </td>
    310 
    311           <!-- whitediffs: every differing pixel shown in white -->
    312           <td valign="top" width="{{imageSize}}">
    313             <div ng-hide="result.expectedHashDigest == result.actualHashDigest"
    314                  title="{{result.numDifferingPixels | number:0}} of {{(100 * result.numDifferingPixels / result.percentDifferingPixels) | number:0}} pixels ({{result.percentDifferingPixels.toFixed(4)}}%) differ from expectation.">
    315               <a class="image-link" target="_blank" href="/static/generated-images/whitediffs/{{result.expectedHashDigest}}-vs-{{result.actualHashDigest}}.png">
    316                 <img width="{{imageSize}}" src="/static/generated-images/whitediffs/{{result.expectedHashDigest}}-vs-{{result.actualHashDigest}}.png"/>
    317               </a><br>
    318               {{result.percentDifferingPixels.toFixed(4)}}%
    319               ({{result.numDifferingPixels}})
    320             </div>
    321             <div ng-hide="result.expectedHashDigest != result.actualHashDigest"
    322                  style="text-align:center">
    323               &ndash;none&ndash;
    324             </div>
    325           </td>
    326 
    327           <!-- diffs: per-channel RGB deltas -->
    328           <td valign="top" width="{{imageSize}}">
    329             <div ng-hide="result.expectedHashDigest == result.actualHashDigest"
    330                  title="Weighted difference measure is {{result.weightedDiffMeasure.toFixed(4)}}%.  Maximum difference per channel: R={{result.maxDiffPerChannel[0]}}, G={{result.maxDiffPerChannel[1]}}, B={{result.maxDiffPerChannel[2]}}">
    331               <a class="image-link" target="_blank" href="/static/generated-images/diffs/{{result.expectedHashDigest}}-vs-{{result.actualHashDigest}}.png">
    332                 <img width="{{imageSize}}" src="/static/generated-images/diffs/{{result.expectedHashDigest}}-vs-{{result.actualHashDigest}}.png"/>
    333               </a><br>
    334               {{result.weightedDiffMeasure.toFixed(4)}}%
    335               {{result.maxDiffPerChannel}}
    336             </div>
    337             <div ng-hide="result.expectedHashDigest != result.actualHashDigest"
    338                  style="text-align:center">
    339               &ndash;none&ndash;
    340             </div>
    341           </td>
    342 
    343           <td>
    344             <input type="checkbox"
    345                    name="rowSelect"
    346                    value="{{result.index}}"
    347                    ng-checked="isValueInArray(result.index, selectedItems)"
    348                    ng-click="toggleValueInArray(result.index, selectedItems)">
    349         </tr>
    350       </table> <!-- results -->
    351     </td></tr></table> <!-- table holding results header + results table -->
    352 
    353   </div><!-- main display area of selected tab -->
    354   </div><!-- everything: hide until data is loaded -->
    355 
    356   <!-- TODO(epoger): Can we get the base URLs (commondatastorage and
    357        issues list) from
    358        http://skia.googlecode.com/svn/buildbot/site_config/global_variables.json
    359        ?  I tried importing the
    360        http://skia.googlecode.com/svn/buildbot/skia_tools.js script and using
    361        that to do so, but I got Access-Control-Allow-Origin errors.
    362     -->
    363 
    364 </body>
    365 </html>
    366