bethaus-app/templates/dashboard.html
2025-03-24 15:13:21 +01:00

253 lines
7.8 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Dashboard - Verbindungsanalyse</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet">
<style>
html, body {
height: 100%;
margin: 0;
padding: 0;
}
/* Use full width */
.container-fluid {
height: 100%;
display: flex;
flex-direction: column;
}
.card { margin-bottom: 20px; }
</style>
</head>
<body>
<div class="container-fluid">
<h1 class="mb-4">Dashboard - Verbindungsanalyse ({{ timeframe }})</h1>
<div class="mb-3">
<a href="{{ url_for('index') }}" class="btn btn-primary mt-1">App</a>
<a href="{{ url_for('mylinks') }}" class="btn btn-primary mt-1">Meine Links</a>
<a href="{{ url_for('connections') }}" class="btn btn-primary mt-1">Verbindungen</a>
<a href="{{ url_for('dashboard') }}" class="btn btn-primary mt-1">Auswertung</a>
</div>
<div class="mb-3">
<a href="{{ url_for('dashboard', timeframe='today') }}" class="btn btn-secondary btn-sm mt-1">Today</a>
<a href="{{ url_for('dashboard', timeframe='7days') }}" class="btn btn-secondary btn-sm mt-1">Last 7 Days</a>
<a href="{{ url_for('dashboard', timeframe='30days') }}" class="btn btn-secondary btn-sm mt-1">Last 30 Days</a>
<a href="{{ url_for('dashboard', timeframe='365days') }}" class="btn btn-secondary btn-sm mt-1">Last 365 Days</a>
</div>
<!-- Summary Cards -->
<div class="row mb-4">
<div class="col-md-4">
<div class="card text-white bg-info">
<div class="card-body">
<h5 class="card-title">Alle Downloads</h5>
<p class="card-text">{{ total_accesses }}</p>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card text-white bg-success">
<div class="card-body">
<h5 class="card-title">eindeutige Dateien</h5>
<p class="card-text">{{ unique_files }}</p>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card text-white bg-warning">
<div class="card-body">
<h5 class="card-title">eindeutige Nutzer</h5>
<p class="card-text">{{ unique_ips }}</p>
</div>
</div>
</div>
</div>
<!-- Charts Section -->
<div class="row">
<!-- Access Trend Chart -->
<div class="col-md-6 mb-4">
<div class="card">
<div class="card-body">
<h5 class="card-title">Downloads</h5>
<canvas id="accessTrendChart"></canvas>
</div>
</div>
</div>
<!-- Top Files Accessed Chart -->
<div class="col-md-6 mb-4">
<div class="card">
<div class="card-body">
<h5 class="card-title">Häufig geladene Dateien</h5>
<canvas id="topFilesChart"></canvas>
</div>
</div>
</div>
<!-- User Agent Distribution Chart -->
<div class="col-md-6 mb-4">
<div class="card">
<div class="card-body">
<h5 class="card-title">Verwendete Endgeräte</h5>
<canvas id="userAgentChart"></canvas>
</div>
</div>
</div>
<!-- Referrer Distribution Chart -->
<div class="col-md-6 mb-4">
<div class="card">
<div class="card-body">
<h5 class="card-title">Verteilung auf Ordner</h5>
<canvas id="referrerChart"></canvas>
</div>
</div>
</div>
</div>
<!-- New Section: IP Address Access Data -->
<div class="card">
<div class="card-header">
Verteilung der Zugriffe
</div>
<div class="card-body">
<table class="table table-bordered">
<thead>
<tr>
<th>Anzahl Downloads</th>
<th>Stadt</th>
<th>Land</th>
</tr>
</thead>
<tbody>
{% for loc in location_data %}
<tr>
<td>{{ loc.count }}</td>
<td>{{ loc.city }}</td>
<td>{{ loc.country }}</td>
</tr>
{% else %}
<tr>
<td colspan="4">No access data available for the selected timeframe.</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<!-- Detailed Table of Top File Accesses -->
<div class="card mb-4">
<div class="card-header">
Detailierte Dateizugriffe (Top 20)
</div>
<div class="card-body">
<table class="table table-striped">
<thead>
<tr>
<th>File Path</th>
<th>Access Count</th>
</tr>
</thead>
<tbody>
{% for row in rows %}
<tr>
<td>{{ row[0] }}</td>
<td>{{ row[1] }}</td>
</tr>
{% else %}
<tr>
<td colspan="2">No data available for the selected timeframe.</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
<!-- Load Chart.js from CDN -->
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
// Data passed from the backend as JSON
const dailyAccessData = {{ daily_access_data|tojson }};
const topFilesData = {{ top_files_data|tojson }};
// Note: user_agent_data now contains 'device' and 'count'
const userAgentData = {{ user_agent_data|tojson }};
const referrerData = {{ referrer_data|tojson }};
// Access Trend Chart - Line Chart
const ctxTrend = document.getElementById('accessTrendChart').getContext('2d');
new Chart(ctxTrend, {
type: 'line',
data: {
labels: dailyAccessData.map(item => item.date),
datasets: [{
label: 'Download Count',
data: dailyAccessData.map(item => item.count),
borderWidth: 2,
fill: true
}]
},
options: {
responsive: true,
plugins: { legend: { position: 'top' } },
scales: {
x: { title: { display: true, text: 'Datum' } },
y: { title: { display: true, text: 'Download Count' } }
}
}
});
// Top Files Chart - Horizontal Bar Chart
const ctxTopFiles = document.getElementById('topFilesChart').getContext('2d');
new Chart(ctxTopFiles, {
type: 'bar',
data: {
labels: topFilesData.map(item => item.full_path),
datasets: [{
label: 'Download Count',
data: topFilesData.map(item => item.access_count),
borderWidth: 1
}]
},
options: {
indexAxis: 'y',
responsive: true,
plugins: { legend: { display: false } },
scales: {
x: { title: { display: true, text: 'Download Count' } },
y: { title: { display: true, text: '' } }
}
}
});
// User Agent Distribution - Pie Chart (using aggregated device data)
const ctxUserAgent = document.getElementById('userAgentChart').getContext('2d');
new Chart(ctxUserAgent, {
type: 'pie',
data: {
labels: userAgentData.map(item => item.device),
datasets: [{
data: userAgentData.map(item => item.count)
}]
},
options: { responsive: true }
});
// Referrer Distribution - Pie Chart (with shortened referrers)
const ctxReferrer = document.getElementById('referrerChart').getContext('2d');
new Chart(ctxReferrer, {
type: 'pie',
data: {
labels: referrerData.map(item => item.referrer),
datasets: [{
data: referrerData.map(item => item.count)
}]
},
options: { responsive: true }
});
</script>
</body>
</html>