feat(ui): detailed per-pool block with type, capacity bar, scrub state
This commit is contained in:
parent
612091ff1e
commit
f05c20ed0b
2 changed files with 75 additions and 14 deletions
|
|
@ -66,21 +66,35 @@ defmodule ServerWeb.HostDetailLive do
|
|||
<header><span>ZFS pools</span><span class="mono">{length(pools(@fast))}</span></header>
|
||||
<div class="body tight">
|
||||
<div :if={pools(@fast) == []} class="empty">No data.</div>
|
||||
<div :for={pool <- pools(@fast)} class="pool-row" style="padding: 0.6rem 0.9rem;">
|
||||
<div>
|
||||
<span class="mono" style="color: var(--fg-bright); font-weight: 600;">
|
||||
{pool["name"]}
|
||||
</span>
|
||||
<span class="badge" style={pool_badge_style(pool["health"])}>{pool["health"]}</span>
|
||||
<div class="details">
|
||||
cap {pool["capacity_percent"]}% ·
|
||||
frag {pool["fragmentation_percent"] || 0}% ·
|
||||
err {pool["error_count"] || 0} ·
|
||||
vdevs {pool["vdev_count"] || 0} (deg {pool["degraded_vdev_count"] || 0})
|
||||
<div :for={pool <- pools(@fast)} class="pool-block">
|
||||
<div class="head">
|
||||
<div>
|
||||
<span class="mono" style="color: var(--fg-bright); font-weight: 600;">{pool["name"]}</span>
|
||||
<span class="layout">{pool_layout(pool)}</span>
|
||||
</div>
|
||||
<span class="badge" style={pool_badge_style(pool["health"])}>{pool["health"]}</span>
|
||||
</div>
|
||||
<div class="mono muted" style="font-size: 0.75rem; align-self: center; text-align: right;">
|
||||
scrub<br/>{pool["last_scrub_end"] || "never"}
|
||||
|
||||
<div class="capbar" data-level={capbar_level(pool["capacity_percent"])}>
|
||||
<span style={"width: #{pool["capacity_percent"] || 0}%"}></span>
|
||||
</div>
|
||||
|
||||
<div class="sizes">
|
||||
used {format_bytes(pool["allocated_bytes"] || 0)} ·
|
||||
free {format_bytes(pool["free_bytes"] || 0)} ·
|
||||
total {format_bytes(pool["size_bytes"] || 0)}
|
||||
<span class="muted">({pool["capacity_percent"] || 0}%)</span>
|
||||
</div>
|
||||
|
||||
<div class="details">
|
||||
frag {pool["fragmentation_percent"] || 0}% ·
|
||||
err {pool["error_count"] || 0} ·
|
||||
vdevs {pool["vdev_count"] || 0} (deg {pool["degraded_vdev_count"] || 0}) ·
|
||||
{pool_scrub_line(pool)}
|
||||
</div>
|
||||
|
||||
<div :for={v <- degraded_vdevs(pool)} class="callout err" style="margin-top: 0.4rem;">
|
||||
{v["name"]} {v["state"]} · r={v["read_errors"]} w={v["write_errors"]} cksum={v["checksum_errors"]}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -155,6 +169,34 @@ defmodule ServerWeb.HostDetailLive do
|
|||
defp pool_badge_style("ONLINE"), do: "color: var(--ok);"
|
||||
defp pool_badge_style(_), do: "color: var(--crit);"
|
||||
|
||||
defp pool_layout(pool) do
|
||||
case pool["pool_type"] do
|
||||
nil -> "—"
|
||||
"" -> "—"
|
||||
t -> t
|
||||
end
|
||||
end
|
||||
|
||||
defp capbar_level(cap) when is_number(cap) and cap >= 90, do: "crit"
|
||||
defp capbar_level(cap) when is_number(cap) and cap >= 80, do: "warn"
|
||||
defp capbar_level(_), do: "ok"
|
||||
|
||||
defp pool_scrub_line(%{"scan_state" => "SCANNING"}), do: "scrub scanning"
|
||||
|
||||
defp pool_scrub_line(%{"scan_state" => "FINISHED", "last_scrub_end" => end_time})
|
||||
when is_binary(end_time) and end_time != "",
|
||||
do: "scrub #{end_time}"
|
||||
|
||||
defp pool_scrub_line(%{"last_scrub_end" => end_time}) when is_binary(end_time) and end_time != "",
|
||||
do: "scrub #{end_time}"
|
||||
|
||||
defp pool_scrub_line(_), do: "scrub never"
|
||||
|
||||
defp degraded_vdevs(pool) do
|
||||
(pool["vdevs"] || [])
|
||||
|> Enum.filter(fn v -> Map.get(v, "state") not in [nil, "ONLINE"] end)
|
||||
end
|
||||
|
||||
defp sys_line(nil), do: "—"
|
||||
defp sys_line(%{payload: p}) do
|
||||
get_in(p, ["system_info", "pve_version"]) || "—"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue