Admin Settings Tab Preservation Fix
Version: 0.229.058
Issue Description
When users were working in the admin settings page and clicked the save button from any tab other than "General", the page would redirect back to the "General" tab after saving, rather than preserving the tab they were working in. This was frustrating for users who were making changes in specific sections like "Search & Extract", "Agents", "AI Models", or "Safety" as they would lose their place and have to navigate back to the tab they were working in.
Note: This issue affected both the traditional tab-based navigation and the newer sidebar navigation interface.
Root Cause Analysis
The issue occurred because:
Server-side redirects lose hash fragments: When the admin settings form is submitted via POST, the Flask backend redirects to
url_for('admin_settings')which goes to the base URL without any hash fragment (like#search-extractor#safety).Hash fragments are not preserved during server redirects: Unlike query parameters, hash fragments are handled entirely on the client side and are not sent to the server during form submissions.
Tab activation only checked URL hash on page load: The existing navigation functions only looked at
window.location.hashbut didn't have any mechanism to restore a previously active tab after a redirect.Dual navigation interfaces: The admin settings page supports both traditional Bootstrap tab navigation and a newer sidebar navigation, requiring different handling for each mode.
Technical Solution
Implementation Details
The fix was implemented entirely on the client-side using JavaScript in admin_settings.js:
1. Active Tab Detection Function
function getCurrentActiveTab() {
// First check if we're using sidebar navigation
const sidebarToggle = document.getElementById('admin-settings-toggle');
if (sidebarToggle) {
// For sidebar navigation, check for active sidebar nav links
const activeSidebarTab = document.querySelector('.admin-nav-tab.active');
if (activeSidebarTab) {
const tabId = activeSidebarTab.getAttribute('data-tab');
return tabId ? '#' + tabId : null;
}
// Fallback: check which tab pane is currently visible for sidebar nav
const activeTabPane = document.querySelector('.tab-pane.show.active');
if (activeTabPane) {
return '#' + activeTabPane.id;
}
// If no active tab found but we have a hash, use that
if (window.location.hash) {
return window.location.hash;
}
} else {
// For tab navigation, check Bootstrap tab buttons
const activeTabButton = document.querySelector('button.nav-link.active[data-bs-target]');
if (activeTabButton) {
return activeTabButton.getAttribute('data-bs-target');
}
// Fallback: check which tab pane is currently visible for tab nav
const activeTabPane = document.querySelector('.tab-pane.fade.show.active');
if (activeTabPane) {
return '#' + activeTabPane.id;
}
}
return null;
}
2. Form Submission Enhancement
adminForm.addEventListener('submit', function(e) {
try {
// Capture the current active tab before form submission
const activeTab = getCurrentActiveTab();
if (activeTab) {
// Store the active tab in sessionStorage to restore after redirect
sessionStorage.setItem('adminSettingsActiveTab', activeTab);
}
// ... rest of existing form validation logic
} catch (err) {
console.error("Error in form submission validation:", err);
}
});
3. Tab Restoration Logic
function activateTabFromHash() {
let hash = window.location.hash;
// If no hash in URL, check sessionStorage for saved tab from form submission
if (!hash) {
const savedTab = sessionStorage.getItem('adminSettingsActiveTab');
if (savedTab) {
hash = savedTab;
// Clear the saved tab to prevent it from affecting future navigation
sessionStorage.removeItem('adminSettingsActiveTab');
// Update URL with the restored hash
history.replaceState(null, null, hash);
}
}
if (hash) {
const tabId = hash.startsWith('#') ? hash.substring(1) : hash;
// Check if we're using sidebar navigation
const sidebarToggle = document.getElementById('admin-settings-toggle');
if (sidebarToggle) {
// Use sidebar navigation functions
if (typeof showAdminTab === 'function') {
showAdminTab(tabId);
// Set active nav link for sidebar
const navLink = document.querySelector(`.admin-nav-tab[data-tab="${tabId}"]`);
if (navLink) {
document.querySelectorAll('.admin-nav-tab').forEach(link => {
link.classList.remove('active');
});
navLink.classList.add('active');
}
}
} else {
// Use Bootstrap tab navigation
const tabButton = document.querySelector(`button.nav-link[data-bs-target="${hash}"]`);
if (tabButton) {
const tab = new bootstrap.Tab(tabButton);
tab.show();
}
}
}
}
Workflow
- User is on a specific tab (e.g.,
#search-extractvia sidebar navigation or#agentsvia tab navigation) - User makes changes and clicks save
- Form submission captures current active tab using
getCurrentActiveTab()(works for both navigation types) - Active tab is stored in sessionStorage as
'adminSettingsActiveTab' - Form submits normally, server processes and redirects to base admin settings URL
- Page reloads,
activateTabFromHash()is called duringDOMContentLoaded - Function checks sessionStorage for saved tab since URL has no hash
- Saved tab is restored using the appropriate navigation method (sidebar or Bootstrap tabs)
- URL is updated with the correct hash and sessionStorage is cleared
Files Modified
JavaScript
- File:
application/single_app/static/js/admin/admin_settings.js - Changes:
- Added
getCurrentActiveTab()function to detect the currently active tab with dual navigation support - Enhanced form submission handler to capture and store active tab in sessionStorage
- Modified
activateTabFromHash()to check sessionStorage when no URL hash is present - Added support for both Bootstrap tab navigation and sidebar navigation systems
- Implemented priority detection for section-level vs tab-level active states in sidebar navigation
- Added comprehensive debug logging for troubleshooting tab preservation workflow
- Added URL hash update using
history.replaceState()for restored tabs
- Added
Version
- File:
application/single_app/config.py - Changes: Updated
VERSION = "0.229.046"
Testing
Functional Tests
General Tab Preservation Test
Created functional_tests/test_admin_settings_tab_preservation.py which validates:
- JavaScript Implementation: Verifies all required functions and logic are present
- HTML Structure: Confirms the HTML template has the necessary tab structure
- Integration Workflow: Tests the complete tab preservation workflow
Sidebar Navigation Test
Created functional_tests/test_sidebar_navigation_tab_preservation.py which validates:
- Sidebar Structure: Confirms proper sidebar navigation HTML structure with data-tab attributes
- JavaScript Support: Verifies enhanced functions support sidebar navigation detection
- Integration: Tests sidebar navigation system integration with tab preservation
- Specific Functionality: Validates search-extract tab preservation functionality
Test Results
General Tab Preservation Tests: 3/3 passed
Sidebar Navigation Tests: 4/4 passed
📊 Total Results: 7/7 tests passed
✅ All tab preservation tests passed!
💡 The admin settings now preserve the active tab when saving for both navigation systems
User Experience Improvements
Before the Fix
- User navigates to "Search & Extract" tab (sidebar) or "Agents" tab (Bootstrap tabs)
- User makes configuration changes
- User clicks "Save Settings"
- Page reloads and always shows "General" tab regardless of which navigation system is used
- User has to manually navigate back to their working tab
- Poor user experience: Loss of context and extra navigation required
After the Fix
- User navigates to "Search & Extract" tab (sidebar) or "Agents" tab (Bootstrap tabs)
- User makes configuration changes
- User clicks "Save Settings"
- Page reloads and automatically returns to the same tab with proper submenu state
- Improved user experience: Seamless workflow with preserved context for both navigation types
Benefits
- Improved User Experience: Users stay in their working context after saving
- Reduced Friction: No need to re-navigate to the tab they were working in
- Better Workflow: Especially beneficial for users making multiple changes in the same section
- Non-Intrusive: Uses sessionStorage which automatically clears on tab close
- Backwards Compatible: Existing URL hash navigation still works as before
Edge Cases Handled
- No active tab detected: Falls back gracefully without errors
- Invalid tab stored: Bootstrap Tab API handles invalid selectors gracefully
- SessionStorage not available: Code uses try-catch blocks for error handling
- Multiple tab navigation: SessionStorage is cleared after use to prevent interference
- Direct URL access with hash: Original hash navigation is preserved and takes precedence
Technical Notes
- SessionStorage vs LocalStorage: Used sessionStorage to ensure the saved tab doesn't persist across browser sessions
- History API: Used
history.replaceState()instead ofhistory.pushState()to avoid creating extra history entries - Event Timing: Form submission capture happens before the actual submission to ensure the active tab is correctly identified
- Bootstrap Integration: Works with Bootstrap 5 tab API and doesn't interfere with existing tab switching logic
This fix ensures that admin users can work efficiently in the settings interface without losing their place when saving changes.