feat: add web UI, query engine, session management, and 20 E2E tests
- Web UI: login, dashboard, links CRUD, collections, API keys, admin pages - Query engine: AND/OR/XOR with field filters, tag search, preview endpoint - Session management: token expiry detection, 401 interceptor, expiry banner - Links search: tags included, multi-word AND, query mode with set operations - Collections: static/dynamic, query builder with preview, public tree view - Save as Collection: convert search results (static) or query (dynamic) - Dashboard stats: resilient loading with allSettled pattern - Login page: redesigned with public collections tree view - Bug fix: query executor None fields crash (notes/description/url/title) - E2E tests: 20 Playwright tests covering all critical user flows - All 104 tests passing (84 unit/integration + 20 E2E)
This commit is contained in:
@@ -3,6 +3,7 @@ LinkSyncServer - Main Application
|
||||
"""
|
||||
|
||||
import os
|
||||
import time
|
||||
from fastapi import FastAPI, Request
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
@@ -15,6 +16,9 @@ from config.settings import settings
|
||||
from models.base import Base, get_engine
|
||||
|
||||
|
||||
BUILD_ID = str(int(time.time()))
|
||||
|
||||
|
||||
@asynccontextmanager
|
||||
async def lifespan(app: FastAPI):
|
||||
engine = get_engine()
|
||||
@@ -58,29 +62,29 @@ def index():
|
||||
|
||||
@app.get("/login")
|
||||
def login_page(request: Request):
|
||||
return templates.TemplateResponse("login.html", {"request": request})
|
||||
return templates.TemplateResponse("login.html", {"request": request, "build_id": BUILD_ID})
|
||||
|
||||
|
||||
@app.get("/dashboard")
|
||||
def dashboard(request: Request):
|
||||
return templates.TemplateResponse("dashboard.html", {"request": request})
|
||||
return templates.TemplateResponse("dashboard.html", {"request": request, "build_id": BUILD_ID})
|
||||
|
||||
|
||||
@app.get("/links")
|
||||
def links_page(request: Request):
|
||||
return templates.TemplateResponse("links.html", {"request": request})
|
||||
return templates.TemplateResponse("links.html", {"request": request, "build_id": BUILD_ID})
|
||||
|
||||
|
||||
@app.get("/collections")
|
||||
def collections_page(request: Request):
|
||||
return templates.TemplateResponse("collections.html", {"request": request})
|
||||
return templates.TemplateResponse("collections.html", {"request": request, "build_id": BUILD_ID})
|
||||
|
||||
|
||||
@app.get("/api-keys")
|
||||
def apikeys_page(request: Request):
|
||||
return templates.TemplateResponse("apikeys.html", {"request": request})
|
||||
return templates.TemplateResponse("apikeys.html", {"request": request, "build_id": BUILD_ID})
|
||||
|
||||
|
||||
@app.get("/admin")
|
||||
def admin_page(request: Request):
|
||||
return templates.TemplateResponse("admin.html", {"request": request})
|
||||
return templates.TemplateResponse("admin.html", {"request": request, "build_id": BUILD_ID})
|
||||
|
||||
Reference in New Issue
Block a user