nuke all old UIs — templates, React SPA, /v2 mount, legacy routes
Removed: - src/web/templates/*.html (all 6 Jinja2 template files) - src/web/ui-dist/ (old React SPA build) - /v2 duplicate static mount (same as /) - /ui static mount (old React SPA) Server.py changes: - Root handler now directly serves v2 UI (no fallback chain) - Old template routes (/presets, /models, /irs, /settings) → redirect to / - Removed Jinja2Templates, TEMPLATES_DIR, TEMPLATE_VERSION, UI_DIST_DIR
This commit is contained in:
+23
-81
@@ -25,9 +25,8 @@ from typing import Any, Optional
|
||||
|
||||
import uvicorn
|
||||
from fastapi import FastAPI, HTTPException, WebSocket, WebSocketDisconnect, Request
|
||||
from fastapi.responses import HTMLResponse, JSONResponse
|
||||
from fastapi.responses import HTMLResponse, JSONResponse, RedirectResponse
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
from fastapi.templating import Jinja2Templates
|
||||
|
||||
from ..dsp.nam_host import NAMHost
|
||||
from ..dsp.ir_loader import IRLoader
|
||||
@@ -51,38 +50,14 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
# ── Cache buster version (bumped on deploy) ─────────────────────────
|
||||
# Increment this when template/static changes need to bypass browser cache
|
||||
TEMPLATE_VERSION = "8"
|
||||
|
||||
# ── Defaults ─────────────────────────────────────────────────────────────────
|
||||
|
||||
DEFAULT_HOST = "0.0.0.0"
|
||||
DEFAULT_PORT = 8080
|
||||
TEMPLATES_DIR = Path(__file__).resolve().parent / "templates"
|
||||
STATIC_DIR = Path(__file__).resolve().parent / "static"
|
||||
|
||||
# React UI dist — built frontend served at /ui/
|
||||
# Can be overridden via UI_DIST_DIR env var
|
||||
_ui_dist_env = os.environ.get("UI_DIST_DIR")
|
||||
if _ui_dist_env:
|
||||
UI_DIST_DIR = Path(_ui_dist_env).resolve()
|
||||
else:
|
||||
# Priority: src/web/ui-dist is the canonical UI
|
||||
_candidates = [
|
||||
Path(__file__).resolve().parent / "ui-dist",
|
||||
Path(__file__).resolve().parent.parent.parent / "frontend-react" / "dist",
|
||||
]
|
||||
UI_DIST_DIR = next((d for d in _candidates if d.is_dir()), None)
|
||||
|
||||
# ── Channel support ──────────────────────────────────────────────────────────────
|
||||
|
||||
VALID_CHANNELS: frozenset = frozenset({"guitar", "bass", "keys", "vocals", "backing_tracks"})
|
||||
|
||||
def _resolve_channel(channel: str = "guitar") -> str:
|
||||
"""Normalize a channel string; fall back to 'guitar' for invalid values."""
|
||||
if isinstance(channel, str) and channel.lower() in VALID_CHANNELS:
|
||||
return channel.lower()
|
||||
return "guitar"
|
||||
|
||||
# v2 UI dist (the only UI we serve)
|
||||
V2_DIST_DIR = Path(__file__).resolve().parent / "ui-v2-dist"
|
||||
|
||||
# ── Channel mode persistence ────────────────────────────────────────────────
|
||||
|
||||
@@ -315,10 +290,6 @@ class WebServer:
|
||||
|
||||
def _build_app(self) -> FastAPI:
|
||||
|
||||
templates = Jinja2Templates(directory=str(TEMPLATES_DIR))
|
||||
# Inject version into all templates (cache buster for CSS/JS)
|
||||
templates.env.globals["version"] = TEMPLATE_VERSION
|
||||
|
||||
@asynccontextmanager
|
||||
async def lifespan(app: FastAPI):
|
||||
logger.info("Web server lifespan started")
|
||||
@@ -330,63 +301,34 @@ class WebServer:
|
||||
# Mount static files
|
||||
app.mount("/static", StaticFiles(directory=str(STATIC_DIR)), name="static")
|
||||
|
||||
# Mount React UI (if dist exists)
|
||||
if UI_DIST_DIR and UI_DIST_DIR.is_dir():
|
||||
logger.info("Mounting React UI from %s at /ui", UI_DIST_DIR)
|
||||
app.mount("/ui", StaticFiles(directory=str(UI_DIST_DIR), html=True), name="ui")
|
||||
|
||||
# Mount V2 React UI (if dist exists)
|
||||
V2_DIST_DIR = Path(__file__).resolve().parent / "ui-v2-dist"
|
||||
if V2_DIST_DIR.is_dir():
|
||||
logger.info("Mounting V2 React UI from %s at /v2", V2_DIST_DIR)
|
||||
app.mount("/v2", StaticFiles(directory=str(V2_DIST_DIR), html=True), name="ui-v2")
|
||||
|
||||
# ── HTML pages ──────────────────────────────────────────────
|
||||
|
||||
@app.get("/", response_class=HTMLResponse)
|
||||
async def root(request: Request):
|
||||
"""Serve the v2 UI (or React SPA / legacy dashboard as fallback)."""
|
||||
# Prefer the v2 UI if available
|
||||
v2_dir = Path(__file__).resolve().parent / "ui-v2-dist"
|
||||
if v2_dir.is_dir():
|
||||
v2_index = v2_dir / "index.html"
|
||||
if v2_index.exists():
|
||||
content = v2_index.read_text()
|
||||
return HTMLResponse(content)
|
||||
# Fallback: React build
|
||||
if UI_DIST_DIR and UI_DIST_DIR.is_dir():
|
||||
index_html = UI_DIST_DIR / "index.html"
|
||||
if index_html.exists():
|
||||
content = index_html.read_text()
|
||||
return HTMLResponse(content)
|
||||
# Fallback: legacy dashboard (guitar channel state)
|
||||
state = self._gather_state(channel="guitar")
|
||||
ctx = {"request": request}
|
||||
ctx.update(state)
|
||||
return templates.TemplateResponse(request, "dashboard.html", ctx)
|
||||
"""Serve the v2 UI."""
|
||||
v2_index = V2_DIST_DIR / "index.html"
|
||||
if v2_index.exists():
|
||||
content = v2_index.read_text()
|
||||
return HTMLResponse(content)
|
||||
return HTMLResponse("<h1>Pi Multi-FX Pedal</h1><p>UI build not found.</p>")
|
||||
|
||||
@app.get("/presets", response_class=HTMLResponse)
|
||||
async def preset_manager(request: Request):
|
||||
"""Preset manager page — browse banks, load/save/edit."""
|
||||
return templates.TemplateResponse(request, "presets.html", {"request": request})
|
||||
# Legacy routes — redirect to the v2 SPA
|
||||
|
||||
@app.get("/models", response_class=HTMLResponse)
|
||||
async def model_manager(request: Request):
|
||||
"""NAM model manager page."""
|
||||
return templates.TemplateResponse(request, "models.html", {"request": request})
|
||||
@app.get("/presets")
|
||||
async def presets_redirect():
|
||||
return RedirectResponse(url="/")
|
||||
|
||||
@app.get("/irs", response_class=HTMLResponse)
|
||||
async def ir_manager(request: Request):
|
||||
"""IR manager page."""
|
||||
return templates.TemplateResponse(request, "irs.html", {"request": request})
|
||||
@app.get("/models")
|
||||
async def models_redirect():
|
||||
return RedirectResponse(url="/")
|
||||
|
||||
@app.get("/settings", response_class=HTMLResponse)
|
||||
async def settings_page(request: Request):
|
||||
"""Settings page."""
|
||||
state = self._gather_state(channel="guitar")
|
||||
ctx = {"request": request}
|
||||
ctx.update(state)
|
||||
return templates.TemplateResponse(request, "settings.html", ctx)
|
||||
@app.get("/irs")
|
||||
async def irs_redirect():
|
||||
return RedirectResponse(url="/")
|
||||
|
||||
@app.get("/settings")
|
||||
async def settings_redirect():
|
||||
return RedirectResponse(url="/")
|
||||
|
||||
# ── REST API ────────────────────────────────────────────────
|
||||
|
||||
|
||||
Reference in New Issue
Block a user