plutonium 0.5.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 (346) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/.ruby-version +1 -0
  4. data/.standard.yml +4 -0
  5. data/.vscode/extensions.json +15 -0
  6. data/.vscode/launch.json +7 -0
  7. data/.vscode/settings.json +35 -0
  8. data/CHANGELOG.md +5 -0
  9. data/LICENSE.txt +21 -0
  10. data/README copy.md +84 -0
  11. data/README.md +67 -0
  12. data/Rakefile +8 -0
  13. data/app/views/layouts/resource.html.erb +43 -0
  14. data/app/views/resource/_color_modes.html.erb +55 -0
  15. data/app/views/resource/_details.html.erb +6 -0
  16. data/app/views/resource/_empty_card.html.erb +12 -0
  17. data/app/views/resource/_flash.html.erb +9 -0
  18. data/app/views/resource/_form.html.erb +32 -0
  19. data/app/views/resource/_header.html.erb +8 -0
  20. data/app/views/resource/_interactive_resource_action_form.html.erb +67 -0
  21. data/app/views/resource/_messages.html.erb +1 -0
  22. data/app/views/resource/_metric_card.html.erb +16 -0
  23. data/app/views/resource/_nav_user.html.erb +4 -0
  24. data/app/views/resource/_pagination.html.erb +6 -0
  25. data/app/views/resource/_pagy_pagination.html.erb +15 -0
  26. data/app/views/resource/_resource.html.erb +1 -0
  27. data/app/views/resource/_resource.rabl +5 -0
  28. data/app/views/resource/_sidebar.html.erb +11 -0
  29. data/app/views/resource/_sidebar_menu.html.erb +1 -0
  30. data/app/views/resource/_tab_menu.html.erb +13 -0
  31. data/app/views/resource/_table.html.erb +78 -0
  32. data/app/views/resource/_table_actions.html.erb +15 -0
  33. data/app/views/resource/_toast.html.erb +26 -0
  34. data/app/views/resource/_toolbar.html.erb +22 -0
  35. data/app/views/resource/_toolbar_actions.html.erb +16 -0
  36. data/app/views/resource/_toolbar_breadcrumbs.html.erb +32 -0
  37. data/app/views/resource/_toolbar_search_input.erb +27 -0
  38. data/app/views/resource/edit.html.erb +10 -0
  39. data/app/views/resource/errors.rabl +3 -0
  40. data/app/views/resource/index.html.erb +19 -0
  41. data/app/views/resource/index.rabl +3 -0
  42. data/app/views/resource/interactive_resource_collection_action.html.erb +11 -0
  43. data/app/views/resource/interactive_resource_record_action.html.erb +11 -0
  44. data/app/views/resource/interactive_resource_recordless_action.html.erb +11 -0
  45. data/app/views/resource/new.html.erb +11 -0
  46. data/app/views/resource/readme.md +16 -0
  47. data/app/views/resource/show.html.erb +14 -0
  48. data/app/views/resource/show.rabl +3 -0
  49. data/brakeman.ignore +51 -0
  50. data/lib/active_model/validations/array_validator.rb +74 -0
  51. data/lib/active_model/validations/attached_validator.rb +17 -0
  52. data/lib/active_model/validations/url_validator.rb +51 -0
  53. data/lib/generators/pu/core/install/install_generator.rb +43 -0
  54. data/lib/generators/pu/core/install/templates/.keep +0 -0
  55. data/lib/generators/pu/core/install/templates/app/controllers/resource_controller.rb.tt +2 -0
  56. data/lib/generators/pu/core/install/templates/app/interactions/resource_interaction.rb.tt +2 -0
  57. data/lib/generators/pu/core/install/templates/app/models/resource_record.rb.tt +5 -0
  58. data/lib/generators/pu/core/install/templates/app/policies/resource_policy.rb.tt +2 -0
  59. data/lib/generators/pu/core/install/templates/app/presenters/resource_presenter.rb.tt +2 -0
  60. data/lib/generators/pu/core/install/templates/config/initializers/plutonium.rb +2 -0
  61. data/lib/generators/pu/core/install/templates/config/packages.rb +3 -0
  62. data/lib/generators/pu/gem/pagy/pagy_generator.rb +25 -0
  63. data/lib/generators/pu/gem/pagy/templates/.keep +0 -0
  64. data/lib/generators/pu/gem/pagy/templates/config/initializers/pagy.rb +4 -0
  65. data/lib/generators/pu/gem/rabl/rabl_generator.rb +25 -0
  66. data/lib/generators/pu/gem/rabl/templates/.keep +0 -0
  67. data/lib/generators/pu/gem/rabl/templates/config/initializers/rabl.rb +60 -0
  68. data/lib/generators/pu/gem/simple_form/simple_form_generator.rb +25 -0
  69. data/lib/generators/pu/gem/simple_form/templates/.keep +0 -0
  70. data/lib/generators/pu/gen/pug/pug_generator.rb +43 -0
  71. data/lib/generators/pu/gen/pug/templates/pug.rb.tt +23 -0
  72. data/lib/generators/pu/pkg/app/app_generator.rb +60 -0
  73. data/lib/generators/pu/pkg/app/templates/app/controllers/resource_controller.rb.tt +26 -0
  74. data/lib/generators/pu/pkg/app/templates/app/interactions/resource_interaction.rb.tt +4 -0
  75. data/lib/generators/pu/pkg/app/templates/app/policies/resource_policy.rb.tt +4 -0
  76. data/lib/generators/pu/pkg/app/templates/app/presenters/resource_presenter.rb.tt +4 -0
  77. data/lib/generators/pu/pkg/app/templates/config/routes.rb.tt +17 -0
  78. data/lib/generators/pu/pkg/app/templates/lib/engine.rb.tt +14 -0
  79. data/lib/generators/pu/pkg/feature/feature_generator.rb +44 -0
  80. data/lib/generators/pu/pkg/feature/templates/.keep +0 -0
  81. data/lib/generators/pu/pkg/feature/templates/app/controllers/resource_controller.rb.tt +7 -0
  82. data/lib/generators/pu/pkg/feature/templates/app/interactions/resource_interaction.rb.tt +4 -0
  83. data/lib/generators/pu/pkg/feature/templates/app/models/resource_record.rb.tt +5 -0
  84. data/lib/generators/pu/pkg/feature/templates/app/policies/resource_policy.rb.tt +4 -0
  85. data/lib/generators/pu/pkg/feature/templates/app/presenters/resource_presenter.rb.tt +4 -0
  86. data/lib/generators/pu/pkg/feature/templates/lib/engine.rb.tt +8 -0
  87. data/lib/generators/pu/resource/conn/conn_generator.rb +54 -0
  88. data/lib/generators/pu/resource/conn/templates/.keep +0 -0
  89. data/lib/generators/pu/resource/conn/templates/app/controllers/resource_controller.rb.tt +3 -0
  90. data/lib/generators/pu/resource/conn/templates/app/policies/resource_policy.rb.tt +3 -0
  91. data/lib/generators/pu/resource/conn/templates/app/presenters/resource_presenter.rb.tt +3 -0
  92. data/lib/generators/pu/resource/model/USAGE +113 -0
  93. data/lib/generators/pu/resource/model/model_generator.rb +163 -0
  94. data/lib/generators/pu/resource/model/templates/controller.rb.tt +5 -0
  95. data/lib/generators/pu/resource/model/templates/create_table_migration.rb.tt +26 -0
  96. data/lib/generators/pu/resource/model/templates/model.rb.tt +53 -0
  97. data/lib/generators/pu/resource/model/templates/module.rb.tt +7 -0
  98. data/lib/generators/pu/resource/model/templates/policy.rb.tt +4 -0
  99. data/lib/generators/pu/resource/model/templates/presenter.rb.tt +4 -0
  100. data/lib/generators/pu/resource/scaffold/scaffold_generator.rb +219 -0
  101. data/lib/generators/pu/resource/scaffold/templates/app/controllers/admin_resources/resource_controller.rb.tt +7 -0
  102. data/lib/generators/pu/resource/scaffold/templates/app/controllers/entity_resources/resource_controller.rb.tt +7 -0
  103. data/lib/generators/pu/resource/scaffold/templates/app/policies/resources/admin/resource_policy.rb.tt +22 -0
  104. data/lib/generators/pu/resource/scaffold/templates/app/policies/resources/entity/resource_policy.rb.tt +22 -0
  105. data/lib/generators/pu/resource/scaffold/templates/app/policies/resources/resource_policy.rb.tt +13 -0
  106. data/lib/generators/pu/resource/scaffold/templates/app/resources/resource/admin_presenter.rb.tt +7 -0
  107. data/lib/generators/pu/resource/scaffold/templates/app/resources/resource/entity_presenter.rb.tt +7 -0
  108. data/lib/generators/pu/resource/scaffold/templates/app/resources/resource/presenter.rb.tt +23 -0
  109. data/lib/generators/pu/resource/scaffold/templates/app/views/resources/resource/_resource.html.erb.tt +3 -0
  110. data/lib/generators/pu/resource/scaffold/templates/app/views/resources/resource/_resource.rabl +7 -0
  111. data/lib/generators/pu/rodauth/account_generator.rb +120 -0
  112. data/lib/generators/pu/rodauth/concerns/account_selector.rb +22 -0
  113. data/lib/generators/pu/rodauth/concerns/configuration.rb +211 -0
  114. data/lib/generators/pu/rodauth/concerns/feature_selector.rb +125 -0
  115. data/lib/generators/pu/rodauth/install_generator.rb +69 -0
  116. data/lib/generators/pu/rodauth/migration/active_record/account_expiration.erb +8 -0
  117. data/lib/generators/pu/rodauth/migration/active_record/active_sessions.erb +7 -0
  118. data/lib/generators/pu/rodauth/migration/active_record/audit_logging.erb +16 -0
  119. data/lib/generators/pu/rodauth/migration/active_record/base.erb +22 -0
  120. data/lib/generators/pu/rodauth/migration/active_record/disallow_password_reuse.erb +5 -0
  121. data/lib/generators/pu/rodauth/migration/active_record/email_auth.erb +8 -0
  122. data/lib/generators/pu/rodauth/migration/active_record/jwt_refresh.erb +7 -0
  123. data/lib/generators/pu/rodauth/migration/active_record/lockout.erb +13 -0
  124. data/lib/generators/pu/rodauth/migration/active_record/otp.erb +8 -0
  125. data/lib/generators/pu/rodauth/migration/active_record/password_expiration.erb +6 -0
  126. data/lib/generators/pu/rodauth/migration/active_record/recovery_codes.erb +6 -0
  127. data/lib/generators/pu/rodauth/migration/active_record/remember.erb +7 -0
  128. data/lib/generators/pu/rodauth/migration/active_record/reset_password.erb +8 -0
  129. data/lib/generators/pu/rodauth/migration/active_record/separate_passwords.erb +5 -0
  130. data/lib/generators/pu/rodauth/migration/active_record/single_session.erb +6 -0
  131. data/lib/generators/pu/rodauth/migration/active_record/sms_codes.erb +9 -0
  132. data/lib/generators/pu/rodauth/migration/active_record/verify_account.erb +8 -0
  133. data/lib/generators/pu/rodauth/migration/active_record/verify_login_change.erb +8 -0
  134. data/lib/generators/pu/rodauth/migration/active_record/webauthn.erb +13 -0
  135. data/lib/generators/pu/rodauth/migration/sequel/account_expiration.erb +7 -0
  136. data/lib/generators/pu/rodauth/migration/sequel/active_sessions.erb +8 -0
  137. data/lib/generators/pu/rodauth/migration/sequel/audit_logging.erb +17 -0
  138. data/lib/generators/pu/rodauth/migration/sequel/base.erb +25 -0
  139. data/lib/generators/pu/rodauth/migration/sequel/disallow_password_reuse.erb +6 -0
  140. data/lib/generators/pu/rodauth/migration/sequel/email_auth.erb +7 -0
  141. data/lib/generators/pu/rodauth/migration/sequel/jwt_refresh.erb +8 -0
  142. data/lib/generators/pu/rodauth/migration/sequel/lockout.erb +11 -0
  143. data/lib/generators/pu/rodauth/migration/sequel/otp.erb +7 -0
  144. data/lib/generators/pu/rodauth/migration/sequel/password_expiration.erb +5 -0
  145. data/lib/generators/pu/rodauth/migration/sequel/recovery_codes.erb +6 -0
  146. data/lib/generators/pu/rodauth/migration/sequel/remember.erb +6 -0
  147. data/lib/generators/pu/rodauth/migration/sequel/reset_password.erb +7 -0
  148. data/lib/generators/pu/rodauth/migration/sequel/separate_passwords.erb +6 -0
  149. data/lib/generators/pu/rodauth/migration/sequel/single_session.erb +5 -0
  150. data/lib/generators/pu/rodauth/migration/sequel/sms_codes.erb +8 -0
  151. data/lib/generators/pu/rodauth/migration/sequel/verify_account.erb +7 -0
  152. data/lib/generators/pu/rodauth/migration/sequel/verify_login_change.erb +7 -0
  153. data/lib/generators/pu/rodauth/migration/sequel/webauthn.erb +13 -0
  154. data/lib/generators/pu/rodauth/migration_generator.rb +190 -0
  155. data/lib/generators/pu/rodauth/templates/INSTRUCTIONS +52 -0
  156. data/lib/generators/pu/rodauth/templates/app/controllers/plugin_controller.rb.tt +6 -0
  157. data/lib/generators/pu/rodauth/templates/app/controllers/rodauth_controller.rb.tt +3 -0
  158. data/lib/generators/pu/rodauth/templates/app/mailers/account_mailer.rb.tt +4 -0
  159. data/lib/generators/pu/rodauth/templates/app/mailers/rodauth_mailer.rb.tt +62 -0
  160. data/lib/generators/pu/rodauth/templates/app/misc/account_rodauth_plugin.rb.tt +255 -0
  161. data/lib/generators/pu/rodauth/templates/app/misc/rodauth_app.rb.tt +24 -0
  162. data/lib/generators/pu/rodauth/templates/app/misc/rodauth_plugin.rb.tt +234 -0
  163. data/lib/generators/pu/rodauth/templates/app/models/account.rb.tt +40 -0
  164. data/lib/generators/pu/rodauth/templates/app/views/rodauth/_email_auth_request_form.html.erb +7 -0
  165. data/lib/generators/pu/rodauth/templates/app/views/rodauth/_login_form.html.erb +26 -0
  166. data/lib/generators/pu/rodauth/templates/app/views/rodauth/_login_form_footer.html.erb +9 -0
  167. data/lib/generators/pu/rodauth/templates/app/views/rodauth/add_recovery_codes.html.erb +6 -0
  168. data/lib/generators/pu/rodauth/templates/app/views/rodauth/change_login.html.erb +27 -0
  169. data/lib/generators/pu/rodauth/templates/app/views/rodauth/change_password.html.erb +27 -0
  170. data/lib/generators/pu/rodauth/templates/app/views/rodauth/close_account.html.erb +13 -0
  171. data/lib/generators/pu/rodauth/templates/app/views/rodauth/confirm_password.html.erb +11 -0
  172. data/lib/generators/pu/rodauth/templates/app/views/rodauth/create_account.html.erb +35 -0
  173. data/lib/generators/pu/rodauth/templates/app/views/rodauth/email_auth.html.erb +5 -0
  174. data/lib/generators/pu/rodauth/templates/app/views/rodauth/login.html.erb +4 -0
  175. data/lib/generators/pu/rodauth/templates/app/views/rodauth/logout.html.erb +14 -0
  176. data/lib/generators/pu/rodauth/templates/app/views/rodauth/multi_phase_login.html.erb +3 -0
  177. data/lib/generators/pu/rodauth/templates/app/views/rodauth/otp_auth.html.erb +15 -0
  178. data/lib/generators/pu/rodauth/templates/app/views/rodauth/otp_disable.html.erb +13 -0
  179. data/lib/generators/pu/rodauth/templates/app/views/rodauth/otp_setup.html.erb +41 -0
  180. data/lib/generators/pu/rodauth/templates/app/views/rodauth/recovery_auth.html.erb +11 -0
  181. data/lib/generators/pu/rodauth/templates/app/views/rodauth/recovery_codes.html.erb +13 -0
  182. data/lib/generators/pu/rodauth/templates/app/views/rodauth/remember.html.erb +22 -0
  183. data/lib/generators/pu/rodauth/templates/app/views/rodauth/reset_password.html.erb +19 -0
  184. data/lib/generators/pu/rodauth/templates/app/views/rodauth/reset_password_request.html.erb +17 -0
  185. data/lib/generators/pu/rodauth/templates/app/views/rodauth/sms_auth.html.erb +15 -0
  186. data/lib/generators/pu/rodauth/templates/app/views/rodauth/sms_confirm.html.erb +15 -0
  187. data/lib/generators/pu/rodauth/templates/app/views/rodauth/sms_disable.html.erb +13 -0
  188. data/lib/generators/pu/rodauth/templates/app/views/rodauth/sms_request.html.erb +5 -0
  189. data/lib/generators/pu/rodauth/templates/app/views/rodauth/sms_setup.html.erb +23 -0
  190. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/_email_auth_request_form.html.erb +5 -0
  191. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/_login_form.html.erb +24 -0
  192. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/_login_form_footer.html.erb +7 -0
  193. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/add_recovery_codes.html.erb +16 -0
  194. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/change_login.html.erb +25 -0
  195. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/change_password.html.erb +25 -0
  196. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/close_account.html.erb +11 -0
  197. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/confirm_password.html.erb +19 -0
  198. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/create_account.html.erb +33 -0
  199. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/email_auth.html.erb +3 -0
  200. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/login.html.erb +5 -0
  201. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/logout.html.erb +10 -0
  202. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/multi_phase_login.html.erb +5 -0
  203. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/otp_auth.html.erb +9 -0
  204. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/otp_disable.html.erb +11 -0
  205. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/otp_setup.html.erb +32 -0
  206. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/recovery_auth.html.erb +9 -0
  207. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/recovery_codes.html.erb +11 -0
  208. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/remember.html.erb +18 -0
  209. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/reset_password.html.erb +17 -0
  210. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/reset_password_request.html.erb +17 -0
  211. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/sms_auth.html.erb +9 -0
  212. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/sms_confirm.html.erb +9 -0
  213. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/sms_disable.html.erb +11 -0
  214. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/sms_request.html.erb +3 -0
  215. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/sms_setup.html.erb +17 -0
  216. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/two_factor_auth.html.erb +5 -0
  217. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/two_factor_disable.html.erb +11 -0
  218. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/two_factor_manage.html.erb +26 -0
  219. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/unlock_account.html.erb +15 -0
  220. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/unlock_account_request.html.erb +9 -0
  221. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/verify_account.html.erb +19 -0
  222. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/verify_account_resend.html.erb +17 -0
  223. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/verify_login_change.html.erb +3 -0
  224. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/webauthn_auth.html.erb +13 -0
  225. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/webauthn_autofill.html.erb +10 -0
  226. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/webauthn_remove.html.erb +21 -0
  227. data/lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind/webauthn_setup.html.erb +21 -0
  228. data/lib/generators/pu/rodauth/templates/app/views/rodauth/two_factor_auth.html.erb +5 -0
  229. data/lib/generators/pu/rodauth/templates/app/views/rodauth/two_factor_disable.html.erb +13 -0
  230. data/lib/generators/pu/rodauth/templates/app/views/rodauth/two_factor_manage.html.erb +22 -0
  231. data/lib/generators/pu/rodauth/templates/app/views/rodauth/unlock_account.html.erb +15 -0
  232. data/lib/generators/pu/rodauth/templates/app/views/rodauth/unlock_account_request.html.erb +9 -0
  233. data/lib/generators/pu/rodauth/templates/app/views/rodauth/verify_account.html.erb +21 -0
  234. data/lib/generators/pu/rodauth/templates/app/views/rodauth/verify_account_resend.html.erb +17 -0
  235. data/lib/generators/pu/rodauth/templates/app/views/rodauth/verify_login_change.html.erb +5 -0
  236. data/lib/generators/pu/rodauth/templates/app/views/rodauth/webauthn_auth.html.erb +15 -0
  237. data/lib/generators/pu/rodauth/templates/app/views/rodauth/webauthn_autofill.html.erb +10 -0
  238. data/lib/generators/pu/rodauth/templates/app/views/rodauth/webauthn_remove.html.erb +23 -0
  239. data/lib/generators/pu/rodauth/templates/app/views/rodauth/webauthn_setup.html.erb +23 -0
  240. data/lib/generators/pu/rodauth/templates/app/views/rodauth_mailer/email_auth.text.erb +5 -0
  241. data/lib/generators/pu/rodauth/templates/app/views/rodauth_mailer/password_changed.text.erb +2 -0
  242. data/lib/generators/pu/rodauth/templates/app/views/rodauth_mailer/reset_password.text.erb +5 -0
  243. data/lib/generators/pu/rodauth/templates/app/views/rodauth_mailer/reset_password_notify.text.erb +2 -0
  244. data/lib/generators/pu/rodauth/templates/app/views/rodauth_mailer/unlock_account.text.erb +5 -0
  245. data/lib/generators/pu/rodauth/templates/app/views/rodauth_mailer/verify_account.text.erb +4 -0
  246. data/lib/generators/pu/rodauth/templates/app/views/rodauth_mailer/verify_login_change.text.erb +10 -0
  247. data/lib/generators/pu/rodauth/templates/config/initializers/rodauth.rb.tt +3 -0
  248. data/lib/generators/pu/rodauth/templates/db/migrate/create_rodauth.rb.tt +13 -0
  249. data/lib/generators/pu/rodauth/views_generator.rb +125 -0
  250. data/lib/plutonium/auth/public_access.rb +17 -0
  251. data/lib/plutonium/auth/rodauth.rb +35 -0
  252. data/lib/plutonium/auth.rb +12 -0
  253. data/lib/plutonium/config.rb +11 -0
  254. data/lib/plutonium/core/.DS_Store +0 -0
  255. data/lib/plutonium/core/action.rb +46 -0
  256. data/lib/plutonium/core/actions/basic_action.rb +16 -0
  257. data/lib/plutonium/core/actions/collection.rb +33 -0
  258. data/lib/plutonium/core/actions/destroy_action.rb +21 -0
  259. data/lib/plutonium/core/actions/edit_action.rb +19 -0
  260. data/lib/plutonium/core/actions/interactive_action.rb +64 -0
  261. data/lib/plutonium/core/actions/new_action.rb +18 -0
  262. data/lib/plutonium/core/actions/show_action.rb +17 -0
  263. data/lib/plutonium/core/actions.rb +17 -0
  264. data/lib/plutonium/core/app_controller.rb +121 -0
  265. data/lib/plutonium/core/autodiscovery/discoverer.rb +15 -0
  266. data/lib/plutonium/core/autodiscovery/input_discoverer.rb +33 -0
  267. data/lib/plutonium/core/autodiscovery/renderer_discoverer.rb +33 -0
  268. data/lib/plutonium/core/autodiscovery.rb +13 -0
  269. data/lib/plutonium/core/controllers/authorizable.rb +56 -0
  270. data/lib/plutonium/core/controllers/bootable.rb +44 -0
  271. data/lib/plutonium/core/controllers/crud_actions.rb +128 -0
  272. data/lib/plutonium/core/controllers/entity_scoping.rb +69 -0
  273. data/lib/plutonium/core/controllers/interactive_actions.rb +210 -0
  274. data/lib/plutonium/core/controllers/presentable.rb +59 -0
  275. data/lib/plutonium/core/controllers.rb +16 -0
  276. data/lib/plutonium/core/definers/action_definer.rb +25 -0
  277. data/lib/plutonium/core/definers/field_definer.rb +19 -0
  278. data/lib/plutonium/core/definers/input_definer.rb +37 -0
  279. data/lib/plutonium/core/definers/renderer_definer.rb +35 -0
  280. data/lib/plutonium/core/definers.rb +14 -0
  281. data/lib/plutonium/core/fields/inputs/association_input.rb +26 -0
  282. data/lib/plutonium/core/fields/inputs/basic_input.rb +42 -0
  283. data/lib/plutonium/core/fields/inputs/belongs_to_input.rb +15 -0
  284. data/lib/plutonium/core/fields/inputs/factory.rb +58 -0
  285. data/lib/plutonium/core/fields/inputs/has_many_input.rb +15 -0
  286. data/lib/plutonium/core/fields/inputs/noop_input.rb +19 -0
  287. data/lib/plutonium/core/fields/inputs.rb +18 -0
  288. data/lib/plutonium/core/fields/renderers/association_renderer.rb +25 -0
  289. data/lib/plutonium/core/fields/renderers/basic_renderer.rb +27 -0
  290. data/lib/plutonium/core/fields/renderers/factory.rb +52 -0
  291. data/lib/plutonium/core/fields/renderers.rb +15 -0
  292. data/lib/plutonium/core/fields.rb +12 -0
  293. data/lib/plutonium/core/ui/collection.rb +14 -0
  294. data/lib/plutonium/core/ui/detail.rb +11 -0
  295. data/lib/plutonium/core/ui/form.rb +11 -0
  296. data/lib/plutonium/core/ui.rb +13 -0
  297. data/lib/plutonium/core.rb +16 -0
  298. data/lib/plutonium/helpers/action_buttons_helper.rb +32 -0
  299. data/lib/plutonium/helpers/application_helper.rb +22 -0
  300. data/lib/plutonium/helpers/attachment_helper.rb +62 -0
  301. data/lib/plutonium/helpers/content_helper.rb +66 -0
  302. data/lib/plutonium/helpers/display_helper.rb +83 -0
  303. data/lib/plutonium/helpers/form_helper.rb +24 -0
  304. data/lib/plutonium/helpers/menu_helper.rb +69 -0
  305. data/lib/plutonium/helpers/pagination_helper.rb +9 -0
  306. data/lib/plutonium/helpers/turbo_helper.rb +13 -0
  307. data/lib/plutonium/helpers/turbo_stream_actions_helper.rb +9 -0
  308. data/lib/plutonium/helpers.rb +31 -0
  309. data/lib/plutonium/initializers/TODO +2 -0
  310. data/lib/plutonium/initializers/pagy.rb +5 -0
  311. data/lib/plutonium/initializers/patches.rb +2 -0
  312. data/lib/plutonium/initializers/rabl.rb +60 -0
  313. data/lib/plutonium/initializers/simple_form.rb +405 -0
  314. data/lib/plutonium/lib/after_commit.rb +34 -0
  315. data/lib/plutonium/lib/bit_flags.rb +36 -0
  316. data/lib/plutonium/packaging/app.rb +125 -0
  317. data/lib/plutonium/packaging/feature.rb +18 -0
  318. data/lib/plutonium/packaging/package.rb +22 -0
  319. data/lib/plutonium/packaging.rb +9 -0
  320. data/lib/plutonium/policy/initializer.rb +22 -0
  321. data/lib/plutonium/policy/scope.rb +19 -0
  322. data/lib/plutonium/policy.rb +8 -0
  323. data/lib/plutonium/preserved__/field.rb +65 -0
  324. data/lib/plutonium/preserved__/input.rb +93 -0
  325. data/lib/plutonium/reactor/core.rb +61 -0
  326. data/lib/plutonium/reactor/resource_context.rb +15 -0
  327. data/lib/plutonium/reactor/resource_controller.rb +108 -0
  328. data/lib/plutonium/reactor/resource_interaction.rb +8 -0
  329. data/lib/plutonium/reactor/resource_policy.rb +105 -0
  330. data/lib/plutonium/reactor/resource_presenter.rb +42 -0
  331. data/lib/plutonium/reactor/resource_record.rb +123 -0
  332. data/lib/plutonium/reactor.rb +13 -0
  333. data/lib/plutonium/refinements/parameter_refinements.rb +26 -0
  334. data/lib/plutonium/simple_form_components/attachment_component.rb +77 -0
  335. data/lib/plutonium/simple_form_components/input_group_component.rb +14 -0
  336. data/lib/plutonium/version.rb +3 -0
  337. data/lib/plutonium.rb +31 -0
  338. data/plutonium.gemspec +47 -0
  339. data/public/.keep +0 -0
  340. data/public/plutonium-assets/application.css +24280 -0
  341. data/public/plutonium-assets/application.js +31420 -0
  342. data/public/plutonium-assets/fonts/bootstrap-icons.woff +0 -0
  343. data/public/plutonium-assets/fonts/bootstrap-icons.woff2 +0 -0
  344. data/public/plutonium-assets/logo.png +0 -0
  345. data/sig/plutonium.rbs +4 -0
  346. metadata +519 -0
@@ -0,0 +1,405 @@
1
+ require "simple_form"
2
+
3
+ # Register components
4
+ Dir[Plutonium.lib_root.join("simple_form_components", "*.rb")].each { |component| require component }
5
+
6
+ # Use this setup block to configure all options available in SimpleForm.
7
+ SimpleForm.setup do |config|
8
+ # Tell browsers whether to use the native HTML5 validations (novalidate form option).
9
+ config.browser_validations = true
10
+
11
+ # Custom mappings for input types. This should be a hash containing a regexp
12
+
13
+ # Disable country select
14
+ config.input_mappings = {/country/ => :select}
15
+
16
+ # Default class for buttons
17
+ config.button_class = "btn"
18
+
19
+ # Define the default class of the input wrapper of the boolean input.
20
+ config.boolean_label_class = "form-check-label"
21
+
22
+ # How the label text should be generated altogether with the required text.
23
+ config.label_text = ->(label, required, _explicit_label) { "#{label} #{required}" }
24
+
25
+ # Define the way to render check boxes / radio buttons with labels.
26
+ config.boolean_style = :inline
27
+
28
+ # You can wrap each item in a collection of radio/check boxes with a tag
29
+ config.item_wrapper_tag = :div
30
+
31
+ # Defines if the default input wrapper class should be included in radio
32
+ # collection wrappers.
33
+ config.include_default_input_wrapper_class = false
34
+
35
+ # CSS class to add for error notification helper.
36
+ config.error_notification_class = "alert alert-danger"
37
+
38
+ # Method used to tidy up errors. Specify any Rails Array method.
39
+ # :first lists the first message for each field.
40
+ # :to_sentence to list all errors for each field.
41
+ config.error_method = :to_sentence
42
+
43
+ # add validation classes to `input_field`
44
+ config.input_field_error_class = "is-invalid"
45
+ config.input_field_valid_class = "is-valid"
46
+
47
+ # vertical forms
48
+ #
49
+ # vertical default_wrapper
50
+ config.wrappers :vertical_form, class: "mb-3" do |b|
51
+ b.use :html5
52
+ b.use :placeholder
53
+ b.use :maxlength
54
+ b.use :minlength
55
+ b.optional :pattern
56
+ b.use :min_max
57
+ b.optional :readonly
58
+ b.use :label, class: "form-label"
59
+ b.use :input, class: "form-control", error_class: "is-invalid", valid_class: "is-valid"
60
+ b.use :full_error, wrap_with: {class: "invalid-feedback"}
61
+ b.use :hint, wrap_with: {class: "form-text"}
62
+ end
63
+
64
+ # vertical input for boolean
65
+ config.wrappers :vertical_boolean, tag: "fieldset", class: "mb-3" do |b|
66
+ b.use :html5
67
+ b.optional :readonly
68
+ b.wrapper :form_check_wrapper, class: "form-check" do |bb|
69
+ bb.use :input, class: "form-check-input", error_class: "is-invalid", valid_class: "is-valid"
70
+ bb.use :label, class: "form-check-label"
71
+ bb.use :full_error, wrap_with: {class: "invalid-feedback"}
72
+ bb.use :hint, wrap_with: {class: "form-text"}
73
+ end
74
+ end
75
+
76
+ # vertical input for radio buttons and check boxes
77
+ config.wrappers :vertical_collection, item_wrapper_class: "form-check", item_label_class: "form-check-label",
78
+ tag: "fieldset", class: "mb-3" do |b|
79
+ b.use :html5
80
+ b.optional :readonly
81
+ b.use :label, class: "form-label"
82
+ b.use :input, class: "form-check-input", error_class: "is-invalid", valid_class: "is-valid"
83
+ b.use :full_error, wrap_with: {class: "invalid-feedback d-block"}
84
+ b.use :hint, wrap_with: {class: "form-text"}
85
+ end
86
+
87
+ # vertical input for inline radio buttons and check boxes
88
+ config.wrappers :vertical_collection_inline, item_wrapper_class: "form-check form-check-inline",
89
+ item_label_class: "form-check-label", tag: "fieldset", class: "mb-3" do |b|
90
+ b.use :html5
91
+ b.optional :readonly
92
+ b.wrapper :legend_tag, tag: "legend", class: "col-form-label pt-0" do |ba|
93
+ ba.use :label_text
94
+ end
95
+ b.use :input, class: "form-check-input", error_class: "is-invalid", valid_class: "is-valid"
96
+ b.use :full_error, wrap_with: {class: "invalid-feedback d-block"}
97
+ b.use :hint, wrap_with: {class: "form-text"}
98
+ end
99
+
100
+ # vertical file input
101
+ config.wrappers :vertical_file, class: "mb-3" do |b|
102
+ b.use :html5
103
+ b.use :placeholder
104
+ b.optional :maxlength
105
+ b.optional :minlength
106
+ b.optional :readonly
107
+ b.use :label, class: "form-label"
108
+ b.wrapper tag: "div", html: {style: "display: flex; flex-direction: column-reverse;"} do |ba|
109
+ ba.optional :attachment
110
+ ba.wrapper tag: "div" do |bc|
111
+ bc.use :input, class: "form-control", error_class: "is-invalid", valid_class: "is-valid"
112
+ bc.use :full_error, wrap_with: {class: "invalid-feedback"}
113
+ bc.use :hint, wrap_with: {class: "form-text"}
114
+ end
115
+ end
116
+ end
117
+
118
+ # vertical select input
119
+ config.wrappers :vertical_select, class: "mb-3" do |b|
120
+ b.use :html5
121
+ b.optional :readonly
122
+ b.use :label, class: "form-label"
123
+ b.use :input, class: "form-select", error_class: "is-invalid", valid_class: "is-valid"
124
+ b.use :full_error, wrap_with: {class: "invalid-feedback"}
125
+ b.use :hint, wrap_with: {class: "form-text"}
126
+ end
127
+
128
+ # vertical multi select
129
+ config.wrappers :vertical_multi_select, class: "mb-3" do |b|
130
+ b.use :html5
131
+ b.optional :readonly
132
+ b.use :label, class: "form-label"
133
+ b.wrapper class: "d-flex flex-row justify-content-between align-items-center" do |ba|
134
+ ba.use :input, class: "form-select mx-1", error_class: "is-invalid", valid_class: "is-valid"
135
+ end
136
+ b.use :full_error, wrap_with: {class: "invalid-feedback d-block"}
137
+ b.use :hint, wrap_with: {class: "form-text"}
138
+ end
139
+
140
+ # vertical range input
141
+ config.wrappers :vertical_range, class: "mb-3" do |b|
142
+ b.use :html5
143
+ b.use :placeholder
144
+ b.optional :readonly
145
+ b.optional :step
146
+ b.use :label, class: "form-label"
147
+ b.use :input, class: "form-range", error_class: "is-invalid", valid_class: "is-valid"
148
+ b.use :full_error, wrap_with: {class: "invalid-feedback"}
149
+ b.use :hint, wrap_with: {class: "form-text"}
150
+ end
151
+
152
+ # horizontal forms
153
+ #
154
+ # horizontal default_wrapper
155
+ config.wrappers :horizontal_form, class: "row mb-3" do |b|
156
+ b.use :html5
157
+ b.use :placeholder
158
+ b.use :maxlength
159
+ b.use :minlength
160
+ b.optional :pattern
161
+ b.use :min_max
162
+ b.optional :readonly
163
+ b.use :label, class: "col-sm-3 col-form-label"
164
+ b.wrapper :grid_wrapper, class: "col-sm-9" do |ba|
165
+ ba.use :input, class: "form-control", error_class: "is-invalid", valid_class: "is-valid"
166
+ ba.use :full_error, wrap_with: {class: "invalid-feedback"}
167
+ ba.use :hint, wrap_with: {class: "form-text"}
168
+ end
169
+ end
170
+
171
+ # horizontal input for boolean
172
+ config.wrappers :horizontal_boolean, class: "row mb-3" do |b|
173
+ b.use :html5
174
+ b.optional :readonly
175
+ b.wrapper :grid_wrapper, class: "col-sm-9 offset-sm-3" do |wr|
176
+ wr.wrapper :form_check_wrapper, class: "form-check" do |bb|
177
+ bb.use :input, class: "form-check-input", error_class: "is-invalid", valid_class: "is-valid"
178
+ bb.use :label, class: "form-check-label"
179
+ bb.use :full_error, wrap_with: {class: "invalid-feedback"}
180
+ bb.use :hint, wrap_with: {class: "form-text"}
181
+ end
182
+ end
183
+ end
184
+
185
+ # horizontal input for radio buttons and check boxes
186
+ config.wrappers :horizontal_collection, item_wrapper_class: "form-check", item_label_class: "form-check-label",
187
+ class: "row mb-3" do |b|
188
+ b.use :html5
189
+ b.optional :readonly
190
+ b.use :label, class: "col-sm-3 col-form-label pt-0"
191
+ b.wrapper :grid_wrapper, class: "col-sm-9" do |ba|
192
+ ba.use :input, class: "form-check-input", error_class: "is-invalid", valid_class: "is-valid"
193
+ ba.use :full_error, wrap_with: {class: "invalid-feedback d-block"}
194
+ ba.use :hint, wrap_with: {class: "form-text"}
195
+ end
196
+ end
197
+
198
+ # horizontal input for inline radio buttons and check boxes
199
+ config.wrappers :horizontal_collection_inline, item_wrapper_class: "form-check form-check-inline",
200
+ item_label_class: "form-check-label", class: "row mb-3" do |b|
201
+ b.use :html5
202
+ b.optional :readonly
203
+ b.use :label, class: "col-sm-3 col-form-label pt-0"
204
+ b.wrapper :grid_wrapper, class: "col-sm-9" do |ba|
205
+ ba.use :input, class: "form-check-input", error_class: "is-invalid", valid_class: "is-valid"
206
+ ba.use :full_error, wrap_with: {class: "invalid-feedback d-block"}
207
+ ba.use :hint, wrap_with: {class: "form-text"}
208
+ end
209
+ end
210
+
211
+ # horizontal file input
212
+ config.wrappers :horizontal_file, class: "row mb-3" do |b|
213
+ b.use :html5
214
+ b.use :placeholder
215
+ b.optional :maxlength
216
+ b.optional :minlength
217
+ b.optional :readonly
218
+ b.use :label, class: "col-sm-3 col-form-label"
219
+ b.wrapper tag: "div", html: {style: "display: flex; flex-direction: column-reverse;"} do |ba|
220
+ ba.optional :attachment
221
+ ba.wrapper :grid_wrapper, class: "col-sm-9" do |bc|
222
+ bc.use :input, class: "form-control", error_class: "is-invalid", valid_class: "is-valid"
223
+ bc.use :full_error, wrap_with: {class: "invalid-feedback"}
224
+ bc.use :hint, wrap_with: {class: "form-text"}
225
+ end
226
+ end
227
+ end
228
+
229
+ # horizontal select input
230
+ config.wrappers :horizontal_select, class: "row mb-3" do |b|
231
+ b.use :html5
232
+ b.optional :readonly
233
+ b.use :label, class: "col-sm-3 col-form-label"
234
+ b.wrapper :grid_wrapper, class: "col-sm-9" do |ba|
235
+ ba.use :input, class: "form-select", error_class: "is-invalid", valid_class: "is-valid"
236
+ ba.use :full_error, wrap_with: {class: "invalid-feedback"}
237
+ ba.use :hint, wrap_with: {class: "form-text"}
238
+ end
239
+ end
240
+
241
+ # horizontal multi select
242
+ config.wrappers :horizontal_multi_select, class: "row mb-3" do |b|
243
+ b.use :html5
244
+ b.optional :readonly
245
+ b.use :label, class: "col-sm-3 col-form-label"
246
+ b.wrapper :grid_wrapper, class: "col-sm-9" do |ba|
247
+ ba.wrapper class: "d-flex flex-row justify-content-between align-items-center" do |bb|
248
+ bb.use :input, class: "form-select mx-1", error_class: "is-invalid", valid_class: "is-valid"
249
+ end
250
+ ba.use :full_error, wrap_with: {class: "invalid-feedback d-block"}
251
+ ba.use :hint, wrap_with: {class: "form-text"}
252
+ end
253
+ end
254
+
255
+ # horizontal range input
256
+ config.wrappers :horizontal_range, class: "row mb-3" do |b|
257
+ b.use :html5
258
+ b.use :placeholder
259
+ b.optional :readonly
260
+ b.optional :step
261
+ b.use :label, class: "col-sm-3 col-form-label pt-0"
262
+ b.wrapper :grid_wrapper, class: "col-sm-9" do |ba|
263
+ ba.use :input, class: "form-range", error_class: "is-invalid", valid_class: "is-valid"
264
+ ba.use :full_error, wrap_with: {class: "invalid-feedback"}
265
+ ba.use :hint, wrap_with: {class: "form-text"}
266
+ end
267
+ end
268
+
269
+ # inline forms
270
+ #
271
+ # inline default_wrapper
272
+ config.wrappers :inline_form, class: "col-12" do |b|
273
+ b.use :html5
274
+ b.use :placeholder
275
+ b.use :maxlength
276
+ b.use :minlength
277
+ b.optional :pattern
278
+ b.use :min_max
279
+ b.optional :readonly
280
+ b.use :label, class: "visually-hidden"
281
+
282
+ b.use :input, class: "form-control", error_class: "is-invalid", valid_class: "is-valid"
283
+ b.use :error, wrap_with: {class: "invalid-feedback"}
284
+ b.optional :hint, wrap_with: {class: "form-text"}
285
+ end
286
+
287
+ # inline input for boolean
288
+ config.wrappers :inline_boolean, class: "col-12" do |b|
289
+ b.use :html5
290
+ b.optional :readonly
291
+ b.wrapper :form_check_wrapper, class: "form-check" do |bb|
292
+ bb.use :input, class: "form-check-input", error_class: "is-invalid", valid_class: "is-valid"
293
+ bb.use :label, class: "form-check-label"
294
+ bb.use :error, wrap_with: {class: "invalid-feedback"}
295
+ bb.optional :hint, wrap_with: {class: "form-text"}
296
+ end
297
+ end
298
+
299
+ # bootstrap custom forms
300
+ #
301
+ # custom input switch for boolean
302
+ config.wrappers :custom_boolean_switch, class: "mb-3" do |b|
303
+ b.use :html5
304
+ b.optional :readonly
305
+ b.wrapper :form_check_wrapper, tag: "div", class: "form-check form-switch" do |bb|
306
+ bb.use :input, class: "form-check-input", error_class: "is-invalid", valid_class: "is-valid"
307
+ bb.use :label, class: "form-check-label"
308
+ bb.use :full_error, wrap_with: {tag: "div", class: "invalid-feedback"}
309
+ bb.use :hint, wrap_with: {class: "form-text"}
310
+ end
311
+ end
312
+
313
+ # Input Group - custom component
314
+ # see example app and config at https://github.com/heartcombo/simple_form-bootstrap
315
+ config.wrappers :input_group, class: "mb-3" do |b|
316
+ b.use :html5
317
+ b.use :placeholder
318
+ b.use :maxlength
319
+ b.use :minlength
320
+ b.optional :pattern
321
+ b.use :min_max
322
+ b.optional :readonly
323
+ b.use :label, class: "form-label"
324
+ b.wrapper :input_group_tag, class: "input-group" do |ba|
325
+ ba.optional :prepend
326
+ ba.use :input, class: "form-control", error_class: "is-invalid", valid_class: "is-valid"
327
+ ba.optional :append
328
+ ba.use :full_error, wrap_with: {class: "invalid-feedback"}
329
+ end
330
+ b.use :hint, wrap_with: {class: "form-text"}
331
+ end
332
+
333
+ # Floating Labels form
334
+ #
335
+ # floating labels default_wrapper
336
+ config.wrappers :floating_labels_form, class: "form-floating mb-3" do |b|
337
+ b.use :html5
338
+ b.use :placeholder
339
+ b.use :maxlength
340
+ b.use :minlength
341
+ b.optional :pattern
342
+ b.use :min_max
343
+ b.optional :readonly
344
+ b.use :input, class: "form-control", error_class: "is-invalid", valid_class: "is-valid"
345
+ b.use :label
346
+ b.use :full_error, wrap_with: {class: "invalid-feedback"}
347
+ b.use :hint, wrap_with: {class: "form-text"}
348
+ end
349
+
350
+ # custom multi select
351
+ config.wrappers :floating_labels_select, class: "form-floating mb-3" do |b|
352
+ b.use :html5
353
+ b.optional :readonly
354
+ b.use :input, class: "form-select", error_class: "is-invalid", valid_class: "is-valid"
355
+ b.use :label
356
+ b.use :full_error, wrap_with: {class: "invalid-feedback"}
357
+ b.use :hint, wrap_with: {class: "form-text"}
358
+ end
359
+
360
+ # slim-select
361
+ config.wrappers :slim_select, class: "mb-3" do |b|
362
+ b.optional :placeholder
363
+ b.optional :readonly
364
+ b.use :label, class: "form-label"
365
+ b.use :input, error_class: "is-invalid", valid_class: "is-valid", data: {controller: "slim-select"}
366
+ b.use :full_error, wrap_with: {class: "invalid-feedback"}
367
+ b.use :hint, wrap_with: {class: "form-text"}
368
+ end
369
+
370
+ # quill
371
+ config.wrappers :quill, class: "mb-3" do |b|
372
+ b.use :label, class: "form-label"
373
+ b.wrapper tag: :div, html: {data: {controller: "quill-editor"}} do |quill|
374
+ quill.wrapper(tag: :div,
375
+ html: {
376
+ data: {quill_editor_target: "editor"}
377
+ }) {}
378
+ quill.use :input, error_class: "is-invalid", valid_class: "is-valid", class: "d-none",
379
+ data: {quill_editor_target: "input"}
380
+ quill.use :full_error, wrap_with: {class: "invalid-feedback"}
381
+ end
382
+ b.use :hint, wrap_with: {class: "form-text"}
383
+ end
384
+
385
+ # TODO: this will conflict with existing apps that use simple_form.
386
+ # A workaround would be to ensure their initializer loads after ours.
387
+ # Since this is for will deal with it when we get there
388
+
389
+ # The default wrapper to be used by the FormBuilder.
390
+ config.default_wrapper = :vertical_form
391
+
392
+ # Custom wrappers for input types. This should be a hash containing an input
393
+ # type as key and the wrapper that will be used for all inputs with specified type.
394
+ config.wrapper_mappings = {
395
+ boolean: :vertical_boolean,
396
+ check_boxes: :vertical_collection,
397
+ date: :vertical_multi_select,
398
+ datetime: :vertical_multi_select,
399
+ file: :vertical_file,
400
+ radio_buttons: :vertical_collection,
401
+ range: :vertical_range,
402
+ time: :vertical_multi_select,
403
+ select: :vertical_select
404
+ }
405
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Plutonium
4
+ module Lib
5
+ class AfterCommit
6
+ def initialize(rolled_back: false, &block)
7
+ @rolled_back = rolled_back
8
+ @callback = block
9
+ end
10
+
11
+ def committed!(*)
12
+ @callback.call
13
+ end
14
+
15
+ def before_committed!(*)
16
+ end
17
+
18
+ def rolledback!(*)
19
+ @callback.call if @rolled_back
20
+ end
21
+
22
+ def trigger_transactional_callbacks?
23
+ true
24
+ end
25
+
26
+ class << self
27
+ def execute(rolled_back: false, connection: ActiveRecord::Base.connection, &block)
28
+ connection.transaction_open? ? connection.add_transaction_record(AfterCommit.new(rolled_back: rolled_back, &block)) : yield
29
+ nil
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,36 @@
1
+ module Plutonium
2
+ module Lib
3
+ class BitFlags
4
+ delegate :sum, to: :indices
5
+
6
+ def initialize(*flags)
7
+ @map = flags.each_with_index.map { |flag, index| [flag, 2.pow(index)] }.to_h
8
+ end
9
+
10
+ def set?(value, *flags)
11
+ check = bits(*flags)
12
+ value & check == check
13
+ end
14
+
15
+ def extract(value)
16
+ @map.select { |_flag, bit| value & bit == bit }.keys
17
+ end
18
+
19
+ def [](*flags)
20
+ bits(*flags)
21
+ end
22
+
23
+ def bits(*flags)
24
+ @map.slice(*flags).values.sum
25
+ end
26
+
27
+ def flags
28
+ @flags ||= @map.keys
29
+ end
30
+
31
+ def indices
32
+ @indices ||= @map.values
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,125 @@
1
+ module Plutonium
2
+ module Packaging
3
+ module App
4
+ extend ActiveSupport::Concern
5
+ include Package
6
+
7
+ included do
8
+ isolate_namespace to_s.deconstantize.constantize
9
+ end
10
+
11
+ class_methods do
12
+ attr_reader :scoped_entity_class, :scoped_entity_param_key, :scoped_entity_strategy
13
+
14
+ def scope_to_entity(entity_class, param_key: nil, strategy: :path)
15
+ @scoped_entity_class = entity_class
16
+ @scoped_entity_strategy = strategy
17
+ @scoped_entity_param_key = param_key || entity_class.model_name.singular_route_key.to_sym
18
+ end
19
+
20
+ def scoped_to_entity?
21
+ scoped_entity_class.present?
22
+ end
23
+
24
+ def initialize_register!
25
+ # this exists solely to support hot reloads
26
+ # if the user has modified the register especially if they removed a registration, we have no way of telling
27
+ # so instead we start over
28
+ @resource_register = []
29
+ end
30
+
31
+ def register_resource(resource)
32
+ @resource_register.append resource
33
+ end
34
+
35
+ def resource_register
36
+ @resource_register || []
37
+ end
38
+
39
+ def registered_resource_route_key_lookup
40
+ @registered_resource_route_key_lookup = resource_register.map { |resource|
41
+ [resource.model_name.singular_route_key.to_sym, resource]
42
+ }.to_h
43
+ end
44
+
45
+ def draw_resource_routes
46
+ registered_resources = resource_register
47
+ scoped_entity_param_key = self.scoped_entity_param_key
48
+ routes.draw do
49
+ shared_resource_concerns = [:interactive_resource_actions] # TODO: make this a config parameter
50
+ concern :interactive_resource_actions do
51
+ # these concerns power the interactive actions feature
52
+ member do
53
+ get "record_actions/:interactive_action", action: :begin_interactive_resource_record_action,
54
+ as: :interactive_resource_record_action
55
+ post "record_actions/:interactive_action", action: :commit_interactive_resource_record_action
56
+ end
57
+
58
+ collection do
59
+ get "collection_actions/:interactive_action", action: :begin_interactive_resource_collection_action,
60
+ as: :interactive_resource_collection_action
61
+ post "collection_actions/:interactive_action", action: :commit_interactive_resource_collection_action
62
+
63
+ get "recordless_actions/:interactive_action", action: :begin_interactive_resource_recordless_action,
64
+ as: :interactive_resource_recordless_action
65
+ post "recordless_actions/:interactive_action", action: :commit_interactive_resource_recordless_action
66
+ end
67
+ end
68
+
69
+ resource_route_names = []
70
+ resource_route_opts_lookup = {}
71
+ # for each of our registered resources, we are registering the routes required
72
+ registered_resources.each do |resource|
73
+ resource_name = resource.to_s # Deeply::Namespaced::ResourceModel
74
+ resource_controller = resource_name.pluralize.underscore # deeply/namespaced/resource_models
75
+ resource_route = resource.model_name.plural # deeply_namespaced_resource_models
76
+ resource_route_name = :"#{resource_route}_routes" # deeply_namespaced_resource_models_routes
77
+
78
+ resource_route_opts = {}
79
+ # rails is not smart enough to infer Deeply::Namespaced::ResourceModelsController from deeply_namespaced_resource_models
80
+ # since we are heavy on namespaces, we choose to be explicit to guarantee there is no confusion
81
+ resource_route_opts[:controller] = resource_controller
82
+ # using collection for path is much nicer than the alternative
83
+ # e.g. deeply/namespaced/resource_models vs deeply_namespaced_resource_models
84
+ resource_route_opts[:path] = resource.model_name.collection
85
+ resource_route_opts_lookup[resource_route] = resource_route_opts
86
+
87
+ # defining our resources with concerns allows us to defer materializing till later,
88
+ # ensuring that resource_route_opts_lookup is populated
89
+ concern resource_route_name do
90
+ resources resource_route, **resource_route_opts, concerns: shared_resource_concerns do
91
+ nested_resources_route_opts = resource_route_opts_lookup.slice(*resource.has_many_association_routes)
92
+ nested_resources_route_opts.each do |nested_resource_route, nested_resource_route_opts|
93
+ resources nested_resource_route, **nested_resource_route_opts, concerns: shared_resource_concerns
94
+ end
95
+ end
96
+ end
97
+ resource_route_names << resource_route_name
98
+ end
99
+
100
+ # materialize our routes using a scope
101
+ # if the app is scoped to an entity, ensure that the expected route param and url helper prefix are specified.
102
+
103
+ # path => /:entity/deeply/namespaced/resource_models/:deeply_namespaced_resource_model_id/
104
+ # helper => entity_deeply_namespaced_resource_models_path
105
+ scope_name = scoped_entity_param_key.present? ? ":#{scoped_entity_param_key}" : ""
106
+
107
+ # path => /deeply/namespaced/resource_models/:deeply_namespaced_resource_model_id/
108
+ # helper => deeply_namespaced_resource_models_path
109
+ scope_options = scoped_entity_param_key.present? ? {as: scoped_entity_param_key} : {}
110
+
111
+ scope scope_name, scope_options do
112
+ # we have to reverse sort our resource routes in order to prevent routing conflicts
113
+ # e.g. /blogs/1 and blogs/comments cause an issue if Blog is registered before Blogs::Comment
114
+ # attempting to load blogs/comments routes to blogs/:id which fails with a 404 since BlogsController
115
+ # essentially performs a Blog.find('comments')
116
+ # since the route names for these 2 will be 'blogs' and 'blog_comments',
117
+ # reverse sorting ensures that blog_comments is registered first, preventing the issue described above
118
+ concerns resource_route_names.sort.reverse
119
+ end
120
+ end
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,18 @@
1
+ module Plutonium
2
+ module Packaging
3
+ module Feature
4
+ extend ActiveSupport::Concern
5
+ include Package
6
+
7
+ included do
8
+ initializer :append_migrations do |app|
9
+ unless app.root.to_s.match root.to_s
10
+ config.paths["db/migrate"].expanded.each do |expanded_path|
11
+ app.config.paths["db/migrate"] << expanded_path
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,22 @@
1
+ module Plutonium
2
+ module Packaging
3
+ module Package
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ # prevent this package from being added to the view lookup
8
+ # since we need finer control over how views are resolved.
9
+ # view lookup configuration is handled at the controller level
10
+ config.before_configuration do
11
+ # this touches the internals of rails, but I could not find a good way of doing this
12
+ # we get the initializer instance and set the block property to a noop
13
+ # There is no error handling, to ensure we know when it breaks.
14
+ add_view_paths_initializer = Rails.application.initializers.find do |a|
15
+ a.context_class == self && a.name.to_s == "add_view_paths"
16
+ end
17
+ add_view_paths_initializer.instance_variable_set(:@block, ->(app) {})
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,9 @@
1
+ module Plutonium
2
+ module Packaging
3
+ extend ActiveSupport::Autoload
4
+
5
+ autoload :App
6
+ autoload :Feature
7
+ autoload :Package
8
+ end
9
+ end
@@ -0,0 +1,22 @@
1
+ require "pundit"
2
+
3
+ module Plutonium
4
+ module Policy
5
+ module Initializer
6
+ def initialize(context, record)
7
+ authorize!(context)
8
+
9
+ @context = context
10
+ @record = record
11
+ end
12
+
13
+ private
14
+
15
+ attr_reader :context, :record
16
+
17
+ def authorize!(context)
18
+ raise Pundit::NotAuthorizedError, "must be logged in" unless context&.user
19
+ end
20
+ end
21
+ end
22
+ end