mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-03-21 21:22:11 -03:00
feat: enhance skip metadata refresh with smart UI and subtle badges, #790
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import { BaseContextMenu } from './BaseContextMenu.js';
|
||||
import { state } from '../../state/index.js';
|
||||
import { bulkManager } from '../../managers/BulkManager.js';
|
||||
import { updateElementText } from '../../utils/i18nHelpers.js';
|
||||
import { updateElementText, translate } from '../../utils/i18nHelpers.js';
|
||||
|
||||
export class BulkContextMenu extends BaseContextMenu {
|
||||
constructor() {
|
||||
@@ -71,6 +71,40 @@ export class BulkContextMenu extends BaseContextMenu {
|
||||
if (setContentRatingItem) {
|
||||
setContentRatingItem.style.display = config.setContentRating ? 'flex' : 'none';
|
||||
}
|
||||
|
||||
const skipMetadataRefreshItem = this.menu.querySelector('[data-action="skip-metadata-refresh"]');
|
||||
const resumeMetadataRefreshItem = this.menu.querySelector('[data-action="resume-metadata-refresh"]');
|
||||
|
||||
if (skipMetadataRefreshItem && resumeMetadataRefreshItem) {
|
||||
const skipCount = this.countSkipStatus(true);
|
||||
const resumeCount = this.countSkipStatus(false);
|
||||
const totalCount = skipCount + resumeCount;
|
||||
|
||||
if (skipCount === totalCount) {
|
||||
skipMetadataRefreshItem.style.display = 'none';
|
||||
resumeMetadataRefreshItem.style.display = 'flex';
|
||||
resumeMetadataRefreshItem.querySelector('span').textContent = translate(
|
||||
'loras.bulkOperations.resumeMetadataRefresh'
|
||||
);
|
||||
} else if (resumeCount === totalCount) {
|
||||
skipMetadataRefreshItem.style.display = 'flex';
|
||||
resumeMetadataRefreshItem.style.display = 'none';
|
||||
skipMetadataRefreshItem.querySelector('span').textContent = translate(
|
||||
'loras.bulkOperations.skipMetadataRefresh'
|
||||
);
|
||||
} else {
|
||||
skipMetadataRefreshItem.style.display = 'flex';
|
||||
resumeMetadataRefreshItem.style.display = 'flex';
|
||||
skipMetadataRefreshItem.querySelector('span').textContent = translate(
|
||||
'loras.bulkOperations.skipMetadataRefreshCount',
|
||||
{ count: resumeCount }
|
||||
);
|
||||
resumeMetadataRefreshItem.querySelector('span').textContent = translate(
|
||||
'loras.bulkOperations.resumeMetadataRefreshCount',
|
||||
{ count: skipCount }
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateSelectedCountHeader() {
|
||||
@@ -80,6 +114,20 @@ export class BulkContextMenu extends BaseContextMenu {
|
||||
}
|
||||
}
|
||||
|
||||
countSkipStatus(skipState) {
|
||||
let count = 0;
|
||||
for (const filePath of state.selectedModels) {
|
||||
const card = document.querySelector(`.model-card[data-filepath="${filePath}"]`);
|
||||
if (card) {
|
||||
const isSkipped = card.dataset.skip_metadata_refresh === 'true';
|
||||
if (isSkipped === skipState) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
showMenu(x, y, card) {
|
||||
this.updateMenuItemsForModelType();
|
||||
this.updateSelectedCountHeader();
|
||||
@@ -118,6 +166,12 @@ export class BulkContextMenu extends BaseContextMenu {
|
||||
case 'auto-organize':
|
||||
bulkManager.autoOrganizeSelectedModels();
|
||||
break;
|
||||
case 'skip-metadata-refresh':
|
||||
bulkManager.setSkipMetadataRefresh(true);
|
||||
break;
|
||||
case 'resume-metadata-refresh':
|
||||
bulkManager.setSkipMetadataRefresh(false);
|
||||
break;
|
||||
case 'delete-all':
|
||||
bulkManager.showBulkDeleteModal();
|
||||
break;
|
||||
|
||||
@@ -433,9 +433,10 @@ export function createModelCard(model, modelType) {
|
||||
card.dataset.usage_count = String(model.usage_count);
|
||||
card.dataset.notes = model.notes || '';
|
||||
card.dataset.base_model = model.base_model || 'Unknown';
|
||||
card.dataset.favorite = model.favorite ? 'true' : 'false';
|
||||
const hasUpdateAvailable = Boolean(model.update_available);
|
||||
card.dataset.update_available = hasUpdateAvailable ? 'true' : 'false';
|
||||
card.dataset.favorite = model.favorite ? 'true' : 'false';
|
||||
const hasUpdateAvailable = Boolean(model.update_available);
|
||||
card.dataset.update_available = hasUpdateAvailable ? 'true' : 'false';
|
||||
card.dataset.skip_metadata_refresh = model.skip_metadata_refresh ? 'true' : 'false';
|
||||
|
||||
// To only show usage_count when sorting by usage.
|
||||
const pageState = getCurrentPageState();
|
||||
@@ -482,6 +483,10 @@ export function createModelCard(model, modelType) {
|
||||
card.classList.add('nsfw-content');
|
||||
}
|
||||
|
||||
if (model.skip_metadata_refresh) {
|
||||
card.classList.add('skip-refresh');
|
||||
}
|
||||
|
||||
// Apply selection state if in bulk mode and this card is in the selected set (LoRA only)
|
||||
if (modelType === MODEL_TYPES.LORA && state.bulkMode && state.selectedLoras.has(model.file_path)) {
|
||||
card.classList.add('selected');
|
||||
@@ -608,6 +613,11 @@ export function createModelCard(model, modelType) {
|
||||
<i class="fas fa-arrow-up"></i>
|
||||
</span>
|
||||
` : ''}
|
||||
${model.skip_metadata_refresh ? `
|
||||
<span class="model-skip-refresh-badge" title="${translate('modelCard.badges.skipRefresh', {}, 'Metadata refresh skipped')}">
|
||||
<i class="fas fa-ban"></i>
|
||||
</span>
|
||||
` : ''}
|
||||
</div>
|
||||
<div class="card-actions">
|
||||
${actionIcons}
|
||||
|
||||
@@ -40,7 +40,8 @@ export class BulkManager {
|
||||
moveAll: true,
|
||||
autoOrganize: true,
|
||||
deleteAll: true,
|
||||
setContentRating: true
|
||||
setContentRating: true,
|
||||
skipMetadataRefresh: true
|
||||
},
|
||||
[MODEL_TYPES.EMBEDDING]: {
|
||||
addTags: true,
|
||||
@@ -51,7 +52,8 @@ export class BulkManager {
|
||||
moveAll: true,
|
||||
autoOrganize: true,
|
||||
deleteAll: true,
|
||||
setContentRating: false
|
||||
setContentRating: false,
|
||||
skipMetadataRefresh: true
|
||||
},
|
||||
[MODEL_TYPES.CHECKPOINT]: {
|
||||
addTags: true,
|
||||
@@ -62,7 +64,8 @@ export class BulkManager {
|
||||
moveAll: false,
|
||||
autoOrganize: true,
|
||||
deleteAll: true,
|
||||
setContentRating: true
|
||||
setContentRating: true,
|
||||
skipMetadataRefresh: true
|
||||
},
|
||||
recipes: {
|
||||
addTags: false,
|
||||
@@ -73,7 +76,8 @@ export class BulkManager {
|
||||
moveAll: true,
|
||||
autoOrganize: false,
|
||||
deleteAll: true,
|
||||
setContentRating: false
|
||||
setContentRating: false,
|
||||
skipMetadataRefresh: false
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1195,6 +1199,59 @@ export class BulkManager {
|
||||
return successCount > 0;
|
||||
}
|
||||
|
||||
async setSkipMetadataRefresh(value) {
|
||||
if (state.selectedModels.size === 0) {
|
||||
showToast('toast.models.noModelsSelected', {}, 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
const totalCount = state.selectedModels.size;
|
||||
|
||||
state.loadingManager.showSimpleLoading(
|
||||
translate('toast.models.skipMetadataRefreshUpdating', { count: totalCount })
|
||||
);
|
||||
let cancelled = false;
|
||||
state.loadingManager.showCancelButton(() => {
|
||||
cancelled = true;
|
||||
});
|
||||
|
||||
let successCount = 0;
|
||||
let failureCount = 0;
|
||||
|
||||
try {
|
||||
const apiClient = getModelApiClient();
|
||||
for (const filePath of state.selectedModels) {
|
||||
if (cancelled) {
|
||||
showToast('toast.api.operationCancelled', {}, 'info');
|
||||
break;
|
||||
}
|
||||
try {
|
||||
await apiClient.saveModelMetadata(filePath, { skip_metadata_refresh: value });
|
||||
successCount++;
|
||||
} catch (error) {
|
||||
failureCount++;
|
||||
console.error(`Failed to set skip_metadata_refresh for ${filePath}:`, error);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
state.loadingManager?.hide?.();
|
||||
}
|
||||
|
||||
if (successCount === totalCount) {
|
||||
const toastKey = value
|
||||
? 'toast.models.skipMetadataRefreshSet'
|
||||
: 'toast.models.skipMetadataRefreshCleared';
|
||||
showToast(toastKey, { count: successCount }, 'success');
|
||||
} else if (successCount > 0) {
|
||||
showToast('toast.models.skipMetadataRefreshPartial', {
|
||||
success: successCount,
|
||||
failed: failureCount
|
||||
}, 'warning');
|
||||
} else {
|
||||
showToast('toast.models.skipMetadataRefreshFailed', {}, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize bulk base model interface
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user