fix(page-tree/dnd): drop-раскрытие + guard от потери детей (#523) #532
Reference in New Issue
Block a user
Delete Branch "fix/523-tree-dnd"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Три правки drag-and-drop дерева страниц (стоит стопкой на #525 — общий класс потери детей #159-#1):
AUTO_EXPAND_MS) — меньше случайных раскрытий при проносе курсора.onToggle(target,true)из make-child-drop; вместо навязчивого раскрытия — teal-пульсdata-landed-child(«уехало сюда») + инвалидация крошек перемещённой страницы.handleMove: при make-child в незагруженную свёрнутую цель оптимистик =remove(source)+update(target, hasChildren:true)(gate взведён,children:[]), а не наивная материализация[source], которая скрыла бы серверных детей. Зеркалит фикс #525 на DnD-пути.closes #523.
How verified
use-tree-mutation.move-guard.test.tsx(3) +update-cache-on-move.breadcrumbs.test.ts(1) — 2 файла, 4 passed.[source]; загруженная — позиционный insert среди существующих детей без потерь/дублей (["c1","X"]); genuinely-empty лист материализует source (["X"]).unloadedMakeChild=false) → тест «UNLOADED folder does NOT materialize [source]» краснеет.doc-tree-row.tsx:137 if(!el||readOnly) return) drag/drop не регистрирует — shared-tree не затронут. Таймер teal-пульса чистится на unmount, уважает prefers-reduced-motion.Примечание по стеку
База —
fix/525-insert-unloaded(общий предикатisUnloadedBranch). После мержа #525 ретаргетить базу наdevelop.Checklist
Хэндофф. Внутренний цикл: 1 проход, чисто — мутация (disable guard → тест «UNLOADED does NOT materialize» краснеет) подтвердила. База — ветка #525 (PR #531); после её мержа ретаргечу на develop. Guard зеркалит фикс #525 на DnD-пути; нормальные перемещения (reorder/reparent/to-root) без регрессий, read-only дерево не затронуто.
🤖 Авто-ревью · #532 (page-tree/dnd: drop-раскрытие + guard от потери детей, #523) — голова
27d51303. Вердикт: PASS ✅Это фикс ровно той вне-scope потери данных, что я флагнул на #531 (локальный DnD make-child в незагруженную ветку материализовал
[source]и скрывал серверных детей). Закрыт корректно. Стоит стопкой на #531 (заапрувлен). Эскалаций нет.Прогнал 9-аспектный веер (свёрнут в 3) + гейт (client vitest 94/94). Все 9 аспектов — LGTM. Сверил лично:
isUnloadedBranch(use-tree-mutation.ts:83) — тот самый single-source-предикат из #531 (не локальная копия, коммент явно это отмечает), значит анти-дрейф держится.hasChildren:true, children:[]) →remove(source)+update(target,{hasChildren:true}), БЕЗ материализации[source](gate взведён); LOADED → позиционный["c1","X"](без потери/дубля); genuinely-empty → материализует["X"].updateCacheOnMovePage(if(!old) return) ничего частичного не создаёт; на expand →isUnloadedBranchtrue → fetch полного серверного набора →appendChildren(dedup-by-id) → X один раз. Серверный move awaited, на failure — restore(before). Потери нет.useEffect-cleanup),prefers-reduced-motionобработан, read-only/shared-дерево drag/drop не регистрирует (doc-tree-row:137).unloadedMakeChild=false→ тест «UNLOADED does NOT materialize» краснеет.Отличный фикс — закрывает мою вне-scope находку, переиспользуя общий предикат, reconcile корректен. Approve.