mirror of
https://github.com/Matysh/houseplan-card
synced 2026-10-07 06:59:46 +00:00
482 lines
38 KiB
Markdown
482 lines
38 KiB
Markdown
# Всегда статичный значок устройства
|
||
|
||
Статус: **ТЗ актуализировано по ревью, реализовано и проверено в v1.60.2**
|
||
Дата: **2026-08-08**
|
||
Область: **редактор устройств, все поверхности отображения marker, единый resolver визуального состояния, backend-валидация и пользовательская документация**
|
||
|
||
## 1. Краткое продуктовое решение
|
||
|
||
В поле **«Отображение»** добавляется четвёртый режим:
|
||
|
||
**«Всегда статичный значок»**.
|
||
|
||
В этом режиме видимый marker устройства всегда имеет один и тот же нейтральный вид:
|
||
|
||
- стандартная тёмная подложка marker;
|
||
- базовая выбранная или автоматически определённая иконка;
|
||
- заданные пользователем размер и угол поворота;
|
||
- без изменения подложки, прозрачности, цвета и иконки из-за состояния Home Assistant;
|
||
- без activity/pulse-эффекта;
|
||
- без RGB-окраски от источника света;
|
||
- без подмены иконки по состоянию;
|
||
- без живых дополнительных значений температуры, влажности и качества связи.
|
||
- без отдельного движущегося puck, следа и других state-driven overlays живого пылесоса.
|
||
|
||
Режим является **только способом отображения marker**. Он не изменяет привязку, действия по нажатию, принадлежность комнате, участие устройства в управлении, источниках света, Glow, заливке комнаты или расчётах плана.
|
||
|
||
Текущий режим **«Значок»** переименовывается в:
|
||
|
||
- RU: **«Значок + динамическая подложка»**;
|
||
- EN: **«Icon + dynamic plate»**.
|
||
|
||
Его внутренняя модель и текущее поведение не меняются. Он остаётся режимом по умолчанию.
|
||
|
||
## 2. Причина изменения
|
||
|
||
Сейчас минимальный режим `badge`, показанный пользователю как «Значок», всё равно является динамическим:
|
||
|
||
- работающие устройства получают жёлтую подложку;
|
||
- открытые объекты получают отдельное состояние;
|
||
- тревоги становятся красными;
|
||
- `off`, `unknown` и `unavailable` используют приглушённое представление согласно действующей общей логике;
|
||
- некоторые классы устройств меняют саму иконку по состоянию;
|
||
- активный источник света может передавать marker цвет;
|
||
- при включённых общих настройках рядом появляются температура, влажность или LQI.
|
||
|
||
Название «Значок» не объясняет эту динамику, а отдельного способа намеренно оставить устройство визуально нейтральным нет. Это особенно заметно у устройств с большим числом вспомогательных сущностей, у декоративных marker и у объектов, состояние которых не нужно акцентировать на плане.
|
||
|
||
## 3. Цели
|
||
|
||
1. Дать пользователю предсказуемый режим, в котором HA state не меняет вид marker.
|
||
2. Явно назвать существующий режим `badge` динамическим.
|
||
3. Сохранить текущий режим по умолчанию для новых и существующих устройств.
|
||
4. Обеспечить одинаковый результат на интерактивном плане, в карточке пространства и в предпросмотре настроек.
|
||
5. Не смешивать отображение marker с логикой света, управления и данных плана.
|
||
6. Не требовать миграции существующих конфигураций.
|
||
|
||
## 4. Не входит в задачу
|
||
|
||
- изменение правил, по которым определяется состояние устройства;
|
||
- изменение `resolvedLightSources(room)`;
|
||
- изменение Glow, заливки «Свет» или управления источниками света;
|
||
- изменение tap action, more-info или диалога устройства;
|
||
- создание отдельной пользовательской палитры статичного marker;
|
||
- фиксация автоматически выбранной MDI-иконки как ручного override;
|
||
- изменение правил скрытых, удалённых и деактивированных в HA устройств;
|
||
- изменение поведения остальных трёх режимов, кроме переименования `badge` в UI.
|
||
|
||
Touch editor: **best effort / intentionally degraded** согласно `docs/TOUCH-SUPPORT.md`. Native select обязан оставаться сохранённым и работоспособным на узком экране, но мобильная компоновка редактора не является отдельной feature-parity целью. View и kiosk полностью поддерживаются.
|
||
|
||
## 5. Список режимов и порядок в UI
|
||
|
||
Порядок в выпадающем списке **обязателен**:
|
||
|
||
| № | Persisted value | RU | EN | Краткое поведение |
|
||
|---:|---|---|---|---|
|
||
| 1 | `badge` или `null` | Значок + динамическая подложка | Icon + dynamic plate | Иконка и текущая динамическая подложка |
|
||
| 2 | `icon_ripple` | Значок + активность | Icon + activity | Динамическая подложка плюс activity-эффект |
|
||
| 3 | `value` | Значение вместо иконки | Value instead of an icon | Значение, когда его можно однозначно получить, иначе иконка |
|
||
| 4 | `static_icon` | Всегда статичный значок | Always static icon | Всегда нейтральная подложка и базовая иконка |
|
||
|
||
Legacy-значение `ripple` по-прежнему принимается только для чтения и нормализуется в `icon_ripple`; в UI оно не показывается.
|
||
|
||
## 6. Значение по умолчанию и совместимость
|
||
|
||
### 6.1. Новые устройства
|
||
|
||
Новый marker по умолчанию получает UI-режим `badge`. При сохранении значение может, как и сейчас, быть записано как `null`/отсутствующее поле. Это означает **«Значок + динамическая подложка»**, а не статичный значок.
|
||
|
||
### 6.2. Существующие устройства
|
||
|
||
- отсутствующий `display` → `badge`;
|
||
- `display: null` → `badge`;
|
||
- `display: "badge"` → `badge`;
|
||
- `display: "ripple"` → `icon_ripple`;
|
||
- `display: "icon_ripple"` → `icon_ripple`;
|
||
- `display: "value"` → `value`;
|
||
- `display: "static_icon"` → новый статичный режим;
|
||
- неизвестное значение во frontend должно безопасно давать `badge`, а backend продолжает отклонять его при записи.
|
||
|
||
Автоматически переводить существующие устройства в `static_icon` запрещено.
|
||
|
||
### 6.3. Изменение режима
|
||
|
||
Переключение режима в открытом диалоге сразу обновляет предпросмотр, но не меняет server config до нажатия **«Сохранить»**. Отмена диалога возвращает сохранённый режим.
|
||
|
||
## 7. Нормативный визуальный контракт `static_icon`
|
||
|
||
### 7.1. Что остаётся видимым
|
||
|
||
- базовая иконка `d.icon`;
|
||
- ручная иконка, если пользователь её выбрал;
|
||
- автоматически определённая иконка, если ручного override нет;
|
||
- пользовательский размер marker;
|
||
- пользовательский угол поворота;
|
||
- обычная рамка и тень нейтрального marker согласно теме House Plan.
|
||
|
||
«Чёрная подложка» в требованиях означает текущую **стандартную нейтральную подложку marker**, а не жёстко заданный `#000000`. Реализация обязана использовать действующие theme tokens (`--hp-bg`, `--hp-line`, `--hp-txt` или их актуальные преемники), чтобы сохранить контраст и совместимость с темами HA.
|
||
|
||
### 7.2. Что принудительно отключается
|
||
|
||
Для `static_icon` renderer-ready presentation всегда получает:
|
||
|
||
- `visual.availability = "available"`;
|
||
- `visual.status = "neutral"`;
|
||
- `visual.activity = "none"`;
|
||
- `activity = "none"`;
|
||
- `valueText = null`;
|
||
- `valueFullText = null`;
|
||
- `fallbackReason = null`;
|
||
- `tempText = null`;
|
||
- `humText = null`;
|
||
- `lqiText = null`;
|
||
- `lqiColor = null`;
|
||
- `lightColor = null`;
|
||
- базовую, а не state-morphed иконку;
|
||
- отсутствие классов `on`, `open`, `alarm`, `unavail` и `activity-*`.
|
||
|
||
Отдельный live-vacuum renderer также обязан скрыть движущийся puck, текущий/предыдущий след и room-highlight для этого marker. Runtime/серверная запись следа может продолжаться независимо: смена режима отображения не удаляет историю уборки.
|
||
|
||
Ручные `ripple_color` и `ripple_size`, оставшиеся в старой конфигурации, не используются и не показываются в форме, пока выбран `static_icon`. Их сохранённые значения не должны неожиданно влиять на статичный marker.
|
||
|
||
### 7.3. Состояния, которые не меняют marker
|
||
|
||
| Условие | Результат в `static_icon` |
|
||
|---|---|
|
||
| Устройство включено | Нейтральный marker |
|
||
| Устройство выключено | Тот же нейтральный marker |
|
||
| Устройство работает | Тот же нейтральный marker |
|
||
| Устройство остановлено | Тот же нейтральный marker |
|
||
| Движение/присутствие обнаружено | Тот же нейтральный marker |
|
||
| Cover открывается/закрывается | Тот же нейтральный marker и базовая иконка |
|
||
| Дверь/замок открыт | Тот же нейтральный marker |
|
||
| Сущность `unknown`/`unavailable` | Тот же нейтральный marker, без fade |
|
||
| Тревога/протечка/дым | Тот же нейтральный marker, без красной подложки |
|
||
| Свет включён | Тот же нейтральный marker, без жёлтой/RGB-подложки |
|
||
| Краткое event-событие | Тот же marker, без activity ring |
|
||
| Общая настройка live states включена/выключена | Тот же marker |
|
||
| Включены temperature/LQI badges | Для этого marker badges не показываются |
|
||
| Живой пылесос движется или имеет сохранённый след | Puck, след и room-highlight не рисуются |
|
||
|
||
Подавление тревоги является осознанным следствием режима. Предпросмотр и диалог Home Assistant всё ещё могут показывать фактическое тревожное состояние, но marker на плане не сигнализирует о нём.
|
||
|
||
## 8. Граница между отображением и поведением устройства
|
||
|
||
`static_icon` меняет только лицо marker. Следующие возможности продолжают работать без изменений:
|
||
|
||
- клик, more-info, toggle, cover action, run action и подтверждение действия;
|
||
- `controls` и управление связанными источниками света;
|
||
- `is_light` и автоматическое определение светового источника;
|
||
- Glow и заливка «Свет по источникам»;
|
||
- световой вклад устройства в карточку комнаты и controls;
|
||
- принадлежность пространству/комнате;
|
||
- температура устройства как источник комнатной температуры, если это настроено;
|
||
- данные в tooltip/more-info и предпросмотре настроек;
|
||
- автоматическое обновление HA state внутри модели данных.
|
||
|
||
Если статичный marker выглядит доступным, но его active binding фактически имеет state `unavailable`, действие по нажатию проходит по существующему безопасному пути. Ошибка service call обязательно показывается существующим toast/HA feedback и не должна превращаться в молчаливый no-op. Новый режим не симулирует доступность сервиса и не подавляет ошибки действий.
|
||
|
||
Следствие: источник света в режиме `static_icon` может освещать комнату и создавать Glow, оставаясь сам визуально чёрным. Если пользователь не хочет, чтобы устройство влияло на освещение, для этого используется существующая настройка **«Это устройство — источник света»** и/или список управляемых источников, а не режим отображения.
|
||
|
||
## 9. Приоритеты и исключения видимости
|
||
|
||
Режим `static_icon` действует только на marker, который по общим правилам разрешено показывать.
|
||
|
||
| Ситуация | Приоритет над `static_icon` |
|
||
|---|---|
|
||
| Marker удалён с плана | Не отображается и снова доступен к добавлению |
|
||
| Пользователь нажал «Скрыть» | Не отображается в просмотре |
|
||
| В редакторе включено «Показать скрытые» | Показывается как служебный blue ghost, а не как обычный чёрный marker |
|
||
| Устройство деактивировано в HA | Принудительно скрыто в просмотре; в разрешённом design-preview показывается HA-disabled ghost |
|
||
| Привязка orphaned | Обрабатывается по отдельному lifecycle-контракту disabled-devices; `static_icon` не возвращает marker на поверхность, где общий контракт запрещает его рендер, и не маскирует диагностику потерянной привязки |
|
||
| Marker выбран в редакторе | Допускается внешняя рамка выделения |
|
||
| Keyboard focus | Обязателен `focus-visible` outline для доступности |
|
||
| Новый marker | Допускается служебная точка «новое устройство» |
|
||
|
||
Служебные editor/diagnostic overlays не считаются реакцией на состояние устройства. Они не должны перекрашивать внутреннюю подложку обычного видимого статичного marker.
|
||
|
||
## 10. Hover, focus и действия
|
||
|
||
Интерактивные состояния интерфейса не входят в понятие статичности устройства и сохраняют текущее общее поведение marker:
|
||
|
||
- hover продолжает использовать существующую accent-подсветку;
|
||
- pointer cursor, tooltip и действие по клику сохраняются;
|
||
- keyboard focus обозначается существующим focus-состоянием;
|
||
- выбор marker в редакторе обозначается существующей рамкой/тенью;
|
||
- drag feedback сохраняется, но не должен имитировать HA-состояния `on`, `open`, `alarm` или `unavailable`.
|
||
|
||
После завершения hover/focus/selection/drag marker возвращается к своей нейтральной статичной подложке. Новый режим подавляет только визуальные реакции на данные и состояния устройства, но не обратную связь на действия пользователя.
|
||
|
||
## 11. Предпросмотр устройства
|
||
|
||
`hp-device-preview` обязан использовать тот же `ResolvedDevicePresentation`, что и план и `houseplan-space-card`.
|
||
|
||
При выборе `static_icon`:
|
||
|
||
- stage сразу показывает нейтральную подложку и базовую иконку;
|
||
- кнопка демонстрации activity не показывается;
|
||
- строка «Текущее состояние» продолжает показывать фактический state HA;
|
||
- строка «Источник отображения» продолжает показывать сущность/сущности;
|
||
- строка интеграции продолжает показывать provider;
|
||
- строка «Результат» показывает локализованное объяснение:
|
||
RU: **«Статичный режим: состояние устройства не меняет значок»**;
|
||
EN: **«Static mode: device state does not change the icon»**;
|
||
- тревога, недоступность и активность могут быть видны в фактах/технических подробностях, но не меняют stage;
|
||
- режим не создаёт и не изменяет activity runtime.
|
||
|
||
Если привязка содержит alarm-capable сущность (`smoke`, `gas`, `carbon_monoxide`, `moisture`, `safety`, `tamper`, `problem`, siren или alarm panel), под select показывается неблокирующее предупреждение: статичный режим скроет визуальную тревогу marker. Предупреждение не запрещает Save и не зависит от того, активна ли тревога прямо сейчас.
|
||
|
||
В `PresentationReason` добавляется отдельная причина `static_icon`. Она имеет приоритет после `ha_disabled`/`orphaned`, но до alarm/availability/state причин для обычного renderable marker.
|
||
|
||
## 12. Автоматическая и ручная иконка
|
||
|
||
Статичный режим использует **базовую effective icon**:
|
||
|
||
- ручной `marker.icon`, если он задан;
|
||
- иначе иконку, определённую текущими правилами автоматического выбора.
|
||
|
||
State morph запрещён: например, cover не меняет `mdi:...-closed` на `mdi:...-open` при изменении state.
|
||
|
||
Автоматическая иконка не превращается в ручной override только из-за выбора `static_icon`. Поэтому она может измениться после реального изменения метаданных устройства или правил иконок. Если пользователю нужна полностью зафиксированная MDI-иконка и при изменении конфигурации HA, он должен нажать существующее действие фиксации автоматической иконки.
|
||
|
||
## 13. Модель данных и backend
|
||
|
||
### 13.1. Frontend
|
||
|
||
Канонический тип:
|
||
|
||
```ts
|
||
type DeviceDisplayMode = 'badge' | 'icon_ripple' | 'value' | 'static_icon';
|
||
```
|
||
|
||
`ripple` остаётся только legacy input и нормализуется в `icon_ripple`.
|
||
|
||
`DISPLAY_MODES`:
|
||
|
||
```ts
|
||
export const DISPLAY_MODES = ['badge', 'icon_ripple', 'value', 'static_icon'] as const;
|
||
```
|
||
|
||
Обязательно использовать единый экспортируемый `DeviceDisplayMode` и normalizer вместо повторения union и локальных `_displayOf()` в нескольких файлах. Неизвестное runtime-значение нормализуется в `badge`; `ripple` нормализуется в `icon_ripple`.
|
||
|
||
### 13.2. Persisted marker
|
||
|
||
```yaml
|
||
display: static_icon
|
||
```
|
||
|
||
Поле `display` не переименовывается. Версия общей модели данных не меняется: это расширение уже существующего enum.
|
||
|
||
### 13.3. Backend
|
||
|
||
`MARKER_SCHEMA` принимает:
|
||
|
||
```text
|
||
badge | ripple | icon_ripple | value | static_icon | null
|
||
```
|
||
|
||
Cross-language test обязан подтверждать, что каждое значение из frontend `DISPLAY_MODES` принимается backend-схемой.
|
||
|
||
## 14. Архитектурный план реализации
|
||
|
||
### 14.1. Единая точка поведения
|
||
|
||
Основная логика реализуется в `resolveDevicePresentation()`, а не отдельно в каждом renderer.
|
||
|
||
Предпросмотр продолжает вычислять sources и фактические HA states для объяснения результата. Плановым поверхностям разрешён явный short-circuit source/value resolution для `static_icon`, поскольку этим данным нечего менять в renderer-ready лице. Short-circuit не должен затронуть отдельные агрегаты света/климата/controls, которые вызывают свои resolver независимо от marker presentation.
|
||
|
||
### 14.2. Поверхности-потребители
|
||
|
||
Должны быть проверены:
|
||
|
||
1. интерактивный план в `houseplan-card`;
|
||
2. `houseplan-space-card` через `space-render`;
|
||
3. `hp-device-preview`;
|
||
4. режим устройства в editor и design preview;
|
||
5. kiosk/view mode;
|
||
6. скрытые и HA-disabled ghosts.
|
||
|
||
Ни одна поверхность не должна самостоятельно повторно классифицировать состояние или добавлять live badges после resolver.
|
||
|
||
### 14.3. CSS
|
||
|
||
Renderer должен иметь стабильный hook для статичного режима, например класс `static-icon` или `data-display="static_icon"`, чтобы:
|
||
|
||
- отключить перекраску внутренней подложки от HA state, не изменяя общий hover;
|
||
- сохранить существующие hover, focus и editor selection;
|
||
- не зависеть от порядка классов `on/open/alarm/unavail`;
|
||
- дать одинаковый результат в основном плане, предпросмотре и статической карточке.
|
||
|
||
Не допускается решать задачу только более специфичным CSS поверх динамических классов: semantic projection тоже обязана быть нейтральной, чтобы tooltip, preview explanation и будущие renderers не получали ложное состояние.
|
||
|
||
### 14.4. Activity runtime
|
||
|
||
- `static_icon` никогда не отображает уже активный event window;
|
||
- preview demo останавливается при переключении на `static_icon`;
|
||
- накопленный runtime не должен менять статичный marker;
|
||
- после перехода обратно в `icon_ripple` не следует искусственно запускать activity только из-за смены режима;
|
||
- реальные последующие события после возврата в `icon_ripple` работают обычно.
|
||
|
||
## 15. Локализация и текстовая подсказка
|
||
|
||
Обновить RU/EN ключи:
|
||
|
||
```text
|
||
display.badge
|
||
display.static_icon
|
||
marker.display_hint
|
||
marker.preview.reason.static_icon
|
||
```
|
||
|
||
Рекомендуемая RU-подсказка:
|
||
|
||
> Динамическая подложка показывает работу, открытие, тревоги и недоступность. «Значок + активность» дополнительно показывает события и движение. «Значение вместо иконки» выводит однозначное состояние HA. Статичный значок не меняется от состояний устройства.
|
||
|
||
Рекомендуемая EN-подсказка:
|
||
|
||
> The dynamic plate shows work, open, alarm and unavailable states. Icon + activity also shows events and motion. Value instead of an icon shows one unambiguous HA state. A static icon does not react to device states.
|
||
|
||
Длинный ярлык `display.badge` проверяется в узком native select. Обрезка закрытого системного select допустима только если после открытия ОС показывает полный текст option; горизонтальный scroll или нарушение ширины диалога недопустимы.
|
||
|
||
## 16. Accessibility
|
||
|
||
- Названия режимов должны полностью озвучиваться native select.
|
||
- Контраст нейтральной иконки и подложки соответствует текущему marker contract.
|
||
- `static_icon` не отменяет `focus-visible`.
|
||
- Нельзя передавать состояние только через скрытую подложку: фактический state остаётся доступен в tooltip/more-info и в текстовом предпросмотре.
|
||
- Для тревожных устройств пользователь осознанно отказывается от визуальной тревоги на marker; это должно быть понятно из предпросмотра и подсказки режима.
|
||
- `prefers-reduced-motion` не требует отдельной ветки: в статичном режиме движения нет изначально.
|
||
|
||
## 17. Edge cases
|
||
|
||
### 17.1. Источник света
|
||
|
||
Свет включён, marker имеет `display: static_icon` и `is_light: true`: marker остаётся нейтральным, но Glow и заливка комнаты продолжают работать.
|
||
|
||
### 17.2. Critical alarm среди вторичных сущностей
|
||
|
||
Resolver продолжает находить critical source для диагностики, но лицо marker не становится красным. В предпросмотре current state/details тревога остаётся видна.
|
||
|
||
### 17.3. Нет HA state при загрузке
|
||
|
||
Marker сразу отображается нейтральным, без промежуточного `unavail` fade и без последующего визуального скачка после прихода states.
|
||
|
||
### 17.4. Виртуальное устройство
|
||
|
||
Виртуальный marker использует тот же статичный контракт. Его обычная dashed-рамка как признак типа объекта сохраняется, поскольку это не HA state.
|
||
|
||
### 17.5. Value → static
|
||
|
||
Текстовое значение немедленно заменяется базовой иконкой. Fallback notice value-режима исчезает.
|
||
|
||
### 17.6. Activity → static
|
||
|
||
Текущее кольцо исчезает немедленно. Возврат в activity-режим не создаёт новое событие сам по себе.
|
||
|
||
### 17.7. Автоматическая state icon
|
||
|
||
Открытие cover, lock или door не меняет glyph. При ручной смене icon в форме предпросмотр меняется — это конфигурационное действие пользователя, а не реакция на HA state.
|
||
|
||
### 17.8. Размер и поворот
|
||
|
||
Ручные size/angle применяются как обычно. «Статичный» не означает «не редактируемый».
|
||
|
||
### 17.9. Custom CSS/card-mod
|
||
|
||
Встроенный контракт гарантирует нейтральный вид без пользовательских overrides. Намеренный custom CSS может изменить marker; задача не должна пытаться перебить все внешние `!important`-правила.
|
||
|
||
## 18. Тестовый план для этапа реализации
|
||
|
||
По действующему правилу проекта тесты запускаются перед пре-релизом; ниже перечислен обязательный набор тестов, который должен быть добавлен вместе с реализацией.
|
||
|
||
### 18.1. Unit: presentation resolver
|
||
|
||
Для `static_icon` проверить минимум:
|
||
|
||
1. `on` и `off` дают одинаковую visual projection;
|
||
2. `unknown` и `unavailable` не дают `unavail`;
|
||
3. `alarm` не даёт `alarm`;
|
||
4. presence/event/transition/running не дают activity;
|
||
5. cover state не меняет базовую иконку;
|
||
6. RGB light не задаёт `lightColor`/динамическую окраску;
|
||
7. value/temp/hum/LQI отсутствуют;
|
||
8. size и angle сохраняются;
|
||
9. source facts/signature остаются доступными;
|
||
10. hidden/HA-disabled precedence соблюдается;
|
||
11. explanation reason равен `static_icon` для обычного marker;
|
||
12. переход между display modes не создаёт activity.
|
||
13. live vacuum projection помечается как подавленная, а plan renderer не рисует puck/след в `static_icon`.
|
||
|
||
### 18.2. Backend
|
||
|
||
- `static_icon` принимается `MARKER_SCHEMA`;
|
||
- неизвестное значение отклоняется;
|
||
- cross-language enum test проходит;
|
||
- legacy `ripple` и `null` по-прежнему принимаются.
|
||
|
||
### 18.3. UI/component
|
||
|
||
- в select четыре пункта в заданном порядке;
|
||
- `badge` выбран по умолчанию;
|
||
- новое название `badge` локализовано RU/EN;
|
||
- `static_icon` последним в RU/EN;
|
||
- activity settings скрыты для `static_icon`;
|
||
- preview сразу становится нейтральным;
|
||
- activity demo отсутствует;
|
||
- hover работает так же, как у остальных marker;
|
||
- focus-visible и editor selection остаются видимыми;
|
||
- сохранение/повторное открытие сохраняет `static_icon`.
|
||
- alarm-capable binding получает неблокирующее предупреждение;
|
||
- tap по `unavailable` binding в `static_icon` показывает видимую ошибку service call, а не молчит;
|
||
- длинный RU/EN ярлык не создаёт горизонтальный scroll на узком экране.
|
||
|
||
### 18.4. Поверхностный parity test
|
||
|
||
Один и тот же draft/config marker при одинаковых входных данных имеет одинаковые icon/classes/badges в:
|
||
|
||
- основном плане;
|
||
- `hp-device-preview`;
|
||
- `houseplan-space-card`.
|
||
|
||
Parity-набор включает отдельную vacuum-фикстуру: base marker статичен, а puck/след отсутствуют. Минимальный browser smoke проверяет alarm-устройство в `static_icon` (нет `alarm`, `unavail`, `activity-*`), мгновенное переключение режима туда и обратно, preview parity и отсутствие vacuum overlay.
|
||
|
||
## 19. Документация реализации
|
||
|
||
В той же локальной серии изменений обновляются:
|
||
|
||
- `docs/CHANGELOG.md` и `docs/CHANGELOG.ru.md` отдельной user-visible записью;
|
||
- `docs/USER-GUIDE.ru.md` — четыре режима и их матрица;
|
||
- `docs/ARCHITECTURE.md` и `docs/STATUS.md` — enum и единая static projection;
|
||
- `docs/FILTERING.md` — исключение из общей state-матрицы;
|
||
- `docs/VACUUM.md` — подавление puck/следа;
|
||
- `docs/TESTING.md` и `docs/TESTING-DEMO.md` — unit/backend/browser/manual сценарии;
|
||
- существующие скриншоты редактора с прежним списком режимов, если такие актуальные скриншоты обнаружены.
|
||
|
||
## 20. Критерии приёмки
|
||
|
||
1. В списке «Отображение» четыре режима, `static_icon` расположен последним.
|
||
2. Текущий «Значок» называется «Значок + динамическая подложка».
|
||
3. Новые и старые устройства остаются в динамическом `badge` по умолчанию.
|
||
4. Устройство в `static_icon` выглядит одинаково при `on`, `off`, working, open, alarm, unknown и unavailable.
|
||
5. Статичный marker не меняет иконку по state, не получает activity, RGB, value, temperature, humidity или LQI.
|
||
6. Размер, угол и базовая иконка применяются.
|
||
7. Световое и управляющее поведение устройства не меняется.
|
||
8. Скрытые, удалённые и HA-disabled устройства не возвращаются на план из-за `static_icon`.
|
||
9. Hover, focus и selection работают так же, как у остальных marker, и не изменяются этой задачей.
|
||
10. Предпросмотр точно объясняет статичный результат, сохраняя фактический HA state в текстовых фактах.
|
||
11. Backend принимает новый enum, существующие конфигурации не мигрируют и не ломаются.
|
||
12. Все три renderer-поверхности используют единый resolver и показывают одинаковый результат.
|
||
13. Живой пылесос в `static_icon` не показывает puck, след или room-highlight, но сохранённая история не удаляется.
|
||
14. Ошибка действия по недоступной сущности остаётся видимой пользователю.
|
||
15. Alarm-capable binding получает честное неблокирующее предупреждение до Save.
|
||
|
||
## 21. Подтверждённые продуктовые решения
|
||
|
||
Владелец продукта подтвердил 2026-08-08:
|
||
|
||
1. Статичность касается только внешнего вида marker. Устройство продолжает влиять на Glow, заливку «Свет» и controls согласно своим отдельным настройкам и фактическому состоянию.
|
||
2. У статичного marker полностью скрываются живые satellite badges температуры, влажности и LQI.
|
||
3. Hover не изменяется этой задачей и сохраняет текущее общее поведение marker, включая существующую accent-подсветку. Статичность относится к HA state и данным устройства, а не к интерактивной обратной связи UI.
|
||
|
||
Тревоги, `unknown`/`unavailable`, state icon morph и RGB-цвет также безусловно подавляются, поскольку статичный marker должен иметь одинаковый вид при любых состояниях устройства.
|