Sfoglia il codice sorgente

fix(providers): fix endpoint hover dark mode and improve error handling

- Add bg-popover/text-popover-foreground to tooltip for correct dark mode colors
- Show endpoint URL directly instead of label in hover tooltip
- Use structured errorCode with getErrorMessage for add/edit endpoint errors
- Add i18n circuit state labels (circuitOpen/circuitHalfOpen)
- Add endpoint count to viewDetails i18n string across all 5 languages
- Replace .filter(Boolean) with .filter(value => value != null) per linter

Co-Authored-By: Claude Opus 4.6 <[email protected]>
ding113 2 mesi fa
parent
commit
eaf6f2a162

+ 1 - 1
messages/en/settings/providers/strings.json

@@ -105,7 +105,7 @@
   "vendorDeleteSuccess": "Vendor deleted successfully",
   "vendorDeleteFailed": "Failed to delete vendor",
   "endpointStatus": {
-    "viewDetails": "View Details",
+    "viewDetails": "View Details ({count})",
     "activeEndpoints": "Active Endpoints",
     "noEndpoints": "No Endpoints",
     "healthy": "Healthy",

+ 1 - 1
messages/ja/settings/providers/strings.json

@@ -105,7 +105,7 @@
   "vendorDeleteSuccess": "ベンダーを削除しました",
   "vendorDeleteFailed": "ベンダーの削除に失敗しました",
   "endpointStatus": {
-    "viewDetails": "詳細を見る",
+    "viewDetails": "詳細を見る({count})",
     "activeEndpoints": "有効なエンドポイント",
     "noEndpoints": "エンドポイントなし",
     "healthy": "正常",

+ 1 - 1
messages/ru/settings/providers/strings.json

@@ -105,7 +105,7 @@
   "vendorDeleteSuccess": "Вендор удалён",
   "vendorDeleteFailed": "Не удалось удалить вендора",
   "endpointStatus": {
-    "viewDetails": "Подробнее",
+    "viewDetails": "Подробнее ({count})",
     "activeEndpoints": "Активные эндпоинты",
     "noEndpoints": "Нет эндпоинтов",
     "healthy": "Доступен",

+ 1 - 1
messages/zh-CN/settings/providers/strings.json

@@ -105,7 +105,7 @@
   "vendorDeleteSuccess": "服务商删除成功",
   "vendorDeleteFailed": "删除服务商失败",
   "endpointStatus": {
-    "viewDetails": "查看详情",
+    "viewDetails": "查看详情({count})",
     "activeEndpoints": "启用端点",
     "noEndpoints": "无端点",
     "healthy": "健康",

+ 1 - 1
messages/zh-TW/settings/providers/strings.json

@@ -105,7 +105,7 @@
   "vendorDeleteSuccess": "供應商已刪除",
   "vendorDeleteFailed": "刪除供應商失敗",
   "endpointStatus": {
-    "viewDetails": "檢視詳情",
+    "viewDetails": "檢視詳情({count})",
     "activeEndpoints": "啟用端點",
     "noEndpoints": "無端點",
     "healthy": "健康",

+ 6 - 4
src/app/[locale]/settings/providers/_components/provider-endpoint-hover.tsx

@@ -72,7 +72,7 @@ export function ProviderEndpointHover({ vendorId, providerType }: ProviderEndpoi
         </TooltipTrigger>
         <TooltipContent
           side="right"
-          className="p-0 border shadow-lg rounded-lg overflow-hidden min-w-[280px] max-w-[320px]"
+          className="p-0 border shadow-lg rounded-lg overflow-hidden min-w-[280px] max-w-[320px] bg-popover text-popover-foreground"
         >
           <div className="bg-muted/40 px-3 py-2 border-b">
             <h4 className="text-xs font-semibold text-foreground">
@@ -122,9 +122,9 @@ function EndpointRow({ endpoint, isOpen }: { endpoint: ProviderEndpoint; isOpen:
       <div className="flex-1 min-w-0 space-y-1">
         <div className="flex items-center justify-between gap-2">
           <span className="text-xs font-medium truncate text-foreground/90">
-            {endpoint.label || endpoint.url}
+            {endpoint.url}
           </span>
-          {endpoint.lastProbeLatencyMs && (
+          {endpoint.lastProbeLatencyMs != null && (
             <span className="text-[10px] text-muted-foreground tabular-nums shrink-0">
               {endpoint.lastProbeLatencyMs}ms
             </span>
@@ -144,7 +144,9 @@ function EndpointRow({ endpoint, isOpen }: { endpoint: ProviderEndpoint; isOpen:
                 statusModel.color
               )}
             >
-              {circuitState}
+              {circuitState === "open"
+                ? t("endpointStatus.circuitOpen")
+                : t("endpointStatus.circuitHalfOpen")}
             </Badge>
           )}
         </div>

+ 18 - 5
src/app/[locale]/settings/providers/_components/provider-endpoints-table.tsx

@@ -55,6 +55,7 @@ import {
   getProviderTypeConfig,
   getProviderTypeTranslationKey,
 } from "@/lib/provider-type-utils";
+import { getErrorMessage } from "@/lib/utils/error-messages";
 import type { ProviderEndpoint, ProviderType } from "@/types/provider";
 import { EndpointLatencySparkline } from "./endpoint-latency-sparkline";
 import { UrlPreview } from "./forms/url-preview";
@@ -96,8 +97,10 @@ export function ProviderEndpointsTable({
 
   // Build query key based on whether we filter by type
   const queryKey = providerType
-    ? ["provider-endpoints", vendorId, providerType, queryKeySuffix].filter(Boolean)
-    : ["provider-endpoints", vendorId, queryKeySuffix].filter(Boolean);
+    ? ["provider-endpoints", vendorId, providerType, queryKeySuffix].filter(
+        (value) => value != null
+      )
+    : ["provider-endpoints", vendorId, queryKeySuffix].filter((value) => value != null);
 
   const { data: rawEndpoints = [], isLoading } = useQuery({
     queryKey,
@@ -371,6 +374,7 @@ export function AddEndpointButton({
   queryKeySuffix,
 }: AddEndpointButtonProps) {
   const t = useTranslations("settings.providers");
+  const tErrors = useTranslations("errors");
   const tTypes = useTranslations("settings.providers.types");
   const tCommon = useTranslations("settings.common");
   const [open, setOpen] = useState(false);
@@ -422,12 +426,16 @@ export function AddEndpointButton({
         if (fixedProviderType) {
           queryClient.invalidateQueries({
             queryKey: ["provider-endpoints", vendorId, fixedProviderType, queryKeySuffix].filter(
-              Boolean
+              (value) => value != null
             ),
           });
         }
       } else {
-        toast.error(res.error || t("endpointAddFailed"));
+        toast.error(
+          res.errorCode
+            ? getErrorMessage(tErrors, res.errorCode, res.errorParams)
+            : t("endpointAddFailed")
+        );
       }
     } catch (_err) {
       toast.error(t("endpointAddFailed"));
@@ -551,6 +559,7 @@ export function AddEndpointButton({
 
 function EditEndpointDialog({ endpoint }: { endpoint: ProviderEndpoint }) {
   const t = useTranslations("settings.providers");
+  const tErrors = useTranslations("errors");
   const tCommon = useTranslations("settings.common");
   const [open, setOpen] = useState(false);
   const queryClient = useQueryClient();
@@ -585,7 +594,11 @@ function EditEndpointDialog({ endpoint }: { endpoint: ProviderEndpoint }) {
         setOpen(false);
         queryClient.invalidateQueries({ queryKey: ["provider-endpoints"] });
       } else {
-        toast.error(res.error || t("endpointUpdateFailed"));
+        toast.error(
+          res.errorCode
+            ? getErrorMessage(tErrors, res.errorCode, res.errorParams)
+            : t("endpointUpdateFailed")
+        );
       }
     } catch (_err) {
       toast.error(t("endpointUpdateFailed"));