avo 2.21.1.pre.issue1450 → 2.21.1.pre.pr1476

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ebf134b0ec573fefe33360ace54658cdaafcf1904a0d88f63e89398f12e34377
4
- data.tar.gz: 4c1ccd709c542910c2590e4b508a549463d0777b33e3baff83a63e4c97a834f9
3
+ metadata.gz: 8f832c5802957b7d88c4271b886cfcb0a727ad98b1d200dc1f8e6d7a5a779067
4
+ data.tar.gz: bb639aec120f3881847aa5ce53bd4bc399da0ae3fde37d01aad77ef13c017cbc
5
5
  SHA512:
6
- metadata.gz: e8bb307e086e09eb90b5cbfcddaee9f0f7fd4437ee742a98a0eaeea24171c68828dfa664a0076c332ce9df0955fb931bd3fe34c41941b4988ebe850d2e7cc682
7
- data.tar.gz: e8169c3475feda95dcf85a9532c26b7157fe598e9544a033684fa343bb15aac0c68f5da776c7120a61d52dc2816ea84b7ac059444f4520e549aeaa09e694f017
6
+ metadata.gz: 53180bdf4636c4dffd120fb8bb0f9ab0dacbbb9aad7e5ac3b906329144510b12b719591ebedb1dd2fb20d81a69d3a4932933d6500b4451e46947e9c3261885f0
7
+ data.tar.gz: 16f6f89ae35d3b8d1c491af4d3b35eee7148d56ee2dcfcdd7ec3a0b0bd16919a0f0424d93c6863f3a1d22acbb1d2be6cf02007122804fed43a11bd6229de491f
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- avo (2.21.1.pre.issue1450)
4
+ avo (2.21.1.pre.pr1476)
5
5
  actionview (>= 6.0)
6
6
  active_link_to
7
7
  activerecord (>= 6.0)
@@ -1,5 +1,6 @@
1
1
  <%= field_wrapper **field_wrapper_args, full_width: true do %>
2
- <%= content_tag :div, class: "relative block overflow-x-auto max-w-full",
2
+ <%= content_tag :div,
3
+ class: "relative block overflow-x-auto max-w-full",
3
4
  data: {
4
5
  controller: "trix-field",
5
6
  trix_field_target: "controller",
@@ -20,6 +20,10 @@ class Avo::Fields::TrixField::EditComponent < Avo::Fields::EditComponent
20
20
  end
21
21
 
22
22
  def trix_id
23
- "trix_#{resource_name}_#{@field.id}"
23
+ if resource_name.present?
24
+ "trix_#{resource_name}_#{@field.id}"
25
+ elsif form.present?
26
+ "trix_#{form.index}_#{@field.id}"
27
+ end
24
28
  end
25
29
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  class Avo::Index::ResourceTableComponent < ViewComponent::Base
4
4
  include Avo::ApplicationHelper
5
- attr_reader :pagy
5
+ attr_reader :pagy, :query
6
6
 
7
7
  def initialize(resources: nil, resource: nil, reflection: nil, parent_model: nil, parent_resource: nil, pagy: nil, query: nil)
8
8
  @resources = resources
@@ -15,10 +15,10 @@ class Avo::Index::ResourceTableComponent < ViewComponent::Base
15
15
  end
16
16
 
17
17
  def encrypted_query
18
- return if @query.nil?
18
+ return :select_all_disabled if query.nil? || !query.respond_to?(:all) || !query.all.respond_to?(:to_sql)
19
19
 
20
20
  Avo::Services::EncryptionService.encrypt(
21
- message: @query.all.to_sql,
21
+ message: query.all.to_sql,
22
22
  purpose: :select_all
23
23
  )
24
24
  end
@@ -53,6 +53,7 @@ class Avo::ResourceComponent < Avo::BaseComponent
53
53
  end
54
54
  end
55
55
 
56
+ # Ex: A Post has many Comments
56
57
  def authorize_association_for(policy_method)
57
58
  policy_result = true
58
59
 
@@ -67,11 +68,12 @@ class Avo::ResourceComponent < Avo::BaseComponent
67
68
 
68
69
  if association_name.present?
69
70
  method_name = "#{policy_method}_#{association_name}?".to_sym
70
- # Prepare the authorization service
71
+ # Use the policy methods from the parent (Post)
71
72
  service = reflection_resource.authorization
72
73
 
73
74
  if service.has_method?(method_name, raise_exception: false)
74
- policy_result = service.authorize_action(method_name, raise_exception: false)
75
+ # Override the record with the child record (Comment not Post)
76
+ policy_result = service.authorize_action(method_name, record: resource.model, raise_exception: false)
75
77
  end
76
78
  end
77
79
  end
@@ -172,11 +172,11 @@ module Avo
172
172
  end
173
173
 
174
174
  def hydrate_resource
175
- @resource.hydrate(view: action_name.to_sym, user: _current_user)
175
+ @resource.hydrate(view: action_name.to_sym, user: _current_user, model: @model)
176
176
  end
177
177
 
178
178
  def hydrate_related_resource
179
- @related_resource.hydrate(view: action_name.to_sym, user: _current_user, model: @model)
179
+ @related_resource.hydrate(view: action_name.to_sym, user: _current_user, model: @related_model)
180
180
  end
181
181
 
182
182
  def authorize_base_action
@@ -3,12 +3,13 @@ require_dependency "avo/base_controller"
3
3
  module Avo
4
4
  class AssociationsController < BaseController
5
5
  before_action :set_model, only: [:show, :index, :new, :create, :destroy, :order]
6
+ before_action :hydrate_resource, only: [:show, :index, :new, :create, :destroy, :order]
6
7
  before_action :set_related_resource_name
7
8
  before_action :set_related_resource, only: [:show, :index, :new, :create, :destroy, :order]
8
9
  before_action :set_related_authorization
9
10
  before_action :set_reflection_field
10
- before_action :hydrate_related_resource, only: [:show, :index, :create, :destroy, :order]
11
11
  before_action :set_related_model, only: [:show, :order]
12
+ before_action :hydrate_related_resource, only: [:show, :index, :create, :destroy, :order]
12
13
  before_action :set_reflection
13
14
  before_action :set_attachment_class, only: [:show, :index, :new, :create, :destroy, :order]
14
15
  before_action :set_attachment_resource, only: [:show, :index, :new, :create, :destroy, :order]
@@ -10,6 +10,10 @@ module Avo
10
10
  blob = ActiveStorage::Blob.create_and_upload! io: params[:file], filename: params[:filename]
11
11
  association_name = BaseResource.valid_attachment_name(@model, params[:attachment_key])
12
12
 
13
+ if association_name.blank?
14
+ raise ActionController::BadRequest.new("Could not find the attachment association for #{params[:attachment_key]} (check the `attachment_key` for this Trix field)")
15
+ end
16
+
13
17
  @model.send(association_name).attach blob
14
18
 
15
19
  render json: {
@@ -315,7 +315,7 @@ module Avo
315
315
  filter[:class].new arguments: filter[:arguments]
316
316
  end
317
317
  .select do |filter|
318
- filter.visible_in_view(resource: @resource, parent_model: @parent_model, parent_resource: @parent_resource)
318
+ filter.visible_in_view(resource: @resource, parent_resource: @parent_resource)
319
319
  end
320
320
  end
321
321
 
@@ -326,7 +326,7 @@ module Avo
326
326
  action[:class].new(model: @model, resource: @resource, view: @view, arguments: action[:arguments])
327
327
  end
328
328
  .select do |action|
329
- action.visible_in_view(parent_model: @parent_model, parent_resource: @parent_resource)
329
+ action.visible_in_view(parent_resource: @parent_resource)
330
330
  end
331
331
  end
332
332
 
@@ -21,7 +21,7 @@ module Avo
21
21
 
22
22
  def set_card
23
23
  @card = @dashboard.item_at_index(params[:index].to_i).tap do |card|
24
- card.hydrate(dashboard: @dashboard, params: params)
24
+ card.hydrate(dashboard: @dashboard)
25
25
  end
26
26
  end
27
27
 
@@ -44,27 +44,33 @@ module Avo
44
44
  end
45
45
 
46
46
  def search_resource(resource)
47
- query = Avo::Hosts::SearchScopeHost.new(
47
+ query = Avo::Hosts::SearchScopeHost.new(
48
48
  block: resource.search_query,
49
49
  params: params,
50
- scope: resource.class.scope.limit(8)
50
+ scope: resource.class.scope
51
51
  ).handle
52
52
 
53
+ # Get the count
54
+ results_count = query.count
55
+
56
+ # Get the results
57
+ query = query.limit(8)
58
+
53
59
  query = apply_scope(query) if should_apply_any_scope?
54
60
 
55
61
  results = apply_search_metadata(query, resource)
56
62
 
57
63
  header = resource.plural_name
58
64
 
59
- if results.length > 0
60
- header += " (#{results.length})"
65
+ if results_count > 0
66
+ header = "#{header} (#{results_count})"
61
67
  end
62
68
 
63
69
  result_object = {
64
70
  header: header,
65
71
  help: resource.class.search_query_help,
66
72
  results: results,
67
- count: results.length
73
+ count: results_count
68
74
  }
69
75
 
70
76
  [resource.name.pluralize.downcase, result_object]
@@ -55,7 +55,7 @@ export default class extends Controller {
55
55
  }
56
56
 
57
57
  // Prevent file uploads for resources that haven't been saved yet.
58
- if (this.resourceId === '') {
58
+ if (!this.resourceId) {
59
59
  event.preventDefault()
60
60
  alert("You can't upload files into the Trix editor until you save the resource.")
61
61
 
@@ -63,7 +63,7 @@ export default class extends Controller {
63
63
  }
64
64
 
65
65
  // Prevent file uploads for fields without an attachment key.
66
- if (this.attachmentKey === '') {
66
+ if (!this.attachmentKey) {
67
67
  event.preventDefault()
68
68
  alert("You haven't set an `attachment_key` to this Trix field.")
69
69
  }
@@ -93,7 +93,10 @@ export default class extends Controller {
93
93
 
94
94
  xhr.open('POST', this.uploadUrl, true)
95
95
 
96
- xhr.setRequestHeader('X-CSRF-Token', document.querySelector('meta[name="csrf-token"]').content)
96
+ const csrfToken = document.querySelector('meta[name="csrf-token"]')?.content
97
+ if (csrfToken) {
98
+ xhr.setRequestHeader('X-CSRF-Token', csrfToken)
99
+ }
97
100
 
98
101
  xhr.upload.addEventListener('progress', (event) => {
99
102
  // eslint-disable-next-line no-mixed-operators
@@ -18,8 +18,7 @@ export default class extends Controller {
18
18
  document.querySelectorAll(`[data-controller="item-selector"][data-resource-name="${this.resourceName}"] input[type=checkbox]`)
19
19
  .forEach((checkbox) => checkbox.checked !== checked && checkbox.click())
20
20
 
21
- // Only run "all matching" if there are more pages available
22
- if (this.pageCountValue > 1) {
21
+ if (this.selectAllEnabled()) {
23
22
  this.selectAllOverlay(checked)
24
23
 
25
24
  // When de-selecting everything, ensure the selectAll toggle is false and hide overlay.
@@ -35,8 +34,7 @@ export default class extends Controller {
35
34
  this.itemCheckboxTargets.forEach((checkbox) => allSelected = allSelected && checkbox.checked)
36
35
  this.checkboxTarget.checked = allSelected
37
36
 
38
- // Only run "all matching" if there are more pages available
39
- if (this.pageCountValue > 1) {
37
+ if (this.selectAllEnabled()) {
40
38
  this.selectAllOverlay(allSelected)
41
39
  this.resetUnselected()
42
40
  }
@@ -63,4 +61,9 @@ export default class extends Controller {
63
61
  this.selectAllOverlayTarget.classList.add('hidden')
64
62
  }
65
63
  }
64
+
65
+ // True if there are more pages available and if query encryption run successfully
66
+ selectAllEnabled() {
67
+ return this.pageCountValue > 1 && this.selectedAllQueryValue !== 'select_all_disabled'
68
+ }
66
69
  }
@@ -18,7 +18,7 @@
18
18
  <%= @action.action_name %>
19
19
  <% end %>
20
20
  <div class="flex-1 flex">
21
- <%= @action.message %>
21
+ <%= @action.get_message %>
22
22
  </div>
23
23
  <%= form.hidden_field :avo_resource_ids, value: params[:resource_ids], 'data-action-target': 'resourceIds' %>
24
24
  <%= form.hidden_field :avo_selected_query, 'data-action-target': 'selectedAllQuery' %>
@@ -72,6 +72,14 @@ module Avo
72
72
  @response[:messages] = []
73
73
  end
74
74
 
75
+ def get_message
76
+ if self.class.message.respond_to? :call
77
+ Avo::Hosts::ResourceRecordHost.new(block: self.class.message, record: self.class.model, resource: self.class.resource).handle
78
+ else
79
+ self.class.message
80
+ end
81
+ end
82
+
75
83
  def get_attributes_for_action
76
84
  get_fields.map do |field|
77
85
  [field.id, field.value || field.default]
@@ -116,7 +124,7 @@ module Avo
116
124
  self
117
125
  end
118
126
 
119
- def visible_in_view(parent_model: nil, parent_resource: nil)
127
+ def visible_in_view(parent_resource: nil)
120
128
  if visible.blank?
121
129
  # Hide on the :new view by default
122
130
  return false if view == :new
@@ -128,9 +136,7 @@ module Avo
128
136
  # Run the visible block if available
129
137
  Avo::Hosts::VisibilityHost.new(
130
138
  block: visible,
131
- model: self.class.model,
132
139
  params: params,
133
- parent_model: parent_model,
134
140
  parent_resource: parent_resource,
135
141
  resource: self.class.resource,
136
142
  view: self.class.view,
data/lib/avo/base_card.rb CHANGED
@@ -20,6 +20,10 @@ module Avo
20
20
  attr_accessor :params
21
21
 
22
22
  delegate :context, to: ::Avo::App
23
+ delegate :current_user, to: ::Avo::App
24
+ delegate :view_context, to: ::Avo::App
25
+ delegate :params, to: ::Avo::App
26
+ delegate :request, to: ::Avo::App
23
27
 
24
28
  class << self
25
29
  def query(&block)
@@ -106,9 +110,8 @@ module Avo
106
110
  self
107
111
  end
108
112
 
109
- def hydrate(dashboard: nil, params: nil)
113
+ def hydrate(dashboard: nil)
110
114
  @dashboard = dashboard if dashboard.present?
111
- @params = params if params.present?
112
115
 
113
116
  self
114
117
  end
@@ -117,9 +117,10 @@ module Avo
117
117
  end
118
118
 
119
119
  def valid_attachment_name(record, association_name)
120
- get_record_associations(record).keys.each do |name|
121
- return association_name if name == "#{association_name}_attachment" || name == "#{association_name}_attachments"
120
+ association_exists = get_record_associations(record).keys.any? do |name|
121
+ name == "#{association_name}_attachment" || name == "#{association_name}_attachments"
122
122
  end
123
+ return association_name if association_exists
123
124
  end
124
125
 
125
126
  def get_available_models
@@ -12,7 +12,14 @@ module Avo
12
12
  value = default
13
13
 
14
14
  if type == :boolean
15
- value = args[name.to_sym] == true
15
+ case args[name.to_sym]
16
+ when nil
17
+ value = default
18
+ when false
19
+ value = false
20
+ when true
21
+ value = true
22
+ end
16
23
  else
17
24
  value = args[name.to_sym] unless args.dig(name.to_sym).nil?
18
25
  end
@@ -10,7 +10,6 @@ module Avo
10
10
  include ActionView::Helpers::UrlHelper
11
11
  include Avo::Fields::FieldExtensions::VisibleInDifferentViews
12
12
 
13
- include Avo::Concerns::HandlesFieldArgs
14
13
  include Avo::Concerns::HasHTMLAttributes
15
14
  include Avo::Fields::Concerns::IsRequired
16
15
  include Avo::Fields::Concerns::IsReadonly
@@ -60,14 +60,13 @@ module Avo
60
60
  self.class.decode_filters params[PARAM_KEY]
61
61
  end
62
62
 
63
- def visible_in_view(resource: nil, parent_model: nil, parent_resource: nil)
63
+ def visible_in_view(resource: nil, parent_resource: nil)
64
64
  return true if visible.blank?
65
65
 
66
66
  # Run the visible block if available
67
67
  Avo::Hosts::VisibilityHost.new(
68
68
  block: visible,
69
69
  params: params,
70
- parent_model: parent_model,
71
70
  parent_resource: parent_resource,
72
71
  resource: resource,
73
72
  arguments: arguments
@@ -0,0 +1,7 @@
1
+ module Avo
2
+ module Hosts
3
+ class ResourceRecordHost < RecordHost
4
+ option :resource
5
+ end
6
+ end
7
+ end
@@ -1,7 +1,6 @@
1
1
  module Avo
2
2
  module Hosts
3
3
  class VisibilityHost < BaseHost
4
- option :parent_model
5
4
  option :parent_resource
6
5
  option :resource
7
6
  option :arguments
@@ -119,7 +119,7 @@ module Avo
119
119
  end
120
120
 
121
121
  def authorize_action(action, **args)
122
- self.class.authorize_action(user, record, action, policy_class: policy_class, **args)
122
+ self.class.authorize_action(user, args[:record] || record, action, policy_class: policy_class, **args)
123
123
  end
124
124
 
125
125
  def apply_policy(model)
@@ -131,7 +131,7 @@ module Avo
131
131
  end
132
132
 
133
133
  def has_method?(method, **args)
134
- defined_methods(record, **args).include? method.to_sym
134
+ defined_methods(args[:record] || record, **args).include? method.to_sym
135
135
  end
136
136
  end
137
137
  end
data/lib/avo/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Avo
2
- VERSION = "2.21.1.pre.issue1450" unless const_defined?(:VERSION)
2
+ VERSION = "2.21.1.pre.pr1476" unless const_defined?(:VERSION)
3
3
  end
@@ -0,0 +1,15 @@
1
+ nn:
2
+ pagy:
3
+ item_name:
4
+ one: "resultat"
5
+ other: "resultat"
6
+ nav:
7
+ prev: "&lsaquo;&nbsp;Førre"
8
+ next: "Neste&nbsp;&rsaquo;"
9
+ gap: "&hellip;"
10
+ info:
11
+ no_items: "Ingen %{item_name} funne"
12
+ single_page: "Viser <b>%{count}</b> %{item_name}"
13
+ multiple_pages: "Viser %{item_name} <b>%{from}-%{to}</b> av totalt <b>%{count}</b>"
14
+ combo_nav_js: "<label>Side %{page_input} av %{pages}</label>"
15
+ items_selector_js: "<label>Vis %{items_input} %{item_name} per side</label>"