({
session,
selectedModelId,
className,
}: {
session: Session;
selectedModelId: string;
} & React.ComponentProps<typeof Button>)
| 18 | import type { Session } from 'next-auth'; |
| 19 | |
| 20 | export function ModelSelector({ |
| 21 | session, |
| 22 | selectedModelId, |
| 23 | className, |
| 24 | }: { |
| 25 | session: Session; |
| 26 | selectedModelId: string; |
| 27 | } & React.ComponentProps<typeof Button>) { |
| 28 | const [open, setOpen] = useState(false); |
| 29 | const [optimisticModelId, setOptimisticModelId] = |
| 30 | useOptimistic(selectedModelId); |
| 31 | |
| 32 | const userType = session.user.type; |
| 33 | const { availableChatModelIds } = entitlementsByUserType[userType]; |
| 34 | |
| 35 | const availableChatModels = chatModels.filter((chatModel) => |
| 36 | availableChatModelIds.includes(chatModel.id), |
| 37 | ); |
| 38 | |
| 39 | const selectedChatModel = useMemo( |
| 40 | () => |
| 41 | availableChatModels.find( |
| 42 | (chatModel) => chatModel.id === optimisticModelId, |
| 43 | ), |
| 44 | [optimisticModelId, availableChatModels], |
| 45 | ); |
| 46 | |
| 47 | return ( |
| 48 | <DropdownMenu open={open} onOpenChange={setOpen}> |
| 49 | <DropdownMenuTrigger |
| 50 | asChild |
| 51 | className={cn( |
| 52 | 'w-fit data-[state=open]:bg-accent data-[state=open]:text-accent-foreground', |
| 53 | className, |
| 54 | )} |
| 55 | > |
| 56 | <Button |
| 57 | data-testid="model-selector" |
| 58 | variant="outline" |
| 59 | className="md:px-2 md:h-[34px]" |
| 60 | > |
| 61 | {selectedChatModel?.name} |
| 62 | <ChevronDownIcon /> |
| 63 | </Button> |
| 64 | </DropdownMenuTrigger> |
| 65 | <DropdownMenuContent align="start" className="min-w-[300px]"> |
| 66 | {availableChatModels.map((chatModel) => { |
| 67 | const { id } = chatModel; |
| 68 | |
| 69 | return ( |
| 70 | <DropdownMenuItem |
| 71 | data-testid={`model-selector-item-${id}`} |
| 72 | key={id} |
| 73 | onSelect={() => { |
| 74 | setOpen(false); |
| 75 | |
| 76 | startTransition(() => { |
| 77 | setOptimisticModelId(id); |
nothing calls this directly
no test coverage detected
searching dependent graphs…