Merge pull request #372 from coreos-inc/notifyui
Better notifications UI
This commit is contained in:
commit
523dc912f7
10 changed files with 89 additions and 12 deletions
|
@ -722,6 +722,7 @@ class RepositoryNotification(BaseModel):
|
||||||
repository = ForeignKeyField(Repository, index=True)
|
repository = ForeignKeyField(Repository, index=True)
|
||||||
event = ForeignKeyField(ExternalNotificationEvent)
|
event = ForeignKeyField(ExternalNotificationEvent)
|
||||||
method = ForeignKeyField(ExternalNotificationMethod)
|
method = ForeignKeyField(ExternalNotificationMethod)
|
||||||
|
title = CharField(null=True)
|
||||||
config_json = TextField()
|
config_json = TextField()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -113,12 +113,12 @@ def delete_matching_notifications(target, kind_name, **kwargs):
|
||||||
notification.delete_instance()
|
notification.delete_instance()
|
||||||
|
|
||||||
|
|
||||||
def create_repo_notification(repo, event_name, method_name, config):
|
def create_repo_notification(repo, event_name, method_name, config, title=None):
|
||||||
event = ExternalNotificationEvent.get(ExternalNotificationEvent.name == event_name)
|
event = ExternalNotificationEvent.get(ExternalNotificationEvent.name == event_name)
|
||||||
method = ExternalNotificationMethod.get(ExternalNotificationMethod.name == method_name)
|
method = ExternalNotificationMethod.get(ExternalNotificationMethod.name == method_name)
|
||||||
|
|
||||||
return RepositoryNotification.create(repository=repo, event=event, method=method,
|
return RepositoryNotification.create(repository=repo, event=event, method=method,
|
||||||
config_json=json.dumps(config))
|
config_json=json.dumps(config), title=title)
|
||||||
|
|
||||||
|
|
||||||
def get_repo_notification(uuid):
|
def get_repo_notification(uuid):
|
||||||
|
|
|
@ -26,7 +26,8 @@ def notification_view(note):
|
||||||
'uuid': note.uuid,
|
'uuid': note.uuid,
|
||||||
'event': note.event.name,
|
'event': note.event.name,
|
||||||
'method': note.method.name,
|
'method': note.method.name,
|
||||||
'config': config
|
'config': config,
|
||||||
|
'title': note.title,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -55,7 +56,11 @@ class RepositoryNotificationList(RepositoryParamResource):
|
||||||
'config': {
|
'config': {
|
||||||
'type': 'object',
|
'type': 'object',
|
||||||
'description': 'JSON config information for the specific method of notification'
|
'description': 'JSON config information for the specific method of notification'
|
||||||
}
|
},
|
||||||
|
'title': {
|
||||||
|
'type': 'string',
|
||||||
|
'description': 'The human-readable title of the notification',
|
||||||
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -78,7 +83,8 @@ class RepositoryNotificationList(RepositoryParamResource):
|
||||||
raise request_error(message=ex.message)
|
raise request_error(message=ex.message)
|
||||||
|
|
||||||
new_notification = model.notification.create_repo_notification(repo, parsed['event'],
|
new_notification = model.notification.create_repo_notification(repo, parsed['event'],
|
||||||
parsed['method'], parsed['config'])
|
parsed['method'], parsed['config'],
|
||||||
|
parsed.get('title', None))
|
||||||
|
|
||||||
resp = notification_view(new_notification)
|
resp = notification_view(new_notification)
|
||||||
log_action('add_repo_notification', namespace,
|
log_action('add_repo_notification', namespace,
|
||||||
|
|
|
@ -11,14 +11,14 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<!-- Creating spinner -->
|
<!-- Creating spinner -->
|
||||||
<div class="quay-spinner" ng-show="status == 'creating' || status == 'authorizing-email'"></div>
|
<div class="cor-loader" ng-show="status == 'creating' || status == 'authorizing-email'"></div>
|
||||||
|
|
||||||
<!-- Authorize e-mail view -->
|
<!-- Authorize e-mail view -->
|
||||||
<div ng-show="status == 'authorizing-email-sent'">
|
<div ng-show="status == 'authorizing-email-sent'">
|
||||||
An e-mail has been sent to <code>{{ currentConfig.email }}</code>. Please click the link contained
|
An e-mail has been sent to <code>{{ currentConfig.email }}</code>. Please click the link contained
|
||||||
in the e-mail.
|
in the e-mail.
|
||||||
<br><br>
|
<br><br>
|
||||||
Waiting... <span class="quay-spinner"></span>
|
<span class="cor-loader-inline"></span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Authorize e-mail view -->
|
<!-- Authorize e-mail view -->
|
||||||
|
@ -30,6 +30,14 @@
|
||||||
|
|
||||||
<!-- Create View -->
|
<!-- Create View -->
|
||||||
<table style="width: 100%" ng-show="status == ''">
|
<table style="width: 100%" ng-show="status == ''">
|
||||||
|
<tr>
|
||||||
|
<td style="width: 120px">Notification title:</td>
|
||||||
|
<td style="padding-right: 21px;">
|
||||||
|
<input class="form-control" type="text" placeholder="(Optional Title)" ng-model="currentTitle"
|
||||||
|
style="margin: 10px;">
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td style="width: 120px">When this occurs:</td>
|
<td style="width: 120px">When this occurs:</td>
|
||||||
<td>
|
<td>
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
<table class="co-table permissions" ng-if="notifications.length">
|
<table class="co-table permissions" ng-if="notifications.length">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
<td>Title</td>
|
||||||
<td>Event</td>
|
<td>Event</td>
|
||||||
<td>Notification</td>
|
<td>Notification</td>
|
||||||
<td class="options-col"></td>
|
<td class="options-col"></td>
|
||||||
|
@ -34,6 +35,10 @@
|
||||||
|
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr class="notification-row" ng-repeat="notification in notifications">
|
<tr class="notification-row" ng-repeat="notification in notifications">
|
||||||
|
<td>
|
||||||
|
{{ notification.title || '(Untitled)' }}
|
||||||
|
</td>
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
<span class="notification-event">
|
<span class="notification-event">
|
||||||
<i class="fa fa-lg" ng-class="getEventInfo(notification).icon"></i>
|
<i class="fa fa-lg" ng-class="getEventInfo(notification).icon"></i>
|
||||||
|
@ -53,6 +58,16 @@
|
||||||
<span class="cor-option" option-click="testNotification(notification)">
|
<span class="cor-option" option-click="testNotification(notification)">
|
||||||
<i class="fa fa-send"></i> Test Notification
|
<i class="fa fa-send"></i> Test Notification
|
||||||
</span>
|
</span>
|
||||||
|
<span class="cor-option" option-click="showNotifyInfo(notification, 'url')"
|
||||||
|
ng-if="getMethodInfo(notification).id == 'webhook'">
|
||||||
|
<i class="fa fa-link"></i>
|
||||||
|
View Webhook URL
|
||||||
|
</span>
|
||||||
|
<span class="cor-option" option-click="showNotifyInfo(notification, 'email')"
|
||||||
|
ng-if="getMethodInfo(notification).id == 'email'">
|
||||||
|
<i class="fa fa-envelope"></i>
|
||||||
|
View E-mail Address
|
||||||
|
</span>
|
||||||
<span class="cor-option" option-click="showWebhookInfo(notification)"
|
<span class="cor-option" option-click="showWebhookInfo(notification)"
|
||||||
ng-if="getMethodInfo(notification).id == 'webhook'">
|
ng-if="getMethodInfo(notification).id == 'webhook'">
|
||||||
<i class="fa fa-book"></i>
|
<i class="fa fa-book"></i>
|
||||||
|
|
|
@ -88,7 +88,8 @@ angular.module('quay').directive('createExternalNotificationDialog', function ()
|
||||||
var data = {
|
var data = {
|
||||||
'event': $scope.currentEvent.id,
|
'event': $scope.currentEvent.id,
|
||||||
'method': $scope.currentMethod.id,
|
'method': $scope.currentMethod.id,
|
||||||
'config': $scope.currentConfig
|
'config': $scope.currentConfig,
|
||||||
|
'title': $scope.currentTitle
|
||||||
};
|
};
|
||||||
|
|
||||||
ApiService.createRepoNotification(data, params).then(function(resp) {
|
ApiService.createRepoNotification(data, params).then(function(resp) {
|
||||||
|
|
|
@ -64,6 +64,25 @@ angular.module('quay').directive('repositoryEventsTable', function () {
|
||||||
}, ApiService.errorDisplay('Cannot delete notification'));
|
}, ApiService.errorDisplay('Cannot delete notification'));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$scope.showNotifyInfo = function(notification, field) {
|
||||||
|
var dom = document.createElement('input');
|
||||||
|
dom.setAttribute('type', 'text');
|
||||||
|
dom.setAttribute('class', 'form-control');
|
||||||
|
dom.setAttribute('value', notification.config[field]);
|
||||||
|
dom.setAttribute('readonly', 'readonly');
|
||||||
|
|
||||||
|
bootbox.dialog({
|
||||||
|
'title': (notification.title || 'Notification') + ' ' + field,
|
||||||
|
'message': dom.outerHTML,
|
||||||
|
'buttons': {
|
||||||
|
"Done": {
|
||||||
|
className: "btn-primary",
|
||||||
|
callback: function() {}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
$scope.showWebhookInfo = function(notification) {
|
$scope.showWebhookInfo = function(notification) {
|
||||||
var eventId = notification.event;
|
var eventId = notification.event;
|
||||||
document.location = 'http://docs.quay.io/guides/notifications.html#webhook_' + eventId;
|
document.location = 'http://docs.quay.io/guides/notifications.html#webhook_' + eventId;
|
||||||
|
|
Binary file not shown.
|
@ -1935,6 +1935,8 @@ class TestRepositoryNotifications(ApiTestCase):
|
||||||
self.assertEquals('repo_push', json['event'])
|
self.assertEquals('repo_push', json['event'])
|
||||||
self.assertEquals('webhook', json['method'])
|
self.assertEquals('webhook', json['method'])
|
||||||
self.assertEquals('http://example.com', json['config']['url'])
|
self.assertEquals('http://example.com', json['config']['url'])
|
||||||
|
self.assertIsNone(json['title'])
|
||||||
|
|
||||||
wid = json['uuid']
|
wid = json['uuid']
|
||||||
|
|
||||||
# Get the notification.
|
# Get the notification.
|
||||||
|
@ -1944,6 +1946,7 @@ class TestRepositoryNotifications(ApiTestCase):
|
||||||
self.assertEquals(wid, json['uuid'])
|
self.assertEquals(wid, json['uuid'])
|
||||||
self.assertEquals('repo_push', json['event'])
|
self.assertEquals('repo_push', json['event'])
|
||||||
self.assertEquals('webhook', json['method'])
|
self.assertEquals('webhook', json['method'])
|
||||||
|
self.assertIsNone(json['title'])
|
||||||
|
|
||||||
# Verify the notification is listed.
|
# Verify the notification is listed.
|
||||||
json = self.getJsonResponse(RepositoryNotificationList,
|
json = self.getJsonResponse(RepositoryNotificationList,
|
||||||
|
@ -1962,6 +1965,29 @@ class TestRepositoryNotifications(ApiTestCase):
|
||||||
params=dict(repository=ADMIN_ACCESS_USER + '/simple', uuid=wid),
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple', uuid=wid),
|
||||||
expected_code=404)
|
expected_code=404)
|
||||||
|
|
||||||
|
# Add another notification.
|
||||||
|
json = self.postJsonResponse(RepositoryNotificationList,
|
||||||
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple'),
|
||||||
|
data=dict(config={'url': 'http://example.com'}, event='repo_push',
|
||||||
|
method='webhook', title='Some Notification'),
|
||||||
|
expected_code=201)
|
||||||
|
|
||||||
|
self.assertEquals('repo_push', json['event'])
|
||||||
|
self.assertEquals('webhook', json['method'])
|
||||||
|
self.assertEquals('http://example.com', json['config']['url'])
|
||||||
|
self.assertEquals('Some Notification', json['title'])
|
||||||
|
|
||||||
|
wid = json['uuid']
|
||||||
|
|
||||||
|
# Get the notification.
|
||||||
|
json = self.getJsonResponse(RepositoryNotification,
|
||||||
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple', uuid=wid))
|
||||||
|
|
||||||
|
self.assertEquals(wid, json['uuid'])
|
||||||
|
self.assertEquals('repo_push', json['event'])
|
||||||
|
self.assertEquals('webhook', json['method'])
|
||||||
|
self.assertEquals('Some Notification', json['title'])
|
||||||
|
|
||||||
|
|
||||||
class TestListAndGetImage(ApiTestCase):
|
class TestListAndGetImage(ApiTestCase):
|
||||||
def test_listandgetimages(self):
|
def test_listandgetimages(self):
|
||||||
|
|
|
@ -13,8 +13,9 @@ def run_slackwebhook_migration():
|
||||||
|
|
||||||
encountered = set()
|
encountered = set()
|
||||||
while True:
|
while True:
|
||||||
found = list(RepositoryNotification.select().where(
|
found = list(RepositoryNotification.select(RepositoryNotification.uuid,
|
||||||
RepositoryNotification.method == slack_method,
|
RepositoryNotification.config_json)
|
||||||
|
.where(RepositoryNotification.method == slack_method,
|
||||||
RepositoryNotification.config_json ** "%subdomain%",
|
RepositoryNotification.config_json ** "%subdomain%",
|
||||||
~(RepositoryNotification.config_json ** "%url%")))
|
~(RepositoryNotification.config_json ** "%url%")))
|
||||||
|
|
||||||
|
|
Reference in a new issue