rolemodel-rails 2.1.0 → 2.3.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 (97) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +30 -9
  3. data/Rakefile +3 -3
  4. data/lib/generators/rolemodel/all_generator.rb +1 -0
  5. data/lib/generators/rolemodel/core_setup/README.md +27 -0
  6. data/lib/generators/rolemodel/core_setup/USAGE +12 -0
  7. data/lib/generators/rolemodel/core_setup/core_setup_generator.rb +23 -0
  8. data/lib/generators/rolemodel/github/README.md +4 -0
  9. data/lib/generators/rolemodel/github/templates/workflows/deploy-production.yml +34 -0
  10. data/lib/generators/rolemodel/github/templates/workflows/deploy-staging.yml +35 -0
  11. data/lib/generators/rolemodel/good_job/good_job_generator.rb +7 -13
  12. data/lib/generators/rolemodel/heroku/README.md +20 -1
  13. data/lib/generators/rolemodel/heroku/heroku_generator.rb +20 -0
  14. data/lib/generators/rolemodel/heroku/templates/app.json.tt +5 -2
  15. data/lib/generators/rolemodel/heroku/templates/deploy-app/SKILL.md +202 -0
  16. data/lib/generators/rolemodel/linters/eslint/eslint_generator.rb +1 -0
  17. data/lib/generators/rolemodel/linters/rubocop/rubocop_generator.rb +5 -1
  18. data/lib/generators/rolemodel/lograge/README.md +1 -1
  19. data/lib/generators/rolemodel/lograge/templates/config/initializers/lograge.rb +1 -1
  20. data/lib/generators/rolemodel/optics/base/base_generator.rb +3 -2
  21. data/lib/generators/rolemodel/react/react_generator.rb +1 -0
  22. data/lib/generators/rolemodel/readme/templates/README.md.erb +2 -4
  23. data/lib/generators/rolemodel/saas/devise/devise_generator.rb +3 -3
  24. data/lib/generators/rolemodel/sentry/README.md +25 -0
  25. data/lib/generators/rolemodel/sentry/USAGE +13 -0
  26. data/lib/generators/rolemodel/sentry/sentry_generator.rb +114 -0
  27. data/lib/generators/rolemodel/sentry/templates/app/controllers/concerns/sentry_user.rb +13 -0
  28. data/lib/generators/rolemodel/sentry/templates/app/javascript/initializers/sentry.js +34 -0
  29. data/lib/generators/rolemodel/sentry/templates/config/initializers/sentry.rb +68 -0
  30. data/lib/generators/rolemodel/simple_form/README.md +6 -0
  31. data/lib/generators/rolemodel/simple_form/USAGE +3 -0
  32. data/lib/generators/rolemodel/simple_form/simple_form_generator.rb +11 -0
  33. data/lib/generators/rolemodel/simple_form/templates/app/inputs/switch_checkbox_input.rb +1 -1
  34. data/lib/generators/rolemodel/slim/templates/app/views/application/_head.html.slim.tt +0 -4
  35. data/lib/generators/rolemodel/tailored_select/USAGE +2 -1
  36. data/lib/generators/rolemodel/tailored_select/tailored_select_generator.rb +15 -0
  37. data/lib/generators/rolemodel/testing/factory_bot/templates/support/factory_bot.rb +2 -0
  38. data/lib/generators/rolemodel/testing/jasmine_playwright/jasmine_playwright_generator.rb +2 -2
  39. data/lib/generators/rolemodel/testing/rspec/rspec_generator.rb +8 -10
  40. data/lib/generators/rolemodel/testing/rspec/templates/spec/rails_helper.rb.tt +4 -1
  41. data/lib/generators/rolemodel/testing/rspec/templates/spec/support/capybara_drivers.rb.tt +2 -0
  42. data/lib/generators/rolemodel/testing/rspec/templates/spec/support/helpers/action_cable_helper.rb +2 -0
  43. data/lib/generators/rolemodel/testing/rspec/templates/spec/support/helpers/test_element_helper.rb +2 -0
  44. data/lib/generators/rolemodel/testing/rspec/templates/spec/support/helpers.rb.tt +3 -1
  45. data/lib/generators/rolemodel/testing/vitest/vitest_generator.rb +1 -0
  46. data/lib/generators/rolemodel/turbo/all/README.md +16 -0
  47. data/lib/generators/rolemodel/turbo/all/USAGE +5 -0
  48. data/lib/generators/rolemodel/turbo/all/all_generator.rb +15 -0
  49. data/lib/generators/rolemodel/turbo/confirm/README.md +25 -0
  50. data/lib/generators/rolemodel/turbo/confirm/USAGE +5 -0
  51. data/lib/generators/rolemodel/turbo/confirm/confirm_generator.rb +35 -0
  52. data/lib/generators/rolemodel/turbo/form/README.md +8 -0
  53. data/lib/generators/rolemodel/turbo/form/USAGE +5 -0
  54. data/lib/generators/rolemodel/turbo/form/form_generator.rb +29 -0
  55. data/lib/generators/rolemodel/turbo/form/templates/app/javascript/controllers/turbo_form_controller.js +15 -0
  56. data/lib/generators/rolemodel/turbo/form/templates/spec/support/helpers/turbo_form_helper.rb +8 -0
  57. data/lib/generators/rolemodel/{ui_components → turbo}/modals/README.md +0 -2
  58. data/lib/generators/rolemodel/turbo/modals/USAGE +5 -0
  59. data/lib/generators/rolemodel/{ui_components → turbo}/modals/modals_generator.rb +9 -22
  60. data/lib/generators/rolemodel/{ui_components → turbo}/modals/templates/app/helpers/turbo_frame_link_helper.rb +2 -0
  61. data/lib/generators/rolemodel/turbo/ready/README.md +12 -0
  62. data/lib/generators/rolemodel/turbo/ready/USAGE +5 -0
  63. data/lib/generators/rolemodel/turbo/ready/ready_generator.rb +48 -0
  64. data/lib/generators/rolemodel/turbo/ready/templates/app/javascript/controllers/prevent_morph_controller.js +22 -0
  65. data/lib/generators/rolemodel/ui_components/navbar/navbar_generator.rb +11 -14
  66. data/lib/generators/rolemodel/webpack/README.md +2 -1
  67. data/lib/generators/rolemodel/webpack/templates/postcss.config.cjs +0 -3
  68. data/lib/generators/rolemodel/webpack/templates/webpack.config.js +6 -14
  69. data/lib/generators/rolemodel/webpack/webpack_generator.rb +18 -18
  70. data/lib/rolemodel/generator_base.rb +15 -0
  71. data/lib/rolemodel/version.rb +1 -1
  72. data/lib/rolemodel/yarn.rb +42 -0
  73. data/lib/rolemodel-rails.rb +0 -1
  74. metadata +58 -28
  75. data/lib/generators/rolemodel/linters/rubocop/templates/lib/cops/form_error_response.rb +0 -54
  76. data/lib/generators/rolemodel/linters/rubocop/templates/lib/cops/no_chrome_tag.rb +0 -45
  77. data/lib/generators/rolemodel/semaphore/README.md +0 -15
  78. data/lib/generators/rolemodel/semaphore/USAGE +0 -11
  79. data/lib/generators/rolemodel/semaphore/semaphore_generator.rb +0 -25
  80. data/lib/generators/rolemodel/semaphore/templates/heroku-deployment-commands.sh +0 -3
  81. data/lib/generators/rolemodel/semaphore/templates/production-deploy.yml.erb +0 -17
  82. data/lib/generators/rolemodel/semaphore/templates/semaphore.yml.erb +0 -145
  83. data/lib/generators/rolemodel/semaphore/templates/staging-deploy.yml.erb +0 -17
  84. data/lib/generators/rolemodel/ui_components/modals/USAGE +0 -8
  85. data/lib/generators/rolemodel/ui_components/modals/templates/app/javascript/controllers/morph_controller.js +0 -23
  86. data/lib/generators/rolemodel/webpack/templates/app/assets/stylesheets/application.scss +0 -5
  87. data/lib/generators/rolemodel/webpack/templates/app/javascript/initializers/honeybadger.js +0 -26
  88. /data/lib/generators/rolemodel/{simple_form → tailored_select}/templates/app/inputs/tailored_select_input.rb +0 -0
  89. /data/lib/generators/rolemodel/{ui_components/modals/templates/app/javascript/initializers/turbo_confirm.js → turbo/confirm/templates/app/javascript/initializers/turbo_confirm.js.tt} +0 -0
  90. /data/lib/generators/rolemodel/{ui_components/modals/templates/app/views/application/_confirm.html.slim → turbo/confirm/templates/app/views/application/_confirm.html.slim.tt} +0 -0
  91. /data/lib/generators/rolemodel/{ui_components → turbo}/modals/templates/app/javascript/controllers/toggle_controller.js +0 -0
  92. /data/lib/generators/rolemodel/{ui_components → turbo}/modals/templates/app/javascript/initializers/frame_missing_handler.js +0 -0
  93. /data/lib/generators/rolemodel/{ui_components → turbo}/modals/templates/app/views/layouts/modal.html.slim.tt +0 -0
  94. /data/lib/generators/rolemodel/{ui_components → turbo}/modals/templates/app/views/layouts/panel.html.slim.tt +0 -0
  95. /data/lib/generators/rolemodel/{ui_components/modals → turbo/ready}/templates/app/javascript/initializers/before_morph_handler.js +0 -0
  96. /data/lib/generators/rolemodel/ui_components/navbar/templates/app/assets/stylesheets/components/shoelace/{index.scss → index.css} +0 -0
  97. /data/lib/generators/rolemodel/ui_components/navbar/templates/app/views/{layouts → application}/_navbar.html.slim +0 -0
@@ -6,15 +6,16 @@ module Rolemodel
6
6
  def add_optics_package
7
7
  say 'installing Optics package', :green
8
8
 
9
+ ensure_yarn
9
10
  run 'yarn add @rolemodel/optics'
10
11
  end
11
12
 
12
13
  def copy_templates
13
14
  say 'importing stylesheet', :green
14
15
 
15
- prepend_to_file Dir.glob('app/assets/stylesheets/application.*').first, <<~SCSS
16
+ prepend_to_file application_stylesheet_path, <<~CSS
16
17
  @import '@rolemodel/optics/dist/css/optics';
17
- SCSS
18
+ CSS
18
19
  end
19
20
  end
20
21
  end
@@ -6,6 +6,7 @@ module Rolemodel
6
6
  @add_react = yes?('Would you like to add react?')
7
7
 
8
8
  if @add_react
9
+ ensure_yarn
9
10
  run 'yarn add react react-dom'
10
11
  end
11
12
  end
@@ -81,12 +81,10 @@ When finished with the feature and the code has been reviewed, the commits shoul
81
81
  ## [Staging](http://staging.<applicationname>.com)
82
82
  ## [Production](http://app.<applicationname>.com)
83
83
  ## External services
84
- * [HoneyBadger](http://honeybadger.io)
85
- * [Skylight](http://skylight.io)
84
+ * [Sentry](https://sentry.io)
86
85
  * [SendGrid](http://sendgrid.com/RoleModel)
87
86
  * [Heroku](http://herokuapp.com)
88
87
 
89
- ## [CI](http://semaphoreci.com/RoleModel)
90
88
  ## [Core project presentation](http://docs.google.com)
91
89
  ## [List of contributors](http://github.com/RoleModel)
92
90
  ## [Change log](file://./docs/change_log.md)
@@ -113,4 +111,4 @@ The application is deployed to Heroku. They are also hosting the DNS. We certifi
113
111
  * Larry Anderson - 919-555-1213
114
112
 
115
113
  # Copyright & licensing
116
- Copyright (c) 2019 Closed Source @CompanyName
114
+ Copyright (c) 2026 Closed Source @CompanyName
@@ -161,11 +161,11 @@ module Rolemodel
161
161
  say 'importing login stylesheet', :green
162
162
  copy_file 'app/assets/stylesheets/login.css'
163
163
 
164
- return unless File.exist?(File.join(destination_root, 'app/assets/stylesheets/application.scss'))
164
+ return unless File.exist?(application_stylesheet_path)
165
165
 
166
- append_to_file 'app/assets/stylesheets/application.scss', <<~SCSS
166
+ append_to_file application_stylesheet_path, <<~CSS
167
167
  @import 'login';
168
- SCSS
168
+ CSS
169
169
  end
170
170
  end
171
171
  end
@@ -0,0 +1,25 @@
1
+ # Sentry Generator
2
+
3
+ ## What you get
4
+
5
+ Error monitoring and performance tracing via [Sentry](https://sentry.io) for both the Ruby and JavaScript sides of the app.
6
+
7
+ ### Ruby
8
+
9
+ * The `sentry-rails` gem
10
+ * `config/initializers/sentry.rb` with sensible defaults: traces sampling, profiling, PII filtering via Rails' parameter filter, noisy-exception exclusion, and health-check transaction filtering
11
+ * Sentry user context wired into `app/controllers/application_controller.rb` via a `set_sentry_user` before_action (Devise-friendly, gated on `user_signed_in?`)
12
+
13
+ ### JavaScript
14
+
15
+ * `@sentry/browser` and `@sentry/webpack-plugin` dependencies
16
+ * `app/javascript/initializers/sentry.js`, which initializes Sentry in production and staging only (avoids ad-blocker noise in development) and attaches the current user from a `current-user-id` meta tag
17
+ * The `sentryWebpackPlugin` wired into `webpack.config.js` to upload source maps in production
18
+
19
+ Depends on the `rolemodel:webpack` generator having already created `webpack.config.js` and `app/javascript/application.js`.
20
+
21
+ ## After running
22
+
23
+ * Update the `project` and `applicationKey` in `webpack.config.js`, and the matching `filterKeys` in `app/javascript/initializers/sentry.js`, to match your Sentry project.
24
+ * Set the `SENTRY_DSN`, `SENTRY_ENVIRONMENT`, and `SENTRY_AUTH_TOKEN` environment variables.
25
+ * Render a `current-user-id` meta tag in your layout so the browser SDK can attach user context.
@@ -0,0 +1,13 @@
1
+ Description:
2
+ Sets up Sentry error monitoring for both Ruby and JavaScript
3
+
4
+ Example:
5
+ rails generate rolemodel:sentry
6
+
7
+ This will:
8
+ Add the sentry-rails gem
9
+ Create config/initializers/sentry.rb
10
+ Add Sentry user context to app/controllers/application_controller.rb
11
+ Add @sentry/browser and @sentry/webpack-plugin JS dependencies
12
+ Create app/javascript/initializers/sentry.js
13
+ Wire the Sentry webpack plugin into webpack.config.js
@@ -0,0 +1,114 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rolemodel
4
+ class SentryGenerator < GeneratorBase
5
+ source_root File.expand_path('templates', __dir__)
6
+
7
+ JS_DEPS = %w[
8
+ @sentry/browser
9
+ @sentry/webpack-plugin
10
+ ]
11
+
12
+ def install_gem
13
+ say 'Adding sentry-rails gem', :green
14
+
15
+ bundle_command 'add sentry-rails'
16
+ end
17
+
18
+ def install_profiler_gem
19
+ say 'Adding stackprof gem for Sentry profiling', :green
20
+
21
+ # config/initializers/sentry.rb sets profiles_sample_rate; without stackprof
22
+ # the SDK logs a warning on every boot and profiling is silently disabled.
23
+ # stackprof is a native MRI extension, so restrict it to compatible platforms.
24
+ bundle_command 'add stackprof --platform ruby'
25
+ run_bundle
26
+ end
27
+
28
+ def add_ruby_initializer
29
+ say 'Setting up Sentry for Ruby error reporting', :green
30
+
31
+ copy_file 'config/initializers/sentry.rb'
32
+ end
33
+
34
+ def add_user_context
35
+ say 'Adding Sentry user context to ApplicationController', :green
36
+
37
+ directory 'app/controllers/concerns'
38
+
39
+ inject_into_class 'app/controllers/application_controller.rb', 'ApplicationController',
40
+ " include SentryUser\n"
41
+ end
42
+
43
+ def add_js_dependencies
44
+ say 'Adding Sentry JS dependencies to package.json', :green
45
+
46
+ ensure_yarn
47
+ run "yarn add --dev #{JS_DEPS.join(' ')}"
48
+ end
49
+
50
+ def add_js_initializer
51
+ say 'Setting up Sentry for JS error reporting', :green
52
+
53
+ copy_file 'app/javascript/initializers/sentry.js'
54
+ append_to_file 'app/javascript/application.js', <<~JS
55
+ import './initializers/sentry'
56
+ JS
57
+ end
58
+
59
+ # Wire the Sentry webpack plugin into webpack.config.js. Idempotent and a
60
+ # no-op if there's no webpack.config.js or it's already wired, so the
61
+ # webpack generator can safely invoke this generator via its --sentry option.
62
+ def configure_webpack
63
+ config = File.expand_path('webpack.config.js', destination_root)
64
+ return unless File.exist?(config)
65
+ return if File.read(config).include?('@sentry/webpack-plugin')
66
+
67
+ say 'Wiring Sentry into webpack.config.js', :green
68
+
69
+ inject_into_file 'webpack.config.js',
70
+ "import { sentryWebpackPlugin } from '@sentry/webpack-plugin'\n",
71
+ after: "import CssMinimizerPlugin from 'css-minimizer-webpack-plugin'\n"
72
+
73
+ inject_into_file 'webpack.config.js', after: "'process.env.RAILS_ENV': JSON.stringify(process.env.RAILS_ENV),\n" do
74
+ <<-JS
75
+ 'process.env.SENTRY_DSN': JSON.stringify(process.env.SENTRY_DSN),
76
+ 'process.env.SENTRY_ENVIRONMENT': JSON.stringify(process.env.SENTRY_ENVIRONMENT),
77
+ 'process.env.SENTRY_AUTH_TOKEN': JSON.stringify(process.env.SENTRY_AUTH_TOKEN),
78
+ JS
79
+ end
80
+
81
+ gsub_file 'webpack.config.js', " })\n ].filter(Boolean)", <<-JS.chomp
82
+ }),
83
+
84
+ // Upload source maps to Sentry in production for easier debugging
85
+ mode === 'production' &&
86
+ !process.env.CI &&
87
+ sentryWebpackPlugin({
88
+ authToken: process.env.SENTRY_AUTH_TOKEN,
89
+ org: 'rolemodel-software',
90
+ project: '#{sentry_app_name}',
91
+ telemetry: false,
92
+ applicationKey: 'app-frontend'
93
+ })
94
+ ].filter(Boolean)
95
+ JS
96
+ end
97
+
98
+ def finishing_notes
99
+ say <<~NOTES
100
+
101
+ *** Update the sentryWebpackPlugin `project` and `applicationKey` in webpack.config.js,
102
+ and the matching `filterKeys` in app/javascript/initializers/sentry.js, to your Sentry project.
103
+
104
+ *** Set the SENTRY_DSN, SENTRY_ENVIRONMENT, and SENTRY_AUTH_TOKEN environment variables.
105
+ NOTES
106
+ end
107
+
108
+ private
109
+
110
+ def sentry_app_name
111
+ Rails.application.name.underscore
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,13 @@
1
+ module SentryUser
2
+ extend ActiveSupport::Concern
3
+
4
+ included { before_action :set_sentry_user }
5
+
6
+ private
7
+
8
+ def set_sentry_user
9
+ return unless respond_to?(:current_user) && current_user
10
+
11
+ Sentry.set_user(id: current_user.id)
12
+ end
13
+ end
@@ -0,0 +1,34 @@
1
+ import * as Sentry from '@sentry/browser'
2
+
3
+ // Only initialize Sentry in production and staging environments
4
+ // This avoids issues with ad blockers during local development
5
+ const environment = process.env.SENTRY_ENVIRONMENT || process.env.RAILS_ENV
6
+ const shouldInitialize = environment === 'production' || environment === 'staging'
7
+
8
+ if (shouldInitialize) {
9
+ Sentry.init({
10
+ dsn: process.env.SENTRY_DSN,
11
+ environment: environment,
12
+ sendDefaultPii: false,
13
+ tracesSampleRate: 0.1,
14
+ replaysOnErrorSampleRate: 1.0,
15
+ integrations: [
16
+ Sentry.thirdPartyErrorFilterIntegration({
17
+ // Must match the applicationKey in the sentryWebpackPlugin configuration
18
+ filterKeys: ['app-frontend'],
19
+ behaviour: 'drop-error-if-exclusively-contains-third-party-frames'
20
+ })
21
+ ],
22
+
23
+ // Capture user context from meta tags rendered by Rails
24
+ beforeSend(event) {
25
+ const userId = document.querySelector('meta[name="current-user-id"]')?.content
26
+
27
+ if (userId) {
28
+ event.user = { id: userId }
29
+ }
30
+
31
+ return event
32
+ }
33
+ })
34
+ }
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ Sentry.init do |config|
4
+ config.dsn = ENV['SENTRY_DSN']
5
+ config.enable_logs = true
6
+ config.debug = Rails.env.local?
7
+
8
+ # Traces sampling — 5% for HTTP requests, 10% for other transactions
9
+ config.traces_sampler = lambda do |sampling_context|
10
+ transaction_context = sampling_context[:transaction_context]
11
+
12
+ case transaction_context[:op]
13
+ when /^http/
14
+ 0.05
15
+ else
16
+ 0.10
17
+ end
18
+ end
19
+
20
+ # Enable profiling at 100% of sampled transactions
21
+ config.profiles_sample_rate = 1.0
22
+
23
+ # Breadcrumbs configuration
24
+ config.breadcrumbs_logger = [:sentry_logger, :http_logger]
25
+
26
+ # Exclude common noisy exceptions
27
+ config.excluded_exceptions += [
28
+ 'ActiveRecord::RecordNotFound',
29
+ 'ActionController::RoutingError',
30
+ ]
31
+
32
+ # Include local variables for debugging
33
+ config.include_local_variables = true
34
+
35
+ # Filter out health check transactions
36
+ config.before_send_transaction = lambda do |event, _hint|
37
+ return nil if event.transaction&.match?(/health|ping|metrics/)
38
+ event
39
+ end
40
+
41
+ # Filter sensitive data using Rails' parameter filter
42
+ filter = ActiveSupport::ParameterFilter.new(Rails.application.config.filter_parameters)
43
+ config.send_default_pii = false
44
+
45
+ config.before_send = lambda do |event, _hint|
46
+ if event.extra
47
+ event.extra = filter.filter(event.extra)
48
+ end
49
+
50
+ if event.user
51
+ event.user = filter.filter(event.user)
52
+ end
53
+
54
+ if event.contexts
55
+ event.contexts = filter.filter(event.contexts)
56
+ end
57
+
58
+ event
59
+ end
60
+
61
+ config.enabled_patches << :logger
62
+ config.std_lib_logger_filter = proc do |_logger, _message, severity|
63
+ [:warn, :error, :fatal].include?(severity)
64
+ end
65
+
66
+ config.rails.register_error_subscriber = Rails.env.production?
67
+ config.rails.structured_logging.subscribers = config.rails.structured_logging.subscribers.slice(:action_controller)
68
+ end
@@ -8,3 +8,9 @@
8
8
  * SimpleForm scaffold generation template
9
9
 
10
10
  Adds SimpleForm for simplified and unified styling that automatically wraps inputs with classes
11
+
12
+ ## Custom inputs
13
+
14
+ All standard custom inputs are included by default. The generator prompts you to
15
+ confirm whether to include the `tailored_select` custom input, since not every
16
+ project uses the tailored-select web component.
@@ -9,3 +9,6 @@ Example:
9
9
  config/locales/simple_form.en.yml
10
10
  simple_form input wrapper classes
11
11
  simple_form template file
12
+
13
+ Pass --tailored_select to also install the experimental tailored_select
14
+ component input (via the rolemodel:tailored_select generator).
@@ -4,6 +4,9 @@ module Rolemodel
4
4
  class SimpleFormGenerator < GeneratorBase
5
5
  source_root File.expand_path('templates', __dir__)
6
6
 
7
+ class_option :tailored_select, type: :boolean, default: false,
8
+ desc: 'Install the tailored_select experimental component input'
9
+
7
10
  def add_gem
8
11
  Bundler.with_unbundled_env do
9
12
  bundle_command 'add simple_form'
@@ -16,5 +19,13 @@ module Rolemodel
16
19
  copy_file 'config/initializers/simple_form.rb'
17
20
  copy_file 'config/locales/simple_form.en.yml'
18
21
  end
22
+
23
+ def install_tailored_select
24
+ return unless options.tailored_select?
25
+
26
+ # The tailored_select generator owns the input template and installs it
27
+ # here because simple_form is now present.
28
+ generate 'rolemodel:tailored_select'
29
+ end
19
30
  end
20
31
  end
@@ -14,7 +14,7 @@
14
14
  # <%= f.input :my_field, as: :switch_checkbox, label_after_input: true %>
15
15
  # <%= f.input :my_field, as: :switch_checkbox, wrapper: :switch_wrapper %>
16
16
  class SwitchCheckboxInput < SimpleForm::Inputs::BooleanInput
17
- def input(wrapper_options = nil)
17
+ def input(wrapper_options = nil) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
18
18
  merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
19
19
 
20
20
  switch_group = template.content_tag(:div, class: "switch #{'switch--small' if options[:small]}") do
@@ -4,10 +4,6 @@ title <%= Rails.application.class.name.deconstantize.titleize %>
4
4
  = csp_meta_tag
5
5
 
6
6
  meta name="viewport" content="width=device-width, initial-scale=1"
7
- meta name="turbo-refresh-method" content="morph"
8
- meta name="turbo-refresh-scroll" content="preserve"
9
7
 
10
8
  = stylesheet_link_tag 'application', 'data-turbo-track': 'reload'
11
9
  = javascript_include_tag 'application', 'data-turbo-track': 'reload', defer: true
12
-
13
- = yield :head
@@ -1,5 +1,6 @@
1
1
  Description:
2
- runs the tailored select generator
2
+ Installs the @rolemodel/tailored-select package. If the app is using
3
+ SimpleForm, it also installs the matching tailored_select SimpleForm input.
3
4
 
4
5
  Example:
5
6
  rails generate rolemodel:tailored_select
@@ -7,7 +7,22 @@ module Rolemodel
7
7
  def add_tailored_select_package
8
8
  say 'Installing Tailored Select package', :green
9
9
 
10
+ ensure_yarn
10
11
  run 'yarn add @rolemodel/tailored-select'
11
12
  end
13
+
14
+ def add_simple_form_input
15
+ return unless simple_form?
16
+
17
+ say 'Installing the Tailored Select SimpleForm input', :green
18
+
19
+ copy_file 'app/inputs/tailored_select_input.rb'
20
+ end
21
+
22
+ private
23
+
24
+ def simple_form?
25
+ File.exist?(File.expand_path('config/initializers/simple_form.rb', destination_root))
26
+ end
12
27
  end
13
28
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  RSpec.configure do |config|
2
4
  config.include FactoryBot::Syntax::Methods
3
5
  end
@@ -18,8 +18,8 @@ module Rolemodel
18
18
  raise Thor::InvocationError, 'a --github_package_token option or GITHUB_PACKAGES_TOKEN environment variable is required' if options[:github_package_token].blank?
19
19
  end
20
20
 
21
- def yarn_init_unless_package_json_exists
22
- run 'yarn init' unless File.exist?(File.expand_path('package.json', destination_root))
21
+ def enable_corepack_and_yarn
22
+ ensure_yarn
23
23
  end
24
24
 
25
25
  def add_browser_test_script
@@ -10,26 +10,24 @@ module Rolemodel
10
10
  def install_rspec
11
11
  say 'Installing RSpec-rails', :green
12
12
 
13
- gem_group :development, :test do
14
- gem 'rspec-rails'
15
- end
13
+ bundle_command('add rspec-rails --group "development, test"')
14
+ end
16
15
 
16
+ def install_system_test_driver
17
17
  say 'Installing capybara-playwright-driver for system tests', :green
18
18
 
19
- gem_group :test do
20
- gem 'capybara-playwright-driver'
19
+ bundle_command('add capybara-playwright-driver --group "test"')
20
+ bundle_command('add marsh_grass --group "test"') if options.marsh_grass?
21
+ end
21
22
 
22
- if options.marsh_grass?
23
- gem 'marsh_grass'
24
- gem 'pry'
25
- end
26
- end
23
+ def bundle_install
27
24
  run_bundle
28
25
  end
29
26
 
30
27
  def install_playwright
31
28
  say 'Installing Playwright for system tests', :green
32
29
 
30
+ ensure_yarn
33
31
  run 'yarn add --dev playwright'
34
32
  run 'yarn run playwright install'
35
33
  end
@@ -70,7 +70,10 @@ RSpec.configure do |config|
70
70
  prep_passed = system 'rails spec:prepare'
71
71
  ENV['ASSET_PRECOMPILE_SUCCESSFUL'] = 'true'
72
72
 
73
- abort "\nYour assets didn't compile. Exiting WITHOUT running any tests. Review the output above to resolve any errors." unless prep_passed
73
+ unless prep_passed
74
+ abort "\nYour assets didn't compile. Exiting WITHOUT running any tests. " \
75
+ 'Review the output above to resolve any errors.'
76
+ end
74
77
  end
75
78
  end
76
79
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  RSpec.configure do |config|
2
4
  Capybara.register_driver :playwright_headless do |app|
3
5
  create_driver(app)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActionCableHelper
2
4
  def wait_for_stream_connection
3
5
  expect(page).to have_selector('turbo-cable-stream-source[connected]', visible: false)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module TestElementHelper
2
4
  include ActionView::RecordIdentifier
3
5
 
@@ -1,4 +1,6 @@
1
- Dir[Rails.root.join('spec', 'support', 'helpers', '**', '*.rb')].each { |f| require f }
1
+ # frozen_string_literal: true
2
+
3
+ Rails.root.glob('spec/support/helpers/**/*.rb').each { |f| require f }
2
4
 
3
5
  # this is a place to pull in all your app specific DSL methods.
4
6
 
@@ -16,6 +16,7 @@ module Rolemodel
16
16
 
17
17
  def update_test_script
18
18
  say 'Update yarn test command', :green
19
+ ensure_yarn
19
20
 
20
21
  add_package_json_script 'test', TEST_COMMAND
21
22
  end
@@ -0,0 +1,16 @@
1
+ # All Generator
2
+
3
+ Runs all Turbo Generators
4
+
5
+ ## Prerequisites
6
+
7
+ - slim
8
+ - webpack (if using webpack)
9
+ - optics
10
+
11
+ ## What you get
12
+
13
+ - Turbo meta tags in HEAD
14
+ - TurboConfirm setup
15
+ - Turbo Frame Modals setup
16
+ - Turbo-Form stimulus controller
@@ -0,0 +1,5 @@
1
+ Description:
2
+ All Turbo Generators
3
+
4
+ Example:
5
+ rails generate rolemodel:turbo:all
@@ -0,0 +1,15 @@
1
+ module Rolemodel
2
+ module Turbo
3
+ class AllGenerator < ::Rolemodel::GeneratorBase
4
+ source_root File.expand_path('templates', __dir__)
5
+
6
+ def run_generators
7
+ generate 'rolemodel:turbo:ready'
8
+ generate 'rolemodel:turbo:confirm'
9
+ generate 'rolemodel:turbo:modals'
10
+ generate 'rolemodel:turbo:form'
11
+ end
12
+ end
13
+ end
14
+ end
15
+
@@ -0,0 +1,25 @@
1
+ # Confirm Generator
2
+
3
+ Add custom dialog support to `data-turbo-confirm`
4
+
5
+ ## Prerequisites
6
+
7
+ * `rolmodel:slim`
8
+ * `rolemodel:webpack`
9
+ * `rolemodel:optics:base`
10
+
11
+ ## What you get
12
+
13
+ * Custom confirm dialogs via `@rolemodel/turbo-confirm` integration
14
+
15
+ ## Example
16
+
17
+ ```slim
18
+ = button_to "Test Confirm", model, method: :delete, data: { \
19
+ turbo_confirm: "For real?!?",
20
+ confirm_details: "You're about to delete #{model.name}, forever. 😱",
21
+ confirm_button: "YOLO!",
22
+ }
23
+ ```
24
+
25
+ data attributes other than `turbo-confirm` are optional & customizable. See [turbo-confirm](https://github.com/RoleModel/turbo-confirm) for more details.
@@ -0,0 +1,5 @@
1
+ Description:
2
+ Install @rolemodel/turbo-confirm
3
+
4
+ Example:
5
+ rails generate rolemodel:turbo:confirm
@@ -0,0 +1,35 @@
1
+ module Rolemodel
2
+ module Turbo
3
+ class ConfirmGenerator < ::Rolemodel::GeneratorBase
4
+ source_root File.expand_path('templates', __dir__)
5
+
6
+ def add_turbo_confirm_package
7
+ say 'Installing Turbo Confirm package', :green
8
+
9
+ ensure_yarn
10
+ run 'yarn add @rolemodel/turbo-confirm'
11
+ end
12
+
13
+ def add_initializer
14
+ template 'app/javascript/initializers/turbo_confirm.js'
15
+
16
+ append_to_file 'app/javascript/application.js' do
17
+ optimize_indentation <<~JS
18
+ import './initializers/turbo_confirm.js'
19
+ JS
20
+ end
21
+ end
22
+
23
+ def add_view_partial
24
+ template 'app/views/application/_confirm.html.slim'
25
+
26
+ inject_into_file 'app/views/layouts/application.html.slim', after: /\bbody.*\n/ do
27
+ optimize_indentation <<~SLIM, 4
28
+ = render 'confirm'
29
+ SLIM
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+
@@ -0,0 +1,8 @@
1
+ # Form Generator
2
+
3
+ Enable the "turbo-fetch" (now Turbo-Form) pattern in new/existing rails apps.
4
+
5
+ ## What you get
6
+
7
+ - turbo-form controller
8
+ - system spec helper