mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-07-18 02:26:11 +00:00
feat(clients): advanced filter drawer with multi-select state/protocol/inbound + expiry/usage ranges + auto-renew/tg/comment
The old toolbar exposed a single-value Search box, a single bucket radio, and one Protocol + Inbound dropdown. Real panels with hundreds of clients across mixed protocols need to slice by combinations (active + expiring, two specific inbounds, expiring within a window, high-usage subset, etc.), which the old shape couldn't express. Backend ClientPageParams now accepts comma-separated multi values for Filter / Protocol / Inbound and three new structured fields each: expiry/usage ranges (ms / bytes), and three trinary toggles (AutoRenew / HasTgID / HasComment with on/off, yes/no). The free-text search predicate also picks up UUID / Password / Auth, which were previously invisible to search. Frontend introduces a dedicated FilterDrawer (multi-select for state/protocol/inbound, DatePicker.RangePicker for expiry, paired InputNumbers for usage, radio buttons for the trinary toggles) opened from a single Filter button with a badge for the active count. Active filters render as closable chips above the table so the user can drop them one at a time, with a Clear-all next to the Filter button. The search box stays inline and always visible.
This commit is contained in:
@@ -42,11 +42,19 @@ export interface ClientQueryParams {
|
||||
page: number;
|
||||
pageSize: number;
|
||||
search?: string;
|
||||
// CSV strings — frontend joins arrays on ',', backend splits the same way.
|
||||
filter?: string;
|
||||
protocol?: string;
|
||||
inbound?: number;
|
||||
inbound?: string;
|
||||
sort?: string;
|
||||
order?: 'ascend' | 'descend';
|
||||
expiryFrom?: number;
|
||||
expiryTo?: number;
|
||||
usageFrom?: number;
|
||||
usageTo?: number;
|
||||
autoRenew?: 'on' | 'off' | '';
|
||||
hasTgId?: 'yes' | 'no' | '';
|
||||
hasComment?: 'yes' | 'no' | '';
|
||||
}
|
||||
|
||||
const DEFAULT_QUERY: ClientQueryParams = { page: 1, pageSize: 25 };
|
||||
@@ -61,9 +69,16 @@ function buildQS(p: ClientQueryParams): string {
|
||||
if (p.search) sp.set('search', p.search);
|
||||
if (p.filter) sp.set('filter', p.filter);
|
||||
if (p.protocol) sp.set('protocol', p.protocol);
|
||||
if (p.inbound && p.inbound > 0) sp.set('inbound', String(p.inbound));
|
||||
if (p.inbound) sp.set('inbound', p.inbound);
|
||||
if (p.sort) sp.set('sort', p.sort);
|
||||
if (p.order) sp.set('order', p.order);
|
||||
if (p.expiryFrom && p.expiryFrom > 0) sp.set('expiryFrom', String(p.expiryFrom));
|
||||
if (p.expiryTo && p.expiryTo > 0) sp.set('expiryTo', String(p.expiryTo));
|
||||
if (p.usageFrom && p.usageFrom > 0) sp.set('usageFrom', String(p.usageFrom));
|
||||
if (p.usageTo && p.usageTo > 0) sp.set('usageTo', String(p.usageTo));
|
||||
if (p.autoRenew) sp.set('autoRenew', p.autoRenew);
|
||||
if (p.hasTgId) sp.set('hasTgId', p.hasTgId);
|
||||
if (p.hasComment) sp.set('hasComment', p.hasComment);
|
||||
return sp.toString();
|
||||
}
|
||||
|
||||
@@ -105,9 +120,16 @@ export function useClients() {
|
||||
&& (prev.search ?? '') === (next.search ?? '')
|
||||
&& (prev.filter ?? '') === (next.filter ?? '')
|
||||
&& (prev.protocol ?? '') === (next.protocol ?? '')
|
||||
&& (prev.inbound ?? 0) === (next.inbound ?? 0)
|
||||
&& (prev.inbound ?? '') === (next.inbound ?? '')
|
||||
&& (prev.sort ?? '') === (next.sort ?? '')
|
||||
&& (prev.order ?? '') === (next.order ?? '')
|
||||
&& (prev.expiryFrom ?? 0) === (next.expiryFrom ?? 0)
|
||||
&& (prev.expiryTo ?? 0) === (next.expiryTo ?? 0)
|
||||
&& (prev.usageFrom ?? 0) === (next.usageFrom ?? 0)
|
||||
&& (prev.usageTo ?? 0) === (next.usageTo ?? 0)
|
||||
&& (prev.autoRenew ?? '') === (next.autoRenew ?? '')
|
||||
&& (prev.hasTgId ?? '') === (next.hasTgId ?? '')
|
||||
&& (prev.hasComment ?? '') === (next.hasComment ?? '')
|
||||
) return prev;
|
||||
return next;
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user