git add templates/! REFACOR INTERFEJSU git add templates/

This commit is contained in:
Mateusz Gruszczyński
2025-02-28 13:12:29 +01:00
parent 4e965195f5
commit d0f1d25063
16 changed files with 1335 additions and 771 deletions

View File

@ -2,116 +2,178 @@
{% block title %}Moje urządzenia - RouterOS Update{% endblock %}
{% block extra_head %}
<style>
.progress-container {
width: 50%;
margin: 20px auto;
background: #444;
border-radius: 5px;
overflow: hidden;
}
.progress-bar {
width: 0%;
height: 30px;
background: #4caf50;
border-radius: 5px;
transition: width 0.5s linear;
}
<style>
/* Karta w trybie ciemnym */
body.dark-mode .card {
background-color: #1e1e1e;
color: #ccc;
border-color: #444;
}
#mass-system-update-overlay, #mass-firmware-update-overlay {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.7);
z-index: 1000;
color: white;
text-align: center;
padding-top: 200px;
}
</style>
/* Nagłówek karty w trybie ciemnym */
body.dark-mode .card .card-header.bg-light {
background-color: #333 !important;
border-bottom: 1px solid #444;
}
/* Tabela w trybie ciemnym */
body.dark-mode .table thead.table-dark {
background-color: #2a2a2a !important;
color: #ccc !important;
border-color: #444 !important;
}
body.dark-mode .table-hover tbody tr:hover {
background-color: #2f2f2f;
}
body.dark-mode .table-bordered > :not(caption) > * > * {
border-color: #444 !important;
}
/* Styl paska postępu w overlay */
.progress-container {
width: 50%;
margin: 20px auto;
background: #444;
border-radius: 5px;
overflow: hidden;
}
.progress-bar {
width: 0%;
height: 30px;
background: #4caf50;
border-radius: 5px;
transition: width 0.5s linear;
}
#mass-system-update-overlay,
#mass-firmware-update-overlay {
display: none;
position: fixed;
top: 0; left: 0;
width: 100%; height: 100%;
background: rgba(0,0,0,0.7);
z-index: 1000;
color: white;
text-align: center;
padding-top: 200px;
}
/* Prompt do firmware w overlay */
#mass-firmware-reboot-prompt {
display:none;
position:fixed;
top:0; left:0;
width:100%; height:100%;
background:rgba(0,0,0,0.7);
z-index:1100;
color:white;
text-align:center;
padding-top:200px;
}
</style>
{% endblock %}
{% block content %}
<h2>Moje urządzenia</h2>
<div class="row mb-3">
<div class="col text-end">
<button type="button" class="btn btn-success" onclick="window.location.href='{{ url_for('add_device') }}'">
Dodaj nowe urządzenie
</button>
<div class="container">
<h2 class="mb-4">Moje urządzenia</h2>
<!-- Karta z tabelą urządzeń i przyciskami masowych akcji -->
<div class="card border-0 shadow">
<div class="card-header bg-light d-flex align-items-center justify-content-between">
<h5 class="mb-0">Lista urządzeń</h5>
<button type="button" class="btn btn-success" onclick="window.location.href='{{ url_for('add_device') }}'">
Dodaj nowe urządzenie
</button>
</div>
<div class="card-body">
<!-- Formularz z przyciskami masowych operacji -->
<form id="mass-update-form">
<div class="mb-3">
<button type="button" id="mass-system-update-btn" class="btn btn-warning me-2">Aktualizuj system (masowo)</button>
<button type="button" id="mass-firmware-update-btn" class="btn btn-danger me-2">Aktualizuj firmware (masowo)</button>
<button type="submit" class="btn btn-primary">Odśwież wybrane</button>
</div>
<div class="table-responsive">
<table class="table table-striped table-hover table-sm align-middle table-bordered">
<thead class="table-dark">
<tr>
<th><input type="checkbox" id="select-all"></th>
<th>Nazwa / Adres IP</th>
<th>Ostatnie sprawdzenie</th>
<th>Status</th>
<th>System / Firmware</th>
<th>Akcje</th>
</tr>
</thead>
<tbody>
{% for device in devices %}
<tr>
<td>
<input type="checkbox" name="selected_devices" value="{{ device.id }}">
</td>
<td>
{% if device.name %}
{{ device.name }}
<br><code class="text-muted">{{ device.ip }}</code>
{% else %}
{{ device.ip }}
{% endif %}
</td>
<td>
{{ device.last_check.strftime('%Y-%m-%d %H:%M:%S') if device.last_check else 'Brak' }}
</td>
<td>
{% if device.update_required or (device.current_firmware and device.upgrade_firmware and device.current_firmware != device.upgrade_firmware) %}
{% if device.update_required and (device.current_firmware and device.upgrade_firmware and device.current_firmware != device.upgrade_firmware) %}
<span class="badge bg-danger">Wymaga aktualizacji <small>(system i firmware)</small></span>
{% elif device.update_required %}
<span class="badge bg-danger">Wymaga aktualizacji <small>(system)</small></span>
{% else %}
<span class="badge bg-danger">Wymaga aktualizacji <small>(firmware)</small></span>
{% endif %}
{% else %}
<span class="badge bg-success">Aktualny</span>
{% endif %}
</td>
<td style="white-space: nowrap;">
<small>
<strong>System:</strong> {{ device.current_version or 'Brak' }}<br>
<strong>Firmware:</strong> {{ device.current_firmware or 'Brak' }}<br>
<strong>Upgrade FW:</strong> {{ device.upgrade_firmware or 'N/A' }}
</small>
</td>
<td>
<button type="button" class="btn btn-info btn-sm"
onclick="window.location.href='{{ url_for('device_detail', device_id=device.id) }}'">
Szczegóły
</button>
<button type="button" class="btn btn-secondary btn-sm"
onclick="window.location.href='{{ url_for('force_check', device_id=device.id) }}'">
Sprawdź
</button>
<button type="button" class="btn btn-warning btn-sm"
onclick="window.location.href='{{ url_for('edit_device', device_id=device.id) }}'">
Edytuj
</button>
<!-- Dodane przykładowe przyciski (potrzebna obsługa w backendzie) -->
<button type="button" class="btn btn-outline-danger btn-sm"
onclick="fetch('/device/{{ device.id }}/restart', {method: 'POST'}) .then(()=>location.reload());">
Restart
</button>
</td>
</tr>
{% else %}
<tr>
<td colspan="6" class="text-center">Brak dodanych urządzeń.</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</form>
</div>
</div>
</div>
<!-- Formularz z przyciskami masowych operacji -->
<form id="mass-update-form">
<div class="mb-3">
<button type="button" id="mass-system-update-btn" class="btn btn-warning">Aktualizuj system (masowo)</button>
<button type="button" id="mass-firmware-update-btn" class="btn btn-danger">Aktualizuj firmware (masowo)</button>
<button type="submit" class="btn btn-primary">Odśwież wybrane</button>
</div>
<table class="table table-bordered table-hover">
<thead class="table-dark">
<tr>
<th><input type="checkbox" id="select-all"></th>
<th>Nazwa / Adres IP</th>
<th>Ostatnie sprawdzenie</th>
<th>Status</th>
<th>System / Firmware</th>
<th>Akcje</th>
</tr>
</thead>
<tbody>
{% for device in devices %}
<tr>
<td>
<input type="checkbox" name="selected_devices" value="{{ device.id }}">
</td>
<td>
{% if device.name %}
{{ device.name }} |
<code><small class="text-muted">{{ device.ip }}</small></code>
{% else %}
{{ device.ip }}
{% endif %}
</td>
<td>{{ device.last_check.strftime('%Y-%m-%d %H:%M:%S') if device.last_check else 'Brak' }}</td>
<td>
{% if device.update_required or (device.current_firmware and device.upgrade_firmware and device.current_firmware != device.upgrade_firmware) %}
{% if device.update_required and (device.current_firmware and device.upgrade_firmware and device.current_firmware != device.upgrade_firmware) %}
<span class="badge bg-danger">Wymaga aktualizacji <small>(system i firmware)</small></span>
{% elif device.update_required %}
<span class="badge bg-danger">Wymaga aktualizacji <small>(system)</small></span>
{% else %}
<span class="badge bg-danger">Wymaga aktualizacji <small>(firmware)</small></span>
{% endif %}
{% else %}
<span class="badge bg-success">Aktualny</span>
{% endif %}
</td>
<td>
<small>
<strong>System:</strong> {{ device.current_version or 'Brak' }}<br>
<strong>Firmware:</strong> {{ device.current_firmware or 'Brak' }}<br>
<strong>Upgrade Firmware:</strong> {{ device.upgrade_firmware or 'N/A' }}
</small>
</td>
<td>
<button type="button" class="btn btn-info btn-sm" onclick="window.location.href='{{ url_for('device_detail', device_id=device.id) }}'">Szczegóły</button>
<button type="button" class="btn btn-secondary btn-sm" onclick="window.location.href='{{ url_for('force_check', device_id=device.id) }}'">Wymuś sprawdzenie</button>
<button type="button" class="btn btn-warning btn-sm" onclick="window.location.href='{{ url_for('edit_device', device_id=device.id) }}'">Edytuj</button>
</td>
</tr>
{% else %}
<tr>
<td colspan="6" class="text-center">Brak dodanych urządzeń.</td>
</tr>
{% endfor %}
</tbody>
</table>
</form>
<!-- Overlay dla masowej aktualizacji systemu -->
<div id="mass-system-update-overlay">
@ -132,7 +194,7 @@
</div>
<!-- Dynamiczny prompt dla masowego restartu firmware -->
<div id="mass-firmware-reboot-prompt" style="display:none; position:fixed; top:0; left:0; width:100%; height:100%; background:rgba(0,0,0,0.7); z-index:1100; color:white; text-align:center; padding-top:200px;">
<div id="mass-firmware-reboot-prompt">
<h3>Firmware update zakończony.</h3>
<p>Czy chcesz zrestartować wszystkie wybrane urządzenia?</p>
<button id="mass-firmware-reboot-btn" class="btn btn-danger">Restart urządzeń</button>
@ -140,7 +202,7 @@
</div>
<script>
// Dodajemy event listenery raz, aby uniknąć wielokrotnego przypisywania
// Ten sam skrypt masowych akcji, przeniesiony bez zmian w logice
document.addEventListener('DOMContentLoaded', function() {
document.getElementById('select-all').addEventListener('change', function() {
var checkboxes = document.querySelectorAll('input[name="selected_devices"]');
@ -156,7 +218,6 @@
});
});
// Pobierz zaznaczone urządzenia
function getSelectedDeviceIds() {
var selected = [];
var checkboxes = document.querySelectorAll('input[name="selected_devices"]:checked');
@ -173,7 +234,6 @@
alert("Wybierz przynajmniej jedno urządzenie.");
return;
}
// Wysyłamy update systemu dla każdego urządzenia asynchronicznie
selectedDevices.forEach(function(id) {
fetch(`/device/${id}/update`, { method: 'POST' })
.catch(function(error){ console.error('Błąd aktualizacji systemu dla urządzenia ' + id, error); });
@ -191,7 +251,7 @@
timerDisplay.textContent = timeLeft + ' sekund';
if(timeLeft <= 0){
clearInterval(interval);
// Po zakończeniu odliczania, dla każdego urządzenia wykonaj force_check
// Po zakończeniu odliczania, force_check
selectedDevices.forEach(function(id) {
fetch(`/device/${id}/force_check`, { method: 'GET' })
.catch(function(error){ console.error('Błąd force check dla urządzenia ' + id, error); });
@ -208,7 +268,6 @@
alert("Wybierz przynajmniej jedno urządzenie.");
return;
}
// Wysyłamy update firmware dla każdego urządzenia asynchronicznie
selectedDevices.forEach(function(id) {
fetch(`/device/${id}/update_firmware`, { method: 'POST' })
.catch(function(error){ console.error('Błąd aktualizacji firmware dla urządzenia ' + id, error); });
@ -217,7 +276,7 @@
document.getElementById('mass-firmware-reboot-prompt').style.display = 'block';
});
// Funkcja sekwencyjnego wysyłania reboot (z opóźnieniem)
// Sekwencyjny reboot
function sendRebootSequentially(devices, index = 0) {
if (index >= devices.length) return Promise.resolve();
return fetch(`/device/${devices[index]}/restart`, { method: 'POST' })
@ -225,7 +284,6 @@
console.error('Błąd wysyłania reboot dla urządzenia ' + devices[index], error);
})
.then(function() {
// Opóźnienie 500 ms przed kolejnym rebootem
return new Promise(resolve => setTimeout(resolve, 500));
})
.then(function() {
@ -233,14 +291,11 @@
});
}
// Obsługa przycisku restartu w prompt dla masowego firmware update
function onMassFirmwareReboot() {
document.getElementById('mass-firmware-reboot-prompt').style.display = 'none';
var selectedDevices = getSelectedDeviceIds();
// Wysyłamy rebooty sekwencyjnie
sendRebootSequentially(selectedDevices)
.then(function() {
// Po wysłaniu reboot dla wszystkich urządzeń, pokazujemy overlay z 2-minutowym paskiem postępu
var overlay = document.getElementById('mass-firmware-update-overlay');
overlay.style.display = 'block';
var timeLeft = 120; // 120 sekund
@ -253,7 +308,7 @@
timerDisplay.textContent = timeLeft + ' sekund';
if(timeLeft <= 0){
clearInterval(interval);
// Po zakończeniu odliczania, dla każdego urządzenia wykonaj force_check
// Po zakończeniu odliczania, force_check
selectedDevices.forEach(function(id) {
fetch(`/device/${id}/force_check`, { method: 'GET' })
.catch(function(error){ console.error('Błąd force check dla urządzenia ' + id, error); });
@ -263,8 +318,8 @@
}, 1000);
});
}
// Obsługa standardowego przycisku "Odśwież wybrane"
// Obsługa "Odśwież wybrane"
document.getElementById('mass-update-form').addEventListener('submit', function(e) {
e.preventDefault();
var selectedDevices = getSelectedDeviceIds();
@ -279,4 +334,4 @@
setTimeout(function(){ location.reload(); }, 2000);
});
</script>
{% endblock %}
{% endblock %}