mirror of
https://github.com/MacRimi/ProxMenux.git
synced 2026-09-14 18:56:52 +00:00
- **VM/LXC modal** — PVE tags (dots on list cards, editable pills in modal with click-to-edit) using NVIDIA-style hash colour and SAPC contrast; Status tab redesign (single card, always-visible subsections, Edit button, autostart toggle, blue subsection icons); Backups and Firewall tabs now fill the full modal height with sticky headers/notes; stopped VMs no longer shift the metrics grid; mount-point card brightness unified across breakpoints. - **Disks modal** — Overview / SMART / History / Schedule tabs adopt the VM/LXC modal size and the mobile icon-only tab pattern; SMART attributes table drops the 15-row cap and gains a sticky "View full SMART report" footer; Print/Save-as-PDF collapses to two icons in the report; loose i18n and layout follow-ups. - **NVIDIA driver installer (#298)** — version picker cross-checks kernel + NVIDIA's Production/New Feature/Legacy branch classification (scraped from `nvidia.com/en-us/drivers/unix/`) + the PCI Device IDs of every host GPU, with a release-count heuristic to keep superseded production branches selectable while dropping Vulkan-beta ones; Recommended follows same-branch head when a driver is installed, Production Branch head on a fresh install; Hardware card now shows installed alongside available driver version. - **Custom notifications (#297)** — `event_type: "custom"` accepts `title`/`message` at the root or nested under `data`; defensive strip of stray `[TITLE]`/`[BODY]` markers echoed by the AI enhancer. - **App tab** — new "Exclude from the LXC updates counter" toggle; the CT's aggregate updates badge now sums OS packages plus registered apps (respecting the flag); Docs page updated; App suggestion no longer treats bare OS helper slugs (alpine/ubuntu/debian…) as installable apps. - **i18n and copy** — Monitor UI available in EN / ES / DE / FR / IT / PT / SV / SK (thanks @vaso73) surfaced as the first entry in the What's New modal with a link to the contributor's profile; ES cleanup pass (`Historial`, `Velocidad de rotación`, `Consumo actual`, `Ejecutar`, `Eliminar`, `Activar`, `Ver contenido`, `Repuesto disp.`, `Registrar`, `Ocultar`, `Descartar`); redundant "Tip: search any Linux/Proxmox command" line removed from the terminal command search across all locales.
422 lines
36 KiB
TypeScript
422 lines
36 KiB
TypeScript
"use client"
|
|
|
|
import { useState, useEffect } from "react"
|
|
import { Button } from "./ui/button"
|
|
import { Dialog, DialogContent, DialogTitle } from "./ui/dialog"
|
|
import { X, Sparkles, Thermometer, Activity, HardDrive, Shield, Globe, Cpu, Zap, Sliders, Wrench, RefreshCw, Server, BellOff, Bell, Calendar, DatabaseBackup, Smartphone, Languages } from "lucide-react"
|
|
import { Checkbox } from "./ui/checkbox"
|
|
import { useT } from "../lib/i18n/provider"
|
|
|
|
const APP_VERSION = "1.2.4.1-beta" // Sync with AppImage/package.json
|
|
|
|
interface ReleaseNote {
|
|
date: string
|
|
changes: {
|
|
added?: string[]
|
|
changed?: string[]
|
|
fixed?: string[]
|
|
}
|
|
}
|
|
|
|
export const CHANGELOG: Record<string, ReleaseNote> = {
|
|
"1.2.3": {
|
|
date: "July 15, 2026",
|
|
changes: {
|
|
added: [
|
|
"Backups integrated in the Monitor — a new first-class section to create, schedule and restore host backups against Local, PBS or Borg destinations from the Web dashboard. Jobs run on a proper systemd timer or attach to an existing PVE vzdump job with retention live-inherited from the parent. Encrypted PBS backups store a paired recovery blob next to each snapshot so a fresh install can always get the key back. After a reboot the tab shows a real-time restore progress card with milestones, per-component status (NVIDIA, Intel GPU tools, Coral, AMD tools), boot sanity warnings and a rollback delta listing anything on the host that wasn't in the backup.",
|
|
"Network Flow diagram — a new live topology view on the Network tab showing NICs → host → bridges → LXCs / VMs with animated rx / tx pulses on every internal link, so the operator can see in real time how traffic distributes inside the host and which guests are pulling or pushing data.",
|
|
"Physical Disks and Physical Interfaces cards redesigned — clearer per-item presentation on the Storage and Network tabs. USB-NVMe / USB-SATA enclosures reporting removable=0 (ASMedia, JMicron, Realtek, ASM105x) now walk sysfs to detect USB attachment, so the -d snt* pass-through is tried and the drive's real model, serial, temperature, power-on hours and health surface — instead of the bridge's chatter.",
|
|
"Richer notifications out of the box — for users not running an AI agent, the templated body now identifies the affected object (which storage, which interface, which container), surfaces the top offenders with an \"…and N more\" tail when the list is long, and preserves the same identity in the recovery message. Users with AI enrichment enabled continue to get their tailored rewrite on top of this improved base.",
|
|
],
|
|
changed: [
|
|
"Redesigned cards across Overview, VM / LXC, Storage and Network — layouts reworked for faster reading and denser, more practical information: key numbers surface at a glance, grouped by relevance, and the responsive grid now behaves cleanly from a phone up to an ultrawide.",
|
|
"Health Monitor Thresholds — the Settings panel that controls per-category Warning and Critical levels (CPU, memory, temperature, storage, disks, ...) was reworked with clearer visual grouping and inline hints, so tuning a threshold now takes a couple of clicks instead of scrolling through a wall of numbers.",
|
|
],
|
|
},
|
|
},
|
|
"1.2.2": {
|
|
date: "May 31, 2026",
|
|
changes: {
|
|
added: [
|
|
"Health Monitor Thresholds - Per-category Warning and Critical levels for CPU, memory, temperature, storage, disks and more, configurable from Settings. The same numbers also feed the colour ranges of every widget (storage bars, CPU/memory rings, temperature chips), so a colour anywhere in the Monitor maps to a definite range relative to the configured pair",
|
|
"Per-error dismiss duration - The Dismiss button on each Health Monitor alert now opens a small dropdown with three options: 24 hours, 7 days, or Permanently. Permanent dismisses persist with suppression_hours = -1, never re-emit and are marked with a distinct amber Permanent badge so the operator knows the alert is intentionally silenced",
|
|
"Active Suppressions panel in Settings - New section inside Settings -> Health Monitor (below the per-category suppression durations) that lists every currently-dismissed alert, time-limited and permanent. Each row carries the error_key, category, severity, when it was dismissed, plus a Re-enable button gated by Edit mode. Permanent dismisses can only be reverted from here",
|
|
"Apprise notification channel - Full feature parity with native channels: the Apprise tab now exposes the same per-event toggles, Quiet Hours and Daily Digest controls as Telegram / Gotify / Discord / Email. One Apprise URL talks to ~80 notification services (Pushover, ntfy, Slack, Matrix, mailto, signal, ...) without ProxMenux needing a dedicated adapter for each",
|
|
"LXC update detection - New dedicated Settings section with a single toggle that gates the per-CT apt list --upgradable / apk list -u scan end-to-end. The checker now reads the mtime of the CT's package-manager metadata and refreshes it via pct exec if it is older than 24 h, so long-running appliance CTs whose caches were months stale finally surface their real upstream backlog",
|
|
"Disk I/O severity tiers - Sliding 24 h window classifies dmesg ATA / SCSI errors into silent (0-10), WARNING (11-100) and CRITICAL (100+ or any hard error like UNC / Buffer I/O / Sense Key Hardware Error), so quiet days stay quiet and a single Buffer I/O event still pages immediately",
|
|
"Quiet Hours buffering - Events suppressed during a channel's quiet window are now persisted to SQLite and released as a grouped summary when the window closes, instead of being silently dropped",
|
|
"Post-install function update detection - The Monitor tracks installed ProxMenux optimizations (Log2Ram, Memory Settings, System Limits, Logrotate, ...) and notifies when a newer version of any of them is available, with one-click apply from Settings",
|
|
"NVIDIA driver update notifications - Kernel-aware detection of newer compatible driver versions, surfaced in the Hardware tab and as notifications when an upstream build is published",
|
|
"Coral TPU installer - Uninstall path mirroring the NVIDIA flow, and registry-driven update notifications for both the PCIe gasket-dkms driver (tracked against feranick/gasket-driver) and the USB libedgetpu1 runtime",
|
|
"Secure Gateway update flow - One-click Tailscale update from Settings with Last-checked / Installed / Latest indicators and notification when a new version is available",
|
|
"Helper-Scripts menu - Richer context and useful information for each entry, making it easier to know what every script does before running it",
|
|
],
|
|
changed: [
|
|
"AI Enhancement section in Notifications - Rewritten from a muted uppercase row to a normal-case foreground label with a Sparkles icon and a persistent badge (green Active when AI is enabled, neutral Optional when it isn't) so the feature is discoverable regardless of state",
|
|
"Disk temperature monitoring - Improved readings, smarter caching across SMART probes and a redesigned history modal that opens at 24 h by default with min / avg / max statistics",
|
|
"VM and LXC modal - Expanded with additional information so a single panel covers data you previously had to look up across multiple tabs",
|
|
"Page load - Faster first paint and lighter network usage on the Overview, Storage and Hardware tabs",
|
|
"Security improvements - Tighter authentication checks across notification, scripts and terminal endpoints, plus a more conservative default policy for new installs",
|
|
"POST /api/health/acknowledge accepts an optional suppression_hours body field - positive integer in hours, -1 for permanent. Omitting it preserves the previous behaviour (uses the category default). New endpoint POST /api/health/un-acknowledge {error_key} reverses a dismiss",
|
|
"Burst aggregation wording - Burst summaries now report only the additional events that arrived after the initial individual alert, so the operator no longer sees the first event counted twice",
|
|
"Known-error classifier - Word-boundary regex on ATA / UNC patterns so kernel messages like nvidia_uvm:FatalError are no longer misclassified as ATA cable issues",
|
|
"Resolved notifications severity matches the user-visible severity instead of the silently escalated value the DB may carry during the 24 h same-key cooldown",
|
|
"log2ram apply path - The auto / update flow now restarts log2ram after writing the new size, so a configured 512M actually takes effect on the running tmpfs",
|
|
"VM / CT control errors - Failed start / stop / restart now surfaces the real pvesh stderr (e.g. \"no space left on device\") in the UI toast and fires a vm_fail / ct_fail notification, instead of a bare 500 INTERNAL SERVER ERROR",
|
|
"Mobile design of Quiet Hours / Daily Digest - Time inputs are now full-height with inline labels instead of the cramped grid layout that overflowed on narrow screens",
|
|
"Health Monitor dismissed annotation - When an alert is acknowledged with suppression_hours = -1, the dashboard payload tags the check with permanent: true alongside dismissed: true so the UI can render the Permanent badge separately from the standard time-limited Dismissed badge",
|
|
],
|
|
fixed: [
|
|
"Terminal modals on HTTPS hosts - Every terminal modal (dashboard terminal, LXC terminal, script terminal) used to fail with WebSocket connection error on hosts with HTTPS enabled. Root cause: the gevent + SSL path stacked geventwebsocket's WebSocketHandler on top of flask-sock's protocol implementation, so the server emitted two consecutive HTTP/1.1 101 Switching Protocols headers and the browser closed the connection as a corrupt frame. Dropping handler_class=WebSocketHandler restores a single 101 response",
|
|
"Health Monitor kernel updates on PVE 9.x (#208) - The System Updates -> Kernel / PVE row used to report \"Kernel/PVE up to date\" even when an update for the running kernel was waiting upstream. Three combined fixes: (a) the kernel-package prefix list now includes proxmox-kernel-* and proxmox-firmware-* (PVE 9.x ships kernels under proxmox-kernel-, not pve-kernel- as in 7.x / 8.x), (b) the dry-run switched from apt-get upgrade --dry-run to apt-get dist-upgrade --dry-run so kernel updates packaged as new installs are visible, (c) the categoriser now reads uname -r and flags an update as a running-kernel update when the package matches the running release",
|
|
"NVIDIA installer - The version menu now respects the running kernel compatibility window, only offering driver branches that won't fail to compile",
|
|
"NVIDIA installer on Alpine LXC - Container-side userspace install reworked so it succeeds on Alpine hosts, and free-space detection works reliably across all storage layouts",
|
|
"NVIDIA installer with NVENC patch - When the host has the NVENC patch applied, the version menu narrows to drivers supported by the patch so reinstalling never silently loses it",
|
|
"Webhook URL - PVE notification webhook now follows the active SSL state automatically, switching between http and https when you toggle HTTPS in the panel",
|
|
"ATA disk error not recorded - disk_observations is now written before the SMART gate, so transient errors that don't yet trip SMART still build the per-disk history",
|
|
"Quiet Hours toggle not persisting - get_settings now returns the per-channel quiet_* / digest_* fields so the toggle state reloads correctly after a refresh",
|
|
"Frontend 401 cascade - Login screen no longer swallows the 401 forever after a brief stale-token state",
|
|
"Apprise URL section - Mobile overflow - On narrow viewports the Apprise URL row used to break the layout. The placeholder is now a single concise example (tgram://bottoken/ChatID), the URL input enforces min-w-0 / flex-1 / shrink-0 on its children, and the examples paragraph uses break-all min-w-0 so it wraps cleanly on any width",
|
|
"Apprise channel rejected by backend with HTTP 400 - The notifications-test validator's hard-coded channel whitelist (used by POST /api/notifications/test and the history filter) was missing 'apprise', so every Apprise test or send returned 400 \"Invalid channel\" before the library was even invoked. The whitelist is now derived live from notification_channels.CHANNEL_TYPES, so adding a new channel implementation cannot silently regress this validator again",
|
|
"Apprise error reporting - When a destination (jsons://, ntfy://, slack://, ...) returns a non-2xx response, the channel now captures Apprise's internal logger during notify() and surfaces the real HTTP status plus the destination's response body (capped at 300 chars) instead of the opaque \"Apprise rejected the notification (transport failure)\" message",
|
|
"fail2ban-client subprocess storm - The cache wrapper around _f2b_get_banned_ips() only updated its timestamp on success, so on hosts where fail2ban-client returned ENOENT (binary not installed) the function fell through the cache check on every single HTTP request and fired 250+ failed execve calls in a 10-minute window. shutil.which('fail2ban-client') is now resolved once at module load and the cache timestamp is updated unconditionally",
|
|
"smartctl scheduler collision - Disk SMART temperature polling, CPU temperature read and latency probe used to fire at the same offset within each minute, producing a measurable CPU / IO spike when all subprocesses spawned together. The polls are now staggered (latency, then CPU temperature, then disk SMART) while preserving the per-disk 60 s cadence",
|
|
"LXC inventory subprocess - The mount monitor used to call `lxc-info -n <vmid> -p` for every running CT just to get its PID. It now reads /proc/<lxc-start-pid>/task/<lxc-start-pid>/children directly and falls back to lxc-info only when /proc reads fail, eliminating one subprocess per CT per scan cycle",
|
|
"Browser-translated terminal pages - The terminal panel used to lose its WebSocket connection when the user enabled the browser's auto-translate feature, because the translator moved DOM nodes that React still held refs to. Added translate=\"no\" on the terminal container divs so the translator skips the embedded tty entirely",
|
|
"Active Suppressions Save not activating after Re-enable - The Re-enable button used to fire the API call immediately without touching pendingChanges, so the Health Monitor Save button never registered the action. Re-enables are now queued (visual: green border + strike-through on the row + button label changes to Undo) and applied atomically when the user clicks Save, alongside any per-category dropdown changes",
|
|
"Active Suppressions stale after dashboard Dismiss - Dismissing an alert from the Health Monitor modal while the Settings page was already open did not refresh the Active Suppressions list. The dashboard now dispatches a `health-suppression-changed` browser event on every dismiss / un-dismiss; the Settings page listens for it (plus window focus and document visibilitychange) and re-fetches the active set",
|
|
],
|
|
},
|
|
},
|
|
"1.2.1.4-beta": {
|
|
date: "May 30, 2026",
|
|
changes: {
|
|
added: [
|
|
"Per-error dismiss duration - The Dismiss button on each Health Monitor alert now opens a small dropdown with three options: 24 hours, 7 days, or Permanently. The 24h / 7d paths behave like the existing time-limited dismiss (the alert reappears after the window expires). Permanent dismisses persist with suppression_hours = -1 in the persistence DB, never re-emit, never re-notify, and are marked with a distinct amber Permanent badge in the Health Monitor so the operator knows the alert is intentionally silenced",
|
|
"Active Suppressions panel in Settings - New section inside Settings -> Health Monitor (below the per-category suppression durations) that lists every currently-dismissed alert, both time-limited (with countdown) and permanent. Each row carries the error_key, category, severity, when it was dismissed, and a Re-enable button that clears the acknowledgment so the alert can fire again on the next scan. The Re-enable button is gated by the Health Monitor Edit mode (same gating as the rest of the Health settings) — toggle Edit at the top of the page first, then the buttons become active. Permanent dismisses can only be reverted from here, time-limited ones can also be force-revived if you don't want to wait for the countdown",
|
|
"Apprise channel - per-event toggles, Quiet Hours and Daily Digest - The Apprise tab now exposes the same Notification Categories block, per-event sub-toggles, Quiet Hours and Daily Digest controls as Telegram / Gotify / Discord / Email. The backend already supported per-channel filtering for Apprise via the generic channel_overrides logic; the UI just wasn't surfacing it",
|
|
],
|
|
changed: [
|
|
"POST /api/health/acknowledge accepts an optional suppression_hours body field - positive integer for the dismiss duration in hours, -1 for permanent. Omitting the field preserves the previous behaviour (uses the category's configured default). New endpoint POST /api/health/un-acknowledge {error_key} reverses a dismiss (used by Settings -> Active Suppressions and by future automations)",
|
|
"Health Monitor dismissed annotation - When an alert is currently acknowledged with suppression_hours = -1, the dashboard payload now tags the check with permanent: true alongside dismissed: true so the UI can render the Permanent badge separately from the standard time-limited Dismissed badge",
|
|
],
|
|
fixed: [
|
|
"Apprise URL section - Mobile overflow - On narrow viewports the Apprise URL row used to break the design: the placeholder packed four full example URLs into one line and the inline <code> examples in the description had no break-all rule, so the section pushed past the right edge of the viewport. The placeholder is now a single concise example (tgram://bottoken/ChatID), the URL input wrapper enforces min-w-0 / flex-1 / shrink-0 on its children, and the examples paragraph uses break-all min-w-0 so it wraps cleanly on any width",
|
|
],
|
|
},
|
|
},
|
|
"1.2.1.3-beta": {
|
|
date: "May 22, 2026",
|
|
changes: {
|
|
added: [
|
|
"LXC Update Detection - A new dedicated section in Settings (between Health Monitor Thresholds and Notifications) with a single toggle that gates the per-CT apt list --upgradable / apk list -u scan end-to-end. Default ON. When OFF the scan stops entirely (no pct exec calls), every type=lxc entry is purged from the managed-installs registry immediately, and the matching notification toggle in Notifications -> Services disappears from the UI while preserving its stored preference",
|
|
"LXC update checker auto-refresh - The checker now reads the mtime of the CT's package-manager metadata cache and runs apt-get update / apk update from outside via pct exec if it is older than 24h, with a 60s timeout and silent failure. Long-running appliance CTs whose caches were months stale now surface their real upstream backlog (a Debian 12 CT with a 524-day-old cache went from \"0 updates\" to \"117 (12 security)\" on lab hardware)",
|
|
],
|
|
changed: [
|
|
"AI Enhancement section in Notifications - Rewritten from a muted uppercase row that testers consistently scrolled past, to a normal-case foreground label with a leading Sparkles icon and a persistent badge (green Active when AI is enabled, neutral Optional when it isn't) so the feature is visible regardless of state",
|
|
],
|
|
fixed: [
|
|
"Terminal modals on HTTPS hosts - Every terminal modal (dashboard terminal, LXC terminal, script terminal) used to fail with WebSocket connection error on hosts with HTTPS enabled. Root cause: the gevent+SSL path stacked geventwebsocket's WebSocketHandler on top of flask-sock's protocol implementation, so the server emitted two consecutive HTTP/1.1 101 Switching Protocols headers and the browser closed the connection as a corrupt frame. Dropping handler_class=WebSocketHandler restores a single 101 response and lets the handshake complete normally",
|
|
"Health Monitor kernel updates on PVE 9.x (#208) - The System Updates -> Kernel/PVE row reported \"Kernel/PVE up to date\" on PVE 9.x hosts even when an update for the running kernel was waiting upstream. Three combined fixes: (a) the kernel-package prefix list now includes proxmox-kernel-* and proxmox-firmware-* (PVE 9.x ships kernels under proxmox-kernel-, not pve-kernel- as in 7.x/8.x), (b) the dry-run switched from apt-get upgrade --dry-run to apt-get dist-upgrade --dry-run so kernel updates packaged as new installs are visible at all, (c) the categoriser now reads uname -r and flags an update as a running-kernel update when the package matches the running release exactly or its branch meta-package (e.g. proxmox-kernel-6.14 for a host on 6.14.11-4-pve). The row text now distinguishes \"Running kernel update available (reboot required)\" from \"N kernel update(s) available (none for running kernel)\"",
|
|
],
|
|
},
|
|
},
|
|
"1.2.1.2-beta": {
|
|
date: "May 20, 2026",
|
|
changes: {
|
|
added: [
|
|
"Coral TPU installer - Uninstall path mirroring the NVIDIA flow, and registry-driven update notifications for both the PCIe gasket-dkms driver (tracked against feranick/gasket-driver) and the USB libedgetpu1 runtime (tracked via apt)",
|
|
"Disk I/O severity tiers - Sliding 24h window classifies dmesg ATA/SCSI errors into silent (0-10), WARNING (11-100) and CRITICAL (100+ or any hard error like UNC / Buffer I/O / Sense Key Hardware Error), so quiet days stay quiet and a single Buffer I/O event still pages immediately",
|
|
"Quiet Hours buffering - Events suppressed during a channel's quiet window are now persisted to SQLite and released as a grouped summary when the window closes, instead of being silently dropped",
|
|
],
|
|
changed: [
|
|
"Burst aggregation wording - Burst summaries now report only the additional events that arrived after the initial individual alert, so the operator no longer sees the first event counted twice (\"+N more X in window\" instead of the old \"N X in window\" overlap)",
|
|
"Known-error classifier - Word-boundary regex on ATA/UNC patterns so kernel messages like nvidia_uvm:FatalError are no longer misclassified as ATA cable issues",
|
|
"Health journal context - Excludes proxmenux-monitor.service systemd lines so internal watchdog SIGKILLs no longer leak into the body of unrelated kernel events",
|
|
"Resolved notifications severity - The \"previous severity\" now matches the severity the user actually saw in the notification, not whatever escalated value silently landed in the DB during the 24h same-key cooldown",
|
|
"log2ram apply path - The auto/update flow now restarts log2ram after writing the new size, so a configured 512M actually takes effect on the running tmpfs (previously left at 128M until a manual restart)",
|
|
"VM/CT control errors - Failed start/stop/restart now surfaces the real pvesh stderr (e.g. \"no space left on device\") in the UI toast and fires a vm_fail / ct_fail notification, instead of a bare 500 INTERNAL SERVER ERROR",
|
|
"Mobile design of Quiet Hours / Daily Digest - Time inputs are now full-height with inline labels instead of the cramped grid layout that overflowed on narrow screens",
|
|
],
|
|
fixed: [
|
|
"ATA disk error not recorded - disk_observations is now written before the SMART gate, so transient errors that don't yet trip SMART still build the per-disk history",
|
|
"Quiet Hours toggle not persisting - get_settings now returns the per-channel quiet_*/digest_* fields so the toggle's state reloads correctly after a refresh",
|
|
"Frontend 401 cascade - Login screen no longer swallows the 401 forever after a brief stale-token state; the dedup flag is cleared on mount and on successful login",
|
|
],
|
|
},
|
|
},
|
|
"1.2.1.1-beta": {
|
|
date: "May 9, 2026",
|
|
changes: {
|
|
added: [
|
|
"Post-install function update detection - The Monitor now tracks installed ProxMenux optimizations (Log2Ram, Memory Settings, System Limits, Logrotate...) and notifies when a newer version of any of them is available, with one-click apply",
|
|
"Health Monitor Thresholds - Per-category warning and critical levels for CPU, memory, temperature, storage and more, configurable from Settings",
|
|
"NVIDIA driver update notifications - Kernel-aware detection of new compatible driver versions, surfaced in the Hardware tab and as notifications when a newer build is published upstream",
|
|
"Secure Gateway update flow - One-click Tailscale update from Settings with Last-checked / Installed / Latest indicators and notification when a new version is available",
|
|
"Helper-Scripts menu - Richer context and useful information for each entry, making it easier to know what every script does before running it",
|
|
],
|
|
changed: [
|
|
"Disk temperature monitoring - Improved readings, smarter caching across SMART probes and a redesigned history modal that opens at 24h by default with min/avg/max statistics",
|
|
"VM and LXC modal - Expanded with additional information so a single panel covers the data you previously had to look up across multiple tabs",
|
|
"Page load - Faster first paint and lighter network usage on the Overview, Storage and Hardware tabs",
|
|
"Security improvements - Tighter authentication checks across notification, scripts and terminal endpoints, plus a more conservative default policy for new installs",
|
|
],
|
|
fixed: [
|
|
"NVIDIA installer - The version menu now respects the running kernel compatibility window, only offering driver branches that won't fail to compile",
|
|
"NVIDIA installer on Alpine LXC - Container-side userspace install reworked so it succeeds on Alpine hosts, and free-space detection works reliably across all storage layouts",
|
|
"NVIDIA installer with NVENC patch - When the host has the NVENC patch applied, the version menu narrows to drivers supported by the patch so reinstalling never silently loses it",
|
|
"Webhook URL - PVE notification webhook now follows the active SSL state automatically, switching between http and https when you toggle HTTPS in the panel",
|
|
],
|
|
},
|
|
},
|
|
"1.1.2-beta": {
|
|
date: "March 18, 2026",
|
|
changes: {
|
|
added: [
|
|
"Temperature & Latency Charts - Real-time visual monitoring with interactive graphs",
|
|
"WebSocket Terminal - Direct access to Proxmox host and LXC containers terminal",
|
|
"AI-Enhanced Notifications - Intelligent message formatting with multi-provider support (OpenAI, Groq, Anthropic, Ollama)",
|
|
"Security Section - Comprehensive security settings for ProxMenux and Proxmox",
|
|
"VPN Integration - Easy Tailscale VPN installation and configuration",
|
|
"GPU Scripts - Installation utilities for Intel, AMD and NVIDIA drivers",
|
|
"Disk Observations System - Track and document disk health observations over time",
|
|
"Enhanced Health Monitor - Configurable monitoring with advanced settings panel",
|
|
],
|
|
changed: [
|
|
"Improved overall performance with optimized data fetching",
|
|
"Notifications now support rich formatting with contextual emojis",
|
|
"Health monitor now configurable from Settings section",
|
|
"Better Proxmox service name translation for non-expert users",
|
|
],
|
|
fixed: [
|
|
"Fixed notification message truncation for large backup reports",
|
|
"Improved disk error deduplication to prevent repeated alerts",
|
|
"Corrected AI provider base URL handling for OpenAI-compatible APIs",
|
|
],
|
|
},
|
|
},
|
|
"1.0.1": {
|
|
date: "November 11, 2025",
|
|
changes: {
|
|
added: [
|
|
"Proxy Support - Access ProxMenux through reverse proxies with full functionality",
|
|
"Authentication System - Secure your dashboard with password protection",
|
|
"PCIe Link Speed Detection - View NVMe drive connection speeds and detect performance issues",
|
|
"Two-Factor Authentication (2FA) - Enhanced security with TOTP support",
|
|
"Health Monitoring System - Comprehensive system health checks with dismissible warnings",
|
|
],
|
|
changed: [
|
|
"Optimized VM & LXC page - Reduced CPU usage by 85% through intelligent caching",
|
|
"Storage metrics now separate local and remote storage for clarity",
|
|
],
|
|
fixed: [
|
|
"Fixed dark mode text contrast issues in various components",
|
|
"Corrected storage calculation discrepancies between Overview and Storage pages",
|
|
],
|
|
},
|
|
},
|
|
"1.0.0": {
|
|
date: "October 15, 2025",
|
|
changes: {
|
|
added: [
|
|
"Initial release of ProxMenux Monitor",
|
|
"Real-time system monitoring dashboard",
|
|
"Storage management with SMART health monitoring",
|
|
"Network metrics and bandwidth tracking",
|
|
"VM & LXC container management",
|
|
"Hardware information display",
|
|
"System logs viewer with filtering",
|
|
],
|
|
},
|
|
},
|
|
}
|
|
|
|
// Each feature carries an i18n key so translations live in the
|
|
// common.json catalogs and the modal renders in the user's chosen
|
|
// locale. `text` is the English source of truth — it's what the
|
|
// build-i18n-messages workflow feeds to Google Translate for locales
|
|
// that haven't been curated by hand.
|
|
const CURRENT_VERSION_FEATURES = [
|
|
{
|
|
icon: <Languages className="h-5 w-5" />,
|
|
key: "releaseNotes.currentFeatures.i18n",
|
|
text: "The Monitor now speaks 8 languages: English, Spanish, German, French, Italian, Portuguese, Swedish and Slovak. Huge thanks to @vaso73 for building the i18n scaffolding that made this possible.",
|
|
},
|
|
{
|
|
icon: <Zap className="h-5 w-5" />,
|
|
key: "releaseNotes.currentFeatures.pageSpeed",
|
|
text: "Faster page loads and smoother navigation across the dashboard. Overview opens instantly and the VMs & LXCs page never flashes 'Loading…' between guest modals again.",
|
|
},
|
|
{
|
|
icon: <Sparkles className="h-5 w-5" />,
|
|
key: "releaseNotes.currentFeatures.appTab",
|
|
text: "New App tab inside the VM & LXC modal — especially for LXCs. Register the apps installed in a container, capture their weblinks, and get notifications when a new upstream version ships.",
|
|
},
|
|
{
|
|
icon: <RefreshCw className="h-5 w-5" />,
|
|
key: "releaseNotes.currentFeatures.updatesTab",
|
|
text: "Reworked Updates tab for LXCs: apply OS packages and registered-app updates from a single button, and schedule a recurring auto-update job that checks the container's OS and its tracked app on every run.",
|
|
},
|
|
{
|
|
icon: <DatabaseBackup className="h-5 w-5" />,
|
|
key: "releaseNotes.currentFeatures.backupNoTimeout",
|
|
text: "Long backup jobs no longer time out. VM and LXC backups launched from the Monitor now run in the background until they naturally finish, so a 30-minute PBS backup completes the same as a 10-second local one.",
|
|
},
|
|
{
|
|
icon: <HardDrive className="h-5 w-5" />,
|
|
key: "releaseNotes.currentFeatures.vmDiskUsage",
|
|
text: "VMs running the QEMU Guest Agent (qemu-guest-agent) now report real used / total disk figures on the dashboard, instead of the '0 GB' that PVE returns for guest-managed filesystems.",
|
|
},
|
|
{
|
|
icon: <Smartphone className="h-5 w-5" />,
|
|
key: "releaseNotes.currentFeatures.pwaInstall",
|
|
text: "First-time visitors on Android and iOS Safari now see an in-app install prompt with clear steps for adding the Monitor to their home screen as a PWA.",
|
|
},
|
|
]
|
|
|
|
// Turn any "@handle" mention inside a release-notes string into a
|
|
// link to that GitHub profile. Applied to every feature bullet so a
|
|
// contributor shout-out reads as a real link without needing rich
|
|
// i18n formatting. Only matches `@` followed by a valid GitHub
|
|
// username (letters/digits/hyphen, no consecutive hyphens, 1-39
|
|
// chars) so unrelated punctuation stays untouched.
|
|
function linkifyGithubMentions(text: string): (string | JSX.Element)[] {
|
|
const parts: (string | JSX.Element)[] = []
|
|
const re = /@([A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?)/g
|
|
let cursor = 0
|
|
let m: RegExpExecArray | null
|
|
let idx = 0
|
|
while ((m = re.exec(text)) !== null) {
|
|
if (m.index > cursor) parts.push(text.slice(cursor, m.index))
|
|
const handle = m[1]
|
|
parts.push(
|
|
<a
|
|
key={`gh-${idx++}`}
|
|
href={`https://github.com/${handle}`}
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
className="text-orange-500 hover:text-orange-400 underline underline-offset-2"
|
|
>
|
|
@{handle}
|
|
</a>,
|
|
)
|
|
cursor = m.index + m[0].length
|
|
}
|
|
if (cursor < text.length) parts.push(text.slice(cursor))
|
|
return parts
|
|
}
|
|
|
|
interface ReleaseNotesModalProps {
|
|
open: boolean
|
|
onClose: () => void
|
|
}
|
|
|
|
export function ReleaseNotesModal({ open, onClose }: ReleaseNotesModalProps) {
|
|
const t = useT()
|
|
const [dontShowAgain, setDontShowAgain] = useState(false)
|
|
|
|
const handleClose = () => {
|
|
if (dontShowAgain) {
|
|
localStorage.setItem("proxmenux-last-seen-version", APP_VERSION)
|
|
}
|
|
onClose()
|
|
}
|
|
|
|
return (
|
|
<Dialog open={open} onOpenChange={handleClose}>
|
|
<DialogContent className="max-w-2xl max-h-[85vh] p-0 gap-0 border-0 bg-transparent">
|
|
<DialogTitle className="sr-only">{t("releaseNotes.dialogTitle", { version: APP_VERSION })}</DialogTitle>
|
|
<div className="relative bg-card rounded-lg shadow-2xl h-full flex flex-col max-h-[85vh]">
|
|
<Button
|
|
variant="ghost"
|
|
size="icon"
|
|
className="absolute top-4 right-4 z-50 h-8 w-8 rounded-full bg-background/80 backdrop-blur-sm hover:bg-background"
|
|
onClick={handleClose}
|
|
>
|
|
<X className="h-4 w-4" />
|
|
</Button>
|
|
|
|
<div className="relative h-32 md:h-40 bg-gradient-to-br from-amber-500 via-orange-500 to-red-500 flex items-center justify-center overflow-hidden flex-shrink-0">
|
|
<div className="absolute inset-0 bg-black/10" />
|
|
<div className="absolute inset-0 bg-[radial-gradient(circle_at_50%_120%,rgba(255,255,255,0.1),transparent)]" />
|
|
|
|
<div className="relative z-10 text-white animate-pulse">
|
|
<Sparkles className="h-12 w-12 md:h-14 md:w-14" />
|
|
</div>
|
|
|
|
<div className="absolute top-10 left-10 w-20 h-20 bg-white/10 rounded-full blur-2xl" />
|
|
<div className="absolute bottom-10 right-10 w-32 h-32 bg-white/10 rounded-full blur-3xl" />
|
|
</div>
|
|
|
|
<div className="flex-1 overflow-y-auto p-6 md:p-8 space-y-4 md:space-y-6 min-h-0">
|
|
<div className="space-y-2">
|
|
<h2 className="text-xl md:text-2xl font-bold text-foreground text-balance">
|
|
{t("releaseNotes.title", { version: APP_VERSION })}
|
|
</h2>
|
|
<p className="text-sm text-muted-foreground leading-relaxed">
|
|
{t("releaseNotes.intro")}
|
|
</p>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
{CURRENT_VERSION_FEATURES.map((feature, index) => (
|
|
<div
|
|
key={index}
|
|
className="flex items-start gap-2 md:gap-3 p-3 rounded-lg bg-muted/50 border border-border/50 hover:bg-muted/70 transition-colors"
|
|
>
|
|
<div className="text-orange-500 mt-0.5 flex-shrink-0">{feature.icon}</div>
|
|
<p className="text-xs md:text-sm text-foreground leading-relaxed">
|
|
{linkifyGithubMentions(t(feature.key))}
|
|
</p>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
<div className="flex-shrink-0 p-6 md:p-8 pt-4 border-t border-border/50 bg-card">
|
|
<div className="flex flex-col gap-3">
|
|
<Button
|
|
onClick={handleClose}
|
|
className="w-full bg-gradient-to-r from-amber-500 to-orange-500 hover:from-amber-600 hover:to-orange-600"
|
|
>
|
|
<Sparkles className="h-4 w-4 mr-2" />
|
|
{t("releaseNotes.gotIt")}
|
|
</Button>
|
|
|
|
<div className="flex items-center justify-center gap-2">
|
|
<Checkbox
|
|
id="dont-show-version-again"
|
|
checked={dontShowAgain}
|
|
onCheckedChange={(checked) => setDontShowAgain(checked as boolean)}
|
|
/>
|
|
<label
|
|
htmlFor="dont-show-version-again"
|
|
className="text-xs md:text-sm text-muted-foreground hover:text-foreground transition-colors cursor-pointer select-none"
|
|
>
|
|
{t("releaseNotes.dontShowAgain")}
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</DialogContent>
|
|
</Dialog>
|
|
)
|
|
}
|
|
|
|
export function useVersionCheck() {
|
|
const [showReleaseNotes, setShowReleaseNotes] = useState(false)
|
|
|
|
useEffect(() => {
|
|
const lastSeenVersion = localStorage.getItem("proxmenux-last-seen-version")
|
|
|
|
if (lastSeenVersion !== APP_VERSION) {
|
|
setShowReleaseNotes(true)
|
|
}
|
|
}, [])
|
|
|
|
return { showReleaseNotes, setShowReleaseNotes }
|
|
}
|
|
|
|
export { APP_VERSION }
|