From 0594673cadc6311b541d924d78469cee6f4ddc91 Mon Sep 17 00:00:00 2001 From: Broque Thomas <26755000+Nezreka@users.noreply.github.com> Date: Sun, 15 Mar 2026 13:00:44 -0700 Subject: [PATCH] Polish finding detail renderers with richer visuals - Cover art findings: show artwork image thumbnail preview - Duplicate findings: KEEP/REMOVE badges highlighting best quality copy - Incomplete album: completion progress bar with percentage - Fake lossless: spectral analysis bar comparing detected vs expected cutoff - Resolved findings: show descriptive action label (e.g. "Entry Removed") - Fix operator precedence bug in fake lossless nyquist calculation --- webui/static/script.js | 87 +++++++++++++++++++++++------- webui/static/style.css | 118 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 187 insertions(+), 18 deletions(-) diff --git a/webui/static/script.js b/webui/static/script.js index 39353a17..e40bcb7a 100644 --- a/webui/static/script.js +++ b/webui/static/script.js @@ -50438,8 +50438,17 @@ async function loadRepairFindings() { container.innerHTML = items.map(f => { const icon = severityIcons[f.severity] || 'ℹ️'; const age = formatCacheAge(f.created_at); - const statusBadge = f.status !== 'pending' ? - `${f.status}` : ''; + const actionLabels = { + removed_db_entry: 'Entry Removed', deleted_file: 'File Deleted', + already_gone: 'Already Gone', fixed_track_number: 'Track # Fixed', + applied_cover_art: 'Art Applied', applied_metadata: 'Metadata Applied', + removed_duplicates: 'Duplicates Removed', + }; + let statusBadge = ''; + if (f.status !== 'pending') { + const actionText = actionLabels[f.user_action] || f.status; + statusBadge = `${actionText}`; + } const typeLabel = typeLabels[f.finding_type] || f.finding_type.replace(/_/g, ' '); const d = f.details || {}; const filePath = f.file_path || d.original_path || d.file_path || ''; @@ -50555,41 +50564,76 @@ function _renderFindingDetail(f) { if (f.file_path) rows.push(['File', f.file_path, 'path']); return _gridRows(rows); - case 'fake_lossless': + case 'fake_lossless': { + const cutoff = d.detected_cutoff_khz || 0; + const expectedMin = d.expected_min_khz || 0; + const nyquist = d.nyquist_khz || (d.sample_rate ? d.sample_rate / 2000 : 22.05); + let flHtml = ''; + if (cutoff && expectedMin) { + const cutoffPct = Math.min(100, Math.round((cutoff / nyquist) * 100)); + const expectedPct = Math.min(100, Math.round((expectedMin / nyquist) * 100)); + flHtml += `
`; + } if (d.format) rows.push(['Format', d.format.toUpperCase()]); - rows.push(['Spectral Cutoff', `${d.detected_cutoff_khz || '?'} kHz`]); - rows.push(['Expected Min', `${d.expected_min_khz || '?'} kHz`]); if (d.sample_rate) rows.push(['Sample Rate', `${d.sample_rate} Hz`]); - if (d.nyquist_khz) rows.push(['Nyquist', `${d.nyquist_khz} kHz`]); if (d.bit_depth) rows.push(['Bit Depth', `${d.bit_depth}-bit`]); if (d.bitrate) rows.push(['Bitrate', `${d.bitrate} kbps`]); if (d.file_size) rows.push(['File Size', _formatFileSize(d.file_size)]); if (f.file_path) rows.push(['File', f.file_path, 'path']); - return _gridRows(rows); + return flHtml + _gridRows(rows); + } case 'duplicate_tracks': if (!d.tracks || !d.tracks.length) return _gridRows([['Count', d.count || '?']]); - return `