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) <noreply@runfusion.ai>
This commit is contained in:
7
.changeset/fn-7801-grok-xai-logo.md
Normal file
7
.changeset/fn-7801-grok-xai-logo.md
Normal file
@@ -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.
|
||||
@@ -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 <Cpu size={size} color={color} aria-label={label} data-testid="llama-cpp-icon" />;
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -122,6 +122,7 @@ describe("ProviderIcon", () => {
|
||||
|
||||
it("renders Cpu icon as fallback for unknown providers", () => {
|
||||
render(<ProviderIcon provider="unknown" />);
|
||||
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(<ProviderIcon provider="" />);
|
||||
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(<ProviderIcon provider={provider} />);
|
||||
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(<ProviderIcon provider={provider} />);
|
||||
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(<ProviderIcon provider="gpt-5.5" />);
|
||||
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(<ProviderIcon provider="xai" />);
|
||||
expect(screen.getByTestId("xai-icon")).toBeInTheDocument();
|
||||
|
||||
Reference in New Issue
Block a user