Commit Graph

73 Commits

Author SHA1 Message Date
794cb7268e Fix status panel: remove innerHTML wipe that destroys status-content div
All checks were successful
Build and Push Docker Image / build (push) Successful in 38s
Licence Check / Licence compatibility and copyright header verification (push) Successful in 57s
CI / Security audit (push) Successful in 1m14s
CI / Tests & coverage (push) Successful in 1m27s
2026-05-19 23:01:14 +01:00
d310d101ed Fix undefined --background CSS variable causing blank status panel
All checks were successful
Build and Push Docker Image / build (push) Successful in 44s
CI / Security audit (push) Successful in 1m15s
CI / Tests & coverage (push) Successful in 1m34s
2026-05-19 22:59:16 +01:00
96f24eb3b7 Fix status card regression: revert webhooks-section to sibling structure
All checks were successful
Build and Push Docker Image / build (push) Successful in 47s
Licence Check / Licence compatibility and copyright header verification (push) Successful in 53s
CI / Security audit (push) Successful in 1m2s
CI / Tests & coverage (push) Successful in 1m14s
2026-05-19 22:57:21 +01:00
abcb9bfded debug: Add DOM structure verification to trace missing contentDiv
All checks were successful
Build and Push Docker Image / build (push) Successful in 40s
Licence Check / Licence compatibility and copyright header verification (push) Successful in 1m1s
CI / Security audit (push) Successful in 1m24s
CI / Tests & coverage (push) Successful in 1m34s
2026-05-19 22:35:05 +01:00
e5920b207f debug: Add more detailed logging to renderStatusPanel
All checks were successful
Build and Push Docker Image / build (push) Successful in 26s
Licence Check / Licence compatibility and copyright header verification (push) Successful in 1m8s
CI / Security audit (push) Successful in 1m21s
CI / Tests & coverage (push) Successful in 1m38s
2026-05-19 22:33:09 +01:00
d3483f3be7 debug(ui): Add visible styling and debug logging for status panel
All checks were successful
Build and Push Docker Image / build (push) Successful in 25s
Licence Check / Licence compatibility and copyright header verification (push) Successful in 56s
CI / Security audit (push) Successful in 1m9s
CI / Tests & coverage (push) Successful in 1m26s
Added debug logging to trace status panel rendering:
- Log when refresh starts
- Log when data is received
- Log errors with details

Also added visible dashed border and background to #status-content
to make it obvious when the div is present but empty.
2026-05-19 22:30:54 +01:00
252cc50aa4 fix(ui): Add loading state and min-height for status-content
Some checks failed
Build and Push Docker Image / build (push) Successful in 39s
CI / Security audit (push) Successful in 1m17s
CI / Tests & coverage (push) Has been cancelled
Added loading indicator text and min-height CSS for #status-content
to prevent the empty card appearance when status panel first opens.
2026-05-19 22:29:03 +01:00
57908e2b9e fix(ui): Add status-content container to preserve webhooks panel
All checks were successful
Build and Push Docker Image / build (push) Successful in 37s
Licence Check / Licence compatibility and copyright header verification (push) Successful in 50s
CI / Security audit (push) Successful in 1m1s
CI / Tests & coverage (push) Successful in 1m19s
The webhooks panel was being destroyed when renderStatusPanel set
panel.innerHTML. Added a dedicated #status-content div for status
data, keeping webhooks section intact when status refreshes.
2026-05-19 22:27:11 +01:00
e2757768c7 fix(ui): Integrate webhooks panel into status panel
All checks were successful
Build and Push Docker Image / build (push) Successful in 27s
Licence Check / Licence compatibility and copyright header verification (push) Successful in 59s
CI / Security audit (push) Successful in 1m21s
CI / Tests & coverage (push) Successful in 1m35s
The webhooks panel was appearing separately from the status panel.
Now it's properly nested inside the status-panel div:

- Moved webhooks-section inside status-panel in HTML
- Updated CSS so nested webhooks looks like a subsection (no double borders)
- Simplified JS toggle logic - webhooks shows/hides automatically with status panel
- Admin users see webhooks inside status panel, collapsed by default
2026-05-19 22:24:15 +01:00
2e85fae57a fix(webhooks): Load collapsed by default, add webhook metrics to status panel
All checks were successful
Licence Check / Licence compatibility and copyright header verification (push) Successful in 1m8s
CI / Security audit (push) Successful in 1m28s
CI / Tests & coverage (push) Successful in 1m53s
Build and Push Docker Image / build (push) Successful in 35s
- Fixed webhooks section to load collapsed (content hidden, toggle arrow reset)
- Added webhook metrics card to status panel for admin users:
  - Shows Sonarr/Radarr enabled/disabled status
  - Shows events received and polls skipped counts
- Updated /api/dashboard/status endpoint to include webhook metrics
- Metrics are aggregated from all Sonarr/Radarr instances
2026-05-19 21:24:28 +01:00
aeacadbe68 refactor(webhooks): Integrate webhooks panel into status card
All checks were successful
Build and Push Docker Image / build (push) Successful in 41s
Licence Check / Licence compatibility and copyright header verification (push) Successful in 59s
CI / Security audit (push) Successful in 1m20s
CI / Tests & coverage (push) Successful in 1m33s
- Moved webhooks-section to be inline with status-panel in HTML
- Updated toggleStatusPanel() to show/hide webhooks section for admin users
- Updated closeStatusPanel() to also hide webhooks section
- Removed webhooks visibility from showDashboard() - now tied to status panel
- Updated CSS to make webhooks section styling consistent with status panel:
  - Same border, border-radius, margin, box-shadow
  - Updated webhook-stats to use status-card styling (background, border)
- Webhooks metrics now display inline with status panel for admin users
2026-05-19 21:20:34 +01:00
3ef35a8c43 fix(webhooks): Send full notification object to test endpoint
All checks were successful
Build and Push Docker Image / build (push) Successful in 48s
Licence Check / Licence compatibility and copyright header verification (push) Successful in 1m9s
CI / Security audit (push) Successful in 1m23s
CI / Tests & coverage (push) Successful in 1m42s
The /notifications/test endpoint requires the full notification object,
not just the ID. Changed testSonarrWebhook() and testRadarrWebhook() to
send the complete notification object (sonarrSofarr/radarrSofarr).

Fixes: 400 validation error when testing webhooks
2026-05-19 21:16:31 +01:00
2d04402284 fix(webhooks): Show webhooks panel only to admin users
All checks were successful
Build and Push Docker Image / build (push) Successful in 39s
Licence Check / Licence compatibility and copyright header verification (push) Successful in 57s
CI / Security audit (push) Successful in 1m4s
CI / Tests & coverage (push) Successful in 1m24s
2026-05-19 20:36:33 +01:00
0310f10e5d fix(webhooks): Restore original vanilla JS app and add webhooks panel properly
All checks were successful
Build and Push Docker Image / build (push) Successful in 1m14s
Licence Check / Licence compatibility and copyright header verification (push) Successful in 1m8s
CI / Security audit (push) Successful in 1m22s
CI / Tests & coverage (push) Successful in 1m43s
The React build replaced the full-featured vanilla JS app with a
simpler UI, causing the dashboard to disappear and lose theming.

This commit:
- Restores original vanilla JS app with auth, themes, tabs, history
- Adds Webhooks Configuration panel for admin users
- Adds webhook status, enable/test buttons, triggers, and stats
- Uses proper CSS variables for theme support

Fixes the dashboard disappearing issue and restores all original functionality.
2026-05-19 20:33:23 +01:00
a7363fcb3a v1.5.2: Build and deploy React client with Webhooks Configuration panel
Some checks failed
Build and Push Docker Image / build (push) Successful in 48s
Licence Check / Licence compatibility and copyright header verification (push) Failing after 1m6s
CI / Security audit (push) Successful in 1m29s
CI / Tests & coverage (push) Successful in 1m46s
2026-05-19 20:27:11 +01:00
917939a9fc fix(ui): wire status panel close button via addEventListener
Some checks failed
CI / Security audit (push) Failing after 29s
Docs Check / Markdown lint (push) Successful in 47s
Build and Push Docker Image / build (push) Successful in 1m3s
Licence Check / Licence compatibility and copyright header verification (push) Successful in 1m14s
CI / Tests & coverage (push) Successful in 1m39s
Docs Check / Mermaid diagram parse check (push) Successful in 1m54s
Inline onclick attribute was silently blocked by the server CSP nonce
policy. Replace with addEventListener after innerHTML is set.

chore: bump version to 1.5.0a
2026-05-19 18:51:50 +01:00
8c4cc20551 Add MIT copyright headers to all source files
All checks were successful
Build and Push Docker Image / build (push) Successful in 48s
Licence Check / Licence compatibility and copyright header verification (push) Successful in 1m21s
CI / Security audit (push) Successful in 1m47s
CI / Tests & coverage (push) Successful in 2m1s
2026-05-19 09:07:42 +01:00
2747ca7754 feat: allow non-admin users to blocklist & search under specific conditions
All checks were successful
Build and Push Docker Image / build (push) Successful in 37s
CI / Security audit (push) Successful in 1m30s
CI / Tests & coverage (push) Successful in 1m47s
- Added addedOn timestamp to qBittorrent torrent mapping
- Added canBlocklist helper function: true for admins, true for non-admins when (importIssues OR (torrent >1h old AND availability<100%))
- Added canBlocklist field to all download objects in /user-downloads and SSE /stream routes (8 blocks total)
- Frontend button now shows when (isAdmin OR download.canBlocklist) && download.arrQueueId
2026-05-17 23:57:06 +01:00
0341540751 feat: show blocklist & search button on all admin downloads (not just import-pending)
All checks were successful
Build and Push Docker Image / build (push) Successful in 35s
CI / Security audit (push) Successful in 1m23s
CI / Tests & coverage (push) Successful in 1m43s
- Remove importIssues condition from arr action fields threading in /user-downloads route (all 4 blocks: SAB+Sonarr, SAB+Radarr, qBit+Sonarr, qBit+Radarr)
- Remove importIssues condition from arr action fields threading in SSE /stream route (all 4 blocks)
- Move blocklist button rendering outside importIssues condition in frontend — now shows for all admin downloads with arrQueueId
2026-05-17 23:43:37 +01:00
a6fcde58cf fix: thread arr action fields through SSE handler; align import-issue tooltip with themed CSS pattern
All checks were successful
Build and Push Docker Image / build (push) Successful in 31s
CI / Security audit (push) Successful in 1m19s
CI / Tests & coverage (push) Successful in 1m36s
2026-05-17 23:20:04 +01:00
d839fa98a0 feat: blocklist & search button for import-pending downloads with caution
All checks were successful
Build and Push Docker Image / build (push) Successful in 29s
CI / Security audit (push) Successful in 1m24s
CI / Tests & coverage (push) Successful in 1m42s
- Poller now stores _instanceKey alongside _instanceUrl on Sonarr/Radarr queue records
- dashboard route threads arrQueueId/arrType/arrInstanceUrl/arrInstanceKey/arrContentId/arrContentType as admin-only fields on downloads with importIssues
- POST /api/dashboard/blocklist-search: admin-only, removes queue item with blocklist=true then triggers EpisodeSearch/MoviesSearch
- Button renders in download card header (admin + importIssues + arrQueueId only)
- Confirm dialog, loading/success/error states on the button
- Kicks a background poll on success so SSE reflects removed item promptly
2026-05-17 23:15:33 +01:00
a92ab85bc0 fix: title link wired via JS goHome() — switches to downloads, closes status, resets showAll
All checks were successful
Build and Push Docker Image / build (push) Successful in 40s
CI / Security audit (push) Successful in 1m33s
CI / Tests & coverage (push) Successful in 1m56s
2026-05-17 23:08:27 +01:00
57b127ea95 fix: title click switches to downloads tab and closes status panel (no page reload)
All checks were successful
Build and Push Docker Image / build (push) Successful in 33s
CI / Security audit (push) Successful in 1m20s
CI / Tests & coverage (push) Successful in 1m37s
2026-05-17 23:01:15 +01:00
56f42755cc fix: title logo links to /, version footer links to repo
All checks were successful
Build and Push Docker Image / build (push) Successful in 26s
CI / Security audit (push) Successful in 1m15s
CI / Tests & coverage (push) Successful in 1m36s
2026-05-17 22:58:53 +01:00
15152714fd fix: use data-tooltip CSS popup for hide-upgrade-failures checkbox, matching episode tooltip style
All checks were successful
Build and Push Docker Image / build (push) Successful in 26s
CI / Security audit (push) Successful in 1m35s
CI / Tests & coverage (push) Successful in 1m44s
2026-05-17 22:55:52 +01:00
19b9c97e64 feat: add 'Hide upgrade failures' checkbox to history controls
All checks were successful
Build and Push Docker Image / build (push) Successful in 36s
CI / Security audit (push) Successful in 1m27s
CI / Tests & coverage (push) Successful in 1m43s
2026-05-17 22:52:55 +01:00
55a5577f2a feat: render availableForUpgrade badge on failed history items where episode/movie is already on disk
All checks were successful
Build and Push Docker Image / build (push) Successful in 38s
CI / Security audit (push) Successful in 1m41s
CI / Tests & coverage (push) Successful in 1m49s
2026-05-17 21:53:58 +01:00
fecb96b04e fix: correct width typo 56x -> 56px
All checks were successful
Build and Push Docker Image / build (push) Successful in 29s
CI / Security audit (push) Successful in 1m34s
CI / Tests & coverage (push) Successful in 2m0s
2026-05-17 21:21:30 +01:00
c98b81c8bd fix: Reduced size of logo to 56px for better balance 2026-05-17 21:21:30 +01:00
90bf411e0c Increased size of logo to 64px for better balance 2026-05-17 21:21:30 +01:00
867e86615e fix: increase header logo to 40px, use 192px source for crispness 2026-05-17 21:21:30 +01:00
2cbe3c6b76 feat: use favicon-192 for header logo, scale to 28px for visual parity with title text 2026-05-17 21:21:30 +01:00
59adcbc36e feat: add logo to header title link 2026-05-17 21:21:30 +01:00
9aaff5c368 feat: link sofarr title to repo
Some checks failed
Build and Push Docker Image / build (push) Successful in 30s
CI / Security audit (push) Failing after 2m56s
CI / Tests & coverage (push) Successful in 5m35s
2026-05-17 20:55:06 +01:00
6a8ca90fd3 feat: add version footer to dashboard UI (v1.2.1)
- /health endpoint now includes version field
- Footer displays 'sofarr vX.Y.Z' fetched on page load
- Subtle .app-version styling (smaller, dimmed)
- Bump version to 1.2.1, update CHANGELOG
2026-05-17 20:34:59 +01:00
c0dd93a1ab feat: production hardening v1.2.0
Some checks failed
Build and Push Docker Image / build (push) Successful in 59s
CI / Security audit (push) Successful in 1m5s
CI / Tests & coverage (push) Successful in 1m24s
Docs Check / Markdown lint (push) Failing after 45s
Docs Check / Mermaid diagram parse check (push) Successful in 1m27s
CI / Security audit (pull_request) Successful in 51s
CI / Tests & coverage (pull_request) Successful in 1m1s
Docs Check / Markdown lint (pull_request) Failing after 39s
Docs Check / Mermaid diagram parse check (pull_request) Successful in 1m12s
Phase 1 - Licensing & Compliance:
- Add MIT LICENSE file
- Add copyright headers to server/index.js, poller.js, config.js,
  sanitizeError.js, and new loadSecrets.js

Phase 2 - Security Hardening:
- Add server/utils/loadSecrets.js: Docker secrets support via _FILE
  env var pattern (COOKIE_SECRET_FILE, EMBY_API_KEY_FILE, etc.)
- Add SSRF/URL validation in config.js: validates all configured
  service instance URLs for scheme and well-formedness at startup
- Add SIGTERM/SIGINT graceful shutdown: stops poller, drains HTTP
  connections, 10s force-exit fallback
- Warn at startup if COOKIE_SECRET is shorter than 32 characters
- Validate EMBY_URL scheme at startup
- Improve sanitizeError: redact host:port from axios error URLs
  while preserving path/query for other redaction patterns

Phase 3 - Config Robustness:
- Weak COOKIE_SECRET warning (< 32 chars)
- EMBY_URL validated via validateInstanceUrl on startup

Phase 4 - Docker & Deployment:
- .dockerignore: add tests/, coverage/, vitest.config.js,
  CHANGELOG.md, SECURITY.md, LICENSE, .markdownlint.json
- docker-compose.yaml: add commented Option B (Docker secrets
  _FILE pattern) alongside existing plain-env Option A

Phase 5 - Docs & Release Readiness:
- Add CHANGELOG.md with entries from v1.0.0 to v1.2.0
- Update SECURITY.md: supported versions table, fix Docker secrets
  note to reflect _FILE support now implemented
- Add public/.well-known/security.txt for responsible disclosure
- Bump version to 1.2.0
2026-05-17 19:40:07 +01:00
bdd78407bb fix: use --surface for episode tooltip background (--card-bg was undefined)
All checks were successful
Build and Push Docker Image / build (push) Successful in 44s
CI / Security audit (push) Successful in 1m6s
CI / Tests & coverage (push) Successful in 1m27s
2026-05-17 17:27:13 +01:00
d1496a76e2 feat: show episode info on download and history cards
All checks were successful
Build and Push Docker Image / build (push) Successful in 37s
CI / Security audit (push) Successful in 59s
CI / Tests & coverage (push) Successful in 54s
- Add includeEpisode:true to Sonarr queue and history API requests
  in both the poller and historyFetcher
- Add extractEpisode() / gatherEpisodes() helpers in dashboard.js
  and history.js to build a sorted, deduplicated episodes array
  covering all records matching a download title (handles multi-
  episode packs and series packs)
- Replace episodeInfo: sonarrMatch with episodes: gatherEpisodes()
  across all 8 assignment sites in dashboard.js
- Add episodes field to /api/history/recent response items
- Frontend: formatEpisodeInfo() renders S01E05 for single episodes
  or 'Multiple episodes' with hover tooltip listing all for packs
- CSS: .episode-info and .multi-episode tooltip styles
- ARCHITECTURE.md: update polling table and download/history schemas
2026-05-17 17:03:23 +01:00
2b089871a0 design(light-theme): replace purple scheme with logo-aligned teal palette, WCAG AA compliant
All checks were successful
Build and Push Docker Image / build (push) Successful in 21s
CI / Security audit (push) Successful in 39s
CI / Tests & coverage (push) Successful in 42s
2026-05-17 13:12:58 +01:00
e8ffd7f7dd feat(ui): split downloads and history into tabs 2026-05-17 13:09:01 +01:00
557137421d fix(history): reload history when showAll toggle changes 2026-05-17 13:02:15 +01:00
eb321312dc feat(history): add Recently Completed section to frontend dashboard 2026-05-17 12:05:39 +01:00
a4004f5e7a fix: progress bar width collapsed by pill display:inline-flex
All checks were successful
Build and Push Docker Image / build (push) Successful in 29s
CI / Security audit (push) Successful in 47s
CI / Tests & coverage (push) Successful in 52s
The pill redesign set display:inline-flex + white-space:nowrap on all
.detail-item elements. The .progress-item (which extends .detail-item)
was then shrinking the .progress-bar to zero usable width.

Override pill styles on .progress-item: display:flex, no background,
no padding, white-space:normal. Also give .progress-container flex:1
so it expands to fill the row.
2026-05-17 09:56:41 +01:00
fd0d5cf6ec fix: progress bar not rendering — replace float:left with position:absolute
All checks were successful
Build and Push Docker Image / build (push) Successful in 29s
CI / Security audit (push) Successful in 50s
CI / Tests & coverage (push) Successful in 56s
float:left on .progress-segment was ignored inside the overflow:hidden
position:relative .progress-bar container, so the coloured fill never
appeared. Absolute positioning from top:0 left:0 with the JS-assigned
width renders correctly.
2026-05-17 09:53:55 +01:00
1f293ae70b ui: compact pill layout for detail items; red availability warning
All checks were successful
Build and Push Docker Image / build (push) Successful in 38s
CI / Security audit (push) Successful in 56s
CI / Tests & coverage (push) Successful in 1m1s
- Detail items (Size, Progress, Speed, ETA, Seeds, Peers, Availability,
  Completed) now render as inline pill badges with background + border-
  radius that wrap naturally on any screen width
- Remove mobile @media override that forced flex-direction:column,
  which was causing one-per-line centred layout on small screens
- Availability < 100%: value text shown in red (--danger) bold, both
  on card creation and on live SSE update via classList.toggle
- Also ensures updateDownloadCard keeps availability-warning in sync
2026-05-17 09:51:04 +01:00
7ff29b669c fix(ui): status panel empty on login / requires double-click to open
Some checks failed
Build and Push Docker Image / build (push) Successful in 26s
CI / Security audit (push) Successful in 40s
CI / Tests & coverage (push) Failing after 36s
showDashboard now explicitly resets the status panel to display:none and
clears its innerHTML on every call. This prevents a stale display value
from a previous session making toggleStatusPanel think it is already open
(causing it to hide on the first click instead of showing).

Also cancel the status refresh timer on logout.
2026-05-17 09:02:00 +01:00
0dbf0e0899 fix: set timing bar widths via JS DOM assignment after innerHTML
Some checks failed
Build and Push Docker Image / build (push) Successful in 21s
CI / Security audit (push) Successful in 40s
CI / Tests & coverage (push) Failing after 51s
All previous attempts (inline style=, CSS custom property via style=)
were ineffective. Setting element.style.width directly in JS after
panel.innerHTML is assigned is the only approach that cannot be
interfered with by CSP or attribute sanitisation.

Width is stored as data-w attribute in the HTML string and applied
by querySelectorAll('.timing-bar[data-w]') post-render.
2026-05-17 08:59:21 +01:00
67a8610843 fix: use CSS custom property for timing bar width to bypass CSP blocking
Some checks failed
Build and Push Docker Image / build (push) Successful in 23s
CI / Security audit (push) Successful in 39s
CI / Tests & coverage (push) Failing after 35s
Inline style= attributes containing property:value pairs are blocked by
strict style-src-attr CSP. CSS custom properties (--foo:value) set via
style= are treated as data not styles and are not subject to this
restriction. The width is now resolved in the stylesheet via
var(--bar-w, 100%) so CSP cannot interfere.
2026-05-17 08:55:06 +01:00
cafa608e8c fix: allow inline style= attributes via CSP style-src-attr
Some checks failed
Build and Push Docker Image / build (push) Successful in 23s
CI / Security audit (push) Successful in 45s
CI / Tests & coverage (push) Failing after 46s
Timing bars in the status panel and any other dynamically-injected
style= attributes were being silently blocked by the Content Security
Policy. style-src only governs <style> blocks and linked stylesheets;
inline element attributes need style-src-attr separately.

Adding style-src-attr 'unsafe-inline' is the minimal fix — it only
affects attribute-level inline styles, not script execution.

Also removes the temporary debug console.log added in the previous commit.
2026-05-17 08:53:07 +01:00
35d50fad0a debug: log task timing data in status panel to diagnose full bars
Some checks failed
Build and Push Docker Image / build (push) Successful in 21s
CI / Security audit (push) Successful in 41s
CI / Tests & coverage (push) Failing after 42s
2026-05-17 08:50:13 +01:00