diff --git a/zaqar_ui/static/app/core/openstack-service-api/zaqar.service.js b/zaqar_ui/static/app/core/openstack-service-api/zaqar.service.js index 0f851ba..52aa64b 100644 --- a/zaqar_ui/static/app/core/openstack-service-api/zaqar.service.js +++ b/zaqar_ui/static/app/core/openstack-service-api/zaqar.service.js @@ -26,12 +26,19 @@ 'horizon.framework.widgets.toast.service' ]; - function ZaqarAPI(apiService, toastService) { + function ZaqarAPI(apiService, toast) { + + var queuePath = '/api/zaqar/queues/'; + var subPath = '/api/zaqar/queues/%s/subscriptions/'; + var service = { getQueues: getQueues, createQueue: createQueue, deleteQueue: deleteQueue, - updateQueue: updateQueue + updateQueue: updateQueue, + getSubscriptions: getSubscriptions, + addSubscription: addSubscription, + deleteSubscription: deleteSubscription }; return service; @@ -39,28 +46,47 @@ ////////// function getQueues() { - return apiService.get('/api/zaqar/queues/') - .error(function() { - toastService.add('error', gettext('Unable to retrieve the Queues.')); - }); + var msg = gettext('Unable to retrieve the Queues.'); + return apiService.get(queuePath).error(error(msg)); } function createQueue(newQueue) { - return apiService.put('/api/zaqar/queues/', newQueue) - .error(function() { - toastService.add('error', gettext('Unable to create the queue.')); - }); + var msg = gettext('Unable to create the queue.'); + return apiService.put(queuePath, newQueue).error(error(msg)); } function deleteQueue(queueName) { - return apiService.delete('/api/zaqar/queues/', [queueName]); + return apiService.delete(queuePath, [queueName]); } function updateQueue(queue) { - return apiService.post('/api/zaqar/queue/' + queue.queue_name, {"metadata": queue.metadata}) - .error(function() { - toastService.add('error', gettext('Unable to update the queue.')); - }); + var msg = gettext('Unable to update the queue.'); + var url = '/api/zaqar/queue/' + queue.queue_name; + var form = { metadata: queue.metadata }; + return apiService.post(url, form).error(error(msg)); + } + + function getSubscriptions(queue) { + var url = interpolate(subPath, [queue.name]); + return apiService.get(url); + } + + function addSubscription(sub) { + var msg = gettext('Unable to add subscription.'); + var url = interpolate(subPath, [sub.queueName]); + return apiService.put(url, sub).error(error(msg)); + } + + function deleteSubscription(queue, subscription) { + var msg = gettext('Unable to delete subscription.'); + var url = interpolate(subPath, [queue.name]); + return apiService.delete(url, subscription).error(error(msg)); + } + + function error(message) { + return function() { + toast.add('error', message); + }; } } }()); diff --git a/zaqar_ui/static/dashboard/project/queues/actions/actions.module.js b/zaqar_ui/static/dashboard/project/queues/actions/actions.module.js index 03e0193..c3d7732 100644 --- a/zaqar_ui/static/dashboard/project/queues/actions/actions.module.js +++ b/zaqar_ui/static/dashboard/project/queues/actions/actions.module.js @@ -32,6 +32,7 @@ 'horizon.dashboard.project.queues.actions.createService', 'horizon.dashboard.project.queues.actions.deleteService', 'horizon.dashboard.project.queues.actions.updateService', + 'horizon.dashboard.project.queues.actions.createSubscriptionService', 'horizon.dashboard.project.queues.resourceType' ]; @@ -40,6 +41,7 @@ createService, deleteService, updateService, + createSubscriptionService, resourceType ) { @@ -52,6 +54,13 @@ text: gettext('Update') } }) + .append({ + id: 'subscriptionsCreate', + service: createSubscriptionService, + template: { + text: gettext('Create Subscription') + } + }) .append({ id: 'queuesItemDelete', service: deleteService, diff --git a/zaqar_ui/static/dashboard/project/queues/actions/createSubscription.service.js b/zaqar_ui/static/dashboard/project/queues/actions/createSubscription.service.js new file mode 100644 index 0000000..69b823d --- /dev/null +++ b/zaqar_ui/static/dashboard/project/queues/actions/createSubscription.service.js @@ -0,0 +1,112 @@ +/** + * Copyright 2016 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ + + (function() { + 'use strict'; + + angular + .module('horizon.dashboard.project.queues') + .factory('horizon.dashboard.project.queues.actions.createSubscriptionService', + createSubscriptionService); + + createSubscriptionService.$inject = [ + '$q', + 'horizon.app.core.metadata.service', + 'horizon.app.core.openstack-service-api.policy', + 'horizon.dashboard.project.queues.events', + 'horizon.dashboard.project.queues.actions.createSubscriptionWorkflow', + 'horizon.app.core.openstack-service-api.zaqar', + 'horizon.framework.widgets.modal.wizard-modal.service', + 'horizon.framework.widgets.toast.service' + ]; + + /** + * @ngDoc factory + * @name horizon.dashboard.project.queues.actions.createSubscriptionService + * @Description A service to open the subscriptions wizard. + */ + function createSubscriptionService( + $q, meta, policy, events, createWorkflow, zaqar, wizard, toast) { + + var message = { + success: gettext('Subscription %s was successfully created.') + }; + + var scope; + var model = null; + + var service = { + initScope: initScope, + perform: perform, + allowed: allowed + }; + + return service; + + ////////////// + + // we define initScope so that the table controller + // will know when a new subscription has been created + function initScope($scope) { + scope = $scope; + var subWatcher = $scope.$on(events.SUBSCRIPTION_CHANGED, onSubscriptionChange); + $scope.$on('$destroy', function destroy() { + subWatcher(); + }); + } + + function onSubscriptionChange(e, subscription) { + angular.extend(model, subscription); + e.stopPropagation(); + } + + function perform(queue) { + model = { subscriber: null, ttl: null, options: {} }; + model.queueName = queue.name; + wizard.modal({ + scope: scope, + workflow: createWorkflow, + submit: submit + }); + } + + function allowed(queue) { + return policy.ifAllowed({ rules: [['queue', 'add_subscriptions']] });; + } + + function submit() { + return zaqar.addSubscription(model).then(success, error); + } + + function success(response) { + angular.extend(model, response.data); + toast.add('success', interpolate(message.success, [model.subscriber])); + scope.$emit(events.SUBSCRIPTION_CREATE_SUCCESS, model); + } + + function error(response) { + // TODO: Currently, when server throws an error + // close the modal dialog and display the error message + // In the future, display the error message inside the dialog + // and allow user to continue with workflow + return; + } + + } // end of createSubscriptionService +})(); // end of IIFE + + + diff --git a/zaqar_ui/static/dashboard/project/queues/actions/createSubscription.workflow.js b/zaqar_ui/static/dashboard/project/queues/actions/createSubscription.workflow.js new file mode 100644 index 0000000..d876ec0 --- /dev/null +++ b/zaqar_ui/static/dashboard/project/queues/actions/createSubscription.workflow.js @@ -0,0 +1,53 @@ +/** + * Copyright 2016 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ + + (function() { + 'use strict'; + + angular + .module('horizon.dashboard.project.queues') + .factory('horizon.dashboard.project.queues.actions.createSubscriptionWorkflow', + createSubscriptionWorkflow); + + createSubscriptionWorkflow.$inject = [ + 'horizon.app.core.workflow.factory', + 'horizon.dashboard.project.queues.basePath', + 'horizon.framework.util.i18n.gettext' + ]; + + /** + * @ngdoc factory + * @name horizon.dashboard.project.queues.actions.createSubscriptionWorkflow + * @description A workflow for the create subscription action. + */ + function createSubscriptionWorkflow(workflowService, basePath, gettext) { + + var workflow = workflowService({ + title: gettext('Create Subscription'), + btnText: { finish: gettext('Create') }, + steps: [ + { + title: gettext('Subscription'), + templateUrl: basePath + 'steps/subscription/subscription.html', + formName: 'subscriptionForm' + } + ] + }); + + return workflow; + } + +})(); diff --git a/zaqar_ui/static/dashboard/project/queues/queues.module.js b/zaqar_ui/static/dashboard/project/queues/queues.module.js index 1777533..2904ed9 100644 --- a/zaqar_ui/static/dashboard/project/queues/queues.module.js +++ b/zaqar_ui/static/dashboard/project/queues/queues.module.js @@ -46,7 +46,8 @@ DETAILS_CHANGED: 'horizon.dashboard.project.queues.DETAILS_CHANGED', METADATA_CHANGED: 'horizon.dashboard.project.queues.METADATA_CHANGED', DELETE_SUCCESS: 'horizon.dashboard.project.queues.DELETE_SUCCESS', - UPDATE_SUCCESS: 'horizon.dashboard.project.queues.UPDATE_SUCCESS' + UPDATE_SUCCESS: 'horizon.dashboard.project.queues.UPDATE_SUCCESS', + SUBSCRIPTION_CREATE_SUCCESS: 'horizon.dashboard.project.queues.SUBSCRIPTION_CREATE_SUCCESS' }; } diff --git a/zaqar_ui/static/dashboard/project/queues/queues.scss b/zaqar_ui/static/dashboard/project/queues/queues.scss index e69de29..a64dba3 100644 --- a/zaqar_ui/static/dashboard/project/queues/queues.scss +++ b/zaqar_ui/static/dashboard/project/queues/queues.scss @@ -0,0 +1,4 @@ + +.subtitle { + margin: 2em 0; +} \ No newline at end of file diff --git a/zaqar_ui/static/dashboard/project/queues/steps/subscription/subscription.controller.js b/zaqar_ui/static/dashboard/project/queues/steps/subscription/subscription.controller.js new file mode 100644 index 0000000..2822c7e --- /dev/null +++ b/zaqar_ui/static/dashboard/project/queues/steps/subscription/subscription.controller.js @@ -0,0 +1,64 @@ +/** + * Copyright 2016 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ + + (function() { + 'use strict'; + + angular + .module('horizon.dashboard.project.queues') + .controller('horizon.dashboard.project.queues.steps.SubscriptionController', + SubscriptionController); + + SubscriptionController.$inject = [ + '$scope', + 'horizon.app.core.openstack-service-api.zaqar', + 'horizon.dashboard.project.queues.events' + ]; + + /** + * @ngdoc controller + * @name horizon.dashboard.project.queues.steps.SubscriptionController + * @description This controller is use for creating a subscription. + */ + function SubscriptionController($scope, zaqar, events) { + + var ctrl = this; + ctrl.subscription = {}; + ctrl.update = false; + + //////////////////////// + + // watch this object, when it changes, emit to parent listeners + var watcher = $scope.$watchCollection(getSubscription, onSubscriptionChange); + $scope.$on('$destroy', function() { + watcher(); + }) + + //////////////////////// + + function getSubscription() { + return ctrl.subscription; + } + + function onSubscriptionChange(newValue, oldValue){ + if (newValue !== oldValue) { + $scope.$emit(events.SUBSCRIPTION_CHANGED, newValue); + } + } + + } // end of SubscriptionController + +})(); diff --git a/zaqar_ui/static/dashboard/project/queues/steps/subscription/subscription.html b/zaqar_ui/static/dashboard/project/queues/steps/subscription/subscription.html new file mode 100644 index 0000000..dcada3b --- /dev/null +++ b/zaqar_ui/static/dashboard/project/queues/steps/subscription/subscription.html @@ -0,0 +1,48 @@ + +
+ +

Subscription

+
+ +
+ Note that you can create a subscription without defining options. + Subscribers must be in the form of mailto, HTTP, or HTTPS. + The TTL for a subscription must be at least 60 seconds long. +
+ +
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+ +
+
diff --git a/zaqar_ui/static/dashboard/project/queues/table/subscriptionTable.controller.js b/zaqar_ui/static/dashboard/project/queues/table/subscriptionTable.controller.js new file mode 100644 index 0000000..18418f0 --- /dev/null +++ b/zaqar_ui/static/dashboard/project/queues/table/subscriptionTable.controller.js @@ -0,0 +1,97 @@ +/** + * Copyright 2016 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ + +(function() { + 'use strict'; + + /** + * @ngdoc overview + * @name queuesTableController + * @ngController + * + * @description + * Controller for the queues table + */ + angular + .module('horizon.dashboard.project.queues') + .controller('horizon.dashboard.project.queues.SubscriptionTableController', + SubscriptionTableController); + + SubscriptionTableController.$inject = [ + '$scope', + 'horizon.app.core.openstack-service-api.zaqar', + 'horizon.dashboard.project.queues.events', + 'horizon.framework.widgets.toast.service' + ]; + + function SubscriptionTableController($scope, zaqar, events, toast) { + + var ctrl = this; + ctrl.queuesMap = {}; + ctrl.deleteSubscription = deleteSubscription; + + init(); + initScope(); + + ////////// + + function initScope() { + var expandWatcher = $scope.$on('hzTable:rowExpanded', getSubscriptions); + var createWatcher = $scope.$on(events.SUBSCRIPTION_CREATE_SUCCESS, addSubscription); + $scope.$on('$destroy', function destroy() { + expandWatcher(); + createWatcher(); + }); + } + + function init() {} + + ////////// + + function checkAndInitMap(id) { + if (!ctrl.queuesMap.hasOwnProperty(id)) { + ctrl.queuesMap[id] = { + subscriptions: [] + }; + } + } + + function addSubscription(event, sub){ + checkAndInitMap(sub.queueName); + ctrl.queuesMap[sub.queueName].subscriptions.push(sub); + } + + function deleteSubscription(queue, sub){ + var msg = gettext('Removed %(subscriber)s subscriber from the %(queue)s queue.'); + var context = { subscriber: sub.subscriber, queue: queue.name }; + zaqar.deleteSubscription(queue.name, sub).success(deleteSuccess); + + function deleteSuccess(){ + toast.add('success', interpolate(msg, context, true)); + var index = ctrl.queuesMap[queue.name].subscriptions.indexOf(sub); + if (index >= 0){ ctrl.queuesMap[queue.name].subscriptions.splice(index, 1); } + } + } + + function getSubscriptions(event, queue) { + zaqar.getSubscriptions(queue).success(function (response) { + checkAndInitMap(queue.name); + ctrl.queuesMap[queue.name].subscriptions = response; + }); + } + } + +})(); diff --git a/zaqar_ui/static/dashboard/project/queues/table/subscriptionTable.html b/zaqar_ui/static/dashboard/project/queues/table/subscriptionTable.html new file mode 100644 index 0000000..3ecc932 --- /dev/null +++ b/zaqar_ui/static/dashboard/project/queues/table/subscriptionTable.html @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + +
SubscriberTime to LiveOptionsActions
No subscribers to show.
{$ sub.subscriber $}{$ sub.ttl $}{$ sub.options $} + +
diff --git a/zaqar_ui/static/dashboard/project/queues/table/table.controller.js b/zaqar_ui/static/dashboard/project/queues/table/table.controller.js index 30d8210..e4d6105 100644 --- a/zaqar_ui/static/dashboard/project/queues/table/table.controller.js +++ b/zaqar_ui/static/dashboard/project/queues/table/table.controller.js @@ -30,19 +30,20 @@ queuesTableController.$inject = [ '$scope', 'horizon.app.core.openstack-service-api.zaqar', + 'horizon.dashboard.project.queues.basePath', 'horizon.dashboard.project.queues.events', 'horizon.dashboard.project.queues.resourceType', 'horizon.framework.conf.resource-type-registry.service', ]; - function queuesTableController($scope, zaqar, events, type, registry) { + function queuesTableController($scope, zaqar, base, events, type, registry) { var ctrl = this; ctrl.queues = []; ctrl.queuesSrc = []; - ctrl.resourceType = registry.getResourceType(type); + ctrl.subsTemplate = base + 'table/subscriptionTable.html'; init(); initScope(); @@ -53,11 +54,13 @@ var createWatcher = $scope.$on(events.CREATE_SUCCESS, onCreateSuccess); var deleteWatcher = $scope.$on(events.DELETE_SUCCESS, onDeleteSuccess); var updateWatcher = $scope.$on(events.UPDATE_SUCCESS, onUpdateSuccess); + var subWatcher = $scope.$on(events.SUBSCRIPTION_CREATE_SUCCESS, broadcastEvents); $scope.$on('$destroy', function destroy() { createWatcher(); deleteWatcher(); updateWatcher(); - }) + subWatcher(); + }); } ////////// @@ -67,6 +70,12 @@ zaqar.getQueues().then(showQueues); } + function broadcastEvents(event, data) { + if (event.targetScope !== $scope) { + $scope.$broadcast(event.name, data); + } + } + function showQueues(response) { // hz-table expects all items to have the id field // so we need to manually add name as id here diff --git a/zaqar_ui/static/dashboard/project/queues/table/table.html b/zaqar_ui/static/dashboard/project/queues/table/table.html index 8ad20d5..7c06bf4 100644 --- a/zaqar_ui/static/dashboard/project/queues/table/table.html +++ b/zaqar_ui/static/dashboard/project/queues/table/table.html @@ -59,7 +59,7 @@ + hz-expand-detail item="q" duration="200"> {$ q.name $} @@ -71,7 +71,7 @@ Table-row-action-column: Actions taken here applies to a single item/row. --> - + @@ -88,8 +88,8 @@ E.g. table header with rsp-p2 should be here with rsp-alt-p2 The layout should minimize vertical space to reduce scrolling. --> -
+
Metadata
{$ q.metadata $}
+