feat: migrate from static config to database and add authentication
- Replaced static hosts.json and staticConfig.ts with SQLite database (Prisma) - Implemented JWT authentication and Login UI - Added dynamic API routes for hosts, topology, and settings - Updated UI components to fetch and manage state dynamically - Added Settings interface for managing hosts and topology nodes
This commit is contained in:
39
src/App.tsx
39
src/App.tsx
@@ -17,6 +17,8 @@ import CommandPalette from './components/CommandPalette';
|
||||
import StaleWarning from './components/StaleWarning';
|
||||
import TerminalPanel from './components/TerminalPanel';
|
||||
import MetricsBar from './components/Dashboard/MetricsBar';
|
||||
import Login from './components/Login';
|
||||
import SettingsOverlay from './components/Settings/SettingsOverlay';
|
||||
|
||||
const API_BASE_URL = import.meta.env.VITE_API_URL || 'http://localhost:3001';
|
||||
|
||||
@@ -60,6 +62,7 @@ function App() {
|
||||
setLastSuccessfulDiscovery: s.setLastSuccessfulDiscovery,
|
||||
})));
|
||||
|
||||
const token = useTopologyStore((s) => s.token);
|
||||
const setConnectionStatus = useTopologyStore((s) => s.setConnectionStatus);
|
||||
|
||||
const {
|
||||
@@ -69,6 +72,8 @@ function App() {
|
||||
pollInterval,
|
||||
terminalOpen,
|
||||
terminalHost,
|
||||
toggleLeftPanel,
|
||||
toggleRightPanel,
|
||||
} = useTopologyStore(useShallow((s) => ({
|
||||
leftPanelOpen: s.leftPanelOpen,
|
||||
rightPanelOpen: s.rightPanelOpen,
|
||||
@@ -76,6 +81,8 @@ function App() {
|
||||
pollInterval: s.pollInterval,
|
||||
terminalOpen: s.terminalOpen,
|
||||
terminalHost: s.terminalHost,
|
||||
toggleLeftPanel: s.toggleLeftPanel,
|
||||
toggleRightPanel: s.toggleRightPanel,
|
||||
})));
|
||||
|
||||
const toggleCommandPalette = useTopologyStore((s) => s.toggleCommandPalette);
|
||||
@@ -99,7 +106,10 @@ function App() {
|
||||
try {
|
||||
const response = await fetch(`${API_BASE_URL}/api/discover`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' }
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${useTopologyStore.getState().token}`
|
||||
}
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
@@ -253,6 +263,10 @@ function App() {
|
||||
};
|
||||
}, [setConnectionStatus, setNodes, setEdges, setLastUpdated]);
|
||||
|
||||
if (!token) {
|
||||
return <Login />;
|
||||
}
|
||||
|
||||
return (
|
||||
<ReactFlowProvider>
|
||||
<div className="h-screen w-screen flex flex-col bg-slate-900">
|
||||
@@ -265,22 +279,37 @@ function App() {
|
||||
<Header onRefresh={loadData} isLoading={isLoading} />
|
||||
<MetricsBar />
|
||||
|
||||
<div className="flex-1 flex overflow-hidden" role="main" id="main-content" tabIndex={-1}>
|
||||
<div className="flex-1 flex overflow-hidden relative" role="main" id="main-content" tabIndex={-1}>
|
||||
{leftPanelOpen && (
|
||||
<LeftPanel />
|
||||
<>
|
||||
<div
|
||||
className="absolute inset-0 bg-black/60 backdrop-blur-sm z-10 md:hidden animate-in fade-in duration-300"
|
||||
onClick={toggleLeftPanel}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<LeftPanel />
|
||||
</>
|
||||
)}
|
||||
|
||||
<div className="flex-1">
|
||||
<div className="flex-1 relative z-0">
|
||||
<TopologyGraph />
|
||||
</div>
|
||||
|
||||
{rightPanelOpen && (
|
||||
<RightPanel />
|
||||
<>
|
||||
<div
|
||||
className="absolute inset-0 bg-black/60 backdrop-blur-sm z-10 md:hidden animate-in fade-in duration-300"
|
||||
onClick={toggleRightPanel}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<RightPanel />
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<Footer />
|
||||
<CommandPalette />
|
||||
<SettingsOverlay />
|
||||
{terminalOpen && terminalHost && (
|
||||
<TerminalPanel host={terminalHost} onClose={closeTerminal} />
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user