mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-05-13 09:36:05 +00:00
fix(inbounds): bulk-delete keeps last client to satisfy backend constraint
Some checks are pending
Release 3X-UI / build (386) (push) Waiting to run
Release 3X-UI / build (amd64) (push) Waiting to run
Release 3X-UI / build (arm64) (push) Waiting to run
Release 3X-UI / build (armv5) (push) Waiting to run
Release 3X-UI / build (armv6) (push) Waiting to run
Release 3X-UI / build (armv7) (push) Waiting to run
Release 3X-UI / build (s390x) (push) Waiting to run
Release 3X-UI / Build for Windows (push) Waiting to run
Some checks are pending
Release 3X-UI / build (386) (push) Waiting to run
Release 3X-UI / build (amd64) (push) Waiting to run
Release 3X-UI / build (arm64) (push) Waiting to run
Release 3X-UI / build (armv5) (push) Waiting to run
Release 3X-UI / build (armv6) (push) Waiting to run
Release 3X-UI / build (armv7) (push) Waiting to run
Release 3X-UI / build (s390x) (push) Waiting to run
Release 3X-UI / Build for Windows (push) Waiting to run
DelClient rejects the removal that would leave an inbound with zero
clients (the constraint exists because Xray protocols need at least
one client to keep the inbound functional). The bulk-delete flow
fired one DelClient call per picked client in a loop, so picking
every client meant the final iteration always errored out with
"no client remained in Inbound" and surfaced as a red toast even
though N-1 deletions had already gone through.
Now confirmBulkDelete detects the "all selected" case up front,
drops the last client from the request, and surfaces the partial
operation in the confirm dialog ("N-1 / N — last selected will
remain. Delete the inbound to remove all."). The pre-existing
single-row delete path and partial-selection bulk delete paths are
untouched. If the only client in the inbound is selected, a
Modal.warning explains the constraint instead of asking for confirm.
This commit is contained in:
parent
5f3e9ed0ea
commit
d8aedcdde4
1 changed files with 19 additions and 3 deletions
|
|
@ -219,14 +219,30 @@ watch(clients, (list) => {
|
||||||
function confirmBulkDelete() {
|
function confirmBulkDelete() {
|
||||||
const picked = clients.value.filter((c) => selected.value.has(rowKey(c)));
|
const picked = clients.value.filter((c) => selected.value.has(rowKey(c)));
|
||||||
if (picked.length === 0) return;
|
if (picked.length === 0) return;
|
||||||
|
|
||||||
|
const total = clients.value.length;
|
||||||
|
const keepLast = picked.length === total;
|
||||||
|
const toDelete = keepLast ? picked.slice(0, -1) : picked;
|
||||||
|
|
||||||
|
if (toDelete.length === 0) {
|
||||||
|
Modal.warning({
|
||||||
|
title: t('pages.inbounds.deleteClient'),
|
||||||
|
content: 'Inbound must keep at least one client — delete the inbound to remove all.',
|
||||||
|
okText: t('confirm'),
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Modal.confirm({
|
Modal.confirm({
|
||||||
title: t('pages.inbounds.deleteClient') + ` — ${picked.length}`,
|
title: `${t('pages.inbounds.deleteClient')} — ${toDelete.length}${keepLast ? ` / ${total}` : ''}`,
|
||||||
content: t('pages.inbounds.deleteClientContent'),
|
content: keepLast
|
||||||
|
? 'Inbound must keep at least one client — the last selected will remain. Delete the inbound to remove all.'
|
||||||
|
: t('pages.inbounds.deleteClientContent'),
|
||||||
okText: t('delete'),
|
okText: t('delete'),
|
||||||
okType: 'danger',
|
okType: 'danger',
|
||||||
cancelText: t('cancel'),
|
cancelText: t('cancel'),
|
||||||
onOk: () => {
|
onOk: () => {
|
||||||
emit('delete-clients', { dbInbound: props.dbInbound, clients: picked });
|
emit('delete-clients', { dbInbound: props.dbInbound, clients: toDelete });
|
||||||
clearSelection();
|
clearSelection();
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue