diff --git a/README.md b/README.md
index cee536856..65117ef76 100644
--- a/README.md
+++ b/README.md
@@ -6,9 +6,8 @@
[![Docker Pulls](https://img.shields.io/docker/pulls/portainer/portainer.svg)](https://hub.docker.com/r/portainer/portainer/)
[![Microbadger](https://images.microbadger.com/badges/image/portainer/portainer.svg)](http://microbadger.com/images/portainer/portainer "Image size")
[![Documentation Status](https://readthedocs.org/projects/portainer/badge/?version=stable)](http://portainer.readthedocs.io/en/stable/?badge=stable)
-[![Build Status](https://semaphoreci.com/api/v1/portainer/portainer-ci/branches/develop/badge.svg)](https://semaphoreci.com/portainer/portainer-ci)
+[![Build Status](https://portainer.visualstudio.com/Portainer%20CI/_apis/build/status/Portainer%20CI?branchName=develop)](https://portainer.visualstudio.com/Portainer%20CI/_build/latest?definitionId=3&branchName=develop)
[![Code Climate](https://codeclimate.com/github/portainer/portainer/badges/gpa.svg)](https://codeclimate.com/github/portainer/portainer)
-[![Slack](https://portainer.io/slack/badge.svg)](https://portainer.io/slack/)
[![Gitter](https://badges.gitter.im/portainer/Lobby.svg)](https://gitter.im/portainer/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
[![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=YHXZJQNJQ36H6)
@@ -20,8 +19,6 @@
## Demo
-
-
You can try out the public demo instance: http://demo.portainer.io/ (login with the username **admin** and the password **tryportainer**).
Please note that the public demo cluster is **reset every 15min**.
diff --git a/api/bolt/datastore.go b/api/bolt/datastore.go
index 0e94ad157..85273c23b 100644
--- a/api/bolt/datastore.go
+++ b/api/bolt/datastore.go
@@ -139,6 +139,7 @@ func (store *Store) MigrateData() error {
DatabaseVersion: version,
EndpointGroupService: store.EndpointGroupService,
EndpointService: store.EndpointService,
+ ExtensionService: store.ExtensionService,
ResourceControlService: store.ResourceControlService,
SettingsService: store.SettingsService,
StackService: store.StackService,
diff --git a/api/bolt/migrator/migrate_dbversion16.go b/api/bolt/migrator/migrate_dbversion16.go
new file mode 100644
index 000000000..4464a87ce
--- /dev/null
+++ b/api/bolt/migrator/migrate_dbversion16.go
@@ -0,0 +1,19 @@
+package migrator
+
+func (m *Migrator) updateExtensionsToDBVersion17() error {
+ legacyExtensions, err := m.extensionService.Extensions()
+ if err != nil {
+ return err
+ }
+
+ for _, extension := range legacyExtensions {
+ extension.License.Valid = true
+
+ err = m.extensionService.Persist(&extension)
+ if err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
diff --git a/api/bolt/migrator/migrator.go b/api/bolt/migrator/migrator.go
index 6ec80dcc9..ccee735ff 100644
--- a/api/bolt/migrator/migrator.go
+++ b/api/bolt/migrator/migrator.go
@@ -5,6 +5,7 @@ import (
"github.com/portainer/portainer"
"github.com/portainer/portainer/bolt/endpoint"
"github.com/portainer/portainer/bolt/endpointgroup"
+ "github.com/portainer/portainer/bolt/extension"
"github.com/portainer/portainer/bolt/resourcecontrol"
"github.com/portainer/portainer/bolt/settings"
"github.com/portainer/portainer/bolt/stack"
@@ -20,6 +21,7 @@ type (
db *bolt.DB
endpointGroupService *endpointgroup.Service
endpointService *endpoint.Service
+ extensionService *extension.Service
resourceControlService *resourcecontrol.Service
settingsService *settings.Service
stackService *stack.Service
@@ -35,6 +37,7 @@ type (
DatabaseVersion int
EndpointGroupService *endpointgroup.Service
EndpointService *endpoint.Service
+ ExtensionService *extension.Service
ResourceControlService *resourcecontrol.Service
SettingsService *settings.Service
StackService *stack.Service
@@ -52,6 +55,7 @@ func NewMigrator(parameters *Parameters) *Migrator {
currentDBVersion: parameters.DatabaseVersion,
endpointGroupService: parameters.EndpointGroupService,
endpointService: parameters.EndpointService,
+ extensionService: parameters.ExtensionService,
resourceControlService: parameters.ResourceControlService,
settingsService: parameters.SettingsService,
templateService: parameters.TemplateService,
@@ -210,5 +214,13 @@ func (m *Migrator) Migrate() error {
}
}
+ // Portainer 1.20.1
+ if m.currentDBVersion < 17 {
+ err := m.updateExtensionsToDBVersion17()
+ if err != nil {
+ return err
+ }
+ }
+
return m.versionService.StoreDBVersion(portainer.DBVersion)
}
diff --git a/api/cmd/portainer/main.go b/api/cmd/portainer/main.go
index e0a9dd2f9..09e223593 100644
--- a/api/cmd/portainer/main.go
+++ b/api/cmd/portainer/main.go
@@ -486,7 +486,10 @@ func initExtensionManager(fileService portainer.FileService, extensionService po
for _, extension := range extensions {
err := extensionManager.EnableExtension(&extension, extension.License.LicenseKey)
if err != nil {
- return nil, err
+ log.Printf("Unable to enable extension: %s [extension: %s]", err.Error(), extension.Name)
+ extension.Enabled = false
+ extension.License.Valid = false
+ extensionService.Persist(&extension)
}
}
diff --git a/api/exec/extension.go b/api/exec/extension.go
index 20cf2eca8..cb58ecad6 100644
--- a/api/exec/extension.go
+++ b/api/exec/extension.go
@@ -113,6 +113,7 @@ func (manager *ExtensionManager) EnableExtension(extension *portainer.Extension,
LicenseKey: licenseKey,
Company: licenseDetails[0],
Expiration: licenseDetails[1],
+ Valid: true,
}
extension.Version = licenseDetails[2]
diff --git a/api/http/handler/extensions/extension_create.go b/api/http/handler/extensions/extension_create.go
index b0ce72406..22d146f6e 100644
--- a/api/http/handler/extensions/extension_create.go
+++ b/api/http/handler/extensions/extension_create.go
@@ -42,7 +42,7 @@ func (handler *Handler) extensionCreate(w http.ResponseWriter, r *http.Request)
}
for _, existingExtension := range extensions {
- if existingExtension.ID == extensionID {
+ if existingExtension.ID == extensionID && existingExtension.Enabled {
return &httperror.HandlerError{http.StatusConflict, "Unable to enable extension", portainer.ErrExtensionAlreadyEnabled}
}
}
diff --git a/api/http/handler/extensions/extension_list.go b/api/http/handler/extensions/extension_list.go
index 392822528..68d26a7e7 100644
--- a/api/http/handler/extensions/extension_list.go
+++ b/api/http/handler/extensions/extension_list.go
@@ -42,6 +42,7 @@ func associateExtensionData(definition *portainer.Extension, extensions []portai
definition.Enabled = extension.Enabled
definition.License.Company = extension.License.Company
definition.License.Expiration = extension.License.Expiration
+ definition.License.Valid = extension.License.Valid
definitionVersion := semver.New(definition.Version)
extensionVersion := semver.New(extension.Version)
diff --git a/api/http/handler/settings/settings_update.go b/api/http/handler/settings/settings_update.go
index 5b4d33ae3..5c68fca94 100644
--- a/api/http/handler/settings/settings_update.go
+++ b/api/http/handler/settings/settings_update.go
@@ -66,7 +66,12 @@ func (handler *Handler) settingsUpdate(w http.ResponseWriter, r *http.Request) *
}
if payload.LDAPSettings != nil {
+ ldapPassword := settings.LDAPSettings.Password
+ if payload.LDAPSettings.Password != "" {
+ ldapPassword = payload.LDAPSettings.Password
+ }
settings.LDAPSettings = *payload.LDAPSettings
+ settings.LDAPSettings.Password = ldapPassword
}
if payload.AllowBindMountsForRegularUsers != nil {
diff --git a/api/portainer.go b/api/portainer.go
index c8062ed7a..9ff82bb37 100644
--- a/api/portainer.go
+++ b/api/portainer.go
@@ -503,6 +503,7 @@ type (
LicenseKey string `json:"LicenseKey,omitempty"`
Company string `json:"Company,omitempty"`
Expiration string `json:"Expiration,omitempty"`
+ Valid bool `json:"Valid,omitempty"`
}
// CLIService represents a service for managing CLI
@@ -778,9 +779,9 @@ type (
const (
// APIVersion is the version number of the Portainer API
- APIVersion = "1.20.0"
+ APIVersion = "1.20.1"
// DBVersion is the version number of the Portainer database
- DBVersion = 16
+ DBVersion = 17
// AssetsServerURL represents the URL of the Portainer asset server
AssetsServerURL = "https://portainer-io-assets.sfo2.digitaloceanspaces.com"
// MessageOfTheDayURL represents the URL where Portainer MOTD message can be retrieved
diff --git a/api/swagger.yaml b/api/swagger.yaml
index d8a3ad48a..7f5339d2e 100644
--- a/api/swagger.yaml
+++ b/api/swagger.yaml
@@ -54,7 +54,7 @@ info:
**NOTE**: You can find more information on how to query the Docker API in the [Docker official documentation](https://docs.docker.com/engine/api/v1.30/) as well as in [this Portainer example](https://gist.github.com/deviantony/77026d402366b4b43fa5918d41bc42f8).
- version: "1.20.0"
+ version: "1.20.1"
title: "Portainer API"
contact:
email: "info@portainer.io"
@@ -525,7 +525,7 @@ paths:
**Access policy**: administrator
operationId: "EndpointJob"
consumes:
- - "application/json"
+ - "multipart/form-data"
produces:
- "application/json"
security:
@@ -1434,7 +1434,7 @@ paths:
**Access policy**: restricted
operationId: "StackCreate"
consumes:
- - "application/json"
+ - "multipart/form-data"
produces:
- "application/json"
security:
@@ -2733,7 +2733,7 @@ paths:
- "application/json"
security:
- jwt: []
- parameters:
+ parameters: []
responses:
200:
description: "Success"
@@ -3018,7 +3018,7 @@ definitions:
description: "Is analytics enabled"
Version:
type: "string"
- example: "1.20.0"
+ example: "1.20.1"
description: "Portainer API version"
PublicSettingsInspectResponse:
type: "object"
@@ -3146,7 +3146,7 @@ definitions:
$ref: "#/definitions/LDAPGroupSearchSettings"
AutoCreateUsers:
type: "boolean"
- example: "true"
+ example: true
description: "Automatically provision users and assign them to matching LDAP group names"
Settings:
@@ -3606,6 +3606,7 @@ definitions:
- "Authentication"
- "Name"
- "Password"
+ - "Type"
- "URL"
- "Username"
properties:
@@ -3613,6 +3614,10 @@ definitions:
type: "string"
example: "my-registry"
description: "Name that will be used to identify this registry"
+ Type:
+ type: "integer"
+ example: 1
+ description: "Registry Type. Valid values are: 1 (Quay.io), 2 (Azure container registry) or 3 (custom registry)"
URL:
type: "string"
example: "registry.mydomain.tld:2375"
@@ -4037,7 +4042,7 @@ definitions:
description: "A list of categories associated to the template"
items:
type: "string"
- exampe: "database"
+ example: "database"
registry:
type: "string"
example: "quay.io"
@@ -4133,7 +4138,7 @@ definitions:
description: "A list of categories associated to the template"
items:
type: "string"
- exampe: "database"
+ example: "database"
registry:
type: "string"
example: "quay.io"
@@ -4233,7 +4238,7 @@ definitions:
description: "A list of categories associated to the template"
items:
type: "string"
- exampe: "database"
+ example: "database"
registry:
type: "string"
example: "quay.io"
diff --git a/api/swagger_config.json b/api/swagger_config.json
index beee114ea..cdd9e1115 100644
--- a/api/swagger_config.json
+++ b/api/swagger_config.json
@@ -1,5 +1,5 @@
{
"packageName": "portainer",
- "packageVersion": "1.20.0",
+ "packageVersion": "1.20.1",
"projectName": "portainer"
}
diff --git a/app/app.js b/app/app.js
index 021f4d58a..8a05b219b 100644
--- a/app/app.js
+++ b/app/app.js
@@ -30,7 +30,7 @@ function ($rootScope, $state, Authentication, authManager, StateManager, Endpoin
};
$transitions.onBefore({ to: 'docker.**' }, function() {
- HttpRequestHelper.resetAgentTargetQueue();
+ HttpRequestHelper.resetAgentHeaders();
});
}]);
@@ -45,7 +45,7 @@ function initAuthentication(authManager, Authentication, $rootScope, $state) {
// to have more controls on which URL should trigger the unauthenticated state.
$rootScope.$on('unauthenticated', function (event, data) {
if (!_.includes(data.config.url, '/v2/')) {
- $state.go('portainer.auth', {error: 'Your session has expired'});
+ $state.go('portainer.auth', {error: 'Your session has expired', redirect: $state.current.name});
}
});
}
diff --git a/app/config.js b/app/config.js
index cd21e1f08..268b39288 100644
--- a/app/config.js
+++ b/app/config.js
@@ -27,6 +27,9 @@ angular.module('portainer')
request: function(config) {
if (config.url.indexOf('/docker/') > -1) {
config.headers['X-PortainerAgent-Target'] = HttpRequestHelper.portainerAgentTargetHeader();
+ if (HttpRequestHelper.portainerAgentManagerOperation()) {
+ config.headers['X-PortainerAgent-ManagerOperation'] = '1';
+ }
}
return config;
}
diff --git a/app/docker/__module.js b/app/docker/__module.js
index 9bd99a7cd..d36f0df8c 100644
--- a/app/docker/__module.js
+++ b/app/docker/__module.js
@@ -5,7 +5,17 @@ angular.module('portainer.docker', ['portainer.app'])
var docker = {
name: 'docker',
parent: 'root',
- abstract: true
+ abstract: true,
+ resolve: {
+ endpointID: ['EndpointProvider', '$state',
+ function (EndpointProvider, $state) {
+ var id = EndpointProvider.endpointID();
+ if (!id) {
+ return $state.go('portainer.home');
+ }
+ }
+ ]
+ }
};
var configs = {
diff --git a/app/docker/components/datatables/container-networks-datatable/containerNetworksDatatable.html b/app/docker/components/datatables/container-networks-datatable/containerNetworksDatatable.html
index a79fdc698..bb8a5d4c6 100644
--- a/app/docker/components/datatables/container-networks-datatable/containerNetworksDatatable.html
+++ b/app/docker/components/datatables/container-networks-datatable/containerNetworksDatatable.html
@@ -38,12 +38,12 @@
- {{ key }} |
+ {{ key }} |
{{ value.IPAddress || '-' }} |
{{ value.Gateway || '-' }} |
{{ value.MacAddress || '-' }} |
- |
-
- Subnet |
- {{ network.IPAM.Config[0].Subnet }} |
-
-
- Gateway |
- {{ network.IPAM.Config[0].Gateway }} |
+
+ Subnet - {{ config.Subnet }} |
+ Gateway - {{ config.Gateway }} |
diff --git a/app/docker/views/services/create/createservice.html b/app/docker/views/services/create/createservice.html
index 2003ff97f..ceca97a55 100644
--- a/app/docker/views/services/create/createservice.html
+++ b/app/docker/views/services/create/createservice.html
@@ -315,8 +315,9 @@
volume
-
diff --git a/app/extensions/registry-management/rest/catalog.js b/app/extensions/registry-management/rest/catalog.js
index 1d6f24be5..728a18dcd 100644
--- a/app/extensions/registry-management/rest/catalog.js
+++ b/app/extensions/registry-management/rest/catalog.js
@@ -1,11 +1,13 @@
angular.module('portainer.extensions.registrymanagement')
-.factory('RegistryCatalog', ['$resource', 'API_ENDPOINT_REGISTRIES', function RegistryCatalogFactory($resource, API_ENDPOINT_REGISTRIES) {
+.factory('RegistryCatalog', ['$resource', 'API_ENDPOINT_REGISTRIES',
+function RegistryCatalogFactory($resource, API_ENDPOINT_REGISTRIES) {
'use strict';
return $resource(API_ENDPOINT_REGISTRIES + '/:id/v2/:action', {},
{
get: {
method: 'GET',
- params: { id: '@id', action: '_catalog' }
+ params: { id: '@id', action: '_catalog' },
+ transformResponse: linkGetResponse
},
ping: {
method: 'GET',
diff --git a/app/extensions/registry-management/rest/transform/linkGetResponse.js b/app/extensions/registry-management/rest/transform/linkGetResponse.js
new file mode 100644
index 000000000..5307701ca
--- /dev/null
+++ b/app/extensions/registry-management/rest/transform/linkGetResponse.js
@@ -0,0 +1,13 @@
+function linkGetResponse(data, headers) {
+ var response = angular.fromJson(data);
+ var link = headers('link');
+ if (link) {
+ var queryString = link.substring(link.indexOf('?') + 1).split('>;')[0];
+ var queries = queryString.split('&');
+ for (var i = 0; i < queries.length; i++) {
+ var kv = queries[i].split('=');
+ response[kv[0]] = kv[1];
+ }
+ }
+ return response;
+}
\ No newline at end of file
diff --git a/app/extensions/registry-management/services/registryAPIService.js b/app/extensions/registry-management/services/registryAPIService.js
index b766ca568..18089bff9 100644
--- a/app/extensions/registry-management/services/registryAPIService.js
+++ b/app/extensions/registry-management/services/registryAPIService.js
@@ -11,16 +11,33 @@ function RegistryV2ServiceFactory($q, RegistryCatalog, RegistryTags, RegistryMan
return RegistryCatalog.ping({ id: id }).$promise;
};
+ function getCatalog(id) {
+ var deferred = $q.defer();
+ var repositories = [];
+
+ _getCatalogPage({id: id}, deferred, repositories);
+
+ return deferred.promise;
+ }
+
+ function _getCatalogPage(params, deferred, repositories) {
+ RegistryCatalog.get(params).$promise.then(function(data) {
+ repositories = _.concat(repositories, data.repositories);
+ if (data.last && data.n) {
+ _getCatalogPage({id: params.id, n: data.n, last: data.last}, deferred, repositories);
+ } else {
+ deferred.resolve(repositories);
+ }
+ });
+ }
+
service.repositories = function (id) {
var deferred = $q.defer();
- RegistryCatalog.get({
- id: id
- }).$promise
- .then(function success(data) {
+ getCatalog(id).then(function success(data) {
var promises = [];
- for (var i = 0; i < data.repositories.length; i++) {
- var repository = data.repositories[i];
+ for (var i = 0; i < data.length; i++) {
+ var repository = data[i];
promises.push(RegistryTags.get({
id: id,
repository: repository
diff --git a/app/extensions/registry-management/views/repositories/edit/registryRepositoryController.js b/app/extensions/registry-management/views/repositories/edit/registryRepositoryController.js
index de4521cb1..04c7b0e46 100644
--- a/app/extensions/registry-management/views/repositories/edit/registryRepositoryController.js
+++ b/app/extensions/registry-management/views/repositories/edit/registryRepositoryController.js
@@ -81,9 +81,17 @@ angular.module('portainer.app')
});
return $q.all(promises);
})
- .then(function success() {
+ .then(function success(data) {
Notifications.success('Success', 'Tags successfully deleted');
- $state.reload();
+ if (data.length === 0) {
+ $state.go('portainer.registries.registry.repositories', {
+ id: $scope.registryId
+ }, {
+ reload: true
+ });
+ } else {
+ $state.reload();
+ }
})
.catch(function error(err) {
Notifications.error('Failure', err, 'Unable to delete tags');
@@ -127,9 +135,9 @@ angular.module('portainer.app')
})
.then(function success(data) {
$scope.registry = data.registry;
- $scope.repository.Tags = data.tags;
+ $scope.repository.Tags = [].concat(data.tags || []);
$scope.tags = [];
- for (var i = 0; i < data.tags.length; i++) {
+ for (var i = 0; i < $scope.repository.Tags.length; i++) {
var tag = data.tags[i];
RegistryV2Service.tag(registryId, repository, tag)
.then(function success(data) {
diff --git a/app/portainer/__module.js b/app/portainer/__module.js
index b79553a52..129c6b4b2 100644
--- a/app/portainer/__module.js
+++ b/app/portainer/__module.js
@@ -48,7 +48,7 @@ angular.module('portainer.app', [])
var authentication = {
name: 'portainer.auth',
- url: '/auth',
+ url: '/auth?redirect',
params: {
logout: false,
error: ''
@@ -87,7 +87,7 @@ angular.module('portainer.app', [])
}
};
- var endpointCreation = {
+ var endpointCreation = {
name: 'portainer.endpoints.new',
url: '/new',
views: {
@@ -242,7 +242,7 @@ angular.module('portainer.app', [])
}
};
- var registryCreation = {
+ var registryCreation = {
name: 'portainer.registries.new',
url: '/new',
views: {
@@ -286,7 +286,7 @@ angular.module('portainer.app', [])
}
};
- var scheduleCreation = {
+ var scheduleCreation = {
name: 'portainer.schedules.new',
url: '/new',
views: {
@@ -327,6 +327,16 @@ angular.module('portainer.app', [])
templateUrl: 'app/portainer/views/stacks/stacks.html',
controller: 'StacksController'
}
+ },
+ resolve: {
+ endpointID: ['EndpointProvider', '$state',
+ function (EndpointProvider, $state) {
+ var id = EndpointProvider.endpointID();
+ if (!id) {
+ return $state.go('portainer.home');
+ }
+ }
+ ]
}
};
@@ -342,7 +352,7 @@ angular.module('portainer.app', [])
};
var stackCreation = {
- name: 'portainer.newstack',
+ name: 'portainer.stacks.newstack',
url: '/newstack',
views: {
'content@': {
diff --git a/app/portainer/components/datatables/stacks-datatable/stacksDatatable.html b/app/portainer/components/datatables/stacks-datatable/stacksDatatable.html
index dc18ed8e1..b9d499949 100644
--- a/app/portainer/components/datatables/stacks-datatable/stacksDatatable.html
+++ b/app/portainer/components/datatables/stacks-datatable/stacksDatatable.html
@@ -11,7 +11,7 @@
ng-disabled="$ctrl.state.selectedItemCount === 0" ng-click="$ctrl.removeAction($ctrl.state.selectedItems)">
Remove
-
+
Add stack
diff --git a/app/portainer/components/endpoint-list/endpoint-item/endpointItem.html b/app/portainer/components/endpoint-list/endpoint-item/endpointItem.html
index a2f96a392..a44f84163 100644
--- a/app/portainer/components/endpoint-list/endpoint-item/endpointItem.html
+++ b/app/portainer/components/endpoint-list/endpoint-item/endpointItem.html
@@ -23,11 +23,11 @@
-
+
Group: {{ $ctrl.model.GroupName }}
diff --git a/app/portainer/components/extension-list/extension-item/extensionItem.html b/app/portainer/components/extension-list/extension-item/extensionItem.html
index 95acdb9cb..18a41ccc4 100644
--- a/app/portainer/components/extension-list/extension-item/extensionItem.html
+++ b/app/portainer/components/extension-list/extension-item/extensionItem.html
@@ -21,10 +21,10 @@
coming soon
- deal
- expired
- enabled
- update available
+ deal
+ expired
+ enabled
+ update available
diff --git a/app/portainer/components/extension-list/extension-item/extensionItemController.js b/app/portainer/components/extension-list/extension-item/extensionItemController.js
index 810e93990..841aadc5a 100644
--- a/app/portainer/components/extension-list/extension-item/extensionItemController.js
+++ b/app/portainer/components/extension-list/extension-item/extensionItemController.js
@@ -3,7 +3,6 @@ angular.module('portainer.app')
function($state) {
var ctrl = this;
- ctrl.$onInit = $onInit;
ctrl.goToExtensionView = goToExtensionView;
function goToExtensionView() {
@@ -11,10 +10,4 @@ angular.module('portainer.app')
$state.go('portainer.extensions.extension', { id: ctrl.model.Id });
}
}
-
- function $onInit() {
- if (ctrl.currentDate === ctrl.model.License.Expiration) {
- ctrl.model.Expired = true;
- }
- }
}]);
diff --git a/app/portainer/components/product-list/product-item/productItem.html b/app/portainer/components/product-list/product-item/productItem.html
index fa72a7092..b4ac46d6b 100644
--- a/app/portainer/components/product-list/product-item/productItem.html
+++ b/app/portainer/components/product-list/product-item/productItem.html
@@ -3,7 +3,7 @@
-
+
@@ -15,11 +15,6 @@
{{ $ctrl.model.Name }}
-
- expired
- enabled
- update available
-
@@ -29,9 +24,6 @@
{{ $ctrl.model.ShortDescription }}
-
- Licensed to {{ $ctrl.model.License.Company }} - Expires on {{ $ctrl.model.License.Expiration }}
-
diff --git a/app/portainer/interceptors/endpointStatusInterceptor.js b/app/portainer/interceptors/endpointStatusInterceptor.js
index 9411f8d62..5acc075f1 100644
--- a/app/portainer/interceptors/endpointStatusInterceptor.js
+++ b/app/portainer/interceptors/endpointStatusInterceptor.js
@@ -1,5 +1,5 @@
angular.module('portainer.app')
- .factory('EndpointStatusInterceptor', ['$q', '$injector', 'EndpointProvider', function ($q, $injector, EndpointProvider) {
+ .factory('EndpointStatusInterceptor', ['$q', 'EndpointProvider', function ($q, EndpointProvider) {
'use strict';
var interceptor = {};
@@ -18,21 +18,17 @@ angular.module('portainer.app')
}
function responseInterceptor(response) {
- var EndpointService = $injector.get('EndpointService');
var url = response.config.url;
if (response.status === 200 && canBeOffline(url) && EndpointProvider.offlineMode()) {
EndpointProvider.setOfflineMode(false);
- EndpointService.updateEndpoint(EndpointProvider.endpointID(), {Status: EndpointProvider.endpointStatusFromOfflineMode(false)});
}
return response || $q.when(response);
}
function responseErrorInterceptor(rejection) {
- var EndpointService = $injector.get('EndpointService');
var url = rejection.config.url;
if ((rejection.status === 502 || rejection.status === 503 || rejection.status === -1) && canBeOffline(url) && !EndpointProvider.offlineMode()) {
EndpointProvider.setOfflineMode(true);
- EndpointService.updateEndpoint(EndpointProvider.endpointID(), {Status: EndpointProvider.endpointStatusFromOfflineMode(true)});
}
return $q.reject(rejection);
}
diff --git a/app/portainer/services/endpointProvider.js b/app/portainer/services/endpointProvider.js
index ebd89497e..72e38d9f6 100644
--- a/app/portainer/services/endpointProvider.js
+++ b/app/portainer/services/endpointProvider.js
@@ -64,10 +64,6 @@ angular.module('portainer.app')
return endpoint.OfflineMode;
};
- service.endpointStatusFromOfflineMode = function(isOffline) {
- return isOffline ? 2 : 1;
- };
-
service.setOfflineMode = function(isOffline) {
endpoint.OfflineMode = isOffline;
LocalStorage.storeOfflineMode(isOffline);
diff --git a/app/portainer/services/httpRequestHelper.js b/app/portainer/services/httpRequestHelper.js
index 1d5b5dbe8..d63e2fe2f 100644
--- a/app/portainer/services/httpRequestHelper.js
+++ b/app/portainer/services/httpRequestHelper.js
@@ -5,6 +5,7 @@ angular.module('portainer.app')
var service = {};
var headers = {};
headers.agentTargetQueue = [];
+ headers.agentManagerOperation = false;
service.registryAuthenticationHeader = function() {
return headers.registryAuthentication;
@@ -36,9 +37,18 @@ angular.module('portainer.app')
}
};
- service.resetAgentTargetQueue = function() {
+ service.setPortainerAgentManagerOperation = function(set) {
+ headers.agentManagerOperation = set;
+ };
+
+ service.portainerAgentManagerOperation = function() {
+ return headers.agentManagerOperation;
+ };
+
+ service.resetAgentHeaders = function() {
headers.agentTargetQueue = [];
delete headers.agentTargetLastValue;
+ headers.agentManagerOperation = false;
};
return service;
diff --git a/app/portainer/views/auth/authController.js b/app/portainer/views/auth/authController.js
index 055d359be..2e2b729bf 100644
--- a/app/portainer/views/auth/authController.js
+++ b/app/portainer/views/auth/authController.js
@@ -1,6 +1,6 @@
angular.module('portainer.app')
-.controller('AuthenticationController', ['$q', '$scope', '$state', '$transition$', '$sanitize', 'Authentication', 'UserService', 'EndpointService', 'StateManager', 'Notifications', 'SettingsService',
-function ($q, $scope, $state, $transition$, $sanitize, Authentication, UserService, EndpointService, StateManager, Notifications, SettingsService) {
+.controller('AuthenticationController', ['$q', '$scope', '$state', '$transition$', '$sanitize', 'Authentication', 'UserService', 'EndpointService', 'StateManager', 'Notifications', 'SettingsService', '$stateParams',
+function ($q, $scope, $state, $transition$, $sanitize, Authentication, UserService, EndpointService, StateManager, Notifications, SettingsService, $stateParams) {
$scope.logo = StateManager.getState().application.logo;
@@ -44,7 +44,7 @@ function ($q, $scope, $state, $transition$, $sanitize, Authentication, UserServi
if (endpoints.length === 0) {
$state.go('portainer.init.endpoint');
} else {
- $state.go('portainer.home');
+ $state.go($stateParams.redirect ||'portainer.home');
}
})
.catch(function error(err) {
@@ -73,7 +73,7 @@ function ($q, $scope, $state, $transition$, $sanitize, Authentication, UserServi
if (endpoints.length === 0 && userDetails.role === 1) {
$state.go('portainer.init.endpoint');
} else {
- $state.go('portainer.home');
+ $state.go($stateParams.redirect || 'portainer.home');
}
})
.catch(function error(err) {
diff --git a/app/portainer/views/endpoints/create/createendpoint.html b/app/portainer/views/endpoints/create/createendpoint.html
index 4b7a762bd..3563a99b9 100644
--- a/app/portainer/views/endpoints/create/createendpoint.html
+++ b/app/portainer/views/endpoints/create/createendpoint.html
@@ -67,7 +67,7 @@
Ensure that you have deployed the Portainer agent in your cluster first. You can use execute the following command on any manager node to deploy it.
- curl -L https://portainer.io/download/agent-stack.yml -o agent-stack.yml && docker stack deploy --compose-file=agent-stack.yml portainer-agent
+ curl -L https://downloads.portainer.io/agent-stack.yml -o agent-stack.yml && docker stack deploy --compose-file=agent-stack.yml portainer-agent
Copy
diff --git a/app/portainer/views/extensions/inspect/extension.html b/app/portainer/views/extensions/inspect/extension.html
index 0a83740d9..df59e2966 100644
--- a/app/portainer/views/extensions/inspect/extension.html
+++ b/app/portainer/views/extensions/inspect/extension.html
@@ -36,7 +36,9 @@