Add diagnostic drilldowns
This commit is contained in:
@@ -3,12 +3,69 @@ const button = document.querySelector('#analyze-button');
|
||||
const errorBox = document.querySelector('#error-message');
|
||||
const results = document.querySelector('#dashboard');
|
||||
const infoButtons = document.querySelectorAll('.info-button');
|
||||
const drillTriggers = document.querySelectorAll('[data-detail]');
|
||||
const drilldownTitle = document.querySelector('#drilldown-title');
|
||||
const drilldownCount = document.querySelector('#drilldown-count');
|
||||
const drilldownSummary = document.querySelector('#drilldown-summary');
|
||||
const drilldownList = document.querySelector('#drilldown-list');
|
||||
let latestAnalysis = null;
|
||||
|
||||
function expandHome(path) {
|
||||
return path.trim();
|
||||
}
|
||||
|
||||
function escapeHtml(value) {
|
||||
return String(value ?? '').replace(/[&<>"']/g, (character) => ({
|
||||
'&': '&',
|
||||
'<': '<',
|
||||
'>': '>',
|
||||
'"': '"',
|
||||
"'": ''',
|
||||
}[character]));
|
||||
}
|
||||
|
||||
function detailLines(item) {
|
||||
if (item.files) {
|
||||
return item.files.map((file) => `<li>${escapeHtml(file)}</li>`).join('');
|
||||
}
|
||||
const lines = [];
|
||||
if (item.artist || item.title) lines.push(`${item.artist || 'Unknown artist'} — ${item.title || item.filename}`);
|
||||
if (item.crate) lines.push(`Crate: ${item.crate}`);
|
||||
if (item.saved_path) lines.push(`Saved path: ${item.saved_path}`);
|
||||
if (item.candidate) lines.push(`Candidate: ${item.candidate}`);
|
||||
if (item.path) lines.push(`File: ${item.path}`);
|
||||
if (item.target) lines.push(`Target: ${item.target}`);
|
||||
if (item.score || item.reason) lines.push(`${item.score || 'Match'} · ${item.reason || 'Candidate found'}`);
|
||||
if (item.repeated_filename) lines.push('Same filename appears more than once in Serato’s missing list.');
|
||||
return lines.map((line) => `<li>${escapeHtml(line)}</li>`).join('');
|
||||
}
|
||||
|
||||
function renderDetail(key) {
|
||||
const detail = latestAnalysis?.details?.[key];
|
||||
if (!detail) return;
|
||||
|
||||
drillTriggers.forEach((trigger) => {
|
||||
trigger.classList.toggle('selected', trigger.dataset.detail === key);
|
||||
});
|
||||
drilldownTitle.textContent = detail.title;
|
||||
drilldownCount.textContent = `${detail.total ?? 0} found`;
|
||||
drilldownSummary.textContent = detail.summary;
|
||||
|
||||
if (!detail.items?.length) {
|
||||
drilldownList.innerHTML = '<div class="empty-detail">Nothing to review here. Tiny victory parade, very tasteful.</div>';
|
||||
return;
|
||||
}
|
||||
|
||||
drilldownList.innerHTML = detail.items.map((item) => `
|
||||
<article class="detail-item">
|
||||
<strong>${escapeHtml(item.filename || item.path || 'Untitled item')}</strong>
|
||||
<ul>${detailLines(item)}</ul>
|
||||
</article>
|
||||
`).join('');
|
||||
}
|
||||
|
||||
function render(data) {
|
||||
latestAnalysis = data;
|
||||
document.querySelectorAll('[data-field]').forEach((element) => {
|
||||
const value = data[element.dataset.field];
|
||||
element.textContent = value ?? '—';
|
||||
@@ -21,6 +78,7 @@ function render(data) {
|
||||
: score >= 95 ? 'Looking excellent' : score >= 80 ? 'A few things need attention' : 'Review recommended';
|
||||
document.querySelector('#score-basis').textContent = data.score_basis;
|
||||
document.querySelector('#analysis-time').textContent = `Completed ${new Date().toLocaleTimeString([], {hour: '2-digit', minute: '2-digit'})}`;
|
||||
renderDetail(data.database_missing_paths > 0 ? 'database_missing_tracks' : 'old_crate_references');
|
||||
results.hidden = false;
|
||||
results.scrollIntoView({behavior: 'smooth', block: 'start'});
|
||||
}
|
||||
@@ -44,6 +102,16 @@ infoButtons.forEach((infoButton) => {
|
||||
});
|
||||
});
|
||||
|
||||
drillTriggers.forEach((trigger) => {
|
||||
trigger.addEventListener('click', () => renderDetail(trigger.dataset.detail));
|
||||
trigger.addEventListener('keydown', (event) => {
|
||||
if (event.key === 'Enter' || event.key === ' ') {
|
||||
event.preventDefault();
|
||||
renderDetail(trigger.dataset.detail);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
document.addEventListener('click', () => closeInfoButtons());
|
||||
document.addEventListener('keydown', (event) => {
|
||||
if (event.key === 'Escape') closeInfoButtons();
|
||||
|
||||
Reference in New Issue
Block a user