Skip to content

Commit ba1fd76

Browse files
committed
feat: enhance custom model selection UX
1 parent 5ac3fde commit ba1fd76

File tree

2 files changed

+53
-24
lines changed

2 files changed

+53
-24
lines changed

src/renderer/src/lib/store/settings.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ interface Settings {
66
apiBaseURL: string
77
apiKey: string
88
model: string
9+
customModels: string[]
910
customPrompt: string
1011

1112
opacity: number
@@ -21,6 +22,7 @@ const defaultSettings: Settings = {
2122
apiBaseURL: '',
2223
apiKey: '',
2324
model: '',
25+
customModels: [],
2426
customPrompt: '',
2527
codeLanguage: '',
2628

@@ -40,7 +42,7 @@ export const useSettingsStore = create<SettingsStore>()(
4042
}),
4143
{
4244
name: 'interview-coder-settings',
43-
version: 3
45+
version: 4
4446
}
4547
)
4648
)

src/renderer/src/settings/SelectModel.tsx

Lines changed: 50 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
import { useState } from 'react'
1+
import { useState, useMemo } from 'react'
22
import { Button } from '@/components/ui/button'
33
import { cn } from '@/lib/utils'
4-
import { ChevronsUpDown, Check, Plus } from 'lucide-react'
4+
import { ChevronsUpDown, Check, Plus, X } from 'lucide-react'
5+
import { useSettingsStore } from '@/lib/store/settings'
56
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'
67
import {
78
Command,
@@ -33,27 +34,41 @@ export function SelectModel({
3334
className?: string
3435
}) {
3536
const [open, setOpen] = useState(false)
36-
const [models, setModels] = useState(defaultModels)
3737
const [searchValue, setSearchValue] = useState('')
38+
const { customModels, updateSetting } = useSettingsStore()
39+
40+
const models = useMemo(() => {
41+
const customItems = customModels.map((m) => ({ value: m, label: m, isCustom: true }))
42+
const defaultItems = defaultModels.map((m) => ({ ...m, isCustom: false }))
43+
return [...customItems, ...defaultItems]
44+
}, [customModels])
3845

3946
const addCustomModel = (newModel: string) => {
40-
const trimmed = newModel.trim()
41-
if (!trimmed) return
42-
const newValue = trimmed
47+
const newValue = newModel.trim()
48+
if (!newValue) return
4349
const exists = models.some((m) => m.value === newValue)
4450
if (exists) {
4551
onChange?.(newValue)
4652
setOpen(false)
4753
setSearchValue('')
4854
return
4955
}
50-
const item = { value: newValue, label: trimmed }
51-
setModels((prev) => [...prev, item])
56+
updateSetting('customModels', [...customModels, newValue])
5257
onChange?.(newValue)
5358
setSearchValue('')
5459
setOpen(false)
5560
}
5661

62+
const deleteCustomModel = (val: string) => {
63+
updateSetting(
64+
'customModels',
65+
customModels.filter((m) => m !== val)
66+
)
67+
if (value === val) {
68+
onChange?.('')
69+
}
70+
}
71+
5772
const filtered = models.filter((m) => m.label.toLowerCase().includes(searchValue.toLowerCase()))
5873
const showCreate =
5974
searchValue && !filtered.some((m) => m.label.toLowerCase() === searchValue.toLowerCase())
@@ -68,7 +83,7 @@ export function SelectModel({
6883
disabled={disabled}
6984
className={cn('w-60 justify-between', className)}
7085
>
71-
{value ? models.find((m) => m.value === value)?.label : '选择模型...'}
86+
{value ? (models.find((m) => m.value === value)?.label ?? value) : '选择模型...'}
7287
<ChevronsUpDown className="opacity-50" />
7388
</Button>
7489
</PopoverTrigger>
@@ -84,20 +99,32 @@ export function SelectModel({
8499
<CommandEmpty>未找到结果</CommandEmpty>
85100
<CommandGroup>
86101
{filtered.map((m) => (
87-
<CommandItem
88-
key={m.value}
89-
value={m.value}
90-
onSelect={(current) => {
91-
onChange?.(current === value ? '' : current)
92-
setSearchValue('')
93-
setOpen(false)
94-
}}
95-
>
96-
{m.label}
97-
<Check
98-
className={cn('ml-auto', value === m.value ? 'opacity-100' : 'opacity-0')}
99-
/>
100-
</CommandItem>
102+
<div key={m.value} className="group flex">
103+
<CommandItem
104+
value={m.value}
105+
onSelect={(current) => {
106+
onChange?.(current === value ? '' : current)
107+
setSearchValue('')
108+
setOpen(false)
109+
}}
110+
className="flex-1"
111+
>
112+
{m.label}
113+
<Check
114+
className={cn('ml-auto', value === m.value ? 'opacity-100' : 'opacity-0')}
115+
/>
116+
</CommandItem>
117+
{m.isCustom && (
118+
<div className="hidden group-hover:flex">
119+
<button
120+
className="text-gray-400 hover:text-red-500 cursor-pointer"
121+
onClick={() => deleteCustomModel(m.value)}
122+
>
123+
<X className="h-6 w-6" />
124+
</button>
125+
</div>
126+
)}
127+
</div>
101128
))}
102129
{showCreate && (
103130
<CommandItem

0 commit comments

Comments
 (0)