Files
ayurishchevandClaude Opus 5.5 7d998066f5 Задача 039: статус устройства и сведения об устройстве в списке адресов
Статус устройства (Активен / Выключен / На обслуживании), назначается вручную на экране
устройств: колонка «Статус», выбор в диалоге, смена — в журнал. Миграция 0016,
существующие устройства — «Активен». В списке адресов префикса колонки «Тип устройства»,
«Устройство», «Статус устройства» (join без N+1). pytest не прогнан: учётная запись admin
из .env отключена на стенде.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 18:18:33 +03:00

5.9 KiB
Raw Permalink Blame History

Статус устройства и сведения об устройстве в списке адресов префикса (изменение 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.