diff --git a/app/agent/components/host-browser/hostBrowserController.js b/app/agent/components/host-browser/hostBrowserController.js index e1fcc998d..22f18960e 100644 --- a/app/agent/components/host-browser/hostBrowserController.js +++ b/app/agent/components/host-browser/hostBrowserController.js @@ -52,7 +52,7 @@ export class HostBrowserController { } async getFilesForPathAsync(path) { try { - const files = await this.HostBrowserService.ls(path); + const files = await this.HostBrowserService.ls(this.endpointId, path); this.state.path = path; this.files = files; } catch (err) { @@ -67,9 +67,9 @@ export class HostBrowserController { const filePath = this.buildPath(this.state.path, name); const newFilePath = this.buildPath(this.state.path, newName); try { - await this.HostBrowserService.rename(filePath, newFilePath); + await this.HostBrowserService.rename(this.endpointId, filePath, newFilePath); this.Notifications.success('File successfully renamed', this.getRelativePath(newFilePath)); - const files = await this.HostBrowserService.ls(this.state.path); + const files = await this.HostBrowserService.ls(this.endpointId, this.state.path); this.files = files; } catch (err) { this.Notifications.error('Failure', err, 'Unable to rename file'); @@ -82,7 +82,7 @@ export class HostBrowserController { async downloadFileAsync(fileName) { const filePath = this.buildPath(this.state.path, fileName); try { - const { file } = await this.HostBrowserService.get(filePath); + const { file } = await this.HostBrowserService.get(this.endpointId, filePath); const downloadData = new Blob([file], { type: 'text/plain;charset=utf-8', }); @@ -108,9 +108,9 @@ export class HostBrowserController { } async deleteFileAsync(path) { try { - await this.HostBrowserService.delete(path); + await this.HostBrowserService.delete(this.endpointId, path); this.Notifications.success('File successfully deleted', this.getRelativePath(path)); - const files = await this.HostBrowserService.ls(this.state.path); + const files = await this.HostBrowserService.ls(this.endpointId, this.state.path); this.files = files; } catch (err) { this.Notifications.error('Failure', err, 'Unable to delete file'); diff --git a/app/agent/components/node-selector/index.js b/app/agent/components/node-selector/index.js index 140319c8a..a489f99cf 100644 --- a/app/agent/components/node-selector/index.js +++ b/app/agent/components/node-selector/index.js @@ -7,5 +7,6 @@ angular.module('portainer.agent').component('nodeSelector', { controller: NodeSelectorController, bindings: { model: '=', + endpointId: '<', }, }); diff --git a/app/agent/components/node-selector/nodeSelectorController.js b/app/agent/components/node-selector/nodeSelectorController.js index f45908886..26cd5bd3b 100644 --- a/app/agent/components/node-selector/nodeSelectorController.js +++ b/app/agent/components/node-selector/nodeSelectorController.js @@ -6,7 +6,7 @@ export class NodeSelectorController { async $onInit() { try { - const agents = await this.AgentService.agents(); + const agents = await this.AgentService.agents(this.endpointId); this.agents = agents; if (!this.model) { this.model = agents[0].NodeName; diff --git a/app/agent/components/volume-browser/volumeBrowserController.js b/app/agent/components/volume-browser/volumeBrowserController.js index 239ceae6d..61524f5cb 100644 --- a/app/agent/components/volume-browser/volumeBrowserController.js +++ b/app/agent/components/volume-browser/volumeBrowserController.js @@ -36,9 +36,9 @@ export class VolumeBrowserController { const newFilePath = this.state.path === '/' ? newName : `${this.state.path}/${newName}`; try { - await this.VolumeBrowserService.rename(this.volumeId, filePath, newFilePath); + await this.VolumeBrowserService.rename(this.endpointId, this.volumeId, filePath, newFilePath); this.Notifications.success('File successfully renamed', newFilePath); - this.files = await this.VolumeBrowserService.ls(this.volumeId, this.state.path); + this.files = await this.VolumeBrowserService.ls(this.endpointId, this.volumeId, this.state.path); } catch (err) { this.Notifications.error('Failure', err, 'Unable to rename file'); } @@ -62,7 +62,7 @@ export class VolumeBrowserController { const filePath = this.state.path === '/' ? file : `${this.state.path}/${file}`; try { - const data = await this.VolumeBrowserService.get(this.volumeId, filePath); + const data = await this.VolumeBrowserService.get(this.endpointId, this.volumeId, filePath); const downloadData = new Blob([data.file]); this.FileSaver.saveAs(downloadData, file); } catch (err) { @@ -85,9 +85,9 @@ export class VolumeBrowserController { } async deleteFileAsync(file) { try { - await this.VolumeBrowserService.delete(this.volumeId, file); + await this.VolumeBrowserService.delete(this.endpointId, this.volumeId, file); this.Notifications.success('File successfully deleted', file); - this.files = await this.VolumeBrowserService.ls(this.volumeId, this.state.path); + this.files = await this.VolumeBrowserService.ls(this.endpointId, this.volumeId, this.state.path); } catch (err) { this.Notifications.error('Failure', err, 'Unable to delete file'); } @@ -98,7 +98,7 @@ export class VolumeBrowserController { } async getFilesForPathAsync(path) { try { - const files = await this.VolumeBrowserService.ls(this.volumeId, path); + const files = await this.VolumeBrowserService.ls(this.endpointId, this.volumeId, path); this.state.path = path; this.files = files; } catch (err) { @@ -145,7 +145,7 @@ export class VolumeBrowserController { async $onInit() { this.HttpRequestHelper.setPortainerAgentTargetHeader(this.nodeName); try { - this.files = await this.VolumeBrowserService.ls(this.volumeId, this.state.path); + this.files = await this.VolumeBrowserService.ls(this.endpointId, this.volumeId, this.state.path); } catch (err) { this.Notifications.error('Failure', err, 'Unable to browse volume'); } diff --git a/app/agent/rest/agent.js b/app/agent/rest/agent.js index 00267ce00..fc93a5207 100644 --- a/app/agent/rest/agent.js +++ b/app/agent/rest/agent.js @@ -2,11 +2,10 @@ import angular from 'angular'; angular.module('portainer.agent').factory('Agent', AgentFactory); -function AgentFactory($resource, API_ENDPOINT_ENDPOINTS, EndpointProvider, StateManager) { +function AgentFactory($resource, API_ENDPOINT_ENDPOINTS, StateManager) { return $resource( `${API_ENDPOINT_ENDPOINTS}/:endpointId/docker/v:version/agents`, { - endpointId: EndpointProvider.endpointID, version: StateManager.getAgentApiVersion, }, { diff --git a/app/agent/rest/browse.js b/app/agent/rest/browse.js index 66f8329d5..d31b31503 100644 --- a/app/agent/rest/browse.js +++ b/app/agent/rest/browse.js @@ -4,11 +4,10 @@ import { browseGetResponse } from './response/browse'; angular.module('portainer.agent').factory('Browse', BrowseFactory); -function BrowseFactory($resource, API_ENDPOINT_ENDPOINTS, EndpointProvider, StateManager) { +function BrowseFactory($resource, API_ENDPOINT_ENDPOINTS, StateManager) { return $resource( `${API_ENDPOINT_ENDPOINTS}/:endpointId/docker/v:version/browse/:action`, { - endpointId: EndpointProvider.endpointID, version: StateManager.getAgentApiVersion, }, { diff --git a/app/agent/rest/host.js b/app/agent/rest/host.js index cd79b9763..daed21caf 100644 --- a/app/agent/rest/host.js +++ b/app/agent/rest/host.js @@ -2,11 +2,10 @@ import angular from 'angular'; angular.module('portainer.agent').factory('Host', HostFactory); -function HostFactory($resource, API_ENDPOINT_ENDPOINTS, EndpointProvider, StateManager) { +function HostFactory($resource, API_ENDPOINT_ENDPOINTS, StateManager) { return $resource( `${API_ENDPOINT_ENDPOINTS}/:endpointId/docker/v:version/host/:action`, { - endpointId: EndpointProvider.endpointID, version: StateManager.getAgentApiVersion, }, { diff --git a/app/agent/rest/ping.js b/app/agent/rest/ping.js index 8726cd8d6..91cb559ab 100644 --- a/app/agent/rest/ping.js +++ b/app/agent/rest/ping.js @@ -2,12 +2,10 @@ import angular from 'angular'; angular.module('portainer.agent').factory('AgentPing', AgentPingFactory); -function AgentPingFactory($resource, API_ENDPOINT_ENDPOINTS, EndpointProvider, $q) { +function AgentPingFactory($resource, API_ENDPOINT_ENDPOINTS, $q) { return $resource( `${API_ENDPOINT_ENDPOINTS}/:endpointId/docker/ping`, - { - endpointId: EndpointProvider.endpointID, - }, + {}, { ping: { method: 'GET', diff --git a/app/agent/rest/v1/agent.js b/app/agent/rest/v1/agent.js index d42a3fb44..2b69ea5fe 100644 --- a/app/agent/rest/v1/agent.js +++ b/app/agent/rest/v1/agent.js @@ -2,12 +2,10 @@ import angular from 'angular'; angular.module('portainer.agent').factory('AgentVersion1', AgentFactory); -function AgentFactory($resource, API_ENDPOINT_ENDPOINTS, EndpointProvider) { +function AgentFactory($resource, API_ENDPOINT_ENDPOINTS) { return $resource( `${API_ENDPOINT_ENDPOINTS}/:endpointId/docker/agents`, - { - endpointId: EndpointProvider.endpointID, - }, + {}, { query: { method: 'GET', isArray: true }, } diff --git a/app/agent/rest/v1/browse.js b/app/agent/rest/v1/browse.js index cfc06128c..f19218540 100644 --- a/app/agent/rest/v1/browse.js +++ b/app/agent/rest/v1/browse.js @@ -4,12 +4,10 @@ import { browseGetResponse } from '../response/browse'; angular.module('portainer.agent').factory('BrowseVersion1', BrowseFactory); -function BrowseFactory($resource, API_ENDPOINT_ENDPOINTS, EndpointProvider) { +function BrowseFactory($resource, API_ENDPOINT_ENDPOINTS) { return $resource( `${API_ENDPOINT_ENDPOINTS}/:endpointId/docker/browse/:volumeID/:action`, - { - endpointId: EndpointProvider.endpointID, - }, + {}, { ls: { method: 'GET', diff --git a/app/agent/services/agentService.js b/app/agent/services/agentService.js index 579cc104b..8dcb06ad8 100644 --- a/app/agent/services/agentService.js +++ b/app/agent/services/agentService.js @@ -15,16 +15,16 @@ function AgentServiceFactory(Agent, AgentVersion1, HttpRequestHelper, Host, Stat return state.endpoint.agentApiVersion; } - function hostInfo(nodeName) { + function hostInfo(endpointId, nodeName) { HttpRequestHelper.setPortainerAgentTargetHeader(nodeName); - return Host.info().$promise; + return Host.info({ endpointId }).$promise; } - async function agents() { + async function agents(endpointId) { const agentVersion = getAgentApiVersion(); const service = agentVersion > 1 ? Agent : AgentVersion1; try { - const agents = await service.query({ version: agentVersion }).$promise; + const agents = await service.query({ version: agentVersion, endpointId }).$promise; return agents.map(function (item) { return new AgentViewModel(item); }); diff --git a/app/agent/services/hostBrowserService.js b/app/agent/services/hostBrowserService.js index f6e6a2808..1c369fc5f 100644 --- a/app/agent/services/hostBrowserService.js +++ b/app/agent/services/hostBrowserService.js @@ -6,24 +6,24 @@ angular.module('portainer.agent').factory('HostBrowserService', HostBrowserServi function HostBrowserServiceFactory(Browse, Upload, API_ENDPOINT_ENDPOINTS, StateManager) { return { ls, get, delete: deletePath, rename, upload }; - function ls(path) { - return Browse.ls({ path: path }).$promise; + function ls(endpointId, path) { + return Browse.ls({ endpointId, path: path }).$promise; } - function get(path) { - return Browse.get({ path: path }).$promise; + function get(endpointId, path) { + return Browse.get({ endpointId, path: path }).$promise; } - function deletePath(path) { - return Browse.delete({ path: path }).$promise; + function deletePath(endpointId, path) { + return Browse.delete({ endpointId, path: path }).$promise; } - function rename(path, newPath) { + function rename(endpointId, path, newPath) { const payload = { CurrentFilePath: path, NewFilePath: newPath, }; - return Browse.rename({}, payload).$promise; + return Browse.rename({ endpointId }, payload).$promise; } function upload(endpointId, Path, file, onProgress) { diff --git a/app/agent/services/pingService.js b/app/agent/services/pingService.js index bd6380912..02d0f577a 100644 --- a/app/agent/services/pingService.js +++ b/app/agent/services/pingService.js @@ -5,7 +5,7 @@ angular.module('portainer.agent').service('AgentPingService', AgentPingService); function AgentPingService(AgentPing) { return { ping }; - function ping() { - return AgentPing.ping().$promise; + function ping(endpointId) { + return AgentPing.ping({ endpointId }).$promise; } } diff --git a/app/agent/services/volumeBrowserService.js b/app/agent/services/volumeBrowserService.js index 29cefcdd3..575696e5b 100644 --- a/app/agent/services/volumeBrowserService.js +++ b/app/agent/services/volumeBrowserService.js @@ -22,24 +22,24 @@ function VolumeBrowserServiceFactory(StateManager, Browse, BrowseVersion1, API_E return agentVersion > 1 ? Browse : BrowseVersion1; } - function ls(volumeId, path) { - return getBrowseService().ls({ volumeID: volumeId, path, version: getAgentApiVersion() }).$promise; + function ls(endpointId, volumeId, path) { + return getBrowseService().ls({ endpointId, volumeID: volumeId, path, version: getAgentApiVersion() }).$promise; } - function get(volumeId, path) { - return getBrowseService().get({ volumeID: volumeId, path, version: getAgentApiVersion() }).$promise; + function get(endpointId, volumeId, path) { + return getBrowseService().get({ endpointId, volumeID: volumeId, path, version: getAgentApiVersion() }).$promise; } - function deletePath(volumeId, path) { - return getBrowseService().delete({ volumeID: volumeId, path, version: getAgentApiVersion() }).$promise; + function deletePath(endpointId, volumeId, path) { + return getBrowseService().delete({ endpointId, volumeID: volumeId, path, version: getAgentApiVersion() }).$promise; } - function rename(volumeId, path, newPath) { + function rename(endpointId, volumeId, path, newPath) { const payload = { CurrentFilePath: path, NewFilePath: newPath, }; - return getBrowseService().rename({ volumeID: volumeId, version: getAgentApiVersion() }, payload).$promise; + return getBrowseService().rename({ endpointId, volumeID: volumeId, version: getAgentApiVersion() }, payload).$promise; } function upload(endpointId, path, file, volumeId, onProgress) { diff --git a/app/app.js b/app/app.js index 5476a3734..ae4adf5f1 100644 --- a/app/app.js +++ b/app/app.js @@ -1,10 +1,7 @@ import $ from 'jquery'; -import { PortainerEndpointTypes } from 'Portainer/models/endpoint/models'; /* @ngInject */ -export function onStartupAngular($rootScope, $state, $interval, LocalStorage, EndpointProvider, SystemService, cfpLoadingBar, $transitions, HttpRequestHelper) { - EndpointProvider.initialize(); - +export function onStartupAngular($rootScope, $state, LocalStorage, cfpLoadingBar, $transitions, HttpRequestHelper, EndpointProvider) { $rootScope.$state = $state; const defaultTitle = document.title; @@ -26,11 +23,6 @@ export function onStartupAngular($rootScope, $state, $interval, LocalStorage, En HttpRequestHelper.resetAgentHeaders(); }); - // Keep-alive Edge endpoints by sending a ping request every minute - $interval(() => { - ping(EndpointProvider, SystemService); - }, 60 * 1000); - $(document).ajaxSend((event, jqXhr, jqOpts) => { const type = jqOpts.type === 'POST' || jqOpts.type === 'PUT' || jqOpts.type === 'PATCH'; const hasNoContentType = jqOpts.contentType !== 'application/json' && jqOpts.headers && !jqOpts.headers['Content-Type']; @@ -40,10 +32,3 @@ export function onStartupAngular($rootScope, $state, $interval, LocalStorage, En jqXhr.setRequestHeader('Authorization', 'Bearer ' + LocalStorage.getJWT()); }); } - -function ping(EndpointProvider, SystemService) { - const endpoint = EndpointProvider.currentEndpoint(); - if (endpoint && endpoint.Type == PortainerEndpointTypes.EdgeAgentOnDockerEnvironment) { - SystemService.ping(endpoint.Id); - } -} diff --git a/app/azure/index.ts b/app/azure/index.ts index a48d33f2f..1d2dd8447 100644 --- a/app/azure/index.ts +++ b/app/azure/index.ts @@ -3,7 +3,7 @@ import { StateRegistry, StateService } from '@uirouter/angularjs'; import { Environment } from '@/react/portainer/environments/types'; import { notifyError } from '@/portainer/services/notifications'; -import { EndpointProvider, StateManager } from '@/portainer/services/types'; +import { StateManager } from '@/portainer/services/types'; import { reactModule } from './react'; @@ -22,7 +22,6 @@ function config($stateRegistryProvider: StateRegistry) { $async: (fn: () => Promise) => Promise, $state: StateService, endpoint: Environment, - EndpointProvider: EndpointProvider, StateManager: StateManager ) { return $async(async () => { @@ -31,9 +30,6 @@ function config($stateRegistryProvider: StateRegistry) { return; } try { - EndpointProvider.setEndpointID(endpoint.Id); - EndpointProvider.setEndpointPublicURL(endpoint.PublicURL); - EndpointProvider.setOfflineModeFromStatus(endpoint.Status); await StateManager.updateEndpointState(endpoint); } catch (e) { notifyError('Failed loading environment', e as Error); diff --git a/app/config.js b/app/config.js index d701ee818..fc72f3d22 100644 --- a/app/config.js +++ b/app/config.js @@ -18,7 +18,7 @@ export function configApp($urlRouterProvider, $httpProvider, localStorageService }); $httpProvider.interceptors.push('jwtInterceptor'); - $httpProvider.interceptors.push('EndpointStatusInterceptor'); + $httpProvider.defaults.headers.post['Content-Type'] = 'application/json'; $httpProvider.defaults.headers.put['Content-Type'] = 'application/json'; $httpProvider.defaults.headers.patch['Content-Type'] = 'application/json'; diff --git a/app/docker/__module.js b/app/docker/__module.js index 59f613677..74e9a80dd 100644 --- a/app/docker/__module.js +++ b/app/docker/__module.js @@ -14,7 +14,7 @@ angular.module('portainer.docker', ['portainer.app', reactModule]).config([ parent: 'endpoint', url: '/docker', abstract: true, - onEnter: /* @ngInject */ function onEnter(endpoint, $async, $state, EndpointService, EndpointProvider, Notifications, StateManager, SystemService) { + onEnter: /* @ngInject */ function onEnter(endpoint, $async, $state, EndpointService, Notifications, StateManager, SystemService) { return $async(async () => { if (![1, 2, 4].includes(endpoint.Type)) { $state.go('portainer.home'); @@ -32,10 +32,6 @@ angular.module('portainer.docker', ['portainer.app', reactModule]).config([ throw new Error('Environment is unreachable.'); } - EndpointProvider.setEndpointID(endpoint.Id); - EndpointProvider.setEndpointPublicURL(endpoint.PublicURL); - EndpointProvider.setOfflineModeFromStatus(endpoint.Status); - await StateManager.updateEndpointState(endpoint); } catch (e) { Notifications.error('Failed loading environment', e); diff --git a/app/docker/components/dashboard-cluster-agent-info/dashboard-cluster-agent-info.js b/app/docker/components/dashboard-cluster-agent-info/dashboard-cluster-agent-info.js index 6498c2edc..9979a8da5 100644 --- a/app/docker/components/dashboard-cluster-agent-info/dashboard-cluster-agent-info.js +++ b/app/docker/components/dashboard-cluster-agent-info/dashboard-cluster-agent-info.js @@ -1,4 +1,7 @@ angular.module('portainer.docker').component('dashboardClusterAgentInfo', { templateUrl: './dashboardClusterAgentInfo.html', controller: 'DashboardClusterAgentInfoController', + bindings: { + endpointId: '<', + }, }); diff --git a/app/docker/components/dashboard-cluster-agent-info/dashboardClusterAgentInfoController.js b/app/docker/components/dashboard-cluster-agent-info/dashboardClusterAgentInfoController.js index 2b421729b..2419181b9 100644 --- a/app/docker/components/dashboard-cluster-agent-info/dashboardClusterAgentInfoController.js +++ b/app/docker/components/dashboard-cluster-agent-info/dashboardClusterAgentInfoController.js @@ -5,7 +5,7 @@ angular.module('portainer.docker').controller('DashboardClusterAgentInfoControll var ctrl = this; this.$onInit = function () { - AgentService.agents() + AgentService.agents(ctrl.endpointId) .then(function success(data) { ctrl.agentCount = data.length; }) diff --git a/app/docker/rest/systemEndpoint.js b/app/docker/rest/systemEndpoint.js deleted file mode 100644 index 2bdad3df3..000000000 --- a/app/docker/rest/systemEndpoint.js +++ /dev/null @@ -1,19 +0,0 @@ -angular.module('portainer.docker').factory('SystemEndpoint', [ - '$resource', - 'API_ENDPOINT_ENDPOINTS', - function SystemEndpointFactory($resource, API_ENDPOINT_ENDPOINTS) { - 'use strict'; - return $resource( - API_ENDPOINT_ENDPOINTS + '/:endpointId/docker/:action/:subAction', - { - name: '@name', - }, - { - ping: { - method: 'GET', - params: { action: '_ping', endpointId: '@endpointId' }, - }, - } - ); - }, -]); diff --git a/app/docker/services/ping.ts b/app/docker/services/ping.ts new file mode 100644 index 000000000..5dad16870 --- /dev/null +++ b/app/docker/services/ping.ts @@ -0,0 +1,10 @@ +import axios, { parseAxiosError } from '@/portainer/services/axios'; +import { EnvironmentId } from '@/react/portainer/environments/types'; + +export async function ping(environmentId: EnvironmentId) { + try { + await axios.get(`/endpoints/${environmentId}/docker/_ping`); + } catch (error) { + throw parseAxiosError(error as Error); + } +} diff --git a/app/docker/services/systemService.js b/app/docker/services/systemService.js index 90ac1168e..b75bff0fc 100644 --- a/app/docker/services/systemService.js +++ b/app/docker/services/systemService.js @@ -1,10 +1,10 @@ import { EventViewModel } from '../models/event'; +import { ping } from './ping'; angular.module('portainer.docker').factory('SystemService', [ '$q', 'System', - 'SystemEndpoint', - function SystemServiceFactory($q, System, SystemEndpoint) { + function SystemServiceFactory($q, System) { 'use strict'; var service = {}; @@ -26,7 +26,7 @@ angular.module('portainer.docker').factory('SystemService', [ }; service.ping = function (endpointId) { - return SystemEndpoint.ping({ endpointId: endpointId }).$promise; + return ping(endpointId); }; service.version = function () { diff --git a/app/docker/views/containers/create/createcontainer.html b/app/docker/views/containers/create/createcontainer.html index 6a3842f6e..58c136883 100644 --- a/app/docker/views/containers/create/createcontainer.html +++ b/app/docker/views/containers/create/createcontainer.html @@ -144,7 +144,7 @@
Deployment
- +
diff --git a/app/docker/views/dashboard/dashboard.html b/app/docker/views/dashboard/dashboard.html index d891ffb42..7097889b7 100644 --- a/app/docker/views/dashboard/dashboard.html +++ b/app/docker/views/dashboard/dashboard.html @@ -2,7 +2,7 @@
- +
diff --git a/app/docker/views/images/build/buildImageController.js b/app/docker/views/images/build/buildImageController.js index fcd2a6aef..1b3b96f2f 100644 --- a/app/docker/views/images/build/buildImageController.js +++ b/app/docker/views/images/build/buildImageController.js @@ -1,7 +1,9 @@ angular.module('portainer.docker').controller('BuildImageController', BuildImageController); /* @ngInject */ -function BuildImageController($scope, $async, $window, ModalService, BuildService, Notifications, HttpRequestHelper) { +function BuildImageController($scope, $async, $window, ModalService, BuildService, Notifications, HttpRequestHelper, endpoint) { + $scope.endpoint = endpoint; + $scope.state = { BuildType: 'editor', actionInProgress: false, diff --git a/app/docker/views/images/build/buildimage.html b/app/docker/views/images/build/buildimage.html index 3e3dea2f8..792a7f4c8 100644 --- a/app/docker/views/images/build/buildimage.html +++ b/app/docker/views/images/build/buildimage.html @@ -220,7 +220,7 @@
Deployment
- +
diff --git a/app/docker/views/images/images.html b/app/docker/views/images/images.html index 715eb444d..c2bd3b0ea 100644 --- a/app/docker/views/images/images.html +++ b/app/docker/views/images/images.html @@ -20,7 +20,7 @@
Deployment
- +
diff --git a/app/docker/views/images/import/importimage.html b/app/docker/views/images/import/importimage.html index acc041acb..b4097e27c 100644 --- a/app/docker/views/images/import/importimage.html +++ b/app/docker/views/images/import/importimage.html @@ -23,7 +23,7 @@
Deployment
- +
diff --git a/app/docker/views/networks/create/createNetworkController.js b/app/docker/views/networks/create/createNetworkController.js index 0d034d796..8c6975138 100644 --- a/app/docker/views/networks/create/createNetworkController.js +++ b/app/docker/views/networks/create/createNetworkController.js @@ -14,7 +14,10 @@ angular.module('portainer.docker').controller('CreateNetworkController', [ 'ResourceControlService', 'FormValidator', 'HttpRequestHelper', - function ($q, $scope, $state, PluginService, Notifications, NetworkService, LabelHelper, Authentication, ResourceControlService, FormValidator, HttpRequestHelper) { + 'endpoint', + function ($q, $scope, $state, PluginService, Notifications, NetworkService, LabelHelper, Authentication, ResourceControlService, FormValidator, HttpRequestHelper, endpoint) { + $scope.endpoint = endpoint; + $scope.formValues = { DriverOptions: [], IPV4: { diff --git a/app/docker/views/networks/create/createnetwork.html b/app/docker/views/networks/create/createnetwork.html index c6cecaae4..89909a162 100644 --- a/app/docker/views/networks/create/createnetwork.html +++ b/app/docker/views/networks/create/createnetwork.html @@ -216,7 +216,7 @@ >
Deployment
- +
diff --git a/app/docker/views/networks/networksController.js b/app/docker/views/networks/networksController.js index 43031bc89..5ae8aa3b2 100644 --- a/app/docker/views/networks/networksController.js +++ b/app/docker/views/networks/networksController.js @@ -66,7 +66,7 @@ angular.module('portainer.docker').controller('NetworksController', [ }; if ($scope.applicationState.endpoint.mode.agentProxy && $scope.applicationState.endpoint.mode.provider === 'DOCKER_SWARM_MODE') { - req.agents = AgentService.agents(); + req.agents = AgentService.agents(endpoint.Id); } $q.all(req) diff --git a/app/docker/views/nodes/node-details/node-details-view-controller.js b/app/docker/views/nodes/node-details/node-details-view-controller.js index c7e1b3478..d3fb439f6 100644 --- a/app/docker/views/nodes/node-details/node-details-view-controller.js +++ b/app/docker/views/nodes/node-details/node-details-view-controller.js @@ -42,7 +42,7 @@ angular.module('portainer.docker').controller('NodeDetailsViewController', [ return; } - AgentService.hostInfo(node.Hostname).then(function onHostInfoLoad(agentHostInfo) { + AgentService.hostInfo(ctrl.endpoint.Id, node.Hostname).then(function onHostInfoLoad(agentHostInfo) { ctrl.devices = agentHostInfo.PCIDevices; ctrl.disks = agentHostInfo.PhysicalDisks; }); diff --git a/app/docker/views/volumes/create/createVolumeController.js b/app/docker/views/volumes/create/createVolumeController.js index 7d23b30c7..f4d68c093 100644 --- a/app/docker/views/volumes/create/createVolumeController.js +++ b/app/docker/views/volumes/create/createVolumeController.js @@ -13,7 +13,10 @@ angular.module('portainer.docker').controller('CreateVolumeController', [ 'Notifications', 'FormValidator', 'HttpRequestHelper', - function ($q, $scope, $state, VolumeService, PluginService, ResourceControlService, Authentication, Notifications, FormValidator, HttpRequestHelper) { + 'endpoint', + function ($q, $scope, $state, VolumeService, PluginService, ResourceControlService, Authentication, Notifications, FormValidator, HttpRequestHelper, endpoint) { + $scope.endpoint = endpoint; + $scope.formValues = { Driver: 'local', DriverOptions: [], diff --git a/app/docker/views/volumes/create/createvolume.html b/app/docker/views/volumes/create/createvolume.html index 39edd55a7..dd3eb7948 100644 --- a/app/docker/views/volumes/create/createvolume.html +++ b/app/docker/views/volumes/create/createvolume.html @@ -72,7 +72,7 @@
Deployment
- +
diff --git a/app/kubernetes/__module.js b/app/kubernetes/__module.js index 4f5d0f5b3..ff8a098a5 100644 --- a/app/kubernetes/__module.js +++ b/app/kubernetes/__module.js @@ -14,7 +14,7 @@ angular.module('portainer.kubernetes', ['portainer.app', registriesModule, custo parent: 'endpoint', abstract: true, - onEnter: /* @ngInject */ function onEnter($async, $state, endpoint, EndpointProvider, KubernetesHealthService, KubernetesNamespaceService, Notifications, StateManager) { + onEnter: /* @ngInject */ function onEnter($async, $state, endpoint, KubernetesHealthService, KubernetesNamespaceService, Notifications, StateManager) { return $async(async () => { if (![5, 6, 7].includes(endpoint.Type)) { $state.go('portainer.home'); @@ -31,7 +31,6 @@ angular.module('portainer.kubernetes', ['portainer.app', registriesModule, custo } } - EndpointProvider.setEndpointID(endpoint.Id); await StateManager.updateEndpointState(endpoint); if (endpoint.Type === 7 && endpoint.Status === 2) { diff --git a/app/kubernetes/components/datatables/resource-pools-datatable/resourcePoolsDatatable.js b/app/kubernetes/components/datatables/resource-pools-datatable/resourcePoolsDatatable.js index aacd0c3c4..93f49255e 100644 --- a/app/kubernetes/components/datatables/resource-pools-datatable/resourcePoolsDatatable.js +++ b/app/kubernetes/components/datatables/resource-pools-datatable/resourcePoolsDatatable.js @@ -2,7 +2,7 @@ angular.module('portainer.kubernetes').component('kubernetesResourcePoolsDatatab templateUrl: './resourcePoolsDatatable.html', controller: 'KubernetesResourcePoolsDatatableController', bindings: { - endpoint: '<', + restrictDefaultNamespace: '<', titleText: '@', titleIcon: '@', dataset: '<', diff --git a/app/kubernetes/components/datatables/resource-pools-datatable/resourcePoolsDatatableController.js b/app/kubernetes/components/datatables/resource-pools-datatable/resourcePoolsDatatableController.js index 46519a99d..f058f39ed 100644 --- a/app/kubernetes/components/datatables/resource-pools-datatable/resourcePoolsDatatableController.js +++ b/app/kubernetes/components/datatables/resource-pools-datatable/resourcePoolsDatatableController.js @@ -19,7 +19,7 @@ angular.module('portainer.docker').controller('KubernetesResourcePoolsDatatableC }; this.canManageAccess = function (item) { - if (!this.endpoint.Kubernetes.Configuration.RestrictDefaultNamespace) { + if (!this.restrictDefaultNamespace) { return !KubernetesNamespaceHelper.isDefaultNamespace(item.Namespace.Name) && !this.isSystemNamespace(item); } else { return !this.isSystemNamespace(item); diff --git a/app/kubernetes/views/configure/configureController.js b/app/kubernetes/views/configure/configureController.js index 080c9a6e0..e42d212a7 100644 --- a/app/kubernetes/views/configure/configureController.js +++ b/app/kubernetes/views/configure/configureController.js @@ -154,8 +154,8 @@ class KubernetesConfigureController { return; } const promises = []; - const oldEndpointID = this.EndpointProvider.endpointID(); - this.EndpointProvider.setEndpointID(this.endpoint.Id); + const oldEndpoint = this.EndpointProvider.currentEndpoint(); + this.EndpointProvider.setCurrentEndpoint(this.endpoint); try { const allResourcePools = await this.KubernetesResourcePoolService.get(); @@ -170,7 +170,7 @@ class KubernetesConfigureController { }); }); } finally { - this.EndpointProvider.setEndpointID(oldEndpointID); + this.EndpointProvider.setCurrentEndpoint(oldEndpoint); } const responses = await Promise.allSettled(promises); @@ -222,13 +222,8 @@ class KubernetesConfigureController { }); await Promise.all(storagePromises); - const endpoints = this.EndpointProvider.endpoints(); - const modifiedEndpoint = _.find(endpoints, (item) => item.Id === this.endpoint.Id); - if (modifiedEndpoint) { - this.assignFormValuesToEndpoint(modifiedEndpoint, storageClasses, ingressClasses); - this.EndpointProvider.setEndpoints(endpoints); - } this.Notifications.success('Success', 'Configuration successfully applied'); + this.$state.go('portainer.home'); } catch (err) { this.Notifications.error('Failure', err, 'Unable to apply configuration'); diff --git a/app/kubernetes/views/resource-pools/resourcePools.html b/app/kubernetes/views/resource-pools/resourcePools.html index c6c6cffdd..c63736563 100644 --- a/app/kubernetes/views/resource-pools/resourcePools.html +++ b/app/kubernetes/views/resource-pools/resourcePools.html @@ -6,7 +6,7 @@
> [$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); - }; - - service.endpointPublicURL = function () { - if (endpoint.PublicURL === undefined) { - endpoint.PublicURL = LocalStorage.getEndpointPublicURL(); - } - return endpoint.PublicURL; - }; - - service.setEndpointPublicURL = function (publicURL) { - endpoint.PublicURL = publicURL; - LocalStorage.storeEndpointPublicURL(publicURL); - }; - - service.endpoints = function () { - return LocalStorage.getEndpoints(); - }; - - service.setEndpoints = function (data) { - LocalStorage.storeEndpoints(data); - }; - - service.offlineMode = function () { - return endpoint.OfflineMode; - }; - - service.setOfflineMode = function (isOffline) { - endpoint.OfflineMode = isOffline; - LocalStorage.storeOfflineMode(isOffline); - }; - - service.setOfflineModeFromStatus = function (status) { - var isOffline = status !== 1; - endpoint.OfflineMode = isOffline; - LocalStorage.storeOfflineMode(isOffline); - }; - - service.currentEndpoint = function () { - return state.currentEndpoint; - }; - - service.setCurrentEndpoint = function (endpoint) { - state.currentEndpoint = endpoint; - }; - - return service; - } -); diff --git a/app/portainer/services/endpointProvider.ts b/app/portainer/services/endpointProvider.ts new file mode 100644 index 000000000..45636ce01 --- /dev/null +++ b/app/portainer/services/endpointProvider.ts @@ -0,0 +1,47 @@ +import { ping } from '@/docker/services/ping'; +import { + Environment, + EnvironmentType, +} from '@/react/portainer/environments/types'; + +interface State { + currentEndpoint: Environment | null; + pingInterval: NodeJS.Timer | null; +} + +/* @ngInject */ +export function EndpointProvider() { + const state: State = { + currentEndpoint: null, + pingInterval: null, + }; + + return { endpointID, setCurrentEndpoint, currentEndpoint, clean }; + + function endpointID() { + return state.currentEndpoint?.Id; + } + + function setCurrentEndpoint(endpoint: Environment | null) { + state.currentEndpoint = endpoint; + + if (state.pingInterval) { + clearInterval(state.pingInterval); + state.pingInterval = null; + } + + if (endpoint && endpoint.Type === EnvironmentType.EdgeAgentOnDocker) { + state.pingInterval = setInterval(() => ping(endpoint.Id), 60 * 1000); + } + } + + function currentEndpoint() { + return state.currentEndpoint; + } + + function clean() { + setCurrentEndpoint(null); + } +} + +export type EndpointProviderInterface = ReturnType; diff --git a/app/portainer/services/index.ts b/app/portainer/services/index.ts index 66b824f5d..ccd88deee 100644 --- a/app/portainer/services/index.ts +++ b/app/portainer/services/index.ts @@ -4,9 +4,11 @@ import { apiServicesModule } from './api'; import { Notifications } from './notifications'; import { ModalServiceAngular } from './modal.service'; import { HttpRequestHelperAngular } from './http-request.helper'; +import { EndpointProvider } from './endpointProvider'; export default angular .module('portainer.app.services', [apiServicesModule]) .factory('Notifications', Notifications) .factory('ModalService', ModalServiceAngular) + .factory('EndpointProvider', EndpointProvider) .factory('HttpRequestHelper', HttpRequestHelperAngular).name; diff --git a/app/portainer/services/localStorage.js b/app/portainer/services/localStorage.js index 7fcafac10..632dfff18 100644 --- a/app/portainer/services/localStorage.js +++ b/app/portainer/services/localStorage.js @@ -2,42 +2,21 @@ angular.module('portainer.app').factory('LocalStorage', [ 'localStorageService', function LocalStorageFactory(localStorageService) { return { - storeEndpointID: function (id) { - localStorageService.set('ENDPOINT_ID', id); - }, - getEndpointID: function () { - return localStorageService.get('ENDPOINT_ID'); - }, - storeEndpointPublicURL: function (publicURL) { - localStorageService.set('ENDPOINT_PUBLIC_URL', publicURL); - }, - getEndpointPublicURL: function () { - return localStorageService.get('ENDPOINT_PUBLIC_URL'); - }, storeLoginStateUUID: function (uuid) { localStorageService.set('LOGIN_STATE_UUID', uuid); }, getLoginStateUUID: function () { return localStorageService.get('LOGIN_STATE_UUID'); }, - storeOfflineMode: function (isOffline) { - localStorageService.set('ENDPOINT_OFFLINE_MODE', isOffline); - }, - getOfflineMode: function () { - return localStorageService.get('ENDPOINT_OFFLINE_MODE'); - }, - storeEndpoints: function (data) { - localStorageService.set('ENDPOINTS_DATA', data); - }, - getEndpoints: function () { - return localStorageService.get('ENDPOINTS_DATA'); - }, storeEndpointState: function (state) { localStorageService.set('ENDPOINT_STATE', state); }, getEndpointState: function () { return localStorageService.get('ENDPOINT_STATE'); }, + cleanEndpointState() { + localStorageService.remove('ENDPOINT_STATE'); + }, storeApplicationState: function (state) { localStorageService.set('APPLICATION_STATE', state); }, @@ -135,9 +114,6 @@ angular.module('portainer.app').factory('LocalStorage', [ cleanAuthData() { localStorageService.remove('JWT', 'APPLICATION_STATE', 'LOGIN_STATE_UUID'); }, - cleanEndpointData() { - localStorageService.remove('ENDPOINT_ID', 'ENDPOINT_PUBLIC_URL', 'ENDPOINT_OFFLINE_MODE', 'ENDPOINTS_DATA', 'ENDPOINT_STATE'); - }, storeKubernetesSummaryToggle(value) { localStorageService.set('kubernetes_summary_expanded', value); }, diff --git a/app/portainer/services/stateManager.js b/app/portainer/services/stateManager.js index bb68aeec1..a470e9958 100644 --- a/app/portainer/services/stateManager.js +++ b/app/portainer/services/stateManager.js @@ -66,13 +66,14 @@ function StateManagerFactory( }; manager.clean = function () { - state.endpoint = {}; + manager.cleanEndpoint(); state.application = {}; }; manager.cleanEndpoint = function () { state.endpoint = {}; EndpointProvider.clean(); + LocalStorage.cleanEndpointState(); }; manager.updateLogo = function (logoURL) { @@ -208,7 +209,7 @@ function StateManagerFactory( state.endpoint.apiVersion = endpointAPIVersion; if (endpointMode.agentProxy && endpoint.Status === 1) { - return AgentPingService.ping().then(function onPingSuccess(data) { + return AgentPingService.ping(endpoint.Id).then(function onPingSuccess(data) { state.endpoint.agentApiVersion = data.version; }); } diff --git a/app/portainer/services/types.ts b/app/portainer/services/types.ts index af8895e80..e1e1b536a 100644 --- a/app/portainer/services/types.ts +++ b/app/portainer/services/types.ts @@ -1,12 +1,5 @@ import { Environment } from '@/react/portainer/environments/types'; -export interface EndpointProvider { - setEndpointID(id: Environment['Id']): void; - setEndpointPublicURL(url?: string): void; - setOfflineModeFromStatus(status: Environment['Status']): void; - setCurrentEndpoint(endpoint: Environment | undefined): void; -} - export interface StateManager { updateEndpointState(endpoint: Environment): Promise; } diff --git a/app/portainer/views/stacks/edit/stackController.js b/app/portainer/views/stacks/edit/stackController.js index 13783eba0..6dc2117f2 100644 --- a/app/portainer/views/stacks/edit/stackController.js +++ b/app/portainer/views/stacks/edit/stackController.js @@ -21,7 +21,6 @@ angular.module('portainer.app').controller('StackController', [ 'TaskHelper', 'Notifications', 'FormHelper', - 'EndpointProvider', 'GroupService', 'ModalService', 'StackHelper', @@ -46,7 +45,6 @@ angular.module('portainer.app').controller('StackController', [ TaskHelper, Notifications, FormHelper, - EndpointProvider, GroupService, ModalService, StackHelper, @@ -112,16 +110,12 @@ angular.module('portainer.app').controller('StackController', [ $scope.duplicateStack = function duplicateStack(name, targetEndpointId) { var stack = $scope.stack; var env = FormHelper.removeInvalidEnvVars($scope.formValues.Env); - // sets the targetEndpointID as global for interceptors - EndpointProvider.setEndpointID(targetEndpointId); return StackService.duplicateStack(name, $scope.stackFileContent, env, targetEndpointId, stack.Type).then(onDuplicationSuccess).catch(notifyOnError); function onDuplicationSuccess() { Notifications.success('Success', 'Stack successfully duplicated'); $state.go('docker.stacks', {}, { reload: true }); - // sets back the original endpointID as global for interceptors - EndpointProvider.setEndpointID(stack.EndpointId); } function notifyOnError(err) { diff --git a/app/react/sidebar/EnvironmentSidebar.tsx b/app/react/sidebar/EnvironmentSidebar.tsx index 86d51413e..febd9a4bf 100644 --- a/app/react/sidebar/EnvironmentSidebar.tsx +++ b/app/react/sidebar/EnvironmentSidebar.tsx @@ -12,7 +12,7 @@ import { import { getPlatformType } from '@/react/portainer/environments/utils'; import { useEnvironment } from '@/react/portainer/environments/queries/useEnvironment'; import { useLocalStorage } from '@/portainer/hooks/useLocalStorage'; -import { EndpointProvider } from '@/portainer/services/types'; +import { EndpointProviderInterface } from '@/portainer/services/endpointProvider'; import { getPlatformIcon } from '../portainer/environments/utils/get-platform-icon'; @@ -107,8 +107,8 @@ function useCurrentEnvironment() { function clearEnvironment() { const $injector = angular.element(document).injector(); $injector.invoke( - /* @ngInject */ (EndpointProvider: EndpointProvider) => { - EndpointProvider.setCurrentEndpoint(undefined); + /* @ngInject */ (EndpointProvider: EndpointProviderInterface) => { + EndpointProvider.setCurrentEndpoint(null); if (!params.endpointId) { document.title = 'Portainer'; }