madmin 2.5.1 → 3.0.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 (85) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +121 -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 +263 -7
  7. data/app/assets/stylesheets/madmin/pagination.css +10 -23
  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 +5 -1
  11. data/app/controllers/madmin/base_controller.rb +1 -5
  12. data/app/controllers/madmin/resource_controller.rb +49 -16
  13. data/app/helpers/madmin/application_helper.rb +15 -2
  14. data/app/helpers/madmin/filters_helper.rb +26 -0
  15. data/app/helpers/madmin/sort_helper.rb +2 -2
  16. data/app/javascript/madmin/controllers/filters_controller.js +35 -0
  17. data/app/javascript/madmin/controllers/nested_form_controller.js +5 -0
  18. data/app/javascript/madmin/controllers/select_controller.js +269 -22
  19. data/app/views/layouts/madmin/application.html.erb +1 -0
  20. data/app/views/madmin/application/_active_filters.html.erb +15 -0
  21. data/app/views/madmin/application/_filter.html.erb +13 -0
  22. data/app/views/madmin/application/_filters.html.erb +32 -0
  23. data/app/views/madmin/application/_javascript.html.erb +0 -2
  24. data/app/views/madmin/application/_pagination.html.erb +32 -0
  25. data/app/views/madmin/application/edit.html.erb +1 -1
  26. data/app/views/madmin/application/index.html.erb +18 -15
  27. data/app/views/madmin/application/new.html.erb +1 -1
  28. data/app/views/madmin/application/show.html.erb +5 -3
  29. data/app/views/madmin/fields/array/_form.html.erb +1 -0
  30. data/app/views/madmin/fields/array/_index.html.erb +1 -0
  31. data/app/views/madmin/fields/array/_show.html.erb +1 -0
  32. data/app/views/madmin/fields/attachment/_form.html.erb +0 -4
  33. data/app/views/madmin/fields/attachment/_show.html.erb +3 -1
  34. data/app/views/madmin/fields/attachments/_index.html.erb +1 -1
  35. data/app/views/madmin/fields/belongs_to/_form.html.erb +1 -1
  36. data/app/views/madmin/fields/belongs_to/_index.html.erb +5 -2
  37. data/app/views/madmin/fields/belongs_to/_show.html.erb +1 -1
  38. data/app/views/madmin/fields/enum/_form.html.erb +1 -1
  39. data/app/views/madmin/fields/has_many/_form.html.erb +1 -1
  40. data/app/views/madmin/fields/has_many/_index.html.erb +1 -1
  41. data/app/views/madmin/fields/has_many/_show.html.erb +3 -11
  42. data/app/views/madmin/fields/has_one/_index.html.erb +5 -1
  43. data/app/views/madmin/fields/has_one/_show.html.erb +1 -1
  44. data/app/views/madmin/fields/json/_form.html.erb +1 -1
  45. data/app/views/madmin/fields/json/_show.html.erb +1 -1
  46. data/app/views/madmin/fields/nested_has_many/_index.html.erb +1 -1
  47. data/app/views/madmin/fields/nested_has_many/_show.html.erb +3 -11
  48. data/app/views/madmin/fields/nested_has_one/_form.html.erb +18 -0
  49. data/app/views/madmin/fields/polymorphic/_form.html.erb +1 -2
  50. data/app/views/madmin/fields/polymorphic/_index.html.erb +5 -1
  51. data/app/views/madmin/fields/polymorphic/_show.html.erb +1 -1
  52. data/app/views/madmin/fields/select/_form.html.erb +1 -1
  53. data/config/importmap.rb +0 -1
  54. data/config/locales/el.yml +86 -0
  55. data/config/locales/en.yml +46 -0
  56. data/config/locales/fr.yml +46 -0
  57. data/config/locales/ko.yml +84 -0
  58. data/lib/madmin/field.rb +27 -1
  59. data/lib/madmin/fields/array.rb +16 -0
  60. data/lib/madmin/fields/attachment.rb +7 -0
  61. data/lib/madmin/fields/belongs_to.rb +2 -1
  62. data/lib/madmin/fields/boolean.rb +1 -0
  63. data/lib/madmin/fields/currency.rb +7 -0
  64. data/lib/madmin/fields/date.rb +1 -0
  65. data/lib/madmin/fields/date_time.rb +1 -0
  66. data/lib/madmin/fields/decimal.rb +1 -0
  67. data/lib/madmin/fields/float.rb +1 -0
  68. data/lib/madmin/fields/has_many.rb +6 -23
  69. data/lib/madmin/fields/integer.rb +1 -0
  70. data/lib/madmin/fields/json.rb +21 -0
  71. data/lib/madmin/fields/nested_has_many.rb +2 -2
  72. data/lib/madmin/fields/nested_has_one.rb +48 -0
  73. data/lib/madmin/fields/polymorphic.rb +5 -0
  74. data/lib/madmin/fields/string.rb +3 -1
  75. data/lib/madmin/fields/text.rb +3 -1
  76. data/lib/madmin/filter.rb +96 -0
  77. data/lib/madmin/menu.rb +2 -1
  78. data/lib/madmin/page.rb +61 -0
  79. data/lib/madmin/pagination.rb +50 -0
  80. data/lib/madmin/resource.rb +95 -7
  81. data/lib/madmin/resource_builder.rb +8 -0
  82. data/lib/madmin/search.rb +5 -7
  83. data/lib/madmin/version.rb +1 -1
  84. data/lib/madmin.rb +47 -2
  85. metadata +19 -16
@@ -0,0 +1,32 @@
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
+ <% request.query_parameters.slice("q", "scope", "sort", "direction").each do |name, value| %>
10
+ <%= hidden_field_tag name, value, id: nil %>
11
+ <% end %>
12
+
13
+ <p class="filters-heading"><%= t("madmin.filters.heading") %></p>
14
+
15
+ <div class="filter-rows" data-filters-target="rows">
16
+ <% (filters.presence || [Madmin::Filter.blank(resource)]).each do |filter| %>
17
+ <%= render "filter", filter: filter %>
18
+ <% end %>
19
+ </div>
20
+
21
+ <template data-filters-target="row"><%= render "filter", filter: Madmin::Filter.blank(resource) %></template>
22
+ <% Madmin::Filter::OPERATORS.each_key do |type| %>
23
+ <template data-filters-target="operators" data-filter-type="<%= type %>"><%= options_for_select(filter_operator_options(type)) %></template>
24
+ <% end %>
25
+
26
+ <div class="filters-footer">
27
+ <button type="button" class="btn btn-link" data-action="filters#add"><%= t("madmin.filters.add") %></button>
28
+ <button type="submit" class="btn btn-primary"><%= t("madmin.filters.apply") %></button>
29
+ </div>
30
+ <% end %>
31
+ </div>
32
+ <% 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,32 @@
1
+ <div class="pagination">
2
+ <% if page.last > 1 %>
3
+ <% page_url = ->(number) { "#{request.path}?#{request.query_parameters.merge(page.param => number).to_query}" } %>
4
+ <nav class="pages" aria-label="<%= t("madmin.pagination.label") %>">
5
+ <%= link_to_if page.prev, "<", page.prev && page_url.call(page.prev), aria: { label: t("madmin.pagination.previous") } do %>
6
+ <a role="link" aria-disabled="true" aria-label="<%= t("madmin.pagination.previous") %>">&lt;</a>
7
+ <% end %>
8
+
9
+ <% page.series.each do |number| %>
10
+ <% if number == :gap %>
11
+ <a role="separator" aria-disabled="true">&hellip;</a>
12
+ <% elsif number == page.page %>
13
+ <a role="link" aria-disabled="true" aria-current="page"><%= number %></a>
14
+ <% else %>
15
+ <%= link_to number, page_url.call(number) %>
16
+ <% end %>
17
+ <% end %>
18
+
19
+ <%= link_to_if page.next, ">", page.next && page_url.call(page.next), aria: { label: t("madmin.pagination.next") } do %>
20
+ <a role="link" aria-disabled="true" aria-label="<%= t("madmin.pagination.next") %>">&gt;</a>
21
+ <% end %>
22
+ </nav>
23
+ <% end %>
24
+
25
+ <span class="pagination-info">
26
+ <% if page.to.zero? %>
27
+ <%= t("madmin.pagination.empty") %>
28
+ <% else %>
29
+ <%= t("madmin.pagination.info", from: page.from, to: page.to, count: page.count) %>
30
+ <% end %>
31
+ </span>
32
+ </div>
@@ -2,7 +2,7 @@
2
2
 
3
3
  <header class="header">
4
4
  <h1>
5
- <%= link_to resource.friendly_name.pluralize, 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,12 +1,17 @@
1
- <%= content_for :title, resource.friendly_name.pluralize %>
1
+ <%= content_for :title, resource.friendly_plural_name %>
2
2
 
3
3
  <header class="header">
4
- <h1><%= resource.friendly_name.pluralize %></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
9
  <%= search_field_tag :q, params[:q], placeholder: t("madmin.search.placeholder") %>
10
+ <% filters.map(&:to_h).each do |filter| %>
11
+ <% filter.each do |name, value| %>
12
+ <%= hidden_field_tag "filters[][#{name}]", value, id: nil %>
13
+ <% end %>
14
+ <% end %>
10
15
  </form>
11
16
 
12
17
  <%= link_to clear_search_params, class: "btn btn-secondary" do %>
@@ -15,23 +20,29 @@
15
20
  </svg>
16
21
  <% end if params[:q].present? %>
17
22
 
23
+ <%= render "filters" %>
24
+
18
25
  <% resource.collection_actions.each do |action| %>
19
26
  <%= instance_exec(&action) %>
20
27
  <% end %>
21
28
 
22
- <%= link_to resource.new_path, class: "btn btn-secondary" do %>
23
- <%= t("madmin.actions.new") %> <%= tag.span resource.friendly_name, class: "hidden md:inline-block" %>
29
+ <% unless resource.readonly? %>
30
+ <%= link_to resource.new_path, class: "btn btn-secondary" do %>
31
+ <%= t("madmin.actions.new") %> <%= tag.span resource.friendly_name, class: "hidden md:inline-block" %>
32
+ <% end %>
24
33
  <% end %>
25
34
  </div>
26
35
  </header>
27
36
 
37
+ <%= render "active_filters" %>
38
+
28
39
  <nav class="scopes">
29
40
  <% if resource.scopes.any? %>
30
41
  <%= link_to t("madmin.actions.all"), resource.index_path, class: class_names("btn btn-secondary", {"active" => params[:scope].blank?}) %>
31
42
  <% end %>
32
43
 
33
44
  <% resource.scopes.each do |scope| %>
34
- <%= link_to scope.to_s.humanize, 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}) %>
45
+ <%= link_to resource.scope_label(scope), index_path_with(scope: scope), class: class_names("btn btn-secondary", {"active" => params[:scope] == scope.to_s}) %>
35
46
  <% end %>
36
47
  </nav>
37
48
 
@@ -60,7 +71,7 @@
60
71
 
61
72
  <td class="actions">
62
73
  <%= link_to t("madmin.actions.view"), resource.show_path(record), class: "btn btn-secondary" %>
63
- <%= link_to t("madmin.actions.edit"), resource.edit_path(record), class: "btn btn-secondary" %>
74
+ <%= link_to t("madmin.actions.edit"), resource.edit_path(record), class: "btn btn-secondary" unless resource.readonly? %>
64
75
 
65
76
  <% resource.collection_member_actions.each do |action| %>
66
77
  <%= instance_exec(record, &action) %>
@@ -72,12 +83,4 @@
72
83
  </table>
73
84
  </div>
74
85
 
75
- <div class="pagination">
76
- <% if @pagy.respond_to?(:series_nav) %>
77
- <%== @pagy.series_nav if @pagy.last > 1 %>
78
- <%== @pagy.info_tag %>
79
- <% else %>
80
- <%== pagy_nav @pagy if @pagy.last > 1 %>
81
- <%== pagy_info @pagy %>
82
- <% end %>
83
- </div>
86
+ <%= render "pagination", page: @page %>
@@ -2,7 +2,7 @@
2
2
 
3
3
  <header class="header">
4
4
  <h1>
5
- <%= link_to resource.friendly_name.pluralize, 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.pluralize, resource.index_path %>
5
+ <%= link_to resource.friendly_plural_name, resource.index_path %>
6
6
  /
7
7
  <%= resource.display_name(@record) %>
8
8
  </h1>
@@ -11,8 +11,10 @@
11
11
  <% resource.member_actions.each do |action| %>
12
12
  <%= instance_exec(@record, &action) %>
13
13
  <% end %>
14
- <%= link_to t("madmin.actions.edit"), resource.edit_path(@record), class: "btn btn-secondary" %>
15
- <%= button_to t("madmin.actions.delete"), resource.show_path(@record), method: :delete, data: { turbo_confirm: t("madmin.confirmations.delete") }, class: "btn btn-danger" %>
14
+ <% unless resource.readonly? %>
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" %>
17
+ <% end %>
16
18
  </div>
17
19
  </header>
18
20
 
@@ -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) %>
@@ -3,9 +3,5 @@
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")} %>
10
+ <% end %>
9
11
  <% end %>
@@ -1 +1 @@
1
- <%= t("madmin.fields.attachment", count: field.value(record).count) %>
1
+ <%= t("madmin.fields.attachment", count: field.value(record).size) %>
@@ -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.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 +1 @@
1
- <%= pluralize field.value(record).count, field.attribute_name.to_s %>
1
+ <%= pluralize field.value(record).size, field.attribute_name.to_s %>
@@ -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 +1 @@
1
- <%= pluralize field.value(record).count, field.attribute_name.to_s %>
1
+ <%= pluralize field.value(record).size, field.attribute_name.to_s %>
@@ -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
@@ -11,5 +11,4 @@ pin "lexxy", to: "lexxy.js" if defined?(::Lexxy)
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
13
 
14
- pin "tom-select", to: "https://ga.jspm.io/npm:tom-select@2.4.1/dist/js/tom-select.complete.js"
15
14
  pin "tailwindcss-stimulus-components", to: "https://ga.jspm.io/npm:tailwindcss-stimulus-components@6.1.2/dist/tailwindcss-stimulus-components.module.js"
@@ -0,0 +1,86 @@
1
+ el:
2
+ madmin:
3
+ layout:
4
+ open_menu: Άνοιγμα μενού
5
+ admin_suffix: Διαχείριση
6
+ navigation:
7
+ dashboard: Πίνακας ελέγχου
8
+ github: Το Madmin στο GitHub
9
+ dashboard:
10
+ title: Πίνακας ελέγχου Madmin
11
+ hint_html: Δημιουργήστε το <code>app/views/madmin/dashboard/show.html.erb</code> για να προσαρμόσετε τον πίνακα ελέγχου σας.
12
+ actions:
13
+ all: Όλα
14
+ view: Προβολή
15
+ edit: Επεξεργασία
16
+ delete: Διαγραφή
17
+ new: Νέο
18
+ remove: Αφαίρεση
19
+ cancel: Ακύρωση
20
+ search:
21
+ placeholder: Αναζήτηση
22
+ titles:
23
+ new: Νέο %{name}
24
+ edit: Επεξεργασία %{name}
25
+ form:
26
+ errors:
27
+ one: Υπήρξε 1 σφάλμα με την υποβολή σας
28
+ other: Υπήρξαν %{count} σφάλματα με την υποβολή σας
29
+ flash:
30
+ readonly: "%{name}: μόνο για ανάγνωση"
31
+ confirmations:
32
+ delete: Είστε σίγουροι;
33
+ remove_with_changes: Είστε σίγουροι; Θα χάσετε όλες τις άλλες αλλαγές.
34
+ nested_form:
35
+ add_new: "+ Προσθήκη νέου"
36
+ fields:
37
+ attachment:
38
+ one: "%{count} συνημμένο"
39
+ other: "%{count} συνημμένα"
40
+ missing_resource:
41
+ message: "Λείπει: %{resource}"
42
+ create_hint: "Δημιουργήστε το εκτελώντας:"
43
+ pagination:
44
+ label: Σελιδοποίηση
45
+ previous: Προηγούμενη
46
+ next: Επόμενη
47
+ info: "Εμφάνιση %{from}-%{to} από %{count}"
48
+ empty: Δεν βρέθηκαν εγγραφές
49
+ filters:
50
+ button: "Φίλτρα"
51
+ heading: "Εμφάνιση εγγραφών όπου"
52
+ add: "+ Προσθήκη φίλτρου"
53
+ apply: "Εφαρμογή"
54
+ clear_all: "Εκκαθάριση φίλτρων"
55
+ remove: "Αφαίρεση φίλτρου"
56
+ column: "Στήλη"
57
+ operator: "Συνθήκη"
58
+ value: "Τιμή"
59
+ operators:
60
+ string:
61
+ contains: "περιέχει"
62
+ eq: "είναι"
63
+ starts_with: "ξεκινά με"
64
+ blank: "είναι κενό"
65
+ present: "δεν είναι κενό"
66
+ number:
67
+ eq: "="
68
+ gt: ">"
69
+ gte: "≥"
70
+ lt: "<"
71
+ lte: "≤"
72
+ blank: "είναι κενό"
73
+ date:
74
+ eq: "στις"
75
+ gte: "στις ή μετά"
76
+ lte: "στις ή πριν"
77
+ blank: "είναι κενό"
78
+ datetime:
79
+ gte: "μετά"
80
+ lte: "πριν"
81
+ blank: "είναι κενό"
82
+ boolean:
83
+ "true": "είναι αληθές"
84
+ "false": "είναι ψευδές"
85
+ array:
86
+ includes: "περιέχει"
@@ -26,6 +26,8 @@ en:
26
26
  errors:
27
27
  one: There was 1 error with your submission
28
28
  other: There were %{count} errors with your submission
29
+ flash:
30
+ readonly: "%{name} is read-only"
29
31
  confirmations:
30
32
  delete: Are you sure?
31
33
  remove_with_changes: Are you sure? You will lose any other changes.
@@ -38,3 +40,47 @@ en:
38
40
  missing_resource:
39
41
  message: "%{resource} is missing."
40
42
  create_hint: "Create it by running:"
43
+ pagination:
44
+ label: Pagination
45
+ previous: Previous
46
+ next: Next
47
+ info: "Displaying %{from}-%{to} of %{count}"
48
+ empty: No records found
49
+ filters:
50
+ button: "Filters"
51
+ heading: "Show records where"
52
+ add: "+ Add filter"
53
+ apply: "Apply"
54
+ clear_all: "Clear filters"
55
+ remove: "Remove filter"
56
+ column: "Column"
57
+ operator: "Condition"
58
+ value: "Value"
59
+ operators:
60
+ string:
61
+ contains: "contains"
62
+ eq: "is"
63
+ starts_with: "starts with"
64
+ blank: "is empty"
65
+ present: "is not empty"
66
+ number:
67
+ eq: "="
68
+ gt: ">"
69
+ gte: "≥"
70
+ lt: "<"
71
+ lte: "≤"
72
+ blank: "is empty"
73
+ date:
74
+ eq: "on"
75
+ gte: "on or after"
76
+ lte: "on or before"
77
+ blank: "is empty"
78
+ datetime:
79
+ gte: "after"
80
+ lte: "before"
81
+ blank: "is empty"
82
+ boolean:
83
+ "true": "is true"
84
+ "false": "is false"
85
+ array:
86
+ includes: "includes"
@@ -26,6 +26,8 @@ fr:
26
26
  errors:
27
27
  one: Il y a eu 1 erreur dans votre soumission
28
28
  other: Il y a eu %{count} erreurs dans votre soumission
29
+ flash:
30
+ readonly: "%{name} est en lecture seule"
29
31
  confirmations:
30
32
  delete: Êtes-vous sûr ?
31
33
  remove_with_changes: Êtes-vous sûr ? Vous perdrez toutes les autres modifications.
@@ -38,3 +40,47 @@ fr:
38
40
  missing_resource:
39
41
  message: "%{resource} est introuvable."
40
42
  create_hint: "Pour le créer, exécutez :"
43
+ pagination:
44
+ label: Pagination
45
+ previous: Précédent
46
+ next: Suivant
47
+ info: "Affichage de %{from} à %{to} sur %{count}"
48
+ empty: Aucun enregistrement trouvé
49
+ filters:
50
+ button: "Filtres"
51
+ heading: "Afficher les enregistrements où"
52
+ add: "+ Ajouter un filtre"
53
+ apply: "Appliquer"
54
+ clear_all: "Effacer les filtres"
55
+ remove: "Retirer le filtre"
56
+ column: "Colonne"
57
+ operator: "Condition"
58
+ value: "Valeur"
59
+ operators:
60
+ string:
61
+ contains: "contient"
62
+ eq: "est"
63
+ starts_with: "commence par"
64
+ blank: "est vide"
65
+ present: "n'est pas vide"
66
+ number:
67
+ eq: "="
68
+ gt: ">"
69
+ gte: "≥"
70
+ lt: "<"
71
+ lte: "≤"
72
+ blank: "est vide"
73
+ date:
74
+ eq: "le"
75
+ gte: "le ou après"
76
+ lte: "le ou avant"
77
+ blank: "est vide"
78
+ datetime:
79
+ gte: "après"
80
+ lte: "avant"
81
+ blank: "est vide"
82
+ boolean:
83
+ "true": "est vrai"
84
+ "false": "est faux"
85
+ array:
86
+ includes: "contient"