+50
-12
@@ -249,7 +249,7 @@ pre.raw-line { background: var(--bs-tertiary-bg); padding: .75rem; border-radius
|
||||
<div class="page-section" id="page-rules">
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<h5 class="mb-0"><i class="bi bi-sliders me-2"></i>Alert Rules</h5>
|
||||
<button class="btn btn-primary btn-sm" data-bs-toggle="modal" data-bs-target="#ruleModal"><i class="bi bi-plus-lg"></i> Add Rule</button>
|
||||
<button class="btn btn-primary btn-sm" onclick="resetRuleForm();new bootstrap.Modal(document.getElementById('ruleModal')).show()"><i class="bi bi-plus-lg"></i> Add Rule</button>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-body p-0">
|
||||
@@ -386,19 +386,20 @@ pre.raw-line { background: var(--bs-tertiary-bg); padding: .75rem; border-radius
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<form id="ruleForm">
|
||||
<div class="modal-header"><h5 class="modal-title">Add Alert Rule</h5><button type="button" class="btn-close" data-bs-dismiss="modal"></button></div>
|
||||
<div class="modal-header"><h5 class="modal-title" id="ruleModalTitle">Add Alert Rule</h5><button type="button" class="btn-close" data-bs-dismiss="modal"></button></div>
|
||||
<div class="modal-body">
|
||||
<input type="hidden" name="id" id="ruleFormId" value="">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Name</label>
|
||||
<input type="text" class="form-control" name="name" required placeholder="e.g. PHP Error">
|
||||
<input type="text" class="form-control" name="name" id="ruleFormName" required placeholder="e.g. SSH Login">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Pattern <small class="text-secondary">(PHP regex)</small></label>
|
||||
<input type="text" class="form-control" name="pattern" required placeholder="/error/i">
|
||||
<input type="text" class="form-control" name="pattern" id="ruleFormPattern" required placeholder="/sshd.*Accepted/i">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Severity</label>
|
||||
<select class="form-select" name="severity" required>
|
||||
<select class="form-select" name="severity" id="ruleFormSeverity" required>
|
||||
<option value="emergency">Emergency</option>
|
||||
<option value="critical_high">Critical High</option>
|
||||
<option value="critical">Critical</option>
|
||||
@@ -414,11 +415,15 @@ pre.raw-line { background: var(--bs-tertiary-bg); padding: .75rem; border-radius
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Rate Limit <small class="text-secondary">(seconds, empty = no limit)</small></label>
|
||||
<input type="number" class="form-control" name="rate_limit_seconds" placeholder="60">
|
||||
<input type="number" class="form-control" name="rate_limit_seconds" id="ruleFormRateLimit" placeholder="60">
|
||||
</div>
|
||||
<div class="form-check mb-3">
|
||||
<input class="form-check-input" type="checkbox" name="active" id="ruleFormActive" checked>
|
||||
<label class="form-check-label" for="ruleFormActive">Active</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="submit" class="btn btn-primary">Add Rule</button>
|
||||
<button type="submit" class="btn btn-primary" id="ruleFormSubmit">Add Rule</button>
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||
</div>
|
||||
</form>
|
||||
@@ -790,7 +795,7 @@ async function loadRules() {
|
||||
<td>${severityBadge(r.severity)}</td>
|
||||
<td>${r.rate_limit_seconds ? r.rate_limit_seconds + 's' : '—'}</td>
|
||||
<td>${r.active ? '<span class="badge bg-success">Active</span>' : '<span class="badge bg-secondary">Inactive</span>'}</td>
|
||||
<td><button class="btn btn-outline-danger btn-sm py-0" onclick="deleteRule(${r.id})"><i class="bi bi-trash"></i></button></td>
|
||||
<td><button class="btn btn-outline-primary btn-sm py-0 me-1" onclick="editRule(${r.id})"><i class="bi bi-pencil"></i></button><button class="btn btn-outline-danger btn-sm py-0" onclick="deleteRule(${r.id})"><i class="bi bi-trash"></i></button></td>
|
||||
</tr>`).join('');
|
||||
}
|
||||
} catch (e) { console.error('rules error', e); }
|
||||
@@ -805,18 +810,51 @@ async function deleteRule(id) {
|
||||
} catch (e) { toast('Delete failed', 'danger'); }
|
||||
}
|
||||
|
||||
function editRule(id) {
|
||||
const r = state.rules.find(x => x.id === id);
|
||||
if (!r) return;
|
||||
document.getElementById('ruleModalTitle').textContent = 'Edit Rule';
|
||||
document.getElementById('ruleFormSubmit').textContent = 'Update Rule';
|
||||
document.getElementById('ruleFormId').value = r.id;
|
||||
document.getElementById('ruleFormName').value = r.name;
|
||||
document.getElementById('ruleFormPattern').value = r.pattern;
|
||||
document.getElementById('ruleFormSeverity').value = r.severity;
|
||||
document.getElementById('ruleFormRateLimit').value = r.rate_limit_seconds || '';
|
||||
document.getElementById('ruleFormActive').checked = r.active;
|
||||
new bootstrap.Modal(document.getElementById('ruleModal')).show();
|
||||
}
|
||||
|
||||
function resetRuleForm() {
|
||||
document.getElementById('ruleModalTitle').textContent = 'Add Alert Rule';
|
||||
document.getElementById('ruleFormSubmit').textContent = 'Add Rule';
|
||||
document.getElementById('ruleFormId').value = '';
|
||||
document.getElementById('ruleForm').reset();
|
||||
document.getElementById('ruleFormActive').checked = true;
|
||||
}
|
||||
|
||||
document.getElementById('ruleModal').addEventListener('hidden.bs.modal', resetRuleForm);
|
||||
|
||||
document.getElementById('ruleForm').addEventListener('submit', async e => {
|
||||
e.preventDefault();
|
||||
const data = Object.fromEntries(new FormData(e.target));
|
||||
if (data.rate_limit_seconds) data.rate_limit_seconds = parseInt(data.rate_limit_seconds);
|
||||
else data.rate_limit_seconds = null;
|
||||
data.active = !!data.active;
|
||||
|
||||
const id = data.id;
|
||||
delete data.id;
|
||||
|
||||
try {
|
||||
await api('/rules', { method: 'POST', body: JSON.stringify(data) });
|
||||
toast('Rule added');
|
||||
if (id) {
|
||||
await api('/rules/' + id, { method: 'PUT', body: JSON.stringify(data) });
|
||||
toast('Rule updated');
|
||||
} else {
|
||||
await api('/rules', { method: 'POST', body: JSON.stringify(data) });
|
||||
toast('Rule added');
|
||||
}
|
||||
bootstrap.Modal.getInstance(document.getElementById('ruleModal')).hide();
|
||||
e.target.reset();
|
||||
loadRules();
|
||||
} catch (err) { toast('Failed to add rule', 'danger'); }
|
||||
} catch (err) { toast('Failed to save rule', 'danger'); }
|
||||
});
|
||||
|
||||
// --- SETTINGS ---
|
||||
|
||||
Reference in New Issue
Block a user