5 <title>WebKit Performance Monitor (Beta)</title>
7 <link rel="prefetch" href="../data/manifest.json">
8 <script type="application/json" src="../data/manifest.json"></script>
10 <link rel="stylesheet" href="app.css">
11 <link rel="stylesheet" href="chart-pane.css">
13 <script src="js/jquery.min.js" defer></script>
14 <script src="js/jquery.min.js" defer></script>
15 <script src="js/handlebars.js" defer></script>
16 <script src="js/ember.js" defer></script>
17 <script src="js/ember-data.js" defer></script>
18 <script src="js/d3/d3.min.js" defer></script>
19 <script src="js/statistics.js" defer></script>
20 <script src="data.js" defer></script>
21 <script src="app.js" defer></script>
22 <script src="manifest.js" defer></script>
23 <script src="analysis.js" defer></script>
24 <script src="popup.js" defer></script>
25 <script src="interactive-chart.js" defer></script>
26 <script src="commits-viewer.js" defer></script>
28 <script type="text/x-handlebars" data-template-name="dashboard">
31 {{view App.NumberOfDaysControlView tagName="ul" numberOfDays=numberOfDays}}
34 <a href="javascript:false" class="control-button" {{action toggleEditMode}}>
35 {{#if controller.editMode}}
45 <table {{bind-attr class=":dashboard editMode:editMode:readonly"}}>
49 {{#each headerColumns}}
50 {{#if controller.editMode}}
52 <a href="javascript:false" title="Remove column" {{action "removeColumn" index}}>
53 {{partial "close-button"}}
61 {{#if controller.editMode}}
62 <td>{{input value=newColumnHeader action="addColumn" placeholder="Add a column"}}</td>
69 {{#if controller.editMode}}
71 <a href="javascript:false" title="Remove row" {{action "removeRow" this}}>
72 {{partial "close-button"}}
74 {{input value=header}}
77 <th><span class="label">{{header}}</span></th>
82 {{#if controller.editMode}}
83 {{view App.PopupView list=pickerData label='Choose'}}
87 <div class="dashboard-status">
89 {{latestStatus.currentValue}}{{chartData.unit}}
90 {{#if latestStatus.label}}
91 <span {{bind-attr class=":status-label latestStatus.className"}}>{{latestStatus.label}}</span>
95 {{#link-to 'charts' (query-params paneList=paneList since=controller.since)}}
98 domain=controller.sharedDomain
99 enableSelection=false}}
103 <div class="failure">{{failure}}</div>
105 <div class="progress">{{partial "spinner"}}</div>
108 {{#if controller.editMode}}
109 <a href="javascript:false" title="Reset pane" class="reset" {{action "resetPane" this}}>
110 {{partial "close-button"}}
116 {{#if controller.editMode}}
121 {{#if controller.editMode}}
123 <td>{{input value=newRowHeader action="addRow" placeholder="Add a row"}}</td>
134 <script type="text/x-handlebars" data-template-name="charts">
137 <ul class="controls">
138 <li>{{view App.PopupView list=platforms label='Add pane'}}</li>
140 <ul class="controls">
141 <li>{{view App.StartTimeSliderView startTime=startTime oldestStartTime=oldestStartTime}}</li>
145 {{#each panes itemController="pane"}}
146 <section class="chart-pane in-charts" tabindex="0">
148 <h1 {{action "toggleDetails"}}>{{metric.fullName}} - {{platform.name}}</h1>
149 <a href="javascript:false" title="Close" class="close-button" {{action "close"}}>{{partial "close-button"}}</a>
150 {{#if movingAverageStrategies}}
151 <a href="javascript:false" title="Statistical Tools" class="stat-button" {{action "toggleStatPane"}}>{{partial "stat-button"}}</a>
153 <a href="javascript:false" {{bind-attr title=showOutlierTitle class=":outlier-button showOutlier:show:hide"}}
154 {{action "toggleShowOutlier"}}>
155 {{partial "outlier-button"}}
157 <a href="javascript:false" title="Analyze the selected range" class="analysis-button" {{action "toggleBugsPane"}}>
158 {{partial "analysis-button"}}
160 {{#if App.Manifest.repositoriesWithReportedCommits}}
161 <a href="javascript:false" title="Search commits by a keyword" class="search-button" {{action "toggleSearchPane"}}>{{partial "search-button"}}</a>
166 <div class="svg-container">
171 domain=mainPlotDomain
174 currentItem=hoveredOrSelectedItem
175 currentTime=sharedTime
176 selectedItem=selectedItem
177 highlightedItems=highlightedItems
178 rangeRoute="analysisTask"
180 selectedPoints=selectedPoints
181 showFullYAxis=showFullYAxis
186 <div class="failure">{{failure}}</div>
188 <div class="progress">{{partial "spinner"}}</div>
192 <div class="details">
193 <div class="overview">
198 domain=overviewDomain
199 selection=overviewSelection}}
202 <div class="details-table-container">
203 {{partial "chart-details"}}
208 <div {{bind-attr class=":popup-pane :analysis-pane showingAnalysisPane::hidden"}}>
209 <section class="analysis-option-option">
210 <h1>Start A/B testing or associate bugs</h1>
211 <label>Name: {{input type=text value=newAnalysisTaskName}} <button {{action "createAnalysisTask"}} {{bind-attr disabled=cannotAnalyze}}>Analyze</button></label>
213 <section class="analysis-option-option">
214 <h1>Marking outliers</h1>
215 <label>{{input type=checkbox checked=selectedItemIsMarkedOutlier disabled=cannotMarkOutlier}} Mark as an outlier and hide it.</label>
219 <form {{bind-attr class=":popup-pane :search-pane showingSearchPane::hidden"}}>
220 <span class="repositories">
222 content=App.Manifest.repositoriesWithReportedCommits
223 optionValuePath='content.id'
224 optionLabelPath='content.name'
225 selection=commitSearchRepository}}
227 {{input action="searchCommit" placeholder="Name or email" value=commitSearchKeyword}}
230 {{partial "stat-pane"}}
232 <nav class="alternative-pane-actions">
234 {{#each alternativePanes}}
235 <li><a href="javascript:false" {{action "addAlternativePanes" pane platform metrics}}>{{label}}</a></li>
243 <script type="text/x-handlebars" data-template-name="components/interactive-chart">
245 <div class="selection-toolbar" style="display: none;">
246 <a href="javascript:false" class="button" {{action "zoom"}}>
247 <svg class="zoom" viewBox="0 0 100 100">
248 <g stroke-width="0" stroke="none">
249 <polygon points="25,25 5,50 25,75"/>
250 <polygon points="75,25 95,50 75,75"/>
252 <line x1="20" y1="50" x2="80" y2="50" stroke-width="10"></line>
257 <div class="rangeBarsContainerInlineStyle">
259 {{#link-to linkRoute linkId title=label}}
260 <span {{bind-attr class=":rangeBar status" style=inlineStyle}}></span>
266 <script type="text/x-handlebars" data-template-name="chart-details">
268 <table class="details-table">
270 {{#each details.bugTrackers}}
276 <a {{bind-attr href=bugUrl}} target="_blank">{{bugNumber}}</a>
282 <tbody class="status">
286 {{details.status.currentValue}} {{chartData.unit}}
287 {{#if details.status.valueDelta}}
288 ({{details.status.valueDelta}} {{chartData.unit}} / {{details.status.relativeDelta}})
290 {{#if details.status.label}}
292 <span {{bind-attr class=details.status.className}}>{{details.status.label}}</span>
298 {{#if details.buildNumber}}
302 {{#if details.buildURL}}
303 <a {{bind-attr href=details.buildURL}} target="_blank">{{details.buildNumber}}</a>
305 {{details.buildNumber}}
307 ({{details.buildTime}})
311 {{#each details.revisions}}
316 <a {{bind-attr href=url}} target="_blank">{{label}}</a>
325 <div class="commits">
326 {{#each details.revisions}}
327 {{commits-viewer repository=repository revisionInfo=this caption=name}}
333 <script type="text/x-handlebars" data-template-name="components/commits-viewer">
335 <table {{bind-attr class=":commits-viewer visible::hidden"}}>
337 <caption {{action toggleVisibility}}>{{caption}} commits</caption>
345 <a {{bind-attr href=url}} target="_blank">{{revision}}</a>
360 <script type="text/x-handlebars" data-template-name="close-button">
361 <svg class="close-button icon-button" viewBox="0 0 100 100">
362 <g stroke="black" stroke-width="10">
363 <circle cx="50" cy="50" r="45" fill="transparent"/>
364 <polygon points="30,30 70,70" />
365 <polygon points="30,70 70,30" />
370 <script type="text/x-handlebars" data-template-name="stat-button">
371 <svg class="stat-button icon-button" viewBox="10 0 110 100">
372 <g stroke="none" stroke-width="0" fill="black">
373 <path id="upper-sigma" d="M 5 5 H 95 V 40 h -10 c -5 -20 -5 -20 -25 -20 H 35 L 60 50 l -20 0" />
374 <use xlink:href="#upper-sigma" transform="translate(0, 100) scale(1, -1)" />
379 <script type="text/x-handlebars" data-template-name="stat-pane">
380 <section {{bind-attr class=":popup-pane :stat-pane showingStatPane::hidden"}}>
381 <section class="stat-option">
382 <h1>Moving average</h1>
383 <label>Type: {{view Ember.Select
384 content=movingAverageStrategies
385 optionValuePath='content'
386 optionLabelPath='content.label'
387 selection=chosenMovingAverageStrategy}}</label>
388 {{#if chosenMovingAverageStrategy.description}}
389 <p class="description">{{chosenMovingAverageStrategy.description}}</p>
391 {{#each chosenMovingAverageStrategy.parameterList}}
392 <label>{{label}}: {{input type="number" value=value min=min max=max step=step}}</label>
395 {{#if chosenMovingAverageStrategy.execute}}
396 <section class="stat-option">
398 <label>Type: {{view Ember.Select
399 content=envelopingStrategies
400 optionValuePath='content'
401 optionLabelPath='content.label'
402 selection=chosenEnvelopingStrategy}}</label>
403 {{#if chosenEnvelopingStrategy.description}}
404 <p class="description">{{chosenEnvelopingStrategy.description}}</p>
406 {{#each chosenEnvelopingStrategy.parameterList}}
407 <label>{{label}}: <input type="number" {{bind-attr value=value min=min max=max step=step}}></label>
411 {{#if chosenMovingAverageStrategy.isSegmentation}}
412 <section class="stat-option">
413 <h1>A/B Test Range Selection</h1>
414 <label>Type: {{view Ember.Select
415 content=testRangeSelectionStrategies
416 optionValuePath='content'
417 optionLabelPath='content.label'
418 selection=chosenTestRangeSelectionStrategy}}</label>
419 {{#if chosenTestRangeSelectionStrategy.description}}
420 <p class="description">{{chosenTestRangeSelectionStrategy.description}}</p>
424 {{#if chosenEnvelopingStrategy.execute}}
425 <section class="stat-option">
426 <h1>Anomaly Detection</h1>
427 {{#each anomalyDetectionStrategies}}
428 <label {{bind-attr title=description}}>{{input type="checkbox" name=id checked=enabled}}{{label}}</label>
435 <script type="text/x-handlebars" data-template-name="outlier-button">
436 <svg class="outlier-button icon-button" viewBox="0 0 100 100">
437 <g stroke="black" fill="black" stroke-width="15">
438 <line x1="0" y1="70" x2="40" y2="70"/>
439 <circle cx="15" cy="70" r="8"/>
440 <circle cx="45" cy="70" r="8"/>
441 <circle cx="85" cy="70" r="8"/>
442 <line x1="85" y1="70" x2="100" y2="70"/>
443 <g class="show-outlier-icon">
444 <line x1="45" y1="70" x2="65" y2="20"/>
445 <line x1="65" y1="20" x2="85" y2="70"/>
446 <circle cx="65" cy="20" r="8"/>
448 <g class="hide-outlier-icon">
449 <line x1="45" y1="70" x2="85" y2="70"/>
455 <script type="text/x-handlebars" data-template-name="analysis-button">
456 <svg class="analysis-button icon-button" viewBox="0 0 100 100">
457 <g stroke="black" fill="black" stroke-width="15">
458 <circle cx="50" cy="50" r="40" fill="transparent"/>
459 <line x1="50" y1="25" x2="50" y2="55"/>
460 <circle cx="50" cy="67.5" r="10" stroke="none"/>
465 <script type="text/x-handlebars" data-template-name="search-button">
466 <svg class="search-button icon-button" viewBox="0 0 100 100">
467 <g stroke="black" stroke-width="15">
468 <circle cx="60" cy="40" r="30" fill="transparent"/>
469 <line x1="10" y1="90" x2="40" y2="60"/>
474 <script type="text/x-handlebars" data-template-name="spinner">
475 <svg class="spinner" viewBox="0 0 100 100">
476 <line x1="10" y1="50" x2="30" y2="50" stroke="black" stroke-width="10" stroke-linecap="round"/>
477 <line x1="21.72" y1="21.72" x2="35.86" y2="35.86" stroke="black" stroke-width="10" stroke-linecap="round"/>
478 <line x1="50" y1="10" x2="50" y2="30" stroke="black" stroke-width="10" stroke-linecap="round"/>
479 <line x1="78.28" y1="21.72" x2="64.14" y2="35.86" stroke="black" stroke-width="10" stroke-linecap="round"/>
480 <line x1="70" y1="50" x2="90" y2="50" stroke="black" stroke-width="10" stroke-linecap="round"/>
481 <line x1="65.86" y1="65.86" x2="78.28" y2="78.28" stroke="black" stroke-width="10" stroke-linecap="round"/>
482 <line x1="50" y1="70" x2="50" y2="90" stroke="black" stroke-width="10" stroke-linecap="round"/>
483 <line x1="21.72" y1="78.28" x2="35.86" y2="65.86" stroke="black" stroke-width="10" stroke-linecap="round"/>
487 <script type="text/x-handlebars" data-template-name="navbar">
488 <nav id="navigation" role="navigation">
489 <h1><a href="#">WebKit Perf Monitor</a></h1>
491 {{#each App.Manifest.dashboards}}
493 {{#link-to 'dashboard' name tagName='li'}}
494 {{#link-to 'dashboard' name}}{{label}}{{/link-to}}
498 {{#link-to 'charts' tagName='li'}}
499 {{#link-to 'charts'}}Charts{{/link-to}}
501 {{#link-to 'analysis' tagName='li'}}
502 {{#link-to 'analysis'}}Analysis{{/link-to}}
508 <script type="text/x-handlebars" data-template-name="number-of-days-controls">
509 <li class="numberOfDaysIs1">
510 <a href="javascript:false" class="control-button" {{action "setNumberOfDays" 1}}>1D</a>
512 <li class="numberOfDaysIs7">
513 <a href="javascript:false" class="control-button" {{action "setNumberOfDays" 7}}>1W</a>
515 <li class="numberOfDaysIs30">
516 <a href="javascript:false" class="control-button" {{action "setNumberOfDays" 30}}>1M</a>
518 <li class="numberOfDaysIs90">
519 <a href="javascript:false" class="control-button" {{action "setNumberOfDays" 90}}>3M</a>
521 <li class="numberOfDaysIs183">
522 <a href="javascript:false" class="control-button" {{action "setNumberOfDays" 183}}>6M</a>
524 <li class="numberOfDaysIs365">
525 <a href="javascript:false" class="control-button" {{action "setNumberOfDays" 365}}>1Y</a>
529 <script type="text/x-handlebars" data-template-name="start-time-slider">
530 <label><input type="range"> <span class="numberOfDays">X</span> days</label>
533 <script type="text/x-handlebars" data-template-name="popup">
534 <span class="label">{{view App.PopupButtonView tagName="a" label=view.label }}</span>
535 {{view view.popupListContainerView viewName="popupListContainerViewInstance"}}
538 <script type="text/x-handlebars" data-template-name="popup-list">
542 {{else }} {{#if children}}
543 <li>{{view App.PopupView list=children label=label}}</li>
547 <a href="javascript:false" class="label" {{action actionName actionArgument}}>{{label}}</a>
549 <a class="label">{{label}}</a>
556 <script type="text/x-handlebars" data-template-name="analysis">
561 <table id="analysis-tasks">
573 {{#each model.tasks}}
575 <td class="task-name">{{#link-to 'analysisTask' id}}{{name}}{{/link-to}}</td>
576 <td class="status">{{statusLabel}}</td>
577 <td class="author">{{author}}</td>
578 <td class="created-at">{{formattedCreatedAt}}</td>
579 <td class="platform-name">{{platform.label}}</td>
580 <td class="test-name">{{metric.fullName}}</td>
587 <script type="text/x-handlebars" data-template-name="analysisTask">
592 <h2 id="analysis-task-title">{{label}}</h2>
593 {{#if platform.label}}
594 <h3 id="analysis-task-testname">{{metric.fullName}} - {{platform.label}}</h3>
598 <section class="analysis-chart-pane chart-pane" tabindex="0">
599 <div class="svg-container">
601 chartData=pane.chartData
603 domain=overviewDomain
606 currentItem=pane.hoveredOrSelectedItem
607 selectedPoints=pane.selectedPoints
609 highlightedItems=highlightedItems
610 rangeRoute="analysisTask"}}
612 <div class="details">
613 <div class="details-table-container">
615 {{partial "chart-details"}}
617 {{partial "analysisStatusForm"}}
624 {{partial "testGroupForm"}}
626 {{#each testGroupPanes}}
627 {{partial "testGroup"}}
631 <script type="text/x-handlebars" data-template-name="testGroup">
632 <section class="analysis-group">
634 <div class="table-container">
635 <table class="results">
638 <td colspan="2">Configuration</td>
641 {{#each repositories}}
646 {{#each configurations}}
647 <tbody {{bind-attr class="showRequestList::hideRequests"}}>
648 <tr class="summary" {{action toggleShowRequestList this}}>
649 <td class="config-letter" colspan="2">{{summary.configLetter}}</td>
651 {{partial "testGroupRow"}}
657 <td class="config-letter" {{action toggleShowRequestList this}}></td>
659 <td>Run {{orderLabel}}</td>
660 {{partial "testGroupRow"}}
665 {{#each comparisons}}
668 <td colspan="2">{{label}}</td>
669 <td>{{difference}}</td>
672 {{#each repositories}}
681 <div class="reference-chart">
682 {{#if referenceChart}}
684 chartData=referenceChart.data
685 domain=overviewDomain
688 enableSelection=false
689 highlightedItems=referenceChart.highlightedItems}}
695 <script type="text/x-handlebars" data-template-name="testGroupRow">
698 {{box-plot range=valueRange value=value delta=delta}}
703 <a {{bind-attr href=url title=buildLabel}}>{{statusLabel}}</a>
705 {{#each revisionList}}
710 <script type="text/x-handlebars" data-template-name="testGroupForm">
711 {{#if rootConfigurations}}
712 <form method="POST" {{action "createTestGroup" newTestGroupName repetitionCount on="submit"}}>
713 <section class="analysis-group">
714 <h1>{{input name="name" value=newTestGroupName placeholder="Test group name" required=true type="text"}}</h1>
718 <th>Configuration</th>
719 {{#each configurations}}
725 {{#each rootConfigurations}}
729 <td>{{view Ember.Select name=name content=options
730 optionValuePath="content.value" optionLabelPath="content.label"
731 selection=selection}}</td>
737 <label>Number of runs {{view Ember.Select content=possibleRepetitionCounts value=repetitionCount}}</label>
738 <button type="submit">Start A/B testing</button>
744 <script type="text/x-handlebars" data-template-name="analysisStatusForm">
745 <table class="analysis-bugs">
749 <th>{{bugTracker.name}}</th>
751 <a {{bind-attr href=url}} target="_blank">{{number}}</a>
752 <a href="javascript:false" {{action "deleteBug" this}}>{{partial "close-button"}}</a>
759 {{view Ember.Select content=bugTrackers optionValuePath="content" optionLabelPath="content.name" value=chosenBugTracker}}
762 {{input id=elementId type=text value=editedBugNumber}}
763 <button {{action "addBug" chosenBugTracker editedBugNumber}}>Add</button>
770 <th><label for="analysis-status">Status<label></th>
772 <form class="analysis-bugs" {{action "saveStatus" on="submit"}}>
773 {{view Ember.Select id="analysis-status" content=analysisResultOptions optionValuePath="content"
774 optionLabelPath="content.label" selection=chosenAnalysisResult}}
775 <input type="submit" value="Save"><br>
776 <label {{bind-attr class="needsFeedback::hidden"}}>{{input type=checkbox checked=notNeeded}} This should not have been created</label>