jav_madmin 2.6.2

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 (172) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +294 -0
  4. data/Rakefile +30 -0
  5. data/app/assets/config/madmin_manifest.js +3 -0
  6. data/app/assets/stylesheets/madmin/actiontext.css +31 -0
  7. data/app/assets/stylesheets/madmin/application-sprockets.css +11 -0
  8. data/app/assets/stylesheets/madmin/application.css +9 -0
  9. data/app/assets/stylesheets/madmin/base.css +144 -0
  10. data/app/assets/stylesheets/madmin/buttons.css +53 -0
  11. data/app/assets/stylesheets/madmin/forms.css +90 -0
  12. data/app/assets/stylesheets/madmin/pagination.css +59 -0
  13. data/app/assets/stylesheets/madmin/reset.css +242 -0
  14. data/app/assets/stylesheets/madmin/sidebar.css +179 -0
  15. data/app/assets/stylesheets/madmin/tables.css +71 -0
  16. data/app/controllers/madmin/application_controller.rb +17 -0
  17. data/app/controllers/madmin/base_controller.rb +15 -0
  18. data/app/controllers/madmin/dashboard_controller.rb +6 -0
  19. data/app/controllers/madmin/resource_controller.rb +119 -0
  20. data/app/helpers/madmin/application_helper.rb +10 -0
  21. data/app/helpers/madmin/nav_helper.rb +34 -0
  22. data/app/helpers/madmin/sort_helper.rb +48 -0
  23. data/app/javascript/madmin/application.js +3 -0
  24. data/app/javascript/madmin/controllers/application.js +12 -0
  25. data/app/javascript/madmin/controllers/index.js +5 -0
  26. data/app/javascript/madmin/controllers/mobile_nav_controller.js +50 -0
  27. data/app/javascript/madmin/controllers/nested_form_controller.js +34 -0
  28. data/app/javascript/madmin/controllers/select_controller.js +37 -0
  29. data/app/views/layouts/madmin/application.html.erb +41 -0
  30. data/app/views/madmin/application/_flash.html.erb +13 -0
  31. data/app/views/madmin/application/_form.html.erb +24 -0
  32. data/app/views/madmin/application/_javascript.html.erb +8 -0
  33. data/app/views/madmin/application/_missing_resource.html.erb +8 -0
  34. data/app/views/madmin/application/_navigation.html.erb +22 -0
  35. data/app/views/madmin/application/edit.html.erb +11 -0
  36. data/app/views/madmin/application/index.html.erb +85 -0
  37. data/app/views/madmin/application/new.html.erb +11 -0
  38. data/app/views/madmin/application/show.html.erb +40 -0
  39. data/app/views/madmin/dashboard/show.html.erb +2 -0
  40. data/app/views/madmin/fields/attachment/_form.html.erb +11 -0
  41. data/app/views/madmin/fields/attachment/_index.html.erb +7 -0
  42. data/app/views/madmin/fields/attachment/_show.html.erb +9 -0
  43. data/app/views/madmin/fields/attachments/_form.html.erb +1 -0
  44. data/app/views/madmin/fields/attachments/_index.html.erb +1 -0
  45. data/app/views/madmin/fields/attachments/_show.html.erb +11 -0
  46. data/app/views/madmin/fields/belongs_to/_form.html.erb +1 -0
  47. data/app/views/madmin/fields/belongs_to/_index.html.erb +4 -0
  48. data/app/views/madmin/fields/belongs_to/_show.html.erb +7 -0
  49. data/app/views/madmin/fields/boolean/_form.html.erb +3 -0
  50. data/app/views/madmin/fields/boolean/_index.html.erb +1 -0
  51. data/app/views/madmin/fields/boolean/_show.html.erb +1 -0
  52. data/app/views/madmin/fields/currency/_form.html.erb +1 -0
  53. data/app/views/madmin/fields/currency/_index.html.erb +1 -0
  54. data/app/views/madmin/fields/currency/_show.html.erb +1 -0
  55. data/app/views/madmin/fields/date/_form.html.erb +1 -0
  56. data/app/views/madmin/fields/date/_index.html.erb +1 -0
  57. data/app/views/madmin/fields/date/_show.html.erb +1 -0
  58. data/app/views/madmin/fields/date_time/_form.html.erb +1 -0
  59. data/app/views/madmin/fields/date_time/_index.html.erb +1 -0
  60. data/app/views/madmin/fields/date_time/_show.html.erb +1 -0
  61. data/app/views/madmin/fields/decimal/_form.html.erb +1 -0
  62. data/app/views/madmin/fields/decimal/_index.html.erb +1 -0
  63. data/app/views/madmin/fields/decimal/_show.html.erb +1 -0
  64. data/app/views/madmin/fields/enum/_form.html.erb +1 -0
  65. data/app/views/madmin/fields/enum/_index.html.erb +1 -0
  66. data/app/views/madmin/fields/enum/_show.html.erb +1 -0
  67. data/app/views/madmin/fields/file/_form.html.erb +1 -0
  68. data/app/views/madmin/fields/file/_index.html.erb +1 -0
  69. data/app/views/madmin/fields/file/_show.html.erb +6 -0
  70. data/app/views/madmin/fields/float/_form.html.erb +1 -0
  71. data/app/views/madmin/fields/float/_index.html.erb +1 -0
  72. data/app/views/madmin/fields/float/_show.html.erb +1 -0
  73. data/app/views/madmin/fields/has_many/_form.html.erb +1 -0
  74. data/app/views/madmin/fields/has_many/_index.html.erb +1 -0
  75. data/app/views/madmin/fields/has_many/_show.html.erb +18 -0
  76. data/app/views/madmin/fields/has_one/_form.html.erb +1 -0
  77. data/app/views/madmin/fields/has_one/_index.html.erb +3 -0
  78. data/app/views/madmin/fields/has_one/_show.html.erb +7 -0
  79. data/app/views/madmin/fields/integer/_form.html.erb +1 -0
  80. data/app/views/madmin/fields/integer/_index.html.erb +1 -0
  81. data/app/views/madmin/fields/integer/_show.html.erb +1 -0
  82. data/app/views/madmin/fields/json/_form.html.erb +1 -0
  83. data/app/views/madmin/fields/json/_index.html.erb +1 -0
  84. data/app/views/madmin/fields/json/_show.html.erb +1 -0
  85. data/app/views/madmin/fields/nested_has_many/_fields.html.erb +17 -0
  86. data/app/views/madmin/fields/nested_has_many/_form.html.erb +28 -0
  87. data/app/views/madmin/fields/nested_has_many/_index.html.erb +1 -0
  88. data/app/views/madmin/fields/nested_has_many/_show.html.erb +18 -0
  89. data/app/views/madmin/fields/password/_form.html.erb +1 -0
  90. data/app/views/madmin/fields/password/_index.html.erb +1 -0
  91. data/app/views/madmin/fields/password/_show.html.erb +1 -0
  92. data/app/views/madmin/fields/polymorphic/_form.html.erb +4 -0
  93. data/app/views/madmin/fields/polymorphic/_index.html.erb +3 -0
  94. data/app/views/madmin/fields/polymorphic/_show.html.erb +7 -0
  95. data/app/views/madmin/fields/rich_text/_form.html.erb +1 -0
  96. data/app/views/madmin/fields/rich_text/_index.html.erb +1 -0
  97. data/app/views/madmin/fields/rich_text/_show.html.erb +3 -0
  98. data/app/views/madmin/fields/select/_form.html.erb +1 -0
  99. data/app/views/madmin/fields/select/_index.html.erb +1 -0
  100. data/app/views/madmin/fields/select/_show.html.erb +1 -0
  101. data/app/views/madmin/fields/string/_form.html.erb +1 -0
  102. data/app/views/madmin/fields/string/_index.html.erb +1 -0
  103. data/app/views/madmin/fields/string/_show.html.erb +1 -0
  104. data/app/views/madmin/fields/text/_form.html.erb +1 -0
  105. data/app/views/madmin/fields/text/_index.html.erb +1 -0
  106. data/app/views/madmin/fields/text/_show.html.erb +1 -0
  107. data/app/views/madmin/fields/time/_form.html.erb +5 -0
  108. data/app/views/madmin/fields/time/_index.html.erb +1 -0
  109. data/app/views/madmin/fields/time/_show.html.erb +1 -0
  110. data/app/views/madmin/shared/_label.html.erb +4 -0
  111. data/config/importmap.rb +15 -0
  112. data/config/locales/el.yml +42 -0
  113. data/config/locales/en.yml +42 -0
  114. data/config/locales/fr.yml +42 -0
  115. data/config/locales/ko.yml +40 -0
  116. data/lib/generators/madmin/field/field_generator.rb +31 -0
  117. data/lib/generators/madmin/field/templates/_form.html.erb +1 -0
  118. data/lib/generators/madmin/field/templates/_index.html.erb +1 -0
  119. data/lib/generators/madmin/field/templates/_show.html.erb +1 -0
  120. data/lib/generators/madmin/field/templates/field.rb.tt +26 -0
  121. data/lib/generators/madmin/install/install_generator.rb +55 -0
  122. data/lib/generators/madmin/install/templates/controller.rb.tt +15 -0
  123. data/lib/generators/madmin/install/templates/routes.rb.tt +3 -0
  124. data/lib/generators/madmin/resource/resource_generator.rb +73 -0
  125. data/lib/generators/madmin/resource/templates/controller.rb.tt +10 -0
  126. data/lib/generators/madmin/resource/templates/resource.rb.tt +33 -0
  127. data/lib/generators/madmin/views/edit_generator.rb +16 -0
  128. data/lib/generators/madmin/views/form_generator.rb +15 -0
  129. data/lib/generators/madmin/views/index_generator.rb +15 -0
  130. data/lib/generators/madmin/views/javascript_generator.rb +15 -0
  131. data/lib/generators/madmin/views/layout_generator.rb +21 -0
  132. data/lib/generators/madmin/views/navigation_generator.rb +15 -0
  133. data/lib/generators/madmin/views/new_generator.rb +16 -0
  134. data/lib/generators/madmin/views/show_generator.rb +15 -0
  135. data/lib/generators/madmin/views/views_generator.rb +16 -0
  136. data/lib/madmin/engine.rb +47 -0
  137. data/lib/madmin/field.rb +67 -0
  138. data/lib/madmin/fields/attachment.rb +6 -0
  139. data/lib/madmin/fields/attachments.rb +9 -0
  140. data/lib/madmin/fields/belongs_to.rb +29 -0
  141. data/lib/madmin/fields/boolean.rb +6 -0
  142. data/lib/madmin/fields/currency.rb +15 -0
  143. data/lib/madmin/fields/date.rb +6 -0
  144. data/lib/madmin/fields/date_time.rb +6 -0
  145. data/lib/madmin/fields/decimal.rb +6 -0
  146. data/lib/madmin/fields/enum.rb +9 -0
  147. data/lib/madmin/fields/file.rb +9 -0
  148. data/lib/madmin/fields/float.rb +6 -0
  149. data/lib/madmin/fields/has_many.rb +62 -0
  150. data/lib/madmin/fields/has_one.rb +10 -0
  151. data/lib/madmin/fields/integer.rb +6 -0
  152. data/lib/madmin/fields/json.rb +6 -0
  153. data/lib/madmin/fields/nested_has_many.rb +44 -0
  154. data/lib/madmin/fields/password.rb +6 -0
  155. data/lib/madmin/fields/polymorphic.rb +22 -0
  156. data/lib/madmin/fields/rich_text.rb +6 -0
  157. data/lib/madmin/fields/select.rb +9 -0
  158. data/lib/madmin/fields/string.rb +9 -0
  159. data/lib/madmin/fields/text.rb +9 -0
  160. data/lib/madmin/fields/time.rb +6 -0
  161. data/lib/madmin/generator_helpers.rb +59 -0
  162. data/lib/madmin/member_action.rb +19 -0
  163. data/lib/madmin/menu.rb +70 -0
  164. data/lib/madmin/namespace.rb +35 -0
  165. data/lib/madmin/resource.rb +295 -0
  166. data/lib/madmin/resource_builder.rb +88 -0
  167. data/lib/madmin/search.rb +62 -0
  168. data/lib/madmin/version.rb +3 -0
  169. data/lib/madmin/view_generator.rb +43 -0
  170. data/lib/madmin.rb +114 -0
  171. data/lib/tasks/madmin_tasks.rake +11 -0
  172. metadata +284 -0
@@ -0,0 +1,34 @@
1
+ module Madmin::NavHelper
2
+ def nav_link_to(name = nil, options = {}, html_options = {}, &block)
3
+ if block
4
+ html_options = options
5
+ options = name
6
+ name = block
7
+ end
8
+
9
+ url = url_for(options)
10
+ starts_with = html_options.delete(:starts_with)
11
+ html_options[:class] = Array.wrap(html_options[:class])
12
+ active_class = html_options.delete(:active_class) || "active"
13
+ inactive_class = html_options.delete(:inactive_class) || ""
14
+
15
+ active = if (paths = Array.wrap(starts_with)) && paths.present?
16
+ paths.any? { |path| request.path.start_with?(path) }
17
+ else
18
+ request.path == url
19
+ end
20
+
21
+ classes = active ? active_class : inactive_class
22
+ html_options[:class] << classes unless classes.empty?
23
+
24
+ html_options.except!(:class) if html_options[:class].empty?
25
+
26
+ return link_to url, html_options, &block if block
27
+
28
+ link_to name, url, html_options
29
+ end
30
+
31
+ def menu_label(label)
32
+ I18n.t("activerecord.models.#{label}", default: [:"madmin.navigation.#{label}", label.titleize])
33
+ end
34
+ end
@@ -0,0 +1,48 @@
1
+ module Madmin
2
+ module SortHelper
3
+ def sortable(column, title, options = {})
4
+ matching_column = (column.to_s == sort_column)
5
+ direction = (sort_direction == "asc") ? "desc" : "asc"
6
+
7
+ link_to resource.index_path(sort: column, direction: direction, scope: params[:scope], q: params[:q]), options do
8
+ concat title
9
+ if matching_column
10
+ concat " "
11
+ concat tag.span((sort_direction == "asc") ? asc_icon : desc_icon)
12
+ end
13
+ end
14
+ end
15
+
16
+ def sort_column
17
+ resource.sortable_columns.include?(params[:sort]) ? params[:sort] : default_sort_column
18
+ end
19
+
20
+ def sort_direction
21
+ ["asc", "desc"].include?(params[:direction]) ? params[:direction] : default_sort_direction
22
+ end
23
+
24
+ def default_sort_column
25
+ resource.try(:default_sort_column) || (["created_at", "id", "uuid"] & resource.sortable_columns).first || resource.sortable_columns.first
26
+ end
27
+
28
+ def default_sort_direction
29
+ resource.try(:default_sort_direction) || "desc"
30
+ end
31
+
32
+ def asc_icon
33
+ <<~SVG.html_safe
34
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" height="1rem" width="1rem">
35
+ <path fill-rule="evenodd" d="M11.78 9.78a.75.75 0 0 1-1.06 0L8 7.06 5.28 9.78a.75.75 0 0 1-1.06-1.06l3.25-3.25a.75.75 0 0 1 1.06 0l3.25 3.25a.75.75 0 0 1 0 1.06Z" clip-rule="evenodd" />
36
+ </svg>
37
+ SVG
38
+ end
39
+
40
+ def desc_icon
41
+ <<~SVG.html_safe
42
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" height="1rem" width="1rem">
43
+ <path fill-rule="evenodd" d="M4.22 6.22a.75.75 0 0 1 1.06 0L8 8.94l2.72-2.72a.75.75 0 1 1 1.06 1.06l-3.25 3.25a.75.75 0 0 1-1.06 0L4.22 7.28a.75.75 0 0 1 0-1.06Z" clip-rule="evenodd" />
44
+ </svg>
45
+ SVG
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,3 @@
1
+ import "@hotwired/turbo-rails"
2
+ import "@rails/actiontext"
3
+ import "controllers"
@@ -0,0 +1,12 @@
1
+ import { Application } from "@hotwired/stimulus"
2
+
3
+ const application = Application.start()
4
+
5
+ // Configure Stimulus development experience
6
+ application.debug = false
7
+ window.Stimulus = application
8
+
9
+ export { application }
10
+
11
+ import { Dropdown } from "tailwindcss-stimulus-components"
12
+ application.register("dropdown", Dropdown)
@@ -0,0 +1,5 @@
1
+ import { application } from "controllers/application"
2
+
3
+ // Eager load all controllers defined in the import map under controllers/**/*_controller
4
+ import { eagerLoadControllersFrom } from "@hotwired/stimulus-loading"
5
+ eagerLoadControllersFrom("controllers", application)
@@ -0,0 +1,50 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+
3
+ export default class extends Controller {
4
+ static targets = ["menu", "overlay"]
5
+
6
+ connect() {
7
+ this.handleEscape = this.handleEscape.bind(this)
8
+ }
9
+
10
+ toggle() {
11
+ const open = this.menuTarget.classList.toggle("open")
12
+ this.element.setAttribute("aria-expanded", open)
13
+ this.toggleOverlay(open)
14
+ this.toggleBodyScroll(open)
15
+ this.toggleEscapeListener(open)
16
+ }
17
+
18
+ close() {
19
+ if (this.menuTarget.classList.contains("open")) {
20
+ this.toggle()
21
+ }
22
+ }
23
+
24
+ handleEscape(event) {
25
+ if (event.key === "Escape") {
26
+ this.close()
27
+ }
28
+ }
29
+
30
+ disconnect() {
31
+ this.toggleEscapeListener(false)
32
+ this.toggleBodyScroll(false)
33
+ this.close()
34
+ }
35
+
36
+ toggleOverlay(open) {
37
+ if (this.hasOverlayTarget) {
38
+ this.overlayTarget.classList.toggle("is-active", open)
39
+ }
40
+ }
41
+
42
+ toggleBodyScroll(open) {
43
+ document.body.style.overflow = open ? 'hidden' : ''
44
+ }
45
+
46
+ toggleEscapeListener(open) {
47
+ const method = open ? 'addEventListener' : 'removeEventListener'
48
+ document[method]("keydown", this.handleEscape)
49
+ }
50
+ }
@@ -0,0 +1,34 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+
3
+ export default class extends Controller {
4
+ static get targets() {
5
+ return [ "links", "template" ]
6
+ }
7
+
8
+ connect() {
9
+ this.wrapperClass = this.data.get("wrapperClass") || "nested-fields"
10
+ }
11
+
12
+ add_association(event) {
13
+ event.preventDefault()
14
+
15
+ var content = this.templateTarget.innerHTML.replace(/NEW_RECORD/g, new Date().getTime())
16
+ this.linksTarget.insertAdjacentHTML('beforebegin', content)
17
+ }
18
+
19
+ remove_association(event) {
20
+ event.preventDefault()
21
+
22
+ let wrapper = event.target.closest("." + this.wrapperClass)
23
+
24
+ // New records are simply removed from the page
25
+ if (wrapper.dataset.newRecord == "true") {
26
+ wrapper.remove()
27
+
28
+ // Existing records are hidden and flagged for deletion
29
+ } else {
30
+ wrapper.querySelector("input[name*='_destroy']").value = 1
31
+ wrapper.style.display = 'none'
32
+ }
33
+ }
34
+ }
@@ -0,0 +1,37 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+ import TomSelect from "tom-select"
3
+
4
+ export default class extends Controller {
5
+ static values = {
6
+ options: Object,
7
+ url: String
8
+ }
9
+
10
+ connect() {
11
+ let options = {
12
+ plugins: ['remove_button'],
13
+ valueField: 'id',
14
+ labelField: 'name',
15
+ searchField: 'name',
16
+ }
17
+
18
+ if (this.hasUrlValue) {
19
+ options["load"] = (search, callback) => {
20
+ let url = search ? `${this.urlValue}?q=${search}` : this.urlValue;
21
+ fetch(url)
22
+ .then(response => response.json())
23
+ .then(json => {
24
+ callback(json);
25
+ }).catch(() => {
26
+ callback();
27
+ });
28
+ }
29
+ }
30
+
31
+ this.select = new TomSelect(this.element, options)
32
+ }
33
+
34
+ disconnect() {
35
+ this.select.destroy()
36
+ }
37
+ }
@@ -0,0 +1,41 @@
1
+ <!DOCTYPE html>
2
+ <html lang="<%= I18n.locale %>">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="ROBOTS" content="NOODP">
6
+ <meta name="viewport" content="initial-scale=1">
7
+ <title>
8
+ <% if content_for? :title %>
9
+ <%= yield(:title) %> -
10
+ <% end %>
11
+ <%= Madmin.site_name %> <%= t("madmin.layout.admin_suffix") %>
12
+ </title>
13
+ <%= csrf_meta_tags %>
14
+ <%= render "javascript" %>
15
+ </head>
16
+ <body class="<%= controller_name %> <%= action_name %>" data-controller="mobile-nav">
17
+ <header>
18
+ <%= render "flash" %>
19
+ </header>
20
+ <header id="navbar">
21
+ <div class="nav-group">
22
+ <button id="hamburger-menu" type="button" data-action="click->mobile-nav#toggle" aria-label="<%= t("madmin.layout.open_menu") %>" aria-expanded="false" aria-controls="sidebar">
23
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="size-5"> <path fill-rule="evenodd" d="M2 4.75A.75.75 0 0 1 2.75 4h14.5a.75.75 0 0 1 0 1.5H2.75A.75.75 0 0 1 2 4.75ZM2 10a.75.75 0 0 1 .75-.75h14.5a.75.75 0 0 1 0 1.5H2.75A.75.75 0 0 1 2 10Zm0 5.25a.75.75 0 0 1 .75-.75h14.5a.75.75 0 0 1 0 1.5H2.75a.75.75 0 0 1-.75-.75Z" clip-rule="evenodd" /> </svg>
24
+ </button>
25
+ <%= link_to Madmin.site_name, try(:root_url) || madmin_root_url, data: {turbo: false} %>
26
+ </div>
27
+ </header>
28
+
29
+ <main>
30
+ <aside id="sidebar" data-mobile-nav-target="menu">
31
+ <%= render "navigation" %>
32
+ </aside>
33
+
34
+ <div>
35
+ <%= yield %>
36
+ </div>
37
+ </main>
38
+
39
+ <div data-mobile-nav-target="overlay" data-action="click->mobile-nav#close" class="mobile-nav-overlay"></div>
40
+ </body>
41
+ </html>
@@ -0,0 +1,13 @@
1
+ <% if alert %>
2
+ <div class="alert alert-danger">
3
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor"><path fill-rule="evenodd" d="M8 15A7 7 0 1 0 8 1a7 7 0 0 0 0 14ZM8 4a.75.75 0 0 1 .75.75v3a.75.75 0 0 1-1.5 0v-3A.75.75 0 0 1 8 4Zm0 8a1 1 0 1 0 0-2 1 1 0 0 0 0 2Z" clip-rule="evenodd"></path></svg>
4
+ <%= alert %>
5
+ </div>
6
+ <% end %>
7
+
8
+ <% if notice %>
9
+ <div class="alert alert-notice">
10
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor"><path fill-rule="evenodd" d="M8 15A7 7 0 1 0 8 1a7 7 0 0 0 0 14Zm3.844-8.791a.75.75 0 0 0-1.188-.918l-3.7 4.79-1.649-1.833a.75.75 0 1 0-1.114 1.004l2.25 2.5a.75.75 0 0 0 1.15-.043l4.25-5.5Z" clip-rule="evenodd"></path></svg>
11
+ <%= notice %>
12
+ </div>
13
+ <% end %>
@@ -0,0 +1,24 @@
1
+ <%= form_with model: [:madmin, record], url: (record.persisted? ? resource.show_path(record) : resource.index_path), local: true do |form| %>
2
+ <% if form.object.errors.any? %>
3
+ <div class="alert alert-danger">
4
+ <div class=""><%= t("madmin.form.errors", count: form.object.errors.full_messages.count) %>:</div>
5
+
6
+ <ul>
7
+ <% form.object.errors.full_messages.each do |message| %>
8
+ <li><%= message %></li>
9
+ <% end %>
10
+ </ul>
11
+ </div>
12
+ <% end %>
13
+
14
+ <% resource.attributes.values.select{ _1.field.present? && _1.field.visible?(action_name) }.each do |attribute| %>
15
+ <div class="form-group">
16
+ <%= render "madmin/shared/label", form: form, field: attribute.field %>
17
+ <%= render partial: attribute.field.to_partial_path("form"), locals: { field: attribute.field, record: record, form: form, resource: resource } %>
18
+ <%= tag.div attribute.field.options.description, class: "form-description" if attribute.field.options.description.present? %>
19
+ </div>
20
+ <% end %>
21
+
22
+ <%= form.submit class: "btn btn-primary" %>
23
+ <%= link_to t("madmin.actions.cancel"), (record.persisted? ? resource.show_path(record) : resource.index_path), class: "btn" %>
24
+ <% end %>
@@ -0,0 +1,8 @@
1
+ <%= javascript_importmap_tags "application", importmap: Madmin.importmap %>
2
+
3
+ <%= tag.script 'import "trix"'.html_safe, type: "module" if defined?(::Trix) || Rails.gem_version < Gem::Version.new("8.1.0.beta1") %>
4
+ <%= tag.script 'import "lexxy"'.html_safe, type: "module" if defined?(::Lexxy) %>
5
+
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,8 @@
1
+ <div class="error"><%= t("madmin.missing_resource.message", resource: resource_name) %></div>
2
+ <% if Rails.env.development? %>
3
+ <div><%= t("madmin.missing_resource.create_hint") %>
4
+ <code>
5
+ bin/rails generate madmin:resource <%= resource_name.split("Resource").first %>
6
+ </code>
7
+ </div>
8
+ <% end %>
@@ -0,0 +1,22 @@
1
+ <nav>
2
+ <%= nav_link_to t("madmin.navigation.dashboard"), madmin_root_path %>
3
+
4
+ <% Madmin.menu.render do |item| %>
5
+ <% if item.url %>
6
+ <%= nav_link_to menu_label(item.label), item.url, starts_with: item.url %>
7
+ <% else %>
8
+ <h4><%= menu_label(item.label) %></h4>
9
+ <% end %>
10
+
11
+ <% item.items.each do |item| %>
12
+ <%= nav_link_to menu_label(item.label), item.url, starts_with: item.url %>
13
+ <% end %>
14
+ <% end %>
15
+ </nav>
16
+
17
+ <footer>
18
+ <%= link_to "https://github.com/excid3/madmin", target: :_blank do %>
19
+ <svg viewBox="0 0 16 16" height="1rem" width="1rem" fill="currentColor" aria-hidden="true"><path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"></path></svg>
20
+ <%= t("madmin.navigation.github") %>
21
+ <% end %>
22
+ </footer>
@@ -0,0 +1,11 @@
1
+ <%= content_for :title, t("madmin.titles.edit", name: resource.display_name(@record)) %>
2
+
3
+ <header class="header">
4
+ <h1>
5
+ <%= link_to resource.friendly_name.pluralize(I18n.locale), resource.index_path %>
6
+ /
7
+ <strong><%= t("madmin.actions.edit") %> <%= link_to resource.display_name(@record), resource.show_path(@record) %></strong>
8
+ </h1>
9
+ </header>
10
+
11
+ <%= render partial: "form", locals: { record: @record, resource: resource } %>
@@ -0,0 +1,85 @@
1
+ <%= content_for :title, resource.friendly_name.pluralize(I18n.locale) %>
2
+
3
+ <header class="header">
4
+ <h1><%= resource.friendly_name.pluralize(I18n.locale) %></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: t("madmin.search.placeholder") %>
10
+ </form>
11
+
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
+ <% resource.collection_actions.each do |action| %>
19
+ <%= instance_exec(&action) %>
20
+ <% end %>
21
+
22
+ <% unless resource.readonly? %>
23
+ <%= link_to resource.new_path, class: "btn btn-secondary" do %>
24
+ <%= t("madmin.actions.new") %> <%= tag.span resource.friendly_name, class: "hidden md:inline-block" %>
25
+ <% end %>
26
+ <% end %>
27
+ </div>
28
+ </header>
29
+
30
+ <nav class="scopes">
31
+ <% if resource.scopes.any? %>
32
+ <%= link_to t("madmin.actions.all"), resource.index_path, class: class_names("btn btn-secondary", {"active" => params[:scope].blank?}) %>
33
+ <% end %>
34
+
35
+ <% 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}) %>
37
+ <% end %>
38
+ </nav>
39
+
40
+ <div class="table-scroll">
41
+ <table>
42
+ <thead>
43
+ <tr>
44
+ <% resource.attributes.values.each do |attribute| %>
45
+ <% next if attribute.field.nil? %>
46
+ <% next unless attribute.field.visible?(action_name) %>
47
+
48
+ <th><%= sortable attribute.name, attribute.field.label %></th>
49
+ <% end %>
50
+ <th></th>
51
+ </tr>
52
+ </thead>
53
+
54
+ <tbody>
55
+ <% @records.each do |record| %>
56
+ <tr>
57
+ <% resource.attributes.values.each do |attribute| %>
58
+ <% next if attribute.field.nil? %>
59
+ <% next unless attribute.field.visible?(action_name) %>
60
+ <td><%= render partial: attribute.field.to_partial_path("index"), locals: { field: attribute.field, record: record, resource: resource } %></td>
61
+ <% end %>
62
+
63
+ <td class="actions">
64
+ <%= link_to t("madmin.actions.view"), resource.show_path(record), class: "btn btn-secondary" %>
65
+ <%= link_to t("madmin.actions.edit"), resource.edit_path(record), class: "btn btn-secondary" unless resource.readonly? %>
66
+
67
+ <% resource.collection_member_actions.each do |action| %>
68
+ <%= instance_exec(record, &action) %>
69
+ <% end %>
70
+ </td>
71
+ </tr>
72
+ <% end %>
73
+ </tbody>
74
+ </table>
75
+ </div>
76
+
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>
@@ -0,0 +1,11 @@
1
+ <%= content_for :title, t("madmin.titles.new", name: resource.friendly_name) %>
2
+
3
+ <header class="header">
4
+ <h1>
5
+ <%= link_to resource.friendly_name.pluralize(I18n.locale), resource.index_path %>
6
+ /
7
+ <strong><%= t("madmin.titles.new", name: resource.friendly_name) %></strong>
8
+ </h1>
9
+ </header>
10
+
11
+ <%= render partial: "form", locals: { record: @record, resource: resource } %>
@@ -0,0 +1,40 @@
1
+ <%= content_for :title, resource.display_name(@record) %>
2
+
3
+ <header class="header">
4
+ <h1>
5
+ <%= link_to resource.friendly_name.pluralize(I18n.locale), resource.index_path %>
6
+ /
7
+ <%= resource.display_name(@record) %>
8
+ </h1>
9
+
10
+ <div class="actions">
11
+ <% resource.member_actions.each do |action| %>
12
+ <%= instance_exec(@record, &action) %>
13
+ <% end %>
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 %>
18
+ </div>
19
+ </header>
20
+
21
+ <div class="table-scroll">
22
+ <table>
23
+ <tbody>
24
+ <% resource.attributes.values.each do |attribute| %>
25
+ <% next if attribute.field.nil? %>
26
+ <% next unless attribute.field.visible?(action_name) %>
27
+
28
+ <tr>
29
+ <th class="label">
30
+ <%= attribute.field.label %>
31
+ </th>
32
+
33
+ <td>
34
+ <%= render partial: attribute.field.to_partial_path("show"), locals: { field: attribute.field, record: @record, resource: resource } %>
35
+ </td>
36
+ </tr>
37
+ <% end %>
38
+ </tbody>
39
+ </table>
40
+ </div>
@@ -0,0 +1,2 @@
1
+ <h1><%= t("madmin.dashboard.title") %></h1>
2
+ <p><%= t("madmin.dashboard.hint_html") %></p>
@@ -0,0 +1,11 @@
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 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
+ </div>
11
+ <% end %>
@@ -0,0 +1,7 @@
1
+ <% if (attachment = field.value(record)) && attachment.attached? %>
2
+ <% if attachment.variable? %>
3
+ <%= image_tag main_app.url_for(attachment), class: "max-h-8" %>
4
+ <% else %>
5
+ <%= attachment.filename %>
6
+ <% end %>
7
+ <% end %>
@@ -0,0 +1,9 @@
1
+ <% if (attachment = field.value(record)) && attachment.attached? %>
2
+ <% if attachment.variable? %>
3
+ <%= image_tag main_app.url_for(attachment), class: "max-h-32" %>
4
+ <% else %>
5
+ <%= link_to attachment.filename, main_app.url_for(attachment), target: :_blank, class: "text-blue-500 underline" %>
6
+ <% end %>
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")} %>
9
+ <% end %>
@@ -0,0 +1 @@
1
+ <%= form.file_field field.attribute_name, multiple: true, class: "form-input" %>
@@ -0,0 +1 @@
1
+ <%= t("madmin.fields.attachment", count: field.value(record).size) %>
@@ -0,0 +1,11 @@
1
+ <% if (attachments = field.value(record)) && attachments.attached? %>
2
+ <% attachments.each do |attachment| %>
3
+ <% if attachment.variable? %>
4
+ <%= link_to main_app.url_for(attachment), target: :_blank do %>
5
+ <%= image_tag main_app.url_for(attachment), class: "max-h-32" %>
6
+ <% end %>
7
+ <% else %>
8
+ <%= link_to attachment.filename, main_app.url_for(attachment), target: :_blank, class: "text-blue-500 underline" %>
9
+ <% end %>
10
+ <% end %>
11
+ <% end %>
@@ -0,0 +1 @@
1
+ <%= form.select field.to_param, field.options_for_select(record), { prompt: true }, { data: { controller: "select", select_url_value: field.index_path } } %>
@@ -0,0 +1,4 @@
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) %>
4
+ <% end %>
@@ -0,0 +1,7 @@
1
+ <% if (object = field.value(record)) %>
2
+ <% if (associated_resource = field.associated_resource_for(object)) %>
3
+ <%= link_to associated_resource.display_name(object), associated_resource.show_path(object) %>
4
+ <% else %>
5
+ <%= render partial: "missing_resource", locals: { resource_name: Madmin.resource_name_for(object) } %>
6
+ <% end %>
7
+ <% end %>
@@ -0,0 +1,3 @@
1
+ <div class="form-input">
2
+ <%= form.check_box field.attribute_name %>
3
+ </div>
@@ -0,0 +1 @@
1
+ <%= field.value(record) %>
@@ -0,0 +1 @@
1
+ <%= field.value(record) %>
@@ -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) %>
@@ -0,0 +1 @@
1
+ <%= form.date_field field.attribute_name, class: "form-input" %>
@@ -0,0 +1 @@
1
+ <%= field.value(record) %>
@@ -0,0 +1 @@
1
+ <%= field.value(record) %>
@@ -0,0 +1 @@
1
+ <%= form.datetime_field field.attribute_name, class: "form-input" %>
@@ -0,0 +1 @@
1
+ <%= field.value(record) %>
@@ -0,0 +1 @@
1
+ <%= field.value(record) %>
@@ -0,0 +1 @@
1
+ <%= form.number_field field.attribute_name, step: :any, class: "form-input" %>
@@ -0,0 +1 @@
1
+ <%= field.value(record) %>
@@ -0,0 +1 @@
1
+ <%= field.value(record) %>
@@ -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) %>