plutonium 0.69.0 → 0.70.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/.claude/skills/plutonium-resource/SKILL.md +13 -0
- data/.ruby-version +1 -1
- data/CHANGELOG.md +17 -0
- data/CLAUDE.md +11 -0
- data/SECURITY.md +1 -1
- data/app/assets/plutonium.css +2 -2
- data/app/assets/plutonium.png +0 -0
- data/config/locales/en/ui.yml +3 -0
- data/docs/blog/introducing-plutonium-dashboards.md +4 -4
- data/docs/blog/the-slowest-query-is-the-count.md +109 -0
- data/docs/guides/performance.md +14 -0
- data/docs/public/favicon-16x16.png +0 -0
- data/docs/public/favicon-32x32.png +0 -0
- data/docs/public/images/blog/i18n-es-admin.png +0 -0
- data/docs/public/images/blog/pagination-capped.png +0 -0
- data/docs/public/images/blog/pagination-countless.png +0 -0
- data/docs/public/images/components/avatar.png +0 -0
- data/docs/public/images/guides/custom-actions-bulk.png +0 -0
- data/docs/public/images/guides/dashboard-card-error.png +0 -0
- data/docs/public/images/guides/dashboard-loading.png +0 -0
- data/docs/public/images/guides/dashboard-overview.png +0 -0
- data/docs/public/images/guides/dashboard-sidebar.png +0 -0
- data/docs/public/images/guides/kanban-after-move.png +0 -0
- data/docs/public/images/guides/kanban-board-light.png +0 -0
- data/docs/public/images/guides/kanban-board.png +0 -0
- data/docs/public/images/guides/kanban-show-centered-modal.png +0 -0
- data/docs/public/images/guides/kanban-wip-toast.png +0 -0
- data/docs/public/images/guides/multi-tenancy-dashboard.png +0 -0
- data/docs/public/images/guides/multi-tenancy-welcome.png +0 -0
- data/docs/public/images/guides/nested-inputs.png +0 -0
- data/docs/public/images/guides/nested-resources-tab.png +0 -0
- data/docs/public/images/guides/search-filtering-index.png +0 -0
- data/docs/public/images/guides/search-filtering-panel.png +0 -0
- data/docs/public/images/guides/theming-after.png +0 -0
- data/docs/public/images/guides/theming-before.png +0 -0
- data/docs/public/images/guides/user-invites-landing.png +0 -0
- data/docs/public/images/guides/user-profile-edit.png +0 -0
- data/docs/public/images/guides/user-profile-show.png +0 -0
- data/docs/public/images/guides/wizards-chooser.png +0 -0
- data/docs/public/images/guides/wizards-completed.png +0 -0
- data/docs/public/images/guides/wizards-index-action.png +0 -0
- data/docs/public/images/guides/wizards-repeater.png +0 -0
- data/docs/public/images/guides/wizards-review.png +0 -0
- data/docs/public/images/guides/wizards-step.png +0 -0
- data/docs/public/images/home/tour-actions.png +0 -0
- data/docs/public/images/home/tour-async.png +0 -0
- data/docs/public/images/home/tour-kanban.png +0 -0
- data/docs/public/images/home/tour-tenancy.png +0 -0
- data/docs/public/images/home/tour-wizard.png +0 -0
- data/docs/public/images/home-index.png +0 -0
- data/docs/public/images/home-new.png +0 -0
- data/docs/public/images/home-show.png +0 -0
- data/docs/public/images/reference/async-progress-page.png +0 -0
- data/docs/public/images/reference/async-running-banner.png +0 -0
- data/docs/public/images/reference/structured-inputs-removed.png +0 -0
- data/docs/public/images/reference/structured-inputs.png +0 -0
- data/docs/public/images/tutorial/02-empty-index.png +0 -0
- data/docs/public/images/tutorial/02-index-with-posts.png +0 -0
- data/docs/public/images/tutorial/02-new-form-modal.png +0 -0
- data/docs/public/images/tutorial/02-new-form.png +0 -0
- data/docs/public/images/tutorial/03-create-account.png +0 -0
- data/docs/public/images/tutorial/03-login.png +0 -0
- data/docs/public/images/tutorial/04-admin-index.png +0 -0
- data/docs/public/images/tutorial/05-actions-menu.png +0 -0
- data/docs/public/images/tutorial/05-row-actions.png +0 -0
- data/docs/public/images/tutorial/06-comments-tab.png +0 -0
- data/docs/public/images/tutorial/06-post-with-comments.png +0 -0
- data/docs/public/images/tutorial/07-author-dashboard.png +0 -0
- data/docs/public/images/tutorial/07-author-portal.png +0 -0
- data/docs/public/images/tutorial/08-customized-index.png +0 -0
- data/docs/public/og-image.png +0 -0
- data/docs/public/plutonium.png +0 -0
- data/docs/public/tutorial/plutonium-association-panel.png +0 -0
- data/docs/public/tutorial/plutonium-dashboard.png +0 -0
- data/docs/public/tutorial/plutonium-login-page.png +0 -0
- data/docs/public/tutorial/plutonium-nested-form.png +0 -0
- data/docs/public/tutorial/plutonium-posts-dashboard-customized.png +0 -0
- data/docs/public/tutorial/plutonium-posts-dashboard.png +0 -0
- data/docs/public/tutorial/plutonium-posts-detail-customized.png +0 -0
- data/docs/public/tutorial/plutonium-posts-detail.png +0 -0
- data/docs/public/tutorial/plutonium-publish-post.png +0 -0
- data/docs/reference/configuration.md +1 -0
- data/docs/reference/i18n.md +1 -1
- data/docs/reference/resource/definition.md +35 -0
- data/docs/reference/ui/layouts.md +13 -0
- data/gemfiles/rails_7.gemfile.lock +3 -3
- data/gemfiles/rails_8.0.gemfile.lock +1 -1
- data/gemfiles/rails_8.1.gemfile.lock +1 -1
- data/lib/plutonium/configuration.rb +17 -0
- data/lib/plutonium/definition/base.rb +22 -0
- data/lib/plutonium/pagination.rb +35 -0
- data/lib/plutonium/resource/controllers/crud_actions/index_action.rb +27 -1
- data/lib/plutonium/ui/grid/card.rb +11 -2
- data/lib/plutonium/ui/grid/resource.rb +2 -2
- data/lib/plutonium/ui/layout/icon_rail.rb +42 -4
- data/lib/plutonium/ui/table/components/filter_pills.rb +8 -2
- data/lib/plutonium/ui/table/components/pagy_info.rb +30 -10
- data/lib/plutonium/ui/table/resource.rb +2 -2
- data/lib/plutonium/version.rb +1 -1
- data/package.json +1 -1
- data/plutonium.gemspec +3 -1
- data/src/css/components.css +3 -1
- metadata +7 -7
- data/docs/public/images/blog/dashboards-card-error.png +0 -0
- data/docs/public/images/blog/dashboards-loading.png +0 -0
- data/docs/public/images/blog/dashboards-overview.png +0 -0
- data/docs/public/images/blog/dashboards-sidebar.png +0 -0
|
@@ -195,7 +195,10 @@ module Plutonium
|
|
|
195
195
|
# - associations → display_name_of (label, not an object inspect)
|
|
196
196
|
# - everything else → humanized, with the RAW value driving the
|
|
197
197
|
# variant so status-like enums (in_progress, published…) still
|
|
198
|
-
# resolve to a semantic color.
|
|
198
|
+
# resolve to a semantic color. A `colors:` map declared on the
|
|
199
|
+
# field's `column` (or else its `display`) picks the variant
|
|
200
|
+
# first, as it does for the Badge in the table and on the show
|
|
201
|
+
# page.
|
|
199
202
|
# The variant hashes the stable formatted label for currency/associations,
|
|
200
203
|
# so the decorative color no longer churns on an object's memory address.
|
|
201
204
|
def render_meta_badge(name, value)
|
|
@@ -209,7 +212,7 @@ module Plutonium
|
|
|
209
212
|
variant = badge.variant_for(label)
|
|
210
213
|
else
|
|
211
214
|
label = Plutonium::Translation.value_label(@record.class, name, value) || badge.humanize(value)
|
|
212
|
-
variant = badge.variant_for(value)
|
|
215
|
+
variant = badge.variant_for(value, colors: declared_colors(name))
|
|
213
216
|
end
|
|
214
217
|
|
|
215
218
|
span(class: tokens("pu-badge", "pu-badge-#{variant}")) do
|
|
@@ -217,6 +220,12 @@ module Plutonium
|
|
|
217
220
|
end
|
|
218
221
|
end
|
|
219
222
|
|
|
223
|
+
def declared_colors(name)
|
|
224
|
+
name = name.to_sym
|
|
225
|
+
resource_definition.defined_columns.dig(name, :options, :colors) ||
|
|
226
|
+
resource_definition.defined_displays.dig(name, :options, :colors)
|
|
227
|
+
end
|
|
228
|
+
|
|
220
229
|
def currency_field?(name)
|
|
221
230
|
klass = record.class
|
|
222
231
|
klass.respond_to?(:has_cents_decimal_attribute?) && klass.has_cents_decimal_attribute?(name.to_sym)
|
|
@@ -54,7 +54,7 @@ module Plutonium
|
|
|
54
54
|
end
|
|
55
55
|
|
|
56
56
|
def render_filter_pills
|
|
57
|
-
TableFilterPills(query: current_query_object, total_count: pagy_instance&.count)
|
|
57
|
+
TableFilterPills(query: current_query_object, total_count: pagy_instance&.count, count_capped: pagy_instance&.options&.fetch(:count_capped, false))
|
|
58
58
|
end
|
|
59
59
|
|
|
60
60
|
def render_bulk_actions_toolbar
|
|
@@ -181,7 +181,7 @@ module Plutonium
|
|
|
181
181
|
|
|
182
182
|
def render_footer
|
|
183
183
|
div(class: "lg:sticky bottom-[-2px] mt-1 p-4 pb-6 w-full z-30 bg-[var(--pu-body)]") {
|
|
184
|
-
TableInfo(pagy_instance, item_name: resource_name(resource_class, pagy_instance.count))
|
|
184
|
+
TableInfo(pagy_instance, item_name: resource_name(resource_class, pagy_instance.count || 2))
|
|
185
185
|
TablePagination(pagy_instance)
|
|
186
186
|
}
|
|
187
187
|
end
|
|
@@ -18,6 +18,12 @@ module Plutonium
|
|
|
18
18
|
# render IconRail.new(menu: @menu) do |rail|
|
|
19
19
|
# rail.with_brand { image_tag("logo.svg", class: "w-8 h-8") }
|
|
20
20
|
# end
|
|
21
|
+
#
|
|
22
|
+
# @example Links pinned above the footer, outside the scrolling nav
|
|
23
|
+
# render IconRail.new(
|
|
24
|
+
# menu: @menu,
|
|
25
|
+
# footer_menu: Phlexi::Menu::Builder.new { |m| m.item "Settings", url: settings_path, icon: Phlex::TablerIcons::Settings }
|
|
26
|
+
# )
|
|
21
27
|
class IconRail < Plutonium::UI::Component::Base
|
|
22
28
|
include Phlex::Slotable
|
|
23
29
|
|
|
@@ -28,9 +34,11 @@ module Plutonium
|
|
|
28
34
|
DEFAULT_MAX_DEPTH = 2
|
|
29
35
|
|
|
30
36
|
# @param menu [Phlexi::Menu::Builder, nil] Menu structure (same shape as SidebarMenu)
|
|
37
|
+
# @param footer_menu [Phlexi::Menu::Builder, nil] Links pinned above the footer, outside the scrolling nav
|
|
31
38
|
# @param max_depth [Integer] Maximum rendering depth (depth 2 supports parent+children)
|
|
32
|
-
def initialize(menu: nil, max_depth: DEFAULT_MAX_DEPTH)
|
|
39
|
+
def initialize(menu: nil, footer_menu: nil, max_depth: DEFAULT_MAX_DEPTH)
|
|
33
40
|
@menu = menu
|
|
41
|
+
@footer_menu = footer_menu
|
|
34
42
|
@max_depth = max_depth
|
|
35
43
|
end
|
|
36
44
|
|
|
@@ -46,6 +54,7 @@ module Plutonium
|
|
|
46
54
|
) do
|
|
47
55
|
render_brand_section
|
|
48
56
|
render_nav_section
|
|
57
|
+
render_footer_menu_section
|
|
49
58
|
render_footer_section
|
|
50
59
|
end
|
|
51
60
|
end
|
|
@@ -72,6 +81,16 @@ module Plutonium
|
|
|
72
81
|
end
|
|
73
82
|
end
|
|
74
83
|
|
|
84
|
+
# Kept ahead of the footer, which stays the rail's last section: the
|
|
85
|
+
# pinned rail's styles right-align that section to place the pin button.
|
|
86
|
+
def render_footer_menu_section
|
|
87
|
+
return if @footer_menu.nil? || @footer_menu.items.empty?
|
|
88
|
+
|
|
89
|
+
div(class: "flex flex-col items-center gap-1 px-2 py-2 border-t border-[var(--pu-border)] shrink-0") do
|
|
90
|
+
render_items(@footer_menu.items, 0)
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
75
94
|
def render_footer_section
|
|
76
95
|
div(class: "h-14 flex items-center justify-center border-t border-[var(--pu-border)] shrink-0") do
|
|
77
96
|
render_pin_button
|
|
@@ -116,11 +135,12 @@ module Plutonium
|
|
|
116
135
|
def render_leaf_item(item, depth)
|
|
117
136
|
a(
|
|
118
137
|
href: item.url,
|
|
119
|
-
title: item
|
|
120
|
-
**item_link_attributes(item, "icon-rail-leaf #{leaf_classes(item, depth)}", base_aria: {label: item
|
|
138
|
+
title: item_title(item),
|
|
139
|
+
**item_link_attributes(item, "icon-rail-leaf #{leaf_classes(item, depth)}", base_aria: {label: item_title(item)})
|
|
121
140
|
) do
|
|
122
141
|
render_item_icon(item)
|
|
123
142
|
span(class: "icon-rail-label hidden") { item.label }
|
|
143
|
+
render_trailing_badge(item, "icon-rail-label hidden")
|
|
124
144
|
end
|
|
125
145
|
end
|
|
126
146
|
|
|
@@ -165,14 +185,32 @@ module Plutonium
|
|
|
165
185
|
a(
|
|
166
186
|
href: child.url,
|
|
167
187
|
role: "menuitem",
|
|
188
|
+
title: item_title(child),
|
|
168
189
|
**item_link_attributes(child, "icon-rail-flyout-item")
|
|
169
|
-
)
|
|
190
|
+
) do
|
|
191
|
+
plain child.label
|
|
192
|
+
render_trailing_badge(child)
|
|
193
|
+
end
|
|
170
194
|
end
|
|
171
195
|
end
|
|
172
196
|
end
|
|
173
197
|
end
|
|
174
198
|
end
|
|
175
199
|
|
|
200
|
+
# The label, with the item's trailing badge in brackets, for tooltips
|
|
201
|
+
# and screen readers: "Reports (Pro)".
|
|
202
|
+
def item_title(item)
|
|
203
|
+
item.trailing_badge ? "#{item.label} (#{item.trailing_badge})" : item.label
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
# A short marker after the label, such as the plan that unlocks a page.
|
|
207
|
+
def render_trailing_badge(item, extra_classes = nil)
|
|
208
|
+
return unless item.trailing_badge
|
|
209
|
+
|
|
210
|
+
span(class: ["icon-rail-badge ml-auto rounded px-1.5 py-0.5 text-[10px] font-medium leading-none " \
|
|
211
|
+
"bg-[var(--pu-surface-alt)] text-[var(--pu-text-muted)]", extra_classes].compact.join(" ")) { item.trailing_badge }
|
|
212
|
+
end
|
|
213
|
+
|
|
176
214
|
def render_item_icon(item)
|
|
177
215
|
if item.icon
|
|
178
216
|
render item.icon.new(class: "w-5 h-5 shrink-0")
|
|
@@ -5,9 +5,14 @@ module Plutonium
|
|
|
5
5
|
module Table
|
|
6
6
|
module Components
|
|
7
7
|
class FilterPills < Plutonium::UI::Component::Base
|
|
8
|
-
|
|
8
|
+
# @param total_count [Integer, nil] nil hides the count (countless
|
|
9
|
+
# pagination, `pagination count: false`)
|
|
10
|
+
# @param count_capped [Boolean] the count stopped at its cap
|
|
11
|
+
# (`pagination count: 10_000`), so it reads "10000+ results"
|
|
12
|
+
def initialize(query:, total_count: nil, count_capped: false)
|
|
9
13
|
@query = query
|
|
10
14
|
@total_count = total_count
|
|
15
|
+
@count_capped = count_capped
|
|
11
16
|
end
|
|
12
17
|
|
|
13
18
|
def view_template
|
|
@@ -79,7 +84,8 @@ module Plutonium
|
|
|
79
84
|
|
|
80
85
|
def render_result_count
|
|
81
86
|
div(class: "ml-auto text-xs text-[var(--pu-text-muted)]") do
|
|
82
|
-
|
|
87
|
+
key = @count_capped ? "plutonium.ui.table.result_count_capped" : "plutonium.ui.table.result_count"
|
|
88
|
+
plain t(key, count: @total_count)
|
|
83
89
|
end
|
|
84
90
|
end
|
|
85
91
|
end
|
|
@@ -34,21 +34,41 @@ module Plutonium
|
|
|
34
34
|
private
|
|
35
35
|
|
|
36
36
|
def results_info
|
|
37
|
-
key = if @pagy.count.zero?
|
|
38
|
-
"pagy.info_tag.no_items"
|
|
39
|
-
elsif @pagy.in == @pagy.count
|
|
40
|
-
"pagy.info_tag.single_page"
|
|
41
|
-
else
|
|
42
|
-
"pagy.info_tag.multiple_pages"
|
|
43
|
-
end
|
|
44
|
-
|
|
45
37
|
div do
|
|
46
|
-
render_template(
|
|
47
|
-
b { @pagy.public_send(placeholder).to_s }
|
|
38
|
+
render_template(results_template) do |placeholder|
|
|
39
|
+
b { (placeholder == :count) ? count_label : @pagy.public_send(placeholder).to_s }
|
|
48
40
|
end
|
|
49
41
|
end
|
|
50
42
|
end
|
|
51
43
|
|
|
44
|
+
def results_template
|
|
45
|
+
count = known_count
|
|
46
|
+
if count.nil?
|
|
47
|
+
# Countless, past page 1: the total is unknown, so no "of N".
|
|
48
|
+
t("plutonium.ui.table.page_range", item_name: item_name(2), from: "%{from}", to: "%{to}")
|
|
49
|
+
elsif count.zero?
|
|
50
|
+
pagy_template("pagy.info_tag.no_items", count)
|
|
51
|
+
elsif count == @pagy.in
|
|
52
|
+
pagy_template("pagy.info_tag.single_page", count)
|
|
53
|
+
else
|
|
54
|
+
pagy_template("pagy.info_tag.multiple_pages", count)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# The total, when it is known. A countless pager (`pagination count:
|
|
59
|
+
# false`) has none, except on a first page with no next page, where the
|
|
60
|
+
# rows on it are the whole set.
|
|
61
|
+
def known_count
|
|
62
|
+
return @pagy.count if @pagy.count
|
|
63
|
+
@pagy.in if @pagy.page == 1 && !@pagy.next
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# "10000+" when the count hit its cap (`pagination count: 10_000`).
|
|
67
|
+
def count_label
|
|
68
|
+
count = known_count.to_s
|
|
69
|
+
@pagy.options[:count_capped] ? t("plutonium.ui.table.capped_count", count:) : count
|
|
70
|
+
end
|
|
71
|
+
|
|
52
72
|
def per_page_selector
|
|
53
73
|
id = "perPage#{SecureRandom.hex}"
|
|
54
74
|
|
|
@@ -71,7 +71,7 @@ module Plutonium
|
|
|
71
71
|
end
|
|
72
72
|
|
|
73
73
|
def render_filter_pills
|
|
74
|
-
TableFilterPills(query: current_query_object, total_count: pagy_instance&.count)
|
|
74
|
+
TableFilterPills(query: current_query_object, total_count: pagy_instance&.count, count_capped: pagy_instance&.options&.fetch(:count_capped, false))
|
|
75
75
|
end
|
|
76
76
|
|
|
77
77
|
def current_search_url
|
|
@@ -315,7 +315,7 @@ module Plutonium
|
|
|
315
315
|
|
|
316
316
|
def render_footer
|
|
317
317
|
div(class: "lg:sticky bottom-[-2px] mt-1 p-4 pb-6 w-full z-30 bg-[var(--pu-body)]") {
|
|
318
|
-
TableInfo(pagy_instance, item_name: resource_name(resource_class, pagy_instance.count))
|
|
318
|
+
TableInfo(pagy_instance, item_name: resource_name(resource_class, pagy_instance.count || 2))
|
|
319
319
|
TablePagination(pagy_instance)
|
|
320
320
|
}
|
|
321
321
|
end
|
data/lib/plutonium/version.rb
CHANGED
data/package.json
CHANGED
data/plutonium.gemspec
CHANGED
|
@@ -35,7 +35,9 @@ Gem::Specification.new do |spec|
|
|
|
35
35
|
f.start_with?(*%w[bin/ test/ spec/ features/ .git .github appveyor Gemfile]) ||
|
|
36
36
|
# Maintainer tooling; host apps read tailwind.options.js and the postcss
|
|
37
37
|
# plugin from the gem, not the lockfile or yarn settings.
|
|
38
|
-
%w[.yarnrc.yml yarn.lock public/plutonium-assets/].any? { |prefix| f.start_with?(prefix) }
|
|
38
|
+
%w[.yarnrc.yml yarn.lock public/plutonium-assets/].any? { |prefix| f.start_with?(prefix) } ||
|
|
39
|
+
# Full-size brand sources; the gem ships the resized app/assets copy.
|
|
40
|
+
f.start_with?("brand/")
|
|
39
41
|
end
|
|
40
42
|
end
|
|
41
43
|
spec.bindir = "exe"
|
data/src/css/components.css
CHANGED
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: plutonium
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.70.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Stefan Froelich
|
|
8
8
|
bindir: exe
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: zeitwerk
|
|
@@ -619,6 +619,7 @@ files:
|
|
|
619
619
|
- docs/blog/jobs-are-not-permission-snapshots.md
|
|
620
620
|
- docs/blog/plutonium-and-ai-agents.md
|
|
621
621
|
- docs/blog/realtime-is-one-line-and-four-dependencies.md
|
|
622
|
+
- docs/blog/the-slowest-query-is-the-count.md
|
|
622
623
|
- docs/blog/two-forms-one-dom-id.md
|
|
623
624
|
- docs/blog/whats-new-async-kanban-wizards.md
|
|
624
625
|
- docs/getting-started/index.md
|
|
@@ -660,11 +661,9 @@ files:
|
|
|
660
661
|
- docs/public/favicon-16x16.png
|
|
661
662
|
- docs/public/favicon-32x32.png
|
|
662
663
|
- docs/public/favicon.ico
|
|
663
|
-
- docs/public/images/blog/dashboards-card-error.png
|
|
664
|
-
- docs/public/images/blog/dashboards-loading.png
|
|
665
|
-
- docs/public/images/blog/dashboards-overview.png
|
|
666
|
-
- docs/public/images/blog/dashboards-sidebar.png
|
|
667
664
|
- docs/public/images/blog/i18n-es-admin.png
|
|
665
|
+
- docs/public/images/blog/pagination-capped.png
|
|
666
|
+
- docs/public/images/blog/pagination-countless.png
|
|
668
667
|
- docs/public/images/components/avatar.png
|
|
669
668
|
- docs/public/images/guides/custom-actions-bulk.png
|
|
670
669
|
- docs/public/images/guides/dashboard-card-error.png
|
|
@@ -1225,6 +1224,7 @@ files:
|
|
|
1225
1224
|
- lib/plutonium/migrations.rb
|
|
1226
1225
|
- lib/plutonium/models/has_cents.rb
|
|
1227
1226
|
- lib/plutonium/package/engine.rb
|
|
1227
|
+
- lib/plutonium/pagination.rb
|
|
1228
1228
|
- lib/plutonium/portal/controller.rb
|
|
1229
1229
|
- lib/plutonium/portal/dynamic_controllers.rb
|
|
1230
1230
|
- lib/plutonium/portal/engine.rb
|
|
@@ -1584,7 +1584,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
1584
1584
|
- !ruby/object:Gem::Version
|
|
1585
1585
|
version: '0'
|
|
1586
1586
|
requirements: []
|
|
1587
|
-
rubygems_version:
|
|
1587
|
+
rubygems_version: 4.0.20
|
|
1588
1588
|
specification_version: 4
|
|
1589
1589
|
summary: Build production-ready Rails apps in minutes, not days
|
|
1590
1590
|
test_files: []
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|