Merge pull request #1839 from coreos-inc/better-notifications
Better notifications UI and features
This commit is contained in:
commit
349bd1e0fa
16 changed files with 644 additions and 263 deletions
|
@ -120,6 +120,9 @@ quayApp.config(['$routeProvider', '$locationProvider', 'pages', function($routeP
|
|||
// Repo Build View
|
||||
.route('/repository/:namespace/:name/build/:buildid', 'build-view')
|
||||
|
||||
// Create repository notification
|
||||
.route('/repository/:namespace/:name/create-notification', 'create-repository-notification')
|
||||
|
||||
// Repo List
|
||||
.route('/repository/', 'repo-list')
|
||||
|
||||
|
|
|
@ -1,16 +1,15 @@
|
|||
/**
|
||||
* An element which displays a dialog to register a new external notification on a repository.
|
||||
* An element which displays a form to register a new external notification on a repository.
|
||||
*/
|
||||
angular.module('quay').directive('createExternalNotificationDialog', function () {
|
||||
angular.module('quay').directive('createExternalNotification', function () {
|
||||
var directiveDefinitionObject = {
|
||||
priority: 0,
|
||||
templateUrl: '/static/directives/create-external-notification-dialog.html',
|
||||
templateUrl: '/static/directives/create-external-notification.html',
|
||||
replace: false,
|
||||
transclude: false,
|
||||
restrict: 'C',
|
||||
scope: {
|
||||
'repository': '=repository',
|
||||
'counter': '=counter',
|
||||
'notificationCreated': '¬ificationCreated',
|
||||
'defaultData': '=defaultData'
|
||||
},
|
||||
|
@ -27,7 +26,12 @@ angular.module('quay').directive('createExternalNotificationDialog', function ()
|
|||
$scope.methods = ExternalNotificationData.getSupportedMethods();
|
||||
|
||||
$scope.getPattern = function(field) {
|
||||
return new RegExp(field.regex);
|
||||
if (field._cached_regex) {
|
||||
return field._cached_regex;
|
||||
}
|
||||
|
||||
field._cached_regex = new RegExp(field.pattern);
|
||||
return field._cached_regex;
|
||||
};
|
||||
|
||||
$scope.setEvent = function(event) {
|
||||
|
@ -99,14 +103,6 @@ angular.module('quay').directive('createExternalNotificationDialog', function ()
|
|||
ApiService.createRepoNotification(data, params).then(function(resp) {
|
||||
$scope.status = '';
|
||||
$scope.notificationCreated({'notification': resp});
|
||||
|
||||
// Used by repository-events-summary.
|
||||
if (!$scope.repository._notificationCounter) {
|
||||
$scope.repository._notificationCounter = 0;
|
||||
}
|
||||
|
||||
$scope.repository._notificationCounter++;
|
||||
$('#createNotificationModal').modal('hide');
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -123,6 +119,7 @@ angular.module('quay').directive('createExternalNotificationDialog', function ()
|
|||
}
|
||||
|
||||
$scope.unauthorizedEmail = true;
|
||||
$('#authorizeEmailModal').modal({});
|
||||
};
|
||||
|
||||
$scope.sendAuthEmail = function() {
|
||||
|
@ -146,6 +143,11 @@ angular.module('quay').directive('createExternalNotificationDialog', function ()
|
|||
}, 1000);
|
||||
};
|
||||
|
||||
$scope.cancelEmailAuth = function() {
|
||||
$scope.status = '';
|
||||
$('#authorizeEmailModal').modal('hide');
|
||||
};
|
||||
|
||||
$scope.getHelpUrl = function(field, config) {
|
||||
var helpUrl = field['help_url'];
|
||||
if (!helpUrl) {
|
||||
|
@ -155,21 +157,9 @@ angular.module('quay').directive('createExternalNotificationDialog', function ()
|
|||
return StringBuilderService.buildUrl(helpUrl, config);
|
||||
};
|
||||
|
||||
$scope.$watch('counter', function(counter) {
|
||||
if (counter) {
|
||||
$scope.clearCounter++;
|
||||
$scope.status = '';
|
||||
$scope.currentEvent = null;
|
||||
$scope.currentMethod = null;
|
||||
$scope.unauthorizedEmail = false;
|
||||
|
||||
$timeout(function() {
|
||||
if ($scope.defaultData && $scope.defaultData['currentEvent']) {
|
||||
$scope.setEvent($scope.defaultData['currentEvent']);
|
||||
}
|
||||
}, 100);
|
||||
|
||||
$('#createNotificationModal').modal({});
|
||||
$scope.$watch('defaultData', function(counter) {
|
||||
if ($scope.defaultData && $scope.defaultData['currentEvent']) {
|
||||
$scope.setEvent($scope.defaultData['currentEvent']);
|
||||
}
|
||||
});
|
||||
}
|
39
static/js/directives/ui/regex-editor.js
Normal file
39
static/js/directives/ui/regex-editor.js
Normal file
|
@ -0,0 +1,39 @@
|
|||
/**
|
||||
* An element which displays an edit box for regular expressions.
|
||||
*/
|
||||
angular.module('quay').directive('regexEditor', function () {
|
||||
var directiveDefinitionObject = {
|
||||
priority: 0,
|
||||
templateUrl: '/static/directives/regex-editor.html',
|
||||
replace: false,
|
||||
transclude: true,
|
||||
restrict: 'C',
|
||||
scope: {
|
||||
'placeholder': '@placeholder',
|
||||
'optional': '=optional',
|
||||
'binding': '=binding'
|
||||
},
|
||||
controller: function($scope, $element) {
|
||||
}
|
||||
};
|
||||
return directiveDefinitionObject;
|
||||
});
|
||||
|
||||
angular.module('quay').directive('requireValidRegex', function() {
|
||||
return {
|
||||
require: 'ngModel',
|
||||
link: function(scope, element, attr, ctrl) {
|
||||
function validator(value) {
|
||||
try {
|
||||
new RegExp(value)
|
||||
ctrl.$setValidity('regex', true);
|
||||
} catch (e) {
|
||||
ctrl.$setValidity('regex', false);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
ctrl.$parsers.push(validator);
|
||||
}
|
||||
};
|
||||
});
|
|
@ -53,14 +53,6 @@ angular.module('quay').directive('repositoryEventsTable', function () {
|
|||
|
||||
loadNotifications();
|
||||
|
||||
$scope.handleNotificationCreated = function(notification) {
|
||||
$scope.notifications.push(notification);
|
||||
};
|
||||
|
||||
$scope.askCreateNotification = function() {
|
||||
$scope.showNewNotificationCounter++;
|
||||
};
|
||||
|
||||
$scope.findEnumValue = function(values, index) {
|
||||
var found = null;
|
||||
Object.keys(values).forEach(function(key) {
|
||||
|
|
33
static/js/pages/create-repository-notification.js
Normal file
33
static/js/pages/create-repository-notification.js
Normal file
|
@ -0,0 +1,33 @@
|
|||
(function() {
|
||||
/**
|
||||
* Create repository notification page.
|
||||
*/
|
||||
angular.module('quayPages').config(['pages', function(pages) {
|
||||
pages.create('create-repository-notification', 'create-repository-notification.html', CreateRepoNotificationCtrl, {
|
||||
'newLayout': true,
|
||||
'title': 'Create Repo Notification: {{ namespace }}/{{ name }}',
|
||||
'description': 'Create repository notification for repository {{ namespace }}/{{ name }}'
|
||||
})
|
||||
}]);
|
||||
|
||||
function CreateRepoNotificationCtrl($scope, $routeParams, $location, ApiService) {
|
||||
$scope.namespace = $routeParams.namespace;
|
||||
$scope.name = $routeParams.name;
|
||||
|
||||
var loadRepository = function() {
|
||||
var params = {
|
||||
'repository': $scope.namespace + '/' + $scope.name
|
||||
};
|
||||
|
||||
$scope.repositoryResource = ApiService.getRepoAsResource(params).get(function(repo) {
|
||||
$scope.repository = repo;
|
||||
});
|
||||
};
|
||||
|
||||
loadRepository();
|
||||
|
||||
$scope.notificationCreated = function() {
|
||||
$location.url('repository/' + $scope.namespace + '/' + $scope.name + '?tab=settings');
|
||||
};
|
||||
}
|
||||
})();
|
|
@ -20,22 +20,66 @@ function(Config, Features, VulnerabilityService) {
|
|||
{
|
||||
'id': 'build_queued',
|
||||
'title': 'Dockerfile Build Queued',
|
||||
'icon': 'fa-tasks'
|
||||
'icon': 'fa-tasks',
|
||||
'fields': [
|
||||
{
|
||||
'name': 'ref-regex',
|
||||
'type': 'regex',
|
||||
'title': 'matching ref(s)',
|
||||
'help_text': 'An optional regular expression for matching the git branch or tag ' +
|
||||
'git ref. If left blank, the notification will fire for all builds.',
|
||||
'optional': true,
|
||||
'placeholder': '(refs/heads/somebranch)|(refs/tags/sometag)'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
'id': 'build_start',
|
||||
'title': 'Dockerfile Build Started',
|
||||
'icon': 'fa-circle-o-notch'
|
||||
'icon': 'fa-circle-o-notch',
|
||||
'fields': [
|
||||
{
|
||||
'name': 'ref-regex',
|
||||
'type': 'regex',
|
||||
'title': 'matching ref(s)',
|
||||
'help_text': 'An optional regular expression for matching the git branch or tag ' +
|
||||
'git ref. If left blank, the notification will fire for all builds.',
|
||||
'optional': true,
|
||||
'placeholder': '(refs/heads/somebranch)|(refs/tags/sometag)'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
'id': 'build_success',
|
||||
'title': 'Dockerfile Build Successfully Completed',
|
||||
'icon': 'fa-check-circle-o'
|
||||
'icon': 'fa-check-circle-o',
|
||||
'fields': [
|
||||
{
|
||||
'name': 'ref-regex',
|
||||
'type': 'regex',
|
||||
'title': 'matching ref(s)',
|
||||
'help_text': 'An optional regular expression for matching the git branch or tag ' +
|
||||
'git ref. If left blank, the notification will fire for all builds.',
|
||||
'optional': true,
|
||||
'placeholder': '(refs/heads/somebranch)|(refs/tags/sometag)'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
'id': 'build_failure',
|
||||
'title': 'Dockerfile Build Failed',
|
||||
'icon': 'fa-times-circle-o'
|
||||
'icon': 'fa-times-circle-o',
|
||||
'fields': [
|
||||
{
|
||||
'name': 'ref-regex',
|
||||
'type': 'regex',
|
||||
'title': 'matching ref(s)',
|
||||
'help_text': 'An optional regular expression for matching the git branch or tag ' +
|
||||
'git ref. If left blank, the notification will fire for all builds.',
|
||||
'optional': true,
|
||||
'placeholder': '(refs/heads/somebranch)|(refs/tags/sometag)'
|
||||
}
|
||||
]
|
||||
}];
|
||||
|
||||
for (var i = 0; i < buildEvents.length; ++i) {
|
||||
|
@ -52,8 +96,12 @@ function(Config, Features, VulnerabilityService) {
|
|||
{
|
||||
'name': 'level',
|
||||
'type': 'enum',
|
||||
'title': 'Minimum Priority Level',
|
||||
'title': 'minimum severity level',
|
||||
'values': VulnerabilityService.LEVELS,
|
||||
'help_text': 'A vulnerability must have a severity of the chosen level (or higher) ' +
|
||||
'for this notification to fire. Defcon 1 is a special severity level ' +
|
||||
'manually tagged by the ' + Config.REGISTRY_TITLE_SHORT + ' team for ' +
|
||||
'above-critical issues',
|
||||
}
|
||||
]
|
||||
});
|
||||
|
@ -68,7 +116,8 @@ function(Config, Features, VulnerabilityService) {
|
|||
{
|
||||
'name': 'target',
|
||||
'type': 'entity',
|
||||
'title': 'Recipient'
|
||||
'title': 'Recipient',
|
||||
'help_text': 'The ' + Config.REGISTRY_TITLE_SHORT + ' user to notify'
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -117,11 +166,11 @@ function(Config, Features, VulnerabilityService) {
|
|||
'fields': [
|
||||
{
|
||||
'name': 'room_id',
|
||||
'type': 'regex',
|
||||
'type': 'pattern',
|
||||
'title': 'Room ID #',
|
||||
'regex': '^[0-9]+$',
|
||||
'pattern': '^[0-9]+$',
|
||||
'help_url': 'https://hipchat.com/admin/rooms',
|
||||
'regex_fail_message': 'We require the HipChat room <b>number</b>, not name.'
|
||||
'pattern_fail_message': 'We require the HipChat room <b>number</b>, not name.'
|
||||
},
|
||||
{
|
||||
'name': 'notification_token',
|
||||
|
@ -138,9 +187,9 @@ function(Config, Features, VulnerabilityService) {
|
|||
'fields': [
|
||||
{
|
||||
'name': 'url',
|
||||
'type': 'regex',
|
||||
'type': 'pattern',
|
||||
'title': 'Webhook URL',
|
||||
'regex': '^https://hooks\\.slack\\.com/services/[A-Z0-9]+/[A-Z0-9]+/[a-zA-Z0-9]+$',
|
||||
'pattern': '^https://hooks\\.slack\\.com/services/[A-Z0-9]+/[A-Z0-9]+/[a-zA-Z0-9]+$',
|
||||
'help_url': 'https://slack.com/services/new/incoming-webhook',
|
||||
'placeholder': 'https://hooks.slack.com/service/{some}/{token}/{here}'
|
||||
}
|
||||
|
|
Reference in a new issue