Redo the UI for the trigger setup dialog and add the ability for github triggers to be filtered using a regex on their branch name.
This commit is contained in:
		
							parent
							
								
									37aa70c28e
								
							
						
					
					
						commit
						c3171a2690
					
				
					 10 changed files with 597 additions and 226 deletions
				
			
		
							
								
								
									
										360
									
								
								static/js/app.js
									
										
									
									
									
								
							
							
						
						
									
										360
									
								
								static/js/app.js
									
										
									
									
									
								
							|  | @ -2988,6 +2988,28 @@ quayApp.directive('dockerAuthDialog', function (Config) { | |||
| }); | ||||
| 
 | ||||
| 
 | ||||
| quayApp.filter('regex', function() { | ||||
|   return function(input, regex) { | ||||
|     if (!regex) { return []; } | ||||
| 
 | ||||
|     try { | ||||
|       var patt = new RegExp(regex); | ||||
|     } catch (ex) { | ||||
|       return []; | ||||
|     } | ||||
| 
 | ||||
|     var out = []; | ||||
|     for (var i = 0; i < input.length; ++i){ | ||||
|       var m = input[i].match(patt); | ||||
|       if (m && m[0].length == input[i].length) { | ||||
|         out.push(input[i]); | ||||
|       } | ||||
|     }       | ||||
|     return out; | ||||
|   }; | ||||
| }); | ||||
| 
 | ||||
| 
 | ||||
| quayApp.filter('reverse', function() { | ||||
|   return function(items) { | ||||
|     return items.slice().reverse(); | ||||
|  | @ -4744,6 +4766,118 @@ quayApp.directive('triggerDescription', function () { | |||
| }); | ||||
| 
 | ||||
| 
 | ||||
| quayApp.directive('stepView', function ($compile) { | ||||
|   var directiveDefinitionObject = { | ||||
|     priority: 0, | ||||
|     templateUrl: '/static/directives/step-view.html', | ||||
|     replace: true, | ||||
|     transclude: true, | ||||
|     restrict: 'C', | ||||
|     scope: { | ||||
|       'nextStepCounter': '=nextStepCounter', | ||||
|       'currentStepValid': '=currentStepValid', | ||||
| 
 | ||||
|       'stepsCompleted': '&stepsCompleted' | ||||
|     }, | ||||
|     controller: function($scope, $element, $rootScope) { | ||||
|       this.currentStepIndex = -1; | ||||
|       this.steps = []; | ||||
|       this.watcher = null; | ||||
| 
 | ||||
|       this.getCurrentStep = function() { | ||||
|         return this.steps[this.currentStepIndex]; | ||||
|       }; | ||||
| 
 | ||||
|       this.reset = function() { | ||||
|         this.currentStepIndex = -1; | ||||
|         for (var i = 0; i < this.steps.length; ++i) { | ||||
|           this.steps[i].element.hide(); | ||||
|         } | ||||
| 
 | ||||
|         $scope.currentStepValid = false; | ||||
|       }; | ||||
| 
 | ||||
|       this.next = function() { | ||||
|         if (this.currentStepIndex >= 0) { | ||||
|           if (!this.getCurrentStep().scope.completeCondition) { | ||||
|             return; | ||||
|           } | ||||
| 
 | ||||
|           this.getCurrentStep().element.hide(); | ||||
| 
 | ||||
|           if (this.unwatch) { | ||||
|             this.unwatch(); | ||||
|             this.unwatch = null; | ||||
|           } | ||||
|         } | ||||
| 
 | ||||
|         this.currentStepIndex++; | ||||
| 
 | ||||
|         if (this.currentStepIndex < this.steps.length) { | ||||
|           var currentStep = this.getCurrentStep(); | ||||
|           currentStep.element.show(); | ||||
|           currentStep.scope.load() | ||||
| 
 | ||||
|           this.unwatch = currentStep.scope.$watch('completeCondition', function(cc) { | ||||
|             $scope.currentStepValid = !!cc; | ||||
|           }); | ||||
|         } else { | ||||
|           $scope.stepsCompleted(); | ||||
|         } | ||||
|       }; | ||||
| 
 | ||||
|       this.register = function(scope, element) { | ||||
|         element.hide(); | ||||
| 
 | ||||
|         this.steps.push({ | ||||
|           'scope': scope, | ||||
|           'element': element | ||||
|         }); | ||||
|       }; | ||||
| 
 | ||||
|       var that = this; | ||||
|       $scope.$watch('nextStepCounter', function(nsc) { | ||||
|         if (nsc >= 0) { | ||||
|           that.next(); | ||||
|         } else { | ||||
|           that.reset(); | ||||
|         } | ||||
|       }); | ||||
|     } | ||||
|   }; | ||||
|   return directiveDefinitionObject; | ||||
| }); | ||||
| 
 | ||||
| 
 | ||||
| quayApp.directive('stepViewStep', function () { | ||||
|   var directiveDefinitionObject = { | ||||
|     priority: 1, | ||||
|     require: '^stepView', | ||||
|     templateUrl: '/static/directives/step-view-step.html', | ||||
|     replace: false, | ||||
|     transclude: true, | ||||
|     restrict: 'C', | ||||
|     scope: { | ||||
|       'completeCondition': '=completeCondition', | ||||
|       'loadCallback': '&loadCallback', | ||||
|       'loadMessage': '@loadMessage' | ||||
|     }, | ||||
|     link: function(scope, element, attrs, controller) { | ||||
|       controller.register(scope, element); | ||||
|     }, | ||||
|     controller: function($scope, $element) { | ||||
|       $scope.load = function() { | ||||
|         $scope.loading = true; | ||||
|         $scope.loadCallback({'callback': function() { | ||||
|           $scope.loading = false; | ||||
|         }}); | ||||
|       }; | ||||
|     } | ||||
|   }; | ||||
|   return directiveDefinitionObject; | ||||
| }); | ||||
| 
 | ||||
| 
 | ||||
| quayApp.directive('dropdownSelect', function ($compile) { | ||||
|   var directiveDefinitionObject = { | ||||
|     priority: 0, | ||||
|  | @ -4986,25 +5120,28 @@ quayApp.directive('setupTriggerDialog', function () { | |||
|     controller: function($scope, $element, ApiService, UserService) { | ||||
|       var modalSetup = false; | ||||
| 
 | ||||
|       $scope.state = {}; | ||||
|       $scope.nextStepCounter = -1; | ||||
|       $scope.currentView = 'config'; | ||||
| 
 | ||||
|       $scope.show = function() { | ||||
|         if (!$scope.trigger || !$scope.repository) { return; } | ||||
| 
 | ||||
|         $scope.activating = false; | ||||
|         $scope.pullEntity = null; | ||||
|         $scope.publicPull = true; | ||||
|         $scope.showPullRequirements = false; | ||||
| 
 | ||||
|         $scope.currentView = 'config'; | ||||
|         $('#setupTriggerModal').modal({}); | ||||
| 
 | ||||
|         if (!modalSetup) { | ||||
|           $('#setupTriggerModal').on('hidden.bs.modal', function () { | ||||
|             if (!$scope.trigger || $scope.trigger['is_active']) { return; } | ||||
| 
 | ||||
|             $scope.nextStepCounter = -1; | ||||
|             $scope.$apply(function() { | ||||
|               $scope.cancelSetupTrigger(); | ||||
|             }); | ||||
|           }); | ||||
| 
 | ||||
|           modalSetup = true; | ||||
|           $scope.nextStepCounter = 0; | ||||
|         } | ||||
|       }; | ||||
| 
 | ||||
|  | @ -5017,27 +5154,20 @@ quayApp.directive('setupTriggerDialog', function () { | |||
|       }; | ||||
| 
 | ||||
|       $scope.hide = function() { | ||||
|         $scope.activating = false; | ||||
|         $('#setupTriggerModal').modal('hide'); | ||||
|       }; | ||||
| 
 | ||||
|       $scope.setPublicPull = function(value) { | ||||
|         $scope.publicPull = value; | ||||
|       }; | ||||
| 
 | ||||
|       $scope.checkAnalyze = function(isValid) { | ||||
|         $scope.currentView = 'analyzing'; | ||||
|         $scope.pullInfo = { | ||||
|           'is_public': true | ||||
|         }; | ||||
| 
 | ||||
|         if (!isValid) { | ||||
|           $scope.publicPull = true; | ||||
|           $scope.pullEntity = null;           | ||||
|           $scope.showPullRequirements = false; | ||||
|           $scope.checkingPullRequirements = false; | ||||
|           $scope.currentView = 'analyzed'; | ||||
|           return; | ||||
|         } | ||||
|          | ||||
|         $scope.checkingPullRequirements = true; | ||||
|         $scope.showPullRequirements = true; | ||||
|         $scope.pullRequirements = null; | ||||
| 
 | ||||
|         var params = { | ||||
|           'repository': $scope.repository.namespace + '/' + $scope.repository.name, | ||||
|           'trigger_uuid': $scope.trigger.id | ||||
|  | @ -5048,26 +5178,20 @@ quayApp.directive('setupTriggerDialog', function () { | |||
|         }; | ||||
| 
 | ||||
|         ApiService.analyzeBuildTrigger(data, params).then(function(resp) { | ||||
|           $scope.pullRequirements = resp; | ||||
| 
 | ||||
|           if (resp['status'] == 'publicbase') { | ||||
|             $scope.publicPull = true; | ||||
|             $scope.pullEntity = null; | ||||
|           } else if (resp['namespace']) { | ||||
|             $scope.publicPull = false; | ||||
|           $scope.currentView = 'analyzed'; | ||||
| 
 | ||||
|           if (resp['status'] == 'analyzed') { | ||||
|             if (resp['robots'] && resp['robots'].length > 0) { | ||||
|               $scope.pullEntity = resp['robots'][0]; | ||||
|             } else { | ||||
|               $scope.pullEntity = null; | ||||
|               $scope.pullInfo['pull_entity'] = resp['robots'][0]; | ||||
|              } else { | ||||
|               $scope.pullInfo['pull_entity'] = null; | ||||
|             } | ||||
| 
 | ||||
|             $scope.pullInfo['is_public'] = false; | ||||
|           } | ||||
| 
 | ||||
|           $scope.checkingPullRequirements = false; | ||||
|         }, function(resp) { | ||||
|           $scope.pullRequirements = resp;           | ||||
|           $scope.checkingPullRequirements = false; | ||||
|         }); | ||||
|           $scope.pullInfo['analysis'] = resp; | ||||
|         }, ApiService.errorDisplay('Cannot load Dockerfile information')); | ||||
|       }; | ||||
| 
 | ||||
|       $scope.activate = function() { | ||||
|  | @ -5084,7 +5208,7 @@ quayApp.directive('setupTriggerDialog', function () { | |||
|           data['pull_robot'] = $scope.pullEntity['name']; | ||||
|         } | ||||
| 
 | ||||
|         $scope.activating = true; | ||||
|         $scope.currentView = 'activating'; | ||||
| 
 | ||||
|         var errorHandler = ApiService.errorDisplay('Cannot activate build trigger', function(resp) { | ||||
|           $scope.hide(); | ||||
|  | @ -5125,17 +5249,99 @@ quayApp.directive('triggerSetupGithub', function () { | |||
|     scope: { | ||||
|       'repository': '=repository', | ||||
|       'trigger': '=trigger', | ||||
| 
 | ||||
|       'nextStepCounter': '=nextStepCounter', | ||||
|       'currentStepValid': '=currentStepValid', | ||||
| 
 | ||||
|       'analyze': '&analyze' | ||||
|     }, | ||||
|     controller: function($scope, $element, ApiService) { | ||||
|       $scope.analyzeCounter = 0; | ||||
|       $scope.setupReady = false; | ||||
|       $scope.loading = true; | ||||
| 
 | ||||
|       $scope.branchNames = null; | ||||
| 
 | ||||
|       $scope.state = { | ||||
|         'branchFilter': '', | ||||
|         'hasBranchFilter': false, | ||||
|         'isInvalidLocation': true, | ||||
|         'currentLocation': null | ||||
|       }; | ||||
| 
 | ||||
|       $scope.isMatchingBranch = function(branchName, filter) { | ||||
|         try { | ||||
|           var patt = new RegExp(filter); | ||||
|         } catch (ex) { | ||||
|           return false; | ||||
|         } | ||||
| 
 | ||||
|         var m = branchName.match(patt); | ||||
|         return m && m[0].length == branchName.length; | ||||
|       } | ||||
| 
 | ||||
|       $scope.stepsCompleted = function() { | ||||
|         $scope.analyze({'isValid': !$scope.state.isInvalidLocation}); | ||||
|       }; | ||||
| 
 | ||||
|       $scope.loadRepositories = function(callback) { | ||||
|         var params = { | ||||
|           'repository': $scope.repository.namespace + '/' + $scope.repository.name, | ||||
|           'trigger_uuid': $scope.trigger.id | ||||
|         }; | ||||
| 
 | ||||
|         ApiService.listTriggerBuildSources(null, params).then(function(resp) { | ||||
|           $scope.orgs = resp['sources']; | ||||
|           setupTypeahead(); | ||||
|           callback(); | ||||
|         }, ApiService.errorDisplay('Cannot load repositories')); | ||||
|       }; | ||||
| 
 | ||||
|       $scope.loadBranches = function(callback) { | ||||
|         var params = { | ||||
|           'repository': $scope.repository.namespace + '/' + $scope.repository.name, | ||||
|           'trigger_uuid': $scope.trigger['id'], | ||||
|           'field_name': 'branch_name' | ||||
|         }; | ||||
| 
 | ||||
|         ApiService.listTriggerFieldValues($scope.trigger['config'], params).then(function(resp) { | ||||
|           $scope.branchNames = resp['values']; | ||||
|           callback(); | ||||
|         }, ApiService.errorDisplay('Cannot load branch names')); | ||||
|       }; | ||||
| 
 | ||||
|       $scope.loadLocations = function(callback) { | ||||
|         $scope.locations = null; | ||||
| 
 | ||||
|         var params = { | ||||
|           'repository': $scope.repository.namespace + '/' + $scope.repository.name, | ||||
|           'trigger_uuid': $scope.trigger.id | ||||
|         }; | ||||
| 
 | ||||
|         ApiService.listBuildTriggerSubdirs($scope.trigger['config'], params).then(function(resp) { | ||||
|           if (resp['status'] == 'error') { | ||||
|             callback(resp['message'] || 'Could not load Dockerfile locations'); | ||||
|             return; | ||||
|           } | ||||
| 
 | ||||
|           $scope.locations = resp['subdir'] || []; | ||||
| 
 | ||||
|           // Select a default location (if any).
 | ||||
|           if ($scope.locations.length > 0) { | ||||
|             $scope.setLocation($scope.locations[0]); | ||||
|           } else { | ||||
|             $scope.state.currentLocation = null; | ||||
|             $scope.state.isInvalidLocation = resp['subdir'].indexOf('') < 0; | ||||
|             $scope.trigger.$ready = true; | ||||
|           } | ||||
| 
 | ||||
|           callback(); | ||||
|         }, ApiService.errorDisplay('Cannot load locations'));         | ||||
|       } | ||||
|             | ||||
|       $scope.handleLocationInput = function(location) { | ||||
|         $scope.state.isInvalidLocation = $scope.locations.indexOf(location) < 0; | ||||
|         $scope.trigger['config']['subdir'] = location || ''; | ||||
|         $scope.isInvalidLocation = $scope.locations.indexOf(location) < 0; | ||||
|         $scope.analyze({'isValid': !$scope.isInvalidLocation}); | ||||
|         $scope.trigger.$ready = true; | ||||
|       }; | ||||
| 
 | ||||
|       $scope.handleLocationSelected = function(datum) { | ||||
|  | @ -5143,10 +5349,10 @@ quayApp.directive('triggerSetupGithub', function () { | |||
|       }; | ||||
| 
 | ||||
|       $scope.setLocation = function(location) { | ||||
|         $scope.currentLocation = location; | ||||
|         $scope.state.currentLocation = location; | ||||
|         $scope.state.isInvalidLocation = false; | ||||
|         $scope.trigger['config']['subdir'] = location || ''; | ||||
|         $scope.isInvalidLocation = false; | ||||
|         $scope.analyze({'isValid': true}); | ||||
|         $scope.trigger.$ready = true; | ||||
|       }; | ||||
|   | ||||
|       $scope.selectRepo = function(repo, org) { | ||||
|  | @ -5160,10 +5366,7 @@ quayApp.directive('triggerSetupGithub', function () { | |||
|       }; | ||||
| 
 | ||||
|       $scope.selectRepoInternal = function(currentRepo) { | ||||
|         if (!currentRepo) { | ||||
|           $scope.trigger.$ready = false; | ||||
|           return; | ||||
|         } | ||||
|         $scope.trigger.$ready = false; | ||||
| 
 | ||||
|         var params = { | ||||
|           'repository': $scope.repository.namespace + '/' + $scope.repository.name, | ||||
|  | @ -5175,39 +5378,6 @@ quayApp.directive('triggerSetupGithub', function () { | |||
|           'build_source': repo, | ||||
|           'subdir': '' | ||||
|         }; | ||||
| 
 | ||||
|         // Lookup the possible Dockerfile locations.
 | ||||
|         $scope.locations = null; | ||||
|         if (repo) { | ||||
|           ApiService.listBuildTriggerSubdirs($scope.trigger['config'], params).then(function(resp) { | ||||
|             if (resp['status'] == 'error') { | ||||
|               $scope.locationError = resp['message'] || 'Could not load Dockerfile locations'; | ||||
|               $scope.locations = null; | ||||
|               $scope.trigger.$ready = false; | ||||
|               $scope.isInvalidLocation = false; | ||||
|               $scope.analyze({'isValid': false}); | ||||
|               return; | ||||
|             } | ||||
| 
 | ||||
|             $scope.locationError = null; | ||||
|             $scope.locations = resp['subdir'] || []; | ||||
|             $scope.trigger.$ready = true; | ||||
| 
 | ||||
|             if ($scope.locations.length > 0) { | ||||
|               $scope.setLocation($scope.locations[0]); | ||||
|             } else { | ||||
|               $scope.currentLocation = null; | ||||
|               $scope.isInvalidLocation = resp['subdir'].indexOf('') < 0; | ||||
|               $scope.analyze({'isValid': !$scope.isInvalidLocation}); | ||||
|             } | ||||
|           }, function(resp) { | ||||
|             $scope.locationError = resp['message'] || 'Could not load Dockerfile locations'; | ||||
|             $scope.locations = null; | ||||
|             $scope.trigger.$ready = false; | ||||
|             $scope.isInvalidLocation = false; | ||||
|             $scope.analyze({'isValid': false}); | ||||
|           }); | ||||
|         } | ||||
|       }; | ||||
| 
 | ||||
|       var setupTypeahead = function() {         | ||||
|  | @ -5237,30 +5407,20 @@ quayApp.directive('triggerSetupGithub', function () { | |||
|         $scope.repoLookahead = repos; | ||||
|       }; | ||||
| 
 | ||||
|       var loadSources = function() { | ||||
|         var params = { | ||||
|           'repository': $scope.repository.namespace + '/' + $scope.repository.name, | ||||
|           'trigger_uuid': $scope.trigger.id | ||||
|         }; | ||||
| 
 | ||||
|         ApiService.listTriggerBuildSources(null, params).then(function(resp) { | ||||
|           $scope.orgs = resp['sources']; | ||||
|           setupTypeahead(); | ||||
|           $scope.loading = false; | ||||
|         }); | ||||
|       }; | ||||
| 
 | ||||
|       var check = function() { | ||||
|         if ($scope.repository && $scope.trigger) { | ||||
|           loadSources(); | ||||
|         } | ||||
|       }; | ||||
| 
 | ||||
|       $scope.$watch('repository', check); | ||||
|       $scope.$watch('trigger', check); | ||||
| 
 | ||||
|       $scope.$watch('currentRepo', function(repo) { | ||||
|         $scope.selectRepoInternal(repo); | ||||
|         if (repo) { | ||||
|           $scope.selectRepoInternal(repo); | ||||
|         } | ||||
|       }); | ||||
| 
 | ||||
|       $scope.$watch('state.branchFilter', function(bf) { | ||||
|         if (!$scope.trigger) { return; } | ||||
| 
 | ||||
|         if ($scope.state.hasBranchFilter) { | ||||
|           $scope.trigger['config']['branch_regex'] = bf; | ||||
|         } else { | ||||
|           delete $scope.trigger['config']['branch_regex']; | ||||
|         } | ||||
|       }); | ||||
|     } | ||||
|   }; | ||||
|  |  | |||
		Reference in a new issue