plutonium 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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