--Added Registered nodes data endpoint
This commit is contained in:
george committed 2026-09-09 11:57:23 +05:30
1 parent 0a5899b009
commit eb16c93fb0
3 files changed
+178 -7

No files matched your search

+1
View File
@@ -0,0 +1 @@
VITE_API_BASE_URL=http://127.0.0.1:8000
+44
View File
@@ -355,6 +355,7 @@
} }
.register-form { .register-form {
margin-bottom: 22px;
border: 1px solid var(--border); border: 1px solid var(--border);
border-radius: 8px; border-radius: 8px;
background: var(--bg); background: var(--bg);
@@ -400,6 +401,49 @@
margin-top: 22px; margin-top: 22px;
} }
.nodes-table-wrap {
overflow-x: auto;
border: 1px solid var(--border);
border-radius: 8px;
background: var(--bg);
}
.nodes-table {
width: 100%;
min-width: 720px;
border-collapse: collapse;
color: var(--text-h);
font-size: 14px;
}
.nodes-table th,
.nodes-table td {
border-bottom: 1px solid var(--border);
padding: 13px 14px;
text-align: left;
white-space: nowrap;
}
.nodes-table th {
background: var(--surface);
color: var(--text);
font-size: 12px;
font-weight: 700;
letter-spacing: 0;
text-transform: uppercase;
}
.nodes-table tbody tr:last-child td {
border-bottom: 0;
}
.table-state {
margin: 0;
color: var(--text);
font-size: 15px;
padding: 18px;
}
.eyebrow { .eyebrow {
margin-bottom: 12px; margin-bottom: 12px;
color: var(--accent); color: var(--accent);
+133 -7
View File
@@ -1,6 +1,8 @@
import { useState } from 'react' import { useEffect, useState } from 'react'
import './App.css' import './App.css'
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL
const navItems = [ const navItems = [
{ id: 'dashboard', label: 'Dashboard' }, { id: 'dashboard', label: 'Dashboard' },
{ id: 'nodes', label: 'Nodes' }, { id: 'nodes', label: 'Nodes' },
@@ -11,6 +13,7 @@ type PageId = (typeof navItems)[number]['id']
type Theme = 'light' | 'dark' type Theme = 'light' | 'dark'
type TokenStatus = 'idle' | 'loading' | 'success' | 'error' type TokenStatus = 'idle' | 'loading' | 'success' | 'error'
type RegisterStatus = 'idle' | 'loading' | 'success' | 'error' type RegisterStatus = 'idle' | 'loading' | 'success' | 'error'
type NodesStatus = 'idle' | 'loading' | 'success' | 'error'
type RegisterNodePayload = { type RegisterNodePayload = {
node_name: string node_name: string
@@ -21,6 +24,28 @@ type RegisterNodePayload = {
password: string password: string
} }
type RegisterNodeResponse = {
status: string
message?: string
}
type NodeInterface = {
if_id: number
if_name: string
if_nodeid: number
host: string
port: number
dbname: string
user: string
}
type NodeInterfacesResponse = {
status: string
count: number
nodes: NodeInterface[]
message?: string
}
const getSavedTheme = (): Theme => { const getSavedTheme = (): Theme => {
try { try {
return localStorage.getItem('theme') === 'dark' ? 'dark' : 'light' return localStorage.getItem('theme') === 'dark' ? 'dark' : 'light'
@@ -58,7 +83,7 @@ const savePage = (page: PageId) => {
} }
const getSessionToken = async () => { const getSessionToken = async () => {
const response = await fetch('http://127.0.0.1:8000/get-token', { const response = await fetch(`${API_BASE_URL}/get-token`, {
method: 'POST', method: 'POST',
}) })
@@ -84,7 +109,9 @@ const getSessionToken = async () => {
return storedToken return storedToken
} }
const registerNode = async (payload: RegisterNodePayload) => { const registerNode = async (
payload: RegisterNodePayload,
): Promise<RegisterNodeResponse> => {
const accessToken = localStorage.getItem('access_token') const accessToken = localStorage.getItem('access_token')
const headers: Record<string, string> = { const headers: Record<string, string> = {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
@@ -94,7 +121,7 @@ const registerNode = async (payload: RegisterNodePayload) => {
headers.Authorization = `Bearer ${accessToken}` headers.Authorization = `Bearer ${accessToken}`
} }
const response = await fetch('http://127.0.0.1:8000/register-node', { const response = await fetch(`${API_BASE_URL}/register-node`, {
method: 'POST', method: 'POST',
headers, headers,
body: JSON.stringify(payload), body: JSON.stringify(payload),
@@ -104,7 +131,27 @@ const registerNode = async (payload: RegisterNodePayload) => {
throw new Error('Failed to register node') throw new Error('Failed to register node')
} }
return response.json() return response.json() as Promise<RegisterNodeResponse>
}
const getNodeInterfaces = async (): Promise<NodeInterfacesResponse> => {
const accessToken = localStorage.getItem('access_token')
const headers: Record<string, string> = {}
if (accessToken) {
headers.Authorization = `Bearer ${accessToken}`
}
const response = await fetch(`${API_BASE_URL}/spock/node-interfaces`, {
method: 'GET',
headers,
})
if (!response.ok) {
throw new Error('Failed to get node interfaces')
}
return response.json() as Promise<NodeInterfacesResponse>
} }
function App() { function App() {
@@ -116,8 +163,42 @@ function App() {
const [tokenError, setTokenError] = useState('') const [tokenError, setTokenError] = useState('')
const [registerStatus, setRegisterStatus] = useState<RegisterStatus>('idle') const [registerStatus, setRegisterStatus] = useState<RegisterStatus>('idle')
const [registerError, setRegisterError] = useState('') const [registerError, setRegisterError] = useState('')
const [nodes, setNodes] = useState<NodeInterface[]>([])
const [nodesStatus, setNodesStatus] = useState<NodesStatus>('idle')
const [nodesError, setNodesError] = useState('')
const nextTheme = theme === 'light' ? 'dark' : 'light' const nextTheme = theme === 'light' ? 'dark' : 'light'
const loadNodeInterfaces = async () => {
setNodesStatus('loading')
setNodesError('')
try {
const nodeInterfacesResponse = await getNodeInterfaces()
if (nodeInterfacesResponse.status !== 'success') {
throw new Error(
nodeInterfacesResponse.message ?? 'Failed to get node interfaces',
)
}
setNodes(nodeInterfacesResponse.nodes)
setNodesStatus('success')
} catch (error) {
setNodesStatus('error')
setNodesError(
error instanceof Error
? error.message
: 'Failed to get node interfaces',
)
}
}
useEffect(() => {
if (activePage === 'nodes') {
void loadNodeInterfaces()
}
}, [activePage])
const selectPage = (page: PageId) => { const selectPage = (page: PageId) => {
setActivePage(page) setActivePage(page)
savePage(page) savePage(page)
@@ -140,6 +221,7 @@ function App() {
try { try {
await getSessionToken() await getSessionToken()
setTokenStatus('success') setTokenStatus('success')
await loadNodeInterfaces()
} catch (error) { } catch (error) {
setTokenStatus('error') setTokenStatus('error')
setTokenError( setTokenError(
@@ -152,10 +234,12 @@ function App() {
event: React.FormEvent<HTMLFormElement>, event: React.FormEvent<HTMLFormElement>,
) => { ) => {
event.preventDefault() event.preventDefault()
const form = event.currentTarget
setRegisterStatus('loading') setRegisterStatus('loading')
setRegisterError('') setRegisterError('')
const formData = new FormData(event.currentTarget) const formData = new FormData(form)
const payload: RegisterNodePayload = { const payload: RegisterNodePayload = {
node_name: String(formData.get('node_name') ?? ''), node_name: String(formData.get('node_name') ?? ''),
host: String(formData.get('host') ?? ''), host: String(formData.get('host') ?? ''),
@@ -170,9 +254,14 @@ function App() {
console.log('Node registration response:', registerResponse) console.log('Node registration response:', registerResponse)
if (registerResponse.status !== 'success') {
throw new Error(registerResponse.message ?? 'Failed to register node')
}
setRegisterStatus('success') setRegisterStatus('success')
event.currentTarget.reset() form.reset()
setIsRegisterFormOpen(false) setIsRegisterFormOpen(false)
window.location.reload()
} catch (error) { } catch (error) {
setRegisterStatus('error') setRegisterStatus('error')
setRegisterError( setRegisterError(
@@ -289,6 +378,10 @@ function App() {
<p className="status-message error">{registerError}</p> <p className="status-message error">{registerError}</p>
)} )}
{nodesStatus === 'error' && (
<p className="status-message error">{nodesError}</p>
)}
{isRegisterFormOpen ? ( {isRegisterFormOpen ? (
<form className="register-form" onSubmit={handleRegisterNode}> <form className="register-form" onSubmit={handleRegisterNode}>
<div className="form-grid"> <div className="form-grid">
@@ -348,6 +441,39 @@ function App() {
</div> </div>
</form> </form>
) : null} ) : null}
<div className="nodes-table-wrap">
{nodesStatus === 'loading' ? (
<p className="table-state">Loading nodes...</p>
) : nodes.length > 0 ? (
<table className="nodes-table">
<thead>
<tr>
<th>Node ID</th>
<th>Node Name</th>
<th>Host</th>
<th>Port</th>
<th>DB Name</th>
<th>DB Username</th>
</tr>
</thead>
<tbody>
{nodes.map((node) => (
<tr key={node.if_id}>
<td>{node.if_nodeid}</td>
<td>{node.if_name}</td>
<td>{node.host}</td>
<td>{node.port}</td>
<td>{node.dbname}</td>
<td>{node.user}</td>
</tr>
))}
</tbody>
</table>
) : (
<p className="table-state">No nodes found.</p>
)}
</div>
</section> </section>
)} )}