avo 2.11.2.pre.3 → 2.11.3.pre.1
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 -1
- data/app/assets/stylesheets/avo.css +1 -0
- data/app/assets/stylesheets/css/scrollbar.css +30 -0
- data/app/components/avo/actions_component.html.erb +3 -3
- data/app/components/avo/actions_component.rb +12 -3
- data/app/components/avo/button_component.rb +1 -3
- data/app/components/avo/paginator_component.html.erb +35 -33
- data/app/components/avo/paginator_component.rb +3 -1
- data/app/components/avo/panel_component.html.erb +1 -1
- data/app/components/avo/resource_component.rb +6 -4
- data/app/components/avo/sidebar_component.html.erb +1 -1
- data/app/components/avo/tab_switcher_component.html.erb +1 -1
- data/app/components/avo/views/resource_index_component.html.erb +3 -3
- data/app/components/avo/views/resource_show_component.html.erb +143 -52
- data/app/components/avo/views/resource_show_component.rb +1 -0
- data/app/controllers/avo/base_controller.rb +8 -7
- data/app/javascript/avo.js +1 -1
- data/app/javascript/js/controllers/fields/date_field_controller.js +7 -3
- data/app/views/avo/debug/report.html.erb +1 -0
- data/app/views/avo/private/design.html.erb +1 -1
- data/lib/avo/base_resource.rb +5 -1
- data/lib/avo/concerns/has_editable_controls.rb +34 -0
- data/lib/avo/fields/date_time_field.rb +2 -2
- data/lib/avo/fields/has_base_field.rb +2 -0
- data/lib/avo/licensing/pro_license.rb +1 -0
- data/lib/avo/resources/controls/action.rb +32 -0
- data/lib/avo/resources/controls/actions_list.rb +19 -0
- data/lib/avo/resources/controls/back_button.rb +13 -0
- data/lib/avo/resources/controls/base_control.rb +59 -0
- data/lib/avo/resources/controls/delete_button.rb +13 -0
- data/lib/avo/resources/controls/detach_button.rb +13 -0
- data/lib/avo/resources/controls/edit_button.rb +13 -0
- data/lib/avo/resources/controls/execution_context.rb +59 -0
- data/lib/avo/resources/controls/items_holder.rb +19 -0
- data/lib/avo/resources/controls/link_to.rb +27 -0
- data/lib/avo/version.rb +1 -1
- data/lib/generators/avo/templates/action.tt +1 -1
- data/lib/generators/avo/templates/resource_tools/partial.tt +1 -1
- data/lib/generators/avo/templates/standalone_action.tt +1 -1
- data/public/avo-assets/avo.css +602 -43
- data/public/avo-assets/avo.js +2 -2
- data/public/avo-assets/avo.js.map +2 -2
- metadata +14 -3
- data/lib/avo/concerns/has_model.rb +0 -11
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 6322eef586c1cf132343d666fa513b2733699349d2945a86ddb2b37669cfcd1c
         | 
| 4 | 
            +
              data.tar.gz: 5fb654449921d9fde5312adbeee074f96752445c34416ea4a6a22e6c5f9be9df
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 8c9ee8afe73d49806a42032b5c3f2b8c49a05763d44048e44c55ab4831d30c475ad2792cb6ad11ce5bd8ce296202c20173dd8bf274b05c64f6ac60174835953b
         | 
| 7 | 
            +
              data.tar.gz: f22c15ebaaee96768cd5c38c2935a513410a32a5e46729b22c4c8375c1b7a229b4e3e733572f3fe47207229bae4775ce3a5510c528a532759c81b8b2b0b39fc7
         | 
    
        data/Gemfile.lock
    CHANGED
    
    
| @@ -0,0 +1,30 @@ | |
| 1 | 
            +
            /* total width */
         | 
| 2 | 
            +
            body.os-pc .mac-styled-scrollbar::-webkit-scrollbar {
         | 
| 3 | 
            +
                background-color: none;
         | 
| 4 | 
            +
                width: 0.5rem;
         | 
| 5 | 
            +
                height: 0.5rem;
         | 
| 6 | 
            +
            }
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            /* background of the scrollbar except button or resizer */
         | 
| 9 | 
            +
            body.os-pc .mac-styled-scrollbar::-webkit-scrollbar-track {
         | 
| 10 | 
            +
                background-color: none;
         | 
| 11 | 
            +
            }
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            /* scrollbar itself */
         | 
| 14 | 
            +
            body.os-pc .mac-styled-scrollbar::-webkit-scrollbar-thumb {
         | 
| 15 | 
            +
                background-color: #babac0;
         | 
| 16 | 
            +
                border-radius: 0.5rem;
         | 
| 17 | 
            +
            }
         | 
| 18 | 
            +
             | 
| 19 | 
            +
            /* set button(top and bottom of the scrollbar) */
         | 
| 20 | 
            +
            body.os-pc .mac-styled-scrollbar::-webkit-scrollbar-button {
         | 
| 21 | 
            +
                display:none;
         | 
| 22 | 
            +
            }
         | 
| 23 | 
            +
            /* hide by default */
         | 
| 24 | 
            +
            body.os-pc .mac-styled-scrollbar::-webkit-scrollbar-thumb {
         | 
| 25 | 
            +
              display:none
         | 
| 26 | 
            +
            }
         | 
| 27 | 
            +
            /* show on hover */
         | 
| 28 | 
            +
            body.os-pc .mac-styled-scrollbar:hover::-webkit-scrollbar-thumb {
         | 
| 29 | 
            +
              display:block
         | 
| 30 | 
            +
            }
         | 
| @@ -3,9 +3,9 @@ | |
| 3 3 | 
             
              data-actions-picker-enabled-class="text-black hover:bg-blue-500 hover:text-white"
         | 
| 4 4 | 
             
              data-actions-picker-disabled-class="cursor-wait text-gray-500"
         | 
| 5 5 | 
             
            >
         | 
| 6 | 
            -
              <%= a_button style:  | 
| 6 | 
            +
              <%= a_button style: @style,
         | 
| 7 7 | 
             
                type: :button,
         | 
| 8 | 
            -
                color:  | 
| 8 | 
            +
                color: @color,
         | 
| 9 9 | 
             
                class: "focus:outline-none",
         | 
| 10 10 | 
             
                icon: 'arrow-circle-right',
         | 
| 11 11 | 
             
                icon_class: 'transform rotate-90',
         | 
| @@ -18,7 +18,7 @@ | |
| 18 18 | 
             
                data-toggle-panel-target="panel"
         | 
| 19 19 | 
             
              >
         | 
| 20 20 | 
             
                <div class="w-full space divide-y">
         | 
| 21 | 
            -
                  <%  | 
| 21 | 
            +
                  <% actions.each_with_index do |action, index| %>
         | 
| 22 22 | 
             
                    <%= link_to action_path(action.param_id),
         | 
| 23 23 | 
             
                      data: {
         | 
| 24 24 | 
             
                        'turbo-frame': 'actions_show',
         | 
| @@ -3,14 +3,23 @@ | |
| 3 3 | 
             
            class Avo::ActionsComponent < ViewComponent::Base
         | 
| 4 4 | 
             
              include Avo::ApplicationHelper
         | 
| 5 5 |  | 
| 6 | 
            -
              def initialize(actions: [], resource: nil, view: nil)
         | 
| 7 | 
            -
                @actions = actions
         | 
| 6 | 
            +
              def initialize(actions: [], resource: nil, view: nil, exclude: [], style: :outline, color: :blue)
         | 
| 7 | 
            +
                @actions = actions || []
         | 
| 8 8 | 
             
                @resource = resource
         | 
| 9 9 | 
             
                @view = view
         | 
| 10 | 
            +
                @exclude = exclude
         | 
| 11 | 
            +
                @color = color
         | 
| 12 | 
            +
                @style = style
         | 
| 10 13 | 
             
              end
         | 
| 11 14 |  | 
| 12 15 | 
             
              def render?
         | 
| 13 | 
            -
                 | 
| 16 | 
            +
                actions.present?
         | 
| 17 | 
            +
              end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
              def actions
         | 
| 20 | 
            +
                @actions.select do |action|
         | 
| 21 | 
            +
                  !action.class.in?(@exclude)
         | 
| 22 | 
            +
                end
         | 
| 14 23 | 
             
              end
         | 
| 15 24 |  | 
| 16 25 | 
             
              # When running an action for one record we should do it on a special path.
         | 
| @@ -43,9 +43,7 @@ class Avo::ButtonComponent < ViewComponent::Base | |
| 43 43 | 
             
                classes = "button-component inline-flex flex-grow-0 items-center font-semibold leading-6 fill-current whitespace-nowrap transition duration-100 transform transition duration-100 cursor-pointer disabled:cursor-not-allowed disabled:opacity-70 border justify-center active:outline active:outline-1 #{@class}"
         | 
| 44 44 |  | 
| 45 45 | 
             
                classes += " rounded" if @rounded.present?
         | 
| 46 | 
            -
             | 
| 47 46 | 
             
                classes += style_classes
         | 
| 48 | 
            -
             | 
| 49 47 | 
             
                classes += horizontal_padding_classes
         | 
| 50 48 | 
             
                classes += vertical_padding_classes
         | 
| 51 49 | 
             
                classes += text_size_classes
         | 
| @@ -151,7 +149,7 @@ class Avo::ButtonComponent < ViewComponent::Base | |
| 151 149 | 
             
              def style_classes
         | 
| 152 150 | 
             
                case @style
         | 
| 153 151 | 
             
                when :primary
         | 
| 154 | 
            -
                  " bg- | 
| 152 | 
            +
                  " bg-#{@color}-500 text-white border-#{@color}-500 hover:bg-#{@color}-600 hover:border-#{@color}-600 active:border-#{@color}-700 active:outline-#{@color}-700 active:bg-#{@color}-600"
         | 
| 155 153 | 
             
                when :outline
         | 
| 156 154 | 
             
                  " bg-white text-#{@color}-500 border-#{@color}-500 hover:bg-#{@color}-100 active:bg-#{@color}-100 active:border-#{@color}-500 active:outline-#{@color}-500"
         | 
| 157 155 | 
             
                when :text
         | 
| @@ -7,43 +7,45 @@ | |
| 7 7 |  | 
| 8 8 | 
             
              per_page_options = per_page_options.sort.uniq
         | 
| 9 9 | 
             
            %>
         | 
| 10 | 
            -
             | 
| 11 | 
            -
              <div class="flex- | 
| 12 | 
            -
                <div>
         | 
| 13 | 
            -
                  <div | 
| 14 | 
            -
                    <div  | 
| 15 | 
            -
                      <div  | 
| 16 | 
            -
                         | 
| 17 | 
            -
                           | 
| 18 | 
            -
             | 
| 19 | 
            -
             | 
| 20 | 
            -
                             | 
| 21 | 
            -
             | 
| 22 | 
            -
             | 
| 23 | 
            -
             | 
| 24 | 
            -
             | 
| 25 | 
            -
             | 
| 26 | 
            -
             | 
| 27 | 
            -
                        <%  | 
| 28 | 
            -
                           | 
| 29 | 
            -
             | 
| 30 | 
            -
                           | 
| 10 | 
            +
            <% unless @pagy.pages <= 1 && discreet_pagination %>
         | 
| 11 | 
            +
              <div class="flex flex-col sm:flex-row items-center justify-between aborder-t aborder-slate-200 rounded-xl space-y-2 sm:space-y-0">
         | 
| 12 | 
            +
                <div class="flex-2 sm:flex sm:items-center sm:justify-between">
         | 
| 13 | 
            +
                  <div>
         | 
| 14 | 
            +
                    <div class="text-sm leading-5 text-slate-600 flex items-center">
         | 
| 15 | 
            +
                      <div data-controller="per-page">
         | 
| 16 | 
            +
                        <div class="flex items-center">
         | 
| 17 | 
            +
                          <%= select_tag 'per_page',
         | 
| 18 | 
            +
                            options_for_select(per_page_options, index_params[:per_page]),
         | 
| 19 | 
            +
                            class: 'appearance-none inline-flex bg-white-100 disabled:bg-white-400 disabled:cursor-not-allowed focus:bg-white text-slate-700 disabled:text-slate-600 rounded-md py-1 px-2 leading-tight border border-slate-300 outline-none focus:border-slate-400 outline w-16 mr-1 text-sm',
         | 
| 20 | 
            +
                            data: {
         | 
| 21 | 
            +
                              'turbo-frame': turbo_frame,
         | 
| 22 | 
            +
                              'per-page-target': 'selector',
         | 
| 23 | 
            +
                              action: 'change->per-page#reload'
         | 
| 24 | 
            +
                            }
         | 
| 25 | 
            +
                          %> <%= t('avo.per_page').downcase %>
         | 
| 26 | 
            +
                        </div>
         | 
| 27 | 
            +
                        <% per_page_options.each do |option| %>
         | 
| 28 | 
            +
                          <% if parent_model.present? %>
         | 
| 29 | 
            +
                            <%= link_to "Change to #{option} items per page", helpers.related_resources_path(parent_model, parent_model, per_page: option, keep_query_params: true, page: 1), class: 'hidden', 'data-per-page-option': option, 'data-turbo-frame': turbo_frame %>
         | 
| 30 | 
            +
                          <% else %>
         | 
| 31 | 
            +
                            <%= link_to "Change to #{option} items per page", helpers.resources_path(resource: resource, per_page: option, keep_query_params: true, page: 1), class: 'hidden', 'data-per-page-option': option, 'data-turbo-frame': turbo_frame %>
         | 
| 32 | 
            +
                          <% end %>
         | 
| 31 33 | 
             
                        <% end %>
         | 
| 32 | 
            -
                       | 
| 34 | 
            +
                      </div>
         | 
| 33 35 | 
             
                    </div>
         | 
| 34 36 | 
             
                  </div>
         | 
| 35 37 | 
             
                </div>
         | 
| 36 | 
            -
             | 
| 37 | 
            -
             | 
| 38 | 
            -
             | 
| 39 | 
            -
             | 
| 40 | 
            -
                     | 
| 41 | 
            -
                  <% end %>
         | 
| 38 | 
            +
                <div class="flex">
         | 
| 39 | 
            +
                  <div class="flex-2 sm:flex sm:items-center sm:justify-between space-y-2 sm:space-y-0 text-center sm:text-left">
         | 
| 40 | 
            +
                    <% if @pagy.count > 0 %>
         | 
| 41 | 
            +
                      <div class="text-sm text-slate-600 mr-4"><%== helpers.pagy_info @pagy %></div>
         | 
| 42 | 
            +
                    <% end %>
         | 
| 42 43 |  | 
| 43 | 
            -
             | 
| 44 | 
            -
             | 
| 45 | 
            -
             | 
| 46 | 
            -
             | 
| 44 | 
            +
                    <% if @pagy.pages > 1 %>
         | 
| 45 | 
            +
                      <%# @todo: add first & last page. make the first and last buttons rounded %>
         | 
| 46 | 
            +
                      <%== helpers.pagy_nav @pagy %>
         | 
| 47 | 
            +
                    <% end %>
         | 
| 48 | 
            +
                  </div>
         | 
| 47 49 | 
             
                </div>
         | 
| 48 50 | 
             
              </div>
         | 
| 49 | 
            -
             | 
| 51 | 
            +
            <% end %>
         | 
| @@ -6,12 +6,14 @@ class Avo::PaginatorComponent < ViewComponent::Base | |
| 6 6 | 
             
              attr_reader :index_params
         | 
| 7 7 | 
             
              attr_reader :resource
         | 
| 8 8 | 
             
              attr_reader :parent_model
         | 
| 9 | 
            +
              attr_reader :discreet_pagination
         | 
| 9 10 |  | 
| 10 | 
            -
              def initialize(resource: nil, parent_model: nil, pagy: nil, turbo_frame: nil, index_params: nil)
         | 
| 11 | 
            +
              def initialize(resource: nil, parent_model: nil, pagy: nil, turbo_frame: nil, index_params: nil, discreet_pagination: nil)
         | 
| 11 12 | 
             
                @pagy = pagy
         | 
| 12 13 | 
             
                @turbo_frame = turbo_frame
         | 
| 13 14 | 
             
                @index_params = index_params
         | 
| 14 15 | 
             
                @resource = resource
         | 
| 15 16 | 
             
                @parent_model = parent_model
         | 
| 17 | 
            +
                @discreet_pagination = discreet_pagination
         | 
| 16 18 | 
             
              end
         | 
| 17 19 | 
             
            end
         | 
| @@ -17,7 +17,7 @@ | |
| 17 17 | 
             
                    <% end %>
         | 
| 18 18 | 
             
                  </div>
         | 
| 19 19 | 
             
                  <% if tools.present? %>
         | 
| 20 | 
            -
                    <div class="flex-1 w-full flex flex-col sm:flex-row xl:justify-end sm:items-end  | 
| 20 | 
            +
                    <div class="flex-1 w-full flex flex-wrap flex-col sm:flex-row xl:justify-end sm:items-end gap-2 mt-4 xl:mt-0" data-target="panel-controls">
         | 
| 21 21 | 
             
                      <%= tools %>
         | 
| 22 22 | 
             
                    </div>
         | 
| 23 23 | 
             
                  <% end %>
         | 
| @@ -22,6 +22,12 @@ class Avo::ResourceComponent < Avo::BaseComponent | |
| 22 22 | 
             
                authorize_association_for("detach")
         | 
| 23 23 | 
             
              end
         | 
| 24 24 |  | 
| 25 | 
            +
              def detach_path
         | 
| 26 | 
            +
                return "/" if @reflection.blank?
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                helpers.resource_detach_path(params[:resource_name], params[:id], @reflection.name.to_s, @resource.model.id)
         | 
| 29 | 
            +
              end
         | 
| 30 | 
            +
             | 
| 25 31 | 
             
              def can_see_the_edit_button?
         | 
| 26 32 | 
             
                @resource.authorization.authorize_action(:edit, raise_exception: false)
         | 
| 27 33 | 
             
              end
         | 
| @@ -30,10 +36,6 @@ class Avo::ResourceComponent < Avo::BaseComponent | |
| 30 36 | 
             
                @resource.authorization.authorize_action(:destroy, raise_exception: false)
         | 
| 31 37 | 
             
              end
         | 
| 32 38 |  | 
| 33 | 
            -
              def detach_path
         | 
| 34 | 
            -
                helpers.resource_detach_path(params[:resource_name], params[:id], @reflection.name.to_s, @resource.model.id)
         | 
| 35 | 
            -
              end
         | 
| 36 | 
            -
             | 
| 37 39 | 
             
              def destroy_path
         | 
| 38 40 | 
             
                helpers.resource_path(model: @resource.model, resource: @resource)
         | 
| 39 41 | 
             
              end
         | 
| @@ -9,7 +9,7 @@ | |
| 9 9 | 
             
              data-transition-leave-end="transform opacity-0 -translate-x-full"
         | 
| 10 10 | 
             
            >
         | 
| 11 11 | 
             
              <div class="flex flex-col w-full h-full">
         | 
| 12 | 
            -
                <div class="flex-1 flex flex-col justify-between overflow-auto h-full pt-3 scroll-shadows">
         | 
| 12 | 
            +
                <div class="flex-1 flex flex-col justify-between overflow-auto h-full pt-3 scroll-shadows mac-styled-scrollbar">
         | 
| 13 13 | 
             
                  <div class="space-y-6 mb-4">
         | 
| 14 14 | 
             
                    <%= render Avo::Sidebar::LinkComponent.new label: 'Get started', path: helpers.avo.root_path, active: :exclusive if Rails.env.development? && Avo.configuration.home_path.nil? %>
         | 
| 15 15 |  | 
| @@ -49,7 +49,7 @@ | |
| 49 49 | 
             
                  </div>
         | 
| 50 50 | 
             
                  <% if view_type.to_sym == :table %>
         | 
| 51 51 | 
             
                    <% if @resources.present? %>
         | 
| 52 | 
            -
                      <div class="w-full overflow-auto flex flex-col mt-0">
         | 
| 52 | 
            +
                      <div class="w-full overflow-auto flex flex-col mt-0 mac-styled-scrollbar">
         | 
| 53 53 | 
             
                        <div class="relative flex-1 flex">
         | 
| 54 54 | 
             
                          <%= render(Avo::Index::ResourceTableComponent.new(resources: @resources, resource: @resource, reflection: @reflection, parent_model: @parent_model, parent_resource: @parent_resource)) %>
         | 
| 55 55 | 
             
                        </div>
         | 
| @@ -63,14 +63,14 @@ | |
| 63 63 | 
             
                  <% if view_type.to_sym == :table %>
         | 
| 64 64 | 
             
                    <% if @models.present? %>
         | 
| 65 65 | 
             
                      <div class="mt-4">
         | 
| 66 | 
            -
                        <%= render Avo::PaginatorComponent.new pagy: @pagy, turbo_frame: @turbo_frame || 'none', index_params: @index_params, resource: @resource, parent_model: @parent_model %>
         | 
| 66 | 
            +
                        <%= render Avo::PaginatorComponent.new pagy: @pagy, turbo_frame: @turbo_frame || 'none', index_params: @index_params, resource: @resource, parent_model: @parent_model, discreet_pagination: field&.discreet_pagination %>
         | 
| 67 67 | 
             
                      </div>
         | 
| 68 68 | 
             
                    <% end %>
         | 
| 69 69 | 
             
                  <% end %>
         | 
| 70 70 | 
             
                  <% if view_type.to_sym == :grid %>
         | 
| 71 71 | 
             
                    <%= render Avo::Index::ResourceGridComponent.new(resources: @resources, resource: @resource, reflection: @reflection, parent_model: @parent_model) %>
         | 
| 72 72 | 
             
                    <div class="mt-6">
         | 
| 73 | 
            -
                      <%= render Avo::PaginatorComponent.new pagy: @pagy, turbo_frame: @turbo_frame || 'none', index_params: @index_params, resource: @resource, parent_model: @parent_model %>
         | 
| 73 | 
            +
                      <%= render Avo::PaginatorComponent.new pagy: @pagy, turbo_frame: @turbo_frame || 'none', index_params: @index_params, resource: @resource, parent_model: @parent_model, discreet_pagination: field&.discreet_pagination %>
         | 
| 74 74 | 
             
                    </div>
         | 
| 75 75 | 
             
                  <% end %>
         | 
| 76 76 | 
             
                <% end %>
         | 
| @@ -7,59 +7,148 @@ | |
| 7 7 | 
             
              } do %>
         | 
| 8 8 | 
             
              <%= render Avo::PanelComponent.new(title: title, description: @resource.resource_description, display_breadcrumbs: @reflection.blank?, index: 0, data: { panel_id: "main" }) do |c| %>
         | 
| 9 9 | 
             
                <% c.tools do %>
         | 
| 10 | 
            -
                  <% if @ | 
| 11 | 
            -
                    <%  | 
| 12 | 
            -
                       | 
| 13 | 
            -
                         | 
| 14 | 
            -
             | 
| 15 | 
            -
             | 
| 16 | 
            -
             | 
| 17 | 
            -
             | 
| 18 | 
            -
             | 
| 19 | 
            -
             | 
| 20 | 
            -
             | 
| 21 | 
            -
             | 
| 22 | 
            -
             | 
| 23 | 
            -
             | 
| 24 | 
            -
             | 
| 25 | 
            -
             | 
| 26 | 
            -
             | 
| 27 | 
            -
             | 
| 28 | 
            -
             | 
| 29 | 
            -
             | 
| 10 | 
            +
                  <% if @resource.has_show_controls? %>
         | 
| 11 | 
            +
                    <% @resource.render_show_controls.each do |control| %>
         | 
| 12 | 
            +
                      <% if control.back_button? %>
         | 
| 13 | 
            +
                        <%= a_link back_path,
         | 
| 14 | 
            +
                            style: :text,
         | 
| 15 | 
            +
                            title: control.title,
         | 
| 16 | 
            +
                            data: {
         | 
| 17 | 
            +
                              tippy: control.title ? :tooltip : nil,
         | 
| 18 | 
            +
                            },
         | 
| 19 | 
            +
                            icon: 'arrow-left' do %>
         | 
| 20 | 
            +
                          <%= control.label %>
         | 
| 21 | 
            +
                        <% end %>
         | 
| 22 | 
            +
                      <% elsif control.delete_button? %>
         | 
| 23 | 
            +
                        <% if can_see_the_destroy_button? %>
         | 
| 24 | 
            +
                        <% end %>
         | 
| 25 | 
            +
                        <%= a_button url: helpers.resource_path(model: @resource.model, resource: @resource),
         | 
| 26 | 
            +
                            method: :delete,
         | 
| 27 | 
            +
                            local: true,
         | 
| 28 | 
            +
                            style: :text,
         | 
| 29 | 
            +
                            loading: true,
         | 
| 30 | 
            +
                            confirm: t('avo.are_you_sure', item: @resource.model.model_name.name.downcase),
         | 
| 31 | 
            +
                            color: :red,
         | 
| 32 | 
            +
                            icon: 'trash',
         | 
| 33 | 
            +
                            form_class: 'flex flex-col sm:flex-row sm:inline-flex',
         | 
| 34 | 
            +
                            title: control.title,
         | 
| 35 | 
            +
                            data: {
         | 
| 36 | 
            +
                              control: :destroy,
         | 
| 37 | 
            +
                              tippy: control.title ? :tooltip : nil,
         | 
| 38 | 
            +
                              'resource-id': @resource.model.id,
         | 
| 39 | 
            +
                            } do %>
         | 
| 40 | 
            +
                        <% end %>
         | 
| 41 | 
            +
                      <% elsif control.actions_list? %>
         | 
| 42 | 
            +
                        <%= render Avo::ActionsComponent.new actions: @actions, resource: @resource, view: @view, exclude: control.exclude, style: control.style, color: control.color %>
         | 
| 43 | 
            +
                      <% elsif control.edit_button? %>
         | 
| 44 | 
            +
                        <% if @resource.authorization.authorize_action(:edit, raise_exception: false) %>
         | 
| 45 | 
            +
                        <% end %>
         | 
| 46 | 
            +
                        <%= a_link edit_path,
         | 
| 47 | 
            +
                            color: :primary,
         | 
| 48 | 
            +
                            style: :primary,
         | 
| 49 | 
            +
                            title: control.title,
         | 
| 50 | 
            +
                            data: {
         | 
| 51 | 
            +
                              tippy: control.title ? :tooltip : nil,
         | 
| 52 | 
            +
                            },
         | 
| 53 | 
            +
                            icon: 'edit' do %>
         | 
| 54 | 
            +
                          <%= control.label %>
         | 
| 55 | 
            +
                        <% end %>
         | 
| 56 | 
            +
                      <% elsif control.action? %>
         | 
| 57 | 
            +
                        <%= a_link control.path,
         | 
| 58 | 
            +
                            color: control.color,
         | 
| 59 | 
            +
                            style: control.style,
         | 
| 60 | 
            +
                            icon: control.icon,
         | 
| 61 | 
            +
                            title: control.title,
         | 
| 62 | 
            +
                            data: {
         | 
| 63 | 
            +
                              tippy: control.title ? :tooltip : nil,
         | 
| 64 | 
            +
                              'turbo-frame': 'actions_show',
         | 
| 65 | 
            +
                              'action': 'click->actions-picker#visitAction',
         | 
| 66 | 
            +
                            } do %>
         | 
| 67 | 
            +
                          <%= control.label %>
         | 
| 68 | 
            +
                        <% end %>
         | 
| 69 | 
            +
                      <% elsif control.link_to? %>
         | 
| 70 | 
            +
                        <%= a_link control.path,
         | 
| 71 | 
            +
                            color: control.color,
         | 
| 72 | 
            +
                            style: control.style,
         | 
| 73 | 
            +
                            icon: control.icon,
         | 
| 74 | 
            +
                            title: control.title,
         | 
| 75 | 
            +
                            target: control.target,
         | 
| 76 | 
            +
                            class: control.class,
         | 
| 77 | 
            +
                            data: {
         | 
| 78 | 
            +
                              **control.data,
         | 
| 79 | 
            +
                              tippy: control.title ? :tooltip : nil,
         | 
| 80 | 
            +
                            } do %>
         | 
| 81 | 
            +
                          <%= control.label %>
         | 
| 82 | 
            +
                        <% end %>
         | 
| 83 | 
            +
                      <% elsif control.detach_button? %>
         | 
| 84 | 
            +
                        <% if @reflection.present? && @resource.model.present? && can_detach? %>
         | 
| 85 | 
            +
                          <%= a_button url: detach_path,
         | 
| 86 | 
            +
                              icon: 'detach',
         | 
| 87 | 
            +
                              method: :delete,
         | 
| 88 | 
            +
                              form_class: 'flex flex-col sm:flex-row sm:inline-flex',
         | 
| 89 | 
            +
                              style: :text,
         | 
| 90 | 
            +
                              data: {
         | 
| 91 | 
            +
                                confirm: "Are you sure you want to detach this #{title}."
         | 
| 92 | 
            +
                              } do %>
         | 
| 93 | 
            +
                            <%= t('avo.detach_item', item: title).capitalize %>
         | 
| 94 | 
            +
                          <% end %>
         | 
| 95 | 
            +
                        <% end %>
         | 
| 30 96 | 
             
                      <% end %>
         | 
| 31 97 | 
             
                    <% end %>
         | 
| 32 98 | 
             
                  <% else %>
         | 
| 33 | 
            -
                     | 
| 34 | 
            -
                       | 
| 35 | 
            -
             | 
| 36 | 
            -
             | 
| 37 | 
            -
             | 
| 38 | 
            -
             | 
| 39 | 
            -
             | 
| 40 | 
            -
             | 
| 41 | 
            -
             | 
| 99 | 
            +
                    <% if @reflection.present? && @resource.model.present? %>
         | 
| 100 | 
            +
                      <% if can_detach? %>
         | 
| 101 | 
            +
                        <%= a_button url: detach_path,
         | 
| 102 | 
            +
                            icon: 'detach',
         | 
| 103 | 
            +
                            method: :delete,
         | 
| 104 | 
            +
                            form_class: 'flex flex-col sm:flex-row sm:inline-flex',
         | 
| 105 | 
            +
                            style: :text,
         | 
| 106 | 
            +
                            data: {
         | 
| 107 | 
            +
                              confirm: "Are you sure you want to detach this #{title}."
         | 
| 108 | 
            +
                            } do %>
         | 
| 109 | 
            +
                          <%= t('avo.detach_item', item: title).capitalize %>
         | 
| 110 | 
            +
                        <% end %>
         | 
| 111 | 
            +
                      <% end %>
         | 
| 112 | 
            +
                      <%= render Avo::ActionsComponent.new actions: @actions, resource: @resource, view: @view %>
         | 
| 113 | 
            +
                      <% if can_see_the_edit_button? %>
         | 
| 114 | 
            +
                        <%= a_link edit_path,
         | 
| 115 | 
            +
                            color: :primary,
         | 
| 116 | 
            +
                            style: :primary,
         | 
| 117 | 
            +
                            icon: 'edit' do %>
         | 
| 118 | 
            +
                          <%= t('avo.edit').capitalize %>
         | 
| 119 | 
            +
                        <% end %>
         | 
| 120 | 
            +
                      <% end %>
         | 
| 121 | 
            +
                    <% else %>
         | 
| 122 | 
            +
                      <%= a_link back_path,
         | 
| 42 123 | 
             
                        style: :text,
         | 
| 43 | 
            -
                         | 
| 44 | 
            -
                         | 
| 45 | 
            -
                        color: :red,
         | 
| 46 | 
            -
                        icon: 'trash',
         | 
| 47 | 
            -
                        form_class: 'flex flex-col sm:flex-row sm:inline-flex',
         | 
| 48 | 
            -
                        data: {
         | 
| 49 | 
            -
                          control: :destroy,
         | 
| 50 | 
            -
                          'resource-id': @resource.model.id,
         | 
| 51 | 
            -
                          'tippy': 'tooltip',
         | 
| 52 | 
            -
                        } do %>
         | 
| 53 | 
            -
                        <%= t('avo.delete').capitalize %>
         | 
| 124 | 
            +
                        icon: 'arrow-left' do %>
         | 
| 125 | 
            +
                        <%= t('avo.go_back') %>
         | 
| 54 126 | 
             
                      <% end %>
         | 
| 55 | 
            -
             | 
| 56 | 
            -
             | 
| 57 | 
            -
             | 
| 58 | 
            -
             | 
| 59 | 
            -
             | 
| 60 | 
            -
             | 
| 61 | 
            -
             | 
| 62 | 
            -
             | 
| 127 | 
            +
                      <% if can_see_the_destroy_button? %>
         | 
| 128 | 
            +
                        <%= a_button url: helpers.resource_path(model: @resource.model, resource: @resource),
         | 
| 129 | 
            +
                            method: :delete,
         | 
| 130 | 
            +
                            local: true,
         | 
| 131 | 
            +
                            style: :text,
         | 
| 132 | 
            +
                            loading: true,
         | 
| 133 | 
            +
                            confirm: t('avo.are_you_sure', item: @resource.model.model_name.name.downcase),
         | 
| 134 | 
            +
                            color: :red,
         | 
| 135 | 
            +
                            icon: 'trash',
         | 
| 136 | 
            +
                            form_class: 'flex flex-col sm:flex-row sm:inline-flex',
         | 
| 137 | 
            +
                            data: {
         | 
| 138 | 
            +
                              control: :destroy,
         | 
| 139 | 
            +
                              'resource-id': @resource.model.id,
         | 
| 140 | 
            +
                            } do %>
         | 
| 141 | 
            +
                          <%= t('avo.delete').capitalize %>
         | 
| 142 | 
            +
                        <% end %>
         | 
| 143 | 
            +
                      <% end %>
         | 
| 144 | 
            +
                      <%= render Avo::ActionsComponent.new actions: @actions, resource: @resource, view: @view %>
         | 
| 145 | 
            +
                      <% if @resource.authorization.authorize_action(:edit, raise_exception: false) %>
         | 
| 146 | 
            +
                        <%= a_link edit_path,
         | 
| 147 | 
            +
                          color: :primary,
         | 
| 148 | 
            +
                          style: :primary,
         | 
| 149 | 
            +
                          icon: 'edit' do %>
         | 
| 150 | 
            +
                          <%= t('avo.edit').capitalize %>
         | 
| 151 | 
            +
                        <% end %>
         | 
| 63 152 | 
             
                      <% end %>
         | 
| 64 153 | 
             
                    <% end %>
         | 
| 65 154 | 
             
                  <% end %>
         | 
| @@ -77,10 +166,12 @@ | |
| 77 166 | 
             
                  <% end %>
         | 
| 78 167 | 
             
                <% end %>
         | 
| 79 168 | 
             
              <% end %>
         | 
| 80 | 
            -
               | 
| 81 | 
            -
                 | 
| 82 | 
            -
                  <%  | 
| 83 | 
            -
             | 
| 169 | 
            +
              <% if @reflection.blank? %>
         | 
| 170 | 
            +
                <%= content_tag :div, class: 'space-y-12 mt-12' do %>
         | 
| 171 | 
            +
                  <% @resource.get_items.each_with_index do |item, index| %>
         | 
| 172 | 
            +
                    <% next if item.nil? %>
         | 
| 173 | 
            +
                    <%= render Avo::ItemSwitcherComponent.new resource: @resource, reflection: @reflection, item: item, index: index + 1, view: @view %>
         | 
| 174 | 
            +
                  <% end %>
         | 
| 84 175 | 
             
                <% end %>
         | 
| 85 176 | 
             
              <% end %>
         | 
| 86 177 | 
             
              <% if should_display_invalid_fields_errors? %>
         | 
| @@ -258,18 +258,19 @@ module Avo | |
| 258 258 | 
             
                def cast_nullable(params)
         | 
| 259 259 | 
             
                  fields = @resource.get_field_definitions
         | 
| 260 260 |  | 
| 261 | 
            -
                  nullable_fields = fields | 
| 262 | 
            -
                    field | 
| 263 | 
            -
             | 
| 261 | 
            +
                  nullable_fields = fields
         | 
| 262 | 
            +
                    .filter do |field|
         | 
| 263 | 
            +
                      field.nullable
         | 
| 264 | 
            +
                    end
         | 
| 264 265 | 
             
                    .map do |field|
         | 
| 265 | 
            -
             | 
| 266 | 
            -
             | 
| 266 | 
            +
                      [field.id, field.null_values]
         | 
| 267 | 
            +
                    end
         | 
| 267 268 | 
             
                    .to_h
         | 
| 268 269 |  | 
| 269 270 | 
             
                  params.each do |key, value|
         | 
| 270 | 
            -
                     | 
| 271 | 
            +
                    nullable_values = nullable_fields[key.to_sym]
         | 
| 271 272 |  | 
| 272 | 
            -
                    if  | 
| 273 | 
            +
                    if nullable_values.present? && value.in?(nullable_values)
         | 
| 273 274 | 
             
                      params[key] = nil
         | 
| 274 275 | 
             
                    end
         | 
| 275 276 | 
             
                  end
         | 
    
        data/app/javascript/avo.js
    CHANGED
    
    
| @@ -106,13 +106,10 @@ export default class extends Controller { | |
| 106 106 |  | 
| 107 107 | 
             
                // enable timezone display
         | 
| 108 108 | 
             
                if (this.enableTimeValue) {
         | 
| 109 | 
            -
                  console.log(1)
         | 
| 110 109 | 
             
                  options.defaultDate = this.parsedValue.setZone(this.displayTimezone).toISO()
         | 
| 111 110 |  | 
| 112 111 | 
             
                  options.dateFormat = 'Y-m-d H:i:S'
         | 
| 113 112 | 
             
                } else {
         | 
| 114 | 
            -
                  console.log(2)
         | 
| 115 | 
            -
             | 
| 116 113 | 
             
                  // Because the browser treats the date like a timestamp and updates it at 00:00 hour, when on a western timezone the date will be converted with one day offset.
         | 
| 117 114 | 
             
                  // Ex: 2022-01-30 will render as 2022-01-29 on an American timezone
         | 
| 118 115 | 
             
                  options.defaultDate = universalTimestamp(this.initialValue)
         | 
| @@ -124,6 +121,13 @@ export default class extends Controller { | |
| 124 121 | 
             
              }
         | 
| 125 122 |  | 
| 126 123 | 
             
              onChange(selectedDates) {
         | 
| 124 | 
            +
                // No date has been selected
         | 
| 125 | 
            +
                if (selectedDates.length === 0) {
         | 
| 126 | 
            +
                  this.updateRealInput('')
         | 
| 127 | 
            +
             | 
| 128 | 
            +
                  return
         | 
| 129 | 
            +
                }
         | 
| 130 | 
            +
             | 
| 127 131 | 
             
                let time
         | 
| 128 132 | 
             
                let args = {}
         | 
| 129 133 |  | 
| @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            <div class="flex flex-col">
         | 
| 2 2 | 
             
              <%= render Avo::PanelComponent.new(title: 'Welcome to Avo', description: 'This page is visible only in development. It will be hidden in other environments.') do |c| %>
         | 
| 3 3 | 
             
                <% c.tools do %>
         | 
| 4 | 
            -
                  <%= a_link('/admin', icon: 'arrow-left', style: :primary, is_link: true) do %>
         | 
| 4 | 
            +
                  <%= a_link('/admin', icon: 'arrow-left', color: :green, style: :primary, is_link: true) do %>
         | 
| 5 5 | 
             
                    Primary
         | 
| 6 6 | 
             
                  <% end %>
         | 
| 7 7 |  | 
    
        data/lib/avo/base_resource.rb
    CHANGED
    
    | @@ -3,8 +3,8 @@ module Avo | |
| 3 3 | 
             
                extend ActiveSupport::DescendantsTracker
         | 
| 4 4 |  | 
| 5 5 | 
             
                include ActionView::Helpers::UrlHelper
         | 
| 6 | 
            -
                include Avo::Concerns::HasModel
         | 
| 7 6 | 
             
                include Avo::Concerns::HasFields
         | 
| 7 | 
            +
                include Avo::Concerns::HasEditableControls
         | 
| 8 8 | 
             
                include Avo::Concerns::HasStimulusControllers
         | 
| 9 9 | 
             
                include Avo::Concerns::ModelClassConstantized
         | 
| 10 10 |  | 
| @@ -439,5 +439,9 @@ module Avo | |
| 439 439 | 
             
                def ordering_host(**args)
         | 
| 440 440 | 
             
                  Avo::Hosts::Ordering.new resource: self, options: self.class.ordering, **args
         | 
| 441 441 | 
             
                end
         | 
| 442 | 
            +
             | 
| 443 | 
            +
                def has_model_id?
         | 
| 444 | 
            +
                  model.present? && model.id.present?
         | 
| 445 | 
            +
                end
         | 
| 442 446 | 
             
              end
         | 
| 443 447 | 
             
            end
         |