Merge branch 'newbuildview'

This commit is contained in:
Joseph Schorr 2015-03-05 16:17:29 -05:00
commit 43ab838998
33 changed files with 1095 additions and 36 deletions

View file

@ -0,0 +1,19 @@
/**
* An element which displays the status of a build in a nice compact bar.
*/
angular.module('quay').directive('buildInfoBar', function () {
var directiveDefinitionObject = {
priority: 0,
templateUrl: '/static/directives/build-info-bar.html',
replace: false,
transclude: false,
restrict: 'C',
scope: {
'build': '=build',
'showTime': '=showTime'
},
controller: function($scope, $element) {
}
};
return directiveDefinitionObject;
});

View file

@ -0,0 +1,168 @@
/**
* An element which displays and auto-updates the logs from a build.
*/
angular.module('quay').directive('buildLogsView', function () {
var directiveDefinitionObject = {
priority: 0,
templateUrl: '/static/directives/build-logs-view.html',
replace: false,
transclude: false,
restrict: 'C',
scope: {
'build': '=build',
'useTimestamps': '=useTimestamps',
'buildUpdated': '&buildUpdated'
},
controller: function($scope, $element, $interval, $sanitize, ansi2html, AngularViewArray,
AngularPollChannel, ApiService, Restangular) {
var result = $element.find('#copyButton').clipboardCopy();
if (!result) {
$element.find('#copyButton').hide();
}
$scope.logEntries = null;
$scope.currentParentEntry = null;
$scope.logStartIndex = 0;
$scope.buildLogsText = '';
var pollChannel = null;
var currentBuild = null;
var appendToTextLog = function(type, message) {
if (type == 'phase') {
text = 'Starting phase: ' + message + '\n';
} else {
text = message + '\n';
}
$scope.buildLogsText += text.replace(new RegExp("\\033\\[[^m]+m"), '');
};
var processLogs = function(logs, startIndex, endIndex) {
if (!$scope.logEntries) { $scope.logEntries = []; }
// If the start index given is less than that requested, then we've received a larger
// pool of logs, and we need to only consider the new ones.
if (startIndex < $scope.logStartIndex) {
logs = logs.slice($scope.logStartIndex - startIndex);
}
for (var i = 0; i < logs.length; ++i) {
var entry = logs[i];
var type = entry['type'] || 'entry';
if (type == 'command' || type == 'phase' || type == 'error') {
entry['logs'] = AngularViewArray.create();
entry['index'] = $scope.logStartIndex + i;
$scope.logEntries.push(entry);
$scope.currentParentEntry = entry;
} else if ($scope.currentParentEntry) {
$scope.currentParentEntry['logs'].push(entry);
}
appendToTextLog(type, entry['message']);
}
return endIndex;
};
var getBuildStatusAndLogs = function(build, callback) {
var params = {
'repository': build.repository.namespace + '/' + build.repository.name,
'build_uuid': build.id
};
ApiService.getRepoBuildStatus(null, params, true).then(function(resp) {
if (resp.id != $scope.build.id) { callback(false); return; }
// Call the build updated handler.
$scope.buildUpdated({'build': resp});
// Save the current build.
currentBuild = resp;
// Load the updated logs for the build.
var options = {
'start': $scope.logStartIndex
};
ApiService.getRepoBuildLogsAsResource(params, true).withOptions(options).get(function(resp) {
// Process the logs we've received.
$scope.logStartIndex = processLogs(resp['logs'], resp['start'], resp['total']);
// If the build status is an error, open the last two log entries.
if (currentBuild['phase'] == 'error' && $scope.logEntries.length > 1) {
var openLogEntries = function(entry) {
if (entry.logs) {
entry.logs.setVisible(true);
}
};
openLogEntries($scope.logEntries[$scope.logEntries.length - 2]);
openLogEntries($scope.logEntries[$scope.logEntries.length - 1]);
}
// If the build phase is an error or a complete, then we mark the channel
// as closed.
callback(currentBuild['phase'] != 'error' && currentBuild['phase'] != 'complete');
}, function() {
callback(false);
});
}, function() {
callback(false);
});
};
var startWatching = function(build) {
// Create a new channel for polling the build status and logs.
var conductStatusAndLogRequest = function(callback) {
getBuildStatusAndLogs(build, callback);
};
pollChannel = AngularPollChannel.create($scope, conductStatusAndLogRequest, 5 * 1000 /* 5s */);
pollChannel.start();
};
var stopWatching = function() {
if (pollChannel) {
pollChannel.stop();
pollChannel = null;
}
};
$scope.$watch('useTimestamps', function() {
if (!$scope.logEntries) { return; }
$scope.logEntries = $scope.logEntries.slice();
});
$scope.$watch('build', function(build) {
if (build) {
startWatching(build);
} else {
stopWatching();
}
});
$scope.hasLogs = function(container) {
return container.logs.hasEntries;
};
$scope.formatDatetime = function(datetimeString) {
var dt = new Date(datetimeString);
return dt.toLocaleString();
}
$scope.processANSI = function(message, container) {
var filter = container.logs._filter = (container.logs._filter || ansi2html.create());
// Note: order is important here.
var setup = filter.getSetupHtml();
var stream = filter.addInputToStream(message);
var teardown = filter.getTeardownHtml();
return setup + stream + teardown;
};
}
};
return directiveDefinitionObject;
});

View file

@ -23,6 +23,9 @@ $.fn.clipboardCopy = function() {
ZeroClipboard.on('aftercopy', function(e) {
var container = e.target.parentNode.parentNode.parentNode;
var message = $(container).find('.clipboard-copied-message')[0];
if (!message) {
return;
}
// Resets the animation.
var elem = message;

View file

@ -11,9 +11,29 @@ angular.module('quay').directive('resourceView', function () {
restrict: 'C',
scope: {
'resource': '=resource',
'resources': '=resources',
'errorMessage': '=errorMessage'
},
controller: function($scope, $element) {
$scope.getState = function() {
if (!$scope.resources && !$scope.resource) {
return 'loading';
}
var resources = $scope.resources || [$scope.resource];
for (var i = 0; i < resources.length; ++i) {
var current = resources[i];
if (current.loading) {
return 'loading';
}
if (current.error) {
return 'error';
}
}
return 'ready';
};
}
};
return directiveDefinitionObject;

View file

@ -0,0 +1,22 @@
/**
* An element which displays a link to a commit in Git or Mercurial or another source control.
*/
angular.module('quay').directive('sourceCommitLink', function () {
var directiveDefinitionObject = {
priority: 0,
templateUrl: '/static/directives/source-commit-link.html',
replace: false,
transclude: false,
restrict: 'C',
scope: {
'commitSha': '=commitSha',
'urlTemplate': '=urlTemplate'
},
controller: function($scope, $element) {
$scope.getUrl = function(sha, template) {
return template.replace('{sha}', sha);
};
}
};
return directiveDefinitionObject;
});

View file

@ -0,0 +1,41 @@
/**
* An element which displays a link to a branch or tag in source control.
*/
angular.module('quay').directive('sourceRefLink', function () {
var directiveDefinitionObject = {
priority: 0,
templateUrl: '/static/directives/source-ref-link.html',
replace: false,
transclude: false,
restrict: 'C',
scope: {
'ref': '=ref',
'branchTemplate': '=branchTemplate',
'tagTemplate': '=tagTemplate'
},
controller: function($scope, $element) {
$scope.getKind = function(ref) {
var parts = (ref || '').split('/');
if (parts.length < 3) {
return '';
}
return parts[1];
};
$scope.getTitle = function(ref) {
var parts = (ref || '').split('/');
if (parts.length < 3) {
return '';
}
return parts[2];
};
$scope.getUrl = function(ref, template, kind) {
return template.replace('{' + kind + '}', $scope.getTitle(ref));
};
}
};
return directiveDefinitionObject;
});

View file

@ -1,5 +1,5 @@
/**
* An element which displays information about a build trigger.
* DEPRECATED: An element which displays information about a build trigger.
*/
angular.module('quay').directive('triggerDescription', function () {
var directiveDefinitionObject = {

View file

@ -0,0 +1,21 @@
/**
* An element which displays information about a build that was triggered from an outside source.
*/
angular.module('quay').directive('triggeredBuildDescription', function () {
var directiveDefinitionObject = {
priority: 0,
templateUrl: '/static/directives/triggered-build-description.html',
replace: false,
transclude: false,
restrict: 'C',
scope: {
'build': '=build'
},
controller: function($scope, $element, KeyService, TriggerService) {
$scope.getGitHubRepoURL = function(build) {
return KeyService['githubTriggerEndpoint'] + build.trigger.config.build_source + '/';
};
}
};
return directiveDefinitionObject;
});