feat: donation banner, About tab, settings UI improvements
Some checks failed
Lint & Test / test (push) Has been cancelled

- Dismissible donation/open-source banner after 3+ sessions (30-day snooze)
- New About tab in Settings: version, repo link, license info
- Centralize project URLs (REPO_URL, DONATE_URL) in __init__.py, served via /health
- Center settings tab bar, reduce tab padding for 6-tab fit
- External URL save button: icon button instead of full-width text button
- Remove redundant settings footer close button
- Footer "Source Code" link replaced with "About" opening settings
- i18n keys for en/ru/zh
This commit is contained in:
2026-03-27 21:09:34 +03:00
parent f61a0206d4
commit f3d07fc47f
18 changed files with 442 additions and 49 deletions

View File

@@ -13,7 +13,11 @@ class HealthResponse(BaseModel):
timestamp: datetime = Field(description="Current server time")
version: str = Field(description="Application version")
demo_mode: bool = Field(default=False, description="Whether demo mode is active")
auth_required: bool = Field(default=True, description="Whether API key authentication is required")
auth_required: bool = Field(
default=True, description="Whether API key authentication is required"
)
repo_url: str = Field(default="", description="Source code repository URL")
donate_url: str = Field(default="", description="Donation page URL")
class VersionResponse(BaseModel):
@@ -84,6 +88,7 @@ class RestoreResponse(BaseModel):
# ─── Auto-backup schemas ──────────────────────────────────────
class AutoBackupSettings(BaseModel):
"""Settings for automatic backup."""
@@ -119,6 +124,7 @@ class BackupListResponse(BaseModel):
# ─── MQTT schemas ──────────────────────────────────────────────
class MQTTSettingsResponse(BaseModel):
"""MQTT broker settings response (password is masked)."""
@@ -138,17 +144,22 @@ class MQTTSettingsRequest(BaseModel):
broker_host: str = Field(description="MQTT broker hostname or IP")
broker_port: int = Field(ge=1, le=65535, description="MQTT broker port")
username: str = Field(default="", description="MQTT username (empty = anonymous)")
password: str = Field(default="", description="MQTT password (empty = keep existing if omitted)")
password: str = Field(
default="", description="MQTT password (empty = keep existing if omitted)"
)
client_id: str = Field(default="ledgrab", description="MQTT client ID")
base_topic: str = Field(default="ledgrab", description="Base topic prefix")
# ─── External URL schema ───────────────────────────────────────
class ExternalUrlResponse(BaseModel):
"""External URL setting response."""
external_url: str = Field(description="External base URL (e.g. https://myserver.example.com:8080). Empty = use auto-detected URL.")
external_url: str = Field(
description="External base URL (e.g. https://myserver.example.com:8080). Empty = use auto-detected URL."
)
class ExternalUrlRequest(BaseModel):
@@ -159,10 +170,13 @@ class ExternalUrlRequest(BaseModel):
# ─── Log level schemas ─────────────────────────────────────────
class LogLevelResponse(BaseModel):
"""Current log level response."""
level: str = Field(description="Current effective log level name (e.g. DEBUG, INFO, WARNING, ERROR, CRITICAL)")
level: str = Field(
description="Current effective log level name (e.g. DEBUG, INFO, WARNING, ERROR, CRITICAL)"
)
class LogLevelRequest(BaseModel):