feat(sidebar): add recursive search functionality and toggle button

This commit is contained in:
Will Miao
2025-10-09 17:07:10 +08:00
parent 2b6910bd55
commit d2c2bfbe6a
13 changed files with 124 additions and 26 deletions

View File

@@ -529,12 +529,15 @@
"title": "Embedding-Modelle"
},
"sidebar": {
"modelRoot": "Modell-Stammverzeichnis",
"modelRoot": "Stammverzeichnis",
"collapseAll": "Alle Ordner einklappen",
"pinSidebar": "Sidebar anheften",
"unpinSidebar": "Sidebar lösen",
"switchToListView": "Zur Listenansicht wechseln",
"switchToTreeView": "Zur Baumansicht wechseln",
"recursiveOn": "Unterordner durchsuchen",
"recursiveOff": "Nur aktuellen Ordner durchsuchen",
"recursiveUnavailable": "Rekursive Suche ist nur in der Baumansicht verfügbar",
"collapseAllDisabled": "Im Listenmodus nicht verfügbar"
},
"statistics": {

View File

@@ -529,12 +529,15 @@
"title": "Embedding Models"
},
"sidebar": {
"modelRoot": "Model Root",
"modelRoot": "Root",
"collapseAll": "Collapse All Folders",
"pinSidebar": "Pin Sidebar",
"unpinSidebar": "Unpin Sidebar",
"switchToListView": "Switch to List View",
"switchToTreeView": "Switch to Tree View",
"recursiveOn": "Search subfolders",
"recursiveOff": "Search current folder only",
"recursiveUnavailable": "Recursive search is available in tree view only",
"collapseAllDisabled": "Not available in list view"
},
"statistics": {

View File

@@ -529,12 +529,15 @@
"title": "Modelos embedding"
},
"sidebar": {
"modelRoot": "Raíz del modelo",
"modelRoot": "Raíz",
"collapseAll": "Colapsar todas las carpetas",
"pinSidebar": "Fijar barra lateral",
"unpinSidebar": "Desfijar barra lateral",
"switchToListView": "Cambiar a vista de lista",
"switchToTreeView": "Cambiar a vista de árbol",
"recursiveOn": "Buscar en subcarpetas",
"recursiveOff": "Buscar solo en la carpeta actual",
"recursiveUnavailable": "La búsqueda recursiva solo está disponible en la vista en árbol",
"collapseAllDisabled": "No disponible en vista de lista"
},
"statistics": {

View File

@@ -529,12 +529,15 @@
"title": "Modèles Embedding"
},
"sidebar": {
"modelRoot": "Racine du modèle",
"modelRoot": "Racine",
"collapseAll": "Réduire tous les dossiers",
"pinSidebar": "Épingler la barre latérale",
"unpinSidebar": "Désépingler la barre latérale",
"switchToListView": "Passer en vue liste",
"switchToTreeView": "Passer en vue arborescence",
"recursiveOn": "Rechercher dans les sous-dossiers",
"recursiveOff": "Rechercher uniquement dans le dossier actuel",
"recursiveUnavailable": "La recherche récursive n'est disponible qu'en vue arborescente",
"collapseAllDisabled": "Non disponible en vue liste"
},
"statistics": {

View File

@@ -529,12 +529,15 @@
"title": "מודלי Embedding"
},
"sidebar": {
"modelRoot": "שורש המודלים",
"modelRoot": "שורש",
"collapseAll": "כווץ את כל התיקיות",
"pinSidebar": "נעל סרגל צד",
"unpinSidebar": "שחרר סרגל צד",
"switchToListView": "עבור לתצוגת רשימה",
"switchToTreeView": "עבור לתצוגת עץ",
"switchToTreeView": "תצוגת עץ",
"recursiveOn": "חיפוש בתיקיות משנה",
"recursiveOff": "חיפוש רק בתיקייה הנוכחית",
"recursiveUnavailable": "חיפוש רקורסיבי זמין רק בתצוגת עץ",
"collapseAllDisabled": "לא זמין בתצוגת רשימה"
},
"statistics": {
@@ -1264,4 +1267,4 @@
"learnMore": "LM Civitai Extension Tutorial"
}
}
}
}

View File

@@ -529,12 +529,15 @@
"title": "Embeddingモデル"
},
"sidebar": {
"modelRoot": "モデルルート",
"modelRoot": "ルート",
"collapseAll": "すべてのフォルダを折りたたむ",
"pinSidebar": "サイドバーを固定",
"unpinSidebar": "サイドバーの固定を解除",
"switchToListView": "リストビューに切り替え",
"switchToTreeView": "ツリービューに切り替え",
"switchToTreeView": "ツリー表示に切り替え",
"recursiveOn": "サブフォルダーを検索",
"recursiveOff": "現在のフォルダーのみを検索",
"recursiveUnavailable": "再帰検索はツリービューでのみ利用できます",
"collapseAllDisabled": "リストビューでは利用できません"
},
"statistics": {
@@ -1264,4 +1267,4 @@
"learnMore": "LM Civitai Extension Tutorial"
}
}
}
}

View File

@@ -529,12 +529,15 @@
"title": "Embedding 모델"
},
"sidebar": {
"modelRoot": "모델 루트",
"modelRoot": "루트",
"collapseAll": "모든 폴더 접기",
"pinSidebar": "사이드바 고정",
"unpinSidebar": "사이드바 고정 해제",
"switchToListView": "목록 보기로 전환",
"switchToTreeView": "트리 보기로 전환",
"recursiveOn": "하위 폴더 검색",
"recursiveOff": "현재 폴더만 검색",
"recursiveUnavailable": "재귀 검색은 트리 보기에서만 사용할 수 있습니다",
"collapseAllDisabled": "목록 보기에서는 사용할 수 없습니다"
},
"statistics": {
@@ -1264,4 +1267,4 @@
"learnMore": "LM Civitai Extension Tutorial"
}
}
}
}

View File

@@ -529,12 +529,15 @@
"title": "Модели Embedding"
},
"sidebar": {
"modelRoot": "Корень моделей",
"modelRoot": "Корень",
"collapseAll": "Свернуть все папки",
"pinSidebar": "Закрепить боковую панель",
"unpinSidebar": "Открепить боковую панель",
"switchToListView": "Переключить на вид списка",
"switchToTreeView": "Переключить на древовидный вид",
"recursiveOn": "Искать во вложенных папках",
"recursiveOff": "Искать только в текущей папке",
"recursiveUnavailable": "Рекурсивный поиск доступен только в режиме дерева",
"collapseAllDisabled": "Недоступно в виде списка"
},
"statistics": {
@@ -1264,4 +1267,4 @@
"learnMore": "LM Civitai Extension Tutorial"
}
}
}
}

View File

@@ -535,12 +535,15 @@
"title": "Embedding 模型"
},
"sidebar": {
"modelRoot": "模型根目录",
"modelRoot": "根目录",
"collapseAll": "折叠所有文件夹",
"pinSidebar": "固定侧边栏",
"unpinSidebar": "取消固定侧边栏",
"switchToListView": "切换到列表视图",
"switchToTreeView": "切换到树状视图",
"recursiveOn": "搜索子文件夹",
"recursiveOff": "仅搜索当前文件夹",
"recursiveUnavailable": "仅在树形视图中可使用递归搜索",
"collapseAllDisabled": "列表视图下不可用"
},
"statistics": {
@@ -1270,4 +1273,4 @@
"learnMore": "LM Civitai Extension Tutorial"
}
}
}
}

View File

@@ -529,12 +529,15 @@
"title": "Embedding 模型"
},
"sidebar": {
"modelRoot": "模型根目錄",
"modelRoot": "根目錄",
"collapseAll": "全部摺疊資料夾",
"pinSidebar": "固定側邊欄",
"unpinSidebar": "取消固定側邊欄",
"switchToListView": "切換至列表檢視",
"switchToTreeView": "切換樹狀檢視",
"switchToTreeView": "切換樹狀檢視",
"recursiveOn": "搜尋子資料夾",
"recursiveOff": "僅搜尋目前資料夾",
"recursiveUnavailable": "遞迴搜尋僅能在樹狀檢視中使用",
"collapseAllDisabled": "列表檢視下不可用"
},
"statistics": {
@@ -1264,4 +1267,4 @@
"learnMore": "LM Civitai Extension Tutorial"
}
}
}
}

View File

@@ -21,6 +21,7 @@ export class SidebarManager {
this.isInitialized = false;
this.displayMode = 'tree'; // 'tree' or 'list'
this.foldersList = [];
this.recursiveSearchEnabled = true;
// Bind methods
this.handleTreeClick = this.handleTreeClick.bind(this);
@@ -36,6 +37,7 @@ export class SidebarManager {
this.updateContainerMargin = this.updateContainerMargin.bind(this);
this.handleDisplayModeToggle = this.handleDisplayModeToggle.bind(this);
this.handleFolderListClick = this.handleFolderListClick.bind(this);
this.handleRecursiveToggle = this.handleRecursiveToggle.bind(this);
}
async initialize(pageControls) {
@@ -89,6 +91,7 @@ export class SidebarManager {
this.isHovering = false;
this.apiClient = null;
this.isInitialized = false;
this.recursiveSearchEnabled = true;
// Reset container margin
const container = document.querySelector('.container');
@@ -111,6 +114,7 @@ export class SidebarManager {
const sidebar = document.getElementById('folderSidebar');
const hoverArea = document.getElementById('sidebarHoverArea');
const displayModeToggleBtn = document.getElementById('sidebarDisplayModeToggle');
const recursiveToggleBtn = document.getElementById('sidebarRecursiveToggle');
if (pinToggleBtn) {
pinToggleBtn.removeEventListener('click', this.handlePinToggle);
@@ -145,6 +149,9 @@ export class SidebarManager {
if (displayModeToggleBtn) {
displayModeToggleBtn.removeEventListener('click', this.handleDisplayModeToggle);
}
if (recursiveToggleBtn) {
recursiveToggleBtn.removeEventListener('click', this.handleRecursiveToggle);
}
}
async init() {
@@ -197,7 +204,7 @@ export class SidebarManager {
updateSidebarTitle() {
const sidebarTitle = document.getElementById('sidebarTitle');
if (sidebarTitle) {
sidebarTitle.textContent = `${this.apiClient.apiConfig.config.displayName} Root`;
sidebarTitle.textContent = translate('sidebar.modelRoot');
}
}
@@ -220,6 +227,12 @@ export class SidebarManager {
collapseAllBtn.addEventListener('click', this.handleCollapseAll);
}
// Recursive toggle button
const recursiveToggleBtn = document.getElementById('sidebarRecursiveToggle');
if (recursiveToggleBtn) {
recursiveToggleBtn.addEventListener('click', this.handleRecursiveToggle);
}
// Tree click handler
const folderTree = document.getElementById('sidebarFolderTree');
if (folderTree) {
@@ -645,11 +658,33 @@ export class SidebarManager {
this.displayMode = this.displayMode === 'tree' ? 'list' : 'tree';
this.updateDisplayModeButton();
this.updateCollapseAllButton();
this.updateRecursiveToggleButton();
this.updateSearchRecursiveOption();
this.saveDisplayMode();
this.loadFolderTree(); // Reload with new display mode
}
async handleRecursiveToggle(event) {
event.stopPropagation();
if (this.displayMode !== 'tree') {
return;
}
this.recursiveSearchEnabled = !this.recursiveSearchEnabled;
setStorageItem(`${this.pageType}_recursiveSearch`, this.recursiveSearchEnabled);
this.updateSearchRecursiveOption();
this.updateRecursiveToggleButton();
if (this.pageControls && typeof this.pageControls.resetAndReload === 'function') {
try {
await this.pageControls.resetAndReload(true);
} catch (error) {
console.error('Failed to reload models after toggling recursive search:', error);
}
}
}
updateDisplayModeButton() {
const displayModeBtn = document.getElementById('sidebarDisplayModeToggle');
if (displayModeBtn) {
@@ -679,8 +714,35 @@ export class SidebarManager {
}
}
updateRecursiveToggleButton() {
const recursiveToggleBtn = document.getElementById('sidebarRecursiveToggle');
if (!recursiveToggleBtn) return;
const icon = recursiveToggleBtn.querySelector('i');
const isTreeMode = this.displayMode === 'tree';
const isActive = isTreeMode && this.recursiveSearchEnabled;
recursiveToggleBtn.classList.toggle('active', isActive);
recursiveToggleBtn.classList.toggle('disabled', !isTreeMode);
recursiveToggleBtn.setAttribute('aria-pressed', isActive ? 'true' : 'false');
recursiveToggleBtn.setAttribute('aria-disabled', isTreeMode ? 'false' : 'true');
if (icon) {
icon.className = 'fas fa-code-branch';
}
if (!isTreeMode) {
recursiveToggleBtn.title = translate('sidebar.recursiveUnavailable');
} else if (this.recursiveSearchEnabled) {
recursiveToggleBtn.title = translate('sidebar.recursiveOn');
} else {
recursiveToggleBtn.title = translate('sidebar.recursiveOff');
}
}
updateSearchRecursiveOption() {
this.pageControls.pageState.searchOptions.recursive = this.displayMode === 'tree';
const isRecursive = this.displayMode === 'tree' && this.recursiveSearchEnabled;
this.pageControls.pageState.searchOptions.recursive = isRecursive;
}
updateTreeSelection() {
@@ -925,15 +987,18 @@ export class SidebarManager {
const isPinned = getStorageItem(`${this.pageType}_sidebarPinned`, true);
const expandedPaths = getStorageItem(`${this.pageType}_expandedNodes`, []);
const displayMode = getStorageItem(`${this.pageType}_displayMode`, 'tree'); // 'tree' or 'list', default to 'tree'
const recursiveSearchEnabled = getStorageItem(`${this.pageType}_recursiveSearch`, true);
this.isPinned = isPinned;
this.expandedNodes = new Set(expandedPaths);
this.displayMode = displayMode;
this.recursiveSearchEnabled = recursiveSearchEnabled;
this.updatePinButton();
this.updateDisplayModeButton();
this.updateCollapseAllButton();
this.updateSearchRecursiveOption();
this.updateRecursiveToggleButton();
}
restoreSelectedFolder() {
@@ -974,4 +1039,4 @@ export class SidebarManager {
}
// Create and export global instance
export const sidebarManager = new SidebarManager();
export const sidebarManager = new SidebarManager();

View File

@@ -67,7 +67,7 @@ export const state = {
modelname: true,
tags: false,
creator: false,
recursive: true,
recursive: getStorageItem(`${MODEL_TYPES.LORA}_recursiveSearch`, true),
},
filters: {
baseModel: [],
@@ -116,7 +116,7 @@ export const state = {
filename: true,
modelname: true,
creator: false,
recursive: true,
recursive: getStorageItem(`${MODEL_TYPES.CHECKPOINT}_recursiveSearch`, true),
},
filters: {
baseModel: [],
@@ -144,7 +144,7 @@ export const state = {
modelname: true,
tags: false,
creator: false,
recursive: true,
recursive: getStorageItem(`${MODEL_TYPES.EMBEDDING}_recursiveSearch`, true),
},
filters: {
baseModel: [],
@@ -261,4 +261,4 @@ export function initPageState(pageType) {
return getCurrentPageState();
}
return null;
}
}

View File

@@ -9,6 +9,9 @@
<button class="sidebar-action-btn" id="sidebarDisplayModeToggle" title="{{ t('sidebar.switchToListView') }}">
<i class="fas fa-sitemap"></i>
</button>
<button class="sidebar-action-btn active" id="sidebarRecursiveToggle" title="{{ t('sidebar.recursiveOn') }}" aria-pressed="true">
<i class="fas fa-code-branch"></i>
</button>
<button class="sidebar-action-btn" id="sidebarCollapseAll" title="{{ t('sidebar.collapseAll') }}">
<i class="fas fa-compress-alt"></i>
</button>