From 910107a09ead9c281439e33b211650214a9214f6 Mon Sep 17 00:00:00 2001 From: Subin C Date: Mon, 4 Nov 2024 13:47:42 +0530 Subject: [PATCH 1/4] feat: add auto file context feature and fix conversation display - Add checkbox to automatically include entire file content when no text is selected - Store auto-context preference in electron-store - Fix undefined message error in currentConversation display - Add proper type safety and null checks - Update UI with clear labeling for auto-context feature --- electron/main/electron-store/ipcHandlers.ts | 9 +++ electron/main/electron-store/storeConfig.ts | 2 + electron/preload/index.ts | 2 + .../WritingAssistant/ConversationHistory.tsx | 58 ++++++++++----- .../WritingAssistant/WritingAssistant.tsx | 74 +++++++++++++++---- 5 files changed, 112 insertions(+), 33 deletions(-) diff --git a/electron/main/electron-store/ipcHandlers.ts b/electron/main/electron-store/ipcHandlers.ts index d9abde35..811da97a 100644 --- a/electron/main/electron-store/ipcHandlers.ts +++ b/electron/main/electron-store/ipcHandlers.ts @@ -213,6 +213,15 @@ export const registerStoreHandlers = (store: Store, windowsManager: chatHistoriesMap[vaultDir] = filteredChatHistories store.set(StoreKeys.Chats, chatHistoriesMap) }) + + ipcMain.handle('set-auto-context', (event, autoContext: boolean) => { + store.set(StoreKeys.AutoContext, autoContext) + event.sender.send('auto-context-changed', autoContext) + }) + + ipcMain.handle('get-auto-context', () => { + return store.get(StoreKeys.AutoContext, true) // Default to true + }) } export function getDefaultEmbeddingModelConfig(store: Store): EmbeddingModelConfig { diff --git a/electron/main/electron-store/storeConfig.ts b/electron/main/electron-store/storeConfig.ts index 110cb088..e347a61d 100644 --- a/electron/main/electron-store/storeConfig.ts +++ b/electron/main/electron-store/storeConfig.ts @@ -61,6 +61,7 @@ export interface StoreSchema { spellCheck: string EditorFlexCenter: boolean showDocumentStats: boolean + autoContext: boolean } export enum StoreKeys { @@ -82,4 +83,5 @@ export enum StoreKeys { SpellCheck = 'spellCheck', EditorFlexCenter = 'editorFlexCenter', showDocumentStats = 'showDocumentStats', + AutoContext = 'autoContext', } diff --git a/electron/preload/index.ts b/electron/preload/index.ts index 88f3d38d..30d3ca77 100644 --- a/electron/preload/index.ts +++ b/electron/preload/index.ts @@ -76,6 +76,8 @@ const electronStore = { setEditorFlexCenter: createIPCHandler<(editorFlexCenter: boolean) => Promise>('set-editor-flex-center'), getAgentConfigs: createIPCHandler<() => Promise>('get-agent-configs'), setAgentConfig: createIPCHandler<(agentConfig: AgentConfig) => Promise>('set-agent-config'), + setAutoContext: (value: boolean) => ipcRenderer.invoke('set-auto-context', value), + getAutoContext: () => ipcRenderer.invoke('get-auto-context'), } const fileSystem = { diff --git a/src/components/WritingAssistant/ConversationHistory.tsx b/src/components/WritingAssistant/ConversationHistory.tsx index 7505bead..1038efec 100644 --- a/src/components/WritingAssistant/ConversationHistory.tsx +++ b/src/components/WritingAssistant/ConversationHistory.tsx @@ -22,6 +22,8 @@ interface ConversationHistoryProps { isNewConversation: boolean // prompts: { option?: string; customPromptInput?: string }[] loadingResponse: boolean + autoContext: boolean + setAutoContext: (value: boolean) => void } const ConversationHistory: React.FC = ({ @@ -41,6 +43,8 @@ const ConversationHistory: React.FC = ({ isNewConversation, // prompts, loadingResponse, + autoContext, + setAutoContext, }) => { const bottomRef = useRef(null) // const [currentPrompt, setCurrentPrompt] = useState<{ option?: string; customPromptInput?: string }>({}) @@ -55,28 +59,44 @@ const ConversationHistory: React.FC = ({ // }, [prompts, currentIndex]) const currentConversation = isNewConversation - ? [history[history.length - 1]] - : history.slice(currentIndex, currentIndex + 2) + ? history.slice(-1) + : history.slice(currentIndex, currentIndex + 2).filter(Boolean) return (
-
- - +
+
+ +
+
+ + +
{currentConversation.map( diff --git a/src/components/WritingAssistant/WritingAssistant.tsx b/src/components/WritingAssistant/WritingAssistant.tsx index a9eb4778..c6f5e02c 100644 --- a/src/components/WritingAssistant/WritingAssistant.tsx +++ b/src/components/WritingAssistant/WritingAssistant.tsx @@ -34,6 +34,7 @@ const WritingAssistant: React.FC = () => { // const [prompts, setPrompts] = useState<{ option?: string; customPromptInput?: string }[]>([]) const { editor, highlightData } = useFileContext() + const [autoContext, setAutoContext] = useState(true) useOutsideClick(markdownContainerRef, () => { setMessages([]) @@ -138,23 +139,48 @@ const WritingAssistant: React.FC = () => { }, [editor]) useEffect(() => { - if (editor && isSpaceTrigger && spacePosition !== null) { - const checkSpacePresence = () => { - const currentContent = editor.state.doc.textBetween(spacePosition, spacePosition + 1) - if (currentContent !== ' ') { - setIsOptionsVisible(false) - setIsSpaceTrigger(false) - setSpacePosition(null) + if (!editor || !isSpaceTrigger || spacePosition === null) { + return undefined + } + + const resetSpaceTrigger = () => { + setIsOptionsVisible(false) + setIsSpaceTrigger(false) + setSpacePosition(null) + } + + const checkSpacePresence = () => { + try { + if (!editor.state?.doc) { + resetSpaceTrigger() + return } - } - editor.on('update', checkSpacePresence) + const { from } = editor.state.selection - return () => { - editor.off('update', checkSpacePresence) + if (from !== spacePosition) { + resetSpaceTrigger() + return + } + + const $pos = editor.state.doc.resolve(from) + if (!$pos?.parent?.textContent?.startsWith(' ')) { + resetSpaceTrigger() + } + } catch (error) { + resetSpaceTrigger() } } - return () => {} + + const handler = () => { + requestAnimationFrame(checkSpacePresence) + } + + editor.on('update', handler) + + return () => { + editor.off('update', handler) + } }, [editor, isSpaceTrigger, spacePosition]) useEffect(() => { @@ -180,6 +206,14 @@ const WritingAssistant: React.FC = () => { } }, [editor, cursorPosition]) + useEffect(() => { + const loadAutoContext = async () => { + const savedAutoContext = await window.electronStore.getAutoContext() + setAutoContext(savedAutoContext) + } + loadAutoContext() + }, []) + const copyToClipboard = () => { const assistantMessage = messages[currentConversationIndex + 1] if (!assistantMessage || assistantMessage.role !== 'assistant') return @@ -213,9 +247,12 @@ const WritingAssistant: React.FC = () => { if (!assistantMessage || assistantMessage.role !== 'assistant' || !editor) return const replacementText = assistantMessage.visibleContent || assistantMessage.content - if (replacementText) { - editor.chain().focus().deleteSelection().insertContent(replacementText).run() + if (highlightData.text) { + editor.chain().focus().deleteSelection().insertContent(replacementText).run() + } else if (autoContext) { + editor.chain().focus().selectAll().deleteSelection().insertContent(replacementText).run() + } } setMessages([]) @@ -260,6 +297,9 @@ const WritingAssistant: React.FC = () => { const handleOption = async (option: string, customPromptInput?: string) => { let selectedText = highlightData.text + if (autoContext && !selectedText && editor) { + selectedText = editor.state.doc.textBetween(0, editor.state.doc.content.size) + } if (lastAssistantMessage) { selectedText = typeof lastAssistantMessage.content === 'string' @@ -272,6 +312,10 @@ const WritingAssistant: React.FC = () => { setIsOptionsVisible(false) await getLLMResponse(prompt) } + const handleAutoContextChange = async (value: boolean) => { + setAutoContext(value) + await window.electronStore.setAutoContext(value) + } if (!isSpaceTrigger && !highlightData.position) return null if (isSpaceTrigger && isOptionsVisible && !getLastMessage(messages, 'assistant')) @@ -429,6 +473,8 @@ const WritingAssistant: React.FC = () => { replaceHighlightedText={replaceHighlightedText} isNewConversation={isNewConversation} loadingResponse={loadingResponse} + autoContext={autoContext} + setAutoContext={handleAutoContextChange} />
)} From f01ef416b8d313cd21fd262b8e20e3d543a2f183 Mon Sep 17 00:00:00 2001 From: Subin C Date: Mon, 4 Nov 2024 13:59:46 +0530 Subject: [PATCH 2/4] feat: add auto file context feature and fix conversation display - Add checkbox to automatically include entire file content when no text is selected - Store auto-context preference in electron-store - Fix undefined message error in currentConversation display - Add proper type safety and null checks - Update UI with clear labeling for auto-context feature --- src/components/WritingAssistant/ConversationHistory.tsx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/components/WritingAssistant/ConversationHistory.tsx b/src/components/WritingAssistant/ConversationHistory.tsx index 1038efec..db688313 100644 --- a/src/components/WritingAssistant/ConversationHistory.tsx +++ b/src/components/WritingAssistant/ConversationHistory.tsx @@ -72,11 +72,9 @@ const ConversationHistory: React.FC = ({ id="autoContextCheckbox" checked={autoContext} onChange={(e) => setAutoContext(e.target.checked)} - className="h-4 w-4 rounded border-gray-600 bg-gray-700 text-indigo-500 focus:ring-1 focus:ring-indigo-500/30" + className="size-4 rounded border-gray-600 bg-gray-700 text-indigo-500 focus:ring-1 focus:ring-indigo-500/30" /> - - Use File Content (If no text selected) - + Use File Content (If no text selected)
From 19ba3dae3ec7ca30a0d5efb4ba25be4979f3df21 Mon Sep 17 00:00:00 2001 From: Subin C Date: Mon, 4 Nov 2024 15:27:48 +0530 Subject: [PATCH 3/4] feat: add auto file context feature and fix conversation display - Add checkbox to automatically include entire file content when no text is selected - Store auto-context preference in electron-store - Fix undefined message error in currentConversation display - Add proper type safety and null checks - Update UI with clear labeling for auto-context feature --- electron/preload/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/electron/preload/index.ts b/electron/preload/index.ts index 30d3ca77..5cc8286c 100644 --- a/electron/preload/index.ts +++ b/electron/preload/index.ts @@ -76,8 +76,8 @@ const electronStore = { setEditorFlexCenter: createIPCHandler<(editorFlexCenter: boolean) => Promise>('set-editor-flex-center'), getAgentConfigs: createIPCHandler<() => Promise>('get-agent-configs'), setAgentConfig: createIPCHandler<(agentConfig: AgentConfig) => Promise>('set-agent-config'), - setAutoContext: (value: boolean) => ipcRenderer.invoke('set-auto-context', value), - getAutoContext: () => ipcRenderer.invoke('get-auto-context'), + setAutoContext: createIPCHandler<(value: boolean) => Promise>('set-auto-context'), + getAutoContext: createIPCHandler<() => Promise>('get-auto-context'), } const fileSystem = { From 6e0744aa95095909caf8d73f43e1ba49c0f2e908 Mon Sep 17 00:00:00 2001 From: Subin C Date: Thu, 7 Nov 2024 18:10:32 +0530 Subject: [PATCH 4/4] refactor: move autoContext checkbox from ConversationHistory to WritingAssistant - Remove autoContext checkbox and related props from ConversationHistory component - Add autoContext checkbox to WritingAssistant's options container - Update component interfaces and prop passing - Maintain existing autoContext functionality and styling --- .../WritingAssistant/ConversationHistory.tsx | 56 +++++++------------ .../WritingAssistant/WritingAssistant.tsx | 14 ++++- 2 files changed, 31 insertions(+), 39 deletions(-) diff --git a/src/components/WritingAssistant/ConversationHistory.tsx b/src/components/WritingAssistant/ConversationHistory.tsx index db688313..7505bead 100644 --- a/src/components/WritingAssistant/ConversationHistory.tsx +++ b/src/components/WritingAssistant/ConversationHistory.tsx @@ -22,8 +22,6 @@ interface ConversationHistoryProps { isNewConversation: boolean // prompts: { option?: string; customPromptInput?: string }[] loadingResponse: boolean - autoContext: boolean - setAutoContext: (value: boolean) => void } const ConversationHistory: React.FC = ({ @@ -43,8 +41,6 @@ const ConversationHistory: React.FC = ({ isNewConversation, // prompts, loadingResponse, - autoContext, - setAutoContext, }) => { const bottomRef = useRef(null) // const [currentPrompt, setCurrentPrompt] = useState<{ option?: string; customPromptInput?: string }>({}) @@ -59,42 +55,28 @@ const ConversationHistory: React.FC = ({ // }, [prompts, currentIndex]) const currentConversation = isNewConversation - ? history.slice(-1) - : history.slice(currentIndex, currentIndex + 2).filter(Boolean) + ? [history[history.length - 1]] + : history.slice(currentIndex, currentIndex + 2) return (
-
-
- -
-
- - -
+
+ +
{currentConversation.map( diff --git a/src/components/WritingAssistant/WritingAssistant.tsx b/src/components/WritingAssistant/WritingAssistant.tsx index c6f5e02c..1b61230d 100644 --- a/src/components/WritingAssistant/WritingAssistant.tsx +++ b/src/components/WritingAssistant/WritingAssistant.tsx @@ -368,6 +368,18 @@ const WritingAssistant: React.FC = () => { List key Takeaways
+
+ +
) return ( @@ -473,8 +485,6 @@ const WritingAssistant: React.FC = () => { replaceHighlightedText={replaceHighlightedText} isNewConversation={isNewConversation} loadingResponse={loadingResponse} - autoContext={autoContext} - setAutoContext={handleAutoContextChange} />
)}