madmin 1.2.11 → 2.0.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 (91) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +36 -7
  3. data/app/assets/config/madmin_manifest.js +3 -0
  4. data/app/assets/stylesheets/madmin/actiontext.css +31 -0
  5. data/app/assets/stylesheets/madmin/application-sprockets.css +11 -0
  6. data/app/assets/stylesheets/madmin/application.css +10 -0
  7. data/app/assets/stylesheets/madmin/base.css +117 -0
  8. data/app/assets/stylesheets/madmin/buttons.css +46 -0
  9. data/app/assets/stylesheets/madmin/forms.css +64 -0
  10. data/app/assets/stylesheets/madmin/pagination.css +59 -0
  11. data/app/assets/stylesheets/madmin/reset.css +242 -0
  12. data/app/assets/stylesheets/madmin/sidebar.css +80 -0
  13. data/app/assets/stylesheets/madmin/tables.css +56 -0
  14. data/app/controllers/madmin/application_controller.rb +7 -12
  15. data/app/controllers/madmin/base_controller.rb +1 -0
  16. data/app/controllers/madmin/resource_controller.rb +7 -1
  17. data/app/helpers/madmin/application_helper.rb +1 -12
  18. data/app/helpers/madmin/sort_helper.rb +17 -1
  19. data/app/javascript/madmin/application.js +4 -0
  20. data/app/javascript/madmin/controllers/application.js +12 -0
  21. data/app/javascript/madmin/controllers/index.js +5 -0
  22. data/app/javascript/madmin/controllers/nested_form_controller.js +34 -0
  23. data/app/javascript/madmin/controllers/select_controller.js +32 -0
  24. data/app/views/layouts/madmin/application.html.erb +12 -13
  25. data/app/views/madmin/application/_flash.html.erb +13 -0
  26. data/app/views/madmin/application/_form.html.erb +13 -12
  27. data/app/views/madmin/application/_javascript.html.erb +3 -136
  28. data/app/views/madmin/application/_navigation.html.erb +22 -27
  29. data/app/views/madmin/application/edit.html.erb +9 -5
  30. data/app/views/madmin/application/index.html.erb +37 -31
  31. data/app/views/madmin/application/new.html.erb +9 -5
  32. data/app/views/madmin/application/show.html.erb +28 -22
  33. data/app/views/madmin/dashboard/show.html.erb +4 -1
  34. data/app/views/madmin/fields/attachment/_form.html.erb +11 -4
  35. data/app/views/madmin/fields/attachment/_index.html.erb +5 -1
  36. data/app/views/madmin/fields/attachment/_show.html.erb +4 -4
  37. data/app/views/madmin/fields/attachments/_form.html.erb +1 -4
  38. data/app/views/madmin/fields/belongs_to/_form.html.erb +1 -4
  39. data/app/views/madmin/fields/belongs_to/_index.html.erb +2 -1
  40. data/app/views/madmin/fields/boolean/_form.html.erb +3 -4
  41. data/app/views/madmin/fields/currency/_form.html.erb +1 -0
  42. data/app/views/madmin/fields/currency/_index.html.erb +1 -0
  43. data/app/views/madmin/fields/currency/_show.html.erb +1 -0
  44. data/app/views/madmin/fields/date/_form.html.erb +1 -4
  45. data/app/views/madmin/fields/date_time/_form.html.erb +1 -4
  46. data/app/views/madmin/fields/decimal/_form.html.erb +1 -4
  47. data/app/views/madmin/fields/enum/_form.html.erb +1 -4
  48. data/app/views/madmin/fields/file/_form.html.erb +1 -4
  49. data/app/views/madmin/fields/float/_form.html.erb +1 -4
  50. data/app/views/madmin/fields/has_many/_form.html.erb +1 -4
  51. data/app/views/madmin/fields/has_many/_show.html.erb +7 -1
  52. data/app/views/madmin/fields/has_one/_form.html.erb +0 -3
  53. data/app/views/madmin/fields/integer/_form.html.erb +1 -4
  54. data/app/views/madmin/fields/integer/_index.html.erb +1 -5
  55. data/app/views/madmin/fields/json/_form.html.erb +1 -4
  56. data/app/views/madmin/fields/nested_has_many/_fields.html.erb +4 -5
  57. data/app/views/madmin/fields/nested_has_many/_form.html.erb +0 -4
  58. data/app/views/madmin/fields/nested_has_many/_show.html.erb +7 -1
  59. data/app/views/madmin/fields/password/_form.html.erb +1 -4
  60. data/app/views/madmin/fields/polymorphic/_form.html.erb +1 -4
  61. data/app/views/madmin/fields/rich_text/_form.html.erb +1 -6
  62. data/app/views/madmin/fields/select/_form.html.erb +1 -0
  63. data/app/views/madmin/fields/select/_index.html.erb +1 -0
  64. data/app/views/madmin/fields/select/_show.html.erb +1 -0
  65. data/app/views/madmin/fields/string/_form.html.erb +1 -4
  66. data/app/views/madmin/fields/text/_form.html.erb +1 -4
  67. data/app/views/madmin/shared/_label.html.erb +2 -2
  68. data/config/importmap.rb +10 -0
  69. data/lib/generators/madmin/field/templates/_form.html.erb +1 -4
  70. data/lib/generators/madmin/install/templates/controller.rb.tt +5 -12
  71. data/lib/generators/madmin/resource/resource_generator.rb +1 -1
  72. data/lib/generators/madmin/resource/templates/resource.rb.tt +12 -10
  73. data/lib/madmin/engine.rb +26 -0
  74. data/lib/madmin/field.rb +21 -5
  75. data/lib/madmin/fields/belongs_to.rb +10 -5
  76. data/lib/madmin/fields/currency.rb +15 -0
  77. data/lib/madmin/fields/has_many.rb +17 -0
  78. data/lib/madmin/fields/nested_has_many.rb +5 -1
  79. data/lib/madmin/fields/polymorphic.rb +1 -1
  80. data/lib/madmin/fields/select.rb +9 -0
  81. data/lib/madmin/generator_helpers.rb +6 -2
  82. data/lib/madmin/menu.rb +70 -0
  83. data/lib/madmin/resource.rb +56 -24
  84. data/lib/madmin/search.rb +1 -1
  85. data/lib/madmin/version.rb +1 -1
  86. data/lib/madmin.rb +23 -1
  87. metadata +61 -13
  88. data/app/assets/config/manifest.js +0 -2
  89. data/app/assets/stylesheets/actiontext.scss +0 -36
  90. data/app/assets/stylesheets/application.css +0 -15
  91. data/app/views/madmin/application/_menu_resources.html.erb +0 -7
@@ -1,62 +1,68 @@
1
- <div class="md:flex justify-between items-center space-y-4 md:space-y-0">
2
- <h1 class="text-xl font-semibold"><%= resource.friendly_name.pluralize %></h1>
3
-
4
- <div class="flex-grow flex md:justify-end gap-4">
5
- <form class="flex items-center gap-2 relative">
6
- <%= hidden_field_tag :page, params[:page], value: 1, class: "hidden" %>
7
- <%= search_field_tag :q, params[:q], placeholder: "Search", class: "rounded-full px-4 focus:bg-white focus:border-blue-500" %>
8
- <%= link_to clear_search_params, class: "absolute top-1/2 right-3 text-gray-500 bg-white transform -translate-y-1/2" do %>
9
- <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
10
- <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clip-rule="evenodd" />
11
- </svg>
12
- <% end %>
1
+ <%= content_for :title, resource.friendly_name.pluralize %>
2
+
3
+ <header class="header">
4
+ <h1><%= resource.friendly_name.pluralize %></h1>
5
+
6
+ <div class="actions">
7
+ <form class="search">
8
+ <%= hidden_field_tag :page, params[:page], value: 1 %>
9
+ <%= search_field_tag :q, params[:q], placeholder: "Search" %>
13
10
  </form>
14
11
 
15
- <%= link_to resource.new_path, class: "bg-white hover:bg-gray-100 text-gray-800 font-semibold py-2 px-4 border border-gray-400 rounded shadow" do %>
16
- New <span class="hidden md:inline"><%= resource.friendly_name %></span>
17
- <% end %>
12
+ <%= link_to clear_search_params, class: "btn btn-secondary" do %>
13
+ <svg xmlns="http://www.w3.org/2000/svg" height="1rem" width="1rem" viewBox="0 0 20 20" fill="currentColor">
14
+ <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clip-rule="evenodd" />
15
+ </svg>
16
+ <% end if params[:q].present? %>
17
+
18
+ <%= link_to "New #{resource.friendly_name}", resource.new_path, class: "btn btn-secondary" %>
18
19
  </div>
19
- </div>
20
+ </header>
20
21
 
21
- <div class="mb-4">
22
+ <nav class="scopes">
22
23
  <% if resource.scopes.any? %>
23
- <%= link_to "All", resource.index_path, class: class_names("p-2 rounded", {"bg-gray-100" => params[:scope].blank?}) %>
24
+ <%= link_to "All", resource.index_path, class: class_names("btn btn-secondary", {"active" => params[:scope].blank?}) %>
24
25
  <% end %>
25
26
 
26
27
  <% resource.scopes.each do |scope| %>
27
- <%= link_to scope.to_s.humanize, resource.index_path(scope: scope), class: class_names("p-2 rounded", {"bg-gray-100" => params[:scope] == scope.to_s}) %>
28
+ <%= link_to scope.to_s.humanize, resource.index_path(scope: scope), class: class_names("btn btn-secondary", {"active" => params[:scope] == scope.to_s}) %>
28
29
  <% end %>
29
- </div>
30
- <div class="min-w-full max-w-xl overflow-x-auto pb-4">
31
- <table class="min-w-full divide-y divide-gray-200">
30
+ </nav>
31
+
32
+ <div class="table-scroll">
33
+ <table>
32
34
  <thead>
33
- <tr class="border-b border-gray-200">
35
+ <tr>
34
36
  <% resource.attributes.values.each do |attribute| %>
35
37
  <% next if attribute.field.nil? %>
36
38
  <% next unless attribute.field.visible?(action_name) %>
37
39
 
38
- <th class="py-2 px-4 text-left text-xs text-gray-500 font-medium uppercase whitespace-nowrap"><%= sortable attribute.name, attribute.name.to_s.titleize %></th>
40
+ <th><%= sortable attribute.name, attribute.name.to_s.titleize %></th>
39
41
  <% end %>
40
- <th class="py-2 px-4 text-left text-xs text-gray-500 font-medium uppercase">Actions</th>
42
+ <th></th>
41
43
  </tr>
42
44
  </thead>
43
45
 
44
- <tbody class="text-sm divide-y">
46
+ <tbody>
45
47
  <% @records.each do |record| %>
46
48
  <tr>
47
49
  <% resource.attributes.values.each do |attribute| %>
48
50
  <% next if attribute.field.nil? %>
49
51
  <% next unless attribute.field.visible?(action_name) %>
50
- <td class="px-4 py-2"><%= render partial: attribute.field.to_partial_path("index"), locals: { field: attribute.field, record: record, resource: resource } %></td>
52
+ <td><%= render partial: attribute.field.to_partial_path("index"), locals: { field: attribute.field, record: record, resource: resource } %></td>
51
53
  <% end %>
52
54
 
53
- <td class="px-4 py-2 text-center">
54
- <%= link_to "View", resource.show_path(record), class: "text-blue-500" %>
55
- <%= link_to "Edit", resource.edit_path(record), class: "text-blue-500" %>
55
+ <td>
56
+ <%= link_to "View", resource.show_path(record) %>
57
+ <%= link_to "Edit", resource.edit_path(record) %>
56
58
  </td>
57
59
  </tr>
58
60
  <% end %>
59
61
  </tbody>
60
62
  </table>
61
63
  </div>
62
- <%== pagy_nav @pagy %>
64
+
65
+ <div class="pagination">
66
+ <%== pagy_nav @pagy if @pagy.pages > 1 %>
67
+ <span>Showing <%= tag.strong @pagy.in %> of <%= tag.strong @pagy.count %></span>
68
+ </div>
@@ -1,7 +1,11 @@
1
- <h1 class="text-xl mb-4">
2
- <%= link_to resource.friendly_name.pluralize, resource.index_path, class: "text-blue-500" %>
3
- /
4
- <strong>New <%= resource.friendly_name %></strong>
5
- </h1>
1
+ <%= content_for :title, "New #{resource.friendly_name}" %>
2
+
3
+ <header class="header">
4
+ <h1>
5
+ <%= link_to resource.friendly_name.pluralize, resource.index_path %>
6
+ /
7
+ <strong>New <%= resource.friendly_name %></strong>
8
+ </h1>
9
+ </header>
6
10
 
7
11
  <%= render partial: "form", locals: { record: @record, resource: resource } %>
@@ -1,32 +1,38 @@
1
- <div class="md:flex items-center justify-between mb-4">
2
- <h1 class="text-xl">
3
- <%= link_to resource.friendly_name.pluralize, resource.index_path, class: "text-blue-500" %>
1
+ <%= content_for :title, resource.display_name(@record) %>
2
+
3
+ <header class="header">
4
+ <h1>
5
+ <%= link_to resource.friendly_name.pluralize, resource.index_path %>
4
6
  /
5
- <%= link_to resource.display_name(@record), resource.show_path(@record), class: "text-blue-500 font-bold" %>
7
+ <%= resource.display_name(@record) %>
6
8
  </h1>
7
9
 
8
- <div class="flex gap-2 items-center px-4">
10
+ <div class="actions">
9
11
  <% resource.member_actions.each do |action| %>
10
- <%= instance_eval(&action) %>
12
+ <%= instance_exec(@record, &action) %>
11
13
  <% end %>
12
- <%= link_to "Edit", resource.edit_path(@record), class: "block bg-white hover:bg-gray-100 text-gray-800 font-semibold py-2 px-4 border border-gray-400 rounded shadow" %>
13
- <%= button_to "Delete", resource.show_path(@record), method: :delete, data: { turbo_confirm: "Are you sure?" }, class: "bg-white hover:bg-gray-100 text-red-500 font-semibold py-2 px-4 border border-red-500 rounded shadow pointer-cursor" %>
14
+ <%= link_to "Edit", resource.edit_path(@record), class: "btn btn-secondary" %>
15
+ <%= button_to "Delete", resource.show_path(@record), method: :delete, data: { turbo_confirm: "Are you sure?" }, class: "btn btn-danger" %>
14
16
  </div>
15
- </div>
17
+ </header>
16
18
 
17
- <div class="divide-y">
18
- <% resource.attributes.values.each do |attribute| %>
19
- <% next if attribute.field.nil? %>
20
- <% next unless attribute.field.visible?(action_name) %>
19
+ <div class="table-scroll">
20
+ <table>
21
+ <tbody>
22
+ <% resource.attributes.values.each do |attribute| %>
23
+ <% next if attribute.field.nil? %>
24
+ <% next unless attribute.field.visible?(action_name) %>
21
25
 
22
- <div class="px-4 py-3 md:grid md:grid-cols-4 md:gap-4 md:px-6">
23
- <div class="text-sm font-medium text-gray-500">
24
- <%= attribute.field.attribute_name.to_s.titleize %>
25
- </div>
26
+ <tr>
27
+ <th class="label">
28
+ <%= attribute.field.options.label || attribute.name.to_s.titleize %>
29
+ </th>
26
30
 
27
- <div class="md:col-span-3">
28
- <%= render partial: attribute.field.to_partial_path("show"), locals: { field: attribute.field, record: @record, resource: resource } %>
29
- </div>
30
- </div>
31
- <% end %>
31
+ <td>
32
+ <%= render partial: attribute.field.to_partial_path("show"), locals: { field: attribute.field, record: @record, resource: resource } %>
33
+ </td>
34
+ </tr>
35
+ <% end %>
36
+ </tbody>
37
+ </table>
32
38
  </div>
@@ -1 +1,4 @@
1
- <h1>Madmin</h1>
1
+ <div class="prose">
2
+ <h1>Madmin Dashboard</h1>
3
+ <p>Create <code>app/views/madmin/dashboard/show.html.erb</code> to customize your dashboard.</p>
4
+ </div>
@@ -1,4 +1,11 @@
1
- <div class="block md:inline-block md:w-32 flex-shrink-0 text-gray-700">
2
- <%= render "madmin/shared/label", form: form, field: field %>
3
- </div>
4
- <%= form.file_field field.to_param %>
1
+ <%= form.file_field field.to_param, class: "form-input"%>
2
+
3
+ <% if form.object.persisted? %>
4
+ <div class="mt-2">
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 "Remove", Madmin.resource_for(value).show_path(value), data: { turbo_method: :delete, turbo_confirm: "Are you sure? You will lose any other changes."} %>
9
+ <% end %>
10
+ </div>
11
+ <% end %>
@@ -1,3 +1,7 @@
1
1
  <% if (attachment = field.value(record)) && attachment.attached? %>
2
- <%= link_to attachment.filename, main_app.url_for(attachment), target: :_blank %>
2
+ <% if attachment.variable? %>
3
+ <%= image_tag main_app.url_for(attachment), class: "max-h-8" %>
4
+ <% else %>
5
+ <%= attachment.filename %>
6
+ <% end %>
3
7
  <% end %>
@@ -1,9 +1,9 @@
1
1
  <% if (attachment = field.value(record)) && attachment.attached? %>
2
2
  <% if attachment.variable? %>
3
- <%= link_to main_app.url_for(attachment), target: :_blank do %>
4
- <%= image_tag main_app.url_for(attachment), class: "max-h-32" %>
5
- <% end %>
3
+ <%= image_tag main_app.url_for(attachment), class: "max-h-32" %>
6
4
  <% else %>
7
5
  <%= link_to attachment.filename, main_app.url_for(attachment), target: :_blank, class: "text-blue-500 underline" %>
8
6
  <% end %>
9
- <% end %>
7
+
8
+ <%= link_to "Remove", Madmin.resource_for(attachment).show_path(attachment), data: { turbo_method: :delete, turbo_confirm: "Are you sure? You will lose any other changes."} %>
9
+ <% end %>
@@ -1,4 +1 @@
1
- <div class="block md:inline-block md:w-32 flex-shrink-0 text-gray-700">
2
- <%= render "madmin/shared/label", form: form, field: field %>
3
- </div>
4
- <%= form.file_field field.attribute_name, multiple: true %>
1
+ <%= form.file_field field.attribute_name, multiple: true, class: "form-input" %>
@@ -1,4 +1 @@
1
- <div class="block md:inline-block md:w-32 flex-shrink-0 text-gray-700">
2
- <%= render "madmin/shared/label", form: form, field: field %>
3
- </div>
4
- <%= form.select field.to_param, field.options_for_select(record), { prompt: true }, { class: "form-select", data: { controller: "select", select_url_value: field.index_path } } %>
1
+ <%= form.select field.to_param, field.options_for_select(record), { prompt: true }, { data: { controller: "select", select_url_value: field.index_path } } %>
@@ -1,3 +1,4 @@
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
+ <% object_resource = Madmin.resource_for(object) %>
3
+ <%= link_to object_resource.display_name(object), object_resource.show_path(object) %>
3
4
  <% end %>
@@ -1,4 +1,3 @@
1
- <div class="block md:inline-block md:w-32 flex-shrink-0 text-gray-700">
2
- <%= render "madmin/shared/label", form: form, field: field %>
3
- </div>
4
- <%= form.check_box field.attribute_name, class: "form-input" %>
1
+ <div class="form-input">
2
+ <%= form.check_box field.attribute_name %>
3
+ </div>
@@ -0,0 +1 @@
1
+ <%= form.number_field field.attribute_name, class: "form-input" %>
@@ -0,0 +1 @@
1
+ <%= number_to_currency field.value(record) if field.value(record) %>
@@ -0,0 +1 @@
1
+ <%= number_to_currency field.value(record) if field.value(record) %>
@@ -1,4 +1 @@
1
- <div class="block md:inline-block md:w-32 flex-shrink-0 text-gray-700">
2
- <%= render "madmin/shared/label", form: form, field: field %>
3
- </div>
4
- <%= form.text_field field.attribute_name, { class: "form-select", data: { controller: "flatpickr" } } %>
1
+ <%= form.date_field field.attribute_name, class: "form-input" %>
@@ -1,4 +1 @@
1
- <div class="block md:inline-block md:w-32 flex-shrink-0 text-gray-700">
2
- <%= render "madmin/shared/label", form: form, field: field %>
3
- </div>
4
- <%= form.text_field field.attribute_name, data: { controller: "flatpickr", flatpickr_enable_time: true } %>
1
+ <%= form.datetime_field field.attribute_name, class: "form-input" %>
@@ -1,4 +1 @@
1
- <div class="block md:inline-block md:w-32 flex-shrink-0 text-gray-700">
2
- <%= render "madmin/shared/label", form: form, field: field %>
3
- </div>
4
- <%= form.number_field field.attribute_name, step: :any, class: "flex-grow form-input" %>
1
+ <%= form.number_field field.attribute_name, step: :any, class: "form-input" %>
@@ -1,4 +1 @@
1
- <div class="block md:inline-block md:w-32 flex-shrink-0 text-gray-700">
2
- <%= render "madmin/shared/label", form: form, field: field %>
3
- </div>
4
- <%= form.select field.attribute_name, field.options_for_select(record), { prompt: true }, { class: "form-select", data: { controller: "select" } } %>
1
+ <%= form.select field.attribute_name, field.options_for_select(record), { prompt: true }, { data: { controller: "select" } } %>
@@ -1,4 +1 @@
1
- <div class="block md:inline-block md:w-32 flex-shrink-0 text-gray-700">
2
- <%= render "madmin/shared/label", form: form, field: field %>
3
- </div>
4
- <%= form.file_field field.attribute_name, class: "flex-grow form-input" %>
1
+ <%= form.file_field field.attribute_name, class: "form-input" %>
@@ -1,4 +1 @@
1
- <div class="block md:inline-block md:w-32 flex-shrink-0 text-gray-700">
2
- <%= render "madmin/shared/label", form: form, field: field %>
3
- </div>
4
- <%= form.number_field field.attribute_name, step: :any, class: "flex-grow form-input" %>
1
+ <%= form.number_field field.attribute_name, step: :any, class: "form-input" %>
@@ -1,4 +1 @@
1
- <div class="block md:inline-block md:w-32 flex-shrink-0 text-gray-700">
2
- <%= render "madmin/shared/label", form: form, field: field %>
3
- </div>
4
- <%= form.select "#{field.attribute_name.to_s.singularize}_ids", field.options_for_select(record), { prompt: true }, { multiple: true, class: "form-select", 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, data: { controller: "select", select_url_value: field.index_path } } %>
@@ -1,5 +1,11 @@
1
- <% field.value(record).each do |object| %>
1
+ <% pagy, records = field.paginated_value(record, params) %>
2
+ <% records.each do |object| %>
2
3
  <div>
3
4
  <%= link_to Madmin.resource_for(object).display_name(object), Madmin.resource_for(object).show_path(object), class: "text-blue-500 underline" %>
4
5
  </div>
5
6
  <% end %>
7
+
8
+ <div class="pagination">
9
+ <%== pagy_nav pagy if pagy.pages > 1 %>
10
+ <span>Showing <%= tag.strong pagy.in %> of <%= tag.strong pagy.count %></span>
11
+ </div>
@@ -1,4 +1 @@
1
- <div class="block md:inline-block md:w-32 flex-shrink-0 text-gray-700">
2
- <%= render "madmin/shared/label", form: form, field: field %>
3
- </div>
4
1
  <%= field.value(record) %>
@@ -1,4 +1 @@
1
- <div class="block md:inline-block md:w-32 flex-shrink-0 text-gray-700">
2
- <%= render "madmin/shared/label", form: form, field: field %>
3
- </div>
4
- <%= form.number_field field.attribute_name, class: "flex-grow form-input" %>
1
+ <%= form.number_field field.attribute_name, class: "form-input" %>
@@ -1,5 +1 @@
1
- <% if field.attribute_name == :id %>
2
- <%= link_to field.value(record), resource.show_path(record), class: "text-blue-500 underline" %>
3
- <% else %>
4
- <%= field.value(record) %>
5
- <% end %>
1
+ <%= link_to_if field.attribute_name.to_s == resource.model.primary_key, field.value(record), resource.show_path(record) %>
@@ -1,4 +1 @@
1
- <div class="block md:inline-block md:w-32 flex-shrink-0 text-gray-700">
2
- <%= render "madmin/shared/label", form: form, field: field %>
3
- </div>
4
- <%= form.text_area field.attribute_name, class: "flex-grow form-input" %>
1
+ <%= form.text_area field.attribute_name, class: "form-input" %>
@@ -1,10 +1,9 @@
1
1
  <%= content_tag :div, class: "nested-fields border border-gray-200 rounded-lg p-5", data: { new_record: f.object.new_record? } do %>
2
2
  <% field.nested_attributes.each do |name, nested_attribute| %>
3
- <% next if nested_attribute[:field].nil? %>
4
- <% next unless nested_attribute[:field].visible?(action_name) %>
5
- <% next unless nested_attribute[:field].visible?(:form) %>
6
-
7
- <% nested_field = nested_attribute[:field] %>
3
+ <% nested_field = nested_attribute.field %>
4
+ <% next if nested_field.nil? %>
5
+ <% next unless nested_field.visible?(action_name) %>
6
+ <% next unless nested_field.visible?(:form) %>
8
7
 
9
8
  <div class="mb-4 flex">
10
9
  <%= render partial: nested_field.to_partial_path("form"), locals: { field: nested_field, record: f.object, form: f, resource: field.resource } %>
@@ -1,7 +1,3 @@
1
- <div class="block md:inline-block w-32 flex-shrink-0">
2
- <%= render "madmin/shared/label", form: form, field: field %>
3
- </div>
4
-
5
1
  <div class="container space-y-8" data-controller="nested-form">
6
2
  <template data-target="nested-form.template">
7
3
 
@@ -1,5 +1,11 @@
1
- <% field.value(record).each do |object| %>
1
+ <% pagy, records = field.paginated_value(record, params) %>
2
+ <% records.each do |object| %>
2
3
  <div>
3
4
  <%= link_to Madmin.resource_for(object).display_name(object), Madmin.resource_for(object).show_path(object), class: "text-blue-500 underline" %>
4
5
  </div>
5
6
  <% end %>
7
+
8
+ <div class="pagination">
9
+ <%== pagy_nav pagy if pagy.pages > 1 %>
10
+ <span>Showing <%= tag.strong pagy.in %> of <%= tag.strong pagy.count %></span>
11
+ </div>
@@ -1,4 +1 @@
1
- <div class="block md:inline-block md:w-32 flex-shrink-0 text-gray-700">
2
- <%= render "madmin/shared/label", form: form, field: field %>
3
- </div>
4
- <%= form.password_field field.attribute_name, class: "flex-grow form-input" %>
1
+ <%= form.password_field field.attribute_name, class: "form-input" %>
@@ -1,7 +1,4 @@
1
1
  <%= form.fields_for field.attribute_name do |pf| %>
2
- <div class="block md:inline-block md:w-32 flex-shrink-0 text-gray-700">
3
- <%= render "madmin/shared/label", form: pf, field: field %>
4
- </div>
5
- <%= pf.select :value, field.options_for_select(record).map(&:to_global_id), { selected: field.value(record)&.to_global_id, prompt: true }, { class: "form-select", data: { controller: "slimselect" } } %>
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" } } %>
6
3
  <%= pf.hidden_field :type, value: "polymorphic" %>
7
4
  <% end %>
@@ -1,6 +1 @@
1
- <div class="block md:inline-block md:w-32 flex-shrink-0 text-gray-700">
2
- <%= render "madmin/shared/label", form: form, field: field %>
3
- </div>
4
- <div class="flex-1">
5
- <%= form.rich_text_area field.attribute_name, class: "flex-grow form-input block" %>
6
- </div>
1
+ <%= form.rich_text_area field.attribute_name, class: "form-input" %>
@@ -0,0 +1 @@
1
+ <%= form.select field.attribute_name, field.options_for_select(record), { prompt: true }, { data: { controller: "select" } } %>
@@ -0,0 +1 @@
1
+ <%= field.value(record) %>
@@ -0,0 +1 @@
1
+ <%= field.value(record) %>
@@ -1,4 +1 @@
1
- <div class="block md:inline-block md:w-32 flex-shrink-0 text-gray-700">
2
- <%= render "madmin/shared/label", form: form, field: field %>
3
- </div>
4
- <%= form.text_field field.attribute_name, class: "flex-grow form-input" %>
1
+ <%= form.text_field field.attribute_name, class: "form-input", placeholder: field.options.placeholder %>
@@ -1,4 +1 @@
1
- <div class="block md:inline-block md:w-32 flex-shrink-0 text-gray-700">
2
- <%= render "madmin/shared/label", form: form, field: field %>
3
- </div>
4
- <%= form.text_area field.attribute_name, class: "flex-grow form-input" %>
1
+ <%= form.text_area field.attribute_name, class: "form-input" %>
@@ -1,4 +1,4 @@
1
- <%= form.label field.attribute_name %>
1
+ <%= form.label field.attribute_name, field.options.label %>
2
2
  <% if field.required? %>
3
- <span class="text-red-500">*</span>
3
+ <span class="required">*</span>
4
4
  <% end %>
@@ -0,0 +1,10 @@
1
+ pin "application", to: "madmin/application.js", preload: true
2
+ pin "@hotwired/turbo-rails", to: "turbo.min.js", preload: true
3
+ pin "@hotwired/stimulus", to: "stimulus.min.js", preload: true
4
+ pin "@hotwired/stimulus-loading", to: "stimulus-loading.js", preload: true
5
+ pin "trix"
6
+ pin "@rails/actiontext", to: "actiontext.esm.js"
7
+ pin_all_from Madmin::Engine.root.join("app/javascript/madmin/controllers"), under: "controllers", to: "madmin/controllers"
8
+
9
+ pin "tom-select", to: "https://ga.jspm.io/npm:tom-select@2.4.1/dist/js/tom-select.complete.js"
10
+ pin "tailwindcss-stimulus-components", to: "https://ga.jspm.io/npm:tailwindcss-stimulus-components@6.1.2/dist/tailwindcss-stimulus-components.module.js"
@@ -1,4 +1 @@
1
- <div class="block md:inline-block md:w-32 flex-shrink-0 text-gray-700">
2
- <%= render "madmin/shared/label", form: form, field: field %>
3
- </div>
4
- <%= form.text_field field.attribute_name, class: "flex-grow form-input" %>
1
+ <%= form.text_field field.attribute_name, class: "form-input" %>
@@ -5,18 +5,11 @@ module Madmin
5
5
  def authenticate_admin_user
6
6
  # TODO: Add your authentication logic here
7
7
 
8
- # For example, we could redirect if the user isn't an admin
9
- # redirect_to "/", alert: "Not authorized." unless user_signed_in? && current_user.admin?
10
- end
11
-
12
- # Authenticate with Clearance
13
- # include Clearance::Controller
14
- # before_action :require_login
8
+ # For example, with Rails 8 authentication
9
+ # redirect_to "/", alert: "Not authorized." unless authenticated? && Current.user.admin?
15
10
 
16
- # Authenticate with Devise
17
- # before_action :authenticate_user!
18
-
19
- # Authenticate with Basic Auth
20
- # http_basic_authenticate_with(name: Rails.application.credentials.admin_username, password: Rails.application.credentials.admin_password)
11
+ # Or with Devise
12
+ # redirect_to "/", alert: "Not authorized." unless current_user&.admin?
13
+ end
21
14
  end
22
15
  end
@@ -20,7 +20,7 @@ module Madmin
20
20
 
21
21
  def generate_route
22
22
  if route_namespace_exists?
23
- route "resources :#{plural_name}", namespace: class_path, indentation: separated_routes_file? ? 2 : 4, sentinel: /namespace :madmin do\s*\n/m
23
+ route "resources :#{plural_name}", namespace: class_path, indentation: separated_routes_file? ? 2 : 4, sentinel: /namespace :madmin[^\n]*do\s*\n/m
24
24
  else
25
25
  route "resources :#{plural_name}", namespace: [:madmin] + class_path
26
26
  end
@@ -9,17 +9,19 @@ class <%= class_name %>Resource < Madmin::Resource
9
9
  attribute :<%= association_name %>
10
10
  <% end -%>
11
11
 
12
- # Uncomment this to customize the display name of records in the admin area.
13
- # def self.display_name(record)
14
- # record.name
15
- # end
12
+ # Add scopes to easily filter records
13
+ # scope :published
16
14
 
17
- # Uncomment this to customize the default sort column and direction.
18
- # def self.default_sort_column
19
- # "created_at"
15
+ # Add actions to the resource's show page
16
+ # member_action do |record|
17
+ # link_to "Do Something", some_path
20
18
  # end
19
+
20
+ # Customize the display name of records in the admin area.
21
+ # def self.display_name(record) = record.name
22
+
23
+ # Customize the default sort column and direction.
24
+ # def self.default_sort_column = "created_at"
21
25
  #
22
- # def self.default_sort_direction
23
- # "desc"
24
- # end
26
+ # def self.default_sort_direction = "desc"
25
27
  end
data/lib/madmin/engine.rb CHANGED
@@ -1,3 +1,5 @@
1
+ require "importmap-rails"
2
+
1
3
  module Madmin
2
4
  class Engine < ::Rails::Engine
3
5
  isolate_namespace Madmin
@@ -9,6 +11,30 @@ module Madmin
9
11
 
10
12
  config.to_prepare do
11
13
  Madmin.reset_resources!
14
+ Madmin.site_name ||= Rails.application.class.module_parent_name
15
+ end
16
+
17
+ initializer "madmin.assets" do |app|
18
+ if app.config.respond_to?(:assets)
19
+ app.config.assets.paths << root.join("app/assets/stylesheets")
20
+ app.config.assets.paths << root.join("app/javascript")
21
+ app.config.assets.precompile += %w[madmin_manifest]
22
+
23
+ Madmin.stylesheets << if defined?(::Sprockets)
24
+ "madmin/application-sprockets"
25
+ else
26
+ "madmin/application"
27
+ end
28
+ end
29
+ end
30
+
31
+ initializer "madmin.importmap", before: "importmap" do |app|
32
+ Madmin.importmap.draw root.join("config/importmap.rb")
33
+ Madmin.importmap.cache_sweeper watches: root.join("app/javascript")
34
+
35
+ ActiveSupport.on_load(:action_controller_base) do
36
+ before_action { Madmin.importmap.cache_sweeper.execute_if_updated }
37
+ end
12
38
  end
13
39
  end
14
40
  end