diff --git a/CHANGELOG.md b/CHANGELOG.md index 071a8e4..f038246 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog — FlowDeck +## v2.1.1 (2026-07-12) — Fix Arborescence Workspace + +### Fixed +- **Arborescence**: création fichier/dossier dans un sous-dossier met à jour l'arbre sans rechargement +- **parentFolder**: corrigé le bug où `parentFolder` était nullifié avant l'insertion dans l'arbre JS +- **displayTree**: nouvelle référence array après chaque mutation pour forcer le re-render Alpine.js +- **doSort/doFilter**: gèrent maintenant le cas où un filtre/tri est actif après création +- **_doUpload**: corrigé `this._reloadAfterAction` → `self._reloadAfterAction` + ## v2.1.0 (2026-07-10) — Intégrations Avancées ### Added diff --git a/app/main.py b/app/main.py index 414702a..82d32c8 100644 --- a/app/main.py +++ b/app/main.py @@ -39,7 +39,7 @@ async def lifespan(_app: FastAPI): app = FastAPI( title="FlowDeck", - version="2.1.0", + version="2.1.1", docs_url="/docs" if settings.log_level == "DEBUG" else None, redoc_url=None, lifespan=lifespan, diff --git a/app/templates/local_workspace.html b/app/templates/local_workspace.html index e92832f..cc1c13f 100644 --- a/app/templates/local_workspace.html +++ b/app/templates/local_workspace.html @@ -889,7 +889,7 @@ document.addEventListener('alpine:init', function() { // ── Sort ── doSort() { var s = this.sortBy; - if (!s) { this.displayTree = this.tree; return; } + if (!s) { this.displayTree = [...this.tree]; return; } var sorted = this.tree.slice(); if (s === 'name-asc') sorted.sort(function(a,b) { return (a.name||'').localeCompare(b.name||''); }); else if (s === 'name-desc') sorted.sort(function(a,b) { return (b.name||'').localeCompare(a.name||''); }); @@ -908,7 +908,9 @@ document.addEventListener('alpine:init', function() { if (!r.ok) { this.undoVisible = false; return; } // Remove from tree immediately this._removeFromTree(this.tree, this.undoItemId); - if (!this.searchQuery && !this.filterType && !this.sortBy) this.displayTree = this.tree; + if (!this.searchQuery && !this.filterType && !this.sortBy) this.displayTree = [...this.tree]; + else if (this.sortBy) this.doSort(); + else this.doFilter(); // Auto-dismiss + permanent after 5s this.undoTimeout = setTimeout(function() { self.undoVisible = false; @@ -1112,7 +1114,7 @@ document.addEventListener('alpine:init', function() { doFilter() { var q = (this.searchQuery || '').toLowerCase().trim(); var ft = this.filterType || ''; - if (!q && !ft) { this.displayTree = this.tree; return; } + if (!q && !ft) { this.displayTree = [...this.tree]; return; } var self = this; this.displayTree = this._filterTree(this.tree, q, ft); }, @@ -1197,6 +1199,8 @@ document.addEventListener('alpine:init', function() { }); if (r.ok) { var d = await r.json(); + // Save parent ref BEFORE clearing so we can insert into tree + var parent = this.parentFolder; this.showCreate = false; this.parentFolder = null; this.newName = ''; @@ -1208,19 +1212,25 @@ document.addEventListener('alpine:init', function() { content_format: isFolder ? null : 'blocks', children: [], has_children: false, depth: 0 }; - if (this.parentFolder && this.parentFolder.db_id) { + if (parent && parent.db_id) { // Insert as child of parent folder - this._insertIntoParent(this.tree, this.parentFolder.db_id, newNode); + this._insertIntoParent(this.tree, parent.db_id, newNode); // Auto-expand parent so the new item is visible - this.expanded[this.parentFolder.db_id] = true; + this.expanded[parent.db_id] = true; this.expanded = Object.assign({}, this.expanded); } else { // Insert at root this.tree.unshift(newNode); } - // Update displayTree + // Force new reference so Alpine x-for re-renders if (!this.searchQuery && !this.filterType) { - this.displayTree = this.tree; + this.displayTree = [...this.tree]; + } else if (this.sortBy) { + // Re-sort with the new item + this.doSort(); + } else { + // Re-apply filter with updated tree + this.doFilter(); } this._saveExpandedState(); } @@ -1498,7 +1508,7 @@ document.addEventListener('alpine:init', function() { var items = d.items || []; setTimeout(function() { self.uploading = false; - this._reloadAfterAction(); + self._reloadAfterAction(); }, 800); } else { this.uploadStatus = '✗ ' + (d.error || 'Upload failed');