Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/brave-horses-pump.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@openproject/primer-view-components': patch
---

Initiate form state for TreeView
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
49 changes: 29 additions & 20 deletions app/components/primer/alpha/tree_view/tree_view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,26 +45,7 @@ export class TreeViewElement extends HTMLElement {

if (!somethingChanged) return

const newInputs = []

// eslint-disable-next-line custom-elements/no-dom-traversal-in-connectedcallback
for (const node of this.querySelectorAll('[role=treeitem][aria-checked=true]')) {
const newInput = this.formInputPrototype.cloneNode() as HTMLInputElement
newInput.removeAttribute('data-target')
newInput.removeAttribute('form')

const payload: {path: string[]; value?: string} = {
path: this.getNodePath(node),
}

const inputValue = this.getFormInputValueForNode(node)
if (inputValue) payload.value = inputValue

newInput.value = JSON.stringify(payload)
newInputs.push(newInput)
}

this.formInputContainer.replaceChildren(...newInputs)
this.updateHiddenFormInputs()
})

updateInputsObserver.observe(this, {
Expand All @@ -73,6 +54,11 @@ export class TreeViewElement extends HTMLElement {
attributeFilter: ['aria-checked'],
})

// Correctly initialize the form
if (this.formInputContainer) {
this.updateHiddenFormInputs()
}

// eslint-disable-next-line github/no-then -- We don't want to wait for this to resolve, just get on with it
customElements.whenDefined('tree-view-sub-tree-node').then(() => {
// depends on TreeViewSubTreeNodeElement#eachAncestorSubTreeNode, which may not be defined yet
Expand Down Expand Up @@ -483,6 +469,29 @@ export class TreeViewElement extends HTMLElement {
selectVariant(node: Element): SelectVariant {
return (node.getAttribute('data-select-variant') || 'none') as SelectVariant
}

updateHiddenFormInputs() {
const newInputs = []

// eslint-disable-next-line custom-elements/no-dom-traversal-in-connectedcallback
for (const node of this.querySelectorAll('[role=treeitem][aria-checked=true]')) {
const newInput = this.formInputPrototype.cloneNode() as HTMLInputElement
newInput.removeAttribute('data-target')
newInput.removeAttribute('form')

const payload: {path: string[]; value?: string} = {
path: this.getNodePath(node),
}

const inputValue = this.getFormInputValueForNode(node)
if (inputValue) payload.value = inputValue

newInput.value = JSON.stringify(payload)
newInputs.push(newInput)
}

this.formInputContainer.replaceChildren(...newInputs)
}
}

if (!window.customElements.get('tree-view')) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<%= render(Primer::Alpha::Stack.new) do %>
<%= render(Primer::Alpha::TreeView.new(form_arguments: { builder: f, name: "folder_structure" })) do |tree| %>
<% tree.with_sub_tree(label: "src", expanded: expanded, select_variant: select_variant, value: 0) do |sub_tree| %>
<% sub_tree.with_leaf(label: "button.rb", select_variant: select_variant, value: 1) %>
<% sub_tree.with_leaf(label: "button.rb", select_variant: select_variant, value: 1, checked: true) %>
<% sub_tree.with_leaf(label: "icon_button.rb", current: true, select_variant: select_variant, value: 2) %>
<% end %>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<% end %>

<% hogwarts.with_sub_tree(label: "Slytherin", select_variant: select_variant, expanded: expanded) do |hufflepuff| %>
<% hufflepuff.with_leaf(label: "Draco Malfoy", select_variant: select_variant) %>
<% hufflepuff.with_leaf(label: "Draco Malfoy", select_variant: select_variant, checked: true) %>
<% end %>

<% hogwarts.with_sub_tree(label: "Hufflepuff", select_variant: select_variant, expanded: expanded) do |hufflepuff| %>
Expand Down
31 changes: 30 additions & 1 deletion test/system/alpha/tree_view_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -834,19 +834,35 @@ def test_self_select_strategy_checking_sub_tree_does_not_check_children
def test_form_submission
visit_preview(:form_input, expanded: true, route_format: :json)

assert_path_checked "src", "button.rb"
check_at_path("action_menu.rb")

find("button[type=submit]").click

# for some reason the JSON response is wrapped in HTML, I have no idea why
response = JSON.parse(find("pre").text)

assert_equal "{\"path\":[\"action_menu.rb\"],\"value\":\"3\"}", response.dig("form_params", "folder_structure", 0)
assert_equal "{\"path\":[\"src\",\"button.rb\"],\"value\":\"1\"}", response.dig("form_params", "folder_structure", 0)
assert_equal "{\"path\":[\"action_menu.rb\"],\"value\":\"3\"}", response.dig("form_params", "folder_structure", 1)
end

def test_initial_form_state
visit_preview(:form_input, expanded: true, route_format: :json)

assert_path_checked "src", "button.rb"

find("button[type=submit]").click

# for some reason the JSON response is wrapped in HTML, I have no idea why
response = JSON.parse(find("pre").text)

assert_equal "{\"path\":[\"src\",\"button.rb\"],\"value\":\"1\"}", response.dig("form_params", "folder_structure", 0)
end

def test_form_submission_with_single_select_variant
visit_preview(:form_input, expanded: true, select_variant: :single, route_format: :json)

assert_path_checked "src", "button.rb"
activate_at_path("action_menu.rb")

find("button[type=submit]").click
Expand All @@ -856,5 +872,18 @@ def test_form_submission_with_single_select_variant

assert_equal "{\"path\":[\"action_menu.rb\"],\"value\":\"3\"}", response.dig("form_params", "folder_structure", 0)
end

def test_initial_form_state_for_single_select
visit_preview(:form_input, expanded: true, route_format: :json)

assert_path_checked "src", "button.rb"

find("button[type=submit]").click

# for some reason the JSON response is wrapped in HTML, I have no idea why
response = JSON.parse(find("pre").text)

assert_equal "{\"path\":[\"src\",\"button.rb\"],\"value\":\"1\"}", response.dig("form_params", "folder_structure", 0)
end
end
end
59 changes: 54 additions & 5 deletions test/system/open_project/filterable_tree_view_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@ def test_automatically_expands_sub_trees_to_show_matching_items
def test_form_submits_checked_nodes_for_single_select_variant
visit_preview(:form_input, select_variant: :single)

assert_path_checked("Students", "Slytherin", "Draco Malfoy")
activate_at_path("Students", "Gryffindor", "Harry Potter")
activate_at_path("Students", "Ravenclaw", "Luna Lovegood")
click_on "Submit"
Expand All @@ -234,28 +235,63 @@ def test_form_submits_checked_nodes_for_single_select_variant
assert_equal character["path"], ["Students", "Ravenclaw", "Luna Lovegood"]
end

def test_initial_form_state_for_single_select
visit_preview(:form_input, select_variant: :single)

assert_path_checked("Students", "Slytherin", "Draco Malfoy")

find("button[type=submit]").click

response = JSON.parse(find("pre").text)
assert character_list = response.dig("form_params", "characters")
assert_equal 1, character_list.size

character = JSON.parse(character_list[0])
assert_equal character["path"], ["Students", "Slytherin", "Draco Malfoy"]
end

def test_form_submits_checked_nodes
visit_preview(:form_input)

assert_path_checked("Students", "Slytherin", "Draco Malfoy")
check_at_path("Students", "Gryffindor", "Harry Potter")
check_at_path("Students", "Ravenclaw", "Luna Lovegood")
click_on "Submit"

response = JSON.parse(find("pre").text)
assert character_list = response.dig("form_params", "characters")
assert_equal 2, character_list.size
assert_equal 3, character_list.size

character = JSON.parse(character_list[0])
assert_equal character["path"], ["Students", "Ravenclaw", "Luna Lovegood"]


character = JSON.parse(character_list[1])
assert_equal character["path"], ["Students", "Slytherin", "Draco Malfoy"]

character = JSON.parse(character_list[2])
assert_equal character["path"], ["Students", "Gryffindor", "Harry Potter"]
end

def test_initial_form_state_for_multi_select
visit_preview(:form_input)

assert_path_checked("Students", "Slytherin", "Draco Malfoy")

find("button[type=submit]").click

response = JSON.parse(find("pre").text)
assert character_list = response.dig("form_params", "characters")
assert_equal 1, character_list.size

character = JSON.parse(character_list[0])
assert_equal character["path"], ["Students", "Slytherin", "Draco Malfoy"]
end

def test_form_submits_checked_nodes_when_sub_items_included_checked
visit_preview(:form_input)

assert_path_checked("Students", "Slytherin", "Draco Malfoy")

check "Include sub-items"
assert_checked_field "Include sub-items"

Expand All @@ -265,18 +301,23 @@ def test_form_submits_checked_nodes_when_sub_items_included_checked

response = JSON.parse(find("pre").text)
assert character_list = response.dig("form_params", "characters")
assert_equal 2, character_list.size
assert_equal 3, character_list.size

character = JSON.parse(character_list[0])
assert_equal character["path"], ["Students", "Ravenclaw"]

character = JSON.parse(character_list[1])
assert_equal character["path"], ["Students", "Ravenclaw", "Luna Lovegood"]

character = JSON.parse(character_list[2])
assert_equal character["path"], ["Students", "Slytherin", "Draco Malfoy"]
end

def test_form_submits_checked_nodes_when_items_filtered_out
visit_preview(:form_input)

assert_path_checked("Students", "Slytherin", "Draco Malfoy")

check_at_path("Students", "Ravenclaw")

fill_in "Filter", with: "Harry"
Expand All @@ -287,18 +328,22 @@ def test_form_submits_checked_nodes_when_items_filtered_out

response = JSON.parse(find("pre").text)
assert character_list = response.dig("form_params", "characters")
assert_equal 2, character_list.size
assert_equal 3, character_list.size

character = JSON.parse(character_list[0])
assert_equal character["path"], ["Students", "Ravenclaw"]

character = JSON.parse(character_list[1])
assert_equal character["path"], ["Students", "Slytherin", "Draco Malfoy"]

character = JSON.parse(character_list[2])
assert_equal character["path"], ["Students", "Gryffindor", "Harry Potter"]
end

def test_form_submits_checked_nodes_when_filtering_for_selected_only
visit_preview(:form_input)

assert_path_checked("Students", "Slytherin", "Draco Malfoy")
check_at_path("Students", "Ravenclaw")
check_at_path("Students", "Ravenclaw", "Luna Lovegood")

Expand All @@ -308,17 +353,21 @@ def test_form_submits_checked_nodes_when_filtering_for_selected_only

uncheck_at_path("Students", "Ravenclaw", "Luna Lovegood")

assert_path_checked("Students", "Slytherin", "Draco Malfoy")
assert_path_checked("Students", "Ravenclaw")
refute_path_checked("Students", "Ravenclaw", "Luna Lovegood")

click_on "Submit"

response = JSON.parse(find("pre").text)
assert character_list = response.dig("form_params", "characters")
assert_equal 1, character_list.size
assert_equal 2, character_list.size

character = JSON.parse(character_list[0])
assert_equal character["path"], ["Students", "Ravenclaw"]

character = JSON.parse(character_list[1])
assert_equal character["path"], ["Students", "Slytherin", "Draco Malfoy"]
end
end
end