mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-03-21 21:22:11 -03:00
Add CivitAI re-linking functionality and related UI components. Fixes #216
- Implemented new API endpoints for re-linking models to CivitAI. - Added context menu options for re-linking in both Lora and Checkpoint context menus. - Created a modal for user confirmation and input for CivitAI model URL. - Updated styles for the new modal and context menu items. - Enhanced error handling and user feedback during the re-linking process.
This commit is contained in:
@@ -4,6 +4,9 @@ import { showToast, getNSFWLevelName, openExampleImagesFolder } from '../../util
|
||||
import { NSFW_LEVELS } from '../../utils/constants.js';
|
||||
import { getStorageItem } from '../../utils/storageHelpers.js';
|
||||
import { showExcludeModal } from '../../utils/modalUtils.js';
|
||||
import { modalManager } from '../../managers/ModalManager.js';
|
||||
import { state } from '../../state/index.js';
|
||||
import { resetAndReload } from '../../api/checkpointApi.js';
|
||||
|
||||
export class CheckpointContextMenu extends BaseContextMenu {
|
||||
constructor() {
|
||||
@@ -56,6 +59,10 @@ export class CheckpointContextMenu extends BaseContextMenu {
|
||||
// Refresh metadata from CivitAI
|
||||
refreshSingleCheckpointMetadata(this.currentCard.dataset.filepath);
|
||||
break;
|
||||
case 'relink-civitai':
|
||||
// Handle re-link to Civitai
|
||||
this.showRelinkCivitaiModal();
|
||||
break;
|
||||
case 'set-nsfw':
|
||||
// Set NSFW level
|
||||
this.showNSFWLevelSelector(null, null, this.currentCard);
|
||||
@@ -319,4 +326,87 @@ export class CheckpointContextMenu extends BaseContextMenu {
|
||||
// Show selector
|
||||
selector.style.display = 'block';
|
||||
}
|
||||
|
||||
showRelinkCivitaiModal() {
|
||||
const filePath = this.currentCard.dataset.filepath;
|
||||
if (!filePath) return;
|
||||
|
||||
// Set up confirm button handler
|
||||
const confirmBtn = document.getElementById('confirmRelinkBtn');
|
||||
const urlInput = document.getElementById('civitaiModelUrl');
|
||||
const errorDiv = document.getElementById('civitaiModelUrlError');
|
||||
|
||||
// Remove previous event listener if exists
|
||||
if (this._boundRelinkHandler) {
|
||||
confirmBtn.removeEventListener('click', this._boundRelinkHandler);
|
||||
}
|
||||
|
||||
// Create new bound handler
|
||||
this._boundRelinkHandler = async () => {
|
||||
const url = urlInput.value.trim();
|
||||
const modelVersionId = this.extractModelVersionId(url);
|
||||
|
||||
if (!modelVersionId) {
|
||||
errorDiv.textContent = 'Invalid URL format. Must include modelVersionId parameter.';
|
||||
return;
|
||||
}
|
||||
|
||||
errorDiv.textContent = '';
|
||||
modalManager.closeModal('relinkCivitaiModal');
|
||||
|
||||
try {
|
||||
state.loadingManager.showSimpleLoading('Re-linking to Civitai...');
|
||||
|
||||
const response = await fetch('/api/checkpoints/relink-civitai', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
file_path: filePath,
|
||||
model_version_id: modelVersionId
|
||||
})
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to re-link model: ${response.statusText}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (data.success) {
|
||||
showToast('Model successfully re-linked to Civitai', 'success');
|
||||
// Reload the current view to show updated data
|
||||
await resetAndReload();
|
||||
} else {
|
||||
throw new Error(data.error || 'Failed to re-link model');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error re-linking model:', error);
|
||||
showToast(`Error: ${error.message}`, 'error');
|
||||
} finally {
|
||||
state.loadingManager.hide();
|
||||
}
|
||||
};
|
||||
|
||||
// Set new event listener
|
||||
confirmBtn.addEventListener('click', this._boundRelinkHandler);
|
||||
|
||||
// Clear previous input
|
||||
urlInput.value = '';
|
||||
errorDiv.textContent = '';
|
||||
|
||||
// Show modal
|
||||
modalManager.showModal('relinkCivitaiModal');
|
||||
}
|
||||
|
||||
extractModelVersionId(url) {
|
||||
try {
|
||||
const parsedUrl = new URL(url);
|
||||
const modelVersionId = parsedUrl.searchParams.get('modelVersionId');
|
||||
return modelVersionId;
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,11 @@
|
||||
import { BaseContextMenu } from './BaseContextMenu.js';
|
||||
import { refreshSingleLoraMetadata, saveModelMetadata, replacePreview } from '../../api/loraApi.js';
|
||||
import { refreshSingleLoraMetadata, saveModelMetadata, replacePreview, resetAndReload } from '../../api/loraApi.js';
|
||||
import { showToast, getNSFWLevelName, copyToClipboard, sendLoraToWorkflow, openExampleImagesFolder } from '../../utils/uiHelpers.js';
|
||||
import { NSFW_LEVELS } from '../../utils/constants.js';
|
||||
import { getStorageItem } from '../../utils/storageHelpers.js';
|
||||
import { showExcludeModal, showDeleteModal } from '../../utils/modalUtils.js';
|
||||
import { modalManager } from '../../managers/ModalManager.js';
|
||||
import { state } from '../../state/index.js';
|
||||
|
||||
export class LoraContextMenu extends BaseContextMenu {
|
||||
constructor() {
|
||||
@@ -64,6 +66,9 @@ export class LoraContextMenu extends BaseContextMenu {
|
||||
case 'refresh-metadata':
|
||||
refreshSingleLoraMetadata(this.currentCard.dataset.filepath);
|
||||
break;
|
||||
case 'relink-civitai':
|
||||
this.showRelinkCivitaiModal();
|
||||
break;
|
||||
case 'set-nsfw':
|
||||
this.showNSFWLevelSelector(null, null, this.currentCard);
|
||||
break;
|
||||
@@ -93,6 +98,90 @@ export class LoraContextMenu extends BaseContextMenu {
|
||||
sendLoraToWorkflow(loraSyntax, replaceMode, 'lora');
|
||||
}
|
||||
|
||||
// New method to handle re-link to Civitai
|
||||
showRelinkCivitaiModal() {
|
||||
const filePath = this.currentCard.dataset.filepath;
|
||||
if (!filePath) return;
|
||||
|
||||
// Set up confirm button handler
|
||||
const confirmBtn = document.getElementById('confirmRelinkBtn');
|
||||
const urlInput = document.getElementById('civitaiModelUrl');
|
||||
const errorDiv = document.getElementById('civitaiModelUrlError');
|
||||
|
||||
// Remove previous event listener if exists
|
||||
if (this._boundRelinkHandler) {
|
||||
confirmBtn.removeEventListener('click', this._boundRelinkHandler);
|
||||
}
|
||||
|
||||
// Create new bound handler
|
||||
this._boundRelinkHandler = async () => {
|
||||
const url = urlInput.value.trim();
|
||||
const modelVersionId = this.extractModelVersionId(url);
|
||||
|
||||
if (!modelVersionId) {
|
||||
errorDiv.textContent = 'Invalid URL format. Must include modelVersionId parameter.';
|
||||
return;
|
||||
}
|
||||
|
||||
errorDiv.textContent = '';
|
||||
modalManager.closeModal('relinkCivitaiModal');
|
||||
|
||||
try {
|
||||
state.loadingManager.showSimpleLoading('Re-linking to Civitai...');
|
||||
|
||||
const response = await fetch('/api/relink-civitai', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
file_path: filePath,
|
||||
model_version_id: modelVersionId
|
||||
})
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to re-link model: ${response.statusText}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (data.success) {
|
||||
showToast('Model successfully re-linked to Civitai', 'success');
|
||||
// Reload the current view to show updated data
|
||||
await resetAndReload();
|
||||
} else {
|
||||
throw new Error(data.error || 'Failed to re-link model');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error re-linking model:', error);
|
||||
showToast(`Error: ${error.message}`, 'error');
|
||||
} finally {
|
||||
state.loadingManager.hide();
|
||||
}
|
||||
};
|
||||
|
||||
// Set new event listener
|
||||
confirmBtn.addEventListener('click', this._boundRelinkHandler);
|
||||
|
||||
// Clear previous input
|
||||
urlInput.value = '';
|
||||
errorDiv.textContent = '';
|
||||
|
||||
// Show modal
|
||||
modalManager.showModal('relinkCivitaiModal');
|
||||
}
|
||||
|
||||
extractModelVersionId(url) {
|
||||
try {
|
||||
const parsedUrl = new URL(url);
|
||||
const modelVersionId = parsedUrl.searchParams.get('modelVersionId');
|
||||
return modelVersionId;
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// NSFW Selector methods from the original context menu
|
||||
initNSFWSelector() {
|
||||
// Close button
|
||||
|
||||
Reference in New Issue
Block a user