mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-03-25 15:15:44 -03:00
refactor: enhance bulk metadata refresh functionality and update UI components
This commit is contained in:
@@ -45,7 +45,7 @@
|
|||||||
opacity: 0.8;
|
opacity: 0.8;
|
||||||
}
|
}
|
||||||
|
|
||||||
.progress-bar {
|
.update-progress-bar {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 8px;
|
height: 8px;
|
||||||
background-color: rgba(0, 0, 0, 0.1);
|
background-color: rgba(0, 0, 0, 0.1);
|
||||||
@@ -53,7 +53,7 @@
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-theme="dark"] .progress-bar {
|
[data-theme="dark"] .update-progress-bar {
|
||||||
background-color: rgba(255, 255, 255, 0.1);
|
background-color: rgba(255, 255, 255, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -477,6 +477,104 @@ class ModelApiClient {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch CivitAI metadata for multiple models with progress tracking
|
||||||
|
*/
|
||||||
|
async refreshBulkModelMetadata(filePaths) {
|
||||||
|
if (!filePaths || filePaths.length === 0) {
|
||||||
|
throw new Error('No file paths provided');
|
||||||
|
}
|
||||||
|
|
||||||
|
const totalItems = filePaths.length;
|
||||||
|
let processedCount = 0;
|
||||||
|
let successCount = 0;
|
||||||
|
let failedItems = [];
|
||||||
|
|
||||||
|
const progressController = state.loadingManager.showEnhancedProgress('Starting metadata refresh...');
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Process files sequentially to avoid overwhelming the API
|
||||||
|
for (let i = 0; i < filePaths.length; i++) {
|
||||||
|
const filePath = filePaths[i];
|
||||||
|
const fileName = filePath.split('/').pop();
|
||||||
|
|
||||||
|
try {
|
||||||
|
const overallProgress = Math.floor((i / totalItems) * 100);
|
||||||
|
progressController.updateProgress(
|
||||||
|
overallProgress,
|
||||||
|
fileName,
|
||||||
|
`Processing ${i + 1}/${totalItems}: ${fileName}`
|
||||||
|
);
|
||||||
|
|
||||||
|
const response = await fetch(this.apiConfig.endpoints.fetchCivitai, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ file_path: filePath })
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
|
||||||
|
if (data.success) {
|
||||||
|
if (data.metadata && state.virtualScroller) {
|
||||||
|
state.virtualScroller.updateSingleItem(filePath, data.metadata);
|
||||||
|
}
|
||||||
|
successCount++;
|
||||||
|
} else {
|
||||||
|
throw new Error(data.error || 'Failed to refresh metadata');
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Error refreshing metadata for ${fileName}:`, error);
|
||||||
|
failedItems.push({ filePath, fileName, error: error.message });
|
||||||
|
}
|
||||||
|
|
||||||
|
processedCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show completion message
|
||||||
|
let completionMessage;
|
||||||
|
if (successCount === totalItems) {
|
||||||
|
completionMessage = `Successfully refreshed all ${successCount} ${this.apiConfig.config.displayName}s`;
|
||||||
|
showToast(completionMessage, 'success');
|
||||||
|
} else if (successCount > 0) {
|
||||||
|
completionMessage = `Refreshed ${successCount} of ${totalItems} ${this.apiConfig.config.displayName}s`;
|
||||||
|
showToast(completionMessage, 'warning');
|
||||||
|
|
||||||
|
if (failedItems.length > 0) {
|
||||||
|
const failureMessage = failedItems.length <= 3
|
||||||
|
? failedItems.map(item => `${item.fileName}: ${item.error}`).join('\n')
|
||||||
|
: failedItems.slice(0, 3).map(item => `${item.fileName}: ${item.error}`).join('\n') +
|
||||||
|
`\n(and ${failedItems.length - 3} more)`;
|
||||||
|
showToast(`Failed refreshes:\n${failureMessage}`, 'warning', 6000);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
completionMessage = `Failed to refresh metadata for any ${this.apiConfig.config.displayName}s`;
|
||||||
|
showToast(completionMessage, 'error');
|
||||||
|
}
|
||||||
|
|
||||||
|
await progressController.complete(completionMessage);
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: successCount > 0,
|
||||||
|
total: totalItems,
|
||||||
|
processed: processedCount,
|
||||||
|
successful: successCount,
|
||||||
|
failed: failedItems.length,
|
||||||
|
errors: failedItems
|
||||||
|
};
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error in bulk metadata refresh:', error);
|
||||||
|
showToast(`Failed to refresh metadata: ${error.message}`, 'error');
|
||||||
|
await progressController.complete('Operation failed');
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Move a single model to target path
|
* Move a single model to target path
|
||||||
* @returns {string|null} - The new file path if moved, null if not moved
|
* @returns {string|null} - The new file path if moved, null if not moved
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { state } from '../state/index.js';
|
|||||||
import { showToast, copyToClipboard, sendLoraToWorkflow } from '../utils/uiHelpers.js';
|
import { showToast, copyToClipboard, sendLoraToWorkflow } from '../utils/uiHelpers.js';
|
||||||
import { updateCardsForBulkMode } from '../components/shared/ModelCard.js';
|
import { updateCardsForBulkMode } from '../components/shared/ModelCard.js';
|
||||||
import { modalManager } from './ModalManager.js';
|
import { modalManager } from './ModalManager.js';
|
||||||
|
import { getModelApiClient } from '../api/baseModelApi.js';
|
||||||
|
|
||||||
export class BulkManager {
|
export class BulkManager {
|
||||||
constructor() {
|
constructor() {
|
||||||
@@ -560,6 +561,55 @@ export class BulkManager {
|
|||||||
this.updateThumbnailStrip();
|
this.updateThumbnailStrip();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add method to refresh metadata for all selected models
|
||||||
|
async refreshAllMetadata() {
|
||||||
|
if (state.selectedLoras.size === 0) {
|
||||||
|
showToast('No models selected', 'warning');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Get the API client for the current model type
|
||||||
|
const apiClient = getModelApiClient();
|
||||||
|
|
||||||
|
// Convert Set to Array for processing
|
||||||
|
const filePaths = Array.from(state.selectedLoras);
|
||||||
|
|
||||||
|
// Call the bulk refresh method
|
||||||
|
const result = await apiClient.refreshBulkModelMetadata(filePaths);
|
||||||
|
|
||||||
|
if (result.success) {
|
||||||
|
// Update the metadata cache for successfully refreshed items
|
||||||
|
for (const filepath of state.selectedLoras) {
|
||||||
|
const metadata = state.loraMetadataCache.get(filepath);
|
||||||
|
if (metadata) {
|
||||||
|
// Find the corresponding card to get updated data
|
||||||
|
const card = document.querySelector(`.model-card[data-filepath="${filepath}"]`);
|
||||||
|
if (card) {
|
||||||
|
state.loraMetadataCache.set(filepath, {
|
||||||
|
...metadata,
|
||||||
|
fileName: card.dataset.file_name,
|
||||||
|
usageTips: card.dataset.usage_tips,
|
||||||
|
previewUrl: this.getCardPreviewUrl(card),
|
||||||
|
isVideo: this.isCardPreviewVideo(card),
|
||||||
|
modelName: card.dataset.name
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update thumbnail strip if visible
|
||||||
|
if (this.isStripVisible) {
|
||||||
|
this.updateThumbnailStrip();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error during bulk metadata refresh:', error);
|
||||||
|
showToast('Failed to refresh metadata', 'error');
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a singleton instance
|
// Create a singleton instance
|
||||||
|
|||||||
@@ -145,6 +145,28 @@ export class LoadingManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Enhanced progress display without callback pattern
|
||||||
|
showEnhancedProgress(message = 'Processing...') {
|
||||||
|
this.show(message, 0);
|
||||||
|
|
||||||
|
// Return update functions
|
||||||
|
return {
|
||||||
|
updateProgress: (percent, currentItem = '', statusMessage = '') => {
|
||||||
|
this.setProgress(percent);
|
||||||
|
if (statusMessage) {
|
||||||
|
this.setStatus(statusMessage);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
complete: async (completionMessage = 'Complete') => {
|
||||||
|
this.setProgress(100);
|
||||||
|
this.setStatus(completionMessage);
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 500));
|
||||||
|
this.hide();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
showSimpleLoading(message = 'Loading...') {
|
showSimpleLoading(message = 'Loading...') {
|
||||||
this.overlay.style.display = 'flex';
|
this.overlay.style.display = 'flex';
|
||||||
this.progressBar.style.display = 'none';
|
this.progressBar.style.display = 'none';
|
||||||
|
|||||||
@@ -125,6 +125,9 @@
|
|||||||
<button onclick="bulkManager.copyAllLorasSyntax()" title="Copy all selected LoRAs syntax">
|
<button onclick="bulkManager.copyAllLorasSyntax()" title="Copy all selected LoRAs syntax">
|
||||||
<i class="fas fa-copy"></i> Copy All
|
<i class="fas fa-copy"></i> Copy All
|
||||||
</button>
|
</button>
|
||||||
|
<button onclick="bulkManager.refreshAllMetadata()" title="Refresh CivitAI metadata for selected models">
|
||||||
|
<i class="fas fa-sync-alt"></i> Refresh All
|
||||||
|
</button>
|
||||||
<button onclick="moveManager.showMoveModal('bulk')" title="Move selected LoRAs to folder">
|
<button onclick="moveManager.showMoveModal('bulk')" title="Move selected LoRAs to folder">
|
||||||
<i class="fas fa-folder-open"></i> Move All
|
<i class="fas fa-folder-open"></i> Move All
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -35,7 +35,7 @@
|
|||||||
<div class="update-progress" id="updateProgress" style="display: none;">
|
<div class="update-progress" id="updateProgress" style="display: none;">
|
||||||
<div class="progress-info">
|
<div class="progress-info">
|
||||||
<div class="progress-text" id="updateProgressText">Preparing update...</div>
|
<div class="progress-text" id="updateProgressText">Preparing update...</div>
|
||||||
<div class="progress-bar">
|
<div class="update-progress-bar">
|
||||||
<div class="progress-fill" id="updateProgressFill"></div>
|
<div class="progress-fill" id="updateProgressFill"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user