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

Side by Side Diff: dashboard/dashboard/elements/test-picker.html

Issue 2767433002: Start using /list_tests to populate subtest menus in test-picker (Closed)
Patch Set: working except for cleanup; need to port tests. Created 3 years, 9 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
« no previous file with comments | « no previous file | dashboard/dashboard/elements/test-picker-test.html » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 <!DOCTYPE html> 1 <!DOCTYPE html>
2 <!-- 2 <!--
3 Copyright 2016 The Chromium Authors. All rights reserved. 3 Copyright 2016 The Chromium Authors. All rights reserved.
4 Use of this source code is governed by a BSD-style license that can be 4 Use of this source code is governed by a BSD-style license that can be
5 found in the LICENSE file. 5 found in the LICENSE file.
6 --> 6 -->
7 7
8 <link rel="import" href="/components/iron-flex-layout/iron-flex-layout-classes.h tml"> 8 <link rel="import" href="/components/iron-flex-layout/iron-flex-layout-classes.h tml">
9 <link rel="import" href="/components/paper-button/paper-button.html"> 9 <link rel="import" href="/components/paper-button/paper-button.html">
10 <link rel="import" href="/components/paper-icon-button/paper-icon-button.html"> 10 <link rel="import" href="/components/paper-icon-button/paper-icon-button.html">
11 <link rel="import" href="/components/paper-progress/paper-progress.html"> 11 <link rel="import" href="/components/paper-progress/paper-progress.html">
12 12
13 <link rel="import" href="/dashboard/elements/autocomplete-box.html"> 13 <link rel="import" href="/dashboard/elements/autocomplete-box.html">
14 <link rel="import" href="/dashboard/static/simple_xhr.html"> 14 <link rel="import" href="/dashboard/static/simple_xhr.html">
15 15
16 <link rel="import" href="/tracing/base/base.html">
17
16 <dom-module id="test-picker"> 18 <dom-module id="test-picker">
17 <template> 19 <template>
18 <style include="iron-flex iron-flex-alignment"> 20 <style include="iron-flex iron-flex-alignment">
19 #container * { 21 #container * {
20 margin-right: 3px; 22 margin-right: 3px;
21 } 23 }
22 24
23 #dnd-btn { 25 #dnd-btn {
24 padding: 1px 2px; 26 padding: 1px 2px;
25 margin: 2px 4px 2px 2px; 27 margin: 2px 4px 2px 2px;
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
94 on-click="onAddButtonClicked" 96 on-click="onAddButtonClicked"
95 disabled$="{{!enableAddSeries}}">Add</paper-button> 97 disabled$="{{!enableAddSeries}}">Add</paper-button>
96 </div> 98 </div>
97 99
98 <div id="suite-description"></div> 100 <div id="suite-description"></div>
99 </template> 101 </template>
100 102
101 <script> 103 <script>
102 'use strict'; 104 'use strict';
103 105
106 // TODO(eakuefner): https://github.com/catapult-project/catapult/issues/3441
107 tr.exportTo('d', function() {
108 class Subtests {
109 constructor() {
110 this.subtests_ = new Map();
111 }
112
113 // TODO(eakuefner): implemement cancellation by wrapping
114 async getSubtestsForPath(path) {
115 if (this.subtests_.has(path)) {
116 return await this.subtests_.get(path);
117 }
118
119 const params = {
120 type: 'pattern'
121 };
122 params.p = `${path}/*`;
123 const fullSubtests = await simple_xhr.asPromise(
124 '/list_tests', params);
125 // TODO(eakuefner): Standardize logic for dealing with test paths on
126 // the client side. See
127 // https://github.com/catapult-project/catapult/issues/3443.
128 const subtests = [];
129 for (const fullSubtest of fullSubtests) {
130 subtests.push({
131 name: fullSubtest.substring(fullSubtest.lastIndexOf('/') + 1)});
132 }
133
134 this.subtests_[path] = subtests;
135 return subtests;
136 }
137
138 prepopulate(obj) {
139 for (const [path, subtests] of obj) {
140 this.subtests_.set(path, Promise.resolve(subtests));
141 }
142 }
143 }
144
145 return {Subtests};
146 });
147
104 Polymer({ 148 Polymer({
105 149
106 is: 'test-picker', 150 is: 'test-picker',
107 properties: { 151 properties: {
108 SUBTEST_LABEL: { 152 SUBTEST_LABEL: {
109 type: String, 153 type: String,
110 value: 'Subtest', 154 value: 'Subtest',
111 }, 155 },
112 DEPRECATED_TAG: { 156 DEPRECATED_TAG: {
113 type: String, 157 type: String,
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
147 disabled: false, 191 disabled: false,
148 }, 192 },
149 { 193 {
150 datalist: [], 194 datalist: [],
151 placeholder: 'Bot', 195 placeholder: 'Bot',
152 disabled: true, 196 disabled: true,
153 } 197 }
154 ]) 198 ])
155 }, 199 },
156 200
201 subtests: {
202 type: Object,
203 value: () => new d.Subtests()
204 },
205
157 xsrfToken: { notify: true } 206 xsrfToken: { notify: true }
158 207
159 }, 208 },
160 209
161 computeAnd: (x, y) => x && y, 210 computeAnd: (x, y) => x && y,
162 211
163 ready: function() { 212 ready: function() {
164 this.pageStateLoading = true; 213 this.pageStateLoading = true;
165 this.hasChart = false; 214 this.hasChart = false;
166 this.enableAddSeries = false; 215 this.enableAddSeries = false;
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
246 * Handles dropdown menu select; updates the subsequent menu accordingly. 295 * Handles dropdown menu select; updates the subsequent menu accordingly.
247 */ 296 */
248 onDropdownSelect: function(event) { 297 onDropdownSelect: function(event) {
249 var model = event.model; 298 var model = event.model;
250 var boxIndex = model.index; 299 var boxIndex = model.index;
251 if (boxIndex === undefined) { 300 if (boxIndex === undefined) {
252 return; 301 return;
253 } else if (boxIndex == 0) { 302 } else if (boxIndex == 0) {
254 this.updateTestSuiteDescription(); 303 this.updateTestSuiteDescription();
255 this.updateBotMenu(); 304 this.updateBotMenu();
256 } else if (boxIndex == 1) {
257 this.sendSubtestRequest();
258 } else { 305 } else {
259 // Update all the next dropdown menus for subtests. 306 // Update all the next dropdown menus for subtests.
260 this.updateSubtestMenus(boxIndex + 1); 307 this.updateSubtestMenus(boxIndex + 1);
261 } 308 }
262 }, 309 },
263 310
264 updateTestSuiteDescription: function() { 311 updateTestSuiteDescription: function() {
265 // Display the test suite description if there is one. 312 // Display the test suite description if there is one.
266 var descriptionElement = this.$['suite-description']; 313 var descriptionElement = this.$['suite-description'];
267 var suite = this.getSelectionMenu(0).selectedName; 314 var suite = this.getSelectionMenu(0).selectedName;
(...skipping 13 matching lines...) Expand all
281 }, 328 },
282 329
283 /** 330 /**
284 * Updates bot dropdown menu with bot items. 331 * Updates bot dropdown menu with bot items.
285 */ 332 */
286 updateBotMenu: function() { 333 updateBotMenu: function() {
287 var menu = this.getSelectionMenu(1); 334 var menu = this.getSelectionMenu(1);
288 var botItems = this.getBotItems(); 335 var botItems = this.getBotItems();
289 menu.set('items', botItems); 336 menu.set('items', botItems);
290 menu.set('disabled', botItems.length === 0); 337 menu.set('disabled', botItems.length === 0);
291 this.subtestDict = null; 338 // If there's a selection, update the subtest menus.
292 // If there's a selection, send a subtest request.
293 if (menu.selectedItem) { 339 if (menu.selectedItem) {
294 this.sendSubtestRequest(); 340 this.updateSubtestMenus(2);
295 } else { 341 } else {
296 // Clear all subtest menus. 342 // Clear all subtest menus.
297 this.splice('selectionModels', 2); 343 this.splice('selectionModels', 2);
298 } 344 }
299 this.updateAddButtonState(); 345 this.updateAddButtonState();
300 }, 346 },
301 347
302 /** 348 /**
303 * Sends a request for subtestDict base on selected test suite and bot.
304 */
305 sendSubtestRequest: function() {
306 if (this.subtestXhr) {
307 this.subtestXhr.abort();
308 this.subtestXhr = null;
309 }
310 var bot = this.getCheckedBot();
311 // If no bot is selected, just leave the current subtests.
312 if (bot === null) {
313 return;
314 }
315 var suite = this.getCheckedSuite();
316 if (!suite) {
317 return;
318 }
319
320 this.loading = true;
321
322 var params = {
323 type: 'sub_tests',
324 suite: suite,
325 bots: bot,
326 xsrf_token: this.xsrfToken
327 };
328 this.subtestXhr = simple_xhr.send(
329 '/list_tests',
330 params,
331 function(response) {
332 this.loading = false;
333 this.subtestDict = response;
334 // Start at first subtest menu.
335 this.updateSubtestMenus(2);
336 }.bind(this),
337 function(error) {
338 // TODO: Display error.
339 this.loading = false;
340 }.bind(this)
341 );
342 },
343
344 /**
345 * Updates all subtest menus starting at 'startIndex'. 349 * Updates all subtest menus starting at 'startIndex'.
346 */ 350 */
347 updateSubtestMenus: function(startIndex) { 351 updateSubtestMenus: async function(startIndex) {
348 var subtestDict = this.getSubtestAtIndex(startIndex); 352 let subtests = await this.subtests.getSubtestsForPath(
349 353 this.getCurrentSelectedPathUpTo(startIndex - 1));
350 // Update existing subtest menu. 354 // Update existing subtest menu.
351 for (var i = startIndex; i < this.selectionModels.length; i++) { 355 for (var i = startIndex; i < this.selectionModels.length; i++) {
352 // Remove the rest of the menu if no subtestDict. 356 // Remove the rest of the menu if no subtests.
353 if (!subtestDict || Object.keys(subtestDict).length == 0) { 357 if (subtests === []) {
354 this.splice('selectionModels', i); 358 this.splice('selectionModels', i);
355 this.updateAddButtonState(); 359 this.updateAddButtonState();
356 return; 360 return;
357 } 361 }
358 var subtestItems = this.getSubtestItems(subtestDict); 362 const menu = this.getSelectionMenu(i);
359 var menu = this.getSelectionMenu(i); 363 menu.set('items', subtests);
360 menu.set('items', subtestItems);
361 364
362 // If there are selected item, update next menu. 365 // If there are selected item, update next menu.
363 if (menu.selectedItem) { 366 if (menu.selectedItem) {
364 subtestDict = subtestDict[menu.selectedName]['sub_tests']; 367 subtests = await this.subtests.getSubtestsForPath(
368 this.getCurrentSelectedPathUpTo(i - 1, false));
365 } else { 369 } else {
366 subtestDict = null; 370 subtests = [];
367 } 371 }
368 } 372 }
369 373
370 // Check if we still need to add a subtest menu. 374 // If we reached the last iteration but still have subtests, that means
371 if (subtestDict && Object.keys(subtestDict).length > 0) { 375 // that means that the last extant subtest selection still has subtests
372 var subtestItems = this.getSubtestItems(subtestDict); 376 // and we need to put those in a new menu.
377 if (subtests !== []) {
373 this.push('selectionModels', { 378 this.push('selectionModels', {
374 placeholder: this.SUBTEST_LABEL, 379 placeholder: this.SUBTEST_LABEL,
375 datalist: subtestItems, 380 datalist: subtests,
376 disabled: false, 381 disabled: false,
377 }); 382 });
378 Polymer.dom.flush(); 383 Polymer.dom.flush();
379 var menu = this.getSelectionMenu(this.selectionModels.length - 1); 384 const menu = this.getSelectionMenu(this.selectionModels.length - 1);
380 menu.set('items', subtestItems); 385 menu.set('items', subtests);
381 } 386 }
382 387
383 this.updateAddButtonState(); 388 this.updateAddButtonState();
384 }, 389 },
385 390
386 updateAddButtonState: function() { 391 updateAddButtonState: function() {
387 this.enableAddSeries = this.getCurrentSelection() instanceof Array; 392 this.enableAddSeries = this.getCurrentSelection() instanceof Array;
388 }, 393 },
389 394
390 getSubtestAtIndex: function(index) {
391 var subtestDict = this.subtestDict;
392 for (var i = 2; i < index; i++) {
393 var test = this.getSelectionMenu(i).selectedName;
394 if (test in subtestDict) {
395 subtestDict = subtestDict[test]['sub_tests'];
396 } else {
397 return null;
398 }
399 }
400 return subtestDict;
401 },
402
403 getSubtestItems: function(subtestDict) {
404 var subtestItems = [];
405 var subtestNames = Object.keys(subtestDict).sort();
406 for (var i = 0; i < subtestNames.length; i++) {
407 var name = subtestNames[i];
408 subtestItems.push({
409 name: name,
410 tag: (subtestDict[name]['deprecated'] ? this.DEPRECATED_TAG : '')
411 });
412 }
413 return subtestItems;
414 },
415
416 getCheckedBot: function() { 395 getCheckedBot: function() {
417 var botMenu = this.getSelectionMenu(1); 396 var botMenu = this.getSelectionMenu(1);
418 if (botMenu.selectedItem) { 397 if (botMenu.selectedItem) {
419 let item = botMenu.selectedItem; 398 let item = botMenu.selectedItem;
420 return item['group'] + '/' + item['name']; 399 return item['group'] + '/' + item['name'];
421 } 400 }
422 return null; 401 return null;
423 }, 402 },
424 403
425 getCheckedSuite: function() { 404 getCheckedSuite: function() {
(...skipping 25 matching lines...) Expand all
451 */ 430 */
452 onAddButtonClicked: function(event, detail) { 431 onAddButtonClicked: function(event, detail) {
453 this.fire('add'); 432 this.fire('add');
454 }, 433 },
455 434
456 /** 435 /**
457 * Gets the current selection from the menus. Returns null unless there 436 * Gets the current selection from the menus. Returns null unless there
458 * is a valid selection. 437 * is a valid selection.
459 */ 438 */
460 getCurrentSelection: function() { 439 getCurrentSelection: function() {
461 var level = 0; 440 const path = this.getCurrentSelectedPathUpTo(-1, true);
462 var parts = []; 441
442 if (this.currentSelectedPath_ === path) {
443 return this.currentSelectedTests_;
444 }
445 this.sendListTestsRequest(path);
446 return null;
447 },
448
449 getCurrentSelectedPathUpTo: function(maxLevel, onlyValid) {
450 let level = 0;
451 const parts = [];
463 while (true) { 452 while (true) {
464 var menu = this.getSelectionMenu(level); 453 if (maxLevel !== -1 && level <= maxLevel) {
465 if (!menu || !menu.selectedItem) { 454 break;
455 }
456 const menu = this.getSelectionMenu(level);
457 if (onlyValid && (!menu || !menu.selectedItem)) {
466 // A selection is only valid if it specifies at least one subtest 458 // A selection is only valid if it specifies at least one subtest
467 // component, which is the third level. 459 // component, which is the third level.
468 if (level <= 2) return null; 460 if (level <= 2) return undefined;
469 break; 461 break;
470 } else { 462 } else {
471 // We want to collect all the subtest components so we can form 463 // We want to collect all the subtest components so we can form
472 // the full test path after this loop is done. 464 // the full test path after this loop is done.
473 if (level >= 2) parts.push(menu.selectedItem.name); 465 if (level >= 2) parts.push(menu.selectedItem.name);
474 } 466 }
475 level += 1; 467 level += 1;
476 } 468 }
477 469
478 var suite = this.getSelectionMenu(0).selectedItem.name; 470 const suite = this.getSelectionMenu(0).selectedItem.name;
479 var bot = this.getCheckedBot(); 471 const bot = this.getCheckedBot();
480 parts.unshift(suite); 472 parts.unshift(suite);
481 parts.unshift(bot); 473 parts.unshift(bot);
482 474
483 var path = parts.join('/'); 475 return parts.join('/');
484
485 if (this.currentSelectedPath_ === path)
486 return this.currentSelectedTests_;
487 this.sendListTestsRequest(path);
488 return null;
489 }, 476 },
490 477
491 getCurrentSelectedPath: function() { 478 getCurrentSelectedPath: function() {
492 return this.currentSelectedPath_; 479 return this.currentSelectedPath_;
493 }, 480 },
494 481
495 getCurrentUnselected: function() { 482 getCurrentUnselected: function() {
496 return this.currentUnselectedTests_; 483 return this.currentUnselectedTests_;
497 }, 484 },
498 485
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
576 * Converts a link in markdown format to a HTML link (anchor elements). 563 * Converts a link in markdown format to a HTML link (anchor elements).
577 * @param {string} text A link in markdown format. 564 * @param {string} text A link in markdown format.
578 * @return {string} A hyperlink string. 565 * @return {string} A hyperlink string.
579 */ 566 */
580 convertMarkdownLinks: function(text) { 567 convertMarkdownLinks: function(text) {
581 return text.replace(/\[(.+?)\]\((.+?)\)/g, '<a href="$2">$1</a>'); 568 return text.replace(/\[(.+?)\]\((.+?)\)/g, '<a href="$2">$1</a>');
582 } 569 }
583 }); 570 });
584 </script> 571 </script>
585 </dom-module> 572 </dom-module>
OLDNEW
« no previous file with comments | « no previous file | dashboard/dashboard/elements/test-picker-test.html » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698