feat: implement core backend API with data models, SSE, index management, and initial admin bootstrap.
This commit is contained in:
parent
2b69c49ed1
commit
3ae430aaa6
@ -707,11 +707,15 @@ async def api_browse(vault_name: str, path: str = "", current_user=Depends(requi
|
|||||||
if not target.exists():
|
if not target.exists():
|
||||||
raise HTTPException(status_code=404, detail=f"Path not found: {path}")
|
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 = []
|
items = []
|
||||||
try:
|
try:
|
||||||
for entry in sorted(target.iterdir(), key=lambda e: (not e.is_dir(), e.name.lower())):
|
for entry in sorted(target.iterdir(), key=lambda e: (not e.is_dir(), e.name.lower())):
|
||||||
# Skip hidden files/dirs
|
# Skip hidden files/dirs if the setting is enabled
|
||||||
if entry.name.startswith("."):
|
if hide_hidden and entry.name.startswith("."):
|
||||||
continue
|
continue
|
||||||
rel = str(entry.relative_to(vault_root)).replace("\\", "/")
|
rel = str(entry.relative_to(vault_root)).replace("\\", "/")
|
||||||
if entry.is_dir():
|
if entry.is_dir():
|
||||||
@ -719,7 +723,7 @@ async def api_browse(vault_name: str, path: str = "", current_user=Depends(requi
|
|||||||
try:
|
try:
|
||||||
file_count = sum(
|
file_count = sum(
|
||||||
1 for child in entry.iterdir()
|
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"))
|
and (child.is_file() and (child.suffix.lower() in SUPPORTED_EXTENSIONS or child.name.lower() in ("dockerfile", "makefile"))
|
||||||
or child.is_dir())
|
or child.is_dir())
|
||||||
)
|
)
|
||||||
|
|||||||
@ -1940,6 +1940,64 @@
|
|||||||
safeCreateIcons();
|
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) {
|
async function toggleVault(itemEl, vaultName, forceExpand) {
|
||||||
const childContainer = document.getElementById(`vault-children-${vaultName}`);
|
const childContainer = document.getElementById(`vault-children-${vaultName}`);
|
||||||
if (!childContainer) return;
|
if (!childContainer) return;
|
||||||
@ -3369,7 +3427,7 @@
|
|||||||
showToast("✓ Paramètres sauvegardés", "success");
|
showToast("✓ Paramètres sauvegardés", "success");
|
||||||
|
|
||||||
// Refresh the UI to apply the filter
|
// Refresh the UI to apply the filter
|
||||||
await Promise.all([loadVaults(), refreshTagsForContext()]);
|
await Promise.all([refreshSidebarTreePreservingState(), refreshTagsForContext()]);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("Failed to save hidden files settings:", err);
|
console.error("Failed to save hidden files settings:", err);
|
||||||
const errorMsg = err.message || "Erreur inconnue";
|
const errorMsg = err.message || "Erreur inconnue";
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user