jav_madmin 2.6.6 → 3.3.1

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 (86) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +89 -4
  3. data/app/assets/stylesheets/madmin/actiontext.css +31 -0
  4. data/app/assets/stylesheets/madmin/base.css +22 -11
  5. data/app/assets/stylesheets/madmin/buttons.css +9 -9
  6. data/app/assets/stylesheets/madmin/forms.css +271 -11
  7. data/app/assets/stylesheets/madmin/pagination.css +25 -21
  8. data/app/assets/stylesheets/madmin/reset.css +1 -1
  9. data/app/assets/stylesheets/madmin/sidebar.css +6 -6
  10. data/app/assets/stylesheets/madmin/tables.css +2 -1
  11. data/app/controllers/madmin/base_controller.rb +1 -5
  12. data/app/controllers/madmin/resource_controller.rb +53 -19
  13. data/app/helpers/madmin/application_helper.rb +33 -2
  14. data/app/helpers/madmin/filters_helper.rb +26 -0
  15. data/app/helpers/madmin/sort_helper.rb +1 -1
  16. data/app/javascript/madmin/application.js +4 -0
  17. data/app/javascript/madmin/controllers/application.js +0 -3
  18. data/app/javascript/madmin/controllers/filters_controller.js +35 -0
  19. data/app/javascript/madmin/controllers/nested_form_controller.js +5 -0
  20. data/app/javascript/madmin/controllers/select_controller.js +269 -22
  21. data/app/views/layouts/madmin/application.html.erb +1 -0
  22. data/app/views/madmin/application/_active_filters.html.erb +15 -0
  23. data/app/views/madmin/application/_filter.html.erb +13 -0
  24. data/app/views/madmin/application/_filters.html.erb +30 -0
  25. data/app/views/madmin/application/_javascript.html.erb +0 -2
  26. data/app/views/madmin/application/_pagination.html.erb +33 -0
  27. data/app/views/madmin/application/_per_page.html.erb +10 -0
  28. data/app/views/madmin/application/edit.html.erb +1 -1
  29. data/app/views/madmin/application/index.html.erb +9 -12
  30. data/app/views/madmin/application/new.html.erb +1 -1
  31. data/app/views/madmin/application/show.html.erb +2 -2
  32. data/app/views/madmin/fields/array/_form.html.erb +1 -0
  33. data/app/views/madmin/fields/array/_index.html.erb +1 -0
  34. data/app/views/madmin/fields/array/_show.html.erb +1 -0
  35. data/app/views/madmin/fields/attachment/_form.html.erb +1 -5
  36. data/app/views/madmin/fields/attachment/_show.html.erb +3 -1
  37. data/app/views/madmin/fields/attachments/_form.html.erb +1 -1
  38. data/app/views/madmin/fields/belongs_to/_form.html.erb +1 -1
  39. data/app/views/madmin/fields/belongs_to/_index.html.erb +5 -2
  40. data/app/views/madmin/fields/belongs_to/_show.html.erb +1 -1
  41. data/app/views/madmin/fields/enum/_form.html.erb +1 -1
  42. data/app/views/madmin/fields/file/_form.html.erb +1 -1
  43. data/app/views/madmin/fields/has_many/_form.html.erb +1 -1
  44. data/app/views/madmin/fields/has_many/_show.html.erb +3 -11
  45. data/app/views/madmin/fields/has_one/_index.html.erb +5 -1
  46. data/app/views/madmin/fields/has_one/_show.html.erb +1 -1
  47. data/app/views/madmin/fields/json/_form.html.erb +1 -1
  48. data/app/views/madmin/fields/json/_show.html.erb +1 -1
  49. data/app/views/madmin/fields/nested_has_many/_show.html.erb +3 -11
  50. data/app/views/madmin/fields/nested_has_one/_form.html.erb +18 -0
  51. data/app/views/madmin/fields/polymorphic/_form.html.erb +1 -2
  52. data/app/views/madmin/fields/polymorphic/_index.html.erb +5 -1
  53. data/app/views/madmin/fields/polymorphic/_show.html.erb +1 -1
  54. data/app/views/madmin/fields/select/_form.html.erb +1 -1
  55. data/config/importmap.rb +0 -3
  56. data/config/locales/el.yml +47 -0
  57. data/config/locales/en.yml +47 -0
  58. data/config/locales/fr.yml +47 -0
  59. data/config/locales/ko.yml +48 -0
  60. data/lib/madmin/field.rb +26 -0
  61. data/lib/madmin/fields/array.rb +16 -0
  62. data/lib/madmin/fields/attachment.rb +7 -0
  63. data/lib/madmin/fields/belongs_to.rb +2 -1
  64. data/lib/madmin/fields/boolean.rb +1 -0
  65. data/lib/madmin/fields/currency.rb +7 -0
  66. data/lib/madmin/fields/date.rb +1 -0
  67. data/lib/madmin/fields/date_time.rb +1 -0
  68. data/lib/madmin/fields/decimal.rb +1 -0
  69. data/lib/madmin/fields/float.rb +1 -0
  70. data/lib/madmin/fields/has_many.rb +8 -23
  71. data/lib/madmin/fields/integer.rb +1 -0
  72. data/lib/madmin/fields/json.rb +21 -0
  73. data/lib/madmin/fields/nested_has_many.rb +2 -2
  74. data/lib/madmin/fields/nested_has_one.rb +48 -0
  75. data/lib/madmin/fields/polymorphic.rb +5 -0
  76. data/lib/madmin/fields/string.rb +2 -0
  77. data/lib/madmin/fields/text.rb +2 -0
  78. data/lib/madmin/filter.rb +113 -0
  79. data/lib/madmin/menu.rb +2 -1
  80. data/lib/madmin/page.rb +89 -0
  81. data/lib/madmin/pagination.rb +50 -0
  82. data/lib/madmin/resource.rb +83 -36
  83. data/lib/madmin/search.rb +5 -7
  84. data/lib/madmin/version.rb +1 -1
  85. data/lib/madmin.rb +45 -3
  86. metadata +17 -15
@@ -0,0 +1,15 @@
1
+ <% if filters.any? %>
2
+ <div class="active-filters">
3
+ <% filters.each do |filter| %>
4
+ <span class="filter-chip">
5
+ <span>
6
+ <strong><%= filter.field.label %></strong>
7
+ <%= t("madmin.filters.operators.#{filter.type}.#{filter.operator}") %>
8
+ <%= tag.strong filter_value_label(filter) if filter.value? %>
9
+ </span>
10
+ <%= link_to "×", index_path_with(filters: filters.excluding(filter).map(&:to_h).presence), aria: {label: t("madmin.filters.remove")} %>
11
+ </span>
12
+ <% end %>
13
+ <%= link_to t("madmin.filters.clear_all"), index_path_with(filters: nil) %>
14
+ </div>
15
+ <% end %>
@@ -0,0 +1,13 @@
1
+ <div class="filter-row" data-filter-row>
2
+ <%= select_tag "filters[][column]", options_for_select(filter_column_options(resource), filter.column),
3
+ id: nil, aria: {label: t("madmin.filters.column")}, data: {action: "filters#changeColumn"} %>
4
+
5
+ <%= select_tag "filters[][operator]", options_for_select(filter_operator_options(filter.type), filter.operator),
6
+ id: nil, aria: {label: t("madmin.filters.operator")}, data: {action: "filters#changeOperator"} %>
7
+
8
+ <%= tag.input name: "filters[][value]", value: filter.value, id: nil,
9
+ type: filter_input_type(filter.type), step: ("any" if filter.type == :number),
10
+ hidden: !filter.value?, aria: {label: t("madmin.filters.value")} %>
11
+
12
+ <button type="button" class="filter-remove" aria-label="<%= t("madmin.filters.remove") %>" data-action="filters#remove">&times;</button>
13
+ </div>
@@ -0,0 +1,30 @@
1
+ <% if resource.filterable_attributes.any? %>
2
+ <button type="button" id="filters-button" class="btn btn-secondary" popovertarget="filters">
3
+ <%= t("madmin.filters.button") %>
4
+ <%= tag.span filters.size, class: "filters-count" if filters.any? %>
5
+ </button>
6
+
7
+ <div id="filters" class="filters" popover data-controller="filters">
8
+ <%= form_with url: resource.index_path, method: :get, skip_enforcing_utf8: true do %>
9
+ <%= index_params_fields except: [:filters] %>
10
+
11
+ <p class="filters-heading"><%= t("madmin.filters.heading") %></p>
12
+
13
+ <div class="filter-rows" data-filters-target="rows">
14
+ <% (filters.presence || [Madmin::Filter.blank(resource)]).each do |filter| %>
15
+ <%= render "filter", filter: filter %>
16
+ <% end %>
17
+ </div>
18
+
19
+ <template data-filters-target="row"><%= render "filter", filter: Madmin::Filter.blank(resource) %></template>
20
+ <% Madmin::Filter::OPERATORS.each_key do |type| %>
21
+ <template data-filters-target="operators" data-filter-type="<%= type %>"><%= options_for_select(filter_operator_options(type)) %></template>
22
+ <% end %>
23
+
24
+ <div class="filters-footer">
25
+ <button type="button" class="btn btn-link" data-action="filters#add"><%= t("madmin.filters.add") %></button>
26
+ <button type="submit" class="btn btn-primary"><%= t("madmin.filters.apply") %></button>
27
+ </div>
28
+ <% end %>
29
+ </div>
30
+ <% end %>
@@ -4,5 +4,3 @@
4
4
  <%= tag.script 'import "lexxy"'.html_safe, type: "module" if defined?(::Lexxy) %>
5
5
 
6
6
  <%= stylesheet_link_tag *Madmin.stylesheets, "data-turbo-track": "reload" %>
7
- <%= stylesheet_link_tag "https://unpkg.com/flatpickr/dist/flatpickr.min.css", "data-turbo-track": "reload" %>
8
- <%= stylesheet_link_tag "https://unpkg.com/tom-select/dist/css/tom-select.min.css", "data-turbo-track": "reload" %>
@@ -0,0 +1,33 @@
1
+ <div class="pagination">
2
+ <% if page.last > 1 %>
3
+ <nav class="pages" aria-label="<%= t("madmin.pagination.label") %>">
4
+ <%= link_to_if page.prev, "<", page.prev && current_path_with(page.param => page.prev), aria: { label: t("madmin.pagination.previous") } do %>
5
+ <a role="link" aria-disabled="true" aria-label="<%= t("madmin.pagination.previous") %>">&lt;</a>
6
+ <% end %>
7
+
8
+ <% page.series.each do |number| %>
9
+ <% if number == :gap %>
10
+ <a role="separator" aria-disabled="true">&hellip;</a>
11
+ <% elsif number == page.page %>
12
+ <a role="link" aria-disabled="true" aria-current="page"><%= number %></a>
13
+ <% else %>
14
+ <%= link_to number, current_path_with(page.param => number) %>
15
+ <% end %>
16
+ <% end %>
17
+
18
+ <%= link_to_if page.next, ">", page.next && current_path_with(page.param => page.next), aria: { label: t("madmin.pagination.next") } do %>
19
+ <a role="link" aria-disabled="true" aria-label="<%= t("madmin.pagination.next") %>">&gt;</a>
20
+ <% end %>
21
+ </nav>
22
+ <% end %>
23
+
24
+ <span class="pagination-info">
25
+ <% if page.to.zero? %>
26
+ <%= t("madmin.pagination.empty") %>
27
+ <% else %>
28
+ <%= t("madmin.pagination.info", from: page.from, to: page.to, count: page.count) %>
29
+ <% end %>
30
+ </span>
31
+
32
+ <%= render "per_page", page: page if page.resizable? %>
33
+ </div>
@@ -0,0 +1,10 @@
1
+ <nav class="per-page" aria-label="<%= t("madmin.pagination.per_page") %>">
2
+ <span><%= t("madmin.pagination.per_page") %></span>
3
+ <% page.per_page_options.each do |size| %>
4
+ <% if size == page.per_page %>
5
+ <a role="link" aria-disabled="true" aria-current="true"><%= size %></a>
6
+ <% else %>
7
+ <%= link_to size, current_path_with(page.param => nil, page.per_page_param => size) %>
8
+ <% end %>
9
+ <% end %>
10
+ </nav>
@@ -2,7 +2,7 @@
2
2
 
3
3
  <header class="header">
4
4
  <h1>
5
- <%= link_to resource.friendly_name(count: 2), resource.index_path %>
5
+ <%= link_to resource.friendly_plural_name, resource.index_path %>
6
6
  /
7
7
  <strong><%= t("madmin.actions.edit") %> <%= link_to resource.display_name(@record), resource.show_path(@record) %></strong>
8
8
  </h1>
@@ -1,11 +1,12 @@
1
- <%= content_for :title, resource.friendly_name(count: 2) %>
1
+ <%= content_for :title, resource.friendly_plural_name %>
2
2
 
3
3
  <header class="header">
4
- <h1><%= resource.friendly_name(count: 2) %></h1>
4
+ <h1><%= resource.friendly_plural_name %></h1>
5
5
 
6
6
  <div class="actions">
7
7
  <form class="search">
8
8
  <%= hidden_field_tag :page, params[:page], value: 1 %>
9
+ <%= index_params_fields except: [:q] %>
9
10
  <%= search_field_tag :q, params[:q], placeholder: t("madmin.search.placeholder") %>
10
11
  </form>
11
12
 
@@ -15,6 +16,8 @@
15
16
  </svg>
16
17
  <% end if params[:q].present? %>
17
18
 
19
+ <%= render "filters" %>
20
+
18
21
  <% resource.collection_actions.each do |action| %>
19
22
  <%= instance_exec(&action) %>
20
23
  <% end %>
@@ -27,13 +30,15 @@
27
30
  </div>
28
31
  </header>
29
32
 
33
+ <%= render "active_filters" %>
34
+
30
35
  <nav class="scopes">
31
36
  <% if resource.scopes.any? %>
32
37
  <%= link_to t("madmin.actions.all"), resource.index_path, class: class_names("btn btn-secondary", {"active" => params[:scope].blank?}) %>
33
38
  <% end %>
34
39
 
35
40
  <% resource.scopes.each do |scope| %>
36
- <%= link_to resource.scope_label(scope), resource.index_path(scope: scope, q: params[:q], sort: params[:sort], direction: params[:direction]), class: class_names("btn btn-secondary", {"active" => params[:scope] == scope.to_s}) %>
41
+ <%= link_to resource.scope_label(scope), index_path_with(scope: scope), class: class_names("btn btn-secondary", {"active" => params[:scope] == scope.to_s}) %>
37
42
  <% end %>
38
43
  </nav>
39
44
 
@@ -74,12 +79,4 @@
74
79
  </table>
75
80
  </div>
76
81
 
77
- <div class="pagination">
78
- <% if @pagy.respond_to?(:series_nav) %>
79
- <%== @pagy.series_nav if @pagy.last > 1 %>
80
- <%== @pagy.info_tag %>
81
- <% else %>
82
- <%== pagy_nav @pagy if @pagy.last > 1 %>
83
- <%== pagy_info @pagy %>
84
- <% end %>
85
- </div>
82
+ <%= render "pagination", page: @page %>
@@ -2,7 +2,7 @@
2
2
 
3
3
  <header class="header">
4
4
  <h1>
5
- <%= link_to resource.friendly_name(count: 2) , resource.index_path %>
5
+ <%= link_to resource.friendly_plural_name, resource.index_path %>
6
6
  /
7
7
  <strong><%= t("madmin.titles.new", name: resource.friendly_name) %></strong>
8
8
  </h1>
@@ -2,7 +2,7 @@
2
2
 
3
3
  <header class="header">
4
4
  <h1>
5
- <%= link_to resource.friendly_name(count: 2), resource.index_path %>
5
+ <%= link_to resource.friendly_plural_name, resource.index_path %>
6
6
  /
7
7
  <%= resource.display_name(@record) %>
8
8
  </h1>
@@ -13,7 +13,7 @@
13
13
  <% end %>
14
14
  <% unless resource.readonly? %>
15
15
  <%= link_to t("madmin.actions.edit"), resource.edit_path(@record), class: "btn btn-secondary" %>
16
- <%= button_to t("madmin.actions.delete"), resource.show_path(@record), method: :delete, data: { turbo_confirm: t("madmin.confirmations.delete") }, class: "btn btn-danger" %>
16
+ <%= button_to t("madmin.actions.delete"), resource.show_path(@record), method: :delete, data: { turbo_confirm: t("madmin.confirmations.delete", resource: resource.friendly_name, name: resource.display_name(@record)) }, class: "btn btn-danger" %>
17
17
  <% end %>
18
18
  </div>
19
19
  </header>
@@ -0,0 +1 @@
1
+ <%= form.text_field field.attribute_name, value: field.text(record), class: "form-input" %>
@@ -0,0 +1 @@
1
+ <%= field.text(record) %>
@@ -0,0 +1 @@
1
+ <%= field.text(record) %>
@@ -1,11 +1,7 @@
1
- <%= form.file_field field.to_param, class: "form-input"%>
1
+ <%= form.file_field field.to_param, direct_upload: field.options.direct_upload, class: "form-input" %>
2
2
 
3
3
  <% if form.object.persisted? %>
4
4
  <div class="mt-2">
5
5
  <%= render partial: field.to_partial_path("show"), locals: {field: field, record: record} %>
6
-
7
- <% if (value = field.value(record) && value&.attached?) %>
8
- <%= link_to t("madmin.actions.remove"), Madmin.resource_for(value).show_path(value), data: { turbo_method: :delete, turbo_confirm: t("madmin.confirmations.remove_with_changes")} %>
9
- <% end %>
10
6
  </div>
11
7
  <% end %>
@@ -5,5 +5,7 @@
5
5
  <%= link_to attachment.filename, main_app.url_for(attachment), target: :_blank, class: "text-blue-500 underline" %>
6
6
  <% end %>
7
7
 
8
- <%= link_to t("madmin.actions.remove"), Madmin.resource_for(attachment).show_path(attachment), data: { turbo_method: :delete, turbo_confirm: t("madmin.confirmations.remove_with_changes")} %>
8
+ <% if (remove_path = field.remove_path(attachment)) %>
9
+ <%= link_to t("madmin.actions.remove"), remove_path, data: { turbo_method: :delete, turbo_confirm: t("madmin.confirmations.remove_with_changes", name: attachment.filename.to_s) } %>
10
+ <% end %>
9
11
  <% end %>
@@ -1 +1 @@
1
- <%= form.file_field field.attribute_name, multiple: true, class: "form-input" %>
1
+ <%= form.file_field field.attribute_name, multiple: true, direct_upload: field.options.direct_upload, class: "form-input" %>
@@ -1 +1 @@
1
- <%= form.select field.to_param, field.options_for_select(record), { prompt: true }, { data: { controller: "select", select_url_value: field.index_path } } %>
1
+ <%= form.select field.to_param, field.options_for_select(record), { prompt: true }, { class: "form-input", data: { controller: "select", select_url_value: field.index_path } } %>
@@ -1,4 +1,7 @@
1
1
  <% if (object = field.value(record)) %>
2
- <% object_resource = Madmin.resource_for(object) %>
3
- <%= link_to object_resource.display_name(object), object_resource.show_path(object) %>
2
+ <% if (associated_resource = field.associated_resource_for(object)) %>
3
+ <%= link_to_record associated_resource, object %>
4
+ <% else %>
5
+ <%= render partial: "missing_resource", locals: { resource_name: Madmin.resource_name_for(object) } %>
6
+ <% end %>
4
7
  <% end %>
@@ -1,6 +1,6 @@
1
1
  <% if (object = field.value(record)) %>
2
2
  <% if (associated_resource = field.associated_resource_for(object)) %>
3
- <%= link_to associated_resource.display_name(object), associated_resource.show_path(object) %>
3
+ <%= link_to_record associated_resource, object %>
4
4
  <% else %>
5
5
  <%= render partial: "missing_resource", locals: { resource_name: Madmin.resource_name_for(object) } %>
6
6
  <% end %>
@@ -1 +1 @@
1
- <%= form.select field.attribute_name, field.options_for_select(record), { prompt: true }, { data: { controller: "select" } } %>
1
+ <%= form.select field.attribute_name, field.options_for_select(record), { prompt: true }, { class: "form-input" } %>
@@ -1 +1 @@
1
- <%= form.file_field field.attribute_name, class: "form-input" %>
1
+ <%= form.file_field field.attribute_name, direct_upload: field.options.direct_upload, class: "form-input" %>
@@ -1 +1 @@
1
- <%= form.select "#{field.attribute_name.to_s.singularize}_ids", field.options_for_select(record), { prompt: true }, { multiple: true, data: { controller: "select", select_url_value: field.index_path } } %>
1
+ <%= form.select "#{field.attribute_name.to_s.singularize}_ids", field.options_for_select(record), { prompt: true }, { multiple: true, class: "form-input", data: { controller: "select", select_url_value: field.index_path } } %>
@@ -1,18 +1,10 @@
1
- <% pagy, records = field.paginated_value(record, params) %>
1
+ <% page, records = field.paginated_value(record, params) %>
2
2
  <% records.each do |object| %>
3
3
  <% if (associated_resource = field.associated_resource_for(object)) %>
4
- <div><%= link_to associated_resource.display_name(object), associated_resource.show_path(object) %></div>
4
+ <div><%= link_to_record associated_resource, object %></div>
5
5
  <% else %>
6
6
  <%= render partial: "missing_resource", locals: { resource_name: Madmin.resource_name_for(object) } %>
7
7
  <% end %>
8
8
  <% end %>
9
9
 
10
- <div class="pagination">
11
- <% if pagy.respond_to?(:series_nav) %>
12
- <%== pagy.series_nav if pagy.last > 1 %>
13
- <%== pagy.info_tag %>
14
- <% else %>
15
- <%== pagy_nav pagy if pagy.last > 1 %>
16
- <%== pagy_info pagy %>
17
- <% end %>
18
- </div>
10
+ <%= render "pagination", page: page %>
@@ -1,3 +1,7 @@
1
1
  <% if (object = field.value(record)) %>
2
- <%= link_to Madmin.resource_for(object).display_name(object), Madmin.resource_for(object).show_path(object) %>
2
+ <% if (associated_resource = field.associated_resource_for(object)) %>
3
+ <%= link_to_record associated_resource, object %>
4
+ <% else %>
5
+ <%= render partial: "missing_resource", locals: { resource_name: Madmin.resource_name_for(object) } %>
6
+ <% end %>
3
7
  <% end %>
@@ -1,6 +1,6 @@
1
1
  <% if (object = field.value(record)) %>
2
2
  <% if (associated_resource = field.associated_resource_for(object)) %>
3
- <%= link_to associated_resource.display_name(object), associated_resource.show_path(object) %>
3
+ <%= link_to_record associated_resource, object %>
4
4
  <% else %>
5
5
  <%= render partial: "missing_resource", locals: { resource_name: Madmin.resource_name_for(object) } %>
6
6
  <% end %>
@@ -1 +1 @@
1
- <%= form.text_area field.attribute_name, class: "form-input" %>
1
+ <%= form.text_area field.attribute_name, value: field.json(record), class: "form-input" %>
@@ -1 +1 @@
1
- <%= field.value(record) %>
1
+ <pre><%= field.json(record) %></pre>
@@ -1,18 +1,10 @@
1
- <% pagy, records = field.paginated_value(record, params) %>
1
+ <% page, records = field.paginated_value(record, params) %>
2
2
  <% records.each do |object| %>
3
3
  <% if (associated_resource = field.associated_resource_for(object)) %>
4
- <div><%= link_to associated_resource.display_name(object), associated_resource.show_path(object) %></div>
4
+ <div><%= link_to_record associated_resource, object %></div>
5
5
  <% else %>
6
6
  <%= render partial: "missing_resource", locals: { resource_name: Madmin.resource_name_for(object) } %>
7
7
  <% end %>
8
8
  <% end %>
9
9
 
10
- <div class="pagination">
11
- <% if pagy.respond_to?(:series_nav) %>
12
- <%== pagy.series_nav if pagy.last > 1 %>
13
- <%== pagy.info_tag %>
14
- <% else %>
15
- <%== pagy_nav pagy if pagy.last > 1 %>
16
- <%== pagy_info pagy %>
17
- <% end %>
18
- </div>
10
+ <%= render "pagination", page: page %>
@@ -0,0 +1,18 @@
1
+ <div data-controller="nested-form" data-nested-form-single="true">
2
+ <template data-nested-form-target="template">
3
+ <%= form.fields_for field.attribute_name, field.to_model.new do |nested_form| %>
4
+ <%= render partial: field.to_partial_path("fields"), locals: { f: nested_form, field: field } %>
5
+ <% end %>
6
+ </template>
7
+
8
+ <% if (object = field.value(record)) %>
9
+ <%= form.fields_for field.attribute_name, object do |nested_form| %>
10
+ <%= render partial: field.to_partial_path("fields"), locals: { f: nested_form, field: field } %>
11
+ <% end %>
12
+ <% end %>
13
+
14
+ <%# Nothing is created until "Add" is clicked, since the template isn't submitted %>
15
+ <%= tag.div data: { nested_form_target: "links" }, hidden: object.present? do %>
16
+ <%= link_to t("madmin.nested_form.add_new"), "#", data: { action: "click->nested-form#add_association" } %>
17
+ <% end %>
18
+ </div>
@@ -1,4 +1,3 @@
1
1
  <%= form.fields_for field.attribute_name do |pf| %>
2
- <%= pf.select :value, field.options_for_select(record).map(&:to_global_id), { selected: field.value(record)&.to_global_id, prompt: true }, { data: { controller: "select" } } %>
3
- <%= pf.hidden_field :type, value: "polymorphic" %>
2
+ <%= pf.select :value, field.options_for_select(record).map(&:to_global_id), { selected: field.value(record)&.to_global_id, prompt: true }, { class: "form-input" } %>
4
3
  <% end %>
@@ -1,3 +1,7 @@
1
1
  <% if (object = field.value(record)) %>
2
- <%= link_to Madmin.resource_for(object).display_name(object), Madmin.resource_for(object).show_path(object) %>
2
+ <% if (associated_resource = field.associated_resource_for(object)) %>
3
+ <%= link_to_record associated_resource, object %>
4
+ <% else %>
5
+ <%= render partial: "missing_resource", locals: { resource_name: Madmin.resource_name_for(object) } %>
6
+ <% end %>
3
7
  <% end %>
@@ -1,6 +1,6 @@
1
1
  <% if (object = field.value(record)) %>
2
2
  <% if (associated_resource = field.associated_resource_for(object)) %>
3
- <%= link_to associated_resource.display_name(object), associated_resource.show_path(object), class: "text-blue-500 underline" %>
3
+ <%= link_to_record associated_resource, object, class: "text-blue-500 underline" %>
4
4
  <% else %>
5
5
  <%= render partial: "missing_resource", locals: { resource_name: Madmin.resource_name_for(object) } %>
6
6
  <% end %>
@@ -1 +1 @@
1
- <%= form.select field.attribute_name, field.options_for_select(record), { prompt: true }, { data: { controller: "select" } } %>
1
+ <%= form.select field.attribute_name, field.options_for_select(record), { prompt: true }, { class: "form-input" } %>
data/config/importmap.rb CHANGED
@@ -10,6 +10,3 @@ pin "lexxy", to: "lexxy.js" if defined?(::Lexxy)
10
10
 
11
11
  pin_all_from Madmin::Engine.root.join("app/javascript/madmin/controllers"), under: "controllers", to: "madmin/controllers"
12
12
  pin_all_from Rails.root.join("app/javascript/madmin/controllers"), under: "controllers", to: "madmin/controllers"
13
-
14
- pin "tom-select", to: "https://ga.jspm.io/npm:tom-select@2.4.1/dist/js/tom-select.complete.js"
15
- pin "tailwindcss-stimulus-components", to: "https://ga.jspm.io/npm:tailwindcss-stimulus-components@6.1.2/dist/tailwindcss-stimulus-components.module.js"
@@ -28,6 +28,8 @@ el:
28
28
  other: Υπήρξαν %{count} σφάλματα με την υποβολή σας
29
29
  flash:
30
30
  readonly: "%{name}: μόνο για ανάγνωση"
31
+ destroy_failed: "%{name}: η διαγραφή απέτυχε"
32
+ destroy_restricted: "%{name}: η διαγραφή απέτυχε επειδή άλλες εγγραφές εξαρτώνται από αυτήν"
31
33
  confirmations:
32
34
  delete: Είστε σίγουροι;
33
35
  remove_with_changes: Είστε σίγουροι; Θα χάσετε όλες τις άλλες αλλαγές.
@@ -40,3 +42,48 @@ el:
40
42
  missing_resource:
41
43
  message: "Λείπει: %{resource}"
42
44
  create_hint: "Δημιουργήστε το εκτελώντας:"
45
+ pagination:
46
+ label: Σελιδοποίηση
47
+ previous: Προηγούμενη
48
+ next: Επόμενη
49
+ info: "Εμφάνιση %{from}-%{to} από %{count}"
50
+ empty: Δεν βρέθηκαν εγγραφές
51
+ per_page: Ανά σελίδα
52
+ filters:
53
+ button: "Φίλτρα"
54
+ heading: "Εμφάνιση εγγραφών όπου"
55
+ add: "+ Προσθήκη φίλτρου"
56
+ apply: "Εφαρμογή"
57
+ clear_all: "Εκκαθάριση φίλτρων"
58
+ remove: "Αφαίρεση φίλτρου"
59
+ column: "Στήλη"
60
+ operator: "Συνθήκη"
61
+ value: "Τιμή"
62
+ operators:
63
+ string:
64
+ contains: "περιέχει"
65
+ eq: "είναι"
66
+ starts_with: "ξεκινά με"
67
+ blank: "είναι κενό"
68
+ present: "δεν είναι κενό"
69
+ number:
70
+ eq: "="
71
+ gt: ">"
72
+ gte: "≥"
73
+ lt: "<"
74
+ lte: "≤"
75
+ blank: "είναι κενό"
76
+ date:
77
+ eq: "στις"
78
+ gte: "στις ή μετά"
79
+ lte: "στις ή πριν"
80
+ blank: "είναι κενό"
81
+ datetime:
82
+ gte: "μετά"
83
+ lte: "πριν"
84
+ blank: "είναι κενό"
85
+ boolean:
86
+ "true": "είναι αληθές"
87
+ "false": "είναι ψευδές"
88
+ array:
89
+ includes: "περιέχει"
@@ -28,6 +28,8 @@ en:
28
28
  other: There were %{count} errors with your submission
29
29
  flash:
30
30
  readonly: "%{name} is read-only"
31
+ destroy_failed: "%{name} could not be deleted"
32
+ destroy_restricted: "%{name} could not be deleted because other records depend on it"
31
33
  confirmations:
32
34
  delete: Are you sure?
33
35
  remove_with_changes: Are you sure? You will lose any other changes.
@@ -40,3 +42,48 @@ en:
40
42
  missing_resource:
41
43
  message: "%{resource} is missing."
42
44
  create_hint: "Create it by running:"
45
+ pagination:
46
+ label: Pagination
47
+ previous: Previous
48
+ next: Next
49
+ info: "Displaying %{from}-%{to} of %{count}"
50
+ empty: No records found
51
+ per_page: Per page
52
+ filters:
53
+ button: "Filters"
54
+ heading: "Show records where"
55
+ add: "+ Add filter"
56
+ apply: "Apply"
57
+ clear_all: "Clear filters"
58
+ remove: "Remove filter"
59
+ column: "Column"
60
+ operator: "Condition"
61
+ value: "Value"
62
+ operators:
63
+ string:
64
+ contains: "contains"
65
+ eq: "is"
66
+ starts_with: "starts with"
67
+ blank: "is empty"
68
+ present: "is not empty"
69
+ number:
70
+ eq: "="
71
+ gt: ">"
72
+ gte: "≥"
73
+ lt: "<"
74
+ lte: "≤"
75
+ blank: "is empty"
76
+ date:
77
+ eq: "on"
78
+ gte: "on or after"
79
+ lte: "on or before"
80
+ blank: "is empty"
81
+ datetime:
82
+ gte: "after"
83
+ lte: "before"
84
+ blank: "is empty"
85
+ boolean:
86
+ "true": "is true"
87
+ "false": "is false"
88
+ array:
89
+ includes: "includes"
@@ -28,6 +28,8 @@ fr:
28
28
  other: Il y a eu %{count} erreurs dans votre soumission
29
29
  flash:
30
30
  readonly: "%{name} est en lecture seule"
31
+ destroy_failed: "%{name} n'a pas pu être supprimé"
32
+ destroy_restricted: "%{name} n'a pas pu être supprimé car d'autres enregistrements en dépendent"
31
33
  confirmations:
32
34
  delete: Êtes-vous sûr ?
33
35
  remove_with_changes: Êtes-vous sûr ? Vous perdrez toutes les autres modifications.
@@ -40,3 +42,48 @@ fr:
40
42
  missing_resource:
41
43
  message: "%{resource} est introuvable."
42
44
  create_hint: "Pour le créer, exécutez :"
45
+ pagination:
46
+ label: Pagination
47
+ previous: Précédent
48
+ next: Suivant
49
+ info: "Affichage de %{from} à %{to} sur %{count}"
50
+ empty: Aucun enregistrement trouvé
51
+ per_page: Par page
52
+ filters:
53
+ button: "Filtres"
54
+ heading: "Afficher les enregistrements où"
55
+ add: "+ Ajouter un filtre"
56
+ apply: "Appliquer"
57
+ clear_all: "Effacer les filtres"
58
+ remove: "Retirer le filtre"
59
+ column: "Colonne"
60
+ operator: "Condition"
61
+ value: "Valeur"
62
+ operators:
63
+ string:
64
+ contains: "contient"
65
+ eq: "est"
66
+ starts_with: "commence par"
67
+ blank: "est vide"
68
+ present: "n'est pas vide"
69
+ number:
70
+ eq: "="
71
+ gt: ">"
72
+ gte: "≥"
73
+ lt: "<"
74
+ lte: "≤"
75
+ blank: "est vide"
76
+ date:
77
+ eq: "le"
78
+ gte: "le ou après"
79
+ lte: "le ou avant"
80
+ blank: "est vide"
81
+ datetime:
82
+ gte: "après"
83
+ lte: "avant"
84
+ blank: "est vide"
85
+ boolean:
86
+ "true": "est vrai"
87
+ "false": "est faux"
88
+ array:
89
+ includes: "contient"