Files
OpenVPN-Monitoring-Simple/UI/artifacts/index.php
2026-01-09 21:07:45 +03:00

198 lines
9.9 KiB
PHP

<?php
require_once 'config.php';
// Wrapper variables for compatibility with existing template logic
$api_url = $api_config['stats_url'];
$refresh_interval = $api_config['refresh_interval'];
$timezone_abbr = date('T');
$timezone_offset = date('P');
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>OpenVPN Client Statistics</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
<link href="css/style.css?v=<?php echo time(); ?>" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="js/utils.js?v=<?php echo time(); ?>"></script>
</head>
<body>
<div class="main-content-wrapper">
<div class="container">
<div class="header">
<div class="d-flex justify-content-between align-items-start flex-wrap">
<div class="mb-3 mb-md-0">
<h1 class="h3 mb-1">OpenVPN Monitor</h1>
<p class="text-muted mb-0">Real-time traffic & connection statistics</p>
</div>
<div class="d-flex align-items-center flex-wrap gap-2">
<a href="index.php" class="btn-nav active">
<i class="fas fa-list me-2"></i>Clients
</a>
<a href="certificates.php" class="btn-nav">
<i class="fas fa-certificate me-2"></i>Certificates
</a>
<a href="dashboard.php" class="btn-nav">
<i class="fas fa-chart-pie me-2"></i>Analytics
</a>
<span class="header-badge" id="clientCount">0 clients</span>
<span class="header-timezone">
<i class="fas fa-globe me-1 text-muted"></i><?php echo $timezone_abbr; ?>
</span>
<button class="btn-header" onclick="toggleTheme()" title="Toggle Theme">
<i class="fas fa-moon" id="themeIcon"></i>
</button>
<button class="btn-header" onclick="fetchData()" title="Refresh">
<i class="fas fa-sync-alt" id="refreshIcon"></i>
</button>
</div>
</div>
</div>
<div class="stats-info" id="statsInfo">
<div class="stat-item">
<div class="stat-value" id="totalReceived">0 B</div>
<div class="stat-label">Total Received</div>
</div>
<div class="stat-item">
<div class="stat-value" id="totalSent">0 B</div>
<div class="stat-label">Total Sent</div>
</div>
<div class="stat-item">
<div class="stat-value" id="activeClients">0</div>
<div class="stat-label">Active Clients</div>
</div>
</div>
<div class="d-flex justify-content-between align-items-center mb-3 flex-wrap gap-3">
<div class="d-flex gap-3 align-items-center flex-wrap">
<div class="sort-btn-group">
<button class="sort-btn" onclick="changeSort('received')" id="sortRecv">Received</button>
<button class="sort-btn active" onclick="changeSort('sent')" id="sortSent">Sent</button>
</div>
<div class="input-group input-group-sm" style="width: 250px;">
<span class="input-group-text"><i class="fas fa-search"></i></span>
<input type="text" class="form-control" id="clientSearch" placeholder="Search client..."
onkeyup="handleSearch(this.value)">
</div>
</div>
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="hideDisconnected"
onchange="toggleDisconnected()">
<label class="form-check-label user-select-none text-muted" for="hideDisconnected">Hide
Disconnected</label>
</div>
</div>
<div class="card">
<div class="card-header d-flex justify-content-between align-items-center bg-transparent border-bottom">
<span><i class="fas fa-network-wired me-2"></i>Clients List</span>
<small class="text-muted" id="lastUpdated">Updating...</small>
</div>
<div class="table-responsive">
<table class="table table-hover mb-0">
<thead>
<tr>
<th>Client Name</th>
<th>Real Address</th>
<th>Status</th>
<th onclick="changeSort('received')" id="thRecv">Received</th>
<th onclick="changeSort('sent')" id="thSent">Sent</th>
<th>Max 30s DL</th>
<th>Max 30s UL</th>
<th>Last Activity</th>
</tr>
</thead>
<tbody id="statsTable">
<tr>
<td colspan="8" class="text-center py-4 text-muted">Loading...</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<div class="modal fade" id="historyModal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-xl modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">
<i class="fas fa-chart-area me-2" style="color: var(--accent-color);"></i>
<span id="modalClientName">Client Name</span>
</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class="chart-controls">
<div class="d-flex align-items-center gap-2">
<label for="historyRange" class="text-muted"><i class="far fa-clock me-1"></i>
Range:</label>
<select id="historyRange" class="form-select form-select-sm"
style="width: auto; min-width: 200px;" onchange="updateHistoryRange()">
<option value="1h">Last 1 Hour (30s agg)</option>
<option value="3h">Last 3 Hours (1m agg)</option>
<option value="6h">Last 6 Hours (1m agg)</option>
<option value="12h">Last 12 Hours (1m agg)</option>
<option value="24h" selected>Last 24 Hours (1m agg)</option>
<option disabled>──────────</option>
<option value="24h">Last 1 Day (15m agg)</option>
<option value="2d">Last 2 Days (15m agg)</option>
<option value="3d">Last 3 Days (15m agg)</option>
<option disabled>──────────</option>
<option value="4d">Last 4 Days (1h agg)</option>
<option value="5d">Last 5 Days (1h agg)</option>
<option value="6d">Last 6 Days (1h agg)</option>
<option value="7d">Last 7 Days (1h agg)</option>
<option value="14d">Last 14 Days (1h agg)</option>
<option value="30d">Last 1 Month (1h agg)</option>
</select>
</div>
<div class="d-flex align-items-center gap-3 bg-white-custom px-3 py-1 border rounded">
<span class="small fw-bold text-muted">Metric:</span>
<div class="form-check form-switch mb-0">
<input class="form-check-input" type="checkbox" role="switch" id="vizToggle"
onchange="toggleVizMode()">
<label class="form-check-label text-main" for="vizToggle" id="vizLabel">Data
Volume</label>
</div>
</div>
</div>
<div class="modal-chart-container">
<canvas id="trafficChart"></canvas>
<div id="chartLoader" class="position-absolute top-50 start-50 translate-middle"
style="display: none;">
<div class="spinner-border text-primary" role="status"></div>
</div>
</div>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script src="js/utils.js"></script>
<script>
// Pass PHP Configuration to JS
window.AppConfig = {
apiUrl: '<?php echo $api_url; ?>',
refreshTime: <?php echo $refresh_interval; ?>
};
</script>
<script src="js/pages/index.js?v=<?php echo time(); ?>"></script>
</body>
</html>