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.
- checksums.yaml +4 -4
- data/Gemfile +30 -26
- data/Gemfile.lock +235 -161
- data/README.md +19 -27
- data/Rakefile +2 -0
- data/app/assets/stylesheets/avo.base.css +1 -1
- data/app/assets/svgs/font.svg +1 -0
- data/app/assets/svgs/triangle-up.svg +1 -0
- data/app/components/avo/actions_component.html.erb +19 -5
- data/app/components/avo/actions_component.rb +39 -19
- data/app/components/avo/asset_manager/javascript_component.html.erb +3 -0
- data/app/components/avo/asset_manager/javascript_component.rb +13 -0
- data/app/components/avo/asset_manager/stylesheet_component.html.erb +3 -0
- data/app/components/avo/asset_manager/stylesheet_component.rb +13 -0
- data/app/components/avo/base_component.rb +15 -12
- data/app/components/avo/button_component.rb +20 -3
- data/app/components/avo/empty_state_component.rb +1 -1
- data/app/components/avo/field_wrapper_component.html.erb +1 -1
- data/app/components/avo/field_wrapper_component.rb +9 -15
- data/app/components/avo/fields/area_field/edit_component.html.erb +2 -2
- data/app/components/avo/fields/belongs_to_field/edit_component.html.erb +75 -79
- data/app/components/avo/fields/belongs_to_field/edit_component.rb +7 -7
- data/app/components/avo/fields/belongs_to_field/index_component.html.erb +1 -1
- data/app/components/avo/fields/belongs_to_field/show_component.rb +2 -2
- data/app/components/avo/fields/boolean_field/edit_component.html.erb +1 -1
- data/app/components/avo/fields/boolean_field/index_component.html.erb +1 -1
- data/app/components/avo/fields/boolean_group_field/edit_component.html.erb +3 -3
- data/app/components/avo/fields/common/badge_viewer_component.rb +1 -1
- data/app/components/avo/fields/common/boolean_check_component.html.erb +1 -12
- data/app/components/avo/fields/common/boolean_check_component.rb +2 -1
- data/app/components/avo/fields/common/boolean_group_component.html.erb +2 -2
- data/app/components/avo/fields/common/files/view_type/grid_item_component.rb +2 -2
- data/app/components/avo/fields/common/gravatar_viewer_component.html.erb +1 -1
- data/app/components/avo/fields/common/gravatar_viewer_component.rb +2 -2
- data/app/components/avo/fields/common/heading_component.html.erb +3 -8
- data/app/components/avo/fields/common/heading_component.rb +1 -3
- data/app/components/avo/fields/common/key_value_component.html.erb +2 -2
- data/app/components/avo/fields/common/key_value_component.rb +2 -2
- data/app/components/avo/fields/common/progress_bar_component.rb +3 -9
- data/app/components/avo/fields/common/status_viewer_component.html.erb +3 -0
- data/app/components/avo/fields/edit_component.rb +2 -2
- data/app/components/avo/fields/external_image_field/index_component.html.erb +1 -1
- data/app/components/avo/fields/file_field/index_component.html.erb +2 -2
- data/app/components/avo/fields/gravatar_field/index_component.html.erb +1 -1
- data/app/components/avo/fields/has_one_field/index_component.html.erb +1 -1
- data/app/components/avo/fields/has_one_field/show_component.html.erb +3 -2
- data/app/components/avo/fields/has_one_field/show_component.rb +2 -2
- data/app/components/avo/fields/heading_field/edit_component.html.erb +1 -1
- data/app/components/avo/fields/heading_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/id_field/index_component.html.erb +1 -1
- data/app/components/avo/fields/index_component.rb +6 -6
- data/app/components/avo/fields/location_field/edit_component.html.erb +12 -10
- data/app/components/avo/fields/preview_field/index_component.html.erb +10 -0
- data/app/components/avo/fields/preview_field/index_component.rb +4 -0
- data/app/components/avo/fields/select_field/edit_component.html.erb +1 -1
- data/app/components/avo/fields/show_component.rb +5 -2
- data/app/components/avo/fields/text_field/index_component.html.erb +1 -1
- data/app/components/avo/fields/trix_field/edit_component.html.erb +2 -2
- data/app/components/avo/fields/trix_field/edit_component.rb +1 -1
- data/app/components/avo/fields/trix_field/show_component.html.erb +1 -1
- data/app/components/avo/filters_component.html.erb +9 -3
- data/app/components/avo/filters_component.rb +4 -4
- data/app/components/avo/index/field_wrapper_component.rb +1 -13
- data/app/components/avo/index/grid_item_component.html.erb +13 -36
- data/app/components/avo/index/grid_item_component.rb +43 -16
- data/app/components/avo/index/resource_controls_component.html.erb +3 -81
- data/app/components/avo/index/resource_controls_component.rb +125 -18
- data/app/components/avo/index/resource_grid_component.html.erb +5 -3
- data/app/components/avo/index/resource_grid_component.rb +5 -2
- data/app/components/avo/index/resource_map_component.html.erb +1 -1
- data/app/components/avo/index/resource_map_component.rb +3 -3
- data/app/components/avo/index/resource_table_component.html.erb +5 -4
- data/app/components/avo/index/resource_table_component.rb +24 -7
- data/app/components/avo/index/table_row_component.html.erb +9 -5
- data/app/components/avo/index/table_row_component.rb +3 -2
- data/app/components/avo/items/panel_component.html.erb +25 -0
- data/app/components/avo/items/panel_component.rb +43 -0
- data/app/components/avo/items/switcher_component.html.erb +17 -0
- data/app/components/avo/items/switcher_component.rb +79 -0
- data/app/components/avo/items/visible_items_component.html.erb +10 -0
- data/app/components/avo/items/visible_items_component.rb +11 -0
- data/app/components/avo/modal_component.html.erb +3 -4
- data/app/components/avo/paginator_component.html.erb +29 -40
- data/app/components/avo/paginator_component.rb +23 -5
- data/app/components/avo/panel_component.html.erb +7 -5
- data/app/components/avo/referrer_params_component.html.erb +1 -1
- data/app/components/avo/resource_component.rb +205 -26
- data/app/components/avo/resource_sidebar_component.html.erb +15 -18
- data/app/components/avo/resource_sidebar_component.rb +5 -3
- data/app/components/avo/sidebar/link_component.rb +1 -1
- data/app/components/avo/sidebar_component.html.erb +10 -3
- data/app/components/avo/sidebar_component.rb +5 -3
- data/app/components/avo/sidebar_profile_component.html.erb +18 -12
- data/app/components/avo/tab_group_component.html.erb +14 -8
- data/app/components/avo/tab_group_component.rb +1 -6
- data/app/components/avo/tab_switcher_component.html.erb +17 -40
- data/app/components/avo/tab_switcher_component.rb +6 -41
- data/app/components/avo/views/resource_edit_component.html.erb +23 -84
- data/app/components/avo/views/resource_edit_component.rb +20 -19
- data/app/components/avo/views/resource_index_component.html.erb +42 -47
- data/app/components/avo/views/resource_index_component.rb +76 -13
- data/app/components/avo/views/resource_show_component.html.erb +16 -177
- data/app/components/avo/views/resource_show_component.rb +16 -10
- data/app/controllers/avo/actions_controller.rb +37 -41
- data/app/controllers/avo/application_controller.rb +119 -181
- data/app/controllers/avo/associations_controller.rb +34 -43
- data/app/controllers/avo/attachments_controller.rb +4 -4
- data/app/controllers/avo/base_controller.rb +145 -98
- data/app/controllers/avo/debug_controller.rb +17 -5
- data/app/controllers/avo/home_controller.rb +1 -1
- data/app/controllers/avo/search_controller.rb +56 -50
- data/app/controllers/concerns/avo/initializes_avo.rb +22 -0
- data/app/helpers/avo/application_helper.rb +18 -8
- data/app/helpers/avo/resources_helper.rb +1 -1
- data/app/helpers/avo/url_helpers.rb +28 -12
- data/app/javascript/avo.base.js +1 -0
- data/app/javascript/js/application.js +3 -0
- data/app/javascript/js/controllers/action_controller.js +3 -1
- data/app/javascript/js/controllers/actions_overflow_controller.js +62 -0
- data/app/javascript/js/controllers/fields/reload_belongs_to_field_controller.js +7 -7
- data/app/javascript/js/controllers/filter_controller.js +1 -1
- data/app/javascript/js/controllers/input_autofocus_controller.js +12 -0
- data/app/javascript/js/controllers/preview_controller.js +24 -0
- data/app/javascript/js/controllers/search_controller.js +4 -2
- data/app/javascript/js/controllers/self_destroy_controller.js +7 -0
- data/app/javascript/js/controllers/toggle_controller.js +48 -0
- data/app/javascript/js/controllers.js +11 -5
- data/app/javascript/js/custom-stream-actions.js +15 -0
- data/app/views/avo/actions/show.html.erb +10 -7
- data/app/views/avo/associations/new.html.erb +2 -2
- data/app/views/avo/base/_new_via_belongs_to.html.erb +1 -1
- data/app/views/avo/base/close_modal_and_reload_field.turbo_stream.erb +3 -3
- data/app/views/avo/base/create_fail_action.turbo_stream.erb +2 -2
- data/app/views/avo/base/edit.html.erb +1 -1
- data/app/views/avo/base/index.html.erb +4 -3
- data/app/views/avo/base/new.html.erb +2 -1
- data/app/views/avo/base/preview.html.erb +19 -0
- data/app/views/avo/base/show.html.erb +2 -2
- data/app/views/avo/debug/_valid_indicator.html.erb +9 -0
- data/app/views/avo/debug/report.html.erb +32 -17
- data/app/views/avo/debug/{index.html.erb → status.html.erb} +31 -14
- data/app/views/avo/partials/_custom_tools_alert.html.erb +2 -2
- data/app/views/avo/partials/_flash_alerts.turbo_stream.erb +1 -1
- data/app/views/avo/partials/_footer.html.erb +1 -1
- data/app/views/avo/partials/_javascript.html.erb +5 -0
- data/app/views/avo/partials/_logo.html.erb +1 -1
- data/app/views/avo/partials/_navbar.html.erb +3 -5
- data/app/views/avo/partials/_resource_search.html.erb +1 -0
- data/app/views/avo/partials/_table_header.html.erb +5 -11
- data/app/views/layouts/avo/application.html.erb +5 -4
- data/avo.gemspec +11 -8
- data/bin/dev +3 -1
- data/bin/prod +0 -0
- data/config/i18n-tasks.yml +1 -1
- data/config/initializers/pagy.rb +2 -0
- data/config/master.key +1 -0
- data/config/routes.rb +7 -10
- data/db/factories.rb +6 -0
- data/lib/avo/asset_manager.rb +30 -0
- data/lib/avo/base_action.rb +84 -82
- data/lib/avo/base_resource.rb +286 -225
- data/lib/avo/base_resource_tool.rb +9 -16
- data/lib/avo/concerns/borrow_items_holder.rb +35 -0
- data/lib/avo/concerns/breadcrumbs.rb +2 -2
- data/lib/avo/concerns/{can_replace_fields.rb → can_replace_items.rb} +5 -9
- data/lib/avo/concerns/filters_session_handler.rb +7 -5
- data/lib/avo/concerns/has_controls.rb +37 -0
- data/lib/avo/concerns/has_description.rb +23 -0
- data/lib/avo/concerns/has_helpers.rb +18 -0
- data/lib/avo/concerns/has_item_type.rb +42 -0
- data/lib/avo/concerns/has_items.rb +339 -0
- data/lib/avo/concerns/hydration.rb +17 -0
- data/lib/avo/concerns/is_resource_item.rb +16 -36
- data/lib/avo/concerns/is_visible.rb +15 -0
- data/lib/avo/concerns/model_class_constantized.rb +0 -2
- data/lib/avo/concerns/pagination.rb +53 -0
- data/lib/avo/concerns/visible_in_different_views.rb +132 -0
- data/lib/avo/concerns/visible_items.rb +7 -38
- data/lib/avo/configuration/branding.rb +0 -12
- data/lib/avo/configuration.rb +28 -11
- data/lib/avo/current.rb +39 -0
- data/lib/avo/dsl/field_parser.rb +3 -3
- data/lib/avo/dynamic_router.rb +18 -3
- data/lib/avo/engine.rb +35 -30
- data/lib/avo/error_manager.rb +25 -0
- data/lib/avo/execution_context.rb +14 -15
- data/lib/avo/fields/base_field.rb +84 -115
- data/lib/avo/fields/belongs_to_field.rb +19 -23
- data/lib/avo/fields/concerns/file_authorization.rb +2 -2
- data/lib/avo/fields/concerns/handles_field_args.rb +49 -0
- data/lib/avo/fields/concerns/has_default.rb +1 -5
- data/lib/avo/fields/concerns/has_field_name.rb +22 -0
- data/lib/avo/fields/concerns/has_html_attributes.rb +112 -0
- data/lib/avo/fields/concerns/is_disabled.rb +1 -5
- data/lib/avo/fields/concerns/is_readonly.rb +1 -5
- data/lib/avo/fields/concerns/is_required.rb +5 -7
- data/lib/avo/fields/concerns/is_searchable.rb +15 -0
- data/lib/avo/fields/concerns/use_resource.rb +5 -1
- data/lib/avo/fields/concerns/use_view_components.rb +45 -0
- data/lib/avo/fields/country_field.rb +4 -0
- data/lib/avo/fields/date_time_field.rb +1 -5
- data/lib/avo/fields/external_image_field.rb +2 -2
- data/lib/avo/fields/field_manager.rb +55 -0
- data/lib/avo/fields/file_field.rb +2 -2
- data/lib/avo/fields/gravatar_field.rb +2 -2
- data/lib/avo/fields/has_and_belongs_to_many_field.rb +1 -2
- data/lib/avo/fields/has_base_field.rb +21 -17
- data/lib/avo/fields/has_many_field.rb +5 -2
- data/lib/avo/fields/has_one_field.rb +8 -12
- data/lib/avo/fields/heading_field.rb +9 -14
- data/lib/avo/fields/hidden_field.rb +1 -1
- data/lib/avo/fields/id_field.rb +3 -3
- data/lib/avo/fields/location_field.rb +10 -10
- data/lib/avo/fields/password_field.rb +1 -1
- data/lib/avo/fields/preview_field.rb +14 -0
- data/lib/avo/fields/select_field.rb +12 -8
- data/lib/avo/fields/status_field.rb +7 -1
- data/lib/avo/fields/text_field.rb +2 -2
- data/lib/avo/filters/base_filter.rb +9 -4
- data/lib/avo/html/builder.rb +8 -8
- data/lib/avo/item_grapher.rb +78 -0
- data/lib/avo/licensing/h_q.rb +11 -73
- data/lib/avo/licensing/license.rb +5 -1
- data/lib/avo/licensing/license_manager.rb +1 -1
- data/lib/avo/licensing/pro_license.rb +1 -7
- data/lib/avo/loaders/fields_loader.rb +7 -1
- data/lib/avo/plugin.rb +36 -0
- data/lib/avo/plugin_manager.rb +56 -0
- data/lib/avo/prefixed_test_helpers.rb +20 -0
- data/lib/avo/reloader.rb +3 -0
- data/lib/avo/resources/controls/actions_list.rb +7 -12
- data/lib/avo/resources/controls/attach_button.rb +15 -0
- data/lib/avo/resources/controls/back_button.rb +1 -1
- data/lib/avo/resources/controls/base_control.rb +15 -49
- data/lib/avo/resources/controls/create_button.rb +15 -0
- data/lib/avo/resources/controls/delete_button.rb +5 -1
- data/lib/avo/resources/controls/detach_button.rb +4 -1
- data/lib/avo/resources/controls/edit_button.rb +4 -1
- data/lib/avo/resources/controls/order_controls.rb +8 -0
- data/lib/avo/resources/controls/save_button.rb +13 -0
- data/lib/avo/resources/controls/show_button.rb +15 -0
- data/lib/avo/resources/items/holder.rb +96 -0
- data/lib/avo/resources/items/item_group.rb +44 -0
- data/lib/avo/resources/items/main_panel.rb +12 -0
- data/lib/avo/resources/items/panel.rb +2 -0
- data/lib/avo/resources/items/row.rb +42 -0
- data/lib/avo/resources/items/sidebar.rb +46 -0
- data/lib/avo/resources/items/tab.rb +54 -0
- data/lib/avo/resources/items/tab_group.rb +62 -0
- data/lib/avo/resources/resource_manager.rb +179 -0
- data/lib/avo/services/authorization_service.rb +11 -110
- data/lib/avo/services/debug_service.rb +93 -0
- data/lib/avo/services/encryption_service.rb +8 -12
- data/lib/avo/services/telemetry_service.rb +85 -0
- data/lib/avo/test_helpers.rb +362 -0
- data/lib/avo/tools/tool_manager.rb +30 -0
- data/lib/avo/version.rb +1 -1
- data/lib/avo/view_inquirer.rb +36 -0
- data/lib/avo.rb +109 -24
- data/lib/generators/avo/action_generator.rb +8 -8
- data/lib/generators/avo/card_generator.rb +27 -0
- data/lib/generators/avo/concerns/parent_controller.rb +20 -0
- data/lib/generators/avo/controller_generator.rb +3 -0
- data/lib/generators/avo/eject_generator.rb +180 -15
- data/lib/generators/avo/field_generator.rb +49 -2
- data/lib/generators/avo/filter_generator.rb +8 -8
- data/lib/generators/avo/js/install_generator.rb +2 -2
- data/lib/generators/avo/resource_generator.rb +12 -9
- data/lib/generators/avo/scope_generator.rb +15 -0
- data/lib/generators/avo/tailwindcss/install_generator.rb +70 -26
- data/lib/generators/avo/templates/action.tt +8 -6
- data/lib/generators/avo/templates/cards/chartkick_card.tt +1 -1
- data/lib/generators/avo/templates/cards/chartkick_card_sample.tt +1 -1
- data/lib/generators/avo/templates/cards/metric_card.tt +1 -1
- data/lib/generators/avo/templates/cards/metric_card_sample.tt +1 -1
- data/lib/generators/avo/templates/cards/partial_card.tt +1 -1
- data/lib/generators/avo/templates/cards/partial_card_sample.tt +1 -1
- data/lib/generators/avo/templates/dashboards/dashboard.tt +5 -3
- data/lib/generators/avo/templates/field/%singular_name%_field.rb.tt +1 -1
- data/lib/generators/avo/templates/filters/boolean_filter.tt +1 -1
- data/lib/generators/avo/templates/filters/multiple_select_filter.tt +1 -1
- data/lib/generators/avo/templates/filters/select_filter.tt +1 -1
- data/lib/generators/avo/templates/filters/text_filter.tt +1 -1
- data/lib/generators/avo/templates/initializer/avo.tt +7 -3
- data/lib/generators/avo/templates/locales/avo.ar.yml +7 -6
- data/lib/generators/avo/templates/locales/avo.en.yml +6 -3
- data/lib/generators/avo/templates/locales/avo.es.yml +127 -0
- data/lib/generators/avo/templates/locales/avo.fr.yml +3 -0
- data/lib/generators/avo/templates/locales/avo.nb.yml +3 -0
- data/lib/generators/avo/templates/locales/avo.nn.yml +3 -0
- data/lib/generators/avo/templates/locales/avo.pt-BR.yml +3 -0
- data/lib/generators/avo/templates/locales/avo.pt.yml +3 -0
- data/lib/generators/avo/templates/locales/avo.ro.yml +8 -5
- data/lib/generators/avo/templates/locales/avo.tr.yml +3 -0
- data/lib/generators/avo/templates/resource/controller.tt +1 -1
- data/lib/generators/avo/templates/resource/resource.tt +7 -7
- data/lib/generators/avo/templates/resource_tools/partial.tt +2 -2
- data/lib/generators/avo/templates/resource_tools/resource_tool.tt +1 -1
- data/lib/generators/avo/templates/scope.tt +6 -0
- data/lib/generators/avo/templates/tailwindcss/Procfile.dev +1 -1
- data/lib/generators/avo/templates/tailwindcss/avo.tailwind.css +5 -3
- data/lib/generators/avo/templates/tailwindcss/tailwind.config.js +11 -0
- data/lib/tasks/avo_tasks.rake +72 -4
- data/public/avo-assets/avo.base.css +1893 -1187
- data/public/avo-assets/avo.base.js +223 -311
- data/public/avo-assets/avo.base.js.map +3 -3
- data/public/avo-assets/avo.css +9744 -0
- data/public/avo-assets/avo.js +513 -0
- data/public/avo-assets/avo.js.map +7 -0
- data/tailwind.custom.js +47 -0
- data/tailwind.preset.js +152 -0
- metadata +121 -116
- data/app/components/avo/card_component.html.erb +0 -46
- data/app/components/avo/card_component.rb +0 -25
- data/app/components/avo/dashboards/divider_component.html.erb +0 -9
- data/app/components/avo/dashboards/divider_component.rb +0 -19
- data/app/components/avo/fields/belongs_to_field/autocomplete_component.html.erb +0 -47
- data/app/components/avo/fields/belongs_to_field/autocomplete_component.rb +0 -95
- data/app/components/avo/fields/tags_field/edit_component.html.erb +0 -35
- data/app/components/avo/fields/tags_field/edit_component.rb +0 -4
- data/app/components/avo/fields/tags_field/index_component.html.erb +0 -10
- data/app/components/avo/fields/tags_field/index_component.rb +0 -9
- data/app/components/avo/fields/tags_field/show_component.html.erb +0 -7
- data/app/components/avo/fields/tags_field/show_component.rb +0 -5
- data/app/components/avo/fields/tags_field/tag_component.html.erb +0 -9
- data/app/components/avo/fields/tags_field/tag_component.rb +0 -11
- data/app/components/avo/index/ordering/base_component.rb +0 -9
- data/app/components/avo/index/ordering/button_component.html.erb +0 -11
- data/app/components/avo/index/ordering/button_component.rb +0 -23
- data/app/components/avo/index/ordering/buttons_component.html.erb +0 -32
- data/app/components/avo/index/ordering/buttons_component.rb +0 -47
- data/app/components/avo/item_switcher_component.html.erb +0 -27
- data/app/components/avo/item_switcher_component.rb +0 -48
- data/app/components/avo/sidebar/item_switcher_component.html.erb +0 -16
- data/app/components/avo/sidebar/item_switcher_component.rb +0 -15
- data/app/controllers/avo/dashboards/cards_controller.rb +0 -37
- data/app/controllers/avo/dashboards_controller.rb +0 -22
- data/app/controllers/avo/reorder_controller.rb +0 -25
- data/app/controllers/avo/team_users_controller.rb +0 -4
- data/app/javascript/js/controllers/base_controller.js +0 -22
- data/app/javascript/js/controllers/fields/tags_field_controller.js +0 -127
- data/app/javascript/js/controllers/toggle_panel_controller.js +0 -18
- data/app/views/avo/dashboards/cards/_chartkick_card.html.erb +0 -3
- data/app/views/avo/dashboards/cards/_metric_card.html.erb +0 -5
- data/app/views/avo/dashboards/cards/chartkick_missing.html.erb +0 -14
- data/app/views/avo/dashboards/cards/show.html.erb +0 -3
- data/app/views/avo/dashboards/show.html.erb +0 -38
- data/app/views/avo/partials/_global_search.html.erb +0 -19
- data/app/views/avo/sidebar/_license_warnings.html.erb +0 -6
- data/lib/avo/action_model.rb +0 -20
- data/lib/avo/app.rb +0 -237
- data/lib/avo/base_card.rb +0 -161
- data/lib/avo/concerns/fetches_things.rb +0 -150
- data/lib/avo/concerns/handles_field_args.rb +0 -47
- data/lib/avo/concerns/has_editable_controls.rb +0 -34
- data/lib/avo/concerns/has_fields.rb +0 -334
- data/lib/avo/concerns/has_html_attributes.rb +0 -108
- data/lib/avo/concerns/policy_helpers.rb +0 -31
- data/lib/avo/concerns/visible_in_dashboard.rb +0 -31
- data/lib/avo/dashboards/base_dashboard.rb +0 -89
- data/lib/avo/dashboards/base_divider.rb +0 -35
- data/lib/avo/dashboards/chartkick_card.rb +0 -77
- data/lib/avo/dashboards/dashboard_card.rb +0 -6
- data/lib/avo/dashboards/metric_card.rb +0 -9
- data/lib/avo/dashboards/partial_card.rb +0 -7
- data/lib/avo/fields/field_extensions/has_field_name.rb +0 -19
- data/lib/avo/fields/field_extensions/visible_in_different_views.rb +0 -111
- data/lib/avo/fields/tags_field.rb +0 -102
- data/lib/avo/grid_collector.rb +0 -42
- data/lib/avo/hosts/association_scope_host.rb +0 -8
- data/lib/avo/hosts/base_host.rb +0 -25
- data/lib/avo/hosts/card_visibility.rb +0 -20
- data/lib/avo/hosts/dashboard_card.rb +0 -22
- data/lib/avo/hosts/dashboard_visibility.rb +0 -19
- data/lib/avo/hosts/ordering.rb +0 -22
- data/lib/avo/hosts/record_host.rb +0 -7
- data/lib/avo/hosts/resource_record_host.rb +0 -7
- data/lib/avo/hosts/resource_view_record_host.rb +0 -7
- data/lib/avo/hosts/search_scope_host.rb +0 -7
- data/lib/avo/hosts/view_record_host.rb +0 -7
- data/lib/avo/hosts/visibility_host.rb +0 -12
- data/lib/avo/items_holder.rb +0 -96
- data/lib/avo/main_panel.rb +0 -3
- data/lib/avo/menu/base_item.rb +0 -25
- data/lib/avo/menu/builder.rb +0 -82
- data/lib/avo/menu/dashboard.rb +0 -22
- data/lib/avo/menu/group.rb +0 -2
- data/lib/avo/menu/link.rb +0 -6
- data/lib/avo/menu/menu.rb +0 -2
- data/lib/avo/menu/resource.rb +0 -22
- data/lib/avo/menu/section.rb +0 -2
- data/lib/avo/panel.rb +0 -24
- data/lib/avo/panel_builder.rb +0 -25
- data/lib/avo/resources/controls/action.rb +0 -38
- data/lib/avo/resources/controls/execution_context.rb +0 -58
- data/lib/avo/resources/controls/items_holder.rb +0 -19
- data/lib/avo/resources/controls/link_to.rb +0 -27
- data/lib/avo/row.rb +0 -26
- data/lib/avo/row_builder.rb +0 -24
- data/lib/avo/services/authorization_clients/nil_client.rb +0 -37
- data/lib/avo/services/authorization_clients/pundit_client.rb +0 -51
- data/lib/avo/sidebar.rb +0 -30
- data/lib/avo/sidebar_builder.rb +0 -24
- data/lib/avo/tab.rb +0 -72
- data/lib/avo/tab_builder.rb +0 -25
- data/lib/avo/tab_group.rb +0 -42
- data/lib/avo/tab_group_builder.rb +0 -43
- data/lib/avo/tools_manager.rb +0 -11
- data/lib/generators/avo/card/chartkick_generator.rb +0 -18
- data/lib/generators/avo/card/metric_generator.rb +0 -18
- data/lib/generators/avo/card/partial_generator.rb +0 -19
- data/lib/generators/avo/templates/js/avo.custom.js +0 -2
- data/lib/generators/avo/templates/standalone_action.tt +0 -8
- /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(
|
10
|
-
new(
|
5
|
+
def encrypt(...)
|
6
|
+
new(...).encrypt
|
11
7
|
end
|
12
8
|
|
13
|
-
def decrypt(
|
14
|
-
new(
|
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
@@ -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
|