avo 2.10.2 → 2.11.1.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 +64 -62
- data/app/components/avo/fields/country_field/edit_component.html.erb +9 -3
- data/app/components/avo/fields/date_field/edit_component.html.erb +26 -8
- data/app/components/avo/fields/date_field/index_component.html.erb +7 -1
- data/app/components/avo/fields/date_field/show_component.html.erb +7 -1
- data/app/components/avo/fields/date_time_field/edit_component.html.erb +26 -10
- data/app/components/avo/fields/date_time_field/index_component.html.erb +10 -1
- data/app/components/avo/fields/date_time_field/show_component.html.erb +10 -1
- data/app/components/avo/fields/file_field/edit_component.html.erb +1 -0
- data/app/components/avo/fields/files_field/edit_component.html.erb +1 -0
- data/app/components/avo/fields/select_field/edit_component.html.erb +14 -10
- data/app/components/avo/index/ordering/button_component.rb +1 -5
- data/app/components/avo/views/resource_index_component.html.erb +1 -1
- data/app/controllers/avo/application_controller.rb +15 -9
- data/app/controllers/avo/base_controller.rb +11 -3
- data/app/controllers/avo/reorder_controller.rb +25 -0
- data/app/helpers/avo/application_helper.rb +6 -0
- data/app/helpers/avo/url_helpers.rb +0 -4
- data/app/javascript/js/controllers/fields/date_field_controller.js +108 -24
- data/app/javascript/js/controllers/search_controller.js +3 -0
- data/app/views/avo/partials/_javascript.html.erb +1 -1
- data/config/routes.rb +5 -4
- data/db/factories.rb +1 -0
- data/lib/avo/app.rb +1 -3
- data/lib/avo/base_action.rb +8 -6
- data/lib/avo/base_resource.rb +7 -8
- data/lib/avo/concerns/handles_field_args.rb +1 -1
- data/lib/avo/concerns/has_fields.rb +2 -0
- data/lib/avo/configuration.rb +2 -12
- data/lib/avo/fields/base_field.rb +2 -0
- data/lib/avo/fields/country_field.rb +2 -0
- data/lib/avo/fields/date_field.rb +12 -10
- data/lib/avo/fields/date_time_field.rb +21 -9
- data/lib/avo/fields/field_extensions/has_include_blank.rb +17 -0
- data/lib/avo/fields/file_field.rb +2 -0
- data/lib/avo/fields/files_field.rb +2 -0
- data/lib/avo/fields/select_field.rb +2 -0
- data/lib/avo/licensing/h_q.rb +2 -0
- data/lib/avo/services/uri_service.rb +4 -0
- data/lib/avo/version.rb +1 -1
- data/lib/generators/avo/action_generator.rb +3 -2
- data/lib/generators/avo/base_generator.rb +14 -0
- data/lib/generators/avo/card/chartkick_generator.rb +18 -0
- data/lib/generators/avo/card/metric_generator.rb +18 -0
- data/lib/generators/avo/card/partial_generator.rb +19 -0
- data/lib/generators/avo/controller_generator.rb +9 -3
- data/lib/generators/avo/dashboard_generator.rb +2 -2
- data/lib/generators/avo/eject_generator.rb +2 -3
- data/lib/generators/avo/field_generator.rb +2 -2
- data/lib/generators/avo/filter_generator.rb +3 -2
- data/lib/generators/avo/install_generator.rb +2 -2
- data/lib/generators/avo/locales_generator.rb +2 -2
- data/lib/generators/avo/named_base_generator.rb +14 -0
- data/lib/generators/avo/resource_generator.rb +2 -2
- data/lib/generators/avo/resource_tool_generator.rb +4 -4
- data/lib/generators/avo/tool_generator.rb +4 -4
- data/lib/generators/avo/version_generator.rb +23 -0
- data/public/avo-assets/avo.css +4 -0
- data/public/avo-assets/avo.js +69 -69
- data/public/avo-assets/avo.js.map +2 -2
- metadata +12 -12
- data/db/migrate/20210421064037_add_color_to_teams.rb +0 -5
- data/db/migrate/20210423075924_add_progress_to_projects.rb +0 -5
- data/db/migrate/20210525143134_add_slug_to_users.rb +0 -6
- data/lib/avo/fields/currency_field.rb +0 -15
- data/lib/avo/has_context.rb +0 -7
- data/lib/generators/avo/chartkick_card_generator.rb +0 -16
- data/lib/generators/avo/metric_card_generator.rb +0 -16
- data/lib/generators/avo/partial_card_generator.rb +0 -17
| @@ -2,63 +2,147 @@ import { Controller } from '@hotwired/stimulus' | |
| 2 2 | 
             
            import { DateTime } from 'luxon'
         | 
| 3 3 | 
             
            import flatpickr from 'flatpickr'
         | 
| 4 4 |  | 
| 5 | 
            -
            import { castBoolean } from '../../helpers/cast_boolean'
         | 
| 6 | 
            -
             | 
| 7 5 | 
             
            // Get the DateTime with the TZ offset applied.
         | 
| 8 6 | 
             
            function universalTimestamp(timestampStr) {
         | 
| 9 7 | 
             
              return new Date(new Date(timestampStr).getTime() + (new Date(timestampStr).getTimezoneOffset() * 60 * 1000))
         | 
| 10 8 | 
             
            }
         | 
| 11 9 |  | 
| 12 10 | 
             
            export default class extends Controller {
         | 
| 13 | 
            -
              static targets = ['input']
         | 
| 11 | 
            +
              static targets = ['input', 'fakeInput']
         | 
| 12 | 
            +
             | 
| 13 | 
            +
              static values = {
         | 
| 14 | 
            +
                view: String,
         | 
| 15 | 
            +
                timezone: String,
         | 
| 16 | 
            +
                format: String,
         | 
| 17 | 
            +
                enableTime: Boolean,
         | 
| 18 | 
            +
                pickerFormat: String,
         | 
| 19 | 
            +
                firstDayOfWeek: Number,
         | 
| 20 | 
            +
                time24Hr: Boolean,
         | 
| 21 | 
            +
                disableMobile: Boolean,
         | 
| 22 | 
            +
              }
         | 
| 23 | 
            +
             | 
| 24 | 
            +
              get browserZone() {
         | 
| 25 | 
            +
                const time = DateTime.local()
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                return time.zoneName
         | 
| 28 | 
            +
              }
         | 
| 29 | 
            +
             | 
| 30 | 
            +
              get initialValue() {
         | 
| 31 | 
            +
                if (this.isOnShow || this.isOnIndex) {
         | 
| 32 | 
            +
                  return this.context.element.innerText
         | 
| 33 | 
            +
                } if (this.isOnEdit) {
         | 
| 34 | 
            +
                  return this.inputTarget.value
         | 
| 35 | 
            +
                }
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                return null
         | 
| 38 | 
            +
              }
         | 
| 39 | 
            +
             | 
| 40 | 
            +
              get isOnIndex() {
         | 
| 41 | 
            +
                return this.viewValue === 'index'
         | 
| 42 | 
            +
              }
         | 
| 43 | 
            +
             | 
| 44 | 
            +
              get isOnEdit() {
         | 
| 45 | 
            +
                return this.viewValue === 'edit'
         | 
| 46 | 
            +
              }
         | 
| 47 | 
            +
             | 
| 48 | 
            +
              get isOnShow() {
         | 
| 49 | 
            +
                return this.viewValue === 'show'
         | 
| 50 | 
            +
              }
         | 
| 51 | 
            +
             | 
| 52 | 
            +
              // Parse the time as if it were UTC
         | 
| 53 | 
            +
              get parsedValue() {
         | 
| 54 | 
            +
                return DateTime.fromISO(this.initialValue, { zone: 'UTC' })
         | 
| 55 | 
            +
              }
         | 
| 56 | 
            +
             | 
| 57 | 
            +
              get displayTimezone() {
         | 
| 58 | 
            +
                return this.timezoneValue || this.browserZone
         | 
| 59 | 
            +
              }
         | 
| 14 60 |  | 
| 15 61 | 
             
              connect() {
         | 
| 62 | 
            +
                if (this.isOnShow || this.isOnIndex) {
         | 
| 63 | 
            +
                  this.initShow()
         | 
| 64 | 
            +
                } else if (this.isOnEdit) {
         | 
| 65 | 
            +
                  this.initEdit()
         | 
| 66 | 
            +
                }
         | 
| 67 | 
            +
              }
         | 
| 68 | 
            +
             | 
| 69 | 
            +
              // Turns the value in the controller wrapper into the timezone of the browser
         | 
| 70 | 
            +
              initShow() {
         | 
| 71 | 
            +
                let value = this.parsedValue
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                // Set the zone only if the type of field is date time.
         | 
| 74 | 
            +
                if (this.enableTimeValue) {
         | 
| 75 | 
            +
                  value = value.setZone(this.displayTimezone)
         | 
| 76 | 
            +
                }
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                this.context.element.innerText = value.toFormat(this.formatValue)
         | 
| 79 | 
            +
              }
         | 
| 80 | 
            +
             | 
| 81 | 
            +
              initEdit() {
         | 
| 16 82 | 
             
                const options = {
         | 
| 17 83 | 
             
                  enableTime: false,
         | 
| 18 84 | 
             
                  enableSeconds: false,
         | 
| 19 85 | 
             
                  // eslint-disable-next-line camelcase
         | 
| 20 | 
            -
                  time_24hr:  | 
| 86 | 
            +
                  time_24hr: this.time24HrValue,
         | 
| 21 87 | 
             
                  locale: {
         | 
| 22 88 | 
             
                    firstDayOfWeek: 0,
         | 
| 23 89 | 
             
                  },
         | 
| 24 90 | 
             
                  altInput: true,
         | 
| 91 | 
            +
                  onChange: this.onChange.bind(this),
         | 
| 25 92 | 
             
                }
         | 
| 26 | 
            -
                const enableTime = castBoolean(this.inputTarget.dataset.enableTime)
         | 
| 27 93 |  | 
| 28 94 | 
             
                // Set the format of the displayed input field.
         | 
| 29 | 
            -
                options.altFormat = this. | 
| 95 | 
            +
                options.altFormat = this.pickerFormatValue
         | 
| 30 96 |  | 
| 31 97 | 
             
                // Disable native input in mobile browsers
         | 
| 32 | 
            -
                options.disableMobile = this. | 
| 98 | 
            +
                options.disableMobile = this.disableMobileValue
         | 
| 33 99 |  | 
| 34 100 | 
             
                // Set first day of the week.
         | 
| 35 | 
            -
                options.locale.firstDayOfWeek = this. | 
| 101 | 
            +
                options.locale.firstDayOfWeek = this.firstDayOfWeekValue
         | 
| 36 102 |  | 
| 37 103 | 
             
                // Enable time if needed.
         | 
| 38 | 
            -
                options.enableTime =  | 
| 39 | 
            -
                options.enableSeconds =  | 
| 40 | 
            -
             | 
| 41 | 
            -
                let currentValue
         | 
| 104 | 
            +
                options.enableTime = this.enableTimeValue
         | 
| 105 | 
            +
                options.enableSeconds = this.enableTimeValue
         | 
| 42 106 |  | 
| 43 107 | 
             
                // enable timezone display
         | 
| 44 | 
            -
                if ( | 
| 45 | 
            -
                   | 
| 46 | 
            -
                   | 
| 47 | 
            -
                  currentValue = currentValue.toISO()
         | 
| 108 | 
            +
                if (this.enableTimeValue) {
         | 
| 109 | 
            +
                  console.log(1)
         | 
| 110 | 
            +
                  options.defaultDate = this.parsedValue.setZone(this.displayTimezone).toISO()
         | 
| 48 111 |  | 
| 49 112 | 
             
                  options.dateFormat = 'Y-m-d H:i:S'
         | 
| 50 | 
            -
                  // eslint-disable-next-line camelcase
         | 
| 51 | 
            -
                  options.time_24hr = castBoolean(this.inputTarget.dataset.time24hr)
         | 
| 52 | 
            -
                  // this.timezone = Intl.DateTimeFormat().resolvedOptions().timeZone
         | 
| 53 | 
            -
                  options.appTimezone = this.inputTarget.dataset.timezone
         | 
| 54 113 | 
             
                } else {
         | 
| 55 | 
            -
                   | 
| 114 | 
            +
                  console.log(2)
         | 
| 115 | 
            +
             | 
| 116 | 
            +
                  // 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.
         | 
| 56 117 | 
             
                  // Ex: 2022-01-30 will render as 2022-01-29 on an American timezone
         | 
| 57 | 
            -
                   | 
| 118 | 
            +
                  options.defaultDate = universalTimestamp(this.initialValue)
         | 
| 58 119 | 
             
                }
         | 
| 59 120 |  | 
| 60 | 
            -
                 | 
| 121 | 
            +
                flatpickr(this.fakeInputTarget, options)
         | 
| 122 | 
            +
             | 
| 123 | 
            +
                this.updateRealInput(this.parsedValue.setZone(this.displayTimezone).toISO())
         | 
| 124 | 
            +
              }
         | 
| 125 | 
            +
             | 
| 126 | 
            +
              onChange(selectedDates) {
         | 
| 127 | 
            +
                let time
         | 
| 128 | 
            +
                let args = {}
         | 
| 129 | 
            +
             | 
| 130 | 
            +
                if (this.timezoneValue) {
         | 
| 131 | 
            +
                  args = { keepLocalTime: true }
         | 
| 132 | 
            +
                } else {
         | 
| 133 | 
            +
                  args = { keepLocalTime: false }
         | 
| 134 | 
            +
                }
         | 
| 135 | 
            +
             | 
| 136 | 
            +
                if (this.enableTimeValue) {
         | 
| 137 | 
            +
                  time = DateTime.fromISO(selectedDates[0].toISOString()).setZone('UTC', args)
         | 
| 138 | 
            +
                } else {
         | 
| 139 | 
            +
                  time = DateTime.fromISO(selectedDates[0].toISOString()).setZone('UTC', { keepLocalTime: true })
         | 
| 140 | 
            +
                }
         | 
| 141 | 
            +
             | 
| 142 | 
            +
                this.updateRealInput(time)
         | 
| 143 | 
            +
              }
         | 
| 61 144 |  | 
| 62 | 
            -
             | 
| 145 | 
            +
              updateRealInput(value) {
         | 
| 146 | 
            +
                this.inputTarget.value = value
         | 
| 63 147 | 
             
              }
         | 
| 64 148 | 
             
            }
         | 
| @@ -1,6 +1,6 @@ | |
| 1 1 | 
             
            <%= javascript_tag nonce: true do %>
         | 
| 2 2 | 
             
              window.Avo = window.Avo || { configuration: {} }
         | 
| 3 3 | 
             
              Avo.configuration.timezone = '<%= Avo.configuration.timezone %>'
         | 
| 4 | 
            -
              Avo.configuration.root_path = '<%=  | 
| 4 | 
            +
              Avo.configuration.root_path = '<%= root_path_without_url %>'
         | 
| 5 5 | 
             
              Avo.configuration.search_debounce = '<%= Avo.configuration.search_debounce %>'
         | 
| 6 6 | 
             
            <% end %>
         | 
    
        data/config/routes.rb
    CHANGED
    
    | @@ -16,16 +16,17 @@ Avo::Engine.routes.draw do | |
| 16 16 | 
             
                post "/resources/:resource_name/:id/attachments/", to: "attachments#create"
         | 
| 17 17 | 
             
              end
         | 
| 18 18 |  | 
| 19 | 
            +
              # Records ordering
         | 
| 20 | 
            +
              scope "reorder", as: "reorder" do
         | 
| 21 | 
            +
                patch "/:resource_name/:id", to: "reorder#order", as: "order"
         | 
| 22 | 
            +
              end
         | 
| 23 | 
            +
             | 
| 19 24 | 
             
              get "failed_to_load", to: "home#failed_to_load"
         | 
| 20 25 |  | 
| 21 26 | 
             
              scope "resources", as: "resources" do
         | 
| 22 27 | 
             
                # Attachments
         | 
| 23 28 | 
             
                delete "/:resource_name/:id/active_storage_attachments/:attachment_name/:attachment_id", to: "attachments#destroy"
         | 
| 24 29 |  | 
| 25 | 
            -
                # Ordering
         | 
| 26 | 
            -
                patch "/:resource_name/:id/order", to: "resources#order", as: "order"
         | 
| 27 | 
            -
                patch "/:resource_name/:id/:related_name/:related_id/order", to: "associations#order", as: "associations_order"
         | 
| 28 | 
            -
             | 
| 29 30 | 
             
                # Actions
         | 
| 30 31 | 
             
                get "/:resource_name(/:id)/actions/:action_id", to: "actions#show"
         | 
| 31 32 | 
             
                post "/:resource_name(/:id)/actions/:action_id", to: "actions#handle"
         | 
    
        data/db/factories.rb
    CHANGED
    
    
    
        data/lib/avo/app.rb
    CHANGED
    
    | @@ -20,8 +20,6 @@ module Avo | |
| 20 20 | 
             
                  def boot
         | 
| 21 21 | 
             
                    init_fields
         | 
| 22 22 |  | 
| 23 | 
            -
                    I18n.locale = Avo.configuration.language_code
         | 
| 24 | 
            -
             | 
| 25 23 | 
             
                    if Rails.cache.instance_of?(ActiveSupport::Cache::NullStore)
         | 
| 26 24 | 
             
                      self.cache_store ||= ActiveSupport::Cache::MemoryStore.new
         | 
| 27 25 | 
             
                    else
         | 
| @@ -172,7 +170,7 @@ module Avo | |
| 172 170 | 
             
                    payload[:license_abilities] = Avo::App&.license&.abilities
         | 
| 173 171 | 
             
                    payload[:cache_store] = self.cache_store&.class&.to_s
         | 
| 174 172 | 
             
                    payload[:avo_metadata] = hq&.avo_metadata
         | 
| 175 | 
            -
                    payload[:app_timezone] = Time. | 
| 173 | 
            +
                    payload[:app_timezone] = Time.current.zone
         | 
| 176 174 | 
             
                    payload[:cache_key] = Avo::Licensing::HQ.cache_key
         | 
| 177 175 | 
             
                    payload[:cache_key_contents] = hq&.cached_response
         | 
| 178 176 |  | 
    
        data/lib/avo/base_action.rb
    CHANGED
    
    | @@ -1,7 +1,5 @@ | |
| 1 1 | 
             
            module Avo
         | 
| 2 2 | 
             
              class BaseAction
         | 
| 3 | 
            -
                extend HasContext
         | 
| 4 | 
            -
             | 
| 5 3 | 
             
                include Avo::Concerns::HasFields
         | 
| 6 4 |  | 
| 7 5 | 
             
                class_attribute :name, default: nil
         | 
| @@ -23,8 +21,16 @@ module Avo | |
| 23 21 | 
             
                attr_accessor :user
         | 
| 24 22 |  | 
| 25 23 | 
             
                delegate :view, to: :class
         | 
| 24 | 
            +
                delegate :context, to: ::Avo::App
         | 
| 25 | 
            +
                delegate :current_user, to: ::Avo::App
         | 
| 26 | 
            +
                delegate :params, to: ::Avo::App
         | 
| 27 | 
            +
                delegate :view_context, to: ::Avo::App
         | 
| 28 | 
            +
                delegate :avo, to: :view_context
         | 
| 29 | 
            +
                delegate :main_app, to: :view_context
         | 
| 26 30 |  | 
| 27 31 | 
             
                class << self
         | 
| 32 | 
            +
                  delegate :context, to: ::Avo::App
         | 
| 33 | 
            +
             | 
| 28 34 | 
             
                  def form_data_attributes
         | 
| 29 35 | 
             
                    # We can't respond with a file download from Turbo se we disable it on the form
         | 
| 30 36 | 
             
                    if may_download_file
         | 
| @@ -64,10 +70,6 @@ module Avo | |
| 64 70 | 
             
                  @response[:messages] = []
         | 
| 65 71 | 
             
                end
         | 
| 66 72 |  | 
| 67 | 
            -
                def context
         | 
| 68 | 
            -
                  self.class.context
         | 
| 69 | 
            -
                end
         | 
| 70 | 
            -
             | 
| 71 73 | 
             
                def get_attributes_for_action
         | 
| 72 74 | 
             
                  get_fields.map do |field|
         | 
| 73 75 | 
             
                    [field.id, field.value]
         | 
    
        data/lib/avo/base_resource.rb
    CHANGED
    
    | @@ -1,7 +1,6 @@ | |
| 1 1 | 
             
            module Avo
         | 
| 2 2 | 
             
              class BaseResource
         | 
| 3 3 | 
             
                extend ActiveSupport::DescendantsTracker
         | 
| 4 | 
            -
                extend HasContext
         | 
| 5 4 |  | 
| 6 5 | 
             
                include ActionView::Helpers::UrlHelper
         | 
| 7 6 | 
             
                include Avo::Concerns::HasModel
         | 
| @@ -10,12 +9,15 @@ module Avo | |
| 10 9 | 
             
                include Avo::Concerns::ModelClassConstantized
         | 
| 11 10 |  | 
| 12 11 | 
             
                delegate :view_context, to: ::Avo::App
         | 
| 12 | 
            +
                delegate :current_user, to: ::Avo::App
         | 
| 13 | 
            +
                delegate :params, to: ::Avo::App
         | 
| 13 14 | 
             
                delegate :simple_format, :content_tag, to: :view_context
         | 
| 14 15 | 
             
                delegate :main_app, to: :view_context
         | 
| 15 16 | 
             
                delegate :avo, to: :view_context
         | 
| 16 17 | 
             
                delegate :resource_path, to: :view_context
         | 
| 17 18 | 
             
                delegate :resources_path, to: :view_context
         | 
| 18 19 | 
             
                delegate :t, to: ::I18n
         | 
| 20 | 
            +
                delegate :context, to: ::Avo::App
         | 
| 19 21 |  | 
| 20 22 | 
             
                attr_accessor :view
         | 
| 21 23 | 
             
                attr_accessor :model
         | 
| @@ -48,6 +50,7 @@ module Avo | |
| 48 50 |  | 
| 49 51 | 
             
                class << self
         | 
| 50 52 | 
             
                  delegate :t, to: ::I18n
         | 
| 53 | 
            +
                  delegate :context, to: ::Avo::App
         | 
| 51 54 |  | 
| 52 55 | 
             
                  def grid(&block)
         | 
| 53 56 | 
             
                    grid_collector = GridCollector.new
         | 
| @@ -101,7 +104,7 @@ module Avo | |
| 101 104 |  | 
| 102 105 | 
             
                def initialize
         | 
| 103 106 | 
             
                  unless self.class.model_class.present?
         | 
| 104 | 
            -
                    if model_class.present?
         | 
| 107 | 
            +
                    if model_class.present? && model_class.respond_to?(:base_class)
         | 
| 105 108 | 
             
                      self.class.model_class = model_class.base_class
         | 
| 106 109 | 
             
                    end
         | 
| 107 110 | 
             
                  end
         | 
| @@ -153,7 +156,7 @@ module Avo | |
| 153 156 | 
             
                end
         | 
| 154 157 |  | 
| 155 158 | 
             
                def class_name_without_resource
         | 
| 156 | 
            -
                  self.class.name.demodulize. | 
| 159 | 
            +
                  self.class.name.demodulize.delete_suffix("Resource")
         | 
| 157 160 | 
             
                end
         | 
| 158 161 |  | 
| 159 162 | 
             
                def model_class
         | 
| @@ -199,7 +202,7 @@ module Avo | |
| 199 202 | 
             
                end
         | 
| 200 203 |  | 
| 201 204 | 
             
                def name
         | 
| 202 | 
            -
                  default = class_name_without_resource. | 
| 205 | 
            +
                  default = class_name_without_resource.to_s.gsub('::', ' ').underscore.humanize
         | 
| 203 206 |  | 
| 204 207 | 
             
                  return @name if @name.present?
         | 
| 205 208 |  | 
| @@ -242,10 +245,6 @@ module Avo | |
| 242 245 | 
             
                  view_types
         | 
| 243 246 | 
             
                end
         | 
| 244 247 |  | 
| 245 | 
            -
                def context
         | 
| 246 | 
            -
                  self.class.context
         | 
| 247 | 
            -
                end
         | 
| 248 | 
            -
             | 
| 249 248 | 
             
                def attached_file_fields
         | 
| 250 249 | 
             
                  get_field_definitions.select do |field|
         | 
| 251 250 | 
             
                    [Avo::Fields::FileField, Avo::Fields::FilesField].include? field.class
         | 
| @@ -28,7 +28,7 @@ module Avo | |
| 28 28 | 
             
                    add_prop_from_args args, name: name, default: default, type: :array
         | 
| 29 29 | 
             
                  end
         | 
| 30 30 |  | 
| 31 | 
            -
                  def add_string_prop(args, name, default =  | 
| 31 | 
            +
                  def add_string_prop(args, name, default = nil)
         | 
| 32 32 | 
             
                    add_prop_from_args args, name: name, default: default, type: :string
         | 
| 33 33 | 
             
                  end
         | 
| 34 34 | 
             
                end
         | 
| @@ -183,6 +183,7 @@ module Avo | |
| 183 183 | 
             
                          if field.is_a?(Avo::Fields::BelongsToField)
         | 
| 184 184 | 
             
                            if field.respond_to?(:foreign_key) &&
         | 
| 185 185 | 
             
                                reflection.inverse_of.present? &&
         | 
| 186 | 
            +
                                reflection.inverse_of.respond_to?(:foreign_key) &&
         | 
| 186 187 | 
             
                                reflection.inverse_of.foreign_key == field.foreign_key
         | 
| 187 188 | 
             
                              is_valid = false
         | 
| 188 189 | 
             
                            end
         | 
| @@ -191,6 +192,7 @@ module Avo | |
| 191 192 | 
             
                            if field.respond_to?(:foreign_key) &&
         | 
| 192 193 | 
             
                                field.is_polymorphic? &&
         | 
| 193 194 | 
             
                                reflection.respond_to?(:polymorphic?) &&
         | 
| 195 | 
            +
                                reflection.inverse_of.respond_to?(:foreign_key) &&
         | 
| 194 196 | 
             
                                reflection.inverse_of.foreign_key == field.reflection.foreign_key
         | 
| 195 197 | 
             
                              is_valid = false
         | 
| 196 198 | 
             
                            end
         | 
    
        data/lib/avo/configuration.rb
    CHANGED
    
    | @@ -40,7 +40,7 @@ module Avo | |
| 40 40 | 
             
                  @per_page = 24
         | 
| 41 41 | 
             
                  @per_page_steps = [12, 24, 48, 72]
         | 
| 42 42 | 
             
                  @via_per_page = 8
         | 
| 43 | 
            -
                  @locale =  | 
| 43 | 
            +
                  @locale = nil
         | 
| 44 44 | 
             
                  @currency = "USD"
         | 
| 45 45 | 
             
                  @default_view_type = :table
         | 
| 46 46 | 
             
                  @license = "community"
         | 
| @@ -78,16 +78,6 @@ module Avo | |
| 78 78 | 
             
                  @profile_menu = nil
         | 
| 79 79 | 
             
                end
         | 
| 80 80 |  | 
| 81 | 
            -
                def locale_tag
         | 
| 82 | 
            -
                  ::ISO::Tag.new(locale)
         | 
| 83 | 
            -
                end
         | 
| 84 | 
            -
             | 
| 85 | 
            -
                def language_code
         | 
| 86 | 
            -
                  locale_tag.language.code
         | 
| 87 | 
            -
                rescue
         | 
| 88 | 
            -
                  "en"
         | 
| 89 | 
            -
                end
         | 
| 90 | 
            -
             | 
| 91 81 | 
             
                def current_user_method(&block)
         | 
| 92 82 | 
             
                  @current_user = block if block.present?
         | 
| 93 83 | 
             
                end
         | 
| @@ -123,7 +113,7 @@ module Avo | |
| 123 113 | 
             
                end
         | 
| 124 114 |  | 
| 125 115 | 
             
                def computed_root_path
         | 
| 126 | 
            -
                  Avo | 
| 116 | 
            +
                  Avo.configuration.root_path
         | 
| 127 117 | 
             
                end
         | 
| 128 118 |  | 
| 129 119 | 
             
                def feature_enabled?(feature)
         | 
| @@ -10,21 +10,23 @@ module Avo | |
| 10 10 | 
             
                  def initialize(id, **args, &block)
         | 
| 11 11 | 
             
                    super(id, **args, &block)
         | 
| 12 12 |  | 
| 13 | 
            -
                     | 
| 14 | 
            -
                     | 
| 15 | 
            -
                     | 
| 16 | 
            -
                     | 
| 17 | 
            -
                     | 
| 13 | 
            +
                    add_string_prop args, :first_day_of_week, 0
         | 
| 14 | 
            +
                    add_string_prop args, :picker_format, "Y-m-d"
         | 
| 15 | 
            +
                    add_string_prop args, :format, "yyyy-LL-dd"
         | 
| 16 | 
            +
                    add_boolean_prop args, :relative
         | 
| 17 | 
            +
                    add_boolean_prop args, :disable_mobile
         | 
| 18 18 | 
             
                  end
         | 
| 19 19 |  | 
| 20 20 | 
             
                  def formatted_value
         | 
| 21 21 | 
             
                    return if value.blank?
         | 
| 22 22 |  | 
| 23 | 
            -
                     | 
| 24 | 
            -
             | 
| 25 | 
            -
             | 
| 26 | 
            -
             | 
| 27 | 
            -
                     | 
| 23 | 
            +
                    value.iso8601
         | 
| 24 | 
            +
                  end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                  def edit_formatted_value
         | 
| 27 | 
            +
                    return nil if value.nil?
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                    value.iso8601
         | 
| 28 30 | 
             
                  end
         | 
| 29 31 | 
             
                end
         | 
| 30 32 | 
             
              end
         | 
| @@ -2,25 +2,29 @@ module Avo | |
| 2 2 | 
             
              module Fields
         | 
| 3 3 | 
             
                class DateTimeField < DateField
         | 
| 4 4 | 
             
                  attr_reader :format
         | 
| 5 | 
            +
                  attr_reader :picker_format
         | 
| 5 6 | 
             
                  attr_reader :time_24hr
         | 
| 6 7 | 
             
                  attr_reader :timezone
         | 
| 7 8 |  | 
| 8 9 | 
             
                  def initialize(id, **args, &block)
         | 
| 9 10 | 
             
                    super(id, **args, &block)
         | 
| 10 11 |  | 
| 11 | 
            -
                     | 
| 12 | 
            -
                     | 
| 13 | 
            -
                     | 
| 12 | 
            +
                    add_boolean_prop args, :time_24hr
         | 
| 13 | 
            +
                    add_string_prop args, :picker_format, "Y-m-d H:i:S"
         | 
| 14 | 
            +
                    add_string_prop args, :format, "yyyy-LL-dd TT"
         | 
| 15 | 
            +
                    add_string_prop args, :timezone
         | 
| 14 16 | 
             
                  end
         | 
| 15 17 |  | 
| 16 18 | 
             
                  def formatted_value
         | 
| 17 19 | 
             
                    return nil if value.nil?
         | 
| 18 20 |  | 
| 19 | 
            -
                     | 
| 20 | 
            -
             | 
| 21 | 
            -
             | 
| 22 | 
            -
             | 
| 23 | 
            -
                     | 
| 21 | 
            +
                    value.utc.to_time.iso8601
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  def edit_formatted_value
         | 
| 25 | 
            +
                    return nil if value.nil?
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                    value.utc.iso8601
         | 
| 24 28 | 
             
                  end
         | 
| 25 29 |  | 
| 26 30 | 
             
                  def fill_field(model, key, value, params)
         | 
| @@ -32,10 +36,18 @@ module Avo | |
| 32 36 |  | 
| 33 37 | 
             
                    return model if value.blank?
         | 
| 34 38 |  | 
| 35 | 
            -
                    model[id] = value | 
| 39 | 
            +
                    model[id] = utc_time(value)
         | 
| 36 40 |  | 
| 37 41 | 
             
                    model
         | 
| 38 42 | 
             
                  end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                  def utc_time(value)
         | 
| 45 | 
            +
                    if timezone.present?
         | 
| 46 | 
            +
                      ActiveSupport::TimeZone.new(timezone).local_to_utc(Time.parse(value))
         | 
| 47 | 
            +
                    else
         | 
| 48 | 
            +
                      value
         | 
| 49 | 
            +
                    end
         | 
| 50 | 
            +
                  end
         | 
| 39 51 | 
             
                end
         | 
| 40 52 | 
             
              end
         | 
| 41 53 | 
             
            end
         | 
| @@ -0,0 +1,17 @@ | |
| 1 | 
            +
            module Avo
         | 
| 2 | 
            +
              module Fields
         | 
| 3 | 
            +
                module FieldExtensions
         | 
| 4 | 
            +
                  module HasIncludeBlank
         | 
| 5 | 
            +
                    def include_blank
         | 
| 6 | 
            +
                      if @args[:include_blank] == true
         | 
| 7 | 
            +
                        placeholder || '—'
         | 
| 8 | 
            +
                      elsif @args[:include_blank] == false
         | 
| 9 | 
            +
                        false
         | 
| 10 | 
            +
                      else
         | 
| 11 | 
            +
                        @args[:include_blank]
         | 
| 12 | 
            +
                      end
         | 
| 13 | 
            +
                    end
         | 
| 14 | 
            +
                  end
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
              end
         | 
| 17 | 
            +
            end
         | 
| @@ -6,6 +6,7 @@ module Avo | |
| 6 6 | 
             
                  attr_accessor :is_image
         | 
| 7 7 | 
             
                  attr_accessor :is_audio
         | 
| 8 8 | 
             
                  attr_accessor :direct_upload
         | 
| 9 | 
            +
                  attr_accessor :accept
         | 
| 9 10 |  | 
| 10 11 | 
             
                  def initialize(id, **args, &block)
         | 
| 11 12 | 
             
                    super(id, **args, &block)
         | 
| @@ -15,6 +16,7 @@ module Avo | |
| 15 16 | 
             
                    @is_image = args[:is_image].present? ? args[:is_image] : @is_avatar
         | 
| 16 17 | 
             
                    @is_audio = args[:is_audio].present? ? args[:is_audio] : false
         | 
| 17 18 | 
             
                    @direct_upload = args[:direct_upload].present? ? args[:direct_upload] : false
         | 
| 19 | 
            +
                    @accept = args[:accept].present? ? args[:accept] : nil
         | 
| 18 20 | 
             
                  end
         | 
| 19 21 |  | 
| 20 22 | 
             
                  def path
         | 
| @@ -4,6 +4,7 @@ module Avo | |
| 4 4 | 
             
                  attr_accessor :is_audio
         | 
| 5 5 | 
             
                  attr_accessor :is_image
         | 
| 6 6 | 
             
                  attr_accessor :direct_upload
         | 
| 7 | 
            +
                  attr_accessor :accept
         | 
| 7 8 |  | 
| 8 9 | 
             
                  def initialize(id, **args, &block)
         | 
| 9 10 | 
             
                    super(id, **args, &block)
         | 
| @@ -11,6 +12,7 @@ module Avo | |
| 11 12 | 
             
                    @is_audio = args[:is_audio].present? ? args[:is_audio] : false
         | 
| 12 13 | 
             
                    @is_image = args[:is_image].present? ? args[:is_image] : @is_avatar
         | 
| 13 14 | 
             
                    @direct_upload = args[:direct_upload].present? ? args[:direct_upload] : false
         | 
| 15 | 
            +
                    @accept = args[:accept].present? ? args[:accept] : nil
         | 
| 14 16 | 
             
                  end
         | 
| 15 17 |  | 
| 16 18 | 
             
                  def view_component_name
         | 
    
        data/lib/avo/licensing/h_q.rb
    CHANGED
    
    | @@ -121,6 +121,8 @@ module Avo | |
| 121 121 | 
             
                      cache_and_return_error "HTTP connection reset error.", exception.message
         | 
| 122 122 | 
             
                    rescue Errno::ECONNREFUSED => exception
         | 
| 123 123 | 
             
                      cache_and_return_error "HTTP connection refused error.", exception.message
         | 
| 124 | 
            +
                    rescue OpenSSL::SSL::SSLError => exception
         | 
| 125 | 
            +
                      cache_and_return_error "OpenSSL error.", exception.message
         | 
| 124 126 | 
             
                    rescue HTTParty::Error => exception
         | 
| 125 127 | 
             
                      cache_and_return_error "HTTP client error.", exception.message
         | 
| 126 128 | 
             
                    rescue Net::OpenTimeout => exception
         | 
    
        data/lib/avo/version.rb
    CHANGED
    
    
| @@ -1,9 +1,10 @@ | |
| 1 | 
            -
             | 
| 1 | 
            +
            require_relative "named_base_generator"
         | 
| 2 2 |  | 
| 3 3 | 
             
            module Generators
         | 
| 4 4 | 
             
              module Avo
         | 
| 5 | 
            -
                class ActionGenerator <  | 
| 5 | 
            +
                class ActionGenerator < NamedBaseGenerator
         | 
| 6 6 | 
             
                  source_root File.expand_path("templates", __dir__)
         | 
| 7 | 
            +
             | 
| 7 8 | 
             
                  class_option :standalone, type: :boolean
         | 
| 8 9 |  | 
| 9 10 | 
             
                  namespace "avo:action"
         | 
| @@ -0,0 +1,18 @@ | |
| 1 | 
            +
            require_relative "../named_base_generator"
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Generators
         | 
| 4 | 
            +
              module Avo
         | 
| 5 | 
            +
                module Card
         | 
| 6 | 
            +
                  class ChartkickGenerator < Generators::Avo::NamedBaseGenerator
         | 
| 7 | 
            +
                    source_root File.expand_path("../templates", __dir__)
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                    namespace "avo:card:chartkick"
         | 
| 10 | 
            +
                    desc "Add a chartkick card for your Avo dashboard."
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                    def handle
         | 
| 13 | 
            +
                      template "cards/chartkick_card_sample.tt", "app/avo/cards/#{name.underscore}.rb"
         | 
| 14 | 
            +
                    end
         | 
| 15 | 
            +
                  end
         | 
| 16 | 
            +
                end
         | 
| 17 | 
            +
              end
         | 
| 18 | 
            +
            end
         |