From 6a619254df8b26b89a716f0d78bfe90289b2bec3 Mon Sep 17 00:00:00 2001 From: Broque Thomas <26755000+Nezreka@users.noreply.github.com> Date: Wed, 27 May 2026 19:38:43 -0700 Subject: [PATCH] Auto-Sync: weekly board cards now match the hourly board MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the Weekly Board shipped, its scheduled-card visual diverged from the hourly board's: weekly cards showed only the playlist name + weekly label + timezone, while hourly cards already carried a full action row (Run-now button, unschedule X, next-run countdown, health badge). Two boards looking like different apps. Standardised the weekly card on the hourly shape so a day-column drop produces the exact same affordances as an interval-bucket drop: - Health badge (warning ⚠ / failing !) when recent runs errored - Source + track-count meta line under the name - Timing line: weekly label + tz pill + next-run countdown - Run-now button (disabled while pipeline running, same gating logic the hourly card already had) - Unschedule X — calls the weekly-specific helper, leaving hourly schedules untouched Click anywhere outside the buttons still opens the weekly editor for changing days / time / tz. Weekly cards also become draggable between day columns now — drop on a new column appends the day to the schedule (matches the multi-day editor flow). --- webui/static/auto-sync.js | 41 +++++++++++++++++++++++++++++++++------ webui/static/helper.js | 1 + 2 files changed, 36 insertions(+), 6 deletions(-) diff --git a/webui/static/auto-sync.js b/webui/static/auto-sync.js index 88d981c0..2ffaf8fc 100644 --- a/webui/static/auto-sync.js +++ b/webui/static/auto-sync.js @@ -610,16 +610,45 @@ function renderAutoSyncWeeklyPanel(playlists, playlistSchedules) { function autoSyncWeeklyCardHtml(playlist, schedule) { - const enabled = schedule.enabled !== false; + // Mirror the hourly board's ``autoSyncScheduledCardHtml`` shape so + // the two boards stay visually consistent — same name + meta + + // timing + actions row regardless of whether the schedule is + // hourly or weekday-based. The only per-board differences are: + // - timing line: weekly label vs interval label + // - click opens the weekly editor (hourly board has no editor) + // - drag fns use the weekly-specific ondragstart / ondragend + // - unschedule calls the weekly-specific helper + const enabled = schedule?.enabled !== false; + const nextLabel = schedule?.next_run ? autoSyncNextRunLabel(schedule.next_run) : ''; + const isRunning = playlist.pipeline_state?.status === 'running'; + const health = autoSyncPlaylistHealth(playlist.id); + const healthClass = health.level === 'failing' ? 'failing' + : health.level === 'warning' ? 'warning' + : ''; const label = autoSyncWeeklyLabel(schedule); + const tz = schedule?.tz || 'UTC'; return ` -
-
${_esc(playlist.name)}
-
- ${_esc(label)} - ${_esc(schedule.tz || 'UTC')} +
+
+ ${health.level !== 'ok' ? `${health.level === 'failing' ? '!' : '⚠'}` : ''} + ${_esc(playlist.name)} +
+
${_esc(autoSyncSourceLabel(playlist.source))} · ${playlist.track_count || 0} tracks
+
+ ${_esc(label)} + ${_esc(tz)} + ${nextLabel ? `${_esc(nextLabel)}` : ''} +
+
+
+ +
`; diff --git a/webui/static/helper.js b/webui/static/helper.js index 4f2f7292..d2598943 100644 --- a/webui/static/helper.js +++ b/webui/static/helper.js @@ -3415,6 +3415,7 @@ function closeHelperSearch() { const WHATS_NEW = { '2.6.3': [ { unreleased: true }, + { title: 'Auto-Sync: weekly board cards now match the hourly board', desc: 'when the Weekly Board shipped, its scheduled-card visual diverged from the hourly board — weekly cards only showed the playlist name + weekly label + timezone, while hourly cards carry the full action row (Run now button, unschedule X, next-run countdown, health badge). Standardised the weekly card on the hourly shape so dropping a playlist onto a day column produces a card with the exact same affordances as dropping it onto an hourly bucket: health indicator dot when recent runs failed, source + track count meta line, weekly label + timezone + "next in Nh" pills, Run-now button (disabled while pipeline is running, same gating as hourly), and an unschedule X. Click anywhere outside the buttons still opens the weekly editor for changing days / time / tz. Weekly cards also became draggable between day columns now — drop on a new column appends that day to the schedule (matches the existing multi-day editor flow).', page: 'automations' }, { title: 'Dashboard: enrichment equalizer bars get next-level polish', desc: 'follow-up to the equalizer redesign. four upgrades that take the bars from "nice" to "vibey": (1) every bar now carries a circular avatar disc above the track loading the service\'s real brand logo (the same images the header-action worker orbs use — Spotify, Apple Music, Deezer, Last.fm, Genius, MusicBrainz, AudioDB, Tidal, Qobuz, Discogs, Amazon Music). Disc has a dark glass backdrop, accent-tinted ring, and slow halo pulse when the worker is running; the brand color shows through as a drop-shadow on the logo + ring tint. Initial-letter fallback kicks in automatically if any CDN URL fails; (2) peak-flash detector — when the worker\'s calls/min actually steps upward between updates, the peak tip briefly flares white-hot and the fill flashes brighter for ~650ms, like a hardware VU meter\'s peak-detect LED catching a beat. only fires on real increases above a noise threshold so jitter doesn\'t pulse the bar constantly; (3) rolling number counter — the live count digit-animates from old→new value with easeOutCubic instead of snapping, the same premium-counter feel you\'d see on a fancy dashboard; (4) glass-surface reflection puddle under each bar — soft accent-colored glow whose opacity tracks the real (unclamped) rate, so the row looks like the bars are standing on a polished pane rather than floating in space. puddle ripples on peak-flash too. all four tied together by the same --eq-accent / --eq-glow CSS variables so future tweaks stay coherent.', page: 'dashboard' }, { title: 'Dashboard: equalizer-bar redesign for the Enrichment Services panel', desc: 'the enrichment rate monitor on the dashboard used a 10-column grid of circular speedometers, which (a) lost symmetry the moment a new service was added — 11 services meant 10 in one row and a lonely orphan in the next, (b) wasted ~80% of pixels on empty gauge arcs showing "0" most of the time. Replaced with a VU-meter / equalizer-bar row: each service is a vertical capsule with the service\'s brand-color fill height tracking calls/min, a continuous shimmer scan + glowing peak tip when active, a slow breathing animation when idle, and a red pulsing variant when rate-limited. Symmetric by design at any service count — the row uses flex with even gaps so new services just slot in. Bar tip + value text adapt color to the service\'s accent. Status pill below each bar (Running / Idle / Paused / Stopped) with its own pulsing dot. Click any bar to open the same detail modal the speedometer used; nothing changed about the underlying data flow.', page: 'dashboard' }, { title: 'Auto-Sync: fix ListenBrainz pipelines stuck on "Refreshing:" for 5+ minutes', desc: 'Auto-Sync pipeline runs against a ListenBrainz playlist (Weekly Jams / Weekly Exploration / Top Discoveries / etc.) would sit on "Refreshing: \'\'" for minutes with zero UI updates before anything else happened. Two real bugs ganging up: (1) the refresh path ran the LB matching engine on every track to produce matched_data — 5+ minutes blocking with no progress emission — and Phase 2 of the pipeline then ran the SAME matching engine on the same tracks via the discovery worker. So LB tracks discovered twice, the first time silently. (2) ListenBrainz manager only exposed an `update_all_playlists` entry-point — refreshing one playlist re-pulled all 12+ cached LB playlists\' details from the API even though we only cared about one. Pipeline now skips the refresh-side discovery (Phase 2 handles it with progress emits every 3s — same pattern that already works for Spotify); refresh uses a new targeted `LBManager.refresh_playlist(mbid)` that hits just the requested playlist. Also killed a silent `except Exception: pass` in the LB adapter that was masking real API failures as stale-cache hits — refresh errors now log with traceback and surface to the run-history error tally. Pinned with 12 new unit tests.', page: 'automations' },