Zwischenstand - ohne Prometheus
Dieser Commit ist enthalten in:
@@ -59,12 +59,15 @@
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.grafana-info {
|
||||
background: #e7f3ff;
|
||||
border: 1px solid #b3d9ff;
|
||||
padding: 15px;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 20px;
|
||||
.loading-spinner {
|
||||
text-align: center;
|
||||
padding: 50px;
|
||||
}
|
||||
|
||||
.no-data {
|
||||
text-align: center;
|
||||
padding: 30px;
|
||||
color: #6c757d;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
@@ -77,21 +80,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Grafana Integration Info -->
|
||||
<div class="grafana-info">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-md-8">
|
||||
<h5><i class="bi bi-graph-up"></i> Erweiterte Analytics verfügbar</h5>
|
||||
<p class="mb-0">Für detaillierte Dashboards und erweiterte Analysen nutzen Sie unser Grafana Dashboard.</p>
|
||||
</div>
|
||||
<div class="col-md-4 text-end">
|
||||
<a href="http://localhost:3000/d/license-server-overview" target="_blank" class="btn btn-primary">
|
||||
<i class="bi bi-box-arrow-up-right"></i> Grafana öffnen
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Date Range Selector -->
|
||||
<div class="date-range-selector">
|
||||
<div class="row align-items-center">
|
||||
@@ -115,115 +103,33 @@
|
||||
|
||||
<!-- Key Metrics Overview -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-3">
|
||||
<div class="col-md-4">
|
||||
<div class="stat-box">
|
||||
<div class="stat-value">1,234</div>
|
||||
<div class="stat-value" id="active-licenses">-</div>
|
||||
<div class="stat-label">Aktive Lizenzen</div>
|
||||
<div class="trend-up">
|
||||
<i class="bi bi-arrow-up"></i> +12% vs. Vormonat
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="col-md-4">
|
||||
<div class="stat-box">
|
||||
<div class="stat-value">45.2K</div>
|
||||
<div class="stat-value" id="total-validations">-</div>
|
||||
<div class="stat-label">Validierungen</div>
|
||||
<div class="trend-up">
|
||||
<i class="bi bi-arrow-up"></i> +8% vs. Vormonat
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="col-md-4">
|
||||
<div class="stat-box">
|
||||
<div class="stat-value">€12.5K</div>
|
||||
<div class="stat-label">MRR</div>
|
||||
<div class="trend-up">
|
||||
<i class="bi bi-arrow-up"></i> +15% vs. Vormonat
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="stat-box">
|
||||
<div class="stat-value">2.3%</div>
|
||||
<div class="stat-label">Churn Rate</div>
|
||||
<div class="trend-down">
|
||||
<i class="bi bi-arrow-down"></i> -0.5% vs. Vormonat
|
||||
</div>
|
||||
<div class="stat-value" id="active-devices">-</div>
|
||||
<div class="stat-label">Aktive Geräte</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Charts Row 1 -->
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="analytics-card">
|
||||
<h5>Lizenz-Nutzung über Zeit</h5>
|
||||
<div class="chart-container">
|
||||
<canvas id="usageChart"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="analytics-card">
|
||||
<h5>Validierungen nach Stunde</h5>
|
||||
<div class="chart-container">
|
||||
<canvas id="validationChart"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Charts Row 2 -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-md-4">
|
||||
<div class="analytics-card">
|
||||
<h5>Lizenztyp-Verteilung</h5>
|
||||
<div class="chart-container">
|
||||
<canvas id="licenseTypeChart"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="analytics-card">
|
||||
<h5>Geografische Verteilung</h5>
|
||||
<div class="chart-container">
|
||||
<canvas id="geoChart"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="analytics-card">
|
||||
<h5>Top 10 Kunden</h5>
|
||||
<div style="height: 300px; overflow-y: auto;">
|
||||
<table class="table table-sm">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Kunde</th>
|
||||
<th>Lizenzen</th>
|
||||
<th>Nutzung</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>ACME Corp</td>
|
||||
<td>45</td>
|
||||
<td><span class="badge bg-success">Hoch</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>TechStart GmbH</td>
|
||||
<td>32</td>
|
||||
<td><span class="badge bg-success">Hoch</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Global Solutions</td>
|
||||
<td>28</td>
|
||||
<td><span class="badge bg-warning">Mittel</span></td>
|
||||
</tr>
|
||||
<!-- More rows... -->
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Analytics Notice -->
|
||||
<div class="analytics-card">
|
||||
<div class="no-data">
|
||||
<i class="bi bi-info-circle" style="font-size: 3rem; color: #6c757d;"></i>
|
||||
<h5 class="mt-3">Analytics-Daten werden gesammelt</h5>
|
||||
<p>Die detaillierten Analysen stehen zur Verfügung, sobald genügend Daten vorhanden sind.</p>
|
||||
<p>Nutzen Sie das <a href="{{ url_for('monitoring.live_dashboard') }}">Live Dashboard</a> für Echtzeit-Statistiken.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -245,114 +151,43 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_js %}
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.js"></script>
|
||||
<script>
|
||||
let usageChart, validationChart, licenseTypeChart, geoChart;
|
||||
|
||||
function initCharts() {
|
||||
// Usage over time
|
||||
const usageCtx = document.getElementById('usageChart').getContext('2d');
|
||||
usageChart = new Chart(usageCtx, {
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: ['Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa', 'So'],
|
||||
datasets: [{
|
||||
label: 'Aktive Lizenzen',
|
||||
data: [1180, 1205, 1195, 1220, 1234, 1150, 1100],
|
||||
borderColor: 'rgb(75, 192, 192)',
|
||||
backgroundColor: 'rgba(75, 192, 192, 0.1)',
|
||||
tension: 0.1
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false
|
||||
}
|
||||
});
|
||||
|
||||
// Validations by hour
|
||||
const validationCtx = document.getElementById('validationChart').getContext('2d');
|
||||
validationChart = new Chart(validationCtx, {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: ['00', '04', '08', '12', '16', '20'],
|
||||
datasets: [{
|
||||
label: 'Validierungen',
|
||||
data: [120, 80, 450, 680, 520, 340],
|
||||
backgroundColor: 'rgba(54, 162, 235, 0.5)',
|
||||
borderColor: 'rgba(54, 162, 235, 1)',
|
||||
borderWidth: 1
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false
|
||||
}
|
||||
});
|
||||
|
||||
// License type distribution
|
||||
const typeCtx = document.getElementById('licenseTypeChart').getContext('2d');
|
||||
licenseTypeChart = new Chart(typeCtx, {
|
||||
type: 'doughnut',
|
||||
data: {
|
||||
labels: ['Professional', 'Enterprise', 'Starter', 'Trial'],
|
||||
datasets: [{
|
||||
data: [45, 30, 20, 5],
|
||||
backgroundColor: [
|
||||
'rgba(255, 99, 132, 0.5)',
|
||||
'rgba(54, 162, 235, 0.5)',
|
||||
'rgba(255, 205, 86, 0.5)',
|
||||
'rgba(75, 192, 192, 0.5)'
|
||||
]
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false
|
||||
}
|
||||
});
|
||||
|
||||
// Geographic distribution
|
||||
const geoCtx = document.getElementById('geoChart').getContext('2d');
|
||||
geoChart = new Chart(geoCtx, {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: ['DE', 'AT', 'CH', 'US', 'UK'],
|
||||
datasets: [{
|
||||
label: 'Aktive Nutzer',
|
||||
data: [580, 230, 180, 120, 90],
|
||||
backgroundColor: 'rgba(153, 102, 255, 0.5)',
|
||||
borderColor: 'rgba(153, 102, 255, 1)',
|
||||
borderWidth: 1
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
indexAxis: 'y'
|
||||
}
|
||||
});
|
||||
function loadAnalyticsData() {
|
||||
// Load basic statistics from database
|
||||
fetch('/monitoring/api/live-stats')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
document.getElementById('active-licenses').textContent = data.active_licenses || '0';
|
||||
document.getElementById('total-validations').textContent = data.validations_last_minute || '0';
|
||||
document.getElementById('active-devices').textContent = data.active_devices || '0';
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error loading analytics:', error);
|
||||
document.getElementById('active-licenses').textContent = '0';
|
||||
document.getElementById('total-validations').textContent = '0';
|
||||
document.getElementById('active-devices').textContent = '0';
|
||||
});
|
||||
}
|
||||
|
||||
function updateAnalytics() {
|
||||
const range = document.getElementById('date-range').value;
|
||||
// In production, this would fetch new data based on the selected range
|
||||
console.log('Updating analytics for range:', range);
|
||||
loadAnalyticsData();
|
||||
}
|
||||
|
||||
function refreshAnalytics() {
|
||||
// Refresh all data
|
||||
location.reload();
|
||||
loadAnalyticsData();
|
||||
}
|
||||
|
||||
function exportReport(format) {
|
||||
alert(`Exporting report as ${format.toUpperCase()}...`);
|
||||
// In production, this would trigger actual export
|
||||
alert(`Export-Funktion wird implementiert für Format: ${format.toUpperCase()}`);
|
||||
}
|
||||
|
||||
// Initialize charts on page load
|
||||
// Load data on page load
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
initCharts();
|
||||
loadAnalyticsData();
|
||||
// Refresh every 30 seconds
|
||||
setInterval(loadAnalyticsData, 30000);
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren