mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-06-09 20:39:25 -03:00
feat(modal): make version name editable in model modal (#931)
This commit is contained in:
@@ -1180,6 +1180,7 @@
|
|||||||
"editModelName": "Modellname bearbeiten",
|
"editModelName": "Modellname bearbeiten",
|
||||||
"editFileName": "Dateiname bearbeiten",
|
"editFileName": "Dateiname bearbeiten",
|
||||||
"editBaseModel": "Basis-Modell bearbeiten",
|
"editBaseModel": "Basis-Modell bearbeiten",
|
||||||
|
"editVersionName": "Versionsname bearbeiten",
|
||||||
"viewOnCivitai": "Auf Civitai anzeigen",
|
"viewOnCivitai": "Auf Civitai anzeigen",
|
||||||
"viewOnCivitaiText": "Auf Civitai anzeigen",
|
"viewOnCivitaiText": "Auf Civitai anzeigen",
|
||||||
"viewCreatorProfile": "Ersteller-Profil anzeigen",
|
"viewCreatorProfile": "Ersteller-Profil anzeigen",
|
||||||
|
|||||||
@@ -1180,6 +1180,7 @@
|
|||||||
"editModelName": "Edit model name",
|
"editModelName": "Edit model name",
|
||||||
"editFileName": "Edit file name",
|
"editFileName": "Edit file name",
|
||||||
"editBaseModel": "Edit base model",
|
"editBaseModel": "Edit base model",
|
||||||
|
"editVersionName": "Edit version name",
|
||||||
"viewOnCivitai": "View on Civitai",
|
"viewOnCivitai": "View on Civitai",
|
||||||
"viewOnCivitaiText": "View on Civitai",
|
"viewOnCivitaiText": "View on Civitai",
|
||||||
"viewCreatorProfile": "View Creator Profile",
|
"viewCreatorProfile": "View Creator Profile",
|
||||||
|
|||||||
@@ -1180,6 +1180,7 @@
|
|||||||
"editModelName": "Editar nombre del modelo",
|
"editModelName": "Editar nombre del modelo",
|
||||||
"editFileName": "Editar nombre de archivo",
|
"editFileName": "Editar nombre de archivo",
|
||||||
"editBaseModel": "Editar modelo base",
|
"editBaseModel": "Editar modelo base",
|
||||||
|
"editVersionName": "Editar nombre de versión",
|
||||||
"viewOnCivitai": "Ver en Civitai",
|
"viewOnCivitai": "Ver en Civitai",
|
||||||
"viewOnCivitaiText": "Ver en Civitai",
|
"viewOnCivitaiText": "Ver en Civitai",
|
||||||
"viewCreatorProfile": "Ver perfil del creador",
|
"viewCreatorProfile": "Ver perfil del creador",
|
||||||
|
|||||||
@@ -1180,6 +1180,7 @@
|
|||||||
"editModelName": "Modifier le nom du modèle",
|
"editModelName": "Modifier le nom du modèle",
|
||||||
"editFileName": "Modifier le nom de fichier",
|
"editFileName": "Modifier le nom de fichier",
|
||||||
"editBaseModel": "Modifier le modèle de base",
|
"editBaseModel": "Modifier le modèle de base",
|
||||||
|
"editVersionName": "Modifier le nom de la version",
|
||||||
"viewOnCivitai": "Voir sur Civitai",
|
"viewOnCivitai": "Voir sur Civitai",
|
||||||
"viewOnCivitaiText": "Voir sur Civitai",
|
"viewOnCivitaiText": "Voir sur Civitai",
|
||||||
"viewCreatorProfile": "Voir le profil du créateur",
|
"viewCreatorProfile": "Voir le profil du créateur",
|
||||||
|
|||||||
@@ -1180,6 +1180,7 @@
|
|||||||
"editModelName": "ערוך שם מודל",
|
"editModelName": "ערוך שם מודל",
|
||||||
"editFileName": "ערוך שם קובץ",
|
"editFileName": "ערוך שם קובץ",
|
||||||
"editBaseModel": "ערוך מודל בסיס",
|
"editBaseModel": "ערוך מודל בסיס",
|
||||||
|
"editVersionName": "ערוך שם גרסה",
|
||||||
"viewOnCivitai": "הצג ב-Civitai",
|
"viewOnCivitai": "הצג ב-Civitai",
|
||||||
"viewOnCivitaiText": "הצג ב-Civitai",
|
"viewOnCivitaiText": "הצג ב-Civitai",
|
||||||
"viewCreatorProfile": "הצג פרופיל יוצר",
|
"viewCreatorProfile": "הצג פרופיל יוצר",
|
||||||
|
|||||||
@@ -1180,6 +1180,7 @@
|
|||||||
"editModelName": "モデル名を編集",
|
"editModelName": "モデル名を編集",
|
||||||
"editFileName": "ファイル名を編集",
|
"editFileName": "ファイル名を編集",
|
||||||
"editBaseModel": "ベースモデルを編集",
|
"editBaseModel": "ベースモデルを編集",
|
||||||
|
"editVersionName": "バージョン名を編集",
|
||||||
"viewOnCivitai": "Civitaiで表示",
|
"viewOnCivitai": "Civitaiで表示",
|
||||||
"viewOnCivitaiText": "Civitaiで表示",
|
"viewOnCivitaiText": "Civitaiで表示",
|
||||||
"viewCreatorProfile": "作成者プロフィールを表示",
|
"viewCreatorProfile": "作成者プロフィールを表示",
|
||||||
|
|||||||
@@ -1180,6 +1180,7 @@
|
|||||||
"editModelName": "모델명 편집",
|
"editModelName": "모델명 편집",
|
||||||
"editFileName": "파일명 편집",
|
"editFileName": "파일명 편집",
|
||||||
"editBaseModel": "베이스 모델 편집",
|
"editBaseModel": "베이스 모델 편집",
|
||||||
|
"editVersionName": "버전명 편집",
|
||||||
"viewOnCivitai": "Civitai에서 보기",
|
"viewOnCivitai": "Civitai에서 보기",
|
||||||
"viewOnCivitaiText": "Civitai에서 보기",
|
"viewOnCivitaiText": "Civitai에서 보기",
|
||||||
"viewCreatorProfile": "제작자 프로필 보기",
|
"viewCreatorProfile": "제작자 프로필 보기",
|
||||||
|
|||||||
@@ -1180,6 +1180,7 @@
|
|||||||
"editModelName": "Редактировать название модели",
|
"editModelName": "Редактировать название модели",
|
||||||
"editFileName": "Редактировать имя файла",
|
"editFileName": "Редактировать имя файла",
|
||||||
"editBaseModel": "Редактировать базовую модель",
|
"editBaseModel": "Редактировать базовую модель",
|
||||||
|
"editVersionName": "Редактировать название версии",
|
||||||
"viewOnCivitai": "Посмотреть на Civitai",
|
"viewOnCivitai": "Посмотреть на Civitai",
|
||||||
"viewOnCivitaiText": "Посмотреть на Civitai",
|
"viewOnCivitaiText": "Посмотреть на Civitai",
|
||||||
"viewCreatorProfile": "Посмотреть профиль создателя",
|
"viewCreatorProfile": "Посмотреть профиль создателя",
|
||||||
|
|||||||
@@ -1180,6 +1180,7 @@
|
|||||||
"editModelName": "编辑模型名称",
|
"editModelName": "编辑模型名称",
|
||||||
"editFileName": "编辑文件名",
|
"editFileName": "编辑文件名",
|
||||||
"editBaseModel": "编辑基础模型",
|
"editBaseModel": "编辑基础模型",
|
||||||
|
"editVersionName": "编辑版本名称",
|
||||||
"viewOnCivitai": "在 Civitai 查看",
|
"viewOnCivitai": "在 Civitai 查看",
|
||||||
"viewOnCivitaiText": "在 Civitai 查看",
|
"viewOnCivitaiText": "在 Civitai 查看",
|
||||||
"viewCreatorProfile": "查看创作者主页",
|
"viewCreatorProfile": "查看创作者主页",
|
||||||
|
|||||||
@@ -1180,6 +1180,7 @@
|
|||||||
"editModelName": "編輯模型名稱",
|
"editModelName": "編輯模型名稱",
|
||||||
"editFileName": "編輯檔案名稱",
|
"editFileName": "編輯檔案名稱",
|
||||||
"editBaseModel": "編輯基礎模型",
|
"editBaseModel": "編輯基礎模型",
|
||||||
|
"editVersionName": "編輯版本名稱",
|
||||||
"viewOnCivitai": "在 Civitai 查看",
|
"viewOnCivitai": "在 Civitai 查看",
|
||||||
"viewOnCivitaiText": "在 Civitai 查看",
|
"viewOnCivitaiText": "在 Civitai 查看",
|
||||||
"viewCreatorProfile": "查看創作者個人檔案",
|
"viewCreatorProfile": "查看創作者個人檔案",
|
||||||
|
|||||||
@@ -255,25 +255,28 @@
|
|||||||
transform: translateY(-2px);
|
transform: translateY(-2px);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* File name copy styles */
|
/* Editable inline field styles (file name, version name, etc.) */
|
||||||
.file-name-wrapper {
|
.file-name-wrapper,
|
||||||
|
.version-name-wrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
padding: 4px;
|
padding: 4px 0;
|
||||||
border-radius: var(--border-radius-xs);
|
border-radius: var(--border-radius-xs);
|
||||||
transition: background-color 0.2s;
|
transition: background-color 0.2s;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.file-name-content {
|
.file-name-content,
|
||||||
padding: 2px 4px;
|
.version-name-content {
|
||||||
|
padding: 2px 4px 2px 0;
|
||||||
border-radius: var(--border-radius-xs);
|
border-radius: var(--border-radius-xs);
|
||||||
border: 1px solid transparent;
|
border: 1px solid transparent;
|
||||||
flex: 1;
|
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);
|
border: 1px solid var(--lora-accent);
|
||||||
background: var(--bg-color);
|
background: var(--bg-color);
|
||||||
outline: none;
|
outline: none;
|
||||||
@@ -283,7 +286,8 @@
|
|||||||
.edit-model-name-btn,
|
.edit-model-name-btn,
|
||||||
.edit-file-name-btn,
|
.edit-file-name-btn,
|
||||||
.edit-base-model-btn,
|
.edit-base-model-btn,
|
||||||
.edit-model-description-btn {
|
.edit-model-description-btn,
|
||||||
|
.edit-version-name-btn {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
border: none;
|
border: none;
|
||||||
color: var(--text-color);
|
color: var(--text-color);
|
||||||
@@ -299,9 +303,11 @@
|
|||||||
.edit-file-name-btn.visible,
|
.edit-file-name-btn.visible,
|
||||||
.edit-base-model-btn.visible,
|
.edit-base-model-btn.visible,
|
||||||
.edit-model-description-btn.visible,
|
.edit-model-description-btn.visible,
|
||||||
|
.edit-version-name-btn.visible,
|
||||||
.model-name-header:hover .edit-model-name-btn,
|
.model-name-header:hover .edit-model-name-btn,
|
||||||
.file-name-wrapper:hover .edit-file-name-btn,
|
.file-name-wrapper:hover .edit-file-name-btn,
|
||||||
.base-model-display:hover .edit-base-model-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 {
|
.model-name-header:hover .edit-model-description-btn {
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
}
|
}
|
||||||
@@ -309,14 +315,16 @@
|
|||||||
.edit-model-name-btn:hover,
|
.edit-model-name-btn:hover,
|
||||||
.edit-file-name-btn:hover,
|
.edit-file-name-btn:hover,
|
||||||
.edit-base-model-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;
|
opacity: 0.8 !important;
|
||||||
background: rgba(0, 0, 0, 0.05);
|
background: rgba(0, 0, 0, 0.05);
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-theme="dark"] .edit-model-name-btn:hover,
|
[data-theme="dark"] .edit-model-name-btn:hover,
|
||||||
[data-theme="dark"] .edit-file-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);
|
background: rgba(255, 255, 255, 0.05);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -338,7 +346,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.base-model-content {
|
.base-model-content {
|
||||||
padding: 2px 4px;
|
padding: 2px 4px 2px 0;
|
||||||
border-radius: var(--border-radius-xs);
|
border-radius: var(--border-radius-xs);
|
||||||
border: 1px solid transparent;
|
border: 1px solid transparent;
|
||||||
color: var(--text-color);
|
color: var(--text-color);
|
||||||
|
|||||||
@@ -66,6 +66,12 @@ function updateModalFilePathReferences(newFilePath) {
|
|||||||
fileNameContent.setAttribute('data-file-path', 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');
|
const editTagsBtn = scopedQuery('.edit-tags-btn');
|
||||||
if (editTagsBtn) {
|
if (editTagsBtn) {
|
||||||
editTagsBtn.dataset.filePath = newFilePath;
|
editTagsBtn.dataset.filePath = newFilePath;
|
||||||
@@ -516,3 +522,127 @@ export function setupFileNameEditing(filePath) {
|
|||||||
editBtn.classList.remove('visible');
|
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 {
|
import {
|
||||||
setupModelNameEditing,
|
setupModelNameEditing,
|
||||||
setupBaseModelEditing,
|
setupBaseModelEditing,
|
||||||
setupFileNameEditing
|
setupFileNameEditing,
|
||||||
|
setupVersionNameEditing
|
||||||
} from './ModelMetadata.js';
|
} from './ModelMetadata.js';
|
||||||
import { setupTagEditMode } from './ModelTags.js';
|
import { setupTagEditMode } from './ModelTags.js';
|
||||||
import { getModelApiClient } from '../../api/modelApiFactory.js';
|
import { getModelApiClient } from '../../api/modelApiFactory.js';
|
||||||
@@ -466,7 +467,12 @@ export async function showModelModal(model, modelType) {
|
|||||||
<div class="info-grid">
|
<div class="info-grid">
|
||||||
<div class="info-item">
|
<div class="info-item">
|
||||||
<label>${translate('modals.model.metadata.version', {}, 'Version')}</label>
|
<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>
|
||||||
<div class="info-item">
|
<div class="info-item">
|
||||||
<label>${translate('modals.model.metadata.fileName', {}, 'File Name')}</label>
|
<label>${translate('modals.model.metadata.fileName', {}, 'File Name')}</label>
|
||||||
@@ -660,6 +666,7 @@ export async function showModelModal(model, modelType) {
|
|||||||
setupTagTooltip();
|
setupTagTooltip();
|
||||||
setupTagEditMode(modelType);
|
setupTagEditMode(modelType);
|
||||||
setupModelNameEditing(modelWithFullData.file_path);
|
setupModelNameEditing(modelWithFullData.file_path);
|
||||||
|
setupVersionNameEditing(modelWithFullData.file_path);
|
||||||
setupBaseModelEditing(modelWithFullData.file_path);
|
setupBaseModelEditing(modelWithFullData.file_path);
|
||||||
setupFileNameEditing(modelWithFullData.file_path);
|
setupFileNameEditing(modelWithFullData.file_path);
|
||||||
setupEventHandlers(modelWithFullData.file_path, modelType);
|
setupEventHandlers(modelWithFullData.file_path, modelType);
|
||||||
|
|||||||
Reference in New Issue
Block a user