UI to associate bugs with an analysis task is crappy
authorrniwa@webkit.org <rniwa@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 20 May 2015 21:52:35 +0000 (21:52 +0000)
committerrniwa@webkit.org <rniwa@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 20 May 2015 21:52:35 +0000 (21:52 +0000)
https://bugs.webkit.org/show_bug.cgi?id=145198

Reviewed by Andreas Kling.

Make the UI less crappy by linkifying bug numbers and adding an explicit button to disassociate
a bug and a separate select view with a text field to associate a new bug instead of implicitly
updating or deleting the existing record based on what the user had typed.

* init-database.sql: Removed the constraint that each bug tracker should appear exactly once for
a given analysis task since it's perfectly reasonable for a given task to be associated with
multiple WebKit bugs.

* public/privileged-api/associate-bug.php:
(main): Only remove the bug specified by newly added bugToDelete instead of implicitly deleting
one that matches the analysis task and the bug tracker when the bug number is falsey.

* public/v2/analysis.js:
(App.Bug.url): Added.
(App.BugAdapter.deleteRecord): Added. Uses the privileged API to delete the record.

* public/v2/app.css:

* public/v2/app.js:
(App.AnalysisTaskController.actions.addBug): Added.
(App.AnalysisTaskController.actions.deleteBug): Added.
(App.AnalysisTaskController.associateBug): Deleted.

* public/v2/index.html: Updated the templates.

* public/v2/manifest.js:
(App.BugTracker.urlFromBugNumber): Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@184661 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Websites/perf.webkit.org/ChangeLog
Websites/perf.webkit.org/init-database.sql
Websites/perf.webkit.org/public/privileged-api/associate-bug.php
Websites/perf.webkit.org/public/v2/analysis.js
Websites/perf.webkit.org/public/v2/app.css
Websites/perf.webkit.org/public/v2/app.js
Websites/perf.webkit.org/public/v2/index.html
Websites/perf.webkit.org/public/v2/manifest.js

index 9b9bec9a6140e8e5d62c77df0210ed29db4e8d54..312d7bc2ea7460b82cfb7ec2df14ef42c3c952d8 100644 (file)
@@ -1,3 +1,38 @@
+2015-05-20  Ryosuke Niwa  <rniwa@webkit.org>
+
+        UI to associate bugs with an analysis task is crappy
+        https://bugs.webkit.org/show_bug.cgi?id=145198
+
+        Reviewed by Andreas Kling.
+
+        Make the UI less crappy by linkifying bug numbers and adding an explicit button to disassociate
+        a bug and a separate select view with a text field to associate a new bug instead of implicitly
+        updating or deleting the existing record based on what the user had typed.
+
+        * init-database.sql: Removed the constraint that each bug tracker should appear exactly once for
+        a given analysis task since it's perfectly reasonable for a given task to be associated with
+        multiple WebKit bugs.
+
+        * public/privileged-api/associate-bug.php:
+        (main): Only remove the bug specified by newly added bugToDelete instead of implicitly deleting
+        one that matches the analysis task and the bug tracker when the bug number is falsey.
+
+        * public/v2/analysis.js:
+        (App.Bug.url): Added.
+        (App.BugAdapter.deleteRecord): Added. Uses the privileged API to delete the record.
+
+        * public/v2/app.css:
+
+        * public/v2/app.js:
+        (App.AnalysisTaskController.actions.addBug): Added.
+        (App.AnalysisTaskController.actions.deleteBug): Added.
+        (App.AnalysisTaskController.associateBug): Deleted.
+
+        * public/v2/index.html: Updated the templates.
+
+        * public/v2/manifest.js:
+        (App.BugTracker.urlFromBugNumber): Added.
+
 2015-05-20  Ryosuke Niwa  <rniwa@webkit.org>
 
         A/B testing rootSets should provide commit times as well as revisions
 2015-05-20  Ryosuke Niwa  <rniwa@webkit.org>
 
         A/B testing rootSets should provide commit times as well as revisions
index 1712623fe162f9e79cd946d4a5a4d4f9a849092d..a0dcc632936b0d5eb4033a408a5bad44131bb3b8 100644 (file)
@@ -200,8 +200,7 @@ CREATE TABLE bugs (
     bug_id serial PRIMARY KEY,
     bug_task integer REFERENCES analysis_tasks NOT NULL,
     bug_tracker integer REFERENCES bug_trackers NOT NULL,
     bug_id serial PRIMARY KEY,
     bug_task integer REFERENCES analysis_tasks NOT NULL,
     bug_tracker integer REFERENCES bug_trackers NOT NULL,
-    bug_number integer NOT NULL,
-    CONSTRAINT bug_task_and_tracker_must_be_unique UNIQUE(bug_task, bug_tracker));
+    bug_number integer NOT NULL);
 
 CREATE TABLE build_triggerables (
     triggerable_id serial PRIMARY KEY,
 
 CREATE TABLE build_triggerables (
     triggerable_id serial PRIMARY KEY,
index d4bd2608688344d12a271c402af4c90436ed6e47..4318d4ab7f59728c125bdf9758fc1a14dfddfb9c 100644 (file)
@@ -8,25 +8,23 @@ function main() {
     $analysis_task_id = array_get($data, 'task');
     $bug_tracker_id = array_get($data, 'bugTracker');
     $bug_number = array_get($data, 'number');
     $analysis_task_id = array_get($data, 'task');
     $bug_tracker_id = array_get($data, 'bugTracker');
     $bug_number = array_get($data, 'number');
-
-    require_format('AnalysisTask', $analysis_task_id, '/^\d+$/');
-    require_format('BugTracker', $bug_tracker_id, '/^\d+$/');
-    require_format('BugNumber', $bug_number, '/^\d*$/');
+    $bug_id = array_get($data, 'bugToDelete');
 
     $db = connect();
     $db->begin_transaction();
 
 
     $db = connect();
     $db->begin_transaction();
 
-    $bug_id = NULL;
-    if (!$bug_number) {
-        $count = $db->query_and_get_affected_rows("DELETE FROM bugs WHERE bug_task = $1 AND bug_tracker = $2",
-            array($analysis_task_id, $bug_tracker_id));
-        if ($count > 1) {
+    if ($bug_id) {
+        require_format('BugToDelete', $bug_id, '/^\d+$/');
+        $count = $db->query_and_get_affected_rows("DELETE FROM bugs WHERE bug_id = $1", array($bug_id));
+        if ($count != 1) {
             $db->rollback_transaction();
             exit_with_error('UnexpectedNumberOfAffectedRows', array('affectedRows' => $count));
         }
     } else {
             $db->rollback_transaction();
             exit_with_error('UnexpectedNumberOfAffectedRows', array('affectedRows' => $count));
         }
     } else {
-        $bug_id = $db->update_or_insert_row('bugs', 'bug', array('task' => $analysis_task_id, 'tracker' => $bug_tracker_id),
-            array('task' => $analysis_task_id, 'tracker' => $bug_tracker_id, 'number' => $bug_number));
+        require_format('AnalysisTask', $analysis_task_id, '/^\d+$/');
+        require_format('BugTracker', $bug_tracker_id, '/^\d+$/');
+        require_format('BugNumber', $bug_number, '/^\d+$/');
+        $bug_id = $db->insert_row('bugs', 'bug', array('task' => $analysis_task_id, 'tracker' => $bug_tracker_id, 'number' => $bug_number));
     }
     $db->commit_transaction();
 
     }
     $db->commit_transaction();
 
index a09e6b384cdcd13d5e1b4917a319d01e72c0a38e..f801626a1d023a4860fa0317f3607faa2590ada0 100644 (file)
@@ -61,6 +61,9 @@ App.Bug = App.Model.extend({
     bugTracker: DS.belongsTo('BugTracker'),
     createdAt: DS.attr('date'),
     number: DS.attr('number'),
     bugTracker: DS.belongsTo('BugTracker'),
     createdAt: DS.attr('date'),
     number: DS.attr('number'),
+    url: function () {
+        return this.get('bugTracker').urlFromBugNumber(this.get('number'));
+    }.property('bugTracker.bugUrl', 'number'),
     label: function () {
         return this.get('bugTracker').get('label') + ': ' + this.get('number');
     }.property('name', 'bugTracker'),
     label: function () {
         return this.get('bugTracker').get('label') + ': ' + this.get('number');
     }.property('name', 'bugTracker'),
@@ -95,6 +98,12 @@ App.BugAdapter = DS.RESTAdapter.extend({
             param['id'] = data['bugId'];
             return {'bug': param};
         });
             param['id'] = data['bugId'];
             return {'bug': param};
         });
+    },
+    deleteRecord: function (store, type, record)
+    {
+        return PrivilegedAPI.sendRequest('associate-bug', {bugToDelete: record.get('id')}).then(function () {
+            return {};
+        });
     }
 });
 
     }
 });
 
index 12334bd1f82410220c7ca07b255cd63b9cb9bbbf..e4a97e2df23a9e9f51e0f86ec7695b5d1ae5b748 100755 (executable)
@@ -587,6 +587,12 @@ form .analysis-group > * {
     font-size: 0.9rem;
 }
 
     font-size: 0.9rem;
 }
 
+.analysis-bugs .icon-button {
+    margin-left: 0.2rem;
+    width: 0.8rem;
+    height: 0.8rem;
+}
+
 .analysis-bugs .hidden {
     display: none;
 }
 .analysis-bugs .hidden {
     display: none;
 }
index 99fa16ab62e817cabc0d21ca158d02388783c43a..73a8af93d1fc62907f64656e6c53837ffc9a6099 100755 (executable)
@@ -1196,6 +1196,7 @@ App.AnalysisTaskController = Ember.Controller.extend({
                 elementId: 'bug-' + bugTracker.get('id'),
                 content: bugTracker,
                 bugNumber: bugNumber,
                 elementId: 'bug-' + bugTracker.get('id'),
                 content: bugTracker,
                 bugNumber: bugNumber,
+                bugUrl: bugTracker.urlFromBugNumber(bugNumber),
                 editedBugNumber: bugNumber,
             });
         }));
                 editedBugNumber: bugNumber,
             });
         }));
@@ -1295,15 +1296,25 @@ App.AnalysisTaskController = Ember.Controller.extend({
         });
     }.observes('analysisPoints'),
     actions: {
         });
     }.observes('analysisPoints'),
     actions: {
-        associateBug: function (bugTracker, bugNumber)
+        addBug: function (bugTracker, bugNumber)
         {
             var model = this.get('model');
         {
             var model = this.get('model');
-            this.store.createRecord('bug',
-                {task: this.get('model'), bugTracker: bugTracker.get('content'), number: bugNumber}).save().then(function () {
-                    // FIXME: Should we notify the user?
-                }, function (error) {
-                    alert('Failed to associate the bug: ' + error);
-                });
+            if (!bugTracker)
+                bugTracker = this.get('bugTrackers').objectAt(0);
+            var bug = {task: this.get('model'), bugTracker: bugTracker.get('content'), number: bugNumber};
+            this.store.createRecord('bug', bug).save().then(function () {
+                alert('Associated the ' + bugTracker.get('name') + ' ' + bugNumber + ' with this analysis.');
+            }, function (error) {
+                alert('Failed to associate the bug: ' + error);
+            });
+        },
+        deleteBug: function (bug)
+        {
+            bug.destroyRecord().then(function () {
+                alert('Successfully deassociated the bug.');
+            }, function (error) {
+                alert('Failed to disassociate the bug: ' + error);
+            });
         },
         saveStatus: function ()
         {
         },
         saveStatus: function ()
         {
index 8c1fac1441d5955ca269ee56671acd80a6f023ca..30f9d1cff55f7cb941d85836994654de7c1a1b89 100755 (executable)
@@ -86,7 +86,7 @@
                                 {{#if chartData}}
                                     <div class="dashboard-status">
                                         {{#if latestStatus}}
                                 {{#if chartData}}
                                     <div class="dashboard-status">
                                         {{#if latestStatus}}
-                                            {{latestStatus.currentValue}} {{chartData.unit}}
+                                            {{latestStatus.currentValue}}{{chartData.unit}}
                                             {{#if latestStatus.label}}
                                                 <span {{bind-attr class=":status-label latestStatus.className"}}>{{latestStatus.label}}</span>
                                             {{/if}}
                                             {{#if latestStatus.label}}
                                                 <span {{bind-attr class=":status-label latestStatus.className"}}>{{latestStatus.label}}</span>
                                             {{/if}}
                     <tr>
                         <th>{{label}}</th>
                         <td>
                     <tr>
                         <th>{{label}}</th>
                         <td>
-                            {{#each bugs}}
-                                <a {{bind-attr href=bugUrl}} target="_blank">{{bugNumber}}</a>
-                            {{/each}}
+                        [{{bugUrl}}]
+                        <a {{bind-attr href=bugUrl}} target="_blank">{{bugNumber}}</a>
                         </td>
                     </tr>
                 {{/if}}
                         </td>
                     </tr>
                 {{/if}}
     <script type="text/x-handlebars" data-template-name="analysisStatusForm">
         <table class="analysis-bugs">
             <tbody>
     <script type="text/x-handlebars" data-template-name="analysisStatusForm">
         <table class="analysis-bugs">
             <tbody>
-                {{#each bugTrackers}}
+                {{#each model.bugs}}
                     <tr>
                     <tr>
-                        <th><label {{bind-attr for=elementId}}>{{label}}</label></th>
+                        <th>{{bugTracker.name}}</th>
                         <td>
                         <td>
-                            <form {{action "associateBug" this editedBugNumber on="submit"}}>
-                                {{input id=elementId type=text value=editedBugNumber}}
-                            </form>
+                            <a {{bind-attr href=url}} target="_blank">{{number}}</a>
+                            <a href="javascript:false" {{action "deleteBug" this}}>{{partial "close-button"}}</a>
                         </td>
                     </tr>
                 {{/each}}
                         </td>
                     </tr>
                 {{/each}}
+                {{#if bugTrackers}}
+                    <tr>
+                        <td>
+                            {{view Ember.Select content=bugTrackers optionValuePath="content" optionLabelPath="content.name" value=chosenBugTracker}}
+                        </td>
+                        <td>
+                            {{input id=elementId type=text value=editedBugNumber}}
+                            <button {{action "addBug" chosenBugTracker editedBugNumber}}>Add</button>
+                        </td>
+                    </tr>
+                {{/if}}
             </tbody>
             <tbody>
                 <tr>
             </tbody>
             <tbody>
                 <tr>
index ef68cae5cc4ba5d2541dd2d383dc889fe1ca9343..b8af8e926761295adb645e0b504e6dd6d3e4b02b 100755 (executable)
@@ -52,6 +52,10 @@ App.BugTracker = App.NameLabelModel.extend({
     bugUrl: DS.attr('string'),
     newBugUrl: DS.attr('string'),
     repositories: DS.hasMany('repository'),
     bugUrl: DS.attr('string'),
     newBugUrl: DS.attr('string'),
     repositories: DS.hasMany('repository'),
+    urlFromBugNumber: function (bugNumber) {
+        var template = this.get('bugUrl');
+        return template && bugNumber ? template.replace(/\$number/g, bugNumber) : null;
+    }
 });
 
 App.DateArrayTransform = DS.Transform.extend({
 });
 
 App.DateArrayTransform = DS.Transform.extend({