mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-05-08 01:16:43 -03:00
feat(bulk): add bulk favorite/unfavorite toggle with context-sensitive single menu item
Replaces two separate menu items with a single smart item that dynamically switches between 'Set as Favorite' and 'Remove from Favorites' based on whether all selected items are already favorited. Shows a count badge '(3/5)' when only some items are favorited in a mixed selection. Supports all model types (LoRA, Checkpoint, Embedding) and recipes via existing per-item save/update API — no backend changes needed.
This commit is contained in:
@@ -3,7 +3,7 @@ import { showToast, copyToClipboard, sendLoraToWorkflow, buildLoraSyntax, getNSF
|
||||
import { updateCardsForBulkMode } from '../components/shared/ModelCard.js';
|
||||
import { modalManager } from './ModalManager.js';
|
||||
import { getModelApiClient, resetAndReload } from '../api/modelApiFactory.js';
|
||||
import { RecipeSidebarApiClient } from '../api/recipeApi.js';
|
||||
import { RecipeSidebarApiClient, updateRecipeMetadata } from '../api/recipeApi.js';
|
||||
import { MODEL_TYPES, MODEL_CONFIG } from '../api/apiConfig.js';
|
||||
import { BASE_MODEL_CATEGORIES } from '../utils/constants.js';
|
||||
import { getPriorityTagSuggestions } from '../utils/priorityTagHelpers.js';
|
||||
@@ -41,7 +41,9 @@ export class BulkManager {
|
||||
autoOrganize: true,
|
||||
deleteAll: true,
|
||||
setContentRating: true,
|
||||
skipMetadataRefresh: true
|
||||
skipMetadataRefresh: true,
|
||||
setFavorite: true,
|
||||
unfavorite: true
|
||||
},
|
||||
[MODEL_TYPES.EMBEDDING]: {
|
||||
addTags: true,
|
||||
@@ -53,7 +55,9 @@ export class BulkManager {
|
||||
autoOrganize: true,
|
||||
deleteAll: true,
|
||||
setContentRating: false,
|
||||
skipMetadataRefresh: true
|
||||
skipMetadataRefresh: true,
|
||||
setFavorite: true,
|
||||
unfavorite: true
|
||||
},
|
||||
[MODEL_TYPES.CHECKPOINT]: {
|
||||
addTags: true,
|
||||
@@ -65,7 +69,9 @@ export class BulkManager {
|
||||
autoOrganize: true,
|
||||
deleteAll: true,
|
||||
setContentRating: true,
|
||||
skipMetadataRefresh: true
|
||||
skipMetadataRefresh: true,
|
||||
setFavorite: true,
|
||||
unfavorite: true
|
||||
},
|
||||
recipes: {
|
||||
addTags: false,
|
||||
@@ -77,7 +83,9 @@ export class BulkManager {
|
||||
autoOrganize: false,
|
||||
deleteAll: true,
|
||||
setContentRating: false,
|
||||
skipMetadataRefresh: false
|
||||
skipMetadataRefresh: false,
|
||||
setFavorite: true,
|
||||
unfavorite: true
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1090,6 +1098,60 @@ export class BulkManager {
|
||||
}
|
||||
}
|
||||
|
||||
async setBulkFavorites(value) {
|
||||
if (state.selectedModels.size === 0) {
|
||||
showToast('toast.models.noModelsSelected', {}, 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
const totalCount = state.selectedModels.size;
|
||||
const isRecipesPage = state.currentPageType === 'recipes';
|
||||
|
||||
state.loadingManager.showSimpleLoading(
|
||||
translate(value ? 'toast.models.bulkFavoriteUpdating' : 'toast.models.bulkUnfavoriteUpdating', { count: totalCount })
|
||||
);
|
||||
let cancelled = false;
|
||||
state.loadingManager.showCancelButton(() => {
|
||||
cancelled = true;
|
||||
});
|
||||
|
||||
let successCount = 0;
|
||||
let failureCount = 0;
|
||||
|
||||
try {
|
||||
for (const filePath of state.selectedModels) {
|
||||
if (cancelled) {
|
||||
showToast('toast.api.operationCancelled', {}, 'info');
|
||||
break;
|
||||
}
|
||||
try {
|
||||
if (isRecipesPage) {
|
||||
await updateRecipeMetadata(filePath, { favorite: value });
|
||||
} else {
|
||||
const apiClient = getModelApiClient();
|
||||
await apiClient.saveModelMetadata(filePath, { favorite: value });
|
||||
}
|
||||
successCount++;
|
||||
} catch (error) {
|
||||
failureCount++;
|
||||
console.error(`Failed to set favorite=${value} for ${filePath}:`, error);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
state.loadingManager?.hide?.();
|
||||
}
|
||||
|
||||
if (successCount === totalCount) {
|
||||
const toastKey = value ? 'modelCard.favorites.added' : 'modelCard.favorites.removed';
|
||||
showToast(toastKey, {}, 'success');
|
||||
} else if (successCount > 0) {
|
||||
const toastKey = value ? 'toast.models.bulkFavoritePartialAdded' : 'toast.models.bulkFavoritePartialRemoved';
|
||||
showToast(toastKey, { success: successCount, failed: failureCount }, 'warning');
|
||||
} else {
|
||||
showToast('toast.models.bulkFavoriteFailed', {}, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show bulk base model modal
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user