Merge "Add loading and error status to detail pages"
This commit is contained in:
commit
54e965a87d
|
@ -23,7 +23,8 @@
|
|||
HealthMonitorDetailController.$inject = [
|
||||
'horizon.app.core.openstack-service-api.lbaasv2',
|
||||
'horizon.dashboard.project.lbaasv2.healthmonitors.actions.rowActions',
|
||||
'$routeParams'
|
||||
'$routeParams',
|
||||
'$q'
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -36,12 +37,15 @@
|
|||
* @param api The LBaaS v2 API service.
|
||||
* @param rowActions The LBaaS v2 health monitor row actions service.
|
||||
* @param $routeParams The angular $routeParams service.
|
||||
* @param $q The angular service for promises.
|
||||
* @returns undefined
|
||||
*/
|
||||
|
||||
function HealthMonitorDetailController(api, rowActions, $routeParams) {
|
||||
function HealthMonitorDetailController(api, rowActions, $routeParams, $q) {
|
||||
var ctrl = this;
|
||||
|
||||
ctrl.loading = true;
|
||||
ctrl.error = false;
|
||||
ctrl.actions = rowActions.init($routeParams.loadbalancerId,
|
||||
$routeParams.listenerId,
|
||||
$routeParams.poolId).actions;
|
||||
|
@ -51,18 +55,46 @@
|
|||
////////////////////////////////
|
||||
|
||||
function init() {
|
||||
api.getHealthMonitor($routeParams.healthmonitorId).success(set('healthmonitor'));
|
||||
api.getPool($routeParams.poolId).success(set('pool'));
|
||||
api.getListener($routeParams.listenerId).success(set('listener'));
|
||||
api.getLoadBalancer($routeParams.loadbalancerId).success(set('loadbalancer'));
|
||||
ctrl.healthmonitor = null;
|
||||
ctrl.pool = null;
|
||||
ctrl.listener = null;
|
||||
ctrl.loadbalancer = null;
|
||||
ctrl.loading = true;
|
||||
ctrl.error = false;
|
||||
$q.all([
|
||||
api.getHealthMonitor($routeParams.healthmonitorId)
|
||||
.then(success('healthmonitor'), fail('healthmonitor')),
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
})();
|
||||
|
|
|
@ -17,26 +17,42 @@
|
|||
'use strict';
|
||||
|
||||
describe('LBaaS v2 Healthmonitor Detail Controller', function() {
|
||||
var lbaasv2API, ctrl;
|
||||
var lbaasv2API, $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('HealthMonitorDetailController', {
|
||||
$routeParams: {
|
||||
loadbalancerId: 'loadbalancerId',
|
||||
listenerId: 'listenerId',
|
||||
poolId: 'poolId',
|
||||
healthmonitorId: 'healthmonitorId'
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
///////////////////////
|
||||
|
@ -47,24 +63,24 @@
|
|||
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, 'getHealthMonitor').and.callFake(fakeAPI);
|
||||
spyOn(lbaasv2API, 'getPool').and.callFake(fakeAPI);
|
||||
spyOn(lbaasv2API, 'getListener').and.callFake(fakeAPI);
|
||||
spyOn(lbaasv2API, 'getLoadBalancer').and.callFake(loadbalancerAPI);
|
||||
var controller = $injector.get('$controller');
|
||||
ctrl = controller('HealthMonitorDetailController', {
|
||||
$routeParams: {
|
||||
loadbalancerId: 'loadbalancerId',
|
||||
listenerId: 'listenerId',
|
||||
poolId: 'poolId',
|
||||
healthmonitorId: 'healthmonitorId'
|
||||
}
|
||||
});
|
||||
$controller = $injector.get('$controller');
|
||||
}));
|
||||
|
||||
it('should invoke lbaasv2 apis', function() {
|
||||
var ctrl = createController();
|
||||
expect(lbaasv2API.getHealthMonitor).toHaveBeenCalledWith('healthmonitorId');
|
||||
expect(lbaasv2API.getPool).toHaveBeenCalledWith('poolId');
|
||||
expect(lbaasv2API.getListener).toHaveBeenCalledWith('listenerId');
|
||||
|
@ -75,6 +91,21 @@
|
|||
expect(ctrl.healthmonitor).toBe('foo');
|
||||
});
|
||||
|
||||
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);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
})();
|
||||
|
|
|
@ -1,39 +1,42 @@
|
|||
<div ng-controller="HealthMonitorDetailController as ctrl">
|
||||
<div class="page-header">
|
||||
<ol class="breadcrumb">
|
||||
<li><a href="project/ngloadbalancersv2/"><translate>Load Balancers</translate></a></li>
|
||||
<li><a href="project/ngloadbalancersv2/{$ ::ctrl.loadbalancer.id $}">{$ ::(ctrl.loadbalancer.name || ctrl.loadbalancer.id) $}</a></li>
|
||||
<li><a href="project/ngloadbalancersv2/{$ ::ctrl.loadbalancer.id $}/listeners/{$ ::ctrl.listener.id $}">{$ ::(ctrl.listener.name || ctrl.listener.id) $}</a></li>
|
||||
<li><a href="project/ngloadbalancersv2/{$ ::ctrl.loadbalancer.id $}/listeners/{$ ::ctrl.listener.id $}/pools/{$ ::ctrl.pool.id $}">{$ ::(ctrl.pool.name || ctrl.pool.id) $}</a></li>
|
||||
<li class="active">{$ ::(ctrl.healthmonitor.name || ctrl.healthmonitor.id) $}</li>
|
||||
<actions allowed="ctrl.actions" type="row" item="ctrl.healthmonitor"
|
||||
ng-if="ctrl.healthmonitor" class="actions_column pull-right"></actions>
|
||||
</ol>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6 detail">
|
||||
<dl class="dl-horizontal">
|
||||
<dt translate>Type</dt>
|
||||
<dd>{$ ::ctrl.healthmonitor.type $}</dd>
|
||||
<dt translate>Delay</dt>
|
||||
<dd>{$ ::ctrl.healthmonitor.delay $}</dd>
|
||||
<dt translate>Max Retries</dt>
|
||||
<dd>{$ ::ctrl.healthmonitor.max_retries $}</dd>
|
||||
<dt translate>Timeout</dt>
|
||||
<dd>{$ ::ctrl.healthmonitor.timeout $}</dd>
|
||||
<dt translate ng-if="::ctrl.healthmonitor.http_method">HTTP Method</dt>
|
||||
<dd ng-if="::ctrl.healthmonitor.http_method">{$ ::ctrl.healthmonitor.http_method $}</dd>
|
||||
<dt translate ng-if="::ctrl.healthmonitor.expected_codes">Expected Codes</dt>
|
||||
<dd ng-if="::ctrl.healthmonitor.expected_codes">{$ ::ctrl.healthmonitor.expected_codes $}</dd>
|
||||
<dt translate ng-if="::ctrl.healthmonitor.url_path">URL Path</dt>
|
||||
<dd ng-if="::ctrl.healthmonitor.url_path">{$ ::ctrl.healthmonitor.url_path $}</dd>
|
||||
<dt translate>Admin State Up</dt>
|
||||
<dd>{$ ctrl.healthmonitor.admin_state_up | yesno $}</dd>
|
||||
<dt translate>Monitor ID</dt>
|
||||
<dd>{$ ::ctrl.healthmonitor.id $}</dd>
|
||||
<dt translate>Tenant ID</dt>
|
||||
<dd>{$ ::ctrl.healthmonitor.tenant_id $}</dd>
|
||||
</dl>
|
||||
<detail-status loading="ctrl.loading" error="ctrl.error"></detail-status>
|
||||
<div ng-if="!ctrl.loading && !ctrl.error">
|
||||
<div class="page-header">
|
||||
<ol class="breadcrumb">
|
||||
<li><a href="project/ngloadbalancersv2/"><translate>Load Balancers</translate></a></li>
|
||||
<li><a href="project/ngloadbalancersv2/{$ ::ctrl.loadbalancer.id $}">{$ ::(ctrl.loadbalancer.name || ctrl.loadbalancer.id) $}</a></li>
|
||||
<li><a href="project/ngloadbalancersv2/{$ ::ctrl.loadbalancer.id $}/listeners/{$ ::ctrl.listener.id $}">{$ ::(ctrl.listener.name || ctrl.listener.id) $}</a></li>
|
||||
<li><a href="project/ngloadbalancersv2/{$ ::ctrl.loadbalancer.id $}/listeners/{$ ::ctrl.listener.id $}/pools/{$ ::ctrl.pool.id $}">{$ ::(ctrl.pool.name || ctrl.pool.id) $}</a></li>
|
||||
<li class="active">{$ ::(ctrl.healthmonitor.name || ctrl.healthmonitor.id) $}</li>
|
||||
<actions allowed="ctrl.actions" type="row" item="ctrl.healthmonitor"
|
||||
ng-if="ctrl.healthmonitor" class="actions_column pull-right"></actions>
|
||||
</ol>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6 detail">
|
||||
<dl class="dl-horizontal">
|
||||
<dt translate>Type</dt>
|
||||
<dd>{$ ::ctrl.healthmonitor.type $}</dd>
|
||||
<dt translate>Delay</dt>
|
||||
<dd>{$ ::ctrl.healthmonitor.delay $}</dd>
|
||||
<dt translate>Max Retries</dt>
|
||||
<dd>{$ ::ctrl.healthmonitor.max_retries $}</dd>
|
||||
<dt translate>Timeout</dt>
|
||||
<dd>{$ ::ctrl.healthmonitor.timeout $}</dd>
|
||||
<dt translate ng-if="::ctrl.healthmonitor.http_method">HTTP Method</dt>
|
||||
<dd ng-if="::ctrl.healthmonitor.http_method">{$ ::ctrl.healthmonitor.http_method $}</dd>
|
||||
<dt translate ng-if="::ctrl.healthmonitor.expected_codes">Expected Codes</dt>
|
||||
<dd ng-if="::ctrl.healthmonitor.expected_codes">{$ ::ctrl.healthmonitor.expected_codes $}</dd>
|
||||
<dt translate ng-if="::ctrl.healthmonitor.url_path">URL Path</dt>
|
||||
<dd ng-if="::ctrl.healthmonitor.url_path">{$ ::ctrl.healthmonitor.url_path $}</dd>
|
||||
<dt translate>Admin State Up</dt>
|
||||
<dd>{$ ctrl.healthmonitor.admin_state_up | yesno $}</dd>
|
||||
<dt translate>Monitor ID</dt>
|
||||
<dd>{$ ::ctrl.healthmonitor.id $}</dd>
|
||||
<dt translate>Tenant ID</dt>
|
||||
<dd>{$ ::ctrl.healthmonitor.tenant_id $}</dd>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -68,8 +68,9 @@
|
|||
}
|
||||
}
|
||||
|
||||
/* Progress indicator in the table while items are loading */
|
||||
[table-status] {
|
||||
/* Progress indicator while data is loading */
|
||||
[table-status],
|
||||
detail-status {
|
||||
.progress {
|
||||
margin: 0px auto;
|
||||
width: 25%;
|
||||
|
@ -78,4 +79,13 @@
|
|||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
detail-status {
|
||||
.progress {
|
||||
margin-top: 25vh;
|
||||
}
|
||||
.error-actions {
|
||||
text-align: center;
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
|
@ -23,7 +23,8 @@
|
|||
ListenerDetailController.$inject = [
|
||||
'horizon.app.core.openstack-service-api.lbaasv2',
|
||||
'horizon.dashboard.project.lbaasv2.listeners.actions.rowActions',
|
||||
'$routeParams'
|
||||
'$routeParams',
|
||||
'$q'
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -36,12 +37,15 @@
|
|||
* @param api The LBaaS v2 API service.
|
||||
* @param rowActions The listener row actions service.
|
||||
* @param $routeParams The angular $routeParams service.
|
||||
* @param $q The angular service for promises.
|
||||
* @returns undefined
|
||||
*/
|
||||
|
||||
function ListenerDetailController(api, rowActions, $routeParams) {
|
||||
function ListenerDetailController(api, rowActions, $routeParams, $q) {
|
||||
var ctrl = this;
|
||||
|
||||
ctrl.loading = true;
|
||||
ctrl.error = false;
|
||||
ctrl.actions = rowActions.init($routeParams.loadbalancerId).actions;
|
||||
|
||||
init();
|
||||
|
@ -49,16 +53,40 @@
|
|||
////////////////////////////////
|
||||
|
||||
function init() {
|
||||
api.getListener($routeParams.listenerId).success(set('listener'));
|
||||
api.getLoadBalancer($routeParams.loadbalancerId).success(set('loadbalancer'));
|
||||
ctrl.listener = null;
|
||||
ctrl.loadbalancer = null;
|
||||
ctrl.loading = true;
|
||||
ctrl.error = false;
|
||||
$q.all([
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
})();
|
||||
|
|
|
@ -17,26 +17,40 @@
|
|||
'use strict';
|
||||
|
||||
describe('LBaaS v2 Listener Detail Controller', function() {
|
||||
var lbaasv2API, ctrl;
|
||||
var lbaasv2API, $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('ListenerDetailController', {
|
||||
$routeParams: {
|
||||
loadbalancerId: 'loadbalancerId',
|
||||
listenerId: 'listenerId'
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
///////////////////////
|
||||
|
@ -48,6 +62,10 @@
|
|||
beforeEach(module('horizon.dashboard.project.lbaasv2'));
|
||||
|
||||
beforeEach(module(function($provide) {
|
||||
apiFail = false;
|
||||
qAllFail = false;
|
||||
|
||||
$provide.value('$q', { all: qAll });
|
||||
$provide.value('$uibModal', {});
|
||||
}));
|
||||
|
||||
|
@ -55,22 +73,32 @@
|
|||
lbaasv2API = $injector.get('horizon.app.core.openstack-service-api.lbaasv2');
|
||||
spyOn(lbaasv2API, 'getListener').and.callFake(fakeAPI);
|
||||
spyOn(lbaasv2API, 'getLoadBalancer').and.callFake(loadbalancerAPI);
|
||||
var controller = $injector.get('$controller');
|
||||
ctrl = controller('ListenerDetailController', {
|
||||
$routeParams: {
|
||||
loadbalancerId: 'loadbalancerId',
|
||||
listenerId: 'listenerId'
|
||||
}
|
||||
});
|
||||
$controller = $injector.get('$controller');
|
||||
}));
|
||||
|
||||
it('should invoke lbaasv2 apis', function() {
|
||||
var ctrl = createController();
|
||||
expect(lbaasv2API.getListener).toHaveBeenCalledWith('listenerId');
|
||||
expect(lbaasv2API.getLoadBalancer).toHaveBeenCalledWith('loadbalancerId');
|
||||
expect(ctrl.loadbalancer).toEqual({ provisioning_status: 'ACTIVE' });
|
||||
expect(ctrl.listener).toBe('foo');
|
||||
});
|
||||
|
||||
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);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
})();
|
||||
|
|
|
@ -1,39 +1,42 @@
|
|||
<div ng-controller="ListenerDetailController as ctrl">
|
||||
<div class="page-header">
|
||||
<ol class="breadcrumb">
|
||||
<li><a href="project/ngloadbalancersv2/"><translate>Load Balancers</translate></a></li>
|
||||
<li><a href="project/ngloadbalancersv2/{$ ::ctrl.loadbalancer.id $}">{$ ::(ctrl.loadbalancer.name || ctrl.loadbalancer.id) $}</a></li>
|
||||
<li class="active">{$ ::(ctrl.listener.name || ctrl.listener.id) $}</li>
|
||||
<actions allowed="ctrl.actions" type="row" item="ctrl.listener" ng-if="ctrl.listener"
|
||||
class="actions_column pull-right"></actions>
|
||||
</ol>
|
||||
<p ng-if="::ctrl.listener.description">{$ ::ctrl.listener.description $}</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6 detail">
|
||||
<dl class="dl-horizontal">
|
||||
<dt translate>Protocol</dt>
|
||||
<dd>{$ ::ctrl.listener.protocol $}</dd>
|
||||
<dt translate>Protocol Port</dt>
|
||||
<dd>{$ ::ctrl.listener.protocol_port $}</dd>
|
||||
<dt translate>Connection Limit</dt>
|
||||
<dd>{$ ctrl.listener.connection_limit | limit $}</dd>
|
||||
<dt translate>Admin State Up</dt>
|
||||
<dd>{$ ctrl.listener.admin_state_up | yesno $}</dd>
|
||||
<dt translate>Default Pool ID</dt>
|
||||
<dd>
|
||||
<a ng-href="project/ngloadbalancersv2/{$ ::ctrl.loadbalancer.id $}/listeners/{$ ::ctrl.listener.id $}/pools/{$ ::ctrl.listener.default_pool_id $}" ng-if="ctrl.listener.default_pool_id">
|
||||
{$ ::ctrl.listener.default_pool_id $}
|
||||
</a>
|
||||
<span ng-if="!ctrl.listener.default_pool_id">
|
||||
{$ 'None' | translate $}
|
||||
</span>
|
||||
</dd>
|
||||
<dt translate>Listener ID</dt>
|
||||
<dd>{$ ::ctrl.listener.id $}</dd>
|
||||
<dt translate>Tenant ID</dt>
|
||||
<dd>{$ ::ctrl.listener.tenant_id $}</dd>
|
||||
</dl>
|
||||
<detail-status loading="ctrl.loading" error="ctrl.error"></detail-status>
|
||||
<div ng-if="!ctrl.loading && !ctrl.error">
|
||||
<div class="page-header">
|
||||
<ol class="breadcrumb">
|
||||
<li><a href="project/ngloadbalancersv2/"><translate>Load Balancers</translate></a></li>
|
||||
<li><a href="project/ngloadbalancersv2/{$ ::ctrl.loadbalancer.id $}">{$ ::(ctrl.loadbalancer.name || ctrl.loadbalancer.id) $}</a></li>
|
||||
<li class="active">{$ ::(ctrl.listener.name || ctrl.listener.id) $}</li>
|
||||
<actions allowed="ctrl.actions" type="row" item="ctrl.listener" ng-if="ctrl.listener"
|
||||
class="actions_column pull-right"></actions>
|
||||
</ol>
|
||||
<p ng-if="::ctrl.listener.description">{$ ::ctrl.listener.description $}</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6 detail">
|
||||
<dl class="dl-horizontal">
|
||||
<dt translate>Protocol</dt>
|
||||
<dd>{$ ::ctrl.listener.protocol $}</dd>
|
||||
<dt translate>Protocol Port</dt>
|
||||
<dd>{$ ::ctrl.listener.protocol_port $}</dd>
|
||||
<dt translate>Connection Limit</dt>
|
||||
<dd>{$ ctrl.listener.connection_limit | limit $}</dd>
|
||||
<dt translate>Admin State Up</dt>
|
||||
<dd>{$ ctrl.listener.admin_state_up | yesno $}</dd>
|
||||
<dt translate>Default Pool ID</dt>
|
||||
<dd>
|
||||
<a ng-href="project/ngloadbalancersv2/{$ ::ctrl.loadbalancer.id $}/listeners/{$ ::ctrl.listener.id $}/pools/{$ ::ctrl.listener.default_pool_id $}" ng-if="ctrl.listener.default_pool_id">
|
||||
{$ ::ctrl.listener.default_pool_id $}
|
||||
</a>
|
||||
<span ng-if="!ctrl.listener.default_pool_id">
|
||||
{$ 'None' | translate $}
|
||||
</span>
|
||||
</dd>
|
||||
<dt translate>Listener ID</dt>
|
||||
<dd>{$ ::ctrl.listener.id $}</dd>
|
||||
<dt translate>Tenant ID</dt>
|
||||
<dd>{$ ::ctrl.listener.tenant_id $}</dd>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -50,6 +50,8 @@
|
|||
) {
|
||||
var ctrl = this;
|
||||
|
||||
ctrl.loading = true;
|
||||
ctrl.error = false;
|
||||
ctrl.actions = rowActions.actions;
|
||||
ctrl.operatingStatus = loadBalancersService.operatingStatus;
|
||||
ctrl.provisioningStatus = loadBalancersService.provisioningStatus;
|
||||
|
@ -60,11 +62,21 @@
|
|||
////////////////////////////////
|
||||
|
||||
function init() {
|
||||
api.getLoadBalancer($routeParams.loadbalancerId, true).success(success);
|
||||
ctrl.loadbalancer = null;
|
||||
ctrl.loading = true;
|
||||
ctrl.error = false;
|
||||
api.getLoadBalancer($routeParams.loadbalancerId, true).then(success, fail);
|
||||
}
|
||||
|
||||
function success(response) {
|
||||
ctrl.loadbalancer = response;
|
||||
ctrl.loadbalancer = response.data;
|
||||
ctrl.loading = false;
|
||||
}
|
||||
|
||||
function fail(/*response*/) {
|
||||
ctrl.loadbalancer = null;
|
||||
ctrl.loading = false;
|
||||
ctrl.error = true;
|
||||
}
|
||||
|
||||
// Save the active state of the listeners tab in the global window object so it can stay
|
||||
|
|
|
@ -17,16 +17,28 @@
|
|||
'use strict';
|
||||
|
||||
describe('LBaaS v2 Load Balancer Detail Controller', function() {
|
||||
var lbaasv2API, ctrl, $scope, $window;
|
||||
var lbaasv2API, $scope, $window, $controller, apiFail;
|
||||
|
||||
function fakeAPI() {
|
||||
return {
|
||||
success: function(callback) {
|
||||
callback({ id: '1234' });
|
||||
then: function(success, fail) {
|
||||
if (apiFail && fail) {
|
||||
fail();
|
||||
} else {
|
||||
success({ id: '1234' });
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function createController() {
|
||||
return $controller('LoadBalancerDetailController', {
|
||||
$scope: $scope,
|
||||
$window: $window,
|
||||
$routeParams: { loadbalancerId: '1234' }
|
||||
});
|
||||
}
|
||||
|
||||
///////////////////////
|
||||
|
||||
beforeEach(module('horizon.framework.widgets'));
|
||||
|
@ -36,6 +48,7 @@
|
|||
beforeEach(module('horizon.dashboard.project.lbaasv2'));
|
||||
|
||||
beforeEach(module(function($provide) {
|
||||
apiFail = false;
|
||||
$provide.value('$uibModal', {});
|
||||
}));
|
||||
|
||||
|
@ -44,19 +57,16 @@
|
|||
spyOn(lbaasv2API, 'getLoadBalancer').and.callFake(fakeAPI);
|
||||
$scope = $injector.get('$rootScope').$new();
|
||||
$window = {};
|
||||
var controller = $injector.get('$controller');
|
||||
ctrl = controller('LoadBalancerDetailController', {
|
||||
$scope: $scope,
|
||||
$window: $window,
|
||||
$routeParams: { loadbalancerId: '1234' }
|
||||
});
|
||||
$controller = $injector.get('$controller');
|
||||
}));
|
||||
|
||||
it('should invoke lbaasv2 apis', function() {
|
||||
createController();
|
||||
expect(lbaasv2API.getLoadBalancer).toHaveBeenCalledWith('1234', true);
|
||||
});
|
||||
|
||||
it('should save changes to listeners tab active state', function() {
|
||||
var ctrl = createController();
|
||||
expect($window.listenersTabActive).toBeUndefined();
|
||||
expect(ctrl.listenersTabActive).toBeUndefined();
|
||||
ctrl.listenersTabActive = true;
|
||||
|
@ -67,6 +77,13 @@
|
|||
expect($window.listenersTabActive).toBe(false);
|
||||
});
|
||||
|
||||
it('should set error state', function() {
|
||||
apiFail = true;
|
||||
var ctrl = createController();
|
||||
expect(ctrl.loading).toBe(false);
|
||||
expect(ctrl.error).toBe(true);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
})();
|
||||
|
|
|
@ -1,54 +1,57 @@
|
|||
<div ng-controller="LoadBalancerDetailController as ctrl">
|
||||
<div class="page-header">
|
||||
<ol class="breadcrumb">
|
||||
<li><a href="project/ngloadbalancersv2/"><translate>Load Balancers</translate></a></li>
|
||||
<li class="active">{$ ctrl.loadbalancer.name || ctrl.loadbalancer.id $}</li>
|
||||
<actions allowed="ctrl.actions" type="row" item="ctrl.loadbalancer"
|
||||
ng-if="ctrl.loadbalancer" class="actions_column pull-right"></actions>
|
||||
</ol>
|
||||
<p ng-if="::ctrl.loadbalancer.description">{$ ::ctrl.loadbalancer.description $}</p>
|
||||
<ul class="list-inline">
|
||||
<li>
|
||||
<strong translate>IP Address</strong>
|
||||
{$ ::ctrl.loadbalancer.vip_address $}
|
||||
</li>
|
||||
<li>
|
||||
<strong translate>Operating Status</strong>
|
||||
{$ ctrl.loadbalancer.operating_status | decode:ctrl.operatingStatus $}
|
||||
</li>
|
||||
<li>
|
||||
<strong translate>Provisioning Status</strong>
|
||||
{$ ctrl.loadbalancer.provisioning_status | decode:ctrl.provisioningStatus $}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<tabset>
|
||||
<tab heading="{$ 'Overview' | translate $}">
|
||||
<div class="row">
|
||||
<div class="col-md-6 detail">
|
||||
<dl class="dl-horizontal">
|
||||
<dt translate>Provider</dt>
|
||||
<dd>{$ ::ctrl.loadbalancer.provider $}</dd>
|
||||
<dt translate>Admin State Up</dt>
|
||||
<dd>{$ ctrl.loadbalancer.admin_state_up | yesno $}</dd>
|
||||
<dt translate ng-if="ctrl.loadbalancer.floating_ip !== undefined">Floating IP Address</dt>
|
||||
<dd ng-if="ctrl.loadbalancer.floating_ip !== undefined">{$ ctrl.loadbalancer.floating_ip.ip | noValue:('None' | translate) $}</dd>
|
||||
<dt translate>Load Balancer ID</dt>
|
||||
<dd>{$ ::ctrl.loadbalancer.id $}</dd>
|
||||
<dt translate>Subnet ID</dt>
|
||||
<dd>
|
||||
<a target="_self" ng-href="project/networks/subnets/{$ ::ctrl.loadbalancer.vip_subnet_id $}/detail">{$ ::ctrl.loadbalancer.vip_subnet_id $}</a>
|
||||
</dd>
|
||||
<dt translate>Port ID</dt>
|
||||
<dd>
|
||||
<a target="_self" ng-href="project/networks/ports/{$ ::ctrl.loadbalancer.vip_port_id $}/detail">{$ ::ctrl.loadbalancer.vip_port_id $}</a>
|
||||
</dd>
|
||||
</dl>
|
||||
<detail-status loading="ctrl.loading" error="ctrl.error"></detail-status>
|
||||
<div ng-if="!ctrl.loading && !ctrl.error">
|
||||
<div class="page-header">
|
||||
<ol class="breadcrumb">
|
||||
<li><a href="project/ngloadbalancersv2/"><translate>Load Balancers</translate></a></li>
|
||||
<li class="active">{$ ctrl.loadbalancer.name || ctrl.loadbalancer.id $}</li>
|
||||
<actions allowed="ctrl.actions" type="row" item="ctrl.loadbalancer"
|
||||
ng-if="ctrl.loadbalancer" class="actions_column pull-right"></actions>
|
||||
</ol>
|
||||
<p ng-if="::ctrl.loadbalancer.description">{$ ::ctrl.loadbalancer.description $}</p>
|
||||
<ul class="list-inline">
|
||||
<li>
|
||||
<strong translate>IP Address</strong>
|
||||
{$ ::ctrl.loadbalancer.vip_address $}
|
||||
</li>
|
||||
<li>
|
||||
<strong translate>Operating Status</strong>
|
||||
{$ ctrl.loadbalancer.operating_status | decode:ctrl.operatingStatus $}
|
||||
</li>
|
||||
<li>
|
||||
<strong translate>Provisioning Status</strong>
|
||||
{$ ctrl.loadbalancer.provisioning_status | decode:ctrl.provisioningStatus $}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<tabset>
|
||||
<tab heading="{$ 'Overview' | translate $}">
|
||||
<div class="row">
|
||||
<div class="col-md-6 detail">
|
||||
<dl class="dl-horizontal">
|
||||
<dt translate>Provider</dt>
|
||||
<dd>{$ ::ctrl.loadbalancer.provider $}</dd>
|
||||
<dt translate>Admin State Up</dt>
|
||||
<dd>{$ ctrl.loadbalancer.admin_state_up | yesno $}</dd>
|
||||
<dt translate ng-if="ctrl.loadbalancer.floating_ip !== undefined">Floating IP Address</dt>
|
||||
<dd ng-if="ctrl.loadbalancer.floating_ip !== undefined">{$ ctrl.loadbalancer.floating_ip.ip | noValue:('None' | translate) $}</dd>
|
||||
<dt translate>Load Balancer ID</dt>
|
||||
<dd>{$ ::ctrl.loadbalancer.id $}</dd>
|
||||
<dt translate>Subnet ID</dt>
|
||||
<dd>
|
||||
<a target="_self" ng-href="project/networks/subnets/{$ ::ctrl.loadbalancer.vip_subnet_id $}/detail">{$ ::ctrl.loadbalancer.vip_subnet_id $}</a>
|
||||
</dd>
|
||||
<dt translate>Port ID</dt>
|
||||
<dd>
|
||||
<a target="_self" ng-href="project/networks/ports/{$ ::ctrl.loadbalancer.vip_port_id $}/detail">{$ ::ctrl.loadbalancer.vip_port_id $}</a>
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</tab>
|
||||
<tab heading="{$ 'Listeners' | translate $}" active="ctrl.listenersTabActive">
|
||||
<ng-include src="'static/dashboard/project/lbaasv2/listeners/table.html'"></ng-include>
|
||||
</tab>
|
||||
</tabset>
|
||||
</tab>
|
||||
<tab heading="{$ 'Listeners' | translate $}" active="ctrl.listenersTabActive">
|
||||
<ng-include src="'static/dashboard/project/lbaasv2/listeners/table.html'"></ng-include>
|
||||
</tab>
|
||||
</tabset>
|
||||
</div>
|
||||
</div>
|
|
@ -24,6 +24,7 @@
|
|||
'horizon.app.core.openstack-service-api.lbaasv2',
|
||||
'horizon.dashboard.project.lbaasv2.members.actions.rowActions',
|
||||
'$routeParams',
|
||||
'$q',
|
||||
'horizon.dashboard.project.lbaasv2.loadbalancers.service',
|
||||
'horizon.dashboard.project.lbaasv2.members.service'
|
||||
];
|
||||
|
@ -38,16 +39,19 @@
|
|||
* @param api The LBaaS v2 API service.
|
||||
* @param rowActions The pool members row actions service.
|
||||
* @param $routeParams The angular $routeParams service.
|
||||
* @param $q The angular service for promises.
|
||||
* @param loadBalancersService The LBaaS v2 load balancers service.
|
||||
* @param membersService The LBaaS v2 members service.
|
||||
* @returns undefined
|
||||
*/
|
||||
|
||||
function MemberDetailController(
|
||||
api, rowActions, $routeParams, loadBalancersService, membersService
|
||||
api, rowActions, $routeParams, $q, loadBalancersService, membersService
|
||||
) {
|
||||
var ctrl = this;
|
||||
|
||||
ctrl.loading = true;
|
||||
ctrl.error = false;
|
||||
ctrl.actions = rowActions.init($routeParams.loadbalancerId, $routeParams.poolId).actions;
|
||||
ctrl.loadbalancerId = $routeParams.loadbalancerId;
|
||||
ctrl.listenerId = $routeParams.listenerId;
|
||||
|
@ -60,25 +64,53 @@
|
|||
////////////////////////////////
|
||||
|
||||
function init() {
|
||||
api.getMember($routeParams.poolId, $routeParams.memberId).success(memberSuccess);
|
||||
api.getPool($routeParams.poolId).success(set('pool'));
|
||||
api.getListener($routeParams.listenerId).success(set('listener'));
|
||||
api.getLoadBalancer($routeParams.loadbalancerId).success(set('loadbalancer'));
|
||||
ctrl.member = null;
|
||||
ctrl.pool = null;
|
||||
ctrl.listener = null;
|
||||
ctrl.loadbalancer = null;
|
||||
ctrl.loading = true;
|
||||
ctrl.error = false;
|
||||
$q.all([
|
||||
api.getMember($routeParams.poolId, $routeParams.memberId)
|
||||
.then(success('member'), fail('member')),
|
||||
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;
|
||||
|
||||
if (property === 'member') {
|
||||
membersService.associateMemberStatuses(
|
||||
ctrl.loadbalancerId,
|
||||
ctrl.listenerId,
|
||||
ctrl.poolId,
|
||||
[ctrl.member]);
|
||||
}
|
||||
|
||||
}, property);
|
||||
}
|
||||
|
||||
function memberSuccess(response) {
|
||||
ctrl.member = response;
|
||||
membersService.associateMemberStatuses(
|
||||
ctrl.loadbalancerId,
|
||||
ctrl.listenerId,
|
||||
ctrl.poolId,
|
||||
[ctrl.member]);
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,26 +17,42 @@
|
|||
'use strict';
|
||||
|
||||
describe('LBaaS v2 Member Detail Controller', function() {
|
||||
var controller, lbaasv2API, membersService, ctrl, actions;
|
||||
var $controller, lbaasv2API, membersService, apiFail, qAllFail, actions;
|
||||
|
||||
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('MemberDetailController', {
|
||||
$routeParams: {
|
||||
loadbalancerId: 'loadbalancerId',
|
||||
listenerId: 'listenerId',
|
||||
poolId: 'poolId',
|
||||
memberId: 'memberId'
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
///////////////////////
|
||||
|
@ -48,6 +64,10 @@
|
|||
beforeEach(module('horizon.dashboard.project.lbaasv2'));
|
||||
|
||||
beforeEach(module(function($provide) {
|
||||
apiFail = false;
|
||||
qAllFail = false;
|
||||
|
||||
$provide.value('$q', { all: qAll });
|
||||
$provide.value('$uibModal', {});
|
||||
$provide.value('horizon.dashboard.project.lbaasv2.members.actions.rowActions', {
|
||||
init: function() {
|
||||
|
@ -68,25 +88,15 @@
|
|||
spyOn(lbaasv2API, 'getLoadBalancer').and.callFake(loadbalancerAPI);
|
||||
spyOn(actions, 'init').and.callThrough();
|
||||
spyOn(membersService, 'associateMemberStatuses');
|
||||
controller = $injector.get('$controller');
|
||||
ctrl = controller('MemberDetailController', {
|
||||
$routeParams: {
|
||||
loadbalancerId: 'loadbalancerId',
|
||||
listenerId: 'listenerId',
|
||||
poolId: 'poolId',
|
||||
memberId: 'memberId'
|
||||
}
|
||||
});
|
||||
$controller = $injector.get('$controller');
|
||||
}));
|
||||
|
||||
it('should invoke lbaasv2 apis', function() {
|
||||
var ctrl = createController();
|
||||
expect(lbaasv2API.getMember).toHaveBeenCalledWith('poolId','memberId');
|
||||
expect(lbaasv2API.getPool).toHaveBeenCalledWith('poolId');
|
||||
expect(lbaasv2API.getListener).toHaveBeenCalledWith('listenerId');
|
||||
expect(lbaasv2API.getLoadBalancer).toHaveBeenCalledWith('loadbalancerId');
|
||||
});
|
||||
|
||||
it('should initialize the controller properties correctly', function() {
|
||||
expect(ctrl.loadbalancerId).toBeDefined();
|
||||
expect(ctrl.listenerId).toBeDefined();
|
||||
expect(ctrl.poolId).toBeDefined();
|
||||
|
@ -97,10 +107,26 @@
|
|||
});
|
||||
|
||||
it('should invoke the "associateMemberStatuses" method', function() {
|
||||
var ctrl = createController();
|
||||
expect(membersService.associateMemberStatuses).toHaveBeenCalledWith(
|
||||
ctrl.loadbalancerId, ctrl.listenerId, ctrl.poolId, [ctrl.member]);
|
||||
});
|
||||
|
||||
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);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
})();
|
||||
|
|
|
@ -1,35 +1,38 @@
|
|||
<div ng-controller="MemberDetailController as ctrl">
|
||||
<div class="page-header">
|
||||
<ol class="breadcrumb">
|
||||
<li><a href="project/ngloadbalancersv2/"><translate>Load Balancers</translate></a></li>
|
||||
<li><a href="project/ngloadbalancersv2/{$ ::ctrl.loadbalancer.id $}">{$ ::(ctrl.loadbalancer.name || ctrl.loadbalancer.id) $}</a></li>
|
||||
<li><a href="project/ngloadbalancersv2/{$ ::ctrl.loadbalancer.id $}/listeners/{$ ::ctrl.listener.id $}">{$ ::(ctrl.listener.name || ctrl.listener.id) $}</a></li>
|
||||
<li><a href="project/ngloadbalancersv2/{$ ::ctrl.loadbalancer.id $}/listeners/{$ ::ctrl.listener.id $}/pools/{$ ::ctrl.pool.id $}">{$ ::(ctrl.pool.name || ctrl.pool.id) $}</a></li>
|
||||
<li class="active">{$ ::(ctrl.member.name || ctrl.member.id) $}</li>
|
||||
<actions allowed="ctrl.actions" type="row" item="ctrl.member"
|
||||
ng-if="ctrl.member" class="actions_column pull-right"></actions>
|
||||
</ol>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6 detail">
|
||||
<dl class="dl-horizontal">
|
||||
<dt translate>Address</dt>
|
||||
<dd>{$ ::ctrl.member.address $}</dd>
|
||||
<dt translate>Protocol Port</dt>
|
||||
<dd>{$ ::ctrl.member.protocol_port $}</dd>
|
||||
<dt translate>Weight</dt>
|
||||
<dd>{$ ctrl.member.weight $}</dd>
|
||||
<dt translate>Operating Status</dt>
|
||||
<dd>{$ ctrl.member.operating_status | decode:ctrl.operatingStatus $}</dd>
|
||||
<dt translate>Provisioning Status</dt>
|
||||
<dd>{$ ctrl.member.provisioning_status | decode:ctrl.provisioningStatus $}</dd>
|
||||
<dt translate>Admin State Up</dt>
|
||||
<dd>{$ ctrl.member.admin_state_up | yesno $}</dd>
|
||||
<dt translate>Member ID</dt>
|
||||
<dd>{$ ::ctrl.member.id $}</dd>
|
||||
<dt translate>Tenant ID</dt>
|
||||
<dd>{$ ::ctrl.member.tenant_id $}</dd>
|
||||
</dl>
|
||||
<detail-status loading="ctrl.loading" error="ctrl.error"></detail-status>
|
||||
<div ng-if="!ctrl.loading && !ctrl.error">
|
||||
<div class="page-header">
|
||||
<ol class="breadcrumb">
|
||||
<li><a href="project/ngloadbalancersv2/"><translate>Load Balancers</translate></a></li>
|
||||
<li><a href="project/ngloadbalancersv2/{$ ::ctrl.loadbalancer.id $}">{$ ::(ctrl.loadbalancer.name || ctrl.loadbalancer.id) $}</a></li>
|
||||
<li><a href="project/ngloadbalancersv2/{$ ::ctrl.loadbalancer.id $}/listeners/{$ ::ctrl.listener.id $}">{$ ::(ctrl.listener.name || ctrl.listener.id) $}</a></li>
|
||||
<li><a href="project/ngloadbalancersv2/{$ ::ctrl.loadbalancer.id $}/listeners/{$ ::ctrl.listener.id $}/pools/{$ ::ctrl.pool.id $}">{$ ::(ctrl.pool.name || ctrl.pool.id) $}</a></li>
|
||||
<li class="active">{$ ::(ctrl.member.name || ctrl.member.id) $}</li>
|
||||
<actions allowed="ctrl.actions" type="row" item="ctrl.member"
|
||||
ng-if="ctrl.member" class="actions_column pull-right"></actions>
|
||||
</ol>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6 detail">
|
||||
<dl class="dl-horizontal">
|
||||
<dt translate>Address</dt>
|
||||
<dd>{$ ::ctrl.member.address $}</dd>
|
||||
<dt translate>Protocol Port</dt>
|
||||
<dd>{$ ::ctrl.member.protocol_port $}</dd>
|
||||
<dt translate>Weight</dt>
|
||||
<dd>{$ ctrl.member.weight $}</dd>
|
||||
<dt translate>Operating Status</dt>
|
||||
<dd>{$ ctrl.member.operating_status | decode:ctrl.operatingStatus $}</dd>
|
||||
<dt translate>Provisioning Status</dt>
|
||||
<dd>{$ ctrl.member.provisioning_status | decode:ctrl.provisioningStatus $}</dd>
|
||||
<dt translate>Admin State Up</dt>
|
||||
<dd>{$ ctrl.member.admin_state_up | yesno $}</dd>
|
||||
<dt translate>Member ID</dt>
|
||||
<dd>{$ ::ctrl.member.id $}</dd>
|
||||
<dt translate>Tenant ID</dt>
|
||||
<dd>{$ ::ctrl.member.tenant_id $}</dd>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
})();
|
||||
|
|
|
@ -1,47 +1,50 @@
|
|||
<div ng-controller="PoolDetailController as ctrl">
|
||||
<div class="page-header">
|
||||
<ol class="breadcrumb">
|
||||
<li><a href="project/ngloadbalancersv2/"><translate>Load Balancers</translate></a></li>
|
||||
<li><a href="project/ngloadbalancersv2/{$ ::ctrl.loadbalancer.id $}">{$ ::(ctrl.loadbalancer.name || ctrl.loadbalancer.id) $}</a></li>
|
||||
<li><a href="project/ngloadbalancersv2/{$ ::ctrl.loadbalancer.id $}/listeners/{$ ::ctrl.listener.id $}">{$ ::(ctrl.listener.name || ctrl.listener.id) $}</a></li>
|
||||
<li class="active">{$ ::(ctrl.pool.name || ctrl.pool.id) $}</li>
|
||||
<actions allowed="ctrl.actions" type="row" item="ctrl.pool"
|
||||
ng-if="ctrl.pool" class="actions_column pull-right"></actions>
|
||||
</ol>
|
||||
<p ng-if="::ctrl.pool.description">{$ ::ctrl.pool.description $}</p>
|
||||
</div>
|
||||
<tabset>
|
||||
<tab heading="{$ 'Overview' | translate $}">
|
||||
<div class="row">
|
||||
<div class="col-md-6 detail">
|
||||
<dl class="dl-horizontal">
|
||||
<dt translate>Protocol</dt>
|
||||
<dd>{$ ::ctrl.pool.protocol $}</dd>
|
||||
<dt translate>Load Balancer Algorithm</dt>
|
||||
<dd>{$ ctrl.pool.lb_algorithm | decode:ctrl.loadBalancerAlgorithm $}</dd>
|
||||
<dt translate>Session Persistence</dt>
|
||||
<dd>{$ ctrl.pool.session_persistence | noValue:('None' | translate) $}</dd>
|
||||
<dt translate>Admin State Up</dt>
|
||||
<dd>{$ ctrl.pool.admin_state_up | yesno $}</dd>
|
||||
<dt translate>Health Monitor ID</dt>
|
||||
<dd>
|
||||
<a ng-href="project/ngloadbalancersv2/{$ ::ctrl.loadbalancer.id $}/listeners/{$ ::ctrl.listener.id $}/pools/{$ ::ctrl.pool.id $}/healthmonitors/{$ ::ctrl.pool.healthmonitor_id $}" ng-if="ctrl.pool.healthmonitor_id">
|
||||
{$ ::ctrl.pool.healthmonitor_id $}
|
||||
</a>
|
||||
<span ng-if="!ctrl.pool.healthmonitor_id">
|
||||
{$ 'None' | translate $}
|
||||
</span>
|
||||
</dd>
|
||||
<dt translate>Pool ID</dt>
|
||||
<dd>{$ ::ctrl.pool.id $}</dd>
|
||||
<dt translate>Tenant ID</dt>
|
||||
<dd>{$ ::ctrl.pool.tenant_id $}</dd>
|
||||
</dl>
|
||||
<detail-status loading="ctrl.loading" error="ctrl.error"></detail-status>
|
||||
<div ng-if="!ctrl.loading && !ctrl.error">
|
||||
<div class="page-header">
|
||||
<ol class="breadcrumb">
|
||||
<li><a href="project/ngloadbalancersv2/"><translate>Load Balancers</translate></a></li>
|
||||
<li><a href="project/ngloadbalancersv2/{$ ::ctrl.loadbalancer.id $}">{$ ::(ctrl.loadbalancer.name || ctrl.loadbalancer.id) $}</a></li>
|
||||
<li><a href="project/ngloadbalancersv2/{$ ::ctrl.loadbalancer.id $}/listeners/{$ ::ctrl.listener.id $}">{$ ::(ctrl.listener.name || ctrl.listener.id) $}</a></li>
|
||||
<li class="active">{$ ::(ctrl.pool.name || ctrl.pool.id) $}</li>
|
||||
<actions allowed="ctrl.actions" type="row" item="ctrl.pool"
|
||||
ng-if="ctrl.pool" class="actions_column pull-right"></actions>
|
||||
</ol>
|
||||
<p ng-if="::ctrl.pool.description">{$ ::ctrl.pool.description $}</p>
|
||||
</div>
|
||||
<tabset>
|
||||
<tab heading="{$ 'Overview' | translate $}">
|
||||
<div class="row">
|
||||
<div class="col-md-6 detail">
|
||||
<dl class="dl-horizontal">
|
||||
<dt translate>Protocol</dt>
|
||||
<dd>{$ ::ctrl.pool.protocol $}</dd>
|
||||
<dt translate>Load Balancer Algorithm</dt>
|
||||
<dd>{$ ctrl.pool.lb_algorithm | decode:ctrl.loadBalancerAlgorithm $}</dd>
|
||||
<dt translate>Session Persistence</dt>
|
||||
<dd>{$ ctrl.pool.session_persistence | noValue:('None' | translate) $}</dd>
|
||||
<dt translate>Admin State Up</dt>
|
||||
<dd>{$ ctrl.pool.admin_state_up | yesno $}</dd>
|
||||
<dt translate>Health Monitor ID</dt>
|
||||
<dd>
|
||||
<a ng-href="project/ngloadbalancersv2/{$ ::ctrl.loadbalancer.id $}/listeners/{$ ::ctrl.listener.id $}/pools/{$ ::ctrl.pool.id $}/healthmonitors/{$ ::ctrl.pool.healthmonitor_id $}" ng-if="ctrl.pool.healthmonitor_id">
|
||||
{$ ::ctrl.pool.healthmonitor_id $}
|
||||
</a>
|
||||
<span ng-if="!ctrl.pool.healthmonitor_id">
|
||||
{$ 'None' | translate $}
|
||||
</span>
|
||||
</dd>
|
||||
<dt translate>Pool ID</dt>
|
||||
<dd>{$ ::ctrl.pool.id $}</dd>
|
||||
<dt translate>Tenant ID</dt>
|
||||
<dd>{$ ::ctrl.pool.tenant_id $}</dd>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</tab>
|
||||
<tab heading="{$ 'Members' | translate $}" active="ctrl.membersTabActive">
|
||||
<ng-include src="'static/dashboard/project/lbaasv2/members/table.html'"></ng-include>
|
||||
</tab>
|
||||
</tabset>
|
||||
</tab>
|
||||
<tab heading="{$ 'Members' | translate $}" active="ctrl.membersTabActive">
|
||||
<ng-include src="'static/dashboard/project/lbaasv2/members/table.html'"></ng-include>
|
||||
</tab>
|
||||
</tabset>
|
||||
</div>
|
||||
</div>
|
|
@ -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
|
||||
* ```
|
||||
* <detail-status loading="ctrl.loading" error="ctrl.error"></detail-status>
|
||||
* ```
|
||||
*/
|
||||
|
||||
function detailStatus(basePath) {
|
||||
var directive = {
|
||||
restrict: 'E',
|
||||
templateUrl: basePath + 'widgets/detail/detail-status.html',
|
||||
scope: {
|
||||
loading: '=',
|
||||
error: '='
|
||||
}
|
||||
};
|
||||
return directive;
|
||||
}
|
||||
}());
|
|
@ -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 = '<detail-status loading="ctrl.loading" error="ctrl.error"></detail-status>';
|
||||
}));
|
||||
|
||||
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);
|
||||
});
|
||||
|
||||
});
|
||||
}());
|
|
@ -0,0 +1,12 @@
|
|||
<div ng-if="loading || error">
|
||||
<div class="progress">
|
||||
<div class="progress-bar" role="progressbar"
|
||||
ng-class="{ 'progress-bar-striped active': !error, 'progress-bar-danger': error }">
|
||||
<span ng-if="!error" class="sr-only" translate>Loading</span>
|
||||
<span ng-if="error" translate>An error occurred. Please try again later.</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="error-actions" ng-if="error">
|
||||
<a href="javascript:window.history.back();" translate>Back</a>
|
||||
</div>
|
||||
</div>
|
Loading…
Reference in New Issue