mirror of
https://github.com/sipeed/NanoKVM.git
synced 2026-09-11 00:22:56 -05:00
feat: add DNS management to Network settings
- Add DNS configuration APIs for manual and DHCP modes, including persistence and udhcpc hook support. - Add a Network settings tab with DNS controls, move Wi-Fi and HTTPS settings into it, and update translations. - Update locales
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
import { http } from '@/lib/http.ts';
|
||||
|
||||
export type DNSMode = 'manual' | 'dhcp';
|
||||
|
||||
// wake on lan
|
||||
export function wol(mac: string) {
|
||||
const data = {
|
||||
@@ -69,3 +71,11 @@ export function connectWifi(ssid: string, password: string) {
|
||||
export function disconnectWifi() {
|
||||
return http.post('/api/network/wifi/disconnect');
|
||||
}
|
||||
|
||||
export function getDNS() {
|
||||
return http.get('/api/network/dns');
|
||||
}
|
||||
|
||||
export function setDNS(mode: DNSMode, servers: string[]) {
|
||||
return http.post('/api/network/dns', { mode, servers });
|
||||
}
|
||||
|
||||
@@ -4,9 +4,12 @@ import clsx from 'clsx';
|
||||
|
||||
function ScrollArea({
|
||||
className,
|
||||
viewportRef,
|
||||
children,
|
||||
...props
|
||||
}: React.ComponentProps<typeof ScrollAreaPrimitive.Root>) {
|
||||
}: React.ComponentProps<typeof ScrollAreaPrimitive.Root> & {
|
||||
viewportRef?: React.Ref<HTMLDivElement>;
|
||||
}) {
|
||||
return (
|
||||
<ScrollAreaPrimitive.Root
|
||||
data-slot="scroll-area"
|
||||
@@ -14,6 +17,7 @@ function ScrollArea({
|
||||
{...props}
|
||||
>
|
||||
<ScrollAreaPrimitive.Viewport
|
||||
ref={viewportRef}
|
||||
data-slot="scroll-area-viewport"
|
||||
className="focus-visible:ring-ring/50 size-full rounded-[inherit] outline-none transition-[color,box-shadow] focus-visible:outline-1 focus-visible:ring-[3px]"
|
||||
>
|
||||
|
||||
@@ -226,19 +226,10 @@ const ca = {
|
||||
1800: "30 min",
|
||||
3600: "1 h"
|
||||
},
|
||||
wifi: {
|
||||
title: "Xarxa sense fils",
|
||||
description: "Configura la xarxa sense fils",
|
||||
setBtn: "Configura"
|
||||
},
|
||||
ssh: {
|
||||
description: "Activa accés remot per SSH",
|
||||
tip: "Configura una contrasenya segura abans (Compte - Canvia contrasenya)"
|
||||
},
|
||||
tls: {
|
||||
description: "Activa el protocol HTTPS",
|
||||
tip: "Atenció: Usar HTTPS pot augmentar la latència, sobretot amb vídeo MJPEG."
|
||||
},
|
||||
advanced: "Configuració avançada",
|
||||
swap: {
|
||||
title: "Swap",
|
||||
@@ -270,6 +261,52 @@ const ca = {
|
||||
okBtn: "Sí",
|
||||
cancelBtn: "No"
|
||||
},
|
||||
network: {
|
||||
title: 'Xarxa',
|
||||
wifi: {
|
||||
title: 'Wi-Fi',
|
||||
description: 'Configura la xarxa Wi-Fi',
|
||||
apMode: 'El mode AP està activat; connecta\'t al Wi-Fi escanejant el codi QR',
|
||||
connect: 'Connecta\'t a Wi-Fi',
|
||||
connectDesc1: 'Introdueix el SSID i la contrasenya de la xarxa',
|
||||
connectDesc2: 'Introdueix la contrasenya per connectar-te a aquesta xarxa',
|
||||
disconnect: 'Segur que vols desconnectar la xarxa?',
|
||||
failed: 'La connexió ha fallat, torna-ho a provar.',
|
||||
ssid: 'Nom',
|
||||
password: 'Contrasenya',
|
||||
joinBtn: 'Connecta',
|
||||
confirmBtn: 'D\'acord',
|
||||
cancelBtn: 'Cancel·la'
|
||||
},
|
||||
tls: {
|
||||
description: 'Activa el protocol HTTPS',
|
||||
tip: 'Atenció: Usar HTTPS pot augmentar la latència, sobretot amb vídeo MJPEG.'
|
||||
},
|
||||
dns: {
|
||||
title: 'DNS',
|
||||
description: 'Configura els servidors DNS per a NanoKVM',
|
||||
mode: 'Mode',
|
||||
dhcp: 'DHCP',
|
||||
manual: 'Manual',
|
||||
add: 'Afegeix DNS',
|
||||
save: 'Desa',
|
||||
invalid: 'Introdueix una adreça IP vàlida',
|
||||
noDhcp: 'No hi ha cap DNS DHCP disponible actualment',
|
||||
saved: 'Configuració DNS desada',
|
||||
saveFailed: 'No s\'ha pogut desar la configuració DNS',
|
||||
unsaved: 'Canvis no desats',
|
||||
maxServers: 'Es permeten com a màxim {{count}} servidors DNS',
|
||||
dnsServers: 'Servidors DNS',
|
||||
dhcpServersDescription: 'Els servidors DNS s\'obtenen automàticament via DHCP.',
|
||||
manualServersDescription: 'Els servidors DNS es poden editar manualment.',
|
||||
networkDetails: 'Detalls de xarxa',
|
||||
interface: 'Interfície',
|
||||
ipAddress: 'Adreça IP',
|
||||
subnetMask: 'Màscara de subxarxa',
|
||||
router: 'Encaminador',
|
||||
none: 'Cap'
|
||||
}
|
||||
},
|
||||
tailscale: {
|
||||
title: "Tailscale",
|
||||
memory: {
|
||||
|
||||
@@ -183,16 +183,57 @@ const cz = {
|
||||
1800: '30 min',
|
||||
3600: '1 hour'
|
||||
},
|
||||
wifi: {
|
||||
title: 'Wi-Fi',
|
||||
description: 'Configure Wi-Fi',
|
||||
setBtn: 'Config'
|
||||
},
|
||||
disk: 'Virtual Disk',
|
||||
diskDesc: 'Mount virtual U-disk on the remote host',
|
||||
network: 'Virtual Network',
|
||||
networkDesc: 'Mount virtual network card on the remote host'
|
||||
},
|
||||
network: {
|
||||
title: 'Síť',
|
||||
wifi: {
|
||||
title: 'Wi-Fi',
|
||||
description: 'Nastavit Wi-Fi',
|
||||
apMode: 'Režim AP je povolen, připojte se k Wi-Fi naskenováním QR kódu',
|
||||
connect: 'Připojit Wi-Fi',
|
||||
connectDesc1: 'Zadejte SSID sítě a heslo',
|
||||
connectDesc2: 'Zadejte heslo pro připojení k této síti',
|
||||
disconnect: 'Opravdu chcete síť odpojit?',
|
||||
failed: 'Připojení se nezdařilo, zkuste to znovu.',
|
||||
ssid: 'Název',
|
||||
password: 'Heslo',
|
||||
joinBtn: 'Připojit',
|
||||
confirmBtn: 'OK',
|
||||
cancelBtn: 'Zrušit'
|
||||
},
|
||||
tls: {
|
||||
description: 'Povolit protokol HTTPS',
|
||||
tip: 'Upozornění: Použití HTTPS může zvýšit latenci, zejména v režimu videa MJPEG.'
|
||||
},
|
||||
dns: {
|
||||
title: 'DNS',
|
||||
description: 'Nastavit DNS servery pro NanoKVM',
|
||||
mode: 'Režim',
|
||||
dhcp: 'DHCP',
|
||||
manual: 'Ručně',
|
||||
add: 'Přidat DNS',
|
||||
save: 'Uložit',
|
||||
invalid: 'Zadejte platnou IP adresu',
|
||||
noDhcp: 'Momentálně není k dispozici žádné DHCP DNS',
|
||||
saved: 'Nastavení DNS uloženo',
|
||||
saveFailed: 'Nastavení DNS se nepodařilo uložit',
|
||||
unsaved: 'Neuložené změny',
|
||||
maxServers: 'Je povoleno maximálně {{count}} DNS serverů',
|
||||
dnsServers: 'DNS servery',
|
||||
dhcpServersDescription: 'DNS servery jsou automaticky získávány z DHCP.',
|
||||
manualServersDescription: 'DNS servery lze upravit ručně.',
|
||||
networkDetails: 'Podrobnosti sítě',
|
||||
interface: 'Rozhraní',
|
||||
ipAddress: 'IP adresa',
|
||||
subnetMask: 'Maska podsítě',
|
||||
router: 'Router',
|
||||
none: 'Žádné'
|
||||
}
|
||||
},
|
||||
tailscale: {
|
||||
title: 'Tailscale',
|
||||
memory: {
|
||||
|
||||
@@ -181,16 +181,57 @@ const da = {
|
||||
1800: '30 min',
|
||||
3600: '1 hour'
|
||||
},
|
||||
wifi: {
|
||||
title: 'Wi-Fi',
|
||||
description: 'Configure Wi-Fi',
|
||||
setBtn: 'Config'
|
||||
},
|
||||
disk: 'Virtual Disk',
|
||||
diskDesc: 'Mount virtual U-disk on the remote host',
|
||||
network: 'Virtual Network',
|
||||
networkDesc: 'Mount virtual network card on the remote host'
|
||||
},
|
||||
network: {
|
||||
title: 'Netværk',
|
||||
wifi: {
|
||||
title: 'Wi-Fi',
|
||||
description: 'Konfigurer Wi-Fi',
|
||||
apMode: 'AP-tilstand er aktiveret, opret forbindelse til Wi-Fi ved at scanne QR-koden',
|
||||
connect: 'Tilslut Wi-Fi',
|
||||
connectDesc1: 'Indtast netværkets SSID og adgangskode',
|
||||
connectDesc2: 'Indtast adgangskoden for at tilslutte dette netværk',
|
||||
disconnect: 'Er du sikker på, at du vil afbryde netværket?',
|
||||
failed: 'Forbindelsen mislykkedes, prøv igen.',
|
||||
ssid: 'Navn',
|
||||
password: 'Adgangskode',
|
||||
joinBtn: 'Tilslut',
|
||||
confirmBtn: 'OK',
|
||||
cancelBtn: 'Annuller'
|
||||
},
|
||||
tls: {
|
||||
description: 'Aktiver HTTPS-protokol',
|
||||
tip: 'Bemærk: Brug af HTTPS kan øge forsinkelsen, især med MJPEG-videotilstand.'
|
||||
},
|
||||
dns: {
|
||||
title: 'DNS',
|
||||
description: 'Konfigurer DNS-servere til NanoKVM',
|
||||
mode: 'Tilstand',
|
||||
dhcp: 'DHCP',
|
||||
manual: 'Manuel',
|
||||
add: 'Tilføj DNS',
|
||||
save: 'Gem',
|
||||
invalid: 'Indtast en gyldig IP-adresse',
|
||||
noDhcp: 'Ingen DHCP-DNS er tilgængelig i øjeblikket',
|
||||
saved: 'DNS-indstillinger gemt',
|
||||
saveFailed: 'DNS-indstillinger kunne ikke gemmes',
|
||||
unsaved: 'Ikke-gemte ændringer',
|
||||
maxServers: 'Maksimalt {{count}} DNS-servere er tilladt',
|
||||
dnsServers: 'DNS-servere',
|
||||
dhcpServersDescription: 'DNS-servere hentes automatisk fra DHCP.',
|
||||
manualServersDescription: 'DNS-servere kan redigeres manuelt.',
|
||||
networkDetails: 'Netværksdetaljer',
|
||||
interface: 'Grænseflade',
|
||||
ipAddress: 'IP-adresse',
|
||||
subnetMask: 'Undernetmaske',
|
||||
router: 'Router',
|
||||
none: 'Ingen'
|
||||
}
|
||||
},
|
||||
tailscale: {
|
||||
title: 'Tailscale',
|
||||
memory: {
|
||||
|
||||
@@ -238,11 +238,6 @@ const de = {
|
||||
1800: '30 Min',
|
||||
3600: '1 Stunde'
|
||||
},
|
||||
wifi: {
|
||||
title: 'Wi-Fi',
|
||||
description: 'Wi-Fi konfigurieren',
|
||||
setBtn: 'Konfigurieren'
|
||||
},
|
||||
ssh: {
|
||||
description: 'Aktiviere entfernten SSH-Zugang',
|
||||
tip: 'Setzten Sie ein starkes Passwort vor dem aktivieren (Konto - Passwort ändern)'
|
||||
@@ -275,6 +270,52 @@ const de = {
|
||||
okBtn: 'Ja',
|
||||
cancelBtn: 'Nein'
|
||||
},
|
||||
network: {
|
||||
title: 'Netzwerk',
|
||||
wifi: {
|
||||
title: 'Wi-Fi',
|
||||
description: 'Wi-Fi konfigurieren',
|
||||
apMode: 'AP-Modus ist aktiviert, verbinden Sie sich per QR-Code mit dem Wi-Fi',
|
||||
connect: 'Wi-Fi verbinden',
|
||||
connectDesc1: 'Bitte geben Sie die Netzwerk-SSID und das Passwort ein',
|
||||
connectDesc2: 'Bitte geben Sie das Passwort ein, um diesem Netzwerk beizutreten',
|
||||
disconnect: 'Möchten Sie die Netzwerkverbindung wirklich trennen?',
|
||||
failed: 'Verbindung fehlgeschlagen, bitte erneut versuchen.',
|
||||
ssid: 'Name',
|
||||
password: 'Passwort',
|
||||
joinBtn: 'Verbinden',
|
||||
confirmBtn: 'OK',
|
||||
cancelBtn: 'Abbrechen'
|
||||
},
|
||||
tls: {
|
||||
description: 'HTTPS-Protokoll aktivieren',
|
||||
tip: 'Hinweis: Die Verwendung von HTTPS kann die Latenz erhöhen, besonders im MJPEG-Videomodus.'
|
||||
},
|
||||
dns: {
|
||||
title: 'DNS',
|
||||
description: 'DNS-Server für NanoKVM konfigurieren',
|
||||
mode: 'Modus',
|
||||
dhcp: 'DHCP',
|
||||
manual: 'Manuell',
|
||||
add: 'DNS hinzufügen',
|
||||
save: 'Speichern',
|
||||
invalid: 'Bitte geben Sie eine gültige IP-Adresse ein',
|
||||
noDhcp: 'Derzeit ist kein DHCP-DNS verfügbar',
|
||||
saved: 'DNS-Einstellungen gespeichert',
|
||||
saveFailed: 'DNS-Einstellungen konnten nicht gespeichert werden',
|
||||
unsaved: 'Ungespeicherte Änderungen',
|
||||
maxServers: 'Maximal {{count}} DNS-Server erlaubt',
|
||||
dnsServers: 'DNS-Server',
|
||||
dhcpServersDescription: 'DNS-Server werden automatisch per DHCP bezogen.',
|
||||
manualServersDescription: 'DNS-Server können manuell bearbeitet werden.',
|
||||
networkDetails: 'Netzwerkdetails',
|
||||
interface: 'Schnittstelle',
|
||||
ipAddress: 'IP-Adresse',
|
||||
subnetMask: 'Subnetzmaske',
|
||||
router: 'Router',
|
||||
none: 'Keine'
|
||||
}
|
||||
},
|
||||
tailscale: {
|
||||
title: 'Tailscale',
|
||||
memory: {
|
||||
|
||||
@@ -309,29 +309,10 @@ const en = {
|
||||
1800: '30 min',
|
||||
3600: '1 hour'
|
||||
},
|
||||
wifi: {
|
||||
title: 'Wi-Fi',
|
||||
description: 'Configure Wi-Fi',
|
||||
apMode: 'AP mode is enabled, connect to Wi-Fi by scanning QR code',
|
||||
connect: 'Join Wi-Fi',
|
||||
connectDesc1: 'Please enter the network ssid and password',
|
||||
connectDesc2: 'Please enter the password to join this network',
|
||||
disconnect: 'Are you sure to disconnect the network?',
|
||||
failed: 'Connection failed, please try again.',
|
||||
ssid: 'Name',
|
||||
password: 'Password',
|
||||
joinBtn: 'Join',
|
||||
confirmBtn: 'Ok',
|
||||
cancelBtn: 'Cancel'
|
||||
},
|
||||
ssh: {
|
||||
description: 'Enable SSH remote access',
|
||||
tip: 'Set a strong password before enabling (Account - Change Password)'
|
||||
},
|
||||
tls: {
|
||||
description: 'Enable HTTPS protocol',
|
||||
tip: 'Be aware: Using HTTPS can increase latency, especially with MJPEG video mode.'
|
||||
},
|
||||
advanced: 'Advanced Settings',
|
||||
swap: {
|
||||
title: 'Swap',
|
||||
@@ -375,6 +356,52 @@ const en = {
|
||||
okBtn: 'Yes',
|
||||
cancelBtn: 'No'
|
||||
},
|
||||
network: {
|
||||
title: 'Network',
|
||||
wifi: {
|
||||
title: 'Wi-Fi',
|
||||
description: 'Configure Wi-Fi',
|
||||
apMode: 'AP mode is enabled, connect to Wi-Fi by scanning QR code',
|
||||
connect: 'Join Wi-Fi',
|
||||
connectDesc1: 'Please enter the network ssid and password',
|
||||
connectDesc2: 'Please enter the password to join this network',
|
||||
disconnect: 'Are you sure to disconnect the network?',
|
||||
failed: 'Connection failed, please try again.',
|
||||
ssid: 'Name',
|
||||
password: 'Password',
|
||||
joinBtn: 'Join',
|
||||
confirmBtn: 'Ok',
|
||||
cancelBtn: 'Cancel'
|
||||
},
|
||||
tls: {
|
||||
description: 'Enable HTTPS protocol',
|
||||
tip: 'Be aware: Using HTTPS can increase latency, especially with MJPEG video mode.'
|
||||
},
|
||||
dns: {
|
||||
title: 'DNS',
|
||||
description: 'Configure DNS servers for NanoKVM',
|
||||
mode: 'Mode',
|
||||
dhcp: 'DHCP',
|
||||
manual: 'Manual',
|
||||
add: 'Add DNS',
|
||||
save: 'Save',
|
||||
invalid: 'Please enter a valid IP address',
|
||||
noDhcp: 'No DHCP DNS is currently available',
|
||||
saved: 'DNS settings saved',
|
||||
saveFailed: 'Failed to save DNS settings',
|
||||
unsaved: 'Unsaved changes',
|
||||
maxServers: 'Maximum {{count}} DNS servers allowed',
|
||||
dnsServers: 'DNS Servers',
|
||||
dhcpServersDescription: 'DNS servers are automatically obtained from DHCP.',
|
||||
manualServersDescription: 'DNS servers can be edited manually.',
|
||||
networkDetails: 'Network Details',
|
||||
interface: 'Interface',
|
||||
ipAddress: 'IP Address',
|
||||
subnetMask: 'Subnet Mask',
|
||||
router: 'Router',
|
||||
none: 'None'
|
||||
}
|
||||
},
|
||||
tailscale: {
|
||||
title: 'Tailscale',
|
||||
memory: {
|
||||
|
||||
@@ -237,19 +237,10 @@ const es = {
|
||||
1800: '30 min',
|
||||
3600: '1 hora'
|
||||
},
|
||||
wifi: {
|
||||
title: 'Wi-Fi',
|
||||
description: 'Configura el Wi-Fi',
|
||||
setBtn: 'Configurar'
|
||||
},
|
||||
ssh: {
|
||||
description: 'Habilitar acceso remoto SSH',
|
||||
tip: 'Establece una contraseña segura antes de habilitar (Cuenta - Cambiar contraseña)'
|
||||
},
|
||||
tls: {
|
||||
description: 'Habilitar protocolo HTTPS',
|
||||
tip: 'Aviso: Usar HTTPS puede aumentar la latencia, especialmente en modo de vídeo MJPEG.'
|
||||
},
|
||||
advanced: 'Ajustes avanzados',
|
||||
swap: {
|
||||
title: 'Memoria Swap',
|
||||
@@ -285,6 +276,52 @@ const es = {
|
||||
okBtn: 'Sí',
|
||||
cancelBtn: 'No'
|
||||
},
|
||||
network: {
|
||||
title: 'Red',
|
||||
wifi: {
|
||||
title: 'Wi-Fi',
|
||||
description: 'Configura el Wi-Fi',
|
||||
apMode: 'El modo AP está activado; conéctate al Wi-Fi escaneando el código QR',
|
||||
connect: 'Conectar Wi-Fi',
|
||||
connectDesc1: 'Introduce el SSID de la red y la contraseña',
|
||||
connectDesc2: 'Introduce la contraseña para unirte a esta red',
|
||||
disconnect: '¿Seguro que quieres desconectar la red?',
|
||||
failed: 'Error de conexión, inténtalo de nuevo.',
|
||||
ssid: 'Nombre',
|
||||
password: 'Contraseña',
|
||||
joinBtn: 'Unirse',
|
||||
confirmBtn: 'Aceptar',
|
||||
cancelBtn: 'Cancelar'
|
||||
},
|
||||
tls: {
|
||||
description: 'Habilitar protocolo HTTPS',
|
||||
tip: 'Aviso: Usar HTTPS puede aumentar la latencia, especialmente en modo de vídeo MJPEG.'
|
||||
},
|
||||
dns: {
|
||||
title: 'DNS',
|
||||
description: 'Configura los servidores DNS para NanoKVM',
|
||||
mode: 'Modo',
|
||||
dhcp: 'DHCP',
|
||||
manual: 'Manual',
|
||||
add: 'Añadir DNS',
|
||||
save: 'Guardar',
|
||||
invalid: 'Introduce una dirección IP válida',
|
||||
noDhcp: 'No hay DNS DHCP disponible actualmente',
|
||||
saved: 'Configuración DNS guardada',
|
||||
saveFailed: 'No se pudo guardar la configuración DNS',
|
||||
unsaved: 'Cambios sin guardar',
|
||||
maxServers: 'Se permiten como máximo {{count}} servidores DNS',
|
||||
dnsServers: 'Servidores DNS',
|
||||
dhcpServersDescription: 'Los servidores DNS se obtienen automáticamente por DHCP.',
|
||||
manualServersDescription: 'Los servidores DNS se pueden editar manualmente.',
|
||||
networkDetails: 'Detalles de red',
|
||||
interface: 'Interfaz',
|
||||
ipAddress: 'Dirección IP',
|
||||
subnetMask: 'Máscara de subred',
|
||||
router: 'Router',
|
||||
none: 'Ninguno'
|
||||
}
|
||||
},
|
||||
tailscale: {
|
||||
title: 'Tailscale',
|
||||
memory: {
|
||||
|
||||
@@ -194,16 +194,57 @@ const fr = {
|
||||
1800: '30 min',
|
||||
3600: '1 heure'
|
||||
},
|
||||
wifi: {
|
||||
title: 'Wi-Fi',
|
||||
description: 'Configurez le Wi-Fi',
|
||||
setBtn: 'Configurer'
|
||||
},
|
||||
disk: 'Disque virtuel',
|
||||
diskDesc: 'Monter le disque virtuel U sur l\'hôte distant',
|
||||
network: 'Réseau virtuel',
|
||||
networkDesc: 'Monter la carte réseau virtuelle sur l\'hôte distant'
|
||||
},
|
||||
network: {
|
||||
title: 'Réseau',
|
||||
wifi: {
|
||||
title: 'Wi-Fi',
|
||||
description: 'Configurez le Wi-Fi',
|
||||
apMode: 'Le mode AP est activé, connectez-vous au Wi-Fi en scannant le code QR',
|
||||
connect: 'Connecter le Wi-Fi',
|
||||
connectDesc1: 'Veuillez saisir le SSID du réseau et le mot de passe',
|
||||
connectDesc2: 'Veuillez saisir le mot de passe pour rejoindre ce réseau',
|
||||
disconnect: 'Voulez-vous vraiment déconnecter le réseau ?',
|
||||
failed: 'Échec de la connexion, veuillez réessayer.',
|
||||
ssid: 'Nom',
|
||||
password: 'Mot de passe',
|
||||
joinBtn: 'Rejoindre',
|
||||
confirmBtn: 'OK',
|
||||
cancelBtn: 'Annuler'
|
||||
},
|
||||
tls: {
|
||||
description: 'Activer le protocole HTTPS',
|
||||
tip: 'Attention : l\'utilisation de HTTPS peut augmenter la latence, surtout en mode vidéo MJPEG.'
|
||||
},
|
||||
dns: {
|
||||
title: 'DNS',
|
||||
description: 'Configurer les serveurs DNS pour NanoKVM',
|
||||
mode: 'Mode',
|
||||
dhcp: 'DHCP',
|
||||
manual: 'Manuel',
|
||||
add: 'Ajouter un DNS',
|
||||
save: 'Enregistrer',
|
||||
invalid: 'Veuillez saisir une adresse IP valide',
|
||||
noDhcp: 'Aucun DNS DHCP n\'est actuellement disponible',
|
||||
saved: 'Paramètres DNS enregistrés',
|
||||
saveFailed: 'Échec de l\'enregistrement des paramètres DNS',
|
||||
unsaved: 'Modifications non enregistrées',
|
||||
maxServers: '{{count}} serveurs DNS maximum autorisés',
|
||||
dnsServers: 'Serveurs DNS',
|
||||
dhcpServersDescription: 'Les serveurs DNS sont obtenus automatiquement par DHCP.',
|
||||
manualServersDescription: 'Les serveurs DNS peuvent être modifiés manuellement.',
|
||||
networkDetails: 'Détails du réseau',
|
||||
interface: 'Interface',
|
||||
ipAddress: 'Adresse IP',
|
||||
subnetMask: 'Masque de sous-réseau',
|
||||
router: 'Routeur',
|
||||
none: 'Aucun'
|
||||
}
|
||||
},
|
||||
tailscale: {
|
||||
title: 'Tailscale',
|
||||
memory: {
|
||||
|
||||
@@ -183,16 +183,57 @@ const hu = {
|
||||
1800: '30 min',
|
||||
3600: '1 hour'
|
||||
},
|
||||
wifi: {
|
||||
title: 'Wi-Fi',
|
||||
description: 'Configure Wi-Fi',
|
||||
setBtn: 'Config'
|
||||
},
|
||||
disk: 'Virtual Disk',
|
||||
diskDesc: 'Mount virtual U-disk on the remote host',
|
||||
network: 'Virtual Network',
|
||||
networkDesc: 'Mount virtual network card on the remote host'
|
||||
},
|
||||
network: {
|
||||
title: 'Hálózat',
|
||||
wifi: {
|
||||
title: 'Wi-Fi',
|
||||
description: 'Wi-Fi beállítása',
|
||||
apMode: 'Az AP mód engedélyezve van, csatlakozzon a Wi-Fihez a QR-kód beolvasásával',
|
||||
connect: 'Wi-Fi csatlakoztatása',
|
||||
connectDesc1: 'Adja meg a hálózat SSID-jét és jelszavát',
|
||||
connectDesc2: 'Adja meg a jelszót a hálózathoz való csatlakozáshoz',
|
||||
disconnect: 'Biztosan bontja a hálózati kapcsolatot?',
|
||||
failed: 'A csatlakozás sikertelen, próbálja újra.',
|
||||
ssid: 'Név',
|
||||
password: 'Jelszó',
|
||||
joinBtn: 'Csatlakozás',
|
||||
confirmBtn: 'OK',
|
||||
cancelBtn: 'Mégse'
|
||||
},
|
||||
tls: {
|
||||
description: 'HTTPS protokoll engedélyezése',
|
||||
tip: 'Figyelem: A HTTPS használata növelheti a késleltetést, különösen MJPEG videó módban.'
|
||||
},
|
||||
dns: {
|
||||
title: 'DNS',
|
||||
description: 'DNS-kiszolgálók beállítása a NanoKVM számára',
|
||||
mode: 'Mód',
|
||||
dhcp: 'DHCP',
|
||||
manual: 'Kézi',
|
||||
add: 'DNS hozzáadása',
|
||||
save: 'Mentés',
|
||||
invalid: 'Adjon meg egy érvényes IP-címet',
|
||||
noDhcp: 'Jelenleg nincs elérhető DHCP DNS',
|
||||
saved: 'DNS-beállítások mentve',
|
||||
saveFailed: 'Nem sikerült menteni a DNS-beállításokat',
|
||||
unsaved: 'Nem mentett módosítások',
|
||||
maxServers: 'Legfeljebb {{count}} DNS-kiszolgáló engedélyezett',
|
||||
dnsServers: 'DNS-kiszolgálók',
|
||||
dhcpServersDescription: 'A DNS-kiszolgálók automatikusan DHCP-n keresztül érkeznek.',
|
||||
manualServersDescription: 'A DNS-kiszolgálók kézzel szerkeszthetők.',
|
||||
networkDetails: 'Hálózati részletek',
|
||||
interface: 'Interfész',
|
||||
ipAddress: 'IP-cím',
|
||||
subnetMask: 'Alhálózati maszk',
|
||||
router: 'Router',
|
||||
none: 'Nincs'
|
||||
}
|
||||
},
|
||||
tailscale: {
|
||||
title: 'Tailscale',
|
||||
memory: {
|
||||
|
||||
@@ -182,16 +182,57 @@ const id = {
|
||||
1800: '30 min',
|
||||
3600: '1 hour'
|
||||
},
|
||||
wifi: {
|
||||
title: 'Wi-Fi',
|
||||
description: 'Configure Wi-Fi',
|
||||
setBtn: 'Config'
|
||||
},
|
||||
disk: 'Virtual Disk',
|
||||
diskDesc: 'Mount virtual U-disk on the remote host',
|
||||
network: 'Virtual Network',
|
||||
networkDesc: 'Mount virtual network card on the remote host'
|
||||
},
|
||||
network: {
|
||||
title: 'Jaringan',
|
||||
wifi: {
|
||||
title: 'Wi-Fi',
|
||||
description: 'Konfigurasi Wi-Fi',
|
||||
apMode: 'Mode AP aktif, sambungkan ke Wi-Fi dengan memindai kode QR',
|
||||
connect: 'Hubungkan Wi-Fi',
|
||||
connectDesc1: 'Masukkan SSID jaringan dan kata sandi',
|
||||
connectDesc2: 'Masukkan kata sandi untuk bergabung ke jaringan ini',
|
||||
disconnect: 'Yakin ingin memutuskan jaringan?',
|
||||
failed: 'Koneksi gagal, coba lagi.',
|
||||
ssid: 'Nama',
|
||||
password: 'Kata sandi',
|
||||
joinBtn: 'Gabung',
|
||||
confirmBtn: 'OK',
|
||||
cancelBtn: 'Batal'
|
||||
},
|
||||
tls: {
|
||||
description: 'Aktifkan protokol HTTPS',
|
||||
tip: 'Perhatian: Menggunakan HTTPS dapat meningkatkan latensi, terutama pada mode video MJPEG.'
|
||||
},
|
||||
dns: {
|
||||
title: 'DNS',
|
||||
description: 'Konfigurasi server DNS untuk NanoKVM',
|
||||
mode: 'Mode',
|
||||
dhcp: 'DHCP',
|
||||
manual: 'Manual',
|
||||
add: 'Tambah DNS',
|
||||
save: 'Simpan',
|
||||
invalid: 'Masukkan alamat IP yang valid',
|
||||
noDhcp: 'DNS DHCP saat ini tidak tersedia',
|
||||
saved: 'Pengaturan DNS disimpan',
|
||||
saveFailed: 'Gagal menyimpan pengaturan DNS',
|
||||
unsaved: 'Perubahan belum disimpan',
|
||||
maxServers: 'Maksimal {{count}} server DNS diizinkan',
|
||||
dnsServers: 'Server DNS',
|
||||
dhcpServersDescription: 'Server DNS diperoleh otomatis dari DHCP.',
|
||||
manualServersDescription: 'Server DNS dapat diedit secara manual.',
|
||||
networkDetails: 'Detail Jaringan',
|
||||
interface: 'Antarmuka',
|
||||
ipAddress: 'Alamat IP',
|
||||
subnetMask: 'Subnet Mask',
|
||||
router: 'Router',
|
||||
none: 'Tidak ada'
|
||||
}
|
||||
},
|
||||
tailscale: {
|
||||
title: 'Tailscale',
|
||||
memory: {
|
||||
|
||||
@@ -183,16 +183,57 @@ const it = {
|
||||
1800: '30 min',
|
||||
3600: '1 hour'
|
||||
},
|
||||
wifi: {
|
||||
title: 'Wi-Fi',
|
||||
description: 'Configure Wi-Fi',
|
||||
setBtn: 'Config'
|
||||
},
|
||||
disk: 'Virtual Disk',
|
||||
diskDesc: 'Mount virtual U-disk on the remote host',
|
||||
network: 'Virtual Network',
|
||||
networkDesc: 'Mount virtual network card on the remote host'
|
||||
},
|
||||
network: {
|
||||
title: 'Rete',
|
||||
wifi: {
|
||||
title: 'Wi-Fi',
|
||||
description: 'Configura Wi-Fi',
|
||||
apMode: 'La modalità AP è attiva, connettiti al Wi-Fi scansionando il codice QR',
|
||||
connect: 'Connetti Wi-Fi',
|
||||
connectDesc1: 'Inserisci SSID e password della rete',
|
||||
connectDesc2: 'Inserisci la password per unirti a questa rete',
|
||||
disconnect: 'Vuoi davvero disconnettere la rete?',
|
||||
failed: 'Connessione non riuscita, riprova.',
|
||||
ssid: 'Nome',
|
||||
password: 'Password',
|
||||
joinBtn: 'Connetti',
|
||||
confirmBtn: 'OK',
|
||||
cancelBtn: 'Annulla'
|
||||
},
|
||||
tls: {
|
||||
description: 'Abilita protocollo HTTPS',
|
||||
tip: 'Attenzione: l\'uso di HTTPS può aumentare la latenza, soprattutto in modalità video MJPEG.'
|
||||
},
|
||||
dns: {
|
||||
title: 'DNS',
|
||||
description: 'Configura i server DNS per NanoKVM',
|
||||
mode: 'Modalità',
|
||||
dhcp: 'DHCP',
|
||||
manual: 'Manuale',
|
||||
add: 'Aggiungi DNS',
|
||||
save: 'Salva',
|
||||
invalid: 'Inserisci un indirizzo IP valido',
|
||||
noDhcp: 'Nessun DNS DHCP è attualmente disponibile',
|
||||
saved: 'Impostazioni DNS salvate',
|
||||
saveFailed: 'Impossibile salvare le impostazioni DNS',
|
||||
unsaved: 'Modifiche non salvate',
|
||||
maxServers: 'Sono consentiti al massimo {{count}} server DNS',
|
||||
dnsServers: 'Server DNS',
|
||||
dhcpServersDescription: 'I server DNS vengono ottenuti automaticamente da DHCP.',
|
||||
manualServersDescription: 'I server DNS possono essere modificati manualmente.',
|
||||
networkDetails: 'Dettagli rete',
|
||||
interface: 'Interfaccia',
|
||||
ipAddress: 'Indirizzo IP',
|
||||
subnetMask: 'Subnet mask',
|
||||
router: 'Router',
|
||||
none: 'Nessuno'
|
||||
}
|
||||
},
|
||||
tailscale: {
|
||||
title: 'Tailscale',
|
||||
memory: {
|
||||
|
||||
@@ -267,29 +267,10 @@ const ja = {
|
||||
1800: '30分',
|
||||
3600: '1時間'
|
||||
},
|
||||
wifi: {
|
||||
title: 'Wi-Fi',
|
||||
description: 'Wi-Fi 設定',
|
||||
apMode: 'AP モードが有効になりました。QR コードをスキャンして Wi-Fi に接続してください。',
|
||||
connect: 'Wi-Fi に接続',
|
||||
connectDesc1: 'SSID とパスワードを入力してください',
|
||||
connectDesc2: 'このネットワークに接続するためのパスワードを入力してください',
|
||||
disconnect: 'このネットワーク接続を切断しますか?',
|
||||
failed: '接続に失敗しました。もう一度お試しください。',
|
||||
ssid: 'SSID',
|
||||
password: 'パスワード',
|
||||
joinBtn: '接続',
|
||||
confirmBtn: 'OK',
|
||||
cancelBtn: 'キャンセル'
|
||||
},
|
||||
ssh: {
|
||||
description: 'SSH リモートアクセスを有効にする',
|
||||
tip: '使用する前に必ず強力なパスワードを設定してください(アカウント - パスワードの変更)'
|
||||
},
|
||||
tls: {
|
||||
description: 'HTTPS プロトコルを有効にする',
|
||||
tip: '注意:HTTPS を使用すると、特に MJPEG ビデオモードで遅延が増加する可能性があります。'
|
||||
},
|
||||
advanced: '詳細設定',
|
||||
swap: {
|
||||
disable: '無効',
|
||||
@@ -330,6 +311,52 @@ const ja = {
|
||||
okBtn: 'はい',
|
||||
cancelBtn: 'いいえ'
|
||||
},
|
||||
network: {
|
||||
title: 'ネットワーク',
|
||||
wifi: {
|
||||
title: 'Wi-Fi',
|
||||
description: 'Wi-Fi 設定',
|
||||
apMode: 'AP モードが有効になりました。QR コードをスキャンして Wi-Fi に接続してください。',
|
||||
connect: 'Wi-Fi に接続',
|
||||
connectDesc1: 'SSID とパスワードを入力してください',
|
||||
connectDesc2: 'このネットワークに接続するためのパスワードを入力してください',
|
||||
disconnect: 'このネットワーク接続を切断しますか?',
|
||||
failed: '接続に失敗しました。もう一度お試しください。',
|
||||
ssid: 'SSID',
|
||||
password: 'パスワード',
|
||||
joinBtn: '接続',
|
||||
confirmBtn: 'OK',
|
||||
cancelBtn: 'キャンセル'
|
||||
},
|
||||
tls: {
|
||||
description: 'HTTPS プロトコルを有効にする',
|
||||
tip: '注意:HTTPS を使用すると、特に MJPEG ビデオモードで遅延が増加する可能性があります。'
|
||||
},
|
||||
dns: {
|
||||
title: 'DNS',
|
||||
description: 'NanoKVM の DNS サーバーを設定',
|
||||
mode: 'モード',
|
||||
dhcp: 'DHCP',
|
||||
manual: '手動',
|
||||
add: 'DNS を追加',
|
||||
save: '保存',
|
||||
invalid: '有効な IP アドレスを入力してください',
|
||||
noDhcp: '現在 DHCP DNS は利用できません',
|
||||
saved: 'DNS 設定を保存しました',
|
||||
saveFailed: 'DNS 設定の保存に失敗しました',
|
||||
unsaved: '未保存の変更',
|
||||
maxServers: 'DNS サーバーは最大 {{count}} 個までです',
|
||||
dnsServers: 'DNS サーバー',
|
||||
dhcpServersDescription: 'DNS サーバーは DHCP から自動取得されます。',
|
||||
manualServersDescription: 'DNS サーバーは手動で編集できます。',
|
||||
networkDetails: 'ネットワーク詳細',
|
||||
interface: 'インターフェイス',
|
||||
ipAddress: 'IP アドレス',
|
||||
subnetMask: 'サブネットマスク',
|
||||
router: 'ルーター',
|
||||
none: 'なし'
|
||||
}
|
||||
},
|
||||
tailscale: {
|
||||
title: 'Tailscale',
|
||||
memory: {
|
||||
|
||||
@@ -246,19 +246,10 @@ const ko = {
|
||||
1800: '30분',
|
||||
3600: '1시간'
|
||||
},
|
||||
wifi: {
|
||||
title: 'Wi-Fi',
|
||||
description: 'Wi-Fi 설정',
|
||||
setBtn: '설정'
|
||||
},
|
||||
ssh: {
|
||||
description: 'SSH 원격 접속 활성화',
|
||||
tip: '활성화하기 전에 강력한 비밀번호를 설정하세요. (계정 - 비밀번호 변경)'
|
||||
},
|
||||
tls: {
|
||||
description: 'HTTPS 프로토콜 활성화',
|
||||
tip: '주의: HTTPS 사용 시 특히 MJPEG 비디오 모드에서 지연 시간이 증가할 수 있습니다.'
|
||||
},
|
||||
advanced: '고급 설정',
|
||||
swap: {
|
||||
title: '스왑',
|
||||
@@ -290,6 +281,52 @@ const ko = {
|
||||
okBtn: '네',
|
||||
cancelBtn: '아니오'
|
||||
},
|
||||
network: {
|
||||
title: '네트워크',
|
||||
wifi: {
|
||||
title: 'Wi-Fi',
|
||||
description: 'Wi-Fi 설정',
|
||||
apMode: 'AP 모드가 활성화되었습니다. QR 코드를 스캔하여 Wi-Fi에 연결하세요',
|
||||
connect: 'Wi-Fi 연결',
|
||||
connectDesc1: '네트워크 SSID와 비밀번호를 입력하세요',
|
||||
connectDesc2: '이 네트워크에 연결할 비밀번호를 입력하세요',
|
||||
disconnect: '네트워크 연결을 끊으시겠습니까?',
|
||||
failed: '연결에 실패했습니다. 다시 시도하세요.',
|
||||
ssid: '이름',
|
||||
password: '비밀번호',
|
||||
joinBtn: '연결',
|
||||
confirmBtn: '확인',
|
||||
cancelBtn: '취소'
|
||||
},
|
||||
tls: {
|
||||
description: 'HTTPS 프로토콜 활성화',
|
||||
tip: '주의: HTTPS 사용 시 특히 MJPEG 비디오 모드에서 지연 시간이 증가할 수 있습니다.'
|
||||
},
|
||||
dns: {
|
||||
title: 'DNS',
|
||||
description: 'NanoKVM의 DNS 서버 설정',
|
||||
mode: '모드',
|
||||
dhcp: 'DHCP',
|
||||
manual: '수동',
|
||||
add: 'DNS 추가',
|
||||
save: '저장',
|
||||
invalid: '유효한 IP 주소를 입력하세요',
|
||||
noDhcp: '현재 사용 가능한 DHCP DNS가 없습니다',
|
||||
saved: 'DNS 설정이 저장되었습니다',
|
||||
saveFailed: 'DNS 설정 저장 실패',
|
||||
unsaved: '저장되지 않은 변경사항',
|
||||
maxServers: '최대 {{count}}개의 DNS 서버가 허용됩니다',
|
||||
dnsServers: 'DNS 서버',
|
||||
dhcpServersDescription: 'DNS 서버는 DHCP에서 자동으로 가져옵니다.',
|
||||
manualServersDescription: 'DNS 서버를 수동으로 편집할 수 있습니다.',
|
||||
networkDetails: '네트워크 세부 정보',
|
||||
interface: '인터페이스',
|
||||
ipAddress: 'IP 주소',
|
||||
subnetMask: '서브넷 마스크',
|
||||
router: '라우터',
|
||||
none: '없음'
|
||||
}
|
||||
},
|
||||
tailscale: {
|
||||
title: 'Tailscale',
|
||||
memory: {
|
||||
|
||||
@@ -182,16 +182,57 @@ const nb = {
|
||||
1800: '30 min',
|
||||
3600: '1 hour'
|
||||
},
|
||||
wifi: {
|
||||
title: 'Wi-Fi',
|
||||
description: 'Configure Wi-Fi',
|
||||
setBtn: 'Config'
|
||||
},
|
||||
disk: 'Virtual Disk',
|
||||
diskDesc: 'Mount virtual U-disk on the remote host',
|
||||
network: 'Virtual Network',
|
||||
networkDesc: 'Mount virtual network card on the remote host'
|
||||
},
|
||||
network: {
|
||||
title: 'Nettverk',
|
||||
wifi: {
|
||||
title: 'Wi-Fi',
|
||||
description: 'Konfigurer Wi-Fi',
|
||||
apMode: 'AP-modus er aktivert, koble til Wi-Fi ved å skanne QR-koden',
|
||||
connect: 'Koble til Wi-Fi',
|
||||
connectDesc1: 'Skriv inn nettverkets SSID og passord',
|
||||
connectDesc2: 'Skriv inn passordet for å koble til dette nettverket',
|
||||
disconnect: 'Er du sikker på at du vil koble fra nettverket?',
|
||||
failed: 'Tilkobling mislyktes, prøv igjen.',
|
||||
ssid: 'Navn',
|
||||
password: 'Passord',
|
||||
joinBtn: 'Koble til',
|
||||
confirmBtn: 'OK',
|
||||
cancelBtn: 'Avbryt'
|
||||
},
|
||||
tls: {
|
||||
description: 'Aktiver HTTPS-protokoll',
|
||||
tip: 'Merk: Bruk av HTTPS kan øke forsinkelsen, spesielt i MJPEG-videomodus.'
|
||||
},
|
||||
dns: {
|
||||
title: 'DNS',
|
||||
description: 'Konfigurer DNS-servere for NanoKVM',
|
||||
mode: 'Modus',
|
||||
dhcp: 'DHCP',
|
||||
manual: 'Manuell',
|
||||
add: 'Legg til DNS',
|
||||
save: 'Lagre',
|
||||
invalid: 'Skriv inn en gyldig IP-adresse',
|
||||
noDhcp: 'Ingen DHCP-DNS er tilgjengelig nå',
|
||||
saved: 'DNS-innstillinger lagret',
|
||||
saveFailed: 'Kunne ikke lagre DNS-innstillinger',
|
||||
unsaved: 'Ulagrede endringer',
|
||||
maxServers: 'Maksimalt {{count}} DNS-servere er tillatt',
|
||||
dnsServers: 'DNS-servere',
|
||||
dhcpServersDescription: 'DNS-servere hentes automatisk fra DHCP.',
|
||||
manualServersDescription: 'DNS-servere kan redigeres manuelt.',
|
||||
networkDetails: 'Nettverksdetaljer',
|
||||
interface: 'Grensesnitt',
|
||||
ipAddress: 'IP-adresse',
|
||||
subnetMask: 'Subnettmaske',
|
||||
router: 'Ruter',
|
||||
none: 'Ingen'
|
||||
}
|
||||
},
|
||||
tailscale: {
|
||||
title: 'Tailscale',
|
||||
memory: {
|
||||
|
||||
@@ -182,16 +182,57 @@ const nl = {
|
||||
1800: '30 min',
|
||||
3600: '1 uur'
|
||||
},
|
||||
wifi: {
|
||||
title: 'Wifi',
|
||||
description: 'Configureer wifi',
|
||||
setBtn: 'Config'
|
||||
},
|
||||
disk: 'Virtuele schijf',
|
||||
diskDesc: 'Koppel virtuele U-schijf aan de externe host',
|
||||
network: 'Virtueel Netwerk',
|
||||
networkDesc: 'Koppel virtueel netwerk kaart aan de externe host'
|
||||
},
|
||||
network: {
|
||||
title: 'Netwerk',
|
||||
wifi: {
|
||||
title: 'Wifi',
|
||||
description: 'Configureer wifi',
|
||||
apMode: 'AP-modus is ingeschakeld, maak verbinding met wifi door de QR-code te scannen',
|
||||
connect: 'Wifi verbinden',
|
||||
connectDesc1: 'Voer de netwerk-SSID en het wachtwoord in',
|
||||
connectDesc2: 'Voer het wachtwoord in om met dit netwerk te verbinden',
|
||||
disconnect: 'Weet je zeker dat je de netwerkverbinding wilt verbreken?',
|
||||
failed: 'Verbinding mislukt, probeer het opnieuw.',
|
||||
ssid: 'Naam',
|
||||
password: 'Wachtwoord',
|
||||
joinBtn: 'Verbinden',
|
||||
confirmBtn: 'OK',
|
||||
cancelBtn: 'Annuleren'
|
||||
},
|
||||
tls: {
|
||||
description: 'HTTPS-protocol inschakelen',
|
||||
tip: 'Let op: HTTPS gebruiken kan de latentie verhogen, vooral in MJPEG-videomodus.'
|
||||
},
|
||||
dns: {
|
||||
title: 'DNS',
|
||||
description: 'Configureer DNS-servers voor NanoKVM',
|
||||
mode: 'Modus',
|
||||
dhcp: 'DHCP',
|
||||
manual: 'Handmatig',
|
||||
add: 'DNS toevoegen',
|
||||
save: 'Opslaan',
|
||||
invalid: 'Voer een geldig IP-adres in',
|
||||
noDhcp: 'Er is momenteel geen DHCP-DNS beschikbaar',
|
||||
saved: 'DNS-instellingen opgeslagen',
|
||||
saveFailed: 'DNS-instellingen opslaan mislukt',
|
||||
unsaved: 'Niet-opgeslagen wijzigingen',
|
||||
maxServers: 'Maximaal {{count}} DNS-servers toegestaan',
|
||||
dnsServers: 'DNS-servers',
|
||||
dhcpServersDescription: 'DNS-servers worden automatisch via DHCP verkregen.',
|
||||
manualServersDescription: 'DNS-servers kunnen handmatig worden bewerkt.',
|
||||
networkDetails: 'Netwerkdetails',
|
||||
interface: 'Interface',
|
||||
ipAddress: 'IP-adres',
|
||||
subnetMask: 'Subnetmasker',
|
||||
router: 'Router',
|
||||
none: 'Geen'
|
||||
}
|
||||
},
|
||||
tailscale: {
|
||||
title: 'Tailscale',
|
||||
memory: {
|
||||
|
||||
@@ -184,16 +184,57 @@ const pl = {
|
||||
1800: '30 min',
|
||||
3600: '1 hour'
|
||||
},
|
||||
wifi: {
|
||||
title: 'Wi-Fi',
|
||||
description: 'Configure Wi-Fi',
|
||||
setBtn: 'Config'
|
||||
},
|
||||
disk: 'Virtual Disk',
|
||||
diskDesc: 'Mount virtual U-disk on the remote host',
|
||||
network: 'Virtual Network',
|
||||
networkDesc: 'Mount virtual network card on the remote host'
|
||||
},
|
||||
network: {
|
||||
title: 'Sieć',
|
||||
wifi: {
|
||||
title: 'Wi-Fi',
|
||||
description: 'Skonfiguruj Wi-Fi',
|
||||
apMode: 'Tryb AP jest włączony, połącz z Wi-Fi skanując kod QR',
|
||||
connect: 'Połącz Wi-Fi',
|
||||
connectDesc1: 'Wprowadź SSID sieci i hasło',
|
||||
connectDesc2: 'Wprowadź hasło, aby połączyć się z tą siecią',
|
||||
disconnect: 'Czy na pewno chcesz rozłączyć sieć?',
|
||||
failed: 'Połączenie nie powiodło się, spróbuj ponownie.',
|
||||
ssid: 'Nazwa',
|
||||
password: 'Hasło',
|
||||
joinBtn: 'Połącz',
|
||||
confirmBtn: 'OK',
|
||||
cancelBtn: 'Anuluj'
|
||||
},
|
||||
tls: {
|
||||
description: 'Włącz protokół HTTPS',
|
||||
tip: 'Uwaga: użycie HTTPS może zwiększyć opóźnienie, szczególnie w trybie wideo MJPEG.'
|
||||
},
|
||||
dns: {
|
||||
title: 'DNS',
|
||||
description: 'Skonfiguruj serwery DNS dla NanoKVM',
|
||||
mode: 'Tryb',
|
||||
dhcp: 'DHCP',
|
||||
manual: 'Ręcznie',
|
||||
add: 'Dodaj DNS',
|
||||
save: 'Zapisz',
|
||||
invalid: 'Wprowadź prawidłowy adres IP',
|
||||
noDhcp: 'Brak obecnie dostępnego DNS z DHCP',
|
||||
saved: 'Ustawienia DNS zapisane',
|
||||
saveFailed: 'Nie udało się zapisać ustawień DNS',
|
||||
unsaved: 'Niezapisane zmiany',
|
||||
maxServers: 'Dozwolone jest maksymalnie {{count}} serwerów DNS',
|
||||
dnsServers: 'Serwery DNS',
|
||||
dhcpServersDescription: 'Serwery DNS są automatycznie pobierane z DHCP.',
|
||||
manualServersDescription: 'Serwery DNS można edytować ręcznie.',
|
||||
networkDetails: 'Szczegóły sieci',
|
||||
interface: 'Interfejs',
|
||||
ipAddress: 'Adres IP',
|
||||
subnetMask: 'Maska podsieci',
|
||||
router: 'Router',
|
||||
none: 'Brak'
|
||||
}
|
||||
},
|
||||
tailscale: {
|
||||
title: 'Tailscale',
|
||||
memory: {
|
||||
|
||||
@@ -226,19 +226,10 @@ const pt_br = {
|
||||
1800: '30 min',
|
||||
3600: '1 hora'
|
||||
},
|
||||
wifi: {
|
||||
title: 'Wi-Fi',
|
||||
description: 'Configurar Wi-Fi',
|
||||
setBtn: 'Configurar'
|
||||
},
|
||||
ssh: {
|
||||
description: 'Habilitar acesso remoto SSH',
|
||||
tip: 'Defina uma senha forte antes de habilitar (Conta - Mudar Senha)'
|
||||
},
|
||||
tls: {
|
||||
description: 'Habilitar protocolo HTTPS',
|
||||
tip: 'Atenção: O uso de HTTPS pode aumentar a latência, especialmente com o modo de vídeo MJPEG.'
|
||||
},
|
||||
advanced: 'Configurações Avançadas',
|
||||
swap: {
|
||||
title: 'Swap',
|
||||
@@ -270,6 +261,52 @@ const pt_br = {
|
||||
okBtn: 'Sim',
|
||||
cancelBtn: 'Não'
|
||||
},
|
||||
network: {
|
||||
title: 'Rede',
|
||||
wifi: {
|
||||
title: 'Wi-Fi',
|
||||
description: 'Configurar Wi-Fi',
|
||||
apMode: 'O modo AP está ativado, conecte-se ao Wi-Fi escaneando o QR code',
|
||||
connect: 'Conectar Wi-Fi',
|
||||
connectDesc1: 'Digite o SSID da rede e a senha',
|
||||
connectDesc2: 'Digite a senha para entrar nesta rede',
|
||||
disconnect: 'Tem certeza de que deseja desconectar a rede?',
|
||||
failed: 'Falha na conexão, tente novamente.',
|
||||
ssid: 'Nome',
|
||||
password: 'Senha',
|
||||
joinBtn: 'Entrar',
|
||||
confirmBtn: 'OK',
|
||||
cancelBtn: 'Cancelar'
|
||||
},
|
||||
tls: {
|
||||
description: 'Habilitar protocolo HTTPS',
|
||||
tip: 'Atenção: O uso de HTTPS pode aumentar a latência, especialmente com o modo de vídeo MJPEG.'
|
||||
},
|
||||
dns: {
|
||||
title: 'DNS',
|
||||
description: 'Configurar servidores DNS para o NanoKVM',
|
||||
mode: 'Modo',
|
||||
dhcp: 'DHCP',
|
||||
manual: 'Manual',
|
||||
add: 'Adicionar DNS',
|
||||
save: 'Salvar',
|
||||
invalid: 'Digite um endereço IP válido',
|
||||
noDhcp: 'Nenhum DNS DHCP está disponível no momento',
|
||||
saved: 'Configurações de DNS salvas',
|
||||
saveFailed: 'Falha ao salvar as configurações de DNS',
|
||||
unsaved: 'Alterações não salvas',
|
||||
maxServers: 'Máximo de {{count}} servidores DNS permitido',
|
||||
dnsServers: 'Servidores DNS',
|
||||
dhcpServersDescription: 'Os servidores DNS são obtidos automaticamente via DHCP.',
|
||||
manualServersDescription: 'Os servidores DNS podem ser editados manualmente.',
|
||||
networkDetails: 'Detalhes da rede',
|
||||
interface: 'Interface',
|
||||
ipAddress: 'Endereço IP',
|
||||
subnetMask: 'Máscara de sub-rede',
|
||||
router: 'Roteador',
|
||||
none: 'Nenhum'
|
||||
}
|
||||
},
|
||||
tailscale: {
|
||||
title: 'Tailscale',
|
||||
memory: {
|
||||
|
||||
@@ -231,19 +231,10 @@ const ru = {
|
||||
1800: '30 мин',
|
||||
3600: '1 час'
|
||||
},
|
||||
wifi: {
|
||||
title: 'Wi-Fi',
|
||||
description: 'Настройка Wi-Fi',
|
||||
setBtn: 'Конфигурация'
|
||||
},
|
||||
ssh: {
|
||||
description: 'Включить удаленный доступ по SSH',
|
||||
tip: 'Задайте сильный пароль перед включением (Аккаунт - Пароль - Обновить)'
|
||||
},
|
||||
tls: {
|
||||
description: 'Включить HTTPS Protocol',
|
||||
tip: 'Имейте в виду: использование HTTPS может увеличить задержку, особенно в режиме видео MJPEG.'
|
||||
},
|
||||
advanced: 'Дополнительные настройки',
|
||||
swap: {
|
||||
title: 'Файл подкачки',
|
||||
@@ -272,6 +263,52 @@ const ru = {
|
||||
okBtn: 'Да',
|
||||
cancelBtn: 'Нет'
|
||||
},
|
||||
network: {
|
||||
title: 'Сеть',
|
||||
wifi: {
|
||||
title: 'Wi-Fi',
|
||||
description: 'Настройка Wi-Fi',
|
||||
apMode: 'Режим AP включен, подключитесь к Wi-Fi, отсканировав QR-код',
|
||||
connect: 'Подключить Wi-Fi',
|
||||
connectDesc1: 'Введите SSID сети и пароль',
|
||||
connectDesc2: 'Введите пароль для подключения к этой сети',
|
||||
disconnect: 'Вы уверены, что хотите отключить сеть?',
|
||||
failed: 'Не удалось подключиться, попробуйте снова.',
|
||||
ssid: 'Имя',
|
||||
password: 'Пароль',
|
||||
joinBtn: 'Подключить',
|
||||
confirmBtn: 'OK',
|
||||
cancelBtn: 'Отмена'
|
||||
},
|
||||
tls: {
|
||||
description: 'Включить протокол HTTPS',
|
||||
tip: 'Имейте в виду: использование HTTPS может увеличить задержку, особенно в режиме видео MJPEG.'
|
||||
},
|
||||
dns: {
|
||||
title: 'DNS',
|
||||
description: 'Настройка DNS-серверов для NanoKVM',
|
||||
mode: 'Режим',
|
||||
dhcp: 'DHCP',
|
||||
manual: 'Вручную',
|
||||
add: 'Добавить DNS',
|
||||
save: 'Сохранить',
|
||||
invalid: 'Введите допустимый IP-адрес',
|
||||
noDhcp: 'DNS от DHCP сейчас недоступен',
|
||||
saved: 'Настройки DNS сохранены',
|
||||
saveFailed: 'Не удалось сохранить настройки DNS',
|
||||
unsaved: 'Несохраненные изменения',
|
||||
maxServers: 'Разрешено не более {{count}} DNS-серверов',
|
||||
dnsServers: 'DNS-серверы',
|
||||
dhcpServersDescription: 'DNS-серверы автоматически получаются от DHCP.',
|
||||
manualServersDescription: 'DNS-серверы можно редактировать вручную.',
|
||||
networkDetails: 'Сведения о сети',
|
||||
interface: 'Интерфейс',
|
||||
ipAddress: 'IP-адрес',
|
||||
subnetMask: 'Маска подсети',
|
||||
router: 'Маршрутизатор',
|
||||
none: 'Нет'
|
||||
}
|
||||
},
|
||||
tailscale: {
|
||||
title: 'Tailscale',
|
||||
memory: {
|
||||
|
||||
@@ -242,19 +242,10 @@ const se = {
|
||||
1800: '30 min',
|
||||
3600: '1 timme'
|
||||
},
|
||||
wifi: {
|
||||
title: 'Wi-Fi',
|
||||
description: 'Konfigurera Wi-Fi',
|
||||
setBtn: 'Konfigurera'
|
||||
},
|
||||
ssh: {
|
||||
description: 'Aktivera SSH-fjärråtkomst',
|
||||
tip: 'Ställ in ett starkt lösenord innan du aktiverar (Konto - Byt lösenord)'
|
||||
},
|
||||
tls: {
|
||||
description: 'Aktivera HTTPS-protokoll',
|
||||
tip: 'Observera: Användning av HTTPS kan öka fördröjningen, särskilt med MJPEG-läge.'
|
||||
},
|
||||
advanced: 'Avancerade inställningar',
|
||||
swap: {
|
||||
title: 'Swap',
|
||||
@@ -286,6 +277,52 @@ const se = {
|
||||
okBtn: 'Ja',
|
||||
cancelBtn: 'Nej'
|
||||
},
|
||||
network: {
|
||||
title: 'Nätverk',
|
||||
wifi: {
|
||||
title: 'Wi-Fi',
|
||||
description: 'Konfigurera Wi-Fi',
|
||||
apMode: 'AP-läge är aktiverat, anslut till Wi-Fi genom att skanna QR-koden',
|
||||
connect: 'Anslut Wi-Fi',
|
||||
connectDesc1: 'Ange nätverkets SSID och lösenord',
|
||||
connectDesc2: 'Ange lösenordet för att ansluta till detta nätverk',
|
||||
disconnect: 'Är du säker på att du vill koppla från nätverket?',
|
||||
failed: 'Anslutningen misslyckades, försök igen.',
|
||||
ssid: 'Namn',
|
||||
password: 'Lösenord',
|
||||
joinBtn: 'Anslut',
|
||||
confirmBtn: 'OK',
|
||||
cancelBtn: 'Avbryt'
|
||||
},
|
||||
tls: {
|
||||
description: 'Aktivera HTTPS-protokoll',
|
||||
tip: 'Observera: Användning av HTTPS kan öka fördröjningen, särskilt med MJPEG-läge.'
|
||||
},
|
||||
dns: {
|
||||
title: 'DNS',
|
||||
description: 'Konfigurera DNS-servrar för NanoKVM',
|
||||
mode: 'Läge',
|
||||
dhcp: 'DHCP',
|
||||
manual: 'Manuell',
|
||||
add: 'Lägg till DNS',
|
||||
save: 'Spara',
|
||||
invalid: 'Ange en giltig IP-adress',
|
||||
noDhcp: 'Ingen DHCP-DNS är tillgänglig just nu',
|
||||
saved: 'DNS-inställningar sparade',
|
||||
saveFailed: 'Det gick inte att spara DNS-inställningar',
|
||||
unsaved: 'Osparade ändringar',
|
||||
maxServers: 'Maximalt {{count}} DNS-servrar tillåtna',
|
||||
dnsServers: 'DNS-servrar',
|
||||
dhcpServersDescription: 'DNS-servrar hämtas automatiskt från DHCP.',
|
||||
manualServersDescription: 'DNS-servrar kan redigeras manuellt.',
|
||||
networkDetails: 'Nätverksdetaljer',
|
||||
interface: 'Gränssnitt',
|
||||
ipAddress: 'IP-adress',
|
||||
subnetMask: 'Subnätmask',
|
||||
router: 'Router',
|
||||
none: 'Ingen'
|
||||
}
|
||||
},
|
||||
tailscale: {
|
||||
title: 'Tailscale',
|
||||
memory: {
|
||||
|
||||
@@ -205,11 +205,6 @@ const th = {
|
||||
1800: '30 นาที',
|
||||
3600: '1 ชั่วโมง'
|
||||
},
|
||||
wifi: {
|
||||
title: 'Wi-Fi',
|
||||
description: 'ตั้งค่า Wi-Fi',
|
||||
setBtn: 'ยืนยัน'
|
||||
},
|
||||
ssh: {
|
||||
description: 'เปิดใช้งาน SSH',
|
||||
tip: 'ตั้งรหัสผ่านทีปลอดถัยก่อนเปิดใช้งาน (บัญชี - เปลี่ยนรหัสผ่าน)'
|
||||
@@ -219,6 +214,52 @@ const th = {
|
||||
network: 'เครือข่ายจำลอง',
|
||||
networkDesc: 'เปิดใช้งานอุปกรณ์เครือข่ายจำลอง'
|
||||
},
|
||||
network: {
|
||||
title: 'เครือข่าย',
|
||||
wifi: {
|
||||
title: 'Wi-Fi',
|
||||
description: 'ตั้งค่า Wi-Fi',
|
||||
apMode: 'เปิดใช้งานโหมด AP แล้ว ให้เชื่อมต่อ Wi-Fi โดยสแกนรหัส QR',
|
||||
connect: 'เชื่อมต่อ Wi-Fi',
|
||||
connectDesc1: 'กรุณาใส่ SSID และรหัสผ่านของเครือข่าย',
|
||||
connectDesc2: 'กรุณาใส่รหัสผ่านเพื่อเข้าร่วมเครือข่ายนี้',
|
||||
disconnect: 'คุณแน่ใจหรือไม่ว่าต้องการตัดการเชื่อมต่อเครือข่าย?',
|
||||
failed: 'เชื่อมต่อไม่สำเร็จ กรุณาลองอีกครั้ง',
|
||||
ssid: 'ชื่อ',
|
||||
password: 'รหัสผ่าน',
|
||||
joinBtn: 'เข้าร่วม',
|
||||
confirmBtn: 'ตกลง',
|
||||
cancelBtn: 'ยกเลิก'
|
||||
},
|
||||
tls: {
|
||||
description: 'เปิดใช้งานโปรโตคอล HTTPS',
|
||||
tip: 'โปรดทราบ: การใช้ HTTPS อาจเพิ่มความหน่วง โดยเฉพาะในโหมดวิดีโอ MJPEG'
|
||||
},
|
||||
dns: {
|
||||
title: 'DNS',
|
||||
description: 'ตั้งค่าเซิร์ฟเวอร์ DNS สำหรับ NanoKVM',
|
||||
mode: 'โหมด',
|
||||
dhcp: 'DHCP',
|
||||
manual: 'กำหนดเอง',
|
||||
add: 'เพิ่ม DNS',
|
||||
save: 'บันทึก',
|
||||
invalid: 'กรุณาใส่ที่อยู่ IP ที่ถูกต้อง',
|
||||
noDhcp: 'ขณะนี้ไม่มี DHCP DNS ให้ใช้งาน',
|
||||
saved: 'บันทึกการตั้งค่า DNS แล้ว',
|
||||
saveFailed: 'บันทึกการตั้งค่า DNS ไม่สำเร็จ',
|
||||
unsaved: 'มีการเปลี่ยนแปลงที่ยังไม่ได้บันทึก',
|
||||
maxServers: 'อนุญาตเซิร์ฟเวอร์ DNS ได้สูงสุด {{count}} รายการ',
|
||||
dnsServers: 'เซิร์ฟเวอร์ DNS',
|
||||
dhcpServersDescription: 'เซิร์ฟเวอร์ DNS จะได้รับจาก DHCP โดยอัตโนมัติ',
|
||||
manualServersDescription: 'สามารถแก้ไขเซิร์ฟเวอร์ DNS ได้ด้วยตนเอง',
|
||||
networkDetails: 'รายละเอียดเครือข่าย',
|
||||
interface: 'อินเทอร์เฟซ',
|
||||
ipAddress: 'ที่อยู่ IP',
|
||||
subnetMask: 'Subnet Mask',
|
||||
router: 'เราเตอร์',
|
||||
none: 'ไม่มี'
|
||||
}
|
||||
},
|
||||
tailscale: {
|
||||
title: 'Tailscale',
|
||||
memory: {
|
||||
|
||||
@@ -230,19 +230,10 @@ const tr = {
|
||||
1800: '30 dakika',
|
||||
3600: '1 saat'
|
||||
},
|
||||
wifi: {
|
||||
title: 'Wi-Fi',
|
||||
description: 'Wi-Fi ayarlayın',
|
||||
setBtn: 'Ayarla'
|
||||
},
|
||||
ssh: {
|
||||
description: 'Güvenli Kabuk Bağlantısı (SSH) aktif et',
|
||||
tip: 'Aktifleştirmeden önce güçlü bir şifreye sahip olduğunuzdan emin olun (Hesap - Şifremi Değiştir)'
|
||||
},
|
||||
tls: {
|
||||
description: 'HTTPS protokolünü etkinleştir',
|
||||
tip: 'HTTPS protokolü bağlantıda gecikmeye sebep olabilir, özellikle MJPEG görüntü modu ile.'
|
||||
},
|
||||
advanced: 'Gelişmiş Ayarlar',
|
||||
swap: {
|
||||
title: 'Swap',
|
||||
@@ -274,6 +265,52 @@ const tr = {
|
||||
okBtn: 'Evet',
|
||||
cancelBtn: 'Hayır'
|
||||
},
|
||||
network: {
|
||||
title: 'Ağ',
|
||||
wifi: {
|
||||
title: 'Wi-Fi',
|
||||
description: 'Wi-Fi ayarlayın',
|
||||
apMode: 'AP modu etkin, QR kodu tarayarak Wi-Fi\'ye bağlanın',
|
||||
connect: 'Wi-Fi\'ye bağlan',
|
||||
connectDesc1: 'Lütfen ağ SSID\'sini ve parolayı girin',
|
||||
connectDesc2: 'Bu ağa katılmak için parolayı girin',
|
||||
disconnect: 'Ağ bağlantısını kesmek istediğinizden emin misiniz?',
|
||||
failed: 'Bağlantı başarısız, lütfen tekrar deneyin.',
|
||||
ssid: 'Ad',
|
||||
password: 'Parola',
|
||||
joinBtn: 'Katıl',
|
||||
confirmBtn: 'Tamam',
|
||||
cancelBtn: 'İptal'
|
||||
},
|
||||
tls: {
|
||||
description: 'HTTPS protokolünü etkinleştir',
|
||||
tip: 'HTTPS protokolü bağlantıda gecikmeye sebep olabilir, özellikle MJPEG görüntü modu ile.'
|
||||
},
|
||||
dns: {
|
||||
title: 'DNS',
|
||||
description: 'NanoKVM için DNS sunucularını yapılandır',
|
||||
mode: 'Mod',
|
||||
dhcp: 'DHCP',
|
||||
manual: 'Manuel',
|
||||
add: 'DNS ekle',
|
||||
save: 'Kaydet',
|
||||
invalid: 'Geçerli bir IP adresi girin',
|
||||
noDhcp: 'Şu anda DHCP DNS mevcut değil',
|
||||
saved: 'DNS ayarları kaydedildi',
|
||||
saveFailed: 'DNS ayarları kaydedilemedi',
|
||||
unsaved: 'Kaydedilmemiş değişiklikler',
|
||||
maxServers: 'En fazla {{count}} DNS sunucusuna izin verilir',
|
||||
dnsServers: 'DNS Sunucuları',
|
||||
dhcpServersDescription: 'DNS sunucuları DHCP\'den otomatik olarak alınır.',
|
||||
manualServersDescription: 'DNS sunucuları manuel olarak düzenlenebilir.',
|
||||
networkDetails: 'Ağ Ayrıntıları',
|
||||
interface: 'Arayüz',
|
||||
ipAddress: 'IP Adresi',
|
||||
subnetMask: 'Alt Ağ Maskesi',
|
||||
router: 'Yönlendirici',
|
||||
none: 'Yok'
|
||||
}
|
||||
},
|
||||
tailscale: {
|
||||
title: 'Tailscale',
|
||||
memory: {
|
||||
|
||||
@@ -227,19 +227,10 @@ const uk = {
|
||||
1800: '30 хв',
|
||||
3600: '1 година'
|
||||
},
|
||||
wifi: {
|
||||
title: 'Wi-Fi',
|
||||
description: 'Налаштування Wi-Fi',
|
||||
setBtn: 'Конфігурація'
|
||||
},
|
||||
ssh: {
|
||||
description: 'Увімкніть віддалений доступ по SSH',
|
||||
tip: 'Перед ввімкненням встановіть надійний пароль (Обліковий запис - Зміна пароля)'
|
||||
},
|
||||
tls: {
|
||||
description: 'Увімкнути протокол HTTPS',
|
||||
tip: 'Будьте в курсі: Використання HTTPS може збільшити затримку, особливо в режимі відео MJPEG.'
|
||||
},
|
||||
advanced: 'Розширені налаштування',
|
||||
swap: {
|
||||
title: 'Swap (файл підкачки)',
|
||||
@@ -268,6 +259,52 @@ const uk = {
|
||||
okBtn: 'Так',
|
||||
cancelBtn: 'Ні'
|
||||
},
|
||||
network: {
|
||||
title: 'Мережа',
|
||||
wifi: {
|
||||
title: 'Wi-Fi',
|
||||
description: 'Налаштування Wi-Fi',
|
||||
apMode: 'Режим AP увімкнено, підключіться до Wi-Fi, відсканувавши QR-код',
|
||||
connect: 'Підключити Wi-Fi',
|
||||
connectDesc1: 'Введіть SSID мережі та пароль',
|
||||
connectDesc2: 'Введіть пароль, щоб підключитися до цієї мережі',
|
||||
disconnect: 'Ви впевнені, що хочете відключити мережу?',
|
||||
failed: 'Не вдалося підключитися, спробуйте ще раз.',
|
||||
ssid: 'Назва',
|
||||
password: 'Пароль',
|
||||
joinBtn: 'Підключити',
|
||||
confirmBtn: 'OK',
|
||||
cancelBtn: 'Скасувати'
|
||||
},
|
||||
tls: {
|
||||
description: 'Увімкнути протокол HTTPS',
|
||||
tip: 'Будьте в курсі: Використання HTTPS може збільшити затримку, особливо в режимі відео MJPEG.'
|
||||
},
|
||||
dns: {
|
||||
title: 'DNS',
|
||||
description: 'Налаштування DNS-серверів для NanoKVM',
|
||||
mode: 'Режим',
|
||||
dhcp: 'DHCP',
|
||||
manual: 'Вручну',
|
||||
add: 'Додати DNS',
|
||||
save: 'Зберегти',
|
||||
invalid: 'Введіть дійсну IP-адресу',
|
||||
noDhcp: 'Наразі DHCP DNS недоступний',
|
||||
saved: 'Налаштування DNS збережено',
|
||||
saveFailed: 'Не вдалося зберегти налаштування DNS',
|
||||
unsaved: 'Незбережені зміни',
|
||||
maxServers: 'Дозволено щонайбільше {{count}} DNS-серверів',
|
||||
dnsServers: 'DNS-сервери',
|
||||
dhcpServersDescription: 'DNS-сервери автоматично отримуються з DHCP.',
|
||||
manualServersDescription: 'DNS-сервери можна редагувати вручну.',
|
||||
networkDetails: 'Відомості про мережу',
|
||||
interface: 'Інтерфейс',
|
||||
ipAddress: 'IP-адреса',
|
||||
subnetMask: 'Маска підмережі',
|
||||
router: 'Маршрутизатор',
|
||||
none: 'Немає'
|
||||
}
|
||||
},
|
||||
tailscale: {
|
||||
title: 'Tailscale',
|
||||
memory: {
|
||||
|
||||
@@ -181,16 +181,57 @@ const vi = {
|
||||
1800: '30 min',
|
||||
3600: '1 hour'
|
||||
},
|
||||
wifi: {
|
||||
title: 'Wi-Fi',
|
||||
description: 'Configure Wi-Fi',
|
||||
setBtn: 'Config'
|
||||
},
|
||||
disk: 'Virtual Disk',
|
||||
diskDesc: 'Mount virtual U-disk on the remote host',
|
||||
network: 'Virtual Network',
|
||||
networkDesc: 'Mount virtual network card on the remote host'
|
||||
},
|
||||
network: {
|
||||
title: 'Mạng',
|
||||
wifi: {
|
||||
title: 'Wi-Fi',
|
||||
description: 'Cấu hình Wi-Fi',
|
||||
apMode: 'Chế độ AP đang bật, hãy kết nối Wi-Fi bằng cách quét mã QR',
|
||||
connect: 'Kết nối Wi-Fi',
|
||||
connectDesc1: 'Vui lòng nhập SSID mạng và mật khẩu',
|
||||
connectDesc2: 'Vui lòng nhập mật khẩu để tham gia mạng này',
|
||||
disconnect: 'Bạn có chắc muốn ngắt kết nối mạng không?',
|
||||
failed: 'Kết nối thất bại, vui lòng thử lại.',
|
||||
ssid: 'Tên',
|
||||
password: 'Mật khẩu',
|
||||
joinBtn: 'Tham gia',
|
||||
confirmBtn: 'OK',
|
||||
cancelBtn: 'Hủy'
|
||||
},
|
||||
tls: {
|
||||
description: 'Bật giao thức HTTPS',
|
||||
tip: 'Lưu ý: Sử dụng HTTPS có thể tăng độ trễ, đặc biệt trong chế độ video MJPEG.'
|
||||
},
|
||||
dns: {
|
||||
title: 'DNS',
|
||||
description: 'Cấu hình máy chủ DNS cho NanoKVM',
|
||||
mode: 'Chế độ',
|
||||
dhcp: 'DHCP',
|
||||
manual: 'Thủ công',
|
||||
add: 'Thêm DNS',
|
||||
save: 'Lưu',
|
||||
invalid: 'Vui lòng nhập địa chỉ IP hợp lệ',
|
||||
noDhcp: 'Hiện không có DNS DHCP khả dụng',
|
||||
saved: 'Đã lưu cài đặt DNS',
|
||||
saveFailed: 'Không thể lưu cài đặt DNS',
|
||||
unsaved: 'Thay đổi chưa lưu',
|
||||
maxServers: 'Cho phép tối đa {{count}} máy chủ DNS',
|
||||
dnsServers: 'Máy chủ DNS',
|
||||
dhcpServersDescription: 'Máy chủ DNS được tự động lấy từ DHCP.',
|
||||
manualServersDescription: 'Có thể chỉnh sửa máy chủ DNS thủ công.',
|
||||
networkDetails: 'Chi tiết mạng',
|
||||
interface: 'Giao diện',
|
||||
ipAddress: 'Địa chỉ IP',
|
||||
subnetMask: 'Mặt nạ mạng con',
|
||||
router: 'Bộ định tuyến',
|
||||
none: 'Không có'
|
||||
}
|
||||
},
|
||||
tailscale: {
|
||||
title: 'Tailscale',
|
||||
memory: {
|
||||
|
||||
@@ -276,29 +276,10 @@ const zh = {
|
||||
1800: '30分钟',
|
||||
3600: '1小时'
|
||||
},
|
||||
wifi: {
|
||||
title: 'Wi-Fi',
|
||||
description: '配置 Wi-Fi 信息',
|
||||
apMode: 'AP 模式已启用,该模式下仅支持扫描二维码配网',
|
||||
connect: '连接 Wi-Fi',
|
||||
connectDesc1: '请输入网络名称和密码',
|
||||
connectDesc2: '请输入密码以连接此网络',
|
||||
disconnect: '是否要断开该网络连接?',
|
||||
failed: '连接失败,请重试',
|
||||
ssid: '名称',
|
||||
password: '密码',
|
||||
joinBtn: '加入',
|
||||
confirmBtn: '确定',
|
||||
cancelBtn: '取消'
|
||||
},
|
||||
ssh: {
|
||||
description: '启用 SSH 远程访问',
|
||||
tip: '启用前请务必设置强密码(帐号 - 修改密码)'
|
||||
},
|
||||
tls: {
|
||||
description: '启用 HTTPS 协议',
|
||||
tip: '注意:使用 HTTPS 可能导致延迟增加,特别是在 MJPEG 视频模式下。'
|
||||
},
|
||||
advanced: '高级设置',
|
||||
swap: {
|
||||
disable: '禁用',
|
||||
@@ -339,6 +320,52 @@ const zh = {
|
||||
okBtn: '是',
|
||||
cancelBtn: '否'
|
||||
},
|
||||
network: {
|
||||
title: '网络',
|
||||
wifi: {
|
||||
title: 'Wi-Fi',
|
||||
description: '配置 Wi-Fi 信息',
|
||||
apMode: 'AP 模式已启用,该模式下仅支持扫描二维码配网',
|
||||
connect: '连接 Wi-Fi',
|
||||
connectDesc1: '请输入网络名称和密码',
|
||||
connectDesc2: '请输入密码以连接此网络',
|
||||
disconnect: '是否要断开该网络连接?',
|
||||
failed: '连接失败,请重试',
|
||||
ssid: '名称',
|
||||
password: '密码',
|
||||
joinBtn: '加入',
|
||||
confirmBtn: '确定',
|
||||
cancelBtn: '取消'
|
||||
},
|
||||
tls: {
|
||||
description: '启用 HTTPS 协议',
|
||||
tip: '注意:使用 HTTPS 可能导致延迟增加,特别是在 MJPEG 视频模式下。'
|
||||
},
|
||||
dns: {
|
||||
title: 'DNS',
|
||||
description: '配置 NanoKVM 使用的 DNS 服务器',
|
||||
mode: '模式',
|
||||
dhcp: 'DHCP',
|
||||
manual: '手动',
|
||||
add: '添加 DNS',
|
||||
save: '保存',
|
||||
invalid: '请输入有效的 IP 地址',
|
||||
noDhcp: '当前未获取到 DHCP DNS',
|
||||
saved: 'DNS 设置已保存',
|
||||
saveFailed: '保存 DNS 设置失败',
|
||||
unsaved: '有未保存的更改',
|
||||
maxServers: '最多允许 {{count}} 个 DNS 服务器',
|
||||
dnsServers: 'DNS 服务器',
|
||||
dhcpServersDescription: 'DNS 服务器由 DHCP 自动获取。',
|
||||
manualServersDescription: 'DNS 服务器可以手动编辑。',
|
||||
networkDetails: '网络详情',
|
||||
interface: '接口',
|
||||
ipAddress: 'IP 地址',
|
||||
subnetMask: '子网掩码',
|
||||
router: '路由器',
|
||||
none: '无'
|
||||
}
|
||||
},
|
||||
tailscale: {
|
||||
title: 'Tailscale',
|
||||
memory: {
|
||||
|
||||
@@ -258,30 +258,10 @@ const zh_tw = {
|
||||
1800: '30 分鐘',
|
||||
3600: '1 小時'
|
||||
},
|
||||
wifi: {
|
||||
title: 'Wi-Fi',
|
||||
description: '設定 Wi-Fi',
|
||||
setBtn: '設定',
|
||||
apMode: 'AP 模式已啟用,該模式下僅支援掃描 QRCode 配網',
|
||||
connect: '連線 Wi-Fi',
|
||||
connectDesc1: '請輸入網路名稱和密碼',
|
||||
connectDesc2: '請輸入密碼以連線此網路',
|
||||
disconnect: '是否要中斷該網路連線?',
|
||||
failed: '連線失敗,請重試',
|
||||
ssid: 'SSID 名稱',
|
||||
password: '密碼',
|
||||
joinBtn: '加入',
|
||||
confirmBtn: '確定',
|
||||
cancelBtn: '取消'
|
||||
},
|
||||
ssh: {
|
||||
description: '啟用 SSH 伺服器',
|
||||
tip: '啟用前請務必設定強密碼(帳號 - 更改密碼)'
|
||||
},
|
||||
tls: {
|
||||
description: '啟用 HTTPS 協議',
|
||||
tip: '啟用 HTTPS 可以提高安全性,但可能會增加傳輸延遲,特別是使用 MJPEG 格式傳輸時。'
|
||||
},
|
||||
advanced: '進階設定',
|
||||
swap: {
|
||||
title: 'Swap',
|
||||
@@ -325,6 +305,52 @@ const zh_tw = {
|
||||
okBtn: '確定',
|
||||
cancelBtn: '取消'
|
||||
},
|
||||
network: {
|
||||
title: '網路',
|
||||
wifi: {
|
||||
title: 'Wi-Fi',
|
||||
description: '設定 Wi-Fi',
|
||||
apMode: 'AP 模式已啟用,該模式下僅支援掃描 QRCode 配網',
|
||||
connect: '連線 Wi-Fi',
|
||||
connectDesc1: '請輸入網路名稱和密碼',
|
||||
connectDesc2: '請輸入密碼以連線此網路',
|
||||
disconnect: '是否要中斷該網路連線?',
|
||||
failed: '連線失敗,請重試',
|
||||
ssid: 'SSID 名稱',
|
||||
password: '密碼',
|
||||
joinBtn: '加入',
|
||||
confirmBtn: '確定',
|
||||
cancelBtn: '取消'
|
||||
},
|
||||
tls: {
|
||||
description: '啟用 HTTPS 協議',
|
||||
tip: '啟用 HTTPS 可以提高安全性,但可能會增加傳輸延遲,特別是使用 MJPEG 格式傳輸時。'
|
||||
},
|
||||
dns: {
|
||||
title: 'DNS',
|
||||
description: '設定 NanoKVM 使用的 DNS 伺服器',
|
||||
mode: '模式',
|
||||
dhcp: 'DHCP',
|
||||
manual: '手動',
|
||||
add: '新增 DNS',
|
||||
save: '儲存',
|
||||
invalid: '請輸入有效的 IP 位址',
|
||||
noDhcp: '目前未取得 DHCP DNS',
|
||||
saved: 'DNS 設定已儲存',
|
||||
saveFailed: '儲存 DNS 設定失敗',
|
||||
unsaved: '有未儲存的變更',
|
||||
maxServers: '最多允許 {{count}} 個 DNS 伺服器',
|
||||
dnsServers: 'DNS 伺服器',
|
||||
dhcpServersDescription: 'DNS 伺服器由 DHCP 自動取得。',
|
||||
manualServersDescription: 'DNS 伺服器可以手動編輯。',
|
||||
networkDetails: '網路詳細資訊',
|
||||
interface: '介面',
|
||||
ipAddress: 'IP 位址',
|
||||
subnetMask: '子網路遮罩',
|
||||
router: '路由器',
|
||||
none: '無'
|
||||
}
|
||||
},
|
||||
tailscale: {
|
||||
title: 'Tailscale',
|
||||
memory: {
|
||||
|
||||
@@ -8,9 +8,7 @@ import { MouseJiggler } from './mouse-jiggler.tsx';
|
||||
import { Oled } from './oled.tsx';
|
||||
import { Reboot } from './reboot.tsx';
|
||||
import { Ssh } from './ssh.tsx';
|
||||
import { Tls } from './tls.tsx';
|
||||
import { VirtualDevices } from './virtual-devices.tsx';
|
||||
import { Wifi } from './wifi.tsx';
|
||||
|
||||
export const Device = () => {
|
||||
const { t } = useTranslation();
|
||||
@@ -21,7 +19,6 @@ export const Device = () => {
|
||||
<Divider className="opacity-50" />
|
||||
|
||||
<div className="flex flex-col space-y-8">
|
||||
<Tls />
|
||||
<Ssh />
|
||||
<Mdns />
|
||||
<Hdmi />
|
||||
@@ -31,7 +28,6 @@ export const Device = () => {
|
||||
<Divider className="opacity-50" />
|
||||
|
||||
<Oled />
|
||||
<Wifi />
|
||||
<MouseJiggler />
|
||||
<Divider className="opacity-50" />
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { Badge, Modal, Tooltip } from 'antd';
|
||||
import clsx from 'clsx';
|
||||
import { useSetAtom } from 'jotai';
|
||||
import {
|
||||
BadgeInfoIcon,
|
||||
CircleArrowUpIcon,
|
||||
NetworkIcon,
|
||||
PaletteIcon,
|
||||
SettingsIcon,
|
||||
SmartphoneIcon,
|
||||
@@ -24,6 +25,7 @@ import { About } from './about';
|
||||
import { Account } from './account';
|
||||
import { Appearance } from './appearance';
|
||||
import { Device } from './device';
|
||||
import { Network } from './network';
|
||||
import { Tailscale } from './tailscale';
|
||||
import { Update } from './update';
|
||||
|
||||
@@ -33,6 +35,7 @@ export const Settings = () => {
|
||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||
const [isLocked, setIsLocked] = useState(false);
|
||||
const [currentTab, setCurrentTab] = useState('about');
|
||||
const scrollViewportRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const [isUpdateAvailable, setIsUpdateAvailable] = useState(false);
|
||||
const setIsKeyboardEnable = useSetAtom(isKeyboardEnableAtom);
|
||||
@@ -42,6 +45,7 @@ export const Settings = () => {
|
||||
{ id: 'about', icon: <BadgeInfoIcon size={16} />, component: <About /> },
|
||||
{ id: 'appearance', icon: <PaletteIcon size={16} />, component: <Appearance /> },
|
||||
{ id: 'device', icon: <SmartphoneIcon size={16} />, component: <Device /> },
|
||||
{ id: 'network', icon: <NetworkIcon size={16} />, component: <Network /> },
|
||||
{
|
||||
id: 'tailscale',
|
||||
icon: <TailscaleIcon />,
|
||||
@@ -62,6 +66,10 @@ export const Settings = () => {
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
scrollViewportRef.current?.scrollTo({ top: 0, left: 0 });
|
||||
}, [currentTab]);
|
||||
|
||||
function checkForUpdates() {
|
||||
api.getVersion().then((rsp: any) => {
|
||||
if (rsp.code !== 0) {
|
||||
@@ -162,7 +170,10 @@ export const Settings = () => {
|
||||
))}
|
||||
</div>
|
||||
|
||||
<ScrollArea className="h-full w-full rounded-r-lg bg-neutral-900/50 px-3">
|
||||
<ScrollArea
|
||||
viewportRef={scrollViewportRef}
|
||||
className="h-full w-full rounded-r-lg bg-neutral-900/50 px-3"
|
||||
>
|
||||
<div className="flex h-full w-full justify-center">
|
||||
<div className="w-full max-w-[600px] pb-10 pt-14">
|
||||
<>{tabs.find((tab) => tab.id === currentTab)?.component}</>
|
||||
|
||||
439
web/src/pages/desktop/menu/settings/network/dns.tsx
Normal file
439
web/src/pages/desktop/menu/settings/network/dns.tsx
Normal file
@@ -0,0 +1,439 @@
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import type { ReactNode } from 'react';
|
||||
import { Button, Input, Segmented } from 'antd';
|
||||
import { CheckIcon, PlusIcon, XIcon } from 'lucide-react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import * as api from '@/api/network.ts';
|
||||
import type { DNSMode } from '@/api/network.ts';
|
||||
|
||||
type DNSState = {
|
||||
mode: DNSMode;
|
||||
servers: string[];
|
||||
dhcp: string[];
|
||||
info: DNSInfo;
|
||||
};
|
||||
|
||||
type DNSInfo = {
|
||||
interface?: string;
|
||||
type?: string;
|
||||
address?: string;
|
||||
subnetMask?: string;
|
||||
gateway?: string;
|
||||
};
|
||||
|
||||
const maxServers = 6;
|
||||
|
||||
function formatInterface(info: DNSInfo) {
|
||||
if (!info.interface) return '';
|
||||
if (!info.type) return info.interface;
|
||||
|
||||
return `${info.type} (${info.interface})`;
|
||||
}
|
||||
|
||||
function normalizeServers(servers: string[]) {
|
||||
const seen = new Set<string>();
|
||||
const normalized: string[] = [];
|
||||
|
||||
for (const server of servers) {
|
||||
const value = normalizeServer(server);
|
||||
if (!value || seen.has(value)) continue;
|
||||
|
||||
seen.add(value);
|
||||
normalized.push(value);
|
||||
}
|
||||
|
||||
return normalized;
|
||||
}
|
||||
|
||||
function normalizeServer(server: string) {
|
||||
return server.split('#')[0].trim().split(/\s+/)[0] || '';
|
||||
}
|
||||
|
||||
function isValidIP(value: string) {
|
||||
return isValidIPv4(value) || isValidIPv6(value);
|
||||
}
|
||||
|
||||
function isValidIPv4(value: string) {
|
||||
const parts = value.split('.');
|
||||
if (parts.length !== 4) return false;
|
||||
|
||||
return parts.every((part) => {
|
||||
if (!/^\d+$/.test(part)) return false;
|
||||
if (part.length > 1 && part.startsWith('0')) return false;
|
||||
|
||||
const number = Number(part);
|
||||
return number >= 0 && number <= 255;
|
||||
});
|
||||
}
|
||||
|
||||
function isValidIPv6(value: string) {
|
||||
if (!value.includes(':')) return false;
|
||||
|
||||
try {
|
||||
new URL(`http://[${value}]/`);
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const Panel = ({
|
||||
title,
|
||||
description,
|
||||
children
|
||||
}: {
|
||||
title: string;
|
||||
description?: string;
|
||||
children: ReactNode;
|
||||
}) => {
|
||||
return (
|
||||
<div className="overflow-hidden rounded-xl bg-neutral-800/50">
|
||||
<div className="px-4 pb-1.5 pt-3">
|
||||
<div className="font-semibold text-neutral-100">{title}</div>
|
||||
{description && (
|
||||
<div className="mt-0.5 text-xs leading-snug text-neutral-500">{description}</div>
|
||||
)}
|
||||
</div>
|
||||
<div>{children}</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const InfoRow = ({
|
||||
label,
|
||||
value,
|
||||
isLast = false
|
||||
}: {
|
||||
label: string;
|
||||
value?: string;
|
||||
isLast?: boolean;
|
||||
}) => {
|
||||
return (
|
||||
<div className="px-4">
|
||||
<div
|
||||
className={`flex min-h-[44px] items-center justify-between ${
|
||||
isLast ? '' : 'border-b border-neutral-700/50'
|
||||
}`}
|
||||
>
|
||||
<span className="text-sm text-neutral-300">{label}</span>
|
||||
<span className="max-w-[330px] break-all text-right text-sm text-neutral-500">
|
||||
{value || '-'}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const ServerList = ({ servers }: { servers: string[] }) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
if (!servers.length) {
|
||||
return (
|
||||
<div className="px-4 py-3 text-sm text-neutral-500">{t('settings.network.dns.none')}</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
{servers.map((server, index) => (
|
||||
<div key={`${server}-${index}`} className="px-4">
|
||||
<div
|
||||
className={`min-h-[44px] py-2.5 text-sm text-neutral-400 ${
|
||||
index === servers.length - 1 ? '' : 'border-b border-neutral-700/50'
|
||||
}`}
|
||||
>
|
||||
{server}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const EditableServerRow = ({
|
||||
value,
|
||||
autoFocus,
|
||||
onChange,
|
||||
onRemove
|
||||
}: {
|
||||
value: string;
|
||||
autoFocus: boolean;
|
||||
onChange: (value: string) => void;
|
||||
onRemove: () => void;
|
||||
}) => {
|
||||
const inputRef = useRef<any>(null);
|
||||
const normalized = normalizeServer(value);
|
||||
const isInvalid = normalized !== '' && !isValidIP(normalized);
|
||||
|
||||
useEffect(() => {
|
||||
if (autoFocus && inputRef.current) {
|
||||
inputRef.current.focus();
|
||||
}
|
||||
}, [autoFocus]);
|
||||
|
||||
return (
|
||||
<div className="group px-4 py-1.5">
|
||||
<div className="flex items-center gap-2">
|
||||
<Input
|
||||
ref={inputRef}
|
||||
value={value}
|
||||
onChange={(e) => onChange(e.target.value)}
|
||||
placeholder="0.0.0.0"
|
||||
status={isInvalid ? 'error' : undefined}
|
||||
/>
|
||||
<Button
|
||||
size="small"
|
||||
shape="circle"
|
||||
icon={<XIcon size={14} />}
|
||||
onClick={onRemove}
|
||||
className="opacity-0 transition-opacity group-focus-within:opacity-100 group-hover:opacity-100"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const DNS = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [mode, setMode] = useState<DNSMode>('dhcp');
|
||||
const [originalMode, setOriginalMode] = useState<DNSMode>('dhcp');
|
||||
const [servers, setServers] = useState<string[]>([]);
|
||||
const [originalServers, setOriginalServers] = useState<string[]>([]);
|
||||
const [dhcp, setDHCP] = useState<string[]>([]);
|
||||
const [info, setInfo] = useState<DNSInfo>({});
|
||||
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
const [message, setMessage] = useState('');
|
||||
const [error, setError] = useState('');
|
||||
const [focusNewRow, setFocusNewRow] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
getDNS();
|
||||
}, []);
|
||||
|
||||
async function getDNS(showLoading = true) {
|
||||
if (showLoading) setIsLoading(true);
|
||||
|
||||
try {
|
||||
const rsp = await api.getDNS();
|
||||
if (rsp.code !== 0) {
|
||||
setError(rsp.msg);
|
||||
return;
|
||||
}
|
||||
|
||||
const data = rsp.data as DNSState;
|
||||
const fetchedMode = data.mode || 'dhcp';
|
||||
setMode(fetchedMode);
|
||||
setOriginalMode(fetchedMode);
|
||||
|
||||
const fetchedServers = data.servers?.filter(Boolean) || [];
|
||||
setServers(fetchedServers);
|
||||
setOriginalServers(fetchedServers);
|
||||
setDHCP(data.dhcp || []);
|
||||
setInfo(data.info || {});
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
} finally {
|
||||
if (showLoading) setIsLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
async function save() {
|
||||
if (isSaving) return;
|
||||
|
||||
setMessage('');
|
||||
setError('');
|
||||
|
||||
const normalized = normalizeServers(servers);
|
||||
if (mode === 'manual' && normalized.length === 0) {
|
||||
setError(t('settings.network.dns.invalid'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (mode === 'manual' && normalized.some((server) => !isValidIP(server))) {
|
||||
setError(t('settings.network.dns.invalid'));
|
||||
return;
|
||||
}
|
||||
|
||||
setIsSaving(true);
|
||||
try {
|
||||
const rsp = await api.setDNS(mode, mode === 'manual' ? normalized : []);
|
||||
if (rsp.code !== 0) {
|
||||
setError(rsp.msg || t('settings.network.dns.saveFailed'));
|
||||
return;
|
||||
}
|
||||
|
||||
setServers(normalized);
|
||||
setOriginalServers(normalized);
|
||||
setOriginalMode(mode);
|
||||
|
||||
await getDNS(false);
|
||||
setMessage(t('settings.network.dns.saved'));
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
setError(t('settings.network.dns.saveFailed'));
|
||||
} finally {
|
||||
setIsSaving(false);
|
||||
}
|
||||
}
|
||||
|
||||
function addServer() {
|
||||
if (servers.length >= maxServers) return;
|
||||
setMessage('');
|
||||
setError('');
|
||||
setServers([...servers, '']);
|
||||
setFocusNewRow(true);
|
||||
}
|
||||
|
||||
function removeServer(index: number) {
|
||||
setMessage('');
|
||||
setError('');
|
||||
setServers(servers.filter((_, i) => i !== index));
|
||||
}
|
||||
|
||||
function updateServer(index: number, value: string) {
|
||||
setMessage('');
|
||||
setError('');
|
||||
const updated = [...servers];
|
||||
updated[index] = value;
|
||||
setServers(updated);
|
||||
}
|
||||
|
||||
const normalizedServers = normalizeServers(servers);
|
||||
const hasInvalidServer =
|
||||
mode === 'manual' &&
|
||||
servers.some((server) => {
|
||||
const val = normalizeServer(server);
|
||||
return val !== '' && !isValidIP(val);
|
||||
});
|
||||
const isExceedMax = mode === 'manual' && normalizedServers.length > maxServers;
|
||||
const hasChanges =
|
||||
mode !== originalMode ||
|
||||
normalizedServers.join(',') !== normalizeServers(originalServers).join(',');
|
||||
|
||||
const statusText = error || message || (hasChanges ? t('settings.network.dns.unsaved') : '');
|
||||
const statusColor = error ? 'text-red-400' : message ? 'text-green-400' : 'text-yellow-400/80';
|
||||
const serversDescription =
|
||||
mode === 'dhcp'
|
||||
? t('settings.network.dns.dhcpServersDescription')
|
||||
: t('settings.network.dns.manualServersDescription');
|
||||
|
||||
const canAdd = !isLoading && !isSaving && servers.length < maxServers;
|
||||
|
||||
return (
|
||||
<div className="flex flex-col space-y-5">
|
||||
{/* Header row: title + segmented control */}
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex flex-col space-y-1">
|
||||
<span>{t('settings.network.dns.title')}</span>
|
||||
<span className="text-xs text-neutral-500">{t('settings.network.dns.description')}</span>
|
||||
</div>
|
||||
|
||||
<Segmented
|
||||
disabled={isLoading || isSaving}
|
||||
value={mode}
|
||||
onChange={(val) => {
|
||||
setMode(val as DNSMode);
|
||||
setMessage('');
|
||||
setError('');
|
||||
}}
|
||||
options={[
|
||||
{ label: t('settings.network.dns.dhcp'), value: 'dhcp' },
|
||||
{ label: t('settings.network.dns.manual'), value: 'manual' }
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-5">
|
||||
<Panel title={t('settings.network.dns.networkDetails')}>
|
||||
<InfoRow label={t('settings.network.dns.interface')} value={formatInterface(info)} />
|
||||
<InfoRow label={t('settings.network.dns.ipAddress')} value={info.address} />
|
||||
<InfoRow label={t('settings.network.dns.subnetMask')} value={info.subnetMask} />
|
||||
<InfoRow label={t('settings.network.dns.router')} value={info.gateway} isLast />
|
||||
</Panel>
|
||||
|
||||
<Panel title={t('settings.network.dns.dnsServers')} description={serversDescription}>
|
||||
{mode === 'manual' ? (
|
||||
<div>
|
||||
{servers.length === 0 ? (
|
||||
<div className="px-4 py-3 text-sm text-neutral-500">
|
||||
{t('settings.network.dns.none')}
|
||||
</div>
|
||||
) : (
|
||||
servers.map((server, index) => (
|
||||
<EditableServerRow
|
||||
key={index}
|
||||
value={server}
|
||||
autoFocus={focusNewRow && index === servers.length - 1}
|
||||
onChange={(val) => updateServer(index, val)}
|
||||
onRemove={() => removeServer(index)}
|
||||
/>
|
||||
))
|
||||
)}
|
||||
|
||||
{/* Add server button */}
|
||||
{canAdd && (
|
||||
<div className="px-4 py-1.5 pb-3">
|
||||
<div className="flex items-center gap-2">
|
||||
<Button
|
||||
type="dashed"
|
||||
className="flex-1"
|
||||
icon={<PlusIcon size={14} />}
|
||||
onClick={addServer}
|
||||
>
|
||||
{t('settings.network.dns.add')}
|
||||
</Button>
|
||||
<Button
|
||||
type="text"
|
||||
size="small"
|
||||
className="invisible shrink-0"
|
||||
icon={<XIcon size={14} />}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Validation hints */}
|
||||
{(hasInvalidServer || isExceedMax) && (
|
||||
<div className="space-y-1 px-4 pb-3">
|
||||
{hasInvalidServer && (
|
||||
<div className="text-xs text-red-400">{t('settings.network.dns.invalid')}</div>
|
||||
)}
|
||||
{isExceedMax && (
|
||||
<div className="text-xs text-red-400">
|
||||
{t('settings.network.dns.maxServers', { count: maxServers })}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
<ServerList servers={dhcp} />
|
||||
)}
|
||||
</Panel>
|
||||
</div>
|
||||
|
||||
{/* Footer: status + save button */}
|
||||
{(hasChanges || statusText) && (
|
||||
<div className="flex items-center justify-between">
|
||||
<span className={`text-xs ${statusColor}`}>{statusText}</span>
|
||||
|
||||
<Button
|
||||
type={hasChanges ? 'primary' : 'default'}
|
||||
icon={message ? <CheckIcon size={14} /> : undefined}
|
||||
loading={isSaving}
|
||||
disabled={
|
||||
isLoading || (!hasChanges && !hasInvalidServer) || hasInvalidServer || isExceedMax
|
||||
}
|
||||
onClick={save}
|
||||
>
|
||||
{t('settings.network.dns.save')}
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
26
web/src/pages/desktop/menu/settings/network/index.tsx
Normal file
26
web/src/pages/desktop/menu/settings/network/index.tsx
Normal file
@@ -0,0 +1,26 @@
|
||||
import { Divider } from 'antd';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { DNS } from './dns.tsx';
|
||||
import { Tls } from './tls.tsx';
|
||||
import { Wifi } from './wifi.tsx';
|
||||
|
||||
export const Network = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="text-base">{t('settings.network.title')}</div>
|
||||
<Divider className="opacity-50" />
|
||||
|
||||
<div className="flex flex-col space-y-8">
|
||||
<Tls />
|
||||
<Wifi />
|
||||
</div>
|
||||
|
||||
<Divider className="opacity-50" style={{ margin: '32px 0' }} />
|
||||
|
||||
<DNS />
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -52,7 +52,7 @@ export const Tls = () => {
|
||||
<span>HTTPS</span>
|
||||
|
||||
<Tooltip
|
||||
title={t('settings.device.tls.tip')}
|
||||
title={t('settings.network.tls.tip')}
|
||||
className="cursor-pointer"
|
||||
placement="right"
|
||||
styles={{ root: { maxWidth: '400px' } }}
|
||||
@@ -60,7 +60,7 @@ export const Tls = () => {
|
||||
<CircleAlertIcon className="text-neutral-500" size={14} />
|
||||
</Tooltip>
|
||||
</div>
|
||||
<span className="text-xs text-neutral-500">{t('settings.device.tls.description')}</span>
|
||||
<span className="text-xs text-neutral-500">{t('settings.network.tls.description')}</span>
|
||||
</div>
|
||||
|
||||
<Switch checked={isEnabled} loading={isLoading} onChange={update} />
|
||||
@@ -56,7 +56,7 @@ export const Wifi = () => {
|
||||
const rsp = await api.connectWifi(ssid, password);
|
||||
if (rsp.code !== 0) {
|
||||
console.log(rsp.msg);
|
||||
setMessage(t('settings.device.wifi.failed'));
|
||||
setMessage(t('settings.network.wifi.failed'));
|
||||
getWiFi();
|
||||
return;
|
||||
}
|
||||
@@ -109,9 +109,9 @@ export const Wifi = () => {
|
||||
if (isAPMode) {
|
||||
return (
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex flex-col">
|
||||
<span>{t('settings.device.wifi.title')}</span>
|
||||
<span className="text-xs text-neutral-500">{t('settings.device.wifi.apMode')}</span>
|
||||
<div className="flex flex-col space-y-1">
|
||||
<span>{t('settings.network.wifi.title')}</span>
|
||||
<span className="text-xs text-neutral-500">{t('settings.network.wifi.apMode')}</span>
|
||||
</div>
|
||||
|
||||
<Button shape="round" size="small" disabled>
|
||||
@@ -127,8 +127,10 @@ export const Wifi = () => {
|
||||
<>
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex flex-col space-y-1">
|
||||
<span>{t('settings.device.wifi.title')}</span>
|
||||
<span className="text-xs text-neutral-500">{t('settings.device.wifi.description')}</span>
|
||||
<span>{t('settings.network.wifi.title')}</span>
|
||||
<span className="text-xs text-neutral-500">
|
||||
{connectedWiFi ? connectedWiFi : t('settings.network.wifi.description')}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<Button
|
||||
@@ -149,8 +151,8 @@ export const Wifi = () => {
|
||||
centered={true}
|
||||
onOk={connect}
|
||||
onCancel={closeModal}
|
||||
okText={t('settings.device.wifi.joinBtn')}
|
||||
cancelText={t('settings.device.wifi.cancelBtn')}
|
||||
okText={t('settings.network.wifi.joinBtn')}
|
||||
cancelText={t('settings.network.wifi.cancelBtn')}
|
||||
confirmLoading={status === 'connecting'}
|
||||
>
|
||||
{/* title */}
|
||||
@@ -161,9 +163,9 @@ export const Wifi = () => {
|
||||
|
||||
{!connectedWiFi ? (
|
||||
<div className="flex flex-col">
|
||||
<span className="text-lg font-bold">{t('settings.device.wifi.connect')}</span>
|
||||
<span className="text-lg font-bold">{t('settings.network.wifi.connect')}</span>
|
||||
<span className="text-xs text-neutral-400">
|
||||
{t('settings.device.wifi.connectDesc1')}
|
||||
{t('settings.network.wifi.connectDesc1')}
|
||||
</span>
|
||||
</div>
|
||||
) : (
|
||||
@@ -188,14 +190,14 @@ export const Wifi = () => {
|
||||
value={ssid}
|
||||
style={{ width: '300px' }}
|
||||
prefix={<WifiOutlined />}
|
||||
placeholder={t('settings.device.wifi.ssid')}
|
||||
placeholder={t('settings.network.wifi.ssid')}
|
||||
onChange={(e) => setSsid(e.target.value)}
|
||||
/>
|
||||
<Input.Password
|
||||
value={password}
|
||||
style={{ width: '300px' }}
|
||||
prefix={<LockOutlined />}
|
||||
placeholder={t('settings.device.wifi.password')}
|
||||
placeholder={t('settings.network.wifi.password')}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user