iron_admin 0.4.1 → 0.6.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.
Files changed (456) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +66 -30
  3. data/app/assets/config/iron_admin_manifest.js +12 -0
  4. data/app/components/iron_admin/dashboards/metric_card_component.html.haml +8 -3
  5. data/app/components/iron_admin/dashboards/metric_card_component.rb +21 -1
  6. data/app/components/iron_admin/form/belongs_to_component.rb +60 -6
  7. data/app/components/iron_admin/form/nested_form_component.html.haml +28 -0
  8. data/app/components/iron_admin/form/nested_form_component.rb +81 -0
  9. data/app/components/iron_admin/resources/data_table_component.html.haml +1 -1
  10. data/app/components/iron_admin/resources/data_table_component.rb +6 -0
  11. data/app/components/iron_admin/resources/show_field_component.rb +2 -0
  12. data/app/controllers/iron_admin/application_controller.rb +32 -1
  13. data/app/controllers/iron_admin/concerns/action_executable.rb +44 -0
  14. data/app/controllers/iron_admin/concerns/filterable.rb +84 -0
  15. data/app/controllers/iron_admin/concerns/json_params_coercion.rb +67 -0
  16. data/app/controllers/iron_admin/concerns/nested_permittable.rb +36 -0
  17. data/app/controllers/iron_admin/concerns/scopeable.rb +84 -0
  18. data/app/controllers/iron_admin/concerns/searchable.rb +13 -16
  19. data/app/controllers/iron_admin/exports_controller.rb +15 -11
  20. data/app/controllers/iron_admin/imports_controller.rb +83 -0
  21. data/app/controllers/iron_admin/live_controller.rb +12 -0
  22. data/app/controllers/iron_admin/resources_controller.rb +118 -117
  23. data/app/controllers/iron_admin/search_controller.rb +5 -5
  24. data/app/controllers/iron_admin/tools_controller.rb +63 -4
  25. data/app/helpers/iron_admin/application_helper.rb +33 -14
  26. data/app/helpers/iron_admin/field_display_helper.rb +160 -1
  27. data/app/javascript/iron_admin/controllers/cp_nested_form_controller.js +113 -0
  28. data/app/javascript/iron_admin/controllers/filter_operator_controller.js +10 -0
  29. data/app/javascript/iron_admin/index.js +4 -0
  30. data/app/views/iron_admin/dashboard/index.html.haml +7 -2
  31. data/app/views/iron_admin/form/_nested_row.html.haml +70 -0
  32. data/app/views/iron_admin/imports/new.html.haml +27 -0
  33. data/app/views/iron_admin/imports/preview.html.haml +31 -0
  34. data/app/views/iron_admin/resources/_form.html.haml +81 -5
  35. data/app/views/iron_admin/resources/action_form.html.haml +62 -0
  36. data/app/views/iron_admin/resources/bulk_action_form.html.haml +62 -0
  37. data/app/views/iron_admin/resources/index.html.haml +60 -18
  38. data/app/views/iron_admin/tools/action_form.html.haml +57 -0
  39. data/app/views/iron_admin/tools/show.html.haml +20 -1
  40. data/config/importmap.rb +2 -0
  41. data/config/locales/en.yml +36 -0
  42. data/config/routes.rb +7 -0
  43. data/docs/components/filter-components.md +60 -0
  44. data/docs/getting-started/installation.md +113 -27
  45. data/docs/getting-started/quick-start.md +17 -1
  46. data/docs/guides/authentication.md +7 -6
  47. data/docs/guides/custom-adapters.md +628 -0
  48. data/docs/guides/extending.md +132 -3
  49. data/docs/guides/fields.md +1 -1
  50. data/docs/guides/resources.md +78 -2
  51. data/docs/guides/troubleshooting.md +68 -10
  52. data/docs/reference/routes.md +10 -0
  53. data/lib/generators/iron_admin/install/install_generator.rb +49 -4
  54. data/lib/generators/iron_admin/install/templates/dashboard.rb.tt +5 -1
  55. data/lib/generators/iron_admin/install_audit/install_audit_generator.rb +26 -10
  56. data/lib/generators/iron_admin/resource/resource_generator.rb +1 -1
  57. data/lib/generators/iron_admin/resource/templates/resource.rb.tt +6 -2
  58. data/lib/iron_admin/action_field.rb +56 -0
  59. data/lib/iron_admin/adapters/active_record.rb +237 -0
  60. data/lib/iron_admin/adapters/base.rb +340 -0
  61. data/lib/iron_admin/adapters/http/column_descriptor.rb +10 -0
  62. data/lib/iron_admin/adapters/http/configuration.rb +27 -0
  63. data/lib/iron_admin/adapters/http/connection.rb +117 -0
  64. data/lib/iron_admin/adapters/http/model_proxy.rb +75 -0
  65. data/lib/iron_admin/adapters/http/query.rb +111 -0
  66. data/lib/iron_admin/adapters/http/record.rb +83 -0
  67. data/lib/iron_admin/adapters/http/type_inferrer.rb +51 -0
  68. data/lib/iron_admin/adapters/http.rb +241 -0
  69. data/lib/iron_admin/adapters/mongoid/association_wrapper.rb +74 -0
  70. data/lib/iron_admin/adapters/mongoid/column_descriptor.rb +10 -0
  71. data/lib/iron_admin/adapters/mongoid.rb +284 -0
  72. data/lib/iron_admin/adapters/registry.rb +44 -0
  73. data/lib/iron_admin/concerns/importable.rb +81 -0
  74. data/lib/iron_admin/concerns/live_updatable.rb +38 -0
  75. data/lib/iron_admin/concerns/nestable.rb +69 -0
  76. data/lib/iron_admin/concerns/soft_deletable.rb +61 -0
  77. data/lib/iron_admin/configuration.rb +20 -0
  78. data/lib/iron_admin/dashboard.rb +15 -20
  79. data/lib/iron_admin/engine.rb +35 -22
  80. data/lib/iron_admin/errors.rb +29 -0
  81. data/lib/iron_admin/field_inferrer.rb +61 -22
  82. data/lib/iron_admin/filters/active_record_query_builder.rb +63 -0
  83. data/lib/iron_admin/filters/base_query_builder.rb +55 -0
  84. data/lib/iron_admin/filters/http_query_builder.rb +39 -0
  85. data/lib/iron_admin/filters/mongoid_query_builder.rb +58 -0
  86. data/lib/iron_admin/filters/query_builder.rb +12 -0
  87. data/lib/iron_admin/import/column_mapper.rb +42 -0
  88. data/lib/iron_admin/import/import_preview.rb +10 -0
  89. data/lib/iron_admin/import/import_result.rb +10 -0
  90. data/lib/iron_admin/import/importer.rb +231 -0
  91. data/lib/iron_admin/import/parser/csv.rb +34 -0
  92. data/lib/iron_admin/import/parser/json.rb +36 -0
  93. data/lib/iron_admin/import/type_caster.rb +47 -0
  94. data/lib/iron_admin/live/broadcaster.rb +43 -0
  95. data/lib/iron_admin/live/poll_cache.rb +28 -0
  96. data/lib/iron_admin/live.rb +29 -0
  97. data/lib/iron_admin/nested_association.rb +15 -0
  98. data/lib/iron_admin/nested_attributes_validator.rb +25 -0
  99. data/lib/iron_admin/policy.rb +72 -13
  100. data/lib/iron_admin/resource.rb +149 -91
  101. data/lib/iron_admin/resource_registry.rb +77 -4
  102. data/lib/iron_admin/tool.rb +50 -0
  103. data/lib/iron_admin/tool_action.rb +73 -0
  104. data/lib/iron_admin/tool_context.rb +49 -0
  105. data/lib/iron_admin/version.rb +1 -1
  106. data/lib/iron_admin.rb +46 -10
  107. data/vendor/bundle/ruby/3.2.0/cache/addressable-2.9.0.gem +0 -0
  108. data/vendor/bundle/ruby/3.2.0/cache/crack-1.0.1.gem +0 -0
  109. data/vendor/bundle/ruby/3.2.0/cache/faraday-2.14.1.gem +0 -0
  110. data/vendor/bundle/ruby/3.2.0/cache/faraday-net_http-3.4.2.gem +0 -0
  111. data/vendor/bundle/ruby/3.2.0/cache/hashdiff-1.2.1.gem +0 -0
  112. data/vendor/bundle/ruby/3.2.0/cache/net-http-0.9.1.gem +0 -0
  113. data/vendor/bundle/ruby/3.2.0/cache/public_suffix-7.0.5.gem +0 -0
  114. data/vendor/bundle/ruby/3.2.0/cache/rexml-3.4.4.gem +0 -0
  115. data/vendor/bundle/ruby/3.2.0/cache/webmock-3.26.2.gem +0 -0
  116. data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/bigdecimal-4.0.1/bigdecimal.so +0 -0
  117. data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/bigdecimal-4.0.1/gem_make.out +6 -6
  118. data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/bigdecimal-4.0.1/mkmf.log +25 -25
  119. data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/date-3.5.1/date_core.so +0 -0
  120. data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/date-3.5.1/gem_make.out +6 -6
  121. data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/date-3.5.1/mkmf.log +4 -4
  122. data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/erb-6.0.1/erb/escape.so +0 -0
  123. data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/erb-6.0.1/gem_make.out +6 -6
  124. data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/erb-6.0.1/mkmf.log +2 -2
  125. data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/io-console-0.8.2/gem_make.out +6 -6
  126. data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/io-console-0.8.2/io/console.so +0 -0
  127. data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/io-console-0.8.2/mkmf.log +22 -22
  128. data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/json-2.18.1/gem_make.out +6 -6
  129. data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/json-2.18.1/json/ext/generator.so +0 -0
  130. data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/json-2.18.1/json/ext/parser.so +0 -0
  131. data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/json-2.18.1/mkmf.log +9 -9
  132. data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/nio4r-2.7.5/gem_make.out +6 -6
  133. data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/nio4r-2.7.5/mkmf.log +12 -12
  134. data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/nio4r-2.7.5/nio4r_ext.so +0 -0
  135. data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/prism-1.9.0/gem_make.out +6 -6
  136. data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/prism-1.9.0/mkmf.log +6 -6
  137. data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/prism-1.9.0/prism/prism.so +0 -0
  138. data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/psych-5.3.1/gem_make.out +6 -6
  139. data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/psych-5.3.1/mkmf.log +7 -7
  140. data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/psych-5.3.1/psych.so +0 -0
  141. data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/racc-1.8.1/gem_make.out +6 -6
  142. data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/racc-1.8.1/racc/cparse.so +0 -0
  143. data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/redcarpet-3.6.1/gem_make.out +6 -6
  144. data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/redcarpet-3.6.1/redcarpet.so +0 -0
  145. data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/stringio-3.2.0/gem_make.out +6 -6
  146. data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/stringio-3.2.0/mkmf.log +2 -2
  147. data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/stringio-3.2.0/stringio.so +0 -0
  148. data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/websocket-driver-0.8.0/gem_make.out +6 -6
  149. data/vendor/bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/websocket-driver-0.8.0/websocket_mask.so +0 -0
  150. data/vendor/bundle/ruby/3.2.0/gems/addressable-2.9.0/CHANGELOG.md +326 -0
  151. data/vendor/bundle/ruby/3.2.0/gems/addressable-2.9.0/LICENSE.txt +202 -0
  152. data/vendor/bundle/ruby/3.2.0/gems/addressable-2.9.0/README.md +121 -0
  153. data/vendor/bundle/ruby/3.2.0/gems/addressable-2.9.0/lib/addressable/idna/native.rb +66 -0
  154. data/vendor/bundle/ruby/3.2.0/gems/addressable-2.9.0/lib/addressable/idna/pure.rb +4710 -0
  155. data/vendor/bundle/ruby/3.2.0/gems/addressable-2.9.0/lib/addressable/idna.rb +26 -0
  156. data/vendor/bundle/ruby/3.2.0/gems/addressable-2.9.0/lib/addressable/template.rb +1040 -0
  157. data/vendor/bundle/ruby/3.2.0/gems/addressable-2.9.0/lib/addressable/uri.rb +2602 -0
  158. data/vendor/bundle/ruby/3.2.0/gems/addressable-2.9.0/lib/addressable/version.rb +31 -0
  159. data/vendor/bundle/ruby/3.2.0/gems/addressable-2.9.0/lib/addressable.rb +4 -0
  160. data/vendor/bundle/ruby/3.2.0/gems/bigdecimal-4.0.1/ext/bigdecimal/Makefile +3 -3
  161. data/vendor/bundle/ruby/3.2.0/gems/bigdecimal-4.0.1/lib/bigdecimal.so +0 -0
  162. data/vendor/bundle/ruby/3.2.0/gems/crack-1.0.1/History +58 -0
  163. data/vendor/bundle/ruby/3.2.0/gems/crack-1.0.1/LICENSE +20 -0
  164. data/vendor/bundle/ruby/3.2.0/gems/crack-1.0.1/README.md +43 -0
  165. data/vendor/bundle/ruby/3.2.0/gems/crack-1.0.1/lib/crack/json.rb +113 -0
  166. data/vendor/bundle/ruby/3.2.0/gems/crack-1.0.1/lib/crack/util.rb +17 -0
  167. data/vendor/bundle/ruby/3.2.0/gems/crack-1.0.1/lib/crack/version.rb +3 -0
  168. data/vendor/bundle/ruby/3.2.0/gems/crack-1.0.1/lib/crack/xml.rb +240 -0
  169. data/vendor/bundle/ruby/3.2.0/gems/crack-1.0.1/lib/crack.rb +8 -0
  170. data/vendor/bundle/ruby/3.2.0/gems/date-3.5.1/ext/date/Makefile +3 -3
  171. data/vendor/bundle/ruby/3.2.0/gems/date-3.5.1/lib/date_core.so +0 -0
  172. data/vendor/bundle/ruby/3.2.0/gems/erb-6.0.1/ext/erb/escape/Makefile +3 -3
  173. data/vendor/bundle/ruby/3.2.0/gems/erb-6.0.1/lib/erb/escape.so +0 -0
  174. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/CHANGELOG.md +574 -0
  175. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/LICENSE.md +20 -0
  176. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/README.md +67 -0
  177. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/Rakefile +12 -0
  178. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/examples/client_spec.rb +119 -0
  179. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/examples/client_test.rb +144 -0
  180. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday/adapter/test.rb +311 -0
  181. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday/adapter.rb +101 -0
  182. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday/adapter_registry.rb +30 -0
  183. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday/connection.rb +565 -0
  184. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday/encoders/flat_params_encoder.rb +105 -0
  185. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday/encoders/nested_params_encoder.rb +183 -0
  186. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday/error.rb +202 -0
  187. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday/logging/formatter.rb +118 -0
  188. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday/methods.rb +6 -0
  189. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday/middleware.rb +72 -0
  190. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday/middleware_registry.rb +83 -0
  191. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday/options/connection_options.rb +23 -0
  192. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday/options/env.rb +204 -0
  193. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday/options/proxy_options.rb +38 -0
  194. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday/options/request_options.rb +23 -0
  195. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday/options/ssl_options.rb +76 -0
  196. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday/options.rb +219 -0
  197. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday/parameters.rb +5 -0
  198. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday/rack_builder.rb +248 -0
  199. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday/request/authorization.rb +54 -0
  200. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday/request/instrumentation.rb +58 -0
  201. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday/request/json.rb +70 -0
  202. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday/request/url_encoded.rb +60 -0
  203. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday/request.rb +139 -0
  204. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday/response/json.rb +74 -0
  205. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday/response/logger.rb +39 -0
  206. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday/response/raise_error.rb +83 -0
  207. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday/response.rb +95 -0
  208. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday/utils/headers.rb +150 -0
  209. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday/utils/params_hash.rb +61 -0
  210. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday/utils.rb +121 -0
  211. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday/version.rb +5 -0
  212. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/lib/faraday.rb +158 -0
  213. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/external_adapters/faraday_specs_setup.rb +14 -0
  214. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/faraday/adapter/test_spec.rb +442 -0
  215. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/faraday/adapter_registry_spec.rb +28 -0
  216. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/faraday/adapter_spec.rb +55 -0
  217. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/faraday/connection_spec.rb +841 -0
  218. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/faraday/error_spec.rb +175 -0
  219. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/faraday/middleware_registry_spec.rb +31 -0
  220. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/faraday/middleware_spec.rb +213 -0
  221. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/faraday/options/env_spec.rb +76 -0
  222. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/faraday/options/options_spec.rb +297 -0
  223. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/faraday/options/proxy_options_spec.rb +79 -0
  224. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/faraday/options/request_options_spec.rb +19 -0
  225. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/faraday/params_encoders/flat_spec.rb +42 -0
  226. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/faraday/params_encoders/nested_spec.rb +151 -0
  227. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/faraday/rack_builder_spec.rb +317 -0
  228. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/faraday/request/authorization_spec.rb +118 -0
  229. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/faraday/request/instrumentation_spec.rb +74 -0
  230. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/faraday/request/json_spec.rb +199 -0
  231. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/faraday/request/url_encoded_spec.rb +93 -0
  232. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/faraday/request_spec.rb +110 -0
  233. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/faraday/response/json_spec.rb +206 -0
  234. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/faraday/response/logger_spec.rb +299 -0
  235. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/faraday/response/raise_error_spec.rb +286 -0
  236. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/faraday/response_spec.rb +84 -0
  237. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/faraday/utils/headers_spec.rb +109 -0
  238. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/faraday/utils_spec.rb +120 -0
  239. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/faraday_spec.rb +43 -0
  240. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/spec_helper.rb +133 -0
  241. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/support/disabling_stub.rb +14 -0
  242. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/support/fake_safe_buffer.rb +15 -0
  243. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/support/faraday_middleware_subclasses.rb +18 -0
  244. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/support/helper_methods.rb +96 -0
  245. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/support/shared_examples/adapter.rb +105 -0
  246. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/support/shared_examples/params_encoder.rb +18 -0
  247. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/support/shared_examples/request_method.rb +263 -0
  248. data/vendor/bundle/ruby/3.2.0/gems/faraday-2.14.1/spec/support/streaming_response_checker.rb +35 -0
  249. data/vendor/bundle/ruby/3.2.0/gems/faraday-net_http-3.4.2/LICENSE.md +21 -0
  250. data/vendor/bundle/ruby/3.2.0/gems/faraday-net_http-3.4.2/README.md +57 -0
  251. data/vendor/bundle/ruby/3.2.0/gems/faraday-net_http-3.4.2/lib/faraday/adapter/net_http.rb +206 -0
  252. data/vendor/bundle/ruby/3.2.0/gems/faraday-net_http-3.4.2/lib/faraday/net_http/version.rb +7 -0
  253. data/vendor/bundle/ruby/3.2.0/gems/faraday-net_http-3.4.2/lib/faraday/net_http.rb +10 -0
  254. data/vendor/bundle/ruby/3.2.0/gems/hashdiff-1.2.1/Gemfile +8 -0
  255. data/vendor/bundle/ruby/3.2.0/gems/hashdiff-1.2.1/LICENSE +19 -0
  256. data/vendor/bundle/ruby/3.2.0/gems/hashdiff-1.2.1/README.md +323 -0
  257. data/vendor/bundle/ruby/3.2.0/gems/hashdiff-1.2.1/Rakefile +18 -0
  258. data/vendor/bundle/ruby/3.2.0/gems/hashdiff-1.2.1/changelog.md +127 -0
  259. data/vendor/bundle/ruby/3.2.0/gems/hashdiff-1.2.1/hashdiff.gemspec +39 -0
  260. data/vendor/bundle/ruby/3.2.0/gems/hashdiff-1.2.1/lib/hashdiff/compare_hashes.rb +101 -0
  261. data/vendor/bundle/ruby/3.2.0/gems/hashdiff-1.2.1/lib/hashdiff/diff.rb +185 -0
  262. data/vendor/bundle/ruby/3.2.0/gems/hashdiff-1.2.1/lib/hashdiff/lcs.rb +66 -0
  263. data/vendor/bundle/ruby/3.2.0/gems/hashdiff-1.2.1/lib/hashdiff/lcs_compare_arrays.rb +32 -0
  264. data/vendor/bundle/ruby/3.2.0/gems/hashdiff-1.2.1/lib/hashdiff/linear_compare_array.rb +159 -0
  265. data/vendor/bundle/ruby/3.2.0/gems/hashdiff-1.2.1/lib/hashdiff/patch.rb +88 -0
  266. data/vendor/bundle/ruby/3.2.0/gems/hashdiff-1.2.1/lib/hashdiff/util.rb +155 -0
  267. data/vendor/bundle/ruby/3.2.0/gems/hashdiff-1.2.1/lib/hashdiff/version.rb +5 -0
  268. data/vendor/bundle/ruby/3.2.0/gems/hashdiff-1.2.1/lib/hashdiff.rb +10 -0
  269. data/vendor/bundle/ruby/3.2.0/gems/io-console-0.8.2/ext/io/console/Makefile +3 -3
  270. data/vendor/bundle/ruby/3.2.0/gems/io-console-0.8.2/lib/io/console.so +0 -0
  271. data/vendor/bundle/ruby/3.2.0/gems/json-2.18.1/ext/json/ext/generator/Makefile +3 -3
  272. data/vendor/bundle/ruby/3.2.0/gems/json-2.18.1/ext/json/ext/parser/Makefile +3 -3
  273. data/vendor/bundle/ruby/3.2.0/gems/json-2.18.1/lib/json/ext/generator.so +0 -0
  274. data/vendor/bundle/ruby/3.2.0/gems/json-2.18.1/lib/json/ext/parser.so +0 -0
  275. data/vendor/bundle/ruby/3.2.0/gems/net-http-0.9.1/BSDL +22 -0
  276. data/vendor/bundle/ruby/3.2.0/gems/net-http-0.9.1/COPYING +56 -0
  277. data/vendor/bundle/ruby/3.2.0/gems/net-http-0.9.1/README.md +93 -0
  278. data/vendor/bundle/ruby/3.2.0/gems/net-http-0.9.1/doc/net-http/examples.rdoc +31 -0
  279. data/vendor/bundle/ruby/3.2.0/gems/net-http-0.9.1/doc/net-http/included_getters.rdoc +3 -0
  280. data/vendor/bundle/ruby/3.2.0/gems/net-http-0.9.1/lib/net/http/exceptions.rb +35 -0
  281. data/vendor/bundle/ruby/3.2.0/gems/net-http-0.9.1/lib/net/http/generic_request.rb +429 -0
  282. data/vendor/bundle/ruby/3.2.0/gems/net-http-0.9.1/lib/net/http/header.rb +985 -0
  283. data/vendor/bundle/ruby/3.2.0/gems/net-http-0.9.1/lib/net/http/proxy_delta.rb +17 -0
  284. data/vendor/bundle/ruby/3.2.0/gems/net-http-0.9.1/lib/net/http/request.rb +88 -0
  285. data/vendor/bundle/ruby/3.2.0/gems/net-http-0.9.1/lib/net/http/requests.rb +444 -0
  286. data/vendor/bundle/ruby/3.2.0/gems/net-http-0.9.1/lib/net/http/response.rb +739 -0
  287. data/vendor/bundle/ruby/3.2.0/gems/net-http-0.9.1/lib/net/http/responses.rb +1242 -0
  288. data/vendor/bundle/ruby/3.2.0/gems/net-http-0.9.1/lib/net/http/status.rb +84 -0
  289. data/vendor/bundle/ruby/3.2.0/gems/net-http-0.9.1/lib/net/http.rb +2608 -0
  290. data/vendor/bundle/ruby/3.2.0/gems/net-http-0.9.1/lib/net/https.rb +23 -0
  291. data/vendor/bundle/ruby/3.2.0/gems/nio4r-2.7.5/ext/nio4r/Makefile +3 -3
  292. data/vendor/bundle/ruby/3.2.0/gems/nio4r-2.7.5/lib/nio4r_ext.so +0 -0
  293. data/vendor/bundle/ruby/3.2.0/gems/prism-1.9.0/ext/prism/Makefile +3 -3
  294. data/vendor/bundle/ruby/3.2.0/gems/prism-1.9.0/lib/prism/prism.so +0 -0
  295. data/vendor/bundle/ruby/3.2.0/gems/psych-5.3.1/ext/psych/Makefile +3 -3
  296. data/vendor/bundle/ruby/3.2.0/gems/psych-5.3.1/lib/psych.so +0 -0
  297. data/vendor/bundle/ruby/3.2.0/gems/public_suffix-7.0.5/CHANGELOG.md +649 -0
  298. data/vendor/bundle/ruby/3.2.0/gems/public_suffix-7.0.5/Gemfile +16 -0
  299. data/vendor/bundle/ruby/3.2.0/gems/public_suffix-7.0.5/LICENSE.txt +22 -0
  300. data/vendor/bundle/ruby/3.2.0/gems/public_suffix-7.0.5/README.md +231 -0
  301. data/vendor/bundle/ruby/3.2.0/gems/public_suffix-7.0.5/SECURITY.md +24 -0
  302. data/vendor/bundle/ruby/3.2.0/gems/public_suffix-7.0.5/data/list.txt +16298 -0
  303. data/vendor/bundle/ruby/3.2.0/gems/public_suffix-7.0.5/lib/public_suffix/domain.rb +235 -0
  304. data/vendor/bundle/ruby/3.2.0/gems/public_suffix-7.0.5/lib/public_suffix/errors.rb +41 -0
  305. data/vendor/bundle/ruby/3.2.0/gems/public_suffix-7.0.5/lib/public_suffix/list.rb +247 -0
  306. data/vendor/bundle/ruby/3.2.0/gems/public_suffix-7.0.5/lib/public_suffix/rule.rb +350 -0
  307. data/vendor/bundle/ruby/3.2.0/gems/public_suffix-7.0.5/lib/public_suffix/version.rb +14 -0
  308. data/vendor/bundle/ruby/3.2.0/gems/public_suffix-7.0.5/lib/public_suffix.rb +177 -0
  309. data/vendor/bundle/ruby/3.2.0/gems/racc-1.8.1/ext/racc/cparse/Makefile +3 -3
  310. data/vendor/bundle/ruby/3.2.0/gems/racc-1.8.1/lib/racc/cparse.so +0 -0
  311. data/vendor/bundle/ruby/3.2.0/gems/redcarpet-3.6.1/ext/redcarpet/Makefile +3 -3
  312. data/vendor/bundle/ruby/3.2.0/gems/redcarpet-3.6.1/lib/redcarpet.so +0 -0
  313. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/LICENSE.txt +22 -0
  314. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/NEWS.md +843 -0
  315. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/README.md +57 -0
  316. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/doc/rexml/context.rdoc +143 -0
  317. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/doc/rexml/tasks/rdoc/child.rdoc +87 -0
  318. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/doc/rexml/tasks/rdoc/document.rdoc +276 -0
  319. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/doc/rexml/tasks/rdoc/element.rdoc +602 -0
  320. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/doc/rexml/tasks/rdoc/node.rdoc +97 -0
  321. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/doc/rexml/tasks/rdoc/parent.rdoc +267 -0
  322. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/doc/rexml/tasks/tocs/child_toc.rdoc +12 -0
  323. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/doc/rexml/tasks/tocs/document_toc.rdoc +30 -0
  324. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/doc/rexml/tasks/tocs/element_toc.rdoc +55 -0
  325. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/doc/rexml/tasks/tocs/master_toc.rdoc +135 -0
  326. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/doc/rexml/tasks/tocs/node_toc.rdoc +16 -0
  327. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/doc/rexml/tasks/tocs/parent_toc.rdoc +25 -0
  328. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/doc/rexml/tutorial.rdoc +1358 -0
  329. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/attlistdecl.rb +63 -0
  330. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/attribute.rb +210 -0
  331. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/cdata.rb +68 -0
  332. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/child.rb +96 -0
  333. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/comment.rb +80 -0
  334. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/doctype.rb +306 -0
  335. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/document.rb +471 -0
  336. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/dtd/attlistdecl.rb +11 -0
  337. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/dtd/dtd.rb +47 -0
  338. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/dtd/elementdecl.rb +18 -0
  339. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/dtd/entitydecl.rb +57 -0
  340. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/dtd/notationdecl.rb +40 -0
  341. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/element.rb +2578 -0
  342. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/encoding.rb +48 -0
  343. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/entity.rb +142 -0
  344. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/formatters/default.rb +116 -0
  345. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/formatters/pretty.rb +142 -0
  346. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/formatters/transitive.rb +58 -0
  347. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/functions.rb +446 -0
  348. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/instruction.rb +79 -0
  349. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/light/node.rb +188 -0
  350. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/namespace.rb +63 -0
  351. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/node.rb +80 -0
  352. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/output.rb +30 -0
  353. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/parent.rb +166 -0
  354. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/parseexception.rb +53 -0
  355. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/parsers/baseparser.rb +949 -0
  356. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/parsers/lightparser.rb +59 -0
  357. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/parsers/pullparser.rb +213 -0
  358. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/parsers/sax2parser.rb +270 -0
  359. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/parsers/streamparser.rb +67 -0
  360. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/parsers/treeparser.rb +89 -0
  361. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/parsers/ultralightparser.rb +57 -0
  362. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/parsers/xpathparser.rb +739 -0
  363. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/quickpath.rb +267 -0
  364. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/rexml.rb +39 -0
  365. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/sax2listener.rb +98 -0
  366. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/security.rb +28 -0
  367. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/source.rb +388 -0
  368. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/streamlistener.rb +93 -0
  369. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/text.rb +420 -0
  370. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/undefinednamespaceexception.rb +9 -0
  371. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/validation/relaxng.rb +540 -0
  372. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/validation/validation.rb +144 -0
  373. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/validation/validationexception.rb +10 -0
  374. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/xmldecl.rb +130 -0
  375. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/xmltokens.rb +85 -0
  376. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/xpath.rb +70 -0
  377. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml/xpath_parser.rb +980 -0
  378. data/vendor/bundle/ruby/3.2.0/gems/rexml-3.4.4/lib/rexml.rb +3 -0
  379. data/vendor/bundle/ruby/3.2.0/gems/stringio-3.2.0/ext/stringio/Makefile +3 -3
  380. data/vendor/bundle/ruby/3.2.0/gems/stringio-3.2.0/lib/stringio.so +0 -0
  381. data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/CHANGELOG.md +2148 -0
  382. data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/LICENSE +20 -0
  383. data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/README.md +1229 -0
  384. data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/api.rb +111 -0
  385. data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/assertion_failure.rb +13 -0
  386. data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/callback_registry.rb +37 -0
  387. data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/config.rb +20 -0
  388. data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/cucumber.rb +12 -0
  389. data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/deprecation.rb +11 -0
  390. data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/errors.rb +19 -0
  391. data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/http_lib_adapters/async_http_client_adapter.rb +228 -0
  392. data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/http_lib_adapters/curb_adapter.rb +354 -0
  393. data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/http_lib_adapters/em_http_request_adapter.rb +239 -0
  394. data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/http_lib_adapters/excon_adapter.rb +167 -0
  395. data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/http_lib_adapters/http_lib_adapter.rb +9 -0
  396. data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/http_lib_adapters/http_lib_adapter_registry.rb +21 -0
  397. data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/http_lib_adapters/http_rb/client.rb +17 -0
  398. data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/http_lib_adapters/http_rb/request.rb +28 -0
  399. data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/http_lib_adapters/http_rb/response.rb +95 -0
  400. data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/http_lib_adapters/http_rb/streamer.rb +44 -0
  401. data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/http_lib_adapters/http_rb/webmock.rb +77 -0
  402. data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/http_lib_adapters/http_rb_adapter.rb +39 -0
  403. data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/http_lib_adapters/httpclient_adapter.rb +260 -0
  404. data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/http_lib_adapters/manticore_adapter.rb +147 -0
  405. data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/http_lib_adapters/net_http.rb +310 -0
  406. data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/http_lib_adapters/net_http_response.rb +36 -0
  407. data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/http_lib_adapters/patron_adapter.rb +132 -0
  408. data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/http_lib_adapters/typhoeus_hydra_adapter.rb +190 -0
  409. data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/matchers/any_arg_matcher.rb +15 -0
  410. data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/matchers/hash_argument_matcher.rb +23 -0
  411. data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/matchers/hash_excluding_matcher.rb +17 -0
  412. data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/matchers/hash_including_matcher.rb +19 -0
  413. data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/minitest.rb +43 -0
  414. data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/rack_response.rb +73 -0
  415. data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/request_body_diff.rb +66 -0
  416. data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/request_execution_verifier.rb +79 -0
  417. data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/request_pattern.rb +428 -0
  418. data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/request_registry.rb +37 -0
  419. data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/request_signature.rb +56 -0
  420. data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/request_signature_snippet.rb +63 -0
  421. data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/request_stub.rb +134 -0
  422. data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/response.rb +161 -0
  423. data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/responses_sequence.rb +42 -0
  424. data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/rspec/matchers/request_pattern_matcher.rb +80 -0
  425. data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/rspec/matchers/webmock_matcher.rb +69 -0
  426. data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/rspec/matchers.rb +29 -0
  427. data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/rspec.rb +44 -0
  428. data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/stub_registry.rb +84 -0
  429. data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/stub_request_snippet.rb +40 -0
  430. data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/test_unit.rb +22 -0
  431. data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/util/hash_counter.rb +45 -0
  432. data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/util/hash_keys_stringifier.rb +27 -0
  433. data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/util/hash_validator.rb +19 -0
  434. data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/util/headers.rb +77 -0
  435. data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/util/parsers/json.rb +72 -0
  436. data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/util/parsers/parse_error.rb +7 -0
  437. data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/util/parsers/xml.rb +16 -0
  438. data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/util/query_mapper.rb +283 -0
  439. data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/util/uri.rb +113 -0
  440. data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/util/values_stringifier.rb +22 -0
  441. data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/util/version_checker.rb +113 -0
  442. data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/version.rb +5 -0
  443. data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock/webmock.rb +175 -0
  444. data/vendor/bundle/ruby/3.2.0/gems/webmock-3.26.2/lib/webmock.rb +61 -0
  445. data/vendor/bundle/ruby/3.2.0/gems/websocket-driver-0.8.0/ext/websocket-driver/Makefile +3 -3
  446. data/vendor/bundle/ruby/3.2.0/gems/websocket-driver-0.8.0/lib/websocket_mask.so +0 -0
  447. data/vendor/bundle/ruby/3.2.0/specifications/addressable-2.9.0.gemspec +29 -0
  448. data/vendor/bundle/ruby/3.2.0/specifications/crack-1.0.1.gemspec +27 -0
  449. data/vendor/bundle/ruby/3.2.0/specifications/faraday-2.14.1.gemspec +0 -0
  450. data/vendor/bundle/ruby/3.2.0/specifications/faraday-net_http-3.4.2.gemspec +26 -0
  451. data/vendor/bundle/ruby/3.2.0/specifications/hashdiff-1.2.1.gemspec +30 -0
  452. data/vendor/bundle/ruby/3.2.0/specifications/net-http-0.9.1.gemspec +27 -0
  453. data/vendor/bundle/ruby/3.2.0/specifications/public_suffix-7.0.5.gemspec +24 -0
  454. data/vendor/bundle/ruby/3.2.0/specifications/rexml-3.4.4.gemspec +25 -0
  455. data/vendor/bundle/ruby/3.2.0/specifications/webmock-3.26.2.gemspec +44 -0
  456. metadata +377 -2
@@ -66,11 +66,12 @@ module IronAdmin
66
66
  # - :number - Plain number with thousands separators
67
67
  # - :currency - Currency format (uses Rails number_to_currency)
68
68
  # - :percentage - Percentage format
69
+ # @param icon [String, nil] Optional Heroicon name for visual context (e.g., "users", "currency-dollar")
69
70
  # @yield Block that computes and returns the metric value
70
71
  # @yieldreturn [Numeric] The metric value
71
72
  #
72
- # @example User count metric
73
- # metric :total_users, format: :number do
73
+ # @example User count metric with icon
74
+ # metric :total_users, format: :number, icon: "users" do
74
75
  # User.count
75
76
  # end
76
77
  #
@@ -79,14 +80,9 @@ module IronAdmin
79
80
  # Order.where(status: "completed").sum(:total)
80
81
  # end
81
82
  #
82
- # @example Conversion rate metric
83
- # metric :conversion_rate, format: :percentage do
84
- # (Order.count.to_f / Visit.count * 100).round(1)
85
- # end
86
- #
87
83
  # @return [void]
88
- def metric(name, format: :number, &block)
89
- self.defined_metrics = defined_metrics + [{ name: name, format: format, block: block }]
84
+ def metric(name, format: :number, icon: nil, live: false, &block)
85
+ self.defined_metrics = defined_metrics + [{ name: name, format: format, icon: icon, live: live, block: block }]
90
86
  end
91
87
 
92
88
  # Defines a chart for the dashboard.
@@ -94,7 +90,7 @@ module IronAdmin
94
90
  # Charts display time-series or categorical data visually.
95
91
  # The block should return data in a format suitable for the chart type.
96
92
  #
97
- # @param name [Symbol] The chart identifier (used as the chart title)
93
+ # @param name [Symbol] The chart identifier
98
94
  # @param type [Symbol] The chart type
99
95
  # - :line - Line chart for trends over time
100
96
  # - :bar - Bar chart for comparisons
@@ -102,12 +98,14 @@ module IronAdmin
102
98
  # - :doughnut - Doughnut chart for proportions
103
99
  # @param colors [Array<String>, nil] Optional per-chart color palette (CSS color values).
104
100
  # Overrides the global theme chart_colors for this chart.
101
+ # @param label [String, nil] Custom display title for the chart.
102
+ # Defaults to `name.to_s.humanize` when not provided.
105
103
  # @yield Block that computes and returns the chart data
106
104
  # @yieldreturn [Hash, Array] Data for the chart (format depends on type)
107
105
  #
108
- # @example Line chart of signups over time
109
- # chart :signups_by_month, type: :line do
110
- # User.group_by_month(:created_at).count
106
+ # @example Chart with custom label
107
+ # chart :projects_by_status, type: :bar, label: "Projects by Status" do
108
+ # Project.group(:status).count
111
109
  # end
112
110
  #
113
111
  # @example Bar chart with custom colors
@@ -115,14 +113,11 @@ module IronAdmin
115
113
  # Order.group(:status).count
116
114
  # end
117
115
  #
118
- # @example Pie chart of users by role
119
- # chart :users_by_role, type: :pie do
120
- # User.group(:role).count
121
- # end
122
- #
123
116
  # @return [void]
124
- def chart(name, type: :line, colors: nil, &block)
125
- self.defined_charts = defined_charts + [{ name: name, type: type, colors: colors, block: block }]
117
+ def chart(name, type: :line, colors: nil, label: nil, live: false, &block)
118
+ self.defined_charts = defined_charts + [
119
+ { name: name, type: type, colors: colors, label: label, live: live, block: block },
120
+ ]
126
121
  end
127
122
 
128
123
  # Displays a list of recent records from a resource.
@@ -24,7 +24,15 @@ module IronAdmin
24
24
 
25
25
  initializer "iron_admin.assets" do |app|
26
26
  if app.config.respond_to?(:assets) && app.config.assets
27
- app.config.assets.precompile += %w[iron_admin_manifest]
27
+ # `app/assets/config/iron_admin_manifest.js` is a Sprockets manifest
28
+ # that link_trees the engine's JavaScript bundle. Adding it to
29
+ # `precompile` recursively pulls in `app/javascript/iron_admin/**/*.js`,
30
+ # which is what the layout references via `javascript_importmap_tags`
31
+ # (importmap pin: `iron_admin/index.js`). Without this entry, hosts on
32
+ # sprockets-rails (Rails 7.1 default) get
33
+ # `Asset 'iron_admin/index.js' was not declared to be precompiled`
34
+ # on every resource page.
35
+ app.config.assets.precompile += %w[iron_admin_manifest.js]
28
36
  app.config.assets.paths << root.join("vendor/assets/javascripts")
29
37
  app.config.assets.paths << root.join("app/javascript")
30
38
  end
@@ -38,31 +46,36 @@ module IronAdmin
38
46
  config.i18n.load_path += Dir[root.join("config", "locales", "**", "*.yml")]
39
47
  end
40
48
 
41
- initializer "iron_admin.tailwindcss" do
42
- if defined?(Tailwindcss)
43
- engine_css = root.join("app/assets/tailwind/iron_admin/engine.css")
44
-
45
- Rails.application.config.after_initialize do
46
- if defined?(Rake) && Rake::Task.task_defined?("tailwindcss:engines")
47
- Rake::Task["tailwindcss:engines"].enhance do
48
- tailwind_dir = Rails.root.join("app/assets/tailwind")
49
- bridge_file = tailwind_dir.join("iron_admin.css")
50
-
51
- if engine_css.exist? && tailwind_dir.exist?
52
- File.write(bridge_file, <<~CSS)
53
- /* DO NOT MODIFY - auto-generated by iron_admin */
54
- @import "#{engine_css}";
55
- CSS
56
- end
57
- end
58
- end
59
- end
49
+ # Expose `heroicon` directly on every ViewComponent instance.
50
+ # ViewComponent does not auto-include host-app `ApplicationHelper`
51
+ # methods on component templates, so calling `heroicon "users"` from
52
+ # a HAML template would otherwise raise `NoMethodError` (depending on
53
+ # ViewComponent version). Including the helper module on
54
+ # `ViewComponent::Base` makes `heroicon` available to every component
55
+ # template and Ruby method without requiring `helpers.heroicon`.
56
+ initializer "iron_admin.view_component_heroicon" do
57
+ ActiveSupport.on_load(:view_component) do
58
+ include Heroicon::ApplicationHelper
60
59
  end
61
60
  end
62
61
 
63
- config.after_initialize do
62
+ initializer "iron_admin.autoload", before: :set_autoload_paths do
63
+ resource_path = Rails.root.join("app/iron_admin")
64
+ Rails.autoloaders.main.push_dir(resource_path, namespace: IronAdmin) if resource_path.exist?
65
+ end
66
+
67
+ config.to_prepare do
64
68
  resource_path = Rails.root.join("app/iron_admin")
65
- Rails.autoloaders.main.eager_load_dir(resource_path.to_s) if resource_path.exist?
69
+ if resource_path.exist?
70
+ IronAdmin::ResourceRegistry.reset!
71
+ Rails.autoloaders.main.eager_load_dir(resource_path)
72
+ # Eager-loading runs each resource's `inherited` hook, which adds
73
+ # the class to the registry. Now that every class body has fully
74
+ # evaluated (and thus `self.adapter_class = :mongoid` etc. have
75
+ # taken effect), call `finalize!` to run the model introspection
76
+ # steps (soft-delete features, etc.) with the correct adapter.
77
+ IronAdmin::ResourceRegistry.finalize!
78
+ end
66
79
  end
67
80
  end
68
81
  end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module IronAdmin
4
+ # Base error class for all IronAdmin errors.
5
+ class Error < StandardError; end
6
+
7
+ # Raised when a record cannot be found by ID.
8
+ # Adapter-agnostic replacement for ActiveRecord::RecordNotFound.
9
+ class RecordNotFound < Error; end
10
+
11
+ # Raised inside a transaction block to trigger a rollback.
12
+ # Adapter-agnostic replacement for ActiveRecord::Rollback.
13
+ class Rollback < Error; end
14
+
15
+ # Raised when an adapter encounters an operational error
16
+ # (network failure, invalid response, etc.).
17
+ class AdapterError < Error; end
18
+
19
+ # Exception classes that mean the database is missing or unreachable
20
+ # at boot time. Resolved lazily so the gem stays usable on
21
+ # `--skip-active-record` hosts where `ActiveRecord` isn't loaded.
22
+ #
23
+ # @return [Array<Class>] Rescue classes for boot-time DB failures
24
+ def self.db_unreachable_exceptions
25
+ return [] unless defined?(ActiveRecord)
26
+
27
+ [ActiveRecord::NoDatabaseError, ActiveRecord::StatementInvalid, ActiveRecord::ConnectionNotEstablished]
28
+ end
29
+ end
@@ -44,33 +44,42 @@ module IronAdmin
44
44
  jsonb: :json,
45
45
  }.freeze
46
46
 
47
- # Infers fields for a model.
47
+ # Infers fields for a model or adapter.
48
48
  #
49
- # @param model [Class] An ActiveRecord model class
49
+ # @param model_or_adapter [Class, IronAdmin::Adapters::Base] An ActiveRecord model class or adapter instance
50
50
  # @return [Array<IronAdmin::Field>] Inferred field objects
51
51
  #
52
- # @example
52
+ # @example With a model (backward compatible)
53
53
  # fields = IronAdmin::FieldInferrer.call(User)
54
- def self.call(model)
55
- new(model).call
54
+ #
55
+ # @example With an adapter (preferred)
56
+ # fields = IronAdmin::FieldInferrer.call(resource.adapter)
57
+ def self.call(model_or_adapter)
58
+ adapter = if model_or_adapter.is_a?(IronAdmin::Adapters::Base)
59
+ model_or_adapter
60
+ else
61
+ IronAdmin::Adapters::ActiveRecord.new(model_or_adapter)
62
+ end
63
+ new(adapter).call
56
64
  end
57
65
 
58
- # Creates a new FieldInferrer for the given model.
66
+ # Creates a new FieldInferrer for the given adapter.
59
67
  #
60
- # @param model [Class] An ActiveRecord model class
61
- def initialize(model)
62
- @model = model
63
- @polymorphic_map = model.reflect_on_all_associations(:belongs_to)
68
+ # @param adapter [IronAdmin::Adapters::Base] An adapter instance
69
+ def initialize(adapter)
70
+ @adapter = adapter
71
+ @polymorphic_map = adapter.associations(:belongs_to)
64
72
  .select(&:polymorphic?)
65
73
  .index_by { |a| a.name.to_s }
66
74
  @polymorphic_columns = @polymorphic_map.values
67
75
  .flat_map { |a| [a.foreign_type, a.foreign_key.to_s] }.to_set
68
- @belongs_to_map = model.reflect_on_all_associations(:belongs_to)
76
+ @belongs_to_map = adapter.associations(:belongs_to)
69
77
  .reject(&:polymorphic?)
70
78
  .index_by { |a| a.foreign_key.to_s }
71
- @shadowed_columns = model.reflect_on_all_associations(:has_many)
72
- .concat(model.reflect_on_all_associations(:has_one))
79
+ @shadowed_columns = adapter.associations(:has_many)
80
+ .concat(adapter.associations(:has_one))
73
81
  .to_set { |a| a.name.to_s }
82
+ @polymorphic_types_map = build_polymorphic_types_map
74
83
  end
75
84
 
76
85
  # Infers fields from the model's columns, associations, attachments,
@@ -84,7 +93,7 @@ module IronAdmin
84
93
  #
85
94
  # @return [Array<IronAdmin::Field>] Inferred field objects
86
95
  def call
87
- fields = @model.columns.filter_map do |column|
96
+ fields = @adapter.columns.filter_map do |column|
88
97
  next if @shadowed_columns.include?(column.name)
89
98
  next if @polymorphic_columns.include?(column.name)
90
99
 
@@ -110,7 +119,7 @@ module IronAdmin
110
119
  name = column.name.to_sym
111
120
 
112
121
  if enum_column?(name)
113
- Field.new(name, type: :select, choices: @model.defined_enums[name.to_s].keys)
122
+ Field.new(name, type: :select, choices: @adapter.enums[name.to_s].keys)
114
123
  else
115
124
  type = infer_type(column)
116
125
  Field.new(name, type: type)
@@ -134,7 +143,12 @@ module IronAdmin
134
143
  end
135
144
 
136
145
  # @api private
137
- # Builds fields for polymorphic belongs_to associations.
146
+ # Builds fields for polymorphic belongs_to associations. Auto-infers the
147
+ # valid target types by scanning all `ApplicationRecord` descendants for
148
+ # `has_many :<name>, as: :<polymorphic_name>` and
149
+ # `has_one :<name>, as: :<polymorphic_name>` declarations. Without this,
150
+ # the form's type `<select>` is empty and the polymorphic association is
151
+ # unusable in the admin (see #79).
138
152
  def polymorphic_fields
139
153
  @polymorphic_map.map do |name, assoc|
140
154
  Field.new(
@@ -142,11 +156,34 @@ module IronAdmin
142
156
  type: :polymorphic_belongs_to,
143
157
  association_name: name.to_sym,
144
158
  type_column: assoc.foreign_type.to_sym,
145
- id_column: assoc.foreign_key.to_sym
159
+ id_column: assoc.foreign_key.to_sym,
160
+ types: infer_polymorphic_types(name.to_sym)
146
161
  )
147
162
  end
148
163
  end
149
164
 
165
+ # @api private
166
+ # Returns the model classes that declare `has_many` / `has_one` with
167
+ # `as: <polymorphic_name>` — i.e. the valid targets for a polymorphic
168
+ # `belongs_to :<polymorphic_name>`.
169
+ #
170
+ # @param polymorphic_name [Symbol] e.g. `:notable`
171
+ # @return [Array<Class>]
172
+ def infer_polymorphic_types(polymorphic_name)
173
+ @polymorphic_types_map[polymorphic_name] || []
174
+ end
175
+
176
+ # @api private
177
+ # Builds `{ polymorphic_name => [target_classes] }` once per inferrer.
178
+ # Each adapter owns model discovery because ActiveRecord and Mongoid load
179
+ # model classes differently.
180
+ def build_polymorphic_types_map
181
+ return {} if @polymorphic_map.empty?
182
+
183
+ needed = @polymorphic_map.keys.to_set(&:to_sym)
184
+ needed.index_with { |name| @adapter.polymorphic_inverse_classes(name) }
185
+ end
186
+
150
187
  # @api private
151
188
  # Builds a belongs_to field from an association reflection.
152
189
  def build_belongs_to_field(association)
@@ -162,15 +199,16 @@ module IronAdmin
162
199
  # @api private
163
200
  # Checks if a column is backed by an enum.
164
201
  def enum_column?(name)
165
- @model.defined_enums.key?(name.to_s)
202
+ @adapter.enums.key?(name.to_s)
166
203
  end
167
204
 
168
205
  # @api private
169
206
  # Builds fields for ActiveStorage attachments (has_one_attached / has_many_attached).
170
207
  def attachment_fields
171
- return [] unless @model.respond_to?(:attachment_reflections)
208
+ attachments = @adapter.attachments
209
+ return [] if attachments.empty?
172
210
 
173
- @model.attachment_reflections.map do |name, reflection|
211
+ attachments.map do |name, reflection|
174
212
  type = reflection.macro == :has_one_attached ? :file : :files
175
213
  Field.new(name.to_sym, type: type)
176
214
  end
@@ -179,9 +217,10 @@ module IronAdmin
179
217
  # @api private
180
218
  # Builds fields for ActionText rich text attributes (has_rich_text).
181
219
  def rich_text_fields
182
- return [] unless @model.respond_to?(:rich_text_association_names)
220
+ rich_text_attrs = @adapter.rich_text_attributes
221
+ return [] if rich_text_attrs.empty?
183
222
 
184
- @model.rich_text_association_names.map do |assoc_name|
223
+ rich_text_attrs.map do |assoc_name|
185
224
  # ActionText associations are named like "rich_text_body" — strip the prefix
186
225
  attr_name = assoc_name.to_s.delete_prefix("rich_text_").to_sym
187
226
  Field.new(attr_name, type: :rich_text)
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module IronAdmin
4
+ module Filters
5
+ # ActiveRecord-specific query builder for operator-based filters.
6
+ # Uses SQL LIKE/ILIKE for string ops and parameterized queries for number ops.
7
+ class ActiveRecordQueryBuilder < BaseQueryBuilder
8
+ private
9
+
10
+ def apply_string_filter
11
+ return @scope unless STRING_OPS.include?(@op)
12
+
13
+ col = quoted_column
14
+ like_op = postgres? ? "ILIKE" : "LIKE"
15
+ escape = "ESCAPE '\\'"
16
+
17
+ case @op
18
+ when "contains" then @scope.where("#{col} #{like_op} ? #{escape}", "%#{sanitize_like(@value)}%")
19
+ when "equals" then @scope.where(@filter[:name] => @value)
20
+ when "starts_with" then @scope.where("#{col} #{like_op} ? #{escape}", "#{sanitize_like(@value)}%")
21
+ when "ends_with" then @scope.where("#{col} #{like_op} ? #{escape}", "%#{sanitize_like(@value)}")
22
+ else @scope
23
+ end
24
+ end
25
+
26
+ def apply_number_filter
27
+ return @scope unless NUMBER_OPS.include?(@op)
28
+
29
+ num = cast_number(@value)
30
+ return @scope unless num
31
+
32
+ case @op
33
+ when "equals" then @scope.where(@filter[:name] => num)
34
+ when "greater_than" then @scope.where("#{quoted_column} > ?", num)
35
+ when "less_than" then @scope.where("#{quoted_column} < ?", num)
36
+ when "between" then apply_between_filter(num)
37
+ else @scope
38
+ end
39
+ end
40
+
41
+ def apply_between_filter(num)
42
+ upper_num = cast_number(@upper_value)
43
+ return @scope unless upper_num
44
+
45
+ @scope.where(@filter[:name] => num..upper_num)
46
+ end
47
+
48
+ def quoted_column
49
+ conn = @scope.connection
50
+ table = conn.quote_table_name(@scope.model.table_name)
51
+ "#{table}.#{conn.quote_column_name(@filter[:name])}"
52
+ end
53
+
54
+ def sanitize_like(value)
55
+ value.gsub(/[%_\\]/) { |m| "\\#{m}" }
56
+ end
57
+
58
+ def postgres?
59
+ @scope.connection.adapter_name.match?(/PostgreSQL/i)
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module IronAdmin
4
+ module Filters
5
+ # Abstract base class for operator-based filter query builders.
6
+ #
7
+ # Subclasses implement the adapter-specific query building for string
8
+ # and number filter operators. ActiveRecord uses SQL LIKE/ILIKE,
9
+ # Mongoid uses $regex and comparison operators.
10
+ class BaseQueryBuilder
11
+ STRING_OPS = %w[contains equals starts_with ends_with].freeze
12
+ NUMBER_OPS = %w[equals greater_than less_than between].freeze
13
+
14
+ def self.call(scope, filter, params_hash)
15
+ new(scope, filter, params_hash).call
16
+ end
17
+
18
+ def initialize(scope, filter, params_hash)
19
+ @scope = scope
20
+ @filter = filter
21
+ @op = params_hash["op"].to_s
22
+ @value = params_hash["value"].to_s.strip
23
+ @upper_value = params_hash["value_2"].to_s.strip
24
+ end
25
+
26
+ def call
27
+ return @scope if @value.blank?
28
+
29
+ case @filter[:type]
30
+ when :string then apply_string_filter
31
+ when :number then apply_number_filter
32
+ else @scope
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def apply_string_filter
39
+ raise NotImplementedError
40
+ end
41
+
42
+ def apply_number_filter
43
+ raise NotImplementedError
44
+ end
45
+
46
+ def cast_number(val)
47
+ return nil if val.blank?
48
+
49
+ val.include?(".") ? Float(val) : Integer(val)
50
+ rescue ArgumentError, TypeError
51
+ nil
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module IronAdmin
4
+ module Filters
5
+ # HTTP-specific query builder for operator-based filters.
6
+ # Translates string and number operators to query parameters
7
+ # that are sent to the remote API.
8
+ class HttpQueryBuilder < BaseQueryBuilder
9
+ private
10
+
11
+ def apply_string_filter
12
+ return @scope unless STRING_OPS.include?(@op)
13
+
14
+ field = @filter[:name].to_s
15
+ @scope.where("#{field}[#{@op}]" => @value)
16
+ end
17
+
18
+ def apply_number_filter
19
+ return @scope unless NUMBER_OPS.include?(@op)
20
+
21
+ num = cast_number(@value)
22
+ return @scope unless num
23
+
24
+ field = @filter[:name].to_s
25
+ case @op
26
+ when "between" then apply_between_filter(field, num)
27
+ else @scope.where("#{field}[#{@op}]" => num)
28
+ end
29
+ end
30
+
31
+ def apply_between_filter(field, num)
32
+ upper_num = cast_number(@upper_value)
33
+ return @scope unless upper_num
34
+
35
+ @scope.where("#{field}[gte]" => num, "#{field}[lte]" => upper_num)
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module IronAdmin
4
+ module Filters
5
+ # Mongoid-specific query builder for operator-based filters.
6
+ # Uses MongoDB $regex for string ops and comparison operators for number ops.
7
+ class MongoidQueryBuilder < BaseQueryBuilder
8
+ BSON_INT64_RANGE = (-9_223_372_036_854_775_808..9_223_372_036_854_775_807)
9
+ private_constant :BSON_INT64_RANGE
10
+
11
+ private
12
+
13
+ def apply_string_filter
14
+ return @scope unless STRING_OPS.include?(@op)
15
+
16
+ case @op
17
+ when "contains" then @scope.where(@filter[:name] => /#{Regexp.escape(@value)}/i)
18
+ when "equals" then @scope.where(@filter[:name] => @value)
19
+ when "starts_with" then @scope.where(@filter[:name] => /\A#{Regexp.escape(@value)}/i)
20
+ when "ends_with" then @scope.where(@filter[:name] => /#{Regexp.escape(@value)}\z/i)
21
+ else @scope
22
+ end
23
+ end
24
+
25
+ def apply_number_filter
26
+ return @scope unless NUMBER_OPS.include?(@op)
27
+
28
+ num = cast_number(@value)
29
+ return @scope unless num
30
+
31
+ field = @filter[:name].to_s
32
+ case @op
33
+ when "equals" then @scope.where(field => num)
34
+ when "greater_than" then @scope.where(field => { "$gt" => num })
35
+ when "less_than" then @scope.where(field => { "$lt" => num })
36
+ when "between" then apply_between_filter(field, num)
37
+ else @scope
38
+ end
39
+ end
40
+
41
+ def apply_between_filter(field, num)
42
+ upper_num = cast_number(@upper_value)
43
+ return @scope unless upper_num
44
+
45
+ @scope.where(field => { "$gte" => num, "$lte" => upper_num })
46
+ end
47
+
48
+ def cast_number(val)
49
+ number = super
50
+ return unless number
51
+ return number unless number.is_a?(Integer)
52
+ return number if BSON_INT64_RANGE.cover?(number)
53
+
54
+ nil
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base_query_builder"
4
+ require_relative "active_record_query_builder"
5
+
6
+ module IronAdmin
7
+ module Filters
8
+ # Backward-compatible alias for ActiveRecordQueryBuilder.
9
+ # @deprecated Use {ActiveRecordQueryBuilder} directly.
10
+ QueryBuilder = ActiveRecordQueryBuilder
11
+ end
12
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module IronAdmin
4
+ module Import
5
+ class ColumnMapper
6
+ def initialize(resource_class, current_user: nil)
7
+ @resource_class = resource_class
8
+ @current_user = current_user
9
+ end
10
+
11
+ def map_headers(headers)
12
+ candidates = field_candidates
13
+
14
+ headers.each_with_object({}) do |header, mapping|
15
+ field = candidates[normalize(header)]
16
+ mapping[header] = field.name if field
17
+ end
18
+ end
19
+
20
+ private
21
+
22
+ def field_candidates
23
+ @resource_class.importable_fields(@current_user).each_with_object({}) do |field, candidates|
24
+ candidate_labels(field).each { |label| candidates[normalize(label)] = field }
25
+ end
26
+ end
27
+
28
+ def candidate_labels(field)
29
+ [
30
+ field.name,
31
+ field.name.to_s,
32
+ field.name.to_s.humanize,
33
+ field.options[:label],
34
+ ].compact
35
+ end
36
+
37
+ def normalize(value)
38
+ value.to_s.downcase.gsub(/[^a-z0-9]/, "")
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module IronAdmin
4
+ module Import
5
+ Row = Struct.new(:number, :attributes, :errors, keyword_init: true) unless const_defined?(:Row)
6
+ Error = Struct.new(:row_number, :message, keyword_init: true) unless const_defined?(:Error)
7
+
8
+ ImportPreview = Struct.new(:total_rows, :headers, :mapping, :rows, :errors, keyword_init: true)
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module IronAdmin
4
+ module Import
5
+ Row = Struct.new(:number, :attributes, :errors, keyword_init: true) unless const_defined?(:Row)
6
+ Error = Struct.new(:row_number, :message, keyword_init: true) unless const_defined?(:Error)
7
+
8
+ ImportResult = Struct.new(:created_count, :updated_count, :failed_count, :errors, :rows, keyword_init: true)
9
+ end
10
+ end