From a37ce3d6b5d0b129357b23818447475854ae0628 Mon Sep 17 00:00:00 2001 From: CaIon Date: Thu, 18 Jun 2026 11:59:17 +0800 Subject: [PATCH] fix: clarify channel test results --- .../components/data-table-row-actions.tsx | 10 ++- .../dialogs/channel-test-dialog.tsx | 1 + .../features/channels/lib/channel-actions.ts | 68 ++++++++++++++++--- web/default/src/i18n/locales/en.json | 6 ++ web/default/src/i18n/locales/fr.json | 6 ++ web/default/src/i18n/locales/ja.json | 6 ++ web/default/src/i18n/locales/ru.json | 6 ++ web/default/src/i18n/locales/vi.json | 6 ++ web/default/src/i18n/locales/zh.json | 6 ++ 9 files changed, 103 insertions(+), 12 deletions(-) diff --git a/web/default/src/features/channels/components/data-table-row-actions.tsx b/web/default/src/features/channels/components/data-table-row-actions.tsx index 0d93bf11..5ba56b31 100644 --- a/web/default/src/features/channels/components/data-table-row-actions.tsx +++ b/web/default/src/features/channels/components/data-table-row-actions.tsx @@ -94,9 +94,13 @@ export function DataTableRowActions({ row }: DataTableRowActionsProps) { e.stopPropagation() setIsTesting(true) try { - await handleTestChannel(channel.id, undefined, () => { - queryClient.invalidateQueries({ queryKey: channelsQueryKeys.lists() }) - }) + await handleTestChannel( + channel.id, + { channelName: channel.name }, + () => { + queryClient.invalidateQueries({ queryKey: channelsQueryKeys.lists() }) + } + ) } finally { setIsTesting(false) } diff --git a/web/default/src/features/channels/components/dialogs/channel-test-dialog.tsx b/web/default/src/features/channels/components/dialogs/channel-test-dialog.tsx index 164b4847..9a3a6ab3 100644 --- a/web/default/src/features/channels/components/dialogs/channel-test-dialog.tsx +++ b/web/default/src/features/channels/components/dialogs/channel-test-dialog.tsx @@ -507,6 +507,7 @@ function ChannelTestDialogContent({ await handleTestChannel( currentRow.id, { + channelName: currentRow.name, testModel: model, endpointType: endpointType === 'auto' ? undefined : endpointType, stream: effectiveStreamTest || undefined, diff --git a/web/default/src/features/channels/lib/channel-actions.ts b/web/default/src/features/channels/lib/channel-actions.ts index bd8dfd71..f32bf520 100644 --- a/web/default/src/features/channels/lib/channel-actions.ts +++ b/web/default/src/features/channels/lib/channel-actions.ts @@ -71,6 +71,41 @@ function getChannelTestResponseTime( return undefined } +function formatChannelTestDuration(responseTime?: number): string | undefined { + if (responseTime === undefined) return undefined + + if (responseTime >= 1000) { + return `${(responseTime / 1000).toFixed(2)} s` + } + + return `${Math.max(1, Math.round(responseTime))} ms` +} + +function getChannelTestLabel(options?: { + channelName?: string + testModel?: string +}): string { + const channelName = options?.channelName?.trim() + const testModel = options?.testModel?.trim() + + if (channelName && testModel) { + return i18next.t('Channel {{name}} model {{model}}', { + name: channelName, + model: testModel, + }) + } + + if (channelName) { + return i18next.t('Channel {{name}}', { name: channelName }) + } + + if (testModel) { + return i18next.t('Model {{model}}', { model: testModel }) + } + + return i18next.t('Channel') +} + // ============================================================================ // Single Channel Actions // ============================================================================ @@ -231,6 +266,7 @@ export async function handleUpdateTagField( export async function handleTestChannel( id: number, options?: { + channelName?: string testModel?: string endpointType?: string stream?: boolean @@ -257,28 +293,42 @@ export async function handleTestChannel( try { const response = await testChannel(id, payload) const responseTime = getChannelTestResponseTime(response) + const duration = formatChannelTestDuration(responseTime) + const target = getChannelTestLabel(options) if (response.success) { if (!options?.silent) { - toast.success(i18next.t(SUCCESS_MESSAGES.TESTED)) + toast.success( + i18next.t('{{target}} test succeeded', { target }), + duration + ? { + description: i18next.t('Response time: {{duration}}', { + duration, + }), + } + : undefined + ) } onTestComplete?.(true, responseTime) } else { + const errorMsg = response.message || i18next.t(ERROR_MESSAGES.TEST_FAILED) if (!options?.silent) { - toast.error(response.message || i18next.t(ERROR_MESSAGES.TEST_FAILED)) + toast.error(i18next.t('{{target}} test failed', { target }), { + description: response.error_code + ? `${errorMsg} (${response.error_code})` + : errorMsg, + }) } - onTestComplete?.( - false, - responseTime, - response.message, - response.error_code - ) + onTestComplete?.(false, responseTime, errorMsg, response.error_code) } } catch (_error: unknown) { const err = _error as { response?: { data?: { message?: string } } } const errorMsg = err?.response?.data?.message || i18next.t(ERROR_MESSAGES.TEST_FAILED) + const target = getChannelTestLabel(options) if (!options?.silent) { - toast.error(errorMsg) + toast.error(i18next.t('{{target}} test failed', { target }), { + description: errorMsg, + }) } onTestComplete?.(false, undefined, errorMsg) } diff --git a/web/default/src/i18n/locales/en.json b/web/default/src/i18n/locales/en.json index 9a544200..c833aca9 100644 --- a/web/default/src/i18n/locales/en.json +++ b/web/default/src/i18n/locales/en.json @@ -53,6 +53,8 @@ "{{modality}} supported": "{{modality}} supported", "{{n}} model(s) selected": "{{n}} model(s) selected", "{{success}} succeeded, {{failed}} failed": "{{success}} succeeded, {{failed}} failed", + "{{target}} test failed": "{{target}} test failed", + "{{target}} test succeeded": "{{target}} test succeeded", "{{value}}ms": "{{value}}ms", "{{value}}s": "{{value}}s", "@lobehub/icons key": "@lobehub/icons key", @@ -669,6 +671,8 @@ "Channel key": "Channel key", "Channel key unlocked": "Channel key unlocked", "Channel models": "Channel models", + "Channel {{name}}": "Channel {{name}}", + "Channel {{name}} model {{model}}": "Channel {{name}} model {{model}}", "Channel name is required": "Channel name is required", "Channel test completed": "Channel test completed", "Channel type is required": "Channel type is required", @@ -2419,6 +2423,7 @@ "Model mapping must be a JSON object with string values": "Model mapping must be a JSON object with string values", "Model mapping must be valid JSON": "Model mapping must be valid JSON", "Model mapping values must be strings": "Model mapping values must be strings", + "Model {{model}}": "Model {{model}}", "Model name": "Model name", "Model Name": "Model Name", "Model Name *": "Model Name *", @@ -3440,6 +3445,7 @@ "Resolve Conflicts": "Resolve Conflicts", "Resource Configuration": "Resource Configuration", "Response": "Response", + "Response time: {{duration}}": "Response time: {{duration}}", "Response Time": "Response Time", "Responses API Version": "Responses API Version", "Restore defaults": "Restore defaults", diff --git a/web/default/src/i18n/locales/fr.json b/web/default/src/i18n/locales/fr.json index 2419094f..01e5cea2 100644 --- a/web/default/src/i18n/locales/fr.json +++ b/web/default/src/i18n/locales/fr.json @@ -53,6 +53,8 @@ "{{modality}} supported": "{{modality}} pris en charge", "{{n}} model(s) selected": "{{n}} modèle(s) sélectionné(s)", "{{success}} succeeded, {{failed}} failed": "{{success}} réussi(s), {{failed}} échoué(s)", + "{{target}} test failed": "Échec du test de {{target}}", + "{{target}} test succeeded": "Test de {{target}} réussi", "{{value}}ms": "{{value}} ms", "{{value}}s": "{{value}} s", "@lobehub/icons key": "@lobehub/icons clé", @@ -669,6 +671,8 @@ "Channel key": "Clé du canal", "Channel key unlocked": "Clé de canal déverrouillée", "Channel models": "Modèles de canaux", + "Channel {{name}}": "Canal {{name}}", + "Channel {{name}} model {{model}}": "Canal {{name}} modèle {{model}}", "Channel name is required": "Le nom du canal est requis", "Channel test completed": "Test du canal terminé", "Channel type is required": "Le type de canal est requis", @@ -2419,6 +2423,7 @@ "Model mapping must be a JSON object with string values": "Le mappage de modèles doit être un objet JSON avec des valeurs de chaîne", "Model mapping must be valid JSON": "La cartographie des modèles doit être un JSON valide", "Model mapping values must be strings": "Les valeurs du mappage de modèles doivent être des chaînes", + "Model {{model}}": "Modèle {{model}}", "Model name": "Nom du modèle", "Model Name": "Nom du modèle", "Model Name *": "Nom du modèle *", @@ -3440,6 +3445,7 @@ "Resolve Conflicts": "Résoudre les conflits", "Resource Configuration": "Configuration des ressources", "Response": "Réponse", + "Response time: {{duration}}": "Temps de réponse : {{duration}}", "Response Time": "Temps de réponse", "Responses API Version": "Version de l'API des réponses", "Restore defaults": "Restaurer les paramètres par défaut", diff --git a/web/default/src/i18n/locales/ja.json b/web/default/src/i18n/locales/ja.json index 99088722..271b758b 100644 --- a/web/default/src/i18n/locales/ja.json +++ b/web/default/src/i18n/locales/ja.json @@ -53,6 +53,8 @@ "{{modality}} supported": "{{modality}} をサポート", "{{n}} model(s) selected": "{{n}} 件のモデルを選択済み", "{{success}} succeeded, {{failed}} failed": "{{success}} 件成功、{{failed}} 件失敗", + "{{target}} test failed": "{{target}} のテストに失敗しました", + "{{target}} test succeeded": "{{target}} のテストに成功しました", "{{value}}ms": "{{value}}ミリ秒", "{{value}}s": "{{value}}秒", "@lobehub/icons key": "@lobehub/icons キー", @@ -669,6 +671,8 @@ "Channel key": "チャネルキー", "Channel key unlocked": "チャネルキーが解除されました", "Channel models": "チャネルモデル", + "Channel {{name}}": "チャネル {{name}}", + "Channel {{name}} model {{model}}": "チャネル {{name}} モデル {{model}}", "Channel name is required": "チャネル名が必要です", "Channel test completed": "チャネルテストが完了しました", "Channel type is required": "チャネルタイプが必要です", @@ -2419,6 +2423,7 @@ "Model mapping must be a JSON object with string values": "モデルマッピングは文字列値を持つ JSON オブジェクトである必要があります", "Model mapping must be valid JSON": "モデルマッピングは有効な JSON である必要があります", "Model mapping values must be strings": "モデルマッピングの値は文字列である必要があります", + "Model {{model}}": "モデル {{model}}", "Model name": "モデル名", "Model Name": "モデル名", "Model Name *": "モデル名 *", @@ -3440,6 +3445,7 @@ "Resolve Conflicts": "競合を解決", "Resource Configuration": "リソース設定", "Response": "レスポンス", + "Response time: {{duration}}": "応答時間: {{duration}}", "Response Time": "応答時間", "Responses API Version": "応答APIバージョン", "Restore defaults": "既定に戻す", diff --git a/web/default/src/i18n/locales/ru.json b/web/default/src/i18n/locales/ru.json index 851ad4d4..cc814260 100644 --- a/web/default/src/i18n/locales/ru.json +++ b/web/default/src/i18n/locales/ru.json @@ -53,6 +53,8 @@ "{{modality}} supported": "{{modality}} поддерживается", "{{n}} model(s) selected": "Выбрано моделей: {{n}}", "{{success}} succeeded, {{failed}} failed": "{{success}} успешно, {{failed}} с ошибкой", + "{{target}} test failed": "Тест {{target}} не выполнен", + "{{target}} test succeeded": "Тест {{target}} успешно выполнен", "{{value}}ms": "{{value}} мс", "{{value}}s": "{{value}} с", "@lobehub/icons key": "Ключ @lobehub/icons", @@ -669,6 +671,8 @@ "Channel key": "Ключ канала", "Channel key unlocked": "Ключ канала разблокирован", "Channel models": "Модели каналов", + "Channel {{name}}": "Канал {{name}}", + "Channel {{name}} model {{model}}": "Канал {{name}}, модель {{model}}", "Channel name is required": "Имя канала обязательно", "Channel test completed": "Тест канала завершён", "Channel type is required": "Тип канала обязателен", @@ -2419,6 +2423,7 @@ "Model mapping must be a JSON object with string values": "Сопоставление моделей должно быть JSON-объектом со строковыми значениями", "Model mapping must be valid JSON": "Сопоставление моделей должно быть допустимым JSON", "Model mapping values must be strings": "Значения сопоставления моделей должны быть строками", + "Model {{model}}": "Модель {{model}}", "Model name": "Имя модели", "Model Name": "Название модели", "Model Name *": "Имя модели *", @@ -3440,6 +3445,7 @@ "Resolve Conflicts": "Разрешить конфликты", "Resource Configuration": "Конфигурация ресурсов", "Response": "Ответ", + "Response time: {{duration}}": "Время ответа: {{duration}}", "Response Time": "Время ответа", "Responses API Version": "Версия API ответов", "Restore defaults": "Сбросить к значениям по умолчанию", diff --git a/web/default/src/i18n/locales/vi.json b/web/default/src/i18n/locales/vi.json index 517b3bfc..d61691ee 100644 --- a/web/default/src/i18n/locales/vi.json +++ b/web/default/src/i18n/locales/vi.json @@ -53,6 +53,8 @@ "{{modality}} supported": "Hỗ trợ {{modality}}", "{{n}} model(s) selected": "Đã chọn {{n}} model", "{{success}} succeeded, {{failed}} failed": "{{success}} thành công, {{failed}} thất bại", + "{{target}} test failed": "Kiểm tra {{target}} thất bại", + "{{target}} test succeeded": "Kiểm tra {{target}} thành công", "{{value}}ms": "{{value}} ms", "{{value}}s": "{{value}} s", "@lobehub/icons key": "@lobehub/icons khóa", @@ -669,6 +671,8 @@ "Channel key": "Khóa kênh", "Channel key unlocked": "Khóa kênh đã được mở khóa", "Channel models": "Mô hình kênh", + "Channel {{name}}": "Kênh {{name}}", + "Channel {{name}} model {{model}}": "Kênh {{name}} mô hình {{model}}", "Channel name is required": "Tên kênh là bắt buộc", "Channel test completed": "Kiểm tra kênh hoàn tất", "Channel type is required": "Loại kênh là bắt buộc", @@ -2419,6 +2423,7 @@ "Model mapping must be a JSON object with string values": "Ánh xạ mô hình phải là đối tượng JSON với giá trị chuỗi", "Model mapping must be valid JSON": "Ánh xạ mô hình phải là JSON hợp lệ", "Model mapping values must be strings": "Giá trị ánh xạ mô hình phải là chuỗi", + "Model {{model}}": "Mô hình {{model}}", "Model name": "Tên mẫu", "Model Name": "Tên mẫu", "Model Name *": "Tên mẫu *", @@ -3440,6 +3445,7 @@ "Resolve Conflicts": "Giải quyết Xung đột", "Resource Configuration": "Cấu hình tài nguyên", "Response": "Phản hồi", + "Response time: {{duration}}": "Thời gian phản hồi: {{duration}}", "Response Time": "Thời gian phản hồi", "Responses API Version": "Phiên bản API Phản hồi", "Restore defaults": "Khôi phục mặc định", diff --git a/web/default/src/i18n/locales/zh.json b/web/default/src/i18n/locales/zh.json index b1f78834..07f56be3 100644 --- a/web/default/src/i18n/locales/zh.json +++ b/web/default/src/i18n/locales/zh.json @@ -53,6 +53,8 @@ "{{modality}} supported": "支持 {{modality}}", "{{n}} model(s) selected": "已选 {{n}} 个模型", "{{success}} succeeded, {{failed}} failed": "{{success}} 个成功,{{failed}} 个失败", + "{{target}} test failed": "{{target}} 测试失败", + "{{target}} test succeeded": "{{target}} 测试成功", "{{value}}ms": "{{value}} 毫秒", "{{value}}s": "{{value}} 秒", "@lobehub/icons key": "@lobehub/icons 键", @@ -669,6 +671,8 @@ "Channel key": "渠道密钥", "Channel key unlocked": "渠道密钥已解锁", "Channel models": "渠道模型", + "Channel {{name}}": "渠道 {{name}}", + "Channel {{name}} model {{model}}": "渠道 {{name}} 模型 {{model}}", "Channel name is required": "渠道名称是必填的", "Channel test completed": "渠道测试完成", "Channel type is required": "渠道类型是必填的", @@ -2419,6 +2423,7 @@ "Model mapping must be a JSON object with string values": "模型映射必须是值为字符串的 JSON 对象", "Model mapping must be valid JSON": "模型映射必须是有效的 JSON", "Model mapping values must be strings": "模型映射的值必须是字符串", + "Model {{model}}": "模型 {{model}}", "Model name": "模型名称", "Model Name": "模型名称", "Model Name *": "模型名称 *", @@ -3440,6 +3445,7 @@ "Resolve Conflicts": "解决冲突", "Resource Configuration": "资源配置", "Response": "响应", + "Response time: {{duration}}": "响应时间:{{duration}}", "Response Time": "响应时间", "Responses API Version": "响应 API 版本", "Restore defaults": "恢复默认",