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

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: 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 /**
epoger 2013/10/23 20:10:31 Combined these functions into generic versions and
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 * @param val boolean value to set $scope.areUpdatesPending to
164 */
165 $scope.setUpdatesPending = function(val) {
166 $scope.areUpdatesPending = val;
167 }
borenet 2013/10/23 20:31:46 Why is this helper function necessary?
epoger 2013/10/24 15:37:17 Great question. I didn't know why, but by asking
borenet 2013/10/28 12:57:09 Thanks for explaining. I don't think this is a TOD
168
169 /**
170 * Update the displayed results, based on filters/settings.
171 */
180 $scope.updateResults = function() { 172 $scope.updateResults = function() {
181 $scope.displayLimit = $scope.displayLimitPending; 173 $scope.displayLimit = $scope.displayLimitPending;
182 // TODO(epoger): Every time we apply a filter, AngularJS creates 174 // TODO(epoger): Every time we apply a filter, AngularJS creates
183 // another copy of the array. Is there a way we can filter out 175 // another copy of the array. Is there a way we can filter out
184 // the items as they are displayed, rather than storing multiple 176 // the items as they are displayed, rather than storing multiple
185 // array copies? (For better performance.) 177 // array copies? (For better performance.)
186 178
187 if ($scope.viewingTab == $scope.defaultTab) { 179 if ($scope.viewingTab == $scope.defaultTab) {
188 $scope.filteredTestData = 180 $scope.filteredTestData =
189 $filter("orderBy")( 181 $filter("orderBy")(
(...skipping 12 matching lines...) Expand all
202 $filter("filter")( 194 $filter("filter")(
203 $scope.testData, 195 $scope.testData,
204 {tab: $scope.viewingTab}, 196 {tab: $scope.viewingTab},
205 true 197 true
206 ), 198 ),
207 $scope.sortColumn); 199 $scope.sortColumn);
208 $scope.limitedTestData = $filter("limitTo")( 200 $scope.limitedTestData = $filter("limitTo")(
209 $scope.filteredTestData, $scope.displayLimit); 201 $scope.filteredTestData, $scope.displayLimit);
210 } 202 }
211 $scope.imageSize = $scope.imageSizePending; 203 $scope.imageSize = $scope.imageSizePending;
212 $scope.areUpdatesPending = false; 204 $scope.setUpdatesPending(false);
213 } 205 }
214 206
207 /**
208 * Re-sort the displayed results.
209 *
210 * @param sortColumn (string): name of the column to sort on
211 */
215 $scope.sortResultsBy = function(sortColumn) { 212 $scope.sortResultsBy = function(sortColumn) {
216 $scope.sortColumn = sortColumn; 213 $scope.sortColumn = sortColumn;
217 $scope.updateResults(); 214 $scope.updateResults();
218 } 215 }
219 216
217
218 //
219 // Operations for sending info back to the server.
220 //
221
220 /** 222 /**
221 * Tell the server that the actual results of these particular tests 223 * Tell the server that the actual results of these particular tests
222 * are acceptable. 224 * are acceptable.
223 * 225 *
224 * @param testDataSubset an array of test results, most likely a subset of 226 * @param testDataSubset an array of test results, most likely a subset of
225 * $scope.testData (perhaps with some modifications) 227 * $scope.testData (perhaps with some modifications)
226 */ 228 */
227 $scope.submitApprovals = function(testDataSubset) { 229 $scope.submitApprovals = function(testDataSubset) {
228 $scope.submitPending = true; 230 $scope.submitPending = true;
229 var newResults = []; 231 var newResults = [];
(...skipping 29 matching lines...) Expand all
259 "the server side to the Skia repo.\n\n" + 261 "the server side to the Skia repo.\n\n" +
260 "Also: in order to see the complete updated data, or to submit " + 262 "Also: in order to see the complete updated data, or to submit " +
261 "more baselines, you will need to reload your client."); 263 "more baselines, you will need to reload your client.");
262 $scope.submitPending = false; 264 $scope.submitPending = false;
263 }).error(function(data, status, headers, config) { 265 }).error(function(data, status, headers, config) {
264 alert("There was an error submitting your baselines.\n\n" + 266 alert("There was an error submitting your baselines.\n\n" +
265 "Please see server-side log for details."); 267 "Please see server-side log for details.");
266 $scope.submitPending = false; 268 $scope.submitPending = false;
267 }); 269 });
268 } 270 }
271
272
273 //
274 // Operations we use to mimic Set semantics, in such a way that
275 // checking for presence within the Set is as fast as possible.
276 // But getting a list of all values within the Set is not necessarily
277 // possible.
278 // TODO(epoger): move into a separate .js file?
279 //
280
281 /**
282 * Returns true if value "value" is present within set "set".
283 *
284 * @param value a value of any type
285 * @param set an Object which we use to mimic set semantics
286 * (this should make isValueInSet faster than if we used an Array)
287 */
288 $scope.isValueInSet = function(value, set) {
289 return (true == set[value]);
290 }
291
292 /**
293 * If value "value" is already in set "set", remove it; otherwise, add it.
294 *
295 * @param value a value of any type
296 * @param set an Object which we use to mimic set semantics
297 */
298 $scope.toggleValueInSet = function(value, set) {
299 if (true == set[value]) {
300 delete set[value];
301 } else {
302 set[value] = true;
303 }
304 }
305
306
307 //
308 // Array operations; similar to our Set operations, but operate on a
309 // Javascript Array so we *can* easily get a list of all values in the Set.
310 // TODO(epoger): move into a separate .js file?
311 //
312
313 /**
314 * Returns true if value "value" is present within array "array".
315 *
316 * @param value a value of any type
317 * @param array a Javascript Array
318 */
319 $scope.isValueInArray = function(value, array) {
320 return (-1 != array.indexOf(value));
321 }
322
323 /**
324 * If value "value" is already in array "array", remove it; otherwise,
325 * add it.
326 *
327 * @param value a value of any type
328 * @param array a Javascript Array
329 */
330 $scope.toggleValueInArray = function(value, array) {
331 var i = array.indexOf(value);
332 if (-1 == i) {
333 array.push(value);
334 } else {
335 array.splice(i, 1);
336 }
337 }
338
339
340 //
341 // Miscellaneous utility functions.
342 // TODO(epoger): move into a separate .js file?
343 //
344
345 /**
346 * Returns a human-readable (in local time zone) time string for a
347 * particular moment in time.
348 *
349 * @param secondsPastEpoch (numeric): seconds past epoch in UTC
350 */
351 $scope.localTimeString = function(secondsPastEpoch) {
352 var d = new Date(secondsPastEpoch * 1000);
353 return d.toString();
354 }
355
269 } 356 }
270 ); 357 );
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