320 lines
10 KiB
HTML
320 lines
10 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<title>GomeshAlerter Dashboard</title>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<meta http-equiv="refresh" content="300"><!-- Auto refresh every 5 minutes -->
|
|
<style>
|
|
body {
|
|
font-family: Arial, sans-serif;
|
|
margin: 0;
|
|
padding: 20px;
|
|
background-color: #f5f5f5;
|
|
color: #333;
|
|
}
|
|
h1, h2 {
|
|
color: #2c3e50;
|
|
}
|
|
.container {
|
|
max-width: 90%;
|
|
margin: 0 auto;
|
|
}
|
|
.stats {
|
|
background-color: #fff;
|
|
border-radius: 5px;
|
|
padding: 15px;
|
|
margin-bottom: 20px;
|
|
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
justify-content: space-between;
|
|
}
|
|
.stat-box {
|
|
text-align: center;
|
|
padding: 10px;
|
|
flex: 1;
|
|
min-width: 150px;
|
|
margin: 5px;
|
|
}
|
|
.stat-number {
|
|
font-size: 24px;
|
|
font-weight: bold;
|
|
margin: 5px 0;
|
|
color: #3498db;
|
|
}
|
|
.stat-label {
|
|
font-size: 14px;
|
|
color: #7f8c8d;
|
|
}
|
|
table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
margin-bottom: 20px;
|
|
background-color: #fff;
|
|
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
|
}
|
|
th, td {
|
|
padding: 12px 15px;
|
|
text-align: left;
|
|
border-bottom: 1px solid #ddd;
|
|
}
|
|
th {
|
|
background-color: #2c3e50;
|
|
color: white;
|
|
position: sticky;
|
|
top: 0;
|
|
}
|
|
tr:hover {
|
|
background-color: #f1f1f1;
|
|
}
|
|
.importance {
|
|
font-weight: bold;
|
|
text-align: center;
|
|
width: 100px;
|
|
}
|
|
.high {
|
|
color: #e74c3c;
|
|
}
|
|
.medium {
|
|
color: #f39c12;
|
|
}
|
|
.low {
|
|
color: #27ae60;
|
|
}
|
|
.timestamp {
|
|
font-size: 0.9em;
|
|
color: #7f8c8d;
|
|
min-width: 120px;
|
|
font-family: monospace;
|
|
white-space: nowrap;
|
|
}
|
|
.timestamp[title] {
|
|
text-decoration: none;
|
|
border-bottom: 1px dotted #7f8c8d;
|
|
}
|
|
.source {
|
|
font-weight: bold;
|
|
color: #2980b9;
|
|
min-width: 120px;
|
|
}
|
|
.id {
|
|
font-family: monospace;
|
|
font-size: 0.85em;
|
|
color: #7f8c8d;
|
|
max-width: 180px;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
.title {
|
|
font-style: italic;
|
|
color: #555;
|
|
}
|
|
.article-link {
|
|
color: #3498db;
|
|
text-decoration: none;
|
|
}
|
|
.article-link:hover {
|
|
text-decoration: underline;
|
|
}
|
|
.refresh {
|
|
margin-bottom: 20px;
|
|
}
|
|
.refresh a {
|
|
display: inline-block;
|
|
padding: 8px 16px;
|
|
background-color: #3498db;
|
|
color: white;
|
|
text-decoration: none;
|
|
border-radius: 4px;
|
|
}
|
|
.refresh a:hover {
|
|
background-color: #2980b9;
|
|
}
|
|
.section {
|
|
margin-bottom: 30px;
|
|
}
|
|
.log-event {
|
|
font-weight: bold;
|
|
font-family: monospace;
|
|
}
|
|
.log-table {
|
|
font-size: 0.9em;
|
|
}
|
|
.log-details {
|
|
white-space: normal;
|
|
word-break: break-word;
|
|
}
|
|
.log-key {
|
|
font-weight: bold;
|
|
color: #2980b9; /* Blue color for keys */
|
|
font-family: monospace;
|
|
}
|
|
.log-value {
|
|
color: #16a085; /* Green color for values */
|
|
margin-right: 10px;
|
|
font-family: monospace;
|
|
}
|
|
.log-separator {
|
|
color: #7f8c8d;
|
|
margin: 0 2px;
|
|
font-family: monospace;
|
|
}
|
|
.footer {
|
|
background-color: #e0e0e0;
|
|
padding: 15px;
|
|
text-align: center;
|
|
font-size: 12px;
|
|
color: #777;
|
|
margin-top: 40px;
|
|
border-radius: 5px;
|
|
box-shadow: 0 -2px 5px rgba(0,0,0,0.1);
|
|
}
|
|
.footer a {
|
|
color: #555;
|
|
text-decoration: none;
|
|
}
|
|
.footer a:hover {
|
|
text-decoration: underline;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="container">
|
|
<h1>GomeshAlerter Dashboard</h1>
|
|
|
|
<div class="refresh">
|
|
<a href="/">Refresh Dashboard</a>
|
|
</div>
|
|
|
|
<div class="stats">
|
|
<div class="stat-box">
|
|
<div class="stat-label">Last Updated</div>
|
|
<div class="stat-number">{{.LastUpdated}}</div>
|
|
</div>
|
|
<div class="stat-box">
|
|
<div class="stat-label">Total Articles</div>
|
|
<div class="stat-number">{{.TotalArticles}}</div>
|
|
</div>
|
|
<div class="stat-box">
|
|
<div class="stat-label">Total Broadcast</div>
|
|
<div class="stat-number">{{.TotalBroadcast}}</div>
|
|
</div>
|
|
<div class="stat-box">
|
|
<div class="stat-label">New in Last Hour</div>
|
|
<div class="stat-number">{{.NewInLastHour}}</div>
|
|
</div>
|
|
<div class="stat-box">
|
|
<div class="stat-label">Awaiting Summary</div>
|
|
<div class="stat-number">{{.UnsummarizedCount}}</div>
|
|
</div>
|
|
<div class="stat-box">
|
|
<div class="stat-label">Next Broadcast In</div>
|
|
<div class="stat-number">{{.NextBroadcastIn}}</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="section">
|
|
<h2>Next Up for Broadcast (Top 25)</h2>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>ID</th>
|
|
<th>Importance</th>
|
|
<th>Source</th>
|
|
<th>Original Title</th>
|
|
<th>Summary</th>
|
|
<th>First Seen</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{{range .NextUp}}
|
|
<tr>
|
|
<td class="id">{{.ID}}</td>
|
|
<td class="importance {{if ge .Importance 70}}high{{else if ge .Importance 40}}medium{{else}}low{{end}}">{{.Importance}}</td>
|
|
<td class="source">{{.Source}}</td>
|
|
<td class="title">{{.Title}}</td>
|
|
<td><a href="{{.Link}}" class="article-link" target="_blank">{{.Summary}}</a></td>
|
|
<td class="timestamp" title="{{.FirstSeen.Format "2006-01-02 15:04:05 MST"}}">{{.RelativeTime}}</td>
|
|
</tr>
|
|
{{else}}
|
|
<tr>
|
|
<td colspan="6">No articles ready for broadcast</td>
|
|
</tr>
|
|
{{end}}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<div class="section">
|
|
<h2>Broadcast History (Last 100)</h2>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>ID</th>
|
|
<th>Broadcast Time</th>
|
|
<th>Importance</th>
|
|
<th>Source</th>
|
|
<th>Original Title</th>
|
|
<th>Summary</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{{range .History}}
|
|
<tr>
|
|
<td class="id">{{.ID}}</td>
|
|
<td class="timestamp" title="{{.BroadcastTime.Format "2006-01-02 15:04:05 MST"}}">{{.BroadcastRelativeTime}}</td>
|
|
<td class="importance {{if ge .Importance 70}}high{{else if ge .Importance 40}}medium{{else}}low{{end}}">{{.Importance}}</td>
|
|
<td class="source">{{.Source}}</td>
|
|
<td class="title">{{.Title}}</td>
|
|
<td><a href="{{.Link}}" class="article-link" target="_blank">{{.Summary}}</a></td>
|
|
</tr>
|
|
{{else}}
|
|
<tr>
|
|
<td colspan="6">No broadcast history available</td>
|
|
</tr>
|
|
{{end}}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<div class="section">
|
|
<h2>Recent Logs (Last 1000)</h2>
|
|
<table class="log-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Timestamp</th>
|
|
<th>Event</th>
|
|
<th>Details</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{{range .RecentLogs}}
|
|
<tr>
|
|
<td class="timestamp" style="white-space: nowrap;">{{.Timestamp.Format "2006-01-02 15:04:05 MST"}}</td>
|
|
<td class="log-event">{{.Event}}</td>
|
|
<td class="log-details">
|
|
{{range $key, $value := .Details}}
|
|
{{if ne $key "timestamp"}}
|
|
{{if ne $key "event"}}
|
|
<span class="log-key">{{$key}}</span><span class="log-separator">=</span><span class="log-value">{{$value}}</span>
|
|
{{end}}
|
|
{{end}}
|
|
{{end}}
|
|
</td>
|
|
</tr>
|
|
{{else}}
|
|
<tr>
|
|
<td colspan="3">No log entries available</td>
|
|
</tr>
|
|
{{end}}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="footer">
|
|
<a href="https://git.eeqj.de/sneak/gomeshalerter">gomeshalerter</a> is a project by <a href="https://sneak.berlin">@sneak</a> and released under the WTFPL (<a href="https://git.eeqj.de/sneak/gomeshalerter">source</a>)
|
|
</div>
|
|
</body>
|
|
</html> |