modularize service layer, add mobile nav drawer, and sync docs

This commit is contained in:
Justin Visser 2026-02-20 01:28:20 +01:00
parent 7f7a8ce2b0
commit 6b6ed91b92
72 changed files with 8122 additions and 7501 deletions

View file

@ -0,0 +1,79 @@
from __future__ import annotations
from sqlalchemy import or_, select
from sqlalchemy.ext.asyncio import AsyncSession
from app.db.models import CrawlRun, RunStatus, RunTriggerType
async def list_recent_runs_for_user(
db_session: AsyncSession,
*,
user_id: int,
limit: int = 20,
) -> list[CrawlRun]:
result = await db_session.execute(
select(CrawlRun)
.where(CrawlRun.user_id == user_id)
.order_by(CrawlRun.start_dt.desc(), CrawlRun.id.desc())
.limit(limit)
)
return list(result.scalars().all())
async def list_runs_for_user(
db_session: AsyncSession,
*,
user_id: int,
limit: int = 100,
failed_only: bool = False,
) -> list[CrawlRun]:
stmt = (
select(CrawlRun)
.where(CrawlRun.user_id == user_id)
.order_by(CrawlRun.start_dt.desc(), CrawlRun.id.desc())
.limit(limit)
)
if failed_only:
stmt = stmt.where(
CrawlRun.status.in_([RunStatus.FAILED, RunStatus.PARTIAL_FAILURE])
)
result = await db_session.execute(stmt)
return list(result.scalars().all())
async def get_run_for_user(
db_session: AsyncSession,
*,
user_id: int,
run_id: int,
) -> CrawlRun | None:
result = await db_session.execute(
select(CrawlRun).where(
CrawlRun.user_id == user_id,
CrawlRun.id == run_id,
)
)
return result.scalar_one_or_none()
async def get_manual_run_by_idempotency_key(
db_session: AsyncSession,
*,
user_id: int,
idempotency_key: str,
) -> CrawlRun | None:
result = await db_session.execute(
select(CrawlRun)
.where(
CrawlRun.user_id == user_id,
CrawlRun.trigger_type == RunTriggerType.MANUAL,
or_(
CrawlRun.idempotency_key == idempotency_key,
CrawlRun.error_log["meta"]["idempotency_key"].astext == idempotency_key,
),
)
.order_by(CrawlRun.start_dt.desc(), CrawlRun.id.desc())
.limit(1)
)
return result.scalar_one_or_none()