diff options
author | 2013-10-23 15:07:26 +0000 | |
---|---|---|
committer | 2013-10-23 15:07:26 +0000 | |
commit | eb832599b631a09b180ea3615347adba6bd5e363 (patch) | |
tree | e4cba2c9055d0da638db1d1a2751c39fb783e832 /gm/rebaseline_server/static | |
parent | 1f81fd6546c111e21bc665657e976b9d842192df (diff) |
rebaseline_server: add tabs, and ability to submit new baselines to the server
Tabs allow the user to divide the tests into groups:
hide these for now, approve these, etc.
(SkipBuildbotRuns)
R=borenet@google.com
Review URL: https://codereview.chromium.org/28903008
git-svn-id: http://skia.googlecode.com/svn/trunk@11915 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'gm/rebaseline_server/static')
-rw-r--r-- | gm/rebaseline_server/static/loader.js | 160 | ||||
-rw-r--r-- | gm/rebaseline_server/static/view.css | 6 | ||||
-rw-r--r-- | gm/rebaseline_server/static/view.html | 148 |
3 files changed, 251 insertions, 63 deletions
diff --git a/gm/rebaseline_server/static/loader.js b/gm/rebaseline_server/static/loader.js index 80f84c6a3a..09b66d5546 100644 --- a/gm/rebaseline_server/static/loader.js +++ b/gm/rebaseline_server/static/loader.js @@ -15,12 +15,14 @@ var Loader = angular.module( Loader.filter( 'removeHiddenItems', function() { - return function(unfilteredItems, hiddenResultTypes, hiddenConfigs) { + return function(unfilteredItems, hiddenResultTypes, hiddenConfigs, + viewingTab) { var filteredItems = []; for (var i = 0; i < unfilteredItems.length; i++) { var item = unfilteredItems[i]; if (!(true == hiddenResultTypes[item.resultType]) && - !(true == hiddenConfigs[item.config])) { + !(true == hiddenConfigs[item.config]) && + (viewingTab == item.tab)) { filteredItems.push(item); } } @@ -45,10 +47,31 @@ Loader.controller( $scope.categories = data.categories; $scope.testData = data.testData; $scope.sortColumn = 'test'; - $scope.showTodos = true; + $scope.showTodos = false; + // Create the list of tabs (lists into which the user can file each + // test). This may vary, depending on isEditable. + $scope.tabs = [ + 'Unfiled', 'Hidden' + ]; + if (data.header.isEditable) { + $scope.tabs = $scope.tabs.concat( + ['Pending Approval']); + } + $scope.defaultTab = $scope.tabs[0]; + $scope.viewingTab = $scope.defaultTab; + + // Track the number of results on each tab. + $scope.numResultsPerTab = {}; + for (var i = 0; i < $scope.tabs.length; i++) { + $scope.numResultsPerTab[$scope.tabs[i]] = 0; + } + $scope.numResultsPerTab[$scope.defaultTab] = $scope.testData.length; + + // Add index and tab fields to all records. for (var i = 0; i < $scope.testData.length; i++) { $scope.testData[i].index = i; + $scope.testData[i].tab = $scope.defaultTab; } $scope.hiddenResultTypes = { @@ -57,7 +80,7 @@ Loader.controller( 'succeeded': true, }; $scope.hiddenConfigs = {}; - $scope.selectedItems = {}; + $scope.selectedItems = []; $scope.updateResults(); $scope.loadingMessage = ""; @@ -72,13 +95,14 @@ Loader.controller( ); $scope.isItemSelected = function(index) { - return (true == $scope.selectedItems[index]); + return (-1 != $scope.selectedItems.indexOf(index)); } $scope.toggleItemSelected = function(index) { - if (true == $scope.selectedItems[index]) { - delete $scope.selectedItems[index]; + var i = $scope.selectedItems.indexOf(index); + if (-1 == i) { + $scope.selectedItems.push(index); } else { - $scope.selectedItems[index] = true; + $scope.selectedItems.splice(i, 1); } // unlike other toggle methods below, does not set // $scope.areUpdatesPending = true; @@ -113,27 +137,77 @@ Loader.controller( $scope.areUpdatesPending = true; } + $scope.setViewingTab = function(tab) { + $scope.viewingTab = tab; + $scope.updateResults(); + } + $scope.localTimeString = function(secondsPastEpoch) { var d = new Date(secondsPastEpoch * 1000); return d.toString(); } + /** + * Move the items in $scope.selectedItems to a different tab, + * and then clear $scope.selectedItems. + * + * @param newTab (string): name of the tab to move the tests to + */ + $scope.moveSelectedItemsToTab = function(newTab) { + $scope.moveItemsToTab($scope.selectedItems, newTab); + $scope.selectedItems = []; + $scope.updateResults(); + } + + /** + * Move a subset of $scope.testData to a different tab. + * + * @param itemIndices (array of ints): indices into $scope.testData + * indicating which test results to move + * @param newTab (string): name of the tab to move the tests to + */ + $scope.moveItemsToTab = function(itemIndices, newTab) { + var itemIndex; + var numItems = itemIndices.length; + for (var i = 0; i < numItems; i++) { + itemIndex = itemIndices[i]; + $scope.numResultsPerTab[$scope.testData[itemIndex].tab]--; + $scope.testData[itemIndex].tab = newTab; + } + $scope.numResultsPerTab[newTab] += numItems; + } + $scope.updateResults = function() { $scope.displayLimit = $scope.displayLimitPending; // TODO(epoger): Every time we apply a filter, AngularJS creates // another copy of the array. Is there a way we can filter out // the items as they are displayed, rather than storing multiple // array copies? (For better performance.) - $scope.filteredTestData = - $filter("orderBy")( - $filter("removeHiddenItems")( - $scope.testData, - $scope.hiddenResultTypes, - $scope.hiddenConfigs - ), - $scope.sortColumn); - $scope.limitedTestData = $filter("limitTo")( - $scope.filteredTestData, $scope.displayLimit); + + if ($scope.viewingTab == $scope.defaultTab) { + $scope.filteredTestData = + $filter("orderBy")( + $filter("removeHiddenItems")( + $scope.testData, + $scope.hiddenResultTypes, + $scope.hiddenConfigs, + $scope.viewingTab + ), + $scope.sortColumn); + $scope.limitedTestData = $filter("limitTo")( + $scope.filteredTestData, $scope.displayLimit); + } else { + $scope.filteredTestData = + $filter("orderBy")( + $filter("filter")( + $scope.testData, + {tab: $scope.viewingTab}, + true + ), + $scope.sortColumn); + $scope.limitedTestData = $filter("limitTo")( + $scope.filteredTestData, $scope.displayLimit); + } $scope.imageSize = $scope.imageSizePending; $scope.areUpdatesPending = false; } @@ -142,5 +216,55 @@ Loader.controller( $scope.sortColumn = sortColumn; $scope.updateResults(); } + + /** + * Tell the server that the actual results of these particular tests + * are acceptable. + * + * @param testDataSubset an array of test results, most likely a subset of + * $scope.testData (perhaps with some modifications) + */ + $scope.submitApprovals = function(testDataSubset) { + $scope.submitPending = true; + var newResults = []; + for (var i = 0; i < testDataSubset.length; i++) { + var actualResult = testDataSubset[i]; + var expectedResult = { + builder: actualResult['builder'], + test: actualResult['test'], + config: actualResult['config'], + expectedHashType: actualResult['actualHashType'], + expectedHashDigest: actualResult['actualHashDigest'], + }; + newResults.push(expectedResult); + } + $http({ + method: "POST", + url: "/edits", + data: { + oldResultsType: $scope.header.type, + oldResultsHash: $scope.header.dataHash, + modifications: newResults + } + }).success(function(data, status, headers, config) { + var itemIndicesToMove = []; + for (var i = 0; i < testDataSubset.length; i++) { + itemIndicesToMove.push(testDataSubset[i].index); + } + $scope.moveItemsToTab(itemIndicesToMove, + "HackToMakeSureThisItemDisappears"); + $scope.updateResults(); + alert("New baselines submitted successfully!\n\n" + + "You still need to commit the updated expectations files on " + + "the server side to the Skia repo.\n\n" + + "Also: in order to see the complete updated data, or to submit " + + "more baselines, you will need to reload your client."); + $scope.submitPending = false; + }).error(function(data, status, headers, config) { + alert("There was an error submitting your baselines.\n\n" + + "Please see server-side log for details."); + $scope.submitPending = false; + }); + } } ); diff --git a/gm/rebaseline_server/static/view.css b/gm/rebaseline_server/static/view.css new file mode 100644 index 0000000000..e4eeb0f5a3 --- /dev/null +++ b/gm/rebaseline_server/static/view.css @@ -0,0 +1,6 @@ +.tab-true { + background-color: #ccccff; +} +.tab-false { + background-color: #8888ff; +} diff --git a/gm/rebaseline_server/static/view.html b/gm/rebaseline_server/static/view.html index 9f0158d579..9bb01fc0c5 100644 --- a/gm/rebaseline_server/static/view.html +++ b/gm/rebaseline_server/static/view.html @@ -6,6 +6,7 @@ <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> + <link rel="stylesheet" href="view.css"> </head> <body> @@ -13,16 +14,69 @@ {{loadingMessage}} </em> - <div ng-hide="!categories"> + <div ng-hide="!categories"><!-- everything: hide until data is loaded --> + <div ng-hide="!(header.isEditable && header.isExported)" style="background-color:#ffbb00"> WARNING! These results are editable and exported, so any user who can connect to this server over the network can modify them. </div> + + <div style="background-color:#bbffbb"><!-- TODOs --> + <p> + TODO(epoger): + <input type="checkbox" name="showTodosCheckbox" value="true" + ng-checked="showTodos == true" + ng-click="showTodos = !showTodos"> + show + <ul ng-hide="!showTodos"> + <li> + If server was run with --reload flag, automatically check for + new results and tell the user when new results are available + (the user can reload the page if he wants to see them). + </li><li> + Add ability to filter builder and test names + (using a free-form text field, with partial string match) + </li><li> + Add more columns, such as pixel diffs, notes/bugs, + ignoreFailure boolean + </li><li> + Improve the column sorting, as per + <a href="http://jsfiddle.net/vojtajina/js64b/14/"> + http://jsfiddle.net/vojtajina/js64b/14/ + </a> + </li><li> + Right now, if you change which column is used to + sort the data, the column widths may fluctuate based on the + longest string <i>currently visible</i> within the top {{displayLimit}} + results. Can we fix the column widths to be wide enough to hold + any result, even the currently hidden results? + </li> + </ul> + </div><!-- TODOs --> + <div ng-hide="!(header.timeUpdated)"> Results current as of {{localTimeString(header.timeUpdated)}} </div> - <table border="1"> + + <div style="font-size:20px"><!-- tabs --> + <div ng-repeat="tab in tabs" + style="display:inline-block"> + <div class="tab-{{tab == viewingTab}}" + style="display:inline-block" + ng-click="setViewingTab(tab)"> + {{tab}} ({{numResultsPerTab[tab]}}) + </div> + <div style="display:inline-block"> + + </div> + </div> + </div><!-- tabs --> + + <div class="tab-true"><!-- display of current tab --> + + <br> + <table ng-hide="viewingTab != defaultTab" border="1"> <tr> <th colspan="2"> Filters @@ -80,49 +134,52 @@ </tr> </table> - <p> - TODO(epoger): - <input type="checkbox" name="showTodosCheckbox" value="true" - ng-checked="showTodos == true" - ng-click="showTodos = !showTodos"> - show - <ul ng-hide="!showTodos"> - <li> - Implement editing of results (we have added the --editable - flag to the server, but it's not fully implemented yet). - <div ng-hide="!header.isEditable"> - Currently selected items are: {{selectedItems}} + <p> + + <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> - </li><li> - If server was run with --reload flag, automatically check for - new results and tell the user when new results are available - (the user can reload the page if he wants to see them). - </li><li> - Add ability to filter builder and test names - (using a free-form text field, with partial string match) - </li><li> - Add more columns, such as pixel diffs, notes/bugs, - ignoreFailure boolean - </li><li> - Improve the column sorting, as per - <a href="http://jsfiddle.net/vojtajina/js64b/14/"> - http://jsfiddle.net/vojtajina/js64b/14/ - </a> - </li><li> - Right now, if you change which column is used to - sort the data, the column widths may fluctuate based on the - longest string <i>currently visible</i> within the top {{displayLimit}} - results. Can we fix the column widths to be wide enough to hold - any result, even the currently hidden results? - </li> - </ul> + </div> + </div> + <p> - Found {{filteredTestData.length}} matches, and displaying the first - {{displayLimit}}: <br> - <!-- TODO(epoger): If (displayLimit <= filteredTestData.length), - modify this message to indicate that all results are shown. --> - (click on the column header radio buttons to re-sort by that column) + + <div> + <div style="float:left"> + 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) + </div> + <div style="float:right"> + <div ng-repeat="otherTab in tabs"> + <button ng-click="moveSelectedItemsToTab(otherTab)" + ng-disabled="selectedItems.length == 0" + ng-hide="otherTab == viewingTab"> + {{selectedItems.length}} move selected tests to {{otherTab}} tab + </button> + </div> + </div> + <div style="clear:both"> + </div> + </div> <br> + <table border="1"> <tr> <th ng-repeat="categoryName in ['resultType', 'builder', 'test', 'config']"> @@ -149,7 +206,7 @@ ng-click="sortResultsBy('actualHashDigest')"> actual image </th> - <th ng-hide="!header.isEditable"> + <th> <!-- item-selection checkbox column --> </th> </tr> @@ -168,7 +225,7 @@ <img width="{{imageSize}}" src="http://chromium-skia-gm.commondatastorage.googleapis.com/gm/{{result.actualHashType}}/{{result.test}}/{{result.actualHashDigest}}.png"/> </a> </td> - <td ng-hide="!header.isEditable"> + <td> <input type="checkbox" name="rowSelect" value="{{result.index}}" @@ -176,7 +233,8 @@ ng-click="toggleItemSelected(result.index)"> </tr> </table> - </div> + </div><!-- display of current tab --> + </div><!-- everything: hide until data is loaded --> <!-- TODO(epoger): Can we get the base URLs (commondatastorage and issues list) from |