UI config

This commit is contained in:
2025-12-19 08:33:42 -05:00
parent 0149f45893
commit ac29b6e929
7 changed files with 134 additions and 8 deletions

View File

@@ -24,6 +24,11 @@ MAIL_FROM_NAME=your_mail_from_name_here
# Application settings
BASE_URL=your_base_url_here
# UI Configuration
TAG=
TOP_BAR_BASE_COLOR=#2c3e50
ENVIRONMENT=development
# Redis (optional)
REDIS_URL=

View File

@@ -11,10 +11,35 @@ from app.models.local_flight import LocalFlightStatus
from app.models.departure import DepartureStatus
from app.models.arrival import ArrivalStatus
from datetime import date, datetime, timedelta
import re
router = APIRouter()
def lighten_color(hex_color, factor=0.3):
"""Lighten a hex color by a factor (0-1)"""
hex_color = hex_color.lstrip('#')
if len(hex_color) != 6:
return hex_color # Invalid, return as is
r, g, b = int(hex_color[0:2], 16), int(hex_color[2:4], 16), int(hex_color[4:6], 16)
r = min(255, int(r + (255 - r) * factor))
g = min(255, int(g + (255 - g) * factor))
b = min(255, int(b + (255 - b) * factor))
return f"#{r:02x}{g:02x}{b:02x}"
def darken_color(hex_color, factor=0.3):
"""Darken a hex color by a factor (0-1)"""
hex_color = hex_color.lstrip('#')
if len(hex_color) != 6:
return hex_color # Invalid, return as is
r, g, b = int(hex_color[0:2], 16), int(hex_color[2:4], 16), int(hex_color[4:6], 16)
r = max(0, int(r * (1 - factor)))
g = max(0, int(g * (1 - factor)))
b = max(0, int(b * (1 - factor)))
return f"#{r:02x}{g:02x}{b:02x}"
@router.get("/arrivals")
async def get_public_arrivals(db: Session = Depends(get_db)):
"""Get today's arrivals for public display (PPR and local flights)"""
@@ -201,3 +226,17 @@ async def get_public_departures(db: Session = Depends(get_db)):
})
return departures_list
@router.get("/config")
async def get_ui_config():
"""Get UI configuration for client-side rendering"""
from app.core.config import settings
base_color = settings.top_bar_base_color
return {
"tag": settings.tag,
"top_bar_gradient_start": base_color,
"top_bar_gradient_end": lighten_color(base_color, 0.4), # Lighten for gradient end
"footer_color": darken_color(base_color, 0.2), # Darken for footer
"environment": settings.environment
}

View File

@@ -28,6 +28,11 @@ class Settings(BaseSettings):
project_name: str = "Airfield PPR API"
base_url: str
# UI Configuration
tag: str = ""
top_bar_base_color: str = "#2c3e50"
environment: str = "production" # production, development, staging, etc.
# Redis settings (for future use)
redis_url: Optional[str] = None

View File

@@ -26,6 +26,8 @@ services:
MAIL_FROM_NAME: ${MAIL_FROM_NAME}
BASE_URL: ${BASE_URL}
REDIS_URL: ${REDIS_URL}
TAG: ${TAG}
TOP_BAR_BASE_COLOR: ${TOP_BAR_BASE_COLOR}
ENVIRONMENT: production
WORKERS: "4"
ports:

View File

@@ -38,6 +38,9 @@ services:
MAIL_FROM_NAME: ${MAIL_FROM_NAME}
BASE_URL: ${BASE_URL}
REDIS_URL: ${REDIS_URL}
TOWER_NAME: ${TOWER_NAME}
TOP_BAR_BASE_COLOR: ${TOP_BAR_BASE_COLOR}
ENVIRONMENT: ${ENVIRONMENT}
ports:
- "${API_PORT_EXTERNAL}:8000" # Use different port to avoid conflicts with existing system
depends_on:

View File

@@ -10,7 +10,7 @@
<body>
<div class="top-bar">
<div class="title">
<h1>✈️ Swansea Tower</h1>
<h1 id="tower-title">✈️ Swansea Tower</h1>
</div>
<div class="menu-buttons">
<div class="dropdown">
@@ -1129,11 +1129,41 @@
let currentUserId = null;
let currentChangePasswordUserId = null;
// ==================== GENERIC MODAL HELPER ====================
function closeModal(modalId, additionalCleanup = null) {
document.getElementById(modalId).style.display = 'none';
if (additionalCleanup) {
additionalCleanup();
// Load UI configuration from API
async function loadUIConfig() {
try {
const response = await fetch('/api/v1/public/config');
if (response.ok) {
const config = await response.json();
// Update tower title
const titleElement = document.getElementById('tower-title');
if (titleElement && config.tag) {
titleElement.innerHTML = `✈️ Tower Ops ${config.tag}`;
}
// Update top bar gradient
const topBar = document.querySelector('.top-bar');
if (topBar && config.top_bar_gradient_start && config.top_bar_gradient_end) {
topBar.style.background = `linear-gradient(135deg, ${config.top_bar_gradient_start}, ${config.top_bar_gradient_end})`;
}
// Update footer color
const footerBar = document.querySelector('.footer-bar');
if (footerBar && config.footer_color) {
footerBar.style.background = config.footer_color;
}
// Optionally indicate environment (e.g., add to title if not production)
if (config.environment && config.environment !== 'production') {
const envIndicator = ` (${config.environment.toUpperCase()})`;
if (titleElement) {
titleElement.innerHTML += envIndicator;
}
}
}
} catch (error) {
console.warn('Failed to load UI config:', error);
}
}
@@ -4748,6 +4778,7 @@
// Initialize the page when DOM is loaded
document.addEventListener('DOMContentLoaded', function() {
loadUIConfig(); // Load UI configuration first
setupLoginForm();
setupKeyboardShortcuts();
initializeTimeDropdowns(); // Initialize time dropdowns

View File

@@ -367,7 +367,7 @@
</button>
</div>
<div class="title">
<h1>📊 PPR Reports</h1>
<h1 id="tower-title">📊 PPR Reports</h1>
</div>
<div class="user-info">
Logged in as: <span id="current-user">Loading...</span> |
@@ -591,8 +591,49 @@
let currentPPRs = []; // Store current results for export
let currentOtherFlights = []; // Store other flights for export
// Load UI configuration from API
async function loadUIConfig() {
try {
const response = await fetch('/api/v1/public/config');
if (response.ok) {
const config = await response.json();
// Update tower title
const titleElement = document.getElementById('tower-title');
if (titleElement && config.tag) {
titleElement.innerHTML = `📊 Reports ${config.tag}`;
}
// Update top bar gradient
const topBar = document.querySelector('.top-bar');
if (topBar && config.top_bar_gradient_start && config.top_bar_gradient_end) {
topBar.style.background = `linear-gradient(135deg, ${config.top_bar_gradient_start}, ${config.top_bar_gradient_end})`;
}
// Update page title
if (config.tag) {
document.title = `PPR Reports - ${config.tag}`;
}
// Optionally indicate environment (e.g., add to title if not production)
if (config.environment && config.environment !== 'production') {
const envIndicator = ` (${config.environment.toUpperCase()})`;
if (titleElement) {
titleElement.innerHTML += envIndicator;
}
if (document.title) {
document.title += envIndicator;
}
}
}
} catch (error) {
console.warn('Failed to load UI config:', error);
}
}
// Initialize the page
async function initializePage() {
loadUIConfig(); // Load UI configuration first
await initializeAuth();
setupDefaultDateRange();
await loadReports();