# WidgetDeviceInfo Component

## Описание

Смарт-виджет информации об устройстве. Как и `WidgetWiFi`, не привязывается к одной произвольной
переменной устройства — работает с фиксированным набором полей, соответствующих реальной
прошивочной конвенции (`main_config.c`, группа `CFG`, ProdFactory-ESP): `DevSN`, `DevID`, `DevFW`,
`RunCnt`, `StaIP`, `ApIP` — только чтение; `DevName`, `HostName`, `WebUser`, `WebPsw` —
редактируются локально и сохраняются одним пакетом по кнопке "Сохранить". Отдельная кнопка
"Перезагрузить" рядом с заголовком вызывает `onRestart` немедленно (не входит в пакет сохранения
полей). Реальное имя поля устройства для каждого ключа можно переопределить через `keys` (по
умолчанию совпадает с именем ключа). Компонент ничего не знает про DeviceStore/WebSocket —
только `value`/`onSave`/`onRestart`.

## Пропсы

| Название         | Тип                                       | По умолчанию                           | Описание                                                                        |
| ---------------- | ----------------------------------------- | -------------------------------------- | ------------------------------------------------------------------------------- |
| `wrapperClass`   | `string`                                  | `""`                                   | CSS-классы для обёртки компонента                                               |
| `componentClass` | `string`                                  | `""`                                   | "Мастер-цвет" виджета — роль вида `"bg-red"` (см. `optionsStore.COLOR_OPTIONS`) |
| `label`          | `{ name?: string }`                       | `{ name: "Информация об устройстве" }` | Заголовок карточки                                                              |
| `value`          | `IWidgetDeviceInfoConfig`                 | внутренний дефолт                      | Текущая информация об устройстве                                                |
| `collapsed`      | `boolean`                                 | `false`                                 | Свёрнуто ли тело виджета (заголовок остаётся); поддерживает двустороннее связывание (`$bindable`) |
| `persistKey`     | `string`                                  | `undefined`                             | Ключ для сохранения состояния `collapsed` в `localStorage` — при заданном ключе состояние сворачивания переживает перезагрузку страницы |
| `onSave`         | `(info: IWidgetDeviceInfoConfig) => void` | `undefined`                            | Срабатывает при нажатии "Сохранить" — редактируемые поля одним пакетом          |
| `onRestart`      | `() => void`                              | `undefined`                            | Срабатывает при нажатии "Перезагрузить"                                         |

### IWidgetDeviceInfoConfig

| Поле       | Тип      | Только чтение | Описание                    |
| ---------- | -------- | :-----------: | --------------------------- |
| `DevSN`    | `string` |      да       | Серийный номер устройства   |
| `DevID`    | `string` |      да       | ID устройства               |
| `DevFW`    | `number` |      да       | Версия ПО                   |
| `RunCnt`   | `number` |      да       | Счётчик запусков            |
| `DevName`  | `string` |      нет      | Имя устройства              |
| `HostName` | `string` |      нет      | Имя хоста                   |
| `WebUser`  | `string` |      нет      | Имя пользователя Web-панели |
| `WebPsw`   | `string` |      нет      | Пароль Web-панели           |
| `StaIP`    | `string` |      да       | Текущий IP-адрес в режиме STA |
| `ApIP`     | `string` |      да       | Текущий IP-адрес в режиме AP  |

## Примеры

```svelte
<script>
  import * as UI from "poe-svelte-ui-lib"

  const handleSave = (info) => {
    console.log("Отправка настроек одним пакетом:", info)
  }
</script>

<UI.WidgetDeviceInfo
  value={{
    DevSN: "00.00.000-00_0000AC670000B22B00007428:DBC5",
    DevID: "20.00.000-01",
    DevFW: 1.4,
    RunCnt: 128,
    DevName: "SYP-Device-01",
    HostName: "syp-device-01",
    WebUser: "admin",
    WebPsw: "",
    StaIP: "192.168.1.42",
    ApIP: "192.168.4.1",
  }}
  onSave={handleSave}
  onRestart={() => console.log("Перезагрузка устройства")}
/>
```

## Конструктор свойств (WidgetDeviceInfoProps.svelte)

### Пропсы конструктора

| Название           | Тип                                                                                             | Описание                                  |
| ------------------ | ----------------------------------------------------------------------------------------------- | ----------------------------------------- |
| `component`        | `UIComponent & { properties: Partial<IWidgetDeviceInfoProps> }`                                 | Объект компонента с его свойствами        |
| `onPropertyChange` | `(updates: Partial<{ properties?: string \| object; name?: string; access?: string }>) => void` | Коллбэк для обновления свойств компонента |

Панель содержит заголовок, мастер-цвет (через общий `WidgetAccentPicker.svelte`), префикс
прошивочной группы (ID), переопределение имени поля устройства для каждого ключа
`IWidgetDeviceInfoConfig` (по умолчанию совпадает с именем ключа) и команду перезагрузки
(Header/Argument, по умолчанию `SET`/`Restart`).

## Заметки

- Серийный номер устройства обычно длинный (например
  `00.00.000-00_0000AC670000B22B00007428:DBC5`) — в разметке занимает отдельную строку, чтобы не
  обрезаться в узкой сетке.
- `WebPsw` в реальном устройстве исторически передаётся обычным текстом; в виджете сделан
  `type="password"` для консистентности с остальным обликом конструктора.
