diff --git a/AppImage/public/favicon.ico b/AppImage/public/favicon.ico
new file mode 100644
index 0000000..35feec3
Binary files /dev/null and b/AppImage/public/favicon.ico differ
diff --git a/AppImage/scripts/build_appimage.sh b/AppImage/scripts/build_appimage.sh
index e65f6ce..eaef42b 100644
--- a/AppImage/scripts/build_appimage.sh
+++ b/AppImage/scripts/build_appimage.sh
@@ -194,9 +194,20 @@ chmod +x "$APP_DIR/usr/bin/translate_cli.py"
# Copy Next.js build
echo "📋 Copying web dashboard..."
if [ -d "$APPIMAGE_ROOT/.next" ]; then
+ mkdir -p "$APP_DIR/web"
cp -r "$APPIMAGE_ROOT/.next" "$APP_DIR/web/"
cp -r "$APPIMAGE_ROOT/public" "$APP_DIR/web/"
cp "$APPIMAGE_ROOT/package.json" "$APP_DIR/web/"
+
+ # Also try to create a static export if possible
+ cd "$APPIMAGE_ROOT"
+ if npm run export 2>/dev/null; then
+ echo "✅ Next.js static export created"
+ if [ -d "out" ]; then
+ cp -r "out" "$APP_DIR/web/"
+ fi
+ fi
+
echo "✅ Next.js build copied successfully"
else
echo "❌ Error: Next.js build not found even after building"
diff --git a/AppImage/scripts/flask_server.py b/AppImage/scripts/flask_server.py
index 02a8564..122421f 100644
--- a/AppImage/scripts/flask_server.py
+++ b/AppImage/scripts/flask_server.py
@@ -21,419 +21,82 @@ CORS(app) # Enable CORS for Next.js frontend
@app.route('/')
def serve_dashboard():
- """Serve the main dashboard page"""
+ """Serve the main dashboard page from Next.js build"""
try:
- web_dir = os.path.join(os.path.dirname(__file__), '..', '.next', 'static')
- index_file = os.path.join(os.path.dirname(__file__), '..', '.next', 'server', 'app', 'page.html')
+ next_dir = os.path.join(os.path.dirname(__file__), '..', 'web', '.next')
+
+ # Try to serve the Next.js built index page
+ index_paths = [
+ os.path.join(next_dir, 'server', 'app', 'page.html'),
+ os.path.join(next_dir, 'server', 'pages', 'index.html'),
+ os.path.join(os.path.dirname(__file__), '..', 'web', 'out', 'index.html'),
+ os.path.join(os.path.dirname(__file__), '..', 'web', 'dist', 'index.html')
+ ]
+
+ for index_path in index_paths:
+ if os.path.exists(index_path):
+ return send_file(index_path)
+
+ # If no Next.js build found, return error message
+ return '''
+
+
+
ProxMenux Monitor - Build Error
+
+ 🚨 ProxMenux Monitor - Build Error
+ Next.js application not found. The AppImage may not have been built correctly.
+ Expected paths checked:
+ ''' + ''.join([f'- {path}
' for path in index_paths]) + '''
+ API endpoints are still available:
+
+
+
+ ''', 500
- if os.path.exists(index_file):
- return send_file(index_file)
- else:
- return '''
-
-
-
- ProxMenux Monitor
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
67.3%
-
-
↓ 2.1% from last hour
-
-
-
-
-
15.8 GB
-
-
49.4% of 32 GB • ↑ 1.2 GB
-
-
-
-
-
52°C
-
- Normal
-
-
Max: 78°C • Avg: 48°C
-
-
-
-
-
12
-
- 8 Running
- 4 Stopped
-
-
Total: 16 VMs configured
-
-
-
-
-
-
- 📈
- CPU Usage (24h)
-
-
- CPU Usage Chart
- Real-time data from /api/system
-
-
-
-
-
- 💾
- Memory Usage (24h)
-
-
- Memory Usage Chart
- Real-time data from /api/system
-
-
-
-
-
-
-
- 🖥️
- System Information
-
-
- Hostname:
- proxmox-01
-
-
- Version:
- PVE 8.1.3
-
-
- Kernel:
- 6.5.11-7-pve
-
-
- Architecture:
- x86_64
-
-
-
-
-
- 👥
- Active Sessions
-
-
- Web Console:
- 3 active
-
-
- SSH Sessions:
- 1 active
-
-
- API Calls:
- 247/hour
-
-
-
-
-
- ⚡
- Power & Performance
-
-
- Power State:
- Running
-
-
- Load Average:
- 1.23, 1.45, 1.67
-
-
- Boot Time:
- 2.3s
-
-
-
-
-
-
-
-
-
-
- '''
except Exception as e:
print(f"Error serving dashboard: {e}")
- return jsonify({'error': 'Dashboard not available'}), 500
+ return jsonify({'error': f'Dashboard not available: {str(e)}'}), 500
@app.route('/manifest.json')
def serve_manifest():
"""Serve PWA manifest"""
- return send_from_directory(os.path.join(os.path.dirname(__file__), '..', 'public'), 'manifest.json')
+ try:
+ manifest_paths = [
+ os.path.join(os.path.dirname(__file__), '..', 'web', 'public', 'manifest.json'),
+ os.path.join(os.path.dirname(__file__), '..', 'public', 'manifest.json')
+ ]
+
+ for manifest_path in manifest_paths:
+ if os.path.exists(manifest_path):
+ return send_file(manifest_path)
+
+ # Return default manifest if not found
+ return jsonify({
+ "name": "ProxMenux Monitor",
+ "short_name": "ProxMenux",
+ "description": "Proxmox System Monitoring Dashboard",
+ "start_url": "/",
+ "display": "standalone",
+ "background_color": "#0a0a0a",
+ "theme_color": "#4f46e5",
+ "icons": [
+ {
+ "src": "/images/proxmenux-logo.png",
+ "sizes": "256x256",
+ "type": "image/png"
+ }
+ ]
+ })
+ except Exception as e:
+ print(f"Error serving manifest: {e}")
+ return jsonify({}), 404
@app.route('/sw.js')
def serve_sw():
@@ -463,19 +126,34 @@ def serve_sw():
});
''', 200, {'Content-Type': 'application/javascript'}
+@app.route('/_next/')
+def serve_next_static(filename):
+ """Serve Next.js static files"""
+ try:
+ next_static_dir = os.path.join(os.path.dirname(__file__), '..', 'web', '.next', 'static')
+ if os.path.exists(os.path.join(next_static_dir, filename)):
+ return send_from_directory(next_static_dir, filename)
+ return '', 404
+ except Exception as e:
+ print(f"Error serving Next.js static file {filename}: {e}")
+ return '', 404
+
@app.route('/')
def serve_static_files(filename):
"""Serve static files (icons, etc.)"""
try:
- # Try public directory first
- public_dir = os.path.join(os.path.dirname(__file__), '..', 'public')
- if os.path.exists(os.path.join(public_dir, filename)):
- return send_from_directory(public_dir, filename)
+ # Try Next.js public directory first
+ public_paths = [
+ os.path.join(os.path.dirname(__file__), '..', 'web', 'public'),
+ os.path.join(os.path.dirname(__file__), '..', 'public'),
+ os.path.join(os.path.dirname(__file__), '..', 'web', 'out'),
+ os.path.join(os.path.dirname(__file__), '..', 'web', '.next', 'static')
+ ]
- # Try Next.js static directory
- static_dir = os.path.join(os.path.dirname(__file__), '..', '.next', 'static')
- if os.path.exists(os.path.join(static_dir, filename)):
- return send_from_directory(static_dir, filename)
+ for public_dir in public_paths:
+ file_path = os.path.join(public_dir, filename)
+ if os.path.exists(file_path):
+ return send_from_directory(public_dir, filename)
return '', 404
except Exception as e:
@@ -486,12 +164,18 @@ def serve_static_files(filename):
def serve_images(filename):
"""Serve image files"""
try:
- web_dir = os.path.join(os.path.dirname(__file__), '..', 'web', 'public', 'images')
- if os.path.exists(os.path.join(web_dir, filename)):
- return send_from_directory(web_dir, filename)
- else:
- # Fallback: try to serve from current directory
- return send_from_directory(os.path.dirname(__file__), filename)
+ image_paths = [
+ os.path.join(os.path.dirname(__file__), '..', 'web', 'public', 'images'),
+ os.path.join(os.path.dirname(__file__), '..', 'public', 'images'),
+ os.path.dirname(__file__)
+ ]
+
+ for image_dir in image_paths:
+ file_path = os.path.join(image_dir, filename)
+ if os.path.exists(file_path):
+ return send_from_directory(image_dir, filename)
+
+ return '', 404
except Exception as e:
print(f"Error serving image {filename}: {e}")
return '', 404