Added some monitoring widgets and scripts

This commit is contained in:
2022-07-06 18:46:02 +02:00
parent d4b9dee6d9
commit 8e86943b83
16 changed files with 308 additions and 78 deletions
+6 -2
View File
@@ -1,9 +1,13 @@
import { MessageWidget } from './MessageWidget.jsx'
import { PieChartWidget } from './PieChartWidget.jsx'
import { DiskUsage } from './widgets/DiskUsage.jsx'
import { MessageWidget } from './widgets/MessageWidget.jsx'
import { PieChartWidget } from './widgets/PieChartWidget.jsx'
import { ScriptStatus } from './widgets/ScriptStatus.jsx'
const WidgetTypes = {
pie: PieChartWidget,
message: MessageWidget,
'script-status': ScriptStatus,
'disk-usage': DiskUsage,
}
export const Widget = ({ type, value }) => {
@@ -1,13 +1,9 @@
import { useEffect, useRef } from 'preact/hooks'
import { hashCode } from '../util.jsx'
const CANVAS_SIZE = 350
export const PieChartWidget = ({ title, parts, labels, total }) => {
title = title || 'Grafico a torta'
import { hashCode } from '../../util.jsx'
export const PieChart = ({ parts, labels, total }) => {
parts = parts || [1]
labels = labels || []
labels = labels || parts
const canvasRef = useRef()
@@ -33,7 +29,7 @@ export const PieChartWidget = ({ title, parts, labels, total }) => {
g.scale(2, 2)
g.translate(width / 2, height / 2)
g.font = `18px 'Open Sans'`
g.font = `16px 'Open Sans'`
g.textAlign = 'center'
g.textBaseline = 'middle'
@@ -62,13 +58,14 @@ export const PieChartWidget = ({ title, parts, labels, total }) => {
g.beginPath()
g.moveTo(0, 0)
g.arc(0, 0, width * 0.5 * 0.8, acc - 0.5 * Math.PI, acc + angle - 0.5 * Math.PI)
g.lineTo(0, 0)
g.stroke()
g.fillStyle = '#333'
g.fillText(
label,
Math.cos(acc + angle / 2 - 0.5 * Math.PI) * width * 0.5 * 0.9,
Math.sin(acc + angle / 2 - 0.5 * Math.PI) * width * 0.5 * 0.9
Math.cos(acc + angle / 2 - 0.5 * Math.PI) * width * 0.5 * 0.9125,
Math.sin(acc + angle / 2 - 0.5 * Math.PI) * width * 0.5 * 0.9125
)
acc += angle
@@ -76,12 +73,5 @@ export const PieChartWidget = ({ title, parts, labels, total }) => {
}
}, [canvasRef, parts])
return (
<>
<div class="title">{title}</div>
<div class="content">
<canvas ref={canvasRef}></canvas>
</div>
</>
)
return <canvas ref={canvasRef}></canvas>
}
@@ -0,0 +1,52 @@
import { byteSizeToString, useRemoteState } from '../../util.jsx'
import { PieChart } from '../charts/PieChart.jsx'
import { Icon } from '../Icon.jsx'
import { ToastMessage, useToasts } from '../Toasts.jsx'
export const DiskUsage = ({ disk }) => {
const [showToast] = useToasts()
const [output, err, refreshOutput] = useRemoteState(
`/api/monitor/status?script=${encodeURIComponent(`disk-usage ${disk}`)}`,
'100\n0'
)
const [total, used] = output.split('\n').map(s => parseInt(s))
const title = (
<>
Spazio Utilizzato &bull; <code>{disk}</code>
</>
)
return (
<>
<div class="title">
<div class="row">
<div class="row-group">
<p>{title}</p>
</div>
<div class="row-group">
<button
class="icon"
onClick={() => {
refreshOutput()
showToast(
<ToastMessage icon="info">Aggiornato "{title}"</ToastMessage>
)
}}
>
<Icon name="refresh" />
</button>
</div>
</div>
</div>
<div class="content">
{err ? (
<p>Errore "{err}"</p>
) : (
<PieChart parts={[used]} labels={[byteSizeToString(used)]} total={total} />
)}
</div>
</>
)
}
@@ -0,0 +1,14 @@
import { PieChart } from '../charts/PieChart.jsx'
export const PieChartWidget = ({ title, ...chart }) => {
title = title || 'Grafico a torta'
return (
<>
<div class="title">{title}</div>
<div class="content">
<PieChart {...chart} />
</div>
</>
)
}
@@ -0,0 +1,43 @@
import { useRemoteState } from '../../util.jsx'
import { Icon } from '../Icon.jsx'
import { ToastMessage, useToasts } from '../Toasts.jsx'
export const ScriptStatus = ({ title, script }) => {
const [showToast] = useToasts()
const [output, err, refreshOutput] = useRemoteState(
`/api/monitor/status?script=${encodeURIComponent(script)}`,
''
)
return (
<>
<div class="title">
<div class="row">
<div class="row-group">{title}</div>
<div class="row-group">
<button
class="icon"
onClick={() => {
refreshOutput()
showToast(
<ToastMessage icon="info">Aggiornato "{title}"</ToastMessage>
)
}}
>
<Icon name="refresh" />
</button>
</div>
</div>
</div>
<div class="content">
{err ? (
<p>Errore "{err}"</p>
) : (
<pre>
<code>{output}</code>
</pre>
)}
</div>
</>
)
}
+21
View File
@@ -137,3 +137,24 @@ const toCaseMap = {
export function changeCase(from, to, s) {
return toCaseMap[to](fromCaseMap[from](s))
}
//
// Disk space conversions
//
const byteUnits = {
K: 1024,
M: 1024 ** 2,
G: 1024 ** 3,
T: 1024 ** 4,
}
export function byteSizeToString(size) {
let i = 0
while (size >= 450) {
size /= 1024
i++
}
return `${size.toFixed(2)}${Object.keys(byteUnits)[i]}B`
}