Задача 039: статус устройства и сведения об устройстве в списке адресов
Статус устройства (Активен / Выключен / На обслуживании), назначается вручную на экране устройств: колонка «Статус», выбор в диалоге, смена — в журнал. Миграция 0016, существующие устройства — «Активен». В списке адресов префикса колонки «Тип устройства», «Устройство», «Статус устройства» (join без N+1). pytest не прогнан: учётная запись admin из .env отключена на стенде. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
aeb89dbded
commit
7d998066f5
10 files changed
+199
-19
No files matched your search
@@ -0,0 +1,63 @@
|
||||
# Статус устройства и сведения об устройстве в списке адресов префикса (изменение 039)
|
||||
|
||||
## Context
|
||||
Сейчас в списке адресов префикса (`screens.address`) не видно, к какому устройству привязан адрес, — только в диалоге правки.
|
||||
У устройства нет эксплуатационного статуса. Нужно:
|
||||
1. Ввести **статус устройства** — «Активен», «Выключен», «На обслуживании». Статус назначается вручную на экране устройств:
|
||||
в диалоге создания и правки, в таблице устройств — новая колонка «Статус».
|
||||
2. В списке адресов префикса — три новые колонки: **тип устройства**, **имя устройства**, **статус устройства**
|
||||
(пусто или «—», если адрес не привязан к устройству).
|
||||
|
||||
## Модель и миграция `0016_device_status.py`
|
||||
- `app/models.py`: `class DeviceStatus(str, enum.Enum): active, off, maintenance`.
|
||||
`Device.status: Mapped[DeviceStatus]` — `Enum(DeviceStatus, name="device_status")`, `default=active`, `server_default='active'`, NOT NULL.
|
||||
- Миграция: создать тип `device_status`, добавить колонку с `server_default 'active'` — существующие устройства станут «Активен».
|
||||
`downgrade`: удалить колонку и тип.
|
||||
|
||||
## API
|
||||
- `app/schemas.py`:
|
||||
- `DeviceIn.status: DeviceStatus = DeviceStatus.active`;
|
||||
- `DeviceUpdate.status: DeviceStatus | None = None`;
|
||||
- `DeviceOut.status`;
|
||||
- `AddressOut`: `device_type_name: str | None`, `device_status: str | None`.
|
||||
- `app/api/v1/refs.py`: создание и правка устройства принимают `status`. Смена статуса попадает в журнал через существующий `apply_update`
|
||||
(`device.updated` с `diff`); `_device_outs` отдаёт `status`.
|
||||
- `app/api/v1/prefixes.py::list_addresses`:
|
||||
- запрос `select(Address, Device.name)` расширить: `Device.status` и `DeviceType.name` через `outerjoin(DeviceType, …)`;
|
||||
- `_addr_out(a, device_name, device_type_name, device_status)` — обновить все вызовы;
|
||||
- остальные эндпоинты, возвращающие `AddressOut` (создание, правка, автоназначение), отдают поля так же — через общий хелпер
|
||||
или отдельный запрос по `device_id`, без N+1 в списке.
|
||||
- Фильтр и поиск по статусу устройства не требуются.
|
||||
|
||||
## UI — `web/app.js`
|
||||
- Справочник `DEVICE_STATUS = {active: ["green","Активен"], off: ["", "Выключен"], maintenance: ["amber","На обслуживании"]}` —
|
||||
цвет бейджа и подпись, по образцу `ADDR_STATUS`.
|
||||
- **Экран устройств** (`screens.devices`):
|
||||
- колонка «Статус» с бейджем (после «Тип»), расширить `selCols` и заголовок;
|
||||
- в `deviceDialog` — `fSelect("status", "Статус", …)`, по умолчанию «Активен», значение уходит в `POST`/`PATCH`.
|
||||
- **Список адресов** (`screens.address`): после «Описание» колонки «Тип устройства», «Устройство», «Статус устройства».
|
||||
- имя устройства ссылкой не делаем — строка и так кликабельна; у свободных и непривязанных адресов — «—»;
|
||||
- статус — тем же бейджем;
|
||||
- ширины подобрать так, чтобы таблица не переполнялась: «Описание» может стать уже; «Изменено» оставить.
|
||||
- Цвета — только через существующие классы бейджей и токены тёмной темы (изменение 038), без литералов.
|
||||
|
||||
## Тесты (минимально)
|
||||
Одна проверка в существующем тесте `tests/test_api.py`, например в `test_in_use_objects_cannot_be_deleted` или рядом, без нового файла:
|
||||
- создать устройство со `status="maintenance"`, привязать к нему адрес;
|
||||
- `GET /prefixes/{id}/addresses` → у адреса `device_name`, `device_type_name`, `device_status == "maintenance"`;
|
||||
- `PATCH /devices/{id} {"status": "off"}` → 200, `status == "off"`.
|
||||
|
||||
## Документация
|
||||
- `README.md`: модель данных — статус устройства; «Интерфейс» — колонки; миграции `0001`–`0016`; строка 039 в истории.
|
||||
- `SUMMARY.md` — по завершении (моя часть).
|
||||
|
||||
## Исполнение
|
||||
По принятой схеме: код, миграцию, UI и тест пишет агент на Sonnet, он же пересобирает стенд с `--force-recreate`; тесты он не запускает.
|
||||
Моя часть — ревью, `pytest`, проверка миграции и API. UI проверяет пользователь.
|
||||
|
||||
## Проверка
|
||||
- `alembic current` = `0016`, `alembic check` чисто; откат до 0015 и повторный upgrade.
|
||||
- Существующие устройства после миграции — `active`.
|
||||
- `pytest -q` — все зелёные.
|
||||
- API: статус меняется и пишется в журнал (`device.updated`, `diff.status`); адреса отдают три новых поля;
|
||||
у свободных и непривязанных адресов — `null`.
|
||||
@@ -0,0 +1,26 @@
|
||||
# Итог: статус устройства и сведения об устройстве в списке адресов (изменение 039)
|
||||
|
||||
План: `PLAN.md`. У устройства появился статус «Активен» / «Выключен» / «На обслуживании», назначаемый вручную на экране устройств.
|
||||
В списке адресов префикса — колонки «Тип устройства», «Устройство», «Статус устройства».
|
||||
|
||||
## Что сделано
|
||||
| Файл | Изменение |
|
||||
|---|---|
|
||||
| `app/models.py`, `alembic/versions/0016_device_status.py` | `DeviceStatus` (`active`/`off`/`maintenance`), `devices.status` NOT NULL, `server_default 'active'` — существующие устройства стали «Активен» |
|
||||
| `app/schemas.py` | `DeviceIn.status` (по умолчанию `active`), `DeviceUpdate.status`, `DeviceOut.status`; `AddressOut.device_type_name`, `device_status` |
|
||||
| `app/api/v1/refs.py` | `status` в ответах об устройствах; смена статуса — в журнал через `apply_update` (`device.updated`, `diff.status`) |
|
||||
| `app/api/v1/prefixes.py` | `list_addresses`: имя, тип и статус устройства одним `outerjoin` на страницу; одиночные ответы (создание/правка/автоназначение адреса) — хелпер `_device_info`, один запрос, раньше `device_name` там не отдавался |
|
||||
| `web/app.js` | `DEVICE_STATUS` (бейджи green / нейтральный / amber); «Устройства»: колонка «Статус», выбор статуса в диалоге; «Адреса»: три колонки, «—» у свободных и непривязанных адресов |
|
||||
| `tests/test_api.py` | `test_device_status_on_address`: устройство `maintenance` → поля в списке адресов; `PATCH status=off` |
|
||||
| `README.md` | Модель данных (устройства), «Интерфейс», миграции `0001`–`0016`, строка 039 |
|
||||
|
||||
## Проверки
|
||||
- Миграция 0016 применена, `alembic check` чисто, откат до 0015 и повторный upgrade — без ошибок; 3 существующих устройства — `active`.
|
||||
- Статус в API — строка (`"maintenance"`), не представление enum (проверено сериализацией `AddressOut`).
|
||||
- `node --check`, `py_compile`, `import app.main` — чисто; стенд пересобран (`--force-recreate`), healthy, отдаёт новый `app.js`.
|
||||
- Новых литеральных цветов в `app.js` нет (бейджи — существующие классы, тёмная тема не затронута).
|
||||
|
||||
## Не проверено
|
||||
- **`pytest` не прогнан**, в том числе новый `test_device_status_on_address`: учётная запись `admin` из `.env` (фикстура `client`)
|
||||
отключена пользователем `tstark` через UI (13:58). Решение о её включении или других учётных данных для тестов — за пользователем.
|
||||
- UI — ручная проверка пользователя.
|
||||
Reference in new issue
Block a user