mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-08-24 22:41:26 -03:00
feat(recipes): add lora availability filter to recipe filter panel
This commit is contained in:
@@ -174,6 +174,11 @@ export async function fetchRecipesPage(page = 1, pageSize = 100) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Add LoRA availability filter (no statuses selected = no filtering)
|
||||
if (pageState.filters?.loraAvailability && pageState.filters.loraAvailability.length > 0) {
|
||||
params.append('lora_availability', pageState.filters.loraAvailability.join(','));
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch recipes
|
||||
|
||||
@@ -7,6 +7,10 @@ import { MODEL_TYPE_DISPLAY_NAMES } from '../utils/constants.js';
|
||||
import { translate } from '../utils/i18nHelpers.js';
|
||||
import { FilterPresetManager, EMPTY_WILDCARD_MARKER } from './FilterPresetManager.js';
|
||||
|
||||
// LoRA availability statuses available on the recipes page. No statuses
|
||||
// selected (the default) means no filtering.
|
||||
const LORA_AVAILABILITY_STATUSES = ['ready', 'missing', 'deleted'];
|
||||
|
||||
export class FilterManager {
|
||||
constructor(options = {}) {
|
||||
this.options = {
|
||||
@@ -74,6 +78,11 @@ export class FilterManager {
|
||||
this.initializeLicenseFilters();
|
||||
}
|
||||
|
||||
// Add click handlers for LoRA availability tags (recipes page only)
|
||||
if (this.shouldShowLoraAvailabilityFilter()) {
|
||||
this.initializeLoraAvailabilityFilters();
|
||||
}
|
||||
|
||||
// Initialize tag logic toggle
|
||||
this.initializeTagLogicToggle();
|
||||
|
||||
@@ -421,6 +430,42 @@ export class FilterManager {
|
||||
});
|
||||
}
|
||||
|
||||
initializeLoraAvailabilityFilters() {
|
||||
const availabilityTags = document.querySelectorAll('.lora-availability-tag');
|
||||
availabilityTags.forEach(tag => {
|
||||
tag.addEventListener('click', async () => {
|
||||
const status = tag.dataset.availability;
|
||||
const selected = this.filters.loraAvailability || [];
|
||||
|
||||
if (selected.includes(status)) {
|
||||
this.filters.loraAvailability = selected.filter(value => value !== status);
|
||||
tag.classList.remove('active');
|
||||
} else {
|
||||
this.filters.loraAvailability = [...selected, status];
|
||||
tag.classList.add('active');
|
||||
}
|
||||
|
||||
this.updateActiveFiltersCount();
|
||||
await this.applyFilters(false);
|
||||
});
|
||||
});
|
||||
|
||||
// Update selections based on stored filters
|
||||
this.updateLoraAvailabilitySelections();
|
||||
}
|
||||
|
||||
updateLoraAvailabilitySelections() {
|
||||
const availabilityTags = document.querySelectorAll('.lora-availability-tag');
|
||||
const selected = this.filters.loraAvailability || [];
|
||||
availabilityTags.forEach(tag => {
|
||||
if (selected.includes(tag.dataset.availability)) {
|
||||
tag.classList.add('active');
|
||||
} else {
|
||||
tag.classList.remove('active');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
createBaseModelTags() {
|
||||
const baseModelTagsContainer = document.getElementById('baseModelTags');
|
||||
if (!baseModelTagsContainer) return;
|
||||
@@ -681,6 +726,11 @@ export class FilterManager {
|
||||
}
|
||||
this.updateModelTypeSelections();
|
||||
|
||||
// Update LoRA availability tags if visible on this page
|
||||
if (this.shouldShowLoraAvailabilityFilter()) {
|
||||
this.updateLoraAvailabilitySelections();
|
||||
}
|
||||
|
||||
const autoTagEls = document.querySelectorAll('.auto-tag-filter');
|
||||
autoTagEls.forEach(el => {
|
||||
const tag = el.dataset.autoTag;
|
||||
@@ -708,7 +758,9 @@ export class FilterManager {
|
||||
const modelTypeFilterCount = this.filters.modelTypes.length;
|
||||
// Exclude EMPTY_WILDCARD_MARKER from base model count
|
||||
const baseModelCount = this.filters.baseModel.filter(m => m !== EMPTY_WILDCARD_MARKER).length;
|
||||
const totalActiveFilters = baseModelCount + tagFilterCount + autoTagFilterCount + licenseFilterCount + modelTypeFilterCount;
|
||||
// Active when at least one availability status is deselected
|
||||
const loraAvailabilityCount = this.filters.loraAvailability?.length ?? 0;
|
||||
const totalActiveFilters = baseModelCount + tagFilterCount + autoTagFilterCount + licenseFilterCount + modelTypeFilterCount + loraAvailabilityCount;
|
||||
|
||||
if (this.activeFiltersCount) {
|
||||
if (totalActiveFilters > 0) {
|
||||
@@ -805,6 +857,7 @@ export class FilterManager {
|
||||
autoTags: {},
|
||||
license: {},
|
||||
modelTypes: [],
|
||||
loraAvailability: [],
|
||||
tagLogic: 'any'
|
||||
});
|
||||
|
||||
@@ -891,12 +944,14 @@ export class FilterManager {
|
||||
const modelTypeCount = this.filters.modelTypes.length;
|
||||
// Exclude EMPTY_WILDCARD_MARKER from base model count
|
||||
const baseModelCount = this.filters.baseModel.filter(m => m !== EMPTY_WILDCARD_MARKER).length;
|
||||
const loraAvailabilityCount = this.filters.loraAvailability?.length ?? 0;
|
||||
return (
|
||||
baseModelCount > 0 ||
|
||||
tagCount > 0 ||
|
||||
autoTagCount > 0 ||
|
||||
licenseCount > 0 ||
|
||||
modelTypeCount > 0
|
||||
modelTypeCount > 0 ||
|
||||
loraAvailabilityCount > 0
|
||||
);
|
||||
}
|
||||
|
||||
@@ -909,6 +964,7 @@ export class FilterManager {
|
||||
autoTags: this.normalizeTagFilters(source.autoTags),
|
||||
license: this.shouldShowLicenseFilters() ? this.normalizeLicenseFilters(source.license) : {},
|
||||
modelTypes: this.normalizeModelTypeFilters(source.modelTypes),
|
||||
loraAvailability: this.normalizeLoraAvailabilityFilters(source.loraAvailability),
|
||||
tagLogic: source.tagLogic || 'any'
|
||||
};
|
||||
}
|
||||
@@ -917,6 +973,33 @@ export class FilterManager {
|
||||
return this.currentPage !== 'recipes';
|
||||
}
|
||||
|
||||
shouldShowLoraAvailabilityFilter() {
|
||||
return this.currentPage === 'recipes';
|
||||
}
|
||||
|
||||
normalizeLoraAvailabilityFilters(loraAvailability) {
|
||||
// Default to no statuses selected (= no filtering)
|
||||
if (!Array.isArray(loraAvailability)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const seen = new Set();
|
||||
return loraAvailability.reduce((acc, status) => {
|
||||
if (typeof status !== 'string') {
|
||||
return acc;
|
||||
}
|
||||
|
||||
const normalized = status.trim().toLowerCase();
|
||||
if (!LORA_AVAILABILITY_STATUSES.includes(normalized) || seen.has(normalized)) {
|
||||
return acc;
|
||||
}
|
||||
|
||||
seen.add(normalized);
|
||||
acc.push(normalized);
|
||||
return acc;
|
||||
}, []);
|
||||
}
|
||||
|
||||
normalizeTagFilters(tagFilters) {
|
||||
if (!tagFilters) {
|
||||
return {};
|
||||
@@ -994,6 +1077,7 @@ export class FilterManager {
|
||||
autoTags: { ...(this.filters.autoTags || {}) },
|
||||
license: { ...(this.filters.license || {}) },
|
||||
modelTypes: [...(this.filters.modelTypes || [])],
|
||||
loraAvailability: [...(this.filters.loraAvailability || [])],
|
||||
tagLogic: this.filters.tagLogic || 'any',
|
||||
search: pageState?.filters?.search ?? ''
|
||||
};
|
||||
|
||||
@@ -148,6 +148,7 @@ export const state = {
|
||||
tags: {},
|
||||
license: {},
|
||||
modelTypes: [],
|
||||
loraAvailability: [],
|
||||
search: ''
|
||||
},
|
||||
pageSize: 20,
|
||||
|
||||
Reference in New Issue
Block a user