plutonium 0.6.2 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (859) hide show
  1. checksums.yaml +4 -4
  2. data/.node-version +1 -0
  3. data/README copy.md +1 -2
  4. data/README.md +25 -5
  5. data/app/assets/css/plutonium.css +3 -0
  6. data/app/assets/icons/flags/ghana.svg +49 -0
  7. data/app/assets/icons/outline/address-book.svg +3 -0
  8. data/app/assets/icons/outline/adjustments-horizontal.svg +3 -0
  9. data/app/assets/icons/outline/adjustments-vertical.svg +3 -0
  10. data/app/assets/icons/outline/align-center.svg +3 -0
  11. data/app/assets/icons/outline/angle-down.svg +3 -0
  12. data/app/assets/icons/outline/angle-left.svg +3 -0
  13. data/app/assets/icons/outline/angle-right.svg +3 -0
  14. data/app/assets/icons/outline/angle-up.svg +3 -0
  15. data/app/assets/icons/outline/annotation.svg +3 -0
  16. data/app/assets/icons/outline/archive-arrow-down.svg +3 -0
  17. data/app/assets/icons/outline/archive.svg +3 -0
  18. data/app/assets/icons/outline/arrow-down-to-bracket.svg +3 -0
  19. data/app/assets/icons/outline/arrow-down.svg +3 -0
  20. data/app/assets/icons/outline/arrow-left-to-bracket.svg +3 -0
  21. data/app/assets/icons/outline/arrow-left.svg +3 -0
  22. data/app/assets/icons/outline/arrow-right-alt.svg +3 -0
  23. data/app/assets/icons/outline/arrow-right-to-bracket.svg +3 -0
  24. data/app/assets/icons/outline/arrow-right.svg +3 -0
  25. data/app/assets/icons/outline/arrow-sort-letters.svg +3 -0
  26. data/app/assets/icons/outline/arrow-up-down.svg +3 -0
  27. data/app/assets/icons/outline/arrow-up-from-bracket.svg +3 -0
  28. data/app/assets/icons/outline/arrow-up-right-down-left.svg +3 -0
  29. data/app/assets/icons/outline/arrow-up-right-from-square.svg +3 -0
  30. data/app/assets/icons/outline/arrow-up.svg +3 -0
  31. data/app/assets/icons/outline/arrows-repeat-count.svg +3 -0
  32. data/app/assets/icons/outline/arrows-repeat.svg +3 -0
  33. data/app/assets/icons/outline/atom.svg +3 -0
  34. data/app/assets/icons/outline/backward-step.svg +3 -0
  35. data/app/assets/icons/outline/badge-check.svg +3 -0
  36. data/app/assets/icons/outline/bars-from-left.svg +3 -0
  37. data/app/assets/icons/outline/bars.svg +3 -0
  38. data/app/assets/icons/outline/bell-active-alt.svg +3 -0
  39. data/app/assets/icons/outline/bell-active.svg +3 -0
  40. data/app/assets/icons/outline/bell-ring.svg +3 -0
  41. data/app/assets/icons/outline/bell.svg +3 -0
  42. data/app/assets/icons/outline/blender-phone.svg +3 -0
  43. data/app/assets/icons/outline/book-open.svg +3 -0
  44. data/app/assets/icons/outline/book.svg +3 -0
  45. data/app/assets/icons/outline/bookmark.svg +3 -0
  46. data/app/assets/icons/outline/brain.svg +3 -0
  47. data/app/assets/icons/outline/briefcase.svg +3 -0
  48. data/app/assets/icons/outline/bug.svg +3 -0
  49. data/app/assets/icons/outline/building.svg +3 -0
  50. data/app/assets/icons/outline/bullhorn.svg +3 -0
  51. data/app/assets/icons/outline/calendar-edit.svg +3 -0
  52. data/app/assets/icons/outline/calendar-month.svg +3 -0
  53. data/app/assets/icons/outline/calendar-plus.svg +3 -0
  54. data/app/assets/icons/outline/calendar-week.svg +3 -0
  55. data/app/assets/icons/outline/camera-photo.svg +4 -0
  56. data/app/assets/icons/outline/caption.svg +3 -0
  57. data/app/assets/icons/outline/caret-down.svg +3 -0
  58. data/app/assets/icons/outline/caret-left.svg +3 -0
  59. data/app/assets/icons/outline/caret-right.svg +3 -0
  60. data/app/assets/icons/outline/caret-sort.svg +3 -0
  61. data/app/assets/icons/outline/caret-up.svg +3 -0
  62. data/app/assets/icons/outline/cart-plus-alt.svg +3 -0
  63. data/app/assets/icons/outline/cart-plus.svg +3 -0
  64. data/app/assets/icons/outline/cart.svg +3 -0
  65. data/app/assets/icons/outline/cash.svg +3 -0
  66. data/app/assets/icons/outline/chart-line-down.svg +3 -0
  67. data/app/assets/icons/outline/chart-line-up.svg +3 -0
  68. data/app/assets/icons/outline/chart-mixed-dollar.svg +3 -0
  69. data/app/assets/icons/outline/chart-mixed.svg +3 -0
  70. data/app/assets/icons/outline/chart-pie.svg +4 -0
  71. data/app/assets/icons/outline/chart.svg +3 -0
  72. data/app/assets/icons/outline/check-circle.svg +3 -0
  73. data/app/assets/icons/outline/check-plus-circle.svg +3 -0
  74. data/app/assets/icons/outline/check.svg +3 -0
  75. data/app/assets/icons/outline/chevron-double-down.svg +3 -0
  76. data/app/assets/icons/outline/chevron-double-left.svg +3 -0
  77. data/app/assets/icons/outline/chevron-double-right.svg +3 -0
  78. data/app/assets/icons/outline/chevron-double-up.svg +3 -0
  79. data/app/assets/icons/outline/chevron-down.svg +3 -0
  80. data/app/assets/icons/outline/chevron-left.svg +3 -0
  81. data/app/assets/icons/outline/chevron-right.svg +3 -0
  82. data/app/assets/icons/outline/chevron-sort.svg +3 -0
  83. data/app/assets/icons/outline/chevron-up.svg +3 -0
  84. data/app/assets/icons/outline/circle-pause.svg +3 -0
  85. data/app/assets/icons/outline/circle-plus.svg +3 -0
  86. data/app/assets/icons/outline/clapperboard-play.svg +3 -0
  87. data/app/assets/icons/outline/clipboard-check.svg +3 -0
  88. data/app/assets/icons/outline/clipboard-list.svg +3 -0
  89. data/app/assets/icons/outline/clipboard.svg +3 -0
  90. data/app/assets/icons/outline/clock.svg +3 -0
  91. data/app/assets/icons/outline/close-circle.svg +3 -0
  92. data/app/assets/icons/outline/close.svg +3 -0
  93. data/app/assets/icons/outline/cloud-arrow-up.svg +3 -0
  94. data/app/assets/icons/outline/code-branch.svg +3 -0
  95. data/app/assets/icons/outline/code-fork.svg +3 -0
  96. data/app/assets/icons/outline/code-merge.svg +3 -0
  97. data/app/assets/icons/outline/code-pull-request.svg +3 -0
  98. data/app/assets/icons/outline/code.svg +3 -0
  99. data/app/assets/icons/outline/cog.svg +4 -0
  100. data/app/assets/icons/outline/column.svg +3 -0
  101. data/app/assets/icons/outline/command.svg +3 -0
  102. data/app/assets/icons/outline/compress.svg +3 -0
  103. data/app/assets/icons/outline/computer-speaker.svg +3 -0
  104. data/app/assets/icons/outline/credit-card.svg +3 -0
  105. data/app/assets/icons/outline/database.svg +3 -0
  106. data/app/assets/icons/outline/desktop-pc.svg +3 -0
  107. data/app/assets/icons/outline/dna.svg +3 -0
  108. data/app/assets/icons/outline/dollar.svg +3 -0
  109. data/app/assets/icons/outline/dots-horizontal.svg +3 -0
  110. data/app/assets/icons/outline/dots-vertical.svg +3 -0
  111. data/app/assets/icons/outline/download.svg +3 -0
  112. data/app/assets/icons/outline/draw-square.svg +3 -0
  113. data/app/assets/icons/outline/edit.svg +3 -0
  114. data/app/assets/icons/outline/envelope-open.svg +3 -0
  115. data/app/assets/icons/outline/envelope.svg +3 -0
  116. data/app/assets/icons/outline/euro.svg +3 -0
  117. data/app/assets/icons/outline/exclamation-circle.svg +3 -0
  118. data/app/assets/icons/outline/expand.svg +3 -0
  119. data/app/assets/icons/outline/eye-slash.svg +3 -0
  120. data/app/assets/icons/outline/eye.svg +4 -0
  121. data/app/assets/icons/outline/face-explode.svg +4 -0
  122. data/app/assets/icons/outline/face-grin-stars.svg +6 -0
  123. data/app/assets/icons/outline/face-grin.svg +3 -0
  124. data/app/assets/icons/outline/face-laugh.svg +3 -0
  125. data/app/assets/icons/outline/file-chart-bar.svg +3 -0
  126. data/app/assets/icons/outline/file-check.svg +3 -0
  127. data/app/assets/icons/outline/file-circle-plus.svg +3 -0
  128. data/app/assets/icons/outline/file-clone.svg +3 -0
  129. data/app/assets/icons/outline/file-code.svg +3 -0
  130. data/app/assets/icons/outline/file-copy-alt.svg +3 -0
  131. data/app/assets/icons/outline/file-copy.svg +3 -0
  132. data/app/assets/icons/outline/file-csv.svg +3 -0
  133. data/app/assets/icons/outline/file-export.svg +3 -0
  134. data/app/assets/icons/outline/file-image.svg +4 -0
  135. data/app/assets/icons/outline/file-import.svg +3 -0
  136. data/app/assets/icons/outline/file-invoice.svg +3 -0
  137. data/app/assets/icons/outline/file-lines.svg +3 -0
  138. data/app/assets/icons/outline/file-music.svg +3 -0
  139. data/app/assets/icons/outline/file-paste.svg +3 -0
  140. data/app/assets/icons/outline/file-pdf.svg +3 -0
  141. data/app/assets/icons/outline/file-pen.svg +3 -0
  142. data/app/assets/icons/outline/file-ppt.svg +3 -0
  143. data/app/assets/icons/outline/file-search.svg +3 -0
  144. data/app/assets/icons/outline/file-shield.svg +3 -0
  145. data/app/assets/icons/outline/file-video.svg +3 -0
  146. data/app/assets/icons/outline/file-word.svg +3 -0
  147. data/app/assets/icons/outline/file-zip.svg +3 -0
  148. data/app/assets/icons/outline/file.svg +3 -0
  149. data/app/assets/icons/outline/filter.svg +3 -0
  150. data/app/assets/icons/outline/fingerprint.svg +3 -0
  151. data/app/assets/icons/outline/fire.svg +3 -0
  152. data/app/assets/icons/outline/flag.svg +3 -0
  153. data/app/assets/icons/outline/folder-arrow-right.svg +3 -0
  154. data/app/assets/icons/outline/folder-duplicate.svg +3 -0
  155. data/app/assets/icons/outline/folder-open.svg +3 -0
  156. data/app/assets/icons/outline/folder-plus.svg +3 -0
  157. data/app/assets/icons/outline/folder.svg +3 -0
  158. data/app/assets/icons/outline/forward-step.svg +3 -0
  159. data/app/assets/icons/outline/forward.svg +3 -0
  160. data/app/assets/icons/outline/gift-box.svg +3 -0
  161. data/app/assets/icons/outline/globe.svg +3 -0
  162. data/app/assets/icons/outline/grid-plus.svg +3 -0
  163. data/app/assets/icons/outline/grid.svg +3 -0
  164. data/app/assets/icons/outline/headphones.svg +3 -0
  165. data/app/assets/icons/outline/heart.svg +3 -0
  166. data/app/assets/icons/outline/home.svg +3 -0
  167. data/app/assets/icons/outline/hourglass.svg +3 -0
  168. data/app/assets/icons/outline/image.svg +3 -0
  169. data/app/assets/icons/outline/inbox-full.svg +3 -0
  170. data/app/assets/icons/outline/inbox.svg +3 -0
  171. data/app/assets/icons/outline/indent.svg +3 -0
  172. data/app/assets/icons/outline/info-circle.svg +3 -0
  173. data/app/assets/icons/outline/keyboard.svg +5 -0
  174. data/app/assets/icons/outline/label.svg +3 -0
  175. data/app/assets/icons/outline/landmark.svg +3 -0
  176. data/app/assets/icons/outline/layers.svg +3 -0
  177. data/app/assets/icons/outline/letter-bold.svg +3 -0
  178. data/app/assets/icons/outline/letter-italic.svg +3 -0
  179. data/app/assets/icons/outline/letter-underline.svg +3 -0
  180. data/app/assets/icons/outline/life-saver.svg +3 -0
  181. data/app/assets/icons/outline/lightbulb.svg +3 -0
  182. data/app/assets/icons/outline/link.svg +3 -0
  183. data/app/assets/icons/outline/list-music.svg +3 -0
  184. data/app/assets/icons/outline/list.svg +3 -0
  185. data/app/assets/icons/outline/lock-open.svg +3 -0
  186. data/app/assets/icons/outline/lock-time.svg +3 -0
  187. data/app/assets/icons/outline/lock.svg +3 -0
  188. data/app/assets/icons/outline/mail-box.svg +3 -0
  189. data/app/assets/icons/outline/map-pin-alt.svg +4 -0
  190. data/app/assets/icons/outline/map-pin.svg +3 -0
  191. data/app/assets/icons/outline/message-caption.svg +3 -0
  192. data/app/assets/icons/outline/message-dots.svg +3 -0
  193. data/app/assets/icons/outline/messages.svg +3 -0
  194. data/app/assets/icons/outline/microphone.svg +3 -0
  195. data/app/assets/icons/outline/minimize.svg +3 -0
  196. data/app/assets/icons/outline/minus.svg +3 -0
  197. data/app/assets/icons/outline/mobile-phone.svg +3 -0
  198. data/app/assets/icons/outline/moon.svg +3 -0
  199. data/app/assets/icons/outline/newspaper.svg +3 -0
  200. data/app/assets/icons/outline/ordered-list.svg +3 -0
  201. data/app/assets/icons/outline/outdent.svg +3 -0
  202. data/app/assets/icons/outline/palette.svg +3 -0
  203. data/app/assets/icons/outline/paper-clip.svg +3 -0
  204. data/app/assets/icons/outline/paper-plane.svg +3 -0
  205. data/app/assets/icons/outline/paragraph.svg +3 -0
  206. data/app/assets/icons/outline/pause.svg +3 -0
  207. data/app/assets/icons/outline/pen-nib.svg +3 -0
  208. data/app/assets/icons/outline/pen.svg +3 -0
  209. data/app/assets/icons/outline/phone.svg +3 -0
  210. data/app/assets/icons/outline/play.svg +3 -0
  211. data/app/assets/icons/outline/plus.svg +3 -0
  212. data/app/assets/icons/outline/printer.svg +3 -0
  213. data/app/assets/icons/outline/profile-card.svg +3 -0
  214. data/app/assets/icons/outline/question-circle.svg +3 -0
  215. data/app/assets/icons/outline/quote.svg +3 -0
  216. data/app/assets/icons/outline/receipt.svg +3 -0
  217. data/app/assets/icons/outline/rectangle-list.svg +3 -0
  218. data/app/assets/icons/outline/redo.svg +3 -0
  219. data/app/assets/icons/outline/refresh.svg +3 -0
  220. data/app/assets/icons/outline/reply-all.svg +3 -0
  221. data/app/assets/icons/outline/reply.svg +3 -0
  222. data/app/assets/icons/outline/restore-window.svg +3 -0
  223. data/app/assets/icons/outline/rocket.svg +3 -0
  224. data/app/assets/icons/outline/ruler-combined.svg +3 -0
  225. data/app/assets/icons/outline/sale-percent.svg +3 -0
  226. data/app/assets/icons/outline/scale-balanced.svg +3 -0
  227. data/app/assets/icons/outline/search.svg +3 -0
  228. data/app/assets/icons/outline/share-all.svg +3 -0
  229. data/app/assets/icons/outline/share-nodes.svg +3 -0
  230. data/app/assets/icons/outline/shield-check.svg +3 -0
  231. data/app/assets/icons/outline/shield.svg +3 -0
  232. data/app/assets/icons/outline/shopping-bag.svg +3 -0
  233. data/app/assets/icons/outline/shuffle.svg +3 -0
  234. data/app/assets/icons/outline/sort-horizontal.svg +3 -0
  235. data/app/assets/icons/outline/sort.svg +3 -0
  236. data/app/assets/icons/outline/star-half-stroke.svg +3 -0
  237. data/app/assets/icons/outline/star-half.svg +3 -0
  238. data/app/assets/icons/outline/star.svg +3 -0
  239. data/app/assets/icons/outline/store.svg +3 -0
  240. data/app/assets/icons/outline/sun.svg +3 -0
  241. data/app/assets/icons/outline/swatchbook.svg +3 -0
  242. data/app/assets/icons/outline/table-column.svg +3 -0
  243. data/app/assets/icons/outline/table-row.svg +3 -0
  244. data/app/assets/icons/outline/tablet.svg +3 -0
  245. data/app/assets/icons/outline/tag.svg +3 -0
  246. data/app/assets/icons/outline/terminal.svg +3 -0
  247. data/app/assets/icons/outline/text-size.svg +3 -0
  248. data/app/assets/icons/outline/text-slash.svg +3 -0
  249. data/app/assets/icons/outline/thumbs-down.svg +3 -0
  250. data/app/assets/icons/outline/thumbs-up.svg +3 -0
  251. data/app/assets/icons/outline/ticket.svg +3 -0
  252. data/app/assets/icons/outline/trash-bin.svg +3 -0
  253. data/app/assets/icons/outline/truck.svg +3 -0
  254. data/app/assets/icons/outline/undo.svg +3 -0
  255. data/app/assets/icons/outline/upload.svg +3 -0
  256. data/app/assets/icons/outline/user-add.svg +3 -0
  257. data/app/assets/icons/outline/user-circle.svg +3 -0
  258. data/app/assets/icons/outline/user-edit.svg +3 -0
  259. data/app/assets/icons/outline/user-headset.svg +3 -0
  260. data/app/assets/icons/outline/user-remove.svg +3 -0
  261. data/app/assets/icons/outline/user-settings.svg +3 -0
  262. data/app/assets/icons/outline/user.svg +3 -0
  263. data/app/assets/icons/outline/users-group.svg +3 -0
  264. data/app/assets/icons/outline/users.svg +3 -0
  265. data/app/assets/icons/outline/video-camera.svg +3 -0
  266. data/app/assets/icons/outline/volume-down.svg +3 -0
  267. data/app/assets/icons/outline/volume-up.svg +3 -0
  268. data/app/assets/icons/outline/wallet.svg +3 -0
  269. data/app/assets/icons/outline/wand-magic-sparkles.svg +3 -0
  270. data/app/assets/icons/outline/window.svg +3 -0
  271. data/app/assets/icons/outline/zoom-in.svg +3 -0
  272. data/app/assets/icons/outline/zoom-out.svg +3 -0
  273. data/app/assets/icons/solid/X.svg +3 -0
  274. data/app/assets/icons/solid/address-book.svg +3 -0
  275. data/app/assets/icons/solid/adjustments-horizontal.svg +3 -0
  276. data/app/assets/icons/solid/adjustments-vertical.svg +3 -0
  277. data/app/assets/icons/solid/annotation.svg +3 -0
  278. data/app/assets/icons/solid/apple.svg +3 -0
  279. data/app/assets/icons/solid/archive-arrow-down.svg +3 -0
  280. data/app/assets/icons/solid/archive.svg +4 -0
  281. data/app/assets/icons/solid/arrow-right-alt.svg +3 -0
  282. data/app/assets/icons/solid/arrow-up-right-from-square.svg +4 -0
  283. data/app/assets/icons/solid/backward-step.svg +3 -0
  284. data/app/assets/icons/solid/badge-check.svg +3 -0
  285. data/app/assets/icons/solid/bell-active-alt.svg +3 -0
  286. data/app/assets/icons/solid/bell-active.svg +5 -0
  287. data/app/assets/icons/solid/bell-ring.svg +3 -0
  288. data/app/assets/icons/solid/bell.svg +3 -0
  289. data/app/assets/icons/solid/blender-phone.svg +3 -0
  290. data/app/assets/icons/solid/book-open.svg +3 -0
  291. data/app/assets/icons/solid/book.svg +3 -0
  292. data/app/assets/icons/solid/bookmark.svg +3 -0
  293. data/app/assets/icons/solid/brain.svg +3 -0
  294. data/app/assets/icons/solid/briefcase.svg +3 -0
  295. data/app/assets/icons/solid/bug.svg +3 -0
  296. data/app/assets/icons/solid/building.svg +3 -0
  297. data/app/assets/icons/solid/bullhorn.svg +3 -0
  298. data/app/assets/icons/solid/calendar-edit.svg +4 -0
  299. data/app/assets/icons/solid/calendar-month.svg +3 -0
  300. data/app/assets/icons/solid/calendar-plus.svg +3 -0
  301. data/app/assets/icons/solid/calendar-week.svg +3 -0
  302. data/app/assets/icons/solid/camera-photo.svg +3 -0
  303. data/app/assets/icons/solid/caption.svg +3 -0
  304. data/app/assets/icons/solid/caret-down.svg +3 -0
  305. data/app/assets/icons/solid/caret-left.svg +3 -0
  306. data/app/assets/icons/solid/caret-right.svg +3 -0
  307. data/app/assets/icons/solid/caret-sort.svg +3 -0
  308. data/app/assets/icons/solid/caret-up.svg +3 -0
  309. data/app/assets/icons/solid/cart-plus-alt.svg +4 -0
  310. data/app/assets/icons/solid/cart-plus.svg +4 -0
  311. data/app/assets/icons/solid/cart.svg +3 -0
  312. data/app/assets/icons/solid/cash.svg +5 -0
  313. data/app/assets/icons/solid/chart-mixed-dollar.svg +3 -0
  314. data/app/assets/icons/solid/chart-pie.svg +4 -0
  315. data/app/assets/icons/solid/check-circle.svg +3 -0
  316. data/app/assets/icons/solid/check-plus-circle.svg +4 -0
  317. data/app/assets/icons/solid/circle-pause.svg +3 -0
  318. data/app/assets/icons/solid/circle-plus.svg +3 -0
  319. data/app/assets/icons/solid/clapperboard-play.svg +3 -0
  320. data/app/assets/icons/solid/clipboard-check.svg +3 -0
  321. data/app/assets/icons/solid/clipboard-list.svg +3 -0
  322. data/app/assets/icons/solid/clipboard.svg +3 -0
  323. data/app/assets/icons/solid/clock.svg +3 -0
  324. data/app/assets/icons/solid/close-circle.svg +3 -0
  325. data/app/assets/icons/solid/cloud-arrow-up.svg +4 -0
  326. data/app/assets/icons/solid/code-branch.svg +3 -0
  327. data/app/assets/icons/solid/code-fork.svg +3 -0
  328. data/app/assets/icons/solid/code-merge.svg +3 -0
  329. data/app/assets/icons/solid/code-pull-request.svg +3 -0
  330. data/app/assets/icons/solid/cog.svg +3 -0
  331. data/app/assets/icons/solid/column.svg +3 -0
  332. data/app/assets/icons/solid/computer-speaker.svg +4 -0
  333. data/app/assets/icons/solid/credit-card.svg +4 -0
  334. data/app/assets/icons/solid/css.svg +3 -0
  335. data/app/assets/icons/solid/database.svg +3 -0
  336. data/app/assets/icons/solid/desktop-pc.svg +3 -0
  337. data/app/assets/icons/solid/discord.svg +3 -0
  338. data/app/assets/icons/solid/download.svg +4 -0
  339. data/app/assets/icons/solid/draw-square.svg +4 -0
  340. data/app/assets/icons/solid/dribbble.svg +3 -0
  341. data/app/assets/icons/solid/dropbox.svg +4 -0
  342. data/app/assets/icons/solid/edit.svg +4 -0
  343. data/app/assets/icons/solid/envelope-open.svg +4 -0
  344. data/app/assets/icons/solid/envelope.svg +4 -0
  345. data/app/assets/icons/solid/exclamation-circle.svg +3 -0
  346. data/app/assets/icons/solid/eye-slash.svg +5 -0
  347. data/app/assets/icons/solid/eye.svg +3 -0
  348. data/app/assets/icons/solid/face-explode.svg +3 -0
  349. data/app/assets/icons/solid/face-grin-stars.svg +3 -0
  350. data/app/assets/icons/solid/face-grin.svg +3 -0
  351. data/app/assets/icons/solid/face-laugh.svg +3 -0
  352. data/app/assets/icons/solid/facebook.svg +3 -0
  353. data/app/assets/icons/solid/file-chart-bar.svg +3 -0
  354. data/app/assets/icons/solid/file-check.svg +4 -0
  355. data/app/assets/icons/solid/file-circle-plus.svg +4 -0
  356. data/app/assets/icons/solid/file-clone.svg +4 -0
  357. data/app/assets/icons/solid/file-code.svg +3 -0
  358. data/app/assets/icons/solid/file-copy-alt.svg +4 -0
  359. data/app/assets/icons/solid/file-copy.svg +4 -0
  360. data/app/assets/icons/solid/file-csv.svg +3 -0
  361. data/app/assets/icons/solid/file-export.svg +3 -0
  362. data/app/assets/icons/solid/file-image.svg +3 -0
  363. data/app/assets/icons/solid/file-import.svg +3 -0
  364. data/app/assets/icons/solid/file-invoice.svg +3 -0
  365. data/app/assets/icons/solid/file-lines.svg +3 -0
  366. data/app/assets/icons/solid/file-music.svg +3 -0
  367. data/app/assets/icons/solid/file-paste.svg +4 -0
  368. data/app/assets/icons/solid/file-pdf.svg +3 -0
  369. data/app/assets/icons/solid/file-pen.svg +4 -0
  370. data/app/assets/icons/solid/file-ppt.svg +3 -0
  371. data/app/assets/icons/solid/file-search.svg +3 -0
  372. data/app/assets/icons/solid/file-shield.svg +4 -0
  373. data/app/assets/icons/solid/file-video.svg +3 -0
  374. data/app/assets/icons/solid/file-word.svg +3 -0
  375. data/app/assets/icons/solid/file-zip.svg +3 -0
  376. data/app/assets/icons/solid/file.svg +3 -0
  377. data/app/assets/icons/solid/filter.svg +3 -0
  378. data/app/assets/icons/solid/fire.svg +3 -0
  379. data/app/assets/icons/solid/flag.svg +3 -0
  380. data/app/assets/icons/solid/flowbite.svg +6 -0
  381. data/app/assets/icons/solid/folder-arrow-right.svg +3 -0
  382. data/app/assets/icons/solid/folder-duplicate.svg +4 -0
  383. data/app/assets/icons/solid/folder-open.svg +3 -0
  384. data/app/assets/icons/solid/folder-plus.svg +3 -0
  385. data/app/assets/icons/solid/folder.svg +3 -0
  386. data/app/assets/icons/solid/forward-step.svg +3 -0
  387. data/app/assets/icons/solid/forward.svg +3 -0
  388. data/app/assets/icons/solid/gift-box.svg +3 -0
  389. data/app/assets/icons/solid/github.svg +3 -0
  390. data/app/assets/icons/solid/globe.svg +3 -0
  391. data/app/assets/icons/solid/google.svg +3 -0
  392. data/app/assets/icons/solid/grid-plus.svg +3 -0
  393. data/app/assets/icons/solid/grid.svg +3 -0
  394. data/app/assets/icons/solid/headphones.svg +3 -0
  395. data/app/assets/icons/solid/heart.svg +3 -0
  396. data/app/assets/icons/solid/home.svg +3 -0
  397. data/app/assets/icons/solid/hourglass.svg +3 -0
  398. data/app/assets/icons/solid/html.svg +3 -0
  399. data/app/assets/icons/solid/image.svg +4 -0
  400. data/app/assets/icons/solid/inbox-full.svg +3 -0
  401. data/app/assets/icons/solid/inbox.svg +3 -0
  402. data/app/assets/icons/solid/indent.svg +3 -0
  403. data/app/assets/icons/solid/info-circle.svg +3 -0
  404. data/app/assets/icons/solid/keyboard.svg +3 -0
  405. data/app/assets/icons/solid/label.svg +3 -0
  406. data/app/assets/icons/solid/landmark.svg +4 -0
  407. data/app/assets/icons/solid/layers.svg +4 -0
  408. data/app/assets/icons/solid/life-saver.svg +3 -0
  409. data/app/assets/icons/solid/lightbulb.svg +3 -0
  410. data/app/assets/icons/solid/linkedin.svg +4 -0
  411. data/app/assets/icons/solid/list-music.svg +3 -0
  412. data/app/assets/icons/solid/lock-open.svg +3 -0
  413. data/app/assets/icons/solid/lock-time.svg +4 -0
  414. data/app/assets/icons/solid/lock.svg +3 -0
  415. data/app/assets/icons/solid/mail-box.svg +3 -0
  416. data/app/assets/icons/solid/map-pin-alt.svg +3 -0
  417. data/app/assets/icons/solid/map-pin.svg +3 -0
  418. data/app/assets/icons/solid/message-caption.svg +3 -0
  419. data/app/assets/icons/solid/message-dots.svg +3 -0
  420. data/app/assets/icons/solid/messages.svg +4 -0
  421. data/app/assets/icons/solid/microphone.svg +4 -0
  422. data/app/assets/icons/solid/mobile-phone.svg +3 -0
  423. data/app/assets/icons/solid/moon.svg +3 -0
  424. data/app/assets/icons/solid/newspaper.svg +3 -0
  425. data/app/assets/icons/solid/npm.svg +3 -0
  426. data/app/assets/icons/solid/outdent.svg +3 -0
  427. data/app/assets/icons/solid/palette.svg +3 -0
  428. data/app/assets/icons/solid/paper-plane.svg +3 -0
  429. data/app/assets/icons/solid/paragraph.svg +3 -0
  430. data/app/assets/icons/solid/pause.svg +3 -0
  431. data/app/assets/icons/solid/pen-nib.svg +3 -0
  432. data/app/assets/icons/solid/pen.svg +3 -0
  433. data/app/assets/icons/solid/phone.svg +3 -0
  434. data/app/assets/icons/solid/play.svg +3 -0
  435. data/app/assets/icons/solid/printer.svg +3 -0
  436. data/app/assets/icons/solid/profile-card.svg +3 -0
  437. data/app/assets/icons/solid/question-circle.svg +3 -0
  438. data/app/assets/icons/solid/quote.svg +3 -0
  439. data/app/assets/icons/solid/react.svg +4 -0
  440. data/app/assets/icons/solid/receipt.svg +3 -0
  441. data/app/assets/icons/solid/rectangle-list.svg +3 -0
  442. data/app/assets/icons/solid/reply-all.svg +3 -0
  443. data/app/assets/icons/solid/reply.svg +3 -0
  444. data/app/assets/icons/solid/rocket.svg +3 -0
  445. data/app/assets/icons/solid/sale-percent.svg +3 -0
  446. data/app/assets/icons/solid/scale-balanced.svg +3 -0
  447. data/app/assets/icons/solid/search.svg +4 -0
  448. data/app/assets/icons/solid/share-all.svg +3 -0
  449. data/app/assets/icons/solid/share-nodes.svg +3 -0
  450. data/app/assets/icons/solid/shield-check.svg +3 -0
  451. data/app/assets/icons/solid/shield.svg +3 -0
  452. data/app/assets/icons/solid/shopping-bag.svg +3 -0
  453. data/app/assets/icons/solid/stackoverflow.svg +4 -0
  454. data/app/assets/icons/solid/star-half-stroke.svg +3 -0
  455. data/app/assets/icons/solid/star-half.svg +3 -0
  456. data/app/assets/icons/solid/star.svg +3 -0
  457. data/app/assets/icons/solid/store.svg +3 -0
  458. data/app/assets/icons/solid/sun.svg +3 -0
  459. data/app/assets/icons/solid/swatchbook.svg +3 -0
  460. data/app/assets/icons/solid/table-column.svg +3 -0
  461. data/app/assets/icons/solid/table-row.svg +3 -0
  462. data/app/assets/icons/solid/tablet.svg +3 -0
  463. data/app/assets/icons/solid/tag.svg +3 -0
  464. data/app/assets/icons/solid/tailwind.svg +3 -0
  465. data/app/assets/icons/solid/terminal.svg +3 -0
  466. data/app/assets/icons/solid/thumbs-down.svg +3 -0
  467. data/app/assets/icons/solid/thumbs-up.svg +3 -0
  468. data/app/assets/icons/solid/ticket.svg +3 -0
  469. data/app/assets/icons/solid/trash-bin.svg +3 -0
  470. data/app/assets/icons/solid/truck.svg +3 -0
  471. data/app/assets/icons/solid/twitter.svg +3 -0
  472. data/app/assets/icons/solid/upload.svg +3 -0
  473. data/app/assets/icons/solid/user-add.svg +3 -0
  474. data/app/assets/icons/solid/user-circle.svg +3 -0
  475. data/app/assets/icons/solid/user-edit.svg +3 -0
  476. data/app/assets/icons/solid/user-headset.svg +3 -0
  477. data/app/assets/icons/solid/user-remove.svg +3 -0
  478. data/app/assets/icons/solid/user-settings.svg +3 -0
  479. data/app/assets/icons/solid/user.svg +3 -0
  480. data/app/assets/icons/solid/users-group.svg +3 -0
  481. data/app/assets/icons/solid/users.svg +3 -0
  482. data/app/assets/icons/solid/video-camera.svg +3 -0
  483. data/app/assets/icons/solid/volume-down.svg +4 -0
  484. data/app/assets/icons/solid/volume-up.svg +5 -0
  485. data/app/assets/icons/solid/vue.svg +3 -0
  486. data/app/assets/icons/solid/wallet.svg +4 -0
  487. data/app/assets/icons/solid/wand-magic-sparkles.svg +4 -0
  488. data/app/assets/icons/solid/window-restore.svg +4 -0
  489. data/app/assets/icons/solid/window.svg +3 -0
  490. data/app/assets/icons/solid/youtube.svg +3 -0
  491. data/app/assets/icons/solid/zoom-in.svg +3 -0
  492. data/app/assets/icons/solid/zoom-out.svg +3 -0
  493. data/app/assets/js/controllers/application.js +7 -0
  494. data/app/assets/js/controllers/index.js +30 -0
  495. data/app/assets/js/controllers/resource_dismiss_controller.js +37 -0
  496. data/app/assets/js/controllers/resource_drop_down_controller.js +29 -0
  497. data/app/assets/js/plutonium.js +2 -0
  498. data/app/assets/js/turbo/index.js +5 -0
  499. data/app/assets/js/turbo/turbo_actions.js +8 -0
  500. data/app/assets/js/turbo/turbo_debug.js +30 -0
  501. data/app/assets/js/turbo/turbo_frame_monkey_patch.js +23 -0
  502. data/app/views/{resource → application}/_color_modes.html.erb +3 -1
  503. data/app/views/application/_flash.html.erb +1 -0
  504. data/app/views/application/_flash_alerts.html.erb +53 -0
  505. data/app/views/application/_flash_toasts.html.erb +56 -0
  506. data/app/views/application/_resource_header.html.erb +723 -0
  507. data/app/views/application/_resource_sidebar.html.erb +12 -0
  508. data/app/views/components/action_button/action_button_component.html.erb +7 -0
  509. data/app/views/components/action_button/action_button_component.rb +15 -0
  510. data/app/views/components/base.rb +50 -0
  511. data/app/views/components/block/block_component.html.erb +3 -0
  512. data/app/views/components/block/block_component.rb +40 -0
  513. data/app/views/components/breadcrumbs/breadcrumbs_component.html.erb +96 -0
  514. data/app/views/components/breadcrumbs/breadcrumbs_component.rb +9 -0
  515. data/app/views/components/button/button_component.html.erb +11 -0
  516. data/app/views/components/button/button_component.rb +123 -0
  517. data/app/views/components/dyna_frame_content/dyna_frame_content_component.html.erb +7 -0
  518. data/app/views/components/dyna_frame_content/dyna_frame_content_component.rb +6 -0
  519. data/app/views/components/dyna_frame_host/dyna_frame_host_component.html.erb +4 -0
  520. data/app/views/components/dyna_frame_host/dyna_frame_host_component.rb +11 -0
  521. data/app/views/components/empty_card/empty_card_component.html.erb +6 -0
  522. data/app/views/components/empty_card/empty_card_component.rb +7 -0
  523. data/app/views/components/form/form_builder.rb +71 -0
  524. data/app/views/components/form/form_component.html.erb +76 -0
  525. data/app/views/components/form/form_component.rb +23 -0
  526. data/app/views/components/form/form_controller.js +13 -0
  527. data/app/views/components/header/header_component.html.erb +1 -0
  528. data/app/views/components/header/header_component.rb +7 -0
  529. data/app/views/components/interactive_action_form/interactive_action_form_component.html.erb +41 -0
  530. data/app/views/components/interactive_action_form/interactive_action_form_component.rb +8 -0
  531. data/app/views/components/interactive_action_form/interactive_action_form_controller.js +13 -0
  532. data/app/views/components/nested_resource_form_fields/nested_resource_form_fields_component.html.erb +66 -0
  533. data/app/views/components/nested_resource_form_fields/nested_resource_form_fields_component.rb +23 -0
  534. data/app/views/components/nested_resource_form_fields/nested_resource_form_fields_controller.js +64 -0
  535. data/app/views/components/pagination/pagination_component.html.erb +6 -0
  536. data/app/views/components/pagination/pagination_component.rb +91 -0
  537. data/app/views/components/panel/panel_component.html.erb +10 -0
  538. data/app/views/components/panel/panel_component.rb +11 -0
  539. data/app/views/components/sidebar/sidebar_component.html.erb +152 -0
  540. data/app/views/components/sidebar/sidebar_component.rb +15 -0
  541. data/app/views/components/sidebar_menu/sidebar_menu_component.html.erb +3 -0
  542. data/app/views/components/sidebar_menu/sidebar_menu_component.rb +13 -0
  543. data/app/views/components/sidebar_menu_item/sidebar_menu_item_component.html.erb +72 -0
  544. data/app/views/components/sidebar_menu_item/sidebar_menu_item_component.rb +23 -0
  545. data/app/views/components/skeleton/table/table_component.html.erb +18 -0
  546. data/app/views/components/skeleton/table/table_component.rb +6 -0
  547. data/app/views/components/tab_bar/tab_bar_component.html.erb +11 -0
  548. data/app/views/components/tab_bar/tab_bar_component.rb +9 -0
  549. data/app/views/components/tab_bar/tab_bar_controller.js +8 -0
  550. data/app/views/components/table/table_component.html.erb +92 -0
  551. data/app/views/components/table/table_component.rb +63 -0
  552. data/app/views/components/table/table_controller.js +8 -0
  553. data/app/views/components/table_search_input/table_search_input_component.html.erb +42 -0
  554. data/app/views/components/table_search_input/table_search_input_component.rb +10 -0
  555. data/app/views/components/table_search_input/table_search_input_controller.js +8 -0
  556. data/app/views/components/table_toolbar/table_toolbar_component.html.erb +7 -0
  557. data/app/views/components/table_toolbar/table_toolbar_component.rb +9 -0
  558. data/app/views/components/table_toolbar/table_toolbar_controller.js +8 -0
  559. data/app/views/components/toolbar/toolbar_component.html.erb +67 -0
  560. data/app/views/components/toolbar/toolbar_component.rb +18 -0
  561. data/app/views/components/toolbar/toolbar_controller.js +8 -0
  562. data/app/views/layouts/resource.html copy.erb +49 -0
  563. data/app/views/layouts/resource.html.erb +30 -25
  564. data/app/views/layouts/rodauth.html.erb +31 -0
  565. data/app/views/resource/_interactive_resource_action_form.html.erb +5 -27
  566. data/app/views/resource/_resource_details.html.erb +26 -0
  567. data/app/views/resource/{_resource.rabl → _resource_details.rabl} +1 -1
  568. data/app/views/resource/_resource_form.html.erb +5 -0
  569. data/app/views/resource/_resource_table.html.erb +15 -0
  570. data/app/views/resource/edit.html.erb +4 -9
  571. data/app/views/resource/index.html.erb +4 -18
  572. data/app/views/resource/interactive_resource_collection_action.html.erb +3 -10
  573. data/app/views/resource/interactive_resource_record_action.html.erb +3 -10
  574. data/app/views/resource/interactive_resource_recordless_action.html.erb +3 -10
  575. data/app/views/resource/new.html.erb +3 -10
  576. data/app/views/resource/show.html.erb +4 -13
  577. data/app/views/resource/show.rabl +1 -1
  578. data/brakeman.ignore +5 -5
  579. data/build.js +12 -0
  580. data/config/initializers/hotwire_turbo_monkey_patches.rb +12 -0
  581. data/{lib/plutonium → config}/initializers/pagy.rb +0 -1
  582. data/config/initializers/simple_form.rb +54 -0
  583. data/exe/pug +6 -0
  584. data/lib/active_model/validations/array_validator.rb +1 -1
  585. data/lib/active_model/validations/attached_validator.rb +1 -1
  586. data/lib/active_model/validations/url_validator.rb +1 -1
  587. data/lib/generators/pu/core/install/install_generator.rb +1 -1
  588. data/lib/generators/pu/core/install/templates/app/controllers/resource_controller.rb.tt +2 -1
  589. data/lib/generators/pu/core/install/templates/app/interactions/resource_interaction.rb.tt +1 -1
  590. data/lib/generators/pu/core/install/templates/app/models/resource_record.rb.tt +1 -1
  591. data/lib/generators/pu/core/install/templates/app/policies/resource_policy.rb.tt +1 -1
  592. data/lib/generators/pu/core/install/templates/app/presenters/resource_presenter.rb.tt +1 -1
  593. data/lib/generators/pu/core/install/templates/app/query_objects/resource_query_object.rb.tt +2 -0
  594. data/lib/generators/pu/core/install/templates/config/packages.rb +1 -3
  595. data/lib/generators/pu/gem/pagy/pagy_generator.rb +1 -1
  596. data/lib/generators/pu/gem/rabl/rabl_generator.rb +1 -1
  597. data/lib/generators/pu/gem/simple_form/simple_form_generator.rb +1 -1
  598. data/lib/generators/pu/gen/component/component_generator.rb +87 -0
  599. data/lib/generators/pu/gen/component/templates/component.html.erb.tt +3 -0
  600. data/lib/generators/pu/gen/component/templates/component.rb.tt +9 -0
  601. data/lib/generators/pu/gen/component/templates/controller.js.tt +8 -0
  602. data/lib/generators/pu/gen/pug/pug_generator.rb +1 -1
  603. data/lib/generators/pu/lib/plutonium_generators/cli.rb +42 -0
  604. data/lib/generators/pu/lib/plutonium_generators/concerns/actions.rb +353 -0
  605. data/lib/generators/pu/lib/plutonium_generators/concerns/config.rb +39 -0
  606. data/lib/generators/pu/lib/plutonium_generators/concerns/logger.rb +36 -0
  607. data/lib/generators/pu/lib/plutonium_generators/concerns/serializer.rb +39 -0
  608. data/lib/generators/pu/lib/plutonium_generators/generator.rb +82 -0
  609. data/lib/generators/pu/lib/plutonium_generators/installer.rb +205 -0
  610. data/lib/generators/pu/lib/plutonium_generators/model_generator.rb +151 -0
  611. data/lib/generators/pu/lib/plutonium_generators.rb +15 -0
  612. data/lib/generators/pu/pkg/app/app_generator.rb +14 -4
  613. data/lib/generators/pu/pkg/app/templates/app/controllers/app_controller.rb.tt +5 -0
  614. data/lib/generators/pu/pkg/app/templates/app/controllers/dashboard_controller.rb.tt +6 -0
  615. data/lib/generators/pu/pkg/app/templates/app/controllers/{resource_controller.rb.tt → package_controller.rb.tt} +3 -3
  616. data/lib/generators/pu/pkg/app/templates/app/{interactions/resource_interaction.rb.tt → query_objects/resource_query_object.rb.tt} +1 -1
  617. data/lib/generators/pu/pkg/app/templates/app/views/package/dashboard/index.html.erb +23 -0
  618. data/lib/generators/pu/pkg/app/templates/config/routes.rb.tt +5 -3
  619. data/lib/generators/pu/pkg/feature/feature_generator.rb +4 -4
  620. data/lib/generators/pu/pkg/feature/templates/app/query_objects/resource_query_object.rb.tt +4 -0
  621. data/lib/generators/pu/{resource → res}/conn/conn_generator.rb +3 -2
  622. data/lib/generators/pu/res/conn/templates/.keep +0 -0
  623. data/lib/generators/pu/{resource → res}/conn/templates/app/controllers/resource_controller.rb.tt +1 -1
  624. data/lib/generators/pu/res/conn/templates/app/query_objects/resource_query_object.rb.tt +3 -0
  625. data/lib/generators/pu/res/model/model_generator.rb +36 -0
  626. data/lib/generators/pu/{resource → res}/model/templates/model.rb.tt +1 -1
  627. data/lib/generators/pu/res/scaffold/scaffold_generator.rb +43 -0
  628. data/lib/generators/pu/res/scaffold/templates/.keep +0 -0
  629. data/lib/generators/pu/{resource/model → res/scaffold}/templates/policy.rb.tt +2 -2
  630. data/lib/generators/pu/{resource/model → res/scaffold}/templates/presenter.rb.tt +0 -5
  631. data/lib/generators/pu/res/scaffold/templates/query_object.rb.tt +17 -0
  632. data/lib/generators/pu/rodauth/account_generator.rb +6 -17
  633. data/lib/generators/pu/rodauth/concerns/account_selector.rb +5 -1
  634. data/lib/generators/pu/rodauth/migration/active_record/base.erb +0 -4
  635. data/lib/generators/pu/rodauth/migration_generator.rb +2 -4
  636. data/lib/generators/pu/rodauth/templates/app/controllers/plugin_controller.rb.tt +11 -1
  637. data/lib/generators/pu/rodauth/templates/app/controllers/rodauth_controller.rb.tt +2 -1
  638. data/lib/generators/pu/rodauth/templates/app/mailers/account_mailer.rb.tt +1 -1
  639. data/lib/generators/pu/rodauth/templates/app/misc/account_rodauth_plugin.rb.tt +26 -11
  640. data/lib/generators/pu/rodauth/templates/app/misc/rodauth_plugin.rb.tt +1 -1
  641. data/lib/generators/pu/rodauth/templates/app/models/account.rb.tt +4 -1
  642. data/lib/generators/pu/rodauth/views_generator.rb +1 -14
  643. data/lib/plutonium/application/controller.rb +43 -0
  644. data/lib/plutonium/auth/{public_access.rb → public.rb} +1 -1
  645. data/lib/plutonium/auth.rb +0 -5
  646. data/lib/plutonium/builders/menus/sidebar_menu.rb.bk +26 -0
  647. data/lib/plutonium/builders/menus/sidebar_menu_item.rb.bk +28 -0
  648. data/lib/plutonium/component_registry.rb +19 -0
  649. data/lib/plutonium/config.rb +17 -2
  650. data/lib/plutonium/core/action.rb +9 -6
  651. data/lib/plutonium/core/actions/collection.rb +5 -1
  652. data/lib/plutonium/core/actions/destroy_action.rb +5 -3
  653. data/lib/plutonium/core/actions/edit_action.rb +5 -3
  654. data/lib/plutonium/core/actions/interactive_action.rb +1 -1
  655. data/lib/plutonium/core/actions/new_action.rb +5 -3
  656. data/lib/plutonium/core/actions/show_action.rb +5 -3
  657. data/lib/plutonium/core/autodiscovery/input_discoverer.rb +0 -2
  658. data/lib/plutonium/core/autodiscovery/renderer_discoverer.rb +0 -2
  659. data/lib/plutonium/core/controllers/authorizable.rb +7 -9
  660. data/lib/plutonium/core/controllers/base.rb +86 -0
  661. data/lib/plutonium/core/controllers/bootable.rb +5 -24
  662. data/lib/plutonium/core/controllers/crud_actions.rb +43 -8
  663. data/lib/plutonium/core/controllers/entity_scoping.rb +16 -5
  664. data/lib/plutonium/core/controllers/interactive_actions.rb +9 -7
  665. data/lib/plutonium/core/controllers/presentable.rb +11 -11
  666. data/lib/plutonium/core/controllers/queryable.rb +26 -0
  667. data/lib/plutonium/core/definers/input_definer.rb +47 -7
  668. data/lib/plutonium/core/definers/renderer_definer.rb +5 -3
  669. data/lib/plutonium/core/fields/inputs/base.rb +3 -3
  670. data/lib/plutonium/core/fields/inputs/date_time_input.rb +13 -0
  671. data/lib/plutonium/core/fields/inputs/factory.rb +13 -4
  672. data/lib/plutonium/core/fields/inputs/nested_input.rb +57 -0
  673. data/lib/plutonium/core/fields/inputs/noop_input.rb +1 -1
  674. data/lib/plutonium/core/fields/inputs/phone_input.rb +22 -0
  675. data/lib/plutonium/core/fields/inputs/polymorphic_belongs_to_association_input.rb +47 -0
  676. data/lib/plutonium/core/fields/inputs/simple_form_association_input.rb +3 -2
  677. data/lib/plutonium/core/fields/inputs/simple_form_input.rb +4 -1
  678. data/lib/plutonium/core/fields/renderers/association_renderer.rb +4 -7
  679. data/lib/plutonium/core/fields/renderers/factory.rb +1 -0
  680. data/lib/plutonium/core/fields/renderers/map_renderer.rb +19 -0
  681. data/lib/plutonium/core/ui/collection.rb +12 -8
  682. data/lib/plutonium/core/ui/detail.rb +8 -5
  683. data/lib/plutonium/core/ui/form.rb +6 -5
  684. data/lib/plutonium/helpers/action_buttons_helper.rb +23 -23
  685. data/lib/plutonium/helpers/application_helper.rb +0 -4
  686. data/lib/plutonium/helpers/attachment_helper.rb +1 -1
  687. data/lib/plutonium/helpers/component_helper.rb +14 -0
  688. data/lib/plutonium/helpers/display_helper.rb +6 -6
  689. data/lib/plutonium/helpers/form_helper.rb +29 -10
  690. data/lib/plutonium/helpers/table_helper.rb +35 -0
  691. data/lib/plutonium/helpers/turbo_helper.rb +2 -2
  692. data/lib/plutonium/helpers.rb +6 -19
  693. data/lib/plutonium/icons.rb +25 -0
  694. data/lib/plutonium/lib/after_commit.rb +2 -2
  695. data/lib/plutonium/{packaging → pkg}/app.rb +8 -6
  696. data/lib/plutonium/{packaging/package.rb → pkg/base.rb} +6 -2
  697. data/lib/plutonium/{packaging → pkg}/feature.rb +2 -2
  698. data/lib/plutonium/preserved__/{field.rb → field.rb.bk} +1 -1
  699. data/lib/plutonium/preserved__/{input.rb → input.rb.bk} +1 -1
  700. data/lib/plutonium/railtie.rb +17 -3
  701. data/lib/plutonium/reactor/core.rb +34 -19
  702. data/lib/plutonium/refinements/parameter_refinements.rb +2 -0
  703. data/lib/plutonium/resource/context.rb +5 -0
  704. data/lib/plutonium/resource/controller.rb +138 -0
  705. data/lib/plutonium/resource/interaction.rb +8 -0
  706. data/lib/plutonium/{reactor/resource_policy.rb → resource/policy.rb} +16 -3
  707. data/lib/plutonium/{reactor → resource}/policy_context.rb +1 -1
  708. data/lib/plutonium/resource/presenter.rb +78 -0
  709. data/lib/plutonium/resource/query_object.rb +219 -0
  710. data/lib/plutonium/{reactor/resource_record.rb → resource/record.rb} +95 -42
  711. data/lib/plutonium/rodauth/controller_methods.rb +12 -0
  712. data/lib/plutonium/{simple_form_components → simple_form}/attachment_component.rb +2 -0
  713. data/lib/plutonium/{simple_form_components → simple_form}/input_group_component.rb +2 -0
  714. data/lib/plutonium/version.rb +1 -1
  715. data/lib/plutonium.rb +33 -16
  716. data/package-lock.json +2530 -0
  717. data/package.json +22 -0
  718. data/postcss.config.js +11 -0
  719. data/public/plutonium-assets/application.css +1617 -811
  720. data/public/plutonium-assets/application.js +299 -300
  721. data/tailwind.config.js +91 -0
  722. data/templates/base.rb +8 -0
  723. metadata +765 -177
  724. data/app/views/resource/_details.html.erb +0 -6
  725. data/app/views/resource/_empty_card.html.erb +0 -12
  726. data/app/views/resource/_flash.html.erb +0 -9
  727. data/app/views/resource/_form.html.erb +0 -32
  728. data/app/views/resource/_header.html.erb +0 -8
  729. data/app/views/resource/_messages.html.erb +0 -1
  730. data/app/views/resource/_pagination.html.erb +0 -6
  731. data/app/views/resource/_pagy_pagination.html.erb +0 -15
  732. data/app/views/resource/_resource.html.erb +0 -1
  733. data/app/views/resource/_sidebar.html.erb +0 -11
  734. data/app/views/resource/_sidebar_menu.html.erb +0 -1
  735. data/app/views/resource/_table.html.erb +0 -78
  736. data/app/views/resource/_table_actions.html.erb +0 -15
  737. data/app/views/resource/_toast.html.erb +0 -26
  738. data/app/views/resource/_toolbar.html.erb +0 -22
  739. data/app/views/resource/_toolbar_actions.html.erb +0 -16
  740. data/app/views/resource/_toolbar_breadcrumbs.html.erb +0 -32
  741. data/app/views/resource/_toolbar_search_input.erb +0 -27
  742. data/lib/generators/pu/resource/model/model_generator.rb +0 -163
  743. data/lib/generators/pu/resource/scaffold/scaffold_generator.rb +0 -219
  744. data/lib/generators/pu/resource/scaffold/templates/app/controllers/admin_resources/resource_controller.rb.tt +0 -7
  745. data/lib/generators/pu/resource/scaffold/templates/app/controllers/entity_resources/resource_controller.rb.tt +0 -7
  746. data/lib/generators/pu/resource/scaffold/templates/app/policies/resources/admin/resource_policy.rb.tt +0 -22
  747. data/lib/generators/pu/resource/scaffold/templates/app/policies/resources/entity/resource_policy.rb.tt +0 -22
  748. data/lib/generators/pu/resource/scaffold/templates/app/policies/resources/resource_policy.rb.tt +0 -13
  749. data/lib/generators/pu/resource/scaffold/templates/app/resources/resource/admin_presenter.rb.tt +0 -7
  750. data/lib/generators/pu/resource/scaffold/templates/app/resources/resource/entity_presenter.rb.tt +0 -7
  751. data/lib/generators/pu/resource/scaffold/templates/app/resources/resource/presenter.rb.tt +0 -23
  752. data/lib/generators/pu/resource/scaffold/templates/app/views/resources/resource/_resource.html.erb.tt +0 -3
  753. data/lib/generators/pu/resource/scaffold/templates/app/views/resources/resource/_resource.rabl +0 -7
  754. data/lib/generators/pu/rodauth/templates/app/views/rodauth/_email_auth_request_form.html.erb +0 -7
  755. data/lib/generators/pu/rodauth/templates/app/views/rodauth/_login_form.html.erb +0 -26
  756. data/lib/generators/pu/rodauth/templates/app/views/rodauth/_login_form_footer.html.erb +0 -9
  757. data/lib/generators/pu/rodauth/templates/app/views/rodauth/add_recovery_codes.html.erb +0 -6
  758. data/lib/generators/pu/rodauth/templates/app/views/rodauth/change_login.html.erb +0 -27
  759. data/lib/generators/pu/rodauth/templates/app/views/rodauth/change_password.html.erb +0 -27
  760. data/lib/generators/pu/rodauth/templates/app/views/rodauth/close_account.html.erb +0 -13
  761. data/lib/generators/pu/rodauth/templates/app/views/rodauth/confirm_password.html.erb +0 -11
  762. data/lib/generators/pu/rodauth/templates/app/views/rodauth/create_account.html.erb +0 -35
  763. data/lib/generators/pu/rodauth/templates/app/views/rodauth/email_auth.html.erb +0 -5
  764. data/lib/generators/pu/rodauth/templates/app/views/rodauth/login.html.erb +0 -4
  765. data/lib/generators/pu/rodauth/templates/app/views/rodauth/logout.html.erb +0 -14
  766. data/lib/generators/pu/rodauth/templates/app/views/rodauth/multi_phase_login.html.erb +0 -3
  767. data/lib/generators/pu/rodauth/templates/app/views/rodauth/otp_auth.html.erb +0 -15
  768. data/lib/generators/pu/rodauth/templates/app/views/rodauth/otp_disable.html.erb +0 -13
  769. data/lib/generators/pu/rodauth/templates/app/views/rodauth/otp_setup.html.erb +0 -41
  770. data/lib/generators/pu/rodauth/templates/app/views/rodauth/recovery_auth.html.erb +0 -11
  771. data/lib/generators/pu/rodauth/templates/app/views/rodauth/recovery_codes.html.erb +0 -13
  772. data/lib/generators/pu/rodauth/templates/app/views/rodauth/remember.html.erb +0 -22
  773. data/lib/generators/pu/rodauth/templates/app/views/rodauth/reset_password.html.erb +0 -19
  774. data/lib/generators/pu/rodauth/templates/app/views/rodauth/reset_password_request.html.erb +0 -17
  775. data/lib/generators/pu/rodauth/templates/app/views/rodauth/sms_auth.html.erb +0 -15
  776. data/lib/generators/pu/rodauth/templates/app/views/rodauth/sms_confirm.html.erb +0 -15
  777. data/lib/generators/pu/rodauth/templates/app/views/rodauth/sms_disable.html.erb +0 -13
  778. data/lib/generators/pu/rodauth/templates/app/views/rodauth/sms_request.html.erb +0 -5
  779. data/lib/generators/pu/rodauth/templates/app/views/rodauth/sms_setup.html.erb +0 -23
  780. data/lib/generators/pu/rodauth/templates/app/views/rodauth/two_factor_auth.html.erb +0 -5
  781. data/lib/generators/pu/rodauth/templates/app/views/rodauth/two_factor_disable.html.erb +0 -13
  782. data/lib/generators/pu/rodauth/templates/app/views/rodauth/two_factor_manage.html.erb +0 -22
  783. data/lib/generators/pu/rodauth/templates/app/views/rodauth/unlock_account.html.erb +0 -15
  784. data/lib/generators/pu/rodauth/templates/app/views/rodauth/unlock_account_request.html.erb +0 -9
  785. data/lib/generators/pu/rodauth/templates/app/views/rodauth/verify_account.html.erb +0 -21
  786. data/lib/generators/pu/rodauth/templates/app/views/rodauth/verify_account_resend.html.erb +0 -17
  787. data/lib/generators/pu/rodauth/templates/app/views/rodauth/verify_login_change.html.erb +0 -5
  788. data/lib/generators/pu/rodauth/templates/app/views/rodauth/webauthn_auth.html.erb +0 -15
  789. data/lib/generators/pu/rodauth/templates/app/views/rodauth/webauthn_autofill.html.erb +0 -10
  790. data/lib/generators/pu/rodauth/templates/app/views/rodauth/webauthn_remove.html.erb +0 -23
  791. data/lib/generators/pu/rodauth/templates/app/views/rodauth/webauthn_setup.html.erb +0 -23
  792. data/lib/plutonium/core/actions.rb +0 -17
  793. data/lib/plutonium/core/app_controller.rb +0 -121
  794. data/lib/plutonium/core/autodiscovery.rb +0 -13
  795. data/lib/plutonium/core/controllers.rb +0 -16
  796. data/lib/plutonium/core/definers.rb +0 -14
  797. data/lib/plutonium/core/fields/inputs.rb +0 -20
  798. data/lib/plutonium/core/fields/renderers.rb +0 -16
  799. data/lib/plutonium/core/fields.rb +0 -12
  800. data/lib/plutonium/core/ui.rb +0 -13
  801. data/lib/plutonium/core.rb +0 -16
  802. data/lib/plutonium/helpers/menu_helper.rb +0 -69
  803. data/lib/plutonium/helpers/pagination_helper.rb +0 -9
  804. data/lib/plutonium/initializers/TODO +0 -2
  805. data/lib/plutonium/initializers/patches.rb +0 -2
  806. data/lib/plutonium/initializers/simple_form.rb +0 -405
  807. data/lib/plutonium/packaging.rb +0 -9
  808. data/lib/plutonium/policy.rb +0 -8
  809. data/lib/plutonium/reactor/resource_context.rb +0 -5
  810. data/lib/plutonium/reactor/resource_controller.rb +0 -131
  811. data/lib/plutonium/reactor/resource_interaction.rb +0 -8
  812. data/lib/plutonium/reactor/resource_presenter.rb +0 -47
  813. data/lib/plutonium/reactor.rb +0 -14
  814. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/_email_auth_request_form.html.erb +0 -0
  815. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/_login_form.html.erb +0 -0
  816. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/_login_form_footer.html.erb +0 -0
  817. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/add_recovery_codes.html.erb +0 -0
  818. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/change_login.html.erb +0 -0
  819. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/change_password.html.erb +0 -0
  820. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/close_account.html.erb +0 -0
  821. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/confirm_password.html.erb +0 -0
  822. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/create_account.html.erb +0 -0
  823. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/email_auth.html.erb +0 -0
  824. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/login.html.erb +0 -0
  825. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/logout.html.erb +0 -0
  826. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/multi_phase_login.html.erb +0 -0
  827. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/otp_auth.html.erb +0 -0
  828. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/otp_disable.html.erb +0 -0
  829. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/otp_setup.html.erb +0 -0
  830. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/recovery_auth.html.erb +0 -0
  831. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/recovery_codes.html.erb +0 -0
  832. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/remember.html.erb +0 -0
  833. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/reset_password.html.erb +0 -0
  834. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/reset_password_request.html.erb +0 -0
  835. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/sms_auth.html.erb +0 -0
  836. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/sms_confirm.html.erb +0 -0
  837. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/sms_disable.html.erb +0 -0
  838. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/sms_request.html.erb +0 -0
  839. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/sms_setup.html.erb +0 -0
  840. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/two_factor_auth.html.erb +0 -0
  841. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/two_factor_disable.html.erb +0 -0
  842. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/two_factor_manage.html.erb +0 -0
  843. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/unlock_account.html.erb +0 -0
  844. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/unlock_account_request.html.erb +0 -0
  845. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/verify_account.html.erb +0 -0
  846. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/verify_account_resend.html.erb +0 -0
  847. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/verify_login_change.html.erb +0 -0
  848. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/webauthn_auth.html.erb +0 -0
  849. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/webauthn_autofill.html.erb +0 -0
  850. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/webauthn_remove.html.erb +0 -0
  851. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/webauthn_setup.html.erb +0 -0
  852. /data/{lib/plutonium → config}/initializers/rabl.rb +0 -0
  853. /data/lib/generators/pu/{resource/conn/templates → pkg/app/templates/app/views/package}/.keep +0 -0
  854. /data/lib/generators/pu/{resource → res}/conn/templates/app/policies/resource_policy.rb.tt +0 -0
  855. /data/lib/generators/pu/{resource → res}/conn/templates/app/presenters/resource_presenter.rb.tt +0 -0
  856. /data/lib/generators/pu/{resource → res}/model/USAGE +0 -0
  857. /data/lib/generators/pu/{resource → res}/model/templates/create_table_migration.rb.tt +0 -0
  858. /data/lib/generators/pu/{resource → res}/model/templates/module.rb.tt +0 -0
  859. /data/lib/generators/pu/{resource/model → res/scaffold}/templates/controller.rb.tt +0 -0
@@ -1,5 +1,5 @@
1
1
  module Plutonium
2
- module UI
2
+ module Ui
3
3
  class Field
4
4
  attr_reader :name, :label, :helper, :options
5
5
 
@@ -1,5 +1,5 @@
1
1
  module Plutonium
2
- module UI
2
+ module Ui
3
3
  class Input
4
4
  attr_reader :name, :options
5
5
 
@@ -1,10 +1,24 @@
1
- # frozen_string_literal: true
1
+ require "view_component"
2
2
 
3
3
  module Plutonium
4
4
  class Railtie < Rails::Railtie
5
- # add railties here
5
+ initializer "plutonium.assets_server" do
6
+ # setup a middleware to serve our assets
7
+ config.app_middleware.insert_before(
8
+ ActionDispatch::Static,
9
+ Rack::Static,
10
+ urls: ["/plutonium-assets"],
11
+ root: Plutonium.root.join("public"),
12
+ cascade: true,
13
+ header_rules: [
14
+ # Cache all static files in public caches (e.g. Rack::Cache) as well as in the browser
15
+ [:all, {"cache-control" => "public, max-age=31536000"}]
16
+ ]
17
+ )
18
+ end
6
19
 
7
- initializer "plutonium.achieve_criticality" do
20
+ initializer "plutonium.view_components" do
21
+ config.view_component.capture_compatibility_patch_enabled = true
8
22
  end
9
23
  end
10
24
  end
@@ -5,33 +5,42 @@ module Plutonium
5
5
  module Reactor
6
6
  class Core
7
7
  def self.achieve_criticality!
8
- Dir[Plutonium.lib_root.join("initializers", "**", "*.rb")].each do |file|
9
- require file
10
- end
8
+ # Eager load the framework
9
+ # Plutonium::ZEITWERK_LOADER.eager_load
10
+
11
+ # Load view components
12
+ load Plutonium.root.join("app", "views", "components", "base.rb")
11
13
 
12
- # setup a middleware to serve our assets
13
- Rails.application.config.middleware.insert_before(
14
- ActionDispatch::Static,
15
- Rack::Static,
16
- urls: ["/plutonium-assets"],
17
- root: Plutonium.root.join("public"),
18
- cascade: true
19
- )
14
+ # Load initializers
15
+ Dir.glob(Plutonium.root.join("config", "initializers", "**", "*.rb")) { |file| load file }
20
16
 
21
17
  start_reloader!
22
18
  end
23
19
 
24
20
  def self.start_reloader!
25
- return unless Plutonium::Config.reload_files
21
+ # TODO: see which parts of this can be moved into zeitwerk
22
+ return unless Plutonium::Config.enable_hotreload
26
23
 
27
- # GLORIOUS hot reloading!!!
24
+ # GLORIOUS hotreload!!!
28
25
  @listener ||= begin
29
26
  require "listen"
30
27
 
31
- plutonium_lib_dir = Plutonium.lib_root.to_s
28
+ reload_paths = []
29
+
30
+ if Plutonium::Config.development
31
+ reload_paths << Plutonium.lib_root.to_s
32
+ reload_paths << Plutonium.root.join("app", "views", "components").to_s
33
+ reload_paths << Plutonium.root.join("config", "initializers").to_s
34
+ end
35
+
36
+ # we want to always watch packages for changes to engines
32
37
  packages_dir = Rails.root.join("packages/").to_s
33
- listener = Listen.to(plutonium_lib_dir, packages_dir, only: /\.rb$/) do |modified, added, removed|
38
+ reload_paths << packages_dir if File.directory?(packages_dir)
39
+
40
+ listener = Listen.to(*reload_paths, only: /\.rb$/) do |modified, added, removed|
34
41
  (modified + added).each do |file|
42
+ next if file == __FILE__ # reloading this file does nothing
43
+
35
44
  if file.starts_with?(packages_dir)
36
45
  # if package file was added, ignore it
37
46
  # otherwise rails gets mad at us since engines cannot be loaded after initial boot
@@ -40,18 +49,24 @@ module Plutonium
40
49
 
41
50
  case File.basename(file)
42
51
  when "engine.rb"
43
- # reload engines. due to how we load packages, rails does not support
52
+ # rails engines are loaded once,
53
+ # so in order to detect resource registration changes, we need to handle reloads ourselves
54
+
55
+ # load the engine and reload routes to pick up any registration changes
56
+ Rails.logger.debug "\nplutonium: reloaded #{file}\n"
44
57
  load file
45
- # reload routes to pick up any registration changes
46
58
  Rails.application.reload_routes!
47
59
  else
48
60
  # non engine package files are reloaded by rails automatically
49
61
  end
50
62
  else
51
- load file
63
+ Plutonium::ZEITWERK_LOADER.reload
64
+ load Plutonium.root.join("app", "views", "components", "base.rb")
65
+ load file # this just a lazy way to ensure we load files that do not contain constants like initializers
52
66
  end
67
+ Rails.logger.debug "\n\nplutonium: reload #{file}\n"
53
68
  rescue => e
54
- Rails.logger.error "\npu.hotreloader: failed to reload #{file}\n\n#{e}\n"
69
+ Rails.logger.error "\n\nplutonium: reload failed #{file}\n\n#{e}\n"
55
70
  end
56
71
  end
57
72
  listener.start
@@ -1,3 +1,5 @@
1
+ require "action_controller"
2
+
1
3
  module Plutonium
2
4
  module Refinements
3
5
  module ParameterRefinements
@@ -0,0 +1,5 @@
1
+ module Plutonium
2
+ module Resource
3
+ Context = Data.define :resource_class, :parent, :scope
4
+ end
5
+ end
@@ -0,0 +1,138 @@
1
+ require "action_controller"
2
+ require "pagy"
3
+
4
+ require File.expand_path("refinements/parameter_refinements", Plutonium.lib_root)
5
+ using Plutonium::Refinements::ParameterRefinements
6
+
7
+ module Plutonium
8
+ module Resource
9
+ module Controller
10
+ extend ActiveSupport::Concern
11
+ include Pagy::Backend
12
+ include Plutonium::Core::Controllers::Base
13
+ include Plutonium::Core::Controllers::Authorizable
14
+ include Plutonium::Core::Controllers::Presentable
15
+ include Plutonium::Core::Controllers::Queryable
16
+ include Plutonium::Core::Controllers::CrudActions
17
+ include Plutonium::Core::Controllers::InteractiveActions
18
+
19
+ included do
20
+ # we use class attribute since we want this value inherited
21
+ class_attribute :resource_class, instance_writer: false, instance_predicate: false
22
+
23
+ # https://github.com/ddnexus/pagy/blob/master/docs/extras/headers.md#headers
24
+ after_action { pagy_headers_merge(@pagy) if @pagy }
25
+
26
+ helper_method :current_parent, :resource_record, :resource_param_key, :resource_class
27
+ end
28
+
29
+ class_methods do
30
+ def controller_for(resource_class)
31
+ self.resource_class = resource_class
32
+ end
33
+ end
34
+
35
+ private
36
+
37
+ def policy_context
38
+ Plutonium::Resource::PolicyContext.new(
39
+ user: current_user,
40
+ resource_context: resource_context
41
+ )
42
+ end
43
+
44
+ def resource_record
45
+ @resource_record ||= (policy_scope(resource_class).from_path_param(params[:id]).first! if params[:id].present?)
46
+ end
47
+
48
+ def submitted_resource_params
49
+ @submitted_resource_params ||= begin
50
+ strong_parameters = resource_class.strong_parameters_for(*permitted_attributes)
51
+ params.require(resource_param_key).permit(*strong_parameters).nilify.to_h
52
+ end
53
+ end
54
+
55
+ def resource_params
56
+ input_params = submitted_resource_params.dup
57
+
58
+ # Override any entity scoping params
59
+ input_params[scoped_entity_param_key] = current_scoped_entity if scoped_to_entity?
60
+ input_params[:"#{scoped_entity_param_key}_id"] = current_scoped_entity.id if scoped_to_entity?
61
+ # Override any parent params
62
+ input_params[parent_input_param] = current_parent if current_parent.present?
63
+ input_params[:"#{parent_input_param}_id"] = current_parent.id if current_parent.present?
64
+
65
+ # additionally filter our input_params through our inputs
66
+ current_presenter.defined_inputs_for(*permitted_attributes).collect_all(input_params)
67
+ end
68
+
69
+ def resource_param_key
70
+ resource_class.model_name.singular_route_key
71
+ end
72
+
73
+ def resource_context
74
+ Plutonium::Resource::Context.new(
75
+ resource_class:,
76
+ parent: current_parent,
77
+ scope: scoped_to_entity? ? current_scoped_entity : nil
78
+ )
79
+ end
80
+
81
+ def resource_presenter(resource_class, resource_record)
82
+ presenter_class = "#{current_package}::#{resource_class}Presenter".constantize
83
+ presenter_class.new resource_context, resource_record
84
+ end
85
+
86
+ def resource_query_object(resource_class, params)
87
+ query_object_class = "#{current_package}::#{resource_class}QueryObject".constantize
88
+ query_object_class.new resource_context, params
89
+ end
90
+
91
+ # sets params on submitted_resource_params if they have been passed
92
+ def maybe_apply_submitted_resource_params!
93
+ # this is useful in dynamic forms as we can read the resource record to determine how to define our inputs
94
+ # we need to ensure that this is being called from get because
95
+ # it is potentially unsafe since we don't apply the input filter. see #resource_params
96
+ # would have been nice to be able to, but we can't until we have the presenter, and the presenter
97
+ # requires the resource_record for our dynamic forms
98
+ # is this perfect? no. but it works.
99
+ raise "🚨🚨🚨 this should be called from actions that are not persisting this data" unless request.method == "GET"
100
+
101
+ resource_record.attributes = submitted_resource_params if params[resource_param_key].present?
102
+ end
103
+
104
+ def current_parent
105
+ return unless parent_route_param.present?
106
+
107
+ @current_parent ||= begin
108
+ parent_route_key = parent_route_param.to_s.gsub(/_id$/, "").to_sym
109
+ parent_class = current_engine.registered_resource_route_key_lookup[parent_route_key]
110
+ parent_scope = parent_class.from_path_param(params[parent_route_param])
111
+ parent_scope = parent_scope.associated_with(current_scoped_entity) if scoped_to_entity?
112
+ parent_scope.first!
113
+ end
114
+ end
115
+
116
+ def parent_route_param
117
+ @parent_route_param ||= request.path_parameters.keys.reverse.find { |key| /_id$/.match? key }
118
+ end
119
+
120
+ def parent_input_param
121
+ return unless current_parent.present?
122
+
123
+ resource_class.reflect_on_all_associations(:belongs_to).find { |assoc| assoc.klass.name == current_parent.class.name }&.name&.to_sym
124
+ end
125
+
126
+ ############
127
+
128
+ # def current_package
129
+ # @current_package ||= self.class.module_parents[-2]
130
+ # end
131
+
132
+ def resource_url_args_for(*args, **kwargs)
133
+ kwargs[:parent] = current_parent unless kwargs.key?(:parent)
134
+ super(*args, **kwargs)
135
+ end
136
+ end
137
+ end
138
+ end
@@ -0,0 +1,8 @@
1
+ require "active_interaction"
2
+
3
+ module Plutonium
4
+ module Resource
5
+ class Interaction < ActiveInteraction::Base
6
+ end
7
+ end
8
+ end
@@ -1,11 +1,17 @@
1
1
  module Plutonium
2
- module Reactor
3
- class ResourcePolicy
2
+ module Resource
3
+ class Policy
4
4
  include Plutonium::Policy::Initializer
5
5
 
6
6
  class Scope < Plutonium::Policy::Scope
7
7
  end
8
8
 
9
+ def send_with_report(method)
10
+ raise NotImplementedError, "#{self.class.name} does not implement the required #{method}" unless respond_to? method
11
+
12
+ send method
13
+ end
14
+
9
15
  # Core actions
10
16
 
11
17
  def create?
@@ -42,10 +48,17 @@ module Plutonium
42
48
  update?
43
49
  end
44
50
 
51
+ def search?
52
+ index?
53
+ end
54
+
45
55
  # Core attributes
46
56
 
47
57
  def permitted_attributes_for_create
48
- autodetect_fields_for(:permitted_attributes_for_create) - [context.resource_context.resource_class.primary_key.to_sym, :created_at, :updated_at]
58
+ autodetect_fields_for(:permitted_attributes_for_create) - [
59
+ context.resource_context.resource_class.primary_key.to_sym, # primary_key
60
+ :created_at, :updated_at # timestamps
61
+ ]
49
62
  end
50
63
 
51
64
  def permitted_attributes_for_read
@@ -1,5 +1,5 @@
1
1
  module Plutonium
2
- module Reactor
2
+ module Resource
3
3
  PolicyContext = Data.define :user, :resource_context
4
4
  end
5
5
  end
@@ -0,0 +1,78 @@
1
+ module Plutonium
2
+ module Resource
3
+ class Presenter
4
+ include Plutonium::Core::Definers::FieldDefiner
5
+ include Plutonium::Core::Definers::ActionDefiner
6
+
7
+ def initialize(context, resource_record)
8
+ @context = context
9
+ @resource_record = resource_record
10
+
11
+ define_standard_actions
12
+ define_actions
13
+ define_fields
14
+ end
15
+
16
+ private
17
+
18
+ attr_reader :context, :resource_record
19
+
20
+ def define_fields
21
+ # override this in child presenters for custom field definitions
22
+ end
23
+
24
+ def define_actions
25
+ # override this in child presenters for custom action definitions
26
+ end
27
+
28
+ def define_standard_actions
29
+ define_action Plutonium::Core::Actions::NewAction.new(:new)
30
+ define_action Plutonium::Core::Actions::ShowAction.new(:show)
31
+ define_action Plutonium::Core::Actions::EditAction.new(:edit)
32
+ define_action Plutonium::Core::Actions::DestroyAction.new(:destroy)
33
+ end
34
+
35
+ # TODO: move this to its own definer
36
+ def define_interactive_action(name, interaction:, **)
37
+ define_action Plutonium::Core::Actions::InteractiveAction.new(name, interaction:, **)
38
+ end
39
+
40
+ # TODO: move this to its own definer
41
+ def define_nested_input(name, inputs:, model_class: nil, **options)
42
+ nested_attribute_options = resource_class.all_nested_attributes_options[name]
43
+
44
+ nested_attribute_options_class = nested_attribute_options&.[](:class)
45
+ if nested_attribute_options_class.nil? && model_class.nil?
46
+ raise ArgumentError, "model_class is required if your field is not an association or is polymorphic"
47
+ end
48
+ model_class ||= nested_attribute_options_class
49
+
50
+ macro = nested_attribute_options&.[](:macro)
51
+ allow_destroy = nested_attribute_options&.[](:allow_destroy).presence
52
+ update_only = nested_attribute_options&.[](:update_only).presence
53
+ limit = if macro == :has_one
54
+ 1
55
+ elsif options.key?(:limit)
56
+ options[:limit]
57
+ else
58
+ nested_attribute_options&.[](:limit)
59
+ end
60
+
61
+ input = Plutonium::Core::Fields::Inputs::NestedInput.new(
62
+ name,
63
+ inputs:,
64
+ allow_destroy: options.key?(:allow_destroy) ? options[:allow_destroy] : allow_destroy,
65
+ update_only: options.key?(:update_only) ? options[:update_only] : update_only,
66
+ limit: limit,
67
+ resource_class: model_class,
68
+ **options
69
+ )
70
+ yield input if block_given?
71
+
72
+ define_input name, input:
73
+ end
74
+
75
+ def resource_class = context.resource_class
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,219 @@
1
+ # TODO: refactor
2
+
3
+ module Plutonium
4
+ # TODO: make standard query type names e.g. search and scope configurable
5
+ module Resource
6
+ class QueryObject
7
+ class << self
8
+ end
9
+
10
+ class Query
11
+ include Plutonium::Core::Definers::InputDefiner
12
+
13
+ def apply(scope, params)
14
+ params = extract_query_params params
15
+
16
+ if input_definitions.size == params.size
17
+ apply_internal scope, params
18
+ else
19
+ scope
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ def apply_internal(scope, params)
26
+ raise NotImplementedError, "#{self.class}#apply_internal"
27
+ end
28
+
29
+ def extract_query_params(params)
30
+ input_definitions.collect_all(params).symbolize_keys
31
+ end
32
+
33
+ def resource_class = nil
34
+ end
35
+
36
+ class ScopeQuery < Query
37
+ attr_reader :name
38
+
39
+ def initialize(name)
40
+ @name = name
41
+ yield self if block_given?
42
+ end
43
+
44
+ private
45
+
46
+ def apply_internal(scope, params)
47
+ scope.send name, **params
48
+ end
49
+ end
50
+
51
+ class BlockQuery < Query
52
+ attr_reader :body
53
+
54
+ def initialize(body)
55
+ @body = body
56
+ yield self if block_given?
57
+ end
58
+
59
+ def apply_internal(scope, params)
60
+ if body.arity == 1
61
+ body.call scope
62
+ else
63
+ body.call scope, **params
64
+ end
65
+ end
66
+ end
67
+
68
+ attr_reader :search_filter, :search_query
69
+
70
+ def initialize(context, params)
71
+ @context = context
72
+
73
+ define_standard_queries
74
+ define_scopes
75
+ define_filters
76
+ define_sorters
77
+
78
+ extract_filter_params(params)
79
+ extract_sort_params(params)
80
+ # @params = params.except(:scope, :search, :sort_fields, :sort_directions)
81
+ end
82
+
83
+ def build_url(**options)
84
+ q = {}
85
+
86
+ q[:search] = options.key?(:search) ? options[:search].presence : search_query
87
+ q[:scope] = options.key?(:scope) ? options[:scope].presence : selected_scope_filter
88
+
89
+ q[:sort_directions] = selected_sort_directions.dup
90
+ q[:sort_fields] = selected_sort_fields.dup
91
+ if (sort = options[:sort])
92
+ if options[:reset]
93
+ q[:sort_fields].delete_if { |e| e == sort.to_s }
94
+ q[:sort_directions].delete sort
95
+ else
96
+ q[:sort_fields] << sort.to_s unless q[:sort_fields].include?(sort.to_s)
97
+
98
+ sort_direction = selected_sort_directions[sort]
99
+ if sort_direction.nil?
100
+ q[:sort_directions][sort] = "ASC"
101
+ elsif sort_direction == "ASC"
102
+ q[:sort_directions][sort] = "DESC"
103
+ else
104
+ q[:sort_fields].delete_if { |e| e == sort.to_s }
105
+ q[:sort_directions].delete sort
106
+ end
107
+ end
108
+ end
109
+
110
+ "?#{{q: q}.to_param}"
111
+ end
112
+
113
+ def apply(scope)
114
+ scope = search_filter.apply(scope, {search: search_query}) if search_filter.present?
115
+ scope = scope_definitions[selected_scope_filter].apply(scope, {}) if selected_scope_filter.present?
116
+ selected_sort_fields.each do |name|
117
+ sorter = sort_definitions[name]
118
+ next unless sorter.present?
119
+
120
+ params = {direction: selected_sort_directions[name] || "ASC"}
121
+ scope = sorter.apply(scope, params)
122
+ end
123
+ scope
124
+ end
125
+
126
+ def scope_definitions = @scope_definitions ||= {}.with_indifferent_access
127
+
128
+ def filter_definitions = @filter_definitions ||= {}.with_indifferent_access
129
+
130
+ def sort_definitions = @sort_definitions ||= {}.with_indifferent_access
131
+
132
+ def sort_params_for(name)
133
+ return unless sort_definitions[name]
134
+
135
+ {
136
+ url: build_url(sort: name),
137
+ reset_url: build_url(sort: name, reset: true),
138
+ position: selected_sort_fields.index(name.to_s),
139
+ direction: selected_sort_directions[name]
140
+ }
141
+ end
142
+
143
+ private
144
+
145
+ attr_reader :context, :selected_sort_fields, :selected_sort_directions, :selected_scope_filter
146
+
147
+ def define_filters
148
+ end
149
+
150
+ def define_scopes
151
+ end
152
+
153
+ def define_sorters
154
+ end
155
+
156
+ def define_standard_queries
157
+ define_search(:search) if resource_class.respond_to?(:search)
158
+ end
159
+
160
+ def define_filter(name, body = nil, &)
161
+ body ||= name
162
+ filter_definitions[name] = build_query(body, &)
163
+ end
164
+
165
+ def define_scope(name, body = nil)
166
+ body ||= name
167
+ scope_definitions[name] = build_query(body)
168
+ end
169
+
170
+ def define_sort(name, body = nil)
171
+ if body.nil?
172
+ sort_field = if resource_class.primary_key == name.to_s || resource_class.content_column_field_names.include?(name)
173
+ name
174
+ elsif resource_class.belongs_to_association_field_names.include? name
175
+ resource_class.reflect_on_association(name).foreign_key.to_sym
176
+ else
177
+ raise "Unable to determine sort logic for '#{body}'"
178
+ end
179
+ body = lambda { |scope, direction:| scope.order(sort_field => direction) }
180
+ end
181
+
182
+ sort_definitions[name] = build_query(body) do |query|
183
+ query.define_input :direction
184
+ end
185
+ end
186
+
187
+ def define_search(body)
188
+ @search_filter = build_query(body) do |query|
189
+ query.define_input :search
190
+ end
191
+ end
192
+
193
+ def extract_filter_params(params)
194
+ @search_query = params[:search]
195
+ @selected_scope_filter = params[:scope]
196
+ end
197
+
198
+ def extract_sort_params(params)
199
+ @selected_sort_fields = Array(params[:sort_fields])
200
+ @selected_sort_fields &= sort_definitions.keys
201
+
202
+ @selected_sort_directions = params[:sort_directions]&.slice(*sort_definitions.keys) || {}
203
+ @selected_sort_directions = @selected_sort_directions.map { |key, value| [key, {"DESC" => "DESC"}[value.upcase] || "ASC"] }.to_h.with_indifferent_access
204
+ end
205
+
206
+ def build_query(body, &)
207
+ case body
208
+ when Symbol
209
+ raise "Cannot find scope :#{body} on #{resource_class}" unless resource_class.respond_to? body
210
+ ScopeQuery.new(body, &)
211
+ else
212
+ BlockQuery.new(body, &)
213
+ end
214
+ end
215
+
216
+ def resource_class = context.resource_class
217
+ end
218
+ end
219
+ end