Update README and code to remove folder registration option

This commit is contained in:
2026-03-20 10:18:12 +01:00
parent d86cb8d0fd
commit c4ee51d05d
5 changed files with 33 additions and 65 deletions

View File

@@ -17,7 +17,7 @@ Heimgeist is a local desktop chat client for Ollama. It combines an Electron + R
The `DBs` tab is no longer a placeholder. You can:
- create and rename libraries
- register files and folders
- register files
- let Heimgeist rebuild retrieval automatically when files change
- open or remove registered files from the UI

View File

@@ -475,20 +475,9 @@ ipcMain.handle('update-settings', (event, settings) => {
return true
})
function pickDialogProperties(kind) {
if (kind === 'directories') {
return ['openDirectory', 'multiSelections']
}
if (kind === 'mixed') {
return ['openFile', 'openDirectory', 'multiSelections']
}
return ['openFile', 'multiSelections']
}
ipcMain.handle('pick-paths', async (event, options = {}) => {
const kind = typeof options?.kind === 'string' ? options.kind : 'files'
ipcMain.handle('pick-paths', async () => {
const result = await dialog.showOpenDialog(mainWindow, {
properties: pickDialogProperties(kind),
properties: ['openFile', 'multiSelections'],
})
return result.canceled ? [] : result.filePaths
})

View File

@@ -8,7 +8,7 @@ contextBridge.exposeInMainWorld('electronAPI', {
checkForUpdates: () => ipcRenderer.invoke('check-for-updates'),
setSetting: (key, value) => ipcRenderer.invoke('set-setting', key, value),
updateSettings: (settings) => ipcRenderer.invoke('update-settings', settings),
pickPaths: (options = {}) => ipcRenderer.invoke('pick-paths', options),
pickPaths: () => ipcRenderer.invoke('pick-paths'),
openPath: (filePath) => ipcRenderer.invoke('open-path', filePath),
openExternalLink: (event) => {
event.preventDefault();

View File

@@ -1532,6 +1532,28 @@ async function createNewChat() {
});
}
function handleLibraryDelete(slug) {
fetch(`${backendApiUrl}/libraries/${slug}`, { method: 'DELETE' })
.then(async (response) => {
if (!response.ok) {
const detail = await response.text()
throw new Error(detail || `HTTP ${response.status}`)
}
const nextLibraries = libraries.filter(library => library.slug !== slug)
setLibraries(nextLibraries)
setLibraryJobs(prevJobs => prevJobs.filter(job => job.slug !== slug))
setEditingLibrarySlug(current => current === slug ? null : current)
if (activeLibrarySlug === slug) {
setActiveLibrarySlug(nextLibraries[0]?.slug || null)
}
removeLibraryFromChatSelections(slug)
})
.catch((error) => {
console.error('Failed to delete library', error)
})
}
// Auto-delete empty "New Chat" sessions
useEffect(() => {
const emptyNewChats = chatSessions.filter(
@@ -1661,6 +1683,9 @@ async function createNewChat() {
<button className="icon-button" onClick={(e) => { e.stopPropagation(); setEditingLibrarySlug(library.slug) }}>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className="feather feather-edit-2"><path d="M17 3a2.828 2.828 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5L17 3z"></path></svg>
</button>
<button className="icon-button" onClick={(e) => { e.stopPropagation(); handleLibraryDelete(library.slug) }}>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className="feather feather-x"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>
</button>
</div>
</>
)}
@@ -1991,13 +2016,6 @@ async function createNewChat() {
await refreshLibraries();
await refreshLibraryJobs();
}}
onDeleted={(slug) => {
if (activeLibrarySlug === slug) {
const next = libraries.find(lib => lib.slug !== slug);
setActiveLibrarySlug(next?.slug || null);
}
removeLibraryFromChatSelections(slug)
}}
/>
</>
)}

View File

@@ -53,11 +53,9 @@ export default function LibraryManager({
apiBase,
library,
jobs,
onRefresh,
onDeleted
onRefresh
}) {
const [busy, setBusy] = useState(false)
const [confirmDelete, setConfirmDelete] = useState(false)
const [errorMessage, setErrorMessage] = useState('')
const [toasts, setToasts] = useState([])
const toastTimeoutsRef = useRef(new Map())
@@ -65,7 +63,6 @@ export default function LibraryManager({
const previousLibraryStateRef = useRef(null)
useEffect(() => {
setConfirmDelete(false)
setErrorMessage('')
}, [library?.slug, library?.name])
@@ -114,7 +111,6 @@ export default function LibraryManager({
try {
setErrorMessage('')
await fn()
setConfirmDelete(false)
} finally {
setBusy(false)
await onRefresh()
@@ -132,9 +128,9 @@ export default function LibraryManager({
})
}
async function addPaths(kind = 'files') {
async function addPaths() {
if (!library) return
const paths = await window.electronAPI?.pickPaths?.({ kind })
const paths = await window.electronAPI?.pickPaths?.()
if (!Array.isArray(paths) || paths.length === 0) return
try {
await registerPaths(paths)
@@ -175,15 +171,6 @@ export default function LibraryManager({
}
}
async function deleteLibrary() {
if (!library) return
await runAction(async () => {
const response = await fetch(`${apiBase}/libraries/${library.slug}`, { method: 'DELETE' })
await expectOk(response)
})
onDeleted?.(library.slug)
}
async function retrySync() {
if (!library) return
try {
@@ -276,22 +263,6 @@ export default function LibraryManager({
return (
<div className="library-panel">
<div className="library-panel-scroll">
{confirmDelete && (
<div className="library-inline-form danger-zone">
<div className="muted-copy">Delete "{library.name}"? This removes the registered files and local retrieval data for this database.</div>
<div className="new-db-actions">
<button
className="button danger"
disabled={busy}
onClick={() => deleteLibrary().catch((error) => setErrorMessage(String(error?.message || error)))}
>
Confirm Delete
</button>
<button className="button ghost" onClick={() => setConfirmDelete(false)}>Cancel</button>
</div>
</div>
)}
{errorMessage && <div className="form-error">{errorMessage}</div>}
<div className="library-files">
@@ -350,20 +321,10 @@ export default function LibraryManager({
</div>
<div className="library-footer-actions">
<button className="button" disabled={busy} onClick={() => addPaths('files')}>Add Files</button>
<button className="button ghost" disabled={busy} onClick={() => addPaths('directories')}>Add Folder</button>
<button className="button" disabled={busy} onClick={addPaths}>Add Files</button>
{library.files?.length > 0 && !isSyncing && !isReadyForChat && (
<button className="button ghost" disabled={busy} onClick={retrySync}>Retry Sync</button>
)}
<button
className="button danger"
onClick={() => {
setConfirmDelete(true)
setErrorMessage('')
}}
>
Delete
</button>
</div>
{toasts.length > 0 && (