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 2e6159a6c4..2d5bc75dc0 100644 --- a/src/renderer/src/pages/notes/NotesPage.tsx +++ b/src/renderer/src/pages/notes/NotesPage.tsx @@ -634,11 +634,46 @@ const NotesPage: FC = () => { } const oldPath = node.externalPath + const normalizedOldPath = normalizePathValue(oldPath) + let cachedContent = '' + + if ( + node.type === 'file' && + activeFilePath && + normalizePathValue(activeFilePath) === normalizedOldPath + ) { + cachedContent = editorRef.current?.getMarkdown() || lastContentRef.current || '' + if (cachedContent.trim()) { + try { + await saveCurrentNote(cachedContent, oldPath) + } catch (error) { + logger.warn('Failed to persist content before rename', error as Error) + } + } + } + const renamed = await renameEntry(node, newName) - if (node.type === 'file' && activeFilePath === oldPath) { - dispatch(setActiveFilePath(renamed.path)) - } else if (node.type === 'folder' && activeFilePath && activeFilePath.startsWith(`${oldPath}/`)) { + if (node.type === 'file') { + if (activeFilePath && normalizePathValue(activeFilePath) === normalizedOldPath) { + dispatch(setActiveFilePath(renamed.path)) + invalidateFileContent(renamed.path) + + if (cachedContent.trim()) { + try { + const latest = await window.api.file.readExternal(renamed.path) + if (!latest || latest.trim() === '') { + await window.api.file.write(renamed.path, cachedContent) + } + } catch (error) { + logger.error('Failed to restore content after rename', error as Error) + } + } + } + } else if ( + activeFilePath && + normalizePathValue(activeFilePath).startsWith(`${normalizedOldPath}/`) + ) { const suffix = activeFilePath.slice(oldPath.length) dispatch(setActiveFilePath(`${renamed.path}${suffix}`)) } @@ -659,7 +694,7 @@ const NotesPage: FC = () => { }, 500) } }, - [activeFilePath, dispatch, notesTree, refreshTree] + [activeFilePath, dispatch, invalidateFileContent, notesTree, refreshTree, saveCurrentNote] ) // 处理文件上传 diff --git a/src/renderer/src/pages/settings/SettingsPage.tsx b/src/renderer/src/pages/settings/SettingsPage.tsx index ca83e149f0..00032484b7 100644 --- a/src/renderer/src/pages/settings/SettingsPage.tsx +++ b/src/renderer/src/pages/settings/SettingsPage.tsx @@ -191,7 +191,6 @@ const ContentContainer = styled.div` flex: 1; flex-direction: row; height: calc(100vh - var(--navbar-height)); - padding: 1px 0; ` const SettingMenus = styled(Scrollbar)`