From 3ae430aaa6de409fbc32858d54efa6a0b92672d9 Mon Sep 17 00:00:00 2001 From: Bruno Charest Date: Thu, 26 Mar 2026 20:18:56 -0400 Subject: [PATCH] feat: implement core backend API with data models, SSE, index management, and initial admin bootstrap. --- backend/main.py | 10 ++++++--- frontend/app.js | 60 ++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 66 insertions(+), 4 deletions(-) diff --git a/backend/main.py b/backend/main.py index ef378bb..6358ee2 100644 --- a/backend/main.py +++ b/backend/main.py @@ -707,11 +707,15 @@ async def api_browse(vault_name: str, path: str = "", current_user=Depends(requi if not target.exists(): raise HTTPException(status_code=404, detail=f"Path not found: {path}") + # Get vault settings for hideHiddenFiles + settings = get_vault_setting(vault_name) or {} + hide_hidden = settings.get("hideHiddenFiles", False) + items = [] try: for entry in sorted(target.iterdir(), key=lambda e: (not e.is_dir(), e.name.lower())): - # Skip hidden files/dirs - if entry.name.startswith("."): + # Skip hidden files/dirs if the setting is enabled + if hide_hidden and entry.name.startswith("."): continue rel = str(entry.relative_to(vault_root)).replace("\\", "/") if entry.is_dir(): @@ -719,7 +723,7 @@ async def api_browse(vault_name: str, path: str = "", current_user=Depends(requi try: file_count = sum( 1 for child in entry.iterdir() - if not child.name.startswith(".") + if (not hide_hidden or not child.name.startswith(".")) and (child.is_file() and (child.suffix.lower() in SUPPORTED_EXTENSIONS or child.name.lower() in ("dockerfile", "makefile")) or child.is_dir()) ) diff --git a/frontend/app.js b/frontend/app.js index 1568213..6050393 100644 --- a/frontend/app.js +++ b/frontend/app.js @@ -1940,6 +1940,64 @@ safeCreateIcons(); } + /** + * Refreshes the sidebar tree while preserving the expanded state of vaults and folders. + */ + async function refreshSidebarTreePreservingState() { + // 1. Capture expanded vaults + const expandedVaults = Array.from(document.querySelectorAll(".vault-item")).filter(v => { + const children = document.getElementById(`vault-children-${v.dataset.vault}`); + return children && !children.classList.contains("collapsed"); + }).map(v => v.dataset.vault); + + // 2. Capture expanded directories + const expandedDirs = Array.from(document.querySelectorAll(".tree-item[data-path]")).filter(item => { + const vault = item.dataset.vault; + const path = item.dataset.path; + const children = document.getElementById(`dir-${vault}-${path}`); + return children && !children.classList.contains("collapsed"); + }).map(item => ({ vault: item.dataset.vault, path: item.dataset.path })); + + // 3. Capture selected path + const selectedItem = document.querySelector(".tree-item.path-selected"); + const selectedState = selectedItem ? { vault: selectedItem.dataset.vault, path: selectedItem.dataset.path } : null; + + // 4. Reload vaults (rebuilds root list) + await loadVaults(); + + // 5. Re-expand vaults + for (const vName of expandedVaults) { + const vItem = document.querySelector(`.vault-item[data-vault="${CSS.escape(vName)}"]`); + if (vItem) { + await toggleVault(vItem, vName, true); + } + } + + // 6. Re-expand directories (parents first) + expandedDirs.sort((a, b) => a.path.split("/").length - b.path.split("/").length); + for (const dir of expandedDirs) { + const dItem = document.querySelector(`.tree-item[data-vault="${CSS.escape(dir.vault)}"][data-path="${CSS.escape(dir.path)}"]`); + const container = document.getElementById(`dir-${dir.vault}-${dir.path}`); + if (dItem && container && container.classList.contains("collapsed")) { + try { + await loadDirectory(dir.vault, dir.path, container); + container.classList.remove("collapsed"); + const chev = dItem.querySelector("[data-lucide]"); + if (chev) chev.setAttribute("data-lucide", "chevron-down"); + } catch (e) { + console.error(`Failed to re-expand ${dir.vault}/${dir.path}`, e); + } + } + } + + // 7. Restore selection + if (selectedState) { + await focusPathInSidebar(selectedState.vault, selectedState.path, { alignToTop: false }); + } + + safeCreateIcons(); + } + async function toggleVault(itemEl, vaultName, forceExpand) { const childContainer = document.getElementById(`vault-children-${vaultName}`); if (!childContainer) return; @@ -3369,7 +3427,7 @@ showToast("✓ Paramètres sauvegardés", "success"); // Refresh the UI to apply the filter - await Promise.all([loadVaults(), refreshTagsForContext()]); + await Promise.all([refreshSidebarTreePreservingState(), refreshTagsForContext()]); } catch (err) { console.error("Failed to save hidden files settings:", err); const errorMsg = err.message || "Erreur inconnue";