diff --git a/frontend/src/components/AgentManagement.js b/frontend/src/components/AgentManagement.js index bae1083..98b1755 100644 --- a/frontend/src/components/AgentManagement.js +++ b/frontend/src/components/AgentManagement.js @@ -235,7 +235,14 @@ const AgentManagement = () => { console.log(`📡 fetchAgents: Fetching agents for pool_id=${targetCluster.pool_id}`); try { const params = { pool_id: targetCluster.pool_id }; - const response = await axios.get('/api/agents', { params, timeout: 10000 }); + const response = await axios.get('/api/agents', { + params, + timeout: 10000, + headers: { + 'Cache-Control': 'no-cache, no-store, must-revalidate', + 'Pragma': 'no-cache' + } + }); const agentsData = response.data.agents || []; console.log(`✅ fetchAgents: Received ${agentsData.length} agents from API`); @@ -308,12 +315,16 @@ const AgentManagement = () => { timeout: 5000, headers: { 'Authorization': `Bearer ${localStorage.getItem('authToken') || ''}`, + 'Cache-Control': 'no-cache, no-store, must-revalidate', + 'Pragma': 'no-cache' }, }), axios.get('/api/agents/platforms', { timeout: 5000, headers: { 'Authorization': `Bearer ${localStorage.getItem('authToken') || ''}`, + 'Cache-Control': 'no-cache, no-store, must-revalidate', + 'Pragma': 'no-cache' }, }) ]); diff --git a/frontend/src/components/ApplyManagement.js b/frontend/src/components/ApplyManagement.js index c4bf4d6..902fa1b 100644 --- a/frontend/src/components/ApplyManagement.js +++ b/frontend/src/components/ApplyManagement.js @@ -93,25 +93,32 @@ const ApplyManagement = () => { } // Fetch pending changes from all modules + // CRITICAL FIX: Add cache-control headers to prevent stale data + const cacheHeaders = { + 'Authorization': `Bearer ${token}`, + 'Cache-Control': 'no-cache, no-store, must-revalidate', + 'Pragma': 'no-cache' + }; + const [frontendsRes, backendsRes, wafRes, sslRes] = await Promise.all([ axios.get('/api/frontends', { params: { cluster_id: selectedCluster.id }, - headers: { Authorization: `Bearer ${token}` } + headers: cacheHeaders }).catch(() => ({ data: { frontends: [] } })), axios.get('/api/backends', { params: { cluster_id: selectedCluster.id }, - headers: { Authorization: `Bearer ${token}` } + headers: cacheHeaders }).catch(() => ({ data: { backends: [] } })), axios.get('/api/waf/rules', { params: { cluster_id: selectedCluster.id }, - headers: { Authorization: `Bearer ${token}` } + headers: cacheHeaders }).catch(() => ({ data: { rules: [] } })), axios.get('/api/ssl/certificates', { params: { cluster_id: selectedCluster.id }, - headers: { Authorization: `Bearer ${token}` } + headers: cacheHeaders }).catch(() => ({ data: [] })) ]); diff --git a/frontend/src/components/BackendServers.js b/frontend/src/components/BackendServers.js index 52a96ef..0cdbbc4 100644 --- a/frontend/src/components/BackendServers.js +++ b/frontend/src/components/BackendServers.js @@ -122,7 +122,16 @@ const BackendServers = () => { setLoading(true); try { const params = selectedCluster ? { cluster_id: selectedCluster.id } : {}; - const response = await axios.get('/api/backends', { params }); + // CRITICAL FIX: Add cache busting to prevent stale data from appearing + // Browser/axios may cache GET requests, causing deleted backends to reappear + const response = await axios.get('/api/backends', { + params, + headers: { + 'Cache-Control': 'no-cache, no-store, must-revalidate', + 'Pragma': 'no-cache', + 'Expires': '0' + } + }); const fetchedBackends = response.data.backends || []; setBackends(fetchedBackends); // CRITICAL FIX: Apply status filters after fetching to maintain filter state @@ -138,7 +147,13 @@ const BackendServers = () => { const fetchFrontends = async () => { try { const params = selectedCluster ? { cluster_id: selectedCluster.id } : {}; - const response = await axios.get('/api/frontends', { params }); + const response = await axios.get('/api/frontends', { + params, + headers: { + 'Cache-Control': 'no-cache, no-store, must-revalidate', + 'Pragma': 'no-cache' + } + }); setFrontends(response.data.frontends || []); } catch (error) { console.error('Failed to fetch frontends:', error); @@ -153,18 +168,26 @@ const BackendServers = () => { const token = localStorage.getItem('token'); // CRITICAL FIX: Use same endpoint as Frontend (/api/ssl/certificates not /api/ssl-certificates) const response = await axios.get(`/api/ssl/certificates?cluster_id=${selectedCluster.id}`, { - headers: { Authorization: `Bearer ${token}` } + headers: { + 'Authorization': `Bearer ${token}`, + 'Cache-Control': 'no-cache, no-store, must-revalidate', + 'Pragma': 'no-cache' + } }); + // CRITICAL FIX: API returns array directly, not wrapped in {certificates: [...]} + const certificates = Array.isArray(response.data) ? response.data : (response.data.certificates || []); + console.log('🔍 SSL FETCH DEBUG (BackendServers):', { cluster_id: selectedCluster.id, - certificates_count: response.data?.certificates?.length || 0, - certificates: response.data?.certificates + certificates_count: certificates.length, + certificates: certificates.map(c => ({ id: c.id, name: c.name, ssl_type: c.ssl_type })) }); - setSslCertificates(response.data.certificates || []); + setSslCertificates(certificates); } catch (error) { console.error('Failed to fetch SSL certificates:', error); + setSslCertificates([]); // Don't show error message as SSL is optional } }; diff --git a/frontend/src/components/Configuration.js b/frontend/src/components/Configuration.js index 1bdb197..4719b4b 100644 --- a/frontend/src/components/Configuration.js +++ b/frontend/src/components/Configuration.js @@ -86,7 +86,14 @@ const Configuration = () => { setLoading(true); try { const params = { pool_id: selectedCluster.pool_id }; - const response = await axios.get('/api/agents', { params, timeout: 10000 }); + const response = await axios.get('/api/agents', { + params, + timeout: 10000, + headers: { + 'Cache-Control': 'no-cache, no-store, must-revalidate', + 'Pragma': 'no-cache' + } + }); const agentsData = response.data.agents || []; setAgents(agentsData); diff --git a/frontend/src/components/FrontendManagement.js b/frontend/src/components/FrontendManagement.js index f52fda6..8436e51 100644 --- a/frontend/src/components/FrontendManagement.js +++ b/frontend/src/components/FrontendManagement.js @@ -157,7 +157,13 @@ const FrontendManagement = () => { setLoading(true); try { const params = selectedCluster ? { cluster_id: selectedCluster.id } : {}; - const response = await axios.get('/api/frontends', { params }); + const response = await axios.get('/api/frontends', { + params, + headers: { + 'Cache-Control': 'no-cache, no-store, must-revalidate', + 'Pragma': 'no-cache' + } + }); // 🔍 DEBUG: Log frontend data to check SSL fields console.log('🔍 FRONTEND FETCH DEBUG: Response data:', response.data); @@ -243,7 +249,13 @@ const FrontendManagement = () => { const fetchBackends = async () => { try { const params = selectedCluster ? { cluster_id: selectedCluster.id } : {}; - const response = await axios.get('/api/backends', { params }); + const response = await axios.get('/api/backends', { + params, + headers: { + 'Cache-Control': 'no-cache, no-store, must-revalidate', + 'Pragma': 'no-cache' + } + }); setBackends(response.data.backends); } catch (error) { console.error('Failed to fetch backends:', error); @@ -261,7 +273,11 @@ const FrontendManagement = () => { console.log('🔍 SSL FETCH DEBUG: Token exists:', token ? 'Yes' : 'No'); const response = await axios.get(`/api/ssl/certificates?cluster_id=${selectedCluster.id}`, { - headers: { Authorization: `Bearer ${token}` } + headers: { + 'Authorization': `Bearer ${token}`, + 'Cache-Control': 'no-cache, no-store, must-revalidate', + 'Pragma': 'no-cache' + } }); console.log('🔍 SSL FETCH DEBUG: Response received:', response.data); diff --git a/frontend/src/components/PoolManagement.js b/frontend/src/components/PoolManagement.js index 0a6b325..291be58 100644 --- a/frontend/src/components/PoolManagement.js +++ b/frontend/src/components/PoolManagement.js @@ -84,6 +84,8 @@ const PoolManagement = () => { const response = await axios.get('/api/haproxy-cluster-pools', { headers: { 'Authorization': `Bearer ${token}`, + 'Cache-Control': 'no-cache, no-store, must-revalidate', + 'Pragma': 'no-cache' }, }); const poolsData = response.data.pools || []; @@ -144,6 +146,8 @@ const PoolManagement = () => { const response = await axios.get(`/api/haproxy-cluster-pools/${poolId}/agents`, { headers: { 'Authorization': `Bearer ${token}`, + 'Cache-Control': 'no-cache, no-store, must-revalidate', + 'Pragma': 'no-cache' }, }); setPoolAgents(response.data.agents || []); diff --git a/frontend/src/components/SSLManagement.js b/frontend/src/components/SSLManagement.js index b48a38d..49e10a2 100644 --- a/frontend/src/components/SSLManagement.js +++ b/frontend/src/components/SSLManagement.js @@ -102,7 +102,12 @@ const SSLManagement = () => { setFilteredCertificates([]); try { - const response = await axios.get(`/api/ssl/certificates?cluster_id=${selectedCluster.id}`); + const response = await axios.get(`/api/ssl/certificates?cluster_id=${selectedCluster.id}`, { + headers: { + 'Cache-Control': 'no-cache, no-store, must-revalidate', + 'Pragma': 'no-cache' + } + }); // Handle different response formats const certs = response.data.certificates || response.data || []; console.log('🎯 SSL FETCH DEBUG: Response structure:', { diff --git a/frontend/src/components/UserManagement.js b/frontend/src/components/UserManagement.js index 60073be..44c66d8 100644 --- a/frontend/src/components/UserManagement.js +++ b/frontend/src/components/UserManagement.js @@ -462,7 +462,12 @@ const UserManagement = () => { const fetchUsers = async () => { setUsersLoading(true); try { - const response = await axios.get('/api/users'); + const response = await axios.get('/api/users', { + headers: { + 'Cache-Control': 'no-cache, no-store, must-revalidate', + 'Pragma': 'no-cache' + } + }); setUsers(response.data.users); } catch (error) { message.error('Failed to fetch users: ' + error.message); diff --git a/frontend/src/components/WAFManagement.js b/frontend/src/components/WAFManagement.js index c0c83c3..78cc354 100644 --- a/frontend/src/components/WAFManagement.js +++ b/frontend/src/components/WAFManagement.js @@ -329,7 +329,12 @@ const WAFManagement = () => { if (!selectedCluster) return; try { - const response = await axios.get(`/api/frontends?cluster_id=${selectedCluster.id}`); + const response = await axios.get(`/api/frontends?cluster_id=${selectedCluster.id}`, { + headers: { + 'Cache-Control': 'no-cache, no-store, must-revalidate', + 'Pragma': 'no-cache' + } + }); setFrontends(response.data.frontends || []); } catch (error) { console.error('Failed to fetch frontends:', error); diff --git a/frontend/src/contexts/ClusterContext.js b/frontend/src/contexts/ClusterContext.js index c79c612..0cef747 100644 --- a/frontend/src/contexts/ClusterContext.js +++ b/frontend/src/contexts/ClusterContext.js @@ -22,7 +22,12 @@ export const ClusterProvider = ({ children }) => { // Fetch all clusters const fetchClusters = async () => { try { - const response = await axios.get('/api/clusters'); + const response = await axios.get('/api/clusters', { + headers: { + 'Cache-Control': 'no-cache, no-store, must-revalidate', + 'Pragma': 'no-cache' + } + }); const clustersData = response.data.clusters || []; setClusters(clustersData); // Precompute health by pool to avoid flicker when switching clusters