Similar Artists worker: dashboard enrichment bubble

Adds the dashboard status bubble (the small icon row) for the Similar Artists
worker, alongside the modal entry. Mirrors the per-source bubbles: MusicMap logo,
purple accent, spinner + active/complete/paused states, hover tooltip, and a 2s
status poll against /api/enrichment/similar_artists/status. Click toggles
pause/resume. Tooltip shows matched/pending (the worker has no artist/album/track
phases). 74 JS integrity tests pass.
This commit is contained in:
BoulderBadgeDad 2026-06-03 15:19:46 -07:00
parent 89e3486e84
commit d70d410f6f
3 changed files with 165 additions and 0 deletions

View file

@ -565,6 +565,29 @@
</div>
</div>
</div>
<!-- Similar Artists (MusicMap) Enrichment Status Icon -->
<div class="similar-artists-enrich-button-container">
<button class="similar-artists-enrich-button" id="similar-artists-enrich-button" title="Similar Artists (MusicMap) Enrichment"
onclick="toggleSimilarArtistsEnrichment()">
<img src="https://www.music-map.com/elements/objects/og_logo.png"
alt="Similar Artists" class="similar-artists-enrich-logo">
<div class="similar-artists-enrich-spinner"></div>
</button>
<div class="similar-artists-enrich-tooltip" id="similar-artists-enrich-tooltip">
<div class="similar-artists-enrich-tooltip-content">
<div class="similar-artists-enrich-tooltip-header">Similar Artists Enrichment</div>
<div class="similar-artists-enrich-tooltip-body" id="similar-artists-enrich-tooltip-body">
<div class="tooltip-status">Status: <span
id="similar-artists-enrich-tooltip-status">Idle</span>
</div>
<div class="tooltip-current" id="similar-artists-enrich-tooltip-current">No active matches
</div>
<div class="tooltip-progress" id="similar-artists-enrich-tooltip-progress">Progress: 0 / 0
</div>
</div>
</div>
</div>
</div>
<!-- Hydrabase P2P Mirror Status Icon -->
<div class="hydrabase-button-container" id="hydrabase-button-container" style="display: none;">
<button class="hydrabase-button" id="hydrabase-button" title="Hydrabase P2P Mirror">

View file

@ -1311,6 +1311,80 @@ if (document.readyState === 'loading') {
}
}
// ===================================================================
// SIMILAR ARTISTS (MUSICMAP) WORKER — dashboard bubble
// ===================================================================
async function updateSimilarArtistsEnrichmentStatus() {
if (socketConnected) return;
if (document.hidden) return;
try {
const response = await fetch('/api/enrichment/similar_artists/status');
if (!response.ok) return;
updateSimilarArtistsEnrichmentStatusFromData(await response.json());
} catch (error) {
console.error('Error updating Similar Artists enrichment status:', error);
}
}
function updateSimilarArtistsEnrichmentStatusFromData(data) {
const button = document.getElementById('similar-artists-enrich-button');
if (!button) return;
button.classList.remove('active', 'paused', 'complete');
if (data.paused) button.classList.add('paused');
else if (data.idle) button.classList.add('complete');
else if (data.running && !data.paused) button.classList.add('active');
const tStatus = document.getElementById('similar-artists-enrich-tooltip-status');
const tCurrent = document.getElementById('similar-artists-enrich-tooltip-current');
const tProgress = document.getElementById('similar-artists-enrich-tooltip-progress');
if (tStatus) {
if (data.paused) tStatus.textContent = 'Paused';
else if (data.idle) tStatus.textContent = 'Complete';
else if (data.running) tStatus.textContent = 'Running';
else tStatus.textContent = 'Idle';
}
if (tCurrent) {
if (data.idle) tCurrent.textContent = 'All library artists processed';
else if (data.current_item) tCurrent.textContent = `Now: ${data.current_item}`;
else tCurrent.textContent = 'No active matches';
}
// This worker has no artist/album/track phases — show its matched/pending tally.
if (tProgress && data.stats) {
const s = data.stats;
tProgress.textContent = `${s.matched || 0} matched · ${s.pending || 0} pending`;
}
}
async function toggleSimilarArtistsEnrichment() {
try {
const button = document.getElementById('similar-artists-enrich-button');
if (!button) return;
const isRunning = button.classList.contains('active');
const endpoint = isRunning ? '/api/enrichment/similar_artists/pause' : '/api/enrichment/similar_artists/resume';
const response = await fetch(endpoint, { method: 'POST' });
if (!response.ok) throw new Error(`Failed to ${isRunning ? 'pause' : 'resume'} Similar Artists enrichment`);
await updateSimilarArtistsEnrichmentStatus();
} catch (error) {
console.error('Error toggling Similar Artists enrichment:', error);
showToast(`Error: ${error.message}`, 'error');
}
}
(function _wireSimilarArtistsBubble() {
const wire = () => {
const button = document.getElementById('similar-artists-enrich-button');
if (button) {
updateSimilarArtistsEnrichmentStatus();
setInterval(updateSimilarArtistsEnrichmentStatus, 2000);
}
};
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', wire);
else wire();
})();
// ===================================================================
// HYDRABASE P2P MIRROR WORKER
// ===================================================================

View file

@ -39710,6 +39710,74 @@ div.artist-hero-badge {
font-weight: 600;
}
/* Similar Artists (MusicMap relationship worker) dashboard bubble mirrors the
per-source bubbles with a purple accent. The MusicMap logo is a wide branded
image, so it's cover-cropped + rounded rather than icon-filtered. */
.similar-artists-enrich-button-container { position: relative; display: inline-block; margin-right: 12px; }
.similar-artists-enrich-button {
position: relative; width: 44px; height: 44px;
background: linear-gradient(135deg, rgba(168,85,247,0.10) 0%, rgba(124,58,237,0.16) 100%);
backdrop-filter: blur(20px) saturate(1.4); -webkit-backdrop-filter: blur(20px) saturate(1.4);
border: 1.5px solid rgba(168,85,247,0.22); border-radius: 50%; cursor: pointer;
display: flex; align-items: center; justify-content: center;
transition: all 0.3s cubic-bezier(0.4,0,0.2,1);
box-shadow: 0 4px 16px rgba(168,85,247,0.12), 0 2px 8px rgba(0,0,0,0.15), inset 0 1px 0 rgba(255,255,255,0.08);
}
.similar-artists-enrich-logo {
width: 26px; height: 26px; opacity: 0.7; object-fit: cover; border-radius: 7px;
transition: all 0.3s ease;
}
.similar-artists-enrich-button:hover {
transform: scale(1.1); border-color: rgba(168,85,247,0.45);
box-shadow: 0 6px 24px rgba(168,85,247,0.28), 0 3px 12px rgba(0,0,0,0.2), inset 0 1px 0 rgba(255,255,255,0.12);
}
.similar-artists-enrich-spinner {
position: absolute; width: 44px; height: 44px; border: 3px solid transparent;
border-top-color: rgba(168,85,247,0.85); border-right-color: rgba(168,85,247,0.5);
border-radius: 50%; opacity: 0; transition: opacity 0.3s ease; pointer-events: none;
}
@keyframes similar-artists-enrich-spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
.similar-artists-enrich-button.active .similar-artists-enrich-spinner { opacity: 1; animation: similar-artists-enrich-spin 1.2s linear infinite; }
.similar-artists-enrich-button.active {
background: linear-gradient(135deg, rgba(168,85,247,0.20) 0%, rgba(124,58,237,0.26) 100%);
border-color: rgba(168,85,247,0.55);
box-shadow: 0 6px 24px rgba(168,85,247,0.35), 0 3px 12px rgba(0,0,0,0.2), inset 0 1px 0 rgba(255,255,255,0.15);
}
.similar-artists-enrich-button.active .similar-artists-enrich-logo { opacity: 1; }
.similar-artists-enrich-button.complete {
background: linear-gradient(135deg, rgba(76,175,80,0.15) 0%, rgba(56,142,60,0.20) 100%);
border-color: rgba(76,175,80,0.35);
box-shadow: 0 4px 16px rgba(76,175,80,0.2), 0 2px 8px rgba(0,0,0,0.15), inset 0 1px 0 rgba(255,255,255,0.08);
}
.similar-artists-enrich-button.complete .similar-artists-enrich-spinner { opacity: 0; }
.similar-artists-enrich-button.paused {
background: linear-gradient(135deg, rgba(255,193,7,0.12) 0%, rgba(255,152,0,0.18) 100%);
border-color: rgba(255,193,7,0.35);
box-shadow: 0 4px 16px rgba(255,193,7,0.2), 0 2px 8px rgba(0,0,0,0.15), inset 0 1px 0 rgba(255,255,255,0.08);
}
.similar-artists-enrich-button.paused .similar-artists-enrich-logo { opacity: 0.5; }
.similar-artists-enrich-button.paused .similar-artists-enrich-spinner { opacity: 0; }
.similar-artists-enrich-tooltip {
position: absolute; left: 50%; top: calc(100% + 12px);
transform: translateX(-50%) translateY(-5px); z-index: 5000;
opacity: 0; visibility: hidden; transition: all 0.3s cubic-bezier(0.4,0,0.2,1); pointer-events: none;
}
.similar-artists-enrich-button:hover + .similar-artists-enrich-tooltip { opacity: 1; visibility: visible; transform: translateX(-50%) translateY(0); }
.similar-artists-enrich-tooltip-content {
min-width: 260px;
background: linear-gradient(135deg, rgba(30,30,30,0.98) 0%, rgba(20,20,20,0.99) 100%);
backdrop-filter: blur(40px) saturate(1.6); -webkit-backdrop-filter: blur(40px) saturate(1.6);
border: 1px solid rgba(255,255,255,0.3); border-radius: 16px; padding: 16px 18px;
box-shadow: 0 12px 40px rgba(0,0,0,0.5), 0 6px 20px rgba(0,0,0,0.3), inset 0 1px 0 rgba(255,255,255,0.1);
}
.similar-artists-enrich-tooltip-header {
font-family: 'SF Pro Display', -apple-system, sans-serif; font-size: 13px; font-weight: 600;
color: rgba(255,255,255,0.95); letter-spacing: -0.2px; margin-bottom: 12px;
padding-bottom: 10px; border-bottom: 1px solid rgba(255,255,255,0.08);
}
.similar-artists-enrich-tooltip-body { display: flex; flex-direction: column; gap: 8px; }
#similar-artists-enrich-tooltip-status { color: #c084fc; font-weight: 600; }
.deezer-button-container {
position: relative;
display: inline-block;