- Enable all apps (Claude, Codex, Gemini) by default when adding MCP servers
- Improve config label with clearer wording: "Full JSON configuration or use [Config Wizard]"
- Add JSON format button to beautify configuration with 2-space indentation
- Update tests to reflect new default behavior
- Clean up redundant explicit prop passing
This provides a more streamlined experience by enabling all apps out of the box
and making it easier to format JSON configurations.
Complete the v3.7.0 MCP refactoring by updating the form layer to match
the unified architecture already implemented in data/service/API layers.
**Breaking Changes:**
- Remove confusing `appId` parameter from McpFormModal
- Replace with `defaultFormat` (json/toml) and `defaultEnabledApps` (array)
**Form Enhancements:**
- Add app enablement checkboxes (Claude/Codex/Gemini) directly in the form
- Smart defaults: new servers default to Claude enabled, editing preserves state
- Support "draft" mode: servers can be created without enabling any apps
**Architecture Improvements:**
- Eliminate semantic confusion: format selection separate from app targeting
- One-step workflow: configure and enable apps in single form submission
- Consistent with unified backend: `apps: { claude, codex, gemini }`
**Testing:**
- Update test mocks to use `useUpsertMcpServer` hook
- Add test case for creating servers with no apps enabled
- Fix parameter references from `appId` to `defaultFormat`
**i18n:**
- Add `mcp.form.enabledApps` translation (zh/en)
- Add `mcp.form.noAppsWarning` translation (zh/en)
This completes the MCP management refactoring, ensuring all layers
(data, service, API, UI) follow the same unified architecture pattern.
This commit addresses parameter naming inconsistencies caused by Tauri v2's
requirement for camelCase parameter names in IPC commands.
Backend changes (Rust):
- Updated all command parameters from snake_case to camelCase
- Commands affected:
* provider.rs: providerId (×4), timeoutSecs
* import_export.rs: filePath (×2), defaultName
* config.rs: defaultPath
- Added #[allow(non_snake_case)] attributes for camelCase parameters
- Removed unused QueryUsageParams struct
Frontend changes (TypeScript):
- Removed redundant snake_case parameters from all invoke() calls
- Updated API files:
* usage.ts: removed debug logs, unified to providerId
* vscode.ts: updated 8 functions (providerId, timeoutSecs, filePath, defaultName)
* settings.ts: updated 4 functions (defaultPath, filePath, defaultName)
- Ensured all parameters now use camelCase exclusively
Test updates:
- Updated MSW handlers to accept both old and new parameter formats during transition
- Added i18n mock compatibility for tests
Root cause:
The issue stemmed from Tauri v2 strictly requiring camelCase for command
parameters, while the codebase was using snake_case. This caused parameters
like 'provider_id' to not be recognized by the backend, resulting in
"missing providerId parameter" errors.
BREAKING CHANGE: All Tauri command invocations now require camelCase parameters.
Any external tools or scripts calling these commands must be updated accordingly.
Fixes: Usage query always failing with "missing providerId" error
Fixes: Custom endpoint management not receiving provider ID
Fixes: Import/export dialogs not respecting default paths
Rename `AppType` to `AppId` across the entire frontend codebase to better
reflect its purpose as an application identifier rather than a type category.
This aligns frontend naming with backend command parameter conventions.
Changes:
- Rename type `AppType` to `AppId` in src/lib/api/types.ts
- Remove `AppType` export from src/lib/api/index.ts
- Update all component props from `appType` to `appId` (43 files)
- Update all variable names from `appType` to `appId`
- Synchronize documentation (CHANGELOG, refactoring plans)
- Update test files and MSW mocks
BREAKING CHANGE: `AppType` type is no longer exported. Use `AppId` instead.
All component props have been renamed from `appType` to `appId`.
Fixed two critical data loss bugs where user-added custom endpoints were discarded:
1. **AddProviderDialog**: Form submission ignored values.meta from ProviderForm and
re-inferred URLs only from presets/config, causing loss of endpoints added via
speed test modal. Now prioritizes form-collected meta and uses fallback inference
only when custom_endpoints is missing.
2. **ProviderForm**: Edit mode always returned initialData.meta, discarding any
changes made in the speed test modal. Now uses mergeProviderMeta to properly
merge customEndpointsMap with existing meta fields.
Changes:
- Extract mergeProviderMeta utility to handle meta field merging logic
- Preserve other meta fields (e.g., usage_script) during endpoint updates
- Unify new/edit code paths to use consistent meta handling
- Add comprehensive unit tests for meta merging scenarios
- Add integration tests for AddProviderDialog submission flow
Impact:
- Third-party and custom providers can now reliably manage multiple endpoints
- Edit operations correctly reflect user modifications
- No data loss for existing meta fields like usage_script
- Add vitest/globals to tsconfig.json types array to provide type
definitions for global test functions (describe, it, expect, vi)
- Fix vi.fn type parameter in useDirectorySettings.test.tsx from
<[], Promise<string>> to <() => Promise<string>>
- Remove unused setMcpConfig import from MSW handlers
- Add type assertions for mock.calls access in McpFormModal tests
to resolve union type inference issues
This ensures pnpm typecheck passes without errors while maintaining
test functionality with vitest globals: true configuration.
## McpFormModal Component Tests (+5 tests)
### Infrastructure Improvements
- Enhance McpWizardModal mock from null to functional mock with testable onApply callback
- Refactor renderForm helper to support custom onSave/onClose mock injection
- Add McpServer type import for type-safe test data
### New Test Cases
1. **Wizard Integration**: Verify wizard generates config and auto-fills ID + JSON fields
- Click "Use Wizard" → Apply → Form fields populated with wizard-id and config
- Uses act() wrapper for React 18 async state updates
2. **TOML Auto-extraction (Codex)**: Test TOML → JSON conversion with ID extraction
- Parse `[mcp.servers.demo]` → auto-fill ID as "demo"
- Verify server object correctly parsed from TOML format
- Codex-specific feature for config.toml compatibility
3. **TOML Validation Error**: Test missing required field handling
- TOML with type="stdio" but no command → block submit
- Display localized error toast: mcp.error.idRequired (3s duration)
4. **Edit Mode Immutability**: Verify ID field disabled during edit
- ID input has disabled attribute and keeps original value
- Config updates applied while enabled state preserved
- syncOtherSide defaults to false in edit mode
5. **Error Recovery**: Test save failure button state restoration
- Inject failing onSave mock → trigger error
- Verify toast error displays translated message
- Submit button disabled state resets to false for retry
## useMcpActions Hook Tests (+2 tests)
### New API Mocks
- Add syncEnabledToClaude and syncEnabledToCodex mock functions
### New Test Cases
1. **Backend Error Message Mapping**: Map Chinese error to i18n key
- Backend: "stdio 类型的 MCP 服务器必须包含 command 字段"
- Frontend: mcp.error.commandRequired (6s toast duration)
2. **Cross-app Sync Logic**: Verify conditional sync behavior
- claude → claude: setEnabled called, syncEnabledToClaude NOT called
- Validates sync only occurs when crossing app types
## Minor Changes
- McpPanel.test.tsx: Add trailing newline (formatter compliance)
## Test Coverage
- Test files: 17 (unchanged)
- Total tests: 112 → 119 (+7, +6.3%)
- Execution time: 3.20s
- All 119 tests passing ✅
## MSW Infrastructure Enhancement
- Add 5 MCP API handlers to tests/msw/handlers.ts:
- get_mcp_config: Fetch MCP configuration for app type
- import_mcp_from_claude/codex: Mock import operations (returns count: 1)
- set_mcp_enabled: Toggle MCP server enabled state
- upsert_mcp_server_in_config: Create/update MCP server
- delete_mcp_server_in_config: Remove MCP server
- Add MCP state management to tests/msw/state.ts:
- McpConfigState type with per-app server storage
- Default test data (stdio server for Claude, http server for Codex)
- CRUD functions: getMcpConfig, setMcpServerEnabled, upsertMcpServer, deleteMcpServer
- Immutable state operations with deep cloning
## McpFormModal Component Tests (4 tests)
- Test preset application: Verify ID and config JSON auto-fill from preset selection
- Test conflict detection: Async validation shows warning when syncing to conflicting ID
- Test field sanitization: Verify trim whitespace, split tags, clean URLs before save
- Test validation errors: Block submit and show toast error for invalid stdio config (missing command)
## McpPanel Integration Tests (3 tests)
- Test toggle enabled state: Click toggle button triggers useMcpActions.toggleEnabled with correct params
- Test create server flow: Open form → submit → saveServer called with syncOtherSide option
- Test delete server flow: Click delete → confirm dialog → deleteServer called with ID
## Test Utilities
- Add createTestQueryClient helper with retry: false for faster test execution
## Test Coverage
- Test files: 15 → 17 (+2)
- Total tests: 105 → 112 (+6.7%)
- All 112 tests passing
- Execution time: 3.15s
Enhanced SettingsDialog component test coverage:
- Add test for import/export status reset on dialog open
- Add test for onImportSuccess callback propagation to hook
- Add test for postponing restart flow (restart later button)
- Add test for directory management callbacks (browse/reset/change)
- Expand existing test to cover export, import, and clear actions
- Fix type safety issues (avoid 'as any', use type guards)
New App.test.tsx integration test:
- Add comprehensive end-to-end test for main App component
- Test settings dialog with import success callback and tray menu update
- Test app switcher between Claude and Codex
- Test provider CRUD operations (add, edit, delete, duplicate)
- Test usage script modal workflow
- Test external website link opening
- Use vi.hoisted() pattern for centralized mock management
Technical improvements:
- Remove two environment-dependent tests (DEV flag) that required 'as any'
- Use proper type guards for optional callback invocation
- Clean up unused mock variables (switchProviderMock, onImportSuccessMock, refetchPromise)
- Simplify useProviderActions mock to avoid spread argument type error
Test results: 50 tests passing across 8 test files
Add component tests for ImportExportSection and SettingsDialog with full coverage of UI interactions, state management, and async workflows.
ImportExportSection.test.tsx (5 tests):
- Verify button states based on file selection
- Test import/export/clear interactions
- Validate loading, success, and error UI states
SettingsDialog.test.tsx (5 tests):
- Test loading state rendering
- Verify tab navigation and child component callbacks
- Validate save/cancel workflows with cleanup
- Test restart prompt and immediate restart flow
- Use Context Provider pattern to mock Tabs component
- Mock 7 child components for isolation
Test patterns demonstrated:
- Complex component isolation with deep mocking
- Context Provider mocking for UI library components
- Async workflow validation with waitFor
- Multi-hook mocking (useSettings + useImportExport)
All 45 tests passing (7 files, 1.13s execution time)
Add extensive unit and component tests covering import/export, settings,
and provider list functionality, advancing to Sprint 2 of test development.
Hook Tests:
- useImportExport (11 tests):
* File selection success/failure flows
* Import process with success/failure/exception paths
* Export functionality with error handling
* User cancellation scenarios
* State management (clear selection, reset status)
* Fake timers for async callback testing
- useSettingsForm (5 tests):
* Settings normalization on initialization
* Language persistence from localStorage
* Field updates with language sync
* Reset functionality with initial language restoration
* Optimization to avoid redundant language changes
Component Tests:
- ProviderList (3 tests):
* Loading state with skeleton placeholders
* Empty state with create callback
* Render order from useDragSort with action callbacks
* Props pass-through (isCurrent, isEditMode, dragHandleProps)
* Mock ProviderCard to isolate component under test
Technical Highlights:
- Fake timers (vi.useFakeTimers) for async control
- i18n mock with changeLanguage spy
- Partial mock of @dnd-kit/sortable using vi.importActual
- ProviderCard render spy for props verification
- Comprehensive error handling coverage
Test Coverage:
✓ 19 new test cases (11 + 5 + 3)
✓ Total: 35 tests passing
✓ Execution time: 865ms
✓ TypeScript: 0 errors
Related: Import/export, settings management, provider list rendering
Sprint Progress: Sprint 1 complete, Sprint 2 in progress (component tests)