Explorar o código

Just make a copy when adding a new profile

Matt Rubens hai 1 ano
pai
achega
11612caac0

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

@@ -36,9 +36,9 @@ const ApiConfigManager = ({
         setInputValue("");
     }, [currentApiConfigName]);
 
-    const handleStartNew = () => {
-        setEditState('new');
-        setInputValue("");
+    const handleAdd = () => {
+        const newConfigName = currentApiConfigName + " (copy)";
+        onUpsertConfig(newConfigName);
     };
 
     const handleStartRename = () => {
@@ -162,7 +162,7 @@ const ApiConfigManager = ({
                             </select>
                             <VSCodeButton
                                 appearance="icon"
-                                onClick={handleStartNew}
+                                onClick={handleAdd}
                                 title="Add profile"
                                 style={{
                                     padding: 0,

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

@@ -0,0 +1,154 @@
+import { render, screen, fireEvent } from '@testing-library/react';
+import '@testing-library/jest-dom';
+import ApiConfigManager from '../ApiConfigManager';
+
+// Mock VSCode components
+jest.mock('@vscode/webview-ui-toolkit/react', () => ({
+  VSCodeButton: ({ children, onClick, title, disabled }: any) => (
+    <button onClick={onClick} title={title} disabled={disabled}>
+      {children}
+    </button>
+  ),
+  VSCodeTextField: ({ value, onInput, placeholder }: any) => (
+    <input
+      value={value}
+      onChange={e => onInput(e)}
+      placeholder={placeholder}
+      ref={undefined} // Explicitly set ref to undefined to avoid warning
+    />
+  ),
+}));
+
+describe('ApiConfigManager', () => {
+  const mockOnSelectConfig = jest.fn();
+  const mockOnDeleteConfig = jest.fn();
+  const mockOnRenameConfig = jest.fn();
+  const mockOnUpsertConfig = jest.fn();
+
+  const defaultProps = {
+    currentApiConfigName: 'Default Config',
+    listApiConfigMeta: [
+      { name: 'Default Config' },
+      { name: 'Another Config' }
+    ],
+    onSelectConfig: mockOnSelectConfig,
+    onDeleteConfig: mockOnDeleteConfig,
+    onRenameConfig: mockOnRenameConfig,
+    onUpsertConfig: mockOnUpsertConfig,
+  };
+
+  beforeEach(() => {
+    jest.clearAllMocks();
+  });
+
+  it('immediately creates a copy when clicking add button', () => {
+    render(<ApiConfigManager {...defaultProps} />);
+
+    // Find and click the add button
+    const addButton = screen.getByTitle('Add profile');
+    fireEvent.click(addButton);
+
+    // Verify that onUpsertConfig was called with the correct name
+    expect(mockOnUpsertConfig).toHaveBeenCalledTimes(1);
+    expect(mockOnUpsertConfig).toHaveBeenCalledWith('Default Config (copy)');
+  });
+
+  it('creates copy with correct name when current config has spaces', () => {
+    render(
+      <ApiConfigManager
+        {...defaultProps}
+        currentApiConfigName="My Test Config"
+      />
+    );
+
+    const addButton = screen.getByTitle('Add profile');
+    fireEvent.click(addButton);
+
+    expect(mockOnUpsertConfig).toHaveBeenCalledWith('My Test Config (copy)');
+  });
+
+  it('handles empty current config name gracefully', () => {
+    render(
+      <ApiConfigManager
+        {...defaultProps}
+        currentApiConfigName=""
+      />
+    );
+
+    const addButton = screen.getByTitle('Add profile');
+    fireEvent.click(addButton);
+
+    expect(mockOnUpsertConfig).toHaveBeenCalledWith(' (copy)');
+  });
+
+  it('allows renaming the current config', () => {
+    render(<ApiConfigManager {...defaultProps} />);
+    
+    // Start rename
+    const renameButton = screen.getByTitle('Rename profile');
+    fireEvent.click(renameButton);
+
+    // Find input and enter new name
+    const input = screen.getByDisplayValue('Default Config');
+    fireEvent.input(input, { target: { value: 'New Name' } });
+
+    // Save
+    const saveButton = screen.getByTitle('Save');
+    fireEvent.click(saveButton);
+
+    expect(mockOnRenameConfig).toHaveBeenCalledWith('Default Config', 'New Name');
+  });
+
+  it('allows selecting a different config', () => {
+    render(<ApiConfigManager {...defaultProps} />);
+    
+    const select = screen.getByRole('combobox');
+    fireEvent.change(select, { target: { value: 'Another Config' } });
+
+    expect(mockOnSelectConfig).toHaveBeenCalledWith('Another Config');
+  });
+
+  it('allows deleting the current config when not the only one', () => {
+    render(<ApiConfigManager {...defaultProps} />);
+    
+    const deleteButton = screen.getByTitle('Delete profile');
+    expect(deleteButton).not.toBeDisabled();
+    
+    fireEvent.click(deleteButton);
+    expect(mockOnDeleteConfig).toHaveBeenCalledWith('Default Config');
+  });
+
+  it('disables delete button when only one config exists', () => {
+    render(
+      <ApiConfigManager
+        {...defaultProps}
+        listApiConfigMeta={[{ name: 'Default Config' }]}
+      />
+    );
+    
+    const deleteButton = screen.getByTitle('Cannot delete the only profile');
+    expect(deleteButton).toHaveAttribute('disabled');
+  });
+
+  it('cancels rename operation when clicking cancel', () => {
+    render(<ApiConfigManager {...defaultProps} />);
+    
+    // Start rename
+    const renameButton = screen.getByTitle('Rename profile');
+    fireEvent.click(renameButton);
+
+    // Find input and enter new name
+    const input = screen.getByDisplayValue('Default Config');
+    fireEvent.input(input, { target: { value: 'New Name' } });
+
+    // Cancel
+    const cancelButton = screen.getByTitle('Cancel');
+    fireEvent.click(cancelButton);
+
+    // Verify rename was not called
+    expect(mockOnRenameConfig).not.toHaveBeenCalled();
+    
+    // Verify we're back to normal view
+    expect(screen.queryByDisplayValue('New Name')).not.toBeInTheDocument();
+  });
+});