Fix dark-mode email readability, silent reply failures, and add an IMAP connection watchdog
Dark theme: inbound email HTML intentionally keeps its own inline colors for fidelity (sanitize-html.ts), but a sender's hardcoded dark text (the common case) was unreadable once the surrounding chrome went dark. Now forced to the theme's own text color in dark mode only; light mode keeps full fidelity as before. Send button: deliverAgentMessage awaited the outbound email/Telegram send *before* recording the reply, so a broken mail/bot account (e.g. bad SMTP creds) made the reply vanish entirely — not sent, not saved, no error shown — with the API's catch-all masking the real cause as a generic "Ticket not found". Channel delivery is now best-effort: the reply is always recorded even if outbound delivery fails, and real errors surface to the compose box instead of failing silently. IMAP watchdog: a live IDLE connection has gone quietly unresponsive in production more than once, with mail landing server-side but never noticed here and no error ever firing. Added a periodic forced NOOP round-trip with its own deadline, independent of ImapFlow's internal socket timeout, that tears down and reconnects a connection that stops answering. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Gh2UXUQUVBWroWEnn1FLFG
This commit is contained in:
1 parent
93e17c37c7
commit
8d1f91187a
7 files changed
+109
-31
No files matched your search
@@ -37,6 +37,7 @@ export function TicketThread({
|
||||
const [visibility, setVisibility] = useState<"public" | "internal">("public");
|
||||
const [pendingFile, setPendingFile] = useState<File | null>(null);
|
||||
const [sending, setSending] = useState(false);
|
||||
const [sendError, setSendError] = useState<string | null>(null);
|
||||
const [cannedResponses, setCannedResponses] = useState<{ id: string; title: string; body: string }[]>([]);
|
||||
const [cannedOpen, setCannedOpen] = useState(false);
|
||||
const bottomRef = useRef<HTMLDivElement>(null);
|
||||
@@ -82,6 +83,7 @@ export function TicketThread({
|
||||
async function sendReply() {
|
||||
if (!draft.trim() && !pendingFile) return;
|
||||
setSending(true);
|
||||
setSendError(null);
|
||||
|
||||
let res: Response;
|
||||
if (pendingFile) {
|
||||
@@ -103,6 +105,9 @@ export function TicketThread({
|
||||
setDraft("");
|
||||
setPendingFile(null);
|
||||
if (fileInputRef.current) fileInputRef.current.value = "";
|
||||
} else {
|
||||
const data = await res.json().catch(() => null);
|
||||
setSendError(data?.error ?? "Не удалось отправить сообщение");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -210,6 +215,7 @@ export function TicketThread({
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
{sendError && <p className="mb-1.5 text-xs text-danger-soft-text">{sendError}</p>}
|
||||
{pendingFile && (
|
||||
<div className="mb-1.5 flex items-center gap-2 rounded-md border border-border bg-surface-hover px-2.5 py-1.5 text-xs">
|
||||
<Paperclip size={12} />
|
||||
|
||||
Reference in new issue
Block a user