1
0
Fork 0
mirror of https://github.com/portainer/portainer.git synced 2025-08-08 07:15:23 +02:00

feat(settings): add settings management (#906)

This commit is contained in:
Anthony Lapenna 2017-06-01 10:14:55 +02:00 committed by GitHub
parent 5e74a3993b
commit c7e306841a
93 changed files with 1086 additions and 457 deletions

View file

@ -57,6 +57,7 @@ angular.module('portainer', [
'templates',
'user',
'users',
'userSettings',
'volume',
'volumes'])
.config(['$stateProvider', '$urlRouterProvider', '$httpProvider', 'localStorageServiceProvider', 'jwtOptionsProvider', 'AnalyticsProvider', '$uibTooltipProvider', '$compileProvider', function ($stateProvider, $urlRouterProvider, $httpProvider, localStorageServiceProvider, jwtOptionsProvider, AnalyticsProvider, $uibTooltipProvider, $compileProvider) {
@ -594,6 +595,19 @@ angular.module('portainer', [
}
}
})
.state('userSettings', {
url: '/userSettings/',
views: {
'content@': {
templateUrl: 'app/components/userSettings/userSettings.html',
controller: 'UserSettingsController'
},
'sidebar@': {
templateUrl: 'app/components/sidebar/sidebar.html',
controller: 'SidebarController'
}
}
})
.state('teams', {
url: '/teams/',
views: {
@ -662,9 +676,11 @@ angular.module('portainer', [
}])
// This is your docker url that the api will use to make requests
// You need to set this to the api endpoint without the port i.e. http://192.168.1.9
.constant('DOCKER_PORT', '') // Docker port, leave as an empty string if no port is required. If you have a port, prefix it with a ':' i.e. :4243
// .constant('DOCKER_PORT', '') // Docker port, leave as an empty string if no port is required. If you have a port, prefix it with a ':' i.e. :4243
.constant('DOCKER_ENDPOINT', 'api/docker')
.constant('CONFIG_ENDPOINT', 'api/settings')
.constant('CONFIG_ENDPOINT', 'api/old_settings')
.constant('SETTINGS_ENDPOINT', 'api/settings')
.constant('STATUS_ENDPOINT', 'api/status')
.constant('AUTH_ENDPOINT', 'api/auth')
.constant('USERS_ENDPOINT', 'api/users')
.constant('TEAMS_ENDPOINT', 'api/teams')
@ -672,5 +688,6 @@ angular.module('portainer', [
.constant('RESOURCE_CONTROL_ENDPOINT', 'api/resource_controls')
.constant('ENDPOINTS_ENDPOINT', 'api/endpoints')
.constant('TEMPLATES_ENDPOINT', 'api/templates')
.constant('PAGINATION_MAX_ITEMS', 10)
.constant('UI_VERSION', 'v1.13.1');
.constant('DEFAULT_TEMPLATES_URL', 'https://raw.githubusercontent.com/portainer/templates/master/templates.json')
.constant('PAGINATION_MAX_ITEMS', 10);
// .constant('UI_VERSION', 'v1.13.1');

View file

@ -1,6 +1,6 @@
angular.module('auth', [])
.controller('AuthenticationController', ['$scope', '$state', '$stateParams', '$window', '$timeout', '$sanitize', 'Config', 'Authentication', 'Users', 'EndpointService', 'StateManager', 'EndpointProvider', 'Notifications',
function ($scope, $state, $stateParams, $window, $timeout, $sanitize, Config, Authentication, Users, EndpointService, StateManager, EndpointProvider, Notifications) {
.controller('AuthenticationController', ['$scope', '$state', '$stateParams', '$window', '$timeout', '$sanitize', 'Authentication', 'Users', 'EndpointService', 'StateManager', 'EndpointProvider', 'Notifications',
function ($scope, $state, $stateParams, $window, $timeout, $sanitize, Authentication, Users, EndpointService, StateManager, EndpointProvider, Notifications) {
$scope.authData = {
username: 'admin',
@ -13,6 +13,8 @@ function ($scope, $state, $stateParams, $window, $timeout, $sanitize, Config, Au
error: false
};
$scope.logo = StateManager.getState().application.logo;
if (!$scope.applicationState.application.authentication) {
EndpointService.endpoints()
.then(function success(data) {
@ -59,10 +61,6 @@ function ($scope, $state, $stateParams, $window, $timeout, $sanitize, Config, Au
$state.go('dashboard');
}
Config.$promise.then(function (c) {
$scope.logo = c.logo;
});
$scope.createAdminUser = function() {
var password = $sanitize($scope.initPasswordData.password);
Users.initAdminUser({password: password}, function (d) {

View file

@ -1,6 +1,6 @@
angular.module('containerConsole', [])
.controller('ContainerConsoleController', ['$scope', '$stateParams', 'Settings', 'Container', 'Image', 'Exec', '$timeout', 'EndpointProvider', 'Notifications',
function ($scope, $stateParams, Settings, Container, Image, Exec, $timeout, EndpointProvider, Notifications) {
.controller('ContainerConsoleController', ['$scope', '$stateParams', 'Container', 'Image', 'Exec', '$timeout', 'EndpointProvider', 'Notifications',
function ($scope, $stateParams, Container, Image, Exec, $timeout, EndpointProvider, Notifications) {
$scope.state = {};
$scope.state.loaded = false;
$scope.state.connected = false;

View file

@ -1,9 +1,9 @@
angular.module('containers', [])
.controller('ContainersController', ['$q', '$scope', '$filter', 'Container', 'ContainerService', 'ContainerHelper', 'Info', 'Settings', 'Notifications', 'Config', 'Pagination', 'EntityListService', 'ModalService', 'ResourceControlService', 'EndpointProvider',
function ($q, $scope, $filter, Container, ContainerService, ContainerHelper, Info, Settings, Notifications, Config, Pagination, EntityListService, ModalService, ResourceControlService, EndpointProvider) {
.controller('ContainersController', ['$q', '$scope', '$filter', 'Container', 'ContainerService', 'ContainerHelper', 'Info', 'Notifications', 'Pagination', 'EntityListService', 'ModalService', 'ResourceControlService', 'EndpointProvider',
function ($q, $scope, $filter, Container, ContainerService, ContainerHelper, Info, Notifications, Pagination, EntityListService, ModalService, ResourceControlService, EndpointProvider) {
$scope.state = {};
$scope.state.pagination_count = Pagination.getPaginationCount('containers');
$scope.state.displayAll = Settings.displayAll;
$scope.state.displayAll = true;
$scope.state.displayIP = false;
$scope.sortType = 'State';
$scope.sortReverse = false;
@ -25,9 +25,6 @@ angular.module('containers', [])
$scope.state.selectedItemCount = 0;
Container.query(data, function (d) {
var containers = d;
if ($scope.containersToHideLabels) {
containers = ContainerHelper.hideContainers(d, $scope.containersToHideLabels);
}
$scope.containers = containers.map(function (container) {
var model = new ContainerViewModel(container);
model.Status = $filter('containerstatus')(model.Status);
@ -59,7 +56,7 @@ angular.module('containers', [])
counter = counter - 1;
if (counter === 0) {
$('#loadContainersSpinner').hide();
update({all: Settings.displayAll ? 1 : 0});
update({all: $scope.state.displayAll ? 1 : 0});
}
};
angular.forEach(items, function (c) {
@ -134,8 +131,7 @@ angular.module('containers', [])
};
$scope.toggleGetAll = function () {
Settings.displayAll = $scope.state.displayAll;
update({all: Settings.displayAll ? 1 : 0});
update({all: $scope.state.displayAll ? 1 : 0});
};
$scope.startAction = function () {
@ -206,15 +202,16 @@ angular.module('containers', [])
return swarm_hosts;
}
Config.$promise.then(function (c) {
$scope.containersToHideLabels = c.hiddenLabels;
function initView(){
if ($scope.applicationState.endpoint.mode.provider === 'DOCKER_SWARM') {
Info.get({}, function (d) {
$scope.swarm_hosts = retrieveSwarmHostsInfo(d);
update({all: Settings.displayAll ? 1 : 0});
update({all: $scope.state.displayAll ? 1 : 0});
});
} else {
update({all: Settings.displayAll ? 1 : 0});
update({all: $scope.state.displayAll ? 1 : 0});
}
});
}
initView();
}]);

View file

@ -1,8 +1,8 @@
// @@OLD_SERVICE_CONTROLLER: this service should be rewritten to use services.
// See app/components/templates/templatesController.js as a reference.
angular.module('createContainer', [])
.controller('CreateContainerController', ['$q', '$scope', '$state', '$stateParams', '$filter', 'Config', 'Info', 'Container', 'ContainerHelper', 'Image', 'ImageHelper', 'Volume', 'Network', 'ResourceControlService', 'Authentication', 'Notifications', 'ContainerService', 'ImageService', 'ControllerDataPipeline', 'FormValidator',
function ($q, $scope, $state, $stateParams, $filter, Config, Info, Container, ContainerHelper, Image, ImageHelper, Volume, Network, ResourceControlService, Authentication, Notifications, ContainerService, ImageService, ControllerDataPipeline, FormValidator) {
.controller('CreateContainerController', ['$q', '$scope', '$state', '$stateParams', '$filter', 'Info', 'Container', 'ContainerHelper', 'Image', 'ImageHelper', 'Volume', 'Network', 'ResourceControlService', 'Authentication', 'Notifications', 'ContainerService', 'ImageService', 'ControllerDataPipeline', 'FormValidator',
function ($q, $scope, $state, $stateParams, $filter, Info, Container, ContainerHelper, Image, ImageHelper, Volume, Network, ResourceControlService, Authentication, Notifications, ContainerService, ImageService, ControllerDataPipeline, FormValidator) {
$scope.formValues = {
alwaysPull: true,
@ -233,47 +233,41 @@ function ($q, $scope, $state, $stateParams, $filter, Config, Info, Container, Co
}
function initView() {
Config.$promise.then(function (c) {
var containersToHideLabels = c.hiddenLabels;
Volume.query({}, function (d) {
$scope.availableVolumes = d.Volumes;
}, function (e) {
Notifications.error('Failure', e, 'Unable to retrieve volumes');
});
Network.query({}, function (d) {
var networks = d;
if ($scope.applicationState.endpoint.mode.provider === 'DOCKER_SWARM' || $scope.applicationState.endpoint.mode.provider === 'DOCKER_SWARM_MODE') {
networks = d.filter(function (network) {
if (network.Scope === 'global') {
return network;
}
});
$scope.globalNetworkCount = networks.length;
networks.push({Name: 'bridge'});
networks.push({Name: 'host'});
networks.push({Name: 'none'});
}
networks.push({Name: 'container'});
$scope.availableNetworks = networks;
if (!_.find(networks, {'Name': 'bridge'})) {
$scope.config.HostConfig.NetworkMode = 'nat';
}
}, function (e) {
Notifications.error('Failure', e, 'Unable to retrieve networks');
});
Container.query({}, function (d) {
var containers = d;
if (containersToHideLabels) {
containers = ContainerHelper.hideContainers(d, containersToHideLabels);
}
$scope.runningContainers = containers;
}, function(e) {
Notifications.error('Failure', e, 'Unable to retrieve running containers');
});
Volume.query({}, function (d) {
$scope.availableVolumes = d.Volumes;
}, function (e) {
Notifications.error('Failure', e, 'Unable to retrieve volumes');
});
Network.query({}, function (d) {
var networks = d;
if ($scope.applicationState.endpoint.mode.provider === 'DOCKER_SWARM' || $scope.applicationState.endpoint.mode.provider === 'DOCKER_SWARM_MODE') {
networks = d.filter(function (network) {
if (network.Scope === 'global') {
return network;
}
});
$scope.globalNetworkCount = networks.length;
networks.push({Name: 'bridge'});
networks.push({Name: 'host'});
networks.push({Name: 'none'});
}
networks.push({Name: 'container'});
$scope.availableNetworks = networks;
if (!_.find(networks, {'Name': 'bridge'})) {
$scope.config.HostConfig.NetworkMode = 'nat';
}
}, function (e) {
Notifications.error('Failure', e, 'Unable to retrieve networks');
});
Container.query({}, function (d) {
var containers = d;
$scope.runningContainers = containers;
}, function(e) {
Notifications.error('Failure', e, 'Unable to retrieve running containers');
});
}
function validateForm(accessControlData, isAdmin) {
@ -327,5 +321,4 @@ function ($q, $scope, $state, $stateParams, $filter, Config, Info, Container, Co
}
initView();
}]);

View file

@ -1,6 +1,6 @@
angular.module('dashboard', [])
.controller('DashboardController', ['$scope', '$q', 'Config', 'Container', 'ContainerHelper', 'Image', 'Network', 'Volume', 'Info', 'Notifications',
function ($scope, $q, Config, Container, ContainerHelper, Image, Network, Volume, Info, Notifications) {
.controller('DashboardController', ['$scope', '$q', 'Container', 'ContainerHelper', 'Image', 'Network', 'Volume', 'Info', 'Notifications',
function ($scope, $q, Container, ContainerHelper, Image, Network, Volume, Info, Notifications) {
$scope.containerData = {
total: 0
@ -15,14 +15,10 @@ function ($scope, $q, Config, Container, ContainerHelper, Image, Network, Volume
total: 0
};
function prepareContainerData(d, containersToHideLabels) {
function prepareContainerData(d) {
var running = 0;
var stopped = 0;
var containers = d;
if (containersToHideLabels) {
containers = ContainerHelper.hideContainers(d, containersToHideLabels);
}
for (var i = 0; i < containers.length; i++) {
var item = containers[i];
@ -65,7 +61,7 @@ function ($scope, $q, Config, Container, ContainerHelper, Image, Network, Volume
$scope.infoData = info;
}
function fetchDashboardData(containersToHideLabels) {
function initView() {
$('#loadingViewSpinner').show();
$q.all([
Container.query({all: 1}).$promise,
@ -74,7 +70,7 @@ function ($scope, $q, Config, Container, ContainerHelper, Image, Network, Volume
Network.query({}).$promise,
Info.get({}).$promise
]).then(function (d) {
prepareContainerData(d[0], containersToHideLabels);
prepareContainerData(d[0]);
prepareImageData(d[1]);
prepareVolumeData(d[2]);
prepareNetworkData(d[3]);
@ -86,7 +82,5 @@ function ($scope, $q, Config, Container, ContainerHelper, Image, Network, Volume
});
}
Config.$promise.then(function (c) {
fetchDashboardData(c.hiddenLabels);
});
initView();
}]);

View file

@ -1,6 +1,6 @@
angular.module('images', [])
.controller('ImagesController', ['$scope', '$state', 'Config', 'ImageService', 'Notifications', 'Pagination', 'ModalService',
function ($scope, $state, Config, ImageService, Notifications, Pagination, ModalService) {
.controller('ImagesController', ['$scope', '$state', 'ImageService', 'Notifications', 'Pagination', 'ModalService',
function ($scope, $state, ImageService, Notifications, Pagination, ModalService) {
$scope.state = {};
$scope.state.pagination_count = Pagination.getPaginationCount('images');
$scope.sortType = 'RepoTags';

View file

@ -1,6 +1,6 @@
angular.module('network', [])
.controller('NetworkController', ['$scope', '$state', '$stateParams', '$filter', 'Config', 'Network', 'Container', 'ContainerHelper', 'Notifications',
function ($scope, $state, $stateParams, $filter, Config, Network, Container, ContainerHelper, Notifications) {
.controller('NetworkController', ['$scope', '$state', '$stateParams', '$filter', 'Network', 'Container', 'ContainerHelper', 'Notifications',
function ($scope, $state, $stateParams, $filter, Network, Container, ContainerHelper, Notifications) {
$scope.removeNetwork = function removeNetwork(networkId) {
$('#loadingViewSpinner').show();
@ -36,21 +36,7 @@ function ($scope, $state, $stateParams, $filter, Config, Network, Container, Con
});
};
function getNetwork() {
$('#loadingViewSpinner').show();
Network.get({id: $stateParams.id}, function success(data) {
$scope.network = data;
getContainersInNetwork(data);
}, function error(err) {
$('#loadingViewSpinner').hide();
Notifications.error('Failure', err, 'Unable to retrieve network info');
});
}
function filterContainersInNetwork(network, containers) {
if ($scope.containersToHideLabels) {
containers = ContainerHelper.hideContainers(containers, $scope.containersToHideLabels);
}
var containersInNetwork = [];
containers.forEach(function(container) {
var containerInNetwork = network.Containers[container.Id];
@ -93,8 +79,16 @@ function ($scope, $state, $stateParams, $filter, Config, Network, Container, Con
}
}
Config.$promise.then(function (c) {
$scope.containersToHideLabels = c.hiddenLabels;
getNetwork();
});
function initView() {
$('#loadingViewSpinner').show();
Network.get({id: $stateParams.id}, function success(data) {
$scope.network = data;
getContainersInNetwork(data);
}, function error(err) {
$('#loadingViewSpinner').hide();
Notifications.error('Failure', err, 'Unable to retrieve network info');
});
}
initView();
}]);

View file

@ -1,6 +1,6 @@
angular.module('networks', [])
.controller('NetworksController', ['$scope', '$state', 'Network', 'Config', 'Notifications', 'Pagination',
function ($scope, $state, Network, Config, Notifications, Pagination) {
.controller('NetworksController', ['$scope', '$state', 'Network', 'Notifications', 'Pagination',
function ($scope, $state, Network, Notifications, Pagination) {
$scope.state = {};
$scope.state.pagination_count = Pagination.getPaginationCount('networks');
$scope.state.selectedItemCount = 0;
@ -97,7 +97,7 @@ function ($scope, $state, Network, Config, Notifications, Pagination) {
});
};
function fetchNetworks() {
function initView() {
$('#loadNetworksSpinner').show();
Network.query({}, function (d) {
$scope.networks = d;
@ -109,7 +109,5 @@ function ($scope, $state, Network, Config, Notifications, Pagination) {
});
}
Config.$promise.then(function (c) {
fetchNetworks();
});
initView();
}]);

View file

@ -1,66 +1,153 @@
<rd-header>
<rd-header-title title="Settings">
<i id="loadingViewSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px;"></i>
</rd-header-title>
<rd-header-content>Settings</rd-header-content>
</rd-header>
<div class="row">
<div class="col-lg-12 col-md-12 col-xs-12">
<div class="col-sm-12">
<rd-widget>
<rd-widget-header icon="fa-lock" title="Change user password"></rd-widget-header>
<rd-widget-header icon="fa-cogs" title="Application settings"></rd-widget-header>
<rd-widget-body>
<form class="form-horizontal" style="margin-top: 15px;">
<!-- current-password-input -->
<form class="form-horizontal">
<!-- logo -->
<div class="col-sm-12 form-section-title">
Logo
</div>
<div class="form-group">
<label for="current_password" class="col-sm-2 control-label text-left">Current password</label>
<div class="col-sm-8">
<div class="input-group">
<span class="input-group-addon"><i class="fa fa-lock" aria-hidden="true"></i></span>
<input type="password" class="form-control" ng-model="formValues.currentPassword" id="current_password">
<div class="col-sm-12">
<label for="toggle_logo" class="control-label text-left">
Use custom logo
</label>
<label class="switch" style="margin-left: 20px;">
<input type="checkbox" name="toggle_logo" ng-model="formValues.customLogo"><i></i>
</label>
</div>
</div>
<div ng-if="formValues.customLogo">
<div class="form-group">
<span class="col-sm-12 text-muted small">
You can specify the URL to your logo here. For an optimal display, logo dimensions should be 155px by 55px.
</span>
</div>
<div class="form-group">
<label for="logo_url" class="col-sm-1 control-label text-left">
URL
</label>
<div class="col-sm-11">
<input type="text" class="form-control" ng-model="settings.LogoURL" id="logo_url" placeholder="https://mycompany.com/logo.png">
</div>
</div>
</div>
<!-- !current-password-input -->
<div class="form-group" ng-if="invalidPassword">
<!-- !logo -->
<!-- app-templates -->
<div class="col-sm-12 form-section-title">
App Templates
</div>
<div class="form-group">
<div class="col-sm-12">
<i class="fa fa-times red-icon" aria-hidden="true"></i>
<span class="small text-muted">Current password is not valid</span>
<label for="toggle_templates" class="control-label text-left">
Use custom templates
</label>
<label class="switch" style="margin-left: 20px;">
<input type="checkbox" name="toggle_templates" ng-model="formValues.customTemplates"><i></i>
</label>
</div>
</div>
<!-- new-password-input -->
<div class="form-group">
<label for="new_password" class="col-sm-2 control-label text-left">New password</label>
<div class="col-sm-8">
<div class="input-group">
<span class="input-group-addon"><i class="fa fa-lock" aria-hidden="true"></i></span>
<input type="password" class="form-control" ng-model="formValues.newPassword" id="new_password">
<div ng-if="formValues.customTemplates">
<div class="form-group">
<span class="col-sm-12 text-muted small">
You can specify the URL to your own template definitions file here. See <a href="https://portainer.readthedocs.io/en/stable/templates.html" target="_blank">Portainer documentation</a> for more details.
</span>
</div>
<div class="form-group" >
<label for="templates_url" class="col-sm-1 control-label text-left">
URL
</label>
<div class="col-sm-11">
<input type="text" class="form-control" ng-model="settings.TemplatesURL" id="templates_url" placeholder="https://myserver.mydomain/templates.json">
</div>
</div>
</div>
<!-- !new-password-input -->
<div class="form-group">
<div class="col-sm-12">
<i ng-class="{true: 'fa fa-check green-icon', false: 'fa fa-times red-icon'}[formValues.newPassword.length >= 8]" aria-hidden="true"></i>
<span class="small text-muted">Your new password must be at least 8 characters long</span>
<label for="toggle_external_contrib" class="control-label text-left">
Hide external contributions
<portainer-tooltip position="bottom" message="When enabled, external contributions such as LinuxServer.io will not be displayed in the sidebar."></portainer-tooltip>
</label>
<label class="switch" style="margin-left: 20px;">
<input type="checkbox" name="toggle_external_contrib" ng-model="formValues.externalContributions"><i></i>
</label>
</div>
</div>
<!-- confirm-password-input -->
<div class="form-group">
<label for="confirm_password" class="col-sm-2 control-label text-left">Confirm password</label>
<div class="col-sm-8">
<div class="input-group">
<span class="input-group-addon"><i class="fa fa-lock" aria-hidden="true"></i></span>
<input type="password" class="form-control" ng-model="formValues.confirmPassword" id="confirm_password">
<span class="input-group-addon"><i ng-class="{true: 'fa fa-check green-icon', false: 'fa fa-times red-icon'}[formValues.newPassword !== '' && formValues.newPassword === formValues.confirmPassword]" aria-hidden="true"></i></span>
</div>
</div>
</div>
<!-- !confirm-password-input -->
<!-- !app-templates -->
<!-- actions -->
<div class="form-group">
<div class="col-sm-12">
<button type="submit" class="btn btn-primary btn-sm" ng-disabled="!formValues.currentPassword || formValues.newPassword.length < 8 || formValues.newPassword !== formValues.confirmPassword" ng-click="updatePassword()">Update password</button>
<button type="button" class="btn btn-primary btn-sm" ng-click="saveApplicationSettings()">Save</button>
<i id="updateSettingsSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px; display: none;"></i>
<!-- <span class="text-danger" ng-if="state.formValidationError" style="margin-left: 5px;">{{ state.formValidationError }}</span> -->
</div>
</div>
<!-- !actions -->
</form>
</rd-widget-body>
</rd-widget>
</div>
</div>
<div class="row">
<div class="col-sm-12">
<rd-widget>
<rd-widget-header icon="fa-tags" title="Filtered containers"></rd-widget-header>
<rd-widget-body>
<form class="form-horizontal">
<div class="form-group">
<span class="col-sm-12 text-muted small">
You can hide containers with specific labels from Portainer UI. You need to specify the label name and value.
</span>
</div>
<div class="form-group">
<label for="header_name" class="col-sm-1 control-label text-left">Name</label>
<div class="col-sm-11 col-md-4">
<input type="text" class="form-control" id="header_name" ng-model="formValues.labelName" placeholder="e.g. com.example.foo">
</div>
<label for="header_value" class="col-sm-1 margin-sm-top control-label text-left">Value</label>
<div class="col-sm-11 col-md-4 margin-sm-top">
<input type="text" class="form-control" id="header_value" ng-model="formValues.labelValue" placeholder="e.g. bar">
</div>
<div class="col-sm-12 col-md-2 margin-sm-top">
<button type="button" class="btn btn-primary btn-sm" ng-click="addFilteredContainerLabel()"><i class="fa fa-plus space-right" aria-hidden="true"></i>Add label</button>
</div>
</div>
<div class="form-group">
<div class="col-sm-12 table-responsive">
<table class="table table-hover">
<thead>
<tr>
<th>Name</th>
<th>Value</th>
<th></th>
</tr>
</thead>
<tbody>
<tr ng-repeat="label in settings.BlackListedLabels">
<td>{{ label.name }}</td>
<td>{{ label.value }}</td>
<td><button type="button" class="btn btn-danger btn-xs" ng-click="removeFilteredContainerLabel($index)"><i class="fa fa-trash space-right" aria-hidden="true"></i>Remove</button></td>
</tr>
<tr ng-if="settings.BlackListedLabels.length === 0">
<td colspan="2" class="text-center text-muted">No filtered containers labels.</td>
</tr>
<tr ng-if="!settings.BlackListedLabels">
<td colspan="2" class="text-center text-muted">Loading...</td>
</tr>
</tbody>
</table>
</div>
</div>
<!-- !filtered-labels -->
</form>
</rd-widget-body>
</rd-widget>

View file

@ -1,29 +1,94 @@
angular.module('settings', [])
.controller('SettingsController', ['$scope', '$state', '$sanitize', 'Authentication', 'UserService', 'Notifications',
function ($scope, $state, $sanitize, Authentication, UserService, Notifications) {
.controller('SettingsController', ['$scope', '$state', 'Notifications', 'SettingsService', 'StateManager', 'DEFAULT_TEMPLATES_URL',
function ($scope, $state, Notifications, SettingsService, StateManager, DEFAULT_TEMPLATES_URL) {
$scope.formValues = {
currentPassword: '',
newPassword: '',
confirmPassword: ''
customLogo: false,
customTemplates: false,
externalContributions: false,
labelName: '',
labelValue: ''
};
$scope.updatePassword = function() {
$scope.invalidPassword = false;
var userID = Authentication.getUserDetails().ID;
var currentPassword = $sanitize($scope.formValues.currentPassword);
var newPassword = $sanitize($scope.formValues.newPassword);
$scope.removeFilteredContainerLabel = function(index) {
var settings = $scope.settings;
settings.BlackListedLabels.splice(index, 1);
UserService.updateUserPassword(userID, currentPassword, newPassword)
.then(function success() {
Notifications.success('Success', 'Password successfully updated');
$state.reload();
updateSettings(settings, false);
};
$scope.addFilteredContainerLabel = function() {
var settings = $scope.settings;
var label = {
name: $scope.formValues.labelName,
value: $scope.formValues.labelValue
};
settings.BlackListedLabels.push(label);
updateSettings(settings, true);
};
$scope.saveApplicationSettings = function() {
var settings = $scope.settings;
if (!$scope.formValues.customLogo) {
settings.LogoURL = '';
}
if (!$scope.formValues.customTemplates) {
settings.TemplatesURL = DEFAULT_TEMPLATES_URL;
}
settings.DisplayExternalContributors = !$scope.formValues.externalContributions;
updateSettings(settings, false);
};
function resetFormValues() {
$scope.formValues.labelName = '';
$scope.formValues.labelValue = '';
}
function updateSettings(settings, resetForm) {
$('#loadingViewSpinner').show();
SettingsService.update(settings)
.then(function success(data) {
Notifications.success('Settings updated');
StateManager.updateLogo(settings.LogoURL);
StateManager.updateExternalContributions(settings.DisplayExternalContributors);
if (resetForm) {
resetFormValues();
}
})
.catch(function error(err) {
if (err.invalidPassword) {
$scope.invalidPassword = true;
} else {
Notifications.error('Failure', err, err.msg);
}
Notifications.error('Failure', err, 'Unable to update settings');
})
.finally(function final() {
$('#loadingViewSpinner').hide();
});
};
}
function initView() {
$('#loadingViewSpinner').show();
SettingsService.settings()
.then(function success(data) {
var settings = data;
$scope.settings = settings;
if (settings.LogoURL !== '') {
$scope.formValues.customLogo = true;
}
if (settings.TemplatesURL !== DEFAULT_TEMPLATES_URL) {
$scope.formValues.customTemplates = true;
}
$scope.formValues.externalContributions = !settings.DisplayExternalContributors;
})
.catch(function error(err) {
Notifications.error('Failure', err, 'Unable to retrieve application settings');
})
.finally(function final() {
$('#loadingViewSpinner').hide();
});
}
initView();
}]);

View file

@ -21,7 +21,7 @@
</li>
<li class="sidebar-list">
<a ui-sref="templates" ui-sref-active="active">App Templates <span class="menu-icon fa fa-rocket"></span></a>
<div class="sidebar-sublist" ng-if="toggle && ($state.current.name === 'templates' || $state.current.name === 'templates_linuxserver')">
<div class="sidebar-sublist" ng-if="toggle && displayExternalContributors && ($state.current.name === 'templates' || $state.current.name === 'templates_linuxserver')">
<a ui-sref="templates_linuxserver" ui-sref-active="active">LinuxServer.io</a>
</div>
</li>
@ -52,7 +52,7 @@
<li class="sidebar-list" ng-if="applicationState.endpoint.mode.provider === 'DOCKER_STANDALONE'">
<a ui-sref="docker" ui-sref-active="active">Docker <span class="menu-icon fa fa-th"></span></a>
</li>
<li class="sidebar-title" ng-if="isAdmin || isTeamLeader">
<li class="sidebar-title" ng-if="!applicationState.application.authentication || isAdmin || isTeamLeader">
<span>Portainer settings</span>
</li>
<li class="sidebar-list" ng-if="applicationState.application.authentication && (isAdmin || isTeamLeader)">
@ -64,6 +64,9 @@
<li class="sidebar-list" ng-if="!applicationState.application.authentication || isAdmin">
<a ui-sref="endpoints" ui-sref-active="active">Endpoints <span class="menu-icon fa fa-plug"></span></a>
</li>
<li class="sidebar-list" ng-if="!applicationState.application.authentication || isAdmin">
<a ui-sref="settings" ui-sref-active="active">Settings <span class="menu-icon fa fa-cogs"></span></a>
</li>
</ul>
<div class="sidebar-footer">
<div class="col-xs-12">

View file

@ -1,12 +1,10 @@
angular.module('sidebar', [])
.controller('SidebarController', ['$q', '$scope', '$state', 'Settings', 'Config', 'EndpointService', 'StateManager', 'EndpointProvider', 'Notifications', 'Authentication', 'UserService',
function ($q, $scope, $state, Settings, Config, EndpointService, StateManager, EndpointProvider, Notifications, Authentication, UserService) {
.controller('SidebarController', ['$q', '$scope', '$state', 'Settings', 'EndpointService', 'StateManager', 'EndpointProvider', 'Notifications', 'Authentication', 'UserService',
function ($q, $scope, $state, Settings, EndpointService, StateManager, EndpointProvider, Notifications, Authentication, UserService) {
Config.$promise.then(function (c) {
$scope.logo = c.logo;
});
$scope.uiVersion = Settings.uiVersion;
$scope.uiVersion = StateManager.getState().application.version;
$scope.displayExternalContributors = StateManager.getState().application.displayExternalContributors;
$scope.logo = StateManager.getState().application.logo;
$scope.endpoints = [];
$scope.switchEndpoint = function(endpoint) {

View file

@ -1,6 +1,6 @@
angular.module('templates', [])
.controller('TemplatesController', ['$scope', '$q', '$state', '$stateParams', '$anchorScroll', '$filter', 'Config', 'ContainerService', 'ContainerHelper', 'ImageService', 'NetworkService', 'TemplateService', 'TemplateHelper', 'VolumeService', 'Notifications', 'Pagination', 'ResourceControlService', 'Authentication', 'ControllerDataPipeline', 'FormValidator',
function ($scope, $q, $state, $stateParams, $anchorScroll, $filter, Config, ContainerService, ContainerHelper, ImageService, NetworkService, TemplateService, TemplateHelper, VolumeService, Notifications, Pagination, ResourceControlService, Authentication, ControllerDataPipeline, FormValidator) {
.controller('TemplatesController', ['$scope', '$q', '$state', '$stateParams', '$anchorScroll', '$filter', 'ContainerService', 'ContainerHelper', 'ImageService', 'NetworkService', 'TemplateService', 'TemplateHelper', 'VolumeService', 'Notifications', 'Pagination', 'ResourceControlService', 'Authentication', 'ControllerDataPipeline', 'FormValidator',
function ($scope, $q, $state, $stateParams, $anchorScroll, $filter, ContainerService, ContainerHelper, ImageService, NetworkService, TemplateService, TemplateHelper, VolumeService, Notifications, Pagination, ResourceControlService, Authentication, ControllerDataPipeline, FormValidator) {
$scope.state = {
selectedTemplate: null,
showAdvancedOptions: false,
@ -159,31 +159,29 @@ function ($scope, $q, $state, $stateParams, $anchorScroll, $filter, Config, Cont
function initTemplates() {
var templatesKey = $stateParams.key;
Config.$promise.then(function (c) {
$q.all({
templates: TemplateService.getTemplates(templatesKey),
containers: ContainerService.getContainers(0, c.hiddenLabels),
networks: NetworkService.networks(),
volumes: VolumeService.getVolumes()
})
.then(function success(data) {
$scope.templates = data.templates;
var availableCategories = [];
angular.forEach($scope.templates, function(template) {
availableCategories = availableCategories.concat(template.Categories);
});
$scope.availableCategories = _.sortBy(_.uniq(availableCategories));
$scope.runningContainers = data.containers;
$scope.availableNetworks = filterNetworksBasedOnProvider(data.networks);
$scope.availableVolumes = data.volumes.Volumes;
})
.catch(function error(err) {
$scope.templates = [];
Notifications.error('Failure', err, 'An error occured during apps initialization.');
})
.finally(function final(){
$('#loadTemplatesSpinner').hide();
$q.all({
templates: TemplateService.getTemplates(templatesKey),
containers: ContainerService.getContainers(0),
networks: NetworkService.networks(),
volumes: VolumeService.getVolumes()
})
.then(function success(data) {
$scope.templates = data.templates;
var availableCategories = [];
angular.forEach($scope.templates, function(template) {
availableCategories = availableCategories.concat(template.Categories);
});
$scope.availableCategories = _.sortBy(_.uniq(availableCategories));
$scope.runningContainers = data.containers;
$scope.availableNetworks = filterNetworksBasedOnProvider(data.networks);
$scope.availableVolumes = data.volumes.Volumes;
})
.catch(function error(err) {
$scope.templates = [];
Notifications.error('Failure', err, 'An error occured during apps initialization.');
})
.finally(function final(){
$('#loadTemplatesSpinner').hide();
});
}

View file

@ -0,0 +1,68 @@
<rd-header>
<rd-header-title title="User settings">
</rd-header-title>
<rd-header-content>User settings</rd-header-content>
</rd-header>
<div class="row">
<div class="col-lg-12 col-md-12 col-xs-12">
<rd-widget>
<rd-widget-header icon="fa-lock" title="Change user password"></rd-widget-header>
<rd-widget-body>
<form class="form-horizontal" style="margin-top: 15px;">
<!-- current-password-input -->
<div class="form-group">
<label for="current_password" class="col-sm-2 control-label text-left">Current password</label>
<div class="col-sm-8">
<div class="input-group">
<span class="input-group-addon"><i class="fa fa-lock" aria-hidden="true"></i></span>
<input type="password" class="form-control" ng-model="formValues.currentPassword" id="current_password">
</div>
</div>
</div>
<!-- !current-password-input -->
<div class="form-group" ng-if="invalidPassword">
<div class="col-sm-12">
<i class="fa fa-times red-icon" aria-hidden="true"></i>
<span class="small text-muted">Current password is not valid</span>
</div>
</div>
<!-- new-password-input -->
<div class="form-group">
<label for="new_password" class="col-sm-2 control-label text-left">New password</label>
<div class="col-sm-8">
<div class="input-group">
<span class="input-group-addon"><i class="fa fa-lock" aria-hidden="true"></i></span>
<input type="password" class="form-control" ng-model="formValues.newPassword" id="new_password">
</div>
</div>
</div>
<!-- !new-password-input -->
<div class="form-group">
<div class="col-sm-12">
<i ng-class="{true: 'fa fa-check green-icon', false: 'fa fa-times red-icon'}[formValues.newPassword.length >= 8]" aria-hidden="true"></i>
<span class="small text-muted">Your new password must be at least 8 characters long</span>
</div>
</div>
<!-- confirm-password-input -->
<div class="form-group">
<label for="confirm_password" class="col-sm-2 control-label text-left">Confirm password</label>
<div class="col-sm-8">
<div class="input-group">
<span class="input-group-addon"><i class="fa fa-lock" aria-hidden="true"></i></span>
<input type="password" class="form-control" ng-model="formValues.confirmPassword" id="confirm_password">
<span class="input-group-addon"><i ng-class="{true: 'fa fa-check green-icon', false: 'fa fa-times red-icon'}[formValues.newPassword !== '' && formValues.newPassword === formValues.confirmPassword]" aria-hidden="true"></i></span>
</div>
</div>
</div>
<!-- !confirm-password-input -->
<div class="form-group">
<div class="col-sm-12">
<button type="submit" class="btn btn-primary btn-sm" ng-disabled="!formValues.currentPassword || formValues.newPassword.length < 8 || formValues.newPassword !== formValues.confirmPassword" ng-click="updatePassword()">Update password</button>
</div>
</div>
</form>
</rd-widget-body>
</rd-widget>
</div>
</div>

View file

@ -0,0 +1,29 @@
angular.module('userSettings', [])
.controller('UserSettingsController', ['$scope', '$state', '$sanitize', 'Authentication', 'UserService', 'Notifications',
function ($scope, $state, $sanitize, Authentication, UserService, Notifications) {
$scope.formValues = {
currentPassword: '',
newPassword: '',
confirmPassword: ''
};
$scope.updatePassword = function() {
$scope.invalidPassword = false;
var userID = Authentication.getUserDetails().ID;
var currentPassword = $sanitize($scope.formValues.currentPassword);
var newPassword = $sanitize($scope.formValues.newPassword);
UserService.updateUserPassword(userID, currentPassword, newPassword)
.then(function success() {
Notifications.success('Success', 'Password successfully updated');
$state.reload();
})
.catch(function error(err) {
if (err.invalidPassword) {
$scope.invalidPassword = true;
} else {
Notifications.error('Failure', err, err.msg);
}
});
};
}]);

View file

@ -7,7 +7,7 @@ angular
link: function (scope, iElement, iAttrs) {
scope.username = Authentication.getUserDetails().username;
},
template: '<div class="breadcrumb-links"><div class="pull-left" ng-transclude></div><div class="pull-right" ng-if="username"><a ui-sref="settings" style="margin-right: 5px;"><u><i class="fa fa-wrench" aria-hidden="true"></i> my account </u></a><a ui-sref="auth({logout: true})" class="text-danger" style="margin-right: 25px;"><u><i class="fa fa-sign-out" aria-hidden="true"></i> log out</u></a></div></div>',
template: '<div class="breadcrumb-links"><div class="pull-left" ng-transclude></div><div class="pull-right" ng-if="username"><a ui-sref="userSettings" style="margin-right: 5px;"><u><i class="fa fa-wrench" aria-hidden="true"></i> my account </u></a><a ui-sref="auth({logout: true})" class="text-danger" style="margin-right: 25px;"><u><i class="fa fa-sign-out" aria-hidden="true"></i> log out</u></a></div></div>',
restrict: 'E'
};
return directive;

View file

@ -7,20 +7,5 @@ angular.module('portainer.helpers')
return splitargs(command);
};
helper.hideContainers = function(containers, containersToHideLabels) {
return containers.filter(function (container) {
var filterContainer = false;
containersToHideLabels.forEach(function(label, index) {
if (_.has(container.Labels, label.name) &&
container.Labels[label.name] === label.value) {
filterContainer = true;
}
});
if (!filterContainer) {
return container;
}
});
};
return helper;
}]);

View file

@ -0,0 +1,6 @@
function SettingsViewModel(data) {
this.TemplatesURL = data.TemplatesURL;
this.LogoURL = data.LogoURL;
this.BlackListedLabels = data.BlackListedLabels;
this.DisplayExternalContributors = data.DisplayExternalContributors;
}

6
app/models/api/status.js Normal file
View file

@ -0,0 +1,6 @@
function StatusViewModel(data) {
this.Authentication = data.Authentication;
this.EndpointManagement = data.EndpointManagement;
this.Analytics = data.Analytics;
this.Version = data.Version;
}

8
app/rest/api/settings.js Normal file
View file

@ -0,0 +1,8 @@
angular.module('portainer.rest')
.factory('Settings', ['$resource', 'SETTINGS_ENDPOINT', function SettingsFactory($resource, SETTINGS_ENDPOINT) {
'use strict';
return $resource(SETTINGS_ENDPOINT, {}, {
get: { method: 'GET' },
update: { method: 'PUT' }
});
}]);

7
app/rest/api/status.js Normal file
View file

@ -0,0 +1,7 @@
angular.module('portainer.rest')
.factory('Status', ['$resource', 'STATUS_ENDPOINT', function StatusFactory($resource, STATUS_ENDPOINT) {
'use strict';
return $resource(STATUS_ENDPOINT, {}, {
get: { method: 'GET' }
});
}]);

View file

@ -1,4 +0,0 @@
angular.module('portainer.rest')
.factory('Config', ['$resource', 'CONFIG_ENDPOINT', function ConfigFactory($resource, CONFIG_ENDPOINT) {
return $resource(CONFIG_ENDPOINT).get();
}]);

View file

@ -1,10 +0,0 @@
angular.module('portainer.rest')
.factory('ContainerCommit', ['$resource', 'Settings', 'EndpointProvider', function ContainerCommitFactory($resource, Settings, EndpointProvider) {
'use strict';
return $resource(Settings.url + '/:endpointId/commit', {
endpointId: EndpointProvider.endpointID
},
{
commit: {method: 'POST', params: {container: '@id', repo: '@repo', tag: '@tag'}}
});
}]);

View file

@ -1,7 +1,7 @@
angular.module('portainer.rest')
.factory('Container', ['$resource', 'Settings', 'EndpointProvider', function ContainerFactory($resource, Settings, EndpointProvider) {
.factory('Container', ['$resource', 'DOCKER_ENDPOINT', 'EndpointProvider', function ContainerFactory($resource, DOCKER_ENDPOINT, EndpointProvider) {
'use strict';
return $resource(Settings.url + '/:endpointId/containers/:id/:action', {
return $resource(DOCKER_ENDPOINT + '/:endpointId/containers/:id/:action', {
name: '@name',
endpointId: EndpointProvider.endpointID
},

View file

@ -0,0 +1,10 @@
angular.module('portainer.rest')
.factory('ContainerCommit', ['$resource', 'DOCKER_ENDPOINT', 'EndpointProvider', function ContainerCommitFactory($resource, DOCKER_ENDPOINT, EndpointProvider) {
'use strict';
return $resource(DOCKER_ENDPOINT + '/:endpointId/commit', {
endpointId: EndpointProvider.endpointID
},
{
commit: {method: 'POST', params: {container: '@id', repo: '@repo', tag: '@tag'}}
});
}]);

View file

@ -1,11 +1,11 @@
angular.module('portainer.rest')
.factory('ContainerLogs', ['$http', 'Settings', 'EndpointProvider', function ContainerLogsFactory($http, Settings, EndpointProvider) {
.factory('ContainerLogs', ['$http', 'DOCKER_ENDPOINT', 'EndpointProvider', function ContainerLogsFactory($http, DOCKER_ENDPOINT, EndpointProvider) {
'use strict';
return {
get: function (id, params, callback) {
$http({
method: 'GET',
url: Settings.url + '/' + EndpointProvider.endpointID() + '/containers/' + id + '/logs',
url: DOCKER_ENDPOINT + '/' + EndpointProvider.endpointID() + '/containers/' + id + '/logs',
params: {
'stdout': params.stdout || 0,
'stderr': params.stderr || 0,

View file

@ -1,11 +1,11 @@
angular.module('portainer.rest')
.factory('ContainerTop', ['$http', 'Settings', 'EndpointProvider', function ($http, Settings, EndpointProvider) {
.factory('ContainerTop', ['$http', 'DOCKER_ENDPOINT', 'EndpointProvider', function ($http, DOCKER_ENDPOINT, EndpointProvider) {
'use strict';
return {
get: function (id, params, callback, errorCallback) {
$http({
method: 'GET',
url: Settings.url + '/' + EndpointProvider.endpointID() + '/containers/' + id + '/top',
url: DOCKER_ENDPOINT + '/' + EndpointProvider.endpointID() + '/containers/' + id + '/top',
params: {
ps_args: params.ps_args
}

View file

@ -1,7 +1,7 @@
angular.module('portainer.rest')
.factory('Events', ['$resource', 'Settings', 'EndpointProvider', function EventFactory($resource, Settings, EndpointProvider) {
.factory('Events', ['$resource', 'DOCKER_ENDPOINT', 'EndpointProvider', function EventFactory($resource, DOCKER_ENDPOINT, EndpointProvider) {
'use strict';
return $resource(Settings.url + '/:endpointId/events', {
return $resource(DOCKER_ENDPOINT + '/:endpointId/events', {
endpointId: EndpointProvider.endpointID
},
{

View file

@ -1,7 +1,7 @@
angular.module('portainer.rest')
.factory('Exec', ['$resource', 'Settings', 'EndpointProvider', function ExecFactory($resource, Settings, EndpointProvider) {
.factory('Exec', ['$resource', 'DOCKER_ENDPOINT', 'EndpointProvider', function ExecFactory($resource, DOCKER_ENDPOINT, EndpointProvider) {
'use strict';
return $resource(Settings.url + '/:endpointId/exec/:id/:action', {
return $resource(DOCKER_ENDPOINT + '/:endpointId/exec/:id/:action', {
endpointId: EndpointProvider.endpointID
},
{

View file

@ -1,7 +1,7 @@
angular.module('portainer.rest')
.factory('Image', ['$resource', 'Settings', 'EndpointProvider', function ImageFactory($resource, Settings, EndpointProvider) {
.factory('Image', ['$resource', 'DOCKER_ENDPOINT', 'EndpointProvider', function ImageFactory($resource, DOCKER_ENDPOINT, EndpointProvider) {
'use strict';
return $resource(Settings.url + '/:endpointId/images/:id/:action', {
return $resource(DOCKER_ENDPOINT + '/:endpointId/images/:id/:action', {
endpointId: EndpointProvider.endpointID
},
{

7
app/rest/docker/info.js Normal file
View file

@ -0,0 +1,7 @@
angular.module('portainer.rest')
.factory('Info', ['$resource', 'DOCKER_ENDPOINT', 'EndpointProvider', function InfoFactory($resource, DOCKER_ENDPOINT, EndpointProvider) {
'use strict';
return $resource(DOCKER_ENDPOINT + '/:endpointId/info', {
endpointId: EndpointProvider.endpointID
});
}]);

View file

@ -1,7 +1,7 @@
angular.module('portainer.rest')
.factory('Network', ['$resource', 'Settings', 'EndpointProvider', function NetworkFactory($resource, Settings, EndpointProvider) {
.factory('Network', ['$resource', 'DOCKER_ENDPOINT', 'EndpointProvider', function NetworkFactory($resource, DOCKER_ENDPOINT, EndpointProvider) {
'use strict';
return $resource(Settings.url + '/:endpointId/networks/:id/:action', {
return $resource(DOCKER_ENDPOINT + '/:endpointId/networks/:id/:action', {
id: '@id',
endpointId: EndpointProvider.endpointID
},

View file

@ -1,7 +1,7 @@
angular.module('portainer.rest')
.factory('Node', ['$resource', 'Settings', 'EndpointProvider', function NodeFactory($resource, Settings, EndpointProvider) {
.factory('Node', ['$resource', 'DOCKER_ENDPOINT', 'EndpointProvider', function NodeFactory($resource, DOCKER_ENDPOINT, EndpointProvider) {
'use strict';
return $resource(Settings.url + '/:endpointId/nodes/:id/:action', {
return $resource(DOCKER_ENDPOINT + '/:endpointId/nodes/:id/:action', {
endpointId: EndpointProvider.endpointID
},
{

View file

@ -1,7 +1,7 @@
angular.module('portainer.rest')
.factory('Secret', ['$resource', 'Settings', 'EndpointProvider', function SecretFactory($resource, Settings, EndpointProvider) {
.factory('Secret', ['$resource', 'DOCKER_ENDPOINT', 'EndpointProvider', function SecretFactory($resource, DOCKER_ENDPOINT, EndpointProvider) {
'use strict';
return $resource(Settings.url + '/:endpointId/secrets/:id/:action', {
return $resource(DOCKER_ENDPOINT + '/:endpointId/secrets/:id/:action', {
endpointId: EndpointProvider.endpointID
}, {
get: { method: 'GET', params: {id: '@id'} },

View file

@ -1,7 +1,7 @@
angular.module('portainer.rest')
.factory('Service', ['$resource', 'Settings', 'EndpointProvider', function ServiceFactory($resource, Settings, EndpointProvider) {
.factory('Service', ['$resource', 'DOCKER_ENDPOINT', 'EndpointProvider', function ServiceFactory($resource, DOCKER_ENDPOINT, EndpointProvider) {
'use strict';
return $resource(Settings.url + '/:endpointId/services/:id/:action', {
return $resource(DOCKER_ENDPOINT + '/:endpointId/services/:id/:action', {
endpointId: EndpointProvider.endpointID
},
{

10
app/rest/docker/swarm.js Normal file
View file

@ -0,0 +1,10 @@
angular.module('portainer.rest')
.factory('Swarm', ['$resource', 'DOCKER_ENDPOINT', 'EndpointProvider', function SwarmFactory($resource, DOCKER_ENDPOINT, EndpointProvider) {
'use strict';
return $resource(DOCKER_ENDPOINT + '/:endpointId/swarm', {
endpointId: EndpointProvider.endpointID
},
{
get: {method: 'GET'}
});
}]);

View file

@ -1,7 +1,7 @@
angular.module('portainer.rest')
.factory('Task', ['$resource', 'Settings', 'EndpointProvider', function TaskFactory($resource, Settings, EndpointProvider) {
.factory('Task', ['$resource', 'DOCKER_ENDPOINT', 'EndpointProvider', function TaskFactory($resource, DOCKER_ENDPOINT, EndpointProvider) {
'use strict';
return $resource(Settings.url + '/:endpointId/tasks/:id', {
return $resource(DOCKER_ENDPOINT + '/:endpointId/tasks/:id', {
endpointId: EndpointProvider.endpointID
},
{

View file

@ -0,0 +1,7 @@
angular.module('portainer.rest')
.factory('Version', ['$resource', 'DOCKER_ENDPOINT', 'EndpointProvider', function VersionFactory($resource, DOCKER_ENDPOINT, EndpointProvider) {
'use strict';
return $resource(DOCKER_ENDPOINT + '/:endpointId/version', {
endpointId: EndpointProvider.endpointID
});
}]);

View file

@ -1,7 +1,7 @@
angular.module('portainer.rest')
.factory('Volume', ['$resource', 'Settings', 'EndpointProvider', function VolumeFactory($resource, Settings, EndpointProvider) {
.factory('Volume', ['$resource', 'DOCKER_ENDPOINT', 'EndpointProvider', function VolumeFactory($resource, DOCKER_ENDPOINT, EndpointProvider) {
'use strict';
return $resource(Settings.url + '/:endpointId/volumes/:id/:action',
return $resource(DOCKER_ENDPOINT + '/:endpointId/volumes/:id/:action',
{
endpointId: EndpointProvider.endpointID
},

View file

@ -1,7 +0,0 @@
angular.module('portainer.rest')
.factory('Info', ['$resource', 'Settings', 'EndpointProvider', function InfoFactory($resource, Settings, EndpointProvider) {
'use strict';
return $resource(Settings.url + '/:endpointId/info', {
endpointId: EndpointProvider.endpointID
});
}]);

View file

@ -1,10 +0,0 @@
angular.module('portainer.rest')
.factory('Swarm', ['$resource', 'Settings', 'EndpointProvider', function SwarmFactory($resource, Settings, EndpointProvider) {
'use strict';
return $resource(Settings.url + '/:endpointId/swarm', {
endpointId: EndpointProvider.endpointID
},
{
get: {method: 'GET'}
});
}]);

View file

@ -1,7 +0,0 @@
angular.module('portainer.rest')
.factory('Version', ['$resource', 'Settings', 'EndpointProvider', function VersionFactory($resource, Settings, EndpointProvider) {
'use strict';
return $resource(Settings.url + '/:endpointId/version', {
endpointId: EndpointProvider.endpointID
});
}]);

View file

@ -0,0 +1,26 @@
angular.module('portainer.services')
.factory('SettingsService', ['$q', 'Settings', function SettingsServiceFactory($q, Settings) {
'use strict';
var service = {};
service.settings = function() {
var deferred = $q.defer();
Settings.get().$promise
.then(function success(data) {
var status = new SettingsViewModel(data);
deferred.resolve(status);
})
.catch(function error(err) {
deferred.reject({ msg: 'Unable to retrieve application settings', err: err });
});
return deferred.promise;
};
service.update = function(settings) {
return Settings.update({}, settings).$promise;
};
return service;
}]);

View file

@ -0,0 +1,22 @@
angular.module('portainer.services')
.factory('StatusService', ['$q', 'Status', function StatusServiceFactory($q, Status) {
'use strict';
var service = {};
service.status = function() {
var deferred = $q.defer();
Status.get().$promise
.then(function success(data) {
var status = new StatusViewModel(data);
deferred.resolve(status);
})
.catch(function error(err) {
deferred.reject({ msg: 'Unable to retrieve application status', err: err });
});
return deferred.promise;
};
return service;
}]);

View file

@ -1,17 +1,14 @@
angular.module('portainer.services')
.factory('ContainerService', ['$q', 'Container', 'ContainerHelper', 'ResourceControlService', function ContainerServiceFactory($q, Container, ContainerHelper, ResourceControlService) {
.factory('ContainerService', ['$q', 'Container', 'ResourceControlService', function ContainerServiceFactory($q, Container, ResourceControlService) {
'use strict';
var service = {};
service.getContainers = function (all, hiddenLabels) {
service.getContainers = function (all) {
var deferred = $q.defer();
Container.query({ all: all }).$promise
.then(function success(data) {
var containers = data;
if (hiddenLabels) {
containers = ContainerHelper.hideContainers(data, hiddenLabels);
}
deferred.resolve(data);
deferred.resolve(containers);
})
.catch(function error(err) {
deferred.reject({ msg: 'Unable to retriever containers', err: err });

View file

@ -1,5 +1,5 @@
angular.module('portainer.services')
.factory('LineChart', ['Settings', function LineChartFactory(Settings) {
.factory('LineChart', [function LineChartFactory() {
'use strict';
return {
build: function (id, data, getkey) {

View file

@ -1,10 +1,10 @@
angular.module('portainer.services')
.factory('Pagination', ['LocalStorage', 'Settings', function PaginationFactory(LocalStorage, Settings) {
.factory('Pagination', ['LocalStorage', 'PAGINATION_MAX_ITEMS', function PaginationFactory(LocalStorage, PAGINATION_MAX_ITEMS) {
'use strict';
return {
getPaginationCount: function(key) {
var storedCount = LocalStorage.getPaginationCount(key);
var paginationCount = Settings.pagination_count;
var paginationCount = PAGINATION_MAX_ITEMS;
if (storedCount !== null) {
paginationCount = storedCount;
}

View file

@ -1,17 +0,0 @@
angular.module('portainer.services')
.factory('Settings', ['DOCKER_ENDPOINT', 'DOCKER_PORT', 'UI_VERSION', 'PAGINATION_MAX_ITEMS', function SettingsFactory(DOCKER_ENDPOINT, DOCKER_PORT, UI_VERSION, PAGINATION_MAX_ITEMS) {
'use strict';
var url = DOCKER_ENDPOINT;
if (DOCKER_PORT) {
url = url + DOCKER_PORT + '\\' + DOCKER_PORT;
}
var firstLoad = (localStorage.getItem('firstLoad') || 'true') === 'true';
return {
displayAll: true,
endpoint: DOCKER_ENDPOINT,
uiVersion: UI_VERSION,
url: url,
firstLoad: firstLoad,
pagination_count: PAGINATION_MAX_ITEMS
};
}]);

View file

@ -1,67 +1,95 @@
angular.module('portainer.services')
.factory('StateManager', ['$q', 'Config', 'Info', 'InfoHelper', 'Version', 'LocalStorage', function StateManagerFactory($q, Config, Info, InfoHelper, Version, LocalStorage) {
.factory('StateManager', ['$q', 'Info', 'InfoHelper', 'Version', 'LocalStorage', 'SettingsService', 'StatusService', function StateManagerFactory($q, Info, InfoHelper, Version, LocalStorage, SettingsService, StatusService) {
'use strict';
var manager = {};
var state = {
loading: true,
application: {},
endpoint: {}
endpoint: {},
UI: {}
};
return {
initialize: function() {
var endpointState = LocalStorage.getEndpointState();
if (endpointState) {
state.endpoint = endpointState;
}
manager.getState = function() {
return state;
};
var deferred = $q.defer();
var applicationState = LocalStorage.getApplicationState();
if (applicationState) {
state.application = applicationState;
state.loading = false;
deferred.resolve(state);
} else {
Config.$promise.then(function success(data) {
state.application.authentication = data.authentication;
state.application.analytics = data.analytics;
state.application.endpointManagement = data.endpointManagement;
state.application.logo = data.logo;
LocalStorage.storeApplicationState(state.application);
state.loading = false;
deferred.resolve(state);
}, function error(err) {
state.loading = false;
deferred.reject({msg: 'Unable to retrieve server configuration', err: err});
});
}
return deferred.promise;
},
clean: function() {
state.endpoint = {};
},
updateEndpointState: function(loading) {
var deferred = $q.defer();
if (loading) {
state.loading = true;
}
$q.all([Info.get({}).$promise, Version.get({}).$promise])
.then(function success(data) {
var endpointMode = InfoHelper.determineEndpointMode(data[0]);
var endpointAPIVersion = parseFloat(data[1].ApiVersion);
state.endpoint.mode = endpointMode;
state.endpoint.apiVersion = endpointAPIVersion;
LocalStorage.storeEndpointState(state.endpoint);
state.loading = false;
deferred.resolve();
}, function error(err) {
state.loading = false;
deferred.reject({msg: 'Unable to connect to the Docker endpoint', err: err});
});
return deferred.promise;
},
getState: function() {
return state;
manager.clean = function () {
state.endpoint = {};
};
manager.updateLogo = function(logoURL) {
state.application.logo = logoURL;
LocalStorage.storeApplicationState(state.application);
};
manager.updateExternalContributions = function(displayExternalContributors) {
state.application.displayExternalContributors = displayExternalContributors;
LocalStorage.storeApplicationState(state.application);
};
manager.initialize = function () {
var deferred = $q.defer();
var endpointState = LocalStorage.getEndpointState();
if (endpointState) {
state.endpoint = endpointState;
}
var applicationState = LocalStorage.getApplicationState();
if (applicationState) {
state.application = applicationState;
state.loading = false;
deferred.resolve(state);
} else {
$q.all({
settings: SettingsService.settings(),
status: StatusService.status()
})
.then(function success(data) {
var status = data.status;
var settings = data.settings;
state.application.authentication = status.Authentication;
state.application.analytics = status.Analytics;
state.application.endpointManagement = status.EndpointManagement;
state.application.version = status.Version;
state.application.logo = settings.LogoURL;
state.application.displayExternalContributors = settings.DisplayExternalContributors;
LocalStorage.storeApplicationState(state.application);
deferred.resolve(state);
})
.catch(function error(err) {
deferred.reject({msg: 'Unable to retrieve server settings and status', err: err});
})
.finally(function final() {
state.loading = false;
});
}
return deferred.promise;
};
manager.updateEndpointState = function(loading) {
var deferred = $q.defer();
if (loading) {
state.loading = true;
}
$q.all([Info.get({}).$promise, Version.get({}).$promise])
.then(function success(data) {
var endpointMode = InfoHelper.determineEndpointMode(data[0]);
var endpointAPIVersion = parseFloat(data[1].ApiVersion);
state.endpoint.mode = endpointMode;
state.endpoint.apiVersion = endpointAPIVersion;
LocalStorage.storeEndpointState(state.endpoint);
state.loading = false;
deferred.resolve();
}, function error(err) {
state.loading = false;
deferred.reject({msg: 'Unable to connect to the Docker endpoint', err: err});
});
return deferred.promise;
};
return manager;
}]);