diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 06d8630b5e..0a2ed2d147 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,4 +1,8 @@ +blank_issues_enabled: false contact_links: + - name: Ask a question + url: https://github.com/avo-hq/avo/discussions + about: Ask questions and discuss with other community members - name: Priority Support url: https://avohq.io/support about: Get fast support from the authors of Avo diff --git a/.github/workflows/i18n-tests.yml b/.github/workflows/i18n-tests.yml index 4d7fd49842..58fe52afcd 100644 --- a/.github/workflows/i18n-tests.yml +++ b/.github/workflows/i18n-tests.yml @@ -106,12 +106,12 @@ jobs: id: run_tests run: bundle exec rspec spec/system/i18n_spec.rb - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: coverage_system_${{ matrix.rails }}_ruby_${{ matrix.ruby }} path: coverage/.resultset.json - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 if: always() && steps.run_tests.outcome == 'failure' with: name: rspec_failed_screenshots_rails_${{ matrix.rails }}_ruby_${{ matrix.ruby }} diff --git a/.github/workflows/system-tests.yml b/.github/workflows/system-tests.yml index 66a06de509..91193e02ab 100644 --- a/.github/workflows/system-tests.yml +++ b/.github/workflows/system-tests.yml @@ -111,12 +111,12 @@ jobs: id: run_tests run: bundle exec rspec spec/system/ --tag=~i18n - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: coverage_system_${{ matrix.rails }}_ruby_${{ matrix.ruby }} path: coverage/.resultset.json - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 if: always() && steps.run_tests.outcome == 'failure' with: name: rspec_failed_screenshots_rails_${{ matrix.rails }}_ruby_${{ matrix.ruby }} diff --git a/.gitignore b/.gitignore index 8e5fdcceb7..72c37ca3c3 100644 --- a/.gitignore +++ b/.gitignore @@ -77,3 +77,4 @@ brakeman_results.html .env .env.test +*~ diff --git a/Appraisals b/Appraisals index d68c9d12ae..b8ba507b1e 100644 --- a/Appraisals +++ b/Appraisals @@ -9,6 +9,12 @@ gem "activestorage", "~> #{rails_version}" gem "activestorage" gem "acts-as-taggable-on" + + if rails_version == "6.1" + # Fix `': uninitialized constant ActiveSupport::LoggerThreadSafeLevel::Logger (NameError) + # https://stackoverflow.com/questions/79360526/uninitialized-constant-activesupportloggerthreadsafelevellogger-nameerror + gem "concurrent-ruby", "1.3.4" + end end end end diff --git a/Gemfile b/Gemfile index 814760193b..3d6c2b2c29 100644 --- a/Gemfile +++ b/Gemfile @@ -175,7 +175,7 @@ gem "image_processing", "~> 1.12" gem "prefixed_ids" gem "mapkick-rb", "~> 0.1.4" - +gem "mapkick-static" gem "pluggy", path: "./pluggy" gem "hashid-rails", "~> 1.4", ">= 1.4.1" diff --git a/Gemfile.lock b/Gemfile.lock index e2f1983218..a3086f7bab 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - avo (3.16.1) + avo (3.17.6) actionview (>= 6.1) active_link_to activerecord (>= 6.1) @@ -107,10 +107,12 @@ GEM acts_as_list (1.2.4) activerecord (>= 6.1) activesupport (>= 6.1) - actual_db_schema (0.8.0) + actual_db_schema (0.8.2) activerecord activesupport + ast csv + parser addressable (2.8.7) public_suffix (>= 2.0.2, < 7.0) amazing_print (1.7.2) @@ -126,20 +128,21 @@ GEM money-rails (~> 1.12) avo-record_link_field (0.0.2) aws-eventstream (1.3.0) - aws-partitions (1.1033.0) - aws-sdk-core (3.214.1) + aws-partitions (1.1050.0) + aws-sdk-core (3.218.1) aws-eventstream (~> 1, >= 1.3.0) aws-partitions (~> 1, >= 1.992.0) aws-sigv4 (~> 1.9) + base64 jmespath (~> 1, >= 1.6.1) - aws-sdk-kms (1.96.0) - aws-sdk-core (~> 3, >= 3.210.0) + aws-sdk-kms (1.98.0) + aws-sdk-core (~> 3, >= 3.216.0) aws-sigv4 (~> 1.5) - aws-sdk-s3 (1.177.0) - aws-sdk-core (~> 3, >= 3.210.0) + aws-sdk-s3 (1.180.0) + aws-sdk-core (~> 3, >= 3.216.0) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.5) - aws-sigv4 (1.10.1) + aws-sigv4 (1.11.0) aws-eventstream (~> 1, >= 1.0.2) axiom-types (0.1.1) descendants_tracker (~> 0.0.4) @@ -173,14 +176,14 @@ GEM rack-test (>= 0.6.3) regexp_parser (>= 1.5, < 3.0) xpath (~> 3.2) - chartkick (5.1.2) + chartkick (5.1.3) childprocess (5.1.0) logger (~> 1.5) coercible (1.0.0) descendants_tracker (~> 0.0.1) concurrent-ruby (1.3.5) connection_pool (2.5.0) - countries (7.1.0) + countries (7.1.1) unaccent (~> 0.3) crack (1.0.0) bigdecimal @@ -221,7 +224,7 @@ GEM railties (>= 4.1.0) responders warden (~> 1.2.3) - diff-lcs (1.5.1) + diff-lcs (1.6.0) docile (1.4.1) dotenv (3.1.7) dotenv-rails (3.1.7) @@ -250,17 +253,16 @@ GEM dry-logic (>= 1.4, < 2) dry-types (>= 1.7, < 2) zeitwerk (~> 2.6) - dry-types (1.8.0) + dry-types (1.8.2) bigdecimal (~> 3.0) concurrent-ruby (~> 1.0) dry-core (~> 1.0) dry-inflector (~> 1.0) dry-logic (~> 1.4) zeitwerk (~> 2.6) - e2mmap (0.1.0) erb-formatter (0.7.3) syntax_tree (~> 6.0) - erb_lint (0.8.0) + erb_lint (0.9.0) activesupport better_html (>= 2.0.1) parser (>= 2.7.1.4) @@ -269,8 +271,8 @@ GEM smart_properties erubi (1.13.1) event_stream_parser (1.0.0) - factory_bot (6.5.0) - activesupport (>= 5.0.0) + factory_bot (6.5.1) + activesupport (>= 6.1.0) factory_bot_rails (6.4.4) factory_bot (~> 6.5) railties (>= 5.0.0) @@ -328,7 +330,7 @@ GEM listen (>= 3.0.0) railties (>= 6.0.0) htmlbeautifier (1.4.3) - i18n (1.14.6) + i18n (1.14.7) concurrent-ruby (~> 1.0) i18n-tasks (1.0.14) activesupport (>= 4.0.2) @@ -341,14 +343,15 @@ GEM rainbow (>= 2.2.2, < 4.0) terminal-table (>= 1.5.1) ice_nine (0.11.2) - image_processing (1.13.0) - mini_magick (>= 4.9.5, < 5) + image_processing (1.14.0) + mini_magick (>= 4.9.5, < 6) ruby-vips (>= 2.0.17, < 3) inline_svg (1.10.0) activesupport (>= 3.0) nokogiri (>= 1.6) io-console (0.8.0) - irb (1.14.3) + irb (1.15.1) + pp (>= 0.6.0) rdoc (>= 4.0.0) reline (>= 0.4.2) iso (0.4.0) @@ -357,15 +360,16 @@ GEM jmespath (1.6.2) jsbundling-rails (1.3.1) railties (>= 6.0.0) - json (2.9.1) + json (2.10.1) kramdown (2.5.1) rexml (>= 3.3.9) kramdown-parser-gfm (1.1.0) kramdown (~> 2.0) - language_server-protocol (3.17.0.3) - launchy (3.0.1) + language_server-protocol (3.17.0.4) + launchy (3.1.0) addressable (~> 2.8) childprocess (~> 5.0) + logger (~> 1.6) lint_roller (1.1.0) listen (3.9.0) rb-fsevent (~> 0.10, >= 0.10.3) @@ -380,6 +384,7 @@ GEM net-pop net-smtp mapkick-rb (0.1.5) + mapkick-static (0.1.1) marcel (1.0.4) matrix (0.4.2) memory_profiler (1.1.0) @@ -387,7 +392,9 @@ GEM actionpack (>= 6.0.0, < 8.1) method_source (1.1.0) mini_histogram (0.3.1) - mini_magick (4.13.2) + mini_magick (5.1.2) + benchmark + logger mini_mime (1.1.5) minitest (5.25.4) monetize (1.13.0) @@ -399,46 +406,48 @@ GEM monetize (~> 1.9) money (~> 6.13) railties (>= 3.0) - msgpack (1.7.5) + msgpack (1.8.0) multipart-post (2.4.1) net-http (0.6.0) uri - net-imap (0.5.5) + net-imap (0.5.6) date net-protocol net-pop (0.1.2) net-protocol net-protocol (0.2.2) timeout - net-smtp (0.5.0) + net-smtp (0.5.1) net-protocol nio4r (2.7.4) - nokogiri (1.18.1-arm64-darwin) + nokogiri (1.18.2-arm64-darwin) racc (~> 1.4) - nokogiri (1.18.1-x86_64-linux-gnu) + nokogiri (1.18.2-x86_64-linux-gnu) racc (~> 1.4) + observer (0.1.2) orm_adapter (0.5.0) + ostruct (0.6.1) pagy (9.3.3) parallel (1.26.3) - parser (3.3.6.0) + parser (3.3.7.1) ast (~> 2.4.1) racc path_expander (1.1.3) pg (1.5.9) + pp (0.6.2) + prettyprint prefixed_ids (1.8.1) hashids (>= 1.0.0, < 2.0.0) rails (>= 6.0.0) prettier_print (1.2.1) + prettyprint (0.2.0) prop_initializer (0.2.0) zeitwerk (>= 2.6.18) - psych (5.2.3) - date - stringio public_suffix (6.0.1) - puma (6.5.0) + puma (6.6.0) nio4r (~> 2.0) racc (1.8.1) - rack (3.1.8) + rack (3.1.10) rack-session (2.1.0) base64 (>= 0.1.0) rack (>= 3.0.0) @@ -484,22 +493,23 @@ GEM zeitwerk (~> 2.6) rainbow (3.1.1) rake (13.2.1) - ransack (4.2.1) + ransack (4.3.0) activerecord (>= 6.1.5) activesupport (>= 6.1.5) i18n rb-fsevent (0.11.2) rb-inotify (0.11.1) ffi (~> 1.0) - rbs (2.8.4) + rbs (3.8.1) + logger rdoc (6.11.0) - psych (>= 4.0.0) redis (5.3.0) redis-client (>= 0.22.0) - redis-client (0.23.0) + redis-client (0.23.2) connection_pool - reek (6.3.0) + reek (6.4.0) dry-schema (~> 1.13.0) + logger (~> 1.6) parser (~> 3.3.0) rainbow (>= 2.0, < 4.0) rexml (~> 3.1) @@ -509,11 +519,11 @@ GEM responders (3.1.1) actionpack (>= 5.2) railties (>= 5.2) - reverse_markdown (2.1.1) + reverse_markdown (3.0.0) nokogiri rexml (3.4.0) ripper-tags (1.0.2) - rspec-core (3.13.2) + rspec-core (3.13.3) rspec-support (~> 3.13.0) rspec-expectations (3.13.3) diff-lcs (>= 1.2.0, < 2.0) @@ -532,30 +542,30 @@ GEM rspec-retry (0.6.2) rspec-core (> 3.3) rspec-support (3.13.2) - rubocop (1.69.2) + rubocop (1.71.2) json (~> 2.3) language_server-protocol (>= 3.17.0) parallel (~> 1.10) parser (>= 3.3.0.2) rainbow (>= 2.2.2, < 4.0) regexp_parser (>= 2.9.3, < 3.0) - rubocop-ast (>= 1.36.2, < 2.0) + rubocop-ast (>= 1.38.0, < 2.0) ruby-progressbar (~> 1.7) unicode-display_width (>= 2.4.0, < 4.0) - rubocop-ast (1.37.0) + rubocop-ast (1.38.0) parser (>= 3.3.1.0) rubocop-performance (1.23.1) rubocop (>= 1.48.1, < 2.0) rubocop-ast (>= 1.31.1, < 2.0) rubocop-shopify (2.15.1) rubocop (~> 1.51) - ruby-openai (7.3.1) + ruby-openai (7.4.0) event_stream_parser (>= 0.3.0, < 2.0.0) faraday (>= 1) faraday-multipart (>= 1) ruby-progressbar (1.13.0) ruby-statistics (3.0.2) - ruby-vips (2.2.2) + ruby-vips (2.2.3) ffi (~> 1.12) logger ruby_parser (3.21.1) @@ -586,18 +596,20 @@ GEM simplecov-lcov (0.8.0) simplecov_json_formatter (0.1.4) smart_properties (1.17.0) - solargraph (0.50.0) + solargraph (0.51.2) backport (~> 1.2) benchmark bundler (~> 2.0) diff-lcs (~> 1.4) - e2mmap - jaro_winkler (~> 1.5) + jaro_winkler (~> 1.6) kramdown (~> 2.3) kramdown-parser-gfm (~> 1.1) + logger (~> 1.6) + observer (~> 0.1) + ostruct (~> 0.6) parser (~> 3.0) - rbs (~> 2.0) - reverse_markdown (~> 2.0) + rbs (~> 3.0) + reverse_markdown (>= 2.0, < 4) rubocop (~> 1.38) thor (~> 1.0) tilt (~> 2.0) @@ -615,10 +627,10 @@ GEM actionpack (>= 6.1) activesupport (>= 6.1) sprockets (>= 3.0.0) - standard (1.43.0) + standard (1.45.0) language_server-protocol (~> 3.17.0.2) lint_roller (~> 1.0) - rubocop (~> 1.69.1) + rubocop (~> 1.71.0) standard-custom (~> 1.0.0) standard-performance (~> 1.6) standard-custom (1.0.2) @@ -627,15 +639,14 @@ GEM standard-performance (1.6.0) lint_roller (~> 1.1) rubocop-performance (~> 1.23.0) - stringio (3.1.2) syntax_tree (6.2.0) prettier_print (>= 1.2.0) - terminal-table (3.0.2) - unicode-display_width (>= 1.1.1, < 3) + terminal-table (4.0.0) + unicode-display_width (>= 1.1.1, < 4) test-prof (1.4.4) thor (1.3.2) thread_safe (0.3.6) - tilt (2.5.0) + tilt (2.6.0) timeout (0.4.3) tty-which (0.5.0) turbo-rails (2.0.11) @@ -646,7 +657,9 @@ GEM tzinfo (2.0.6) concurrent-ruby (~> 1.0) unaccent (0.4.0) - unicode-display_width (2.6.0) + unicode-display_width (3.1.4) + unicode-emoji (~> 4.0, >= 4.0.4) + unicode-emoji (4.0.4) uri (1.0.2) useragent (0.16.11) view_component (3.21.0) @@ -664,7 +677,7 @@ GEM activemodel (>= 6.0.0) bindex (>= 0.4.0) railties (>= 6.0.0) - webmock (3.24.0) + webmock (3.25.0) addressable (>= 2.8.0) crack (>= 0.3.2) hashdiff (>= 0.4.0, < 2.0.0) @@ -680,6 +693,7 @@ GEM PLATFORMS arm64-darwin-23 + arm64-darwin-24 x86_64-linux DEPENDENCIES @@ -730,6 +744,7 @@ DEPENDENCIES launchy listen (>= 3.5.1) mapkick-rb (~> 0.1.4) + mapkick-static meta-tags money-rails (~> 1.12) net-smtp diff --git a/app/assets/stylesheets/avo.base.css b/app/assets/stylesheets/avo.base.css index 4ed8088797..956131a321 100644 --- a/app/assets/stylesheets/avo.base.css +++ b/app/assets/stylesheets/avo.base.css @@ -93,6 +93,26 @@ dialog#turbo-confirm { @apply bg-transparent; } +dl { + @apply text-sm; + + dt { + @apply font-bold inline-block mt-1; + } + + dd { + @apply inline-block ml-0; + } +} + +/* TODO: make content like tailwindcss */ +.floating-row-controls { + &:before { + content: ""; + @apply absolute z-10 inset-auto left-0 top-0 mt-0 -translate-x-full w-3 h-full bg-gradient-to-l from-white to-transparent group-hover:from-gray-50; + } +} + .shift-pressed { & .highlighted-row { @apply !bg-neutral-200; diff --git a/app/assets/stylesheets/css/fields/trix.css b/app/assets/stylesheets/css/fields/trix.css index 53c2046296..5a4044408f 100644 --- a/app/assets/stylesheets/css/fields/trix.css +++ b/app/assets/stylesheets/css/fields/trix.css @@ -35,3 +35,10 @@ trix-toolbar { @apply ml-0; } } + +/* Hack to remove border from trix when rendered from ActionText */ +.trix-content { + & .trix-content { + border: none; + } +} diff --git a/app/assets/svgs/avo/square-kanban.svg b/app/assets/svgs/avo/square-kanban.svg new file mode 100644 index 0000000000..dcab361ce0 --- /dev/null +++ b/app/assets/svgs/avo/square-kanban.svg @@ -0,0 +1 @@ + diff --git a/app/components/avo/actions_component.rb b/app/components/avo/actions_component.rb index 2e809a809c..9acb59f524 100644 --- a/app/components/avo/actions_component.rb +++ b/app/components/avo/actions_component.rb @@ -102,7 +102,8 @@ def action_data_attributes(action) disabled: action.disabled?, turbo_prefetch: false, enabled_classes: "text-black", - disabled_classes: "text-gray-500" + disabled_classes: "text-gray-500", + resource_name: action.resource.model_key } end diff --git a/app/components/avo/asset_manager/javascript_component.html.erb b/app/components/avo/asset_manager/javascript_component.html.erb index 92ab565571..973877b3f3 100644 --- a/app/components/avo/asset_manager/javascript_component.html.erb +++ b/app/components/avo/asset_manager/javascript_component.html.erb @@ -1,3 +1,12 @@ <% javascripts.each do |path| %> <%= javascript_include_tag path, "data-turbo-track": "reload", defer: true %> <% end %> + +<%# Collect all the custom StimulusJS controllers from plugins. %> +<%= javascript_tag nonce: true do %> + Avo.configuration.stimulus_controllers = <%== Avo.asset_manager.stimulus_controllers.to_a.to_json %> +<% end %> + +<%# This is the last script to run so it can register custom StimulusJS controllers from plugins. %> +<% path = Avo::PACKED ? '/avo-assets/late-registration' : 'late-registration' %> +<%= javascript_include_tag path, "data-turbo-track": "reload", defer: true %> diff --git a/app/components/avo/asset_manager/javascript_component.rb b/app/components/avo/asset_manager/javascript_component.rb index 3de1aa8ee9..b08e80da4a 100644 --- a/app/components/avo/asset_manager/javascript_component.rb +++ b/app/components/avo/asset_manager/javascript_component.rb @@ -4,4 +4,5 @@ class Avo::AssetManager::JavascriptComponent < Avo::BaseComponent prop :asset_manager delegate :javascripts, to: :@asset_manager + delegate :stimulus_controllers, to: :@asset_manager end diff --git a/app/components/avo/base_component.rb b/app/components/avo/base_component.rb index aadcbbaf5c..72dfe5ba75 100644 --- a/app/components/avo/base_component.rb +++ b/app/components/avo/base_component.rb @@ -5,10 +5,17 @@ class Avo::BaseComponent < ViewComponent::Base include Turbo::FramesHelper include Avo::Concerns::FindAssociationField + delegate :e, to: :helpers + delegate :d, to: :helpers + delegate :main_app, to: :helpers + delegate :avo, to: :helpers + def has_with_trial(ability) Avo.license.has_with_trial(ability) end + def component_name = self.class.name.to_s.underscore + private # Use the @parent_resource to fetch the field using the @reflection name. diff --git a/app/components/avo/button_component.rb b/app/components/avo/button_component.rb index 3c913313f7..7613ed1476 100644 --- a/app/components/avo/button_component.rb +++ b/app/components/avo/button_component.rb @@ -1,5 +1,10 @@ # frozen_string_literal: true +# A button/link can have the following settings: +# style: primary/outline/text/icon +# size: :xs :sm, :md, :lg, :xl +# color: :gray, :red, :green, :blue, or any other tailwind color +# icon: "heroicons/outline/paperclip" as specified in the docs (https://docs.avohq.io/3.0/icons.html) class Avo::ButtonComponent < Avo::BaseComponent prop :path, kind: :positional prop :size, default: :md diff --git a/app/components/avo/fields/area_field/edit_component.html.erb b/app/components/avo/fields/area_field/edit_component.html.erb index 28ffcb87e8..5b410aa6d1 100644 --- a/app/components/avo/fields/area_field/edit_component.html.erb +++ b/app/components/avo/fields/area_field/edit_component.html.erb @@ -1,4 +1,4 @@ -<%= field_wrapper **field_wrapper_args do %> +<%= field_wrapper(**field_wrapper_args) do %> <%= @form.text_field field.id, value: field.value.to_s, class: classes("w-full"), diff --git a/app/components/avo/fields/area_field/show_component.html.erb b/app/components/avo/fields/area_field/show_component.html.erb index f4377507c7..0466bf9de5 100644 --- a/app/components/avo/fields/area_field/show_component.html.erb +++ b/app/components/avo/fields/area_field/show_component.html.erb @@ -1,4 +1,4 @@ -<%= field_wrapper **field_wrapper_args do %> +<%= field_wrapper(**field_wrapper_args) do %> <% if field.value.present? %> <%= area_map field.map_data, **field.mapkick_options %> <% else %> diff --git a/app/components/avo/fields/badge_field/index_component.html.erb b/app/components/avo/fields/badge_field/index_component.html.erb index 4fdf9e07b1..6d137ecb98 100644 --- a/app/components/avo/fields/badge_field/index_component.html.erb +++ b/app/components/avo/fields/badge_field/index_component.html.erb @@ -1,3 +1,3 @@ -<%= index_field_wrapper **field_wrapper_args, flush: true do %> +<%= index_field_wrapper(**field_wrapper_args, flush: true) do %> <%= render Avo::Fields::Common::BadgeViewerComponent.new value: @field.value, options: @field.options %> <% end %> diff --git a/app/components/avo/fields/badge_field/show_component.html.erb b/app/components/avo/fields/badge_field/show_component.html.erb index 461a7b8bbe..b18ed6fded 100644 --- a/app/components/avo/fields/badge_field/show_component.html.erb +++ b/app/components/avo/fields/badge_field/show_component.html.erb @@ -1,3 +1,3 @@ -<%= field_wrapper **field_wrapper_args do %> +<%= field_wrapper(**field_wrapper_args) do %> <%= render Avo::Fields::Common::BadgeViewerComponent.new value: @field.value, options: @field.options %> <% end %> diff --git a/app/components/avo/fields/belongs_to_field/edit_component.html.erb b/app/components/avo/fields/belongs_to_field/edit_component.html.erb index b38be635bd..5d7a30e362 100644 --- a/app/components/avo/fields/belongs_to_field/edit_component.html.erb +++ b/app/components/avo/fields/belongs_to_field/edit_component.html.erb @@ -5,7 +5,7 @@ data-association="<%= @field.id %>" data-association-class="<%= @field&.target_resource&.model_class || nil %>" > - <%= field_wrapper **field_wrapper_args, label_for: @field.polymorphic_form_field_label, help: @field.polymorphic_help || '' do %> + <%= field_wrapper(**field_wrapper_args, label_for: @field.polymorphic_form_field_label, help: @field.polymorphic_help || '') do %> <%= @form.select @field.type_input_foreign_key, @field.types.map { |type| [Avo.resource_manager.get_resource_by_model_class(type.to_s).name, type.to_s] }, { value: @field.value, @@ -32,7 +32,7 @@ <% @field.types.each do |type| %>