avo 3.0.0.beta1 → 3.0.0.pre1

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 (215) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +5 -5
  3. data/Gemfile.lock +81 -92
  4. data/{public/avo-assets/avo.css → app/assets/builds/avo.base.css} +686 -728
  5. data/app/assets/builds/avo.base.js +93804 -0
  6. data/app/assets/builds/avo.base.js.map +7 -0
  7. data/app/assets/stylesheets/avo.base.css +2 -1
  8. data/app/assets/svgs/failed_to_load.svg +1 -0
  9. data/app/assets/svgs/grid-empty-state.svg +1 -0
  10. data/app/assets/svgs/table-empty-state.svg +1 -0
  11. data/app/assets/svgs/triangle-up.svg +1 -1
  12. data/app/components/avo/actions_component.html.erb +1 -1
  13. data/app/components/avo/actions_component.rb +16 -42
  14. data/app/components/avo/alert_component.html.erb +1 -1
  15. data/app/components/avo/base_component.rb +7 -7
  16. data/app/components/avo/field_wrapper_component.html.erb +4 -4
  17. data/app/components/avo/field_wrapper_component.rb +1 -1
  18. data/app/components/avo/fields/belongs_to_field/edit_component.html.erb +5 -5
  19. data/app/components/avo/fields/belongs_to_field/edit_component.rb +4 -8
  20. data/app/components/avo/fields/boolean_field/edit_component.html.erb +0 -1
  21. data/app/components/avo/fields/boolean_group_field/edit_component.html.erb +1 -1
  22. data/app/components/avo/fields/code_field/edit_component.html.erb +0 -1
  23. data/app/components/avo/fields/common/files_list_viewer_component.html.erb +5 -0
  24. data/app/components/avo/fields/common/files_list_viewer_component.rb +8 -0
  25. data/app/components/avo/fields/common/heading_component.html.erb +1 -1
  26. data/app/components/avo/fields/common/single_file_viewer_component.html.erb +56 -0
  27. data/app/components/avo/fields/common/single_file_viewer_component.rb +55 -0
  28. data/app/components/avo/fields/country_field/edit_component.html.erb +1 -3
  29. data/app/components/avo/fields/file_field/edit_component.html.erb +2 -4
  30. data/app/components/avo/fields/file_field/edit_component.rb +0 -1
  31. data/app/components/avo/fields/file_field/index_component.rb +2 -2
  32. data/app/components/avo/fields/file_field/show_component.html.erb +1 -1
  33. data/app/components/avo/fields/files_field/edit_component.html.erb +2 -4
  34. data/app/components/avo/fields/files_field/edit_component.rb +0 -1
  35. data/app/components/avo/fields/files_field/show_component.html.erb +1 -1
  36. data/app/components/avo/fields/has_many_field/show_component.html.erb +1 -1
  37. data/app/components/avo/fields/has_one_field/show_component.html.erb +4 -5
  38. data/app/components/avo/fields/has_one_field/show_component.rb +2 -6
  39. data/app/components/avo/fields/index_component.rb +0 -1
  40. data/app/components/avo/fields/markdown_field/edit_component.html.erb +3 -4
  41. data/app/components/avo/fields/markdown_field/show_component.html.erb +3 -3
  42. data/app/components/avo/fields/number_field/edit_component.html.erb +1 -3
  43. data/app/components/avo/fields/password_field/edit_component.html.erb +1 -3
  44. data/app/components/avo/fields/progress_bar_field/edit_component.html.erb +0 -1
  45. data/app/components/avo/fields/select_field/edit_component.html.erb +1 -2
  46. data/app/components/avo/fields/status_field/edit_component.html.erb +1 -1
  47. data/app/components/avo/fields/text_field/edit_component.html.erb +2 -3
  48. data/app/components/avo/fields/textarea_field/edit_component.html.erb +0 -1
  49. data/app/components/avo/fields/trix_field/edit_component.html.erb +1 -2
  50. data/app/components/avo/fields/trix_field/show_component.html.erb +1 -1
  51. data/app/components/avo/index/field_wrapper_component.html.erb +1 -1
  52. data/app/components/avo/index/field_wrapper_component.rb +12 -0
  53. data/app/components/avo/index/grid_item_component.html.erb +35 -9
  54. data/app/components/avo/index/grid_item_component.rb +10 -36
  55. data/app/components/avo/index/resource_controls_component.rb +11 -8
  56. data/app/components/avo/index/resource_table_component.rb +1 -1
  57. data/app/components/avo/item_switcher_component.html.erb +5 -10
  58. data/app/components/avo/item_switcher_component.rb +1 -2
  59. data/app/components/avo/modal_component.html.erb +1 -1
  60. data/app/components/avo/panel_component.html.erb +1 -6
  61. data/app/components/avo/panel_component.rb +0 -1
  62. data/app/components/avo/profile_item_component.html.erb +2 -17
  63. data/app/components/avo/profile_item_component.rb +1 -13
  64. data/app/components/avo/referrer_params_component.html.erb +0 -2
  65. data/app/components/avo/resource_component.rb +6 -69
  66. data/app/components/avo/resource_sidebar_component.rb +1 -1
  67. data/app/components/avo/sidebar/link_component.html.erb +0 -2
  68. data/app/components/avo/sidebar/link_component.rb +3 -5
  69. data/app/components/avo/sidebar_component.html.erb +3 -3
  70. data/app/components/avo/sidebar_component.rb +4 -4
  71. data/app/components/avo/sidebar_profile_component.html.erb +27 -27
  72. data/app/components/avo/views/resource_edit_component.html.erb +5 -5
  73. data/app/components/avo/views/resource_edit_component.rb +1 -1
  74. data/app/components/avo/views/resource_index_component.html.erb +10 -19
  75. data/app/components/avo/views/resource_index_component.rb +16 -22
  76. data/app/components/avo/views/resource_show_component.html.erb +4 -4
  77. data/app/controllers/avo/actions_controller.rb +20 -20
  78. data/app/controllers/avo/application_controller.rb +67 -90
  79. data/app/controllers/avo/associations_controller.rb +7 -5
  80. data/app/controllers/avo/attachments_controller.rb +7 -22
  81. data/app/controllers/avo/base_controller.rb +35 -47
  82. data/app/controllers/avo/home_controller.rb +1 -1
  83. data/app/controllers/avo/search_controller.rb +16 -20
  84. data/app/controllers/concerns/avo/initializes_avo.rb +8 -3
  85. data/app/helpers/avo/application_helper.rb +6 -13
  86. data/app/javascript/js/application.js +0 -2
  87. data/app/javascript/js/controllers/fields/{easy_mde_controller.js → simple_mde_controller.js} +3 -4
  88. data/app/javascript/js/controllers/search_controller.js +1 -3
  89. data/app/javascript/js/controllers.js +2 -2
  90. data/app/views/avo/actions/show.html.erb +3 -5
  91. data/app/views/avo/associations/new.html.erb +3 -3
  92. data/app/views/avo/debug/status.html.erb +5 -6
  93. data/app/views/avo/home/index.html.erb +1 -1
  94. data/app/views/avo/partials/_custom_tools_alert.html.erb +2 -2
  95. data/app/views/avo/partials/_footer.html.erb +1 -1
  96. data/app/views/avo/partials/_javascript.html.erb +1 -1
  97. data/app/views/avo/partials/_navbar.html.erb +1 -1
  98. data/app/views/avo/partials/_table_header.html.erb +8 -0
  99. data/app/views/avo/partials/_view_toggle_button.html.erb +0 -9
  100. data/app/views/avo/private/design.html.erb +2 -2
  101. data/app/views/layouts/avo/application.html.erb +3 -2
  102. data/avo.gemspec +1 -2
  103. data/config/initializers/pagy.rb +10 -12
  104. data/config/routes.rb +5 -5
  105. data/db/factories.rb +0 -17
  106. data/lib/avo/app.rb +165 -0
  107. data/lib/avo/base_action.rb +18 -31
  108. data/lib/avo/base_resource.rb +213 -238
  109. data/lib/avo/concerns/breadcrumbs.rb +2 -2
  110. data/lib/avo/concerns/can_replace_items.rb +7 -3
  111. data/lib/avo/concerns/filters_session_handler.rb +4 -5
  112. data/lib/avo/concerns/has_item_type.rb +0 -4
  113. data/lib/avo/concerns/has_items.rb +115 -93
  114. data/lib/avo/concerns/is_visible.rb +1 -1
  115. data/lib/avo/concerns/model_class_constantized.rb +2 -0
  116. data/lib/avo/configuration.rb +8 -9
  117. data/lib/avo/current.rb +1 -35
  118. data/lib/avo/dsl/field_parser.rb +1 -1
  119. data/lib/avo/dynamic_router.rb +2 -13
  120. data/lib/avo/engine.rb +13 -11
  121. data/lib/avo/execution_context.rb +2 -4
  122. data/lib/avo/fields/base_field.rb +14 -51
  123. data/lib/avo/fields/belongs_to_field.rb +13 -20
  124. data/lib/avo/fields/concerns/is_searchable.rb +1 -1
  125. data/lib/avo/fields/concerns/use_resource.rb +1 -1
  126. data/lib/avo/fields/date_field.rb +3 -16
  127. data/lib/avo/fields/field_manager.rb +3 -13
  128. data/lib/avo/fields/file_field.rb +0 -2
  129. data/lib/avo/fields/files_field.rb +0 -6
  130. data/lib/avo/fields/has_base_field.rb +5 -5
  131. data/lib/avo/fields/has_one_field.rb +1 -2
  132. data/lib/avo/fields/id_field.rb +1 -2
  133. data/lib/avo/filters/base_filter.rb +0 -9
  134. data/lib/avo/grid_collector.rb +40 -0
  135. data/lib/avo/html/builder.rb +1 -3
  136. data/lib/avo/licensing/h_q.rb +6 -11
  137. data/lib/avo/licensing/license.rb +1 -1
  138. data/lib/avo/licensing/license_manager.rb +1 -1
  139. data/lib/avo/licensing/{nil_license.rb → null_license.rb} +1 -1
  140. data/lib/avo/loaders/fields_loader.rb +1 -7
  141. data/lib/avo/plugin.rb +0 -10
  142. data/lib/avo/plugin_manager.rb +4 -2
  143. data/lib/avo/reloader.rb +1 -1
  144. data/lib/avo/resources/controls/actions_list.rb +1 -2
  145. data/lib/avo/resources/controls/create_button.rb +1 -1
  146. data/lib/avo/resources/controls/delete_button.rb +1 -1
  147. data/lib/avo/resources/controls/detach_button.rb +1 -1
  148. data/lib/avo/resources/controls/edit_button.rb +1 -1
  149. data/lib/avo/resources/controls/show_button.rb +1 -1
  150. data/lib/avo/resources/items/holder.rb +5 -13
  151. data/lib/avo/resources/items/item_group.rb +0 -1
  152. data/lib/avo/resources/resource_manager.rb +18 -11
  153. data/lib/avo/services/debug_service.rb +5 -6
  154. data/lib/avo/services/telemetry_service.rb +2 -3
  155. data/lib/avo/version.rb +1 -1
  156. data/lib/avo.rb +25 -109
  157. data/lib/generators/avo/action_generator.rb +8 -8
  158. data/lib/generators/avo/card/chartkick_generator.rb +18 -0
  159. data/lib/generators/avo/card/metric_generator.rb +18 -0
  160. data/lib/generators/avo/card/partial_generator.rb +19 -0
  161. data/lib/generators/avo/eject_generator.rb +0 -1
  162. data/lib/generators/avo/filter_generator.rb +8 -8
  163. data/lib/generators/avo/install_generator.rb +1 -11
  164. data/lib/generators/avo/resource_generator.rb +4 -22
  165. data/lib/generators/avo/tailwindcss/install_generator.rb +1 -4
  166. data/lib/generators/avo/templates/action.tt +5 -7
  167. data/lib/generators/avo/templates/cards/chartkick_card.tt +1 -1
  168. data/lib/generators/avo/templates/cards/chartkick_card_sample.tt +1 -1
  169. data/lib/generators/avo/templates/cards/metric_card.tt +1 -1
  170. data/lib/generators/avo/templates/cards/metric_card_sample.tt +1 -1
  171. data/lib/generators/avo/templates/cards/partial_card.tt +1 -1
  172. data/lib/generators/avo/templates/cards/partial_card_sample.tt +1 -1
  173. data/lib/generators/avo/templates/dashboards/dashboard.tt +3 -5
  174. data/lib/generators/avo/templates/initializer/avo.tt +2 -4
  175. data/lib/generators/avo/templates/resource/resource.tt +6 -6
  176. data/lib/generators/avo/templates/scope.tt +1 -1
  177. data/lib/generators/avo/templates/standalone_action.tt +8 -0
  178. data/lib/generators/avo/templates/tailwindcss/Procfile.dev +1 -1
  179. data/lib/tasks/avo_tasks.rake +0 -5
  180. metadata +19 -56
  181. data/app/assets/svgs/map-empty-state.svg +0 -35
  182. data/app/assets/svgs/map-view-type.svg +0 -3
  183. data/app/components/avo/fields/area_field/edit_component.html.erb +0 -7
  184. data/app/components/avo/fields/area_field/edit_component.rb +0 -4
  185. data/app/components/avo/fields/area_field/show_component.html.erb +0 -8
  186. data/app/components/avo/fields/area_field/show_component.rb +0 -4
  187. data/app/components/avo/fields/common/files/controls_component.html.erb +0 -29
  188. data/app/components/avo/fields/common/files/controls_component.rb +0 -19
  189. data/app/components/avo/fields/common/files/list_viewer_component.html.erb +0 -20
  190. data/app/components/avo/fields/common/files/list_viewer_component.rb +0 -41
  191. data/app/components/avo/fields/common/files/view_type/grid_component.html.erb +0 -27
  192. data/app/components/avo/fields/common/files/view_type/grid_component.rb +0 -51
  193. data/app/components/avo/fields/common/files/view_type/list_component.html.erb +0 -22
  194. data/app/components/avo/fields/common/files/view_type/list_component.rb +0 -15
  195. data/app/components/avo/fields/location_field/edit_component.html.erb +0 -22
  196. data/app/components/avo/fields/location_field/edit_component.rb +0 -4
  197. data/app/components/avo/fields/location_field/show_component.html.erb +0 -7
  198. data/app/components/avo/fields/location_field/show_component.rb +0 -4
  199. data/app/components/avo/index/resource_map_component.html.erb +0 -16
  200. data/app/components/avo/index/resource_map_component.rb +0 -109
  201. data/app/components/avo/row_component.html.erb +0 -3
  202. data/app/components/avo/row_component.rb +0 -12
  203. data/app/views/avo/attachments/destroy.turbo_stream.erb +0 -7
  204. data/app/views/avo/partials/_profile_menu_extra.html.erb +0 -2
  205. data/lib/avo/concerns/has_description.rb +0 -23
  206. data/lib/avo/fields/area_field.rb +0 -39
  207. data/lib/avo/fields/concerns/file_authorization.rb +0 -31
  208. data/lib/avo/fields/location_field.rb +0 -86
  209. data/lib/avo/resources/items/row.rb +0 -54
  210. data/lib/generators/avo/card_generator.rb +0 -27
  211. data/public/avo-assets/avo.base.css +0 -10542
  212. data/public/avo-assets/avo.base.js +0 -949
  213. data/public/avo-assets/avo.base.js.map +0 -7
  214. data/public/avo-assets/avo.js +0 -513
  215. data/public/avo-assets/avo.js.map +0 -7
@@ -1,4 +1,4 @@
1
- @import './../../../node_modules/easymde/dist/easymde.min.css';
1
+ @import './../../../node_modules/simplemde/dist/simplemde.min.css';
2
2
  @import './../../../node_modules/tippy.js/dist/tippy.css';
3
3
  @import './../../../node_modules/tippy.js/themes/light.css';
4
4
  @import './../../../node_modules/flatpickr/dist/flatpickr.css';
@@ -70,6 +70,7 @@ body {
70
70
  @apply opacity-0 translate-y-1;
71
71
  }
72
72
 
73
+
73
74
  .turbo-progress-bar {
74
75
  @apply bg-primary-400;
75
76
  }
@@ -9,5 +9,6 @@
9
9
  <defs>
10
10
  <stop stop-color="#E3ECFA"/>
11
11
  <stop offset="1" stop-color="#DAE7FF"/>
12
+ </linearGradient>
12
13
  </defs>
13
14
  </svg>
@@ -22,6 +22,7 @@
22
22
  <feColorMatrix type="matrix" values="0 0 0 0 0.788235 0 0 0 0 0.803922 0 0 0 0 0.85098 0 0 0 0.349 0"/>
23
23
  <feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_577_1090"/>
24
24
  <feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_577_1090" result="shape"/>
25
+ </filter>
25
26
  <filter id="filter1_d_577_1090" x="38.6401" y="0" width="170.72" height="78.1333" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
26
27
  <feFlood flood-opacity="0" result="BackgroundImageFix"/>
27
28
  <feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
@@ -51,5 +51,6 @@
51
51
  </filter>
52
52
  <stop stop-color="#E3ECFA"/>
53
53
  <stop offset="1" stop-color="#DAE7FF"/>
54
+ </linearGradient>
54
55
  </defs>
55
56
  </svg>
@@ -1 +1 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" width="21" height="9" role="presentation"><g fill="none" fill-rule="evenodd"><path fill="#C9CBCF" fill-opacity="1" d="M1 9.092h19l-6.402-6.74c-1.717-1.806-4.485-1.8-6.196 0L1 9.093zM20.342 8l-6.02-6.336c-2.108-2.22-5.538-2.218-7.645 0L.658 8h19.684z"></path><path fill="currentcolor" d="M7.402 2.353c1.711-1.801 4.48-1.807 6.196 0L20 9.093H1l6.402-6.74z"></path></g></svg>
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="21" height="9" role="presentation"><g fill="none" fill-rule="evenodd"><path fill="#8898AA" fill-opacity="0.1" d="M1 9.092h19l-6.402-6.74c-1.717-1.806-4.485-1.8-6.196 0L1 9.093zM20.342 8l-6.02-6.336c-2.108-2.22-5.538-2.218-7.645 0L.658 8h19.684z"></path><path fill="currentcolor" d="M7.402 2.353c1.711-1.801 4.48-1.807 6.196 0L20 9.093H1l6.402-6.74z"></path></g></svg>
@@ -32,7 +32,7 @@
32
32
  >
33
33
  <div data-target="actions-list" class="w-full space divide-y">
34
34
  <% actions.each_with_index do |action, index| %>
35
- <%= link_to action_path(action),
35
+ <%= link_to action_path(action.param_id),
36
36
  data: {
37
37
  action_name: action.action_name,
38
38
  'turbo-frame': 'actions_show',
@@ -4,15 +4,14 @@ class Avo::ActionsComponent < ViewComponent::Base
4
4
  include Avo::ApplicationHelper
5
5
  attr_reader :label, :size, :as_row_control
6
6
 
7
- def initialize(actions: [], resource: nil, view: nil, exclude: [], include: [], style: :outline, color: :primary, label: nil, size: :md, as_row_control: false)
7
+ def initialize(actions: [], resource: nil, view: nil, exclude: [], style: :outline, color: :primary, label: nil, size: :md, as_row_control: false)
8
8
  @actions = actions || []
9
9
  @resource = resource
10
10
  @view = view
11
11
  @exclude = exclude
12
- @include = include
13
12
  @color = color
14
13
  @style = style
15
- @label = label || I18n.t("avo.actions")
14
+ @label = label || t("avo.actions")
16
15
  @size = size
17
16
  @as_row_control = as_row_control
18
17
  end
@@ -22,25 +21,19 @@ class Avo::ActionsComponent < ViewComponent::Base
22
21
  end
23
22
 
24
23
  def actions
25
- if @exclude.present?
26
- @actions.reject { |action| action.class.in?(@exclude) }
27
- elsif @include.present?
28
- @actions.select { |action| action.class.in?(@include) }
29
- else
30
- @actions
31
- end
24
+ @actions.reject { |action| action.class.in?(@exclude) }
32
25
  end
33
26
 
34
27
  # When running an action for one record we should do it on a special path.
35
28
  # We do that so we get the `record` param inside the action so we can prefill fields.
36
- def action_path(action)
37
- return single_record_path(action) if as_row_control
38
- return many_records_path(action) unless @resource.has_record_id?
29
+ def action_path(id)
30
+ return single_record_path(id) if as_row_control
31
+ return many_records_path(id) unless @resource.has_record_id?
39
32
 
40
33
  if on_record_page?
41
- single_record_path action
34
+ single_record_path id
42
35
  else
43
- many_records_path action
36
+ many_records_path id
44
37
  end
45
38
  end
46
39
 
@@ -61,34 +54,15 @@ class Avo::ActionsComponent < ViewComponent::Base
61
54
  !on_record_page?
62
55
  end
63
56
 
64
- def single_record_path(action)
65
- action_url(action, @resource.record_path)
66
- end
67
-
68
- def many_records_path(action)
69
- action_url(action, @resource.records_path)
57
+ def single_record_path(id)
58
+ Avo::Services::URIService.parse(@resource.record_path)
59
+ .append_paths("actions", id)
60
+ .to_s
70
61
  end
71
62
 
72
- def action_url(action, path)
73
- Avo::Services::URIService.parse(path)
74
- .append_paths("actions")
75
- .append_query(
76
- {
77
- action_id: action.param_id,
78
- arguments: encrypted_arguments(action)
79
- }.compact
80
- ).to_s
81
- end
82
-
83
- # Encrypt the arguments so we can pass them as a query param.
84
- # EncryptionService can generate special characters that can break the URL.
85
- # We use Base64 to encode the encrypted string so we can safely pass it as a query param and don't break the URL.
86
- def encrypted_arguments(action)
87
- return if action.arguments.blank?
88
-
89
- Base64.encode64 Avo::Services::EncryptionService.encrypt(
90
- message: action.arguments,
91
- purpose: :action_arguments
92
- )
63
+ def many_records_path(id)
64
+ Avo::Services::URIService.parse(@resource.records_path)
65
+ .append_paths("actions", id)
66
+ .to_s
93
67
  end
94
68
  end
@@ -10,7 +10,7 @@
10
10
  </div>
11
11
  <div class="ml-3 w-0 flex-1 pt-0.5">
12
12
  <p class="text-sm leading-5 font-semibold">
13
- <%= sanitize message.to_s %>
13
+ <%== message %>
14
14
  </p>
15
15
  </div>
16
16
  <div class="ml-4 flex-shrink-0 flex items-center">
@@ -4,7 +4,7 @@ class Avo::BaseComponent < ViewComponent::Base
4
4
  include Turbo::FramesHelper
5
5
 
6
6
  def has_with_trial(ability)
7
- Avo.license.has_with_trial(ability)
7
+ ::Avo::App.license.has_with_trial(ability)
8
8
  end
9
9
 
10
10
  private
@@ -18,7 +18,7 @@ class Avo::BaseComponent < ViewComponent::Base
18
18
 
19
19
  # Fetch the resource and hydrate it with the record
20
20
  def association_resource
21
- resource = Avo.resource_manager.get_resource(params[:via_resource_class])
21
+ resource = ::Avo::App.resources.get_resource(params[:via_resource_class])
22
22
 
23
23
  model_class = if params[:via_relation_class].present?
24
24
  ::Avo::BaseResource.get_model_by_name params[:via_relation_class]
@@ -26,23 +26,23 @@ class Avo::BaseComponent < ViewComponent::Base
26
26
  resource.model_class
27
27
  end
28
28
 
29
- resource = Avo.resource_manager.get_resource_by_model_class model_class if resource.blank?
29
+ resource = ::Avo::App.resources.get_resource_by_model_class model_class if resource.blank?
30
30
 
31
31
  record = resource.find_record params[:via_record_id], query: model_class, params: params
32
32
 
33
- resource.new record: record
33
+ resource.dup.hydrate record: record
34
34
  end
35
35
 
36
36
  # Get the resource for the resource using the klass attribute so we get the namespace too
37
37
  def reflection_resource
38
- Avo.resource_manager.get_resource_by_model_class(@reflection.klass.to_s)
38
+ ::Avo::App.resources.get_resource_by_model_class(@reflection.klass.to_s)
39
39
  rescue
40
40
  nil
41
41
  end
42
42
 
43
43
  # Get the resource for the resource using the klass attribute so we get the namespace too
44
44
  def reflection_parent_resource
45
- Avo.resource_manager.get_resource_by_model_class(@reflection.active_record.to_s)
45
+ ::Avo::App.resources.get_resource_by_model_class(@reflection.active_record.to_s)
46
46
  rescue
47
47
  nil
48
48
  end
@@ -51,7 +51,7 @@ class Avo::BaseComponent < ViewComponent::Base
51
51
  return @resource unless link_to_child_resource_is_enabled?
52
52
  return @resource if @resource.record.class.base_class == @resource.record.class
53
53
 
54
- Avo.resource_manager.get_resource_by_model_class(@resource.record.class) || @resource
54
+ ::Avo::App.resources.get_resource_by_model_class(@resource.record.class).dup || @resource
55
55
  end
56
56
 
57
57
  def link_to_child_resource_is_enabled?
@@ -2,7 +2,7 @@
2
2
  class: classes,
3
3
  style: style,
4
4
  data: data do %>
5
- <div class="h-full <% if stacked? %> md:pt-4 <% else %> md:pt-0 <% if short? %> md:h-10 <% else %> md:h-14 <% end %> <% end %> pt-4 flex self-start items-center flex-shrink-0 <%= @field.get_html(:classes, view: view, element: :label) %> w-48 <% if compact? %> md:w-48 xl:w-64 <% else %> md:w-64 <% end %> px-6 uppercase font-semibold text-gray-500 text-sm" data-slot="label">
5
+ <div class="h-full <% if stacked? %> md:pt-4 <% else %> md:pt-0 <% if short? %> md:h-10 <% else %> md:h-14 <% end %> <% end %> pt-4 flex self-start items-center <%= @field.get_html(:classes, view: view, element: :label) %> w-48 <% if compact? %> md:w-48 xl:w-64 <% else %> md:w-64 <% end %> px-6 uppercase font-semibold text-gray-500 text-sm" data-slot="label">
6
6
  <% if form.present? %>
7
7
  <%= form.label field.id, label %>
8
8
  <% else %>
@@ -11,7 +11,7 @@
11
11
  <% if on_edit? && field.is_required? %> <span class="text-red-600 ml-1">*</span> <% end %>
12
12
  </div>
13
13
  <div class="flex-1 flex flex-row md:min-h-inherit py-2 <% if stacked? %> pb-4 <% else %><% end %> px-6 <%= @field.get_html(:classes, view: view, element: :content) %>" data-slot="value">
14
- <div class="self-center w-full <% unless full_width? || compact? || stacked? %> md:w-8/12 <% end %>">
14
+ <div class="self-center <% if full_width? || compact? || stacked? %> w-full <% else %> md:w-8/12 <% end %>">
15
15
  <% if on_show? %>
16
16
  <% if field.value.blank? and dash_if_blank %>
17
17
 
@@ -24,13 +24,13 @@
24
24
  <div class="text-red-600 mt-2 text-sm"><%= record.errors.full_messages_for(field.id).to_sentence %></div>
25
25
  <% end %>
26
26
  <% if help.present? %>
27
- <div class="text-gray-600 mt-2 text-sm"><%= sanitize help %></div>
27
+ <div class="text-gray-600 mt-2 text-sm"><%== help %></div>
28
28
  <% end %>
29
29
  <% end %>
30
30
  </div>
31
31
  </div>
32
32
  <% if params[:avo_debug].present? %>
33
33
  <!-- Raw value: -->
34
- <!-- <%= sanitize field.value.inspect %> -->
34
+ <!-- <%== field.value.inspect %> -->
35
35
  <% end %>
36
36
  <% end %>
@@ -43,7 +43,7 @@ class Avo::FieldWrapperComponent < ViewComponent::Base
43
43
  end
44
44
 
45
45
  def classes(extra_classes = "")
46
- "field-wrapper relative flex flex-col grow pb-2 md:pb-0 leading-tight min-h-14 h-full #{stacked? ? "field-wrapper-layout-stacked" : "field-wrapper-layout-inline md:flex-row md:items-center"} #{compact? ? "field-wrapper-size-compact" : "field-wrapper-size-regular"} #{full_width? ? "field-width-full" : "field-width-regular"} #{@classes || ""} #{extra_classes || ""} #{@field.get_html(:classes, view: view, element: :wrapper)}"
46
+ "field-wrapper relative flex flex-col flex-grow pb-2 md:pb-0 leading-tight min-h-14 #{stacked? ? "field-wrapper-layout-stacked" : "field-wrapper-layout-inline md:flex-row md:items-center"} #{compact? ? "field-wrapper-size-compact" : "field-wrapper-size-regular"} #{full_width? ? "field-width-full" : "field-width-regular"} #{@classes || ""} #{extra_classes || ""} #{@field.get_html(:classes, view: view, element: :wrapper)}"
47
47
  end
48
48
 
49
49
  def style
@@ -2,7 +2,7 @@
2
2
  <%
3
3
  # Set the model keys so we can pass them over
4
4
  model_keys = @field.types.map do |type|
5
- resource = Avo.resource_manager.get_resource_by_model_class(type.to_s)
5
+ resource = Avo::App.resources.get_resource_by_model_class(type.to_s)
6
6
  [type.to_s, resource.model_key]
7
7
  end.to_h
8
8
  %>
@@ -13,7 +13,7 @@
13
13
  data-association-class="<%= @field&.target_resource&.model_class || nil %>"
14
14
  >
15
15
  <%= field_wrapper **field_wrapper_args, help: @field.polymorphic_help || '' do %>
16
- <%= @form.select @field.type_input_foreign_key, @field.types.map { |type| [Avo.resource_manager.get_resource_by_model_class(type.to_s).name, type.to_s] },
16
+ <%= @form.select @field.type_input_foreign_key, @field.types.map { |type| [::Avo::App.resources.get_resource_by_model_class(type.to_s).name, type.to_s] },
17
17
  {
18
18
  value: @field.value,
19
19
  include_blank: @field.placeholder,
@@ -40,9 +40,9 @@
40
40
  data-belongs-to-field-target="type"
41
41
  data-type="<%= type %>"
42
42
  >
43
- <%= field_wrapper **field_wrapper_args, label: Avo.resource_manager.get_resource_by_model_class(type.to_s).name do %>
43
+ <%= field_wrapper **field_wrapper_args, label: ::Avo::App.resources.get_resource_by_model_class(type.to_s).name do %>
44
44
  <% if @field.is_searchable? %>
45
- <%= render Avo::Pro::SearchableAssociations::AutocompleteComponent.new form: @form,
45
+ <%= render AvoPro::SearchableAssociations::AutocompleteComponent.new form: @form,
46
46
  disabled: disabled,
47
47
  field: @field,
48
48
  foreign_key: @field.id_input_foreign_key,
@@ -81,7 +81,7 @@
81
81
  <% else %>
82
82
  <%= field_wrapper **field_wrapper_args do %>
83
83
  <% if @field.is_searchable? %>
84
- <%= render Avo::Pro::SearchableAssociations::AutocompleteComponent.new form: @form,
84
+ <%= render AvoPro::SearchableAssociations::AutocompleteComponent.new form: @form,
85
85
  field: @field,
86
86
  model_key: @field.target_resource&.model_key,
87
87
  foreign_key: @field.id_input_foreign_key,
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Avo::Fields::BelongsToField::EditComponent < Avo::Fields::EditComponent
4
- def initialize(...)
5
- super(...)
4
+ def initialize(field: nil, resource: nil, index: 0, form: nil, compact: false, **args)
5
+ super field: field, resource: resource, index: index, form: form, compact: compact, **args
6
6
 
7
7
  @polymorphic_record = nil
8
8
  end
@@ -31,10 +31,6 @@ class Avo::Fields::BelongsToField::EditComponent < Avo::Fields::EditComponent
31
31
  @resource.record["#{@field.foreign_key}_type"]
32
32
  end
33
33
 
34
- def polymorphic_resource
35
- Avo.resource_manager.get_resource_by_model_class(polymorphic_class)
36
- end
37
-
38
34
  # Get the polymorphic id
39
35
  def polymorphic_id
40
36
  @resource.record["#{@field.foreign_key}_id"]
@@ -48,7 +44,7 @@ class Avo::Fields::BelongsToField::EditComponent < Avo::Fields::EditComponent
48
44
 
49
45
  return @polymorphic_record if @polymorphic_record.present?
50
46
 
51
- @polymorphic_record = polymorphic_resource.find_record polymorphic_id, query: polymorphic_class.safe_constantize, params: params
47
+ @polymorphic_record = @resource.find_record polymorphic_id, query: polymorphic_class.safe_constantize, params: params
52
48
 
53
49
  @polymorphic_record
54
50
  end
@@ -60,6 +56,6 @@ class Avo::Fields::BelongsToField::EditComponent < Avo::Fields::EditComponent
60
56
  private
61
57
 
62
58
  def visit_through_association?
63
- @field.target_resource.to_s == params[:via_resource_class].to_s
59
+ @field.target_resource.class.to_s == params[:via_resource_class].to_s
64
60
  end
65
61
  end
@@ -1,7 +1,6 @@
1
1
  <%= field_wrapper **field_wrapper_args, dash_if_blank: false do %>
2
2
  <div class="h-8 flex items-center">
3
3
  <%= @form.check_box @field.id,
4
- value: @field.value,
5
4
  checked: @field.value,
6
5
  class: "text-lg h-4 w-4 checked:bg-primary-400 focus:checked:!bg-primary-400 rounded #{@field.get_html(:classes, view: view, element: :input)}",
7
6
  data: @field.get_html(:data, view: view, element: :input),
@@ -2,7 +2,7 @@
2
2
  <div class="flex items-center">
3
3
  <div class="space-y-2">
4
4
  <% model_param_key = model_name_from_record_or_class(@resource.record).param_key %>
5
- <%= check_box_tag "#{model_param_key}[#{@field.id}][]", '', true, { class: "hidden" } %>
5
+ <%= check_box_tag "#{model_name_from_record_or_class(@resource.record).param_key}[#{@field.id}][]", '', true, { class: "hidden" } %>
6
6
  <% @field.options.each do |id, label| %>
7
7
  <%
8
8
  checked = false
@@ -1,7 +1,6 @@
1
1
  <%= field_wrapper **field_wrapper_args, full_width: true do %>
2
2
  <div data-controller="code-field">
3
3
  <%= @form.text_area @field.id,
4
- value: @field.value,
5
4
  class: classes("w-full"),
6
5
  data: {
7
6
  'code-field-target': 'element',
@@ -0,0 +1,5 @@
1
+ <div class="relative py-3 grid xs:grid-cols-2 sm:grid-cols-2 xl:grid-cols-3 2xl:grid-cols-4 gap-3 rounded-xl">
2
+ <% @field.value.attachments.each do |file| %>
3
+ <%= render Avo::Fields::Common::SingleFileViewerComponent.new field: @field, resource: @resource, file: file %>
4
+ <% end %>
5
+ </div>
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Avo::Fields::Common::FilesListViewerComponent < ViewComponent::Base
4
+ def initialize(field:, resource:)
5
+ @field = field
6
+ @resource = resource
7
+ end
8
+ end
@@ -3,7 +3,7 @@
3
3
  <% if empty %>
4
4
  <% elsif value.present? %>
5
5
  <% if as_html %>
6
- <%= sanitize value %>
6
+ <%== value %>
7
7
  <% else %>
8
8
  <div class="font-semibold uppercase"><%= value %></div>
9
9
  <% end %>
@@ -0,0 +1,56 @@
1
+ <div class="relative min-h-full max-w-full flex-1 flex flex-col justify-between space-y-3">
2
+ <% if file.present? %>
3
+ <div class="flex flex-col justify-between h-full">
4
+ <% if file.representable? && is_image? %>
5
+ <div class="max-h-[42rem] h-full flex">
6
+ <%= image_tag helpers.main_app.url_for(file), class: 'rounded-lg object-cover' %>
7
+ </div>
8
+ <% elsif is_audio? %>
9
+ <%= audio_tag(helpers.main_app.url_for(file), controls: true, preload: false, class: 'w-full') %>
10
+ <% elsif is_video? %>
11
+ <%= video_tag(helpers.main_app.url_for(file), controls: true, preload: false, class: 'w-full') %>
12
+ <% else %>
13
+ <div class="relative flex flex-col justify-evenly items-center px-2 rounded-lg border bg-white border-gray-500 min-h-24">
14
+ <div class="flex flex-col justify-center items-center w-full">
15
+ <%= helpers.svg 'document-text', class: 'h-10 text-gray-600 mb-2' %>
16
+ </div>
17
+ </div>
18
+ <% end %>
19
+ <span class="text-gray-500 mt-2 text-sm truncate" title="<%= file.filename %>"><%= file.filename %></span>
20
+ </div>
21
+ <div class="flex space-x-2">
22
+ <div class="flex">
23
+ <% if @resource.authorization.authorize_action(:download_attachments?, raise_exception: false) %>
24
+ <%= a_link Rails.application.routes.url_helpers.rails_blob_path(file, only_path: true, disposition: :attachment),
25
+ icon: 'heroicons/outline/download',
26
+ color: :primary,
27
+ download: true,
28
+ class: 'text-center',
29
+ title: t('avo.download_file'),
30
+ data: { tippy: :tooltip },
31
+ compact: true,
32
+ size: :xs %>
33
+ <% end %>
34
+ </div>
35
+ <div>
36
+ <% if @resource.authorization.authorize_action(:delete_attachments?, raise_exception: false) %>
37
+ <%= a_link destroy_path,
38
+ icon: 'heroicons/outline/trash',
39
+ color: :red,
40
+ compact: true,
41
+ size: :xs,
42
+ class: 'text-center',
43
+ title: t('avo.delete_file', item: file.filename),
44
+ data: {
45
+ turbo_method: :delete,
46
+ turbo_frame: 'destroy_attachment_form',
47
+ turbo_confirm: t('avo.are_you_sure'),
48
+ tippy: :tooltip
49
+ } %>
50
+ <% end %>
51
+ </div>
52
+ </div>
53
+ <% else %>
54
+
55
+ <% end %>
56
+ </div>
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Avo::Fields::Common::SingleFileViewerComponent < ViewComponent::Base
4
+ include Avo::ApplicationHelper
5
+
6
+ def initialize(file: nil, field:, resource:)
7
+ @file = file
8
+ @field = field
9
+ @resource = resource
10
+ end
11
+
12
+ def destroy_path
13
+ Avo::Services::URIService.parse(@resource.record_path).append_paths("active_storage_attachments", id, file.id).to_s
14
+ end
15
+
16
+ def id
17
+ @field.id
18
+ end
19
+
20
+ def file
21
+ @file || @field.value.attachment
22
+ rescue
23
+ nil
24
+ end
25
+
26
+ def is_image?
27
+ file.image? || @field.is_image
28
+ rescue
29
+ false
30
+ end
31
+
32
+ def is_audio?
33
+ file.audio? || @field.is_audio
34
+ rescue
35
+ false
36
+ end
37
+
38
+ def is_video?
39
+ file.video? || @field.is_video
40
+ rescue
41
+ false
42
+ end
43
+
44
+ def render?
45
+ record_persisted?
46
+ end
47
+
48
+ # If record is not persistent blob is automatically destroyed otherwise it can be "lost" on storage
49
+ def record_persisted?
50
+ return true if @resource.record.persisted?
51
+
52
+ ActiveStorage::Blob.destroy(file.blob_id) if file.blob_id.present?
53
+ false
54
+ end
55
+ end
@@ -1,6 +1,5 @@
1
1
  <%= field_wrapper **field_wrapper_args do %>
2
2
  <%= @form.select @field.id, @field.select_options, {
3
- value: @field.value,
4
3
  selected: @field.value,
5
4
  include_blank: @field.include_blank
6
5
  },
@@ -11,7 +10,6 @@
11
10
  data: @field.get_html(:data, view: view, element: :input),
12
11
  disabled: disabled?,
13
12
  style: @field.get_html(:style, view: view, element: :input),
14
- placeholder: @field.include_blank.present? ? nil : @field.placeholder,
15
- autocomplete: @field.autocomplete
13
+ placeholder: @field.include_blank.present? ? nil : @field.placeholder
16
14
  %>
17
15
  <% end %>
@@ -1,11 +1,11 @@
1
1
  <%= field_wrapper **field_wrapper_args do %>
2
2
  <% if @field.value.present? %>
3
3
  <div class="mb-2">
4
- <%= render Avo::Fields::Common::Files::ViewType::GridComponent.new resource: @resource, field: @field %>
4
+ <%= render Avo::Fields::Common::SingleFileViewerComponent.new resource: @resource, field: @field %>
5
5
  </div>
6
6
  <% end %>
7
7
 
8
- <% if can_upload_file? %>
8
+ <% if @resource.authorization.authorize_action(:upload_attachments?, raise_exception: false) %>
9
9
  <%= @form.file_field @field.id,
10
10
  accept: @field.accept,
11
11
  data: @field.get_html(:data, view: view, element: :input),
@@ -14,7 +14,5 @@
14
14
  style: @field.get_html(:style, view: view, element: :input),
15
15
  class: "w-full"
16
16
  %>
17
- <% else %>
18
-
19
17
  <% end %>
20
18
  <% end %>
@@ -1,5 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Avo::Fields::FileField::EditComponent < Avo::Fields::EditComponent
4
- include Avo::Fields::Concerns::FileAuthorization
5
4
  end
@@ -6,10 +6,10 @@ class Avo::Fields::FileField::IndexComponent < Avo::Fields::IndexComponent
6
6
  end
7
7
 
8
8
  def has_image_tag?
9
- field.value.present? && field.value.attached? && field.value.representable? && field.is_image
9
+ @field.value.attached? && @field.value.representable? && @field.is_image
10
10
  end
11
11
 
12
12
  def has_audio_tag?
13
- field.value.present? && field.value.attached? && field.is_audio
13
+ @field.value.attached? && @field.is_audio
14
14
  end
15
15
  end
@@ -1,3 +1,3 @@
1
1
  <%= field_wrapper **field_wrapper_args do %>
2
- <%= render Avo::Fields::Common::Files::ViewType::GridComponent.new resource: @resource, field: @field %>
2
+ <%= render Avo::Fields::Common::SingleFileViewerComponent.new resource: @resource, field: @field %>
3
3
  <% end %>
@@ -1,7 +1,7 @@
1
1
  <%= field_wrapper **field_wrapper_args, full_width: true do %>
2
- <%= render Avo::Fields::Common::Files::ListViewerComponent.new(field: @field, resource: @resource) if @field.value.present? %>
2
+ <%= render Avo::Fields::Common::FilesListViewerComponent.new(field: @field, resource: @resource) if @field.value.present? %>
3
3
 
4
- <% if can_upload_file? %>
4
+ <% if @resource.authorization.authorize_action(:upload_attachments?, raise_exception: false) %>
5
5
  <div class="mt-2">
6
6
  <%= @form.file_field @field.id,
7
7
  accept: @field.accept,
@@ -13,7 +13,5 @@
13
13
  class: "w-full"
14
14
  %>
15
15
  </div>
16
- <% else %>
17
-
18
16
  <% end %>
19
17
  <% end %>
@@ -1,5 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Avo::Fields::FilesField::EditComponent < Avo::Fields::EditComponent
4
- include Avo::Fields::Concerns::FileAuthorization
5
4
  end
@@ -1,3 +1,3 @@
1
1
  <%= field_wrapper **field_wrapper_args, full_width: true do %>
2
- <%= render Avo::Fields::Common::Files::ListViewerComponent.new(field: @field, resource: @resource) if @field.value.present? %>
2
+ <%= render Avo::Fields::Common::FilesListViewerComponent.new(field: @field, resource: @resource) if @field.value.present? %>
3
3
  <% end %>
@@ -1,3 +1,3 @@
1
1
  <turbo-frame id="<%= @field.turbo_frame %>" src="<%= @field.frame_url %>" target="_top" class="block">
2
- <%= render(Avo::LoadingComponent.new(title: @field.plural_name)) %>
2
+ <%= render(Avo::LoadingComponent.new(title: @field.name)) %>
3
3
  </turbo-frame>
@@ -4,14 +4,13 @@
4
4
  </turbo-frame>
5
5
  <% else %>
6
6
  <%= render Avo::PanelComponent.new(name: @field.name) do |c| %>
7
- <% c.with_tools do %>
7
+ <% c.tools do %>
8
8
  <% if !@field.is_readonly? && !@field.is_disabled? && can_attach? %>
9
9
  <%= a_link attach_path,
10
10
  icon: 'heroicons/outline/link',
11
11
  color: :primary,
12
- style: :text,
13
12
  'data-turbo-frame': 'attach_modal' do %>
14
- <%= t('avo.attach_item', item: @field.name.humanize(capitalize: false)) %>
13
+ <%= t('avo.attach_item', item: @field.name.downcase) %>
15
14
  <% end %>
16
15
  <% end %>
17
16
  <% if !@field.is_readonly? && !@field.is_disabled? && can_see_the_create_button? %>
@@ -21,12 +20,12 @@
21
20
  'data-turbo-frame': '_top',
22
21
  style: :primary,
23
22
  color: :primary do %>
24
- <%= t('avo.create_new_item', item: @field.name.humanize(capitalize: false) ) %>
23
+ <%= t('avo.create_new_item', item: @field.name.downcase ) %>
25
24
  <% end %>
26
25
  <% end %>
27
26
  <% end %>
28
27
 
29
- <% c.with_body do %>
28
+ <% c.body do %>
30
29
  <div class="py-8 flex justify-center items-center">
31
30
  <%= empty_state by_association: params[:related_name].present? %>
32
31
  </div>