Added some monitoring widgets and scripts
This commit is contained in:
@@ -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 }) => {
|
||||
|
||||
+8
-18
@@ -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 • <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>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -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`
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user