avo 2.12.0 → 2.13.1

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.

Potentially problematic release.


This version of avo might be problematic. Click here for more details.

Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +2 -2
  3. data/README.md +2 -1
  4. data/app/components/avo/actions_component.html.erb +3 -3
  5. data/app/components/avo/actions_component.rb +12 -3
  6. data/app/components/avo/button_component.rb +1 -3
  7. data/app/components/avo/fields/common/gravatar_viewer_component.html.erb +1 -1
  8. data/app/components/avo/fields/date_field/edit_component.html.erb +0 -3
  9. data/app/components/avo/fields/date_time_field/edit_component.html.erb +0 -2
  10. data/app/components/avo/fields/has_one_field/show_component.html.erb +1 -1
  11. data/app/components/avo/fields/tags_field/show_component.rb +0 -2
  12. data/app/components/avo/item_switcher_component.html.erb +1 -1
  13. data/app/components/avo/panel_component.html.erb +1 -1
  14. data/app/components/avo/panel_component.rb +3 -4
  15. data/app/components/avo/resource_component.rb +6 -4
  16. data/app/components/avo/sidebar_component.html.erb +1 -1
  17. data/app/components/avo/tab_group_component.html.erb +1 -1
  18. data/app/components/avo/tab_switcher_component.rb +2 -2
  19. data/app/components/avo/views/resource_edit_component.html.erb +1 -1
  20. data/app/components/avo/views/resource_edit_component.rb +1 -1
  21. data/app/components/avo/views/resource_index_component.html.erb +3 -3
  22. data/app/components/avo/views/resource_index_component.rb +18 -1
  23. data/app/components/avo/views/resource_show_component.html.erb +139 -48
  24. data/app/components/avo/views/resource_show_component.rb +1 -0
  25. data/app/controllers/avo/base_controller.rb +87 -33
  26. data/app/controllers/avo/search_controller.rb +57 -20
  27. data/app/javascript/js/controllers/menu_controller.js +2 -2
  28. data/app/javascript/js/controllers/search_controller.js +42 -15
  29. data/app/views/avo/associations/new.html.erb +1 -0
  30. data/app/views/avo/dashboards/show.html.erb +1 -1
  31. data/app/views/avo/debug/index.html.erb +1 -1
  32. data/app/views/avo/debug/report.html.erb +1 -0
  33. data/app/views/avo/home/index.html.erb +1 -1
  34. data/app/views/avo/partials/_resource_search.html.erb +6 -0
  35. data/app/views/avo/private/design.html.erb +2 -2
  36. data/app/views/layouts/avo/application.html.erb +1 -1
  37. data/lib/avo/base_resource.rb +5 -1
  38. data/lib/avo/concerns/has_editable_controls.rb +34 -0
  39. data/lib/avo/concerns/has_fields.rb +11 -10
  40. data/lib/avo/fields/base_field.rb +1 -1
  41. data/lib/avo/fields/date_field.rb +1 -3
  42. data/lib/avo/fields/field_extensions/has_include_blank.rb +1 -1
  43. data/lib/avo/fields/has_base_field.rb +2 -0
  44. data/lib/avo/fields/key_value_field.rb +6 -6
  45. data/lib/avo/hosts/base_host.rb +2 -1
  46. data/lib/avo/hosts/search_scope_host.rb +7 -0
  47. data/lib/avo/licensing/h_q.rb +12 -4
  48. data/lib/avo/licensing/pro_license.rb +1 -0
  49. data/lib/avo/menu/builder.rb +2 -0
  50. data/lib/avo/resources/controls/action.rb +32 -0
  51. data/lib/avo/resources/controls/actions_list.rb +19 -0
  52. data/lib/avo/resources/controls/back_button.rb +13 -0
  53. data/lib/avo/resources/controls/base_control.rb +59 -0
  54. data/lib/avo/resources/controls/delete_button.rb +13 -0
  55. data/lib/avo/resources/controls/detach_button.rb +13 -0
  56. data/lib/avo/resources/controls/edit_button.rb +13 -0
  57. data/lib/avo/resources/controls/execution_context.rb +58 -0
  58. data/lib/avo/resources/controls/items_holder.rb +19 -0
  59. data/lib/avo/resources/controls/link_to.rb +27 -0
  60. data/lib/avo/version.rb +1 -1
  61. data/lib/generators/avo/templates/action.tt +1 -1
  62. data/lib/generators/avo/templates/initializer/avo.tt +1 -0
  63. data/lib/generators/avo/templates/resource/resource.tt +1 -1
  64. data/lib/generators/avo/templates/resource_tools/partial.tt +1 -1
  65. data/lib/generators/avo/templates/standalone_action.tt +1 -1
  66. data/public/avo-assets/avo.css +564 -44
  67. data/public/avo-assets/avo.js +47 -47
  68. data/public/avo-assets/avo.js.map +2 -2
  69. metadata +14 -3
  70. data/lib/avo/concerns/has_model.rb +0 -11
@@ -115,7 +115,7 @@ module Avo
115
115
  add_breadcrumb via_resource.model_title, resource_path(model: via_model, resource: via_resource)
116
116
  end
117
117
 
118
- add_breadcrumb @resource.plural_name.humanize
118
+ add_breadcrumb @resource.plural_name.humanize, resources_path(resource: @resource)
119
119
  add_breadcrumb t("avo.new").humanize
120
120
  end
121
121
 
@@ -129,21 +129,14 @@ module Avo
129
129
  @reflection = @model._reflections[params[:via_relation]]
130
130
  # Figure out what kind of association does the record have with the parent record
131
131
 
132
- # belongs_to
133
- # has_many
132
+ # Fills in the required infor for belongs_to and has_many
134
133
  # Get the foreign key and set it to the id we received in the params
135
134
  if @reflection.is_a?(ActiveRecord::Reflection::BelongsToReflection) || @reflection.is_a?(ActiveRecord::Reflection::HasManyReflection)
136
- foreign_key = @reflection.foreign_key
137
- @model.send("#{foreign_key}=", params[:via_resource_id])
135
+ @model.send("#{@reflection.foreign_key}=", params[:via_resource_id])
138
136
  @model.save
139
137
  end
140
138
 
141
- # has_one
142
- # has_one_through
143
-
144
- # has_many_through
145
- # has_and_belongs_to_many
146
- # polymorphic
139
+ # For when working with has_one, has_one_through, has_many_through, has_and_belongs_to_many, polymorphic
147
140
  if @reflection.is_a? ActiveRecord::Reflection::ThroughReflection
148
141
  # find the record
149
142
  via_resource = ::Avo::App.get_resource_by_model_name params[:via_relation_class]
@@ -153,13 +146,14 @@ module Avo
153
146
  end
154
147
  end
155
148
 
156
- respond_to do |format|
157
- if saved
158
- format.html { redirect_to after_create_path, notice: "#{@resource.name} #{t("avo.was_successfully_created")}." }
159
- else
160
- flash.now[:error] = t "avo.you_missed_something_check_form"
161
- format.html { render :new, status: :unprocessable_entity }
162
- end
149
+ add_breadcrumb @resource.plural_name.humanize, resources_path(resource: @resource)
150
+ add_breadcrumb t("avo.new").humanize
151
+ set_actions
152
+
153
+ if saved
154
+ create_success_action
155
+ else
156
+ create_fail_action
163
157
  end
164
158
  end
165
159
 
@@ -171,26 +165,20 @@ module Avo
171
165
  # model gets instantiated and filled in the fill_model method
172
166
  saved = save_model
173
167
  @resource = @resource.hydrate(model: @model, view: :edit, user: _current_user)
168
+ set_actions
174
169
 
175
- respond_to do |format|
176
- if saved
177
- format.html { redirect_to after_update_path, notice: "#{@resource.name} #{t("avo.was_successfully_updated")}." }
178
- else
179
- flash.now[:error] = t "avo.you_missed_something_check_form"
180
- format.html { render :edit, status: :unprocessable_entity }
181
- end
170
+ if saved
171
+ update_success_action
172
+ else
173
+ update_fail_action
182
174
  end
183
175
  end
184
176
 
185
177
  def destroy
186
- respond_to do |format|
187
- if destroy_model
188
- format.html { redirect_to params[:referrer] || resources_path(resource: @resource, turbo_frame: params[:turbo_frame], view_type: params[:view_type]), notice: t("avo.resource_destroyed", attachment_class: @attachment_class) }
189
- else
190
- error_message = @errors.present? ? @errors.first : t("avo.failed")
191
-
192
- format.html { redirect_back fallback_location: params[:referrer] || resources_path(resource: @resource, turbo_frame: params[:turbo_frame], view_type: params[:view_type]), error: error_message }
193
- end
178
+ if destroy_model
179
+ destroy_success_action
180
+ else
181
+ destroy_fail_action
194
182
  end
195
183
  end
196
184
 
@@ -401,6 +389,27 @@ module Avo
401
389
  add_breadcrumb t("avo.edit").humanize
402
390
  end
403
391
 
392
+ def create_success_action
393
+ respond_to do |format|
394
+ format.html { redirect_to after_create_path, notice: create_success_message}
395
+ end
396
+ end
397
+
398
+ def create_fail_action
399
+ respond_to do |format|
400
+ flash.now[:error] = create_fail_message
401
+ format.html { render :new, status: :unprocessable_entity }
402
+ end
403
+ end
404
+
405
+ def create_success_message
406
+ "#{@resource.name} #{t("avo.was_successfully_created")}."
407
+ end
408
+
409
+ def create_fail_message
410
+ t "avo.you_missed_something_check_form"
411
+ end
412
+
404
413
  def after_create_path
405
414
  # If this is an associated record return to the association show page
406
415
  if params[:via_relation_class].present? && params[:via_resource_id].present?
@@ -412,12 +421,57 @@ module Avo
412
421
  redirect_path_from_resource_option(:after_create_path) || resource_path(model: @model, resource: @resource)
413
422
  end
414
423
 
424
+ def update_success_action
425
+ respond_to do |format|
426
+ format.html { redirect_to after_update_path, notice: update_success_message }
427
+ end
428
+ end
429
+
430
+ def update_fail_action
431
+ respond_to do |format|
432
+ flash.now[:error] = update_fail_message
433
+ format.html { render :edit, status: :unprocessable_entity }
434
+ end
435
+ end
436
+
437
+ def update_success_message
438
+ "#{@resource.name} #{t("avo.was_successfully_updated")}."
439
+ end
440
+
441
+ def update_fail_message
442
+ t "avo.you_missed_something_check_form"
443
+ end
444
+
415
445
  def after_update_path
416
446
  return params[:referrer] if params[:referrer].present?
417
447
 
418
448
  redirect_path_from_resource_option(:after_update_path) || resource_path(model: @model, resource: @resource)
419
449
  end
420
450
 
451
+ def destroy_success_action
452
+ respond_to do |format|
453
+ format.html { redirect_to after_destroy_path, notice: destroy_success_message }
454
+ end
455
+ end
456
+
457
+ def destroy_fail_action
458
+ respond_to do |format|
459
+ format.html { redirect_back fallback_location: params[:referrer] || resources_path(resource: @resource, turbo_frame: params[:turbo_frame], view_type: params[:view_type]), error: destroy_fail_message }
460
+ end
461
+ end
462
+
463
+ def destroy_success_message
464
+ t("avo.resource_destroyed", attachment_class: @attachment_class)
465
+ end
466
+
467
+ def destroy_fail_message
468
+ @errors.present? ? @errors.first : t("avo.failed")
469
+ end
470
+
471
+ def after_destroy_path
472
+ params[:referrer] || resources_path(resource: @resource, turbo_frame: params[:turbo_frame], view_type: params[:view_type])
473
+ end
474
+
421
475
  def redirect_path_from_resource_option(action = :after_update_path)
422
476
  return nil if @resource.class.send(action).blank?
423
477
 
@@ -44,10 +44,13 @@ module Avo
44
44
  end
45
45
 
46
46
  def search_resource(resource)
47
- query = resource.search_query.call(params: params).limit(8)
47
+ query = Avo::Hosts::SearchScopeHost.new(
48
+ block: resource.search_query,
49
+ params: params,
50
+ scope: resource.class.scope.limit(8)
51
+ ).handle
48
52
 
49
- # Figure out if this is a belongs_to search
50
- query = apply_attach_scope query
53
+ query = apply_scope(query) if should_apply_any_scope?
51
54
 
52
55
  results = apply_search_metadata(query, resource)
53
56
 
@@ -67,22 +70,19 @@ module Avo
67
70
  [resource.name.pluralize.downcase, result_object]
68
71
  end
69
72
 
70
- # Figure out if it's a belongs to search and if it has the attach_scope block present.
71
- # If so, set the parent for those edit view and the parent with the grandparent for the new view.
72
- def apply_attach_scope(query)
73
- return query if params[:via_reflection_class].blank?
74
-
75
- # Fetch the field
76
- field = belongs_to_field
77
-
78
- # No need to modify the query if there's no attach_scope present.
79
- return query if field.attach_scope.blank?
80
-
81
- # Try to fetch the parent.
82
- if params[:via_reflection_id].present?
83
- parent = params[:via_reflection_class].safe_constantize.find params[:via_reflection_id]
73
+ # When searching in a `has_many` association and will scope out the records against the parent record.
74
+ # This is also used when looking for `belongs_to` associations, and this method applies the parents `attach_scope` if present.
75
+ def apply_scope(query)
76
+ if should_apply_has_many_scope?
77
+ apply_has_many_scope
78
+ elsif should_apply_attach_scope?
79
+ apply_attach_scope(query, parent)
84
80
  end
81
+ end
85
82
 
83
+ # Parent passed as argument to be used as a variable instead of the method "def parent"
84
+ # Otherwise parent = params...safe_constantize... will try to call method "def parent="
85
+ def apply_attach_scope(query, parent)
86
86
  # If the parent is nil it probably means that someone's creating the record so it's not attached yet.
87
87
  # In these scenarios, try to find the grandparent for the new views where the parent is nil
88
88
  # and initialize the parent record with the grandparent attached so the user has the required information
@@ -94,8 +94,13 @@ module Avo
94
94
  )
95
95
  end
96
96
 
97
- # Add to the query
98
- Avo::Hosts::AssociationScopeHost.new(block: belongs_to_field.attach_scope, query: query, parent: parent).handle
97
+ Avo::Hosts::AssociationScopeHost.new(block: attach_scope, query: query, parent: parent).handle
98
+ end
99
+
100
+ def apply_has_many_scope
101
+ scope = parent.send(params[:via_association_id])
102
+
103
+ Avo::Hosts::SearchScopeHost.new(block: @resource.search_query, params: params, scope: scope).handle
99
104
  end
100
105
 
101
106
  def apply_search_metadata(models, avo_resource)
@@ -118,9 +123,41 @@ module Avo
118
123
  end
119
124
  end
120
125
 
121
- def belongs_to_field
126
+ private
127
+
128
+ def should_apply_has_many_scope?
129
+ params[:via_association] == "has_many" && @resource.search_query.present?
130
+ end
131
+
132
+ def should_apply_attach_scope?
133
+ params[:via_association] == "belongs_to" && attach_scope.present?
134
+ end
135
+
136
+ def should_apply_any_scope?
137
+ should_apply_has_many_scope? || should_apply_attach_scope?
138
+ end
139
+
140
+ def attach_scope
141
+ @attach_scope ||= field&.attach_scope
142
+ end
143
+
144
+ def field
145
+ @field ||= fetch_field
146
+ end
147
+
148
+ def parent
149
+ @parent ||= fetch_parent
150
+ end
151
+
152
+ def fetch_field
122
153
  fields = ::Avo::App.get_resource_by_model_name(params[:via_reflection_class]).get_field_definitions
123
154
  fields.find { |f| f.id.to_s == params[:via_association_id] }
124
155
  end
156
+
157
+ def fetch_parent
158
+ return unless params[:via_reflection_id].present?
159
+
160
+ params[:via_reflection_class].safe_constantize.find params[:via_reflection_id]
161
+ end
125
162
  end
126
163
  end
@@ -22,8 +22,8 @@ export default class extends Controller {
22
22
  }
23
23
 
24
24
  get initiallyCollapsed() {
25
- if (this.defaultState === 'collapsed') {
26
- return this.userState === 'collapsed'
25
+ if (!this.userState) {
26
+ return this.defaultState === 'collapsed'
27
27
  }
28
28
 
29
29
  return this.userState === 'collapsed'
@@ -48,6 +48,10 @@ export default class extends Controller {
48
48
  return this.dataset.viaAssociation === 'belongs_to'
49
49
  }
50
50
 
51
+ get isHasManySearch() {
52
+ return this.dataset.viaAssociation === 'has_many'
53
+ }
54
+
51
55
  get isGlobalSearch() {
52
56
  return this.dataset.searchResource === 'global'
53
57
  }
@@ -83,27 +87,50 @@ export default class extends Controller {
83
87
  params.global = true
84
88
  }
85
89
 
86
- if (this.isBelongsToSearch) {
87
- params = {
88
- ...params,
89
- // eslint-disable-next-line camelcase
90
- via_association_id: this.dataset.viaAssociationId,
91
- // eslint-disable-next-line camelcase
92
- via_reflection_class: this.dataset.viaReflectionClass,
93
- // eslint-disable-next-line camelcase
94
- via_reflection_id: this.dataset.viaReflectionId,
95
- // eslint-disable-next-line camelcase
96
- via_parent_resource_id: this.dataset.viaParentResourceId,
97
- // eslint-disable-next-line camelcase
98
- via_parent_resource_class: this.dataset.viaParentResourceClass,
99
- // eslint-disable-next-line camelcase
100
- via_relation: this.dataset.viaRelation,
90
+ if (this.isBelongsToSearch || this.isHasManySearch) {
91
+ params = this.addAssociationParams(params)
92
+ params = this.addReflectionParams(params)
93
+
94
+ if (this.isBelongsToSearch) {
95
+ params = {
96
+ ...params,
97
+ // eslint-disable-next-line camelcase
98
+ via_parent_resource_id: this.dataset.viaParentResourceId,
99
+ // eslint-disable-next-line camelcase
100
+ via_parent_resource_class: this.dataset.viaParentResourceClass,
101
+ // eslint-disable-next-line camelcase
102
+ via_relation: this.dataset.viaRelation,
103
+ }
101
104
  }
102
105
  }
103
106
 
104
107
  return params
105
108
  }
106
109
 
110
+ addAssociationParams(params) {
111
+ params = {
112
+ ...params,
113
+ // eslint-disable-next-line camelcase
114
+ via_association: this.dataset.viaAssociation,
115
+ // eslint-disable-next-line camelcase
116
+ via_association_id: this.dataset.viaAssociationId,
117
+ }
118
+
119
+ return params
120
+ }
121
+
122
+ addReflectionParams(params) {
123
+ params = {
124
+ ...params,
125
+ // eslint-disable-next-line camelcase
126
+ via_reflection_class: this.dataset.viaReflectionClass,
127
+ // eslint-disable-next-line camelcase
128
+ via_reflection_id: this.dataset.viaReflectionId,
129
+ }
130
+
131
+ return params
132
+ }
133
+
107
134
  handleOnSelect({ item }) {
108
135
  if (this.isBelongsToSearch) {
109
136
  this.updateFieldAttribute(this.hiddenIdTarget, 'value', item._id)
@@ -13,6 +13,7 @@
13
13
  <div class="flex-1 flex items-center justify-center px-0 lg:px-8 text-lg mt-8 mb-12">
14
14
  <% if @field.searchable %>
15
15
  <%= render Avo::Fields::BelongsToField::AutocompleteComponent.new form: form,
16
+ classes: input_classes("w-full"),
16
17
  field: @field,
17
18
  model_key: @field.target_resource&.model_key,
18
19
  foreign_key: 'related_id',
@@ -1,4 +1,4 @@
1
- <%= render Avo::PanelComponent.new(title: @dashboard.name, description: @dashboard.description) do |c| %>
1
+ <%= render Avo::PanelComponent.new(name: @dashboard.name, description: @dashboard.description) do |c| %>
2
2
  <% c.bare_content do %>
3
3
  <% if @dashboard.items.present? %>
4
4
  <div class="min-h-24">
@@ -14,7 +14,7 @@
14
14
  hq_payload = Avo::Licensing::HQ.new(request).payload
15
15
  %>
16
16
  <div class="flex flex-col">
17
- <%= render Avo::PanelComponent.new(title: 'Debug Avo', description: 'Use this page to debug the Avo license.') do |c| %>
17
+ <%= render Avo::PanelComponent.new(name: 'Debug Avo', description: 'Use this page to debug the Avo license.') do |c| %>
18
18
  <% c.tools do %>
19
19
  <% end %>
20
20
  <% c.bare_content do %>
@@ -9,6 +9,7 @@
9
9
  </div>
10
10
  <div class="flex justify-end">
11
11
  <%= a_button icon: 'heroicons/outline/clipboard',
12
+ color: :primary,
12
13
  style: :primary,
13
14
  data: {
14
15
  controller: 'copy-to-clipboard',
@@ -1,5 +1,5 @@
1
1
  <div class="flex flex-col">
2
- <%= render Avo::PanelComponent.new(title: 'Welcome to Avo', description: 'This page is visible only in development. It will be hidden in other environments.') do |c| %>
2
+ <%= render Avo::PanelComponent.new(name: 'Welcome to Avo', description: 'This page is visible only in development. It will be hidden in other environments.') do |c| %>
3
3
  <% c.body do %>
4
4
  <div class="flex flex-col justify-between py-6 min-h-24">
5
5
  <div class="px-6 space-y-4">
@@ -3,6 +3,12 @@
3
3
  data-search-target="autocomplete"
4
4
  data-search-resource="<%= resource %>"
5
5
  data-translation-keys='{"no_item_found": "<%= I18n.translate 'avo.no_item_found' %>"}'
6
+ <% if via_reflection.present? %>
7
+ data-via-association="<%= via_reflection[:association] %>"
8
+ data-via-association-id="<%= via_reflection[:association_id] %>"
9
+ data-via-reflection-class="<%= via_reflection[:class] %>"
10
+ data-via-reflection-id="<%= via_reflection[:id] %>"
11
+ <% end %>
6
12
  >
7
13
  </div>
8
14
  <div class="hidden relative inline-flex text-gray-400 text-sm border border-gray-300 rounded cursor-pointer" data-search-target="button"></div>
@@ -1,7 +1,7 @@
1
1
  <div class="flex flex-col">
2
- <%= render Avo::PanelComponent.new(title: 'Welcome to Avo', description: 'This page is visible only in development. It will be hidden in other environments.') do |c| %>
2
+ <%= render Avo::PanelComponent.new(name: 'Welcome to Avo', description: 'This page is visible only in development. It will be hidden in other environments.') do |c| %>
3
3
  <% c.tools do %>
4
- <%= a_link('/admin', icon: 'arrow-left', style: :primary, is_link: true) do %>
4
+ <%= a_link('/admin', icon: 'arrow-left', color: :green, style: :primary, is_link: true) do %>
5
5
  Primary
6
6
  <% end %>
7
7
 
@@ -18,7 +18,7 @@
18
18
  <% end %>
19
19
  <% end %>
20
20
  </head>
21
- <body class="bg-gray-25 os-mac">
21
+ <body class="bg-application os-mac">
22
22
  <div class="relative flex flex-1 w-full min-h-full" data-controller="sidebar" data-sidebar-open-value="<%= @sidebar_open %>">
23
23
  <div class="flex-1 flex flex-col max-w-full">
24
24
  <%= render partial: "avo/partials/navbar" %>
@@ -3,8 +3,8 @@ module Avo
3
3
  extend ActiveSupport::DescendantsTracker
4
4
 
5
5
  include ActionView::Helpers::UrlHelper
6
- include Avo::Concerns::HasModel
7
6
  include Avo::Concerns::HasFields
7
+ include Avo::Concerns::HasEditableControls
8
8
  include Avo::Concerns::HasStimulusControllers
9
9
  include Avo::Concerns::ModelClassConstantized
10
10
 
@@ -439,5 +439,9 @@ module Avo
439
439
  def ordering_host(**args)
440
440
  Avo::Hosts::Ordering.new resource: self, options: self.class.ordering, **args
441
441
  end
442
+
443
+ def has_model_id?
444
+ model.present? && model.id.present?
445
+ end
442
446
  end
443
447
  end
@@ -0,0 +1,34 @@
1
+ module Avo
2
+ module Concerns
3
+ module HasEditableControls
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ class_attribute :show_controls
8
+ class_attribute :show_controls_holder
9
+ class_attribute :show_controls_holder_called, default: false
10
+ end
11
+
12
+ def has_show_controls?
13
+ return false if ::Avo::App.license.lacks_with_trial(:resource_show_controls)
14
+
15
+ self.class.show_controls.present?
16
+ end
17
+
18
+ def render_show_controls
19
+ return [] if ::Avo::App.license.lacks_with_trial(:resource_show_controls)
20
+
21
+ if show_controls.present?
22
+ Avo::Resources::Controls::ExecutionContext.new(
23
+ block: show_controls,
24
+ resource: self,
25
+ record: model,
26
+ view: view
27
+ ).handle&.items || []
28
+ else
29
+ []
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -17,19 +17,19 @@ module Avo
17
17
  def field(name, **args, &block)
18
18
  ensure_items_holder_initialized
19
19
 
20
- self.items_holder.field name, **args, &block
20
+ items_holder.field name, **args, &block
21
21
  end
22
22
 
23
23
  def panel(name = nil, **args, &block)
24
24
  ensure_items_holder_initialized
25
25
 
26
- self.items_holder.panel name, **args, &block
26
+ items_holder.panel name, **args, &block
27
27
  end
28
28
 
29
29
  def tabs(&block)
30
30
  ensure_items_holder_initialized
31
31
 
32
- self.items_holder.tabs Avo::TabGroupBuilder.parse_block(&block)
32
+ items_holder.tabs Avo::TabGroupBuilder.parse_block(&block)
33
33
  end
34
34
 
35
35
  def tool(klass, **args)
@@ -39,27 +39,29 @@ module Avo
39
39
  end
40
40
 
41
41
  def heading(body, **args)
42
- self.items_holder.heading body, **args
42
+ ensure_items_holder_initialized
43
+
44
+ items_holder.heading body, **args
43
45
  end
44
46
  # END DSL methods
45
47
 
46
48
  def items
47
- if self.items_holder.present?
48
- self.items_holder.items
49
+ if items_holder.present?
50
+ items_holder.items
49
51
  else
50
52
  []
51
53
  end
52
54
  end
53
55
 
54
56
  def tools
55
- self.tools_holder
57
+ tools_holder
56
58
  end
57
59
 
58
60
  # Dives deep into panels and tabs to fetch all the fields for a resource.
59
61
  def fields(only_root: false)
60
62
  fields = []
61
63
 
62
- self.items.each do |item|
64
+ items.each do |item|
63
65
  next if item.nil?
64
66
 
65
67
  unless only_root
@@ -76,7 +78,6 @@ module Avo
76
78
  end
77
79
  end
78
80
 
79
-
80
81
  if item.is_field?
81
82
  fields << item
82
83
  end
@@ -86,7 +87,7 @@ module Avo
86
87
  end
87
88
 
88
89
  def tab_groups
89
- self.items.select do |item|
90
+ items.select do |item|
90
91
  item.instance_of? Avo::TabGroup
91
92
  end
92
93
  end
@@ -160,7 +160,7 @@ module Avo
160
160
  final_value = @model.send(property) if (model_or_class(@model) == "model") && @model.respond_to?(property)
161
161
 
162
162
  # On new views and actions modals we need to prefill the fields
163
- if (@view === :new) || @action.present?
163
+ if @view.in?([:new, :create]) || @action.present?
164
164
  if default.present?
165
165
  final_value = if default.respond_to?(:call)
166
166
  default.call
@@ -5,15 +5,13 @@ module Avo
5
5
  attr_reader :picker_format
6
6
  attr_reader :disable_mobile
7
7
  attr_reader :format
8
- attr_reader :relative
9
8
 
10
9
  def initialize(id, **args, &block)
11
10
  super(id, **args, &block)
12
11
 
13
- add_string_prop args, :first_day_of_week, 0
12
+ add_string_prop args, :first_day_of_week, 1
14
13
  add_string_prop args, :picker_format, "Y-m-d"
15
14
  add_string_prop args, :format, "yyyy-LL-dd"
16
- add_boolean_prop args, :relative
17
15
  add_boolean_prop args, :disable_mobile
18
16
  end
19
17
 
@@ -4,7 +4,7 @@ module Avo
4
4
  module HasIncludeBlank
5
5
  def include_blank
6
6
  if @args[:include_blank] == true
7
- placeholder || ''
7
+ placeholder || ""
8
8
  elsif @args[:include_blank] == false
9
9
  false
10
10
  else
@@ -6,6 +6,7 @@ module Avo
6
6
  attr_accessor :attach_scope
7
7
  attr_accessor :description
8
8
  attr_accessor :discreet_pagination
9
+ attr_accessor :hide_search_input
9
10
 
10
11
  def initialize(id, **args, &block)
11
12
  super(id, **args, &block)
@@ -14,6 +15,7 @@ module Avo
14
15
  @attach_scope = args[:attach_scope].present? ? args[:attach_scope] : nil
15
16
  @display = args[:display].present? ? args[:display] : :show
16
17
  @searchable = args[:searchable] == true
18
+ @hide_search_input = args[:hide_search_input] || false
17
19
  @description = args[:description]
18
20
  @use_resource = args[:use_resource] || nil
19
21
  @discreet_pagination = args[:discreet_pagination] || false