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.extraColumnHeaders and $scope.imagePairs . |
5 */ | 5 */ |
6 var Loader = angular.module( | 6 var Loader = angular.module( |
7 'Loader', | 7 'Loader', |
8 ['diff_viewer'] | 8 ['ConstantsModule', 'diff_viewer'] |
9 ); | 9 ); |
10 | 10 |
11 | |
12 // TODO(epoger): Combine ALL of our filtering operations (including | 11 // TODO(epoger): Combine ALL of our filtering operations (including |
13 // truncation) into this one filter, so that runs most efficiently? | 12 // truncation) into this one filter, so that runs most efficiently? |
14 // (We would have to make sure truncation still took place after | 13 // (We would have to make sure truncation still took place after |
15 // sorting, though.) | 14 // sorting, though.) |
16 Loader.filter( | 15 Loader.filter( |
17 'removeHiddenItems', | 16 'removeHiddenImagePairs', |
18 function() { | 17 function(constants) { |
19 return function(unfilteredItems, hiddenResultTypes, hiddenConfigs, | 18 return function(unfilteredImagePairs, hiddenResultTypes, hiddenConfigs, |
20 builderSubstring, testSubstring, viewingTab) { | 19 builderSubstring, testSubstring, viewingTab) { |
21 var filteredItems = []; | 20 var filteredImagePairs = []; |
22 for (var i = 0; i < unfilteredItems.length; i++) { | 21 for (var i = 0; i < unfilteredImagePairs.length; i++) { |
23 var item = unfilteredItems[i]; | 22 var imagePair = unfilteredImagePairs[i]; |
| 23 var extraColumnValues = imagePair[constants.KEY__EXTRA_COLUMN_VALUES]; |
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 // Besides, I don't think we have access to $scope in here... |
27 if (!(true == hiddenResultTypes[item.resultType]) && | 27 if (!(true == hiddenResultTypes[extraColumnValues[ |
28 !(true == hiddenConfigs[item.config]) && | 28 constants.KEY__EXTRACOLUMN__RESULT_TYPE]]) && |
29 !(-1 == item.builder.indexOf(builderSubstring)) && | 29 !(true == hiddenConfigs[extraColumnValues[ |
30 !(-1 == item.test.indexOf(testSubstring)) && | 30 constants.KEY__EXTRACOLUMN__CONFIG]]) && |
31 (viewingTab == item.tab)) { | 31 !(-1 == extraColumnValues[constants.KEY__EXTRACOLUMN__BUILDER] |
32 filteredItems.push(item); | 32 .indexOf(builderSubstring)) && |
| 33 !(-1 == extraColumnValues[constants.KEY__EXTRACOLUMN__TEST] |
| 34 .indexOf(testSubstring)) && |
| 35 (viewingTab == imagePair.tab)) { |
| 36 filteredImagePairs.push(imagePair); |
33 } | 37 } |
34 } | 38 } |
35 return filteredItems; | 39 return filteredImagePairs; |
36 }; | 40 }; |
37 } | 41 } |
38 ); | 42 ); |
39 | 43 |
40 | 44 |
41 Loader.controller( | 45 Loader.controller( |
42 'Loader.Controller', | 46 'Loader.Controller', |
43 function($scope, $http, $filter, $location, $timeout) { | 47 function($scope, $http, $filter, $location, $timeout, constants) { |
| 48 $scope.constants = constants; |
44 $scope.windowTitle = "Loading GM Results..."; | 49 $scope.windowTitle = "Loading GM Results..."; |
45 $scope.resultsToLoad = $location.search().resultsToLoad; | 50 $scope.resultsToLoad = $location.search().resultsToLoad; |
46 $scope.loadingMessage = "Loading results of type '" + $scope.resultsToLoad + | 51 $scope.loadingMessage = "Loading results of type '" + $scope.resultsToLoad + |
47 "', please wait..."; | 52 "', please wait..."; |
48 | 53 |
49 /** | 54 /** |
50 * On initial page load, load a full dictionary of results. | 55 * On initial page load, load a full dictionary of results. |
51 * Once the dictionary is loaded, unhide the page elements so they can | 56 * Once the dictionary is loaded, unhide the page elements so they can |
52 * render the data. | 57 * render the data. |
53 */ | 58 */ |
54 $http.get("/results/" + $scope.resultsToLoad).success( | 59 $http.get("/results/" + $scope.resultsToLoad).success( |
55 function(data, status, header, config) { | 60 function(data, status, header, config) { |
56 if (data.header.resultsStillLoading) { | 61 var dataHeader = data[constants.KEY__HEADER]; |
| 62 if (dataHeader[constants.KEY__HEADER__IS_STILL_LOADING]) { |
57 $scope.loadingMessage = | 63 $scope.loadingMessage = |
58 "Server is still loading results; will retry at " + | 64 "Server is still loading results; will retry at " + |
59 $scope.localTimeString(data.header.timeNextUpdateAvailable); | 65 $scope.localTimeString(dataHeader[ |
| 66 constants.KEY__HEADER__TIME_NEXT_UPDATE_AVAILABLE]); |
60 $timeout( | 67 $timeout( |
61 function(){location.reload();}, | 68 function(){location.reload();}, |
62 (data.header.timeNextUpdateAvailable * 1000) - new Date().getTime(
)); | 69 (dataHeader[constants.KEY__HEADER__TIME_NEXT_UPDATE_AVAILABLE] |
| 70 * 1000) - new Date().getTime()); |
63 } else { | 71 } else { |
64 $scope.loadingMessage = "Processing data, please wait..."; | 72 $scope.loadingMessage = "Processing data, please wait..."; |
65 | 73 |
66 $scope.header = data.header; | 74 $scope.header = dataHeader; |
67 $scope.categories = data.categories; | 75 $scope.extraColumnHeaders = data[constants.KEY__EXTRACOLUMNHEADERS]; |
68 $scope.testData = data.testData; | 76 $scope.imagePairs = data[constants.KEY__IMAGEPAIRS]; |
69 $scope.sortColumn = 'weightedDiffMeasure'; | 77 $scope.imageSets = data[constants.KEY__IMAGESETS]; |
| 78 $scope.sortColumnSubdict = constants.KEY__DIFFERENCE_DATA; |
| 79 $scope.sortColumnKey = constants.KEY__DIFFERENCE_DATA__WEIGHTED_DIFF; |
70 $scope.showTodos = false; | 80 $scope.showTodos = false; |
71 | 81 |
72 $scope.showSubmitAdvancedSettings = false; | 82 $scope.showSubmitAdvancedSettings = false; |
73 $scope.submitAdvancedSettings = {}; | 83 $scope.submitAdvancedSettings = {}; |
74 $scope.submitAdvancedSettings['reviewed-by-human'] = true; | 84 $scope.submitAdvancedSettings[ |
75 $scope.submitAdvancedSettings['ignore-failure'] = false; | 85 constants.KEY__EXPECTATIONS__REVIEWED] = true; |
| 86 $scope.submitAdvancedSettings[ |
| 87 constants.KEY__EXPECTATIONS__IGNOREFAILURE] = false; |
76 $scope.submitAdvancedSettings['bug'] = ''; | 88 $scope.submitAdvancedSettings['bug'] = ''; |
77 | 89 |
78 // Create the list of tabs (lists into which the user can file each | 90 // Create the list of tabs (lists into which the user can file each |
79 // test). This may vary, depending on isEditable. | 91 // test). This may vary, depending on isEditable. |
80 $scope.tabs = [ | 92 $scope.tabs = [ |
81 'Unfiled', 'Hidden' | 93 'Unfiled', 'Hidden' |
82 ]; | 94 ]; |
83 if (data.header.isEditable) { | 95 if (dataHeader[constants.KEY__HEADER__IS_EDITABLE]) { |
84 $scope.tabs = $scope.tabs.concat( | 96 $scope.tabs = $scope.tabs.concat( |
85 ['Pending Approval']); | 97 ['Pending Approval']); |
86 } | 98 } |
87 $scope.defaultTab = $scope.tabs[0]; | 99 $scope.defaultTab = $scope.tabs[0]; |
88 $scope.viewingTab = $scope.defaultTab; | 100 $scope.viewingTab = $scope.defaultTab; |
89 | 101 |
90 // Track the number of results on each tab. | 102 // Track the number of results on each tab. |
91 $scope.numResultsPerTab = {}; | 103 $scope.numResultsPerTab = {}; |
92 for (var i = 0; i < $scope.tabs.length; i++) { | 104 for (var i = 0; i < $scope.tabs.length; i++) { |
93 $scope.numResultsPerTab[$scope.tabs[i]] = 0; | 105 $scope.numResultsPerTab[$scope.tabs[i]] = 0; |
94 } | 106 } |
95 $scope.numResultsPerTab[$scope.defaultTab] = $scope.testData.length; | 107 $scope.numResultsPerTab[$scope.defaultTab] = $scope.imagePairs.length; |
96 | 108 |
97 // Add index and tab fields to all records. | 109 // Add index and tab fields to all records. |
98 for (var i = 0; i < $scope.testData.length; i++) { | 110 for (var i = 0; i < $scope.imagePairs.length; i++) { |
99 $scope.testData[i].index = i; | 111 $scope.imagePairs[i].index = i; |
100 $scope.testData[i].tab = $scope.defaultTab; | 112 $scope.imagePairs[i].tab = $scope.defaultTab; |
101 } | 113 } |
102 | 114 |
103 // Arrays within which the user can toggle individual elements. | 115 // Arrays within which the user can toggle individual elements. |
104 $scope.selectedItems = []; | 116 $scope.selectedImagePairs = []; |
105 | 117 |
106 // Sets within which the user can toggle individual elements. | 118 // Sets within which the user can toggle individual elements. |
107 $scope.hiddenResultTypes = { | 119 $scope.hiddenResultTypes = {}; |
108 'failure-ignored': true, | 120 $scope.hiddenResultTypes[ |
109 'no-comparison': true, | 121 constants.KEY__RESULT_TYPE__FAILUREIGNORED] = true; |
110 'succeeded': true, | 122 $scope.hiddenResultTypes[ |
111 }; | 123 constants.KEY__RESULT_TYPE__NOCOMPARISON] = true; |
112 $scope.allResultTypes = Object.keys(data.categories['resultType']); | 124 $scope.hiddenResultTypes[ |
| 125 constants.KEY__RESULT_TYPE__SUCCEEDED] = true; |
| 126 $scope.allResultTypes = Object.keys( |
| 127 $scope.extraColumnHeaders[constants.KEY__EXTRACOLUMN__RESULT_TYPE] |
| 128 [constants.KEY__VALUES_AND_COUNTS]); |
113 $scope.hiddenConfigs = {}; | 129 $scope.hiddenConfigs = {}; |
114 $scope.allConfigs = Object.keys(data.categories['config']); | 130 $scope.allConfigs = Object.keys( |
| 131 $scope.extraColumnHeaders[constants.KEY__EXTRACOLUMN__CONFIG] |
| 132 [constants.KEY__VALUES_AND_COUNTS]); |
115 | 133 |
116 // Associative array of partial string matches per category. | 134 // Associative array of partial string matches per category. |
117 $scope.categoryValueMatch = {}; | 135 $scope.categoryValueMatch = {}; |
118 $scope.categoryValueMatch.builder = ""; | 136 $scope.categoryValueMatch.builder = ""; |
119 $scope.categoryValueMatch.test = ""; | 137 $scope.categoryValueMatch.test = ""; |
120 | 138 |
121 // If any defaults were overridden in the URL, get them now. | 139 // If any defaults were overridden in the URL, get them now. |
122 $scope.queryParameters.load(); | 140 $scope.queryParameters.load(); |
123 | 141 |
124 $scope.updateResults(); | 142 $scope.updateResults(); |
(...skipping 10 matching lines...) Expand all Loading... |
135 ); | 153 ); |
136 | 154 |
137 | 155 |
138 // | 156 // |
139 // Select/Clear/Toggle all tests. | 157 // Select/Clear/Toggle all tests. |
140 // | 158 // |
141 | 159 |
142 /** | 160 /** |
143 * Select all currently showing tests. | 161 * Select all currently showing tests. |
144 */ | 162 */ |
145 $scope.selectAllItems = function() { | 163 $scope.selectAllImagePairs = function() { |
146 var numItemsShowing = $scope.limitedTestData.length; | 164 var numImagePairsShowing = $scope.limitedImagePairs.length; |
147 for (var i = 0; i < numItemsShowing; i++) { | 165 for (var i = 0; i < numImagePairsShowing; i++) { |
148 var index = $scope.limitedTestData[i].index; | 166 var index = $scope.limitedImagePairs[i].index; |
149 if (!$scope.isValueInArray(index, $scope.selectedItems)) { | 167 if (!$scope.isValueInArray(index, $scope.selectedImagePairs)) { |
150 $scope.toggleValueInArray(index, $scope.selectedItems); | 168 $scope.toggleValueInArray(index, $scope.selectedImagePairs); |
151 } | 169 } |
152 } | 170 } |
153 } | 171 } |
154 | 172 |
155 /** | 173 /** |
156 * Deselect all currently showing tests. | 174 * Deselect all currently showing tests. |
157 */ | 175 */ |
158 $scope.clearAllItems = function() { | 176 $scope.clearAllImagePairs = function() { |
159 var numItemsShowing = $scope.limitedTestData.length; | 177 var numImagePairsShowing = $scope.limitedImagePairs.length; |
160 for (var i = 0; i < numItemsShowing; i++) { | 178 for (var i = 0; i < numImagePairsShowing; i++) { |
161 var index = $scope.limitedTestData[i].index; | 179 var index = $scope.limitedImagePairs[i].index; |
162 if ($scope.isValueInArray(index, $scope.selectedItems)) { | 180 if ($scope.isValueInArray(index, $scope.selectedImagePairs)) { |
163 $scope.toggleValueInArray(index, $scope.selectedItems); | 181 $scope.toggleValueInArray(index, $scope.selectedImagePairs); |
164 } | 182 } |
165 } | 183 } |
166 } | 184 } |
167 | 185 |
168 /** | 186 /** |
169 * Toggle selection of all currently showing tests. | 187 * Toggle selection of all currently showing tests. |
170 */ | 188 */ |
171 $scope.toggleAllItems = function() { | 189 $scope.toggleAllImagePairs = function() { |
172 var numItemsShowing = $scope.limitedTestData.length; | 190 var numImagePairsShowing = $scope.limitedImagePairs.length; |
173 for (var i = 0; i < numItemsShowing; i++) { | 191 for (var i = 0; i < numImagePairsShowing; i++) { |
174 var index = $scope.limitedTestData[i].index; | 192 var index = $scope.limitedImagePairs[i].index; |
175 $scope.toggleValueInArray(index, $scope.selectedItems); | 193 $scope.toggleValueInArray(index, $scope.selectedImagePairs); |
176 } | 194 } |
177 } | 195 } |
178 | 196 |
179 | 197 |
180 // | 198 // |
181 // Tab operations. | 199 // Tab operations. |
182 // | 200 // |
183 | 201 |
184 /** | 202 /** |
185 * Change the selected tab. | 203 * Change the selected tab. |
186 * | 204 * |
187 * @param tab (string): name of the tab to select | 205 * @param tab (string): name of the tab to select |
188 */ | 206 */ |
189 $scope.setViewingTab = function(tab) { | 207 $scope.setViewingTab = function(tab) { |
190 $scope.viewingTab = tab; | 208 $scope.viewingTab = tab; |
191 $scope.updateResults(); | 209 $scope.updateResults(); |
192 } | 210 } |
193 | 211 |
194 /** | 212 /** |
195 * Move the items in $scope.selectedItems to a different tab, | 213 * Move the imagePairs in $scope.selectedImagePairs to a different tab, |
196 * and then clear $scope.selectedItems. | 214 * and then clear $scope.selectedImagePairs. |
197 * | 215 * |
198 * @param newTab (string): name of the tab to move the tests to | 216 * @param newTab (string): name of the tab to move the tests to |
199 */ | 217 */ |
200 $scope.moveSelectedItemsToTab = function(newTab) { | 218 $scope.moveSelectedImagePairsToTab = function(newTab) { |
201 $scope.moveItemsToTab($scope.selectedItems, newTab); | 219 $scope.moveImagePairsToTab($scope.selectedImagePairs, newTab); |
202 $scope.selectedItems = []; | 220 $scope.selectedImagePairs = []; |
203 $scope.updateResults(); | 221 $scope.updateResults(); |
204 } | 222 } |
205 | 223 |
206 /** | 224 /** |
207 * Move a subset of $scope.testData to a different tab. | 225 * Move a subset of $scope.imagePairs to a different tab. |
208 * | 226 * |
209 * @param itemIndices (array of ints): indices into $scope.testData | 227 * @param imagePairIndices (array of ints): indices into $scope.imagePairs |
210 * indicating which test results to move | 228 * indicating which test results to move |
211 * @param newTab (string): name of the tab to move the tests to | 229 * @param newTab (string): name of the tab to move the tests to |
212 */ | 230 */ |
213 $scope.moveItemsToTab = function(itemIndices, newTab) { | 231 $scope.moveImagePairsToTab = function(imagePairIndices, newTab) { |
214 var itemIndex; | 232 var imagePairIndex; |
215 var numItems = itemIndices.length; | 233 var numImagePairs = imagePairIndices.length; |
216 for (var i = 0; i < numItems; i++) { | 234 for (var i = 0; i < numImagePairs; i++) { |
217 itemIndex = itemIndices[i]; | 235 imagePairIndex = imagePairIndices[i]; |
218 $scope.numResultsPerTab[$scope.testData[itemIndex].tab]--; | 236 $scope.numResultsPerTab[$scope.imagePairs[imagePairIndex].tab]--; |
219 $scope.testData[itemIndex].tab = newTab; | 237 $scope.imagePairs[imagePairIndex].tab = newTab; |
220 } | 238 } |
221 $scope.numResultsPerTab[newTab] += numItems; | 239 $scope.numResultsPerTab[newTab] += numImagePairs; |
222 } | 240 } |
223 | 241 |
224 | 242 |
225 // | 243 // |
226 // $scope.queryParameters: | 244 // $scope.queryParameters: |
227 // Transfer parameter values between $scope and the URL query string. | 245 // Transfer parameter values between $scope and the URL query string. |
228 // | 246 // |
229 $scope.queryParameters = {}; | 247 $scope.queryParameters = {}; |
230 | 248 |
231 // load and save functions for parameters of each type | 249 // load and save functions for parameters of each type |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
270 } | 288 } |
271 }, | 289 }, |
272 | 290 |
273 }; | 291 }; |
274 | 292 |
275 // parameter name -> copier objects to load/save parameter value | 293 // parameter name -> copier objects to load/save parameter value |
276 $scope.queryParameters.map = { | 294 $scope.queryParameters.map = { |
277 'resultsToLoad': $scope.queryParameters.copiers.simple, | 295 'resultsToLoad': $scope.queryParameters.copiers.simple, |
278 'displayLimitPending': $scope.queryParameters.copiers.simple, | 296 'displayLimitPending': $scope.queryParameters.copiers.simple, |
279 'imageSizePending': $scope.queryParameters.copiers.simple, | 297 'imageSizePending': $scope.queryParameters.copiers.simple, |
280 'sortColumn': $scope.queryParameters.copiers.simple, | 298 'sortColumnSubdict': $scope.queryParameters.copiers.simple, |
281 | 299 'sortColumnKey': $scope.queryParameters.copiers.simple, |
282 'builder': $scope.queryParameters.copiers.categoryValueMatch, | |
283 'test': $scope.queryParameters.copiers.categoryValueMatch, | |
284 | 300 |
285 'hiddenResultTypes': $scope.queryParameters.copiers.set, | 301 'hiddenResultTypes': $scope.queryParameters.copiers.set, |
286 'hiddenConfigs': $scope.queryParameters.copiers.set, | 302 'hiddenConfigs': $scope.queryParameters.copiers.set, |
287 }; | 303 }; |
| 304 $scope.queryParameters.map[constants.KEY__EXTRACOLUMN__BUILDER] = |
| 305 $scope.queryParameters.copiers.categoryValueMatch; |
| 306 $scope.queryParameters.map[constants.KEY__EXTRACOLUMN__TEST] = |
| 307 $scope.queryParameters.copiers.categoryValueMatch; |
288 | 308 |
289 // Loads all parameters into $scope from the URL query string; | 309 // Loads all parameters into $scope from the URL query string; |
290 // any which are not found within the URL will keep their current value. | 310 // any which are not found within the URL will keep their current value. |
291 $scope.queryParameters.load = function() { | 311 $scope.queryParameters.load = function() { |
292 var nameValuePairs = $location.search(); | 312 var nameValuePairs = $location.search(); |
293 angular.forEach($scope.queryParameters.map, | 313 angular.forEach($scope.queryParameters.map, |
294 function(copier, paramName) { | 314 function(copier, paramName) { |
295 copier.load(nameValuePairs, paramName); | 315 copier.load(nameValuePairs, paramName); |
296 } | 316 } |
297 ); | 317 ); |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
332 | 352 |
333 /** | 353 /** |
334 * Update the displayed results, based on filters/settings, | 354 * Update the displayed results, based on filters/settings, |
335 * and call $scope.queryParameters.save() so that the new filter results | 355 * and call $scope.queryParameters.save() so that the new filter results |
336 * can be bookmarked. | 356 * can be bookmarked. |
337 */ | 357 */ |
338 $scope.updateResults = function() { | 358 $scope.updateResults = function() { |
339 $scope.displayLimit = $scope.displayLimitPending; | 359 $scope.displayLimit = $scope.displayLimitPending; |
340 // TODO(epoger): Every time we apply a filter, AngularJS creates | 360 // TODO(epoger): Every time we apply a filter, AngularJS creates |
341 // another copy of the array. Is there a way we can filter out | 361 // another copy of the array. Is there a way we can filter out |
342 // the items as they are displayed, rather than storing multiple | 362 // the imagePairs as they are displayed, rather than storing multiple |
343 // array copies? (For better performance.) | 363 // array copies? (For better performance.) |
344 | 364 |
345 if ($scope.viewingTab == $scope.defaultTab) { | 365 if ($scope.viewingTab == $scope.defaultTab) { |
346 | 366 |
347 // TODO(epoger): Until we allow the user to reverse sort order, | 367 // TODO(epoger): Until we allow the user to reverse sort order, |
348 // there are certain columns we want to sort in a different order. | 368 // there are certain columns we want to sort in a different order. |
349 var doReverse = ( | 369 var doReverse = ( |
350 ($scope.sortColumn == 'percentDifferingPixels') || | 370 ($scope.sortColumnKey == |
351 ($scope.sortColumn == 'weightedDiffMeasure')); | 371 constants.KEY__DIFFERENCE_DATA__PERCENT_DIFF_PIXELS) || |
| 372 ($scope.sortColumnKey == |
| 373 constants.KEY__DIFFERENCE_DATA__WEIGHTED_DIFF)); |
352 | 374 |
353 $scope.filteredTestData = | 375 $scope.filteredImagePairs = |
354 $filter("orderBy")( | 376 $filter("orderBy")( |
355 $filter("removeHiddenItems")( | 377 $filter("removeHiddenImagePairs")( |
356 $scope.testData, | 378 $scope.imagePairs, |
357 $scope.hiddenResultTypes, | 379 $scope.hiddenResultTypes, |
358 $scope.hiddenConfigs, | 380 $scope.hiddenConfigs, |
359 $scope.categoryValueMatch.builder, | 381 $scope.categoryValueMatch.builder, |
360 $scope.categoryValueMatch.test, | 382 $scope.categoryValueMatch.test, |
361 $scope.viewingTab | 383 $scope.viewingTab |
362 ), | 384 ), |
363 $scope.sortColumn, doReverse); | 385 $scope.getSortColumnValue, doReverse); |
364 $scope.limitedTestData = $filter("limitTo")( | 386 $scope.limitedImagePairs = $filter("limitTo")( |
365 $scope.filteredTestData, $scope.displayLimit); | 387 $scope.filteredImagePairs, $scope.displayLimit); |
366 } else { | 388 } else { |
367 $scope.filteredTestData = | 389 $scope.filteredImagePairs = |
368 $filter("orderBy")( | 390 $filter("orderBy")( |
369 $filter("filter")( | 391 $filter("filter")( |
370 $scope.testData, | 392 $scope.imagePairs, |
371 {tab: $scope.viewingTab}, | 393 {tab: $scope.viewingTab}, |
372 true | 394 true |
373 ), | 395 ), |
374 $scope.sortColumn); | 396 $scope.getSortColumnValue); |
375 $scope.limitedTestData = $scope.filteredTestData; | 397 $scope.limitedImagePairs = $scope.filteredImagePairs; |
376 } | 398 } |
377 $scope.imageSize = $scope.imageSizePending; | 399 $scope.imageSize = $scope.imageSizePending; |
378 $scope.setUpdatesPending(false); | 400 $scope.setUpdatesPending(false); |
379 $scope.queryParameters.save(); | 401 $scope.queryParameters.save(); |
380 } | 402 } |
381 | 403 |
382 /** | 404 /** |
383 * Re-sort the displayed results. | 405 * Re-sort the displayed results. |
384 * | 406 * |
385 * @param sortColumn (string): name of the column to sort on | 407 * @param subdict (string): which subdictionary |
| 408 * (constants.KEY__DIFFERENCE_DATA, constants.KEY__EXPECTATIONS_DATA, |
| 409 * constants.KEY__EXTRA_COLUMN_VALUES) the sort column key is within |
| 410 * @param key (string): sort by value associated with this key in subdict |
386 */ | 411 */ |
387 $scope.sortResultsBy = function(sortColumn) { | 412 $scope.sortResultsBy = function(subdict, key) { |
388 $scope.sortColumn = sortColumn; | 413 $scope.sortColumnSubdict = subdict; |
| 414 $scope.sortColumnKey = key; |
389 $scope.updateResults(); | 415 $scope.updateResults(); |
390 } | 416 } |
391 | 417 |
392 /** | 418 /** |
| 419 * For a particular ImagePair, return the value of the column we are |
| 420 * sorting on (according to $scope.sortColumnSubdict and |
| 421 * $scope.sortColumnKey). |
| 422 * |
| 423 * @param imagePair: imagePair to get a column value out of. |
| 424 */ |
| 425 $scope.getSortColumnValue = function(imagePair) { |
| 426 if ($scope.sortColumnSubdict in imagePair) { |
| 427 return imagePair[$scope.sortColumnSubdict][$scope.sortColumnKey]; |
| 428 } else { |
| 429 return undefined; |
| 430 } |
| 431 } |
| 432 |
| 433 /** |
393 * Set $scope.categoryValueMatch[name] = value, and update results. | 434 * Set $scope.categoryValueMatch[name] = value, and update results. |
394 * | 435 * |
395 * @param name | 436 * @param name |
396 * @param value | 437 * @param value |
397 */ | 438 */ |
398 $scope.setCategoryValueMatch = function(name, value) { | 439 $scope.setCategoryValueMatch = function(name, value) { |
399 $scope.categoryValueMatch[name] = value; | 440 $scope.categoryValueMatch[name] = value; |
400 $scope.updateResults(); | 441 $scope.updateResults(); |
401 } | 442 } |
402 | 443 |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
449 | 490 |
450 | 491 |
451 // | 492 // |
452 // Operations for sending info back to the server. | 493 // Operations for sending info back to the server. |
453 // | 494 // |
454 | 495 |
455 /** | 496 /** |
456 * Tell the server that the actual results of these particular tests | 497 * Tell the server that the actual results of these particular tests |
457 * are acceptable. | 498 * are acceptable. |
458 * | 499 * |
459 * @param testDataSubset an array of test results, most likely a subset of | 500 * TODO(epoger): This assumes that the original expectations are in |
460 * $scope.testData (perhaps with some modifications) | 501 * imageSetA, and the actuals are in imageSetB. |
| 502 * |
| 503 * @param imagePairsSubset an array of test results, most likely a subset of |
| 504 * $scope.imagePairs (perhaps with some modifications) |
461 */ | 505 */ |
462 $scope.submitApprovals = function(testDataSubset) { | 506 $scope.submitApprovals = function(imagePairsSubset) { |
463 $scope.submitPending = true; | 507 $scope.submitPending = true; |
464 | 508 |
465 // Convert bug text field to null or 1-item array. | 509 // Convert bug text field to null or 1-item array. |
466 var bugs = null; | 510 var bugs = null; |
467 var bugNumber = parseInt($scope.submitAdvancedSettings['bug']); | 511 var bugNumber = parseInt($scope.submitAdvancedSettings['bug']); |
468 if (!isNaN(bugNumber)) { | 512 if (!isNaN(bugNumber)) { |
469 bugs = [bugNumber]; | 513 bugs = [bugNumber]; |
470 } | 514 } |
471 | 515 |
472 // TODO(epoger): This is a suboptimal way to prevent users from | 516 // TODO(epoger): This is a suboptimal way to prevent users from |
473 // rebaselining failures in alternative renderModes, but it does work. | 517 // rebaselining failures in alternative renderModes, but it does work. |
474 // For a better solution, see | 518 // For a better solution, see |
475 // https://code.google.com/p/skia/issues/detail?id=1748 ('gm: add new | 519 // https://code.google.com/p/skia/issues/detail?id=1748 ('gm: add new |
476 // result type, RenderModeMismatch') | 520 // result type, RenderModeMismatch') |
477 var encounteredComparisonConfig = false; | 521 var encounteredComparisonConfig = false; |
478 | 522 |
479 var newResults = []; | 523 var updatedExpectations = []; |
480 for (var i = 0; i < testDataSubset.length; i++) { | 524 for (var i = 0; i < imagePairsSubset.length; i++) { |
481 var actualResult = testDataSubset[i]; | 525 var imagePair = imagePairsSubset[i]; |
482 var expectedResult = { | 526 var updatedExpectation = {}; |
483 builder: actualResult['builder'], | 527 updatedExpectation[constants.KEY__EXPECTATIONS_DATA] = |
484 test: actualResult['test'], | 528 imagePair[constants.KEY__EXPECTATIONS_DATA]; |
485 config: actualResult['config'], | 529 updatedExpectation[constants.KEY__EXTRA_COLUMN_VALUES] = |
486 expectedHashType: actualResult['actualHashType'], | 530 imagePair[constants.KEY__EXTRA_COLUMN_VALUES]; |
487 expectedHashDigest: actualResult['actualHashDigest'], | 531 updatedExpectation[constants.KEY__NEW_IMAGE_URL] = |
488 }; | 532 imagePair[constants.KEY__IMAGE_B_URL]; |
489 if (0 == expectedResult.config.indexOf('comparison-')) { | 533 if (0 == updatedExpectation[constants.KEY__EXTRA_COLUMN_VALUES] |
| 534 [constants.KEY__EXTRACOLUMN__CONFIG] |
| 535 .indexOf('comparison-')) { |
490 encounteredComparisonConfig = true; | 536 encounteredComparisonConfig = true; |
491 } | 537 } |
492 | 538 |
493 // Advanced settings... | 539 // Advanced settings... |
494 expectedResult['reviewed-by-human'] = | 540 if (null == updatedExpectation[constants.KEY__EXPECTATIONS_DATA]) { |
495 $scope.submitAdvancedSettings['reviewed-by-human']; | 541 updatedExpectation[constants.KEY__EXPECTATIONS_DATA] = {}; |
496 if (true == $scope.submitAdvancedSettings['ignore-failure']) { | 542 } |
| 543 updatedExpectation[constants.KEY__EXPECTATIONS_DATA] |
| 544 [constants.KEY__EXPECTATIONS__REVIEWED] = |
| 545 $scope.submitAdvancedSettings[ |
| 546 constants.KEY__EXPECTATIONS__REVIEWED]; |
| 547 if (true == $scope.submitAdvancedSettings[ |
| 548 constants.KEY__EXPECTATIONS__IGNOREFAILURE]) { |
497 // if it's false, don't send it at all (just keep the default) | 549 // if it's false, don't send it at all (just keep the default) |
498 expectedResult['ignore-failure'] = true; | 550 updatedExpectation[constants.KEY__EXPECTATIONS_DATA] |
| 551 [constants.KEY__EXPECTATIONS__IGNOREFAILURE] = true; |
499 } | 552 } |
500 expectedResult['bugs'] = bugs; | 553 updatedExpectation[constants.KEY__EXPECTATIONS_DATA] |
| 554 [constants.KEY__EXPECTATIONS__BUGS] = bugs; |
501 | 555 |
502 newResults.push(expectedResult); | 556 updatedExpectations.push(updatedExpectation); |
503 } | 557 } |
504 if (encounteredComparisonConfig) { | 558 if (encounteredComparisonConfig) { |
505 alert("Approval failed -- you cannot approve results with config " + | 559 alert("Approval failed -- you cannot approve results with config " + |
506 "type comparison-*"); | 560 "type comparison-*"); |
507 $scope.submitPending = false; | 561 $scope.submitPending = false; |
508 return; | 562 return; |
509 } | 563 } |
| 564 var modificationData = {}; |
| 565 modificationData[constants.KEY__EDITS__MODIFICATIONS] = |
| 566 updatedExpectations; |
| 567 modificationData[constants.KEY__EDITS__OLD_RESULTS_HASH] = |
| 568 $scope.header[constants.KEY__HEADER__DATAHASH]; |
| 569 modificationData[constants.KEY__EDITS__OLD_RESULTS_TYPE] = |
| 570 $scope.header[constants.KEY__HEADER__TYPE]; |
510 $http({ | 571 $http({ |
511 method: "POST", | 572 method: "POST", |
512 url: "/edits", | 573 url: "/edits", |
513 data: { | 574 data: modificationData |
514 oldResultsType: $scope.header.type, | 575 }).success(function(data, status, headers, config) { |
515 oldResultsHash: $scope.header.dataHash, | 576 var imagePairIndicesToMove = []; |
516 modifications: newResults | 577 for (var i = 0; i < imagePairsSubset.length; i++) { |
| 578 imagePairIndicesToMove.push(imagePairsSubset[i].index); |
517 } | 579 } |
518 }).success(function(data, status, headers, config) { | 580 $scope.moveImagePairsToTab(imagePairIndicesToMove, |
519 var itemIndicesToMove = []; | 581 "HackToMakeSureThisImagePairDisappears"); |
520 for (var i = 0; i < testDataSubset.length; i++) { | |
521 itemIndicesToMove.push(testDataSubset[i].index); | |
522 } | |
523 $scope.moveItemsToTab(itemIndicesToMove, | |
524 "HackToMakeSureThisItemDisappears"); | |
525 $scope.updateResults(); | 582 $scope.updateResults(); |
526 alert("New baselines submitted successfully!\n\n" + | 583 alert("New baselines submitted successfully!\n\n" + |
527 "You still need to commit the updated expectations files on " + | 584 "You still need to commit the updated expectations files on " + |
528 "the server side to the Skia repo.\n\n" + | 585 "the server side to the Skia repo.\n\n" + |
529 "When you click OK, your web UI will reload; after that " + | 586 "When you click OK, your web UI will reload; after that " + |
530 "completes, you will see the updated data (once the server has " + | 587 "completes, you will see the updated data (once the server has " + |
531 "finished loading the update results into memory!) and you can " + | 588 "finished loading the update results into memory!) and you can " + |
532 "submit more baselines if you want."); | 589 "submit more baselines if you want."); |
533 // I don't know why, but if I just call reload() here it doesn't work. | 590 // I don't know why, but if I just call reload() here it doesn't work. |
534 // Making a timer call it fixes the problem. | 591 // Making a timer call it fixes the problem. |
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
675 * @param brightnessString (string): 0-255, 0 is completely black | 732 * @param brightnessString (string): 0-255, 0 is completely black |
676 * | 733 * |
677 * TODO(epoger): It might be nice to tint the color when it's not completely | 734 * TODO(epoger): It might be nice to tint the color when it's not completely |
678 * black or completely white. | 735 * black or completely white. |
679 */ | 736 */ |
680 $scope.brightnessStringToHexColor = function(brightnessString) { | 737 $scope.brightnessStringToHexColor = function(brightnessString) { |
681 var v = parseInt(brightnessString); | 738 var v = parseInt(brightnessString); |
682 return $scope.hexColorString(v, v, v); | 739 return $scope.hexColorString(v, v, v); |
683 } | 740 } |
684 | 741 |
| 742 /** |
| 743 * Returns the last path component of image diff URL for a given ImagePair. |
| 744 * |
| 745 * Depending on which diff this is (whitediffs, pixeldiffs, etc.) this |
| 746 * will be relative to different base URLs. |
| 747 * |
| 748 * We must keep this function in sync with _get_difference_locator() in |
| 749 * ../imagediffdb.py |
| 750 * |
| 751 * @param imagePair: ImagePair to generate image diff URL for |
| 752 */ |
| 753 $scope.getImageDiffRelativeUrl = function(imagePair) { |
| 754 var before = |
| 755 imagePair[constants.KEY__IMAGE_A_URL] + "-vs-" + |
| 756 imagePair[constants.KEY__IMAGE_B_URL]; |
| 757 return before.replace(/[^\w\-]/g, "_") + ".png"; |
| 758 } |
| 759 |
685 } | 760 } |
686 ); | 761 ); |
OLD | NEW |