mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-05-06 16:36:45 -03:00
fix(filters): improve base model filtering UX
This commit is contained in:
@@ -240,9 +240,7 @@ export class BulkManager {
|
||||
*/
|
||||
handleGlobalKeyboard(e) {
|
||||
// Skip if modal is open (handled by event manager conditions)
|
||||
// Skip if search input is focused
|
||||
const searchInput = document.getElementById('searchInput');
|
||||
if (searchInput && document.activeElement === searchInput) {
|
||||
if (this.isEditingTextInputContext(e.target)) {
|
||||
return false; // Don't handle, allow default behavior
|
||||
}
|
||||
|
||||
@@ -266,6 +264,26 @@ export class BulkManager {
|
||||
return false; // Continue with other handlers
|
||||
}
|
||||
|
||||
isEditingTextInputContext(target) {
|
||||
const activeElement = document.activeElement;
|
||||
const candidate = target instanceof Element ? target : activeElement;
|
||||
if (!candidate) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const tagName = candidate.tagName?.toLowerCase();
|
||||
if (
|
||||
candidate.isContentEditable
|
||||
|| tagName === 'input'
|
||||
|| tagName === 'textarea'
|
||||
|| tagName === 'select'
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return Boolean(candidate.closest?.('#filterPanel'));
|
||||
}
|
||||
|
||||
toggleBulkMode() {
|
||||
state.bulkMode = !state.bulkMode;
|
||||
|
||||
|
||||
@@ -20,6 +20,8 @@ export class FilterManager {
|
||||
this.filterPanel = document.getElementById('filterPanel');
|
||||
this.filterButton = document.getElementById('filterButton');
|
||||
this.activeFiltersCount = document.getElementById('activeFiltersCount');
|
||||
this.baseModelSearchInput = document.getElementById('baseModelSearchInput');
|
||||
this.baseModelOptions = [];
|
||||
this.tagsLoaded = false;
|
||||
|
||||
// Initialize preset manager
|
||||
@@ -49,6 +51,8 @@ export class FilterManager {
|
||||
}
|
||||
|
||||
initialize() {
|
||||
this.initializeFilterSearchInputs();
|
||||
|
||||
// Create base model filter tags if they exist
|
||||
if (document.getElementById('baseModelTags')) {
|
||||
this.createBaseModelTags();
|
||||
@@ -110,6 +114,18 @@ export class FilterManager {
|
||||
this.updateTagLogicToggleUI();
|
||||
}
|
||||
|
||||
initializeFilterSearchInputs() {
|
||||
if (this.baseModelSearchInput) {
|
||||
this.baseModelSearchInput.addEventListener('input', () => {
|
||||
this.renderBaseModelTags();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
getNormalizedSearchQuery(input) {
|
||||
return (input?.value || '').trim().toLowerCase();
|
||||
}
|
||||
|
||||
updateTagLogicToggleUI() {
|
||||
const toggleContainer = document.getElementById('tagLogicToggle');
|
||||
if (!toggleContainer) return;
|
||||
@@ -164,11 +180,6 @@ export class FilterManager {
|
||||
|
||||
tagsContainer.innerHTML = '';
|
||||
|
||||
if (!tags.length) {
|
||||
tagsContainer.innerHTML = `<div class="no-tags">No ${this.currentPage === 'recipes' ? 'recipe ' : ''}tags available</div>`;
|
||||
return;
|
||||
}
|
||||
|
||||
// Collect existing tag names from the API response
|
||||
const existingTagNames = new Set(tags.map(t => t.tag));
|
||||
|
||||
@@ -186,6 +197,11 @@ export class FilterManager {
|
||||
});
|
||||
}
|
||||
|
||||
if (!tags.length) {
|
||||
tagsContainer.innerHTML = `<div class="no-tags">No ${this.currentPage === 'recipes' ? 'recipe ' : ''}tags available</div>`;
|
||||
return;
|
||||
}
|
||||
|
||||
tags.forEach(tag => {
|
||||
const tagEl = document.createElement('div');
|
||||
tagEl.className = 'filter-tag tag-filter';
|
||||
@@ -212,7 +228,6 @@ export class FilterManager {
|
||||
await this.applyFilters(false);
|
||||
});
|
||||
|
||||
this.applyTagElementState(tagEl, (this.filters.tags && this.filters.tags[tagName]) || 'none');
|
||||
tagsContainer.appendChild(tagEl);
|
||||
});
|
||||
|
||||
@@ -235,8 +250,8 @@ export class FilterManager {
|
||||
await this.applyFilters(false);
|
||||
});
|
||||
|
||||
this.applyTagElementState(noTagsEl, (this.filters.tags && this.filters.tags[noTagsKey]) || 'none');
|
||||
tagsContainer.appendChild(noTagsEl);
|
||||
this.updateTagSelections();
|
||||
}
|
||||
|
||||
initializeLicenseFilters() {
|
||||
@@ -323,44 +338,15 @@ export class FilterManager {
|
||||
if (!baseModelTagsContainer) return;
|
||||
|
||||
// Set the API endpoint based on current page
|
||||
const apiEndpoint = `/api/lm/${this.currentPage}/base-models`;
|
||||
const apiEndpoint = `/api/lm/${this.currentPage}/base-models?limit=0`;
|
||||
|
||||
// Fetch base models
|
||||
fetch(apiEndpoint)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success && data.base_models) {
|
||||
baseModelTagsContainer.innerHTML = '';
|
||||
|
||||
data.base_models.forEach(model => {
|
||||
const tag = document.createElement('div');
|
||||
tag.className = `filter-tag base-model-tag`;
|
||||
tag.dataset.baseModel = model.name;
|
||||
tag.innerHTML = `${model.name} <span class="tag-count">${model.count}</span>`;
|
||||
|
||||
// Add click handler to toggle selection and automatically apply
|
||||
tag.addEventListener('click', async () => {
|
||||
tag.classList.toggle('active');
|
||||
|
||||
if (tag.classList.contains('active')) {
|
||||
if (!this.filters.baseModel.includes(model.name)) {
|
||||
this.filters.baseModel.push(model.name);
|
||||
}
|
||||
} else {
|
||||
this.filters.baseModel = this.filters.baseModel.filter(m => m !== model.name);
|
||||
}
|
||||
|
||||
this.updateActiveFiltersCount();
|
||||
|
||||
// Auto-apply filter when tag is clicked
|
||||
await this.applyFilters(false);
|
||||
});
|
||||
|
||||
baseModelTagsContainer.appendChild(tag);
|
||||
});
|
||||
|
||||
// Update selections based on stored filters
|
||||
this.updateTagSelections();
|
||||
this.baseModelOptions = data.base_models;
|
||||
this.renderBaseModelTags();
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
@@ -369,6 +355,57 @@ export class FilterManager {
|
||||
});
|
||||
}
|
||||
|
||||
renderBaseModelTags() {
|
||||
const baseModelTagsContainer = document.getElementById('baseModelTags');
|
||||
const emptyState = document.getElementById('baseModelEmptyState');
|
||||
if (!baseModelTagsContainer) return;
|
||||
|
||||
baseModelTagsContainer.innerHTML = '';
|
||||
|
||||
if (!this.baseModelOptions.length) {
|
||||
baseModelTagsContainer.innerHTML = '<div class="no-tags">No base models available</div>';
|
||||
if (emptyState) {
|
||||
emptyState.hidden = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const query = this.getNormalizedSearchQuery(this.baseModelSearchInput);
|
||||
const filteredModels = query
|
||||
? this.baseModelOptions.filter(model => model.name.toLowerCase().includes(query))
|
||||
: this.baseModelOptions;
|
||||
|
||||
filteredModels.forEach(model => {
|
||||
const tag = document.createElement('div');
|
||||
tag.className = 'filter-tag base-model-tag';
|
||||
tag.dataset.baseModel = model.name;
|
||||
tag.innerHTML = `${model.name} <span class="tag-count">${model.count}</span>`;
|
||||
|
||||
tag.addEventListener('click', async () => {
|
||||
tag.classList.toggle('active');
|
||||
|
||||
if (tag.classList.contains('active')) {
|
||||
if (!this.filters.baseModel.includes(model.name)) {
|
||||
this.filters.baseModel.push(model.name);
|
||||
}
|
||||
} else {
|
||||
this.filters.baseModel = this.filters.baseModel.filter(m => m !== model.name);
|
||||
}
|
||||
|
||||
this.updateActiveFiltersCount();
|
||||
await this.applyFilters(false);
|
||||
});
|
||||
|
||||
baseModelTagsContainer.appendChild(tag);
|
||||
});
|
||||
|
||||
if (emptyState) {
|
||||
emptyState.hidden = filteredModels.length > 0;
|
||||
}
|
||||
|
||||
this.updateTagSelections();
|
||||
}
|
||||
|
||||
async createModelTypeTags() {
|
||||
const modelTypeContainer = document.getElementById('modelTypeTags');
|
||||
if (!modelTypeContainer) return;
|
||||
@@ -453,6 +490,7 @@ export class FilterManager {
|
||||
|
||||
this.filterPanel.classList.remove('hidden');
|
||||
this.filterButton.classList.add('active');
|
||||
this.baseModelSearchInput?.focus();
|
||||
|
||||
// Load tags if they haven't been loaded yet
|
||||
if (!this.tagsLoaded) {
|
||||
|
||||
Reference in New Issue
Block a user