mirror of
https://github.com/lucaspalomodevelop/core.git
synced 2026-03-20 03:16:12 +00:00
dashboard: interface statistics widget
This commit is contained in:
parent
ceb51410ba
commit
70867a40fd
@ -55,7 +55,17 @@ class DashboardController extends ApiControllerBase
|
||||
'datetime' => gettext('Current date/time'),
|
||||
'uptime' => gettext('Uptime'),
|
||||
'config' => gettext('Last configuration change')
|
||||
]
|
||||
],
|
||||
'interfacestatistics' => [
|
||||
'title' => gettext('Interface Statistics'),
|
||||
'bytesin' => gettext('Bytes In'),
|
||||
'bytesout' => gettext('Bytes Out'),
|
||||
'packetsin' => gettext('Packets In'),
|
||||
'packetsout' => gettext('Packets Out'),
|
||||
'errorsin' => gettext('Errors In'),
|
||||
'errorsout' => gettext('Errors Out'),
|
||||
'collisions' => gettext('Collisions'),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
177
src/opnsense/www/js/widgets/InterfaceStatistics.js
Normal file
177
src/opnsense/www/js/widgets/InterfaceStatistics.js
Normal file
@ -0,0 +1,177 @@
|
||||
// endpoint:/api/diagnostics/traffic/interface
|
||||
|
||||
/**
|
||||
* Copyright (C) 2024 Deciso B.V.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
import BaseWidget from "./BaseWidget.js";
|
||||
|
||||
export default class InterfaceStatistics extends BaseWidget {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.chart = null;
|
||||
this.labels = [];
|
||||
this.rawData = {};
|
||||
this.dataset = {};
|
||||
}
|
||||
|
||||
getMarkup() {
|
||||
return $(`
|
||||
<div class="interface-statistics-chart-container">
|
||||
<div class="canvas-container">
|
||||
<canvas id="intf-stats"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
`);
|
||||
}
|
||||
|
||||
_setAlpha(color, opacity) {
|
||||
const op = Math.round(Math.min(Math.max(opacity || 1, 0), 1) * 255);
|
||||
return color + op.toString(16).toUpperCase();
|
||||
}
|
||||
|
||||
_getIndexedData(data) {
|
||||
let indexedData = Array(this.labels.length).fill(null);
|
||||
let indexedColors = Array(this.labels.length).fill(null);
|
||||
for (const item in data) {
|
||||
let obj = data[item];
|
||||
let idx = this.labels.indexOf(obj.name);
|
||||
indexedData[idx] = obj.data;
|
||||
indexedColors[idx] = obj.color;
|
||||
}
|
||||
return {
|
||||
data: indexedData,
|
||||
colors: indexedColors
|
||||
};
|
||||
}
|
||||
|
||||
async onWidgetTick() {
|
||||
ajaxGet('/api/diagnostics/traffic/interface', {}, (data, status) => {
|
||||
let i = 0;
|
||||
let colors = Chart.colorschemes.tableau.Classic10;
|
||||
for (const intf in data.interfaces) {
|
||||
const obj = data.interfaces[intf];
|
||||
this.labels.indexOf(obj.name) === -1 && this.labels.push(obj.name);
|
||||
obj.data = parseInt(obj["packets received"]) + parseInt(obj["packets transmitted"]);
|
||||
obj.color = colors[i % colors.length]
|
||||
this.rawData[obj.name] = obj;
|
||||
i++;
|
||||
}
|
||||
|
||||
let formattedData = this._getIndexedData(data.interfaces);
|
||||
this.dataset = {
|
||||
label: 'statistics',
|
||||
data: formattedData.data,
|
||||
backgroundColor: formattedData.colors,
|
||||
hoverBackgroundColor: formattedData.colors.map((color) => this._setAlpha(color, 0.5)),
|
||||
fill: true,
|
||||
borderWidth: 2,
|
||||
hoverOffset: 10,
|
||||
}
|
||||
|
||||
if (this.chart.config.data.datasets.length > 0) {
|
||||
this.chart.config.data.datasets[0].data = this.dataset.data;
|
||||
} else {
|
||||
this.chart.config.data.labels = this.labels;
|
||||
this.chart.config.data.datasets.push(this.dataset);
|
||||
}
|
||||
|
||||
this.chart.update();
|
||||
});
|
||||
}
|
||||
|
||||
async onMarkupRendered() {
|
||||
let context = $(`#intf-stats`)[0].getContext('2d');
|
||||
|
||||
let config = {
|
||||
type: 'doughnut',
|
||||
data: {
|
||||
labels: [],
|
||||
datasets: []
|
||||
},
|
||||
options: {
|
||||
cutout: '40%',
|
||||
maintainAspectRatio: true,
|
||||
responsive: true,
|
||||
aspectRatio: 2,
|
||||
layout: {
|
||||
padding: 10
|
||||
},
|
||||
parsing: false,
|
||||
plugins: {
|
||||
legend: {
|
||||
display: false,
|
||||
position: 'left',
|
||||
title: 'Traffic',
|
||||
onHover: (event, legendItem) => {
|
||||
const activeElement = {
|
||||
datasetIndex: 0,
|
||||
index: legendItem.index
|
||||
};
|
||||
this.chart.setActiveElements([activeElement]);
|
||||
this.chart.tooltip.setActiveElements([activeElement]);
|
||||
this.chart.update();
|
||||
}
|
||||
},
|
||||
tooltip: {
|
||||
callbacks: {
|
||||
label: (tooltipItem) => {
|
||||
const idx = this.labels.indexOf(tooltipItem.label);
|
||||
let obj = this.rawData[tooltipItem.label];
|
||||
let result = [
|
||||
`${tooltipItem.label}`,
|
||||
`${this.translations.bytesin}: ${obj["bytes received"]}`,
|
||||
`${this.translations.bytesout}: ${obj["bytes transmitted"]}`,
|
||||
`${this.translations.packetsin}: ${obj["packets received"]}`,
|
||||
`${this.translations.packetsout}: ${obj["packets transmitted"]}`,
|
||||
`${this.translations.errorsin}: ${obj["input errors"]}`,
|
||||
`${this.translations.errorsout}: ${obj["output errors"]}`,
|
||||
`${this.translations.collisions}: ${obj["collisions"]}`,
|
||||
];
|
||||
return result;
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.chart = new Chart(context, config);
|
||||
}
|
||||
|
||||
onWidgetResize(elem, width, height) {
|
||||
if (this.chart !== null) {
|
||||
if (width > 450) {
|
||||
this.chart.options.plugins.legend.display = true;
|
||||
} else {
|
||||
this.chart.options.plugins.legend.display = false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user