links to revisions working. better resultstatus handling.

This commit is contained in:
Cameron Dawson 2013-12-05 16:01:14 -08:00
Родитель ed9f67d099
Коммит 7d4b6a8330
9 изменённых файлов: 267 добавлений и 107 удалений

Просмотреть файл

@ -75,13 +75,13 @@ body {
}
.revision {
font-size: 10px;
font-size: 12px;
padding-top: 2px;
overflow: auto;
}
.platform {
font-size: 11px;
font-size: 12px;
padding-left: 0;
padding-right: 5px;
}
@ -96,7 +96,17 @@ body {
padding-left: 0;
}
.result-set .job-list {
.revision-list {
overflow: auto;
white-space: nowrap;
}
.result-set .job-list-pad-left {
padding-left: 8;
padding-right: 0;
}
.result-set .job-list-nopad {
padding-left: 0;
padding-right: 0;
}
@ -123,10 +133,127 @@ body {
}
/* Custom Job buttons*/
.btn-orange {
background-color: rgba(221, 102, 2, 0.56);
border-color: #dd6602;
color: white;
}
.btn-orange:hover,
.btn-orange:focus,
.btn-orange:active,
.btn-orange.active {
background-color: #c45a02;
border-color: #aa4f02;
color: white;
}
.btn-orange.disabled:hover,
.btn-orange.disabled:focus,
.btn-orange.disabled:active,
.btn-orange.disabled.active,
.btn-orange[disabled]:hover,
.btn-orange[disabled]:focus,
.btn-orange[disabled]:active,
.btn-orange[disabled].active,
fieldset[disabled] .btn-orange:hover,
fieldset[disabled] .btn-orange:focus,
fieldset[disabled] .btn-orange:active,
fieldset[disabled] .btn-orange.active {
background-color: #dd6602;
border-color: #dd6602;
}
.btn-red {
background-color: rgba(144, 0, 0, 0.60);
border-color: #a1020e;
color: white;
}
.btn-red:hover,
.btn-red:focus,
.btn-red:active,
.btn-red.active {
background-color: #a9020c;
border-color: #90010a;
color: white;
}
.btn-red.disabled:hover,
.btn-red.disabled:focus,
.btn-red.disabled:active,
.btn-red.disabled.active,
.btn-red[disabled]:hover,
.btn-red[disabled]:focus,
.btn-red[disabled]:active,
.btn-red[disabled].active,
fieldset[disabled] .btn-red:hover,
fieldset[disabled] .btn-red:focus,
fieldset[disabled] .btn-red:active,
fieldset[disabled] .btn-red.active {
background-color: #c2020e;
border-color: #c2020e;
}
.btn-dkblue {
background-color: rgba(44, 71, 174, 0.57);
border-color: #283aa2;
color: white;
}
.btn-dkblue:hover,
.btn-dkblue:focus,
.btn-dkblue:active,
.btn-dkblue.active {
background-color: #263fc3;
border-color: #2238ae;
color: white;
}
.btn-dkblue.disabled:hover,
.btn-dkblue.disabled:focus,
.btn-dkblue.disabled:active,
.btn-dkblue.disabled.active,
.btn-dkblue[disabled]:hover,
.btn-dkblue[disabled]:focus,
.btn-dkblue[disabled]:active,
.btn-dkblue[disabled].active,
fieldset[disabled] .btn-dkblue:hover,
fieldset[disabled] .btn-dkblue:focus,
fieldset[disabled] .btn-dkblue:active,
fieldset[disabled] .btn-dkblue.active {
background-color: #2d48d6;
border-color: #2d48d6;
}
.btn-green {
background-color: rgba(2, 151, 42, 0.47);
border-color: #028233;
color: white;
}
.btn-green:hover,
.btn-green:focus,
.btn-green:active,
.btn-green.active {
background-color: #02a931;
border-color: #019029;
color: white;
}
.btn-green.disabled:hover,
.btn-green.disabled:focus,
.btn-green.disabled:active,
.btn-green.disabled.active,
.btn-green[disabled]:hover,
.btn-green[disabled]:focus,
.btn-green[disabled]:active,
.btn-green[disabled].active,
fieldset[disabled] .btn-green:hover,
fieldset[disabled] .btn-green:focus,
fieldset[disabled] .btn-green:active,
fieldset[disabled] .btn-green.active {
background-color: #02c238;
border-color: #02c238;
}
.btn-purple {
background-color: #9002c2;
border-color: #9002c2;
background-color: rgba(61, 2, 85, 0.50);
border-color: #6f0296;
color: white;
}
.btn-purple:hover,
@ -239,8 +366,9 @@ fieldset[disabled] .btn-dkgray.active {
}
.btn-black {
background-color: #000000;
background-color: rgba(0, 0, 0, 0.71);
border-color: #000000;
color: white;
}
.btn-black:hover,
.btn-black:focus,
@ -248,6 +376,7 @@ fieldset[disabled] .btn-dkgray.active {
.btn-black.active {
background-color: #000000;
border-color: #000000;
color: white;
}
.btn-black.disabled:hover,
.btn-black.disabled:focus,
@ -266,8 +395,9 @@ fieldset[disabled] .btn-black.active {
}
.btn-pink {
background-color: #fa73ac;
background-color: rgba(250, 115, 172, 0.63);
border-color: #fa73ac;
color: white;
}
.btn-pink:hover,
.btn-pink:focus,
@ -275,6 +405,7 @@ fieldset[disabled] .btn-black.active {
.btn-pink.active {
background-color: #f95a9d;
border-color: #f8428f;
color: white;
}
.btn-pink.disabled:hover,
.btn-pink.disabled:focus,

Просмотреть файл

@ -1,7 +1,7 @@
<!DOCTYPE html>
<html ng-app="treeherder">
<head>
<title>Treeherder: {{ repo }}</title>
<title>Treeherder: {{ repoName }}</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<!-- Bootstrap -->
@ -19,14 +19,16 @@
<li class="dropdown" ng-controller="RepoDropDownCtrl">
<a href="" class="dropdown-toggle" data-toggle="dropdown">Repos<b class="caret"></b></a>
<ul class="dropdown-menu">
<li ng-repeat="item in repos"><a href="" ng-click="changeRepo(item.name)">{{item.name}}</a></li>
<li ng-repeat="item in repos">
<a href="" ng-click="changeRepo(item)" ng-bind="item.name"></a>
</li>
</ul>
</li>
<li class="divider-vertical"></li>
<li><a href="">Help</a></li>
</ul>
<span class="navbar-text">
<span class="label label-info">{{ repo }}</span>
<span class="label label-info">{{ repoName }}</span>
<span class="label label-info">0 unstarred</span>
</span>
<p class="navbar-text pull-right">

Просмотреть файл

@ -2,16 +2,18 @@
treeherder.controller('JobsCtrl',
function JobsCtrl($scope, $http, $rootScope, $routeParams, $log,
thUrl, thResultSets) {
thUrl, thResultSets, thRepos) {
// set the default repo to mozilla-central if not specified
// set the default repo to mozilla-inbound if not specified
if ($routeParams.hasOwnProperty("repo") &&
$routeParams.repo !== "") {
$rootScope.repo = $routeParams.repo;
$rootScope.repoName = $routeParams.repo;
} else {
$rootScope.repo = "mozilla-inbound";
$rootScope.repoName = "mozilla-central";
}
thRepos.load($scope.repoName);
$scope.offset = 0;
$scope.result_sets = [];
$scope.isLoadingRsBatch = false;
@ -40,72 +42,31 @@ treeherder.controller('JobsCtrl',
treeherder.controller('ResultSetCtrl',
function ResultSetCtrl($scope, $rootScope, $http, $log,
thUrl, thServiceDomain) {
var SEVERITY = {
"busted": {
level: 1,
isCollapsedResults: false
},
"exception": {
level: 2,
isCollapsedResults: false
},
"testfailed": {
level: 3,
isCollapsedResults: false
},
"unknown": { // completed, unknown error
level: 4,
isCollapsedResults: true
},
"usercancel": {
level: 5,
isCollapsedResults: false
},
"retry": {
level: 6,
isCollapsedResults: true
},
"success": {
level: 7,
isCollapsedResults: true
},
"running": {
level: 8,
isCollapsedResults: true
},
"pending": {
level: 100,
isCollapsedResults: true
}
};
thUrl, thServiceDomain, thResultStatusInfo) {
// determine the greatest severity this resultset contains
// so that the UI can show depict that
var getSeverity = function(result_types) {
// so that the UI can depict that
var getMostSevereResultStatus = function(result_types) {
var severity = "unknown",
highest = SEVERITY.unknown;
var status = "pending",
rsInfo = thResultStatusInfo(status);
for (var i = 0; i < result_types.length; i++) {
if (SEVERITY[result_types[i]]) {
if (SEVERITY[result_types[i]].level < highest.level) {
severity = result_types[i];
highest = SEVERITY[severity];
}
} else {
console.warn("WARNING: Unidentified result_type: " + result_types[i]);
var res = thResultStatusInfo(result_types[i]);
if (res.severity < rsInfo.severity) {
status = result_types[i];
rsInfo = res;
}
}
return severity;
return {status: status, isCollapsedResults: rsInfo.isCollapsedResults};
};
$scope.resultSeverity = getSeverity($scope.resultset.result_types);
var severeResultStatus = getMostSevereResultStatus($scope.resultset.result_types);
$scope.resultSeverity = severeResultStatus.status;
$scope.isCollapsedResults = severeResultStatus.isCollapsedResults;
// whether or not revision list for a resultset is collapsed
$scope.isCollapsedRevisions = true;
$scope.isCollapsedResults = SEVERITY[$scope.resultSeverity].isCollapsedResults;
// convert the platform names to human-readable using the TBPL
// Config.js file
@ -122,9 +83,6 @@ treeherder.controller('ResultSetCtrl',
}
}
$scope.viewJob = function(job) {
// set the selected job
$rootScope.selectedJob = job;

Просмотреть файл

@ -21,10 +21,10 @@ treeherder.controller('MainCtrl',
treeherder.controller('RepoDropDownCtrl',
function RepoDropDownCtrl($scope, $http, $location, thRepos) {
function RepoDropDownCtrl($scope, $rootScope, $http, $location, thRepos) {
$scope.changeRepo = function(repo) {
$location.search({repo: repo});
thRepos.setCurrent(repo.name);
$location.search({repo: repo.name});
};
thRepos.getRepos($scope);
}
);

Просмотреть файл

@ -67,7 +67,7 @@ treeherder.directive('thStar', function ($parse, thStarTypes) {
},
link: function(scope, element, attrs) {
scope.$watch('starId', function(newVal) {
if (newVal) {
if (newVal !== undefined) {
scope.starType = thStarTypes[newVal];
scope.badgeColorClass=scope.starType.star;
scope.hoverText=scope.starType.name;
@ -99,3 +99,14 @@ treeherder.directive('thShowJobs', function ($parse, thResultStatusInfo) {
'{{ \' jobs\' | showOrHide:isCollapsedResults }}</a>'
};
});
treeherder.directive('thRevision', function($parse) {
return {
restrict: "E",
link: function(scope, element, attrs) {
scope.revisionUrl = scope.currentRepo.url + "/rev/" + scope.revision.revision;
},
templateUrl: 'partials/thRevision.html'
};
});

Просмотреть файл

@ -29,7 +29,7 @@ treeherder.provider('thStarTypes', function() {
},
4: {
name: "intermittent needs filing",
star: "label-important"
star: "label-danger"
}
};
};
@ -40,6 +40,8 @@ treeherder.provider('thResultStatusInfo', function() {
return function(resultState) {
// default if there is no match, used for pending
var resultStatusInfo = {
severity: 100,
isCollapsedResults: true,
btnClass: "btn-default",
showButtonIcon: "glyphicon glyphicon-time",
jobButtonIcon: ""
@ -48,56 +50,81 @@ treeherder.provider('thResultStatusInfo', function() {
switch (resultState) {
case "busted":
resultStatusInfo = {
btnClass: "btn-danger",
severity: 1,
isCollapsedResults: false,
btnClass: "btn-red",
showButtonIcon: "glyphicon glyphicon-fire",
jobButtonIcon: "glyphicon glyphicon-fire"
};
break;
case "exception":
resultStatusInfo = {
severity: 2,
isCollapsedResults: false,
btnClass: "btn-purple",
showButtonIcon: "glyphicon glyphicon-fire",
jobButtonIcon: "glyphicon glyphicon-fire"
};
break;
case "running":
case "testfailed":
resultStatusInfo = {
btnClass: "btn-ltgray",
showButtonIcon: "glyphicon glyphicon-time",
severity: 3,
isCollapsedResults: false,
btnClass: "btn-orange",
showButtonIcon: "glyphicon glyphicon-warning-sign",
jobButtonIcon: "glyphicon glyphicon-warning-sign"
};
break;
case "unknown":
resultStatusInfo = {
severity: 4,
isCollapsedResults: false,
btnClass: "btn-black",
showButtonIcon: "glyphicon glyphicon-warning-sign",
jobButtonIcon: ""
};
break;
case "usercancel":
resultStatusInfo = {
severity: 5,
isCollapsedResults: true,
btnClass: "btn-pink",
showButtonIcon: "glyphicon glyphicon-stop",
jobButtonIcon: ""
};
break;
case "retry":
resultStatusInfo = {
btnClass: "btn-primary",
severity: 6,
isCollapsedResults: true,
btnClass: "btn-dkblue",
showButtonIcon: "glyphicon glyphicon-time",
jobButtonIcon: ""
};
break;
case "success":
resultStatusInfo = {
btnClass: "btn-success",
severity: 7,
isCollapsedResults: true,
btnClass: "btn-green",
showButtonIcon: "glyphicon glyphicon-ok",
jobButtonIcon: ""
};
break;
case "testfailed":
case "running":
resultStatusInfo = {
btnClass: "btn-warning",
showButtonIcon: "glyphicon glyphicon-warning-sign",
jobButtonIcon: "glyphicon glyphicon-warning-sign"
};
break;
case "usercancel":
resultStatusInfo = {
btnClass: "btn-pink",
showButtonIcon: "glyphicon glyphicon-stop",
severity: 8,
isCollapsedResults: true,
btnClass: "btn-ltgray",
showButtonIcon: "glyphicon glyphicon-time",
jobButtonIcon: ""
};
break;
case "unknown":
case "pending":
resultStatusInfo = {
btnClass: "btn-black",
severity: 100,
isCollapsedResults: true,
btnClass: "btn-default",
showButtonIcon: "glyphicon glyphicon-time",
jobButtonIcon: ""
};

Просмотреть файл

@ -9,10 +9,10 @@ treeherder.factory('thUrl',
return thServiceDomain + "/api" + uri;
},
getProjectUrl: function(uri) {
return thServiceDomain + "/api/project/" + $rootScope.repo + uri;
return thServiceDomain + "/api/project/" + $rootScope.repoName + uri;
},
getLogViewerUrl: function(artifactId) {
return "logviewer.html#?id=" + artifactId + "&repo=" + $rootScope.repo;
return "logviewer.html#?id=" + artifactId + "&repo=" + $rootScope.repoName;
}
};
return thUrl;
@ -55,17 +55,48 @@ treeherder.factory('thResultSets',
}]);
treeherder.factory('thRepos',
['$http', 'thUrl', '$rootScope',
function($http, thUrl, $rootScope) {
['$http', 'thUrl', '$rootScope', '$log',
function($http, thUrl, $rootScope, $log) {
// get the repositories (aka trees)
// sample: 'resources/menu.json'
var byName = function(name) {
if ($rootScope.repos != undefined) {
for (var i = 0; i < $rootScope.repos.length; i++) {
var repo = $rootScope.repos[i];
if (repo.name === name) {
return repo;
}
};
} else {
$log.warn("Repos list has not been loaded.")
}
$log.warn("'" + name + "' not found in repos list.")
return null;
}
return {
getRepos: function($rootScope) {
$http.get(thUrl.getRootUrl("/repository/")).
// load the list of repos into $rootScope, and set the current repo.
load: function(name) {
return $http.get(thUrl.getRootUrl("/repository/")).
success(function(data) {
$rootScope.repos = data;
if (name) {
$rootScope.currentRepo = byName(name)
}
});
},
// return the currently selected repo
getCurrent: function() {
return $rootScope.currentRepo;
},
// set the current repo to one in the repos list
setCurrent: function(name) {
$rootScope.currentRepo = byName(name)
},
// get a repo object without setting anything
getRepo: function(name) {
return byName(name);
}
};
}]);

Просмотреть файл

@ -6,8 +6,7 @@
<span th-show-jobs severity="resultSeverity"></span>
<a class="text-left btn btn-info th-revision-btn"
ng-click="isCollapsedRevisions = !isCollapsedRevisions"
>
ng-click="isCollapsedRevisions = !isCollapsedRevisions">
<div class="text-left">{{resultset.push_timestamp*1000|date:'medium'}} - {{resultset.author}} - {{resultset.revision}}</div>
</a>
@ -42,15 +41,13 @@
ng-class="{'col-md-4': (isCollapsedResults==false)}"
class="revision-list">
<ul class="list-unstyled">
<li ng-repeat="revision in resultset.revision_list"
class="revision">
<span class="label label-default">{{revision.revision}}</span> {{revision.author}} <span ng-show="revision.comment" class="italic">"{{revision.comments}}"</span>
<li ng-repeat="revision in resultset.revision_list">
<th-revision></th-revision>
</li>
</ul>
</span>
<span ng-hide="isCollapsedResults"
ng-class="{'col-md-8': (isCollapsedRevisions==false), 'col-md-12': (isCollapsedRevisions)}"
class="job-list">
ng-class="{'col-md-8 job-list-pad-left': (isCollapsedRevisions==false), 'col-md-12 job-list-nopad': (isCollapsedRevisions)}">
<table class="table-hover">
<tr ng-repeat="platform in resultset.platforms | filter:query">
<td class="col-md-2 platform"><span>{{ platform.name }}</span></td>

Просмотреть файл

@ -0,0 +1,3 @@
<span class="revision">
<a href="{{revisionUrl}}" target="_blank">{{revision.revision}}</a> {{revision.author}} <span ng-show="revision.comments"><em>"{{revision.comments}}"</em></span>
</span>