release
This commit is contained in:
146
static/js/bans.js
Normal file
146
static/js/bans.js
Normal file
@@ -0,0 +1,146 @@
|
||||
(function () {
|
||||
const $ = (sel, root = document) => root.querySelector(sel);
|
||||
const $$ = (sel, root = document) => Array.from(root.querySelectorAll(sel));
|
||||
|
||||
// --- SEARCH / FILTER (client-side) ---
|
||||
const searchInput = $('#search-input');
|
||||
const rows = () => $$('#bans-tbody tr.ban-row');
|
||||
const noDataRow = () => $('#bans-tbody tr[data-empty]');
|
||||
|
||||
function applySearch() {
|
||||
const q = (searchInput?.value || '').trim().toLowerCase();
|
||||
let visible = 0;
|
||||
rows().forEach(r => {
|
||||
const text = r.textContent.toLowerCase();
|
||||
const show = !q || text.includes(q);
|
||||
r.classList.toggle('d-none', !show);
|
||||
if (show) visible++;
|
||||
});
|
||||
if (!visible && !noDataRow()) {
|
||||
const tr = document.createElement('tr');
|
||||
tr.setAttribute('data-empty', '');
|
||||
tr.innerHTML = '<td colspan="6" class="text-center py-5 text-secondary">Brak wyników dla podanego filtra</td>';
|
||||
$('#bans-tbody').appendChild(tr);
|
||||
} else if (visible && noDataRow()) {
|
||||
noDataRow().remove();
|
||||
}
|
||||
}
|
||||
let t;
|
||||
searchInput?.addEventListener('input', () => { clearTimeout(t); t = setTimeout(applySearch, 120); });
|
||||
|
||||
// --- BULK SELECT ---
|
||||
const selectAll = $('#select-all');
|
||||
const counter = $('#selection-counter');
|
||||
const delBtn = $('#delete-selected');
|
||||
const bulkForm = $('#bulk-form');
|
||||
|
||||
function currentChecks() { return $$('.row-check'); }
|
||||
function selectedCount() { return currentChecks().filter(c => c.checked).length; }
|
||||
function updateState() {
|
||||
const total = currentChecks().length;
|
||||
const sel = selectedCount();
|
||||
if (counter) counter.textContent = sel + ' zaznaczonych';
|
||||
if (delBtn) delBtn.disabled = sel === 0;
|
||||
if (selectAll) {
|
||||
selectAll.checked = sel > 0 && sel === total;
|
||||
selectAll.indeterminate = sel > 0 && sel < total;
|
||||
}
|
||||
}
|
||||
selectAll?.addEventListener('change', () => {
|
||||
currentChecks().forEach(c => (c.checked = selectAll.checked));
|
||||
updateState();
|
||||
});
|
||||
document.addEventListener('change', (e) => {
|
||||
if (e.target.classList?.contains('row-check')) updateState();
|
||||
});
|
||||
// Kliknięcie w wiersz przełącza zaznaczenie (poza elementami interaktywnymi)
|
||||
document.addEventListener('click', (e) => {
|
||||
const row = e.target.closest('tr.ban-row');
|
||||
if (!row) return;
|
||||
if (e.target.closest('input,button,a,label,select,textarea')) return;
|
||||
const cb = row.querySelector('.row-check');
|
||||
if (cb) { cb.checked = !cb.checked; updateState(); }
|
||||
});
|
||||
updateState();
|
||||
|
||||
// Potwierdzenia akcji
|
||||
bulkForm?.addEventListener('submit', (e) => {
|
||||
const submitter = e.submitter;
|
||||
if (!submitter) return;
|
||||
const sel = selectedCount();
|
||||
const isDeleteAll = submitter.name === 'delete_all';
|
||||
const msg = isDeleteAll ? 'Usunąć WSZYSTKIE bany?' : `Usunąć ${sel} wybrane bany?`;
|
||||
if (!confirm(msg)) e.preventDefault();
|
||||
});
|
||||
|
||||
// --- ADD BAN: walidacja klientowa ---
|
||||
const addForm = $('#add-ban-form');
|
||||
addForm?.addEventListener('submit', (e) => {
|
||||
if (!addForm.checkValidity()) {
|
||||
e.preventDefault();
|
||||
addForm.classList.add('was-validated');
|
||||
}
|
||||
});
|
||||
|
||||
// --- DETAILS MODAL ---
|
||||
function formatBanDetails(data) {
|
||||
let html = '<div class="table-responsive"><table class="table table-bordered table-dark">';
|
||||
html += '<thead><tr><th>Klucz</th><th>Wartość</th></tr></thead><tbody>';
|
||||
for (let key in data) {
|
||||
let value = data[key];
|
||||
if (key === 'attack_details' || key === 'geo') {
|
||||
try {
|
||||
const parsed = typeof value === 'string' ? JSON.parse(value) : value;
|
||||
let nested = '<table class="table table-sm table-bordered table-dark mb-0">';
|
||||
for (let subKey in parsed) nested += `<tr><td>${subKey}</td><td>${parsed[subKey]}</td></tr>`;
|
||||
nested += '</table>';
|
||||
value = nested;
|
||||
} catch (_) { }
|
||||
}
|
||||
html += `<tr><td>${key}</td><td>${value}</td></tr>`;
|
||||
}
|
||||
html += '</tbody></table></div>';
|
||||
return html;
|
||||
}
|
||||
|
||||
// Otwórz modal po kliknięciu IP
|
||||
document.addEventListener('click', (e) => {
|
||||
const btn = e.target.closest('.ban-ip');
|
||||
if (!btn) return;
|
||||
const ip = btn.dataset.ip;
|
||||
const modalEl = document.getElementById('banModal');
|
||||
const bodyEl = document.getElementById('banModalBody');
|
||||
const titleEl = document.getElementById('banModalLabel');
|
||||
|
||||
if (titleEl) titleEl.textContent = 'Szczegóły bana dla ' + ip;
|
||||
if (bodyEl) {
|
||||
bodyEl.innerHTML = '<div class="placeholder-glow"><span class="placeholder col-12"></span><span class="placeholder col-10"></span></div>';
|
||||
}
|
||||
|
||||
fetch('/api/banned/' + encodeURIComponent(ip) + '?full_info=1')
|
||||
.then(r => r.ok ? r.json() : Promise.reject(r.status))
|
||||
.then(data => { bodyEl.innerHTML = formatBanDetails(data); })
|
||||
.catch(() => { bodyEl.innerHTML = '<div class="text-danger">Nie udało się pobrać szczegółów.</div>'; })
|
||||
.finally(() => {
|
||||
const m = new bootstrap.Modal(modalEl);
|
||||
m.show();
|
||||
});
|
||||
});
|
||||
|
||||
document.getElementById('delete-all-btn')?.addEventListener('click', async () => {
|
||||
if (!confirm('Usunąć WSZYSTKIE bany?')) return;
|
||||
try {
|
||||
const res = await fetch('/api/banned/all', { method: 'DELETE' });
|
||||
if (!res.ok) throw new Error('HTTP ' + res.status);
|
||||
window.showToast?.({ text: 'Wszystkie bany usunięte', variant: 'success' });
|
||||
location.reload();
|
||||
} catch (e) {
|
||||
window.showToast?.({ text: 'Nie udało się usunąć wszystkich banów', variant: 'danger' });
|
||||
}
|
||||
});
|
||||
|
||||
const url = new URL(location.href);
|
||||
if (url.searchParams.get('created') === '1') {
|
||||
window.showToast?.({ text: 'Ban został dodany.', variant: 'success' });
|
||||
}
|
||||
})();
|
||||
Reference in New Issue
Block a user