From da5c57096872093721c6ef8d587f9e602870faef Mon Sep 17 00:00:00 2001 From: xAt0mZ Date: Tue, 2 Mar 2021 19:51:15 +0100 Subject: [PATCH] fix(app): EndpointProvider fallback on URL EndpointID when no endpoint is selected --- .../views/configure/configureController.js | 14 +++++-- app/portainer/services/endpointProvider.js | 38 ++++++++++++++++--- 2 files changed, 44 insertions(+), 8 deletions(-) diff --git a/app/kubernetes/views/configure/configureController.js b/app/kubernetes/views/configure/configureController.js index 8c53ce502..a66bf5a19 100644 --- a/app/kubernetes/views/configure/configureController.js +++ b/app/kubernetes/views/configure/configureController.js @@ -8,11 +8,19 @@ import { KubernetesIngressClassTypes } from 'Kubernetes/ingress/constants'; class KubernetesConfigureController { /* #region CONSTRUCTOR */ + + // TODO: technical debt + // $transition$ cannot be injected as bindings: { $transition$: '<' } inside app/portainer/__module.js + // because this view is not using a component (https://ui-router.github.io/guide/ng1/route-to-component#accessing-transition) + // and will cause + // >> Error: Cannot combine: component|bindings|componentProvider + // >> with: templateProvider|templateUrl|template|notify|async|controller|controllerProvider|controllerAs|resolveAs + // >> in stateview: 'content@@portainer.endpoints.endpoint.kubernetesConfig' /* @ngInject */ constructor( $async, $state, - $stateParams, + $transition$, Notifications, KubernetesStorageService, EndpointService, @@ -24,7 +32,7 @@ class KubernetesConfigureController { ) { this.$async = $async; this.$state = $state; - this.$stateParams = $stateParams; + this.$transition$ = $transition$; this.Notifications = Notifications; this.KubernetesStorageService = KubernetesStorageService; this.EndpointService = EndpointService; @@ -210,7 +218,7 @@ class KubernetesConfigureController { actionInProgress: false, displayConfigureClassPanel: {}, viewReady: false, - endpointId: this.$stateParams.id, + endpointId: this.$transition$.params().id, duplicates: { ingressClasses: new KubernetesFormValidationReferences(), }, diff --git a/app/portainer/services/endpointProvider.js b/app/portainer/services/endpointProvider.js index 1a49f1321..ea18ca01d 100644 --- a/app/portainer/services/endpointProvider.js +++ b/app/portainer/services/endpointProvider.js @@ -1,8 +1,9 @@ import _ from 'lodash-es'; -angular.module('portainer.app').factory('EndpointProvider', [ - 'LocalStorage', - function EndpointProviderFactory(LocalStorage) { +angular.module('portainer.app').factory( + 'EndpointProvider', + /* @ngInject */ + function EndpointProviderFactory(LocalStorage, $uiRouterGlobals) { 'use strict'; var service = {}; var endpoint = {}; @@ -36,9 +37,36 @@ angular.module('portainer.app').factory('EndpointProvider', [ if (endpoint.ID === undefined) { endpoint.ID = LocalStorage.getEndpointID(); } + if (endpoint.ID === null || endpoint.ID === undefined) { + return service.getUrlEndpointID(); + } return endpoint.ID; }; + // TODO: technical debt + // Reference issue: JIRA CE-463 + // Documentation (https://ui-router.github.io/ng1/docs/latest/modules/injectables.html) show the usage of either + // * $stateParams + // * $transition$ + // * $uiRouterGlobals + // to retrieve the URL params + // + // * $stateParams: is deprecated and will cause a circular dependency injection error + // because EndpointProvider is used by EndpointStatusInterceptor which is injected inside $httpProvider + // >> [$injector:cdep] Circular dependency found: $uiRouter <- $stateParams <- EndpointProvider <- EndpointStatusInterceptor <- $http <- $uiRouter + // For more details, see https://stackoverflow.com/questions/20230691/injecting-state-ui-router-into-http-interceptor-causes-circular-dependency#20230786 + // + // * $transition$: mentionned as the replacement of $stateParams (https://ui-router.github.io/guide/ng1/migrate-to-1_0#stateparams-deprecation) + // but is not injectable without tweaks inside a service + // + // * $uiRouterGlobal: per https://github.com/angular-ui/ui-router/issues/3237#issuecomment-271979688 + // seems the recommanded way to retrieve params inside a service/factory + // + // We need this function to fallback on URL endpoint ID when no endpoint has been selected + service.getUrlEndpointID = () => { + return $uiRouterGlobals.params.id; + }; + service.setEndpointID = function (id) { endpoint.ID = id; LocalStorage.storeEndpointID(id); @@ -88,5 +116,5 @@ angular.module('portainer.app').factory('EndpointProvider', [ }; return service; - }, -]); + } +);