342 lines
10 KiB
JavaScript
342 lines
10 KiB
JavaScript
/**
|
|
* SPDX-FileCopyrightText: 2016 F7cloud GmbH and F7cloud contributors
|
|
* SPDX-License-Identifier: AGPL-3.0-or-later
|
|
*/
|
|
|
|
(function ($, OC) {
|
|
|
|
var memoryUsageChart,
|
|
memoryUsageLine,
|
|
swapUsageLine,
|
|
cpuLoadChart,
|
|
cpuLoadLine
|
|
|
|
const chartOptions = {
|
|
millisPerPixel: 100,
|
|
minValue: 0,
|
|
grid: {fillStyle: 'rgba(0,0,0,0)', strokeStyle: 'transparent'},
|
|
labels: {fillStyle: getThemedPassiveColor(), fontSize: 12, precision: 1},
|
|
responsive: true,
|
|
tooltip: true,
|
|
tooltipLine: {
|
|
strokeStyle: getThemedPassiveColor()
|
|
}
|
|
};
|
|
|
|
$(function () {
|
|
initDiskCharts();
|
|
|
|
setHumanReadableSizeToElement("databaseSize");
|
|
setHumanReadableSizeToElement("phpMemLimit");
|
|
setHumanReadableSizeToElement("phpUploadMaxSize");
|
|
setHumanReadableSizeToElement("systemDiskFreeSpace");
|
|
|
|
initMonitoringLinkToClipboard();
|
|
$("#monitoring-endpoint-url").on('click', function () {
|
|
$(this).select();
|
|
});
|
|
|
|
function updateInfo() {
|
|
const url = OC.generateUrl('/apps/serverinfo/update')
|
|
|
|
$.get(url)
|
|
.done(function (response) {
|
|
updateCPUStatistics(response.system.cpuload, response.system.cpunum)
|
|
updateMemoryStatistics(response.system.mem_total, response.system.mem_free, response.system.swap_total, response.system.swap_free)
|
|
})
|
|
.always(function () {
|
|
setTimeout(updateInfo, 2000)
|
|
})
|
|
}
|
|
|
|
setTimeout(updateInfo, 0)
|
|
});
|
|
|
|
window.addEventListener('load', resizeSystemCharts)
|
|
window.addEventListener('resize', resizeSystemCharts)
|
|
|
|
function getThemedPrimaryColor() {
|
|
return OCA.Theming ? OCA.Theming.color : 'rgb(54, 129, 195)';
|
|
}
|
|
|
|
function getThemedPassiveColor() {
|
|
return 'rgb(148, 148, 148)';
|
|
}
|
|
|
|
/**
|
|
* Reset all canvas widths on window resize so canvas is responsive
|
|
*/
|
|
function resizeSystemCharts() {
|
|
let cpuCanvas = $("#cpuloadcanvas"),
|
|
cpuCanvasWidth = cpuCanvas.parents('.infobox').width(),
|
|
memCanvas = $("#memorycanvas"),
|
|
memCanvasWidth = memCanvas.parents('.infobox').width();
|
|
|
|
|
|
// We have to set css width AND attribute width
|
|
cpuCanvas.width(cpuCanvasWidth);
|
|
cpuCanvas.attr('width', cpuCanvasWidth);
|
|
memCanvas.width(memCanvasWidth);
|
|
memCanvas.attr('width', memCanvasWidth);
|
|
}
|
|
|
|
function updateCPUStatistics(cpuload, numCpus) {
|
|
let $cpuFooterInfo = $('#cpuFooterInfo');
|
|
let $cpuLoadCanvas = $('#cpuloadcanvas');
|
|
|
|
// We need to stop touch events here, since they cause the tooltip to open, but never close again
|
|
$cpuLoadCanvas[0].addEventListener('touchstart', (e) => {
|
|
e.preventDefault();
|
|
})
|
|
|
|
if (cpuload === false || numCpus === -1) {
|
|
$cpuFooterInfo.text(t('serverinfo', 'CPU info not available'));
|
|
$cpuLoadCanvas.addClass('hidden');
|
|
return;
|
|
} else if ($cpuLoadCanvas.hasClass('hidden')) {
|
|
$cpuLoadCanvas.removeClass('hidden');
|
|
}
|
|
|
|
let cpuloadFixed = cpuload.map((load) => load.toFixed(2));
|
|
let cpuloadPercentageFixed = cpuload.map((load) => ((load / numCpus) * 100).toFixed(1));
|
|
|
|
if (typeof cpuLoadChart === 'undefined') {
|
|
const percentageFormatter = (val, precision) => val.toFixed(precision) + " %";
|
|
|
|
cpuLoadChart = new SmoothieChart({
|
|
...chartOptions,
|
|
yMinFormatter: percentageFormatter,
|
|
yMaxFormatter: percentageFormatter,
|
|
maxValue: 100
|
|
});
|
|
cpuLoadChart.streamTo(document.getElementById("cpuloadcanvas"), 1000/*delay*/);
|
|
cpuLoadLine = new TimeSeries();
|
|
cpuLoadChart.addTimeSeries(cpuLoadLine, {
|
|
lineWidth: 1,
|
|
strokeStyle: getThemedPassiveColor(),
|
|
fillStyle: getThemedPrimaryColor(),
|
|
tooltipLabel: t('serverinfo', 'CPU Usage:')
|
|
});
|
|
}
|
|
|
|
$cpuFooterInfo.text(t('serverinfo', 'Load average: {percentage} % ({load}) last minute', { percentage: cpuloadPercentageFixed[0], load: cpuloadFixed[0] }));
|
|
$cpuFooterInfo[0].title = t(
|
|
'serverinfo',
|
|
'{lastMinutePercentage} % ({lastMinute}) last Minute\n{last5MinutesPercentage} % ({last5Minutes}) last 5 Minutes\n{last15MinutesPercentage} % ({last15Minutes}) last 15 Minutes',
|
|
{
|
|
lastMinute: cpuloadFixed[0],
|
|
lastMinutePercentage: cpuloadPercentageFixed[0],
|
|
last5Minutes: cpuloadFixed[1],
|
|
last5MinutesPercentage: cpuloadPercentageFixed[1],
|
|
last15Minutes: cpuloadFixed[2],
|
|
last15MinutesPercentage: cpuloadPercentageFixed[2]
|
|
}
|
|
);
|
|
|
|
cpuLoadLine.append(new Date().getTime(), cpuload[0] / numCpus * 100);
|
|
}
|
|
|
|
function isMemoryStat(memTotal, memFree) {
|
|
if (memTotal === 'N/A' || memFree === 'N/A') {
|
|
return false;
|
|
} else {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
function isSwapStat(swapTotal, swapFree) {
|
|
if (swapTotal === 'N/A' || swapFree === 'N/A') {
|
|
return false;
|
|
} else {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
function updateMemoryStatistics(memTotal, memFree, swapTotal, swapFree) {
|
|
var $memFooterInfo = $('#memFooterInfo');
|
|
var $swapFooterInfo = $('#swapFooterInfo');
|
|
var $memoryCanvas = $('#memorycanvas');
|
|
|
|
// We need to stop touch events here, since they cause the tooltip to open, but never close again
|
|
$memoryCanvas[0].addEventListener('touchstart', (e) => {
|
|
e.preventDefault();
|
|
})
|
|
|
|
var memTotalBytes = memTotal * 1024,
|
|
memUsageBytes = (memTotal - memFree) * 1024,
|
|
memTotalGB = memTotal / (1024 * 1024),
|
|
memUsageGB = (memTotal - memFree) / (1024 * 1024);
|
|
|
|
var swapTotalBytes = swapTotal * 1024,
|
|
swapUsageBytes = (swapTotal - swapFree) * 1024,
|
|
swapTotalGB = swapTotal / (1024 * 1024),
|
|
swapUsageGB = (swapTotal - swapFree) / (1024 * 1024);
|
|
|
|
var maxValueOfChart = swapTotalGB;
|
|
if (memTotalGB > swapTotalGB) {
|
|
maxValueOfChart = memTotalGB;
|
|
}
|
|
|
|
if (typeof memoryUsageChart === 'undefined') {
|
|
const gbFormatter = (val, precision) => val.toFixed(precision) + " GB";
|
|
|
|
memoryUsageChart = new SmoothieChart(
|
|
{
|
|
...chartOptions,
|
|
maxValue: maxValueOfChart,
|
|
yMinFormatter: gbFormatter,
|
|
yMaxFormatter: gbFormatter
|
|
});
|
|
memoryUsageChart.streamTo(document.getElementById("memorycanvas"), 1000/*delay*/);
|
|
memoryUsageLine = new TimeSeries();
|
|
memoryUsageChart.addTimeSeries(memoryUsageLine, {
|
|
lineWidth: 1,
|
|
strokeStyle: getThemedPassiveColor(),
|
|
fillStyle: getThemedPrimaryColor(),
|
|
tooltipLabel: t('serverinfo', 'RAM Usage:')
|
|
});
|
|
swapUsageLine = new TimeSeries();
|
|
memoryUsageChart.addTimeSeries(swapUsageLine, {
|
|
lineWidth: 1,
|
|
strokeStyle: getThemedPassiveColor(),
|
|
fillStyle: 'rgba(100, 100, 100, 0.2)',
|
|
tooltipLabel: t('serverinfo', 'SWAP Usage:')
|
|
});
|
|
}
|
|
|
|
if (isMemoryStat(memTotal, memFree)) {
|
|
$memFooterInfo.text(t('serverinfo','RAM: Total: {memTotalBytes}/Current usage: {memUsageBytes}', { memTotalBytes: OC.Util.humanFileSize(memTotalBytes), memUsageBytes: OC.Util.humanFileSize(memUsageBytes) }));
|
|
memoryUsageLine.append(new Date().getTime(), memUsageGB);
|
|
|
|
if ($memoryCanvas.hasClass('hidden')) {
|
|
$memoryCanvas.removeClass('hidden');
|
|
}
|
|
} else {
|
|
$memFooterInfo.text(t('serverinfo', 'RAM info not available'));
|
|
$memoryCanvas.addClass('hidden');
|
|
}
|
|
|
|
if (isSwapStat(swapTotal, swapFree)) {
|
|
$swapFooterInfo.text(t('serverinfo','SWAP: Total: {swapTotalBytes}/Current usage: {swapUsageBytes}', { swapTotalBytes: OC.Util.humanFileSize(swapTotalBytes), swapUsageBytes: OC.Util.humanFileSize(swapUsageBytes) }));
|
|
swapUsageLine.append(new Date().getTime(), swapUsageGB);
|
|
} else {
|
|
$swapFooterInfo.text(t('serverinfo', 'SWAP info not available'));
|
|
}
|
|
}
|
|
|
|
function setHumanReadableSizeToElement(elementId) {
|
|
var maxUploadSize = parseInt($('#' + elementId).text());
|
|
|
|
if ($.isNumeric(maxUploadSize)) {
|
|
$('#' + elementId).text(OC.Util.humanFileSize(maxUploadSize));
|
|
}
|
|
}
|
|
|
|
function initMonitoringLinkToClipboard() {
|
|
var clipboard = new Clipboard('.clipboardButton');
|
|
clipboard.on('success', function (e) {
|
|
OC.Notification.show(t('serverinfo', 'Copied!'), { type: 'success' })
|
|
});
|
|
clipboard.on('error', function () {
|
|
var actionMsg = '';
|
|
if (/iPhone|iPad/i.test(navigator.userAgent)) {
|
|
actionMsg = t('core', 'Not supported!');
|
|
} else if (/Mac/i.test(navigator.userAgent)) {
|
|
actionMsg = t('core', 'Press ⌘-C to copy.');
|
|
} else {
|
|
actionMsg = t('core', 'Press Ctrl-C to copy.');
|
|
}
|
|
OC.Notification.show(actionMsg, { type: 'error' })
|
|
});
|
|
}
|
|
|
|
function initDiskCharts() {
|
|
const url = OC.linkToOCS('apps/serverinfo/api/v1/', 2) + 'diskdata?format=json';
|
|
$.get(url)
|
|
.done(function (response) {
|
|
var diskdata = response.ocs.data;
|
|
var diskcharts = document.querySelectorAll(".DiskChart");
|
|
var i;
|
|
for (i = 0; i < diskcharts.length; i++) {
|
|
var chartdata = {
|
|
datasets: [
|
|
{
|
|
backgroundColor: [
|
|
getThemedPrimaryColor(),
|
|
getThemedPassiveColor(),
|
|
],
|
|
data: diskdata[i],
|
|
}
|
|
]
|
|
};
|
|
var ctx = diskcharts[i];
|
|
var barGraph = new Chart(ctx, {
|
|
type: 'doughnut',
|
|
data: chartdata,
|
|
options: {
|
|
plugins: {
|
|
legend: { display: false },
|
|
tooltip: {
|
|
enabled: false
|
|
}
|
|
},
|
|
tooltips: {
|
|
enabled: true,
|
|
},
|
|
cutoutPercentage: 60,
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
var interval = 10000; // 1000 = 1 second, 3000 = 3 seconds
|
|
function doAjax() {
|
|
const url = OC.linkToOCS('apps/serverinfo/api/v1/', 2) + 'basicdata?format=json';
|
|
$.get(url)
|
|
.done(function (response) {
|
|
var data = response.ocs.data;
|
|
document.getElementById("servertime").innerHTML = data.servertime;
|
|
document.getElementById("uptime").innerHTML = data.uptime;
|
|
for (const thermalzone of data.thermalzones) {
|
|
document.getElementById(thermalzone.zone).textContent = thermalzone.temp;
|
|
}
|
|
})
|
|
.always(function () {
|
|
setTimeout(doAjax, interval);
|
|
});
|
|
}
|
|
|
|
setTimeout(doAjax, 0);
|
|
}
|
|
|
|
})(jQuery, OC);
|
|
|
|
function updateMonitoringUrl(event) {
|
|
const $endpointUrl = document.getElementById('monitoring-endpoint-url');
|
|
const $params = document.querySelectorAll('.update-monitoring-endpoint-url');
|
|
|
|
const url = new URL($endpointUrl.value)
|
|
url.searchParams.delete('format')
|
|
url.searchParams.delete('skipApps')
|
|
url.searchParams.delete('skipUpdate')
|
|
|
|
for (const $param of $params) {
|
|
if ($param.name === 'format_json' && $param.checked) {
|
|
url.searchParams.set('format', 'json')
|
|
}
|
|
if ($param.name === 'skip_apps' && !$param.checked) {
|
|
url.searchParams.set('skipApps', 'false')
|
|
}
|
|
if ($param.name === 'skip_update' && !$param.checked) {
|
|
url.searchParams.set('skipUpdate', 'false')
|
|
}
|
|
}
|
|
|
|
$endpointUrl.value = url.toString()
|
|
}
|
|
|
|
document.addEventListener('DOMContentLoaded', function (event) {
|
|
const $params = document.querySelectorAll('.update-monitoring-endpoint-url');
|
|
$params.forEach($param => $param.addEventListener('change', updateMonitoringUrl));
|
|
});
|