Skip to content

Commit 38eaff8

Browse files
committed
refactor: improve API configuration management
- Rename onUpsertConfig to onDuplicateConfig for clarity - Add dedicated functions in ExtensionStateContext for API config operations - Update tests to match new function names and behavior - Add initial memory bank documentation structure
1 parent d6ebfb9 commit 38eaff8

File tree

4 files changed

+60
-29
lines changed

4 files changed

+60
-29
lines changed

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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ interface ApiConfigManagerProps {
88
onSelectConfig: (configName: string) => void
99
onDeleteConfig: (configName: string) => void
1010
onRenameConfig: (oldName: string, newName: string) => void
11-
onUpsertConfig: (configName: string) => void
11+
onDuplicateConfig: (configName: string) => void
1212
}
1313

1414
const ApiConfigManager = ({
@@ -17,7 +17,7 @@ const ApiConfigManager = ({
1717
onSelectConfig,
1818
onDeleteConfig,
1919
onRenameConfig,
20-
onUpsertConfig,
20+
onDuplicateConfig,
2121
}: ApiConfigManagerProps) => {
2222
const [editState, setEditState] = useState<"new" | "rename" | null>(null)
2323
const [inputValue, setInputValue] = useState("")
@@ -36,9 +36,9 @@ const ApiConfigManager = ({
3636
setInputValue("")
3737
}, [currentApiConfigName])
3838

39-
const handleAdd = () => {
39+
const handleDuplicate = () => {
4040
const newConfigName = currentApiConfigName + " (copy)"
41-
onUpsertConfig(newConfigName)
41+
onDuplicateConfig(newConfigName)
4242
}
4343

4444
const handleStartRename = () => {
@@ -56,7 +56,7 @@ const ApiConfigManager = ({
5656
if (!trimmedValue) return
5757

5858
if (editState === "new") {
59-
onUpsertConfig(trimmedValue)
59+
onDuplicateConfig(trimmedValue)
6060
} else if (editState === "rename" && currentApiConfigName) {
6161
if (currentApiConfigName !== trimmedValue) {
6262
onRenameConfig(currentApiConfigName, trimmedValue)
@@ -159,7 +159,7 @@ const ApiConfigManager = ({
159159
</select>
160160
<VSCodeButton
161161
appearance="icon"
162-
onClick={handleAdd}
162+
onClick={handleDuplicate}
163163
title="Add profile"
164164
style={{
165165
padding: 0,

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

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ const SettingsView = ({ onDone }: SettingsViewProps) => {
5353
listApiConfigMeta,
5454
experimentalDiffStrategy,
5555
setExperimentalDiffStrategy,
56+
renameApiConfiguration,
57+
duplicateApiConfig,
5658
} = useExtensionState()
5759
const [apiErrorMessage, setApiErrorMessage] = useState<string | undefined>(undefined)
5860
const [modelIdErrorMessage, setModelIdErrorMessage] = useState<string | undefined>(undefined)
@@ -172,18 +174,10 @@ const SettingsView = ({ onDone }: SettingsViewProps) => {
172174
})
173175
}}
174176
onRenameConfig={(oldName: string, newName: string) => {
175-
vscode.postMessage({
176-
type: "renameApiConfiguration",
177-
values: { oldName, newName },
178-
apiConfiguration,
179-
})
177+
renameApiConfiguration(oldName, newName)
180178
}}
181-
onUpsertConfig={(configName: string) => {
182-
vscode.postMessage({
183-
type: "upsertApiConfiguration",
184-
text: configName,
185-
apiConfiguration,
186-
})
179+
onDuplicateConfig={(configName: string) => {
180+
duplicateApiConfig(configName)
187181
}}
188182
/>
189183
<ApiOptions apiErrorMessage={apiErrorMessage} modelIdErrorMessage={modelIdErrorMessage} />

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

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,18 @@ describe("ApiConfigManager", () => {
2323
const mockOnSelectConfig = jest.fn()
2424
const mockOnDeleteConfig = jest.fn()
2525
const mockOnRenameConfig = jest.fn()
26-
const mockOnUpsertConfig = jest.fn()
26+
const mockOnDuplicateConfig = jest.fn()
2727

2828
const defaultProps = {
2929
currentApiConfigName: "Default Config",
30-
listApiConfigMeta: [{ name: "Default Config" }, { name: "Another Config" }],
30+
listApiConfigMeta: [
31+
{ name: "Default Config", id: "default" },
32+
{ name: "Another Config", id: "another" },
33+
],
3134
onSelectConfig: mockOnSelectConfig,
3235
onDeleteConfig: mockOnDeleteConfig,
3336
onRenameConfig: mockOnRenameConfig,
34-
onUpsertConfig: mockOnUpsertConfig,
37+
onDuplicateConfig: mockOnDuplicateConfig,
3538
}
3639

3740
beforeEach(() => {
@@ -45,9 +48,9 @@ describe("ApiConfigManager", () => {
4548
const addButton = screen.getByTitle("Add profile")
4649
fireEvent.click(addButton)
4750

48-
// Verify that onUpsertConfig was called with the correct name
49-
expect(mockOnUpsertConfig).toHaveBeenCalledTimes(1)
50-
expect(mockOnUpsertConfig).toHaveBeenCalledWith("Default Config (copy)")
51+
// Verify that onDuplicateConfig was called with the correct name
52+
expect(mockOnDuplicateConfig).toHaveBeenCalledTimes(1)
53+
expect(mockOnDuplicateConfig).toHaveBeenCalledWith("Default Config (copy)")
5154
})
5255

5356
it("creates copy with correct name when current config has spaces", () => {
@@ -56,7 +59,7 @@ describe("ApiConfigManager", () => {
5659
const addButton = screen.getByTitle("Add profile")
5760
fireEvent.click(addButton)
5861

59-
expect(mockOnUpsertConfig).toHaveBeenCalledWith("My Test Config (copy)")
62+
expect(mockOnDuplicateConfig).toHaveBeenCalledWith("My Test Config (copy)")
6063
})
6164

6265
it("handles empty current config name gracefully", () => {
@@ -65,7 +68,7 @@ describe("ApiConfigManager", () => {
6568
const addButton = screen.getByTitle("Add profile")
6669
fireEvent.click(addButton)
6770

68-
expect(mockOnUpsertConfig).toHaveBeenCalledWith(" (copy)")
71+
expect(mockOnDuplicateConfig).toHaveBeenCalledWith(" (copy)")
6972
})
7073

7174
it("allows renaming the current config", () => {
@@ -106,7 +109,7 @@ describe("ApiConfigManager", () => {
106109
})
107110

108111
it("disables delete button when only one config exists", () => {
109-
render(<ApiConfigManager {...defaultProps} listApiConfigMeta={[{ name: "Default Config" }]} />)
112+
render(<ApiConfigManager {...defaultProps} listApiConfigMeta={[{ name: "Default Config", id: "default" }]} />)
110113

111114
const deleteButton = screen.getByTitle("Cannot delete the only profile")
112115
expect(deleteButton).toHaveAttribute("disabled")

webview-ui/src/context/ExtensionStateContext.tsx

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ export interface ExtensionStateContextType extends ExtensionState {
2626
mcpServers: McpServer[]
2727
filePaths: string[]
2828
setApiConfiguration: (config: ApiConfiguration) => void
29+
renameApiConfiguration: (oldName: string, newName: string) => void
30+
duplicateApiConfig: (configName: string) => void
2931
setCustomInstructions: (value?: string) => void
3032
setAlwaysAllowReadOnly: (value: boolean) => void
3133
setAlwaysAllowWrite: (value: boolean) => void
@@ -114,8 +116,26 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
114116
const [openAiModels, setOpenAiModels] = useState<string[]>([])
115117
const [mcpServers, setMcpServers] = useState<McpServer[]>([])
116118

119+
const renameApiConfiguration = useCallback(
120+
(oldName: string, newName: string) =>
121+
setState((currentState) => {
122+
vscode.postMessage({
123+
type: "renameApiConfiguration",
124+
values: { oldName, newName },
125+
apiConfiguration: currentState.apiConfiguration,
126+
})
127+
128+
return currentState
129+
}),
130+
[],
131+
)
132+
117133
const setListApiConfigMeta = useCallback(
118-
(value: ApiConfigMeta[]) => setState((prevState) => ({ ...prevState, listApiConfigMeta: value })),
134+
(value: ApiConfigMeta[]) =>
135+
setState((prevState) => ({
136+
...prevState,
137+
listApiConfigMeta: value,
138+
})),
119139
[],
120140
)
121141

@@ -126,7 +146,18 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
126146
text: currentState.currentApiConfigName,
127147
apiConfiguration: apiConfig,
128148
})
129-
return currentState // No state update needed
149+
return currentState
150+
})
151+
}, [])
152+
153+
const duplicateApiConfig = useCallback((configName: string) => {
154+
setState((currentState) => {
155+
vscode.postMessage({
156+
type: "upsertApiConfiguration",
157+
text: configName,
158+
apiConfiguration: currentState.apiConfiguration,
159+
})
160+
return currentState
130161
})
131162
}, [])
132163

@@ -138,7 +169,8 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
138169
text: currentState.currentApiConfigName,
139170
apiConfiguration: { ...currentState.apiConfiguration, [field]: event.target.value },
140171
})
141-
return currentState // No state update needed
172+
173+
return currentState
142174
})
143175
},
144176
[],
@@ -278,6 +310,8 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
278310
setAutoApprovalEnabled: (value) => setState((prevState) => ({ ...prevState, autoApprovalEnabled: value })),
279311
handleInputChange,
280312
setCustomModes: (value) => setState((prevState) => ({ ...prevState, customModes: value })),
313+
renameApiConfiguration,
314+
duplicateApiConfig,
281315
}
282316

283317
return <ExtensionStateContext.Provider value={contextValue}>{children}</ExtensionStateContext.Provider>

0 commit comments

Comments
 (0)