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:
parent
89e3486e84
commit
d70d410f6f
3 changed files with 165 additions and 0 deletions
|
|
@ -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">
|
||||
|
|
|
|||
|
|
@ -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
|
||||
// ===================================================================
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in a new issue