From a451a129fe0b211369f336f09f8c8e1abd105173 Mon Sep 17 00:00:00 2001 From: c0mrade Date: Wed, 19 Aug 2026 18:11:58 +0300 Subject: [PATCH] =?UTF-8?q?fix(geocheck):=20=D1=83=D0=B1=D1=80=D0=B0=D1=82?= =?UTF-8?q?=D1=8C=20=D1=81=D0=BA=D0=B0=D1=87=D0=B8=D0=B2=D0=B0=D0=BD=D0=B8?= =?UTF-8?q?=D0=B5=20=D0=BE=D1=82=D1=87=D1=91=D1=82=D0=B0=20=D0=B2=20Telegr?= =?UTF-8?q?am=20Mini=20App?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit В webview Telegram атрибут `download` игнорируется: вместо сохранения файла webview уходит на blob-ссылку и подменяет собой Mini App, вернуться можно только кнопкой «Назад». То есть кнопка не просто не работала, а выкидывала администратора из приложения. Штатный путь тут не подходит. `downloadFile` из Bot API 8.0 требует HTTPS-URL файла с заголовками `Content-Disposition: attachment` и CORS для web.telegram.org, а отчёт приходит base64 внутри JSON-ответа бота — ссылки на него не существует. Отдать её можно только новым эндпоинтом бота, причём подписанным: `downloadFile` скачивает URL сам, без заголовка Authorization. Это отдельная работа, а не правка кнопки. Пока кнопка скрыта в Mini App тем же признаком платформы, что и полный экран. Данные из отчёта там по-прежнему достаются копированием JSON, а на десктопе скачивание работает как раньше. Проверено рендером обеих платформ: в Telegram тулбар — отчёт, JSON, копирование, перезапуск, зум; в вебе к ним добавляются полный экран и скачивание. Co-Authored-By: Claude Opus 5 (1M context) --- .../admin/remnawave/GeoCheckModal.tsx | 7 ++++- .../admin/remnawave/GeoCheckReport.tsx | 31 +++++++++++++------ 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/src/components/admin/remnawave/GeoCheckModal.tsx b/src/components/admin/remnawave/GeoCheckModal.tsx index 33d6fe3..0bd6a32 100644 --- a/src/components/admin/remnawave/GeoCheckModal.tsx +++ b/src/components/admin/remnawave/GeoCheckModal.tsx @@ -32,7 +32,11 @@ export function GeoCheckModal({ node, onClose }: GeoCheckModalProps) { // В Mini App окно Telegram и так занимает экран целиком: отдельный // полноэкранный режим там только снимал отступы и залезал под хром. - const canFullscreen = !useIsTelegram(); + // Тот же признак закрывает и скачивание: в webview Telegram оно уводит + // из приложения вместо сохранения файла. + const isTelegram = useIsTelegram(); + const canFullscreen = !isTelegram; + const canDownload = !isTelegram; const fullscreen = canFullscreen && fullscreenRequested; const job = useGeoCheckJob(node.uuid); @@ -218,6 +222,7 @@ export function GeoCheckModal({ node, onClose }: GeoCheckModalProps) { nodeName={node.name} fullscreen={fullscreen} canFullscreen={canFullscreen} + canDownload={canDownload} onToggleFullscreen={() => setFullscreenRequested((v) => !v)} onRerun={job.retry} /> diff --git a/src/components/admin/remnawave/GeoCheckReport.tsx b/src/components/admin/remnawave/GeoCheckReport.tsx index c1894af..f3a8f03 100644 --- a/src/components/admin/remnawave/GeoCheckReport.tsx +++ b/src/components/admin/remnawave/GeoCheckReport.tsx @@ -30,6 +30,14 @@ interface GeoCheckReportProps { * во весь экран — режим лишь снимал отступы и лез под хром Telegram. */ canFullscreen: boolean; + /** + * Показывать ли скачивание. В webview Telegram атрибут `download` + * игнорируется: вместо сохранения файла webview уходит на blob и подменяет + * собой Mini App, вернуться можно только кнопкой «Назад». Штатный + * `downloadFile` из Bot API 8.0 тут не помогает — он требует HTTPS-ссылку + * на файл, а отчёт приходит base64 внутри JSON. + */ + canDownload: boolean; onToggleFullscreen: () => void; onRerun: () => void; } @@ -48,6 +56,7 @@ export function GeoCheckReport({ nodeName, fullscreen, canFullscreen, + canDownload, onToggleFullscreen, onRerun, }: GeoCheckReportProps) { @@ -170,16 +179,18 @@ export function GeoCheckReport({ )} - + {canDownload && ( + + )}