avo 4.0.8 → 4.0.10
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/Gemfile.lock +1 -1
- data/app/assets/builds/avo/application.css +3 -0
- data/app/assets/builds/avo/application.js +1 -1
- data/app/assets/builds/avo/application.js.map +2 -2
- data/app/assets/stylesheets/css/components/filters.css +1 -1
- data/app/components/avo/filters_component.html.erb +14 -1
- data/app/components/avo/resource_component.rb +20 -5
- data/app/components/avo/sidebar_component.html.erb +1 -1
- data/app/controllers/avo/actions_controller.rb +2 -1
- data/app/controllers/avo/base_controller.rb +1 -1
- data/app/helpers/avo/resources_helper.rb +0 -9
- data/app/javascript/js/controllers/fields/date_field_controller.js +7 -1
- data/app/views/avo/base/_boolean_filter.html.erb +21 -24
- data/app/views/avo/base/_date_time_filter.html.erb +34 -35
- data/app/views/avo/base/_multiple_select_filter.html.erb +15 -17
- data/app/views/avo/base/_select_filter.html.erb +10 -13
- data/app/views/avo/base/_text_filter.html.erb +16 -17
- data/lib/avo/base_action.rb +2 -1
- data/lib/avo/version.rb +1 -1
- data/lib/avo.rb +1 -1
- metadata +2 -3
- data/app/views/layouts/avo/_filter_wrapper.html.erb +0 -8
|
@@ -22,7 +22,20 @@
|
|
|
22
22
|
<div class="filters-card__content">
|
|
23
23
|
<div class="divide-y divide-secondary">
|
|
24
24
|
<% @filters.each do |filter| %>
|
|
25
|
-
|
|
25
|
+
<div class="filters-section">
|
|
26
|
+
<div class="filters-section__title">
|
|
27
|
+
<%= filter.name %>
|
|
28
|
+
<% if Rails.env.development? %>
|
|
29
|
+
<%= render Avo::DiscreetInformationComponent.new(
|
|
30
|
+
as: :icon,
|
|
31
|
+
url: helpers.editor_file_path(filter),
|
|
32
|
+
icon: "tabler/outline/code",
|
|
33
|
+
title: t("avo.open_in_your_editor")
|
|
34
|
+
) %>
|
|
35
|
+
<% end %>
|
|
36
|
+
</div>
|
|
37
|
+
<%= render partial: filter.class.template, locals: {filter: filter} %>
|
|
38
|
+
</div>
|
|
26
39
|
<% end %>
|
|
27
40
|
</div>
|
|
28
41
|
</div>
|
|
@@ -126,14 +126,23 @@ class Avo::ResourceComponent < Avo::BaseComponent
|
|
|
126
126
|
def render_actions_list(actions_list)
|
|
127
127
|
return unless can_see_the_actions_button?
|
|
128
128
|
|
|
129
|
-
# `as_row_control` hydrates each action with the current record (needed for both
|
|
130
|
-
# index rows and the single-record show/edit headers).
|
|
131
|
-
as_row_control = @item.present?
|
|
132
|
-
|
|
133
129
|
# Inside an index table row the hotkey must be managed by the index-row-navigator
|
|
134
130
|
# (data-hotkey-original); page-level headers use a plain data-hotkey.
|
|
135
131
|
as_index_row_control = row_controls_context?
|
|
136
132
|
|
|
133
|
+
# `as_row_control` hydrates each action with the current record (needed for both
|
|
134
|
+
# index rows and the single-record show/edit headers). @item is only ever set for
|
|
135
|
+
# the show/edit field-panel switcher, so it's blank for index rows -- fall back to
|
|
136
|
+
# row_controls_context? there so per-row actions_list entries get hydrated too.
|
|
137
|
+
as_row_control = @item.present? || as_index_row_control
|
|
138
|
+
|
|
139
|
+
# @actions is built once by the controller's set_actions, before any row exists
|
|
140
|
+
# (its @resource.record is nil there), so a `visible` block that inspects the
|
|
141
|
+
# record can't tell rows apart -- and since set_actions already dropped the
|
|
142
|
+
# non-visible ones, there's nothing left downstream to recover them from. Rebuild
|
|
143
|
+
# the list fresh from this row's own hydrated resource instead of reusing it.
|
|
144
|
+
actions = as_index_row_control ? row_actions : @actions
|
|
145
|
+
|
|
137
146
|
# Actions button hotkey "a" on the main index, show and edit pages (non-nested,
|
|
138
147
|
# not an index row). The index component doesn't carry a @view, so detect it by
|
|
139
148
|
# class; show renders through the switcher and edit directly, both of which do
|
|
@@ -143,7 +152,7 @@ class Avo::ResourceComponent < Avo::BaseComponent
|
|
|
143
152
|
)
|
|
144
153
|
|
|
145
154
|
render Avo::ActionsComponent.new(
|
|
146
|
-
actions
|
|
155
|
+
actions:,
|
|
147
156
|
resource: @resource,
|
|
148
157
|
view: @view,
|
|
149
158
|
exclude: actions_list.exclude,
|
|
@@ -161,6 +170,12 @@ class Avo::ResourceComponent < Avo::BaseComponent
|
|
|
161
170
|
)
|
|
162
171
|
end
|
|
163
172
|
|
|
173
|
+
def row_actions
|
|
174
|
+
@resource.get_actions
|
|
175
|
+
.map { |action_bag| action_bag[:class].new(record: @resource.record, resource: @resource, view: @view, **action_bag.except(:class)) }
|
|
176
|
+
.select { |action| action.is_a?(Avo::Divider) || action.visible_in_view(parent_resource: @parent_resource) }
|
|
177
|
+
end
|
|
178
|
+
|
|
164
179
|
def render_delete_button(control)
|
|
165
180
|
# If the resource is a related resource, we use the can_delete? policy method because it uses
|
|
166
181
|
# authorize_association_for(:destroy).
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
<div class="sidebar-status">
|
|
68
68
|
<%= link_to helpers.avo.avo_private_status_path, class: "sidebar-status__link" do %>
|
|
69
69
|
<span>Avo Status</span>
|
|
70
|
-
<span><div class="sidebar-status__indicator
|
|
70
|
+
<span><div class="sidebar-status__indicator sidebar-status__indicator--<%= Avo.app_status %>"></div></span>
|
|
71
71
|
<% end %>
|
|
72
72
|
</div>
|
|
73
73
|
<% end %>
|
|
@@ -370,7 +370,7 @@ module Avo
|
|
|
370
370
|
@actions = @resource
|
|
371
371
|
.get_actions
|
|
372
372
|
.map do |action_bag|
|
|
373
|
-
action_bag
|
|
373
|
+
action_bag[:class].new(record: @record, resource: @resource, view: @view, **action_bag.except(:class))
|
|
374
374
|
end
|
|
375
375
|
.select do |action|
|
|
376
376
|
action.is_a?(DividerComponent) || action.visible_in_view(parent_resource: @parent_resource)
|
|
@@ -28,15 +28,6 @@ module Avo
|
|
|
28
28
|
alias_method :edit_field_wrapper, :field_wrapper
|
|
29
29
|
alias_method :show_field_wrapper, :field_wrapper
|
|
30
30
|
|
|
31
|
-
def filter_wrapper(name: nil, index: nil, **args, &block)
|
|
32
|
-
render layout: "layouts/avo/filter_wrapper", locals: {
|
|
33
|
-
name: name,
|
|
34
|
-
index: index
|
|
35
|
-
} do
|
|
36
|
-
capture(&block)
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
|
-
|
|
40
31
|
def item_selector_data_attributes(resource, controller: "")
|
|
41
32
|
{
|
|
42
33
|
resource_name: resource.model_key,
|
|
@@ -86,6 +86,12 @@ export default class extends Controller {
|
|
|
86
86
|
return this.timezoneValue || this.browserZone
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
+
// Locale from the <html lang> attribute so Luxon tokens like `cccc` translate.
|
|
90
|
+
// Luxon reads locale data from the browser's native Intl API, so no locale files are bundled.
|
|
91
|
+
get locale() {
|
|
92
|
+
return document.documentElement.lang || 'en'
|
|
93
|
+
}
|
|
94
|
+
|
|
89
95
|
connect() {
|
|
90
96
|
// Cache the initial value so we can fill it back on disconnection.
|
|
91
97
|
// We do that so the JS parser will continue to work when the user hits the back button to return on this page.
|
|
@@ -125,7 +131,7 @@ export default class extends Controller {
|
|
|
125
131
|
}
|
|
126
132
|
}
|
|
127
133
|
|
|
128
|
-
this.context.element.innerText = value.toFormat(this.formatValue)
|
|
134
|
+
this.context.element.innerText = value.toFormat(this.formatValue, { locale: this.locale })
|
|
129
135
|
}
|
|
130
136
|
|
|
131
137
|
initEdit() {
|
|
@@ -1,28 +1,25 @@
|
|
|
1
1
|
<div
|
|
2
|
+
class="filters-section__body"
|
|
2
3
|
data-controller="boolean-filter"
|
|
3
4
|
data-filter-name="<%= filter.name %>"
|
|
4
|
-
data-boolean-filter-keep-filters-panel-open-value="<%= @resource.keep_filters_panel_open %>"
|
|
5
|
-
>
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
<% end %>
|
|
25
|
-
<%= link_to 'url_redirect', request.url, data: { 'boolean-filter-target': 'urlRedirect', 'turbo-frame': params[:turbo_frame] }, class: 'hidden' %>
|
|
26
|
-
</div>
|
|
27
|
-
<% end %>
|
|
5
|
+
data-boolean-filter-keep-filters-panel-open-value="<%= @resource.keep_filters_panel_open %>">
|
|
6
|
+
<div class="flex items-center">
|
|
7
|
+
<% if filter.options.empty? %>
|
|
8
|
+
<div class="filters-section__empty-state"><%= filter.class.empty_message %></div>
|
|
9
|
+
<% else %>
|
|
10
|
+
<div class="filters-boolean-options">
|
|
11
|
+
<% filter.options.each do |value, label| %>
|
|
12
|
+
<label class="filters-boolean-option">
|
|
13
|
+
<%= check_box_tag filter.id, value, filter.selected_value(value.to_s, @applied_filters),
|
|
14
|
+
id: "avo_filters_#{filter.id.parameterize.underscore}",
|
|
15
|
+
"data-filter-class": filter.class,
|
|
16
|
+
"data-boolean-filter-target": "option",
|
|
17
|
+
"data-action": "input->boolean-filter#changeFilter" %>
|
|
18
|
+
<span><%= label %></span>
|
|
19
|
+
</label>
|
|
20
|
+
<% end %>
|
|
21
|
+
</div>
|
|
22
|
+
<% end %>
|
|
23
|
+
<%= link_to "url_redirect", request.url, data: {"boolean-filter-target": "urlRedirect", "turbo-frame": params[:turbo_frame]}, class: "hidden" %>
|
|
24
|
+
</div>
|
|
28
25
|
</div>
|
|
@@ -1,39 +1,38 @@
|
|
|
1
|
-
<%= content_tag :div, data: {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
<div class="
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
data: {
|
|
15
|
-
date_time_filter_target: "input",
|
|
16
|
-
} %>
|
|
17
|
-
</div>
|
|
18
|
-
|
|
19
|
-
<%= content_tag :button,
|
|
20
|
-
class: "filters-date-input__action",
|
|
21
|
-
id: :reset,
|
|
22
|
-
type: :button,
|
|
23
|
-
title: t("avo.reset").capitalize,
|
|
1
|
+
<%= content_tag :div, class: "filters-section__body", data: {
|
|
2
|
+
controller: "date-time-filter",
|
|
3
|
+
filter_name: filter.name,
|
|
4
|
+
date_time_filter_class_value: filter.class.to_s,
|
|
5
|
+
date_time_filter_keep_filters_panel_open_value: @resource.keep_filters_panel_open,
|
|
6
|
+
date_time_filter_picker_options_value: filter.picker_options(@applied_filters[filter.class.to_s])
|
|
7
|
+
} do %>
|
|
8
|
+
<div class="filters-date-input">
|
|
9
|
+
<div class="w-full" data-slot="value">
|
|
10
|
+
<%= text_field_tag :value, "",
|
|
11
|
+
class: input_classes("w-full mb-0 !pe-9"),
|
|
12
|
+
placeholder: filter.class.empty_message,
|
|
13
|
+
autocomplete: "off",
|
|
24
14
|
data: {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
} do %>
|
|
28
|
-
<%= svg "tabler/outline/x", class: "filters-date-input__action-icon" %>
|
|
29
|
-
<% end %>
|
|
15
|
+
date_time_filter_target: "input"
|
|
16
|
+
} %>
|
|
30
17
|
</div>
|
|
31
18
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
19
|
+
<%= content_tag :button,
|
|
20
|
+
class: "filters-date-input__action",
|
|
21
|
+
id: :reset,
|
|
22
|
+
type: :button,
|
|
23
|
+
title: t("avo.reset").capitalize,
|
|
24
|
+
data: {
|
|
25
|
+
action: "click->date-time-filter#clear",
|
|
26
|
+
tippy: :tooltip
|
|
27
|
+
} do %>
|
|
28
|
+
<%= svg "tabler/outline/x", class: "filters-date-input__action-icon" %>
|
|
29
|
+
<% end %>
|
|
30
|
+
</div>
|
|
31
|
+
|
|
32
|
+
<div class="flex justify-end">
|
|
33
|
+
<%= a_button style: :primary, data: {action: "date-time-filter#changeFilter"}, size: :sm do %>
|
|
34
|
+
<%= filter.button_label || "#{t("avo.filter_by")} #{filter.name}" %>
|
|
35
|
+
<% end %>
|
|
36
|
+
</div>
|
|
37
|
+
<%= link_to "url_redirect", request.url, data: {"date-time-filter-target": "urlRedirect", "turbo-frame": params[:turbo_frame]}, class: "hidden" %>
|
|
39
38
|
<% end %>
|
|
@@ -1,22 +1,20 @@
|
|
|
1
1
|
<div
|
|
2
|
+
class="filters-section__body"
|
|
2
3
|
data-controller="multiple-select-filter"
|
|
3
4
|
data-filter-name="<%= filter.name %>"
|
|
4
|
-
data-multiple-select-filter-keep-filters-panel-open-value="<%= @resource.keep_filters_panel_open %>"
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
'data-filter-class': filter.class.to_s,
|
|
13
|
-
'data-multiple-select-filter-target': 'selector' %>
|
|
5
|
+
data-multiple-select-filter-keep-filters-panel-open-value="<%= @resource.keep_filters_panel_open %>">
|
|
6
|
+
<%= select_tag filter.id, options_for_select(filter.options.invert, filter.selected_value(@applied_filters)),
|
|
7
|
+
class: input_classes("filters-multi-select w-full"),
|
|
8
|
+
multiple: true,
|
|
9
|
+
size: filter.options.size.clamp(2, 4),
|
|
10
|
+
id: "avo_filters_#{filter.id.parameterize.underscore}",
|
|
11
|
+
"data-filter-class": filter.class.to_s,
|
|
12
|
+
"data-multiple-select-filter-target": "selector" %>
|
|
14
13
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
<% end %>
|
|
14
|
+
<div class="flex justify-end">
|
|
15
|
+
<%= a_button style: :primary, size: :sm, data: {action: "multiple-select-filter#changeFilter"} do %>
|
|
16
|
+
<%= filter.button_label || "#{t("avo.filter_by")} #{filter.name}" %>
|
|
17
|
+
<% end %>
|
|
18
|
+
</div>
|
|
19
|
+
<%= link_to "url_redirect", request.url, data: {"multiple-select-filter-target": "urlRedirect", "turbo-frame": params[:turbo_frame]}, class: "hidden" %>
|
|
22
20
|
</div>
|
|
@@ -1,17 +1,14 @@
|
|
|
1
1
|
<div
|
|
2
|
+
class="filters-section__body"
|
|
2
3
|
data-controller="select-filter"
|
|
3
4
|
data-filter-name="<%= filter.name %>"
|
|
4
|
-
data-select-filter-keep-filters-panel-open-value="<%= @resource.keep_filters_panel_open %>"
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
'data-action': "change->select-filter#changeFilter"
|
|
14
|
-
%>
|
|
15
|
-
<%= link_to 'url_redirect', request.url, data: { 'select-filter-target': 'urlRedirect', 'turbo-frame': params[:turbo_frame] }, class: 'hidden' %>
|
|
16
|
-
<% end %>
|
|
5
|
+
data-select-filter-keep-filters-panel-open-value="<%= @resource.keep_filters_panel_open %>">
|
|
6
|
+
<%= select_tag filter.id, options_for_select(filter.options.invert, filter.applied_or_default_value(@applied_filters)),
|
|
7
|
+
class: input_classes("w-full mb-0"),
|
|
8
|
+
include_blank: filter.class.empty_message || "—",
|
|
9
|
+
id: "avo_filters_#{filter.id.parameterize.underscore}",
|
|
10
|
+
"data-filter-class": filter.class,
|
|
11
|
+
"data-select-filter-target": "selector",
|
|
12
|
+
"data-action": "change->select-filter#changeFilter" %>
|
|
13
|
+
<%= link_to "url_redirect", request.url, data: {"select-filter-target": "urlRedirect", "turbo-frame": params[:turbo_frame]}, class: "hidden" %>
|
|
17
14
|
</div>
|
|
@@ -1,22 +1,21 @@
|
|
|
1
1
|
<div
|
|
2
|
+
class="filters-section__body"
|
|
2
3
|
data-controller="text-filter"
|
|
3
4
|
data-filter-name="<%= filter.name %>"
|
|
4
|
-
data-text-filter-keep-filters-panel-open-value="<%= @resource.keep_filters_panel_open %>"
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
'data-action': 'keypress->text-filter#tryToSubmit' %>
|
|
5
|
+
data-text-filter-keep-filters-panel-open-value="<%= @resource.keep_filters_panel_open %>">
|
|
6
|
+
<%= text_field_tag filter.id, filter.applied_or_default_value(@applied_filters),
|
|
7
|
+
class: input_classes("w-full mb-0"),
|
|
8
|
+
id: "avo_filters_#{filter.id.parameterize.underscore}",
|
|
9
|
+
placeholder: filter.class.empty_message,
|
|
10
|
+
autocomplete: "off",
|
|
11
|
+
"data-filter-class": filter.class.to_s,
|
|
12
|
+
"data-text-filter-target": "text",
|
|
13
|
+
"data-action": "keypress->text-filter#tryToSubmit" %>
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
<% end %>
|
|
15
|
+
<div class="flex justify-end">
|
|
16
|
+
<%= a_button style: :primary, data: {action: "text-filter#changeFilter"}, size: :sm do %>
|
|
17
|
+
<%= filter.button_label || "#{t("avo.filter_by")} #{filter.name}" %>
|
|
18
|
+
<% end %>
|
|
19
|
+
</div>
|
|
20
|
+
<%= link_to "url_redirect", request.url, data: {"text-filter-target": "urlRedirect", "turbo-frame": params[:turbo_frame]}, class: "hidden" %>
|
|
22
21
|
</div>
|
data/lib/avo/base_action.rb
CHANGED
data/lib/avo/version.rb
CHANGED
data/lib/avo.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: avo
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 4.0.
|
|
4
|
+
version: 4.0.10
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Adrian Marin
|
|
@@ -10,7 +10,7 @@ authors:
|
|
|
10
10
|
autorequire:
|
|
11
11
|
bindir: bin
|
|
12
12
|
cert_chain: []
|
|
13
|
-
date: 2026-07-
|
|
13
|
+
date: 2026-07-08 00:00:00.000000000 Z
|
|
14
14
|
dependencies:
|
|
15
15
|
- !ruby/object:Gem::Dependency
|
|
16
16
|
name: activerecord
|
|
@@ -895,7 +895,6 @@ files:
|
|
|
895
895
|
- app/views/avo/private/appearance.html.erb
|
|
896
896
|
- app/views/avo/private/design.html.erb
|
|
897
897
|
- app/views/avo/sidebar/_license_warning.html.erb
|
|
898
|
-
- app/views/layouts/avo/_filter_wrapper.html.erb
|
|
899
898
|
- app/views/layouts/avo/application.html.erb
|
|
900
899
|
- app/views/layouts/avo/blank.html.erb
|
|
901
900
|
- app/views/layouts/avo/modal.html.erb
|