-
-
-
-
- - Address
- - {$ ::ctrl.member.address $}
- - Protocol Port
- - {$ ::ctrl.member.protocol_port $}
- - Weight
- - {$ ctrl.member.weight $}
- - Operating Status
- - {$ ctrl.member.operating_status | decode:ctrl.operatingStatus $}
- - Provisioning Status
- - {$ ctrl.member.provisioning_status | decode:ctrl.provisioningStatus $}
- - Admin State Up
- - {$ ctrl.member.admin_state_up | yesno $}
- - Member ID
- - {$ ::ctrl.member.id $}
- - Tenant ID
- - {$ ::ctrl.member.tenant_id $}
-
+
+
+
+
+
+
+ - Address
+ - {$ ::ctrl.member.address $}
+ - Protocol Port
+ - {$ ::ctrl.member.protocol_port $}
+ - Weight
+ - {$ ctrl.member.weight $}
+ - Operating Status
+ - {$ ctrl.member.operating_status | decode:ctrl.operatingStatus $}
+ - Provisioning Status
+ - {$ ctrl.member.provisioning_status | decode:ctrl.provisioningStatus $}
+ - Admin State Up
+ - {$ ctrl.member.admin_state_up | yesno $}
+ - Member ID
+ - {$ ::ctrl.member.id $}
+ - Tenant ID
+ - {$ ::ctrl.member.tenant_id $}
+
+
-
\ No newline at end of file
+
diff --git a/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/pools/detail.controller.js b/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/pools/detail.controller.js
index aabea9f..4f0e188 100644
--- a/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/pools/detail.controller.js
+++ b/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/pools/detail.controller.js
@@ -26,7 +26,8 @@
'$routeParams',
'horizon.framework.util.i18n.gettext',
'$window',
- '$scope'
+ '$scope',
+ '$q'
];
/**
@@ -42,12 +43,15 @@
* @param gettext The horizon gettext function for translation.
* @param $window Angular's reference to the browser window object.
* @param $scope The angular scope object.
+ * @param $q The angular service for promises.
* @returns undefined
*/
- function PoolDetailController(api, rowActions, $routeParams, gettext, $window, $scope) {
+ function PoolDetailController(api, rowActions, $routeParams, gettext, $window, $scope, $q) {
var ctrl = this;
+ ctrl.loading = true;
+ ctrl.error = false;
ctrl.loadBalancerAlgorithm = {
ROUND_ROBIN: gettext('Round Robin'),
LEAST_CONNECTIONS: gettext('Least Connections'),
@@ -61,17 +65,43 @@
////////////////////////////////
function init() {
- api.getPool($routeParams.poolId).success(set('pool'));
- api.getListener($routeParams.listenerId).success(set('listener'));
- api.getLoadBalancer($routeParams.loadbalancerId).success(set('loadbalancer'));
+ ctrl.pool = null;
+ ctrl.listener = null;
+ ctrl.loadbalancer = null;
+ ctrl.loading = true;
+ ctrl.error = false;
+ $q.all([
+ api.getPool($routeParams.poolId)
+ .then(success('pool'), fail('pool')),
+ api.getListener($routeParams.listenerId)
+ .then(success('listener'), fail('listener')),
+ api.getLoadBalancer($routeParams.loadbalancerId)
+ .then(success('loadbalancer'), fail('loadbalancer'))
+ ]).then(postInit, initError);
}
- function set(property) {
- return angular.bind(null, function setProp(property, value) {
- ctrl[property] = value;
+ function success(property) {
+ return angular.bind(null, function setProp(property, response) {
+ ctrl[property] = response.data;
}, property);
}
+ function fail(property) {
+ return angular.bind(null, function setProp(property, error) {
+ ctrl[property] = null;
+ throw error;
+ }, property);
+ }
+
+ function postInit() {
+ ctrl.loading = false;
+ }
+
+ function initError() {
+ ctrl.loading = false;
+ ctrl.error = true;
+ }
+
// Save the active state of the members tab in the global window object so it can stay
// active after reloading the route following an action.
$scope.$watch(function() {
diff --git a/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/pools/detail.controller.spec.js b/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/pools/detail.controller.spec.js
index 8716523..894383d 100644
--- a/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/pools/detail.controller.spec.js
+++ b/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/pools/detail.controller.spec.js
@@ -17,26 +17,43 @@
'use strict';
describe('LBaaS v2 Pool Detail Controller', function() {
- var lbaasv2API, ctrl, $scope, $window;
+ var lbaasv2API, $scope, $window, $controller, apiFail, qAllFail;
- function fakeAPI() {
+ function fakePromise(data, reject) {
return {
- success: function(callback) {
- callback('foo');
+ then: function(success, fail) {
+ if (reject) {
+ fail();
+ } else {
+ success({ data: data });
+ }
+ return fakePromise();
}
};
}
+ function fakeAPI() {
+ return fakePromise('foo', apiFail);
+ }
+
function loadbalancerAPI() {
- var loadbalancer = { provisioning_status: 'ACTIVE' };
- return {
- success: function(callback) {
- callback(loadbalancer);
- },
- then: function(callback) {
- callback({ data: loadbalancer });
+ return fakePromise({ provisioning_status: 'ACTIVE' });
+ }
+
+ function qAll() {
+ return fakePromise(null, qAllFail);
+ }
+
+ function createController() {
+ return $controller('PoolDetailController', {
+ $scope: $scope,
+ $window: $window,
+ $routeParams: {
+ loadbalancerId: 'loadbalancerId',
+ listenerId: 'listenerId',
+ poolId: 'poolId'
}
- };
+ });
}
///////////////////////
@@ -47,6 +64,13 @@
beforeEach(module('horizon.app.core.openstack-service-api'));
beforeEach(module('horizon.dashboard.project.lbaasv2'));
+ beforeEach(module(function($provide) {
+ apiFail = false;
+ qAllFail = false;
+
+ $provide.value('$q', { all: qAll });
+ }));
+
beforeEach(inject(function($injector) {
lbaasv2API = $injector.get('horizon.app.core.openstack-service-api.lbaasv2');
spyOn(lbaasv2API, 'getPool').and.callFake(fakeAPI);
@@ -54,19 +78,11 @@
spyOn(lbaasv2API, 'getLoadBalancer').and.callFake(loadbalancerAPI);
$scope = $injector.get('$rootScope').$new();
$window = {};
- var controller = $injector.get('$controller');
- ctrl = controller('PoolDetailController', {
- $scope: $scope,
- $window: $window,
- $routeParams: {
- loadbalancerId: 'loadbalancerId',
- listenerId: 'listenerId',
- poolId: 'poolId'
- }
- });
+ $controller = $injector.get('$controller');
}));
it('should invoke lbaasv2 apis', function() {
+ var ctrl = createController();
expect(lbaasv2API.getPool).toHaveBeenCalledWith('poolId');
expect(lbaasv2API.getListener).toHaveBeenCalledWith('listenerId');
expect(lbaasv2API.getLoadBalancer).toHaveBeenCalledWith('loadbalancerId');
@@ -76,10 +92,12 @@
});
it('should define mapping for the load balancer algorithm', function() {
+ var ctrl = createController();
expect(ctrl.loadBalancerAlgorithm).toBeDefined();
});
it('should save changes to members tab active state', function() {
+ var ctrl = createController();
expect($window.membersTabActive).toBeUndefined();
expect(ctrl.membersTabActive).toBeUndefined();
ctrl.membersTabActive = true;
@@ -90,6 +108,21 @@
expect($window.membersTabActive).toBe(false);
});
+ it('should throw error on API fail', function() {
+ apiFail = true;
+ var init = function() {
+ createController();
+ };
+ expect(init).toThrow();
+ });
+
+ it('should set error state if any APIs fail', function() {
+ qAllFail = true;
+ var ctrl = createController();
+ expect(ctrl.loading).toBe(false);
+ expect(ctrl.error).toBe(true);
+ });
+
});
})();
diff --git a/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/pools/detail.html b/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/pools/detail.html
index faaa253..510deaa 100644
--- a/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/pools/detail.html
+++ b/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/pools/detail.html
@@ -1,47 +1,50 @@
-
-
-
-
-
-
- - Protocol
- - {$ ::ctrl.pool.protocol $}
- - Load Balancer Algorithm
- - {$ ctrl.pool.lb_algorithm | decode:ctrl.loadBalancerAlgorithm $}
- - Session Persistence
- - {$ ctrl.pool.session_persistence | noValue:('None' | translate) $}
- - Admin State Up
- - {$ ctrl.pool.admin_state_up | yesno $}
- - Health Monitor ID
- -
-
- {$ ::ctrl.pool.healthmonitor_id $}
-
-
- {$ 'None' | translate $}
-
-
- - Pool ID
- - {$ ::ctrl.pool.id $}
- - Tenant ID
- - {$ ::ctrl.pool.tenant_id $}
-
+
+
+
+
+
+
+
+
+ - Protocol
+ - {$ ::ctrl.pool.protocol $}
+ - Load Balancer Algorithm
+ - {$ ctrl.pool.lb_algorithm | decode:ctrl.loadBalancerAlgorithm $}
+ - Session Persistence
+ - {$ ctrl.pool.session_persistence | noValue:('None' | translate) $}
+ - Admin State Up
+ - {$ ctrl.pool.admin_state_up | yesno $}
+ - Health Monitor ID
+ -
+
+ {$ ::ctrl.pool.healthmonitor_id $}
+
+
+ {$ 'None' | translate $}
+
+
+ - Pool ID
+ - {$ ::ctrl.pool.id $}
+ - Tenant ID
+ - {$ ::ctrl.pool.tenant_id $}
+
+
-
-
-
-
-
-
+
+
+
+
+
+
\ No newline at end of file
diff --git a/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/widgets/detail/detail-status.directive.js b/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/widgets/detail/detail-status.directive.js
new file mode 100644
index 0000000..24cb0f9
--- /dev/null
+++ b/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/widgets/detail/detail-status.directive.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.lbaasv2')
+ .directive('detailStatus', detailStatus);
+
+ detailStatus.$inject = [
+ 'horizon.dashboard.project.lbaasv2.basePath'
+ ];
+
+ /**
+ * @ngdoc directive
+ * @name horizon.dashboard.project.lbaasv2:detailStatus
+ * @description
+ * The `detailStatus` directive provides a status indicator while loading detail pages. It will
+ * show a loading indicator while the page is loading and an error indicator if there is an
+ * error loading the page.
+ * @restrict E
+ *
+ * @example
+ * ```
+ *
+ * ```
+ */
+
+ function detailStatus(basePath) {
+ var directive = {
+ restrict: 'E',
+ templateUrl: basePath + 'widgets/detail/detail-status.html',
+ scope: {
+ loading: '=',
+ error: '='
+ }
+ };
+ return directive;
+ }
+}());
diff --git a/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/widgets/detail/detail-status.directive.spec.js b/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/widgets/detail/detail-status.directive.spec.js
new file mode 100644
index 0000000..c26c5fd
--- /dev/null
+++ b/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/widgets/detail/detail-status.directive.spec.js
@@ -0,0 +1,87 @@
+/*
+ * 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';
+
+ function digestMarkup(scope, compile, markup) {
+ var element = angular.element(markup);
+ compile(element)(scope);
+ scope.$apply();
+ return element;
+ }
+
+ describe('detailStatus directive', function() {
+ var $scope, $compile, markup, ctrl;
+
+ beforeEach(module('templates'));
+ beforeEach(module('horizon.dashboard.project.lbaasv2'));
+
+ beforeEach(inject(function($injector) {
+ $compile = $injector.get('$compile');
+ $scope = $injector.get('$rootScope').$new();
+ ctrl = {
+ loading: true,
+ error: false
+ };
+ $scope.ctrl = ctrl;
+ markup = '';
+ }));
+
+ it('initially shows loading status', function() {
+ var element = digestMarkup($scope, $compile, markup);
+ expect(element).toBeDefined();
+
+ expect(element.children().length).toBe(1);
+ expect(element.find('.progress-bar').hasClass('progress-bar-striped')).toBe(true);
+ expect(element.find('.progress-bar').hasClass('progress-bar-danger')).toBe(false);
+ expect(element.find('.progress-bar > span').length).toBe(1);
+ expect(element.find('.progress-bar > span').hasClass('sr-only')).toBe(true);
+ expect(element.find('.progress-bar > span').text().trim()).toBe('Loading');
+ expect(element.find('.message').length).toBe(0);
+ });
+
+ it('indicates error status on error', function() {
+ var element = digestMarkup($scope, $compile, markup);
+ expect(element).toBeDefined();
+
+ ctrl.loading = false;
+ ctrl.error = true;
+ $scope.$apply();
+
+ expect(element.children().length).toBe(1);
+ expect(element.find('.progress-bar').hasClass('progress-bar-striped')).toBe(false);
+ expect(element.find('.progress-bar').hasClass('progress-bar-danger')).toBe(true);
+ expect(element.find('.progress-bar > span').length).toBe(1);
+ expect(element.find('.progress-bar > span').hasClass('sr-only')).toBe(false);
+ expect(element.find('.progress-bar > span').text().trim())
+ .toBe('An error occurred. Please try again later.');
+ expect(element.find('.error-actions').length).toBe(1);
+ expect(element.find('.error-actions > a').text().trim()).toBe('Back');
+ });
+
+ it('goes away when done loading', function() {
+ var element = digestMarkup($scope, $compile, markup);
+ expect(element).toBeDefined();
+
+ ctrl.loading = false;
+ ctrl.error = false;
+ $scope.$apply();
+
+ expect(element.children().length).toBe(0);
+ });
+
+ });
+}());
diff --git a/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/widgets/detail/detail-status.html b/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/widgets/detail/detail-status.html
new file mode 100644
index 0000000..3278ed1
--- /dev/null
+++ b/neutron_lbaas_dashboard/static/dashboard/project/lbaasv2/widgets/detail/detail-status.html
@@ -0,0 +1,12 @@
+
+
+
+ Loading
+ An error occurred. Please try again later.
+
+
+
+
\ No newline at end of file