Improve Media Manager loading state with parallel fetching and overlay
- Implemented simultaneous execution of getMediaDiagnostics and getMediaForSku in MediaManager.html to speed up initial load and refresh. - Added a translucent grid-loading-overlay that appears over existing tiles during refresh, preventing interaction while maintaining context. - Differentiated loading messages: 'Connecting to systems...' for initial load vs 'Refreshing media...' for updates. - Fixed a syntax error in the save handler.
This commit is contained in:
@ -477,6 +477,25 @@
|
||||
padding-top: 12px;
|
||||
border-top: 1px solid #f1f5f9;
|
||||
}
|
||||
|
||||
/* Grid Overlay */
|
||||
.grid-loading-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(255, 255, 255, 0.75);
|
||||
backdrop-filter: blur(1px);
|
||||
z-index: 50;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: var(--text-secondary);
|
||||
font-weight: 500;
|
||||
border-radius: 8px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
@ -560,8 +579,8 @@
|
||||
</button>
|
||||
</div>
|
||||
<input type="file" id="file-input" multiple style="display:none" onchange="controller.handleFiles(this.files)">
|
||||
<!-- Unified Transfer Session UI -->
|
||||
<div id="transfer-session-ui" class="transfer-session" style="display:none;">
|
||||
<!-- Unified Transfer Session UI -->
|
||||
<div id="transfer-session-ui" class="transfer-session" style="display:none;">
|
||||
<!-- Instructions (Top) -->
|
||||
<div id="transfer-desc" style="font-size:13px; color:var(--text); margin-bottom:12px; line-height:1.4;">
|
||||
<!-- Dynamic Helper Text -->
|
||||
@ -983,10 +1002,31 @@
|
||||
};
|
||||
|
||||
UI.prototype.setLoadingState = function (isLoading) {
|
||||
var overlay = document.getElementById('grid-loading-overlay');
|
||||
|
||||
if (isLoading) {
|
||||
// Check if we have items
|
||||
var hasItems = this.grid.children.length > 0 && !this.grid.querySelector('.empty-state');
|
||||
|
||||
if (hasItems) {
|
||||
// Create overlay if not exists
|
||||
if (!overlay) {
|
||||
overlay = document.createElement('div');
|
||||
overlay.id = 'grid-loading-overlay';
|
||||
overlay.className = 'grid-loading-overlay';
|
||||
overlay.innerHTML = '<div class="spinner" style="margin-bottom: 12px;"></div><div>Refreshing media...</div>';
|
||||
this.grid.style.position = 'relative'; // Ensure positioning context
|
||||
this.grid.appendChild(overlay);
|
||||
}
|
||||
} else {
|
||||
// Standard empty state loading
|
||||
this.grid.innerHTML = '<div style="grid-column: 1 / -1; text-align: center; padding: 40px; color: var(--text-secondary);">' +
|
||||
'<div class="spinner" style="margin-bottom: 12px;"></div>' +
|
||||
'<div>Connecting to systems...</div></div>';
|
||||
'<div>Loading media...</div></div>';
|
||||
}
|
||||
} else {
|
||||
// Clear overlay
|
||||
if (overlay) overlay.remove();
|
||||
}
|
||||
};
|
||||
|
||||
@ -1281,9 +1321,9 @@
|
||||
|
||||
ui.logStatus('init', 'Initializing access...', 'info');
|
||||
|
||||
// 1. Diagnostics (Parallel)
|
||||
google.script.run
|
||||
.withSuccessHandler((diagnostics) => { // Use arrow
|
||||
|
||||
.withSuccessHandler((diagnostics) => {
|
||||
// Check Resumption
|
||||
if (diagnostics.activeJobId) {
|
||||
ui.logStatus('resume', 'Resuming active background job...', 'info');
|
||||
@ -1304,7 +1344,6 @@
|
||||
// Capture Token
|
||||
if (diagnostics.token) state.token = diagnostics.token;
|
||||
|
||||
|
||||
// Shopify Status
|
||||
if (diagnostics.shopify.status === 'ok') {
|
||||
ui.logStatus('shopify', `Shopify Product: ok (${diagnostics.shopify.mediaCount} media) (ID: ${diagnostics.shopify.id}) <a href="${diagnostics.shopify.adminUrl}" target="_blank" style="margin-left:8px;">Open Admin ↗</a>`, 'success');
|
||||
@ -1314,20 +1353,26 @@
|
||||
} else {
|
||||
ui.logStatus('shopify', `Shopify Check Failed: ${diagnostics.shopify.error}`, 'error');
|
||||
}
|
||||
})
|
||||
.withFailureHandler(function (err) {
|
||||
ui.logStatus('fatal', `Diagnostics failed: ${err.message}`, 'error');
|
||||
})
|
||||
.getMediaDiagnostics(sku, "");
|
||||
|
||||
ui.logStatus('fetch', 'Fetching full media state (this may take a moment)...', 'info');
|
||||
|
||||
// 2. Load Full Media
|
||||
// 2. Load Full Media (Parallel)
|
||||
ui.logStatus('fetch', 'Fetching full media state...', 'info');
|
||||
google.script.run
|
||||
.withSuccessHandler(function (items) {
|
||||
// Normalize items
|
||||
const normalized = items.map(i => ({
|
||||
const normalized = items.map(function (i) {
|
||||
return {
|
||||
...i,
|
||||
id: i.id || Math.random().toString(36).substr(2, 9),
|
||||
status: i.source || 'drive_only', // Fix: Use source as status
|
||||
status: i.source || 'drive_only',
|
||||
source: i.source,
|
||||
_deleted: false // Init soft delete flag
|
||||
}));
|
||||
_deleted: false
|
||||
};
|
||||
});
|
||||
|
||||
state.setItems(normalized);
|
||||
|
||||
@ -1337,20 +1382,15 @@
|
||||
} else {
|
||||
controller.showGallery();
|
||||
}
|
||||
|
||||
})
|
||||
.withFailureHandler(function (err) {
|
||||
ui.logStatus('fatal', `Failed to load media: ${err.message}`, 'error');
|
||||
ui.setLoadingState(false);
|
||||
})
|
||||
.getMediaForSku(sku);
|
||||
|
||||
})
|
||||
.withFailureHandler(function (err) {
|
||||
ui.logStatus('fatal', `Diagnostics failed: ${err.message}`, 'error');
|
||||
})
|
||||
.getMediaDiagnostics(sku, "");
|
||||
},
|
||||
|
||||
|
||||
saveChanges() {
|
||||
ui.toggleSave(false);
|
||||
ui.saveBtn.innerText = "Saving...";
|
||||
|
||||
Reference in New Issue
Block a user