2026-05-08 12:13:26 +00:00
|
|
|
<script setup>
|
2026-05-08 15:41:01 +00:00
|
|
|
import { computed, ref } from 'vue';
|
i18n(frontend): translate page chrome — sidebar, save bars, tabs, summary cards
Replaces hardcoded English with t() calls in the components every
user sees on every page load. The translations themselves come from
the existing TOML files via the sync script — no new strings, no
new locale keys.
Per component:
- AppSidebar.vue: 5 menu titles (dashboard / inbounds / settings /
xray / logout). Computed so the sidebar re-renders when the
cookie-driven locale flips on reload.
- IndexPage.vue: Quick actions card title + Logs / Backup / Up-to-
date / Update buttons.
- StatusCard.vue: CPU / Memory / Swap / Storage labels +
logical-processors / frequency tooltips.
- XrayStatusCard.vue: card title + error popover header + Stop /
Restart / Switch xray action labels (kept the v-prefix version
string as-is — it's content, not a label).
- SettingsPage.vue: 5 tab titles + Save / Restart-panel buttons +
unsaved-changes warning.
- XrayPage.vue: 6 tab titles + Save / Restart-xray buttons +
unsaved-changes warning.
- InboundsPage.vue: 5 summary-stat card titles.
- InboundList.vue: 10 column titles (computed for live locale),
Add inbound / General actions buttons + every dropdown menu item,
search placeholder, filter radio labels, popover titles
(disabled / depleted / depleting / online), traffic + info
popover row labels.
Total: ~75 strings localised across 8 files. The remaining English
labels live in the per-tab settings forms, the form modals
(Inbound / Client / Outbound / Rule / Balancer / WARP / Nord), and
the per-row table cell helpers — all incremental work that doesn't
touch infrastructure.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 13:07:41 +00:00
|
|
|
import { useI18n } from 'vue-i18n';
|
2026-05-08 15:39:36 +00:00
|
|
|
import { Modal, message } from 'ant-design-vue';
|
2026-05-08 12:13:26 +00:00
|
|
|
import {
|
|
|
|
|
SettingOutlined,
|
|
|
|
|
SwapOutlined,
|
|
|
|
|
UploadOutlined,
|
|
|
|
|
ClusterOutlined,
|
|
|
|
|
DatabaseOutlined,
|
|
|
|
|
CodeOutlined,
|
|
|
|
|
QuestionCircleOutlined,
|
|
|
|
|
} from '@ant-design/icons-vue';
|
|
|
|
|
|
2026-05-08 15:39:36 +00:00
|
|
|
import { theme as themeState, antdThemeConfig } from '@/composables/useTheme.js';
|
2026-05-08 12:13:26 +00:00
|
|
|
import { useMediaQuery } from '@/composables/useMediaQuery.js';
|
|
|
|
|
import AppSidebar from '@/components/AppSidebar.vue';
|
feat(frontend): Phase 6-ii — xray Basics tab structured editor
Replaces the placeholder on the Basics tab with a structured form for
the most-touched fields of the xray template — outbound + routing
strategy, log levels, traffic stat counters, and the "basic routing"
shortcuts (block torrent / IPs / domains, direct IPs / domains, IPv4
forced, WARP / NordVPN routing).
- useXraySetting.js: hoists a parsed `templateSettings` reactive
alongside the JSON string, with two cooperating watches that keep
them in sync. Editing structured fields stringifies into xraySetting
for the dirty-poll + Advanced JSON tab; editing the JSON re-parses
into templateSettings only when valid, so structured tabs stay
readable mid-edit.
- BasicsTab.vue: collapse panels mirror the legacy partial — General,
Statistics, Logs, Basic routing. Every input is a computed v-model
reading/writing into templateSettings; the routing-rule shortcuts
funnel through ruleGetter/ruleSetter which match the legacy
templateRuleGetter/templateRuleSetter behavior (replace-first,
drop-duplicates, pop-the-rule-when-empty). Direct/IPv4 setters
also call syncOutbound() to provision/prune the matching outbound.
- XrayPage.vue: imports BasicsTab + derives `warpExist`/`nordExist`
from the parsed templateSettings. WARP/NordVPN provisioning modals
are still placeholders that toast — those land in 6-v with the
routing/outbound editors.
Default tab flips back to Basics so users land on the structured
editor.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 12:18:21 +00:00
|
|
|
import BasicsTab from './BasicsTab.vue';
|
2026-05-08 12:23:02 +00:00
|
|
|
import RoutingTab from './RoutingTab.vue';
|
2026-05-08 12:27:40 +00:00
|
|
|
import OutboundsTab from './OutboundsTab.vue';
|
2026-05-08 12:30:48 +00:00
|
|
|
import BalancersTab from './BalancersTab.vue';
|
|
|
|
|
import DnsTab from './DnsTab.vue';
|
feat(frontend): Phase 6-vi — WARP + NordVPN provisioning modals
Replaces the toast stubs on the Basics tab and Outbounds toolbar
with the legacy WARP + NordVPN provisioning flows. Both modals now
stage their wireguard outbounds back into templateSettings.outbounds
through the same event channels OutboundsTab uses, so the existing
add / reset / delete / refresh-traffic surface keeps working.
- WarpModal.vue: empty state shows a single Create button that
generates a wireguard keypair locally (Wireguard.generateKeypair)
and posts it to /panel/xray/warp/reg; populated state surfaces
the access_token / device_id / license_key / private_key, lets
the user upgrade to WARP+ via /panel/xray/warp/license, refreshes
the account info from /panel/xray/warp/config (plan / quota /
usage in human-readable bytes), and stages a wireguard outbound
with the WARP-specific reserved-byte encoding pulled from
client_id. Add / Reset / Delete go through events the parent
routes back to templateSettings.outbounds.
- NordModal.vue: dual-tab login (NordVPN access token →
/panel/xray/nord/reg, or paste a NordLynx private key →
/panel/xray/nord/setKey). Once authenticated, country / city /
server selectors fetch from /panel/xray/nord/{countries,servers},
servers sort by load ascending, the lowest-load server in the
current city auto-selects. Reset emits oldTag/newTag so the
parent renames matching routing rules in place; logout emits a
remove-routing-rules event with prefix `nord-` to purge any
dangling references.
- XrayPage.vue: holds warpOpen / nordOpen flags, ensures the
outbounds array exists before mutating it, and wires the modal
events (add-outbound / reset-outbound / remove-outbound /
remove-routing-rules) to in-place edits of templateSettings.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 12:44:46 +00:00
|
|
|
import WarpModal from './WarpModal.vue';
|
|
|
|
|
import NordModal from './NordModal.vue';
|
2026-05-08 12:13:26 +00:00
|
|
|
import { useXraySetting } from './useXraySetting.js';
|
|
|
|
|
|
i18n(frontend): translate page chrome — sidebar, save bars, tabs, summary cards
Replaces hardcoded English with t() calls in the components every
user sees on every page load. The translations themselves come from
the existing TOML files via the sync script — no new strings, no
new locale keys.
Per component:
- AppSidebar.vue: 5 menu titles (dashboard / inbounds / settings /
xray / logout). Computed so the sidebar re-renders when the
cookie-driven locale flips on reload.
- IndexPage.vue: Quick actions card title + Logs / Backup / Up-to-
date / Update buttons.
- StatusCard.vue: CPU / Memory / Swap / Storage labels +
logical-processors / frequency tooltips.
- XrayStatusCard.vue: card title + error popover header + Stop /
Restart / Switch xray action labels (kept the v-prefix version
string as-is — it's content, not a label).
- SettingsPage.vue: 5 tab titles + Save / Restart-panel buttons +
unsaved-changes warning.
- XrayPage.vue: 6 tab titles + Save / Restart-xray buttons +
unsaved-changes warning.
- InboundsPage.vue: 5 summary-stat card titles.
- InboundList.vue: 10 column titles (computed for live locale),
Add inbound / General actions buttons + every dropdown menu item,
search placeholder, filter radio labels, popover titles
(disabled / depleted / depleting / online), traffic + info
popover row labels.
Total: ~75 strings localised across 8 files. The remaining English
labels live in the per-tab settings forms, the form modals
(Inbound / Client / Outbound / Rule / Balancer / WARP / Nord), and
the per-row table cell helpers — all incremental work that doesn't
touch infrastructure.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 13:07:41 +00:00
|
|
|
const { t } = useI18n();
|
|
|
|
|
|
2026-05-08 12:13:26 +00:00
|
|
|
const {
|
|
|
|
|
fetched,
|
|
|
|
|
spinning,
|
|
|
|
|
saveDisabled,
|
2026-05-08 15:20:30 +00:00
|
|
|
fetchError,
|
2026-05-08 12:13:26 +00:00
|
|
|
xraySetting,
|
feat(frontend): Phase 6-ii — xray Basics tab structured editor
Replaces the placeholder on the Basics tab with a structured form for
the most-touched fields of the xray template — outbound + routing
strategy, log levels, traffic stat counters, and the "basic routing"
shortcuts (block torrent / IPs / domains, direct IPs / domains, IPv4
forced, WARP / NordVPN routing).
- useXraySetting.js: hoists a parsed `templateSettings` reactive
alongside the JSON string, with two cooperating watches that keep
them in sync. Editing structured fields stringifies into xraySetting
for the dirty-poll + Advanced JSON tab; editing the JSON re-parses
into templateSettings only when valid, so structured tabs stay
readable mid-edit.
- BasicsTab.vue: collapse panels mirror the legacy partial — General,
Statistics, Logs, Basic routing. Every input is a computed v-model
reading/writing into templateSettings; the routing-rule shortcuts
funnel through ruleGetter/ruleSetter which match the legacy
templateRuleGetter/templateRuleSetter behavior (replace-first,
drop-duplicates, pop-the-rule-when-empty). Direct/IPv4 setters
also call syncOutbound() to provision/prune the matching outbound.
- XrayPage.vue: imports BasicsTab + derives `warpExist`/`nordExist`
from the parsed templateSettings. WARP/NordVPN provisioning modals
are still placeholders that toast — those land in 6-v with the
routing/outbound editors.
Default tab flips back to Basics so users land on the structured
editor.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 12:18:21 +00:00
|
|
|
templateSettings,
|
2026-05-08 12:13:26 +00:00
|
|
|
outboundTestUrl,
|
2026-05-08 12:23:02 +00:00
|
|
|
inboundTags,
|
|
|
|
|
clientReverseTags,
|
2026-05-08 12:13:26 +00:00
|
|
|
restartResult,
|
2026-05-08 12:27:40 +00:00
|
|
|
outboundsTraffic,
|
|
|
|
|
outboundTestStates,
|
2026-05-08 15:20:30 +00:00
|
|
|
fetchAll,
|
2026-05-08 12:27:40 +00:00
|
|
|
fetchOutboundsTraffic,
|
|
|
|
|
resetOutboundsTraffic,
|
|
|
|
|
testOutbound,
|
2026-05-08 12:13:26 +00:00
|
|
|
saveAll,
|
feat(frontend): xray tab fixes — modal close, tag validation, full XHTTP, reset to default
Modal close: BalancersTab / OutboundsTab / RoutingTab confirmDelete used
arrow expressions that returned splice's removed-items array. AD-Vue 4
treats truthy non-thenables from onOk as "still pending" and never closes
the dialog (see ActionButton.js:103-106), so the confirm modal stayed
open. Wrap the body so onOk returns undefined and AD-Vue auto-closes.
Tag validation: outbound + balancer modals only flipped between
warning/success on duplicate, leaving the empty case as a green ✓.
Split into a 3-state computed — error (empty) / warning (duplicate) /
success — and wire a help message so the input clearly explains why
the OK button is disabled.
Reset to default: re-add the legacy "Reset to Default" panel at the
bottom of BasicsTab. Calls /panel/setting/getDefaultJsonConfig and
overwrites templateSettings; the existing watch re-stringifies so the
JSON tab + dirty-poll see the new state.
Restored Basics option lists from main: IPs (4→10, +Vietnam/Spain/
Indonesia/Ukraine/Türkiye/Brazil), DomainsOptions (4→10, +regex
entries), BlockDomainsOptions (5→17, +Malware/Phishing/Adult/regex),
ServicesOptions (Reddit/Speedtest in, off-template Microsoft out).
Outbound form parity with main:
• Reverse Sniffing UI for VLESS — toggle + destOverride checkboxes
(HTTP/TLS/QUIC/FAKEDNS) + Metadata/Route Only + IPs/Domains
excluded multi-selects, gated on reverseTag being set.
• Full XHTTP transport — request headers list, Max Upload Size /
Min Upload Interval (packet-up), Padding Obfs Mode + sub-fields,
Uplink HTTP Method, Session/Sequence/UplinkData placement +
keys, No gRPC Header (stream-up/stream-one), expanded XMUX with
Max Concurrency/Connections/Reuse/Request/Reusable/Keep-alive.
Strip a-divider from the outbound form per request — replaced with
plain section/item heading divs so the labels and per-row delete
icons stay but the horizontal rule is gone.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 19:47:22 +00:00
|
|
|
resetToDefault,
|
2026-05-08 12:13:26 +00:00
|
|
|
restartXray,
|
|
|
|
|
} = useXraySetting();
|
feat(frontend): Phase 6-ii — xray Basics tab structured editor
Replaces the placeholder on the Basics tab with a structured form for
the most-touched fields of the xray template — outbound + routing
strategy, log levels, traffic stat counters, and the "basic routing"
shortcuts (block torrent / IPs / domains, direct IPs / domains, IPv4
forced, WARP / NordVPN routing).
- useXraySetting.js: hoists a parsed `templateSettings` reactive
alongside the JSON string, with two cooperating watches that keep
them in sync. Editing structured fields stringifies into xraySetting
for the dirty-poll + Advanced JSON tab; editing the JSON re-parses
into templateSettings only when valid, so structured tabs stay
readable mid-edit.
- BasicsTab.vue: collapse panels mirror the legacy partial — General,
Statistics, Logs, Basic routing. Every input is a computed v-model
reading/writing into templateSettings; the routing-rule shortcuts
funnel through ruleGetter/ruleSetter which match the legacy
templateRuleGetter/templateRuleSetter behavior (replace-first,
drop-duplicates, pop-the-rule-when-empty). Direct/IPv4 setters
also call syncOutbound() to provision/prune the matching outbound.
- XrayPage.vue: imports BasicsTab + derives `warpExist`/`nordExist`
from the parsed templateSettings. WARP/NordVPN provisioning modals
are still placeholders that toast — those land in 6-v with the
routing/outbound editors.
Default tab flips back to Basics so users land on the structured
editor.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 12:18:21 +00:00
|
|
|
|
2026-05-08 12:27:40 +00:00
|
|
|
async function onTestOutbound(idx) {
|
|
|
|
|
const outbound = templateSettings.value?.outbounds?.[idx];
|
|
|
|
|
if (outbound) await testOutbound(idx, outbound);
|
|
|
|
|
}
|
|
|
|
|
|
feat(frontend): Phase 6-ii — xray Basics tab structured editor
Replaces the placeholder on the Basics tab with a structured form for
the most-touched fields of the xray template — outbound + routing
strategy, log levels, traffic stat counters, and the "basic routing"
shortcuts (block torrent / IPs / domains, direct IPs / domains, IPv4
forced, WARP / NordVPN routing).
- useXraySetting.js: hoists a parsed `templateSettings` reactive
alongside the JSON string, with two cooperating watches that keep
them in sync. Editing structured fields stringifies into xraySetting
for the dirty-poll + Advanced JSON tab; editing the JSON re-parses
into templateSettings only when valid, so structured tabs stay
readable mid-edit.
- BasicsTab.vue: collapse panels mirror the legacy partial — General,
Statistics, Logs, Basic routing. Every input is a computed v-model
reading/writing into templateSettings; the routing-rule shortcuts
funnel through ruleGetter/ruleSetter which match the legacy
templateRuleGetter/templateRuleSetter behavior (replace-first,
drop-duplicates, pop-the-rule-when-empty). Direct/IPv4 setters
also call syncOutbound() to provision/prune the matching outbound.
- XrayPage.vue: imports BasicsTab + derives `warpExist`/`nordExist`
from the parsed templateSettings. WARP/NordVPN provisioning modals
are still placeholders that toast — those land in 6-v with the
routing/outbound editors.
Default tab flips back to Basics so users land on the structured
editor.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 12:18:21 +00:00
|
|
|
// `WarpExist` / `NordExist` derive from the parsed templateSettings —
|
|
|
|
|
// the Basics tab gates its WARP / NordVPN domain selectors on whether
|
|
|
|
|
// the matching outbound is provisioned, falling back to a "configure"
|
|
|
|
|
// button that today just toasts (the modals land in 6-v).
|
|
|
|
|
const warpExist = computed(
|
|
|
|
|
() => !!templateSettings.value?.outbounds?.find((o) => o?.tag === 'warp'),
|
|
|
|
|
);
|
|
|
|
|
const nordExist = computed(
|
|
|
|
|
() => !!templateSettings.value?.outbounds?.find((o) => o?.tag?.startsWith?.('nord-')),
|
|
|
|
|
);
|
|
|
|
|
|
feat(frontend): Phase 6-vi — WARP + NordVPN provisioning modals
Replaces the toast stubs on the Basics tab and Outbounds toolbar
with the legacy WARP + NordVPN provisioning flows. Both modals now
stage their wireguard outbounds back into templateSettings.outbounds
through the same event channels OutboundsTab uses, so the existing
add / reset / delete / refresh-traffic surface keeps working.
- WarpModal.vue: empty state shows a single Create button that
generates a wireguard keypair locally (Wireguard.generateKeypair)
and posts it to /panel/xray/warp/reg; populated state surfaces
the access_token / device_id / license_key / private_key, lets
the user upgrade to WARP+ via /panel/xray/warp/license, refreshes
the account info from /panel/xray/warp/config (plan / quota /
usage in human-readable bytes), and stages a wireguard outbound
with the WARP-specific reserved-byte encoding pulled from
client_id. Add / Reset / Delete go through events the parent
routes back to templateSettings.outbounds.
- NordModal.vue: dual-tab login (NordVPN access token →
/panel/xray/nord/reg, or paste a NordLynx private key →
/panel/xray/nord/setKey). Once authenticated, country / city /
server selectors fetch from /panel/xray/nord/{countries,servers},
servers sort by load ascending, the lowest-load server in the
current city auto-selects. Reset emits oldTag/newTag so the
parent renames matching routing rules in place; logout emits a
remove-routing-rules event with prefix `nord-` to purge any
dangling references.
- XrayPage.vue: holds warpOpen / nordOpen flags, ensures the
outbounds array exists before mutating it, and wires the modal
events (add-outbound / reset-outbound / remove-outbound /
remove-routing-rules) to in-place edits of templateSettings.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 12:44:46 +00:00
|
|
|
// === WARP / NordVPN provisioning modals ============================
|
|
|
|
|
const warpOpen = ref(false);
|
|
|
|
|
const nordOpen = ref(false);
|
|
|
|
|
|
|
|
|
|
function showWarp() { warpOpen.value = true; }
|
|
|
|
|
function showNord() { nordOpen.value = true; }
|
|
|
|
|
|
|
|
|
|
function ensureOutbounds() {
|
|
|
|
|
if (!templateSettings.value) return null;
|
|
|
|
|
if (!Array.isArray(templateSettings.value.outbounds)) {
|
|
|
|
|
templateSettings.value.outbounds = [];
|
|
|
|
|
}
|
|
|
|
|
return templateSettings.value.outbounds;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function onAddOutbound(outbound) {
|
|
|
|
|
const list = ensureOutbounds();
|
|
|
|
|
if (list) list.push(outbound);
|
|
|
|
|
}
|
|
|
|
|
function onResetOutbound({ index, outbound, oldTag, newTag }) {
|
|
|
|
|
const list = ensureOutbounds();
|
|
|
|
|
if (!list || index < 0) return;
|
|
|
|
|
list[index] = outbound;
|
|
|
|
|
// Tag rename across routing rules — preserves Nord's
|
|
|
|
|
// server-switch flow without dangling references.
|
|
|
|
|
if (oldTag && newTag && oldTag !== newTag) {
|
|
|
|
|
const rules = templateSettings.value?.routing?.rules || [];
|
|
|
|
|
for (const r of rules) {
|
|
|
|
|
if (r?.outboundTag === oldTag) r.outboundTag = newTag;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
function onRemoveOutboundByTag(tag) {
|
|
|
|
|
const list = ensureOutbounds();
|
|
|
|
|
if (!list) return;
|
|
|
|
|
const idx = list.findIndex((o) => o?.tag === tag);
|
|
|
|
|
if (idx >= 0) list.splice(idx, 1);
|
|
|
|
|
}
|
|
|
|
|
function onRemoveOutboundByIndex(index) {
|
|
|
|
|
const list = ensureOutbounds();
|
|
|
|
|
if (list && index >= 0) list.splice(index, 1);
|
|
|
|
|
}
|
|
|
|
|
function onRemoveRoutingRules({ prefix }) {
|
|
|
|
|
const rules = templateSettings.value?.routing?.rules;
|
|
|
|
|
if (!Array.isArray(rules)) return;
|
|
|
|
|
templateSettings.value.routing.rules = rules.filter(
|
|
|
|
|
(r) => !r?.outboundTag?.startsWith?.(prefix),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// `message` is used by some of the in-progress UX flows (kept around
|
|
|
|
|
// because future provisioning errors will surface through it).
|
|
|
|
|
void message;
|
2026-05-08 12:13:26 +00:00
|
|
|
const { isMobile } = useMediaQuery();
|
|
|
|
|
|
|
|
|
|
const basePath = window.__X_UI_BASE_PATH__ || '';
|
|
|
|
|
const requestUri = window.location.pathname;
|
|
|
|
|
|
2026-05-08 15:20:30 +00:00
|
|
|
// See SettingsPage scrollTarget — wrap so `document` is in scope.
|
|
|
|
|
function scrollTarget() {
|
|
|
|
|
return document.getElementById('content-layout');
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-08 12:13:26 +00:00
|
|
|
function confirmRestart() {
|
|
|
|
|
Modal.confirm({
|
|
|
|
|
title: 'Restart xray?',
|
|
|
|
|
content: 'Reloads the xray service with the saved configuration.',
|
|
|
|
|
okText: 'Restart',
|
|
|
|
|
cancelText: 'Cancel',
|
|
|
|
|
onOk: () => restartXray(),
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<template>
|
|
|
|
|
<a-config-provider :theme="antdThemeConfig">
|
|
|
|
|
<a-layout
|
|
|
|
|
class="xray-page"
|
|
|
|
|
:class="{ 'is-dark': themeState.isDark, 'is-ultra': themeState.isUltra }"
|
|
|
|
|
>
|
|
|
|
|
<AppSidebar :base-path="basePath" :request-uri="requestUri" />
|
|
|
|
|
|
|
|
|
|
<a-layout class="content-shell">
|
|
|
|
|
<a-layout-content id="content-layout" class="content-area">
|
|
|
|
|
<a-spin :spinning="spinning || !fetched" :delay="200" tip="Loading…" size="large">
|
|
|
|
|
<div v-if="!fetched" class="loading-spacer" />
|
|
|
|
|
|
2026-05-08 15:20:30 +00:00
|
|
|
<a-result
|
|
|
|
|
v-else-if="fetchError"
|
|
|
|
|
status="error"
|
|
|
|
|
:title="t('somethingWentWrong')"
|
|
|
|
|
:sub-title="fetchError"
|
|
|
|
|
>
|
|
|
|
|
<template #extra>
|
|
|
|
|
<a-button type="primary" @click="fetchAll">{{ t('check') }}</a-button>
|
|
|
|
|
</template>
|
|
|
|
|
</a-result>
|
|
|
|
|
|
2026-05-08 12:13:26 +00:00
|
|
|
<template v-else>
|
|
|
|
|
<a-row :gutter="[isMobile ? 8 : 16, isMobile ? 0 : 12]">
|
|
|
|
|
<!-- Save / Restart bar -->
|
|
|
|
|
<a-col :span="24">
|
|
|
|
|
<a-card hoverable>
|
|
|
|
|
<a-row class="header-row">
|
|
|
|
|
<a-col :xs="24" :sm="14" class="header-actions">
|
|
|
|
|
<a-space direction="horizontal">
|
|
|
|
|
<a-button type="primary" :disabled="saveDisabled" @click="saveAll">
|
i18n(frontend): translate page chrome — sidebar, save bars, tabs, summary cards
Replaces hardcoded English with t() calls in the components every
user sees on every page load. The translations themselves come from
the existing TOML files via the sync script — no new strings, no
new locale keys.
Per component:
- AppSidebar.vue: 5 menu titles (dashboard / inbounds / settings /
xray / logout). Computed so the sidebar re-renders when the
cookie-driven locale flips on reload.
- IndexPage.vue: Quick actions card title + Logs / Backup / Up-to-
date / Update buttons.
- StatusCard.vue: CPU / Memory / Swap / Storage labels +
logical-processors / frequency tooltips.
- XrayStatusCard.vue: card title + error popover header + Stop /
Restart / Switch xray action labels (kept the v-prefix version
string as-is — it's content, not a label).
- SettingsPage.vue: 5 tab titles + Save / Restart-panel buttons +
unsaved-changes warning.
- XrayPage.vue: 6 tab titles + Save / Restart-xray buttons +
unsaved-changes warning.
- InboundsPage.vue: 5 summary-stat card titles.
- InboundList.vue: 10 column titles (computed for live locale),
Add inbound / General actions buttons + every dropdown menu item,
search placeholder, filter radio labels, popover titles
(disabled / depleted / depleting / online), traffic + info
popover row labels.
Total: ~75 strings localised across 8 files. The remaining English
labels live in the per-tab settings forms, the form modals
(Inbound / Client / Outbound / Rule / Balancer / WARP / Nord), and
the per-row table cell helpers — all incremental work that doesn't
touch infrastructure.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 13:07:41 +00:00
|
|
|
{{ t('pages.xray.save') }}
|
2026-05-08 12:13:26 +00:00
|
|
|
</a-button>
|
|
|
|
|
<a-button type="primary" danger :disabled="!saveDisabled" @click="confirmRestart">
|
i18n(frontend): translate page chrome — sidebar, save bars, tabs, summary cards
Replaces hardcoded English with t() calls in the components every
user sees on every page load. The translations themselves come from
the existing TOML files via the sync script — no new strings, no
new locale keys.
Per component:
- AppSidebar.vue: 5 menu titles (dashboard / inbounds / settings /
xray / logout). Computed so the sidebar re-renders when the
cookie-driven locale flips on reload.
- IndexPage.vue: Quick actions card title + Logs / Backup / Up-to-
date / Update buttons.
- StatusCard.vue: CPU / Memory / Swap / Storage labels +
logical-processors / frequency tooltips.
- XrayStatusCard.vue: card title + error popover header + Stop /
Restart / Switch xray action labels (kept the v-prefix version
string as-is — it's content, not a label).
- SettingsPage.vue: 5 tab titles + Save / Restart-panel buttons +
unsaved-changes warning.
- XrayPage.vue: 6 tab titles + Save / Restart-xray buttons +
unsaved-changes warning.
- InboundsPage.vue: 5 summary-stat card titles.
- InboundList.vue: 10 column titles (computed for live locale),
Add inbound / General actions buttons + every dropdown menu item,
search placeholder, filter radio labels, popover titles
(disabled / depleted / depleting / online), traffic + info
popover row labels.
Total: ~75 strings localised across 8 files. The remaining English
labels live in the per-tab settings forms, the form modals
(Inbound / Client / Outbound / Rule / Balancer / WARP / Nord), and
the per-row table cell helpers — all incremental work that doesn't
touch infrastructure.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 13:07:41 +00:00
|
|
|
{{ t('pages.xray.restart') }}
|
2026-05-08 12:13:26 +00:00
|
|
|
</a-button>
|
|
|
|
|
<a-popover v-if="restartResult" placement="rightTop">
|
|
|
|
|
<template #title>Xray restart output</template>
|
|
|
|
|
<template #content>
|
|
|
|
|
<pre class="restart-result">{{ restartResult }}</pre>
|
|
|
|
|
</template>
|
|
|
|
|
<QuestionCircleOutlined class="restart-icon" />
|
|
|
|
|
</a-popover>
|
|
|
|
|
</a-space>
|
|
|
|
|
</a-col>
|
|
|
|
|
<a-col :xs="24" :sm="10" class="header-info">
|
2026-05-08 15:20:30 +00:00
|
|
|
<a-back-top :target="scrollTarget" :visibility-height="200" />
|
2026-05-08 12:13:26 +00:00
|
|
|
<a-alert
|
|
|
|
|
type="warning"
|
|
|
|
|
show-icon
|
i18n(frontend): translate page chrome — sidebar, save bars, tabs, summary cards
Replaces hardcoded English with t() calls in the components every
user sees on every page load. The translations themselves come from
the existing TOML files via the sync script — no new strings, no
new locale keys.
Per component:
- AppSidebar.vue: 5 menu titles (dashboard / inbounds / settings /
xray / logout). Computed so the sidebar re-renders when the
cookie-driven locale flips on reload.
- IndexPage.vue: Quick actions card title + Logs / Backup / Up-to-
date / Update buttons.
- StatusCard.vue: CPU / Memory / Swap / Storage labels +
logical-processors / frequency tooltips.
- XrayStatusCard.vue: card title + error popover header + Stop /
Restart / Switch xray action labels (kept the v-prefix version
string as-is — it's content, not a label).
- SettingsPage.vue: 5 tab titles + Save / Restart-panel buttons +
unsaved-changes warning.
- XrayPage.vue: 6 tab titles + Save / Restart-xray buttons +
unsaved-changes warning.
- InboundsPage.vue: 5 summary-stat card titles.
- InboundList.vue: 10 column titles (computed for live locale),
Add inbound / General actions buttons + every dropdown menu item,
search placeholder, filter radio labels, popover titles
(disabled / depleted / depleting / online), traffic + info
popover row labels.
Total: ~75 strings localised across 8 files. The remaining English
labels live in the per-tab settings forms, the form modals
(Inbound / Client / Outbound / Rule / Balancer / WARP / Nord), and
the per-row table cell helpers — all incremental work that doesn't
touch infrastructure.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 13:07:41 +00:00
|
|
|
:message="t('pages.settings.infoDesc')"
|
2026-05-08 12:13:26 +00:00
|
|
|
/>
|
|
|
|
|
</a-col>
|
|
|
|
|
</a-row>
|
|
|
|
|
</a-card>
|
|
|
|
|
</a-col>
|
|
|
|
|
|
|
|
|
|
<!-- Tabs -->
|
|
|
|
|
<a-col :span="24">
|
feat(frontend): Phase 6-ii — xray Basics tab structured editor
Replaces the placeholder on the Basics tab with a structured form for
the most-touched fields of the xray template — outbound + routing
strategy, log levels, traffic stat counters, and the "basic routing"
shortcuts (block torrent / IPs / domains, direct IPs / domains, IPv4
forced, WARP / NordVPN routing).
- useXraySetting.js: hoists a parsed `templateSettings` reactive
alongside the JSON string, with two cooperating watches that keep
them in sync. Editing structured fields stringifies into xraySetting
for the dirty-poll + Advanced JSON tab; editing the JSON re-parses
into templateSettings only when valid, so structured tabs stay
readable mid-edit.
- BasicsTab.vue: collapse panels mirror the legacy partial — General,
Statistics, Logs, Basic routing. Every input is a computed v-model
reading/writing into templateSettings; the routing-rule shortcuts
funnel through ruleGetter/ruleSetter which match the legacy
templateRuleGetter/templateRuleSetter behavior (replace-first,
drop-duplicates, pop-the-rule-when-empty). Direct/IPv4 setters
also call syncOutbound() to provision/prune the matching outbound.
- XrayPage.vue: imports BasicsTab + derives `warpExist`/`nordExist`
from the parsed templateSettings. WARP/NordVPN provisioning modals
are still placeholders that toast — those land in 6-v with the
routing/outbound editors.
Default tab flips back to Basics so users land on the structured
editor.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 12:18:21 +00:00
|
|
|
<a-tabs default-active-key="tpl-basic">
|
2026-05-08 12:13:26 +00:00
|
|
|
<a-tab-pane key="tpl-basic" class="tab-pane">
|
|
|
|
|
<template #tab>
|
i18n(frontend): translate page chrome — sidebar, save bars, tabs, summary cards
Replaces hardcoded English with t() calls in the components every
user sees on every page load. The translations themselves come from
the existing TOML files via the sync script — no new strings, no
new locale keys.
Per component:
- AppSidebar.vue: 5 menu titles (dashboard / inbounds / settings /
xray / logout). Computed so the sidebar re-renders when the
cookie-driven locale flips on reload.
- IndexPage.vue: Quick actions card title + Logs / Backup / Up-to-
date / Update buttons.
- StatusCard.vue: CPU / Memory / Swap / Storage labels +
logical-processors / frequency tooltips.
- XrayStatusCard.vue: card title + error popover header + Stop /
Restart / Switch xray action labels (kept the v-prefix version
string as-is — it's content, not a label).
- SettingsPage.vue: 5 tab titles + Save / Restart-panel buttons +
unsaved-changes warning.
- XrayPage.vue: 6 tab titles + Save / Restart-xray buttons +
unsaved-changes warning.
- InboundsPage.vue: 5 summary-stat card titles.
- InboundList.vue: 10 column titles (computed for live locale),
Add inbound / General actions buttons + every dropdown menu item,
search placeholder, filter radio labels, popover titles
(disabled / depleted / depleting / online), traffic + info
popover row labels.
Total: ~75 strings localised across 8 files. The remaining English
labels live in the per-tab settings forms, the form modals
(Inbound / Client / Outbound / Rule / Balancer / WARP / Nord), and
the per-row table cell helpers — all incremental work that doesn't
touch infrastructure.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 13:07:41 +00:00
|
|
|
<SettingOutlined /> <span>{{ t('pages.xray.basicTemplate') }}</span>
|
2026-05-08 12:13:26 +00:00
|
|
|
</template>
|
feat(frontend): Phase 6-ii — xray Basics tab structured editor
Replaces the placeholder on the Basics tab with a structured form for
the most-touched fields of the xray template — outbound + routing
strategy, log levels, traffic stat counters, and the "basic routing"
shortcuts (block torrent / IPs / domains, direct IPs / domains, IPv4
forced, WARP / NordVPN routing).
- useXraySetting.js: hoists a parsed `templateSettings` reactive
alongside the JSON string, with two cooperating watches that keep
them in sync. Editing structured fields stringifies into xraySetting
for the dirty-poll + Advanced JSON tab; editing the JSON re-parses
into templateSettings only when valid, so structured tabs stay
readable mid-edit.
- BasicsTab.vue: collapse panels mirror the legacy partial — General,
Statistics, Logs, Basic routing. Every input is a computed v-model
reading/writing into templateSettings; the routing-rule shortcuts
funnel through ruleGetter/ruleSetter which match the legacy
templateRuleGetter/templateRuleSetter behavior (replace-first,
drop-duplicates, pop-the-rule-when-empty). Direct/IPv4 setters
also call syncOutbound() to provision/prune the matching outbound.
- XrayPage.vue: imports BasicsTab + derives `warpExist`/`nordExist`
from the parsed templateSettings. WARP/NordVPN provisioning modals
are still placeholders that toast — those land in 6-v with the
routing/outbound editors.
Default tab flips back to Basics so users land on the structured
editor.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 12:18:21 +00:00
|
|
|
<BasicsTab
|
|
|
|
|
:template-settings="templateSettings"
|
|
|
|
|
:outbound-test-url="outboundTestUrl"
|
|
|
|
|
:warp-exist="warpExist"
|
|
|
|
|
:nord-exist="nordExist"
|
|
|
|
|
@update:outbound-test-url="(v) => (outboundTestUrl = v)"
|
|
|
|
|
@show-warp="showWarp"
|
|
|
|
|
@show-nord="showNord"
|
feat(frontend): xray tab fixes — modal close, tag validation, full XHTTP, reset to default
Modal close: BalancersTab / OutboundsTab / RoutingTab confirmDelete used
arrow expressions that returned splice's removed-items array. AD-Vue 4
treats truthy non-thenables from onOk as "still pending" and never closes
the dialog (see ActionButton.js:103-106), so the confirm modal stayed
open. Wrap the body so onOk returns undefined and AD-Vue auto-closes.
Tag validation: outbound + balancer modals only flipped between
warning/success on duplicate, leaving the empty case as a green ✓.
Split into a 3-state computed — error (empty) / warning (duplicate) /
success — and wire a help message so the input clearly explains why
the OK button is disabled.
Reset to default: re-add the legacy "Reset to Default" panel at the
bottom of BasicsTab. Calls /panel/setting/getDefaultJsonConfig and
overwrites templateSettings; the existing watch re-stringifies so the
JSON tab + dirty-poll see the new state.
Restored Basics option lists from main: IPs (4→10, +Vietnam/Spain/
Indonesia/Ukraine/Türkiye/Brazil), DomainsOptions (4→10, +regex
entries), BlockDomainsOptions (5→17, +Malware/Phishing/Adult/regex),
ServicesOptions (Reddit/Speedtest in, off-template Microsoft out).
Outbound form parity with main:
• Reverse Sniffing UI for VLESS — toggle + destOverride checkboxes
(HTTP/TLS/QUIC/FAKEDNS) + Metadata/Route Only + IPs/Domains
excluded multi-selects, gated on reverseTag being set.
• Full XHTTP transport — request headers list, Max Upload Size /
Min Upload Interval (packet-up), Padding Obfs Mode + sub-fields,
Uplink HTTP Method, Session/Sequence/UplinkData placement +
keys, No gRPC Header (stream-up/stream-one), expanded XMUX with
Max Concurrency/Connections/Reuse/Request/Reusable/Keep-alive.
Strip a-divider from the outbound form per request — replaced with
plain section/item heading divs so the labels and per-row delete
icons stay but the horizontal rule is gone.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 19:47:22 +00:00
|
|
|
@reset-default="resetToDefault"
|
feat(frontend): Phase 6-ii — xray Basics tab structured editor
Replaces the placeholder on the Basics tab with a structured form for
the most-touched fields of the xray template — outbound + routing
strategy, log levels, traffic stat counters, and the "basic routing"
shortcuts (block torrent / IPs / domains, direct IPs / domains, IPv4
forced, WARP / NordVPN routing).
- useXraySetting.js: hoists a parsed `templateSettings` reactive
alongside the JSON string, with two cooperating watches that keep
them in sync. Editing structured fields stringifies into xraySetting
for the dirty-poll + Advanced JSON tab; editing the JSON re-parses
into templateSettings only when valid, so structured tabs stay
readable mid-edit.
- BasicsTab.vue: collapse panels mirror the legacy partial — General,
Statistics, Logs, Basic routing. Every input is a computed v-model
reading/writing into templateSettings; the routing-rule shortcuts
funnel through ruleGetter/ruleSetter which match the legacy
templateRuleGetter/templateRuleSetter behavior (replace-first,
drop-duplicates, pop-the-rule-when-empty). Direct/IPv4 setters
also call syncOutbound() to provision/prune the matching outbound.
- XrayPage.vue: imports BasicsTab + derives `warpExist`/`nordExist`
from the parsed templateSettings. WARP/NordVPN provisioning modals
are still placeholders that toast — those land in 6-v with the
routing/outbound editors.
Default tab flips back to Basics so users land on the structured
editor.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 12:18:21 +00:00
|
|
|
/>
|
2026-05-08 12:13:26 +00:00
|
|
|
</a-tab-pane>
|
|
|
|
|
|
|
|
|
|
<a-tab-pane key="tpl-routing" class="tab-pane">
|
|
|
|
|
<template #tab>
|
i18n(frontend): translate page chrome — sidebar, save bars, tabs, summary cards
Replaces hardcoded English with t() calls in the components every
user sees on every page load. The translations themselves come from
the existing TOML files via the sync script — no new strings, no
new locale keys.
Per component:
- AppSidebar.vue: 5 menu titles (dashboard / inbounds / settings /
xray / logout). Computed so the sidebar re-renders when the
cookie-driven locale flips on reload.
- IndexPage.vue: Quick actions card title + Logs / Backup / Up-to-
date / Update buttons.
- StatusCard.vue: CPU / Memory / Swap / Storage labels +
logical-processors / frequency tooltips.
- XrayStatusCard.vue: card title + error popover header + Stop /
Restart / Switch xray action labels (kept the v-prefix version
string as-is — it's content, not a label).
- SettingsPage.vue: 5 tab titles + Save / Restart-panel buttons +
unsaved-changes warning.
- XrayPage.vue: 6 tab titles + Save / Restart-xray buttons +
unsaved-changes warning.
- InboundsPage.vue: 5 summary-stat card titles.
- InboundList.vue: 10 column titles (computed for live locale),
Add inbound / General actions buttons + every dropdown menu item,
search placeholder, filter radio labels, popover titles
(disabled / depleted / depleting / online), traffic + info
popover row labels.
Total: ~75 strings localised across 8 files. The remaining English
labels live in the per-tab settings forms, the form modals
(Inbound / Client / Outbound / Rule / Balancer / WARP / Nord), and
the per-row table cell helpers — all incremental work that doesn't
touch infrastructure.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 13:07:41 +00:00
|
|
|
<SwapOutlined /> <span>{{ t('pages.xray.Routings') }}</span>
|
2026-05-08 12:13:26 +00:00
|
|
|
</template>
|
2026-05-08 12:23:02 +00:00
|
|
|
<RoutingTab
|
|
|
|
|
:template-settings="templateSettings"
|
|
|
|
|
:inbound-tags="inboundTags"
|
|
|
|
|
:client-reverse-tags="clientReverseTags"
|
|
|
|
|
:is-mobile="isMobile"
|
|
|
|
|
/>
|
2026-05-08 12:13:26 +00:00
|
|
|
</a-tab-pane>
|
|
|
|
|
|
|
|
|
|
<a-tab-pane key="tpl-outbound" class="tab-pane">
|
|
|
|
|
<template #tab>
|
i18n(frontend): translate page chrome — sidebar, save bars, tabs, summary cards
Replaces hardcoded English with t() calls in the components every
user sees on every page load. The translations themselves come from
the existing TOML files via the sync script — no new strings, no
new locale keys.
Per component:
- AppSidebar.vue: 5 menu titles (dashboard / inbounds / settings /
xray / logout). Computed so the sidebar re-renders when the
cookie-driven locale flips on reload.
- IndexPage.vue: Quick actions card title + Logs / Backup / Up-to-
date / Update buttons.
- StatusCard.vue: CPU / Memory / Swap / Storage labels +
logical-processors / frequency tooltips.
- XrayStatusCard.vue: card title + error popover header + Stop /
Restart / Switch xray action labels (kept the v-prefix version
string as-is — it's content, not a label).
- SettingsPage.vue: 5 tab titles + Save / Restart-panel buttons +
unsaved-changes warning.
- XrayPage.vue: 6 tab titles + Save / Restart-xray buttons +
unsaved-changes warning.
- InboundsPage.vue: 5 summary-stat card titles.
- InboundList.vue: 10 column titles (computed for live locale),
Add inbound / General actions buttons + every dropdown menu item,
search placeholder, filter radio labels, popover titles
(disabled / depleted / depleting / online), traffic + info
popover row labels.
Total: ~75 strings localised across 8 files. The remaining English
labels live in the per-tab settings forms, the form modals
(Inbound / Client / Outbound / Rule / Balancer / WARP / Nord), and
the per-row table cell helpers — all incremental work that doesn't
touch infrastructure.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 13:07:41 +00:00
|
|
|
<UploadOutlined /> <span>{{ t('pages.xray.Outbounds') }}</span>
|
2026-05-08 12:13:26 +00:00
|
|
|
</template>
|
2026-05-08 12:27:40 +00:00
|
|
|
<OutboundsTab
|
|
|
|
|
:template-settings="templateSettings"
|
|
|
|
|
:outbounds-traffic="outboundsTraffic"
|
|
|
|
|
:outbound-test-states="outboundTestStates"
|
|
|
|
|
:is-mobile="isMobile"
|
|
|
|
|
@refresh-traffic="fetchOutboundsTraffic"
|
|
|
|
|
@reset-traffic="resetOutboundsTraffic"
|
|
|
|
|
@test="onTestOutbound"
|
|
|
|
|
@show-warp="showWarp"
|
|
|
|
|
@show-nord="showNord"
|
|
|
|
|
/>
|
2026-05-08 12:13:26 +00:00
|
|
|
</a-tab-pane>
|
|
|
|
|
|
|
|
|
|
<a-tab-pane key="tpl-balancer" class="tab-pane">
|
|
|
|
|
<template #tab>
|
i18n(frontend): translate page chrome — sidebar, save bars, tabs, summary cards
Replaces hardcoded English with t() calls in the components every
user sees on every page load. The translations themselves come from
the existing TOML files via the sync script — no new strings, no
new locale keys.
Per component:
- AppSidebar.vue: 5 menu titles (dashboard / inbounds / settings /
xray / logout). Computed so the sidebar re-renders when the
cookie-driven locale flips on reload.
- IndexPage.vue: Quick actions card title + Logs / Backup / Up-to-
date / Update buttons.
- StatusCard.vue: CPU / Memory / Swap / Storage labels +
logical-processors / frequency tooltips.
- XrayStatusCard.vue: card title + error popover header + Stop /
Restart / Switch xray action labels (kept the v-prefix version
string as-is — it's content, not a label).
- SettingsPage.vue: 5 tab titles + Save / Restart-panel buttons +
unsaved-changes warning.
- XrayPage.vue: 6 tab titles + Save / Restart-xray buttons +
unsaved-changes warning.
- InboundsPage.vue: 5 summary-stat card titles.
- InboundList.vue: 10 column titles (computed for live locale),
Add inbound / General actions buttons + every dropdown menu item,
search placeholder, filter radio labels, popover titles
(disabled / depleted / depleting / online), traffic + info
popover row labels.
Total: ~75 strings localised across 8 files. The remaining English
labels live in the per-tab settings forms, the form modals
(Inbound / Client / Outbound / Rule / Balancer / WARP / Nord), and
the per-row table cell helpers — all incremental work that doesn't
touch infrastructure.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 13:07:41 +00:00
|
|
|
<ClusterOutlined /> <span>{{ t('pages.xray.Balancers') }}</span>
|
2026-05-08 12:13:26 +00:00
|
|
|
</template>
|
2026-05-08 12:30:48 +00:00
|
|
|
<BalancersTab :template-settings="templateSettings" />
|
2026-05-08 12:13:26 +00:00
|
|
|
</a-tab-pane>
|
|
|
|
|
|
|
|
|
|
<a-tab-pane key="tpl-dns" class="tab-pane">
|
|
|
|
|
<template #tab>
|
|
|
|
|
<DatabaseOutlined /> <span>DNS</span>
|
|
|
|
|
</template>
|
2026-05-08 12:30:48 +00:00
|
|
|
<DnsTab :template-settings="templateSettings" />
|
2026-05-08 12:13:26 +00:00
|
|
|
</a-tab-pane>
|
|
|
|
|
|
|
|
|
|
<a-tab-pane key="tpl-advanced" class="tab-pane">
|
|
|
|
|
<template #tab>
|
i18n(frontend): translate page chrome — sidebar, save bars, tabs, summary cards
Replaces hardcoded English with t() calls in the components every
user sees on every page load. The translations themselves come from
the existing TOML files via the sync script — no new strings, no
new locale keys.
Per component:
- AppSidebar.vue: 5 menu titles (dashboard / inbounds / settings /
xray / logout). Computed so the sidebar re-renders when the
cookie-driven locale flips on reload.
- IndexPage.vue: Quick actions card title + Logs / Backup / Up-to-
date / Update buttons.
- StatusCard.vue: CPU / Memory / Swap / Storage labels +
logical-processors / frequency tooltips.
- XrayStatusCard.vue: card title + error popover header + Stop /
Restart / Switch xray action labels (kept the v-prefix version
string as-is — it's content, not a label).
- SettingsPage.vue: 5 tab titles + Save / Restart-panel buttons +
unsaved-changes warning.
- XrayPage.vue: 6 tab titles + Save / Restart-xray buttons +
unsaved-changes warning.
- InboundsPage.vue: 5 summary-stat card titles.
- InboundList.vue: 10 column titles (computed for live locale),
Add inbound / General actions buttons + every dropdown menu item,
search placeholder, filter radio labels, popover titles
(disabled / depleted / depleting / online), traffic + info
popover row labels.
Total: ~75 strings localised across 8 files. The remaining English
labels live in the per-tab settings forms, the form modals
(Inbound / Client / Outbound / Rule / Balancer / WARP / Nord), and
the per-row table cell helpers — all incremental work that doesn't
touch infrastructure.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 13:07:41 +00:00
|
|
|
<CodeOutlined /> <span>{{ t('pages.xray.advancedTemplate') }}</span>
|
2026-05-08 12:13:26 +00:00
|
|
|
</template>
|
|
|
|
|
<a-form layout="vertical">
|
|
|
|
|
<a-form-item label="xraySetting (full JSON)">
|
|
|
|
|
<a-textarea
|
|
|
|
|
v-model:value="xraySetting"
|
|
|
|
|
:auto-size="{ minRows: 18, maxRows: 40 }"
|
|
|
|
|
spellcheck="false"
|
|
|
|
|
class="json-editor"
|
|
|
|
|
/>
|
|
|
|
|
</a-form-item>
|
|
|
|
|
</a-form>
|
|
|
|
|
</a-tab-pane>
|
|
|
|
|
</a-tabs>
|
|
|
|
|
</a-col>
|
|
|
|
|
</a-row>
|
|
|
|
|
</template>
|
|
|
|
|
</a-spin>
|
|
|
|
|
</a-layout-content>
|
|
|
|
|
</a-layout>
|
feat(frontend): Phase 6-vi — WARP + NordVPN provisioning modals
Replaces the toast stubs on the Basics tab and Outbounds toolbar
with the legacy WARP + NordVPN provisioning flows. Both modals now
stage their wireguard outbounds back into templateSettings.outbounds
through the same event channels OutboundsTab uses, so the existing
add / reset / delete / refresh-traffic surface keeps working.
- WarpModal.vue: empty state shows a single Create button that
generates a wireguard keypair locally (Wireguard.generateKeypair)
and posts it to /panel/xray/warp/reg; populated state surfaces
the access_token / device_id / license_key / private_key, lets
the user upgrade to WARP+ via /panel/xray/warp/license, refreshes
the account info from /panel/xray/warp/config (plan / quota /
usage in human-readable bytes), and stages a wireguard outbound
with the WARP-specific reserved-byte encoding pulled from
client_id. Add / Reset / Delete go through events the parent
routes back to templateSettings.outbounds.
- NordModal.vue: dual-tab login (NordVPN access token →
/panel/xray/nord/reg, or paste a NordLynx private key →
/panel/xray/nord/setKey). Once authenticated, country / city /
server selectors fetch from /panel/xray/nord/{countries,servers},
servers sort by load ascending, the lowest-load server in the
current city auto-selects. Reset emits oldTag/newTag so the
parent renames matching routing rules in place; logout emits a
remove-routing-rules event with prefix `nord-` to purge any
dangling references.
- XrayPage.vue: holds warpOpen / nordOpen flags, ensures the
outbounds array exists before mutating it, and wires the modal
events (add-outbound / reset-outbound / remove-outbound /
remove-routing-rules) to in-place edits of templateSettings.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 12:44:46 +00:00
|
|
|
|
|
|
|
|
<WarpModal
|
|
|
|
|
v-model:open="warpOpen"
|
|
|
|
|
:template-settings="templateSettings"
|
|
|
|
|
@add-outbound="onAddOutbound"
|
|
|
|
|
@reset-outbound="onResetOutbound"
|
|
|
|
|
@remove-outbound="onRemoveOutboundByTag"
|
|
|
|
|
/>
|
|
|
|
|
<NordModal
|
|
|
|
|
v-model:open="nordOpen"
|
|
|
|
|
:template-settings="templateSettings"
|
|
|
|
|
@add-outbound="onAddOutbound"
|
|
|
|
|
@reset-outbound="onResetOutbound"
|
|
|
|
|
@remove-outbound="onRemoveOutboundByIndex"
|
|
|
|
|
@remove-routing-rules="onRemoveRoutingRules"
|
|
|
|
|
/>
|
2026-05-08 12:13:26 +00:00
|
|
|
</a-layout>
|
|
|
|
|
</a-config-provider>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
|
.xray-page {
|
2026-05-08 16:41:59 +00:00
|
|
|
--bg-page: #e6e8ec;
|
2026-05-08 12:13:26 +00:00
|
|
|
--bg-card: #ffffff;
|
|
|
|
|
|
|
|
|
|
min-height: 100vh;
|
|
|
|
|
background: var(--bg-page);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.xray-page.is-dark {
|
|
|
|
|
--bg-page: #0a1222;
|
|
|
|
|
--bg-card: #151f31;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.xray-page.is-dark.is-ultra {
|
|
|
|
|
--bg-page: #21242a;
|
|
|
|
|
--bg-card: #0c0e12;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.xray-page :deep(.ant-layout),
|
|
|
|
|
.xray-page :deep(.ant-layout-content) {
|
|
|
|
|
background: transparent;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.content-shell { background: transparent; }
|
|
|
|
|
.content-area { padding: 24px; }
|
|
|
|
|
|
|
|
|
|
.loading-spacer { min-height: calc(100vh - 120px); }
|
|
|
|
|
|
|
|
|
|
.header-row {
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-wrap: wrap;
|
|
|
|
|
align-items: center;
|
|
|
|
|
}
|
|
|
|
|
.header-actions { padding: 4px; }
|
|
|
|
|
.header-info {
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: flex-end;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.tab-pane { padding-top: 20px; }
|
|
|
|
|
|
|
|
|
|
.restart-icon {
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
color: var(--ant-primary-color, #1890ff);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.restart-result {
|
|
|
|
|
max-width: 480px;
|
|
|
|
|
white-space: pre-wrap;
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
margin: 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.json-editor {
|
|
|
|
|
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
}
|
|
|
|
|
</style>
|