290 lines
10 KiB
JavaScript
290 lines
10 KiB
JavaScript
let currentSeriesData = [];
|
|
let darkMode = true;
|
|
|
|
function toggleTheme() {
|
|
darkMode = !darkMode;
|
|
document.body.classList.toggle('bg-dark', darkMode);
|
|
document.body.classList.toggle('text-light', darkMode);
|
|
document.querySelector('.theme-switch').className = `bi ${darkMode ? 'bi-moon-stars-fill' : 'bi-sun-fill'} theme-switch`;
|
|
document.querySelectorAll('.form-select, .form-control').forEach(el => {
|
|
el.classList.toggle('bg-dark', darkMode);
|
|
el.classList.toggle('text-light', darkMode);
|
|
el.classList.toggle('border-secondary', darkMode);
|
|
});
|
|
}
|
|
|
|
async function fetchDatabases() {
|
|
const res = await fetch('/databases');
|
|
const dbs = await res.json();
|
|
const select = document.getElementById('db-select');
|
|
select.innerHTML = '<option value="">Wybierz bazę danych...</option>';
|
|
dbs.forEach(db => {
|
|
const option = document.createElement('option');
|
|
option.value = db;
|
|
option.textContent = db;
|
|
select.appendChild(option);
|
|
});
|
|
const params = new URLSearchParams(window.location.search);
|
|
const dbParam = params.get('db');
|
|
if (dbParam && dbs.includes(dbParam)) {
|
|
select.value = dbParam;
|
|
fetchSeries();
|
|
}
|
|
}
|
|
|
|
async function fetchSeries() {
|
|
const db = document.getElementById('db-select').value;
|
|
if (!db) return;
|
|
const params = new URLSearchParams(window.location.search);
|
|
params.set('db', db);
|
|
window.history.replaceState({}, '', `${location.pathname}?${params}`);
|
|
showMessage('Ładowanie serii...', 'info');
|
|
const res = await fetch(`/series?db=${db}`);
|
|
const series = await res.json();
|
|
currentSeriesData = series;
|
|
renderSeriesTable(series);
|
|
showMessage('', 'info');
|
|
}
|
|
|
|
function renderSeriesTable(series) {
|
|
const container = document.getElementById('series-list');
|
|
container.innerHTML = '';
|
|
if (!Array.isArray(series) || series.length === 0) {
|
|
container.innerHTML = `<tr><td colspan="3" class="text-center">Brak serii w wybranej bazie danych</td></tr>`;
|
|
return;
|
|
}
|
|
|
|
const baseNames = new Map();
|
|
series.forEach(s => {
|
|
const entity = s.tags?.entity_id;
|
|
if (!entity) return;
|
|
const base = entity.replace(/_\d+$/, '');
|
|
if (baseNames.has(base)) baseNames.get(base).push(s.series);
|
|
else baseNames.set(base, [s.series]);
|
|
});
|
|
|
|
const duplicates = new Set();
|
|
for (const [_, entries] of baseNames.entries()) {
|
|
if (entries.length > 1) entries.forEach(ser => duplicates.add(ser));
|
|
}
|
|
|
|
series.forEach((s, i) => {
|
|
const id = `series-${i}`;
|
|
const isDuplicate = duplicates.has(s.series);
|
|
const row = document.createElement('tr');
|
|
row.className = isDuplicate ? 'table-warning' : '';
|
|
row.innerHTML = `
|
|
<td><input class="form-check-input" type="checkbox" value="${s.series}" id="${id}" onchange="updateCount()"></td>
|
|
<td class="series-item">
|
|
<label class="form-check-label" for="${id}">${s.series}</label>
|
|
${isDuplicate ? '<div class="text-warning small">Duplikat entity_id</div>' : ''}
|
|
</td>
|
|
<td>
|
|
<button class="btn btn-sm btn-outline-danger me-1" onclick="deleteSingleSeries('${s.series}')"><i class="bi bi-trash"></i></button>
|
|
<button class="btn btn-sm btn-outline-warning" onclick="openTimeDeleteModal('${s.series}')"><i class="bi bi-clock-history"></i></button>
|
|
</td>
|
|
`;
|
|
container.appendChild(row);
|
|
});
|
|
updateCount();
|
|
}
|
|
|
|
function filterSeries() {
|
|
const term = document.getElementById('series-filter').value.toLowerCase();
|
|
const filtered = currentSeriesData.filter(s => s.series.toLowerCase().includes(term));
|
|
renderSeriesTable(filtered);
|
|
}
|
|
|
|
function updateCount() {
|
|
const count = document.querySelectorAll('input[type="checkbox"]:checked').length;
|
|
document.getElementById('selected-count').innerText = `Zaznaczono: ${count}`;
|
|
}
|
|
|
|
function toggleSelectAll() {
|
|
const checkboxes = document.querySelectorAll('input[type="checkbox"]:not(#select-all)');
|
|
const selectAll = document.getElementById('select-all').checked;
|
|
checkboxes.forEach(checkbox => checkbox.checked = selectAll);
|
|
updateCount();
|
|
}
|
|
|
|
function showMessage(message, type) {
|
|
const el = document.getElementById('info-message');
|
|
el.textContent = message;
|
|
el.className = `alert alert-${type} ${message ? 'd-block' : 'd-none'}`;
|
|
}
|
|
|
|
async function deleteSelected() {
|
|
const checkboxes = document.querySelectorAll('input[type="checkbox"]:checked:not(#select-all)');
|
|
if (checkboxes.length === 0) return showMessage('Nie zaznaczono żadnych serii', 'warning');
|
|
const series = Array.from(checkboxes).map(cb => cb.value);
|
|
const db = document.getElementById('db-select').value;
|
|
const preview = series.map(s => `DROP SERIES FROM "${s.split(',')[0]}" WHERE ...`).join('\n');
|
|
document.getElementById('confirmMessage').textContent = `Czy na pewno chcesz usunąć ${series.length} serii?`;
|
|
document.getElementById('queryPreview').textContent = preview;
|
|
const modal = new bootstrap.Modal(document.getElementById('confirmModal'));
|
|
modal.show();
|
|
document.getElementById('confirmDeleteBtn').onclick = async () => {
|
|
modal.hide();
|
|
await deleteSeries(series);
|
|
};
|
|
}
|
|
|
|
async function deleteSingleSeries(seriesId) {
|
|
document.getElementById('confirmMessage').textContent = `Czy na pewno chcesz usunąć serię:`;
|
|
document.getElementById('queryPreview').textContent = `DROP SERIES FROM "${seriesId.split(',')[0]}" WHERE ...`;
|
|
const modal = new bootstrap.Modal(document.getElementById('confirmModal'));
|
|
modal.show();
|
|
document.getElementById('confirmDeleteBtn').onclick = async () => {
|
|
modal.hide();
|
|
await deleteSeries([seriesId]);
|
|
};
|
|
}
|
|
|
|
async function deleteSeries(series) {
|
|
const db = document.getElementById('db-select').value;
|
|
showMessage('Usuwanie serii...', 'info');
|
|
const res = await fetch('/delete', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ db, series })
|
|
});
|
|
const data = await res.json();
|
|
if (data.status === 'success') {
|
|
showMessage(`Usunięto ${data.deleted} serii`, 'success');
|
|
setTimeout(fetchSeries, 1000);
|
|
} else {
|
|
showMessage('Wystąpił błąd podczas usuwania serii', 'danger');
|
|
}
|
|
}
|
|
|
|
fetchDatabases();
|
|
|
|
|
|
|
|
let currentSeriesForTimeDelete = null;
|
|
|
|
function openTimeDeleteModal(seriesId) {
|
|
currentSeriesForTimeDelete = seriesId;
|
|
document.getElementById('time-from').value = '';
|
|
document.getElementById('time-to').value = '';
|
|
document.getElementById('time-query-preview').textContent = '';
|
|
const modal = new bootstrap.Modal(document.getElementById('timeDeleteModal'));
|
|
modal.show();
|
|
}
|
|
|
|
async function confirmTimeDelete() {
|
|
const from = document.getElementById('time-from').value;
|
|
const to = document.getElementById('time-to').value;
|
|
const db = document.getElementById('db-select').value;
|
|
const series = currentSeriesForTimeDelete;
|
|
|
|
if (!from || !to || !series || !db) {
|
|
showMessage('Uzupełnij wszystkie pola i wybierz bazę danych', 'warning');
|
|
return;
|
|
}
|
|
|
|
showMessage('Usuwanie danych z serii...', 'info');
|
|
const res = await fetch('/delete_range', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ db, series, from, to })
|
|
});
|
|
|
|
const data = await res.json();
|
|
if (data.status === 'success') {
|
|
showMessage('Dane zostały usunięte', 'success');
|
|
setTimeout(fetchSeries, 1000);
|
|
} else {
|
|
showMessage(`Błąd: ${data.error}`, 'danger');
|
|
}
|
|
}
|
|
|
|
|
|
function setPredefinedRange(value) {
|
|
if (!value) return;
|
|
|
|
const now = new Date();
|
|
const to = now.toISOString().slice(0, 16);
|
|
let fromDate = new Date(now);
|
|
|
|
if (value.endsWith('h')) {
|
|
fromDate.setHours(fromDate.getHours() - parseInt(value));
|
|
} else if (value.endsWith('d')) {
|
|
fromDate.setDate(fromDate.getDate() - parseInt(value));
|
|
}
|
|
|
|
const from = fromDate.toISOString().slice(0, 16);
|
|
document.getElementById('time-from').value = from;
|
|
document.getElementById('time-to').value = to;
|
|
}
|
|
|
|
|
|
function setPredefinedRange(value) {
|
|
if (!value) return;
|
|
|
|
const now = new Date();
|
|
const to = now.toISOString().slice(0, 16);
|
|
let fromDate = new Date(now);
|
|
|
|
if (value.endsWith('h')) {
|
|
fromDate.setHours(fromDate.getHours() - parseInt(value));
|
|
} else if (value.endsWith('d')) {
|
|
fromDate.setDate(fromDate.getDate() - parseInt(value));
|
|
} else if (value === 'before-current-year') {
|
|
const start = new Date(now.getFullYear(), 0, 1);
|
|
document.getElementById('time-from').value = '2000-01-01T00:00';
|
|
document.getElementById('time-to').value = start.toISOString().slice(0, 16);
|
|
return;
|
|
} else if (value === 'keep-2y') {
|
|
fromDate.setFullYear(fromDate.getFullYear() - 2);
|
|
} else if (value === 'keep-3y') {
|
|
fromDate.setFullYear(fromDate.getFullYear() - 3);
|
|
}
|
|
|
|
const from = fromDate.toISOString().slice(0, 16);
|
|
document.getElementById('time-from').value = from;
|
|
document.getElementById('time-to').value = to;
|
|
}
|
|
|
|
async function deleteRangeForSelected() {
|
|
const checkboxes = document.querySelectorAll('input[type="checkbox"]:checked:not(#select-all)');
|
|
if (checkboxes.length === 0) {
|
|
showMessage('Zaznacz przynajmniej jedną serię', 'warning');
|
|
return;
|
|
}
|
|
|
|
const fromInput = document.getElementById('time-from').value;
|
|
const toInput = document.getElementById('time-to').value;
|
|
const db = document.getElementById('db-select').value;
|
|
|
|
if (!fromInput || !toInput || !db) {
|
|
showMessage('Wybierz zakres czasu i bazę danych', 'warning');
|
|
return;
|
|
}
|
|
|
|
const from = new Date(fromInput).toISOString();
|
|
const to = new Date(toInput).toISOString();
|
|
const series = Array.from(checkboxes).map(cb => cb.value);
|
|
|
|
showMessage('Usuwanie danych z wielu serii...', 'info');
|
|
for (const s of series) {
|
|
await fetch('/delete_range', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ db, series: s, from, to })
|
|
});
|
|
}
|
|
|
|
showMessage('Dane zostały usunięte', 'success');
|
|
setTimeout(fetchSeries, 1000);
|
|
}
|
|
|
|
function openTimeDeleteModalForMany() {
|
|
currentSeriesForTimeDelete = null; // żeby nie używać pojedynczej serii
|
|
document.getElementById('time-from').value = '';
|
|
document.getElementById('time-to').value = '';
|
|
document.getElementById('time-query-preview').textContent = '';
|
|
const modal = new bootstrap.Modal(document.getElementById('timeDeleteModal'));
|
|
modal.show();
|
|
}
|