mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-06-09 12:39:23 -03:00
feat(modal): make version name editable in model modal (#931)
This commit is contained in:
@@ -1180,6 +1180,7 @@
|
||||
"editModelName": "Modellname bearbeiten",
|
||||
"editFileName": "Dateiname bearbeiten",
|
||||
"editBaseModel": "Basis-Modell bearbeiten",
|
||||
"editVersionName": "Versionsname bearbeiten",
|
||||
"viewOnCivitai": "Auf Civitai anzeigen",
|
||||
"viewOnCivitaiText": "Auf Civitai anzeigen",
|
||||
"viewCreatorProfile": "Ersteller-Profil anzeigen",
|
||||
|
||||
@@ -1180,6 +1180,7 @@
|
||||
"editModelName": "Edit model name",
|
||||
"editFileName": "Edit file name",
|
||||
"editBaseModel": "Edit base model",
|
||||
"editVersionName": "Edit version name",
|
||||
"viewOnCivitai": "View on Civitai",
|
||||
"viewOnCivitaiText": "View on Civitai",
|
||||
"viewCreatorProfile": "View Creator Profile",
|
||||
|
||||
@@ -1180,6 +1180,7 @@
|
||||
"editModelName": "Editar nombre del modelo",
|
||||
"editFileName": "Editar nombre de archivo",
|
||||
"editBaseModel": "Editar modelo base",
|
||||
"editVersionName": "Editar nombre de versión",
|
||||
"viewOnCivitai": "Ver en Civitai",
|
||||
"viewOnCivitaiText": "Ver en Civitai",
|
||||
"viewCreatorProfile": "Ver perfil del creador",
|
||||
|
||||
@@ -1180,6 +1180,7 @@
|
||||
"editModelName": "Modifier le nom du modèle",
|
||||
"editFileName": "Modifier le nom de fichier",
|
||||
"editBaseModel": "Modifier le modèle de base",
|
||||
"editVersionName": "Modifier le nom de la version",
|
||||
"viewOnCivitai": "Voir sur Civitai",
|
||||
"viewOnCivitaiText": "Voir sur Civitai",
|
||||
"viewCreatorProfile": "Voir le profil du créateur",
|
||||
|
||||
@@ -1180,6 +1180,7 @@
|
||||
"editModelName": "ערוך שם מודל",
|
||||
"editFileName": "ערוך שם קובץ",
|
||||
"editBaseModel": "ערוך מודל בסיס",
|
||||
"editVersionName": "ערוך שם גרסה",
|
||||
"viewOnCivitai": "הצג ב-Civitai",
|
||||
"viewOnCivitaiText": "הצג ב-Civitai",
|
||||
"viewCreatorProfile": "הצג פרופיל יוצר",
|
||||
|
||||
@@ -1180,6 +1180,7 @@
|
||||
"editModelName": "モデル名を編集",
|
||||
"editFileName": "ファイル名を編集",
|
||||
"editBaseModel": "ベースモデルを編集",
|
||||
"editVersionName": "バージョン名を編集",
|
||||
"viewOnCivitai": "Civitaiで表示",
|
||||
"viewOnCivitaiText": "Civitaiで表示",
|
||||
"viewCreatorProfile": "作成者プロフィールを表示",
|
||||
|
||||
@@ -1180,6 +1180,7 @@
|
||||
"editModelName": "모델명 편집",
|
||||
"editFileName": "파일명 편집",
|
||||
"editBaseModel": "베이스 모델 편집",
|
||||
"editVersionName": "버전명 편집",
|
||||
"viewOnCivitai": "Civitai에서 보기",
|
||||
"viewOnCivitaiText": "Civitai에서 보기",
|
||||
"viewCreatorProfile": "제작자 프로필 보기",
|
||||
|
||||
@@ -1180,6 +1180,7 @@
|
||||
"editModelName": "Редактировать название модели",
|
||||
"editFileName": "Редактировать имя файла",
|
||||
"editBaseModel": "Редактировать базовую модель",
|
||||
"editVersionName": "Редактировать название версии",
|
||||
"viewOnCivitai": "Посмотреть на Civitai",
|
||||
"viewOnCivitaiText": "Посмотреть на Civitai",
|
||||
"viewCreatorProfile": "Посмотреть профиль создателя",
|
||||
|
||||
@@ -1180,6 +1180,7 @@
|
||||
"editModelName": "编辑模型名称",
|
||||
"editFileName": "编辑文件名",
|
||||
"editBaseModel": "编辑基础模型",
|
||||
"editVersionName": "编辑版本名称",
|
||||
"viewOnCivitai": "在 Civitai 查看",
|
||||
"viewOnCivitaiText": "在 Civitai 查看",
|
||||
"viewCreatorProfile": "查看创作者主页",
|
||||
|
||||
@@ -1180,6 +1180,7 @@
|
||||
"editModelName": "編輯模型名稱",
|
||||
"editFileName": "編輯檔案名稱",
|
||||
"editBaseModel": "編輯基礎模型",
|
||||
"editVersionName": "編輯版本名稱",
|
||||
"viewOnCivitai": "在 Civitai 查看",
|
||||
"viewOnCivitaiText": "在 Civitai 查看",
|
||||
"viewCreatorProfile": "查看創作者個人檔案",
|
||||
|
||||
@@ -255,25 +255,28 @@
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
/* File name copy styles */
|
||||
.file-name-wrapper {
|
||||
/* Editable inline field styles (file name, version name, etc.) */
|
||||
.file-name-wrapper,
|
||||
.version-name-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 4px;
|
||||
padding: 4px 0;
|
||||
border-radius: var(--border-radius-xs);
|
||||
transition: background-color 0.2s;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.file-name-content {
|
||||
padding: 2px 4px;
|
||||
.file-name-content,
|
||||
.version-name-content {
|
||||
padding: 2px 4px 2px 0;
|
||||
border-radius: var(--border-radius-xs);
|
||||
border: 1px solid transparent;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.file-name-wrapper.editing .file-name-content {
|
||||
.file-name-wrapper.editing .file-name-content,
|
||||
.version-name-wrapper.editing .version-name-content {
|
||||
border: 1px solid var(--lora-accent);
|
||||
background: var(--bg-color);
|
||||
outline: none;
|
||||
@@ -283,7 +286,8 @@
|
||||
.edit-model-name-btn,
|
||||
.edit-file-name-btn,
|
||||
.edit-base-model-btn,
|
||||
.edit-model-description-btn {
|
||||
.edit-model-description-btn,
|
||||
.edit-version-name-btn {
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: var(--text-color);
|
||||
@@ -299,9 +303,11 @@
|
||||
.edit-file-name-btn.visible,
|
||||
.edit-base-model-btn.visible,
|
||||
.edit-model-description-btn.visible,
|
||||
.edit-version-name-btn.visible,
|
||||
.model-name-header:hover .edit-model-name-btn,
|
||||
.file-name-wrapper:hover .edit-file-name-btn,
|
||||
.base-model-display:hover .edit-base-model-btn,
|
||||
.version-name-wrapper:hover .edit-version-name-btn,
|
||||
.model-name-header:hover .edit-model-description-btn {
|
||||
opacity: 0.5;
|
||||
}
|
||||
@@ -309,14 +315,16 @@
|
||||
.edit-model-name-btn:hover,
|
||||
.edit-file-name-btn:hover,
|
||||
.edit-base-model-btn:hover,
|
||||
.edit-model-description-btn:hover {
|
||||
.edit-model-description-btn:hover,
|
||||
.edit-version-name-btn:hover {
|
||||
opacity: 0.8 !important;
|
||||
background: rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
[data-theme="dark"] .edit-model-name-btn:hover,
|
||||
[data-theme="dark"] .edit-file-name-btn:hover,
|
||||
[data-theme="dark"] .edit-base-model-btn:hover {
|
||||
[data-theme="dark"] .edit-base-model-btn:hover,
|
||||
[data-theme="dark"] .edit-version-name-btn:hover {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
|
||||
@@ -338,7 +346,7 @@
|
||||
}
|
||||
|
||||
.base-model-content {
|
||||
padding: 2px 4px;
|
||||
padding: 2px 4px 2px 0;
|
||||
border-radius: var(--border-radius-xs);
|
||||
border: 1px solid transparent;
|
||||
color: var(--text-color);
|
||||
|
||||
@@ -66,6 +66,12 @@ function updateModalFilePathReferences(newFilePath) {
|
||||
fileNameContent.setAttribute('data-file-path', newFilePath);
|
||||
}
|
||||
|
||||
const versionNameContent = scopedQuery('.version-name-content');
|
||||
if (versionNameContent && versionNameContent.dataset) {
|
||||
versionNameContent.dataset.filePath = newFilePath;
|
||||
versionNameContent.setAttribute('data-file-path', newFilePath);
|
||||
}
|
||||
|
||||
const editTagsBtn = scopedQuery('.edit-tags-btn');
|
||||
if (editTagsBtn) {
|
||||
editTagsBtn.dataset.filePath = newFilePath;
|
||||
@@ -516,3 +522,127 @@ export function setupFileNameEditing(filePath) {
|
||||
editBtn.classList.remove('visible');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up version name editing functionality
|
||||
* @param {string} filePath - File path
|
||||
*/
|
||||
export function setupVersionNameEditing(filePath) {
|
||||
const versionNameContent = document.querySelector('.version-name-content');
|
||||
const editBtn = document.querySelector('.edit-version-name-btn');
|
||||
|
||||
if (!versionNameContent || !editBtn) return;
|
||||
|
||||
// Store the file path in a data attribute for later use
|
||||
versionNameContent.dataset.filePath = filePath;
|
||||
|
||||
// Show edit button on hover
|
||||
const versionNameWrapper = document.querySelector('.version-name-wrapper');
|
||||
versionNameWrapper.addEventListener('mouseenter', () => {
|
||||
editBtn.classList.add('visible');
|
||||
});
|
||||
|
||||
versionNameWrapper.addEventListener('mouseleave', () => {
|
||||
if (!versionNameWrapper.classList.contains('editing')) {
|
||||
editBtn.classList.remove('visible');
|
||||
}
|
||||
});
|
||||
|
||||
// Handle edit button click
|
||||
editBtn.addEventListener('click', () => {
|
||||
versionNameWrapper.classList.add('editing');
|
||||
versionNameContent.setAttribute('contenteditable', 'true');
|
||||
// Store original value for comparison later
|
||||
versionNameContent.dataset.originalValue = versionNameContent.textContent.trim();
|
||||
versionNameContent.focus();
|
||||
|
||||
// Place cursor at the end
|
||||
const range = document.createRange();
|
||||
const sel = window.getSelection();
|
||||
if (versionNameContent.childNodes.length > 0) {
|
||||
range.setStart(versionNameContent.childNodes[0], versionNameContent.textContent.length);
|
||||
range.collapse(true);
|
||||
sel.removeAllRanges();
|
||||
sel.addRange(range);
|
||||
}
|
||||
|
||||
editBtn.classList.add('visible');
|
||||
});
|
||||
|
||||
// Handle keyboard events in edit mode
|
||||
versionNameContent.addEventListener('keydown', function(e) {
|
||||
if (!this.getAttribute('contenteditable')) return;
|
||||
|
||||
if (e.key === 'Enter') {
|
||||
e.preventDefault();
|
||||
this.blur(); // Trigger save on Enter
|
||||
} else if (e.key === 'Escape') {
|
||||
e.preventDefault();
|
||||
// Restore original value
|
||||
this.textContent = this.dataset.originalValue;
|
||||
exitEditMode();
|
||||
}
|
||||
});
|
||||
|
||||
// Limit version name length
|
||||
versionNameContent.addEventListener('input', function() {
|
||||
if (!this.getAttribute('contenteditable')) return;
|
||||
|
||||
if (this.textContent.length > 100) {
|
||||
this.textContent = this.textContent.substring(0, 100);
|
||||
// Place cursor at the end
|
||||
const range = document.createRange();
|
||||
const sel = window.getSelection();
|
||||
range.setStart(this.childNodes[0], 100);
|
||||
range.collapse(true);
|
||||
sel.removeAllRanges();
|
||||
sel.addRange(range);
|
||||
|
||||
showToast('toast.models.nameTooLong', {}, 'warning');
|
||||
}
|
||||
});
|
||||
|
||||
// Handle focus out - save changes
|
||||
versionNameContent.addEventListener('blur', async function() {
|
||||
if (!this.getAttribute('contenteditable')) return;
|
||||
|
||||
const newVersionName = this.textContent.trim();
|
||||
const originalValue = this.dataset.originalValue;
|
||||
|
||||
// Basic validation
|
||||
if (!newVersionName) {
|
||||
// Restore original value if empty
|
||||
this.textContent = originalValue;
|
||||
showToast('toast.models.nameCannotBeEmpty', {}, 'error');
|
||||
exitEditMode();
|
||||
return;
|
||||
}
|
||||
|
||||
if (newVersionName === originalValue) {
|
||||
// No changes, just exit edit mode
|
||||
exitEditMode();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Resolve current file path from modal state
|
||||
const filePath = getActiveModalFilePath(this.dataset.filePath);
|
||||
|
||||
await getModelApiClient().saveModelMetadata(filePath, { civitai: { name: newVersionName } });
|
||||
|
||||
showToast('toast.models.nameUpdatedSuccessfully', {}, 'success');
|
||||
} catch (error) {
|
||||
console.error('Error updating version name:', error);
|
||||
this.textContent = originalValue; // Restore original version name
|
||||
showToast('toast.models.nameUpdateFailed', {}, 'error');
|
||||
} finally {
|
||||
exitEditMode();
|
||||
}
|
||||
});
|
||||
|
||||
function exitEditMode() {
|
||||
versionNameContent.removeAttribute('contenteditable');
|
||||
versionNameWrapper.classList.remove('editing');
|
||||
editBtn.classList.remove('visible');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,8 @@ import { setupTabSwitching } from './ModelDescription.js';
|
||||
import {
|
||||
setupModelNameEditing,
|
||||
setupBaseModelEditing,
|
||||
setupFileNameEditing
|
||||
setupFileNameEditing,
|
||||
setupVersionNameEditing
|
||||
} from './ModelMetadata.js';
|
||||
import { setupTagEditMode } from './ModelTags.js';
|
||||
import { getModelApiClient } from '../../api/modelApiFactory.js';
|
||||
@@ -466,7 +467,12 @@ export async function showModelModal(model, modelType) {
|
||||
<div class="info-grid">
|
||||
<div class="info-item">
|
||||
<label>${translate('modals.model.metadata.version', {}, 'Version')}</label>
|
||||
<span>${modelWithFullData.civitai?.name || 'N/A'}</span>
|
||||
<div class="version-name-wrapper">
|
||||
<span class="version-name-content">${modelWithFullData.civitai?.name || 'N/A'}</span>
|
||||
<button class="edit-version-name-btn" title="${translate('modals.model.actions.editVersionName', {}, 'Edit version name')}">
|
||||
<i class="fas fa-pencil-alt"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<label>${translate('modals.model.metadata.fileName', {}, 'File Name')}</label>
|
||||
@@ -660,6 +666,7 @@ export async function showModelModal(model, modelType) {
|
||||
setupTagTooltip();
|
||||
setupTagEditMode(modelType);
|
||||
setupModelNameEditing(modelWithFullData.file_path);
|
||||
setupVersionNameEditing(modelWithFullData.file_path);
|
||||
setupBaseModelEditing(modelWithFullData.file_path);
|
||||
setupFileNameEditing(modelWithFullData.file_path);
|
||||
setupEventHandlers(modelWithFullData.file_path, modelType);
|
||||
|
||||
Reference in New Issue
Block a user