mirror of
https://github.com/lucaspalomodevelop/core.git
synced 2026-03-18 18:44:44 +00:00
dashboard: add CPU Usage widget
Also allow for each widget to override the resize handles in case they should be more restrictive in terms of dimensions.
This commit is contained in:
parent
af459fff31
commit
1d593fe984
1
plist
1
plist
@ -1913,6 +1913,7 @@
|
||||
/usr/local/opnsense/www/js/tree.jquery.min.js
|
||||
/usr/local/opnsense/www/js/widgets/BaseTableWidget.js
|
||||
/usr/local/opnsense/www/js/widgets/BaseWidget.js
|
||||
/usr/local/opnsense/www/js/widgets/Cpu.js
|
||||
/usr/local/opnsense/www/js/widgets/Interfaces.js
|
||||
/usr/local/opnsense/www/themes/opnsense/LICENSE
|
||||
/usr/local/opnsense/www/themes/opnsense/assets/fonts/SourceSansPro-Bold/SourceSansPro-Bold.eot
|
||||
|
||||
@ -37,6 +37,7 @@
|
||||
|
||||
<script src="{{ cache_safe('/ui/js/chart.min.js') }}"></script>
|
||||
<script src="{{ cache_safe('/ui/js/chartjs-plugin-colorschemes.js') }}"></script>
|
||||
<script src="{{ cache_safe('/ui/js/smoothie.js') }}"></script>
|
||||
|
||||
<script>
|
||||
$( document ).ready(function() {
|
||||
@ -47,7 +48,7 @@ $( document ).ready(function() {
|
||||
alwaysShowResizeHandle: false,
|
||||
sizeToContent: true,
|
||||
resizable: {
|
||||
handles: 'e, w'
|
||||
handles: 'all'
|
||||
}
|
||||
}, {
|
||||
'save': "{{ lang._('Save') }}",
|
||||
|
||||
@ -32,6 +32,8 @@
|
||||
import subprocess
|
||||
import select
|
||||
import argparse
|
||||
import ujson
|
||||
import re
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser()
|
||||
@ -53,8 +55,20 @@ if __name__ == '__main__':
|
||||
|
||||
if data:
|
||||
output = data.decode().strip()
|
||||
if not (output.startswith("tty") or output.startswith("tin")):
|
||||
print(f"event: message\ndata: {output}\n\n", flush=True)
|
||||
if output.startswith("tty") or output.startswith("tin"):
|
||||
continue
|
||||
|
||||
formatted = re.sub(r'\s+', ' ', output).split(" ")[2:]
|
||||
formatted = [int(x) for x in formatted]
|
||||
result = {
|
||||
'total': sum(formatted) - formatted[4],
|
||||
'user': formatted[0],
|
||||
'nice': formatted[1],
|
||||
'sys': formatted[2],
|
||||
'intr': formatted[3],
|
||||
'idle': formatted[4]
|
||||
}
|
||||
print(f"event: message\ndata: {ujson.dumps(result)}\n\n", flush=True)
|
||||
else:
|
||||
read_fds.remove(fd)
|
||||
|
||||
|
||||
@ -74,6 +74,11 @@ td {
|
||||
}
|
||||
|
||||
.canvas-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.smoothie-container {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
||||
@ -316,6 +316,12 @@ class WidgetManager {
|
||||
await onMarkupRendered();
|
||||
$(`.spinner-${widget.id}`).remove();
|
||||
|
||||
// XXX this code enforces per-widget resize handle definitions, which isn't natively
|
||||
// supported by GridStack.
|
||||
$(this.widgetHTMLElements[widget.id]).attr('gs-resize-handles', widget.getResizeHandles());
|
||||
this.widgetHTMLElements[widget.id].gridstackNode._initDD = false;
|
||||
this.grid.resizable(this.widgetHTMLElements[widget.id], true);
|
||||
|
||||
// second: start the widget-specific tick routine
|
||||
let onWidgetTick = widget.onWidgetTick.bind(widget);
|
||||
await onWidgetTick();
|
||||
|
||||
@ -4,6 +4,11 @@ export default class BaseWidget {
|
||||
this.title = "";
|
||||
this.id = null;
|
||||
this.tickTimeout = 5000; // Default tick timeout
|
||||
this.resizeHandles = "all"
|
||||
}
|
||||
|
||||
getResizeHandles() {
|
||||
return this.resizeHandles;
|
||||
}
|
||||
|
||||
setId(id) {
|
||||
|
||||
126
src/opnsense/www/js/widgets/Cpu.js
Normal file
126
src/opnsense/www/js/widgets/Cpu.js
Normal file
@ -0,0 +1,126 @@
|
||||
// endpoint:/api/diagnostics/cpu_usage/*
|
||||
|
||||
/**
|
||||
* 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 Cpu extends BaseWidget {
|
||||
constructor() {
|
||||
super();
|
||||
this.title = 'CPU Usage';
|
||||
this.resizeHandles = "e, w";
|
||||
}
|
||||
|
||||
_createChart(selector, timeSeries) {
|
||||
let smoothie = new SmoothieChart({
|
||||
responsive: true,
|
||||
millisPerPixel:50,
|
||||
tooltip: true,
|
||||
labels: {
|
||||
fillStyle: '#000000',
|
||||
precision: 0,
|
||||
fontSize: 11
|
||||
},
|
||||
grid: {
|
||||
strokeStyle:'rgba(119,119,119,0.12)',
|
||||
verticalSections:4,
|
||||
millisPerLine:1000,
|
||||
fillStyle: 'transparent'
|
||||
}
|
||||
});
|
||||
|
||||
smoothie.streamTo(document.getElementById(selector), 1000);
|
||||
smoothie.addTimeSeries(timeSeries, {
|
||||
lineWidth: 3,
|
||||
strokeStyle: '#d94f00'
|
||||
});
|
||||
}
|
||||
|
||||
getMarkup() {
|
||||
let $container = $(`
|
||||
<div class="canvas-container">
|
||||
<div class="smoothie-container">
|
||||
<b>Total</b>
|
||||
<div><canvas id="cpu-usage" style="width: 80%; height: 50px;"></canvas></div>
|
||||
</div>
|
||||
<div class="smoothie-container">
|
||||
<b>Interrupt</b>
|
||||
<div><canvas id="cpu-usage-intr" style="width: 80%; height: 50px;"></canvas></div>
|
||||
</div>
|
||||
<div class="smoothie-container">
|
||||
<b>User</b>
|
||||
<div><canvas id="cpu-usage-user" style="width: 80%; height: 50px;"></canvas></div>
|
||||
</div>
|
||||
<div class="smoothie-container">
|
||||
<b>System</b>
|
||||
<div><canvas id="cpu-usage-sys" style="width: 80%; height: 50px;"></canvas></div>
|
||||
</div>
|
||||
</div>`);
|
||||
|
||||
return $container;
|
||||
}
|
||||
|
||||
async onMarkupRendered() {
|
||||
let total_ts = new TimeSeries();
|
||||
let intr_ts = new TimeSeries();
|
||||
let user_ts = new TimeSeries();
|
||||
let sys_ts = new TimeSeries();
|
||||
this._createChart('cpu-usage', total_ts);
|
||||
this._createChart('cpu-usage-intr', intr_ts);
|
||||
this._createChart('cpu-usage-user', user_ts);
|
||||
this._createChart('cpu-usage-sys', sys_ts);
|
||||
const eventSource = new EventSource('/api/diagnostics/cpu_usage/stream');
|
||||
|
||||
eventSource.onmessage = function(event) {
|
||||
if (!event) {
|
||||
eventSource.close();
|
||||
}
|
||||
const data = JSON.parse(event.data);
|
||||
let date = Date.now();
|
||||
total_ts.append(date, data.total);
|
||||
intr_ts.append(date, data.intr);
|
||||
user_ts.append(date, data.user);
|
||||
sys_ts.append(date, data.sys);
|
||||
}
|
||||
|
||||
eventSource.onerror = function(event) {
|
||||
eventSource.close();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
onWidgetResize(elem, width, height) {
|
||||
let curWidth = document.getElementById('cpu-usage').getBoundingClientRect().width;
|
||||
let viewPort = document.getElementsByClassName('page-content-main')[0].getBoundingClientRect().width;
|
||||
if (width > (viewPort / 2)) {
|
||||
$('.canvas-container').css('flex-direction', 'row');
|
||||
} else {
|
||||
$('.canvas-container').css('flex-direction', 'column');
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -33,6 +33,7 @@ export default class Interfaces extends BaseTableWidget {
|
||||
constructor() {
|
||||
super();
|
||||
this.title = "Interfaces";
|
||||
this.resizeHandles = "e, w";
|
||||
}
|
||||
|
||||
getGridOptions() {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user