feat(dashboard+api): card-based dashboard, camelCase API, UTC fixes
Dashboard: new Syncfusion card layout, global stats, filters, health bars, active event display, client details, bulk restart, 15s auto-refresh, manual refresh toasts API: standardized responses to camelCase; added serializers.py and updated events endpoints Time: ensured UTC storage; frontend appends 'Z' for parsing and displays local time Docs: updated copilot-instructions.md, README.md, TECH-CHANGELOG.md Program Info: bumped to 2025.1.0-alpha.12 with user-facing changelog BREAKING: external API consumers must migrate field names from PascalCase to camelCase.
This commit is contained in:
74
server/serializers.py
Normal file
74
server/serializers.py
Normal file
@@ -0,0 +1,74 @@
|
||||
"""
|
||||
Serialization helpers for converting between Python snake_case and JavaScript camelCase.
|
||||
"""
|
||||
import re
|
||||
from typing import Any, Dict, List, Union
|
||||
|
||||
|
||||
def to_camel_case(snake_str: str) -> str:
|
||||
"""
|
||||
Convert snake_case string to camelCase.
|
||||
|
||||
Examples:
|
||||
event_type -> eventType
|
||||
start_time -> startTime
|
||||
is_active -> isActive
|
||||
"""
|
||||
components = snake_str.split('_')
|
||||
# Keep the first component as-is, capitalize the rest
|
||||
return components[0] + ''.join(word.capitalize() for word in components[1:])
|
||||
|
||||
|
||||
def to_snake_case(camel_str: str) -> str:
|
||||
"""
|
||||
Convert camelCase string to snake_case.
|
||||
|
||||
Examples:
|
||||
eventType -> event_type
|
||||
startTime -> start_time
|
||||
isActive -> is_active
|
||||
"""
|
||||
# Insert underscore before uppercase letters and convert to lowercase
|
||||
snake = re.sub('([A-Z])', r'_\1', camel_str).lower()
|
||||
# Remove leading underscore if present
|
||||
return snake.lstrip('_')
|
||||
|
||||
|
||||
def dict_to_camel_case(data: Union[Dict, List, Any]) -> Union[Dict, List, Any]:
|
||||
"""
|
||||
Recursively convert dictionary keys from snake_case to camelCase.
|
||||
Also handles lists of dictionaries.
|
||||
|
||||
Args:
|
||||
data: Dictionary, list, or primitive value to convert
|
||||
|
||||
Returns:
|
||||
Converted data structure with camelCase keys
|
||||
"""
|
||||
if isinstance(data, dict):
|
||||
return {to_camel_case(key): dict_to_camel_case(value)
|
||||
for key, value in data.items()}
|
||||
elif isinstance(data, list):
|
||||
return [dict_to_camel_case(item) for item in data]
|
||||
else:
|
||||
return data
|
||||
|
||||
|
||||
def dict_to_snake_case(data: Union[Dict, List, Any]) -> Union[Dict, List, Any]:
|
||||
"""
|
||||
Recursively convert dictionary keys from camelCase to snake_case.
|
||||
Also handles lists of dictionaries.
|
||||
|
||||
Args:
|
||||
data: Dictionary, list, or primitive value to convert
|
||||
|
||||
Returns:
|
||||
Converted data structure with snake_case keys
|
||||
"""
|
||||
if isinstance(data, dict):
|
||||
return {to_snake_case(key): dict_to_snake_case(value)
|
||||
for key, value in data.items()}
|
||||
elif isinstance(data, list):
|
||||
return [dict_to_snake_case(item) for item in data]
|
||||
else:
|
||||
return data
|
||||
Reference in New Issue
Block a user