3x-ui/frontend/src/pages/inbounds/InboundList.vue

659 lines
25 KiB
Vue
Raw Normal View History

2026-05-08 11:32:44 +00:00
<script setup>
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';
import InfinityIcon from '@/components/InfinityIcon.vue';
import ClientRowTable from './ClientRowTable.vue';
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 },
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 },
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',
// 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();
});
// 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 },
{ 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 },
{ 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')">
<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">
<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')">
<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>
<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>
<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">
<template #checkedChildren>
<SearchOutlined />
</template>
<template #unCheckedChildren>
<FilterOutlined />
</template>
2026-05-08 11:32:44 +00:00
</a-switch>
<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>
<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')">
<!-- 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 }">
<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)"
@reset-traffic-client="(p) => emit('reset-traffic-client', p)"
@delete-client="(p) => emit('delete-client', p)"
@toggle-enable-client="(p) => emit('toggle-enable-client', p)" />
</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 })">
<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()">
<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>
<a-menu-item key="showInfo">
<InfoCircleOutlined /> {{ t('info') }}
</a-menu-item>
2026-05-08 11:32:44 +00:00
</template>
<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'">
<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>
<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>
<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">
<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>
<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>
<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">
<template #content>{{ IntlUtil.formatDate(record.expiryTime, datepicker) }}</template>
<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>
<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">
<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>
<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>
<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>
<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>
<td>
<a-tag>
{{ SizeFormatter.sizeFormat(record.up + record.down) }} /
<template v-if="record.total > 0">{{ SizeFormatter.sizeFormat(record.total) }}</template>
<InfinityIcon v-else />
</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>
<td>
<a-tag v-if="record.expiryTime > 0">{{ IntlUtil.formatRelativeTime(record.expiryTime) }}</a-tag>
<a-tag v-else color="purple">
<InfinityIcon />
</a-tag>
</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 11:32:44 +00:00
.filter-bar.mobile {
display: block;
}
.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;
}
/* 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;
}
/* 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;
}
/* ===== 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>