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.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +294 -0
- data/Rakefile +30 -0
- data/app/assets/config/madmin_manifest.js +3 -0
- data/app/assets/stylesheets/madmin/actiontext.css +31 -0
- data/app/assets/stylesheets/madmin/application-sprockets.css +11 -0
- data/app/assets/stylesheets/madmin/application.css +9 -0
- data/app/assets/stylesheets/madmin/base.css +144 -0
- data/app/assets/stylesheets/madmin/buttons.css +53 -0
- data/app/assets/stylesheets/madmin/forms.css +90 -0
- data/app/assets/stylesheets/madmin/pagination.css +59 -0
- data/app/assets/stylesheets/madmin/reset.css +242 -0
- data/app/assets/stylesheets/madmin/sidebar.css +179 -0
- data/app/assets/stylesheets/madmin/tables.css +71 -0
- data/app/controllers/madmin/application_controller.rb +17 -0
- data/app/controllers/madmin/base_controller.rb +15 -0
- data/app/controllers/madmin/dashboard_controller.rb +6 -0
- data/app/controllers/madmin/resource_controller.rb +119 -0
- data/app/helpers/madmin/application_helper.rb +10 -0
- data/app/helpers/madmin/nav_helper.rb +34 -0
- data/app/helpers/madmin/sort_helper.rb +48 -0
- data/app/javascript/madmin/application.js +3 -0
- data/app/javascript/madmin/controllers/application.js +12 -0
- data/app/javascript/madmin/controllers/index.js +5 -0
- data/app/javascript/madmin/controllers/mobile_nav_controller.js +50 -0
- data/app/javascript/madmin/controllers/nested_form_controller.js +34 -0
- data/app/javascript/madmin/controllers/select_controller.js +37 -0
- data/app/views/layouts/madmin/application.html.erb +41 -0
- data/app/views/madmin/application/_flash.html.erb +13 -0
- data/app/views/madmin/application/_form.html.erb +24 -0
- data/app/views/madmin/application/_javascript.html.erb +8 -0
- data/app/views/madmin/application/_missing_resource.html.erb +8 -0
- data/app/views/madmin/application/_navigation.html.erb +22 -0
- data/app/views/madmin/application/edit.html.erb +11 -0
- data/app/views/madmin/application/index.html.erb +85 -0
- data/app/views/madmin/application/new.html.erb +11 -0
- data/app/views/madmin/application/show.html.erb +40 -0
- data/app/views/madmin/dashboard/show.html.erb +2 -0
- data/app/views/madmin/fields/attachment/_form.html.erb +11 -0
- data/app/views/madmin/fields/attachment/_index.html.erb +7 -0
- data/app/views/madmin/fields/attachment/_show.html.erb +9 -0
- data/app/views/madmin/fields/attachments/_form.html.erb +1 -0
- data/app/views/madmin/fields/attachments/_index.html.erb +1 -0
- data/app/views/madmin/fields/attachments/_show.html.erb +11 -0
- data/app/views/madmin/fields/belongs_to/_form.html.erb +1 -0
- data/app/views/madmin/fields/belongs_to/_index.html.erb +4 -0
- data/app/views/madmin/fields/belongs_to/_show.html.erb +7 -0
- data/app/views/madmin/fields/boolean/_form.html.erb +3 -0
- data/app/views/madmin/fields/boolean/_index.html.erb +1 -0
- data/app/views/madmin/fields/boolean/_show.html.erb +1 -0
- data/app/views/madmin/fields/currency/_form.html.erb +1 -0
- data/app/views/madmin/fields/currency/_index.html.erb +1 -0
- data/app/views/madmin/fields/currency/_show.html.erb +1 -0
- data/app/views/madmin/fields/date/_form.html.erb +1 -0
- data/app/views/madmin/fields/date/_index.html.erb +1 -0
- data/app/views/madmin/fields/date/_show.html.erb +1 -0
- data/app/views/madmin/fields/date_time/_form.html.erb +1 -0
- data/app/views/madmin/fields/date_time/_index.html.erb +1 -0
- data/app/views/madmin/fields/date_time/_show.html.erb +1 -0
- data/app/views/madmin/fields/decimal/_form.html.erb +1 -0
- data/app/views/madmin/fields/decimal/_index.html.erb +1 -0
- data/app/views/madmin/fields/decimal/_show.html.erb +1 -0
- data/app/views/madmin/fields/enum/_form.html.erb +1 -0
- data/app/views/madmin/fields/enum/_index.html.erb +1 -0
- data/app/views/madmin/fields/enum/_show.html.erb +1 -0
- data/app/views/madmin/fields/file/_form.html.erb +1 -0
- data/app/views/madmin/fields/file/_index.html.erb +1 -0
- data/app/views/madmin/fields/file/_show.html.erb +6 -0
- data/app/views/madmin/fields/float/_form.html.erb +1 -0
- data/app/views/madmin/fields/float/_index.html.erb +1 -0
- data/app/views/madmin/fields/float/_show.html.erb +1 -0
- data/app/views/madmin/fields/has_many/_form.html.erb +1 -0
- data/app/views/madmin/fields/has_many/_index.html.erb +1 -0
- data/app/views/madmin/fields/has_many/_show.html.erb +18 -0
- data/app/views/madmin/fields/has_one/_form.html.erb +1 -0
- data/app/views/madmin/fields/has_one/_index.html.erb +3 -0
- data/app/views/madmin/fields/has_one/_show.html.erb +7 -0
- data/app/views/madmin/fields/integer/_form.html.erb +1 -0
- data/app/views/madmin/fields/integer/_index.html.erb +1 -0
- data/app/views/madmin/fields/integer/_show.html.erb +1 -0
- data/app/views/madmin/fields/json/_form.html.erb +1 -0
- data/app/views/madmin/fields/json/_index.html.erb +1 -0
- data/app/views/madmin/fields/json/_show.html.erb +1 -0
- data/app/views/madmin/fields/nested_has_many/_fields.html.erb +17 -0
- data/app/views/madmin/fields/nested_has_many/_form.html.erb +28 -0
- data/app/views/madmin/fields/nested_has_many/_index.html.erb +1 -0
- data/app/views/madmin/fields/nested_has_many/_show.html.erb +18 -0
- data/app/views/madmin/fields/password/_form.html.erb +1 -0
- data/app/views/madmin/fields/password/_index.html.erb +1 -0
- data/app/views/madmin/fields/password/_show.html.erb +1 -0
- data/app/views/madmin/fields/polymorphic/_form.html.erb +4 -0
- data/app/views/madmin/fields/polymorphic/_index.html.erb +3 -0
- data/app/views/madmin/fields/polymorphic/_show.html.erb +7 -0
- data/app/views/madmin/fields/rich_text/_form.html.erb +1 -0
- data/app/views/madmin/fields/rich_text/_index.html.erb +1 -0
- data/app/views/madmin/fields/rich_text/_show.html.erb +3 -0
- data/app/views/madmin/fields/select/_form.html.erb +1 -0
- data/app/views/madmin/fields/select/_index.html.erb +1 -0
- data/app/views/madmin/fields/select/_show.html.erb +1 -0
- data/app/views/madmin/fields/string/_form.html.erb +1 -0
- data/app/views/madmin/fields/string/_index.html.erb +1 -0
- data/app/views/madmin/fields/string/_show.html.erb +1 -0
- data/app/views/madmin/fields/text/_form.html.erb +1 -0
- data/app/views/madmin/fields/text/_index.html.erb +1 -0
- data/app/views/madmin/fields/text/_show.html.erb +1 -0
- data/app/views/madmin/fields/time/_form.html.erb +5 -0
- data/app/views/madmin/fields/time/_index.html.erb +1 -0
- data/app/views/madmin/fields/time/_show.html.erb +1 -0
- data/app/views/madmin/shared/_label.html.erb +4 -0
- data/config/importmap.rb +15 -0
- data/config/locales/el.yml +42 -0
- data/config/locales/en.yml +42 -0
- data/config/locales/fr.yml +42 -0
- data/config/locales/ko.yml +40 -0
- data/lib/generators/madmin/field/field_generator.rb +31 -0
- data/lib/generators/madmin/field/templates/_form.html.erb +1 -0
- data/lib/generators/madmin/field/templates/_index.html.erb +1 -0
- data/lib/generators/madmin/field/templates/_show.html.erb +1 -0
- data/lib/generators/madmin/field/templates/field.rb.tt +26 -0
- data/lib/generators/madmin/install/install_generator.rb +55 -0
- data/lib/generators/madmin/install/templates/controller.rb.tt +15 -0
- data/lib/generators/madmin/install/templates/routes.rb.tt +3 -0
- data/lib/generators/madmin/resource/resource_generator.rb +73 -0
- data/lib/generators/madmin/resource/templates/controller.rb.tt +10 -0
- data/lib/generators/madmin/resource/templates/resource.rb.tt +33 -0
- data/lib/generators/madmin/views/edit_generator.rb +16 -0
- data/lib/generators/madmin/views/form_generator.rb +15 -0
- data/lib/generators/madmin/views/index_generator.rb +15 -0
- data/lib/generators/madmin/views/javascript_generator.rb +15 -0
- data/lib/generators/madmin/views/layout_generator.rb +21 -0
- data/lib/generators/madmin/views/navigation_generator.rb +15 -0
- data/lib/generators/madmin/views/new_generator.rb +16 -0
- data/lib/generators/madmin/views/show_generator.rb +15 -0
- data/lib/generators/madmin/views/views_generator.rb +16 -0
- data/lib/madmin/engine.rb +47 -0
- data/lib/madmin/field.rb +67 -0
- data/lib/madmin/fields/attachment.rb +6 -0
- data/lib/madmin/fields/attachments.rb +9 -0
- data/lib/madmin/fields/belongs_to.rb +29 -0
- data/lib/madmin/fields/boolean.rb +6 -0
- data/lib/madmin/fields/currency.rb +15 -0
- data/lib/madmin/fields/date.rb +6 -0
- data/lib/madmin/fields/date_time.rb +6 -0
- data/lib/madmin/fields/decimal.rb +6 -0
- data/lib/madmin/fields/enum.rb +9 -0
- data/lib/madmin/fields/file.rb +9 -0
- data/lib/madmin/fields/float.rb +6 -0
- data/lib/madmin/fields/has_many.rb +62 -0
- data/lib/madmin/fields/has_one.rb +10 -0
- data/lib/madmin/fields/integer.rb +6 -0
- data/lib/madmin/fields/json.rb +6 -0
- data/lib/madmin/fields/nested_has_many.rb +44 -0
- data/lib/madmin/fields/password.rb +6 -0
- data/lib/madmin/fields/polymorphic.rb +22 -0
- data/lib/madmin/fields/rich_text.rb +6 -0
- data/lib/madmin/fields/select.rb +9 -0
- data/lib/madmin/fields/string.rb +9 -0
- data/lib/madmin/fields/text.rb +9 -0
- data/lib/madmin/fields/time.rb +6 -0
- data/lib/madmin/generator_helpers.rb +59 -0
- data/lib/madmin/member_action.rb +19 -0
- data/lib/madmin/menu.rb +70 -0
- data/lib/madmin/namespace.rb +35 -0
- data/lib/madmin/resource.rb +295 -0
- data/lib/madmin/resource_builder.rb +88 -0
- data/lib/madmin/search.rb +62 -0
- data/lib/madmin/version.rb +3 -0
- data/lib/madmin/view_generator.rb +43 -0
- data/lib/madmin.rb +114 -0
- data/lib/tasks/madmin_tasks.rake +11 -0
- 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,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,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,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,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 @@
|
|
|
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) %>
|