1
0
Fork 0
mirror of https://github.com/portainer/portainer.git synced 2025-08-05 13:55:21 +02:00

feat(home): add a new home view (#2033)

This commit is contained in:
Anthony Lapenna 2018-07-11 10:39:20 +02:00 committed by GitHub
parent a94f2ee7b8
commit b6792461a4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
46 changed files with 994 additions and 399 deletions

View file

@ -4,9 +4,6 @@ angular.module('portainer.docker').component('dockerSidebarContent', {
'endpointApiVersion': '<',
'swarmManagement': '<',
'standaloneManagement': '<',
'adminAccess': '<',
'externalContributions': '<',
'sidebarToggledOn': '<',
'currentState': '<'
'adminAccess': '<'
}
});

View file

@ -1,6 +1,6 @@
<rd-header>
<rd-header-title title-text="Home"></rd-header-title>
<rd-header-content>Dashboard</rd-header-content>
<rd-header-title title-text="Dashboard"></rd-header-title>
<rd-header-content>Endpoint summary</rd-header-content>
</rd-header>
<div class="row" ng-if="applicationState.endpoint.mode.agentProxy">

View file

@ -187,6 +187,17 @@ angular.module('portainer.app', [])
}
};
var home = {
name: 'portainer.home',
url: '/home',
views: {
'content@': {
templateUrl: 'app/portainer/views/home/home.html',
controller: 'HomeController'
}
}
};
var registries = {
name: 'portainer.registries',
url: '/registries',
@ -404,6 +415,7 @@ angular.module('portainer.app', [])
$stateRegistryProvider.register(group);
$stateRegistryProvider.register(groupAccess);
$stateRegistryProvider.register(groupCreation);
$stateRegistryProvider.register(home);
$stateRegistryProvider.register(registries);
$stateRegistryProvider.register(registry);
$stateRegistryProvider.register(registryAccess);

View file

@ -30,8 +30,9 @@
}
.datatable .searchBar {
border-top: 1px solid #f6f6f6;
padding: 10px;
border-top: 1px solid #d2d1d1;
border-bottom: 1px solid #d2d1d1;
padding: 8px;
}
.datatable .searchInput {

View file

@ -0,0 +1,113 @@
<div class="datatable">
<rd-widget>
<rd-widget-body classes="no-padding">
<div class="toolBar">
<div class="toolBarTitle">
<i class="fa" ng-class="$ctrl.titleIcon" aria-hidden="true" style="margin-right: 2px;"></i> {{ $ctrl.titleText }}
</div>
</div>
<div class="searchBar">
<i class="fa fa-search searchIcon" aria-hidden="true"></i>
<input type="text" class="searchInput" ng-model="$ctrl.state.textFilter" placeholder="Search by name, group, tag..." auto-focus>
</div>
<div class="table-responsive">
<table class="table">
<thead>
<tr>
<th>
<a ng-click="$ctrl.changeOrderBy('Name')">
Name
<i class="fa fa-sort-alpha-down" aria-hidden="true" ng-if="$ctrl.state.orderBy === 'Name' && !$ctrl.state.reverseOrder"></i>
<i class="fa fa-sort-alpha-up" aria-hidden="true" ng-if="$ctrl.state.orderBy === 'Name' && $ctrl.state.reverseOrder"></i>
</a>
</th>
<th>
<a ng-click="$ctrl.changeOrderBy('GroupName')">
Group
<i class="fa fa-sort-alpha-down" aria-hidden="true" ng-if="$ctrl.state.orderBy === 'GroupName' && !$ctrl.state.reverseOrder"></i>
<i class="fa fa-sort-alpha-up" aria-hidden="true" ng-if="$ctrl.state.orderBy === 'GroupName' && $ctrl.state.reverseOrder"></i>
</a>
</th>
<th>
<a ng-click="$ctrl.changeOrderBy('Status')">
Status
<i class="fa fa-sort-alpha-down" aria-hidden="true" ng-if="$ctrl.state.orderBy === 'Status' && !$ctrl.state.reverseOrder"></i>
<i class="fa fa-sort-alpha-up" aria-hidden="true" ng-if="$ctrl.state.orderBy === 'Status' && $ctrl.state.reverseOrder"></i>
</a>
</th>
<th>
<a ng-click="$ctrl.changeOrderBy('Type')">
Type
<i class="fa fa-sort-alpha-down" aria-hidden="true" ng-if="$ctrl.state.orderBy === 'Type' && !$ctrl.state.reverseOrder"></i>
<i class="fa fa-sort-alpha-up" aria-hidden="true" ng-if="$ctrl.state.orderBy === 'Type' && $ctrl.state.reverseOrder"></i>
</a>
</th>
<th>
<a ng-click="$ctrl.changeOrderBy('Snapshots[0].Time')">
Last snapshot
<i class="fa fa-sort-alpha-down" aria-hidden="true" ng-if="$ctrl.state.orderBy === 'Snapshots[0].Time' && !$ctrl.state.reverseOrder"></i>
<i class="fa fa-sort-alpha-up" aria-hidden="true" ng-if="$ctrl.state.orderBy === 'Snapshots[0].Time' && $ctrl.state.reverseOrder"></i>
</a>
</th>
</tr>
</thead>
<tbody>
<tr dir-paginate-start="item in ($ctrl.state.filteredDataSet = ($ctrl.dataset | filter:$ctrl.state.textFilter | orderBy:$ctrl.state.orderBy:$ctrl.state.reverseOrder | itemsPerPage: $ctrl.state.paginatedItemLimit))" ng-class="{active: item.Checked}">
<td>
<a ng-click="$ctrl.dashboardAction(item)"><i class="fa fa-sign-in-alt" aria-hidden="true"></i> {{ item.Name }}</a>
</td>
<td>{{ item.GroupName }}</td>
<td>
<span class="label label-{{ item.Status|endpointstatusbadge }}">{{ item.Status === 1 ? 'up' : 'down' }}</span>
</td>
<td>
<span>
<i ng-class="item.Type | endpointtypeicon" aria-hidden="true" style="margin-right: 2px;"></i>
{{ item.Type | endpointtypename }}
</span>
</td>
<td>
<span ng-if="item.Snapshots.length > 0">
{{ item.Snapshots[0].Time | getisodatefromtimestamp }}
</span>
<span ng-if="item.Snapshots.length === 0">-</span>
</td>
</tr>
<tr dir-paginate-end class="text-muted" ng-if="item.Snapshots.length > 0">
<td colspan="5" style="border: 0; text-align:center;">
<snapshot-details
snapshot="item.Snapshots[0]"
></snapshot-details
</td>
</tr>
<tr ng-if="!$ctrl.dataset">
<td colspan="5" class="text-center text-muted">Loading...</td>
</tr>
<tr ng-if="$ctrl.state.filteredDataSet.length === 0">
<td colspan="5" class="text-center text-muted">No endpoint available.</td>
</tr>
</tbody>
</table>
</div>
<div class="footer" ng-if="$ctrl.dataset">
<div class="paginationControls">
<form class="form-inline">
<span class="limitSelector">
<span style="margin-right: 5px;">
Items per page
</span>
<select class="form-control" ng-model="$ctrl.state.paginatedItemLimit" ng-change="$ctrl.changePaginationLimit()">
<option value="0">All</option>
<option value="10">10</option>
<option value="25">25</option>
<option value="50">50</option>
<option value="100">100</option>
</select>
</span>
<dir-pagination-controls max-size="5"></dir-pagination-controls>
</form>
</div>
</div>
</rd-widget-body>
</rd-widget>
</div>

View file

@ -0,0 +1,13 @@
angular.module('portainer.app').component('endpointsSnapshotDatatable', {
templateUrl: 'app/portainer/components/datatables/endpoints-snapshot-datatable/endpointsSnapshotDatatable.html',
controller: 'GenericDatatableController',
bindings: {
titleText: '@',
titleIcon: '@',
dataset: '<',
tableKey: '@',
orderBy: '@',
reverseOrder: '<',
dashboardAction: '<'
}
});

View file

@ -0,0 +1,29 @@
<span style="border-top: 2px solid #e2e2e2; padding: 7px;">
<span style="padding: 0 7px 0 7px;">
<i class="fa fa-th-list space-right" aria-hidden="true"></i>{{ $ctrl.snapshot.StackCount }} stacks
</span>
<span style="padding: 0 7px 0 7px;" ng-if="$ctrl.snapshot.Swarm">
<i class="fa fa-list-alt space-right" aria-hidden="true"></i>{{ $ctrl.snapshot.ServiceCount }} services
</span>
<span style="padding: 0 7px 0 7px;">
<i class="fa fa-server space-right" aria-hidden="true"></i>{{ $ctrl.snapshot.RunningContainerCount + $ctrl.snapshot.StoppedContainerCount }} containers
<span ng-if="$ctrl.snapshot.RunningContainerCount > 0 || $ctrl.snapshot.StoppedContainerCount > 0">
-
<i class="fa fa-heartbeat green-icon" aria-hidden="true"></i> {{ $ctrl.snapshot.RunningContainerCount }}
<i class="fa fa-heartbeat red-icon" aria-hidden="true"></i> {{ $ctrl.snapshot.StoppedContainerCount }}
</span>
</span>
<span style="padding: 0 7px 0 7px;">
<i class="fa fa-cubes space-right" aria-hidden="true"></i>{{ $ctrl.snapshot.VolumeCount }} volumes
</span>
<span style="padding: 0 7px 0 7px;">
<i class="fa fa-clone space-right" aria-hidden="true"></i>{{ $ctrl.snapshot.ImageCount }} images
</span>
<span style="padding: 0 7px 0 7px; border-left: 2px solid #e2e2e2;">
<i class="fa fa-memory" aria-hidden="true"></i> {{ $ctrl.snapshot.TotalMemory | humansize }}
<i class="fa fa-microchip space-left" aria-hidden="true"></i> {{ $ctrl.snapshot.TotalCPU }}
</span>
<span style="padding: 0 7px 0 7px; border-left: 2px solid #e2e2e2;">
{{ $ctrl.snapshot.Swarm ? 'Swarm' : 'Standalone' }} {{ $ctrl.snapshot.DockerVersion }}
</span>
</span>

View file

@ -0,0 +1,6 @@
angular.module('portainer.app').component('snapshotDetails', {
templateUrl: 'app/portainer/components/datatables/endpoints-snapshot-datatable/snapshot-details/snapshotDetails.html',
bindings: {
snapshot: '<'
}
});

View file

@ -0,0 +1,7 @@
angular.module('portainer.app').component('informationPanel', {
templateUrl: 'app/portainer/components/information-panel/informationPanel.html',
bindings: {
titleText: '@'
},
transclude: true
});

View file

@ -0,0 +1,14 @@
<div class="row">
<div class="col-sm-12">
<rd-widget>
<rd-widget-body>
<div class="col-sm-12 form-section-title">
{{ $ctrl.titleText }}
</div>
<div class="form-group">
<ng-transclude></ng-transclude>
</div>
</rd-widget-body>
</rd-widget>
</div>
</div>

View file

@ -1,9 +0,0 @@
angular.module('portainer.app').component('sidebarEndpointSelector', {
templateUrl: 'app/portainer/components/sidebar-endpoint-selector/sidebarEndpointSelector.html',
controller: 'SidebarEndpointSelectorController',
bindings: {
'endpoints': '<',
'groups': '<',
'selectEndpoint': '<'
}
});

View file

@ -1,27 +0,0 @@
<div ng-if="$ctrl.endpoints.length > 1">
<div ng-if="!$ctrl.state.show">
<li class="sidebar-title">
<span class="interactive" style="color: #fff;" ng-click="$ctrl.state.show = true;">
<span class="fa fa-plug space-right"></span>Change environment
</span>
</li>
</div>
<div ng-if="$ctrl.state.show">
<div ng-if="$ctrl.availableGroups.length > 1">
<li class="sidebar-title"><span>Group</span></li>
<li class="sidebar-title">
<select class="select-endpoint form-control" ng-options="group.Name for group in $ctrl.availableGroups" ng-model="$ctrl.state.selectedGroup" ng-change="$ctrl.selectGroup()">
<option value="" disabled selected>Select a group</option>
</select>
</li>
</div>
<div ng-if="$ctrl.state.selectedGroup || $ctrl.availableGroups.length <= 1">
<li class="sidebar-title"><span>Endpoint</span></li>
<li class="sidebar-title">
<select class="select-endpoint form-control" ng-options="endpoint.Name for endpoint in $ctrl.availableEndpoints" ng-model="$ctrl.state.selectedEndpoint" ng-change="$ctrl.selectEndpoint($ctrl.state.selectedEndpoint)">
<option value="" disabled selected>Select an endpoint</option>
</select>
</li>
</div>
</div>
</div>

View file

@ -1,34 +0,0 @@
angular.module('portainer.app')
.controller('SidebarEndpointSelectorController', function () {
var ctrl = this;
this.state = {
show: false,
selectedGroup: null,
selectedEndpoint: null
};
this.selectGroup = function() {
this.availableEndpoints = this.endpoints.filter(function f(endpoint) {
return endpoint.GroupId === ctrl.state.selectedGroup.Id;
});
};
this.$onInit = function() {
this.availableGroups = filterEmptyGroups(this.groups, this.endpoints);
this.availableEndpoints = this.endpoints;
};
function filterEmptyGroups(groups, endpoints) {
return groups.filter(function f(group) {
for (var i = 0; i < endpoints.length; i++) {
var endpoint = endpoints[i];
if (endpoint.GroupId === group.Id) {
return true;
}
}
return false;
});
}
});

View file

@ -138,4 +138,13 @@ angular.module('portainer.app')
return 'fa fa-eye';
}
};
})
.filter('endpointstatusbadge', function () {
'use strict';
return function (status) {
if (status === 2) {
return 'danger';
}
return 'success';
};
});

View file

@ -5,4 +5,5 @@ function SettingsViewModel(data) {
this.LDAPSettings = data.LDAPSettings;
this.AllowBindMountsForRegularUsers = data.AllowBindMountsForRegularUsers;
this.AllowPrivilegedModeForRegularUsers = data.AllowPrivilegedModeForRegularUsers;
this.SnapshotInterval = data.SnapshotInterval;
}

View file

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

View file

@ -25,12 +25,19 @@ function StateManagerFactory($q, SystemService, InfoHelper, LocalStorage, Settin
LocalStorage.storeApplicationState(state.application);
};
manager.updateSnapshotInterval = function(interval) {
state.application.snapshotInterval = interval;
LocalStorage.storeApplicationState(state.application);
};
function assignStateFromStatusAndSettings(status, settings) {
state.application.authentication = status.Authentication;
state.application.analytics = status.Analytics;
state.application.endpointManagement = status.EndpointManagement;
state.application.snapshot = status.Snapshot;
state.application.version = status.Version;
state.application.logo = settings.LogoURL;
state.application.snapshotInterval = settings.SnapshotInterval;
state.application.validity = moment().unix();
}
@ -110,14 +117,11 @@ function StateManagerFactory($q, SystemService, InfoHelper, LocalStorage, Settin
return extensions;
}
manager.updateEndpointState = function(loading, type, extensions) {
manager.updateEndpointState = function(name, type, extensions) {
var deferred = $q.defer();
if (loading) {
state.loading = true;
}
if (type === 3) {
state.endpoint.name = name;
state.endpoint.mode = { provider: 'AZURE' };
LocalStorage.storeEndpointState(state.endpoint);
deferred.resolve();
@ -132,6 +136,7 @@ function StateManagerFactory($q, SystemService, InfoHelper, LocalStorage, Settin
var endpointMode = InfoHelper.determineEndpointMode(data.info, type);
var endpointAPIVersion = parseFloat(data.version.ApiVersion);
state.endpoint.mode = endpointMode;
state.endpoint.name = name;
state.endpoint.apiVersion = endpointAPIVersion;
state.endpoint.extensions = assignExtensions(extensions);
LocalStorage.storeEndpointState(state.endpoint);

View file

@ -1,6 +1,6 @@
angular.module('portainer.app')
.controller('AuthenticationController', ['$scope', '$state', '$transition$', '$window', '$timeout', '$sanitize', 'Authentication', 'Users', 'UserService', 'EndpointService', 'StateManager', 'EndpointProvider', 'Notifications', 'SettingsService', 'ExtensionManager',
function ($scope, $state, $transition$, $window, $timeout, $sanitize, Authentication, Users, UserService, EndpointService, StateManager, EndpointProvider, Notifications, SettingsService, ExtensionManager) {
.controller('AuthenticationController', ['$scope', '$state', '$transition$', '$sanitize', 'Authentication', 'UserService', 'EndpointService', 'StateManager', 'Notifications', 'SettingsService',
function ($scope, $state, $transition$, $sanitize, Authentication, UserService, EndpointService, StateManager, Notifications, SettingsService) {
$scope.logo = StateManager.getState().application.logo;
@ -13,47 +13,13 @@ function ($scope, $state, $transition$, $window, $timeout, $sanitize, Authentica
AuthenticationError: ''
};
function redirectToDockerDashboard(endpoint) {
ExtensionManager.initEndpointExtensions(endpoint.Id)
.then(function success(data) {
var extensions = data;
return StateManager.updateEndpointState(true, endpoint.Type, extensions);
})
.then(function success(data) {
$state.go('docker.dashboard');
})
.catch(function error(err) {
Notifications.error('Failure', err, 'Unable to connect to the Docker endpoint');
});
}
function redirectToAzureDashboard(endpoint) {
StateManager.updateEndpointState(false, endpoint.Type, [])
.then(function success(data) {
$state.go('azure.dashboard');
})
.catch(function error(err) {
Notifications.error('Failure', err, 'Unable to connect to the Docker endpoint');
});
}
function redirectToDashboard(endpoint) {
EndpointProvider.setEndpointID(endpoint.Id);
if (endpoint.Type === 3) {
return redirectToAzureDashboard(endpoint);
}
redirectToDockerDashboard(endpoint);
}
function unauthenticatedFlow() {
EndpointService.endpoints()
.then(function success(data) {
var endpoints = data;
if (endpoints.length > 0) {
redirectToDashboard(endpoints[0]);
} else {
if (endpoints.length === 0) {
$state.go('portainer.init.endpoint');
} else {
$state.go('portainer.home');
}
})
.catch(function error(err) {
@ -92,13 +58,10 @@ function ($scope, $state, $transition$, $window, $timeout, $sanitize, Authentica
.then(function success(data) {
var endpoints = data;
var userDetails = Authentication.getUserDetails();
if (endpoints.length > 0) {
redirectToDashboard(endpoints[0]);
} else if (endpoints.length === 0 && userDetails.role === 1) {
if (endpoints.length === 0 && userDetails.role === 1) {
$state.go('portainer.init.endpoint');
} else if (endpoints.length === 0 && userDetails.role === 2) {
Authentication.logout();
$scope.state.AuthenticationError = 'User not allowed. Please contact your administrator.';
} else {
$state.go('portainer.home');
}
})
.catch(function error() {
@ -114,7 +77,7 @@ function ($scope, $state, $transition$, $window, $timeout, $sanitize, Authentica
}
if (Authentication.isAuthenticated()) {
$state.go('docker.dashboard');
$state.go('portainer.home');
}
var authenticationEnabled = $scope.applicationState.application.authentication;

View file

@ -0,0 +1,37 @@
<rd-header>
<rd-header-title title-text="Home">
<a data-toggle="tooltip" title="Refresh" ui-sref="portainer.home" ui-sref-opts="{reload: true}">
<i class="fa fa-sync" aria-hidden="true"></i>
</a>
</rd-header-title>
<rd-header-content>Endpoints</rd-header-content>
</rd-header>
<information-panel title-text="Information" ng-if="!isAdmin && endpoints.length === 0">
<span class="small">
<p class="text-muted">
<i class="fa fa-exclamation-circle orange-icon" aria-hidden="true" style="margin-right: 2px;"></i>
You do not have access to any environment. Please contact your administrator.
</p>
</span>
</information-panel>
<information-panel title-text="Information" ng-if="isAdmin && !applicationState.application.snapshot">
<span class="small">
<p class="text-muted">
<i class="fa fa-exclamation-circle orange-icon" aria-hidden="true" style="margin-right: 2px;"></i>
Endpoint snapshot is disabled.
</p>
</span>
</information-panel>
<div class="row" ng-if="endpoints.length > 0">
<div class="col-sm-12">
<endpoints-snapshot-datatable
title-text="Endpoints" title-icon="fa-plug"
dataset="endpoints" table-key="endpoints"
order-by="Name"
dashboard-action="goToDashboard"
></endpoints-snapshot-datatable>
</div>
</div>

View file

@ -0,0 +1,58 @@
angular.module('portainer.app')
.controller('HomeController', ['$q', '$scope', '$state', 'Authentication', 'EndpointService', 'EndpointHelper', 'GroupService', 'Notifications', 'EndpointProvider', 'StateManager', 'ExtensionManager',
function ($q, $scope, $state, Authentication, EndpointService, EndpointHelper, GroupService, Notifications, EndpointProvider, StateManager, ExtensionManager) {
$scope.goToDashboard = function(endpoint) {
EndpointProvider.setEndpointID(endpoint.Id);
EndpointProvider.setEndpointPublicURL(endpoint.PublicURL);
if (endpoint.Type === 3) {
switchToAzureEndpoint(endpoint);
} else {
switchToDockerEndpoint(endpoint);
}
};
function switchToAzureEndpoint(endpoint) {
StateManager.updateEndpointState(endpoint.Name, endpoint.Type, [])
.then(function success() {
$state.go('azure.dashboard');
})
.catch(function error(err) {
Notifications.error('Failure', err, 'Unable to connect to the Azure endpoint');
});
}
function switchToDockerEndpoint(endpoint) {
ExtensionManager.initEndpointExtensions(endpoint.Id)
.then(function success(data) {
var extensions = data;
return StateManager.updateEndpointState(endpoint.Name, endpoint.Type, extensions);
})
.then(function success() {
$state.go('docker.dashboard');
})
.catch(function error(err) {
Notifications.error('Failure', err, 'Unable to connect to the Docker endpoint');
});
}
function initView() {
$scope.isAdmin = Authentication.getUserDetails().role === 1;
$q.all({
endpoints: EndpointService.endpoints(),
groups: GroupService.groups()
})
.then(function success(data) {
var endpoints = data.endpoints;
var groups = data.groups;
EndpointHelper.mapGroupNameToEndpoint(endpoints, groups);
$scope.endpoints = endpoints;
})
.catch(function error(err) {
Notifications.error('Failure', err, 'Unable to retrieve endpoint information');
});
}
initView();
}]);

View file

@ -1,6 +1,6 @@
angular.module('portainer.app')
.controller('InitAdminController', ['$scope', '$state', '$sanitize', 'Notifications', 'Authentication', 'StateManager', 'UserService', 'EndpointService', 'EndpointProvider', 'ExtensionManager',
function ($scope, $state, $sanitize, Notifications, Authentication, StateManager, UserService, EndpointService, EndpointProvider, ExtensionManager) {
.controller('InitAdminController', ['$scope', '$state', '$sanitize', 'Notifications', 'Authentication', 'StateManager', 'UserService', 'EndpointService',
function ($scope, $state, $sanitize, Notifications, Authentication, StateManager, UserService, EndpointService) {
$scope.logo = StateManager.getState().application.logo;
@ -30,20 +30,7 @@ function ($scope, $state, $sanitize, Notifications, Authentication, StateManager
if (data.length === 0) {
$state.go('portainer.init.endpoint');
} else {
var endpoint = data[0];
endpointID = endpoint.Id;
EndpointProvider.setEndpointID(endpointID);
ExtensionManager.initEndpointExtensions(endpointID)
.then(function success(data) {
var extensions = data;
return StateManager.updateEndpointState(false, endpoint.Type, extensions);
})
.then(function success() {
$state.go('docker.dashboard');
})
.catch(function error(err) {
Notifications.error('Failure', err, 'Unable to connect to Docker environment');
});
$state.go('portainer.home');
}
})
.catch(function error(err) {

View file

@ -1,9 +1,9 @@
angular.module('portainer.app')
.controller('InitEndpointController', ['$scope', '$state', 'EndpointService', 'StateManager', 'EndpointProvider', 'Notifications', 'ExtensionManager',
function ($scope, $state, EndpointService, StateManager, EndpointProvider, Notifications, ExtensionManager) {
.controller('InitEndpointController', ['$scope', '$state', 'EndpointService', 'StateManager', 'Notifications',
function ($scope, $state, EndpointService, StateManager, Notifications) {
if (!_.isEmpty($scope.applicationState.endpoint)) {
$state.go('docker.dashboard');
$state.go('portainer.home');
}
$scope.logo = StateManager.getState().application.logo;
@ -36,16 +36,7 @@ function ($scope, $state, EndpointService, StateManager, EndpointProvider, Notif
$scope.state.actionInProgress = true;
EndpointService.createLocalEndpoint()
.then(function success(data) {
endpoint = data;
EndpointProvider.setEndpointID(endpoint.Id);
return ExtensionManager.initEndpointExtensions(endpoint.Id);
})
.then(function success(data) {
var extensions = data;
return StateManager.updateEndpointState(false, endpoint.Type, extensions);
})
.then(function success(data) {
$state.go('docker.dashboard');
$state.go('portainer.home');
})
.catch(function error(err) {
Notifications.error('Failure', err, 'Unable to connect to the Docker environment');
@ -92,12 +83,7 @@ function ($scope, $state, EndpointService, StateManager, EndpointProvider, Notif
$scope.state.actionInProgress = true;
EndpointService.createAzureEndpoint(name, applicationId, tenantId, authenticationKey, 1, [])
.then(function success(data) {
endpoint = data;
EndpointProvider.setEndpointID(endpoint.Id);
return StateManager.updateEndpointState(false, endpoint.Type, []);
})
.then(function success(data) {
$state.go('azure.dashboard');
$state.go('portainer.home');
})
.catch(function error(err) {
Notifications.error('Failure', err, 'Unable to connect to the Azure environment');
@ -112,16 +98,7 @@ function ($scope, $state, EndpointService, StateManager, EndpointProvider, Notif
$scope.state.actionInProgress = true;
EndpointService.createRemoteEndpoint(name, type, URL, PublicURL, 1, [], TLS, TLSSkipVerify, TLSSKipClientVerify, TLSCAFile, TLSCertFile, TLSKeyFile)
.then(function success(data) {
endpoint = data;
EndpointProvider.setEndpointID(endpoint.Id);
return ExtensionManager.initEndpointExtensions(endpoint.Id);
})
.then(function success(data) {
var extensions = data;
return StateManager.updateEndpointState(false, endpoint.Type, extensions);
})
.then(function success(data) {
$state.go('docker.dashboard');
$state.go('portainer.home');
})
.catch(function error(err) {
Notifications.error('Failure', err, 'Unable to connect to the Docker environment');

View file

@ -9,6 +9,14 @@
<rd-widget-header icon="fa-cogs" title-text="Application settings"></rd-widget-header>
<rd-widget-body>
<form class="form-horizontal">
<!-- snapshot-interval -->
<div class="form-group">
<label for="snapshot_interval" class="col-sm-2 control-label text-left">Snapshot interval</label>
<div class="col-sm-10">
<input type="text" class="form-control" ng-model="settings.SnapshotInterval" id="snapshot_interval" placeholder="e.g. 15m">
</div>
</div>
<!-- !snapshot-interval -->
<!-- logo -->
<div class="form-group">
<div class="col-sm-12">

View file

@ -51,6 +51,7 @@ function ($scope, $state, Notifications, SettingsService, StateManager, DEFAULT_
.then(function success(data) {
Notifications.success('Settings updated');
StateManager.updateLogo(settings.LogoURL);
StateManager.updateSnapshotInterval(settings.SnapshotInterval);
$state.reload();
})
.catch(function error(err) {

View file

@ -1,35 +1,32 @@
<!-- Sidebar -->
<div id="sidebar-wrapper">
<div class="sidebar-header">
<a ng-click="toggleSidebar()" class="interactive">
<a ui-sref="portainer.home">
<img ng-if="logo" ng-src="{{ logo }}" class="img-responsive logo">
<img ng-if="!logo" src="images/logo.png" class="img-responsive logo" alt="Portainer">
<span class="menu-icon glyphicon glyphicon-transfer"></span>
</a>
<a ng-click="toggleSidebar()"><span class="menu-icon glyphicon glyphicon-transfer"></span></a>
</div>
<div class="sidebar-content">
<ul class="sidebar">
<sidebar-endpoint-selector ng-if="endpoints && groups"
endpoints="endpoints"
groups="groups"
select-endpoint="switchEndpoint"
></sidebar-endpoint-selector>
<li class="sidebar-title"><span class="endpoint-name">{{ activeEndpoint.Name }}</span></li>
<azure-sidebar-content ng-if="applicationState.endpoint.mode.provider === 'AZURE'">
<li class="sidebar-list">
<a ui-sref="portainer.home" ui-sref-active="active">Home <span class="menu-icon fa fa-home fa-fw"></span></a>
</li>
<li class="sidebar-title endpoint-name" ng-if="applicationState.endpoint.name">
<span class="fa fa-plug space-right"></span>{{ applicationState.endpoint.name }}
</li>
<azure-sidebar-content ng-if="applicationState.endpoint.mode && applicationState.endpoint.mode.provider === 'AZURE'">
</azure-sidebar-content>
<docker-sidebar-content ng-if="applicationState.endpoint.mode.provider !== 'AZURE'"
<docker-sidebar-content ng-if="applicationState.endpoint.mode && applicationState.endpoint.mode.provider !== 'AZURE'"
endpoint-api-version="applicationState.endpoint.apiVersion"
swarm-management="applicationState.endpoint.mode.provider === 'DOCKER_SWARM_MODE' && applicationState.endpoint.mode.role === 'MANAGER'"
standalone-management="applicationState.endpoint.mode.provider === 'DOCKER_STANDALONE' || applicationState.endpoint.mode.provider === 'VMWARE_VIC'"
admin-access="!applicationState.application.authentication || isAdmin"
external-contributions="displayExternalContributors"
sidebar-toggled-on="toggle"
current-state="$state.current.name"
></docker-sidebar-content>
<li class="sidebar-title" ng-if="applicationState.endpoint.extensions.length > 0">
<li class="sidebar-title" ng-if="applicationState.endpoint.mode && applicationState.endpoint.extensions.length > 0">
<span>Extensions</span>
</li>
<li class="sidebar-list" ng-if="applicationState.endpoint.extensions.indexOf('storidge') !== -1 && applicationState.endpoint.mode.provider === 'DOCKER_SWARM_MODE' && applicationState.endpoint.mode.role === 'MANAGER'">
<li class="sidebar-list" ng-if="applicationState.endpoint.mode && applicationState.endpoint.extensions.indexOf('storidge') !== -1 && applicationState.endpoint.mode.provider === 'DOCKER_SWARM_MODE' && applicationState.endpoint.mode.role === 'MANAGER'">
<a ui-sref="storidge.cluster" ui-sref-active="active">Storidge <span class="menu-icon fa fa-bolt fa-fw"></span></a>
<div class="sidebar-sublist" ng-if="toggle && ($state.current.name === 'storidge.cluster' || $state.current.name === 'storidge.profiles' || $state.current.name === 'storidge.monitor' || $state.current.name === 'storidge.profiles.new' || $state.current.name === 'storidge.profiles.profile')">
<a ui-sref="storidge.monitor" ui-sref-active="active">Monitor</a>
@ -39,10 +36,10 @@
</div>
</li>
<li class="sidebar-title" ng-if="!applicationState.application.authentication || isAdmin || isTeamLeader">
<span>Portainer settings</span>
<span>Settings</span>
</li>
<li class="sidebar-list" ng-if="applicationState.application.authentication && (isAdmin || isTeamLeader)">
<a ui-sref="portainer.users" ui-sref-active="active">User management <span class="menu-icon fa fa-users fa-fw"></span></a>
<a ui-sref="portainer.users" ui-sref-active="active">Users <span class="menu-icon fa fa-users fa-fw"></span></a>
<div class="sidebar-sublist" ng-if="toggle && ($state.current.name === 'portainer.users' || $state.current.name === 'portainer.users.user' || $state.current.name === 'portainer.teams' || $state.current.name === 'portainer.teams.team')">
<a ui-sref="portainer.teams" ui-sref-active="active">Teams</a>
</div>

View file

@ -1,64 +1,6 @@
angular.module('portainer.app')
.controller('SidebarController', ['$q', '$scope', '$state', 'EndpointService', 'GroupService', 'StateManager', 'EndpointProvider', 'Notifications', 'Authentication', 'UserService', 'ExtensionManager',
function ($q, $scope, $state, EndpointService, GroupService, StateManager, EndpointProvider, Notifications, Authentication, UserService, ExtensionManager) {
$scope.switchEndpoint = function(endpoint) {
EndpointProvider.setEndpointID(endpoint.Id);
EndpointProvider.setEndpointPublicURL(endpoint.PublicURL);
if (endpoint.Type === 3) {
switchToAzureEndpoint(endpoint);
} else {
switchToDockerEndpoint(endpoint);
}
};
function switchToAzureEndpoint(endpoint) {
StateManager.updateEndpointState(false, endpoint.Type, [])
.then(function success() {
$scope.currentEndpoint = endpoint;
$state.go('azure.dashboard');
})
.catch(function error(err) {
Notifications.error('Failure', err, 'Unable to connect to the Docker endpoint');
var currentEndpoint = $scope.currentEndpoint;
EndpointProvider.setEndpointID(currentEndpoint.Id);
EndpointProvider.setEndpointPublicURL(currentEndpoint.PublicURL);
return StateManager.updateEndpointState(true, currentEndpoint.Type, currentEndpoint.Extensions);
});
}
function switchToDockerEndpoint(endpoint) {
ExtensionManager.initEndpointExtensions(endpoint.Id)
.then(function success(data) {
var extensions = data;
return StateManager.updateEndpointState(true, endpoint.Type, extensions);
})
.then(function success() {
$scope.currentEndpoint = endpoint;
$state.go('docker.dashboard');
})
.catch(function error(err) {
Notifications.error('Failure', err, 'Unable to connect to the Docker endpoint');
var currentEndpoint = $scope.currentEndpoint;
EndpointProvider.setEndpointID(currentEndpoint.Id);
EndpointProvider.setEndpointPublicURL(currentEndpoint.PublicURL);
return StateManager.updateEndpointState(true, currentEndpoint.Type, currentEndpoint.Extensions);
});
}
function setActiveEndpoint(endpoints) {
var activeEndpointID = EndpointProvider.endpointID();
for (var i = 0; i < endpoints.length; i++) {
var endpoint = endpoints[i];
if (endpoint.Id === activeEndpointID) {
$scope.activeEndpoint = endpoint;
$scope.currentEndpoint = endpoint;
EndpointProvider.setEndpointPublicURL(endpoint.PublicURL);
break;
}
}
}
.controller('SidebarController', ['$q', '$scope', 'StateManager', 'Notifications', 'Authentication', 'UserService',
function ($q, $scope, StateManager, Notifications, Authentication, UserService) {
function checkPermissions(memberships) {
var isLeader = false;
@ -72,32 +14,18 @@ function ($q, $scope, $state, EndpointService, GroupService, StateManager, Endpo
function initView() {
$scope.uiVersion = StateManager.getState().application.version;
$scope.displayExternalContributors = StateManager.getState().application.displayExternalContributors;
$scope.logo = StateManager.getState().application.logo;
$q.all({
endpoints: EndpointService.endpoints(),
groups: GroupService.groups()
})
.then(function success(data) {
var endpoints = data.endpoints;
$scope.groups = _.sortBy(data.groups, ['Name']);
$scope.endpoints = _.sortBy(endpoints, ['Name']);
var userDetails = Authentication.getUserDetails();
var isAdmin = userDetails.role === 1;
$scope.isAdmin = isAdmin;
setActiveEndpoint(endpoints);
if (StateManager.getState().application.authentication) {
var userDetails = Authentication.getUserDetails();
var isAdmin = userDetails.role === 1 ? true: false;
$scope.isAdmin = isAdmin;
return $q.when(!isAdmin ? UserService.userMemberships(userDetails.ID) : []);
}
})
$q.when(!isAdmin ? UserService.userMemberships(userDetails.ID) : [])
.then(function success(data) {
checkPermissions(data);
})
.catch(function error(err) {
Notifications.error('Failure', err, 'Unable to retrieve endpoints');
Notifications.error('Failure', err, 'Unable to retrieve user memberships');
});
}