feat:
--Added delete funct --Added uuid funct
This commit is contained in:
1 parent
eb16c93fb0
commit
79e10f9cad
2 files changed
+97
-3
No files matched your search
+25
-3
@@ -265,7 +265,8 @@
|
||||
}
|
||||
|
||||
.primary-button,
|
||||
.secondary-button {
|
||||
.secondary-button,
|
||||
.danger-button {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@@ -292,7 +293,8 @@
|
||||
}
|
||||
|
||||
.primary-button:disabled,
|
||||
.secondary-button:disabled {
|
||||
.secondary-button:disabled,
|
||||
.danger-button:disabled {
|
||||
cursor: not-allowed;
|
||||
opacity: 0.65;
|
||||
}
|
||||
@@ -315,11 +317,31 @@
|
||||
|
||||
.primary-button:focus-visible,
|
||||
.secondary-button:focus-visible,
|
||||
.danger-button:focus-visible,
|
||||
.register-form input:focus-visible {
|
||||
outline: 2px solid var(--accent);
|
||||
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 {
|
||||
width: fit-content;
|
||||
margin-bottom: 18px;
|
||||
@@ -410,7 +432,7 @@
|
||||
|
||||
.nodes-table {
|
||||
width: 100%;
|
||||
min-width: 720px;
|
||||
min-width: 820px;
|
||||
border-collapse: collapse;
|
||||
color: var(--text-h);
|
||||
font-size: 14px;
|
||||
|
||||
+72
@@ -37,6 +37,7 @@ type NodeInterface = {
|
||||
port: number
|
||||
dbname: string
|
||||
user: string
|
||||
uuid: string
|
||||
}
|
||||
|
||||
type NodeInterfacesResponse = {
|
||||
@@ -46,6 +47,11 @@ type NodeInterfacesResponse = {
|
||||
message?: string
|
||||
}
|
||||
|
||||
type DeleteNodeInterfaceResponse = {
|
||||
status: string
|
||||
message?: string
|
||||
}
|
||||
|
||||
const getSavedTheme = (): Theme => {
|
||||
try {
|
||||
return localStorage.getItem('theme') === 'dark' ? 'dark' : 'light'
|
||||
@@ -154,6 +160,34 @@ const getNodeInterfaces = async (): 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() {
|
||||
const [isCollapsed, setIsCollapsed] = useState(false)
|
||||
const [activePage, setActivePage] = useState<PageId>(getSavedPage)
|
||||
@@ -166,6 +200,7 @@ function App() {
|
||||
const [nodes, setNodes] = useState<NodeInterface[]>([])
|
||||
const [nodesStatus, setNodesStatus] = useState<NodesStatus>('idle')
|
||||
const [nodesError, setNodesError] = useState('')
|
||||
const [deletingNodeId, setDeletingNodeId] = useState<number | null>(null)
|
||||
const nextTheme = theme === 'light' ? 'dark' : 'light'
|
||||
|
||||
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 (
|
||||
<div
|
||||
className={`app-shell theme-${theme} ${isCollapsed ? 'nav-collapsed' : ''}`}
|
||||
@@ -442,6 +499,7 @@ function App() {
|
||||
</form>
|
||||
) : null}
|
||||
|
||||
{!isRegisterFormOpen && (
|
||||
<div className="nodes-table-wrap">
|
||||
{nodesStatus === 'loading' ? (
|
||||
<p className="table-state">Loading nodes...</p>
|
||||
@@ -455,6 +513,7 @@ function App() {
|
||||
<th>Port</th>
|
||||
<th>DB Name</th>
|
||||
<th>DB Username</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -466,6 +525,18 @@ function App() {
|
||||
<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>
|
||||
@@ -474,6 +545,7 @@ function App() {
|
||||
<p className="table-state">No nodes found.</p>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</section>
|
||||
)}
|
||||
|
||||
|
||||
Reference in new issue
Block a user