Files
SportstimeAPI/templates/dashboard/stats.html
Trey t 63acf7accb feat: add Django web app, CloudKit sync, dashboard, and game_datetime_utc export
Adds the full Django application layer on top of sportstime_parser:
- core: Sport, Team, Stadium, Game models with aliases and league structure
- scraper: orchestration engine, adapter, job management, Celery tasks
- cloudkit: CloudKit sync client, sync state tracking, sync jobs
- dashboard: staff dashboard for monitoring scrapers, sync, review queue
- notifications: email reports for scrape/sync results
- Docker setup for deployment (Dockerfile, docker-compose, entrypoint)

Game exports now use game_datetime_utc (ISO 8601 UTC) instead of
venue-local date+time strings, matching the canonical format used
by the iOS app.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 14:04:27 -06:00

112 lines
3.7 KiB
HTML

{% extends 'base.html' %}
{% block content %}
<div class="page-header">
<h2>Statistics</h2>
</div>
<!-- Game Stats -->
<div class="card">
<div class="card-header">
<h3>Game Statistics</h3>
</div>
<div class="stat-grid">
<div class="stat-card">
<div class="stat-value">{{ game_stats.total|floatformat:0 }}</div>
<div class="stat-label">Total Games</div>
</div>
<div class="stat-card success">
<div class="stat-value">{{ game_stats.final|floatformat:0 }}</div>
<div class="stat-label">Completed</div>
</div>
<div class="stat-card primary">
<div class="stat-value">{{ game_stats.scheduled|floatformat:0 }}</div>
<div class="stat-label">Scheduled</div>
</div>
<div class="stat-card warning">
<div class="stat-value">{{ game_stats.today }}</div>
<div class="stat-label">Today</div>
</div>
<div class="stat-card">
<div class="stat-value">{{ game_stats.this_week }}</div>
<div class="stat-label">This Week</div>
</div>
</div>
</div>
<!-- Sync Stats -->
<div class="card">
<div class="card-header">
<h3>CloudKit Sync Statistics</h3>
</div>
<div class="stat-grid">
<div class="stat-card">
<div class="stat-value">{{ sync_stats.total|floatformat:0 }}</div>
<div class="stat-label">Total Records</div>
</div>
<div class="stat-card success">
<div class="stat-value">{{ sync_stats.synced|floatformat:0 }}</div>
<div class="stat-label">Synced</div>
</div>
<div class="stat-card warning">
<div class="stat-value">{{ sync_stats.pending|floatformat:0 }}</div>
<div class="stat-label">Pending</div>
</div>
<div class="stat-card danger">
<div class="stat-value">{{ sync_stats.failed|floatformat:0 }}</div>
<div class="stat-label">Failed</div>
</div>
</div>
{% if sync_stats.total > 0 %}
<div class="mt-2">
<div style="display: flex; justify-content: space-between; margin-bottom: 0.5rem;">
<span>Sync Progress</span>
<span>{{ sync_stats.synced }} / {{ sync_stats.total }} ({% widthratio sync_stats.synced sync_stats.total 100 %}%)</span>
</div>
<div class="progress-bar">
<div class="fill" style="width: {% widthratio sync_stats.synced sync_stats.total 100 %}%; background: #28a745;"></div>
</div>
</div>
{% endif %}
</div>
<!-- Sport Breakdown -->
<div class="card">
<div class="card-header">
<h3>Statistics by Sport</h3>
</div>
<table class="table">
<thead>
<tr>
<th>Sport</th>
<th>Teams</th>
<th>Stadiums</th>
<th>Games</th>
<th>Pending Reviews</th>
</tr>
</thead>
<tbody>
{% for stat in sport_stats %}
<tr>
<td>
<strong>{{ stat.sport.short_name }}</strong>
<div class="text-muted" style="font-size: 0.8rem;">{{ stat.sport.name }}</div>
</td>
<td>{{ stat.teams }}</td>
<td>{{ stat.stadiums }}</td>
<td>{{ stat.games }}</td>
<td>
{% if stat.pending_reviews > 0 %}
<span class="badge badge-warning">{{ stat.pending_reviews }}</span>
{% else %}
<span class="badge badge-success">0</span>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endblock %}