#!/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!")