feat(jellyseer): sortable/filterable requests table on the Requests tab
Replace the static "recent requests" list with a proper table of all Jellyseerr requests, sorted by date added (newest first by default) with standard sorting and filtering. Backend: - JellyseerrClient.requests(max_count=500): paginated GET /api/v1/request (sort=added), mapped with type (movie/tv), status, media_status, and created_at labels. Returns up to 500 so the table can sort/filter client-side. - fetch_jellyseer_requests(service) reuses the per-service cached client (shared with the stats widgets). - new GET /api/jellyseerr/requests endpoint. Frontend: - JellyseerRequestsTable: TanStack Table (sorting via getSortedRowModel, pagination via getPaginationRowModel) reusing the Table primitives + TablePagination. Columns: Name / Type / Status / Media / Requested, all sortable; default sort Requested desc. A search box filters by name and a status dropdown defaults to "Open" (pending+approved+processing) with All/Pending/Approved/Declined options. (The shared DataTable is deliberately visibility-only, so this is a dedicated sortable table.) - RequestsTab renders the stats grid + the new table (the compact recent list stays on the Requests overview widget). - useJellyseerRequests hook + fetchJellyseerRequests API client. Tests: client requests() mapping + single-page stop; fetch helper not-configured; RequestsTab test mocks both hooks. 404/404 backend + 184/184 frontend pass; build (tsc -b && vite build) + ESLint clean.
This commit is contained in:
@@ -24,6 +24,7 @@ _MEDIA_STATUS: dict[int, str] = {
|
||||
4: "partially_available",
|
||||
5: "available",
|
||||
}
|
||||
_REQUEST_TYPE: dict[int, str] = {1: "movie", 2: "tv"}
|
||||
|
||||
|
||||
def _label(value: Any, table: dict[int, str]) -> str:
|
||||
@@ -195,3 +196,41 @@ class JellyseerrClient:
|
||||
}
|
||||
)
|
||||
return mapped
|
||||
|
||||
def requests(self, max_count: int = 500) -> list[dict[str, Any]]:
|
||||
"""Return requests (paginated), mapped for the requests table.
|
||||
|
||||
Fetches up to ``max_count`` requests (no status filter, so the table
|
||||
can filter/sort client-side). The table defaults to showing "open"
|
||||
(pending/approved/processing) sorted by date added (newest first).
|
||||
"""
|
||||
max_count = max(1, min(int(max_count), 1000))
|
||||
results: list[dict[str, Any]] = []
|
||||
take = 100
|
||||
skip = 0
|
||||
while skip < max_count:
|
||||
payload = self.get("/request", sort="added", skip=skip, take=take)
|
||||
if not isinstance(payload, dict):
|
||||
break
|
||||
page = payload.get("results") or []
|
||||
items = [r for r in page if isinstance(r, dict)] if isinstance(page, list) else []
|
||||
for r in items:
|
||||
media = r.get("media") or {}
|
||||
results.append(
|
||||
{
|
||||
"id": r.get("id"),
|
||||
"type": _label(r.get("type"), _REQUEST_TYPE),
|
||||
"name": r.get("title") or (media or {}).get("title") or (media or {}).get("name") or "—",
|
||||
"status": _label(r.get("status"), _REQUEST_STATUS),
|
||||
"media_status": _label((media or {}).get("status"), _MEDIA_STATUS),
|
||||
"created_at": r.get("createdAt"),
|
||||
}
|
||||
)
|
||||
if len(items) < take:
|
||||
break
|
||||
skip += len(items)
|
||||
if len(results) >= max_count:
|
||||
results = results[:max_count]
|
||||
break
|
||||
logger.info("Jellyseerr returned %s requests", len(results))
|
||||
return results
|
||||
|
||||
Reference in New Issue
Block a user