mirror of https://github.com/portainer/portainer
feat(services): display clearer information about services
parent
22c02a8fe9
commit
35e2cecee1
|
@ -105,7 +105,7 @@
|
||||||
<td><span class="label label-{{ container.Status|containerstatusbadge }}">{{ container.Status }}</span></td>
|
<td><span class="label label-{{ container.Status|containerstatusbadge }}">{{ container.Status }}</span></td>
|
||||||
<td ng-if="applicationState.endpoint.mode.provider === 'DOCKER_SWARM'"><a ui-sref="container({id: container.Id})">{{ container|swarmcontainername}}</a></td>
|
<td ng-if="applicationState.endpoint.mode.provider === 'DOCKER_SWARM'"><a ui-sref="container({id: container.Id})">{{ container|swarmcontainername}}</a></td>
|
||||||
<td ng-if="applicationState.endpoint.mode.provider !== 'DOCKER_SWARM'"><a ui-sref="container({id: container.Id})">{{ container|containername}}</a></td>
|
<td ng-if="applicationState.endpoint.mode.provider !== 'DOCKER_SWARM'"><a ui-sref="container({id: container.Id})">{{ container|containername}}</a></td>
|
||||||
<td><a ui-sref="image({id: container.Image})">{{ container.Image }}</a></td>
|
<td><a ui-sref="image({id: container.Image})">{{ container.Image | hideshasum }}</a></td>
|
||||||
<td ng-if="state.displayIP">{{ container.IP ? container.IP : '-' }}</td>
|
<td ng-if="state.displayIP">{{ container.IP ? container.IP : '-' }}</td>
|
||||||
<td ng-if="applicationState.endpoint.mode.provider === 'DOCKER_SWARM'">{{ container.hostIP }}</td>
|
<td ng-if="applicationState.endpoint.mode.provider === 'DOCKER_SWARM'">{{ container.hostIP }}</td>
|
||||||
<td>
|
<td>
|
||||||
|
|
|
@ -70,11 +70,13 @@
|
||||||
<tr dir-paginate="service in (state.filteredServices = ( services | filter:state.filter | orderBy:sortType:sortReverse | itemsPerPage: state.pagination_count))">
|
<tr dir-paginate="service in (state.filteredServices = ( services | filter:state.filter | orderBy:sortType:sortReverse | itemsPerPage: state.pagination_count))">
|
||||||
<td><input type="checkbox" ng-model="service.Checked" ng-change="selectItem(service)"/></td>
|
<td><input type="checkbox" ng-model="service.Checked" ng-change="selectItem(service)"/></td>
|
||||||
<td><a ui-sref="service({id: service.Id})">{{ service.Name }}</a></td>
|
<td><a ui-sref="service({id: service.Id})">{{ service.Name }}</a></td>
|
||||||
<td>{{ service.Image }}</td>
|
<td>{{ service.Image | hideshasum }}</td>
|
||||||
<td>
|
<td>
|
||||||
{{ service.Mode }}
|
{{ service.Mode }}
|
||||||
|
<code data-toggle="tooltip" title="Replicas">{{ service.Running }}</code>
|
||||||
|
/
|
||||||
|
<code data-toggle="tooltip" title="Replicas">{{ service.Replicas }}</code>
|
||||||
<span ng-if="service.Mode === 'replicated' && !service.Scale">
|
<span ng-if="service.Mode === 'replicated' && !service.Scale">
|
||||||
<code data-toggle="tooltip" title="Replicas">{{ service.Replicas }}</code>
|
|
||||||
<a class="interactive" ng-click="service.Scale = true; service.ReplicaCount = service.Replicas;"><i class="fa fa-arrows-v" aria-hidden="true"></i> Scale</a>
|
<a class="interactive" ng-click="service.Scale = true; service.ReplicaCount = service.Replicas;"><i class="fa fa-arrows-v" aria-hidden="true"></i> Scale</a>
|
||||||
</span>
|
</span>
|
||||||
<span ng-if="service.Mode === 'replicated' && service.Scale">
|
<span ng-if="service.Mode === 'replicated' && service.Scale">
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
angular.module('services', [])
|
angular.module('services', [])
|
||||||
.controller('ServicesController', ['$q', '$scope', '$stateParams', '$state', 'Service', 'ServiceHelper', 'Messages', 'Pagination', 'Authentication', 'UserService', 'ModalService', 'ResourceControlService',
|
.controller('ServicesController', ['$q', '$scope', '$stateParams', '$state', 'Service', 'ServiceHelper', 'Messages', 'Pagination', 'Task', 'Node', 'Authentication', 'UserService', 'ModalService', 'ResourceControlService',
|
||||||
function ($q, $scope, $stateParams, $state, Service, ServiceHelper, Messages, Pagination, Authentication, UserService, ModalService, ResourceControlService) {
|
function ($q, $scope, $stateParams, $state, Service, ServiceHelper, Messages, Pagination, Task, Node, Authentication, UserService, ModalService, ResourceControlService) {
|
||||||
$scope.state = {};
|
$scope.state = {};
|
||||||
$scope.state.selectedItemCount = 0;
|
$scope.state.selectedItemCount = 0;
|
||||||
$scope.state.pagination_count = Pagination.getPaginationCount('services');
|
$scope.state.pagination_count = Pagination.getPaginationCount('services');
|
||||||
|
@ -127,30 +127,41 @@ function ($q, $scope, $stateParams, $state, Service, ServiceHelper, Messages, Pa
|
||||||
|
|
||||||
function fetchServices() {
|
function fetchServices() {
|
||||||
$('#loadServicesSpinner').show();
|
$('#loadServicesSpinner').show();
|
||||||
|
|
||||||
var userDetails = Authentication.getUserDetails();
|
var userDetails = Authentication.getUserDetails();
|
||||||
$scope.user = userDetails;
|
$scope.user = userDetails;
|
||||||
|
|
||||||
Service.query({}, function (d) {
|
$q.all({
|
||||||
$scope.services = d.map(function (service) {
|
services: Service.query({}).$promise,
|
||||||
return new ServiceViewModel(service);
|
tasks: Task.query({filters: {'desired-state': ['running']}}).$promise,
|
||||||
|
nodes: Node.query({}).$promise,
|
||||||
|
})
|
||||||
|
.then(function success(data) {
|
||||||
|
$scope.services = data.services.map(function (service) {
|
||||||
|
var serviceTasks = data.tasks.filter(function (task) {
|
||||||
|
return task.ServiceID === service.ID;
|
||||||
|
});
|
||||||
|
var taskNodes = data.nodes.filter(function (node) {
|
||||||
|
return node.Spec.Availability === 'active' && node.Status.State === 'ready';
|
||||||
|
});
|
||||||
|
return new ServiceViewModel(service, serviceTasks, taskNodes);
|
||||||
});
|
});
|
||||||
if (userDetails.role === 1) {
|
if (userDetails.role === 1) {
|
||||||
UserService.users()
|
UserService.users()
|
||||||
.then(function success(data) {
|
.then(function success(data) {
|
||||||
mapUsersToServices(data);
|
mapUsersToServices(data);
|
||||||
})
|
})
|
||||||
.catch(function error(err) {
|
|
||||||
Messages.error("Failure", err, "Unable to retrieve users");
|
|
||||||
})
|
|
||||||
.finally(function final() {
|
.finally(function final() {
|
||||||
$('#loadServicesSpinner').hide();
|
$('#loadServicesSpinner').hide();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
$('#loadServicesSpinner').hide();
|
})
|
||||||
}, function(e) {
|
.catch(function error(err) {
|
||||||
$('#loadServicesSpinner').hide();
|
|
||||||
Messages.error("Failure", e, "Unable to retrieve services");
|
|
||||||
$scope.services = [];
|
$scope.services = [];
|
||||||
|
Messages.error("Failure", err, "Unable to retrieve services");
|
||||||
|
})
|
||||||
|
.finally(function final() {
|
||||||
|
$('#loadServicesSpinner').hide();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -228,4 +228,13 @@ angular.module('portainer.filters', [])
|
||||||
}
|
}
|
||||||
return '';
|
return '';
|
||||||
};
|
};
|
||||||
|
})
|
||||||
|
.filter('hideshasum', function () {
|
||||||
|
'use strict';
|
||||||
|
return function (imageName) {
|
||||||
|
if (imageName) {
|
||||||
|
return imageName.split('@sha')[0];
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
function ServiceViewModel(data) {
|
function ServiceViewModel(data, runningTasks, nodes) {
|
||||||
this.Model = data;
|
this.Model = data;
|
||||||
this.Id = data.ID;
|
this.Id = data.ID;
|
||||||
this.Name = data.Spec.Name;
|
this.Name = data.Spec.Name;
|
||||||
|
@ -9,6 +9,12 @@ function ServiceViewModel(data) {
|
||||||
this.Replicas = data.Spec.Mode.Replicated.Replicas;
|
this.Replicas = data.Spec.Mode.Replicated.Replicas;
|
||||||
} else {
|
} else {
|
||||||
this.Mode = 'global';
|
this.Mode = 'global';
|
||||||
|
if (nodes) {
|
||||||
|
this.Replicas = nodes.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (runningTasks) {
|
||||||
|
this.Running = runningTasks.length;
|
||||||
}
|
}
|
||||||
this.Labels = data.Spec.Labels;
|
this.Labels = data.Spec.Labels;
|
||||||
if (data.Spec.TaskTemplate.ContainerSpec) {
|
if (data.Spec.TaskTemplate.ContainerSpec) {
|
||||||
|
|
Loading…
Reference in New Issue