- Websites/perf.webkit.org/ChangeLog +59 lines
Lines 1-3 Websites/perf.webkit.org/ChangeLog_sec1
1
2015-02-06  Ryosuke Niwa  <rniwa@webkit.org>
2
3
        New perf dashboard should have multiple dashboard pages
4
        https://bugs.webkit.org/show_bug.cgi?id=141339
5
6
        Reviewed by NOBODY (OOPS!).
7
8
        Added the support for multiple dashboard pages. Also added the status of the latest data point.
9
        e.g. "5% better than target"
10
11
        * public/v2/app.css: Tweaked the styles to work around the fact Ember.js creates empty script elements.
12
        Also hid the border lines around charts on the dashboard page for a cleaner look.
13
14
        * public/v2/app.js:
15
        (App.IndexRoute): Added. Navigate to /dashboard/<defaultDashboardName> once the manifest.json is loaded.
16
        (App.IndexRoute.beforeModel): Added.
17
        (App.DashboardRoute): Added.
18
        (App.DashboardRoute.model): Added. Return the dashboard specified by the name.
19
        (App.CustomDashboardRoute): Added. This route is used for a customized dashboard specified by "grid".
20
        (App.CustomDashboardRoute.model): Create a dashboard model from "grid" query parameter.
21
        (App.CustomDashboardRoute.renderTemplate): Use the dashboard template.
22
        (App.DashboardController): Renamed from App.IndexController.
23
        (App.DashboardController.modelChanged): Renamed from gridChanged. Removed the code to deal with "grid"
24
        and "defaultDashboard" as these are taken care of by newly added routers.
25
        (App.DashboardController.computeGrid): Renamed from updateGrid. No longer updates "grid" since this is
26
        now done in actions.toggleEditMode.
27
        (App.DashboardController.actions.toggleEditMode): Navigate to CustomDashboardRoute when start editing
28
        an existing dashboard.
29
30
        (App.Pane.computeStatus): Moved from App.PaneController so that to be called in App.Pane.latestStatus.
31
        Also moved the code to compute the delta with respect to the previous data point from _updateDetails.
32
        (App.Pane._relativeDifferentToLaterPointInTimeSeries): Ditto.
33
        (App.Pane.latestStatus): Added. Used by the dashboard template to show the status of the latest result.
34
35
        (App.createChartData): Added deltaFormatter to show less significant digits for differences.
36
37
        (App.PaneController._updateDetails): Updated per changes to computeStatus.
38
39
        * public/v2/chart-pane.css: Added style rules for the status labels on the dashboard.
40
41
        * public/v2/data.js:
42
        (TimeSeries.prototype.lastPoint): Added.
43
44
        * public/v2/index.html: Prefetch manifest.json as soon as possible, show the latest data points' status
45
        on the dashboard, and enumerate all predefined dashboards.
46
47
        * public/v2/interactive-chart.js:
48
        (App.InteractiveChartComponent._relayoutDataAndAxes): Slightly adjust the offset at which we show unit
49
        for the dashboard page.
50
51
        * public/v2/manifest.js:
52
        (App.Dashboard): Inherit from App.NameLabelModel now that each predefined dashboard has a name.
53
        (App.MetricSerializer.normalizePayload): Parse all predefined dashboards instead of a single dashboard.
54
        IDs are generated for each dashboard for forward compatibility.
55
        (App.Manifest):
56
        (App.Manifest.dashboardByName): Added.
57
        (App.Manifest.defaultDashboardName): Added.
58
        (App.Manifest._fetchedManifest): Create dashboard model objects for all predefined ones.
59
1
2015-02-05  Ryosuke Niwa  <rniwa@webkit.org>
60
2015-02-05  Ryosuke Niwa  <rniwa@webkit.org>
2
61
3
        Move commits viewer to the end of details view
62
        Move commits viewer to the end of details view
- Websites/perf.webkit.org/public/v2/app.css -3 / +3 lines
Lines 201-212 body { Websites/perf.webkit.org/public/v2/app.css_sec1
201
    margin: 0;
201
    margin: 0;
202
    line-height: 1rem;
202
    line-height: 1rem;
203
}
203
}
204
#navigation li:not(:last-child) a {
204
#navigation li:not(:last-of-type) a {
205
    border-top-right-radius: 0;
205
    border-top-right-radius: 0;
206
    border-bottom-right-radius: 0;
206
    border-bottom-right-radius: 0;
207
    border-right: 0;
207
    border-right: 0;
208
}
208
}
209
#navigation li:not(:first-child) a {
209
#navigation li:not(:first-of-type) a {
210
    border-top-left-radius: 0;
210
    border-top-left-radius: 0;
211
    border-bottom-left-radius: 0;
211
    border-bottom-left-radius: 0;
212
}
212
}
Lines 397-403 table.dashboard tbody td a.reset svg { Websites/perf.webkit.org/public/v2/app.css_sec2
397
}
397
}
398
398
399
table.dashboard tbody td .chart {
399
table.dashboard tbody td .chart {
400
    border: solid 1px #ddd;
400
    border: solid 0px #ddd;
401
    border-radius: 0.5rem;
401
    border-radius: 0.5rem;
402
    margin: 0.5rem 0.5rem;
402
    margin: 0.5rem 0.5rem;
403
}
403
}
- Websites/perf.webkit.org/public/v2/app.js -68 / +99 lines
Lines 1-6 Websites/perf.webkit.org/public/v2/app.js_sec1
1
window.App = Ember.Application.create();
1
window.App = Ember.Application.create();
2
2
3
App.Router.map(function () {
3
App.Router.map(function () {
4
    this.resource('customDashboard', {path: 'dashboard/custom'});
5
    this.resource('dashboard', {path: 'dashboard/:name'});
4
    this.resource('charts', {path: 'charts'});
6
    this.resource('charts', {path: 'charts'});
5
    this.resource('analysis', {path: 'analysis'});
7
    this.resource('analysis', {path: 'analysis'});
6
    this.resource('analysisTask', {path: 'analysis/task/:taskId'});
8
    this.resource('analysisTask', {path: 'analysis/task/:taskId'});
Lines 54-81 App.DashboardPaneProxyForPicker = Ember. Websites/perf.webkit.org/public/v2/app.js_sec2
54
    }.property('platformId', 'metricId'),
56
    }.property('platformId', 'metricId'),
55
});
57
});
56
58
57
App.IndexController = Ember.Controller.extend({
59
App.IndexRoute = Ember.Route.extend({
60
    beforeModel: function ()
61
    {
62
        var self = this;
63
        App.Manifest.fetch(this.store).then(function () {
64
            self.transitionTo('dashboard', App.Manifest.defaultDashboardName());
65
        });
66
    },
67
});
68
69
App.DashboardRoute = Ember.Route.extend({
70
    model: function (param)
71
    {
72
        return App.Manifest.fetch(this.store).then(function () {
73
            return App.Manifest.dashboardByName(param.name);
74
        });
75
    },
76
});
77
78
App.CustomDashboardRoute = Ember.Route.extend({
79
    controllerName: 'dashboard',
80
    model: function (param)
81
    {
82
        return this.store.createRecord('dashboard', {serialized: param.grid});
83
    },
84
    renderTemplate: function()
85
    {
86
        this.render('dashboard');
87
    }
88
});
89
90
App.DashboardController = Ember.Controller.extend({
58
    queryParams: ['grid', 'numberOfDays'],
91
    queryParams: ['grid', 'numberOfDays'],
59
    _previousGrid: {},
60
    headerColumns: [],
92
    headerColumns: [],
61
    rows: [],
93
    rows: [],
62
    numberOfDays: 7,
94
    numberOfDays: 7,
63
    editMode: false,
95
    editMode: false,
64
96
65
    gridChanged: function ()
97
    modelChanged: function ()
66
    {
98
    {
67
        var grid = this.get('grid');
99
        var dashboard = this.get('model');
68
        if (grid === this._previousGrid)
69
            return;
70
71
        var dashboard = null;
72
        if (grid) {
73
            dashboard = this.store.createRecord('dashboard', {serialized: grid});
74
            if (!dashboard.get('headerColumns').length)
75
                dashboard = null;
76
        }
77
        if (!dashboard)
78
            dashboard = App.Manifest.get('defaultDashboard');
79
        if (!dashboard)
100
        if (!dashboard)
80
            return;
101
            return;
81
102
Lines 95-103 App.IndexController = Ember.Controller.e Websites/perf.webkit.org/public/v2/app.js_sec3
95
        }));
116
        }));
96
117
97
        this.set('emptyRow', new Array(columnCount));
118
        this.set('emptyRow', new Array(columnCount));
98
    }.observes('grid', 'App.Manifest.defaultDashboard').on('init'),
119
    }.observes('model').on('init'),
99
120
100
    updateGrid: function()
121
    computeGrid: function()
101
    {
122
    {
102
        var headers = this.get('headerColumns').map(function (header) { return header.label; });
123
        var headers = this.get('headerColumns').map(function (header) { return header.label; });
103
        var table = [headers].concat(this.get('rows').map(function (row) {
124
        var table = [headers].concat(this.get('rows').map(function (row) {
Lines 106-113 App.IndexController = Ember.Controller.e Websites/perf.webkit.org/public/v2/app.js_sec4
106
                return platformAndMetric[0] || platformAndMetric[1] ? platformAndMetric : [];
127
                return platformAndMetric[0] || platformAndMetric[1] ? platformAndMetric : [];
107
            }));
128
            }));
108
        }));
129
        }));
109
        this._previousGrid = JSON.stringify(table);
130
        return JSON.stringify(table);
110
        this.set('grid', this._previousGrid);
111
    },
131
    },
112
132
113
    _sharedDomainChanged: function ()
133
    _sharedDomainChanged: function ()
Lines 173-180 App.IndexController = Ember.Controller.e Websites/perf.webkit.org/public/v2/app.js_sec5
173
        toggleEditMode: function ()
193
        toggleEditMode: function ()
174
        {
194
        {
175
            this.toggleProperty('editMode');
195
            this.toggleProperty('editMode');
176
            if (!this.get('editMode'))
196
            if (this.get('editMode'))
177
                this.updateGrid();
197
                this.transitionToRoute('dashboard', 'custom', {name: null, queryParams: {grid: this.computeGrid()}});
198
            else
199
                this.set('grid', this.computeGrid());
178
        },
200
        },
179
    },
201
    },
180
202
Lines 362-368 App.Pane = Ember.Object.extend({ Websites/perf.webkit.org/public/v2/app.js_sec6
362
        if (typeof(id) == "string")
384
        if (typeof(id) == "string")
363
            return !!id.match(/^[A-Za-z0-9_]+$/);
385
            return !!id.match(/^[A-Za-z0-9_]+$/);
364
        return false;
386
        return false;
365
    }
387
    },
388
    computeStatus: function (currentPoint, previousPoint)
389
    {
390
        var chartData = this.get('chartData');
391
        var diffFromBaseline = this._relativeDifferentToLaterPointInTimeSeries(currentPoint, chartData.baseline);
392
        var diffFromTarget = this._relativeDifferentToLaterPointInTimeSeries(currentPoint, chartData.target);
393
394
        var label = '';
395
        var className = '';
396
        var formatter = d3.format('.3p');
397
398
        var smallerIsBetter = chartData.smallerIsBetter;
399
        if (diffFromBaseline !== undefined && diffFromBaseline > 0 == smallerIsBetter) {
400
            label = formatter(Math.abs(diffFromBaseline)) + ' ' + (smallerIsBetter ? 'above' : 'below') + ' baseline';
401
            className = 'worse';
402
        } else if (diffFromTarget !== undefined && diffFromTarget < 0 == smallerIsBetter) {
403
            label = formatter(Math.abs(diffFromTarget)) + ' ' + (smallerIsBetter ? 'below' : 'above') + ' target';
404
            className = 'better';
405
        } else if (diffFromTarget !== undefined)
406
            label = formatter(Math.abs(diffFromTarget)) + ' until target';
407
408
        var valueDelta = previousPoint ? chartData.deltaFormatter(currentPoint.value - previousPoint.value) : null;
409
        if (valueDelta && valueDelta > 0)
410
            valueDelta = '+' + valueDelta;
411
412
        return {className: className, label: label, currentValue: chartData.formatter(currentPoint.value), valueDelta: valueDelta};
413
    },
414
    _relativeDifferentToLaterPointInTimeSeries: function (currentPoint, timeSeries)
415
    {
416
        if (!currentPoint || !timeSeries)
417
            return undefined;
418
419
        var referencePoint = timeSeries.findPointAfterTime(currentPoint.time);
420
        if (!referencePoint)
421
            return undefined;
422
423
        return (currentPoint.value - referencePoint.value) / referencePoint.value;
424
    },
425
    latestStatus: function ()
426
    {
427
        var chartData = this.get('chartData');
428
        if (!chartData || !chartData.current)
429
            return null;
430
431
        var lastPoint = chartData.current.lastPoint();
432
        if (!lastPoint)
433
            return null;
434
435
        return this.computeStatus(lastPoint, chartData.current.previousPoint(lastPoint));
436
    }.property('chartData'),
366
});
437
});
367
438
368
App.createChartData = function (data)
439
App.createChartData = function (data)
Lines 374-379 App.createChartData = function (data) Websites/perf.webkit.org/public/v2/app.js_sec7
374
        target: runs.target ? runs.target.timeSeriesByCommitTime() : null,
445
        target: runs.target ? runs.target.timeSeriesByCommitTime() : null,
375
        unit: data.unit,
446
        unit: data.unit,
376
        formatter: data.useSI ? d3.format('.4s') : d3.format('.4g'),
447
        formatter: data.useSI ? d3.format('.4s') : d3.format('.4g'),
448
        deltaFormatter: data.useSI ? d3.format('.2s') : d3.format('.2g'),
377
        smallerIsBetter: data.smallerIsBetter,
449
        smallerIsBetter: data.smallerIsBetter,
378
    };
450
    };
379
}
451
}
Lines 730-744 App.PaneController = Ember.ObjectControl Websites/perf.webkit.org/public/v2/app.js_sec8
730
        }
802
        }
731
803
732
        var currentMeasurement;
804
        var currentMeasurement;
733
        var oldMeasurement;
805
        var previousPoint;
734
        if (currentPoint) {
806
        if (currentPoint) {
735
            currentMeasurement = currentPoint.measurement;
807
            currentMeasurement = currentPoint.measurement;
736
            var previousPoint = currentPoint.series.previousPoint(currentPoint);
808
            previousPoint = currentPoint.series.previousPoint(currentPoint);
737
            oldMeasurement = previousPoint ? previousPoint.measurement : null;
738
        } else {
809
        } else {
739
            currentMeasurement = selectedPoints[selectedPoints.length - 1].measurement;
810
            currentMeasurement = selectedPoints[selectedPoints.length - 1].measurement;
740
            oldMeasurement = selectedPoints[0].measurement;            
811
            previousPoint = selectedPoints[0];
741
        }
812
        }
813
        var oldMeasurement = previousPoint ? previousPoint.measurement : null;
742
814
743
        var formattedRevisions = currentMeasurement.formattedRevisions(oldMeasurement);
815
        var formattedRevisions = currentMeasurement.formattedRevisions(oldMeasurement);
744
        var revisions = App.Manifest.get('repositories')
816
        var revisions = App.Manifest.get('repositories')
Lines 762-776 App.PaneController = Ember.ObjectControl Websites/perf.webkit.org/public/v2/app.js_sec9
762
                buildURL = builder.urlFromBuildNumber(buildNumber);
834
                buildURL = builder.urlFromBuildNumber(buildNumber);
763
        }
835
        }
764
836
765
        var chartData = this.get('chartData');
766
        var valueDiff = oldMeasurement ? chartData.formatter(currentMeasurement.mean() - oldMeasurement.mean()) : null;
767
        if (valueDiff && valueDiff > 0)
768
            valueDiff = '+' + valueDiff;
769
770
        this.set('details', Ember.Object.create({
837
        this.set('details', Ember.Object.create({
771
            status: this._computeStatus(currentPoint),
838
            status: this.get('model').computeStatus(currentPoint, previousPoint),
772
            currentValue: chartData.formatter(currentMeasurement.mean()),
773
            valueDiff: valueDiff,
774
            buildNumber: buildNumber,
839
            buildNumber: buildNumber,
775
            buildURL: buildURL,
840
            buildURL: buildURL,
776
            buildTime: currentMeasurement.formattedBuildTime(),
841
            buildTime: currentMeasurement.formattedBuildTime(),
Lines 783-822 App.PaneController = Ember.ObjectControl Websites/perf.webkit.org/public/v2/app.js_sec10
783
        var points = this.get('selectedPoints');
848
        var points = this.get('selectedPoints');
784
        this.set('cannotAnalyze', !this.get('newAnalysisTaskName') || !points || points.length < 2);
849
        this.set('cannotAnalyze', !this.get('newAnalysisTaskName') || !points || points.length < 2);
785
    }.observes('newAnalysisTaskName'),
850
    }.observes('newAnalysisTaskName'),
786
    _computeStatus: function (currentPoint)
787
    {
788
        var chartData = this.get('chartData');
789
790
        var diffFromBaseline = this._relativeDifferentToLaterPointInTimeSeries(currentPoint, chartData.baseline);
791
        var diffFromTarget = this._relativeDifferentToLaterPointInTimeSeries(currentPoint, chartData.target);
792
793
        var label = '';
794
        var className = '';
795
        var formatter = d3.format('.3p');
796
797
        var smallerIsBetter = chartData.smallerIsBetter;
798
        if (diffFromBaseline !== undefined && diffFromBaseline > 0 == smallerIsBetter) {
799
            label = formatter(Math.abs(diffFromBaseline)) + ' ' + (smallerIsBetter ? 'above' : 'below') + ' baseline';
800
            className = 'worse';
801
        } else if (diffFromTarget !== undefined && diffFromTarget < 0 == smallerIsBetter) {
802
            label = formatter(Math.abs(diffFromTarget)) + ' ' + (smallerIsBetter ? 'below' : 'above') + ' target';
803
            className = 'better';
804
        } else if (diffFromTarget !== undefined)
805
            label = formatter(Math.abs(diffFromTarget)) + ' until target';
806
807
        return {className: className, label: label};
808
    },
809
    _relativeDifferentToLaterPointInTimeSeries: function (currentPoint, timeSeries)
810
    {
811
        if (!currentPoint || !timeSeries)
812
            return undefined;
813
        
814
        var referencePoint = timeSeries.findPointAfterTime(currentPoint.time);
815
        if (!referencePoint)
816
            return undefined;
817
818
        return (currentPoint.value - referencePoint.value) / referencePoint.value;
819
    }
820
});
851
});
821
852
822
853
- Websites/perf.webkit.org/public/v2/chart-pane.css -2 / +8 lines
Lines 320-336 Websites/perf.webkit.org/public/v2/chart-pane.css_sec1
320
.chart path.baseline {
320
.chart path.baseline {
321
    stroke: #f66;
321
    stroke: #f66;
322
}
322
}
323
.chart-pane .status .worse {
323
.chart-pane .status .worse,
324
.dashboard-status .worse {
324
    color: #c33;
325
    color: #c33;
325
}
326
}
326
327
327
.chart path.target {
328
.chart path.target {
328
    stroke: #66f;
329
    stroke: #66f;
329
}
330
}
330
.chart-pane .status .better {
331
.chart-pane .status .better,
332
.dashboard-status .better {
331
    color: #33c;
333
    color: #33c;
332
}
334
}
333
335
336
.dashboard-status .status-label {
337
    margin-left: 1rem;
338
}
339
334
.chart .axis,
340
.chart .axis,
335
.chart .domain {
341
.chart .domain {
336
  fill: none;
342
  fill: none;
- Websites/perf.webkit.org/public/v2/data.js +7 lines
Lines 405-410 TimeSeries.prototype.minMaxForTimeRange Websites/perf.webkit.org/public/v2/data.js_sec1
405
405
406
TimeSeries.prototype.series = function () { return this._series; }
406
TimeSeries.prototype.series = function () { return this._series; }
407
407
408
TimeSeries.prototype.lastPoint = function ()
409
{
410
    if (!this._series || !this._series.length)
411
        return null;
412
    return this._series[this._series.length - 1];
413
}
414
408
TimeSeries.prototype.previousPoint = function (point)
415
TimeSeries.prototype.previousPoint = function (point)
409
{
416
{
410
    if (!point.seriesIndex)
417
    if (!point.seriesIndex)
- Websites/perf.webkit.org/public/v2/index.html -13 / +31 lines
Lines 3-8 Websites/perf.webkit.org/public/v2/index.html_sec1
3
<head>
3
<head>
4
    <meta charset="utf-8">
4
    <meta charset="utf-8">
5
    <title>WebKit Performance Monitor (Beta)</title>
5
    <title>WebKit Performance Monitor (Beta)</title>
6
7
    <link rel="prefetch" href="../data/manifest.json">
8
    <script type="application/json" src="../data/manifest.json"></script>
9
10
    <link rel="stylesheet" href="app.css">
11
    <link rel="stylesheet" href="chart-pane.css">
12
13
    <script src="js/jquery.min.js" defer></script>
6
    <script src="js/jquery.min.js" defer></script>
14
    <script src="js/jquery.min.js" defer></script>
7
    <script src="js/handlebars.js" defer></script>
15
    <script src="js/handlebars.js" defer></script>
8
    <script src="js/ember.js" defer></script>
16
    <script src="js/ember.js" defer></script>
Lines 16-25 Websites/perf.webkit.org/public/v2/index.html_sec2
16
    <script src="popup.js" defer></script>
24
    <script src="popup.js" defer></script>
17
    <script src="interactive-chart.js" defer></script>
25
    <script src="interactive-chart.js" defer></script>
18
    <script src="commits-viewer.js" defer></script>
26
    <script src="commits-viewer.js" defer></script>
19
    <link rel="stylesheet" href="app.css">
20
    <link rel="stylesheet" href="chart-pane.css">
21
27
22
    <script type="text/x-handlebars" data-template-name="index">
28
    <script type="text/x-handlebars" data-template-name="dashboard">
23
        <header id="header">
29
        <header id="header">
24
            {{partial "navbar"}}
30
            {{partial "navbar"}}
25
            {{view App.NumberOfDaysControlView tagName="ul" numberOfDays=numberOfDays}}
31
            {{view App.NumberOfDaysControlView tagName="ul" numberOfDays=numberOfDays}}
Lines 78-88 Websites/perf.webkit.org/public/v2/index.html_sec3
78
                                {{/if}}
84
                                {{/if}}
79
                            {{else}}
85
                            {{else}}
80
                                {{#if chartData}}
86
                                {{#if chartData}}
87
                                    <div class="dashboard-status">
88
                                        {{#if latestStatus}}
89
                                            {{latestStatus.currentValue}} {{chartData.unit}}
90
                                            {{#if latestStatus.label}}
91
                                                <span {{bind-attr class=":status-label latestStatus.className"}}>{{latestStatus.label}}</span>
92
                                            {{/if}}
93
                                        {{/if}}
94
                                    </div>
81
                                    {{#link-to 'charts' (query-params paneList=paneList since=controller.since)}}
95
                                    {{#link-to 'charts' (query-params paneList=paneList since=controller.since)}}
82
                                    {{interactive-chart
96
                                        {{interactive-chart
83
                                        chartData=chartData
97
                                            chartData=chartData
84
                                        domain=controller.sharedDomain
98
                                            domain=controller.sharedDomain
85
                                        enableSelection=false}}
99
                                            enableSelection=false}}
86
                                    {{/link-to}}
100
                                    {{/link-to}}
87
                                {{else}}
101
                                {{else}}
88
                                    {{#if failure}}
102
                                    {{#if failure}}
Lines 258-266 Websites/perf.webkit.org/public/v2/index.html_sec4
258
                <tr>
272
                <tr>
259
                    <th>Current</th>
273
                    <th>Current</th>
260
                    <td>
274
                    <td>
261
                        {{details.currentValue}} {{chartData.unit}}
275
                        {{details.status.currentValue}} {{chartData.unit}}
262
                        {{#if details.valueDiff}}
276
                        {{#if details.status.valueDelta}}
263
                            ({{details.valueDiff}} {{chartData.unit}})
277
                            ({{details.status.valueDelta}} {{chartData.unit}})
264
                        {{/if}}
278
                        {{/if}}
265
                        {{#if details.status.label}}
279
                        {{#if details.status.label}}
266
                            <br>
280
                            <br>
Lines 378-386 Websites/perf.webkit.org/public/v2/index.html_sec5
378
        <nav id="navigation" role="navigation">
392
        <nav id="navigation" role="navigation">
379
            <h1><a href="#">WebKit Perf Monitor</a></h1>
393
            <h1><a href="#">WebKit Perf Monitor</a></h1>
380
            <ul>
394
            <ul>
381
                {{#link-to 'index' tagName='li'}}
395
                {{#each App.Manifest.dashboards}}
382
                    {{#link-to 'index'}}Dashboard{{/link-to}}
396
                    {{#if name}}
383
                {{/link-to}}
397
                        {{#link-to 'dashboard' name tagName='li'}}
398
                            {{#link-to 'dashboard' name}}{{label}}{{/link-to}}
399
                        {{/link-to}}
400
                    {{/if}}
401
                {{/each}}
384
                {{#link-to 'charts' tagName='li'}}
402
                {{#link-to 'charts' tagName='li'}}
385
                    {{#link-to 'charts'}}Charts{{/link-to}}
403
                    {{#link-to 'charts'}}Charts{{/link-to}}
386
                {{/link-to}}
404
                {{/link-to}}
- Websites/perf.webkit.org/public/v2/interactive-chart.js -1 / +1 lines
Lines 288-294 App.InteractiveChartComponent = Ember.Co Websites/perf.webkit.org/public/v2/interactive-chart.js_sec1
288
        this._yAxisLabels.call(this._yAxis);
288
        this._yAxisLabels.call(this._yAxis);
289
        if (this._yAxisUnitContainer)
289
        if (this._yAxisUnitContainer)
290
            this._yAxisUnitContainer.remove();
290
            this._yAxisUnitContainer.remove();
291
        var x = - 3 * this._rem;
291
        var x = - 3.2 * this._rem;
292
        var y = this._contentHeight / 2;
292
        var y = this._contentHeight / 2;
293
        this._yAxisUnitContainer = this._yAxisLabels.append("text")
293
        this._yAxisUnitContainer = this._yAxisLabels.append("text")
294
            .attr("transform", "rotate(90 0 0) translate(" + y + ", " + (-x) + ")")
294
            .attr("transform", "rotate(90 0 0) translate(" + y + ", " + (-x) + ")")
- Websites/perf.webkit.org/public/v2/manifest.js -3 / +21 lines
Lines 92-98 App.Repository = App.NameLabelModel.exte Websites/perf.webkit.org/public/v2/manifest.js_sec1
92
    },
92
    },
93
});
93
});
94
94
95
App.Dashboard = App.Model.extend({
95
App.Dashboard = App.NameLabelModel.extend({
96
    serialized: DS.attr('string'),
96
    serialized: DS.attr('string'),
97
    table: function ()
97
    table: function ()
98
    {
98
    {
Lines 152-158 App.MetricSerializer = App.PlatformSeria Websites/perf.webkit.org/public/v2/manifest.js_sec2
152
            metrics: this._normalizeIdMap(payload['metrics']),
152
            metrics: this._normalizeIdMap(payload['metrics']),
153
            repositories: this._normalizeIdMap(payload['repositories']),
153
            repositories: this._normalizeIdMap(payload['repositories']),
154
            bugTrackers: this._normalizeIdMap(payload['bugTrackers']),
154
            bugTrackers: this._normalizeIdMap(payload['bugTrackers']),
155
            dashboards: [{id: 1, serialized: JSON.stringify(payload['defaultDashboard'])}],
155
            dashboards: [],
156
        };
156
        };
157
157
158
        for (var testId in payload['tests']) {
158
        for (var testId in payload['tests']) {
Lines 173-178 App.MetricSerializer = App.PlatformSeria Websites/perf.webkit.org/public/v2/manifest.js_sec3
173
            test['metrics'].push(metricId);
173
            test['metrics'].push(metricId);
174
        }
174
        }
175
175
176
        var id = 1;
177
        var dashboardsInPayload = payload['dashboards'];
178
        for (var dashboardName in dashboardsInPayload) {
179
            results['dashboards'].push({
180
                id: id,
181
                name: dashboardName,
182
                serialized: JSON.stringify(dashboardsInPayload[dashboardName])
183
            });
184
            id++;
185
        }
186
176
        return results;
187
        return results;
177
    },
188
    },
178
    _normalizeIdMap: function (idMap)
189
    _normalizeIdMap: function (idMap)
Lines 211-216 App.Manifest = Ember.Controller.extend({ Websites/perf.webkit.org/public/v2/manifest.js_sec4
211
    _metricById: {},
222
    _metricById: {},
212
    _builderById: {},
223
    _builderById: {},
213
    _repositoryById: {},
224
    _repositoryById: {},
225
    _dashboardByName: {},
226
    _defaultDashboardName: null,
214
    _fetchPromise: null,
227
    _fetchPromise: null,
215
    fetch: function (store)
228
    fetch: function (store)
216
    {
229
    {
Lines 223-228 App.Manifest = Ember.Controller.extend({ Websites/perf.webkit.org/public/v2/manifest.js_sec5
223
    metric: function (id) { return this._metricById[id]; },
236
    metric: function (id) { return this._metricById[id]; },
224
    builder: function (id) { return this._builderById[id]; },
237
    builder: function (id) { return this._builderById[id]; },
225
    repository: function (id) { return this._repositoryById[id]; },
238
    repository: function (id) { return this._repositoryById[id]; },
239
    dashboardByName: function (name) { return this._dashboardByName[name]; },
240
    defaultDashboardName: function () { return this._defaultDashboardName; },
226
    _fetchedManifest: function (store)
241
    _fetchedManifest: function (store)
227
    {
242
    {
228
        var startTime = Date.now();
243
        var startTime = Date.now();
Lines 259-265 App.Manifest = Ember.Controller.extend({ Websites/perf.webkit.org/public/v2/manifest.js_sec6
259
274
260
        this.set('bugTrackers', store.all('bugTracker').sortBy('name'));
275
        this.set('bugTrackers', store.all('bugTracker').sortBy('name'));
261
276
262
        this.set('defaultDashboard', store.all('dashboard').objectAt(0));
277
        var dashboards = store.all('dashboard').sortBy('name');
278
        this.set('dashboards', dashboards);
279
        dashboards.forEach(function (dashboard) { self._dashboardByName[dashboard.get('name')] = dashboard; });
280
        this._defaultDashboardName = dashboards.length ? dashboards[0].get('name') : null;
263
    },
281
    },
264
    fetchRunsWithPlatformAndMetric: function (store, platformId, metricId)
282
    fetchRunsWithPlatformAndMetric: function (store, platformId, metricId)
265
    {
283
    {

Return to Bug 141339