Files
3x-ui/frontend/src/api/queries/useClientOptions.ts
Zane 02002dc1c3 feat(routing): add client picker to user rules (#6271)
* feat(routing): add client picker to user rules

Replace the free-text user criterion with a searchable multi-select backed by existing panel clients. Preserve saved values that no longer exist so editing legacy rules remains lossless.

* feat(routing): polish user picker states

Align the routing user selector with the inbound-tag multi-select, including search, clear, loading, empty, and error states. Localize the new copy across every supported locale and cover legacy saved users with a regression test.

* fix(routing): keep custom user identifiers

Use tags mode with comma tokenization so the user picker suggests panel clients without rejecting HTTP, Mixed, or raw-template identifiers. Restore the comma hint and cover custom entries with a regression test.
2026-08-22 23:13:34 +02:00

34 lines
1.0 KiB
TypeScript

import { useQuery } from '@tanstack/react-query';
import { z } from 'zod';
import { HttpUtil } from '@/utils';
import { parseMsg } from '@/utils/zodValidate';
import { keys } from '@/api/queryKeys';
import { ClientRecordSchema, type ClientRecord } from '@/schemas/client';
const ClientRecordListSchema = z
.array(ClientRecordSchema)
.nullable()
.transform((value) => value ?? []);
async function fetchClients(): Promise<ClientRecord[]> {
const msg = await HttpUtil.get('/panel/api/clients/list', undefined, { silent: true });
if (!msg?.success) throw new Error(msg?.msg || 'Failed to load clients');
const validated = parseMsg(msg, ClientRecordListSchema, 'clients/list');
return validated.obj ?? [];
}
export function useClientOptions(enabled = true) {
return useQuery({
queryKey: keys.clients.all(),
queryFn: fetchClients,
enabled,
staleTime: 30_000,
select: (clients) =>
clients
.map((client) => client.email.trim())
.filter(Boolean)
.sort((a, b) => a.localeCompare(b)),
});
}