501 lines
35 KiB
Markdown
501 lines
35 KiB
Markdown
# Dashboard Service - Full Chat Context For Next Agent
|
||
|
||
Updated: 2026-04-16
|
||
Owner: naeel
|
||
|
||
## 1. Что это за сервис
|
||
|
||
Cloud Dashboard - отдельный веб-сервис (backend + frontend), который показывает инстансы облака, фильтрацию, детали, историю операций и граф зависимостей.
|
||
|
||
Текущая реализация:
|
||
- Backend: Python + FastAPI
|
||
- Frontend: статический SPA (HTML/CSS/vanilla JS)
|
||
- Граф: Cytoscape
|
||
- Runtime: контейнер в Kubernetes
|
||
|
||
## 2. Бизнес-цель
|
||
|
||
Сделать рабочий дашборд для повседневной эксплуатации:
|
||
- быстрый вход по API token
|
||
- фильтрация по статусам
|
||
- понятная таблица и карточки статистики
|
||
- просмотр параметров/зависимостей инстанса
|
||
- визуализация зависимостей
|
||
- стабильная работа в PROD
|
||
|
||
## 3. Ключевые сделанные фичи
|
||
|
||
### 3.1 Аутентификация и сессия
|
||
- Логин по API token.
|
||
- Токен сохраняется в localStorage.
|
||
- Logout очищает токен.
|
||
|
||
### 3.2 Выбор стенда (ВАЖНО)
|
||
Сделано переключение окружений на экране логина:
|
||
- PROD -> https://deck-api.ngcloud.ru/api/v1
|
||
- DEV -> https://deck-api-dev.ngcloud.ru/api/v1
|
||
- TEST -> https://deck-api-test.ngcloud.ru/api/v1
|
||
|
||
Как работает:
|
||
- выбранный стенд сохраняется в localStorage как deck_env
|
||
- frontend отправляет в backend заголовок X-Deck-Env
|
||
- backend выбирает base URL по whitelist
|
||
- если значение некорректное, fallback на test
|
||
|
||
### 3.3 Таблица и UX
|
||
- Фильтры статусов с чекбоксами (увеличены).
|
||
- Sticky header и правильный скролл области таблицы.
|
||
- Сортировки по колонкам.
|
||
- Статистика по статусам.
|
||
- Detail row с вкладками: параметры, история, зависимости, граф.
|
||
|
||
### 3.4 Зависимости и графы
|
||
Добавлены два режима:
|
||
- граф для конкретного инстанса
|
||
- общий граф для running
|
||
|
||
Оптимизации:
|
||
- lazy-load графа (не считать сразу)
|
||
- кэш графа на backend с TTL
|
||
- клиентская подвыборка subgraph
|
||
- индикаторы загрузки
|
||
- open large graph in modal/fullscreen behavior при большом числе узлов
|
||
|
||
UI графа:
|
||
- прямоугольные узлы
|
||
- более крупный и читаемый текст
|
||
- улучшенные стрелки/контраст
|
||
- упрощенный layout (grid-подход)
|
||
|
||
### 3.5 Визуал и брендинг
|
||
- day/night переключатель темы с сохранением в localStorage
|
||
- favicon/logo из docs assets
|
||
- удалены лишние декоративные элементы
|
||
|
||
## 4. Техническая архитектура
|
||
|
||
## Browser
|
||
- SPA рендерит UI
|
||
- вызывает backend по префиксу /dashboard/api
|
||
- хранит deck_token и deck_env в localStorage
|
||
|
||
## Backend (FastAPI)
|
||
Главные маршруты:
|
||
- GET /api/instances
|
||
- GET /api/instances/{uid}
|
||
- GET /api/graph
|
||
|
||
Транспорт:
|
||
- принимает X-Deck-Token
|
||
- принимает X-Deck-Env
|
||
- проксирует запросы в Deck API выбранного окружения
|
||
|
||
Граф:
|
||
- собирается из списка инстансов и деталей
|
||
- edges из dependencies/dependentInstances
|
||
- кэш in-memory по ключу token+env+statuses
|
||
|
||
## Kubernetes
|
||
- deployment/service/ingress в namespace terra
|
||
- публичный доступ через /dashboard
|
||
|
||
## 5. Эксплуатационные детали
|
||
|
||
- Сервис не использует БД.
|
||
- Основная интеграция backend - только с Deck API.
|
||
- Узкое место в производительности обычно внешний API, не сам UI.
|
||
- В проекте уже обсужден путь: сначала стабилизировать логику на Python, потом при необходимости переписать backend на Go с сохранением API контрактов.
|
||
|
||
## 6. История решений (сжатая)
|
||
|
||
1) Сначала починили критичные JS ошибки и нестабильный логин.
|
||
2) Исправили фильтры статусов и прокинули корректный parsing на backend.
|
||
3) Переделали скролл + sticky элементы.
|
||
4) Добавили графы зависимостей, затем несколько итераций UX/производительности.
|
||
5) Сделали lazy загрузку и кэш.
|
||
6) Подчистили визуал (читаемость, стрелки, тема, favicon/logo).
|
||
7) Реализовали выбор стенда PROD/DEV/TEST на логине с end-to-end маршрутизацией.
|
||
8) Вынесли сервис в новую репу-папку dashboard и добавили правила агента + gitignore.
|
||
|
||
## 7. Что уже перенесено в новую репу dashboard
|
||
|
||
Из старого пути cloud-dashboard в новый dashboard перенесены:
|
||
- Dockerfile
|
||
- main.py
|
||
- requirements.txt
|
||
- static/
|
||
- k8s/
|
||
|
||
Дополнительно создано:
|
||
- .github/copilot-instructions.md (скопированы правила агента)
|
||
- .gitignore (Python/кэши/локальные артефакты)
|
||
|
||
## 8. Что важно для нового агента
|
||
|
||
1) Не ломать контракт frontend/backend без явного запроса.
|
||
2) Заголовки X-Deck-Token и X-Deck-Env обязательны.
|
||
3) Поддерживать 3 стенда через whitelist.
|
||
4) Не тащить секреты/токены в git.
|
||
5) Для графа сохранять lazy-load и кэш (иначе будет тяжелая загрузка).
|
||
|
||
## 9. Рекомендованный план ближайших шагов
|
||
|
||
1) Сделать первичный commit в новой репе dashboard.
|
||
2) Настроить CI:
|
||
- lint
|
||
- build image
|
||
- push image
|
||
- deploy (опционально)
|
||
3) Добавить smoke tests:
|
||
- /api/instances с разными env
|
||
- /api/graph с фильтрами
|
||
4) Подготовить migration checklist для возможного будущего Go backend.
|
||
|
||
## 10. Definition of Done (текущее состояние)
|
||
|
||
Сервис:
|
||
- работает в k8s
|
||
- логин и фильтры стабильны
|
||
- графы и тема работают
|
||
- выбор стенда реализован и сохраняется
|
||
- код перенесен в новую папку/repo baseline
|
||
|
||
|
||
## 11. Текущие задачи (v9.7 — в работе)
|
||
|
||
Все 4 задачи согласованы с оператором. Реализовывать в таком порядке:
|
||
|
||
### Задача 1 — Стриминговая загрузка инстансов
|
||
- Backend `/api/instances/stream` уже есть (NDJSON, main.py строка ~297)
|
||
- Фронт **ещё использует старый** `/api/instances` (index.html строка ~1004)
|
||
- Нужно: переключить фронт на `/api/instances/stream`, строки добавлять в таблицу по одной по мере прихода
|
||
- Все загруженные инстансы держать в памяти (`allInstances`). К API обращаться ТОЛЬКО по кнопке "Обновить"
|
||
|
||
### Задача 2 — Метка "Актуально на ЧЧ:ММ:СС"
|
||
- Разместить **слева от кнопки "Обновить"**
|
||
- Показывать время завершения последней загрузки
|
||
- Обновлять при каждом refresh
|
||
|
||
### Задача 3 — Фильтрация зависимостей по чекбоксам
|
||
- В блоке "Зависимости" инстанса показывать ТОЛЬКО те инстансы, статус которых выбран чекбоксами (running/suspended/etc)
|
||
- При изменении чекбокса — сразу перерисовывать список зависимостей (без обращения к API, из памяти)
|
||
|
||
### Задача 4 — Переход по клику + кнопка "Назад"
|
||
- Клик на инстанс в блоке "Зависимости" → открыть его строку/детали в таблице
|
||
- Добавить кнопку "Назад" для возврата к исходному инстансу
|
||
|
||
### Правила разработки (напоминание):
|
||
- ЧАСТО коммитить: `git add -A && git commit` на ВМ в `~/terra/dashboard`
|
||
- Всё через SSH: `ssh -i ~/.ssh/naeel_vm_id_ed25519 -o StrictHostKeyChecking=no naeel@5.172.178.213`
|
||
- Не ломать существующий рабочий код
|
||
- Новая логика = новые функции в конце файла
|
||
|
||
---
|
||
|
||
## 12. Операционная дисциплина (КРИТИЧЕСКОЕ)
|
||
|
||
Для нового агента это обязательное правило:
|
||
- Все команды по проекту выполнять ТОЛЬКО через SSH на ВМ.
|
||
|
||
SSH-шаблон:
|
||
ssh -i ~/.ssh/naeel_vm_id_ed25519 -o StrictHostKeyChecking=no -o ConnectTimeout=10 naeel@5.172.178.213 КОМАНДА
|
||
|
||
Локально ЗАПРЕЩЕНО выполнять:
|
||
- git-команды проекта
|
||
- docker-команды
|
||
- kubectl-команды
|
||
- curl к API проекта
|
||
- bash/python/go/тесты проекта
|
||
|
||
Почему:
|
||
- так исключаются конфликты сред и ложные результаты;
|
||
- единая точка выполнения (ВМ) дает предсказуемость и воспроизводимость.
|
||
|
||
---
|
||
|
||
## 13. Дисциплина загрузки таблицы (актуально)
|
||
|
||
Обязательная модель работы таблицы:
|
||
- В начале загрузки читаем данные инстансов и их параметры только из API.
|
||
- Строка таблицы появляется сразу после чтения параметров конкретного инстанса.
|
||
- Параллельные обращения к внешнему API запрещены: только последовательная обработка.
|
||
- После завершения загрузки повторных обращений к API нет.
|
||
- Новые обращения к API выполняются только по кнопке Обновить.
|
||
|
||
Требования к UX загрузки:
|
||
- В верхней строке перед кнопкой Обновить показывать прогресс в формате Загрузка X/Y.
|
||
- После завершения загрузки показывать Актуально на ЧЧ:ММ:СС.
|
||
- Рядом с меткой актуальности показывать время загрузки последнего обновления.
|
||
|
||
Требования к таблице (операторский режим):
|
||
- После чтения параметров конкретного инстанса из API сразу добавлять его строку в таблицу.
|
||
- Добавить узкий столбец удаляемости сразу после статуса.
|
||
- Зеленый индикатор показывать только если инстанс в suspended и прошло 14+ дней с входа в suspended (по данным API).
|
||
- В раскрытой строке suspended-инстанса показывать пояснение по удаляемости.
|
||
- Блоки Input/Output параметров не растягивать на всю ширину; сделать компактный читаемый layout.
|
||
- Порог удаляемости, паттерны операций и пользовательские тексты хранить в конфиге фронта (без хардкода в вычислениях).
|
||
|
||
## 14. Журнал решений и хронология (без скрытых рассуждений)
|
||
|
||
### Шаг A — Режим загрузки таблицы
|
||
- Цель: сделать поведение предсказуемым для оператора и убрать лишние запросы.
|
||
- Входные ограничения: читать данные только из API; после загрузки работать из памяти; новые запросы только по Обновить.
|
||
- Варианты:
|
||
- A1: догружать детали по клику строки.
|
||
- A2: читать детали сразу в стриме и больше не дергать API.
|
||
- Выбранный вариант: A2.
|
||
- Причина выбора: минимальная фрагментация данных, прозрачный UX, отсутствие неожиданной сетевой активности.
|
||
- Проверка: поток отдает progress и done-событие; во фронте удалена догрузка деталей по клику.
|
||
|
||
### Шаг B — Последовательные вызовы API
|
||
- Цель: исключить параллельные обращения к API.
|
||
- Входные ограничения: запрет на параллельные запросы.
|
||
- Варианты:
|
||
- B1: batch-параллелизм с ограничением concurrency.
|
||
- B2: строго последовательный обход uid.
|
||
- Выбранный вариант: B2.
|
||
- Причина выбора: полное соответствие ограничению и упрощение отладки.
|
||
- Проверка: убраны gather/create_task/Semaphore для стрим-логики.
|
||
|
||
### Шаг C — Удаляемость suspended > 14 дней
|
||
- Цель: добавить операторский индикатор удаления без лишней визуальной нагрузки.
|
||
- Входные ограничения: считать только по API-данным.
|
||
- Варианты:
|
||
- C1: считать от dtState всегда.
|
||
- C2: сначала искать suspend-операции, затем fallback на поля detail.
|
||
- Выбранный вариант: C2.
|
||
- Причина выбора: меньше ложных срабатываний при изменениях, не связанных с suspend.
|
||
- Проверка: индикатор и пояснение показываются только для suspended; порог 14+ дней.
|
||
|
||
### Шаг D — Немонолитная, но умеренная структура
|
||
- Цель: не превращать файл в монолит и одновременно не перегрузить архитектуру.
|
||
- Входные ограничения: без чрезмерного рефакторинга.
|
||
- Варианты:
|
||
- D1: полный вынос JS в модули/файлы.
|
||
- D2: локальная модульность внутри файла через конфиг и мелкие функции.
|
||
- Выбранный вариант: D2.
|
||
- Причина выбора: безопасно для текущей стадии, быстро настраивается, меньше риск поломок.
|
||
- Реализация:
|
||
- Конфиг политики/текстов вынесен в DASHBOARD_CFG.
|
||
- Общие шаблоны строк через fmtText.
|
||
- Рендер таблицы разделен на renderDataRow и renderDetailRow.
|
||
- Константа TABLE_COLSPAN и состояние TABLE_STATE исключают магические значения.
|
||
|
||
### Шаг E — Backend как источник вычисляемых метаданных
|
||
- Цель: убрать дублирующую бизнес-логику из фронта и сделать поведение единообразным.
|
||
- Входные ограничения: без избыточного рефакторинга, только практичный шаг.
|
||
- Варианты:
|
||
- E1: оставить расчеты удаляемости только во фронте.
|
||
- E2: считать удаляемость на backend и отдавать в stream-строке как мета-поля.
|
||
- Выбранный вариант: E2.
|
||
- Причина выбора: policy централизована на сервере, фронт становится проще и легче переконфигурируется.
|
||
- Реализация:
|
||
- В backend добавлен конфиг DELETE_POLICY и функции вычисления suspend-возраста.
|
||
- В stream добавлено поле _meta.deleteCandidate.
|
||
- Фронт сначала применяет backend _meta; клиентский fallback использовался временно и отключен на шаге G.
|
||
|
||
### Шаг F — Локальный snapshot таблицы в браузере
|
||
- Цель: после перезагрузки страницы не обращаться к API до явного нажатия Обновить.
|
||
- Входные ограничения: решение должно быть легким и не монолитным.
|
||
- Варианты:
|
||
- F1: только RAM (теряется при reload).
|
||
- F2: локальный snapshot per user+env в browser storage.
|
||
- Выбранный вариант: F2.
|
||
- Причина выбора: быстрый старт UI после reload и автономная работа без нового API-вызова.
|
||
- Реализация:
|
||
- Добавлен snapshot storage key на основе user+env.
|
||
- После успешного полного refresh snapshot сохраняется.
|
||
- На init сначала пробуется восстановление snapshot; API вызывается только если snapshot отсутствует.
|
||
- На logout snapshot очищается.
|
||
|
||
### Шаг G — Backend-only deleteability + snapshot schema v2
|
||
- Цель: исключить расхождение бизнес-правил между клиентом и сервером и безопасно версионировать локальный кэш.
|
||
- Входные ограничения: без тяжелого рефакторинга.
|
||
- Реализация:
|
||
- Клиентский fallback вычисления удаляемости отключен в stream-обработке.
|
||
- Поля `_canDelete`/`_suspendDays` инициализируются из backend `_meta.deleteCandidate` (или остаются нулевыми по умолчанию).
|
||
- Формат snapshot переведен на `version=2` и `schema=instance-stream-v2`.
|
||
- Ключ snapshot обновлен до `dashboard_snapshot_v2`, чтобы отделить новый формат от старого.
|
||
|
||
### Шаг H — Релиз v9.22 (build/push/deploy + верификация)
|
||
- Цель: доставить изменения шага G в кластер и подтвердить фактическую версию рантайма.
|
||
- Реализация:
|
||
- Собран образ `naeel/cloud-dashboard:v9.22`.
|
||
- Выполнен push в Docker Hub.
|
||
- Применен `k8s/deployment.yaml` в namespace `terra`.
|
||
- Rollout завершен успешно.
|
||
- Проверено соответствие версии в deployment и pod.
|
||
- Проверка:
|
||
- `spec.image`: `naeel/cloud-dashboard:v9.22`.
|
||
- `pod.image`: `naeel/cloud-dashboard:v9.22`.
|
||
- `pod.imageID`: `docker.io/naeel/cloud-dashboard@sha256:18e87ff592a333cc280fd2af13390f47b111616b8da31f2e32d7ac24e3a3a7ea`.
|
||
- `pod` статус: `Running`, `Ready=true`, `Restarts=0`.
|
||
- Внутренний smoke-check: `GET http://127.0.0.1:8080/` -> `HTTP 200`.
|
||
- Внешний smoke-check (ingress `terra.k8c.ru`): `HTTPS /` -> `200`, `HTTP /` -> `308`.
|
||
|
||
### Шаг I — Добавлен столбец UUID после Имени (v9.29)
|
||
- Цель: сделать идентификацию инстанса в таблице мгновенной без раскрытия строки.
|
||
- Реализация:
|
||
- В таблицу добавлен новый sortable-столбец `UUID` сразу после `Имя`.
|
||
- В рендере строк добавлена ячейка `instanceUid` (моноширинный стиль).
|
||
- `TABLE_COLSPAN` увеличен с `8` до `9`.
|
||
- Обновлены мобильные индексы скрываемых колонок (`nth-child`) после сдвига структуры.
|
||
- Выполнен version bump: .naeel/cloud-dashboard:v9.29`.
|
||
|
||
### Шаг J — Фикс `renderDataRow is not defined` (v9.30)
|
||
- Цель: убрать runtime-ошибку в таблице после добавления UUID-колонки.
|
||
- Реализация:
|
||
- `renderDataRow` и `renderDetailRow` вынесены из `toggle()` в общий scope.
|
||
- Рендер таблицы (`render`) снова вызывает доступные функции без `ReferenceError`.
|
||
- Выполнен version bump: .naeel/cloud-dashboard:v9.30`.
|
||
|
||
### Шаг K — Перенос светофора в колонку Изменён (v9.31)
|
||
- Цель: убрать отдельный столбец индикатора и показывать только полезный сигнал.
|
||
- Реализация:
|
||
- Удален отдельный столбец светофора из таблицы.
|
||
- Зеленая точка теперь рисуется после времени в колонке `Изменён` только для eligible (`suspended` > 14 дней, по backend-метаданным).
|
||
- Серые точки полностью убраны.
|
||
- `TABLE_COLSPAN` обновлен с 9 до 8.
|
||
- Обновлены мобильные индексы скрываемых колонок.
|
||
- Выполнен version bump: .naeel/cloud-dashboard:v9.31`.
|
||
|
||
### Шаг L — Возврат потокового вывода строк (v9.32)
|
||
- Цель: показывать строки таблицы по мере загрузки stream, без ожидания `_done`.
|
||
- Реализация:
|
||
- Исправлен `scheduleRender()`: вместо perpetual-debounce применяется throttle (если таймер уже запущен, новый не ставится).
|
||
- UI теперь обновляется регулярно в ходе потока, а не откладывается до конца непрерывного чтения.
|
||
- Выполнен version bump: .naeel/cloud-dashboard:v9.32`.
|
||
|
||
### Шаг M — Левое выравнивание 4 колонок в Параметрах (v9.33)
|
||
- Цель: сделать `Input/Output` читабельным в табличном стиле без центрирования.
|
||
- Реализация:
|
||
- `params-grid` переведен на `max-content` колонки и выравнивание влево.
|
||
- `p-item` переведен на grid из 2 колонок (`key` + `value`) с увеличенным фиксированным зазором между ними.
|
||
- `p-key` и `p-val` выровнены влево.
|
||
- Ширина колонок определяется содержимым; при реальном переполнении включается перенос (`overflow-wrap: anywhere`).
|
||
- Выполнен version bump: .naeel/cloud-dashboard:v9.33`.
|
||
|
||
### Шаг N — Ширина колонки имен: max + 10ch (v9.34)
|
||
- Цель: сделать значения читаемыми по единой вертикали и увеличить отступ от имен.
|
||
- Реализация:
|
||
- Для каждой секции (`Input`/`Output`) вычисляется максимальная длина имени параметра.
|
||
- Ширина колонки имен задается формулой: `maxKeyLen * 1ch + 10ch`.
|
||
- Значения начинаются строго от единой левой границы value-колонки в каждой секции.
|
||
- Выполнен version bump: .naeel/cloud-dashboard:v9.34`.
|
||
|
||
### Шаг O — Output +20 и copy-иконка параметров (v9.35)
|
||
- Цель: повысить читаемость `Input/Output` и ускорить копирование значений.
|
||
- Реализация:
|
||
- Увеличен межсекционный отступ между `Input` и `Output` на +20.
|
||
- Каждая строка параметров переведена в 3 зоны: `key | value | copy`.
|
||
- Иконка копирования фиксирована в конце строки (правая зона), со вспышкой `✓` после успешного копирования.
|
||
- Добавлена функция `copyParamValue` с Clipboard API и fallback через `execCommand`.
|
||
- Выполнен version bump: .naeel/cloud-dashboard:v9.35`.
|
||
|
||
### Шаг P — Скрытие copy для пустых + фикс дневного режима (v9.36)
|
||
- Цель: убрать визуальный шум и исправить неполное переключение в light theme.
|
||
- Реализация:
|
||
- `renderCopyBtnHtml` не рисует кнопку копирования для пустых значений и `—`.
|
||
- Добавлены `body.light` стили для `.stat-card` и `.stat-card .lbl`, чтобы карточки статистики реально становились светлыми.
|
||
- Выполнен version bump: .naeel/cloud-dashboard:v9.36`.
|
||
|
||
### Шаг Q — Light-theme для status-badge (v9.37)
|
||
- Цель: убрать темные/кислотные бейджи статусов в дневном режиме.
|
||
- Реализация:
|
||
- Добавлены `body.light` переопределения для `.s-running`, `.s-suspended`, `.s-deleting`, `.s-deleted`, `.s-pending`, `.s-creating`, `.s-default`.
|
||
- Для светлой темы введены мягкие светлые фоны и контрастный текст, плюс тонкая рамка бейджа.
|
||
- Выполнен version bump: .naeel/cloud-dashboard:v9.37`.
|
||
|
||
### Шаг R — Контрастный фон блока деталей/параметров (v9.38)
|
||
- Цель: убрать визуальное слияние раскрытой области деталей с основной таблицей.
|
||
- Реализация:
|
||
- Усилен контейнер `.detail-box`: отдельный фон, рамка, скругление, внутренний отступ от таблицы.
|
||
- Добавлен фон для `.detail-row td` и контрастная подложка вкладок `.tabs`.
|
||
- Увеличен контраст панелей `.panel-params`, `.panel-history`, `.panel-deps` в dark/light режимах.
|
||
- Выполнен version bump: .naeel/cloud-dashboard:v9.38`.
|
||
|
||
### Шаг S — Полосатые строки (zebra) для читаемости (v9.39)
|
||
- Цель: улучшить восприятие строк, чтобы данные не сливались по горизонтали.
|
||
- Реализация:
|
||
- Добавлена мягкая zebra-разметка в основной таблице (`tbody tr.data-row`) с разным тоном соседних строк.
|
||
- Добавлена zebra-разметка в таблице истории (`.hist-table tbody tr`).
|
||
- Добавлена лёгкая zebra-подложка для строк параметров (`.p-item`).
|
||
- Отдельно настроены оттенки для `dark` и `light` темы.
|
||
- Выполнен version bump: .naeel/cloud-dashboard:v9.39`.
|
||
|
||
### Шаг T — Полная деактивация графа + явная зебра основной таблицы (v9.40)
|
||
- Цель: полностью убрать интеракции графа и сделать полосатость в основной таблице заметной.
|
||
- Реализация:
|
||
- Из header удалена кнопка `Граф зависимостей`.
|
||
- Из деталей удалена вкладка `Граф` и панель графа.
|
||
- Удалены обработчики клика по глобальному графу/модалке, чтобы граф не открывался вообще.
|
||
- Полосатость основной таблицы переведена на классы `row-base/row-alt`, назначаемые в `renderDataRow` по индексу данных (не зависит от `detail-row`).
|
||
- Усилен контраст тонов зебры в light/dark.
|
||
- Выполнен version bump: .naeel/cloud-dashboard:v9.40`.
|
||
|
||
### Шаг U — Copy для UUID + жирные имена инстансов (v9.41)
|
||
- Цель: ускорить работу оператора в таблице и усилить визуальный приоритет названий.
|
||
- Реализация:
|
||
- В колонке UUID добавлена иконка копирования `⧉` для каждой строки.
|
||
- Кнопка UUID-копирования использует существующую логику `copyParamValue` и не триггерит раскрытие строки (`event.stopPropagation()`).
|
||
- Имена инстансов в колонке `Имя` переведены в жирное начертание (`.inst-name`).
|
||
- Для `uuid-copy` добавлены отдельные hover/ok стили в dark/light теме.
|
||
- Выполнен version bump: .naeel/cloud-dashboard:v9.41`.
|
||
|
||
### Шаг V — Правильная логика иконки day/night (v9.42)
|
||
- Цель: сделать поведение кнопки темы интуитивным (иконка показывает целевое переключение, а не текущий режим).
|
||
- Реализация:
|
||
- В `applyTheme` изменена логика кнопки:
|
||
- при активной дневной теме показывается `🌙` (переключение на ночь),
|
||
- при активной ночной теме показывается `☀` (переключение на день).
|
||
- Обновлены `title`-подсказки на действие: `Переключить на ... тему`.
|
||
- Выполнен version bump: naeel/cloud-dashboard:v9.42.
|
||
|
||
## 15. HANDOFF для нового чата (что делать дальше без доп. подсказок)
|
||
|
||
Текущее состояние (baseline):
|
||
- Таблица загружается через `/instances/stream` один раз на refresh, далее работает из памяти.
|
||
- Повторных API-вызовов между refresh нет.
|
||
- После reload данные восстанавливаются из browser snapshot (`version=2`, `schema=instance-stream-v2`).
|
||
- Удаляемость берется только из backend `_meta.deleteCandidate`.
|
||
- В кластере задеплоен образ `naeel/cloud-dashboard:v9.43`.
|
||
|
||
Нельзя нарушать (инварианты):
|
||
- Не добавлять параллельные обращения к внешнему API.
|
||
- Не делать догрузку detail по клику строки.
|
||
- Не возвращать клиентский fallback вычисления удаляемости.
|
||
- Все проектные команды выполнять только через SSH на ВМ.
|
||
|
||
При старте нового чата сделать в таком порядке:
|
||
1. Проверить, что в `k8s/deployment.yaml` увеличен image tag относительно предыдущего.
|
||
2. Проверить соответствие stream-контракта: `_progress`, `_detail`, `_meta`, `_done`.
|
||
3. Проверить, что `restoreSnapshot()` вызывается до `loadAllDetails()`.
|
||
4. Прогнать smoke-flow вручную: login -> refresh -> reload -> refresh.
|
||
5. Зафиксировать результат в этот файл отдельным шагом (H, I, ...).
|
||
|
||
Примечание по sync-проверке путей:
|
||
- Путь `/home/naeel/remote_dev/dashboard` может отсутствовать на ВМ, поэтому прямое сравнение хешей с `~/terra/dashboard` не всегда выполнимо на стороне ВМ.
|
||
- Если путь отсутствует, источником истины считать `~/terra/dashboard`, а для альтернативной проверки синхронизации запросить у оператора допустимый способ сравнения.
|
||
|
||
Чеклист smoke-flow (обязательный):
|
||
- После login/refresh видно `Загрузка X/Y`.
|
||
- После завершения видно `Актуально на ... (загрузка N c)`.
|
||
- После reload видно `Актуально на ... (из локального snapshot)`.
|
||
- До кнопки `Обновить` новых обращений к API нет.
|
||
- Индикатор удаляемости совпадает с backend `_meta.deleteCandidate`.
|
||
|
||
Definition of Done для следующего изменения:
|
||
- Выполнен version bump (минимум patch) в image tag.
|
||
- Изменение не ломает table-first режим и snapshot-режим.
|
||
- Документация обновлена новым шагом в разделе 14 или отдельной секцией.
|
||
|
||
### Шаг W — Реальный фикс theme-toggle после валидации pod (v9.43)
|
||
- Цель: гарантировать, что в рантайме действительно применяется инвертированная UX-логика иконки day/night.
|
||
- Причина: после релиза v9.42 в pod обнаружилась старая логика `applyTheme`.
|
||
- Реализация:
|
||
- На VM подтвержденно обновлен `static/index.html`:
|
||
- `light -> 🌙` (переключение на ночь),
|
||
- `dark -> ☀` (переключение на день),
|
||
- `title` показывает действие переключения.
|
||
- Выполнен повторный version bump: `naeel/cloud-dashboard:v9.43`.
|