avo 2.43.0 → 3.0.2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of avo might be problematic. Click here for more details.

Files changed (414) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +30 -26
  3. data/Gemfile.lock +235 -161
  4. data/README.md +19 -27
  5. data/Rakefile +2 -0
  6. data/app/assets/stylesheets/avo.base.css +1 -1
  7. data/app/assets/svgs/font.svg +1 -0
  8. data/app/assets/svgs/triangle-up.svg +1 -0
  9. data/app/components/avo/actions_component.html.erb +19 -5
  10. data/app/components/avo/actions_component.rb +39 -19
  11. data/app/components/avo/asset_manager/javascript_component.html.erb +3 -0
  12. data/app/components/avo/asset_manager/javascript_component.rb +13 -0
  13. data/app/components/avo/asset_manager/stylesheet_component.html.erb +3 -0
  14. data/app/components/avo/asset_manager/stylesheet_component.rb +13 -0
  15. data/app/components/avo/base_component.rb +15 -12
  16. data/app/components/avo/button_component.rb +20 -3
  17. data/app/components/avo/empty_state_component.rb +1 -1
  18. data/app/components/avo/field_wrapper_component.html.erb +1 -1
  19. data/app/components/avo/field_wrapper_component.rb +9 -15
  20. data/app/components/avo/fields/area_field/edit_component.html.erb +2 -2
  21. data/app/components/avo/fields/belongs_to_field/edit_component.html.erb +75 -79
  22. data/app/components/avo/fields/belongs_to_field/edit_component.rb +7 -7
  23. data/app/components/avo/fields/belongs_to_field/index_component.html.erb +1 -1
  24. data/app/components/avo/fields/belongs_to_field/show_component.rb +2 -2
  25. data/app/components/avo/fields/boolean_field/edit_component.html.erb +1 -1
  26. data/app/components/avo/fields/boolean_field/index_component.html.erb +1 -1
  27. data/app/components/avo/fields/boolean_group_field/edit_component.html.erb +3 -3
  28. data/app/components/avo/fields/common/badge_viewer_component.rb +1 -1
  29. data/app/components/avo/fields/common/boolean_check_component.html.erb +1 -12
  30. data/app/components/avo/fields/common/boolean_check_component.rb +2 -1
  31. data/app/components/avo/fields/common/boolean_group_component.html.erb +2 -2
  32. data/app/components/avo/fields/common/files/view_type/grid_item_component.rb +2 -2
  33. data/app/components/avo/fields/common/gravatar_viewer_component.html.erb +1 -1
  34. data/app/components/avo/fields/common/gravatar_viewer_component.rb +2 -2
  35. data/app/components/avo/fields/common/heading_component.html.erb +3 -8
  36. data/app/components/avo/fields/common/heading_component.rb +1 -3
  37. data/app/components/avo/fields/common/key_value_component.html.erb +2 -2
  38. data/app/components/avo/fields/common/key_value_component.rb +2 -2
  39. data/app/components/avo/fields/common/progress_bar_component.rb +3 -9
  40. data/app/components/avo/fields/common/status_viewer_component.html.erb +3 -0
  41. data/app/components/avo/fields/edit_component.rb +2 -2
  42. data/app/components/avo/fields/external_image_field/index_component.html.erb +1 -1
  43. data/app/components/avo/fields/file_field/index_component.html.erb +2 -2
  44. data/app/components/avo/fields/gravatar_field/index_component.html.erb +1 -1
  45. data/app/components/avo/fields/has_one_field/index_component.html.erb +1 -1
  46. data/app/components/avo/fields/has_one_field/show_component.html.erb +3 -2
  47. data/app/components/avo/fields/has_one_field/show_component.rb +2 -2
  48. data/app/components/avo/fields/heading_field/edit_component.html.erb +1 -1
  49. data/app/components/avo/fields/heading_field/show_component.html.erb +1 -1
  50. data/app/components/avo/fields/id_field/index_component.html.erb +1 -1
  51. data/app/components/avo/fields/index_component.rb +6 -6
  52. data/app/components/avo/fields/location_field/edit_component.html.erb +12 -10
  53. data/app/components/avo/fields/preview_field/index_component.html.erb +10 -0
  54. data/app/components/avo/fields/preview_field/index_component.rb +4 -0
  55. data/app/components/avo/fields/select_field/edit_component.html.erb +1 -1
  56. data/app/components/avo/fields/show_component.rb +5 -2
  57. data/app/components/avo/fields/text_field/index_component.html.erb +1 -1
  58. data/app/components/avo/fields/trix_field/edit_component.html.erb +2 -2
  59. data/app/components/avo/fields/trix_field/edit_component.rb +1 -1
  60. data/app/components/avo/fields/trix_field/show_component.html.erb +1 -1
  61. data/app/components/avo/filters_component.html.erb +9 -3
  62. data/app/components/avo/filters_component.rb +4 -4
  63. data/app/components/avo/index/field_wrapper_component.rb +1 -13
  64. data/app/components/avo/index/grid_item_component.html.erb +13 -36
  65. data/app/components/avo/index/grid_item_component.rb +43 -16
  66. data/app/components/avo/index/resource_controls_component.html.erb +3 -81
  67. data/app/components/avo/index/resource_controls_component.rb +125 -18
  68. data/app/components/avo/index/resource_grid_component.html.erb +5 -3
  69. data/app/components/avo/index/resource_grid_component.rb +5 -2
  70. data/app/components/avo/index/resource_map_component.html.erb +1 -1
  71. data/app/components/avo/index/resource_map_component.rb +3 -3
  72. data/app/components/avo/index/resource_table_component.html.erb +5 -4
  73. data/app/components/avo/index/resource_table_component.rb +24 -7
  74. data/app/components/avo/index/table_row_component.html.erb +9 -5
  75. data/app/components/avo/index/table_row_component.rb +3 -2
  76. data/app/components/avo/items/panel_component.html.erb +25 -0
  77. data/app/components/avo/items/panel_component.rb +43 -0
  78. data/app/components/avo/items/switcher_component.html.erb +17 -0
  79. data/app/components/avo/items/switcher_component.rb +79 -0
  80. data/app/components/avo/items/visible_items_component.html.erb +10 -0
  81. data/app/components/avo/items/visible_items_component.rb +11 -0
  82. data/app/components/avo/modal_component.html.erb +3 -4
  83. data/app/components/avo/paginator_component.html.erb +29 -40
  84. data/app/components/avo/paginator_component.rb +23 -5
  85. data/app/components/avo/panel_component.html.erb +7 -5
  86. data/app/components/avo/referrer_params_component.html.erb +1 -1
  87. data/app/components/avo/resource_component.rb +205 -26
  88. data/app/components/avo/resource_sidebar_component.html.erb +15 -18
  89. data/app/components/avo/resource_sidebar_component.rb +5 -3
  90. data/app/components/avo/sidebar/link_component.rb +1 -1
  91. data/app/components/avo/sidebar_component.html.erb +10 -3
  92. data/app/components/avo/sidebar_component.rb +5 -3
  93. data/app/components/avo/sidebar_profile_component.html.erb +18 -12
  94. data/app/components/avo/tab_group_component.html.erb +14 -8
  95. data/app/components/avo/tab_group_component.rb +1 -6
  96. data/app/components/avo/tab_switcher_component.html.erb +17 -40
  97. data/app/components/avo/tab_switcher_component.rb +6 -41
  98. data/app/components/avo/views/resource_edit_component.html.erb +23 -84
  99. data/app/components/avo/views/resource_edit_component.rb +20 -19
  100. data/app/components/avo/views/resource_index_component.html.erb +42 -47
  101. data/app/components/avo/views/resource_index_component.rb +76 -13
  102. data/app/components/avo/views/resource_show_component.html.erb +16 -177
  103. data/app/components/avo/views/resource_show_component.rb +16 -10
  104. data/app/controllers/avo/actions_controller.rb +37 -41
  105. data/app/controllers/avo/application_controller.rb +119 -181
  106. data/app/controllers/avo/associations_controller.rb +34 -43
  107. data/app/controllers/avo/attachments_controller.rb +4 -4
  108. data/app/controllers/avo/base_controller.rb +145 -98
  109. data/app/controllers/avo/debug_controller.rb +17 -5
  110. data/app/controllers/avo/home_controller.rb +1 -1
  111. data/app/controllers/avo/search_controller.rb +56 -50
  112. data/app/controllers/concerns/avo/initializes_avo.rb +22 -0
  113. data/app/helpers/avo/application_helper.rb +18 -8
  114. data/app/helpers/avo/resources_helper.rb +1 -1
  115. data/app/helpers/avo/url_helpers.rb +28 -12
  116. data/app/javascript/avo.base.js +1 -0
  117. data/app/javascript/js/application.js +3 -0
  118. data/app/javascript/js/controllers/action_controller.js +3 -1
  119. data/app/javascript/js/controllers/actions_overflow_controller.js +62 -0
  120. data/app/javascript/js/controllers/fields/reload_belongs_to_field_controller.js +7 -7
  121. data/app/javascript/js/controllers/filter_controller.js +1 -1
  122. data/app/javascript/js/controllers/input_autofocus_controller.js +12 -0
  123. data/app/javascript/js/controllers/preview_controller.js +24 -0
  124. data/app/javascript/js/controllers/search_controller.js +4 -2
  125. data/app/javascript/js/controllers/self_destroy_controller.js +7 -0
  126. data/app/javascript/js/controllers/toggle_controller.js +48 -0
  127. data/app/javascript/js/controllers.js +11 -5
  128. data/app/javascript/js/custom-stream-actions.js +15 -0
  129. data/app/views/avo/actions/show.html.erb +10 -7
  130. data/app/views/avo/associations/new.html.erb +2 -2
  131. data/app/views/avo/base/_new_via_belongs_to.html.erb +1 -1
  132. data/app/views/avo/base/close_modal_and_reload_field.turbo_stream.erb +3 -3
  133. data/app/views/avo/base/create_fail_action.turbo_stream.erb +2 -2
  134. data/app/views/avo/base/edit.html.erb +1 -1
  135. data/app/views/avo/base/index.html.erb +4 -3
  136. data/app/views/avo/base/new.html.erb +2 -1
  137. data/app/views/avo/base/preview.html.erb +19 -0
  138. data/app/views/avo/base/show.html.erb +2 -2
  139. data/app/views/avo/debug/_valid_indicator.html.erb +9 -0
  140. data/app/views/avo/debug/report.html.erb +32 -17
  141. data/app/views/avo/debug/{index.html.erb → status.html.erb} +31 -14
  142. data/app/views/avo/partials/_custom_tools_alert.html.erb +2 -2
  143. data/app/views/avo/partials/_flash_alerts.turbo_stream.erb +1 -1
  144. data/app/views/avo/partials/_footer.html.erb +1 -1
  145. data/app/views/avo/partials/_javascript.html.erb +5 -0
  146. data/app/views/avo/partials/_logo.html.erb +1 -1
  147. data/app/views/avo/partials/_navbar.html.erb +3 -5
  148. data/app/views/avo/partials/_resource_search.html.erb +1 -0
  149. data/app/views/avo/partials/_table_header.html.erb +5 -11
  150. data/app/views/layouts/avo/application.html.erb +5 -4
  151. data/avo.gemspec +11 -8
  152. data/bin/dev +3 -1
  153. data/bin/prod +0 -0
  154. data/config/i18n-tasks.yml +1 -1
  155. data/config/initializers/pagy.rb +2 -0
  156. data/config/master.key +1 -0
  157. data/config/routes.rb +7 -10
  158. data/db/factories.rb +6 -0
  159. data/lib/avo/asset_manager.rb +30 -0
  160. data/lib/avo/base_action.rb +84 -82
  161. data/lib/avo/base_resource.rb +286 -225
  162. data/lib/avo/base_resource_tool.rb +9 -16
  163. data/lib/avo/concerns/borrow_items_holder.rb +35 -0
  164. data/lib/avo/concerns/breadcrumbs.rb +2 -2
  165. data/lib/avo/concerns/{can_replace_fields.rb → can_replace_items.rb} +5 -9
  166. data/lib/avo/concerns/filters_session_handler.rb +7 -5
  167. data/lib/avo/concerns/has_controls.rb +37 -0
  168. data/lib/avo/concerns/has_description.rb +23 -0
  169. data/lib/avo/concerns/has_helpers.rb +18 -0
  170. data/lib/avo/concerns/has_item_type.rb +42 -0
  171. data/lib/avo/concerns/has_items.rb +339 -0
  172. data/lib/avo/concerns/hydration.rb +17 -0
  173. data/lib/avo/concerns/is_resource_item.rb +16 -36
  174. data/lib/avo/concerns/is_visible.rb +15 -0
  175. data/lib/avo/concerns/model_class_constantized.rb +0 -2
  176. data/lib/avo/concerns/pagination.rb +53 -0
  177. data/lib/avo/concerns/visible_in_different_views.rb +132 -0
  178. data/lib/avo/concerns/visible_items.rb +7 -38
  179. data/lib/avo/configuration/branding.rb +0 -12
  180. data/lib/avo/configuration.rb +28 -11
  181. data/lib/avo/current.rb +39 -0
  182. data/lib/avo/dsl/field_parser.rb +3 -3
  183. data/lib/avo/dynamic_router.rb +18 -3
  184. data/lib/avo/engine.rb +35 -30
  185. data/lib/avo/error_manager.rb +25 -0
  186. data/lib/avo/execution_context.rb +14 -15
  187. data/lib/avo/fields/base_field.rb +84 -115
  188. data/lib/avo/fields/belongs_to_field.rb +19 -23
  189. data/lib/avo/fields/concerns/file_authorization.rb +2 -2
  190. data/lib/avo/fields/concerns/handles_field_args.rb +49 -0
  191. data/lib/avo/fields/concerns/has_default.rb +1 -5
  192. data/lib/avo/fields/concerns/has_field_name.rb +22 -0
  193. data/lib/avo/fields/concerns/has_html_attributes.rb +112 -0
  194. data/lib/avo/fields/concerns/is_disabled.rb +1 -5
  195. data/lib/avo/fields/concerns/is_readonly.rb +1 -5
  196. data/lib/avo/fields/concerns/is_required.rb +5 -7
  197. data/lib/avo/fields/concerns/is_searchable.rb +15 -0
  198. data/lib/avo/fields/concerns/use_resource.rb +5 -1
  199. data/lib/avo/fields/concerns/use_view_components.rb +45 -0
  200. data/lib/avo/fields/country_field.rb +4 -0
  201. data/lib/avo/fields/date_time_field.rb +1 -5
  202. data/lib/avo/fields/external_image_field.rb +2 -2
  203. data/lib/avo/fields/field_manager.rb +55 -0
  204. data/lib/avo/fields/file_field.rb +2 -2
  205. data/lib/avo/fields/gravatar_field.rb +2 -2
  206. data/lib/avo/fields/has_and_belongs_to_many_field.rb +1 -2
  207. data/lib/avo/fields/has_base_field.rb +21 -17
  208. data/lib/avo/fields/has_many_field.rb +5 -2
  209. data/lib/avo/fields/has_one_field.rb +8 -12
  210. data/lib/avo/fields/heading_field.rb +9 -14
  211. data/lib/avo/fields/hidden_field.rb +1 -1
  212. data/lib/avo/fields/id_field.rb +3 -3
  213. data/lib/avo/fields/location_field.rb +10 -10
  214. data/lib/avo/fields/password_field.rb +1 -1
  215. data/lib/avo/fields/preview_field.rb +14 -0
  216. data/lib/avo/fields/select_field.rb +12 -8
  217. data/lib/avo/fields/status_field.rb +7 -1
  218. data/lib/avo/fields/text_field.rb +2 -2
  219. data/lib/avo/filters/base_filter.rb +9 -4
  220. data/lib/avo/html/builder.rb +8 -8
  221. data/lib/avo/item_grapher.rb +78 -0
  222. data/lib/avo/licensing/h_q.rb +11 -73
  223. data/lib/avo/licensing/license.rb +5 -1
  224. data/lib/avo/licensing/license_manager.rb +1 -1
  225. data/lib/avo/licensing/pro_license.rb +1 -7
  226. data/lib/avo/loaders/fields_loader.rb +7 -1
  227. data/lib/avo/plugin.rb +36 -0
  228. data/lib/avo/plugin_manager.rb +56 -0
  229. data/lib/avo/prefixed_test_helpers.rb +20 -0
  230. data/lib/avo/reloader.rb +3 -0
  231. data/lib/avo/resources/controls/actions_list.rb +7 -12
  232. data/lib/avo/resources/controls/attach_button.rb +15 -0
  233. data/lib/avo/resources/controls/back_button.rb +1 -1
  234. data/lib/avo/resources/controls/base_control.rb +15 -49
  235. data/lib/avo/resources/controls/create_button.rb +15 -0
  236. data/lib/avo/resources/controls/delete_button.rb +5 -1
  237. data/lib/avo/resources/controls/detach_button.rb +4 -1
  238. data/lib/avo/resources/controls/edit_button.rb +4 -1
  239. data/lib/avo/resources/controls/order_controls.rb +8 -0
  240. data/lib/avo/resources/controls/save_button.rb +13 -0
  241. data/lib/avo/resources/controls/show_button.rb +15 -0
  242. data/lib/avo/resources/items/holder.rb +96 -0
  243. data/lib/avo/resources/items/item_group.rb +44 -0
  244. data/lib/avo/resources/items/main_panel.rb +12 -0
  245. data/lib/avo/resources/items/panel.rb +2 -0
  246. data/lib/avo/resources/items/row.rb +42 -0
  247. data/lib/avo/resources/items/sidebar.rb +46 -0
  248. data/lib/avo/resources/items/tab.rb +54 -0
  249. data/lib/avo/resources/items/tab_group.rb +62 -0
  250. data/lib/avo/resources/resource_manager.rb +179 -0
  251. data/lib/avo/services/authorization_service.rb +11 -110
  252. data/lib/avo/services/debug_service.rb +93 -0
  253. data/lib/avo/services/encryption_service.rb +8 -12
  254. data/lib/avo/services/telemetry_service.rb +85 -0
  255. data/lib/avo/test_helpers.rb +362 -0
  256. data/lib/avo/tools/tool_manager.rb +30 -0
  257. data/lib/avo/version.rb +1 -1
  258. data/lib/avo/view_inquirer.rb +36 -0
  259. data/lib/avo.rb +109 -24
  260. data/lib/generators/avo/action_generator.rb +8 -8
  261. data/lib/generators/avo/card_generator.rb +27 -0
  262. data/lib/generators/avo/concerns/parent_controller.rb +20 -0
  263. data/lib/generators/avo/controller_generator.rb +3 -0
  264. data/lib/generators/avo/eject_generator.rb +180 -15
  265. data/lib/generators/avo/field_generator.rb +49 -2
  266. data/lib/generators/avo/filter_generator.rb +8 -8
  267. data/lib/generators/avo/js/install_generator.rb +2 -2
  268. data/lib/generators/avo/resource_generator.rb +12 -9
  269. data/lib/generators/avo/scope_generator.rb +15 -0
  270. data/lib/generators/avo/tailwindcss/install_generator.rb +70 -26
  271. data/lib/generators/avo/templates/action.tt +8 -6
  272. data/lib/generators/avo/templates/cards/chartkick_card.tt +1 -1
  273. data/lib/generators/avo/templates/cards/chartkick_card_sample.tt +1 -1
  274. data/lib/generators/avo/templates/cards/metric_card.tt +1 -1
  275. data/lib/generators/avo/templates/cards/metric_card_sample.tt +1 -1
  276. data/lib/generators/avo/templates/cards/partial_card.tt +1 -1
  277. data/lib/generators/avo/templates/cards/partial_card_sample.tt +1 -1
  278. data/lib/generators/avo/templates/dashboards/dashboard.tt +5 -3
  279. data/lib/generators/avo/templates/field/%singular_name%_field.rb.tt +1 -1
  280. data/lib/generators/avo/templates/filters/boolean_filter.tt +1 -1
  281. data/lib/generators/avo/templates/filters/multiple_select_filter.tt +1 -1
  282. data/lib/generators/avo/templates/filters/select_filter.tt +1 -1
  283. data/lib/generators/avo/templates/filters/text_filter.tt +1 -1
  284. data/lib/generators/avo/templates/initializer/avo.tt +7 -3
  285. data/lib/generators/avo/templates/locales/avo.ar.yml +7 -6
  286. data/lib/generators/avo/templates/locales/avo.en.yml +6 -3
  287. data/lib/generators/avo/templates/locales/avo.es.yml +127 -0
  288. data/lib/generators/avo/templates/locales/avo.fr.yml +3 -0
  289. data/lib/generators/avo/templates/locales/avo.nb.yml +3 -0
  290. data/lib/generators/avo/templates/locales/avo.nn.yml +3 -0
  291. data/lib/generators/avo/templates/locales/avo.pt-BR.yml +3 -0
  292. data/lib/generators/avo/templates/locales/avo.pt.yml +3 -0
  293. data/lib/generators/avo/templates/locales/avo.ro.yml +8 -5
  294. data/lib/generators/avo/templates/locales/avo.tr.yml +3 -0
  295. data/lib/generators/avo/templates/resource/controller.tt +1 -1
  296. data/lib/generators/avo/templates/resource/resource.tt +7 -7
  297. data/lib/generators/avo/templates/resource_tools/partial.tt +2 -2
  298. data/lib/generators/avo/templates/resource_tools/resource_tool.tt +1 -1
  299. data/lib/generators/avo/templates/scope.tt +6 -0
  300. data/lib/generators/avo/templates/tailwindcss/Procfile.dev +1 -1
  301. data/lib/generators/avo/templates/tailwindcss/avo.tailwind.css +5 -3
  302. data/lib/generators/avo/templates/tailwindcss/tailwind.config.js +11 -0
  303. data/lib/tasks/avo_tasks.rake +72 -4
  304. data/public/avo-assets/avo.base.css +1893 -1187
  305. data/public/avo-assets/avo.base.js +223 -311
  306. data/public/avo-assets/avo.base.js.map +3 -3
  307. data/public/avo-assets/avo.css +9744 -0
  308. data/public/avo-assets/avo.js +513 -0
  309. data/public/avo-assets/avo.js.map +7 -0
  310. data/tailwind.custom.js +47 -0
  311. data/tailwind.preset.js +152 -0
  312. metadata +121 -116
  313. data/app/components/avo/card_component.html.erb +0 -46
  314. data/app/components/avo/card_component.rb +0 -25
  315. data/app/components/avo/dashboards/divider_component.html.erb +0 -9
  316. data/app/components/avo/dashboards/divider_component.rb +0 -19
  317. data/app/components/avo/fields/belongs_to_field/autocomplete_component.html.erb +0 -47
  318. data/app/components/avo/fields/belongs_to_field/autocomplete_component.rb +0 -95
  319. data/app/components/avo/fields/tags_field/edit_component.html.erb +0 -35
  320. data/app/components/avo/fields/tags_field/edit_component.rb +0 -4
  321. data/app/components/avo/fields/tags_field/index_component.html.erb +0 -10
  322. data/app/components/avo/fields/tags_field/index_component.rb +0 -9
  323. data/app/components/avo/fields/tags_field/show_component.html.erb +0 -7
  324. data/app/components/avo/fields/tags_field/show_component.rb +0 -5
  325. data/app/components/avo/fields/tags_field/tag_component.html.erb +0 -9
  326. data/app/components/avo/fields/tags_field/tag_component.rb +0 -11
  327. data/app/components/avo/index/ordering/base_component.rb +0 -9
  328. data/app/components/avo/index/ordering/button_component.html.erb +0 -11
  329. data/app/components/avo/index/ordering/button_component.rb +0 -23
  330. data/app/components/avo/index/ordering/buttons_component.html.erb +0 -32
  331. data/app/components/avo/index/ordering/buttons_component.rb +0 -47
  332. data/app/components/avo/item_switcher_component.html.erb +0 -27
  333. data/app/components/avo/item_switcher_component.rb +0 -48
  334. data/app/components/avo/sidebar/item_switcher_component.html.erb +0 -16
  335. data/app/components/avo/sidebar/item_switcher_component.rb +0 -15
  336. data/app/controllers/avo/dashboards/cards_controller.rb +0 -37
  337. data/app/controllers/avo/dashboards_controller.rb +0 -22
  338. data/app/controllers/avo/reorder_controller.rb +0 -25
  339. data/app/controllers/avo/team_users_controller.rb +0 -4
  340. data/app/javascript/js/controllers/base_controller.js +0 -22
  341. data/app/javascript/js/controllers/fields/tags_field_controller.js +0 -127
  342. data/app/javascript/js/controllers/toggle_panel_controller.js +0 -18
  343. data/app/views/avo/dashboards/cards/_chartkick_card.html.erb +0 -3
  344. data/app/views/avo/dashboards/cards/_metric_card.html.erb +0 -5
  345. data/app/views/avo/dashboards/cards/chartkick_missing.html.erb +0 -14
  346. data/app/views/avo/dashboards/cards/show.html.erb +0 -3
  347. data/app/views/avo/dashboards/show.html.erb +0 -38
  348. data/app/views/avo/partials/_global_search.html.erb +0 -19
  349. data/app/views/avo/sidebar/_license_warnings.html.erb +0 -6
  350. data/lib/avo/action_model.rb +0 -20
  351. data/lib/avo/app.rb +0 -237
  352. data/lib/avo/base_card.rb +0 -161
  353. data/lib/avo/concerns/fetches_things.rb +0 -150
  354. data/lib/avo/concerns/handles_field_args.rb +0 -47
  355. data/lib/avo/concerns/has_editable_controls.rb +0 -34
  356. data/lib/avo/concerns/has_fields.rb +0 -334
  357. data/lib/avo/concerns/has_html_attributes.rb +0 -108
  358. data/lib/avo/concerns/policy_helpers.rb +0 -31
  359. data/lib/avo/concerns/visible_in_dashboard.rb +0 -31
  360. data/lib/avo/dashboards/base_dashboard.rb +0 -89
  361. data/lib/avo/dashboards/base_divider.rb +0 -35
  362. data/lib/avo/dashboards/chartkick_card.rb +0 -77
  363. data/lib/avo/dashboards/dashboard_card.rb +0 -6
  364. data/lib/avo/dashboards/metric_card.rb +0 -9
  365. data/lib/avo/dashboards/partial_card.rb +0 -7
  366. data/lib/avo/fields/field_extensions/has_field_name.rb +0 -19
  367. data/lib/avo/fields/field_extensions/visible_in_different_views.rb +0 -111
  368. data/lib/avo/fields/tags_field.rb +0 -102
  369. data/lib/avo/grid_collector.rb +0 -42
  370. data/lib/avo/hosts/association_scope_host.rb +0 -8
  371. data/lib/avo/hosts/base_host.rb +0 -25
  372. data/lib/avo/hosts/card_visibility.rb +0 -20
  373. data/lib/avo/hosts/dashboard_card.rb +0 -22
  374. data/lib/avo/hosts/dashboard_visibility.rb +0 -19
  375. data/lib/avo/hosts/ordering.rb +0 -22
  376. data/lib/avo/hosts/record_host.rb +0 -7
  377. data/lib/avo/hosts/resource_record_host.rb +0 -7
  378. data/lib/avo/hosts/resource_view_record_host.rb +0 -7
  379. data/lib/avo/hosts/search_scope_host.rb +0 -7
  380. data/lib/avo/hosts/view_record_host.rb +0 -7
  381. data/lib/avo/hosts/visibility_host.rb +0 -12
  382. data/lib/avo/items_holder.rb +0 -96
  383. data/lib/avo/main_panel.rb +0 -3
  384. data/lib/avo/menu/base_item.rb +0 -25
  385. data/lib/avo/menu/builder.rb +0 -82
  386. data/lib/avo/menu/dashboard.rb +0 -22
  387. data/lib/avo/menu/group.rb +0 -2
  388. data/lib/avo/menu/link.rb +0 -6
  389. data/lib/avo/menu/menu.rb +0 -2
  390. data/lib/avo/menu/resource.rb +0 -22
  391. data/lib/avo/menu/section.rb +0 -2
  392. data/lib/avo/panel.rb +0 -24
  393. data/lib/avo/panel_builder.rb +0 -25
  394. data/lib/avo/resources/controls/action.rb +0 -38
  395. data/lib/avo/resources/controls/execution_context.rb +0 -58
  396. data/lib/avo/resources/controls/items_holder.rb +0 -19
  397. data/lib/avo/resources/controls/link_to.rb +0 -27
  398. data/lib/avo/row.rb +0 -26
  399. data/lib/avo/row_builder.rb +0 -24
  400. data/lib/avo/services/authorization_clients/nil_client.rb +0 -37
  401. data/lib/avo/services/authorization_clients/pundit_client.rb +0 -51
  402. data/lib/avo/sidebar.rb +0 -30
  403. data/lib/avo/sidebar_builder.rb +0 -24
  404. data/lib/avo/tab.rb +0 -72
  405. data/lib/avo/tab_builder.rb +0 -25
  406. data/lib/avo/tab_group.rb +0 -42
  407. data/lib/avo/tab_group_builder.rb +0 -43
  408. data/lib/avo/tools_manager.rb +0 -11
  409. data/lib/generators/avo/card/chartkick_generator.rb +0 -18
  410. data/lib/generators/avo/card/metric_generator.rb +0 -18
  411. data/lib/generators/avo/card/partial_generator.rb +0 -19
  412. data/lib/generators/avo/templates/js/avo.custom.js +0 -2
  413. data/lib/generators/avo/templates/standalone_action.tt +0 -8
  414. /data/app/assets/stylesheets/css/{tags.css → fields/tags.css} +0 -0
@@ -0,0 +1,93 @@
1
+ class Avo::Services::DebugService
2
+ class << self
3
+ def debug_report(request = nil)
4
+ payload = {}
5
+
6
+ hq = Avo::Licensing::HQ.new(request)
7
+
8
+ payload[:license_id] = Avo::Current&.license&.id
9
+ payload[:license_valid] = Avo::Current&.license&.valid?
10
+ payload[:license_payload] = Avo::Current&.license&.payload
11
+ payload[:license_response] = Avo::Current&.license&.response
12
+ payload[:hq_payload] = hq&.payload
13
+ payload[:thread_count] = get_thread_count
14
+ payload[:license_abilities] = Avo::Current&.license&.abilities
15
+ payload[:cache_store] = Avo.cache_store&.class&.to_s
16
+ payload[:avo_metadata] = avo_metadata
17
+ payload[:app_timezone] = Time.current.zone
18
+ payload[:cache_key] = Avo::Licensing::HQ.cache_key
19
+ payload[:cache_key_contents] = hq&.cached_response
20
+ payload[:plugins] = Avo.plugin_manager
21
+
22
+ payload
23
+ rescue => e
24
+ e
25
+ end
26
+
27
+ def get_thread_count
28
+ Thread.list.count { |thread| thread.status == "run" }
29
+ rescue => e
30
+ e
31
+ end
32
+
33
+ def avo_metadata
34
+ resources = Avo.resource_manager.all
35
+ dashboards = defined?(Avo::Dashboards) ? Avo::Dashboards.dashboard_manager.all : []
36
+ # field_definitions = resources.map(&:get_field_definitions)
37
+ # fields_count = field_definitions.map(&:count).sum
38
+ # fields_per_resource = sprintf("%0.01f", fields_count / (resources.count + 0.0))
39
+
40
+ # field_types = {}
41
+ # custom_fields_count = 0
42
+ # field_definitions.each do |fields|
43
+ # fields.each do |field|
44
+ # field_types[field.type] ||= 0
45
+ # field_types[field.type] += 1
46
+
47
+ # custom_fields_count += 1 if field.custom?
48
+ # end
49
+ # end
50
+
51
+ {
52
+ resources_count: resources.count,
53
+ dashboards_count: dashboards.count,
54
+ # fields_count: fields_count,
55
+ # fields_per_resource: fields_per_resource,
56
+ # custom_fields_count: custom_fields_count,
57
+ # field_types: field_types,
58
+ # **other_metadata(:actions), # TODO: this is fetching actions without hydration
59
+ # **other_metadata(:filters),
60
+ main_menu_present: Avo.configuration.main_menu.present?,
61
+ profile_menu_present: Avo.configuration.profile_menu.present?,
62
+ cache_store: Avo.cache_store&.class&.to_s,
63
+ **config_metadata
64
+ }
65
+ # rescue => error
66
+ # {
67
+ # error: error.message
68
+ # }
69
+ end
70
+
71
+ def other_metadata(type = :actions)
72
+ resources = Avo.resource_manager.all
73
+
74
+ types = resources.map(&:"get_#{type}")
75
+ type_count = types.flatten.uniq.count
76
+ type_per_resource = sprintf("%0.01f", types.map(&:count).sum / (resources.count + 0.0))
77
+
78
+ {
79
+ "#{type}_count": type_count,
80
+ "#{type}_per_resource": type_per_resource
81
+ }
82
+ end
83
+
84
+ def config_metadata
85
+ {
86
+ config: {
87
+ root_path: Avo.configuration.root_path,
88
+ app_name: Avo.configuration.app_name
89
+ }
90
+ }
91
+ end
92
+ end
93
+ end
@@ -1,32 +1,28 @@
1
1
  module Avo
2
2
  module Services
3
3
  class EncryptionService
4
- attr_reader :message
5
- attr_reader :purpose
6
- attr_reader :crypt
7
-
8
4
  class << self
9
- def encrypt(message:, purpose:)
10
- new(message: message, purpose: purpose).encrypt
5
+ def encrypt(...)
6
+ new(...).encrypt
11
7
  end
12
8
 
13
- def decrypt(message:, purpose:)
14
- new(message: message, purpose: purpose).decrypt
9
+ def decrypt(...)
10
+ new(...).decrypt
15
11
  end
16
12
  end
17
13
 
18
- def initialize(message:, purpose:)
14
+ def initialize(message:, purpose:, **kwargs)
19
15
  @message = message
20
16
  @purpose = purpose
21
- @crypt = ActiveSupport::MessageEncryptor.new(encryption_key)
17
+ @crypt = ActiveSupport::MessageEncryptor.new(encryption_key, **kwargs)
22
18
  end
23
19
 
24
20
  def encrypt
25
- crypt.encrypt_and_sign(message, purpose: purpose)
21
+ @crypt.encrypt_and_sign(@message, purpose: @purpose)
26
22
  end
27
23
 
28
24
  def decrypt
29
- crypt.decrypt_and_verify(message, purpose: purpose)
25
+ @crypt.decrypt_and_verify(@message, purpose: @purpose)
30
26
  end
31
27
 
32
28
  private
@@ -0,0 +1,85 @@
1
+ class Avo::Services::TelemetryService
2
+ class << self
3
+ def telemetry_info
4
+ {
5
+ # license: Avo.configuration.license,
6
+ # license_key: Avo.configuration.license_key,
7
+ avo_version: Avo::VERSION,
8
+ rails_version: Rails::VERSION::STRING,
9
+ ruby_version: RUBY_VERSION,
10
+ environment: Rails.env,
11
+ # ip: current_request&.ip,
12
+ # host: current_request&.host,
13
+ # port: current_request&.port,
14
+ app_name: app_name,
15
+ avo_metadata: avo_metadata,
16
+ }
17
+ end
18
+
19
+ def app_name
20
+ Rails.application.class.to_s.split("::").first
21
+ rescue
22
+ nil
23
+ end
24
+
25
+ def avo_metadata
26
+ resources = Avo.resource_manager.all
27
+ dashboards = Avo::Current.app.dashboard_manager.all
28
+ field_definitions = resources.map(&:get_field_definitions)
29
+ fields_count = field_definitions.map(&:count).sum
30
+ fields_per_resource = sprintf("%0.01f", fields_count / (resources.count + 0.0))
31
+
32
+ field_types = {}
33
+ custom_fields_count = 0
34
+ field_definitions.each do |fields|
35
+ fields.each do |field|
36
+ field_types[field.type] ||= 0
37
+ field_types[field.type] += 1
38
+
39
+ custom_fields_count += 1 if field.custom?
40
+ end
41
+ end
42
+
43
+ {
44
+ resources_count: resources.count,
45
+ dashboards_count: dashboards.count,
46
+ fields_count: fields_count,
47
+ fields_per_resource: fields_per_resource,
48
+ custom_fields_count: custom_fields_count,
49
+ field_types: field_types,
50
+ **other_metadata(:actions),
51
+ **other_metadata(:filters),
52
+ main_menu_present: Avo.configuration.main_menu.present?,
53
+ profile_menu_present: Avo.configuration.profile_menu.present?,
54
+ cache_store: Avo.cache_store&.class&.to_s,
55
+ **config_metadata
56
+ }
57
+ # rescue => error
58
+ # {
59
+ # error: error.message
60
+ # }
61
+ end
62
+
63
+ def other_metadata(type = :actions)
64
+ resources = Avo.resource_manager.all
65
+
66
+ types = resources.map(&:"get_#{type}")
67
+ type_count = types.flatten.uniq.count
68
+ type_per_resource = sprintf("%0.01f", types.map(&:count).sum / (resources.count + 0.0))
69
+
70
+ {
71
+ "#{type}_count": type_count,
72
+ "#{type}_per_resource": type_per_resource
73
+ }
74
+ end
75
+
76
+ def config_metadata
77
+ {
78
+ config: {
79
+ root_path: Avo.configuration.root_path,
80
+ app_name: Avo.configuration.app_name
81
+ }
82
+ }
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,362 @@
1
+ module Avo
2
+ module TestHelpers
3
+ # Finds the wrapper element on the index view for the given field id and type, and associated with the given record id
4
+ # Example usage:
5
+ # index_field_wrapper(id: "name", type: "text", record_id: 2)
6
+ # index_field_wrapper(id: "name", record_id: 2)
7
+ def index_field_wrapper(id:, record_id:, type: nil)
8
+ base_data = "#{row(record_id)} [data-field-id='#{id}']"
9
+
10
+ if type.present?
11
+ find("#{base_data}[data-resource-index-target='#{wrapper_name_for(id: id, type: type)}']")
12
+ else
13
+ find(base_data)
14
+ end
15
+ end
16
+
17
+ # Finds the wrapper element on the index grid view type for the given record id
18
+ # Example usage:
19
+ # grid_field_wrapper(record_id: 5)
20
+ def grid_field_wrapper(record_id:)
21
+ find("[data-component-name='avo/index/grid_item_component'][data-resource-id='#{record_id}']")
22
+ end
23
+
24
+ # Finds the wrapper element on the show view for the given field id and type
25
+ # Example usage:
26
+ # show_field_wrapper(id: "name", type: "text")
27
+ # show_field_wrapper(id: "name")
28
+ def show_field_wrapper(id:, type: nil)
29
+ base_data = "[data-panel-id='main'] [data-field-id='#{id}']"
30
+
31
+ if type.present?
32
+ find("#{base_data}[data-resource-show-target='#{wrapper_name_for(id: id, type: type)}']")
33
+ else
34
+ find(base_data)
35
+ end
36
+ end
37
+
38
+ # Finds the table on the show view for the given has_many field id and view
39
+ # Example usage:
40
+ # has_many_field_wrapper(id: :users)
41
+ # has_many_field_wrapper(id: :users, view: :edit)
42
+ def has_many_field_wrapper(id:, view: :show)
43
+ related_field_context(id: id, relation: :has_many, view: view)
44
+ end
45
+
46
+ # Finds the table on the show view for the given has_and_belongs_to_many field id and view
47
+ # Example usage:
48
+ # has_and_belongs_to_many_field_wrapper(id: :users)
49
+ # has_and_belongs_to_many_field_wrapper(id: :users, view: :edit)
50
+ def has_and_belongs_to_many_field_wrapper(id:, view: :show)
51
+ related_field_context(id: id, relation: :has_and_belongs_to_many, view: view)
52
+ end
53
+
54
+ # Finds the table on the show view for the given has_one field id and view
55
+ # Example usage:
56
+ # has_one_field_wrapper(id: :users)
57
+ # has_one_field_wrapper(id: :users, view: :edit)
58
+ def has_one_field_wrapper(id:, view: :show)
59
+ related_field_context(id: id, relation: :has_one, view: view)
60
+ end
61
+
62
+ # Finds the label element on the index view for the given field id
63
+ # Example usage:
64
+ # index_field_label(id: "name")
65
+ def index_field_label(id:)
66
+ find("[data-component-name='avo/partials/table_header'] [data-table-header-field-id='#{id}']").text
67
+ end
68
+
69
+ # Finds the label element on the show view for the given field id
70
+ # Example usage:
71
+ # show_field_label(id: "name")
72
+ def show_field_label(id:)
73
+ within(show_field_wrapper(id: id)) { find("[data-slot='label']").text }
74
+ end
75
+
76
+ # Finds the value element on the index view for the given field id
77
+ # Example usage:
78
+ # index_field_value(id: "name", record_id: 2)
79
+ def index_field_value(id:, record_id:, type: nil)
80
+ index_field_wrapper(id: id, record_id: record_id, type: type).text
81
+ end
82
+
83
+ # Finds the value element on the show view for the given field id
84
+ # Example usage:
85
+ # show_field_value(id: "name")
86
+ def show_field_value(id:, type: nil)
87
+ within(show_field_wrapper(id: id, type: type)) { find("[data-slot='value']").text }
88
+ end
89
+
90
+ def empty_dash
91
+ "—"
92
+ end
93
+
94
+ def confirm_alert
95
+ Capybara.using_wait_time(1) do
96
+ page.driver.browser.switch_to.alert.accept
97
+ rescue Selenium::WebDriver::Error::NoSuchAlertError
98
+ retry
99
+ end
100
+ end
101
+
102
+ # Example usage:
103
+ # click_resource_search_input # opens the first search box on the given page
104
+ # opens the search box for the "users" resource
105
+ # within(has_and_belongs_to_many_field_wrapper(id: :users)) {
106
+ # click_resource_search_input
107
+ # write_in_search("Bob")
108
+ # }
109
+ def click_resource_search_input
110
+ first("[data-search-resource]:not([data-search-resource='global'])").click
111
+ wait_for_search_loaded
112
+ end
113
+
114
+ def click_global_search_input
115
+ page.find(:xpath, "//*[contains(@class, 'global-search')]").click
116
+ wait_for_search_loaded
117
+ end
118
+
119
+ # Should use the click_global_search_input or click_resource_search_input method to open the search box first.
120
+ # Example usage:
121
+ # open_search_box(:users)
122
+ # within(has_and_belongs_to_many_field_wrapper(id: :users)) {
123
+ # click_resource_search_input # opens the search box for the "users" resource
124
+ # write_in_search("Bob")
125
+ # }
126
+ def write_in_search(input)
127
+ # Use xpath to find outside of within context if any
128
+ find(:xpath, "//input[@class='aa-Input']").set(input)
129
+ wait_for_search_loaded
130
+ end
131
+
132
+ # Should use the click_global_search_input or click_resource_search_input method to open the search box first and optionaly write_in_search.
133
+ # Example usage:
134
+ # open_search_box(:users) # opens the search box for the "users" resource
135
+ # write_in_search("John Doe")
136
+ # select_first_result_in_search
137
+ def select_first_result_in_search
138
+ find(".aa-Input").send_keys :arrow_down
139
+ find(".aa-Input").send_keys :enter
140
+ wait_for_search_loaded
141
+ end
142
+
143
+ # Save a record and wait for the page to load
144
+ def save
145
+ click_on "Save"
146
+ wait_for_loaded
147
+ end
148
+
149
+ def click_tab(tab_name = "", within_target: nil, **args)
150
+ if within_target.present?
151
+ within within_target do
152
+ within find('[data-controller="tabs"] turbo-frame:not(.hidden) [data-target="tab-switcher"]') do
153
+ find_link(tab_name).click
154
+ end
155
+ end
156
+ else
157
+ within find('[data-controller="tabs"] turbo-frame:not(.hidden) [data-target="tab-switcher"]') do
158
+ find_link(tab_name).click
159
+ end
160
+ end
161
+ end
162
+
163
+ def tab_group(index = 0)
164
+ find_all('[data-controller="tabs"]')[index]
165
+ end
166
+
167
+ def first_tab_group
168
+ tab_group 0
169
+ end
170
+
171
+ def second_tab_group
172
+ tab_group 1
173
+ end
174
+
175
+ def third_tab_group
176
+ tab_group 3
177
+ end
178
+
179
+ def click_on_sidebar_item(label)
180
+ within main_sidebar do
181
+ click_on label
182
+ end
183
+ end
184
+
185
+ def set_picker_day(date)
186
+ find(".flatpickr-day[aria-label=\"#{date}\"]").click
187
+ sleep 0.2
188
+ end
189
+
190
+ def set_picker_hour(value)
191
+ find(".flatpickr-hour").set(value)
192
+ end
193
+
194
+ def set_picker_minute(value)
195
+ find(".flatpickr-minute").set(value)
196
+ end
197
+
198
+ def set_picker_second(value)
199
+ find(".flatpickr-second").set(value)
200
+ end
201
+
202
+ def open_picker
203
+ text_input.click
204
+ end
205
+
206
+ def close_picker
207
+ find('[data-target="title"]').click
208
+ sleep 0.3
209
+ end
210
+
211
+ # Click on the action from the panel (index and show above the table)
212
+ # Pass list: nil to run an action outside of the list
213
+ # Pass list: "List name" if list is not the default "Actions"
214
+ # Example usage:
215
+ # open_panel_action(action_name: "Dummy action")
216
+ # open_panel_action(list: nil, action_name: "Release fish")
217
+ # open_panel_action(list: "Runnables", action_name: "Release fish")
218
+ def open_panel_action(action_name:, list: "Actions")
219
+ open_action(action_name: action_name, list: list, context: first("[data-target='panel-tools']"))
220
+ end
221
+
222
+ # Open the action from the record_id row
223
+ # Pass list: nil to run an action outside of the list
224
+ # Pass list: "List name" if list is not the default "Actions"
225
+ # Example usage:
226
+ # open_row_action(action_name: "Dummy action")
227
+ # open_row_action(list: nil, action_name: "Release fish")
228
+ # open_row_action(list: "Runnables", action_name: "Release fish")
229
+ def open_row_action(record_id:, action_name:, list: "Actions")
230
+ open_action(action_name: action_name, list: list, context: row(record_id))
231
+ end
232
+
233
+ # Click on submit action button if dialog is open
234
+ def run_action
235
+ within(find("[role='dialog']")) do
236
+ find("[data-target='submit_action']").click
237
+ end
238
+
239
+ wait_for_action_dialog_to_disappear
240
+ end
241
+
242
+ def check_select_all
243
+ find("input[type='checkbox'][name='Select all'][data-action='input->item-select-all#toggle']").set(true)
244
+ end
245
+
246
+ def toggle_collapsable(section)
247
+ find("[data-action='click->menu#triggerCollapse'][data-menu-key-param*='main_menu.#{section.underscore}'] svg").click
248
+ end
249
+
250
+ # Example usage:
251
+ # expect(add_tag(field: :tags, tag: "one")).to eq ["one"]
252
+ # add_tag(field: :tags, tag: "two")
253
+ def add_tag(field:, tag:)
254
+ # Find the input field for the specified field
255
+ input = find("[data-field-id='#{field}'] [data-slot='value'] [role='textbox']")
256
+
257
+ # Enter the specified tag into the input field
258
+ input.set(tag)
259
+ sleep 0.1
260
+
261
+ input.send_keys :return
262
+ wait_for_tag_to_appear(tag)
263
+
264
+ # Return an array of the current tags
265
+ tags(field: field)
266
+ end
267
+
268
+ # Example usage:
269
+ # expect(remove_tag(field: :tags, tag: "one")).to eq ["three"]
270
+ # remove_tag(field: :tags, tag: "one")
271
+ def remove_tag(field:, tag:)
272
+ # Within the specified field
273
+ within("[data-field-id='#{field}'] [data-slot='value']") do
274
+ # Find the tag with the specified text and click the remove button for the tag
275
+ page.find(".tagify__tag", text: tag).find(".tagify__tag__removeBtn").click
276
+
277
+ wait_for_tag_to_disappear(tag)
278
+ end
279
+
280
+ # Return an array of the current tags
281
+ tags(field: field)
282
+ end
283
+
284
+ # Example usage:
285
+ # expect(tags(field: :tags)).to eq ["one", "two", "three"]
286
+ # expect(tags(field: :tags)).to eq []
287
+ def tags(field:)
288
+ # Find all elements with class 'tagify__tag'
289
+ # Map the elements to their 'label' attribute values and return the array of labels
290
+ page.all(".tagify__tag").map { |element| element[:label] }
291
+ end
292
+
293
+ # Example usage:
294
+ # expect(tag_suggestions(field: :tags, input: "")).to eq ["one", "two", "three"]
295
+ # expect(tag_suggestions(field: :tags, input: "t")).to eq ["two", "three"]
296
+ def tag_suggestions(field:, input:)
297
+ # Find the input field for the specified tag field
298
+ input_area = find("[data-field-id='#{field}'] [data-slot='value'] [role='textbox']")
299
+
300
+ # If the input argument is present, enter it into the input field
301
+ # Else, just click on the middle of the input field to display the dropdown
302
+ if input.present?
303
+ input_area.set(input)
304
+ else
305
+ input_area.click(x: input_area.native.size.width / 2, y: input_area.native.size.height / 2)
306
+ end
307
+ wait_for_tag_suggestions_to_appear
308
+
309
+ # Find all elements with class 'tagify_dropdown_item' within the dropdown
310
+ # Map the elements to their 'label' attribute values and return the array of labels
311
+ page.all(".tagify__dropdown__item").map { |element| element[:label] }
312
+ end
313
+
314
+ private
315
+
316
+ # Returns the name of the wrapper element for the given field id and type
317
+ def wrapper_name_for(id:, type:)
318
+ "#{id.camelize(:lower)}#{type.camelize}Wrapper"
319
+ end
320
+
321
+ # Finds the context element for the related field with the given id, relation, and view
322
+ # ex: has_and_belongs_to_many_users = related_field_context(id: :users, relation: :has_and_belongs_to_many)
323
+ # Now on the returend element you can do:
324
+ # first_name_wrapper = within has_and_belongs_to_many_users do
325
+ # index_field_wrapper(id: "first_name", type: "text", record_id: 7)
326
+ # end
327
+ def related_field_context(id:, relation:, view: :show)
328
+ turbo_frame = "#{relation}_field_#{view}_#{id}"
329
+ find("[id='#{turbo_frame}']")
330
+ end
331
+
332
+ def main_sidebar
333
+ find('[data-sidebar-target="sidebar"]')
334
+ end
335
+
336
+ # Opens an action. If a list is provided, it will click on the list first
337
+ # and then find the specified action name within the panel.
338
+ # If no list is present, it will directly click on the action link.
339
+ def open_action(action_name:, list:, context:, &block)
340
+ within(context) do
341
+ if list.present?
342
+ sleep 0.1
343
+ click_on list
344
+ within("[data-toggle-target='panel']") do
345
+ find("a[data-action-name='#{action_name}']").click
346
+ end
347
+ else
348
+ click_link(action_name)
349
+ end
350
+ end
351
+
352
+ # Within the dialog, ensure that the action name is present
353
+ within(find("[role='dialog']")) do
354
+ expect(page).to have_content(action_name)
355
+ end
356
+ end
357
+
358
+ def row(id)
359
+ "[data-component-name='avo/index/table_row_component'][data-resource-id='#{id}']"
360
+ end
361
+ end
362
+ end
@@ -0,0 +1,30 @@
1
+ module Avo
2
+ module Tools
3
+ class ToolManager
4
+ class << self
5
+ def build
6
+ new
7
+ end
8
+ end
9
+
10
+ # Insert any partials that we find in app/views/avo/sidebar/items.
11
+ def get_sidebar_partials
12
+ Dir.glob(Rails.root.join("app", "views", "avo", "sidebar", "items", "*.html.erb"))
13
+ .map do |path|
14
+ File.basename path
15
+ end
16
+ .map do |filename|
17
+ # remove the leading underscore (_)
18
+ filename[0] = ""
19
+ # remove the extension
20
+ filename.gsub!(".html.erb", "")
21
+ filename
22
+ end
23
+ end
24
+
25
+ def tools_for_navigation
26
+ get_sidebar_partials
27
+ end
28
+ end
29
+ end
30
+ end
data/lib/avo/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Avo
2
- VERSION = "2.43.0" unless const_defined?(:VERSION)
2
+ VERSION = "3.0.2" unless const_defined?(:VERSION)
3
3
  end
@@ -0,0 +1,36 @@
1
+ # Allows to check the the view type by using `view.index?` or `view.edit?` etc...
2
+ # It also allows to check if the view is a form or a display view by using `view.form?` or `view.display?`
3
+ module Avo
4
+ class ViewInquirer < ActiveSupport::StringInquirer
5
+ DISPLAY_VIEWS = %w[index show].freeze unless defined? DISPLAY_VIEWS
6
+ FORM_VIEWS = %w[new edit].freeze unless defined? FORM_VIEWS
7
+
8
+ def initialize(view)
9
+ super(view.to_s)
10
+
11
+ @display = in? DISPLAY_VIEWS
12
+ @form = in? FORM_VIEWS
13
+ end
14
+
15
+ def display?
16
+ @display
17
+ end
18
+
19
+ def form?
20
+ @form
21
+ end
22
+
23
+ # To avoid breaking changes we allow the comparison with symbols
24
+ def ==(other)
25
+ if other.is_a? Symbol
26
+ to_sym == other
27
+ else
28
+ super(other)
29
+ end
30
+ end
31
+
32
+ def in?(another_object)
33
+ super another_object.map(&:to_s)
34
+ end
35
+ end
36
+ end