mirror of https://github.com/jetkvm/kvm.git
feat(ui): add network settings tab
This commit is contained in:
parent
d9eae340bf
commit
fd3a8cb553
|
@ -143,3 +143,7 @@ func (c *DHCPClient) loadLeaseFile() error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *DHCPClient) GetLease() *Lease {
|
||||
return c.lease
|
||||
}
|
||||
|
|
|
@ -960,6 +960,8 @@ var rpcHandlers = map[string]RPCHandler{
|
|||
"getDeviceID": {Func: rpcGetDeviceID},
|
||||
"deregisterDevice": {Func: rpcDeregisterDevice},
|
||||
"getCloudState": {Func: rpcGetCloudState},
|
||||
"getNetworkState": {Func: rpcGetNetworkState},
|
||||
"renewDHCPLease": {Func: rpcRenewDHCPLease},
|
||||
"keyboardReport": {Func: rpcKeyboardReport, Params: []string{"modifier", "keys"}},
|
||||
"absMouseReport": {Func: rpcAbsMouseReport, Params: []string{"x", "y", "buttons"}},
|
||||
"relMouseReport": {Func: rpcRelMouseReport, Params: []string{"dx", "dy", "buttons"}},
|
||||
|
|
29
network.go
29
network.go
|
@ -47,6 +47,14 @@ type NetworkInterfaceState struct {
|
|||
checked bool
|
||||
}
|
||||
|
||||
type RpcNetworkState struct {
|
||||
InterfaceName string `json:"interface_name"`
|
||||
MacAddress string `json:"mac_address"`
|
||||
IPv4 string `json:"ipv4,omitempty"`
|
||||
IPv6 string `json:"ipv6,omitempty"`
|
||||
DHCPLease *udhcpc.Lease `json:"dhcp_lease,omitempty"`
|
||||
}
|
||||
|
||||
func (s *NetworkInterfaceState) IsUp() bool {
|
||||
return s.interfaceUp
|
||||
}
|
||||
|
@ -305,6 +313,27 @@ func (s *NetworkInterfaceState) HandleLinkUpdate(update netlink.LinkUpdate) {
|
|||
}
|
||||
}
|
||||
|
||||
func rpcGetNetworkState() RpcNetworkState {
|
||||
return RpcNetworkState{
|
||||
InterfaceName: networkState.interfaceName,
|
||||
MacAddress: networkState.macAddr.String(),
|
||||
IPv4: networkState.ipv4Addr.String(),
|
||||
IPv6: networkState.ipv6Addr.String(),
|
||||
DHCPLease: networkState.dhcpClient.GetLease(),
|
||||
}
|
||||
}
|
||||
|
||||
func rpcRenewDHCPLease() error {
|
||||
if networkState == nil {
|
||||
return fmt.Errorf("network state not initialized")
|
||||
}
|
||||
if networkState.dhcpClient == nil {
|
||||
return fmt.Errorf("dhcp client not initialized")
|
||||
}
|
||||
|
||||
return networkState.dhcpClient.Renew()
|
||||
}
|
||||
|
||||
func initNetwork() {
|
||||
ensureConfigLoaded()
|
||||
|
||||
|
|
|
@ -42,6 +42,7 @@ import SettingsVideoRoute from "./routes/devices.$id.settings.video";
|
|||
import SettingsAppearanceRoute from "./routes/devices.$id.settings.appearance";
|
||||
import * as SettingsGeneralIndexRoute from "./routes/devices.$id.settings.general._index";
|
||||
import SettingsGeneralUpdateRoute from "./routes/devices.$id.settings.general.update";
|
||||
import SettingsNetworkRoute from "./routes/devices.$id.settings.network";
|
||||
import SecurityAccessLocalAuthRoute from "./routes/devices.$id.settings.access.local-auth";
|
||||
import SettingsMacrosRoute from "./routes/devices.$id.settings.macros";
|
||||
import SettingsMacrosAddRoute from "./routes/devices.$id.settings.macros.add";
|
||||
|
@ -156,6 +157,10 @@ if (isOnDevice) {
|
|||
path: "hardware",
|
||||
element: <SettingsHardwareRoute />,
|
||||
},
|
||||
{
|
||||
path: "network",
|
||||
element: <SettingsNetworkRoute />,
|
||||
},
|
||||
{
|
||||
path: "access",
|
||||
children: [
|
||||
|
|
|
@ -0,0 +1,135 @@
|
|||
import { useCallback, useEffect, useState } from "react";
|
||||
|
||||
import { SettingsPageHeader } from "../components/SettingsPageheader";
|
||||
import { SelectMenuBasic } from "../components/SelectMenuBasic";
|
||||
|
||||
import { SettingsItem } from "./devices.$id.settings";
|
||||
import { useJsonRpc } from "@/hooks/useJsonRpc";
|
||||
import { Button } from "@components/Button";
|
||||
import notifications from "@/notifications";
|
||||
|
||||
interface DhcpLease {
|
||||
ip?: string;
|
||||
netmask?: string;
|
||||
broadcast?: string;
|
||||
ttl?: string;
|
||||
mtu?: string;
|
||||
hostname?: string;
|
||||
domain?: string;
|
||||
bootp_next_server?: string;
|
||||
bootp_server_name?: string;
|
||||
bootp_file?: string;
|
||||
timezone?: string;
|
||||
routers?: string[];
|
||||
dns?: string[];
|
||||
ntp_servers?: string[];
|
||||
lpr_servers?: string[];
|
||||
_time_servers?: string[];
|
||||
_name_servers?: string[];
|
||||
_log_servers?: string[];
|
||||
_cookie_servers?: string[];
|
||||
_wins_servers?: string[];
|
||||
_swap_server?: string;
|
||||
boot_size?: string;
|
||||
root_path?: string;
|
||||
lease?: string;
|
||||
dhcp_type?: string;
|
||||
server_id?: string;
|
||||
message?: string;
|
||||
tftp?: string;
|
||||
bootfile?: string;
|
||||
}
|
||||
|
||||
|
||||
interface NetworkState {
|
||||
interface_name?: string;
|
||||
mac_address?: string;
|
||||
ipv4?: string;
|
||||
ipv6?: string;
|
||||
dhcp_lease?: DhcpLease;
|
||||
}
|
||||
|
||||
export default function SettingsNetworkRoute() {
|
||||
const [send] = useJsonRpc();
|
||||
const [networkState, setNetworkState] = useState<NetworkState | null>(null);
|
||||
|
||||
|
||||
const getNetworkState = useCallback(() => {
|
||||
send("getNetworkState", {}, resp => {
|
||||
if ("error" in resp) return;
|
||||
setNetworkState(resp.result as NetworkState);
|
||||
});
|
||||
}, [send]);
|
||||
|
||||
const handleRenewLease = useCallback(() => {
|
||||
send("renewDHCPLease", {}, resp => {
|
||||
if ("error" in resp) {
|
||||
notifications.error("Failed to renew lease: " + resp.error.message);
|
||||
} else {
|
||||
notifications.success("DHCP lease renewed");
|
||||
getNetworkState();
|
||||
}
|
||||
});
|
||||
}, [send, getNetworkState]);
|
||||
|
||||
useEffect(() => {
|
||||
getNetworkState();
|
||||
}, [getNetworkState]);
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<SettingsPageHeader
|
||||
title="Network"
|
||||
description="Configure your network settings"
|
||||
/>
|
||||
<div className="space-y-4">
|
||||
<SettingsItem
|
||||
title="IPv4 Address"
|
||||
description={
|
||||
<span className="select-text font-mono">{networkState?.ipv4}</span>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-4">
|
||||
<SettingsItem
|
||||
title="IPv6 Address"
|
||||
description={<span className="select-text font-mono">{networkState?.ipv6}</span>}
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-4">
|
||||
<SettingsItem
|
||||
title="MAC Address"
|
||||
description={<span className="select-auto font-mono">{networkState?.mac_address}</span>}
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-4">
|
||||
<SettingsItem
|
||||
title="DHCP Lease"
|
||||
description={<>
|
||||
<ul>
|
||||
{networkState?.dhcp_lease?.ip && <li>IP: <strong>{networkState?.dhcp_lease?.ip}</strong></li>}
|
||||
{networkState?.dhcp_lease?.netmask && <li>Subnet: <strong>{networkState?.dhcp_lease?.netmask}</strong></li>}
|
||||
{networkState?.dhcp_lease?.broadcast && <li>Broadcast: <strong>{networkState?.dhcp_lease?.broadcast}</strong></li>}
|
||||
{networkState?.dhcp_lease?.ttl && <li>TTL: <strong>{networkState?.dhcp_lease?.ttl}</strong></li>}
|
||||
{networkState?.dhcp_lease?.mtu && <li>MTU: <strong>{networkState?.dhcp_lease?.mtu}</strong></li>}
|
||||
{networkState?.dhcp_lease?.hostname && <li>Hostname: <strong>{networkState?.dhcp_lease?.hostname}</strong></li>}
|
||||
{networkState?.dhcp_lease?.domain && <li>Domain: <strong>{networkState?.dhcp_lease?.domain}</strong></li>}
|
||||
{networkState?.dhcp_lease?.routers && <li>Gateway: <strong>{networkState?.dhcp_lease?.routers.join(", ")}</strong></li>}
|
||||
{networkState?.dhcp_lease?.dns && <li>DNS: <strong>{networkState?.dhcp_lease?.dns.join(", ")}</strong></li>}
|
||||
{networkState?.dhcp_lease?.ntp_servers && <li>NTP Servers: <strong>{networkState?.dhcp_lease?.ntp_servers.join(", ")}</strong></li>}
|
||||
</ul>
|
||||
</>}
|
||||
>
|
||||
<Button
|
||||
size="SM"
|
||||
theme="light"
|
||||
text="Renew lease"
|
||||
onClick={() => {
|
||||
handleRenewLease();
|
||||
}}
|
||||
/>
|
||||
</SettingsItem>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -9,6 +9,7 @@ import {
|
|||
LuArrowLeft,
|
||||
LuPalette,
|
||||
LuCommand,
|
||||
LuNetwork,
|
||||
} from "react-icons/lu";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
|
||||
|
@ -207,6 +208,17 @@ export default function SettingsRoute() {
|
|||
</div>
|
||||
</NavLink>
|
||||
</div>
|
||||
<div className="shrink-0">
|
||||
<NavLink
|
||||
to="network"
|
||||
className={({ isActive }) => (isActive ? "active" : "")}
|
||||
>
|
||||
<div className="flex items-center gap-x-2 rounded-md px-2.5 py-2.5 text-sm transition-colors hover:bg-slate-100 dark:hover:bg-slate-700 [.active_&]:bg-blue-50 [.active_&]:!text-blue-700 md:[.active_&]:bg-transparent dark:[.active_&]:bg-blue-900 dark:[.active_&]:!text-blue-200 dark:md:[.active_&]:bg-transparent">
|
||||
<LuNetwork className="h-4 w-4 shrink-0" />
|
||||
<h1>Network</h1>
|
||||
</div>
|
||||
</NavLink>
|
||||
</div>
|
||||
<div className="shrink-0">
|
||||
<NavLink
|
||||
to="advanced"
|
||||
|
|
Loading…
Reference in New Issue