import React, { memo, useMemo, useState } from "react"; function prettyJson(text) { if (!text) return "—"; try { return JSON.stringify(JSON.parse(text), null, 2); } catch { return text; } } function ApiTraceTab({ hasSelectedTask, selectedTaskName, apiTraceLogs, formatTimestamp, clearApiTrace, exportApiTraceJson, exportApiTraceCsv }) { const [search, setSearch] = useState(""); const query = String(search || "").trim().toLowerCase(); const allRows = Array.isArray(apiTraceLogs) ? apiTraceLogs : []; const rows = useMemo(() => { if (!query) return allRows; return allRows.filter((item) => { const hay = [ item.method, item.phone, item.errorText, item.requestJson, item.responseJson ].map((part) => String(part || "").toLowerCase()).join(" "); return hay.includes(query); }); }, [allRows, query]); const okCount = rows.filter((item) => item.ok).length; const failCount = rows.length - okCount; const inviteRows = allRows.filter((item) => item.method === "channels.InviteToChannel"); const inviteTotal = inviteRows.length; const inviteMissing = inviteRows.filter((item) => { const response = String(item.responseJson || ""); return response.includes("missingInvitees") || response.includes("missing_invitees"); }).length; const inviteRpcError = inviteRows.filter((item) => !item.ok || String(item.errorText || "").trim()).length; const inviteOkNoMissing = Math.max(0, inviteTotal - inviteMissing - inviteRpcError); return (

API трассировка

Задача: {hasSelectedTask ? selectedTaskName : "—"}. Для Telegram MTProto HTTP‑headers отсутствуют, поэтому в лог пишется транспортный контекст.
setSearch(event.target.value)} placeholder="Поиск по методу / ошибке / JSON" /> Всего: {rows.length} OK: {okCount} Ошибок: {failCount}
InviteToChannel: {inviteTotal} missing_invitees: {inviteMissing} без missing: {inviteOkNoMissing} RPC errors: {inviteRpcError}
{!rows.length &&
Трассировка пуста.
} {rows.map((item) => (
{item.method || "unknown"} {formatTimestamp(item.createdAt)}
Аккаунт: {item.phone || item.accountId || "—"}
Задача: {item.taskId || "—"} · {item.ok ? "OK" : "Ошибка"} · {item.durationMs || 0} ms
{!item.ok &&
Ошибка: {item.errorText || "—"}
}
Запрос (JSON)
{prettyJson(item.requestJson)}
Заголовки / контекст
{prettyJson(item.headersJson)}
Ответ (JSON)
{prettyJson(item.responseJson)}
))}
); } export default memo(ApiTraceTab);