diff --git a/core/repair_worker.py b/core/repair_worker.py index 6cb4eb75..facb4cdf 100644 --- a/core/repair_worker.py +++ b/core/repair_worker.py @@ -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 diff --git a/web_server.py b/web_server.py index 16a758be..131fa9d8 100644 --- a/web_server.py +++ b/web_server.py @@ -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""" diff --git a/webui/index.html b/webui/index.html index 5dcd17d8..e100db4f 100644 --- a/webui/index.html +++ b/webui/index.html @@ -5774,6 +5774,7 @@ +
Loading findings...
diff --git a/webui/static/script.js b/webui/static/script.js index 6b07fc79..9cb218ac 100644 --- a/webui/static/script.js +++ b/webui/static/script.js @@ -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; diff --git a/webui/static/style.css b/webui/static/style.css index 903a761e..52fa1e26 100644 --- a/webui/static/style.css +++ b/webui/static/style.css @@ -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;