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
@@ -1,42 +0,0 @@
1
- <div data-target="panel-header" class="flex flex-col w-full mb-4">
2
- <div class="flex justify-center sm:justify-start flex-col sm:flex-row w-full flex-1 has-cover-photo:mt-0">
3
- <%= render Avo::ProfilePhotoComponent.new profile_photo: @profile_photo %>
4
- <div class="flex flex-col flex-1 w-full">
5
- <% if display_breadcrumbs? %>
6
- <div class="breadcrumbs text-center sm:text-left mb-2">
7
- <%= helpers.render_avo_breadcrumbs(separator: helpers.svg("chevron-right", class: "inline-block h-3 stroke-current relative top-[-1px] ml-1")) if Avo.configuration.display_breadcrumbs %>
8
- </div>
9
- <% end %>
10
- <div class="flex-1 flex flex-col xl:flex-row justify-between gap-1 grow-0">
11
- <div class="overflow-hidden flex flex-col">
12
- <% if name_slot? %>
13
- <%= name_slot %>
14
- <% else %>
15
- <%= render Avo::PanelNameComponent.new name: @name do |panel_name_component| %>
16
- <% panel_name_component.with_body do %>
17
- <% if @external_link.present? %>
18
- <%= link_to @external_link, class: "text-gray-600 hover:text-gray-900 mt-1", title: helpers.t("avo.visit_record_on_external_path"), data: {tippy: :tooltip}, target: :_blank do %>
19
- <%= helpers.svg "heroicons/outline/arrow-top-right-on-square", class: "ml-2 text-2xl h-4" %>
20
- <% end %>
21
- <% end %>
22
- <% if @discreet_information.present? %>
23
- <%= render Avo::DiscreetInformationComponent.new(payload: @discreet_information) %>
24
- <% end %>
25
- <% end %>
26
- <% end %>
27
- <% end %>
28
- <% if @description.present? %>
29
- <div class="text-sm tracking-normal font-medium text-gray-600 text-center sm:text-left" data-target="description">
30
- <%== @description %>
31
- </div>
32
- <% end %>
33
- </div>
34
- <% if tools.present? %>
35
- <div class="flex-1 w-full flex flex-col sm:flex-row xl:justify-end sm:items-end gap-2 mt-4 xl:mt-0" data-target="panel-tools">
36
- <%= tools %>
37
- </div>
38
- <% end %>
39
- </div>
40
- </div>
41
- </div>
42
- </div>
@@ -1,31 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class Avo::PanelHeaderComponent < Avo::BaseComponent
4
- include Avo::ApplicationHelper
5
-
6
- renders_one :name_slot
7
- renders_one :tools
8
-
9
- prop :name
10
- prop :external_link
11
- prop :description
12
- prop :display_breadcrumbs, default: false
13
- prop :discreet_information
14
- prop :profile_photo
15
-
16
- private
17
-
18
- def display_breadcrumbs?
19
- @display_breadcrumbs && Avo.configuration.display_breadcrumbs
20
- end
21
-
22
- def description
23
- return @description if @description.present?
24
-
25
- ""
26
- end
27
-
28
- def render?
29
- @name.present? || description.present? || tools.present? || display_breadcrumbs?
30
- end
31
- end
@@ -1,6 +0,0 @@
1
- <%= image_tag helpers.main_app.url_for(@profile_photo.value), class: class_names(
2
- "relative rounded-full object-cover aspect-square border-4 border-application",
3
- "has-cover-photo:sm:ml-8 sm:mr-2",
4
- "self-center sm:self-start",
5
- "size-24 has-cover-photo:size-36 has-cover-photo:sm:size-48 has-cover-photo:-mt-12",
6
- ), data: {component: self.class.to_s.underscore} %>
@@ -1,9 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class Avo::ProfilePhotoComponent < Avo::BaseComponent
4
- prop :profile_photo
5
-
6
- def render?
7
- @profile_photo.present? && @profile_photo.visible_in_current_view?
8
- end
9
- end
@@ -1,21 +0,0 @@
1
- <% if @collapsable %>
2
- <div class="flex justify-between cursor-pointer px-4 pr-2 py-1 text-gray-500"
3
- data-action="click->menu#triggerCollapse"
4
- data-menu-key-param="<%= @key %>"
5
- >
6
- <div class="flex items-center text-sm uppercase font-semibold leading-none space-x-1">
7
- <span class="min-w-[20px]"><%= @icon %></span> <span><%= @label %></span>
8
- </div>
9
- <div class="<%= 'rotate-90' if @collapsed %>"
10
- data-menu-target="svg"
11
- >
12
- <%= helpers.svg 'heroicons/outline/chevron-down', class: 'h-5'%>
13
- </div>
14
- </div>
15
- <% else %>
16
- <div class="flex justify-between px-4 pr-2 py-1 text-gray-500">
17
- <div class="flex items-center text-sm uppercase font-semibold leading-none space-x-1">
18
- <span class="min-w-[20px]"><%= @icon %></span> <span><%= @label %></span>
19
- </div>
20
- </div>
21
- <% end %>
@@ -1,9 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class Avo::Sidebar::HeadingComponent < Avo::BaseComponent
4
- prop :label
5
- prop :icon
6
- prop :collapsable, default: false
7
- prop :collapsed, default: false
8
- prop :key
9
- end
@@ -1,20 +0,0 @@
1
- <div class="flex flex-wrap gap-2 p-2 <%= white_panel_classes %>" data-tabs-target="tabSwitcher">
2
- <% @group.visible_items.each do |tab| %>
3
- <%= a_link tab_path(tab),
4
- color: current_one?(tab) ? :primary : :gray,
5
- style: current_one?(tab) ? :outline : :text,
6
- size: :sm,
7
- class: current_one?(tab) ? "z-20 bg-primary-100" : "",
8
- title: tab.description,
9
- data: {
10
- tippy: tab.description.present? ? 'tooltip' : '',
11
- selected: current_one?(tab),
12
- action: 'click->tabs#changeTab',
13
- tabs_tab_name_param: tab.name,
14
- tabs_group_id_param: @group.to_param,
15
- tabs_resource_name_param: @resource.underscore_name,
16
- } do %>
17
- <%= tab.name %>
18
- <% end %>
19
- <% end %>
20
- </div>
@@ -1,45 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class Avo::TabSwitcherComponent < Avo::BaseComponent
4
- include Avo::UrlHelpers
5
- include Avo::ApplicationHelper
6
-
7
- delegate :white_panel_classes, to: :helpers
8
- delegate :group_param, to: :@group
9
-
10
- prop :resource
11
- prop :group
12
- prop :current_tab
13
- prop :active_tab_name, reader: :public
14
- prop :view
15
-
16
- #TOD: helper to record:
17
- def tab_path(tab)
18
- if is_edit?
19
- helpers.edit_resource_path(resource: @resource, record: @resource.record, keep_query_params: true, active_tab_name: tab.name, tab_turbo_frame: @group.turbo_frame_id)
20
- elsif is_new?
21
- helpers.new_resource_path(resource: @resource, keep_query_params: true, active_tab_name: tab.name, tab_turbo_frame: @group.turbo_frame_id)
22
- else
23
- helpers.resource_path(resource: @resource, record: @resource.record, keep_query_params: true, active_tab_name: tab.name, tab_turbo_frame: @group.turbo_frame_id)
24
- end
25
- end
26
-
27
- def is_edit?
28
- @view.in?(%w[edit update])
29
- end
30
-
31
- def is_new?
32
- @view.in?(%w[new create])
33
- end
34
-
35
- # We'll mark the tab as selected if it's the current one
36
- def current_one?(tab)
37
- tab.name == @active_tab_name
38
- end
39
-
40
- private
41
-
42
- def tab_param_missing?
43
- params[group_param].blank?
44
- end
45
- end
@@ -1,8 +0,0 @@
1
- <%= turbo_stream.remove("new_via_belongs_to") %>
2
-
3
- <turbo-stream action="update-belongs-to"
4
- data-relation-name="<%= params[:via_relation] %>"
5
- data-target-record-id="<%= @record.to_param %>"
6
- data-target-resource-label="<%= @resource.record_title %>"
7
- data-target-resource-class="<%= @record.class.name %>">
8
- </turbo-stream>
@@ -1,37 +0,0 @@
1
- <turbo-frame id="debug-report">
2
- <div class="flex gap-2">
3
- <%= form_with url: avo.avo_private_send_to_hq_path, data: {turbo_frame: :send_to_hq}, class: "w-full" do |f| %>
4
- <div class="space-y-8 divide-y divide-gray-200">
5
- <div>
6
- <div>
7
- <h3 class="text-lg font-medium leading-6 text-gray-900">Send in a bug report (pro feature)</h3>
8
- <p class="mt-1 text-sm text-gray-500">If you think there is something wrong with Avo and you'd like to report with some (anonymized) telemetry about the app, please fill in any relevant details and send it in.</p>
9
- <p class="mt-1 text-sm text-gray-500">Otherwise, please <a href="https://avo.cool/new-issue" target="_blank">create a GitHub issue</a> where everyone can contribute.</p>
10
- </div>
11
-
12
- <div class="sm:col-span-6 mt-4">
13
- <label for="about" class="block text-sm font-medium text-gray-700">Details</label>
14
- <div class="mt-1">
15
- <%= f.text_area :body, rows: 3, class: "block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm disabled:bg-gray-100", disabled: !Avo::Current.license.pro? %>
16
- </div>
17
- </div>
18
- <%= f.hidden_field :license_key, value: Avo::Services::DebugService.debug_report(request)[:license_response]["license_key"] %>
19
- <%= a_button icon: 'heroicons/outline/paper-airplane',
20
- color: :primary,
21
- style: :primary,
22
- class: "mt-4",
23
- disabled: !Avo::Current.license.pro?,
24
- type: :submit do %>
25
- Send to HQ
26
- <% end %>
27
- </div>
28
- </div>
29
- <% end %>
30
- </div>
31
- <div class="text-right">
32
- <%= turbo_frame_tag :send_to_hq %>
33
- </div>
34
- <div class="overflow-auto max-w-full">
35
-
36
- </div>
37
- </turbo-frame>
@@ -1,3 +0,0 @@
1
- <div class="breadcrumbs text-center sm:text-left mb-2">
2
- <%= render_avo_breadcrumbs(separator: svg("chevron-right", class: "inline-block h-3 stroke-current relative top-[-1px] mx-1")) %>
3
- </div>
@@ -1,16 +0,0 @@
1
- <div data-controller="search" class="resource-search flex items-center h-full w-full">
2
- <div class="w-full"
3
- data-search-target="autocomplete"
4
- data-search-resource="<%= resource %>"
5
- data-translation-keys='{"no_item_found": "<%= I18n.translate 'avo.no_item_found' %>", "placeholder": "<%= I18n.translate 'avo.search.placeholder' %>", "cancel_button": "<%= I18n.translate 'avo.search.cancel_button' %>"}'
6
- <% if via_reflection.present? %>
7
- data-via-association="<%= via_reflection[:association] %>"
8
- data-via-association-id="<%= via_reflection[:association_id] %>"
9
- data-via-reflection-class="<%= via_reflection[:class] %>"
10
- data-via-reflection-id="<%= via_reflection[:id] %>"
11
- data-via-reflection-view="<%= via_reflection[:view] %>"
12
- <% end %>
13
- >
14
- </div>
15
- <div class="hidden relative inline-flex text-gray-400 text-sm border border-gray-300 rounded cursor-pointer" data-search-target="button"></div>
16
- </div>
@@ -1,6 +0,0 @@
1
- module Avo
2
- module Licensing
3
- class CommunityLicense < License
4
- end
5
- end
6
- end
@@ -1,202 +0,0 @@
1
- require "active_support/core_ext/integer/time"
2
-
3
- module Avo
4
- module Licensing
5
- class HQ
6
- attr_accessor :current_request
7
- attr_accessor :cache_store
8
-
9
- ENDPOINT = "https://v3.avohq.io/api/v3/licenses/check".freeze unless const_defined?(:ENDPOINT)
10
- REQUEST_TIMEOUT = 5 unless const_defined?(:REQUEST_TIMEOUT) # seconds
11
- CACHE_TIME = 6.hours.to_i unless const_defined?(:CACHE_TIME) # seconds
12
- RESPONSE_STRUCT = Struct.new(:code, :body) unless const_defined?(:RESPONSE_STRUCT)
13
-
14
- class << self
15
- def cache_key
16
- "avo.hq-#{digested_attributes}-#{Avo::VERSION.parameterize}.response"
17
- end
18
-
19
- private
20
-
21
- # Digest the attributes to a few character string. Ex: "j8q2"
22
- def digested_attributes
23
- # This list of attributes will make sure that the cached response is invalidated when any of them changes.
24
- attributes_to_digest = [
25
- Avo.configuration.license_key,
26
- Avo.configuration.license
27
- ].join("-")
28
-
29
- Digest::MD5.hexdigest(attributes_to_digest).yield_self { |h| "#{h[0, 2]}#{h[-2, 2]}" }
30
- end
31
- end
32
-
33
- def initialize(current_request = nil)
34
- @current_request = current_request
35
- @cache_store = Avo.cache_store
36
- end
37
-
38
- def response
39
- expire_cache_if_overdue
40
-
41
- # ------------------------------------------------------------------
42
- # You could set this to true to become a pro user for free.
43
- # I'd rather you didn't. Avo takes time & love to build,
44
- # and I can't do that if it doesn't pay my bills!
45
- #
46
- # If you want Pro, help pay for its development.
47
- # Can't afford it? Get in touch: adrian@avohq.io
48
- # ------------------------------------------------------------------
49
- make_request
50
- end
51
-
52
- # Some cache stores don't auto-expire their keys and payloads so we need to do it for them
53
- def expire_cache_if_overdue
54
- return unless cached_response.present? || cached_response&.fetch(:fetched_at, nil).present?
55
-
56
- parsed_time = Time.parse(cached_response["fetched_at"].to_s)
57
- cache_should_expire = parsed_time < Time.now - CACHE_TIME
58
-
59
- clear_response if cache_should_expire
60
- end
61
-
62
- def fresh_response
63
- clear_response
64
-
65
- make_request
66
- end
67
-
68
- def clear_response
69
- cache_store.delete self.class.cache_key
70
- end
71
-
72
- def payload
73
- result = {
74
- license: Avo.configuration.license,
75
- license_key: Avo.configuration.license_key,
76
- avo_version: Avo::VERSION,
77
- rails_version: Rails::VERSION::STRING,
78
- ruby_version: RUBY_VERSION,
79
- environment: Rails.env,
80
- ip: current_request&.ip,
81
- host: current_request&.host,
82
- port: current_request&.port,
83
- app_name: app_name
84
- }
85
-
86
- begin
87
- metadata = Avo::Services::DebugService.avo_metadata
88
- rescue => error
89
- metadata = {
90
- error_message: error.message,
91
- error: "Failed to generate the Avo metadata"
92
- }
93
- end
94
-
95
- result[:avo_metadata] = metadata
96
-
97
- result
98
- end
99
-
100
- def cached_response
101
- cache_store.read self.class.cache_key
102
- end
103
-
104
- private
105
-
106
- def make_request
107
- return cached_response if has_cached_response
108
-
109
- begin
110
- perform_and_cache_request
111
- rescue Errno::EHOSTUNREACH => exception
112
- cache_and_return_error "HTTP host not reachable error.", exception.message
113
- rescue Errno::ECONNRESET => exception
114
- cache_and_return_error "HTTP connection reset error.", exception.message
115
- rescue Errno::ECONNREFUSED => exception
116
- cache_and_return_error "HTTP connection refused error.", exception.message
117
- rescue OpenSSL::SSL::SSLError => exception
118
- cache_and_return_error "OpenSSL error.", exception.message
119
- rescue Net::OpenTimeout => exception
120
- cache_and_return_error "Request timeout.", exception.message
121
- rescue Net::ReadTimeout => exception
122
- cache_and_return_error "Request timeout.", exception.message
123
- rescue SocketError => exception
124
- cache_and_return_error "Connection error.", exception.message
125
- rescue => exception
126
- cache_and_return_error "HQ call error.", exception.message
127
- end
128
- end
129
-
130
- def perform_and_cache_request
131
- hq_response = perform_request
132
-
133
- case hq_response.code.to_i
134
- when 500
135
- cache_and_return_error "Avo HQ Internal server error.", hq_response.body
136
- when 200
137
- cache_response response: JSON.parse(hq_response.body)
138
- else
139
- cache_and_return_error "Invalid response.", "code: #{hq_response.code}, body: #{hq_response.body}"
140
- end
141
- end
142
-
143
- def cache_response(response: nil, time: CACHE_TIME)
144
- response = normalize_response response
145
-
146
- response.merge!(
147
- expiry: time,
148
- fetched_at: Time.now,
149
- **payload
150
- ).stringify_keys!
151
-
152
- cache_store.write(self.class.cache_key, response, expires_in: time)
153
-
154
- response
155
- end
156
-
157
- def normalize_response(response)
158
- if response.is_a? Hash
159
- response
160
- else
161
- {
162
- normalized_response: JSON.stringify(response)
163
- }
164
- end
165
- response.merge({})
166
- rescue
167
- {
168
- normalized_response: "rescued"
169
- }
170
- end
171
-
172
- def perform_request
173
- Avo.logger.debug "Performing request to avohq.io API to check license availability." if Rails.env.development?
174
-
175
- if Rails.env.test?
176
- RESPONSE_STRUCT.new(200, "{\"id\":\"pro\",\"valid\":true}")
177
- else
178
- Avo::Licensing::Request.post ENDPOINT, body: payload.to_json, timeout: REQUEST_TIMEOUT
179
- end
180
- end
181
-
182
- def app_name
183
- Rails.application.class.to_s.split("::").first
184
- rescue
185
- nil
186
- end
187
-
188
- def cache_and_return_error(error, exception_message = "")
189
- cache_response response: {
190
- id: Avo.configuration.license,
191
- valid: true,
192
- error: error,
193
- exception_message: exception_message
194
- }.stringify_keys, time: 5.minutes.to_i
195
- end
196
-
197
- def has_cached_response
198
- cache_store.exist? self.class.cache_key
199
- end
200
- end
201
- end
202
- end
@@ -1,76 +0,0 @@
1
- module Avo
2
- module Licensing
3
- class License
4
- attr_accessor :id
5
- attr_accessor :response
6
- attr_accessor :valid
7
- attr_accessor :payload
8
-
9
- def initialize(response = {})
10
- @response = response
11
- @id = response["id"]
12
- @valid = response["valid"]
13
- @payload = response["payload"]
14
- end
15
-
16
- def valid?
17
- valid
18
- end
19
-
20
- def invalid?
21
- !valid?
22
- end
23
-
24
- def pro?
25
- id == "pro"
26
- end
27
-
28
- def advanced?
29
- id == "advanced"
30
- end
31
-
32
- def error
33
- @response["error"]
34
- end
35
-
36
- def properties
37
- @response.slice("valid", "id", "error").symbolize_keys
38
- end
39
-
40
- def abilities
41
- []
42
- end
43
-
44
- def can(ability)
45
- abilities.include? ability
46
- end
47
-
48
- def cant(ability)
49
- !can ability
50
- end
51
-
52
- alias_method :has, :can
53
- alias_method :lacks, :cant
54
-
55
- # Returns if has ability and if is a valid license or app is in development.
56
- def has_with_trial(ability)
57
- return can(ability) && valid? if Rails.env.production?
58
-
59
- true
60
- end
61
-
62
- # Returns if lacks ability and if is a valid license or app is in development.
63
- def lacks_with_trial(ability)
64
- !has_with_trial ability
65
- end
66
-
67
- def name
68
- if id.present?
69
- id.humanize
70
- else
71
- self.class.to_s.split("::").last.underscore.humanize.gsub " license", ""
72
- end
73
- end
74
- end
75
- end
76
- end
@@ -1,24 +0,0 @@
1
- module Avo
2
- module Licensing
3
- class LicenseManager
4
- def initialize(hq_response)
5
- @hq_response = hq_response
6
- end
7
-
8
- def license
9
- case @hq_response["id"]
10
- when "community"
11
- CommunityLicense.new @hq_response
12
- when "pro", "advanced"
13
- ProLicense.new @hq_response
14
- else
15
- NilLicense.new @hq_response
16
- end
17
- end
18
-
19
- def self.refresh_license(request)
20
- new(Licensing::HQ.new(request).fresh_response).license
21
- end
22
- end
23
- end
24
- end
@@ -1,14 +0,0 @@
1
- module Avo
2
- module Licensing
3
- class NilLicense < License
4
- def initialize(response = nil)
5
- response ||= {
6
- id: "community",
7
- valid: true
8
- }
9
-
10
- super(response)
11
- end
12
- end
13
- end
14
- end
@@ -1,20 +0,0 @@
1
- module Avo
2
- module Licensing
3
- class ProLicense < License
4
- def abilities
5
- [
6
- :authorization,
7
- :global_search,
8
- :enhanced_search_results,
9
- :searchable_associations,
10
- :resource_ordering,
11
- :dashboards,
12
- :menu_editor,
13
- :customizable_controls,
14
- :resource_sidebar,
15
- :advanced_fields
16
- ]
17
- end
18
- end
19
- end
20
- end
@@ -1,20 +0,0 @@
1
- require "net/http"
2
-
3
- module Avo
4
- module Licensing
5
- class Request
6
- class << self
7
- def post(endpoint, body:, timeout:)
8
- uri = URI.parse(endpoint)
9
- http = Net::HTTP.new(uri.host, uri.port)
10
- http.use_ssl = (uri.scheme == "https")
11
- http.read_timeout = timeout
12
- http.open_timeout = timeout
13
- request = Net::HTTP::Post.new(uri.request_uri, {"Content-Type" => "application/json"})
14
- request.body = body
15
- http.request(request)
16
- end
17
- end
18
- end
19
- end
20
- end
@@ -1,7 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Avo
4
- class ProfilePhoto < PhotoObject
5
- def key = :profile_photo
6
- end
7
- end