activeadmin-tom_select 4.1.0
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 +7 -0
- data/.actrc +20 -0
- data/.claude/commands/fix-tests.md +203 -0
- data/.github/workflows/ci.yml +174 -0
- data/.github/workflows/npm-publish.yml +50 -0
- data/.gitignore +35 -0
- data/.npmignore +58 -0
- data/.rspec +1 -0
- data/.rubocop.yml +75 -0
- data/.yardopts +2 -0
- data/AGENTS.md +39 -0
- data/Appraisals +9 -0
- data/CHANGELOG.md +64 -0
- data/CLAUDE.md +157 -0
- data/Gemfile +12 -0
- data/Gemfile.lock +368 -0
- data/LICENSE.txt +25 -0
- data/README.md +483 -0
- data/Rakefile +4 -0
- data/activeadmin-tom_select.gemspec +43 -0
- data/bin/rspec +17 -0
- data/config/database.yml +16 -0
- data/docs/activeadmin-4-detailed-reference.md +932 -0
- data/docs/activeadmin-4-gem-migration-guide.md +313 -0
- data/docs/combustion.md +213 -0
- data/docs/fail.png +0 -0
- data/docs/guide-update-your-app.md +283 -0
- data/docs/normal.png +0 -0
- data/docs/propshaft-readme.md +320 -0
- data/docs/propshaft-upgrade.md +484 -0
- data/docs/setup-activeadmin-app.md +552 -0
- data/docs/setup-activeadmin-gem.md +535 -0
- data/docs/tailwind/blog-page.md +341 -0
- data/docs/tailwind/upgrade-guide-enhanced.md +438 -0
- data/docs/tailwind/upgrade-guide.md +416 -0
- data/docs/tailwind-4/active_admin.rake +38 -0
- data/docs/tailwind-4/active_admin.tailwind.css +415 -0
- data/docs/tailwind-4/tailwind-active_admin.config.js +18 -0
- data/docs/test-app-change.md +154 -0
- data/docs/test-environment-fixes.md +58 -0
- data/docs/update-tom-select.md +184 -0
- data/docs/upload-system.md +225 -0
- data/gemfiles/rails_7.x_active_admin_4.x.gemfile +10 -0
- data/gemfiles/rails_7.x_active_admin_4.x.gemfile.lock +377 -0
- data/gemfiles/rails_8.x_active_admin_4.x.gemfile +10 -0
- data/gemfiles/rails_8.x_active_admin_4.x.gemfile.lock +372 -0
- data/lefthook.yml +17 -0
- data/lib/activeadmin/inputs/filters/searchable_select_input.rb +19 -0
- data/lib/activeadmin/inputs/searchable_select_input.rb +16 -0
- data/lib/activeadmin/tom_select/engine.rb +17 -0
- data/lib/activeadmin/tom_select/option_collection.rb +128 -0
- data/lib/activeadmin/tom_select/resource_dsl_extension.rb +56 -0
- data/lib/activeadmin/tom_select/resource_extension.rb +10 -0
- data/lib/activeadmin/tom_select/select_input_extension.rb +168 -0
- data/lib/activeadmin/tom_select/version.rb +5 -0
- data/lib/activeadmin/tom_select.rb +20 -0
- data/lib/activeadmin-tom_select.rb +5 -0
- data/lib/generators/active_admin/tom_select/install/install_generator.rb +180 -0
- data/npm-package/package-lock.json +51 -0
- data/npm-package/package.json +43 -0
- data/npm-package/src/index.js +153 -0
- data/npm-package/src/tom-select-tailwind.css +392 -0
- data/sonar-project.properties +25 -0
- data/spec/features/ajax_params_spec.rb +31 -0
- data/spec/features/asset_pipeline_diagnostic_spec.rb +155 -0
- data/spec/features/end_to_end_spec.rb +273 -0
- data/spec/features/filter_input_spec.rb +144 -0
- data/spec/features/form_input_spec.rb +122 -0
- data/spec/features/inline_ajax_setting_spec.rb +26 -0
- data/spec/features/input_errors_spec.rb +76 -0
- data/spec/features/input_html_options_spec.rb +30 -0
- data/spec/features/options_dsl_spec.rb +230 -0
- data/spec/features/production_build_spec.rb +108 -0
- data/spec/internal/.node-version +1 -0
- data/spec/internal/Gemfile +43 -0
- data/spec/internal/Gemfile.lock +333 -0
- data/spec/internal/Procfile.dev +3 -0
- data/spec/internal/README.md +24 -0
- data/spec/internal/Rakefile +6 -0
- data/spec/internal/app/admin/categories.rb +26 -0
- data/spec/internal/app/admin/dashboard.rb +29 -0
- data/spec/internal/app/admin/option_types.rb +19 -0
- data/spec/internal/app/admin/option_values.rb +30 -0
- data/spec/internal/app/admin/posts.rb +27 -0
- data/spec/internal/app/admin/products.rb +22 -0
- data/spec/internal/app/admin/rgb_colors.rb +25 -0
- data/spec/internal/app/admin/tag_names.rb +21 -0
- data/spec/internal/app/admin/test_ajax_params_category.rb +10 -0
- data/spec/internal/app/admin/test_ajax_params_post.rb +20 -0
- data/spec/internal/app/admin/test_form_post_class.rb +7 -0
- data/spec/internal/app/admin/test_form_post_custom.rb +11 -0
- data/spec/internal/app/admin/test_form_post_resource.rb +11 -0
- data/spec/internal/app/admin/test_form_post_resource_custom.rb +12 -0
- data/spec/internal/app/admin/test_inline_ajax_post.rb +9 -0
- data/spec/internal/app/admin/test_input_html_post.rb +11 -0
- data/spec/internal/app/admin/test_posts_display_text.rb +9 -0
- data/spec/internal/app/admin/test_posts_filter.rb +9 -0
- data/spec/internal/app/admin/test_posts_named.rb +9 -0
- data/spec/internal/app/admin/test_posts_pagination.rb +9 -0
- data/spec/internal/app/admin/test_posts_payload_lambda.rb +11 -0
- data/spec/internal/app/admin/test_posts_payload_proc.rb +9 -0
- data/spec/internal/app/admin/test_posts_scope_lambda.rb +8 -0
- data/spec/internal/app/admin/test_posts_scope_params.rb +8 -0
- data/spec/internal/app/admin/test_posts_scope_user.rb +8 -0
- data/spec/internal/app/admin/test_posts_text_attr.rb +5 -0
- data/spec/internal/app/admin/users.rb +23 -0
- data/spec/internal/app/admin/variants.rb +31 -0
- data/spec/internal/app/assets/config/manifest.js +2 -0
- data/spec/internal/app/assets/images/.keep +0 -0
- data/spec/internal/app/assets/stylesheets/active_admin.tailwind.css +16 -0
- data/spec/internal/app/assets/stylesheets/application.tailwind.css +15 -0
- data/spec/internal/app/controllers/application_controller.rb +9 -0
- data/spec/internal/app/controllers/concerns/.keep +0 -0
- data/spec/internal/app/helpers/application_helper.rb +2 -0
- data/spec/internal/app/javascript/active_admin.js +19 -0
- data/spec/internal/app/javascript/application.js +2 -0
- data/spec/internal/app/jobs/application_job.rb +7 -0
- data/spec/internal/app/mailers/application_mailer.rb +4 -0
- data/spec/internal/app/models/admin_user.rb +9 -0
- data/spec/internal/app/models/application_record.rb +3 -0
- data/spec/internal/app/models/article.rb +12 -0
- data/spec/internal/app/models/category.rb +12 -0
- data/spec/internal/app/models/color.rb +9 -0
- data/spec/internal/app/models/concerns/.keep +0 -0
- data/spec/internal/app/models/internal/tag_name.rb +14 -0
- data/spec/internal/app/models/internal_tag_name.rb +11 -0
- data/spec/internal/app/models/option_type.rb +12 -0
- data/spec/internal/app/models/option_value.rb +4 -0
- data/spec/internal/app/models/post.rb +15 -0
- data/spec/internal/app/models/product.rb +12 -0
- data/spec/internal/app/models/rgb_color.rb +16 -0
- data/spec/internal/app/models/tag.rb +12 -0
- data/spec/internal/app/models/tagging.rb +12 -0
- data/spec/internal/app/models/user.rb +12 -0
- data/spec/internal/app/models/variant.rb +12 -0
- data/spec/internal/app/views/layouts/application.html.erb +28 -0
- data/spec/internal/app/views/layouts/mailer.html.erb +13 -0
- data/spec/internal/app/views/layouts/mailer.text.erb +1 -0
- data/spec/internal/app/views/pwa/manifest.json.erb +22 -0
- data/spec/internal/app/views/pwa/service-worker.js +26 -0
- data/spec/internal/bin/bundle +117 -0
- data/spec/internal/bin/dev +11 -0
- data/spec/internal/bin/rackup +27 -0
- data/spec/internal/bin/rails +4 -0
- data/spec/internal/bin/rake +4 -0
- data/spec/internal/bin/setup +37 -0
- data/spec/internal/config/application.rb +50 -0
- data/spec/internal/config/boot.rb +3 -0
- data/spec/internal/config/credentials.yml.enc +1 -0
- data/spec/internal/config/database.yml +32 -0
- data/spec/internal/config/environment.rb +5 -0
- data/spec/internal/config/environments/development.rb +63 -0
- data/spec/internal/config/environments/production.rb +86 -0
- data/spec/internal/config/environments/test.rb +50 -0
- data/spec/internal/config/initializers/active_admin.rb +54 -0
- data/spec/internal/config/initializers/assets.rb +8 -0
- data/spec/internal/config/initializers/content_security_policy.rb +25 -0
- data/spec/internal/config/initializers/devise.rb +315 -0
- data/spec/internal/config/initializers/filter_parameter_logging.rb +8 -0
- data/spec/internal/config/initializers/inflections.rb +16 -0
- data/spec/internal/config/initializers/searchable_select.rb +6 -0
- data/spec/internal/config/locales/devise.en.yml +65 -0
- data/spec/internal/config/locales/en.yml +31 -0
- data/spec/internal/config/master.key +1 -0
- data/spec/internal/config/puma.rb +38 -0
- data/spec/internal/config/routes.rb +17 -0
- data/spec/internal/config.ru +6 -0
- data/spec/internal/db/schema.rb +174 -0
- data/spec/internal/db/seeds.rb +167 -0
- data/spec/internal/esbuild.config.js +34 -0
- data/spec/internal/lib/tasks/.keep +0 -0
- data/spec/internal/lib/tasks/active_admin.rake +55 -0
- data/spec/internal/log/.keep +0 -0
- data/spec/internal/package-lock.json +1954 -0
- data/spec/internal/package.json +21 -0
- data/spec/internal/public/400.html +114 -0
- data/spec/internal/public/404.html +114 -0
- data/spec/internal/public/406-unsupported-browser.html +114 -0
- data/spec/internal/public/422.html +114 -0
- data/spec/internal/public/500.html +114 -0
- data/spec/internal/public/icon.png +0 -0
- data/spec/internal/public/icon.svg +3 -0
- data/spec/internal/public/robots.txt +1 -0
- data/spec/internal/script/.keep +0 -0
- data/spec/internal/storage/.keep +0 -0
- data/spec/internal/tailwind.config.js +23 -0
- data/spec/internal/vendor/.keep +0 -0
- data/spec/internal/yarn.lock +824 -0
- data/spec/rails_helper.rb +62 -0
- data/spec/spec_helper.rb +138 -0
- data/spec/support/active_admin_helpers.rb +17 -0
- data/spec/support/capybara.rb +8 -0
- data/spec/support/models.rb +11 -0
- data/spec/support/pluck_polyfill.rb +12 -0
- data/spec/support/reset_settings.rb +5 -0
- metadata +497 -0
@@ -0,0 +1,392 @@
|
|
1
|
+
/*
|
2
|
+
Tom Select Tailwind CSS styles for ActiveAdmin Searchable Select
|
3
|
+
|
4
|
+
Credits:
|
5
|
+
- Based on discussion at https://github.com/orchidjs/tom-select/discussions/693
|
6
|
+
- Original Tailwind styles by @LeZellus (https://github.com/LeZellus)
|
7
|
+
- Updated for Tailwind CSS v4 compatibility
|
8
|
+
*/
|
9
|
+
|
10
|
+
/* Plugin: Drag & Drop */
|
11
|
+
.ts-wrapper.plugin-drag_drop.multi > .ts-control > div.ui-sortable-placeholder {
|
12
|
+
@apply visible border-none;
|
13
|
+
}
|
14
|
+
|
15
|
+
.ts-wrapper.plugin-drag_drop .ui-sortable-placeholder::after {
|
16
|
+
content: "!";
|
17
|
+
visibility: hidden;
|
18
|
+
}
|
19
|
+
|
20
|
+
/* Plugin: Checkbox Options */
|
21
|
+
.plugin-checkbox_options .option input {
|
22
|
+
margin-right: 0.5rem;
|
23
|
+
}
|
24
|
+
|
25
|
+
/* Plugin: Clear Button */
|
26
|
+
.plugin-clear_button .clear-button {
|
27
|
+
@apply opacity-0 absolute top-1/2 transform -translate-y-1/2 right-0 cursor-pointer;
|
28
|
+
}
|
29
|
+
|
30
|
+
.plugin-clear_button.single .clear-button {
|
31
|
+
@apply right-2;
|
32
|
+
}
|
33
|
+
|
34
|
+
.plugin-clear_button.focus.has-items .clear-button,
|
35
|
+
.plugin-clear_button:hover.has-items .clear-button {
|
36
|
+
@apply opacity-100;
|
37
|
+
}
|
38
|
+
|
39
|
+
/* Plugin: Dropdown Header */
|
40
|
+
.ts-wrapper .dropdown-header {
|
41
|
+
@apply relative p-2.5 rounded-t border-b border-gray-300 bg-gray-100;
|
42
|
+
}
|
43
|
+
|
44
|
+
.ts-wrapper .dropdown-header-close {
|
45
|
+
@apply absolute right-2 top-1/2 opacity-40 -mt-3 leading-5 text-xl;
|
46
|
+
}
|
47
|
+
|
48
|
+
.ts-wrapper .dropdown-header-close:hover {
|
49
|
+
@apply text-black;
|
50
|
+
}
|
51
|
+
|
52
|
+
/* Plugin: Dropdown Input */
|
53
|
+
.plugin-dropdown_input .dropdown-input {
|
54
|
+
@apply block p-2 shadow-none w-full bg-transparent border-b border-gray-300;
|
55
|
+
}
|
56
|
+
|
57
|
+
/* Plugin: Input Autogrow */
|
58
|
+
.ts-wrapper.plugin-input_autogrow.has-items .ts-control > input {
|
59
|
+
@apply min-w-0;
|
60
|
+
}
|
61
|
+
|
62
|
+
.ts-wrapper.plugin-input_autogrow.has-items.focus .ts-control > input {
|
63
|
+
@apply flex;
|
64
|
+
min-width: 4px;
|
65
|
+
}
|
66
|
+
|
67
|
+
.ts-wrapper.plugin-input_autogrow.has-items.focus .ts-control > input::-webkit-input-placeholder {
|
68
|
+
@apply text-transparent;
|
69
|
+
}
|
70
|
+
|
71
|
+
.ts-wrapper.plugin-input_autogrow.has-items.focus .ts-control > input::-ms-input-placeholder {
|
72
|
+
@apply text-transparent;
|
73
|
+
}
|
74
|
+
|
75
|
+
.ts-wrapper.plugin-input_autogrow.has-items.focus .ts-control > input::placeholder {
|
76
|
+
@apply text-transparent;
|
77
|
+
}
|
78
|
+
|
79
|
+
/* Plugin: Optgroup Columns */
|
80
|
+
.ts-dropdown.plugin-optgroup_columns .ts-dropdown-content {
|
81
|
+
@apply flex;
|
82
|
+
}
|
83
|
+
|
84
|
+
.ts-dropdown.plugin-optgroup_columns .optgroup {
|
85
|
+
@apply flex-grow border-t-0 border-r border-gray-100 basis-0 min-w-0;
|
86
|
+
}
|
87
|
+
|
88
|
+
.ts-dropdown.plugin-optgroup_columns .optgroup:last-child {
|
89
|
+
@apply border-r-0;
|
90
|
+
}
|
91
|
+
|
92
|
+
.ts-dropdown.plugin-optgroup_columns .optgroup:before {
|
93
|
+
@apply hidden;
|
94
|
+
}
|
95
|
+
|
96
|
+
.ts-dropdown.plugin-optgroup_columns .optgroup-header {
|
97
|
+
@apply border-t-0;
|
98
|
+
}
|
99
|
+
|
100
|
+
/* Plugin: Remove Button */
|
101
|
+
.ts-wrapper.plugin-remove_button .item {
|
102
|
+
@apply inline-flex items-center pr-0;
|
103
|
+
}
|
104
|
+
|
105
|
+
.ts-wrapper.plugin-remove_button .item .remove {
|
106
|
+
@apply text-inherit no-underline align-middle inline-block p-0 px-1.5 border-l border-gray-300 rounded-r-sm box-border ml-1.5;
|
107
|
+
}
|
108
|
+
|
109
|
+
.ts-wrapper.plugin-remove_button .item .remove:hover {
|
110
|
+
background: rgba(0, 0, 0, 0.05);
|
111
|
+
}
|
112
|
+
|
113
|
+
.ts-wrapper.plugin-remove_button .item.active .remove {
|
114
|
+
border-left-color: #cacaca;
|
115
|
+
}
|
116
|
+
|
117
|
+
.ts-wrapper.plugin-remove_button.disabled .item .remove:hover {
|
118
|
+
background: none;
|
119
|
+
}
|
120
|
+
|
121
|
+
.ts-wrapper.plugin-remove_button.disabled .item .remove {
|
122
|
+
border-left-color: white;
|
123
|
+
}
|
124
|
+
|
125
|
+
.ts-wrapper.plugin-remove_button .remove-single {
|
126
|
+
position: absolute;
|
127
|
+
right: 0;
|
128
|
+
top: 0;
|
129
|
+
font-size: 23px;
|
130
|
+
}
|
131
|
+
|
132
|
+
/* Core Tom Select Styles */
|
133
|
+
.ts-wrapper {
|
134
|
+
position: relative;
|
135
|
+
}
|
136
|
+
|
137
|
+
.ts-dropdown,
|
138
|
+
.ts-control,
|
139
|
+
.ts-control input {
|
140
|
+
color: #303030;
|
141
|
+
font-family: inherit;
|
142
|
+
font-size: 13px;
|
143
|
+
line-height: 18px;
|
144
|
+
}
|
145
|
+
|
146
|
+
/* Control (Input) Styles */
|
147
|
+
.ts-control,
|
148
|
+
.ts-wrapper.single.input-active .ts-control {
|
149
|
+
@apply bg-white dark:bg-gray-900;
|
150
|
+
cursor: text;
|
151
|
+
}
|
152
|
+
|
153
|
+
.ts-control {
|
154
|
+
@apply border border-gray-300 dark:border-gray-600 p-2 w-full overflow-hidden relative z-10 box-border shadow-none rounded-sm flex flex-wrap;
|
155
|
+
}
|
156
|
+
|
157
|
+
.ts-wrapper.multi.has-items .ts-control {
|
158
|
+
padding: 6px 8px 3px;
|
159
|
+
}
|
160
|
+
|
161
|
+
.full .ts-control {
|
162
|
+
@apply bg-gray-50 dark:bg-gray-900 dark:text-gray-100;
|
163
|
+
}
|
164
|
+
|
165
|
+
.disabled .ts-control,
|
166
|
+
.disabled .ts-control * {
|
167
|
+
@apply cursor-default;
|
168
|
+
}
|
169
|
+
|
170
|
+
.focus .ts-control {
|
171
|
+
@apply shadow-none border-indigo-500 ring-1 ring-indigo-500;
|
172
|
+
}
|
173
|
+
|
174
|
+
.ts-control > * {
|
175
|
+
@apply align-baseline inline-block;
|
176
|
+
}
|
177
|
+
|
178
|
+
/* Multi-select Items */
|
179
|
+
.ts-wrapper.multi .ts-control > div {
|
180
|
+
@apply cursor-pointer m-0 mr-1 my-1 px-2 py-1 bg-gray-100 text-gray-800 border-0 rounded-sm;
|
181
|
+
}
|
182
|
+
|
183
|
+
.ts-wrapper.multi .ts-control > div.active {
|
184
|
+
@apply bg-gray-200 text-gray-900;
|
185
|
+
}
|
186
|
+
|
187
|
+
.ts-wrapper.multi.disabled .ts-control > div,
|
188
|
+
.ts-wrapper.multi.disabled .ts-control > div.active {
|
189
|
+
@apply text-gray-400 bg-gray-50 border-0;
|
190
|
+
}
|
191
|
+
|
192
|
+
/* Selected items display */
|
193
|
+
.ts-control .item {
|
194
|
+
@apply inline-flex items-center;
|
195
|
+
}
|
196
|
+
|
197
|
+
/* Input Field */
|
198
|
+
.ts-control > input {
|
199
|
+
@apply inline-block p-0 min-h-0 max-w-full m-0 indent-0 border-0 bg-transparent flex-grow select-auto placeholder-gray-400 dark:placeholder-gray-600;
|
200
|
+
min-width: 7rem;
|
201
|
+
max-height: none !important;
|
202
|
+
box-shadow: none !important;
|
203
|
+
outline: none !important;
|
204
|
+
}
|
205
|
+
|
206
|
+
.ts-control > input::-ms-clear {
|
207
|
+
@apply hidden;
|
208
|
+
}
|
209
|
+
|
210
|
+
.ts-control > input:focus {
|
211
|
+
@apply outline-none;
|
212
|
+
}
|
213
|
+
|
214
|
+
.has-items .ts-control > input {
|
215
|
+
margin: 0 4px !important;
|
216
|
+
}
|
217
|
+
|
218
|
+
/* RTL Support */
|
219
|
+
.ts-control.rtl {
|
220
|
+
@apply text-right;
|
221
|
+
}
|
222
|
+
|
223
|
+
.ts-control.rtl.single .ts-control:after {
|
224
|
+
@apply absolute right-auto;
|
225
|
+
content: '';
|
226
|
+
left: 15px;
|
227
|
+
}
|
228
|
+
|
229
|
+
.ts-control.rtl .ts-control > input {
|
230
|
+
margin: 0 4px 0 -2px !important;
|
231
|
+
}
|
232
|
+
|
233
|
+
/* Disabled State */
|
234
|
+
.disabled .ts-control {
|
235
|
+
@apply opacity-50 bg-gray-50 cursor-not-allowed;
|
236
|
+
}
|
237
|
+
|
238
|
+
.input-hidden .ts-control > input {
|
239
|
+
@apply opacity-0 absolute;
|
240
|
+
left: -10000px;
|
241
|
+
}
|
242
|
+
|
243
|
+
/* Dropdown Styles */
|
244
|
+
.ts-dropdown {
|
245
|
+
@apply absolute top-full left-0 w-full z-50 border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-900 mt-1 box-border rounded-sm shadow-sm overflow-hidden;
|
246
|
+
}
|
247
|
+
|
248
|
+
.ts-dropdown [data-selectable] {
|
249
|
+
@apply cursor-pointer overflow-hidden;
|
250
|
+
}
|
251
|
+
|
252
|
+
.ts-dropdown [data-selectable] .highlight {
|
253
|
+
background: rgba(125, 168, 208, 0.2);
|
254
|
+
border-radius: 1px;
|
255
|
+
}
|
256
|
+
|
257
|
+
.ts-dropdown .option,
|
258
|
+
.ts-dropdown .optgroup-header,
|
259
|
+
.ts-dropdown .no-results,
|
260
|
+
.ts-dropdown .create {
|
261
|
+
@apply px-3 py-2;
|
262
|
+
}
|
263
|
+
|
264
|
+
.ts-dropdown .option,
|
265
|
+
.ts-dropdown [data-disabled],
|
266
|
+
.ts-dropdown [data-disabled] [data-selectable].option {
|
267
|
+
cursor: inherit;
|
268
|
+
opacity: 0.5;
|
269
|
+
}
|
270
|
+
|
271
|
+
.ts-dropdown [data-selectable].option {
|
272
|
+
@apply opacity-100 cursor-pointer text-gray-900 dark:text-gray-100;
|
273
|
+
}
|
274
|
+
|
275
|
+
.ts-dropdown .optgroup:first-child .optgroup-header {
|
276
|
+
@apply border-t-0;
|
277
|
+
}
|
278
|
+
|
279
|
+
.ts-dropdown .optgroup-header {
|
280
|
+
@apply cursor-default bg-gray-50 text-gray-700 font-semibold text-xs uppercase tracking-wider;
|
281
|
+
}
|
282
|
+
|
283
|
+
/* Hover and Active States */
|
284
|
+
.ts-dropdown .create:hover,
|
285
|
+
.ts-dropdown .option:hover,
|
286
|
+
.ts-dropdown .active {
|
287
|
+
@apply bg-indigo-50 dark:bg-gray-800 text-indigo-900 dark:text-gray-100;
|
288
|
+
}
|
289
|
+
|
290
|
+
.ts-dropdown .create:hover.create,
|
291
|
+
.ts-dropdown .option:hover.create,
|
292
|
+
.ts-dropdown .active.create {
|
293
|
+
@apply text-gray-600;
|
294
|
+
}
|
295
|
+
|
296
|
+
.ts-dropdown .create {
|
297
|
+
@apply text-gray-500;
|
298
|
+
}
|
299
|
+
|
300
|
+
/* Loading Spinner */
|
301
|
+
.ts-dropdown .spinner {
|
302
|
+
@apply inline-block w-7 h-7 m-1 mx-2;
|
303
|
+
}
|
304
|
+
|
305
|
+
.ts-dropdown .spinner:after {
|
306
|
+
@apply block w-6 h-6 m-1 rounded-full border-4 border-gray-300;
|
307
|
+
content: " ";
|
308
|
+
border-color: #3b82f6 transparent #3b82f6 transparent;
|
309
|
+
animation: lds-dual-ring 1.2s linear infinite;
|
310
|
+
}
|
311
|
+
|
312
|
+
@keyframes lds-dual-ring {
|
313
|
+
0% {
|
314
|
+
transform: rotate(0deg);
|
315
|
+
}
|
316
|
+
100% {
|
317
|
+
transform: rotate(360deg);
|
318
|
+
}
|
319
|
+
}
|
320
|
+
|
321
|
+
/* Dropdown Content Scrolling */
|
322
|
+
.ts-dropdown-content {
|
323
|
+
@apply overflow-y-auto overflow-x-hidden max-h-52;
|
324
|
+
-webkit-overflow-scrolling: touch;
|
325
|
+
scroll-behavior: smooth;
|
326
|
+
}
|
327
|
+
|
328
|
+
/* Accessibility Helper */
|
329
|
+
.ts-hidden-accessible {
|
330
|
+
@apply border-0 overflow-hidden p-0 absolute whitespace-nowrap;
|
331
|
+
width: 1px !important;
|
332
|
+
height: 1px !important;
|
333
|
+
clip: rect(0 0 0 0) !important;
|
334
|
+
clip-path: inset(50%) !important;
|
335
|
+
}
|
336
|
+
|
337
|
+
/* Single Select Arrow */
|
338
|
+
.ts-wrapper.single .ts-control:not(.dropdown-active) {
|
339
|
+
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e");
|
340
|
+
background-position: right 0.5rem center;
|
341
|
+
background-repeat: no-repeat;
|
342
|
+
background-size: 1.5em 1.5em;
|
343
|
+
padding-right: 2.5rem;
|
344
|
+
}
|
345
|
+
|
346
|
+
/* Override ActiveAdmin's width: 100% on inputs inside Tom Select */
|
347
|
+
.ts-wrapper.single .ts-control,
|
348
|
+
.ts-wrapper.single .ts-control input {
|
349
|
+
width: auto !important;
|
350
|
+
}
|
351
|
+
|
352
|
+
/* ActiveAdmin Specific Overrides */
|
353
|
+
.searchable_select.input .ts-wrapper {
|
354
|
+
min-width: 30%;
|
355
|
+
display: inline-block;
|
356
|
+
}
|
357
|
+
|
358
|
+
.searchable_select.input .ts-control {
|
359
|
+
margin-top: 0;
|
360
|
+
}
|
361
|
+
|
362
|
+
/* Filter Form Specific Styles */
|
363
|
+
.filter_form .searchable_select.input .ts-wrapper {
|
364
|
+
width: 100%;
|
365
|
+
}
|
366
|
+
|
367
|
+
/* Hide Duplicate Elements */
|
368
|
+
.ts-wrapper + .ts-control {
|
369
|
+
display: none;
|
370
|
+
}
|
371
|
+
|
372
|
+
/* Dark Mode Support */
|
373
|
+
.dark .ts-control {
|
374
|
+
@apply bg-gray-800 border-gray-600 text-gray-100;
|
375
|
+
}
|
376
|
+
|
377
|
+
.dark .ts-dropdown {
|
378
|
+
@apply bg-gray-800 border-gray-600;
|
379
|
+
}
|
380
|
+
|
381
|
+
.dark .ts-dropdown .option {
|
382
|
+
@apply text-gray-100;
|
383
|
+
}
|
384
|
+
|
385
|
+
.dark .ts-dropdown .option:hover,
|
386
|
+
.dark .ts-dropdown [data-selectable].active {
|
387
|
+
@apply bg-gray-700 text-white;
|
388
|
+
}
|
389
|
+
|
390
|
+
.dark .ts-wrapper.multi .ts-control > div {
|
391
|
+
@apply bg-gray-700 text-gray-100;
|
392
|
+
}
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# SonarQube project configuration
|
2
|
+
sonar.projectKey=glebtv_activeadmin-searchable_select
|
3
|
+
sonar.projectName=activeadmin-searchable_select
|
4
|
+
sonar.projectVersion=0.5.0
|
5
|
+
|
6
|
+
# Source code directories
|
7
|
+
sonar.sources=lib,app
|
8
|
+
sonar.tests=spec
|
9
|
+
|
10
|
+
# Language
|
11
|
+
sonar.language=ruby
|
12
|
+
|
13
|
+
# Encoding
|
14
|
+
sonar.sourceEncoding=UTF-8
|
15
|
+
|
16
|
+
# Ruby specific settings
|
17
|
+
sonar.ruby.file.suffixes=.rb,.rake
|
18
|
+
sonar.ruby.coverage.reportPaths=coverage/coverage.json
|
19
|
+
|
20
|
+
# Exclusions
|
21
|
+
sonar.exclusions=spec/**/*,vendor/**/*,coverage/**/*,tmp/**/*,*.gemspec,gemfiles/**/*,Appraisals
|
22
|
+
sonar.test.exclusions=spec/internal/app/assets/builds/**/*,spec/internal/public/**/*,spec/internal/node_modules/**/*
|
23
|
+
|
24
|
+
# Coverage exclusions (files that don't need coverage)
|
25
|
+
sonar.coverage.exclusions=spec/**/*,vendor/**/*,spec/internal/**/*,**/*_spec.rb
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
|
3
|
+
require 'support/models'
|
4
|
+
require 'support/capybara'
|
5
|
+
|
6
|
+
RSpec.describe 'ajax params', type: :request do
|
7
|
+
# Using static TestAjaxParamsPost and TestAjaxParamsCategory admins
|
8
|
+
|
9
|
+
it 'passes parameters when rendering selected item' do
|
10
|
+
user = User.create
|
11
|
+
category = Category.create(name: 'Travel', created_by: user)
|
12
|
+
post = Post.create(category: category)
|
13
|
+
|
14
|
+
ApplicationController.current_user = user
|
15
|
+
get "/admin/test_ajax_params_posts/#{post.id}/edit"
|
16
|
+
|
17
|
+
expect(response.body).to have_selector('.searchable-select-input option[selected]',
|
18
|
+
text: 'Travel')
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'includes parameters in ajax url' do
|
22
|
+
user = User.create
|
23
|
+
|
24
|
+
ApplicationController.current_user = user
|
25
|
+
get '/admin/test_ajax_params_posts/new'
|
26
|
+
|
27
|
+
url_matcher = "?created_by=#{user.id}"
|
28
|
+
expect(response.body).to have_selector('.searchable-select-input' \
|
29
|
+
"[data-ajax-url*='#{url_matcher}']")
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,155 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
|
3
|
+
RSpec.describe 'Asset Pipeline Diagnostics', type: :feature do
|
4
|
+
describe 'Asset Configuration' do
|
5
|
+
it 'verifies all asset pipeline components are properly configured', js: true do
|
6
|
+
errors = []
|
7
|
+
|
8
|
+
# 1. Check Propshaft is loaded
|
9
|
+
if defined?(Rails.application.assets)
|
10
|
+
# 2. Check asset paths are configured
|
11
|
+
errors << 'No asset paths configured' if Rails.application.assets.load_path.paths.empty?
|
12
|
+
|
13
|
+
# 3. Check resolver type
|
14
|
+
unless Rails.application.assets.resolver.is_a?(Propshaft::Resolver::Dynamic)
|
15
|
+
errors << "Wrong resolver type: #{Rails.application.assets.resolver.class}"
|
16
|
+
end
|
17
|
+
else
|
18
|
+
errors << 'Rails.application.assets not defined - Propshaft not loaded'
|
19
|
+
end
|
20
|
+
|
21
|
+
# 4. Check built assets exist and contain expected content
|
22
|
+
builds_path = Rails.root.join('app/assets/builds')
|
23
|
+
if File.exist?(builds_path)
|
24
|
+
# Check JavaScript file
|
25
|
+
js_file = File.join(builds_path, 'active_admin.js')
|
26
|
+
if File.exist?(js_file)
|
27
|
+
js_content = File.read(js_file)
|
28
|
+
js_checks = {
|
29
|
+
'TomSelect class' => js_content.include?('TomSelect'),
|
30
|
+
'initSearchableSelects function' => js_content.include?('initSearchableSelects'),
|
31
|
+
'window.TomSelect assignment' => js_content.include?('window.TomSelect'),
|
32
|
+
'DOMContentLoaded listener' => js_content.include?('DOMContentLoaded'),
|
33
|
+
'searchable-select-input selector' => js_content.include?('searchable-select-input')
|
34
|
+
}
|
35
|
+
|
36
|
+
js_checks.each do |check, present|
|
37
|
+
errors << "JavaScript missing: #{check}" unless present
|
38
|
+
end
|
39
|
+
else
|
40
|
+
errors << 'active_admin.js not found in builds directory'
|
41
|
+
end
|
42
|
+
|
43
|
+
# Check CSS file
|
44
|
+
css_file = File.join(builds_path, 'active_admin.css')
|
45
|
+
if File.exist?(css_file)
|
46
|
+
css_content = File.read(css_file)
|
47
|
+
css_checks = {
|
48
|
+
'ts-wrapper styles' => css_content.include?('.ts-wrapper'),
|
49
|
+
'ts-control styles' => css_content.include?('.ts-control'),
|
50
|
+
'ts-dropdown styles' => css_content.include?('.ts-dropdown')
|
51
|
+
}
|
52
|
+
|
53
|
+
css_checks.each do |check, present|
|
54
|
+
errors << "CSS missing: #{check}" unless present
|
55
|
+
end
|
56
|
+
else
|
57
|
+
errors << 'active_admin.css not found in builds directory'
|
58
|
+
end
|
59
|
+
else
|
60
|
+
errors << "Builds directory does not exist at #{builds_path}"
|
61
|
+
end
|
62
|
+
|
63
|
+
# 5. Test actual asset serving in browser
|
64
|
+
visit '/admin/posts'
|
65
|
+
|
66
|
+
# Check if assets are loaded in browser
|
67
|
+
js_loaded = page.evaluate_script("typeof window.TomSelect !== 'undefined'")
|
68
|
+
errors << 'TomSelect not loaded in browser' unless js_loaded
|
69
|
+
|
70
|
+
init_loaded = page.evaluate_script("typeof window.initSearchableSelects !== 'undefined'")
|
71
|
+
errors << 'initSearchableSelects not loaded in browser' unless init_loaded
|
72
|
+
|
73
|
+
# Check if Tom Select initialized
|
74
|
+
inputs = page.evaluate_script("document.querySelectorAll('.searchable-select-input').length")
|
75
|
+
ts_wrappers = page.evaluate_script("document.querySelectorAll('.ts-wrapper').length")
|
76
|
+
|
77
|
+
if inputs > 0 && ts_wrappers == 0
|
78
|
+
errors << "Tom Select not initializing (#{inputs} inputs but 0 wrappers)"
|
79
|
+
end
|
80
|
+
|
81
|
+
# Only print diagnostic info if there are errors
|
82
|
+
if errors.any?
|
83
|
+
puts "\n#{'=' * 80}"
|
84
|
+
puts 'ASSET PIPELINE DIAGNOSTIC FAILURES'
|
85
|
+
puts '=' * 80
|
86
|
+
|
87
|
+
errors.each do |error|
|
88
|
+
puts " ✗ #{error}"
|
89
|
+
end
|
90
|
+
|
91
|
+
# Print additional debugging info
|
92
|
+
puts "\nDEBUG INFO:"
|
93
|
+
puts '-' * 40
|
94
|
+
|
95
|
+
if defined?(Rails.application.assets)
|
96
|
+
puts "Asset paths (#{Rails.application.assets.load_path.paths.count}):"
|
97
|
+
Rails.application.assets.load_path.paths.each { |path| puts " - #{path}" }
|
98
|
+
|
99
|
+
puts "\nResolver: #{Rails.application.assets.resolver.class}"
|
100
|
+
end
|
101
|
+
|
102
|
+
if File.exist?(builds_path)
|
103
|
+
puts "\nBuilt files:"
|
104
|
+
Dir.glob(File.join(builds_path, '*')).each do |file|
|
105
|
+
puts " - #{File.basename(file)}: #{File.size(file)} bytes"
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# Check asset URLs in page
|
110
|
+
html = page.html
|
111
|
+
js_tags = html.scan(/<script[^>]*src=["']([^"']+)["'][^>]*>/).flatten
|
112
|
+
css_tags = html.scan(/<link[^>]*href=["']([^"']+\.css[^"']*)["'][^>]*>/).flatten
|
113
|
+
|
114
|
+
puts "\nAsset tags in HTML:"
|
115
|
+
puts " JS: #{js_tags.join(', ')}"
|
116
|
+
puts " CSS: #{css_tags.join(', ')}"
|
117
|
+
|
118
|
+
puts "\nBrowser state:"
|
119
|
+
puts " Inputs found: #{inputs}"
|
120
|
+
puts " Tom Select wrappers: #{ts_wrappers}"
|
121
|
+
|
122
|
+
puts '=' * 80
|
123
|
+
end
|
124
|
+
|
125
|
+
# Fail the test if there are any errors
|
126
|
+
expect(errors).to be_empty
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
describe 'Asset Serving in Test Mode', js: true do
|
131
|
+
it 'serves assets correctly through Propshaft' do
|
132
|
+
visit '/admin/posts'
|
133
|
+
|
134
|
+
# Check that assets are served with digest URLs
|
135
|
+
js_url = page.evaluate_script("document.querySelector('script[src*=\"active_admin\"]')?.src")
|
136
|
+
css_url = page.evaluate_script("document.querySelector('link[href*=\"active_admin\"]')?.href")
|
137
|
+
|
138
|
+
# Only check if URLs exist and use /assets/ path
|
139
|
+
expect(js_url).to match(%r{/assets/active_admin-[a-f0-9]+\.js})
|
140
|
+
expect(css_url).to match(%r{/assets/active_admin-[a-f0-9]+\.css})
|
141
|
+
|
142
|
+
# Check that assets actually load
|
143
|
+
if js_url
|
144
|
+
response = Net::HTTP.get_response(URI(js_url))
|
145
|
+
expect(response.code).to eq('200')
|
146
|
+
expect(response.body).to include('TomSelect')
|
147
|
+
end
|
148
|
+
|
149
|
+
if css_url
|
150
|
+
response = Net::HTTP.get_response(URI(css_url))
|
151
|
+
expect(response.code).to eq('200')
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|