Compare commits

...

11 Commits
1.4.0 ... 1.5.0

Author SHA1 Message Date
Anthony Lapenna
85140c7dcf Merge branch 'release/1.5.0' 2016-07-14 12:12:13 +12:00
Anthony Lapenna
30e9a604cd chore(version): bump version number 2016-07-14 12:12:01 +12:00
Anthony Lapenna
8c769148ad refactor(ui): remove console logging 2016-07-14 12:07:37 +12:00
Anthony Lapenna
b857970236 feat(ui): replace repository field with tags field in image view (#79) 2016-07-14 12:02:42 +12:00
Anthony Lapenna
23bff41304 Merge branch 'develop' of github.com:cloud-inovasi/cloudinovasi-ui into develop 2016-07-14 11:31:10 +12:00
Anthony Lapenna
8243326692 refactor(ui): fix lint issue 2016-07-14 11:29:41 +12:00
Anthony Lapenna
52d953a1c2 style(ui): fix typo in Engine view (#76) 2016-07-14 11:16:23 +12:00
Anthony Lapenna
e145d82947 style(ui): fix extra space in widget-header (#78) 2016-07-14 11:16:16 +12:00
Anthony Lapenna
25df1fe26c style(ui): add table-hover class to all entity tables (#77) 2016-07-14 11:16:10 +12:00
Anthony Lapenna
8464faa2a1 style(ui): add table-hover class to all entity tables 2016-07-14 11:03:40 +12:00
Anthony Lapenna
c8a5b82c89 feat(ui): new dashboard view (#75) 2016-07-14 10:58:39 +12:00
13 changed files with 231 additions and 113 deletions

View File

@@ -144,4 +144,4 @@ angular.module('uifordocker', [
.constant('DOCKER_ENDPOINT', 'dockerapi')
.constant('DOCKER_PORT', '') // Docker port, leave as an empty string if no port is requred. If you have a port, prefix it with a ':' i.e. :4243
.constant('CONFIG_ENDPOINT', '/config')
.constant('UI_VERSION', 'v1.4.0');
.constant('UI_VERSION', 'v1.5.0');

View File

@@ -1,76 +1,131 @@
<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>
<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-body>
<div class="widget-icon blue pull-left">
<i class="fa fa-tasks"></i>
</div>
<div class="title">{{ containerData.total }}</div>
<div class="comment">Containers</div>
<rd-widget-header icon="fa-cogs" title="Node info"></rd-widget-header>
<rd-widget-body classes="no-padding">
<table class="table">
<tbody>
<tr>
<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>
</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-body>
<div class="widget-icon green pull-left">
<i class="fa fa-tasks"></i>
</div>
<div class="title">{{ containerData.running }}</div>
<div class="comment">Running</div>
</rd-widget-body>
</rd-widget>
</div>
<div class="col-lg-3 col-md-6 col-xs-12">
<rd-widget>
<rd-widget-body>
<div class="widget-icon red pull-left">
<i class="fa fa-tasks"></i>
</div>
<div class="title">{{ containerData.stopped }}</div>
<div class="comment">Stopped</div>
</rd-widget-body>
</rd-widget>
</div>
<div class="col-lg-3 col-md-6 col-xs-12">
<rd-widget>
<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-header icon="fa-cogs" title="Cluster info"></rd-widget-header>
<rd-widget-body classes="no-padding">
<table class="table">
<tbody>
<tr>
<td>Nodes</td>
<td>{{ infoData.SystemStatus[3][1] }}</td>
</tr>
<tr>
<td>Swarm version</td>
<td>{{ infoData.ServerVersion|swarmversion }}</td>
</tr>
<tr>
<td>Total CPU</td>
<td>{{ infoData.NCPU }}</td>
</tr>
<tr>
<td>Total memory</td>
<td>{{ infoData.MemTotal|humansize }}</td>
</tr>
</tbody>
</table>
</rd-widget-body>
</rd-widget>
</div>
</div>
<div class="row">
<div class="col-lg-6">
<rd-widget>
<rd-widget-header icon="fa-tasks" title="Containers created"></rd-widget-header>
<rd-widget-body>
<canvas id="containers-started-chart" width="770" height="230">
<p class="browserupgrade">You are using an <strong>outdated</strong> browser. Please <a
href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p>
</canvas>
</rd-widget-body>
</rd-widget>
<div class="col-lg-6 col-md-6 col-sm-6 col-xs-12">
<a ui-sref="containers">
<rd-widget>
<rd-widget-body>
<div class="widget-icon blue pull-left">
<i class="fa fa-tasks"></i>
</div>
<div class="pull-right">
<div><i class="fa fa-heartbeat text-icon green-icon"></i>{{ containerData.running }} running</div>
<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 class="col-lg-6">
<rd-widget>
<rd-widget-header icon="fa-clone" title="Images created"></rd-widget-header>
<rd-widget-body>
<canvas id="images-created-chart" width="770" height="230">
<p class="browserupgrade">You are using an <strong>outdated</strong> browser. Please <a
href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p>
</canvas>
</rd-widget-body>
</rd-widget>
<div class="col-lg-6 col-md-6 col-sm-6 col-xs-12">
<a ui-sref="images">
<rd-widget>
<rd-widget-body>
<div class="widget-icon blue pull-left">
<i class="fa fa-clone"></i>
</div>
<div class="pull-right">
<div><i class="fa fa-pie-chart text-icon"></i>{{ imageData.size|humansize }}</div>
</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 class="row">
</div>

View File

@@ -1,49 +1,83 @@
angular.module('dashboard', [])
.controller('DashboardController', ['$scope', 'Config', 'Container', 'Image', 'Settings', 'LineChart',
function ($scope, Config, Container, Image, Settings, LineChart) {
.controller('DashboardController', ['$scope', '$q', 'Config', 'Container', 'Image', 'Network', 'Volume', 'Info',
function ($scope, $q, Config, Container, Image, Network, Volume, Info) {
$scope.containerData = {};
var buildCharts = function (data) {
$scope.containerData.total = data.length;
LineChart.build('#containers-started-chart', data, function (c) {
return new Date(c.Created * 1000).toLocaleDateString();
});
var s = $scope;
Image.query({}, function (d) {
s.totalImages = d.length;
LineChart.build('#images-created-chart', d, function (c) {
return new Date(c.Created * 1000).toLocaleDateString();
});
});
$scope.containerData = {
total: 0
};
$scope.imageData = {
total: 0
};
$scope.networkData = {
total: 0
};
$scope.volumeData = {
total: 0
};
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() {
Container.query({all: 1}, function (d) {
var running = 0;
var ghost = 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 === "Ghost") {
ghost += 1;
} 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);
$('#loadingViewSpinner').show();
$q.all([
Container.query({all: 1}).$promise,
Image.query({}).$promise,
Volume.query({}).$promise,
Network.query({}).$promise,
Info.get({}).$promise
]).then(function (d) {
prepareContainerData(d[0]);
prepareImageData(d[1]);
prepareVolumeData(d[2]);
prepareNetworkData(d[3]);
prepareInfoData(d[4]);
$('#loadingViewSpinner').hide();
});
}
@@ -63,6 +97,7 @@ function ($scope, Config, Container, Image, Settings, LineChart) {
};
Config.$promise.then(function (c) {
$scope.swarm = c.swarm;
hiddenLabels = c.hiddenLabels;
fetchDashboardData();
});

View File

@@ -45,7 +45,7 @@
<div class="row">
<div class="col-lg-12">
<rd-widget>
<rd-widget-header icon="fa-object-group" title="Cluster status"></rd-widget-header>
<rd-widget-header icon="fa-object-group" title="Engine status"></rd-widget-header>
<rd-widget-body classes="no-padding">
<table class="table">
<tbody>

View File

@@ -63,7 +63,7 @@
</rd-widget-taskbar>
<rd-widget-body classes="no-padding">
<div class="table-responsive">
<table class="table">
<table class="table table-hover">
<thead>
<tr>
<th><label><input type="checkbox" ng-model="state.toggle" ng-change="toggleSelectAll()" /> Select</label></th>
@@ -76,7 +76,7 @@
</th>
<th>
<a ui-sref="images" ng-click="order('RepoTags')">
Repository
Tags
<span ng-show="sortType == 'RepoTags' && !sortReverse" class="glyphicon glyphicon-chevron-down"></span>
<span ng-show="sortType == 'RepoTags' && sortReverse" class="glyphicon glyphicon-chevron-up"></span>
</a>
@@ -101,7 +101,9 @@
<tr ng-repeat="image in (state.filteredImages = (images | filter:state.filter | orderBy:sortType:sortReverse))">
<td><input type="checkbox" ng-model="image.Checked" ng-change="selectItem(image)" /></td>
<td><a ui-sref="image({id: image.Id})">{{ image.Id|truncate:20}}</a></td>
<td>{{ image|repotag }}</td>
<td>
<span class="label label-primary image-tag" ng-repeat="tag in (image|repotags)">{{ tag }}</span>
</td>
<td>{{ image.VirtualSize|humansize }}</td>
<td>{{ image.Created|getdate }}</td>
</tr>

View File

@@ -25,7 +25,7 @@
</rd-widget-taskbar>
<rd-widget-body classes="no-padding">
<div class="table-responsive">
<table class="table">
<table class="table table-hover">
<thead>
<tr>
<th><label><input type="checkbox" ng-model="state.toggle" ng-change="toggleSelectAll()"/> Select</label></th>

View File

@@ -25,7 +25,7 @@
</rd-widget-taskbar>
<rd-widget-body classes="no-padding">
<div class="table-responsive">
<table class="table">
<table class="table table-hover">
<thead>
<tr>
<th><label><input type="checkbox" ng-model="state.toggle" ng-change="toggleSelectAll()"/> Select</label></th>

View File

@@ -8,7 +8,7 @@ angular
icon: '@'
},
transclude: true,
template: '<div class="widget-header"><div class="row"><div class="pull-left"><i class="fa" ng-class="icon"></i> {{title}} </div><div class="pull-right col-xs-6 col-sm-4" ng-transclude></div></div></div>',
template: '<div class="widget-header"><div class="row"><span class="pull-left"><i class="fa" ng-class="icon"></i> {{title}} </span><span class="pull-right col-xs-6 col-sm-4" ng-transclude></span></div></div>',
restrict: 'E'
};
return directive;

View File

@@ -130,23 +130,29 @@ angular.module('dockerui.filters', [])
return _.split(container.Names[0], '/')[2];
};
})
.filter('swarmversion', function () {
'use strict';
return function (text) {
return _.split(text, '/')[1];
};
})
.filter('swarmhostname', function () {
'use strict';
return function (container) {
return _.split(container.Names[0], '/')[1];
};
})
.filter('repotag', function () {
.filter('repotags', function () {
'use strict';
return function (image) {
if (image.RepoTags && image.RepoTags.length > 0) {
var tag = image.RepoTags[0];
if (tag === '<none>:<none>') {
tag = '';
return [];
}
return tag;
return image.RepoTags;
}
return '';
return [];
};
})
.filter('getdate', function () {

View File

@@ -165,3 +165,23 @@ input[type="radio"] {
.clickable {
cursor: pointer;
}
.text-icon {
margin-right: 5px;
}
.green-icon {
color: #23ae89;
}
.red-icon {
color: #ae2323;
}
.image-tag {
margin-right: 5px;
}
.widget .widget-body table tbody .image-tag {
font-size: 90% !important;
}

View File

@@ -1,6 +1,6 @@
{
"name": "uifordocker",
"version": "1.4.0",
"version": "1.5.0",
"homepage": "https://github.com/kevana/ui-for-docker",
"authors": [
"Michael Crosby <crosbymichael@gmail.com>",

View File

@@ -221,7 +221,7 @@ func csrfWrapper(h http.Handler) http.Handler {
}
func main() {
kingpin.Version("1.4.0")
kingpin.Version("1.5.0")
kingpin.Parse()
configuration := Config{

View File

@@ -2,7 +2,7 @@
"author": "Michael Crosby & Kevan Ahlquist",
"name": "uifordocker",
"homepage": "https://github.com/kevana/ui-for-docker",
"version": "1.4.0",
"version": "1.5.0",
"repository": {
"type": "git",
"url": "git@github.com:kevana/ui-for-docker.git"