feat: fichier filter dropdown + fonctionnel sur toutes les vues
FlowDeck CI / test (push) Failing after 12s
FlowDeck CI / docker (push) Has been skipped

- Dropdown Filter dans la toolbar (icône filtre, à côté de Sort)
- Menu avec Folders, Pages, PDF, Images, Code, Text + Clear filter
- doFilter() applique maintenant filterType au tree view via _filterTree()
- Filter chips visibles dans toutes les vues comme indicateur
- L'enhanced table prend le relais quand un filtre est actif dans les vues non-tree

143 tests passent
This commit is contained in:
2026-07-21 20:47:32 -04:00
parent 85b4d624b8
commit ce2bae1f1b
+27 -10
View File
@@ -484,6 +484,7 @@ window._wsInitData = (function() {
currentFolder: {{ current_folder_id }}, currentFolder: {{ current_folder_id }},
searchQuery: '', searchQuery: '',
filterType: '', filterType: '',
filterOpen: false,
editingPath: false, editingPath: false,
folderStack: [], folderStack: [],
@@ -1629,11 +1630,10 @@ window._wsInitData = (function() {
var q = (this.searchQuery || '').toLowerCase().trim(); var q = (this.searchQuery || '').toLowerCase().trim();
var ft = this.filterType || ''; var ft = this.filterType || '';
if (!q && !ft && !this.tagFilter) { this.displayTree = [...this.tree]; this.showAll = false; this._computeFilteredTableItems(); return; } if (!q && !ft && !this.tagFilter) { this.displayTree = [...this.tree]; this.showAll = false; this._computeFilteredTableItems(); return; }
// Apply all filters (search + type + tag) to tree view
this.displayTree = this._filterTree([...this.tree], q, ft);
if (this.tagFilter) { if (this.tagFilter) {
// Filter tree by tag this.displayTree = this._filterTreeByTag(this.displayTree, this.tagFilter);
this.displayTree = this._filterTreeByTag([...this.tree], this.tagFilter);
} else {
this.displayTree = [...this.tree];
} }
this._computeFilteredTableItems(); this._computeFilteredTableItems();
}, },
@@ -2309,6 +2309,23 @@ console.log('FLOWDECK v2.4.6 — IIFE done, _wsInitData keys:', Object.keys(wind
<div class="dd-item" :class="{active: sortBy==='date-desc'}" @click="sortBy='date-desc', doSort(), sortOpen=false"><span class="check" x-text="sortBy==='date-desc'?'✓':''"></span> Newest</div> <div class="dd-item" :class="{active: sortBy==='date-desc'}" @click="sortBy='date-desc', doSort(), sortOpen=false"><span class="check" x-text="sortBy==='date-desc'?'✓':''"></span> Newest</div>
</div> </div>
</div> </div>
<!-- Filter -->
<div class="lib-toolbar-wrap" style="position:relative;">
<button class="ws-icon-btn" :class="{active: filterOpen || filterType}" title="Filter" @click.stop="filterOpen=!filterOpen; viewMenuOpen=false; sortOpen=false">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polygon points="22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3"/></svg>
</button>
<div class="ws-dropdown" x-show="filterOpen" @click.outside="filterOpen=false" x-transition style="right:0;">
<div class="dd-label">File type</div>
<div class="dd-item" :class="{active: filterType==='folder'}" @click="filterByType('folder'), filterOpen=false"><span class="check" x-text="filterType==='folder'?'✓':''"></span>{{ fd_icon("folder",14) }} Folders</div>
<div class="dd-item" :class="{active: filterType==='page'}" @click="filterByType('page'), filterOpen=false"><span class="check" x-text="filterType==='page'?'✓':''"></span>{{ fd_icon("file",14) }} Pages</div>
<div class="dd-item" :class="{active: filterType==='pdf'}" @click="filterByType('pdf'), filterOpen=false"><span class="check" x-text="filterType==='pdf'?'✓':''"></span>{{ fd_icon("file",14) }} PDF</div>
<div class="dd-item" :class="{active: filterType==='image'}" @click="filterByType('image'), filterOpen=false"><span class="check" x-text="filterType==='image'?'✓':''"></span>{{ fd_icon("image",14) }} Images</div>
<div class="dd-item" :class="{active: filterType==='code'}" @click="filterByType('code'), filterOpen=false"><span class="check" x-text="filterType==='code'?'✓':''"></span>{{ fd_icon("file",14) }} Code</div>
<div class="dd-item" :class="{active: filterType==='text'}" @click="filterByType('text'), filterOpen=false"><span class="check" x-text="filterType==='text'?'✓':''"></span>{{ fd_icon("file",14) }} Text</div>
<div class="more-sep" x-show="filterType"></div>
<div class="dd-item" x-show="filterType" @click="filterType='', doFilter(), filterOpen=false" style="color:var(--text-dim);">{{ fd_icon("x",14) }} Clear filter</div>
</div>
</div>
<!-- Search toggle --> <!-- Search toggle -->
<button class="ws-icon-btn" :class="{active: searchOpen}" title="Search" @click.stop="searchOpen=!searchOpen; if(searchOpen) $nextTick(()=>$refs.searchInput?.focus())"> <button class="ws-icon-btn" :class="{active: searchOpen}" title="Search" @click.stop="searchOpen=!searchOpen; if(searchOpen) $nextTick(()=>$refs.searchInput?.focus())">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
@@ -2335,20 +2352,20 @@ console.log('FLOWDECK v2.4.6 — IIFE done, _wsInitData keys:', Object.keys(wind
</button> </button>
</div> </div>
<!-- Tree --> <!-- Filter chips (visual indicator when filter is active — shown in all views) -->
<div x-show="viewMode==='tree'" style="display:contents;"> <div class="filter-row" x-show="filterType" style="padding:4px 0;margin-bottom:6px;">
<!-- Compact filter row -->
<div class="filter-row" x-show="tree.length>0 || searchQuery || filterType">
<button class="filter-chip" :class="{ active: filterType === 'folder' }" @click="filterByType('folder')" title="Folders" x-html="getSvgIcon('folder',14)"></button> <button class="filter-chip" :class="{ active: filterType === 'folder' }" @click="filterByType('folder')" title="Folders" x-html="getSvgIcon('folder',14)"></button>
<button class="filter-chip" :class="{ active: filterType === 'page' }" @click="filterByType('page')" title="Pages" x-html="getSvgIcon('file',14)"></button> <button class="filter-chip" :class="{ active: filterType === 'page' }" @click="filterByType('page')" title="Pages" x-html="getSvgIcon('file',14)"></button>
<button class="filter-chip" :class="{ active: filterType === 'pdf' }" @click="filterByType('pdf')" title="PDF" x-html="getSvgIcon('file',14)"></button> <button class="filter-chip" :class="{ active: filterType === 'pdf' }" @click="filterByType('pdf')" title="PDF" x-html="getSvgIcon('file',14)"></button>
<button class="filter-chip" :class="{ active: filterType === 'image' }" @click="filterByType('image')" title="Images" x-html="getSvgIcon('image',14)"></button> <button class="filter-chip" :class="{ active: filterType === 'image' }" @click="filterByType('image')" title="Images" x-html="getSvgIcon('image',14)"></button>
<button class="filter-chip" :class="{ active: filterType === 'code' }" @click="filterByType('code')" title="Code" x-html="getSvgIcon('file',14)"></button> <button class="filter-chip" :class="{ active: filterType === 'code' }" @click="filterByType('code')" title="Code" x-html="getSvgIcon('file',14)"></button>
<button class="filter-chip" :class="{ active: filterType === 'text' }" @click="filterByType('text')" title="Text" x-html="getSvgIcon('file',14)"></button> <button class="filter-chip" :class="{ active: filterType === 'text' }" @click="filterByType('text')" title="Text" x-html="getSvgIcon('file',14)"></button>
<span x-show="filterType || searchQuery" class="filter-clear" @click="filterType='', searchQuery='', doFilter()">clear</span> <span class="filter-clear" @click="filterType='', doFilter()">clear filter</span>
</div> </div>
<!-- Tree -->
<div x-show="viewMode==='tree'" style="display:contents;">
<ul class="ws-tree" x-show="viewMode==='tree' && (displayTree.length>0 || (currentFolder > 0))" @click="handleTreeAction($event)"> <ul class="ws-tree" x-show="viewMode==='tree' && (displayTree.length>0 || (currentFolder > 0))" @click="handleTreeAction($event)">
<!-- Parent folder ".." --> <!-- Parent folder ".." -->
<li x-show="currentFolder > 0" style="list-style:none;"> <li x-show="currentFolder > 0" style="list-style:none;">