Add global loader overlay and progress feedback for imports

This commit is contained in:
Stu Leak 2025-12-04 12:22:47 -05:00
parent fa4423acfe
commit 4ff7708f76
3 changed files with 86 additions and 0 deletions

View File

@ -540,6 +540,44 @@ main.container {
color: #ff8a8a;
}
.global-loader {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.55);
backdrop-filter: blur(2px);
display: flex;
align-items: center;
justify-content: center;
z-index: 2000;
}
.global-loader .loader-content {
background: var(--color-bg-card);
padding: 1.5rem 2rem;
border-radius: 12px;
border: 1px solid var(--color-border);
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.35);
display: flex;
gap: 1rem;
align-items: center;
color: var(--color-text-primary);
min-width: 280px;
justify-content: center;
}
.global-loader .spinner {
width: 24px;
height: 24px;
border: 3px solid rgba(255, 255, 255, 0.2);
border-top-color: var(--color-brand);
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
/* Detail views */
.breadcrumb {
margin-bottom: 1.5rem;

View File

@ -97,7 +97,9 @@ function displayGlobalSearchResults(data) {
// Bulk Import Functions
async function bulkImportAll() {
showLoader('Importing all data from TPDB...');
if (!confirm('This will import ALL data from TPDB. This may take several hours. Continue?')) {
hideLoader();
return;
}
@ -127,11 +129,15 @@ async function bulkImportAll() {
}
} catch (error) {
setImportStatus('import-all', 'Error: ' + error.message, false);
} finally {
hideLoader();
}
}
async function bulkImportPerformers() {
showLoader('Importing performers from TPDB...');
if (!confirm('This will import ALL performers from TPDB. Continue?')) {
hideLoader();
return;
}
@ -165,11 +171,14 @@ async function bulkImportPerformers() {
eventSource.onerror = function() {
updateProgress('performers', 0, 0, 'Connection error', true);
eventSource.close();
hideLoader();
};
}
async function bulkImportStudios() {
showLoader('Importing studios from TPDB...');
if (!confirm('This will import ALL studios from TPDB. Continue?')) {
hideLoader();
return;
}
@ -203,11 +212,14 @@ async function bulkImportStudios() {
eventSource.onerror = function() {
updateProgress('studios', 0, 0, 'Connection error', true);
eventSource.close();
hideLoader();
};
}
async function bulkImportScenes() {
showLoader('Importing scenes from TPDB...');
if (!confirm('This will import ALL scenes from TPDB. Continue?')) {
hideLoader();
return;
}
@ -241,6 +253,7 @@ async function bulkImportScenes() {
eventSource.onerror = function() {
updateProgress('scenes', 0, 0, 'Connection error', true);
eventSource.close();
hideLoader();
};
}
@ -291,6 +304,7 @@ async function aeImportPerformerByName() {
const name = prompt('Import performer by name (Adult Empire):');
if (!name) return;
setAEStatus(`Searching Adult Empire for "${name}"...`);
showLoader(`Importing performer "${name}" from Adult Empire...`);
try {
const res = await fetch('/api/ae/import/performer', {
method: 'POST',
@ -306,6 +320,8 @@ async function aeImportPerformerByName() {
}
} catch (err) {
setAEStatus(`Error: ${err.message}`, true);
} finally {
hideLoader();
}
}
@ -313,6 +329,7 @@ async function aeImportPerformerByURL() {
const url = prompt('Paste Adult Empire performer URL:');
if (!url) return;
setAEStatus('Importing performer from Adult Empire URL...');
showLoader('Importing performer from Adult Empire URL...');
try {
const res = await fetch('/api/ae/import/performer-by-url', {
method: 'POST',
@ -328,6 +345,8 @@ async function aeImportPerformerByURL() {
}
} catch (err) {
setAEStatus(`Error: ${err.message}`, true);
} finally {
hideLoader();
}
}
@ -335,6 +354,7 @@ async function aeImportSceneByName() {
const title = prompt('Import scene by title (Adult Empire):');
if (!title) return;
setAEStatus(`Searching Adult Empire for "${title}"...`);
showLoader(`Importing scene "${title}" from Adult Empire...`);
try {
const res = await fetch('/api/ae/import/scene', {
method: 'POST',
@ -350,6 +370,8 @@ async function aeImportSceneByName() {
}
} catch (err) {
setAEStatus(`Error: ${err.message}`, true);
} finally {
hideLoader();
}
}
@ -357,6 +379,7 @@ async function aeImportSceneByURL() {
const url = prompt('Paste Adult Empire scene URL:');
if (!url) return;
setAEStatus('Importing scene from Adult Empire URL...');
showLoader('Importing scene from Adult Empire URL...');
try {
const res = await fetch('/api/ae/import/scene-by-url', {
method: 'POST',
@ -372,6 +395,8 @@ async function aeImportSceneByURL() {
}
} catch (err) {
setAEStatus(`Error: ${err.message}`, true);
} finally {
hideLoader();
}
}
@ -539,6 +564,23 @@ function setImportStatus(type, message, success) {
}
// Close modals when clicking outside
// Global loader helpers
function showLoader(msg) {
const overlay = document.getElementById('global-loader');
const text = document.getElementById('global-loader-text');
if (overlay) {
overlay.style.display = 'flex';
}
if (text && msg) {
text.textContent = msg;
}
}
function hideLoader() {
const overlay = document.getElementById('global-loader');
if (overlay) overlay.style.display = 'none';
}
window.onclick = function(event) {
if (event.target.classList.contains('modal')) {
event.target.classList.remove('active');

View File

@ -57,4 +57,10 @@
</div>
</div>
</nav>
<div id="global-loader" class="global-loader" style="display:none;">
<div class="loader-content">
<div class="spinner"></div>
<div id="global-loader-text">Working...</div>
</div>
</div>
{{end}}