1- import { useState } from 'react'
1+ import { useState , useMemo } from 'react'
22import { Button } from '@/components/ui/button'
33import { 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'
56import { Popover , PopoverContent , PopoverTrigger } from '@/components/ui/popover'
67import {
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