new file: backend/src/migrations/008_add_database_schemas.sql modified: backend/src/routes/sqlInterface.ts modified: frontend/package.json modified: frontend/src/App.tsx modified: frontend/src/components/Sidebar.tsx new file: frontend/src/pages/DatabaseSchema.tsx modified: frontend/src/services/api.ts
159 lines
4.1 KiB
TypeScript
159 lines
4.1 KiB
TypeScript
import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom';
|
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
import { Toaster } from 'react-hot-toast';
|
|
import { useAuthStore } from '@/stores/authStore';
|
|
import { authApi } from '@/services/api';
|
|
import { useEffect } from 'react';
|
|
import Navbar from '@/components/Navbar';
|
|
import Sidebar from '@/components/Sidebar';
|
|
import Login from '@/pages/Login';
|
|
import Dashboard from '@/pages/Dashboard';
|
|
import Endpoints from '@/pages/Endpoints';
|
|
import ApiKeys from '@/pages/ApiKeys';
|
|
import Folders from '@/pages/Folders';
|
|
import Logs from '@/pages/Logs';
|
|
import Settings from '@/pages/Settings';
|
|
import SqlInterface from '@/pages/SqlInterface';
|
|
import DatabaseSchema from '@/pages/DatabaseSchema';
|
|
|
|
const queryClient = new QueryClient({
|
|
defaultOptions: {
|
|
queries: {
|
|
refetchOnWindowFocus: false,
|
|
retry: 1,
|
|
},
|
|
},
|
|
});
|
|
|
|
function PrivateRoute({ children }: { children: React.ReactNode }) {
|
|
const isAuthenticated = useAuthStore((state) => state.isAuthenticated);
|
|
return isAuthenticated ? <>{children}</> : <Navigate to="/login" />;
|
|
}
|
|
|
|
function Layout({ children }: { children: React.ReactNode }) {
|
|
return (
|
|
<div className="min-h-screen flex flex-col">
|
|
<Navbar />
|
|
<div className="flex flex-1">
|
|
<Sidebar />
|
|
<main className="flex-1 p-8 bg-gray-50 overflow-auto">
|
|
{children}
|
|
</main>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
function App() {
|
|
const { isAuthenticated, setUser } = useAuthStore();
|
|
|
|
// Load user data on app start if authenticated
|
|
useEffect(() => {
|
|
const loadUser = async () => {
|
|
if (isAuthenticated) {
|
|
try {
|
|
const { data } = await authApi.getMe();
|
|
setUser(data);
|
|
} catch (error) {
|
|
console.error('Failed to load user:', error);
|
|
}
|
|
}
|
|
};
|
|
loadUser();
|
|
}, [isAuthenticated, setUser]);
|
|
|
|
return (
|
|
<QueryClientProvider client={queryClient}>
|
|
<BrowserRouter>
|
|
<Routes>
|
|
<Route path="/login" element={<Login />} />
|
|
<Route
|
|
path="/"
|
|
element={
|
|
<PrivateRoute>
|
|
<Layout>
|
|
<Dashboard />
|
|
</Layout>
|
|
</PrivateRoute>
|
|
}
|
|
/>
|
|
<Route
|
|
path="/workbench"
|
|
element={
|
|
<PrivateRoute>
|
|
<Layout>
|
|
<SqlInterface />
|
|
</Layout>
|
|
</PrivateRoute>
|
|
}
|
|
/>
|
|
<Route
|
|
path="/schema"
|
|
element={
|
|
<PrivateRoute>
|
|
<Layout>
|
|
<DatabaseSchema />
|
|
</Layout>
|
|
</PrivateRoute>
|
|
}
|
|
/>
|
|
<Route
|
|
path="/endpoints"
|
|
element={
|
|
<PrivateRoute>
|
|
<Layout>
|
|
<Endpoints />
|
|
</Layout>
|
|
</PrivateRoute>
|
|
}
|
|
/>
|
|
<Route
|
|
path="/api-keys"
|
|
element={
|
|
<PrivateRoute>
|
|
<Layout>
|
|
<ApiKeys />
|
|
</Layout>
|
|
</PrivateRoute>
|
|
}
|
|
/>
|
|
<Route
|
|
path="/folders"
|
|
element={
|
|
<PrivateRoute>
|
|
<Layout>
|
|
<Folders />
|
|
</Layout>
|
|
</PrivateRoute>
|
|
}
|
|
/>
|
|
<Route
|
|
path="/logs"
|
|
element={
|
|
<PrivateRoute>
|
|
<Layout>
|
|
<Logs />
|
|
</Layout>
|
|
</PrivateRoute>
|
|
}
|
|
/>
|
|
<Route
|
|
path="/settings"
|
|
element={
|
|
<PrivateRoute>
|
|
<Layout>
|
|
<Settings />
|
|
</Layout>
|
|
</PrivateRoute>
|
|
}
|
|
/>
|
|
<Route path="*" element={<Navigate to="/" />} />
|
|
</Routes>
|
|
</BrowserRouter>
|
|
<Toaster position="top-right" />
|
|
</QueryClientProvider>
|
|
);
|
|
}
|
|
|
|
export default App;
|