fixes and improvements
This commit is contained in:
@@ -44,7 +44,32 @@ def get_monitoring_overview(
|
|||||||
) -> dict[str, Any]:
|
) -> dict[str, Any]:
|
||||||
"""Return one lightweight monitoring row per configured machine."""
|
"""Return one lightweight monitoring row per configured machine."""
|
||||||
machines = store.list_machines()
|
machines = store.list_machines()
|
||||||
rows = [collect_machine_overview(machine, store) for machine in machines]
|
rows: list[dict[str, Any]] = []
|
||||||
|
for machine in machines:
|
||||||
|
try:
|
||||||
|
rows.append(collect_machine_overview(machine, store))
|
||||||
|
except Exception as exc:
|
||||||
|
logger.exception(
|
||||||
|
"Dashboard monitoring overview failed for machine_id=%s",
|
||||||
|
machine.get("id"),
|
||||||
|
)
|
||||||
|
rows.append({
|
||||||
|
"machine": {k: machine.get(k) for k in ("id", "name", "mode", "enabled", "host", "port", "username", "media_root", "path_prefix", "notes")},
|
||||||
|
"status": "",
|
||||||
|
"status_error": str(exc),
|
||||||
|
"metrics_error": str(exc),
|
||||||
|
"disk_error": str(exc),
|
||||||
|
"sample_count": 0,
|
||||||
|
"latest_sample": None,
|
||||||
|
"cpu_summary": None,
|
||||||
|
"iowait_summary": None,
|
||||||
|
"mem_summary": None,
|
||||||
|
"net_rx_summary": None,
|
||||||
|
"net_tx_summary": None,
|
||||||
|
"disk_read_summary": None,
|
||||||
|
"disk_write_summary": None,
|
||||||
|
"disk": None,
|
||||||
|
})
|
||||||
poller = get_monitoring_poller().snapshot()
|
poller = get_monitoring_poller().snapshot()
|
||||||
enabled_count = sum(1 for machine in machines if machine.get("enabled"))
|
enabled_count = sum(1 for machine in machines if machine.get("enabled"))
|
||||||
logger.info("Dashboard monitoring machines=%s enabled=%s", len(machines), enabled_count)
|
logger.info("Dashboard monitoring machines=%s enabled=%s", len(machines), enabled_count)
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import {
|
|||||||
TableHead,
|
TableHead,
|
||||||
TableRow,
|
TableRow,
|
||||||
TableSortLabel,
|
TableSortLabel,
|
||||||
|
Tooltip,
|
||||||
Typography,
|
Typography,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import type {
|
import type {
|
||||||
@@ -102,6 +103,19 @@ function sortableText(value: string) {
|
|||||||
return value.toLowerCase();
|
return value.toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getStatusChipProps(row: MonitoringMachineOverview) {
|
||||||
|
if (row.status_error) {
|
||||||
|
return { color: "error" as const, label: row.status_error };
|
||||||
|
}
|
||||||
|
if (row.status === "running") {
|
||||||
|
return { color: "success" as const, label: "running" };
|
||||||
|
}
|
||||||
|
if (row.status === "not running") {
|
||||||
|
return { color: "warning" as const, label: "not running" };
|
||||||
|
}
|
||||||
|
return { color: "default" as const, label: row.status || "-" };
|
||||||
|
}
|
||||||
|
|
||||||
function metricSortValue(
|
function metricSortValue(
|
||||||
row: MonitoringMachineOverview,
|
row: MonitoringMachineOverview,
|
||||||
key: SortKey,
|
key: SortKey,
|
||||||
@@ -136,6 +150,34 @@ function metricSortValue(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function NoDataCell() {
|
||||||
|
return (
|
||||||
|
<Stack
|
||||||
|
sx={{
|
||||||
|
width: "100%",
|
||||||
|
minWidth: 0,
|
||||||
|
height: "100%",
|
||||||
|
minHeight: 118,
|
||||||
|
textAlign: "center",
|
||||||
|
justifyContent: "center",
|
||||||
|
py: 0.5,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography
|
||||||
|
variant="caption"
|
||||||
|
color="text.secondary"
|
||||||
|
sx={{
|
||||||
|
fontSize: "0.7rem",
|
||||||
|
fontStyle: "italic",
|
||||||
|
lineHeight: 1.2,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
No data
|
||||||
|
</Typography>
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function MetricCell({
|
function MetricCell({
|
||||||
value,
|
value,
|
||||||
min,
|
min,
|
||||||
@@ -441,7 +483,7 @@ export function MonitoringOverviewTable({
|
|||||||
) : (
|
) : (
|
||||||
sortedRows.map((row) => {
|
sortedRows.map((row) => {
|
||||||
const machine = row.machine;
|
const machine = row.machine;
|
||||||
const status = row.status || row.status_error || "-";
|
const hasMetrics = row.sample_count > 0;
|
||||||
const cpu = formatSummary(
|
const cpu = formatSummary(
|
||||||
row.cpu_summary,
|
row.cpu_summary,
|
||||||
(value) => `${value.toFixed(1)}%`,
|
(value) => `${value.toFixed(1)}%`,
|
||||||
@@ -524,62 +566,106 @@ export function MonitoringOverviewTable({
|
|||||||
</Stack>
|
</Stack>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell sx={{ width: 90 }}>{machine.mode}</TableCell>
|
<TableCell sx={{ width: 90 }}>{machine.mode}</TableCell>
|
||||||
<TableCell sx={{ width: 120 }}>
|
<TableCell sx={{ width: 120 }}>
|
||||||
|
{(() => {
|
||||||
|
const chip = getStatusChipProps(row);
|
||||||
|
return (
|
||||||
|
<Tooltip
|
||||||
|
title={
|
||||||
|
row.metrics_error
|
||||||
|
? `Metrics: ${row.metrics_error}`
|
||||||
|
: row.sample_count === 0
|
||||||
|
? "No metrics collected yet. Start the collector to begin monitoring."
|
||||||
|
: ""
|
||||||
|
}
|
||||||
|
arrow
|
||||||
|
>
|
||||||
<Chip
|
<Chip
|
||||||
size="small"
|
size="small"
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
color={row.status_error ? "error" : "success"}
|
color={chip.color}
|
||||||
label={status}
|
label={chip.label}
|
||||||
/>
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
|
})()}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell align="center">
|
||||||
|
{hasMetrics ? (
|
||||||
|
<MetricCell
|
||||||
|
value={cpu.value}
|
||||||
|
min={cpu.min}
|
||||||
|
max={cpu.max}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<NoDataCell />
|
||||||
|
)}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell align="center">
|
<TableCell align="center">
|
||||||
<MetricCell
|
{hasMetrics ? (
|
||||||
value={cpu.value}
|
<MetricCell
|
||||||
min={cpu.min}
|
value={iowait.value}
|
||||||
max={cpu.max}
|
min={iowait.min}
|
||||||
/>
|
max={iowait.max}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<NoDataCell />
|
||||||
|
)}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell align="center">
|
<TableCell align="center">
|
||||||
<MetricCell
|
{hasMetrics ? (
|
||||||
value={iowait.value}
|
<MetricCell
|
||||||
min={iowait.min}
|
value={mem.value}
|
||||||
max={iowait.max}
|
min={mem.min}
|
||||||
/>
|
max={mem.max}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<NoDataCell />
|
||||||
|
)}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell align="center">
|
<TableCell align="center">
|
||||||
<MetricCell
|
{hasMetrics ? (
|
||||||
value={mem.value}
|
<MetricCell
|
||||||
min={mem.min}
|
value={netDown.value}
|
||||||
max={mem.max}
|
min={netDown.min}
|
||||||
/>
|
max={netDown.max}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<NoDataCell />
|
||||||
|
)}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell align="center">
|
<TableCell align="center">
|
||||||
<MetricCell
|
{hasMetrics ? (
|
||||||
value={netDown.value}
|
<MetricCell
|
||||||
min={netDown.min}
|
value={netUp.value}
|
||||||
max={netDown.max}
|
min={netUp.min}
|
||||||
/>
|
max={netUp.max}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<NoDataCell />
|
||||||
|
)}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell align="center">
|
<TableCell align="center">
|
||||||
<MetricCell
|
{hasMetrics ? (
|
||||||
value={netUp.value}
|
<MetricCell
|
||||||
min={netUp.min}
|
value={diskRead.value}
|
||||||
max={netUp.max}
|
min={diskRead.min}
|
||||||
/>
|
max={diskRead.max}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<NoDataCell />
|
||||||
|
)}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell align="center">
|
<TableCell align="center">
|
||||||
<MetricCell
|
{hasMetrics ? (
|
||||||
value={diskRead.value}
|
<MetricCell
|
||||||
min={diskRead.min}
|
value={diskWrite.value}
|
||||||
max={diskRead.max}
|
min={diskWrite.min}
|
||||||
/>
|
max={diskWrite.max}
|
||||||
</TableCell>
|
/>
|
||||||
<TableCell align="center">
|
) : (
|
||||||
<MetricCell
|
<NoDataCell />
|
||||||
value={diskWrite.value}
|
)}
|
||||||
min={diskWrite.min}
|
|
||||||
max={diskWrite.max}
|
|
||||||
/>
|
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell align="center">
|
<TableCell align="center">
|
||||||
{disk ? (
|
{disk ? (
|
||||||
@@ -588,22 +674,34 @@ export function MonitoringOverviewTable({
|
|||||||
min={disk.min}
|
min={disk.min}
|
||||||
max={disk.max}
|
max={disk.max}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : hasMetrics ? (
|
||||||
"-"
|
"-"
|
||||||
|
) : (
|
||||||
|
<NoDataCell />
|
||||||
)}
|
)}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell sx={{ width: 180 }}>
|
<TableCell sx={{ width: 180 }}>
|
||||||
<Stack spacing={0.1} sx={{ alignItems: "center" }}>
|
<Stack spacing={0.1} sx={{ alignItems: "center" }}>
|
||||||
{updated.map((line) => (
|
{hasMetrics ? (
|
||||||
|
updated.map((line) => (
|
||||||
|
<Typography
|
||||||
|
key={line}
|
||||||
|
variant="caption"
|
||||||
|
color="text.secondary"
|
||||||
|
sx={{ lineHeight: 1.1 }}
|
||||||
|
>
|
||||||
|
{line}
|
||||||
|
</Typography>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
<Typography
|
<Typography
|
||||||
key={line}
|
|
||||||
variant="caption"
|
variant="caption"
|
||||||
color="text.secondary"
|
color="text.secondary"
|
||||||
sx={{ lineHeight: 1.1 }}
|
sx={{ lineHeight: 1.1, fontStyle: "italic" }}
|
||||||
>
|
>
|
||||||
{line}
|
No data yet
|
||||||
</Typography>
|
</Typography>
|
||||||
))}
|
)}
|
||||||
</Stack>
|
</Stack>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
|
|||||||
Reference in New Issue
Block a user