avo 2.11.1.pre.2 → 2.11.1.pre.3
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of avo might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/app/assets/stylesheets/avo.css +1 -4
- data/app/assets/stylesheets/css/sidebar.css +28 -0
- data/app/components/avo/fields/date_field/show_component.html.erb +4 -0
- data/app/components/avo/fields/has_one_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/has_one_field/show_component.rb +7 -6
- data/app/components/avo/fields/text_field/index_component.html.erb +2 -0
- data/app/components/avo/fields/text_field/show_component.html.erb +2 -0
- data/app/components/avo/index/field_wrapper_component.html.erb +4 -0
- data/app/components/avo/index/resource_controls_component.rb +7 -5
- data/app/components/avo/index/resource_table_component.html.erb +1 -1
- data/app/components/avo/index/resource_table_component.rb +2 -1
- data/app/components/avo/index/table_row_component.html.erb +1 -1
- data/app/components/avo/index/table_row_component.rb +2 -1
- data/app/components/avo/resource_component.rb +11 -5
- data/app/components/avo/sidebar_component.html.erb +2 -2
- data/app/components/avo/tab_switcher_component.rb +4 -0
- data/app/components/avo/views/resource_edit_component.rb +4 -6
- data/app/components/avo/views/resource_index_component.html.erb +1 -1
- data/app/components/avo/views/resource_index_component.rb +5 -3
- data/app/components/avo/views/resource_show_component.html.erb +1 -1
- data/app/components/avo/views/resource_show_component.rb +3 -1
- data/app/controllers/avo/application_controller.rb +24 -9
- data/app/controllers/avo/associations_controller.rb +38 -12
- data/app/controllers/avo/base_controller.rb +2 -1
- data/app/javascript/js/controllers/sidebar_controller.js +46 -0
- data/app/javascript/js/controllers.js +2 -2
- data/app/views/avo/base/index.html.erb +1 -0
- data/app/views/avo/base/show.html.erb +7 -1
- data/app/views/avo/partials/_javascript.html.erb +1 -0
- data/app/views/avo/partials/_navbar.html.erb +5 -2
- data/app/views/layouts/avo/application.html.erb +3 -3
- data/lib/avo/concerns/has_fields.rb +5 -0
- data/lib/avo/concerns/has_html_attributes.rb +1 -1
- data/lib/avo/fields/has_base_field.rb +11 -0
- data/lib/avo/fields/text_field.rb +4 -2
- data/lib/avo/services/authorization_service.rb +41 -37
- data/lib/avo/version.rb +1 -1
- data/lib/avo.rb +1 -0
- data/public/avo-assets/avo.css +43 -11
- data/public/avo-assets/avo.js +68 -67
- data/public/avo-assets/avo.js.map +3 -3
- metadata +4 -3
- data/app/javascript/js/controllers/mobile_controller.js +0 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 794b7326ae2257afd693641ff51ba513d09d4729a77a671a96f1291f0b31b8e3
|
4
|
+
data.tar.gz: a3b8b5d2f19e9ac16164ae6cb634a0f53d92da7af1b4bc3c829704327f112c91
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 15b95f8cef9a7ec9af6a272dd2abddbb7d8471f5edefb568b16e84f3b26165f7ac4f913974d70291463c8fcbc4427d7608a41a01c0167864d0368178ebf1e755
|
7
|
+
data.tar.gz: 7a7b600d0cc554e8aa30377199dad939e82c8165310b9f81cfe911c06a4d3cac3c72617fdad432475cd61bfcb60a1d00ee5ba4101a2d204940f48f6c6f03ba72
|
data/Gemfile.lock
CHANGED
@@ -16,6 +16,7 @@
|
|
16
16
|
@import './css/breadcrumbs.css';
|
17
17
|
@import './css/search.css';
|
18
18
|
@import './css/active-storage.css';
|
19
|
+
@import './css/sidebar.css';
|
19
20
|
@import './css/spinner.css';
|
20
21
|
@import './css/tags.css';
|
21
22
|
|
@@ -69,10 +70,6 @@ body {
|
|
69
70
|
@apply opacity-0 translate-y-1;
|
70
71
|
}
|
71
72
|
|
72
|
-
.application-sidebar .active:hover,
|
73
|
-
.application-sidebar .active {
|
74
|
-
@apply bg-blue-100 text-blue-500;
|
75
|
-
}
|
76
73
|
|
77
74
|
.turbo-progress-bar {
|
78
75
|
@apply bg-blue-400;
|
@@ -0,0 +1,28 @@
|
|
1
|
+
.application-sidebar .active:hover,
|
2
|
+
.application-sidebar .active {
|
3
|
+
@apply bg-blue-100 text-blue-500;
|
4
|
+
}
|
5
|
+
|
6
|
+
.content-area {
|
7
|
+
/* remove the left padding. */
|
8
|
+
.main-content-area {
|
9
|
+
@apply lg:pl-0;
|
10
|
+
}
|
11
|
+
|
12
|
+
/* Hide the sidebar by default. */
|
13
|
+
.avo-sidebar {
|
14
|
+
@apply lg:hidden;
|
15
|
+
}
|
16
|
+
|
17
|
+
&.sidebar-open {
|
18
|
+
/* Add padding to the main area to allow for the sidebar to expand. */
|
19
|
+
.main-content-area {
|
20
|
+
@apply lg:pl-64;
|
21
|
+
}
|
22
|
+
|
23
|
+
/* Show the sidebar. */
|
24
|
+
.avo-sidebar {
|
25
|
+
@apply lg:block;
|
26
|
+
}
|
27
|
+
}
|
28
|
+
}
|
@@ -7,7 +7,7 @@
|
|
7
7
|
<% c.tools do %>
|
8
8
|
<% if !@field.readonly && can_attach? %>
|
9
9
|
<%= a_link attach_path, icon: 'heroicons/outline/link', color: :primary, 'data-turbo-frame': 'attach_modal' do %>
|
10
|
-
<%= t('avo.attach_item', item: @field.name) %>
|
10
|
+
<%= t('avo.attach_item', item: @field.name.downcase) %>
|
11
11
|
<% end %>
|
12
12
|
<% end %>
|
13
13
|
<% end %>
|
@@ -4,19 +4,20 @@ class Avo::Fields::HasOneField::ShowComponent < Avo::Fields::ShowComponent
|
|
4
4
|
include Avo::ApplicationHelper
|
5
5
|
|
6
6
|
def can_attach?
|
7
|
-
|
7
|
+
policy_result = true
|
8
|
+
|
8
9
|
if @field.present?
|
9
10
|
reflection_resource = @field.target_resource
|
10
11
|
if reflection_resource.present? && @resource.present?
|
11
|
-
method_name =
|
12
|
-
defined_policy_methods = @resource.authorization.defined_methods(@resource.model_class, raise_exception: false)
|
12
|
+
method_name = "attach_#{@field.id}?".to_sym
|
13
13
|
|
14
|
-
if
|
15
|
-
|
14
|
+
if @resource.authorization.has_method?(method_name, raise_exception: false)
|
15
|
+
policy_result = @resource.authorization.authorize_action(method_name, raise_exception: false)
|
16
16
|
end
|
17
17
|
end
|
18
18
|
end
|
19
|
-
|
19
|
+
|
20
|
+
policy_result
|
20
21
|
end
|
21
22
|
|
22
23
|
def attach_path
|
@@ -1,6 +1,8 @@
|
|
1
1
|
<%= index_field_wrapper field: @field, resource: @resource do %>
|
2
2
|
<% if @field.as_html %>
|
3
3
|
<%== @field.value %>
|
4
|
+
<% elsif @field.protocol.present? %>
|
5
|
+
<%= link_to @field.value, "#{@field.protocol}:#{@field.value}" %>
|
4
6
|
<% else %>
|
5
7
|
<%= link_to_if @field.link_to_resource, @field.value, resource_path %>
|
6
8
|
<% end %>
|
@@ -1,6 +1,8 @@
|
|
1
1
|
<%= show_field_wrapper field: @field, resource: @resource, index: @index do %>
|
2
2
|
<% if @field.as_html %>
|
3
3
|
<%== @field.value %>
|
4
|
+
<% elsif @field.protocol.present? %>
|
5
|
+
<%= link_to @field.value, "#{@field.protocol}:#{@field.value}" %>
|
4
6
|
<% else %>
|
5
7
|
<%= @field.value %>
|
6
8
|
<% end %>
|
@@ -1,10 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
class Avo::Index::ResourceControlsComponent < Avo::ResourceComponent
|
4
|
-
def initialize(resource: nil, reflection: nil, parent_model: nil, view_type: :table)
|
4
|
+
def initialize(resource: nil, reflection: nil, parent_model: nil, parent_resource: nil, view_type: :table)
|
5
5
|
@resource = resource
|
6
6
|
@reflection = reflection
|
7
7
|
@parent_model = parent_model
|
8
|
+
@parent_resource = parent_resource
|
8
9
|
@view_type = view_type
|
9
10
|
end
|
10
11
|
|
@@ -12,7 +13,7 @@ class Avo::Index::ResourceControlsComponent < Avo::ResourceComponent
|
|
12
13
|
@reflection.present? &&
|
13
14
|
@resource.model.present? &&
|
14
15
|
is_has_many_association &&
|
15
|
-
authorize_association_for(
|
16
|
+
authorize_association_for(:detach)
|
16
17
|
end
|
17
18
|
|
18
19
|
def can_edit?
|
@@ -22,8 +23,9 @@ class Avo::Index::ResourceControlsComponent < Avo::ResourceComponent
|
|
22
23
|
end
|
23
24
|
|
24
25
|
def can_view?
|
25
|
-
return authorize_association_for(:
|
26
|
+
return authorize_association_for(:show) if @reflection.present?
|
26
27
|
|
28
|
+
# Even if there's a @reflection object present, for show we're going to fallback to the original policy.
|
27
29
|
@resource.authorization.authorize_action(:show, raise_exception: false)
|
28
30
|
end
|
29
31
|
|
@@ -42,7 +44,7 @@ class Avo::Index::ResourceControlsComponent < Avo::ResourceComponent
|
|
42
44
|
|
43
45
|
def edit_path
|
44
46
|
# Add the `view` param to let Avo know where to redirect back when the user clicks the `Cancel` button.
|
45
|
-
args = {via_view:
|
47
|
+
args = {via_view: "index"}
|
46
48
|
|
47
49
|
if @parent_model.present?
|
48
50
|
args = {
|
@@ -73,6 +75,6 @@ class Avo::Index::ResourceControlsComponent < Avo::ResourceComponent
|
|
73
75
|
end
|
74
76
|
|
75
77
|
def referrer_path
|
76
|
-
Avo::App.root_path(paths: [
|
78
|
+
Avo::App.root_path(paths: ["resources", params[:resource_name], params[:id], params[:related_name]], query: request.query_parameters.to_h)
|
77
79
|
end
|
78
80
|
end
|
@@ -4,7 +4,7 @@
|
|
4
4
|
<tbody class="divide-y">
|
5
5
|
<% @resources.each_with_index do |resource, index| %>
|
6
6
|
<% cache_if Avo.configuration.cache_resources_on_index_view, resource.cache_hash(@parent_model), expires_in: 1.day do %>
|
7
|
-
<%= render Avo::Index::TableRowComponent.new(resource: resource, reflection: @reflection, parent_model: @parent_model) %>
|
7
|
+
<%= render Avo::Index::TableRowComponent.new(resource: resource, reflection: @reflection, parent_model: @parent_model, parent_resource: @parent_resource) %>
|
8
8
|
<% end %>
|
9
9
|
<% end %>
|
10
10
|
</tbody>
|
@@ -1,10 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
class Avo::Index::ResourceTableComponent < ViewComponent::Base
|
4
|
-
def initialize(resources: nil, resource: nil, reflection: nil, parent_model: nil)
|
4
|
+
def initialize(resources: nil, resource: nil, reflection: nil, parent_model: nil, parent_resource: nil)
|
5
5
|
@resources = resources
|
6
6
|
@resource = resource
|
7
7
|
@reflection = reflection
|
8
8
|
@parent_model = parent_model
|
9
|
+
@parent_resource = parent_resource
|
9
10
|
end
|
10
11
|
end
|
@@ -14,7 +14,7 @@
|
|
14
14
|
<% end %>
|
15
15
|
<td class="text-right whitespace-nowrap px-2">
|
16
16
|
<div class="flex items-center justify-end flex-grow-0 h-full w-full">
|
17
|
-
<%= render(Avo::Index::ResourceControlsComponent.new(resource: @resource, reflection: @reflection, parent_model: @parent_model, view_type: :table)) %>
|
17
|
+
<%= render(Avo::Index::ResourceControlsComponent.new(resource: @resource, reflection: @reflection, parent_model: @parent_model, parent_resource: @parent_resource, view_type: :table)) %>
|
18
18
|
</div>
|
19
19
|
</td>
|
20
20
|
</tr>
|
@@ -3,9 +3,10 @@
|
|
3
3
|
class Avo::Index::TableRowComponent < ViewComponent::Base
|
4
4
|
include Avo::ResourcesHelper
|
5
5
|
|
6
|
-
def initialize(resource: nil, reflection: nil, parent_model: nil)
|
6
|
+
def initialize(resource: nil, reflection: nil, parent_model: nil, parent_resource: nil)
|
7
7
|
@resource = resource
|
8
8
|
@reflection = reflection
|
9
9
|
@parent_model = parent_model
|
10
|
+
@parent_resource = parent_resource
|
10
11
|
end
|
11
12
|
end
|
@@ -39,23 +39,29 @@ class Avo::ResourceComponent < Avo::BaseComponent
|
|
39
39
|
end
|
40
40
|
|
41
41
|
def authorize_association_for(policy_method)
|
42
|
-
|
42
|
+
policy_result = true
|
43
43
|
|
44
44
|
if @reflection.present?
|
45
|
+
# Fetch the appropiate resource
|
45
46
|
reflection_resource = ::Avo::App.get_resource_by_model_name(@reflection.active_record.name)
|
47
|
+
# Fetch the model
|
48
|
+
# Hydrate the resource with the model if we have one
|
46
49
|
reflection_resource.hydrate(model: @parent_model) if @parent_model.present?
|
47
|
-
|
50
|
+
# Use the related_name as the base of the association
|
51
|
+
association_name = @reflection.name
|
48
52
|
|
49
53
|
if association_name.present?
|
50
54
|
method_name = "#{policy_method}_#{association_name}?".to_sym
|
55
|
+
# Prepare the authorization service
|
56
|
+
service = reflection_resource.authorization
|
51
57
|
|
52
|
-
if
|
53
|
-
|
58
|
+
if service.has_method?(method_name, raise_exception: false)
|
59
|
+
policy_result = service.authorize_action(method_name, raise_exception: false)
|
54
60
|
end
|
55
61
|
end
|
56
62
|
end
|
57
63
|
|
58
|
-
|
64
|
+
policy_result
|
59
65
|
end
|
60
66
|
|
61
67
|
def main_panel
|
@@ -1,6 +1,6 @@
|
|
1
1
|
<div
|
2
|
-
class="fixed z-[60] t-0 application-sidebar w-64 hidden lg:flex flex-1 border-r lg:border-none bg-none h-[calc(100vh-4rem)] bg-gray-25 lg:bg-transparent <%= 'print:hidden' if Avo.configuration.hide_layout_when_printing %>"
|
3
|
-
data-
|
2
|
+
class="avo-sidebar fixed z-[60] t-0 application-sidebar w-64 hidden lg:flex flex-1 border-r lg:border-none bg-none h-[calc(100vh-4rem)] bg-gray-25 lg:bg-transparent <%= 'print:hidden' if Avo.configuration.hide_layout_when_printing %>";
|
3
|
+
data-sidebar-target="sidebar"
|
4
4
|
>
|
5
5
|
<div class="flex flex-col w-full h-full">
|
6
6
|
<div class="flex-1 flex flex-col justify-between overflow-auto h-full pt-3 scroll-shadows">
|
@@ -22,12 +22,10 @@ class Avo::Views::ResourceEditComponent < Avo::ResourceComponent
|
|
22
22
|
helpers.resource_path(model: params[:via_resource_class].safe_constantize, resource: relation_resource, resource_id: params[:via_resource_id])
|
23
23
|
elsif via_index?
|
24
24
|
helpers.resources_path(resource: @resource)
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
helpers.resources_path(resource: @resource)
|
30
|
-
end
|
25
|
+
elsif is_edit? # via resource show page
|
26
|
+
helpers.resource_path(model: @resource.model, resource: @resource)
|
27
|
+
else
|
28
|
+
helpers.resources_path(resource: @resource)
|
31
29
|
end
|
32
30
|
end
|
33
31
|
|
@@ -51,7 +51,7 @@
|
|
51
51
|
<% if @resources.present? %>
|
52
52
|
<div class="w-full overflow-auto flex flex-col mt-0">
|
53
53
|
<div class="relative flex-1 flex">
|
54
|
-
<%= render(Avo::Index::ResourceTableComponent.new(resources: @resources, resource: @resource, reflection: @reflection, parent_model: @parent_model)) %>
|
54
|
+
<%= render(Avo::Index::ResourceTableComponent.new(resources: @resources, resource: @resource, reflection: @reflection, parent_model: @parent_model, parent_resource: @parent_resource)) %>
|
55
55
|
</div>
|
56
56
|
</div>
|
57
57
|
<% else %>
|
@@ -15,6 +15,7 @@ class Avo::Views::ResourceIndexComponent < Avo::ResourceComponent
|
|
15
15
|
reflection: nil,
|
16
16
|
turbo_frame: "",
|
17
17
|
parent_model: nil,
|
18
|
+
parent_resource: nil,
|
18
19
|
applied_filters: []
|
19
20
|
)
|
20
21
|
@resource = resource
|
@@ -27,6 +28,7 @@ class Avo::Views::ResourceIndexComponent < Avo::ResourceComponent
|
|
27
28
|
@reflection = reflection
|
28
29
|
@turbo_frame = turbo_frame
|
29
30
|
@parent_model = parent_model
|
31
|
+
@parent_resource = parent_resource
|
30
32
|
@applied_filters = applied_filters
|
31
33
|
@view = :index
|
32
34
|
end
|
@@ -52,7 +54,7 @@ class Avo::Views::ResourceIndexComponent < Avo::ResourceComponent
|
|
52
54
|
# The Create button is dependent on the new? policy method.
|
53
55
|
# The create? should be called only when the user clicks the Save button so the developers gets access to the params from the form.
|
54
56
|
def can_see_the_create_button?
|
55
|
-
return authorize_association_for(
|
57
|
+
return authorize_association_for(:create) if @reflection.present?
|
56
58
|
|
57
59
|
@resource.authorization.authorize_action(:new, raise_exception: false) && !has_reflection_and_is_read_only
|
58
60
|
end
|
@@ -60,7 +62,7 @@ class Avo::Views::ResourceIndexComponent < Avo::ResourceComponent
|
|
60
62
|
def can_see_the_actions_button?
|
61
63
|
return false if @actions.blank?
|
62
64
|
|
63
|
-
return authorize_association_for(
|
65
|
+
return authorize_association_for(:act_on) if @reflection.present?
|
64
66
|
|
65
67
|
@resource.authorization.authorize_action(:act_on, raise_exception: false) && !has_reflection_and_is_read_only
|
66
68
|
end
|
@@ -69,7 +71,7 @@ class Avo::Views::ResourceIndexComponent < Avo::ResourceComponent
|
|
69
71
|
klass = @reflection
|
70
72
|
klass = @reflection.through_reflection if klass.is_a? ::ActiveRecord::Reflection::ThroughReflection
|
71
73
|
|
72
|
-
@reflection.present? && klass.is_a?(::ActiveRecord::Reflection::HasManyReflection) && !has_reflection_and_is_read_only && authorize_association_for(
|
74
|
+
@reflection.present? && klass.is_a?(::ActiveRecord::Reflection::HasManyReflection) && !has_reflection_and_is_read_only && authorize_association_for(:attach)
|
73
75
|
end
|
74
76
|
|
75
77
|
def has_reflection_and_is_read_only
|
@@ -19,8 +19,8 @@
|
|
19
19
|
} do %>
|
20
20
|
<%= t('avo.detach_item', item: title).capitalize %>
|
21
21
|
<% end %>
|
22
|
-
<%= render Avo::ActionsComponent.new actions: @actions, resource: @resource, view: @view %>
|
23
22
|
<% end %>
|
23
|
+
<%= render Avo::ActionsComponent.new actions: @actions, resource: @resource, view: @view %>
|
24
24
|
<% if can_see_the_edit_button? %>
|
25
25
|
<%= a_link edit_path,
|
26
26
|
color: :primary,
|
@@ -4,11 +4,13 @@ class Avo::Views::ResourceShowComponent < Avo::ResourceComponent
|
|
4
4
|
include Avo::ResourcesHelper
|
5
5
|
include Avo::ApplicationHelper
|
6
6
|
|
7
|
-
def initialize(resource: nil, reflection: nil, parent_model: nil, resource_panel: nil, actions: [])
|
7
|
+
def initialize(resource: nil, reflection: nil, parent_resource: nil, parent_model: nil, resource_panel: nil, actions: [])
|
8
8
|
@resource = resource
|
9
9
|
@reflection = reflection
|
10
10
|
@resource_panel = resource_panel
|
11
11
|
@actions = actions
|
12
|
+
@parent_model = parent_model
|
13
|
+
@parent_resource = parent_resource
|
12
14
|
@view = :show
|
13
15
|
end
|
14
16
|
|
@@ -21,6 +21,7 @@ module Avo
|
|
21
21
|
before_action :set_container_classes
|
22
22
|
before_action :add_initial_breadcrumbs
|
23
23
|
before_action :set_view
|
24
|
+
before_action :set_sidebar_open
|
24
25
|
|
25
26
|
rescue_from Pundit::NotAuthorizedError, with: :render_unauthorized
|
26
27
|
rescue_from ActiveRecord::RecordInvalid, with: :exception_logger
|
@@ -129,7 +130,11 @@ module Avo
|
|
129
130
|
end
|
130
131
|
|
131
132
|
def set_related_model
|
132
|
-
@related_model =
|
133
|
+
@related_model = if @field.is_a? Avo::Fields::HasOneField
|
134
|
+
@model.send params[:related_name]
|
135
|
+
else
|
136
|
+
eager_load_files(@related_resource, @model.send(params[:related_name])).find params[:related_id]
|
137
|
+
end
|
133
138
|
end
|
134
139
|
|
135
140
|
def set_view
|
@@ -155,15 +160,20 @@ module Avo
|
|
155
160
|
end
|
156
161
|
|
157
162
|
def hydrate_related_resource
|
158
|
-
@related_resource.hydrate(view: action_name.to_sym, user: _current_user)
|
163
|
+
@related_resource.hydrate(view: action_name.to_sym, user: _current_user, model: @model)
|
159
164
|
end
|
160
165
|
|
161
|
-
def
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
166
|
+
def authorize_base_action
|
167
|
+
class_to_authorize = @model || @resource.model_class
|
168
|
+
|
169
|
+
authorize_action class_to_authorize
|
170
|
+
end
|
171
|
+
|
172
|
+
def authorize_action(class_to_authorize, action = nil)
|
173
|
+
# Use the provided action or figure it out from the request
|
174
|
+
action_to_authorize = action || action_name
|
175
|
+
|
176
|
+
@authorization.set_record(class_to_authorize).authorize_action action_to_authorize.to_sym
|
167
177
|
end
|
168
178
|
|
169
179
|
# Get the pluralized resource name for this request
|
@@ -310,10 +320,15 @@ module Avo
|
|
310
320
|
|
311
321
|
def default_url_options
|
312
322
|
if params[:force_locale].present?
|
313
|
-
{
|
323
|
+
{**super, force_locale: params[:force_locale]}
|
314
324
|
else
|
315
325
|
super
|
316
326
|
end
|
317
327
|
end
|
328
|
+
|
329
|
+
def set_sidebar_open
|
330
|
+
value = cookies["#{Avo::COOKIES_KEY}.sidebar.open"]
|
331
|
+
@sidebar_open = value.blank? || value == '1'
|
332
|
+
end
|
318
333
|
end
|
319
334
|
end
|
@@ -5,12 +5,16 @@ module Avo
|
|
5
5
|
before_action :set_model, only: [:show, :index, :new, :create, :destroy, :order]
|
6
6
|
before_action :set_related_resource_name
|
7
7
|
before_action :set_related_resource, only: [:show, :index, :new, :create, :destroy, :order]
|
8
|
-
before_action :
|
8
|
+
before_action :set_reflection_field
|
9
|
+
before_action :hydrate_related_resource, only: [:show, :index, :create, :destroy, :order]
|
9
10
|
before_action :set_related_model, only: [:show, :order]
|
11
|
+
before_action :set_reflection
|
10
12
|
before_action :set_attachment_class, only: [:show, :index, :new, :create, :destroy, :order]
|
11
13
|
before_action :set_attachment_resource, only: [:show, :index, :new, :create, :destroy, :order]
|
12
14
|
before_action :set_attachment_model, only: [:create, :destroy, :order]
|
13
|
-
before_action :
|
15
|
+
before_action :authorize_index_action, only: :index
|
16
|
+
before_action :authorize_attach_action, only: :new
|
17
|
+
before_action :authorize_detach_action, only: :destroy
|
14
18
|
|
15
19
|
def index
|
16
20
|
@parent_resource = @resource.dup
|
@@ -28,6 +32,8 @@ module Avo
|
|
28
32
|
end
|
29
33
|
|
30
34
|
def show
|
35
|
+
@parent_resource, @parent_model = @resource, @model
|
36
|
+
|
31
37
|
@resource, @model = @related_resource, @related_model
|
32
38
|
|
33
39
|
super
|
@@ -36,12 +42,6 @@ module Avo
|
|
36
42
|
def new
|
37
43
|
@resource.hydrate(model: @model)
|
38
44
|
|
39
|
-
begin
|
40
|
-
@field = @resource.get_field_definitions.find { |f| f.id == @related_resource_name.to_sym }
|
41
|
-
@field.hydrate(resource: @resource, model: @model, view: :new)
|
42
|
-
rescue
|
43
|
-
end
|
44
|
-
|
45
45
|
if @field.present? && !@field.searchable
|
46
46
|
query = @authorization.apply_policy @attachment_class
|
47
47
|
|
@@ -93,8 +93,12 @@ module Avo
|
|
93
93
|
|
94
94
|
private
|
95
95
|
|
96
|
+
def set_reflection
|
97
|
+
@reflection = @model._reflections[params[:related_name].to_s]
|
98
|
+
end
|
99
|
+
|
96
100
|
def set_attachment_class
|
97
|
-
@attachment_class = @
|
101
|
+
@attachment_class = @reflection.klass
|
98
102
|
end
|
99
103
|
|
100
104
|
def set_attachment_resource
|
@@ -102,11 +106,13 @@ module Avo
|
|
102
106
|
end
|
103
107
|
|
104
108
|
def set_attachment_model
|
105
|
-
@attachment_model = @
|
109
|
+
@attachment_model = @attachment_class.find attachment_id
|
106
110
|
end
|
107
111
|
|
108
|
-
def
|
109
|
-
@
|
112
|
+
def set_reflection_field
|
113
|
+
@field = @resource.get_field_definitions.find { |f| f.id == @related_resource_name.to_sym }
|
114
|
+
@field.hydrate(resource: @resource, model: @model, view: :new)
|
115
|
+
rescue
|
110
116
|
end
|
111
117
|
|
112
118
|
def attachment_id
|
@@ -121,5 +127,25 @@ module Avo
|
|
121
127
|
|
122
128
|
klass
|
123
129
|
end
|
130
|
+
|
131
|
+
def authorize_if_defined(method)
|
132
|
+
@authorization.set_record(@model)
|
133
|
+
|
134
|
+
if @authorization.has_method?(method.to_sym)
|
135
|
+
@authorization.authorize_action method.to_sym
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def authorize_index_action
|
140
|
+
authorize_if_defined "view_#{@field.id}?"
|
141
|
+
end
|
142
|
+
|
143
|
+
def authorize_attach_action
|
144
|
+
authorize_if_defined "attach_#{@field.id}?"
|
145
|
+
end
|
146
|
+
|
147
|
+
def authorize_detach_action
|
148
|
+
authorize_if_defined "detach_#{@field.id}?"
|
149
|
+
end
|
124
150
|
end
|
125
151
|
end
|
@@ -10,7 +10,8 @@ module Avo
|
|
10
10
|
before_action :set_model_to_fill
|
11
11
|
before_action :set_edit_title_and_breadcrumbs, only: [:edit, :update]
|
12
12
|
before_action :fill_model, only: [:create, :update]
|
13
|
-
|
13
|
+
# Don't run base authorizations for associations
|
14
|
+
before_action :authorize_base_action, if: -> {controller_name != "associations"}
|
14
15
|
|
15
16
|
def index
|
16
17
|
@page_title = @resource.plural_name.humanize
|
@@ -0,0 +1,46 @@
|
|
1
|
+
import { Controller } from '@hotwired/stimulus'
|
2
|
+
import Cookies from 'js-cookie'
|
3
|
+
|
4
|
+
export default class extends Controller {
|
5
|
+
static targets = ['sidebar', 'mainArea']
|
6
|
+
|
7
|
+
static values = {
|
8
|
+
open: Boolean,
|
9
|
+
}
|
10
|
+
|
11
|
+
get cookieKey() {
|
12
|
+
return `${window.Avo.configuration.cookies_key}.sidebar.open`
|
13
|
+
}
|
14
|
+
|
15
|
+
get sidebarOpen() {
|
16
|
+
return Cookies.get(this.cookieKey) === '1'
|
17
|
+
}
|
18
|
+
|
19
|
+
set cookie(state) {
|
20
|
+
Cookies.set(this.cookieKey, state === true ? 1 : 0)
|
21
|
+
}
|
22
|
+
|
23
|
+
markSidebarClosed() {
|
24
|
+
Cookies.set(this.cookieKey, '0')
|
25
|
+
this.openValue = false
|
26
|
+
this.mainAreaTarget.classList.remove('sidebar-open')
|
27
|
+
}
|
28
|
+
|
29
|
+
markSidebarOpen() {
|
30
|
+
Cookies.set(this.cookieKey, '1')
|
31
|
+
this.openValue = true
|
32
|
+
this.mainAreaTarget.classList.add('sidebar-open')
|
33
|
+
}
|
34
|
+
|
35
|
+
toggleSidebar() {
|
36
|
+
if (this.openValue) {
|
37
|
+
this.markSidebarClosed()
|
38
|
+
} else {
|
39
|
+
this.markSidebarOpen()
|
40
|
+
}
|
41
|
+
}
|
42
|
+
|
43
|
+
toggleSidebarOnMobile() {
|
44
|
+
this.sidebarTarget.classList.toggle('hidden')
|
45
|
+
}
|
46
|
+
}
|
@@ -16,7 +16,6 @@ import ItemSelectorController from './controllers/item_selector_controller'
|
|
16
16
|
import KeyValueController from './controllers/fields/key_value_controller'
|
17
17
|
import LoadingButtonController from './controllers/loading_button_controller'
|
18
18
|
import MenuController from './controllers/menu_controller'
|
19
|
-
import MobileController from './controllers/mobile_controller'
|
20
19
|
import ModalController from './controllers/modal_controller'
|
21
20
|
import MultipleSelectFilterController from './controllers/multiple_select_filter_controller'
|
22
21
|
import PerPageController from './controllers/per_page_controller'
|
@@ -26,6 +25,7 @@ import ResourceShowController from './controllers/resource_show_controller'
|
|
26
25
|
import SearchController from './controllers/search_controller'
|
27
26
|
import SelectController from './controllers/select_controller'
|
28
27
|
import SelectFilterController from './controllers/select_filter_controller'
|
28
|
+
import SidebarController from './controllers/sidebar_controller'
|
29
29
|
import SimpleMdeController from './controllers/fields/simple_mde_controller'
|
30
30
|
import TabsController from './controllers/tabs_controller'
|
31
31
|
import TagsFieldController from './controllers/fields/tags_field_controller'
|
@@ -46,7 +46,6 @@ application.register('item-select-all', ItemSelectAllController)
|
|
46
46
|
application.register('item-selector', ItemSelectorController)
|
47
47
|
application.register('loading-button', LoadingButtonController)
|
48
48
|
application.register('menu', MenuController)
|
49
|
-
application.register('mobile', MobileController)
|
50
49
|
application.register('modal', ModalController)
|
51
50
|
application.register('multiple-select-filter', MultipleSelectFilterController)
|
52
51
|
application.register('per-page', PerPageController)
|
@@ -56,6 +55,7 @@ application.register('resource-show', ResourceShowController)
|
|
56
55
|
application.register('search', SearchController)
|
57
56
|
application.register('select', SelectController)
|
58
57
|
application.register('select-filter', SelectFilterController)
|
58
|
+
application.register('sidebar', SidebarController)
|
59
59
|
application.register('tabs', TabsController)
|
60
60
|
application.register('tags-field', TagsFieldController)
|
61
61
|
application.register('text-filter', TextFilterController)
|