mirror of https://github.com/portainer/portainer
				
				
				
			feat(config): add base url support EE-506 (#5999)
							parent
							
								
									335f951e6b
								
							
						
					
					
						commit
						4aea5690a8
					
				| 
						 | 
				
			
			@ -55,6 +55,7 @@ func (*Service) ParseFlags(version string) (*portainer.CLIFlags, error) {
 | 
			
		|||
		Labels:                    pairs(kingpin.Flag("hide-label", "Hide containers with a specific label in the UI").Short('l')),
 | 
			
		||||
		Logo:                      kingpin.Flag("logo", "URL for the logo displayed in the UI").String(),
 | 
			
		||||
		Templates:                 kingpin.Flag("templates", "URL to the templates definitions.").Short('t').String(),
 | 
			
		||||
		BaseURL:                   kingpin.Flag("base-url", "Base URL parameter such as portainer if running portainer as http://yourdomain.com/portainer/.").Short('b').Default(defaultBaseURL).String(),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	kingpin.Parse()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,4 +19,5 @@ const (
 | 
			
		|||
	defaultSSLCertPath         = "/certs/portainer.crt"
 | 
			
		||||
	defaultSSLKeyPath          = "/certs/portainer.key"
 | 
			
		||||
	defaultSnapshotInterval    = "5m"
 | 
			
		||||
	defaultBaseURL             = "/"
 | 
			
		||||
)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,4 +17,5 @@ const (
 | 
			
		|||
	defaultSSLCertPath         = "C:\\certs\\portainer.crt"
 | 
			
		||||
	defaultSSLKeyPath          = "C:\\certs\\portainer.key"
 | 
			
		||||
	defaultSnapshotInterval    = "5m"
 | 
			
		||||
	defaultBaseURL             = "/"
 | 
			
		||||
)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -653,6 +653,7 @@ func buildServer(flags *portainer.CLIFlags) portainer.Server {
 | 
			
		|||
		ShutdownCtx:                 shutdownCtx,
 | 
			
		||||
		ShutdownTrigger:             shutdownTrigger,
 | 
			
		||||
		StackDeployer:               stackDeployer,
 | 
			
		||||
		BaseURL:                     *flags.BaseURL,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,15 +21,17 @@ type Handler struct {
 | 
			
		|||
	kubernetesClientFactory *cli.ClientFactory
 | 
			
		||||
	authorizationService    *authorization.Service
 | 
			
		||||
	JwtService              portainer.JWTService
 | 
			
		||||
	BaseURL                 string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewHandler creates a handler to process pre-proxied requests to external APIs.
 | 
			
		||||
func NewHandler(bouncer *security.RequestBouncer, authorizationService *authorization.Service, dataStore portainer.DataStore, kubernetesClientFactory *cli.ClientFactory) *Handler {
 | 
			
		||||
func NewHandler(bouncer *security.RequestBouncer, authorizationService *authorization.Service, dataStore portainer.DataStore, kubernetesClientFactory *cli.ClientFactory, baseURL string) *Handler {
 | 
			
		||||
	h := &Handler{
 | 
			
		||||
		Router:                  mux.NewRouter(),
 | 
			
		||||
		dataStore:               dataStore,
 | 
			
		||||
		kubernetesClientFactory: kubernetesClientFactory,
 | 
			
		||||
		authorizationService:    authorizationService,
 | 
			
		||||
		BaseURL:                 baseURL,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	kubeRouter := h.PathPrefix("/kubernetes").Subrouter()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,6 +4,7 @@ import (
 | 
			
		|||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	clientV1 "k8s.io/client-go/tools/clientcmd/api/v1"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -133,7 +134,7 @@ func (handler *Handler) buildConfig(r *http.Request, tokenData *portainer.TokenD
 | 
			
		|||
			return nil, &httperror.HandlerError{http.StatusInternalServerError, fmt.Sprintf("unable to find serviceaccount associated with user; username=%s", tokenData.Username), err}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		configClusters[idx] = buildCluster(r, endpoint)
 | 
			
		||||
		configClusters[idx] = buildCluster(r, handler.BaseURL, endpoint)
 | 
			
		||||
		configContexts[idx] = buildContext(serviceAccount.Name, endpoint)
 | 
			
		||||
		if !authInfosSet[serviceAccount.Name] {
 | 
			
		||||
			configAuthInfos = append(configAuthInfos, buildAuthInfo(serviceAccount.Name, bearerToken))
 | 
			
		||||
| 
						 | 
				
			
			@ -151,8 +152,11 @@ func (handler *Handler) buildConfig(r *http.Request, tokenData *portainer.TokenD
 | 
			
		|||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func buildCluster(r *http.Request, endpoint portainer.Endpoint) clientV1.NamedCluster {
 | 
			
		||||
	proxyURL := fmt.Sprintf("https://%s/api/endpoints/%d/kubernetes", r.Host, endpoint.ID)
 | 
			
		||||
func buildCluster(r *http.Request, baseURL string, endpoint portainer.Endpoint) clientV1.NamedCluster {
 | 
			
		||||
	if baseURL != "/" {
 | 
			
		||||
		baseURL = fmt.Sprintf("/%s/", strings.Trim(baseURL, "/"))
 | 
			
		||||
	}
 | 
			
		||||
	proxyURL := fmt.Sprintf("https://%s%sapi/endpoints/%d/kubernetes", r.Host, baseURL, endpoint.ID)
 | 
			
		||||
	return clientV1.NamedCluster{
 | 
			
		||||
		Name: buildClusterName(endpoint.Name),
 | 
			
		||||
		Cluster: clientV1.Cluster{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -96,6 +96,7 @@ type Server struct {
 | 
			
		|||
	ShutdownCtx                 context.Context
 | 
			
		||||
	ShutdownTrigger             context.CancelFunc
 | 
			
		||||
	StackDeployer               stackdeployer.StackDeployer
 | 
			
		||||
	BaseURL string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Start starts the HTTP server
 | 
			
		||||
| 
						 | 
				
			
			@ -172,7 +173,7 @@ func (server *Server) Start() error {
 | 
			
		|||
	endpointProxyHandler.ProxyManager = server.ProxyManager
 | 
			
		||||
	endpointProxyHandler.ReverseTunnelService = server.ReverseTunnelService
 | 
			
		||||
 | 
			
		||||
	var kubernetesHandler = kubehandler.NewHandler(requestBouncer, server.AuthorizationService, server.DataStore, server.KubernetesClientFactory)
 | 
			
		||||
	var kubernetesHandler = kubehandler.NewHandler(requestBouncer, server.AuthorizationService, server.DataStore, server.KubernetesClientFactory, server.BaseURL)
 | 
			
		||||
	kubernetesHandler.JwtService = server.JWTService
 | 
			
		||||
 | 
			
		||||
	var fileHandler = file.NewHandler(filepath.Join(server.AssetsPath, "public"))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -95,6 +95,7 @@ type (
 | 
			
		|||
		SSLKey                    *string
 | 
			
		||||
		Rollback                  *bool
 | 
			
		||||
		SnapshotInterval          *string
 | 
			
		||||
		BaseURL                   *string
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// CustomTemplate represents a custom template
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,5 @@
 | 
			
		|||
import { Terminal } from 'xterm';
 | 
			
		||||
import { baseHref } from '@/portainer/helpers/pathHelper';
 | 
			
		||||
 | 
			
		||||
angular.module('portainer.docker').controller('ContainerConsoleController', [
 | 
			
		||||
  '$scope',
 | 
			
		||||
| 
						 | 
				
			
			@ -69,7 +70,8 @@ angular.module('portainer.docker').controller('ContainerConsoleController', [
 | 
			
		|||
          };
 | 
			
		||||
 | 
			
		||||
          var url =
 | 
			
		||||
            window.location.href.split('#')[0] +
 | 
			
		||||
            window.location.origin +
 | 
			
		||||
            baseHref() +
 | 
			
		||||
            'api/websocket/attach?' +
 | 
			
		||||
            Object.keys(params)
 | 
			
		||||
              .map((k) => k + '=' + params[k])
 | 
			
		||||
| 
						 | 
				
			
			@ -109,7 +111,8 @@ angular.module('portainer.docker').controller('ContainerConsoleController', [
 | 
			
		|||
          };
 | 
			
		||||
 | 
			
		||||
          var url =
 | 
			
		||||
            window.location.href.split('#')[0] +
 | 
			
		||||
            window.location.origin +
 | 
			
		||||
            baseHref() +
 | 
			
		||||
            'api/websocket/exec?' +
 | 
			
		||||
            Object.keys(params)
 | 
			
		||||
              .map((k) => k + '=' + params[k])
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,9 +19,7 @@
 | 
			
		|||
          </div>
 | 
			
		||||
          <div class="form-group">
 | 
			
		||||
            <div class="col-sm-12">
 | 
			
		||||
              <button type="button" class="btn btn-sm btn-primary" ngf-select ngf-min-size="10" ng-model="formValues.UploadFile"
 | 
			
		||||
                >Select file</button
 | 
			
		||||
              >
 | 
			
		||||
              <button type="button" class="btn btn-sm btn-primary" ngf-select ngf-min-size="10" ng-model="formValues.UploadFile">Select file</button>
 | 
			
		||||
              <span style="margin-left: 5px;">
 | 
			
		||||
                {{ formValues.UploadFile.name }}
 | 
			
		||||
                <i class="fa fa-times red-icon" ng-if="!formValues.UploadFile" aria-hidden="true"></i>
 | 
			
		||||
| 
						 | 
				
			
			@ -42,16 +40,16 @@
 | 
			
		|||
              <rd-widget>
 | 
			
		||||
                <rd-widget-header icon="fa-tag" title-text="Tag the image"></rd-widget-header>
 | 
			
		||||
                <rd-widget-body>
 | 
			
		||||
                    <!-- image-and-registry -->
 | 
			
		||||
                    <por-image-registry
 | 
			
		||||
                      model="formValues.RegistryModel"
 | 
			
		||||
                      label-class="col-sm-1"
 | 
			
		||||
                      input-class="col-sm-11"
 | 
			
		||||
                      endpoint="endpoint"
 | 
			
		||||
                      is-admin="isAdmin"
 | 
			
		||||
                      set-validity="setPullImageValidity"
 | 
			
		||||
                      check-rate-limits="true"
 | 
			
		||||
                    ></por-image-registry>
 | 
			
		||||
                  <!-- image-and-registry -->
 | 
			
		||||
                  <por-image-registry
 | 
			
		||||
                    model="formValues.RegistryModel"
 | 
			
		||||
                    label-class="col-sm-1"
 | 
			
		||||
                    input-class="col-sm-11"
 | 
			
		||||
                    endpoint="endpoint"
 | 
			
		||||
                    is-admin="isAdmin"
 | 
			
		||||
                    set-validity="setPullImageValidity"
 | 
			
		||||
                    check-rate-limits="true"
 | 
			
		||||
                  ></por-image-registry>
 | 
			
		||||
                </rd-widget-body>
 | 
			
		||||
              </rd-widget>
 | 
			
		||||
            </div>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,6 +5,12 @@
 | 
			
		|||
    <title>Portainer</title>
 | 
			
		||||
    <meta name="description" content="" />
 | 
			
		||||
    <meta name="author" content="<%= author %>" />
 | 
			
		||||
    <base id="base" />
 | 
			
		||||
    <script>
 | 
			
		||||
      var path = window.location.pathname.replace(/^\/+|\/+$/g, '');
 | 
			
		||||
      var basePath = path ? '/' + path + '/' : '/';
 | 
			
		||||
      document.getElementById('base').href = basePath;
 | 
			
		||||
    </script>
 | 
			
		||||
 | 
			
		||||
    <!-- HTML5 shim, for IE6-8 support of HTML5 elements -->
 | 
			
		||||
    <!--[if lt IE 9]>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,6 @@
 | 
			
		|||
import { Terminal } from 'xterm';
 | 
			
		||||
import * as fit from 'xterm/lib/addons/fit/fit';
 | 
			
		||||
import { baseHref } from '@/portainer/helpers/pathHelper';
 | 
			
		||||
 | 
			
		||||
export default class KubectlShellController {
 | 
			
		||||
  /* @ngInject */
 | 
			
		||||
| 
						 | 
				
			
			@ -91,7 +92,7 @@ export default class KubectlShellController {
 | 
			
		|||
    };
 | 
			
		||||
 | 
			
		||||
    const wsProtocol = this.$window.location.protocol === 'https:' ? 'wss://' : 'ws://';
 | 
			
		||||
    const path = '/api/websocket/kubernetes-shell';
 | 
			
		||||
    const path = baseHref() + 'api/websocket/kubernetes-shell';
 | 
			
		||||
    const queryParams = Object.entries(params)
 | 
			
		||||
      .map(([k, v]) => `${k}=${v}`)
 | 
			
		||||
      .join('&');
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,6 @@
 | 
			
		|||
import angular from 'angular';
 | 
			
		||||
import { Terminal } from 'xterm';
 | 
			
		||||
import { baseHref } from '@/portainer/helpers/pathHelper';
 | 
			
		||||
 | 
			
		||||
class KubernetesApplicationConsoleController {
 | 
			
		||||
  /* @ngInject */
 | 
			
		||||
| 
						 | 
				
			
			@ -59,7 +60,8 @@ class KubernetesApplicationConsoleController {
 | 
			
		|||
    };
 | 
			
		||||
 | 
			
		||||
    let url =
 | 
			
		||||
      window.location.href.split('#')[0] +
 | 
			
		||||
      window.location.origin +
 | 
			
		||||
      baseHref() +
 | 
			
		||||
      'api/websocket/pod?' +
 | 
			
		||||
      Object.keys(params)
 | 
			
		||||
        .map((k) => k + '=' + params[k])
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,9 +11,7 @@ interface InputGroupSubComponents {
 | 
			
		|||
  NumberInput: typeof NumberInput;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const InputGroup: typeof MainComponent &
 | 
			
		||||
  InputGroupSubComponents = MainComponent as typeof MainComponent &
 | 
			
		||||
  InputGroupSubComponents;
 | 
			
		||||
const InputGroup: typeof MainComponent & InputGroupSubComponents = MainComponent as typeof MainComponent & InputGroupSubComponents;
 | 
			
		||||
 | 
			
		||||
InputGroup.Addon = InputGroupAddon;
 | 
			
		||||
InputGroup.ButtonWrapper = InputGroupButtonWrapper;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,18 +2,7 @@ import { arrayMove } from './utils';
 | 
			
		|||
 | 
			
		||||
it('moves items in an array', () => {
 | 
			
		||||
  expect(arrayMove(['a', 'b', 'c'], 2, 0)).toEqual(['c', 'a', 'b']);
 | 
			
		||||
  expect(
 | 
			
		||||
    arrayMove(
 | 
			
		||||
      [
 | 
			
		||||
        { name: 'Fred' },
 | 
			
		||||
        { name: 'Barney' },
 | 
			
		||||
        { name: 'Wilma' },
 | 
			
		||||
        { name: 'Betty' },
 | 
			
		||||
      ],
 | 
			
		||||
      2,
 | 
			
		||||
      1
 | 
			
		||||
    )
 | 
			
		||||
  ).toEqual([
 | 
			
		||||
  expect(arrayMove([{ name: 'Fred' }, { name: 'Barney' }, { name: 'Wilma' }, { name: 'Betty' }], 2, 1)).toEqual([
 | 
			
		||||
    { name: 'Fred' },
 | 
			
		||||
    { name: 'Wilma' },
 | 
			
		||||
    { name: 'Barney' },
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,23 +10,13 @@ export function arrayMove<T>(array: Array<T>, from: number, to: number) {
 | 
			
		|||
 | 
			
		||||
  if (diff > 0) {
 | 
			
		||||
    // move left
 | 
			
		||||
    return [
 | 
			
		||||
      ...array.slice(0, to),
 | 
			
		||||
      item,
 | 
			
		||||
      ...array.slice(to, from),
 | 
			
		||||
      ...array.slice(from + 1, length),
 | 
			
		||||
    ];
 | 
			
		||||
    return [...array.slice(0, to), item, ...array.slice(to, from), ...array.slice(from + 1, length)];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (diff < 0) {
 | 
			
		||||
    // move right
 | 
			
		||||
    const targetIndex = to + 1;
 | 
			
		||||
    return [
 | 
			
		||||
      ...array.slice(0, from),
 | 
			
		||||
      ...array.slice(from + 1, targetIndex),
 | 
			
		||||
      item,
 | 
			
		||||
      ...array.slice(targetIndex, length),
 | 
			
		||||
    ];
 | 
			
		||||
    return [...array.slice(0, from), ...array.slice(from + 1, targetIndex), item, ...array.slice(targetIndex, length)];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return [...array];
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,10 @@
 | 
			
		|||
/**
 | 
			
		||||
 * calculates baseHref
 | 
			
		||||
 *
 | 
			
		||||
 * return [string]
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
export function baseHref() {
 | 
			
		||||
  const base = document.getElementById('base');
 | 
			
		||||
  return base ? base.getAttribute('href') : '/';
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,3 +1,5 @@
 | 
			
		|||
import { baseHref } from '@/portainer/helpers/pathHelper';
 | 
			
		||||
 | 
			
		||||
angular.module('portainer.app').factory('WebhookHelper', [
 | 
			
		||||
  '$location',
 | 
			
		||||
  'API_ENDPOINT_WEBHOOKS',
 | 
			
		||||
| 
						 | 
				
			
			@ -11,11 +13,11 @@ angular.module('portainer.app').factory('WebhookHelper', [
 | 
			
		|||
    const displayPort = (protocol === 'http' && port === 80) || (protocol === 'https' && port === 443) ? '' : ':' + port;
 | 
			
		||||
 | 
			
		||||
    helper.returnWebhookUrl = function (token) {
 | 
			
		||||
      return `${protocol}://${$location.host()}${displayPort}/${API_ENDPOINT_WEBHOOKS}/${token}`;
 | 
			
		||||
      return `${protocol}://${$location.host()}${displayPort}${baseHref()}${API_ENDPOINT_WEBHOOKS}/${token}`;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    helper.returnStackWebhookUrl = function (token) {
 | 
			
		||||
      return `${protocol}://${$location.host()}${displayPort}/${API_ENDPOINT_STACKS}/webhooks/${token}`;
 | 
			
		||||
      return `${protocol}://${$location.host()}${displayPort}${baseHref()}${API_ENDPOINT_STACKS}/webhooks/${token}`;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    return helper;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,5 @@
 | 
			
		|||
import { HIDE_INTERNAL_AUTH } from '@/portainer/feature-flags/feature-ids';
 | 
			
		||||
import { baseHref } from '@/portainer/helpers/pathHelper';
 | 
			
		||||
 | 
			
		||||
import providers, { getProviderByUrl } from './providers';
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -95,7 +96,7 @@ export default class OAuthSettingsController {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    if (this.settings.RedirectURI === '') {
 | 
			
		||||
      this.settings.RedirectURI = window.location.origin;
 | 
			
		||||
      this.settings.RedirectURI = window.location.origin + baseHref();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (this.settings.AuthorizationURI) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,9 +1,11 @@
 | 
			
		|||
import { baseHref } from '@/portainer/helpers/pathHelper';
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  microsoft: {
 | 
			
		||||
    authUrl: 'https://login.microsoftonline.com/TENANT_ID/oauth2/authorize',
 | 
			
		||||
    accessTokenUrl: 'https://login.microsoftonline.com/TENANT_ID/oauth2/token',
 | 
			
		||||
    resourceUrl: 'https://graph.windows.net/TENANT_ID/me?api-version=2013-11-08',
 | 
			
		||||
    logoutUrl: `https://login.microsoftonline.com/common/oauth2/v2.0/logout?post_logout_redirect_uri=${window.location.origin}/#!/auth`,
 | 
			
		||||
    logoutUrl: `https://login.microsoftonline.com/common/oauth2/v2.0/logout?post_logout_redirect_uri=${window.location.origin}${baseHref()}#!/auth`,
 | 
			
		||||
    userIdentifier: 'userPrincipalName',
 | 
			
		||||
    scopes: 'id,email,name',
 | 
			
		||||
  },
 | 
			
		||||
| 
						 | 
				
			
			@ -11,7 +13,7 @@ export default {
 | 
			
		|||
    authUrl: 'https://accounts.google.com/o/oauth2/auth',
 | 
			
		||||
    accessTokenUrl: 'https://accounts.google.com/o/oauth2/token',
 | 
			
		||||
    resourceUrl: 'https://www.googleapis.com/oauth2/v1/userinfo?alt=json',
 | 
			
		||||
    logoutUrl: `https://www.google.com/accounts/Logout?continue=https://appengine.google.com/_ah/logout?continue=${window.location.origin}/#!/auth`,
 | 
			
		||||
    logoutUrl: `https://www.google.com/accounts/Logout?continue=https://appengine.google.com/_ah/logout?continue=${window.location.origin}${baseHref()}#!/auth`,
 | 
			
		||||
    userIdentifier: 'email',
 | 
			
		||||
    scopes: 'profile email',
 | 
			
		||||
  },
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,6 @@
 | 
			
		|||
import { PortainerEndpointCreationTypes, PortainerEndpointTypes } from 'Portainer/models/endpoint/models';
 | 
			
		||||
import { getAgentShortVersion } from 'Portainer/views/endpoints/helpers';
 | 
			
		||||
import { baseHref } from '@/portainer/helpers/pathHelper';
 | 
			
		||||
import { EndpointSecurityFormData } from '../../../components/endpointSecurity/porEndpointSecurityModel';
 | 
			
		||||
 | 
			
		||||
angular
 | 
			
		||||
| 
						 | 
				
			
			@ -84,7 +85,8 @@ angular
 | 
			
		|||
    };
 | 
			
		||||
 | 
			
		||||
    $scope.setDefaultPortainerInstanceURL = function () {
 | 
			
		||||
      $scope.formValues.URL = window.location.origin;
 | 
			
		||||
      const baseHREF = baseHref();
 | 
			
		||||
      $scope.formValues.URL = window.location.origin + (baseHREF !== '/' ? baseHREF : '');
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    $scope.resetEndpointURL = function () {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue