avo 1.19.1.pre.7 → 1.19.1.pre.11

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: c2aa4bc482fe6f5a0298a1a664a74ebcecff6df7043c0cf22a820afb8f9b57b4
4
- data.tar.gz: 345cca21367ba38c1a00a664ef2800dc86790dd0dd7970358a7cad1c7e27e17c
3
+ metadata.gz: d5138e11c8508c204270f3b71100905e2046cddba58dc4328459b6f230918b10
4
+ data.tar.gz: 5b63ee835184e1e6b49f4fe6685eb3da91d435a88304917a20c187e88ce8c377
5
5
  SHA512:
6
- metadata.gz: ab9b6ade5c36ed9eb742f8d0731f8c0f3abf4ffcd19e5d5ca82a845a481a1eb1ca9a189ee88b532e8cf27bfe079a417c2aeae55669b762c5cec3e47582bb0943
7
- data.tar.gz: b10299831311156fcee1bc6013a56c788bce6ae33d808c0de06c611fbf871a2d7b641909822509e222eb96439179bc06bcc2cf1b3ad2d05924104c11e6a34aed
6
+ metadata.gz: 8fcb3d6de28e6582d29c80f58d618a4c00676ea9cbd2e9120c6affd3bf3ebe0816ffcb01fdd692584813f928e0977615304cd0768d3c2f88cf72cd54ef4e0101
7
+ data.tar.gz: 8349c52ce5985fdb37c64c7a39a9ecff8b0b7b1985a90904c181655d2a3f01095e2cc66f69e5a0c5e7facc74f9ccc8ecd64d5b1bc010c055f34db5a8bbd014d8
data/Gemfile CHANGED
@@ -80,6 +80,7 @@ group :development do
80
80
  end
81
81
 
82
82
  group :development, :test do
83
+ gem 'ap'
83
84
  gem "faker", require: false
84
85
  end
85
86
 
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- avo (1.19.1.pre.7)
4
+ avo (1.19.1.pre.11)
5
5
  active_link_to
6
6
  addressable
7
7
  breadcrumbs_on_rails
@@ -83,6 +83,8 @@ GEM
83
83
  zeitwerk (~> 2.3)
84
84
  addressable (2.8.0)
85
85
  public_suffix (>= 2.0.2, < 5.0)
86
+ ap (0.1.1)
87
+ httparty (>= 0.7.7)
86
88
  appraisal (2.4.1)
87
89
  bundler
88
90
  rake
@@ -230,7 +232,7 @@ GEM
230
232
  nokogiri (1.13.1-x86_64-linux)
231
233
  racc (~> 1.4)
232
234
  orm_adapter (0.5.0)
233
- pagy (5.10.0)
235
+ pagy (5.10.1)
234
236
  activesupport
235
237
  parallel (1.21.0)
236
238
  parser (3.1.0.0)
@@ -397,6 +399,7 @@ PLATFORMS
397
399
  DEPENDENCIES
398
400
  active_link_to
399
401
  addressable
402
+ ap
400
403
  appraisal
401
404
  avo!
402
405
  aws-sdk-s3
@@ -4,6 +4,7 @@
4
4
  show_path,
5
5
  title: t('avo.view_item', item: singular_resource_name).capitalize,
6
6
  data: {
7
+ target: 'control:view',
7
8
  control: :show,
8
9
  'tippy': 'tooltip',
9
10
  }
@@ -15,6 +16,7 @@
15
16
  edit_path,
16
17
  title: t('avo.edit_item', item: singular_resource_name).capitalize,
17
18
  data: {
19
+ target: 'control:edit',
18
20
  control: :edit,
19
21
  'resource-id': @resource.model.id,
20
22
  'tippy': 'tooltip',
@@ -30,6 +32,7 @@
30
32
  title: t('avo.detach_item', item: singular_resource_name).capitalize,
31
33
  type: :submit,
32
34
  data: {
35
+ target: 'control:detach',
33
36
  confirm: t('avo.are_you_sure_detach_item', item: singular_resource_name),
34
37
  control: :detach,
35
38
  'resource-id': @resource.model.id,
@@ -49,6 +52,7 @@
49
52
  title: t('avo.delete_item', item: singular_resource_name).capitalize,
50
53
  type: :submit,
51
54
  data: {
55
+ target: 'control:destroy',
52
56
  confirm: t('avo.are_you_sure', item: singular_resource_name),
53
57
  control: :destroy,
54
58
  'resource-id': @resource.model.id,
@@ -10,15 +10,19 @@ class Avo::Index::ResourceControlsComponent < Avo::ResourceComponent
10
10
  def can_detach?
11
11
  @reflection.present? &&
12
12
  @resource.model.present? &&
13
- (@reflection.is_a?(::ActiveRecord::Reflection::HasManyReflection) || @reflection.is_a?(::ActiveRecord::Reflection::ThroughReflection)) &&
13
+ is_has_many_association &&
14
14
  authorize_association_for("detach")
15
15
  end
16
16
 
17
17
  def can_edit?
18
+ return authorize_association_for(:edit) if @reflection.present?
19
+
18
20
  @resource.authorization.authorize_action(:edit, raise_exception: false)
19
21
  end
20
22
 
21
23
  def can_view?
24
+ return authorize_association_for(:view) if @reflection.present?
25
+
22
26
  @resource.authorization.authorize_action(:show, raise_exception: false)
23
27
  end
24
28
 
@@ -50,7 +54,7 @@ class Avo::Index::ResourceControlsComponent < Avo::ResourceComponent
50
54
 
51
55
  def singular_resource_name
52
56
  if @reflection.present?
53
- ::Avo::App.get_resource_by_model_name(@reflection.class_name).name
57
+ reflection_resource.name
54
58
  else
55
59
  @resource.singular_name.present? ? @resource.singular_name : @resource.model_class.model_name.name.downcase
56
60
  end
@@ -61,4 +65,8 @@ class Avo::Index::ResourceControlsComponent < Avo::ResourceComponent
61
65
 
62
66
  ::Avo::App.get_resource_by_model_name @parent_model.class
63
67
  end
68
+
69
+ def is_has_many_association
70
+ @reflection.is_a?(::ActiveRecord::Reflection::HasManyReflection) || @reflection.is_a?(::ActiveRecord::Reflection::ThroughReflection)
71
+ end
64
72
  end
@@ -6,9 +6,12 @@
6
6
  <%= helpers.render_breadcrumbs(separator: helpers.svg('chevron-right', class: 'inline-block h-3 stroke-current relative top-[-1px] ml-1' )) if Avo.configuration.display_breadcrumbs %>
7
7
  </div>
8
8
  <% end %>
9
- <div class="text-2xl tracking-normal font-bold text-gray-800 truncate">
9
+ <div class="text-2xl tracking-normal font-bold text-gray-800 truncate" data-target="title">
10
10
  <%= @title %>
11
11
  </div>
12
+ <div class="text-sm tracking-normal text-gray-600" data-target="description">
13
+ <%== description %>
14
+ </div>
12
15
  </div>
13
16
 
14
17
  <div>
@@ -6,8 +6,9 @@ class Avo::PanelComponent < ViewComponent::Base
6
6
  renders_one :bare_content
7
7
  renders_one :footer
8
8
 
9
- def initialize(title: nil, body_classes: nil, data: {}, display_breadcrumbs: false, index: nil)
9
+ def initialize(title: nil, description: nil, body_classes: nil, data: {}, display_breadcrumbs: false, index: nil)
10
10
  @title = title
11
+ @description = description
11
12
  @body_classes = body_classes
12
13
  @data = data
13
14
  @display_breadcrumbs = display_breadcrumbs
@@ -25,4 +26,10 @@ class Avo::PanelComponent < ViewComponent::Base
25
26
  def display_breadcrumbs?
26
27
  @display_breadcrumbs
27
28
  end
29
+
30
+ def description
31
+ return @description if @description.present?
32
+
33
+ '&nbsp;'
34
+ end
28
35
  end
@@ -1,20 +1,27 @@
1
1
  class Avo::ResourceComponent < ViewComponent::Base
2
2
  def can_create?
3
+ return authorize_association_for(:create) if @reflection.present?
4
+
3
5
  @resource.authorization.authorize_action(:create, raise_exception: false)
4
6
  end
5
7
 
6
8
  def can_delete?
9
+ return authorize_association_for(:destroy) if @reflection.present?
10
+
7
11
  @resource.authorization.authorize_action(:destroy, raise_exception: false)
8
12
  end
9
13
 
10
14
  def authorize_association_for(policy_method)
11
15
  association_policy = true
16
+
12
17
  if @reflection.present?
13
18
  reflection_resource = ::Avo::App.get_resource_by_model_name(@reflection.active_record.name)
14
- if reflection_resource.present?
15
- method_name = "#{policy_method}_#{@reflection.name.to_s.underscore}?".to_sym
16
- defined_policy_methods = reflection_resource.authorization.defined_methods(reflection_resource.model_class, raise_exception: false)
17
- if defined_policy_methods.present? && defined_policy_methods.include?(method_name)
19
+ association_name = params['related_name']
20
+
21
+ if association_name.present?
22
+ method_name = "#{policy_method}_#{association_name}?".to_sym
23
+
24
+ if reflection_resource.authorization.has_method?(method_name, raise_exception: false)
18
25
  association_policy = reflection_resource.authorization.authorize_action(method_name, raise_exception: false)
19
26
  end
20
27
  end
@@ -25,7 +32,22 @@ class Avo::ResourceComponent < ViewComponent::Base
25
32
 
26
33
  private
27
34
 
35
+ # Figure out what is the corresponding field for this @reflection
36
+ def field
37
+ fields = ::Avo::App.get_resource_by_model_name(@reflection.active_record.name).get_field_definitions
38
+ fields.find { |f| f.id == @reflection.name }
39
+ rescue
40
+ nil
41
+ end
42
+
28
43
  def relation_resource
29
44
  ::Avo::App.get_resource_by_model_name params[:via_resource_class].safe_constantize
30
45
  end
46
+
47
+ # Get the resource for the resource using the klass attribute so we get the namespace too
48
+ def reflection_resource
49
+ ::Avo::App.get_resource_by_model_name(@reflection.klass.to_s)
50
+ rescue
51
+ nil
52
+ end
31
53
  end
@@ -1,9 +1,13 @@
1
1
  <div data-model-id="<%= @resource.model.id %>">
2
2
  <% @resource.panels.each do |resource_panel| %>
3
- <%= form_with model: @resource.model, scope: @resource.form_scope, url: helpers.resource_path(model: @resource.model, resource: @resource), method: :put, multipart: true do |form| %>
3
+ <%= form_with model: @resource.model,
4
+ scope: @resource.form_scope,
5
+ url: helpers.resource_path(model: @resource.model, resource: @resource),
6
+ method: :put,
7
+ multipart: true do |form| %>
4
8
  <%= hidden_field_tag :referrer, back_path if params[:via_resource_class] %>
5
9
 
6
- <%= render Avo::PanelComponent.new(title: resource_panel[:name], display_breadcrumbs: true) do |c| %>
10
+ <%= render Avo::PanelComponent.new(title: resource_panel[:name], description: @resource.resource_description, display_breadcrumbs: true) do |c| %>
7
11
  <% c.tools do %>
8
12
  <div class="flex justify-end space-x-2">
9
13
  <%= a_link back_path do %>
@@ -1,16 +1,18 @@
1
1
  <div>
2
- <%= render Avo::PanelComponent.new(title: title, body_classes: 'py-4', data: { component: 'resources-index' }, display_breadcrumbs: @reflection.blank?) do |c| %>
2
+ <%= render Avo::PanelComponent.new(title: title, description: description, body_classes: 'py-4', data: { component: 'resources-index' }, display_breadcrumbs: @reflection.blank?) do |c| %>
3
3
  <% c.tools do %>
4
- <%= render 'actions' if @actions.present? %>
4
+ <% if can_see_the_actions_button? %>
5
+ <%= render 'actions' %>
6
+ <% end %>
5
7
 
6
8
  <% if can_see_the_create_button? %>
7
- <%= a_link create_path do %>
9
+ <%= a_link create_path, 'data-target': 'create' do %>
8
10
  <%= svg 'plus' %> <%= t('avo.create_new_item', item: singular_resource_name.downcase ) %>
9
11
  <% end %>
10
12
  <% end %>
11
13
 
12
14
  <% if can_attach? %>
13
- <%= a_link attach_path, color: 'indigo', 'data-turbo-frame': 'attach_modal' do %>
15
+ <%= a_link attach_path, color: 'indigo', 'data-turbo-frame': 'attach_modal', 'data-target': 'attach' do %>
14
16
  <%= svg 'view-grid-add' %> <%= t('avo.attach_item', item: singular_resource_name).capitalize %>
15
17
  <% end %>
16
18
  <% end %>
@@ -30,7 +30,9 @@ class Avo::Views::ResourceIndexComponent < Avo::ResourceComponent
30
30
 
31
31
  def title
32
32
  if @reflection.present?
33
- ::Avo::App.get_resource_by_model_name(@reflection.class_name).plural_name
33
+ return field.plural_name if field.present?
34
+
35
+ reflection_resource.plural_name
34
36
  else
35
37
  @resource.plural_name
36
38
  end
@@ -47,9 +49,19 @@ class Avo::Views::ResourceIndexComponent < Avo::ResourceComponent
47
49
  # The Create button is dependent on the new? policy method.
48
50
  # The create? should be called only when the user clicks the Save button so the developers gets access to the params from the form.
49
51
  def can_see_the_create_button?
52
+ return authorize_association_for("create") if @reflection.present?
53
+
50
54
  @resource.authorization.authorize_action(:new, raise_exception: false) && !has_reflection_and_is_read_only
51
55
  end
52
56
 
57
+ def can_see_the_actions_button?
58
+ return false if @actions.blank?
59
+
60
+ return authorize_association_for("act_on") if @reflection.present?
61
+
62
+ @resource.authorization.authorize_action(:act_on, raise_exception: false) && !has_reflection_and_is_read_only
63
+ end
64
+
53
65
  def can_attach?
54
66
  klass = @reflection
55
67
  klass = @reflection.through_reflection if klass.is_a? ::ActiveRecord::Reflection::ThroughReflection
@@ -107,12 +119,18 @@ class Avo::Views::ResourceIndexComponent < Avo::ResourceComponent
107
119
 
108
120
  def singular_resource_name
109
121
  if @reflection.present?
110
- ::Avo::App.get_resource_by_model_name(@reflection.class_name).name
122
+ reflection_resource.name
111
123
  else
112
124
  @resource.singular_name || @resource.model_class.model_name.name.downcase
113
125
  end
114
126
  end
115
127
 
128
+ def description
129
+ return if @reflection.present?
130
+
131
+ @resource.resource_description
132
+ end
133
+
116
134
  private
117
135
 
118
136
  def reflection_model_class
@@ -1,7 +1,14 @@
1
1
  <div>
2
2
  <% @resource.panels.each do |resource_panel| %>
3
- <%= form_with model: @resource.model, url: helpers.resources_path(resource: @resource, via_relation_class: params[:via_relation_class], via_relation: params[:via_relation], via_resource_id: params[:via_resource_id]), local: true, multipart: true do |form| %>
4
- <%= render Avo::PanelComponent.new(title: resource_panel[:name], display_breadcrumbs: true) do |c| %>
3
+ <%= form_with model: @resource.model,
4
+ scope: @resource.form_scope,
5
+ url: helpers.resources_path(resource: @resource,
6
+ via_relation_class: params[:via_relation_class],
7
+ via_relation: params[:via_relation],
8
+ via_resource_id: params[:via_resource_id]),
9
+ local: true,
10
+ multipart: true do |form| %>
11
+ <%= render Avo::PanelComponent.new(title: resource_panel[:name], description: @resource.resource_description, display_breadcrumbs: true) do |c| %>
5
12
  <% c.tools do %>
6
13
  <div class="flex justify-end space-x-2">
7
14
  <%= a_link back_path do %>
@@ -3,7 +3,7 @@
3
3
  data-selected-resources='["<%= @resource.model.id %>"]'
4
4
  >
5
5
  <% @resource.panels.each_with_index do |resource_panel, index| %>
6
- <%= render Avo::PanelComponent.new(title: resource_panel[:name], display_breadcrumbs: @reflection.blank?, index: index) do |c| %>
6
+ <%= render Avo::PanelComponent.new(title: title, description: @resource.resource_description, display_breadcrumbs: @reflection.blank?, index: index) do |c| %>
7
7
  <% c.tools do %>
8
8
  <% if resource_panel[:name] == @resource.default_panel_name %>
9
9
  <%= render 'actions' %>
@@ -6,13 +6,24 @@ class Avo::Views::ResourceShowComponent < Avo::ResourceComponent
6
6
 
7
7
  attr_reader :fields_by_panel, :has_one_panels, :has_many_panels, :has_as_belongs_to_many_panels
8
8
 
9
- def initialize(resource: nil, reflection: nil, parent_model: nil)
9
+ def initialize(resource: nil, reflection: nil, parent_model: nil, resource_panel: nil)
10
10
  @resource = resource
11
11
  @reflection = reflection
12
+ @resource_panel = resource_panel
12
13
 
13
14
  split_panel_fields
14
15
  end
15
16
 
17
+ def title
18
+ if @reflection.present?
19
+ return field.name if field.present?
20
+
21
+ reflection_resource.name
22
+ else
23
+ @resource.panels.first[:name]
24
+ end
25
+ end
26
+
16
27
  def back_path
17
28
  if via_resource?
18
29
  helpers.resource_path(model: params[:via_resource_class].safe_constantize, resource: relation_resource, resource_id: params[:via_resource_id])
@@ -194,7 +194,7 @@ module Avo
194
194
  private
195
195
 
196
196
  def model_params
197
- model_param_key = @resource.singular_model_key
197
+ model_param_key = @resource.form_scope
198
198
 
199
199
  request_params = params.require(model_param_key).permit(permitted_params)
200
200
 
@@ -18,6 +18,11 @@ module Avo
18
18
  @parent_model = @parent_resource.class.find_scope.find(params[:id])
19
19
  @parent_resource.hydrate(model: @parent_model)
20
20
  @query = @authorization.apply_policy @parent_model.public_send(params[:related_name])
21
+ @association_field = @parent_resource.get_field params[:related_name]
22
+
23
+ if @association_field.present? && @association_field.scope.present?
24
+ @query = @query.instance_exec(&@association_field.scope)
25
+ end
21
26
 
22
27
  super
23
28
  end
data/config/routes.rb CHANGED
@@ -23,7 +23,7 @@ Avo::Engine.routes.draw do
23
23
 
24
24
  # Generate resource routes as below:
25
25
  # resources :posts
26
- instance_eval(&Avo::App.draw_routes)
26
+ Avo::DynamicRouter::routes(self)
27
27
 
28
28
  # Relations
29
29
  get "/:resource_name/:id/:related_name/new", to: "relations#new", as: "associations_new"
data/db/factories.rb CHANGED
@@ -53,4 +53,12 @@ FactoryBot.define do
53
53
  name { "#{Faker::Name.first_name} #{Faker::Name.last_name}" }
54
54
  type { "Spouse" }
55
55
  end
56
+
57
+ factory :course do
58
+ name { Faker::Company.name }
59
+ end
60
+
61
+ factory :link do
62
+ name { Faker::Internet.url }
63
+ end
56
64
  end
data/lib/avo/app.rb CHANGED
@@ -155,24 +155,6 @@ module Avo
155
155
  filename
156
156
  end
157
157
  end
158
-
159
- def draw_routes
160
- # We should eager load all the classes so we find all descendants
161
- Rails.application.eager_load!
162
-
163
- proc do
164
- BaseResource.descendants
165
- .select do |resource|
166
- resource != :BaseResource
167
- end
168
- .select do |resource|
169
- resource.is_a? Class
170
- end
171
- .map do |resource|
172
- resources resource.new.model_key
173
- end
174
- end
175
- end
176
158
  end
177
159
  end
178
160
  end
@@ -19,6 +19,7 @@ module Avo
19
19
 
20
20
  class_attribute :id, default: :id
21
21
  class_attribute :title, default: :id
22
+ class_attribute :description, default: :id
22
23
  class_attribute :search_query, default: nil
23
24
  class_attribute :search_query_help, default: ''
24
25
  class_attribute :includes, default: []
@@ -154,6 +155,12 @@ module Avo
154
155
  fields
155
156
  end
156
157
 
158
+ def get_field(id)
159
+ get_field_definitions.find do |f|
160
+ f.id == id.to_sym
161
+ end
162
+ end
163
+
157
164
  def get_grid_fields
158
165
  return if self.class.grid_loader.blank?
159
166
 
@@ -224,6 +231,16 @@ module Avo
224
231
  name
225
232
  end
226
233
 
234
+ def resource_description
235
+ return instance_exec(&self.class.description) if self.class.description.respond_to? :call
236
+
237
+ # Show the description only on the resource index view.
238
+ # If the user wants to conditionally it on all pages, they should use a block.
239
+ if view == :index
240
+ return self.class.description if self.class.description.is_a? String
241
+ end
242
+ end
243
+
227
244
  def translation_key
228
245
  return "avo.resource_translations.#{class_name_without_resource.underscore}" if self.class.translation_enabled
229
246
 
@@ -442,7 +459,7 @@ module Avo
442
459
  end
443
460
 
444
461
  def form_scope
445
- model.class.base_class.to_s.underscore.downcase
462
+ model_class.base_class.to_s.underscore.downcase
446
463
  end
447
464
  end
448
465
  end
@@ -0,0 +1,18 @@
1
+ module Avo
2
+ module DynamicRouter
3
+ def self.routes(router)
4
+ Rails.application.eager_load!
5
+
6
+ BaseResource.descendants
7
+ .select do |resource|
8
+ resource != :BaseResource
9
+ end
10
+ .select do |resource|
11
+ resource.is_a? Class
12
+ end
13
+ .map do |resource|
14
+ router.resources resource.new.model_key
15
+ end
16
+ end
17
+ end
18
+ end
@@ -102,6 +102,12 @@ module Avo
102
102
  @id.to_s.humanize(keep_id_suffix: true)
103
103
  end
104
104
 
105
+ def plural_name
106
+ return I18n.t(translation_key, count: 2).capitalize if translation_key
107
+
108
+ name.pluralize
109
+ end
110
+
105
111
  def placeholder
106
112
  return @placeholder if @placeholder.present?
107
113
 
@@ -2,11 +2,13 @@ module Avo
2
2
  module Fields
3
3
  class HasBaseField < BaseField
4
4
  attr_accessor :display
5
+ attr_accessor :scope
5
6
 
6
7
  def initialize(id, **args, &block)
7
8
  super(id, **args, &block)
8
9
 
9
10
  @display = args[:display].present? ? args[:display] : :show
11
+ @scope = args[:scope].present? ? args[:scope] : nil
10
12
  end
11
13
 
12
14
  def resource
@@ -3,10 +3,6 @@ require "json"
3
3
  module Avo
4
4
  module Fields
5
5
  class KeyValueField < BaseField
6
- attr_reader :key_label
7
- attr_reader :value_label
8
- attr_reader :action_text
9
- attr_reader :delete_text
10
6
  attr_reader :disable_editing_keys
11
7
  attr_reader :disable_adding_rows
12
8
 
@@ -15,10 +11,10 @@ module Avo
15
11
 
16
12
  hide_on :index
17
13
 
18
- @key_label = args[:key_label].present? ? args[:key_label].to_s : I18n.translate('avo.key_value_field.key')
19
- @value_label = args[:value_label].present? ? args[:value_label].to_s : I18n.translate('avo.key_value_field.value')
20
- @action_text = args[:action_text].present? ? args[:action_text].to_s : I18n.translate('avo.key_value_field.add_row')
21
- @delete_text = args[:delete_text].present? ? args[:delete_text].to_s : I18n.translate('avo.key_value_field.delete_row')
14
+ @key_label = args[:key_label].to_s if args[:key_label].present?
15
+ @value_label = args[:value_label].to_s if args[:value_label].present?
16
+ @action_text = args[:action_text].to_s if args[:action_text].present?
17
+ @delete_text = args[:delete_text].to_s if args[:delete_text].present?
22
18
 
23
19
  @disable_editing_keys = args[:disable_editing_keys].present? ? args[:disable_editing_keys] : false
24
20
  # disabling editing keys also disables adding rows (doesn't take into account the value of disable_adding_rows)
@@ -32,6 +28,30 @@ module Avo
32
28
  @disable_deleting_rows = args[:disable_deleting_rows].present? ? args[:disable_deleting_rows] : false
33
29
  end
34
30
 
31
+ def key_label
32
+ return @key_label if @key_label && !@key_label.empty?
33
+
34
+ I18n.translate('avo.key_value_field.key')
35
+ end
36
+
37
+ def value_label
38
+ return @value_label if @value_label && !@value_label.empty?
39
+
40
+ I18n.translate('avo.key_value_field.value')
41
+ end
42
+
43
+ def action_text
44
+ return @action_text if @action_text && !@action_text.empty?
45
+
46
+ I18n.translate('avo.key_value_field.add_row')
47
+ end
48
+
49
+ def delete_text
50
+ return @delete_text if @delete_text && !@delete_text.empty?
51
+
52
+ I18n.translate('avo.key_value_field.delete_row')
53
+ end
54
+
35
55
  def to_permitted_param
36
56
  [:"#{id}", "#{id}": {}]
37
57
  end
@@ -37,6 +37,10 @@ module Avo
37
37
  self.class.defined_methods(user, model, **args)
38
38
  end
39
39
 
40
+ def has_method?(method, **args)
41
+ self.class.defined_methods(user, record, **args).include? method.to_sym
42
+ end
43
+
40
44
  class << self
41
45
  def authorize(user, record, action, **args)
42
46
  return true if skip_authorization
@@ -64,6 +68,9 @@ module Avo
64
68
  def authorize_action(user, record, action, **args)
65
69
  action = Avo.configuration.authorization_methods.stringify_keys[action.to_s] || action
66
70
 
71
+ # Add the question mark if it's missing
72
+ action = "#{action}?" unless action.end_with? '?'
73
+
67
74
  return true if action.nil?
68
75
 
69
76
  authorize user, record, action, **args
@@ -101,7 +108,7 @@ module Avo
101
108
  Pundit.policy!(user, record).methods
102
109
  rescue => error
103
110
  if args[:raise_exception] == false
104
- false
111
+ []
105
112
  else
106
113
  raise error
107
114
  end
data/lib/avo/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Avo
2
- VERSION = "1.19.1.pre.7"
2
+ VERSION = "1.19.1.pre.11"
3
3
  end
Binary file
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: 1.19.1.pre.7
4
+ version: 1.19.1.pre.11
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adrian Marin
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2022-02-03 00:00:00.000000000 Z
12
+ date: 2022-02-07 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
@@ -583,6 +583,7 @@ files:
583
583
  - lib/avo/base_action.rb
584
584
  - lib/avo/base_resource.rb
585
585
  - lib/avo/configuration.rb
586
+ - lib/avo/dynamic_router.rb
586
587
  - lib/avo/engine.rb
587
588
  - lib/avo/fields/badge_field.rb
588
589
  - lib/avo/fields/base_field.rb
@@ -688,6 +689,7 @@ files:
688
689
  - public/avo-assets/fonts/nunito-v16-latin-regular.ttf
689
690
  - public/avo-assets/fonts/nunito-v16-latin-regular.woff
690
691
  - public/avo-assets/fonts/nunito-v16-latin-regular.woff2
692
+ - public/avo-assets/logo.png
691
693
  homepage: https://avohq.io
692
694
  licenses:
693
695
  - Commercial