fix(FN-1475): replace Kimi logo with correct Moonshot AI brand mark

- Update ProviderIcon.tsx to use Moonshot AI logo instead of Kimi branding
- Fix logo display in UsageIndicator component
- Add ProviderIcon unit tests covering all provider icons
- Add UsageIndicator tests for provider icon rendering
- Add CustomModelDropdown integration tests for model selection flow
This commit is contained in:
gsxdsm
2026-04-09 21:08:16 -07:00
parent 3ab16f6ad4
commit 402b1db123
6 changed files with 102 additions and 9 deletions

View File

@@ -0,0 +1,5 @@
---
"@gsxdsm/fusion": patch
---
Correct the Kimi/Moonshot AI logo in Usage modal and model selection dropdowns. The crescent moon placeholder icon has been replaced with the official Moonshot AI stylized "K" mark, and both `kimi` and `moonshot` provider names now correctly resolve to the Kimi icon.

View File

@@ -131,7 +131,8 @@ function ZaiIcon({ size, color, label = "Z.ai" }: { size: number; color: string;
);
}
// Kimi / Moonshot AI logo — crescent moon with star
// Kimi / Moonshot AI logo — stylized "K" mark from official Moonshot AI brand identity
// Source: https://iconify.design/icon/logos:moonshot-ai
function KimiIcon({ size, color, label = "Kimi" }: { size: number; color: string; label?: string }) {
return (
<svg
@@ -143,14 +144,9 @@ function KimiIcon({ size, color, label = "Kimi" }: { size: number; color: string
data-testid="kimi-icon"
aria-label={label}
>
{/* Crescent moon */}
{/* Stylized "K" character from Moonshot AI brand */}
<path
d="M12 3C7.03 3 3 7.03 3 12s4.03 9 9 9c1.66 0 3.22-.45 4.57-1.23C14.76 17.82 13 15 13 12c0-3.87 3.13-7 7-7 1.66 0 3.22.45 4.57 1.23-1.27 1.97-3.35 3.22-5.57 3.22C14.76 9.45 13 12 13 12c0 3.87-3.13 7-7 7-1.66 0-3.22-.45-4.57-1.23C3.24 19.97 5.32 21 7.54 21 11.24 21 13 17.97 13 14c0-1.1.9-2 2-2s2 .9 2 2c0 2.97-1.76 6-5.46 6-1.66 0-3.22-.45-4.57-1.23C8.68 20.72 10.21 21 11.76 21 16.97 21 21 16.97 21 12c0-4.97-4.03-9-9-9z"
fill={color}
/>
{/* Star sparkle */}
<path
d="M19.5 4.5l-1 1.5 2 .5-.5 2 1.5-1-1-1.5.5-2z"
d="M5.5 5.5h8v2.5h-5v2h3.5v2.5h-3.5v6.5h-3z"
fill={color}
/>
</svg>
@@ -170,6 +166,7 @@ const providerConfig: Record<
minimax: { component: MiniMaxIcon, color: "#E73562" }, // pink/red
zai: { component: ZaiIcon, color: "#1A6DFF" }, // blue
kimi: { component: KimiIcon, color: "#6C5CE7" }, // purple
moonshot: { component: KimiIcon, color: "#6C5CE7" }, // purple (same as kimi)
};
export function ProviderIcon({ provider, size = "sm" }: ProviderIconProps) {

View File

@@ -591,6 +591,23 @@ describe("UsageIndicator", () => {
expect(document.querySelector('[data-provider="kimi"]')).toBeInTheDocument();
});
it("maps Moonshot provider to kimi icon (alias)", () => {
mockUseUsageData.mockReturnValue({
providers: [
{ name: "Moonshot", icon: "🌙", status: "ok", windows: [] },
],
loading: false,
error: null,
lastUpdated: new Date(),
refresh: mockRefresh,
});
render(<UsageIndicator isOpen={true} onClose={mockOnClose} projectId={TEST_PROJECT_ID} />);
expect(document.querySelector('[data-provider="kimi"]')).toBeInTheDocument();
expect(screen.getByText("Moonshot")).toBeInTheDocument();
});
// Pace indicator tests
it("renders pace marker for weekly windows with timing data", () => {
mockUseUsageData.mockReturnValue({

View File

@@ -235,7 +235,7 @@ function getProviderIconKey(providerName: string): string {
if (normalized.includes('zai') || normalized.includes('zhipu')) {
return 'zai';
}
if (normalized.includes('kimi')) {
if (normalized.includes('kimi') || normalized.includes('moonshot')) {
return 'kimi';
}

View File

@@ -9,6 +9,8 @@ const MOCK_MODELS: ModelInfo[] = [
{ provider: "anthropic", id: "claude-opus-4", name: "Claude Opus 4", reasoning: true, contextWindow: 200000 },
{ provider: "openai", id: "gpt-4o", name: "GPT-4o", reasoning: false, contextWindow: 128000 },
{ provider: "ollama", id: "llama3", name: "Llama 3", reasoning: false, contextWindow: 4096 },
{ provider: "kimi", id: "moonshot-v1-8k", name: "Moonshot V1 8K", reasoning: false, contextWindow: 8192 },
{ provider: "moonshot", id: "moonshot-v1-32k", name: "Moonshot V1 32K", reasoning: false, contextWindow: 32768 },
];
const defaultProps = {
@@ -119,4 +121,49 @@ describe("CustomModelDropdown ProviderIcon Integration", () => {
expect(icon).toHaveAttribute("height", "16");
});
});
it("renders Kimi brand icon for kimi provider model in dropdown", async () => {
const user = userEvent.setup();
render(<CustomModelDropdown {...defaultProps} />);
await user.click(screen.getByLabelText("Test Model"));
// Verify at least one Kimi icon is rendered in dropdown
const kimiIcons = screen.getAllByTestId("kimi-icon");
expect(kimiIcons.length).toBeGreaterThanOrEqual(1);
// Verify the first one has correct attributes
const kimiIcon = kimiIcons[0];
expect(kimiIcon).toHaveAttribute("aria-label", "Kimi");
expect(kimiIcon.querySelector("path")).toHaveAttribute("fill", "#6C5CE7");
});
it("renders Kimi brand icon for moonshot provider model in dropdown (alias)", async () => {
const user = userEvent.setup();
render(<CustomModelDropdown {...defaultProps} />);
await user.click(screen.getByLabelText("Test Model"));
// Both kimi and moonshot providers should show the same Kimi icon
const kimiIcons = screen.getAllByTestId("kimi-icon");
expect(kimiIcons.length).toBeGreaterThanOrEqual(1);
});
it("renders Kimi icon in trigger when kimi model is selected", () => {
render(<CustomModelDropdown {...defaultProps} value="kimi/moonshot-v1-8k" />);
const kimiIcon = screen.getByTestId("kimi-icon");
expect(kimiIcon).toBeInTheDocument();
expect(kimiIcon).toHaveAttribute("aria-label", "Kimi");
expect(kimiIcon.querySelector("path")).toHaveAttribute("fill", "#6C5CE7");
});
it("renders Kimi icon in trigger when moonshot model is selected (alias)", () => {
render(<CustomModelDropdown {...defaultProps} value="moonshot/moonshot-v1-32k" />);
const kimiIcon = screen.getByTestId("kimi-icon");
expect(kimiIcon).toBeInTheDocument();
expect(kimiIcon).toHaveAttribute("aria-label", "Kimi");
expect(kimiIcon.querySelector("path")).toHaveAttribute("fill", "#6C5CE7");
});
});

View File

@@ -263,4 +263,31 @@ describe("ProviderIcon", () => {
const wrapper = screen.getByTestId("kimi-icon").parentElement;
expect(wrapper).toHaveAttribute("data-provider", "kimi");
});
it("renders Kimi brand icon for moonshot provider (alias)", () => {
render(<ProviderIcon provider="moonshot" />);
expect(screen.getByTestId("kimi-icon")).toBeInTheDocument();
expect(screen.getByLabelText("Kimi")).toBeInTheDocument();
});
it("applies provider-specific color for moonshot (alias)", () => {
render(<ProviderIcon provider="moonshot" />);
const icon = screen.getByTestId("kimi-icon").parentElement;
expect(icon).toHaveStyle({ color: "#6C5CE7" });
});
it("passes correct color to SVG fill for moonshot (alias)", () => {
render(<ProviderIcon provider="moonshot" />);
const svg = screen.getByTestId("kimi-icon");
const paths = svg.querySelectorAll("path");
expect(paths.length).toBeGreaterThan(0);
expect(paths[0]).toHaveAttribute("fill", "#6C5CE7");
});
it("normalizes Moonshot (capitalized) to moonshot", () => {
render(<ProviderIcon provider="Moonshot" />);
expect(screen.getByTestId("kimi-icon")).toBeInTheDocument();
const wrapper = screen.getByTestId("kimi-icon").parentElement;
expect(wrapper).toHaveAttribute("data-provider", "moonshot");
});
});