avo 3.0.0.pre12 → 3.0.0.pre13

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 (52) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +1 -1
  3. data/app/assets/stylesheets/avo.base.css +1 -1
  4. data/app/components/avo/actions_component.html.erb +1 -1
  5. data/app/components/avo/actions_component.rb +40 -16
  6. data/app/components/avo/alert_component.html.erb +1 -1
  7. data/app/components/avo/field_wrapper_component.html.erb +2 -2
  8. data/app/components/avo/fields/common/heading_component.html.erb +1 -1
  9. data/app/components/avo/fields/markdown_field/edit_component.html.erb +3 -3
  10. data/app/components/avo/fields/markdown_field/show_component.html.erb +3 -3
  11. data/app/components/avo/fields/trix_field/edit_component.html.erb +1 -1
  12. data/app/components/avo/fields/trix_field/show_component.html.erb +1 -1
  13. data/app/components/avo/index/field_wrapper_component.html.erb +1 -1
  14. data/app/components/avo/index/grid_item_component.html.erb +9 -35
  15. data/app/components/avo/index/grid_item_component.rb +36 -10
  16. data/app/components/avo/panel_component.html.erb +1 -1
  17. data/app/components/avo/profile_item_component.html.erb +17 -2
  18. data/app/components/avo/profile_item_component.rb +13 -1
  19. data/app/components/avo/resource_component.rb +1 -0
  20. data/app/components/avo/sidebar_profile_component.html.erb +27 -27
  21. data/app/controllers/avo/actions_controller.rb +11 -1
  22. data/app/controllers/avo/associations_controller.rb +1 -1
  23. data/app/controllers/avo/base_controller.rb +14 -2
  24. data/app/controllers/avo/home_controller.rb +1 -1
  25. data/app/controllers/avo/search_controller.rb +7 -11
  26. data/app/javascript/js/controllers/fields/{simple_mde_controller.js → easy_mde_controller.js} +3 -3
  27. data/app/javascript/js/controllers/search_controller.js +3 -1
  28. data/app/javascript/js/controllers.js +2 -2
  29. data/app/views/avo/actions/show.html.erb +2 -1
  30. data/app/views/avo/partials/_profile_menu_extra.html.erb +2 -0
  31. data/lib/avo/base_action.rb +8 -1
  32. data/lib/avo/base_resource.rb +73 -102
  33. data/lib/avo/concerns/filters_session_handler.rb +0 -1
  34. data/lib/avo/concerns/has_items.rb +8 -8
  35. data/lib/avo/configuration.rb +6 -2
  36. data/lib/avo/engine.rb +5 -0
  37. data/lib/avo/fields/base_field.rb +0 -4
  38. data/lib/avo/fields/belongs_to_field.rb +14 -8
  39. data/lib/avo/fields/has_base_field.rb +1 -1
  40. data/lib/avo/resources/controls/actions_list.rb +2 -1
  41. data/lib/avo/services/debug_service.rb +1 -1
  42. data/lib/avo/version.rb +1 -1
  43. data/lib/generators/avo/eject_generator.rb +1 -0
  44. data/lib/generators/avo/install_generator.rb +0 -1
  45. data/lib/generators/avo/resource_generator.rb +4 -1
  46. data/lib/generators/avo/templates/resource/resource.tt +3 -4
  47. data/lib/tasks/avo_tasks.rake +27 -0
  48. data/public/avo-assets/avo.base.css +273 -138
  49. data/public/avo-assets/avo.base.js +245 -217
  50. data/public/avo-assets/avo.base.js.map +3 -3
  51. metadata +4 -4
  52. data/lib/avo/grid_collector.rb +0 -40
@@ -10,6 +10,7 @@ import CodeFieldController from './controllers/fields/code_field_controller'
10
10
  import CopyToClipboardController from './controllers/copy_to_clipboard_controller'
11
11
  import DashboardCardController from './controllers/dashboard_card_controller'
12
12
  import DateFieldController from './controllers/fields/date_field_controller'
13
+ import EasyMdeController from './controllers/fields/easy_mde_controller'
13
14
  import FilterController from './controllers/filter_controller'
14
15
  import HiddenInputController from './controllers/hidden_input_controller'
15
16
  import InputAutofocusController from './controllers/input_autofocus_controller'
@@ -31,7 +32,6 @@ import SelectController from './controllers/select_controller'
31
32
  import SelectFilterController from './controllers/select_filter_controller'
32
33
  import SelfDestroyController from './controllers/self_destroy_controller'
33
34
  import SidebarController from './controllers/sidebar_controller'
34
- import SimpleMdeController from './controllers/fields/simple_mde_controller'
35
35
  import TabsController from './controllers/tabs_controller'
36
36
  import TextFilterController from './controllers/text_filter_controller'
37
37
  import TippyController from './controllers/tippy_controller'
@@ -73,9 +73,9 @@ application.register('toggle', ToggleController)
73
73
  application.register('belongs-to-field', BelongsToFieldController)
74
74
  application.register('code-field', CodeFieldController)
75
75
  application.register('date-field', DateFieldController)
76
+ application.register('easy-mde', EasyMdeController)
76
77
  application.register('key-value', KeyValueController)
77
78
  application.register('progress-bar-field', ProgressBarFieldController)
78
- application.register('simple-mde', SimpleMdeController)
79
79
  application.register('trix-field', TrixFieldController)
80
80
 
81
81
  // Custom controllers
@@ -9,7 +9,7 @@
9
9
  >
10
10
  <%= form_with model: @record,
11
11
  scope: 'fields',
12
- url: "#{@resource.records_path}/actions",
12
+ url: Avo::Services::URIService.parse(@resource.records_path).append_paths("actions").to_s,
13
13
  local: true,
14
14
  data: @action.class.form_data_attributes do |form|
15
15
  %>
@@ -23,6 +23,7 @@
23
23
  <%= hidden_field_tag :action_id, @action.param_id %>
24
24
  <%= form.hidden_field :avo_resource_ids, value: params[:id] || params[:resource_ids], 'data-action-target': 'resourceIds' %>
25
25
  <%= form.hidden_field :avo_selected_query, 'data-action-target': 'selectedAllQuery' %>
26
+ <%= form.hidden_field :arguments, value: params[:arguments] %>
26
27
  <% if @action.get_fields.present? %>
27
28
  <div class="my-4 -mx-6">
28
29
  <% @action.get_fields.each_with_index do |field, index| %>
@@ -0,0 +1,2 @@
1
+ <%# Example link below %>
2
+ <%#= render Avo::ProfileItemComponent.new label: 'Profile', path: '/profile', icon: 'user-circle' %>
@@ -86,7 +86,14 @@ module Avo
86
86
 
87
87
  def get_attributes_for_action
88
88
  get_fields.map do |field|
89
- [field.id, field.value || field.default]
89
+ value = field.value || Avo::ExecutionContext.new(
90
+ target: field.default,
91
+ record: self.class.record,
92
+ resource: self.class.resource,
93
+ view: view
94
+ ).handle
95
+
96
+ [field.id, value]
90
97
  end.to_h
91
98
  end
92
99
 
@@ -38,19 +38,17 @@ module Avo
38
38
  attr_accessor :record
39
39
 
40
40
  class_attribute :id, default: :id
41
- class_attribute :title, default: :id
42
- class_attribute :search_query, default: nil
43
- class_attribute :search_query_help, default: ""
44
- class_attribute :search_result_path
41
+ class_attribute :title
42
+ class_attribute :search, default: {}
45
43
  class_attribute :includes, default: []
46
44
  class_attribute :authorization_policy
47
45
  class_attribute :translation_key
48
46
  class_attribute :default_view_type, default: :table
49
47
  class_attribute :devise_password_optional, default: false
50
- class_attribute :actions_loader
51
48
  class_attribute :scopes_loader
52
49
  class_attribute :filters_loader
53
- class_attribute :grid_loader
50
+ class_attribute :view_types
51
+ class_attribute :grid_view
54
52
  class_attribute :visible_on_sidebar, default: true
55
53
  class_attribute :index_query, default: -> {
56
54
  query
@@ -58,7 +56,6 @@ module Avo
58
56
  class_attribute :find_record_method, default: -> {
59
57
  query.find id
60
58
  }
61
- class_attribute :hide_from_global_search, default: false
62
59
  class_attribute :after_create_path, default: :show
63
60
  class_attribute :after_update_path, default: :show
64
61
  class_attribute :record_selector, default: true
@@ -74,39 +71,16 @@ module Avo
74
71
  delegate :t, to: ::I18n
75
72
  delegate :context, to: ::Avo::Current
76
73
 
77
- def grid(&block)
78
- grid_collector = GridCollector.new
79
- grid_collector.instance_eval(&block)
80
-
81
- self.grid_loader = grid_collector
82
- end
83
-
84
74
  def action(action_class, arguments: {})
85
- self.actions_loader ||= Avo::Loaders::Loader.new
86
-
87
- action = {class: action_class, arguments: arguments}
88
- self.actions_loader.use action
75
+ deprecated_dsl_api __method__, "actions"
89
76
  end
90
77
 
91
78
  def filter(filter_class, arguments: {})
92
- self.filters_loader ||= Avo::Loaders::Loader.new
93
-
94
- filter = { class: filter_class , arguments: arguments }
95
- self.filters_loader.use filter
79
+ deprecated_dsl_api __method__, "filters"
96
80
  end
97
81
 
98
- # This is the search_query scope
99
- # This should be removed and passed to the search block
100
- def scope
101
- query_scope
102
- end
103
-
104
- def scopes(*args)
105
- self.scopes_loader ||= Avo::Loaders::Loader.new
106
-
107
- args.each do |scope_class|
108
- self.scopes_loader.use scope_class
109
- end
82
+ def scope(scope_class)
83
+ deprecated_dsl_api __method__, "scopes"
110
84
  end
111
85
 
112
86
  # This resolves the scope when doing "where" queries (not find queries)
@@ -195,54 +169,47 @@ module Avo
195
169
  # blank fields method
196
170
  end
197
171
 
198
- def hydrate(record: nil, view: nil, user: nil, params: nil)
199
- @view = view if view.present?
200
- @user = user if user.present?
201
- @params = params if params.present?
172
+ [:action, :filter, :scope].each do |entity|
173
+ plural_entity = entity.to_s.pluralize
202
174
 
203
- if record.present?
204
- @record = record
205
-
206
- hydrate_model_with_default_values if @view == :new
175
+ # def actions / def filters / def scopes
176
+ define_method plural_entity do
177
+ # blank entity method
207
178
  end
208
179
 
209
- self
210
- end
211
-
212
- def get_grid_fields
213
- return if self.class.grid_loader.blank?
214
-
215
- self.class.grid_loader.hydrate(record: @record, view: @view, resource: self)
216
- end
217
-
218
- def get_filters
219
- return [] if self.class.filters_loader.blank?
220
-
221
- self.class.filters_loader.bag
222
- end
180
+ # def action / def filter / def scope
181
+ define_method entity do |entity_class, arguments: {}|
182
+ entity_loader(entity).use({class: entity_class, arguments: arguments})
183
+ end
223
184
 
224
- def get_filter_arguments(filter_class)
225
- filter = get_filters.find { |filter| filter[:class] == filter_class.constantize }
185
+ # def get_actions / def get_filters / def get_scopes
186
+ define_method "get_#{plural_entity}" do
187
+ return entity_loader(entity).bag if entity_loader(entity).present?
226
188
 
227
- filter[:arguments]
228
- end
189
+ instance_variable_set("@#{plural_entity}_loader", Avo::Loaders::Loader.new)
190
+ send plural_entity
229
191
 
230
- def get_actions
231
- return [] if self.class.actions_loader.blank?
192
+ entity_loader(entity).bag
193
+ end
232
194
 
233
- self.class.actions_loader.bag
195
+ # def get_action_arguments / def get_filter_arguments / def get_scope_arguments
196
+ define_method "get_#{entity}_arguments" do |entity_class|
197
+ send("get_#{plural_entity}").find { |entity| entity[:class] == entity_class.constantize }[:arguments]
198
+ end
234
199
  end
235
200
 
236
- def get_action_arguments(action_class)
237
- action = get_actions.find { |action| action[:class].to_s == action_class.to_s }
201
+ def hydrate(record: nil, view: nil, user: nil, params: nil)
202
+ @view = view if view.present?
203
+ @user = user if user.present?
204
+ @params = params if params.present?
238
205
 
239
- action[:arguments]
240
- end
206
+ if record.present?
207
+ @record = record
241
208
 
242
- def get_scopes
243
- return [] if self.class.scopes_loader.blank?
209
+ hydrate_model_with_default_values if @view == :new
210
+ end
244
211
 
245
- self.class.scopes_loader.bag
212
+ self
246
213
  end
247
214
 
248
215
  def default_panel_name
@@ -272,12 +239,16 @@ module Avo
272
239
  def record_title
273
240
  return name if @record.nil?
274
241
 
275
- the_title = @record.send title
276
- return the_title if the_title.present?
242
+ # Get the title from the record if title is not set, try to get the name, title or label, or fallback to the id
243
+ return @record.try(:name) || @record.try(:title) || @record.try(:label) || @record.id if title.nil?
277
244
 
278
- @record.id
279
- rescue
280
- name
245
+ # If the title is a symbol, get the value from the record else execute the block/string
246
+ case title
247
+ when Symbol
248
+ @record.send title
249
+ when Proc
250
+ Avo::ExecutionContext.new(target: title, resource: self, record: @record).handle
251
+ end
281
252
  end
282
253
 
283
254
  def translation_key
@@ -285,10 +256,10 @@ module Avo
285
256
  end
286
257
 
287
258
  def name
288
- default = class_name.underscore.humanize
289
-
290
259
  return @name if @name.present?
291
260
 
261
+ default = class_name.underscore.humanize
262
+
292
263
  if translation_key
293
264
  t(translation_key, count: 1, default: default).capitalize
294
265
  else
@@ -321,9 +292,19 @@ module Avo
321
292
  end
322
293
 
323
294
  def available_view_types
295
+ if self.class.view_types.present?
296
+ return Array(
297
+ Avo::ExecutionContext.new(
298
+ target: self.class.view_types,
299
+ resource: self,
300
+ record: record
301
+ ).handle
302
+ )
303
+ end
304
+
324
305
  view_types = [:table]
325
306
 
326
- view_types << :grid if get_grid_fields.present?
307
+ view_types << :grid if self.class.grid_view.present?
327
308
  view_types << :map if map_view.present?
328
309
 
329
310
  view_types
@@ -461,18 +442,6 @@ module Avo
461
442
  resources_path(resource: self)
462
443
  end
463
444
 
464
- def label_field
465
- get_field_definitions.find do |field|
466
- field.as_label.present?
467
- end
468
- rescue
469
- nil
470
- end
471
-
472
- def label
473
- label_field&.value || record_title
474
- end
475
-
476
445
  def avatar_field
477
446
  get_field_definitions.find do |field|
478
447
  field.as_avatar.present?
@@ -497,18 +466,6 @@ module Avo
497
466
  nil
498
467
  end
499
468
 
500
- def description_field
501
- get_field_definitions.find do |field|
502
- field.as_description.present?
503
- end
504
- rescue
505
- nil
506
- end
507
-
508
- def search_description
509
- description_field&.value
510
- end
511
-
512
469
  def form_scope
513
470
  model_class.base_class.to_s.underscore.downcase
514
471
  end
@@ -541,5 +498,19 @@ module Avo
541
498
  record: record
542
499
  }
543
500
  end
501
+
502
+ def search_query
503
+ self.class.search.dig(:query)
504
+ end
505
+
506
+ def fetch_search(key)
507
+ Avo::ExecutionContext.new(target: self.class.search[key], resource: self, record: record).handle
508
+ end
509
+
510
+ private
511
+
512
+ def entity_loader(entity)
513
+ instance_variable_get("@#{entity.to_s.pluralize}_loader")
514
+ end
544
515
  end
545
516
  end
@@ -1,4 +1,3 @@
1
-
2
1
  module Avo
3
2
  module Concerns
4
3
  module FiltersSessionHandler
@@ -4,34 +4,34 @@ module Avo
4
4
  extend ActiveSupport::Concern
5
5
 
6
6
  class_methods do
7
- def deprecated_dsl_api(name = nil)
8
- message = "This API was deprecated. Please use the `#{name}` method inside the `fields` method."
7
+ def deprecated_dsl_api(name, method)
8
+ message = "This API was deprecated. Please use the `#{name}` method inside the `#{method}` method."
9
9
  raise DeprecatedAPIError.new message
10
10
  end
11
11
 
12
12
  # DSL methods
13
13
  def field(name, as: :text, **args, &block)
14
- deprecated_dsl_api "field"
14
+ deprecated_dsl_api __method__, "fields"
15
15
  end
16
16
 
17
17
  def panel(name = nil, **args, &block)
18
- deprecated_dsl_api "panel"
18
+ deprecated_dsl_api __method__, "fields"
19
19
  end
20
20
 
21
21
  def tabs(**args, &block)
22
- deprecated_dsl_api "tabs"
22
+ deprecated_dsl_api __method__, "fields"
23
23
  end
24
24
 
25
25
  def tool(klass, **args)
26
- deprecated_dsl_api "tool"
26
+ deprecated_dsl_api __method__, "fields"
27
27
  end
28
28
 
29
29
  def heading(body, **args)
30
- deprecated_dsl_api "heading"
30
+ deprecated_dsl_api __method__, "fields"
31
31
  end
32
32
 
33
33
  def sidebar(**args, &block)
34
- deprecated_dsl_api "sidebar"
34
+ deprecated_dsl_api __method__, "fields"
35
35
  end
36
36
  # END DSL methods
37
37
  end
@@ -2,8 +2,9 @@ module Avo
2
2
  class Configuration
3
3
  include ResourceConfiguration
4
4
 
5
+ attr_writer :app_name
6
+ attr_writer :branding
5
7
  attr_writer :root_path
6
- attr_accessor :app_name
7
8
  attr_accessor :timezone
8
9
  attr_accessor :per_page
9
10
  attr_accessor :per_page_steps
@@ -42,7 +43,6 @@ module Avo
42
43
  attr_accessor :sign_out_path_name
43
44
  attr_accessor :resources
44
45
  attr_accessor :prefix_path
45
- attr_writer :branding
46
46
 
47
47
  def initialize
48
48
  @root_path = "/avo"
@@ -136,6 +136,10 @@ module Avo
136
136
  def branding
137
137
  Avo::Configuration::Branding.new(**@branding || {})
138
138
  end
139
+
140
+ def app_name
141
+ Avo::ExecutionContext.new(target: @app_name).handle
142
+ end
139
143
  end
140
144
 
141
145
  def self.configuration
data/lib/avo/engine.rb CHANGED
@@ -91,5 +91,10 @@ module Avo
91
91
  Rails::Generators.configure! app.config.generators
92
92
  require_relative "../generators/model_generator"
93
93
  end
94
+
95
+ initializer "avo.locales" do |app|
96
+ I18n.load_path += Dir[Avo::Engine.root.join("lib", "generators", "avo", "templates", "locales", "*.{rb,yml}")]
97
+ I18n.load_path += Dir[Rails.root.join("config", "locales", "*.{rb,yml}")]
98
+ end
94
99
  end
95
100
  end
@@ -36,9 +36,7 @@ module Avo
36
36
  attr_reader :autocomplete
37
37
  attr_reader :help
38
38
  attr_reader :default
39
- attr_reader :as_label
40
39
  attr_reader :as_avatar
41
- attr_reader :as_description
42
40
  attr_reader :stacked
43
41
  attr_reader :for_presentation_only
44
42
 
@@ -72,9 +70,7 @@ module Avo
72
70
  @help = args[:help] || nil
73
71
  @default = args[:default] || nil
74
72
  @visible = args[:visible]
75
- @as_label = args[:as_label] || false
76
73
  @as_avatar = args[:as_avatar] || false
77
- @as_description = args[:as_description] || false
78
74
  @html = args[:html] || nil
79
75
  @view = args[:view] || nil
80
76
  @value = args[:value] || nil
@@ -104,9 +104,7 @@ module Avo
104
104
 
105
105
  # What the user sees in the text field
106
106
  def field_label
107
- value.send(target_resource.class.title)
108
- rescue
109
- nil
107
+ label
110
108
  end
111
109
 
112
110
  def options
@@ -123,8 +121,8 @@ module Avo
123
121
  query = Avo::ExecutionContext.new(target: attach_scope, query: query, parent: get_model).handle
124
122
  end
125
123
 
126
- query.all.map do |model|
127
- [model.send(resource.class.title), model.id]
124
+ query.all.map do |record|
125
+ [resource.hydrate(record: record).record_title, record.id]
128
126
  end
129
127
  end
130
128
 
@@ -182,7 +180,7 @@ module Avo
182
180
  end
183
181
 
184
182
  def label
185
- value.send(target_resource.class.title)
183
+ target_resource.hydrate(record: value).record_title
186
184
  end
187
185
 
188
186
  def to_permitted_param
@@ -197,10 +195,12 @@ module Avo
197
195
  return model unless model.methods.include? key.to_sym
198
196
 
199
197
  if polymorphic_as.present?
200
- model.send("#{polymorphic_as}_type=", params["#{polymorphic_as}_type"])
198
+ valid_model_class = valid_polymorphic_class params["#{polymorphic_as}_type"]
199
+
200
+ model.send("#{polymorphic_as}_type=", valid_model_class)
201
201
 
202
202
  # If the type is blank, reset the id too.
203
- if params["#{polymorphic_as}_type"].blank?
203
+ if valid_model_class.blank?
204
204
  model.send("#{polymorphic_as}_id=", nil)
205
205
  else
206
206
  model.send("#{polymorphic_as}_id=", params["#{polymorphic_as}_id"])
@@ -212,6 +212,12 @@ module Avo
212
212
  model
213
213
  end
214
214
 
215
+ def valid_polymorphic_class(possible_class)
216
+ types.find do |type|
217
+ type.to_s == possible_class.to_s
218
+ end
219
+ end
220
+
215
221
  def database_id
216
222
  # If the field is a polymorphic value, return the polymorphic_type as key and pre-fill the _id in fill_field.
217
223
  return "#{polymorphic_as}_type" if polymorphic_as.present?
@@ -50,7 +50,7 @@ module Avo
50
50
 
51
51
  # What the user sees in the text field
52
52
  def field_label
53
- value.send(target_resource.class.title)
53
+ target_resource.hydrate(record: value).record_title
54
54
  rescue
55
55
  nil
56
56
  end
@@ -2,13 +2,14 @@ module Avo
2
2
  module Resources
3
3
  module Controls
4
4
  class ActionsList < BaseControl
5
- attr_reader :color, :exclude, :style
5
+ attr_reader :color, :exclude, :include, :style
6
6
 
7
7
  def initialize(**args)
8
8
  super(**args)
9
9
 
10
10
  @color = args[:color] || :primary
11
11
  @exclude = args[:exclude] || []
12
+ @include = args[:include] || []
12
13
  @style = args[:style] || :outline
13
14
  end
14
15
  end
@@ -55,7 +55,7 @@ class Avo::Services::DebugService
55
55
  fields_per_resource: fields_per_resource,
56
56
  custom_fields_count: custom_fields_count,
57
57
  field_types: field_types,
58
- **other_metadata(:actions),
58
+ # **other_metadata(:actions), #FIEXME: this is fetching actions without hydration
59
59
  **other_metadata(:filters),
60
60
  main_menu_present: Avo.configuration.main_menu.present?,
61
61
  profile_menu_present: Avo.configuration.profile_menu.present?,
data/lib/avo/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Avo
2
- VERSION = "3.0.0.pre12" unless const_defined?(:VERSION)
2
+ VERSION = "3.0.0.pre13" unless const_defined?(:VERSION)
3
3
  end
@@ -17,6 +17,7 @@ module Generators
17
17
  pre_head: "app/views/avo/partials/_pre_head.html.erb",
18
18
  scripts: "app/views/avo/partials/_scripts.html.erb",
19
19
  sidebar_extra: "app/views/avo/partials/_sidebar_extra.html.erb",
20
+ profile_menu_extra: "app/views/avo/partials/_profile_menu_extra.html.erb",
20
21
  }
21
22
 
22
23
  def handle
@@ -13,7 +13,6 @@ module Generators
13
13
  route "mount Avo::Engine, at: Avo.configuration.root_path"
14
14
 
15
15
  template "initializer/avo.tt", "config/initializers/avo.rb"
16
- directory File.join(__dir__, "templates", "locales"), "config/locales"
17
16
  create_resources
18
17
  end
19
18
 
@@ -135,6 +135,9 @@ module Generators
135
135
  fields_string = ""
136
136
 
137
137
  fields.each do |field_name, field_options|
138
+ # if field_options are not available (likely a missing resource for an association), skip the field
139
+ fields_string += "\n # Could not generate a field for #{field_name}" and next unless field_options
140
+
138
141
  options = ""
139
142
  field_options[:options].each { |k, v| options += ", #{k}: #{v}" } if field_options[:options].present?
140
143
 
@@ -181,7 +184,7 @@ module Generators
181
184
  end
182
185
 
183
186
  def field_from_through_association(association)
184
- if association.through_reflection.is_a? ActiveRecord::Reflection::HasManyReflection
187
+ if association.through_reflection.is_a?(ActiveRecord::Reflection::HasManyReflection) || association.through_reflection.is_a?(ActiveRecord::Reflection::ThroughReflection)
185
188
  {
186
189
  field: "has_many",
187
190
  options: {
@@ -1,9 +1,8 @@
1
1
  class Avo::Resources::<%= resource_class %> < Avo::BaseResource
2
- self.title = :id
3
2
  self.includes = []<%= model_class_from_args %>
4
- # self.search_query = -> do
5
- # query.ransack(id_eq: params[:q], m: "or").result(distinct: false)
6
- # end
3
+ # self.search = {
4
+ # query: -> { query.ransack(id_eq: params[:q], m: "or").result(distinct: false) }
5
+ # }
7
6
 
8
7
  def fields
9
8
  field :id, as: :id<%= generate_fields %>
@@ -63,3 +63,30 @@ task "avo:gem_paths" do
63
63
  # avo:/Users/adrian/work/avocado/avo-3,avo_filters:/Users/adrian/work/avocado/advanced/avo_filters
64
64
  puts result
65
65
  end
66
+
67
+ desc "Symlink registered gems in `./tmp/gems` so their views, etc. can be inspected by Tailwind CSS."
68
+ task "avo:link" do
69
+ Avo::App.boot
70
+ abort Avo.plugin_manager.plugins.inspect
71
+ if Dir.exist?("tmp/gems")
72
+ puts "Removing previously linked gems."
73
+ `rm -f tmp/gems/*`
74
+ else
75
+ if File.exist?("tmp/gems")
76
+ raise "A file named `tmp/gems` already exists? It has to be removed before we can create the required directory."
77
+ end
78
+
79
+ puts "Creating 'tmp/gems' directory."
80
+ `mkdir tmp/gems`
81
+ end
82
+
83
+ `touch tmp/gems/.keep`
84
+
85
+ Avo.plugin_manager.plugins.each do |linked_gem|
86
+ target = `bundle show #{linked_gem}`.chomp
87
+ if target.present?
88
+ puts "Linking '#{linked_gem}' to '#{target}'."
89
+ `ln -s #{target} tmp/gems/#{linked_gem}`
90
+ end
91
+ end
92
+ end