From 915c1e0152a3b4a7d8d8e1e8e8aeb3fc826d6ac5 Mon Sep 17 00:00:00 2001 From: gsxdsm Date: Fri, 10 Jul 2026 17:07:06 -0700 Subject: [PATCH] FN-7801: infer xAI icon for Grok model IDs in ProviderIcon Fix ProviderIcon so Grok model-shaped provider strings (e.g. grok-4.5, grok-cli/grok-4-fast) render the xAI brand icon instead of falling back to the generic Cpu icon. - ProviderIcon now falls back to inferProviderIconKey(provider) when an exact providerConfig lookup misses, before defaulting to the Cpu icon - Added a changeset (patch) documenting the fix for dashboard provider icon surfaces - Added regression tests covering exact xAI/Grok keys, inferred Grok model-id strings, non-Grok inferred providers (e.g. gpt-5.5), and confirming unknown/empty providers still fall back to Cpu without the xAI icon Files changed: .changeset/fn-7801-grok-xai-logo.md | 7 ++++++ packages/dashboard/app/components/ProviderIcon.tsx | 11 ++++++++- .../app/components/__tests__/ProviderIcon.test.tsx | 27 ++++++++++++++++++++++ 3 files changed, 44 insertions(+), 1 deletion(-) Fusion-Task-Id: FN-7801 Fusion-Task-Lineage: e81f15f6-d295-4f6d-b21f-7cf58854457f Co-authored-by: Fusion (runfusion.ai) --- .changeset/fn-7801-grok-xai-logo.md | 7 +++++ .../dashboard/app/components/ProviderIcon.tsx | 11 +++++++- .../__tests__/ProviderIcon.test.tsx | 27 +++++++++++++++++++ 3 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 .changeset/fn-7801-grok-xai-logo.md diff --git a/.changeset/fn-7801-grok-xai-logo.md b/.changeset/fn-7801-grok-xai-logo.md new file mode 100644 index 0000000000..4d55de01ad --- /dev/null +++ b/.changeset/fn-7801-grok-xai-logo.md @@ -0,0 +1,7 @@ +--- +"@runfusion/fusion": patch +--- + +summary: Show the xAI logo for Grok model IDs across dashboard provider surfaces. +category: fix +dev: ProviderIcon now falls back through inferProviderIconKey before the generic CPU icon. diff --git a/packages/dashboard/app/components/ProviderIcon.tsx b/packages/dashboard/app/components/ProviderIcon.tsx index b374577ddc..8c3ab8c7c1 100644 --- a/packages/dashboard/app/components/ProviderIcon.tsx +++ b/packages/dashboard/app/components/ProviderIcon.tsx @@ -1,5 +1,7 @@ import { Cpu } from "lucide-react"; +import { inferProviderIconKey } from "../utils/providerIconKey"; + function LlamaCppIcon({ size, color, label = "llama.cpp" }: { size: number; color: string; label?: string }) { return ; } @@ -829,7 +831,14 @@ const providerConfig: Record< export function ProviderIcon({ provider, size = "sm" }: ProviderIconProps) { const normalizedProvider = provider.toLowerCase(); - const config = providerConfig[normalizedProvider]; + const directConfig = providerConfig[normalizedProvider]; + /* + FNXC:ProviderIcons 2026-07-10-00:00: + FN-7801: dashboard surfaces can pass model-id-shaped provider strings such as grok-4.5 or grok-cli/grok-4-fast, which strict providerConfig lookups miss. + Fall through to the shared inferProviderIconKey normalizer before the Cpu default so Grok/xAI and other provider families keep their brand icons, while exact keys and genuinely unknown providers retain existing behavior. + */ + const inferredConfig = directConfig ? undefined : providerConfig[inferProviderIconKey(provider)]; + const config = directConfig ?? inferredConfig; const IconComponent = config?.component; const color = config?.color ?? "var(--text-muted)"; const label = config?.label; diff --git a/packages/dashboard/app/components/__tests__/ProviderIcon.test.tsx b/packages/dashboard/app/components/__tests__/ProviderIcon.test.tsx index d06deebba1..08a9567e00 100644 --- a/packages/dashboard/app/components/__tests__/ProviderIcon.test.tsx +++ b/packages/dashboard/app/components/__tests__/ProviderIcon.test.tsx @@ -122,6 +122,7 @@ describe("ProviderIcon", () => { it("renders Cpu icon as fallback for unknown providers", () => { render(); + expect(screen.queryByTestId("xai-icon")).not.toBeInTheDocument(); // Cpu icon from lucide-react renders as an svg without our custom data-testid const icon = screen.getByText((_, element) => { return element?.tagName.toLowerCase() === "svg" && @@ -132,6 +133,7 @@ describe("ProviderIcon", () => { it("renders Cpu icon as fallback for empty provider", () => { render(); + expect(screen.queryByTestId("xai-icon")).not.toBeInTheDocument(); const icon = screen.getByText((_, element) => { return element?.tagName.toLowerCase() === "svg" && element?.parentElement?.getAttribute("data-provider") === ""; @@ -418,6 +420,31 @@ describe("ProviderIcon", () => { }); // xAI provider tests + it.each(["xai", "grok", "grok-cli"])("renders xAI brand icon for exact %s provider key", (provider) => { + render(); + expect(screen.getByTestId("xai-icon")).toBeInTheDocument(); + }); + + it.each([ + ["grok-4.5", "grok-4.5"], + ["grok-4-fast", "grok-4-fast"], + ["grok-cli/grok-4-fast", "grok-cli/grok-4-fast"], + ["xai-grok-4", "xai-grok-4"], + ["Grok-4.5", "grok-4.5"], + ])("renders xAI brand icon for inferred Grok model/provider string %s", (provider, expectedDataProvider) => { + render(); + const icon = screen.getByTestId("xai-icon").parentElement; + expect(icon).toHaveStyle({ color: "var(--text)" }); + expect(icon).toHaveAttribute("data-provider", expectedDataProvider); + }); + + it("infers non-Grok provider icons from model-shaped ids", () => { + render(); + const icon = screen.getByTestId("openai-icon").parentElement; + expect(icon).toHaveStyle({ color: "var(--provider-openai)" }); + expect(icon).toHaveAttribute("data-provider", "gpt-5.5"); + }); + it("renders xAI brand icon for xai provider", () => { render(); expect(screen.getByTestId("xai-icon")).toBeInTheDocument();