Merge remote-tracking branch 'origin/master' into comewithmeifyouwanttowork

Conflicts:
	data/model/legacy.py
This commit is contained in:
Jake Moshenko 2014-09-15 17:52:17 -04:00
commit 75d2ef377e
35 changed files with 743 additions and 93 deletions

View file

@ -223,6 +223,78 @@ quayApp = angular.module('quay', quayDependencies, function($provide, cfpLoading
return service;
}]);
/**
* Specialized class for conducting an HTTP poll, while properly preventing multiple calls.
*/
$provide.factory('AngularPollChannel', ['ApiService', '$timeout', function(ApiService, $timeout) {
var _PollChannel = function(scope, requester, opt_sleeptime) {
this.scope_ = scope;
this.requester_ = requester;
this.sleeptime_ = opt_sleeptime || (60 * 1000 /* 60s */);
this.timer_ = null;
this.working = false;
this.polling = false;
var that = this;
scope.$on('$destroy', function() {
that.stop();
});
};
_PollChannel.prototype.stop = function() {
if (this.timer_) {
$timeout.cancel(this.timer_);
this.timer_ = null;
this.polling_ = false;
}
this.working = false;
};
_PollChannel.prototype.start = function() {
// Make sure we invoke call outside the normal digest cycle, since
// we'll call $scope.$apply ourselves.
var that = this;
setTimeout(function() { that.call_(); }, 0);
};
_PollChannel.prototype.call_ = function() {
if (this.working) { return; }
var that = this;
this.working = true;
this.scope_.$apply(function() {
that.requester_(function(status) {
if (status) {
that.working = false;
that.setupTimer_();
} else {
that.stop();
}
});
});
};
_PollChannel.prototype.setupTimer_ = function() {
if (this.timer_) { return; }
var that = this;
this.polling = true;
this.timer_ = $timeout(function() {
that.timer_ = null;
that.call_();
}, this.sleeptime_)
};
var service = {
'create': function(scope, requester, opt_sleeptime) {
return new _PollChannel(scope, requester, opt_sleeptime);
}
};
return service;
}]);
$provide.factory('DataFileService', [function() {
var dataFileService = {};
@ -489,7 +561,7 @@ quayApp = angular.module('quay', quayDependencies, function($provide, cfpLoading
// If an error occurred, report it and done.
if (ping < 0) {
cached['pings'] = [-1];
invokeCallback($scope, pings, callback);
invokeCallback($scope, [-1], callback);
return;
}
@ -1502,7 +1574,12 @@ quayApp = angular.module('quay', quayDependencies, function($provide, cfpLoading
};
notificationService.getPage = function(notification) {
var page = notificationKinds[notification['kind']]['page'];
var kindInfo = notificationKinds[notification['kind']];
if (!kindInfo) {
return null;
}
var page = kindInfo['page'];
if (typeof page != 'string') {
page = page(notification['metadata']);
}

View file

@ -982,14 +982,9 @@ function BuildPackageCtrl($scope, Restangular, ApiService, DataFileService, $rou
}
function RepoBuildCtrl($scope, Restangular, ApiService, $routeParams, $rootScope, $location, $interval, $sanitize,
ansi2html, AngularViewArray) {
ansi2html, AngularViewArray, AngularPollChannel) {
var namespace = $routeParams.namespace;
var name = $routeParams.name;
var pollTimerHandle = null;
$scope.$on('$destroy', function() {
stopPollTimer();
});
// Watch for changes to the current parameter.
$scope.$on('$routeUpdate', function(){
@ -999,8 +994,7 @@ function RepoBuildCtrl($scope, Restangular, ApiService, $routeParams, $rootScope
});
$scope.builds = null;
$scope.polling = false;
$scope.pollChannel = null;
$scope.buildDialogShowCounter = 0;
$scope.showNewBuildDialog = function() {
@ -1085,8 +1079,6 @@ function RepoBuildCtrl($scope, Restangular, ApiService, $routeParams, $rootScope
$scope.setCurrentBuildInternal = function(index, build, opt_updateURL) {
if (build == $scope.currentBuild) { return; }
stopPollTimer();
$scope.logEntries = null;
$scope.logStartIndex = null;
$scope.currentParentEntry = null;
@ -1107,47 +1099,35 @@ function RepoBuildCtrl($scope, Restangular, ApiService, $routeParams, $rootScope
$scope.adjustLogHeight();
}, 1);
// Load the first set of logs.
getBuildStatusAndLogs();
// If the build is currently processing, start the build timer.
checkPollTimer();
};
var checkPollTimer = function() {
var build = $scope.currentBuild;
if (!build) {
stopPollTimer();
return;
// Stop any existing polling.
if ($scope.pollChannel) {
$scope.pollChannel.stop();
}
// Create a new channel for polling the build status and logs.
var conductStatusAndLogRequest = function(callback) {
getBuildStatusAndLogs(build, callback);
};
if (build['phase'] != 'complete' && build['phase'] != 'error') {
startPollTimer();
return true;
} else {
stopPollTimer();
return false;
}
$scope.pollChannel = AngularPollChannel.create($scope, conductStatusAndLogRequest, 5 * 1000 /* 5s */);
$scope.pollChannel.start();
};
var stopPollTimer = function() {
$interval.cancel(pollTimerHandle);
};
var startPollTimer = function() {
stopPollTimer();
pollTimerHandle = $interval(getBuildStatusAndLogs, 2000);
};
var processLogs = function(logs, startIndex) {
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'] = startIndex + i;
entry['index'] = $scope.logStartIndex + i;
$scope.logEntries.push(entry);
$scope.currentParentEntry = entry;
@ -1155,18 +1135,19 @@ function RepoBuildCtrl($scope, Restangular, ApiService, $routeParams, $rootScope
$scope.currentParentEntry['logs'].push(entry);
}
}
return endIndex;
};
var getBuildStatusAndLogs = function() {
if (!$scope.currentBuild || $scope.polling) { return; }
$scope.polling = true;
var getBuildStatusAndLogs = function(build, callback) {
var params = {
'repository': namespace + '/' + name,
'build_uuid': $scope.currentBuild.id
'build_uuid': build.id
};
ApiService.getRepoBuildStatus(null, params, true).then(function(resp) {
if (build != $scope.currentBuild) { callback(false); return; }
// Note: We use extend here rather than replacing as Angular is depending on the
// root build object to remain the same object.
var matchingBuilds = $.grep($scope.builds, function(elem) {
@ -1181,22 +1162,16 @@ function RepoBuildCtrl($scope, Restangular, ApiService, $routeParams, $rootScope
$scope.builds.push(currentBuild);
}
checkPollTimer();
// Load the updated logs for the build.
var options = {
'start': $scope.logStartIndex
};
ApiService.getRepoBuildLogsAsResource(params, true).withOptions(options).get(function(resp) {
if ($scope.logStartIndex != null && resp['start'] != $scope.logStartIndex) {
$scope.polling = false;
return;
}
ApiService.getRepoBuildLogsAsResource(params, true).withOptions(options).get(function(resp) {
if (build != $scope.currentBuild) { callback(false); return; }
processLogs(resp['logs'], resp['start']);
$scope.logStartIndex = resp['total'];
$scope.polling = false;
// 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) {
@ -1209,9 +1184,15 @@ function RepoBuildCtrl($scope, Restangular, ApiService, $routeParams, $rootScope
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() {
$scope.polling = false;
callback(false);
});
}, function() {
callback(false);
});
};
@ -1804,6 +1785,18 @@ function UserAdminCtrl($scope, $timeout, $location, ApiService, PlanService, Use
UIService.showFormError('#changePasswordForm', result);
});
};
$scope.detachExternalLogin = function(kind) {
var params = {
'servicename': kind
};
ApiService.detachExternalLogin(null, params).then(function() {
$scope.hasGithubLogin = false;
$scope.hasGoogleLogin = false;
UserService.load();
}, ApiService.errorDisplay('Count not detach service'));
};
}
function ImageViewCtrl($scope, $routeParams, $rootScope, $timeout, ApiService, ImageMetadataService) {