diff --git a/.gitignore b/.gitignore index 077f19f..2b9520c 100644 --- a/.gitignore +++ b/.gitignore @@ -44,6 +44,7 @@ test_dir/video/ test_vault/images/ test_vault/markdown/ test_vault/budget.xlsx +test_home/ # Tauri updater signing keys (private key — never commit) desktop/*.key diff --git a/CHANGELOG.md b/CHANGELOG.md index 4ae7f98..aaa9f8c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ Format basé sur [Keep a Changelog](https://keepachangelog.com/fr/1.1.0/), et [Semantic Versioning](https://semver.org/spec/v2.0.0.html). > **En cours de développement** : les changements à venir sont listés dans la section -> [Unreleased](#unreleased). La dernière version livrée est **2.64.0**. +> [Unreleased](#unreleased). La dernière version livrée est **2.65.0**. --- @@ -14,6 +14,25 @@ et [Semantic Versioning](https://semver.org/spec/v2.0.0.html). --- +## [2.65.0] — 2026-10-10 + +### Ajouté + +- **#194 (UI) — Dossier personnel visible dans l'arborescence** + - Les vaults `home-` s'affichent **en premier** dans l'arborescence de + la barre latérale (tri stable appliqué à la source, `frontend/js/sidebar.js`, + donc aussi les sélecteurs de vault). + - Icône **maison** lucide (`data-lucide="home"`, même style/`stroke: + currentColor` que les autres icônes) via `getVaultIcon()` — + `frontend/js/viewer.js`. + - `docker-compose.test-win.yml` : montage `test_home:/vaults/Home` + + `OBSIGATE_HOME_ROOT=/vaults/Home` pour tester la feature en local + (dossier `test_home/` ignoré par git). + - Tests : `sidebar-filters.test.mjs` +2 (icône maison pour `home-*`, + gemme violette inchangée ailleurs). + +--- + ## [2.64.0] — 2026-10-10 ### Ajouté diff --git a/README.fr.md b/README.fr.md index f294869..87d7a8b 100644 --- a/README.fr.md +++ b/README.fr.md @@ -4,7 +4,7 @@ **Porte d'entrée web ultra-léger pour vos vaults Obsidian** — Accédez, naviguez et recherchez dans toutes vos notes Obsidian depuis n'importe quel appareil via une interface web moderne et responsive. -[![Version](https://img.shields.io/badge/Version-2.64.0-blue.svg)]() +[![Version](https://img.shields.io/badge/Version-2.65.0-blue.svg)]() [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![Docker](https://img.shields.io/badge/Docker-Ready-blue.svg)](https://www.docker.com/) [![Python](https://img.shields.io/badge/Python-3.11+-green.svg)](https://www.python.org/) @@ -977,8 +977,8 @@ Ce projet est sous licence **MIT** — voir le fichier [LICENSE](LICENSE) pour l ## 📝 Changelog -Consultez le [CHANGELOG.md](./CHANGELOG.md) pour l'historique complet de toutes les versions (v1.0.0 → v2.64.0). +Consultez le [CHANGELOG.md](./CHANGELOG.md) pour l'historique complet de toutes les versions (v1.0.0 → v2.65.0). --- -*Projet : ObsiGate | Version : 2.64.0 | Dernière mise à jour : Septembre 2026* +*Projet : ObsiGate | Version : 2.65.0 | Dernière mise à jour : Septembre 2026* diff --git a/README.md b/README.md index 73089c6..96e6dd1 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ **Ultra-light web gateway for your Obsidian vaults** — Access, browse, and search all your Obsidian notes from any device via a modern, responsive web interface. -[![Version](https://img.shields.io/badge/Version-2.64.0-blue.svg)]() +[![Version](https://img.shields.io/badge/Version-2.65.0-blue.svg)]() [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![Docker](https://img.shields.io/badge/Docker-Ready-blue.svg)](https://www.docker.com/) [![Python](https://img.shields.io/badge/Python-3.11+-green.svg)](https://www.python.org/) @@ -1152,8 +1152,8 @@ This project is licensed under the **MIT License** - see the [LICENSE](LICENSE) ## 📝 Changelog -See [CHANGELOG.md](./CHANGELOG.md) for the complete version history (v1.0.0 → v2.64.0). +See [CHANGELOG.md](./CHANGELOG.md) for the complete version history (v1.0.0 → v2.65.0). --- -*Project: ObsiGate | Version: 2.64.0 | Last updated: September 2026* +*Project: ObsiGate | Version: 2.65.0 | Last updated: September 2026* diff --git a/VERSION b/VERSION index d1524d4..9fbc3d9 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.64.0 +2.65.0 diff --git a/desktop/Cargo.lock b/desktop/Cargo.lock index 06102d1..2ddac84 100644 --- a/desktop/Cargo.lock +++ b/desktop/Cargo.lock @@ -2626,7 +2626,7 @@ dependencies = [ [[package]] name = "obsigate-desktop" -version = "2.64.0" +version = "2.65.0" dependencies = [ "chrono", "env_logger", diff --git a/desktop/Cargo.toml b/desktop/Cargo.toml index aabcdd6..02ec951 100644 --- a/desktop/Cargo.toml +++ b/desktop/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "obsigate-desktop" -version = "2.64.0" +version = "2.65.0" description = "ObsiGate Desktop — Porte d'entrée native pour vos vaults Obsidian" authors = ["Bruno Charest"] edition = "2021" diff --git a/desktop/tauri.conf.json b/desktop/tauri.conf.json index 7f8b404..56012de 100644 --- a/desktop/tauri.conf.json +++ b/desktop/tauri.conf.json @@ -1,7 +1,7 @@ { "$schema": "https://raw.githubusercontent.com/nicedoc/obsigate/main/desktop/tauri.conf.schema.json", "productName": "ObsiGate", - "version": "2.64.0", + "version": "2.65.0", "identifier": "com.obsigate.desktop", "build": { "frontendDist": "../frontend", diff --git a/docker-compose.test-win.yml b/docker-compose.test-win.yml index 01f2480..cd0a0eb 100644 --- a/docker-compose.test-win.yml +++ b/docker-compose.test-win.yml @@ -21,12 +21,17 @@ services: volumes: - /c/dev/git/python/ObsiGate/test_vault:/vaults/TestVault - /c/dev/git/python/ObsiGate/test_dir:/vaults/TestDir + # #194 : racine des dossiers persos — UN seul montage pour tous les + # utilisateurs (dossier hôte : mkdir test_home à côté du dépôt). + - /c/dev/git/python/ObsiGate/test_home:/vaults/Home - obsigate_data:/app/data environment: - VAULT_1_NAME=TestVault - VAULT_1_PATH=/vaults/TestVault - DIR_1_NAME=TestDir - DIR_1_PATH=/vaults/TestDir + # #194 : dossier personnel par utilisateur = /home- + - OBSIGATE_HOME_ROOT=/vaults/Home - OBSIGATE_AUTH_ENABLED=true - OBSIGATE_ADMIN_USER=admin - OBSIGATE_ADMIN_PASSWORD=test123 diff --git a/docs/ISSUES_TODOLIST.md b/docs/ISSUES_TODOLIST.md index 9fbaa37..69d372a 100644 --- a/docs/ISSUES_TODOLIST.md +++ b/docs/ISSUES_TODOLIST.md @@ -341,6 +341,8 @@ Avant de corriger quoi que ce soit, un agent IA doit : | 2026-10-09 | #194 | Fonctionnalité | `backend/user_home.py` (nouveau), `backend/indexer.py`, `backend/auth/router.py`, `backend/routers/vaults.py`, `backend/main.py`, `docker-compose.yml`, `tests/test_user_home.py` (nouveau), `tests/test_auth_api.py`, `docs/features/user-home-194.md` (nouveau), `docs/ROADMAP.md`, `CHANGELOG.md`, `README.md`, `README.fr.md` | **#194 — dossier personnel par utilisateur** : chaque compte reçoit `/` monté comme vault propre `home-` (option A validée) — l'isolation s'appuie sur l'ACL par vault **existante** (`check_vault_access`), aucune ACL par chemin inventée. `backend/user_home.py` : `ensure_user_home()` idempotent (mkdir → `add_vault_to_index` → `persist_vault` → watcher → SSE → octroi dans `user.vaults`) appelé à `POST /api/auth/admin/users` **et** au démarrage (`ensure_all_user_homes()` : migration des users existants, réparation des dossiers/registres manquants, sweep des vaults `home-*` orphelins dont l'utilisateur a disparu hors route — garde `Path.parent == racine` pour ne jamais toucher à un vault admin homonyme) ; `release_user_home()` à la suppression (index/watcher/registre refermés, **dossier conservé**). **Blocage levé** : registre persistant `data/vaults.json` fusionné par `load_vault_config()` — avant, tout vault ajouté à la volée (`/api/vaults/add`) disparaissait au premier reindex complet et au redémarrage. Correctif au passage : `reload_single_vault()` remet `vault_config[name]` après `remove_vault_from_index()`. Réponse du POST = vaults réactualisés (l'instantané de `create_user` était antérieur à l'octroi). Déploiement : montage unique `/NFS/OBSIDIAN_DOC/Home:/vaults/Home` + `OBSIGATE_HOME_ROOT` (absente = feature inactive, dev/tests/desktop inchangés). Vérifié : `test_user_home.py` 12/12 (création, idempotence, username invalide, persistance après `load_vault_config`, retrait, isolation `check_vault_access`, orphelins), `test_auth_api.py::TestUserHome` 2/2, suite **1703 passed / 2 skipped**, ruff backend 0, mypy 114 fichiers 0, `validate-imports` 42 modules / 372 exports, `unit.test.mjs` 13/13 | ✅ livré (en attente vérif utilisateur) | +| 2026-10-09 | #194 | Fonctionnalité (UI) | `frontend/js/sidebar.js`, `frontend/js/viewer.js`, `docker-compose.test-win.yml`, `.gitignore`, `tests/frontend/sidebar-filters.test.mjs`, `docs/ROADMAP.md`, `docs/features/user-home-194.md`, `CHANGELOG.md` | **#194 (incrément UI)** : les vaults `home-` s'affichent **en premier** dans l'arborescence de la sidebar — tri stable appliqué à la source (`_homeFirst` dans `loadVaults()` et dans le soft-refresh, donc `state.allVaults`, l'arborescence et les sélecteurs restent cohérents) — et portent l'icône **maison** lucide (`data-lucide="home"` via `getVaultIcon`, même `safeCreateIcons`/`stroke: currentColor` que les autres icônes, thème-aware). Compose de test : `test_home:/vaults/Home` + `OBSIGATE_HOME_ROOT=/vaults/Home` (dossier `test_home/` ignoré par git). Vérifié : `sidebar-filters.test.mjs` 8→**10/10**, `validate-imports` 42 modules / 372 exports, `unit.test.mjs` 13/13, suites voisines (ai-sidebar, toolbar-order, search-facets, pane-manager, editor-inline) vertes, **live Playwright sur l'instance 2020** : ordre `home-admin, home-bruno, TestDir, TestVault` + `svg.lucide-home` rendu (placeholder `` remplacé) | ✅ livré (en attente vérif utilisateur) | + --- ## 📜 Historique des bugs résolus diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index 6f3043b..02ed149 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -1,6 +1,6 @@ # ObsiGate — Roadmap -> **Version :** 2.64.0 | **Dernière mise à jour :** 2026-10-10 +> **Version :** 2.65.0 | **Dernière mise à jour :** 2026-10-10 > **Ce fichier ne contient que le travail à venir** (🔵 En cours + ⚪ Backlog) et un index compact > vers les fonctionnalités livrées. > - **Méthode de livraison à appliquer pour toute tâche : [DELIVERY_WORKFLOW.md](./DELIVERY_WORKFLOW.md)** @@ -46,7 +46,10 @@ - [x] Service `ensure_user_home()` idempotent : mkdir + vault + octroi, appelé à la création d'un user et au démarrage (réparation/migration) - [x] Retrait au suppression de compte (index/watcher/registre) sans supprimer le dossier - - [x] Montage Docker + `OBSIGATE_HOME_ROOT` dans `docker-compose.yml` + - [x] Montage Docker + `OBSIGATE_HOME_ROOT` (prod **et** compose de test + `docker-compose.test-win.yml` → `test_home:/vaults/Home`) + - [x] UI : vaults `home-*` en **premier** dans l'arborescence + icône maison + lucide (`getVaultIcon`), vérifié live sur l'instance 2020 - [x] Tests (création, persistance après rebuild, isolation 403 entre users) + docs --- diff --git a/docs/features/user-home-194.md b/docs/features/user-home-194.md index 547f067..e490360 100644 --- a/docs/features/user-home-194.md +++ b/docs/features/user-home-194.md @@ -70,6 +70,21 @@ suppression du compte, racine `/NFS/OBSIDIAN_DOC/Home` montée `/vaults/Home`. → vault refermé / dossier conservé) + absence de dossier sans `OBSIGATE_HOME_ROOT`. +## UI — arborescence (incrément) + +- **Ordre** : tri stable `home-*` en premier, appliqué à la source + (`frontend/js/sidebar.js::_homeFirst`, sur les deux sites qui alimentent + `state.allVaults`) → arborescence, sélecteurs et refreshs homogènes. +- **Icône** : `getVaultIcon()` (`frontend/js/viewer.js`) renvoie + `icon("home", size)` pour `home-*` → même pipeline lucide que le reste de + l'app (`safeCreateIcons`, `stroke: currentColor`, suit le thème). +- **Test local** : `docker-compose.test-win.yml` monte + `test_home:/vaults/Home` + `OBSIGATE_HOME_ROOT=/vaults/Home` + (`test_home/` est dans `.gitignore`). +- **Vérifié live** (instance 2020, Playwright) : ordre + `home-admin, home-bruno, TestDir, TestVault`, `svg.lucide-home` rendu, + placeholder `` remplacé. + ## Impact utilisateur Aucune nouvelle chaîne i18n : les noms de vault sont des données, la liste diff --git a/frontend/js/sidebar.js b/frontend/js/sidebar.js index 40b5fc9..99cae5e 100644 --- a/frontend/js/sidebar.js +++ b/frontend/js/sidebar.js @@ -220,8 +220,15 @@ async function loadVaultSettings() { // --------------------------------------------------------------------------- // Sidebar — Vault tree // --------------------------------------------------------------------------- +// #194 : le dossier personnel (vault « home- ») s'affiche en premier +// dans l'arborescence. Tri stable fait sur place, à la source de toutes les +// listes (arborescence, sélecteurs, state.allVaults). +const _homeFirst = (a, b) => + (String(b?.name).startsWith("home-") ? 1 : 0) - (String(a?.name).startsWith("home-") ? 1 : 0); + async function loadVaults() { const vaults = await api("/api/vaults"); + vaults.sort(_homeFirst); state.allVaults = vaults; const container = document.getElementById("vault-tree"); container.innerHTML = ""; @@ -426,6 +433,7 @@ export async function refreshSidebarTreePreservingState() { // 2. Soft update: vault names/counts without wiping the tree try { const vaults = await api("/api/vaults"); + vaults.sort(_homeFirst); state.allVaults = vaults; vaults.forEach((v) => { const vItem = document.querySelector(`.vault-item[data-vault="${CSS.escape(v.name)}"]`); diff --git a/frontend/js/viewer.js b/frontend/js/viewer.js index 7b6c942..38688fe 100644 --- a/frontend/js/viewer.js +++ b/frontend/js/viewer.js @@ -7579,6 +7579,10 @@ export function attachTreeItemLongPress(itemEl, getMenuData) { } export function getVaultIcon(vaultName, size = 16) { + // Dossier personnel (#194) : icône maison, même style lucide que le reste. + if (typeof vaultName === "string" && vaultName.startsWith("home-")) { + return icon("home", size); + } const v = state.allVaults.find((val) => val.name === vaultName); const type = v ? v.type : "VAULT"; diff --git a/package.json b/package.json index 905abc1..7d45b15 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "obsigate", - "version": "2.64.0", + "version": "2.65.0", "description": "**Porte d'entrée web ultra-léger pour vos vaults Obsidian** — Accédez, naviguez et recherchez dans toutes vos notes Obsidian depuis n'importe quel appareil via une interface web moderne et responsive.", "main": "patch.js", "directories": { diff --git a/tests/frontend/sidebar-filters.test.mjs b/tests/frontend/sidebar-filters.test.mjs index 80d1d1a..9160662 100644 --- a/tests/frontend/sidebar-filters.test.mjs +++ b/tests/frontend/sidebar-filters.test.mjs @@ -176,6 +176,19 @@ await test("filterSavedSearches combines with the type pills", async () => { assert.equal(visibleSaved(), 3, "clearing both filters restores everything"); }); +// ── #194 : icône du dossier personnel ── +await test("getVaultIcon returns the lucide house icon for home-* vaults", async () => { + const homeIcon = viewerMod.getVaultIcon("home-bruno", 16); + assert.equal(homeIcon.tagName.toLowerCase(), "i", "placeholder lucide (comme les autres icônes)"); + assert.equal(homeIcon.getAttribute("data-lucide"), "home", "icône maison lucide"); + assert.equal(homeIcon.style.width, "16px", "taille demandée respectée"); +}); + +await test("getVaultIcon is unchanged for regular vaults", async () => { + const vaultIcon = viewerMod.getVaultIcon("Recettes", 16); + assert.equal(vaultIcon.tagName.toLowerCase(), "svg", "gemme violette SVG d'origine"); +}); + // ── Summary ── console.log(`\n${passCount}/${testCount} tests passed`); if (passCount !== testCount) {