mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-03-25 07:05:43 -03:00
checkpoint
This commit is contained in:
@@ -220,12 +220,19 @@ class RecipeRoutes:
|
|||||||
|
|
||||||
# Check if this LoRA exists locally by SHA256 hash
|
# Check if this LoRA exists locally by SHA256 hash
|
||||||
exists_locally = False
|
exists_locally = False
|
||||||
|
local_path = None
|
||||||
|
|
||||||
if civitai_info and 'files' in civitai_info and civitai_info['files']:
|
if civitai_info and 'files' in civitai_info:
|
||||||
sha256 = civitai_info['files'][0].get('hashes', {}).get('SHA256', '')
|
# Find the model file (type="Model") in the files list
|
||||||
if sha256:
|
model_file = next((file for file in civitai_info.get('files', [])
|
||||||
sha256 = sha256.lower() # Convert to lowercase for consistency
|
if file.get('type') == 'Model'), None)
|
||||||
exists_locally = self.recipe_scanner._lora_scanner.has_lora_hash(sha256)
|
|
||||||
|
if model_file:
|
||||||
|
sha256 = model_file.get('hashes', {}).get('SHA256', '')
|
||||||
|
if sha256:
|
||||||
|
exists_locally = self.recipe_scanner._lora_scanner.has_lora_hash(sha256)
|
||||||
|
if exists_locally:
|
||||||
|
local_path = self.recipe_scanner._lora_scanner.get_lora_path_by_hash(sha256)
|
||||||
|
|
||||||
# Create LoRA entry
|
# Create LoRA entry
|
||||||
lora_entry = {
|
lora_entry = {
|
||||||
@@ -235,6 +242,7 @@ class RecipeRoutes:
|
|||||||
'type': resource.get('type', 'lora'),
|
'type': resource.get('type', 'lora'),
|
||||||
'weight': resource.get('weight', 1.0),
|
'weight': resource.get('weight', 1.0),
|
||||||
'existsLocally': exists_locally,
|
'existsLocally': exists_locally,
|
||||||
|
'localPath': local_path,
|
||||||
'thumbnailUrl': '',
|
'thumbnailUrl': '',
|
||||||
'baseModel': '',
|
'baseModel': '',
|
||||||
'size': 0,
|
'size': 0,
|
||||||
@@ -250,9 +258,9 @@ class RecipeRoutes:
|
|||||||
# Get base model
|
# Get base model
|
||||||
lora_entry['baseModel'] = civitai_info.get('baseModel', '')
|
lora_entry['baseModel'] = civitai_info.get('baseModel', '')
|
||||||
|
|
||||||
# Get file size
|
# Get file size from model file
|
||||||
if 'files' in civitai_info and civitai_info['files']:
|
if model_file:
|
||||||
lora_entry['size'] = civitai_info['files'][0].get('sizeKB', 0) * 1024
|
lora_entry['size'] = model_file.get('sizeKB', 0) * 1024
|
||||||
|
|
||||||
# Get download URL
|
# Get download URL
|
||||||
lora_entry['downloadUrl'] = civitai_info.get('downloadUrl', '')
|
lora_entry['downloadUrl'] = civitai_info.get('downloadUrl', '')
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
/* Import Modal Styles */
|
/* Import Modal Styles */
|
||||||
.import-step {
|
.import-step {
|
||||||
margin: var(--space-2) 0;
|
margin: var(--space-2) 0;
|
||||||
|
transition: none !important; /* Disable any transitions that might affect display */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* File Input Styles */
|
/* File Input Styles */
|
||||||
@@ -364,14 +365,6 @@
|
|||||||
margin-top: 4px;
|
margin-top: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Modal Actions */
|
|
||||||
.modal-actions {
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-end;
|
|
||||||
gap: var(--space-2);
|
|
||||||
margin-top: var(--space-3);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Dark theme adjustments */
|
/* Dark theme adjustments */
|
||||||
[data-theme="dark"] .lora-item {
|
[data-theme="dark"] .lora-item {
|
||||||
background: var(--lora-surface);
|
background: var(--lora-surface);
|
||||||
@@ -391,3 +384,58 @@
|
|||||||
height: 150px;
|
height: 150px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Size badge for LoRA items */
|
||||||
|
.size-badge {
|
||||||
|
background: var(--lora-surface);
|
||||||
|
padding: 2px 8px;
|
||||||
|
border-radius: var(--border-radius-xs);
|
||||||
|
font-size: 0.85em;
|
||||||
|
color: var(--text-color);
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Missing LoRAs summary section */
|
||||||
|
.missing-loras-summary {
|
||||||
|
margin-bottom: var(--space-3);
|
||||||
|
padding: var(--space-2);
|
||||||
|
background: var(--bg-color);
|
||||||
|
border-radius: var(--border-radius-sm);
|
||||||
|
border: 1px solid var(--lora-error);
|
||||||
|
}
|
||||||
|
|
||||||
|
.missing-loras-summary h3 {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: var(--space-2);
|
||||||
|
font-size: 1.1em;
|
||||||
|
color: var(--text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.total-size-info {
|
||||||
|
margin-bottom: var(--space-2);
|
||||||
|
font-size: 0.9em;
|
||||||
|
color: var(--text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.missing-lora-item {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 8px;
|
||||||
|
border-bottom: 1px solid var(--border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.missing-lora-item:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.missing-lora-name {
|
||||||
|
font-weight: 500;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.missing-lora-size {
|
||||||
|
font-size: 0.9em;
|
||||||
|
color: var(--text-color);
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
@@ -36,14 +36,22 @@ export class ImportManager {
|
|||||||
this.initialized = true;
|
this.initialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Always reset the state when opening the modal
|
||||||
|
this.resetSteps();
|
||||||
|
|
||||||
|
// Show the modal
|
||||||
modalManager.showModal('importModal', null, () => {
|
modalManager.showModal('importModal', null, () => {
|
||||||
// Cleanup handler when modal closes
|
// Cleanup handler when modal closes
|
||||||
this.cleanupFolderBrowser();
|
this.cleanupFolderBrowser();
|
||||||
|
|
||||||
// 移除任何强制样式
|
// Remove any injected styles
|
||||||
this.removeInjectedStyles();
|
this.removeInjectedStyles();
|
||||||
});
|
});
|
||||||
this.resetSteps();
|
|
||||||
|
// Verify the modal is properly shown
|
||||||
|
setTimeout(() => {
|
||||||
|
this.ensureModalVisible();
|
||||||
|
}, 50);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加移除注入样式的方法
|
// 添加移除注入样式的方法
|
||||||
@@ -52,12 +60,18 @@ export class ImportManager {
|
|||||||
this.injectedStyles.parentNode.removeChild(this.injectedStyles);
|
this.injectedStyles.parentNode.removeChild(this.injectedStyles);
|
||||||
this.injectedStyles = null;
|
this.injectedStyles = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Also reset any inline styles that might have been set with !important
|
||||||
|
document.querySelectorAll('.import-step').forEach(step => {
|
||||||
|
step.style.cssText = '';
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
resetSteps() {
|
resetSteps() {
|
||||||
// 移除可能存在的强制样式
|
// Remove any existing injected styles
|
||||||
this.removeInjectedStyles();
|
this.removeInjectedStyles();
|
||||||
|
|
||||||
|
// Show the first step
|
||||||
this.showStep('uploadStep');
|
this.showStep('uploadStep');
|
||||||
|
|
||||||
// Reset file input
|
// Reset file input
|
||||||
@@ -78,6 +92,18 @@ export class ImportManager {
|
|||||||
previewElement.innerHTML = '<div class="placeholder">Image preview will appear here</div>';
|
previewElement.innerHTML = '<div class="placeholder">Image preview will appear here</div>';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reset recipe name input
|
||||||
|
const recipeName = document.getElementById('recipeName');
|
||||||
|
if (recipeName) {
|
||||||
|
recipeName.value = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset tags container
|
||||||
|
const tagsContainer = document.getElementById('tagsContainer');
|
||||||
|
if (tagsContainer) {
|
||||||
|
tagsContainer.innerHTML = '<div class="empty-tags">No tags added</div>';
|
||||||
|
}
|
||||||
|
|
||||||
// Reset state variables
|
// Reset state variables
|
||||||
this.recipeImage = null;
|
this.recipeImage = null;
|
||||||
this.recipeData = null;
|
this.recipeData = null;
|
||||||
@@ -92,6 +118,18 @@ export class ImportManager {
|
|||||||
folderBrowser.querySelectorAll('.folder-item').forEach(f =>
|
folderBrowser.querySelectorAll('.folder-item').forEach(f =>
|
||||||
f.classList.remove('selected'));
|
f.classList.remove('selected'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clear missing LoRAs list if it exists
|
||||||
|
const missingLorasList = document.getElementById('missingLorasList');
|
||||||
|
if (missingLorasList) {
|
||||||
|
missingLorasList.innerHTML = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset total download size
|
||||||
|
const totalSizeDisplay = document.getElementById('totalDownloadSize');
|
||||||
|
if (totalSizeDisplay) {
|
||||||
|
totalSizeDisplay.textContent = 'Calculating...';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleImageUpload(event) {
|
handleImageUpload(event) {
|
||||||
@@ -207,6 +245,10 @@ export class ImportManager {
|
|||||||
<i class="fas fa-exclamation-triangle"></i> Not in Library
|
<i class="fas fa-exclamation-triangle"></i> Not in Library
|
||||||
</div>`;
|
</div>`;
|
||||||
|
|
||||||
|
// Format size if available
|
||||||
|
const sizeDisplay = lora.size ?
|
||||||
|
`<div class="size-badge">${this.formatFileSize(lora.size)}</div>` : '';
|
||||||
|
|
||||||
return `
|
return `
|
||||||
<div class="lora-item ${existsLocally ? 'exists-locally' : 'missing-locally'}">
|
<div class="lora-item ${existsLocally ? 'exists-locally' : 'missing-locally'}">
|
||||||
<div class="lora-thumbnail">
|
<div class="lora-thumbnail">
|
||||||
@@ -220,6 +262,7 @@ export class ImportManager {
|
|||||||
${lora.version ? `<div class="lora-version">${lora.version}</div>` : ''}
|
${lora.version ? `<div class="lora-version">${lora.version}</div>` : ''}
|
||||||
<div class="lora-info">
|
<div class="lora-info">
|
||||||
${lora.baseModel ? `<div class="base-model">${lora.baseModel}</div>` : ''}
|
${lora.baseModel ? `<div class="base-model">${lora.baseModel}</div>` : ''}
|
||||||
|
${sizeDisplay}
|
||||||
<div class="weight-badge">Weight: ${lora.weight || 1.0}</div>
|
<div class="weight-badge">Weight: ${lora.weight || 1.0}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -291,8 +334,6 @@ export class ImportManager {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('Proceeding from details, missing LoRAs:', this.missingLoras.length);
|
|
||||||
|
|
||||||
// If we have missing LoRAs, go to location step
|
// If we have missing LoRAs, go to location step
|
||||||
if (this.missingLoras.length > 0) {
|
if (this.missingLoras.length > 0) {
|
||||||
this.proceedToLocation();
|
this.proceedToLocation();
|
||||||
@@ -303,30 +344,61 @@ export class ImportManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async proceedToLocation() {
|
async proceedToLocation() {
|
||||||
// 先移除可能已有的样式
|
|
||||||
this.removeInjectedStyles();
|
|
||||||
|
|
||||||
// 添加强制CSS覆盖
|
|
||||||
this.injectedStyles = document.createElement('style');
|
|
||||||
this.injectedStyles.innerHTML = `
|
|
||||||
#locationStep {
|
|
||||||
display: block !important;
|
|
||||||
opacity: 1 !important;
|
|
||||||
visibility: visible !important;
|
|
||||||
position: static !important;
|
|
||||||
z-index: 10000 !important;
|
|
||||||
width: auto !important;
|
|
||||||
height: auto !important;
|
|
||||||
overflow: visible !important;
|
|
||||||
transform: none !important;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
document.head.appendChild(this.injectedStyles);
|
|
||||||
console.log('Added override CSS to force visibility');
|
|
||||||
|
|
||||||
|
// Show the location step with special handling
|
||||||
this.showStep('locationStep');
|
this.showStep('locationStep');
|
||||||
|
|
||||||
|
// Double-check after a short delay to ensure the step is visible
|
||||||
|
setTimeout(() => {
|
||||||
|
const locationStep = document.getElementById('locationStep');
|
||||||
|
if (locationStep.style.display !== 'block' ||
|
||||||
|
window.getComputedStyle(locationStep).display !== 'block') {
|
||||||
|
// Force display again
|
||||||
|
locationStep.style.display = 'block';
|
||||||
|
|
||||||
|
// If still not visible, try with injected style
|
||||||
|
if (window.getComputedStyle(locationStep).display !== 'block') {
|
||||||
|
this.injectedStyles = document.createElement('style');
|
||||||
|
this.injectedStyles.innerHTML = `
|
||||||
|
#locationStep {
|
||||||
|
display: block !important;
|
||||||
|
opacity: 1 !important;
|
||||||
|
visibility: visible !important;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
document.head.appendChild(this.injectedStyles);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// Display missing LoRAs that will be downloaded
|
||||||
|
const missingLorasList = document.getElementById('missingLorasList');
|
||||||
|
if (missingLorasList && this.missingLoras.length > 0) {
|
||||||
|
// Calculate total size
|
||||||
|
const totalSize = this.missingLoras.reduce((sum, lora) => {
|
||||||
|
return sum + (lora.size ? parseInt(lora.size) : 0);
|
||||||
|
}, 0);
|
||||||
|
|
||||||
|
// Update total size display
|
||||||
|
const totalSizeDisplay = document.getElementById('totalDownloadSize');
|
||||||
|
if (totalSizeDisplay) {
|
||||||
|
totalSizeDisplay.textContent = this.formatFileSize(totalSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate missing LoRAs list
|
||||||
|
missingLorasList.innerHTML = this.missingLoras.map(lora => {
|
||||||
|
const sizeDisplay = lora.size ? this.formatFileSize(lora.size) : 'Unknown size';
|
||||||
|
|
||||||
|
return `
|
||||||
|
<div class="missing-lora-item">
|
||||||
|
<div class="missing-lora-name">${lora.name}</div>
|
||||||
|
<div class="missing-lora-size">${sizeDisplay}</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}).join('');
|
||||||
|
}
|
||||||
|
|
||||||
// Fetch LoRA roots
|
// Fetch LoRA roots
|
||||||
const rootsResponse = await fetch('/api/lora-roots');
|
const rootsResponse = await fetch('/api/lora-roots');
|
||||||
if (!rootsResponse.ok) {
|
if (!rootsResponse.ok) {
|
||||||
@@ -365,6 +437,18 @@ export class ImportManager {
|
|||||||
|
|
||||||
backToUpload() {
|
backToUpload() {
|
||||||
this.showStep('uploadStep');
|
this.showStep('uploadStep');
|
||||||
|
|
||||||
|
// Reset file input to ensure it can trigger change events again
|
||||||
|
const fileInput = document.getElementById('recipeImageUpload');
|
||||||
|
if (fileInput) {
|
||||||
|
fileInput.value = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear any previous error messages
|
||||||
|
const errorElement = document.getElementById('uploadError');
|
||||||
|
if (errorElement) {
|
||||||
|
errorElement.textContent = '';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
backToDetails() {
|
backToDetails() {
|
||||||
@@ -397,7 +481,6 @@ export class ImportManager {
|
|||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
// Handle successful save
|
// Handle successful save
|
||||||
console.log(`Recipe saved with ID: ${result.recipe_id}`);
|
|
||||||
// Show success message for recipe save
|
// Show success message for recipe save
|
||||||
showToast(`Recipe "${this.recipeName}" saved successfully`, 'success');
|
showToast(`Recipe "${this.recipeName}" saved successfully`, 'success');
|
||||||
|
|
||||||
@@ -544,7 +627,6 @@ export class ImportManager {
|
|||||||
if (loraRoot) loraRoot.addEventListener('change', this.updateTargetPath);
|
if (loraRoot) loraRoot.addEventListener('change', this.updateTargetPath);
|
||||||
if (newFolder) newFolder.addEventListener('input', this.updateTargetPath);
|
if (newFolder) newFolder.addEventListener('input', this.updateTargetPath);
|
||||||
|
|
||||||
console.log('Initializing folder browser...');
|
|
||||||
// Update initial path
|
// Update initial path
|
||||||
this.updateTargetPath();
|
this.updateTargetPath();
|
||||||
}
|
}
|
||||||
@@ -588,36 +670,80 @@ export class ImportManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
showStep(stepId) {
|
showStep(stepId) {
|
||||||
// 隐藏所有步骤
|
|
||||||
|
// First, remove any injected styles to prevent conflicts
|
||||||
|
this.removeInjectedStyles();
|
||||||
|
|
||||||
|
// Hide all steps first
|
||||||
document.querySelectorAll('.import-step').forEach(step => {
|
document.querySelectorAll('.import-step').forEach(step => {
|
||||||
step.style.display = 'none';
|
step.style.display = 'none';
|
||||||
});
|
});
|
||||||
|
|
||||||
// 显示目标步骤
|
// Show target step with a monitoring mechanism
|
||||||
const targetStep = document.getElementById(stepId);
|
const targetStep = document.getElementById(stepId);
|
||||||
if (targetStep) {
|
if (targetStep) {
|
||||||
// 强制显示目标步骤 - 使用 !important 覆盖任何其他CSS规则
|
// Use direct style setting
|
||||||
targetStep.setAttribute('style', 'display: block !important');
|
targetStep.style.display = 'block';
|
||||||
|
|
||||||
// 调试信息
|
// For the locationStep specifically, we need additional measures
|
||||||
console.log(`Showing step: ${stepId}`);
|
if (stepId === 'locationStep') {
|
||||||
const rect = targetStep.getBoundingClientRect();
|
// Create a more persistent style to override any potential conflicts
|
||||||
console.log('Step dimensions:', {
|
this.injectedStyles = document.createElement('style');
|
||||||
width: rect.width,
|
this.injectedStyles.innerHTML = `
|
||||||
height: rect.height,
|
#locationStep {
|
||||||
top: rect.top,
|
display: block !important;
|
||||||
left: rect.left,
|
opacity: 1 !important;
|
||||||
visible: rect.width > 0 && rect.height > 0
|
visibility: visible !important;
|
||||||
});
|
}
|
||||||
|
`;
|
||||||
|
document.head.appendChild(this.injectedStyles);
|
||||||
|
|
||||||
|
// Force layout recalculation
|
||||||
|
targetStep.offsetHeight;
|
||||||
|
|
||||||
|
// Set up a monitor to ensure the step remains visible
|
||||||
|
setTimeout(() => {
|
||||||
|
if (targetStep.style.display !== 'block') {
|
||||||
|
targetStep.style.display = 'block';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check dimensions again after a short delay
|
||||||
|
const newRect = targetStep.getBoundingClientRect();
|
||||||
|
}, 50);
|
||||||
|
}
|
||||||
|
|
||||||
// 强制重新计算布局
|
// Scroll modal content to top
|
||||||
targetStep.offsetHeight;
|
|
||||||
|
|
||||||
// 滚动模态内容到顶部
|
|
||||||
const modalContent = document.querySelector('#importModal .modal-content');
|
const modalContent = document.querySelector('#importModal .modal-content');
|
||||||
if (modalContent) {
|
if (modalContent) {
|
||||||
modalContent.scrollTop = 0;
|
modalContent.scrollTop = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add a helper method to format file sizes
|
||||||
|
formatFileSize(bytes) {
|
||||||
|
if (!bytes || isNaN(bytes)) return '';
|
||||||
|
|
||||||
|
const sizes = ['B', 'KB', 'MB', 'GB'];
|
||||||
|
const i = Math.floor(Math.log(bytes) / Math.log(1024));
|
||||||
|
return (bytes / Math.pow(1024, i)).toFixed(2) + ' ' + sizes[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add this method to ensure the modal is fully visible and initialized
|
||||||
|
ensureModalVisible() {
|
||||||
|
const importModal = document.getElementById('importModal');
|
||||||
|
if (!importModal) {
|
||||||
|
console.error('Import modal element not found');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if modal is actually visible
|
||||||
|
const modalDisplay = window.getComputedStyle(importModal).display;
|
||||||
|
if (modalDisplay !== 'block') {
|
||||||
|
console.error('Import modal is not visible, display: ' + modalDisplay);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -68,6 +68,17 @@
|
|||||||
<!-- Step 3: Download Location (if needed) -->
|
<!-- Step 3: Download Location (if needed) -->
|
||||||
<div class="import-step" id="locationStep" style="display: none;">
|
<div class="import-step" id="locationStep" style="display: none;">
|
||||||
<div class="location-selection">
|
<div class="location-selection">
|
||||||
|
<!-- Add missing LoRAs summary section -->
|
||||||
|
<div class="missing-loras-summary">
|
||||||
|
<h3>Missing LoRAs to Download</h3>
|
||||||
|
<div class="total-size-info">
|
||||||
|
Total download size: <span id="totalDownloadSize">Calculating...</span>
|
||||||
|
</div>
|
||||||
|
<div id="missingLorasList" class="missing-loras-list">
|
||||||
|
<!-- Missing LoRAs will be populated here -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Move path preview to top -->
|
<!-- Move path preview to top -->
|
||||||
<div class="path-preview">
|
<div class="path-preview">
|
||||||
<label>Download Location Preview:</label>
|
<label>Download Location Preview:</label>
|
||||||
|
|||||||
Reference in New Issue
Block a user