"""Chat-list helpers with no Qt, shared by the Chats dialog and the terminal's /chats: turning what GET /desk/chats returns into readable rows.""" from __future__ import annotations import re from datetime import datetime, timezone from typing import Optional # Context notes clients append to what you typed. They're in the stored last # message, but they aren't what you said, so they stay out of the preview. # The preview may be cut off mid-note, so an unclosed one runs to the end. _CONTEXT_NOTES = re.compile(r"\s*\[(?:Bolt Console:|on screen right now:)[^\]]*(?:\]|$)", re.IGNORECASE) def clean_preview(text: str, limit: int = 110) -> str: text = " ".join(_CONTEXT_NOTES.sub("", str(text or "")).split()) return text if len(text) <= limit else text[: limit - 1].rstrip() + "…" def relative_time(iso: str, now: Optional[datetime] = None) -> str: """'just now', '12 min ago', '3 h ago', 'yesterday', '4 days ago', or a date. Unparseable input comes back as it was.""" try: then = datetime.fromisoformat(str(iso).replace("Z", "+00:00")) except (TypeError, ValueError): return str(iso or "") if then.tzinfo is None: then = then.replace(tzinfo=timezone.utc) now = now or datetime.now(timezone.utc) seconds = (now - then).total_seconds() if seconds < 60: return "just now" if seconds < 3600: return f"{int(seconds // 60)} min ago" if seconds < 86400: return f"{int(seconds // 3600)} h ago" days = int(seconds // 86400) if days == 1: return "yesterday" if days < 7: return f"{days} days ago" return then.astimezone().strftime("%d %b %Y").lstrip("0") def local_time(iso: str) -> str: try: then = datetime.fromisoformat(str(iso).replace("Z", "+00:00")) if then.tzinfo is None: then = then.replace(tzinfo=timezone.utc) return then.astimezone().strftime("%A %d %B %Y, %H:%M") except (TypeError, ValueError): return str(iso or "")