feat(ipv6): IPv6-Support für HAProxy + Settings-Toggle
- setup.State.IPv6Enabled + Store.SetIPv6Enabled() - GET/POST /system/ipv6 im SystemHandler; HAProxy-Reload on save - HAProxy-Template: bind [::]:80, [::]:443, quic6@:443, [::]:3443 werden nur emittiert wenn IPv6Enabled=true - haproxy.View.IPv6Enabled aus SetupStore befüllt - Settings-UI: neues IPv6-Card (zwischen Auto-Update und Passwort) - i18n de+en ergänzt Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -558,6 +558,12 @@
|
||||
"autoUpdateHint": "Whitelist umfasst nur edgeguard, edgeguard-api, edgeguard-ui. Andere Pakete bleiben unter manueller Kontrolle. Verlangt unattended-upgrades (Distro-Standard auf Trixie). Conf-File: /etc/apt/apt.conf.d/52edgeguard-auto-updates.",
|
||||
"autoUpdateToggled": "Auto-Update-Einstellung gespeichert.",
|
||||
"autoUpdateFailed": "Auto-Update-Toggle fehlgeschlagen",
|
||||
"ipv6CardTitle": "IPv6",
|
||||
"ipv6On": "Aktiviert — HAProxy bindet zusätzlich zu IPv4 auf [::]:80, [::]:443 und [::]:3443.",
|
||||
"ipv6Off": "Deaktiviert — HAProxy lauscht nur auf IPv4.",
|
||||
"ipv6Hint": "Erfordert IPv6-Konfiguration auf den Netzwerk-Interfaces dieses Servers. HAProxy wird nach der Änderung automatisch neu geladen.",
|
||||
"ipv6Toggled": "IPv6-Einstellung gespeichert.",
|
||||
"ipv6Failed": "IPv6-Toggle fehlgeschlagen",
|
||||
"passwordCardTitle": "Admin-Passwort ändern",
|
||||
"currentPassword": "Aktuelles Passwort",
|
||||
"newPassword": "Neues Passwort",
|
||||
|
||||
@@ -558,6 +558,12 @@
|
||||
"autoUpdateHint": "Whitelist covers edgeguard, edgeguard-api, edgeguard-ui only. Other packages stay under manual control. Requires unattended-upgrades (Trixie distro default). Conf file: /etc/apt/apt.conf.d/52edgeguard-auto-updates.",
|
||||
"autoUpdateToggled": "Auto-update setting saved.",
|
||||
"autoUpdateFailed": "Auto-update toggle failed",
|
||||
"ipv6CardTitle": "IPv6",
|
||||
"ipv6On": "Enabled — HAProxy binds on [::]:80, [::]:443 and [::]:3443 in addition to IPv4.",
|
||||
"ipv6Off": "Disabled — HAProxy listens on IPv4 only.",
|
||||
"ipv6Hint": "Requires IPv6 to be configured on this server's network interfaces. HAProxy reloads automatically after changing this setting.",
|
||||
"ipv6Toggled": "IPv6 setting saved.",
|
||||
"ipv6Failed": "IPv6 toggle failed",
|
||||
"passwordCardTitle": "Change admin password",
|
||||
"currentPassword": "Current password",
|
||||
"newPassword": "New password",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Alert, Button, Card, Descriptions, Form, Input, InputNumber, Space, Spin, Switch, Typography, message } from 'antd'
|
||||
import { CloudDownloadOutlined, CloudSyncOutlined, DatabaseOutlined, ExclamationCircleOutlined, FileSearchOutlined, LockOutlined, MailOutlined, ReloadOutlined, SettingOutlined, StopOutlined, ToolOutlined } from '@ant-design/icons'
|
||||
import { CloudDownloadOutlined, CloudSyncOutlined, DatabaseOutlined, ExclamationCircleOutlined, FileSearchOutlined, GlobalOutlined, LockOutlined, MailOutlined, ReloadOutlined, SettingOutlined, StopOutlined, ToolOutlined } from '@ant-design/icons'
|
||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
@@ -239,6 +239,27 @@ export default function SettingsPage() {
|
||||
},
|
||||
})
|
||||
|
||||
const { data: ipv6 } = useQuery({
|
||||
queryKey: ['system', 'ipv6'],
|
||||
queryFn: async () => {
|
||||
const r = await apiClient.get('/system/ipv6')
|
||||
return isEnvelope(r.data) ? (r.data.data as { enabled: boolean }) : { enabled: false }
|
||||
},
|
||||
})
|
||||
const toggleIPv6 = useMutation({
|
||||
mutationFn: async (enabled: boolean) => {
|
||||
const r = await apiClient.post('/system/ipv6', { enabled })
|
||||
return r.data
|
||||
},
|
||||
onSuccess: () => {
|
||||
msg.success(t('settings.ipv6Toggled'))
|
||||
void qc.invalidateQueries({ queryKey: ['system', 'ipv6'] })
|
||||
},
|
||||
onError: (e: Error) => {
|
||||
msg.error(t('settings.ipv6Failed') + ': ' + e.message)
|
||||
},
|
||||
})
|
||||
|
||||
const changePassword = useMutation({
|
||||
mutationFn: async (v: { current_password: string; new_password: string }) => {
|
||||
const r = await apiClient.post('/auth/change-password', v)
|
||||
@@ -606,6 +627,28 @@ export default function SettingsPage() {
|
||||
</Space>
|
||||
</Card>
|
||||
|
||||
<Card
|
||||
title={<><GlobalOutlined /> {t('settings.ipv6CardTitle')}</>}
|
||||
className="mb-12"
|
||||
size="small"
|
||||
>
|
||||
<Space direction="vertical" size={8} style={{ width: '100%' }}>
|
||||
<Space>
|
||||
<Switch
|
||||
checked={ipv6?.enabled ?? false}
|
||||
loading={toggleIPv6.isPending}
|
||||
onChange={(checked) => toggleIPv6.mutate(checked)}
|
||||
/>
|
||||
<Typography.Text>
|
||||
{ipv6?.enabled ? t('settings.ipv6On') : t('settings.ipv6Off')}
|
||||
</Typography.Text>
|
||||
</Space>
|
||||
<Typography.Text type="secondary" style={{ fontSize: 12 }}>
|
||||
{t('settings.ipv6Hint')}
|
||||
</Typography.Text>
|
||||
</Space>
|
||||
</Card>
|
||||
|
||||
<Card title={<><LockOutlined /> {t('settings.passwordCardTitle')}</>} size="small">
|
||||
<Form<ChangePasswordValues>
|
||||
form={pwForm}
|
||||
|
||||
Reference in New Issue
Block a user