fix(ui): avoid model selector tooltip ref loop
This commit is contained in:
parent
a2e82e498a
commit
7c3c852520
2 changed files with 9 additions and 58 deletions
|
|
@ -6,12 +6,6 @@ import { Input } from '@renderer/components/ui/input';
|
|||
import { Label } from '@renderer/components/ui/label';
|
||||
import { Popover, PopoverContent, PopoverTrigger } from '@renderer/components/ui/popover';
|
||||
import { Tabs, TabsList, TabsTrigger } from '@renderer/components/ui/tabs';
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipProvider,
|
||||
TooltipTrigger,
|
||||
} from '@renderer/components/ui/tooltip';
|
||||
import { useEffectiveCliProviderStatus } from '@renderer/hooks/useEffectiveCliProviderStatus';
|
||||
import { cn } from '@renderer/lib/utils';
|
||||
import { useStore } from '@renderer/store';
|
||||
|
|
@ -53,7 +47,6 @@ import {
|
|||
CheckCircle2,
|
||||
ChevronDown,
|
||||
Filter,
|
||||
Info,
|
||||
Search,
|
||||
Star,
|
||||
} from 'lucide-react';
|
||||
|
|
@ -740,6 +733,8 @@ export const TeamModelSelector: React.FC<TeamModelSelectorProps> = ({
|
|||
effectiveProviderId === 'opencode'
|
||||
? getOpenCodeModelPricingInfo(openCodeCatalogModelById.get(opt.value))
|
||||
: null;
|
||||
const modelButtonTitle =
|
||||
modelStatusMessage ?? (opt.value === '' ? defaultModelTooltip : undefined);
|
||||
|
||||
return (
|
||||
<button
|
||||
|
|
@ -747,7 +742,7 @@ export const TeamModelSelector: React.FC<TeamModelSelectorProps> = ({
|
|||
type="button"
|
||||
id={opt.value === normalizedValue ? id : undefined}
|
||||
aria-disabled={!modelSelectable}
|
||||
title={modelStatusMessage ?? undefined}
|
||||
title={modelButtonTitle}
|
||||
className={cn(
|
||||
'flex min-h-[44px] items-center justify-center gap-1.5 rounded-md border bg-[var(--color-surface)] px-3 py-2 text-center text-xs font-medium transition-[background-color,border-color,color,box-shadow] duration-150',
|
||||
hasModelIssue && normalizedValue === opt.value
|
||||
|
|
@ -824,25 +819,6 @@ export const TeamModelSelector: React.FC<TeamModelSelectorProps> = ({
|
|||
<span>{modelRecommendation.label}</span>
|
||||
</span>
|
||||
) : null}
|
||||
{opt.value === '' && (
|
||||
<span className="flex items-center justify-center gap-1">
|
||||
<TooltipProvider delayDuration={200}>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild onClick={(e: React.MouseEvent) => e.stopPropagation()}>
|
||||
<Info className="size-3 shrink-0 opacity-40 transition-opacity hover:opacity-70" />
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="top" className="max-w-[240px] text-xs">
|
||||
{defaultModelTooltip.split('\n').map((line, index) => (
|
||||
<React.Fragment key={line}>
|
||||
{index > 0 ? <br /> : null}
|
||||
{line}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
</span>
|
||||
)}
|
||||
{hasModelIssue && (
|
||||
<span
|
||||
className="flex items-center justify-center gap-1 text-[10px] font-normal text-red-300"
|
||||
|
|
@ -850,16 +826,6 @@ export const TeamModelSelector: React.FC<TeamModelSelectorProps> = ({
|
|||
>
|
||||
<AlertTriangle className="size-3 shrink-0" />
|
||||
<span>{modelUnavailableReason ? 'Unavailable' : 'Issue'}</span>
|
||||
<TooltipProvider delayDuration={200}>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild onClick={(e: React.MouseEvent) => e.stopPropagation()}>
|
||||
<Info className="size-3 shrink-0 opacity-50 transition-opacity hover:opacity-80" />
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="top" className="max-w-[240px] text-xs">
|
||||
{modelStatusMessage}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
</span>
|
||||
)}
|
||||
{!hasModelIssue && modelDisabledReason && (
|
||||
|
|
@ -868,16 +834,6 @@ export const TeamModelSelector: React.FC<TeamModelSelectorProps> = ({
|
|||
title={modelDisabledReason}
|
||||
>
|
||||
<span>{TEAM_MODEL_UI_DISABLED_BADGE_LABEL}</span>
|
||||
<TooltipProvider delayDuration={200}>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild onClick={(e: React.MouseEvent) => e.stopPropagation()}>
|
||||
<Info className="size-3 shrink-0 opacity-40 transition-opacity hover:opacity-70" />
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="top" className="max-w-[240px] text-xs">
|
||||
{modelDisabledReason}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
</span>
|
||||
)}
|
||||
</span>
|
||||
|
|
|
|||
|
|
@ -4,17 +4,6 @@ import { afterEach, describe, expect, it, vi } from 'vitest';
|
|||
|
||||
import type { CodexAccountSnapshotDto } from '@features/codex-account/contracts';
|
||||
|
||||
vi.mock('@renderer/components/ui/tooltip', () => ({
|
||||
TooltipProvider: ({ children }: { children: React.ReactNode }) =>
|
||||
React.createElement(React.Fragment, null, children),
|
||||
Tooltip: ({ children }: { children: React.ReactNode }) =>
|
||||
React.createElement(React.Fragment, null, children),
|
||||
TooltipTrigger: ({ children }: { children: React.ReactNode }) =>
|
||||
React.createElement(React.Fragment, null, children),
|
||||
TooltipContent: ({ children }: { children: React.ReactNode }) =>
|
||||
React.createElement('div', null, children),
|
||||
}));
|
||||
|
||||
vi.mock('@renderer/components/ui/tabs', () => {
|
||||
let currentValue = '';
|
||||
let currentOnValueChange: ((value: string) => void) | null = null;
|
||||
|
|
@ -131,6 +120,12 @@ describe('TeamModelSelector disabled Codex models', () => {
|
|||
expect(host.textContent).toContain('Default');
|
||||
expect(host.textContent).not.toContain('5.1 Codex Mini');
|
||||
expect(host.textContent).not.toContain('5.3 Codex Spark');
|
||||
const defaultButton = Array.from(host.querySelectorAll('button')).find((button) =>
|
||||
button.textContent?.trim().startsWith('Default')
|
||||
);
|
||||
expect(defaultButton?.getAttribute('title')).toBe(
|
||||
'Uses the runtime default for the selected provider.'
|
||||
);
|
||||
|
||||
await act(async () => {
|
||||
root.unmount();
|
||||
|
|
|
|||
Loading…
Reference in a new issue