diff --git a/src/renderer/src/components/Popups/SaveToKnowledgePopup.tsx b/src/renderer/src/components/Popups/SaveToKnowledgePopup.tsx index b7c02cd4ec..cea3aca7cb 100644 --- a/src/renderer/src/components/Popups/SaveToKnowledgePopup.tsx +++ b/src/renderer/src/components/Popups/SaveToKnowledgePopup.tsx @@ -253,12 +253,39 @@ const PopupContainer: React.FC = ({ source, title, resolve }) => { let savedCount = 0 try { + // Validate knowledge base configuration before proceeding + if (!selectedBaseId) { + throw new Error('No knowledge base selected') + } + + const selectedBase = bases.find((base) => base.id === selectedBaseId) + if (!selectedBase) { + throw new Error('Selected knowledge base not found') + } + + if (!selectedBase.version) { + throw new Error('Knowledge base is not properly configured. Please check the knowledge base settings.') + } + if (isNoteMode) { const note = source.data as NotesTreeNode - const content = note.externalPath - ? await window.api.file.readExternal(note.externalPath) - : await window.api.file.read(note.id + '.md') - logger.debug('Note content:', content) + if (!note.externalPath) { + throw new Error('Note external path is required for export') + } + + let content = '' + try { + content = await window.api.file.readExternal(note.externalPath) + } catch (error) { + logger.error('Failed to read note file:', error as Error) + throw new Error('Failed to read note content. Please ensure the file exists and is accessible.') + } + + if (!content || content.trim() === '') { + throw new Error('Note content is empty. Cannot export empty notes to knowledge base.') + } + + logger.debug('Note content loaded', { contentLength: content.length }) await addNote(content) savedCount = 1 } else { @@ -283,9 +310,23 @@ const PopupContainer: React.FC = ({ source, title, resolve }) => { resolve({ success: true, savedCount }) } catch (error) { logger.error('save failed:', error as Error) - window.toast.error( - t(isTopicMode ? 'chat.save.topic.knowledge.error.save_failed' : 'chat.save.knowledge.error.save_failed') + + // Provide more specific error messages + let errorMessage = t( + isTopicMode ? 'chat.save.topic.knowledge.error.save_failed' : 'chat.save.knowledge.error.save_failed' ) + + if (error instanceof Error) { + if (error.message.includes('not properly configured')) { + errorMessage = error.message + } else if (error.message.includes('empty')) { + errorMessage = error.message + } else if (error.message.includes('read note content')) { + errorMessage = error.message + } + } + + window.toast.error(errorMessage) setLoading(false) } } diff --git a/src/renderer/src/pages/notes/NotesPage.tsx b/src/renderer/src/pages/notes/NotesPage.tsx index c85793e781..bc039e5ef2 100644 --- a/src/renderer/src/pages/notes/NotesPage.tsx +++ b/src/renderer/src/pages/notes/NotesPage.tsx @@ -492,10 +492,42 @@ const NotesPage: FC = () => { if (node && node.name !== newName) { const oldExternalPath = node.externalPath + let currentContent = '' + + // Save current content before rename to prevent content loss + if (node.type === 'file' && activeFilePath === oldExternalPath) { + // Get content from editor or current cache + currentContent = editorRef.current?.getMarkdown() || lastContentRef.current || currentContent + + // Save current content to the file before renaming + if (currentContent.trim()) { + try { + await saveCurrentNote(currentContent, oldExternalPath) + } catch (error) { + logger.warn('Failed to save content before rename:', error as Error) + } + } + } + const renamedNode = await renameNode(nodeId, newName) if (renamedNode.type === 'file' && activeFilePath === oldExternalPath) { + // Restore content to the new file path if content was lost during rename + if (currentContent.trim()) { + try { + const newFileContent = await window.api.file.readExternal(renamedNode.externalPath) + if (!newFileContent || newFileContent.trim() === '') { + await window.api.file.write(renamedNode.externalPath, currentContent) + logger.info('Restored content to renamed file') + } + } catch (error) { + logger.error('Failed to restore content after rename:', error as Error) + } + } + dispatch(setActiveFilePath(renamedNode.externalPath)) + // Invalidate cache for the new path to ensure content is loaded correctly + invalidateFileContent(renamedNode.externalPath) } else if ( renamedNode.type === 'folder' && activeFilePath && @@ -504,6 +536,8 @@ const NotesPage: FC = () => { const relativePath = activeFilePath.substring(oldExternalPath.length) const newFilePath = renamedNode.externalPath + relativePath dispatch(setActiveFilePath(newFilePath)) + // Invalidate cache for the new file path after folder rename + invalidateFileContent(newFilePath) } await sortAllLevels(sortType) if (renamedNode.name !== newName) { @@ -518,7 +552,7 @@ const NotesPage: FC = () => { }, 500) } }, - [activeFilePath, dispatch, findNodeById, sortType, t] + [activeFilePath, dispatch, findNodeById, sortType, t, invalidateFileContent, saveCurrentNote] ) // 处理文件上传