feat: add dark mode, navigation, and Web Vitals tracking to marketplace

Backend:
- Simplify DatabaseConfig: remove effective_url property and project root finder
- Update to Pydantic v2 model_config (replace nested Config class)
- Add web_vitals router to main.py and __init__.py
- Fix ExplorerService datetime handling (ensure timezone-naive comparisons)
- Fix status_label extraction to handle both enum and string job states

Frontend (Marketplace):
- Add dark mode toggle with system preference detection
This commit is contained in:
oib
2026-02-15 19:02:51 +01:00
parent 72e21fd07f
commit 7062b2cc78
26 changed files with 1945 additions and 769 deletions

View File

@@ -11,6 +11,7 @@ from .users import router as users
from .exchange import router as exchange
from .marketplace_offers import router as marketplace_offers
from .payments import router as payments
from .web_vitals import router as web_vitals
# from .registry import router as registry
__all__ = ["client", "miner", "admin", "marketplace", "marketplace_gpu", "explorer", "services", "users", "exchange", "marketplace_offers", "payments", "registry"]
__all__ = ["client", "miner", "admin", "marketplace", "marketplace_gpu", "explorer", "services", "users", "exchange", "marketplace_offers", "payments", "web_vitals", "registry"]

View File

@@ -0,0 +1,53 @@
#!/usr/bin/env python3
"""
Web Vitals API endpoint for collecting performance metrics
"""
from fastapi import APIRouter, HTTPException
from pydantic import BaseModel
from typing import List, Dict, Any, Optional
import logging
router = APIRouter()
class WebVitalsEntry(BaseModel):
name: str
startTime: Optional[float] = None
duration: Optional[float] = None
class WebVitalsMetric(BaseModel):
name: str
value: float
id: str
delta: Optional[float] = None
entries: List[WebVitalsEntry] = []
url: Optional[str] = None
timestamp: Optional[str] = None
@router.post("/web-vitals")
async def collect_web_vitals(metric: WebVitalsMetric):
"""
Collect Web Vitals performance metrics from the frontend.
This endpoint receives Core Web Vitals (LCP, FID, CLS, TTFB, FCP) for monitoring.
"""
try:
# Log the metric for monitoring/analysis
logging.info(f"Web Vitals - {metric.name}: {metric.value}ms (ID: {metric.id}) from {metric.url or 'unknown'}")
# In a production setup, you might:
# - Store in database for trend analysis
# - Send to monitoring service (DataDog, New Relic, etc.)
# - Trigger alerts for poor performance
# For now, just acknowledge receipt
return {"status": "received", "metric": metric.name, "value": metric.value}
except Exception as e:
logging.error(f"Error processing web vitals metric: {e}")
raise HTTPException(status_code=500, detail="Failed to process metric")
# Health check for web vitals endpoint
@router.get("/web-vitals/health")
async def web_vitals_health():
"""Health check for web vitals collection endpoint"""
return {"status": "healthy", "service": "web-vitals"}