feat: add services page and API endpoints for service cost breakdown

- Implemented new API endpoints for fetching global services and service tenants details.
- Created a new services.html page with a sidebar for navigation and a chart for service costs.
- Updated frontend JavaScript to handle service data loading and rendering.
- Enhanced the dashboard with provider filtering options for AWS and Azure.
- Added a segmented toggle for selecting the date range for service costs.
- Improved styling for the sidebar and data tables.
- Refactored common utility functions for better reusability across pages.
This commit is contained in:
ludal committed 2026-09-20 21:55:52 +02:00
1 parent 9e78dfa4f2
commit c39364eda4
12 files changed
+834 -114

No files matched your search

+39 -2
View File
@@ -52,6 +52,11 @@ def tenant_page(provider: str, name: str):
return _read_page("tenant.html")
@app.get("/services", response_class=HTMLResponse)
def services_page():
return _read_page("services.html")
@app.get("/health")
def health():
try:
@@ -74,11 +79,43 @@ def api_overview(months: int = Query(12, ge=1, le=24)):
conn.close()
VALID_RANGES = (1, 7, 30, 365)
def _validate_provider_filter(provider: str | None) -> None:
if provider is not None and provider not in PROVIDERS:
raise HTTPException(status_code=404, detail=f"Provider inconnu : {provider}")
@app.get("/api/services")
def api_services(range: int = Query(30, alias="range"), provider: str | None = Query(None)):
if range not in VALID_RANGES:
raise HTTPException(status_code=400, detail="range doit être 1, 7, 30 ou 365")
_validate_provider_filter(provider)
conn = queries.get_connection()
try:
return queries.global_services(conn, range_days=range, provider=provider)
finally:
conn.close()
@app.get("/api/services/{service_name}/tenants")
def api_service_tenants(service_name: str, range: int = Query(30, alias="range"), provider: str | None = Query(None)):
if range not in VALID_RANGES:
raise HTTPException(status_code=400, detail="range doit être 1, 7, 30 ou 365")
_validate_provider_filter(provider)
conn = queries.get_connection()
try:
return queries.service_tenants_detail(conn, service_name, range_days=range, provider=provider)
finally:
conn.close()
@app.get("/api/tenant/{provider}/{name}")
def api_tenant_detail(provider: str, name: str, range: int = Query(30, alias="range")):
_require_provider(provider)
if range not in (7, 30, 365):
raise HTTPException(status_code=400, detail="range doit être 7, 30 ou 365")
if range not in VALID_RANGES:
raise HTTPException(status_code=400, detail="range doit être 1, 7, 30 ou 365")
conn = queries.get_connection()
try:
return queries.tenant_detail(conn, provider, name, range_days=range)