mirror of
https://github.com/sipeed/NanoKVM.git
synced 2026-09-11 00:22:56 -05:00
add the Hostname Editbar into the Web UI
This commit is contained in:
@@ -102,3 +102,11 @@ type GetMouseJigglerStateRsp struct {
|
||||
type GetMdnsStateRsp struct {
|
||||
Enabled bool `json:"enabled"`
|
||||
}
|
||||
|
||||
type SetHostnameReq struct {
|
||||
Hostname string `json:"hostname"`
|
||||
}
|
||||
|
||||
type GetHostnameRsp struct {
|
||||
Hostname string `json:"hostname"`
|
||||
}
|
||||
|
||||
@@ -48,6 +48,9 @@ func vmRouter(r *gin.Engine) {
|
||||
api.POST("/vm/mouseJiggler/enable", service.EnableMouseJiggler) // enable MouseJiggler
|
||||
api.POST("/vm/mouseJiggler/disable", service.DisableMouseJiggler) // disable MouseJiggler
|
||||
|
||||
api.GET("/vm/hostname", service.GetHostname) // Get Hostname
|
||||
api.POST("/vm/hostname", service.SetHostname) // Set Hostname
|
||||
|
||||
api.GET("/vm/mdns", service.GetMdnsState) // get mDNS state
|
||||
api.POST("/vm/mdns/enable", service.EnableMdns) // enable mDNS
|
||||
api.POST("/vm/mdns/disable", service.DisableMdns) // disable mDNS
|
||||
|
||||
51
server/service/vm/hostname.go
Normal file
51
server/service/vm/hostname.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package vm
|
||||
|
||||
import (
|
||||
"NanoKVM-Server/proto"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
const (
|
||||
HostnameFile = "/etc/hostname"
|
||||
)
|
||||
|
||||
func (s *Service) SetHostname(c *gin.Context) {
|
||||
var req proto.SetHostnameReq
|
||||
var rsp proto.Response
|
||||
|
||||
if err := proto.ParseFormRequest(c, &req); err != nil {
|
||||
rsp.ErrRsp(c, -1, "invalid arguments")
|
||||
return
|
||||
}
|
||||
|
||||
data := []byte(fmt.Sprintf("%s", req.Hostname))
|
||||
|
||||
err := os.WriteFile(HostnameFile, data, 0o644)
|
||||
if err != nil {
|
||||
rsp.ErrRsp(c, -2, "failed to write data")
|
||||
return
|
||||
}
|
||||
|
||||
rsp.OkRsp(c)
|
||||
log.Debugf("set Hostname: %s", req.Hostname)
|
||||
}
|
||||
|
||||
func (s *Service) GetHostname(c *gin.Context) {
|
||||
var rsp proto.Response
|
||||
|
||||
data, err := os.ReadFile(HostnameFile)
|
||||
if err != nil {
|
||||
rsp.ErrRsp(c, -1, "read Hostname failed")
|
||||
return
|
||||
}
|
||||
|
||||
rsp.OkRspWithData(c, &proto.GetHostnameRsp{
|
||||
Hostname: strings.Replace(string(data), "\n", "", -1),
|
||||
})
|
||||
log.Debugf("get Hostname successful")
|
||||
}
|
||||
@@ -107,6 +107,16 @@ export function disableMouseJiggler() {
|
||||
return http.post('/api/vm/mouseJiggler/disable');
|
||||
}
|
||||
|
||||
// get Hostname
|
||||
export function getHostname() {
|
||||
return http.get('/api/vm/hostname');
|
||||
}
|
||||
|
||||
// set Hostname
|
||||
export function setHostname(hostname: string) {
|
||||
return http.post('/api/vm/hostname', { hostname });
|
||||
}
|
||||
|
||||
// get mDNS state
|
||||
export function getMdnsState() {
|
||||
return http.get('/api/vm/mdns');
|
||||
|
||||
@@ -225,6 +225,13 @@ const en = {
|
||||
description: 'Enable the swap partition',
|
||||
tip: 'Enable the default swap partition(128M)'
|
||||
},
|
||||
hostname: {
|
||||
title: 'Hostname',
|
||||
description: 'NanoKVM Hostname',
|
||||
tip: 'Need reboot to apply the change',
|
||||
success: 'Hostname changed successfully',
|
||||
error: 'Hostname change failed'
|
||||
},
|
||||
mouseJiggler: {
|
||||
title: 'Mouse Jiggler',
|
||||
description: 'Enable the mouse jiggler',
|
||||
|
||||
@@ -216,6 +216,13 @@ const zh = {
|
||||
description: '启用鼠标抖动',
|
||||
tip: '在鼠标离开60s未操作时自动进行抖动以防止系统睡眠'
|
||||
},
|
||||
hostname: {
|
||||
title: 'Hostname',
|
||||
description: 'NanoKVM 主机名',
|
||||
tip: '修改后需要重启生效',
|
||||
success: '主机名修改成功',
|
||||
error: '主机名修改失败'
|
||||
},
|
||||
powerConfirm:{
|
||||
title: '电源操作确认',
|
||||
description: '启用电源操作二次确认',
|
||||
|
||||
74
web/src/pages/desktop/menu/settings/device/hostname.tsx
Normal file
74
web/src/pages/desktop/menu/settings/device/hostname.tsx
Normal file
@@ -0,0 +1,74 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Input, Tooltip, message } from 'antd';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { CircleAlertIcon } from 'lucide-react';
|
||||
import { isKeyboardEnableAtom } from '@/jotai/keyboard.ts';
|
||||
import { useSetAtom } from 'jotai';
|
||||
|
||||
import * as api from '@/api/vm.ts';
|
||||
import { LoadingOutlined } from '@ant-design/icons';
|
||||
|
||||
export const Hostname = () => {
|
||||
|
||||
const { t } = useTranslation();
|
||||
const setIsKeyboardEnable = useSetAtom(isKeyboardEnableAtom);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [hostname, setHostname] = useState("");
|
||||
const [messageApi, contextHolder] = message.useMessage();
|
||||
useEffect(() => {
|
||||
setIsLoading(true);
|
||||
|
||||
api
|
||||
.getHostname()
|
||||
.then((rsp) => {
|
||||
if (rsp.data?.hostname) {
|
||||
setHostname(rsp.data?.hostname.toString());
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
setIsLoading(false);
|
||||
});
|
||||
}, []);
|
||||
|
||||
|
||||
async function update() {
|
||||
if (isLoading) return;
|
||||
setIsLoading(true);
|
||||
|
||||
const rsp = await api.setHostname(hostname);
|
||||
|
||||
if (rsp.code !== 0) {
|
||||
console.log(rsp.msg);
|
||||
messageApi.error(t('settings.device.hostname.error') + ":" + rsp.msg);
|
||||
return;
|
||||
}else{
|
||||
messageApi.success(t('settings.device.hostname.success'));
|
||||
}
|
||||
setIsLoading(false);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex flex-col">
|
||||
<div className="flex items-center space-x-2">
|
||||
<span>{t('settings.device.hostname.title')}</span>
|
||||
|
||||
<Tooltip
|
||||
title={t('settings.device.hostname.tip')}
|
||||
className="cursor-pointer"
|
||||
placement="bottom"
|
||||
overlayStyle={{ maxWidth: '300px' }}
|
||||
>
|
||||
<CircleAlertIcon size={15} />
|
||||
</Tooltip>
|
||||
</div>
|
||||
<span className="text-xs text-neutral-500">{t('settings.device.hostname.description')}</span>
|
||||
</div>
|
||||
{!isLoading ? <Input onFocus={() => setIsKeyboardEnable(false)} onBlur={() => setIsKeyboardEnable(true)} style={{ width: 150 }} value={hostname} onChange={(e) => setHostname(e.target.value)} onPressEnter={update} /> : <LoadingOutlined />}
|
||||
{contextHolder}
|
||||
</div>
|
||||
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ import { Wifi } from './wifi.tsx';
|
||||
import { Swap } from './swap.tsx';
|
||||
import { MouseJiggler } from './mouse-jiggler.tsx';
|
||||
import { PowerConfirm } from './PowerConfirm.tsx';
|
||||
import { Hostname } from './hostname.tsx';
|
||||
|
||||
export const Device = () => {
|
||||
const { t } = useTranslation();
|
||||
@@ -37,6 +38,7 @@ export const Device = () => {
|
||||
|
||||
<div className="flex flex-col space-y-6">
|
||||
<Oled />
|
||||
<Hostname />
|
||||
<Wifi />
|
||||
<Ssh />
|
||||
<Mdns />
|
||||
|
||||
Reference in New Issue
Block a user