| <!DOCTYPE html> |
| <!-- |
| Copyright (c) 2015 The Chromium Authors. All rights reserved. |
| Use of this source code is governed by a BSD-style license that can be |
| found in the LICENSE file. |
| --> |
| <link rel="import" href="/tracing/base/xhr.html"> |
| <link rel="import" href="/tracing/ui/base/dom_helpers.html"> |
| <link rel="import" href="/tracing/ui/base/info_bar_group.html"> |
| <link rel="import" href="/tracing/ui/base/polymer_utils.html"> |
| <link rel="import" href="/perf_insights/ui/reports/pi_report.html"> |
| <link rel="import" href="/perf_insights/function_handle.html"> |
| <link rel="import" href="/perf_insights/ui/generic_results_view.html"> |
| |
| <polymer-element name="pi-ui-pi-app-main"> |
| <template> |
| <style> |
| :host { |
| display: flex; |
| flex-direction: column; |
| } |
| |
| top-controls { |
| display: flex; |
| flex: 0 0 auto; |
| background-color: rgb(236, 236, 236); |
| border-bottom: 1px solid #8e8e8e; |
| padding: 4px; |
| } |
| |
| top-controls > span.spacer { |
| flex: 1 1 auto; |
| } |
| |
| top-left-controls { |
| display: flex; |
| } |
| top-right-controls { |
| display: flex; |
| } |
| |
| report-container { |
| display: flex; |
| flex: 1 1 auto; |
| min-height: 0; |
| min-width: 0; |
| overflow: auto; |
| } |
| report-container > * { |
| flex: 1 1 auto; |
| } |
| </style> |
| <top-controls> |
| <top-left-controls id="top_left_controls"></top-left-controls> |
| <span class="spacer"></span> |
| <top-right-controls id="top_right_controls"></top-right-controls> |
| </top-controls> |
| <tr-ui-b-info-bar-group id="infobars"></tr-ui-b-info-bar-group> |
| <report-container id="report_container"></report-container> |
| </template> |
| </polymer-element> |
| <script> |
| 'use strict'; |
| |
| tr.exportTo('pi.ui', function() { |
| function areMappingStatesSame(a, b) { |
| for (var k in a) |
| if (a[k] !== b[k]) |
| return false; |
| return true; |
| } |
| |
| Polymer('pi-ui-pi-app-main', { |
| created: function() { |
| // Non-mapping state. |
| this.mapTracesDrivers_ = undefined; |
| |
| // Mapping state. |
| this.currentMapTracesDriver_ = undefined; |
| this.corpusQuery_ = undefined; |
| this.piReportElementName_ = undefined; |
| this.showRawResults_ = false; |
| }, |
| |
| ready: function() { |
| var topLeftControls = this.$.top_left_controls; |
| var topRightControls = this.$.top_right_controls; |
| |
| var mapTracesDriverSelector = document.createElement('select'); |
| mapTracesDriverSelector.classList.add('map-traces-driver-selector'); |
| // This selector is actually populated in the mapTracesDrivers setter. |
| topLeftControls.appendChild(mapTracesDriverSelector); |
| |
| var cannedCorpusQueries = [ |
| { |
| 'label': 'All traces', |
| 'value': 'True' |
| }, |
| { |
| 'label': 'At most one trace', |
| 'value': 'MAX_TRACE_HANDLES=1' |
| }, |
| { |
| 'label': 'At most two traces', |
| 'value': 'MAX_TRACE_HANDLES=2' |
| }, |
| { |
| 'label': 'At most 5 traces', |
| 'value': 'MAX_TRACE_HANDLES=5' |
| }, |
| { |
| 'label': 'At most 10 traces', |
| 'value': 'MAX_TRACE_HANDLES=10' |
| }, |
| { |
| 'label': 'At most 50 traces', |
| 'value': 'MAX_TRACE_HANDLES=50' |
| }, |
| { |
| 'label': 'At most 100 traces', |
| 'value': 'MAX_TRACE_HANDLES=100' |
| } |
| ]; |
| var corpusQuerySelector = tr.ui.b.createSelector( |
| this, 'corpusQuery', |
| 'pi.app_main.corpusQuery', |
| cannedCorpusQueries[0].value, |
| cannedCorpusQueries); |
| topLeftControls.appendChild(corpusQuerySelector); |
| |
| var piReportPolymerElementNames = tr.ui.b.getPolymerElementsThatSubclass( |
| 'pi-ui-r-pi-report'); |
| var piReportElementOptions = piReportPolymerElementNames.map( |
| function(peTagName) { |
| return { |
| label: peTagName, |
| value: peTagName |
| }; |
| }); |
| var reportSelector = tr.ui.b.createSelector( |
| this, 'piReportElementName', |
| 'pi.app_main.piReportElementName', |
| piReportElementOptions[0].value, |
| piReportElementOptions); |
| topLeftControls.appendChild(reportSelector); |
| |
| var showRawResultsCheckbox = tr.ui.b.createCheckBox( |
| this, 'showRawResults', |
| 'pi.app_main.showRawResults', false, |
| 'Show raw results'); |
| topRightControls.appendChild(showRawResultsCheckbox); |
| }, |
| |
| get mapTracesDrivers() { |
| return this.mapTracesDrivers_; |
| }, |
| |
| set mapTracesDrivers(mapTracesDrivers) { |
| this.mapTracesDrivers_ = mapTracesDrivers; |
| |
| var topLeftControls = this.$.top_left_controls; |
| var oldSelector = topLeftControls.querySelector( |
| '.map-traces-driver-selector'); |
| var options = mapTracesDrivers.map(function(mapTracesDriver) { |
| return { |
| label: mapTracesDriver.name, |
| value: mapTracesDriver |
| }; |
| }); |
| var newSelector = tr.ui.b.createSelector( |
| this, 'currentMapTracesDriver', |
| 'pi.app_main.currentMapTracesDriver', |
| options[0].value, |
| options); |
| newSelector.classList.add('map-traces-driver-selector'); |
| topLeftControls.replaceChild(newSelector, oldSelector); |
| }, |
| |
| |
| get mappingState() { |
| return { |
| currentMapTracesDriver: this.currentMapTracesDriver_, |
| corpusQuery: this.corpusQuery_, |
| piReportElementName: this.piReportElementName_, |
| showRawResults: this.showRawResults_ |
| }; |
| }, |
| |
| get currentMapTracesDriver() { |
| return this.currentMapTracesDriver_; |
| }, |
| |
| set currentMapTracesDriver(currentMapTracesDriver) { |
| this.currentMapTracesDriver_ = currentMapTracesDriver; |
| this.scheduleUpdateContents_(); |
| this.fire('ui-state-changed'); |
| }, |
| |
| get corpusQuery() { |
| return this.corpusQuery_; |
| }, |
| |
| set corpusQuery(corpusQuery) { |
| this.corpusQuery_ = corpusQuery; |
| this.scheduleUpdateContents_(); |
| this.fire('ui-state-changed'); |
| }, |
| |
| get piReportElementName() { |
| return this.piReportElementName_; |
| }, |
| |
| set piReportElementName(piReportElementName) { |
| this.piReportElementName_ = piReportElementName; |
| this.scheduleUpdateContents_(); |
| this.fire('ui-state-changed'); |
| }, |
| |
| get mapClientSide() { |
| return this.mapClientSide_; |
| }, |
| |
| set mapClientSide(mapClientSide) { |
| this.mapClientSide_ = mapClientSide; |
| this.scheduleUpdateContents_(); |
| this.fire('ui-state-changed'); |
| }, |
| |
| get showRawResults() { |
| return this.showRawResults_; |
| }, |
| |
| set showRawResults(showRawResults) { |
| this.showRawResults_ = showRawResults; |
| this.scheduleUpdateContents_(); |
| this.fire('ui-state-changed'); |
| }, |
| |
| scheduleUpdateContents_: function() { |
| if (this.pendingUpdateContentsPromise_) |
| return; |
| |
| var mappingState = this.mappingState; |
| |
| var p = this.beginUpdatingContents_(mappingState); |
| p = p.catch(function(err) { |
| tr.showPanic('Something is wrong', err); |
| }); |
| p = p.then(updateDone.bind(this)); |
| |
| function updateDone() { |
| this.pendingUpdateContentsPromise_ = undefined; |
| if (!areMappingStatesSame(this.mappingState, mappingState)) |
| this.scheduleUpdateContents_(); |
| } |
| this.pendingUpdateContentsPromise_ = p; |
| }, |
| |
| beginUpdatingContents_: function(mappingState) { |
| var pe = tr.ui.b.getPolymerElementNamed(mappingState.piReportElementName); |
| var reportContainer = this.$.report_container; |
| var infobars = this.$.infobars; |
| |
| function clearInfobarsOrUpdateWithErrors(mapResults) { |
| infobars.clearMessages(); |
| if (!mapResults) { |
| infobars.addMessage('Cannot map'); |
| return mapResults; |
| } |
| if (!mapResults.hadFailures) |
| return mapResults; |
| |
| function onTellMeMore() { |
| var dlg = new tr.ui.b.Overlay(); |
| dlg.dlg = 'Results summary'; |
| |
| var grv = document.createElement('pi-ui-generic-results-view'); |
| |
| grv.mapResults = mapResults; |
| grv.style.minHeight = '500px'; |
| dlg.appendChild(grv); |
| dlg.visible = true; |
| } |
| |
| var numFailedRuns = mapResults.failedRunInfos.length; |
| infobars.addMessage( |
| 'There were ' + numFailedRuns + ' traces that did not process.', |
| [ |
| { |
| buttonText: 'Tell me more...', |
| onClick: onTellMeMore |
| } |
| ]); |
| |
| return mapResults; |
| } |
| |
| var p = Promise.resolve(); |
| p = p.then(function indicateThinking() { |
| infobars.clearMessages(); |
| infobars.addMessage('... thinking...'); |
| }); |
| |
| p = p.then(function doMapping() { |
| if (mappingState.currentMapTracesDriver === undefined || |
| mappingState.piReportElementName === undefined || |
| mappingState.corpusQuery === undefined) { |
| return undefined; |
| } |
| |
| var mapFunctionName = pe.getAttribute('map-function-name'); |
| var mapFunctionHref = pe.getAttribute('map-function-href'); |
| var moduleToLoad = new pi.ModuleToLoad(mapFunctionHref); |
| var mapFunctionHandle = new pi.FunctionHandle([moduleToLoad], |
| mapFunctionName); |
| |
| if (mappingState.mapClientSide) { |
| throw new Error('Currently unsupported'); |
| } |
| return mappingState.currentMapTracesDriver(mapFunctionHandle, |
| mappingState.corpusQuery); |
| }); |
| p = p.then(function responseToResults(responseText) { |
| if (responseText === undefined) |
| return undefined; |
| |
| var data = JSON.parse(responseText); |
| return pi.r.Results.fromDict(data); |
| }); |
| |
| p = p.then(clearInfobarsOrUpdateWithErrors); |
| |
| p = p.then(function showMappingResults(mapResults) { |
| reportContainer.textContent = ''; |
| if (mapResults === undefined) |
| return; |
| |
| var reportEl; |
| if (mappingState.showRawResults) { |
| reportEl = document.createElement('pi-ui-generic-results-view'); |
| } else { |
| reportEl = document.createElement(mappingState.piReportElementName); |
| } |
| reportEl.mapResults = mapResults; |
| reportContainer.appendChild(reportEl); |
| }); |
| |
| return p; |
| } |
| }); |
| |
| return { |
| }; |
| }); |
| </script> |
| |