Features: - Device management and monitoring dashboard - Remote command execution on devices via port 80 - Auto-update coordination for multiple devices - Database reset functionality with safety confirmations - Server logs filtering and dedicated logging interface - Device status monitoring and management - SQLite database for comprehensive logging - Web interface with Bootstrap styling - Comprehensive error handling and logging Key components: - server.py: Main Flask application with all routes - templates/: Complete web interface templates - data/database.db: SQLite database for device logs - UPDATE_SUMMARY.md: Development progress documentation
210 lines
8.4 KiB
HTML
210 lines
8.4 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Device Logs Dashboard</title>
|
||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css">
|
||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
|
||
<style>
|
||
body {
|
||
background-color: #f8f9fa;
|
||
font-family: Arial, sans-serif;
|
||
}
|
||
h1 {
|
||
text-align: center;
|
||
color: #343a40;
|
||
}
|
||
.table-container {
|
||
background-color: #ffffff;
|
||
border-radius: 8px;
|
||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
||
padding: 20px;
|
||
}
|
||
.table {
|
||
margin-bottom: 0;
|
||
table-layout: fixed; /* Ensures consistent column widths */
|
||
width: 100%; /* Makes the table take up the full container width */
|
||
}
|
||
.table th, .table td {
|
||
text-align: center;
|
||
word-wrap: break-word; /* Ensures long text wraps within the cell */
|
||
}
|
||
.table th:nth-child(1), .table td:nth-child(1) {
|
||
width: 20%; /* Hostname column */
|
||
}
|
||
.table th:nth-child(2), .table td:nth-child(2) {
|
||
width: 20%; /* Device IP column */
|
||
}
|
||
.table th:nth-child(3), .table td:nth-child(3) {
|
||
width: 20%; /* Nume Masa column */
|
||
}
|
||
.table th:nth-child(4), .table td:nth-child(4) {
|
||
width: 20%; /* Timestamp column */
|
||
}
|
||
.table th:nth-child(5), .table td:nth-child(5) {
|
||
width: 20%; /* Event Description column */
|
||
}
|
||
.refresh-timer {
|
||
text-align: center;
|
||
margin-bottom: 10px;
|
||
font-size: 1.2rem;
|
||
color: #343a40;
|
||
}
|
||
</style>
|
||
<script>
|
||
// Countdown timer for refresh
|
||
let countdown = 30; // 30 seconds
|
||
function updateTimer() {
|
||
document.getElementById('refresh-timer').innerText = countdown;
|
||
countdown--;
|
||
if (countdown < 0) {
|
||
location.reload(); // Refresh the page
|
||
}
|
||
}
|
||
setInterval(updateTimer, 1000); // Update every second
|
||
|
||
// Database reset functionality
|
||
async function resetDatabase() {
|
||
try {
|
||
// First, get database statistics
|
||
const statsResponse = await fetch('/database_stats');
|
||
const stats = await statsResponse.json();
|
||
|
||
if (!stats.success) {
|
||
alert('❌ Error getting database statistics:\n' + stats.error);
|
||
return;
|
||
}
|
||
|
||
const totalLogs = stats.total_logs;
|
||
const uniqueDevices = stats.unique_devices;
|
||
|
||
if (totalLogs === 0) {
|
||
alert('ℹ️ Database is already empty!\nNo logs to delete.');
|
||
return;
|
||
}
|
||
|
||
// Show confirmation dialog with detailed statistics
|
||
const confirmed = confirm(
|
||
`⚠️ WARNING: Database Reset Operation ⚠️\n\n` +
|
||
`This will permanently delete:\n` +
|
||
`• ${totalLogs} log entries\n` +
|
||
`• Data from ${uniqueDevices} unique devices\n` +
|
||
`• Date range: ${stats.earliest_log} to ${stats.latest_log}\n\n` +
|
||
`⚠️ ALL DEVICE HISTORY WILL BE LOST ⚠️\n\n` +
|
||
`This action cannot be undone!\n\n` +
|
||
`Are you absolutely sure you want to proceed?`
|
||
);
|
||
|
||
if (!confirmed) {
|
||
return;
|
||
}
|
||
|
||
// Second confirmation for safety
|
||
const doubleConfirmed = confirm(
|
||
`🚨 FINAL CONFIRMATION 🚨\n\n` +
|
||
`You are about to permanently DELETE:\n` +
|
||
`✗ ${totalLogs} log entries\n` +
|
||
`✗ ${uniqueDevices} device histories\n\n` +
|
||
`This is your LAST CHANCE to cancel!\n\n` +
|
||
`Click OK to proceed with deletion.`
|
||
);
|
||
|
||
if (!doubleConfirmed) {
|
||
return;
|
||
}
|
||
|
||
// Show loading indicator
|
||
const button = event.target;
|
||
const originalText = button.innerHTML;
|
||
button.innerHTML = '<span class="spinner-border spinner-border-sm" role="status"></span> Clearing Database...';
|
||
button.disabled = true;
|
||
|
||
// Send reset request
|
||
const resetResponse = await fetch('/reset_database', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json'
|
||
}
|
||
});
|
||
|
||
const result = await resetResponse.json();
|
||
|
||
if (result.success) {
|
||
alert(
|
||
`✅ Database Reset Completed Successfully!\n\n` +
|
||
`Operation Summary:\n` +
|
||
`• ${result.deleted_count} log entries deleted\n` +
|
||
`• Database schema reinitialized\n` +
|
||
`• Reset timestamp: ${result.timestamp}\n\n` +
|
||
`The dashboard will refresh to show the clean database.`
|
||
);
|
||
location.reload(); // Refresh to show empty database
|
||
} else {
|
||
alert('❌ Database Reset Failed:\n' + result.error);
|
||
button.innerHTML = originalText;
|
||
button.disabled = false;
|
||
}
|
||
|
||
} catch (error) {
|
||
alert('❌ Network Error:\n' + error.message);
|
||
// Restore button if it was changed
|
||
try {
|
||
const button = event.target;
|
||
button.innerHTML = '<i class="fas fa-trash-alt"></i> Clear Database';
|
||
button.disabled = false;
|
||
} catch (e) {
|
||
// Ignore if button restoration fails
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
</head>
|
||
<body>
|
||
<div class="container mt-5">
|
||
<h1 class="mb-4">Device Logs Dashboard</h1>
|
||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||
<div class="refresh-timer">
|
||
Time until refresh: <span id="refresh-timer">30</span> seconds
|
||
</div>
|
||
<div>
|
||
<a href="/unique_devices" class="btn btn-secondary">View Unique Devices</a>
|
||
<a href="/device_management" class="btn btn-primary">Device Management</a>
|
||
<a href="/server_logs" class="btn btn-info" title="View server operations and system logs">
|
||
<i class="fas fa-server"></i> Server Logs
|
||
</a>
|
||
<button class="btn btn-danger" onclick="resetDatabase()" title="Clear all logs and reset database">
|
||
<i class="fas fa-trash-alt"></i> Clear Database
|
||
</button>
|
||
</div>
|
||
</div>
|
||
<div class="table-container">
|
||
<table class="table table-striped table-bordered">
|
||
<thead class="table-dark">
|
||
<tr>
|
||
<th>Hostname</th>
|
||
<th>Device IP</th>
|
||
<th>Nume Masa</th>
|
||
<th>Timestamp</th>
|
||
<th>Event Description</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
{% for log in logs %}
|
||
<tr>
|
||
<td><a href="hostname_logs/{{ log[0] }}">{{ log[0] }}</a></td>
|
||
<td>{{ log[1] }}</td>
|
||
<td><a href="/device_logs/{{ log[2] }}">{{ log[2] }}</a></td>
|
||
<td>{{ log[3] }}</td>
|
||
<td>{{ log[4] }}</td>
|
||
</tr>
|
||
{% endfor %}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
<footer>
|
||
<p class="text-center mt-4">© 2023 Device Logs Dashboard. All rights reserved.</p>
|
||
</footer>
|
||
</body>
|
||
</html> |