feat(ui): add progress modal for LoRA import (#52)

Closes settings modal and shows a dedicated progress modal with
progress bar, status text, and processed/imported counts during
LoRA import. Auto-closes after completion.
This commit is contained in:
Vito Sansevero
2026-04-03 08:46:08 -07:00
parent 0e41e6d65c
commit b24343dc6c
2 changed files with 53 additions and 6 deletions
+26
View File
@@ -471,6 +471,32 @@
</div>
</div>
<!-- LoRA Import Progress Modal -->
<div id="loraImportModal" class="fixed inset-0 bg-black/60 backdrop-blur-[2px] hidden items-center justify-center z-50">
<div class="bg-pm-surface rounded-pm-lg p-4 max-w-md w-full mx-4 border border-pm shadow-pm">
<h3 class="text-sm font-semibold text-pm mb-4">Importing LoRA Data</h3>
<div class="mb-3">
<p class="text-pm-secondary text-xs">Status:</p>
<p id="loraImportStatus" class="text-pm text-xs font-medium truncate">Initializing...</p>
</div>
<div class="mb-3">
<div class="flex justify-between text-xs text-pm-secondary mb-1">
<span>Progress</span>
<span id="loraImportPercent">0%</span>
</div>
<div class="w-full bg-pm-input rounded-full h-1.5">
<div id="loraImportBar" class="bg-pm-accent h-1.5 rounded-full transition-all duration-300" style="width: 0%"></div>
</div>
<div class="flex justify-between text-[11px] text-pm-muted mt-1">
<span id="loraImportProcessed">0 processed</span>
<span id="loraImportImported">0 imported</span>
</div>
</div>
</div>
</div>
<!-- Bulk Tag Modal -->
<div id="bulkTagModal" class="fixed inset-0 bg-black/60 backdrop-blur-[2px] hidden items-center justify-center z-50">
<div class="bg-pm-surface rounded-pm-lg p-4 max-w-md w-full mx-4 border border-pm shadow-pm">
+27 -6
View File
@@ -881,7 +881,14 @@
const saved = await this.saveLoraSettings();
if (!saved) return;
this.showNotification("Scanning LoRA metadata...", "info");
// Close settings and show progress modal
this.hideModal("settingsModal");
document.getElementById("loraImportStatus").textContent = "Initializing...";
document.getElementById("loraImportBar").style.width = "0%";
document.getElementById("loraImportPercent").textContent = "0%";
document.getElementById("loraImportProcessed").textContent = "0 processed";
document.getElementById("loraImportImported").textContent = "0 imported";
this.showModal("loraImportModal");
try {
const res = await fetch("/prompt_manager/lora/scan", { method: "POST" });
@@ -901,18 +908,32 @@
if (!line.startsWith("data: ")) continue;
try {
const data = JSON.parse(line.slice(6));
const pct = data.progress || 0;
document.getElementById("loraImportBar").style.width = `${pct}%`;
document.getElementById("loraImportPercent").textContent = `${pct}%`;
if (data.status) {
document.getElementById("loraImportStatus").textContent = data.status;
}
if (data.processed !== undefined) {
document.getElementById("loraImportProcessed").textContent = `${data.processed} processed`;
}
if (data.imported !== undefined) {
document.getElementById("loraImportImported").textContent = `${data.imported} imported`;
}
if (data.type === "complete") {
this.showNotification(
`LoRA import complete: ${data.imported} imported, ${data.skipped} skipped`,
data.imported > 0 ? "success" : "info"
);
document.getElementById("loraImportStatus").textContent =
`Done — ${data.imported} imported, ${data.skipped} skipped`;
this.loadStatistics();
setTimeout(() => this.hideModal("loraImportModal"), 2000);
}
} catch (e) { /* skip malformed SSE */ }
}
}
} catch (e) {
this.showNotification("LoRA import failed: " + e.message, "error");
document.getElementById("loraImportStatus").textContent = `Error: ${e.message}`;
setTimeout(() => this.hideModal("loraImportModal"), 3000);
}
}