11import { VSCodeButton , VSCodeTextField } from "@vscode/webview-ui-toolkit/react"
2- import { memo , useEffect , useReducer , useRef } from "react"
2+ import { memo , useEffect , useRef , useState } from "react"
33import { ApiConfigMeta } from "../../../../src/shared/ExtensionMessage"
44import { Dropdown } from "vscrui"
55import type { DropdownOption } from "vscrui"
@@ -14,86 +14,6 @@ interface ApiConfigManagerProps {
1414 onUpsertConfig : ( configName : string ) => void
1515}
1616
17- type State = {
18- isRenaming : boolean
19- isCreating : boolean
20- inputValue : string
21- newProfileName : string
22- error : string | null
23- }
24-
25- type Action =
26- | { type : "START_RENAME" ; payload : string }
27- | { type : "CANCEL_EDIT" }
28- | { type : "SET_INPUT" ; payload : string }
29- | { type : "SET_NEW_NAME" ; payload : string }
30- | { type : "START_CREATE" }
31- | { type : "CANCEL_CREATE" }
32- | { type : "SET_ERROR" ; payload : string | null }
33- | { type : "RESET_STATE" }
34-
35- const initialState : State = {
36- isRenaming : false ,
37- isCreating : false ,
38- inputValue : "" ,
39- newProfileName : "" ,
40- error : null ,
41- }
42-
43- const reducer = ( state : State , action : Action ) : State => {
44- switch ( action . type ) {
45- case "START_RENAME" :
46- return {
47- ...state ,
48- isRenaming : true ,
49- inputValue : action . payload ,
50- error : null ,
51- }
52- case "CANCEL_EDIT" :
53- return {
54- ...state ,
55- isRenaming : false ,
56- inputValue : "" ,
57- error : null ,
58- }
59- case "SET_INPUT" :
60- return {
61- ...state ,
62- inputValue : action . payload ,
63- error : null ,
64- }
65- case "SET_NEW_NAME" :
66- return {
67- ...state ,
68- newProfileName : action . payload ,
69- error : null ,
70- }
71- case "START_CREATE" :
72- return {
73- ...state ,
74- isCreating : true ,
75- newProfileName : "" ,
76- error : null ,
77- }
78- case "CANCEL_CREATE" :
79- return {
80- ...state ,
81- isCreating : false ,
82- newProfileName : "" ,
83- error : null ,
84- }
85- case "SET_ERROR" :
86- return {
87- ...state ,
88- error : action . payload ,
89- }
90- case "RESET_STATE" :
91- return initialState
92- default :
93- return state
94- }
95- }
96-
9717const ApiConfigManager = ( {
9818 currentApiConfigName = "" ,
9919 listApiConfigMeta = [ ] ,
@@ -102,7 +22,11 @@ const ApiConfigManager = ({
10222 onRenameConfig,
10323 onUpsertConfig,
10424} : ApiConfigManagerProps ) => {
105- const [ state , dispatch ] = useReducer ( reducer , initialState )
25+ const [ isRenaming , setIsRenaming ] = useState ( false )
26+ const [ isCreating , setIsCreating ] = useState ( false )
27+ const [ inputValue , setInputValue ] = useState ( "" )
28+ const [ newProfileName , setNewProfileName ] = useState ( "" )
29+ const [ error , setError ] = useState < string | null > ( null )
10630 const inputRef = useRef < any > ( null )
10731 const newProfileInputRef = useRef < any > ( null )
10832
@@ -127,68 +51,84 @@ const ApiConfigManager = ({
12751
12852 // Focus input when entering rename mode
12953 useEffect ( ( ) => {
130- if ( state . isRenaming ) {
54+ if ( isRenaming ) {
13155 const timeoutId = setTimeout ( ( ) => inputRef . current ?. focus ( ) , 0 )
13256 return ( ) => clearTimeout ( timeoutId )
13357 }
134- } , [ state . isRenaming ] )
58+ } , [ isRenaming ] )
13559
13660 // Focus input when opening new dialog
13761 useEffect ( ( ) => {
138- if ( state . isCreating ) {
62+ if ( isCreating ) {
13963 const timeoutId = setTimeout ( ( ) => newProfileInputRef . current ?. focus ( ) , 0 )
14064 return ( ) => clearTimeout ( timeoutId )
14165 }
142- } , [ state . isCreating ] )
66+ } , [ isCreating ] )
14367
14468 // Reset state when current profile changes
14569 useEffect ( ( ) => {
146- dispatch ( { type : "RESET_STATE" } )
70+ setIsRenaming ( false )
71+ setIsCreating ( false )
72+ setInputValue ( "" )
73+ setNewProfileName ( "" )
74+ setError ( null )
14775 } , [ currentApiConfigName ] )
14876
14977 const handleAdd = ( ) => {
150- dispatch ( { type : "START_CREATE" } )
78+ setIsCreating ( true )
79+ setNewProfileName ( "" )
80+ setError ( null )
15181 }
15282
15383 const handleStartRename = ( ) => {
154- dispatch ( { type : "START_RENAME" , payload : currentApiConfigName || "" } )
84+ setIsRenaming ( true )
85+ setInputValue ( currentApiConfigName || "" )
86+ setError ( null )
15587 }
15688
15789 const handleCancel = ( ) => {
158- dispatch ( { type : "CANCEL_EDIT" } )
90+ setIsRenaming ( false )
91+ setInputValue ( "" )
92+ setError ( null )
15993 }
16094
16195 const handleSave = ( ) => {
162- const trimmedValue = state . inputValue . trim ( )
96+ const trimmedValue = inputValue . trim ( )
16397 const error = validateName ( trimmedValue , false )
16498
16599 if ( error ) {
166- dispatch ( { type : "SET_ERROR" , payload : error } )
100+ setError ( error )
167101 return
168102 }
169103
170- if ( state . isRenaming && currentApiConfigName ) {
104+ if ( isRenaming && currentApiConfigName ) {
171105 if ( currentApiConfigName === trimmedValue ) {
172- dispatch ( { type : "CANCEL_EDIT" } )
106+ setIsRenaming ( false )
107+ setInputValue ( "" )
108+ setError ( null )
173109 return
174110 }
175111 onRenameConfig ( currentApiConfigName , trimmedValue )
176112 }
177113
178- dispatch ( { type : "CANCEL_EDIT" } )
114+ setIsRenaming ( false )
115+ setInputValue ( "" )
116+ setError ( null )
179117 }
180118
181119 const handleNewProfileSave = ( ) => {
182- const trimmedValue = state . newProfileName . trim ( )
120+ const trimmedValue = newProfileName . trim ( )
183121 const error = validateName ( trimmedValue , true )
184122
185123 if ( error ) {
186- dispatch ( { type : "SET_ERROR" , payload : error } )
124+ setError ( error )
187125 return
188126 }
189127
190128 onUpsertConfig ( trimmedValue )
191- dispatch ( { type : "CANCEL_CREATE" } )
129+ setIsCreating ( false )
130+ setNewProfileName ( "" )
131+ setError ( null )
192132 }
193133
194134 const handleDelete = ( ) => {
@@ -212,23 +152,24 @@ const ApiConfigManager = ({
212152 < span style = { { fontWeight : "500" } } > Configuration Profile</ span >
213153 </ label >
214154
215- { state . isRenaming ? (
155+ { isRenaming ? (
216156 < div
217157 data-testid = "rename-form"
218158 style = { { display : "flex" , gap : "4px" , alignItems : "center" , flexDirection : "column" } } >
219159 < div style = { { display : "flex" , gap : "4px" , alignItems : "center" , width : "100%" } } >
220160 < VSCodeTextField
221161 ref = { inputRef }
222- value = { state . inputValue }
162+ value = { inputValue }
223163 onInput = { ( e : unknown ) => {
224164 const target = e as { target : { value : string } }
225- dispatch ( { type : "SET_INPUT" , payload : target . target . value } )
165+ setInputValue ( target . target . value )
166+ setError ( null )
226167 } }
227168 placeholder = "Enter new name"
228169 style = { { flexGrow : 1 } }
229170 onKeyDown = { ( e : unknown ) => {
230171 const event = e as { key : string }
231- if ( event . key === "Enter" && state . inputValue . trim ( ) ) {
172+ if ( event . key === "Enter" && inputValue . trim ( ) ) {
232173 handleSave ( )
233174 } else if ( event . key === "Escape" ) {
234175 handleCancel ( )
@@ -237,7 +178,7 @@ const ApiConfigManager = ({
237178 />
238179 < VSCodeButton
239180 appearance = "icon"
240- disabled = { ! state . inputValue . trim ( ) }
181+ disabled = { ! inputValue . trim ( ) }
241182 onClick = { handleSave }
242183 title = "Save"
243184 style = { {
@@ -263,9 +204,9 @@ const ApiConfigManager = ({
263204 < span className = "codicon codicon-close" />
264205 </ VSCodeButton >
265206 </ div >
266- { state . error && (
207+ { error && (
267208 < p className = "text-red-500 text-sm mt-2" data-testid = "error-message" >
268- { state . error }
209+ { error }
269210 </ p >
270211 ) }
271212 </ div >
@@ -345,8 +286,18 @@ const ApiConfigManager = ({
345286 ) }
346287
347288 < Dialog
348- open = { state . isCreating }
349- onOpenChange = { ( open : boolean ) => dispatch ( { type : open ? "START_CREATE" : "CANCEL_CREATE" } ) }
289+ open = { isCreating }
290+ onOpenChange = { ( open : boolean ) => {
291+ if ( open ) {
292+ setIsCreating ( true )
293+ setNewProfileName ( "" )
294+ setError ( null )
295+ } else {
296+ setIsCreating ( false )
297+ setNewProfileName ( "" )
298+ setError ( null )
299+ }
300+ } }
350301 aria-labelledby = "new-profile-title" >
351302 < DialogContent className = "p-4 max-w-sm" >
352303 < h2 id = "new-profile-title" className = "text-lg font-semibold mb-4" >
@@ -355,39 +306,52 @@ const ApiConfigManager = ({
355306 < button
356307 className = "absolute right-4 top-4"
357308 aria-label = "Close dialog"
358- onClick = { ( ) => dispatch ( { type : "CANCEL_CREATE" } ) } >
309+ onClick = { ( ) => {
310+ setIsCreating ( false )
311+ setNewProfileName ( "" )
312+ setError ( null )
313+ } } >
359314 < span className = "codicon codicon-close" />
360315 </ button >
361316 < VSCodeTextField
362317 ref = { newProfileInputRef }
363- value = { state . newProfileName }
318+ value = { newProfileName }
364319 onInput = { ( e : unknown ) => {
365320 const target = e as { target : { value : string } }
366- dispatch ( { type : "SET_NEW_NAME" , payload : target . target . value } )
321+ setNewProfileName ( target . target . value )
322+ setError ( null )
367323 } }
368324 placeholder = "Enter profile name"
369325 style = { { width : "100%" } }
370326 onKeyDown = { ( e : unknown ) => {
371327 const event = e as { key : string }
372- if ( event . key === "Enter" && state . newProfileName . trim ( ) ) {
328+ if ( event . key === "Enter" && newProfileName . trim ( ) ) {
373329 handleNewProfileSave ( )
374330 } else if ( event . key === "Escape" ) {
375- dispatch ( { type : "CANCEL_CREATE" } )
331+ setIsCreating ( false )
332+ setNewProfileName ( "" )
333+ setError ( null )
376334 }
377335 } }
378336 />
379- { state . error && (
337+ { error && (
380338 < p className = "text-red-500 text-sm mt-2" data-testid = "error-message" >
381- { state . error }
339+ { error }
382340 </ p >
383341 ) }
384342 < div className = "flex justify-end gap-2 mt-4" >
385- < VSCodeButton appearance = "secondary" onClick = { ( ) => dispatch ( { type : "CANCEL_CREATE" } ) } >
343+ < VSCodeButton
344+ appearance = "secondary"
345+ onClick = { ( ) => {
346+ setIsCreating ( false )
347+ setNewProfileName ( "" )
348+ setError ( null )
349+ } } >
386350 Cancel
387351 </ VSCodeButton >
388352 < VSCodeButton
389353 appearance = "primary"
390- disabled = { ! state . newProfileName . trim ( ) }
354+ disabled = { ! newProfileName . trim ( ) }
391355 onClick = { handleNewProfileSave } >
392356 Create Profile
393357 </ VSCodeButton >
0 commit comments