feat: production-harden app and finalize merge-ready UX/theme baseline
- complete tokenized theme preset system and admin style guide visibility - refine dashboard layout/scroll behavior and shared async/request UI states - add user nav-visibility settings across API, migration, and frontend stores - harden security headers/CSP handling and related test coverage - enforce CI repository hygiene + frontend contract/theme/build quality gates - update docs/env references and make migration smoke test head-aware
This commit is contained in:
parent
ab1d29b203
commit
ae2ca8f149
66 changed files with 5655 additions and 853 deletions
|
|
@ -10,13 +10,38 @@ class UserSettingsServiceError(ValueError):
|
|||
"""Raised for expected settings-validation failures."""
|
||||
|
||||
|
||||
NAV_PAGE_DASHBOARD = "dashboard"
|
||||
NAV_PAGE_SCHOLARS = "scholars"
|
||||
NAV_PAGE_PUBLICATIONS = "publications"
|
||||
NAV_PAGE_SETTINGS = "settings"
|
||||
NAV_PAGE_STYLE_GUIDE = "style-guide"
|
||||
NAV_PAGE_RUNS = "runs"
|
||||
NAV_PAGE_USERS = "users"
|
||||
|
||||
ALLOWED_NAV_PAGES = (
|
||||
NAV_PAGE_DASHBOARD,
|
||||
NAV_PAGE_SCHOLARS,
|
||||
NAV_PAGE_PUBLICATIONS,
|
||||
NAV_PAGE_SETTINGS,
|
||||
NAV_PAGE_STYLE_GUIDE,
|
||||
NAV_PAGE_RUNS,
|
||||
NAV_PAGE_USERS,
|
||||
)
|
||||
REQUIRED_NAV_PAGES = (
|
||||
NAV_PAGE_DASHBOARD,
|
||||
NAV_PAGE_SCHOLARS,
|
||||
NAV_PAGE_SETTINGS,
|
||||
)
|
||||
DEFAULT_NAV_VISIBLE_PAGES = list(ALLOWED_NAV_PAGES)
|
||||
|
||||
|
||||
def parse_run_interval_minutes(value: str) -> int:
|
||||
try:
|
||||
parsed = int(value)
|
||||
except ValueError as exc:
|
||||
raise UserSettingsServiceError("Run interval must be a whole number.") from exc
|
||||
raise UserSettingsServiceError("Check interval must be a whole number.") from exc
|
||||
if parsed < 15:
|
||||
raise UserSettingsServiceError("Run interval must be at least 15 minutes.")
|
||||
raise UserSettingsServiceError("Check interval must be at least 15 minutes.")
|
||||
return parsed
|
||||
|
||||
|
||||
|
|
@ -25,11 +50,41 @@ def parse_request_delay_seconds(value: str) -> int:
|
|||
parsed = int(value)
|
||||
except ValueError as exc:
|
||||
raise UserSettingsServiceError("Request delay must be a whole number.") from exc
|
||||
if parsed < 1:
|
||||
raise UserSettingsServiceError("Request delay must be at least 1 second.")
|
||||
if parsed < 2:
|
||||
raise UserSettingsServiceError("Request delay must be at least 2 seconds.")
|
||||
return parsed
|
||||
|
||||
|
||||
def parse_nav_visible_pages(value: object) -> list[str]:
|
||||
if not isinstance(value, list):
|
||||
raise UserSettingsServiceError("Navigation visibility must be a list of page ids.")
|
||||
|
||||
deduped: list[str] = []
|
||||
seen: set[str] = set()
|
||||
|
||||
for raw_page in value:
|
||||
if not isinstance(raw_page, str):
|
||||
raise UserSettingsServiceError("Navigation visibility entries must be strings.")
|
||||
|
||||
page_id = raw_page.strip()
|
||||
if page_id not in ALLOWED_NAV_PAGES:
|
||||
raise UserSettingsServiceError(f"Unsupported navigation page id: {page_id}")
|
||||
|
||||
if page_id in seen:
|
||||
continue
|
||||
|
||||
seen.add(page_id)
|
||||
deduped.append(page_id)
|
||||
|
||||
missing_required = [page for page in REQUIRED_NAV_PAGES if page not in seen]
|
||||
if missing_required:
|
||||
raise UserSettingsServiceError(
|
||||
"Dashboard, Scholars, and Settings must remain visible."
|
||||
)
|
||||
|
||||
return deduped
|
||||
|
||||
|
||||
async def get_or_create_settings(
|
||||
db_session: AsyncSession,
|
||||
*,
|
||||
|
|
@ -56,11 +111,12 @@ async def update_settings(
|
|||
auto_run_enabled: bool,
|
||||
run_interval_minutes: int,
|
||||
request_delay_seconds: int,
|
||||
nav_visible_pages: list[str],
|
||||
) -> UserSetting:
|
||||
settings.auto_run_enabled = auto_run_enabled
|
||||
settings.run_interval_minutes = run_interval_minutes
|
||||
settings.request_delay_seconds = request_delay_seconds
|
||||
settings.nav_visible_pages = nav_visible_pages
|
||||
await db_session.commit()
|
||||
await db_session.refresh(settings)
|
||||
return settings
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue