From 6d732d8d32ddf85478da574608ef9c3626746635 Mon Sep 17 00:00:00 2001 From: MHSanaei Date: Mon, 11 May 2026 03:50:28 +0200 Subject: [PATCH] feat(inbounds): bulk-select clients + UX polish MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ClientBulkModal: add `comment` and VLESS `reverseTag` fields so the bulk-add modal can set them on every generated client (matching the single-client form) - ClientRowTable: add multi-select checkboxes (desktop + mobile) with a tri-state select-all and a sticky bulk-action bar; emits a new `delete-clients` event so the parent can wipe the picked clients in one go. Hidden entirely when the inbound has only one client (the last one must stay) - ClientRowTable: new "Remained" column shows live remaining quota per client (∞ for unlimited, red when depleted) - InboundInfoModal: Remained cell now shows the ∞ tag when the client has no totalGB limit, matching how Total Usage already renders it - InboundsPage: add Online tag (+ per-bucket popovers listing client emails) to the summary card so it mirrors the per-inbound row, and wire an `onDeleteClients` handler that loops the existing single- delete endpoint then refreshes once - InboundList: forward the `delete-clients` event; hide empty remarks on both the desktop table (custom #bodyCell) and the mobile card - useInbounds: aggregate an `online` email list across all inbounds so the summary popover has data to render --- .../src/pages/inbounds/ClientBulkModal.vue | 7 + .../src/pages/inbounds/ClientRowTable.vue | 150 +++++++++++++++++- .../src/pages/inbounds/InboundInfoModal.vue | 3 + frontend/src/pages/inbounds/InboundList.vue | 19 ++- frontend/src/pages/inbounds/InboundsPage.vue | 62 +++++++- frontend/src/pages/inbounds/useInbounds.js | 4 +- 6 files changed, 231 insertions(+), 14 deletions(-) diff --git a/frontend/src/pages/inbounds/ClientBulkModal.vue b/frontend/src/pages/inbounds/ClientBulkModal.vue index e5a109ef..19804a26 100644 --- a/frontend/src/pages/inbounds/ClientBulkModal.vue +++ b/frontend/src/pages/inbounds/ClientBulkModal.vue @@ -53,6 +53,7 @@ const form = reactive({ flow: '', subId: '', tgId: 0, + comment: '', limitIp: 0, totalGB: 0, expiryTime: 0, // ms epoch; negative => delayed start days @@ -85,6 +86,7 @@ watch(() => props.open, (next) => { form.flow = ''; form.subId = ''; form.tgId = 0; + form.comment = ''; form.limitIp = 0; form.totalGB = 0; form.expiryTime = 0; @@ -135,6 +137,7 @@ function buildClients() { if (form.subId.length > 0) c.subId = form.subId; c.tgId = form.tgId; + if (form.comment.length > 0) c.comment = form.comment; c.security = form.security; c.limitIp = form.limitIp; // Use the clien's totalGB setter (ms epoch and bytes already handled @@ -227,6 +230,10 @@ async function submit() { + + + + diff --git a/frontend/src/pages/inbounds/ClientRowTable.vue b/frontend/src/pages/inbounds/ClientRowTable.vue index 07b9523b..3659d643 100644 --- a/frontend/src/pages/inbounds/ClientRowTable.vue +++ b/frontend/src/pages/inbounds/ClientRowTable.vue @@ -1,5 +1,5 @@