Просмотр исходного кода

Change to useState to match the rest of the codebase

Roo Code 10 месяцев назад
Родитель
Сommit
b85ebbc89a
1 измененных файлов с 80 добавлено и 116 удалено
  1. 80 116
      webview-ui/src/components/settings/ApiConfigManager.tsx

+ 80 - 116
webview-ui/src/components/settings/ApiConfigManager.tsx

@@ -1,5 +1,5 @@
 import { VSCodeButton, VSCodeTextField } from "@vscode/webview-ui-toolkit/react"
-import { memo, useEffect, useReducer, useRef } from "react"
+import { memo, useEffect, useRef, useState } from "react"
 import { ApiConfigMeta } from "../../../../src/shared/ExtensionMessage"
 import { Dropdown } from "vscrui"
 import type { DropdownOption } from "vscrui"
@@ -14,86 +14,6 @@ interface ApiConfigManagerProps {
 	onUpsertConfig: (configName: string) => void
 }
 
-type State = {
-	isRenaming: boolean
-	isCreating: boolean
-	inputValue: string
-	newProfileName: string
-	error: string | null
-}
-
-type Action =
-	| { type: "START_RENAME"; payload: string }
-	| { type: "CANCEL_EDIT" }
-	| { type: "SET_INPUT"; payload: string }
-	| { type: "SET_NEW_NAME"; payload: string }
-	| { type: "START_CREATE" }
-	| { type: "CANCEL_CREATE" }
-	| { type: "SET_ERROR"; payload: string | null }
-	| { type: "RESET_STATE" }
-
-const initialState: State = {
-	isRenaming: false,
-	isCreating: false,
-	inputValue: "",
-	newProfileName: "",
-	error: null,
-}
-
-const reducer = (state: State, action: Action): State => {
-	switch (action.type) {
-		case "START_RENAME":
-			return {
-				...state,
-				isRenaming: true,
-				inputValue: action.payload,
-				error: null,
-			}
-		case "CANCEL_EDIT":
-			return {
-				...state,
-				isRenaming: false,
-				inputValue: "",
-				error: null,
-			}
-		case "SET_INPUT":
-			return {
-				...state,
-				inputValue: action.payload,
-				error: null,
-			}
-		case "SET_NEW_NAME":
-			return {
-				...state,
-				newProfileName: action.payload,
-				error: null,
-			}
-		case "START_CREATE":
-			return {
-				...state,
-				isCreating: true,
-				newProfileName: "",
-				error: null,
-			}
-		case "CANCEL_CREATE":
-			return {
-				...state,
-				isCreating: false,
-				newProfileName: "",
-				error: null,
-			}
-		case "SET_ERROR":
-			return {
-				...state,
-				error: action.payload,
-			}
-		case "RESET_STATE":
-			return initialState
-		default:
-			return state
-	}
-}
-
 const ApiConfigManager = ({
 	currentApiConfigName = "",
 	listApiConfigMeta = [],
@@ -102,7 +22,11 @@ const ApiConfigManager = ({
 	onRenameConfig,
 	onUpsertConfig,
 }: ApiConfigManagerProps) => {
-	const [state, dispatch] = useReducer(reducer, initialState)
+	const [isRenaming, setIsRenaming] = useState(false)
+	const [isCreating, setIsCreating] = useState(false)
+	const [inputValue, setInputValue] = useState("")
+	const [newProfileName, setNewProfileName] = useState("")
+	const [error, setError] = useState<string | null>(null)
 	const inputRef = useRef<any>(null)
 	const newProfileInputRef = useRef<any>(null)
 
@@ -127,68 +51,84 @@ const ApiConfigManager = ({
 
 	// Focus input when entering rename mode
 	useEffect(() => {
-		if (state.isRenaming) {
+		if (isRenaming) {
 			const timeoutId = setTimeout(() => inputRef.current?.focus(), 0)
 			return () => clearTimeout(timeoutId)
 		}
-	}, [state.isRenaming])
+	}, [isRenaming])
 
 	// Focus input when opening new dialog
 	useEffect(() => {
-		if (state.isCreating) {
+		if (isCreating) {
 			const timeoutId = setTimeout(() => newProfileInputRef.current?.focus(), 0)
 			return () => clearTimeout(timeoutId)
 		}
-	}, [state.isCreating])
+	}, [isCreating])
 
 	// Reset state when current profile changes
 	useEffect(() => {
-		dispatch({ type: "RESET_STATE" })
+		setIsRenaming(false)
+		setIsCreating(false)
+		setInputValue("")
+		setNewProfileName("")
+		setError(null)
 	}, [currentApiConfigName])
 
 	const handleAdd = () => {
-		dispatch({ type: "START_CREATE" })
+		setIsCreating(true)
+		setNewProfileName("")
+		setError(null)
 	}
 
 	const handleStartRename = () => {
-		dispatch({ type: "START_RENAME", payload: currentApiConfigName || "" })
+		setIsRenaming(true)
+		setInputValue(currentApiConfigName || "")
+		setError(null)
 	}
 
 	const handleCancel = () => {
-		dispatch({ type: "CANCEL_EDIT" })
+		setIsRenaming(false)
+		setInputValue("")
+		setError(null)
 	}
 
 	const handleSave = () => {
-		const trimmedValue = state.inputValue.trim()
+		const trimmedValue = inputValue.trim()
 		const error = validateName(trimmedValue, false)
 
 		if (error) {
-			dispatch({ type: "SET_ERROR", payload: error })
+			setError(error)
 			return
 		}
 
-		if (state.isRenaming && currentApiConfigName) {
+		if (isRenaming && currentApiConfigName) {
 			if (currentApiConfigName === trimmedValue) {
-				dispatch({ type: "CANCEL_EDIT" })
+				setIsRenaming(false)
+				setInputValue("")
+				setError(null)
 				return
 			}
 			onRenameConfig(currentApiConfigName, trimmedValue)
 		}
 
-		dispatch({ type: "CANCEL_EDIT" })
+		setIsRenaming(false)
+		setInputValue("")
+		setError(null)
 	}
 
 	const handleNewProfileSave = () => {
-		const trimmedValue = state.newProfileName.trim()
+		const trimmedValue = newProfileName.trim()
 		const error = validateName(trimmedValue, true)
 
 		if (error) {
-			dispatch({ type: "SET_ERROR", payload: error })
+			setError(error)
 			return
 		}
 
 		onUpsertConfig(trimmedValue)
-		dispatch({ type: "CANCEL_CREATE" })
+		setIsCreating(false)
+		setNewProfileName("")
+		setError(null)
 	}
 
 	const handleDelete = () => {
@@ -212,23 +152,24 @@ const ApiConfigManager = ({
 					<span style={{ fontWeight: "500" }}>Configuration Profile</span>
 				</label>
 
-				{state.isRenaming ? (
+				{isRenaming ? (
 					<div
 						data-testid="rename-form"
 						style={{ display: "flex", gap: "4px", alignItems: "center", flexDirection: "column" }}>
 						<div style={{ display: "flex", gap: "4px", alignItems: "center", width: "100%" }}>
 							<VSCodeTextField
 								ref={inputRef}
-								value={state.inputValue}
+								value={inputValue}
 								onInput={(e: unknown) => {
 									const target = e as { target: { value: string } }
-									dispatch({ type: "SET_INPUT", payload: target.target.value })
+									setInputValue(target.target.value)
+									setError(null)
 								}}
 								placeholder="Enter new name"
 								style={{ flexGrow: 1 }}
 								onKeyDown={(e: unknown) => {
 									const event = e as { key: string }
-									if (event.key === "Enter" && state.inputValue.trim()) {
+									if (event.key === "Enter" && inputValue.trim()) {
 										handleSave()
 									} else if (event.key === "Escape") {
 										handleCancel()
@@ -237,7 +178,7 @@ const ApiConfigManager = ({
 							/>
 							<VSCodeButton
 								appearance="icon"
-								disabled={!state.inputValue.trim()}
+								disabled={!inputValue.trim()}
 								onClick={handleSave}
 								title="Save"
 								style={{
@@ -263,9 +204,9 @@ const ApiConfigManager = ({
 								<span className="codicon codicon-close" />
 							</VSCodeButton>
 						</div>
-						{state.error && (
+						{error && (
 							<p className="text-red-500 text-sm mt-2" data-testid="error-message">
-								{state.error}
+								{error}
 							</p>
 						)}
 					</div>
@@ -345,8 +286,18 @@ const ApiConfigManager = ({
 				)}
 
 				<Dialog
-					open={state.isCreating}
-					onOpenChange={(open: boolean) => dispatch({ type: open ? "START_CREATE" : "CANCEL_CREATE" })}
+					open={isCreating}
+					onOpenChange={(open: boolean) => {
+						if (open) {
+							setIsCreating(true)
+							setNewProfileName("")
+							setError(null)
+						} else {
+							setIsCreating(false)
+							setNewProfileName("")
+							setError(null)
+						}
+					}}
 					aria-labelledby="new-profile-title">
 					<DialogContent className="p-4 max-w-sm">
 						<h2 id="new-profile-title" className="text-lg font-semibold mb-4">
@@ -355,39 +306,52 @@ const ApiConfigManager = ({
 						<button
 							className="absolute right-4 top-4"
 							aria-label="Close dialog"
-							onClick={() => dispatch({ type: "CANCEL_CREATE" })}>
+							onClick={() => {
+								setIsCreating(false)
+								setNewProfileName("")
+								setError(null)
+							}}>
 							<span className="codicon codicon-close" />
 						</button>
 						<VSCodeTextField
 							ref={newProfileInputRef}
-							value={state.newProfileName}
+							value={newProfileName}
 							onInput={(e: unknown) => {
 								const target = e as { target: { value: string } }
-								dispatch({ type: "SET_NEW_NAME", payload: target.target.value })
+								setNewProfileName(target.target.value)
+								setError(null)
 							}}
 							placeholder="Enter profile name"
 							style={{ width: "100%" }}
 							onKeyDown={(e: unknown) => {
 								const event = e as { key: string }
-								if (event.key === "Enter" && state.newProfileName.trim()) {
+								if (event.key === "Enter" && newProfileName.trim()) {
 									handleNewProfileSave()
 								} else if (event.key === "Escape") {
-									dispatch({ type: "CANCEL_CREATE" })
+									setIsCreating(false)
+									setNewProfileName("")
+									setError(null)
 								}
 							}}
 						/>
-						{state.error && (
+						{error && (
 							<p className="text-red-500 text-sm mt-2" data-testid="error-message">
-								{state.error}
+								{error}
 							</p>
 						)}
 						<div className="flex justify-end gap-2 mt-4">
-							<VSCodeButton appearance="secondary" onClick={() => dispatch({ type: "CANCEL_CREATE" })}>
+							<VSCodeButton
+								appearance="secondary"
+								onClick={() => {
+									setIsCreating(false)
+									setNewProfileName("")
+									setError(null)
+								}}>
 								Cancel
 							</VSCodeButton>
 							<VSCodeButton
 								appearance="primary"
-								disabled={!state.newProfileName.trim()}
+								disabled={!newProfileName.trim()}
 								onClick={handleNewProfileSave}>
 								Create Profile
 							</VSCodeButton>