feat(devices): inline rename UI for connected HWID devices

Pairs with the bot commit that adds the user_device_aliases table.
Surfaces the new local_name field on the existing devices list in
both the user-facing subscription page and the admin user-detail
page, with the same inline-edit pattern in both places.

User-side (src/pages/Subscription.tsx):
- pencil button next to each device row toggles edit mode
- input is focused automatically, capped at 64 chars (matches the
  backend ALIAS_MAX_LENGTH and DB column width)
- Enter saves, Escape cancels, empty input clears the alias
- display priority: local_name → device_model → platform
- works identically in classic / single-tariff / multi-tariff —
  subscriptionId is forwarded as a query param like every other
  device-management endpoint already does

Admin-side (src/pages/AdminUserDetail.tsx):
- same pencil + inline input pattern, admin acts on behalf of the
  user. notify.success on save, loadDevices() refresh.

API (src/api/subscription.ts + src/api/adminUsers.ts):
- new renameDevice(hwid, name, subscriptionId?) on subscriptionApi
- new renameUserDevice(userId, hwid, name) on adminUsersApi
- existing getDevices/getUserDevices contracts widened with
  local_name?: string | null on the returned device shape

Locales (src/locales/ru.json):
- subscription.renameDevice / .renameDeviceSave / .renameDeviceCancel
  / .renameDevicePlaceholder / .deviceRenamed
- admin.users.detail.devices.rename / .renameSave / .renamed
This commit is contained in:
Fringg
2026-05-16 03:02:45 +03:00
parent d85da9e03f
commit 321c65b68b
6 changed files with 421 additions and 100 deletions

View File

@@ -141,6 +141,12 @@ export interface Device {
platform: string;
device_model: string;
created_at: string | null;
/**
* User-set local alias persisted in the bot DB (`user_device_aliases`).
* `null` when the user hasn't renamed the device — clients fall back
* to `device_model` / `platform` for display.
*/
local_name?: string | null;
}
export interface DevicesResponse {