Commit Graph

3 Commits

Author SHA1 Message Date
bvandeusen f77245bc41 feat(requests): show ingest progress while requests are in flight
After Lidarr accepts a request the local reconciler imports albums and
tracks as they arrive — but until the request hit 'completed' the
operator had no way to see "is anything happening?" The /requests and
/admin/requests rows now surface a live progress line whenever the
request's matched entity has children in our library.

Backend:
- New CountAlbumsByArtist + CountTracksByArtist sqlc queries.
- requestView gains imported_album_count and imported_track_count.
- New fillProgress helper computes them from the matched entity:
  - kind=artist  → counts albums + tracks under matched_artist_id
  - kind=album   → counts tracks under matched_album_id
  - kind=track   → 1 once matched_track_id is set
  N+1 in the list endpoints; acceptable at admin scale.
- handleListRequests, handleGetRequest, and handleListAdminRequests
  populate the new fields on every response.

Frontend:
- LidarrRequest TS type extended with the two counters.
- Both the operator's /requests page and the admin /admin/requests
  page render an accent-colored line under the row meta when at
  least one counter is non-zero, e.g.:
    Artist:  "5 albums · 47 tracks ingested"
    Album:   "12 tracks ingested"
    Track:   "Track ingested"
- Updated test fixtures to include the new required fields.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 13:04:38 -04:00
bvandeusen ab8235dd0b fix(admin): approve flow surfaces real errors; auto-default Lidarr picks
The "I can't approve a request, the toast just says unknown" bug was
four problems compounded:

1. Lidarr config let enabled=true save with default_quality_profile_id=0
   and default_root_folder_path=''. Approve then sent invalid POST bodies
   to Lidarr, which 5xx'd.
2. lidarr.client.post() discarded Lidarr's response body on error, so
   we couldn't tell why Lidarr 5xx'd from server logs.
3. handleApproveRequest's error switch didn't map ErrServerError or
   ErrLookupFailed — both fell through to a generic 500 server_error.
4. apiFetch only parsed {error: {code, message}} envelopes, but admin
   endpoints write {error: 'code_string'}. Every admin error toast
   rendered as 'unknown'.

Fixes:

- internal/lidarr/client.go: capture up to 512 bytes of Lidarr's response
  body when it returns 4xx/5xx; include in the wrapped error so server
  logs show what Lidarr actually said instead of just the status bucket.
- internal/lidarrrequests/service.go: new ErrDefaultsIncomplete fires
  before the Lidarr call when QP=0 or root_folder=''. Stops the bad
  POST entirely.
- internal/api/admin_requests.go: handleApproveRequest now maps
  ErrDefaultsIncomplete -> 'lidarr_defaults_incomplete' (400),
  ErrServerError -> 'lidarr_server_error' (502),
  ErrLookupFailed -> 'lidarr_rejected' (502).
- internal/api/admin_lidarr.go: handlePutLidarrConfig now requires
  QP + root folder to be set whenever enabled=true.
- web/src/lib/api/client.ts: apiFetch handles both error envelope shapes
  so admin error codes propagate to toasts.
- web/src/routes/admin/integrations/+page.svelte: auto-default to the
  first quality profile and first root folder Lidarr returns when the
  operator hasn't picked one yet — saves a click for typical
  one-profile/one-folder home setups.
- web/src/routes/admin/requests/+page.svelte: friendly toast copy for
  the new error codes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 23:37:17 -04:00
bvandeusen 82ffb12f68 feat(api): add /api/admin/requests approval queue
Three admin-gated handlers: GET /admin/requests (list by status),
POST /admin/requests/:id/approve (with optional overrides), and
POST /admin/requests/:id/reject. testHandlers updated to inject a
real clientFn so Approve exercises Lidarr in integration tests.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-29 17:56:25 -04:00