mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-08-14 23:31:00 +00:00
feat(clients): bulk-set XTLS flow from the Adjust dialog (#5524)
* feat(clients): bulk-set XTLS flow from the Adjust dialog Add a "Set flow" dropdown to the bulk Adjust dialog so an admin can set or clear the XTLS flow on all selected clients at once, alongside the existing days/traffic bumps. Empty by default (no effect on save); "Disable" clears flow, and the two vision values mirror the per-client credential tab. Flow rides the existing inbound-JSON -> SyncInbound path (ClientRecord.Flow + client_inbounds.flow_override), so no new endpoint, DB column, or migration. Setting a vision flow is gated by inboundCanEnableTlsFlow: ineligible inbounds are left untouched and reported as skipped; clearing is always allowed. A real flow change requests an xray restart (local) or a node reconcile (remote). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(clients): keep days/traffic write when bulk flow is ineligible Address review on the bulk-flow-adjust PR: - Blocking: a client adjusted with both a days/traffic delta and a flow directive on a flow-ineligible inbound had the flow-ineligibility recorded into the same skip set that gates the ClientTraffic write, so the inbound JSON / ClientRecord advanced but ClientTraffic did not — divergent stores, and the client misreported as skipped. Track flow ineligibility in its own map (bulkInboundAdjustResult.flowIneligible) so it only feeds the final Skipped report and never suppresses the expiry/total persistence. - Drop the broad delete(skippedReasons, email): flow reasons no longer enter skippedReasons, so honoring a flow can no longer erase an unrelated skip reason (unlimited expiry, a real persistence error on another inbound). - Drop the inline comment block from ClientBulkAdjustModal.tsx (file had none); move the whitelist-sync note next to bulkFlowAllowed, the source of truth. - Document the optional flow field in the bulkAdjust API-docs example (endpoints.ts) and regenerate openapi.json. - Add a regression test covering days+flow on an ineligible inbound. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -341,7 +341,7 @@ export function useClients() {
|
||||
});
|
||||
|
||||
const bulkAdjustMut = useMutation({
|
||||
mutationFn: async (payload: { emails: string[]; addDays: number; addBytes: number }): Promise<Msg<BulkAdjustResult>> => {
|
||||
mutationFn: async (payload: { emails: string[]; addDays: number; addBytes: number; flow: string }): Promise<Msg<BulkAdjustResult>> => {
|
||||
const raw = await HttpUtil.post('/panel/api/clients/bulkAdjust', payload, JSON_HEADERS);
|
||||
return parseMsg(raw, BulkAdjustResultSchema, 'clients/bulkAdjust');
|
||||
},
|
||||
@@ -435,9 +435,9 @@ export function useClients() {
|
||||
if (!Array.isArray(payloads) || payloads.length === 0) return Promise.resolve(null as unknown as Msg<BulkCreateResult>);
|
||||
return bulkCreateMut.mutateAsync(payloads);
|
||||
}, [bulkCreateMut]);
|
||||
const bulkAdjust = useCallback((emails: string[], addDays: number, addBytes: number) => {
|
||||
const bulkAdjust = useCallback((emails: string[], addDays: number, addBytes: number, flow = '') => {
|
||||
if (!Array.isArray(emails) || emails.length === 0) return Promise.resolve(null);
|
||||
return bulkAdjustMut.mutateAsync({ emails, addDays, addBytes });
|
||||
return bulkAdjustMut.mutateAsync({ emails, addDays, addBytes, flow });
|
||||
}, [bulkAdjustMut]);
|
||||
const bulkAddToGroup = useCallback((emails: string[], group: string) => {
|
||||
if (!Array.isArray(emails) || emails.length === 0) return Promise.resolve(null);
|
||||
|
||||
Reference in New Issue
Block a user