diff --git a/backend/indexer.py b/backend/indexer.py index 9a89987..29282ec 100644 --- a/backend/indexer.py +++ b/backend/indexer.py @@ -52,7 +52,7 @@ SUPPORTED_EXTENSIONS = { def load_vault_config() -> Dict[str, Dict[str, Any]]: - """Read VAULT_N_* env vars and return vault configuration. + """Read VAULT_N_* and DIR_N_* env vars and return vault configuration. Scans environment variables ``VAULT_1_NAME``/``VAULT_1_PATH``, ``VAULT_2_NAME``/``VAULT_2_PATH``, etc. in sequential order. @@ -67,6 +67,7 @@ def load_vault_config() -> Dict[str, Dict[str, Any]]: - path: filesystem path (required) - attachmentsPath: relative attachments folder (optional) - scanAttachmentsOnStartup: boolean (default True) + - type: "VAULT" or "DIR" """ vaults: Dict[str, Dict[str, Any]] = {} n = 1 @@ -84,8 +85,25 @@ def load_vault_config() -> Dict[str, Dict[str, Any]]: "path": path, "attachmentsPath": attachments_path, "scanAttachmentsOnStartup": scan_attachments, + "type": "VAULT" } n += 1 + + n = 1 + while True: + name = os.environ.get(f"DIR_{n}_NAME") + path = os.environ.get(f"DIR_{n}_PATH") + if not name or not path: + break + + vaults[name] = { + "path": path, + "attachmentsPath": None, + "scanAttachmentsOnStartup": False, + "type": "DIR" + } + n += 1 + return vaults diff --git a/backend/main.py b/backend/main.py index 26d0ddd..7827a8e 100644 --- a/backend/main.py +++ b/backend/main.py @@ -59,6 +59,7 @@ class VaultInfo(BaseModel): name: str = Field(description="Display name of the vault") file_count: int = Field(description="Number of indexed files") tag_count: int = Field(description="Number of unique tags") + type: str = Field(default="VAULT", description="Type of the vault mapping (VAULT or DIR)") class BrowseItem(BaseModel): @@ -603,10 +604,12 @@ async def api_vaults(current_user=Depends(require_auth)): result = [] for name, data in index.items(): if "*" in user_vaults or name in user_vaults: + v_type = vault_config.get(name, {}).get("type", "VAULT") result.append({ "name": name, "file_count": len(data["files"]), "tag_count": len(data["tags"]), + "type": v_type, }) return result diff --git a/docker-compose.yml b/docker-compose.yml index 26a912a..c7897da 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -39,8 +39,8 @@ services: - VAULT_4_PATH=/vaults/Obsidian_WORKOUT - VAULT_5_NAME=Sessions - VAULT_5_PATH=/vaults/SessionsManager - - VAULT_6_NAME=Bruno - - VAULT_6_PATH=/vaults/bruno + - DIR_1_NAME=Bruno + - DIR_1_PATH=/vaults/bruno # Auth configuration (uncomment to enable) - OBSIGATE_AUTH_ENABLED=true - OBSIGATE_ADMIN_USER=admin diff --git a/frontend/app.js b/frontend/app.js index 728a259..0f59556 100644 --- a/frontend/app.js +++ b/frontend/app.js @@ -1400,7 +1400,7 @@ vaultsToShow.forEach((v) => { const vaultItem = el("div", { class: "tree-item vault-item", "data-vault": v.name }, [ icon("chevron-right", 14), - icon("database", 16), + getVaultIcon(v.name, 16), document.createTextNode(` ${v.name} `), smallBadge(v.file_count), ]); @@ -1457,7 +1457,7 @@ // Sidebar tree entry const vaultItem = el("div", { class: "tree-item vault-item", "data-vault": v.name }, [ icon("chevron-right", 14), - icon("database", 16), + getVaultIcon(v.name, 16), document.createTextNode(` ${v.name} `), smallBadge(v.file_count), ]); @@ -1736,7 +1736,7 @@ entries.sort((a, b) => a.path.localeCompare(b.path, undefined, { sensitivity: "base" })); const vaultHeader = el("div", { class: "tree-item vault-item filter-results-header", "data-vault": vaultName }, [ - icon("database", 16), + getVaultIcon(vaultName, 16), document.createTextNode(` ${vaultName} `), smallBadge(entries.length), ]); @@ -3296,6 +3296,46 @@ return s; } + function getVaultIcon(vaultName, size = 16) { + const v = allVaults.find((val) => val.name === vaultName); + const type = v ? v.type : "VAULT"; + + if (type === "DIR") { + const i = icon("folder", size); + i.style.color = "#eab308"; // yellow tint + return i; + } else { + const purple = "#8b5cf6"; + const svgNS = "http://www.w3.org/2000/svg"; + const svg = document.createElementNS(svgNS, "svg"); + svg.setAttribute("xmlns", svgNS); + svg.setAttribute("width", size); + svg.setAttribute("height", size); + svg.setAttribute("viewBox", "0 0 24 24"); + svg.setAttribute("fill", "none"); + svg.setAttribute("stroke", purple); + svg.setAttribute("stroke-width", "2"); + svg.setAttribute("stroke-linecap", "round"); + svg.setAttribute("stroke-linejoin", "round"); + svg.classList.add("icon"); + + const path1 = document.createElementNS(svgNS, "path"); + path1.setAttribute("d", "M6 3h12l4 6-10 12L2 9z"); + const path2 = document.createElementNS(svgNS, "path"); + path2.setAttribute("d", "M11 3 8 9l4 12"); + const path3 = document.createElementNS(svgNS, "path"); + path3.setAttribute("d", "M12 21l4-12-3-6"); + const path4 = document.createElementNS(svgNS, "path"); + path4.setAttribute("d", "M2 9h20"); + + svg.appendChild(path1); + svg.appendChild(path2); + svg.appendChild(path3); + svg.appendChild(path4); + return svg; + } + } + function makeBreadcrumbSpan(text, onClick) { const s = document.createElement("span"); s.textContent = text;