fix(stacks): сохранять стек-крошки при Quick Actions контейнера #24

Merged
vvzvlad merged 1 commits from fix/stack-breadcrumb-quickactions into develop 2026-07-01 20:23:58 +03:00
Collaborator

Summary

Чинит баг из твоего скрина: в списке контейнеров стека клик по иконке Quick Actions (Logs/Stats/Console/Inspect/Attach) уводил на ГЛОБАЛЬНЫЙ роут docker.containers.container.* и схлопывал хлебные крошки в «Containers > … > Logs», теряя стек-трейл (который добавил #7).

Причина: таблица контейнеров стека переиспользует общую datatable контейнеров, а её колонка Quick Actions хардкодила глобальные ссылки. Стек-скоуп состояния docker.stacks.stack.container.* уже были (из #7) — Quick Actions на них просто не смотрели.

Фикс: прокидываю параметры маршрута стека через RowContext в ContainerQuickActions; когда рендеримся внутри стека — ссылки ведут на docker.stacks.stack.container.{logs,stats,inspect,exec,attach} (переиспользую buildStackContainerLinkParams/STACK_CONTAINER_STATE_NAME из #7). Глобальный список контейнеров и вкладка задач сервиса стек-параметров не передают → их ссылки не меняются.

Доводка к #7 (тот уже смержен), поэтому отдельным PR.

How verified

  • Собрал стенд со всеми PR, воспроизвёл баг именно так (Stacks → web-demo → Quick Actions → logs → крошка «Containers…», URL /docker/containers//logs). После фикса ссылки ведут на стек-скоуп состояние.
  • Юнит-тест ContainerQuickActions.test.tsx: без стек-контекста все 5 ссылок → docker.containers.container.* c {id,nodeName}; со стек-контекстом → docker.stacks.stack.container.* c параметрами стека + id/nodeName.
  • tsc --noEmit — 0; eslint изменённых — 0; vitest — passed.
  • Внутренний ревью: APPROVE (регрессий в глобальном списке и задачах сервиса нет; имена состояний совпадают с регистрацией в __module.js; набор параметров для перестроения крошек полный, внешние стеки обработаны).

Checklist

  • хлебные крошки сохраняются при Quick Actions из стека
  • глобальный список контейнеров и задачи сервиса не затронуты
  • вне scope ничего не менялось
## Summary Чинит баг из твоего скрина: в списке контейнеров стека клик по иконке Quick Actions (Logs/Stats/Console/Inspect/Attach) уводил на ГЛОБАЛЬНЫЙ роут `docker.containers.container.*` и схлопывал хлебные крошки в «Containers > … > Logs», теряя стек-трейл (который добавил #7). Причина: таблица контейнеров стека переиспользует общую datatable контейнеров, а её колонка Quick Actions хардкодила глобальные ссылки. Стек-скоуп состояния `docker.stacks.stack.container.*` уже были (из #7) — Quick Actions на них просто не смотрели. Фикс: прокидываю параметры маршрута стека через RowContext в `ContainerQuickActions`; когда рендеримся внутри стека — ссылки ведут на `docker.stacks.stack.container.{logs,stats,inspect,exec,attach}` (переиспользую `buildStackContainerLinkParams`/`STACK_CONTAINER_STATE_NAME` из #7). Глобальный список контейнеров и вкладка задач сервиса стек-параметров не передают → их ссылки не меняются. Доводка к #7 (тот уже смержен), поэтому отдельным PR. ## How verified - Собрал стенд со всеми PR, воспроизвёл баг именно так (Stacks → web-demo → Quick Actions → logs → крошка «Containers…», URL /docker/containers/<id>/logs). После фикса ссылки ведут на стек-скоуп состояние. - Юнит-тест `ContainerQuickActions.test.tsx`: без стек-контекста все 5 ссылок → `docker.containers.container.*` c {id,nodeName}; со стек-контекстом → `docker.stacks.stack.container.*` c параметрами стека + id/nodeName. - `tsc --noEmit` — 0; `eslint` изменённых — 0; `vitest` — passed. - Внутренний ревью: APPROVE (регрессий в глобальном списке и задачах сервиса нет; имена состояний совпадают с регистрацией в `__module.js`; набор параметров для перестроения крошек полный, внешние стеки обработаны). ## Checklist - [x] хлебные крошки сохраняются при Quick Actions из стека - [x] глобальный список контейнеров и задачи сервиса не затронуты - [x] вне scope ничего не менялось
agent_coder added 1 commit 2026-07-01 18:53:29 +03:00
The stack container list reuses the shared containers datatable, whose
Quick Actions column linked to the global docker.containers.container.*
states with only {id,nodeName}. Clicking Logs/Stats/Console/Inspect/Attach
from within a stack therefore jumped to the global route and collapsed the
breadcrumb to "Containers > <name> > Logs", losing the stack trail that
PR #7 added.

Thread the current stack route params (via RowContext) down to
ContainerQuickActions so, when rendered inside a stack, its links target the
stack-scoped docker.stacks.stack.container.* sub-tab states (reusing #7's
buildStackContainerLinkParams / STACK_CONTAINER_STATE_NAME helpers). The
global containers list and service tasks pass no stack params and keep the
global links unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
agent_coder added the review/needs label 2026-07-01 18:53:43 +03:00
Collaborator

Ревью f379e8057 — раунд 1 (полный фан-аут: security/stability/regressions/test-coverage/conventions/simplification/architecture/coherence, отдельный субагент на аспект).

Вердикт: PASS. Фикс делает ровно то, что нужно, и не задевает ничего вокруг. Готово к мержу.

Что проверено

  • Coherence (сквозной механизм крошек). Проследил цепочку до конца: под-табы контейнера (Logs/Stats/Console/Inspect) строят хлебные крошки в getContainerSubTabBreadcrumbs(state, params, …) — то есть трейл выводится и из имени состояния (isStackContainerStatestartsWith('docker.stacks.stack.container')), и из route-параметров. Фикс линкует на docker.stacks.stack.container.{tab} — это реальные дочерние состояния docker.stacks.stack, зарегистрированные в app/docker/__module.js (все пять: logs/inspect/stats/exec/attach). Ключи совпадают на каждом стыке: docker.stacks.stack url-params (name,stackId,type,regular,external,orphaned,orphanedRunning,tab) → useCurrentStateAndParams().params → RowContext stackRouteParamsbuildStackContainerLinkParams({...stackRouteParams, nodeName}, id) (читает ровно эти ключи, добавляет id/nodeName). Тихого рассинхрона ключей нет — фикс действительно восстанавливает трейл «Stacks › стек › контейнер › таб», а не просто компилируется.
  • Regressions. ContainerQuickActions без stackLinkParams даёт БАЙТ-идентичное старое поведение (to="docker.containers.container.<tab>", params={id,nodeName}). Оба не-стековых вызова падают в этот путь: глобальный список контейнеров передаёт только {environment}; вкладка задач сервиса проп не передаёт вовсе. isActive-гейтинг stats/exec/attach не тронут. Второй потребитель того же RowContext (ports.tsx) берёт только environment — новое опциональное поле его не задевает.
  • Stability. Все 5 целевых состояний зарегистрированы (не «ссылка в никуда»); состояние docker.stacks.stack декларирует нужные url-параметры; useRowContext() не роняет — оба потребителя колонки обёрнуты в RowProvider, а путь service-tasks зовёт компонент напрямую (без колонки).
  • Test-coverage. ContainerQuickActions.test.tsx гоняет реальный компонент (мок только @@/Link/Authorized), обе ветки non-vacuous (реверт логики роутинга уронил бы ассерты), сверяется с реальным buildStackContainerLinkParams, а не с реимплементацией. Тонкая обвязка (колонка/дататейбл) — pass-through, отдельный интеграционный тест был бы gold-plating (риск низкий).
  • Conventions / simplification — чисто: useCurrentStateAndParams идиоматичен, тип Record<string, string|undefined> совпадает с сигнатурой buildStackContainerLinkParams, абстракция linkTo/linkParams пропорциональна (5 ссылок), дублей нет.

Объективные проверки (запущены в окружении ревью, не со слов кодера)

  • tsc --noEmit -p . (весь проект) — exit 0.
  • eslint по 5 изменённым файлам — чисто.
  • vitest run ContainerQuickActions.test.tsx2 passed.

Маркер reviewed_head обновлён на f379e8057.

Ревью **f379e8057** — раунд 1 (полный фан-аут: security/stability/regressions/test-coverage/conventions/simplification/architecture/coherence, отдельный субагент на аспект). **Вердикт: PASS.** Фикс делает ровно то, что нужно, и не задевает ничего вокруг. Готово к мержу. ### Что проверено - **Coherence (сквозной механизм крошек).** Проследил цепочку до конца: под-табы контейнера (Logs/Stats/Console/Inspect) строят хлебные крошки в `getContainerSubTabBreadcrumbs(state, params, …)` — то есть трейл выводится и из **имени состояния** (`isStackContainerState` → `startsWith('docker.stacks.stack.container')`), и из **route-параметров**. Фикс линкует на `docker.stacks.stack.container.{tab}` — это реальные дочерние состояния `docker.stacks.stack`, зарегистрированные в `app/docker/__module.js` (все пять: logs/inspect/stats/exec/attach). Ключи совпадают на каждом стыке: `docker.stacks.stack` url-params (`name,stackId,type,regular,external,orphaned,orphanedRunning,tab`) → `useCurrentStateAndParams().params` → RowContext `stackRouteParams` → `buildStackContainerLinkParams({...stackRouteParams, nodeName}, id)` (читает ровно эти ключи, добавляет `id`/`nodeName`). Тихого рассинхрона ключей нет — фикс действительно восстанавливает трейл «Stacks › стек › контейнер › таб», а не просто компилируется. - **Regressions.** `ContainerQuickActions` без `stackLinkParams` даёт БАЙТ-идентичное старое поведение (`to="docker.containers.container.<tab>"`, `params={id,nodeName}`). Оба не-стековых вызова падают в этот путь: глобальный список контейнеров передаёт только `{environment}`; вкладка задач сервиса проп не передаёт вовсе. `isActive`-гейтинг stats/exec/attach не тронут. Второй потребитель того же RowContext (`ports.tsx`) берёт только `environment` — новое опциональное поле его не задевает. - **Stability.** Все 5 целевых состояний зарегистрированы (не «ссылка в никуда»); состояние `docker.stacks.stack` декларирует нужные url-параметры; `useRowContext()` не роняет — оба потребителя колонки обёрнуты в `RowProvider`, а путь service-tasks зовёт компонент напрямую (без колонки). - **Test-coverage.** `ContainerQuickActions.test.tsx` гоняет реальный компонент (мок только `@@/Link`/`Authorized`), обе ветки non-vacuous (реверт логики роутинга уронил бы ассерты), сверяется с реальным `buildStackContainerLinkParams`, а не с реимплементацией. Тонкая обвязка (колонка/дататейбл) — pass-through, отдельный интеграционный тест был бы gold-plating (риск низкий). - **Conventions / simplification** — чисто: `useCurrentStateAndParams` идиоматичен, тип `Record<string, string|undefined>` совпадает с сигнатурой `buildStackContainerLinkParams`, абстракция `linkTo`/`linkParams` пропорциональна (5 ссылок), дублей нет. ### Объективные проверки (запущены в окружении ревью, не со слов кодера) - `tsc --noEmit -p .` (весь проект) — **exit 0**. - `eslint` по 5 изменённым файлам — **чисто**. - `vitest run ContainerQuickActions.test.tsx` — **2 passed**. Маркер `reviewed_head` обновлён на `f379e8057`. <!-- state:review reviewed_head=f379e8057 round=1 verdict=approved -->
agent_reviewer added review/approved and removed review/needs labels 2026-07-01 19:26:13 +03:00
vvzvlad merged commit 394075c94c into develop 2026-07-01 20:23:58 +03:00
Sign in to join this conversation.