avo 3.30.4 → 4.0.0.beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (470) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +18 -1
  3. data/Gemfile.lock +257 -174
  4. data/README.md +1 -1
  5. data/app/assets/builds/avo/application.css +13979 -0
  6. data/app/assets/builds/avo/application.js +1160 -0
  7. data/app/assets/builds/avo/application.js.map +7 -0
  8. data/app/assets/builds/avo/late-registration.js +2 -0
  9. data/app/assets/builds/avo/late-registration.js.map +7 -0
  10. data/app/assets/config/avo_manifest.js +2 -1
  11. data/app/assets/images/avo/placeholder.svg +1 -0
  12. data/app/assets/stylesheets/application.css +250 -0
  13. data/app/assets/stylesheets/css/button-group.css +23 -0
  14. data/app/assets/stylesheets/css/components/avatar.css +128 -0
  15. data/app/assets/stylesheets/css/components/breadcrumbs.css +43 -0
  16. data/app/assets/stylesheets/css/components/button.css +343 -0
  17. data/app/assets/stylesheets/css/components/color_scheme_switcher.css +226 -0
  18. data/app/assets/stylesheets/css/components/discreet_information.css +49 -0
  19. data/app/assets/stylesheets/css/components/field-wrapper.css +107 -0
  20. data/app/assets/stylesheets/css/components/grid.css +120 -0
  21. data/app/assets/stylesheets/css/components/input.css +312 -0
  22. data/app/assets/stylesheets/css/components/modal.css +228 -0
  23. data/app/assets/stylesheets/css/components/tooltip.css +25 -0
  24. data/app/assets/stylesheets/css/components/ui/badge.css +143 -0
  25. data/app/assets/stylesheets/css/components/ui/card.css +95 -0
  26. data/app/assets/stylesheets/css/components/ui/checkbox.css +50 -0
  27. data/app/assets/stylesheets/css/components/ui/description_list.css +3 -0
  28. data/app/assets/stylesheets/css/components/ui/dropdown.css +68 -0
  29. data/app/assets/stylesheets/css/components/ui/file_upload_input.css +94 -0
  30. data/app/assets/stylesheets/css/components/ui/file_upload_item.css +78 -0
  31. data/app/assets/stylesheets/css/components/ui/panel.css +59 -0
  32. data/app/assets/stylesheets/css/components/ui/panel_header.css +48 -0
  33. data/app/assets/stylesheets/css/components/ui/radio.css +22 -0
  34. data/app/assets/stylesheets/css/components/ui/tabs.css +74 -0
  35. data/app/assets/stylesheets/css/css-animations.css +54 -0
  36. data/app/assets/stylesheets/css/fields/code.css +75 -9
  37. data/app/assets/stylesheets/css/fields/easy-mde.css +7 -0
  38. data/app/assets/stylesheets/css/fields/key_value.css +97 -0
  39. data/app/assets/stylesheets/css/fields/progress.css +4 -4
  40. data/app/assets/stylesheets/css/fields/status.css +7 -1
  41. data/app/assets/stylesheets/css/fields/tags.css +33 -16
  42. data/app/assets/stylesheets/css/fields/tiptap.css +17 -15
  43. data/app/assets/stylesheets/css/fields/trix.css +62 -2
  44. data/app/assets/stylesheets/css/fonts.css +24 -24
  45. data/app/assets/stylesheets/css/layout.css +135 -0
  46. data/app/assets/stylesheets/css/pagination.css +114 -78
  47. data/app/assets/stylesheets/css/resource-controls.css +13 -0
  48. data/app/assets/stylesheets/css/search.css +22 -12
  49. data/app/assets/stylesheets/css/sidebar.css +310 -24
  50. data/app/assets/stylesheets/css/table.css +60 -0
  51. data/app/assets/stylesheets/css/tooltips.css +1 -1
  52. data/app/assets/stylesheets/css/typography.css +10 -1
  53. data/app/assets/stylesheets/css/variables.css +318 -0
  54. data/app/assets/svgs/avo/moon-plus-plus.svg +1 -0
  55. data/app/components/avo/actions_component.html.erb +30 -36
  56. data/app/components/avo/actions_component.rb +8 -11
  57. data/app/components/avo/alert_component.html.erb +3 -3
  58. data/app/components/avo/alert_component.rb +1 -1
  59. data/app/components/avo/asset_manager/javascript_component.html.erb +1 -2
  60. data/app/components/avo/backtrace_alert_component.html.erb +4 -4
  61. data/app/components/avo/base_component.rb +3 -4
  62. data/app/components/avo/breadcrumb_element_component.html.erb +17 -0
  63. data/app/components/avo/breadcrumb_element_component.rb +21 -0
  64. data/app/components/avo/breadcrumbs_component.html.erb +19 -0
  65. data/app/components/avo/breadcrumbs_component.rb +5 -0
  66. data/app/components/avo/button_component.rb +20 -126
  67. data/app/components/avo/clipboard_component.html.erb +3 -2
  68. data/app/components/avo/clipboard_component.rb +1 -1
  69. data/app/components/avo/component_missing_component.rb +11 -0
  70. data/app/components/avo/cover_component.html.erb +3 -0
  71. data/app/components/avo/cover_component.rb +25 -0
  72. data/app/components/avo/debug/status_component.html.erb +59 -0
  73. data/app/components/avo/debug/status_component.rb +30 -0
  74. data/app/components/avo/description_list_component.rb +11 -0
  75. data/app/components/avo/discreet_information_component.html.erb +31 -6
  76. data/app/components/avo/discreet_information_component.rb +23 -32
  77. data/app/components/avo/divider_component.html.erb +2 -2
  78. data/app/components/avo/empty_state_component.html.erb +2 -9
  79. data/app/components/avo/empty_state_component.rb +0 -8
  80. data/app/components/avo/field_wrapper_component.html.erb +21 -22
  81. data/app/components/avo/field_wrapper_component.rb +9 -18
  82. data/app/components/avo/fields/avatar_field/index_component.html.erb +9 -0
  83. data/app/components/avo/fields/avatar_field/index_component.rb +4 -0
  84. data/app/components/avo/fields/badge_field/index_component.html.erb +7 -1
  85. data/app/components/avo/fields/badge_field/show_component.html.erb +6 -1
  86. data/app/components/avo/fields/belongs_to_field/edit_component.html.erb +16 -14
  87. data/app/components/avo/fields/belongs_to_field/edit_component.rb +13 -3
  88. data/app/components/avo/fields/boolean_field/edit_component.html.erb +2 -2
  89. data/app/components/avo/fields/boolean_group_field/edit_component.html.erb +1 -1
  90. data/app/components/avo/fields/boolean_group_field/edit_component.rb +2 -3
  91. data/app/components/avo/fields/code_field/show_component.html.erb +1 -1
  92. data/app/components/avo/fields/common/boolean_check_component.rb +3 -3
  93. data/app/components/avo/fields/common/boolean_group_component.html.erb +2 -2
  94. data/app/components/avo/fields/common/files/controls_component.html.erb +30 -27
  95. data/app/components/avo/fields/common/files/controls_component.rb +0 -1
  96. data/app/components/avo/fields/common/files/list_viewer_component.html.erb +4 -5
  97. data/app/components/avo/fields/common/files/view_type/grid_item_component.html.erb +1 -1
  98. data/app/components/avo/fields/common/files/view_type/list_item_component.html.erb +7 -19
  99. data/app/components/avo/fields/common/heading_component.html.erb +2 -2
  100. data/app/components/avo/fields/common/heading_component.rb +1 -1
  101. data/app/components/avo/fields/common/key_value_component.html.erb +20 -24
  102. data/app/components/avo/fields/common/nested_field_component.html.erb +1 -1
  103. data/app/components/avo/fields/common/nested_field_component.rb +1 -1
  104. data/app/components/avo/fields/common/progress_bar_component.html.erb +2 -2
  105. data/app/components/avo/fields/common/stars_component.html.erb +1 -1
  106. data/app/components/avo/fields/common/status_viewer_component.html.erb +4 -10
  107. data/app/components/avo/fields/date_field/edit_component.html.erb +14 -1
  108. data/app/components/avo/fields/date_time_field/edit_component.html.erb +3 -3
  109. data/app/components/avo/fields/easy_mde_field/show_component.html.erb +1 -1
  110. data/app/components/avo/fields/edit_component.rb +9 -5
  111. data/app/components/avo/fields/file_field/edit_component.html.erb +14 -6
  112. data/app/components/avo/fields/files_field/edit_component.html.erb +11 -4
  113. data/app/components/avo/fields/has_one_field/show_component.html.erb +10 -9
  114. data/app/components/avo/fields/heading_field/edit_component.html.erb +1 -1
  115. data/app/components/avo/fields/heading_field/show_component.html.erb +2 -2
  116. data/app/components/avo/fields/password_field/edit_component.html.erb +5 -7
  117. data/app/components/avo/fields/progress_bar_field/edit_component.html.erb +1 -1
  118. data/app/components/avo/fields/radio_field/edit_component.html.erb +1 -1
  119. data/app/components/avo/fields/show_component.rb +4 -7
  120. data/app/components/avo/fields/stars_field/edit_component.html.erb +3 -4
  121. data/app/components/avo/fields/tags_field/edit_component.html.erb +1 -1
  122. data/app/components/avo/fields/tags_field/tag_component.html.erb +7 -8
  123. data/app/components/avo/fields/time_field/edit_component.html.erb +3 -3
  124. data/app/components/avo/fields/tiptap_field/edit_component.html.erb +11 -11
  125. data/app/components/avo/fields/tiptap_field/show_component.html.erb +4 -4
  126. data/app/components/avo/fields/trix_field/edit_component.html.erb +2 -2
  127. data/app/components/avo/filters_component.html.erb +8 -16
  128. data/app/components/avo/index/field_wrapper_component.html.erb +9 -2
  129. data/app/components/avo/index/field_wrapper_component.rb +0 -16
  130. data/app/components/avo/index/grid_cover_empty_state_component.html.erb +16 -2
  131. data/app/components/avo/index/grid_cover_empty_state_component.rb +90 -0
  132. data/app/components/avo/index/grid_item_component.html.erb +29 -12
  133. data/app/components/avo/index/grid_item_component.rb +12 -10
  134. data/app/components/avo/index/resource_controls_component.html.erb +1 -1
  135. data/app/components/avo/index/resource_controls_component.rb +7 -17
  136. data/app/components/avo/index/resource_controls_dropdown_component.html.erb +3 -0
  137. data/app/components/avo/index/resource_controls_dropdown_component.rb +81 -0
  138. data/app/components/avo/index/table_row_component.html.erb +11 -11
  139. data/app/components/avo/items/panel_component.html.erb +8 -18
  140. data/app/components/avo/items/panel_component.rb +0 -20
  141. data/app/components/avo/items/switcher_component.html.erb +60 -1
  142. data/app/components/avo/items/switcher_component.rb +10 -5
  143. data/app/components/avo/items/visible_items_component.html.erb +2 -1
  144. data/app/components/avo/items/visible_items_component.rb +1 -0
  145. data/app/components/avo/media_library/item_details_component.html.erb +2 -2
  146. data/app/components/avo/media_library/list_component.html.erb +24 -19
  147. data/app/components/avo/media_library/list_component.rb +2 -2
  148. data/app/components/avo/media_library/list_item_component.html.erb +3 -3
  149. data/app/components/avo/modal_component.html.erb +52 -20
  150. data/app/components/avo/modal_component.rb +7 -12
  151. data/app/components/avo/paginator_component.html.erb +46 -33
  152. data/app/components/avo/paginator_component.rb +10 -5
  153. data/app/components/avo/panel_name_component.html.erb +1 -1
  154. data/app/components/avo/profile_item_component.html.erb +4 -4
  155. data/app/components/avo/profile_item_component.rb +2 -4
  156. data/app/components/avo/referrer_params_component.html.erb +1 -1
  157. data/app/components/avo/resource_component.rb +8 -19
  158. data/app/components/avo/resource_listing_component.html.erb +22 -0
  159. data/app/components/avo/resource_listing_component.rb +28 -0
  160. data/app/components/avo/resource_sidebar_component.html.erb +2 -2
  161. data/app/components/avo/resource_sidebar_component.rb +0 -4
  162. data/app/components/avo/row_component.html.erb +1 -1
  163. data/app/components/avo/row_selector_component.html.erb +2 -4
  164. data/app/components/avo/row_selector_component.rb +0 -1
  165. data/app/components/avo/search_overlay_component.html.erb +6 -0
  166. data/app/components/avo/search_overlay_component.rb +2 -0
  167. data/app/components/avo/sidebar/base_item_component.rb +9 -9
  168. data/app/components/avo/sidebar/group_component.html.erb +23 -27
  169. data/app/components/avo/sidebar/group_component.rb +4 -0
  170. data/app/components/avo/sidebar/link_component.html.erb +30 -7
  171. data/app/components/avo/sidebar/link_component.rb +30 -2
  172. data/app/components/avo/sidebar/section_component.html.erb +31 -11
  173. data/app/components/avo/sidebar/section_component.rb +1 -3
  174. data/app/components/avo/sidebar_component.html.erb +35 -36
  175. data/app/components/avo/sidebar_component.rb +16 -0
  176. data/app/components/avo/sidebar_profile_component.html.erb +27 -36
  177. data/app/components/avo/sidebar_profile_component.rb +14 -0
  178. data/app/components/avo/tab_group_component.html.erb +21 -9
  179. data/app/components/avo/tab_group_component.rb +54 -15
  180. data/app/components/avo/turbo_frame_wrapper_component.html.erb +4 -8
  181. data/app/components/avo/turbo_frame_wrapper_component.rb +9 -0
  182. data/app/components/avo/u_i/avatar_component.html.erb +11 -0
  183. data/app/components/avo/u_i/avatar_component.rb +61 -0
  184. data/app/components/avo/u_i/badge_component.html.erb +9 -0
  185. data/app/components/avo/u_i/badge_component.rb +35 -0
  186. data/app/components/avo/u_i/card_component.html.erb +29 -0
  187. data/app/components/avo/u_i/card_component.rb +65 -0
  188. data/app/components/avo/u_i/dropdown_component.html.erb +14 -0
  189. data/app/components/avo/u_i/dropdown_component.rb +26 -0
  190. data/app/components/avo/u_i/dropdown_menu_component.html.erb +16 -0
  191. data/app/components/avo/u_i/dropdown_menu_component.rb +8 -0
  192. data/app/components/avo/u_i/file_upload_input_component.html.erb +26 -0
  193. data/app/components/avo/u_i/file_upload_input_component.rb +15 -0
  194. data/app/components/avo/u_i/file_upload_item_component.html.erb +48 -0
  195. data/app/components/avo/u_i/file_upload_item_component.rb +17 -0
  196. data/app/components/avo/u_i/icon_button_component.html.erb +7 -0
  197. data/app/components/avo/u_i/icon_button_component.rb +22 -0
  198. data/app/components/avo/u_i/panel_component.html.erb +49 -0
  199. data/app/components/avo/u_i/panel_component.rb +29 -0
  200. data/app/components/avo/u_i/panel_header_component.html.erb +37 -0
  201. data/app/components/avo/u_i/panel_header_component.rb +24 -0
  202. data/app/components/avo/u_i/search_input_component.html.erb +28 -0
  203. data/app/components/avo/u_i/search_input_component.rb +12 -0
  204. data/app/components/avo/u_i/tabs/tab_component.html.erb +26 -0
  205. data/app/components/avo/u_i/tabs/tab_component.rb +25 -0
  206. data/app/components/avo/u_i/tabs/tabs_component.html.erb +7 -0
  207. data/app/components/avo/u_i/tabs/tabs_component.rb +13 -0
  208. data/app/components/avo/view_types/base_view_type_component.rb +26 -0
  209. data/app/components/avo/view_types/grid_component.html.erb +18 -0
  210. data/app/components/avo/view_types/grid_component.rb +4 -0
  211. data/app/components/avo/view_types/map_component.html.erb +17 -0
  212. data/app/components/avo/view_types/map_component.rb +110 -0
  213. data/app/components/avo/view_types/table_component.html.erb +63 -0
  214. data/app/components/avo/{index/resource_table_component.rb → view_types/table_component.rb} +1 -10
  215. data/app/components/avo/views/resource_edit_component.html.erb +12 -18
  216. data/app/components/avo/views/resource_edit_component.rb +1 -27
  217. data/app/components/avo/views/resource_index_component.html.erb +97 -74
  218. data/app/components/avo/views/resource_index_component.rb +23 -3
  219. data/app/components/avo/views/resource_show_component.html.erb +4 -2
  220. data/app/components/avo/views/resource_show_component.rb +1 -4
  221. data/app/controllers/avo/associations_controller.rb +1 -1
  222. data/app/controllers/avo/base_application_controller.rb +7 -5
  223. data/app/controllers/avo/base_controller.rb +139 -40
  224. data/app/controllers/avo/debug_controller.rb +0 -29
  225. data/app/controllers/avo/media_library_controller.rb +17 -1
  226. data/app/controllers/avo/search_controller.rb +5 -0
  227. data/app/controllers/concerns/avo/initializes_avo.rb +7 -8
  228. data/app/helpers/avo/application_helper.rb +60 -46
  229. data/app/helpers/avo/turbo_stream_actions_helper.rb +10 -1
  230. data/app/helpers/avo/url_helpers.rb +3 -2
  231. data/app/javascript/{avo.base.js → application.js} +9 -18
  232. data/app/javascript/js/application.js +40 -0
  233. data/app/javascript/js/controllers/action_controller.js +4 -4
  234. data/app/javascript/js/controllers/actions_overflow_controller.js +21 -6
  235. data/app/javascript/js/controllers/color_scheme_switcher_controller.js +226 -0
  236. data/app/javascript/js/controllers/dropdown_menu_controller.js +42 -0
  237. data/app/javascript/js/controllers/fields/code_field_controller.js +20 -3
  238. data/app/javascript/js/controllers/fields/easy_mde_controller.js +23 -1
  239. data/app/javascript/js/controllers/fields/key_value_controller.js +43 -39
  240. data/app/javascript/js/controllers/fields/panel_refresh_controller.js +4 -0
  241. data/app/javascript/js/controllers/fields/tags_field_controller.js +2 -2
  242. data/app/javascript/js/controllers/fields/tags_field_helpers.js +4 -6
  243. data/app/javascript/js/controllers/grid_cover_empty_state_controller.js +42 -0
  244. data/app/javascript/js/controllers/item_selector_controller.js +0 -2
  245. data/app/javascript/js/controllers/loading_button_controller.js +1 -5
  246. data/app/javascript/js/controllers/map_dark_mode_controller.js +131 -0
  247. data/app/javascript/js/controllers/menu_controller.js +38 -16
  248. data/app/javascript/js/controllers/modal_controller.js +16 -0
  249. data/app/javascript/js/controllers/modal_size_controller.js +83 -0
  250. data/app/javascript/js/controllers/nested_form_controller.js +2 -2
  251. data/app/javascript/js/controllers/password_visibility_controller.js +13 -0
  252. data/app/javascript/js/controllers/preview_controller.js +2 -2
  253. data/app/javascript/js/controllers/resource_search_controller.js +123 -0
  254. data/app/javascript/js/controllers/search_controller.js +10 -29
  255. data/app/javascript/js/controllers/sidebar_controller.js +29 -9
  256. data/app/javascript/js/controllers/table_row_controller.js +28 -0
  257. data/app/javascript/js/controllers/tippy_controller.js +1 -1
  258. data/app/javascript/js/controllers/toggle_controller.js +40 -5
  259. data/app/javascript/js/controllers.js +14 -2
  260. data/app/javascript/js/custom-stream-actions.js +10 -8
  261. data/app/views/avo/actions/show.html.erb +14 -10
  262. data/app/views/avo/base/_boolean_filter.html.erb +1 -1
  263. data/app/views/avo/base/_date_time_filter.html.erb +3 -3
  264. data/app/views/avo/base/_multiple_select_filter.html.erb +1 -1
  265. data/app/views/avo/base/_new_via_belongs_to.html.erb +2 -3
  266. data/app/views/avo/base/_text_filter.html.erb +1 -1
  267. data/app/views/avo/base/preview.html.erb +5 -4
  268. data/app/views/avo/debug/status.html.erb +5 -92
  269. data/app/views/avo/debug/status.text.erb +0 -2
  270. data/app/views/avo/home/_actions.html.erb +1 -1
  271. data/app/views/avo/home/_dashboards.html.erb +1 -1
  272. data/app/views/avo/home/_filters.html.erb +1 -1
  273. data/app/views/avo/home/_resources.html.erb +2 -2
  274. data/app/views/avo/home/failed_to_load.html.erb +2 -2
  275. data/app/views/avo/home/index.html.erb +25 -25
  276. data/app/views/avo/media_library/_form.html.erb +43 -28
  277. data/app/views/avo/media_library/show.html.erb +7 -3
  278. data/app/views/avo/modal/_size_selector.html.erb +46 -0
  279. data/app/views/avo/partials/_alerts.html.erb +1 -1
  280. data/app/views/avo/partials/_color_scheme_switcher.html.erb +106 -0
  281. data/app/views/avo/partials/_color_theme_override.html.erb +49 -0
  282. data/app/views/avo/partials/_confirm_dialog.html.erb +19 -17
  283. data/app/views/avo/partials/_custom_tools_alert.html.erb +6 -6
  284. data/app/views/avo/partials/_footer.html.erb +1 -1
  285. data/app/views/avo/partials/_header.html.erb +1 -1
  286. data/app/views/avo/partials/_javascript.html.erb +0 -2
  287. data/app/views/avo/partials/_navbar.html.erb +53 -8
  288. data/app/views/avo/partials/_sortable_component.html.erb +1 -1
  289. data/app/views/avo/partials/_table_header.html.erb +28 -19
  290. data/app/views/avo/partials/_view_toggle_button.html.erb +6 -29
  291. data/app/views/avo/partials/distribution_chart.html.erb +2 -2
  292. data/app/views/avo/private/_links_and_buttons.html.erb +12 -8
  293. data/app/views/avo/private/design.html.erb +8 -4
  294. data/app/views/avo/sidebar/_license_warning.html.erb +3 -3
  295. data/app/views/layouts/avo/application.html.erb +39 -17
  296. data/app/views/layouts/avo/modal.html.erb +7 -0
  297. data/avo.gemspec +3 -4
  298. data/config/i18n-tasks.yml +1 -1
  299. data/config/importmap.rb +1 -0
  300. data/config/initializers/pagy.rb +5 -25
  301. data/config/routes/dynamic_routes.rb +4 -0
  302. data/config/routes.rb +6 -7
  303. data/db/factories.rb +14 -0
  304. data/lib/avo/asset_manager.rb +2 -0
  305. data/lib/avo/avatar.rb +7 -0
  306. data/lib/avo/base_action.rb +16 -4
  307. data/lib/avo/concerns/breadcrumbs.rb +7 -66
  308. data/lib/avo/concerns/form_builder.rb +41 -0
  309. data/lib/avo/concerns/{has_profile_photo.rb → has_avatar.rb} +8 -4
  310. data/lib/avo/concerns/{has_cover_photo.rb → has_cover.rb} +4 -4
  311. data/lib/avo/concerns/has_description.rb +9 -0
  312. data/lib/avo/concerns/has_item_type.rb +6 -2
  313. data/lib/avo/concerns/has_items.rb +43 -58
  314. data/lib/avo/concerns/pagination.rb +29 -19
  315. data/lib/avo/concerns/row_controls_configuration.rb +22 -15
  316. data/lib/avo/configuration/branding.rb +7 -7
  317. data/lib/avo/configuration.rb +92 -45
  318. data/lib/avo/{cover_photo.rb → cover.rb} +2 -2
  319. data/lib/avo/current.rb +0 -11
  320. data/lib/avo/discreet_information.rb +52 -29
  321. data/lib/avo/dsl/field_parser.rb +1 -1
  322. data/lib/avo/engine.rb +41 -8
  323. data/lib/avo/error_manager.rb +1 -1
  324. data/lib/avo/fields/avatar_field.rb +19 -0
  325. data/lib/avo/fields/badge_field.rb +23 -3
  326. data/lib/avo/fields/base_field.rb +46 -1
  327. data/lib/avo/fields/concerns/dom_id.rb +17 -0
  328. data/lib/avo/fields/concerns/file_authorization.rb +4 -0
  329. data/lib/avo/fields/concerns/has_html_attributes.rb +1 -1
  330. data/lib/avo/fields/concerns/is_searchable.rb +2 -5
  331. data/lib/avo/fields/concerns/nested.rb +1 -1
  332. data/lib/avo/fields/files_field.rb +2 -2
  333. data/lib/avo/fields/frame_base_field.rb +2 -2
  334. data/lib/avo/fields/id_field.rb +5 -1
  335. data/lib/avo/fields/progress_bar_field.rb +1 -1
  336. data/lib/avo/fields/text_field.rb +1 -1
  337. data/lib/avo/photo_object.rb +12 -1
  338. data/lib/avo/plugin_manager.rb +4 -0
  339. data/lib/avo/resources/base.rb +33 -21
  340. data/lib/avo/resources/controls/actions_list.rb +3 -3
  341. data/lib/avo/resources/controls/base_control.rb +1 -1
  342. data/lib/avo/resources/items/card.rb +16 -0
  343. data/lib/avo/resources/items/header.rb +11 -0
  344. data/lib/avo/resources/items/holder.rb +18 -23
  345. data/lib/avo/resources/items/item_group.rb +5 -7
  346. data/lib/avo/resources/items/sidebar.rb +5 -9
  347. data/lib/avo/resources/items/tab.rb +8 -8
  348. data/lib/avo/resources/items/tab_group.rb +8 -10
  349. data/lib/avo/resources/resource_manager.rb +2 -1
  350. data/lib/avo/services/hq_reporter.rb +102 -0
  351. data/lib/avo/services/telemetry_service.rb +0 -1
  352. data/lib/avo/test_helpers.rb +36 -22
  353. data/lib/avo/u_i_instance.rb +60 -0
  354. data/lib/avo/version.rb +1 -1
  355. data/lib/avo/view_inquirer.rb +6 -1
  356. data/lib/avo/view_types/view_type_manager.rb +70 -0
  357. data/lib/avo.rb +30 -45
  358. data/lib/generators/avo/action_generator.rb +1 -1
  359. data/lib/generators/avo/resource_generator.rb +43 -0
  360. data/lib/generators/avo/resource_tool_generator.rb +1 -1
  361. data/lib/generators/avo/tailwindcss/install_generator.rb +0 -6
  362. data/lib/generators/avo/templates/cards/partial_card_partial.tt +1 -1
  363. data/lib/generators/avo/templates/initializer/avo.tt +7 -9
  364. data/lib/generators/avo/templates/locales/avo.ar.yml +25 -0
  365. data/lib/generators/avo/templates/locales/avo.de.yml +25 -0
  366. data/lib/generators/avo/templates/locales/avo.en.yml +25 -0
  367. data/lib/generators/avo/templates/locales/avo.es.yml +25 -0
  368. data/lib/generators/avo/templates/locales/avo.fr.yml +25 -0
  369. data/lib/generators/avo/templates/locales/avo.it.yml +25 -0
  370. data/lib/generators/avo/templates/locales/avo.ja.yml +25 -0
  371. data/lib/generators/avo/templates/locales/avo.nb.yml +25 -0
  372. data/lib/generators/avo/templates/locales/avo.nl.yml +25 -0
  373. data/lib/generators/avo/templates/locales/avo.nn.yml +25 -0
  374. data/lib/generators/avo/templates/locales/avo.pl.yml +25 -0
  375. data/lib/generators/avo/templates/locales/avo.pt-BR.yml +25 -0
  376. data/lib/generators/avo/templates/locales/avo.pt.yml +25 -0
  377. data/lib/generators/avo/templates/locales/avo.ro.yml +25 -0
  378. data/lib/generators/avo/templates/locales/avo.ru.yml +25 -0
  379. data/lib/generators/avo/templates/locales/avo.tr.yml +25 -0
  380. data/lib/generators/avo/templates/locales/{avo.uk.yml → avo.ua.yml} +26 -1
  381. data/lib/generators/avo/templates/locales/avo.zh-TW.yml +25 -0
  382. data/lib/generators/avo/templates/locales/avo.zh.yml +25 -0
  383. data/lib/generators/avo/templates/resource/resource.tt +10 -1
  384. data/lib/generators/avo/templates/resource_tools/partial.tt +20 -22
  385. data/lib/generators/avo/templates/tailwindcss/avo.tailwind.css +1 -3
  386. data/lib/generators/avo/templates/tailwindcss/tailwind.config.js +0 -7
  387. data/lib/generators/avo/templates/tool/view.tt +14 -16
  388. data/lib/generators/avo/tool_generator.rb +3 -3
  389. data/lib/generators/avo/version_generator.rb +1 -1
  390. data/lib/tasks/avo_tasks.rake +29 -25
  391. metadata +145 -97
  392. data/app/assets/stylesheets/avo.base.css +0 -130
  393. data/app/assets/stylesheets/css/breadcrumbs.css +0 -16
  394. data/app/assets/stylesheets/css/buttons.css +0 -19
  395. data/app/assets/stylesheets/css/tailwindcss/base.css +0 -1
  396. data/app/assets/stylesheets/css/tailwindcss/components.css +0 -1
  397. data/app/assets/stylesheets/css/tailwindcss/utilities.css +0 -1
  398. data/app/assets/svgs/avo/arrow-down.svg +0 -3
  399. data/app/assets/svgs/avo/arrow-up.svg +0 -3
  400. data/app/assets/svgs/avo/detach.svg +0 -8
  401. data/app/assets/svgs/avo/download-solid-reversed.svg +0 -3
  402. data/app/assets/svgs/avo/download-solid.svg +0 -3
  403. data/app/assets/svgs/avo/edit.svg +0 -5
  404. data/app/assets/svgs/avo/editor-bold.svg +0 -1
  405. data/app/assets/svgs/avo/editor-italic.svg +0 -1
  406. data/app/assets/svgs/avo/editor-link.svg +0 -1
  407. data/app/assets/svgs/avo/editor-list.svg +0 -1
  408. data/app/assets/svgs/avo/editor-strike.svg +0 -1
  409. data/app/assets/svgs/avo/editor-underline.svg +0 -1
  410. data/app/assets/svgs/avo/eye.svg +0 -1
  411. data/app/assets/svgs/avo/trash-sm.svg +0 -3
  412. data/app/assets/svgs/avo/trash.svg +0 -7
  413. data/app/components/avo/cover_photo_component.html.erb +0 -3
  414. data/app/components/avo/cover_photo_component.rb +0 -19
  415. data/app/components/avo/fields/common/badge_viewer_component.html.erb +0 -1
  416. data/app/components/avo/fields/common/badge_viewer_component.rb +0 -33
  417. data/app/components/avo/index/resource_grid_component.html.erb +0 -23
  418. data/app/components/avo/index/resource_grid_component.rb +0 -10
  419. data/app/components/avo/index/resource_map_component.html.erb +0 -16
  420. data/app/components/avo/index/resource_map_component.rb +0 -114
  421. data/app/components/avo/index/resource_table_component.html.erb +0 -52
  422. data/app/components/avo/panel_component.html.erb +0 -63
  423. data/app/components/avo/panel_component.rb +0 -43
  424. data/app/components/avo/panel_header_component.html.erb +0 -42
  425. data/app/components/avo/panel_header_component.rb +0 -31
  426. data/app/components/avo/profile_photo_component.html.erb +0 -6
  427. data/app/components/avo/profile_photo_component.rb +0 -9
  428. data/app/components/avo/sidebar/heading_component.html.erb +0 -21
  429. data/app/components/avo/sidebar/heading_component.rb +0 -9
  430. data/app/components/avo/tab_switcher_component.html.erb +0 -20
  431. data/app/components/avo/tab_switcher_component.rb +0 -45
  432. data/app/views/avo/base/close_modal_and_reload_field.turbo_stream.erb +0 -8
  433. data/app/views/avo/debug/report.html.erb +0 -37
  434. data/app/views/avo/partials/_panel_breadcrumbs.html.erb +0 -3
  435. data/app/views/avo/partials/_resource_search.html.erb +0 -16
  436. data/lib/avo/licensing/community_license.rb +0 -6
  437. data/lib/avo/licensing/h_q.rb +0 -202
  438. data/lib/avo/licensing/license.rb +0 -76
  439. data/lib/avo/licensing/license_manager.rb +0 -24
  440. data/lib/avo/licensing/nil_license.rb +0 -14
  441. data/lib/avo/licensing/pro_license.rb +0 -20
  442. data/lib/avo/licensing/request.rb +0 -20
  443. data/lib/avo/profile_photo.rb +0 -7
  444. data/lib/avo/services/debug_service.rb +0 -107
  445. data/public/avo-assets/placeholder.svg +0 -1
  446. data/tailwind.preset.js +0 -171
  447. /data/{public/avo-assets → app/assets/images/avo}/favicon.ico +0 -0
  448. /data/{public/avo-assets → app/assets/images/avo}/fonts/inter-v7-latin-500.eot +0 -0
  449. /data/{public/avo-assets → app/assets/images/avo}/fonts/inter-v7-latin-500.svg +0 -0
  450. /data/{public/avo-assets → app/assets/images/avo}/fonts/inter-v7-latin-500.ttf +0 -0
  451. /data/{public/avo-assets → app/assets/images/avo}/fonts/inter-v7-latin-500.woff +0 -0
  452. /data/{public/avo-assets → app/assets/images/avo}/fonts/inter-v7-latin-500.woff2 +0 -0
  453. /data/{public/avo-assets → app/assets/images/avo}/fonts/inter-v7-latin-600.eot +0 -0
  454. /data/{public/avo-assets → app/assets/images/avo}/fonts/inter-v7-latin-600.svg +0 -0
  455. /data/{public/avo-assets → app/assets/images/avo}/fonts/inter-v7-latin-600.ttf +0 -0
  456. /data/{public/avo-assets → app/assets/images/avo}/fonts/inter-v7-latin-600.woff +0 -0
  457. /data/{public/avo-assets → app/assets/images/avo}/fonts/inter-v7-latin-600.woff2 +0 -0
  458. /data/{public/avo-assets → app/assets/images/avo}/fonts/inter-v7-latin-700.eot +0 -0
  459. /data/{public/avo-assets → app/assets/images/avo}/fonts/inter-v7-latin-700.svg +0 -0
  460. /data/{public/avo-assets → app/assets/images/avo}/fonts/inter-v7-latin-700.ttf +0 -0
  461. /data/{public/avo-assets → app/assets/images/avo}/fonts/inter-v7-latin-700.woff +0 -0
  462. /data/{public/avo-assets → app/assets/images/avo}/fonts/inter-v7-latin-700.woff2 +0 -0
  463. /data/{public/avo-assets → app/assets/images/avo}/fonts/inter-v7-latin-regular.eot +0 -0
  464. /data/{public/avo-assets → app/assets/images/avo}/fonts/inter-v7-latin-regular.svg +0 -0
  465. /data/{public/avo-assets → app/assets/images/avo}/fonts/inter-v7-latin-regular.ttf +0 -0
  466. /data/{public/avo-assets → app/assets/images/avo}/fonts/inter-v7-latin-regular.woff +0 -0
  467. /data/{public/avo-assets → app/assets/images/avo}/fonts/inter-v7-latin-regular.woff2 +0 -0
  468. /data/{public/avo-assets → app/assets/images/avo}/logo-on-white.png +0 -0
  469. /data/{public/avo-assets → app/assets/images/avo}/logo.png +0 -0
  470. /data/{public/avo-assets → app/assets/images/avo}/logomark.png +0 -0
@@ -11,19 +11,24 @@ module Avo
11
11
  before_action :set_record_to_fill, only: [:new, :edit, :create, :update]
12
12
  before_action :detect_fields
13
13
  before_action :set_edit_title_and_breadcrumbs, only: [:edit, :update]
14
- before_action :fill_record, only: [:create, :update]
14
+ before_action :fill_record, if: -> { action_name.in?(["create", "update"]) || params["react_on"].present? }
15
15
  # Don't run base authorizations for associations
16
- before_action :authorize_base_action, except: :preview, if: -> { controller_name != "associations" }
16
+ before_action :authorize_base_action, except: [:preview, :search], if: -> { controller_name != "associations" }
17
17
  before_action :set_pagy_locale, only: :index
18
18
 
19
+ before_action :set_modal_params
20
+ layout :choose_layout
21
+
19
22
  def index
20
23
  @page_title = @resource.plural_name.humanize
21
24
 
22
25
  if @reflection.present? && !turbo_frame_request?
23
- add_breadcrumb @record.class.to_s.pluralize, resources_path(resource: @parent_resource)
24
- add_breadcrumb @parent_resource.record_title, resource_path(record: @record, resource: @parent_resource)
26
+ # A good rule of thumb is that the resource name entry (Users) gets just the initials
27
+ # The record name gets initials and avatar
28
+ add_breadcrumb title: @record.class.to_s.pluralize, path: resources_path(resource: @parent_resource), initials: @parent_resource.class.initials
29
+ add_breadcrumb title: @parent_resource.record_title, path: resource_path(record: @record, resource: @parent_resource), initials: @parent_resource.initials, avatar: @parent_resource.avatar
25
30
  end
26
- add_breadcrumb @resource.plural_name.humanize
31
+ add_breadcrumb title: @resource.plural_name.humanize, initials: @resource.class.initials
27
32
 
28
33
  set_applied_filters
29
34
  set_index_params
@@ -36,6 +41,9 @@ module Avo
36
41
  @query = @query.includes(*@resource.includes)
37
42
  end
38
43
 
44
+ # Apply the search query if configured on the resource
45
+ apply_search
46
+
39
47
  # Eager load attachments
40
48
  if @resource.attachments.present?
41
49
  @resource.attachments.each do |attachment|
@@ -64,6 +72,36 @@ module Avo
64
72
  end
65
73
 
66
74
  set_component_for __method__
75
+
76
+ if request.headers["X-Search-Request"] == "resource-search-controller"
77
+ respond_to do |format|
78
+ format.turbo_stream do
79
+ has_resources = @resources.present?
80
+ common_args = {
81
+ resources: @resources,
82
+ resource: @resource,
83
+ reflection: @reflection,
84
+ parent_record: @parent_record,
85
+ parent_resource: @parent_resource,
86
+ pagy: @pagy,
87
+ query: @query,
88
+ actions: @actions
89
+ }
90
+
91
+ render turbo_stream: [
92
+ turbo_stream.replace("#{@resource.model_key}_body_content") do
93
+ Avo::Current.view_context.render Avo::ResourceListingComponent.new(
94
+ **common_args,
95
+ turbo_frame: @turbo_frame,
96
+ index_params: @index_params
97
+ )
98
+ end,
99
+ # used to show/hide the filters button and bar
100
+ has_resources ? turbo_stream.remove_css_class("body", "index-missing-resources") : turbo_stream.add_css_class("body", "index-missing-resources")
101
+ ]
102
+ end
103
+ end
104
+ end
67
105
  end
68
106
 
69
107
  def show
@@ -84,16 +122,17 @@ module Avo
84
122
  via_record = via_resource.find_record params[:via_record_id], params: params
85
123
  via_resource = via_resource.new record: via_record
86
124
 
87
- add_breadcrumb via_resource.plural_name, resources_path(resource: via_resource)
88
- add_breadcrumb via_resource.record_title, resource_path(record: via_record, resource: via_resource)
125
+ add_breadcrumb title: via_resource.plural_name, path: resources_path(resource: via_resource), initials: via_resource.class.initials
126
+ add_breadcrumb title: via_resource.record_title, path: resource_path(record: via_record, resource: via_resource), avatar: via_resource.avatar, initials: via_resource.initials
89
127
 
90
- add_breadcrumb @resource.plural_name.humanize
128
+ # The path is nil because it's not easy to compute the association link (course->course_links = /links)
129
+ add_breadcrumb title: @resource.plural_name.humanize, path: nil, initials: @resource.class.initials
91
130
  else
92
- add_breadcrumb @resource.plural_name.humanize, resources_path(resource: @resource)
131
+ add_breadcrumb title: @resource.plural_name.humanize, path: resources_path(resource: @resource), initials: @resource.class.initials
93
132
  end
94
133
 
95
- add_breadcrumb @resource.record_title
96
- add_breadcrumb I18n.t("avo.details").upcase_first
134
+ add_breadcrumb title: @resource.record_title, path: nil, avatar: @resource.avatar, initials: @resource.initials
135
+ add_breadcrumb title: I18n.t("avo.details").upcase_first, path: nil
97
136
 
98
137
  set_component_for __method__
99
138
  end
@@ -103,11 +142,6 @@ module Avo
103
142
  @record = @resource.record
104
143
  @resource.hydrate(view: Avo::ViewInquirer.new(:new), user: _current_user)
105
144
 
106
- # Handle special cases when creating a new record via a belongs_to relationship
107
- if params[:via_belongs_to_resource_class].present?
108
- return render turbo_stream: turbo_stream.append(Avo::MODAL_FRAME_ID, partial: "avo/base/new_via_belongs_to")
109
- end
110
-
111
145
  set_actions
112
146
 
113
147
  @page_title = @resource.default_panel_name.to_s
@@ -117,17 +151,20 @@ module Avo
117
151
  via_record = via_resource.find_record params[:via_record_id], params: params
118
152
  via_resource = via_resource.new record: via_record
119
153
 
120
- add_breadcrumb via_resource.plural_name, resources_path(resource: via_resource)
121
- add_breadcrumb via_resource.record_title, resource_path(record: via_record, resource: via_resource)
154
+ add_breadcrumb title: via_resource.plural_name, path: resources_path(resource: via_resource), initials: via_resource.class.initials
155
+ add_breadcrumb title: via_resource.record_title, path: resource_path(record: via_record, resource: via_resource), avatar: via_resource.avatar, initials: via_resource.initials
122
156
 
123
- add_breadcrumb @resource.plural_name.humanize
157
+ add_breadcrumb title: @resource.plural_name.humanize, initials: @resource.class.initials
124
158
  else
125
- add_breadcrumb @resource.plural_name.humanize, resources_path(resource: @resource)
159
+ add_breadcrumb title: @resource.plural_name.humanize, path: resources_path(resource: @resource), initials: @resource.class.initials
126
160
  end
127
161
 
128
- add_breadcrumb t("avo.new").humanize
162
+ add_breadcrumb title: t("avo.new").humanize
129
163
 
130
164
  set_component_for __method__, fallback_view: :edit
165
+
166
+ # Called from avo-advanced
167
+ safe_call :handle_reactive_fields
131
168
  end
132
169
 
133
170
  def create
@@ -165,8 +202,8 @@ module Avo
165
202
  saved = save_record
166
203
  @resource.hydrate(record: @record, view: Avo::ViewInquirer.new(:new), user: _current_user)
167
204
 
168
- add_breadcrumb @resource.plural_name.humanize, resources_path(resource: @resource)
169
- add_breadcrumb t("avo.new").humanize
205
+ add_breadcrumb title: @resource.plural_name.humanize, path: resources_path(resource: @resource), initials: @resource.class.initials
206
+ add_breadcrumb title: t("avo.new").humanize, path: nil, avatar: @resource.avatar, initials: @resource.initials
170
207
  set_actions
171
208
 
172
209
  set_component_for :edit
@@ -182,6 +219,9 @@ module Avo
182
219
  set_actions
183
220
 
184
221
  set_component_for __method__
222
+
223
+ # Called from avo-advanced
224
+ safe_call :handle_reactive_fields
185
225
  end
186
226
 
187
227
  def update
@@ -219,8 +259,25 @@ module Avo
219
259
  render layout: params[:turbo_frame].blank?
220
260
  end
221
261
 
262
+ def search
263
+ # Do not remove this method, it is implemented on avo-pro
264
+ # Just a placeholder to avoid:
265
+ # The search action could not be found for the :authorize_base_action
266
+ # callback on Avo::UsersController, but it is listed in the controller's
267
+ # :except option.
268
+ # Raising for missing callback actions is a new default in Rails 7.1, if you'd
269
+ # like to turn this off you can delete the option from the environment configurations
270
+ # or set `config.action_controller.raise_on_missing_callback_actions` to `false`.
271
+ end
272
+
222
273
  private
223
274
 
275
+ def unprocessable_status
276
+ # :unprocessable_content was added in Rails 7.1
277
+ # Use it when available, fall back to :unprocessable_entity for older versions
278
+ (Rails.version.to_f >= 7.1) ? :unprocessable_content : :unprocessable_entity
279
+ end
280
+
224
281
  def save_record
225
282
  perform_action_and_record_errors do
226
283
  save_record_action
@@ -324,17 +381,18 @@ module Avo
324
381
  @index_params = {}
325
382
 
326
383
  set_pagination_params
327
-
328
- # Sorting
329
- @index_params[:sort_by] = params[:sort_by] || @resource.sort_by_param
330
-
331
- @index_params[:sort_direction] = params[:sort_direction] || @resource.default_sort_direction
384
+ set_sorting_params
332
385
 
333
386
  if @resource.available_view_types.exclude? @resource.view_type.to_sym
334
387
  raise "View type '#{@resource.view_type}' is unavailable for #{@resource.class}."
335
388
  end
336
389
  end
337
390
 
391
+ def set_sorting_params
392
+ @index_params[:sort_by] = params[:sort_by] || @resource.sort_by_param
393
+ @index_params[:sort_direction] = params[:sort_direction] || @resource.default_sort_direction
394
+ end
395
+
338
396
  def set_filters
339
397
  @filters = @resource
340
398
  .get_filters
@@ -415,24 +473,39 @@ module Avo
415
473
  via_record = via_resource.find_record params[:via_record_id], params: params
416
474
  via_resource = via_resource.new record: via_record
417
475
 
418
- add_breadcrumb via_resource.plural_name, resources_path(resource: @resource)
419
- add_breadcrumb via_resource.record_title, resource_path(record: via_record, resource: via_resource)
476
+ add_breadcrumb title: via_resource.plural_name, path: resources_path(resource: @resource), initials: via_resource.class.initials
477
+ add_breadcrumb title: via_resource.record_title, path: resource_path(record: via_record, resource: via_resource), avatar: via_resource.avatar, initials: via_resource.initials
420
478
 
421
479
  last_crumb_args = {
422
480
  via_resource_class: params[:via_resource_class],
423
481
  via_record_id: params[:via_record_id]
424
482
  }
425
- add_breadcrumb @resource.plural_name.humanize
483
+ add_breadcrumb title: @resource.plural_name.humanize, initials: @resource.class.initials
426
484
  else
427
- add_breadcrumb @resource.plural_name.humanize, resources_path(resource: @resource)
485
+ add_breadcrumb title: @resource.plural_name.humanize, path: resources_path(resource: @resource), initials: @resource.class.initials
428
486
  end
429
487
 
430
- add_breadcrumb @resource.record_title, resource_path(record: @resource.record, resource: @resource, **last_crumb_args)
431
- add_breadcrumb t("avo.edit").humanize
488
+ add_breadcrumb title: @resource.record_title, path: resource_path(record: @resource.record, resource: @resource, **last_crumb_args), avatar: @resource.avatar, initials: @resource.initials
489
+ add_breadcrumb title: t("avo.edit").humanize
432
490
  end
433
491
 
434
492
  def create_success_action
435
- return render "close_modal_and_reload_field" if params[:via_belongs_to_resource_class].present?
493
+ if params[:via_belongs_to_resource_class].present?
494
+ respond_to do |format|
495
+ format.turbo_stream do
496
+ render turbo_stream: [
497
+ turbo_stream.remove(Avo::MODAL_FRAME_ID),
498
+ turbo_stream.avo_update_belongs_to(
499
+ relation_name: params[:via_relation],
500
+ target_record_id: @record.to_param,
501
+ target_resource_label: @resource.record_title,
502
+ target_resource_class: @record.class.name
503
+ )
504
+ ]
505
+ end
506
+ end
507
+ return
508
+ end
436
509
 
437
510
  respond_to do |format|
438
511
  format.html { redirect_to after_create_path, notice: create_success_message }
@@ -443,7 +516,7 @@ module Avo
443
516
  flash.now[:error] = create_fail_message
444
517
 
445
518
  respond_to do |format|
446
- format.html { render :new, status: :unprocessable_entity }
519
+ format.html { render :new, status: unprocessable_status }
447
520
  format.turbo_stream { render "create_fail_action" }
448
521
  end
449
522
  end
@@ -481,7 +554,7 @@ module Avo
481
554
  flash.now[:error] = update_fail_message
482
555
 
483
556
  respond_to do |format|
484
- format.html { render :edit, status: :unprocessable_entity }
557
+ format.html { render :edit, status: unprocessable_status }
485
558
  format.turbo_stream { render "update_fail_action" }
486
559
  end
487
560
  end
@@ -546,9 +619,7 @@ module Avo
546
619
  return nil if @resource.class.send(action).blank?
547
620
 
548
621
  extra_args = {}
549
- if params[:return_to].present?
550
- extra_args[:return_to] = e(params[:return_to])
551
- end
622
+ extra_args[:return_to] = params[:return_to] if params[:return_to].present?
552
623
 
553
624
  if @resource.class.send(action) == :index
554
625
  resources_path(resource: @resource, **extra_args)
@@ -566,6 +637,7 @@ module Avo
566
637
  # Set pagy locale from params or from avo configuration, if both nil locale = "en"
567
638
  def set_pagy_locale
568
639
  @pagy_locale = locale.to_s || Avo.configuration.default_locale || "en"
640
+ Pagy::I18n.locale = @pagy_locale if defined?(Pagy::I18n) && Pagy::I18n.respond_to?(:locale=)
569
641
  end
570
642
 
571
643
  def pagy_query
@@ -645,5 +717,32 @@ module Avo
645
717
  def set_query
646
718
  @query ||= @resource.class.query_scope
647
719
  end
720
+
721
+ def apply_search
722
+ return if @resource.class.search_query.nil? || params[:q].nil?
723
+
724
+ @query = Avo::ExecutionContext.new(
725
+ target: @resource.class.search_query,
726
+ params: params,
727
+ q: params[:q].strip,
728
+ query: @query
729
+ ).handle
730
+ end
731
+
732
+ def choose_layout
733
+ if params[:modal_layout].present?
734
+ "avo/modal"
735
+ else
736
+ "avo/application"
737
+ end
738
+ end
739
+
740
+ def set_modal_params
741
+ return unless params[:modal_layout].present?
742
+
743
+ @modal_width = params[:modal_width] || "4xl"
744
+ @modal_height = params[:modal_height] || "4xl"
745
+ @wrapper_class = params[:wrapper_class] || ""
746
+ end
648
747
  end
649
748
  end
@@ -10,34 +10,5 @@ module Avo
10
10
  format.text { render :status }
11
11
  end
12
12
  end
13
-
14
- def send_to_hq
15
- url = "#{ENV["HQ_URL"]}/api/v3/debug_requests"
16
- timeout = 10 # seconds
17
- license_key = Avo::Services::DebugService.debug_report(request)[:hq_payload][:license_key]
18
- body = params[:body]
19
- body = {license_key: license_key, body: body, payload: Avo::Services::DebugService.debug_report(request).to_json}.to_json
20
-
21
- Avo::Licensing::Request.post(url, body:, timeout:)
22
-
23
- render turbo_stream: turbo_stream.replace(:send_to_hq, plain: "Payload sent to Avo HQ.")
24
- end
25
-
26
- def report
27
- end
28
-
29
- def refresh_license
30
- license = Licensing::LicenseManager.refresh_license request
31
-
32
- if license.valid?
33
- flash[:notice] = "avohq.io responded: \"#{license.id.humanize} license is valid\"."
34
- elsif license.response["reason"].present?
35
- flash[:error] = "avohq.io responded: \"#{license.response["reason"]}\"."
36
- else
37
- flash[:error] = license.response["error"]
38
- end
39
-
40
- redirect_back fallback_location: avo.avo_private_status_path
41
- end
42
13
  end
43
14
  end
@@ -1,14 +1,30 @@
1
1
  module Avo
2
2
  class MediaLibraryController < ApplicationController
3
- include Pagy::Backend
3
+ include Pagy::Method
4
4
  before_action :authorize_access!
5
+ before_action -> { @container_size = "large" }, only: [:show]
5
6
 
6
7
  def index
7
8
  @attaching = false
9
+ add_breadcrumb title: "Media Library", initials: "ML"
8
10
  end
9
11
 
10
12
  def show
11
13
  @blob = ActiveStorage::Blob.find(params[:id])
14
+
15
+ add_breadcrumb title: "Media Library", path: avo.media_library_index_path, initials: "ML"
16
+ add_breadcrumb title: @blob.filename.to_s, path: nil, initials: extract_initials(@blob.filename.to_s)
17
+ end
18
+
19
+ def extract_initials(filename)
20
+ # Remove file extension
21
+ name_without_ext = File.basename(filename, File.extname(filename))
22
+
23
+ # Split by spaces and take first 2 words
24
+ words = name_without_ext.split(" ").first(2)
25
+
26
+ # Extract first character of each word and join
27
+ words.map { |word| word[0] }.join("").upcase
12
28
  end
13
29
 
14
30
  def destroy
@@ -1,3 +1,8 @@
1
+ # Only used for searchable fields
2
+
3
+ # This controller is currently only used for searchable fields, it keeps the old search controller without any changes
4
+ # Possibly have much more logic that it uses, but it's not worth the effort to refactor it since we're going to replace it with a new searchable fields way
5
+
1
6
  require_dependency "avo/application_controller"
2
7
 
3
8
  module Avo
@@ -1,19 +1,18 @@
1
1
  module Avo
2
2
  module InitializesAvo
3
+ include Avo::Concerns::SafeCall
4
+
3
5
  def init_app
4
- Avo::Current.license = Avo::Licensing::NilLicense.new
5
6
  Avo::Current.context = context
6
7
  Avo::Current.user = _current_user
7
8
  Avo::Current.view_context = view_context
9
+ safe_call(:before_init_app)
8
10
  Avo.init
9
- Avo::Current.license = Licensing::LicenseManager.new(Licensing::HQ.new(request).response).license
10
-
11
- # Output a warning in the logs if the license is invalid
12
- if Avo::Current.license.invalid?
13
- Avo.logger.debug "Your Avo license looks invalid. Please troubleshoot it using the directions here: https://docs.avohq.io/3.0/license-troubleshooting.html"
14
- end
15
-
16
11
  Avo::Current.locale = locale
12
+
13
+ # Fire and forget HQ reporting
14
+ request_info = {ip: request.ip, host: request.host, port: request.port}
15
+ Thread.new { Avo::Services::HqReporter.report(request_info) }
17
16
  end
18
17
 
19
18
  def _current_user
@@ -1,8 +1,9 @@
1
1
  module Avo
2
2
  module ApplicationHelper
3
- include ::Pagy::Frontend
4
3
  include Avo::ResourcesHelper
5
4
 
5
+ def ui = Avo::UIInstance
6
+
6
7
  def render_license_warning(title: "", message: "", icon: "exclamation")
7
8
  render partial: "avo/sidebar/license_warning", locals: {
8
9
  title: title,
@@ -28,7 +29,7 @@ module Avo
28
29
  end
29
30
 
30
31
  def button_classes(extra_classes = nil, color: nil, variant: nil, size: :md, active: false)
31
- classes = "inline-flex flex-grow-0 items-center text-sm font-semibold leading-6 fill-current whitespace-nowrap transition duration-100 rounded transform transition duration-100 active:translate-x-px active:translate-y-px cursor-pointer disabled:cursor-not-allowed #{extra_classes}"
32
+ classes = "inline-flex grow-0 items-center text-sm font-semibold leading-6 fill-current whitespace-nowrap transition duration-100 rounded-sm transform transition duration-100 active:translate-x-px active:translate-y-px cursor-pointer disabled:cursor-not-allowed #{extra_classes}"
32
33
 
33
34
  if color.present?
34
35
  if variant.present? && (variant.to_sym == :outlined)
@@ -59,26 +60,12 @@ module Avo
59
60
  classes
60
61
  end
61
62
 
62
- def input_classes(extra_classes = "", has_error: false)
63
- classes = "appearance-none inline-flex bg-gray-25 disabled:cursor-not-allowed text-gray-600 disabled:opacity-50 rounded py-2 px-3 leading-tight border focus:border-gray-600 focus-visible:ring-0 focus:text-gray-700 placeholder:text-gray-300"
64
-
65
- classes += if has_error
66
- " border-red-600"
67
- else
68
- " border-gray-200"
69
- end
70
-
63
+ def input_classes(extra_classes = "", has_error: false, size: :md)
64
+ classes = ""
65
+ classes += "input--size-#{size}" if [:sm, :md, :lg].include?(size)
66
+ classes += " input-field--error" if has_error
71
67
  classes += " #{extra_classes}"
72
-
73
- classes
74
- end
75
-
76
- def white_panel_classes
77
- "bg-white rounded shadow-md"
78
- end
79
-
80
- def card_classes
81
- "bg-white rounded shadow-panel"
68
+ classes.strip
82
69
  end
83
70
 
84
71
  def get_model_class(model)
@@ -134,47 +121,76 @@ module Avo
134
121
  defined?(Authentication) && Authentication.private_instance_methods.include?(:require_authentication) && Authentication.private_instance_methods.include?(:authenticated?)
135
122
  end
136
123
 
137
- def pagy_major_version
138
- return nil unless defined?(Pagy::VERSION)
139
- version = Pagy::VERSION&.split(".")&.first&.to_i
124
+ def body_classes
125
+ os_class = request.user_agent.to_s.include?("Mac") ? "os-mac" : "os-pc"
140
126
 
141
- return "8-or-more" if version >= 8
127
+ view_class = if controller.class.superclass.to_s == "Avo::ResourcesController"
128
+ case action_name.to_sym
129
+ when :index
130
+ "resource-index-view"
131
+ when :show
132
+ "resource-show-view"
133
+ when :edit, :update
134
+ "resource-edit-view"
135
+ when :new, :create
136
+ "resource-new-view"
137
+ end
138
+ end
142
139
 
143
- version
140
+ [os_class, view_class, *Array.wrap(Avo.configuration.body_classes)]
144
141
  end
145
142
 
146
- def container_is_full_width?
147
- if @container_full_width.present?
148
- @container_full_width
149
- elsif Avo.configuration.full_width_container
150
- true
151
- elsif Avo.configuration.full_width_index_view && action_name.to_sym == :index && controller.class.superclass.to_s == "Avo::ResourcesController"
152
- true
153
- else
154
- false
155
- end
143
+ # Check if the current locale is RTL (Right-to-Left)
144
+ def rtl?
145
+ Avo.configuration.rtl?
146
+ end
147
+
148
+ # Returns "rtl" or "ltr" based on current locale
149
+ def text_direction
150
+ Avo.configuration.text_direction
156
151
  end
157
152
 
158
153
  def container_classes
159
- container_is_full_width? ? "" : "2xl:container 2xl:mx-auto"
154
+ return "container-#{container_width_css_suffix(@container_size.to_sym)}" if @container_size.present?
155
+
156
+ width = Avo.configuration.container_width.fetch(@view&.to_sym, :large)
157
+ "container-#{container_width_css_suffix(width)}"
160
158
  end
161
159
 
162
160
  # encode & encrypt params
163
161
  def e(value)
164
- encrypted = Avo::Services::EncryptionService.encrypt(message: value, purpose: :return_to, serializer: Marshal)
165
- Base64.urlsafe_encode64(encrypted, padding: false)
162
+ Avo::Services::EncryptionService.encrypt(message: value, purpose: :return_to, serializer: Marshal)
166
163
  end
167
164
 
168
165
  # decrypt & decode params
169
166
  def d(value)
170
- decoded = Base64.urlsafe_decode64(value.to_s)
171
- Avo::Services::EncryptionService.decrypt(message: decoded, purpose: :return_to, serializer: Marshal)
167
+ Avo::Services::EncryptionService.decrypt(message: value, purpose: :return_to, serializer: Marshal)
172
168
  rescue
173
- nil
169
+ value
170
+ end
171
+
172
+ def wrap_in_modal(content)
173
+ turbo_frame_tag Avo::MODAL_FRAME_ID do
174
+ render(Avo::ModalComponent.new(width: :xl, body_class: "bg-application")) do |c|
175
+ content
176
+ end
177
+ end
178
+ end
179
+
180
+ def editor_file_path(path)
181
+ editor_url(Object.const_source_location(path.class.to_s)&.first)
182
+ end
183
+
184
+ def editor_url(path)
185
+ Avo.configuration.default_editor_url.gsub("%{path}", path)
174
186
  end
175
187
 
176
188
  private
177
189
 
190
+ def container_width_css_suffix(width)
191
+ (width == :full) ? "full-width" : width.to_s
192
+ end
193
+
178
194
  def avo_field(type = nil, id = nil, as: nil, view: :show, form: nil, component_options: {}, **args, &block)
179
195
  if as.present?
180
196
  id = type
@@ -197,10 +213,8 @@ module Avo
197
213
  avo_field(id, type, **args, view: view, &block)
198
214
  end
199
215
 
200
- def field_container(**args, &block)
201
- classes = args[:class] || ""
202
- classes << "flex flex-col divide-y"
203
- content_tag :div, **args, class: classes, &block
216
+ def accent_colors
217
+ %w[red orange amber yellow lime green emerald teal cyan sky blue indigo violet purple fuchsia pink rose]
204
218
  end
205
219
  end
206
220
  end
@@ -19,6 +19,15 @@ module Avo
19
19
  def avo_turbo_reload
20
20
  turbo_stream_action_tag :turbo_reload
21
21
  end
22
+
23
+ def avo_update_belongs_to(relation_name:, target_record_id:, target_resource_label:, target_resource_class:)
24
+ turbo_stream_action_tag "update-belongs-to",
25
+ data: {
26
+ relation_name: relation_name,
27
+ target_record_id: target_record_id,
28
+ target_resource_label: target_resource_label,
29
+ target_resource_class: target_resource_class
30
+ }
31
+ end
22
32
  end
23
33
  end
24
-
@@ -52,9 +52,10 @@ module Avo
52
52
  model_name, # teams
53
53
  record_id, # 1
54
54
  related_name, # admin
55
- related_id = nil
55
+ related_id = nil,
56
+ **args
56
57
  )
57
- avo.resources_associations_destroy_path(model_name, record_id, related_name, related_id)
58
+ avo.resources_associations_destroy_path(model_name, record_id, related_name, related_id, **args)
58
59
  end
59
60
 
60
61
  def related_resources_path(