avo 2.13.5.pre.2 → 2.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of avo might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -3
- data/README.md +7 -11
- data/app/components/avo/base_component.rb +3 -2
- data/app/components/avo/button_component.rb +1 -1
- data/app/components/avo/fields/common/progress_bar_component.html.erb +8 -0
- data/app/components/avo/fields/common/progress_bar_component.rb +15 -0
- data/app/components/avo/fields/common/single_file_viewer_component.html.erb +1 -1
- data/app/components/avo/fields/common/single_file_viewer_component.rb +12 -0
- data/app/components/avo/fields/progress_bar_field/index_component.html.erb +1 -6
- data/app/components/avo/fields/progress_bar_field/show_component.html.erb +1 -6
- data/app/components/avo/filters_component.html.erb +1 -1
- data/app/components/avo/filters_component.rb +11 -1
- data/app/components/avo/index/resource_table_component.html.erb +37 -2
- data/app/components/avo/index/resource_table_component.rb +15 -1
- data/app/components/avo/item_switcher_component.rb +1 -1
- data/app/components/avo/resource_component.rb +2 -3
- data/app/components/avo/tab_group_component.html.erb +4 -4
- data/app/components/avo/tab_group_component.rb +7 -1
- data/app/components/avo/tab_switcher_component.html.erb +28 -8
- data/app/components/avo/tab_switcher_component.rb +3 -1
- data/app/components/avo/views/resource_edit_component.rb +2 -0
- data/app/components/avo/views/resource_index_component.html.erb +3 -6
- data/app/components/avo/views/resource_index_component.rb +3 -2
- data/app/controllers/avo/actions_controller.rb +17 -4
- data/app/helpers/avo/resources_helper.rb +1 -1
- data/app/javascript/js/controllers/action_controller.js +11 -2
- data/app/javascript/js/controllers/fields/date_field_controller.js +5 -1
- data/app/javascript/js/controllers/item_select_all_controller.js +42 -4
- data/app/javascript/js/controllers/tabs_controller.js +13 -9
- data/app/views/avo/actions/show.html.erb +2 -1
- data/app/views/avo/base/index.html.erb +1 -0
- data/app/views/avo/partials/_table_header.html.erb +1 -1
- data/app/views/avo/partials/_view_toggle_button.html.erb +2 -2
- data/lib/avo/base_resource.rb +1 -5
- data/lib/avo/concerns/fetches_things.rb +2 -13
- data/lib/avo/concerns/has_fields.rb +2 -2
- data/lib/avo/configuration.rb +2 -2
- data/lib/avo/fields/base_field.rb +1 -1
- data/lib/avo/fields/concerns/is_required.rb +15 -1
- data/lib/avo/services/encryption_service.rb +33 -0
- data/lib/avo/tab_group.rb +3 -1
- data/lib/avo/tab_group_builder.rb +4 -4
- data/lib/avo/version.rb +1 -1
- data/lib/generators/avo/templates/initializer/avo.tt +9 -10
- data/lib/generators/avo/templates/locales/avo.en.yml +5 -1
- data/lib/generators/avo/templates/locales/avo.fr.yml +4 -0
- data/lib/generators/avo/templates/locales/avo.nb-NO.yml +5 -0
- data/lib/generators/avo/templates/locales/avo.pt-BR.yml +5 -0
- data/lib/generators/avo/templates/locales/avo.ro.yml +6 -0
- data/public/avo-assets/avo.css +44 -4
- data/public/avo-assets/avo.js +64 -64
- data/public/avo-assets/avo.js.map +2 -2
- metadata +7 -6
- data/app/controllers/avo/team_users_controller.rb +0 -4
- data/app/views/avo/partials/_tabs_toggle.html.erb +0 -20
| @@ -1,21 +1,59 @@ | |
| 1 1 | 
             
            import { Controller } from '@hotwired/stimulus'
         | 
| 2 2 |  | 
| 3 3 | 
             
            export default class extends Controller {
         | 
| 4 | 
            -
              static targets = ['itemCheckbox', 'checkbox']
         | 
| 4 | 
            +
              static targets = ['itemCheckbox', 'checkbox', 'selectAllOvelay', 'unselectedMessage', 'selectedMessage']
         | 
| 5 | 
            +
             | 
| 6 | 
            +
              static values = {
         | 
| 7 | 
            +
                selectedAll: Boolean,
         | 
| 8 | 
            +
                selectedAllQuery: String,
         | 
| 9 | 
            +
              }
         | 
| 5 10 |  | 
| 6 11 | 
             
              connect() {
         | 
| 7 12 | 
             
                this.resourceName = this.element.dataset.resourceName
         | 
| 8 13 | 
             
              }
         | 
| 9 14 |  | 
| 10 15 | 
             
              toggle(event) {
         | 
| 11 | 
            -
                const  | 
| 16 | 
            +
                const checked = !!event.target.checked
         | 
| 12 17 | 
             
                document.querySelectorAll(`[data-controller="item-selector"][data-resource-name="${this.resourceName}"] input[type=checkbox]`)
         | 
| 13 | 
            -
                  .forEach((checkbox) => checkbox.checked  | 
| 18 | 
            +
                  .forEach((checkbox) => checkbox.checked !== checked && checkbox.click())
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                this.selectAllOverlay(checked)
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                // When de-selecting everything, ensure the selectAll toggle is false and hide overlay.
         | 
| 23 | 
            +
                if (!checked) {
         | 
| 24 | 
            +
                  this.resetUnselected()
         | 
| 25 | 
            +
                }
         | 
| 14 26 | 
             
              }
         | 
| 15 27 |  | 
| 16 | 
            -
               | 
| 28 | 
            +
              selectRow() {
         | 
| 17 29 | 
             
                let allSelected = true
         | 
| 30 | 
            +
                // eslint-disable-next-line no-return-assign
         | 
| 18 31 | 
             
                this.itemCheckboxTargets.forEach((checkbox) => allSelected = allSelected && checkbox.checked)
         | 
| 19 32 | 
             
                this.checkboxTarget.checked = allSelected
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                this.selectAllOverlay(allSelected)
         | 
| 35 | 
            +
                this.resetUnselected()
         | 
| 36 | 
            +
              }
         | 
| 37 | 
            +
             | 
| 38 | 
            +
              selectAll(event) {
         | 
| 39 | 
            +
                event.preventDefault()
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                this.selectedAllValue = !this.selectedAllValue
         | 
| 42 | 
            +
                this.unselectedMessageTarget.classList.toggle('hidden')
         | 
| 43 | 
            +
                this.selectedMessageTarget.classList.toggle('hidden')
         | 
| 44 | 
            +
              }
         | 
| 45 | 
            +
             | 
| 46 | 
            +
              resetUnselected() {
         | 
| 47 | 
            +
                this.selectedAllValue = false
         | 
| 48 | 
            +
                this.unselectedMessageTarget.classList.remove('hidden')
         | 
| 49 | 
            +
                this.selectedMessageTarget.classList.add('hidden')
         | 
| 50 | 
            +
              }
         | 
| 51 | 
            +
             | 
| 52 | 
            +
              selectAllOverlay(show) {
         | 
| 53 | 
            +
                if (show) {
         | 
| 54 | 
            +
                  this.selectAllOvelayTarget.classList.remove('hidden')
         | 
| 55 | 
            +
                } else {
         | 
| 56 | 
            +
                  this.selectAllOvelayTarget.classList.add('hidden')
         | 
| 57 | 
            +
                }
         | 
| 20 58 | 
             
              }
         | 
| 21 59 | 
             
            }
         | 
| @@ -3,7 +3,7 @@ import { Controller } from '@hotwired/stimulus' | |
| 3 3 | 
             
            import { castBoolean } from '../helpers/cast_boolean'
         | 
| 4 4 |  | 
| 5 5 | 
             
            export default class extends Controller {
         | 
| 6 | 
            -
              static targets = [' | 
| 6 | 
            +
              static targets = ['tabPanel'];
         | 
| 7 7 |  | 
| 8 8 | 
             
              static values = {
         | 
| 9 9 | 
             
                view: String,
         | 
| @@ -11,13 +11,17 @@ export default class extends Controller { | |
| 11 11 | 
             
              };
         | 
| 12 12 |  | 
| 13 13 | 
             
              get currentTab() {
         | 
| 14 | 
            -
                return this. | 
| 14 | 
            +
                return this.tabPanelTargets.find(
         | 
| 15 15 | 
             
                  (element) => element.dataset.tabId === this.activeTabValue,
         | 
| 16 16 | 
             
                )
         | 
| 17 17 | 
             
              }
         | 
| 18 18 |  | 
| 19 19 | 
             
              targetTab(id) {
         | 
| 20 | 
            -
                return this.tabTargets.find((element) => element.dataset. | 
| 20 | 
            +
                return this.tabTargets.find((element) => element.dataset.tabsIdParam === id)
         | 
| 21 | 
            +
              }
         | 
| 22 | 
            +
             | 
| 23 | 
            +
              targetTabPanel(id) {
         | 
| 24 | 
            +
                return this.tabPanelTargets.find((element) => element.dataset.tabId === id)
         | 
| 21 25 | 
             
              }
         | 
| 22 26 |  | 
| 23 27 | 
             
              changeTab(e) {
         | 
| @@ -46,17 +50,17 @@ export default class extends Controller { | |
| 46 50 | 
             
                }
         | 
| 47 51 |  | 
| 48 52 | 
             
                // We don't need to add a height to this panel because it was loaded before
         | 
| 49 | 
            -
                if (castBoolean(this. | 
| 53 | 
            +
                if (castBoolean(this.targetTabPanel(id).dataset.loaded)) {
         | 
| 50 54 | 
             
                  return
         | 
| 51 55 | 
             
                }
         | 
| 52 56 |  | 
| 53 57 | 
             
                // Get the height of the active panel
         | 
| 54 58 | 
             
                const { height } = this.currentTab.getBoundingClientRect()
         | 
| 55 59 | 
             
                // Set it to the target panel
         | 
| 56 | 
            -
                this. | 
| 60 | 
            +
                this.targetTabPanel(id).style.height = `${height}px`
         | 
| 57 61 |  | 
| 58 62 | 
             
                // Wait until the panel loaded it's content and then remove the forced height
         | 
| 59 | 
            -
                const observer = new AttributeObserver(this. | 
| 63 | 
            +
                const observer = new AttributeObserver(this.targetTabPanel(id), 'busy', {
         | 
| 60 64 | 
             
                  elementUnmatchedAttribute: () => {
         | 
| 61 65 | 
             
                    // The content is not available in an instant so delay the height reset a bit.
         | 
| 62 66 | 
             
                    setTimeout(() => {
         | 
| @@ -69,11 +73,11 @@ export default class extends Controller { | |
| 69 73 | 
             
              }
         | 
| 70 74 |  | 
| 71 75 | 
             
              markTabLoaded(id) {
         | 
| 72 | 
            -
                this. | 
| 76 | 
            +
                this.targetTabPanel(id).dataset.loaded = true
         | 
| 73 77 | 
             
              }
         | 
| 74 78 |  | 
| 75 79 | 
             
              showTab(id) {
         | 
| 76 | 
            -
                this. | 
| 80 | 
            +
                this.tabPanelTargets.forEach((element) => {
         | 
| 77 81 | 
             
                  if (element.dataset.tabId === id) {
         | 
| 78 82 | 
             
                    element.classList.remove('hidden')
         | 
| 79 83 | 
             
                  }
         | 
| @@ -81,6 +85,6 @@ export default class extends Controller { | |
| 81 85 | 
             
              }
         | 
| 82 86 |  | 
| 83 87 | 
             
              hideTabs() {
         | 
| 84 | 
            -
                this. | 
| 88 | 
            +
                this.tabPanelTargets.map((element) => element.classList.add('hidden'))
         | 
| 85 89 | 
             
              }
         | 
| 86 90 | 
             
            }
         | 
| @@ -20,7 +20,8 @@ | |
| 20 20 | 
             
                  <div class="flex-1 flex">
         | 
| 21 21 | 
             
                    <%= @action.message %>
         | 
| 22 22 | 
             
                  </div>
         | 
| 23 | 
            -
                  <%= form.hidden_field : | 
| 23 | 
            +
                  <%= form.hidden_field :avo_resource_ids, value: params[:resource_ids], 'data-action-target': 'resourceIds' %>
         | 
| 24 | 
            +
                  <%= form.hidden_field :avo_selected_query, 'data-action-target': 'selectedAllQuery' %>
         | 
| 24 25 | 
             
                  <% if @action.get_fields.present? %>
         | 
| 25 26 | 
             
                    <div class="mt-4">
         | 
| 26 27 | 
             
                      <% @action.get_fields.each_with_index do |field, index| %>
         | 
| @@ -44,7 +44,7 @@ | |
| 44 44 | 
             
                      ""
         | 
| 45 45 | 
             
                    end
         | 
| 46 46 | 
             
                %>
         | 
| 47 | 
            -
                <th class="text-left uppercase px-3 py- | 
| 47 | 
            +
                <th class="text-left uppercase px-3 py-3 whitespace-nowrap rounded-l" data-control="resource-field-th">
         | 
| 48 48 | 
             
                  <% if field.sortable %>
         | 
| 49 49 | 
             
                    <%= link_to params.permit!.merge(sort_by: sort_by, sort_direction: sort_direction), class: "flex items-center #{classes} #{'cursor-pointer' if field.sortable}", 'data-turbo-frame': params[:turbo_frame] do %>
         | 
| 50 50 | 
             
                      <%= field.name %>
         | 
| @@ -20,10 +20,10 @@ | |
| 20 20 |  | 
| 21 21 | 
             
                    <%= a_link url_for(params.permit!.merge(view_type: type)).to_s,
         | 
| 22 22 | 
             
                      icon: info[type][:new_icon],
         | 
| 23 | 
            -
                      color: is_active_view ? : | 
| 23 | 
            +
                      color: is_active_view ? :primary : :gray,
         | 
| 24 24 | 
             
                      rounded: false,
         | 
| 25 25 | 
             
                      size: :sm,
         | 
| 26 | 
            -
                      class: is_active_view ?  | 
| 26 | 
            +
                      class: is_active_view ? "z-20" : "bg-gray-100 border-gray-300",
         | 
| 27 27 | 
             
                      title: t('avo.switch_to_view', view_type: type),
         | 
| 28 28 | 
             
                      data: {
         | 
| 29 29 | 
             
                        tippy: 'tooltip',
         | 
    
        data/lib/avo/base_resource.rb
    CHANGED
    
    | @@ -20,6 +20,7 @@ module Avo | |
| 20 20 | 
             
                delegate :context, to: ::Avo::App
         | 
| 21 21 |  | 
| 22 22 | 
             
                attr_accessor :view
         | 
| 23 | 
            +
                attr_accessor :model
         | 
| 23 24 | 
             
                attr_accessor :reflection
         | 
| 24 25 | 
             
                attr_accessor :user
         | 
| 25 26 | 
             
                attr_accessor :params
         | 
| @@ -110,11 +111,6 @@ module Avo | |
| 110 111 | 
             
                  end
         | 
| 111 112 | 
             
                end
         | 
| 112 113 |  | 
| 113 | 
            -
                def record
         | 
| 114 | 
            -
                  @model
         | 
| 115 | 
            -
                end
         | 
| 116 | 
            -
                alias :model :record
         | 
| 117 | 
            -
             | 
| 118 114 | 
             
                def hydrate(model: nil, view: nil, user: nil, params: nil)
         | 
| 119 115 | 
             
                  @view = view if view.present?
         | 
| 120 116 | 
             
                  @user = user if user.present?
         | 
| @@ -51,15 +51,10 @@ module Avo | |
| 51 51 | 
             
                    #
         | 
| 52 52 | 
             
                    # get_resource_by_name('User') => UserResource
         | 
| 53 53 | 
             
                    # get_resource_by_name(User) => UserResource
         | 
| 54 | 
            -
                    def get_resource_by_model_name( | 
| 55 | 
            -
                      # Fetch the mappings imposed by the user.
         | 
| 56 | 
            -
                      # If they are present, use those ones.
         | 
| 57 | 
            -
                      mapping = get_mapping_for_model klass
         | 
| 58 | 
            -
                      return get_resource(mapping) if mapping.present?
         | 
| 59 | 
            -
             | 
| 54 | 
            +
                    def get_resource_by_model_name(name)
         | 
| 60 55 | 
             
                      valid_resources
         | 
| 61 56 | 
             
                        .find do |resource|
         | 
| 62 | 
            -
                          resource.model_class.model_name.name ==  | 
| 57 | 
            +
                          resource.model_class.model_name.name == name.to_s
         | 
| 63 58 | 
             
                        end
         | 
| 64 59 | 
             
                    end
         | 
| 65 60 |  | 
| @@ -133,12 +128,6 @@ module Avo | |
| 133 128 |  | 
| 134 129 | 
             
                      get_sidebar_partials
         | 
| 135 130 | 
             
                    end
         | 
| 136 | 
            -
             | 
| 137 | 
            -
                    private
         | 
| 138 | 
            -
             | 
| 139 | 
            -
                    def get_mapping_for_model(klass)
         | 
| 140 | 
            -
                      (Avo.configuration.model_resource_mapping || {}).stringify_keys.transform_values(&:to_s)[klass.to_s]
         | 
| 141 | 
            -
                    end
         | 
| 142 131 | 
             
                  end
         | 
| 143 132 | 
             
                end
         | 
| 144 133 | 
             
              end
         | 
| @@ -26,10 +26,10 @@ module Avo | |
| 26 26 | 
             
                      items_holder.panel name, **args, &block
         | 
| 27 27 | 
             
                    end
         | 
| 28 28 |  | 
| 29 | 
            -
                    def tabs(&block)
         | 
| 29 | 
            +
                    def tabs(**args, &block)
         | 
| 30 30 | 
             
                      ensure_items_holder_initialized
         | 
| 31 31 |  | 
| 32 | 
            -
                      items_holder.tabs Avo::TabGroupBuilder.parse_block(&block)
         | 
| 32 | 
            +
                      items_holder.tabs Avo::TabGroupBuilder.parse_block(**args, &block)
         | 
| 33 33 | 
             
                    end
         | 
| 34 34 |  | 
| 35 35 | 
             
                    def tool(klass, **args)
         | 
    
        data/lib/avo/configuration.rb
    CHANGED
    
    | @@ -34,7 +34,7 @@ module Avo | |
| 34 34 | 
             
                attr_accessor :buttons_on_form_footers
         | 
| 35 35 | 
             
                attr_accessor :main_menu
         | 
| 36 36 | 
             
                attr_accessor :profile_menu
         | 
| 37 | 
            -
                attr_accessor : | 
| 37 | 
            +
                attr_accessor :tabs_style
         | 
| 38 38 |  | 
| 39 39 | 
             
                def initialize
         | 
| 40 40 | 
             
                  @root_path = "/avo"
         | 
| @@ -79,7 +79,7 @@ module Avo | |
| 79 79 | 
             
                  @buttons_on_form_footers = false
         | 
| 80 80 | 
             
                  @main_menu = nil
         | 
| 81 81 | 
             
                  @profile_menu = nil
         | 
| 82 | 
            -
                  @ | 
| 82 | 
            +
                  @tabs_style = :tabs
         | 
| 83 83 | 
             
                end
         | 
| 84 84 |  | 
| 85 85 | 
             
                def current_user_method(&block)
         | 
| @@ -61,7 +61,7 @@ module Avo | |
| 61 61 | 
             
                    @name = args[:name]
         | 
| 62 62 | 
             
                    @translation_key = args[:translation_key]
         | 
| 63 63 | 
             
                    @block = block
         | 
| 64 | 
            -
                    @required = args | 
| 64 | 
            +
                    @required = args.dig(:required) # Value if :required present on args, nil otherwise
         | 
| 65 65 | 
             
                    @readonly = args[:readonly] || false
         | 
| 66 66 | 
             
                    @sortable = args[:sortable] || false
         | 
| 67 67 | 
             
                    @nullable = args[:nullable] || false
         | 
| @@ -8,9 +8,23 @@ module Avo | |
| 8 8 | 
             
                      if required.respond_to? :call
         | 
| 9 9 | 
             
                        Avo::Hosts::ViewRecordHost.new(block: required, record: model, view: view).handle
         | 
| 10 10 | 
             
                      else
         | 
| 11 | 
            -
                        required
         | 
| 11 | 
            +
                        required.nil? ? required_from_validators : required
         | 
| 12 12 | 
             
                      end
         | 
| 13 13 | 
             
                    end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                    private
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                    def required_from_validators
         | 
| 18 | 
            +
                      return false if model.nil?
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                      validators.any? do |validator|
         | 
| 21 | 
            +
                        validator.kind_of? ActiveModel::Validations::PresenceValidator
         | 
| 22 | 
            +
                      end
         | 
| 23 | 
            +
                    end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                    def validators
         | 
| 26 | 
            +
                      model.class.validators_on(id)
         | 
| 27 | 
            +
                    end
         | 
| 14 28 | 
             
                  end
         | 
| 15 29 | 
             
                end
         | 
| 16 30 | 
             
              end
         | 
| @@ -0,0 +1,33 @@ | |
| 1 | 
            +
            module Avo
         | 
| 2 | 
            +
              module Services
         | 
| 3 | 
            +
                class EncryptionService
         | 
| 4 | 
            +
                  attr_reader :message
         | 
| 5 | 
            +
                  attr_reader :purpose
         | 
| 6 | 
            +
                  attr_reader :crypt
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                  class << self
         | 
| 9 | 
            +
                    def encrypt(message:, purpose:)
         | 
| 10 | 
            +
                      new(message: message, purpose: purpose).encrypt
         | 
| 11 | 
            +
                    end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                    def decrypt(message:, purpose:)
         | 
| 14 | 
            +
                      new(message: message, purpose: purpose).decrypt
         | 
| 15 | 
            +
                    end
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                  def initialize(message:, purpose:)
         | 
| 19 | 
            +
                    @message = message
         | 
| 20 | 
            +
                    @purpose = purpose
         | 
| 21 | 
            +
                    @crypt = ActiveSupport::MessageEncryptor.new(Rails.application.secrets.secret_key_base[0..31])
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  def encrypt
         | 
| 25 | 
            +
                    crypt.encrypt_and_sign(message, purpose: purpose)
         | 
| 26 | 
            +
                  end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                  def decrypt
         | 
| 29 | 
            +
                    crypt.decrypt_and_verify(message, purpose: purpose)
         | 
| 30 | 
            +
                  end
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
              end
         | 
| 33 | 
            +
            end
         | 
    
        data/lib/avo/tab_group.rb
    CHANGED
    
    | @@ -7,11 +7,13 @@ class Avo::TabGroup | |
| 7 7 | 
             
              attr_reader :view
         | 
| 8 8 | 
             
              attr_accessor :index
         | 
| 9 9 | 
             
              attr_accessor :items_holder
         | 
| 10 | 
            +
              attr_accessor :style
         | 
| 10 11 |  | 
| 11 | 
            -
              def initialize(index: 0, view: nil)
         | 
| 12 | 
            +
              def initialize(index: 0, view: nil, style: nil)
         | 
| 12 13 | 
             
                @index = index
         | 
| 13 14 | 
             
                @items_holder = Avo::ItemsHolder.new
         | 
| 14 15 | 
             
                @view = view
         | 
| 16 | 
            +
                @style = style
         | 
| 15 17 | 
             
              end
         | 
| 16 18 |  | 
| 17 19 | 
             
              def hydrate(view: nil)
         | 
| @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            class Avo::TabGroupBuilder
         | 
| 2 2 | 
             
              class << self
         | 
| 3 | 
            -
                def parse_block(&block)
         | 
| 4 | 
            -
                  Docile.dsl_eval(new, &block).build
         | 
| 3 | 
            +
                def parse_block(**args, &block)
         | 
| 4 | 
            +
                  Docile.dsl_eval(new(**args), &block).build
         | 
| 5 5 | 
             
                end
         | 
| 6 6 | 
             
              end
         | 
| 7 7 |  | 
| @@ -9,8 +9,8 @@ class Avo::TabGroupBuilder | |
| 9 9 |  | 
| 10 10 | 
             
              delegate :tab, to: :items_holder
         | 
| 11 11 |  | 
| 12 | 
            -
              def initialize
         | 
| 13 | 
            -
                @group = Avo::TabGroup.new
         | 
| 12 | 
            +
              def initialize(style: nil)
         | 
| 13 | 
            +
                @group = Avo::TabGroup.new(style: style)
         | 
| 14 14 | 
             
                @items_holder = Avo::ItemsHolder.new
         | 
| 15 15 | 
             
              end
         | 
| 16 16 |  | 
    
        data/lib/avo/version.rb
    CHANGED
    
    
| @@ -34,27 +34,26 @@ Avo.configure do |config| | |
| 34 34 | 
             
              ## == Localization ==
         | 
| 35 35 | 
             
              # config.locale = 'en-US'
         | 
| 36 36 |  | 
| 37 | 
            -
              ## == Resource options ==
         | 
| 38 | 
            -
              # config.resource_controls = :right
         | 
| 39 | 
            -
              # config.model_resource_mapping = {}
         | 
| 40 | 
            -
              # config.default_view_type = :table
         | 
| 41 | 
            -
              # config.per_page = 24
         | 
| 42 | 
            -
              # config.per_page_steps = [12, 24, 48, 72]
         | 
| 43 | 
            -
              # config.via_per_page = 8
         | 
| 44 | 
            -
              # config.id_links_to_resource = false
         | 
| 45 | 
            -
              # config.cache_resources_on_index_view = true
         | 
| 46 | 
            -
             | 
| 47 37 | 
             
              ## == Customization ==
         | 
| 48 38 | 
             
              # config.app_name = 'Avocadelicious'
         | 
| 49 39 | 
             
              # config.timezone = 'UTC'
         | 
| 50 40 | 
             
              # config.currency = 'USD'
         | 
| 41 | 
            +
              # config.per_page = 24
         | 
| 42 | 
            +
              # config.per_page_steps = [12, 24, 48, 72]
         | 
| 43 | 
            +
              # config.via_per_page = 8
         | 
| 44 | 
            +
              # config.default_view_type = :table
         | 
| 51 45 | 
             
              # config.hide_layout_when_printing = false
         | 
| 46 | 
            +
              # config.id_links_to_resource = false
         | 
| 52 47 | 
             
              # config.full_width_container = false
         | 
| 53 48 | 
             
              # config.full_width_index_view = false
         | 
| 49 | 
            +
              # config.cache_resources_on_index_view = true
         | 
| 54 50 | 
             
              # config.search_debounce = 300
         | 
| 55 51 | 
             
              # config.view_component_path = "app/components"
         | 
| 56 52 | 
             
              # config.display_license_request_timeout_error = true
         | 
| 57 53 | 
             
              # config.disabled_features = []
         | 
| 54 | 
            +
              # config.resource_controls = :right
         | 
| 55 | 
            +
              # config.tabs_style = :tabs # can be :tabs or :pills
         | 
| 56 | 
            +
             | 
| 58 57 |  | 
| 59 58 | 
             
              ## == Breadcrumbs ==
         | 
| 60 59 | 
             
              # config.display_breadcrumbs = true
         | 
| @@ -23,7 +23,9 @@ en: | |
| 23 23 | 
             
                you_missed_something_check_form: 'You might have missed something. Please check the form.'
         | 
| 24 24 | 
             
                remove_selection: 'Remove selection'
         | 
| 25 25 | 
             
                select_item: 'Select item'
         | 
| 26 | 
            -
                select_all: 'Select all | 
| 26 | 
            +
                select_all: 'Select all'
         | 
| 27 | 
            +
                select_all_matching: 'Select all matching'
         | 
| 28 | 
            +
                undo: undo
         | 
| 27 29 | 
             
                delete_file: 'Delete file'
         | 
| 28 30 | 
             
                delete: 'delete'
         | 
| 29 31 | 
             
                delete_item: 'Delete %{item}'
         | 
| @@ -113,3 +115,5 @@ en: | |
| 113 115 | 
             
                empty_dashboard_message: Add cards to this dashboard
         | 
| 114 116 | 
             
                no_cards_present: No cards present
         | 
| 115 117 | 
             
                no_options_available: No options available
         | 
| 118 | 
            +
                x_records_selected_from_a_total_of_x_html: <span class="font-bold text-gray-700">%{selected}</span> records selected on this page from a total of <span class="font-bold text-gray-700">%{count}</span>
         | 
| 119 | 
            +
                x_records_selected_from_all_pages_html: <span class="font-bold text-gray-700">%{count}</span> records selected from all pages
         | 
| @@ -24,6 +24,8 @@ fr: | |
| 24 24 | 
             
                remove_selection: 'Supprimer la sélection'
         | 
| 25 25 | 
             
                select_item: 'Sélectionnez un élément'
         | 
| 26 26 | 
             
                select_all: 'Sélectionner tout sur la page'
         | 
| 27 | 
            +
                select_all_matching: 'Sélectionner toutes les correspondances'
         | 
| 28 | 
            +
                undo: annuler
         | 
| 27 29 | 
             
                delete_file: 'Supprimer le fichier'
         | 
| 28 30 | 
             
                delete: 'supprimer'
         | 
| 29 31 | 
             
                delete_item: 'Supprimer %{item}'
         | 
| @@ -113,3 +115,5 @@ fr: | |
| 113 115 | 
             
                empty_dashboard_message: Ajouter des cartes à ce tableau de bord
         | 
| 114 116 | 
             
                no_cards_present: Aucune carte présente
         | 
| 115 117 | 
             
                no_options_available: Aucune option disponible
         | 
| 118 | 
            +
                x_records_selected_from_a_total_of_x_html: <span class="font-bold text-gray-700">%{selected}</span> enregistrements sélectionnés sur cette page sur un total de <span class="font-bold text-gray-700">%{count}</span>
         | 
| 119 | 
            +
                x_records_selected_from_all_pages_html: <span class="font-bold text-gray-700">%{count}</span> enregistrements sélectionnés dans toutes les pages
         | 
| @@ -23,6 +23,9 @@ nb-NO: | |
| 23 23 | 
             
                you_missed_something_check_form: 'Her mangler du noe. Vennligst sjekk skjemaet.'
         | 
| 24 24 | 
             
                remove_selection: 'Fjern valg'
         | 
| 25 25 | 
             
                select_item: 'Velg'
         | 
| 26 | 
            +
                select_all: 'Velg alle'
         | 
| 27 | 
            +
                select_all_matching: 'Velg alle samsvarende'
         | 
| 28 | 
            +
                undo: angre
         | 
| 26 29 | 
             
                delete_file: 'Slett fil'
         | 
| 27 30 | 
             
                delete: 'slett'
         | 
| 28 31 | 
             
                delete_item: 'Slett %{item}'
         | 
| @@ -85,4 +88,6 @@ nb-NO: | |
| 85 88 | 
             
                empty_dashboard_message: Legg til kort i dette dashbordet
         | 
| 86 89 | 
             
                no_cards_present: Ingen kort til stede
         | 
| 87 90 | 
             
                no_options_available: Ingen tilgjengelige alternativer
         | 
| 91 | 
            +
                x_records_selected_from_a_total_of_x_html: <span class="font-bold text-gray-700">%{selected}</span> poster valgt på denne siden fra totalt <span class="font-bold text-gray-700">%{count}</span>
         | 
| 92 | 
            +
                x_records_selected_from_all_pages_html: <span class="font-bold text-gray-700">%{count}</span> poster valgt fra alle sider
         | 
| 88 93 |  | 
| @@ -23,6 +23,9 @@ pt-BR: | |
| 23 23 | 
             
                you_missed_something_check_form: 'Você pode ter esquecido algo. Por favor, cheque o formulário.'
         | 
| 24 24 | 
             
                remove_selection: 'Remover seleção'
         | 
| 25 25 | 
             
                select_item: 'Selecionar item'
         | 
| 26 | 
            +
                select_all: 'Selecionar tudo'
         | 
| 27 | 
            +
                select_all_matching: 'Selecione todas as correspondências'
         | 
| 28 | 
            +
                undo: desfazer
         | 
| 26 29 | 
             
                delete_file: 'Deletar arquivo'
         | 
| 27 30 | 
             
                delete: 'deletar'
         | 
| 28 31 | 
             
                delete_item: 'Deletar %{item}'
         | 
| @@ -87,3 +90,5 @@ pt-BR: | |
| 87 90 | 
             
                empty_dashboard_message: Adicionar cartões a este painel
         | 
| 88 91 | 
             
                no_cards_present: Nenhum cartão presente
         | 
| 89 92 | 
             
                no_options_available: Nenhuma opção disponível
         | 
| 93 | 
            +
                x_records_selected_from_a_total_of_x_html: <span class="font-bold text-gray-700">%{selected}</span> registros selecionados nesta página de um total de <span class="font-bold text-gray-700">%{count}</span>
         | 
| 94 | 
            +
                x_records_selected_from_all_pages_html: <span class="font-bold text-gray-700">%{count}</span> registros selecionados de todas as páginas
         | 
| @@ -16,6 +16,10 @@ ro: | |
| 16 16 | 
             
                resource_created: 'Resursa creata'
         | 
| 17 17 | 
             
                resource_destroyed: 'Resursa stearsa'
         | 
| 18 18 | 
             
                remove_selection: 'Sterge selectia'
         | 
| 19 | 
            +
                select_item: 'Selecteaza record'
         | 
| 20 | 
            +
                select_all: 'Selecteaza totul'
         | 
| 21 | 
            +
                select_all_matching: 'Selecteaza toate care se potrivesc'
         | 
| 22 | 
            +
                undo: Anuleaza
         | 
| 19 23 | 
             
                delete_file: 'Sterge fisierul'
         | 
| 20 24 | 
             
                delete: 'sterge'
         | 
| 21 25 | 
             
                delete_item: 'Sterge %{item}'
         | 
| @@ -83,3 +87,5 @@ ro: | |
| 83 87 | 
             
                empty_dashboard_message: Adauga carduri in acest dashboard
         | 
| 84 88 | 
             
                no_cards_present: Niciun card disponibil
         | 
| 85 89 | 
             
                no_options_available: Nicio optiune disponibila
         | 
| 90 | 
            +
                x_records_selected_from_a_total_of_x_html: <span class="font-bold text-gray-700">%{selected}</span> selectate dintr-un total de <span class="font-bold text-gray-700">%{count}</span>
         | 
| 91 | 
            +
                x_records_selected_from_all_pages_html: <span class="font-bold text-gray-700">%{count}</span> selectate din toate paginile
         | 
    
        data/public/avo-assets/avo.css
    CHANGED
    
    | @@ -6315,6 +6315,10 @@ trix-editor .attachment__metadata .attachment__size { | |
| 6315 6315 | 
             
              top:-1px
         | 
| 6316 6316 | 
             
            }
         | 
| 6317 6317 |  | 
| 6318 | 
            +
            .-top-\[0\.1rem\]{
         | 
| 6319 | 
            +
              top:-0.1rem
         | 
| 6320 | 
            +
            }
         | 
| 6321 | 
            +
             | 
| 6318 6322 | 
             
            .right-3{
         | 
| 6319 6323 | 
             
              right:0.75rem
         | 
| 6320 6324 | 
             
            }
         | 
| @@ -6527,6 +6531,26 @@ trix-editor .attachment__metadata .attachment__size { | |
| 6527 6531 | 
             
              margin-left:50%
         | 
| 6528 6532 | 
             
            }
         | 
| 6529 6533 |  | 
| 6534 | 
            +
            .ml-10{
         | 
| 6535 | 
            +
              margin-left:2.5rem
         | 
| 6536 | 
            +
            }
         | 
| 6537 | 
            +
             | 
| 6538 | 
            +
            .mt-0\.5{
         | 
| 6539 | 
            +
              margin-top:0.125rem
         | 
| 6540 | 
            +
            }
         | 
| 6541 | 
            +
             | 
| 6542 | 
            +
            .mt-0{
         | 
| 6543 | 
            +
              margin-top:0px
         | 
| 6544 | 
            +
            }
         | 
| 6545 | 
            +
             | 
| 6546 | 
            +
            .mt-1\.5{
         | 
| 6547 | 
            +
              margin-top:0.375rem
         | 
| 6548 | 
            +
            }
         | 
| 6549 | 
            +
             | 
| 6550 | 
            +
            .ml-2{
         | 
| 6551 | 
            +
              margin-left:0.5rem
         | 
| 6552 | 
            +
            }
         | 
| 6553 | 
            +
             | 
| 6530 6554 | 
             
            .mr-0\.5{
         | 
| 6531 6555 | 
             
              margin-right:0.125rem
         | 
| 6532 6556 | 
             
            }
         | 
| @@ -6547,10 +6571,6 @@ trix-editor .attachment__metadata .attachment__size { | |
| 6547 6571 | 
             
              margin-bottom:-0.5rem
         | 
| 6548 6572 | 
             
            }
         | 
| 6549 6573 |  | 
| 6550 | 
            -
            .mt-0{
         | 
| 6551 | 
            -
              margin-top:0px
         | 
| 6552 | 
            -
            }
         | 
| 6553 | 
            -
             | 
| 6554 6574 | 
             
            .mt-6{
         | 
| 6555 6575 | 
             
              margin-top:1.5rem
         | 
| 6556 6576 | 
             
            }
         | 
| @@ -6687,6 +6707,10 @@ trix-editor .attachment__metadata .attachment__size { | |
| 6687 6707 | 
             
              height:2.5rem
         | 
| 6688 6708 | 
             
            }
         | 
| 6689 6709 |  | 
| 6710 | 
            +
            .h-9{
         | 
| 6711 | 
            +
              height:2.25rem
         | 
| 6712 | 
            +
            }
         | 
| 6713 | 
            +
             | 
| 6690 6714 | 
             
            .max-h-\[42rem\]{
         | 
| 6691 6715 | 
             
              max-height:42rem
         | 
| 6692 6716 | 
             
            }
         | 
| @@ -6795,6 +6819,14 @@ trix-editor .attachment__metadata .attachment__size { | |
| 6795 6819 | 
             
              min-width:20px
         | 
| 6796 6820 | 
             
            }
         | 
| 6797 6821 |  | 
| 6822 | 
            +
            .min-w-\[2rem\]{
         | 
| 6823 | 
            +
              min-width:2rem
         | 
| 6824 | 
            +
            }
         | 
| 6825 | 
            +
             | 
| 6826 | 
            +
            .min-w-\[6rem\]{
         | 
| 6827 | 
            +
              min-width:6rem
         | 
| 6828 | 
            +
            }
         | 
| 6829 | 
            +
             | 
| 6798 6830 | 
             
            .max-w-168{
         | 
| 6799 6831 | 
             
              max-width:42rem
         | 
| 6800 6832 | 
             
            }
         | 
| @@ -7723,6 +7755,10 @@ trix-editor .attachment__metadata .attachment__size { | |
| 7723 7755 | 
             
              padding-bottom:75%
         | 
| 7724 7756 | 
             
            }
         | 
| 7725 7757 |  | 
| 7758 | 
            +
            .pt-px{
         | 
| 7759 | 
            +
              padding-top:1px
         | 
| 7760 | 
            +
            }
         | 
| 7761 | 
            +
             | 
| 7726 7762 | 
             
            .pr-2{
         | 
| 7727 7763 | 
             
              padding-right:0.5rem
         | 
| 7728 7764 | 
             
            }
         | 
| @@ -9181,6 +9217,10 @@ trix-editor { | |
| 9181 9217 | 
             
              outline-width:1px
         | 
| 9182 9218 | 
             
            }
         | 
| 9183 9219 |  | 
| 9220 | 
            +
            .active\:outline-0:active{
         | 
| 9221 | 
            +
              outline-width:0px
         | 
| 9222 | 
            +
            }
         | 
| 9223 | 
            +
             | 
| 9184 9224 | 
             
            .active\:outline-slate-500:active{
         | 
| 9185 9225 | 
             
              outline-color:#64748b
         | 
| 9186 9226 | 
             
            }
         |