Add new beta 1.2.2.1

This commit is contained in:
MacRimi
2026-06-05 19:45:46 +02:00
parent 3191f5250d
commit d401e5f7de
7 changed files with 75 additions and 20 deletions

View File

@@ -1 +1 @@
e0128ac327ea74b645b37bcfab03aa744f067a355f9960a822b411c6ac75cb02 ProxMenux-1.2.2.AppImage
8ea86a03ea86d45050d4e24e6432e022f76d805eeaaeeab3ee376ebaa48da52a ProxMenux-1.2.2.1-beta.AppImage

View File

@@ -1,9 +1,9 @@
"use client"
import { useEffect, useState } from "react"
import { useEffect, useRef, useState } from "react"
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from "./ui/dialog"
import { ScrollArea } from "./ui/scroll-area"
import { Activity, FileText, HardDrive, Clock } from "lucide-react"
import { Activity, FileText, HardDrive, Clock, Info } from "lucide-react"
import { fetchApi } from "@/lib/api-config"
interface ProcessDetail {
@@ -78,8 +78,17 @@ export function ProcessInfoModal({ pid, accent, onClose }: ProcessInfoModalProps
const [data, setData] = useState<ProcessDetail | null>(null)
const [error, setError] = useState<string | null>(null)
const [loading, setLoading] = useState(false)
const [exited, setExited] = useState(false)
const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null)
const open = pid != null
const stopPolling = () => {
if (intervalRef.current) {
clearInterval(intervalRef.current)
intervalRef.current = null
}
}
const fetchDetail = async (silent = false) => {
if (pid == null) return
if (!silent) setLoading(true)
@@ -88,11 +97,16 @@ export function ProcessInfoModal({ pid, accent, onClose }: ProcessInfoModalProps
const res = await fetchApi<ProcessDetail>(`/api/processes/${pid}`)
setData(res)
} catch (e: any) {
// 404 means the process exited while the modal was open — surface a
// clear message instead of stale data, but don't auto-close (user may
// want to read the last snapshot).
setError(e?.message?.includes("404") ? "Process exited" : (e?.message || "Failed to fetch process"))
if (e?.message?.includes("404")) setData(null)
// 404 = the process exited while the modal was open. Expected for
// short-lived helpers (pct exec, backup subprocesses, the `ps` snapshot
// itself). Keep the last good snapshot on screen, stop polling, and
// surface an info banner — NOT an error — so it doesn't look like a bug.
if (e?.message?.includes("404")) {
setExited(true)
stopPolling()
} else {
setError(e?.message || "Failed to fetch process")
}
} finally {
if (!silent) setLoading(false)
}
@@ -102,11 +116,14 @@ export function ProcessInfoModal({ pid, accent, onClose }: ProcessInfoModalProps
if (pid == null) {
setData(null)
setError(null)
setExited(false)
stopPolling()
return
}
setExited(false)
fetchDetail()
const id = setInterval(() => fetchDetail(true), REFRESH_MS)
return () => clearInterval(id)
intervalRef.current = setInterval(() => fetchDetail(true), REFRESH_MS)
return () => stopPolling()
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [pid])
@@ -123,10 +140,28 @@ export function ProcessInfoModal({ pid, accent, onClose }: ProcessInfoModalProps
<span className="text-xs text-muted-foreground font-mono flex-shrink-0">PID {pid}</span>
</DialogTitle>
<DialogDescription className="text-xs">
Live snapshot from <span className="font-mono">/proc/{pid}</span>. Auto-refreshes every {REFRESH_MS / 1000} s while open.
{exited ? (
<>Last snapshot from <span className="font-mono">/proc/{pid}</span> before the process finished.</>
) : (
<>Live snapshot from <span className="font-mono">/proc/{pid}</span>. Auto-refreshes every {REFRESH_MS / 1000} s while open.</>
)}
</DialogDescription>
</DialogHeader>
{/* Info banner when the process has finished. Amber, not red — this is
expected behavior for short-lived processes, not an error. */}
{exited && (
<div className="flex items-start gap-2 px-3 py-2 rounded-md border border-amber-500/30 bg-amber-500/10 text-xs text-amber-300">
<Info className="h-4 w-4 flex-shrink-0 mt-0.5" />
<div>
<div className="font-medium text-amber-200">This process has finished</div>
<div className="text-amber-300/80 mt-0.5">
It was likely a short-lived helper (a script, a <span className="font-mono">pct exec</span>, or a one-shot command) that completed while the modal was open. The data below is the last snapshot captured before it exited not a stale or broken read.
</div>
</div>
</div>
)}
{error && !data ? (
<div className="text-sm text-red-500 py-4">{error}</div>
) : !data ? (
@@ -134,11 +169,11 @@ export function ProcessInfoModal({ pid, accent, onClose }: ProcessInfoModalProps
{loading ? "Loading…" : "—"}
</div>
) : (
<ScrollArea className="max-h-[480px] pr-2">
<ScrollArea className={`max-h-[480px] pr-2 ${exited ? "opacity-75" : ""}`}>
<div className="space-y-4">
{/* Overview */}
<Section icon={<Activity className="h-4 w-4 text-blue-400" />} title="Overview">
<Row label="State" value={stateLabel(data.state)} />
<Row label="State" value={exited ? "Exited" : stateLabel(data.state)} />
<Row label="Parent" value={data.parent_name ? `${data.parent_name} (PID ${data.ppid})` : `PID ${data.ppid}`} mono />
<Row label="Threads" value={String(data.threads)} mono />
<Row label="Open FDs" value={data.fd_count != null ? String(data.fd_count) : "—"} mono />
@@ -176,7 +211,7 @@ export function ProcessInfoModal({ pid, accent, onClose }: ProcessInfoModalProps
{data?.captured_at && (
<div className="text-[10px] text-muted-foreground text-right mt-1">
Captured {new Date(data.captured_at * 1000).toLocaleTimeString()}
{exited ? "Last seen" : "Captured"} {new Date(data.captured_at * 1000).toLocaleTimeString()}
{error ? ` · ${error}` : ""}
</div>
)}

View File

@@ -216,17 +216,37 @@ export const CHANGELOG: Record<string, ReleaseNote> = {
}
const CURRENT_VERSION_FEATURES = [
{
icon: <Sliders className="h-5 w-5" />,
text: "Dashboard header restyle - The Overview, Storage, Network and VMs & LXCs tabs now lead with a unified card design: circular gauges paired with mini progress bars, and a clearer headline-plus-pill layout for counts. CPU Usage and Memory cards also expose a User / System and Used / Cached breakdown under the gauge",
},
{
icon: <Activity className="h-5 w-5" />,
text: "Header Critical badge now respects dismissals (#228) - Permanently silencing every critical alert in a category used to leave the badge stuck on Critical even though the popup correctly reported 0 critical. The rollup that drives /api/system-info now runs a dismiss-aware pass over every category, so the badge, the popup and any API consumer all see the same view",
text: "Top processes drill-down - Click the CPU Usage or Memory cards on the Overview tab to open a sortable top-25 list of processes by %CPU or RSS, then click any row for a live per-process detail modal with state, command line, resource usage and lifetime",
},
{
icon: <HardDrive className="h-5 w-5" />,
text: "Storage and Network refinements - Storage Used now leads the Storage tab card, Network Status cells stack label-over-value so long hostnames and IPv6 DNS no longer truncate, and the 24 h CPU and Network charts smooth into 5-minute buckets",
},
{
icon: <Cpu className="h-5 w-5" />,
text: "Coral on non-Debian LXCs - The Coral LXC installer now detects Alpine / Arch / RHEL / SUSE containers and offers an opt-in passthrough-only mode, so Frigate Docker and other apps bundling their own libedgetpu runtime can wire the device through without aborting",
},
{
icon: <Wrench className="h-5 w-5" />,
text: "Coral PCIe driver false-positive update fix - The installer now records the upstream feranick release tag on disk, so the update detector compares like-for-like and stops firing a phantom 'driver update available' notification right after a fresh install",
},
{
icon: <RefreshCw className="h-5 w-5" />,
text: "Auto-reconcile of stale alerts - Errors for resources that no longer exist now auto-clear within the regular cleanup cycle. New cases: a PVE storage removed via pvesm, an NFS/CIFS share whose mount target is no longer in /proc/mounts (the lazy-umount case reported in the field), and LXC mount-capacity alerts whose CT has been deleted",
text: "Auto-reconcile of stale alerts - Errors for resources that no longer exist auto-clear within the regular cleanup cycle. New cases: a PVE storage removed via pvesm, an NFS/CIFS share whose mount target is gone from /proc/mounts, and LXC mount-capacity alerts for a deleted CT",
},
{
icon: <Shield className="h-5 w-5" />,
text: "Header Critical badge respects dismissals (#228) - Permanently silencing every critical alert in a category now also clears the top-right badge, so the header pill and the bottom popup always agree on the count",
},
{
icon: <Bell className="h-5 w-5" />,
text: "Notification Send Test buttons unified (#226) - All five channel Send Test buttons (Telegram, Gotify, Discord, Email, Apprise) now sit on the left side and carry their channel's brand colour with white text, instead of Apprise being the right-aligned cyan outlier",
text: "Notification Send Test buttons unified (#226) - All five channel Send Test buttons (Telegram, Gotify, Discord, Email, Apprise) now sit on the left and carry their channel's brand colour, instead of Apprise being the right-aligned cyan outlier",
},
]

View File

@@ -1 +1 @@
1.2.1.4
1.2.2.1

View File

@@ -73,7 +73,7 @@
"<strong>Command</strong> — short name (<code>comm</code>), full command line, executable path and working directory.",
"<strong>Lifetime</strong> — start timestamp and elapsed runtime."
],
"detailRefresh": "The detail modal refreshes every 3 s while open. If the process exits mid-modal the next refresh surfaces <em>Process exited</em> instead of stale data — expected for short-lived helpers like <code>pct exec</code> or backup subprocesses.",
"detailRefresh": "The detail modal refreshes every 3 s while open. If the process exits mid-modal the polling stops, an amber <em>This process has finished</em> banner appears, and the last captured snapshot stays on screen (dimmed) so you can still read what was happening just before it exited — expected for short-lived helpers like <code>pct exec</code>, backup subprocesses or the underlying <code>ps</code> snapshot itself.",
"captureDetailAlt": "Process detail modal — Overview, Resources, Command and Lifetime sections for a single PID",
"captureDetailCaption": "Per-process detail modal opened from a list row. The accent colour matches the card that opened it (blue for CPU, indigo for Memory).",
"sourceTitle": "Where the data comes from",

View File

@@ -73,7 +73,7 @@
"<strong>Command</strong> — nombre corto (<code>comm</code>), línea de comandos completa, ruta del ejecutable y directorio de trabajo.",
"<strong>Lifetime</strong> — timestamp de arranque y tiempo transcurrido en ejecución."
],
"detailRefresh": "La modal de detalle se refresca cada 3 s mientras está abierta. Si el proceso termina con la modal abierta, el siguiente refresco muestra <em>Process exited</em> en vez de datos obsoletos — esperable para procesos efímeros como <code>pct exec</code> o subprocesos de backup.",
"detailRefresh": "La modal de detalle se refresca cada 3 s mientras está abierta. Si el proceso termina con la modal abierta, el polling se detiene, aparece un banner ámbar <em>This process has finished</em> y el último snapshot capturado se queda en pantalla (atenuado) para que sigas viendo qué estaba pasando justo antes de que terminara — esperable para procesos efímeros como <code>pct exec</code>, subprocesos de backup o el propio <code>ps</code> que alimenta la lista.",
"captureDetailAlt": "Modal de detalle de proceso — secciones Overview, Resources, Command y Lifetime para un único PID",
"captureDetailCaption": "Modal de detalle por proceso abierta desde una fila de la lista. El color de acento sigue al de la tarjeta que la abrió (azul para CPU, índigo para Memory).",
"sourceTitle": "De dónde salen los datos",