fix: copy mcp config through native clipboard

This commit is contained in:
lucaronin
2026-04-30 17:45:49 +02:00
parent fbb0927401
commit d3a577b488
8 changed files with 118 additions and 4 deletions

View File

@@ -6,11 +6,16 @@ vi.mock('@tauri-apps/api/core', () => ({
invoke: vi.fn(),
}))
const runtimeMock = vi.hoisted(() => ({
isTauri: false,
}))
vi.mock('../mock-tauri', () => ({
isTauri: () => false,
isTauri: () => runtimeMock.isTauri,
mockInvoke: vi.fn(),
}))
const { invoke } = await import('@tauri-apps/api/core') as { invoke: ReturnType<typeof vi.fn> }
const { mockInvoke } = await import('../mock-tauri') as { mockInvoke: ReturnType<typeof vi.fn> }
function mockCommands(handlers: Partial<Record<string, unknown>>) {
@@ -83,6 +88,7 @@ async function runMutationScenario({
describe('useMcpStatus', () => {
beforeEach(() => {
runtimeMock.isTauri = false
vi.clearAllMocks()
mockClipboard()
})
@@ -212,4 +218,30 @@ describe('useMcpStatus', () => {
expect(writeText).toHaveBeenCalledWith(snippet)
expect(onToast).toHaveBeenCalledWith('Tolaria MCP config copied to clipboard')
})
it('uses the native clipboard command inside the Tauri app', async () => {
runtimeMock.isTauri = true
const writeText = mockClipboard()
const onToast = vi.fn()
const snippet = JSON.stringify({ mcpServers: { tolaria: { type: 'stdio' } } })
invoke.mockImplementation((command: string) => {
if (command === 'check_mcp_status') return Promise.resolve('not_installed')
if (command === 'get_mcp_config_snippet') return Promise.resolve(snippet)
if (command === 'copy_text_to_clipboard') return Promise.resolve(null)
return Promise.resolve(null)
})
const { result } = renderSubject(onToast)
await waitFor(() => {
expect(result.current.mcpStatus).toBe('not_installed')
})
await act(async () => {
await expect(result.current.copyMcpConfig()).resolves.toBe(true)
})
expect(invoke).toHaveBeenCalledWith('copy_text_to_clipboard', { text: snippet })
expect(writeText).not.toHaveBeenCalled()
expect(onToast).toHaveBeenCalledWith('Tolaria MCP config copied to clipboard')
})
})

View File

@@ -7,6 +7,7 @@ export type McpStatus = 'checking' | 'installed' | 'not_installed'
type ManualConfigSnippet = string
type McpCommand =
| 'check_mcp_status'
| 'copy_text_to_clipboard'
| 'get_mcp_config_snippet'
| 'register_mcp_tools'
| 'remove_mcp_tools'
@@ -72,6 +73,11 @@ function visibleManualConfig(
}
async function writeClipboardText(value: ManualConfigSnippet, t: Translator): Promise<void> {
if (isTauri()) {
await tauriCall('copy_text_to_clipboard', { text: value })
return
}
if (!navigator.clipboard?.writeText) {
throw new Error(t('mcp.error.clipboardUnavailable'))
}

View File

@@ -194,6 +194,7 @@ describe('mockHandlers additional coverage', () => {
expect(mockHandlers.migrate_is_a_to_type()).toBe(0)
expect(mockHandlers.register_mcp_tools()).toBe('registered')
expect(mockHandlers.check_mcp_status()).toBe('installed')
expect(mockHandlers.copy_text_to_clipboard()).toBeNull()
expect(mockHandlers.reinit_telemetry()).toBeNull()
expect(mockHandlers.stream_claude_chat()).toBe('mock-session')
expect(mockHandlers.stream_ai_agent()).toBeNull()

View File

@@ -503,6 +503,7 @@ export const mockHandlers: Record<string, (args: any) => any> = {
},
},
}, null, 2),
copy_text_to_clipboard: () => null,
sync_mcp_bridge_vault: (args: { vaultPath?: string | null }) => args.vaultPath ? 'started' : 'stopped',
repair_vault: (): string => {
mockVaultAiGuidanceStatus = {