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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6a7e6f008423227296c7d793dc516a5e535249bedececc1c41af83dd91a019d4
4
- data.tar.gz: 1eb8f4c673a35d21fd1f04bc38fa72d55fba0e984cccc965156bc273f9696ab3
3
+ metadata.gz: cd7c68ca4e035fc4fe1b47d4c3415e76dcbb9ba77a53e9a574abe55a7e3bd6c9
4
+ data.tar.gz: 95ef292dd61db7778af10963a749cc63a9f67e9ecda2a8f115207522ffb28caf
5
5
  SHA512:
6
- metadata.gz: 7259b141211a0575f49d8df3dc3f22fc3d421b0ef60a31770b26aff5da46da70d566a8e6c4255723f836ce7995c39ea4b5764a036dc96157b42004897d52aade
7
- data.tar.gz: fb326e0e209721a1341c8b0740325f2129a5d8e66de8ba2697f3e6325a271227961128c786c25574c88006333c4887c3d805055584284c7589ac925290c45ef3
6
+ metadata.gz: 056e8a6cf97e585a4d979e303aa2a9ca10618b50e6fb75a5f61d5c52070adb7d8d4ae65498eefad9346700eb8ad629a11203a8fc940bd0f96cf44065e2b02b3e
7
+ data.tar.gz: 419a9faf097e0a4f0beab00624eb7e79876cb1b6fbce0d61703dd13f3d879b102586d1271bb58073e7da1dd7cb0709776b625f9cfefaaac41881ecb9be79c259
data/README.md CHANGED
@@ -20,6 +20,7 @@ Convention-over-configuration admin panel engine for Ruby on Rails. Build beauti
20
20
 
21
21
  - Ruby >= 3.2
22
22
  - Rails >= 7.1
23
+ - [tailwindcss-rails](https://github.com/rails/tailwindcss-rails) >= 4.0
23
24
 
24
25
  ## Installation
25
26
 
@@ -27,6 +28,7 @@ Add to your Gemfile:
27
28
 
28
29
  ```ruby
29
30
  gem "iron_admin"
31
+ gem "tailwindcss-rails"
30
32
  ```
31
33
 
32
34
  Then run:
@@ -36,14 +38,40 @@ bundle install
36
38
  rails generate iron_admin:install
37
39
  ```
38
40
 
39
- Mount the engine in your `config/routes.rb`:
41
+ The install generator will:
42
+ - Create `app/iron_admin/resources/` and `app/iron_admin/dashboards/` directories
43
+ - Add a configuration initializer at `config/initializers/iron_admin.rb`
44
+ - Create a sample dashboard
45
+ - Mount the engine at `/admin` in your routes
46
+ - Add the IronAdmin Tailwind CSS import to your `app/assets/tailwind/application.css`
40
47
 
41
- ```ruby
42
- Rails.application.routes.draw do
43
- mount IronAdmin::Engine, at: "/admin"
44
- end
48
+ ### Tailwind CSS Setup
49
+
50
+ IronAdmin uses Tailwind CSS v4 for all styling. The `tailwindcss-rails` gem handles
51
+ compilation. After running the install generator, your `app/assets/tailwind/application.css`
52
+ should include:
53
+
54
+ ```css
55
+ @import "tailwindcss";
56
+ @import "../builds/tailwind/iron_admin";
57
+ ```
58
+
59
+ The second line imports IronAdmin's `@source` directives so the Tailwind compiler
60
+ scans the engine's views and components for CSS classes. Without it, the admin panel
61
+ will render unstyled.
62
+
63
+ If you're setting up manually (without the generator), run:
64
+
65
+ ```bash
66
+ rails tailwindcss:build
45
67
  ```
46
68
 
69
+ Then verify that `app/assets/builds/tailwind/iron_admin.css` was created. If not,
70
+ check that `tailwindcss-rails` >= 4.0 is installed and that the engine gem is properly
71
+ loaded.
72
+
73
+ For development, use `bin/dev` or `rails tailwindcss:watch` to recompile CSS on changes.
74
+
47
75
  ## Quick Start
48
76
 
49
77
  ### 1. Configure Authentication
@@ -75,26 +103,30 @@ rails generate iron_admin:resource Order
75
103
  ### 3. Customize Resources
76
104
 
77
105
  ```ruby
78
- # app/iron_admin/user_resource.rb
79
- class UserResource < IronAdmin::Resource
80
- field :role, type: :badge, colors: { admin: :purple, user: :blue }
81
- field :email, type: :text
106
+ # app/iron_admin/resources/user_resource.rb
107
+ module IronAdmin
108
+ module Resources
109
+ class UserResource < IronAdmin::Resource
110
+ field :role, type: :badge, colors: { admin: :purple, user: :blue }
111
+ field :email, type: :text
82
112
 
83
- searchable :name, :email
113
+ searchable :name, :email
84
114
 
85
- filter :role, type: :select, choices: User.roles.keys
86
- filter :created_at, type: :date_range
115
+ filter :role, type: :select, choices: User.roles.keys
116
+ filter :created_at, type: :date_range
87
117
 
88
- scope :admins, -> { where(role: :admin) }
89
- scope :recent, -> { where("created_at > ?", 7.days.ago) }
118
+ scope :admins, -> { where(role: :admin) }
119
+ scope :recent, -> { where("created_at > ?", 7.days.ago) }
90
120
 
91
- index_fields :id, :name, :email, :role, :created_at
92
- form_fields :name, :email, :role
121
+ index_fields :id, :name, :email, :role, :created_at
122
+ form_fields :name, :email, :role
93
123
 
94
- menu priority: 1, icon: "users", group: "People"
124
+ menu priority: 1, icon: "users", group: "People"
95
125
 
96
- action :lock, icon: "lock-closed", confirm: true do |record|
97
- record.update!(locked_at: Time.current)
126
+ action :lock, icon: "lock-closed", confirm: true do |record|
127
+ record.update!(locked_at: Time.current)
128
+ end
129
+ end
98
130
  end
99
131
  end
100
132
  ```
@@ -102,18 +134,22 @@ end
102
134
  ### 4. Create a Dashboard
103
135
 
104
136
  ```ruby
105
- # app/iron_admin/admin_dashboard.rb
106
- class AdminDashboard < IronAdmin::Dashboard
107
- metric :total_users, format: :number do
108
- User.count
137
+ # app/iron_admin/dashboards/admin_dashboard.rb
138
+ module IronAdmin
139
+ module Dashboards
140
+ class AdminDashboard < IronAdmin::Dashboard
141
+ metric :total_users, format: :number do
142
+ User.count
143
+ end
144
+
145
+ metric :monthly_revenue, format: :currency do
146
+ Payment.where("created_at > ?", 30.days.ago).sum(:amount)
147
+ end
148
+
149
+ recent :users, limit: 5, scope: -> { order(created_at: :desc) }
150
+ recent :payments, limit: 5
151
+ end
109
152
  end
110
-
111
- metric :monthly_revenue, format: :currency do
112
- Payment.where("created_at > ?", 30.days.ago).sum(:amount)
113
- end
114
-
115
- recent :users, limit: 5, scope: -> { order(created_at: :desc) }
116
- recent :payments, limit: 5
117
153
  end
118
154
  ```
119
155
 
@@ -0,0 +1,12 @@
1
+ // Sprockets manifest for IronAdmin engine assets.
2
+ // Engine initializer adds this manifest to the host's precompile list,
3
+ // recursively pulling these assets into Sprockets' precompile set.
4
+
5
+ // Stimulus / importmap entry point + controllers.
6
+ //= link_tree ../../javascript/iron_admin .js
7
+
8
+ // Chart.js (vendored) — loaded by the dashboard layout via
9
+ // `javascript_include_tag "chart.min"`. Without this link, hosts on
10
+ // sprockets-rails 500 on `/admin` with
11
+ // `Asset 'chart.min.js' was not declared to be precompiled`.
12
+ //= link chart.min.js
@@ -1,3 +1,8 @@
1
- .bg-white.rounded-lg.shadow.p-6
2
- %p.text-sm.font-medium.text-gray-500= label
3
- %p.mt-2.text-3xl.font-bold.text-gray-900= formatted_value
1
+ .bg-white.rounded-lg.shadow.p-6{ id: (live_target_id if live?) }
2
+ .flex.items-center.justify-between
3
+ %div
4
+ %p.text-sm.font-medium.text-gray-500= label
5
+ %p.mt-2.text-3xl.font-bold.text-gray-900= formatted_value
6
+ - if icon
7
+ .flex-shrink-0.p-3.bg-indigo-50.rounded-lg
8
+ = heroicon icon, variant: :outline, options: { class: "h-6 w-6 text-indigo-600" }
@@ -7,10 +7,14 @@ module IronAdmin
7
7
  # @param name [String, Symbol] Metric name
8
8
  # @param value [Numeric] Metric value
9
9
  # @param format [Symbol] Format (:number, :currency, :percentage)
10
- def initialize(name:, value:, format: :number)
10
+ # @param icon [String, nil] Optional Heroicon name (e.g., "users", "currency-dollar")
11
+ # @param live [Boolean] Whether to render a stable Turbo Stream target id
12
+ def initialize(name:, value:, format: :number, icon: nil, live: false)
11
13
  @name = name
12
14
  @value = value
13
15
  @format = format
16
+ @icon = icon
17
+ @live = live
14
18
  end
15
19
 
16
20
  # @api private
@@ -28,6 +32,22 @@ module IronAdmin
28
32
  def label
29
33
  @name.to_s.humanize
30
34
  end
35
+
36
+ # @api private
37
+ # @return [Boolean] True when the metric should expose a live target
38
+ def live?
39
+ @live
40
+ end
41
+
42
+ # @api private
43
+ # @return [String] Stable Turbo Stream target id
44
+ def live_target_id
45
+ "metric_#{@name.to_s.parameterize(separator: "_")}"
46
+ end
47
+
48
+ # @api private
49
+ # @return [String, nil] Heroicon name
50
+ attr_reader :icon
31
51
  end
32
52
  end
33
53
  end
@@ -15,6 +15,12 @@ module IronAdmin
15
15
  # @return [Integer]
16
16
  DEFAULT_OPTIONS_LIMIT = 100
17
17
 
18
+ # Methods tried (in order) when no explicit `display_method:` is
19
+ # passed, or when the explicit method returns a blank value.
20
+ # Single source of truth lives on `IronAdmin::ApplicationHelper`
21
+ # so forms and show/index pages can never silently drift apart.
22
+ DISPLAY_METHOD_FALLBACKS = IronAdmin::ApplicationHelper::DISPLAY_METHODS
23
+
18
24
  # @return [String] Select name attribute
19
25
  attr_reader :name
20
26
 
@@ -45,13 +51,17 @@ module IronAdmin
45
51
  # @param name [String] Select name
46
52
  # @param association_class [Class] Associated model class
47
53
  # @param selected [Integer, nil] Selected ID
48
- # @param display_method [Symbol] Display method (default: :name)
54
+ # @param display_method [Symbol, Proc, nil] Custom display method.
55
+ # Pass `nil` (the default) to let the component auto-detect a
56
+ # sensible label from `IronAdmin::ApplicationHelper::DISPLAY_METHODS`
57
+ # (`:name`, `:title`, `:email`, `:label`, `:slug`), falling back
58
+ # to `"<Model> #<id>"` if none of those exist.
49
59
  # @param include_blank [Boolean] Include blank option
50
60
  # @param disabled [Boolean] Disabled state
51
61
  # @param has_error [Boolean] Error state
52
62
  # @param options_limit [Integer] Max options
53
63
  # @param options_scope [Proc, nil] Custom scope
54
- def initialize(name:, association_class:, selected: nil, display_method: :name,
64
+ def initialize(name:, association_class:, selected: nil, display_method: nil,
55
65
  include_blank: true, disabled: false, has_error: false,
56
66
  options_limit: DEFAULT_OPTIONS_LIMIT, options_scope: nil)
57
67
  @name = name
@@ -74,16 +84,43 @@ module IronAdmin
74
84
  # @api private
75
85
  # @return [Array<Array(String, Integer)>] Options array for select tag
76
86
  def options
77
- scope = options_scope ? association_class.instance_exec(&options_scope) : association_class.all
78
- scope.limit(options_limit).map do |record|
79
- [record.public_send(display_method), record.id]
87
+ scope = options_scope ? association_class.instance_exec(&options_scope) : association_adapter.all
88
+ association_adapter.limit(scope, options_limit).map do |record|
89
+ [option_label_for(record), record.id]
90
+ end
91
+ end
92
+
93
+ # @api private
94
+ # Resolves the option label for a single record. Mirrors
95
+ # `IronAdmin::ApplicationHelper#display_record_label` so callers
96
+ # who construct the component directly (or test it without
97
+ # rendering) get the same fallback behavior:
98
+ #
99
+ # 1. Try the explicit `display_method:` (`Proc` or `Symbol`/
100
+ # `String`) and return it if it produces a non-blank value.
101
+ # 2. If the explicit method is absent or returns blank/nil, walk
102
+ # `DISPLAY_METHOD_FALLBACKS` and return the first non-blank one.
103
+ # 3. Otherwise return `"<Model> #<id>"` so the option is at least
104
+ # identifiable.
105
+ #
106
+ # @param record [Object] The associated record
107
+ # @return [String] The label
108
+ def option_label_for(record)
109
+ explicit = explicit_display_value(record)
110
+ return explicit if explicit.present?
111
+
112
+ DISPLAY_METHOD_FALLBACKS.each do |method|
113
+ value = record.public_send(method) if record.respond_to?(method)
114
+ return value if value.present?
80
115
  end
116
+
117
+ "#{record.class.model_name.human} ##{record.id}"
81
118
  end
82
119
 
83
120
  # @api private
84
121
  # @return [Boolean] Whether to show hint about more records available
85
122
  def show_search_hint?
86
- association_class.count > options_limit
123
+ association_adapter.count > options_limit
87
124
  end
88
125
 
89
126
  # @api private
@@ -105,6 +142,23 @@ module IronAdmin
105
142
  "stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e\"); background-position: right 0.5rem center; " \
106
143
  "background-repeat: no-repeat; background-size: 1.5em 1.5em; padding-right: 2.5rem;"
107
144
  end
145
+
146
+ private
147
+
148
+ # Calls the explicit `display_method:` (if any) and returns its
149
+ # result. Returns `nil` when no explicit method is set, so callers
150
+ # can `present?`-check and fall through to the auto-detect chain.
151
+ def explicit_display_value(record)
152
+ case display_method
153
+ when Proc then display_method.call(record)
154
+ when Symbol, String then record.public_send(display_method)
155
+ end
156
+ end
157
+
158
+ # @return [IronAdmin::Adapters::Base] Adapter for the associated model
159
+ def association_adapter
160
+ @association_adapter ||= IronAdmin::Adapters::ActiveRecord.new(association_class)
161
+ end
108
162
  end
109
163
  end
110
164
  end
@@ -0,0 +1,28 @@
1
+ %div{ data: { controller: "cp-nested-form",
2
+ "cp-nested-form-association-name-value": name,
3
+ "cp-nested-form-allow-destroy-value": allow_destroy,
4
+ "cp-nested-form-sortable-value": sortable? } }
5
+
6
+ .flex.items-center.justify-between.mb-4
7
+ %h3.text-base.font-semibold{ class: "#{theme.heading_weight} #{theme.body_text}" }= title
8
+ - if show_add_button?
9
+ %button.inline-flex.items-center.gap-1.px-3.py-1.text-sm.font-medium.rounded-lg.border.border-dashed.cursor-pointer{ type: "button",
10
+ class: "#{theme.link} border-current hover:bg-gray-50",
11
+ data: { action: "cp-nested-form#addRow" } }
12
+ = I18n.t("iron_admin.nested_form.add_button", default: "Add row")
13
+
14
+ -# Hidden template for JS cloning of new rows
15
+ %template{ id: "#{name}-nested-template" }
16
+ - if form
17
+ - new_child = nested_association.reflection.klass.new
18
+ = form.fields_for name, new_child, child_index: template_index do |child_f|
19
+ = render "iron_admin/form/nested_row", child_f: child_f, nested_association: nested_association,
20
+ child: new_child, current_user: current_user
21
+
22
+ -# Existing rows container
23
+ %div{ data: { "cp-nested-form-target": "rowsContainer" } }
24
+ - child_records.each do |child|
25
+ - if form
26
+ = form.fields_for name, child do |child_f|
27
+ = render "iron_admin/form/nested_row", child_f: child_f, nested_association: nested_association,
28
+ child: child, current_user: current_user
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ module IronAdmin
4
+ module Form
5
+ # ViewComponent for rendering nested association forms inline within a parent form.
6
+ #
7
+ # Renders existing child records as editable rows and provides a hidden <template>
8
+ # element that JavaScript clones to add new rows dynamically.
9
+ class NestedFormComponent < ViewComponent::Base
10
+ # @return [ActionView::Helpers::FormBuilder] The parent form builder
11
+ attr_reader :form
12
+
13
+ # @return [IronAdmin::NestedAssociation] The nested association configuration
14
+ attr_reader :nested_association
15
+
16
+ # @return [ActiveRecord::Base] The parent record
17
+ attr_reader :record
18
+
19
+ # @return [Object, nil] The current authenticated user
20
+ attr_reader :current_user
21
+
22
+ delegate :name, :kind, :fields, :allow_destroy, :position_field, to: :nested_association
23
+
24
+ # @param form [ActionView::Helpers::FormBuilder] The parent form builder
25
+ # @param nested_association [IronAdmin::NestedAssociation] Nested config
26
+ # @param record [ActiveRecord::Base] The parent record
27
+ # @param current_user [Object, nil] Current user for permission checks
28
+ def initialize(form:, nested_association:, record:, current_user: nil)
29
+ super()
30
+ @form = form
31
+ @nested_association = nested_association
32
+ @record = record
33
+ @current_user = current_user
34
+ end
35
+
36
+ # @return [IronAdmin::Configuration::Theme] Theme configuration
37
+ def theme
38
+ IronAdmin.configuration.theme
39
+ end
40
+
41
+ # @return [String] Human-readable title for the section header
42
+ def title
43
+ name.to_s.humanize
44
+ end
45
+
46
+ # @return [Boolean] Whether to show the "Add" button (has_many only)
47
+ def show_add_button?
48
+ kind == :has_many
49
+ end
50
+
51
+ # @return [Boolean] Whether drag-and-drop sorting is enabled
52
+ def sortable?
53
+ position_field.present?
54
+ end
55
+
56
+ # @return [String] The placeholder index used in template rows
57
+ def template_index
58
+ "NEW_RECORD_INDEX"
59
+ end
60
+
61
+ # Returns the child records for the nested association.
62
+ #
63
+ # For has_one, wraps the record in an array or builds a new instance.
64
+ # For has_many with a position_field, sorts by that field ascending.
65
+ # Returns in-memory objects so validation errors are preserved.
66
+ #
67
+ # @return [Array<ActiveRecord::Base>] Child records
68
+ def child_records
69
+ children = record.public_send(name)
70
+
71
+ if kind == :has_one
72
+ [children || nested_association.reflection.klass.new]
73
+ elsif position_field
74
+ children.to_a.sort_by { |c| c.public_send(position_field) || Float::INFINITY }
75
+ else
76
+ children.to_a
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
@@ -23,7 +23,7 @@
23
23
  No records found.
24
24
  - else
25
25
  - records.each do |record|
26
- %tr{ class: theme.table_row_hover }
26
+ %tr{ id: row_dom_id(record), class: theme.table_row_hover }
27
27
  - visible_fields.each do |field|
28
28
  %td.px-6.py-4.whitespace-nowrap.text-sm{ class: theme.body_text }
29
29
  = helpers.display_index_field_value(record, field)
@@ -89,6 +89,12 @@ module IronAdmin
89
89
  def sort_direction
90
90
  current_direction
91
91
  end
92
+
93
+ # @api private
94
+ # @return [String] Stable Turbo Stream target id for a record row
95
+ def row_dom_id(record)
96
+ "iron_admin_#{resource_class.resource_name}_row_#{record.id}"
97
+ end
92
98
  end
93
99
  end
94
100
  end
@@ -23,6 +23,8 @@ module IronAdmin
23
23
  end
24
24
 
25
25
  def render?
26
+ return false if field.type == :hidden
27
+
26
28
  field.visible?(@current_user)
27
29
  end
28
30
 
@@ -13,7 +13,10 @@ module IronAdmin
13
13
 
14
14
  before_action :authenticate_iron_admin_user!
15
15
 
16
- helper_method :iron_admin_current_user
16
+ rescue_from IronAdmin::RecordNotFound, with: :render_not_found
17
+ rescue_from ActionController::ParameterMissing, with: :render_bad_request
18
+
19
+ helper_method :iron_admin_current_user, :iron_admin_filter_param, :iron_admin_active_filter?
17
20
 
18
21
  private
19
22
 
@@ -30,5 +33,33 @@ module IronAdmin
30
33
 
31
34
  @iron_admin_current_user ||= instance_exec(self, &IronAdmin.configuration.current_user_block)
32
35
  end
36
+
37
+ def iron_admin_filter_param(*keys)
38
+ iron_admin_param_dig(params[:filters], *keys)
39
+ end
40
+
41
+ def iron_admin_active_filter?(filter)
42
+ iron_admin_filter_param(filter[:name]).present? ||
43
+ iron_admin_filter_param("#{filter[:name]}_from").present? ||
44
+ iron_admin_filter_param("#{filter[:name]}_to").present? ||
45
+ (iron_admin_filter_param(filter[:name].to_s).is_a?(ActionController::Parameters) &&
46
+ iron_admin_filter_param(filter[:name].to_s, "value").present?)
47
+ end
48
+
49
+ def iron_admin_param_dig(value, *keys)
50
+ keys.reduce(value) do |current, key|
51
+ return nil unless current.is_a?(ActionController::Parameters) || current.is_a?(Hash)
52
+
53
+ current[key]
54
+ end
55
+ end
56
+
57
+ def render_not_found
58
+ head(:not_found)
59
+ end
60
+
61
+ def render_bad_request
62
+ head(:bad_request)
63
+ end
33
64
  end
34
65
  end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module IronAdmin
4
+ module Concerns
5
+ # Provides action execution with arity-based dispatch for form params.
6
+ #
7
+ # Supports both legacy 1-arg blocks (backward compat) and 2-arg blocks
8
+ # that receive collected action_form params as the second argument.
9
+ module ActionExecutable
10
+ extend ActiveSupport::Concern
11
+
12
+ private
13
+
14
+ # Dispatches an action block with the correct number of arguments.
15
+ #
16
+ # 1-arg blocks receive only the subject (record or records).
17
+ # 2-arg blocks receive the subject and collected form params.
18
+ #
19
+ # @param block [Proc] The action block
20
+ # @param subject [Object] The record or records
21
+ # @param collected_params [Hash] Collected form params
22
+ # @return [Object] The block's return value
23
+ def call_action_block(block, subject, collected_params)
24
+ if block.arity.in?([1, -1])
25
+ block.call(subject)
26
+ else
27
+ block.call(subject, collected_params)
28
+ end
29
+ end
30
+
31
+ # Extracts and permits action form params based on declared form_fields.
32
+ #
33
+ # @param action [Hash] The action definition with :form_fields key
34
+ # @return [Hash] Permitted params with symbolized keys, or empty hash
35
+ def action_form_params(action)
36
+ fields = action[:form_fields] || []
37
+ return {} if fields.empty?
38
+
39
+ permitted_keys = fields.map(&:name)
40
+ params.fetch(:action_form, {}).permit(*permitted_keys).to_h.symbolize_keys
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ module IronAdmin
4
+ module Concerns
5
+ # Provides filter functionality for resource controllers.
6
+ #
7
+ # Supports flat filters (:select, :boolean), date range filters,
8
+ # and operator-based filters (:string, :number) via QueryBuilder.
9
+ module Filterable
10
+ extend ActiveSupport::Concern
11
+
12
+ included do
13
+ helper_method :iron_admin_visible_filters if respond_to?(:helper_method)
14
+ end
15
+
16
+ private
17
+
18
+ # Applies all configured filters to the scope.
19
+ #
20
+ # @param scope [Object] Base query scope (ActiveRecord::Relation or Mongoid::Criteria)
21
+ # @return [Object] Filtered scope
22
+ def apply_filters(scope)
23
+ iron_admin_visible_filters.each do |filter|
24
+ scope = case filter[:type]
25
+ when :string, :number then apply_operator_filter(scope, filter)
26
+ when :date_range then apply_date_range_filter(scope, filter)
27
+ else apply_flat_filter(scope, filter)
28
+ end
29
+ end
30
+ scope
31
+ end
32
+
33
+ def iron_admin_visible_filters
34
+ @iron_admin_visible_filters ||= begin
35
+ resolved_fields = @resource_class.resolved_fields
36
+ resolved_names = resolved_fields.map(&:name)
37
+ visible_names = resolved_fields.select { |field| field.visible?(iron_admin_current_user) }.map(&:name)
38
+
39
+ @resource_class.all_filters.select do |filter|
40
+ filter_name = filter[:name].to_sym
41
+ resolved_names.exclude?(filter_name) || visible_names.include?(filter_name)
42
+ end
43
+ end
44
+ end
45
+
46
+ def apply_operator_filter(scope, filter)
47
+ sub = iron_admin_filter_param(filter[:name].to_s)
48
+ return scope unless sub.is_a?(ActionController::Parameters) && sub["value"].present?
49
+
50
+ adapter.query_builder_class.call(scope, filter, sub.to_unsafe_h)
51
+ end
52
+
53
+ def apply_date_range_filter(scope, filter)
54
+ from = iron_admin_filter_param("#{filter[:name]}_from")
55
+ to = iron_admin_filter_param("#{filter[:name]}_to")
56
+ scope = adapter.filter(scope, filter[:name], parse_date(from)..) if from.present? && parse_date(from)
57
+ scope = adapter.filter(scope, filter[:name], ..parse_date(to)&.end_of_day) if to.present? && parse_date(to)
58
+ scope
59
+ end
60
+
61
+ def apply_flat_filter(scope, filter)
62
+ value = iron_admin_filter_param(filter[:name])
63
+ return scope if value.blank?
64
+ return scope unless value.is_a?(String)
65
+
66
+ value = adapter.cast_boolean(value) if filter[:type] == :boolean
67
+
68
+ if filter[:scope]
69
+ filter[:scope].call(value, scope)
70
+ else
71
+ adapter.filter(scope, filter[:name], value)
72
+ end
73
+ end
74
+
75
+ def parse_date(value)
76
+ return nil if value.blank?
77
+
78
+ Date.parse(value)
79
+ rescue ArgumentError, TypeError
80
+ nil
81
+ end
82
+ end
83
+ end
84
+ end