Split webui into Flask blueprints and data domain modules
- Split app.py (66 routes) into 3 blueprints: pages (public), api (JSON), admin (@admin_required) - Split data.py (4,360 LOC) into 7 domain modules: drafts, authors, ratings, gaps, analysis, search, proposals - Add data/__init__.py re-exporting all public functions for backward compatibility - Add custom 404/500 error pages matching dark theme - Add request timing logging via before_request/after_request hooks - Refactor app.py into create_app() factory pattern - All 106 tests pass, all 66 routes preserved Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
46
src/webui/data/_shared.py
Normal file
46
src/webui/data/_shared.py
Normal file
@@ -0,0 +1,46 @@
|
||||
"""Shared utilities for webui data modules."""
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
# Ensure project src is on path
|
||||
_project_root = Path(__file__).resolve().parent.parent.parent.parent
|
||||
if str(_project_root) not in sys.path:
|
||||
sys.path.insert(0, str(_project_root / "src"))
|
||||
|
||||
from ietf_analyzer.config import Config
|
||||
from ietf_analyzer.db import Database
|
||||
from ietf_analyzer.readiness import compute_readiness, compute_readiness_batch
|
||||
|
||||
# Simple TTL cache for expensive computations (t-SNE, clustering, similarity)
|
||||
_cache: dict[str, tuple[float, object]] = {}
|
||||
_CACHE_TTL = 300 # 5 minutes
|
||||
|
||||
|
||||
def _extract_month(time_str: str | None) -> str:
|
||||
"""Normalize a date string to YYYY-MM format."""
|
||||
if not time_str:
|
||||
return "unknown"
|
||||
if len(time_str) >= 7 and time_str[4] == '-':
|
||||
return time_str[:7] # Already YYYY-MM-DD
|
||||
if len(time_str) >= 6 and time_str[:4].isdigit():
|
||||
return time_str[:4] + '-' + time_str[4:6] # YYYYMMDD → YYYY-MM
|
||||
return time_str[:7]
|
||||
|
||||
def _cached(key: str, fn, ttl: float = _CACHE_TTL):
|
||||
"""Return cached result or compute and cache it."""
|
||||
now = time.monotonic()
|
||||
if key in _cache:
|
||||
ts, val = _cache[key]
|
||||
if now - ts < ttl:
|
||||
return val
|
||||
val = fn()
|
||||
_cache[key] = (now, val)
|
||||
return val
|
||||
|
||||
def get_db() -> Database:
|
||||
"""Get a Database instance using default config."""
|
||||
config = Config.load()
|
||||
return Database(config)
|
||||
Reference in New Issue
Block a user