Files
Nexus/server/api/browser.py
T

88 lines
2.6 KiB
Python
Raw Normal View History

"""Embedded browser UI preferences API."""
from __future__ import annotations
from fastapi import APIRouter, Depends
from pydantic import BaseModel, Field
from sqlalchemy.ext.asyncio import AsyncSession
from server.api.auth_jwt import get_current_admin
from server.api.dependencies import get_db
from server.domain.models import Admin
from server.infrastructure.database.admin_ui_preference_repo import AdminUiPreferenceRepositoryImpl
from server.utils.browser_ui_state import (
BROWSER_UI_CONTEXT,
merge_browser_state,
parse_browser_state,
record_visit,
)
router = APIRouter(prefix="/api/browser", tags=["browser"])
class BrowserVisitRecord(BaseModel):
url: str
title: str | None = None
class BrowserTabState(BaseModel):
id: str
url: str
title: str | None = None
stack: list[str] | None = None
stack_index: int | None = None
class BrowserPanelRect(BaseModel):
x: float
y: float
w: float
h: float
class BrowserStateUpdate(BaseModel):
url_history: list[str] | None = None
visits: list[dict] | None = None
tabs: list[BrowserTabState] | None = None
active_tab_id: str | None = None
minimized: bool | None = None
rect: BrowserPanelRect | None = None
minimized_rect: BrowserPanelRect | None = None
record_url: str | None = Field(default=None, description="Append one visit + history entry")
record_title: str | None = None
@router.get("/state")
async def get_browser_state(
admin: Admin = Depends(get_current_admin),
db: AsyncSession = Depends(get_db),
):
repo = AdminUiPreferenceRepositoryImpl(db)
raw = await repo.get(admin.id, BROWSER_UI_CONTEXT)
return parse_browser_state(raw)
@router.put("/state")
async def put_browser_state(
payload: BrowserStateUpdate,
admin: Admin = Depends(get_current_admin),
db: AsyncSession = Depends(get_db),
):
repo = AdminUiPreferenceRepositoryImpl(db)
current = parse_browser_state(await repo.get(admin.id, BROWSER_UI_CONTEXT))
incoming = payload.model_dump(exclude_none=True)
if payload.tabs is not None:
incoming["tabs"] = [t.model_dump(exclude_none=True) for t in payload.tabs]
if payload.rect is not None:
incoming["rect"] = payload.rect.model_dump()
if payload.minimized_rect is not None:
incoming["minimized_rect"] = payload.minimized_rect.model_dump()
merged = merge_browser_state(current, incoming)
if payload.record_url:
merged = record_visit(merged, payload.record_url, payload.record_title)
await repo.upsert(admin.id, BROWSER_UI_CONTEXT, merged)
return merged