mirror of https://github.com/portainer/portainer
merge branch feat54-revamp-internal into internal
commit
a4a82b4502
|
@ -12,6 +12,12 @@ UI For Docker is a web interface for the Docker Remote API. The goal is to prov
|
||||||
* Minimal dependencies - I really want to keep this project a pure html/js app.
|
* Minimal dependencies - I really want to keep this project a pure html/js app.
|
||||||
* Consistency - The web UI should be consistent with the commands found on the docker CLI.
|
* Consistency - The web UI should be consistent with the commands found on the docker CLI.
|
||||||
|
|
||||||
|
## Supported Docker versions
|
||||||
|
|
||||||
|
The current Docker version support policy is the following: `N` to `N-2` included where `N` is the latest version.
|
||||||
|
|
||||||
|
At the moment, the following versions are supported: 1.9, 1.10 & 1.11.
|
||||||
|
|
||||||
## Run
|
## Run
|
||||||
|
|
||||||
### Quickstart
|
### Quickstart
|
||||||
|
|
|
@ -1,76 +1,131 @@
|
||||||
<rd-header>
|
<rd-header>
|
||||||
<rd-header-title title="Home"></rd-header-title>
|
<rd-header-title title="Home">
|
||||||
|
<i id="loadingViewSpinner" class="fa fa-cog fa-spin"></i>
|
||||||
|
</rd-header-title>
|
||||||
<rd-header-content>Dashboard</rd-header-content>
|
<rd-header-content>Dashboard</rd-header-content>
|
||||||
</rd-header>
|
</rd-header>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-3 col-md-6 col-xs-12">
|
<div class="col-lg-12 col-md-12 col-xs-12" ng-if="!swarm">
|
||||||
<rd-widget>
|
<rd-widget>
|
||||||
<rd-widget-body>
|
<rd-widget-header icon="fa-cogs" title="Node info"></rd-widget-header>
|
||||||
<div class="widget-icon blue pull-left">
|
<rd-widget-body classes="no-padding">
|
||||||
<i class="fa fa-tasks"></i>
|
<table class="table">
|
||||||
</div>
|
<tbody>
|
||||||
<div class="title">{{ containerData.total }}</div>
|
<tr>
|
||||||
<div class="comment">Containers</div>
|
<td>Name</td>
|
||||||
|
<td>{{ infoData.Name }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Docker version</td>
|
||||||
|
<td>{{ infoData.ServerVersion }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>CPU</td>
|
||||||
|
<td>{{ infoData.NCPU }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Memory</td>
|
||||||
|
<td>{{ infoData.MemTotal|humansize }}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
</rd-widget-body>
|
</rd-widget-body>
|
||||||
</rd-widget>
|
</rd-widget>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-lg-3 col-md-6 col-xs-12">
|
<div class="col-lg-12 col-md-12 col-xs-12" ng-if="swarm">
|
||||||
<rd-widget>
|
<rd-widget>
|
||||||
<rd-widget-body>
|
<rd-widget-header icon="fa-cogs" title="Cluster info"></rd-widget-header>
|
||||||
<div class="widget-icon green pull-left">
|
<rd-widget-body classes="no-padding">
|
||||||
<i class="fa fa-tasks"></i>
|
<table class="table">
|
||||||
</div>
|
<tbody>
|
||||||
<div class="title">{{ containerData.running }}</div>
|
<tr>
|
||||||
<div class="comment">Running</div>
|
<td>Nodes</td>
|
||||||
</rd-widget-body>
|
<td>{{ infoData.SystemStatus[3][1] }}</td>
|
||||||
</rd-widget>
|
</tr>
|
||||||
</div>
|
<tr>
|
||||||
<div class="col-lg-3 col-md-6 col-xs-12">
|
<td>Swarm version</td>
|
||||||
<rd-widget>
|
<td>{{ infoData.ServerVersion|swarmversion }}</td>
|
||||||
<rd-widget-body>
|
</tr>
|
||||||
<div class="widget-icon red pull-left">
|
<tr>
|
||||||
<i class="fa fa-tasks"></i>
|
<td>Total CPU</td>
|
||||||
</div>
|
<td>{{ infoData.NCPU }}</td>
|
||||||
<div class="title">{{ containerData.stopped }}</div>
|
</tr>
|
||||||
<div class="comment">Stopped</div>
|
<tr>
|
||||||
</rd-widget-body>
|
<td>Total memory</td>
|
||||||
</rd-widget>
|
<td>{{ infoData.MemTotal|humansize }}</td>
|
||||||
</div>
|
</tr>
|
||||||
<div class="col-lg-3 col-md-6 col-xs-12">
|
</tbody>
|
||||||
<rd-widget>
|
</table>
|
||||||
<rd-widget-body>
|
|
||||||
<div class="widget-icon gray pull-left">
|
|
||||||
<i class="fa fa-tasks"></i>
|
|
||||||
</div>
|
|
||||||
<div class="title">{{ containerData.ghost }}</div>
|
|
||||||
<div class="comment">Ghost</div>
|
|
||||||
</rd-widget-body>
|
</rd-widget-body>
|
||||||
</rd-widget>
|
</rd-widget>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-6">
|
<div class="col-lg-6 col-md-6 col-sm-6 col-xs-12">
|
||||||
<rd-widget>
|
<a ui-sref="containers">
|
||||||
<rd-widget-header icon="fa-tasks" title="Containers created"></rd-widget-header>
|
<rd-widget>
|
||||||
<rd-widget-body>
|
<rd-widget-body>
|
||||||
<canvas id="containers-started-chart" width="770" height="230">
|
<div class="widget-icon blue pull-left">
|
||||||
<p class="browserupgrade">You are using an <strong>outdated</strong> browser. Please <a
|
<i class="fa fa-tasks"></i>
|
||||||
href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p>
|
</div>
|
||||||
</canvas>
|
<div class="pull-right">
|
||||||
</rd-widget-body>
|
<div><i class="fa fa-heartbeat text-icon green-icon"></i>{{ containerData.running }} running</div>
|
||||||
</rd-widget>
|
<div><i class="fa fa-heartbeat text-icon red-icon"></i>{{ containerData.stopped }} stopped</div>
|
||||||
|
</div>
|
||||||
|
<div class="title">{{ containerData.total }}</div>
|
||||||
|
<div class="comment">Containers</div>
|
||||||
|
</rd-widget-body>
|
||||||
|
</rd-widget>
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-lg-6">
|
<div class="col-lg-6 col-md-6 col-sm-6 col-xs-12">
|
||||||
<rd-widget>
|
<a ui-sref="images">
|
||||||
<rd-widget-header icon="fa-clone" title="Images created"></rd-widget-header>
|
<rd-widget>
|
||||||
<rd-widget-body>
|
<rd-widget-body>
|
||||||
<canvas id="images-created-chart" width="770" height="230">
|
<div class="widget-icon blue pull-left">
|
||||||
<p class="browserupgrade">You are using an <strong>outdated</strong> browser. Please <a
|
<i class="fa fa-clone"></i>
|
||||||
href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p>
|
</div>
|
||||||
</canvas>
|
<div class="pull-right">
|
||||||
</rd-widget-body>
|
<div><i class="fa fa-pie-chart text-icon"></i>{{ imageData.size|humansize }}</div>
|
||||||
</rd-widget>
|
</div>
|
||||||
|
<div class="title">{{ imageData.total }}</div>
|
||||||
|
<div class="comment">Images</div>
|
||||||
|
</rd-widget-body>
|
||||||
|
</rd-widget>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="col-lg-6 col-md-6 col-sm-6 col-xs-12">
|
||||||
|
<a ui-sref="volumes">
|
||||||
|
<rd-widget>
|
||||||
|
<rd-widget-body>
|
||||||
|
<div class="widget-icon blue pull-left">
|
||||||
|
<i class="fa fa-cubes"></i>
|
||||||
|
</div>
|
||||||
|
<div class="pull-right" ng-if="infoData.Driver">
|
||||||
|
<div><i class="fa fa-hdd-o text-icon"></i>{{ infoData.Driver }} driver</div>
|
||||||
|
</div>
|
||||||
|
<div class="title">{{ volumeData.total }}</div>
|
||||||
|
<div class="comment">Volumes</div>
|
||||||
|
</rd-widget-body>
|
||||||
|
</rd-widget>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="col-lg-6 col-md-6 col-sm-6 col-xs-12">
|
||||||
|
<a ui-sref="networks">
|
||||||
|
<rd-widget>
|
||||||
|
<rd-widget-body>
|
||||||
|
<div class="widget-icon blue pull-left">
|
||||||
|
<i class="fa fa-sitemap"></i>
|
||||||
|
</div>
|
||||||
|
<div class="title">{{ networkData.total }}</div>
|
||||||
|
<div class="comment">Networks</div>
|
||||||
|
</rd-widget-body>
|
||||||
|
</rd-widget>
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
</div>
|
||||||
|
|
|
@ -1,49 +1,83 @@
|
||||||
angular.module('dashboard', [])
|
angular.module('dashboard', [])
|
||||||
.controller('DashboardController', ['$scope', 'Config', 'Container', 'Image', 'Settings', 'LineChart',
|
.controller('DashboardController', ['$scope', '$q', 'Config', 'Container', 'Image', 'Network', 'Volume', 'Info',
|
||||||
function ($scope, Config, Container, Image, Settings, LineChart) {
|
function ($scope, $q, Config, Container, Image, Network, Volume, Info) {
|
||||||
|
|
||||||
$scope.containerData = {};
|
$scope.containerData = {
|
||||||
|
total: 0
|
||||||
var buildCharts = function (data) {
|
};
|
||||||
$scope.containerData.total = data.length;
|
$scope.imageData = {
|
||||||
LineChart.build('#containers-started-chart', data, function (c) {
|
total: 0
|
||||||
return new Date(c.Created * 1000).toLocaleDateString();
|
};
|
||||||
});
|
$scope.networkData = {
|
||||||
var s = $scope;
|
total: 0
|
||||||
Image.query({}, function (d) {
|
};
|
||||||
s.totalImages = d.length;
|
$scope.volumeData = {
|
||||||
LineChart.build('#images-created-chart', d, function (c) {
|
total: 0
|
||||||
return new Date(c.Created * 1000).toLocaleDateString();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function prepareContainerData(d) {
|
||||||
|
var running = 0;
|
||||||
|
var stopped = 0;
|
||||||
|
|
||||||
|
var containers = d;
|
||||||
|
if (hiddenLabels) {
|
||||||
|
containers = hideContainers(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < containers.length; i++) {
|
||||||
|
var item = containers[i];
|
||||||
|
if (item.Status.indexOf('Up') !== -1) {
|
||||||
|
running += 1;
|
||||||
|
} else if (item.Status.indexOf('Exit') !== -1) {
|
||||||
|
stopped += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$scope.containerData.running = running;
|
||||||
|
$scope.containerData.stopped = stopped;
|
||||||
|
$scope.containerData.total = containers.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
function prepareImageData(d) {
|
||||||
|
var images = d;
|
||||||
|
var totalImageSize = 0;
|
||||||
|
for (var i = 0; i < images.length; i++) {
|
||||||
|
var item = images[i];
|
||||||
|
totalImageSize += item.VirtualSize;
|
||||||
|
}
|
||||||
|
$scope.imageData.total = images.length;
|
||||||
|
$scope.imageData.size = totalImageSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
function prepareVolumeData(d) {
|
||||||
|
var volumes = d.Volumes;
|
||||||
|
$scope.volumeData.total = volumes.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
function prepareNetworkData(d) {
|
||||||
|
var networks = d;
|
||||||
|
$scope.networkData.total = networks.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
function prepareInfoData(d) {
|
||||||
|
var info = d;
|
||||||
|
$scope.infoData = info;
|
||||||
|
}
|
||||||
|
|
||||||
function fetchDashboardData() {
|
function fetchDashboardData() {
|
||||||
Container.query({all: 1}, function (d) {
|
$('#loadingViewSpinner').show();
|
||||||
var running = 0;
|
$q.all([
|
||||||
var ghost = 0;
|
Container.query({all: 1}).$promise,
|
||||||
var stopped = 0;
|
Image.query({}).$promise,
|
||||||
|
Volume.query({}).$promise,
|
||||||
var containers = d;
|
Network.query({}).$promise,
|
||||||
if (hiddenLabels) {
|
Info.get({}).$promise,
|
||||||
containers = hideContainers(d);
|
]).then(function (d) {
|
||||||
}
|
prepareContainerData(d[0]);
|
||||||
|
prepareImageData(d[1]);
|
||||||
for (var i = 0; i < containers.length; i++) {
|
prepareVolumeData(d[2]);
|
||||||
var item = containers[i];
|
prepareNetworkData(d[3]);
|
||||||
if (item.Status === "Ghost") {
|
prepareInfoData(d[4]);
|
||||||
ghost += 1;
|
$('#loadingViewSpinner').hide();
|
||||||
} else if (item.Status.indexOf('Exit') !== -1) {
|
|
||||||
stopped += 1;
|
|
||||||
} else {
|
|
||||||
running += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$scope.containerData.running = running;
|
|
||||||
$scope.containerData.stopped = stopped;
|
|
||||||
$scope.containerData.ghost = ghost;
|
|
||||||
|
|
||||||
buildCharts(containers);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,6 +97,7 @@ function ($scope, Config, Container, Image, Settings, LineChart) {
|
||||||
};
|
};
|
||||||
|
|
||||||
Config.$promise.then(function (c) {
|
Config.$promise.then(function (c) {
|
||||||
|
$scope.swarm = c.swarm;
|
||||||
hiddenLabels = c.hiddenLabels;
|
hiddenLabels = c.hiddenLabels;
|
||||||
fetchDashboardData();
|
fetchDashboardData();
|
||||||
});
|
});
|
||||||
|
|
|
@ -130,6 +130,12 @@ angular.module('dockerui.filters', [])
|
||||||
return _.split(container.Names[0], '/')[2];
|
return _.split(container.Names[0], '/')[2];
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
|
.filter('swarmversion', function () {
|
||||||
|
'use strict';
|
||||||
|
return function (text) {
|
||||||
|
return _.split(text, '/')[1];
|
||||||
|
};
|
||||||
|
})
|
||||||
.filter('swarmhostname', function () {
|
.filter('swarmhostname', function () {
|
||||||
'use strict';
|
'use strict';
|
||||||
return function (container) {
|
return function (container) {
|
||||||
|
|
|
@ -165,3 +165,15 @@ input[type="radio"] {
|
||||||
.clickable {
|
.clickable {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.text-icon {
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.green-icon {
|
||||||
|
color: #23ae89;
|
||||||
|
}
|
||||||
|
|
||||||
|
.red-icon {
|
||||||
|
color: #ae2323;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue