OLD | NEW |
1 /* | 1 /* |
2 * Loader: | 2 * Loader: |
3 * Reads GM result reports written out by results.py, and imports | 3 * Reads GM result reports written out by results.py, and imports |
4 * them into $scope.categories and $scope.testData . | 4 * them into $scope.categories and $scope.testData . |
5 */ | 5 */ |
6 var Loader = angular.module( | 6 var Loader = angular.module( |
7 'Loader', | 7 'Loader', |
8 [] | 8 [] |
9 ); | 9 ); |
10 | 10 |
11 | 11 |
12 // TODO(epoger): Combine ALL of our filtering operations (including | 12 // TODO(epoger): Combine ALL of our filtering operations (including |
13 // truncation) into this one filter, so that runs most efficiently? | 13 // truncation) into this one filter, so that runs most efficiently? |
14 // (We would have to make sure truncation still took place after | 14 // (We would have to make sure truncation still took place after |
15 // sorting, though.) | 15 // sorting, though.) |
16 Loader.filter( | 16 Loader.filter( |
17 'removeHiddenItems', | 17 'removeHiddenItems', |
18 function() { | 18 function() { |
19 return function(unfilteredItems, hiddenResultTypes, hiddenConfigs, | 19 return function(unfilteredItems, hiddenResultTypes, hiddenConfigs, |
20 viewingTab) { | 20 viewingTab) { |
21 var filteredItems = []; | 21 var filteredItems = []; |
22 for (var i = 0; i < unfilteredItems.length; i++) { | 22 for (var i = 0; i < unfilteredItems.length; i++) { |
23 var item = unfilteredItems[i]; | 23 var item = unfilteredItems[i]; |
24 » // For performance, we examine the "set" objects directly rather | 24 // For performance, we examine the "set" objects directly rather |
25 » // than calling $scope.isValueInSet(). | 25 // than calling $scope.isValueInSet(). |
| 26 // Besides, I don't think we have access to $scope in here... |
26 if (!(true == hiddenResultTypes[item.resultType]) && | 27 if (!(true == hiddenResultTypes[item.resultType]) && |
27 !(true == hiddenConfigs[item.config]) && | 28 !(true == hiddenConfigs[item.config]) && |
28 (viewingTab == item.tab)) { | 29 (viewingTab == item.tab)) { |
29 filteredItems.push(item); | 30 filteredItems.push(item); |
30 } | 31 } |
31 } | 32 } |
32 return filteredItems; | 33 return filteredItems; |
33 }; | 34 }; |
34 } | 35 } |
35 ); | 36 ); |
(...skipping 15 matching lines...) Expand all Loading... |
51 $http.get("/results/" + resultsToLoad).success( | 52 $http.get("/results/" + resultsToLoad).success( |
52 function(data, status, header, config) { | 53 function(data, status, header, config) { |
53 $scope.loadingMessage = "Processing data, please wait..."; | 54 $scope.loadingMessage = "Processing data, please wait..."; |
54 | 55 |
55 $scope.header = data.header; | 56 $scope.header = data.header; |
56 $scope.categories = data.categories; | 57 $scope.categories = data.categories; |
57 $scope.testData = data.testData; | 58 $scope.testData = data.testData; |
58 $scope.sortColumn = 'test'; | 59 $scope.sortColumn = 'test'; |
59 $scope.showTodos = false; | 60 $scope.showTodos = false; |
60 | 61 |
| 62 $scope.showSubmitAdvancedSettings = false; |
| 63 $scope.submitAdvancedSettings = {}; |
| 64 $scope.submitAdvancedSettings['reviewed-by-human'] = true; |
| 65 $scope.submitAdvancedSettings['ignore-failures'] = false; |
| 66 $scope.submitAdvancedSettings['bug'] = ''; |
| 67 |
61 // Create the list of tabs (lists into which the user can file each | 68 // Create the list of tabs (lists into which the user can file each |
62 // test). This may vary, depending on isEditable. | 69 // test). This may vary, depending on isEditable. |
63 $scope.tabs = [ | 70 $scope.tabs = [ |
64 'Unfiled', 'Hidden' | 71 'Unfiled', 'Hidden' |
65 ]; | 72 ]; |
66 if (data.header.isEditable) { | 73 if (data.header.isEditable) { |
67 $scope.tabs = $scope.tabs.concat( | 74 $scope.tabs = $scope.tabs.concat( |
68 ['Pending Approval']); | 75 ['Pending Approval']); |
69 } | 76 } |
70 $scope.defaultTab = $scope.tabs[0]; | 77 $scope.defaultTab = $scope.tabs[0]; |
71 $scope.viewingTab = $scope.defaultTab; | 78 $scope.viewingTab = $scope.defaultTab; |
72 | 79 |
73 // Track the number of results on each tab. | 80 // Track the number of results on each tab. |
74 $scope.numResultsPerTab = {}; | 81 $scope.numResultsPerTab = {}; |
75 for (var i = 0; i < $scope.tabs.length; i++) { | 82 for (var i = 0; i < $scope.tabs.length; i++) { |
76 $scope.numResultsPerTab[$scope.tabs[i]] = 0; | 83 $scope.numResultsPerTab[$scope.tabs[i]] = 0; |
77 } | 84 } |
78 $scope.numResultsPerTab[$scope.defaultTab] = $scope.testData.length; | 85 $scope.numResultsPerTab[$scope.defaultTab] = $scope.testData.length; |
79 | 86 |
80 // Add index and tab fields to all records. | 87 // Add index and tab fields to all records. |
81 for (var i = 0; i < $scope.testData.length; i++) { | 88 for (var i = 0; i < $scope.testData.length; i++) { |
82 $scope.testData[i].index = i; | 89 $scope.testData[i].index = i; |
83 $scope.testData[i].tab = $scope.defaultTab; | 90 $scope.testData[i].tab = $scope.defaultTab; |
84 } | 91 } |
85 | 92 |
86 » // Arrays within which the user can toggle individual elements. | 93 // Arrays within which the user can toggle individual elements. |
87 $scope.selectedItems = []; | 94 $scope.selectedItems = []; |
88 | 95 |
89 » // Sets within which the user can toggle individual elements. | 96 // Sets within which the user can toggle individual elements. |
90 $scope.hiddenResultTypes = { | 97 $scope.hiddenResultTypes = { |
91 'failure-ignored': true, | 98 'failure-ignored': true, |
92 'no-comparison': true, | 99 'no-comparison': true, |
93 'succeeded': true, | 100 'succeeded': true, |
94 }; | 101 }; |
95 $scope.hiddenConfigs = {}; | 102 $scope.hiddenConfigs = {}; |
96 | 103 |
97 $scope.updateResults(); | 104 $scope.updateResults(); |
98 $scope.loadingMessage = ""; | 105 $scope.loadingMessage = ""; |
99 $scope.windowTitle = "Current GM Results"; | 106 $scope.windowTitle = "Current GM Results"; |
100 } | 107 } |
101 ).error( | 108 ).error( |
102 function(data, status, header, config) { | 109 function(data, status, header, config) { |
103 $scope.loadingMessage = "Failed to load results of type '" | 110 $scope.loadingMessage = "Failed to load results of type '" |
104 + resultsToLoad + "'"; | 111 + resultsToLoad + "'"; |
105 $scope.windowTitle = "Failed to Load GM Results"; | 112 $scope.windowTitle = "Failed to Load GM Results"; |
106 } | 113 } |
107 ); | 114 ); |
108 | 115 |
109 | 116 |
110 // | 117 // |
| 118 // Select/Clear/Toggle all tests. |
| 119 // |
| 120 |
| 121 /** |
| 122 * Select all currently showing tests. |
| 123 */ |
| 124 $scope.selectAllItems = function() { |
| 125 var numItemsShowing = $scope.limitedTestData.length; |
| 126 for (var i = 0; i < numItemsShowing; i++) { |
| 127 var index = $scope.limitedTestData[i].index; |
| 128 if (!$scope.isValueInArray(index, $scope.selectedItems)) { |
| 129 $scope.toggleValueInArray(index, $scope.selectedItems); |
| 130 } |
| 131 } |
| 132 } |
| 133 |
| 134 /** |
| 135 * Deselect all currently showing tests. |
| 136 */ |
| 137 $scope.clearAllItems = function() { |
| 138 var numItemsShowing = $scope.limitedTestData.length; |
| 139 for (var i = 0; i < numItemsShowing; i++) { |
| 140 var index = $scope.limitedTestData[i].index; |
| 141 if ($scope.isValueInArray(index, $scope.selectedItems)) { |
| 142 $scope.toggleValueInArray(index, $scope.selectedItems); |
| 143 } |
| 144 } |
| 145 } |
| 146 |
| 147 /** |
| 148 * Toggle selection of all currently showing tests. |
| 149 */ |
| 150 $scope.toggleAllItems = function() { |
| 151 var numItemsShowing = $scope.limitedTestData.length; |
| 152 for (var i = 0; i < numItemsShowing; i++) { |
| 153 var index = $scope.limitedTestData[i].index; |
| 154 $scope.toggleValueInArray(index, $scope.selectedItems); |
| 155 } |
| 156 } |
| 157 |
| 158 |
| 159 // |
111 // Tab operations. | 160 // Tab operations. |
112 // | 161 // |
113 | 162 |
114 /** | 163 /** |
115 * Change the selected tab. | 164 * Change the selected tab. |
116 * | 165 * |
117 * @param tab (string): name of the tab to select | 166 * @param tab (string): name of the tab to select |
118 */ | 167 */ |
119 $scope.setViewingTab = function(tab) { | 168 $scope.setViewingTab = function(tab) { |
120 $scope.viewingTab = tab; | 169 $scope.viewingTab = tab; |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
197 $scope.filteredTestData, $scope.displayLimit); | 246 $scope.filteredTestData, $scope.displayLimit); |
198 } else { | 247 } else { |
199 $scope.filteredTestData = | 248 $scope.filteredTestData = |
200 $filter("orderBy")( | 249 $filter("orderBy")( |
201 $filter("filter")( | 250 $filter("filter")( |
202 $scope.testData, | 251 $scope.testData, |
203 {tab: $scope.viewingTab}, | 252 {tab: $scope.viewingTab}, |
204 true | 253 true |
205 ), | 254 ), |
206 $scope.sortColumn); | 255 $scope.sortColumn); |
207 $scope.limitedTestData = $filter("limitTo")( | 256 $scope.limitedTestData = $scope.filteredTestData; |
208 $scope.filteredTestData, $scope.displayLimit); | |
209 } | 257 } |
210 $scope.imageSize = $scope.imageSizePending; | 258 $scope.imageSize = $scope.imageSizePending; |
211 $scope.setUpdatesPending(false); | 259 $scope.setUpdatesPending(false); |
212 } | 260 } |
213 | 261 |
214 /** | 262 /** |
215 * Re-sort the displayed results. | 263 * Re-sort the displayed results. |
216 * | 264 * |
217 * @param sortColumn (string): name of the column to sort on | 265 * @param sortColumn (string): name of the column to sort on |
218 */ | 266 */ |
219 $scope.sortResultsBy = function(sortColumn) { | 267 $scope.sortResultsBy = function(sortColumn) { |
220 $scope.sortColumn = sortColumn; | 268 $scope.sortColumn = sortColumn; |
221 $scope.updateResults(); | 269 $scope.updateResults(); |
222 } | 270 } |
223 | 271 |
224 | 272 |
225 // | 273 // |
226 // Operations for sending info back to the server. | 274 // Operations for sending info back to the server. |
227 // | 275 // |
228 | 276 |
229 /** | 277 /** |
230 * Tell the server that the actual results of these particular tests | 278 * Tell the server that the actual results of these particular tests |
231 * are acceptable. | 279 * are acceptable. |
232 * | 280 * |
233 * @param testDataSubset an array of test results, most likely a subset of | 281 * @param testDataSubset an array of test results, most likely a subset of |
234 * $scope.testData (perhaps with some modifications) | 282 * $scope.testData (perhaps with some modifications) |
235 */ | 283 */ |
236 $scope.submitApprovals = function(testDataSubset) { | 284 $scope.submitApprovals = function(testDataSubset) { |
237 $scope.submitPending = true; | 285 $scope.submitPending = true; |
| 286 |
| 287 // Convert bug text field to null or 1-item array. |
| 288 var bugs = null; |
| 289 var bugNumber = parseInt($scope.submitAdvancedSettings['bug']); |
| 290 if (!isNaN(bugNumber)) { |
| 291 bugs = [bugNumber]; |
| 292 } |
| 293 |
| 294 // TODO(epoger): This is a suboptimal way to prevent users from |
| 295 // rebaselining failures in alternative renderModes, but it does work. |
| 296 // For a better solution, see |
| 297 // https://code.google.com/p/skia/issues/detail?id=1748 ('gm: add new |
| 298 // result type, RenderModeMismatch') |
| 299 var encounteredComparisonConfig = false; |
| 300 |
238 var newResults = []; | 301 var newResults = []; |
239 for (var i = 0; i < testDataSubset.length; i++) { | 302 for (var i = 0; i < testDataSubset.length; i++) { |
240 var actualResult = testDataSubset[i]; | 303 var actualResult = testDataSubset[i]; |
241 var expectedResult = { | 304 var expectedResult = { |
242 builder: actualResult['builder'], | 305 builder: actualResult['builder'], |
243 test: actualResult['test'], | 306 test: actualResult['test'], |
244 config: actualResult['config'], | 307 config: actualResult['config'], |
245 expectedHashType: actualResult['actualHashType'], | 308 expectedHashType: actualResult['actualHashType'], |
246 expectedHashDigest: actualResult['actualHashDigest'], | 309 expectedHashDigest: actualResult['actualHashDigest'], |
247 }; | 310 }; |
| 311 if (0 == expectedResult.config.indexOf('comparison-')) { |
| 312 encounteredComparisonConfig = true; |
| 313 } |
| 314 |
| 315 // Advanced settings... |
| 316 expectedResult['reviewed-by-human'] = |
| 317 $scope.submitAdvancedSettings['reviewed-by-human']; |
| 318 if (true == $scope.submitAdvancedSettings['ignore-failure']) { |
| 319 // if it's false, don't send it at all (just keep the default) |
| 320 expectedResult['ignoreFailure'] = true; |
| 321 } |
| 322 expectedResult['bugs'] = bugs; |
| 323 |
248 newResults.push(expectedResult); | 324 newResults.push(expectedResult); |
249 } | 325 } |
| 326 if (encounteredComparisonConfig) { |
| 327 alert("Approval failed -- you cannot approve results with config " + |
| 328 "type comparison-*"); |
| 329 $scope.submitPending = false; |
| 330 return; |
| 331 } |
250 $http({ | 332 $http({ |
251 method: "POST", | 333 method: "POST", |
252 url: "/edits", | 334 url: "/edits", |
253 data: { | 335 data: { |
254 oldResultsType: $scope.header.type, | 336 oldResultsType: $scope.header.type, |
255 oldResultsHash: $scope.header.dataHash, | 337 oldResultsHash: $scope.header.dataHash, |
256 modifications: newResults | 338 modifications: newResults |
257 } | 339 } |
258 }).success(function(data, status, headers, config) { | 340 }).success(function(data, status, headers, config) { |
259 var itemIndicesToMove = []; | 341 var itemIndicesToMove = []; |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
355 * | 437 * |
356 * @param secondsPastEpoch (numeric): seconds past epoch in UTC | 438 * @param secondsPastEpoch (numeric): seconds past epoch in UTC |
357 */ | 439 */ |
358 $scope.localTimeString = function(secondsPastEpoch) { | 440 $scope.localTimeString = function(secondsPastEpoch) { |
359 var d = new Date(secondsPastEpoch * 1000); | 441 var d = new Date(secondsPastEpoch * 1000); |
360 return d.toString(); | 442 return d.toString(); |
361 } | 443 } |
362 | 444 |
363 } | 445 } |
364 ); | 446 ); |
OLD | NEW |