feat:
--Added delete funct --Added uuid funct
This commit is contained in:
1 parent
eb16c93fb0
commit
79e10f9cad
2 files changed
+128
-34
No files matched your search
+25
-3
@@ -265,7 +265,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.primary-button,
|
.primary-button,
|
||||||
.secondary-button {
|
.secondary-button,
|
||||||
|
.danger-button {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
@@ -292,7 +293,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.primary-button:disabled,
|
.primary-button:disabled,
|
||||||
.secondary-button:disabled {
|
.secondary-button:disabled,
|
||||||
|
.danger-button:disabled {
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
opacity: 0.65;
|
opacity: 0.65;
|
||||||
}
|
}
|
||||||
@@ -315,11 +317,31 @@
|
|||||||
|
|
||||||
.primary-button:focus-visible,
|
.primary-button:focus-visible,
|
||||||
.secondary-button:focus-visible,
|
.secondary-button:focus-visible,
|
||||||
|
.danger-button:focus-visible,
|
||||||
.register-form input:focus-visible {
|
.register-form input:focus-visible {
|
||||||
outline: 2px solid var(--accent);
|
outline: 2px solid var(--accent);
|
||||||
outline-offset: 2px;
|
outline-offset: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.danger-button {
|
||||||
|
min-height: 34px;
|
||||||
|
border: 1px solid #ef4444;
|
||||||
|
background: #ef4444;
|
||||||
|
color: #ffffff;
|
||||||
|
font-size: 14px;
|
||||||
|
padding-inline: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.danger-button:hover {
|
||||||
|
border-color: #dc2626;
|
||||||
|
background: #dc2626;
|
||||||
|
}
|
||||||
|
|
||||||
|
.danger-button:disabled:hover {
|
||||||
|
border-color: #ef4444;
|
||||||
|
background: #ef4444;
|
||||||
|
}
|
||||||
|
|
||||||
.status-message {
|
.status-message {
|
||||||
width: fit-content;
|
width: fit-content;
|
||||||
margin-bottom: 18px;
|
margin-bottom: 18px;
|
||||||
@@ -410,7 +432,7 @@
|
|||||||
|
|
||||||
.nodes-table {
|
.nodes-table {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
min-width: 720px;
|
min-width: 820px;
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
color: var(--text-h);
|
color: var(--text-h);
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
|
|||||||
+103
-31
@@ -37,6 +37,7 @@ type NodeInterface = {
|
|||||||
port: number
|
port: number
|
||||||
dbname: string
|
dbname: string
|
||||||
user: string
|
user: string
|
||||||
|
uuid: string
|
||||||
}
|
}
|
||||||
|
|
||||||
type NodeInterfacesResponse = {
|
type NodeInterfacesResponse = {
|
||||||
@@ -46,6 +47,11 @@ type NodeInterfacesResponse = {
|
|||||||
message?: string
|
message?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type DeleteNodeInterfaceResponse = {
|
||||||
|
status: string
|
||||||
|
message?: string
|
||||||
|
}
|
||||||
|
|
||||||
const getSavedTheme = (): Theme => {
|
const getSavedTheme = (): Theme => {
|
||||||
try {
|
try {
|
||||||
return localStorage.getItem('theme') === 'dark' ? 'dark' : 'light'
|
return localStorage.getItem('theme') === 'dark' ? 'dark' : 'light'
|
||||||
@@ -154,6 +160,34 @@ const getNodeInterfaces = async (): Promise<NodeInterfacesResponse> => {
|
|||||||
return response.json() as Promise<NodeInterfacesResponse>
|
return response.json() as Promise<NodeInterfacesResponse>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const deleteNodeInterface = async (
|
||||||
|
node: NodeInterface,
|
||||||
|
): Promise<DeleteNodeInterfaceResponse> => {
|
||||||
|
const accessToken = localStorage.getItem('access_token')
|
||||||
|
const headers: Record<string, string> = {}
|
||||||
|
const params = new URLSearchParams({
|
||||||
|
uuid: node.uuid,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (accessToken) {
|
||||||
|
headers.Authorization = `Bearer ${accessToken}`
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await fetch(
|
||||||
|
`${API_BASE_URL}/spock/del-node-interfaces?${params.toString()}`,
|
||||||
|
{
|
||||||
|
method: 'DELETE',
|
||||||
|
headers,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error('Failed to delete node interface')
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.json() as Promise<DeleteNodeInterfaceResponse>
|
||||||
|
}
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
const [isCollapsed, setIsCollapsed] = useState(false)
|
const [isCollapsed, setIsCollapsed] = useState(false)
|
||||||
const [activePage, setActivePage] = useState<PageId>(getSavedPage)
|
const [activePage, setActivePage] = useState<PageId>(getSavedPage)
|
||||||
@@ -166,6 +200,7 @@ function App() {
|
|||||||
const [nodes, setNodes] = useState<NodeInterface[]>([])
|
const [nodes, setNodes] = useState<NodeInterface[]>([])
|
||||||
const [nodesStatus, setNodesStatus] = useState<NodesStatus>('idle')
|
const [nodesStatus, setNodesStatus] = useState<NodesStatus>('idle')
|
||||||
const [nodesError, setNodesError] = useState('')
|
const [nodesError, setNodesError] = useState('')
|
||||||
|
const [deletingNodeId, setDeletingNodeId] = useState<number | null>(null)
|
||||||
const nextTheme = theme === 'light' ? 'dark' : 'light'
|
const nextTheme = theme === 'light' ? 'dark' : 'light'
|
||||||
|
|
||||||
const loadNodeInterfaces = async () => {
|
const loadNodeInterfaces = async () => {
|
||||||
@@ -270,6 +305,28 @@ function App() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleDeleteNodeClick = async (node: NodeInterface) => {
|
||||||
|
setDeletingNodeId(node.if_id)
|
||||||
|
setNodesError('')
|
||||||
|
|
||||||
|
try {
|
||||||
|
const deleteResponse = await deleteNodeInterface(node)
|
||||||
|
|
||||||
|
if (deleteResponse.status !== 'success') {
|
||||||
|
throw new Error(deleteResponse.message ?? 'Failed to delete node')
|
||||||
|
}
|
||||||
|
|
||||||
|
await loadNodeInterfaces()
|
||||||
|
} catch (error) {
|
||||||
|
setNodesStatus('error')
|
||||||
|
setNodesError(
|
||||||
|
error instanceof Error ? error.message : 'Failed to delete node',
|
||||||
|
)
|
||||||
|
} finally {
|
||||||
|
setDeletingNodeId(null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`app-shell theme-${theme} ${isCollapsed ? 'nav-collapsed' : ''}`}
|
className={`app-shell theme-${theme} ${isCollapsed ? 'nav-collapsed' : ''}`}
|
||||||
@@ -442,38 +499,53 @@ function App() {
|
|||||||
</form>
|
</form>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
<div className="nodes-table-wrap">
|
{!isRegisterFormOpen && (
|
||||||
{nodesStatus === 'loading' ? (
|
<div className="nodes-table-wrap">
|
||||||
<p className="table-state">Loading nodes...</p>
|
{nodesStatus === 'loading' ? (
|
||||||
) : nodes.length > 0 ? (
|
<p className="table-state">Loading nodes...</p>
|
||||||
<table className="nodes-table">
|
) : nodes.length > 0 ? (
|
||||||
<thead>
|
<table className="nodes-table">
|
||||||
<tr>
|
<thead>
|
||||||
<th>Node ID</th>
|
<tr>
|
||||||
<th>Node Name</th>
|
<th>Node ID</th>
|
||||||
<th>Host</th>
|
<th>Node Name</th>
|
||||||
<th>Port</th>
|
<th>Host</th>
|
||||||
<th>DB Name</th>
|
<th>Port</th>
|
||||||
<th>DB Username</th>
|
<th>DB Name</th>
|
||||||
</tr>
|
<th>DB Username</th>
|
||||||
</thead>
|
<th>Actions</th>
|
||||||
<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>
|
</tr>
|
||||||
))}
|
</thead>
|
||||||
</tbody>
|
<tbody>
|
||||||
</table>
|
{nodes.map((node) => (
|
||||||
) : (
|
<tr key={node.if_id}>
|
||||||
<p className="table-state">No nodes found.</p>
|
<td>{node.if_nodeid}</td>
|
||||||
)}
|
<td>{node.if_name}</td>
|
||||||
</div>
|
<td>{node.host}</td>
|
||||||
|
<td>{node.port}</td>
|
||||||
|
<td>{node.dbname}</td>
|
||||||
|
<td>{node.user}</td>
|
||||||
|
<td>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="danger-button"
|
||||||
|
disabled={deletingNodeId === node.if_id}
|
||||||
|
onClick={() => handleDeleteNodeClick(node)}
|
||||||
|
>
|
||||||
|
{deletingNodeId === node.if_id
|
||||||
|
? 'Deleting'
|
||||||
|
: 'Delete'}
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
) : (
|
||||||
|
<p className="table-state">No nodes found.</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</section>
|
</section>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user