• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1<!DOCTYPE html>
2<!--
3Copyright (c) 2015 The Chromium Authors. All rights reserved.
4Use of this source code is governed by a BSD-style license that can be
5found in the LICENSE file.
6-->
7<link rel="import" href="/perf_insights/function_handle.html">
8<link rel="import" href="/perf_insights/mre/job.html">
9<link rel="import" href="/perf_insights/mre/mre_result.html">
10<link rel="import" href="/perf_insights/ui/generic_results_view.html">
11<link rel="import" href="/perf_insights/ui/reports/pi_report.html">
12<link rel="import" href="/tracing/base/xhr.html">
13<link rel="import" href="/tracing/ui/base/dom_helpers.html">
14<link rel="import" href="/tracing/ui/base/info_bar_group.html">
15<link rel="import" href="/tracing/ui/base/polymer_utils.html">
16
17<polymer-element name="pi-ui-pi-app-main">
18  <template>
19    <style>
20      :host {
21        display: flex;
22        flex-direction: column;
23      }
24
25      top-controls {
26        display: flex;
27        flex: 0 0 auto;
28        background-color: rgb(236, 236, 236);
29        border-bottom: 1px solid #8e8e8e;
30        padding: 4px;
31      }
32
33      top-controls > span.spacer {
34        flex: 1 1 auto;
35      }
36
37      top-left-controls {
38        display: flex;
39      }
40      top-right-controls {
41        display: flex;
42      }
43
44      report-container {
45        display: flex;
46        flex: 1 1 auto;
47        min-height: 0;
48        min-width: 0;
49        overflow: auto;
50      }
51      report-container > * {
52        flex: 1 1 auto;
53      }
54    </style>
55    <top-controls>
56      <top-left-controls id="top_left_controls"></top-left-controls>
57      <span class="spacer"></span>
58      <top-right-controls id="top_right_controls"></top-right-controls>
59    </top-controls>
60    <tr-ui-b-info-bar-group id="infobars"></tr-ui-b-info-bar-group>
61    <report-container id="report_container"></report-container>
62  </template>
63</polymer-element>
64<script>
65'use strict';
66
67tr.exportTo('pi.ui', function() {
68  function areMappingStatesSame(a, b) {
69    for (var k in a)
70      if (a[k] !== b[k])
71        return false;
72    return true;
73  }
74
75  Polymer('pi-ui-pi-app-main', {
76    created: function() {
77      // Non-mapping state.
78      this.mapTracesDrivers_ = undefined;
79
80      // Mapping state.
81      this.currentMapTracesDriver_ = undefined;
82      this.corpusQuery_ = undefined;
83      this.piReportElementName_ = undefined;
84      this.showRawResults_ = false;
85    },
86
87    ready: function() {
88      var topLeftControls = this.$.top_left_controls;
89      var topRightControls = this.$.top_right_controls;
90
91      var piDriverPolymerElementNames = tr.ui.b.getPolymerElementsThatSubclass(
92          'pi-driver-base');
93      var piDriverElementOptions = piDriverPolymerElementNames.map(
94          function(peTagName) {
95            var pe = tr.ui.b.getPolymerElementNamed(peTagName);
96            return {
97              label: pe.getAttribute('display-name'),
98              value: peTagName
99            };
100          });
101
102      var driverSelector = tr.ui.b.createSelector(
103          this, 'currentMapTracesDriver',
104          'pi.app_main.currentMapTracesDriver',
105          piDriverElementOptions[0].value,
106          piDriverElementOptions);
107
108      topLeftControls.appendChild(driverSelector);
109
110      var corpusSelections = [
111        {
112          'label': 'Deep Reports',
113          'value': 'https://performance-insights.appspot.com'
114        },
115        {
116          'label': 'Bulk Reports',
117          'value': 'https://performance-insights.appspot.com'
118        }
119      ];
120      var corpusSelector = tr.ui.b.createSelector(
121          this, 'corpus',
122          'pi.app_main.corpus',
123          corpusSelections[0].value,
124          corpusSelections);
125      topLeftControls.appendChild(corpusSelector);
126
127      var corpusQuerySelector = tr.ui.b.createTextInput(
128          this, 'corpusQuery',
129          'pi.app_main.corpusQuery',
130          'MAX_TRACE_HANDLES=10');
131
132      var self = this;
133      function onQuerySelectorKeypress(e) {
134        var key = e.which || e.keyCode;
135        if (key === 13) { // 13 is enter
136            self.scheduleUpdateContents_();
137            self.fire('ui-state-changed');
138        }
139      }
140
141      corpusQuerySelector.addEventListener('keypress', onQuerySelectorKeypress);
142
143      corpusQuerySelector.style.width = '350px';
144      topLeftControls.appendChild(corpusQuerySelector);
145
146      var piReportPolymerElementNames = tr.ui.b.getPolymerElementsThatSubclass(
147          'pi-ui-r-pi-report');
148      var piReportElementOptions = piReportPolymerElementNames.map(
149          function(peTagName) {
150            return {
151              label: peTagName,
152              value: peTagName
153            };
154          });
155      var reportSelector = tr.ui.b.createSelector(
156          this, 'piReportElementName',
157          'pi.app_main.piReportElementName',
158          piReportElementOptions[0].value,
159          piReportElementOptions);
160      topLeftControls.appendChild(reportSelector);
161
162      var self = this;
163      function onProcessButton() {
164        self.scheduleUpdateContents_();
165        self.fire('ui-state-changed');
166      }
167
168      var processButton = tr.ui.b.createButton(
169          this, 'processButton',
170          'Process!', onProcessButton);
171      topLeftControls.appendChild(processButton);
172
173      var showRawResultsCheckbox = tr.ui.b.createCheckBox(
174          this, 'showRawResults',
175          'pi.app_main.showRawResults', false,
176          'Show raw results');
177      topRightControls.appendChild(showRawResultsCheckbox);
178    },
179
180    get mapTracesDrivers() {
181      return this.mapTracesDrivers_;
182    },
183
184    get mappingState() {
185      return {
186        currentMapTracesDriver: this.currentMapTracesDriver_,
187        corpusQuery: this.corpusQuery_,
188        piReportElementName: this.piReportElementName_,
189        showRawResults: this.showRawResults_
190      };
191    },
192
193    get currentMapTracesDriver() {
194      return this.currentMapTracesDriver_;
195    },
196
197    set currentMapTracesDriver(currentMapTracesDriver) {
198      this.currentMapTracesDriver_ = currentMapTracesDriver;
199    },
200
201    get corpusQuery() {
202      return this.corpusQuery_;
203    },
204
205    set corpusQuery(corpusQuery) {
206      this.corpusQuery_ = corpusQuery;
207    },
208
209    get piReportElementName() {
210      return this.piReportElementName_;
211    },
212
213    set piReportElementName(piReportElementName) {
214      this.piReportElementName_ = piReportElementName;
215    },
216
217    get mapClientSide() {
218      return this.mapClientSide_;
219    },
220
221    set mapClientSide(mapClientSide) {
222      this.mapClientSide_ = mapClientSide;
223    },
224
225    get showRawResults() {
226      return this.showRawResults_;
227    },
228
229    set showRawResults(showRawResults) {
230      this.showRawResults_ = showRawResults;
231    },
232
233    scheduleUpdateContents_: function() {
234      if (this.pendingUpdateContentsPromise_)
235        return;
236
237      var mappingState = this.mappingState;
238
239      var p = this.beginUpdatingContents_(mappingState);
240      p = p.catch(function(err) {
241        tr.showPanic('Something is wrong', err);
242      });
243      p = p.then(updateDone.bind(this));
244
245      function updateDone() {
246        this.pendingUpdateContentsPromise_ = undefined;
247        if (!areMappingStatesSame(this.mappingState, mappingState))
248          this.scheduleUpdateContents_();
249      }
250      this.pendingUpdateContentsPromise_ = p;
251    },
252
253    beginUpdatingContents_: function(mappingState) {
254      var pe = tr.ui.b.getPolymerElementNamed(mappingState.piReportElementName);
255      var reportContainer = this.$.report_container;
256      var infobars = this.$.infobars;
257
258      function clearInfobarsOrUpdateWithErrors(mapResults) {
259        infobars.clearMessages();
260        if (!mapResults) {
261          infobars.addMessage('Cannot map');
262          return mapResults;
263        }
264        if (!mapResults.some(function(r) { return r.hadFailures(); }))
265          return mapResults;
266
267        infobars.addMessage(
268            'Some traces that did not process.'
269            );
270
271        return mapResults;
272      }
273
274      var p = Promise.resolve();
275      p = p.then(function indicateThinking() {
276        infobars.clearMessages();
277        infobars.addMessage('... thinking...');
278      });
279
280      p = p.then(function doMapping() {
281        if (mappingState.currentMapTracesDriver === undefined ||
282            mappingState.piReportElementName === undefined ||
283            mappingState.corpusQuery === undefined) {
284          return undefined;
285        }
286        var mapFunctionName = pe.getAttribute('map-function-name');
287        var mapFunctionHref = pe.getAttribute('map-function-href');
288        var mapModuleToLoad = new pi.ModuleToLoad(mapFunctionHref);
289        var mapFunctionHandle = new pi.FunctionHandle(
290            [mapModuleToLoad], mapFunctionName);
291
292        var reduceFunctionName = pe.getAttribute('reduce-function-name');
293        var reduceFunctionHref = pe.getAttribute('reduce-function-href');
294        var reduceFunctionHandle;
295        if (reduceFunctionName && reduceFunctionHref) {
296          var reduceModuleToLoad = new pi.ModuleToLoad(reduceFunctionHref);
297          reduceFunctionHandle = new pi.FunctionHandle(
298              [reduceModuleToLoad], reduceFunctionName);
299        }
300
301        var job = new pi.mre.Job(mapFunctionHandle, reduceFunctionHandle);
302
303        if (mappingState.mapClientSide) {
304          throw new Error('Currently unsupported');
305        }
306
307        var peCurrentDriver = document.querySelector(
308            mappingState.currentMapTracesDriver);
309        return peCurrentDriver.runMapFunction(job, mappingState.corpusQuery);
310      });
311      p = p.then(function responseToResults(responseText) {
312        if (responseText === undefined)
313          return undefined;
314
315        var data = JSON.parse(responseText);
316        if (!data) {
317          return [];
318        } else {
319          return data.map(pi.mre.MreResult.fromDict);
320        }
321      });
322
323      p = p.then(clearInfobarsOrUpdateWithErrors);
324
325      p = p.then(function showMappingResults(mapResults) {
326        reportContainer.textContent = '';
327        if (mapResults === undefined)
328          return;
329
330        var reportEl;
331        if (mappingState.showRawResults) {
332          reportEl = document.createElement('pi-ui-generic-results-view');
333        } else {
334          reportEl = document.createElement(mappingState.piReportElementName);
335        }
336
337        reportEl.mapResults = mapResults;
338        reportContainer.appendChild(reportEl);
339      });
340
341      return p;
342    }
343  });
344
345  return {
346  };
347});
348</script>
349
350