diff --git a/components/app-core/backend/info.go b/components/app-core/backend/info.go
index b1a69ffd2b..b1b40093bd 100644
--- a/components/app-core/backend/info.go
+++ b/components/app-core/backend/info.go
@@ -23,6 +23,7 @@ type Info struct {
User *interfaces.ConnectedUser `json:"user"`
Endpoints map[string]map[string]*Endpoint `json:"endpoints"`
CloudFoundry *interfaces.CFInfo `json:"cloud-foundry,omitempty"`
+ PluginConfig map[string]string `json:"plugin-config,omitempty"`
}
func (p *portalProxy) info(c echo.Context) error {
@@ -59,6 +60,7 @@ func (p *portalProxy) getInfo(c echo.Context) (*Info, error) {
User: uaaUser,
Endpoints: make(map[string]map[string]*Endpoint),
CloudFoundry: p.Config.CloudFoundryInfo,
+ PluginConfig: p.Config.PluginConfig,
}
// initialize the Endpoints maps
for _, plugin := range p.Plugins {
diff --git a/components/app-core/backend/main.go b/components/app-core/backend/main.go
index 8eba804a49..873108f40a 100644
--- a/components/app-core/backend/main.go
+++ b/components/app-core/backend/main.go
@@ -305,6 +305,7 @@ func loadPortalConfig(pc interfaces.PortalConfig) (interfaces.PortalConfig, erro
// Add custom properties
pc.CFAdminIdentifier = CFAdminIdentifier
pc.HTTPS = true
+ pc.PluginConfig = make(map[string]string)
return pc, nil
}
diff --git a/components/app-core/backend/repository/interfaces/structs.go b/components/app-core/backend/repository/interfaces/structs.go
index 62ce711d3a..8293d862ed 100644
--- a/components/app-core/backend/repository/interfaces/structs.go
+++ b/components/app-core/backend/repository/interfaces/structs.go
@@ -102,4 +102,5 @@ type PortalConfig struct {
LoginHook LoginHookFunc
SessionStore SessionStorer
ConsoleConfig *ConsoleConfig
+ PluginConfig map[string]string
}
diff --git a/components/app-core/frontend/src/utils/logged-in.service.js b/components/app-core/frontend/src/utils/logged-in.service.js
index 46116a9a28..c41bf26d7b 100644
--- a/components/app-core/frontend/src/utils/logged-in.service.js
+++ b/components/app-core/frontend/src/utils/logged-in.service.js
@@ -26,7 +26,7 @@
var loggedIn = false;
var lastUserInteraction = moment();
- var sessionChecker, dialog;
+ var sessionChecker, dialog, dashboardRouteFunc;
// Check the session every 30 seconds (Note: this is vey cheap to do unless the session is about to expire)
var checkSessionInterval = 30 * 1000;
@@ -147,7 +147,9 @@
return {
isLoggedIn: isLoggedIn,
- userInteracted: userInteracted
+ userInteracted: userInteracted,
+ setDashboardRouteFunc: setDashboardRouteFunc,
+ getDashboardRoute: getDashboardRoute
};
function isLoggedIn() {
@@ -158,6 +160,17 @@
lastUserInteraction = moment();
}
+ function setDashboardRouteFunc(func) {
+ dashboardRouteFunc = func;
+ }
+
+ function getDashboardRoute() {
+ // At this point console-info must have been called
+ if (angular.isFunction(dashboardRouteFunc)) {
+ return dashboardRouteFunc();
+ }
+ }
+
function _getAccountModel() {
return modelManager.retrieve('app.model.account');
}
diff --git a/components/app-core/frontend/src/view/application.directive.js b/components/app-core/frontend/src/view/application.directive.js
index ea963cf1a7..6392fd2807 100644
--- a/components/app-core/frontend/src/view/application.directive.js
+++ b/components/app-core/frontend/src/view/application.directive.js
@@ -26,18 +26,19 @@
* @namespace app.view.application.ApplicationController
* @memberof app.view.application
* @name ApplicationController
+ * @param {object} $q - Angular $q service
* @param {app.utils.appEventService} appEventService - the event bus service
* @param {app.model.modelManager} modelManager - the application model manager
* @param {app.model.loginManager} loginManager - the login management service
* @param {app.view.appUpgradeCheck} appUpgradeCheck - the upgrade check service
* @param {object} appLocalStorage - the Local Storage In Service
- * @param {object} appUtilsService - the App Utils service
* @param {app.view.consoleSetupCheck} consoleSetupCheck - the Console Setup checkservice
* @param {object} $timeout - Angular $timeout service
* @param {$stateParams} $stateParams - Angular ui-router $stateParams service
* @param {$window} $window - Angular $window service
* @param {$rootScope} $rootScope - Angular $rootScope service
* @param {$scope} $scope - Angular $scope service
+ * @param {appLoggedInService} appLoggedInService - Logged In Service
* @property {app.utils.appEventService} appEventService - the event bus service
* @property {app.model.modelManager} modelManager - the application model manager
* @property {app.view.appUpgradeCheck} appUpgradeCheck - the upgrade check service
@@ -47,8 +48,9 @@
* @property {boolean} serverErrorOnLogin - a flag indicating if user login failed because of a server error.
* @class
*/
- function ApplicationController(appEventService, modelManager, loginManager, appUpgradeCheck, appLocalStorage,
- appUtilsService, consoleSetupCheck, $timeout, $stateParams, $window, $rootScope, $scope) {
+ function ApplicationController($q, appEventService, modelManager, loginManager, appUpgradeCheck, appLocalStorage,
+ consoleSetupCheck, $timeout, $stateParams, $window, $rootScope, $scope,
+ appLoggedInService) {
var vm = this;
@@ -63,7 +65,6 @@
vm.hideNavigation = $stateParams.hideNavigation;
vm.hideAccount = $stateParams.hideAccount;
vm.navbarIconsOnly = false;
- vm.isEndpointsDashboardAvailable = appUtilsService.isPluginAvailable('endpointsDashboard');
vm.login = login;
vm.logout = logout;
@@ -184,61 +185,49 @@
*/
var account = modelManager.retrieve('app.model.account');
- // Fetch the list of services instances
+ var serviceInstanceModel = modelManager.retrieve('app.model.serviceInstance');
+ var userServiceInstanceModel = modelManager.retrieve('app.model.serviceInstance.user');
/* eslint-disable */
// TODO: If this fails, we should show a notification message
/* eslint-enable */
- modelManager.retrieve('app.model.serviceInstance')
- .list()
- .then(function onSuccess(data) {
- var noEndpoints = data.numAvailable === 0;
- // Admin
- if (account.isAdmin()) {
- // Go the endpoints dashboard if there are no CF clusters
- if (noEndpoints) {
- vm.redirectState = 'endpoint.dashboard';
- if (!vm.isEndpointsDashboardAvailable) {
- appEventService.$emit(appEventService.events.TRANSFER, 'error-page', {error: 'notSetup'});
- continueLogin = false;
- }
+ $q.all([
+ serviceInstanceModel.list(),
+ modelManager.retrieve('app.model.consoleInfo').getConsoleInfo(),
+ userServiceInstanceModel.list()
+ ])
+ .then(function () {
+ var cfOnly = _.filter(serviceInstanceModel.serviceInstances, {cnsi_type: 'cf'}) || [];
+ var noEndpoints = cfOnly.length === 0;
+ var dashboardRedirect = appLoggedInService.getDashboardRoute();
+
+ if (noEndpoints) {
+ // Admin
+ if (account.isAdmin()) {
+ vm.redirectState = dashboardRedirect;
}
- } else {
- // Developer or Endpoint Dashboard plugin isn't loaded
- if (noEndpoints) {
+ if (!vm.redirectState) {
// No CF instances, so the system is not setup and the user can't fix this
continueLogin = false;
appEventService.$emit(appEventService.events.TRANSFER, 'error-page', {error: 'notSetup'});
- } else {
- var userServiceInstanceModel = modelManager.retrieve('app.model.serviceInstance.user');
- // Need to get the user's service list to determine if they have any connected
- return userServiceInstanceModel.list().then(function () {
- // Developer - allow user to connect services, if we have some and none are connected
- if (userServiceInstanceModel.getNumValid() === 0) {
- vm.redirectState = 'endpoint.dashboard';
- if (!vm.isEndpointsDashboardAvailable) {
- appEventService.$emit(appEventService.events.TRANSFER, 'error-page', {error: 'notConnected'});
- continueLogin = false;
- }
- }
- });
+ }
+ } else {
+ // Need to get the user's service list to determine if they have any connected
+ // Developer - allow user to connect services, if we have some and none are connected
+ if (userServiceInstanceModel.getNumValid() === 0) {
+ vm.redirectState = dashboardRedirect;
+ if (!vm.redirectState) {
+ appEventService.$emit(appEventService.events.TRANSFER, 'error-page', {error: 'notConnected'});
+ continueLogin = false;
+ }
}
}
})
- .then(function () {
- // Update consoleInfo
- return modelManager.retrieve('app.model.consoleInfo').getConsoleInfo();
- })
- .then(function () {
- // Get the user registered services once at login - only refreshed in endpoints dashboard
- var userServiceInstanceModel = modelManager.retrieve('app.model.serviceInstance.user');
- return userServiceInstanceModel.list();
- })
.finally(function () {
vm.showGlobalSpinner = false;
if (continueLogin) {
// When we notify listeners that login has completed, in some cases we don't want them
- // to redirect tp their page - we might want to control that the go to the endpoints dahsboard (for exmample).
- // So, we pass this flag to tell them login happenned, but that they should not redirect
+ // to redirect to their page - we might want to control that they go to the endpoints dashboard (for example).
+ // So, we pass this flag to tell them login happened, but that they should not redirect
appEventService.$emit(appEventService.events.LOGIN, !!vm.redirectState);
// We need to do this after the login events are handled, so that ui-router states we might go to are registered
if (vm.redirectState) {
diff --git a/components/app-core/frontend/test/unit/view/application.directive.spec.js b/components/app-core/frontend/test/unit/view/application.directive.spec.js
index c630516d59..3eee943e98 100644
--- a/components/app-core/frontend/test/unit/view/application.directive.spec.js
+++ b/components/app-core/frontend/test/unit/view/application.directive.spec.js
@@ -27,7 +27,6 @@
applicationCtrl = $element.controller('application');
$httpBackend.when('GET', '/pp/v1/proxy/v2/info').respond(200, {});
$httpBackend.when('GET', '/pp/v1/proxy/v2/apps?page=1&results-per-page=48').respond(200, {guid: {}});
- $httpBackend.when('GET', '/pp/v1/cnsis/registered').respond([]);
// For some tests, the redirected state depends on whether the endpoints dashboard is available
redirectStateName = $state.get('endpoint.dashboard') ? 'endpoint.dashboard' : 'error-page';
@@ -98,10 +97,11 @@
$httpBackend.when('POST', '/pp/v1/auth/login/uaa').respond(200, {account: 'dev', scope: 'foo'});
$httpBackend.when('GET', '/pp/v1/cnsis').respond(200, []);
$httpBackend.when('GET', '/pp/v1/info').respond(200, {});
+ $httpBackend.when('GET', '/pp/v1/cnsis/registered').respond(200, []);
$httpBackend.expectPOST('/pp/v1/auth/login/uaa');
// No endpoints are set up, so we should go to error page
- $httpBackend.expectGET('/pp/v1/cnsis/registered').respond(200, []);
+ $httpBackend.expectGET('/pp/v1/cnsis/registered');
applicationCtrl.login('dev', 'dev');
$httpBackend.flush();
@@ -241,7 +241,7 @@
expect($state.current.name).toBe(redirectStateName);
});
- it('should not show cluster registration if cluster count > 0', function () {
+ it('should go to endpoints dashboard if cluster count > 0 and none connected', function () {
var responseData = [
{id: 1, name: 'name', api_endpoint: {Scheme: 'http', Host: 'api.host.com'}, cnsi_type: 'cf'}
];
@@ -253,6 +253,27 @@
applicationCtrl.login('admin', 'admin');
$httpBackend.flush();
+ expect(applicationCtrl.redirectState).toBe('endpoint.dashboard');
+ expect(applicationCtrl.showGlobalSpinner).toBe(false);
+ });
+
+ it('should not go to endpoints dashboard if cluster count > 0 and at least one connected', function () {
+ var responseData = [
+ {id: 1, name: 'name', api_endpoint: {Scheme: 'http', Host: 'api.host.com'}, cnsi_type: 'cf'}
+ ];
+ $httpBackend.when('GET', '/pp/v1/cnsis')
+ .respond(200, responseData);
+
+ var future = 50000 + (new Date()).getTime() / 1000;
+
+ $httpBackend.when('GET', '/pp/v1/info').respond(200, []);
+ $httpBackend.when('GET', '/pp/v1/cnsis/registered').respond(200, [
+ { account: 'test', token_expiry: future, guid: 'service', cnsi_type: 'cf', name: 'test', api_endpoint: testAptEndpoint }
+ ]);
+
+ applicationCtrl.login('admin', 'admin');
+ $httpBackend.flush();
+
expect(applicationCtrl.redirectState).toBe(false);
expect(applicationCtrl.showGlobalSpinner).toBe(false);
});
@@ -267,7 +288,7 @@
]);
});
- it('should show service instance registration if we dont not have registered services', function () {
+ it('should show service instance registration if we don\'t have registered services', function () {
$httpBackend.when('GET', '/pp/v1/cnsis').respond(200, []);
$httpBackend.when('GET', '/pp/v1/info').respond(200, []);
$httpBackend.when('GET', '/pp/v1/cnsis/registered').respond(200, []);
@@ -275,10 +296,27 @@
applicationCtrl.login('dev', 'dev');
$httpBackend.flush();
+ expect(applicationCtrl.redirectState).toBe('endpoint.dashboard');
expect(applicationCtrl.showGlobalSpinner).toBe(false);
});
- it('should not show service instance registration if we have registered services', function () {
+ it('should show service instance registration if we don\'t have connected services', function () {
+ var responseData = [
+ {id: 1, name: 'name', api_endpoint: {Scheme: 'http', Host: 'api.host.com'}, cnsi_type: 'cf'}
+ ];
+ $httpBackend.when('GET', '/pp/v1/cnsis')
+ .respond(200, responseData);
+ $httpBackend.when('GET', '/pp/v1/info').respond(200, []);
+ $httpBackend.when('GET', '/pp/v1/cnsis/registered').respond(200, []);
+
+ applicationCtrl.login('dev', 'dev');
+ $httpBackend.flush();
+
+ expect(applicationCtrl.redirectState).toBe('endpoint.dashboard');
+ expect(applicationCtrl.showGlobalSpinner).toBe(false);
+ });
+
+ it('should not show service instance registration if we have connected services', function () {
var future = 50000 + (new Date()).getTime() / 1000;
$httpBackend.when('GET', '/pp/v1/info').respond(200, []);
@@ -289,6 +327,7 @@
applicationCtrl.login('dev', 'dev');
$httpBackend.flush();
+ expect(applicationCtrl.redirectState).toBe(false);
expect(applicationCtrl.showGlobalSpinner).toBe(false);
});
});
diff --git a/components/cloud-foundry-hosting/backend/main.go b/components/cloud-foundry-hosting/backend/main.go
index df746bd495..d45d4e9e48 100644
--- a/components/cloud-foundry-hosting/backend/main.go
+++ b/components/cloud-foundry-hosting/backend/main.go
@@ -20,10 +20,11 @@ import (
)
const (
- VCapApplication = "VCAP_APPLICATION"
- CFApiURLOverride = "CF_API_URL"
- CFApiForceSecure = "CF_API_FORCE_SECURE"
- cfSessionCookieName = "JSESSIONID"
+ VCapApplication = "VCAP_APPLICATION"
+ CFApiURLOverride = "CF_API_URL"
+ CFApiForceSecure = "CF_API_FORCE_SECURE"
+ cfSessionCookieName = "JSESSIONID"
+ ForceEndpointDashboard = "FORCE_ENDPOINT_DASHBOARD"
)
type CFHosting struct {
@@ -100,6 +101,23 @@ func (ch *CFHosting) Init() error {
log.Info("No forced override to HTTPS")
}
+ disableEndpointDashboard := true
+ if config.IsSet(ForceEndpointDashboard) {
+ // Force the Endpoint Dashboard to be visible?
+ if forceStr, err := config.GetValue(ForceEndpointDashboard); err == nil {
+ if force, err := strconv.ParseBool(forceStr); err == nil {
+ disableEndpointDashboard = !force
+ }
+ }
+ }
+
+ if disableEndpointDashboard {
+ log.Info("Endpoint Dashboard has been DISABLED")
+ } else {
+ log.Info("Endpoint Dashboard has been ENABLED")
+ }
+ ch.portalProxy.GetConfig().PluginConfig["endpointsDashboardDisabled"] = strconv.FormatBool(disableEndpointDashboard)
+
log.Infof("Using Cloud Foundry API URL: %s", appData.API)
cfEndpointSpec, _ := ch.portalProxy.GetEndpointTypeSpec("cf")
newCNSI, _, err := cfEndpointSpec.Info(appData.API, true)
diff --git a/components/cloud-foundry/frontend/test/e2e/application-wall.spec.js b/components/cloud-foundry/frontend/test/e2e/application-wall.spec.js
index 541f7d3760..786b763425 100644
--- a/components/cloud-foundry/frontend/test/e2e/application-wall.spec.js
+++ b/components/cloud-foundry/frontend/test/e2e/application-wall.spec.js
@@ -19,6 +19,7 @@
appWallConfigNoClusters(ngMockE2E.$httpBackend);
helpers.setBrowserNormal();
helpers.loadApp();
+ applicationWall.showApplications();
});
afterAll(function () {
diff --git a/components/endpoints-dashboard/i18n/en_US/dashboard.json b/components/endpoints-dashboard/i18n/en_US/dashboard.json
index 556bf99b89..17570b90d0 100644
--- a/components/endpoints-dashboard/i18n/en_US/dashboard.json
+++ b/components/endpoints-dashboard/i18n/en_US/dashboard.json
@@ -13,6 +13,7 @@
"start": "To enable developers to use the [[@:console]] to interact with [[@:product.name]],",
"link": "please register endpoints.",
"end": "The process of registering these endpoints will make them discoverable for anyone who logs into the [[@:product.console]]. Once you register an endpoint, we recommend connecting it to your account so you can manage it.",
+ "admin": "To access your cloud native workloads and other related third party services, connect with your personal credentials to the corresponding registered services.",
"non-admin": "To access your cloud native workloads and other related third party services, connect with your personal credentials to the corresponding registered services. Registered services are provided by your systems administrator."
},
"no-endpoints": {
diff --git a/components/endpoints-dashboard/src/endpoints-dashboard.module.js b/components/endpoints-dashboard/src/endpoints-dashboard.module.js
index a904ec776d..4d9aef4001 100644
--- a/components/endpoints-dashboard/src/endpoints-dashboard.module.js
+++ b/components/endpoints-dashboard/src/endpoints-dashboard.module.js
@@ -3,30 +3,51 @@
angular
.module('endpoints-dashboard', [])
+ .constant('endpointsDashboardDisabledKey', 'endpointsDashboardDisabled')
.run(register);
- function register($q, $state, modelManager, appEventService, appUtilsService) {
- return new EndpointsDashboard($q, $state, modelManager, appEventService, appUtilsService);
+ function register($q, $state, modelManager, appEventService, appUtilsService,
+ endpointsDashboardDisabledKey, appLoggedInService) {
+ return new EndpointsDashboard($q, $state, modelManager, appEventService, appUtilsService,
+ endpointsDashboardDisabledKey, appLoggedInService);
}
- function EndpointsDashboard($q, $state, modelManager, appEventService, appUtilsService) {
+ function EndpointsDashboard($q, $state, modelManager, appEventService, appUtilsService, endpointsDashboardDisabledKey,
+ appLoggedInService) {
var initialized = $q.defer();
- function init() {
- return initialized.promise;
- }
+ appLoggedInService.setDashboardRouteFunc(getDashboardRoute);
appEventService.$on(appEventService.events.LOGIN, function () {
- onLoggedIn();
+ if (isDashboardDisabled()) {
+ delete env.plugins.endpointsDashboard;
+ } else {
+ onLoggedIn();
+ }
});
appUtilsService.chainStateResolve('endpoint', $state, init);
+ function init() {
+ return initialized.promise;
+ }
+
function onLoggedIn() {
var menu = modelManager.retrieve('app.model.navigation').menu;
menu.addMenuItem('endpoints', 'endpoint.dashboard', 'menu.endpoints', 2, 'settings_input_component');
initialized.resolve();
}
+
+ function getDashboardRoute() {
+ if (!isDashboardDisabled()) {
+ return 'endpoint.dashboard';
+ }
+ }
+
+ function isDashboardDisabled() {
+ var info = modelManager.retrieve('app.model.consoleInfo').info;
+ return _.get(info, 'plugin-config.' + endpointsDashboardDisabledKey) === 'true';
+ }
}
})();
diff --git a/components/endpoints-dashboard/src/view/view.html b/components/endpoints-dashboard/src/view/view.html
index 1f88d3691a..85441b2291 100644
--- a/components/endpoints-dashboard/src/view/view.html
+++ b/components/endpoints-dashboard/src/view/view.html
@@ -16,13 +16,17 @@
class="endpoint-notification panel panel-default alert"
ng-class="{'endpoint-notification-slim': endpointsDashboardCtrl.endpoints.length === 0}">