merge: bring in session-loop and dashboard fixes from main
This commit is contained in:
@@ -30,8 +30,8 @@ type DashboardStats struct {
|
|||||||
PendingUpdates int `json:"pending_updates"`
|
PendingUpdates int `json:"pending_updates"`
|
||||||
FailedUpdates int `json:"failed_updates"`
|
FailedUpdates int `json:"failed_updates"`
|
||||||
CriticalUpdates int `json:"critical_updates"`
|
CriticalUpdates int `json:"critical_updates"`
|
||||||
ImportantUpdates int `json:"important_updates"`
|
ImportantUpdates int `json:"high_updates"`
|
||||||
ModerateUpdates int `json:"moderate_updates"`
|
ModerateUpdates int `json:"medium_updates"`
|
||||||
LowUpdates int `json:"low_updates"`
|
LowUpdates int `json:"low_updates"`
|
||||||
UpdatesByType map[string]int `json:"updates_by_type"`
|
UpdatesByType map[string]int `json:"updates_by_type"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,10 +48,12 @@ api.interceptors.request.use((config) => {
|
|||||||
// Response interceptor to handle errors
|
// Response interceptor to handle errors
|
||||||
api.interceptors.response.use(
|
api.interceptors.response.use(
|
||||||
(response: AxiosResponse) => response,
|
(response: AxiosResponse) => response,
|
||||||
(error) => {
|
async (error) => {
|
||||||
if (error.response?.status === 401) {
|
if (error.response?.status === 401) {
|
||||||
// Clear token and redirect to login
|
const { useAuthStore } = await import('./store');
|
||||||
|
useAuthStore.getState().logout();
|
||||||
localStorage.removeItem('auth_token');
|
localStorage.removeItem('auth_token');
|
||||||
|
localStorage.removeItem('user');
|
||||||
window.location.href = '/login';
|
window.location.href = '/login';
|
||||||
}
|
}
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
|
|||||||
@@ -16,7 +16,11 @@ export const useAuthStore = create<AuthState>()(
|
|||||||
token: null,
|
token: null,
|
||||||
isAuthenticated: false,
|
isAuthenticated: false,
|
||||||
setToken: (token) => set({ token, isAuthenticated: true }),
|
setToken: (token) => set({ token, isAuthenticated: true }),
|
||||||
logout: () => set({ token: null, isAuthenticated: false }),
|
logout: () => {
|
||||||
|
localStorage.removeItem('auth_token');
|
||||||
|
localStorage.removeItem('user');
|
||||||
|
set({ token: null, isAuthenticated: false });
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
name: 'auth-storage',
|
name: 'auth-storage',
|
||||||
|
|||||||
@@ -9,9 +9,12 @@ import './index.css'
|
|||||||
const queryClient = new QueryClient({
|
const queryClient = new QueryClient({
|
||||||
defaultOptions: {
|
defaultOptions: {
|
||||||
queries: {
|
queries: {
|
||||||
retry: 2,
|
retry: (failureCount, error: any) => {
|
||||||
staleTime: 0, // Data is always stale to allow real-time updates
|
if (error?.response?.status === 401) return false;
|
||||||
refetchOnWindowFocus: false, // Don't refetch on window focus to avoid unnecessary requests
|
return failureCount < 2;
|
||||||
|
},
|
||||||
|
staleTime: 0,
|
||||||
|
refetchOnWindowFocus: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { useNavigate } from 'react-router-dom';
|
|||||||
import { Settings, Database, User, Shield, Eye, EyeOff, CheckCircle } from 'lucide-react';
|
import { Settings, Database, User, Shield, Eye, EyeOff, CheckCircle } from 'lucide-react';
|
||||||
import { toast } from 'react-hot-toast';
|
import { toast } from 'react-hot-toast';
|
||||||
import { setupApi } from '@/lib/api';
|
import { setupApi } from '@/lib/api';
|
||||||
|
import { useAuthStore } from '@/lib/store';
|
||||||
|
|
||||||
interface SetupFormData {
|
interface SetupFormData {
|
||||||
adminUser: string;
|
adminUser: string;
|
||||||
@@ -19,6 +20,7 @@ interface SetupFormData {
|
|||||||
|
|
||||||
const Setup: React.FC = () => {
|
const Setup: React.FC = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
const { logout } = useAuthStore();
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
const [envContent, setEnvContent] = useState<string | null>(null);
|
const [envContent, setEnvContent] = useState<string | null>(null);
|
||||||
@@ -106,12 +108,12 @@ const Setup: React.FC = () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logout();
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result = await setupApi.configure(formData);
|
const result = await setupApi.configure(formData);
|
||||||
|
|
||||||
// Store env content and show success screen
|
|
||||||
setEnvContent(result.envContent || null);
|
setEnvContent(result.envContent || null);
|
||||||
setShowSuccess(true);
|
setShowSuccess(true);
|
||||||
toast.success(result.message || 'Configuration saved successfully!');
|
toast.success(result.message || 'Configuration saved successfully!');
|
||||||
|
|||||||
Reference in New Issue
Block a user