plutonium 0.6.2 → 0.8.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 (845) hide show
  1. checksums.yaml +4 -4
  2. data/.node-version +1 -0
  3. data/README copy.md +1 -2
  4. data/README.md +19 -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 +6 -0
  494. data/app/assets/js/controllers/dropdown_controller.js +12 -0
  495. data/app/assets/js/controllers/index.js +21 -0
  496. data/app/assets/js/plutonium.js +2 -0
  497. data/app/assets/js/turbo/index.js +5 -0
  498. data/app/assets/js/turbo/turbo_actions.js +8 -0
  499. data/app/assets/js/turbo/turbo_debug.js +30 -0
  500. data/app/assets/js/turbo/turbo_frame_monkey_patch.js +23 -0
  501. data/app/views/{resource → application}/_color_modes.html.erb +3 -1
  502. data/app/views/application/_flash.html.erb +1 -0
  503. data/app/views/application/_resource_header.html.erb +721 -0
  504. data/app/views/application/_resource_sidebar.html.erb +12 -0
  505. data/app/views/components/action_button/action_button_component.html.erb +7 -0
  506. data/app/views/components/action_button/action_button_component.rb +15 -0
  507. data/app/views/components/base.rb +50 -0
  508. data/app/views/components/block/block_component.html.erb +3 -0
  509. data/app/views/components/block/block_component.rb +40 -0
  510. data/app/views/components/breadcrumbs/breadcrumbs_component.html.erb +96 -0
  511. data/app/views/components/breadcrumbs/breadcrumbs_component.rb +9 -0
  512. data/app/views/components/button/button_component.html.erb +11 -0
  513. data/app/views/components/button/button_component.rb +123 -0
  514. data/app/views/components/dyna_frame_content/dyna_frame_content_component.html.erb +7 -0
  515. data/app/views/components/dyna_frame_content/dyna_frame_content_component.rb +6 -0
  516. data/app/views/components/dyna_frame_host/dyna_frame_host_component.html.erb +4 -0
  517. data/app/views/components/dyna_frame_host/dyna_frame_host_component.rb +11 -0
  518. data/app/views/components/empty_card/empty_card_component.html.erb +6 -0
  519. data/app/views/components/empty_card/empty_card_component.rb +7 -0
  520. data/app/views/components/form/form_builder.rb +71 -0
  521. data/app/views/components/form/form_component.html.erb +77 -0
  522. data/app/views/components/form/form_component.rb +23 -0
  523. data/app/views/components/form/form_controller.js +13 -0
  524. data/app/views/components/header/header_component.html.erb +1 -0
  525. data/app/views/components/header/header_component.rb +7 -0
  526. data/app/views/components/interactive_action_form/interactive_action_form_component.html.erb +41 -0
  527. data/app/views/components/interactive_action_form/interactive_action_form_component.rb +8 -0
  528. data/app/views/components/interactive_action_form/interactive_action_form_controller.js +13 -0
  529. data/app/views/components/pagination/pagination_component.html.erb +6 -0
  530. data/app/views/components/pagination/pagination_component.rb +91 -0
  531. data/app/views/components/panel/panel_component.html.erb +10 -0
  532. data/app/views/components/panel/panel_component.rb +11 -0
  533. data/app/views/components/sidebar/sidebar_component.html.erb +154 -0
  534. data/app/views/components/sidebar/sidebar_component.rb +15 -0
  535. data/app/views/components/sidebar_menu/sidebar_menu_component.html.erb +3 -0
  536. data/app/views/components/sidebar_menu/sidebar_menu_component.rb +13 -0
  537. data/app/views/components/sidebar_menu_item/sidebar_menu_item_component.html.erb +72 -0
  538. data/app/views/components/sidebar_menu_item/sidebar_menu_item_component.rb +23 -0
  539. data/app/views/components/skeleton/table/table_component.html.erb +18 -0
  540. data/app/views/components/skeleton/table/table_component.rb +6 -0
  541. data/app/views/components/tab_bar/tab_bar_component.html.erb +11 -0
  542. data/app/views/components/tab_bar/tab_bar_component.rb +9 -0
  543. data/app/views/components/tab_bar/tab_bar_controller.js +8 -0
  544. data/app/views/components/table/table_component.html.erb +92 -0
  545. data/app/views/components/table/table_component.rb +63 -0
  546. data/app/views/components/table/table_controller.js +8 -0
  547. data/app/views/components/table_search_input/table_search_input_component.html.erb +42 -0
  548. data/app/views/components/table_search_input/table_search_input_component.rb +10 -0
  549. data/app/views/components/table_search_input/table_search_input_controller.js +8 -0
  550. data/app/views/components/table_toolbar/table_toolbar_component.html.erb +7 -0
  551. data/app/views/components/table_toolbar/table_toolbar_component.rb +9 -0
  552. data/app/views/components/table_toolbar/table_toolbar_controller.js +8 -0
  553. data/app/views/components/toolbar/toolbar_component.html.erb +67 -0
  554. data/app/views/components/toolbar/toolbar_component.rb +18 -0
  555. data/app/views/components/toolbar/toolbar_controller.js +8 -0
  556. data/app/views/layouts/resource.html copy.erb +51 -0
  557. data/app/views/layouts/resource.html.erb +32 -25
  558. data/app/views/layouts/rodauth.html.erb +32 -0
  559. data/app/views/resource/_interactive_resource_action_form.html.erb +4 -26
  560. data/app/views/resource/_resource_details.html.erb +26 -0
  561. data/app/views/resource/{_resource.rabl → _resource_details.rabl} +1 -1
  562. data/app/views/resource/_resource_form.html.erb +5 -0
  563. data/app/views/resource/_resource_table.html.erb +15 -0
  564. data/app/views/resource/edit.html.erb +4 -9
  565. data/app/views/resource/index.html.erb +4 -18
  566. data/app/views/resource/interactive_resource_collection_action.html.erb +3 -10
  567. data/app/views/resource/interactive_resource_record_action.html.erb +3 -10
  568. data/app/views/resource/interactive_resource_recordless_action.html.erb +3 -10
  569. data/app/views/resource/new.html.erb +3 -10
  570. data/app/views/resource/show.html.erb +4 -13
  571. data/app/views/resource/show.rabl +1 -1
  572. data/brakeman.ignore +5 -5
  573. data/build.js +12 -0
  574. data/config/initializers/hotwire_turbo_monkey_patches.rb +12 -0
  575. data/{lib/plutonium → config}/initializers/pagy.rb +0 -1
  576. data/config/initializers/simple_form.rb +54 -0
  577. data/lib/active_model/validations/array_validator.rb +1 -1
  578. data/lib/active_model/validations/attached_validator.rb +1 -1
  579. data/lib/active_model/validations/url_validator.rb +1 -1
  580. data/lib/generators/pu/core/install/install_generator.rb +1 -1
  581. data/lib/generators/pu/core/install/templates/app/controllers/resource_controller.rb.tt +2 -1
  582. data/lib/generators/pu/core/install/templates/app/interactions/resource_interaction.rb.tt +1 -1
  583. data/lib/generators/pu/core/install/templates/app/models/resource_record.rb.tt +1 -1
  584. data/lib/generators/pu/core/install/templates/app/policies/resource_policy.rb.tt +1 -1
  585. data/lib/generators/pu/core/install/templates/app/presenters/resource_presenter.rb.tt +1 -1
  586. data/lib/generators/pu/core/install/templates/app/query_objects/resource_query_object.rb.tt +2 -0
  587. data/lib/generators/pu/core/install/templates/config/packages.rb +1 -3
  588. data/lib/generators/pu/gem/pagy/pagy_generator.rb +1 -1
  589. data/lib/generators/pu/gem/rabl/rabl_generator.rb +1 -1
  590. data/lib/generators/pu/gem/simple_form/simple_form_generator.rb +1 -1
  591. data/lib/generators/pu/gen/component/component_generator.rb +87 -0
  592. data/lib/generators/pu/gen/component/templates/component.html.erb.tt +3 -0
  593. data/lib/generators/pu/gen/component/templates/component.rb.tt +9 -0
  594. data/lib/generators/pu/gen/component/templates/controller.js.tt +8 -0
  595. data/lib/generators/pu/lib/plutonium_generators/concerns/actions.rb +353 -0
  596. data/lib/generators/pu/lib/plutonium_generators/concerns/config.rb +39 -0
  597. data/lib/generators/pu/lib/plutonium_generators/concerns/logger.rb +36 -0
  598. data/lib/generators/pu/lib/plutonium_generators/concerns/serializer.rb +39 -0
  599. data/lib/generators/pu/lib/plutonium_generators/generator.rb +86 -0
  600. data/lib/generators/pu/lib/plutonium_generators/installer.rb +205 -0
  601. data/lib/generators/pu/lib/plutonium_generators/model_generator.rb +151 -0
  602. data/lib/generators/pu/lib/plutonium_generators.rb +7 -0
  603. data/lib/generators/pu/pkg/app/app_generator.rb +14 -4
  604. data/lib/generators/pu/pkg/app/templates/app/controllers/app_controller.rb.tt +5 -0
  605. data/lib/generators/pu/pkg/app/templates/app/controllers/dashboard_controller.rb.tt +6 -0
  606. data/lib/generators/pu/pkg/app/templates/app/controllers/{resource_controller.rb.tt → package_controller.rb.tt} +3 -3
  607. data/lib/generators/pu/pkg/app/templates/app/{interactions/resource_interaction.rb.tt → query_objects/resource_query_object.rb.tt} +1 -1
  608. data/lib/generators/pu/pkg/app/templates/app/views/package/dashboard/index.html.erb +23 -0
  609. data/lib/generators/pu/pkg/app/templates/config/routes.rb.tt +5 -3
  610. data/lib/generators/pu/pkg/feature/feature_generator.rb +4 -4
  611. data/lib/generators/pu/pkg/feature/templates/app/query_objects/resource_query_object.rb.tt +4 -0
  612. data/lib/generators/pu/{resource → res}/conn/conn_generator.rb +3 -2
  613. data/lib/generators/pu/res/conn/templates/.keep +0 -0
  614. data/lib/generators/pu/{resource → res}/conn/templates/app/controllers/resource_controller.rb.tt +1 -1
  615. data/lib/generators/pu/res/conn/templates/app/query_objects/resource_query_object.rb.tt +3 -0
  616. data/lib/generators/pu/res/model/model_generator.rb +36 -0
  617. data/lib/generators/pu/{resource → res}/model/templates/model.rb.tt +1 -1
  618. data/lib/generators/pu/res/scaffold/scaffold_generator.rb +43 -0
  619. data/lib/generators/pu/res/scaffold/templates/.keep +0 -0
  620. data/lib/generators/pu/{resource/model → res/scaffold}/templates/policy.rb.tt +2 -2
  621. data/lib/generators/pu/{resource/model → res/scaffold}/templates/presenter.rb.tt +0 -5
  622. data/lib/generators/pu/res/scaffold/templates/query_object.rb.tt +17 -0
  623. data/lib/generators/pu/rodauth/account_generator.rb +6 -17
  624. data/lib/generators/pu/rodauth/concerns/account_selector.rb +5 -1
  625. data/lib/generators/pu/rodauth/migration/active_record/base.erb +0 -4
  626. data/lib/generators/pu/rodauth/migration_generator.rb +2 -4
  627. data/lib/generators/pu/rodauth/templates/app/controllers/plugin_controller.rb.tt +11 -1
  628. data/lib/generators/pu/rodauth/templates/app/controllers/rodauth_controller.rb.tt +2 -1
  629. data/lib/generators/pu/rodauth/templates/app/mailers/account_mailer.rb.tt +1 -1
  630. data/lib/generators/pu/rodauth/templates/app/misc/account_rodauth_plugin.rb.tt +26 -11
  631. data/lib/generators/pu/rodauth/templates/app/misc/rodauth_plugin.rb.tt +1 -1
  632. data/lib/generators/pu/rodauth/templates/app/models/account.rb.tt +4 -1
  633. data/lib/generators/pu/rodauth/views_generator.rb +1 -14
  634. data/lib/plutonium/application/controller.rb +43 -0
  635. data/lib/plutonium/auth/{public_access.rb → public.rb} +1 -1
  636. data/lib/plutonium/auth.rb +0 -5
  637. data/lib/plutonium/builders/menus/sidebar_menu.rb.bk +26 -0
  638. data/lib/plutonium/builders/menus/sidebar_menu_item.rb.bk +28 -0
  639. data/lib/plutonium/component_registry.rb +19 -0
  640. data/lib/plutonium/config.rb +17 -2
  641. data/lib/plutonium/core/action.rb +9 -6
  642. data/lib/plutonium/core/actions/collection.rb +4 -0
  643. data/lib/plutonium/core/actions/destroy_action.rb +5 -3
  644. data/lib/plutonium/core/actions/edit_action.rb +5 -3
  645. data/lib/plutonium/core/actions/interactive_action.rb +1 -1
  646. data/lib/plutonium/core/actions/new_action.rb +5 -3
  647. data/lib/plutonium/core/actions/show_action.rb +5 -3
  648. data/lib/plutonium/core/autodiscovery/input_discoverer.rb +0 -2
  649. data/lib/plutonium/core/autodiscovery/renderer_discoverer.rb +0 -2
  650. data/lib/plutonium/core/controllers/authorizable.rb +3 -5
  651. data/lib/plutonium/core/controllers/base.rb +86 -0
  652. data/lib/plutonium/core/controllers/bootable.rb +5 -24
  653. data/lib/plutonium/core/controllers/crud_actions.rb +43 -8
  654. data/lib/plutonium/core/controllers/entity_scoping.rb +16 -5
  655. data/lib/plutonium/core/controllers/interactive_actions.rb +9 -7
  656. data/lib/plutonium/core/controllers/presentable.rb +11 -11
  657. data/lib/plutonium/core/controllers/queryable.rb +26 -0
  658. data/lib/plutonium/core/definers/input_definer.rb +47 -7
  659. data/lib/plutonium/core/definers/renderer_definer.rb +5 -3
  660. data/lib/plutonium/core/fields/inputs/base.rb +3 -3
  661. data/lib/plutonium/core/fields/inputs/date_time_input.rb +13 -0
  662. data/lib/plutonium/core/fields/inputs/factory.rb +13 -4
  663. data/lib/plutonium/core/fields/inputs/noop_input.rb +1 -1
  664. data/lib/plutonium/core/fields/inputs/phone_input.rb +22 -0
  665. data/lib/plutonium/core/fields/inputs/polymorphic_belongs_to_association_input.rb +47 -0
  666. data/lib/plutonium/core/fields/inputs/simple_form_association_input.rb +3 -2
  667. data/lib/plutonium/core/fields/inputs/simple_form_input.rb +4 -1
  668. data/lib/plutonium/core/fields/renderers/association_renderer.rb +4 -7
  669. data/lib/plutonium/core/ui/collection.rb +12 -8
  670. data/lib/plutonium/core/ui/detail.rb +8 -5
  671. data/lib/plutonium/core/ui/form.rb +6 -5
  672. data/lib/plutonium/helpers/action_buttons_helper.rb +23 -23
  673. data/lib/plutonium/helpers/application_helper.rb +0 -4
  674. data/lib/plutonium/helpers/attachment_helper.rb +1 -1
  675. data/lib/plutonium/helpers/component_helper.rb +14 -0
  676. data/lib/plutonium/helpers/display_helper.rb +6 -6
  677. data/lib/plutonium/helpers/form_helper.rb +29 -10
  678. data/lib/plutonium/helpers/table_helper.rb +35 -0
  679. data/lib/plutonium/helpers/turbo_helper.rb +2 -2
  680. data/lib/plutonium/helpers.rb +6 -19
  681. data/lib/plutonium/icons.rb +25 -0
  682. data/lib/plutonium/lib/after_commit.rb +2 -2
  683. data/lib/plutonium/{packaging → pkg}/app.rb +8 -6
  684. data/lib/plutonium/{packaging/package.rb → pkg/base.rb} +6 -2
  685. data/lib/plutonium/{packaging → pkg}/feature.rb +2 -2
  686. data/lib/plutonium/preserved__/{field.rb → field.rb.bk} +1 -1
  687. data/lib/plutonium/preserved__/{input.rb → input.rb.bk} +1 -1
  688. data/lib/plutonium/railtie.rb +17 -3
  689. data/lib/plutonium/reactor/core.rb +34 -19
  690. data/lib/plutonium/refinements/parameter_refinements.rb +2 -0
  691. data/lib/plutonium/resource/context.rb +5 -0
  692. data/lib/plutonium/resource/controller.rb +138 -0
  693. data/lib/plutonium/resource/interaction.rb +8 -0
  694. data/lib/plutonium/{reactor/resource_policy.rb → resource/policy.rb} +10 -3
  695. data/lib/plutonium/{reactor → resource}/policy_context.rb +1 -1
  696. data/lib/plutonium/{reactor/resource_presenter.rb → resource/presenter.rb} +2 -6
  697. data/lib/plutonium/resource/query_object.rb +219 -0
  698. data/lib/plutonium/{reactor/resource_record.rb → resource/record.rb} +55 -35
  699. data/lib/plutonium/rodauth/controller_methods.rb +12 -0
  700. data/lib/plutonium/{simple_form_components → simple_form}/attachment_component.rb +2 -0
  701. data/lib/plutonium/{simple_form_components → simple_form}/input_group_component.rb +2 -0
  702. data/lib/plutonium/version.rb +1 -1
  703. data/lib/plutonium.rb +33 -16
  704. data/package-lock.json +2523 -0
  705. data/package.json +21 -0
  706. data/postcss.config.js +11 -0
  707. data/public/plutonium-assets/application.css +1617 -811
  708. data/public/plutonium-assets/application.js +299 -300
  709. data/tailwind.config.js +91 -0
  710. metadata +754 -176
  711. data/app/views/resource/_details.html.erb +0 -6
  712. data/app/views/resource/_empty_card.html.erb +0 -12
  713. data/app/views/resource/_form.html.erb +0 -32
  714. data/app/views/resource/_header.html.erb +0 -8
  715. data/app/views/resource/_messages.html.erb +0 -1
  716. data/app/views/resource/_pagination.html.erb +0 -6
  717. data/app/views/resource/_pagy_pagination.html.erb +0 -15
  718. data/app/views/resource/_resource.html.erb +0 -1
  719. data/app/views/resource/_sidebar.html.erb +0 -11
  720. data/app/views/resource/_sidebar_menu.html.erb +0 -1
  721. data/app/views/resource/_table.html.erb +0 -78
  722. data/app/views/resource/_table_actions.html.erb +0 -15
  723. data/app/views/resource/_toolbar.html.erb +0 -22
  724. data/app/views/resource/_toolbar_actions.html.erb +0 -16
  725. data/app/views/resource/_toolbar_breadcrumbs.html.erb +0 -32
  726. data/app/views/resource/_toolbar_search_input.erb +0 -27
  727. data/lib/generators/pu/resource/model/model_generator.rb +0 -163
  728. data/lib/generators/pu/resource/scaffold/scaffold_generator.rb +0 -219
  729. data/lib/generators/pu/resource/scaffold/templates/app/controllers/admin_resources/resource_controller.rb.tt +0 -7
  730. data/lib/generators/pu/resource/scaffold/templates/app/controllers/entity_resources/resource_controller.rb.tt +0 -7
  731. data/lib/generators/pu/resource/scaffold/templates/app/policies/resources/admin/resource_policy.rb.tt +0 -22
  732. data/lib/generators/pu/resource/scaffold/templates/app/policies/resources/entity/resource_policy.rb.tt +0 -22
  733. data/lib/generators/pu/resource/scaffold/templates/app/policies/resources/resource_policy.rb.tt +0 -13
  734. data/lib/generators/pu/resource/scaffold/templates/app/resources/resource/admin_presenter.rb.tt +0 -7
  735. data/lib/generators/pu/resource/scaffold/templates/app/resources/resource/entity_presenter.rb.tt +0 -7
  736. data/lib/generators/pu/resource/scaffold/templates/app/resources/resource/presenter.rb.tt +0 -23
  737. data/lib/generators/pu/resource/scaffold/templates/app/views/resources/resource/_resource.html.erb.tt +0 -3
  738. data/lib/generators/pu/resource/scaffold/templates/app/views/resources/resource/_resource.rabl +0 -7
  739. data/lib/generators/pu/rodauth/templates/app/views/rodauth/_email_auth_request_form.html.erb +0 -7
  740. data/lib/generators/pu/rodauth/templates/app/views/rodauth/_login_form.html.erb +0 -26
  741. data/lib/generators/pu/rodauth/templates/app/views/rodauth/_login_form_footer.html.erb +0 -9
  742. data/lib/generators/pu/rodauth/templates/app/views/rodauth/add_recovery_codes.html.erb +0 -6
  743. data/lib/generators/pu/rodauth/templates/app/views/rodauth/change_login.html.erb +0 -27
  744. data/lib/generators/pu/rodauth/templates/app/views/rodauth/change_password.html.erb +0 -27
  745. data/lib/generators/pu/rodauth/templates/app/views/rodauth/close_account.html.erb +0 -13
  746. data/lib/generators/pu/rodauth/templates/app/views/rodauth/confirm_password.html.erb +0 -11
  747. data/lib/generators/pu/rodauth/templates/app/views/rodauth/create_account.html.erb +0 -35
  748. data/lib/generators/pu/rodauth/templates/app/views/rodauth/email_auth.html.erb +0 -5
  749. data/lib/generators/pu/rodauth/templates/app/views/rodauth/login.html.erb +0 -4
  750. data/lib/generators/pu/rodauth/templates/app/views/rodauth/logout.html.erb +0 -14
  751. data/lib/generators/pu/rodauth/templates/app/views/rodauth/multi_phase_login.html.erb +0 -3
  752. data/lib/generators/pu/rodauth/templates/app/views/rodauth/otp_auth.html.erb +0 -15
  753. data/lib/generators/pu/rodauth/templates/app/views/rodauth/otp_disable.html.erb +0 -13
  754. data/lib/generators/pu/rodauth/templates/app/views/rodauth/otp_setup.html.erb +0 -41
  755. data/lib/generators/pu/rodauth/templates/app/views/rodauth/recovery_auth.html.erb +0 -11
  756. data/lib/generators/pu/rodauth/templates/app/views/rodauth/recovery_codes.html.erb +0 -13
  757. data/lib/generators/pu/rodauth/templates/app/views/rodauth/remember.html.erb +0 -22
  758. data/lib/generators/pu/rodauth/templates/app/views/rodauth/reset_password.html.erb +0 -19
  759. data/lib/generators/pu/rodauth/templates/app/views/rodauth/reset_password_request.html.erb +0 -17
  760. data/lib/generators/pu/rodauth/templates/app/views/rodauth/sms_auth.html.erb +0 -15
  761. data/lib/generators/pu/rodauth/templates/app/views/rodauth/sms_confirm.html.erb +0 -15
  762. data/lib/generators/pu/rodauth/templates/app/views/rodauth/sms_disable.html.erb +0 -13
  763. data/lib/generators/pu/rodauth/templates/app/views/rodauth/sms_request.html.erb +0 -5
  764. data/lib/generators/pu/rodauth/templates/app/views/rodauth/sms_setup.html.erb +0 -23
  765. data/lib/generators/pu/rodauth/templates/app/views/rodauth/two_factor_auth.html.erb +0 -5
  766. data/lib/generators/pu/rodauth/templates/app/views/rodauth/two_factor_disable.html.erb +0 -13
  767. data/lib/generators/pu/rodauth/templates/app/views/rodauth/two_factor_manage.html.erb +0 -22
  768. data/lib/generators/pu/rodauth/templates/app/views/rodauth/unlock_account.html.erb +0 -15
  769. data/lib/generators/pu/rodauth/templates/app/views/rodauth/unlock_account_request.html.erb +0 -9
  770. data/lib/generators/pu/rodauth/templates/app/views/rodauth/verify_account.html.erb +0 -21
  771. data/lib/generators/pu/rodauth/templates/app/views/rodauth/verify_account_resend.html.erb +0 -17
  772. data/lib/generators/pu/rodauth/templates/app/views/rodauth/verify_login_change.html.erb +0 -5
  773. data/lib/generators/pu/rodauth/templates/app/views/rodauth/webauthn_auth.html.erb +0 -15
  774. data/lib/generators/pu/rodauth/templates/app/views/rodauth/webauthn_autofill.html.erb +0 -10
  775. data/lib/generators/pu/rodauth/templates/app/views/rodauth/webauthn_remove.html.erb +0 -23
  776. data/lib/generators/pu/rodauth/templates/app/views/rodauth/webauthn_setup.html.erb +0 -23
  777. data/lib/plutonium/core/actions.rb +0 -17
  778. data/lib/plutonium/core/app_controller.rb +0 -121
  779. data/lib/plutonium/core/autodiscovery.rb +0 -13
  780. data/lib/plutonium/core/controllers.rb +0 -16
  781. data/lib/plutonium/core/definers.rb +0 -14
  782. data/lib/plutonium/core/fields/inputs.rb +0 -20
  783. data/lib/plutonium/core/fields/renderers.rb +0 -16
  784. data/lib/plutonium/core/fields.rb +0 -12
  785. data/lib/plutonium/core/ui.rb +0 -13
  786. data/lib/plutonium/core.rb +0 -16
  787. data/lib/plutonium/helpers/menu_helper.rb +0 -69
  788. data/lib/plutonium/helpers/pagination_helper.rb +0 -9
  789. data/lib/plutonium/initializers/TODO +0 -2
  790. data/lib/plutonium/initializers/patches.rb +0 -2
  791. data/lib/plutonium/initializers/simple_form.rb +0 -405
  792. data/lib/plutonium/packaging.rb +0 -9
  793. data/lib/plutonium/policy.rb +0 -8
  794. data/lib/plutonium/reactor/resource_context.rb +0 -5
  795. data/lib/plutonium/reactor/resource_controller.rb +0 -131
  796. data/lib/plutonium/reactor/resource_interaction.rb +0 -8
  797. data/lib/plutonium/reactor.rb +0 -14
  798. /data/app/views/{resource/_flash.html.erb → application/_flash_alerts.html.erb} +0 -0
  799. /data/app/views/{resource/_toast.html.erb → application/_flash_toasts.html.erb} +0 -0
  800. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/_email_auth_request_form.html.erb +0 -0
  801. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/_login_form.html.erb +0 -0
  802. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/_login_form_footer.html.erb +0 -0
  803. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/add_recovery_codes.html.erb +0 -0
  804. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/change_login.html.erb +0 -0
  805. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/change_password.html.erb +0 -0
  806. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/close_account.html.erb +0 -0
  807. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/confirm_password.html.erb +0 -0
  808. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/create_account.html.erb +0 -0
  809. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/email_auth.html.erb +0 -0
  810. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/login.html.erb +0 -0
  811. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/logout.html.erb +0 -0
  812. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/multi_phase_login.html.erb +0 -0
  813. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/otp_auth.html.erb +0 -0
  814. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/otp_disable.html.erb +0 -0
  815. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/otp_setup.html.erb +0 -0
  816. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/recovery_auth.html.erb +0 -0
  817. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/recovery_codes.html.erb +0 -0
  818. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/remember.html.erb +0 -0
  819. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/reset_password.html.erb +0 -0
  820. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/reset_password_request.html.erb +0 -0
  821. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/sms_auth.html.erb +0 -0
  822. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/sms_confirm.html.erb +0 -0
  823. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/sms_disable.html.erb +0 -0
  824. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/sms_request.html.erb +0 -0
  825. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/sms_setup.html.erb +0 -0
  826. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/two_factor_auth.html.erb +0 -0
  827. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/two_factor_disable.html.erb +0 -0
  828. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/two_factor_manage.html.erb +0 -0
  829. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/unlock_account.html.erb +0 -0
  830. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/unlock_account_request.html.erb +0 -0
  831. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/verify_account.html.erb +0 -0
  832. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/verify_account_resend.html.erb +0 -0
  833. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/verify_login_change.html.erb +0 -0
  834. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/webauthn_auth.html.erb +0 -0
  835. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/webauthn_autofill.html.erb +0 -0
  836. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/webauthn_remove.html.erb +0 -0
  837. /data/{lib/generators/pu/rodauth/templates/app/views/rodauth/tailwind → app/views/rodauth}/webauthn_setup.html.erb +0 -0
  838. /data/{lib/plutonium → config}/initializers/rabl.rb +0 -0
  839. /data/lib/generators/pu/{resource/conn/templates → pkg/app/templates/app/views/package}/.keep +0 -0
  840. /data/lib/generators/pu/{resource → res}/conn/templates/app/policies/resource_policy.rb.tt +0 -0
  841. /data/lib/generators/pu/{resource → res}/conn/templates/app/presenters/resource_presenter.rb.tt +0 -0
  842. /data/lib/generators/pu/{resource → res}/model/USAGE +0 -0
  843. /data/lib/generators/pu/{resource → res}/model/templates/create_table_migration.rb.tt +0 -0
  844. /data/lib/generators/pu/{resource → res}/model/templates/module.rb.tt +0 -0
  845. /data/lib/generators/pu/{resource/model → res/scaffold}/templates/controller.rb.tt +0 -0
@@ -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,6 +1,6 @@
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
@@ -42,10 +42,17 @@ module Plutonium
42
42
  update?
43
43
  end
44
44
 
45
+ def search?
46
+ index?
47
+ end
48
+
45
49
  # Core attributes
46
50
 
47
51
  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]
52
+ autodetect_fields_for(:permitted_attributes_for_create) - [
53
+ context.resource_context.resource_class.primary_key.to_sym, # primary_key
54
+ :created_at, :updated_at # timestamps
55
+ ]
49
56
  end
50
57
 
51
58
  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
@@ -1,6 +1,6 @@
1
1
  module Plutonium
2
- module Reactor
3
- class ResourcePresenter
2
+ module Resource
3
+ class Presenter
4
4
  include Plutonium::Core::Definers::FieldDefiner
5
5
  include Plutonium::Core::Definers::ActionDefiner
6
6
 
@@ -13,10 +13,6 @@ module Plutonium
13
13
  define_fields
14
14
  end
15
15
 
16
- def search_field
17
- nil
18
- end
19
-
20
16
  private
21
17
 
22
18
  attr_reader :context, :resource_record
@@ -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
@@ -1,6 +1,6 @@
1
1
  module Plutonium
2
- module Reactor
3
- module ResourceRecord
2
+ module Resource
3
+ module Record
4
4
  extend ActiveSupport::Concern
5
5
 
6
6
  included do
@@ -10,10 +10,11 @@ module Plutonium
10
10
  named_scope = :"associated_with_#{record.model_name.singular}"
11
11
  return send(named_scope, record) if respond_to?(named_scope)
12
12
 
13
- # TOD: add suppport for polymorphic associations
14
-
13
+ # TODO: add suppport for polymorphic associations
15
14
  # TODO: add logging
16
- if (own_association = reflect_on_all_associations.find { |assoc| assoc.klass == record.class })
15
+ # TODO: memoize this
16
+
17
+ if (own_association = reflect_on_all_associations.find { |assoc| assoc.klass.name == record.class.name })
17
18
  case own_association.macro
18
19
  when :has_one
19
20
  joins(own_association.name).where({
@@ -28,7 +29,7 @@ module Plutonium
28
29
  else
29
30
  raise NotImplementedError, "associated_with->##{own_association.macro}"
30
31
  end
31
- elsif (record_association = record.class.reflect_on_all_associations.find { |assoc| assoc.klass == klass })
32
+ elsif (record_association = record.class.reflect_on_all_associations.find { |assoc| assoc.klass.name == klass.name })
32
33
  # TODO: add a warning here about a potentially poor performing query
33
34
  where(id: record.send(record_association.name))
34
35
  else
@@ -41,7 +42,7 @@ module Plutonium
41
42
  end
42
43
  end
43
44
 
44
- module ClassMethods
45
+ class_methods do
45
46
  def resource_field_names
46
47
  @resource_field_names ||= belongs_to_association_field_names +
47
48
  has_one_attached_field_names + has_one_association_field_names +
@@ -49,6 +50,29 @@ module Plutonium
49
50
  content_column_field_names
50
51
  end
51
52
 
53
+ def belongs_to(name, scope = nil, **options)
54
+ super(name, scope, **options)
55
+
56
+ if options[:polymorphic]
57
+ mod = Module.new
58
+ mod.module_eval <<-RUBY, __FILE__, __LINE__ + 1
59
+ extend ActiveSupport::Concern
60
+
61
+ def #{name}_sgid
62
+ #{name}&.to_signed_global_id
63
+ end
64
+
65
+ def #{name}_sgid=(sgid)
66
+ self.#{name} = GlobalID::Locator.locate_signed(sgid)
67
+ end
68
+
69
+ define_singleton_method(:to_s) { "Plutonium::Polymormorphic::BelongsTo(:#{name})" }
70
+ define_singleton_method(:inspect) { "Plutonium::Polymormorphic::BelongsTo(:#{name})" }
71
+ RUBY
72
+ include mod
73
+ end
74
+ end
75
+
52
76
  def belongs_to_association_field_names
53
77
  @belongs_to_association_field_names ||= reflect_on_all_associations(:belongs_to).map(&:name)
54
78
  end
@@ -66,15 +90,23 @@ module Plutonium
66
90
  end
67
91
 
68
92
  def has_one_attached_field_names
69
- @has_one_attached_field_names ||= reflect_on_all_attachments
70
- .map { |a| (a.macro == :has_one_attached) ? a.name : nil }
71
- .compact
93
+ @has_one_attached_field_names ||= if respond_to?(:reflect_on_all_attachments)
94
+ reflect_on_all_attachments
95
+ .map { |a| (a.macro == :has_one_attached) ? a.name : nil }
96
+ .compact
97
+ else
98
+ []
99
+ end
72
100
  end
73
101
 
74
102
  def has_many_attached_field_names
75
- @has_many_attached_field_names ||= reflect_on_all_attachments
76
- .map { |a| (a.macro == :has_many_attached) ? a.name : nil }
77
- .compact
103
+ @has_many_attached_field_names ||= if respond_to?(:reflect_on_all_attachments)
104
+ reflect_on_all_attachments
105
+ .map { |a| (a.macro == :has_many_attached) ? a.name : nil }
106
+ .compact
107
+ else
108
+ []
109
+ end
78
110
  end
79
111
 
80
112
  def content_column_field_names
@@ -94,34 +126,22 @@ module Plutonium
94
126
  # [:title, :body, {:images=>[]}, {:docs=>[]}]
95
127
  #
96
128
  def strong_parameters_for(*attributes)
129
+ # attributes that are passed but we do not have a model/database backed definition for e.g. virtual attributes.
130
+ unbacked = attributes - strong_parameters_definition.keys
131
+
132
+ # attributes backed by some model/database definition
97
133
  # {:name=>{:name=>nil}, :body=>{:body=>nil}, :cover_image=>{:cover_image=>nil}, :comments=>{:comment_ids=>[]}}
98
- strong_parameters_definition
134
+ backed = strong_parameters_definition.
99
135
  # {:name=>{:name=>nil}, :comments=>{:comment_ids=>[]}, :cover_image=>{:cover_image=>nil}}
100
- .slice(*attributes)
136
+ slice(*attributes).
101
137
  # [{:name=>nil}, {:comment_ids=>[]}, {:cover_image=>nil}]
102
- .values
138
+ values.
103
139
  # {:name=>nil, :comment_ids=>[], :cover_image=>nil}
104
- .reduce(:merge)
140
+ reduce(:merge)&.
105
141
  # [:name, {:comment_ids=>[]}, :cover_image]
106
- &.map { |key, value| value.nil? ? key : {key => value} } || {}
107
- end
108
-
109
- # Ransack
110
-
111
- def ransackable_attributes(_auth_object = nil)
112
- _ransackers.keys
113
- end
114
-
115
- def ransackable_associations(_auth_object = nil)
116
- [] # reflect_on_all_associations.map { |a| a.name.to_s }
117
- end
118
-
119
- def ransortable_attributes(auth_object = nil)
120
- ransackable_attributes(auth_object) + %w[id created_at updated_at]
121
- end
142
+ map { |key, value| value.nil? ? key : {key => value} } || {}
122
143
 
123
- def ransackable_scopes(_auth_object = nil)
124
- []
144
+ unbacked + backed
125
145
  end
126
146
 
127
147
  private
@@ -0,0 +1,12 @@
1
+ module Plutonium
2
+ module Rodauth
3
+ module ControllerMethods
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ layout "rodauth"
8
+ append_view_path File.expand_path("app/views", Plutonium.root)
9
+ end
10
+ end
11
+ end
12
+ end
@@ -1,3 +1,5 @@
1
+ require "simple_form"
2
+
1
3
  module Plutonium
2
4
  module SimpleForm
3
5
  module AttachmentComponent