Add clear findings button to library maintenance modal

Per-job and per-status filtering — respects active toolbar filters so
users can clear e.g. only track number findings or only dismissed items.
Confirmation uses the app's styled modal instead of browser confirm().
This commit is contained in:
Broque Thomas 2026-03-16 15:37:33 -07:00
parent 658f5c60f7
commit 42a4285e09
5 changed files with 107 additions and 1 deletions

View file

@ -1075,6 +1075,36 @@ class RepairWorker:
if conn:
conn.close()
def clear_findings(self, job_id: str = None, status: str = None) -> int:
"""Delete findings from the database. Optionally filter by job_id and/or status. Returns count deleted."""
conn = None
try:
conn = self.db._get_connection()
cursor = conn.cursor()
conditions = []
params = []
if job_id:
conditions.append("job_id = ?")
params.append(job_id)
if status:
conditions.append("status = ?")
params.append(status)
where = f" WHERE {' AND '.join(conditions)}" if conditions else ""
cursor.execute(f"SELECT COUNT(*) FROM repair_findings{where}", params)
count = cursor.fetchone()[0]
cursor.execute(f"DELETE FROM repair_findings{where}", params)
conn.commit()
logger.info("Cleared %d findings%s%s", count,
f" for job {job_id}" if job_id else "",
f" with status {status}" if status else "")
return count
except Exception as e:
logger.error("Error clearing findings: %s", e)
return 0
finally:
if conn:
conn.close()
def _get_findings_count(self, status: str = None) -> int:
"""Get count of findings by status."""
conn = None

View file

@ -39031,6 +39031,23 @@ def repair_findings_bulk():
logger.error(f"Error bulk updating findings: {e}")
return jsonify({'error': str(e)}), 500
@app.route('/api/repair/findings/clear', methods=['POST'])
def repair_findings_clear():
"""Clear (delete) findings, optionally filtered by job_id and/or status"""
try:
if repair_worker is None:
return jsonify({'error': 'Repair worker not initialized'}), 400
data = request.get_json(silent=True) or {}
job_id = data.get('job_id')
status = data.get('status')
count = repair_worker.clear_findings(job_id=job_id, status=status)
return jsonify({'success': True, 'deleted': count}), 200
except Exception as e:
logger.error(f"Error clearing findings: {e}")
return jsonify({'error': str(e)}), 500
@app.route('/api/repair/history', methods=['GET'])
def repair_history():
"""Get job run history"""

View file

@ -5774,6 +5774,7 @@
<button class="repair-bulk-btn fix" onclick="bulkFixFindings()">Fix Selected</button>
<button class="repair-bulk-btn" onclick="bulkRepairAction('dismiss')">Dismiss Selected</button>
</div>
<button class="repair-clear-btn" onclick="clearRepairFindings()" title="Clear findings matching current filters">Clear Findings</button>
</div>
<div class="repair-findings-list" id="repair-findings-list">
<div class="repair-loading">Loading findings...</div>

View file

@ -52617,6 +52617,47 @@ async function bulkFixFindings() {
updateRepairStatus();
}
async function clearRepairFindings() {
const jobFilter = document.getElementById('repair-findings-job-filter');
const statusFilter = document.getElementById('repair-findings-status-filter');
const jobId = jobFilter ? jobFilter.value : '';
const status = statusFilter ? statusFilter.value : '';
const scopeLabel = jobId ? jobId.replace(/_/g, ' ') : 'all jobs';
const statusLabel = status ? ` (${status})` : '';
if (!await showConfirmDialog({
title: 'Clear Findings',
message: `Delete all findings for ${scopeLabel}${statusLabel}? This cannot be undone.`,
confirmText: 'Clear',
destructive: true
})) return;
try {
const body = {};
if (jobId) body.job_id = jobId;
if (status) body.status = status;
const response = await fetch('/api/repair/findings/clear', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body)
});
const result = await response.json();
if (result.success) {
showToast(`Cleared ${result.deleted} findings`, 'success');
} else {
showToast(result.error || 'Failed to clear findings', 'error');
}
_repairSelectedFindings.clear();
loadRepairFindingsDashboard();
loadRepairFindings();
updateRepairStatus();
} catch (error) {
console.error('Error clearing findings:', error);
showToast('Error clearing findings', 'error');
}
}
async function loadRepairHistory() {
const container = document.getElementById('repair-history-list');
if (!container) return;

View file

@ -40803,7 +40803,7 @@ tr.tag-diff-same {
.repair-findings-toolbar {
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
margin-bottom: 14px;
gap: 10px;
flex-wrap: wrap;
@ -40872,6 +40872,23 @@ tr.tag-diff-same {
background: rgba(var(--accent-rgb, 99, 102, 241), 0.2);
}
.repair-clear-btn {
margin-left: auto;
background: rgba(239, 68, 68, 0.08);
border: 1px solid rgba(239, 68, 68, 0.2);
border-radius: 6px;
padding: 5px 12px;
color: #f87171;
font-size: 11px;
cursor: pointer;
transition: all 0.2s ease;
}
.repair-clear-btn:hover {
background: rgba(239, 68, 68, 0.18);
border-color: rgba(239, 68, 68, 0.4);
}
.repair-findings-list {
display: flex;
flex-direction: column;