diff --git a/src/components/Draft/DraftTab.tsx b/src/components/Draft/DraftTab.tsx index f6fd95c..a6c246d 100644 --- a/src/components/Draft/DraftTab.tsx +++ b/src/components/Draft/DraftTab.tsx @@ -5,6 +5,7 @@ import { useImperativeHandle, useMemo, } from "react"; +import { auditResponseCopyOverride, exportDraft } from "./draftTauriCommands"; import { DraftResponsePanel } from "./DraftResponsePanel"; import { InputPanel } from "./InputPanel"; import { DiagnosisPanel, TreeResult } from "./DiagnosisPanel"; @@ -529,6 +530,8 @@ export const DraftTab = forwardRef( streamingText, cancelGeneration, saveAsTemplate, + auditResponseCopyOverride, + exportDraft, logEvent, setResponse, setOriginalResponse, diff --git a/src/components/Draft/draftTauriCommands.ts b/src/components/Draft/draftTauriCommands.ts new file mode 100644 index 0000000..3aec346 --- /dev/null +++ b/src/components/Draft/draftTauriCommands.ts @@ -0,0 +1,22 @@ +import { invoke } from "@tauri-apps/api/core"; + +interface AuditResponseCopyOverrideParams { + reason: string; + confidenceMode: string | null; + sourcesCount: number; +} + +export function auditResponseCopyOverride( + params: AuditResponseCopyOverrideParams, +): Promise { + return invoke("audit_response_copy_override", { ...params }); +} + +interface ExportDraftParams { + responseText: string; + format: "Markdown"; +} + +export function exportDraft(params: ExportDraftParams): Promise { + return invoke("export_draft", { ...params }); +} diff --git a/src/components/Draft/useResponseActions.test.ts b/src/components/Draft/useResponseActions.test.ts index 00ce133..aaf5a9f 100644 --- a/src/components/Draft/useResponseActions.test.ts +++ b/src/components/Draft/useResponseActions.test.ts @@ -1,13 +1,6 @@ // @vitest-environment jsdom import { act, renderHook } from "@testing-library/react"; import { beforeEach, describe, expect, it, vi } from "vitest"; - -const invokeMock = vi.fn(); -vi.mock("@tauri-apps/api/core", () => ({ - invoke: (command: string, payload?: Record) => - invokeMock(command, payload), -})); - import { useResponseActions } from "./useResponseActions"; type HookOptions = Parameters[0]; @@ -16,8 +9,6 @@ const writeText = vi.fn().mockResolvedValue(undefined); beforeEach(() => { writeText.mockClear(); - invokeMock.mockReset(); - invokeMock.mockResolvedValue(true); Object.defineProperty(navigator, "clipboard", { value: { writeText }, configurable: true, @@ -38,6 +29,8 @@ function makeOptions(overrides: Partial = {}): HookOptions { cancelGeneration: vi.fn(), saveAsTemplate: vi.fn().mockResolvedValue("tpl-1"), + auditResponseCopyOverride: vi.fn().mockResolvedValue(undefined), + exportDraft: vi.fn().mockResolvedValue(true), logEvent: vi.fn(), setResponse: vi.fn(), @@ -62,10 +55,7 @@ describe("useResponseActions", () => { }); expect(writeText).toHaveBeenCalledWith("generated text"); - expect(invokeMock).not.toHaveBeenCalledWith( - "audit_response_copy_override", - expect.anything(), - ); + expect(options.auditResponseCopyOverride).not.toHaveBeenCalled(); expect(options.setHandoffTouched).toHaveBeenCalledWith(true); expect(options.onShowSuccess).toHaveBeenCalledWith( "Response copied to clipboard", @@ -84,7 +74,7 @@ describe("useResponseActions", () => { }); expect(promptSpy).toHaveBeenCalled(); - expect(invokeMock).toHaveBeenCalledWith("audit_response_copy_override", { + expect(options.auditResponseCopyOverride).toHaveBeenCalledWith({ reason: "ops needs this now", confidenceMode: "answer", sourcesCount: 0, @@ -115,7 +105,7 @@ describe("useResponseActions", () => { await result.current.handleExportResponse(); }); - expect(invokeMock).toHaveBeenCalledWith("export_draft", { + expect(options.exportDraft).toHaveBeenCalledWith({ responseText: "generated text", format: "Markdown", }); diff --git a/src/components/Draft/useResponseActions.ts b/src/components/Draft/useResponseActions.ts index c22f73a..fb1a9d2 100644 --- a/src/components/Draft/useResponseActions.ts +++ b/src/components/Draft/useResponseActions.ts @@ -1,4 +1,3 @@ -import { invoke } from "@tauri-apps/api/core"; import { useCallback, useState } from "react"; import { calculateEditRatio, @@ -14,6 +13,17 @@ interface TemplateSaveOptions { variablesJson?: string; } +interface AuditResponseCopyOverrideParams { + reason: string; + confidenceMode: string | null; + sourcesCount: number; +} + +interface ExportDraftParams { + responseText: string; + format: "Markdown"; +} + interface UseResponseActionsOptions { response: string; originalResponse: string; @@ -29,6 +39,10 @@ interface UseResponseActionsOptions { content: string, options: TemplateSaveOptions, ) => Promise; + auditResponseCopyOverride: ( + params: AuditResponseCopyOverrideParams, + ) => Promise; + exportDraft: (params: ExportDraftParams) => Promise; logEvent: (event: string, payload?: Record) => unknown; setResponse: (value: string) => void; @@ -51,6 +65,8 @@ export function useResponseActions({ streamingText, cancelGeneration, saveAsTemplate, + auditResponseCopyOverride, + exportDraft, logEvent, setResponse, setOriginalResponse, @@ -146,7 +162,7 @@ export function useResponseActions({ onShowError("Copy cancelled (reason required)."); return; } - await invoke("audit_response_copy_override", { + await auditResponseCopyOverride({ reason: reason.trim(), confidenceMode: confidence?.mode ?? null, sourcesCount: sources.length, @@ -170,6 +186,7 @@ export function useResponseActions({ response, confidence?.mode, sources.length, + auditResponseCopyOverride, logEvent, savedDraftId, isResponseEdited, @@ -185,7 +202,7 @@ export function useResponseActions({ return; } try { - const saved = await invoke("export_draft", { + const saved = await exportDraft({ responseText: response, format: "Markdown", }); @@ -196,7 +213,7 @@ export function useResponseActions({ } catch (e) { onShowError(`Export failed: ${e}`); } - }, [response, setHandoffTouched, onShowSuccess, onShowError]); + }, [response, exportDraft, setHandoffTouched, onShowSuccess, onShowError]); const resetResponseActions = useCallback(() => { setShowTemplateModal(false);