# WidgetStackInfo Component

## Описание

Отладочный смарт-виджет памяти и задач FreeRTOS: занятость каждой кучи и минимальный запас стека
каждой задачи. Работает с одним объектом `StackInfo` ровно в том виде, в каком его отдаёт
`API_GetStackInfo` (ProdFactory-ESP и ProdFactory-STM — контракт общий), и с одним запросом
`GET StackInfo`. Компонент ничего не знает про DeviceStore/WebSocket — только `value` и `onRefresh`.

- **Кучи** — карточка на каждую: «занято X из Y», процент (оранжевый от 75%, красный от 90%) и
  полоса мастер-цвета; светлая подложка полосы — пик занятости с момента старта (`Total − MinFree`).
- **Задачи** — таблица «Задача / Состояние / Приоритет / Ядро / Запас». Порядок всегда по
  возрастанию запаса стека: самые рискованные сверху (сортировка кликом при автоопросе сбрасывалась
  бы на каждом ответе). Запас меньше `warnBytes` — красный, меньше удвоенного — оранжевый, над
  таблицей — число задач ниже порога. Колонка «Ядро» есть, только если устройство передаёт `Core`.
- **Обновление** — кнопка «Обновить» и автоопрос «Выкл / 1 с / 5 с / 10 с» (`period`); при
  включении опрос сразу шлёт запрос, свёрнутый виджет не опрашивает.

## Протокол устройства

```
"StackInfo": {
  "Heap": [
    { "Name": "Internal", "Total": 327680,  "Free": 118000,  "MinFree": 92000 },
    { "Name": "Default",  "Total": 4521984, "Free": 4100000, "MinFree": 4040000 }
  ],
  "Tasks": [{ "Name": "api_task", "FreeMin": 1240, "Prio": 5, "Core": 1, "State": 2 }]
}
```

Все размеры в байтах. ESP отдаёт две кучи (`Internal` — внутренний DRAM, `Default` — всё, что
отдаёт `malloc`, включая PSRAM) и `Core` (-1 — без привязки к ядру); STM — одну кучу `Heap`
(heap_4, `configTOTAL_HEAP_SIZE`) и без `Core`. `State` — `eTaskState`: 0 работает, 1 готова,
2 ожидает, 3 приостановлена, 4 удалена.

## Пропсы

| Название         | Тип                      | По умолчанию                  | Описание                                                                  |
| ---------------- | ------------------------ | ----------------------------- | ------------------------------------------------------------------------- |
| `wrapperClass`   | `string`                 | `""`                          | CSS-классы обёртки                                                        |
| `componentClass` | `string`                 | `""`                          | «Мастер-цвет» виджета — роль вида `"bg-red"`, перекрашивает весь виджет   |
| `label`          | `{ name?: string }`      | `{ name: "Память и задачи" }` | Заголовок карточки                                                        |
| `value`          | `IWidgetStackInfo`       | `undefined`                   | Снимок `StackInfo`; без него — «Нет данных»                               |
| `keys`           | `{ StackInfo?: string }` | `undefined`                   | Переопределение имени объекта ответа, по умолчанию `StackInfo`            |
| `argument`       | `string`                 | `undefined`                   | Аргумент запроса, по умолчанию `"StackInfo"` (используется вызывающим)    |
| `warnBytes`      | `number`                 | `512`                         | Порог подсветки запаса стека, байт                                        |
| `period`         | `number`                 | `0`                           | Период автоопроса, мс; 0 — только по кнопке (`$bindable`)                 |
| `collapsed`      | `boolean`                | `false`                       | Свёрнуто ли тело виджета (`$bindable`)                                    |
| `persistKey`     | `string`                 | `undefined`                   | Ключ для сохранения `collapsed` в `localStorage`                          |
| `onRefresh`      | `() => void`             | `undefined`                   | Запрос снимка (`GET StackInfo`); без обработчика кнопка и опрос неактивны |

## Примеры

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

  let stackInfo = $state()
</script>

<UI.WidgetStackInfo value={stackInfo} warnBytes={768} onRefresh={() => console.log("GET StackInfo")} />
```

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

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

Группы панели: общие (заголовок, мастер-цвет), отображение (`warnBytes`, `period`), устройство
(объект ответа, аргумент запроса).
