openproject-primer_view_components 0.71.0 → 0.72.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +14 -0
  3. data/app/assets/javascripts/components/primer/open_project/filterable_tree_view.d.ts +2 -2
  4. data/app/assets/javascripts/components/primer/primer.d.ts +4 -4
  5. data/app/assets/javascripts/primer_view_components.js +1 -1
  6. data/app/assets/javascripts/primer_view_components.js.map +1 -1
  7. data/app/assets/styles/primer_view_components.css +1 -1
  8. data/app/assets/styles/primer_view_components.css.map +1 -1
  9. data/app/components/primer/{open_project → alpha}/file_tree_view/directory_node.rb +1 -1
  10. data/app/components/primer/{open_project → alpha}/file_tree_view/file_node.rb +1 -1
  11. data/app/components/primer/{open_project → alpha}/file_tree_view.rb +1 -1
  12. data/app/components/primer/{open_project → alpha}/skeleton_box.css.json +1 -1
  13. data/app/components/primer/{open_project → alpha}/skeleton_box.css.map +1 -1
  14. data/app/components/primer/{open_project → alpha}/skeleton_box.pcss +1 -1
  15. data/app/components/primer/{open_project → alpha}/skeleton_box.rb +3 -1
  16. data/app/components/primer/{open_project → alpha}/tree_view/icon.rb +2 -2
  17. data/app/components/primer/{open_project → alpha}/tree_view/icon_pair.rb +4 -4
  18. data/app/components/primer/{open_project → alpha}/tree_view/leading_action.rb +2 -2
  19. data/app/components/primer/{open_project → alpha}/tree_view/leaf_node.rb +6 -6
  20. data/app/components/primer/{open_project → alpha}/tree_view/loading_failure_message.rb +2 -2
  21. data/app/components/primer/{open_project → alpha}/tree_view/node.rb +17 -17
  22. data/app/components/primer/{open_project → alpha}/tree_view/skeleton_loader.html.erb +3 -3
  23. data/app/components/primer/{open_project → alpha}/tree_view/skeleton_loader.rb +4 -4
  24. data/app/components/primer/{open_project → alpha}/tree_view/spinner_loader.html.erb +2 -2
  25. data/app/components/primer/{open_project → alpha}/tree_view/spinner_loader.rb +4 -4
  26. data/app/components/primer/{open_project → alpha}/tree_view/sub_tree.html.erb +1 -1
  27. data/app/components/primer/{open_project → alpha}/tree_view/sub_tree.rb +10 -10
  28. data/app/components/primer/{open_project → alpha}/tree_view/sub_tree_container.rb +2 -2
  29. data/app/components/primer/{open_project → alpha}/tree_view/sub_tree_node.rb +15 -15
  30. data/app/components/primer/{open_project → alpha}/tree_view/tree_view_include_fragment_element.js +0 -1
  31. data/app/components/primer/{open_project → alpha}/tree_view/tree_view_include_fragment_element.ts +0 -1
  32. data/app/components/primer/{open_project → alpha}/tree_view/visual.rb +2 -2
  33. data/app/components/primer/{open_project → alpha}/tree_view.css +1 -1
  34. data/app/components/primer/{open_project → alpha}/tree_view.css.json +1 -3
  35. data/app/components/primer/alpha/tree_view.css.map +1 -0
  36. data/app/components/primer/{open_project → alpha}/tree_view.html.erb +1 -0
  37. data/app/components/primer/{open_project → alpha}/tree_view.pcss +6 -15
  38. data/app/components/primer/{open_project → alpha}/tree_view.rb +14 -11
  39. data/app/components/primer/beta/breadcrumbs.css +1 -1
  40. data/app/components/primer/beta/breadcrumbs.css.json +0 -1
  41. data/app/components/primer/beta/breadcrumbs.css.map +1 -1
  42. data/app/components/primer/beta/breadcrumbs.pcss +2 -8
  43. data/app/components/primer/beta/progress_bar.css +1 -1
  44. data/app/components/primer/beta/progress_bar.css.map +1 -1
  45. data/app/components/primer/beta/progress_bar.pcss +3 -2
  46. data/app/components/primer/beta/relative_time.rb +3 -0
  47. data/app/components/primer/open_project/filterable_tree_view/sub_tree.rb +1 -1
  48. data/app/components/primer/open_project/filterable_tree_view.d.ts +2 -2
  49. data/app/components/primer/open_project/filterable_tree_view.html.erb +1 -1
  50. data/app/components/primer/open_project/filterable_tree_view.js +2 -2
  51. data/app/components/primer/open_project/filterable_tree_view.rb +4 -4
  52. data/app/components/primer/open_project/filterable_tree_view.ts +2 -2
  53. data/app/components/primer/primer.d.ts +4 -4
  54. data/app/components/primer/primer.js +4 -4
  55. data/app/components/primer/primer.pcss +2 -2
  56. data/app/components/primer/primer.ts +4 -4
  57. data/app/controllers/primer/view_components/tree_view_items_controller.rb +1 -1
  58. data/app/forms/check_box_with_nested_form.rb +10 -10
  59. data/app/forms/radio_button_with_nested_form.rb +16 -16
  60. data/app/lib/primer/experimental_slot_helpers.rb +2 -2
  61. data/app/views/primer/view_components/tree_view_items/async_alpha.html_fragment.erb +1 -1
  62. data/app/views/primer/view_components/tree_view_items/index.html_fragment.erb +1 -1
  63. data/lib/primer/view_components/version.rb +1 -1
  64. data/previews/primer/{open_project → alpha}/file_tree_view_preview/default.html.erb +1 -1
  65. data/previews/primer/{open_project → alpha}/file_tree_view_preview/playground.html.erb +1 -1
  66. data/previews/primer/{open_project → alpha}/file_tree_view_preview.rb +1 -1
  67. data/previews/primer/{open_project → alpha}/skeleton_box_preview.rb +3 -3
  68. data/previews/primer/{open_project → alpha}/tree_view_preview/async_alpha.html.erb +1 -1
  69. data/previews/primer/{open_project → alpha}/tree_view_preview/buttons.html.erb +1 -1
  70. data/previews/primer/{open_project → alpha}/tree_view_preview/default.html.erb +2 -2
  71. data/previews/primer/{open_project → alpha}/tree_view_preview/empty.html.erb +1 -1
  72. data/previews/primer/alpha/tree_view_preview/form_input.html.erb +14 -0
  73. data/previews/primer/{open_project → alpha}/tree_view_preview/leaf_node_playground.html.erb +1 -1
  74. data/previews/primer/{open_project → alpha}/tree_view_preview/links.html.erb +1 -1
  75. data/previews/primer/{open_project → alpha}/tree_view_preview/loading_failure.html.erb +1 -1
  76. data/previews/primer/{open_project → alpha}/tree_view_preview/loading_skeleton.html.erb +1 -1
  77. data/previews/primer/{open_project → alpha}/tree_view_preview/loading_spinner.html.erb +1 -1
  78. data/previews/primer/{open_project → alpha}/tree_view_preview/playground.html.erb +1 -1
  79. data/previews/primer/{open_project → alpha}/tree_view_preview.rb +17 -8
  80. data/previews/primer/open_project/filterable_tree_view_preview/stress_test.html.erb +28 -0
  81. data/static/arguments.json +1560 -1542
  82. data/static/audited_at.json +17 -17
  83. data/static/classes.json +5 -5
  84. data/static/constants.json +101 -101
  85. data/static/info_arch.json +6203 -6170
  86. data/static/previews.json +34 -21
  87. data/static/statuses.json +17 -17
  88. metadata +86 -84
  89. data/app/components/primer/open_project/tree_view.css.map +0 -1
  90. /data/app/assets/javascripts/components/primer/{open_project → alpha}/tree_view/tree_view.d.ts +0 -0
  91. /data/app/assets/javascripts/components/primer/{open_project → alpha}/tree_view/tree_view_icon_pair_element.d.ts +0 -0
  92. /data/app/assets/javascripts/components/primer/{open_project → alpha}/tree_view/tree_view_include_fragment_element.d.ts +0 -0
  93. /data/app/assets/javascripts/components/primer/{open_project → alpha}/tree_view/tree_view_roving_tab_index.d.ts +0 -0
  94. /data/app/assets/javascripts/components/primer/{open_project → alpha}/tree_view/tree_view_sub_tree_node_element.d.ts +0 -0
  95. /data/app/components/primer/{open_project → alpha}/file_tree_view/directory_node.html.erb +0 -0
  96. /data/app/components/primer/{open_project → alpha}/file_tree_view/file_node.html.erb +0 -0
  97. /data/app/components/primer/{open_project → alpha}/skeleton_box.css +0 -0
  98. /data/app/components/primer/{open_project → alpha}/skeleton_box.html.erb +0 -0
  99. /data/app/components/primer/{open_project → alpha}/tree_view/icon.html.erb +0 -0
  100. /data/app/components/primer/{open_project → alpha}/tree_view/icon_pair.html.erb +0 -0
  101. /data/app/components/primer/{open_project → alpha}/tree_view/leading_action.html.erb +0 -0
  102. /data/app/components/primer/{open_project → alpha}/tree_view/leaf_node.html.erb +0 -0
  103. /data/app/components/primer/{open_project → alpha}/tree_view/loading_failure_message.html.erb +0 -0
  104. /data/app/components/primer/{open_project → alpha}/tree_view/node.html.erb +0 -0
  105. /data/app/components/primer/{open_project → alpha}/tree_view/sub_tree_container.html.erb +0 -0
  106. /data/app/components/primer/{open_project → alpha}/tree_view/sub_tree_node.html.erb +0 -0
  107. /data/app/components/primer/{open_project → alpha}/tree_view/tree_view.d.ts +0 -0
  108. /data/app/components/primer/{open_project → alpha}/tree_view/tree_view.js +0 -0
  109. /data/app/components/primer/{open_project → alpha}/tree_view/tree_view.ts +0 -0
  110. /data/app/components/primer/{open_project → alpha}/tree_view/tree_view_icon_pair_element.d.ts +0 -0
  111. /data/app/components/primer/{open_project → alpha}/tree_view/tree_view_icon_pair_element.js +0 -0
  112. /data/app/components/primer/{open_project → alpha}/tree_view/tree_view_icon_pair_element.ts +0 -0
  113. /data/app/components/primer/{open_project → alpha}/tree_view/tree_view_include_fragment_element.d.ts +0 -0
  114. /data/app/components/primer/{open_project → alpha}/tree_view/tree_view_roving_tab_index.d.ts +0 -0
  115. /data/app/components/primer/{open_project → alpha}/tree_view/tree_view_roving_tab_index.js +0 -0
  116. /data/app/components/primer/{open_project → alpha}/tree_view/tree_view_roving_tab_index.ts +0 -0
  117. /data/app/components/primer/{open_project → alpha}/tree_view/tree_view_sub_tree_node_element.d.ts +0 -0
  118. /data/app/components/primer/{open_project → alpha}/tree_view/tree_view_sub_tree_node_element.js +0 -0
  119. /data/app/components/primer/{open_project → alpha}/tree_view/tree_view_sub_tree_node_element.ts +0 -0
  120. /data/app/components/primer/{open_project → alpha}/tree_view/visual.html.erb +0 -0
@@ -1,19 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Primer
4
- module OpenProject
4
+ module Alpha
5
5
  # @label SkeletonBox
6
6
  class SkeletonBoxPreview < ViewComponent::Preview
7
7
  # @label Default
8
8
  def default
9
- render(Primer::OpenProject::SkeletonBox.new(width: "64px", height: "64px"))
9
+ render(Primer::Alpha::SkeletonBox.new(width: "64px", height: "64px"))
10
10
  end
11
11
 
12
12
  # @label Playground
13
13
  # @param width text
14
14
  # @param height text
15
15
  def playground(width: "64px", height: "64px")
16
- render(Primer::OpenProject::SkeletonBox.new(width: width, height: height))
16
+ render(Primer::Alpha::SkeletonBox.new(width: width, height: height))
17
17
  end
18
18
  end
19
19
  end
@@ -1,5 +1,5 @@
1
1
  <div style="max-width: 400px">
2
- <%= render(Primer::OpenProject::TreeView.new) do |tree_view| %>
2
+ <%= render(Primer::Alpha::TreeView.new) do |tree_view| %>
3
3
  <% tree_view.with_sub_tree(label: "primer") do |sub_tree| %>
4
4
  <% sub_tree.with_leading_visual_icons do |icons| %>
5
5
  <% icons.with_expanded_icon(icon: :"file-directory-open-fill", color: :accent) %>
@@ -1,5 +1,5 @@
1
1
  <div style="max-width: 400px">
2
- <%= render(Primer::OpenProject::TreeView.new(node_variant: :button)) do |tree_view| %>
2
+ <%= render(Primer::Alpha::TreeView.new(node_variant: :button)) do |tree_view| %>
3
3
  <% tree_view.with_sub_tree(label: "Secrets", expanded: expanded, onclick: "alert('Shhhh')", disabled: disabled) do |sub_tree| %>
4
4
  <% sub_tree.with_leaf(label: "Life and the universe", onclick: "alert(42)", disabled: disabled) %>
5
5
  <% sub_tree.with_leaf(label: "Secret ingredient", onclick: "alert('Love')", disabled: disabled) %>
@@ -1,5 +1,5 @@
1
1
  <div style="max-width: 400px">
2
- <%= render(Primer::OpenProject::TreeView.new) do |tree_view| %>
2
+ <%= render(Primer::Alpha::TreeView.new) do |tree_view| %>
3
3
  <% tree_view.with_sub_tree(label: "src", expanded: expanded, disabled: disabled, select_variant: select_variant, select_strategy: select_strategy) do |sub_tree| %>
4
4
  <% sub_tree.with_leading_visual_icons(label: "Foobar") do |icons| %>
5
5
  <% icons.with_expanded_icon(icon: :"file-directory-open-fill", color: :accent) %>
@@ -12,7 +12,7 @@
12
12
  <% item.with_leading_visual_icon(icon: :file) %>
13
13
  <% end %>
14
14
 
15
- <% sub_tree.with_leaf(label: "icon_button.rb", disabled: disabled, current: true, select_variant: select_variant) do |item| %>
15
+ <% sub_tree.with_leaf(label: "icon_button.rb", current: true, disabled: disabled, select_variant: select_variant) do |item| %>
16
16
  <% item.with_leading_visual_icon(icon: :file) %>
17
17
  <% end %>
18
18
  <% end %>
@@ -1,5 +1,5 @@
1
1
  <div style="max-width: 400px">
2
- <%= render(Primer::OpenProject::TreeView.new) do |tree_view| %>
2
+ <%= render(Primer::Alpha::TreeView.new) do |tree_view| %>
3
3
  <% tree_view.with_sub_tree(label: "src") do |sub_tree| %>
4
4
  <% sub_tree.with_leading_visual_icons do |icons| %>
5
5
  <% icons.with_expanded_icon(icon: :"file-directory-open-fill", color: :accent) %>
@@ -0,0 +1,14 @@
1
+ <%= form_with(url: primer_view_components.generic_form_submission_path(format: :json)) do |f| %>
2
+ <%= render(Primer::Alpha::Stack.new) do %>
3
+ <%= render(Primer::Alpha::TreeView.new(form_arguments: { builder: f, name: "folder_structure" })) do |tree| %>
4
+ <% tree.with_sub_tree(label: "src", expanded: expanded, select_variant: :multiple, value: 0) do |sub_tree| %>
5
+ <% sub_tree.with_leaf(label: "button.rb", select_variant: :multiple, value: 1) %>
6
+ <% sub_tree.with_leaf(label: "icon_button.rb", current: true, select_variant: :multiple, value: 2) %>
7
+ <% end %>
8
+
9
+ <% tree.with_leaf(label: "action_menu.rb", select_variant: :multiple, value: 3) %>
10
+ <% end %>
11
+
12
+ <%= render(Primer::Alpha::SubmitButton.new(name: :submit, label: "Submit")) %>
13
+ <% end %>
14
+ <% end %>
@@ -1,4 +1,4 @@
1
- <%= render(Primer::OpenProject::TreeView.new) do |tree| %>
1
+ <%= render(Primer::Alpha::TreeView.new) do |tree| %>
2
2
  <% tree.with_leaf(label: label, select_variant: select_variant, disabled: disabled) do |node| %>
3
3
  <% if leading_visual_icon && leading_visual_icon != :none %>
4
4
  <% node.with_leading_visual_icon(icon: leading_visual_icon) %>
@@ -1,5 +1,5 @@
1
1
  <div style="max-width: 400px">
2
- <%= render(Primer::OpenProject::TreeView.new(node_variant: :anchor)) do |tree_view| %>
2
+ <%= render(Primer::Alpha::TreeView.new(node_variant: :anchor)) do |tree_view| %>
3
3
  <% tree_view.with_sub_tree(label: "Cloud Services", href: "https://en.wikipedia.org/wiki/Cloud_computing", target: "blank", expanded: expanded, disabled: disabled) do |sub_tree| %>
4
4
  <% sub_tree.with_leaf(label: "OpenProject", href: "https://www.openproject.org", target: "blank", disabled: disabled) do |node| %>
5
5
  <% node.with_trailing_visual_icon(icon: :"link-external") %>
@@ -1,7 +1,7 @@
1
1
  <% subject_id = SecureRandom.hex %>
2
2
 
3
3
  <div style="max-width: 400px">
4
- <%= render(Primer::OpenProject::TreeView.new(data: { interaction_subject: subject_id })) do |tree_view| %>
4
+ <%= render(Primer::Alpha::TreeView.new(data: { interaction_subject: subject_id })) do |tree_view| %>
5
5
  <% tree_view.with_sub_tree(label: "primer") do |sub_tree| %>
6
6
  <% sub_tree.with_leading_visual_icons do |icons| %>
7
7
  <% icons.with_expanded_icon(icon: :"file-directory-open-fill", color: :accent) %>
@@ -1,5 +1,5 @@
1
1
  <div style="max-width: 400px">
2
- <%= render(Primer::OpenProject::TreeView.new) do |tree_view| %>
2
+ <%= render(Primer::Alpha::TreeView.new) do |tree_view| %>
3
3
  <% tree_view.with_sub_tree(label: "primer") do |sub_tree| %>
4
4
  <% sub_tree.with_leading_visual_icons do |icons| %>
5
5
  <% icons.with_expanded_icon(icon: :"file-directory-open-fill", color: :accent) %>
@@ -1,5 +1,5 @@
1
1
  <div style="max-width: 400px">
2
- <%= render(Primer::OpenProject::TreeView.new) do |tree_view| %>
2
+ <%= render(Primer::Alpha::TreeView.new) do |tree_view| %>
3
3
  <% tree_view.with_sub_tree(label: "primer") do |sub_tree| %>
4
4
  <% sub_tree.with_leading_visual_icons do |icons| %>
5
5
  <% icons.with_expanded_icon(icon: :"file-directory-open-fill", color: :accent) %>
@@ -1,4 +1,4 @@
1
1
  <% data = Primer::ViewComponents::TreeViewItemsController::TREE %>
2
- <%= render(Primer::OpenProject::TreeView.new) do |tree| %>
2
+ <%= render(Primer::Alpha::TreeView.new) do |tree| %>
3
3
  <% populate.call(tree, data, { select_variant: select_variant, select_strategy: select_strategy, expanded: expanded }) %>
4
4
  <% end %>
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Primer
4
- module OpenProject
4
+ module Alpha
5
5
  # @label TreeView
6
6
  class TreeViewPreview < ViewComponent::Preview
7
7
  # @label Default
@@ -14,8 +14,8 @@ module Primer
14
14
  def default(
15
15
  expanded: false,
16
16
  disabled: false,
17
- select_variant: Primer::OpenProject::TreeView::Node::DEFAULT_SELECT_VARIANT,
18
- select_strategy: Primer::OpenProject::TreeView::SubTreeNode::DEFAULT_SELECT_STRATEGY
17
+ select_variant: Primer::Alpha::TreeView::Node::DEFAULT_SELECT_VARIANT,
18
+ select_strategy: Primer::Alpha::TreeView::SubTreeNode::DEFAULT_SELECT_STRATEGY
19
19
  )
20
20
  render_with_template(locals: {
21
21
  expanded: coerce_bool(expanded),
@@ -32,8 +32,8 @@ module Primer
32
32
  # @param select_strategy [Symbol] select [self, descendants, mixed_descendants]
33
33
  def playground(
34
34
  expanded: false,
35
- select_variant: Primer::OpenProject::TreeView::Node::DEFAULT_SELECT_VARIANT,
36
- select_strategy: Primer::OpenProject::TreeView::SubTreeNode::DEFAULT_SELECT_STRATEGY
35
+ select_variant: Primer::Alpha::TreeView::Node::DEFAULT_SELECT_VARIANT,
36
+ select_strategy: Primer::Alpha::TreeView::SubTreeNode::DEFAULT_SELECT_STRATEGY
37
37
  )
38
38
  render_with_template(locals: {
39
39
  expanded: coerce_bool(expanded),
@@ -101,7 +101,7 @@ module Primer
101
101
  leading_visual_icon: nil,
102
102
  leading_action_icon: nil,
103
103
  trailing_visual_icon: nil,
104
- select_variant: Primer::OpenProject::TreeView::Node::DEFAULT_SELECT_VARIANT,
104
+ select_variant: Primer::Alpha::TreeView::Node::DEFAULT_SELECT_VARIANT,
105
105
  disabled: false
106
106
  )
107
107
  render_with_template(locals: {
@@ -139,7 +139,7 @@ module Primer
139
139
  # @label Auto expansion
140
140
  #
141
141
  def auto_expansion
142
- render(Primer::OpenProject::TreeView.new) do |tree|
142
+ render(Primer::Alpha::TreeView.new) do |tree|
143
143
  tree.with_sub_tree(label: "Level 1") do |level1|
144
144
  level1.with_sub_tree(label: "Level 2") do |level2|
145
145
  # marking this node as expanded should automatically expand all ancestors
@@ -151,6 +151,15 @@ module Primer
151
151
  end
152
152
  end
153
153
 
154
+ # @label Form input
155
+ #
156
+ # @param expanded [Boolean] toggle
157
+ def form_input(expanded: true)
158
+ render_with_template(locals: {
159
+ expanded: coerce_bool(expanded)
160
+ })
161
+ end
162
+
154
163
  private
155
164
 
156
165
  def coerce_bool(value)
@@ -171,7 +180,7 @@ module Primer
171
180
 
172
181
  entries = (
173
182
  data.fetch("children", {}).keys.map { |label, idx| [label, :directory] } +
174
- data.fetch("files", []).map { |label| [label, :file] }
183
+ data.fetch("files", []).map { |label| [label, :file] }
175
184
  )
176
185
 
177
186
  entries.sort_by!(&:first)
@@ -0,0 +1,28 @@
1
+ <%= render(Primer::OpenProject::FilterableTreeView.new) do |tree| %>
2
+ <% (1..500).each do %>
3
+ <% tree.with_sub_tree(label: "Students", expanded: expanded) do |hogwarts| %>
4
+ <% hogwarts.with_sub_tree(label: "Ravenclaw", expanded: expanded) do |ravenclaw| %>
5
+ <% ravenclaw.with_leaf(label: "Luna Lovegood") %>
6
+ <% end %>
7
+
8
+ <% hogwarts.with_sub_tree(label: "Slytherin", expanded: expanded) do |hufflepuff| %>
9
+ <% hufflepuff.with_leaf(label: "Draco Malfoy") %>
10
+ <% end %>
11
+
12
+ <% hogwarts.with_sub_tree(label: "Hufflepuff", expanded: expanded) do |hufflepuff| %>
13
+ <% hufflepuff.with_leaf(label: "Susan Bones") %>
14
+ <% end %>
15
+
16
+ <% hogwarts.with_sub_tree(label: "Gryffindor", expanded: expanded) do |hufflepuff| %>
17
+ <% hufflepuff.with_leaf(label: "Harry Potter") %>
18
+ <% hufflepuff.with_leaf(label: "Ronald Weasley") %>
19
+ <% hufflepuff.with_leaf(label: "Hermione Granger") %>
20
+ <% end %>
21
+ <% end %>
22
+
23
+ <% tree.with_leaf(label: "Albus Dumbledore") %>
24
+ <% tree.with_leaf(label: "Minerva McGonagall") %>
25
+ <% tree.with_leaf(label: "Severus Snape") %>
26
+ <% tree.with_leaf(label: "Rubeus Hagrid") %>
27
+ <% end %>
28
+ <% end %>