fix loading icon

This commit is contained in:
Lukas Pupka-Lipinski 2025-09-29 11:08:49 +02:00
parent 7cc0d7c7a5
commit f9102d7bcd
4 changed files with 93 additions and 31 deletions

View File

@ -69,17 +69,41 @@ RESCAN_LOCK = "rescan"
DOWNLOAD_LOCK = "download"
CLEANUP_LOCK = "cleanup"
# Simple in-memory process lock system
_active_locks = {}
def is_process_running(lock_name):
"""Placeholder function for process lock checking."""
return False
"""Check if a process is currently running (locked)."""
return lock_name in _active_locks
def acquire_lock(lock_name, locked_by="system"):
"""Acquire a process lock."""
if lock_name in _active_locks:
raise ProcessLockError(f"Process {lock_name} is already running")
_active_locks[lock_name] = {
'locked_by': locked_by,
'timestamp': datetime.now()
}
def release_lock(lock_name):
"""Release a process lock."""
if lock_name in _active_locks:
del _active_locks[lock_name]
def with_process_lock(lock_name, timeout_minutes=30):
"""Placeholder decorator for process locking."""
"""Decorator for process locking."""
def decorator(f):
from functools import wraps
@wraps(f)
def decorated_function(*args, **kwargs):
# Extract locked_by from kwargs if provided
locked_by = kwargs.pop('_locked_by', 'system')
try:
acquire_lock(lock_name, locked_by)
return f(*args, **kwargs)
finally:
release_lock(lock_name)
return decorated_function
return decorator

View File

@ -869,10 +869,6 @@ body {
.process-status {
gap: 4px;
}
.status-text {
font-size: 0.8rem;
}
}
@media (max-width: 768px) {
@ -1441,16 +1437,22 @@ body {
}
.status-indicator i {
font-size: 12px;
font-size: 24px; /* 2x bigger: 12px -> 24px */
transition: all var(--animation-duration-normal) var(--animation-easing-standard);
}
.status-text {
font-weight: 500;
white-space: nowrap;
flex-shrink: 0;
margin-left: 2px;
/* Rescan icon specific styling */
#rescan-status i {
color: var(--color-text-disabled); /* Gray when idle */
}
#rescan-status.running i {
color: #22c55e; /* Green when running */
animation: iconPulse 2s infinite;
}
/* Status text removed - using tooltips only */
.status-dot {
width: 8px;
height: 8px;
@ -1472,7 +1474,6 @@ body {
}
@keyframes pulse {
0%,
100% {
opacity: 1;
@ -1485,6 +1486,19 @@ body {
}
}
@keyframes iconPulse {
0%,
100% {
opacity: 1;
transform: scale(1) rotate(0deg);
}
50% {
opacity: 0.7;
transform: scale(1.1) rotate(180deg);
}
}
/* Process status in mobile view */
@media (max-width: 768px) {
.process-status {
@ -1499,12 +1513,8 @@ body {
gap: 4px;
}
.status-text {
display: none;
}
.status-indicator i {
font-size: 14px;
font-size: 20px; /* Maintain 2x scale for mobile: was 14px -> 20px */
}
}

View File

@ -896,30 +896,45 @@ class AniWorldApp {
const statusDot = statusElement.querySelector('.status-dot');
if (!statusDot) return;
// Remove all status classes
// Remove all status classes from both dot and element
statusDot.classList.remove('idle', 'running', 'error');
statusElement.classList.remove('running', 'error', 'idle');
// Capitalize process name for display
const displayName = processName.charAt(0).toUpperCase() + processName.slice(1);
if (hasError) {
statusDot.classList.add('error');
statusElement.title = `${processName} error - click for details`;
statusElement.classList.add('error');
statusElement.title = `${displayName} error - click for details`;
} else if (isRunning) {
statusDot.classList.add('running');
statusElement.title = `${processName} is running...`;
statusElement.classList.add('running');
statusElement.title = `${displayName} is running...`;
} else {
statusDot.classList.add('idle');
statusElement.title = `${processName} is idle`;
statusElement.classList.add('idle');
statusElement.title = `${displayName} is idle`;
}
}
async checkProcessLocks() {
try {
const response = await this.makeAuthenticatedRequest('/api/process/locks/status');
if (!response) return;
if (!response) {
// If no response, set status as idle
this.updateProcessStatus('rescan', false);
this.updateProcessStatus('download', false);
return;
}
// Check if response is actually JSON and not HTML (login page)
const contentType = response.headers.get('content-type');
if (!contentType || !contentType.includes('application/json')) {
console.warn('Process locks API returned non-JSON response, likely authentication issue');
// Set status as idle if we can't get proper response
this.updateProcessStatus('rescan', false);
this.updateProcessStatus('download', false);
return;
}
@ -935,25 +950,40 @@ class AniWorldApp {
if (rescanBtn) {
if (locks.rescan?.is_locked) {
rescanBtn.disabled = true;
rescanBtn.querySelector('span').textContent = 'Scanning...';
const span = rescanBtn.querySelector('span');
if (span) span.textContent = 'Scanning...';
} else {
rescanBtn.disabled = false;
rescanBtn.querySelector('span').textContent = 'Rescan';
const span = rescanBtn.querySelector('span');
if (span) span.textContent = 'Rescan';
}
}
} else {
// If API returns error, set status as idle
console.warn('Process locks API returned error:', data.error);
this.updateProcessStatus('rescan', false);
this.updateProcessStatus('download', false);
}
} catch (error) {
console.error('Error checking process locks:', error);
// On error, set status as idle
this.updateProcessStatus('rescan', false);
this.updateProcessStatus('download', false);
}
}
startProcessStatusMonitoring() {
// Initial check on page load
this.checkProcessLocks();
// Check process status every 5 seconds
setInterval(() => {
if (this.isConnected) {
this.checkProcessLocks();
}
}, 5000);
console.log('Process status monitoring started');
}
async showConfigModal() {

View File

@ -24,14 +24,12 @@
<div class="header-actions">
<!-- Process Status Indicators -->
<div class="process-status" id="process-status">
<div class="status-indicator" id="rescan-status">
<div class="status-indicator" id="rescan-status" title="Scan is idle">
<i class="fas fa-sync-alt"></i>
<span class="status-text">Scan</span>
<div class="status-dot idle"></div>
</div>
<div class="status-indicator" id="download-status">
<div class="status-indicator" id="download-status" title="Download is idle">
<i class="fas fa-download"></i>
<span class="status-text">Download</span>
<div class="status-dot idle"></div>
</div>
</div>