diff --git a/locales/de.json b/locales/de.json
index fcab555a..b52eeead 100644
--- a/locales/de.json
+++ b/locales/de.json
@@ -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": {
diff --git a/locales/en.json b/locales/en.json
index 9fff5e22..49fd7004 100644
--- a/locales/en.json
+++ b/locales/en.json
@@ -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": {
diff --git a/locales/es.json b/locales/es.json
index 3cb739a0..84268244 100644
--- a/locales/es.json
+++ b/locales/es.json
@@ -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": {
diff --git a/locales/fr.json b/locales/fr.json
index 21e965c4..69360a8d 100644
--- a/locales/fr.json
+++ b/locales/fr.json
@@ -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": {
diff --git a/locales/he.json b/locales/he.json
index a273c451..2c9a7f66 100644
--- a/locales/he.json
+++ b/locales/he.json
@@ -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"
}
}
-}
+}
\ No newline at end of file
diff --git a/locales/ja.json b/locales/ja.json
index 61bfb9ea..319d46aa 100644
--- a/locales/ja.json
+++ b/locales/ja.json
@@ -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"
}
}
-}
+}
\ No newline at end of file
diff --git a/locales/ko.json b/locales/ko.json
index aae9ed40..98813f25 100644
--- a/locales/ko.json
+++ b/locales/ko.json
@@ -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"
}
}
-}
+}
\ No newline at end of file
diff --git a/locales/ru.json b/locales/ru.json
index 7ae561ae..ab6a2e5a 100644
--- a/locales/ru.json
+++ b/locales/ru.json
@@ -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"
}
}
-}
+}
\ No newline at end of file
diff --git a/locales/zh-CN.json b/locales/zh-CN.json
index d8a20d70..ecc4edb8 100644
--- a/locales/zh-CN.json
+++ b/locales/zh-CN.json
@@ -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"
}
}
-}
+}
\ No newline at end of file
diff --git a/locales/zh-TW.json b/locales/zh-TW.json
index 09856038..53ed58be 100644
--- a/locales/zh-TW.json
+++ b/locales/zh-TW.json
@@ -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"
}
}
-}
+}
\ No newline at end of file
diff --git a/static/js/components/SidebarManager.js b/static/js/components/SidebarManager.js
index 674fe825..dffe8f18 100644
--- a/static/js/components/SidebarManager.js
+++ b/static/js/components/SidebarManager.js
@@ -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();
\ No newline at end of file
+export const sidebarManager = new SidebarManager();
diff --git a/static/js/state/index.js b/static/js/state/index.js
index 6f0cedd1..43f30454 100644
--- a/static/js/state/index.js
+++ b/static/js/state/index.js
@@ -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;
-}
\ No newline at end of file
+}
diff --git a/templates/components/folder_sidebar.html b/templates/components/folder_sidebar.html
index 9fdbc3fe..5f3748c8 100644
--- a/templates/components/folder_sidebar.html
+++ b/templates/components/folder_sidebar.html
@@ -9,6 +9,9 @@
+