feat(ui): allow custom model names in Quick Setup wizard

- Add "Custom model name..." option to model dropdown
- Show text input when custom selected
- Allow any CLIProxy-supported model name
- Toggle back to presets with link
This commit is contained in:
kaitranntt committed 2026-01-28 11:57:22 -05:00
1 parent 85aa747aeb
commit ab9bbedfa9
1 file changed
+46 -3
@@ -2,6 +2,7 @@
* Variant Creation Step * Variant Creation Step
*/ */
import { useState } from 'react';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input'; import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label'; import { Label } from '@/components/ui/label';
@@ -18,6 +19,8 @@ import { PRIVACY_BLUR_CLASS } from '@/contexts/privacy-context';
import { MODEL_CATALOGS } from '@/lib/model-catalogs'; import { MODEL_CATALOGS } from '@/lib/model-catalogs';
import type { VariantStepProps } from '../types'; import type { VariantStepProps } from '../types';
const CUSTOM_MODEL_VALUE = '__custom__';
export function VariantStep({ export function VariantStep({
selectedProvider, selectedProvider,
selectedAccount, selectedAccount,
@@ -31,6 +34,21 @@ export function VariantStep({
onSkip, onSkip,
onCreate, onCreate,
}: VariantStepProps) { }: VariantStepProps) {
// Track if user selected custom model option
const catalogModels = MODEL_CATALOGS[selectedProvider]?.models || [];
const isCustomModel = modelName && !catalogModels.some((m) => m.id === modelName);
const [showCustomInput, setShowCustomInput] = useState(isCustomModel);
const handleModelSelect = (value: string) => {
if (value === CUSTOM_MODEL_VALUE) {
setShowCustomInput(true);
onModelChange(''); // Clear to let user type custom
} else {
setShowCustomInput(false);
onModelChange(value);
}
};
return ( return (
<div className="space-y-4"> <div className="space-y-4">
{selectedAccount && ( {selectedAccount && (
@@ -60,12 +78,31 @@ export function VariantStep({
<div className="space-y-2"> <div className="space-y-2">
<Label>Model</Label> <Label>Model</Label>
<Select value={modelName} onValueChange={onModelChange}> {showCustomInput ? (
<div className="space-y-2">
<Input
value={modelName}
onChange={(e) => onModelChange(e.target.value)}
placeholder="e.g., gemini-2.5-pro, claude-opus-4-5"
/>
<button
type="button"
className="text-xs text-primary hover:underline"
onClick={() => setShowCustomInput(false)}
>
Choose from presets instead
</button>
</div>
) : (
<Select
value={catalogModels.some((m) => m.id === modelName) ? modelName : ''}
onValueChange={handleModelSelect}
>
<SelectTrigger> <SelectTrigger>
<SelectValue placeholder="Select a model" /> <SelectValue placeholder="Select a model" />
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
{MODEL_CATALOGS[selectedProvider]?.models.map((m) => ( {catalogModels.map((m) => (
<SelectItem key={m.id} value={m.id}> <SelectItem key={m.id} value={m.id}>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<span>{m.name}</span> <span>{m.name}</span>
@@ -75,10 +112,16 @@ export function VariantStep({
</div> </div>
</SelectItem> </SelectItem>
))} ))}
<SelectItem value={CUSTOM_MODEL_VALUE}>
<span className="text-primary">Custom model name...</span>
</SelectItem>
</SelectContent> </SelectContent>
</Select> </Select>
)}
<div className="text-xs text-muted-foreground"> <div className="text-xs text-muted-foreground">
Default: {MODEL_CATALOGS[selectedProvider]?.defaultModel || 'provider default'} {showCustomInput
? 'Enter any model name supported by CLIProxy'
: `Default: ${MODEL_CATALOGS[selectedProvider]?.defaultModel || 'provider default'}`}
</div> </div>
</div> </div>