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.
- checksums.yaml +7 -0
- data/README.md +92 -0
- data/Rakefile +8 -0
- data/app/assets/config/devtools_manifest.js +1 -0
- data/app/assets/stylesheets/devtools/application.css +15 -0
- data/app/controllers/rails_devtools/application_controller.rb +4 -0
- data/app/controllers/rails_devtools/base_controller.rb +7 -0
- data/app/controllers/rails_devtools/database_tables_controller.rb +16 -0
- data/app/controllers/rails_devtools/frontend/modules_controller.rb +18 -0
- data/app/controllers/rails_devtools/gems_controller.rb +16 -0
- data/app/controllers/rails_devtools/host_app_images_controller.rb +35 -0
- data/app/controllers/rails_devtools/image_assets_controller.rb +43 -0
- data/app/controllers/rails_devtools/routes/route_path_inputs_controller.rb +23 -0
- data/app/controllers/rails_devtools/routes_controller.rb +21 -0
- data/app/forms/rails_devtools/database_table_search_form.rb +51 -0
- data/app/forms/rails_devtools/gem_search_form.rb +86 -0
- data/app/forms/rails_devtools/image_search_form.rb +30 -0
- data/app/forms/rails_devtools/route_search_form.rb +17 -0
- data/app/helpers/rails_devtools/application_helper.rb +4 -0
- data/app/javascript/application.js +4 -0
- data/app/javascript/controllers/application.js +10 -0
- data/app/javascript/controllers/checkbox_controller.js +9 -0
- data/app/javascript/controllers/index.js +11 -0
- data/app/javascript/controllers/search_reset_controller.js +7 -0
- data/app/javascript/controllers/turbo_form_controller.js +9 -0
- data/app/jobs/rails_devtools/application_job.rb +4 -0
- data/app/mailers/rails_devtools/application_mailer.rb +6 -0
- data/app/models/rails_devtools/application_record.rb +5 -0
- data/app/models/rails_devtools/image_assets/image_info.rb +85 -0
- data/app/models/rails_devtools/routes/collection.rb +83 -0
- data/app/models/rails_devtools/routes/controller_info.rb +30 -0
- data/app/models/rails_devtools/routes/engine_info.rb +33 -0
- data/app/models/rails_devtools/routes/route_info.rb +120 -0
- data/app/views/rails_devtools/application_layout.rb +90 -0
- data/app/views/rails_devtools/application_view.rb +6 -0
- data/app/views/rails_devtools/components/application_component.rb +24 -0
- data/app/views/rails_devtools/components/flash_message.rb +29 -0
- data/app/views/rails_devtools/components/lucide/base.rb +18 -0
- data/app/views/rails_devtools/components/lucide/close.rb +25 -0
- data/app/views/rails_devtools/components/lucide/database.rb +26 -0
- data/app/views/rails_devtools/components/lucide/external_link.rb +26 -0
- data/app/views/rails_devtools/components/lucide/images.rb +27 -0
- data/app/views/rails_devtools/components/lucide/menu.rb +26 -0
- data/app/views/rails_devtools/components/lucide/package.rb +30 -0
- data/app/views/rails_devtools/components/lucide/pocket_knife.rb +28 -0
- data/app/views/rails_devtools/components/lucide/sign_post.rb +29 -0
- data/app/views/rails_devtools/components/lucide/trash.rb +26 -0
- data/app/views/rails_devtools/components/lucide/triangle_alert.rb +29 -0
- data/app/views/rails_devtools/components/page_content.rb +27 -0
- data/app/views/rails_devtools/components/ui/drawer.rb +49 -0
- data/app/views/rails_devtools/components/ui/menu.rb +81 -0
- data/app/views/rails_devtools/components/ui/search_form.rb +65 -0
- data/app/views/rails_devtools/components.rb +5 -0
- data/app/views/rails_devtools/database_tables/index.rb +32 -0
- data/app/views/rails_devtools/database_tables/table_card.rb +61 -0
- data/app/views/rails_devtools/gems/gem_card.rb +74 -0
- data/app/views/rails_devtools/gems/index.rb +32 -0
- data/app/views/rails_devtools/image_assets/image_card.rb +37 -0
- data/app/views/rails_devtools/image_assets/image_details.rb +82 -0
- data/app/views/rails_devtools/image_assets/index.rb +39 -0
- data/app/views/rails_devtools/routes/index.rb +37 -0
- data/app/views/rails_devtools/routes/route_card.rb +70 -0
- data/app/views/rails_devtools/routes/route_details/controller_card.rb +87 -0
- data/app/views/rails_devtools/routes/route_details/route_path_input.rb +46 -0
- data/app/views/rails_devtools/routes/route_details.rb +171 -0
- data/config/routes.rb +24 -0
- data/lib/rails_devtools/asset_config.rb +52 -0
- data/lib/rails_devtools/asset_providers/jsbundling_rails_config.rb +21 -0
- data/lib/rails_devtools/asset_providers/propshaft_config.rb +19 -0
- data/lib/rails_devtools/asset_providers/shakapacker_config.rb +26 -0
- data/lib/rails_devtools/asset_providers/sprocket_config.rb +19 -0
- data/lib/rails_devtools/asset_providers/vite_rails_config.rb +19 -0
- data/lib/rails_devtools/engine.rb +22 -0
- data/lib/rails_devtools/importmap.rb +16 -0
- data/lib/rails_devtools/importmaps/base.rb +82 -0
- data/lib/rails_devtools/version.rb +3 -0
- data/lib/rails_devtools.rb +20 -0
- data/lib/tasks/rails_devtools_tasks.rake +4 -0
- data/vendor/javascript/@stimulus-components--clipboard.js +4 -0
- data/vendor/javascript/@stimulus-components--notification.js +4 -0
- data/vendor/javascript/@stimulus-components--reveal.js +4 -0
- data/vendor/javascript/stimulus-autoloader.js +54 -0
- data/vendor/javascript/stimulus-importmap-autoloader.js +27 -0
- data/vendor/javascript/stimulus-loading.js +93 -0
- data/vendor/javascript/stimulus-use.js +4 -0
- data/vendor/javascript/stimulus.min.js +5 -0
- data/vendor/javascript/turbo.min.js +36 -0
- 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
|