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

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 (45) 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/actions_component.html.erb +3 -3
  6. data/app/components/avo/actions_component.rb +12 -3
  7. data/app/components/avo/button_component.rb +1 -3
  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/panel_component.html.erb +1 -1
  11. data/app/components/avo/resource_component.rb +6 -4
  12. data/app/components/avo/sidebar_component.html.erb +1 -1
  13. data/app/components/avo/tab_switcher_component.html.erb +1 -1
  14. data/app/components/avo/views/resource_index_component.html.erb +3 -3
  15. data/app/components/avo/views/resource_show_component.html.erb +143 -52
  16. data/app/components/avo/views/resource_show_component.rb +1 -0
  17. data/app/controllers/avo/base_controller.rb +8 -7
  18. data/app/javascript/avo.js +1 -1
  19. data/app/javascript/js/controllers/fields/date_field_controller.js +7 -3
  20. data/app/views/avo/debug/report.html.erb +1 -0
  21. data/app/views/avo/private/design.html.erb +1 -1
  22. data/lib/avo/base_resource.rb +5 -1
  23. data/lib/avo/concerns/has_editable_controls.rb +34 -0
  24. data/lib/avo/fields/date_time_field.rb +2 -2
  25. data/lib/avo/fields/has_base_field.rb +2 -0
  26. data/lib/avo/licensing/pro_license.rb +1 -0
  27. data/lib/avo/resources/controls/action.rb +32 -0
  28. data/lib/avo/resources/controls/actions_list.rb +19 -0
  29. data/lib/avo/resources/controls/back_button.rb +13 -0
  30. data/lib/avo/resources/controls/base_control.rb +59 -0
  31. data/lib/avo/resources/controls/delete_button.rb +13 -0
  32. data/lib/avo/resources/controls/detach_button.rb +13 -0
  33. data/lib/avo/resources/controls/edit_button.rb +13 -0
  34. data/lib/avo/resources/controls/execution_context.rb +59 -0
  35. data/lib/avo/resources/controls/items_holder.rb +19 -0
  36. data/lib/avo/resources/controls/link_to.rb +27 -0
  37. data/lib/avo/version.rb +1 -1
  38. data/lib/generators/avo/templates/action.tt +1 -1
  39. data/lib/generators/avo/templates/resource_tools/partial.tt +1 -1
  40. data/lib/generators/avo/templates/standalone_action.tt +1 -1
  41. data/public/avo-assets/avo.css +602 -43
  42. data/public/avo-assets/avo.js +2 -2
  43. data/public/avo-assets/avo.js.map +2 -2
  44. metadata +14 -3
  45. data/lib/avo/concerns/has_model.rb +0 -11
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3d9e1f29fde441425a8bb70c8d3afc6f8acece76e6ac2a2dc2abc953567c6053
4
- data.tar.gz: 8f9a42b1f4084a1846f8b1a279dd15119323cacad40054709677ac980cb7387d
3
+ metadata.gz: 6322eef586c1cf132343d666fa513b2733699349d2945a86ddb2b37669cfcd1c
4
+ data.tar.gz: 5fb654449921d9fde5312adbeee074f96752445c34416ea4a6a22e6c5f9be9df
5
5
  SHA512:
6
- metadata.gz: 07e9b92e4bfa7031cb8ef415c64d886f10c4e83c7b2974485f9f891f99d56bf1176ae3d576c7e2f68a4a8b202f829ca53e0978d06b2fbf0620deef581567c79c
7
- data.tar.gz: 7700c610f99c0509b513a3180d420f28c82c403dfd4456867eb74e53178ac287d8c4d28a0c64c501b9923c0dbdc057d9940988fb222008024e836aabfb4c96ae
6
+ metadata.gz: 8c9ee8afe73d49806a42032b5c3f2b8c49a05763d44048e44c55ab4831d30c475ad2792cb6ad11ce5bd8ce296202c20173dd8bf274b05c64f6ac60174835953b
7
+ data.tar.gz: f22c15ebaaee96768cd5c38c2935a513410a32a5e46729b22c4c8375c1b7a229b4e3e733572f3fe47207229bae4775ce3a5510c528a532759c81b8b2b0b39fc7
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.1)
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
+ }
@@ -3,9 +3,9 @@
3
3
  data-actions-picker-enabled-class="text-black hover:bg-blue-500 hover:text-white"
4
4
  data-actions-picker-disabled-class="cursor-wait text-gray-500"
5
5
  >
6
- <%= a_button style: :outline,
6
+ <%= a_button style: @style,
7
7
  type: :button,
8
- color: :primary,
8
+ color: @color,
9
9
  class: "focus:outline-none",
10
10
  icon: 'arrow-circle-right',
11
11
  icon_class: 'transform rotate-90',
@@ -18,7 +18,7 @@
18
18
  data-toggle-panel-target="panel"
19
19
  >
20
20
  <div class="w-full space divide-y">
21
- <% @actions.each_with_index do |action, index| %>
21
+ <% actions.each_with_index do |action, index| %>
22
22
  <%= link_to action_path(action.param_id),
23
23
  data: {
24
24
  'turbo-frame': 'actions_show',
@@ -3,14 +3,23 @@
3
3
  class Avo::ActionsComponent < ViewComponent::Base
4
4
  include Avo::ApplicationHelper
5
5
 
6
- def initialize(actions: [], resource: nil, view: nil)
7
- @actions = actions
6
+ def initialize(actions: [], resource: nil, view: nil, exclude: [], style: :outline, color: :blue)
7
+ @actions = actions || []
8
8
  @resource = resource
9
9
  @view = view
10
+ @exclude = exclude
11
+ @color = color
12
+ @style = style
10
13
  end
11
14
 
12
15
  def render?
13
- @actions.present?
16
+ actions.present?
17
+ end
18
+
19
+ def actions
20
+ @actions.select do |action|
21
+ !action.class.in?(@exclude)
22
+ end
14
23
  end
15
24
 
16
25
  # When running an action for one record we should do it on a special path.
@@ -43,9 +43,7 @@ class Avo::ButtonComponent < ViewComponent::Base
43
43
  classes = "button-component inline-flex flex-grow-0 items-center font-semibold leading-6 fill-current whitespace-nowrap transition duration-100 transform transition duration-100 cursor-pointer disabled:cursor-not-allowed disabled:opacity-70 border justify-center active:outline active:outline-1 #{@class}"
44
44
 
45
45
  classes += " rounded" if @rounded.present?
46
-
47
46
  classes += style_classes
48
-
49
47
  classes += horizontal_padding_classes
50
48
  classes += vertical_padding_classes
51
49
  classes += text_size_classes
@@ -151,7 +149,7 @@ class Avo::ButtonComponent < ViewComponent::Base
151
149
  def style_classes
152
150
  case @style
153
151
  when :primary
154
- " bg-primary-500 text-white border-primary-500 hover:bg-primary-600 hover:border-primary-600 active:border-primary-700 active:outline-primary-700 active:bg-primary-600"
152
+ " bg-#{@color}-500 text-white border-#{@color}-500 hover:bg-#{@color}-600 hover:border-#{@color}-600 active:border-#{@color}-700 active:outline-#{@color}-700 active:bg-#{@color}-600"
155
153
  when :outline
156
154
  " bg-white text-#{@color}-500 border-#{@color}-500 hover:bg-#{@color}-100 active:bg-#{@color}-100 active:border-#{@color}-500 active:outline-#{@color}-500"
157
155
  when :text
@@ -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
@@ -17,7 +17,7 @@
17
17
  <% end %>
18
18
  </div>
19
19
  <% if tools.present? %>
20
- <div class="flex-1 w-full flex flex-col sm:flex-row xl:justify-end sm:items-end space-y-2 sm:space-y-0 sm:space-x-2 mt-4 xl:mt-0">
20
+ <div class="flex-1 w-full flex flex-wrap flex-col sm:flex-row xl:justify-end sm:items-end gap-2 mt-4 xl:mt-0" data-target="panel-controls">
21
21
  <%= tools %>
22
22
  </div>
23
23
  <% end %>
@@ -22,6 +22,12 @@ class Avo::ResourceComponent < Avo::BaseComponent
22
22
  authorize_association_for("detach")
23
23
  end
24
24
 
25
+ def detach_path
26
+ return "/" if @reflection.blank?
27
+
28
+ helpers.resource_detach_path(params[:resource_name], params[:id], @reflection.name.to_s, @resource.model.id)
29
+ end
30
+
25
31
  def can_see_the_edit_button?
26
32
  @resource.authorization.authorize_action(:edit, raise_exception: false)
27
33
  end
@@ -30,10 +36,6 @@ class Avo::ResourceComponent < Avo::BaseComponent
30
36
  @resource.authorization.authorize_action(:destroy, raise_exception: false)
31
37
  end
32
38
 
33
- def detach_path
34
- helpers.resource_detach_path(params[:resource_name], params[:id], @reflection.name.to_s, @resource.model.id)
35
- end
36
-
37
39
  def destroy_path
38
40
  helpers.resource_path(model: @resource.model, resource: @resource)
39
41
  end
@@ -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),
@@ -49,7 +49,7 @@
49
49
  </div>
50
50
  <% if view_type.to_sym == :table %>
51
51
  <% if @resources.present? %>
52
- <div class="w-full overflow-auto flex flex-col mt-0">
52
+ <div class="w-full overflow-auto flex flex-col mt-0 mac-styled-scrollbar">
53
53
  <div class="relative flex-1 flex">
54
54
  <%= render(Avo::Index::ResourceTableComponent.new(resources: @resources, resource: @resource, reflection: @reflection, parent_model: @parent_model, parent_resource: @parent_resource)) %>
55
55
  </div>
@@ -63,14 +63,14 @@
63
63
  <% if view_type.to_sym == :table %>
64
64
  <% if @models.present? %>
65
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 %>
66
+ <%= 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
67
  </div>
68
68
  <% end %>
69
69
  <% end %>
70
70
  <% if view_type.to_sym == :grid %>
71
71
  <%= render Avo::Index::ResourceGridComponent.new(resources: @resources, resource: @resource, reflection: @reflection, parent_model: @parent_model) %>
72
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 %>
73
+ <%= 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 %>
74
74
  </div>
75
75
  <% end %>
76
76
  <% end %>
@@ -7,59 +7,148 @@
7
7
  } do %>
8
8
  <%= render Avo::PanelComponent.new(title: title, description: @resource.resource_description, display_breadcrumbs: @reflection.blank?, index: 0, data: { panel_id: "main" }) do |c| %>
9
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 %>
21
- <% end %>
22
- <% end %>
23
- <%= render Avo::ActionsComponent.new actions: @actions, resource: @resource, view: @view %>
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 %>
10
+ <% if @resource.has_show_controls? %>
11
+ <% @resource.render_show_controls.each do |control| %>
12
+ <% if control.back_button? %>
13
+ <%= a_link back_path,
14
+ style: :text,
15
+ title: control.title,
16
+ data: {
17
+ tippy: control.title ? :tooltip : nil,
18
+ },
19
+ icon: 'arrow-left' do %>
20
+ <%= control.label %>
21
+ <% end %>
22
+ <% elsif control.delete_button? %>
23
+ <% if can_see_the_destroy_button? %>
24
+ <% end %>
25
+ <%= a_button url: helpers.resource_path(model: @resource.model, resource: @resource),
26
+ method: :delete,
27
+ local: true,
28
+ style: :text,
29
+ loading: true,
30
+ confirm: t('avo.are_you_sure', item: @resource.model.model_name.name.downcase),
31
+ color: :red,
32
+ icon: 'trash',
33
+ form_class: 'flex flex-col sm:flex-row sm:inline-flex',
34
+ title: control.title,
35
+ data: {
36
+ control: :destroy,
37
+ tippy: control.title ? :tooltip : nil,
38
+ 'resource-id': @resource.model.id,
39
+ } do %>
40
+ <% end %>
41
+ <% elsif control.actions_list? %>
42
+ <%= render Avo::ActionsComponent.new actions: @actions, resource: @resource, view: @view, exclude: control.exclude, style: control.style, color: control.color %>
43
+ <% elsif control.edit_button? %>
44
+ <% if @resource.authorization.authorize_action(:edit, raise_exception: false) %>
45
+ <% end %>
46
+ <%= a_link edit_path,
47
+ color: :primary,
48
+ style: :primary,
49
+ title: control.title,
50
+ data: {
51
+ tippy: control.title ? :tooltip : nil,
52
+ },
53
+ icon: 'edit' do %>
54
+ <%= control.label %>
55
+ <% end %>
56
+ <% elsif control.action? %>
57
+ <%= a_link control.path,
58
+ color: control.color,
59
+ style: control.style,
60
+ icon: control.icon,
61
+ title: control.title,
62
+ data: {
63
+ tippy: control.title ? :tooltip : nil,
64
+ 'turbo-frame': 'actions_show',
65
+ 'action': 'click->actions-picker#visitAction',
66
+ } do %>
67
+ <%= control.label %>
68
+ <% end %>
69
+ <% elsif control.link_to? %>
70
+ <%= a_link control.path,
71
+ color: control.color,
72
+ style: control.style,
73
+ icon: control.icon,
74
+ title: control.title,
75
+ target: control.target,
76
+ class: control.class,
77
+ data: {
78
+ **control.data,
79
+ tippy: control.title ? :tooltip : nil,
80
+ } do %>
81
+ <%= control.label %>
82
+ <% end %>
83
+ <% elsif control.detach_button? %>
84
+ <% if @reflection.present? && @resource.model.present? && can_detach? %>
85
+ <%= a_button url: detach_path,
86
+ icon: 'detach',
87
+ method: :delete,
88
+ form_class: 'flex flex-col sm:flex-row sm:inline-flex',
89
+ style: :text,
90
+ data: {
91
+ confirm: "Are you sure you want to detach this #{title}."
92
+ } do %>
93
+ <%= t('avo.detach_item', item: title).capitalize %>
94
+ <% end %>
95
+ <% end %>
30
96
  <% end %>
31
97
  <% end %>
32
98
  <% 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,
99
+ <% if @reflection.present? && @resource.model.present? %>
100
+ <% if can_detach? %>
101
+ <%= a_button url: detach_path,
102
+ icon: 'detach',
103
+ method: :delete,
104
+ form_class: 'flex flex-col sm:flex-row sm:inline-flex',
105
+ style: :text,
106
+ data: {
107
+ confirm: "Are you sure you want to detach this #{title}."
108
+ } do %>
109
+ <%= t('avo.detach_item', item: title).capitalize %>
110
+ <% end %>
111
+ <% end %>
112
+ <%= render Avo::ActionsComponent.new actions: @actions, resource: @resource, view: @view %>
113
+ <% if can_see_the_edit_button? %>
114
+ <%= a_link edit_path,
115
+ color: :primary,
116
+ style: :primary,
117
+ icon: 'edit' do %>
118
+ <%= t('avo.edit').capitalize %>
119
+ <% end %>
120
+ <% end %>
121
+ <% else %>
122
+ <%= a_link back_path,
42
123
  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 %>
124
+ icon: 'arrow-left' do %>
125
+ <%= t('avo.go_back') %>
54
126
  <% 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 %>
127
+ <% if can_see_the_destroy_button? %>
128
+ <%= a_button url: helpers.resource_path(model: @resource.model, resource: @resource),
129
+ method: :delete,
130
+ local: true,
131
+ style: :text,
132
+ loading: true,
133
+ confirm: t('avo.are_you_sure', item: @resource.model.model_name.name.downcase),
134
+ color: :red,
135
+ icon: 'trash',
136
+ form_class: 'flex flex-col sm:flex-row sm:inline-flex',
137
+ data: {
138
+ control: :destroy,
139
+ 'resource-id': @resource.model.id,
140
+ } do %>
141
+ <%= t('avo.delete').capitalize %>
142
+ <% end %>
143
+ <% end %>
144
+ <%= render Avo::ActionsComponent.new actions: @actions, resource: @resource, view: @view %>
145
+ <% if @resource.authorization.authorize_action(:edit, raise_exception: false) %>
146
+ <%= a_link edit_path,
147
+ color: :primary,
148
+ style: :primary,
149
+ icon: 'edit' do %>
150
+ <%= t('avo.edit').capitalize %>
151
+ <% end %>
63
152
  <% end %>
64
153
  <% end %>
65
154
  <% end %>
@@ -77,10 +166,12 @@
77
166
  <% end %>
78
167
  <% end %>
79
168
  <% 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 %>
169
+ <% if @reflection.blank? %>
170
+ <%= content_tag :div, class: 'space-y-12 mt-12' do %>
171
+ <% @resource.get_items.each_with_index do |item, index| %>
172
+ <% next if item.nil? %>
173
+ <%= render Avo::ItemSwitcherComponent.new resource: @resource, reflection: @reflection, item: item, index: index + 1, view: @view %>
174
+ <% end %>
84
175
  <% end %>
85
176
  <% end %>
86
177
  <% if should_display_invalid_fields_errors? %>
@@ -17,6 +17,7 @@ class Avo::Views::ResourceShowComponent < Avo::ResourceComponent
17
17
  def title
18
18
  if @reflection.present?
19
19
  return field.name if has_one_field?
20
+
20
21
  reflection_resource.name
21
22
  else
22
23
  @resource.default_panel_name
@@ -258,18 +258,19 @@ module Avo
258
258
  def cast_nullable(params)
259
259
  fields = @resource.get_field_definitions
260
260
 
261
- nullable_fields = fields.filter do |field|
262
- field.nullable
263
- end
261
+ nullable_fields = fields
262
+ .filter do |field|
263
+ field.nullable
264
+ end
264
265
  .map do |field|
265
- [field.id, field.null_values]
266
- end
266
+ [field.id, field.null_values]
267
+ end
267
268
  .to_h
268
269
 
269
270
  params.each do |key, value|
270
- nullable = nullable_fields[key.to_sym]
271
+ nullable_values = nullable_fields[key.to_sym]
271
272
 
272
- if nullable.present? && value.in?(nullable)
273
+ if nullable_values.present? && value.in?(nullable_values)
273
274
  params[key] = nil
274
275
  end
275
276
  end
@@ -29,7 +29,7 @@ Mousetrap.bind('r r r', () => {
29
29
  function isMac() {
30
30
  const isMac = window.navigator.userAgent.indexOf('Mac OS X')
31
31
 
32
- if (isMac) {
32
+ if (isMac >= 0) {
33
33
  document.body.classList.add('os-mac')
34
34
  document.body.classList.remove('os-pc')
35
35
  } else {
@@ -106,13 +106,10 @@ export default class extends Controller {
106
106
 
107
107
  // enable timezone display
108
108
  if (this.enableTimeValue) {
109
- console.log(1)
110
109
  options.defaultDate = this.parsedValue.setZone(this.displayTimezone).toISO()
111
110
 
112
111
  options.dateFormat = 'Y-m-d H:i:S'
113
112
  } else {
114
- console.log(2)
115
-
116
113
  // Because the browser treats the date like a timestamp and updates it at 00:00 hour, when on a western timezone the date will be converted with one day offset.
117
114
  // Ex: 2022-01-30 will render as 2022-01-29 on an American timezone
118
115
  options.defaultDate = universalTimestamp(this.initialValue)
@@ -124,6 +121,13 @@ export default class extends Controller {
124
121
  }
125
122
 
126
123
  onChange(selectedDates) {
124
+ // No date has been selected
125
+ if (selectedDates.length === 0) {
126
+ this.updateRealInput('')
127
+
128
+ return
129
+ }
130
+
127
131
  let time
128
132
  let args = {}
129
133
 
@@ -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,7 +1,7 @@
1
1
  <div class="flex flex-col">
2
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| %>
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
 
@@ -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