Fix history: correct score field name + add delete button

- api.php: read accessibility_score (not score) from result.json
- api.php: handleDelete() also removes .dismissed.json, .overrides.json, .error.log
- js/app.js: add Delete button to each history row with confirm dialog
- css/styles.css: red hover style for delete button

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Vadym Samoilenko 2026-03-13 15:13:30 +00:00
parent 0443cb450a
commit 1126c8a700
3 changed files with 41 additions and 6 deletions

13
api.php
View file

@ -715,9 +715,9 @@ function handleList() {
if (file_exists($result_file)) {
$job_data['status'] = 'completed';
$result = json_decode(file_get_contents($result_file), true);
$job_data['score'] = $result['score'] ?? null;
$job_data['grade'] = $result['grade'] ?? null;
$job_data['total_issues'] = $result['total_issues'] ?? null;
$job_data['score'] = $result['accessibility_score'] ?? ($result['score'] ?? null);
$job_data['grade'] = $result['grade'] ?? null;
$job_data['total_issues'] = $result['total_issues'] ?? null;
$job_data['critical_count'] = $result['severity_counts']['critical'] ?? 0;
$job_data['error_count'] = $result['severity_counts']['error'] ?? 0;
}
@ -752,10 +752,13 @@ function handleDelete() {
$job_data = json_decode(file_get_contents($meta_file), true);
// Delete files
@unlink($job_data['filepath']);
// Delete all files associated with this job
@unlink($job_data['filepath'] ?? '');
@unlink($meta_file);
@unlink(RESULTS_DIR . '/' . $job_id . '.result.json');
@unlink(RESULTS_DIR . '/' . $job_id . '.dismissed.json');
@unlink(RESULTS_DIR . '/' . $job_id . '.overrides.json');
@unlink(RESULTS_DIR . '/' . $job_id . '.error.log');
success(['message' => 'Job deleted']);
}

View file

@ -1658,6 +1658,11 @@ h1::before {
color: var(--accent);
}
.history-action-delete:hover {
border-color: var(--error);
color: var(--error);
}
/* ── Reduced Motion ── */
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {

View file

@ -155,6 +155,7 @@ function renderHistory(jobs) {
const jsonBtn = j.status === 'completed'
? `<a class="history-action-btn" href="api.php?action=export&job_id=${j.job_id}&format=json" target="_blank" title="Download JSON">JSON</a>`
: '';
const deleteBtn = `<button class="history-action-btn history-action-delete" onclick="deleteHistoryJob('${j.job_id}', this)" title="Delete">&#x1F5D1;</button>`;
return `<tr>
<td class="history-filename" title="${escapeHtml(j.original_filename || '')}">${name}</td>
@ -162,7 +163,7 @@ function renderHistory(jobs) {
<td>${status}</td>
<td><span class="history-score ${scoreClass}">${score}${j.score != null ? '<small>/100</small>' : ''}</span> <span class="history-grade">${grade}</span></td>
<td>${critical > 0 ? `<span class="history-crit">${critical} crit</span>` : ''} ${errors > 0 ? `<span class="history-err">${errors} err</span>` : ''}${!critical && !errors ? '<span style="color:var(--success)">✓ Clean</span>' : ''}</td>
<td class="history-actions">${openBtn}${htmlBtn}${pdfBtn}${jsonBtn}</td>
<td class="history-actions">${openBtn}${htmlBtn}${pdfBtn}${jsonBtn}${deleteBtn}</td>
</tr>`;
}).join('');
@ -194,6 +195,32 @@ function escapeHtml(str) {
.replace(/"/g, '&quot;');
}
async function deleteHistoryJob(jobId, btn) {
if (!confirm('Delete this document and its report?')) return;
btn.disabled = true;
try {
const formData = new FormData();
formData.append('job_id', jobId);
const data = await apiCall('delete', { method: 'POST', body: formData });
if (data.success) {
btn.closest('tr').remove();
// Show empty state if no rows left
const tbody = document.querySelector('.history-table tbody');
if (tbody && !tbody.querySelector('tr')) {
document.querySelector('.history-table').remove();
const empty = document.getElementById('historyEmpty');
if (empty) empty.style.display = '';
}
} else {
alert('Delete failed: ' + (data.error || 'Unknown error'));
btn.disabled = false;
}
} catch (e) {
alert('Delete failed.');
btn.disabled = false;
}
}
async function openHistoryJob(jobId) {
// Show results section and load the job — reuse the existing display flow
currentJobId = jobId;