import { Check, ChevronsUpDown } from 'lucide-react' import { useState } from 'react' import { Button, cn, Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, Popover, PopoverContent, PopoverTrigger, RadioGroupStacked, RadioGroupStackedItem, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Switch, } from 'ui' import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout' import { MultiSelector, MultiSelectorContent, MultiSelectorItem, MultiSelectorList, MultiSelectorTrigger, } from 'ui-patterns/multi-select' import type { ConnectMode, FieldOption, ResolvedField } from './Connect.types' import { getOptionMatchScore } from './ConnectConfigSection.utils' import { ConnectionIcon } from './ConnectionIcon' import { ConnectModeButton, getConnectModeButtonCornerVariants, getConnectModeEmptySlotClasses, } from './ConnectModeButton' interface ConnectConfigSectionProps { activeFields: ResolvedField[] state: Record onFieldChange: (fieldId: string, value: string | boolean | string[]) => void getFieldOptions: (fieldId: string) => FieldOption[] } export function ConnectConfigSection({ activeFields, state, onFieldChange, getFieldOptions, }: ConnectConfigSectionProps) { if (activeFields.length === 0) return null return (
{activeFields.map((field) => { const options = getFieldOptions(field.id) const value = state[field.id] // Skip fields with no options (or single option that's auto-selected) // Exception: switch and multi-select fields don't require options if (field.type !== 'switch' && field.type !== 'multi-select') { if (options.length === 0) return null if (options.length === 1) return null } switch (field.type) { case 'combobox': return ( onFieldChange(field.id, v)} placeholder={field.combobox?.placeholder ?? 'Select option'} searchPlaceholder={field.combobox?.searchPlaceholder ?? 'Search...'} emptyMessage={field.combobox?.emptyMessage ?? 'No results found'} /* [Joshen] Omitting MCP icons for now as the images are not optimized (large) and is causing noticeably latency issues on the browser (even with the existing Connect UI) */ showIcons={field.id === 'framework'} /> ) case 'radio-grid': return ( onFieldChange(field.id, v)} className="flex-row gap-3 space-y-0" > {options.map((option) => (
{option.icon && } {option.label}
))}
) case 'radio-list': return ( onFieldChange(field.id, v)} className="min-w-0 w-full" > {options.map((option) => ( {option.icon && } {option.label} } description={option.description} /> ))} ) case 'select': return ( ) case 'switch': return ( onFieldChange(field.id, v)} /> ) case 'multi-select': return ( onFieldChange(field.id, v)} > {options.map((option) => (
{option.label} {option.description && ( {option.description} )}
))}
) default: return null } })}
) } interface ConnectComboboxProps { id: string options: FieldOption[] value: string onValueChange: (value: string) => void placeholder: string searchPlaceholder: string emptyMessage: string showIcons: boolean } function ConnectCombobox({ id, options, value, onValueChange, placeholder, searchPlaceholder, emptyMessage, showIcons, }: ConnectComboboxProps) { const [isOpen, setIsOpen] = useState(false) const [search, setSearch] = useState('') const [listboxElementId, setListboxElementId] = useState() const selectedOption = options.find((option) => option.value === value) const showEmptyStatus = search.trim().length > 0 && !options.some((option) => getOptionMatchScore(option.label, search, [option.value]) > 0) const handleOpenChange = (open: boolean) => { setIsOpen(open) if (!open) setSearch('') } return (

{showEmptyStatus ? emptyMessage : ''}

{ if (node?.id) setListboxElementId(node.id) }} > {emptyMessage} {options.map((option) => ( { onValueChange(option.value) handleOpenChange(false) }} className="gap-x-2" > {showIcons && option.icon && ( )} {option.label} ))}
) } interface ModeSelectorProps { modes: Array<{ id: ConnectMode; label: string; description: string }> selected: ConnectMode onChange: (mode: ConnectMode) => void } export function ModeSelector({ modes, selected, onChange }: ModeSelectorProps) { const count = modes.length // 2-col layout leaves an empty cell when count is odd; hide it once we switch to a single row const emptySlots = count % 2 === 1 ? 1 : 0 return ( // Container query: 2-col when the sheet is narrow; one equal row when there's room
= 6 && '@[36rem]:grid-cols-6' )} > {modes.map((mode, index) => ( onChange(mode.id)} {...getConnectModeButtonCornerVariants({ index, count, emptySlots })} /> ))} {Array.from({ length: emptySlots }, (_, index) => (
))}
) }