You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

163 lines
6.2 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>📊 Video Storage Analytics</title>
<style>
body { font-family: Arial, sans-serif; background:#111; color:#eee; text-align:center; }
table { margin:auto; border-collapse:collapse; width:90%; margin-top:20px; }
th, td { border:1px solid #444; padding:10px; }
th { background:#333; }
tr:nth-child(even){ background:#222; }
.controls { margin: 10px 0; }
.pagination { margin-top: 15px; }
.pagination a, .pagination span {
display:inline-block; background:#222; color:#eee; border:1px solid #444;
margin:0 5px; padding:6px 12px; text-decoration:none;
}
.pagination .active { background:#555; }
input[type="text"] { padding:8px; width:300px; }
button { padding:8px 12px; }
</style>
</head>
<body>
<script>
const table = document.getElementById('analytics-table');
const headers = table.querySelectorAll('th');
const searchInput = document.getElementById('search');
const rows = Array.from(table.querySelector('tbody').rows);
const pagination = document.getElementById('pagination');
let sortDirection = {};
let currentPage = 1;
const rowsPerPage = 100;
// Sorting
headers.forEach((header, index) => {
header.addEventListener('click', () => {
const isNumeric = index >= 2;
const dir = sortDirection[index] === 'asc' ? 'desc' : 'asc';
sortDirection = { [index]: dir };
headers.forEach(h => h.classList.remove('sort-asc', 'sort-desc'));
header.classList.add(dir === 'asc' ? 'sort-asc' : 'sort-desc');
rows.sort((a, b) => {
const aVal = isNumeric ? parseFloat(a.cells[index].innerText) : a.cells[index].innerText.toLowerCase();
const bVal = isNumeric ? parseFloat(b.cells[index].innerText) : b.cells[index].innerText.toLowerCase();
return dir === 'asc' ? (aVal > bVal ? 1 : -1) : (aVal < bVal ? 1 : -1);
});
updateTable();
});
});
// Search
searchInput.addEventListener('keyup', () => {
currentPage = 1;
updateTable();
});
function updateTable() {
const term = searchInput.value.toLowerCase();
const filtered = rows.filter(row => row.cells[0].innerText.toLowerCase().includes(term));
const totalPages = Math.ceil(filtered.length / rowsPerPage);
updatePagination(totalPages);
table.querySelector('tbody').innerHTML = '';
const start = (currentPage - 1) * rowsPerPage;
const paginated = filtered.slice(start, start + rowsPerPage);
paginated.forEach(row => table.querySelector('tbody').appendChild(row));
}
updateTable(); // Initial render
</script>
<h1>📊 Video Storage Analytics</h1>
<div class="controls">
<button onclick="window.location.href='/refresh'">🔄 Refresh Data</button>
<!-- Server-side search -->
<form method="get" action="{{ url_for('dashboard') }}" style="display:inline-block; margin-left:10px;">
<input type="text" name="q" placeholder="Search users..." value="{{ query or '' }}">
<button type="submit">Search</button>
</form>
</div>
<table id="analytics-table">
<thead>
<tr>
{% set next_user_dir = 'asc' if sort != 'user' or dir == 'desc' else 'desc' %}
{% set next_platform_dir = 'asc' if sort != 'platform' or dir == 'desc' else 'desc' %}
{% set next_total_dir = 'asc' if sort != 'total_size' or dir == 'desc' else 'desc' %}
{% set next_count_dir = 'asc' if sort != 'video_count' or dir == 'desc' else 'desc' %}
{% set next_avg_dir = 'asc' if sort != 'avg_size' or dir == 'desc' else 'desc' %}
<th>
<a href="{{ url_for('dashboard', q=query, page=1, sort='user', dir=next_user_dir) }}">
User{% if sort=='user' %} {{ '▲' if dir=='asc' else '▼' }}{% endif %}
</a>
</th>
<th>
<a href="{{ url_for('dashboard', q=query, page=1, sort='platform', dir=next_platform_dir) }}">
Platform{% if sort=='platform' %} {{ '▲' if dir=='asc' else '▼' }}{% endif %}
</a>
</th>
<th>
<a href="{{ url_for('dashboard', q=query, page=1, sort='total_size', dir=next_total_dir) }}">
Total Storage (GB){% if sort=='total_size' %} {{ '▲' if dir=='asc' else '▼' }}{% endif %}
</a>
</th>
<th>
<a href="{{ url_for('dashboard', q=query, page=1, sort='video_count', dir=next_count_dir) }}">
Video Count{% if sort=='video_count' %} {{ '▲' if dir=='asc' else '▼' }}{% endif %}
</a>
</th>
<th>
<a href="{{ url_for('dashboard', q=query, page=1, sort='avg_size', dir=next_avg_dir) }}">
Avg Size per Video (GB){% if sort=='avg_size' %} {{ '▲' if dir=='asc' else '▼' }}{% endif %}
</a>
</th>
</tr>
</thead>
<tbody>
{% for key, stats in storage_usage %}
{% set user, platform = key.split("::") %}
<tr>
<td><a href="/user/{{ user }}" style="color:#4af;">{{ user }}</a></td>
<td>{{ platform }}</td>
<td>{{ "%.2f"|format(stats.total_size) }}</td>
<td>{{ stats.video_count }}</td>
<td>{{ "%.2f"|format(avg_sizes[key]) }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<!-- Server-side pagination -->
{% if total_pages > 1 %}
<div class="pagination">
{% if page > 1 %}
<a href="{{ url_for('dashboard', page=page-1, q=query) }}">« Prev</a>
{% else %}
<span>« Prev</span>
{% endif %}
{% for p in range(1, total_pages + 1) %}
{% if p == page %}
<span class="active">{{ p }}</span>
{% else %}
<a href="{{ url_for('dashboard', page=p, q=query) }}">{{ p }}</a>
{% endif %}
{% endfor %}
{% if page < total_pages %}
<a href="{{ url_for('dashboard', page=page+1, q=query) }}">Next »</a>
{% else %}
<span>Next »</span>
{% endif %}
</div>
{% endif %}
</body>
</html>