diff --git a/src/pages/hosts/NetworkHostDetailsPage.tsx b/src/pages/hosts/NetworkHostDetailsPage.tsx index 3db8fffb..7f1d5bdb 100644 --- a/src/pages/hosts/NetworkHostDetailsPage.tsx +++ b/src/pages/hosts/NetworkHostDetailsPage.tsx @@ -167,6 +167,40 @@ export default function NetworkHostDetailsPage(props: PageProps) { [hostId, node, networkId, notify, storeDeleteNode, navigate] ); + const onHostToggleConnectivity = useCallback( + async (newStatus: boolean) => { + try { + if (!hostId || !node || !networkId) { + throw new Error('Host or network not found'); + } + const updatedNode = (await NodesService.updateNode(node.id, networkId, { ...node, connected: newStatus })).data; + store.updateNode(node.id, updatedNode); + notify.success({ + message: `Successfully ${newStatus ? 'connected' : 'disconnected'}`, + description: `Host is now ${newStatus ? 'connected to' : 'disconnected from'} network ${networkId}.`, + }); + } catch (err) { + notify.error({ + message: `Failed to ${newStatus ? 'connect' : 'disconnect'} host ${newStatus ? 'to' : 'from'} network`, + description: extractErrorMsg(err as any), + }); + } + }, + [hostId, node, networkId, notify, store] + ); + + const promptConfirmDisconnect = () => { + Modal.confirm({ + title: `Do you want to ${node?.connected ? 'disconnect' : 'connect'} host ${host?.name} ${ + node?.connected ? 'from' : 'to' + } network ${networkId}?`, + icon: , + onOk() { + onHostToggleConnectivity(!node?.connected); + }, + }); + }; + const promptConfirmRemove = () => { let forceDelete = false; @@ -626,6 +660,18 @@ export default function NetworkHostDetailsPage(props: PageProps) { navigate(getHostRoute(hostId ?? '')); }, }, + { + key: 'disconnect', + label: ( + + {node?.connected ? 'Disconnect from' : 'Connect to'} network + + ), + onClick: (ev) => { + ev.domEvent.stopPropagation(); + promptConfirmDisconnect(); + }, + }, { key: 'remove', label: Remove from network, diff --git a/src/pages/networks/NetworkDetailsPage.tsx b/src/pages/networks/NetworkDetailsPage.tsx index f94efc31..c5d01c79 100644 --- a/src/pages/networks/NetworkDetailsPage.tsx +++ b/src/pages/networks/NetworkDetailsPage.tsx @@ -60,6 +60,7 @@ import { TableColumnProps, Tabs, TabsProps, + Tag, theme, Tooltip, Typography, @@ -1393,12 +1394,12 @@ export default function NetworkDetailsPage(props: PageProps) { [networkNodes, store.hostsCommonDetails] ); - const disconnectNodeFromNetwork = useCallback( + const removeNodeFromNetwork = useCallback( (newStatus: boolean, node: ExtendedNode) => { let forceDelete = false; Modal.confirm({ - title: 'Disconnect host from network', + title: 'Remove host from network', content: ( <> @@ -1450,6 +1451,46 @@ export default function NetworkDetailsPage(props: PageProps) { [networkId, notify, storeDeleteNode] ); + const disconnectNodeFromNetwork = useCallback( + (newStatus: boolean, node: ExtendedNode) => { + Modal.confirm({ + title: newStatus ? 'Connect host to network' : 'Disconnect host from network', + content: ( + <> + + + + Are you sure you want {node?.name ?? ''} to {newStatus ? 'connect to' : 'disconnect from'} the + network? + + + + + ), + async onOk() { + try { + if (!networkId) return; + const updatedNode = (await NodesService.updateNode(node.id, networkId, { ...node, connected: newStatus })) + .data; + store.updateNode(node.id, updatedNode); + notify.success({ + message: `Successfully ${newStatus ? 'connected' : 'disconnected'}`, + description: `${node?.name ?? 'Host'} is now ${ + newStatus ? 'connected to' : 'disconnected from' + } network ${networkId}.`, + }); + } catch (err) { + notify.error({ + message: 'Failed to update host', + description: extractErrorMsg(err as any), + }); + } + }, + }); + }, + [networkId, notify, store] + ); + // ui components const getOverviewContent = useCallback(() => { if (!network) return ; @@ -1630,6 +1671,12 @@ export default function NetworkDetailsPage(props: PageProps) { // title: 'Preferred DNS', // dataIndex: 'name', // }, + { + title: 'Connectivity', + render: (_, node) => ( + {node.connected ? 'Connected' : 'Disconnected'} + ), + }, { title: 'Health Status', render(_, node) { @@ -1653,12 +1700,23 @@ export default function NetworkDetailsPage(props: PageProps) { }, { key: 'disconnect', + label: node.connected ? 'Disconnect host' : 'Connect host', + disabled: node.pendingdelete !== false, + title: node.pendingdelete !== false ? 'Host is being disconnected from network' : '', + onClick: () => + disconnectNodeFromNetwork( + !node.connected, + getExtendedNode(node, store.hostsCommonDetails) + ), + }, + { + key: 'remove', label: 'Remove from network', danger: true, disabled: node.pendingdelete !== false, title: node.pendingdelete !== false ? 'Host is being removed from network' : '', onClick: () => - disconnectNodeFromNetwork(false, getExtendedNode(node, store.hostsCommonDetails)), + removeNodeFromNetwork(false, getExtendedNode(node, store.hostsCommonDetails)), }, ], }}