refactor: unify model download system across all model types

- Add download-related methods to baseModelApi.js for fetching versions, roots, folders, and downloading models
- Replace separate download managers with a unified DownloadManager.js supporting all model types
- Create a single download_modals.html template that adapts to model type (LoRA, checkpoint, etc.)
- Remove old download modals from lora_modals.html and checkpoint_modals.html
- Update apiConfig.js to include civitaiVersions endpoints for each model type
- Centralize event handler binding in DownloadManager.js (no more inline HTML handlers)
- Modal UI and logic now auto-adapt to the current model type, making future extension easier
This commit is contained in:
Will Miao
2025-07-25 17:35:06 +08:00
parent e587189880
commit 7f205cdcc8
16 changed files with 337 additions and 785 deletions

View File

@@ -12,7 +12,6 @@
{% block init_check_url %}/api/checkpoints?page=1&page_size=1{% endblock %}
{% block additional_components %}
{% include 'components/checkpoint_modals.html' %}
<div id="checkpointContextMenu" class="context-menu" style="display: none;">
<!-- <div class="context-menu-item" data-action="details"><i class="fas fa-info-circle"></i> View Details</div> -->

View File

@@ -1,73 +0,0 @@
<!-- Checkpoint Modals -->
<!-- Checkpoint details Modal -->
<div id="modelModal" class="modal"></div>
<!-- Download Checkpoint from URL Modal -->
<div id="checkpointDownloadModal" class="modal">
<div class="modal-content">
<button class="close" onclick="modalManager.closeModal('checkpointDownloadModal')">&times;</button>
<h2>Download Checkpoint from URL</h2>
<!-- Step 1: URL Input -->
<div class="download-step" id="cpUrlStep">
<div class="input-group">
<label for="checkpointUrl">Civitai URL:</label>
<input type="text" id="checkpointUrl" placeholder="https://civitai.com/models/..." />
<div class="error-message" id="cpUrlError"></div>
</div>
<div class="modal-actions">
<button class="primary-btn" onclick="checkpointDownloadManager.validateAndFetchVersions()">Next</button>
</div>
</div>
<!-- Step 2: Version Selection -->
<div class="download-step" id="cpVersionStep" style="display: none;">
<div class="version-list" id="cpVersionList">
<!-- Versions will be inserted here dynamically -->
</div>
<div class="modal-actions">
<button class="secondary-btn" onclick="checkpointDownloadManager.backToUrl()">Back</button>
<button class="primary-btn" onclick="checkpointDownloadManager.proceedToLocation()">Next</button>
</div>
</div>
<!-- Step 3: Location Selection -->
<div class="download-step" id="cpLocationStep" style="display: none;">
<div class="location-selection">
<!-- Move path preview to top -->
<div class="path-preview">
<label>Download Location Preview:</label>
<div class="path-display" id="cpTargetPathDisplay">
<span class="path-text">Select a Checkpoint root directory</span>
</div>
</div>
<div class="input-group">
<label>Select Checkpoint Root:</label>
<select id="checkpointRoot"></select>
</div>
<div class="input-group">
<label>Target Folder:</label>
<div class="folder-browser" id="cpFolderBrowser">
{% for folder in folders %}
{% if folder %}
<div class="folder-item" data-folder="{{ folder }}">
{{ folder }}
</div>
{% endif %}
{% endfor %}
</div>
</div>
<div class="input-group">
<label for="cpNewFolder">New Folder (optional):</label>
<input type="text" id="cpNewFolder" placeholder="Enter folder name" />
</div>
</div>
<div class="modal-actions">
<button class="secondary-btn" onclick="checkpointDownloadManager.backToVersions()">Back</button>
<button class="primary-btn" onclick="checkpointDownloadManager.startDownload()">Download</button>
</div>
</div>
</div>
</div>

View File

@@ -1,102 +0,0 @@
<!-- Model details Modal -->
<div id="modelModal" class="modal"></div>
<!-- Download from URL Modal (for LoRAs) -->
<div id="downloadModal" class="modal">
<div class="modal-content">
<button class="close" onclick="modalManager.closeModal('downloadModal')">&times;</button>
<h2>Download LoRA from URL</h2>
<!-- Step 1: URL Input -->
<div class="download-step" id="urlStep">
<div class="input-group">
<label for="loraUrl">Civitai URL:</label>
<input type="text" id="loraUrl" placeholder="https://civitai.com/models/..." />
<div class="error-message" id="urlError"></div>
</div>
<div class="modal-actions">
<button class="primary-btn" onclick="downloadManager.validateAndFetchVersions()">Next</button>
</div>
</div>
<!-- Step 2: Version Selection -->
<div class="download-step" id="versionStep" style="display: none;">
<div class="version-list" id="versionList">
<!-- Versions will be inserted here dynamically -->
</div>
<div class="modal-actions">
<button class="secondary-btn" onclick="downloadManager.backToUrl()">Back</button>
<button class="primary-btn" onclick="downloadManager.proceedToLocation()">Next</button>
</div>
</div>
<!-- Step 3: Location Selection -->
<div class="download-step" id="locationStep" style="display: none;">
<div class="location-selection">
<!-- Move path preview to top -->
<div class="path-preview">
<label>Download Location Preview:</label>
<div class="path-display" id="targetPathDisplay">
<span class="path-text">Select a LoRA root directory</span>
</div>
</div>
<div class="input-group">
<label>Select LoRA Root:</label>
<select id="loraRoot"></select>
</div>
<div class="input-group">
<label>Target Folder:</label>
<div class="folder-browser" id="folderBrowser">
<!-- Folders will be loaded dynamically -->
</div>
</div>
<div class="input-group">
<label for="newFolder">New Folder (optional):</label>
<input type="text" id="newFolder" placeholder="Enter folder name" />
</div>
</div>
<div class="modal-actions">
<button class="secondary-btn" onclick="downloadManager.backToVersions()">Back</button>
<button class="primary-btn" onclick="downloadManager.startDownload()">Download</button>
</div>
</div>
</div>
</div>
<!-- Move Model Modal -->
<div id="moveModal" class="modal">
<div class="modal-content">
<div class="modal-header">
<h2 id="moveModalTitle">Move Model</h2>
<span class="close" onclick="modalManager.closeModal('moveModal')">&times;</span>
</div>
<div class="location-selection">
<div class="path-preview">
<label>Target Location Preview:</label>
<div class="path-display" id="moveTargetPathDisplay">
<span class="path-text">Select a LoRA root directory</span>
</div>
</div>
<div class="input-group">
<label>Select LoRA Root:</label>
<select id="moveLoraRoot"></select>
</div>
<div class="input-group">
<label>Target Folder:</label>
<div class="folder-browser" id="moveFolderBrowser">
<!-- Folders will be loaded dynamically -->
</div>
</div>
<div class="input-group">
<label for="moveNewFolder">New Folder (optional):</label>
<input type="text" id="moveNewFolder" placeholder="Enter folder name" />
</div>
</div>
<div class="modal-actions">
<button class="cancel-btn" onclick="modalManager.closeModal('moveModal')">Cancel</button>
<button class="primary-btn" onclick="moveManager.moveModel()">Move</button>
</div>
</div>
</div>

View File

@@ -1,7 +1,12 @@
<!-- Model details Modal -->
<div id="modelModal" class="modal"></div>
{% include 'components/modals/confirm_modals.html' %}
{% include 'components/modals/settings_modal.html' %}
{% include 'components/modals/support_modal.html' %}
{% include 'components/modals/update_modal.html' %}
{% include 'components/modals/help_modal.html' %}
{% include 'components/modals/relink_civitai_modal.html' %}
{% include 'components/modals/example_access_modal.html' %}
{% include 'components/modals/example_access_modal.html' %}
{% include 'components/modals/download_modal.html' %}
{% include 'components/modals/move_modal.html' %}

View File

@@ -0,0 +1,62 @@
<!-- Unified Download Modal for all model types -->
<div id="downloadModal" class="modal">
<div class="modal-content">
<button class="close" id="closeDownloadModal">&times;</button>
<h2 id="downloadModalTitle">Download Model from URL</h2>
<!-- Step 1: URL Input -->
<div class="download-step" id="urlStep">
<div class="input-group">
<label for="modelUrl" id="modelUrlLabel">Civitai URL:</label>
<input type="text" id="modelUrl" placeholder="https://civitai.com/models/..." />
<div class="error-message" id="urlError"></div>
</div>
<div class="modal-actions">
<button class="primary-btn" id="nextFromUrl">Next</button>
</div>
</div>
<!-- Step 2: Version Selection -->
<div class="download-step" id="versionStep" style="display: none;">
<div class="version-list" id="versionList">
<!-- Versions will be inserted here dynamically -->
</div>
<div class="modal-actions">
<button class="secondary-btn" id="backToUrlBtn">Back</button>
<button class="primary-btn" id="nextFromVersion">Next</button>
</div>
</div>
<!-- Step 3: Location Selection -->
<div class="download-step" id="locationStep" style="display: none;">
<div class="location-selection">
<!-- Path preview -->
<div class="path-preview">
<label>Download Location Preview:</label>
<div class="path-display" id="targetPathDisplay">
<span class="path-text">Select a root directory</span>
</div>
</div>
<div class="input-group">
<label for="modelRoot" id="modelRootLabel">Select Model Root:</label>
<select id="modelRoot"></select>
</div>
<div class="input-group">
<label>Target Folder:</label>
<div class="folder-browser" id="folderBrowser">
<!-- Folders will be loaded dynamically -->
</div>
</div>
<div class="input-group">
<label for="newFolder">New Folder (optional):</label>
<input type="text" id="newFolder" placeholder="Enter folder name" />
</div>
</div>
<div class="modal-actions">
<button class="secondary-btn" id="backToVersionsBtn">Back</button>
<button class="primary-btn" id="startDownloadBtn">Download</button>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,36 @@
<!-- Move Model Modal -->
<div id="moveModal" class="modal">
<div class="modal-content">
<div class="modal-header">
<h2 id="moveModalTitle">Move Model</h2>
<span class="close" onclick="modalManager.closeModal('moveModal')">&times;</span>
</div>
<div class="location-selection">
<div class="path-preview">
<label>Target Location Preview:</label>
<div class="path-display" id="moveTargetPathDisplay">
<span class="path-text">Select a LoRA root directory</span>
</div>
</div>
<div class="input-group">
<label>Select LoRA Root:</label>
<select id="moveLoraRoot"></select>
</div>
<div class="input-group">
<label>Target Folder:</label>
<div class="folder-browser" id="moveFolderBrowser">
<!-- Folders will be loaded dynamically -->
</div>
</div>
<div class="input-group">
<label for="moveNewFolder">New Folder (optional):</label>
<input type="text" id="moveNewFolder" placeholder="Enter folder name" />
</div>
</div>
<div class="modal-actions">
<button class="cancel-btn" onclick="modalManager.closeModal('moveModal')">Cancel</button>
<button class="primary-btn" onclick="moveManager.moveModel()">Move</button>
</div>
</div>
</div>

View File

@@ -13,10 +13,6 @@
{% block init_message %}Scanning and building LoRA cache. This may take a few minutes...{% endblock %}
{% block init_check_url %}/api/loras?page=1&page_size=1{% endblock %}
{% block additional_components %}
{% include 'components/lora_modals.html' %}
{% endblock %}
{% block content %}
{% include 'components/controls.html' %}
{% include 'components/alphabet_bar.html' %}