Allow detail pages to auto refresh upon action

Change-Id: I9740399b03cd6192be7e6d2b969650687e97bd75
Depends-On: https://review.openstack.org/#/c/561457/
Story: 1713841
Task: 5218
This commit is contained in:
Jacky Hu 2018-04-15 20:10:48 +08:00
parent c1888b9faa
commit bb0cb86451
29 changed files with 663 additions and 43 deletions

View File

@ -22,6 +22,9 @@
.controller('HealthMonitorDetailController', HealthMonitorDetailController);
HealthMonitorDetailController.$inject = [
'$timeout',
'horizon.dashboard.project.lbaasv2.events',
'$scope',
'loadbalancer',
'listener',
'pool',
@ -40,6 +43,9 @@
* @description
* Controller for the LBaaS v2 health monitor detail page.
*
* @param $timeout The angular timeout object.
* @param events The LBaaS v2 events object.
* @param $scope The angular scope object.
* @param loadbalancer The loadbalancer object.
* @param listener The listener object.
* @param pool The pool object.
@ -54,7 +60,8 @@
*/
function HealthMonitorDetailController(
loadbalancer, listener, pool, healthmonitor, loadBalancersService,
$timeout, events,
$scope, loadbalancer, listener, pool, healthmonitor, loadBalancersService,
resourceType, typeRegistry, spinnerService, $q
) {
var ctrl = this;
@ -78,6 +85,33 @@
ctrl.resultHandler = actionResultHandler;
$scope.$watch(
function() {
return ctrl.healthmonitor;
},
function() {
$timeout.cancel($scope.loadTimeout);
$scope.loadTimeout = $timeout(function() {
ctrl.context.loadPromise = ctrl.resourceType.load(ctrl.context.identifier);
ctrl.context.loadPromise.then(loadData);
}, loadBalancersService.backoff.duration());
}
);
$scope.$on(
events.ACTION_DONE,
function() {
loadBalancersService.backoff.reset();
}
);
$scope.$on(
'$destroy',
function() {
$timeout.cancel($scope.loadTimeout);
}
);
function actionResultHandler(returnValue) {
return $q.when(returnValue, actionSuccessHandler);
}

View File

@ -52,7 +52,7 @@
loadbalancer: { id: '123' },
listener: {},
pool: { id: '123' },
healthmonitor: { id: '123' },
healthmonitor: { id: '123', provisioning_status: 'ACTIVE' },
'horizon.framework.conf.resource-type-registry.service': service,
'horizon.framework.util.actions.action-result.service': actionResultService,
'horizon.framework.widgets.modal-wait-spinner.service': {
@ -65,7 +65,7 @@
loadbalancer: { id: '123' },
listener: { id: '123' },
pool: { id: '123' },
healthmonitor: { id: '123' },
healthmonitor: { id: '123', provisioning_status: 'ACTIVE' },
'horizon.framework.conf.resource-type-registry.service': service,
'horizon.framework.util.actions.action-result.service': actionResultService,
'horizon.framework.widgets.modal-wait-spinner.service': {
@ -83,6 +83,30 @@
expect(ctrl.healthmonitor).toBeDefined();
});
describe('data watchers', function() {
var events, loadBalancersService;
beforeEach(inject(function($injector) {
events = $injector.get('horizon.dashboard.project.lbaasv2.events');
loadBalancersService = $injector.get(
'horizon.dashboard.project.lbaasv2.loadbalancers.service'
);
}));
it('should refresh on provisioning status change', function() {
var loadFunctionDeferred = $q.defer();
spyOn(ctrl.resourceType, 'load').and.returnValue(loadFunctionDeferred.promise);
ctrl.healthmonitor = { id: '123', provisioning_status: 'PENDING_UPDATE' };
scope.$apply();
$timeout.flush();
expect(ctrl.resourceType.load).toHaveBeenCalled();
spyOn(loadBalancersService.backoff, 'reset').and.callThrough();
scope.$broadcast(events.ACTION_DONE);
expect(loadBalancersService.backoff.reset).toHaveBeenCalled();
});
});
describe('resultHandler', function() {
it('handles empty results', function() {

View File

@ -7,7 +7,7 @@
<li class="breadcrumb-item-truncate" ng-style="ctrl.withListenerStyle"><a href="project/load_balancer/{$ ::ctrl.loadbalancer.id $}/listeners/{$ :: ctrl.listener.id $}">{$ :: (ctrl.listener.name || ctrl.listener.id) $}</a></li>
<li class="breadcrumb-item-truncate" ng-style="ctrl.withListenerStyle"><a href="project/load_balancer/{$ ::ctrl.loadbalancer.id $}/listeners/{$ :: ctrl.listener.id $}/pools/{$ ::ctrl.pool.id $}">{$ ::(ctrl.pool.name || ctrl.pool.id) $}</a></li>
<li class="breadcrumb-item-truncate" ng-style="ctrl.withoutListenerStyle"><a href="project/load_balancer/{$ ::ctrl.loadbalancer.id $}/pools/{$ ::ctrl.pool.id $}">{$ ::(ctrl.pool.name || ctrl.pool.id) $}</a></li>
<li class="breadcrumb-item-truncate active">{$ ::(ctrl.healthmonitor.name || ctrl.healthmonitor.id) $}</li>
<li class="breadcrumb-item-truncate active">{$ (ctrl.healthmonitor.name || ctrl.healthmonitor.id) $}</li>
</ol>
<div class="row">
<div class="col-xs-12 col-sm-9 text-left">

View File

@ -21,6 +21,9 @@
.controller('L7PolicyDetailController', L7PolicyDetailController);
L7PolicyDetailController.$inject = [
'$timeout',
'horizon.dashboard.project.lbaasv2.events',
'$scope',
'loadbalancer',
'listener',
'l7policy',
@ -38,6 +41,9 @@
* @description
* Controller for the LBaaS v2 l7policy detail page.
*
* @param $timeout The angular timeout object.
* @param events The LBaaS v2 events object.
* @param $scope The angular scope object.
* @param loadbalancer The loadbalancer object.
* @param listener The listener object.
* @param l7policy The l7policy object.
@ -51,7 +57,8 @@
*/
function L7PolicyDetailController(
loadbalancer, listener, l7policy, loadBalancersService,
$timeout, events,
$scope, loadbalancer, listener, l7policy, loadBalancersService,
resourceType, typeRegistry, spinnerService, $q
) {
var ctrl = this;
@ -73,6 +80,34 @@
ctrl.resultHandler = actionResultHandler;
$scope.$watch(
function() {
return ctrl.l7policy;
},
function() {
$timeout.cancel($scope.loadTimeout);
$scope.loadTimeout = $timeout(function() {
ctrl.context.loadPromise = ctrl.resourceType.load(ctrl.context.identifier);
ctrl.context.loadPromise.then(loadData);
}, loadBalancersService.backoff.duration());
}
);
$scope.$on(
events.ACTION_DONE,
function() {
loadBalancersService.backoff.reset();
ctrl.l7policy = angular.copy(ctrl.l7policy);
}
);
$scope.$on(
'$destroy',
function() {
$timeout.cancel($scope.loadTimeout);
}
);
function actionResultHandler(returnValue) {
return $q.when(returnValue, actionSuccessHandler);
}
@ -84,6 +119,11 @@
ctrl.l7policy = response.data;
ctrl.l7policy.loadbalancerId = ctrl.loadbalancer.id;
ctrl.l7policy.listenerId = ctrl.listener.id;
ctrl.listFunctionExtraParams = {
loadbalancerId: ctrl.loadbalancer.id,
listenerId: ctrl.listener.id,
l7policyId: ctrl.l7policy.id
};
}
function actionSuccessHandler(result) {

View File

@ -50,7 +50,7 @@
$scope: scope,
loadbalancer: { id: '123' },
listener: { id: '123' },
l7policy: { id: '123' },
l7policy: { id: '123', provisioning_status: 'ACTIVE' },
'horizon.framework.conf.resource-type-registry.service': service,
'horizon.framework.util.actions.action-result.service': actionResultService,
'horizon.framework.widgets.modal-wait-spinner.service': {
@ -67,6 +67,30 @@
expect(ctrl.l7policy).toBeDefined();
});
describe('data watchers', function() {
var events, loadBalancersService;
beforeEach(inject(function($injector) {
events = $injector.get('horizon.dashboard.project.lbaasv2.events');
loadBalancersService = $injector.get(
'horizon.dashboard.project.lbaasv2.loadbalancers.service'
);
}));
it('should refresh on provisioning status change', function() {
var loadFunctionDeferred = $q.defer();
spyOn(ctrl.resourceType, 'load').and.returnValue(loadFunctionDeferred.promise);
ctrl.l7policy = { id: '123', provisioning_status: 'PENDING_UPDATE' };
scope.$apply();
$timeout.flush();
expect(ctrl.resourceType.load).toHaveBeenCalled();
spyOn(loadBalancersService.backoff, 'reset').and.callThrough();
scope.$broadcast(events.ACTION_DONE);
expect(loadBalancersService.backoff.reset).toHaveBeenCalled();
});
});
describe('resultHandler', function() {
it('handles empty results', function() {

View File

@ -5,14 +5,14 @@
<li class="breadcrumb-item-truncate"><a href="project/load_balancer/"><translate>Load Balancers</translate></a></li>
<li class="breadcrumb-item-truncate"><a href="project/load_balancer/{$ ::ctrl.loadbalancer.id $}">{$ ::(ctrl.loadbalancer.name || ctrl.loadbalancer.id) $}</a></li>
<li class="breadcrumb-item-truncate"><a href="project/load_balancer/{$ ::ctrl.loadbalancer.id $}/listeners/{$ ::ctrl.listener.id $}">{$ ::(ctrl.listener.name || ctrl.listener.id) $}</a></li>
<li class="breadcrumb-item-truncate active">{$ ::(ctrl.l7policy.name || ctrl.l7policy.id) $}</li>
<li class="breadcrumb-item-truncate active">{$ (ctrl.l7policy.name || ctrl.l7policy.id) $}</li>
</ol>
<div class="row">
<div class="col-xs-12 col-sm-9 text-left">
<ul class="list-inline">
<li>
<strong translate>Action</strong>
{$ ::ctrl.l7policy.action | decode:ctrl.l7policyAction $}
{$ ctrl.l7policy.action | decode:ctrl.l7policyAction $}
</li>
<li>
<strong translate>Operating Status</strong>

View File

@ -21,6 +21,9 @@
.controller('L7RuleDetailController', L7RuleDetailController);
L7RuleDetailController.$inject = [
'$timeout',
'horizon.dashboard.project.lbaasv2.events',
'$scope',
'loadbalancer',
'listener',
'l7policy',
@ -39,6 +42,9 @@
* @description
* Controller for the LBaaS v2 l7rule detail page.
*
* @param $timeout The angular timeout object.
* @param events The LBaaS v2 events object.
* @param $scope The angular scope object.
* @param loadbalancer The loadbalancer object.
* @param listener The listener object.
* @param l7policy The l7policy object.
@ -53,7 +59,8 @@
*/
function L7RuleDetailController(
loadbalancer, listener, l7policy, l7rule, loadBalancersService,
$timeout, events,
$scope, loadbalancer, listener, l7policy, l7rule, loadBalancersService,
resourceType, typeRegistry, spinnerService, $q
) {
var ctrl = this;
@ -79,6 +86,36 @@
ctrl.resultHandler = actionResultHandler;
$scope.$watch(
function() {
return ctrl.l7rule;
},
function() {
$timeout.cancel($scope.loadTimeout);
$scope.loadTimeout = $timeout(function() {
ctrl.context.loadPromise = ctrl.resourceType.load(
ctrl.context.l7policyId,
ctrl.context.l7ruleId
);
ctrl.context.loadPromise.then(loadData);
}, loadBalancersService.backoff.duration());
}
);
$scope.$on(
events.ACTION_DONE,
function() {
loadBalancersService.backoff.reset();
}
);
$scope.$on(
'$destroy',
function() {
$timeout.cancel($scope.loadTimeout);
}
);
function actionResultHandler(returnValue) {
return $q.when(returnValue, actionSuccessHandler);
}

View File

@ -51,7 +51,7 @@
loadbalancer: { id: '123' },
listener: { id: '123' },
l7policy: { id: '123' },
l7rule: { id: '123' },
l7rule: { id: '123', provisioning_status: 'ACTIVE' },
'horizon.framework.conf.resource-type-registry.service': service,
'horizon.framework.util.actions.action-result.service': actionResultService,
'horizon.framework.widgets.modal-wait-spinner.service': {
@ -69,6 +69,30 @@
expect(ctrl.l7rule).toBeDefined();
});
describe('data watchers', function() {
var events, loadBalancersService;
beforeEach(inject(function($injector) {
events = $injector.get('horizon.dashboard.project.lbaasv2.events');
loadBalancersService = $injector.get(
'horizon.dashboard.project.lbaasv2.loadbalancers.service'
);
}));
it('should refresh on provisioning status change', function() {
var loadFunctionDeferred = $q.defer();
spyOn(ctrl.resourceType, 'load').and.returnValue(loadFunctionDeferred.promise);
ctrl.l7rule = { id: '123', provisioning_status: 'PENDING_UPDATE' };
scope.$apply();
$timeout.flush();
expect(ctrl.resourceType.load).toHaveBeenCalled();
spyOn(loadBalancersService.backoff, 'reset').and.callThrough();
scope.$broadcast(events.ACTION_DONE);
expect(loadBalancersService.backoff.reset).toHaveBeenCalled();
});
});
describe('resultHandler', function() {
it('handles empty results', function() {

View File

@ -13,7 +13,7 @@
<ul class="list-inline">
<li>
<strong translate>Type</strong>
{$ ::ctrl.l7rule.type | decode:ctrl.l7ruleType $}
{$ ctrl.l7rule.type | decode:ctrl.l7ruleType $}
</li>
<li>
<strong translate>Operating Status</strong>

View File

@ -52,6 +52,7 @@
.constant('horizon.dashboard.project.lbaasv2.popovers', {
ipAddresses: '<ul><li ng-repeat="addr in member.addresses">{$ addr.ip $}</li></ul>'
})
.constant('horizon.dashboard.project.lbaasv2.events', events())
.run(['$rootScope', '$location', function ($rootScope, $location) {
$rootScope.$on('$routeChangeError', function() {
$location.path('project/load_balancer');
@ -64,6 +65,12 @@
'$routeProvider'
];
function events() {
return {
ACTION_DONE: 'horizon.dashboard.project.lbaasv2.ACTION_DONE'
};
}
function config($provide, $windowProvider, $routeProvider) {
var basePath = $windowProvider.$get().STATIC_URL + 'dashboard/project/lbaasv2/';
$provide.constant('horizon.dashboard.project.lbaasv2.basePath', basePath);
@ -81,7 +88,9 @@
$routeProvider
.when(loadbalancers, {
templateUrl: basePath + 'loadbalancers/panel.html'
templateUrl: basePath + 'loadbalancers/panel.html',
controller: 'PanelController',
controllerAs: 'ctrl'
})
.when(loadbalancers + '/:loadbalancerId', {
templateUrl: basePath + 'loadbalancers/details/detail.html',

View File

@ -88,7 +88,7 @@
});
describe('LBaaS v2 Module Config', function () {
var $routeProvider, basePath;
var $routeProvider, basePath; // eslint-disable-line no-unused-vars
beforeEach(function() {
// Create a dummy module so that we can test $routeProvider calls in our actual
@ -105,18 +105,16 @@
inject();
});
it('should route to loadbalancer panel', function () {
var loadbalancers = '/project/load_balancer';
var routes = [[
loadbalancers, {
templateUrl: basePath + 'loadbalancers/panel.html'
}
]];
routes.forEach(function(route) {
expect($routeProvider.when).toHaveBeenCalledWith(route[0], route[1]);
});
});
it('should route resolved loadbalancer panel',
inject(function($route, $location, $rootScope, $httpBackend) {
$httpBackend.expectGET(
'/static/dashboard/project/lbaasv2/loadbalancers/panel.html'
).respond({});
$location.path('/project/load_balancer/');
$rootScope.$digest();
expect($route.current).toBeDefined();
})
);
it('should route resolved loadbalancer detail', inject(function($injector) {
function loadbalancerAPI() {

View File

@ -22,6 +22,9 @@
.controller('ListenerDetailController', ListenerDetailController);
ListenerDetailController.$inject = [
'$timeout',
'horizon.dashboard.project.lbaasv2.events',
'$scope',
'loadbalancer',
'listener',
'horizon.dashboard.project.lbaasv2.loadbalancers.service',
@ -38,6 +41,7 @@
* @description
* Controller for the LBaaS v2 listener detail page.
*
* @param $scope The angular scope object.
* @param loadbalancer The loadbalancer object.
* @param listener The listener object.
* @param loadBalancersService The LBaaS v2 load balancers service.
@ -50,7 +54,8 @@
*/
function ListenerDetailController(
loadbalancer, listener, loadBalancersService, resourceType, typeRegistry,
$timeout, events,
$scope, loadbalancer, listener, loadBalancersService, resourceType, typeRegistry,
spinnerService, $q
) {
var ctrl = this;
@ -69,6 +74,34 @@
ctrl.resultHandler = actionResultHandler;
$scope.$watch(
function() {
return ctrl.listener;
},
function() {
$timeout.cancel($scope.loadTimeout);
$scope.loadTimeout = $timeout(function() {
ctrl.context.loadPromise = ctrl.resourceType.load(ctrl.context.identifier);
ctrl.context.loadPromise.then(loadData);
}, loadBalancersService.backoff.duration());
}
);
$scope.$on(
events.ACTION_DONE,
function() {
loadBalancersService.backoff.reset();
ctrl.listener = angular.copy(ctrl.listener);
}
);
$scope.$on(
'$destroy',
function() {
$timeout.cancel($scope.loadTimeout);
}
);
function actionResultHandler(returnValue) {
return $q.when(returnValue, actionSuccessHandler);
}
@ -79,6 +112,10 @@
ctrl.resourceType.initActions();
ctrl.listener = response.data;
ctrl.listener.loadbalancerId = ctrl.loadbalancer.id;
ctrl.listFunctionExtraParams = {
loadbalancerId: ctrl.loadbalancer.id,
listenerId: ctrl.listener.id
};
}
function actionSuccessHandler(result) {

View File

@ -50,7 +50,7 @@
ctrl = $controller('ListenerDetailController', {
$scope: scope,
loadbalancer: { id: '123' },
listener: { id: '123' },
listener: { id: '123', provisioning_status: 'ACTIVE' },
'horizon.framework.conf.resource-type-registry.service': service,
'horizon.framework.util.actions.action-result.service': actionResultService,
'horizon.framework.widgets.modal-wait-spinner.service': {
@ -66,6 +66,30 @@
expect(ctrl.listener).toBeDefined();
});
describe('data watchers', function() {
var events, loadBalancersService;
beforeEach(inject(function($injector) {
events = $injector.get('horizon.dashboard.project.lbaasv2.events');
loadBalancersService = $injector.get(
'horizon.dashboard.project.lbaasv2.loadbalancers.service'
);
}));
it('should refresh on provisioning status change', function() {
var loadFunctionDeferred = $q.defer();
spyOn(ctrl.resourceType, 'load').and.returnValue(loadFunctionDeferred.promise);
ctrl.listener = { id: '123', provisioning_status: 'PENDING_UPDATE' };
scope.$apply();
$timeout.flush();
expect(ctrl.resourceType.load).toHaveBeenCalled();
spyOn(loadBalancersService.backoff, 'reset').and.callThrough();
scope.$broadcast(events.ACTION_DONE);
expect(loadBalancersService.backoff.reset).toHaveBeenCalled();
});
});
describe('resultHandler', function() {
it('handles empty results', function() {

View File

@ -4,7 +4,7 @@
<li class="breadcrumb-item-truncate"><translate>Network</translate></li>
<li class="breadcrumb-item-truncate"><a href="project/load_balancer/"><translate>Load Balancers</translate></a></li>
<li class="breadcrumb-item-truncate"><a href="project/load_balancer/{$ ::ctrl.loadbalancer.id $}">{$ ::(ctrl.loadbalancer.name || ctrl.loadbalancer.id) $}</a></li>
<li class="breadcrumb-item-truncate active">{$ ::(ctrl.listener.name || ctrl.listener.id) $}</li>
<li class="breadcrumb-item-truncate active">{$ (ctrl.listener.name || ctrl.listener.id) $}</li>
</ol>
<div class="row">
<div class="col-xs-12 col-sm-9 text-left">

View File

@ -22,6 +22,9 @@
.controller('LoadBalancerDetailController', LoadBalancerDetailController);
LoadBalancerDetailController.$inject = [
'$timeout',
'horizon.dashboard.project.lbaasv2.events',
'$scope',
'loadbalancer',
'horizon.dashboard.project.lbaasv2.loadbalancers.service',
'horizon.dashboard.project.lbaasv2.loadbalancers.resourceType',
@ -37,6 +40,9 @@
* @description
* Controller for the LBaaS v2 load balancers detail page.
*
* @param $timeout The angular timeout object.
* @param events The LBaaS v2 events object.
* @param $scope The angular scope object.
* @param loadbalancer The loadbalancer object.
* @param loadBalancersService The LBaaS v2 load balancers service.
* @param resourceType The load balancer resource type.
@ -48,8 +54,9 @@
*/
function LoadBalancerDetailController(
loadbalancer, loadBalancersService, resourceType, typeRegistry,
spinnerService, $q
$timeout, events,
$scope, loadbalancer, loadBalancersService,
resourceType, typeRegistry, spinnerService, $q
) {
var ctrl = this;
@ -65,6 +72,34 @@
ctrl.resultHandler = actionResultHandler;
$scope.$watch(
function() {
return ctrl.loadbalancer;
},
function() {
$timeout.cancel($scope.loadTimeout);
$scope.loadTimeout = $timeout(function() {
ctrl.context.loadPromise = ctrl.resourceType.load(ctrl.context.identifier);
ctrl.context.loadPromise.then(loadData);
}, loadBalancersService.backoff.duration());
}
);
$scope.$on(
events.ACTION_DONE,
function() {
loadBalancersService.backoff.reset();
ctrl.loadbalancer = angular.copy(ctrl.loadbalancer);
}
);
$scope.$on(
'$destroy',
function() {
$timeout.cancel($scope.loadTimeout);
}
);
function actionResultHandler(returnValue) {
return $q.when(returnValue, actionSuccessHandler);
}
@ -75,6 +110,9 @@
ctrl.resourceType.initActions();
ctrl.loadbalancer = response.data;
ctrl.loadbalancer.floating_ip_address = response.data.floating_ip.ip;
ctrl.listFunctionExtraParams = {
loadbalancerId: ctrl.loadbalancer.id
};
}
function actionSuccessHandler(result) {

View File

@ -49,7 +49,7 @@
scope = $rootScope.$new();
ctrl = $controller('LoadBalancerDetailController', {
$scope: scope,
loadbalancer: { id: '123' },
loadbalancer: { id: '123', provisioning_status: 'ACTIVE' },
'horizon.framework.conf.resource-type-registry.service': service,
'horizon.framework.util.actions.action-result.service': actionResultService,
'horizon.framework.widgets.modal-wait-spinner.service': {
@ -64,6 +64,30 @@
expect(ctrl.loadbalancer).toBeDefined();
});
describe('data watchers', function() {
var events, loadBalancersService;
beforeEach(inject(function($injector) {
events = $injector.get('horizon.dashboard.project.lbaasv2.events');
loadBalancersService = $injector.get(
'horizon.dashboard.project.lbaasv2.loadbalancers.service'
);
}));
it('should refresh on provisioning status change', function() {
var loadFunctionDeferred = $q.defer();
spyOn(ctrl.resourceType, 'load').and.returnValue(loadFunctionDeferred.promise);
ctrl.loadbalancer = { id: '123', provisioning_status: 'PENDING_UPDATE' };
scope.$apply();
$timeout.flush();
expect(ctrl.resourceType.load).toHaveBeenCalled();
spyOn(loadBalancersService.backoff, 'reset').and.callThrough();
scope.$broadcast(events.ACTION_DONE);
expect(loadBalancersService.backoff.reset).toHaveBeenCalled();
});
});
describe('resultHandler', function() {
it('handles empty results', function() {
@ -97,7 +121,7 @@
var result = $q.defer();
result.resolve({some: 'thing', failed: [], deleted: [{id: 1}]});
ctrl.resultHandler(result.promise);
deferred.resolve({data: {some: 'data'}});
deferred.resolve({data: {some: 'data', floating_ip: {}}});
$timeout.flush();
expect(ctrl.showDetails).toBe(undefined);
});

View File

@ -90,6 +90,27 @@
null: gettext('None')
};
var backoff = (function() {
var min = 250;
var max = 5000;
var factor = 2;
var attempts = 0;
function duration() {
var ms = min * Math.pow(factor, attempts++);
return Math.min(ms, max) | 0;
}
function reset() {
attempts = 0;
}
return {
duration: duration,
reset: reset
};
}());
var service = {
operatingStatus: operatingStatus,
provisioningStatus: provisioningStatus,
@ -120,7 +141,8 @@
getHealthMonitorPromise: getHealthMonitorPromise,
getHealthMonitorsPromise: getHealthMonitorsPromise,
getHealthMonitorDetailsPath: getHealthMonitorDetailsPath,
isActionable: isActionable
isActionable: isActionable,
backoff: backoff
};
return service;

View File

@ -0,0 +1,79 @@
/*
* Copyright 2018 Walmart.
*
* 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.loadbalancers')
.controller('PanelController', PanelController);
PanelController.$inject = [
'$scope',
'$timeout',
'horizon.dashboard.project.lbaasv2.loadbalancers.service',
'horizon.dashboard.project.lbaasv2.events'
];
/**
* @ngdoc controller
* @name PanelController
*
* @description
* Controller for the LBaaS v2 load balancers panel.
*
* @param $scope The angular scope object.
* @param $timeout The angular timeout object.
* @param loadBalancersService The LBaaS v2 load balancers service.
* @param events The LBaaS v2 events object.
* @returns undefined
*/
function PanelController(
$scope, $timeout, loadBalancersService, events
) {
var ctrl = this;
ctrl.listFunctionExtraParams = {};
$scope.$watch(
function() {
return ctrl.listFunctionExtraParams;
},
function() {
$timeout.cancel($scope.listTimeout);
$scope.listTimeout = $timeout(function () {
ctrl.listFunctionExtraParams = angular.copy(ctrl.listFunctionExtraParams);
}, loadBalancersService.backoff.duration());
}
);
$scope.$on(
events.ACTION_DONE,
function() {
loadBalancersService.backoff.reset();
ctrl.listFunctionExtraParams = angular.copy(ctrl.listFunctionExtraParams);
}
);
$scope.$on(
'$destroy',
function() {
$timeout.cancel($scope.listTimeout);
}
);
}
})();

View File

@ -0,0 +1,66 @@
/*
* Copyright 2018 Walmart.
*
* 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';
describe('LBaaS v2 Load Balancer Panel Controller', function() {
var ctrl, scope, $timeout;
///////////////////////
beforeEach(module('horizon.dashboard.project.lbaasv2'));
beforeEach(module(function($provide) {
$provide.value('$uibModal', {});
}));
beforeEach(inject(function($controller, $rootScope, _$timeout_) {
$timeout = _$timeout_;
scope = $rootScope.$new();
ctrl = $controller('PanelController', {
$scope: scope
});
}));
it('should create a controller', function() {
expect(ctrl).toBeDefined();
expect(ctrl.listFunctionExtraParams).toBeDefined();
});
describe('data watchers', function() {
var events, loadBalancersService;
beforeEach(inject(function($injector) {
events = $injector.get('horizon.dashboard.project.lbaasv2.events');
loadBalancersService = $injector.get(
'horizon.dashboard.project.lbaasv2.loadbalancers.service'
);
}));
it('should refresh on provisioning status change', function() {
ctrl.listFunctionExtraParams = {};
scope.$apply();
$timeout.flush();
spyOn(loadBalancersService.backoff, 'reset').and.callThrough();
scope.$broadcast(events.ACTION_DONE);
expect(loadBalancersService.backoff.reset).toHaveBeenCalled();
});
});
});
})();

View File

@ -5,5 +5,5 @@
</ol>
<hz-resource-panel resource-type-name="OS::Octavia::LoadBalancer">
<hz-resource-table resource-type-name="OS::Octavia::LoadBalancer"
track-by="trackBy"></hz-resource-table>
track-by="trackBy" list-function-extra-params="ctrl.listFunctionExtraParams"></hz-resource-table>
</hz-resource-panel>

View File

@ -23,6 +23,8 @@
modalService);
modalService.$inject = [
'$rootScope',
'horizon.dashboard.project.lbaasv2.events',
'horizon.dashboard.project.lbaasv2.members.resourceType',
'horizon.framework.util.actions.action-result.service',
'$uibModal',
@ -39,6 +41,8 @@
* @description
* Provides the service for the pool member Edit Member action.
*
* @param $rootScope The angular root scope object.
* @param events The LBaaS v2 events object.
* @param resourceType The member resource type.
* @param actionResultService The horizon action result service.
* @param $uibModal The angular bootstrap $uibModal service.
@ -51,6 +55,7 @@
*/
function modalService(
$rootScope, events,
resourceType,
actionResultService,
$uibModal,
@ -107,6 +112,7 @@
function onModalClose() {
toastService.add('success', gettext('Pool member has been updated.'));
$rootScope.$broadcast(events.ACTION_DONE);
return actionResultService.getActionResult()
.updated(resourceType, member.id)
.result;

View File

@ -22,6 +22,9 @@
.controller('MemberDetailController', MemberDetailController);
MemberDetailController.$inject = [
'$timeout',
'horizon.dashboard.project.lbaasv2.events',
'$scope',
'loadbalancer',
'listener',
'pool',
@ -40,6 +43,9 @@
* @description
* Controller for the LBaaS v2 member detail page.
*
* @param $timeout The angular timeout object.
* @param events The LBaaS v2 events object.
* @param $scope The angular scope object.
* @param loadbalancer The loadbalancer object.
* @param listener The listener object.
* @param pool The pool object.
@ -54,7 +60,8 @@
*/
function MemberDetailController(
loadbalancer, listener, pool, member, loadBalancersService,
$timeout, events,
$scope, loadbalancer, listener, pool, member, loadBalancersService,
resourceType, typeRegistry, spinnerService, $q
) {
var ctrl = this;
@ -79,6 +86,36 @@
ctrl.resultHandler = actionResultHandler;
$scope.$watch(
function() {
return ctrl.member;
},
function() {
$timeout.cancel($scope.loadTimeout);
$scope.loadTimeout = $timeout(function() {
ctrl.context.loadPromise = ctrl.resourceType.load(
ctrl.context.poolId,
ctrl.context.memberId
);
ctrl.context.loadPromise.then(loadData);
}, loadBalancersService.backoff.duration());
}
);
$scope.$on(
events.ACTION_DONE,
function() {
loadBalancersService.backoff.reset();
}
);
$scope.$on(
'$destroy',
function() {
$timeout.cancel($scope.loadTimeout);
}
);
function actionResultHandler(returnValue) {
return $q.when(returnValue, actionSuccessHandler);
}

View File

@ -65,7 +65,7 @@
loadbalancer: { id: '123' },
listener: { id: '123' },
pool: { id: '123' },
member: { id: '123' },
member: { id: '123', provisioning_status: 'ACTIVE' },
'horizon.framework.conf.resource-type-registry.service': service,
'horizon.framework.util.actions.action-result.service': actionResultService,
'horizon.framework.widgets.modal-wait-spinner.service': {
@ -83,6 +83,30 @@
expect(ctrl.member).toBeDefined();
});
describe('data watchers', function() {
var events, loadBalancersService;
beforeEach(inject(function($injector) {
events = $injector.get('horizon.dashboard.project.lbaasv2.events');
loadBalancersService = $injector.get(
'horizon.dashboard.project.lbaasv2.loadbalancers.service'
);
}));
it('should refresh on provisioning status change', function() {
var loadFunctionDeferred = $q.defer();
spyOn(ctrl.resourceType, 'load').and.returnValue(loadFunctionDeferred.promise);
ctrl.member = { id: '123', provisioning_status: 'PENDING_UPDATE' };
scope.$apply();
$timeout.flush();
expect(ctrl.resourceType.load).toHaveBeenCalled();
spyOn(loadBalancersService.backoff, 'reset').and.callThrough();
scope.$broadcast(events.ACTION_DONE);
expect(loadBalancersService.backoff.reset).toHaveBeenCalled();
});
});
describe('resultHandler', function() {
it('handles empty results', function() {

View File

@ -7,7 +7,7 @@
<li class="breadcrumb-item-truncate" ng-style="ctrl.withListenerStyle"><a href="project/load_balancer/{$ ::ctrl.loadbalancer.id $}/listeners/{$ :: ctrl.listener.id $}">{$ :: (ctrl.listener.name || ctrl.listener.id) $}</a></li>
<li class="breadcrumb-item-truncate" ng-style="ctrl.withListenerStyle"><a href="project/load_balancer/{$ ::ctrl.loadbalancer.id $}/listeners/{$ :: ctrl.listener.id $}/pools/{$ ::ctrl.pool.id $}">{$ ::(ctrl.pool.name || ctrl.pool.id) $}</a></li>
<li class="breadcrumb-item-truncate" ng-style="ctrl.withoutListenerStyle"><a href="project/load_balancer/{$ ::ctrl.loadbalancer.id $}/pools/{$ ::ctrl.pool.id $}">{$ ::(ctrl.pool.name || ctrl.pool.id) $}</a></li>
<li class="breadcrumb-item-truncate active">{$ ::(ctrl.member.name || ctrl.member.id) $}</li>
<li class="breadcrumb-item-truncate active">{$ (ctrl.member.name || ctrl.member.id) $}</li>
</ol>
<div class="row">
<div class="col-xs-12 col-sm-9 text-left">

View File

@ -22,6 +22,9 @@
.controller('PoolDetailController', PoolDetailController);
PoolDetailController.$inject = [
'$timeout',
'horizon.dashboard.project.lbaasv2.events',
'$scope',
'loadbalancer',
'listener',
'pool',
@ -39,6 +42,9 @@
* @description
* Controller for the LBaaS v2 pool detail page.
*
* @param $timeout The angular timeout object.
* @param events The LBaaS v2 events object.
* @param $scope The angular scope object.
* @param loadbalancer The loadbalancer object.
* @param listener The listener object.
* @param pool The pool object.
@ -52,7 +58,8 @@
*/
function PoolDetailController(
loadbalancer, listener, pool, loadBalancersService,
$timeout, events,
$scope, loadbalancer, listener, pool, loadBalancersService,
resourceType, typeRegistry, spinnerService, $q
) {
var ctrl = this;
@ -79,6 +86,34 @@
ctrl.resultHandler = actionResultHandler;
$scope.$watch(
function() {
return ctrl.pool;
},
function() {
$timeout.cancel($scope.loadTimeout);
$scope.loadTimeout = $timeout(function() {
ctrl.context.loadPromise = ctrl.resourceType.load(ctrl.context.identifier);
ctrl.context.loadPromise.then(loadData);
}, loadBalancersService.backoff.duration());
}
);
$scope.$on(
events.ACTION_DONE,
function() {
loadBalancersService.backoff.reset();
ctrl.pool = angular.copy(ctrl.pool);
}
);
$scope.$on(
'$destroy',
function() {
$timeout.cancel($scope.loadTimeout);
}
);
function actionResultHandler(returnValue) {
return $q.when(returnValue, actionSuccessHandler);
}
@ -90,6 +125,11 @@
ctrl.pool = response.data;
ctrl.pool.loadbalancerId = ctrl.loadbalancer.id;
ctrl.pool.listenerId = ctrl.listener.id;
ctrl.listFunctionExtraParams = {
loadbalancerId: ctrl.loadbalancer.id,
listenerId: ctrl.listener.id,
poolId: ctrl.pool.id
};
}
function actionSuccessHandler(result) {

View File

@ -51,7 +51,7 @@
$scope: scope,
loadbalancer: { id: '123' },
listener: {},
pool: { id: '123' },
pool: { id: '123', provisioning_status: 'ACTIVE' },
'horizon.framework.conf.resource-type-registry.service': service,
'horizon.framework.util.actions.action-result.service': actionResultService,
'horizon.framework.widgets.modal-wait-spinner.service': {
@ -63,7 +63,7 @@
$scope: scope,
loadbalancer: { id: '123' },
listener: { id: '123' },
pool: { id: '123' },
pool: { id: '123', provisioning_status: 'ACTIVE' },
'horizon.framework.conf.resource-type-registry.service': service,
'horizon.framework.util.actions.action-result.service': actionResultService,
'horizon.framework.widgets.modal-wait-spinner.service': {
@ -80,6 +80,30 @@
expect(ctrl.pool).toBeDefined();
});
describe('data watchers', function() {
var events, loadBalancersService;
beforeEach(inject(function($injector) {
events = $injector.get('horizon.dashboard.project.lbaasv2.events');
loadBalancersService = $injector.get(
'horizon.dashboard.project.lbaasv2.loadbalancers.service'
);
}));
it('should refresh on provisioning status change', function() {
var loadFunctionDeferred = $q.defer();
spyOn(ctrl.resourceType, 'load').and.returnValue(loadFunctionDeferred.promise);
ctrl.pool = { id: '123', provisioning_status: 'PENDING_UPDATE' };
scope.$apply();
$timeout.flush();
expect(ctrl.resourceType.load).toHaveBeenCalled();
spyOn(loadBalancersService.backoff, 'reset').and.callThrough();
scope.$broadcast(events.ACTION_DONE);
expect(loadBalancersService.backoff.reset).toHaveBeenCalled();
});
});
describe('resultHandler', function() {
it('handles empty results', function() {

View File

@ -5,7 +5,7 @@
<li class="breadcrumb-item-truncate"><a href="project/load_balancer/"><translate>Load Balancers</translate></a></li>
<li class="breadcrumb-item-truncate"><a href="project/load_balancer/{$ ::ctrl.loadbalancer.id $}">{$ ::(ctrl.loadbalancer.name || ctrl.loadbalancer.id) $}</a></li>
<li class="breadcrumb-item-truncate" ng-style="ctrl.withListenerStyle"><a href="project/load_balancer/{$ ::ctrl.loadbalancer.id $}/listeners/{$ :: ctrl.listener.id $}">{$ :: (ctrl.listener.name || ctrl.listener.id) $}</a></li>
<li class="breadcrumb-item-truncate active">{$ ::(ctrl.pool.name || ctrl.pool.id) $}</li>
<li class="breadcrumb-item-truncate active">{$ (ctrl.pool.name || ctrl.pool.id) $}</li>
</ol>
<div class="row">
<div class="col-xs-12 col-sm-9 text-left">
@ -16,7 +16,7 @@
</li>
<li>
<strong translate>Algorithm</strong>
{$ ::ctrl.pool.lb_algorithm | decode:ctrl.loadBalancerAlgorithm $}
{$ ctrl.pool.lb_algorithm | decode:ctrl.loadBalancerAlgorithm $}
</li>
<li>
<strong translate>Operating Status</strong>

View File

@ -21,6 +21,8 @@
.factory('horizon.dashboard.project.lbaasv2.workflow.modal', modalService);
modalService.$inject = [
'$rootScope',
'horizon.dashboard.project.lbaasv2.events',
'$uibModal',
'horizon.framework.widgets.toast.service'
];
@ -32,12 +34,14 @@
* @description
* Provides the service for opening the LBaaS create / edit modal.
*
* @param $rootScope The angular root scope object.
* @param events The LBaaS v2 events object.
* @param $uibModal The angular bootstrap $uibModal service.
* @param toastService The horizon toast service.
* @returns The modal service for the LBaaS workflow.
*/
function modalService($uibModal, toastService) {
function modalService($rootScope, events, $uibModal, toastService) {
var service = {
init: init
@ -100,6 +104,7 @@
function onModalClose(response) {
toastService.add('success', args.message);
if (args.handle) {
$rootScope.$broadcast(events.ACTION_DONE);
return args.handle(response);
}
}

View File

@ -0,0 +1,4 @@
---
features:
- |
Adds the ability to auto refresh detail pages upon action.