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:
parent
a94f2ee7b8
commit
b6792461a4
46 changed files with 994 additions and 399 deletions
|
@ -4,9 +4,6 @@ angular.module('portainer.docker').component('dockerSidebarContent', {
|
|||
'endpointApiVersion': '<',
|
||||
'swarmManagement': '<',
|
||||
'standaloneManagement': '<',
|
||||
'adminAccess': '<',
|
||||
'externalContributions': '<',
|
||||
'sidebarToggledOn': '<',
|
||||
'currentState': '<'
|
||||
'adminAccess': '<'
|
||||
}
|
||||
});
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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>
|
|
@ -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: '<'
|
||||
}
|
||||
});
|
|
@ -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>
|
|
@ -0,0 +1,6 @@
|
|||
angular.module('portainer.app').component('snapshotDetails', {
|
||||
templateUrl: 'app/portainer/components/datatables/endpoints-snapshot-datatable/snapshot-details/snapshotDetails.html',
|
||||
bindings: {
|
||||
snapshot: '<'
|
||||
}
|
||||
});
|
|
@ -0,0 +1,7 @@
|
|||
angular.module('portainer.app').component('informationPanel', {
|
||||
templateUrl: 'app/portainer/components/information-panel/informationPanel.html',
|
||||
bindings: {
|
||||
titleText: '@'
|
||||
},
|
||||
transclude: true
|
||||
});
|
|
@ -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>
|
|
@ -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': '<'
|
||||
}
|
||||
});
|
|
@ -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>
|
|
@ -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;
|
||||
});
|
||||
}
|
||||
});
|
|
@ -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';
|
||||
};
|
||||
});
|
||||
|
|
|
@ -5,4 +5,5 @@ function SettingsViewModel(data) {
|
|||
this.LDAPSettings = data.LDAPSettings;
|
||||
this.AllowBindMountsForRegularUsers = data.AllowBindMountsForRegularUsers;
|
||||
this.AllowPrivilegedModeForRegularUsers = data.AllowPrivilegedModeForRegularUsers;
|
||||
this.SnapshotInterval = data.SnapshotInterval;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
37
app/portainer/views/home/home.html
Normal file
37
app/portainer/views/home/home.html
Normal 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>
|
58
app/portainer/views/home/homeController.js
Normal file
58
app/portainer/views/home/homeController.js
Normal 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();
|
||||
}]);
|
|
@ -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) {
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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');
|
||||
});
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue