feat(interface): update AddInterfacePage with dynamic interface selection and localization updates for multiple languages

This commit is contained in:
Ivan
2026-04-30 11:46:23 -05:00
parent 96ad7a3480
commit 24da5de7fd
9 changed files with 126 additions and 8 deletions
@@ -1117,6 +1117,48 @@
placeholder="e.g. eth0, wlan0"
class="input-field"
/>
<div
v-if="
hostKernelInterfacesLoading ||
hostKernelInterfaces.length ||
hostKernelInterfacesUnavailable
"
class="mt-1.5 space-y-1"
>
<p class="text-[10px] text-gray-500 dark:text-zinc-500">
{{ $t("interfaces.auto_iface_ifname_chips_hint") }}
</p>
<div
v-if="hostKernelInterfacesLoading"
class="text-[10px] text-gray-400"
>
{{ $t("interfaces.kernel_iface_loading") }}
</div>
<div v-else class="flex flex-wrap gap-1 max-h-20 overflow-y-auto">
<button
v-for="iface in hostKernelInterfaces"
:key="'auto-allow-' + iface.name"
type="button"
class="max-w-full truncate px-1.5 py-0.5 text-[10px] rounded border font-mono transition-colors"
:class="
autoInterfaceChipActive(
'newInterfaceDevices',
iface.name
)
? 'border-blue-400 bg-blue-50/90 text-blue-900 dark:border-blue-500 dark:bg-blue-950/40 dark:text-blue-200'
: 'border-gray-200 bg-white/80 text-gray-800 hover:border-blue-300 dark:border-zinc-700 dark:bg-zinc-900/80 dark:text-zinc-200 dark:hover:border-blue-500'
"
@click="
toggleAutoInterfaceCommaToken(
'newInterfaceDevices',
iface.name
)
"
>
{{ iface.name }}
</button>
</div>
</div>
</div>
<div>
<FormLabel class="glass-label"
@@ -1128,6 +1170,48 @@
placeholder="e.g. tun0, docker0"
class="input-field"
/>
<div
v-if="
hostKernelInterfacesLoading ||
hostKernelInterfaces.length ||
hostKernelInterfacesUnavailable
"
class="mt-1.5 space-y-1"
>
<p class="text-[10px] text-gray-500 dark:text-zinc-500">
{{ $t("interfaces.auto_iface_ifname_chips_hint") }}
</p>
<div
v-if="hostKernelInterfacesLoading"
class="text-[10px] text-gray-400"
>
{{ $t("interfaces.kernel_iface_loading") }}
</div>
<div v-else class="flex flex-wrap gap-1 max-h-20 overflow-y-auto">
<button
v-for="iface in hostKernelInterfaces"
:key="'auto-ignore-' + iface.name"
type="button"
class="max-w-full truncate px-1.5 py-0.5 text-[10px] rounded border font-mono transition-colors"
:class="
autoInterfaceChipActive(
'newInterfaceIgnoredDevices',
iface.name
)
? 'border-amber-400 bg-amber-50/90 text-amber-950 dark:border-amber-600 dark:bg-amber-950/40 dark:text-amber-100'
: 'border-gray-200 bg-white/80 text-gray-800 hover:border-amber-300 dark:border-zinc-700 dark:bg-zinc-900/80 dark:text-zinc-200 dark:hover:border-amber-600'
"
@click="
toggleAutoInterfaceCommaToken(
'newInterfaceIgnoredDevices',
iface.name
)
"
>
{{ iface.name }}
</button>
</div>
</div>
</div>
<div>
<FormLabel class="glass-label">Configured Bitrate (bps)</FormLabel>
@@ -2118,6 +2202,32 @@ export default {
}
return rest;
},
autoInterfaceChipActive(fieldKey, token) {
const raw = this[fieldKey];
if (raw == null || raw === "") {
return false;
}
return String(raw)
.split(",")
.map((s) => s.trim())
.includes(token);
},
toggleAutoInterfaceCommaToken(fieldKey, token) {
const raw = this[fieldKey];
let str = raw == null || raw === "" ? "" : String(raw);
const tokens = str
.split(",")
.map((s) => s.trim())
.filter(Boolean);
const i = tokens.indexOf(token);
if (i === -1) {
tokens.push(token);
} else {
tokens.splice(i, 1);
}
const next = tokens.join(", ");
this[fieldKey] = next === "" ? null : next;
},
async loadHostKernelInterfaces() {
this.hostKernelInterfacesLoading = true;
this.hostKernelInterfacesUnavailable = null;
+2 -1
View File
@@ -960,7 +960,8 @@
"listen_ip_required": "Listen-IP ist erforderlich.",
"kernel_iface_picker_title": "Schnittstellen auf diesem Rechner",
"kernel_iface_loading": "Laden…",
"kernel_iface_picker_help": "Optional ein Kernel-Interface-Name, oder leer lassen und nur über Listen-IP binden. Klick füllt das Feld."
"kernel_iface_picker_help": "Optional ein Kernel-Interface-Name, oder leer lassen und nur über Listen-IP binden. Klick füllt das Feld.",
"auto_iface_ifname_chips_hint": "Schnittstellen dieses Rechners: Klicken zum Hinzufügen oder Entfernen im Feld darüber."
},
"map": {
"title": "Karte",
+2 -1
View File
@@ -908,7 +908,8 @@
"listen_ip_required": "Listen IP is required.",
"kernel_iface_picker_title": "Interfaces on this host",
"kernel_iface_loading": "Loading…",
"kernel_iface_picker_help": "Device is optional: one kernel interface name, or leave empty to bind using Listen IP only. Click a row to fill the field."
"kernel_iface_picker_help": "Device is optional: one kernel interface name, or leave empty to bind using Listen IP only. Click a row to fill the field.",
"auto_iface_ifname_chips_hint": "This host's interfaces: click to add or remove names in the field above."
},
"map": {
"title": "Map",
+2 -1
View File
@@ -908,7 +908,8 @@
"listen_ip_required": "La IP de escucha es obligatoria.",
"kernel_iface_picker_title": "Interfaces en este equipo",
"kernel_iface_loading": "Cargando…",
"kernel_iface_picker_help": "“Dispositivo” es opcional: un nombre de interfaz del kernel, o vacío para enlazar solo con la IP de escucha. Pulse una fila para rellenar."
"kernel_iface_picker_help": "“Dispositivo” es opcional: un nombre de interfaz del kernel, o vacío para enlazar solo con la IP de escucha. Pulse una fila para rellenar.",
"auto_iface_ifname_chips_hint": "Interfaces de este equipo: pulse para añadir o quitar nombres en el campo de arriba."
},
"map": {
"title": "Mapa",
+2 -1
View File
@@ -908,7 +908,8 @@
"listen_ip_required": "L'adresse IP d'écoute est obligatoire.",
"kernel_iface_picker_title": "Interfaces sur cette machine",
"kernel_iface_loading": "Chargement…",
"kernel_iface_picker_help": "Le champ Périphérique est optionnel : un seul nom d'interface noyau, ou laisser vide pour lier via l'IP d'écoute uniquement. Cliquez sur une ligne pour remplir."
"kernel_iface_picker_help": "Le champ Périphérique est optionnel : un seul nom d'interface noyau, ou laisser vide pour lier via l'IP d'écoute uniquement. Cliquez sur une ligne pour remplir.",
"auto_iface_ifname_chips_hint": "Interfaces sur cette machine : cliquez pour ajouter ou retirer des noms dans le champ ci-dessus."
},
"map": {
"title": "Carte",
+2 -1
View File
@@ -960,7 +960,8 @@
"listen_ip_required": "L'IP di ascolto è obbligatoria.",
"kernel_iface_picker_title": "Interfacce su questo host",
"kernel_iface_loading": "Caricamento…",
"kernel_iface_picker_help": "Il dispositivo è facoltativo: un solo nome di interfaccia del kernel, o lascia vuoto e lega solo con l'IP di ascolto. Clic su una riga per compilare."
"kernel_iface_picker_help": "Il dispositivo è facoltativo: un solo nome di interfaccia del kernel, o lascia vuoto e lega solo con l'IP di ascolto. Clic su una riga per compilare.",
"auto_iface_ifname_chips_hint": "Interfacce su questo host: clic per aggiungere o rimuovere nomi nel campo sopra."
},
"map": {
"title": "Mappa",
+2 -1
View File
@@ -908,7 +908,8 @@
"listen_ip_required": "Listen-IP is verplicht.",
"kernel_iface_picker_title": "Interfaces op deze host",
"kernel_iface_loading": "Laden…",
"kernel_iface_picker_help": "Apparaat is optioneel: één kernelinterfacenaam, of leeg laten en alleen via listen-IP binden. Klik op een regel om in te vullen."
"kernel_iface_picker_help": "Apparaat is optioneel: één kernelinterfacenaam, of leeg laten en alleen via listen-IP binden. Klik op een regel om in te vullen.",
"auto_iface_ifname_chips_hint": "Interfaces op deze host: klik om namen in het veld erboven toe te voegen of te verwijderen."
},
"map": {
"title": "Kaart",
+2 -1
View File
@@ -960,7 +960,8 @@
"listen_ip_required": "Укажите IP для прослушивания.",
"kernel_iface_picker_title": "Интерфейсы на этом узле",
"kernel_iface_loading": "Загрузка…",
"kernel_iface_picker_help": "Поле «устройство» необязательно: одно имя интерфейса ядра или пусто — привязка только по Listen IP. Нажмите строку, чтобы подставить имя."
"kernel_iface_picker_help": "Поле «устройство» необязательно: одно имя интерфейса ядра или пусто — привязка только по Listen IP. Нажмите строку, чтобы подставить имя.",
"auto_iface_ifname_chips_hint": "Интерфейсы этого узла: нажмите, чтобы добавить или убрать имя в поле выше."
},
"map": {
"title": "Карта",
+2 -1
View File
@@ -908,7 +908,8 @@
"listen_ip_required": "Listen IP 为必填项。",
"kernel_iface_picker_title": "本机网络接口",
"kernel_iface_loading": "加载中…",
"kernel_iface_picker_help": "“设备”为可选,填写一个内核网卡名,或留空仅按 Listen IP 绑定。点击一行填入输入框。"
"kernel_iface_picker_help": "“设备”为可选,填写一个内核网卡名,或留空仅按 Listen IP 绑定。点击一行填入输入框。",
"auto_iface_ifname_chips_hint": "本机接口:点击可在上方字段中添加或移除名称。"
},
"map": {
"title": "地图",