@@ -419,6 +443,93 @@ function clearCache() {
queryCache.clear();
}
+function setSearchButtonLoading(isLoading) {
+ const button = document.getElementById('searchButton');
+ const icon = document.getElementById('searchIcon');
+ const text = document.getElementById('searchText');
+
+ if (isLoading) {
+ button.disabled = true;
+ button.classList.add('opacity-75', 'cursor-not-allowed');
+ button.classList.remove('hover:bg-blue-700');
+ icon.className = 'fas fa-spinner fa-spin text-xs sm:text-sm';
+ text.textContent = 'Searching...';
+ } else {
+ button.disabled = false;
+ button.classList.remove('opacity-75', 'cursor-not-allowed');
+ button.classList.add('hover:bg-blue-700');
+ icon.className = 'fas fa-search text-xs sm:text-sm';
+ text.textContent = 'Search';
+ }
+}
+
+function showToast(message, type = 'success', duration = 4000) {
+ const container = document.getElementById('toastContainer');
+ const toastId = 'toast-' + Date.now();
+
+ // Determine colors and icon based on type
+ const config = {
+ success: {
+ bgColor: 'bg-green-500',
+ icon: 'fas fa-check-circle',
+ borderColor: 'border-green-400'
+ },
+ error: {
+ bgColor: 'bg-red-500',
+ icon: 'fas fa-exclamation-circle',
+ borderColor: 'border-red-400'
+ },
+ warning: {
+ bgColor: 'bg-yellow-500',
+ icon: 'fas fa-exclamation-triangle',
+ borderColor: 'border-yellow-400'
+ },
+ info: {
+ bgColor: 'bg-blue-500',
+ icon: 'fas fa-info-circle',
+ borderColor: 'border-blue-400'
+ }
+ };
+
+ const { bgColor, icon, borderColor } = config[type] || config.success;
+
+ // Create toast element
+ const toast = document.createElement('div');
+ toast.id = toastId;
+ toast.className = `${bgColor} text-white px-4 py-3 rounded-lg shadow-lg flex items-center gap-3 min-w-[320px] max-w-md border-l-4 ${borderColor} toast-enter`;
+
+ toast.innerHTML = `
+
+
${message}
+
+ `;
+
+ // Add to container
+ container.appendChild(toast);
+
+ // Auto remove after duration
+ setTimeout(() => {
+ removeToast(toastId);
+ }, duration);
+}
+
+function removeToast(toastId) {
+ const toast = document.getElementById(toastId);
+ if (toast) {
+ toast.classList.remove('toast-enter');
+ toast.classList.add('toast-exit');
+
+ // Remove from DOM after animation
+ setTimeout(() => {
+ if (toast.parentNode) {
+ toast.parentNode.removeChild(toast);
+ }
+ }, 300);
+ }
+}
+
function openModal(id) {
document.getElementById(id).classList.remove("hidden");
document.body.style.overflow = 'hidden';
@@ -429,6 +540,31 @@ function closeModal(id) {
document.body.style.overflow = 'auto';
}
+function toggleAdvancedPanel() {
+ const content = document.getElementById('advancedContent');
+ const actions = document.getElementById('advancedActions');
+ const icon = document.getElementById('advancedToggleIcon');
+
+ // Check if currently hidden (using Tailwind's hidden class)
+ if (content.classList.contains('hidden')) {
+ // Show content
+ content.classList.remove('hidden');
+ content.classList.add('grid');
+ actions.classList.remove('hidden');
+ actions.classList.add('flex');
+ icon.classList.remove('fa-chevron-right');
+ icon.classList.add('fa-chevron-down');
+ } else {
+ // Hide content
+ content.classList.remove('grid');
+ content.classList.add('hidden');
+ actions.classList.remove('flex');
+ actions.classList.add('hidden');
+ icon.classList.remove('fa-chevron-down');
+ icon.classList.add('fa-chevron-right');
+ }
+}
+
function setSearchQuery(query) {
document.getElementById('searchInput').value = query;
performSearch();
@@ -462,11 +598,11 @@ async function submitModalEdit() {
const { error } = await client.from(editContext.table).update(update).eq("id", editContext.id);
if (error) {
console.error('Update error:', error);
- alert("❌ Update failed: " + error.message);
+ showToast("Update failed: " + error.message, 'error');
return;
}
- alert("✅ Updated!");
+ showToast("Record updated successfully!", 'success');
clearCache(); // Clear cache after data modification
closeModal("editModal");
@@ -476,7 +612,7 @@ async function submitModalEdit() {
}
} catch (error) {
console.error('Submit edit error:', error);
- alert("❌ Update failed: " + error.message);
+ showToast("Update failed: " + error.message, 'error');
}
}
@@ -537,8 +673,8 @@ function renderRecord(r) {
- ${badge.label}
- ${badge.label.slice(0,3)}
+ ${badge.label}
+ ${badge.label.slice(0,3).toUpperCase()}
@@ -768,6 +904,11 @@ async function performSearch(loadMore = false) {
return;
}
+ // Show loading state on search button
+ if (!loadMore) {
+ setSearchButtonLoading(true);
+ }
+
// Reset pagination if new search
if (!loadMore || searchState.query !== query) {
searchState = { query, page: 0, hasMore: false, results: [] };
@@ -850,6 +991,11 @@ async function performSearch(loadMore = false) {
} catch (e) {
console.error('Search error:', e);
showErrorMessage(`Search failed: ${e.message}`);
+ } finally {
+ // Hide loading state on search button
+ if (!loadMore) {
+ setSearchButtonLoading(false);
+ }
}
}
@@ -1295,7 +1441,7 @@ function sortResults() {
function exportResults() {
if (!searchState.results || searchState.results.length === 0) {
- alert("No results to export");
+ showToast("No results to export", 'warning');
return;
}
@@ -1326,9 +1472,11 @@ function exportResults() {
a.click();
document.body.removeChild(a);
window.URL.revokeObjectURL(url);
+
+ showToast(`Exported ${searchState.results.length} records successfully`, 'success');
} catch (error) {
console.error('Export error:', error);
- alert('Export failed: ' + error.message);
+ showToast('Export failed: ' + error.message, 'error');
}
}
@@ -1379,7 +1527,7 @@ async function deleteRecord(btn) {
if (!table || !id) {
console.error('Missing table or id data');
- alert("❌ Could not delete: missing record information");
+ showToast("Could not delete: missing record information", 'error');
return;
}
@@ -1388,11 +1536,11 @@ async function deleteRecord(btn) {
const { error } = await client.from(table).delete().eq("id", id);
if (error) {
console.error('Delete error:', error);
- alert("❌ Delete failed: " + error.message);
+ showToast("Delete failed: " + error.message, 'error');
return;
}
- alert("🗑️ Deleted");
+ showToast("Record deleted successfully", 'success');
clearCache(); // Clear cache after data modification
// Refresh current search if one exists
@@ -1401,7 +1549,7 @@ async function deleteRecord(btn) {
}
} catch (error) {
console.error('Delete record error:', error);
- alert("❌ Delete failed: " + error.message);
+ showToast("Delete failed: " + error.message, 'error');
}
}
@@ -1487,12 +1635,12 @@ async function handleCreateSubmit(event) {
const { data: result, error } = await client.from(table).insert([data]);
if (error) {
console.error('Create error details:', error);
- alert("❌ Create failed: " + (error.message || JSON.stringify(error)));
+ showToast("Create failed: " + (error.message || JSON.stringify(error)), 'error');
return;
}
console.log('Insert successful:', result);
- alert("✅ Record created successfully!");
+ showToast("Record created successfully!", 'success');
clearCache();
closeCreateModal();
@@ -1502,7 +1650,7 @@ async function handleCreateSubmit(event) {
}
} catch (error) {
console.error('Create record error:', error);
- alert("❌ Create failed: " + (error.message || JSON.stringify(error)));
+ showToast("Create failed: " + (error.message || JSON.stringify(error)), 'error');
}
}
@@ -1575,4 +1723,4 @@ input:focus, select:focus, button:focus {
-