From fb2b69b787a8fa7229ed55ff7c9201f4a9437216 Mon Sep 17 00:00:00 2001
From: Will Miao <13051207myq@gmail.com>
Date: Fri, 5 Sep 2025 09:27:45 +0800
Subject: [PATCH] feat(tags): refactor preset tags to constants for better
maintainability
---
static/js/components/shared/ModelTags.js | 9 +-
static/js/managers/BulkManager.js | 124 +++++++++++++++++++----
static/js/utils/constants.js | 7 ++
3 files changed, 113 insertions(+), 27 deletions(-)
diff --git a/static/js/components/shared/ModelTags.js b/static/js/components/shared/ModelTags.js
index ca958d6a..08ae6900 100644
--- a/static/js/components/shared/ModelTags.js
+++ b/static/js/components/shared/ModelTags.js
@@ -4,14 +4,7 @@
*/
import { showToast } from '../../utils/uiHelpers.js';
import { getModelApiClient } from '../../api/modelApiFactory.js';
-import { translate } from '../../utils/i18nHelpers.js';
-
-// Preset tag suggestions
-const PRESET_TAGS = [
- 'character', 'style', 'concept', 'clothing',
- 'poses', 'background', 'vehicle', 'buildings',
- 'objects', 'animal'
-];
+import { PRESET_TAGS } from '../../utils/constants.js';
// Create a named function so we can remove it later
let saveTagsHandler = null;
diff --git a/static/js/managers/BulkManager.js b/static/js/managers/BulkManager.js
index 3b4116f2..7ecdadcf 100644
--- a/static/js/managers/BulkManager.js
+++ b/static/js/managers/BulkManager.js
@@ -4,6 +4,7 @@ import { updateCardsForBulkMode } from '../components/shared/ModelCard.js';
import { modalManager } from './ModalManager.js';
import { getModelApiClient } from '../api/modelApiFactory.js';
import { MODEL_TYPES, MODEL_CONFIG } from '../api/apiConfig.js';
+import { PRESET_TAGS } from '../utils/constants.js';
export class BulkManager {
constructor() {
@@ -437,13 +438,6 @@ export class BulkManager {
}
initializeBulkTagsInterface() {
- // Import preset tags from ModelTags.js
- const PRESET_TAGS = [
- 'character', 'style', 'concept', 'clothing',
- 'poses', 'background', 'vehicle', 'buildings',
- 'objects', 'animal'
- ];
-
// Setup tag input behavior
const tagInput = document.querySelector('.bulk-metadata-input');
if (tagInput) {
@@ -452,6 +446,8 @@ export class BulkManager {
e.preventDefault();
this.addBulkTag(e.target.value.trim());
e.target.value = '';
+ // Update dropdown to show added indicator
+ this.updateBulkSuggestionsDropdown();
}
});
}
@@ -496,19 +492,30 @@ export class BulkManager {
container.className = 'metadata-suggestions-container';
presetTags.forEach(tag => {
- const item = document.createElement('div');
- item.className = 'metadata-suggestion-item';
- item.title = tag;
- item.innerHTML = `${tag}`;
+ // Check if tag is already added
+ const existingTags = this.getBulkExistingTags();
+ const isAdded = existingTags.includes(tag);
- item.addEventListener('click', () => {
- this.addBulkTag(tag);
- const input = document.querySelector('.bulk-metadata-input');
- if (input) {
- input.value = tag;
- input.focus();
- }
- });
+ const item = document.createElement('div');
+ item.className = `metadata-suggestion-item ${isAdded ? 'already-added' : ''}`;
+ item.title = tag;
+ item.innerHTML = `
+ ${tag}
+ ${isAdded ? '' : ''}
+ `;
+
+ if (!isAdded) {
+ item.addEventListener('click', () => {
+ this.addBulkTag(tag);
+ const input = document.querySelector('.bulk-metadata-input');
+ if (input) {
+ input.value = tag;
+ input.focus();
+ }
+ // Update dropdown to show added indicator
+ this.updateBulkSuggestionsDropdown();
+ });
+ }
container.appendChild(item);
});
@@ -560,11 +567,81 @@ export class BulkManager {
deleteBtn.addEventListener('click', (e) => {
e.stopPropagation();
newTag.remove();
+ // Update dropdown to show/hide added indicator
+ this.updateBulkSuggestionsDropdown();
});
tagsContainer.appendChild(newTag);
}
+ /**
+ * Get existing tags in the bulk tags container
+ * @returns {Array} Array of existing tag strings
+ */
+ getBulkExistingTags() {
+ const tagsContainer = document.getElementById('bulkTagsItems');
+ if (!tagsContainer) return [];
+
+ const currentTags = tagsContainer.querySelectorAll('.metadata-item');
+ return Array.from(currentTags).map(tag => tag.dataset.tag);
+ }
+
+ /**
+ * Update status of items in the bulk suggestions dropdown
+ */
+ updateBulkSuggestionsDropdown() {
+ const dropdown = document.querySelector('.metadata-suggestions-dropdown');
+ if (!dropdown) return;
+
+ // Get all current tags
+ const existingTags = this.getBulkExistingTags();
+
+ // Update status of each item in dropdown
+ dropdown.querySelectorAll('.metadata-suggestion-item').forEach(item => {
+ const tagText = item.querySelector('.metadata-suggestion-text').textContent;
+ const isAdded = existingTags.includes(tagText);
+
+ if (isAdded) {
+ item.classList.add('already-added');
+
+ // Add indicator if it doesn't exist
+ let indicator = item.querySelector('.added-indicator');
+ if (!indicator) {
+ indicator = document.createElement('span');
+ indicator.className = 'added-indicator';
+ indicator.innerHTML = '';
+ item.appendChild(indicator);
+ }
+
+ // Remove click event
+ item.onclick = null;
+ item.removeEventListener('click', item._clickHandler);
+ } else {
+ // Re-enable items that are no longer in the list
+ item.classList.remove('already-added');
+
+ // Remove indicator if it exists
+ const indicator = item.querySelector('.added-indicator');
+ if (indicator) indicator.remove();
+
+ // Restore click event if not already set
+ if (!item._clickHandler) {
+ item._clickHandler = () => {
+ this.addBulkTag(tagText);
+ const input = document.querySelector('.bulk-metadata-input');
+ if (input) {
+ input.value = tagText;
+ input.focus();
+ }
+ // Update dropdown to show added indicator
+ this.updateBulkSuggestionsDropdown();
+ };
+ item.addEventListener('click', item._clickHandler);
+ }
+ }
+ });
+ }
+
async saveBulkTags(mode = 'append') {
const tagElements = document.querySelectorAll('#bulkTagsItems .metadata-item');
const tags = Array.from(tagElements).map(tag => tag.dataset.tag);
@@ -647,6 +724,15 @@ export class BulkManager {
if (replaceBtn) {
replaceBtn.replaceWith(replaceBtn.cloneNode(true));
}
+
+ // Remove the suggestions dropdown
+ const tagForm = document.querySelector('#bulkAddTagsModal .metadata-add-form');
+ if (tagForm) {
+ const dropdown = tagForm.querySelector('.metadata-suggestions-dropdown');
+ if (dropdown) {
+ dropdown.remove();
+ }
+ }
}
}
diff --git a/static/js/utils/constants.js b/static/js/utils/constants.js
index 9f440aa5..196de1fc 100644
--- a/static/js/utils/constants.js
+++ b/static/js/utils/constants.js
@@ -163,3 +163,10 @@ export const NODE_TYPE_ICONS = {
// Default ComfyUI node color when bgcolor is null
export const DEFAULT_NODE_COLOR = "#353535";
+
+// Preset tag suggestions
+export const PRESET_TAGS = [
+ 'character', 'style', 'concept', 'clothing',
+ 'poses', 'background', 'vehicle', 'buildings',
+ 'objects', 'animal'
+];