1
0
Fork 0
mirror of https://github.com/portainer/portainer.git synced 2025-08-02 20:35:25 +02:00

Rdash theme integration (#1)

* Adding latest build to dist.

* Adding latest build to dist.

* Bump other app version.

* Build latest changes.

* Bump version to 0.7.0.

* Version bump to 0.9.0-beta and remote API 1.20.

* Whoah there, back down to 0.8.0-beta.

* Merge branch 'crosbymichael-master' into crosbymichael-dist

* Add volume options in volume creation form

* display swarm cluster information in Swarm tab

* update LICENSE

* update repository URL in status bar

* remove console logs

* do not display Swarm containers anywhere in the UI

* update position for add/remove option on Volumes page

* compliant with swarm == 1.2.0 API support

* update nginx-basic-auth examples with latest nginx and swarm example

* Updated .gitignore

* update .gitignore

* reverted entry for dist/uifordocker in .gitignore

* WIP

* fix linter issues

* added logo

* update repository URL

* update .gitignore (ignore dist/*)

* add lodash

* add containers actions binding (start, stop...)

* replace image icon

* bind remove image action

* bind network remove action

* bind volume remove action

* update logo

* wip on container details

* update logo scaling, favicon and page title

* wip container view

* add containers actions in container view

* add image view

* add network view

* remove useless data in tables

* add pull image, create network modals

* add create volume modal

* update style for createVolume options

* add start container modal

* create volume modal now use a select to display drivers

* add container stats

* add containerTop view in stats view

* fix trimcontainername filter

* add container logs view

* updated .gitignore

* remove useless files/modules

* remove useless chart in image view

* replace $location usage with $state.go

* remove useless swarm example
This commit is contained in:
Anthony Lapenna 2016-06-02 17:34:03 +12:00
parent 1b206f223f
commit 0f51cb66e0
71 changed files with 2790 additions and 3211 deletions

View file

@ -1,67 +1,67 @@
<div class="row">
<div class="col-xs-12">
<h1>Stats for: {{ containerName }}</h1>
<h2>CPU</h2>
<div class="row">
<div class="col-sm-7">
<canvas id="cpu-stats-chart" width="650" height="300"></canvas>
</div>
<div class="col-lg-12 col-md-12 col-xs-12">
<rd-widget>
<rd-widget-body>
<div class="widget-icon grey pull-left">
<i class="fa fa-tasks"></i>
</div>
<h2>Memory</h2>
<div class="row">
<div class="col-sm-7">
<canvas id="memory-stats-chart" width="650" height="300"></canvas>
</div>
<div class="col-sm-offset-1 col-sm-4">
<table class="table">
<tr>
<td>Max usage</td>
<td>{{ data.memory_stats.max_usage | humansize }}</td>
</tr>
<tr>
<td>Limit</td>
<td>{{ data.memory_stats.limit | humansize }}</td>
</tr>
<tr>
<td>Fail count</td>
<td>{{ data.memory_stats.failcnt }}</td>
</tr>
</table>
<accordion>
<accordion-group heading="Other stats">
<table class="table">
<tr ng-repeat="(key, value) in data.memory_stats.stats">
<td>{{ key }}</td>
<td>{{ value }}</td>
</tr>
</table>
</accordion-group>
</accordion>
</div>
<div class="title">{{ containerName }}</div>
<div class="comment">
Name
</div>
<h1>Network {{ networkName}}</h1>
<div class="row">
<div class="col-sm-7">
<canvas id="network-stats-chart" width="650" height="300"></canvas>
</div>
<div class="col-sm-offset-1 col-sm-4">
<div id="network-legend" style="margin-bottom: 20px;"></div>
<accordion>
<accordion-group heading="Other stats">
<table class="table">
<tr ng-repeat="(key, value) in data.network">
<td>{{ key }}</td>
<td>{{ value }}</td>
</tr>
</table>
</accordion-group>
</accordion>
</div>
</div>
</div>
</rd-widget-body>
</rd-widget>
</div>
</div>
<div class="row">
<div class="col-lg-6">
<rd-widget>
<rd-widget-header icon="fa-area-chart" title="CPU usage"></rd-widget-header>
<rd-widget-body>
<canvas id="cpu-stats-chart" width="770" height="230"></canvas>
</rd-widget-body>
</rd-widget>
</div>
<div class="col-lg-6">
<rd-widget>
<rd-widget-header icon="fa-area-chart" title="Memory usage"></rd-widget-header>
<rd-widget-body>
<canvas id="memory-stats-chart" width="770" height="230"></canvas>
</rd-widget-body>
</rd-widget>
</div>
</div>
<div class="row">
<div class="col-lg-6">
<rd-widget>
<rd-widget-header icon="fa-area-chart" title="Network usage"></rd-widget-header>
<rd-widget-body>
<canvas id="network-stats-chart" width="770" height="230"></canvas>
<div class="comment">
<div id="network-legend" style="margin-bottom: 20px;"></div>
</div>
</rd-widget-body>
</rd-widget>
</div>
<div class="col-lg-6">
<rd-widget>
<rd-widget-header icon="fa-tasks" title="Processes"></rd-widget-header>
<rd-widget-body classes="no-padding">
<table class="table table-striped">
<thead>
<tr>
<th ng-repeat="title in containerTop.Titles">{{title}}</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="processInfos in containerTop.Processes">
<td ng-repeat="processInfo in processInfos track by $index">{{processInfo}}</td>
</tr>
</tbody>
</table>
</rd-widget-body>
</rd-widget>
</div>
</div>

View file

@ -1,182 +1,194 @@
angular.module('stats', [])
.controller('StatsController', ['Settings', '$scope', 'Messages', '$timeout', 'Container', '$routeParams', 'humansizeFilter', '$sce', function (Settings, $scope, Messages, $timeout, Container, $routeParams, humansizeFilter, $sce) {
// TODO: Force scale to 0-100 for cpu, fix charts on dashboard,
// TODO: Force memory scale to 0 - max memory
.controller('StatsController', ['Settings', '$scope', 'Messages', '$timeout', 'Container', 'ContainerTop', '$stateParams', 'humansizeFilter', '$sce', '$document',
function (Settings, $scope, Messages, $timeout, Container, ContainerTop, $stateParams, humansizeFilter, $sce, $document) {
// TODO: Force scale to 0-100 for cpu, fix charts on dashboard,
// TODO: Force memory scale to 0 - max memory
$scope.ps_args = '';
$scope.getTop = function () {
ContainerTop.get($stateParams.id, {
ps_args: $scope.ps_args
}, function (data) {
$scope.containerTop = data;
});
};
$document.ready(function(){
var cpuLabels = [];
var cpuData = [];
var memoryLabels = [];
var memoryData = [];
var networkLabels = [];
var networkTxData = [];
var networkRxData = [];
for (var i = 0; i < 20; i++) {
cpuLabels.push('');
cpuData.push(0);
memoryLabels.push('');
memoryData.push(0);
networkLabels.push('');
networkTxData.push(0);
networkRxData.push(0);
}
var cpuDataset = { // CPU Usage
fillColor: "rgba(151,187,205,0.5)",
strokeColor: "rgba(151,187,205,1)",
pointColor: "rgba(151,187,205,1)",
pointStrokeColor: "#fff",
data: cpuData
};
var memoryDataset = {
fillColor: "rgba(151,187,205,0.5)",
strokeColor: "rgba(151,187,205,1)",
pointColor: "rgba(151,187,205,1)",
pointStrokeColor: "#fff",
data: memoryData
};
var networkRxDataset = {
label: "Rx Bytes",
fillColor: "rgba(151,187,205,0.5)",
strokeColor: "rgba(151,187,205,1)",
pointColor: "rgba(151,187,205,1)",
pointStrokeColor: "#fff",
data: networkRxData
};
var networkTxDataset = {
label: "Tx Bytes",
fillColor: "rgba(255,180,174,0.5)",
strokeColor: "rgba(255,180,174,1)",
pointColor: "rgba(255,180,174,1)",
pointStrokeColor: "#fff",
data: networkTxData
};
var networkLegendData = [
{
//value: '',
color: 'rgba(151,187,205,0.5)',
title: 'Rx Data'
},
{
//value: '',
color: 'rgba(255,180,174,0.5)',
title: 'Tx Data'
}
];
var cpuLabels = [];
var cpuData = [];
var memoryLabels = [];
var memoryData = [];
var networkLabels = [];
var networkTxData = [];
var networkRxData = [];
for (var i = 0; i < 20; i++) {
cpuLabels.push('');
cpuData.push(0);
memoryLabels.push('');
memoryData.push(0);
networkLabels.push('');
networkTxData.push(0);
networkRxData.push(0);
}
var cpuDataset = { // CPU Usage
fillColor: "rgba(151,187,205,0.5)",
strokeColor: "rgba(151,187,205,1)",
pointColor: "rgba(151,187,205,1)",
pointStrokeColor: "#fff",
data: cpuData
};
var memoryDataset = {
fillColor: "rgba(151,187,205,0.5)",
strokeColor: "rgba(151,187,205,1)",
pointColor: "rgba(151,187,205,1)",
pointStrokeColor: "#fff",
data: memoryData
};
var networkRxDataset = {
label: "Rx Bytes",
fillColor: "rgba(151,187,205,0.5)",
strokeColor: "rgba(151,187,205,1)",
pointColor: "rgba(151,187,205,1)",
pointStrokeColor: "#fff",
data: networkRxData
};
var networkTxDataset = {
label: "Tx Bytes",
fillColor: "rgba(255,180,174,0.5)",
strokeColor: "rgba(255,180,174,1)",
pointColor: "rgba(255,180,174,1)",
pointStrokeColor: "#fff",
data: networkTxData
};
var networkLegendData = [
{
//value: '',
color: 'rgba(151,187,205,0.5)',
title: 'Rx Data'
},
{
//value: '',
color: 'rgba(255,180,174,0.5)',
title: 'Rx Data'
}];
legend($('#network-legend').get(0), networkLegendData);
legend($('#network-legend').get(0), networkLegendData);
Chart.defaults.global.animationSteps = 30; // Lower from 60 to ease CPU load.
var cpuChart = new Chart($('#cpu-stats-chart').get(0).getContext("2d")).Line({
labels: cpuLabels,
datasets: [cpuDataset]
}, {
responsive: true
Chart.defaults.global.animationSteps = 30; // Lower from 60 to ease CPU load.
var cpuChart = new Chart($('#cpu-stats-chart').get(0).getContext("2d")).Line({
labels: cpuLabels,
datasets: [cpuDataset]
}, {
responsive: true
});
var memoryChart = new Chart($('#memory-stats-chart').get(0).getContext('2d')).Line({
labels: memoryLabels,
datasets: [memoryDataset]
},
{
scaleLabel: function (valueObj) {
return humansizeFilter(parseInt(valueObj.value, 10));
},
responsive: true
//scaleOverride: true,
//scaleSteps: 10,
//scaleStepWidth: Math.ceil(initialStats.memory_stats.limit / 10),
//scaleStartValue: 0
});
var networkChart = new Chart($('#network-stats-chart').get(0).getContext("2d")).Line({
labels: networkLabels,
datasets: [networkRxDataset, networkTxDataset]
}, {
scaleLabel: function (valueObj) {
return humansizeFilter(parseInt(valueObj.value, 10));
},
responsive: true
});
$scope.networkLegend = $sce.trustAsHtml(networkChart.generateLegend());
function updateStats() {
Container.stats({id: $stateParams.id}, function (d) {
var arr = Object.keys(d).map(function (key) {
return d[key];
});
var memoryChart = new Chart($('#memory-stats-chart').get(0).getContext('2d')).Line({
labels: memoryLabels,
datasets: [memoryDataset]
},
{
scaleLabel: function (valueObj) {
return humansizeFilter(parseInt(valueObj.value, 10));
},
responsive: true
//scaleOverride: true,
//scaleSteps: 10,
//scaleStepWidth: Math.ceil(initialStats.memory_stats.limit / 10),
//scaleStartValue: 0
});
var networkChart = new Chart($('#network-stats-chart').get(0).getContext("2d")).Line({
labels: networkLabels,
datasets: [networkRxDataset, networkTxDataset]
}, {
scaleLabel: function (valueObj) {
return humansizeFilter(parseInt(valueObj.value, 10));
},
responsive: true
});
$scope.networkLegend = $sce.trustAsHtml(networkChart.generateLegend());
function updateStats() {
Container.stats({id: $routeParams.id}, function (d) {
var arr = Object.keys(d).map(function (key) {
return d[key];
});
if (arr.join('').indexOf('no such id') !== -1) {
Messages.error('Unable to retrieve stats', 'Is this container running?');
return;
}
// Update graph with latest data
$scope.data = d;
updateCpuChart(d);
updateMemoryChart(d);
updateNetworkChart(d);
timeout = $timeout(updateStats, 5000);
}, function () {
Messages.error('Unable to retrieve stats', 'Is this container running?');
timeout = $timeout(updateStats, 5000);
});
if (arr.join('').indexOf('no such id') !== -1) {
Messages.error('Unable to retrieve stats', 'Is this container running?');
return;
}
var timeout;
$scope.$on('$destroy', function () {
$timeout.cancel(timeout);
});
// Update graph with latest data
$scope.data = d;
updateCpuChart(d);
updateMemoryChart(d);
updateNetworkChart(d);
timeout = $timeout(updateStats, 5000);
}, function () {
Messages.error('Unable to retrieve stats', 'Is this container running?');
timeout = $timeout(updateStats, 5000);
});
}
updateStats();
var timeout;
$scope.$on('$destroy', function () {
$timeout.cancel(timeout);
});
function updateCpuChart(data) {
cpuChart.addData([calculateCPUPercent(data)], new Date(data.read).toLocaleTimeString());
cpuChart.removeData();
}
updateStats();
function updateMemoryChart(data) {
memoryChart.addData([data.memory_stats.usage], new Date(data.read).toLocaleTimeString());
memoryChart.removeData();
}
function updateCpuChart(data) {
cpuChart.addData([calculateCPUPercent(data)], new Date(data.read).toLocaleTimeString());
cpuChart.removeData();
}
var lastRxBytes = 0, lastTxBytes = 0;
function updateMemoryChart(data) {
memoryChart.addData([data.memory_stats.usage], new Date(data.read).toLocaleTimeString());
memoryChart.removeData();
}
function updateNetworkChart(data) {
// 1.9+ contains an object of networks, for now we'll just show stats for the first network
// TODO: Show graphs for all networks
if (data.networks) {
$scope.networkName = Object.keys(data.networks)[0];
data.network = data.networks[$scope.networkName];
}
var rxBytes = 0, txBytes = 0;
if (lastRxBytes !== 0 || lastTxBytes !== 0) {
// These will be zero on first call, ignore to prevent large graph spike
rxBytes = data.network.rx_bytes - lastRxBytes;
txBytes = data.network.tx_bytes - lastTxBytes;
}
lastRxBytes = data.network.rx_bytes;
lastTxBytes = data.network.tx_bytes;
networkChart.addData([rxBytes, txBytes], new Date(data.read).toLocaleTimeString());
networkChart.removeData();
}
var lastRxBytes = 0, lastTxBytes = 0;
function calculateCPUPercent(stats) {
// Same algorithm the official client uses: https://github.com/docker/docker/blob/master/api/client/stats.go#L195-L208
var prevCpu = stats.precpu_stats;
var curCpu = stats.cpu_stats;
function updateNetworkChart(data) {
// 1.9+ contains an object of networks, for now we'll just show stats for the first network
// TODO: Show graphs for all networks
if (data.networks) {
$scope.networkName = Object.keys(data.networks)[0];
data.network = data.networks[$scope.networkName];
}
var rxBytes = 0, txBytes = 0;
if (lastRxBytes !== 0 || lastTxBytes !== 0) {
// These will be zero on first call, ignore to prevent large graph spike
rxBytes = data.network.rx_bytes - lastRxBytes;
txBytes = data.network.tx_bytes - lastTxBytes;
}
lastRxBytes = data.network.rx_bytes;
lastTxBytes = data.network.tx_bytes;
networkChart.addData([rxBytes, txBytes], new Date(data.read).toLocaleTimeString());
networkChart.removeData();
}
var cpuPercent = 0.0;
function calculateCPUPercent(stats) {
// Same algorithm the official client uses: https://github.com/docker/docker/blob/master/api/client/stats.go#L195-L208
var prevCpu = stats.precpu_stats;
var curCpu = stats.cpu_stats;
// calculate the change for the cpu usage of the container in between readings
var cpuDelta = curCpu.cpu_usage.total_usage - prevCpu.cpu_usage.total_usage;
// calculate the change for the entire system between readings
var systemDelta = curCpu.system_cpu_usage - prevCpu.system_cpu_usage;
var cpuPercent = 0.0;
if (systemDelta > 0.0 && cpuDelta > 0.0) {
cpuPercent = (cpuDelta / systemDelta) * curCpu.cpu_usage.percpu_usage.length * 100.0;
}
return cpuPercent;
}
// calculate the change for the cpu usage of the container in between readings
var cpuDelta = curCpu.cpu_usage.total_usage - prevCpu.cpu_usage.total_usage;
// calculate the change for the entire system between readings
var systemDelta = curCpu.system_cpu_usage - prevCpu.system_cpu_usage;
Container.get({id: $routeParams.id}, function (d) {
$scope.containerName = d.Name.substring(1);
}, function (e) {
Messages.error("Failure", e.data);
});
}])
;
if (systemDelta > 0.0 && cpuDelta > 0.0) {
cpuPercent = (cpuDelta / systemDelta) * curCpu.cpu_usage.percpu_usage.length * 100.0;
}
return cpuPercent;
}
});
Container.get({id: $stateParams.id}, function (d) {
$scope.containerName = d.Name.substring(1);
}, function (e) {
Messages.error("Failure", e.data);
});
$scope.getTop();
}]);