madmin 3.1.2 → 3.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/assets/stylesheets/madmin/forms.css +14 -10
- data/app/assets/stylesheets/madmin/pagination.css +16 -0
- data/app/controllers/madmin/resource_controller.rb +1 -1
- data/app/helpers/madmin/application_helper.rb +18 -0
- data/app/views/madmin/application/_filters.html.erb +1 -3
- data/app/views/madmin/application/_pagination.html.erb +5 -4
- data/app/views/madmin/application/_per_page.html.erb +10 -0
- data/app/views/madmin/application/index.html.erb +1 -5
- data/app/views/madmin/application/show.html.erb +1 -1
- data/app/views/madmin/fields/attachment/_show.html.erb +1 -1
- data/config/locales/el.yml +1 -0
- data/config/locales/en.yml +1 -0
- data/config/locales/fr.yml +1 -0
- data/config/locales/ko.yml +1 -0
- data/lib/madmin/fields/has_many.rb +3 -1
- data/lib/madmin/page.rb +28 -0
- data/lib/madmin/version.rb +1 -1
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 565609ba87bcf66877e39fc115b8f6fedff6337a3dbc45ca2ea8b045ee52902e
|
|
4
|
+
data.tar.gz: eaf2ef17153d0b50b61ffa19922b34c6f2d810cc28d2b899cc0f45365f4ce501
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f9ef7c90457d5dda3297aa9343273e15d354742538da9d6166a6921d2bd80646ed4ebd388e34fc2cc381e4c5e05fd3f98991ae49aba7eec02668c9e44c2dc823
|
|
7
|
+
data.tar.gz: ea8d222e6ab24dc84a49506d764286ec1636db07ece7cbf7fe965f3b7f7427184063d69af321225c25123453f687914bb799a26a6fd2448ce5ca2d9c015b9a1b
|
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
color: var(--danger-color);
|
|
3
3
|
}
|
|
4
4
|
|
|
5
|
+
/* Apps often add .error to invalid fields with a field_error_proc. Outline those fields instead of coloring their text, which would also tint Lexxy's toolbar */
|
|
6
|
+
:is(input, select, textarea, lexxy-editor, trix-editor).error {
|
|
7
|
+
color: inherit;
|
|
8
|
+
border-color: var(--danger-color);
|
|
9
|
+
}
|
|
10
|
+
|
|
5
11
|
.form-hint {
|
|
6
12
|
font-size: 0.875rem;
|
|
7
13
|
margin-top: 0.5rem;
|
|
@@ -64,16 +70,14 @@ select {
|
|
|
64
70
|
appearance: none;
|
|
65
71
|
background-color: var(--surface-color);
|
|
66
72
|
|
|
73
|
+
border: 1px solid var(--input-border-color);
|
|
67
74
|
border-radius: 0.375rem;
|
|
68
|
-
box-shadow: inset 0 0 0 1px var(--input-border-color);
|
|
69
75
|
line-height: 1.5rem;
|
|
70
|
-
|
|
71
|
-
padding
|
|
72
|
-
padding-right: 0.75rem;
|
|
73
|
-
padding-top: 0.375rem;
|
|
76
|
+
/* Subtract the border so fields keep their size */
|
|
77
|
+
padding: calc(0.375rem - 1px) calc(0.75rem - 1px);
|
|
74
78
|
|
|
75
79
|
&:focus {
|
|
76
|
-
|
|
80
|
+
border-color: var(--primary-color);
|
|
77
81
|
}
|
|
78
82
|
}
|
|
79
83
|
|
|
@@ -109,13 +113,13 @@ select:not([multiple]) {
|
|
|
109
113
|
align-items: center;
|
|
110
114
|
gap: 0.25rem;
|
|
111
115
|
background-color: var(--surface-color);
|
|
116
|
+
border: 1px solid var(--input-border-color);
|
|
112
117
|
border-radius: 0.375rem;
|
|
113
|
-
|
|
114
|
-
padding: 0.375rem 0.75rem;
|
|
118
|
+
padding: calc(0.375rem - 1px) calc(0.75rem - 1px);
|
|
115
119
|
cursor: text;
|
|
116
120
|
|
|
117
121
|
&:focus-within {
|
|
118
|
-
|
|
122
|
+
border-color: var(--primary-color);
|
|
119
123
|
}
|
|
120
124
|
}
|
|
121
125
|
|
|
@@ -124,7 +128,7 @@ select:not([multiple]) {
|
|
|
124
128
|
flex: 1;
|
|
125
129
|
min-width: 8rem;
|
|
126
130
|
background: transparent;
|
|
127
|
-
|
|
131
|
+
border: none;
|
|
128
132
|
outline: none;
|
|
129
133
|
padding: 0;
|
|
130
134
|
}
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
.pagination {
|
|
2
|
+
display: flex;
|
|
3
|
+
flex-wrap: wrap;
|
|
4
|
+
align-items: center;
|
|
2
5
|
padding: 0.5rem;
|
|
3
6
|
}
|
|
4
7
|
|
|
@@ -44,3 +47,16 @@
|
|
|
44
47
|
.pagination-info {
|
|
45
48
|
margin-left: 0.5rem;
|
|
46
49
|
}
|
|
50
|
+
|
|
51
|
+
.per-page {
|
|
52
|
+
display: inline-flex;
|
|
53
|
+
gap: 0.5rem;
|
|
54
|
+
align-items: center;
|
|
55
|
+
margin-left: auto;
|
|
56
|
+
font-size: 0.875rem;
|
|
57
|
+
|
|
58
|
+
a[aria-current="true"] {
|
|
59
|
+
color: var(--text-color);
|
|
60
|
+
font-weight: 600;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -91,7 +91,7 @@ module Madmin
|
|
|
91
91
|
# Returns [page, records]. Override for non-ActiveRecord collections and
|
|
92
92
|
# return an object responding to the Madmin::Page interface.
|
|
93
93
|
def paginate_collection(collection)
|
|
94
|
-
paginate(collection, page: params[:page])
|
|
94
|
+
paginate(collection, page: params[:page], per_page: Madmin::Page.per_page_for(params[:per_page]))
|
|
95
95
|
end
|
|
96
96
|
|
|
97
97
|
def valid_scope
|
|
@@ -19,5 +19,23 @@ module Madmin
|
|
|
19
19
|
def index_path_with(**changes)
|
|
20
20
|
resource.index_path(request.query_parameters.symbolize_keys.except(:page).merge(changes))
|
|
21
21
|
end
|
|
22
|
+
|
|
23
|
+
# The current URL with some params changed, or removed when nil. Works on
|
|
24
|
+
# any page, unlike index_path_with
|
|
25
|
+
def current_path_with(changes)
|
|
26
|
+
"#{request.path}?#{request.query_parameters.merge(changes).compact.to_query}"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Hidden fields carrying the current index params through a GET form, so
|
|
30
|
+
# submitting it keeps what index_path_with keeps. Pass the params the form
|
|
31
|
+
# sets itself in except
|
|
32
|
+
def index_params_fields(except: [])
|
|
33
|
+
query = request.query_parameters.except("page", *except.map(&:to_s)).to_query
|
|
34
|
+
fields = query.split("&").map do |pair|
|
|
35
|
+
name, value = pair.split("=", 2).map { |part| CGI.unescape(part) }
|
|
36
|
+
hidden_field_tag name, value, id: nil
|
|
37
|
+
end
|
|
38
|
+
safe_join(fields, "\n")
|
|
39
|
+
end
|
|
22
40
|
end
|
|
23
41
|
end
|
|
@@ -6,9 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
<div id="filters" class="filters" popover data-controller="filters">
|
|
8
8
|
<%= form_with url: resource.index_path, method: :get, skip_enforcing_utf8: true do %>
|
|
9
|
-
|
|
10
|
-
<%= hidden_field_tag name, value, id: nil %>
|
|
11
|
-
<% end %>
|
|
9
|
+
<%= index_params_fields except: [:filters] %>
|
|
12
10
|
|
|
13
11
|
<p class="filters-heading"><%= t("madmin.filters.heading") %></p>
|
|
14
12
|
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
<div class="pagination">
|
|
2
2
|
<% if page.last > 1 %>
|
|
3
|
-
<% page_url = ->(number) { "#{request.path}?#{request.query_parameters.merge(page.param => number).to_query}" } %>
|
|
4
3
|
<nav class="pages" aria-label="<%= t("madmin.pagination.label") %>">
|
|
5
|
-
<%= link_to_if page.prev, "<", page.prev &&
|
|
4
|
+
<%= link_to_if page.prev, "<", page.prev && current_path_with(page.param => page.prev), aria: { label: t("madmin.pagination.previous") } do %>
|
|
6
5
|
<a role="link" aria-disabled="true" aria-label="<%= t("madmin.pagination.previous") %>"><</a>
|
|
7
6
|
<% end %>
|
|
8
7
|
|
|
@@ -12,11 +11,11 @@
|
|
|
12
11
|
<% elsif number == page.page %>
|
|
13
12
|
<a role="link" aria-disabled="true" aria-current="page"><%= number %></a>
|
|
14
13
|
<% else %>
|
|
15
|
-
<%= link_to number,
|
|
14
|
+
<%= link_to number, current_path_with(page.param => number) %>
|
|
16
15
|
<% end %>
|
|
17
16
|
<% end %>
|
|
18
17
|
|
|
19
|
-
<%= link_to_if page.next, ">", page.next &&
|
|
18
|
+
<%= link_to_if page.next, ">", page.next && current_path_with(page.param => page.next), aria: { label: t("madmin.pagination.next") } do %>
|
|
20
19
|
<a role="link" aria-disabled="true" aria-label="<%= t("madmin.pagination.next") %>">></a>
|
|
21
20
|
<% end %>
|
|
22
21
|
</nav>
|
|
@@ -29,4 +28,6 @@
|
|
|
29
28
|
<%= t("madmin.pagination.info", from: page.from, to: page.to, count: page.count) %>
|
|
30
29
|
<% end %>
|
|
31
30
|
</span>
|
|
31
|
+
|
|
32
|
+
<%= render "per_page", page: page if page.resizable? %>
|
|
32
33
|
</div>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<nav class="per-page" aria-label="<%= t("madmin.pagination.per_page") %>">
|
|
2
|
+
<span><%= t("madmin.pagination.per_page") %></span>
|
|
3
|
+
<% page.per_page_options.each do |size| %>
|
|
4
|
+
<% if size == page.per_page %>
|
|
5
|
+
<a role="link" aria-disabled="true" aria-current="true"><%= size %></a>
|
|
6
|
+
<% else %>
|
|
7
|
+
<%= link_to size, current_path_with(page.param => nil, page.per_page_param => size) %>
|
|
8
|
+
<% end %>
|
|
9
|
+
<% end %>
|
|
10
|
+
</nav>
|
|
@@ -6,12 +6,8 @@
|
|
|
6
6
|
<div class="actions">
|
|
7
7
|
<form class="search">
|
|
8
8
|
<%= hidden_field_tag :page, params[:page], value: 1 %>
|
|
9
|
+
<%= index_params_fields except: [:q] %>
|
|
9
10
|
<%= search_field_tag :q, params[:q], placeholder: t("madmin.search.placeholder") %>
|
|
10
|
-
<% filters.map(&:to_h).each do |filter| %>
|
|
11
|
-
<% filter.each do |name, value| %>
|
|
12
|
-
<%= hidden_field_tag "filters[][#{name}]", value, id: nil %>
|
|
13
|
-
<% end %>
|
|
14
|
-
<% end %>
|
|
15
11
|
</form>
|
|
16
12
|
|
|
17
13
|
<%= link_to clear_search_params, class: "btn btn-secondary" do %>
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
<% end %>
|
|
14
14
|
<% unless resource.readonly? %>
|
|
15
15
|
<%= link_to t("madmin.actions.edit"), resource.edit_path(@record), class: "btn btn-secondary" %>
|
|
16
|
-
<%= button_to t("madmin.actions.delete"), resource.show_path(@record), method: :delete, data: { turbo_confirm: t("madmin.confirmations.delete") }, class: "btn btn-danger" %>
|
|
16
|
+
<%= button_to t("madmin.actions.delete"), resource.show_path(@record), method: :delete, data: { turbo_confirm: t("madmin.confirmations.delete", resource: resource.friendly_name, name: resource.display_name(@record)) }, class: "btn btn-danger" %>
|
|
17
17
|
<% end %>
|
|
18
18
|
</div>
|
|
19
19
|
</header>
|
|
@@ -6,6 +6,6 @@
|
|
|
6
6
|
<% end %>
|
|
7
7
|
|
|
8
8
|
<% if (remove_path = field.remove_path(attachment)) %>
|
|
9
|
-
<%= link_to t("madmin.actions.remove"), remove_path, data: { turbo_method: :delete, turbo_confirm: t("madmin.confirmations.remove_with_changes")} %>
|
|
9
|
+
<%= link_to t("madmin.actions.remove"), remove_path, data: { turbo_method: :delete, turbo_confirm: t("madmin.confirmations.remove_with_changes", name: attachment.filename.to_s) } %>
|
|
10
10
|
<% end %>
|
|
11
11
|
<% end %>
|
data/config/locales/el.yml
CHANGED
data/config/locales/en.yml
CHANGED
data/config/locales/fr.yml
CHANGED
data/config/locales/ko.yml
CHANGED
|
@@ -38,7 +38,9 @@ module Madmin
|
|
|
38
38
|
|
|
39
39
|
def paginated_value(record, params)
|
|
40
40
|
page_key = "#{attribute_name}_page"
|
|
41
|
-
|
|
41
|
+
per_page = Madmin::Page.per_page_for(params["#{attribute_name}_per_page"])
|
|
42
|
+
|
|
43
|
+
paginate value(record), page: params[page_key], per_page: per_page, param: page_key
|
|
42
44
|
end
|
|
43
45
|
end
|
|
44
46
|
end
|
data/lib/madmin/page.rb
CHANGED
|
@@ -5,9 +5,22 @@ module Madmin
|
|
|
5
5
|
# these (or any object responding to the same methods) alongside their records.
|
|
6
6
|
class Page
|
|
7
7
|
SERIES_SLOTS = 7
|
|
8
|
+
PER_PAGE_OPTIONS = [20, 50, 100, 200].freeze
|
|
8
9
|
|
|
9
10
|
attr_reader :count, :page, :per_page, :param
|
|
10
11
|
|
|
12
|
+
# The page size for a request param. Invalid sizes fall back to the default
|
|
13
|
+
# and large ones are capped. Sizes passed to Page.new directly aren't capped
|
|
14
|
+
def self.per_page_for(param)
|
|
15
|
+
size = param.to_s.to_i
|
|
16
|
+
size.positive? ? [size, max_per_page].min : Madmin.per_page
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def self.max_per_page
|
|
20
|
+
[PER_PAGE_OPTIONS.max, Madmin.per_page].max
|
|
21
|
+
end
|
|
22
|
+
private_class_method :max_per_page
|
|
23
|
+
|
|
11
24
|
def initialize(count:, page: 1, per_page: Madmin.per_page, param: :page)
|
|
12
25
|
@count = count.to_i
|
|
13
26
|
@per_page = [per_page.to_i, 1].max
|
|
@@ -15,6 +28,21 @@ module Madmin
|
|
|
15
28
|
@param = param.to_s
|
|
16
29
|
end
|
|
17
30
|
|
|
31
|
+
# The param carrying the page size: "per_page", or "posts_per_page" for a "posts_page" param
|
|
32
|
+
def per_page_param
|
|
33
|
+
"#{param.delete_suffix("page")}per_page"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Page sizes to offer, always including the default and the current one
|
|
37
|
+
def per_page_options
|
|
38
|
+
(PER_PAGE_OPTIONS | [Madmin.per_page, per_page]).sort
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Whether a different page size would change what's shown
|
|
42
|
+
def resizable?
|
|
43
|
+
count > per_page_options.min
|
|
44
|
+
end
|
|
45
|
+
|
|
18
46
|
def last
|
|
19
47
|
[(count.to_f / per_page).ceil, 1].max
|
|
20
48
|
end
|
data/lib/madmin/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: madmin
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.
|
|
4
|
+
version: 3.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Chris Oliver
|
|
@@ -113,6 +113,7 @@ files:
|
|
|
113
113
|
- app/views/madmin/application/_missing_resource.html.erb
|
|
114
114
|
- app/views/madmin/application/_navigation.html.erb
|
|
115
115
|
- app/views/madmin/application/_pagination.html.erb
|
|
116
|
+
- app/views/madmin/application/_per_page.html.erb
|
|
116
117
|
- app/views/madmin/application/edit.html.erb
|
|
117
118
|
- app/views/madmin/application/index.html.erb
|
|
118
119
|
- app/views/madmin/application/new.html.erb
|