mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-03-21 21:22:11 -03:00
feat(tags): implement bulk tag addition and replacement functionality
This commit is contained in:
@@ -37,6 +37,10 @@ body.modal-open {
|
||||
overflow-x: hidden; /* 防止水平滚动条 */
|
||||
}
|
||||
|
||||
.modal-content-large {
|
||||
min-height: 480px;
|
||||
}
|
||||
|
||||
/* 当 modal 打开时锁定 body */
|
||||
body.modal-open {
|
||||
overflow: hidden !important; /* 覆盖 base.css 中的 scroll */
|
||||
|
||||
@@ -80,6 +80,7 @@
|
||||
align-items: flex-start;
|
||||
margin-bottom: var(--space-2);
|
||||
width: 100%;
|
||||
min-height: 30px; /* Ensure some height even if empty to prevent layout shifts */
|
||||
}
|
||||
|
||||
/* Individual Item */
|
||||
@@ -153,17 +154,42 @@
|
||||
}
|
||||
|
||||
.metadata-save-btn,
|
||||
.save-tags-btn {
|
||||
.save-tags-btn,
|
||||
.append-tags-btn,
|
||||
.replace-tags-btn {
|
||||
background: var(--lora-accent) !important;
|
||||
color: white !important;
|
||||
border-color: var(--lora-accent) !important;
|
||||
}
|
||||
|
||||
.metadata-save-btn:hover,
|
||||
.save-tags-btn:hover {
|
||||
.save-tags-btn:hover,
|
||||
.append-tags-btn:hover,
|
||||
.replace-tags-btn:hover {
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
/* Specific styling for bulk tag action buttons */
|
||||
.bulk-append-tags-btn {
|
||||
background: var(--lora-accent) !important;
|
||||
color: white !important;
|
||||
border-color: var(--lora-accent) !important;
|
||||
}
|
||||
|
||||
.bulk-replace-tags-btn {
|
||||
background: var(--lora-warning, #f59e0b) !important;
|
||||
color: white !important;
|
||||
border-color: var(--lora-warning, #f59e0b) !important;
|
||||
}
|
||||
|
||||
.bulk-append-tags-btn:hover {
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.bulk-replace-tags-btn:hover {
|
||||
background: var(--lora-warning-dark, #d97706) !important;
|
||||
}
|
||||
|
||||
/* Add Form */
|
||||
.metadata-add-form {
|
||||
display: flex;
|
||||
|
||||
@@ -63,6 +63,9 @@ export function getApiEndpoints(modelType) {
|
||||
|
||||
// Bulk operations
|
||||
bulkDelete: `/api/${modelType}/bulk-delete`,
|
||||
|
||||
// Tag operations
|
||||
addTags: `/api/${modelType}/add-tags`,
|
||||
|
||||
// Move operations (now common for all model types that support move)
|
||||
moveModel: `/api/${modelType}/move_model`,
|
||||
|
||||
@@ -306,6 +306,34 @@ export class BaseModelApiClient {
|
||||
}
|
||||
}
|
||||
|
||||
async addTags(filePath, data) {
|
||||
try {
|
||||
const response = await fetch(this.apiConfig.endpoints.addTags, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
file_path: filePath,
|
||||
...data
|
||||
})
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to add tags');
|
||||
}
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success && result.tags) {
|
||||
state.virtualScroller.updateSingleItem(filePath, { tags: result.tags });
|
||||
}
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error('Error adding tags:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async refreshModels(fullRebuild = false) {
|
||||
try {
|
||||
state.loadingManager.showSimpleLoading(
|
||||
|
||||
@@ -464,10 +464,18 @@ export class BulkManager {
|
||||
}
|
||||
|
||||
// Setup save button
|
||||
const saveBtn = document.querySelector('.bulk-save-tags-btn');
|
||||
if (saveBtn) {
|
||||
saveBtn.addEventListener('click', () => {
|
||||
this.saveBulkTags();
|
||||
const appendBtn = document.querySelector('.bulk-append-tags-btn');
|
||||
const replaceBtn = document.querySelector('.bulk-replace-tags-btn');
|
||||
|
||||
if (appendBtn) {
|
||||
appendBtn.addEventListener('click', () => {
|
||||
this.saveBulkTags('append');
|
||||
});
|
||||
}
|
||||
|
||||
if (replaceBtn) {
|
||||
replaceBtn.addEventListener('click', () => {
|
||||
this.saveBulkTags('replace');
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -557,7 +565,7 @@ export class BulkManager {
|
||||
tagsContainer.appendChild(newTag);
|
||||
}
|
||||
|
||||
async saveBulkTags() {
|
||||
async saveBulkTags(mode = 'append') {
|
||||
const tagElements = document.querySelectorAll('#bulkTagsItems .metadata-item');
|
||||
const tags = Array.from(tagElements).map(tag => tag.dataset.tag);
|
||||
|
||||
@@ -577,13 +585,17 @@ export class BulkManager {
|
||||
let successCount = 0;
|
||||
let failCount = 0;
|
||||
|
||||
// Add tags to each selected model
|
||||
// Add or replace tags for each selected model based on mode
|
||||
for (const filePath of filePaths) {
|
||||
try {
|
||||
await apiClient.addTags(filePath, { tags: tags });
|
||||
if (mode === 'replace') {
|
||||
await apiClient.saveModelMetadata(filePath, { tags: tags });
|
||||
} else {
|
||||
await apiClient.addTags(filePath, { tags: tags });
|
||||
}
|
||||
successCount++;
|
||||
} catch (error) {
|
||||
console.error(`Failed to add tags to ${filePath}:`, error);
|
||||
console.error(`Failed to ${mode} tags for ${filePath}:`, error);
|
||||
failCount++;
|
||||
}
|
||||
}
|
||||
@@ -592,7 +604,8 @@ export class BulkManager {
|
||||
|
||||
if (successCount > 0) {
|
||||
const currentConfig = MODEL_CONFIG[state.currentPageType];
|
||||
showToast('toast.models.tagsAddedSuccessfully', {
|
||||
const toastKey = mode === 'replace' ? 'toast.models.tagsReplacedSuccessfully' : 'toast.models.tagsAddedSuccessfully';
|
||||
showToast(toastKey, {
|
||||
count: successCount,
|
||||
tagCount: tags.length,
|
||||
type: currentConfig.displayName.toLowerCase()
|
||||
@@ -600,12 +613,14 @@ export class BulkManager {
|
||||
}
|
||||
|
||||
if (failCount > 0) {
|
||||
showToast('toast.models.tagsAddFailed', { count: failCount }, 'warning');
|
||||
const toastKey = mode === 'replace' ? 'toast.models.tagsReplaceFailed' : 'toast.models.tagsAddFailed';
|
||||
showToast(toastKey, { count: failCount }, 'warning');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error during bulk tag addition:', error);
|
||||
showToast('toast.models.bulkTagsAddFailed', {}, 'error');
|
||||
console.error('Error during bulk tag operation:', error);
|
||||
const toastKey = mode === 'replace' ? 'toast.models.bulkTagsReplaceFailed' : 'toast.models.bulkTagsAddFailed';
|
||||
showToast(toastKey, {}, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -623,9 +638,14 @@ export class BulkManager {
|
||||
}
|
||||
|
||||
// Remove event listeners (they will be re-added when modal opens again)
|
||||
const saveBtn = document.querySelector('.bulk-save-tags-btn');
|
||||
if (saveBtn) {
|
||||
saveBtn.replaceWith(saveBtn.cloneNode(true));
|
||||
const appendBtn = document.querySelector('.bulk-append-tags-btn');
|
||||
if (appendBtn) {
|
||||
appendBtn.replaceWith(appendBtn.cloneNode(true));
|
||||
}
|
||||
|
||||
const replaceBtn = document.querySelector('.bulk-replace-tags-btn');
|
||||
if (replaceBtn) {
|
||||
replaceBtn.replaceWith(replaceBtn.cloneNode(true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user