avo 3.30.4 → 4.0.0.beta.1

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 (466) 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 +13942 -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/stylesheets/application.css +241 -0
  12. data/app/assets/stylesheets/css/button-group.css +23 -0
  13. data/app/assets/stylesheets/css/components/avatar.css +128 -0
  14. data/app/assets/stylesheets/css/components/breadcrumbs.css +43 -0
  15. data/app/assets/stylesheets/css/components/button.css +343 -0
  16. data/app/assets/stylesheets/css/components/color_scheme_switcher.css +226 -0
  17. data/app/assets/stylesheets/css/components/discreet_information.css +49 -0
  18. data/app/assets/stylesheets/css/components/field-wrapper.css +107 -0
  19. data/app/assets/stylesheets/css/components/grid.css +61 -0
  20. data/app/assets/stylesheets/css/components/input.css +312 -0
  21. data/app/assets/stylesheets/css/components/modal.css +228 -0
  22. data/app/assets/stylesheets/css/components/tooltip.css +25 -0
  23. data/app/assets/stylesheets/css/components/ui/badge.css +143 -0
  24. data/app/assets/stylesheets/css/components/ui/card.css +95 -0
  25. data/app/assets/stylesheets/css/components/ui/checkbox.css +50 -0
  26. data/app/assets/stylesheets/css/components/ui/description_list.css +3 -0
  27. data/app/assets/stylesheets/css/components/ui/dropdown.css +68 -0
  28. data/app/assets/stylesheets/css/components/ui/file_upload_input.css +94 -0
  29. data/app/assets/stylesheets/css/components/ui/file_upload_item.css +78 -0
  30. data/app/assets/stylesheets/css/components/ui/panel.css +59 -0
  31. data/app/assets/stylesheets/css/components/ui/panel_header.css +48 -0
  32. data/app/assets/stylesheets/css/components/ui/radio.css +22 -0
  33. data/app/assets/stylesheets/css/components/ui/tabs.css +74 -0
  34. data/app/assets/stylesheets/css/css-animations.css +54 -0
  35. data/app/assets/stylesheets/css/fields/code.css +75 -9
  36. data/app/assets/stylesheets/css/fields/easy-mde.css +7 -0
  37. data/app/assets/stylesheets/css/fields/key_value.css +97 -0
  38. data/app/assets/stylesheets/css/fields/progress.css +4 -4
  39. data/app/assets/stylesheets/css/fields/status.css +7 -1
  40. data/app/assets/stylesheets/css/fields/tags.css +33 -16
  41. data/app/assets/stylesheets/css/fields/tiptap.css +17 -15
  42. data/app/assets/stylesheets/css/fields/trix.css +62 -2
  43. data/app/assets/stylesheets/css/fonts.css +24 -24
  44. data/app/assets/stylesheets/css/layout.css +135 -0
  45. data/app/assets/stylesheets/css/pagination.css +114 -78
  46. data/app/assets/stylesheets/css/resource-controls.css +13 -0
  47. data/app/assets/stylesheets/css/search.css +22 -12
  48. data/app/assets/stylesheets/css/sidebar.css +310 -24
  49. data/app/assets/stylesheets/css/table.css +60 -0
  50. data/app/assets/stylesheets/css/tooltips.css +1 -1
  51. data/app/assets/stylesheets/css/typography.css +10 -1
  52. data/app/assets/stylesheets/css/variables.css +318 -0
  53. data/app/assets/svgs/avo/moon-plus-plus.svg +1 -0
  54. data/app/components/avo/actions_component.html.erb +30 -36
  55. data/app/components/avo/actions_component.rb +8 -11
  56. data/app/components/avo/alert_component.html.erb +3 -3
  57. data/app/components/avo/alert_component.rb +1 -1
  58. data/app/components/avo/asset_manager/javascript_component.html.erb +1 -2
  59. data/app/components/avo/backtrace_alert_component.html.erb +4 -4
  60. data/app/components/avo/base_component.rb +3 -4
  61. data/app/components/avo/breadcrumb_element_component.html.erb +17 -0
  62. data/app/components/avo/breadcrumb_element_component.rb +21 -0
  63. data/app/components/avo/breadcrumbs_component.html.erb +19 -0
  64. data/app/components/avo/breadcrumbs_component.rb +5 -0
  65. data/app/components/avo/button_component.rb +20 -126
  66. data/app/components/avo/clipboard_component.html.erb +3 -2
  67. data/app/components/avo/clipboard_component.rb +1 -1
  68. data/app/components/avo/component_missing_component.rb +11 -0
  69. data/app/components/avo/cover_component.html.erb +3 -0
  70. data/app/components/avo/cover_component.rb +25 -0
  71. data/app/components/avo/debug/status_component.html.erb +59 -0
  72. data/app/components/avo/debug/status_component.rb +30 -0
  73. data/app/components/avo/description_list_component.rb +11 -0
  74. data/app/components/avo/discreet_information_component.html.erb +31 -6
  75. data/app/components/avo/discreet_information_component.rb +23 -32
  76. data/app/components/avo/divider_component.html.erb +2 -2
  77. data/app/components/avo/empty_state_component.html.erb +2 -9
  78. data/app/components/avo/empty_state_component.rb +0 -8
  79. data/app/components/avo/field_wrapper_component.html.erb +21 -22
  80. data/app/components/avo/field_wrapper_component.rb +9 -18
  81. data/app/components/avo/fields/avatar_field/index_component.html.erb +9 -0
  82. data/app/components/avo/fields/avatar_field/index_component.rb +4 -0
  83. data/app/components/avo/fields/badge_field/index_component.html.erb +7 -1
  84. data/app/components/avo/fields/badge_field/show_component.html.erb +6 -1
  85. data/app/components/avo/fields/belongs_to_field/edit_component.html.erb +16 -14
  86. data/app/components/avo/fields/belongs_to_field/edit_component.rb +13 -3
  87. data/app/components/avo/fields/boolean_field/edit_component.html.erb +2 -2
  88. data/app/components/avo/fields/boolean_group_field/edit_component.html.erb +1 -1
  89. data/app/components/avo/fields/boolean_group_field/edit_component.rb +2 -3
  90. data/app/components/avo/fields/code_field/show_component.html.erb +1 -1
  91. data/app/components/avo/fields/common/boolean_check_component.rb +3 -3
  92. data/app/components/avo/fields/common/boolean_group_component.html.erb +2 -2
  93. data/app/components/avo/fields/common/files/controls_component.html.erb +30 -27
  94. data/app/components/avo/fields/common/files/controls_component.rb +0 -1
  95. data/app/components/avo/fields/common/files/list_viewer_component.html.erb +4 -5
  96. data/app/components/avo/fields/common/files/view_type/grid_item_component.html.erb +1 -1
  97. data/app/components/avo/fields/common/files/view_type/list_item_component.html.erb +7 -19
  98. data/app/components/avo/fields/common/heading_component.html.erb +2 -2
  99. data/app/components/avo/fields/common/heading_component.rb +1 -1
  100. data/app/components/avo/fields/common/key_value_component.html.erb +20 -24
  101. data/app/components/avo/fields/common/nested_field_component.html.erb +1 -1
  102. data/app/components/avo/fields/common/nested_field_component.rb +1 -1
  103. data/app/components/avo/fields/common/progress_bar_component.html.erb +2 -2
  104. data/app/components/avo/fields/common/stars_component.html.erb +1 -1
  105. data/app/components/avo/fields/common/status_viewer_component.html.erb +4 -10
  106. data/app/components/avo/fields/date_field/edit_component.html.erb +14 -1
  107. data/app/components/avo/fields/date_time_field/edit_component.html.erb +3 -3
  108. data/app/components/avo/fields/easy_mde_field/show_component.html.erb +1 -1
  109. data/app/components/avo/fields/edit_component.rb +9 -5
  110. data/app/components/avo/fields/file_field/edit_component.html.erb +14 -6
  111. data/app/components/avo/fields/files_field/edit_component.html.erb +11 -4
  112. data/app/components/avo/fields/has_one_field/show_component.html.erb +10 -9
  113. data/app/components/avo/fields/heading_field/edit_component.html.erb +1 -1
  114. data/app/components/avo/fields/heading_field/show_component.html.erb +2 -2
  115. data/app/components/avo/fields/password_field/edit_component.html.erb +5 -7
  116. data/app/components/avo/fields/progress_bar_field/edit_component.html.erb +1 -1
  117. data/app/components/avo/fields/radio_field/edit_component.html.erb +1 -1
  118. data/app/components/avo/fields/show_component.rb +4 -7
  119. data/app/components/avo/fields/stars_field/edit_component.html.erb +3 -4
  120. data/app/components/avo/fields/tags_field/edit_component.html.erb +1 -1
  121. data/app/components/avo/fields/tags_field/tag_component.html.erb +7 -8
  122. data/app/components/avo/fields/time_field/edit_component.html.erb +3 -3
  123. data/app/components/avo/fields/tiptap_field/edit_component.html.erb +11 -11
  124. data/app/components/avo/fields/tiptap_field/show_component.html.erb +4 -4
  125. data/app/components/avo/fields/trix_field/edit_component.html.erb +2 -2
  126. data/app/components/avo/filters_component.html.erb +8 -16
  127. data/app/components/avo/index/field_wrapper_component.html.erb +9 -2
  128. data/app/components/avo/index/field_wrapper_component.rb +0 -16
  129. data/app/components/avo/index/grid_cover_empty_state_component.html.erb +2 -2
  130. data/app/components/avo/index/grid_item_component.html.erb +29 -12
  131. data/app/components/avo/index/grid_item_component.rb +12 -10
  132. data/app/components/avo/index/resource_controls_component.html.erb +1 -1
  133. data/app/components/avo/index/resource_controls_component.rb +7 -17
  134. data/app/components/avo/index/resource_controls_dropdown_component.html.erb +3 -0
  135. data/app/components/avo/index/resource_controls_dropdown_component.rb +81 -0
  136. data/app/components/avo/index/table_row_component.html.erb +11 -11
  137. data/app/components/avo/items/panel_component.html.erb +8 -18
  138. data/app/components/avo/items/panel_component.rb +0 -20
  139. data/app/components/avo/items/switcher_component.html.erb +62 -1
  140. data/app/components/avo/items/switcher_component.rb +10 -5
  141. data/app/components/avo/items/visible_items_component.html.erb +2 -1
  142. data/app/components/avo/items/visible_items_component.rb +1 -0
  143. data/app/components/avo/media_library/item_details_component.html.erb +2 -2
  144. data/app/components/avo/media_library/list_component.html.erb +24 -19
  145. data/app/components/avo/media_library/list_component.rb +2 -2
  146. data/app/components/avo/media_library/list_item_component.html.erb +3 -3
  147. data/app/components/avo/modal_component.html.erb +52 -20
  148. data/app/components/avo/modal_component.rb +7 -12
  149. data/app/components/avo/paginator_component.html.erb +46 -33
  150. data/app/components/avo/paginator_component.rb +10 -5
  151. data/app/components/avo/panel_name_component.html.erb +1 -1
  152. data/app/components/avo/profile_item_component.html.erb +4 -4
  153. data/app/components/avo/profile_item_component.rb +2 -4
  154. data/app/components/avo/referrer_params_component.html.erb +1 -1
  155. data/app/components/avo/resource_component.rb +8 -19
  156. data/app/components/avo/resource_listing_component.html.erb +22 -0
  157. data/app/components/avo/resource_listing_component.rb +28 -0
  158. data/app/components/avo/resource_sidebar_component.html.erb +2 -2
  159. data/app/components/avo/resource_sidebar_component.rb +0 -4
  160. data/app/components/avo/row_component.html.erb +1 -1
  161. data/app/components/avo/row_selector_component.html.erb +2 -4
  162. data/app/components/avo/row_selector_component.rb +0 -1
  163. data/app/components/avo/search_overlay_component.html.erb +6 -0
  164. data/app/components/avo/search_overlay_component.rb +2 -0
  165. data/app/components/avo/sidebar/base_item_component.rb +9 -9
  166. data/app/components/avo/sidebar/group_component.html.erb +23 -27
  167. data/app/components/avo/sidebar/group_component.rb +4 -0
  168. data/app/components/avo/sidebar/link_component.html.erb +30 -7
  169. data/app/components/avo/sidebar/link_component.rb +30 -2
  170. data/app/components/avo/sidebar/section_component.html.erb +31 -11
  171. data/app/components/avo/sidebar/section_component.rb +1 -3
  172. data/app/components/avo/sidebar_component.html.erb +35 -36
  173. data/app/components/avo/sidebar_component.rb +16 -0
  174. data/app/components/avo/sidebar_profile_component.html.erb +27 -36
  175. data/app/components/avo/sidebar_profile_component.rb +14 -0
  176. data/app/components/avo/tab_group_component.html.erb +21 -9
  177. data/app/components/avo/tab_group_component.rb +54 -15
  178. data/app/components/avo/turbo_frame_wrapper_component.html.erb +4 -8
  179. data/app/components/avo/turbo_frame_wrapper_component.rb +9 -0
  180. data/app/components/avo/u_i/avatar_component.html.erb +11 -0
  181. data/app/components/avo/u_i/avatar_component.rb +61 -0
  182. data/app/components/avo/u_i/badge_component.html.erb +9 -0
  183. data/app/components/avo/u_i/badge_component.rb +35 -0
  184. data/app/components/avo/u_i/card_component.html.erb +29 -0
  185. data/app/components/avo/u_i/card_component.rb +65 -0
  186. data/app/components/avo/u_i/dropdown_component.html.erb +14 -0
  187. data/app/components/avo/u_i/dropdown_component.rb +26 -0
  188. data/app/components/avo/u_i/dropdown_menu_component.html.erb +16 -0
  189. data/app/components/avo/u_i/dropdown_menu_component.rb +8 -0
  190. data/app/components/avo/u_i/file_upload_input_component.html.erb +26 -0
  191. data/app/components/avo/u_i/file_upload_input_component.rb +15 -0
  192. data/app/components/avo/u_i/file_upload_item_component.html.erb +48 -0
  193. data/app/components/avo/u_i/file_upload_item_component.rb +17 -0
  194. data/app/components/avo/u_i/icon_button_component.html.erb +7 -0
  195. data/app/components/avo/u_i/icon_button_component.rb +22 -0
  196. data/app/components/avo/u_i/panel_component.html.erb +49 -0
  197. data/app/components/avo/u_i/panel_component.rb +29 -0
  198. data/app/components/avo/u_i/panel_header_component.html.erb +37 -0
  199. data/app/components/avo/u_i/panel_header_component.rb +24 -0
  200. data/app/components/avo/u_i/search_input_component.html.erb +28 -0
  201. data/app/components/avo/u_i/search_input_component.rb +12 -0
  202. data/app/components/avo/u_i/tabs/tab_component.html.erb +26 -0
  203. data/app/components/avo/u_i/tabs/tab_component.rb +25 -0
  204. data/app/components/avo/u_i/tabs/tabs_component.html.erb +7 -0
  205. data/app/components/avo/u_i/tabs/tabs_component.rb +13 -0
  206. data/app/components/avo/view_types/base_view_type_component.rb +26 -0
  207. data/app/components/avo/view_types/grid_component.html.erb +18 -0
  208. data/app/components/avo/view_types/grid_component.rb +4 -0
  209. data/app/components/avo/view_types/map_component.html.erb +17 -0
  210. data/app/components/avo/view_types/map_component.rb +110 -0
  211. data/app/components/avo/view_types/table_component.html.erb +63 -0
  212. data/app/components/avo/{index/resource_table_component.rb → view_types/table_component.rb} +1 -10
  213. data/app/components/avo/views/resource_edit_component.html.erb +12 -18
  214. data/app/components/avo/views/resource_edit_component.rb +1 -27
  215. data/app/components/avo/views/resource_index_component.html.erb +97 -74
  216. data/app/components/avo/views/resource_index_component.rb +21 -1
  217. data/app/components/avo/views/resource_show_component.html.erb +4 -2
  218. data/app/components/avo/views/resource_show_component.rb +1 -4
  219. data/app/controllers/avo/associations_controller.rb +1 -1
  220. data/app/controllers/avo/base_application_controller.rb +7 -5
  221. data/app/controllers/avo/base_controller.rb +139 -40
  222. data/app/controllers/avo/debug_controller.rb +0 -29
  223. data/app/controllers/avo/media_library_controller.rb +17 -1
  224. data/app/controllers/avo/search_controller.rb +5 -0
  225. data/app/controllers/concerns/avo/initializes_avo.rb +7 -8
  226. data/app/helpers/avo/application_helper.rb +60 -46
  227. data/app/helpers/avo/turbo_stream_actions_helper.rb +10 -1
  228. data/app/helpers/avo/url_helpers.rb +3 -2
  229. data/app/javascript/{avo.base.js → application.js} +9 -18
  230. data/app/javascript/js/application.js +40 -0
  231. data/app/javascript/js/controllers/action_controller.js +4 -4
  232. data/app/javascript/js/controllers/actions_overflow_controller.js +21 -6
  233. data/app/javascript/js/controllers/color_scheme_switcher_controller.js +226 -0
  234. data/app/javascript/js/controllers/dropdown_menu_controller.js +42 -0
  235. data/app/javascript/js/controllers/fields/code_field_controller.js +20 -3
  236. data/app/javascript/js/controllers/fields/easy_mde_controller.js +23 -1
  237. data/app/javascript/js/controllers/fields/key_value_controller.js +43 -39
  238. data/app/javascript/js/controllers/fields/panel_refresh_controller.js +4 -0
  239. data/app/javascript/js/controllers/fields/tags_field_controller.js +2 -2
  240. data/app/javascript/js/controllers/fields/tags_field_helpers.js +4 -6
  241. data/app/javascript/js/controllers/item_selector_controller.js +0 -2
  242. data/app/javascript/js/controllers/loading_button_controller.js +1 -5
  243. data/app/javascript/js/controllers/map_dark_mode_controller.js +131 -0
  244. data/app/javascript/js/controllers/menu_controller.js +38 -16
  245. data/app/javascript/js/controllers/modal_controller.js +16 -0
  246. data/app/javascript/js/controllers/modal_size_controller.js +83 -0
  247. data/app/javascript/js/controllers/nested_form_controller.js +2 -2
  248. data/app/javascript/js/controllers/password_visibility_controller.js +13 -0
  249. data/app/javascript/js/controllers/preview_controller.js +2 -2
  250. data/app/javascript/js/controllers/resource_search_controller.js +123 -0
  251. data/app/javascript/js/controllers/search_controller.js +10 -29
  252. data/app/javascript/js/controllers/sidebar_controller.js +29 -9
  253. data/app/javascript/js/controllers/table_row_controller.js +28 -0
  254. data/app/javascript/js/controllers/tippy_controller.js +1 -1
  255. data/app/javascript/js/controllers/toggle_controller.js +40 -5
  256. data/app/javascript/js/controllers.js +12 -2
  257. data/app/javascript/js/custom-stream-actions.js +10 -8
  258. data/app/views/avo/actions/show.html.erb +14 -10
  259. data/app/views/avo/base/_boolean_filter.html.erb +1 -1
  260. data/app/views/avo/base/_date_time_filter.html.erb +3 -3
  261. data/app/views/avo/base/_multiple_select_filter.html.erb +1 -1
  262. data/app/views/avo/base/_new_via_belongs_to.html.erb +2 -3
  263. data/app/views/avo/base/_text_filter.html.erb +1 -1
  264. data/app/views/avo/base/preview.html.erb +5 -4
  265. data/app/views/avo/debug/status.html.erb +5 -92
  266. data/app/views/avo/debug/status.text.erb +0 -2
  267. data/app/views/avo/home/_actions.html.erb +1 -1
  268. data/app/views/avo/home/_dashboards.html.erb +1 -1
  269. data/app/views/avo/home/_filters.html.erb +1 -1
  270. data/app/views/avo/home/_resources.html.erb +2 -2
  271. data/app/views/avo/home/failed_to_load.html.erb +2 -2
  272. data/app/views/avo/home/index.html.erb +25 -25
  273. data/app/views/avo/media_library/_form.html.erb +43 -28
  274. data/app/views/avo/media_library/show.html.erb +7 -3
  275. data/app/views/avo/modal/_size_selector.html.erb +46 -0
  276. data/app/views/avo/partials/_alerts.html.erb +1 -1
  277. data/app/views/avo/partials/_color_scheme_switcher.html.erb +106 -0
  278. data/app/views/avo/partials/_color_theme_override.html.erb +49 -0
  279. data/app/views/avo/partials/_confirm_dialog.html.erb +4 -4
  280. data/app/views/avo/partials/_custom_tools_alert.html.erb +6 -6
  281. data/app/views/avo/partials/_footer.html.erb +1 -1
  282. data/app/views/avo/partials/_header.html.erb +1 -1
  283. data/app/views/avo/partials/_javascript.html.erb +0 -2
  284. data/app/views/avo/partials/_navbar.html.erb +53 -8
  285. data/app/views/avo/partials/_sortable_component.html.erb +1 -1
  286. data/app/views/avo/partials/_table_header.html.erb +28 -19
  287. data/app/views/avo/partials/_view_toggle_button.html.erb +6 -29
  288. data/app/views/avo/partials/distribution_chart.html.erb +2 -2
  289. data/app/views/avo/private/_links_and_buttons.html.erb +12 -8
  290. data/app/views/avo/private/design.html.erb +8 -4
  291. data/app/views/avo/sidebar/_license_warning.html.erb +3 -3
  292. data/app/views/layouts/avo/application.html.erb +39 -17
  293. data/app/views/layouts/avo/modal.html.erb +7 -0
  294. data/avo.gemspec +3 -4
  295. data/config/i18n-tasks.yml +1 -1
  296. data/config/importmap.rb +1 -0
  297. data/config/initializers/pagy.rb +5 -25
  298. data/config/routes/dynamic_routes.rb +4 -0
  299. data/config/routes.rb +6 -7
  300. data/db/factories.rb +14 -0
  301. data/lib/avo/asset_manager.rb +2 -0
  302. data/lib/avo/avatar.rb +7 -0
  303. data/lib/avo/base_action.rb +16 -4
  304. data/lib/avo/concerns/breadcrumbs.rb +7 -66
  305. data/lib/avo/concerns/form_builder.rb +41 -0
  306. data/lib/avo/concerns/{has_profile_photo.rb → has_avatar.rb} +8 -4
  307. data/lib/avo/concerns/{has_cover_photo.rb → has_cover.rb} +4 -4
  308. data/lib/avo/concerns/has_description.rb +9 -0
  309. data/lib/avo/concerns/has_item_type.rb +6 -2
  310. data/lib/avo/concerns/has_items.rb +43 -58
  311. data/lib/avo/concerns/pagination.rb +29 -19
  312. data/lib/avo/concerns/row_controls_configuration.rb +22 -15
  313. data/lib/avo/configuration/branding.rb +7 -7
  314. data/lib/avo/configuration.rb +92 -45
  315. data/lib/avo/{cover_photo.rb → cover.rb} +2 -2
  316. data/lib/avo/current.rb +0 -11
  317. data/lib/avo/discreet_information.rb +52 -29
  318. data/lib/avo/dsl/field_parser.rb +1 -1
  319. data/lib/avo/engine.rb +41 -8
  320. data/lib/avo/error_manager.rb +1 -1
  321. data/lib/avo/fields/avatar_field.rb +19 -0
  322. data/lib/avo/fields/badge_field.rb +23 -3
  323. data/lib/avo/fields/base_field.rb +46 -1
  324. data/lib/avo/fields/concerns/dom_id.rb +17 -0
  325. data/lib/avo/fields/concerns/file_authorization.rb +4 -0
  326. data/lib/avo/fields/concerns/has_html_attributes.rb +1 -1
  327. data/lib/avo/fields/concerns/is_searchable.rb +2 -5
  328. data/lib/avo/fields/concerns/nested.rb +1 -1
  329. data/lib/avo/fields/files_field.rb +2 -2
  330. data/lib/avo/fields/frame_base_field.rb +2 -2
  331. data/lib/avo/fields/id_field.rb +5 -1
  332. data/lib/avo/fields/progress_bar_field.rb +1 -1
  333. data/lib/avo/fields/text_field.rb +1 -1
  334. data/lib/avo/plugin_manager.rb +4 -0
  335. data/lib/avo/resources/base.rb +33 -21
  336. data/lib/avo/resources/controls/actions_list.rb +3 -3
  337. data/lib/avo/resources/controls/base_control.rb +1 -1
  338. data/lib/avo/resources/items/card.rb +16 -0
  339. data/lib/avo/resources/items/header.rb +11 -0
  340. data/lib/avo/resources/items/holder.rb +18 -23
  341. data/lib/avo/resources/items/item_group.rb +5 -7
  342. data/lib/avo/resources/items/sidebar.rb +5 -9
  343. data/lib/avo/resources/items/tab.rb +8 -8
  344. data/lib/avo/resources/items/tab_group.rb +8 -10
  345. data/lib/avo/resources/resource_manager.rb +2 -1
  346. data/lib/avo/services/hq_reporter.rb +102 -0
  347. data/lib/avo/services/telemetry_service.rb +0 -1
  348. data/lib/avo/test_helpers.rb +36 -22
  349. data/lib/avo/u_i_instance.rb +60 -0
  350. data/lib/avo/version.rb +1 -1
  351. data/lib/avo/view_inquirer.rb +6 -1
  352. data/lib/avo/view_types/view_type_manager.rb +70 -0
  353. data/lib/avo.rb +30 -45
  354. data/lib/generators/avo/action_generator.rb +1 -1
  355. data/lib/generators/avo/resource_generator.rb +43 -0
  356. data/lib/generators/avo/resource_tool_generator.rb +1 -1
  357. data/lib/generators/avo/tailwindcss/install_generator.rb +0 -6
  358. data/lib/generators/avo/templates/cards/partial_card_partial.tt +1 -1
  359. data/lib/generators/avo/templates/initializer/avo.tt +7 -9
  360. data/lib/generators/avo/templates/locales/avo.ar.yml +25 -0
  361. data/lib/generators/avo/templates/locales/avo.de.yml +25 -0
  362. data/lib/generators/avo/templates/locales/avo.en.yml +25 -0
  363. data/lib/generators/avo/templates/locales/avo.es.yml +25 -0
  364. data/lib/generators/avo/templates/locales/avo.fr.yml +25 -0
  365. data/lib/generators/avo/templates/locales/avo.it.yml +25 -0
  366. data/lib/generators/avo/templates/locales/avo.ja.yml +25 -0
  367. data/lib/generators/avo/templates/locales/avo.nb.yml +25 -0
  368. data/lib/generators/avo/templates/locales/avo.nl.yml +25 -0
  369. data/lib/generators/avo/templates/locales/avo.nn.yml +25 -0
  370. data/lib/generators/avo/templates/locales/avo.pl.yml +25 -0
  371. data/lib/generators/avo/templates/locales/avo.pt-BR.yml +25 -0
  372. data/lib/generators/avo/templates/locales/avo.pt.yml +25 -0
  373. data/lib/generators/avo/templates/locales/avo.ro.yml +25 -0
  374. data/lib/generators/avo/templates/locales/avo.ru.yml +25 -0
  375. data/lib/generators/avo/templates/locales/avo.tr.yml +25 -0
  376. data/lib/generators/avo/templates/locales/{avo.uk.yml → avo.ua.yml} +26 -1
  377. data/lib/generators/avo/templates/locales/avo.zh-TW.yml +25 -0
  378. data/lib/generators/avo/templates/locales/avo.zh.yml +25 -0
  379. data/lib/generators/avo/templates/resource/resource.tt +10 -1
  380. data/lib/generators/avo/templates/resource_tools/partial.tt +20 -22
  381. data/lib/generators/avo/templates/tailwindcss/avo.tailwind.css +1 -3
  382. data/lib/generators/avo/templates/tailwindcss/tailwind.config.js +0 -7
  383. data/lib/generators/avo/templates/tool/view.tt +14 -16
  384. data/lib/generators/avo/tool_generator.rb +3 -3
  385. data/lib/generators/avo/version_generator.rb +1 -1
  386. data/lib/tasks/avo_tasks.rake +29 -25
  387. metadata +144 -97
  388. data/app/assets/stylesheets/avo.base.css +0 -130
  389. data/app/assets/stylesheets/css/breadcrumbs.css +0 -16
  390. data/app/assets/stylesheets/css/buttons.css +0 -19
  391. data/app/assets/stylesheets/css/tailwindcss/base.css +0 -1
  392. data/app/assets/stylesheets/css/tailwindcss/components.css +0 -1
  393. data/app/assets/stylesheets/css/tailwindcss/utilities.css +0 -1
  394. data/app/assets/svgs/avo/arrow-down.svg +0 -3
  395. data/app/assets/svgs/avo/arrow-up.svg +0 -3
  396. data/app/assets/svgs/avo/detach.svg +0 -8
  397. data/app/assets/svgs/avo/download-solid-reversed.svg +0 -3
  398. data/app/assets/svgs/avo/download-solid.svg +0 -3
  399. data/app/assets/svgs/avo/edit.svg +0 -5
  400. data/app/assets/svgs/avo/editor-bold.svg +0 -1
  401. data/app/assets/svgs/avo/editor-italic.svg +0 -1
  402. data/app/assets/svgs/avo/editor-link.svg +0 -1
  403. data/app/assets/svgs/avo/editor-list.svg +0 -1
  404. data/app/assets/svgs/avo/editor-strike.svg +0 -1
  405. data/app/assets/svgs/avo/editor-underline.svg +0 -1
  406. data/app/assets/svgs/avo/eye.svg +0 -1
  407. data/app/assets/svgs/avo/trash-sm.svg +0 -3
  408. data/app/assets/svgs/avo/trash.svg +0 -7
  409. data/app/components/avo/cover_photo_component.html.erb +0 -3
  410. data/app/components/avo/cover_photo_component.rb +0 -19
  411. data/app/components/avo/fields/common/badge_viewer_component.html.erb +0 -1
  412. data/app/components/avo/fields/common/badge_viewer_component.rb +0 -33
  413. data/app/components/avo/index/resource_grid_component.html.erb +0 -23
  414. data/app/components/avo/index/resource_grid_component.rb +0 -10
  415. data/app/components/avo/index/resource_map_component.html.erb +0 -16
  416. data/app/components/avo/index/resource_map_component.rb +0 -114
  417. data/app/components/avo/index/resource_table_component.html.erb +0 -52
  418. data/app/components/avo/panel_component.html.erb +0 -63
  419. data/app/components/avo/panel_component.rb +0 -43
  420. data/app/components/avo/panel_header_component.html.erb +0 -42
  421. data/app/components/avo/panel_header_component.rb +0 -31
  422. data/app/components/avo/profile_photo_component.html.erb +0 -6
  423. data/app/components/avo/profile_photo_component.rb +0 -9
  424. data/app/components/avo/sidebar/heading_component.html.erb +0 -21
  425. data/app/components/avo/sidebar/heading_component.rb +0 -9
  426. data/app/components/avo/tab_switcher_component.html.erb +0 -20
  427. data/app/components/avo/tab_switcher_component.rb +0 -45
  428. data/app/views/avo/base/close_modal_and_reload_field.turbo_stream.erb +0 -8
  429. data/app/views/avo/debug/report.html.erb +0 -37
  430. data/app/views/avo/partials/_panel_breadcrumbs.html.erb +0 -3
  431. data/app/views/avo/partials/_resource_search.html.erb +0 -16
  432. data/lib/avo/licensing/community_license.rb +0 -6
  433. data/lib/avo/licensing/h_q.rb +0 -202
  434. data/lib/avo/licensing/license.rb +0 -76
  435. data/lib/avo/licensing/license_manager.rb +0 -24
  436. data/lib/avo/licensing/nil_license.rb +0 -14
  437. data/lib/avo/licensing/pro_license.rb +0 -20
  438. data/lib/avo/licensing/request.rb +0 -20
  439. data/lib/avo/profile_photo.rb +0 -7
  440. data/lib/avo/services/debug_service.rb +0 -107
  441. data/tailwind.preset.js +0 -171
  442. /data/{public/avo-assets → app/assets/images/avo}/favicon.ico +0 -0
  443. /data/{public/avo-assets → app/assets/images/avo}/fonts/inter-v7-latin-500.eot +0 -0
  444. /data/{public/avo-assets → app/assets/images/avo}/fonts/inter-v7-latin-500.svg +0 -0
  445. /data/{public/avo-assets → app/assets/images/avo}/fonts/inter-v7-latin-500.ttf +0 -0
  446. /data/{public/avo-assets → app/assets/images/avo}/fonts/inter-v7-latin-500.woff +0 -0
  447. /data/{public/avo-assets → app/assets/images/avo}/fonts/inter-v7-latin-500.woff2 +0 -0
  448. /data/{public/avo-assets → app/assets/images/avo}/fonts/inter-v7-latin-600.eot +0 -0
  449. /data/{public/avo-assets → app/assets/images/avo}/fonts/inter-v7-latin-600.svg +0 -0
  450. /data/{public/avo-assets → app/assets/images/avo}/fonts/inter-v7-latin-600.ttf +0 -0
  451. /data/{public/avo-assets → app/assets/images/avo}/fonts/inter-v7-latin-600.woff +0 -0
  452. /data/{public/avo-assets → app/assets/images/avo}/fonts/inter-v7-latin-600.woff2 +0 -0
  453. /data/{public/avo-assets → app/assets/images/avo}/fonts/inter-v7-latin-700.eot +0 -0
  454. /data/{public/avo-assets → app/assets/images/avo}/fonts/inter-v7-latin-700.svg +0 -0
  455. /data/{public/avo-assets → app/assets/images/avo}/fonts/inter-v7-latin-700.ttf +0 -0
  456. /data/{public/avo-assets → app/assets/images/avo}/fonts/inter-v7-latin-700.woff +0 -0
  457. /data/{public/avo-assets → app/assets/images/avo}/fonts/inter-v7-latin-700.woff2 +0 -0
  458. /data/{public/avo-assets → app/assets/images/avo}/fonts/inter-v7-latin-regular.eot +0 -0
  459. /data/{public/avo-assets → app/assets/images/avo}/fonts/inter-v7-latin-regular.svg +0 -0
  460. /data/{public/avo-assets → app/assets/images/avo}/fonts/inter-v7-latin-regular.ttf +0 -0
  461. /data/{public/avo-assets → app/assets/images/avo}/fonts/inter-v7-latin-regular.woff +0 -0
  462. /data/{public/avo-assets → app/assets/images/avo}/fonts/inter-v7-latin-regular.woff2 +0 -0
  463. /data/{public/avo-assets → app/assets/images/avo}/logo-on-white.png +0 -0
  464. /data/{public/avo-assets → app/assets/images/avo}/logo.png +0 -0
  465. /data/{public/avo-assets → app/assets/images/avo}/logomark.png +0 -0
  466. /data/{public/avo-assets → app/assets/images/avo}/placeholder.svg +0 -0
@@ -0,0 +1,102 @@
1
+ require "net/http"
2
+
3
+ module Avo
4
+ module Services
5
+ class HqReporter
6
+ ENDPOINT = "https://v3.avohq.io/api/v3/licenses/check".freeze unless const_defined?(:ENDPOINT)
7
+ REQUEST_TIMEOUT = 5 unless const_defined?(:REQUEST_TIMEOUT) # seconds
8
+ CACHE_TIME = 24.hours.to_i unless const_defined?(:CACHE_TIME) # seconds
9
+
10
+ class << self
11
+ def cache_key
12
+ "avo.hq_reporter-#{Avo::VERSION.parameterize}.reported"
13
+ end
14
+
15
+ # Fire and forget - call this from a thread
16
+ # request_info should be a hash with :ip, :host, :port keys
17
+ def report(request_info = {})
18
+ return unless should_report?
19
+
20
+ cache_store.write(cache_key, {reported_at: Time.now}, expires_in: CACHE_TIME)
21
+
22
+ perform_request(request_info)
23
+ rescue
24
+ # Silently swallow all errors
25
+ end
26
+
27
+ private
28
+
29
+ def should_report?
30
+ return false unless Rails.env.production?
31
+ return false if Avo.plugin_manager.installed?("avo-licensing")
32
+ return false if already_reported?
33
+
34
+ true
35
+ end
36
+
37
+ def already_reported?
38
+ cached = cache_store.read(cache_key)
39
+ return false unless cached.present?
40
+
41
+ # Handle cache stores that don't auto-expire
42
+ reported_at = cached[:reported_at] || cached["reported_at"]
43
+ return false unless reported_at
44
+
45
+ Time.parse(reported_at.to_s) > Time.now - CACHE_TIME
46
+ rescue
47
+ false
48
+ end
49
+
50
+ def cache_store
51
+ Avo.configuration.cache_store
52
+ end
53
+
54
+ def payload(request_info)
55
+ result = {
56
+ license_key: Avo.configuration.license_key,
57
+ avo_version: Avo::VERSION,
58
+ rails_version: Rails::VERSION::STRING,
59
+ ruby_version: RUBY_VERSION,
60
+ environment: Rails.env,
61
+ ip: request_info[:ip],
62
+ host: request_info[:host],
63
+ port: request_info[:port],
64
+ app_name: app_name
65
+ }
66
+
67
+ if Avo.configuration.send_metadata
68
+ begin
69
+ result[:avo_metadata] = Avo::Services::TelemetryService.avo_metadata
70
+ rescue => e
71
+ result[:avo_metadata] = {
72
+ error_message: e.message,
73
+ error: "Failed to generate the Avo metadata"
74
+ }
75
+ end
76
+ else
77
+ result[:avo_metadata] = :disabled
78
+ end
79
+
80
+ result
81
+ end
82
+
83
+ def perform_request(request_info)
84
+ uri = URI.parse(ENDPOINT)
85
+ http = Net::HTTP.new(uri.host, uri.port)
86
+ http.use_ssl = (uri.scheme == "https")
87
+ http.read_timeout = REQUEST_TIMEOUT
88
+ http.open_timeout = REQUEST_TIMEOUT
89
+ request = Net::HTTP::Post.new(uri.request_uri, {"Content-Type" => "application/json"})
90
+ request.body = payload(request_info).to_json
91
+ http.request(request)
92
+ end
93
+
94
+ def app_name
95
+ Rails.application.class.to_s.split("::").first
96
+ rescue
97
+ nil
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
@@ -2,7 +2,6 @@ class Avo::Services::TelemetryService
2
2
  class << self
3
3
  def telemetry_info
4
4
  {
5
- # license: Avo.configuration.license,
6
5
  # license_key: Avo.configuration.license_key,
7
6
  avo_version: Avo::VERSION,
8
7
  rails_version: Rails::VERSION::STRING,
@@ -28,7 +28,7 @@ module Avo
28
28
  # show_field_wrapper(id: "name", type: "text")
29
29
  # show_field_wrapper(id: "name")
30
30
  def show_field_wrapper(id:, type: nil)
31
- base_data = "[data-panel-id='main'] [data-field-id='#{id}']"
31
+ base_data = "[data-field-id='#{id}']"
32
32
 
33
33
  if type.present?
34
34
  find("#{base_data}[data-resource-show-target='#{wrapper_name_for(id: id, type: type)}']")
@@ -93,21 +93,8 @@ module Avo
93
93
  "—"
94
94
  end
95
95
 
96
- # Example usage:
97
- # click_resource_search_input # opens the first search box on the given page
98
- # opens the search box for the "users" resource
99
- # within(has_and_belongs_to_many_field_wrapper(id: :users)) {
100
- # click_resource_search_input
101
- # write_in_search("Bob")
102
- # }
103
- def click_resource_search_input
104
- first("[data-search-resource]:not([data-search-resource='global'])").click
105
- wait_for_search_loaded
106
- end
107
-
108
96
  def click_global_search_input
109
- page.find(:xpath, "//*[contains(@class, 'global-search')]").click
110
- wait_for_search_loaded
97
+ page.find("[data-global-search-target='input']").click
111
98
  end
112
99
 
113
100
  # Should use the click_global_search_input or click_resource_search_input method to open the search box first.
@@ -119,10 +106,15 @@ module Avo
119
106
  # }
120
107
  def write_in_search(input)
121
108
  # Use xpath to find outside of within context if any
122
- find(:xpath, "//input[@class='aa-Input']").set(input)
109
+ find('[data-resource-search-target="input"]').set(input)
123
110
  wait_for_search_loaded
124
111
  end
125
112
 
113
+ def write_in_global_search(input)
114
+ page.find("[data-global-search-target='input']").set(input)
115
+ end
116
+
117
+ # TODO: this will make sense only on global search
126
118
  # Should use the click_global_search_input or click_resource_search_input method to open the search box first and optionaly write_in_search.
127
119
  # Example usage:
128
120
  # open_search_box(:users) # opens the search box for the "users" resource
@@ -142,7 +134,7 @@ module Avo
142
134
  # Sometimes other element may be overlapping the button so the `.trigger("click")` solves the issue
143
135
  # Trigger can't be used by default because it breaks on some feature specs
144
136
  def save
145
- button = find("button.button-component", text: "Save")
137
+ button = find("button.button", text: "Save")
146
138
  button.click
147
139
  rescue Capybara::Cuprite::MouseEventFailed
148
140
  button.trigger("click")
@@ -151,14 +143,16 @@ module Avo
151
143
  end
152
144
 
153
145
  def click_tab(tab_name = "", within_target: nil, **args)
146
+ tab_container_selector = '[data-controller="tabs"] [role="tablist"]'
147
+
154
148
  if within_target.present?
155
149
  within within_target do
156
- within find('[data-controller="tabs"] [data-tabs-target="tabSwitcher"]') do
150
+ within find(tab_container_selector) do
157
151
  find_link(tab_name).trigger("click")
158
152
  end
159
153
  end
160
154
  else
161
- within find('[data-controller="tabs"] [data-tabs-target="tabSwitcher"]') do
155
+ within find(tab_container_selector) do
162
156
  find_link(tab_name).trigger("click")
163
157
  end
164
158
  end
@@ -192,6 +186,22 @@ module Avo
192
186
  sleep 0.2
193
187
  end
194
188
 
189
+ def set_picker_dates(input, *dates)
190
+ page.execute_script(
191
+ "arguments[0]._flatpickr.setDate(arguments[1], true)",
192
+ input.native,
193
+ (dates.length == 1) ? dates.first : dates
194
+ )
195
+ end
196
+
197
+ def set_picker_time(input, hour:, minute: 0, second: 0)
198
+ page.execute_script(
199
+ "arguments[0]._flatpickr.setDate(arguments[1], true)",
200
+ input.native,
201
+ "#{hour}:#{minute}:#{second}"
202
+ )
203
+ end
204
+
195
205
  def set_picker_hour(value)
196
206
  find(".flatpickr-hour").set(value)
197
207
  end
@@ -215,7 +225,7 @@ module Avo
215
225
  end
216
226
 
217
227
  def close_picker
218
- find('[data-target="title"]').trigger("click")
228
+ all(".header__title").first.trigger("click")
219
229
  sleep 0.3
220
230
  end
221
231
 
@@ -227,7 +237,7 @@ module Avo
227
237
  # open_panel_action(list: nil, action_name: "Release fish")
228
238
  # open_panel_action(list: "Runnables", action_name: "Release fish")
229
239
  def open_panel_action(action_name:, list: "Actions")
230
- open_action(action_name: action_name, list: list, context: first("[data-target='panel-tools']"))
240
+ open_action(action_name: action_name, list: list, context: first(".header__controls"))
231
241
  end
232
242
 
233
243
  # Open the action from the record_id row
@@ -363,7 +373,7 @@ module Avo
363
373
  if list.present?
364
374
  sleep 0.1
365
375
  click_on list
366
- within("[data-toggle-target='panel']") do
376
+ within("[data-dropdown-list='#{list}']", visible: :all) do
367
377
  find("a[data-action-name='#{action_name}']").click
368
378
  end
369
379
  else
@@ -382,5 +392,9 @@ module Avo
382
392
  def row(id)
383
393
  "[data-component-name='avo/index/table_row_component'][data-resource-id='#{id}']"
384
394
  end
395
+
396
+ def strip_html(text)
397
+ text.strip.gsub(/\s+/, " ")
398
+ end
385
399
  end
386
400
  end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Avo::UIInstance
4
+ unless defined?(MISSING_COMPONENT_CLASS)
5
+ MISSING_COMPONENT_CLASS = "Avo::ComponentMissingComponent"
6
+ end
7
+
8
+ # Cache for resolved component classes to avoid repeated classify/constantize calls
9
+ @component_cache = {}
10
+ @cache_mutex = Mutex.new
11
+
12
+ class << self
13
+ def resolve_component(method)
14
+ # Check cache first (thread-safe read)
15
+ cached = @component_cache[method]
16
+ return cached if cached
17
+
18
+ # Cache miss - resolve and store (thread-safe write)
19
+ @cache_mutex.synchronize do
20
+ # Double-check after acquiring lock
21
+ return @component_cache[method] if @component_cache[method]
22
+
23
+ component_class = "#{method.to_s.delete_suffix("_component")}_component"
24
+ full_class_name = "Avo::#{component_class.classify}"
25
+ ui_full_class_name = "Avo::UI::#{component_class.classify}"
26
+
27
+ resolved = if Object.const_defined?(full_class_name)
28
+ full_class_name.constantize
29
+ elsif Object.const_defined?(ui_full_class_name)
30
+ ui_full_class_name.constantize
31
+ end
32
+
33
+ @component_cache[method] = resolved
34
+ end
35
+ end
36
+
37
+ def clear_cache!
38
+ @cache_mutex.synchronize { @component_cache.clear }
39
+ end
40
+
41
+ # Used in parent apps like this `ui.panel(...)`
42
+ # @method: string "panel"
43
+ # @return: (method: String) -> Component
44
+ def method_missing(method, ...)
45
+ component_class = resolve_component(method)
46
+
47
+ if component_class
48
+ component_class.new(...)
49
+ else
50
+ MISSING_COMPONENT_CLASS.safe_constantize.new(component_name: method)
51
+ end
52
+ end
53
+
54
+ def respond_to_missing?(method, include_private = false)
55
+ # Since method_missing always handles any method call (either with a real component
56
+ # or falling back to MISSING_COMPONENT_CLASS), respond_to? should return true
57
+ true
58
+ end
59
+ end
60
+ end
data/lib/avo/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Avo
2
- VERSION = "3.30.4" unless const_defined?(:VERSION)
2
+ VERSION = "4.0.0.beta.1" unless const_defined?(:VERSION)
3
3
  end
@@ -10,6 +10,7 @@ module Avo
10
10
 
11
11
  @display = in? DISPLAY_VIEWS
12
12
  @form = in? FORM_VIEWS
13
+ @single = in? [*FORM_VIEWS, :show].compact.uniq
13
14
  end
14
15
 
15
16
  def display?
@@ -20,12 +21,16 @@ module Avo
20
21
  @form
21
22
  end
22
23
 
24
+ def single?
25
+ @single
26
+ end
27
+
23
28
  # To avoid breaking changes we allow the comparison with symbols
24
29
  def ==(other)
25
30
  if other.is_a? Symbol
26
31
  to_sym == other
27
32
  else
28
- super(other)
33
+ super
29
34
  end
30
35
  end
31
36
 
@@ -0,0 +1,70 @@
1
+ module Avo
2
+ module ViewTypes
3
+ class ViewTypeManager
4
+ attr_reader :registry
5
+
6
+ def initialize
7
+ @registry = {}
8
+ end
9
+
10
+ def register(name, component:, icon:, active_icon:, translation_key: nil)
11
+ @registry[name.to_sym] = {
12
+ component: component,
13
+ icon: icon,
14
+ active_icon: active_icon,
15
+ translation_key: translation_key
16
+ }
17
+ end
18
+
19
+ def find(name)
20
+ @registry[name.to_sym]
21
+ end
22
+
23
+ def component_for(name)
24
+ entry = find(name)
25
+
26
+ raise Avo::ViewTypeComponentNotFoundError, "No component registered for view type '#{name}'" unless entry
27
+
28
+ component = entry[:component]
29
+ component.is_a?(String) ? component.constantize : component
30
+ end
31
+
32
+ def registered?(name)
33
+ @registry.key?(name.to_sym)
34
+ end
35
+
36
+ def reset
37
+ @registry = {}
38
+ register_defaults
39
+ end
40
+
41
+ private
42
+
43
+ def register_defaults
44
+ register :table,
45
+ component: Avo::ViewTypes::TableComponent,
46
+ icon: "tabler/outline/layout-list",
47
+ active_icon: "tabler/filled/layout-list"
48
+
49
+ register :grid,
50
+ component: Avo::ViewTypes::GridComponent,
51
+ icon: "tabler/outline/layout-grid",
52
+ active_icon: "tabler/filled/layout-grid"
53
+
54
+ register :map,
55
+ component: Avo::ViewTypes::MapComponent,
56
+ icon: "tabler/outline/compass",
57
+ active_icon: "tabler/filled/compass"
58
+
59
+ register :list,
60
+ component: Avo::ViewTypes::TableComponent,
61
+ icon: "tabler/outline/layout-list",
62
+ active_icon: "tabler/filled/layout-list"
63
+ end
64
+ end
65
+ end
66
+
67
+ def self.view_type_manager
68
+ @view_type_manager ||= Avo::ViewTypes::ViewTypeManager.new.tap(&:reset)
69
+ end
70
+ end
data/lib/avo.rb CHANGED
@@ -1,6 +1,5 @@
1
1
  require "zeitwerk"
2
2
  require "net/http"
3
- require "active_support/inflector"
4
3
  require_relative "avo/version"
5
4
  require_relative "avo/engine" if defined?(Rails)
6
5
 
@@ -36,6 +35,8 @@ module Avo
36
35
 
37
36
  class DeprecatedAPIError < StandardError; end
38
37
 
38
+ class ViewTypeComponentNotFoundError < StandardError; end
39
+
39
40
  # Exception raised when a resource is missing
40
41
  class MissingResourceError < StandardError
41
42
  def initialize(model_class, field)
@@ -69,16 +70,19 @@ module Avo
69
70
  attr_reader :logger
70
71
  attr_reader :cache_store
71
72
  attr_reader :field_manager
72
-
73
- delegate :license, :app, :error_manager, :tool_manager, :resource_manager, to: Avo::Current
73
+ delegate :app, :error_manager, :tool_manager, :resource_manager, to: Avo::Current
74
74
 
75
75
  # Runs when the app boots up
76
76
  def boot
77
77
  Turbo::Streams::TagBuilder.prepend(Avo::TurboStreamActionsHelper)
78
78
  @logger = Avo.configuration.logger
79
79
  @field_manager = Avo::Fields::FieldManager.build
80
+ @view_type_manager = nil # force re-init with defaults on next access
80
81
  @cache_store = Avo.configuration.cache_store
81
82
  Avo.plugin_manager.reset
83
+ # Run load hooks for plugins to include them in the app.
84
+ # This is useful for plugins that need to include modules in the app that will be used on avo_boot hook.
85
+ ActiveSupport.run_load_hooks(:avo_plugin_include, self)
82
86
  ActiveSupport.run_load_hooks(:avo_boot, self)
83
87
  eager_load_actions
84
88
  end
@@ -90,6 +94,7 @@ module Avo
90
94
  unless Rails.env.production?
91
95
  check_rails_version_issues
92
96
  display_menu_editor_warning
97
+ display_profile_menu_editor_warning
93
98
  end
94
99
  Avo::Current.resource_manager = Avo::Resources::ResourceManager.build
95
100
  Avo::Current.tool_manager = Avo::Tools::ToolManager.build
@@ -105,46 +110,14 @@ module Avo
105
110
  .to_s
106
111
  end
107
112
 
108
- def main_menu
109
- return unless Avo.plugin_manager.installed?("avo-menu")
110
-
111
- # Return empty menu if the app doesn't have the profile menu configured
112
- return Avo::Menu::Builder.new.build unless has_main_menu?
113
-
114
- Avo::Menu::Builder.parse_menu(&Avo.configuration.main_menu)
115
- end
116
-
117
- def profile_menu
118
- return unless Avo.plugin_manager.installed?("avo-menu")
119
-
120
- # Return empty menu if the app doesn't have the profile menu configured
121
- return Avo::Menu::Builder.new.build unless has_profile_menu?
122
-
123
- Avo::Menu::Builder.parse_menu(&Avo.configuration.profile_menu)
124
- end
125
-
126
113
  def app_status
127
- license.valid?
114
+ true
128
115
  end
129
116
 
130
117
  def avo_dynamic_filters_installed?
131
118
  defined?(Avo::DynamicFilters).present?
132
119
  end
133
120
 
134
- def has_main_menu?
135
- return false if Avo.license.lacks_with_trial(:menu_editor)
136
- return false if Avo.configuration.main_menu.nil?
137
-
138
- true
139
- end
140
-
141
- def has_profile_menu?
142
- return false if Avo.license.lacks_with_trial(:menu_editor)
143
- return false if Avo.configuration.profile_menu.nil?
144
-
145
- true
146
- end
147
-
148
121
  def mount_engines
149
122
  -> {
150
123
  raise "'mount_engines' method is now obsolete. \n" \
@@ -162,7 +135,9 @@ module Avo
162
135
  end
163
136
 
164
137
  def check_rails_version_issues
165
- if Rails.version.start_with?("7.1") && Avo.configuration.license.in?(["pro", "advanced"])
138
+ return if Rails.env.test?
139
+
140
+ if Rails.version.start_with?("7.1")
166
141
  Avo.error_manager.add({
167
142
  url: "https://docs.avohq.io/3.0/upgrade.html#upgrade-from-3-7-4-to-3-9-1",
168
143
  target: "_blank",
@@ -177,13 +152,23 @@ module Avo
177
152
  end
178
153
 
179
154
  def display_menu_editor_warning
180
- if Avo.configuration.license == "community" && has_main_menu?
181
- Avo.error_manager.add({
182
- url: "https://docs.avohq.io/3.0/menu-editor.html",
183
- target: "_blank",
184
- message: "The menu editor is available exclusively with the Pro license or above. Consider upgrading to access this feature."
185
- })
186
- end
155
+ return if Avo.configuration.main_menu.nil?
156
+
157
+ Avo.error_manager.add({
158
+ url: "https://docs.avohq.io/3.0/menu-editor.html",
159
+ target: "_blank",
160
+ message: "The menu editor is available exclusively with the Pro license or above. Consider upgrading to access this feature."
161
+ })
162
+ end
163
+
164
+ def display_profile_menu_editor_warning
165
+ return if Avo.configuration.profile_menu.nil?
166
+
167
+ Avo.error_manager.add({
168
+ url: "https://docs.avohq.io/3.0/menu-editor.html#profile-menu",
169
+ target: "_blank",
170
+ message: "The profile menu editor is available exclusively with the Pro license or above. Consider upgrading to access this feature."
171
+ })
187
172
  end
188
173
  end
189
174
  end
@@ -192,4 +177,4 @@ def 🥑
192
177
  Avo
193
178
  end
194
179
 
195
- loader.eager_load if defined?(Rails)
180
+ loader.eager_load
@@ -15,7 +15,7 @@ module Generators
15
15
  end
16
16
 
17
17
  def configuration_options
18
- configuration = " self.name = \"#{options[:name] || name.titleize}\""
18
+ configuration = " self.name = \"#{options[:name] || name.humanize}\""
19
19
  configuration += "\n self.standalone = true" if options[:standalone]
20
20
 
21
21
  configuration
@@ -321,6 +321,49 @@ module Generators
321
321
  def field(name, type)
322
322
  ::Avo::Mappings::NAMES_MAPPING[name.to_sym] || ::Avo::Mappings::FIELDS_MAPPING[type&.to_sym] || {field: "text"}
323
323
  end
324
+
325
+ ICON_MAP = {
326
+ user: "tabler/outline/users",
327
+ customer: "tabler/outline/user",
328
+ transaction: "tabler/outline/credit-card-pay",
329
+ post: "tabler/outline/ballpen",
330
+ comment: "tabler/outline/message",
331
+ product: "tabler/outline/package",
332
+ order: "tabler/outline/shopping-cart",
333
+ category: "tabler/outline/folder",
334
+ tag: "tabler/outline/tag",
335
+ project: "tabler/outline/building-store",
336
+ team: "tabler/outline/users-group",
337
+ company: "tabler/outline/building",
338
+ invoice: "tabler/outline/file-invoice",
339
+ payment: "tabler/outline/cash",
340
+ article: "tabler/outline/article",
341
+ event: "tabler/outline/calendar-event",
342
+ notification: "tabler/outline/bell",
343
+ message: "tabler/outline/mail",
344
+ setting: "tabler/outline/settings",
345
+ report: "tabler/outline/chart-bar",
346
+ task: "tabler/outline/checklist",
347
+ review: "tabler/outline/star",
348
+ photo: "tabler/outline/photo",
349
+ image: "tabler/outline/photo",
350
+ video: "tabler/outline/video",
351
+ file: "tabler/outline/file",
352
+ document: "tabler/outline/file-text",
353
+ role: "tabler/outline/shield",
354
+ permission: "tabler/outline/lock",
355
+ subscription: "tabler/outline/credit-card",
356
+ plan: "tabler/outline/list",
357
+ address: "tabler/outline/map-pin",
358
+ location: "tabler/outline/map-pin",
359
+ country: "tabler/outline/globe",
360
+ city: "tabler/outline/building-community",
361
+ account: "tabler/outline/user-circle",
362
+ }.freeze
363
+
364
+ def icon_for_resource
365
+ ICON_MAP[singular_name.underscore.split("/").last.downcase.to_sym]
366
+ end
324
367
  end
325
368
  end
326
369
 
@@ -32,7 +32,7 @@ module Generators
32
32
  end
33
33
 
34
34
  def in_code(text)
35
- "<code class='p-1 rounded bg-gray-500 text-white text-sm'>#{text}</code>"
35
+ "<code class='p-1 rounded-sm bg-gray-500 text-white text-sm'>#{text}</code>"
36
36
  end
37
37
  end
38
38
  end
@@ -21,12 +21,6 @@ module Generators
21
21
  copy_file template_path("tailwind.config.js"), path
22
22
  end
23
23
 
24
- unless (path = Rails.root.join("app", "assets", "stylesheets", "avo", "tailwindcss")).exist?
25
- say "Generating the tailwindcss directory."
26
- directory ::Avo::Engine.root.join("app", "assets", "stylesheets", "css", "tailwindcss"), path
27
- end
28
-
29
-
30
24
  unless (path = Rails.root.join("app", "assets", "stylesheets", "avo" ,"avo.tailwind.css")).exist?
31
25
  say "Add default tailwind.css"
32
26
  copy_file template_path("avo.tailwind.css"), path
@@ -5,6 +5,6 @@
5
5
  @dashboard: <%%= @dashboard %>
6
6
  <br />
7
7
  <br />
8
- Customize this partial under <code class='p-1 rounded bg-gray-500 text-white text-sm'>app/views/avo/cards/_<%= name.underscore %>.html.erb</code>
8
+ Customize this partial under <code class='p-1 rounded-sm bg-gray-500 text-white text-sm'>app/views/avo/cards/_<%= name.underscore %>.html.erb</code>
9
9
  </div>
10
10
  </div>
@@ -106,12 +106,11 @@ Avo.configure do |config|
106
106
  # config.timezone = 'UTC'
107
107
  # config.currency = 'USD'
108
108
  # config.hide_layout_when_printing = false
109
- # config.full_width_container = false
110
- # config.full_width_index_view = false
109
+ # config.container_width = :large # :full, :large, or :small. Hash for per-view: { index: :full, single: :small }
110
+ # config.use_stacked_fields = false
111
111
  # config.search_debounce = 300
112
112
  # config.view_component_path = "app/components"
113
113
  # config.display_license_request_timeout_error = true
114
- # config.disabled_features = []
115
114
  # config.buttons_on_form_footers = true
116
115
  # config.field_wrapper_layout = true
117
116
  # config.resource_parent_controller = "Avo::ResourcesController"
@@ -129,16 +128,15 @@ Avo.configure do |config|
129
128
  # 600 => "#066BB2",
130
129
  # },
131
130
  # chart_colors: ["#0B8AE2", "#34C683", "#2AB1EE", "#34C6A8"],
132
- # logo: "/avo-assets/logo.png",
133
- # logomark: "/avo-assets/logomark.png",
134
- # placeholder: "/avo-assets/placeholder.svg",
135
- # favicon: "/avo-assets/favicon.ico"
131
+ # logo: "avo/logo.png",
132
+ # logomark: "avo/logomark.png",
133
+ # placeholder: "avo/placeholder.svg",
134
+ # favicon: "avo/favicon.ico"
136
135
  # }
137
136
 
138
137
  ## == Breadcrumbs ==
139
- # config.display_breadcrumbs = true
140
138
  # config.set_initial_breadcrumbs do
141
- # add_breadcrumb "Home", '/<%= options[:path] %>'
139
+ # add_breadcrumb title: "Home", path: '/<%= options[:path] %>'
142
140
  # end
143
141
 
144
142
  ## == Menus ==