Shared components for L1 and L2 servers: - Jinja2 template system with base template and components - Middleware for auth and content negotiation - Pydantic models for requests/responses - Utility functions for pagination, media, formatting - Constants for Tailwind/HTMX/Cytoscape CDNs 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
166 lines
3.7 KiB
Python
166 lines
3.7 KiB
Python
"""
|
|
Formatting utilities for display.
|
|
"""
|
|
|
|
from datetime import datetime
|
|
from typing import Optional, Union
|
|
|
|
|
|
def format_date(
|
|
value: Optional[Union[str, datetime]],
|
|
length: int = 10,
|
|
include_time: bool = False,
|
|
) -> str:
|
|
"""
|
|
Format a date/datetime for display.
|
|
|
|
Args:
|
|
value: Date string or datetime object
|
|
length: Length to truncate to (default 10 for YYYY-MM-DD)
|
|
include_time: Whether to include time portion
|
|
|
|
Returns:
|
|
Formatted date string
|
|
"""
|
|
if value is None:
|
|
return ""
|
|
|
|
if isinstance(value, str):
|
|
# Parse ISO format string
|
|
try:
|
|
if "T" in value:
|
|
dt = datetime.fromisoformat(value.replace("Z", "+00:00"))
|
|
else:
|
|
return value[:length]
|
|
except ValueError:
|
|
return value[:length]
|
|
else:
|
|
dt = value
|
|
|
|
if include_time:
|
|
return dt.strftime("%Y-%m-%d %H:%M")
|
|
return dt.strftime("%Y-%m-%d")
|
|
|
|
|
|
def format_size(size_bytes: Optional[int]) -> str:
|
|
"""
|
|
Format file size in human-readable form.
|
|
|
|
Args:
|
|
size_bytes: Size in bytes
|
|
|
|
Returns:
|
|
Human-readable size string (e.g., "1.5 MB")
|
|
"""
|
|
if size_bytes is None:
|
|
return "Unknown"
|
|
if size_bytes < 0:
|
|
return "Unknown"
|
|
if size_bytes == 0:
|
|
return "0 B"
|
|
|
|
units = ["B", "KB", "MB", "GB", "TB"]
|
|
unit_index = 0
|
|
size = float(size_bytes)
|
|
|
|
while size >= 1024 and unit_index < len(units) - 1:
|
|
size /= 1024
|
|
unit_index += 1
|
|
|
|
if unit_index == 0:
|
|
return f"{int(size)} {units[unit_index]}"
|
|
return f"{size:.1f} {units[unit_index]}"
|
|
|
|
|
|
def truncate_hash(value: str, length: int = 16, suffix: str = "...") -> str:
|
|
"""
|
|
Truncate a hash or long string with ellipsis.
|
|
|
|
Args:
|
|
value: String to truncate
|
|
length: Maximum length before truncation
|
|
suffix: Suffix to add when truncated
|
|
|
|
Returns:
|
|
Truncated string
|
|
"""
|
|
if not value:
|
|
return ""
|
|
if len(value) <= length:
|
|
return value
|
|
return f"{value[:length]}{suffix}"
|
|
|
|
|
|
def format_duration(seconds: Optional[float]) -> str:
|
|
"""
|
|
Format duration in human-readable form.
|
|
|
|
Args:
|
|
seconds: Duration in seconds
|
|
|
|
Returns:
|
|
Human-readable duration string (e.g., "2m 30s")
|
|
"""
|
|
if seconds is None or seconds < 0:
|
|
return "Unknown"
|
|
|
|
if seconds < 1:
|
|
return f"{int(seconds * 1000)}ms"
|
|
|
|
if seconds < 60:
|
|
return f"{seconds:.1f}s"
|
|
|
|
minutes = int(seconds // 60)
|
|
remaining_seconds = int(seconds % 60)
|
|
|
|
if minutes < 60:
|
|
if remaining_seconds:
|
|
return f"{minutes}m {remaining_seconds}s"
|
|
return f"{minutes}m"
|
|
|
|
hours = minutes // 60
|
|
remaining_minutes = minutes % 60
|
|
|
|
if remaining_minutes:
|
|
return f"{hours}h {remaining_minutes}m"
|
|
return f"{hours}h"
|
|
|
|
|
|
def format_count(count: int) -> str:
|
|
"""
|
|
Format a count with abbreviation for large numbers.
|
|
|
|
Args:
|
|
count: Number to format
|
|
|
|
Returns:
|
|
Formatted string (e.g., "1.2K", "3.5M")
|
|
"""
|
|
if count < 1000:
|
|
return str(count)
|
|
if count < 1000000:
|
|
return f"{count / 1000:.1f}K"
|
|
if count < 1000000000:
|
|
return f"{count / 1000000:.1f}M"
|
|
return f"{count / 1000000000:.1f}B"
|
|
|
|
|
|
def format_percentage(value: float, decimals: int = 1) -> str:
|
|
"""
|
|
Format a percentage value.
|
|
|
|
Args:
|
|
value: Percentage value (0-100 or 0-1)
|
|
decimals: Number of decimal places
|
|
|
|
Returns:
|
|
Formatted percentage string
|
|
"""
|
|
# Assume 0-1 if less than 1
|
|
if value <= 1:
|
|
value *= 100
|
|
|
|
if decimals == 0:
|
|
return f"{int(value)}%"
|
|
return f"{value:.{decimals}f}%"
|