Skip to content

feat(web): settings page — *arr instances, search behaviour, downloads (#4) - #64

Open
ChrisonSimtian wants to merge 1 commit into
mainfrom
feat/settings-ui
Open

feat(web): settings page — *arr instances, search behaviour, downloads (#4)#64
ChrisonSimtian wants to merge 1 commit into
mainfrom
feat/settings-ui

Conversation

@ChrisonSimtian

Copy link
Copy Markdown
Contributor

PR 3 of 3 for #4, completing the config UI. The instance model (PR 1) and outbound client (PR 2) had no way for a user to configure them — this is that surface, at /settings.

Three sections

API keys are write-only in the read model

ArrInstanceResponse carries a masked key (last four characters) and never the real one, so this page can only set credentials, not harvest them. Editing shows a blank key field meaning "unchanged", since the true value is never sent to the browser.

Two tests guard this: one asserts no property on the DTO holds the full key, another that a blank key on update preserves the stored one rather than wiping it — the failure mode that would otherwise destroy a credential when someone edits a name.

⚠️ Verification is incomplete — please read

Verified: all three sections render; /settings returns 302 anonymously and 200 authenticated; every handler is unit-tested. PageAuthorizationSpecs covers the new page automatically.

Not verified: any interactive behaviour. Clicking Add / Test / Save / Delete is compile-verified and unit-tested, but never exercised end to end.

While driving a real browser to check it, I found the Web host returns HTTP 500 for /_framework/blazor.web.js, so no Blazor circuit starts and every interactive page is inert — including the pre-existing Search and Activity pages. app.css is also an empty 200 when the client negotiates compression, so the UI renders unstyled:

GET /_framework/blazor.web.js -> HTTP 500, 0 bytes
GET /app.css (plain)          -> HTTP 200, 6318 bytes
GET /app.css (compressed)     -> HTTP 200, 0 bytes
System.IO.FileNotFoundException: Could not find file
  '.../src/Presentation/Web/wwwroot/_framework/blazor.web.js'
   at Microsoft.AspNetCore.Builder.StaticAssetDevelopmentRuntimeHandler.AttachRuntimePatching

Pre-existing, not caused by this work — confirmed by stashing this branch and reproducing on main. Filed as #63 with the exception, the manifest evidence (AssetFile: app.css.gz resolving to a path that doesn't exist), and the reproduction.

It also means an uncomfortable thing worth stating plainly: earlier verification in this area used curl, which cannot detect it, because the static-SSR pages (/login, /setup) genuinely do work without JavaScript. So the auth flow I verified is fine, but nothing interactive has ever been exercised in a browser.

Testing

App 110 / Arch 11 / Infra 102 green, 0 warnings. Base URLs validated as absolute http/https and normalised (trimmed, trailing slash removed), with reverse-proxy subpaths accepted since PR 2's client preserves them.

Suggested order

I'd merge this (it's additive and the handlers are covered), then take #63 before any further UI work — otherwise every subsequent front-end change is equally unverifiable.

Plan: docs/plans/2026-07-27 - arr-instance-config-ui.md

🤖 Generated with Claude Code

#4)

PR 3 of 3 for #4. The instance model (PR 1) and outbound client (PR 2) had no way for a
user to configure them; this is that surface, at /settings.

Three sections:

- Sonarr/Radarr instances — table with add/edit/delete and a per-row Test button, plus
  "Test without saving" so a wrong key never has to be persisted just to find out it is
  wrong.
- Search — the first-query behaviour toggle added in #58 (return fast, with the wait
  seconds behind an Advanced disclosure, vs. wait for a complete result), including the
  warning that a long wait can make Sonarr treat a working indexer as failing.
- Downloads — adopts GetSettingsHandler/SaveSettingsHandler, which were registered in DI
  but called by nothing, so download directory and refresh interval finally have a UI.
  Parallel downloads is labelled as not yet honoured, since #51 is still open; showing it
  as if it worked would be a lie.

API keys are write-only in the read model. ArrInstanceResponse carries only a masked key
(last four characters), so the settings page cannot be used to harvest credentials — only
to set them. Editing shows a blank key field meaning "unchanged", because the real value is
never sent to the browser. There is a test asserting no property on the DTO holds the full
key, and another that a blank key on update preserves the stored one rather than wiping it.

Base URLs are validated as absolute http/https and normalised (trimmed, trailing slash
removed), with reverse-proxy subpaths accepted since PR 2's client preserves them.

Tests: App 110 / Arch 11 / Infra 102 green, 0 warnings. PageAuthorizationSpecs covers the
new page automatically — it carries [Authorize] and the anonymous-page list is unchanged.

## Verification is incomplete, and honestly so

Verified: the page renders all three sections, /settings returns 302 anonymously and 200
authenticated, and every handler is unit-tested.

NOT verified: any interactive behaviour — clicking Add/Test/Save/Delete. While driving a
real browser I found the Web host returns HTTP 500 for /_framework/blazor.web.js, so no
Blazor circuit starts and every interactive page is inert, including the pre-existing
Search and Activity pages. app.css is also served as an empty 200 when the client
negotiates compression, so the UI renders unstyled.

That is pre-existing, not caused by this work — confirmed by stashing this branch and
reproducing on main. Filed as #63 with the exception
(StaticAssetDevelopmentRuntimeHandler looking for framework assets as physical files under
wwwroot) and the manifest evidence. It blocks browser verification of this page, so the
interactive wiring here is compile-verified and unit-tested but not exercised end to end.

Plan: docs/plans/2026-07-27 - arr-instance-config-ui.md

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant