rails_devtools 0.1.1

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 (88) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +92 -0
  3. data/Rakefile +8 -0
  4. data/app/assets/config/devtools_manifest.js +1 -0
  5. data/app/assets/stylesheets/devtools/application.css +15 -0
  6. data/app/controllers/rails_devtools/application_controller.rb +4 -0
  7. data/app/controllers/rails_devtools/base_controller.rb +7 -0
  8. data/app/controllers/rails_devtools/database_tables_controller.rb +16 -0
  9. data/app/controllers/rails_devtools/frontend/modules_controller.rb +18 -0
  10. data/app/controllers/rails_devtools/gems_controller.rb +16 -0
  11. data/app/controllers/rails_devtools/host_app_images_controller.rb +35 -0
  12. data/app/controllers/rails_devtools/image_assets_controller.rb +43 -0
  13. data/app/controllers/rails_devtools/routes/route_path_inputs_controller.rb +23 -0
  14. data/app/controllers/rails_devtools/routes_controller.rb +21 -0
  15. data/app/forms/rails_devtools/database_table_search_form.rb +51 -0
  16. data/app/forms/rails_devtools/gem_search_form.rb +86 -0
  17. data/app/forms/rails_devtools/image_search_form.rb +30 -0
  18. data/app/forms/rails_devtools/route_search_form.rb +17 -0
  19. data/app/helpers/rails_devtools/application_helper.rb +4 -0
  20. data/app/javascript/application.js +4 -0
  21. data/app/javascript/controllers/application.js +10 -0
  22. data/app/javascript/controllers/checkbox_controller.js +9 -0
  23. data/app/javascript/controllers/index.js +11 -0
  24. data/app/javascript/controllers/search_reset_controller.js +7 -0
  25. data/app/javascript/controllers/turbo_form_controller.js +9 -0
  26. data/app/jobs/rails_devtools/application_job.rb +4 -0
  27. data/app/mailers/rails_devtools/application_mailer.rb +6 -0
  28. data/app/models/rails_devtools/application_record.rb +5 -0
  29. data/app/models/rails_devtools/image_assets/image_info.rb +85 -0
  30. data/app/models/rails_devtools/routes/collection.rb +83 -0
  31. data/app/models/rails_devtools/routes/controller_info.rb +30 -0
  32. data/app/models/rails_devtools/routes/engine_info.rb +33 -0
  33. data/app/models/rails_devtools/routes/route_info.rb +120 -0
  34. data/app/views/rails_devtools/application_layout.rb +90 -0
  35. data/app/views/rails_devtools/application_view.rb +6 -0
  36. data/app/views/rails_devtools/components/application_component.rb +24 -0
  37. data/app/views/rails_devtools/components/flash_message.rb +29 -0
  38. data/app/views/rails_devtools/components/lucide/base.rb +18 -0
  39. data/app/views/rails_devtools/components/lucide/close.rb +25 -0
  40. data/app/views/rails_devtools/components/lucide/database.rb +26 -0
  41. data/app/views/rails_devtools/components/lucide/external_link.rb +26 -0
  42. data/app/views/rails_devtools/components/lucide/images.rb +27 -0
  43. data/app/views/rails_devtools/components/lucide/menu.rb +26 -0
  44. data/app/views/rails_devtools/components/lucide/package.rb +30 -0
  45. data/app/views/rails_devtools/components/lucide/pocket_knife.rb +28 -0
  46. data/app/views/rails_devtools/components/lucide/sign_post.rb +29 -0
  47. data/app/views/rails_devtools/components/lucide/trash.rb +26 -0
  48. data/app/views/rails_devtools/components/lucide/triangle_alert.rb +29 -0
  49. data/app/views/rails_devtools/components/page_content.rb +27 -0
  50. data/app/views/rails_devtools/components/ui/drawer.rb +49 -0
  51. data/app/views/rails_devtools/components/ui/menu.rb +81 -0
  52. data/app/views/rails_devtools/components/ui/search_form.rb +65 -0
  53. data/app/views/rails_devtools/components.rb +5 -0
  54. data/app/views/rails_devtools/database_tables/index.rb +32 -0
  55. data/app/views/rails_devtools/database_tables/table_card.rb +61 -0
  56. data/app/views/rails_devtools/gems/gem_card.rb +74 -0
  57. data/app/views/rails_devtools/gems/index.rb +32 -0
  58. data/app/views/rails_devtools/image_assets/image_card.rb +37 -0
  59. data/app/views/rails_devtools/image_assets/image_details.rb +82 -0
  60. data/app/views/rails_devtools/image_assets/index.rb +39 -0
  61. data/app/views/rails_devtools/routes/index.rb +37 -0
  62. data/app/views/rails_devtools/routes/route_card.rb +70 -0
  63. data/app/views/rails_devtools/routes/route_details/controller_card.rb +87 -0
  64. data/app/views/rails_devtools/routes/route_details/route_path_input.rb +46 -0
  65. data/app/views/rails_devtools/routes/route_details.rb +171 -0
  66. data/config/routes.rb +24 -0
  67. data/lib/rails_devtools/asset_config.rb +52 -0
  68. data/lib/rails_devtools/asset_providers/jsbundling_rails_config.rb +21 -0
  69. data/lib/rails_devtools/asset_providers/propshaft_config.rb +19 -0
  70. data/lib/rails_devtools/asset_providers/shakapacker_config.rb +26 -0
  71. data/lib/rails_devtools/asset_providers/sprocket_config.rb +19 -0
  72. data/lib/rails_devtools/asset_providers/vite_rails_config.rb +19 -0
  73. data/lib/rails_devtools/engine.rb +22 -0
  74. data/lib/rails_devtools/importmap.rb +16 -0
  75. data/lib/rails_devtools/importmaps/base.rb +82 -0
  76. data/lib/rails_devtools/version.rb +3 -0
  77. data/lib/rails_devtools.rb +20 -0
  78. data/lib/tasks/rails_devtools_tasks.rake +4 -0
  79. data/vendor/javascript/@stimulus-components--clipboard.js +4 -0
  80. data/vendor/javascript/@stimulus-components--notification.js +4 -0
  81. data/vendor/javascript/@stimulus-components--reveal.js +4 -0
  82. data/vendor/javascript/stimulus-autoloader.js +54 -0
  83. data/vendor/javascript/stimulus-importmap-autoloader.js +27 -0
  84. data/vendor/javascript/stimulus-loading.js +93 -0
  85. data/vendor/javascript/stimulus-use.js +4 -0
  86. data/vendor/javascript/stimulus.min.js +5 -0
  87. data/vendor/javascript/turbo.min.js +36 -0
  88. metadata +241 -0
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsDevtools
4
+ class ImageAssets::Index < ApplicationView
5
+ def initialize(form:, images_by_folder: {})
6
+ @images_by_folder = images_by_folder
7
+ @form = form
8
+ end
9
+
10
+ def view_template
11
+ render Components::PageContent.new do |page|
12
+ page.page_title { "Image assets" }
13
+ page.search_form(form: @form, path: helpers.image_assets_path)
14
+ page.results { results }
15
+ end
16
+ end
17
+
18
+ private
19
+
20
+ def results
21
+ if @images_by_folder.empty?
22
+ div(class: "text-neutral") { "No results found" }
23
+ else
24
+ div(class: "flex flex-col gap-12") do
25
+ @images_by_folder.each do |folder, images|
26
+ div do
27
+ h3(class: "text-lg font-bold mb-4 truncate") { folder }
28
+ div(class: "flex gap-4 flex-wrap w-full items-start") do
29
+ images.each do |image_info|
30
+ render ImageAssets::ImageCard.new(image_info: image_info)
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsDevtools
4
+ module Routes
5
+ class Index < ApplicationView
6
+ def initialize(form: nil, routes: [])
7
+ @routes = routes
8
+ @form = form
9
+ end
10
+
11
+ def view_template
12
+ render Components::PageContent.new do |page|
13
+ page.page_title { "Routes" }
14
+ page.search_form(form: @form, path: helpers.routes_path, method: :get)
15
+ page.results { results }
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ def results
22
+ if @routes.values.all? { |routes| routes.empty? }
23
+ div(class: "text-neutral") { "No results found" }
24
+ else
25
+ div(class: "flex gap-2 flex-wrap w-full items-start") do
26
+ @routes.each do |engine, routes|
27
+ h3(class: "first:mt-0 mt-4 text-neutral opacity-75 text-lg") { engine }
28
+ routes.each do |route|
29
+ render Routes::RouteCard.new(route: route, engine: engine)
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsDevtools
4
+ class Routes::RouteCard < Components::ApplicationComponent
5
+ def initialize(route:, engine:)
6
+ @route = route
7
+ @engine = engine
8
+ end
9
+
10
+ def view_template
11
+ a(
12
+ href: helpers.route_path(
13
+ @route.id
14
+ ),
15
+ data: { turbo_frame: "drawer_content", action: "click->checkbox#toggle" },
16
+ class: "group flex w-full"
17
+ ) do
18
+ div(class: "card card-compact bg-white text-sm w-full shadow-sm") do
19
+ div(class: "card-body") do
20
+ div(class: "flex flex-col sm:flex-row justify-between sm:items-center gap-y-2 sm:gap-x-2") do
21
+ div(class: "flex items-center") do
22
+ h2(class: "inline-flex card-title !mb-0 leading-none text-base items-center") do
23
+ route_name
24
+ end
25
+ redirection_badge
26
+ no_matching_controller_alert
27
+ engine_badge
28
+ end
29
+ div(class: "flex gap-2 items-center justify-between sm:justify-normal") do
30
+ div(class: "truncate") { @route.path.gsub("(.:format)", "") }
31
+ div(class: "badge badge-sm ml-1") { @route.verb }
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+
39
+ private
40
+
41
+ def route_name
42
+ if @route.inline?
43
+ @route.name
44
+ else
45
+ "#{@route.name}_path"
46
+ end
47
+ end
48
+
49
+ def no_matching_controller_alert
50
+ return unless @route.kind == "controller"
51
+ return if @route.controller_info.action_exists?
52
+
53
+ span(class: "text-error ml-1") do
54
+ render Components::Lucide::TriangleAlert.new(width: 16, height: 16)
55
+ end
56
+ end
57
+
58
+ def engine_badge
59
+ return unless @route.engine?
60
+
61
+ span(class: "badge badge-sm badge-accent ml-1") { "engine" }
62
+ end
63
+
64
+ def redirection_badge
65
+ return unless @route.redirection?
66
+
67
+ span(class: "badge badge-sm badge-accent ml-1") { @route.redirection_info.status }
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsDevtools
4
+ module Routes
5
+ class RouteDetails::ControllerCard < Components::ApplicationComponent
6
+ def initialize(controller_info:)
7
+ @controller_info = controller_info
8
+ end
9
+
10
+ delegate(
11
+ :full_class_name,
12
+ :action,
13
+ :controller,
14
+ :action_exists?,
15
+ :file_path,
16
+ to: :@controller_info
17
+ )
18
+
19
+ def view_template
20
+ div(class: card_class) do
21
+ div(class: "card-body") do
22
+ div(class: [
23
+ "text-base flex justify-between gap-4 items-center",
24
+ error? && "text-error"
25
+ ]) do
26
+ div(class: "flex items-center ") do
27
+ if error?
28
+ span(class: "mr-1") do
29
+ render Components::Lucide::TriangleAlert.new(width: 16, height: 16)
30
+ end
31
+ end
32
+ h4(class: "font-bold") { full_class_name }
33
+ end
34
+ span(class: "italic") { action }
35
+ end
36
+
37
+ if error?
38
+ ul(class: "text-sm text-error mt-2") do
39
+ if controller.nil?
40
+ li { "No controller found for this route." }
41
+ else
42
+ li { "No action ##{action} found in associated controller." }
43
+ end
44
+ end
45
+ end
46
+
47
+ div(class: "card-actions justify-end mt-8") do
48
+ controller_file_path_input
49
+ end
50
+ end
51
+ end
52
+ end
53
+
54
+ private
55
+
56
+ def card_class
57
+ [
58
+ "card card-compact bg-white text-sm w-full shadow-sm mb-4",
59
+ error? ? "border border-error" : "border border-base-300"
60
+ ].compact.join(" ")
61
+ end
62
+
63
+ def error?
64
+ !action_exists?
65
+ end
66
+
67
+ def controller_file_path_input
68
+ div(
69
+ class: "",
70
+ data_controller: "clipboard",
71
+ data_clipboard_success_content_value: "Copied!"
72
+ ) do
73
+ input(
74
+ value: file_path,
75
+ class: "hidden",
76
+ data_clipboard_target: "source"
77
+ )
78
+ button(
79
+ class: ["btn btn-outline btn-xs", error? ? "btn-error" : "btn-primary"],
80
+ data_action: "clipboard#copy",
81
+ data_clipboard_target: "button"
82
+ ) { "Copy file path" }
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsDevtools
4
+ module Routes
5
+ class RouteDetails::RoutePathInput < Components::ApplicationComponent
6
+ def initialize(route:, prefix: "", suffix: "path")
7
+ @route = route
8
+ @prefix = prefix
9
+ @suffix = suffix
10
+ end
11
+
12
+ def view_template
13
+ turbo_frame_tag("route_path_input") do
14
+ div(
15
+ class: "join w-full",
16
+ data_controller: "clipboard",
17
+ data_clipboard_success_content_value: "Copied!"
18
+ ) do
19
+ input(
20
+ value: input_value,
21
+ class: "input input-bordered input-primary input-sm w-full join-item",
22
+ data_clipboard_target: "source"
23
+ )
24
+ button(
25
+ class: "btn btn-primary btn-outline btn-sm join-item",
26
+ data_action: "clipboard#copy",
27
+ data_clipboard_target: "button"
28
+ ) { "Copy" }
29
+ end
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ def input_value
36
+ "#{prefix}#{@route.name}_#{@suffix}()"
37
+ end
38
+
39
+ def prefix
40
+ return "" if @prefix.blank?
41
+
42
+ "#{@prefix}."
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,171 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsDevtools
4
+ class Routes::RouteDetails < Components::ApplicationComponent
5
+ include Phlex::Rails::Helpers::FormWith
6
+
7
+ def initialize(route:)
8
+ @route = route
9
+ end
10
+
11
+ def view_template
12
+ turbo_frame_tag("drawer_content") do
13
+ div(class: "mt-4 w-full sm:min-w-80") do
14
+ engine_name
15
+ div(class: "flex justify-between gap-x-2 items-center") do
16
+ h3(class: "text-lg font-bold mb-2") { route_name }
17
+ div(class: "badge badge-lg bg-base-300 text-sm") { @route.verb }
18
+ end
19
+ p(class: "text-sm text-neutral") { only_path }
20
+ open_link
21
+ segments
22
+ div(class: "mt-4 pt-4 border-t-2 border-base-300 mt-2 text-sm text-neutral") do
23
+ more_info_card
24
+ end
25
+ route_path_input
26
+ end
27
+ end
28
+ end
29
+
30
+ private
31
+
32
+ def more_info_card
33
+ case @route.kind
34
+ when "controller"
35
+ controller_card
36
+ when "redirection"
37
+ redirection_card
38
+ when "rack_app"
39
+ rack_app_card
40
+ when "inline"
41
+ inline_card
42
+ when "engine"
43
+ engine_card
44
+ end
45
+ end
46
+
47
+ def route_name
48
+ if @route.inline?
49
+ @route.endpoint
50
+ else
51
+ "#{@route.name}_path"
52
+ end
53
+ end
54
+
55
+ def redirection_card
56
+ div(class: "card card-compact bg-white text-sm w-full shadow-sm mb-4 border border-base-300") do
57
+ div(class: "card-body flex flex-col lg:flex-row lg:justify-between lg:items-center gap-4") do
58
+ h3(class: "block text-lg font-bold mb-2") { "Redirection #{@route.redirection_info.status}" }
59
+ div(class: "text-sm text-neutral") { @route.redirection_info.block }
60
+ end
61
+ end
62
+ end
63
+
64
+ def rack_app_card
65
+ div(class: "card card-compact bg-white text-sm w-full shadow-sm mb-4 border border-base-300") do
66
+ div(class: "card-body flex flex-col lg:flex-row lg:justify-between lg:items-center gap-4") do
67
+ h3(class: "block text-lg font-bold mb-2") { "Custom rack app #{@route.name}" }
68
+ end
69
+ end
70
+ end
71
+
72
+ def engine_card
73
+ div(class: "card card-compact bg-white text-sm w-full shadow-sm mb-4 border border-base-300") do
74
+ div(class: "card-body flex flex-col lg:flex-row lg:justify-between lg:items-center gap-4") do
75
+ h3(class: "block text-lg font-bold mb-2") { "Mounted engine #{@route.name}" }
76
+ end
77
+ end
78
+ end
79
+
80
+ def controller_card
81
+ render Routes::RouteDetails::ControllerCard.new(
82
+ controller_info: @route.controller_info
83
+ )
84
+ end
85
+
86
+ def inline_card
87
+ div(class: "card card-compact bg-white text-sm w-full shadow-sm mb-4 border border-base-300") do
88
+ div(class: "card-body flex flex-col lg:flex-row lg:justify-between lg:items-center gap-4") do
89
+ h3(class: "block text-lg font-bold mb-2") { @route.endpoint }
90
+ end
91
+ end
92
+ end
93
+
94
+ def engine_name
95
+ return unless @route.engine_info.engine?
96
+
97
+ div(class: "text-neutral opacity-75") do
98
+ @route.engine_info.name
99
+ end
100
+ end
101
+
102
+ def only_path
103
+ @route.path.gsub("(.:format)", "")
104
+ end
105
+
106
+ def open_link
107
+ return unless @route.controller_info.action_exists?
108
+ return if @route.segments.any? || @route.verb != "GET"
109
+
110
+ div(class: "mt-2 flex justify-end") do
111
+ a(href: only_path, target: "_blank", class: "btn btn-xs btn-outline btn-neutral opacity-75") do
112
+ render RailsDevtools::Components::Lucide::ExternalLink.new(width: 16, height: 16)
113
+ span { "Open" }
114
+ end
115
+ end
116
+ end
117
+
118
+ def segments
119
+ return unless @route.segments.any?
120
+
121
+ div(class: "mt-4 pt-4 border-t-2 border-base-300 mt-2 text-sm text-neutral") do
122
+ h3(class: "text-lg font-bold mb-2") { "Segments" }
123
+ ul(class: "flex gap-x-2") do
124
+ @route.segments.each do |segment|
125
+ li(class: "badge badge-md badge-outline badge-neutral opacity-75") { segment }
126
+ end
127
+ end
128
+ end
129
+ end
130
+
131
+ def route_path_input
132
+ return if @route.inline?
133
+
134
+ turbo_frame_tag("route_path_input_form") do
135
+ div(data_controller: "turbo-form") do
136
+ form_with(
137
+ url: helpers.routes_route_path_input_path(@route.id),
138
+ method: :patch,
139
+ data: { turbo_frame: "route_path_input", turbo_form_target: "form" }
140
+ ) do |form|
141
+ div(class: "flex gap-2") do
142
+ engine_checkbox(form)
143
+ div do
144
+ label(class: "label cursor-pointer justify-normal gap-1") do
145
+ span(class: "label-text") { "URL" }
146
+ form.check_box(
147
+ :url_suffix,
148
+ class: "checkbox checkbox-xs",
149
+ data: { action: "change->turbo-form#submit" }
150
+ )
151
+ end
152
+ end
153
+ end
154
+ end
155
+ end
156
+ end
157
+ render Routes::RouteDetails::RoutePathInput.new(route: @route)
158
+ end
159
+
160
+ def engine_checkbox(form)
161
+ return unless @route.engine_info.engine?
162
+
163
+ div do
164
+ label(class: "label cursor-pointer justify-normal gap-1") do
165
+ span(class: "label-text") { "engine" }
166
+ form.check_box(:engine_prefix, class: "checkbox checkbox-xs", data: { action: "change->turbo-form#submit" })
167
+ end
168
+ end
169
+ end
170
+ end
171
+ end
data/config/routes.rb ADDED
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ RailsDevtools::Engine.routes.draw do
4
+ root to: "database_tables#index"
5
+ get "*path.js.map", to: proc { [204, {}, [""]] }
6
+
7
+ resources :image_assets, only: [:show, :index, :destroy]
8
+ resources :database_tables, only: [:show, :index]
9
+ resources :gems, only: [:show, :index]
10
+
11
+ resources :routes, only: [:show, :index]
12
+ namespace :routes do
13
+ resources :route_path_inputs, only: :update
14
+ end
15
+
16
+ namespace :frontend do
17
+ get "modules/*path", to: "modules#show", format: :js, constraints: ->(request) { request.path.end_with?(".js") }
18
+ end
19
+
20
+ get "host_app_images/*path", as: :host_app_image, to: "host_app_images#show",
21
+ constraints: lambda { |request|
22
+ request.path.end_with?(*RailsDevtools::ImageAssets::ImageInfo::IMAGE_EXTENSIONS.to_a)
23
+ }
24
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsDevtools
4
+ class AssetConfig
5
+ def self.find
6
+ providers = AssetProvider.new.list
7
+ new(providers)
8
+ end
9
+
10
+ def initialize(providers)
11
+ @providers = providers
12
+ end
13
+
14
+ def paths
15
+ @paths ||= @providers.flat_map(&:paths)
16
+ end
17
+
18
+ def helper_snippet
19
+ if vite_rails?
20
+ "vite_image_tag"
21
+ else
22
+ "image_tag"
23
+ end
24
+ end
25
+
26
+ def implicit_path
27
+ if vite_rails?
28
+ ""
29
+ else
30
+ "images/"
31
+ end
32
+ end
33
+
34
+ def vite_rails?
35
+ @providers.any? { |p| p.provider == :vite_rails }
36
+ end
37
+ end
38
+
39
+ class AssetProvider
40
+ PROVIDERS = [
41
+ AssetProviders::SprocketConfig,
42
+ AssetProviders::ViteRailsConfig,
43
+ AssetProviders::JsbundlingRailsConfig,
44
+ AssetProviders::ShakapackerConfig,
45
+ AssetProviders::PropshaftConfig
46
+ ].freeze
47
+
48
+ def list
49
+ @list ||= PROVIDERS.select { |config| config.new.used? }.map(&:new)
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsDevtools
4
+ module AssetProviders
5
+ class JsbundlingRailsConfig
6
+ def provider
7
+ :jsbundling_rails
8
+ end
9
+
10
+ def paths
11
+ [Rails.root.join("app/javascript").to_s]
12
+ end
13
+
14
+ def used?
15
+ Bundler.definition.dependencies.any? do |dep|
16
+ dep.name == "jsbundling-rails"
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsDevtools
4
+ module AssetProviders
5
+ class PropshaftConfig
6
+ def provider
7
+ :propshaft
8
+ end
9
+
10
+ def paths
11
+ Rails.application.config.assets.paths.select { |p| p.to_s.end_with?("images") }
12
+ end
13
+
14
+ def used?
15
+ defined?(Propshaft)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsDevtools
4
+ module AssetProviders
5
+ class ShakapackerConfig
6
+ def provider
7
+ :shakapacker
8
+ end
9
+
10
+ def paths
11
+ return @paths if defined?(@paths)
12
+
13
+ shakapacker_config_path = Rails.root.join("config", "shakapacker.yml")
14
+ shakapacker_config = YAML.load_file(shakapacker_config_path, aliases: true)
15
+
16
+ @paths = Set.new([shakapacker_config["source_path"]])
17
+ additional_paths = Set.new(shakapacker_config["additional_paths"])
18
+ @paths = @paths.merge(additional_paths).to_a.compact
19
+ end
20
+
21
+ def used?
22
+ Rails.root.join("config", "shakapacker.yml").exist?
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsDevtools
4
+ module AssetProviders
5
+ class SprocketConfig
6
+ def provider
7
+ :sprockets
8
+ end
9
+
10
+ def paths
11
+ Rails.application.config.assets.paths.select { |p| p.to_s.end_with?("images") }
12
+ end
13
+
14
+ def used?
15
+ Rails.application.config.respond_to?(:assets)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsDevtools
4
+ module AssetProviders
5
+ class ViteRailsConfig
6
+ def provider
7
+ :vite_rails
8
+ end
9
+
10
+ def paths
11
+ [Rails.root.join("app/frontend").to_s]
12
+ end
13
+
14
+ def used?
15
+ Rails.root.join("config/vite.json").exist?
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,22 @@
1
+ require "fastimage"
2
+ require "phlex-rails"
3
+ require "turbo-rails"
4
+
5
+ module RailsDevtools
6
+ class Engine < ::Rails::Engine
7
+ isolate_namespace RailsDevtools
8
+
9
+ # rubocop:disable Layout/LineLength
10
+ initializer "rails_devtools.environment_check" do
11
+ unless Rails.env.local?
12
+ raise "Rails Devtools can only be used in your local environment. Please make sure that it is not included in production environment in your gemfile."
13
+ end
14
+ end
15
+ # rubocop:enable Layout/LineLength
16
+
17
+ # Add views to autoload paths for Phlex
18
+ config.autoload_paths << "#{root}/app/views"
19
+ config.autoload_paths << "#{root}/app/views/layouts"
20
+ config.autoload_paths << "#{root}/app/views/components"
21
+ end
22
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsDevtools
4
+ class Importmap < Importmaps::Base
5
+ pin "@hotwired/turbo-rails", to: "turbo.min.js", vendor: true
6
+ pin "@hotwired/stimulus", to: "stimulus.min.js", vendor: true
7
+ pin "@hotwired/stimulus-loading", to: "stimulus-loading.js", vendor: true
8
+ pin "@stimulus-components/reveal", to: "@stimulus-components--reveal.js", vendor: true # @5.0.0
9
+ pin "@stimulus-components/clipboard", to: "@stimulus-components--clipboard.js", vendor: true # @5.0.0
10
+ pin "@stimulus-components/notification", to: "@stimulus-components--notification.js", vendor: true # @3.0.0
11
+ pin "stimulus-use", vendor: true # @0.52.2
12
+
13
+ pin "application"
14
+ pin_all_from RailsDevtools::Engine.root.join("app/javascript/controllers"), under: "controllers"
15
+ end
16
+ end