+2015-02-20 Ryosuke Niwa <rniwa@webkit.org>
+
+ Selecting revisions for A/B testing is hard
+ https://bugs.webkit.org/show_bug.cgi?id=141824
+
+ Reviewed by Andreas Kling.
+
+ Update the revisions used in A/B testing based on the selection in the overview chart. This allows users to
+ intuitively select revisions based on points shown in the chart. Removed the old select elements used to
+ select A/B testing points manually.
+
+ Also renamed 'testSets' to 'configurations', 'roots' to 'rootConfigurations', and 'revisions' in each root's
+ sets to 'options' for clarity.
+
+ * public/v2/app.css: Reorganized style rules.
+
+ * public/v2/app.js:
+ (App.AnalysisTaskController):
+ (App.AnalysisTaskController._taskUpdated): Merged updateTestGroupPanes.
+ (App.AnalysisTaskController._chartDataChanged): Renamed from paneDomain. It's now an observer instead of
+ a property, which sets 'overviewDomain' property as well as other properties.
+ (App.AnalysisTaskController.updateRootConfigurations): Renamed from updateRoots.
+ (App.AnalysisTaskController._updateRootsBySelectedPoints): Added. Select roots based on the selected points
+ in the overview chart.
+
+ * public/v2/chart-pane.css: Added arrows next to the configuration names (e.g. 'A') to indicate whether
+ individual build requests / test results are shown or not.
+
+ * public/v2/index.html: Removed the select element per configuration column. Also moved the select element
+ for the number of runs as it doesn't belong in the same table as the one that lists repositories and roots.
+
2015-02-20 Ryosuke Niwa <rniwa@webkit.org>
Unreviewed test fixes after r179037, r179591, and r179763.
platform: Ember.computed.alias('model.platform'),
metric: Ember.computed.alias('model.metric'),
details: Ember.computed.alias('pane.details'),
- testSets: [],
roots: [],
bugTrackers: [],
possibleRepetitionCounts: [1, 2, 3, 4, 5, 6],
platformId: model.get('platform').get('id'),
metricId: model.get('metric').get('id'),
}));
- }.observes('model').on('init'),
+
+ var self = this;
+ model.get('testGroups').then(function (groups) {
+ self.set('testGroupPanes', groups.map(function (group) { return App.TestGroupPane.create({content: group}); }));
+ });
+ }.observes('model', 'model.testGroups').on('init'),
_fetchedManifest: function ()
{
var trackerIdToBugNumber = {};
});
}));
},
- paneDomain: function ()
+ _chartDataChanged: function ()
{
var pane = this.get('pane');
if (!pane)
var margin = (end.time - start.time) * 0.1;
this.set('highlightedItems', highlightedItems);
+ this.set('overviewEndPoints', [start, end]);
this.set('analysisPoints', formatedPoints);
- var paneDomain = [start.time - margin, +end.time + margin];
+ var overviewDomain = [start.time - margin, +end.time + margin];
var testGroupPanes = this.get('testGroupPanes');
if (testGroupPanes) {
testGroupPanes.setEach('overviewPane', pane);
- testGroupPanes.setEach('overviewDomain', paneDomain);
+ testGroupPanes.setEach('overviewDomain', overviewDomain);
}
- return paneDomain;
- }.property('pane.chartData'),
- testSets: function ()
- {
- var analysisPoints = this.get('analysisPoints');
- if (!analysisPoints)
- return;
- var pointOptions = [{value: ' ', label: 'None'}]
- .concat(analysisPoints.map(function (point) { return {value: point.id, label: point.label}; }));
- return [
- Ember.Object.create({name: "A", options: pointOptions, selection: pointOptions[1]}),
- Ember.Object.create({name: "B", options: pointOptions, selection: pointOptions[pointOptions.length - 1]}),
- ];
- }.property('analysisPoints'),
- _rootChangedForTestSet: function ()
- {
- var sets = this.get('testSets');
- var roots = this.get('roots');
- if (!sets || !roots)
- return;
-
- sets.forEach(function (testSet, setIndex) {
- var currentSelection = testSet.get('selection');
- if (currentSelection == testSet.get('previousSelection'))
- return;
- testSet.set('previousSelection', currentSelection);
- var pointIndex = testSet.get('options').indexOf(currentSelection);
-
- roots.forEach(function (root) {
- var set = root.sets[setIndex];
- set.set('selection', set.revisions[pointIndex]);
- });
- });
-
- }.observes('testSets.@each.selection'),
- updateRoots: function ()
+ this.set('overviewDomain', overviewDomain);
+ }.observes('pane.chartData'),
+ updateRootConfigurations: function ()
{
var analysisPoints = this.get('analysisPoints');
if (!analysisPoints)
if (!triggerable)
return;
- self.set('roots', triggerable.get('acceptedRepositories').map(function (repository) {
+ self.set('configurations', ['A', 'B']);
+ self.set('rootConfigurations', triggerable.get('acceptedRepositories').map(function (repository) {
var repositoryId = repository.get('id');
- var revisions = [{value: ' ', label: 'None'}].concat(repositoryToRevisions[repositoryId]);
+ var options = [{value: ' ', label: 'None'}].concat(repositoryToRevisions[repositoryId]);
return Ember.Object.create({
+ repository: repository,
name: repository.get('name'),
sets: [
Ember.Object.create({name: 'A[' + repositoryId + ']',
- revisions: revisions,
- selection: revisions[1]}),
+ options: options,
+ selection: options[1]}),
Ember.Object.create({name: 'B[' + repositoryId + ']',
- revisions: revisions,
- selection: revisions[revisions.length - 1]}),
+ options: options,
+ selection: options[options.length - 1]}),
],
});
}));
});
}.observes('analysisPoints'),
- updateTestGroupPanes: function ()
- {
- var model = this.get('model');
- if (!model)
- return;
- var self = this;
- model.get('testGroups').then(function (groups) {
- self.set('testGroupPanes', groups.map(function (group) { return App.TestGroupPane.create({content: group}); }));
- });
- }.observes('model'),
actions: {
associateBug: function (bugTracker, bugNumber)
{
createTestGroup: function (name, repetitionCount)
{
var roots = {};
- this.get('roots').map(function (root) {
+ this.get('rootConfigurations').map(function (root) {
roots[root.get('name')] = root.get('sets').map(function (item) { return item.get('selection').value; });
});
App.TestGroup.create(this.get('model'), name, roots, repetitionCount).then(function () {
-
+ }, function (error) {
+ alert('Failed to create a new test group:' + error);
});
},
toggleShowRequestList: function (configuration)
configuration.toggleProperty('showRequestList');
}
},
+ _updateRootsBySelectedPoints: function ()
+ {
+ var rootConfigurations = this.get('rootConfigurations');
+ var pane = this.get('pane');
+ if (!rootConfigurations || !pane)
+ return;
+
+ var rootSetPoints;
+ var selectedPoints = pane.get('selectedPoints');
+ if (selectedPoints && selectedPoints.length >= 2)
+ rootSetPoints = [selectedPoints[0], selectedPoints[selectedPoints.length - 1]];
+ else
+ rootSetPoints = this.get('overviewEndPoints');
+ if (!rootSetPoints)
+ return;
+
+ rootConfigurations.forEach(function (root) {
+ root.get('sets').forEach(function (set, setIndex) {
+ if (setIndex >= rootSetPoints.length)
+ return;
+ var targetRevision = rootSetPoints[setIndex].measurement.revisionForRepository(root.get('repository').get('id'));
+ var selectedOption;
+ if (targetRevision)
+ selectedOption = set.get('options').find(function (option) { return option.value == targetRevision; });
+ set.set('selection', selectedOption || sets[i].get('options')[0]);
+ });
+ });
+
+ }.observes('pane.selectedPoints'),
});
App.TestGroupPane = Ember.ObjectProxy.extend({