Update 1.2.2.2 beta

This commit is contained in:
MacRimi
2026-06-22 18:52:26 +02:00
parent cfdd78244d
commit 6ab9d4ca27
10 changed files with 100 additions and 4 deletions

View File

@@ -1 +1 @@
eae86502621e2ebb7d021b123d8161195e8c8e6441cf1a0e1c752fb206420e59 ProxMenux-1.2.2.2-beta.AppImage
30c427079c3b2b829ece1b801f045c76b8dd7d16286b5ce243f56a5df9928eb8 ProxMenux-1.2.2.2-beta.AppImage

View File

@@ -3,6 +3,7 @@ import type { Metadata, Viewport } from "next"
import { GeistSans } from "geist/font/sans"
import { GeistMono } from "geist/font/mono"
import { ThemeProvider } from "../components/theme-provider"
import { PwaRegister } from "../components/pwa-register"
import { Suspense } from "react"
import "./globals.css"
@@ -46,6 +47,7 @@ export default function RootLayout({
{children}
</ThemeProvider>
</Suspense>
<PwaRegister />
</body>
</html>
)

View File

@@ -0,0 +1,39 @@
"use client"
import { useEffect } from "react"
// ===========================================================
// PwaRegister
// ===========================================================
// Registers /sw.js once on mount. Chrome (Android) only
// surfaces the "Install app" prompt when a service worker
// is active, so even though the SW itself does nothing
// (network-only, no caching), its mere presence flips the
// PWA-installability check from no-to-yes.
//
// Mounted from app/layout.tsx so it runs on every route.
// ===========================================================
export function PwaRegister() {
useEffect(() => {
if (typeof window === "undefined") return
if (!("serviceWorker" in navigator)) return
// Wait for the load event to avoid competing with the
// initial render — the SW registration is not on the
// critical render path.
const register = () => {
navigator.serviceWorker
.register("/sw.js", { scope: "/" })
.catch((err) => {
// Surface the failure only in DevTools — silent in prod.
console.warn("[pwa] service worker registration failed:", err)
})
}
if (document.readyState === "complete") {
register()
} else {
window.addEventListener("load", register, { once: true })
return () => window.removeEventListener("load", register)
}
}, [])
return null
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

BIN
AppImage/public/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -3,14 +3,29 @@
"short_name": "ProxMenux",
"description": "Proxmox System Dashboard and Monitor",
"start_url": "/",
"scope": "/",
"display": "standalone",
"orientation": "any",
"background_color": "#2b2f36",
"theme_color": "#2b2f36",
"icons": [
{
"src": "/images/proxmenux-logo.png",
"sizes": "256x256",
"type": "image/png"
"src": "/icons/icon-192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "any"
},
{
"src": "/icons/icon-512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "any"
},
{
"src": "/icons/icon-maskable-512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "maskable"
}
]
}

40
AppImage/public/sw.js Normal file
View File

@@ -0,0 +1,40 @@
// ==========================================================
// ProxMenux Monitor — Service Worker
// ==========================================================
// Minimal SW whose only job is to make Chrome (Android) treat
// the Monitor as an installable PWA. The Monitor lives on the
// operator's LAN, hits a self-signed HTTPS endpoint and has
// ZERO offline value (every page calls /api/* over the wire),
// so we do NOT cache pages or API responses — caching them
// would only cause stale-data bugs after an AppImage update.
//
// The install / activate handlers clean up old SW caches from
// previous Monitor versions so a beta-to-stable upgrade never
// strands the browser on a cached old shell.
// ==========================================================
const SW_VERSION = 'proxmenux-monitor-v1';
self.addEventListener('install', (event) => {
// Take over as soon as installed; no skipWaiting handshake.
self.skipWaiting();
});
self.addEventListener('activate', (event) => {
event.waitUntil((async () => {
// Wipe any cache name that isn't ours — survives renames /
// version bumps without piling up stale entries.
const names = await caches.keys();
await Promise.all(
names.filter((n) => n !== SW_VERSION).map((n) => caches.delete(n))
);
await self.clients.claim();
})());
});
// Network-only fetch. The SW exists so Chrome marks the site as
// installable; we deliberately do not serve cached responses.
self.addEventListener('fetch', (event) => {
// Let the browser handle it normally — no respondWith → no cache.
return;
});