avo 0.5.0.beta4 → 0.5.0.beta5

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 (133) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +4 -2
  3. data/Gemfile.lock +1 -1
  4. data/app/components/avo/index/grid_item_component.html.erb +8 -8
  5. data/app/components/avo/index/grid_item_component.rb +6 -12
  6. data/app/components/avo/index/resource_table_component.html.erb +1 -1
  7. data/app/components/avo/index/table_row_component.html.erb +1 -1
  8. data/app/controllers/avo/actions_controller.rb +2 -4
  9. data/app/controllers/avo/application_controller.rb +6 -3
  10. data/app/controllers/avo/base_controller.rb +0 -3
  11. data/app/controllers/avo/relations_controller.rb +1 -1
  12. data/app/controllers/avo/search_controller.rb +1 -1
  13. data/app/frontend/packs/application.js +1 -1
  14. data/app/views/avo/base/_actions.html.erb +0 -6
  15. data/app/views/avo/base/_boolean_filter.html.erb +1 -1
  16. data/app/views/avo/base/_filters.html.erb +3 -11
  17. data/app/views/avo/base/_select_filter.html.erb +1 -1
  18. data/app/views/avo/home/_resources.html.erb +0 -1
  19. data/app/views/layouts/avo/_filter_wrapper.html.erb +1 -1
  20. data/app/views/layouts/avo/application.html.erb +5 -0
  21. data/config/webpacker.yml +10 -23
  22. data/lib/avo.rb +5 -16
  23. data/lib/avo/app.rb +190 -0
  24. data/lib/avo/base_action.rb +115 -0
  25. data/lib/avo/base_resource.rb +321 -0
  26. data/lib/avo/configuration.rb +6 -0
  27. data/lib/avo/engine.rb +12 -31
  28. data/lib/avo/{app/fields → fields}/badge_field.rb +1 -1
  29. data/lib/avo/{app/fields/field.rb → fields/base_field.rb} +3 -7
  30. data/lib/avo/{app/fields/belongs_to.rb → fields/belongs_to_field.rb} +3 -3
  31. data/lib/avo/{app/fields → fields}/boolean_field.rb +1 -1
  32. data/lib/avo/{app/fields → fields}/boolean_group_field.rb +1 -1
  33. data/lib/avo/{app/fields → fields}/code_field.rb +1 -1
  34. data/lib/avo/{app/fields → fields}/country_field.rb +1 -1
  35. data/lib/avo/{app/fields → fields}/currency_field.rb +1 -1
  36. data/lib/avo/{app/fields → fields}/date_field.rb +0 -2
  37. data/lib/avo/{app/fields → fields}/date_time_field.rb +0 -2
  38. data/lib/avo/{app/fields → fields}/external_image_field.rb +1 -1
  39. data/lib/avo/{app/fields → fields}/field_extensions/has_field_name.rb +0 -0
  40. data/lib/avo/{app/fields → fields}/field_extensions/visible_in_different_views.rb +1 -1
  41. data/lib/avo/{app/fields → fields}/file_field.rb +1 -2
  42. data/lib/avo/{app/fields → fields}/files_field.rb +1 -2
  43. data/lib/avo/{app/fields → fields}/gravatar_field.rb +1 -1
  44. data/lib/avo/{app/fields/has_and_belongs_to_many.rb → fields/has_and_belongs_to_many_field.rb} +1 -1
  45. data/lib/avo/{app/fields/has_many.rb → fields/has_many_field.rb} +1 -1
  46. data/lib/avo/{app/fields/has_one.rb → fields/has_one_field.rb} +1 -1
  47. data/lib/avo/{app/fields → fields}/heading_field.rb +1 -1
  48. data/lib/avo/{app/fields → fields}/hidden_field.rb +0 -2
  49. data/lib/avo/{app/fields → fields}/id_field.rb +1 -1
  50. data/lib/avo/{app/fields → fields}/key_value_field.rb +1 -1
  51. data/lib/avo/{app/fields → fields}/markdown_field.rb +1 -3
  52. data/lib/avo/{app/fields → fields}/number_field.rb +0 -2
  53. data/lib/avo/{app/fields → fields}/password_field.rb +0 -2
  54. data/lib/avo/{app/fields → fields}/select_field.rb +1 -1
  55. data/lib/avo/{app/fields → fields}/status_field.rb +1 -1
  56. data/lib/avo/{app/fields → fields}/text_field.rb +1 -1
  57. data/lib/avo/{app/fields → fields}/textarea_field.rb +0 -2
  58. data/lib/avo/{app/fields → fields}/trix_field.rb +1 -3
  59. data/lib/avo/filters/base_filter.rb +20 -0
  60. data/lib/avo/filters/boolean_filter.rb +7 -0
  61. data/lib/avo/filters/select_filter.rb +7 -0
  62. data/lib/avo/{app/grid_fields → grid_fields}/body_field.rb +0 -2
  63. data/lib/avo/{app/grid_fields → grid_fields}/grid_field.rb +0 -0
  64. data/lib/avo/{app/grid_fields → grid_fields}/preview_field.rb +0 -2
  65. data/lib/avo/{app/grid_fields → grid_fields}/title_field.rb +0 -2
  66. data/lib/avo/licensing/community_license.rb +6 -0
  67. data/lib/avo/licensing/h_q.rb +88 -0
  68. data/lib/avo/licensing/license.rb +50 -0
  69. data/lib/avo/licensing/license_manager.rb +22 -0
  70. data/lib/avo/licensing/null_license.rb +14 -0
  71. data/lib/avo/licensing/pro_license.rb +11 -0
  72. data/lib/avo/loaders/actions_loader.rb +6 -0
  73. data/lib/avo/loaders/fields_loader.rb +27 -0
  74. data/lib/avo/loaders/filters_loader.rb +6 -0
  75. data/lib/avo/loaders/loader.rb +15 -0
  76. data/lib/avo/services/authorization_service.rb +93 -0
  77. data/lib/avo/services/panel_service.rb +27 -0
  78. data/lib/avo/{app/tools_manager.rb → tools_manager.rb} +0 -0
  79. data/lib/avo/version.rb +1 -1
  80. data/lib/generators/avo/action_generator.rb +11 -5
  81. data/lib/generators/avo/controller_generator.rb +14 -8
  82. data/lib/generators/avo/filter_generator.rb +14 -8
  83. data/lib/generators/avo/install_generator.rb +14 -10
  84. data/lib/generators/avo/locales_generator.rb +11 -7
  85. data/lib/generators/avo/partials_generator.rb +11 -5
  86. data/lib/generators/avo/resource_generator.rb +33 -15
  87. data/lib/generators/avo/templates/{action.rb → action.tt} +2 -4
  88. data/lib/generators/avo/templates/filters/boolean_filter.tt +11 -0
  89. data/lib/generators/avo/templates/filters/select_filter.tt +11 -0
  90. data/lib/generators/avo/templates/initializer/{avo.rb → avo.tt} +6 -0
  91. data/lib/generators/avo/templates/resource/controller.tt +2 -0
  92. data/lib/generators/avo/templates/resource/resource.tt +17 -0
  93. data/public/avo-packs/css/{application-3598cfbb.css → application-c75ac28c.css} +1 -1
  94. data/public/avo-packs/css/application-c75ac28c.css.br +0 -0
  95. data/public/avo-packs/css/{application-3598cfbb.css.gz → application-c75ac28c.css.gz} +0 -0
  96. data/public/avo-packs/js/{application-6ba2bd1bca05d69b96e0.js → application-8849c6e2c8f75d55c666.js} +3 -3
  97. data/public/avo-packs/js/{application-6ba2bd1bca05d69b96e0.js.LICENSE.txt → application-8849c6e2c8f75d55c666.js.LICENSE.txt} +0 -0
  98. data/public/avo-packs/js/application-8849c6e2c8f75d55c666.js.br +0 -0
  99. data/public/avo-packs/js/application-8849c6e2c8f75d55c666.js.gz +0 -0
  100. data/public/avo-packs/js/{application-6ba2bd1bca05d69b96e0.js.map → application-8849c6e2c8f75d55c666.js.map} +1 -1
  101. data/public/avo-packs/js/application-8849c6e2c8f75d55c666.js.map.br +0 -0
  102. data/public/avo-packs/js/{application-6ba2bd1bca05d69b96e0.js.map.gz → application-8849c6e2c8f75d55c666.js.map.gz} +0 -0
  103. data/public/avo-packs/manifest.json +6 -6
  104. data/public/avo-packs/manifest.json.br +0 -0
  105. data/public/avo-packs/manifest.json.gz +0 -0
  106. metadata +72 -73
  107. data/config/webpacker_packed.yml +0 -86
  108. data/lib/avo/app/action.rb +0 -145
  109. data/lib/avo/app/actions_loader.rb +0 -11
  110. data/lib/avo/app/app.rb +0 -183
  111. data/lib/avo/app/fields_loader.rb +0 -29
  112. data/lib/avo/app/filter.rb +0 -23
  113. data/lib/avo/app/filters/boolean_filter.rb +0 -13
  114. data/lib/avo/app/filters/select_filter.rb +0 -13
  115. data/lib/avo/app/licensing/community_license.rb +0 -4
  116. data/lib/avo/app/licensing/hq.rb +0 -86
  117. data/lib/avo/app/licensing/license.rb +0 -48
  118. data/lib/avo/app/licensing/license_manager.rb +0 -25
  119. data/lib/avo/app/licensing/null_license.rb +0 -12
  120. data/lib/avo/app/licensing/pro_license.rb +0 -9
  121. data/lib/avo/app/resource.rb +0 -299
  122. data/lib/avo/app/resource_grid_fields.rb +0 -30
  123. data/lib/avo/app/services/authorization_service.rb +0 -110
  124. data/lib/avo/app/services/panel_service.rb +0 -25
  125. data/lib/avo/app/tool.rb +0 -5
  126. data/lib/generators/avo/templates/filters/boolean_filter.rb +0 -17
  127. data/lib/generators/avo/templates/filters/select_filter.rb +0 -17
  128. data/lib/generators/avo/templates/resource/%plural_name%_controller.tt +0 -2
  129. data/lib/generators/avo/templates/resource/%singular_name%.tt +0 -20
  130. data/public/avo-packs/css/application-3598cfbb.css.br +0 -0
  131. data/public/avo-packs/js/application-6ba2bd1bca05d69b96e0.js.br +0 -0
  132. data/public/avo-packs/js/application-6ba2bd1bca05d69b96e0.js.gz +0 -0
  133. data/public/avo-packs/js/application-6ba2bd1bca05d69b96e0.js.map.br +0 -0
@@ -0,0 +1,115 @@
1
+ module Avo
2
+ class BaseAction
3
+ class_attribute :name, default: self.class.to_s.demodulize.underscore.humanize(keep_id_suffix: true)
4
+ class_attribute :message, default: I18n.t('avo.are_you_sure_you_want_to_run_this_option')
5
+ class_attribute :confirm_text, default: I18n.t('avo.run')
6
+ class_attribute :cancel_text, default: I18n.t('avo.cancel')
7
+ class_attribute :no_confirmation, default: false
8
+
9
+ attr_accessor :response
10
+ attr_accessor :model
11
+ attr_accessor :resource
12
+ attr_accessor :user
13
+
14
+ attr_accessor :field_loader
15
+
16
+ alias :field :field_loader
17
+ alias :f :field
18
+
19
+ def initialize
20
+ @fields ||= []
21
+ @response ||= {}
22
+ @response[:message_type] ||= :notice
23
+ @response[:message] ||= I18n.t('avo.action_ran_successfully')
24
+ end
25
+
26
+ def boot_fields(request)
27
+ @field_loader = Avo::Loaders::FieldsLoader.new
28
+ fields request if self.respond_to? :fields
29
+ end
30
+
31
+ def get_fields(view_type: :table)
32
+ get_field_definitions.map do |field|
33
+ field.hydrate(action: self, model: @model)
34
+ end
35
+ .select do |field|
36
+ field.can_see.present? ? field.can_see.call : true
37
+ end
38
+ end
39
+
40
+ def get_field_definitions
41
+ @field_loader.bag.map do |field|
42
+ field.hydrate(action: self)
43
+ end
44
+ end
45
+
46
+ def hydrate(model: nil, resource: nil, user: nil)
47
+ @model = model if model.present?
48
+ @resource = resource if resource.present?
49
+ @user = user if user.present?
50
+
51
+ self
52
+ end
53
+
54
+ def handle_action(request, models, raw_fields)
55
+ avo_fields = get_fields.map { |field| [field.id, field] }.to_h
56
+
57
+ if raw_fields.present?
58
+ fields = raw_fields.to_unsafe_h.map do |name, value|
59
+ [name, avo_fields[name.to_sym].resolve_attribute(value)]
60
+ end
61
+
62
+ fields = fields.to_h
63
+ else
64
+ fields = {}
65
+ end
66
+
67
+ result = self.handle request, models, fields
68
+
69
+ self
70
+ end
71
+
72
+ def param_id
73
+ self.class.to_s.demodulize.underscore.gsub '/', '_'
74
+ end
75
+
76
+ def succeed(text)
77
+ self.response[:message_type] = :notice
78
+ self.response[:message] = text
79
+
80
+ self
81
+ end
82
+
83
+ def fail(text)
84
+ self.response[:message_type] = :alert
85
+ self.response[:message] = text
86
+
87
+ self
88
+ end
89
+
90
+ def redirect_to(path = nil, &block)
91
+ self.response[:type] = :redirect
92
+ if block.present?
93
+ self.response[:path] = block
94
+ else
95
+ self.response[:path] = path
96
+ end
97
+
98
+ self
99
+ end
100
+
101
+ def reload
102
+ self.response[:type] = :reload
103
+
104
+ self
105
+ end
106
+
107
+ def download(path, filename)
108
+ self.response[:type] = :download
109
+ self.response[:path] = path
110
+ self.response[:filename] = filename
111
+
112
+ self
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,321 @@
1
+ module Avo
2
+ class BaseResource
3
+ extend ActiveSupport::DescendantsTracker
4
+
5
+ attr_accessor :view
6
+ attr_accessor :model
7
+ attr_accessor :user
8
+ attr_accessor :params
9
+
10
+ class_attribute :id, default: :id
11
+ class_attribute :title, default: :id
12
+ class_attribute :search, default: [:id]
13
+ class_attribute :includes, default: []
14
+ class_attribute :translation_key
15
+ class_attribute :default_view_type, default: :table
16
+ class_attribute :devise_password_optional, default: false
17
+ class_attribute :fields_loader
18
+ class_attribute :actions_loader
19
+ class_attribute :filters_loader
20
+ class_attribute :grid_cover_loader
21
+ class_attribute :grid_title_loader
22
+ class_attribute :grid_body_loader
23
+
24
+ class << self
25
+ def fields(&block)
26
+ self.fields_loader ||= Avo::Loaders::FieldsLoader.new
27
+
28
+ yield(fields_loader)
29
+ end
30
+
31
+ def actions(&block)
32
+ self.actions_loader ||= Avo::Loaders::ActionsLoader.new
33
+
34
+ yield(actions_loader)
35
+ end
36
+
37
+ def filters(&block)
38
+ self.filters_loader ||= Avo::Loaders::FiltersLoader.new
39
+
40
+ yield(filters_loader)
41
+ end
42
+
43
+ def grid(&block)
44
+ self.grid_cover_loader ||= Avo::Loaders::FieldsLoader.new
45
+ self.grid_title_loader ||= Avo::Loaders::FieldsLoader.new
46
+ self.grid_body_loader ||= Avo::Loaders::FieldsLoader.new
47
+
48
+ yield(grid_cover_loader, grid_title_loader, grid_body_loader)
49
+ end
50
+
51
+ def context
52
+ App.context
53
+ end
54
+ end
55
+
56
+ def hydrate(model: nil, view: nil, user: nil, params: nil)
57
+ @view = view if view.present?
58
+ @user = user if user.present?
59
+ @params = params if params.present?
60
+
61
+ if model.present?
62
+ @model = model
63
+
64
+ hydrate_model_with_default_values if @view == :new
65
+ end
66
+
67
+ self
68
+ end
69
+
70
+ def get_fields(panel: nil, reflection: nil)
71
+ fields = get_field_definitions.select do |field|
72
+ field.send("show_on_#{@view.to_s}")
73
+ end
74
+ .select do |field|
75
+ field.can_see.present? ? field.can_see.call : true
76
+ end
77
+ .select do |field|
78
+ unless field.respond_to?(:foreign_key) &&
79
+ reflection.present? &&
80
+ reflection.respond_to?(:foreign_key) &&
81
+ reflection.foreign_key == field.foreign_key
82
+ true
83
+ end
84
+ end
85
+
86
+ if panel.present?
87
+ fields = fields.select do |field|
88
+ field.panel_name == panel
89
+ end
90
+ end
91
+
92
+ fields = fields.map do |field|
93
+ field.hydrate(model: @model, view: @view, resource: self)
94
+ end
95
+
96
+ fields
97
+ end
98
+
99
+ def get_grid_fields
100
+ return if self.class.grid_title_loader.blank?
101
+
102
+ card = {
103
+ cover: [*self.class.grid_cover_loader.bag],
104
+ title: [*self.class.grid_title_loader.bag],
105
+ body: [*self.class.grid_body_loader.bag],
106
+ }
107
+
108
+ card.each do |section, fields|
109
+ fields = fields.map do |field|
110
+ field.hydrate(model: @model, view: @view, resource: self)
111
+ end
112
+ end
113
+ end
114
+
115
+ def get_filters
116
+ return [] if self.class.filters_loader.blank?
117
+
118
+ self.class.filters_loader.bag
119
+ end
120
+
121
+ def get_actions
122
+ return [] if self.class.actions_loader.blank?
123
+
124
+ self.class.actions_loader.bag
125
+ end
126
+
127
+ def get_field_definitions
128
+ self.class.fields_loader.bag.map do |field|
129
+ field.hydrate(resource: self, panel_name: default_panel_name, user: user)
130
+ end
131
+ end
132
+
133
+ def default_panel_name
134
+ return @params[:related_name].capitalize if @params[:related_name].present?
135
+
136
+ case @view
137
+ when :show
138
+ I18n.t('avo.resource_details', item: self.name.downcase, title: model_title).upcase_first
139
+ when :edit
140
+ I18n.t('avo.update_item', item: self.name.downcase, title: model_title).upcase_first
141
+ when :new
142
+ I18n.t('avo.create_new_item', item: self.name.downcase).upcase_first
143
+ end
144
+ end
145
+
146
+ def panels
147
+ panels = [
148
+ {
149
+ name: default_panel_name,
150
+ type: :fields,
151
+ in_panel: true,
152
+ }
153
+ ]
154
+
155
+ panels
156
+ end
157
+
158
+ def model_class
159
+ return @model.class if @model.present?
160
+
161
+ self.class.name.demodulize.chomp('Resource').safe_constantize
162
+ end
163
+
164
+ def model_title
165
+ return @model.send title if @model.present?
166
+
167
+ name
168
+ end
169
+
170
+ def name
171
+ return @name if @name.present?
172
+
173
+ return I18n.t(@translation_key, count: 1).capitalize if @translation_key
174
+
175
+ self.class.name.demodulize.chomp('Resource').titlecase
176
+ end
177
+
178
+ def singular_name
179
+ name
180
+ end
181
+
182
+ def plural_name
183
+ return I18n.t(@translation_key, count: 2).capitalize if @translation_key
184
+
185
+ name.pluralize
186
+ end
187
+
188
+ def underscore_name
189
+ return @name if @name.present?
190
+
191
+ self.class.name.demodulize.underscore
192
+ end
193
+
194
+ def available_view_types
195
+ view_types = [:table]
196
+
197
+ view_types << :grid if get_grid_fields.present?
198
+
199
+ view_types
200
+ end
201
+
202
+ def route_key
203
+ model_class.model_name.route_key
204
+ end
205
+
206
+ def context
207
+ App.context
208
+ end
209
+
210
+ # def fields
211
+ # raise NotImplementedError
212
+ # end
213
+
214
+ def query_search(query: '', via_resource_name: , via_resource_id:, user:)
215
+ # model_class = self.model
216
+
217
+ db_query = AuthorizationService.apply_policy(user, model_class)
218
+
219
+ if via_resource_name.present?
220
+ related_model = App.get_resource_by_name(via_resource_name).model
221
+
222
+ db_query = related_model.find(via_resource_id).public_send(self.plural_name.downcase)
223
+ end
224
+
225
+ new_query = []
226
+
227
+ [self.search].flatten.each_with_index do |search_by, index|
228
+ new_query.push 'or' if index != 0
229
+
230
+ new_query.push "text(#{search_by}) ILIKE '%#{query}%'"
231
+ end
232
+
233
+ db_query.where(new_query.join(' '))
234
+ end
235
+
236
+ def attached_file_fields
237
+ get_field_definitions.select do |field|
238
+ [Avo::Fields::FileField, Avo::Fields::FilesField].include? field.class
239
+ end
240
+ end
241
+
242
+ def fill_model(model, params)
243
+ # Map the received params to their actual fields
244
+ fields_by_database_id = self.get_field_definitions.map { |field| [field.database_id(model).to_s, field] }.to_h
245
+
246
+ params.each do |key, value|
247
+ field = fields_by_database_id[key]
248
+
249
+ next unless field
250
+
251
+ model = field.fill_field model, key, value
252
+ end
253
+
254
+ model
255
+ end
256
+
257
+ def authorization
258
+ Avo::Services::AuthorizationService.new(user, model)
259
+ end
260
+
261
+ def file_hash
262
+ content_to_be_hashed = ''
263
+
264
+ # resource file hash
265
+ resource_path = Rails.root.join('app', 'avo', 'resources', "#{name.underscore}.rb").to_s
266
+ if File.file? resource_path
267
+ content_to_be_hashed += File.read(resource_path)
268
+ end
269
+
270
+ # policy file hash
271
+ policy_path = Rails.root.join('app', 'policies', "#{name.underscore}_policy.rb").to_s
272
+ if File.file? policy_path
273
+ content_to_be_hashed += File.read(policy_path)
274
+ end
275
+
276
+ Digest::MD5.hexdigest(content_to_be_hashed)
277
+ end
278
+
279
+ def cache_hash(parent_model)
280
+ if parent_model.present?
281
+ [self.model, self.file_hash, parent_model]
282
+ else
283
+ [self.model, self.file_hash]
284
+ end
285
+ end
286
+
287
+ # For :new views we're hydrating the model with the values from the resource's default attribute.
288
+ # We will not overwrite any attributes that come pre-filled in the model.
289
+ def hydrate_model_with_default_values
290
+ default_values = get_fields.select do |field|
291
+ !field.computed
292
+ end
293
+ .map do |field|
294
+ id = field.id
295
+ value = field.value
296
+
297
+ if field.respond_to? :foreign_key
298
+ id = field.foreign_key.to_sym
299
+
300
+ reflection = @model._reflections[@params[:via_relation]]
301
+
302
+ if reflection.present? && reflection.foreign_key.present?
303
+ value = @params[:via_resource_id]
304
+ end
305
+ end
306
+
307
+ [id, value]
308
+ end
309
+ .to_h
310
+ .select do |id, value|
311
+ value.present?
312
+ end
313
+
314
+ default_values.each do |id, value|
315
+ if @model.send(id).nil?
316
+ @model.send("#{id}=", value)
317
+ end
318
+ end
319
+ end
320
+ end
321
+ end
@@ -20,6 +20,7 @@ module Avo
20
20
  attr_accessor :full_width_container
21
21
  attr_accessor :full_width_index_view
22
22
  attr_accessor :cache_resources_on_index_view
23
+ attr_accessor :context
23
24
 
24
25
  def initialize
25
26
  @root_path = '/avo'
@@ -50,6 +51,7 @@ module Avo
50
51
  @full_width_container = false
51
52
  @full_width_index_view = false
52
53
  @cache_resources_on_index_view = Avo::PACKED
54
+ @context = proc {}
53
55
  end
54
56
 
55
57
  def locale_tag
@@ -71,6 +73,10 @@ module Avo
71
73
  def authenticate_with(&block)
72
74
  @authenticate = block if block.present?
73
75
  end
76
+
77
+ def set_context(&block)
78
+ @context = block if block.present?
79
+ end
74
80
  end
75
81
 
76
82
  def self.configuration