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
@@ -17,7 +17,7 @@ export function tagTemplate(tagData) {
17
17
  class="tagify__tag ${tagData.class ? tagData.class : ''}"
18
18
  ${this.getAttributes(tagData)}
19
19
  >
20
- <x title='' class='tagify__tag__removeBtn' role='button' aria-label='remove tag'></x>
20
+ <x title='' class=' tagify__tag__removeBtn' role='button' aria-label='remove tag'></x>
21
21
  <div>
22
22
  <span class='tagify__tag-text'>${possibleLabel}</span>
23
23
  </div>
@@ -28,15 +28,13 @@ export function tagTemplate(tagData) {
28
28
  export function suggestionItemTemplate(tagData) {
29
29
  return `
30
30
  <div ${this.getAttributes(tagData)}
31
- class='tagify__dropdown__item flex items-center ${
32
- tagData.class ? tagData.class : ''
31
+ class='tagify__dropdown__item dropdown-menu__item ${tagData.class ? tagData.class : ''
33
32
  }'
34
33
  tabindex="0"
35
34
  role="option">
36
- ${
37
- tagData.avatar
35
+ ${tagData.avatar
38
36
  ? `
39
- <div class='rounded w-8 h-8 block mr-2'>
37
+ <div class='rounded-sm w-8 h-8 block me-2'>
40
38
  <img onerror="this.style.visibility='hidden'" class="w-full" src="${tagData.avatar}">
41
39
  </div>`
42
40
  : ''
@@ -0,0 +1,42 @@
1
+ import { Controller } from '@hotwired/stimulus'
2
+
3
+ // Connects to data-controller="grid-cover-empty-state"
4
+ export default class extends Controller {
5
+ static targets = ['icon']
6
+
7
+ mousemove(event) {
8
+ const maxDist = 90
9
+ const maxPush = 30
10
+ const cursorX = event.clientX
11
+ const cursorY = event.clientY
12
+
13
+ this.iconTargets.forEach((icon) => {
14
+ const r = icon.getBoundingClientRect()
15
+ const cx = r.left + r.width / 2
16
+ const cy = r.top + r.height / 2
17
+ const dx = cx - cursorX
18
+ const dy = cy - cursorY
19
+ const dist = Math.sqrt(dx * dx + dy * dy)
20
+
21
+ if (dist < maxDist && dist > 0) {
22
+ const scale = parseFloat(icon.dataset.repulsionScale ?? 1)
23
+ const force = (1 - dist / maxDist) * maxPush * scale
24
+ icon.style.setProperty('--tx', `${(dx / dist) * force}px`)
25
+ icon.style.setProperty('--ty', `${(dy / dist) * force}px`)
26
+ icon.classList.add('grid-card__icon--repelling')
27
+ } else {
28
+ icon.style.setProperty('--tx', '0px')
29
+ icon.style.setProperty('--ty', '0px')
30
+ icon.classList.remove('grid-card__icon--repelling')
31
+ }
32
+ })
33
+ }
34
+
35
+ mouseleave() {
36
+ this.iconTargets.forEach((icon) => {
37
+ icon.style.setProperty('--tx', '0px')
38
+ icon.style.setProperty('--ty', '0px')
39
+ icon.classList.remove('grid-card__icon--repelling')
40
+ })
41
+ }
42
+ }
@@ -78,7 +78,6 @@ export default class extends Controller {
78
78
  // Enable only if is on the same resource context
79
79
  // Avoiding to enable unrelated actions when selecting items on a has many table
80
80
  if (link.dataset.resourceName === this.resourceName) {
81
- link.classList.add(link.dataset.enabledClasses)
82
81
  link.classList.remove(link.dataset.disabledClasses)
83
82
  link.setAttribute('data-href', link.getAttribute('href'))
84
83
  link.dataset.disabled = false
@@ -91,7 +90,6 @@ export default class extends Controller {
91
90
  // Disable only if is on the same resource context
92
91
  // Avoiding to disable unrelated actions when selecting items on a has many table
93
92
  if (link.dataset.resourceName === this.resourceName) {
94
- link.classList.remove(link.dataset.enabledClasses)
95
93
  link.classList.add(link.dataset.disabledClasses)
96
94
  link.setAttribute('href', link.getAttribute('data-href'))
97
95
  link.dataset.disabled = true
@@ -2,11 +2,7 @@
2
2
  import { Controller } from '@hotwired/stimulus'
3
3
 
4
4
  export default class extends Controller {
5
- spinnerMarkup = `
6
- <div class="button-spinner">
7
- <div class="double-bounce1"></div>
8
- <div class="double-bounce2"></div>
9
- </div>`
5
+ spinnerMarkup = '<span class="loading-spinner" aria-hidden="true"></span>'
10
6
 
11
7
  static values = {
12
8
  confirmationMessage: String,
@@ -0,0 +1,131 @@
1
+ import { Controller } from '@hotwired/stimulus'
2
+
3
+ export default class extends Controller {
4
+ connect() {
5
+ this.observer = new MutationObserver(() => this.updateMapStyle())
6
+ this.observer.observe(document.documentElement, {
7
+ attributes: true,
8
+ attributeFilter: ['class'],
9
+ })
10
+
11
+ this.waitForMap().then(() => this.updateMapStyle())
12
+ }
13
+
14
+ disconnect() {
15
+ if (this.observer) {
16
+ this.observer.disconnect()
17
+ }
18
+ }
19
+
20
+ waitForMap() {
21
+ return new Promise((resolve) => {
22
+ const check = () => {
23
+ if (this.mapkickInstance?.map) {
24
+ resolve()
25
+ } else {
26
+ requestAnimationFrame(check)
27
+ }
28
+ }
29
+ check()
30
+ })
31
+ }
32
+
33
+ get mapkickInstance() {
34
+ const mapDiv = this.element.querySelector('[id^="map-"]') || this.element.querySelector('[id]')
35
+ if (!mapDiv?.id) return null
36
+
37
+ return window.Mapkick?.maps?.[mapDiv.id]
38
+ }
39
+
40
+ get isDark() {
41
+ return document.documentElement.classList.contains('dark')
42
+ }
43
+
44
+ updateMapStyle() {
45
+ const instance = this.mapkickInstance
46
+ if (!instance?.map) return
47
+
48
+ const map = instance.map
49
+ const style = map.getStyle()
50
+ if (!style) return
51
+
52
+ const targetStyle = this.isDark
53
+ ? 'mapbox://styles/mapbox/dark-v11'
54
+ : 'mapbox://styles/mapbox/light-v11'
55
+
56
+ // Detect current style from the sprite URL or stylesheet name
57
+ const styleName = style.name || style.sprite || ''
58
+ const currentIsDark = /dark/i.test(styleName)
59
+ if (this.isDark === currentIsDark) return
60
+
61
+ // Save custom sources and layers added by Mapkick before the style swap
62
+ const snapshot = this.captureMapkickState(map)
63
+
64
+ map.setStyle(targetStyle)
65
+
66
+ // Restore sources, layers, and marker images after the new style loads
67
+ map.once('style.load', () => {
68
+ this.restoreMapkickState(map, snapshot)
69
+ })
70
+ }
71
+
72
+ captureMapkickState(map) {
73
+ const style = map.getStyle()
74
+ const sources = {}
75
+ const layers = []
76
+ const images = []
77
+
78
+ // Capture Mapkick's custom sources (e.g. "objects", "trails", labels)
79
+ for (const [name, source] of Object.entries(style.sources)) {
80
+ // Skip Mapbox's built-in sources (composite, mapbox-)
81
+ if (name === 'composite' || name.startsWith('mapbox')) continue
82
+
83
+ sources[name] = {
84
+ type: source.type,
85
+ data: source.data,
86
+ }
87
+ }
88
+
89
+ // Capture layers that reference our custom sources
90
+ for (const layer of style.layers) {
91
+ if (layer.source && sources[layer.source]) {
92
+ layers.push(layer)
93
+ }
94
+ }
95
+
96
+ // Capture marker images (mapkick-{id}-15 pattern)
97
+ for (const id of Object.keys(map.style?.imageManager?.images || {})) {
98
+ if (id.startsWith('mapkick-')) {
99
+ const image = map.style.imageManager.images[id]
100
+ if (image) {
101
+ images.push({ id, data: image.data, pixelRatio: image.pixelRatio || 1 })
102
+ }
103
+ }
104
+ }
105
+
106
+ return { sources, layers, images }
107
+ }
108
+
109
+ restoreMapkickState(map, snapshot) {
110
+ // Re-add marker images
111
+ for (const img of snapshot.images) {
112
+ if (!map.hasImage(img.id)) {
113
+ map.addImage(img.id, img.data, { pixelRatio: img.pixelRatio })
114
+ }
115
+ }
116
+
117
+ // Re-add sources
118
+ for (const [name, config] of Object.entries(snapshot.sources)) {
119
+ if (!map.getSource(name)) {
120
+ map.addSource(name, config)
121
+ }
122
+ }
123
+
124
+ // Re-add layers in original order
125
+ for (const layer of snapshot.layers) {
126
+ if (!map.getLayer(layer.id)) {
127
+ map.addLayer(layer)
128
+ }
129
+ }
130
+ }
131
+ }
@@ -1,11 +1,12 @@
1
1
  import { Controller } from '@hotwired/stimulus'
2
- import { enter, leave } from 'el-transition'
3
2
 
4
3
  export default class extends Controller {
5
- static targets = ['svg', 'items', 'self']
4
+ static targets = ['svg', 'items', 'self', 'trigger']
6
5
 
7
6
  collapsed = true
8
7
 
8
+ transitionClass = 'css-animate-slide-down'
9
+
9
10
  get key() {
10
11
  return this.selfTarget.getAttribute('data-menu-key-param')
11
12
  }
@@ -49,27 +50,48 @@ export default class extends Controller {
49
50
 
50
51
  updateDom() {
51
52
  if (this.collapsed) {
52
- this.markCollapsed(true)
53
+ this.markCollapsed()
53
54
  } else {
54
- this.markExpanded(true)
55
+ this.markExpanded()
55
56
  }
56
57
  }
57
58
 
58
- markCollapsed(animate = false) {
59
+ markCollapsed() {
59
60
  this.svgTarget.classList.add('rotate-90')
60
- if (animate) {
61
- leave(this.itemsTarget)
62
- } else {
63
- this.itemsTarget.classList.add('hidden')
64
- }
61
+ if (this.hasTriggerTarget) this.triggerTarget.setAttribute('aria-expanded', 'false')
62
+ this.leave(this.itemsTarget)
65
63
  }
66
64
 
67
- markExpanded(animate = false) {
65
+ markExpanded() {
68
66
  this.svgTarget.classList.remove('rotate-90')
69
- if (animate) {
70
- enter(this.itemsTarget)
71
- } else {
72
- this.itemsTarget.classList.remove('hidden')
73
- }
67
+ if (this.hasTriggerTarget) this.triggerTarget.setAttribute('aria-expanded', 'true')
68
+ this.enter(this.itemsTarget)
69
+ }
70
+
71
+ async toggle(element) {
72
+ element.toggleAttribute('hidden')
73
+ await this.animateTransition(element)
74
+ }
75
+
76
+ async leave(element) {
77
+ element.setAttribute('hidden', true)
78
+ await this.animateTransition(element)
79
+ }
80
+
81
+ async enter(element) {
82
+ element.removeAttribute('hidden')
83
+ await this.animateTransition(element)
84
+ }
85
+
86
+ async animateTransition(element) {
87
+ element.classList.add(this.transitionClass)
88
+ await this.onTransitionsEnded(element)
89
+ element.classList.remove(this.transitionClass)
90
+ }
91
+
92
+ onTransitionsEnded(node) {
93
+ return Promise.allSettled(
94
+ node.getAnimations().map((animation) => animation.finished),
95
+ )
74
96
  }
75
97
  }
@@ -8,6 +8,22 @@ export default class extends Controller {
8
8
  closeModalOnBackdropClick: true,
9
9
  }
10
10
 
11
+ connect() {
12
+ document.body.classList.add('modal-open')
13
+ this.handleKeydown = this.handleKeydown.bind(this)
14
+ document.addEventListener('keydown', this.handleKeydown)
15
+ }
16
+
17
+ disconnect() {
18
+ document.removeEventListener('keydown', this.handleKeydown)
19
+ }
20
+
21
+ handleKeydown(event) {
22
+ if (event.key === 'Escape' && this.closeModalOnBackdropClickValue) {
23
+ this.closeModal()
24
+ }
25
+ }
26
+
11
27
  close(event) {
12
28
  if (event.target === this.backdropTarget && !this.closeModalOnBackdropClickValue) return
13
29
 
@@ -0,0 +1,83 @@
1
+ import { Controller } from '@hotwired/stimulus'
2
+
3
+ // Connects to data-controller="modal-size"
4
+ export default class extends Controller {
5
+ static targets = ['container']
6
+
7
+ static values = {
8
+ currentWidth: String,
9
+ currentHeight: String,
10
+ }
11
+
12
+ connect() {
13
+ this.modalElement = this.element
14
+ this.updateWidthClass(this.currentWidthValue)
15
+ this.updateHeightClass(this.currentHeightValue)
16
+ }
17
+
18
+ changeWidth(event) {
19
+ const newWidth = event.currentTarget.dataset.width
20
+ this.updateWidthClass(newWidth)
21
+ this.currentWidthValue = newWidth
22
+ }
23
+
24
+ changeHeight(event) {
25
+ const newHeight = event.currentTarget.dataset.height
26
+ this.updateHeightClass(newHeight)
27
+ this.currentHeightValue = newHeight
28
+ }
29
+
30
+ updateWidthClass(width) {
31
+ // Remove all modal width classes from the modal element
32
+ this.modalElement.classList.remove(
33
+ 'modal--width-sm',
34
+ 'modal--width-md',
35
+ 'modal--width-lg',
36
+ 'modal--width-xl',
37
+ 'modal--width-2xl',
38
+ 'modal--width-3xl',
39
+ 'modal--width-4xl',
40
+ 'modal--width-full',
41
+ 'modal--width-25',
42
+ 'modal--width-50',
43
+ 'modal--width-75',
44
+ 'modal--width-100',
45
+ )
46
+
47
+ // Remove all width classes from the container
48
+ this.containerTarget.classList.remove('w-sm', 'w-md', 'w-lg', 'w-xl', 'w-2xl', 'w-3xl', 'w-4xl', 'w-full')
49
+
50
+ // Add the new modal width class to the modal element
51
+ this.modalElement.classList.add(`modal--width-${width}`)
52
+
53
+ // Add the corresponding width class to the container
54
+ if (width === 'full') {
55
+ this.containerTarget.classList.add('w-full')
56
+ } else {
57
+ this.containerTarget.classList.add(`w-${width}`)
58
+ }
59
+ }
60
+
61
+ updateHeightClass(height) {
62
+ // Remove all modal height classes from the modal element
63
+ this.modalElement.classList.remove(
64
+ 'modal--height-auto',
65
+ 'modal--height-sm',
66
+ 'modal--height-md',
67
+ 'modal--height-lg',
68
+ 'modal--height-xl',
69
+ 'modal--height-2xl',
70
+ 'modal--height-3xl',
71
+ 'modal--height-4xl',
72
+ 'modal--height-full',
73
+ 'modal--height-25',
74
+ 'modal--height-50',
75
+ 'modal--height-75',
76
+ 'modal--height-100',
77
+ )
78
+
79
+ // Add the new modal height class to the modal element
80
+ // The CSS will handle applying the appropriate height to .modal__card
81
+ this.modalElement.classList.add(`modal--height-${height}`)
82
+ }
83
+ }
@@ -22,7 +22,7 @@ export default class extends NestedForm {
22
22
  }
23
23
 
24
24
  remove(event) {
25
- if (confirm(this.confirmMessageValue)) {
25
+ if (window.confirm(this.confirmMessageValue)) {
26
26
  super.remove(event)
27
27
  this.toggleAddButton()
28
28
  }
@@ -30,7 +30,7 @@ export default class extends NestedForm {
30
30
 
31
31
  toggleAddButton() {
32
32
  if (this.limitValue > 0) {
33
- this.addButtonTarget.classList.toggle('hidden', this.nestedRecordTargets.length >= this.limitValue)
33
+ this.addButtonTarget.classList.toggle('!hidden', this.nestedRecordTargets.length >= this.limitValue)
34
34
  }
35
35
  }
36
36
  }
@@ -0,0 +1,13 @@
1
+ import PasswordVisibility from '@stimulus-components/password-visibility'
2
+
3
+ export default class extends PasswordVisibility {
4
+ toggle(event) {
5
+ // Check if the input is disabled before allowing toggle
6
+ if (this.inputTarget.disabled) {
7
+ return
8
+ }
9
+
10
+ // Call the parent toggle method if input is not disabled
11
+ super.toggle(event)
12
+ }
13
+ }
@@ -7,12 +7,12 @@ export default class extends Controller {
7
7
  }
8
8
 
9
9
  connect() {
10
- const vm = this;
10
+ const vm = this
11
11
 
12
12
  this.tippyInstance = tippy(vm.context.element, {
13
13
  content: "loading...",
14
14
  allowHTML: true,
15
- theme: 'light',
15
+ theme: 'basic',
16
16
  maxWidth: 550,
17
17
  async onShow(instance) {
18
18
  const response = await fetch(vm.urlValue)
@@ -0,0 +1,123 @@
1
+ import { Controller } from '@hotwired/stimulus'
2
+ import { get } from '@rails/request.js'
3
+
4
+ export default class extends Controller {
5
+ static targets = ['input', 'overlay']
6
+
7
+ static values = {
8
+ debounce: { type: Number, default: 300 },
9
+ url: String,
10
+ }
11
+
12
+ connect() {
13
+ this.#clearSpinnerTimer()
14
+ this.#removeSpinner()
15
+ }
16
+
17
+ disconnect() {
18
+ this.#clearSpinnerTimer()
19
+ this.#removeSpinner()
20
+ }
21
+
22
+ search() {
23
+ this.debouncedSearch()
24
+ }
25
+
26
+ debouncedSearch = this.debounce(this.performSearch, this.debounceValue)
27
+
28
+ async performSearch() {
29
+ const query = this.inputTarget.value
30
+
31
+ const [pathName, queryString] = this.urlValue.split('?')
32
+ const newUrl = this.buildSearchUrl(pathName, queryString, query)
33
+
34
+ // Replace current URL without affecting browser history
35
+ if (!queryString || !queryString.includes('turbo_frame')) {
36
+ window.history.replaceState({}, '', newUrl)
37
+ }
38
+
39
+ try {
40
+ // Show a spinner if the request takes longer than 300ms (after debounce)
41
+ this.#startSpinnerTimer()
42
+
43
+ await get(newUrl, {
44
+ responseKind: 'turbo-stream',
45
+ headers: {
46
+ Accept: 'text/vnd.turbo-stream.html',
47
+ 'X-Search-Request': 'resource-search-controller',
48
+ },
49
+ })
50
+ } catch (error) {
51
+ // Silently fail; network errors are surfaced via Turbo stream failures
52
+ } finally {
53
+ this.#stopSpinner()
54
+ }
55
+ }
56
+
57
+ // Utility function to build search URL with query and pagination reset
58
+ buildSearchUrl(pathname, currentSearch, query) {
59
+ const searchParams = new URLSearchParams(currentSearch)
60
+
61
+ if (query) {
62
+ searchParams.set('q', query)
63
+ } else {
64
+ searchParams.delete('q')
65
+ }
66
+
67
+ searchParams.set('page', '1')
68
+
69
+ return `${pathname}?${searchParams.toString()}`
70
+ }
71
+
72
+ debounce(func, wait) {
73
+ let timeout
74
+
75
+ return function executedFunction(...args) {
76
+ const later = () => {
77
+ clearTimeout(timeout)
78
+ func.apply(this, args)
79
+ }
80
+ clearTimeout(timeout)
81
+ timeout = setTimeout(later, wait)
82
+ }
83
+ }
84
+
85
+ // Private
86
+
87
+ #spinnerTimer = null
88
+
89
+ #spinnerEl = null
90
+
91
+ #spinnerDelayMs = 500
92
+
93
+ #startSpinnerTimer() {
94
+ this.#clearSpinnerTimer()
95
+ this.#spinnerTimer = setTimeout(() => this.#showSpinner(), this.#spinnerDelayMs)
96
+ }
97
+
98
+ #clearSpinnerTimer() {
99
+ if (this.#spinnerTimer) {
100
+ clearTimeout(this.#spinnerTimer)
101
+ this.#spinnerTimer = null
102
+ }
103
+ }
104
+
105
+ #showSpinner() {
106
+ // Add a body class to signal loading (used by tests/possible styles)
107
+ document.body.classList.add('search-loading')
108
+
109
+ this.overlayTarget.classList.add('is-active')
110
+ this.#spinnerEl = this.overlayTarget
111
+ }
112
+
113
+ #removeSpinner() {
114
+ document.body.classList.remove('search-loading')
115
+ if (this.#spinnerEl) this.#spinnerEl.classList.remove('is-active')
116
+ this.#spinnerEl = null
117
+ }
118
+
119
+ #stopSpinner() {
120
+ this.#clearSpinnerTimer()
121
+ this.#removeSpinner()
122
+ }
123
+ }
@@ -1,5 +1,9 @@
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
  /* eslint-disable no-underscore-dangle */
2
- import * as Mousetrap from 'mousetrap'
3
7
  import { Controller } from '@hotwired/stimulus'
4
8
  import { Turbo } from '@hotwired/turbo-rails'
5
9
  import { autocomplete } from '@algolia/autocomplete-js'
@@ -9,9 +13,8 @@ import debouncePromise from '../helpers/debounce_promise'
9
13
 
10
14
  /**
11
15
  * The search controller is used in three places.
12
- * 1. Global search (on the top navbar) and can search through multiple resources.
13
- * 2. Resource search (on the Index page on top of the table panel) and will search one resource
14
- * 3. belongs_to field. This requires a bit more cleanup because the user will not navigate away from the page.
16
+ * 1. Resource search (on the Index page on top of the table panel) and will search one resource
17
+ * 2. belongs_to field. This requires a bit more cleanup because the user will not navigate away from the page.
15
18
  * It will replace the id and label in some fields on the page and also needs a "clear" button which clears the information so the user can submit the form without a value.
16
19
  */
17
20
  export default class extends Controller {
@@ -59,11 +62,8 @@ export default class extends Controller {
59
62
  return this.dataset.viaAssociation === 'has_many'
60
63
  }
61
64
 
62
- get isGlobalSearch() {
63
- return this.dataset.searchResource === 'global'
64
- }
65
-
66
65
  connect() {
66
+ console.log('search controller connected')
67
67
  const that = this
68
68
 
69
69
  this.buttonTarget.onclick = () => this.showSearchPanel()
@@ -74,16 +74,6 @@ export default class extends Controller {
74
74
  }
75
75
  })
76
76
 
77
- if (this.isGlobalSearch) {
78
- Mousetrap.bind(['command+k', 'ctrl+k'], (e) => {
79
- // Prevent browser from focusing the address bar
80
- e.preventDefault()
81
- e.stopPropagation()
82
- this.showSearchPanel()
83
- return false
84
- })
85
- }
86
-
87
77
  // This line fixes a bug where the search box would be duplicated on back navigation.
88
78
  this.autocompleteTarget.innerHTML = ''
89
79
 
@@ -162,7 +152,7 @@ export default class extends Controller {
162
152
  classes = 'rounded-full'
163
153
  break
164
154
  case 'rounded':
165
- classes = 'rounded'
155
+ classes = 'rounded-sm'
166
156
  break
167
157
  case 'square':
168
158
  classes = 'rounded-none'
@@ -173,7 +163,7 @@ export default class extends Controller {
173
163
  createElement('img', {
174
164
  src: item._avatar,
175
165
  alt: item._label,
176
- class: `flex-shrink-0 w-8 h-8 my-[2px] inline mr-2 ${classes}`,
166
+ class: `shrink-0 w-8 h-8 my-[2px] inline me-2 ${classes}`,
177
167
  }),
178
168
  )
179
169
  }
@@ -256,10 +246,6 @@ export default class extends Controller {
256
246
  'search',
257
247
  ]
258
248
 
259
- if (this.isGlobalSearch) {
260
- segments = ['avo_api', 'search']
261
- }
262
-
263
249
  return segments
264
250
  }
265
251
 
@@ -267,14 +253,9 @@ export default class extends Controller {
267
253
  let params = {
268
254
  ...Object.fromEntries(new URLSearchParams(window.location.search)),
269
255
  q: query,
270
- global: false,
271
256
  ...this.extraParamsValue,
272
257
  }
273
258
 
274
- if (this.isGlobalSearch) {
275
- params.global = true
276
- }
277
-
278
259
  if (this.isBelongsToSearch || this.isHasManySearch) {
279
260
  params = this.addAssociationParams(params)
280
261
  params = this.addReflectionParams(params)