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,19 @@
1
+ module Plutonium
2
+ module Core
3
+ module Definers
4
+ module FieldDefiner
5
+ extend ActiveSupport::Concern
6
+
7
+ include InputDefiner
8
+ include RendererDefiner
9
+
10
+ private
11
+
12
+ def define_field(name, type: nil, input: nil, renderer: nil, input_options: {}, renderer_options: {})
13
+ define_input(name, type:, input:, **input_options)
14
+ define_renderer(name, type:, renderer:, **renderer_options)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,37 @@
1
+ module Plutonium
2
+ module Core
3
+ module Definers
4
+ module InputDefiner
5
+ extend ActiveSupport::Concern
6
+ include Plutonium::Core::Autodiscovery::InputDiscoverer
7
+
8
+ def defined_inputs_for(names)
9
+ (names - input_definitions.keys).each do |name|
10
+ define_input(name, input: autodiscover_input(name))
11
+ end
12
+ input_definitions.slice(*names)
13
+ end
14
+
15
+ private
16
+
17
+ def input_definitions = @input_definitions ||= {}
18
+
19
+ def define_input(name, input: nil, type: nil, **options)
20
+ input_definitions[name] = if input.present?
21
+ input
22
+ elsif type.present?
23
+ Plutonium::Core::Fields::Inputs.build(name, type:, **options)
24
+ elsif options.present?
25
+ Plutonium::Core::Fields::Inputs::Factory.for_resource_attribute(context.resource_class, name, **options)
26
+ else
27
+ autodiscover_input(name)
28
+ end
29
+ end
30
+
31
+ def input_defined?(name)
32
+ input_definitions.key? name
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,35 @@
1
+ module Plutonium
2
+ module Core
3
+ module Definers
4
+ module RendererDefiner
5
+ extend ActiveSupport::Concern
6
+ include Plutonium::Core::Autodiscovery::RendererDiscoverer
7
+
8
+ def defined_renderers_for(names)
9
+ (names - renderer_definitions.keys).each do |name|
10
+ define_renderer(name, renderer: autodiscover_renderer(name))
11
+ end
12
+ renderer_definitions.slice(*names)
13
+ end
14
+
15
+ private
16
+
17
+ def renderer_definitions = @renderer_definitions ||= {}
18
+
19
+ def define_renderer(name, renderer: nil, type: nil, **options)
20
+ renderer_definitions[name] = if renderer.present?
21
+ renderer
22
+ elsif type.present? || options.present?
23
+ Plutonium::Core::Fields::Renderers::Factory.for_resource_attribute(context.resource_class, name, type:, **options)
24
+ else
25
+ autodiscover_renderer(name)
26
+ end
27
+ end
28
+
29
+ def renderer_defined?(name)
30
+ renderer_definitions.key? name
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,14 @@
1
+ module Plutonium
2
+ module Core
3
+ module Definers
4
+ extend ActiveSupport::Autoload
5
+
6
+ eager_autoload do
7
+ autoload :ActionDefiner
8
+ autoload :FieldDefiner
9
+ autoload :InputDefiner
10
+ autoload :RendererDefiner
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,26 @@
1
+ module Plutonium
2
+ module Core
3
+ module Fields
4
+ module Inputs
5
+ class AssociationInput < BasicInput
6
+ attr_reader :reflection
7
+
8
+ def initialize(name, reflection:, **user_options)
9
+ @reflection = reflection
10
+ super(name, **user_options)
11
+ end
12
+
13
+ def render(f, record)
14
+ f.association name, **options
15
+ end
16
+
17
+ private
18
+
19
+ def param
20
+ raise NotImplementedError, "#{self.class}#param"
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,42 @@
1
+ module Plutonium
2
+ module Core
3
+ module Fields
4
+ module Inputs
5
+ class BasicInput
6
+ attr_reader :name, :user_options
7
+
8
+ def initialize(name, **user_options)
9
+ @name = name
10
+ @user_options = user_options
11
+ end
12
+
13
+ def render(f, record) = f.input name, **options
14
+
15
+ def collect(params)
16
+ # Handles multi parameter attributes
17
+ # https://www.cookieshq.co.uk/posts/rails-spelunking-date-select
18
+ # https://www.cookieshq.co.uk/posts/multiparameter-attributes
19
+
20
+ # Matches
21
+ # - parameter
22
+ # - parameter(1)
23
+ # - parameter(2)
24
+ # - parameter(1i)
25
+ # - parameter(2f)
26
+ regex = /^#{param}(\(\d+[if]?\))?$/
27
+
28
+ params.select { |key| regex.match? key }
29
+ end
30
+
31
+ protected
32
+
33
+ def input_options = {}
34
+
35
+ def param = name
36
+
37
+ def options = @options ||= input_options.deep_merge(@user_options)
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,15 @@
1
+ module Plutonium
2
+ module Core
3
+ module Fields
4
+ module Inputs
5
+ class BelongsToInput < AssociationInput
6
+ private
7
+
8
+ def param
9
+ (reflection.respond_to?(:options) && reflection.options[:foreign_key]) || :"#{reflection.name}_id"
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,58 @@
1
+ require "simple_form/map_type"
2
+
3
+ module Plutonium
4
+ module Core
5
+ module Fields
6
+ module Inputs
7
+ class Factory
8
+ extend ::SimpleForm::MapType
9
+
10
+ map_type :has_one, to: Plutonium::Core::Fields::Inputs::NoopInput
11
+ map_type :belongs_to, to: Plutonium::Core::Fields::Inputs::BelongsToInput
12
+ map_type :has_many, to: Plutonium::Core::Fields::Inputs::HasManyInput
13
+
14
+ def self.build(name, type:, **)
15
+ mapping = mappings[type] || Plutonium::Core::Fields::Inputs::BasicInput
16
+ mapping.new(name, **)
17
+
18
+ # type ||= :slim_select if options.key? :collection
19
+
20
+ # case type
21
+ # when :belongs_to
22
+ # Plutonium::Core::Fields::Inputs::BelongsToInput.new(name, **)
23
+ # when :has_one
24
+ # Plutonium::Core::Fields::Inputs::NoopInput.new
25
+ # when :has_many
26
+ # Plutonium::Core::Fields::Inputs::HasManyInput.new(name, **)
27
+ # else
28
+ # Plutonium::Core::Fields::Inputs::BasicInput.new(name, **)
29
+ # end
30
+ end
31
+
32
+ def self.for_resource_attribute(resource_class, attr_name, **options)
33
+ type = nil
34
+
35
+ if resource_class.respond_to? :reflect_on_association
36
+ attachment = resource_class.reflect_on_association(:"#{attr_name}_attachment") || \
37
+ resource_class.reflect_on_association(:"#{attr_name}_attachments")
38
+ association = resource_class.reflect_on_association(attr_name)
39
+ end
40
+
41
+ if attachment.present?
42
+ type = :attachment
43
+ options[:multiple] = (attachment.macro == :has_many) unless options.key?(:multiple)
44
+ elsif association.present?
45
+ type = association.macro
46
+ options[:reflection] = association
47
+ elsif (column = resource_class.try(:column_for_attribute, attr_name))
48
+ type = column.type
49
+ options[:multiple] = column.try(:array?) if options[:multiple].nil?
50
+ end
51
+
52
+ build(attr_name, type:, **options)
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,15 @@
1
+ module Plutonium
2
+ module Core
3
+ module Fields
4
+ module Inputs
5
+ class HasManyInput < AssociationInput
6
+ private
7
+
8
+ def param
9
+ :"#{reflection.name.to_s.singularize}_ids"
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,19 @@
1
+ module Plutonium
2
+ module Core
3
+ module Fields
4
+ module Inputs
5
+ class NoopInput
6
+ def initialize(*)
7
+ end
8
+
9
+ def render(f, record)
10
+ end
11
+
12
+ def collect(params)
13
+ {}
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,18 @@
1
+ module Plutonium
2
+ module Core
3
+ module Fields
4
+ module Inputs
5
+ extend ActiveSupport::Autoload
6
+
7
+ eager_autoload do
8
+ autoload :Factory
9
+ autoload :AssociationInput
10
+ autoload :BasicInput
11
+ autoload :BelongsToInput
12
+ autoload :HasManyInput
13
+ autoload :NoopInput
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,25 @@
1
+ module Plutonium
2
+ module Core
3
+ module Fields
4
+ module Renderers
5
+ class AssociationRenderer < BasicRenderer
6
+ attr_reader :reflection
7
+
8
+ def initialize(name, reflection:, **user_options)
9
+ @reflection = reflection
10
+ super(name, **user_options)
11
+ end
12
+
13
+ private
14
+
15
+ def renderer_options
16
+ resource_record = reflection.klass.include? Plutonium::Reactor::ResourceRecord
17
+ {
18
+ helper: resource_record ? :display_association_value : :display_name_of
19
+ }
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,27 @@
1
+ module Plutonium
2
+ module Core
3
+ module Fields
4
+ module Renderers
5
+ class BasicRenderer
6
+ attr_reader :name, :label, :user_options
7
+
8
+ def initialize(name, label:, **user_options)
9
+ @name = name
10
+ @label = label
11
+ @user_options = user_options
12
+ end
13
+
14
+ def render(view_context, record)
15
+ view_context.display_field value: record.send(name), **options
16
+ end
17
+
18
+ def options = @options ||= renderer_options.deep_merge(@user_options)
19
+
20
+ private
21
+
22
+ def renderer_options = {}
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,52 @@
1
+ require "simple_form/map_type"
2
+
3
+ module Plutonium
4
+ module Core
5
+ module Fields
6
+ module Renderers
7
+ class Factory
8
+ extend ::SimpleForm::MapType
9
+
10
+ map_type :belongs_to, :has_one, :has_many, to: Plutonium::Core::Fields::Renderers::AssociationRenderer
11
+
12
+ def self.build(name, type:, **)
13
+ mapping = mappings[type] || Plutonium::Core::Fields::Renderers::BasicRenderer
14
+ mapping.new(name, **)
15
+
16
+ # type ||= :slim_select if options.key? :collection
17
+
18
+ # case type
19
+ # when :belongs_to, :has_one, :has_many
20
+ # Plutonium::Core::Fields::Renderers::AssociationRenderer.new(name, **)
21
+ # else
22
+ # Plutonium::Core::Fields::Renderers::BasicRenderer.new(name, **)
23
+ # end
24
+ end
25
+
26
+ def self.for_resource_attribute(resource_class, attr_name, **options)
27
+ type = nil
28
+ options[:label] ||= resource_class.human_attribute_name(attr_name)
29
+
30
+ if resource_class.respond_to? :reflect_on_association
31
+ attachment = resource_class.reflect_on_association(:"#{attr_name}_attachment") || \
32
+ resource_class.reflect_on_association(:"#{attr_name}_attachments")
33
+ association = resource_class.reflect_on_association(attr_name)
34
+ end
35
+
36
+ if attachment.present?
37
+ type = :attachment
38
+ options[:multiple] = (attachment.macro == :has_many) unless options.key?(:multiple)
39
+ elsif association.present?
40
+ type = association.macro
41
+ options[:reflection] = association
42
+ elsif (column = resource_class.try(:column_for_attribute, attr_name))
43
+ type = column.type
44
+ end
45
+
46
+ build(attr_name, type:, **options)
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,15 @@
1
+ module Plutonium
2
+ module Core
3
+ module Fields
4
+ module Renderers
5
+ extend ActiveSupport::Autoload
6
+
7
+ eager_autoload do
8
+ autoload :Factory
9
+ autoload :BasicRenderer
10
+ autoload :AssociationRenderer
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,12 @@
1
+ module Plutonium
2
+ module Core
3
+ module Fields
4
+ extend ActiveSupport::Autoload
5
+
6
+ eager_autoload do
7
+ autoload :Inputs
8
+ autoload :Renderers
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,14 @@
1
+ module Plutonium
2
+ module Core
3
+ module UI
4
+ Collection = Data.define :resource_class, :records, :fields, :actions, :pagination, :search_object do
5
+ def initialize(
6
+ resource_class:, records: [], fields: {}, actions: Plutonium::Core::Actions::Collection.new,
7
+ pagination: nil, search_object: nil
8
+ )
9
+ super
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,11 @@
1
+ module Plutonium
2
+ module Core
3
+ module UI
4
+ Detail = Data.define :resource_class, :record, :fields, :actions do
5
+ def initialize(resource_class:, record: nil, fields: {}, actions: Plutonium::Core::Actions::Collection.new)
6
+ super
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module Plutonium
2
+ module Core
3
+ module UI
4
+ Form = Data.define :record, :inputs do
5
+ def initialize(record: nil, inputs: {})
6
+ super
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,13 @@
1
+ module Plutonium
2
+ module Core
3
+ module UI
4
+ extend ActiveSupport::Autoload
5
+
6
+ eager_autoload do
7
+ autoload :Collection
8
+ autoload :Detail
9
+ autoload :Form
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,16 @@
1
+ module Plutonium
2
+ module Core
3
+ extend ActiveSupport::Autoload
4
+
5
+ eager_autoload do
6
+ autoload :Action
7
+ autoload :Actions
8
+ autoload :AppController
9
+ autoload :Autodiscovery
10
+ autoload :Controllers
11
+ autoload :Definers
12
+ autoload :Fields
13
+ autoload :UI
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,32 @@
1
+ module Plutonium
2
+ module Helpers
3
+ module ActionButtonsHelper
4
+ def generic_action_button(url, icon:, button_class:, method:, confirm:, turbo_frame:)
5
+ if method == :get
6
+ link_to url, class: button_class, data: {turbo_frame:} do
7
+ tag.i class: "bi bi-#{icon}"
8
+ end
9
+ else
10
+ form_for :action, url:, method:, turbo_frame:,
11
+ html: {class: "d-inline-block", data: {turbo_confirm: confirm}} do
12
+ tag.button class: button_class do
13
+ tag.i class: "bi bi-#{icon}"
14
+ end
15
+ end
16
+ end
17
+ end
18
+
19
+ def toolbar_action_button(url, icon:, button_class: "secondary", method: :get, confirm: nil, turbo_frame: nil)
20
+ button_class = "btn btn-sm btn-outline-#{button_class} toolbar-action-button"
21
+
22
+ generic_action_button(url, icon:, button_class:, method:, confirm:, turbo_frame:)
23
+ end
24
+
25
+ def table_action_button(url, icon:, button_class: "secondary", method: :get, confirm: nil, turbo_frame: nil)
26
+ button_class = "btn btn-sm btn-link text-#{button_class}"
27
+
28
+ generic_action_button(url, icon:, button_class:, method:, confirm:, turbo_frame:)
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,22 @@
1
+ module Plutonium
2
+ module Helpers
3
+ module ApplicationHelper
4
+ # def tooltip(text)
5
+ # text = sanitize text
6
+ # "title=\"#{text}\" data-controller=\"tooltip\" data-bs-title=\"#{text}\"".html_safe
7
+ # end
8
+
9
+ def page_title(title)
10
+ [title.presence, Rails.application.class.module_parent.name].compact.join(" | ")
11
+ end
12
+
13
+ def resource_name(resource_class, count = 1)
14
+ resource_class.model_name.human.pluralize(count)
15
+ end
16
+
17
+ def resource_name_plural(resource_class)
18
+ resource_name resource_class, 2
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,62 @@
1
+ module Plutonium
2
+ module Helpers
3
+ module AttachmentHelper
4
+ def attachment_preview(attachments, **options)
5
+ clamp_content begin
6
+ tag.div class: [options[:identity_class], "attachment-preview-container d-flex flex-wrap gap-1 my-1"],
7
+ data: {controller: "attachment-preview-container"} do
8
+ Array(attachments).each do |attachment|
9
+ next unless attachment.file.present?
10
+
11
+ concat begin
12
+ tag.div class: [options[:identity_class], "attachment-preview d-inline-block text-center"],
13
+ title: attachment.file.original_filename,
14
+ data: {
15
+ controller: "attachment-preview",
16
+ attachment_preview_mime_type_value: attachment.file.mime_type,
17
+ attachment_preview_thumbnail_url_value: attachment.thumbnail_url
18
+ } do
19
+ tag.figure class: "figure my-1", style: "width: 160px;" do
20
+ concat attachment_preview_thumnail(attachment)
21
+ concat begin
22
+ tag.figcaption class: "figure-caption text-truncate" do
23
+ if options[:caption]
24
+ caption = options[:caption].is_a?(String) ? options[:caption] : attachment.file.original_filename
25
+ concat link_to(caption, attachment.file_url, class: "text-decoration-none", target: :blank)
26
+ end
27
+
28
+ if block_given?
29
+ elements = Array(yield attachment).compact
30
+ elements.each { |elem| concat elem }
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+
42
+ def attachment_preview_thumnail(attachment)
43
+ return unless attachment.file.present?
44
+
45
+ # Any changes made here must be reflected in attachment_input_controller#buildPreviewTemplate
46
+
47
+ tag.div class: "d-inline-block img-thumbnail", data: {attachment_preview_target: "thumbnail"} do
48
+ link_body = if attachment.representable?
49
+ image_tag attachment.thumbnail_url, style: "width:100%; height:100%; object-fit: contain;"
50
+ else
51
+ attachment.file.extension.to_s
52
+ end
53
+
54
+ link_to link_body, attachment.file_url, style: "width:150px; height:150px; line-height: 150px;",
55
+ class: "d-block text-decoration-none user-select-none fs-5 font-monospace text-body-secondary",
56
+ target: :blank,
57
+ data: {attachment_preview_target: "thumbnailLink"}
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end