avo 2.11.2.pre.3 → 2.11.3.pre.3

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


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

Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +1 -1
  3. data/app/assets/stylesheets/avo.css +1 -0
  4. data/app/assets/stylesheets/css/scrollbar.css +30 -0
  5. data/app/components/avo/card_component.html.erb +8 -8
  6. data/app/components/avo/cards_list_component.html.erb +16 -0
  7. data/app/components/avo/cards_list_component.rb +13 -0
  8. data/app/components/avo/paginator_component.html.erb +35 -33
  9. data/app/components/avo/paginator_component.rb +3 -1
  10. data/app/components/avo/sidebar_component.html.erb +2 -2
  11. data/app/components/avo/tab_switcher_component.html.erb +1 -1
  12. data/app/components/avo/views/resource_edit_component.rb +20 -0
  13. data/app/components/avo/views/resource_index_component.html.erb +98 -50
  14. data/app/components/avo/views/resource_show_component.html.erb +11 -5
  15. data/app/controllers/avo/application_controller.rb +3 -2
  16. data/app/controllers/avo/associations_controller.rb +1 -1
  17. data/app/controllers/avo/base_controller.rb +15 -10
  18. data/app/controllers/avo/cards_controller.rb +18 -5
  19. data/app/controllers/avo/dashboards_controller.rb +4 -2
  20. data/app/javascript/avo.js +1 -1
  21. data/app/javascript/js/controllers/{dashboard_card_controller.js → card_controller.js} +0 -0
  22. data/app/javascript/js/controllers/fields/date_field_controller.js +7 -3
  23. data/app/javascript/js/controllers.js +2 -2
  24. data/app/views/avo/cards/_metric_card.html.erb +2 -2
  25. data/app/views/avo/dashboards/show.html.erb +2 -19
  26. data/app/views/layouts/avo/application.html.erb +1 -1
  27. data/config/routes.rb +3 -0
  28. data/lib/avo/base_card.rb +40 -21
  29. data/lib/avo/base_resource.rb +1 -0
  30. data/lib/avo/concerns/has_cards.rb +88 -0
  31. data/lib/avo/concerns/styles_cards.rb +48 -0
  32. data/lib/avo/dashboards/base_dashboard.rb +15 -50
  33. data/lib/avo/dashboards/base_divider.rb +5 -1
  34. data/lib/avo/dashboards/chartkick_card.rb +5 -4
  35. data/lib/avo/fields/base_field.rb +2 -6
  36. data/lib/avo/fields/date_time_field.rb +2 -2
  37. data/lib/avo/fields/field_extensions/visible_in_different_views.rb +12 -1
  38. data/lib/avo/fields/has_base_field.rb +2 -0
  39. data/lib/avo/hosts/dashboard_card.rb +1 -1
  40. data/lib/avo/tab.rb +3 -1
  41. data/lib/avo/version.rb +1 -1
  42. data/lib/generators/avo/templates/cards/partial_card_partial.tt +1 -1
  43. data/public/avo-assets/avo.css +125 -34
  44. data/public/avo-assets/avo.js +7 -7
  45. data/public/avo-assets/avo.js.map +3 -3
  46. metadata +8 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3d9e1f29fde441425a8bb70c8d3afc6f8acece76e6ac2a2dc2abc953567c6053
4
- data.tar.gz: 8f9a42b1f4084a1846f8b1a279dd15119323cacad40054709677ac980cb7387d
3
+ metadata.gz: 33a3f78d32b04247f263b94f22dcfbc0e825e3ea99a311c1642866b30a46524f
4
+ data.tar.gz: 7344cfbc9197ac2537003045a2ab340165ba4964b095ef914e6ca49852881373
5
5
  SHA512:
6
- metadata.gz: 07e9b92e4bfa7031cb8ef415c64d886f10c4e83c7b2974485f9f891f99d56bf1176ae3d576c7e2f68a4a8b202f829ca53e0978d06b2fbf0620deef581567c79c
7
- data.tar.gz: 7700c610f99c0509b513a3180d420f28c82c403dfd4456867eb74e53178ac287d8c4d28a0c64c501b9923c0dbdc057d9940988fb222008024e836aabfb4c96ae
6
+ metadata.gz: 25e7ee4600617e4786e3b0c43e6b1f03fa4e3e14ab861745d5c9915352cdeb2c66e4d1444ebf1e834c6cb82fea7d854f3440b274ca90a946630279370928cc69
7
+ data.tar.gz: 4363ffce5ed2b2172d0c992d98dd8c9bcc8c68e82e7e48dfec8040efe877f8b2aab9203e538110f1ac3a2f77fa2f2d90caa573fc24f7eddc6af6f619da791966
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- avo (2.11.2.pre.3)
4
+ avo (2.11.3.pre.3)
5
5
  active_link_to
6
6
  addressable
7
7
  breadcrumbs_on_rails
@@ -16,6 +16,7 @@
16
16
  @import './css/breadcrumbs.css';
17
17
  @import './css/search.css';
18
18
  @import './css/active-storage.css';
19
+ @import './css/scrollbar.css';
19
20
  @import './css/sidebar.css';
20
21
  @import './css/spinner.css';
21
22
  @import './css/tags.css';
@@ -0,0 +1,30 @@
1
+ /* total width */
2
+ body.os-pc .mac-styled-scrollbar::-webkit-scrollbar {
3
+ background-color: none;
4
+ width: 0.5rem;
5
+ height: 0.5rem;
6
+ }
7
+
8
+ /* background of the scrollbar except button or resizer */
9
+ body.os-pc .mac-styled-scrollbar::-webkit-scrollbar-track {
10
+ background-color: none;
11
+ }
12
+
13
+ /* scrollbar itself */
14
+ body.os-pc .mac-styled-scrollbar::-webkit-scrollbar-thumb {
15
+ background-color: #babac0;
16
+ border-radius: 0.5rem;
17
+ }
18
+
19
+ /* set button(top and bottom of the scrollbar) */
20
+ body.os-pc .mac-styled-scrollbar::-webkit-scrollbar-button {
21
+ display:none;
22
+ }
23
+ /* hide by default */
24
+ body.os-pc .mac-styled-scrollbar::-webkit-scrollbar-thumb {
25
+ display:none
26
+ }
27
+ /* show on hover */
28
+ body.os-pc .mac-styled-scrollbar:hover::-webkit-scrollbar-thumb {
29
+ display:block
30
+ }
@@ -1,19 +1,19 @@
1
1
  <div class="relative flex-1 flex flex-col justify-between h-full"
2
- data-controller="dashboard-card"
3
- data-dashboard-card-target="card"
2
+ data-controller="card"
3
+ data-card-target="card"
4
4
  data-refresh-every="<%= @card.refresh_every %>"
5
5
  data-card-id="<%= @card.id %>"
6
6
  data-card-index="<%= @card.index %>">
7
7
  <% if @card.class.display_header %>
8
8
  <div class="px-4 pt-4">
9
- <div class="flex justify-between items-center min-h-6">
10
- <div class="text-base font-bold text-gray-700 leading-none">
11
- <%= @card.label %>
12
- </div>
13
- <div data-controller="select">
9
+ <div class="flex justify-between items-center">
10
+ <div class="text-sm font-bold text-gray-700 leading-none">
11
+ <%= @card.label %>
12
+ </div>
13
+ <div class="flex" data-controller="select">
14
14
  <% if @card.type.in?([:metric, :chartkick, :partial]) && @card.ranges.present? %>
15
15
  <%= select_tag "#{@card.id}_#{@card.index}_range", options_for_select(@card.ranges, @card.range),
16
- class: 'appearance-none inline-flex bg-blue-gray-100 disabled:bg-blue-gray-300 disabled:cursor-not-allowed focus:bg-white text-sm text-blue-gray-700 disabled:text-blue-gray-700 leading-none rounded-md py-px px-2 leading-tight border outline-none outline w-24',
16
+ class: 'appearance-none inline-flex bg-blue-gray-100 disabled:bg-blue-gray-300 disabled:cursor-not-allowed focus:bg-white text-xs text-blue-gray-700 disabled:text-blue-gray-700 leading-none rounded-md py-px px-2 border outline-none outline w-24',
17
17
  data: {
18
18
  target: 'select',
19
19
  action: 'change->select#onChange'
@@ -0,0 +1,16 @@
1
+ <%= content_tag(:div, class: "grid gap-4 grid-cols-1 #{parent.class.cards_classes}") do %>
2
+ <% parent.cards.each do |card| %>
3
+ <% if card.is_divider? %>
4
+ <%= render Avo::Dashboards::DividerComponent.new(divider: card) %>
5
+ <% elsif card.is_card? %>
6
+ <%= content_tag(:div, class: "relative bg-white rounded shadow-panel space-y-2 overflow-hidden h-full #{card.card_classes}") do %>
7
+ <turbo-frame id="<%= card.turbo_frame %>"
8
+ src="<%= card.frame_url(enforced_range: @range, params: params) %>"
9
+ data-card-index="<%= card.index %>"
10
+ >
11
+ <%= render(Avo::LoadingComponent.new(title: card.label)) %>
12
+ </turbo-frame>
13
+ <% end %>
14
+ <% end %>
15
+ <% end %>
16
+ <% end %>
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Avo::CardsListComponent < ViewComponent::Base
4
+ attr_reader :parent
5
+
6
+ def initialize(parent: nil)
7
+ @parent = parent
8
+ end
9
+
10
+ def render?
11
+ parent.cards.present?
12
+ end
13
+ end
@@ -7,43 +7,45 @@
7
7
 
8
8
  per_page_options = per_page_options.sort.uniq
9
9
  %>
10
- <div class="flex flex-col sm:flex-row items-center justify-between aborder-t aborder-slate-200 rounded-xl space-y-2 sm:space-y-0">
11
- <div class="flex-2 sm:flex sm:items-center sm:justify-between">
12
- <div>
13
- <div class="text-sm leading-5 text-slate-600 flex items-center">
14
- <div data-controller="per-page">
15
- <div class="flex items-center">
16
- <%= select_tag 'per_page',
17
- options_for_select(per_page_options, index_params[:per_page]),
18
- class: 'appearance-none inline-flex bg-white-100 disabled:bg-white-400 disabled:cursor-not-allowed focus:bg-white text-slate-700 disabled:text-slate-600 rounded-md py-1 px-2 leading-tight border border-slate-300 outline-none focus:border-slate-400 outline w-16 mr-1 text-sm',
19
- data: {
20
- 'turbo-frame': turbo_frame,
21
- 'per-page-target': 'selector',
22
- action: 'change->per-page#reload'
23
- }
24
- %> <%= t('avo.per_page').downcase %>
25
- </div>
26
- <% per_page_options.each do |option| %>
27
- <% if parent_model.present? %>
28
- <%= link_to "Change to #{option} items per page", helpers.related_resources_path(parent_model, parent_model, per_page: option, keep_query_params: true, page: 1), class: 'hidden', 'data-per-page-option': option, 'data-turbo-frame': turbo_frame %>
29
- <% else %>
30
- <%= link_to "Change to #{option} items per page", helpers.resources_path(resource: resource, per_page: option, keep_query_params: true, page: 1), class: 'hidden', 'data-per-page-option': option, 'data-turbo-frame': turbo_frame %>
10
+ <% unless @pagy.pages <= 1 && discreet_pagination %>
11
+ <div class="flex flex-col sm:flex-row items-center justify-between aborder-t aborder-slate-200 rounded-xl space-y-2 sm:space-y-0">
12
+ <div class="flex-2 sm:flex sm:items-center sm:justify-between">
13
+ <div>
14
+ <div class="text-sm leading-5 text-slate-600 flex items-center">
15
+ <div data-controller="per-page">
16
+ <div class="flex items-center">
17
+ <%= select_tag 'per_page',
18
+ options_for_select(per_page_options, index_params[:per_page]),
19
+ class: 'appearance-none inline-flex bg-white-100 disabled:bg-white-400 disabled:cursor-not-allowed focus:bg-white text-slate-700 disabled:text-slate-600 rounded-md py-1 px-2 leading-tight border border-slate-300 outline-none focus:border-slate-400 outline w-16 mr-1 text-sm',
20
+ data: {
21
+ 'turbo-frame': turbo_frame,
22
+ 'per-page-target': 'selector',
23
+ action: 'change->per-page#reload'
24
+ }
25
+ %> <%= t('avo.per_page').downcase %>
26
+ </div>
27
+ <% per_page_options.each do |option| %>
28
+ <% if parent_model.present? %>
29
+ <%= link_to "Change to #{option} items per page", helpers.related_resources_path(parent_model, parent_model, per_page: option, keep_query_params: true, page: 1), class: 'hidden', 'data-per-page-option': option, 'data-turbo-frame': turbo_frame %>
30
+ <% else %>
31
+ <%= link_to "Change to #{option} items per page", helpers.resources_path(resource: resource, per_page: option, keep_query_params: true, page: 1), class: 'hidden', 'data-per-page-option': option, 'data-turbo-frame': turbo_frame %>
32
+ <% end %>
31
33
  <% end %>
32
- <% end %>
34
+ </div>
33
35
  </div>
34
36
  </div>
35
37
  </div>
36
- </div>
37
- <div class="flex">
38
- <div class="flex-2 sm:flex sm:items-center sm:justify-between space-y-2 sm:space-y-0 text-center sm:text-left">
39
- <% if @pagy.count > 0 %>
40
- <div class="text-sm text-slate-600 mr-4"><%== helpers.pagy_info @pagy %></div>
41
- <% end %>
38
+ <div class="flex">
39
+ <div class="flex-2 sm:flex sm:items-center sm:justify-between space-y-2 sm:space-y-0 text-center sm:text-left">
40
+ <% if @pagy.count > 0 %>
41
+ <div class="text-sm text-slate-600 mr-4"><%== helpers.pagy_info @pagy %></div>
42
+ <% end %>
42
43
 
43
- <% if @pagy.pages > 1 %>
44
- <%# @todo: add first & last page. make the first and last buttons rounded %>
45
- <%== helpers.pagy_nav @pagy %>
46
- <% end %>
44
+ <% if @pagy.pages > 1 %>
45
+ <%# @todo: add first & last page. make the first and last buttons rounded %>
46
+ <%== helpers.pagy_nav @pagy %>
47
+ <% end %>
48
+ </div>
47
49
  </div>
48
50
  </div>
49
- </div>
51
+ <% end %>
@@ -6,12 +6,14 @@ class Avo::PaginatorComponent < ViewComponent::Base
6
6
  attr_reader :index_params
7
7
  attr_reader :resource
8
8
  attr_reader :parent_model
9
+ attr_reader :discreet_pagination
9
10
 
10
- def initialize(resource: nil, parent_model: nil, pagy: nil, turbo_frame: nil, index_params: nil)
11
+ def initialize(resource: nil, parent_model: nil, pagy: nil, turbo_frame: nil, index_params: nil, discreet_pagination: nil)
11
12
  @pagy = pagy
12
13
  @turbo_frame = turbo_frame
13
14
  @index_params = index_params
14
15
  @resource = resource
15
16
  @parent_model = parent_model
17
+ @discreet_pagination = discreet_pagination
16
18
  end
17
19
  end
@@ -1,5 +1,5 @@
1
1
  <div
2
- class="avo-sidebar fixed z-[60] t-0 application-sidebar w-64 flex-1 border-r lg:border-none bg-none h-[calc(100vh-4rem)] bg-gray-25 lg:bg-transparent <%= 'print:hidden' if Avo.configuration.hide_layout_when_printing %> <%= @sidebar_open ? 'flex' : 'hidden' %>"
2
+ class="avo-sidebar fixed z-[60] t-0 application-sidebar w-64 flex-1 border-r lg:border-none bg-none h-[calc(100vh-4rem)] bg-application lg:bg-transparent <%= 'print:hidden' if Avo.configuration.hide_layout_when_printing %> <%= @sidebar_open ? 'flex' : 'hidden' %>"
3
3
  data-sidebar-target="<%= stimulus_target %>"
4
4
  data-transition-enter="transition ease-out duration-100"
5
5
  data-transition-enter-start="transform opacity-0 -translate-x-full"
@@ -9,7 +9,7 @@
9
9
  data-transition-leave-end="transform opacity-0 -translate-x-full"
10
10
  >
11
11
  <div class="flex flex-col w-full h-full">
12
- <div class="flex-1 flex flex-col justify-between overflow-auto h-full pt-3 scroll-shadows">
12
+ <div class="flex-1 flex flex-col justify-between overflow-auto h-full pt-3 scroll-shadows mac-styled-scrollbar">
13
13
  <div class="space-y-6 mb-4">
14
14
  <%= render Avo::Sidebar::LinkComponent.new label: 'Get started', path: helpers.avo.root_path, active: :exclusive if Rails.env.development? && Avo.configuration.home_path.nil? %>
15
15
 
@@ -1,4 +1,4 @@
1
- <div class="flex" data-target="tab-switcher">
1
+ <div class="flex overflow-auto mac-styled-scrollbar" data-target="tab-switcher">
2
2
  <div class="button-group">
3
3
  <% visible_items.each do |tab| %>
4
4
  <%= a_link tab_path(tab),
@@ -35,6 +35,26 @@ class Avo::Views::ResourceEditComponent < Avo::ResourceComponent
35
35
  @resource.authorization.authorize_action @view, raise_exception: false
36
36
  end
37
37
 
38
+ def is_edit?
39
+ view == :edit
40
+ end
41
+
42
+ def form_url
43
+ if is_edit?
44
+ helpers.resource_path(
45
+ model: @resource.model,
46
+ resource: @resource
47
+ )
48
+ else
49
+ helpers.resources_path(
50
+ resource: @resource,
51
+ via_relation_class: params[:via_relation_class],
52
+ via_relation: params[:via_relation],
53
+ via_resource_id: params[:via_resource_id]
54
+ )
55
+ end
56
+ end
57
+
38
58
  private
39
59
 
40
60
  def via_index?
@@ -1,78 +1,126 @@
1
1
  <%= content_tag :div,
2
+ class: 'space-y-6',
2
3
  data: {
3
4
  **@resource.stimulus_data_attributes
4
5
  } do %>
5
- <%= render Avo::PanelComponent.new(title: title, description: description, data: { component: 'resources-index' }, display_breadcrumbs: @reflection.blank?) do |c| %>
6
- <% c.tools do %>
7
- <% if can_attach? %>
8
- <%= a_link attach_path,
6
+ <%= render Avo::CardsListComponent.new parent: @resource %>
7
+ <%= content_tag :div, class: "space-y-12" do %>
8
+ <%= render Avo::PanelComponent.new(title: title, description: description, data: { component: 'resources-index' }, display_breadcrumbs: @reflection.blank?) do |c| %>
9
+ <% c.tools do %>
10
+ <% if can_attach? %>
11
+ <%= a_link attach_path,
9
12
  icon: 'heroicons/outline/link',
10
13
  color: :primary,
11
14
  style: :text,
12
15
  'data-turbo-frame': 'attach_modal',
13
16
  'data-target': 'attach' do %>
14
- <%= t('avo.attach_item', item: singular_resource_name).capitalize %>
17
+ <%= t('avo.attach_item', item: singular_resource_name).capitalize %>
18
+ <% end %>
15
19
  <% end %>
16
- <% end %>
17
- <% if can_see_the_actions_button? %>
18
- <%= render Avo::ActionsComponent.new actions: @actions, resource: @resource, view: @view %>
19
- <% end %>
20
- <% if can_see_the_create_button? %>
21
- <%= a_link create_path,
20
+ <% if can_see_the_actions_button? %>
21
+ <%= render Avo::ActionsComponent.new actions: @actions, resource: @resource, view: @view %>
22
+ <% end %>
23
+ <% if can_see_the_create_button? %>
24
+ <%= a_link create_path,
22
25
  icon: 'heroicons/outline/plus',
23
26
  'data-target': 'create',
24
27
  style: :primary,
25
28
  color: :primary do %>
26
- <%= t('avo.create_new_item', item: singular_resource_name.downcase ) %>
29
+ <%= t('avo.create_new_item', item: singular_resource_name.downcase ) %>
30
+ <% end %>
27
31
  <% end %>
28
32
  <% end %>
29
- <% end %>
30
- <% c.body do %>
31
- <div class="flex flex-col xs:flex-row xs:justify-between space-y-2 xs:space-y-0 py-4 <%= 'hidden' if @resource.search_query.nil? && @filters.empty? && available_view_types.count <= 1 %>"
33
+ <% c.body do %>
34
+ <div class="flex flex-col xs:flex-row xs:justify-between space-y-2 xs:space-y-0 py-4 <%= 'hidden' if @resource.search_query.nil? && @filters.empty? && available_view_types.count <= 1 %>"
32
35
  data-selected-resources-name="<%= @resource.model_key %>"
33
36
  data-selected-resources="[]"
34
37
  >
35
- <% if @resource.search_query.present? %>
36
- <div class="flex items-center px-4 w-64">
37
- <%= render partial: 'avo/partials/resource_search', locals: {resource: @resource.route_key} %>
38
- </div>
39
- <% else %>
40
- <%# Offset for the space-y-2 property when the search is missing %>
41
- <div class="-mb-2"></div>
42
- <% end %>
43
- <% if @filters.present? || available_view_types.count > 1 %>
44
- <div class="justify-self-end flex justify-start xs:justify-end items-center px-4 space-x-3">
45
- <%= render Avo::FiltersComponent.new filters: @filters, resource: @resource, applied_filters: @applied_filters %>
46
- <%= render partial: 'avo/partials/view_toggle_button', locals: { available_view_types: available_view_types, view_type: view_type, turbo_frame: @turbo_frame } if available_view_types.count > 1 %>
47
- </div>
48
- <% end %>
49
- </div>
50
- <% if view_type.to_sym == :table %>
51
- <% if @resources.present? %>
52
- <div class="w-full overflow-auto flex flex-col mt-0">
53
- <div class="relative flex-1 flex">
54
- <%= render(Avo::Index::ResourceTableComponent.new(resources: @resources, resource: @resource, reflection: @reflection, parent_model: @parent_model, parent_resource: @parent_resource)) %>
38
+ <% if @resource.search_query.present? %>
39
+ <div class="flex items-center px-4 w-64">
40
+ <%= render partial: 'avo/partials/resource_search', locals: {resource: @resource.route_key} %>
55
41
  </div>
56
- </div>
57
- <% else %>
58
- <%= helpers.empty_state resource_name: @resource.name.downcase.pluralize, related_name: params[:related_name], view_type: view_type, add_background: true %>
42
+ <% else %>
43
+ <%# Offset for the space-y-2 property when the search is missing %>
44
+ <div class="-mb-2"></div>
45
+ <% end %>
46
+ <% if @filters.present? || available_view_types.count > 1 %>
47
+ <div class="justify-self-end flex justify-start xs:justify-end items-center px-4 space-x-3">
48
+ <%= render Avo::FiltersComponent.new filters: @filters, resource: @resource, applied_filters: @applied_filters %>
49
+ <%= render partial: 'avo/partials/view_toggle_button', locals: { available_view_types: available_view_types, view_type: view_type, turbo_frame: @turbo_frame } if available_view_types.count > 1 %>
50
+ </div>
51
+ <% end %>
52
+ </div>
53
+ <% if view_type.to_sym == :table %>
54
+ <% if @resources.present? %>
55
+ <div class="w-full overflow-auto flex flex-col mt-0 mac-styled-scrollbar">
56
+ <div class="relative flex-1 flex">
57
+ <%= render(Avo::Index::ResourceTableComponent.new(resources: @resources, resource: @resource, reflection: @reflection, parent_model: @parent_model, parent_resource: @parent_resource)) %>
58
+ </div>
59
+ </div>
60
+ <% else %>
61
+ <%= helpers.empty_state resource_name: @resource.name.downcase.pluralize, related_name: params[:related_name], view_type: view_type, add_background: true %>
62
+ <% end %>
59
63
  <% end %>
60
64
  <% end %>
61
- <% end %>
62
- <% c.bare_content do %>
63
- <% if view_type.to_sym == :table %>
64
- <% if @models.present? %>
65
- <div class="mt-4">
66
- <%= render Avo::PaginatorComponent.new pagy: @pagy, turbo_frame: @turbo_frame || 'none', index_params: @index_params, resource: @resource, parent_model: @parent_model %>
65
+ <% c.bare_content do %>
66
+ <% if view_type.to_sym == :table %>
67
+ <% if @models.present? %>
68
+ <div class="mt-4">
69
+ <%= render Avo::PaginatorComponent.new pagy: @pagy, turbo_frame: @turbo_frame || 'none', index_params: @index_params, resource: @resource, parent_model: @parent_model, discreet_pagination: field&.discreet_pagination %>
70
+ </div>
71
+ <% end %>
72
+ <% end %>
73
+ <% if view_type.to_sym == :grid %>
74
+ <%= render Avo::Index::ResourceGridComponent.new(resources: @resources, resource: @resource, reflection: @reflection, parent_model: @parent_model) %>
75
+ <div class="mt-6">
76
+ <%= render Avo::PaginatorComponent.new pagy: @pagy, turbo_frame: @turbo_frame || 'none', index_params: @index_params, resource: @resource, parent_model: @parent_model, discreet_pagination: field&.discreet_pagination %>
67
77
  </div>
78
+ <% if view_type.to_sym == :table %>
79
+ <% if @resources.present? %>
80
+ <div class="w-full overflow-auto flex flex-col mt-0">
81
+ <div class="relative flex-1 flex">
82
+ <%= render(Avo::Index::ResourceTableComponent.new(resources: @resources, resource: @resource, reflection: @reflection, parent_model: @parent_model)) %>
83
+ </div>
84
+ <% else %>
85
+ <%# Offset for the space-y-2 property when the serach is missing %>
86
+ <div class="-mb-2"></div>
87
+ <% end %>
88
+ <% if @filters.present? || available_view_types.count > 1 %>
89
+ <div class="justify-self-end flex justify-start xs:justify-end items-center px-4 space-x-3">
90
+ <%= render Avo::FiltersComponent.new filters: @filters, resource: @resource, applied_filters: @applied_filters %>
91
+ <%= render partial: 'avo/partials/view_toggle_button', locals: { available_view_types: available_view_types, view_type: view_type, turbo_frame: @turbo_frame } if available_view_types.count > 1 %>
92
+ </div>
93
+ <% end %>
94
+ </div>
95
+ <% if view_type.to_sym == :table %>
96
+ <% if @resources.present? %>
97
+ <div class="w-full overflow-auto flex flex-col mt-0">
98
+ <div class="relative flex-1 flex">
99
+ <%= render(Avo::Index::ResourceTableComponent.new(resources: @resources, resource: @resource, reflection: @reflection, parent_model: @parent_model)) %>
100
+ </div>
101
+ </div>
102
+ <% else %>
103
+ <%= helpers.empty_state resource_name: @resource.name.downcase.pluralize, related_name: params[:related_name], view_type: view_type, add_background: true %>
104
+ <% end %>
105
+ <% end %>
106
+ <% end %>
107
+ <% c.bare_content do %>
108
+ <% if view_type.to_sym == :table %>
109
+ <% if @models.present? %>
110
+ <div class="mt-4">
111
+ <%= render Avo::PaginatorComponent.new pagy: @pagy, turbo_frame: @turbo_frame || 'none', index_params: @index_params, resource: @resource, parent_model: @parent_model %>
112
+ </div>
113
+ <% end %>
114
+ <% end %>
115
+ <% if view_type.to_sym == :grid %>
116
+ <%= render Avo::Index::ResourceGridComponent.new(resources: @resources, resource: @resource, reflection: @reflection, parent_model: @parent_model) %>
117
+ <div class="mt-6">
118
+ <%= render Avo::PaginatorComponent.new pagy: @pagy, turbo_frame: @turbo_frame || 'none', index_params: @index_params, resource: @resource, parent_model: @parent_model %>
119
+ </div>
120
+ <% end %>
121
+ <% end %>
68
122
  <% end %>
69
123
  <% end %>
70
- <% if view_type.to_sym == :grid %>
71
- <%= render Avo::Index::ResourceGridComponent.new(resources: @resources, resource: @resource, reflection: @reflection, parent_model: @parent_model) %>
72
- <div class="mt-6">
73
- <%= render Avo::PaginatorComponent.new pagy: @pagy, turbo_frame: @turbo_frame || 'none', index_params: @index_params, resource: @resource, parent_model: @parent_model %>
74
- </div>
75
- <% end %>
76
124
  <% end %>
77
125
  <% end %>
78
126
  <% end %>
@@ -5,6 +5,11 @@
5
5
  selected_resources: [@resource.model.id],
6
6
  **@resource.stimulus_data_attributes
7
7
  } do %>
8
+ <% if @resource.cards.present? %>
9
+ <%= content_tag :div, class: "mb-6" do %>
10
+ <%= render Avo::CardsListComponent.new parent: @resource %>
11
+ <% end %>
12
+ <% end %>
8
13
  <%= render Avo::PanelComponent.new(title: title, description: @resource.resource_description, display_breadcrumbs: @reflection.blank?, index: 0, data: { panel_id: "main" }) do |c| %>
9
14
  <% c.tools do %>
10
15
  <% if @reflection.present? && @resource.model.present? %>
@@ -48,7 +53,6 @@
48
53
  data: {
49
54
  control: :destroy,
50
55
  'resource-id': @resource.model.id,
51
- 'tippy': 'tooltip',
52
56
  } do %>
53
57
  <%= t('avo.delete').capitalize %>
54
58
  <% end %>
@@ -77,10 +81,12 @@
77
81
  <% end %>
78
82
  <% end %>
79
83
  <% end %>
80
- <%= content_tag :div, class: 'space-y-12 mt-12' do %>
81
- <% @resource.get_items.each_with_index do |item, index| %>
82
- <% next if item.nil? %>
83
- <%= render Avo::ItemSwitcherComponent.new resource: @resource, reflection: @reflection, item: item, index: index + 1, view: @view %>
84
+ <% if @reflection.blank? %>
85
+ <%= content_tag :div, class: 'space-y-12 mt-12' do %>
86
+ <% @resource.get_items.each_with_index do |item, index| %>
87
+ <% next if item.nil? %>
88
+ <%= render Avo::ItemSwitcherComponent.new resource: @resource, reflection: @reflection, item: item, index: index + 1, view: @view %>
89
+ <% end %>
84
90
  <% end %>
85
91
  <% end %>
86
92
  <% if should_display_invalid_fields_errors? %>
@@ -118,7 +118,7 @@ module Avo
118
118
  def set_resource
119
119
  raise ActionController::RoutingError.new "No route matches" if resource.nil?
120
120
 
121
- @resource = resource.hydrate(params: params)
121
+ @resource = resource
122
122
  end
123
123
 
124
124
  def set_related_resource
@@ -126,6 +126,7 @@ module Avo
126
126
  end
127
127
 
128
128
  def set_model
129
+ puts ["controller_name->", controller_name].inspect
129
130
  @model = eager_load_files(@resource, @resource.class.find_scope).find params[:id]
130
131
  end
131
132
 
@@ -156,7 +157,7 @@ module Avo
156
157
  end
157
158
 
158
159
  def hydrate_resource
159
- @resource.hydrate(view: action_name.to_sym, user: _current_user)
160
+ @resource.hydrate(view: action_name.to_sym, user: _current_user, model: @model, params: params)
160
161
  end
161
162
 
162
163
  def hydrate_related_resource
@@ -6,8 +6,8 @@ module Avo
6
6
  before_action :set_related_resource_name
7
7
  before_action :set_related_resource, only: [:show, :index, :new, :create, :destroy, :order]
8
8
  before_action :set_reflection_field
9
- before_action :hydrate_related_resource, only: [:show, :index, :create, :destroy, :order]
10
9
  before_action :set_related_model, only: [:show, :order]
10
+ before_action :hydrate_related_resource, only: [:show, :index, :create, :destroy, :order]
11
11
  before_action :set_reflection
12
12
  before_action :set_attachment_class, only: [:show, :index, :new, :create, :destroy, :order]
13
13
  before_action :set_attachment_resource, only: [:show, :index, :new, :create, :destroy, :order]
@@ -7,6 +7,7 @@ module Avo
7
7
  before_action :hydrate_resource
8
8
  before_action :set_applied_filters, only: :index
9
9
  before_action :set_model, only: [:show, :edit, :destroy, :update, :order]
10
+ before_action :hydrate_resource
10
11
  before_action :set_model_to_fill
11
12
  before_action :set_edit_title_and_breadcrumbs, only: [:edit, :update]
12
13
  before_action :fill_model, only: [:create, :update]
@@ -100,7 +101,7 @@ module Avo
100
101
 
101
102
  def new
102
103
  @model = @resource.model_class.new
103
- @resource = @resource.hydrate(model: @model, view: :new, user: _current_user)
104
+ @resource = @resource.hydrate(model: @model, view: :new)
104
105
 
105
106
  set_actions
106
107
 
@@ -170,7 +171,7 @@ module Avo
170
171
  def update
171
172
  # model gets instantiated and filled in the fill_model method
172
173
  saved = save_model
173
- @resource = @resource.hydrate(model: @model, view: :edit, user: _current_user)
174
+ @resource = @resource.hydrate(model: @model, view: :edit)
174
175
 
175
176
  respond_to do |format|
176
177
  if saved
@@ -209,6 +210,9 @@ module Avo
209
210
  end
210
211
  end
211
212
 
213
+ def cards
214
+ end
215
+
212
216
  private
213
217
 
214
218
  def save_model
@@ -258,18 +262,19 @@ module Avo
258
262
  def cast_nullable(params)
259
263
  fields = @resource.get_field_definitions
260
264
 
261
- nullable_fields = fields.filter do |field|
262
- field.nullable
263
- end
265
+ nullable_fields = fields
266
+ .filter do |field|
267
+ field.nullable
268
+ end
264
269
  .map do |field|
265
- [field.id, field.null_values]
266
- end
270
+ [field.id, field.null_values]
271
+ end
267
272
  .to_h
268
273
 
269
274
  params.each do |key, value|
270
- nullable = nullable_fields[key.to_sym]
275
+ nullable_values = nullable_fields[key.to_sym]
271
276
 
272
- if nullable.present? && value.in?(nullable)
277
+ if nullable_values.present? && value.in?(nullable_values)
273
278
  params[key] = nil
274
279
  end
275
280
  end
@@ -375,7 +380,7 @@ module Avo
375
380
  end
376
381
 
377
382
  def set_edit_title_and_breadcrumbs
378
- @resource = @resource.hydrate(model: @model, view: :edit, user: _current_user)
383
+ @resource = @resource.hydrate(model: @model, view: :edit)
379
384
  @page_title = @resource.default_panel_name.to_s
380
385
 
381
386
  last_crumb_args = {}
@@ -2,7 +2,12 @@ require_dependency "avo/application_controller"
2
2
 
3
3
  module Avo
4
4
  class CardsController < ApplicationController
5
- before_action :set_dashboard, only: :show
5
+ before_action :set_dashboard
6
+ before_action :set_resource_name
7
+ before_action :set_resource, if: -> { @dashboard.blank? }
8
+ before_action :set_model, only: :show, if: -> { @resource.present? }
9
+ before_action :hydrate_resource, if: -> { @resource.present? }
10
+ before_action :set_parent, only: :show
6
11
  before_action :set_card, only: :show
7
12
 
8
13
  def show
@@ -10,15 +15,23 @@ module Avo
10
15
 
11
16
  private
12
17
 
18
+ def set_parent
19
+ @parent = @dashboard || @resource
20
+ end
21
+
13
22
  def set_dashboard
14
- @dashboard = Avo::App.get_dashboard_by_id params[:dashboard_id]
23
+ return if params[:dashboard_id].blank?
24
+
25
+ @dashboard_class = Avo::App.get_dashboard_by_id params[:dashboard_id]
26
+
27
+ raise ActionController::RoutingError.new("Not Found") if @dashboard_class.nil? || @dashboard_class.is_hidden?
15
28
 
16
- raise ActionController::RoutingError.new("Not Found") if @dashboard.nil? || @dashboard.is_hidden?
29
+ @dashboard = @dashboard_class.new
17
30
  end
18
31
 
19
32
  def set_card
20
- @card = @dashboard.item_at_index(params[:index].to_i).tap do |card|
21
- card.hydrate(dashboard: @dashboard, params: params)
33
+ @card = @parent.item_at_index(params[:index].to_i).tap do |card|
34
+ card.hydrate(parent: @parent, params: params)
22
35
  end
23
36
  end
24
37
  end