rs-activeadmin-searchable_select 4.0.5

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.
Files changed (145) hide show
  1. checksums.yaml +7 -0
  2. data/.actrc +20 -0
  3. data/.claude/commands/fix-tests.md +203 -0
  4. data/.github/workflows/ci.yml +170 -0
  5. data/.github/workflows/npm-publish.yml +47 -0
  6. data/.gitignore +27 -0
  7. data/.npmignore +58 -0
  8. data/.rspec +2 -0
  9. data/.rubocop.yml +67 -0
  10. data/.yardopts +2 -0
  11. data/AGENTS.md +39 -0
  12. data/Appraisals +15 -0
  13. data/CHANGELOG.md +24 -0
  14. data/CLAUDE.md +104 -0
  15. data/Gemfile +11 -0
  16. data/Gemfile.lock +366 -0
  17. data/LICENSE.txt +25 -0
  18. data/README.md +439 -0
  19. data/Rakefile +4 -0
  20. data/bin/rspec +17 -0
  21. data/config/database.yml +16 -0
  22. data/config.ru +28 -0
  23. data/docs/activeadmin-4-detailed-reference.md +932 -0
  24. data/docs/activeadmin-4-gem-migration-guide.md +313 -0
  25. data/docs/combustion.md +213 -0
  26. data/docs/for-next-session.md +199 -0
  27. data/docs/guide-update-your-app.md +213 -0
  28. data/docs/propshaft-readme.md +121 -0
  29. data/docs/propshaft-upgrade.md +267 -0
  30. data/docs/rails-7-asset-pipeline.md +279 -0
  31. data/docs/setup-activeadmin-app.md +552 -0
  32. data/docs/setup-activeadmin-gem.md +535 -0
  33. data/docs/upload-system.md +225 -0
  34. data/gemfiles/rails_7.x_active_admin_4.x.gemfile +11 -0
  35. data/gemfiles/rails_7.x_active_admin_4.x.gemfile.lock +371 -0
  36. data/gemfiles/rails_8.x_active_admin_4.x.gemfile +11 -0
  37. data/gemfiles/rails_8.x_active_admin_4.x.gemfile.lock +366 -0
  38. data/lefthook.yml +17 -0
  39. data/lib/activeadmin/inputs/filters/searchable_select_input.rb +13 -0
  40. data/lib/activeadmin/inputs/searchable_select_input.rb +11 -0
  41. data/lib/activeadmin/searchable_select/engine.rb +17 -0
  42. data/lib/activeadmin/searchable_select/option_collection.rb +119 -0
  43. data/lib/activeadmin/searchable_select/resource_dsl_extension.rb +56 -0
  44. data/lib/activeadmin/searchable_select/resource_extension.rb +10 -0
  45. data/lib/activeadmin/searchable_select/select_input_extension.rb +159 -0
  46. data/lib/activeadmin/searchable_select/version.rb +5 -0
  47. data/lib/activeadmin/searchable_select.rb +20 -0
  48. data/lib/activeadmin-searchable_select.rb +4 -0
  49. data/lib/generators/active_admin/searchable_select/install/install_generator.rb +217 -0
  50. data/package-lock.json +18 -0
  51. data/package.json +45 -0
  52. data/rs-activeadmin-searchable_select.gemspec +38 -0
  53. data/sonar-project.properties +25 -0
  54. data/spec/features/ajax_params_spec.rb +31 -0
  55. data/spec/features/end_to_end_spec.rb +227 -0
  56. data/spec/features/filter_input_spec.rb +137 -0
  57. data/spec/features/form_input_spec.rb +122 -0
  58. data/spec/features/inline_ajax_setting_spec.rb +26 -0
  59. data/spec/features/input_errors_spec.rb +76 -0
  60. data/spec/features/input_html_options_spec.rb +30 -0
  61. data/spec/features/options_dsl_spec.rb +220 -0
  62. data/spec/features/production_build_spec.rb +108 -0
  63. data/spec/internal/app/admin/categories.rb +26 -0
  64. data/spec/internal/app/admin/dashboard.rb +29 -0
  65. data/spec/internal/app/admin/option_types.rb +19 -0
  66. data/spec/internal/app/admin/option_values.rb +30 -0
  67. data/spec/internal/app/admin/posts.rb +27 -0
  68. data/spec/internal/app/admin/products.rb +22 -0
  69. data/spec/internal/app/admin/rgb_colors.rb +25 -0
  70. data/spec/internal/app/admin/tag_names.rb +21 -0
  71. data/spec/internal/app/admin/test_ajax_params_category.rb +10 -0
  72. data/spec/internal/app/admin/test_ajax_params_post.rb +20 -0
  73. data/spec/internal/app/admin/test_form_post_class.rb +7 -0
  74. data/spec/internal/app/admin/test_form_post_custom.rb +11 -0
  75. data/spec/internal/app/admin/test_form_post_resource.rb +11 -0
  76. data/spec/internal/app/admin/test_form_post_resource_custom.rb +12 -0
  77. data/spec/internal/app/admin/test_inline_ajax_post.rb +9 -0
  78. data/spec/internal/app/admin/test_input_html_post.rb +11 -0
  79. data/spec/internal/app/admin/test_posts_display_text.rb +9 -0
  80. data/spec/internal/app/admin/test_posts_filter.rb +9 -0
  81. data/spec/internal/app/admin/test_posts_named.rb +9 -0
  82. data/spec/internal/app/admin/test_posts_pagination.rb +9 -0
  83. data/spec/internal/app/admin/test_posts_payload_lambda.rb +11 -0
  84. data/spec/internal/app/admin/test_posts_payload_proc.rb +9 -0
  85. data/spec/internal/app/admin/test_posts_scope_lambda.rb +8 -0
  86. data/spec/internal/app/admin/test_posts_scope_params.rb +8 -0
  87. data/spec/internal/app/admin/test_posts_scope_user.rb +8 -0
  88. data/spec/internal/app/admin/test_posts_text_attr.rb +5 -0
  89. data/spec/internal/app/admin/users.rb +23 -0
  90. data/spec/internal/app/admin/variants.rb +31 -0
  91. data/spec/internal/app/assets/config/manifest.js +1 -0
  92. data/spec/internal/app/assets/javascripts/active_admin.js +2 -0
  93. data/spec/internal/app/assets/javascripts/searchable_select_test.js +2 -0
  94. data/spec/internal/app/controllers/application_controller.rb +5 -0
  95. data/spec/internal/app/css/active_admin_source.css +81 -0
  96. data/spec/internal/app/js/active_admin.js +17 -0
  97. data/spec/internal/app/models/article.rb +12 -0
  98. data/spec/internal/app/models/category.rb +12 -0
  99. data/spec/internal/app/models/internal/tag_name.rb +14 -0
  100. data/spec/internal/app/models/internal_tag_name.rb +11 -0
  101. data/spec/internal/app/models/option_type.rb +12 -0
  102. data/spec/internal/app/models/option_value.rb +4 -0
  103. data/spec/internal/app/models/post.rb +15 -0
  104. data/spec/internal/app/models/product.rb +12 -0
  105. data/spec/internal/app/models/rgb_color.rb +16 -0
  106. data/spec/internal/app/models/user.rb +12 -0
  107. data/spec/internal/app/models/variant.rb +12 -0
  108. data/spec/internal/build_activeadmin_css.js +115 -0
  109. data/spec/internal/config/database.yml +7 -0
  110. data/spec/internal/config/environment.rb +48 -0
  111. data/spec/internal/config/initializers/active_admin.rb +53 -0
  112. data/spec/internal/config/initializers/assets.rb +9 -0
  113. data/spec/internal/config/initializers/searchable_select.rb +6 -0
  114. data/spec/internal/config/routes.rb +4 -0
  115. data/spec/internal/config.ru +4 -0
  116. data/spec/internal/db/schema.rb +63 -0
  117. data/spec/internal/db/seeds.rb +88 -0
  118. data/spec/internal/esbuild.config.js +30 -0
  119. data/spec/internal/inject-jquery.js +4 -0
  120. data/spec/internal/log/.gitignore +1 -0
  121. data/spec/internal/package/LICENSE.txt +25 -0
  122. data/spec/internal/package/README.md +439 -0
  123. data/spec/internal/package/package.json +45 -0
  124. data/spec/internal/package/src/index.js +1 -0
  125. data/spec/internal/package/src/searchable_select/init.js +1 -0
  126. data/spec/internal/package/src/searchable_select.css +1 -0
  127. data/spec/internal/package/src/searchable_select.scss +1 -0
  128. data/spec/internal/package-lock.json +1385 -0
  129. data/spec/internal/package.json +26 -0
  130. data/spec/internal/public/favicon.ico +0 -0
  131. data/spec/internal/spec/internal/app/css/active_admin_source.css +38 -0
  132. data/spec/internal/spec/internal/log/test.log +0 -0
  133. data/spec/internal/tailwind-active_admin.config.js +53 -0
  134. data/spec/rails_helper.rb +86 -0
  135. data/spec/spec_helper.rb +137 -0
  136. data/spec/support/active_admin_helpers.rb +17 -0
  137. data/spec/support/capybara.rb +8 -0
  138. data/spec/support/models.rb +88 -0
  139. data/spec/support/pluck_polyfill.rb +12 -0
  140. data/spec/support/reset_settings.rb +5 -0
  141. data/src/index.js +77 -0
  142. data/src/searchable_select/init.js +58 -0
  143. data/src/searchable_select.css +5 -0
  144. data/src/searchable_select.css.map +1 -0
  145. metadata +405 -0
@@ -0,0 +1,26 @@
1
+ {
2
+ "name": "internal",
3
+ "version": "1.0.0",
4
+ "main": "index.js",
5
+ "scripts": {
6
+ "copy:select2": "mkdir -p public/select2 && cp -r node_modules/select2/dist/css/* public/select2/",
7
+ "build:js": "node esbuild.config.js",
8
+ "build:css:activeadmin": "node build_activeadmin_css.js",
9
+ "build:assets": "npm run copy:select2 && npm run build:js && npm run build:css:activeadmin",
10
+ "build": "npm run build:assets",
11
+ "watch:js": "node esbuild.config.js --watch",
12
+ "watch": "npm run watch:js",
13
+ "start": "npm run watch"
14
+ },
15
+ "dependencies": {
16
+ "@activeadmin/activeadmin": "^4.0.0-beta10",
17
+ "@rails/ujs": "^7.1.400",
18
+ "@rocket-sensei/activeadmin-searchable_select": "file:package",
19
+ "esbuild": "^0.24.2",
20
+ "jquery": "^3.7.1",
21
+ "select2": "^4.1.0-rc.0"
22
+ },
23
+ "devDependencies": {
24
+ "tailwindcss": "^3.4.17"
25
+ }
26
+ }
File without changes
@@ -0,0 +1,38 @@
1
+ @tailwind base;
2
+ @tailwind components;
3
+ @tailwind utilities;
4
+
5
+ /* Searchable Select Styles */
6
+ .searchable_select.input .select2-container {
7
+ min-width: 30%;
8
+ }
9
+
10
+ /* Custom Select2 overrides */
11
+ .select2-container {
12
+ @apply w-full;
13
+ }
14
+
15
+ .select2-selection {
16
+ @apply border border-gray-300 rounded-md min-h-[40px];
17
+ }
18
+
19
+ .select2-selection__rendered {
20
+ @apply p-2;
21
+ }
22
+
23
+ /* Dark mode support */
24
+ .dark .select2-selection {
25
+ @apply border-gray-600 bg-gray-800 text-gray-100;
26
+ }
27
+
28
+ .dark .select2-dropdown {
29
+ @apply bg-gray-800 border-gray-600;
30
+ }
31
+
32
+ .dark .select2-results__option {
33
+ @apply text-gray-100;
34
+ }
35
+
36
+ .dark .select2-results__option--highlighted {
37
+ @apply bg-gray-700;
38
+ }
File without changes
@@ -0,0 +1,53 @@
1
+ const execSync = require('child_process').execSync;
2
+ const activeAdminPath = execSync('bundle show activeadmin', { encoding: 'utf-8' }).trim();
3
+
4
+ module.exports = {
5
+ content: [
6
+ `${activeAdminPath}/vendor/javascript/flowbite.js`,
7
+ `${activeAdminPath}/plugin.js`,
8
+ `${activeAdminPath}/app/views/**/*.{arb,erb,html,rb}`,
9
+ './app/admin/**/*.{arb,erb,html,rb}',
10
+ './app/views/active_admin/**/*.{arb,erb,html,rb}',
11
+ './app/views/admin/**/*.{arb,erb,html,rb}',
12
+ './app/javascript/**/*.js',
13
+ './app/js/**/*.js'
14
+ ],
15
+ darkMode: "selector",
16
+ plugins: [
17
+ require(`@activeadmin/activeadmin/plugin`)
18
+ ],
19
+ // CRITICAL: Safelist for ActiveAdmin 4 dynamic classes
20
+ safelist: [
21
+ // Grid and layout
22
+ 'grid', 'gap-4', 'gap-6', 'lg:grid-cols-3', 'md:grid-cols-2',
23
+ 'col-span-2', 'col-span-3', 'lg:col-span-2', 'lg:col-span-1',
24
+ // Flexbox
25
+ 'flex', 'flex-col', 'flex-row', 'flex-wrap', 'items-center',
26
+ 'justify-between', 'justify-center', 'items-start', 'items-end',
27
+ // Spacing
28
+ 'p-4', 'p-6', 'px-4', 'px-6', 'py-2', 'py-4', 'm-0', 'mx-auto',
29
+ 'mt-4', 'mb-4', 'ml-auto', 'mr-auto', 'space-y-4', 'space-x-4',
30
+ // Display
31
+ 'block', 'inline-block', 'hidden', 'lg:hidden', 'lg:block', 'lg:flex',
32
+ // Width/Height
33
+ 'w-full', 'w-auto', 'w-64', 'h-full', 'min-h-screen', 'max-w-7xl',
34
+ // Typography
35
+ 'text-sm', 'text-base', 'text-lg', 'text-xl', 'font-medium', 'font-semibold',
36
+ // Colors
37
+ 'bg-white', 'bg-gray-50', 'bg-gray-100', 'text-gray-900', 'text-gray-600',
38
+ 'dark:bg-gray-800', 'dark:bg-gray-900', 'dark:text-white', 'dark:text-gray-300',
39
+ // Borders
40
+ 'border', 'border-gray-200', 'dark:border-gray-700', 'rounded-lg', 'rounded-md',
41
+ // Forms
42
+ 'form-input', 'form-select', 'form-checkbox',
43
+ // Position & Z-index
44
+ 'relative', 'absolute', 'fixed', 'sticky', 'top-0', 'left-0', 'right-0',
45
+ 'z-10', 'z-20', 'z-30', 'z-40', 'z-50',
46
+ // Shadows
47
+ 'shadow', 'shadow-md', 'shadow-lg',
48
+ // Tables
49
+ 'table-auto', 'border-collapse',
50
+ // Buttons
51
+ 'inline-flex', 'cursor-pointer'
52
+ ]
53
+ }
@@ -0,0 +1,86 @@
1
+ require_relative 'spec_helper'
2
+
3
+ ENV['RAILS_ENV'] ||= 'test'
4
+
5
+ require 'combustion'
6
+ require 'propshaft'
7
+
8
+ # Fix for FrozenError - initialize Combustion with proper configuration
9
+ Combustion.path = 'spec/internal'
10
+ # Always include Propshaft so test app serves assets from app/assets/builds
11
+ Combustion.initialize!(
12
+ :active_record,
13
+ :action_controller,
14
+ :action_view,
15
+ :propshaft
16
+ ) do
17
+ config.load_defaults Rails::VERSION::STRING.to_f if Rails::VERSION::MAJOR >= 7
18
+ end
19
+
20
+ require 'rspec/rails'
21
+ require 'capybara/rails'
22
+ require 'capybara-playwright-driver'
23
+ require 'database_cleaner/active_record'
24
+
25
+ # Load ActiveAdmin and models
26
+ require_relative 'internal/config/initializers/active_admin'
27
+
28
+ # Ensure ActiveAdmin loads properly with batch actions
29
+ ActiveAdmin.application.load!
30
+
31
+ require_relative 'internal/app/models/category'
32
+ require_relative 'internal/app/models/post'
33
+ require_relative 'internal/app/models/user'
34
+ require_relative 'internal/app/models/rgb_color'
35
+ require_relative 'internal/app/models/internal_tag_name'
36
+ require_relative 'internal/app/models/internal/tag_name'
37
+ require_relative 'internal/app/models/option_type'
38
+ require_relative 'internal/app/models/option_value'
39
+ require_relative 'internal/app/models/product'
40
+ require_relative 'internal/app/models/variant'
41
+
42
+ # Load admin files - this is crucial for static admin resources to be registered
43
+ Dir[File.expand_path('internal/app/admin/*.rb', __dir__)].each { |f| require f }
44
+
45
+ Dir[File.expand_path('support/**/*.rb', __dir__)].each { |f| require_relative f }
46
+
47
+ # Configure Capybara with Playwright for modern browser testing
48
+ Capybara.register_driver :playwright do |app|
49
+ Capybara::Playwright::Driver.new(app,
50
+ browser_type: :chromium,
51
+ headless: ENV['HEADLESS'] != 'false')
52
+ end
53
+
54
+ Capybara.default_driver = :rack_test
55
+ Capybara.javascript_driver = :playwright
56
+ Capybara.default_max_wait_time = 5
57
+
58
+ RSpec.configure do |config|
59
+ config.use_transactional_fixtures = false
60
+ config.infer_spec_type_from_file_location!
61
+ config.filter_rails_from_backtrace!
62
+
63
+ # Database cleaner setup
64
+ config.before(:suite) do
65
+ DatabaseCleaner.clean_with(:truncation)
66
+ end
67
+
68
+ config.before(:each) do
69
+ DatabaseCleaner.strategy = :transaction
70
+ end
71
+
72
+ config.before(:each, js: true) do
73
+ DatabaseCleaner.strategy = :truncation
74
+ end
75
+
76
+ config.before(:each) do
77
+ DatabaseCleaner.start
78
+ end
79
+
80
+ config.after(:each) do
81
+ DatabaseCleaner.clean
82
+ end
83
+
84
+ # Include Capybara DSL in feature specs
85
+ config.include Capybara::DSL, type: :feature
86
+ end
@@ -0,0 +1,137 @@
1
+ # SimpleCov must be started before any application code is loaded
2
+ # Make SimpleCov optional so tests can run without it (e.g., in Appraisal gemfiles)
3
+ begin
4
+ require 'simplecov'
5
+ require 'simplecov-cobertura'
6
+
7
+ SimpleCov.start do
8
+ # Use multiple formatters to generate both HTML and Cobertura XML reports
9
+ formatter SimpleCov::Formatter::MultiFormatter.new([
10
+ SimpleCov::Formatter::HTMLFormatter,
11
+ SimpleCov::Formatter::CoberturaFormatter
12
+ ])
13
+
14
+ # Configure coverage directory
15
+ coverage_dir 'coverage'
16
+
17
+ # Add filters to exclude non-application code
18
+ add_filter '/spec/'
19
+ add_filter '/vendor/'
20
+ add_filter '/config/'
21
+ add_filter '/app/assets/builds/' # Exclude built assets
22
+ add_filter '/spec/internal/app/assets/builds/'
23
+ add_filter '/spec/internal/public/'
24
+ add_filter '/spec/internal/node_modules/'
25
+ add_filter '/spec/internal/package/' # Since these are now symlinks
26
+
27
+ # Track all files in lib and app directories
28
+ track_files 'lib/**/*.rb'
29
+ track_files 'app/**/*.rb'
30
+
31
+ # Set minimum coverage percentage (optional but recommended)
32
+ minimum_coverage 80
33
+ end
34
+ rescue LoadError
35
+ # SimpleCov not available, continue without coverage
36
+ # This allows tests to run in environments where SimpleCov is not installed
37
+ end
38
+
39
+ # This file was generated by the `rspec --init` command. Conventionally, all
40
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
41
+ # The generated `.rspec` file contains `--require spec_helper` which will cause
42
+ # this file to always be loaded, without a need to explicitly require it in any
43
+ # files.
44
+ #
45
+ # Given that it is always loaded, you are encouraged to keep this file as
46
+ # light-weight as possible. Requiring heavyweight dependencies from this file
47
+ # will add to the boot time of your test suite on EVERY test run, even for an
48
+ # individual file that may not need all of that loaded. Instead, consider making
49
+ # a separate helper file that requires the additional dependencies and performs
50
+ # the additional setup, and require it from the spec files that actually need
51
+ # it.
52
+ #
53
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
54
+ RSpec.configure do |config|
55
+ # Exclude vendor and node_modules directories from spec discovery
56
+ # This prevents RSpec from picking up specs from dependencies
57
+ config.exclude_pattern = '**/vendor/**/*,**/node_modules/**/*'
58
+ # rspec-expectations config goes here. You can use an alternate
59
+ # assertion/expectation library such as wrong or the stdlib/minitest
60
+ # assertions if you prefer.
61
+ config.expect_with :rspec do |expectations|
62
+ # This option will default to `true` in RSpec 4. It makes the `description`
63
+ # and `failure_message` of custom matchers include text for helper methods
64
+ # defined using `chain`, e.g.:
65
+ # be_bigger_than(2).and_smaller_than(4).description
66
+ # # => "be bigger than 2 and smaller than 4"
67
+ # ...rather than:
68
+ # # => "be bigger than 2"
69
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
70
+ end
71
+
72
+ # rspec-mocks config goes here. You can use an alternate test double
73
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
74
+ config.mock_with :rspec do |mocks|
75
+ # Prevents you from mocking or stubbing a method that does not exist on
76
+ # a real object. This is generally recommended, and will default to
77
+ # `true` in RSpec 4.
78
+ mocks.verify_partial_doubles = true
79
+ end
80
+
81
+ # This option will default to `:apply_to_host_groups` in RSpec 4 (and will
82
+ # have no way to turn it off -- the option exists only for backwards
83
+ # compatibility in RSpec 3). It causes shared context metadata to be
84
+ # inherited by the metadata hash of host groups and examples, rather than
85
+ # triggering implicit auto-inclusion in groups with matching metadata.
86
+ config.shared_context_metadata_behavior = :apply_to_host_groups
87
+
88
+ # This allows you to limit a spec run to individual examples or groups
89
+ # you care about by tagging them with `:focus` metadata. When nothing
90
+ # is tagged with `:focus`, all examples get run. RSpec also provides
91
+ # aliases for `it`, `describe`, and `context` that include `:focus`
92
+ # metadata: `fit`, `fdescribe` and `fcontext`, respectively.
93
+ config.filter_run_when_matching :focus
94
+
95
+ # Allows RSpec to persist some state between runs in order to support
96
+ # the `--only-failures` and `--next-failure` CLI options. We recommend
97
+ # you configure your source control system to ignore this file.
98
+ config.example_status_persistence_file_path = 'spec/examples.txt'
99
+
100
+ # Limits the available syntax to the non-monkey patched syntax that is
101
+ # recommended. For more details, see:
102
+ # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/
103
+ # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
104
+ # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode
105
+ config.disable_monkey_patching!
106
+
107
+ # This setting enables warnings. It's recommended, but in some cases may
108
+ # be too noisy due to issues in dependencies.
109
+ config.warnings = false
110
+
111
+ # Many RSpec users commonly either run the entire suite or an individual
112
+ # file, and it's useful to allow more verbose output when running an
113
+ # individual spec file.
114
+ if config.files_to_run.one?
115
+ # Use the documentation formatter for detailed output,
116
+ # unless a formatter has already been configured
117
+ # (e.g. via a command-line flag).
118
+ config.default_formatter = 'doc'
119
+ end
120
+
121
+ # Print the 2 slowest examples at the
122
+ # end of the spec run, to help surface which specs are running
123
+ # particularly slow. No groups to save space in logs.
124
+ config.profile_examples = 2
125
+
126
+ # Run specs in random order to surface order dependencies. If you find an
127
+ # order dependency and want to debug it, you can fix the order by providing
128
+ # the seed, which is printed after each run.
129
+ # --seed 1234
130
+ config.order = :random
131
+
132
+ # Seed global randomization in this process using the `--seed` CLI option.
133
+ # Setting this allows you to use `--seed` to deterministically reproduce
134
+ # test failures related to randomization by passing the same `--seed` value
135
+ # as the one that triggered the failure.
136
+ Kernel.srand config.seed
137
+ end
@@ -0,0 +1,17 @@
1
+ module ActiveAdminHelpers
2
+ module_function
3
+
4
+ def reload_routes!
5
+ return unless Rails.application
6
+
7
+ Rails.application.reload_routes!
8
+ end
9
+
10
+ def setup
11
+ # Since we can't easily override static registrations,
12
+ # just yield to let tests define additional config if needed
13
+ # Most tests will need to be updated to work with existing static admin files
14
+ yield if block_given?
15
+ reload_routes!
16
+ end
17
+ end
@@ -0,0 +1,8 @@
1
+ require 'capybara/rspec'
2
+
3
+ # Capybara configuration is now in rails_helper.rb
4
+ # Using Playwright driver for modern browser testing
5
+
6
+ RSpec.configure do |config|
7
+ config.include Capybara::RSpecMatchers, type: :request
8
+ end
@@ -0,0 +1,88 @@
1
+ require 'database_cleaner-active_record'
2
+
3
+ class User < ActiveRecord::Base
4
+ def self.ransackable_attributes(_auth_object = nil)
5
+ %w[name email]
6
+ end
7
+
8
+ def self.ransackable_associations(_auth_object = nil)
9
+ []
10
+ end
11
+
12
+ def to_s
13
+ name.presence || "User #{id}"
14
+ end
15
+ end
16
+
17
+ class Category < ActiveRecord::Base
18
+ belongs_to :created_by, class_name: 'User', optional: true
19
+
20
+ def self.ransackable_attributes(_auth_object = nil)
21
+ ['name']
22
+ end
23
+
24
+ def self.ransackable_associations(_auth_object = nil)
25
+ []
26
+ end
27
+ end
28
+
29
+ class Post < ActiveRecord::Base
30
+ belongs_to :category, optional: true
31
+ belongs_to :user, optional: true
32
+
33
+ scope(:published, -> { where(published: true) })
34
+
35
+ def self.ransackable_attributes(_auth_object = nil)
36
+ %w[category_id title user_id]
37
+ end
38
+
39
+ def self.ransackable_associations(_auth_object = nil)
40
+ []
41
+ end
42
+ end
43
+
44
+ module Internal
45
+ class TagName < ActiveRecord::Base
46
+ self.table_name = :internal_tag_names
47
+ belongs_to :color, class_name: 'RgbColor', foreign_key: :color_id, optional: true
48
+
49
+ def self.ransackable_attributes(_auth_object = nil)
50
+ ['color_id']
51
+ end
52
+
53
+ def self.ransackable_associations(_auth_object = nil)
54
+ []
55
+ end
56
+ end
57
+ end
58
+
59
+ class OptionType < ActiveRecord::Base; end
60
+
61
+ class OptionValue < ActiveRecord::Base
62
+ belongs_to :option_type, optional: true
63
+
64
+ def self.ransackable_attributes(_auth_object = nil)
65
+ ['value']
66
+ end
67
+
68
+ def self.ransackable_associations(_auth_object = nil)
69
+ []
70
+ end
71
+ end
72
+
73
+ class Product < ActiveRecord::Base
74
+ belongs_to :option_type, optional: true
75
+ has_many :variants
76
+ end
77
+
78
+ class Variant < ActiveRecord::Base
79
+ belongs_to :product, optional: true
80
+ belongs_to :option_value, optional: true
81
+ end
82
+
83
+ RSpec.configure do |config|
84
+ config.after do
85
+ DatabaseCleaner.strategy = :truncation
86
+ DatabaseCleaner.clean
87
+ end
88
+ end
@@ -0,0 +1,12 @@
1
+ # Required for ActiveSupport < 5
2
+ unless [].respond_to?(:pluck)
3
+ module Enumerable
4
+ def pluck(*keys)
5
+ if keys.many?
6
+ map { |element| keys.map { |key| element[key] } }
7
+ else
8
+ map { |element| element[keys.first] }
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,5 @@
1
+ RSpec.configure do |config|
2
+ config.before(:each) do
3
+ ActiveAdmin::SearchableSelect.inline_ajax_options = false
4
+ end
5
+ end
data/src/index.js ADDED
@@ -0,0 +1,77 @@
1
+ // ES Module version for ActiveAdmin 4+ with esbuild/webpack
2
+ // The consuming app must import jQuery and Select2 BEFORE importing this module
3
+
4
+ // Core initialization function
5
+ export function initSearchableSelects(inputs, extra) {
6
+ const $ = window.jQuery || window.$;
7
+
8
+ if (!$?.fn) {
9
+ console.error('ActiveAdmin Searchable Select: jQuery not found');
10
+ return;
11
+ }
12
+
13
+ // Ensure select2 is available
14
+ if (!$.fn.select2) {
15
+ console.error('ActiveAdmin Searchable Select: Select2 is not loaded. Please ensure select2 is properly imported.');
16
+ return;
17
+ }
18
+
19
+ inputs.each(function() {
20
+ const item = $(this);
21
+
22
+ // reading from data allows <input data-searchable_select='{"tags": ['some']}'>
23
+ // to be passed to select2
24
+ const options = $.extend(extra || {}, item.data('searchableSelect'));
25
+ const url = item.data('ajaxUrl');
26
+
27
+ if (url) {
28
+ $.extend(options, {
29
+ ajax: {
30
+ url: url,
31
+ dataType: 'json',
32
+
33
+ data: function (params) {
34
+ return {
35
+ term: params.term,
36
+ page: pageParamWithBaseZero(params)
37
+ };
38
+ }
39
+ }
40
+ });
41
+ }
42
+
43
+ item.select2(options);
44
+ });
45
+ }
46
+
47
+ function pageParamWithBaseZero(params) {
48
+ return params.page ? params.page - 1 : undefined;
49
+ }
50
+
51
+ // Auto-initialize on common events
52
+ export function setupAutoInit() {
53
+ const $ = window.jQuery || window.$;
54
+ if (!$) {
55
+ console.error('ActiveAdmin Searchable Select: jQuery not found for auto-init');
56
+ return;
57
+ }
58
+
59
+ // Initialize on DOM ready
60
+ $(function() {
61
+ initSearchableSelects($(".searchable-select-input"));
62
+ });
63
+
64
+ // Support Turbo (Rails 7+)
65
+ document.addEventListener('turbo:load', function() {
66
+ initSearchableSelects($(".searchable-select-input"), {placeholder: ""});
67
+ });
68
+
69
+ // ActiveAdmin 4 uses .has-many-add button click for dynamic content
70
+ $(document).on('click', '.has-many-add', function() {
71
+ setTimeout(function() {
72
+ initSearchableSelects($(".searchable-select-input:not(.select2-hidden-accessible)"));
73
+ }, 10);
74
+ });
75
+
76
+ console.log('ActiveAdmin Searchable Select initialized');
77
+ }
@@ -0,0 +1,58 @@
1
+ (function() {
2
+ // Wait for jQuery to be available
3
+ if (typeof $ === 'undefined' && typeof jQuery !== 'undefined') {
4
+ window.$ = jQuery;
5
+ }
6
+
7
+ function initSearchableSelects(inputs, extra) {
8
+ // Ensure select2 is available
9
+ if (!$.fn.select2) {
10
+ console.error('Select2 is not loaded. Please ensure select2 is properly imported.');
11
+ return;
12
+ }
13
+
14
+ inputs.each(function() {
15
+ const item = $(this);
16
+
17
+ // reading from data allows <input data-searchable_select='{"tags": ['some']}'>
18
+ // to be passed to select2
19
+ const options = $.extend(extra || {}, item.data('searchableSelect'));
20
+ const url = item.data('ajaxUrl');
21
+
22
+ if (url) {
23
+ $.extend(options, {
24
+ ajax: {
25
+ url: url,
26
+ dataType: 'json',
27
+
28
+ data: function (params) {
29
+ return {
30
+ term: params.term,
31
+ page: pageParamWithBaseZero(params)
32
+ };
33
+ }
34
+ }
35
+ });
36
+ }
37
+
38
+ item.select2(options);
39
+ });
40
+ }
41
+
42
+ function pageParamWithBaseZero(params) {
43
+ return params.page ? params.page - 1 : undefined;
44
+ }
45
+
46
+ $(document).on('has_many_add:after', '.has_many_container', function(e, fieldset) {
47
+ initSearchableSelects(fieldset.find('.searchable-select-input'));
48
+ });
49
+
50
+ // Support both Turbolinks and Turbo
51
+ $(document).on('page:load turbolinks:load turbo:load', function() {
52
+ initSearchableSelects($(".searchable-select-input"), {placeholder: ""});
53
+ });
54
+
55
+ $(function() {
56
+ initSearchableSelects($(".searchable-select-input"));
57
+ });
58
+ }());
@@ -0,0 +1,5 @@
1
+ .searchable_select.input .select2-container {
2
+ min-width: 30%;
3
+ }
4
+
5
+ /*# sourceMappingURL=searchable_select.css.map */
@@ -0,0 +1 @@
1
+ {"version":3,"sourceRoot":"","sources":["searchable_select.scss"],"names":[],"mappings":"AAEA;EACE","file":"searchable_select.css"}