rolemodel-rails 0.26.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 (251) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +21 -0
  3. data/README.md +161 -0
  4. data/Rakefile +6 -0
  5. data/lib/generators/rolemodel/README.md +29 -0
  6. data/lib/generators/rolemodel/USAGE +5 -0
  7. data/lib/generators/rolemodel/all_generator.rb +29 -0
  8. data/lib/generators/rolemodel/base_generator.rb +14 -0
  9. data/lib/generators/rolemodel/editors/README.md +9 -0
  10. data/lib/generators/rolemodel/editors/USAGE +9 -0
  11. data/lib/generators/rolemodel/editors/editors_generator.rb +30 -0
  12. data/lib/generators/rolemodel/editors/vscode_helpers.rb +22 -0
  13. data/lib/generators/rolemodel/github/README.md +23 -0
  14. data/lib/generators/rolemodel/github/USAGE +9 -0
  15. data/lib/generators/rolemodel/github/github_generator.rb +43 -0
  16. data/lib/generators/rolemodel/good_job/README.md +13 -0
  17. data/lib/generators/rolemodel/good_job/USAGE +5 -0
  18. data/lib/generators/rolemodel/good_job/good_job_generator.rb +73 -0
  19. data/lib/generators/rolemodel/good_job/templates/config/initializers/active_job.rb +17 -0
  20. data/lib/generators/rolemodel/good_job/templates/config/initializers/good_job.rb +24 -0
  21. data/lib/generators/rolemodel/heroku/README.md +8 -0
  22. data/lib/generators/rolemodel/heroku/USAGE +9 -0
  23. data/lib/generators/rolemodel/heroku/heroku_generator.rb +52 -0
  24. data/lib/generators/rolemodel/heroku/templates/Procfile +2 -0
  25. data/lib/generators/rolemodel/heroku/templates/app.json.tt +30 -0
  26. data/lib/generators/rolemodel/kaminari/README.md +14 -0
  27. data/lib/generators/rolemodel/kaminari/USAGE +5 -0
  28. data/lib/generators/rolemodel/kaminari/kaminari_generator.rb +17 -0
  29. data/lib/generators/rolemodel/kaminari/templates/app/views/kaminari/_first_page.html.slim +9 -0
  30. data/lib/generators/rolemodel/kaminari/templates/app/views/kaminari/_gap.html.slim +8 -0
  31. data/lib/generators/rolemodel/kaminari/templates/app/views/kaminari/_last_page.html.slim +9 -0
  32. data/lib/generators/rolemodel/kaminari/templates/app/views/kaminari/_next_page.html.slim +12 -0
  33. data/lib/generators/rolemodel/kaminari/templates/app/views/kaminari/_page.html.slim +10 -0
  34. data/lib/generators/rolemodel/kaminari/templates/app/views/kaminari/_paginator.html.slim +19 -0
  35. data/lib/generators/rolemodel/kaminari/templates/app/views/kaminari/_prev_page.html.slim +12 -0
  36. data/lib/generators/rolemodel/linters/README.md +32 -0
  37. data/lib/generators/rolemodel/linters/USAGE +5 -0
  38. data/lib/generators/rolemodel/linters/all_generator.rb +14 -0
  39. data/lib/generators/rolemodel/linters/eslint/README.md +5 -0
  40. data/lib/generators/rolemodel/linters/eslint/USAGE +8 -0
  41. data/lib/generators/rolemodel/linters/eslint/eslint_generator.rb +33 -0
  42. data/lib/generators/rolemodel/linters/eslint/templates/eslint.config.js +92 -0
  43. data/lib/generators/rolemodel/linters/rubocop/README.md +7 -0
  44. data/lib/generators/rolemodel/linters/rubocop/USAGE +9 -0
  45. data/lib/generators/rolemodel/linters/rubocop/rubocop_generator.rb +23 -0
  46. data/lib/generators/rolemodel/linters/rubocop/templates/lib/cops/form_error_response.rb +54 -0
  47. data/lib/generators/rolemodel/linters/rubocop/templates/lib/cops/no_chrome_tag.rb +45 -0
  48. data/lib/generators/rolemodel/lograge/README.md +10 -0
  49. data/lib/generators/rolemodel/lograge/USAGE +8 -0
  50. data/lib/generators/rolemodel/lograge/lograge_generator.rb +15 -0
  51. data/lib/generators/rolemodel/lograge/templates/config/initializers/lograge.rb +16 -0
  52. data/lib/generators/rolemodel/mailers/README.md +13 -0
  53. data/lib/generators/rolemodel/mailers/USAGE +22 -0
  54. data/lib/generators/rolemodel/mailers/mailers_generator.rb +99 -0
  55. data/lib/generators/rolemodel/mailers/templates/app/assets/stylesheets/mailer.scss +61 -0
  56. data/lib/generators/rolemodel/mailers/templates/app/mailers/example_mailer.rb +8 -0
  57. data/lib/generators/rolemodel/mailers/templates/app/mailers/staging_mailer_interceptor.rb +9 -0
  58. data/lib/generators/rolemodel/mailers/templates/app/views/example_mailer/example_email.html.slim +16 -0
  59. data/lib/generators/rolemodel/mailers/templates/app/views/layouts/mailer.html.slim +16 -0
  60. data/lib/generators/rolemodel/mailers/templates/config/initializers/premailer_rails.rb +15 -0
  61. data/lib/generators/rolemodel/mailers/templates/public/logo.png +0 -0
  62. data/lib/generators/rolemodel/mailers/templates/spec/mailers/previews/example_mailer_preview.rb +6 -0
  63. data/lib/generators/rolemodel/optics/README.md +8 -0
  64. data/lib/generators/rolemodel/optics/USAGE +5 -0
  65. data/lib/generators/rolemodel/optics/all_generator.rb +12 -0
  66. data/lib/generators/rolemodel/optics/base/README.md +9 -0
  67. data/lib/generators/rolemodel/optics/base/USAGE +5 -0
  68. data/lib/generators/rolemodel/optics/base/base_generator.rb +21 -0
  69. data/lib/generators/rolemodel/optics/icons/README.md +7 -0
  70. data/lib/generators/rolemodel/optics/icons/USAGE +8 -0
  71. data/lib/generators/rolemodel/optics/icons/icons_generator.rb +48 -0
  72. data/lib/generators/rolemodel/optics/icons/templates/app/helpers/icon_helper.rb.tt +24 -0
  73. data/lib/generators/rolemodel/optics/icons/templates/app/icon_builders/custom_icon_builder.rb +53 -0
  74. data/lib/generators/rolemodel/optics/icons/templates/app/icon_builders/feather_icon_builder.rb +22 -0
  75. data/lib/generators/rolemodel/optics/icons/templates/app/icon_builders/icon_builder.rb +73 -0
  76. data/lib/generators/rolemodel/optics/icons/templates/app/icon_builders/lucide_icon_builder.rb +22 -0
  77. data/lib/generators/rolemodel/optics/icons/templates/app/icon_builders/material_icon_builder.rb +31 -0
  78. data/lib/generators/rolemodel/optics/icons/templates/app/icon_builders/phosphor_icon_builder.rb +27 -0
  79. data/lib/generators/rolemodel/optics/icons/templates/app/icon_builders/tabler_icon_builder.rb +22 -0
  80. data/lib/generators/rolemodel/react/README.md +12 -0
  81. data/lib/generators/rolemodel/react/USAGE +5 -0
  82. data/lib/generators/rolemodel/react/react_generator.rb +36 -0
  83. data/lib/generators/rolemodel/react/templates/app/helpers/react_helper.rb +11 -0
  84. data/lib/generators/rolemodel/react/templates/app/javascript/components/HelloReact.jsx +14 -0
  85. data/lib/generators/rolemodel/react/templates/app/javascript/controllers/react_controller.js +24 -0
  86. data/lib/generators/rolemodel/readme/README.md +9 -0
  87. data/lib/generators/rolemodel/readme/USAGE +8 -0
  88. data/lib/generators/rolemodel/readme/readme_generator.rb +11 -0
  89. data/lib/generators/rolemodel/readme/templates/README.md.erb +116 -0
  90. data/lib/generators/rolemodel/replace_content_helper.rb +29 -0
  91. data/lib/generators/rolemodel/saas/README.md +7 -0
  92. data/lib/generators/rolemodel/saas/USAGE +5 -0
  93. data/lib/generators/rolemodel/saas/all_generator.rb +15 -0
  94. data/lib/generators/rolemodel/saas/devise/README.md +24 -0
  95. data/lib/generators/rolemodel/saas/devise/USAGE +25 -0
  96. data/lib/generators/rolemodel/saas/devise/devise_generator.rb +172 -0
  97. data/lib/generators/rolemodel/saas/devise/templates/app/assets/stylesheets/login.css +30 -0
  98. data/lib/generators/rolemodel/saas/devise/templates/app/controllers/admin/users_controller.rb +34 -0
  99. data/lib/generators/rolemodel/saas/devise/templates/app/controllers/application_controller.rb +11 -0
  100. data/lib/generators/rolemodel/saas/devise/templates/app/controllers/users/invitations_controller.rb +77 -0
  101. data/lib/generators/rolemodel/saas/devise/templates/app/controllers/users/omniauth_callbacks_controller.rb +30 -0
  102. data/lib/generators/rolemodel/saas/devise/templates/app/controllers/users/registrations_controller.rb +80 -0
  103. data/lib/generators/rolemodel/saas/devise/templates/app/views/admin/users/edit.html.slim +10 -0
  104. data/lib/generators/rolemodel/saas/devise/templates/app/views/admin/users/index.html.slim +27 -0
  105. data/lib/generators/rolemodel/saas/devise/templates/app/views/devise/confirmations/new.html.slim +11 -0
  106. data/lib/generators/rolemodel/saas/devise/templates/app/views/devise/invitations/edit.html.slim +13 -0
  107. data/lib/generators/rolemodel/saas/devise/templates/app/views/devise/invitations/new.html.slim +14 -0
  108. data/lib/generators/rolemodel/saas/devise/templates/app/views/devise/mailer/confirmation_instructions.html.slim +3 -0
  109. data/lib/generators/rolemodel/saas/devise/templates/app/views/devise/mailer/email_changed.html.slim +5 -0
  110. data/lib/generators/rolemodel/saas/devise/templates/app/views/devise/mailer/invitation_instructions.html.slim +11 -0
  111. data/lib/generators/rolemodel/saas/devise/templates/app/views/devise/mailer/invitation_instructions.text.slim +6 -0
  112. data/lib/generators/rolemodel/saas/devise/templates/app/views/devise/mailer/password_change.html.slim +2 -0
  113. data/lib/generators/rolemodel/saas/devise/templates/app/views/devise/mailer/reset_password_instructions.html.slim +5 -0
  114. data/lib/generators/rolemodel/saas/devise/templates/app/views/devise/mailer/unlock_instructions.html.slim +4 -0
  115. data/lib/generators/rolemodel/saas/devise/templates/app/views/devise/passwords/edit.html.slim +13 -0
  116. data/lib/generators/rolemodel/saas/devise/templates/app/views/devise/passwords/new.html.slim +11 -0
  117. data/lib/generators/rolemodel/saas/devise/templates/app/views/devise/registrations/edit.html.slim +34 -0
  118. data/lib/generators/rolemodel/saas/devise/templates/app/views/devise/registrations/new.html.slim +17 -0
  119. data/lib/generators/rolemodel/saas/devise/templates/app/views/devise/sessions/new.html.slim +14 -0
  120. data/lib/generators/rolemodel/saas/devise/templates/app/views/devise/shared/_error_messages.html.slim +9 -0
  121. data/lib/generators/rolemodel/saas/devise/templates/app/views/devise/shared/_links.html.slim +14 -0
  122. data/lib/generators/rolemodel/saas/devise/templates/app/views/devise/unlocks/new.html.slim +11 -0
  123. data/lib/generators/rolemodel/saas/devise/templates/config/locales/devise.en.yml +151 -0
  124. data/lib/generators/rolemodel/saas/devise/templates/config/locales/devise_invitable.en.yml +31 -0
  125. data/lib/generators/rolemodel/saas/devise/templates/spec/factories/organizations.rb +9 -0
  126. data/lib/generators/rolemodel/saas/devise/templates/spec/factories/users.rb +33 -0
  127. data/lib/generators/rolemodel/saas/devise/templates/spec/mailers/previews/devise_mailer_preview.rb +36 -0
  128. data/lib/generators/rolemodel/saas/devise/templates/spec/models/user_spec.rb +29 -0
  129. data/lib/generators/rolemodel/saas/devise/templates/spec/support/devise.rb +8 -0
  130. data/lib/generators/rolemodel/saas/devise/templates/spec/system/users_spec.rb +128 -0
  131. data/lib/generators/rolemodel/semaphore/README.md +15 -0
  132. data/lib/generators/rolemodel/semaphore/USAGE +11 -0
  133. data/lib/generators/rolemodel/semaphore/semaphore_generator.rb +25 -0
  134. data/lib/generators/rolemodel/semaphore/templates/heroku-deployment-commands.sh +3 -0
  135. data/lib/generators/rolemodel/semaphore/templates/production-deploy.yml.erb +17 -0
  136. data/lib/generators/rolemodel/semaphore/templates/semaphore.yml.erb +145 -0
  137. data/lib/generators/rolemodel/semaphore/templates/staging-deploy.yml.erb +17 -0
  138. data/lib/generators/rolemodel/simple_form/README.md +10 -0
  139. data/lib/generators/rolemodel/simple_form/USAGE +11 -0
  140. data/lib/generators/rolemodel/simple_form/simple_form_generator.rb +20 -0
  141. data/lib/generators/rolemodel/simple_form/templates/app/inputs/collection_check_boxes_input.rb +7 -0
  142. data/lib/generators/rolemodel/simple_form/templates/app/inputs/collection_select_input.rb +7 -0
  143. data/lib/generators/rolemodel/simple_form/templates/app/inputs/grouped_collection_select_input.rb +7 -0
  144. data/lib/generators/rolemodel/simple_form/templates/app/inputs/segmented_control_input.rb +48 -0
  145. data/lib/generators/rolemodel/simple_form/templates/app/inputs/switch_checkbox_input.rb +39 -0
  146. data/lib/generators/rolemodel/simple_form/templates/app/inputs/tailored_select_input.rb +75 -0
  147. data/lib/generators/rolemodel/simple_form/templates/config/initializers/simple_form.rb +207 -0
  148. data/lib/generators/rolemodel/simple_form/templates/config/locales/simple_form.en.yml +31 -0
  149. data/lib/generators/rolemodel/simple_form/templates/lib/templates/slim/scaffold/_form.html.slim.tt +12 -0
  150. data/lib/generators/rolemodel/slim/README.md +9 -0
  151. data/lib/generators/rolemodel/slim/USAGE +5 -0
  152. data/lib/generators/rolemodel/slim/slim_generator.rb +24 -0
  153. data/lib/generators/rolemodel/slim/templates/app/views/application/_head.html.slim.tt +13 -0
  154. data/lib/generators/rolemodel/slim/templates/app/views/layouts/application.html.slim.tt +6 -0
  155. data/lib/generators/rolemodel/slim/templates/lib/templates/slim/scaffold/edit.html.slim.tt +15 -0
  156. data/lib/generators/rolemodel/slim/templates/lib/templates/slim/scaffold/index.html.slim.tt +13 -0
  157. data/lib/generators/rolemodel/slim/templates/lib/templates/slim/scaffold/new.html.slim.tt +13 -0
  158. data/lib/generators/rolemodel/slim/templates/lib/templates/slim/scaffold/partial.html.slim.tt +10 -0
  159. data/lib/generators/rolemodel/slim/templates/lib/templates/slim/scaffold/show.html.slim.tt +33 -0
  160. data/lib/generators/rolemodel/soft_destroyable/README.md +8 -0
  161. data/lib/generators/rolemodel/soft_destroyable/USAGE +9 -0
  162. data/lib/generators/rolemodel/soft_destroyable/soft_destroyable_generator.rb +13 -0
  163. data/lib/generators/rolemodel/soft_destroyable/templates/soft_destroyable.rb +82 -0
  164. data/lib/generators/rolemodel/soft_destroyable/templates/soft_destroyable_behavior.rb +166 -0
  165. data/lib/generators/rolemodel/source_map/README.md +13 -0
  166. data/lib/generators/rolemodel/source_map/USAGE +9 -0
  167. data/lib/generators/rolemodel/source_map/source_map_generator.rb +22 -0
  168. data/lib/generators/rolemodel/source_map/templates/lib/middleware/rolemodel/source_map.rb +45 -0
  169. data/lib/generators/rolemodel/source_map/templates/lib/tasks/assets.rake +43 -0
  170. data/lib/generators/rolemodel/tailored_select/README.md +7 -0
  171. data/lib/generators/rolemodel/tailored_select/USAGE +5 -0
  172. data/lib/generators/rolemodel/tailored_select/tailored_select_generator.rb +13 -0
  173. data/lib/generators/rolemodel/testing/README.md +11 -0
  174. data/lib/generators/rolemodel/testing/USAGE +5 -0
  175. data/lib/generators/rolemodel/testing/all_generator.rb +17 -0
  176. data/lib/generators/rolemodel/testing/factory_bot/README.md +18 -0
  177. data/lib/generators/rolemodel/testing/factory_bot/USAGE +8 -0
  178. data/lib/generators/rolemodel/testing/factory_bot/factory_bot_generator.rb +20 -0
  179. data/lib/generators/rolemodel/testing/factory_bot/templates/support/factory_bot.rb +3 -0
  180. data/lib/generators/rolemodel/testing/jasmine_playwright/README.md +9 -0
  181. data/lib/generators/rolemodel/testing/jasmine_playwright/jasmine_playwright_generator.rb +52 -0
  182. data/lib/generators/rolemodel/testing/jasmine_playwright/templates/jp-runner.config.mjs +5 -0
  183. data/lib/generators/rolemodel/testing/jasmine_playwright/templates/spec/javascript/browser/example_spec.js +15 -0
  184. data/lib/generators/rolemodel/testing/jasmine_playwright/templates/spec/javascript/browser/setupTests.js +3 -0
  185. data/lib/generators/rolemodel/testing/jasmine_playwright/templates/support/react.mjs +26 -0
  186. data/lib/generators/rolemodel/testing/parallel_tests/README.md +53 -0
  187. data/lib/generators/rolemodel/testing/parallel_tests/USAGE +12 -0
  188. data/lib/generators/rolemodel/testing/parallel_tests/parallel_tests_generator.rb +42 -0
  189. data/lib/generators/rolemodel/testing/rspec/README.md +46 -0
  190. data/lib/generators/rolemodel/testing/rspec/USAGE +14 -0
  191. data/lib/generators/rolemodel/testing/rspec/rspec_generator.rb +46 -0
  192. data/lib/generators/rolemodel/testing/rspec/templates/rails_helper.rb +72 -0
  193. data/lib/generators/rolemodel/testing/rspec/templates/spec_helper.rb +97 -0
  194. data/lib/generators/rolemodel/testing/rspec/templates/support/capybara_drivers.rb +51 -0
  195. data/lib/generators/rolemodel/testing/rspec/templates/support/capybara_testid.rb +5 -0
  196. data/lib/generators/rolemodel/testing/rspec/templates/support/helpers/action_cable_helper.rb +5 -0
  197. data/lib/generators/rolemodel/testing/rspec/templates/support/helpers/capybara_helper.rb +72 -0
  198. data/lib/generators/rolemodel/testing/rspec/templates/support/helpers/playwright_helper.rb +85 -0
  199. data/lib/generators/rolemodel/testing/rspec/templates/support/helpers/select_helper.rb +33 -0
  200. data/lib/generators/rolemodel/testing/rspec/templates/support/helpers/test_element_helper.rb +11 -0
  201. data/lib/generators/rolemodel/testing/rspec/templates/support/helpers.rb +12 -0
  202. data/lib/generators/rolemodel/testing/test_prof/README.md +5 -0
  203. data/lib/generators/rolemodel/testing/test_prof/USAGE +5 -0
  204. data/lib/generators/rolemodel/testing/test_prof/test_prof_generator.rb +14 -0
  205. data/lib/generators/rolemodel/testing/vitest/README.md +5 -0
  206. data/lib/generators/rolemodel/testing/vitest/USAGE +5 -0
  207. data/lib/generators/rolemodel/testing/vitest/templates/spec/javascript/example.spec.js +12 -0
  208. data/lib/generators/rolemodel/testing/vitest/templates/spec/javascript/test-setup.js +1 -0
  209. data/lib/generators/rolemodel/testing/vitest/templates/vitest.config.js +23 -0
  210. data/lib/generators/rolemodel/testing/vitest/vitest_generator.rb +38 -0
  211. data/lib/generators/rolemodel/ui_components/README.md +9 -0
  212. data/lib/generators/rolemodel/ui_components/USAGE +5 -0
  213. data/lib/generators/rolemodel/ui_components/all_generator.rb +15 -0
  214. data/lib/generators/rolemodel/ui_components/flash/README.md +10 -0
  215. data/lib/generators/rolemodel/ui_components/flash/USAGE +9 -0
  216. data/lib/generators/rolemodel/ui_components/flash/flash_generator.rb +22 -0
  217. data/lib/generators/rolemodel/ui_components/flash/templates/app/views/application/_flash.html.slim +6 -0
  218. data/lib/generators/rolemodel/ui_components/flash/templates/spec/support/matchers/flash_matchers.rb +19 -0
  219. data/lib/generators/rolemodel/ui_components/modals/README.md +119 -0
  220. data/lib/generators/rolemodel/ui_components/modals/USAGE +8 -0
  221. data/lib/generators/rolemodel/ui_components/modals/modals_generator.rb +74 -0
  222. data/lib/generators/rolemodel/ui_components/modals/templates/app/helpers/turbo_frame_link_helper.rb +20 -0
  223. data/lib/generators/rolemodel/ui_components/modals/templates/app/javascript/controllers/morph_controller.js +23 -0
  224. data/lib/generators/rolemodel/ui_components/modals/templates/app/javascript/controllers/toggle_controller.js +55 -0
  225. data/lib/generators/rolemodel/ui_components/modals/templates/app/javascript/initializers/before_morph_handler.js +21 -0
  226. data/lib/generators/rolemodel/ui_components/modals/templates/app/javascript/initializers/frame_missing_handler.js +12 -0
  227. data/lib/generators/rolemodel/ui_components/modals/templates/app/javascript/initializers/turbo_confirm.js +3 -0
  228. data/lib/generators/rolemodel/ui_components/modals/templates/app/views/application/_confirm.html.slim +12 -0
  229. data/lib/generators/rolemodel/ui_components/modals/templates/app/views/layouts/modal.html.slim.tt +26 -0
  230. data/lib/generators/rolemodel/ui_components/modals/templates/app/views/layouts/panel.html.slim.tt +21 -0
  231. data/lib/generators/rolemodel/ui_components/navbar/README.md +11 -0
  232. data/lib/generators/rolemodel/ui_components/navbar/USAGE +10 -0
  233. data/lib/generators/rolemodel/ui_components/navbar/navbar_generator.rb +54 -0
  234. data/lib/generators/rolemodel/ui_components/navbar/templates/app/assets/stylesheets/components/shoelace/index.scss +2 -0
  235. data/lib/generators/rolemodel/ui_components/navbar/templates/app/javascript/lib/shoelace.js +9 -0
  236. data/lib/generators/rolemodel/ui_components/navbar/templates/app/views/layouts/_navbar.html.slim +29 -0
  237. data/lib/generators/rolemodel/webpack/README.md +8 -0
  238. data/lib/generators/rolemodel/webpack/USAGE +5 -0
  239. data/lib/generators/rolemodel/webpack/templates/app/assets/stylesheets/application.scss +5 -0
  240. data/lib/generators/rolemodel/webpack/templates/app/javascript/initializers/honeybadger.js +26 -0
  241. data/lib/generators/rolemodel/webpack/templates/postcss.config.cjs +14 -0
  242. data/lib/generators/rolemodel/webpack/templates/webpack.config.js +104 -0
  243. data/lib/generators/rolemodel/webpack/webpack_generator.rb +76 -0
  244. data/lib/generators/templates/generator/%filename%.rb.tt +11 -0
  245. data/lib/generators/templates/generator/README.md.tt +11 -0
  246. data/lib/generators/templates/generator/USAGE.tt +5 -0
  247. data/lib/generators/templates/generator_spec/%filename%_spec.rb.tt +5 -0
  248. data/lib/rolemodel/engine.rb +9 -0
  249. data/lib/rolemodel/version.rb +5 -0
  250. data/lib/rolemodel-rails.rb +7 -0
  251. metadata +416 -0
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ FactoryBot.define do
4
+ factory :user do
5
+ first_name { 'Default' }
6
+ last_name { 'User' }
7
+ sequence :email do |n|
8
+ "person#{n}@example.com"
9
+ end
10
+ organization
11
+
12
+ password { 'password123' }
13
+ password_confirmation { password }
14
+
15
+ trait :regular_user do
16
+ first_name { 'Regular' }
17
+ last_name { 'User' }
18
+ role { User.roles[:user] }
19
+ end
20
+
21
+ trait :org_admin do
22
+ first_name { 'Org' }
23
+ last_name { 'Admin' }
24
+ role { User.roles[:admin] }
25
+ end
26
+
27
+ trait :super_admin do
28
+ first_name { 'Support' }
29
+ last_name { 'Admin' }
30
+ super_admin { true }
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ # mailers/previews/devise_mailer_preview.rb
4
+ class DeviseMailerPreview < ActionMailer::Preview
5
+ def email_changed
6
+ Devise::Mailer.email_changed(User.first)
7
+ end
8
+
9
+ if Devise.mappings[:user].confirmable?
10
+ def confirmation_instructions
11
+ Devise::Mailer.confirmation_instructions(User.first, 'faketoken')
12
+ end
13
+ end
14
+
15
+ if Devise.mappings[:user].recoverable?
16
+ def password_change
17
+ Devise::Mailer.password_change(User.first)
18
+ end
19
+
20
+ def reset_password_instructions
21
+ Devise::Mailer.reset_password_instructions(User.first, 'faketoken')
22
+ end
23
+ end
24
+
25
+ if Devise.mappings[:user].lockable?
26
+ def unlock_instructions
27
+ Devise::Mailer.unlock_instructions(User.first, 'faketoken')
28
+ end
29
+ end
30
+
31
+ if Devise.mappings[:user].invitable?
32
+ def invitation_instructions
33
+ Devise::Mailer.invitation_instructions(User.first, 'faketoken')
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ RSpec.describe User, type: :model do
6
+ describe 'validations' do
7
+ it 'validates the default factory' do
8
+ expect(build(:user)).to be_valid
9
+ end
10
+
11
+ it 'validates presence of first_name' do
12
+ user = build(:user, first_name: nil)
13
+ expect(user).not_to be_valid
14
+ expect(user.errors[:first_name]).to include("can't be blank")
15
+ end
16
+
17
+ it 'validates presence of last_name' do
18
+ user = build(:user, last_name: nil)
19
+ expect(user).not_to be_valid
20
+ expect(user.errors[:last_name]).to include("can't be blank")
21
+ end
22
+
23
+ it 'validates presence of role' do
24
+ user = build(:user, role: nil)
25
+ expect(user).not_to be_valid
26
+ expect(user.errors[:role]).to include("can't be blank")
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.configure do |config|
4
+ # Make it load Devise helpers for controller, system tests so you can sign in users
5
+ config.include Devise::Test::ControllerHelpers, type: :controller
6
+ config.include Devise::Test::IntegrationHelpers, type: :request
7
+ config.include Devise::Test::IntegrationHelpers, type: :system
8
+ end
@@ -0,0 +1,128 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ RSpec.describe 'Users', type: :system do # rubocop:disable Metrics/BlockLength
6
+ describe 'Signing up' do
7
+ let(:user) { build(:user) }
8
+
9
+ it 'allows user to sign up' do
10
+ visit new_user_registration_path
11
+ fill_in 'First name', with: user.first_name
12
+ fill_in 'Last name', with: user.last_name
13
+ fill_in 'Organization name', with: user.organization_name
14
+ fill_in 'Email', with: user.email
15
+ fill_in 'user[password]', with: 'password123'
16
+ fill_in 'Password confirmation', with: 'password123'
17
+ expect { click_on 'Sign up' }.to change(User, :count).by 1
18
+ expect(page).to have_content 'Welcome! You have signed up successfully.'
19
+ expect(User.last.first_name).to eq user.first_name
20
+ expect(User.last.last_name).to eq user.last_name
21
+ expect(User.last.email).to eq user.email
22
+ end
23
+ end
24
+
25
+ describe 'Signing in' do
26
+ let(:password) { 'password123' }
27
+ let!(:user) do
28
+ create(
29
+ :user,
30
+ password: password,
31
+ password_confirmation: password
32
+ )
33
+ end
34
+
35
+ it 'requires user to log in before visiting application' do
36
+ visit root_path
37
+ expect(page).to have_current_path(new_user_session_path)
38
+ end
39
+
40
+ it 'allows user to sign in' do
41
+ visit new_user_session_path
42
+ fill_in 'Email', with: user.email
43
+ fill_in 'Password', with: password
44
+ click_on 'Login'
45
+ expect(page).to have_current_path(root_path)
46
+ expect(page).to have_content('Signed in successfully.')
47
+ end
48
+ end
49
+
50
+ describe 'Signing out' do
51
+ let!(:user) { create(:user) }
52
+
53
+ before do
54
+ sign_in user
55
+ end
56
+
57
+ it 'allows user to sign out' do
58
+ visit root_path
59
+ click_on 'Sign Out'
60
+ expect(page).to have_current_path(new_user_session_path)
61
+ expect(page).to have_content('Login')
62
+ end
63
+ end
64
+
65
+ describe 'Editing account info' do # rubocop:disable Metrics/BlockLength
66
+ let(:password) { 'password123' }
67
+ let!(:user) do
68
+ create(
69
+ :user,
70
+ password: password,
71
+ password_confirmation: password
72
+ )
73
+ end
74
+ let(:new_user_info) do
75
+ {
76
+ first_name: 'New',
77
+ last_name: 'Name',
78
+ email: 'new_email@example.com'
79
+ }
80
+ end
81
+
82
+ before do
83
+ sign_in user
84
+ end
85
+
86
+ it 'allows user to update account info' do
87
+ visit root_path
88
+ click_on 'Edit Profile'
89
+ fill_in 'First name', with: new_user_info[:first_name]
90
+ fill_in 'Last name', with: new_user_info[:last_name]
91
+ fill_in 'Email', with: new_user_info[:email]
92
+ fill_in 'Current password', with: password
93
+ click_on 'Update'
94
+ expect(user.reload.first_name).to eq new_user_info[:first_name]
95
+ expect(user.last_name).to eq new_user_info[:last_name]
96
+ expect(user.email).to eq new_user_info[:email]
97
+ end
98
+
99
+ it 'does not show Organization name field if user is not admin' do
100
+ visit edit_user_registration_path
101
+ expect(page).not_to have_field 'Organization name'
102
+ sign_out user
103
+
104
+ org_admin = create(:user, :org_admin)
105
+ sign_in org_admin
106
+ refresh
107
+
108
+ expect(page).to have_field 'Organization name'
109
+ end
110
+
111
+ it 'allows admin user to update associated organization name' do
112
+ user.admin!
113
+ old_organization_name = user.organization_name
114
+ new_organization_name = 'New Org Name'
115
+ old_organization_id = user.organization.id
116
+
117
+ visit edit_user_registration_path
118
+ fill_in 'Organization name', with: new_organization_name
119
+ fill_in 'Current password', with: password
120
+ click_on 'Update'
121
+ expect(user.organization.reload.name).to_not eq old_organization_name
122
+ expect(user.organization_name).to eq new_organization_name
123
+
124
+ # ensure it doesn't create a new organization
125
+ expect(user.organization.id).to eq old_organization_id
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,15 @@
1
+ # Semaphore Generator
2
+
3
+ ## What you get
4
+
5
+ * semaphore.yml file to run the relevant CI commands
6
+ * heroku-deployment-commands.sh file with commands to deploy to heroku
7
+ * staging-deploy.yml file with commands to deploy to staging
8
+ * production-deploy.yml file with commands to deploy to production
9
+
10
+ This is the basic config needed to use semaphore.
11
+
12
+ ## Note
13
+ This config assumes
14
+ - `main` is the base branch
15
+ - `yarn test` is the command to run JS tests
@@ -0,0 +1,11 @@
1
+ Description:
2
+ Sets up our standard semaphore configuration
3
+
4
+ Example:
5
+ rails generate rolemodel:semaphore
6
+
7
+ This will create:
8
+ semaphore.yml
9
+ heroku-deployment-commands.sh
10
+ staging-deploy.yml
11
+ production-deploy.yml
@@ -0,0 +1,25 @@
1
+ module Rolemodel
2
+ class SemaphoreGenerator < BaseGenerator
3
+ source_root File.expand_path('templates', __dir__)
4
+
5
+ def create_base_semaphore_config
6
+ @project_name = Rails.application.class.try(:parent_name) || Rails.application.class.module_parent_name
7
+ template 'semaphore.yml.erb', '.semaphore/semaphore.yml'
8
+
9
+ if yes?('Does your project have JavaScript tests and/or eslint?')
10
+ uncomment_lines('.semaphore/semaphore.yml', '- yarn test')
11
+ uncomment_lines('.semaphore/semaphore.yml', '- yarn run eslint')
12
+ end
13
+ end
14
+
15
+ def create_deplyment_commands
16
+ default_heroku_prefix = (Rails.application.class.try(:parent_name) || Rails.application.class.module_parent_name).underscore.dasherize
17
+
18
+ @heroku_prefix = ask('Enter the heroku project prefix', default: default_heroku_prefix)
19
+
20
+ template 'heroku-deployment-commands.sh', '.semaphore/heroku-deployment-commands.sh'
21
+ template 'staging-deploy.yml.erb', '.semaphore/staging-deploy.yml'
22
+ template 'production-deploy.yml.erb', '.semaphore/production-deploy.yml'
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,3 @@
1
+ checkout --use-cache
2
+ heroku git:remote -a $HEROKU_APP_NAME
3
+ git push heroku -f $SEMAPHORE_GIT_BRANCH:main
@@ -0,0 +1,17 @@
1
+ version: v1.0
2
+ name: Deploy to Production
3
+ agent:
4
+ machine:
5
+ type: e1-standard-2
6
+ os_image: ubuntu1804
7
+ blocks:
8
+ - name: Deploy
9
+ task:
10
+ secrets:
11
+ - name: heroku_http_auth
12
+ env_vars:
13
+ - name: HEROKU_APP_NAME
14
+ value: <%= "#{@heroku_prefix}-production" %>
15
+ jobs:
16
+ - name: 'Push code to Production'
17
+ commands_file: heroku-deployment-commands.sh
@@ -0,0 +1,145 @@
1
+ version: v1.0
2
+ name: <%= @project_name %>
3
+ agent:
4
+ machine:
5
+ type: e1-standard-2
6
+ os_image: ubuntu2004
7
+ auto_cancel:
8
+ running:
9
+ when: branch != 'main'
10
+ global_job_config:
11
+ env_vars:
12
+ - name: RAILS_ENV
13
+ value: test
14
+ - name: HONEYBADGER_SOURCE_MAP_DISABLED
15
+ value: 'true'
16
+ - name: DATABASE_URL
17
+ value: 'postgres://postgres:@0.0.0.0/<%= Rails.application.config.database_configuration['test']['database'] %>'
18
+ - name: GOOGLE_CHROME_BIN
19
+ value: 'google-chrome'
20
+ # https://github.com/renderedtext/test-boosters#rspec-booster
21
+ - name: TB_RSPEC_OPTIONS
22
+ value: '--format RspecJunitFormatter --out tmp/test_results/rspec_junit.xml --format documentation'
23
+ secrets:
24
+ - name: rmsbackup_ssh_private_key
25
+ prologue:
26
+ commands:
27
+ # Add keys
28
+ - ssh-keyscan -H github.com >> ~/.ssh/known_hosts
29
+ - chmod 600 ~/.ssh/id_rsa_rmsbackup_ssh_private_key
30
+ - ssh-add ~/.ssh/id_rsa_rmsbackup_ssh_private_key
31
+
32
+ - checkout
33
+
34
+ # Ruby setup
35
+ - sem-service start postgres 14
36
+ - sem-version ruby $(cat .ruby-version)
37
+ - gem install bundler --no-document
38
+ - bundle config set deployment 'true'
39
+ - bundle config set path 'vendor/bundle'
40
+
41
+ # Node setup
42
+ - sem-version node $(cat .node-version)
43
+ - npm i -g yarn
44
+
45
+ # Cache setup
46
+ - cache restore gems-$(checksum .ruby-version)-$(checksum Gemfile.lock)
47
+ - cache restore yarn-cache-$(checksum .node-version)-$(checksum yarn.lock)
48
+ - cache restore yarn-node-modules-$(checksum .node-version)-$(checksum yarn.lock)
49
+ blocks:
50
+ - name: Build
51
+ dependencies: []
52
+ task:
53
+ jobs:
54
+ - name: Install Dependencies
55
+ commands:
56
+ - bundle check || bundle install
57
+ - yarn check || yarn install
58
+ epilogue:
59
+ commands:
60
+ - cache store gems-$(checksum .ruby-version)-$(checksum Gemfile.lock) vendor/bundle
61
+ - cache store yarn-cache-$(checksum .node-version)-$(checksum yarn.lock) /home/semaphore/.cache/yarn
62
+ - cache store yarn-node-modules-$(checksum .node-version)-$(checksum yarn.lock) node_modules
63
+ - name: Ruby/JS/Linting
64
+ execution_time_limit:
65
+ minutes: 20
66
+ dependencies:
67
+ - Build
68
+ task:
69
+ jobs:
70
+ - name: Ruby Test/JS Tests/Audit/Linting
71
+ commands:
72
+ - bundle exec rails db:setup db:test:prepare
73
+ - bundle exec rspec --exclude-pattern "spec/system/**/*_spec.rb" --format RspecJunitFormatter --out tmp/test_results/rspec_junit.xml --format documentation
74
+ - bundle exec bundle-audit update
75
+ - bundle exec bundle-audit check
76
+ # - bundle exec rubocop --fail-level warning --display-only-fail-level-offenses
77
+ # - yarn test
78
+ # - yarn run eslint
79
+ epilogue:
80
+ always:
81
+ commands:
82
+ - test-results publish tmp/test_results
83
+ on_fail:
84
+ commands:
85
+ - artifact push job log/test.log
86
+ - name: Assets Compile
87
+ dependencies:
88
+ - Build
89
+ execution_time_limit:
90
+ minutes: 20
91
+ task:
92
+ jobs:
93
+ - name: Webpack Compile and Store Assets
94
+ commands:
95
+ - bundle check || bundle install --without legacy_data_migration
96
+ - yarn check || yarn install
97
+ - yarn build
98
+ - cache store assets-public-$SEMAPHORE_WORKFLOW_ID public
99
+ - name: System Tests
100
+ dependencies:
101
+ - Assets Compile
102
+ execution_time_limit:
103
+ minutes: 20
104
+ task:
105
+ agent:
106
+ machine:
107
+ type: e1-standard-2
108
+ os_image: ubuntu2004
109
+ env_vars:
110
+ - name: TEST_BOOSTERS_RSPEC_TEST_FILE_PATTERN
111
+ value: spec/system/**/*_spec.rb
112
+ prologue:
113
+ commands:
114
+ - gem install semaphore_test_boosters
115
+ - bundle exec rails db:setup db:test:prepare
116
+ - cache restore assets-public-$SEMAPHORE_WORKFLOW_ID
117
+ jobs:
118
+ - name: Ruby System Tests
119
+ parallelism: 2
120
+ commands:
121
+ - rspec_booster --job $SEMAPHORE_JOB_INDEX/$SEMAPHORE_JOB_COUNT
122
+ epilogue:
123
+ always:
124
+ commands:
125
+ - test-results publish tmp/test_results
126
+ - cache delete assets-public-$SEMAPHORE_WORKFLOW_ID
127
+ on_fail:
128
+ commands:
129
+ - artifact push job log/test.log
130
+ - artifact push workflow tmp/capybara
131
+ after_pipeline:
132
+ task:
133
+ jobs:
134
+ - name: Publish Results
135
+ commands:
136
+ - test-results gen-pipeline-report
137
+ promotions:
138
+ - name: Deploy Staging
139
+ pipeline_file: staging-deploy.yml
140
+ auto_promote_on:
141
+ - result: passed
142
+ branch:
143
+ - main
144
+ - name: Deploy Production
145
+ pipeline_file: production-deploy.yml
@@ -0,0 +1,17 @@
1
+ version: v1.0
2
+ name: Deploy to Staging
3
+ agent:
4
+ machine:
5
+ type: e1-standard-2
6
+ os_image: ubuntu1804
7
+ blocks:
8
+ - name: Deploy
9
+ task:
10
+ secrets:
11
+ - name: heroku_http_auth
12
+ env_vars:
13
+ - name: HEROKU_APP_NAME
14
+ value: <%= "#{@heroku_prefix}-staging" %>
15
+ jobs:
16
+ - name: 'Push code to staging'
17
+ commands_file: heroku-deployment-commands.sh
@@ -0,0 +1,10 @@
1
+ # SimpleForm Generator
2
+
3
+ ## What you get
4
+
5
+ * SimpleForm config
6
+ * SimpleForm en.yml
7
+ * SimpleForm input wrapper classes
8
+ * SimpleForm scaffold generation template
9
+
10
+ Adds SimpleForm for simplified and unified styling that automatically wraps inputs with classes
@@ -0,0 +1,11 @@
1
+ Description:
2
+ Add SimpleForm and configuration
3
+
4
+ Example:
5
+ rails generate rolemodel:simple_form
6
+
7
+ This will create:
8
+ config/initializers/simple_form.rb
9
+ config/locales/simple_form.en.yml
10
+ simple_form input wrapper classes
11
+ simple_form template file
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rolemodel
4
+ class SimpleFormGenerator < BaseGenerator
5
+ source_root File.expand_path('templates', __dir__)
6
+
7
+ def add_gem
8
+ Bundler.with_unbundled_env do
9
+ bundle_command 'add simple_form'
10
+ end
11
+ end
12
+
13
+ def add_files
14
+ directory 'app/inputs'
15
+ directory 'lib/templates/slim/scaffold'
16
+ copy_file 'config/initializers/simple_form.rb'
17
+ copy_file 'config/locales/simple_form.en.yml'
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CollectionCheckBoxesInput < SimpleForm::Inputs::CollectionCheckBoxesInput
4
+ def item_wrapper_class
5
+ 'form__group--checkbox'
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CollectionSelectInput < SimpleForm::Inputs::CollectionSelectInput
4
+ def input_html_classes
5
+ super.push('form__dropdown')
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class GroupedCollectionSelectInput < SimpleForm::Inputs::GroupedCollectionSelectInput
4
+ def input_html_classes
5
+ super.push('form__dropdown')
6
+ end
7
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ # SegmentedControlInput is a custom input type for SimpleForm that renders a radio group as an optics (v2.2.0+) segmented control
4
+ #
5
+ # Options:
6
+ # :size (:small, :medium, :large) - renders the control at different sizes
7
+ # :full_width - renders the control to take the full width of its container
8
+ #
9
+ # Usage:
10
+ # <%= f.input :my_field, as: :segmented_control, collection: collection_options %>
11
+ # <%= f.input :my_field, as: :segmented_control, collection: collection_options, size: :small %>
12
+ # <%= f.input :my_field, as: :segmented_control, collection: collection_options, disabled: true %>
13
+ # <%= f.input :my_field, as: :segmented_control, collection: collection_options, full_width: true %>
14
+ class SegmentedControlInput < SimpleForm::Inputs::CollectionRadioButtonsInput
15
+ def input_type
16
+ 'radio_buttons'
17
+ end
18
+
19
+ def input_options
20
+ options = super
21
+ options[:item_wrapper_tag] = false
22
+ options[:collection_wrapper_tag] = 'div'
23
+ options[:collection_wrapper_class] = collection_wrapper_classes
24
+ options[:item_label_class] = 'segmented-control__label'
25
+ options
26
+ end
27
+
28
+ def input_html_options
29
+ super.tap do |options|
30
+ options[:class].delete('form-control')
31
+ end
32
+ end
33
+
34
+ def input_html_classes
35
+ super.push('segmented-control__input')
36
+ end
37
+
38
+ private
39
+
40
+ def collection_wrapper_classes
41
+ class_names(
42
+ 'segmented-control',
43
+ options[:class],
44
+ "segmented-control--#{options[:size]}": options[:size].present?,
45
+ 'segmented-control--full-width': options[:full_width].present?
46
+ )
47
+ end
48
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ # SwitchCheckboxInput is a custom input type for SimpleForm that renders a checkbox as an optics (v0.5.0+) switch control
4
+ #
5
+ # Options:
6
+ # :small - renders a smaller switch control
7
+ # :label_after_input - renders the label after the switch control
8
+ # :wrapper - the wrapper to use for this input, defaults to :inline_switch_wrapper. :switch_wrapper is also available.
9
+ #
10
+ # Usage:
11
+ # <%= f.input :my_field, as: :switch_checkbox %>
12
+ # <%= f.input :my_field, as: :switch_checkbox, small: true %>
13
+ # <%= f.input :my_field, as: :switch_checkbox, disabled: true %>
14
+ # <%= f.input :my_field, as: :switch_checkbox, label_after_input: true %>
15
+ # <%= f.input :my_field, as: :switch_checkbox, wrapper: :switch_wrapper %>
16
+ class SwitchCheckboxInput < SimpleForm::Inputs::BooleanInput
17
+ def input(wrapper_options = nil)
18
+ merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
19
+
20
+ switch_group = template.content_tag(:div, class: "switch #{'switch--small' if options[:small]}") do
21
+ if include_hidden?
22
+ build_check_box(unchecked_value, merged_input_options)
23
+ else
24
+ build_check_box_without_hidden_field(merged_input_options)
25
+ end +
26
+ label(wrapper_options)
27
+ end
28
+
29
+ if options[:label_after_input]
30
+ switch_group + label(wrapper_options)
31
+ else
32
+ label(wrapper_options) + switch_group
33
+ end
34
+ end
35
+
36
+ def input_html_classes
37
+ []
38
+ end
39
+ end