Skip to content

Commit b85ebbc

Browse files
author
Roo Code
committed
Change to useState to match the rest of the codebase
1 parent 85dacb0 commit b85ebbc

File tree

1 file changed

+80
-116
lines changed

1 file changed

+80
-116
lines changed

webview-ui/src/components/settings/ApiConfigManager.tsx

Lines changed: 80 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { VSCodeButton, VSCodeTextField } from "@vscode/webview-ui-toolkit/react"
2-
import { memo, useEffect, useReducer, useRef } from "react"
2+
import { memo, useEffect, useRef, useState } from "react"
33
import { ApiConfigMeta } from "../../../../src/shared/ExtensionMessage"
44
import { Dropdown } from "vscrui"
55
import 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-
9717
const 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

Comments
 (0)