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:
committed by
GitHub
co-authored by
Bohdan Triapitsyn
parent
6a173211b0
commit
cc3d1bd63c
@@ -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">
|
||||||
|
|||||||
Reference in New Issue
Block a user