Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(139)

Side by Side Diff: gm/rebaseline_server/static/loader.js

Issue 31583007: rebaseline_server: cleanup of HTML/Javascript (Closed) Base URL: http://skia.googlecode.com/svn/trunk/
Patch Set: why Created 7 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | gm/rebaseline_server/static/view.css » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 // TODO(epoger): Combine ALL of our filtering operations (including 12 // TODO(epoger): Combine ALL of our filtering operations (including
12 // truncation) into this one filter, so that runs most efficiently? 13 // truncation) into this one filter, so that runs most efficiently?
13 // (We would have to make sure truncation still took place after 14 // (We would have to make sure truncation still took place after
14 // sorting, though.) 15 // sorting, though.)
15 Loader.filter( 16 Loader.filter(
16 'removeHiddenItems', 17 'removeHiddenItems',
17 function() { 18 function() {
18 return function(unfilteredItems, hiddenResultTypes, hiddenConfigs, 19 return function(unfilteredItems, hiddenResultTypes, hiddenConfigs,
19 viewingTab) { 20 viewingTab) {
20 var filteredItems = []; 21 var filteredItems = [];
21 for (var i = 0; i < unfilteredItems.length; i++) { 22 for (var i = 0; i < unfilteredItems.length; i++) {
22 var item = unfilteredItems[i]; 23 var item = unfilteredItems[i];
24 // For performance, we examine the "set" objects directly rather
25 // than calling $scope.isValueInSet().
23 if (!(true == hiddenResultTypes[item.resultType]) && 26 if (!(true == hiddenResultTypes[item.resultType]) &&
24 !(true == hiddenConfigs[item.config]) && 27 !(true == hiddenConfigs[item.config]) &&
25 (viewingTab == item.tab)) { 28 (viewingTab == item.tab)) {
26 filteredItems.push(item); 29 filteredItems.push(item);
27 } 30 }
28 } 31 }
29 return filteredItems; 32 return filteredItems;
30 }; 33 };
31 } 34 }
32 ); 35 );
33 36
37
34 Loader.controller( 38 Loader.controller(
35 'Loader.Controller', 39 'Loader.Controller',
36 function($scope, $http, $filter, $location) { 40 function($scope, $http, $filter, $location) {
37 $scope.windowTitle = "Loading GM Results..."; 41 $scope.windowTitle = "Loading GM Results...";
38 var resultsToLoad = $location.search().resultsToLoad; 42 var resultsToLoad = $location.search().resultsToLoad;
39 $scope.loadingMessage = "Loading results of type '" + resultsToLoad + 43 $scope.loadingMessage = "Loading results of type '" + resultsToLoad +
40 "', please wait..."; 44 "', please wait...";
41 45
46 /**
47 * On initial page load, load a full dictionary of results.
48 * Once the dictionary is loaded, unhide the page elements so they can
49 * render the data.
50 */
42 $http.get("/results/" + resultsToLoad).success( 51 $http.get("/results/" + resultsToLoad).success(
43 function(data, status, header, config) { 52 function(data, status, header, config) {
44 $scope.loadingMessage = "Processing data, please wait..."; 53 $scope.loadingMessage = "Processing data, please wait...";
45 54
46 $scope.header = data.header; 55 $scope.header = data.header;
47 $scope.categories = data.categories; 56 $scope.categories = data.categories;
48 $scope.testData = data.testData; 57 $scope.testData = data.testData;
49 $scope.sortColumn = 'test'; 58 $scope.sortColumn = 'test';
50 $scope.showTodos = false; 59 $scope.showTodos = false;
51 60
(...skipping 15 matching lines...) Expand all
67 $scope.numResultsPerTab[$scope.tabs[i]] = 0; 76 $scope.numResultsPerTab[$scope.tabs[i]] = 0;
68 } 77 }
69 $scope.numResultsPerTab[$scope.defaultTab] = $scope.testData.length; 78 $scope.numResultsPerTab[$scope.defaultTab] = $scope.testData.length;
70 79
71 // Add index and tab fields to all records. 80 // Add index and tab fields to all records.
72 for (var i = 0; i < $scope.testData.length; i++) { 81 for (var i = 0; i < $scope.testData.length; i++) {
73 $scope.testData[i].index = i; 82 $scope.testData[i].index = i;
74 $scope.testData[i].tab = $scope.defaultTab; 83 $scope.testData[i].tab = $scope.defaultTab;
75 } 84 }
76 85
86 // Arrays within which the user can toggle individual elements.
87 $scope.selectedItems = [];
88
89 // Sets within which the user can toggle individual elements.
77 $scope.hiddenResultTypes = { 90 $scope.hiddenResultTypes = {
78 'failure-ignored': true, 91 'failure-ignored': true,
79 'no-comparison': true, 92 'no-comparison': true,
80 'succeeded': true, 93 'succeeded': true,
81 }; 94 };
82 $scope.hiddenConfigs = {}; 95 $scope.hiddenConfigs = {};
83 $scope.selectedItems = [];
84 96
85 $scope.updateResults(); 97 $scope.updateResults();
86 $scope.loadingMessage = ""; 98 $scope.loadingMessage = "";
87 $scope.windowTitle = "Current GM Results"; 99 $scope.windowTitle = "Current GM Results";
88 } 100 }
89 ).error( 101 ).error(
90 function(data, status, header, config) { 102 function(data, status, header, config) {
91 $scope.loadingMessage = "Failed to load results of type '" 103 $scope.loadingMessage = "Failed to load results of type '"
92 + resultsToLoad + "'"; 104 + resultsToLoad + "'";
93 $scope.windowTitle = "Failed to Load GM Results"; 105 $scope.windowTitle = "Failed to Load GM Results";
94 } 106 }
95 ); 107 );
96 108
97 $scope.isItemSelected = function(index) {
98 return (-1 != $scope.selectedItems.indexOf(index));
99 }
100 $scope.toggleItemSelected = function(index) {
101 var i = $scope.selectedItems.indexOf(index);
102 if (-1 == i) {
103 $scope.selectedItems.push(index);
104 } else {
105 $scope.selectedItems.splice(i, 1);
106 }
107 // unlike other toggle methods below, does not set
108 // $scope.areUpdatesPending = true;
109 }
110 109
111 $scope.isHiddenResultType = function(thisResultType) { 110 //
112 return (true == $scope.hiddenResultTypes[thisResultType]); 111 // Tab operations.
113 } 112 //
114 $scope.toggleHiddenResultType = function(thisResultType) {
115 if (true == $scope.hiddenResultTypes[thisResultType]) {
116 delete $scope.hiddenResultTypes[thisResultType];
117 } else {
118 $scope.hiddenResultTypes[thisResultType] = true;
119 }
120 $scope.areUpdatesPending = true;
121 }
122 113
123 // TODO(epoger): Rather than maintaining these as hard-coded 114 /**
124 // variants of isHiddenResultType and toggleHiddenResultType, we 115 * Change the selected tab.
125 // should create general-purpose functions that can work with ANY 116 *
126 // category. 117 * @param tab (string): name of the tab to select
127 // But for now, I wanted to see this working. :-) 118 */
128 $scope.isHiddenConfig = function(thisConfig) {
129 return (true == $scope.hiddenConfigs[thisConfig]);
130 }
131 $scope.toggleHiddenConfig = function(thisConfig) {
132 if (true == $scope.hiddenConfigs[thisConfig]) {
133 delete $scope.hiddenConfigs[thisConfig];
134 } else {
135 $scope.hiddenConfigs[thisConfig] = true;
136 }
137 $scope.areUpdatesPending = true;
138 }
139
140 $scope.setViewingTab = function(tab) { 119 $scope.setViewingTab = function(tab) {
141 $scope.viewingTab = tab; 120 $scope.viewingTab = tab;
142 $scope.updateResults(); 121 $scope.updateResults();
143 } 122 }
144 123
145 $scope.localTimeString = function(secondsPastEpoch) {
146 var d = new Date(secondsPastEpoch * 1000);
147 return d.toString();
148 }
149
150 /** 124 /**
151 * Move the items in $scope.selectedItems to a different tab, 125 * Move the items in $scope.selectedItems to a different tab,
152 * and then clear $scope.selectedItems. 126 * and then clear $scope.selectedItems.
153 * 127 *
154 * @param newTab (string): name of the tab to move the tests to 128 * @param newTab (string): name of the tab to move the tests to
155 */ 129 */
156 $scope.moveSelectedItemsToTab = function(newTab) { 130 $scope.moveSelectedItemsToTab = function(newTab) {
157 $scope.moveItemsToTab($scope.selectedItems, newTab); 131 $scope.moveItemsToTab($scope.selectedItems, newTab);
158 $scope.selectedItems = []; 132 $scope.selectedItems = [];
159 $scope.updateResults(); 133 $scope.updateResults();
(...skipping 10 matching lines...) Expand all
170 var itemIndex; 144 var itemIndex;
171 var numItems = itemIndices.length; 145 var numItems = itemIndices.length;
172 for (var i = 0; i < numItems; i++) { 146 for (var i = 0; i < numItems; i++) {
173 itemIndex = itemIndices[i]; 147 itemIndex = itemIndices[i];
174 $scope.numResultsPerTab[$scope.testData[itemIndex].tab]--; 148 $scope.numResultsPerTab[$scope.testData[itemIndex].tab]--;
175 $scope.testData[itemIndex].tab = newTab; 149 $scope.testData[itemIndex].tab = newTab;
176 } 150 }
177 $scope.numResultsPerTab[newTab] += numItems; 151 $scope.numResultsPerTab[newTab] += numItems;
178 } 152 }
179 153
154
155 //
156 // updateResults() and friends.
157 //
158
159 /**
160 * Set $scope.areUpdatesPending (to enable/disable the Update Results
161 * button).
162 *
163 * TODO(epoger): We could reduce the amount of code by just setting the
164 * variable directly (from, e.g., a button's ng-click handler). But when
165 * I tried that, the HTML elements depending on the variable did not get
166 * updated.
167 * It turns out that this is due to variable scoping within an ng-repeat
168 * element; see http://stackoverflow.com/questions/15388344/behavior-of-assi gnment-expression-invoked-by-ng-click-within-ng-repeat
169 *
170 * @param val boolean value to set $scope.areUpdatesPending to
171 */
172 $scope.setUpdatesPending = function(val) {
173 $scope.areUpdatesPending = val;
174 }
175
176 /**
177 * Update the displayed results, based on filters/settings.
178 */
180 $scope.updateResults = function() { 179 $scope.updateResults = function() {
181 $scope.displayLimit = $scope.displayLimitPending; 180 $scope.displayLimit = $scope.displayLimitPending;
182 // TODO(epoger): Every time we apply a filter, AngularJS creates 181 // TODO(epoger): Every time we apply a filter, AngularJS creates
183 // another copy of the array. Is there a way we can filter out 182 // another copy of the array. Is there a way we can filter out
184 // the items as they are displayed, rather than storing multiple 183 // the items as they are displayed, rather than storing multiple
185 // array copies? (For better performance.) 184 // array copies? (For better performance.)
186 185
187 if ($scope.viewingTab == $scope.defaultTab) { 186 if ($scope.viewingTab == $scope.defaultTab) {
188 $scope.filteredTestData = 187 $scope.filteredTestData =
189 $filter("orderBy")( 188 $filter("orderBy")(
(...skipping 12 matching lines...) Expand all
202 $filter("filter")( 201 $filter("filter")(
203 $scope.testData, 202 $scope.testData,
204 {tab: $scope.viewingTab}, 203 {tab: $scope.viewingTab},
205 true 204 true
206 ), 205 ),
207 $scope.sortColumn); 206 $scope.sortColumn);
208 $scope.limitedTestData = $filter("limitTo")( 207 $scope.limitedTestData = $filter("limitTo")(
209 $scope.filteredTestData, $scope.displayLimit); 208 $scope.filteredTestData, $scope.displayLimit);
210 } 209 }
211 $scope.imageSize = $scope.imageSizePending; 210 $scope.imageSize = $scope.imageSizePending;
212 $scope.areUpdatesPending = false; 211 $scope.setUpdatesPending(false);
213 } 212 }
214 213
214 /**
215 * Re-sort the displayed results.
216 *
217 * @param sortColumn (string): name of the column to sort on
218 */
215 $scope.sortResultsBy = function(sortColumn) { 219 $scope.sortResultsBy = function(sortColumn) {
216 $scope.sortColumn = sortColumn; 220 $scope.sortColumn = sortColumn;
217 $scope.updateResults(); 221 $scope.updateResults();
218 } 222 }
219 223
224
225 //
226 // Operations for sending info back to the server.
227 //
228
220 /** 229 /**
221 * Tell the server that the actual results of these particular tests 230 * Tell the server that the actual results of these particular tests
222 * are acceptable. 231 * are acceptable.
223 * 232 *
224 * @param testDataSubset an array of test results, most likely a subset of 233 * @param testDataSubset an array of test results, most likely a subset of
225 * $scope.testData (perhaps with some modifications) 234 * $scope.testData (perhaps with some modifications)
226 */ 235 */
227 $scope.submitApprovals = function(testDataSubset) { 236 $scope.submitApprovals = function(testDataSubset) {
228 $scope.submitPending = true; 237 $scope.submitPending = true;
229 var newResults = []; 238 var newResults = [];
(...skipping 29 matching lines...) Expand all
259 "the server side to the Skia repo.\n\n" + 268 "the server side to the Skia repo.\n\n" +
260 "Also: in order to see the complete updated data, or to submit " + 269 "Also: in order to see the complete updated data, or to submit " +
261 "more baselines, you will need to reload your client."); 270 "more baselines, you will need to reload your client.");
262 $scope.submitPending = false; 271 $scope.submitPending = false;
263 }).error(function(data, status, headers, config) { 272 }).error(function(data, status, headers, config) {
264 alert("There was an error submitting your baselines.\n\n" + 273 alert("There was an error submitting your baselines.\n\n" +
265 "Please see server-side log for details."); 274 "Please see server-side log for details.");
266 $scope.submitPending = false; 275 $scope.submitPending = false;
267 }); 276 });
268 } 277 }
278
279
280 //
281 // Operations we use to mimic Set semantics, in such a way that
282 // checking for presence within the Set is as fast as possible.
283 // But getting a list of all values within the Set is not necessarily
284 // possible.
285 // TODO(epoger): move into a separate .js file?
286 //
287
288 /**
289 * Returns true if value "value" is present within set "set".
290 *
291 * @param value a value of any type
292 * @param set an Object which we use to mimic set semantics
293 * (this should make isValueInSet faster than if we used an Array)
294 */
295 $scope.isValueInSet = function(value, set) {
296 return (true == set[value]);
297 }
298
299 /**
300 * If value "value" is already in set "set", remove it; otherwise, add it.
301 *
302 * @param value a value of any type
303 * @param set an Object which we use to mimic set semantics
304 */
305 $scope.toggleValueInSet = function(value, set) {
306 if (true == set[value]) {
307 delete set[value];
308 } else {
309 set[value] = true;
310 }
311 }
312
313
314 //
315 // Array operations; similar to our Set operations, but operate on a
316 // Javascript Array so we *can* easily get a list of all values in the Set.
317 // TODO(epoger): move into a separate .js file?
318 //
319
320 /**
321 * Returns true if value "value" is present within array "array".
322 *
323 * @param value a value of any type
324 * @param array a Javascript Array
325 */
326 $scope.isValueInArray = function(value, array) {
327 return (-1 != array.indexOf(value));
328 }
329
330 /**
331 * If value "value" is already in array "array", remove it; otherwise,
332 * add it.
333 *
334 * @param value a value of any type
335 * @param array a Javascript Array
336 */
337 $scope.toggleValueInArray = function(value, array) {
338 var i = array.indexOf(value);
339 if (-1 == i) {
340 array.push(value);
341 } else {
342 array.splice(i, 1);
343 }
344 }
345
346
347 //
348 // Miscellaneous utility functions.
349 // TODO(epoger): move into a separate .js file?
350 //
351
352 /**
353 * Returns a human-readable (in local time zone) time string for a
354 * particular moment in time.
355 *
356 * @param secondsPastEpoch (numeric): seconds past epoch in UTC
357 */
358 $scope.localTimeString = function(secondsPastEpoch) {
359 var d = new Date(secondsPastEpoch * 1000);
360 return d.toString();
361 }
362
269 } 363 }
270 ); 364 );
OLDNEW
« no previous file with comments | « no previous file | gm/rebaseline_server/static/view.css » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698