headmin 0.2.2 → 0.2.6

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 (81) hide show
  1. checksums.yaml +4 -4
  2. data/.nvmrc +1 -1
  3. data/Gemfile.lock +3 -3
  4. data/README.md +17 -7
  5. data/app/helpers/headmin/admin_helper.rb +3 -59
  6. data/app/helpers/headmin/bootstrap_helper.rb +9 -0
  7. data/app/helpers/headmin/filter_helper.rb +7 -3
  8. data/app/helpers/headmin/form_helper.rb +36 -0
  9. data/app/helpers/headmin/request_helper.rb +39 -0
  10. data/app/models/concerns/headmin/fieldable.rb +53 -23
  11. data/app/services/block_service.rb +8 -4
  12. data/app/views/headmin/_blocks.html.erb +1 -1
  13. data/app/views/headmin/_filters.html.erb +1 -1
  14. data/app/views/headmin/_pagination.html.erb +4 -1
  15. data/app/views/headmin/dropdown/_devise.html.erb +20 -10
  16. data/app/views/headmin/dropdown/_list.html.erb +17 -7
  17. data/app/views/headmin/filters/_select.html.erb +3 -2
  18. data/app/views/headmin/filters/filter/_button.html.erb +0 -1
  19. data/app/views/headmin/forms/_blocks.html.erb +11 -4
  20. data/app/views/headmin/forms/_date.html.erb +1 -1
  21. data/app/views/headmin/forms/_label.html.erb +2 -2
  22. data/app/views/headmin/forms/_repeater.html.erb +6 -10
  23. data/app/views/headmin/table/_actions.html.erb +37 -11
  24. data/app/views/headmin/views/devise/confirmations/_new.html.erb +1 -1
  25. data/app/views/headmin/views/devise/passwords/_edit.html.erb +2 -2
  26. data/app/views/headmin/views/devise/passwords/_new.html.erb +1 -1
  27. data/app/views/headmin/views/devise/registrations/_edit.html.erb +4 -4
  28. data/app/views/headmin/views/devise/registrations/_new.html.erb +3 -3
  29. data/app/views/headmin/views/devise/shared/_links.html.erb +7 -7
  30. data/app/views/headmin/views/devise/unlocks/_new.html.erb +1 -1
  31. data/config/locales/activerecord/en.yml +9 -0
  32. data/config/locales/activerecord/nl.yml +9 -0
  33. data/config/locales/headmin/table/en.yml +5 -1
  34. data/config/locales/headmin/table/nl.yml +5 -1
  35. data/config/locales/headmin/views/en.yml +1 -1
  36. data/config/locales/headmin/views/nl.yml +14 -14
  37. data/dist/css/headmin.css +54 -13
  38. data/dist/js/headmin.js +45 -513
  39. data/docs/blocks-and-fields.md +54 -0
  40. data/docs/blocks.md +1 -54
  41. data/docs/devise.md +40 -2
  42. data/docs/fields.md +31 -9
  43. data/headmin.gemspec +1 -1
  44. data/lib/generators/headmin/blocks_generator.rb +4 -1
  45. data/lib/generators/headmin/devise_generator.rb +16 -0
  46. data/lib/generators/headmin/fields_generator.rb +5 -1
  47. data/lib/generators/templates/controllers/auth/confirmations_controller.rb +31 -0
  48. data/lib/generators/templates/controllers/auth/omniauth_callbacks_controller.rb +31 -0
  49. data/lib/generators/templates/controllers/auth/passwords_controller.rb +35 -0
  50. data/lib/generators/templates/controllers/auth/registrations_controller.rb +63 -0
  51. data/lib/generators/templates/controllers/auth/sessions_controller.rb +28 -0
  52. data/lib/generators/templates/controllers/auth/unlocks_controller.rb +31 -0
  53. data/lib/generators/templates/migrations/create_field_hierarchies.rb +16 -0
  54. data/lib/generators/templates/views/auth/confirmations/new.html.erb +1 -0
  55. data/lib/generators/templates/views/auth/mailer/confirmation_instructions.html.erb +1 -0
  56. data/lib/generators/templates/views/auth/mailer/email_changed.html.erb +1 -0
  57. data/lib/generators/templates/views/auth/mailer/password_change.html.erb +1 -0
  58. data/lib/generators/templates/views/auth/mailer/reset_password_instructions.html.erb +1 -0
  59. data/lib/generators/templates/views/auth/mailer/unlock_instructions.html.erb +1 -0
  60. data/lib/generators/templates/views/auth/passwords/edit.html.erb +1 -0
  61. data/lib/generators/templates/views/auth/passwords/new.html.erb +1 -0
  62. data/lib/generators/templates/views/auth/registrations/edit.html.erb +1 -0
  63. data/lib/generators/templates/views/auth/registrations/new.html.erb +1 -0
  64. data/lib/generators/templates/views/auth/sessions/new.html.erb +1 -0
  65. data/lib/generators/templates/views/auth/unlocks/new.html.erb +1 -0
  66. data/lib/generators/templates/views/layouts/auth.html.erb +20 -0
  67. data/lib/headmin/engine.rb +2 -0
  68. data/lib/headmin/version.rb +1 -1
  69. data/package.json +4 -3
  70. data/src/js/headmin/controllers/blocks_controller.js +1 -1
  71. data/src/js/headmin/controllers/filter_controller.js +1 -1
  72. data/src/js/headmin/controllers/filters_controller.js +1 -1
  73. data/src/js/headmin/controllers/popup_controller.js +1 -1
  74. data/src/js/headmin/controllers/repeater_controller.js +9 -10
  75. data/src/js/headmin/controllers/table_actions_controller.js +104 -9
  76. data/src/js/headmin/controllers/table_controller.js +28 -57
  77. data/src/js/headmin/headmin.js +2 -2
  78. data/src/scss/headmin/table.scss +1 -0
  79. data/yarn.lock +1159 -1237
  80. metadata +33 -7
  81. data/docs/README.md +0 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5b4489879289d2643f3045d91f28b3530f3c21e5a888246ceb36029106ea0692
4
- data.tar.gz: 0e161c13ca9f3fd26f96401eefea905cd3858d0c3b3dfe86cd8ce4bda718d8f8
3
+ metadata.gz: 1ff0537188eb3c41240a97c8660f5c1cdd891615495eef10b1b86c66857170c9
4
+ data.tar.gz: 7add1ca43dd66063a4f1283f6817bbedf0ff9a666a04143a283929f92830da2a
5
5
  SHA512:
6
- metadata.gz: 78d063e6e740edba6d1a849e1bacbff2a8750300848c20134b3e15bc5217b216e53a15be5d923de6671aecf768ce98c41cffa31bbd8939abd42e6a12ee877c7f
7
- data.tar.gz: c515db4260d09f9a402d8b46d7d8b36acc10a3dbad433248a19716c5b3b59459ee965dfc8a862d8a35137b58aa4b8af734a6ef73a094b425a9f6ee81140a7261
6
+ metadata.gz: cd060f8b895ff9bd71f26c91bd152d2b3ed7eac3a59a09cf6afaf9473764a363ab81134f6aac656b84d698a17601bbd84a9d4e26143c6e8562c3be65ab4597af
7
+ data.tar.gz: 6192291a6b45d1341ef1ba85b97280e55c59a31550a112202bb304d4945024c9f151dfdd394542933c7a8bb4baae616b5c45c93b3fb9179deb924116d2af84cc
data/.nvmrc CHANGED
@@ -1 +1 @@
1
- lts/*
1
+ lts/gallium
data/Gemfile.lock CHANGED
@@ -1,8 +1,8 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- headmin (0.2.1)
5
- closure_tree (~> 7.3)
4
+ headmin (0.2.5)
5
+ closure_tree
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
@@ -23,7 +23,7 @@ GEM
23
23
  activerecord (>= 4.2.10)
24
24
  with_advisory_lock (>= 4.0.0)
25
25
  concurrent-ruby (1.1.9)
26
- i18n (1.8.10)
26
+ i18n (1.8.11)
27
27
  concurrent-ruby (~> 1.0)
28
28
  minitest (5.14.4)
29
29
  parallel (1.20.1)
data/README.md CHANGED
@@ -1,10 +1,8 @@
1
1
  # Headmin
2
2
  A complete library of commonly used components to build an admin interface in your Ruby on Rails project.
3
3
 
4
- ## Interesting links
5
- - [Full documentation](docs/README.md)
6
- - [Rubygems](https://rubygems.org/gems/headmin)
7
- - [NPM](https://www.npmjs.com/package/headmin)
4
+ [![Gem Version](https://badge.fury.io/rb/headmin.svg)](https://rubygems.org/gems/headmin)
5
+ [![npm version](https://badge.fury.io/js/headmin.svg)](https://www.npmjs.com/package/headmin)
8
6
 
9
7
  ## Installation
10
8
 
@@ -47,6 +45,12 @@ Finally import Headmin in your stylesheet.
47
45
  @import '~headmin/src/scss/headmin.scss';
48
46
  ```
49
47
 
48
+ ### Integrations
49
+ - [Blocks](docs/blocks.md)
50
+ - [Fields](docs/fields.md)
51
+ - [Blocks + Fields = Magic](docs/blocks-and-fields.md)
52
+ - [Devise](docs/devise.md)
53
+
50
54
  ## Development
51
55
  For development purposes it's helpful to have both the test project and Headmin located in the same directory.
52
56
 
@@ -59,7 +63,7 @@ In package.json
59
63
  ```json
60
64
  {
61
65
  "dependencies": {
62
- "bar": "link:../headmin"
66
+ "bar": "file:../headmin"
63
67
  }
64
68
  }
65
69
  ```
@@ -94,8 +98,14 @@ $ yarn build
94
98
  Update the version number of the gem
95
99
 
96
100
  ```shell
97
- $ gem bump -v {patch,minor,major,...} -p
98
- $ gem tag -p
101
+ # First bundle if new runtime dependencies were added
102
+ $ bundle
103
+ $ git push
104
+
105
+ # Update the version number and tag the release
106
+ $ gem bump -v {patch,minor,major,...} --push --tag
107
+
108
+ # Release to Rubygems
99
109
  $ gem release
100
110
  ```
101
111
 
@@ -1,65 +1,9 @@
1
1
  module Headmin
2
2
  module AdminHelper
3
+ include Headmin::BootstrapHelper
3
4
  include Headmin::FilterHelper
5
+ include Headmin::FormHelper
4
6
  include Headmin::NotificationHelper
5
-
6
- def current_model
7
- controller_name.classify.constantize
8
- end
9
-
10
- def bootstrap_icon(icon, options = {})
11
- data = options.has_key?(:data) ? options[:data] : nil
12
- klass = options.has_key?(:class) ? options[:class] : nil
13
- content_tag(:i, class: "bi bi-#{icon} #{klass}", data: data) {}
14
- end
15
-
16
- def current_url?(url)
17
- uri = URI(url)
18
- path = uri.path
19
- query_string = uri.query
20
- matches_path = request.path.include?(path)
21
- matches_query = uri.query ? request.query_string.include?(query_string) : true
22
- is_root = request.fullpath == url
23
- if url == admin_root_path
24
- is_root
25
- else
26
- matches_path && matches_query
27
- end
28
- end
29
-
30
- def form_field_valid?(form, name)
31
- !form.object.errors.has_key?(name)
32
- end
33
-
34
- def form_field_validation_id(form, name)
35
- [form.object_name, name.to_s, 'validation'].join('_').parameterize.underscore
36
- end
37
-
38
- def form_field_validation_class(form, name)
39
- return nil if request.get?
40
- form.object.errors.has_key?(name) ? 'is-invalid' : 'is-valid'
41
- end
42
-
43
- def default_params
44
- params.select { |key, value| is_default_param?(key) }
45
- end
46
-
47
- def add_default_param_key(key)
48
- keys = default_param_keys || []
49
- keys.push(key)
50
- @default_param_keys = keys
51
- end
52
-
53
- def default_param_keys
54
- @default_param_keys ||= [:page, :start, :length, :per_page]
55
- end
56
-
57
- def is_default_param?(key)
58
- default_param_keys.include?(key.to_sym) || is_sort_param_key?(key)
59
- end
60
-
61
- def is_sort_param_key?(key)
62
- key.to_s.include?('sort_')
63
- end
7
+ include Headmin::RequestHelper
64
8
  end
65
9
  end
@@ -0,0 +1,9 @@
1
+ module Headmin
2
+ module BootstrapHelper
3
+ def bootstrap_icon(icon, options = {})
4
+ data = options.has_key?(:data) ? options[:data] : nil
5
+ klass = options.has_key?(:class) ? options[:class] : nil
6
+ content_tag(:i, class: "bi bi-#{icon} #{klass}", data: data) {}
7
+ end
8
+ end
9
+ end
@@ -1,11 +1,15 @@
1
1
  module Headmin
2
2
  module FilterHelper
3
3
  def filter_param_exists?(name)
4
- return false unless params.has_key?(name)
4
+ filter_param(name).present?
5
+ end
6
+
7
+ def filter_param(name)
8
+ return nil unless params.has_key?(name)
5
9
  if params[name].is_a?(Array)
6
- params[name].reject { |c| c.empty? }.present?
10
+ params[name].reject { |c| c.empty? }
7
11
  else
8
- params[name].present?
12
+ params[name]
9
13
  end
10
14
  end
11
15
  end
@@ -0,0 +1,36 @@
1
+ module Headmin
2
+ module FormHelper
3
+ def form_field_valid?(form, name)
4
+ !form.object.errors.has_key?(name)
5
+ end
6
+
7
+ def form_field_validation_id(form, name)
8
+ [form.object_name, name.to_s, 'validation'].join('_').parameterize.underscore
9
+ end
10
+
11
+ def form_field_validation_class(form, name)
12
+ return nil if request.get?
13
+ form.object.errors.has_key?(name) ? 'is-invalid' : 'is-valid'
14
+ end
15
+
16
+ # Outputs currently present query parameters as hidden fields for a given form
17
+ #
18
+ # https://example.com/products?amount=1&type[]=food&type[]=beverage
19
+ #
20
+ # <%= form.hidden_input :amount, value: 1 %>
21
+ # <%= form.hidden_input :'type[]', value: 'food' %>
22
+ # <%= form.hidden_input :'type[]', value: 'beverage' %>
23
+ def query_parameter_fields(form)
24
+ test = request.query_parameters.map do |name, value|
25
+ if value.is_a?(Array)
26
+ value.map do |value_element|
27
+ form.hidden_field "#{name}[]", value: value_element
28
+ end.join
29
+ else
30
+ form.hidden_field name, value: value
31
+ end
32
+ end
33
+ test.join.html_safe
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,39 @@
1
+ module Headmin
2
+ module RequestHelper
3
+ def current_url?(url)
4
+ uri = URI(url)
5
+ path = uri.path
6
+ query_string = uri.query
7
+ matches_path = request.path.include?(path)
8
+ matches_query = uri.query ? request.query_string.include?(query_string) : true
9
+ is_root = request.fullpath == url
10
+ if url == admin_root_path
11
+ is_root
12
+ else
13
+ matches_path && matches_query
14
+ end
15
+ end
16
+
17
+ def default_params
18
+ params.select { |key, value| is_default_param?(key) }
19
+ end
20
+
21
+ def add_default_param_key(key)
22
+ keys = default_param_keys || []
23
+ keys.push(key)
24
+ @default_param_keys = keys
25
+ end
26
+
27
+ def default_param_keys
28
+ @default_param_keys ||= [:page, :start, :length, :per_page]
29
+ end
30
+
31
+ def is_default_param?(key)
32
+ default_param_keys.include?(key.to_sym) || is_sort_param_key?(key)
33
+ end
34
+
35
+ def is_sort_param_key?(key)
36
+ key.to_s.include?('sort_')
37
+ end
38
+ end
39
+ end
@@ -7,37 +7,67 @@ module Headmin
7
7
  accepts_nested_attributes_for :fields, allow_destroy: true
8
8
 
9
9
  def fields_hash
10
- save_pair(fields.hash_tree)
10
+ fields.order(position: :asc).map do |field|
11
+ parse_hash_tree(field.hash_tree)
12
+ end.reduce({}, :merge)
13
+ end
14
+
15
+ def fields_hash=(hash)
16
+ parse_fields_hash(hash)
11
17
  end
12
18
 
13
19
  private
14
20
 
15
- def save_pair(my_hash, array = false)
16
- if array
17
- my_hash.map { |key, value|
18
- save_pair(value)
19
- }
20
- else
21
- Hash[my_hash.map { |key, value|
22
- if value.empty?
23
- case key.field_type
24
- when 'group'
25
- [key.name, save_pair(key.hash_tree[key])]
26
- when 'list'
27
- [key.name, save_pair(key.hash_tree[key], true)]
28
- else
29
- [key.name, return_field_output(key)]
21
+ def parse_fields_hash(hash)
22
+ hash.map do |key, value|
23
+ case value
24
+ when Hash
25
+ fields.build(
26
+ name: key,
27
+ field_type: 'group',
28
+ fields: parse_fields_hash(value)
29
+ )
30
+ when Array
31
+ fields.build(
32
+ name: key,
33
+ field_type: 'list',
34
+ fields: value.map do |item|
35
+ fields.new(name: 'item', field_type: 'group', fields: parse_fields_hash(item))
30
36
  end
31
- else
32
- key.field_type == 'list' ? [key.name, save_pair(value, true)] : [key.name, save_pair(value)]
33
- end
34
- }]
37
+ )
38
+ when String
39
+ fields.build(
40
+ name: key,
41
+ field_type: 'text',
42
+ value: value
43
+ )
44
+ else
45
+ fields.build(
46
+ name: key,
47
+ field_type: 'file',
48
+ file: value
49
+ )
50
+ end
35
51
  end
36
52
  end
37
53
 
38
- # returns what a field_type should return, e.g. its value, the file, the object ...
39
- def return_field_output(key)
40
- key.field_type == 'image' ? key.file : key.value
54
+ def parse_hash_tree(hash_tree)
55
+ Hash[hash_tree.map do |field, children|
56
+ case field.field_type.to_sym
57
+ when :group
58
+ children = children.any? ? children : field.hash_tree
59
+ [field.name, parse_hash_tree(children)]
60
+ when :list
61
+ children = children.any? ? children : field.hash_tree
62
+ [field.name, children.map { |child, grand_children| parse_hash_tree(grand_children) }]
63
+ when :image
64
+ [field.name, field.file]
65
+ when :file
66
+ [field.name, field.file]
67
+ else
68
+ [field.name, field.value]
69
+ end
70
+ end]
41
71
  end
42
72
  end
43
73
  end
@@ -1,10 +1,7 @@
1
1
  class BlockService
2
2
  def self.block_names(path:)
3
3
  form_views(path: path).map do |view|
4
- filename = File.basename(view, '.html.erb')
5
-
6
- # Removes leading _ if exists
7
- filename.sub!(/^_/, '')
4
+ view_name(view)
8
5
  end
9
6
  end
10
7
 
@@ -24,6 +21,13 @@ class BlockService
24
21
  views(form_view_paths(path))
25
22
  end
26
23
 
24
+ def self.view_name(view)
25
+ filename = File.basename(view, '.html.erb')
26
+
27
+ # Removes leading _ if exists
28
+ filename.sub(/^_/, '')
29
+ end
30
+
27
31
  private
28
32
 
29
33
  # Looks for a block view by its name.
@@ -18,7 +18,7 @@
18
18
 
19
19
  <% if blockable && blockable.respond_to?(:blocks) %>
20
20
  <% blockable.blocks.order(:position).each do |block| %>
21
- <% view_path = BlockService.frontend_view(block.name, path: path).gsub('/_', '/') %>
21
+ <% view_path = BlockService.frontend_view(block.name, path: path).gsub('/_', '/').split('.').first %>
22
22
  <%= render view_path, block: block %>
23
23
  <% end %>
24
24
  <% end %>
@@ -11,7 +11,7 @@
11
11
  # With custom URL
12
12
  # <%= render "headmin/filters", url: admin_polls_path %#>
13
13
 
14
- action = local_assigns.has_key?(:url) ? url : request.url
14
+ action = local_assigns.has_key?(:url) ? url : request.path
15
15
  %>
16
16
 
17
17
  <form action="<%= action %>" data-controller="filters" data-filters-target="form">
@@ -10,8 +10,11 @@
10
10
  %>
11
11
 
12
12
  <div class="d-flex flex-row-reverse flex-md-row align-items-center justify-content-between justify-content-md-end my-1">
13
+ <% content_for :collection_total_count do %>
14
+ <%= collection.total_count %>
15
+ <% end %>
13
16
  <div class="ms-2 me-md-2 text-secondary">
14
- <%= t('.items', count: collection.total_count) %>
17
+ <%= t('.items', count: content_for(:collection_total_count)) %>
15
18
  </div>
16
19
  <%= paginate collection, views_prefix: 'headmin/pagination' %>
17
20
  </div>
@@ -1,19 +1,29 @@
1
- <%#
2
- headmin/dropdown/locale
3
- accepts block: yes
4
- parameters:
5
- scope: (symbol) devise scope, i.e. ':users' => current_user
1
+ <%
2
+ # headmin/dropdown/devise
3
+ #
4
+ # ==== Options
5
+ # * <tt>scope</tt> - (symbol) devise scope, i.e. ':users' => current_user
6
+ # * <tt>class</tt> - Custom class names to put on the dropdown
7
+ #
8
+ # ==== Examples
9
+ # Basic version
10
+ # <%= render "headmin/dropdown/devise" %#>
11
+ #
12
+ # Custom scope
13
+ # <%= render "headmin/dropdown/devise", scope: :admins %#>
14
+
15
+ class_names = local_assigns.has_key?(:class) ? local_assigns[:class] : ''
16
+ scope = local_assigns.has_key?(:scope) ? scope : :users
17
+ singular = scope.to_s.singularize.to_sym
18
+ user = send("current_#{singular}")
6
19
  %>
7
20
 
8
- <% scope = local_assigns.has_key?(:scope) ? scope : :users %>
9
- <% singular = scope.to_s.singularize.to_sym %>
10
- <% user = send("current_#{singular}") %>
11
21
 
12
- <%= render 'headmin/dropdown' do %>
22
+ <%= render 'headmin/dropdown', class: class_names do %>
13
23
  <%= render 'headmin/dropdown/button' do %>
14
24
  <%= user.to_s %>
15
25
  <% end %>
16
- <%= render 'headmin/dropdown/list' do %>
26
+ <%= render 'headmin/dropdown/list', class: 'dropdown-menu-end' do %>
17
27
  <%= render 'headmin/dropdown/item', name: t('.edit_profile'), url: polymorphic_path([:edit, singular, :registration]) %>
18
28
  <%= render 'headmin/dropdown/divider' %>
19
29
  <%= render 'headmin/dropdown/item', name: t('.log_out'), url: polymorphic_path([:destroy, singular, :session]), method: :delete %>
@@ -1,11 +1,21 @@
1
- <%#
2
- headmin/dropdown/list
3
- accepts block: yes
4
- parameters:
5
- id: unique identifier for the dropdown
1
+ <%
2
+ # headmin/dropdown/list
3
+ #
4
+ # ==== Options
5
+ # * <tt>id</tt> - unique identifier for the dropdown
6
+ # * <tt>class</tt> - Custom class names to put on the dropdown menu
7
+ #
8
+ # ==== Examples
9
+ # Basic version
10
+ # <%= render "headmin/dropdown/devise" %#>
11
+ #
12
+ # Custom scope
13
+ # <%= render "headmin/dropdown/devise", scope: :admins %#>
14
+
15
+ class_names = local_assigns.has_key?(:class) ? local_assigns[:class] : ''
16
+ id = local_assigns.has_key?(:id) ? id : 'dropdown-1'
6
17
  %>
7
- <% id = local_assigns.has_key?(:id) ? id : 'dropdown-1' %>
8
18
 
9
- <ul class="dropdown-menu" aria-labelledby="<%= id %>">
19
+ <ul class="dropdown-menu <%= class_names %>" aria-labelledby="<%= id %>">
10
20
  <%= yield %>
11
21
  </ul>
@@ -36,8 +36,9 @@
36
36
 
37
37
  <%= content_for :filters_buttons do %>
38
38
  <% (params[name] || []).each_with_index do |param, index| %>
39
- <% value = options.detect { |value, key, config| key == param } %>
40
- <%= render 'headmin/filters/filter/button', name: name, label: label, value: value ? value.first : nil, id: "#{name}_#{index}" do %>
39
+ <% selected_option = options.detect { |value, key, config| (key.present? ? key : value) == param } %>
40
+ <% selected_value = selected_option.is_a?(Array) ? selected_option.first : selected_option %>
41
+ <%= render 'headmin/filters/filter/button', name: name, label: label, value: selected_value, id: "#{name}_#{index}" do %>
41
42
  <%= select_tag("#{name}[]", options_for_select(options, param), select_options) %>
42
43
  <% end %>
43
44
  <% end %>
@@ -12,7 +12,6 @@
12
12
  <% value = local_assigns.has_key?(:value) ? value : nil %>
13
13
 
14
14
  <div class="h-filter me-1 my-1" data-filter-name="<%= name %>">
15
-
16
15
  <button
17
16
  type="button"
18
17
  class="h-filter-button btn h-btn-outline-transparent"
@@ -22,11 +22,18 @@
22
22
  templates = allowed_block_names.map { |name| BlockService.form_view(name, path: path) }
23
23
  %>
24
24
 
25
- <%= render 'headmin/forms/repeater', form: form, attribute: :blocks, templates: templates, label: false do |block| %>
26
- <% view_path = BlockService.form_view(block.object.name, path: path).gsub('/_', '/') %>
27
- <%= render view_path, form: block, name: block.object.name %>
25
+ <%= render 'headmin/forms/repeater', form: form, attribute: :blocks, templates: templates, label: false do |block_form, template| %>
26
+ <% name = template ? BlockService.view_name(template) : block_form.object.name %>
28
27
 
28
+ <!-- Name input of the block -->
29
+ <%= block_form.hidden_field :name, value: name %>
30
+
31
+ <!-- Render block form fields -->
32
+ <% view_path = BlockService.form_view(name, path: path).gsub('/_', '/') %>
33
+ <%= render view_path, form: block_form %>
34
+
35
+ <!-- Label -->
29
36
  <span class="position-absolute top-0 end-0 badge bg-light text-dark">
30
- <%= block.object.name.titleize %>
37
+ <%= name.titleize %>
31
38
  </span>
32
39
  <% end %>
@@ -27,7 +27,7 @@
27
27
  required = local_assigns.has_key?(:required) ? required : false
28
28
  datepicker = local_assigns.has_key?(:datepicker) ? local_assigns[:datepicker] : false
29
29
 
30
- class_names = "#{class_names} flatpicker" if datepicker
30
+ class_names = "#{class_names} flatpickr" if datepicker
31
31
 
32
32
  options = {
33
33
  'aria-describedby': form_field_validation_id(form, attribute),
@@ -12,7 +12,7 @@
12
12
  # <%= render 'headmin/forms/label', form: form, attribute: :image %#>
13
13
 
14
14
  class_names = local_assigns.has_key?(:class) ? local_assigns[:class] : false
15
- name = local_assigns.has_key?(:name) && name ? name.to_s.humanize : attribute
15
+ custom_name = local_assigns.has_key?(:name) && name ? name.to_s.humanize : nil
16
16
  required = local_assigns.has_key?(:required) ? required : false
17
17
 
18
18
  options = {
@@ -21,4 +21,4 @@
21
21
  }
22
22
  %>
23
23
 
24
- <%= form.label name, options %>
24
+ <%= form.label attribute, custom_name, options %>
@@ -39,14 +39,14 @@
39
39
 
40
40
  template_names = templates.map { |template| File.basename(template, '.html.erb') }
41
41
  template_names = template_names.any? ? template_names : ['new']
42
- multiple_templates = template_names.count > 1
43
42
  object_model = form.object.class
44
43
  association_model = object_model.reflect_on_association(attribute).class_name.constantize
45
- with_positions = association_model.new.attributes.keys.include?('position')
44
+ association_object = association_model.new
45
+ with_positions = association_object.attributes.keys.include?('position')
46
46
  associations = form.object.send(attribute)
47
47
  associations = with_positions ? associations.order(:position) : associations
48
48
  repeater_id = form.object_id
49
- pass_thru = multiple_templates ? nil : '[data-template-name="new"]'
49
+ pass_thru = template_names.count == 1 ? "[data-template-name=\"#{template_names.first}\"]" : nil
50
50
  show_label = label != false
51
51
  %>
52
52
 
@@ -115,15 +115,11 @@
115
115
 
116
116
  <!-- Templates -->
117
117
  <% template_names.each do |name| %>
118
- <template data-repeater-target="template" data-template-name="<%= name %>">
119
- <%= form.fields_for attribute, association_model.new, child_index: 'template_id' do |ff| %>
118
+ <template data-repeater-target="template" data-template-name="<%= name %>" data-template-id-regex="<%= association_object.object_id %>">
119
+ <%= form.fields_for attribute, association_object, child_index: association_object.object_id do |ff| %>
120
120
  <%= render 'headmin/forms/repeater/row', form: ff, pass_thru: pass_thru, repeater_id: repeater_id do %>
121
121
  <% template = templates.detect { |t| t.include?("/#{name}.") } %>
122
- <% if template %>
123
- <%= render(template.gsub('/_', '/'), form: ff) %>
124
- <% else %>
125
- <% yield(ff) %>
126
- <% end %>
122
+ <% yield(ff, template&.gsub('/_', '/')) %>
127
123
  <% end %>
128
124
  <% end %>
129
125
  </template>