coalesced jobs visible and filterable

This commit is contained in:
Cameron Dawson 2014-05-14 16:01:24 -07:00
Родитель 0a53fc2136
Коммит 64fa1a7a09
16 изменённых файлов: 251 добавлений и 115 удалений

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

@ -296,19 +296,18 @@ body {
}
.result-set-title-left {
width: 600px;
padding-right: 10px;
white-space: nowrap;
padding-top: 5px;
}
.result-set .revision-list {
padding-left: 0;
}
.revision-link {
padding-top: 5px;
width: 155px;
.result-set-buttons {
width: 242px;
display: block;
}
.revision-text {
overflow: hidden;
text-overflow: ellipsis;
}
@ -668,6 +667,10 @@ ul.bug-suggestion-list li .btn-xs{
* RESULT STATUS COUNTS
*/
.result-counts {
margin-left: -11px;
}
.result-status-shading-success {background-color: rgba(2, 131, 44, 0.24);}
.result-status-shading-testfailed {background-color: rgba(221, 102, 2, 0.25);}
.result-status-shading-busted {background-color: rgba(144, 0, 0, 0.25);}
@ -676,6 +679,7 @@ ul.bug-suggestion-list li .btn-xs{
.result-status-shading-usercancel {background-color: rgba(250, 115, 172, 0.25)}
.result-status-shading-pending {background-color: white;}
.result-status-shading-running {background-color: white;}
.result-status-shading-coalesced {background-color: white;}
.result-status-count-group {
font-size: 12px;
@ -721,6 +725,9 @@ ul.bug-suggestion-list li .btn-xs{
.result-status-count-pending {
width: 69px;
}
.result-status-count-coalesced {
width: 75px;
}
.click-able-icon, .nav-tabs li {
cursor: pointer;
@ -982,6 +989,36 @@ fieldset[disabled] .btn-purple.active {
color: rgba(61, 2, 85, 0.68);
}
.btn-yellow {
border-color: rgba(205, 206, 29, 0.24);
color: #cdce1d;
}
.btn-yellow:hover,
.btn-yellow:focus,
.btn-yellow:active,
.btn-yellow.active {
border-color: #cdce1d;
color: #cdce1d;
}
.btn-yellow.disabled:hover,
.btn-yellow.disabled:focus,
.btn-yellow.disabled:active,
.btn-yellow.disabled.active,
.btn-yellow[disabled]:hover,
.btn-yellow[disabled]:focus,
.btn-yellow[disabled]:active,
.btn-yellow[disabled].active,
fieldset[disabled] .btn-yellow:hover,
fieldset[disabled] .btn-yellow:focus,
fieldset[disabled] .btn-yellow:active,
fieldset[disabled] .btn-yellow.active {
border-color: #cdce1d;
}
.btn-yellow-count-classified, .btn-yellow-count-unclassified {
color: #cdce1d;
}
.btn-ltgray-count-unclassified, .btn-ltgray-count-classified {
border-color: #bfbfbf;
color: #e0e0e0;

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

@ -11,25 +11,22 @@ treeherder.controller('FilterPanelCtrl', [
var $log = new ThLog(this.constructor.name);
$scope.filterOptions = thResultStatusList;
$scope.filterOptions = thResultStatusList.all();
$scope.filterGroups = {
failures: {
value: "failures",
name: "failures",
allChecked: true,
resultStatuses: ["testfailed", "busted", "exception"]
},
nonfailures: {
value: "nonfailures",
name: "non-failures",
allChecked: true,
resultStatuses: ["success", "retry", "usercancel"]
resultStatuses: ["success", "retry", "usercancel", "coalesced"]
},
inProgress: {
value: "inProgress",
name: "in progress",
allChecked: true,
resultStatuses: ["pending", "running"]
}
};
@ -41,7 +38,7 @@ treeherder.controller('FilterPanelCtrl', [
*
* quiet - whether or not to broadcast a message about this change.
*/
$scope.toggleResultStatusGroup = function(group, quiet) {
$scope.toggleResultStatusGroup = function(group) {
var check = function(rs) {
$scope.resultStatusFilters[rs] = group.allChecked;
};
@ -52,11 +49,6 @@ treeherder.controller('FilterPanelCtrl', [
group.resultStatuses,
group.allChecked
);
if (!quiet) {
$rootScope.$broadcast(thEvents.globalFilterChanged,
{target: group, newValue: group.allChecked});
}
};
/**
@ -72,8 +64,6 @@ treeherder.controller('FilterPanelCtrl', [
} else {
thJobFilters.addFilter(thJobFilters.resultStatus, filter);
}
$rootScope.$broadcast(thEvents.globalFilterChanged,
{target: filter, newValue: $scope.resultStatusFilters[filter]});
};
/**
@ -92,7 +82,7 @@ treeherder.controller('FilterPanelCtrl', [
* ``classified`` (when true) or ``unclassified``
* (when false)
*/
$scope.setClassificationFilter = function(isClassified, isChecked, quiet) {
$scope.setClassificationFilter = function(isClassified, isChecked) {
var field = "isClassified";
// this function is called before the checkbox value has actually
// changed the scope model value, so change to the inverse.
@ -100,11 +90,6 @@ treeherder.controller('FilterPanelCtrl', [
var target = isClassified? "classified": "unclassified";
func(field, isClassified, thJobFilters.matchType.bool);
if (!quiet) {
$rootScope.$broadcast(thEvents.globalFilterChanged,
{target: target, newValue: isChecked});
}
};
$scope.createFieldFilter = function() {
@ -149,18 +134,12 @@ treeherder.controller('FilterPanelCtrl', [
field: $scope.newFieldFilter.field,
value: value
});
$rootScope.$broadcast(thEvents.globalFilterChanged,
{target: $scope.newFieldFilter.field, newValue: $scope.newFieldFilter.value});
$scope.newFieldFilter = null;
};
$scope.removeAllFieldFilters = function() {
$scope.fieldFilters.forEach(function(ff) {
thJobFilters.removeFilter(ff.field, ff.value);
});
$rootScope.$broadcast(thEvents.globalFilterChanged,
{target: "allFieldFilters", newValue: null});
thJobFilters.removeAllFieldFilters();
$scope.fieldFilters = [];
};
@ -170,14 +149,10 @@ treeherder.controller('FilterPanelCtrl', [
$scope.fieldFilters[index].field,
$scope.fieldFilters[index].value
);
$rootScope.$broadcast(thEvents.globalFilterChanged,
{target: $scope.fieldFilters[index].field, newValue: null});
$scope.fieldFilters.splice(index, 1);
};
$scope.pinAllShownJobs = function() {
thJobFilters.pinAllShownJobs();
};
$scope.thJobFilters = thJobFilters;
var updateToggleFilters = function() {
for (var i = 0; i < $scope.filterOptions.length; i++) {

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

@ -3,11 +3,11 @@
treeherder.controller('JobsCtrl', [
'$scope', '$http', '$rootScope', '$routeParams', 'ThLog', '$cookies',
'localStorageService', 'thUrl', 'ThRepositoryModel', 'thSocket',
'ThResultSetModel', 'thResultStatusCountsList', '$location', 'thEvents',
'ThResultSetModel', 'thResultStatusList', '$location', 'thEvents',
function JobsCtrl(
$scope, $http, $rootScope, $routeParams, ThLog, $cookies,
localStorageService, thUrl, ThRepositoryModel, thSocket,
ThResultSetModel, thResultStatusCountsList, $location, thEvents) {
ThResultSetModel, thResultStatusList, $location, thEvents) {
var $log = new ThLog(this.constructor.name);
@ -33,7 +33,7 @@ treeherder.controller('JobsCtrl', [
$scope.isLoadingRsBatch = ThResultSetModel.getLoadingStatus($scope.repoName);
$scope.result_sets = ThResultSetModel.getResultSetsArray($scope.repoName);
$scope.job_map = ThResultSetModel.getJobMap($scope.repoName);
$scope.statusList = thResultStatusCountsList;
$scope.statusList = thResultStatusList.counts();
// determine how many resultsets to fetch. default to 10.
var count = 10;
@ -127,6 +127,10 @@ treeherder.controller('ResultSetCtrl', [
};
$scope.pinAllShownJobs = function() {
thJobFilters.pinAllShownJobs($scope.resultset.id, $scope.resultStatusFilters);
};
$scope.revisionUrlCopied = function(revision) {
thNotify.send("url to " + revision + " copied to clipboard");
};

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

@ -116,7 +116,6 @@ treeherder.controller('MainCtrl', [
$scope.toggleExcludedJobs = function() {
thJobFilters.toggleSkipExclusionProfiles();
$rootScope.$broadcast(thEvents.globalFilterChanged);
};
$scope.toggleUnclassifiedFailures = function() {
@ -126,13 +125,10 @@ treeherder.controller('MainCtrl', [
} else {
thJobFilters.showUnclassifiedFailures();
}
$rootScope.$broadcast(thEvents.globalFilterChanged);
};
$scope.toggleInProgress = function() {
thJobFilters.toggleInProgress();
$rootScope.$broadcast(thEvents.globalFilterChanged);
};
$scope.allExpanded = function(cls) {

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

@ -2,15 +2,12 @@
treeherder.directive('thPinnedJob', [
'thResultStatusInfo',
function (thResultStatusInfo) {
'thResultStatusInfo', 'thResultStatus',
function (thResultStatusInfo, thResultStatus) {
var getHoverText = function(job) {
var duration = Math.round((job.end_timestamp - job.start_timestamp) / 60);
var status = job.result;
if (job.state !== "completed") {
status = job.state;
}
var status = thResultStatus(job);
return job.job_type_name + " - " + status + " - " + duration + "mins";
};
@ -18,10 +15,7 @@ treeherder.directive('thPinnedJob', [
restrict: "E",
link: function(scope, element, attrs) {
var unbindWatcher = scope.$watch("job", function(newValue) {
var resultState = scope.job.result;
if (scope.job.state !== "completed") {
resultState = scope.job.state;
}
var resultState = thResultStatus(scope.job);
scope.job.display = thResultStatusInfo(resultState);
scope.hoverText = getHoverText(scope.job);

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

@ -5,11 +5,12 @@ treeherder.directive('thCloneJobs', [
'$rootScope', '$http', 'ThLog', 'thUrl', 'thCloneHtml',
'thServiceDomain', 'thResultStatusInfo', 'thEvents', 'thAggregateIds',
'thJobFilters', 'thResultStatusObject', 'ThResultSetModel',
'ThJobModel', 'linkifyBugsFilter',
'ThJobModel', 'linkifyBugsFilter', 'thResultStatus',
function(
$rootScope, $http, ThLog, thUrl, thCloneHtml, thServiceDomain,
thResultStatusInfo, thEvents, thAggregateIds, thJobFilters,
thResultStatusObject, ThResultSetModel, ThJobModel, linkifyBugsFilter){
$rootScope, $http, ThLog, thUrl, thCloneHtml,
thServiceDomain, thResultStatusInfo, thEvents, thAggregateIds,
thJobFilters, thResultStatusObject, ThResultSetModel,
ThJobModel, linkifyBugsFilter, thResultStatus){
var $log = new ThLog("thCloneJobs");
@ -49,10 +50,7 @@ treeherder.directive('thCloneJobs', [
};
var getHoverText = function(job) {
var jobStatus = job.result;
if (job.state !== "completed") {
jobStatus = job.state;
}
var jobStatus = thResultStatus(job);
var result = job.job_type_name + " - " + jobStatus;
$log.debug("job timestamps", job, job.end_timestamp, job.submit_timestamp);
if (job.end_timestamp && job.submit_timestamp) {
@ -181,16 +179,7 @@ treeherder.directive('thCloneJobs', [
job = jgObj.jobs[l];
//Set the resultState
resultState = job.result;
if (job.state !== "completed") {
resultState = job.state;
}
resultState = resultState || 'unknown';
if(job.job_coalesced_to_guid !== null){
// Don't count or render coalesced jobs
continue;
}
resultState = thResultStatus(job);
//Increment the jobCounts here so they're not modified by
//filtering

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

@ -11,14 +11,24 @@ treeherder.provider('thServiceDomain', function() {
});
treeherder.provider('thResultStatusList', function() {
this.$get = function() {
var all = function() {
return ['success', 'testfailed', 'busted', 'exception', 'retry', 'usercancel', 'running', 'pending', 'coalesced'];
};
var counts = function() {
return ['success', 'testfailed', 'busted', 'exception', 'retry', 'running', 'pending', 'coalesced'];
};
var defaultFilters = function() {
return ['success', 'testfailed', 'busted', 'exception', 'retry', 'usercancel', 'running', 'pending'];
};
});
treeherder.provider('thResultStatusCountsList', function() {
this.$get = function() {
return ['success', 'testfailed', 'busted', 'exception', 'retry', 'running', 'pending'];
return {
all: all,
counts: counts,
defaultFilters: defaultFilters
};
};
});
@ -26,7 +36,9 @@ treeherder.provider('thResultStatus', function() {
this.$get = function() {
return function(job) {
var rs = job.result;
if (job.state !== "completed") {
if (job.job_coalesced_to_guid !== null) {
rs = 'coalesced';
} else if (job.state !== "completed") {
rs = job.state;
}
return rs;
@ -43,7 +55,8 @@ treeherder.provider('thResultStatusObject', function() {
'exception':0,
'retry':0,
'running':0,
'pending':0
'pending':0,
'coalesced': 0
};
};
@ -62,7 +75,6 @@ treeherder.provider('thResultStatusInfo', function() {
severity: 100,
isCollapsedResults: true,
btnClass: "btn-default",
showButtonIcon: "glyphicon glyphicon-time",
jobButtonIcon: ""
};
@ -72,7 +84,6 @@ treeherder.provider('thResultStatusInfo', function() {
severity: 1,
isCollapsedResults: false,
btnClass: "btn-red",
showButtonIcon: "glyphicon glyphicon-fire",
jobButtonIcon: "glyphicon glyphicon-fire",
countText: "busted"
};
@ -82,7 +93,6 @@ treeherder.provider('thResultStatusInfo', function() {
severity: 2,
isCollapsedResults: false,
btnClass: "btn-purple",
showButtonIcon: "glyphicon glyphicon-fire",
jobButtonIcon: "glyphicon glyphicon-fire",
countText: "exception"
};
@ -92,7 +102,6 @@ treeherder.provider('thResultStatusInfo', function() {
severity: 3,
isCollapsedResults: false,
btnClass: "btn-orange",
showButtonIcon: "glyphicon glyphicon-warning-sign",
jobButtonIcon: "glyphicon glyphicon-warning-sign",
countText: "failed"
};
@ -102,7 +111,6 @@ treeherder.provider('thResultStatusInfo', function() {
severity: 4,
isCollapsedResults: false,
btnClass: "btn-black",
showButtonIcon: "glyphicon glyphicon-warning-sign",
jobButtonIcon: "",
countText: "unknown"
};
@ -112,7 +120,6 @@ treeherder.provider('thResultStatusInfo', function() {
severity: 5,
isCollapsedResults: true,
btnClass: "btn-pink",
showButtonIcon: "glyphicon glyphicon-stop",
jobButtonIcon: "",
countText: "cancel"
};
@ -122,7 +129,6 @@ treeherder.provider('thResultStatusInfo', function() {
severity: 6,
isCollapsedResults: true,
btnClass: "btn-dkblue",
showButtonIcon: "glyphicon glyphicon-time",
jobButtonIcon: "",
countText: "retry"
};
@ -132,7 +138,6 @@ treeherder.provider('thResultStatusInfo', function() {
severity: 7,
isCollapsedResults: true,
btnClass: "btn-green",
showButtonIcon: "glyphicon glyphicon-ok",
jobButtonIcon: "",
countText: "success"
};
@ -142,7 +147,6 @@ treeherder.provider('thResultStatusInfo', function() {
severity: 8,
isCollapsedResults: true,
btnClass: "btn-dkgray",
showButtonIcon: "glyphicon glyphicon-time",
jobButtonIcon: "",
countText: "running"
};
@ -152,11 +156,19 @@ treeherder.provider('thResultStatusInfo', function() {
severity: 100,
isCollapsedResults: true,
btnClass: "btn-ltgray",
showButtonIcon: "glyphicon glyphicon-time",
jobButtonIcon: "",
countText: "pending"
};
break;
case "coalesced":
resultStatusInfo = {
severity: 101,
isCollapsedResults: true,
btnClass: "btn-yellow",
jobButtonIcon: "",
countText: "coalesced"
};
break;
}
return resultStatusInfo;

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

@ -0,0 +1,25 @@
'use strict';
treeherder.factory('thBuildApi', [
'$http', '$location', 'thUrl', 'thServiceDomain', 'ThLog',
function($http, $location, thUrl, thServiceDomain, ThLog) {
var $log = new ThLog("thBuildApi");
var selfServeUrl = "https://secure.pub.build.mozilla.org/buildapi/self-serve/";
return {
retrigger: function(repoName, buildId) {
var params = {
build_id: buildId
};
return $http.post(selfServeUrl + repoName + "/build",
{params: params}
);
},
cancel: function(repoName, buildId) {
return $http.delete(selfServeUrl + repoName + "/build/" + buildId);
}
};
}]);

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

@ -22,8 +22,9 @@
* must match at least one value in every field.
*/
treeherder.factory('thJobFilters', [
'thResultStatusList', 'ThLog', '$rootScope', 'ThResultSetModel',
'thPinboard', 'thNotify', 'thEvents', 'thResultStatus', 'ThRepositoryModel',
'thResultStatusList', 'ThLog', '$rootScope',
'ThResultSetModel', 'thPinboard', 'thNotify', 'thEvents',
'thResultStatus', 'ThRepositoryModel',
function(
thResultStatusList, ThLog, $rootScope,
ThResultSetModel, thPinboard, thNotify, thEvents,
@ -43,7 +44,7 @@ treeherder.factory('thJobFilters', [
var filters = {
resultStatus: {
matchType: matchType.exactstr,
values: thResultStatusList.slice(),
values: thResultStatusList.defaultFilters(),
removeWhenEmpty: false
},
isClassified: {
@ -98,8 +99,8 @@ treeherder.factory('thJobFilters', [
if (field === api.resultStatus) {
// resultStatus is a special case that spans two job fields
var filterList = resultStatusList || filters[field].values;
return _.contains(filterList, job.result) ||
_.contains(filterList, job.state);
var resultState = thResultStatus(job);
return _.contains(filterList, resultState);
} else if (field === api.isClassified) {
// isClassified is a special case, too. Where value of 1 in the
// job field of ``failure_classification_id`` is "not classified"
@ -208,6 +209,7 @@ treeherder.factory('thJobFilters', [
$log.debug("adding ", field, ": ", value);
$log.debug("filters", filters);
$rootScope.$broadcast(thEvents.globalFilterChanged);
};
var removeFilter = function(field, value) {
@ -220,6 +222,7 @@ treeherder.factory('thJobFilters', [
if(idx > -1) {
$log.debug("removing ", value);
filters[field].values.splice(idx, 1);
$rootScope.$broadcast(thEvents.globalFilterChanged);
}
}
@ -233,6 +236,32 @@ treeherder.factory('thJobFilters', [
$log.debug("filters", filters);
};
var removeAllFilters = function(field, value) {
var someRemoved = false;
var removeAll = function(field) {
if (!_.contains(['resultStatus', 'isClassified'], field)) {
filters[field].values = [];
someRemoved = true;
}
// if this filer no longer has any values, then remove it
// if it has the ``removeWhenEmpty`` setting
if (filters[field].removeWhenEmpty) {
delete filters[field];
}
};
_.forEach(filterKeys, removeAll);
if (someRemoved) {
$rootScope.$broadcast(thEvents.globalFilterChanged);
}
filterKeys = _.keys(filters);
$log.debug("filters", filters);
};
/**
* used mostly for resultStatus doing group toggles
*
@ -246,6 +275,7 @@ treeherder.factory('thJobFilters', [
for (var i = 0; i < values.length; i++) {
action(field, values[i]);
}
$rootScope.$broadcast(thEvents.globalFilterChanged);
};
var copyResultStatusFilters = function() {
@ -373,13 +403,19 @@ treeherder.factory('thJobFilters', [
/**
* Pin all jobs that pass the GLOBAL filters. Ignores toggling at
* the result set level.
*
* If optional resultsetId is passed in, then only pin jobs from that
* resultset.
*/
var pinAllShownJobs = function() {
var pinAllShownJobs = function(resultsetId, resultStatusFilters) {
var jobs = ThResultSetModel.getJobMap($rootScope.repoName);
var jobsToPin = [];
var queuePinIfShown = function(jMap) {
if (api.showJob(jMap.job_obj)) {
if (resultsetId && jMap.job_obj.result_set_id !== resultsetId) {
return;
}
if (api.showJob(jMap.job_obj, resultStatusFilters)) {
jobsToPin.push(jMap.job_obj);
}
};
@ -392,13 +428,14 @@ treeherder.factory('thJobFilters', [
true);
}
$rootScope.selectedJob = jobsToPin[0];
if (!$rootScope.selectedJob) {
$rootScope.selectedJob = jobsToPin[0];
}
_.forEach(jobsToPin, thPinboard.pinJob);
};
$rootScope.$on(thEvents.showUnclassifiedFailures, function() {
showUnclassifiedFailures();
$rootScope.$broadcast(thEvents.globalFilterChanged);
});
/**
@ -411,6 +448,20 @@ treeherder.factory('thJobFilters', [
};
filters.resultStatus.values = ["busted", "testfailed", "exception"];
filters.isClassified.values = [false];
$rootScope.$broadcast(thEvents.globalFilterChanged);
};
/**
* Set the non-field filters so that we only view coalesced jobs
*/
var showCoalesced = function() {
stashedStatusFilterValues = {
resultStatus: filters.resultStatus.values,
isClassified: filters.isClassified.values
};
filters.resultStatus.values = ["coalesced"];
filters.isClassified.values = [false, true];
$rootScope.$broadcast(thEvents.globalFilterChanged);
};
var toggleInProgress = function() {
@ -420,6 +471,7 @@ treeherder.factory('thJobFilters', [
}
func(api.resultStatus, 'pending');
func(api.resultStatus, 'running');
$rootScope.$broadcast(thEvents.globalFilterChanged);
};
/**
@ -436,8 +488,21 @@ treeherder.factory('thJobFilters', [
* is used to undo the call to ``showUnclassifiedFailures``.
*/
var resetNonFieldFilters = function() {
filters.resultStatus.values = thResultStatusList.defaultFilters();
filters.isClassified.values = [true, false];
$rootScope.$broadcast(thEvents.globalFilterChanged);
};
/**
* Revert the filters back to what they were before one of the
* showXXX functions was called.
*/
var revertNonFieldFilters = function() {
filters.resultStatus.values = stashedStatusFilterValues.resultStatus;
filters.isClassified.values = stashedStatusFilterValues.isClassified;
$rootScope.$broadcast(thEvents.globalFilterChanged);
};
var toggleSkipExclusionProfiles = function() {
@ -457,9 +522,11 @@ treeherder.factory('thJobFilters', [
filters: filters,
pinAllShownJobs: pinAllShownJobs,
showUnclassifiedFailures: showUnclassifiedFailures,
showCoalesced: showCoalesced,
toggleInProgress: toggleInProgress,
isUnclassifiedFailures: isUnclassifiedFailures,
resetNonFieldFilters: resetNonFieldFilters,
revertNonFieldFilters: revertNonFieldFilters,
toggleSkipExclusionProfiles: toggleSkipExclusionProfiles,
isSkippingExclusionProfiles: isSkippingExclusionProfiles,
excludedJobs: excludedJobs,

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

@ -9,10 +9,8 @@
data-id="{{resultset.id}}">
<div class="result-set-title row">
<span class="col-xs-5">
<a class="btn btn-default btn-sm" ng-hide="true"><i class=" glyphicon glyphicon-pushpin"></i></a>
<span class="col-xs-4 result-set-title-left">
<span class="btn btn-default btn-sm glyphicon glyphicon-download" ng-show="isLoadingJobs"></span>
<th-action-button ng-hide="isLoadingJobs"></th-action-button>
<span class="timestamp-name">
<span>
<a href="{{revisionResultsetFilterUrl}}"
@ -21,18 +19,25 @@
<th-author author="{{resultset.author}}"></th-author>
</span>
</span>
<span class="col-xs-3 revision-link">
<span class="btn btn-default btn-xs"
<span class="col-xs-4 result-set-buttons">
<span class="revision-text">{{resultset.revision}}</span>
<span class="btn btn-default btn-sm"
title="copy revision link to clipboard"
clip-copy="revisionResultsetFilterUrl"
clip-click="revisionUrlCopied(resultset.revision)">
<i class="glyphicon glyphicon-link"></i></span>
{{resultset.revision}}
<span class="btn btn-default btn-sm"
title="pin all visible jobs in this resultset"
ng-click="pinAllShownJobs()">
<span class="glyphicon glyphicon-pushpin"></span>
</span>
<th-action-button ng-hide="isLoadingJobs"></th-action-button>
</span>
<span class="col-xs-1 btn btn-default btn-sm revision-button"
ng-click="toggleRevisions()"
title="show revisions"><i class="fa fa-code-fork fa-lg"></i> {{resultset.revision_count}}</span>
<th-result-counts class="col-xs-4"/>
<th-result-counts class="col-xs-4 result-counts"/>
</div>
<div th-clone-jobs ></div>

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

@ -5,7 +5,13 @@
<span class="pull-right">
<span class="btn btn-default btn-xs"
title="pin all jobs that pass the global filters"
ng-click="pinAllShownJobs()"><i class="glyphicon glyphicon-pushpin"></i> pin all showing</span>
ng-click="thJobFilters.pinAllShownJobs()"><i class="glyphicon glyphicon-pushpin"></i> pin all showing</span>
<span class="btn btn-default btn-xs"
title="show only coalesced jobs"
ng-click="thJobFilters.showCoalesced()">coalesced only</span>
<span class="btn btn-default btn-xs"
title="reset to default status filters"
ng-click="thJobFilters.resetNonFieldFilters()">reset</span>
</span>
</div>

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

@ -3,7 +3,6 @@
ng-class="{'btn-lg selected-job': (selectedJob==job), 'btn-xs': (selectedJob!=job)}"
title="{{ hoverText }}"
ng-click="viewJob(job)"
ng-hide="job.job_coalesced_to_guid"
ng-right-click="viewLog(job.resource_uri)"
data-job-id="{{ job.job_id }}">
{{ job.job_type_symbol }}

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

@ -1,6 +1,6 @@
<span class="btn btn-default btn-sm result-status-total-count"
ng-click="toggleJobs()"
title="total job count - toggle jobs"><i class="fa fa-th-list fa-lg"></i> {{resultset.job_counts.total - totalExcluded()}}</span>
title="total job count - toggle jobs"><i class="fa fa-list fa-lg"></i> {{resultset.job_counts.total - totalExcluded()}}</span>
<span class="result-status-count-group">
<th-result-status-count ng-repeat="resultStatus in statusList"/>
</span>

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

@ -20,7 +20,7 @@
ng-click="toggleAllRevisions()"><i class="fa fa-code-fork fa-lg"></i></span>
<span class="btn btn-view-nav btn-sm"
title="collapse/expand all jobs"
ng-click="toggleAllJobs()"><i class="fa fa-th-list fa-lg"></i></span>
ng-click="toggleAllJobs()"><i class="fa fa-list fa-lg"></i></span>
<div ng-controller="SearchCtrl" class="form-group form-inline">
<input id="platform-job-text-search-field"
ng-model="searchQuery" ng-keyup="search($event)" type="text"

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

@ -4,12 +4,12 @@ treeherder.controller('PluginCtrl', [
'$scope', '$rootScope', 'thUrl', 'ThJobClassificationModel',
'thClassificationTypes', 'ThJobModel', 'thEvents', 'dateFilter',
'numberFilter', 'ThBugJobMapModel', 'thResultStatus', 'thSocket',
'ThResultSetModel', 'ThLog', '$q', 'thPinboard',
'ThResultSetModel', 'ThLog', '$q', 'thPinboard', 'ThJobArtifactModel',
function PluginCtrl(
$scope, $rootScope, thUrl, ThJobClassificationModel,
thClassificationTypes, ThJobModel, thEvents, dateFilter,
numberFilter, ThBugJobMapModel, thResultStatus, thSocket,
ThResultSetModel, ThLog, $q, thPinboard) {
ThResultSetModel, ThLog, $q, thPinboard, ThJobArtifactModel) {
var $log = new ThLog("PluginCtrl");
@ -24,7 +24,7 @@ treeherder.controller('PluginCtrl', [
$scope.job = newValue;
if(timeout_promise !== null){
console.log("timing out previous job request");
$log.debug("timing out previous job request");
timeout_promise.resolve();
}
timeout_promise = $q.defer();
@ -40,7 +40,16 @@ treeherder.controller('PluginCtrl', [
$scope.logs = data.logs;
});
$scope.artifacts = {};
ThJobArtifactModel.get_list({
name: "buildapi",
"type": "json",
job_id: $scope.job.id
}, {timeout: timeout_promise})
.then(function(data) {
if (data.length === 1 && _.has(data[0], 'blob')){
$scope.job.build_id = data[0].blob.id;
}
});
$scope.visibleFields = {
"Job Name": $scope.job.job_type_name,

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

@ -8,8 +8,26 @@
</ul>
<ul class="nav navbar-nav pull-right">
<li ng-show="job.build_id">
<a title="Cancel job"
href=""
target="_blank"
ng-click="cancelJob()">
<span class="fa fa-stop"></span>
</a>
</li>
<li ng-show="job.build_id">
<a title="Retrigger job"
href=""
target="_blank"
ng-click="retriggerJob()">
<span class="fa fa-play"></span>
</a>
</li>
<li ng-show="isReftest()">
<a title="Launch the Reftest Analyser in a new page" target="_blank" href="https://hg.mozilla.org/mozilla-central/raw-file/tip/layout/tools/reftest/reftest-analyzer.xhtml">
<a title="Launch the Reftest Analyser in a new page"
target="_blank"
href="https://hg.mozilla.org/mozilla-central/raw-file/tip/layout/tools/reftest/reftest-analyzer.xhtml">
<span class="fa fa-bar-chart-o"></span>
</a>
</li>
@ -38,10 +56,10 @@
<li>
<a href="" ng-click="togglePinboardVisibility()">
<span ng-hide="isPinboardVisible"
title="show pinboard"
title="Show the pinboard"
class="glyphicon glyphicon-chevron-down"></span>
<span ng-show="isPinboardVisible"
title="hide pinboard"
title="Hide the pinboard"
class="glyphicon glyphicon-chevron-up"></span>
</a>
</li>