Skip to content

Commit 8491824

Browse files
committed
[DREAM-808] Fixes inserted checked node form state
https://community.openproject.org/wp/DREAM-808 Extends the TreeView form observer guard to recognize childList mutations that add checked tree items. Previously only aria-checked attribute changes triggered a rebuild of the hidden form inputs, so checked nodes inserted after connect (e.g. from async fragments) appeared selected but were omitted from form submission. Adds a browser regression test cloning a checked node into an already-connected tree.
1 parent c27e9ed commit 8491824

2 files changed

Lines changed: 37 additions & 0 deletions

File tree

app/components/primer/alpha/tree_view/tree_view.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,17 @@ export class TreeViewElement extends HTMLElement {
3838
// nodes based on the component's select strategy. These two observers can conflict and cause infinite
3939
// looping, so we make sure something actually changed before computing inputs again.
4040
const somethingChanged = mutations.some(m => {
41+
if (m.type === 'childList') {
42+
return [...m.addedNodes].some(node => {
43+
if (!(node instanceof Element)) return false
44+
45+
return (
46+
node.matches('[role=treeitem][aria-checked=true]') ||
47+
Boolean(node.querySelector('[role=treeitem][aria-checked=true]'))
48+
)
49+
})
50+
}
51+
4152
if (!(m.target instanceof HTMLElement)) return false
4253
return m.target.getAttribute('aria-checked') !== m.oldValue
4354
})

test/system/alpha/tree_view_test.rb

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -952,6 +952,32 @@ def test_initial_form_state
952952
assert_equal "{\"path\":[\"src\",\"button.rb\"],\"nodeId\":\"src-button-rb\",\"value\":\"1\"}", response.dig("form_params", "folder_structure", 0)
953953
end
954954

955+
def test_form_state_updates_when_checked_nodes_are_inserted
956+
visit_preview(:form_input, expanded: true, route_format: :json)
957+
958+
evaluate_multiline_script(<<~JS)
959+
const tree = document.querySelector("tree-view")
960+
const checkedNode = tree.querySelector("[role=treeitem][aria-checked=true]")
961+
const clone = checkedNode.closest("li").cloneNode(true)
962+
const clonedTreeItem = clone.querySelector("[role=treeitem]")
963+
964+
clonedTreeItem.removeAttribute("id")
965+
clonedTreeItem.removeAttribute("data-node-id")
966+
clonedTreeItem.removeAttribute("data-value")
967+
clonedTreeItem.setAttribute("data-path", JSON.stringify(["async.rb"]))
968+
969+
tree.querySelector(":scope > ul").append(clone)
970+
JS
971+
972+
assert_selector("[data-target='tree-view.formInputContainer'] input", count: 2, visible: :all)
973+
974+
find("button[type=submit]").click
975+
976+
response = JSON.parse(find("pre").text)
977+
978+
assert_includes response.dig("form_params", "folder_structure"), "{\"path\":[\"async.rb\"]}"
979+
end
980+
955981
def test_form_submission_with_single_select_variant
956982
visit_preview(:form_input, expanded: true, select_variant: :single, route_format: :json)
957983

0 commit comments

Comments
 (0)