fix: improve todo send dialog model picker (#1426)

* fix: improve todo send dialog model picker

* fix: truncate long model selector labels

---------

Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
This commit is contained in:
Robert Hamilton
2026-05-26 20:46:30 +03:00
committed by GitHub
co-authored by Bohdan Triapitsyn
parent 6a173211b0
commit cc3d1bd63c
2 changed files with 40 additions and 25 deletions
@@ -23,6 +23,8 @@ interface ModelSelectorProps {
className?: string; className?: string;
allowedProviderIds?: string[]; allowedProviderIds?: string[];
placeholder?: string; placeholder?: string;
tooltipsEnabled?: boolean;
dropdownPortalToBody?: boolean;
} }
export const ModelSelector: React.FC<ModelSelectorProps> = ({ export const ModelSelector: React.FC<ModelSelectorProps> = ({
@@ -32,6 +34,8 @@ export const ModelSelector: React.FC<ModelSelectorProps> = ({
className, className,
allowedProviderIds, allowedProviderIds,
placeholder, placeholder,
tooltipsEnabled = true,
dropdownPortalToBody = false,
}) => { }) => {
const { t } = useI18n(); const { t } = useI18n();
const { isReady, isUnavailable } = useOpenCodeReadiness(); const { isReady, isUnavailable } = useOpenCodeReadiness();
@@ -103,7 +107,7 @@ export const ModelSelector: React.FC<ModelSelectorProps> = ({
includeNotSelected includeNotSelected
onSelectNone={handleSelectNone} onSelectNone={handleSelectNone}
onEscape={closePicker} onEscape={closePicker}
tooltipsEnabled={isActuallyMobile ? isMobilePanelOpen : isDropdownOpen} tooltipsEnabled={tooltipsEnabled && (isActuallyMobile ? isMobilePanelOpen : isDropdownOpen)}
isFavorite={(entry) => isFavoriteModel(entry.providerID, entry.modelID)} isFavorite={(entry) => isFavoriteModel(entry.providerID, entry.modelID)}
onToggleFavorite={(entry) => toggleFavoriteModel(entry.providerID, entry.modelID)} onToggleFavorite={(entry) => toggleFavoriteModel(entry.providerID, entry.modelID)}
/> />
@@ -152,7 +156,7 @@ export const ModelSelector: React.FC<ModelSelectorProps> = ({
<DropdownMenu open={isReady && isDropdownOpen} onOpenChange={isReady ? setIsDropdownOpen : undefined}> <DropdownMenu open={isReady && isDropdownOpen} onOpenChange={isReady ? setIsDropdownOpen : undefined}>
<DropdownMenuTrigger asChild> <DropdownMenuTrigger asChild>
<div className={cn( <div className={cn(
'border-input data-[placeholder]:text-muted-foreground flex items-center justify-between gap-2 rounded-lg border bg-transparent px-2 py-2 typography-ui-label whitespace-nowrap shadow-none outline-none hover:bg-interactive-hover data-[popup-open]:bg-interactive-active h-6 w-fit', 'border-input data-[placeholder]:text-muted-foreground flex min-w-0 items-center justify-between gap-2 rounded-lg border bg-transparent px-2 py-2 typography-ui-label whitespace-nowrap shadow-none outline-none hover:bg-interactive-hover data-[popup-open]:bg-interactive-active h-6 w-fit',
!isReady && 'opacity-60 cursor-not-allowed', !isReady && 'opacity-60 cursor-not-allowed',
className, className,
)}> )}>
@@ -165,14 +169,14 @@ export const ModelSelector: React.FC<ModelSelectorProps> = ({
</> </>
) : ( ) : (
<> <>
{providerId ? <ProviderLogo providerId={providerId} className="h-3.5 w-3.5 flex-shrink-0" /> : <Icon name="pencil-ai" className="h-3.5 w-3.5 text-muted-foreground" />} {providerId ? <ProviderLogo providerId={providerId} className="h-3.5 w-3.5 flex-shrink-0" /> : <Icon name="pencil-ai" className="h-3.5 w-3.5 flex-shrink-0 text-muted-foreground" />}
<span className="typography-ui-label font-normal whitespace-nowrap text-foreground">{triggerLabel}</span> <span className="typography-ui-label min-w-0 truncate font-normal text-foreground">{triggerLabel}</span>
</> </>
)} )}
<Icon name="arrow-down-s" className="h-4 w-4 flex-shrink-0 text-muted-foreground/50" /> <Icon name="arrow-down-s" className="h-4 w-4 flex-shrink-0 text-muted-foreground/50" />
</div> </div>
</DropdownMenuTrigger> </DropdownMenuTrigger>
<DropdownMenuContent className="w-[min(380px,calc(100vw-2rem))] p-0 flex flex-col" align="start"> <DropdownMenuContent className="w-[min(380px,calc(100vw-2rem))] p-0 flex flex-col" align="start" portalToBody={dropdownPortalToBody}>
{picker} {picker}
</DropdownMenuContent> </DropdownMenuContent>
</DropdownMenu> </DropdownMenu>
@@ -196,30 +196,41 @@ export function TodoSendDialog(props: TodoSendDialogProps) {
return ( return (
<Dialog open={open} onOpenChange={(nextOpen) => { if (!submitting) onOpenChange(nextOpen); }}> <Dialog open={open} onOpenChange={(nextOpen) => { if (!submitting) onOpenChange(nextOpen); }}>
<DialogContent className="max-w-lg"> <DialogContent className="max-w-2xl overflow-visible">
<DialogHeader> <DialogHeader>
<DialogTitle>{title}</DialogTitle> <DialogTitle>{title}</DialogTitle>
</DialogHeader> </DialogHeader>
<div className="flex flex-wrap items-center gap-x-4 gap-y-2"> <div className="grid gap-4 sm:grid-cols-[minmax(0,1fr)_auto_auto]">
<ModelSelector <div className="flex min-w-0 flex-col gap-1.5">
providerId={execution.providerID} <span className="typography-meta font-medium text-muted-foreground">{t('chat.modelControls.model')}</span>
modelId={execution.modelID} <ModelSelector
onChange={(providerID, modelID) => { providerId={execution.providerID}
setExecution((prev) => ({ ...prev, providerID, modelID, variant: '' })); modelId={execution.modelID}
}} className="w-full justify-between"
/> dropdownPortalToBody
<ThinkingPill onChange={(providerID, modelID) => {
value={execution.variant} setExecution((prev) => ({ ...prev, providerID, modelID, variant: '' }));
options={variantOptions} }}
disabled={!hasVariantOptions} />
onChange={(variant) => setExecution((prev) => ({ ...prev, variant }))} </div>
/> <div className="flex flex-col gap-1.5">
<AgentSelector <span className="typography-meta font-medium text-muted-foreground">{t('sessions.scheduledTasks.editor.thinkingLevel.label')}</span>
agentName={execution.agent} <ThinkingPill
filter={agentFilter} value={execution.variant}
onChange={(agent) => setExecution((prev) => ({ ...prev, agent }))} options={variantOptions}
/> disabled={!hasVariantOptions}
onChange={(variant) => setExecution((prev) => ({ ...prev, variant }))}
/>
</div>
<div className="flex flex-col gap-1.5">
<span className="typography-meta font-medium text-muted-foreground">{t('sessions.scheduledTasks.editor.agent.label')}</span>
<AgentSelector
agentName={execution.agent}
filter={agentFilter}
onChange={(agent) => setExecution((prev) => ({ ...prev, agent }))}
/>
</div>
</div> </div>
<div className="flex items-center justify-end gap-2"> <div className="flex items-center justify-end gap-2">