avo 2.9.1.pre7 → 2.10.2

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.

Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +8 -10
  3. data/README.md +4 -0
  4. data/app/assets/stylesheets/css/buttons.css +4 -1
  5. data/app/components/avo/base_component.rb +2 -0
  6. data/app/components/avo/button_component.rb +3 -1
  7. data/app/components/avo/fields/edit_component.rb +5 -0
  8. data/app/components/avo/fields/show_component.rb +1 -1
  9. data/app/components/avo/index/ordering/button_component.rb +3 -5
  10. data/app/components/avo/index/resource_table_component.html.erb +1 -1
  11. data/app/components/avo/index/table_row_component.html.erb +1 -1
  12. data/app/components/avo/item_switcher_component.html.erb +19 -0
  13. data/app/components/avo/item_switcher_component.rb +45 -0
  14. data/app/components/avo/panel_component.html.erb +23 -24
  15. data/app/components/avo/panel_component.rb +8 -5
  16. data/app/components/avo/tab_group_component.html.erb +53 -0
  17. data/app/components/avo/tab_group_component.rb +51 -0
  18. data/app/components/avo/tab_switcher_component.html.erb +21 -0
  19. data/app/components/avo/tab_switcher_component.rb +86 -0
  20. data/app/components/avo/views/resource_edit_component.html.erb +34 -56
  21. data/app/components/avo/views/resource_edit_component.rb +10 -0
  22. data/app/components/avo/views/resource_index_component.html.erb +1 -1
  23. data/app/components/avo/views/resource_index_component.rb +1 -1
  24. data/app/components/avo/views/resource_show_component.html.erb +58 -89
  25. data/app/components/avo/views/resource_show_component.rb +2 -2
  26. data/app/controllers/avo/actions_controller.rb +1 -1
  27. data/app/controllers/avo/application_controller.rb +11 -15
  28. data/app/helpers/avo/application_helper.rb +0 -6
  29. data/app/helpers/avo/url_helpers.rb +1 -1
  30. data/app/javascript/js/controllers/loading_button_controller.js +25 -21
  31. data/app/javascript/js/controllers/tabs_controller.js +9 -3
  32. data/app/javascript/js/controllers.js +2 -0
  33. data/app/views/avo/base/index.html.erb +1 -1
  34. data/app/views/avo/base/show.html.erb +1 -1
  35. data/app/views/avo/cards/show.html.erb +1 -1
  36. data/app/views/avo/debug/index.html.erb +1 -1
  37. data/app/views/avo/home/_actions.html.erb +1 -1
  38. data/app/views/avo/home/_dashboards.html.erb +19 -0
  39. data/app/views/avo/home/_filters.html.erb +1 -1
  40. data/app/views/avo/home/_resources.html.erb +1 -1
  41. data/app/views/avo/home/failed_to_load.html.erb +1 -1
  42. data/app/views/avo/home/index.html.erb +14 -2
  43. data/app/views/avo/partials/_tabs_toggle.html.erb +20 -0
  44. data/app/views/avo/private/design.html.erb +1 -1
  45. data/lib/avo/base_action.rb +2 -19
  46. data/lib/avo/base_resource.rb +0 -94
  47. data/lib/avo/base_resource_tool.rb +3 -1
  48. data/lib/avo/concerns/has_fields.rb +247 -50
  49. data/lib/avo/concerns/has_html_attributes.rb +1 -1
  50. data/lib/avo/concerns/is_resource_item.rb +36 -0
  51. data/lib/avo/dsl/field_parser.rb +83 -0
  52. data/lib/avo/fields/base_field.rb +19 -2
  53. data/lib/avo/fields/field_extensions/visible_in_different_views.rb +18 -1
  54. data/lib/avo/fields/has_base_field.rb +18 -1
  55. data/lib/avo/fields/key_value_field.rb +4 -4
  56. data/lib/avo/grid_collector.rb +6 -3
  57. data/lib/avo/items_holder.rb +68 -0
  58. data/lib/avo/licensing/h_q.rb +10 -0
  59. data/lib/avo/main_panel.rb +3 -0
  60. data/lib/avo/menu/builder.rb +6 -6
  61. data/lib/avo/panel.rb +25 -0
  62. data/lib/avo/panel_builder.rb +23 -0
  63. data/lib/avo/tab.rb +78 -0
  64. data/lib/avo/tab_builder.rb +25 -0
  65. data/lib/avo/tab_group.rb +40 -0
  66. data/lib/avo/tab_group_builder.rb +43 -0
  67. data/lib/avo/version.rb +1 -1
  68. data/lib/generators/avo/templates/resource/controller.tt +2 -0
  69. data/lib/generators/avo/templates/resource_tools/partial.tt +1 -1
  70. data/lib/generators/avo/templates/tool/view.tt +1 -1
  71. data/public/avo-assets/avo.css +27 -3
  72. data/public/avo-assets/avo.js +73 -73
  73. data/public/avo-assets/avo.js.map +3 -3
  74. metadata +22 -5
  75. data/lib/avo/concerns/has_tools.rb +0 -47
@@ -1,77 +1,55 @@
1
1
  <%= content_tag :div,
2
- class: "space-y-12",
3
2
  data: {
4
3
  'model-id': @resource.model.id,
5
4
  selected_resources_name: @resource.model_key,
6
5
  selected_resources: [@resource.model.id],
7
6
  **@resource.stimulus_data_attributes
8
7
  } do %>
9
- <% @resource.panels.each_with_index do |resource_panel, index| %>
10
- <%= form_with model: @resource.model,
11
- scope: @resource.form_scope,
12
- url: form_url,
13
- local: true,
14
- multipart: true do |form| %>
15
- <%= render Avo::ReferrerParamsComponent.new back_path: back_path %>
16
- <%= render Avo::PanelComponent.new(title: resource_panel[:name], description: @resource.resource_description, display_breadcrumbs: true, index: index) do |c| %>
17
- <% c.tools do %>
18
- <%= a_link back_path,
19
- style: :text,
20
- icon: 'arrow-left' do %>
21
- <%= t('avo.cancel').capitalize %>
22
- <% end %>
23
- <%= render Avo::ActionsComponent.new actions: @actions, resource: @resource, view: @view %>
24
- <% if can_see_the_save_button? %>
25
- <%= a_button color: :primary,
8
+ <%= form_with model: @resource.model,
9
+ scope: @resource.form_scope,
10
+ url: form_url,
11
+ method: form_method,
12
+ local: true,
13
+ html: {
14
+ novalidate: true
15
+ },
16
+ multipart: true do |form| %>
17
+ <%= render Avo::ReferrerParamsComponent.new back_path: back_path %>
18
+ <%= render Avo::PanelComponent.new(title: title, description: @resource.resource_description, display_breadcrumbs: @reflection.blank?, index: 0, data: { panel_id: "main" }) do |c| %>
19
+ <% c.tools do %>
20
+ <%= a_link back_path,
21
+ style: :text,
22
+ icon: 'arrow-left' do %>
23
+ <%= t('avo.cancel').capitalize %>
24
+ <% end %>
25
+ <%= render Avo::ActionsComponent.new actions: @actions, resource: @resource, view: @view %>
26
+ <% if can_see_the_save_button? %>
27
+ <%= a_button color: :primary,
26
28
  style: :primary,
27
29
  loading: true,
28
30
  type: :submit,
29
31
  icon: 'save' do %>
30
- <%= t('avo.save').capitalize %>
31
- <% end %>
32
+ <%= t('avo.save').capitalize %>
32
33
  <% end %>
33
34
  <% end %>
34
- <% if Avo.configuration.buttons_on_form_footers %>
35
- <% c.footer_tools do %>
36
- <%= a_link back_path, icon: 'arrow-left' do %>
37
- <%= t('avo.cancel').capitalize %>
38
- <% end %>
39
- <% if can_see_the_save_button? %>
40
- <%= a_button color: :green, loading: true, type: :submit, icon: 'save' do %>
41
- <%= t('avo.save').capitalize %>
42
- <% end %>
43
- <% end %>
35
+ <% end %>
36
+ <% if Avo.configuration.buttons_on_form_footers %>
37
+ <% c.footer_tools do %>
38
+ <%= a_link back_path, icon: 'arrow-left' do %>
39
+ <%= t('avo.cancel').capitalize %>
44
40
  <% end %>
45
- <% end %>
46
- <% c.body do %>
47
- <div class="divide-y">
48
- <% @resource.get_fields.each_with_index do |field, index| %>
49
- <%= render field.component_for_view(:edit).new(field: field, resource: @resource, index: index, form: form) unless field.computed %>
41
+ <% if can_see_the_save_button? %>
42
+ <%= a_button color: :green, loading: true, type: :submit, icon: 'save' do %>
43
+ <%= t('avo.save').capitalize %>
50
44
  <% end %>
51
- </div>
45
+ <% end %>
52
46
  <% end %>
53
47
  <% end %>
54
48
  <% end %>
55
- <% end %>
56
- <% if @reflection.blank? %>
57
- <% if has_one_panels.present? %>
58
- <% has_one_panels.each_with_index do |field, index| %>
59
- <%= render field.component_for_view(:show).new(field: field, resource: @resource, index: index) %>
60
- <% end %>
61
- <% end %>
62
- <% if has_many_panels.present? %>
63
- <% has_many_panels.each_with_index do |field, index| %>
64
- <%= render field.component_for_view(:show).new(field: field, resource: @resource, index: index) %>
65
- <% end %>
66
- <% end %>
67
- <% if has_as_belongs_to_many_panels.present? %>
68
- <% has_as_belongs_to_many_panels.each_with_index do |field, index| %>
69
- <%= render field.component_for_view(:show).new(field: field, resource: @resource, index: index) %>
70
- <% end %>
71
- <% end %>
72
- <% if resource_tools.present? %>
73
- <% resource_tools.each do |tool, index| %>
74
- <%= render tool.partial, tool: tool %>
49
+ <%= content_tag :div, class: 'space-y-12' do %>
50
+ <% @resource.get_items.each_with_index do |item, index| %>
51
+ <% next if item.nil? %>
52
+ <%= render Avo::ItemSwitcherComponent.new resource: @resource, item: item, index: index + 1, view: @view, form: form %>
75
53
  <% end %>
76
54
  <% end %>
77
55
  <% end %>
@@ -15,6 +15,10 @@ class Avo::Views::ResourceEditComponent < Avo::ResourceComponent
15
15
  split_panel_fields
16
16
  end
17
17
 
18
+ def title
19
+ @resource.default_panel_name
20
+ end
21
+
18
22
  def back_path
19
23
  if via_resource?
20
24
  helpers.resource_path(model: params[:via_resource_class].safe_constantize, resource: relation_resource, resource_id: params[:via_resource_id])
@@ -45,6 +49,12 @@ class Avo::Views::ResourceEditComponent < Avo::ResourceComponent
45
49
  view == :edit
46
50
  end
47
51
 
52
+ def form_method
53
+ return :put if is_edit?
54
+
55
+ :post
56
+ end
57
+
48
58
  def form_url
49
59
  if is_edit?
50
60
  helpers.resource_path(
@@ -37,7 +37,7 @@
37
37
  <%= render partial: 'avo/partials/resource_search', locals: {resource: @resource.model_name.collection} %>
38
38
  </div>
39
39
  <% else %>
40
- <%# Offset for the space-y-2 property when the serach is missing %>
40
+ <%# Offset for the space-y-2 property when the search is missing %>
41
41
  <div class="-mb-2"></div>
42
42
  <% end %>
43
43
  <% if @filters.present? || available_view_types.count > 1 %>
@@ -113,7 +113,7 @@ class Avo::Views::ResourceIndexComponent < Avo::ResourceComponent
113
113
  end
114
114
  end
115
115
 
116
- helpers.new_resource_path(model: @resource.model_class, resource: @resource, **args)
116
+ helpers.new_resource_path(resource: @resource, **args)
117
117
  end
118
118
 
119
119
  def attach_path
@@ -1,105 +1,74 @@
1
1
  <%= content_tag :div,
2
- class: "space-y-12",
3
2
  data: {
4
3
  'model-id': @resource.model.id,
5
4
  selected_resources_name: @resource.model_key,
6
5
  selected_resources: [@resource.model.id],
7
6
  **@resource.stimulus_data_attributes
8
7
  } do %>
9
- <% @resource.panels.each_with_index do |resource_panel, index| %>
10
- <%= render Avo::PanelComponent.new(title: title, description: @resource.resource_description, display_breadcrumbs: @reflection.blank?, index: index) do |c| %>
11
- <% c.tools do %>
12
- <% if resource_panel[:name] == @resource.default_panel_name %>
13
- <% if @reflection.present? && @resource.model.present? %>
14
- <% if can_detach? %>
15
- <%= a_button url: detach_path,
16
- icon: 'detach',
17
- method: :delete,
18
- form_class: 'flex flex-col sm:flex-row sm:inline-flex',
19
- style: :text,
20
- data: {
21
- confirm: "Are you sure you want to detach this #{title}."
22
- } do %>
23
- <%= t('avo.detach_item', item: title).capitalize %>
24
- <% end %>
25
- <%= render Avo::ActionsComponent.new actions: @actions, resource: @resource, view: @view %>
26
- <% end %>
27
- <% if can_see_the_edit_button? %>
28
- <%= a_link edit_path,
29
- color: :primary,
30
- style: :primary,
31
- icon: 'edit' do %>
32
- <%= t('avo.edit').capitalize %>
33
- <% end %>
34
- <% end %>
35
- <% else %>
36
- <%= a_link back_path,
37
- style: :text,
38
- icon: 'arrow-left' do %>
39
- <%= t('avo.go_back') %>
40
- <% end %>
41
- <% if can_see_the_destroy_button? %>
42
- <%= a_button url: helpers.resource_path(model: @resource.model, resource: @resource),
43
- method: :delete,
44
- local: true,
45
- style: :text,
46
- title: t('avo.delete_item', item: @resource.model.model_name.name.downcase).capitalize,
47
- loading: true,
48
- confirm: t('avo.are_you_sure', item: @resource.model.model_name.name.downcase),
49
- color: :red,
50
- icon: 'trash',
51
- form_class: 'flex flex-col sm:flex-row sm:inline-flex',
52
- data: {
53
- control: :destroy,
54
- 'resource-id': @resource.model.id,
55
- 'tippy': 'tooltip',
56
- } do %>
57
- <%= t('avo.delete').capitalize %>
58
- <% end %>
59
- <% end %>
60
- <%= render Avo::ActionsComponent.new actions: @actions, resource: @resource, view: @view %>
61
- <% if @resource.authorization.authorize_action(:edit, raise_exception: false) %>
62
- <%= a_link edit_path,
63
- color: :primary,
64
- style: :primary,
65
- icon: 'edit' do %>
66
- <%= t('avo.edit').capitalize %>
67
- <% end %>
68
- <% end %>
8
+ <%= render Avo::PanelComponent.new(title: title, description: @resource.resource_description, display_breadcrumbs: @reflection.blank?, index: 0, data: { panel_id: "main" }) do |c| %>
9
+ <% c.tools do %>
10
+ <% if @reflection.present? && @resource.model.present? %>
11
+ <% if can_detach? %>
12
+ <%= a_button url: detach_path,
13
+ icon: 'detach',
14
+ method: :delete,
15
+ form_class: 'flex flex-col sm:flex-row sm:inline-flex',
16
+ style: :text,
17
+ data: {
18
+ confirm: "Are you sure you want to detach this #{title}."
19
+ } do %>
20
+ <%= t('avo.detach_item', item: title).capitalize %>
69
21
  <% end %>
22
+ <%= render Avo::ActionsComponent.new actions: @actions, resource: @resource, view: @view %>
70
23
  <% end %>
71
- <% end %>
72
- <% c.body do %>
73
- <% if fields_by_panel[resource_panel[:name]].present? %>
74
- <div class="divide-y">
75
- <% fields_by_panel[resource_panel[:name]].each_with_index do |field, index| %>
76
- <%= render field.component_for_view(:show).new(field: field, resource: @resource, index: index) %>
77
- <% end %>
78
- </div>
24
+ <% if can_see_the_edit_button? %>
25
+ <%= a_link edit_path,
26
+ color: :primary,
27
+ style: :primary,
28
+ icon: 'edit' do %>
29
+ <%= t('avo.edit').capitalize %>
30
+ <% end %>
31
+ <% end %>
32
+ <% else %>
33
+ <%= a_link back_path,
34
+ style: :text,
35
+ icon: 'arrow-left' do %>
36
+ <%= t('avo.go_back') %>
37
+ <% end %>
38
+ <% if can_see_the_destroy_button? %>
39
+ <%= a_button url: helpers.resource_path(model: @resource.model, resource: @resource),
40
+ method: :delete,
41
+ local: true,
42
+ style: :text,
43
+ loading: true,
44
+ confirm: t('avo.are_you_sure', item: @resource.model.model_name.name.downcase),
45
+ color: :red,
46
+ icon: 'trash',
47
+ form_class: 'flex flex-col sm:flex-row sm:inline-flex',
48
+ data: {
49
+ control: :destroy,
50
+ 'resource-id': @resource.model.id,
51
+ 'tippy': 'tooltip',
52
+ } do %>
53
+ <%= t('avo.delete').capitalize %>
54
+ <% end %>
55
+ <% end %>
56
+ <%= render Avo::ActionsComponent.new actions: @actions, resource: @resource, view: @view %>
57
+ <% if @resource.authorization.authorize_action(:edit, raise_exception: false) %>
58
+ <%= a_link edit_path,
59
+ color: :primary,
60
+ style: :primary,
61
+ icon: 'edit' do %>
62
+ <%= t('avo.edit').capitalize %>
63
+ <% end %>
79
64
  <% end %>
80
65
  <% end %>
81
66
  <% end %>
82
67
  <% end %>
83
- <% if @reflection.blank? %>
84
- <% if has_one_panels.present? %>
85
- <% has_one_panels.each_with_index do |field, index| %>
86
- <%= render field.component_for_view(:show).new(field: field, resource: @resource, index: index) %>
87
- <% end %>
88
- <% end %>
89
- <% if has_many_panels.present? %>
90
- <% has_many_panels.each_with_index do |field, index| %>
91
- <%= render field.component_for_view(:show).new(field: field, resource: @resource, index: index) %>
92
- <% end %>
93
- <% end %>
94
- <% if has_as_belongs_to_many_panels.present? %>
95
- <% has_as_belongs_to_many_panels.each_with_index do |field, index| %>
96
- <%= render field.component_for_view(:show).new(field: field, resource: @resource, index: index) %>
97
- <% end %>
98
- <% end %>
99
- <% if resource_tools.present? %>
100
- <% resource_tools.each do |tool, index| %>
101
- <%= render tool.partial, tool: tool %>
102
- <% end %>
68
+ <%= content_tag :div, class: 'space-y-12' do %>
69
+ <% @resource.get_items.each_with_index do |item, index| %>
70
+ <% next if item.nil? %>
71
+ <%= render Avo::ItemSwitcherComponent.new resource: @resource, reflection: @reflection, item: item, index: index + 1, view: @view %>
103
72
  <% end %>
104
73
  <% end %>
105
74
  <% if should_display_invalid_fields_errors? %>
@@ -19,7 +19,7 @@ class Avo::Views::ResourceShowComponent < Avo::ResourceComponent
19
19
  return field.name if has_one_field?
20
20
  reflection_resource.name
21
21
  else
22
- @resource.panels.first[:name]
22
+ @resource.default_panel_name
23
23
  end
24
24
  end
25
25
 
@@ -52,6 +52,6 @@ class Avo::Views::ResourceShowComponent < Avo::ResourceComponent
52
52
  end
53
53
 
54
54
  def has_one_field?
55
- field.present? and field.class == Avo::Fields::HasOneField
55
+ field.present? and field.instance_of? Avo::Fields::HasOneField
56
56
  end
57
57
  end
@@ -42,7 +42,7 @@ module Avo
42
42
  model = @resource.class.find_scope.find params[:id]
43
43
  end
44
44
 
45
- @action = action_class.new(model: model, resource: resource, user: _current_user)
45
+ @action = action_class.new(model: model, resource: resource, user: _current_user, view: :edit)
46
46
  end
47
47
 
48
48
  def respond(response)
@@ -14,7 +14,7 @@ module Avo
14
14
  before_action :init_app
15
15
  before_action :check_avo_license
16
16
  before_action :set_default_locale
17
- around_action :set_force_locale
17
+ around_action :set_force_locale, if: -> { params[:force_locale].present? }
18
18
  before_action :set_authorization
19
19
  before_action :_authenticate!
20
20
  before_action :set_container_classes
@@ -261,23 +261,23 @@ module Avo
261
261
  end
262
262
 
263
263
  def on_root_path
264
- [Avo::App.root_path, "#{Avo::App.root_path}/"].include?(request.original_fullpath)
264
+ [Avo.configuration.root_path, "#{Avo.configuration.root_path}/"].include?(request.original_fullpath)
265
265
  end
266
266
 
267
267
  def on_resources_path
268
- request.original_url.match?(/.*#{Avo::App.root_path}\/resources\/.*/)
268
+ request.original_url.match?(/.*#{Avo.configuration.root_path}\/resources\/.*/)
269
269
  end
270
270
 
271
271
  def on_api_path
272
- request.original_url.match?(/.*#{Avo::App.root_path}\/avo_api\/.*/)
272
+ request.original_url.match?(/.*#{Avo.configuration.root_path}\/avo_api\/.*/)
273
273
  end
274
274
 
275
275
  def on_dashboards_path
276
- request.original_url.match?(/.*#{Avo::App.root_path}\/dashboards\/.*/)
276
+ request.original_url.match?(/.*#{Avo.configuration.root_path}\/dashboards\/.*/)
277
277
  end
278
278
 
279
279
  def on_debug_path
280
- request.original_url.match?(/.*#{Avo::App.root_path}\/avo_private\/debug.*/)
280
+ request.original_url.match?(/.*#{Avo.configuration.root_path}\/avo_private\/debug.*/)
281
281
  end
282
282
 
283
283
  def on_custom_tool_page
@@ -294,16 +294,12 @@ module Avo
294
294
  I18n.default_locale = I18n.locale
295
295
  end
296
296
 
297
- # Temporary set the locale
297
+ # Temporary set the locale and reverting at the end of the request.
298
298
  def set_force_locale
299
- if params[:force_locale].present?
300
- initial_locale = I18n.locale.to_s.dup
301
- I18n.locale = params[:force_locale]
302
- yield
303
- I18n.locale = initial_locale
304
- else
305
- yield
306
- end
299
+ initial_locale = I18n.locale.to_s.dup
300
+ I18n.locale = params[:force_locale]
301
+ yield
302
+ I18n.locale = initial_locale
307
303
  end
308
304
 
309
305
  def default_url_options
@@ -20,12 +20,6 @@ module Avo
20
20
  render Avo::EmptyStateComponent.new **args
21
21
  end
22
22
 
23
- def turbo_frame_wrap(name, &block)
24
- render Avo::TurboFrameWrapperComponent.new name do
25
- capture(&block)
26
- end
27
- end
28
-
29
23
  def a_button(**args, &block)
30
24
  render Avo::ButtonComponent.new(is_link: false, **args) do
31
25
  capture(&block) if block_given?
@@ -35,7 +35,7 @@ module Avo
35
35
  avo.send :"resources_#{resource.singular_route_key}_path", id, **args
36
36
  end
37
37
 
38
- def new_resource_path(model:, resource:, **args)
38
+ def new_resource_path(resource:, **args)
39
39
  avo.send :"new_resources_#{resource.singular_route_key}_path", **args
40
40
  end
41
41
 
@@ -7,33 +7,37 @@ export default class extends Controller {
7
7
  <div class="double-bounce2"></div>
8
8
  </div>`;
9
9
 
10
- confirmed = false
11
-
12
- connect() {
13
- this.context.scope.element.addEventListener('click', (e) => {
14
- // If the user has to confirm the action
15
- if (this.confirmationMessage) {
16
- // Intervene only if not confirmed
17
- if (!this.confirmed) {
18
- e.preventDefault()
19
- if (window.confirm(this.confirmationMessage)) {
20
- this.applyLoader()
21
- }
22
- }
23
- } else {
10
+ static values = {
11
+ confirmationMessage: String,
12
+ confirmed: Boolean,
13
+ }
14
+
15
+ attemptSubmit(e) {
16
+ // If the user has to confirm the action
17
+ if (this.confirmationMessageValue) {
18
+ this.confirmAndApply(e)
19
+ } else {
20
+ this.applyLoader()
21
+ }
22
+
23
+ return null
24
+ }
25
+
26
+ confirmAndApply(e) {
27
+ // Intervene only if not confirmed
28
+ if (!this.confirmedValue) {
29
+ e.preventDefault()
30
+
31
+ if (window.confirm(this.confirmationMessageValue)) {
24
32
  this.applyLoader()
25
33
  }
26
- })
34
+ }
27
35
  }
28
36
 
29
37
  get button() {
30
38
  return this.context.scope.element
31
39
  }
32
40
 
33
- get confirmationMessage() {
34
- return this.context.scope.element.getAttribute('data-avo-confirm')
35
- }
36
-
37
41
  applyLoader() {
38
42
  const { button } = this
39
43
 
@@ -50,10 +54,10 @@ export default class extends Controller {
50
54
  }
51
55
 
52
56
  markConfirmed() {
53
- this.confirmed = true
57
+ this.confirmedValue = true
54
58
  }
55
59
 
56
60
  markUnconfirmed() {
57
- this.confirmed = false
61
+ this.confirmedValue = false
58
62
  }
59
63
  }
@@ -6,6 +6,7 @@ export default class extends Controller {
6
6
  static targets = ['tab'];
7
7
 
8
8
  static values = {
9
+ view: String,
9
10
  activeTab: String,
10
11
  };
11
12
 
@@ -35,9 +36,15 @@ export default class extends Controller {
35
36
  }
36
37
 
37
38
  /**
38
- * Sets the target container height to the previous panel height so we don't get jerky tab changes.
39
- */
39
+ * Sets the target container height to the previous panel height so we don't get jerky tab changes.
40
+ */
40
41
  setTheTargetPanelHeight(id) {
42
+ // Ignore this on edit.
43
+ // All tabs are loaded beforehand, they have their own height, and the page won't jiggle when the user toggles between them.
44
+ if (this.viewValue === 'edit' || this.viewValue === 'new') {
45
+ return
46
+ }
47
+
41
48
  // We don't need to add a height to this panel because it was loaded before
42
49
  if (castBoolean(this.targetTab(id).dataset.loaded)) {
43
50
  return
@@ -71,7 +78,6 @@ export default class extends Controller {
71
78
  element.classList.remove('hidden')
72
79
  }
73
80
  })
74
- // this.tabTargets.map((element) => element.clasList.add('hidden'))
75
81
  }
76
82
 
77
83
  hideTabs() {
@@ -27,6 +27,7 @@ import SearchController from './controllers/search_controller'
27
27
  import SelectController from './controllers/select_controller'
28
28
  import SelectFilterController from './controllers/select_filter_controller'
29
29
  import SimpleMdeController from './controllers/fields/simple_mde_controller'
30
+ import TabsController from './controllers/tabs_controller'
30
31
  import TagsFieldController from './controllers/fields/tags_field_controller'
31
32
  import TextFilterController from './controllers/text_filter_controller'
32
33
  import TippyController from './controllers/tippy_controller'
@@ -55,6 +56,7 @@ application.register('resource-show', ResourceShowController)
55
56
  application.register('search', SearchController)
56
57
  application.register('select', SelectController)
57
58
  application.register('select-filter', SelectFilterController)
59
+ application.register('tabs', TabsController)
58
60
  application.register('tags-field', TagsFieldController)
59
61
  application.register('text-filter', TextFilterController)
60
62
  application.register('tippy', TippyController)
@@ -1,4 +1,4 @@
1
- <%= turbo_frame_wrap(params[:turbo_frame]) do %>
1
+ <%= render Avo::TurboFrameWrapperComponent.new(params[:turbo_frame]) do %>
2
2
  <%= render Avo::Views::ResourceIndexComponent.new(
3
3
  resource: @resource,
4
4
  resources: @resources,
@@ -1,3 +1,3 @@
1
- <%= turbo_frame_wrap(params[:turbo_frame]) do %>
1
+ <%= render Avo::TurboFrameWrapperComponent.new(params[:turbo_frame]) do %>
2
2
  <%= render Avo::Views::ResourceShowComponent.new(resource: @resource, reflection: @reflection, actions: @actions) %>
3
3
  <% end %>
@@ -1,3 +1,3 @@
1
- <%= turbo_frame_wrap(params[:turbo_frame]) do %>
1
+ <%= render Avo::TurboFrameWrapperComponent.new(params[:turbo_frame]) do %>
2
2
  <%= render Avo::CardComponent.new card: @card %>
3
3
  <% end %>
@@ -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(title: '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 %>
@@ -11,6 +11,6 @@
11
11
  </div>
12
12
  </div>
13
13
 
14
- <a href="https://docs.avohq.io/1.0/actions.html" target="_blank" title="Avo Actions documentation" class="text-bold cursor-pointer block mt-2">Actions in the docs 👉</a>
14
+ <a href="https://docs.avohq.io/2.0/actions.html" target="_blank" title="Avo Actions documentation" class="text-bold cursor-pointer block mt-2">Actions in the docs 👉</a>
15
15
  </div>
16
16
  </div>
@@ -0,0 +1,19 @@
1
+ <div>
2
+ <h3>Dashboards</h3>
3
+
4
+ <div>There comes the point in your app's life when you need to display the data in an aggregated form like a metric or chart. That's what Avo's Dashboards are all about.</div>
5
+
6
+ <div>Generate a dashboard using the command below 👇👇</div>
7
+
8
+
9
+ <div class="mt-2">
10
+ <div class="mt-1">
11
+ <code class="p-1 rounded bg-sky-500 text-white">bin/rails generate avo:dashboard dashy</code>
12
+ </div>
13
+ </div>
14
+
15
+ <p>
16
+ <a href="https://docs.avohq.io/2.0/dashboards.html" target="_blank" title="Avo Dashboards documentation">Docs</a>
17
+ </p>
18
+ </div>
19
+
@@ -11,6 +11,6 @@
11
11
  </div>
12
12
  </div>
13
13
 
14
- <a href="https://docs.avohq.io/1.0/filters.html" target="_blank" title="Avo Filters documentation" class="text-bold cursor-pointer block mt-2">Filters in the docs 👉</a>
14
+ <a href="https://docs.avohq.io/2.0/filters.html" target="_blank" title="Avo Filters documentation" class="text-bold cursor-pointer block mt-2">Filters in the docs 👉</a>
15
15
  </div>
16
16
  </div>
@@ -35,7 +35,7 @@
35
35
  <% end %>
36
36
 
37
37
  <p>
38
- <a href="https://docs.avohq.io/1.0/resources.html" target="_blank" title="Avo Resources documentation">Docs</a>
38
+ <a href="https://docs.avohq.io/2.0/resources.html" target="_blank" title="Avo Resources documentation">Docs</a>
39
39
  </p>
40
40
  </div>
41
41
 
@@ -1,4 +1,4 @@
1
- <%= turbo_frame_wrap(params[:turbo_frame]) do %>
1
+ <%= render Avo::TurboFrameWrapperComponent.new(params[:turbo_frame]) do %>
2
2
  <%
3
3
  classes = 'absolute inset-auto left-1/2 top-1/2 transform -translate-x-1/2 -translate-y-1/2'
4
4
  label = t 'avo.failed_to_load'