diff --git a/changelog.d/fixes/6936-providercard-audio-badge.md b/changelog.d/fixes/6936-providercard-audio-badge.md new file mode 100644 index 0000000000..6b70fb4434 --- /dev/null +++ b/changelog.d/fixes/6936-providercard-audio-badge.md @@ -0,0 +1 @@ +- fix(dashboard): label audio/embeddings/image compatible providers by kind instead of "Chat" on ProviderCard (#6936) diff --git a/src/app/(dashboard)/dashboard/providers/components/ProviderCard.tsx b/src/app/(dashboard)/dashboard/providers/components/ProviderCard.tsx index 23a990abf5..d290f07be0 100644 --- a/src/app/(dashboard)/dashboard/providers/components/ProviderCard.tsx +++ b/src/app/(dashboard)/dashboard/providers/components/ProviderCard.tsx @@ -42,6 +42,15 @@ const KIND_LABEL: Record = { music: "Music", }; +/** Maps a compatible-provider `apiType` to its `KIND_LABEL` key (#6936: non-chat + * apiTypes — audio/embeddings/image — were falling through to the "Chat" badge). */ +const COMPATIBLE_API_TYPE_KIND: Record = { + "audio-transcriptions": "stt", + "audio-speech": "tts", + "images-generations": "image", + embeddings: "embedding", +}; + interface ProviderCardProps { providerId: string; provider: { @@ -319,7 +328,10 @@ export default function ProviderCard({ ))} {isCompatible && ( - {provider.apiType === "responses" ? t("responses") : t("chat")} + {provider.apiType === "responses" + ? t("responses") + : (KIND_LABEL[COMPATIBLE_API_TYPE_KIND[provider.apiType ?? ""] ?? ""] ?? + t("chat"))} )} {isCcCompatible && ( diff --git a/src/app/(dashboard)/dashboard/providers/components/__tests__/providerCardAudioBadge.test.tsx b/src/app/(dashboard)/dashboard/providers/components/__tests__/providerCardAudioBadge.test.tsx new file mode 100644 index 0000000000..71850594aa --- /dev/null +++ b/src/app/(dashboard)/dashboard/providers/components/__tests__/providerCardAudioBadge.test.tsx @@ -0,0 +1,94 @@ +import React from "react"; +import { createRoot } from "react-dom/client"; +import { act } from "react"; +import { afterEach, describe, expect, it, vi } from "vitest"; +import ProviderCard from "../ProviderCard"; + +vi.mock("next-intl", () => ({ useTranslations: () => (k: string) => k })); +vi.mock("@/shared/components/ProviderTestSlideOver", () => ({ default: () => null })); +vi.mock("@/shared/components/ProviderIcon", () => ({ default: () => null })); + +describe("ProviderCard — #6936 audio-transcriptions provider badge", () => { + let container: HTMLDivElement | null = null; + + afterEach(() => { + if (container) { + document.body.removeChild(container); + container = null; + } + }); + + it("does NOT label an audio-transcriptions compatible node as Chat", () => { + container = document.createElement("div"); + document.body.appendChild(container); + const root = createRoot(container); + act(() => { + root.render( + {}} + /> + ); + }); + const text = (container.textContent || "").toLowerCase(); + expect(text).not.toContain("chat"); + expect(text).toContain("stt"); + }); + + it("labels an audio-speech compatible node as TTS", () => { + container = document.createElement("div"); + document.body.appendChild(container); + const root = createRoot(container); + act(() => { + root.render( + {}} + /> + ); + }); + const text = (container.textContent || "").toLowerCase(); + expect(text).not.toContain("chat"); + expect(text).toContain("tts"); + }); + + it("still labels a plain chat compatible node as Chat", () => { + container = document.createElement("div"); + document.body.appendChild(container); + const root = createRoot(container); + act(() => { + root.render( + {}} + /> + ); + }); + const text = (container.textContent || "").toLowerCase(); + expect(text).toContain("chat"); + }); +});