avo 1.23.0 → 1.24.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 (36) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -0
  3. data/Gemfile.lock +6 -1
  4. data/app/assets/svgs/arrow-down.svg +3 -0
  5. data/app/assets/svgs/arrow-up.svg +3 -0
  6. data/app/assets/svgs/download-solid-reversed.svg +3 -0
  7. data/app/assets/svgs/download-solid.svg +3 -0
  8. data/app/assets/svgs/switch-vertical.svg +3 -0
  9. data/app/components/avo/base_component.rb +35 -0
  10. data/app/components/avo/index/grid_item_component.html.erb +1 -1
  11. data/app/components/avo/index/ordering/base_component.rb +9 -0
  12. data/app/components/avo/index/ordering/button_component.html.erb +11 -0
  13. data/app/components/avo/index/ordering/button_component.rb +37 -0
  14. data/app/components/avo/index/ordering/buttons_component.html.erb +32 -0
  15. data/app/components/avo/index/ordering/buttons_component.rb +45 -0
  16. data/app/components/avo/index/resource_controls_component.html.erb +9 -4
  17. data/app/components/avo/index/resource_controls_component.rb +2 -1
  18. data/app/components/avo/index/table_row_component.html.erb +1 -1
  19. data/app/components/avo/resource_component.rb +1 -22
  20. data/app/components/avo/turbo_frame_wrapper_component.html.erb +3 -1
  21. data/app/controllers/avo/application_controller.rb +7 -1
  22. data/app/controllers/avo/base_controller.rb +16 -1
  23. data/app/controllers/avo/relations_controller.rb +15 -8
  24. data/app/helpers/avo/url_helpers.rb +4 -0
  25. data/app/javascript/js/application.js +4 -0
  26. data/avo.gemspec +1 -0
  27. data/config/routes.rb +4 -0
  28. data/lib/avo/base_resource.rb +13 -0
  29. data/lib/avo/hosts/ordering.rb +22 -0
  30. data/lib/avo/licensing/pro_license.rb +1 -0
  31. data/lib/avo/version.rb +1 -1
  32. data/lib/generators/avo/templates/locales/avo.en.yml +6 -0
  33. data/public/avo-assets/avo.css +4 -0
  34. data/public/avo-assets/avo.js +7633 -7374
  35. data/public/avo-assets/avo.js.map +3 -3
  36. metadata +28 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 93ddc5b52a7eb149886833f2eda8dcf69e5cfa29af5d357f57dfbc3b6e03800e
4
- data.tar.gz: 44050a09443ff49550f7d9e3c22c3a4b03eea83f9c0d3a08bbc4a97d5084a355
3
+ metadata.gz: 4990a8b947c8086e635f9a4efedf7b58692ffbeebcd7bbc5ee002f8526a0e1fc
4
+ data.tar.gz: 80f48c2eaf8dbe17271afbb64dfb07e3c7b2710371dd049d293981ed0ddf2cb3
5
5
  SHA512:
6
- metadata.gz: 346e58ffb98b4b60576282f43a766f6e9e388dcf83041dffc8b1f9c1e81292271869e2f356df92471afa77e51eff5945f127a236e2adc1c41a24ccb6847d2a5f
7
- data.tar.gz: 5dbeae53b1d1179117f035c1bc2b806c9f88064f5af9c9c1498fbd6fe24107d96a67c02345f437f2cd73789de4935932c97f52730142e970808a68e49c5e2aa0
6
+ metadata.gz: 53cdb462a0b8dbb76060ab440760115b309c05d16dbbde23108811b1b369eeb4a59763d908ff4f5466fe15596f35427817443c146994d9c4466cb2955cdbb6e0
7
+ data.tar.gz: 83afde6824181a8354d20fb8d9197734abc3d162200625731a47f2adf17501f43f1d08abf897f3e60fbe01960893d2ad71ef2ba4fee540b2c4f943859199eb2a
data/Gemfile CHANGED
@@ -133,3 +133,5 @@ gem 'friendly_id', '~> 5.4.0'
133
133
  gem 'aws-sdk-s3', require: false
134
134
 
135
135
  gem 'net-smtp', require: false
136
+
137
+ gem 'acts_as_list'
data/Gemfile.lock CHANGED
@@ -1,11 +1,12 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- avo (1.23.0)
4
+ avo (1.24.2)
5
5
  active_link_to
6
6
  addressable
7
7
  breadcrumbs_on_rails
8
8
  countries
9
+ dry-initializer
9
10
  hotwire-rails
10
11
  httparty
11
12
  image_processing
@@ -81,6 +82,8 @@ GEM
81
82
  minitest (>= 5.1)
82
83
  tzinfo (~> 2.0)
83
84
  zeitwerk (~> 2.3)
85
+ acts_as_list (1.0.4)
86
+ activerecord (>= 4.2)
84
87
  addressable (2.8.0)
85
88
  public_suffix (>= 2.0.2, < 5.0)
86
89
  ap (0.1.1)
@@ -153,6 +156,7 @@ GEM
153
156
  dotenv-rails (2.7.6)
154
157
  dotenv (= 2.7.6)
155
158
  railties (>= 3.2)
159
+ dry-initializer (3.1.1)
156
160
  erubi (1.10.0)
157
161
  factory_bot (6.2.0)
158
162
  activesupport (>= 5.0.0)
@@ -397,6 +401,7 @@ PLATFORMS
397
401
 
398
402
  DEPENDENCIES
399
403
  active_link_to
404
+ acts_as_list
400
405
  addressable
401
406
  ap
402
407
  appraisal
@@ -0,0 +1,3 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
2
+ <path stroke-linecap="round" stroke-linejoin="round" d="M19 14l-7 7m0 0l-7-7m7 7V3" />
3
+ </svg>
@@ -0,0 +1,3 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
2
+ <path stroke-linecap="round" stroke-linejoin="round" d="M5 10l7-7m0 0l7 7m-7-7v18" />
3
+ </svg>
@@ -0,0 +1,3 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor" transform="rotate(-180)">
2
+ <path fill-rule="evenodd" d="M3 17a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zm3.293-7.707a1 1 0 011.414 0L9 10.586V3a1 1 0 112 0v7.586l1.293-1.293a1 1 0 111.414 1.414l-3 3a1 1 0 01-1.414 0l-3-3a1 1 0 010-1.414z" clip-rule="evenodd" />
3
+ </svg>
@@ -0,0 +1,3 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
2
+ <path fill-rule="evenodd" d="M3 17a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zm3.293-7.707a1 1 0 011.414 0L9 10.586V3a1 1 0 112 0v7.586l1.293-1.293a1 1 0 111.414 1.414l-3 3a1 1 0 01-1.414 0l-3-3a1 1 0 010-1.414z" clip-rule="evenodd" />
3
+ </svg>
@@ -0,0 +1,3 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
2
+ <path stroke-linecap="round" stroke-linejoin="round" d="M7 16V4m0 0L3 8m4-4l4 4m6 0v12m0 0l4-4m-4 4l-4-4" />
3
+ </svg>
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Avo::BaseComponent < ViewComponent::Base
4
+ def has_with_trial(ability)
5
+ ::Avo::App.license.has_with_trial(ability)
6
+ end
7
+
8
+ private
9
+
10
+ # Figure out what is the corresponding field for this @reflection
11
+ def field
12
+ fields = ::Avo::App.get_resource_by_model_name(@reflection.active_record.name).get_field_definitions
13
+ fields.find { |f| f.id == @reflection.name }
14
+ rescue
15
+ nil
16
+ end
17
+
18
+ def relation_resource
19
+ ::Avo::App.get_resource_by_model_name params[:via_resource_class].safe_constantize
20
+ end
21
+
22
+ # Get the resource for the resource using the klass attribute so we get the namespace too
23
+ def reflection_resource
24
+ ::Avo::App.get_resource_by_model_name(@reflection.klass.to_s)
25
+ rescue
26
+ nil
27
+ end
28
+
29
+ # Get the resource for the resource using the klass attribute so we get the namespace too
30
+ def reflection_parent_resource
31
+ ::Avo::App.get_resource_by_model_name(@reflection.active_record.to_s)
32
+ rescue
33
+ nil
34
+ end
35
+ end
@@ -32,7 +32,7 @@
32
32
  </div>
33
33
  </div>
34
34
  <div class="w-full place-self-end">
35
- <%= render(Avo::Index::ResourceControlsComponent.new(resource: @resource, reflection: @reflection, parent_model: @parent_model)) %>
35
+ <%= render(Avo::Index::ResourceControlsComponent.new(resource: @resource, reflection: @reflection, parent_model: @parent_model, view_type: :grid)) %>
36
36
  </div>
37
37
  </div>
38
38
  </div>
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Avo::Index::Ordering::BaseComponent < Avo::BaseComponent
4
+ private
5
+
6
+ def order_actions
7
+ @resource.class.order_actions
8
+ end
9
+ end
@@ -0,0 +1,11 @@
1
+ <%= button_to order_path(direction: direction, referrer: request.fullpath),
2
+ title: t("avo.order.#{direction}").capitalize,
3
+ method: :patch,
4
+ class: 'flex items-center',
5
+ data: {
6
+ target: "order:#{direction}",
7
+ 'turbo-frame': params[:turbo_frame],
8
+ 'tippy': 'tooltip',
9
+ } do %>
10
+ <%= helpers.svg(svg, class: 'text-gray-400 h-6 hover:text-gray-600') %>
11
+ <% end %>
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Avo::Index::Ordering::ButtonComponent < Avo::Index::Ordering::BaseComponent
4
+ attr_accessor :resource
5
+ attr_accessor :reflection
6
+ attr_accessor :direction
7
+ attr_accessor :svg
8
+
9
+ def initialize(resource:, direction:, svg: nil, reflection: nil)
10
+ @resource = resource
11
+ @reflection = reflection
12
+ @direction = direction
13
+ @svg = svg
14
+ end
15
+
16
+ def render?
17
+ order_actions[direction].present?
18
+ end
19
+
20
+ def order_path(args)
21
+ if reflection.present?
22
+ path = "#{::Avo::App.root_path}/resources/#{reflection_parent_resource.route_key}/#{params[:id]}/#{field.id}/#{resource.model.id}/order"
23
+ else
24
+ path = "#{::Avo::App.root_path}/resources/#{resource.route_key}/#{resource.model.id}/order"
25
+ end
26
+
27
+ if args.present?
28
+ string_args = args.map do |key, value|
29
+ "#{key}=#{value}"
30
+ end.join('&')
31
+
32
+ path = "#{path}?#{string_args}"
33
+ end
34
+
35
+ path
36
+ end
37
+ end
@@ -0,0 +1,32 @@
1
+ <div class="flex items-center justify-center">
2
+ <% if display_inline? %>
3
+ <div class="flex max-w-xs rounded">
4
+ <%= render Avo::Index::Ordering::ButtonComponent.new resource: @resource, reflection: @reflection, direction: :higher, svg: 'arrow-up' %>
5
+ <%= render Avo::Index::Ordering::ButtonComponent.new resource: @resource, reflection: @reflection, direction: :lower, svg: 'arrow-down' %>
6
+ <%= render Avo::Index::Ordering::ButtonComponent.new resource: @resource, reflection: @reflection, direction: :to_top, svg: 'download-solid-reversed' %>
7
+ <%= render Avo::Index::Ordering::ButtonComponent.new resource: @resource, reflection: @reflection, direction: :to_bottom, svg: 'download-solid' %>
8
+ </div>
9
+ <% else %>
10
+ <div class="popover inline-block"
11
+ data-controller="popover"
12
+ data-popover-translate-x="-100%"
13
+ data-popover-translate-y="-32px"
14
+ data-action="mouseover->popover#mouseOver mouseout->popover#mouseOut"
15
+ >
16
+ <%= button_tag nil,
17
+ title: t('avo.order.reorder_record').capitalize,
18
+ class: 'flex items-center',
19
+ data: {
20
+ 'tippy': 'tooltip',
21
+ } do
22
+ %>
23
+ <%= helpers.svg('switch-vertical', class: 'text-gray-400 h-6 hover:text-gray-600') %>
24
+ <% end %>
25
+ <div class="flex hidden absolute max-w-xs bg-white rounded p-2 z-40" data-popover-target="content">
26
+ <%= render Avo::Index::Ordering::ButtonComponent.new resource: @resource, reflection: @reflection, direction: :higher, svg: 'arrow-up' %>
27
+ <%= render Avo::Index::Ordering::ButtonComponent.new resource: @resource, reflection: @reflection, direction: :lower, svg: 'arrow-down' %>
28
+ <%= render Avo::Index::Ordering::ButtonComponent.new resource: @resource, reflection: @reflection, direction: :to_top, svg: 'download-solid-reversed' %>
29
+ <%= render Avo::Index::Ordering::ButtonComponent.new resource: @resource, reflection: @reflection, direction: :to_bottom, svg: 'download-solid' %>
30
+ </div>
31
+ <% end %>
32
+ </div>
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Avo::Index::Ordering::ButtonsComponent < Avo::Index::Ordering::BaseComponent
4
+ def initialize(resource: nil, reflection: nil, view_type: nil)
5
+ @resource = resource
6
+ @reflection = reflection
7
+ @view_type = view_type
8
+ end
9
+
10
+ def render?
11
+ has_with_trial(:resource_ordering) && can_order_any? && view_type_is_table? && enabled_in_view?
12
+ end
13
+
14
+ private
15
+
16
+ def can_order_any?
17
+ order_actions.present?
18
+ end
19
+
20
+ def view_type_is_table?
21
+ @view_type.to_sym == :table
22
+ end
23
+
24
+ def display_inline?
25
+ ordering[:display_inline]
26
+ end
27
+
28
+ def enabled_in_view?
29
+ in_association = @reflection.present?
30
+
31
+ if in_association
32
+ visible_on_option.include? :association
33
+ else
34
+ visible_on_option.include? :index
35
+ end
36
+ end
37
+
38
+ def visible_on_option
39
+ [ordering[:visible_on]].flatten
40
+ end
41
+
42
+ def ordering
43
+ @resource.class.ordering
44
+ end
45
+ end
@@ -1,14 +1,16 @@
1
- <div class="space-x-2 flex flex-row justify-around w-full">
1
+ <div class="space-x-2 flex flex-row justify-around items-center w-full">
2
+ <%= render Avo::Index::Ordering::ButtonsComponent.new resource: @resource, reflection: @reflection, view_type: @view_type %>
3
+
2
4
  <% if can_view? %>
3
5
  <%= link_to helpers.svg('eye', class: 'text-gray-400 h-6 hover:text-gray-600'),
4
6
  show_path,
5
- title: t('avo.view_item', item: singular_resource_name).capitalize,
7
+ title: t('avo.view_item', item: singular_resource_name).capitalize,
6
8
  data: {
7
9
  target: 'control:view',
8
10
  control: :show,
9
11
  'tippy': 'tooltip',
10
12
  }
11
- %>
13
+ %>
12
14
  <% end %>
13
15
 
14
16
  <% if can_edit? %>
@@ -45,7 +47,10 @@
45
47
  <% end %>
46
48
 
47
49
  <% if can_delete? %>
48
- <%= form_with url: helpers.resource_path(model: @resource.model, resource: @resource), method: :delete, html: {
50
+ <%= form_with url: helpers.resource_path(model: @resource.model, resource: @resource),
51
+ method: :delete,
52
+ class: 'flex items-center',
53
+ html: {
49
54
  'data-turbo-frame': params[:turbo_frame]
50
55
  } do |form| %>
51
56
  <%= form.button helpers.svg('trash', class: 'text-gray-400 h-6 hover:text-gray-600'),
@@ -1,10 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Avo::Index::ResourceControlsComponent < Avo::ResourceComponent
4
- def initialize(resource: nil, reflection: nil, parent_model: nil)
4
+ def initialize(resource: nil, reflection: nil, parent_model: nil, view_type: :table)
5
5
  @resource = resource
6
6
  @reflection = reflection
7
7
  @parent_model = parent_model
8
+ @view_type = view_type
8
9
  end
9
10
 
10
11
  def can_detach?
@@ -12,7 +12,7 @@
12
12
  <% end %>
13
13
  <td class="text-right whitespace-nowrap px-2">
14
14
  <div class="flex items-center justify-end flex-grow-0 h-full w-full">
15
- <%= render(Avo::Index::ResourceControlsComponent.new(resource: @resource, reflection: @reflection, parent_model: @parent_model)) %>
15
+ <%= render(Avo::Index::ResourceControlsComponent.new(resource: @resource, reflection: @reflection, parent_model: @parent_model, view_type: :table)) %>
16
16
  </div>
17
17
  </td>
18
18
  </tr>
@@ -1,4 +1,4 @@
1
- class Avo::ResourceComponent < ViewComponent::Base
1
+ class Avo::ResourceComponent < Avo::BaseComponent
2
2
  def can_create?
3
3
  return authorize_association_for(:create) if @reflection.present?
4
4
 
@@ -30,25 +30,4 @@ class Avo::ResourceComponent < ViewComponent::Base
30
30
 
31
31
  association_policy
32
32
  end
33
-
34
- private
35
-
36
- # Figure out what is the corresponding field for this @reflection
37
- def field
38
- fields = ::Avo::App.get_resource_by_model_name(@reflection.active_record.name).get_field_definitions
39
- fields.find { |f| f.id == @reflection.name }
40
- rescue
41
- nil
42
- end
43
-
44
- def relation_resource
45
- ::Avo::App.get_resource_by_model_name params[:via_resource_class].safe_constantize
46
- end
47
-
48
- # Get the resource for the resource using the klass attribute so we get the namespace too
49
- def reflection_resource
50
- ::Avo::App.get_resource_by_model_name(@reflection.klass.to_s)
51
- rescue
52
- nil
53
- end
54
33
  end
@@ -3,7 +3,9 @@
3
3
  # When rendering the frames the flashed content gets lost.
4
4
  # By including the alerts partial, the stimulus will pick them up and display them to the user.
5
5
  %>
6
- <%= render Avo::AlertsComponent.new if helpers.flash.present? && name.present? %>
6
+ <% if helpers.turbo_frame_request? %>
7
+ <%= render Avo::AlertsComponent.new if helpers.flash.present? && name.present? %>
8
+ <% end %>
7
9
 
8
10
  <%= content %>
9
11
  <% if name.present? %></turbo-frame><% end %>
@@ -24,7 +24,7 @@ module Avo
24
24
  rescue_from Pundit::NotAuthorizedError, with: :render_unauthorized
25
25
  rescue_from ActiveRecord::RecordInvalid, with: :exception_logger
26
26
 
27
- helper_method :_current_user, :resources_path, :resource_path, :new_resource_path, :edit_resource_path, :resource_attach_path, :resource_detach_path, :related_resources_path
27
+ helper_method :_current_user, :resources_path, :resource_path, :new_resource_path, :edit_resource_path, :resource_attach_path, :resource_detach_path, :related_resources_path, :turbo_frame_request?
28
28
  add_flash_types :info, :warning, :success, :error
29
29
 
30
30
  def init_app
@@ -79,6 +79,12 @@ module Avo
79
79
  instance_eval(&Avo.configuration.context)
80
80
  end
81
81
 
82
+ # This is coming from Turbo::Frames::FrameRequest module.
83
+ # Exposing it as public method
84
+ def turbo_frame_request?
85
+ super
86
+ end
87
+
82
88
  private
83
89
 
84
90
  def set_resource_name
@@ -5,7 +5,7 @@ module Avo
5
5
  before_action :set_resource_name
6
6
  before_action :set_resource
7
7
  before_action :hydrate_resource
8
- before_action :set_model, only: [:show, :edit, :destroy, :update]
8
+ before_action :set_model, only: [:show, :edit, :destroy, :update, :order]
9
9
  before_action :set_model_to_fill
10
10
  before_action :fill_model, only: [:create, :update]
11
11
  before_action :authorize_action
@@ -190,6 +190,21 @@ module Avo
190
190
  end
191
191
  end
192
192
 
193
+ def order
194
+ direction = params[:direction].to_sym
195
+
196
+ if direction.present?
197
+ @resource
198
+ .hydrate(model: @model, params: params)
199
+ .ordering_host
200
+ .order direction
201
+ end
202
+
203
+ respond_to do |format|
204
+ format.html { redirect_to params[:referrer] || resources_path(resource: @resource) }
205
+ end
206
+ end
207
+
193
208
  private
194
209
 
195
210
  def model_params
@@ -2,15 +2,15 @@ require_dependency "avo/base_controller"
2
2
 
3
3
  module Avo
4
4
  class RelationsController < BaseController
5
- before_action :set_model, only: [:show, :index, :new, :create, :destroy]
5
+ before_action :set_model, only: [:show, :index, :new, :create, :destroy, :order]
6
6
  before_action :set_related_resource_name
7
- before_action :set_related_resource, only: [:show, :index, :new, :create, :destroy]
8
- before_action :hydrate_related_resource, only: [:show, :index, :new, :create, :destroy]
9
- before_action :set_related_model, only: [:show]
10
- before_action :set_attachment_class, only: [:show, :index, :new, :create, :destroy]
11
- before_action :set_attachment_resource, only: [:show, :index, :new, :create, :destroy]
12
- before_action :set_attachment_model, only: [:create, :destroy]
13
- before_action :set_reflection, only: [:index, :show]
7
+ before_action :set_related_resource, only: [:show, :index, :new, :create, :destroy, :order]
8
+ before_action :hydrate_related_resource, only: [:show, :index, :new, :create, :destroy, :order]
9
+ before_action :set_related_model, only: [:show, :order]
10
+ before_action :set_attachment_class, only: [:show, :index, :new, :create, :destroy, :order]
11
+ before_action :set_attachment_resource, only: [:show, :index, :new, :create, :destroy, :order]
12
+ before_action :set_attachment_model, only: [:create, :destroy, :order]
13
+ before_action :set_reflection, only: [:index, :show, :order]
14
14
 
15
15
  def index
16
16
  @parent_resource = @resource.dup
@@ -71,6 +71,13 @@ module Avo
71
71
  end
72
72
  end
73
73
 
74
+ def order
75
+ @parent_resource = @resource.dup
76
+ @resource, @model = @related_resource, @related_model
77
+
78
+ super
79
+ end
80
+
74
81
  private
75
82
 
76
83
  def set_attachment_class
@@ -73,5 +73,9 @@ module Avo
73
73
 
74
74
  avo.resources_associations_index_path(@parent_resource.model_class.model_name.route_key, @parent_resource.model.id, **existing_params, **args )
75
75
  end
76
+
77
+ def order_up_resource_path(model:, resource:, **args)
78
+ avo.send :"order_up_resources_#{resource.singular_model_key}_path", model, **args
79
+ end
76
80
  end
77
81
  end
@@ -1,4 +1,5 @@
1
1
  import { Application } from '@hotwired/stimulus'
2
+ import { Popover } from 'tailwindcss-stimulus-components'
2
3
 
3
4
  const application = Application.start()
4
5
 
@@ -6,4 +7,7 @@ const application = Application.start()
6
7
  application.debug = false
7
8
  window.Stimulus = application
8
9
 
10
+ // Register stimulus-components controller
11
+ application.register('popover', Popover)
12
+
9
13
  export { application }
data/avo.gemspec CHANGED
@@ -44,4 +44,5 @@ Gem::Specification.new do |spec|
44
44
  spec.add_dependency "addressable"
45
45
  spec.add_dependency "meta-tags"
46
46
  spec.add_dependency "breadcrumbs_on_rails"
47
+ spec.add_dependency "dry-initializer"
47
48
  end
data/config/routes.rb CHANGED
@@ -17,6 +17,10 @@ Avo::Engine.routes.draw do
17
17
  get "/:resource_name/:id/active_storage_attachments/:attachment_name/:signed_attachment_id", to: "attachments#show"
18
18
  delete "/:resource_name/:id/active_storage_attachments/:attachment_name/:signed_attachment_id", to: "attachments#destroy"
19
19
 
20
+ # Ordering
21
+ patch "/:resource_name/:id/order", to: "resources#order"
22
+ patch "/:resource_name/:id/:related_name/:related_id/order", to: "relations#order", as: "associations_order"
23
+
20
24
  # Actions
21
25
  get "/:resource_name(/:id)/actions/:action_id", to: "actions#show"
22
26
  post "/:resource_name(/:id)/actions/:action_id", to: "actions#handle"
@@ -14,6 +14,7 @@ module Avo
14
14
 
15
15
  attr_accessor :view
16
16
  attr_accessor :model
17
+ attr_accessor :reflection
17
18
  attr_accessor :user
18
19
  attr_accessor :params
19
20
 
@@ -36,6 +37,7 @@ module Avo
36
37
  class_attribute :unscoped_queries_on_index, default: false
37
38
  class_attribute :resolve_query_scope
38
39
  class_attribute :resolve_find_scope
40
+ class_attribute :ordering
39
41
 
40
42
  class << self
41
43
  def grid(&block)
@@ -80,6 +82,12 @@ module Avo
80
82
  def authorization
81
83
  Avo::Services::AuthorizationService.new Avo::App.current_user
82
84
  end
85
+
86
+ def order_actions
87
+ return {} if ordering.blank?
88
+
89
+ ordering.dig(:actions) || {}
90
+ end
83
91
  end
84
92
 
85
93
  def initialize
@@ -135,6 +143,7 @@ module Avo
135
143
  # we're matching the reflection inverse_of foriegn key with the field's foreign_key
136
144
  if field.is_a?(Avo::Fields::BelongsToField)
137
145
  if field.respond_to?(:foreign_key) &&
146
+ reflection.inverse_of.present? &&
138
147
  reflection.inverse_of.foreign_key == field.foreign_key
139
148
  is_valid = false
140
149
  end
@@ -469,5 +478,9 @@ module Avo
469
478
  def form_scope
470
479
  model_class.base_class.to_s.underscore.downcase
471
480
  end
481
+
482
+ def ordering_host(**args)
483
+ Avo::Hosts::Ordering.new resource: self, options: self.class.ordering, **args
484
+ end
472
485
  end
473
486
  end
@@ -0,0 +1,22 @@
1
+ require 'dry-initializer'
2
+
3
+ module Avo
4
+ module Hosts
5
+ class Ordering
6
+ extend Dry::Initializer
7
+
8
+ option :options, default: proc { {} }
9
+ option :resource
10
+ option :record, default: proc { resource.model }
11
+ option :params, default: proc { resource.params }
12
+
13
+ def order(direction)
14
+ action = options.dig(:actions, direction.to_sym)
15
+
16
+ if action.present?
17
+ instance_exec(&action)
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -9,6 +9,7 @@ module Avo
9
9
  :global_search,
10
10
  :enhanced_search_results,
11
11
  :searchable_belongs_to,
12
+ :resource_ordering,
12
13
  ]
13
14
  end
14
15
  end
data/lib/avo/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Avo
2
- VERSION = "1.23.0"
2
+ VERSION = "1.24.2"
3
3
  end
@@ -95,3 +95,9 @@ en:
95
95
  was_successfully_updated: 'was successfully updated'
96
96
  clear_value: "Clear value"
97
97
  tools: Tools
98
+ order:
99
+ reorder_record: Reorder record
100
+ higher: Move record higher
101
+ lower: Move record lower
102
+ to_top: Move record to top
103
+ to_bottom: Move record to bottom
@@ -6791,6 +6791,10 @@ progress[value]::-moz-progress-bar{
6791
6791
  max-width:100%
6792
6792
  }
6793
6793
 
6794
+ .max-w-xs{
6795
+ max-width:20rem
6796
+ }
6797
+
6794
6798
  .flex-1{
6795
6799
  flex:1 1 0%
6796
6800
  }