feat(frontend): T44 setup FastAPI static files and templates
- Mount static files on /static endpoint - Configure Jinja2Templates with directory structure - Create base template with Pico.css, HTMX, Chart.js - Create all template subdirectories (auth, dashboard, keys, tokens, profile, components) - Create initial CSS and JS files - Add tests for static files and templates configuration Tests: 12 passing Coverage: 100% on new configuration code
This commit is contained in:
133
templates/dashboard/index.html
Normal file
133
templates/dashboard/index.html
Normal file
@@ -0,0 +1,133 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Dashboard - OpenRouter Monitor{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Dashboard</h1>
|
||||
|
||||
<!-- Summary Cards -->
|
||||
<div class="grid">
|
||||
<article>
|
||||
<header>
|
||||
<h3>Total Requests</h3>
|
||||
</header>
|
||||
<p style="font-size: 2rem; font-weight: bold;">{{ stats.total_requests | default(0) }}</p>
|
||||
</article>
|
||||
|
||||
<article>
|
||||
<header>
|
||||
<h3>Total Cost</h3>
|
||||
</header>
|
||||
<p style="font-size: 2rem; font-weight: bold;">${{ stats.total_cost | default(0) | round(2) }}</p>
|
||||
</article>
|
||||
|
||||
<article>
|
||||
<header>
|
||||
<h3>API Keys</h3>
|
||||
</header>
|
||||
<p style="font-size: 2rem; font-weight: bold;">{{ stats.api_keys_count | default(0) }}</p>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
<!-- Charts -->
|
||||
<div class="grid">
|
||||
<article>
|
||||
<header>
|
||||
<h3>Usage Over Time</h3>
|
||||
</header>
|
||||
<canvas id="usageChart" height="200"></canvas>
|
||||
</article>
|
||||
|
||||
<article>
|
||||
<header>
|
||||
<h3>Top Models</h3>
|
||||
</header>
|
||||
<canvas id="modelsChart" height="200"></canvas>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
<!-- Recent Activity -->
|
||||
<article>
|
||||
<header>
|
||||
<h3>Recent Usage</h3>
|
||||
</header>
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Date</th>
|
||||
<th>Model</th>
|
||||
<th>Requests</th>
|
||||
<th>Cost</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for usage in recent_usage %}
|
||||
<tr>
|
||||
<td>{{ usage.date }}</td>
|
||||
<td>{{ usage.model }}</td>
|
||||
<td>{{ usage.requests }}</td>
|
||||
<td>${{ usage.cost | round(4) }}</td>
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="4" style="text-align: center;">No usage data available</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</article>
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_scripts %}
|
||||
<script>
|
||||
// Usage Chart
|
||||
const usageCtx = document.getElementById('usageChart').getContext('2d');
|
||||
const usageData = {{ chart_data | default({"labels": [], "data": []}) | tojson }};
|
||||
|
||||
new Chart(usageCtx, {
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: usageData.labels || [],
|
||||
datasets: [{
|
||||
label: 'Requests',
|
||||
data: usageData.data || [],
|
||||
borderColor: '#2563eb',
|
||||
backgroundColor: 'rgba(37, 99, 235, 0.1)',
|
||||
fill: true
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
scales: {
|
||||
y: {
|
||||
beginAtZero: true
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Models Chart
|
||||
const modelsCtx = document.getElementById('modelsChart').getContext('2d');
|
||||
const modelsData = {{ models_data | default({"labels": [], "data": []}) | tojson }};
|
||||
|
||||
new Chart(modelsCtx, {
|
||||
type: 'doughnut',
|
||||
data: {
|
||||
labels: modelsData.labels || [],
|
||||
datasets: [{
|
||||
data: modelsData.data || [],
|
||||
backgroundColor: [
|
||||
'#2563eb',
|
||||
'#10b981',
|
||||
'#f59e0b',
|
||||
'#ef4444',
|
||||
'#8b5cf6'
|
||||
]
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true
|
||||
}
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user