/** * An element which displays the builds panel for a repository view. */ angular.module('quay').directive('repoPanelBuilds', function () { var directiveDefinitionObject = { priority: 0, templateUrl: '/static/directives/repo-view/repo-panel-builds.html', replace: false, transclude: false, restrict: 'C', scope: { 'repository': '=repository', 'builds': '=builds' }, controller: function($scope, $element, $filter, $routeParams, ApiService, TriggerService, UserService) { var orderBy = $filter('orderBy'); $scope.TriggerService = TriggerService; UserService.updateUserIn($scope); $scope.options = { 'filter': 'recent', 'reverse': false, 'predicate': 'started_datetime' }; $scope.currentFilter = null; $scope.currentStartTrigger = null; $scope.currentSetupTrigger = null; $scope.showBuildDialogCounter = 0; $scope.showTriggerStartDialogCounter = 0; $scope.showTriggerSetupCounter = 0; var updateBuilds = function() { if (!$scope.allBuilds) { return; } var unordered = $scope.allBuilds.map(function(build_info) { var commit_sha = null; var job_config = build_info.job_config || {}; if (job_config.trigger_metadata) { commit_sha = job_config.trigger_metadata.commit_sha; } return $.extend(build_info, { 'started_datetime': (new Date(build_info.started)).valueOf() * (-1), 'building_tags': job_config.docker_tags || [], 'commit_sha': commit_sha }); }); $scope.fullBuilds = orderBy(unordered, $scope.options.predicate, $scope.options.reverse); }; var loadBuilds = function() { if (!$scope.builds || !$scope.repository || !$scope.options.filter) { return; } // Note: We only refresh if the filter has changed. var filter = $scope.options.filter; if ($scope.buildsResource && filter == $scope.currentFilter) { return; } var since = null; var limit = 10; if ($scope.options.filter == '48hour') { since = Math.floor(moment().subtract(2, 'days').valueOf() / 1000); limit = 100; } else if ($scope.options.filter == '30day') { since = Math.floor(moment().subtract(30, 'days').valueOf() / 1000); limit = 100; } else { since = null; limit = 10; } var params = { 'repository': $scope.repository.namespace + '/' + $scope.repository.name, 'limit': limit, 'since': since }; $scope.buildsResource = ApiService.getRepoBuildsAsResource(params).get(function(resp) { $scope.allBuilds = resp.builds; $scope.currentFilter = filter; updateBuilds(); }); }; var buildsChanged = function() { if (!$scope.allBuilds) { loadBuilds(); return; } if (!$scope.builds || !$scope.repository) { return; } // Replace any build records with updated records from the server. $scope.builds.map(function(build) { for (var i = 0; i < $scope.allBuilds.length; ++i) { var current = $scope.allBuilds[i]; if (current.id == build.id && current.phase != build.phase) { $scope.allBuilds[i] = build; break } } }); updateBuilds(); }; var loadBuildTriggers = function() { if (!$scope.repository || !$scope.repository.can_admin) { return; } var params = { 'repository': $scope.repository.namespace + '/' + $scope.repository.name }; $scope.triggersResource = ApiService.listBuildTriggersAsResource(params).get(function(resp) { $scope.triggers = resp.triggers; // Check to see if we need to setup any trigger. var newTriggerId = $routeParams.newtrigger; if (newTriggerId) { $scope.triggers.map(function(trigger) { if (trigger['id'] == newTriggerId && !trigger['is_active']) { $scope.setupTrigger(trigger); } }); } }); }; $scope.$watch('repository', loadBuildTriggers); $scope.$watch('repository', loadBuilds); $scope.$watch('builds', buildsChanged); $scope.$watch('options.filter', loadBuilds); $scope.$watch('options.predicate', updateBuilds); $scope.$watch('options.reverse', updateBuilds); $scope.tablePredicateClass = function(name, predicate, reverse) { if (name != predicate) { return ''; } return 'current ' + (reverse ? 'reversed' : ''); }; $scope.orderBy = function(predicate) { if (predicate == $scope.options.predicate) { $scope.options.reverse = !$scope.options.reverse; return; } $scope.options.reverse = false; $scope.options.predicate = predicate; }; $scope.askDeleteTrigger = function(trigger) { $scope.deleteTriggerInfo = { 'trigger': trigger }; }; $scope.askRunTrigger = function(trigger) { if ($scope.user.username != trigger.connected_user) { bootbox.alert('For security reasons, only user "' + trigger.connected_user + '" can manually invoke this trigger'); return; } $scope.currentStartTrigger = trigger; $scope.showTriggerStartDialogCounter++; }; $scope.cancelSetupTrigger = function(trigger) { if ($scope.currentSetupTrigger != trigger) { return; } $scope.currentSetupTrigger = null; $scope.deleteTrigger(trigger); }; $scope.setupTrigger = function(trigger) { $scope.currentSetupTrigger = trigger; $scope.showTriggerSetupCounter++; }; $scope.startTrigger = function(trigger, opt_custom) { var parameters = TriggerService.getRunParameters(trigger.service); if (parameters.length && !opt_custom) { $scope.currentStartTrigger = trigger; $scope.showTriggerStartDialogCounter++; return; } var params = { 'repository': $scope.repository.namespace + '/' + $scope.repository.name, 'trigger_uuid': trigger.id }; ApiService.manuallyStartBuildTrigger(opt_custom || {}, params).then(function(resp) { $scope.allBuilds.push(resp); updateBuilds(); }, ApiService.errorDisplay('Could not start build')); }; $scope.deleteTrigger = function(trigger, opt_callback) { if (!trigger) { return; } var params = { 'repository': $scope.repository.namespace + '/' + $scope.repository.name, 'trigger_uuid': trigger.id }; var errorHandler = ApiService.errorDisplay('Could not delete build trigger', function() { opt_callback && opt_callback(false); }); ApiService.deleteBuildTrigger(null, params).then(function(resp) { $scope.triggers.splice($scope.triggers.indexOf(trigger), 1); opt_callback && opt_callback(true); }, errorHandler); }; $scope.showNewBuildDialog = function() { $scope.showBuildDialogCounter++; }; $scope.handleBuildStarted = function(build) { $scope.allBuilds.push(build); updateBuilds(); }; } }; return directiveDefinitionObject; });