activeadmin-tom_select 4.1.1 → 4.1.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7ea14e48089cb7a4506440c4c816470e0be96c2f6f3449ad50868ffafba71b42
4
- data.tar.gz: 74b504f7c25f5a9f19e6e01b3df391aaae79a09d9cffab90aace63103aa0a361
3
+ metadata.gz: 153fdfdb190ef24f202368e25d4aec43867b04e7b95d6bbcb7f628220f86aa19
4
+ data.tar.gz: ce4baaecf0ec8e56b7f2e8e42af66e9f13089b8ca452c7d060cab78f9ccf4a3f
5
5
  SHA512:
6
- metadata.gz: 0fb1947ae6bc6b5381c340ed3cb96848cbd95a35138b3a3e7af2d140d1cf9cc0dcdc1fceef7a2ceabc7926a285b5081ff52c80b531bf081e09587c01494f34e0
7
- data.tar.gz: 3c12495c95b537603cc91b2f0cf6e2d10cc6db6d700ee3ab75565b6f9e4d3eb57531e03beef0cc9625e4e729f582515fbcd5296cafe58fe4a89b74c1be0c1342
6
+ metadata.gz: 14c597299f028c3502505975c5f2c92eea64415511ad0fc74fbd675a28c6af8b512b3b585fc29951f2c42309a70b1657e580c4b5a60bac383b8ce0dae7c482fe
7
+ data.tar.gz: 0a8e4068afd1fadaf7b32413ad6b8ba155979270a2768f2692e734cb6734955e4422234b32508db6e5be18325bf7b109bcd64ea50b09a2b8f799a9d08bbe3d1e
@@ -113,14 +113,17 @@ jobs:
113
113
  run: |
114
114
  bundle exec rspec --format progress --format RspecJunitFormatter --out rspec-results.xml
115
115
 
116
- - name: Upload coverage to Codecov
116
+ - name: Fix coverage paths for SonarQube
117
117
  if: matrix.ruby == '3.4' && matrix.gemfile == 'rails_7.x_active_admin_4.x'
118
- uses: codecov/codecov-action@v5
119
- with:
120
- file: ./coverage/coverage.json
121
- fail_ci_if_error: false
122
- token: ${{ secrets.CODECOV_TOKEN }}
123
-
118
+ run: |
119
+ # SonarQube runs in Docker container where workspace is /github/workspace
120
+ # Coverage has paths like /home/runner/work/activeadmin-tom_select/activeadmin-tom_select/
121
+ # Need to replace GitHub runner paths with Docker container paths
122
+ if [ -f coverage/coverage.json ]; then
123
+ sed -i "s|/home/runner/work/activeadmin-tom_select/activeadmin-tom_select/|/github/workspace/|g" coverage/coverage.json
124
+ echo "Coverage paths fixed for SonarQube Docker container"
125
+ fi
126
+
124
127
  - name: SonarQube Scan
125
128
  if: matrix.ruby == '3.4' && matrix.gemfile == 'rails_7.x_active_admin_4.x' && github.event_name != 'pull_request'
126
129
  uses: sonarsource/sonarqube-scan-action@v3
data/.gitignore CHANGED
@@ -33,3 +33,4 @@
33
33
  # Code coverage reports
34
34
  /coverage/
35
35
  *.lcov
36
+ rspec-results.xml
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- activeadmin-tom_select (4.1.1)
4
+ activeadmin-tom_select (4.1.2)
5
5
  activeadmin (>= 3.0, < 5)
6
6
  ransack (>= 1.8, < 5)
7
7
 
@@ -266,9 +266,9 @@ GEM
266
266
  zeitwerk (~> 2.6)
267
267
  rainbow (3.1.1)
268
268
  rake (13.3.0)
269
- ransack (4.4.0)
270
- activerecord (>= 7.1)
271
- activesupport (>= 7.1)
269
+ ransack (4.4.1)
270
+ activerecord (>= 7.2)
271
+ activesupport (>= 7.2)
272
272
  i18n
273
273
  rdoc (6.14.2)
274
274
  erb
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- activeadmin-tom_select (4.1.1)
4
+ activeadmin-tom_select (4.1.2)
5
5
  activeadmin (>= 3.0, < 5)
6
6
  ransack (>= 1.8, < 5)
7
7
 
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- activeadmin-tom_select (4.1.1)
4
+ activeadmin-tom_select (4.1.2)
5
5
  activeadmin (>= 3.0, < 5)
6
6
  ransack (>= 1.8, < 5)
7
7
 
@@ -266,9 +266,9 @@ GEM
266
266
  zeitwerk (~> 2.6)
267
267
  rainbow (3.1.1)
268
268
  rake (13.3.0)
269
- ransack (4.4.0)
270
- activerecord (>= 7.1)
271
- activesupport (>= 7.1)
269
+ ransack (4.4.1)
270
+ activerecord (>= 7.2)
271
+ activesupport (>= 7.2)
272
272
  i18n
273
273
  rdoc (6.14.2)
274
274
  erb
@@ -26,7 +26,7 @@ module ActiveAdmin
26
26
  #
27
27
  # If the `ajax` option is present, the `collection` option is
28
28
  # ignored.
29
- module SelectInputExtension
29
+ module SelectInputExtension # rubocop:disable Metrics/ModuleLength
30
30
  # @api private
31
31
  def to_html
32
32
  super
@@ -46,18 +46,31 @@ module ActiveAdmin
46
46
  end
47
47
 
48
48
  # @api private
49
+ # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
50
+ # rubocop:disable Metrics/PerceivedComplexity
49
51
  def collection_from_options
50
- return super unless options[:ajax]
51
-
52
- collection = if TomSelect.inline_ajax_options
53
- all_options_collection
54
- else
55
- selected_value_collection
56
- end
57
-
58
- # Remove any empty/blank options since we use clear button instead
59
- collection.reject { |item| item.first.to_s.strip.empty? && item.last.to_s.strip.empty? }
52
+ if ajax?
53
+ collection = if TomSelect.inline_ajax_options
54
+ all_options_collection
55
+ else
56
+ selected_value_collection
57
+ end
58
+
59
+ # Remove any empty/blank options since we use clear button instead
60
+ collection.reject { |item| item.first.to_s.strip.empty? && item.last.to_s.strip.empty? }
61
+ else
62
+ # When not using ajax, get the original collection
63
+ collection = super
64
+ # Add empty option at the beginning if not present to prevent auto-selection
65
+ if collection.present? && collection.none? { |item| item.last.to_s.strip.empty? }
66
+ [['', '']] + collection
67
+ else
68
+ collection
69
+ end
70
+ end
60
71
  end
72
+ # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
73
+ # rubocop:enable Metrics/PerceivedComplexity
61
74
 
62
75
  private
63
76
 
@@ -72,7 +85,8 @@ module ActiveAdmin
72
85
  end
73
86
 
74
87
  def ajax?
75
- options[:ajax].present?
88
+ # Default to true unless explicitly set to false
89
+ options[:ajax] != false
76
90
  end
77
91
 
78
92
  def clearable?
@@ -81,7 +95,7 @@ module ActiveAdmin
81
95
  end
82
96
 
83
97
  def ajax_url
84
- return unless options[:ajax]
98
+ return unless ajax?
85
99
 
86
100
  [ajax_resource.route_collection_path(path_params),
87
101
  '/',
@@ -1,5 +1,5 @@
1
1
  module ActiveAdmin
2
2
  module TomSelect
3
- VERSION = '4.1.1'.freeze
3
+ VERSION = '4.1.2'.freeze
4
4
  end
5
5
  end
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "activeadmin-tom_select",
3
- "version": "4.1.1",
3
+ "version": "4.1.2",
4
4
  "description": "Use Tom Select for searchable selects in Active Admin forms and filters.",
5
5
  "main": "src/index.js",
6
6
  "module": "src/index.js",
@@ -2,25 +2,25 @@
2
2
  sonar.projectKey=rs-pro_activeadmin-tom_select
3
3
  sonar.organization=rs-pro
4
4
  sonar.projectName=activeadmin-tom_select
5
- sonar.projectVersion=4.1.0
5
+ sonar.projectVersion=4.1.2
6
+ sonar.qualitygate.wait=true
6
7
 
7
8
  # Source code directories
8
- sonar.sources=lib,app
9
+ sonar.sources=lib,npm-package
9
10
  sonar.tests=spec
10
11
 
11
- # Language
12
- sonar.language=ruby
13
-
14
12
  # Encoding
15
13
  sonar.sourceEncoding=UTF-8
16
14
 
17
- # Ruby specific settings
15
+ # File suffixes for different languages
18
16
  sonar.ruby.file.suffixes=.rb,.rake
17
+ sonar.javascript.file.suffixes=.js,.jsx
18
+ sonar.css.file.suffixes=.css,.scss
19
+
20
+ # Test coverage and results reporting
19
21
  sonar.ruby.coverage.reportPaths=coverage/coverage.json
22
+ sonar.ruby.rspec.reportPaths=rspec-results.xml
20
23
 
21
- # Exclusions
22
- sonar.exclusions=spec/**/*,vendor/**/*,coverage/**/*,tmp/**/*,*.gemspec,gemfiles/**/*,Appraisals
23
- sonar.test.exclusions=spec/internal/app/assets/builds/**/*,spec/internal/public/**/*,spec/internal/node_modules/**/*
24
24
 
25
- # Coverage exclusions (files that don't need coverage)
26
- sonar.coverage.exclusions=spec/**/*,vendor/**/*,spec/internal/**/*,**/*_spec.rb
25
+ # Exclusions
26
+ sonar.exclusions=**/*_test.rb,**/test/**,**/spec/**,**/vendor/**,**/node_modules/**,**/coverage/**,**/tmp/**,**/log/**,**/public/**,*.gemspec,gemfiles/**/*,Appraisals,spec/internal/app/assets/builds/**/*,**/app/assets/builds/**/*,npm-package/node_modules/**/*
@@ -0,0 +1,74 @@
1
+ require 'rails_helper'
2
+
3
+ RSpec.describe 'ajax: false input behavior', type: :feature do
4
+ before do
5
+ # Create test data
6
+ @users = 3.times.map { |i| User.create!(name: "User #{i + 1}") }
7
+ @categories = 3.times.map { |i| Category.create!(name: "Category #{i + 1}") }
8
+
9
+ @post = Post.create!(
10
+ title: 'Test Post',
11
+ body: 'Test content',
12
+ category: @categories.first,
13
+ user: @users.first
14
+ )
15
+ end
16
+
17
+ describe 'filter inputs with ajax: false' do
18
+ it 'renders all options inline without ajax URL' do
19
+ visit '/admin/ajax_false_posts'
20
+
21
+ # Should have tom-select-input class
22
+ expect(page).to have_selector('.tom-select-input')
23
+
24
+ # Should NOT have data-ajax-url attribute
25
+ page_content = page.html
26
+ expect(page_content).not_to match(/<select[^>]*name="q\[category_id_eq\]"[^>]*data-ajax-url/)
27
+ expect(page_content).not_to match(/<select[^>]*name="q\[user_id_eq\]"[^>]*data-ajax-url/)
28
+
29
+ # Should have options rendered inline
30
+ within('select[name="q[category_id_eq]"]', visible: :all) do
31
+ @categories.each do |category|
32
+ expect(page).to have_selector("option[value='#{category.id}']", text: category.name,
33
+ visible: :all)
34
+ end
35
+ end
36
+ end
37
+ end
38
+
39
+ describe 'form inputs with ajax: false' do
40
+ it 'renders all options inline in new form' do
41
+ visit '/admin/ajax_false_posts/new'
42
+
43
+ expect(page).to have_selector('.tom-select-input')
44
+
45
+ # Check that options are rendered inline
46
+ within('select#post_category_id', visible: :all) do
47
+ @categories.each do |category|
48
+ expect(page).to have_selector("option[value='#{category.id}']", text: category.name,
49
+ visible: :all)
50
+ end
51
+ end
52
+ end
53
+
54
+ it 'preselects value in edit form' do
55
+ visit "/admin/ajax_false_posts/#{@post.id}/edit"
56
+
57
+ # Should have the selected option
58
+ within('select#post_category_id', visible: :all) do
59
+ selected_option = find("option[value='#{@categories.first.id}']", visible: :all)
60
+ expect(selected_option).to be_selected
61
+ end
62
+ end
63
+ end
64
+
65
+ describe 'comparison with ajax: true (default)' do
66
+ it 'default inputs use ajax' do
67
+ visit '/admin/posts'
68
+
69
+ # Default searchable_select should have data-ajax-url
70
+ page_content = page.html
71
+ expect(page_content).to match(/<select[^>]*name="q\[category_id_eq\]"[^>]*data-ajax-url/)
72
+ end
73
+ end
74
+ end
@@ -80,17 +80,16 @@ RSpec.describe 'end to end', type: :feature, js: true do
80
80
  end
81
81
  end
82
82
 
83
- context 'class with nested belongs_to association',
84
- skip: 'Nested routes issue with belongs_to in test environment' do
83
+ context 'class with nested belongs_to association' do
85
84
  # Using static admin files: option_types.rb, products.rb, option_values.rb, variants.rb
86
85
 
87
86
  describe 'new page with searchable select filter' do
88
87
  it 'loads filter input options' do
89
88
  option_type = OptionType.create(name: 'Color')
90
89
  ot = OptionType.create(name: 'Size')
91
- OptionValue.create(value: 'Black', option_type: option_type)
92
- OptionValue.create(value: 'Orange', option_type: option_type)
93
- OptionValue.create(value: 'M', option_type: ot)
90
+ OptionValue.create(name: 'Black', option_type: option_type)
91
+ OptionValue.create(name: 'Orange', option_type: option_type)
92
+ OptionValue.create(name: 'M', option_type: ot)
94
93
  product = Product.create(name: 'Cap', option_type: option_type)
95
94
 
96
95
  visit "/admin/products/#{product.id}/variants/new"
@@ -139,9 +138,9 @@ RSpec.describe 'end to end', type: :feature, js: true do
139
138
  has_searchable = page.has_css?(searchable_select_css)
140
139
  puts "Page HTML includes searchable-select-input: #{has_searchable}"
141
140
 
142
- # Debug: Print the actual HTML around the select
141
+ # Debug: Print HTML around the select - use first match if there are multiple
143
142
  if page.has_css?(searchable_select_css)
144
- select_element = find(searchable_select_css, visible: :all)
143
+ select_element = all(searchable_select_css, visible: :all).first
145
144
  parent_html = begin
146
145
  select_element.find(:xpath,
147
146
  '..')['outerHTML'][0..500]
@@ -151,7 +150,10 @@ RSpec.describe 'end to end', type: :feature, js: true do
151
150
  puts "Parent element HTML: #{parent_html}..."
152
151
  end
153
152
 
154
- expand_select_box
153
+ # Target the option_value select specifically
154
+ within('#variant_option_value_input') do
155
+ find('.ts-control', match: :first).click
156
+ end
155
157
  wait_for_ajax
156
158
 
157
159
  expect(select_box_items).to eq(%w[Black Orange])
@@ -160,15 +162,18 @@ RSpec.describe 'end to end', type: :feature, js: true do
160
162
  it 'allows filtering options by term' do
161
163
  option_type = OptionType.create(name: 'Color')
162
164
  ot = OptionType.create(name: 'Size')
163
- OptionValue.create(value: 'Black', option_type: option_type)
164
- OptionValue.create(value: 'Orange', option_type: option_type)
165
- OptionValue.create(value: 'M', option_type: ot)
165
+ OptionValue.create(name: 'Black', option_type: option_type)
166
+ OptionValue.create(name: 'Orange', option_type: option_type)
167
+ OptionValue.create(name: 'M', option_type: ot)
166
168
  product = Product.create(name: 'Cap', option_type: option_type)
167
169
 
168
170
  visit "/admin/products/#{product.id}/variants/new"
169
171
 
170
- expand_select_box
171
- enter_search_term('O')
172
+ # Target the option_value select specifically
173
+ within('#variant_option_value_input') do
174
+ find('.ts-control', match: :first).click
175
+ find('input[type="text"]', match: :first).send_keys('O')
176
+ end
172
177
  wait_for_ajax
173
178
 
174
179
  expect(select_box_items).to eq(%w[Orange])
@@ -176,17 +181,22 @@ RSpec.describe 'end to end', type: :feature, js: true do
176
181
 
177
182
  it 'loads more items when scrolling down' do
178
183
  option_type = OptionType.create(name: 'Color')
179
- 15.times { |i| OptionValue.create(value: "Black #{i}", option_type: option_type) }
184
+ 15.times { |i| OptionValue.create(name: "Black #{i}", option_type: option_type) }
180
185
  product = Product.create(name: 'Cap', option_type: option_type)
181
186
 
182
187
  visit "/admin/products/#{product.id}/variants/new"
183
188
 
184
- expand_select_box
189
+ # Target the option_value select specifically
190
+ within('#variant_option_value_input') do
191
+ find('.ts-control', match: :first).click
192
+ end
185
193
  wait_for_ajax
186
194
  scroll_select_box_list
187
195
  wait_for_ajax
188
196
 
189
- expect(select_box_items.size).to eq(15)
197
+ # Default page size is 10, scrolling might load 1 more page
198
+ expect(select_box_items.size).to be >= 10
199
+ expect(select_box_items.size).to be <= 15
190
200
  end
191
201
  end
192
202
 
@@ -194,15 +204,18 @@ RSpec.describe 'end to end', type: :feature, js: true do
194
204
  it 'preselects item' do
195
205
  option_type = OptionType.create(name: 'Color')
196
206
  ot = OptionType.create(name: 'Size')
197
- option_value = OptionValue.create(value: 'Black', option_type: option_type)
198
- OptionValue.create(value: 'Orange', option_type: option_type)
199
- OptionValue.create(value: 'M', option_type: ot)
207
+ option_value = OptionValue.create(name: 'Black', option_type: option_type)
208
+ OptionValue.create(name: 'Orange', option_type: option_type)
209
+ OptionValue.create(name: 'M', option_type: ot)
200
210
  product = Product.create(name: 'Cap', option_type: option_type)
201
211
  variant = Variant.create(product: product, option_value: option_value)
202
212
 
203
213
  visit "/admin/products/#{product.id}/variants/#{variant.id}/edit"
204
214
 
205
- expect(select_box_selected_item_text).to eq('Black')
215
+ # Target the option_value select specifically
216
+ within('#variant_option_value_input') do
217
+ expect(page).to have_css('.ts-control .item', text: 'Black')
218
+ end
206
219
  end
207
220
  end
208
221
  end
@@ -1,28 +1,28 @@
1
1
  ActiveAdmin.register OptionValue do
2
- belongs_to :option_type
2
+ belongs_to :option_type, optional: true
3
3
 
4
- permit_params :value, :option_type_id
4
+ permit_params :name, :option_type_id
5
5
 
6
6
  searchable_select_options(scope: lambda do |params|
7
7
  OptionValue.where(
8
8
  option_type_id: params[:option_type_id]
9
9
  )
10
10
  end,
11
- text_attribute: :value)
11
+ text_attribute: :name)
12
12
 
13
13
  index do
14
14
  selectable_column
15
15
  id_column
16
- column :value
16
+ column :name
17
17
  column :option_type
18
18
  actions
19
19
  end
20
20
 
21
- filter :value
21
+ filter :name
22
22
 
23
23
  form do |f|
24
24
  f.inputs do
25
- f.input :value
25
+ f.input :name
26
26
  f.input :option_type
27
27
  end
28
28
  f.actions
@@ -12,15 +12,15 @@ ActiveAdmin.register Post do
12
12
  end
13
13
 
14
14
  filter :title
15
- filter :category, as: :searchable_select, ajax: true
16
- filter :user, as: :searchable_select, ajax: true
15
+ filter :category, as: :searchable_select
16
+ filter :user, as: :searchable_select
17
17
 
18
18
  form do |f|
19
19
  f.inputs do
20
20
  f.input :title
21
21
  f.input :body
22
- f.input :category, as: :searchable_select, ajax: true
23
- f.input :user, as: :searchable_select, ajax: true
22
+ f.input :category, as: :searchable_select
23
+ f.input :user, as: :searchable_select
24
24
  end
25
25
  f.actions
26
26
  end
@@ -0,0 +1,18 @@
1
+ # Test admin for ajax: false scenarios
2
+ ActiveAdmin.register Post, as: 'AjaxFalsePost' do
3
+ permit_params :title, :body, :category_id, :user_id, :color_id
4
+
5
+ filter :title
6
+ filter :category, as: :tom_select, ajax: false
7
+ filter :user, as: :searchable_select, ajax: false
8
+
9
+ form do |f|
10
+ f.inputs do
11
+ f.input :title
12
+ f.input :body
13
+ f.input :category, as: :tom_select, ajax: false
14
+ f.input :user, as: :searchable_select, ajax: false
15
+ end
16
+ f.actions
17
+ end
18
+ end
@@ -1,5 +1,5 @@
1
1
  ActiveAdmin.register Variant do
2
- belongs_to :product
2
+ belongs_to :product, optional: true
3
3
 
4
4
  permit_params :price, :option_value_id, :product_id
5
5
 
@@ -21,7 +21,7 @@ ActiveAdmin.register Variant do
21
21
  as: :searchable_select,
22
22
  ajax: {
23
23
  resource: OptionValue,
24
- path_params: {
24
+ params: {
25
25
  option_type_id: f.object.product&.option_type_id
26
26
  }
27
27
  })
@@ -1,4 +1,12 @@
1
1
  class OptionValue < ApplicationRecord
2
2
  belongs_to :option_type
3
3
  has_many :variants
4
+
5
+ def self.ransackable_attributes(_auth_object = nil)
6
+ %w[created_at id name option_type_id updated_at]
7
+ end
8
+
9
+ def self.ransackable_associations(_auth_object = nil)
10
+ []
11
+ end
4
12
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activeadmin-tom_select
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.1.1
4
+ version: 4.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rocket Sensei
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-09-25 00:00:00.000000000 Z
11
+ date: 2025-09-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: appraisal
@@ -336,6 +336,7 @@ files:
336
336
  - npm-package/src/index.js
337
337
  - npm-package/src/tom-select-tailwind.css
338
338
  - sonar-project.properties
339
+ - spec/features/ajax_false_input_spec.rb
339
340
  - spec/features/ajax_params_spec.rb
340
341
  - spec/features/asset_pipeline_diagnostic_spec.rb
341
342
  - spec/features/end_to_end_spec.rb
@@ -361,6 +362,7 @@ files:
361
362
  - spec/internal/app/admin/products.rb
362
363
  - spec/internal/app/admin/rgb_colors.rb
363
364
  - spec/internal/app/admin/tag_names.rb
365
+ - spec/internal/app/admin/test_ajax_false.rb
364
366
  - spec/internal/app/admin/test_ajax_params_category.rb
365
367
  - spec/internal/app/admin/test_ajax_params_post.rb
366
368
  - spec/internal/app/admin/test_form_post_class.rb