added webhooks, moved app name and verison to simple config file
This commit is contained in:
250
app/web/templates/webhooks/list.html
Normal file
250
app/web/templates/webhooks/list.html
Normal file
@@ -0,0 +1,250 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Webhooks - SneakyScanner{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row mt-4">
|
||||
<div class="col-12 d-flex justify-content-between align-items-center mb-4">
|
||||
<h1 style="color: #60a5fa;">Webhook Management</h1>
|
||||
<a href="{{ url_for('webhooks.new_webhook') }}" class="btn btn-primary">
|
||||
<i class="bi bi-plus-circle"></i> Add Webhook
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Loading indicator -->
|
||||
<div id="loading" class="text-center my-5">
|
||||
<div class="spinner-border text-primary" role="status">
|
||||
<span class="visually-hidden">Loading...</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Webhooks table -->
|
||||
<div id="webhooks-container" style="display: none;">
|
||||
<div class="row mb-4">
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>URL</th>
|
||||
<th>Alert Types</th>
|
||||
<th>Severity Filter</th>
|
||||
<th>Status</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="webhooks-tbody">
|
||||
<!-- Populated via JavaScript -->
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Pagination -->
|
||||
<nav aria-label="Webhooks pagination" id="pagination-container">
|
||||
<ul class="pagination justify-content-center" id="pagination">
|
||||
<!-- Populated via JavaScript -->
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<!-- Empty state -->
|
||||
<div id="empty-state" class="text-center my-5" style="display: none;">
|
||||
<i class="bi bi-webhook" style="font-size: 4rem; color: #94a3b8;"></i>
|
||||
<p class="text-muted mt-3">No webhooks configured yet.</p>
|
||||
<a href="{{ url_for('webhooks.new_webhook') }}" class="btn btn-primary">
|
||||
<i class="bi bi-plus-circle"></i> Create Your First Webhook
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script>
|
||||
let currentPage = 1;
|
||||
const perPage = 20;
|
||||
|
||||
async function loadWebhooks(page = 1) {
|
||||
try {
|
||||
const response = await fetch(`/api/webhooks?page=${page}&per_page=${perPage}`);
|
||||
const data = await response.json();
|
||||
|
||||
if (data.webhooks && data.webhooks.length > 0) {
|
||||
renderWebhooks(data.webhooks);
|
||||
renderPagination(data.page, data.pages, data.total);
|
||||
document.getElementById('webhooks-container').style.display = 'block';
|
||||
document.getElementById('empty-state').style.display = 'none';
|
||||
} else {
|
||||
document.getElementById('webhooks-container').style.display = 'none';
|
||||
document.getElementById('empty-state').style.display = 'block';
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error loading webhooks:', error);
|
||||
alert('Failed to load webhooks');
|
||||
} finally {
|
||||
document.getElementById('loading').style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
function renderWebhooks(webhooks) {
|
||||
const tbody = document.getElementById('webhooks-tbody');
|
||||
tbody.innerHTML = '';
|
||||
|
||||
webhooks.forEach(webhook => {
|
||||
const row = document.createElement('tr');
|
||||
|
||||
// Truncate URL for display
|
||||
const truncatedUrl = webhook.url.length > 50 ?
|
||||
webhook.url.substring(0, 47) + '...' : webhook.url;
|
||||
|
||||
// Format alert types
|
||||
const alertTypes = webhook.alert_types && webhook.alert_types.length > 0 ?
|
||||
webhook.alert_types.map(t => `<span class="badge bg-secondary me-1">${t}</span>`).join('') :
|
||||
'<span class="text-muted">All</span>';
|
||||
|
||||
// Format severity filter
|
||||
const severityFilter = webhook.severity_filter && webhook.severity_filter.length > 0 ?
|
||||
webhook.severity_filter.map(s => `<span class="badge bg-${getSeverityColor(s)} me-1">${s}</span>`).join('') :
|
||||
'<span class="text-muted">All</span>';
|
||||
|
||||
// Status badge
|
||||
const statusBadge = webhook.enabled ?
|
||||
'<span class="badge bg-success">Enabled</span>' :
|
||||
'<span class="badge bg-secondary">Disabled</span>';
|
||||
|
||||
row.innerHTML = `
|
||||
<td><strong>${escapeHtml(webhook.name)}</strong></td>
|
||||
<td><code class="small">${escapeHtml(truncatedUrl)}</code></td>
|
||||
<td>${alertTypes}</td>
|
||||
<td>${severityFilter}</td>
|
||||
<td>${statusBadge}</td>
|
||||
<td>
|
||||
<div class="btn-group btn-group-sm" role="group">
|
||||
<button class="btn btn-outline-primary" onclick="testWebhook(${webhook.id})" title="Test">
|
||||
<i class="bi bi-send"></i>
|
||||
</button>
|
||||
<a href="/webhooks/${webhook.id}/edit" class="btn btn-outline-primary" title="Edit">
|
||||
<i class="bi bi-pencil"></i>
|
||||
</a>
|
||||
<a href="/webhooks/${webhook.id}/logs" class="btn btn-outline-info" title="Logs">
|
||||
<i class="bi bi-list-ul"></i>
|
||||
</a>
|
||||
<button class="btn btn-outline-danger" onclick="deleteWebhook(${webhook.id}, '${escapeHtml(webhook.name)}')" title="Delete">
|
||||
<i class="bi bi-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
`;
|
||||
tbody.appendChild(row);
|
||||
});
|
||||
}
|
||||
|
||||
function renderPagination(currentPage, totalPages, totalItems) {
|
||||
const pagination = document.getElementById('pagination');
|
||||
pagination.innerHTML = '';
|
||||
|
||||
if (totalPages <= 1) {
|
||||
document.getElementById('pagination-container').style.display = 'none';
|
||||
return;
|
||||
}
|
||||
|
||||
document.getElementById('pagination-container').style.display = 'block';
|
||||
|
||||
// Previous button
|
||||
const prevLi = document.createElement('li');
|
||||
prevLi.className = `page-item ${currentPage === 1 ? 'disabled' : ''}`;
|
||||
prevLi.innerHTML = `<a class="page-link" href="#" onclick="changePage(${currentPage - 1}); return false;">Previous</a>`;
|
||||
pagination.appendChild(prevLi);
|
||||
|
||||
// Page numbers
|
||||
for (let i = 1; i <= totalPages; i++) {
|
||||
if (i === 1 || i === totalPages || (i >= currentPage - 2 && i <= currentPage + 2)) {
|
||||
const li = document.createElement('li');
|
||||
li.className = `page-item ${i === currentPage ? 'active' : ''}`;
|
||||
li.innerHTML = `<a class="page-link" href="#" onclick="changePage(${i}); return false;">${i}</a>`;
|
||||
pagination.appendChild(li);
|
||||
} else if (i === currentPage - 3 || i === currentPage + 3) {
|
||||
const li = document.createElement('li');
|
||||
li.className = 'page-item disabled';
|
||||
li.innerHTML = '<a class="page-link" href="#">...</a>';
|
||||
pagination.appendChild(li);
|
||||
}
|
||||
}
|
||||
|
||||
// Next button
|
||||
const nextLi = document.createElement('li');
|
||||
nextLi.className = `page-item ${currentPage === totalPages ? 'disabled' : ''}`;
|
||||
nextLi.innerHTML = `<a class="page-link" href="#" onclick="changePage(${currentPage + 1}); return false;">Next</a>`;
|
||||
pagination.appendChild(nextLi);
|
||||
}
|
||||
|
||||
function changePage(page) {
|
||||
currentPage = page;
|
||||
loadWebhooks(page);
|
||||
}
|
||||
|
||||
async function testWebhook(id) {
|
||||
if (!confirm('Send a test payload to this webhook?')) return;
|
||||
|
||||
try {
|
||||
const response = await fetch(`/api/webhooks/${id}/test`, { method: 'POST' });
|
||||
const result = await response.json();
|
||||
|
||||
if (result.status === 'success') {
|
||||
alert(`Test successful!\nHTTP ${result.status_code}\n${result.message}`);
|
||||
} else {
|
||||
alert(`Test failed:\n${result.message}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error testing webhook:', error);
|
||||
alert('Failed to test webhook');
|
||||
}
|
||||
}
|
||||
|
||||
async function deleteWebhook(id, name) {
|
||||
if (!confirm(`Are you sure you want to delete webhook "${name}"?`)) return;
|
||||
|
||||
try {
|
||||
const response = await fetch(`/api/webhooks/${id}`, { method: 'DELETE' });
|
||||
const result = await response.json();
|
||||
|
||||
if (result.status === 'success') {
|
||||
alert('Webhook deleted successfully');
|
||||
loadWebhooks(currentPage);
|
||||
} else {
|
||||
alert(`Failed to delete webhook: ${result.message}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error deleting webhook:', error);
|
||||
alert('Failed to delete webhook');
|
||||
}
|
||||
}
|
||||
|
||||
function getSeverityColor(severity) {
|
||||
const colors = {
|
||||
'critical': 'danger',
|
||||
'warning': 'warning',
|
||||
'info': 'info'
|
||||
};
|
||||
return colors[severity] || 'secondary';
|
||||
}
|
||||
|
||||
function escapeHtml(text) {
|
||||
const div = document.createElement('div');
|
||||
div.textContent = text;
|
||||
return div.innerHTML;
|
||||
}
|
||||
|
||||
// Load webhooks on page load
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
loadWebhooks(1);
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user