feat(screenshots): add automated screenshot utility and refresh all UI image assets
CI & Build NaxOS Web Dashboard / build (push) Successful in 1m7s

This commit is contained in:
Lukas Holzner
2026-09-04 14:08:47 +02:00
parent 7096294d10
commit 02a0fb428b
13 changed files with 108 additions and 1 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

+2 -1
View File
@@ -6,7 +6,8 @@
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",
"build": "tsc && vite build", "build": "tsc && vite build",
"preview": "vite preview" "preview": "vite preview",
"screenshots": "python3 scripts/capture-screenshots.py"
}, },
"dependencies": { "dependencies": {
"react": "^18.3.1", "react": "^18.3.1",
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 223 KiB

After

Width:  |  Height:  |  Size: 247 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 272 KiB

After

Width:  |  Height:  |  Size: 282 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 166 KiB

After

Width:  |  Height:  |  Size: 170 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 158 KiB

After

Width:  |  Height:  |  Size: 161 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 272 KiB

After

Width:  |  Height:  |  Size: 312 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 144 KiB

After

Width:  |  Height:  |  Size: 149 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 144 KiB

After

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 148 KiB

After

Width:  |  Height:  |  Size: 153 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 271 KiB

After

Width:  |  Height:  |  Size: 312 KiB

+106
View File
@@ -0,0 +1,106 @@
#!/usr/bin/env python3
"""
NaxOS Dashboard Automated Screenshot Utility
Builds the UI and launches headless Chrome to capture crisp, authentic application screenshots.
"""
import subprocess
import time
import os
import shutil
import sys
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
UI_DIR = os.path.abspath(os.path.join(SCRIPT_DIR, ".."))
DIST_DIR = os.path.join(UI_DIR, "dist")
SCREENSHOTS_DIR = os.path.join(UI_DIR, "public", "screenshots")
PORT = 4199
# Detect Chrome binary
CHROME_CANDIDATES = [
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
"/usr/bin/google-chrome",
"/usr/bin/chromium-browser",
"/usr/bin/chromium",
]
CHROME_BIN = None
for candidate in CHROME_CANDIDATES:
if os.path.exists(candidate):
CHROME_BIN = candidate
break
if not CHROME_BIN:
print("Error: Google Chrome / Chromium not found. Please install Chrome to use automated screenshot capture.", file=sys.stderr)
sys.exit(1)
os.makedirs(SCREENSHOTS_DIR, exist_ok=True)
# 1. Build UI dist
print("==> [1/3] Building NaxOS UI production bundle...")
subprocess.run(["npm", "run", "build"], cwd=UI_DIR, check=True)
# 2. Start HTTP server
print(f"==> [2/3] Serving UI dist at http://localhost:{PORT}...")
server_proc = subprocess.Popen(
[sys.executable, "-m", "http.server", str(PORT), "--directory", DIST_DIR],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL
)
VIEWS = [
("dashboard-overview.png", "#overview", 1440, 960),
("system-telemetry.png", "#overview", 1440, 1280),
("storage-management.png", "#storage", 1440, 1000),
("app-store.png", "#apps", 1440, 1000),
("migration-wizard.png", "#wizard", 1440, 960),
("shares-management.png", "#shares", 1440, 960),
("gitops-sync.png", "#gitops", 1440, 960),
("system-logs.png", "#logs", 1440, 960),
]
try:
time.sleep(1.5)
print("==> [3/3] Capturing authentic application screenshots via headless Chrome...")
for filename, hash_route, width, height in VIEWS:
target_file = os.path.join(SCREENSHOTS_DIR, filename)
url = f"http://localhost:{PORT}/{hash_route}"
print(f" Capturing {hash_route:<10} ({width}x{height}) -> {filename}...")
cmd = [
CHROME_BIN,
"--headless=new",
"--disable-gpu",
f"--window-size={width},{height}",
"--virtual-time-budget=3000",
f"--screenshot={target_file}",
url
]
res = subprocess.run(cmd, capture_output=True, text=True)
if os.path.exists(target_file):
size = os.path.getsize(target_file)
print(f" [OK] {filename} ({size // 1024} KB)")
else:
print(f" [FAILED] {filename}: {res.stderr}", file=sys.stderr)
# Legacy alias
telemetry_src = os.path.join(SCREENSHOTS_DIR, "system-telemetry.png")
perses_dst = os.path.join(SCREENSHOTS_DIR, "perses-analytics.png")
if os.path.exists(telemetry_src):
shutil.copyfile(telemetry_src, perses_dst)
# Copy to sister documentation repositories if present
repo_root = os.path.abspath(os.path.join(UI_DIR, ".."))
for repo in ["naxos-os", "naxos-api", "naxos-docs"]:
doc_img_dir = os.path.join(repo_root, repo, "docs", "images")
if os.path.exists(doc_img_dir):
for filename, _, _, _ in VIEWS:
src_path = os.path.join(SCREENSHOTS_DIR, filename)
if os.path.exists(src_path):
shutil.copyfile(src_path, os.path.join(doc_img_dir, filename))
if os.path.exists(perses_dst):
shutil.copyfile(perses_dst, os.path.join(doc_img_dir, "perses-analytics.png"))
print(f" Synced screenshots to {repo}/docs/images/")
finally:
server_proc.terminate()
server_proc.wait()
print("\nAll NaxOS UI screenshots successfully captured and distributed!")