mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-07-15 00:56:08 +00:00
feat(clients): orphan cleanup + export/import via CodeMirror modals
Add three client-management actions to the Clients page More menu:
- Delete unattached clients: removes every client with no inbound
attachment, cascading its traffic rows, IP log, and external links
(POST /clients/delOrphans).
- Export clients: shows the {client, inboundIds} list in a read-only
CodeMirror viewer with copy/download (GET /clients/export returns the
array in the standard envelope).
- Import clients: pastes that JSON into an editable CodeMirror editor,
mirroring Import an Inbound (POST /clients/import takes a { data }
body). Attached clients go through the create-and-attach path; items
with no inboundIds are restored as bare records; existing emails are
never overwritten and are reported as skipped.
Document the new endpoints in api-docs and translate the new strings
into all supported languages.
This commit is contained in:
@@ -402,6 +402,22 @@ export function useClients() {
|
||||
onSuccess: (msg) => { if (msg?.success) invalidateAll(); },
|
||||
});
|
||||
|
||||
const delOrphansMut = useMutation({
|
||||
mutationFn: async () => {
|
||||
const raw = await HttpUtil.post('/panel/api/clients/delOrphans');
|
||||
return parseMsg(raw, DelDepletedResultSchema, 'clients/delOrphans');
|
||||
},
|
||||
onSuccess: (msg) => { if (msg?.success) invalidateAll(); },
|
||||
});
|
||||
|
||||
const importClientsMut = useMutation({
|
||||
mutationFn: async (data: string): Promise<Msg<BulkCreateResult>> => {
|
||||
const raw = await HttpUtil.post('/panel/api/clients/import', { data }, JSON_HEADERS);
|
||||
return parseMsg(raw, BulkCreateResultSchema, 'clients/import');
|
||||
},
|
||||
onSuccess: (msg) => { if (msg?.success) invalidateAll(); },
|
||||
});
|
||||
|
||||
const create = useCallback((payload: unknown) => createMut.mutateAsync(payload), [createMut]);
|
||||
const update = useCallback((email: string, client: unknown) => {
|
||||
if (!email) return Promise.resolve(null as unknown as Msg<unknown>);
|
||||
@@ -459,6 +475,15 @@ export function useClients() {
|
||||
}, [resetTrafficMut]);
|
||||
const resetAllTraffics = useCallback(() => resetAllTrafficsMut.mutateAsync(), [resetAllTrafficsMut]);
|
||||
const delDepleted = useCallback(() => delDepletedMut.mutateAsync(), [delDepletedMut]);
|
||||
const delOrphans = useCallback(() => delOrphansMut.mutateAsync(), [delOrphansMut]);
|
||||
const importClients = useCallback((data: string) => importClientsMut.mutateAsync(data), [importClientsMut]);
|
||||
// Fetch the exported clients so the page can show them in a CodeMirror viewer
|
||||
// (Copy / Download), rather than triggering an immediate browser download.
|
||||
const exportClients = useCallback(async (): Promise<unknown[] | null> => {
|
||||
const msg = await HttpUtil.get('/panel/api/clients/export');
|
||||
if (!msg?.success) return null;
|
||||
return Array.isArray(msg.obj) ? msg.obj : [];
|
||||
}, []);
|
||||
|
||||
const setEnable = useCallback(async (client: ClientRecord, enable: boolean) => {
|
||||
if (!client?.email) return null;
|
||||
@@ -575,6 +600,9 @@ export function useClients() {
|
||||
resetTraffic,
|
||||
resetAllTraffics,
|
||||
delDepleted,
|
||||
delOrphans,
|
||||
exportClients,
|
||||
importClients,
|
||||
setEnable,
|
||||
applyTrafficEvent,
|
||||
applyClientStatsEvent,
|
||||
|
||||
Reference in New Issue
Block a user