fix: admin bugs from the audit: a playback-error delete no longer reports failure, a failed Overview load no longer reads as all-clear, and email settings can't be saved over with defaults (M503 #5604)
release / govulncheck (push) Successful in 16s
release / web (push) Successful in 1m31s
release / go (push) Successful in 1m49s
release / integration (push) Successful in 5m20s
release / Build signed APK (releases and dev) (push) Successful in 5m9s
release / android (push) Successful in 6m26s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 25s
release / Verify release artifacts (tag releases only) (push) Skipped

- Playback errors: Delete file stops resolving the error row the track
  deletion already took with it (ON DELETE CASCADE), which 404'd into
  "Delete failed".
- Overview: a queue that fails to load says so with Try again, and its tile
  shows a dash, not 0. Delete via Lidarr shows only for an album Lidarr
  holds while Lidarr is connected. An approve refreshes the Collection.
- Quarantine: Delete via Lidarr is in the row menu, so a phone reaches it;
  "1 report", not "1 reports".
- Duplicates: the Keep badge follows the copy picked.
- Integrations: provider save failures and load errors are said, not
  swallowed or shown as "No providers registered"; the Lidarr test catches
  a failed call; SMTP fills once and Save stays off until it has loaded.
  Lidarr's blurb says what it is still used for.
- Requests: release profiles point at Collection › Following.
- Library: an empty library sends an admin to Admin to run a scan, and
  tells anyone else the admin scans it, instead of opening Settings.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-11 09:40:11 -04:00
co-authored by Claude Opus 5.5
parent c94c09aeae
commit 7c89e59536
14 changed files with 343 additions and 95 deletions
+16 -28
View File
@@ -170,7 +170,6 @@
<ul class="divide-y divide-border rounded-lg border border-border bg-surface">
{#each rows as r (r.track_id)}
{@const isExpanded = !!expanded[r.track_id]}
{@const lidarrDisabled = !r.lidarr_album_mbid}
{@const primary: RowAction = {
icon: RotateCcw,
label: 'Resolve',
@@ -190,7 +189,19 @@
ariaLabel: `Delete file for ${r.track_title}`,
onclick: () => openDeleteFile(r),
danger: true
}
},
// In the row's actions, so a phone reaches it from the menu too
// (#5604). A local-only track has no Lidarr album to remove, so
// it isn't offered.
...(r.lidarr_album_mbid
? [{
icon: Cloud,
label: 'Delete via Lidarr',
ariaLabel: `Delete via Lidarr for ${r.track_title}`,
onclick: () => openDeleteLidarr(r),
danger: true
}]
: [])
]}
<li
class="flex items-start gap-4 p-3"
@@ -219,7 +230,7 @@
{r.track_title}
</div>
<div class="truncate text-sm text-text-secondary">
{r.artist_name} · {r.album_title} · {r.report_count} reports — latest {relativeTime(r.latest_at)}
{r.artist_name} · {r.album_title} · {r.report_count} {r.report_count === 1 ? 'report' : 'reports'} — latest {relativeTime(r.latest_at)}
</div>
<!-- Reason distribution pills -->
@@ -247,7 +258,7 @@
strokeWidth={1.5}
class="transition-transform {isExpanded ? 'rotate-90' : ''}"
/>
{isExpanded ? 'Hide reports' : `Show ${r.reports.length} reports`}
{isExpanded ? 'Hide reports' : `Show ${r.reports.length} ${r.reports.length === 1 ? 'report' : 'reports'}`}
</button>
{#if isExpanded}
@@ -273,29 +284,6 @@
<div class="flex shrink-0 items-center gap-2">
<RowActionsMenu {primary} {secondary} />
{#if lidarrDisabled}
<span
aria-label={`Delete via Lidarr disabled for ${r.track_title}`}
title="Local-only track — no Lidarr album to remove."
class="hidden md:inline-flex items-center gap-1 rounded-md bg-action-destructive px-3 py-1.5 text-sm text-action-fg opacity-50 cursor-not-allowed"
data-testid="delete-lidarr-disabled"
>
<Trash2 size={14} strokeWidth={2} />
<Cloud size={14} strokeWidth={2} />
Delete via Lidarr
</span>
{:else}
<button
type="button"
aria-label={`Delete via Lidarr for ${r.track_title}`}
class="hidden md:inline-flex items-center gap-1 rounded-md bg-action-destructive px-3 py-1.5 text-sm text-action-fg"
onclick={() => openDeleteLidarr(r)}
>
<Trash2 size={14} strokeWidth={2} />
<Cloud size={14} strokeWidth={2} />
Delete via Lidarr
</button>
{/if}
</div>
</li>
{/each}
@@ -311,7 +299,7 @@
{#if deleteFileRow}
<p class="-mt-2 text-sm text-text-secondary">
Remove <em class="font-medium text-text-primary">{deleteFileRow.track_title}</em>
from disk and clear {deleteFileRow.report_count} reports? Lidarr may auto-redownload depending on its monitor settings.
from disk and clear {deleteFileRow.report_count} {deleteFileRow.report_count === 1 ? 'report' : 'reports'}? Lidarr may auto-redownload depending on its monitor settings.
</p>
<div class="mt-5 flex justify-end gap-2">
<button