Disable grid interactions during save operations

- Added .grid-disabled CSS class to prevent pointer events and provide visual feedback (grayscale/opacity) during save.
- Implemented UI.prototype.setSavingState to toggle grid interaction and disable SortableJS reordering.
- Integrated setSavingState into controller.saveChanges to block edits while saving is in progress.
- Added loading message updates ('Refreshing media...' and 'Loading media...') for better UX.
This commit is contained in:
Ben Miller
2025-12-31 09:11:57 -07:00
parent e0e5b76c8e
commit fc25e877f1

View File

@ -496,6 +496,12 @@
font-weight: 500; font-weight: 500;
border-radius: 8px; border-radius: 8px;
} }
.grid-disabled {
pointer-events: none;
opacity: 0.7;
filter: grayscale(0.5);
}
</style> </style>
</head> </head>
@ -1002,9 +1008,15 @@
}; };
UI.prototype.setLoadingState = function (isLoading) { UI.prototype.setLoadingState = function (isLoading) {
// If loading, ensure saving state is cleared (visual conflict)
// but actually we might want saving state to take precedence or exist.
// Loading typically replaces everything or adds overlay.
var overlay = document.getElementById('grid-loading-overlay'); var overlay = document.getElementById('grid-loading-overlay');
if (isLoading) { if (isLoading) {
// Clear disabled state if moving to loading (refreshing)
this.grid.classList.remove('grid-disabled');
// Check if we have items // Check if we have items
var hasItems = this.grid.children.length > 0 && !this.grid.querySelector('.empty-state'); var hasItems = this.grid.children.length > 0 && !this.grid.querySelector('.empty-state');
@ -1030,6 +1042,24 @@
} }
}; };
UI.prototype.setSavingState = function (isSaving) {
if (isSaving) {
this.grid.classList.add('grid-disabled');
if (this.sortable) this.sortable.option('disabled', true);
// Disable action buttons explicitly if needed (pointer-events handles most, but keyboard nav?)
var btns = this.grid.querySelectorAll('button');
btns.forEach(function (b) { b.disabled = true; });
} else {
this.grid.classList.remove('grid-disabled');
if (this.sortable) this.sortable.option('disabled', false);
var btns = this.grid.querySelectorAll('button');
btns.forEach(function (b) { b.disabled = false; });
}
};
UI.prototype.logStatus = function (step, message, type) { UI.prototype.logStatus = function (step, message, type) {
if (!type) type = 'info'; if (!type) type = 'info';
var container = this.logContainer; var container = this.logContainer;
@ -1394,6 +1424,7 @@
saveChanges() { saveChanges() {
ui.toggleSave(false); ui.toggleSave(false);
ui.saveBtn.innerText = "Saving..."; ui.saveBtn.innerText = "Saving...";
ui.setSavingState(true);
// Generate Job ID // Generate Job ID
const jobId = Math.random().toString(36).substring(2) + Date.now().toString(36); const jobId = Math.random().toString(36).substring(2) + Date.now().toString(36);
@ -1420,13 +1451,19 @@
// Reload to get fresh IDs/State, preserving the save logs // Reload to get fresh IDs/State, preserving the save logs
setTimeout(() => this.loadMedia(true), 1500); setTimeout(() => {
// The refresh will clear the saving state implicitly via setLoadingState(true) -> remove disabled
// But let's be clean
ui.setSavingState(false);
this.loadMedia(true);
}, 1500);
}) })
.withFailureHandler(e => { .withFailureHandler(e => {
this.stopLogPolling(); this.stopLogPolling();
alert(`Save Failed: ${e.message}`); alert(`Save Failed: ${e.message}`);
ui.logStatus('fatal', `Save Failed: ${e.message}`, 'error'); ui.logStatus('fatal', `Save Failed: ${e.message}`, 'error');
ui.toggleSave(true); ui.toggleSave(true);
ui.setSavingState(false);
}) })
.saveMediaChanges(state.sku, activeItems, jobId); .saveMediaChanges(state.sku, activeItems, jobId);
}, },