* feat(clients): allow removing a single HWID device
Only "list" and "clear all" existed for registered HWID devices, so
freeing one slot under a client's HWID limit meant clearing every
device and waiting for the ones you kept to re-register. Adds a
per-device delete: DELETE /panel/api/clients/hwids/:email/:id, scoped
to the client's own sub_id (device ids are a global auto-increment,
not per-subID, so this also prevents deleting another client's
device), plus a delete button next to each device in the existing
HWID modal.
Addresses MHSanaei/3x-ui#6245.
* feat(clients): surface HWID limit + device log in the client info card
Mirrors the existing IP-limit row/eye-icon-modal pattern that's
already in this card. The HWID devices modal reuses the same
list/clear-all/per-device-delete UI already shipped for the edit
form's own HWID modal, so a device can be removed without opening the
edit form at all.
* i18n: add HWID single-delete strings to all 13 locales
deleteHwid/deleteHwidConfirm/hwidDeleted were only added to en-US and
ru-RU in the previous commit; backfilling the other 11 locales the
project's own translation set covers.
* fix(clients): address automated review of HWID single-delete PR
- ClientInfoModal: use the existing dateLabel() helper (Jalali-aware)
for HWID first/last-seen instead of a raw dayjs format, matching
every other timestamp in the same modal.
- Add okText/cancelText to the delete-device Popconfirm in both
ClientInfoModal and ClientFormModal so all 13 locales get a
translated confirm dialog instead of Antd's English default.
- deleteHwid controller: stop reusing the success toast key on both
error paths, which rendered a red "Update successful" toast on a
real (not just theoretical) failure such as a stale HWID modal.
- Trim DeleteClientHwid's doc comment to the repo's 2-line cap and
correct it: deletion is scoped by sub_id, which can span more than
one ClientRecord, not strictly "this client only".
- Add TestDeleteClientHwid covering cross-sub_id id rejection, unknown
id rejection, and a real successful delete.
* chore: retrigger CI (previous run stuck installing Playwright Chromium)
* fix(clients): address the arbiter review on the HWID single-delete PR
- Extract the HWID device list into a shared frontend/src/lib/clients/
hwid-log.ts type/normalizer, a shared useClientHwids hook, and a
shared ClientHwidListModal component, mirroring the existing IP-log
pattern. ClientInfoModal and ClientFormModal both render the same
component now, so the two copies can no longer drift the way they
already had (different date formatting, different tag styles).
- Add a Popconfirm to the HWID "Clear all" button (previously
unconfirmed, unlike the per-device delete right next to it) — closes
the confirm/no-confirm asymmetry the review flagged as the main risk.
- Sync docs/public/openapi.json with the two hwids paths and regenerate
clients.mdx. Scoped to just those two paths rather than a full copy
from frontend/public/openapi.json: the docs copy is far enough behind
on unrelated paths (a host-group API rename) that a full sync breaks
the Next.js build on locale pages referencing the old shape — out of
scope for this PR.
* fix(clients): trim HWID list comment blocks to 2 lines
Repo convention caps comment blocks at 2 lines; both were 1 line over.
* chore: retrigger CI
build (arm64) and build (armv6) failed on a transient Go module proxy
network error (INTERNAL_ERROR stream reset), unrelated to this PR's
changes.