3x-ui/web/service
MHSanaei 93eda06878
feat(clients,groups): client groups + sub-links export + dedicated groups page
Persistent client groups
- New ClientGroup model + client_groups table that holds empty
  (placeholder) groups so a user can define a label before any client
  references it. ListGroups merges these with the distinct group_name
  values already stored on clients and reports {name, clientCount}.
- ClientRecord gains group_name column; the model.Client wire shape
  gains a matching `group` JSON field that survives the
  inbound.settings → SyncInbound round-trip.
- Rename/Delete on a group mutates client_groups (rename row / delete
  row) AND propagates to all matching clients in ClientRecord and in
  every owning inbound's settings JSON, all in one transaction.

Bulk operations
- AssignGroup(emails, group) updates clients.group_name + patches each
  affected inbound's settings JSON in one read-modify-write per inbound.
  Empty group clears the label. Auto-creates the client_groups row when
  the user assigns to a brand-new name.
- BulkResetTraffic(emails) loops the existing single-reset path so the
  caller can zero traffic across a whole selection or a whole group.
- EmailsByGroup(name) returns just the email list (used by the groups
  page to fan a single bulk action over every member).

Endpoints (all under /panel/api/clients)
- GET  /groups                         — summaries with counts
- GET  /groups/:name/emails            — emails in a group
- POST /groups/create                  — empty placeholder group
- POST /groups/rename                  — rename (table + clients + JSON)
- POST /groups/delete                  — drop label everywhere (clients survive)
- POST /bulkAssignGroup                — assign N selected clients
- POST /bulkResetTraffic               — reset traffic on a list

Clients page UX
- New Group column (Actions → Client → Group → Inbounds → …) with a
  click-to-filter chip.
- FilterDrawer gains a multi-select Group filter whose options come
  from the new ClientPageResponse.groups field (sourced from ListGroups
  so empty/placeholder groups are pickable too).
- Single-client and bulk-add forms gain a Group AutoComplete pre-loaded
  with all known group names.
- New toolbar buttons when selection > 0: "Group ({n})" opens
  BulkAssignGroupModal, "Sub links ({n})" opens SubLinksModal.

Sub-links export modal (new SubLinksModal.tsx)
- Table of selected clients with their subscription URL (and JSON URL
  when subJsonEnable is on), per-row copy, Copy all, and Download as
  sub-links-<timestamp>.txt. Warns when subscription is disabled or
  none of the selected clients have a subId.

Dedicated Groups page (new pages/groups/GroupsPage.tsx)
- /groups route + sidebar entry (TagsOutlined icon) + page title key.
- Card-based layout matching Clients/Inbounds/Nodes — summary card with
  Total/Grouped/Empty stats, main card with Add Group button + table.
- Per-row More dropdown (icon-first column on the left): Sub links,
  Adjust (days+traffic), Reset traffic, Rename, Delete clients in
  group, Delete group (keep clients). Empty groups disable the
  client-targeted actions.
- Reuses SubLinksModal and ClientBulkAdjustModal — emails for the
  group are fetched on demand from GET /groups/:name/emails.

Other polish
- /groups + groups-page selectors added to page-shell.css and
  page-cards.css so the new page inherits the same background, padding,
  card borders, hover shadow, and summary-card padding.
- .card-toolbar gains a small vertical padding so the larger toolbar
  buttons (now default size, matching Inbounds) don't crowd the top of
  the card-head on Clients and Groups pages.
2026-05-27 17:30:55 +02:00
..
api_token.go feat(api-tokens): manage multiple named tokens; add tab/section anchor URLs 2026-05-13 16:34:31 +02:00
client.go feat(clients,groups): client groups + sub-links export + dedicated groups page 2026-05-27 17:30:55 +02:00
client_sync_multiprotocol_test.go feat: complete Zod migration of frontend + bulk client batching (#4599) 2026-05-27 04:26:50 +02:00
client_test.go Feat/multi inbound clients (#4469) 2026-05-19 12:20:24 +02:00
config.json fix(xray): allow private-IP destinations via freedom finalRules 2026-05-19 15:42:16 +02:00
custom_geo.go fix(security): SSRF-guard node and remote HTTP clients 2026-05-13 13:33:53 +02:00
custom_geo_test.go v3 2026-05-10 02:13:42 +02:00
fallback.go Feat/multi inbound clients (#4469) 2026-05-19 12:20:24 +02:00
inbound.go feat(clients): toolbar sort selector + preserve updated_at on unchanged rows 2026-05-27 15:07:17 +02:00
metric_history.go Feat/multi inbound clients (#4469) 2026-05-19 12:20:24 +02:00
node.go Feat/multi inbound clients (#4469) 2026-05-19 12:20:24 +02:00
node_test.go Feat/multi inbound clients (#4469) 2026-05-19 12:20:24 +02:00
nord.go feat(xray/nord): searchable server list + colored load tag, surface API errors 2026-05-11 10:06:01 +02:00
outbound.go refactor(outbound): probe via xray burstObservatory instead of SOCKS round-trip 2026-05-27 04:53:13 +02:00
panel.go Feat/multi inbound clients (#4469) 2026-05-19 12:20:24 +02:00
panel_other.go feat: add panel update functionality via web GUI (#4117) 2026-04-28 18:46:55 +02:00
panel_test.go feat: add panel update functionality via web GUI (#4117) 2026-04-28 18:46:55 +02:00
panel_unix.go feat: add panel update functionality via web GUI (#4117) 2026-04-28 18:46:55 +02:00
port_conflict.go docs(port-conflict): refresh stale comments after the refactor 2026-05-27 12:57:37 +02:00
port_conflict_test.go feat(port-conflict): include offending inbound + L4 in the error, cover quic and tunnel.allowedNetwork 2026-05-27 12:56:15 +02:00
server.go Frontend rewrite: React + TypeScript with AntD v6 (#4498) 2026-05-23 15:21:45 +02:00
server_vlessenc_test.go Feat: clarify VLESS encryption auth selection (#4271) 2026-05-12 11:39:28 +02:00
setting.go feat: complete Zod migration of frontend + bulk client batching (#4599) 2026-05-27 04:26:50 +02:00
setting_security_test.go feat(api-tokens): manage multiple named tokens; add tab/section anchor URLs 2026-05-13 16:34:31 +02:00
tgbot.go Feat/multi inbound clients (#4469) 2026-05-19 12:20:24 +02:00
tgbot_test.go Feat/multi inbound clients (#4469) 2026-05-19 12:20:24 +02:00
traffic_writer.go Fix: traffic writer restart freeze (#4265) 2026-05-12 11:36:05 +02:00
traffic_writer_test.go Fix: traffic writer restart freeze (#4265) 2026-05-12 11:36:05 +02:00
url_safety.go Security hardening: sessions, SSRF, CSP nonce, CSRF logout, trusted proxies (#4275) 2026-05-13 12:52:52 +02:00
user.go fix(auth): invalidate sessions when 2FA is enabled, fix dev 401 loop 2026-05-13 14:08:16 +02:00
warp.go fix(warp): set license against Cloudflare API and surface errors inline 2026-05-13 21:13:16 +02:00
websocket.go v3 2026-05-10 02:13:42 +02:00
xray.go feat: complete Zod migration of frontend + bulk client batching (#4599) 2026-05-27 04:26:50 +02:00
xray_metrics.go Security hardening: sessions, SSRF, CSP nonce, CSRF logout, trusted proxies (#4275) 2026-05-13 12:52:52 +02:00
xray_setting.go Feat/multi inbound clients (#4469) 2026-05-19 12:20:24 +02:00
xray_setting_test.go Feat/multi inbound clients (#4469) 2026-05-19 12:20:24 +02:00