- Flask-based web application with PostgreSQL - User authentication and session management - Content moderation and filtering - Docker deployment with docker-compose - Admin interface for content management 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
189 lines
6.1 KiB
HTML
189 lines
6.1 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Polling Logs - {{ source.display_name }} - Admin</title>
|
|
<link rel="stylesheet" href="{{ url_for('serve_theme', filename='modern-card-ui/styles.css') }}">
|
|
<style>
|
|
.admin-container {
|
|
max-width: 1400px;
|
|
margin: 0 auto;
|
|
padding: 24px;
|
|
}
|
|
|
|
.admin-header {
|
|
background: linear-gradient(135deg, var(--primary-dark) 0%, #2a5068 100%);
|
|
color: white;
|
|
padding: 32px;
|
|
border-radius: 12px;
|
|
margin-bottom: 24px;
|
|
}
|
|
|
|
.log-table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
background: var(--surface-color);
|
|
border-radius: 12px;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.log-table th {
|
|
background: var(--primary-color);
|
|
color: white;
|
|
padding: 12px;
|
|
text-align: left;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.log-table td {
|
|
padding: 12px;
|
|
border-bottom: 1px solid var(--divider-color);
|
|
}
|
|
|
|
.log-table tr:last-child td {
|
|
border-bottom: none;
|
|
}
|
|
|
|
.status-badge {
|
|
display: inline-block;
|
|
padding: 4px 12px;
|
|
border-radius: 12px;
|
|
font-size: 0.85rem;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.status-success {
|
|
background: #d4edda;
|
|
color: #155724;
|
|
}
|
|
|
|
.status-error {
|
|
background: #f8d7da;
|
|
color: #721c24;
|
|
}
|
|
|
|
.status-running {
|
|
background: #fff3cd;
|
|
color: #856404;
|
|
}
|
|
|
|
.error-detail {
|
|
background: #fff3cd;
|
|
padding: 12px;
|
|
border-radius: 6px;
|
|
margin-top: 8px;
|
|
font-size: 0.9rem;
|
|
white-space: pre-wrap;
|
|
max-height: 200px;
|
|
overflow-y: auto;
|
|
}
|
|
|
|
.btn {
|
|
padding: 8px 16px;
|
|
border: none;
|
|
border-radius: 6px;
|
|
cursor: pointer;
|
|
font-weight: 500;
|
|
text-decoration: none;
|
|
display: inline-block;
|
|
transition: all 0.2s;
|
|
}
|
|
|
|
.btn-secondary {
|
|
background: var(--divider-color);
|
|
color: var(--text-primary);
|
|
}
|
|
|
|
.btn-secondary:hover {
|
|
background: #d0d0d0;
|
|
}
|
|
|
|
.no-logs {
|
|
text-align: center;
|
|
padding: 48px;
|
|
color: var(--text-secondary);
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="admin-container">
|
|
<div class="admin-header">
|
|
<h1>📋 Polling Logs</h1>
|
|
<p>{{ source.display_name }} ({{ source.platform}}:{{ source.source_id }})</p>
|
|
</div>
|
|
|
|
{% if logs %}
|
|
<table class="log-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Started</th>
|
|
<th>Completed</th>
|
|
<th>Duration</th>
|
|
<th>Status</th>
|
|
<th>Posts Found</th>
|
|
<th>New</th>
|
|
<th>Updated</th>
|
|
<th>Details</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for log in logs %}
|
|
<tr>
|
|
<td>{{ log.started_at.strftime('%Y-%m-%d %H:%M:%S') }}</td>
|
|
<td>
|
|
{% if log.completed_at %}
|
|
{{ log.completed_at.strftime('%Y-%m-%d %H:%M:%S') }}
|
|
{% else %}
|
|
-
|
|
{% endif %}
|
|
</td>
|
|
<td>
|
|
{% if log.completed_at %}
|
|
{{ ((log.completed_at - log.started_at).total_seconds())|round(1) }}s
|
|
{% else %}
|
|
-
|
|
{% endif %}
|
|
</td>
|
|
<td>
|
|
{% if log.status == 'success' %}
|
|
<span class="status-badge status-success">Success</span>
|
|
{% elif log.status == 'error' %}
|
|
<span class="status-badge status-error">Error</span>
|
|
{% elif log.status == 'running' %}
|
|
<span class="status-badge status-running">Running</span>
|
|
{% else %}
|
|
<span class="status-badge">{{ log.status }}</span>
|
|
{% endif %}
|
|
</td>
|
|
<td>{{ log.posts_found }}</td>
|
|
<td>{{ log.posts_new }}</td>
|
|
<td>{{ log.posts_updated }}</td>
|
|
<td>
|
|
{% if log.error_message %}
|
|
<details>
|
|
<summary style="cursor: pointer; color: var(--primary-color);">View Error</summary>
|
|
<div class="error-detail">{{ log.error_message }}</div>
|
|
</details>
|
|
{% else %}
|
|
-
|
|
{% endif %}
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
{% else %}
|
|
<div class="no-logs">
|
|
<p>No polling logs yet.</p>
|
|
<p>Logs will appear here after the first poll.</p>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<div style="margin-top: 24px;">
|
|
<a href="{{ url_for('admin_polling') }}" class="btn btn-secondary">← Back to Polling Management</a>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>
|