feat: test menu dropdown, split text/media messages, target settings, provider URL links

- Replace 3 test buttons with unified dropdown menu (basic/periodic/scheduled/memory)
- Send text message first, then assets as reply (not combined caption+media)
- Pass all target config settings to Telegram client (disable_url_preview, max_media, chunk_delay, etc.)
- Real data test notifications for periodic/scheduled/memory (fetch from Immich)
- Provider card URL is now a clickable hyperlink
- Localized test type labels (EN/RU)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-20 16:34:25 +03:00
parent 03c5c66eed
commit 5015e378fe
9 changed files with 407 additions and 78 deletions
@@ -1,5 +1,7 @@
"""Status/dashboard API route."""
from datetime import datetime, timedelta, timezone
from fastapi import APIRouter, Depends, Query
from sqlmodel import func, select
from sqlmodel.ext.asyncio.session import AsyncSession
@@ -89,3 +91,46 @@ async def get_status(
for e in recent_events.all()
],
}
@router.get("/chart")
async def get_event_chart(
user: User = Depends(get_current_user),
session: AsyncSession = Depends(get_session),
days: int = Query(14, ge=1, le=90),
):
"""Return daily event counts by type for the last N days."""
cutoff = datetime.now(timezone.utc) - timedelta(days=days)
day_col = func.date(EventLog.created_at)
query = (
select(
day_col.label("day"),
EventLog.event_type,
func.count().label("count"),
)
.join(Tracker, EventLog.tracker_id == Tracker.id)
.where(Tracker.user_id == user.id, EventLog.created_at >= cutoff)
.group_by(day_col, EventLog.event_type)
.order_by(day_col)
)
rows = (await session.exec(query)).all()
# Build a dict: { "2026-03-15": { "assets_added": 3, ... }, ... }
by_day: dict[str, dict[str, int]] = {}
for row in rows:
day_str = str(row.day)
if day_str not in by_day:
by_day[day_str] = {}
by_day[day_str][row.event_type] = row.count
# Fill in missing days so the frontend gets a continuous series
result = []
for i in range(days):
d = (datetime.now(timezone.utc) - timedelta(days=days - 1 - i)).strftime("%Y-%m-%d")
counts = by_day.get(d, {})
result.append({"date": d, **counts})
return {"days": result}