38f3a1e01e
Adds "Telemetria törlése" button that deletes all telemetry records and known issues for a specific app. Useful after major app updates when old data is no longer representative. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
221 lines
9.9 KiB
HTML
221 lines
9.9 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="hu">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>{{.AppName}} — Felhom Hub</title>
|
||
<link rel="stylesheet" href="/style.css">
|
||
<script src="/static/chart.min.js"></script>
|
||
</head>
|
||
<body>
|
||
<div class="container">
|
||
<header>
|
||
<h1>Felhom Hub</h1>
|
||
<nav class="nav-links">
|
||
<a href="/" class="nav-link">Dashboard</a>
|
||
<a href="/configs" class="nav-link">Customers</a>
|
||
<a href="/apps" class="nav-link active">Alkalmazások</a>
|
||
</nav>
|
||
</header>
|
||
|
||
<a href="/apps{{if .Period}}?period={{.Period}}{{end}}" class="back-link">← Alkalmazások</a>
|
||
|
||
<!-- Period selector -->
|
||
<div class="period-selector" style="margin-top: 1rem;">
|
||
<a href="?period=24h" class="period-btn{{if eq .Period "24h"}} active{{end}}">24 óra</a>
|
||
<a href="?period=7d" class="period-btn{{if or (eq .Period "7d") (eq .Period "")}} active{{end}}">7 nap</a>
|
||
<a href="?period=30d" class="period-btn{{if eq .Period "30d"}} active{{end}}">30 nap</a>
|
||
</div>
|
||
|
||
{{if eq .Flash "telemetry_reset"}}
|
||
<div class="flash flash-success" style="margin-top: 1rem;">Telemetria sikeresen törölve.</div>
|
||
{{end}}
|
||
|
||
<!-- Overview card -->
|
||
<section class="card">
|
||
<div style="display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 0.5rem;">
|
||
<h2 style="margin: 0;">{{if .Summary}}{{if .Summary.DisplayName}}{{.Summary.DisplayName}}{{else}}{{.AppName}}{{end}}{{else}}{{.AppName}}{{end}}</h2>
|
||
<form method="POST" action="/apps/{{.AppName}}/reset-telemetry{{if .Period}}?period={{.Period}}{{end}}"
|
||
onsubmit="return confirm('Biztosan törlöd a(z) {{.AppName}} összes telemetriai adatát? Ez nem vonható vissza.');">
|
||
<input type="hidden" name="csrf_token" value="{{.CSRFToken}}">
|
||
<button type="submit" class="btn btn-sm btn-danger">Telemetria törlése</button>
|
||
</form>
|
||
</div>
|
||
<div class="info-grid">
|
||
<div class="info-item">
|
||
<span class="label">App neve</span>
|
||
<span class="value" style="font-family: var(--font-mono)">{{.AppName}}</span>
|
||
</div>
|
||
{{if .Summary}}
|
||
<div class="info-item">
|
||
<span class="label">Telepítések</span>
|
||
<span class="value">{{.Summary.DeploymentCount}}</span>
|
||
</div>
|
||
<div class="info-item">
|
||
<span class="label">Katalógus becslés</span>
|
||
<span class="value">{{if .Summary.CatalogEstimate}}{{.Summary.CatalogEstimate}}{{else}}—{{end}}</span>
|
||
</div>
|
||
<div class="info-item">
|
||
<span class="label">Katalógus limit</span>
|
||
<span class="value">{{if .Summary.CatalogLimit}}{{.Summary.CatalogLimit}}{{else}}—{{end}}</span>
|
||
</div>
|
||
{{if .SuggestedLimit}}
|
||
<div class="info-item">
|
||
<span class="label">Javasolt limit (P95×1.2)</span>
|
||
<span class="value" style="color: var(--yellow)">{{.SuggestedLimit}} MB</span>
|
||
</div>
|
||
{{end}}
|
||
<div class="info-item">
|
||
<span class="label">Átl. memória</span>
|
||
<span class="value">{{formatFloat .Summary.AvgMemoryMB}} MB</span>
|
||
</div>
|
||
<div class="info-item">
|
||
<span class="label">P95 memória</span>
|
||
<span class="value {{accuracyClass .Summary.P95MemoryMB .Summary.CatalogLimit}}">{{formatFloat .Summary.P95MemoryMB}} MB</span>
|
||
</div>
|
||
<div class="info-item">
|
||
<span class="label">Átl. CPU</span>
|
||
<span class="value">{{formatFloat .Summary.AvgCPU}}%</span>
|
||
</div>
|
||
{{end}}
|
||
</div>
|
||
</section>
|
||
|
||
<!-- Memory trend chart -->
|
||
<section class="card">
|
||
<h2>Memória trend</h2>
|
||
<div class="chart-container">
|
||
<canvas id="memoryChart"></canvas>
|
||
</div>
|
||
<script>
|
||
(function() {
|
||
var chartData = {{json .ChartData}};
|
||
if (!chartData || !chartData.labels || chartData.labels.length === 0) {
|
||
document.getElementById('memoryChart').parentElement.innerHTML = '<p class="text-muted">Nincs elegendő adat a grafikonhoz.</p>';
|
||
return;
|
||
}
|
||
var ctx = document.getElementById('memoryChart').getContext('2d');
|
||
var datasets = [
|
||
{
|
||
label: 'Átl. memória (MB)',
|
||
data: chartData.avg_memory,
|
||
borderColor: '#60a5fa',
|
||
backgroundColor: 'rgba(96,165,250,0.1)',
|
||
fill: true,
|
||
tension: 0.3,
|
||
pointRadius: 2
|
||
},
|
||
{
|
||
label: 'Csúcs memória (MB)',
|
||
data: chartData.peak_memory,
|
||
borderColor: '#f87171',
|
||
backgroundColor: 'transparent',
|
||
fill: false,
|
||
tension: 0.3,
|
||
pointRadius: 2,
|
||
borderDash: [4, 2]
|
||
}
|
||
];
|
||
if (chartData.catalog_limit > 0) {
|
||
datasets.push({
|
||
label: 'Katalógus limit',
|
||
data: chartData.labels.map(function() { return chartData.catalog_limit; }),
|
||
borderColor: '#4ade80',
|
||
backgroundColor: 'transparent',
|
||
fill: false,
|
||
pointRadius: 0,
|
||
borderWidth: 1,
|
||
borderDash: [6, 4]
|
||
});
|
||
}
|
||
new Chart(ctx, {
|
||
type: 'line',
|
||
data: { labels: chartData.labels, datasets: datasets },
|
||
options: {
|
||
responsive: true,
|
||
maintainAspectRatio: false,
|
||
plugins: {
|
||
legend: { labels: { color: '#94a3b8', font: { size: 11 } } }
|
||
},
|
||
scales: {
|
||
x: { ticks: { color: '#64748b', font: { size: 10 }, maxTicksLimit: 10 }, grid: { color: 'rgba(100,116,139,0.15)' } },
|
||
y: { ticks: { color: '#64748b', font: { size: 10 } }, grid: { color: 'rgba(100,116,139,0.15)' }, title: { display: true, text: 'MB', color: '#64748b' } }
|
||
}
|
||
}
|
||
});
|
||
})();
|
||
</script>
|
||
</section>
|
||
|
||
<!-- Customer breakdown -->
|
||
{{if .Customers}}
|
||
<section class="card">
|
||
<h2>Ügyfél bontás</h2>
|
||
<table class="data-table">
|
||
<thead>
|
||
<tr>
|
||
<th>Ügyfél</th>
|
||
<th>Átl. memória</th>
|
||
<th>Csúcs memória</th>
|
||
<th>Átl. CPU</th>
|
||
<th>Hibák összesen</th>
|
||
<th>Utolsó riport</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
{{range .Customers}}
|
||
<tr>
|
||
<td><a href="/customers/{{.CustomerID}}">{{.CustomerID}}</a></td>
|
||
<td>{{formatFloat .AvgMemoryMB}} MB</td>
|
||
<td>{{formatFloat .PeakMemoryMB}} MB</td>
|
||
<td>{{formatFloat .AvgCPU}}%</td>
|
||
<td>{{if gt .TotalErrors 0}}<span class="badge badge-error">{{.TotalErrors}}</span>{{else}}0{{end}}</td>
|
||
<td>{{timeAgo .LastReport}}</td>
|
||
</tr>
|
||
{{end}}
|
||
</tbody>
|
||
</table>
|
||
</section>
|
||
{{end}}
|
||
|
||
<!-- Known issues -->
|
||
{{if .Issues}}
|
||
<section class="card">
|
||
<h2>Ismert hibák</h2>
|
||
<table class="data-table">
|
||
<thead>
|
||
<tr>
|
||
<th>Súlyosság</th>
|
||
<th>Üzenet</th>
|
||
<th>Előfordulások</th>
|
||
<th>Érintett ügyfelek</th>
|
||
<th>Első észlelés</th>
|
||
<th>Utolsó észlelés</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
{{range .Issues}}
|
||
<tr>
|
||
<td>
|
||
{{if eq .Severity "error"}}<span class="badge badge-error">error</span>
|
||
{{else}}<span class="badge badge-warn">warn</span>{{end}}
|
||
</td>
|
||
<td style="font-family: var(--font-mono); font-size: 0.8rem; max-width: 40ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;" title="{{.Message}}">{{.Message}}</td>
|
||
<td>{{.OccurrenceCount}}</td>
|
||
<td>{{len .AffectedCustomers}}</td>
|
||
<td>{{timeAgo .FirstSeen}}</td>
|
||
<td>{{timeAgo .LastSeen}}</td>
|
||
</tr>
|
||
{{end}}
|
||
</tbody>
|
||
</table>
|
||
</section>
|
||
{{end}}
|
||
|
||
<footer style="margin-top: 2rem; color: var(--text-muted); font-size: 0.8rem; text-align: center;">
|
||
Felhom Hub <span style="font-family: var(--font-mono)">v{{hubVersion}}</span>
|
||
</footer>
|
||
</div>
|
||
</body>
|
||
</html>
|