avo 2.18.1 → 2.19.0

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 (79) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +4 -5
  3. data/Gemfile.lock +75 -76
  4. data/app/components/avo/actions_component.html.erb +1 -1
  5. data/app/components/avo/actions_component.rb +4 -4
  6. data/app/components/avo/base_component.rb +17 -0
  7. data/app/components/avo/field_wrapper_component.rb +7 -1
  8. data/app/components/avo/fields/has_one_field/show_component.rb +1 -2
  9. data/app/components/avo/fields/index_component.rb +4 -3
  10. data/app/components/avo/filters_component.html.erb +1 -1
  11. data/app/components/avo/filters_component.rb +2 -2
  12. data/app/components/avo/index/grid_item_component.rb +2 -2
  13. data/app/components/avo/index/resource_controls_component.rb +2 -2
  14. data/app/components/avo/index/table_row_component.html.erb +1 -1
  15. data/app/components/avo/item_switcher_component.html.erb +1 -1
  16. data/app/components/avo/resource_component.rb +1 -1
  17. data/app/components/avo/resource_sidebar_component.rb +1 -6
  18. data/app/components/avo/sidebar_profile_component.rb +3 -1
  19. data/app/components/avo/tab_group_component.rb +1 -1
  20. data/app/components/avo/views/resource_show_component.html.erb +1 -1
  21. data/app/controllers/avo/application_controller.rb +6 -0
  22. data/app/controllers/avo/base_controller.rb +14 -7
  23. data/app/controllers/avo/dashboards/cards_controller.rb +37 -0
  24. data/app/helpers/avo/application_helper.rb +5 -1
  25. data/app/javascript/js/controllers/search_controller.js +11 -2
  26. data/app/views/avo/{cards → dashboards/cards}/_chartkick_card.html.erb +0 -0
  27. data/app/views/avo/{cards → dashboards/cards}/_metric_card.html.erb +0 -0
  28. data/app/views/avo/{cards → dashboards/cards}/chartkick_missing.html.erb +0 -0
  29. data/app/views/avo/{cards → dashboards/cards}/show.html.erb +0 -0
  30. data/app/views/avo/partials/_branding.html.erb +1 -0
  31. data/avo.gemspec +1 -1
  32. data/bin/init +11 -1
  33. data/bin/test +1 -0
  34. data/config/routes.rb +2 -2
  35. data/db/factories.rb +10 -0
  36. data/lib/avo/app.rb +11 -1
  37. data/lib/avo/base_action.rb +19 -9
  38. data/lib/avo/base_resource.rb +3 -6
  39. data/lib/avo/concerns/filters_session_handler.rb +43 -0
  40. data/lib/avo/concerns/has_fields.rb +2 -0
  41. data/lib/avo/concerns/visible_items.rb +44 -0
  42. data/lib/avo/configuration/branding.rb +10 -2
  43. data/lib/avo/configuration.rb +3 -0
  44. data/lib/avo/dynamic_router.rb +16 -15
  45. data/lib/avo/engine.rb +6 -9
  46. data/lib/avo/fields/base_field.rb +21 -12
  47. data/lib/avo/fields/concerns/has_default.rb +17 -0
  48. data/lib/avo/fields/concerns/is_readonly.rb +1 -1
  49. data/lib/avo/fields/concerns/is_required.rb +2 -2
  50. data/lib/avo/fields/has_base_field.rb +2 -0
  51. data/lib/avo/fields/key_value_field.rb +1 -1
  52. data/lib/avo/filters/base_filter.rb +17 -2
  53. data/lib/avo/hosts/resource_view_record_host.rb +7 -0
  54. data/lib/avo/hosts/visibility_host.rb +11 -0
  55. data/lib/avo/panel.rb +4 -1
  56. data/lib/avo/resources/controls/action.rb +1 -3
  57. data/lib/avo/sidebar.rb +1 -31
  58. data/lib/avo/tab.rb +5 -22
  59. data/lib/avo/version.rb +1 -1
  60. data/lib/avo.rb +9 -0
  61. data/lib/generators/avo/resource_generator.rb +281 -0
  62. data/lib/generators/avo/templates/action.tt +3 -0
  63. data/lib/generators/avo/templates/filters/boolean_filter.tt +3 -0
  64. data/lib/generators/avo/templates/filters/multiple_select_filter.tt +3 -0
  65. data/lib/generators/avo/templates/filters/select_filter.tt +3 -0
  66. data/lib/generators/avo/templates/filters/text_filter.tt +3 -0
  67. data/lib/generators/avo/templates/initializer/avo.tt +4 -0
  68. data/lib/generators/avo/templates/resource/controller.tt +1 -1
  69. data/lib/generators/avo/templates/resource/resource.tt +2 -2
  70. data/lib/generators/model_generator.rb +10 -0
  71. data/lib/generators/rails/avo_resource_generator.rb +11 -0
  72. data/public/avo-assets/avo.base.css +10 -10
  73. data/public/avo-assets/avo.base.js +1 -1
  74. data/public/avo-assets/avo.base.js.map +2 -2
  75. data/public/avo-assets/favicon.ico +0 -0
  76. data/{app/assets/svgs → public/avo-assets}/placeholder.svg +0 -0
  77. metadata +18 -11
  78. data/app/controllers/avo/cards_controller.rb +0 -35
  79. data/config/master.key +0 -1
@@ -6,7 +6,7 @@ module Avo
6
6
 
7
7
  def is_required?
8
8
  if required.respond_to? :call
9
- Avo::Hosts::ViewRecordHost.new(block: required, record: model, view: view).handle
9
+ Avo::Hosts::ResourceViewRecordHost.new(block: required, record: model, view: view, resource: resource).handle
10
10
  else
11
11
  required.nil? ? required_from_validators : required
12
12
  end
@@ -18,7 +18,7 @@ module Avo
18
18
  return false if model.nil?
19
19
 
20
20
  validators.any? do |validator|
21
- validator.kind_of? ActiveModel::Validations::PresenceValidator
21
+ validator.is_a? ActiveModel::Validations::PresenceValidator
22
22
  end
23
23
  end
24
24
 
@@ -7,6 +7,7 @@ module Avo
7
7
  attr_accessor :description
8
8
  attr_accessor :discreet_pagination
9
9
  attr_accessor :hide_search_input
10
+ attr_reader :link_to_child_resource
10
11
 
11
12
  def initialize(id, **args, &block)
12
13
  super(id, **args, &block)
@@ -19,6 +20,7 @@ module Avo
19
20
  @description = args[:description]
20
21
  @use_resource = args[:use_resource] || nil
21
22
  @discreet_pagination = args[:discreet_pagination] || false
23
+ @link_to_child_resource = args[:link_to_child_resource] || false
22
24
  end
23
25
 
24
26
  def searchable
@@ -81,7 +81,7 @@ module Avo
81
81
  new_value = {}
82
82
  end
83
83
 
84
- model[key] = new_value
84
+ model.send("#{key}=", new_value)
85
85
 
86
86
  model
87
87
  end
@@ -3,11 +3,12 @@ module Avo
3
3
  class BaseFilter
4
4
  PARAM_KEY = :filters unless const_defined?(:PARAM_KEY)
5
5
 
6
- class_attribute :name, default: "Filter"
7
6
  class_attribute :component, default: "boolean-filter"
8
7
  class_attribute :default, default: nil
9
- class_attribute :template, default: "avo/base/select_filter"
10
8
  class_attribute :empty_message
9
+ class_attribute :name, default: "Filter"
10
+ class_attribute :template, default: "avo/base/select_filter"
11
+ class_attribute :visible
11
12
 
12
13
  delegate :params, to: Avo::App
13
14
 
@@ -52,6 +53,20 @@ module Avo
52
53
  def applied_filters
53
54
  self.class.decode_filters params[PARAM_KEY]
54
55
  end
56
+
57
+ def visible_in_view(resource: nil, parent_model: nil, parent_resource: nil)
58
+ return true if visible.blank?
59
+
60
+ # Run the visible block if available
61
+ Avo::Hosts::VisibilityHost.new(
62
+ block: visible,
63
+ params: params,
64
+ parent_model: parent_model,
65
+ parent_resource: parent_resource,
66
+ resource: resource
67
+ ).handle
68
+
69
+ end
55
70
  end
56
71
  end
57
72
  end
@@ -0,0 +1,7 @@
1
+ module Avo
2
+ module Hosts
3
+ class ResourceViewRecordHost < ViewRecordHost
4
+ option :resource
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,11 @@
1
+ module Avo
2
+ module Hosts
3
+ class VisibilityHost < BaseHost
4
+ option :parent_model
5
+ option :parent_resource
6
+ option :resource
7
+ # View is optional because in filter context the view is always :index
8
+ option :view, optional: true
9
+ end
10
+ end
11
+ end
data/lib/avo/panel.rb CHANGED
@@ -1,16 +1,19 @@
1
1
  class Avo::Panel
2
2
  include Avo::Concerns::IsResourceItem
3
+ include Avo::Concerns::VisibleItems
3
4
 
4
5
  class_attribute :item_type, default: :panel
5
6
 
6
7
  attr_reader :name
8
+ attr_reader :view
7
9
  attr_reader :description
8
10
  attr_accessor :items_holder
9
11
 
10
12
  delegate :items, :add_item, to: :items_holder
11
13
 
12
- def initialize(name: nil, description: nil)
14
+ def initialize(name: nil, description: nil, view: nil)
13
15
  @name = name
16
+ @view = view
14
17
  @description = description
15
18
  @items_holder = Avo::ItemsHolder.new
16
19
  end
@@ -14,9 +14,7 @@ module Avo
14
14
  end
15
15
 
16
16
  def action
17
- return @instance if @instance.present?
18
-
19
- @instance = @klass.new(model: @model, resource: @resource, view: @view)
17
+ @instance ||= @klass.new(model: @model, resource: @resource, view: @view)
20
18
  end
21
19
 
22
20
  def path
data/lib/avo/sidebar.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  class Avo::Sidebar
2
2
  include Avo::Concerns::IsResourceItem
3
+ include Avo::Concerns::VisibleItems
3
4
  include Avo::Fields::FieldExtensions::VisibleInDifferentViews
4
5
 
5
6
  class_attribute :item_type, default: :sidebar
@@ -23,38 +24,7 @@ class Avo::Sidebar
23
24
  except_on args[:except_on] if args[:except_on].present?
24
25
  end
25
26
 
26
- def hydrate(view: nil)
27
- @view = view
28
-
29
- self
30
- end
31
-
32
27
  def empty?
33
28
  visible_items.blank?
34
29
  end
35
-
36
- def items
37
- if self.items_holder.present?
38
- self.items_holder.items
39
- else
40
- []
41
- end
42
- end
43
-
44
- def visible_items
45
- items.map do |item|
46
- # Remove the fields that shouldn't be visible in this view
47
- # eg: has_many fields on edit
48
- if not_visible_field(item)
49
- nil
50
- else
51
- item
52
- end
53
- end
54
- .compact
55
- end
56
-
57
- def not_visible_field(item)
58
- item.is_field? && !item.visible_on?(view)
59
- end
60
30
  end
data/lib/avo/tab.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  class Avo::Tab
2
2
  include Avo::Concerns::IsResourceItem
3
+ include Avo::Concerns::VisibleItems
3
4
  include Avo::Fields::FieldExtensions::VisibleInDifferentViews
4
5
 
5
6
  class_attribute :item_type, default: :tab
@@ -30,6 +31,10 @@ class Avo::Tab
30
31
  def hydrate(view: nil)
31
32
  @view = view
32
33
 
34
+ items_holder.items.grep(Avo::Panel).each do |panel|
35
+ panel.hydrate(view: view)
36
+ end
37
+
33
38
  self
34
39
  end
35
40
 
@@ -53,26 +58,4 @@ class Avo::Tab
53
58
  super(view)
54
59
  end
55
60
  end
56
-
57
- def items
58
- if self.items_holder.present?
59
- self.items_holder.items
60
- else
61
- []
62
- end
63
- end
64
-
65
- def visible_items
66
- items.map do |item|
67
- if item.is_field?
68
- visible = item.visible_on?(view)
69
- # Remove the fields that shouldn't be visible in this view
70
- # eg: has_many fields on edit
71
- item = nil unless visible
72
- end
73
-
74
- item
75
- end
76
- .compact
77
- end
78
61
  end
data/lib/avo/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Avo
2
- VERSION = "2.18.1" unless const_defined?(:VERSION)
2
+ VERSION = "2.19.0" unless const_defined?(:VERSION)
3
3
  end
data/lib/avo.rb CHANGED
@@ -40,6 +40,15 @@ module Avo
40
40
  IN_DEVELOPMENT = ENV["AVO_IN_DEVELOPMENT"] == "1"
41
41
  PACKED = !IN_DEVELOPMENT
42
42
  COOKIES_KEY = "avo"
43
+ ENTITIES = {
44
+ cards: ["app", "avo", "cards"],
45
+ fields: ["app", "avo", "fields"],
46
+ filters: ["app", "avo", "filters"],
47
+ actions: ["app", "avo", "actions"],
48
+ resources: ["app", "avo", "resources"],
49
+ dashboards: ["app", "avo", "dashboards"],
50
+ resource_tools: ["app", "avo", "resource_tools"]
51
+ }
43
52
 
44
53
  class LicenseVerificationTemperedError < StandardError; end
45
54
 
@@ -7,6 +7,11 @@ module Generators
7
7
 
8
8
  namespace "avo:resource"
9
9
 
10
+ class_option "model-class",
11
+ type: :string,
12
+ required: false,
13
+ desc: "The name of the model."
14
+
10
15
  def create
11
16
  template "resource/resource.tt", "app/avo/resources/#{resource_name}.rb"
12
17
  template "resource/controller.tt", "app/controllers/avo/#{controller_name}.rb"
@@ -33,6 +38,282 @@ module Generators
33
38
  model.capitalize.singularize.camelize
34
39
  end
35
40
  end
41
+
42
+ def class_from_args
43
+ @class_from_args ||= options["model-class"]&.capitalize
44
+ end
45
+
46
+ def model_class_from_args
47
+ "\n self.model_class = ::#{class_from_args}" if class_from_args.present?
48
+ end
49
+
50
+ private
51
+
52
+ def model_class
53
+ @model_class ||= class_from_args || singular_name
54
+ end
55
+
56
+ def model
57
+ @model ||= model_class.classify.safe_constantize
58
+ end
59
+
60
+ def model_db_columns
61
+ @model_db_columns ||= model.columns_hash.reject { |name, _| db_columns_to_ignore.include? name }
62
+ end
63
+
64
+ def db_columns_to_ignore
65
+ %w[id encrypted_password reset_password_token reset_password_sent_at remember_created_at created_at updated_at]
66
+ end
67
+
68
+ def reflections
69
+ @reflections ||= model.reflections.reject do |name, _|
70
+ reflections_sufixes_to_ignore.include?(name.split("_").pop) || reflections_to_ignore.include?(name)
71
+ end
72
+ end
73
+
74
+ def reflections_sufixes_to_ignore
75
+ %w[blob blobs tags]
76
+ end
77
+
78
+ def reflections_to_ignore
79
+ %w[taggings]
80
+ end
81
+
82
+ def attachments
83
+ @attachments ||= reflections.select do |_, reflection|
84
+ reflection.options[:class_name] == "ActiveStorage::Attachment"
85
+ end
86
+ end
87
+
88
+ def tags
89
+ @tags ||= reflections.select { |_, reflection| reflection.options[:as] == :taggable }
90
+ end
91
+
92
+ def associations
93
+ @associations ||= reflections.reject { |key| attachments.key?(key) || tags.key?(key) }
94
+ end
95
+
96
+ def fields
97
+ @fields ||= {}
98
+ end
99
+
100
+ def invoked_by_model_generator?
101
+ @options.dig("from_model_generator")
102
+ end
103
+
104
+ def generate_fields
105
+ return generate_fields_from_args if invoked_by_model_generator?
106
+
107
+ if model.blank?
108
+ puts "Can't generate fields from model. '#{model_class}.rb' not found!"
109
+ return
110
+ end
111
+
112
+ fields_from_model_db_columns
113
+ fields_from_model_enums
114
+ fields_from_model_attachements
115
+ fields_from_model_associations
116
+ fields_from_model_tags
117
+
118
+ generated_fields_template
119
+ end
120
+
121
+ def generated_fields_template
122
+ return if fields.blank?
123
+
124
+ fields_string = "\n # Fields generated from the model"
125
+
126
+ fields.each do |field_name, field_options|
127
+ options = ""
128
+ field_options[:options].each { |k, v| options += ", #{k}: #{v}" } if field_options[:options].present?
129
+
130
+ fields_string += "\n #{field_string field_name, field_options[:field], options}"
131
+ end
132
+
133
+ fields_string
134
+ end
135
+
136
+ def field_string(name, type, options)
137
+ "field :#{name}, as: :#{type}#{options}"
138
+ end
139
+
140
+ def generate_fields_from_args
141
+ @args.each do |arg|
142
+ name, type = arg.split(":")
143
+ type = "string" if type.blank?
144
+ fields[name] = field(name, type.to_sym)
145
+ end
146
+
147
+ generated_fields_template
148
+ end
149
+
150
+ def fields_from_model_tags
151
+ tags.each do |name, _|
152
+ fields[(remove_last_word_from name).pluralize] = {field: "tags"}
153
+ end
154
+ end
155
+
156
+ def fields_from_model_associations
157
+ associations.each do |name, association|
158
+ fields[name] = associations_mapping[association.class]
159
+
160
+ if association.is_a? ActiveRecord::Reflection::ThroughReflection
161
+ fields[name][:options][:through] = ":#{association.options[:through]}"
162
+ end
163
+ end
164
+ end
165
+
166
+ def fields_from_model_attachements
167
+ attachments.each do |name, attachment|
168
+ fields[remove_last_word_from name] = attachments_mapping[attachment.class]
169
+ end
170
+ end
171
+
172
+ # "hello_world_hehe".split('_') => ['hello', 'world', 'hehe']
173
+ # ['hello', 'world', 'hehe'].pop => ['hello', 'world']
174
+ # ['hello', 'world'].join('_') => "hello_world"
175
+ def remove_last_word_from(snake_case_string)
176
+ snake_case_string = snake_case_string.split("_")
177
+ snake_case_string.pop
178
+ snake_case_string.join("_")
179
+ end
180
+
181
+ def fields_from_model_enums
182
+ model.defined_enums.each_key do |enum|
183
+ fields[enum] = {
184
+ field: "select",
185
+ options: {
186
+ enum: "::#{model_class.capitalize}.#{enum.pluralize}"
187
+ }
188
+ }
189
+ end
190
+ end
191
+
192
+ def fields_from_model_db_columns
193
+ model_db_columns.each do |name, data|
194
+ fields[name] = field(name, data.type)
195
+ end
196
+ end
197
+
198
+ def field(name, type)
199
+ names_mapping[name.to_sym] || fields_mapping[type.to_sym] || {field: "text"}
200
+ end
201
+
202
+ def associations_mapping
203
+ {
204
+ ActiveRecord::Reflection::BelongsToReflection => {
205
+ field: "belongs_to"
206
+ },
207
+ ActiveRecord::Reflection::HasOneReflection => {
208
+ field: "has_one"
209
+ },
210
+ ActiveRecord::Reflection::HasManyReflection => {
211
+ field: "has_many"
212
+ },
213
+ ActiveRecord::Reflection::ThroughReflection => {
214
+ field: "has_many",
215
+ options: {
216
+ through: ":..."
217
+ }
218
+ },
219
+ ActiveRecord::Reflection::HasAndBelongsToManyReflection => {
220
+ field: "has_and_belongs_to_many"
221
+ }
222
+ }
223
+ end
224
+
225
+ def attachments_mapping
226
+ {
227
+ ActiveRecord::Reflection::HasOneReflection => {
228
+ field: "file"
229
+ },
230
+ ActiveRecord::Reflection::HasManyReflection => {
231
+ field: "files"
232
+ }
233
+ }
234
+ end
235
+
236
+ def names_mapping
237
+ {
238
+ id: {
239
+ field: "id"
240
+ },
241
+ description: {
242
+ field: "textarea"
243
+ },
244
+ gravatar: {
245
+ field: "gravatar"
246
+ },
247
+ email: {
248
+ field: "text"
249
+ },
250
+ password: {
251
+ field: "password"
252
+ },
253
+ password_confirmation: {
254
+ field: "password"
255
+ },
256
+ stage: {
257
+ field: "select"
258
+ },
259
+ budget: {
260
+ field: "currency"
261
+ },
262
+ money: {
263
+ field: "currency"
264
+ },
265
+ country: {
266
+ field: "country"
267
+ }
268
+ }
269
+ end
270
+
271
+ def fields_mapping
272
+ {
273
+ primary_key: {
274
+ field: "id"
275
+ },
276
+ string: {
277
+ field: "text"
278
+ },
279
+ text: {
280
+ field: "textarea"
281
+ },
282
+ integer: {
283
+ field: "number"
284
+ },
285
+ float: {
286
+ field: "number"
287
+ },
288
+ decimal: {
289
+ field: "number"
290
+ },
291
+ datetime: {
292
+ field: "datetime"
293
+ },
294
+ timestamp: {
295
+ field: "datetime"
296
+ },
297
+ time: {
298
+ field: "datetime"
299
+ },
300
+ date: {
301
+ field: "date"
302
+ },
303
+ binary: {
304
+ field: "number"
305
+ },
306
+ boolean: {
307
+ field: "boolean"
308
+ },
309
+ references: {
310
+ field: "belongs_to"
311
+ },
312
+ json: {
313
+ field: "code"
314
+ }
315
+ }
316
+ end
36
317
  end
37
318
  end
38
319
  end
@@ -1,5 +1,8 @@
1
1
  class <%= class_name.camelize %> < Avo::BaseAction
2
2
  self.name = "<%= name.underscore.humanize %>"
3
+ # self.visible = -> do
4
+ # true
5
+ # end
3
6
 
4
7
  def handle(**args)
5
8
  models, fields, current_user, resource = args.values_at(:models, :fields, :current_user, :resource)
@@ -1,5 +1,8 @@
1
1
  class <%= class_name.camelize %> < Avo::Filters::BooleanFilter
2
2
  self.name = "<%= name.underscore.humanize %>"
3
+ # self.visible = -> do
4
+ # true
5
+ # end
3
6
 
4
7
  def apply(request, query, values)
5
8
  query
@@ -1,5 +1,8 @@
1
1
  class <%= class_name.camelize %> < Avo::Filters::MultipleSelectFilter
2
2
  self.name = "<%= name.underscore.humanize %>"
3
+ # self.visible = -> do
4
+ # true
5
+ # end
3
6
 
4
7
  def apply(request, query, value)
5
8
  query
@@ -1,5 +1,8 @@
1
1
  class <%= class_name.camelize %> < Avo::Filters::SelectFilter
2
2
  self.name = "<%= name.underscore.humanize %>"
3
+ # self.visible = -> do
4
+ # true
5
+ # end
3
6
 
4
7
  def apply(request, query, value)
5
8
  query
@@ -1,6 +1,9 @@
1
1
  class <%= class_name.camelize %> < Avo::Filters::TextFilter
2
2
  self.name = "<%= name.underscore.humanize %>"
3
3
  self.button_label = 'Filter by <%= class_name.underscore.humanize.downcase.gsub(' filter', '') %>'
4
+ # self.visible = -> do
5
+ # true
6
+ # end
4
7
 
5
8
  def apply(request, query, value)
6
9
  query
@@ -44,6 +44,10 @@ Avo.configure do |config|
44
44
  # config.via_per_page = 8
45
45
  # config.id_links_to_resource = false
46
46
  # config.cache_resources_on_index_view = true
47
+ ## permanent enable or disable cache_resource_filters, default value is false
48
+ # config.cache_resource_filters = false
49
+ ## provide a lambda to enable or disable cache_resource_filters per user/resource.
50
+ # config.cache_resource_filters = ->(current_user:, resource:) { current_user.cache_resource_filters?}
47
51
 
48
52
  ## == Customization ==
49
53
  # config.app_name = 'Avocadelicious'
@@ -1,4 +1,4 @@
1
1
  # This controller has been generated to enable Rails' resource routes.
2
- # You shouldn't need to modify it in order to use Avo.
2
+ # More information on https://docs.avohq.io/2.0/controllers.html
3
3
  class <%= controller_class %> < Avo::ResourcesController
4
4
  end
@@ -1,10 +1,10 @@
1
1
  class <%= resource_class %> < Avo::BaseResource
2
2
  self.title = :id
3
- self.includes = []
3
+ self.includes = []<%= model_class_from_args %>
4
4
  # self.search_query = -> do
5
5
  # scope.ransack(id_eq: params[:q], m: "or").result(distinct: false)
6
6
  # end
7
7
 
8
- field :id, as: :id
8
+ field :id, as: :id<%= generate_fields %>
9
9
  # add fields here
10
10
  end
@@ -0,0 +1,10 @@
1
+ require 'rails/generators'
2
+ require 'rails/generators/rails/model/model_generator'
3
+
4
+ module Rails
5
+ module Generators
6
+ class ModelGenerator
7
+ hook_for :avo_resource, type: :boolean, default: true unless ARGV.include?("--skip-avo-resource")
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,11 @@
1
+ require 'rails/generators/active_record/model/model_generator'
2
+
3
+ module Rails
4
+ module Generators
5
+ class AvoResourceGenerator < ::Rails::Generators::Base
6
+ def invoke_avo_command
7
+ invoke "avo:resource", @args, {from_model_generator: true}
8
+ end
9
+ end
10
+ end
11
+ end
@@ -7783,16 +7783,6 @@ trix-toolbar .trix-button-group:not(:first-child){
7783
7783
  line-height:1.5rem
7784
7784
  }
7785
7785
 
7786
- .text-3xl{
7787
- font-size:1.875rem;
7788
- line-height:2.25rem
7789
- }
7790
-
7791
- .text-5xl{
7792
- font-size:3rem;
7793
- line-height:1
7794
- }
7795
-
7796
7786
  .text-xl{
7797
7787
  font-size:1.25rem;
7798
7788
  line-height:1.75rem
@@ -7803,6 +7793,16 @@ trix-toolbar .trix-button-group:not(:first-child){
7803
7793
  line-height:1rem
7804
7794
  }
7805
7795
 
7796
+ .text-3xl{
7797
+ font-size:1.875rem;
7798
+ line-height:2.25rem
7799
+ }
7800
+
7801
+ .text-5xl{
7802
+ font-size:3rem;
7803
+ line-height:1
7804
+ }
7805
+
7806
7806
  .text-2xl{
7807
7807
  font-size:1.5rem;
7808
7808
  line-height:2rem