fix(maintenance): auto-expiry + adaptive markdown height + tests

- Auto-expiry: expired events auto-end on GET /events via task manager
- Height: _estimate_markdown_height adapted to unit=8px scale with padding detection
- CRITICAL-1: removed dead import remove_chart_from_position (QA finding)
- CRITICAL-2: added chart alive check in ensure_banner_chart (QA finding)
- CRITICAL-3: fixed test assertions update_markdown_chart → update_banner_on_dashboard
- @POST contract: fixed return range [2,12] → [19,200]
- Tests: 8 new tests (auto-expiry + layout height)
This commit is contained in:
2026-05-25 08:36:33 +03:00
parent 2bf686674e
commit 31680a1bc9
100 changed files with 19635 additions and 7923 deletions

View File

@@ -393,6 +393,7 @@ class ConsolidatedSettingsResponse(BaseModel):
storage: dict
notifications: dict = {}
features: dict = {}
app_timezone: str = "Europe/Moscow"
# #endregion ConsolidatedSettingsResponse
@@ -463,6 +464,7 @@ async def get_consolidated_settings(
storage=config.settings.storage.dict(),
notifications=notifications_payload,
features=config.settings.features.model_dump(),
app_timezone=config.settings.app_timezone,
)
logger.reflect(
"Consolidated settings payload assembled",
@@ -526,6 +528,15 @@ async def update_consolidated_settings(
payload["notifications"] = settings_patch["notifications"]
config_manager.save_config(payload)
# Update app_timezone if provided
if "app_timezone" in settings_patch:
new_tz = settings_patch["app_timezone"]
from ...core.timezone import validate_timezone, invalidate_timezone_cache
if not validate_timezone(new_tz):
raise HTTPException(status_code=422, detail=f"Invalid IANA timezone: {new_tz}")
current_settings.app_timezone = new_tz
invalidate_timezone_cache()
config_manager.update_global_settings(current_settings)
return {"status": "success", "message": "Settings updated"}