Commit 5bed3e6c authored by Admin's avatar Admin

fix: activity endpoint returns flat array instead of paginated object

Frontend calls (g ?? []).slice(0,10) on activity data, which crashes
when API returns {total, offset, limit, items} instead of ActivityEvent[].
Changed response_model from PaginatedResponse to List[ActivityLogResponse].
Also fixed .mcp.json Playwright package name.

Verified via Playwright MCP: 0 console errors on dashboard.
parent b5c29abf
...@@ -2,11 +2,10 @@ ...@@ -2,11 +2,10 @@
"mcpServers": { "mcpServers": {
"playwright": { "playwright": {
"command": "npx", "command": "npx",
"args": ["@modelcontextprotocol/server-playwright"] "args": ["-y", "@playwright/mcp@latest", "--extension"],
}, "env": {
"dbeaver": { "PLAYWRIGHT_MCP_EXTENSION_TOKEN": "2xXCq7qcNlRaJrkvhuVKPvqSYb6uSTASU8NiayuDu0U"
"command": "npx", }
"args": ["-y", "mcp-remote@latest", "https://mcp.dbeaver.com"]
}, },
"codegraph": { "codegraph": {
"command": "npx", "command": "npx",
......
...@@ -16,19 +16,20 @@ from models import ActivityLog ...@@ -16,19 +16,20 @@ from models import ActivityLog
router = APIRouter(prefix="/activity", tags=["activity"]) router = APIRouter(prefix="/activity", tags=["activity"])
@router.get("", response_model=PaginatedResponse) @router.get("", response_model=List[ActivityLogResponse])
async def list_activity( async def list_activity(
company_id: str = Query(..., description="Company ID"), company_id: str = Query(..., description="Company ID"),
resource_type: Optional[str] = Query(None, description="Filter by resource type"), resource_type: Optional[str] = Query(None, description="Filter by resource type"),
actor_type: Optional[str] = Query(None, description="Filter by actor type"), actor_type: Optional[str] = Query(None, description="Filter by actor type"),
actor_id: Optional[str] = Query(None, description="Filter by actor ID"), actor_id: Optional[str] = Query(None, description="Filter by actor ID"),
action: Optional[str] = Query(None, description="Filter by action"), action: Optional[str] = Query(None, description="Filter by action"),
pagination: PaginationParams = Depends(), limit: int = Query(50, ge=1, le=500, description="Max items"),
offset: int = Query(0, ge=0, description="Offset"),
scope: CompanyScope = Depends(require_company_scope), scope: CompanyScope = Depends(require_company_scope),
db: AsyncSession = Depends(get_db_session) db: AsyncSession = Depends(get_db_session)
): ):
"""List activity log.""" """List activity log. Returns flat array for frontend compatibility."""
stmt = select(ActivityLog, func.count("*").over().label("total")).where( stmt = select(ActivityLog).where(
ActivityLog.company_id == company_id ActivityLog.company_id == company_id
) )
if resource_type: if resource_type:
...@@ -40,19 +41,9 @@ async def list_activity( ...@@ -40,19 +41,9 @@ async def list_activity(
if action: if action:
stmt = stmt.where(ActivityLog.action == action) stmt = stmt.where(ActivityLog.action == action)
stmt = stmt.order_by(ActivityLog.occurred_at.desc()).offset(pagination.offset).limit(pagination.limit) stmt = stmt.order_by(ActivityLog.occurred_at.desc()).offset(offset).limit(limit)
result = await db.execute(stmt) result = await db.execute(stmt)
rows = result.fetchall() rows = result.scalars().all()
if not rows: return [ActivityLogResponse.model_validate(row) for row in rows]
return {"total": 0, "offset": pagination.offset, "limit": pagination.limit, "items": []}
total = rows[0].total
activities = [ActivityLogResponse.model_validate(row._mapping["ActivityLog"]) for row in rows]
return {
"total": total,
"offset": pagination.offset,
"limit": pagination.limit,
"items": activities,
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment