feat(xray/dns): align DNS settings with Xray docs + UI polish

- 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 <noreply@anthropic.com>
This commit is contained in:
MHSanaei
2026-05-10 17:03:11 +02:00
parent 8e7d215b4a
commit a96612f595
50 changed files with 1203 additions and 886 deletions
@@ -327,14 +327,16 @@ const showSubscriptionTab = computed(
<tr>
<td>{{ t('pages.inbounds.createdAt') }}</td>
<td>
<a-tag v-if="clientSettings.created_at">{{ IntlUtil.formatDate(clientSettings.created_at, datepicker) }}</a-tag>
<a-tag v-if="clientSettings.created_at">{{ IntlUtil.formatDate(clientSettings.created_at, datepicker)
}}</a-tag>
<a-tag v-else>-</a-tag>
</td>
</tr>
<tr>
<td>{{ t('pages.inbounds.updatedAt') }}</td>
<td>
<a-tag v-if="clientSettings.updated_at">{{ IntlUtil.formatDate(clientSettings.updated_at, datepicker) }}</a-tag>
<a-tag v-if="clientSettings.updated_at">{{ IntlUtil.formatDate(clientSettings.updated_at, datepicker)
}}</a-tag>
<a-tag v-else>-</a-tag>
</td>
</tr>
@@ -356,7 +358,7 @@ const showSubscriptionTab = computed(
<div class="ip-log">
<div v-if="clientIpsArray.length > 0">
<a-tag v-for="(item, idx) in clientIpsArray" :key="idx" color="blue" class="ip-log-row">{{ item
}}</a-tag>
}}</a-tag>
</div>
<a-tag v-else>{{ clientIpsText || t('tgbot.noIpRecord') }}</a-tag>
</div>
@@ -472,7 +474,7 @@ const showSubscriptionTab = computed(
</a-tooltip>
</div>
<a :href="subJsonLink" target="_blank" rel="noopener noreferrer" class="link-panel-anchor">{{ subJsonLink
}}</a>
}}</a>
</div>
</template>
</a-tab-pane>
@@ -627,11 +629,7 @@ const showSubscriptionTab = computed(
<dd><a-tag class="value-tag">{{ inbound.settings.ip }}</a-tag></dd>
</div>
<template v-if="inbound.settings.auth === 'password' && inbound.settings.accounts?.length">
<div
v-for="(account, idx) in inbound.settings.accounts"
:key="idx"
class="info-row"
>
<div v-for="(account, idx) in inbound.settings.accounts" :key="idx" class="info-row">
<dt>{{ t('username') }} #{{ idx + 1 }}</dt>
<dd class="account-row">
<a-tag color="green" class="value-tag">{{ account.user }}</a-tag>
@@ -651,11 +649,7 @@ const showSubscriptionTab = computed(
<!-- HTTP accounts -->
<dl v-if="dbInbound.isHTTP && inbound.settings.accounts?.length" class="info-list info-list-block">
<div
v-for="(account, idx) in inbound.settings.accounts"
:key="idx"
class="info-row"
>
<div v-for="(account, idx) in inbound.settings.accounts" :key="idx" class="info-row">
<dt>{{ t('username') }} #{{ idx + 1 }}</dt>
<dd class="account-row">
<a-tag color="green" class="value-tag">{{ account.user }}</a-tag>