feat: Refactor template handling, improve scheduler functions, and add timezone utilities
- Moved Jinja2 template setup to a shared configuration file (templates_config.py) for consistent usage across routers. - Introduced timezone utilities in a new module (timezone.py) to handle UTC to local time conversions and formatting. - Updated all relevant routers to use the new shared template configuration and timezone filters. - Enhanced templates to utilize local time formatting for various datetime fields, improving user experience with timezone awareness.
This commit is contained in:
@@ -9,17 +9,19 @@ Provides API endpoints for the Projects system:
|
||||
"""
|
||||
|
||||
from fastapi import APIRouter, Request, Depends, HTTPException, Query
|
||||
from fastapi.templating import Jinja2Templates
|
||||
from fastapi.responses import HTMLResponse, JSONResponse, StreamingResponse
|
||||
from sqlalchemy.orm import Session
|
||||
from sqlalchemy import func, and_
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Optional
|
||||
from collections import OrderedDict
|
||||
import uuid
|
||||
import json
|
||||
import logging
|
||||
import io
|
||||
|
||||
from backend.utils.timezone import utc_to_local, format_local_datetime
|
||||
|
||||
from backend.database import get_db
|
||||
from backend.models import (
|
||||
Project,
|
||||
@@ -31,9 +33,9 @@ from backend.models import (
|
||||
RecurringSchedule,
|
||||
RosterUnit,
|
||||
)
|
||||
from backend.templates_config import templates
|
||||
|
||||
router = APIRouter(prefix="/api/projects", tags=["projects"])
|
||||
templates = Jinja2Templates(directory="templates")
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -461,16 +463,37 @@ async def get_project_schedules(
|
||||
if status:
|
||||
query = query.filter(ScheduledAction.execution_status == status)
|
||||
|
||||
schedules = query.order_by(ScheduledAction.scheduled_time.desc()).all()
|
||||
# For pending actions, show soonest first (ascending)
|
||||
# For completed/failed, show most recent first (descending)
|
||||
if status == "pending":
|
||||
schedules = query.order_by(ScheduledAction.scheduled_time.asc()).all()
|
||||
else:
|
||||
schedules = query.order_by(ScheduledAction.scheduled_time.desc()).all()
|
||||
|
||||
# Enrich with location details
|
||||
schedules_data = []
|
||||
# Enrich with location details and group by date
|
||||
schedules_by_date = OrderedDict()
|
||||
for schedule in schedules:
|
||||
location = None
|
||||
if schedule.location_id:
|
||||
location = db.query(MonitoringLocation).filter_by(id=schedule.location_id).first()
|
||||
|
||||
schedules_data.append({
|
||||
# Get local date for grouping
|
||||
if schedule.scheduled_time:
|
||||
local_dt = utc_to_local(schedule.scheduled_time)
|
||||
date_key = local_dt.strftime("%Y-%m-%d")
|
||||
date_display = local_dt.strftime("%A, %B %d, %Y") # "Wednesday, January 22, 2026"
|
||||
else:
|
||||
date_key = "unknown"
|
||||
date_display = "Unknown Date"
|
||||
|
||||
if date_key not in schedules_by_date:
|
||||
schedules_by_date[date_key] = {
|
||||
"date_display": date_display,
|
||||
"date_key": date_key,
|
||||
"actions": [],
|
||||
}
|
||||
|
||||
schedules_by_date[date_key]["actions"].append({
|
||||
"schedule": schedule,
|
||||
"location": location,
|
||||
})
|
||||
@@ -478,7 +501,7 @@ async def get_project_schedules(
|
||||
return templates.TemplateResponse("partials/projects/schedule_list.html", {
|
||||
"request": request,
|
||||
"project_id": project_id,
|
||||
"schedules": schedules_data,
|
||||
"schedules_by_date": schedules_by_date,
|
||||
})
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user