feat(#115): Leaflet layer toggle для connection points (Макс KILLER) #230

Merged
lekss361 merged 2 commits from feat/connection-points-leaflet-layer into main 2026-05-16 20:00:55 +00:00
Owner

Summary

Реализация visual слоя connection points на Leaflet карте SiteMap.tsx с per-категория toggle — требование Макса из #115 Phase 1 (KILLER feature).

«Если отдельным слоем можно вывести точки подключения и параметры точек подключения — то это лучшая новость в мире будет для всех нас.» — Макс, 2026-05-12

Что сделано

Новые компоненты

  • frontend/src/components/site-finder/ConnectionPointsLayer.tsx — рендерится внутри <MapContainer>, принимает grouped: Map<CpCategory, EngineeringStructure[]> + visibleCategories: Set<CpCategory>. Рисует CircleMarker с Popup (название, тип, адрес, расстояние, источник). Классификация по keywords в name/type/source.
  • frontend/src/components/site-finder/CpLayerControlPanel.tsx — collapsible panel под картой: checkbox per-category с цветным dot + count, toggle-all, summary strip.

Расширения

  • SiteMap.tsx — управляет visibleCategories state, pre-группирует через groupStructuresByCategory, передаёт в оба компонента.
  • app/site-finder/page.tsx — вызывает useConnectionPoints(data?.cad_num) (уже существующий хук) и прокидывает в SiteMap через optional prop.

Категории

  • электричество / газ / вода / тепло / канализация / связь / другое (классификация по keywords)
  • Каждая со своим цветом и счётчиком

Известное ограничение (P0 — не блокирует merge)

Backend nspd_quarter_dumps сейчас = 0 строк (beat schedule намеренно отключён 2026-05-14 до Sprint 2 grid sampling rewrite — vault Bug_NSPD_WMS_NotBulk_2026_May14). UI gracefully показывает empty state. После Sprint 2 fix — слой автоматически наполнится данными.

Test plan

  • cd frontend && npx tsc --noEmit && npm run lint — pass
  • Smoke на /site-finder с cad имеющим dump → cluster маркеров видим, toggle работает
  • Empty state (dump пуст) → нет крашей, panel показывает "0 точек"
  • Mobile responsive проверить
## Summary Реализация visual слоя connection points на Leaflet карте `SiteMap.tsx` с per-категория toggle — требование Макса из #115 Phase 1 (KILLER feature). > «Если отдельным слоем можно вывести точки подключения и параметры точек подключения — то это лучшая новость в мире будет для всех нас.» — Макс, 2026-05-12 ## Что сделано ### Новые компоненты - `frontend/src/components/site-finder/ConnectionPointsLayer.tsx` — рендерится внутри `<MapContainer>`, принимает `grouped: Map<CpCategory, EngineeringStructure[]>` + `visibleCategories: Set<CpCategory>`. Рисует `CircleMarker` с `Popup` (название, тип, адрес, расстояние, источник). Классификация по keywords в `name`/`type`/`source`. - `frontend/src/components/site-finder/CpLayerControlPanel.tsx` — collapsible panel под картой: checkbox per-category с цветным dot + count, toggle-all, summary strip. ### Расширения - `SiteMap.tsx` — управляет `visibleCategories` state, pre-группирует через `groupStructuresByCategory`, передаёт в оба компонента. - `app/site-finder/page.tsx` — вызывает `useConnectionPoints(data?.cad_num)` (уже существующий хук) и прокидывает в SiteMap через optional prop. ## Категории - электричество / газ / вода / тепло / канализация / связь / другое (классификация по keywords) - Каждая со своим цветом и счётчиком ## Известное ограничение (P0 — не блокирует merge) Backend `nspd_quarter_dumps` сейчас = 0 строк (beat schedule намеренно отключён 2026-05-14 до Sprint 2 grid sampling rewrite — vault `Bug_NSPD_WMS_NotBulk_2026_May14`). UI gracefully показывает empty state. После Sprint 2 fix — слой автоматически наполнится данными. ## Test plan - [ ] `cd frontend && npx tsc --noEmit && npm run lint` — pass - [ ] Smoke на /site-finder с cad имеющим dump → cluster маркеров видим, toggle работает - [ ] Empty state (dump пуст) → нет крашей, panel показывает "0 точек" - [ ] Mobile responsive проверить
lekss361 added 2 commits 2026-05-16 19:53:46 +00:00
Add SQL migration 100_user_weight_profiles_default_seed.sql with system
presets Эконом/Комфорт/Бизнес (user_id='__system__'). Migration is
idempotent via ON CONFLICT DO UPDATE.

Backend:
- weight_profiles.py: add SYSTEM_USER_ID constant + list_profiles_with_system()
- admin_weight_profiles.py: add include_system query param to GET list endpoint

Tests: 3 new tests covering include_system flag and service sentinel behaviour.
- ConnectionPointsLayer.tsx — per-category CircleMarker слой внутри MapContainer
  (electricity/gas/water/heat/sewage/telecom/other, классификация по keywords)
- CpLayerControlPanel.tsx — toggle panel под картой: checkbox per-category + count,
  toggle-all, summary badges (ближайший, охранная зона)
- SiteMap.tsx — принимает connectionPoints?: ConnectionPointsResponse,
  управляет visibleCategories state, рендерит оба новых компонента
- page.tsx — useConnectionPoints(data?.cad_num) -> передаёт в SiteMap
- Empty-state: "0 точек подключения" при dump_available=false или пустом ответе
Author
Owner

Deep Code Review — verdict APPROVE

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

  • 8 файлов, +742/-4, 2 коммита (#115 Leaflet layer + #114 weight presets seed — scope creep, но обе фичи завершены).
  • Leaflet layer рендерится внутри <MapContainer> (SiteMap.tsx:269-274) — RuntimeError исключён.
  • Классификация case-insensitive через .toLowerCase(), name ?? "" обработка null ✓.
  • Set<CpCategory> immutable: setVisibleCategories(prev => new Set(prev)) — корректно ✓.
  • Toggle-all: prev.size === CP_ALL_CATEGORIES.length ↔ all/none — корректно ✓.
  • XSS: только React text rendering, никаких dangerouslySetInnerHTML ✓.
  • Backward compat: connectionPoints?: ... optional → existing callers SiteMap не сломаны ✓.
  • TanStack Query (useConnectionPoints) с enabled: !!cadNum — нет фетча на пустом cad ✓.
  • Migration 100_user_weight_profiles_default_seed.sql: BEGIN/COMMIT, ON CONFLICT (user_id, profile_name) DO UPDATE (UNIQUE существует в 90_user_weight_profiles.sql:25) — идемпотентно ✓.
  • Tests добавлены (3 для #114 include_system endpoint + service) ✓.

🟡 Minor (не блокирует merge, можно отдельным PR)

  • ConnectionPointsLayer.tsx:108-119extractLatLon обрабатывает только geojson.type === "Point". LineString/Polygon (газопровод/водопровод линейные) — silent drop. Если backend возвращает линейные структуры — на карте их не будет. Желательно добавить fallback на centroid или вынести в follow-up.
  • SiteMap.tsx:149cpGrouped без useMemo, re-grouping на каждый render. Для ~10-50 точек ок, при росте до 500+ — обернуть в useMemo([connectionPoints]).
  • Scope creep: PR title feat(#115) но содержит #114 коммит. В будущем — отдельные PR per issue.

Known limitation (подтверждено)

nspd_quarter_dumps сейчас = 0 строк (beat schedule отключён 2026-05-14 до Sprint 2 grid sampling rewrite, см. Bug_NSPD_WMS_NotBulk_2026_May14). UI gracefully показывает:

  • !dump_available → жёлтый badge "Дамп квартала не загружен"
  • totalCount === 0 → "0 точек подключения в этом квартале"

Слой автоматически наполнится после Sprint 2 fix без правок UI.

Recommendation для qa-tester после deploy

  1. /site-finder с любым cad → панель "Точки подключения" видна, показывает "0 шт" и yellow badge "Дамп не загружен".
  2. После Sprint 2 grid-sampling rewrite — повторный smoke с заполненным dump, проверить toggle per-category + popup.
  3. Mobile responsive — панель ниже карты, проверить на 375px viewport.

Merging via deep-code-reviewer.

## Deep Code Review — verdict ✅ APPROVE ### Что проверено - 8 файлов, +742/-4, 2 коммита (#115 Leaflet layer + #114 weight presets seed — scope creep, но обе фичи завершены). - Leaflet layer рендерится **внутри** `<MapContainer>` (SiteMap.tsx:269-274) — RuntimeError исключён. - Классификация case-insensitive через `.toLowerCase()`, `name ?? ""` обработка null ✓. - `Set<CpCategory>` immutable: `setVisibleCategories(prev => new Set(prev))` — корректно ✓. - Toggle-all: `prev.size === CP_ALL_CATEGORIES.length` ↔ all/none — корректно ✓. - XSS: только React text rendering, никаких `dangerouslySetInnerHTML` ✓. - Backward compat: `connectionPoints?: ...` optional → existing callers SiteMap не сломаны ✓. - TanStack Query (`useConnectionPoints`) с `enabled: !!cadNum` — нет фетча на пустом cad ✓. - Migration `100_user_weight_profiles_default_seed.sql`: `BEGIN/COMMIT`, `ON CONFLICT (user_id, profile_name) DO UPDATE` (UNIQUE существует в 90_user_weight_profiles.sql:25) — идемпотентно ✓. - Tests добавлены (3 для #114 include_system endpoint + service) ✓. ### 🟡 Minor (не блокирует merge, можно отдельным PR) - `ConnectionPointsLayer.tsx:108-119` — `extractLatLon` обрабатывает только `geojson.type === "Point"`. LineString/Polygon (газопровод/водопровод линейные) — silent drop. Если backend возвращает линейные структуры — на карте их не будет. Желательно добавить fallback на centroid или вынести в follow-up. - `SiteMap.tsx:149` — `cpGrouped` без `useMemo`, re-grouping на каждый render. Для ~10-50 точек ок, при росте до 500+ — обернуть в `useMemo([connectionPoints])`. - Scope creep: PR title `feat(#115)` но содержит #114 коммит. В будущем — отдельные PR per issue. ### Known limitation (подтверждено) `nspd_quarter_dumps` сейчас = 0 строк (beat schedule отключён 2026-05-14 до Sprint 2 grid sampling rewrite, см. `Bug_NSPD_WMS_NotBulk_2026_May14`). UI gracefully показывает: - `!dump_available` → жёлтый badge "Дамп квартала не загружен" - `totalCount === 0` → "0 точек подключения в этом квартале" Слой автоматически наполнится после Sprint 2 fix без правок UI. ### Recommendation для qa-tester после deploy 1. `/site-finder` с любым cad → панель "Точки подключения" видна, показывает "0 шт" и yellow badge "Дамп не загружен". 2. После Sprint 2 grid-sampling rewrite — повторный smoke с заполненным dump, проверить toggle per-category + popup. 3. Mobile responsive — панель ниже карты, проверить на 375px viewport. Merging via deep-code-reviewer.
lekss361 merged commit 56bf28758c into main 2026-05-16 20:00:55 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: lekss361/gendesign#230
No description provided.