Home | History | Annotate | Download | only in ui
      1 /*
      2  * Copyright (C) 2011 Google Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  * 1. Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2. Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
     14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
     17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
     23  * THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 var ui = ui || {};
     27 ui.notifications = ui.notifications || {};
     28 
     29 (function(){
     30 
     31 var kMaxTestsPerGroup = 3;
     32 
     33 ui.notifications.Stream = base.extends('ol', {
     34     init: function()
     35     {
     36         this.className = 'notifications';
     37     },
     38     add: function(notification)
     39     {
     40         var insertBefore = null;
     41         Array.prototype.some.call(this.children, function(existingNotification) {
     42             if (existingNotification.index() < notification.index()) {
     43                 insertBefore = existingNotification;
     44                 return true;
     45             }
     46         });
     47         this.insertBefore(notification, insertBefore);
     48         return notification;
     49     }
     50 });
     51 
     52 ui.notifications.Notification = base.extends('li', {
     53     init: function()
     54     {
     55         this._how = this.appendChild(document.createElement('div'));
     56         this._how.className = 'how';
     57         this._what = this.appendChild(document.createElement('div'));
     58         this._what.className = 'what';
     59         this._index = 0;
     60         $(this).hide().fadeIn('fast');
     61     },
     62     index: function()
     63     {
     64         return this._index;
     65     },
     66     setIndex: function(index)
     67     {
     68         this._index = index;
     69     },
     70     dismiss: function()
     71     {
     72         // FIXME: These fade in/out effects are lame.
     73         $(this).fadeOut(function()
     74         {
     75             this.parentNode && this.parentNode.removeChild(this);
     76         });
     77     },
     78 });
     79 
     80 ui.notifications.Info = base.extends(ui.notifications.Notification, {
     81     init: function(message)
     82     {
     83         this.update(message);
     84     },
     85     update: function(message)
     86     {
     87         this._what.textContent = message;
     88     },
     89     updateWithNode: function(node)
     90     {
     91         $(this._what).empty();
     92         this._what.appendChild(node);
     93     }
     94 });
     95 
     96 ui.notifications.FailingTestGroup = base.extends('li', {
     97     init: function(groupName, testNameList)
     98     {
     99         this.appendChild(base.createLinkNode(ui.urlForFlakinessDashboard(testNameList), groupName, '_blank'));
    100     }
    101 });
    102 
    103 var Cause = base.extends('li', {
    104     init: function()
    105     {
    106         this._description = this.appendChild(document.createElement('div'));
    107         this._description.className = 'description';
    108     }
    109 });
    110 
    111 ui.notifications.SuspiciousCommit = base.extends(Cause, {
    112     init: function(commitData)
    113     {
    114         this._revision = commitData.revision;
    115         this._description.appendChild(base.createLinkNode(trac.changesetURL(commitData.revision), commitData.revision, '_blank'));
    116         this._details = this._description.appendChild(document.createElement('span'));
    117         this._addDetail('summary', commitData);
    118         this._addDetail('author', commitData);
    119         this._addDetail('reviewer', commitData);
    120         // FIXME: Add bugID detail.
    121         // this._addDetail('bugID', commitData, bugzilla.bugURL);
    122     },
    123     hasRevision: function(revision)
    124     {
    125         return this._revision == revision;
    126     },
    127     _addDetail: function(part, commitData, linkFunction)
    128     {
    129         var content = commitData[part];
    130         if (!content)
    131             return;
    132 
    133         var span = this._details.appendChild(document.createElement('span'));
    134         span.className = part;
    135 
    136         if (linkFunction) {
    137             var link = base.createLinkNode(linkFunction(content), content, '_blank');
    138             span.appendChild(link);
    139         } else
    140             span.textContent = content;
    141     }
    142 });
    143 
    144 ui.notifications.Failure = base.extends(ui.notifications.Notification, {
    145     init: function()
    146     {
    147         this._time = this._how.appendChild(new ui.RelativeTime());
    148         this._problem = this._what.appendChild(document.createElement('div'));
    149         this._problem.className = 'problem';
    150         this._effects = this._problem.appendChild(document.createElement('ul'));
    151         this._effects.className = 'effects';
    152         this._causes = this._what.appendChild(document.createElement('ul'));
    153         this._causes.className = 'causes';
    154     },
    155     date: function()
    156     {
    157         return this._time.date;
    158     }
    159 });
    160 
    161 ui.notifications.FailingTests = base.extends(ui.notifications.Failure, {
    162     init: function() {
    163         // FIXME: Convert actions to a link from test!
    164         this._problem.appendChild(new ui.actions.List([
    165             new ui.actions.Examine().makeDefault(),
    166             new ui.actions.Rebaseline(),
    167         ]));
    168         this._testNameList = [];
    169     },
    170     testNameList: function()
    171     {
    172         return this._testNameList;
    173     },
    174     containsFailureAnalysis: function(failureAnalysis)
    175     {
    176         return this._testNameList.indexOf(failureAnalysis.testName) != -1;
    177     },
    178     addFailureAnalysis: function(failureAnalysis)
    179     {
    180         if (this.containsFailureAnalysis(failureAnalysis))
    181             return false;
    182         this._testNameList.push(failureAnalysis.testName);
    183         $(this._effects).empty();
    184         this._forEachTestGroup(function(groupName, testNameList) {
    185             this._effects.appendChild(new ui.notifications.FailingTestGroup(groupName, testNameList))
    186         }.bind(this));
    187         return true;
    188     },
    189     _forEachTestGroup: function(callback)
    190     {
    191         var individualTests = [];
    192         base.forEachDirectory(this._testNameList, function(groupLabel, testsInDirectory) {
    193             if (testsInDirectory.length <= kMaxTestsPerGroup) {
    194                 individualTests = individualTests.concat(testsInDirectory);
    195                 return;
    196             }
    197             callback(groupLabel, testsInDirectory);
    198         });
    199         individualTests.forEach(function(testName) {
    200             callback(testName, [testName]);
    201         });
    202     }
    203 });
    204 
    205 ui.notifications.FailingTestsSummary = base.extends(ui.notifications.FailingTests, {
    206     init: function() {
    207         this._where = this._how.appendChild(new ui.failures.FailureGrid());
    208         this._commitDataPinned = false;
    209     },
    210     purge: function() {
    211         this._where.purge();
    212     },
    213     updateBuilderResults: function(resultNodesByBuilder)
    214     {
    215         this._where.update(resultNodesByBuilder);
    216     },
    217     addFailureAnalysis: function(failureAnalysis)
    218     {
    219         this.updateBuilderResults(failureAnalysis.resultNodesByBuilder);
    220         if (!ui.notifications.FailingTests.prototype.addFailureAnalysis.call(this, failureAnalysis))
    221             return false;
    222     },
    223     pinToCommitData: function(commitData)
    224     {
    225         if (this._commitDataPinned)
    226             return;
    227         this._commitDataPinned = true;
    228         $(this._causes).children().each(function() {
    229             if (this.hasRevision(commitData.revision))
    230                 return;
    231             $(this).detach();
    232         });
    233     },
    234     addCommitData: function(commitData)
    235     {
    236         if (this._commitDataPinned)
    237             return null;
    238         var commitDataDate = new Date(commitData.time);
    239         if (this._time.date > commitDataDate); {
    240             this.setIndex(commitDataDate.getTime());
    241             this._time.setDate(commitDataDate);
    242         }
    243         return this._causes.appendChild(new ui.notifications.SuspiciousCommit(commitData));
    244     }
    245 });
    246 
    247 ui.notifications.BuildersFailing = base.extends(ui.notifications.Failure, {
    248     init: function(message)
    249     {
    250         this._problem.insertBefore(document.createTextNode(message + ':'), this._problem.firstChild);
    251     },
    252     setFailingBuilders: function(failuresList)
    253     {
    254         $(this._effects).empty().append(Object.keys(failuresList).map(function(builderName) {
    255             var effect = document.createElement('li');
    256             effect.className = 'builder';
    257             effect.appendChild(new ui.failures.Builder(builderName, failuresList[builderName]));
    258             return effect;
    259         }));
    260     }
    261 });
    262 
    263 })();
    264