From d052de9a939d3c9a945e918c942dab9e7a142e87 Mon Sep 17 00:00:00 2001 From: MHSanaei Date: Fri, 8 May 2026 13:47:04 +0200 Subject: [PATCH] =?UTF-8?q?feat(frontend):=20Phase=205f-iv=20=E2=80=94=20c?= =?UTF-8?q?lient=20add/edit=20+=20bulk-add=20modals?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Wires per-inbound client management. Both flows go through the same addClient/updateClient endpoints as legacy; the modals just funnel the form state into the right shape (`{id, settings: '{"clients": [...]}'}`). - ClientFormModal.vue: protocol-aware single-client editor — email/ password/id/auth/security/flow/subId/tgId/comment/ipLimit/totalGB/ expiry/renewal fields are shown/hidden per protocol like legacy. Edit mode displays the per-client traffic stats with a reset button; IP-limit log is read on click and clearable. Random helpers (sync icon next to each label) regenerate UUID/email/ password/sub-id values. - ClientBulkModal.vue: 1–500 clients in one POST, with the legacy five email-generation modes (Random / +Prefix / +Num / +Postfix / Pure-Prefix-Num-Postfix). Builds clients via the protocol-aware factory and concatenates their toString() output into a single settings.clients JSON array. - InboundsPage.vue: opens both modals from the row action menu (`addClient` / `addBulkClient`). They both refresh the inbound list on success. - Outstanding row actions still toast as "coming soon": qrcode, showInfo, copyClients, clipboard. Those land in 5f-v / 5f-vi. Co-Authored-By: Claude Opus 4.7 --- .../src/pages/inbounds/ClientBulkModal.vue | 293 ++++++++++++ .../src/pages/inbounds/ClientFormModal.vue | 444 ++++++++++++++++++ frontend/src/pages/inbounds/InboundsPage.vue | 50 ++ 3 files changed, 787 insertions(+) create mode 100644 frontend/src/pages/inbounds/ClientBulkModal.vue create mode 100644 frontend/src/pages/inbounds/ClientFormModal.vue diff --git a/frontend/src/pages/inbounds/ClientBulkModal.vue b/frontend/src/pages/inbounds/ClientBulkModal.vue new file mode 100644 index 00000000..ffe034c8 --- /dev/null +++ b/frontend/src/pages/inbounds/ClientBulkModal.vue @@ -0,0 +1,293 @@ + + + + + diff --git a/frontend/src/pages/inbounds/ClientFormModal.vue b/frontend/src/pages/inbounds/ClientFormModal.vue new file mode 100644 index 00000000..1f00497a --- /dev/null +++ b/frontend/src/pages/inbounds/ClientFormModal.vue @@ -0,0 +1,444 @@ + + + + + diff --git a/frontend/src/pages/inbounds/InboundsPage.vue b/frontend/src/pages/inbounds/InboundsPage.vue index f33a1b7a..c951091a 100644 --- a/frontend/src/pages/inbounds/InboundsPage.vue +++ b/frontend/src/pages/inbounds/InboundsPage.vue @@ -17,6 +17,8 @@ import AppSidebar from '@/components/AppSidebar.vue'; import CustomStatistic from '@/components/CustomStatistic.vue'; import InboundList from './InboundList.vue'; import InboundFormModal from './InboundFormModal.vue'; +import ClientFormModal from './ClientFormModal.vue'; +import ClientBulkModal from './ClientBulkModal.vue'; import { useInbounds } from './useInbounds.js'; const antdThemeConfig = computed(() => ({ @@ -34,6 +36,8 @@ const { trafficDiff, pageSize, subSettings, + tgBotEnable, + ipLimitEnable, refresh, fetchDefaultSettings, } = useInbounds(); @@ -52,6 +56,15 @@ const formOpen = ref(false); const formMode = ref('add'); const formDbInbound = ref(null); +// === Client modal (single + bulk) ===================================== +const clientOpen = ref(false); +const clientMode = ref('add'); +const clientDbInbound = ref(null); +const clientIndex = ref(null); + +const bulkOpen = ref(false); +const bulkDbInbound = ref(null); + function onAddInbound() { formMode.value = 'add'; formDbInbound.value = null; @@ -64,6 +77,18 @@ function openEdit(dbInbound) { formOpen.value = true; } +function openAddClient(dbInbound) { + clientMode.value = 'add'; + clientDbInbound.value = dbInbound; + clientIndex.value = null; + clientOpen.value = true; +} + +function openAddBulkClient(dbInbound) { + bulkDbInbound.value = dbInbound; + bulkOpen.value = true; +} + // Per-row destructive actions go through Modal.confirm (matches legacy). function confirmDelete(dbInbound) { Modal.confirm({ @@ -173,6 +198,12 @@ function onRowAction({ key, dbInbound }) { case 'edit': openEdit(dbInbound); break; + case 'addClient': + openAddClient(dbInbound); + break; + case 'addBulkClient': + openAddBulkClient(dbInbound); + break; case 'delete': confirmDelete(dbInbound); break; @@ -295,6 +326,25 @@ function onRowAction({ key, dbInbound }) { :db-inbound="formDbInbound" @saved="refresh" /> + +