2026-05-08 11:32:44 +00:00
|
|
|
<script setup>
|
fix(frontend): Phase 9 — restore index dashboard, fix login/CSRF, port legacy styles
- Index dashboard regains the 8 cards that were lost in the SPA port
(3X-UI panel info, Operation Hours, System Load, Usage, Overall Speed,
Total Data, IP Addresses, Connection Stats), plus a Config button that
shows the live xray config.json. Version display falls back through
panelUpdateInfo → window.__X_UI_CUR_VER__ → '?' so dev mode isn't blank.
- Xray config no longer hangs on load: useXraySetting surfaces failures
instead of leaving a perpetual spinner, and the Vite dev proxy stops
hijacking POST requests to migrated routes (only GETs get bypassed).
- Inbound page no longer throws __asyncLoader/emitsOptions errors —
inbound.js was missing imports (NumberFormatter, SizeFormatter,
Wireguard) and InboundList kept emitting after unmount.
- Login round-trip works after logout: a public /csrf-token endpoint
bootstraps the SPA before authentication, axios caches the token
module-level, and the dev 401 handler navigates to /login.html
instead of reloading the dashboard into a redirect loop.
- legacy.css mirrors the legacy panel's surface/text variables so dark
and ultra-dark themes match main; every SPA entry imports it.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 15:21:03 +00:00
|
|
|
import { computed, onBeforeUnmount, ref, watch } 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 11:32:44 +00:00
|
|
|
import {
|
|
|
|
|
PlusOutlined,
|
|
|
|
|
MenuOutlined,
|
|
|
|
|
SyncOutlined,
|
|
|
|
|
DownOutlined,
|
|
|
|
|
SearchOutlined,
|
|
|
|
|
FilterOutlined,
|
|
|
|
|
MoreOutlined,
|
|
|
|
|
EditOutlined,
|
|
|
|
|
QrcodeOutlined,
|
|
|
|
|
UserAddOutlined,
|
|
|
|
|
UsergroupAddOutlined,
|
|
|
|
|
CopyOutlined,
|
|
|
|
|
FileDoneOutlined,
|
|
|
|
|
ExportOutlined,
|
|
|
|
|
ImportOutlined,
|
|
|
|
|
ReloadOutlined,
|
|
|
|
|
RestOutlined,
|
|
|
|
|
RetweetOutlined,
|
|
|
|
|
BlockOutlined,
|
|
|
|
|
DeleteOutlined,
|
|
|
|
|
InfoCircleOutlined,
|
|
|
|
|
} from '@ant-design/icons-vue';
|
|
|
|
|
|
|
|
|
|
import { HttpUtil, ObjectUtil, SizeFormatter, IntlUtil, ColorUtils } from '@/utils';
|
|
|
|
|
import { DBInbound } from '@/models/dbinbound.js';
|
|
|
|
|
import { Inbound } from '@/models/inbound.js';
|
fix(frontend): redesign expand-row + retheme client visuals
When you expanded an inbound row, the nested <a-table> inside
ClientRowTable burst out of the parent's scroll-x box — its
.ant-spin-container ended up wider than the parent's narrow
.ant-table-cell, so the child looked oversized while the parent looked
squeezed. Replace the nested table with a CSS-grid layout that owns
its sizing, sits flush inside the expanded cell, and collapses to a
3-column layout on mobile (action menu, client identity, info popover).
While in there, fix three other client-row visuals:
- The Unicode infinity glyph (U+221E) renders as an "m"-shaped
character in some system fonts (Windows Segoe UI in particular).
Add a shared <InfinityIcon /> SVG component (legacy panel's path)
and use it in ClientRowTable, InboundList, and InboundInfoModal —
desktop and mobile cells.
- The "unlimited quota" traffic bar passed :percent="100" with no
stroke-color, so AD-Vue auto-coloured it success-green. Pin it to
the AD-Vue purple token (#722ed1) so it reads as the no-limit
sentinel rather than another usage state.
- ColorUtils + the in-row statsExpColor still hardcoded the legacy
teal/orange/red/purple palette (#008771 / #f37b24 / #cf3c3c /
#7a316f). Map them onto AD-Vue 4's success/warning/danger/purple
tokens (#52c41a / #faad14 / #ff4d4f / #722ed1) so badges, tags,
and progress bars all match the rest of the panel.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 16:32:37 +00:00
|
|
|
import InfinityIcon from '@/components/InfinityIcon.vue';
|
2026-05-08 12:00:39 +00:00
|
|
|
import ClientRowTable from './ClientRowTable.vue';
|
2026-05-08 22:34:07 +00:00
|
|
|
import { useDatepicker } from '@/composables/useDatepicker.js';
|
|
|
|
|
|
|
|
|
|
const { datepicker } = useDatepicker();
|
2026-05-08 11:32:44 +00:00
|
|
|
|
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 11:32:44 +00:00
|
|
|
const props = defineProps({
|
|
|
|
|
dbInbounds: { type: Array, required: true },
|
|
|
|
|
clientCount: { type: Object, required: true },
|
|
|
|
|
onlineClients: { type: Array, required: true },
|
2026-05-08 12:00:39 +00:00
|
|
|
lastOnlineMap: { type: Object, default: () => ({}) },
|
2026-05-08 11:32:44 +00:00
|
|
|
refreshing: { type: Boolean, default: false },
|
|
|
|
|
expireDiff: { type: Number, default: 0 },
|
|
|
|
|
trafficDiff: { type: Number, default: 0 },
|
|
|
|
|
pageSize: { type: Number, default: 0 },
|
|
|
|
|
isMobile: { type: Boolean, default: false },
|
2026-05-08 12:00:39 +00:00
|
|
|
isDarkTheme: { type: Boolean, default: false },
|
2026-05-08 11:32:44 +00:00
|
|
|
subEnable: { type: Boolean, default: false },
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const emit = defineEmits([
|
|
|
|
|
'refresh',
|
|
|
|
|
'add-inbound',
|
|
|
|
|
'general-action',
|
|
|
|
|
'row-action',
|
2026-05-08 12:00:39 +00:00
|
|
|
// Per-client events surfaced from the expand-row table.
|
|
|
|
|
'edit-client',
|
|
|
|
|
'qrcode-client',
|
|
|
|
|
'info-client',
|
|
|
|
|
'reset-traffic-client',
|
|
|
|
|
'delete-client',
|
|
|
|
|
'toggle-enable-client',
|
2026-05-08 11:32:44 +00:00
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
// ============ Toolbar / search & filter =============================
|
|
|
|
|
const enableFilter = ref(false);
|
|
|
|
|
const searchKey = ref('');
|
|
|
|
|
const filterBy = ref('');
|
|
|
|
|
|
|
|
|
|
// Auto-refresh — same defaults as legacy (5s, opt-in via switch).
|
|
|
|
|
const isRefreshEnabled = ref(localStorage.getItem('isRefreshEnabled') === 'true');
|
|
|
|
|
const refreshIntervalMs = ref(Number(localStorage.getItem('refreshInterval')) || 5000);
|
|
|
|
|
|
|
|
|
|
let timer = null;
|
|
|
|
|
function startAutoRefresh() {
|
|
|
|
|
stopAutoRefresh();
|
|
|
|
|
timer = setInterval(() => emit('refresh'), refreshIntervalMs.value);
|
|
|
|
|
}
|
|
|
|
|
function stopAutoRefresh() {
|
|
|
|
|
if (timer != null) {
|
|
|
|
|
clearInterval(timer);
|
|
|
|
|
timer = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
watch(isRefreshEnabled, (next) => {
|
|
|
|
|
localStorage.setItem('isRefreshEnabled', String(next));
|
|
|
|
|
if (next) startAutoRefresh();
|
|
|
|
|
else stopAutoRefresh();
|
|
|
|
|
}, { immediate: true });
|
|
|
|
|
watch(refreshIntervalMs, (next) => {
|
|
|
|
|
localStorage.setItem('refreshInterval', String(next));
|
|
|
|
|
if (isRefreshEnabled.value) startAutoRefresh();
|
|
|
|
|
});
|
fix(frontend): Phase 9 — restore index dashboard, fix login/CSRF, port legacy styles
- Index dashboard regains the 8 cards that were lost in the SPA port
(3X-UI panel info, Operation Hours, System Load, Usage, Overall Speed,
Total Data, IP Addresses, Connection Stats), plus a Config button that
shows the live xray config.json. Version display falls back through
panelUpdateInfo → window.__X_UI_CUR_VER__ → '?' so dev mode isn't blank.
- Xray config no longer hangs on load: useXraySetting surfaces failures
instead of leaving a perpetual spinner, and the Vite dev proxy stops
hijacking POST requests to migrated routes (only GETs get bypassed).
- Inbound page no longer throws __asyncLoader/emitsOptions errors —
inbound.js was missing imports (NumberFormatter, SizeFormatter,
Wireguard) and InboundList kept emitting after unmount.
- Login round-trip works after logout: a public /csrf-token endpoint
bootstraps the SPA before authentication, axios caches the token
module-level, and the dev 401 handler navigates to /login.html
instead of reloading the dashboard into a redirect loop.
- legacy.css mirrors the legacy panel's surface/text variables so dark
and ultra-dark themes match main; every SPA entry imports it.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 15:21:03 +00:00
|
|
|
// Without this, a stale setInterval keeps firing emit('refresh') after
|
|
|
|
|
// the component unmounts, which Vue surfaces as "emitsOptions" /
|
|
|
|
|
// "__asyncLoader" exceptions on the next tick.
|
|
|
|
|
onBeforeUnmount(stopAutoRefresh);
|
2026-05-08 11:32:44 +00:00
|
|
|
|
|
|
|
|
// Toggle the filter mode — flip cleans the other input.
|
|
|
|
|
function onToggleFilter() {
|
|
|
|
|
if (enableFilter.value) searchKey.value = '';
|
|
|
|
|
else filterBy.value = '';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ============ Search / filter projection =============================
|
|
|
|
|
// Mirrors the legacy logic: when searching, keep inbounds that match
|
|
|
|
|
// anywhere (deep search); when filtering, keep inbounds that have at
|
|
|
|
|
// least one client in the requested bucket and reduce their settings
|
|
|
|
|
// to that bucket.
|
|
|
|
|
function projectInbound(dbInbound, predicate) {
|
|
|
|
|
const next = new DBInbound(dbInbound);
|
|
|
|
|
let settings = {};
|
|
|
|
|
try {
|
|
|
|
|
settings = JSON.parse(dbInbound.settings || '{}');
|
|
|
|
|
} catch (_e) {
|
|
|
|
|
settings = {};
|
|
|
|
|
}
|
|
|
|
|
if (!Array.isArray(settings.clients)) return next;
|
|
|
|
|
const filtered = settings.clients.filter(predicate);
|
|
|
|
|
next.settings = Inbound.Settings.fromJson(dbInbound.protocol, { clients: filtered });
|
|
|
|
|
next.invalidateCache();
|
|
|
|
|
return next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const visibleInbounds = computed(() => {
|
|
|
|
|
if (enableFilter.value) {
|
|
|
|
|
if (ObjectUtil.isEmpty(filterBy.value)) return [...props.dbInbounds];
|
|
|
|
|
const out = [];
|
|
|
|
|
for (const dbInbound of props.dbInbounds) {
|
|
|
|
|
const c = props.clientCount[dbInbound.id];
|
|
|
|
|
if (!c || !c[filterBy.value] || c[filterBy.value].length === 0) continue;
|
|
|
|
|
const list = c[filterBy.value];
|
|
|
|
|
out.push(projectInbound(dbInbound, (client) => list.includes(client.email)));
|
|
|
|
|
}
|
|
|
|
|
return out;
|
|
|
|
|
}
|
|
|
|
|
if (ObjectUtil.isEmpty(searchKey.value)) return [...props.dbInbounds];
|
|
|
|
|
const out = [];
|
|
|
|
|
for (const dbInbound of props.dbInbounds) {
|
|
|
|
|
if (!ObjectUtil.deepSearch(dbInbound, searchKey.value)) continue;
|
|
|
|
|
out.push(projectInbound(dbInbound, (client) => ObjectUtil.deepSearch(client, searchKey.value)));
|
|
|
|
|
}
|
|
|
|
|
return out;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// ============ Columns =================================================
|
|
|
|
|
// `key`-driven so we can render via the body-cell slot below. AD-Vue 4's
|
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
|
|
|
// `responsive` array still works on column defs. Computed so column
|
|
|
|
|
// labels react to live locale switches.
|
|
|
|
|
const desktopColumns = computed(() => [
|
2026-05-08 11:32:44 +00:00
|
|
|
{ title: 'ID', dataIndex: 'id', key: 'id', align: 'right', width: 30, responsive: ['xs'] },
|
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
|
|
|
{ title: t('pages.inbounds.operate'), key: 'action', align: 'center', width: 30 },
|
|
|
|
|
{ title: t('pages.inbounds.enable'), key: 'enable', align: 'center', width: 35 },
|
|
|
|
|
{ title: t('pages.inbounds.remark'), dataIndex: 'remark', key: 'remark', align: 'center', width: 60 },
|
|
|
|
|
{ title: t('pages.inbounds.port'), dataIndex: 'port', key: 'port', align: 'center', width: 40 },
|
feat(frontend): inbound modal QR + tabs + restored TLS fallbacks
Per-client QR action: the qr icon on the expand-row table opened the
big info modal instead of the QR modal. Route it to QrCodeModal and
extend that modal with a `client` prop so genAllLinks() produces the
per-client share URLs (and per-peer remarks for WireGuard).
Inbound's Data redesign: split the dense single-page view into three
tabs — Inbound, Client, Subscription. Drop every QR rendering from
this modal (QrCodeModal is the QR home now). Each row in the Inbound
tab is one label/value pair instead of the legacy 2-column grid, and
long values like the VLESS encryption blob render as a wrapping code
block with a copy button so they can't blow out the dialog. The
Subscription tab renders sub URL + JSON URL as clickable anchors that
open in a new tab.
Restored TLS fallbacks UI: the model already exposed
VLESSSettings.Fallback / TrojanSettings.Fallback with addFallback /
delFallback / fallbackToJson, but the form modal never surfaced them
during the Vue 3 migration. Re-add the legacy form (SNI, ALPN, Path,
Destination, PROXY) on the protocol tab, gated on TCP transport plus
(for VLESS) encryption=none — same conditions as main.
Column widths: Protocol 70→130 and All-time Traffic 60→95 in the
inbound list; All-time Traffic 90→130 in the client expand-row, so
the header text fits and tags don't get squeezed.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 17:45:14 +00:00
|
|
|
{ title: t('pages.inbounds.protocol'), key: 'protocol', align: 'left', width: 130 },
|
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
|
|
|
{ title: t('clients'), key: 'clients', align: 'left', width: 50 },
|
|
|
|
|
{ title: t('pages.inbounds.traffic'), key: 'traffic', align: 'center', width: 90 },
|
feat(frontend): inbound modal QR + tabs + restored TLS fallbacks
Per-client QR action: the qr icon on the expand-row table opened the
big info modal instead of the QR modal. Route it to QrCodeModal and
extend that modal with a `client` prop so genAllLinks() produces the
per-client share URLs (and per-peer remarks for WireGuard).
Inbound's Data redesign: split the dense single-page view into three
tabs — Inbound, Client, Subscription. Drop every QR rendering from
this modal (QrCodeModal is the QR home now). Each row in the Inbound
tab is one label/value pair instead of the legacy 2-column grid, and
long values like the VLESS encryption blob render as a wrapping code
block with a copy button so they can't blow out the dialog. The
Subscription tab renders sub URL + JSON URL as clickable anchors that
open in a new tab.
Restored TLS fallbacks UI: the model already exposed
VLESSSettings.Fallback / TrojanSettings.Fallback with addFallback /
delFallback / fallbackToJson, but the form modal never surfaced them
during the Vue 3 migration. Re-add the legacy form (SNI, ALPN, Path,
Destination, PROXY) on the protocol tab, gated on TCP transport plus
(for VLESS) encryption=none — same conditions as main.
Column widths: Protocol 70→130 and All-time Traffic 60→95 in the
inbound list; All-time Traffic 90→130 in the client expand-row, so
the header text fits and tags don't get squeezed.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 17:45:14 +00:00
|
|
|
{ title: t('pages.inbounds.allTimeTraffic'), key: 'allTimeInbound', align: 'center', width: 95 },
|
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
|
|
|
{ title: t('pages.inbounds.expireDate'), key: 'expiryTime', align: 'center', width: 40 },
|
|
|
|
|
]);
|
|
|
|
|
const mobileColumns = computed(() => [
|
2026-05-08 11:32:44 +00:00
|
|
|
{ title: 'ID', dataIndex: 'id', key: 'id', align: 'right', width: 10, responsive: ['s'] },
|
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
|
|
|
{ title: t('pages.inbounds.operate'), key: 'action', align: 'center', width: 25 },
|
|
|
|
|
{ title: t('pages.inbounds.remark'), dataIndex: 'remark', key: 'remark', align: 'left', width: 70 },
|
|
|
|
|
{ title: t('info'), key: 'info', align: 'center', width: 10 },
|
|
|
|
|
]);
|
|
|
|
|
const columns = computed(() => (props.isMobile ? mobileColumns.value : desktopColumns.value));
|
2026-05-08 11:32:44 +00:00
|
|
|
|
|
|
|
|
// ============ Pagination ============================================
|
|
|
|
|
function paginationFor(rows) {
|
|
|
|
|
const size = props.pageSize > 0 ? props.pageSize : rows.length || 1;
|
|
|
|
|
return {
|
|
|
|
|
pageSize: size,
|
|
|
|
|
showSizeChanger: false,
|
|
|
|
|
hideOnSinglePage: true,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ============ Per-row enable switch =================================
|
|
|
|
|
async function onSwitchEnable(dbInbound, next) {
|
|
|
|
|
const previous = dbInbound.enable;
|
|
|
|
|
dbInbound.enable = next; // optimistic
|
|
|
|
|
try {
|
|
|
|
|
const formData = new FormData();
|
|
|
|
|
formData.append('enable', String(next));
|
|
|
|
|
const msg = await HttpUtil.post(`/panel/api/inbounds/setEnable/${dbInbound.id}`, formData);
|
|
|
|
|
if (!msg?.success) dbInbound.enable = previous;
|
|
|
|
|
} catch (_e) {
|
|
|
|
|
dbInbound.enable = previous;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ============ Helpers shared with the templates =====================
|
|
|
|
|
function isClientOnline(email) {
|
|
|
|
|
return props.onlineClients.includes(email);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Whether to show the "Switch xray" / qrcode menu entry — same predicate
|
|
|
|
|
// as legacy: SS single-user inbounds and WireGuard inbounds expose
|
|
|
|
|
// inbound-wide QR codes.
|
|
|
|
|
function showQrCodeMenu(dbInbound) {
|
|
|
|
|
if (dbInbound.isWireguard) return true;
|
|
|
|
|
if (dbInbound.isSS) {
|
|
|
|
|
try {
|
|
|
|
|
return !dbInbound.toInbound().isSSMultiUser;
|
|
|
|
|
} catch (_e) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<template>
|
|
|
|
|
<a-card hoverable>
|
|
|
|
|
<template #title>
|
|
|
|
|
<a-space direction="horizontal">
|
|
|
|
|
<a-button type="primary" @click="emit('add-inbound')">
|
2026-05-08 19:05:14 +00:00
|
|
|
<template #icon>
|
|
|
|
|
<PlusOutlined />
|
|
|
|
|
</template>
|
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
|
|
|
<template v-if="!isMobile">{{ t('pages.inbounds.addInbound') }}</template>
|
2026-05-08 11:32:44 +00:00
|
|
|
</a-button>
|
|
|
|
|
<a-dropdown :trigger="['click']">
|
|
|
|
|
<a-button type="primary">
|
2026-05-08 19:05:14 +00:00
|
|
|
<template #icon>
|
|
|
|
|
<MenuOutlined />
|
|
|
|
|
</template>
|
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
|
|
|
<template v-if="!isMobile">{{ t('pages.inbounds.generalActions') }}</template>
|
2026-05-08 11:32:44 +00:00
|
|
|
</a-button>
|
|
|
|
|
<template #overlay>
|
|
|
|
|
<a-menu @click="(a) => emit('general-action', a.key)">
|
|
|
|
|
<a-menu-item key="import">
|
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
|
|
|
<ImportOutlined /> {{ t('pages.inbounds.importInbound') }}
|
2026-05-08 11:32:44 +00:00
|
|
|
</a-menu-item>
|
|
|
|
|
<a-menu-item key="export">
|
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
|
|
|
<ExportOutlined /> {{ t('pages.inbounds.export') }}
|
2026-05-08 11:32:44 +00:00
|
|
|
</a-menu-item>
|
|
|
|
|
<a-menu-item v-if="subEnable" key="subs">
|
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
|
|
|
<ExportOutlined /> {{ t('pages.inbounds.export') }} — {{ t('pages.settings.subSettings') }}
|
2026-05-08 11:32:44 +00:00
|
|
|
</a-menu-item>
|
|
|
|
|
<a-menu-item key="resetInbounds">
|
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
|
|
|
<ReloadOutlined /> {{ t('pages.inbounds.resetAllTraffic') }}
|
2026-05-08 11:32:44 +00:00
|
|
|
</a-menu-item>
|
|
|
|
|
<a-menu-item key="resetClients">
|
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
|
|
|
<FileDoneOutlined /> {{ t('pages.inbounds.resetAllClientTraffics') }}
|
2026-05-08 11:32:44 +00:00
|
|
|
</a-menu-item>
|
|
|
|
|
<a-menu-item key="delDepletedClients" class="danger-item">
|
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
|
|
|
<RestOutlined /> {{ t('pages.inbounds.delDepletedClients') }}
|
2026-05-08 11:32:44 +00:00
|
|
|
</a-menu-item>
|
|
|
|
|
</a-menu>
|
|
|
|
|
</template>
|
|
|
|
|
</a-dropdown>
|
|
|
|
|
</a-space>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<template #extra>
|
|
|
|
|
<a-button-group>
|
|
|
|
|
<a-button :loading="refreshing" @click="emit('refresh')">
|
2026-05-08 19:05:14 +00:00
|
|
|
<template #icon>
|
|
|
|
|
<SyncOutlined />
|
|
|
|
|
</template>
|
2026-05-08 11:32:44 +00:00
|
|
|
</a-button>
|
|
|
|
|
<a-popover placement="bottomRight" trigger="click">
|
|
|
|
|
<template #title>
|
|
|
|
|
<div class="auto-refresh-title">
|
|
|
|
|
<a-switch v-model:checked="isRefreshEnabled" size="small" />
|
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
|
|
|
<span>{{ t('pages.inbounds.autoRefresh') }}</span>
|
2026-05-08 11:32:44 +00:00
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
<template #content>
|
|
|
|
|
<a-space direction="vertical">
|
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
|
|
|
<span>{{ t('pages.inbounds.autoRefreshInterval') }}</span>
|
2026-05-08 19:05:14 +00:00
|
|
|
<a-select v-model:value="refreshIntervalMs" :disabled="!isRefreshEnabled" :style="{ width: '100%' }">
|
2026-05-08 11:32:44 +00:00
|
|
|
<a-select-option v-for="key in [5, 10, 30, 60]" :key="key" :value="key * 1000">
|
|
|
|
|
{{ key }}s
|
|
|
|
|
</a-select-option>
|
|
|
|
|
</a-select>
|
|
|
|
|
</a-space>
|
|
|
|
|
</template>
|
|
|
|
|
<a-button>
|
2026-05-08 19:05:14 +00:00
|
|
|
<template #icon>
|
|
|
|
|
<DownOutlined />
|
|
|
|
|
</template>
|
2026-05-08 11:32:44 +00:00
|
|
|
</a-button>
|
|
|
|
|
</a-popover>
|
|
|
|
|
</a-button-group>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<a-space direction="vertical" :style="{ width: '100%' }">
|
|
|
|
|
<!-- Search / filter toolbar -->
|
|
|
|
|
<div :class="isMobile ? 'filter-bar mobile' : 'filter-bar'">
|
|
|
|
|
<a-switch v-model:checked="enableFilter" @change="onToggleFilter">
|
2026-05-08 19:05:14 +00:00
|
|
|
<template #checkedChildren>
|
|
|
|
|
<SearchOutlined />
|
|
|
|
|
</template>
|
|
|
|
|
<template #unCheckedChildren>
|
|
|
|
|
<FilterOutlined />
|
|
|
|
|
</template>
|
2026-05-08 11:32:44 +00:00
|
|
|
</a-switch>
|
2026-05-08 19:05:14 +00:00
|
|
|
<a-input v-if="!enableFilter" v-model:value="searchKey" :placeholder="t('search')" autofocus
|
|
|
|
|
:size="isMobile ? 'small' : 'middle'" :style="{ maxWidth: '300px' }" />
|
|
|
|
|
<a-radio-group v-if="enableFilter" v-model:value="filterBy" button-style="solid"
|
|
|
|
|
:size="isMobile ? 'small' : 'middle'">
|
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
|
|
|
<a-radio-button value="">{{ t('none') }}</a-radio-button>
|
|
|
|
|
<a-radio-button value="active">{{ t('subscription.active') }}</a-radio-button>
|
|
|
|
|
<a-radio-button value="deactive">{{ t('disabled') }}</a-radio-button>
|
|
|
|
|
<a-radio-button value="depleted">{{ t('depleted') }}</a-radio-button>
|
|
|
|
|
<a-radio-button value="expiring">{{ t('depletingSoon') }}</a-radio-button>
|
|
|
|
|
<a-radio-button value="online">{{ t('online') }}</a-radio-button>
|
2026-05-08 11:32:44 +00:00
|
|
|
</a-radio-group>
|
|
|
|
|
</div>
|
|
|
|
|
|
2026-05-08 19:05:14 +00:00
|
|
|
<a-table :columns="columns" :data-source="visibleInbounds" :row-key="(r) => r.id"
|
|
|
|
|
:pagination="paginationFor(visibleInbounds)" :scroll="isMobile ? {} : { x: 1000 }"
|
|
|
|
|
:style="{ marginTop: '10px' }" size="small"
|
|
|
|
|
:row-class-name="(r) => (r.isMultiUser() ? '' : 'hide-expand-icon')">
|
2026-05-08 12:00:39 +00:00
|
|
|
<!-- Per-inbound client list, expanded by clicking the row's
|
|
|
|
|
default expand chevron. Hidden via row-class-name for
|
|
|
|
|
non-multi-user inbounds (matches legacy behavior). -->
|
|
|
|
|
<template #expandedRowRender="{ record }">
|
2026-05-08 19:05:14 +00:00
|
|
|
<ClientRowTable v-if="record.isMultiUser()" :db-inbound="record" :is-mobile="isMobile"
|
|
|
|
|
:traffic-diff="trafficDiff" :expire-diff="expireDiff" :online-clients="onlineClients"
|
|
|
|
|
:last-online-map="lastOnlineMap" :is-dark-theme="isDarkTheme" @edit-client="(p) => emit('edit-client', p)"
|
|
|
|
|
@qrcode-client="(p) => emit('qrcode-client', p)" @info-client="(p) => emit('info-client', p)"
|
2026-05-08 12:00:39 +00:00
|
|
|
@reset-traffic-client="(p) => emit('reset-traffic-client', p)"
|
|
|
|
|
@delete-client="(p) => emit('delete-client', p)"
|
2026-05-08 19:05:14 +00:00
|
|
|
@toggle-enable-client="(p) => emit('toggle-enable-client', p)" />
|
2026-05-08 12:00:39 +00:00
|
|
|
</template>
|
|
|
|
|
|
2026-05-08 11:32:44 +00:00
|
|
|
<template #bodyCell="{ column, record }">
|
|
|
|
|
<!-- ============== Action dropdown ============== -->
|
|
|
|
|
<template v-if="column.key === 'action'">
|
|
|
|
|
<a-dropdown :trigger="['click']">
|
|
|
|
|
<MoreOutlined class="row-action-trigger" @click.prevent />
|
|
|
|
|
<template #overlay>
|
|
|
|
|
<a-menu @click="(a) => emit('row-action', { key: a.key, dbInbound: record })">
|
2026-05-08 19:05:14 +00:00
|
|
|
<a-menu-item key="edit">
|
|
|
|
|
<EditOutlined /> {{ t('edit') }}
|
|
|
|
|
</a-menu-item>
|
2026-05-08 11:32:44 +00:00
|
|
|
<a-menu-item v-if="showQrCodeMenu(record)" key="qrcode">
|
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
|
|
|
<QrcodeOutlined /> {{ t('qrCode') }}
|
2026-05-08 11:32:44 +00:00
|
|
|
</a-menu-item>
|
|
|
|
|
<template v-if="record.isMultiUser()">
|
2026-05-08 19:05:14 +00:00
|
|
|
<a-menu-item key="addClient">
|
|
|
|
|
<UserAddOutlined /> {{ t('pages.client.add') }}
|
|
|
|
|
</a-menu-item>
|
|
|
|
|
<a-menu-item key="addBulkClient">
|
|
|
|
|
<UsergroupAddOutlined /> {{ t('pages.client.bulk') }}
|
|
|
|
|
</a-menu-item>
|
|
|
|
|
<a-menu-item key="copyClients">
|
|
|
|
|
<CopyOutlined /> {{ t('pages.client.copyFromInbound') }}
|
|
|
|
|
</a-menu-item>
|
|
|
|
|
<a-menu-item key="resetClients">
|
|
|
|
|
<FileDoneOutlined /> {{ t('pages.inbounds.resetInboundClientTraffics') }}
|
|
|
|
|
</a-menu-item>
|
|
|
|
|
<a-menu-item key="export">
|
|
|
|
|
<ExportOutlined /> {{ t('pages.inbounds.export') }}
|
|
|
|
|
</a-menu-item>
|
2026-05-08 11:32:44 +00:00
|
|
|
<a-menu-item v-if="subEnable" key="subs">
|
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
|
|
|
<ExportOutlined /> {{ t('pages.inbounds.export') }} — {{ t('pages.settings.subSettings') }}
|
2026-05-08 11:32:44 +00:00
|
|
|
</a-menu-item>
|
|
|
|
|
<a-menu-item key="delDepletedClients" class="danger-item">
|
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
|
|
|
<RestOutlined /> {{ t('pages.inbounds.delDepletedClients') }}
|
2026-05-08 11:32:44 +00:00
|
|
|
</a-menu-item>
|
|
|
|
|
</template>
|
|
|
|
|
<template v-else>
|
2026-05-08 19:05:14 +00:00
|
|
|
<a-menu-item key="showInfo">
|
|
|
|
|
<InfoCircleOutlined /> {{ t('info') }}
|
|
|
|
|
</a-menu-item>
|
2026-05-08 11:32:44 +00:00
|
|
|
</template>
|
2026-05-08 19:05:14 +00:00
|
|
|
<a-menu-item key="clipboard">
|
|
|
|
|
<CopyOutlined /> {{ t('pages.inbounds.exportInbound') }}
|
|
|
|
|
</a-menu-item>
|
|
|
|
|
<a-menu-item key="resetTraffic">
|
|
|
|
|
<RetweetOutlined /> {{ t('pages.inbounds.resetTraffic') }}
|
|
|
|
|
</a-menu-item>
|
|
|
|
|
<a-menu-item key="clone">
|
|
|
|
|
<BlockOutlined /> {{ t('pages.inbounds.clone') }}
|
|
|
|
|
</a-menu-item>
|
2026-05-08 11:32:44 +00:00
|
|
|
<a-menu-item key="delete" class="danger-item">
|
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
|
|
|
<DeleteOutlined /> {{ t('delete') }}
|
2026-05-08 11:32:44 +00:00
|
|
|
</a-menu-item>
|
|
|
|
|
</a-menu>
|
|
|
|
|
</template>
|
|
|
|
|
</a-dropdown>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<!-- ============== Enable switch (desktop) ============== -->
|
|
|
|
|
<template v-else-if="column.key === 'enable'">
|
2026-05-08 19:05:14 +00:00
|
|
|
<a-switch :checked="record.enable" @change="(next) => onSwitchEnable(record, next)" />
|
2026-05-08 11:32:44 +00:00
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<!-- ============== Protocol tags ============== -->
|
|
|
|
|
<template v-else-if="column.key === 'protocol'">
|
|
|
|
|
<div class="protocol-tags">
|
|
|
|
|
<a-tag color="purple">{{ record.protocol }}</a-tag>
|
|
|
|
|
<template v-if="record.isVMess || record.isVLess || record.isTrojan || record.isSS">
|
|
|
|
|
<a-tag color="green">{{ record.toInbound().stream.network }}</a-tag>
|
|
|
|
|
<a-tag v-if="record.toInbound().stream.isTls" color="blue">TLS</a-tag>
|
|
|
|
|
<a-tag v-if="record.toInbound().stream.isReality" color="blue">Reality</a-tag>
|
|
|
|
|
</template>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<!-- ============== Clients tag + popovers ============== -->
|
|
|
|
|
<template v-else-if="column.key === 'clients'">
|
|
|
|
|
<template v-if="clientCount[record.id]">
|
|
|
|
|
<a-tag color="green" style="margin: 0">{{ clientCount[record.id].clients }}</a-tag>
|
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
|
|
|
<a-popover v-if="clientCount[record.id].deactive.length" :title="t('disabled')">
|
2026-05-08 11:32:44 +00:00
|
|
|
<template #content>
|
|
|
|
|
<div v-for="email in clientCount[record.id].deactive" :key="email">{{ email }}</div>
|
|
|
|
|
</template>
|
|
|
|
|
<a-tag style="margin: 0; padding: 0 2px">{{ clientCount[record.id].deactive.length }}</a-tag>
|
|
|
|
|
</a-popover>
|
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
|
|
|
<a-popover v-if="clientCount[record.id].depleted.length" :title="t('depleted')">
|
2026-05-08 11:32:44 +00:00
|
|
|
<template #content>
|
|
|
|
|
<div v-for="email in clientCount[record.id].depleted" :key="email">{{ email }}</div>
|
|
|
|
|
</template>
|
2026-05-08 19:05:14 +00:00
|
|
|
<a-tag color="red" style="margin: 0; padding: 0 2px">{{ clientCount[record.id].depleted.length
|
|
|
|
|
}}</a-tag>
|
2026-05-08 11:32:44 +00:00
|
|
|
</a-popover>
|
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
|
|
|
<a-popover v-if="clientCount[record.id].expiring.length" :title="t('depletingSoon')">
|
2026-05-08 11:32:44 +00:00
|
|
|
<template #content>
|
|
|
|
|
<div v-for="email in clientCount[record.id].expiring" :key="email">{{ email }}</div>
|
|
|
|
|
</template>
|
2026-05-08 19:05:14 +00:00
|
|
|
<a-tag color="orange" style="margin: 0; padding: 0 2px">{{ clientCount[record.id].expiring.length
|
|
|
|
|
}}</a-tag>
|
2026-05-08 11:32:44 +00:00
|
|
|
</a-popover>
|
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
|
|
|
<a-popover v-if="clientCount[record.id].online.length" :title="t('online')">
|
2026-05-08 11:32:44 +00:00
|
|
|
<template #content>
|
|
|
|
|
<div v-for="email in clientCount[record.id].online" :key="email">{{ email }}</div>
|
|
|
|
|
</template>
|
|
|
|
|
<a-tag color="blue" style="margin: 0; padding: 0 2px">{{ clientCount[record.id].online.length }}</a-tag>
|
|
|
|
|
</a-popover>
|
|
|
|
|
</template>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<!-- ============== Traffic ============== -->
|
|
|
|
|
<template v-else-if="column.key === 'traffic'">
|
|
|
|
|
<a-popover>
|
|
|
|
|
<template #content>
|
|
|
|
|
<table cellpadding="2">
|
2026-05-08 11:36:24 +00:00
|
|
|
<tbody>
|
|
|
|
|
<tr>
|
|
|
|
|
<td>↑ {{ SizeFormatter.sizeFormat(record.up) }}</td>
|
|
|
|
|
<td>↓ {{ SizeFormatter.sizeFormat(record.down) }}</td>
|
|
|
|
|
</tr>
|
|
|
|
|
<tr v-if="record.total > 0 && record.up + record.down < record.total">
|
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
|
|
|
<td>{{ t('remained') }}</td>
|
2026-05-08 11:36:24 +00:00
|
|
|
<td>{{ SizeFormatter.sizeFormat(record.total - record.up - record.down) }}</td>
|
|
|
|
|
</tr>
|
|
|
|
|
</tbody>
|
2026-05-08 11:32:44 +00:00
|
|
|
</table>
|
|
|
|
|
</template>
|
|
|
|
|
<a-tag :color="ColorUtils.usageColor(record.up + record.down, trafficDiff, record.total)">
|
|
|
|
|
{{ SizeFormatter.sizeFormat(record.up + record.down) }} /
|
|
|
|
|
<template v-if="record.total > 0">{{ SizeFormatter.sizeFormat(record.total) }}</template>
|
fix(frontend): redesign expand-row + retheme client visuals
When you expanded an inbound row, the nested <a-table> inside
ClientRowTable burst out of the parent's scroll-x box — its
.ant-spin-container ended up wider than the parent's narrow
.ant-table-cell, so the child looked oversized while the parent looked
squeezed. Replace the nested table with a CSS-grid layout that owns
its sizing, sits flush inside the expanded cell, and collapses to a
3-column layout on mobile (action menu, client identity, info popover).
While in there, fix three other client-row visuals:
- The Unicode infinity glyph (U+221E) renders as an "m"-shaped
character in some system fonts (Windows Segoe UI in particular).
Add a shared <InfinityIcon /> SVG component (legacy panel's path)
and use it in ClientRowTable, InboundList, and InboundInfoModal —
desktop and mobile cells.
- The "unlimited quota" traffic bar passed :percent="100" with no
stroke-color, so AD-Vue auto-coloured it success-green. Pin it to
the AD-Vue purple token (#722ed1) so it reads as the no-limit
sentinel rather than another usage state.
- ColorUtils + the in-row statsExpColor still hardcoded the legacy
teal/orange/red/purple palette (#008771 / #f37b24 / #cf3c3c /
#7a316f). Map them onto AD-Vue 4's success/warning/danger/purple
tokens (#52c41a / #faad14 / #ff4d4f / #722ed1) so badges, tags,
and progress bars all match the rest of the panel.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 16:32:37 +00:00
|
|
|
<InfinityIcon v-else />
|
2026-05-08 11:32:44 +00:00
|
|
|
</a-tag>
|
|
|
|
|
</a-popover>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<!-- ============== All-time inbound traffic ============== -->
|
|
|
|
|
<template v-else-if="column.key === 'allTimeInbound'">
|
|
|
|
|
<a-tag>{{ SizeFormatter.sizeFormat(record.allTime || 0) }}</a-tag>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<!-- ============== Expiry ============== -->
|
|
|
|
|
<template v-else-if="column.key === 'expiryTime'">
|
|
|
|
|
<a-popover v-if="record.expiryTime > 0">
|
2026-05-08 22:34:07 +00:00
|
|
|
<template #content>{{ IntlUtil.formatDate(record.expiryTime, datepicker) }}</template>
|
2026-05-08 19:05:14 +00:00
|
|
|
<a-tag :color="ColorUtils.usageColor(Date.now(), expireDiff, record._expiryTime)" style="min-width: 50px">
|
2026-05-08 11:32:44 +00:00
|
|
|
{{ IntlUtil.formatRelativeTime(record.expiryTime) }}
|
|
|
|
|
</a-tag>
|
|
|
|
|
</a-popover>
|
2026-05-08 19:05:14 +00:00
|
|
|
<a-tag v-else color="purple">
|
|
|
|
|
<InfinityIcon />
|
|
|
|
|
</a-tag>
|
2026-05-08 11:32:44 +00:00
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<!-- ============== Mobile info popover ============== -->
|
|
|
|
|
<template v-else-if="column.key === 'info'">
|
|
|
|
|
<a-popover placement="bottomRight" trigger="click">
|
|
|
|
|
<template #content>
|
|
|
|
|
<table cellpadding="2">
|
2026-05-08 11:36:24 +00:00
|
|
|
<tbody>
|
|
|
|
|
<tr>
|
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
|
|
|
<td>{{ t('pages.inbounds.protocol') }}</td>
|
2026-05-08 11:36:24 +00:00
|
|
|
<td><a-tag color="purple">{{ record.protocol }}</a-tag></td>
|
|
|
|
|
</tr>
|
|
|
|
|
<tr>
|
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
|
|
|
<td>{{ t('pages.inbounds.port') }}</td>
|
2026-05-08 11:36:24 +00:00
|
|
|
<td><a-tag>{{ record.port }}</a-tag></td>
|
|
|
|
|
</tr>
|
|
|
|
|
<tr v-if="clientCount[record.id]">
|
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
|
|
|
<td>{{ t('clients') }}</td>
|
2026-05-08 11:36:24 +00:00
|
|
|
<td><a-tag color="blue">{{ clientCount[record.id].clients }}</a-tag></td>
|
|
|
|
|
</tr>
|
|
|
|
|
<tr>
|
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
|
|
|
<td>{{ t('pages.inbounds.traffic') }}</td>
|
2026-05-08 11:36:24 +00:00
|
|
|
<td>
|
|
|
|
|
<a-tag>
|
|
|
|
|
{{ SizeFormatter.sizeFormat(record.up + record.down) }} /
|
|
|
|
|
<template v-if="record.total > 0">{{ SizeFormatter.sizeFormat(record.total) }}</template>
|
fix(frontend): redesign expand-row + retheme client visuals
When you expanded an inbound row, the nested <a-table> inside
ClientRowTable burst out of the parent's scroll-x box — its
.ant-spin-container ended up wider than the parent's narrow
.ant-table-cell, so the child looked oversized while the parent looked
squeezed. Replace the nested table with a CSS-grid layout that owns
its sizing, sits flush inside the expanded cell, and collapses to a
3-column layout on mobile (action menu, client identity, info popover).
While in there, fix three other client-row visuals:
- The Unicode infinity glyph (U+221E) renders as an "m"-shaped
character in some system fonts (Windows Segoe UI in particular).
Add a shared <InfinityIcon /> SVG component (legacy panel's path)
and use it in ClientRowTable, InboundList, and InboundInfoModal —
desktop and mobile cells.
- The "unlimited quota" traffic bar passed :percent="100" with no
stroke-color, so AD-Vue auto-coloured it success-green. Pin it to
the AD-Vue purple token (#722ed1) so it reads as the no-limit
sentinel rather than another usage state.
- ColorUtils + the in-row statsExpColor still hardcoded the legacy
teal/orange/red/purple palette (#008771 / #f37b24 / #cf3c3c /
#7a316f). Map them onto AD-Vue 4's success/warning/danger/purple
tokens (#52c41a / #faad14 / #ff4d4f / #722ed1) so badges, tags,
and progress bars all match the rest of the panel.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 16:32:37 +00:00
|
|
|
<InfinityIcon v-else />
|
2026-05-08 11:36:24 +00:00
|
|
|
</a-tag>
|
|
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
<tr>
|
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
|
|
|
<td>{{ t('pages.inbounds.expireDate') }}</td>
|
2026-05-08 11:36:24 +00:00
|
|
|
<td>
|
|
|
|
|
<a-tag v-if="record.expiryTime > 0">{{ IntlUtil.formatRelativeTime(record.expiryTime) }}</a-tag>
|
2026-05-08 19:05:14 +00:00
|
|
|
<a-tag v-else color="purple">
|
|
|
|
|
<InfinityIcon />
|
|
|
|
|
</a-tag>
|
2026-05-08 11:36:24 +00:00
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
</tbody>
|
2026-05-08 11:32:44 +00:00
|
|
|
</table>
|
|
|
|
|
</template>
|
|
|
|
|
<InfoCircleOutlined class="row-info-trigger" />
|
|
|
|
|
</a-popover>
|
|
|
|
|
</template>
|
|
|
|
|
</template>
|
|
|
|
|
</a-table>
|
|
|
|
|
</a-space>
|
|
|
|
|
</a-card>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
|
.auto-refresh-title {
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
gap: 8px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.filter-bar {
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
gap: 8px;
|
|
|
|
|
}
|
2026-05-08 19:05:14 +00:00
|
|
|
|
2026-05-08 11:32:44 +00:00
|
|
|
.filter-bar.mobile {
|
|
|
|
|
display: block;
|
|
|
|
|
}
|
2026-05-08 19:05:14 +00:00
|
|
|
|
|
|
|
|
.filter-bar.mobile>* {
|
2026-05-08 11:32:44 +00:00
|
|
|
margin-bottom: 4px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.protocol-tags {
|
|
|
|
|
display: inline-flex;
|
|
|
|
|
flex-wrap: wrap;
|
|
|
|
|
gap: 4px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.row-action-trigger,
|
|
|
|
|
.row-info-trigger {
|
|
|
|
|
font-size: 20px;
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.danger-item {
|
|
|
|
|
color: #ff4d4f;
|
|
|
|
|
}
|
2026-05-08 12:00:39 +00:00
|
|
|
|
|
|
|
|
/* Hide the expand chevron on rows whose inbound has no client list
|
|
|
|
|
* (HTTP/Mixed/Tunnel/WireGuard single-config). */
|
|
|
|
|
:deep(.hide-expand-icon .ant-table-row-expand-icon) {
|
|
|
|
|
visibility: hidden;
|
|
|
|
|
}
|
2026-05-08 19:05:14 +00:00
|
|
|
|
|
|
|
|
/* Round the table's outer corners — AD-Vue gives .ant-table the radius
|
|
|
|
|
* token, but the inner header strip and footer touch the edges, so clip
|
|
|
|
|
* them here. */
|
|
|
|
|
:deep(.ant-table) {
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
:deep(.ant-table-container) {
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
:deep(.ant-table-thead > tr:first-child > *:first-child) {
|
|
|
|
|
border-start-start-radius: 8px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
:deep(.ant-table-thead > tr:first-child > *:last-child) {
|
|
|
|
|
border-start-end-radius: 8px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
:deep(.ant-table-tbody > tr:last-child > *:first-child) {
|
|
|
|
|
border-end-start-radius: 8px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
:deep(.ant-table-tbody > tr:last-child > *:last-child) {
|
|
|
|
|
border-end-end-radius: 8px;
|
|
|
|
|
}
|
2026-05-08 22:51:45 +00:00
|
|
|
|
|
|
|
|
/* ===== Mobile-tightening ============================================
|
|
|
|
|
* Below 768px the inbound list is on a tiny viewport — squeeze the
|
|
|
|
|
* card chrome and table cell padding so the actual rows have room. */
|
|
|
|
|
@media (max-width: 768px) {
|
|
|
|
|
/* Card header/body breathe less on mobile */
|
|
|
|
|
:deep(.ant-card-head) {
|
|
|
|
|
padding: 0 12px;
|
|
|
|
|
min-height: 44px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
:deep(.ant-card-head-title),
|
|
|
|
|
:deep(.ant-card-extra) {
|
|
|
|
|
padding: 8px 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
:deep(.ant-card-body) {
|
|
|
|
|
padding: 8px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Filter bar wraps cleanly without forcing block layout (which made
|
|
|
|
|
* the input + radio group stack on separate full-width lines). */
|
|
|
|
|
.filter-bar.mobile {
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-wrap: wrap;
|
|
|
|
|
gap: 6px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.filter-bar.mobile > * {
|
|
|
|
|
margin-bottom: 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Tighten table cell padding so the 3 visible columns get room. */
|
|
|
|
|
:deep(.ant-table-thead > tr > th),
|
|
|
|
|
:deep(.ant-table-tbody > tr > td) {
|
|
|
|
|
padding: 8px 6px;
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Slightly bigger expand chevron (touch target). */
|
|
|
|
|
:deep(.ant-table-row-expand-icon) {
|
|
|
|
|
width: 20px;
|
|
|
|
|
height: 20px;
|
|
|
|
|
line-height: 18px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* The action / info icons are the row's primary touch targets. */
|
|
|
|
|
.row-action-trigger,
|
|
|
|
|
.row-info-trigger {
|
|
|
|
|
font-size: 22px;
|
|
|
|
|
padding: 4px;
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-05-08 11:32:44 +00:00
|
|
|
</style>
|