3x-ui/frontend/src/pages/xray/DnsTab.vue
MHSanaei b69cc7a18e
feat(frontend): Phase 6-v — xray Balancers tab + DNS placeholder
Brings Balancers to full parity with the legacy panel and adds a
DNS tab placeholder that exposes the full dns/fakedns trees as JSON
so users can edit them without falling through to Advanced.

- BalancerFormModal.vue: tag (with duplicate-tag warning across
  other balancers), strategy (random/roundRobin/leastLoad/leastPing),
  selector tag-mode multi-select sourced from existing outbound
  tags + free-form additions, fallback. Disable-on-invalid is
  driven by the duplicateTag + emptySelector computed flags.
- BalancersTab.vue: empty state with a single "Add balancer" CTA;
  populated state shows the legacy 4-column table (action / tag /
  strategy / selector / fallback) with per-row edit + delete in a
  dropdown. On submit the wire shape preserves the
  `strategy: { type }` nesting only when the strategy is non-default,
  matching the legacy emit. Tag renames also chase across
  routing.rules.balancerTag references so existing rules don't dangle.
- DnsTab.vue: master enable switch + raw JSON for `dns` and
  `fakedns`. Legacy had a dedicated server-by-server editor + a
  fakedns row editor; both are big enough to deserve their own
  commits, and the JSON path supports every field today.

WARP / NordVPN provisioning modals still toast as "coming soon" —
those are third-party API integrations worth their own commits.
The xray page now has structured editors for Basics / Routing /
Outbounds / Balancers and JSON editors for DNS / Advanced — every
xray tab the legacy panel offered is functional.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 14:30:48 +02:00

111 lines
3.1 KiB
Vue

<script setup>
import { computed } from 'vue';
// Compact DNS editor — a master enable switch plus a JSON textarea
// for the full dns + fakedns trees. The legacy panel had a
// dedicated DNS-server modal + fakedns row editor; both are large
// enough to deserve their own commits. For now this gives users a
// working path to edit DNS settings without leaving the structured
// page.
const props = defineProps({
templateSettings: { type: Object, default: null },
});
const enableDns = computed({
get: () => !!props.templateSettings?.dns,
set: (next) => {
if (!props.templateSettings) return;
if (next) {
props.templateSettings.dns = {
servers: [],
queryStrategy: 'UseIP',
tag: 'dns_inbound',
enableParallelQuery: false,
};
props.templateSettings.fakedns = null;
} else {
delete props.templateSettings.dns;
delete props.templateSettings.fakedns;
}
},
});
const dnsJson = computed({
get: () => {
if (!props.templateSettings?.dns) return '';
try { return JSON.stringify(props.templateSettings.dns, null, 2); }
catch (_e) { return ''; }
},
set: (next) => {
if (!props.templateSettings) return;
try {
const parsed = next.trim() ? JSON.parse(next) : null;
props.templateSettings.dns = parsed;
} catch (_e) {
// wait for valid JSON — leaves the previous value untouched
}
},
});
const fakednsJson = computed({
get: () => {
if (!props.templateSettings?.fakedns) return '';
try { return JSON.stringify(props.templateSettings.fakedns, null, 2); }
catch (_e) { return ''; }
},
set: (next) => {
if (!props.templateSettings) return;
try {
const parsed = next.trim() ? JSON.parse(next) : null;
if (parsed) props.templateSettings.fakedns = parsed;
else delete props.templateSettings.fakedns;
} catch (_e) { /* wait for valid JSON */ }
},
});
</script>
<template>
<a-space direction="vertical" size="middle" :style="{ width: '100%' }">
<a-form layout="vertical">
<a-form-item label="Enable DNS">
<a-switch v-model:checked="enableDns" />
</a-form-item>
<template v-if="enableDns">
<a-alert
type="info"
show-icon
message="The full DNS tree is editable here. A dedicated server-by-server editor is coming in a future commit."
class="mb-12"
/>
<a-form-item label="dns (JSON)">
<a-textarea
v-model:value="dnsJson"
:auto-size="{ minRows: 12, maxRows: 28 }"
spellcheck="false"
class="json-editor"
/>
</a-form-item>
<a-form-item label="fakedns (JSON, optional)">
<a-textarea
v-model:value="fakednsJson"
:auto-size="{ minRows: 6, maxRows: 18 }"
spellcheck="false"
class="json-editor"
placeholder="Leave empty to omit fakedns."
/>
</a-form-item>
</template>
</a-form>
</a-space>
</template>
<style scoped>
.mb-12 { margin-bottom: 12px; }
.json-editor {
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
font-size: 12px;
}
</style>