From a96612f595898b83b5ba01882a2a133bbff20c31 Mon Sep 17 00:00:00 2001 From: MHSanaei Date: Sun, 10 May 2026 17:03:11 +0200 Subject: [PATCH] feat(xray/dns): align DNS settings with Xray docs + UI polish MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - DNS server modal: rename expectIPs -> expectedIPs (per docs); add per-server tag, clientIP, serveStale, serveExpiredTTL, timeoutMs; flip skipFallback default to false; hydration still accepts legacy expectIPs for back-compat. - DNS tab: add hosts editor (domain -> IP/array), serveStale + serveExpiredTTL controls, "Use Preset" button bringing back the legacy preset gallery (Google / Cloudflare / AdGuard + Family variants — fixed AdGuard Family IPs that were wrong in legacy), and a "Delete All" button to wipe the server list at once. - i18n: add 15 new dns.* keys across all 13 locales. - Frontend-wide formatter pass on Vue components (whitespace and attribute layout only, no behavior changes). Co-Authored-By: Claude Opus 4.7 --- frontend/src/components/AppSidebar.vue | 53 +--- frontend/src/components/CustomStatistic.vue | 8 +- frontend/src/components/DateTimePicker.vue | 40 +-- frontend/src/components/FinalMaskForm.vue | 174 +++++------- frontend/src/components/InfinityIcon.vue | 13 +- frontend/src/components/PromptModal.vue | 28 +- frontend/src/components/SettingListItem.vue | 8 +- frontend/src/components/Sparkline.vue | 82 ++---- frontend/src/components/TableSortable.vue | 19 +- frontend/src/components/TextModal.vue | 15 +- .../src/pages/inbounds/ClientFormModal.vue | 2 +- .../src/pages/inbounds/ClientRowTable.vue | 15 +- .../src/pages/inbounds/InboundFormModal.vue | 16 +- .../src/pages/inbounds/InboundInfoModal.vue | 22 +- frontend/src/pages/inbounds/InboundList.vue | 32 ++- frontend/src/pages/inbounds/InboundsPage.vue | 10 +- frontend/src/pages/inbounds/QrPanel.vue | 7 +- frontend/src/pages/index/LogModal.vue | 89 ++++-- frontend/src/pages/index/StatusCard.vue | 16 +- .../src/pages/index/SystemHistoryModal.vue | 9 +- frontend/src/pages/index/XrayLogModal.vue | 40 ++- frontend/src/pages/nodes/NodeFormModal.vue | 35 +-- frontend/src/pages/nodes/NodeHistoryPanel.vue | 30 +- frontend/src/pages/nodes/NodeList.vue | 35 ++- frontend/src/pages/nodes/NodesPage.vue | 47 +--- frontend/src/pages/settings/SecurityTab.vue | 7 +- frontend/src/pages/sub/SubPage.vue | 72 ++--- frontend/src/pages/xray/BalancerFormModal.vue | 14 +- frontend/src/pages/xray/DnsPresetsModal.vue | 103 +++++++ frontend/src/pages/xray/DnsServerModal.vue | 120 ++++---- frontend/src/pages/xray/DnsTab.vue | 258 ++++++++++++++---- frontend/src/pages/xray/OutboundFormModal.vue | 10 +- frontend/src/pages/xray/OutboundsTab.vue | 129 +++++---- frontend/src/pages/xray/RoutingTab.vue | 65 +++-- frontend/src/pages/xray/RuleFormModal.vue | 58 ++-- frontend/src/pages/xray/WarpModal.vue | 62 +++-- frontend/src/pages/xray/XrayPage.vue | 125 +++------ web/translation/ar-EG.json | 17 +- web/translation/en-US.json | 17 +- web/translation/es-ES.json | 17 +- web/translation/fa-IR.json | 17 +- web/translation/id-ID.json | 17 +- web/translation/ja-JP.json | 17 +- web/translation/pt-BR.json | 17 +- web/translation/ru-RU.json | 17 +- web/translation/tr-TR.json | 17 +- web/translation/uk-UA.json | 17 +- web/translation/vi-VN.json | 17 +- web/translation/zh-CN.json | 17 +- web/translation/zh-TW.json | 17 +- 50 files changed, 1203 insertions(+), 886 deletions(-) create mode 100644 frontend/src/pages/xray/DnsPresetsModal.vue diff --git a/frontend/src/components/AppSidebar.vue b/frontend/src/components/AppSidebar.vue index b72da591..51857e6e 100644 --- a/frontend/src/components/AppSidebar.vue +++ b/frontend/src/components/AppSidebar.vue @@ -50,12 +50,12 @@ const prefix = props.basePath?.startsWith('/') ? props.basePath : `/${props.base // Labels are i18n-driven so the sidebar matches the locale picked // in panel settings without a page reload of the sidebar component. const tabs = computed(() => [ - { key: `${prefix}panel/`, icon: 'dashboard', title: t('menu.dashboard') }, - { key: `${prefix}panel/inbounds`, icon: 'user', title: t('menu.inbounds') }, - { key: `${prefix}panel/nodes`, icon: 'cluster', title: t('menu.nodes') }, - { key: `${prefix}panel/settings`, icon: 'setting', title: t('menu.settings') }, - { key: `${prefix}panel/xray`, icon: 'tool', title: t('menu.xray') }, - { key: `${prefix}logout`, icon: 'logout', title: t('logout') }, + { key: `${prefix}panel/`, icon: 'dashboard', title: t('menu.dashboard') }, + { key: `${prefix}panel/inbounds`, icon: 'user', title: t('menu.inbounds') }, + { key: `${prefix}panel/nodes`, icon: 'cluster', title: t('menu.nodes') }, + { key: `${prefix}panel/settings`, icon: 'setting', title: t('menu.settings') }, + { key: `${prefix}panel/xray`, icon: 'tool', title: t('menu.xray') }, + { key: `${prefix}logout`, icon: 'logout', title: t('logout') }, ]); const activeTab = ref([props.requestUri]); @@ -90,20 +90,9 @@ function closeDrawer() { diff --git a/frontend/src/pages/index/LogModal.vue b/frontend/src/pages/index/LogModal.vue index 8c1e9111..a385a919 100644 --- a/frontend/src/pages/index/LogModal.vue +++ b/frontend/src/pages/index/LogModal.vue @@ -89,8 +89,8 @@ const modalWidth = computed(() => (isMobile.value ? '100vw' : '800px'));