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
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: d185839dcc19c72b18c2f20b4be8846054d829f8b6d0b517b512fc8c17ea5c99
4
+ data.tar.gz: b9af4f7560bb0ad748e35db0aaf3566f49bd4d020cc3bdf99564da79251d1156
5
+ SHA512:
6
+ metadata.gz: 9f5311dd1591a436c7d0e81b6545a1131a014affb8e9b94cdecea219d42d33974e25d54dabb4243f21ac93d4c64000410f0ed0447de82498d5c68f7c30b984a2
7
+ data.tar.gz: 70286d2e5bb2ab8ca7670deb7335a941b3ec549ca70e00f801a490d5d900e821ba06d8ae6f53551b75406fa71932c546e02b1426746d1a0f6b0ca5d9bb3837ed
data/README.md ADDED
@@ -0,0 +1,92 @@
1
+ # Rails Devtools
2
+
3
+ Rails Devtools is a set of "quality of life" tools for your rails project, distributed as a rails engine.
4
+ This is inspired by the likes of Nuxt Devtools, Laravel Telescope...
5
+
6
+ This gem is meant to be only used in development, and cannot work at all in production.
7
+
8
+ > [!IMPORTANT]
9
+ > The gem is an alpha version. Is has been tested on several Rails projects from Rails 7.1 to Rails 8.0. It should work on many projects but it could also break easily if your project has some tricky stuff I didn't think about.
10
+ > If you encounter a bug, please create an issue, I'll do my best to fix it.
11
+
12
+ <br />
13
+
14
+ ## Installation
15
+
16
+ - Add the gem to your Gemfile
17
+ ```ruby
18
+ gem 'rails-devtools, group: :development'
19
+ ````
20
+
21
+ - Mount the engine in your routes
22
+ ```ruby
23
+ mount RailsDevtools::Engine => "/devtools"
24
+ ```
25
+
26
+ - Update the bundle
27
+ ```sh
28
+ bundle install
29
+ ```
30
+ - Go to `http://localhost:3000/devtools`
31
+
32
+ <br /><br />
33
+
34
+ ## Screenshots
35
+ <details>
36
+ <summary> Expand to see more screnshots
37
+ <br /><br />
38
+ <img width="1187" alt="devtools_database_tables" src="https://github.com/user-attachments/assets/a5289293-c8c1-475c-abb2-b3c3f322c281" />
39
+ </summary>
40
+ <img width="1191" alt="devtools_gems" src="https://github.com/user-attachments/assets/204293e5-3eaf-400d-99e9-74e493571997" />
41
+ <img width="1194" alt="devtools_image_assets" src="https://github.com/user-attachments/assets/f6b41437-9ea4-4d0e-b1d5-3aff9c156730" />
42
+ <img width="1188" alt="devtools_routes" src="https://github.com/user-attachments/assets/9bcd8435-cc7e-48a3-8a71-83b2ee99afd7" />
43
+ <img width="459" alt="devtools_routes_responsive" src="https://github.com/user-attachments/assets/e3e3ff2d-a54e-4e45-9618-1653d4291d0c" />
44
+ <img width="474" alt="devtools_routes_details_responsive" src="https://github.com/user-attachments/assets/a245e2d0-23d1-4a19-b871-a738a68cd83a" />
45
+ </details>
46
+ <br /><br />
47
+
48
+ ## Features
49
+
50
+ Rails Devtools are fully responsive. I think of them as a companion to my editing efforts and I want to be able to put them next to my IDE.
51
+
52
+ #### Database tables
53
+ - List all your database tables along with their columns and indexes.
54
+ - Search for tables or columns
55
+
56
+ #### Routes
57
+ - List all your application routes
58
+ - Display details about it, along with helpful actions and snippets
59
+ - Warn if a route is not linked to a controller / action (details provide more information)
60
+ - Search for routes by name
61
+
62
+ #### Image assets
63
+ Since there are quite a few asset pipelines in the rails ecosystem, Rails Devtools detects which one is used and adapts its behavior to it. It supports Propshaft, Sprockets, Shakapacker, JS-Bundling-Rails and Vite-Rails.
64
+
65
+ - list image assets in your codebase
66
+ - Display information about them, along with helpful actions and snippets
67
+ - Search for images by name
68
+
69
+ #### Gems
70
+ - list gems in your bundle
71
+ - display their summary
72
+ - display links to their code source, website...
73
+ - display outdated gems along with information about the last version
74
+ - search for gems by name
75
+ <br /><br />
76
+ > [!NOTE]
77
+ > Most of those features are starting points. There are many ways to get a better grasp of a rails codebase. I have some in mind but if you happen to have ideas, feel free to share them in the discussions!
78
+
79
+ <br /><br />
80
+ ## Philosophy
81
+
82
+ As developers, we spend much of our time looking at walls of text. Our codebase does not provide any information architecture, besides classes or methods. There is no high level view of the project, and most of the tooling is either a bunch of commands to run or a script found on stackoverflow.
83
+
84
+ Rails, as a framework, knows many things about our project. This might seem obvious but it knows how to match a route and a controller, what path you need to write to use an image, or what scopes are defined on a model.
85
+
86
+ When you run `rails s`, all those informations are available. But they are hidden behind the mysteries of ActiveRecord, Rails.application and so on.
87
+
88
+ This is why I believe that it makes a lot of sense to provide tools that surface these informations when needed, in a friendly way.
89
+
90
+ <br /><br />
91
+ ## License
92
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require "bundler/setup"
2
+
3
+ APP_RAKEFILE = File.expand_path("test/dummy/Rakefile", __dir__)
4
+ load "rails/tasks/engine.rake"
5
+
6
+ load "rails/tasks/statistics.rake"
7
+
8
+ require "bundler/gem_tasks"
@@ -0,0 +1 @@
1
+ //= link_directory ../stylesheets/devtools .css
@@ -0,0 +1,15 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
+ * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
10
+ * files in this directory. Styles in this file should be added after the last require_* statement.
11
+ * It is generally better to create a new file per style scope.
12
+ *
13
+ *= require_tree .
14
+ *= require_self
15
+ */
@@ -0,0 +1,4 @@
1
+ module RailsDevtools
2
+ class ApplicationController < ActionController::Base
3
+ end
4
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsDevtools
4
+ class BaseController < ApplicationController
5
+ layout -> { ApplicationLayout }
6
+ end
7
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsDevtools
4
+ class DatabaseTablesController < BaseController
5
+ def index
6
+ form = DatabaseTableSearchForm.new(search: form_params[:search])
7
+ render DatabaseTables::Index.new(tables: form.results, form: form)
8
+ end
9
+
10
+ private
11
+
12
+ def form_params
13
+ params[:database_table_search_form] || { search: "" }
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,18 @@
1
+ module RailsDevtools
2
+ module Frontend
3
+ class ModulesController < ApplicationController
4
+ protect_from_forgery except: :show
5
+
6
+ def show
7
+ file = RailsDevtools.importmap.find(params[:path]).file_path
8
+ return head :not_found unless file
9
+
10
+ send_file(
11
+ file,
12
+ type: "application/javascript",
13
+ disposition: "inline"
14
+ )
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsDevtools
4
+ class GemsController < BaseController
5
+ def index
6
+ form = GemSearchForm.new(search: form_params[:search])
7
+ render Gems::Index.new(gems: form.results, form: form)
8
+ end
9
+
10
+ private
11
+
12
+ def form_params
13
+ params[:gem_search_form] || { search: "" }
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsDevtools
4
+ class HostAppImagesController < BaseController
5
+ def show
6
+ return head :not_found unless image?
7
+
8
+ image_path = find_source_image
9
+ return head :not_found unless image_path
10
+
11
+ mime_type = Mime::Type.lookup_by_extension(params[:format])
12
+
13
+ send_file image_path, type: mime_type, disposition: "inline"
14
+ end
15
+
16
+ private
17
+
18
+ def image?
19
+ ImageAssets::ImageInfo::IMAGE_EXTENSIONS.include?(".#{params[:format]}")
20
+ end
21
+
22
+ def find_source_image
23
+ filename = CGI.unescape(File.basename(params[:path]))
24
+ found = nil
25
+
26
+ RailsDevtools.asset_config.paths.each do |base_path|
27
+ paths = Dir.glob("#{base_path}/**/*#{filename}*")
28
+ found = paths.find { |file_path| File.file?(file_path) }
29
+ break if found
30
+ end
31
+
32
+ found
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsDevtools
4
+ class ImageAssetsController < BaseController
5
+ def show
6
+ image_info = ImageAssets::ImageInfo.new(params[:image_path])
7
+ render ImageAssets::ImageDetails.new(image_info: image_info)
8
+ end
9
+
10
+ def index
11
+ form = ImageSearchForm.new(search: form_params[:search])
12
+ render ImageAssets::Index.new(images_by_folder: form.results, form: form)
13
+ end
14
+
15
+ def destroy
16
+ image_info = ImageAssets::ImageInfo.new(params[:image_path])
17
+ raise "This is a not an image" unless image_info.valid?
18
+
19
+ File.delete(image_info.full_path)
20
+
21
+ respond_to do |format|
22
+ format.html { redirect_to image_assets_path, notice: "Image was successfully destroyed." }
23
+ format.turbo_stream {
24
+ render turbo_stream: [
25
+ turbo_stream.remove(image_info.full_path),
26
+ turbo_stream.append(
27
+ "flash_messages",
28
+ Components::FlashMessage.new(
29
+ message: "Image was successfully destroyed."
30
+ )
31
+ )
32
+ ]
33
+ }
34
+ end
35
+ end
36
+
37
+ private
38
+
39
+ def form_params
40
+ params[:image_search_form] || { search: "" }
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsDevtools
4
+ module Routes
5
+ class RoutePathInputsController < ApplicationController
6
+ def update
7
+ route = Routes::Collection.find(params[:id])
8
+
9
+ input_params = { route: route }
10
+
11
+ if params[:engine_prefix].present? && params[:engine_prefix] == "1"
12
+ input_params.merge!(prefix: route.engine_info.helper_prefix)
13
+ end
14
+
15
+ if params[:url_suffix].present? && params[:url_suffix] == "1"
16
+ input_params.merge!(suffix: "url")
17
+ end
18
+
19
+ render Routes::RouteDetails::RoutePathInput.new(**input_params)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsDevtools
4
+ class RoutesController < BaseController
5
+ def index
6
+ form = RouteSearchForm.new(search: form_params[:search])
7
+ render Routes::Index.new(routes: form.results, form: form)
8
+ end
9
+
10
+ def show
11
+ route = Routes::Collection.find(params[:id])
12
+ render Routes::RouteDetails.new(route: route)
13
+ end
14
+
15
+ private
16
+
17
+ def form_params
18
+ params[:route_search_form] || { search: "" }
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsDevtools
4
+ class DatabaseTableSearchForm
5
+ include ActiveModel::Model
6
+
7
+ DatabaseTable = Data.define(:table_name, :columns, :indexes)
8
+
9
+ def initialize(search: "")
10
+ @search = search.downcase
11
+ end
12
+
13
+ def results
14
+ table_names = ActiveRecord::Base.connection.tables - ["schema_migrations", "ar_internal_metadata"]
15
+
16
+ tables = table_names.map do |table|
17
+ DatabaseTable.new(
18
+ table_name: table,
19
+ columns: ActiveRecord::Base.connection.columns(table),
20
+ indexes: indexes(table)
21
+ )
22
+ end
23
+
24
+ return tables if @search.empty?
25
+
26
+ tables.select do |table|
27
+ table.table_name.include?(@search) ||
28
+ table.columns.any? { |column| column.name.include?(@search) }
29
+ end
30
+ end
31
+
32
+ private
33
+
34
+ ShortIndex = Data.define(:name, :columns, :unique)
35
+
36
+ def indexes(table)
37
+ indexes = ActiveRecord::Base.connection.indexes(table)
38
+ indexes.map do |index|
39
+ long_name = index.name
40
+ prefix = "index_#{table}_on_"
41
+ short_name = long_name.gsub(prefix, "").humanize
42
+
43
+ ShortIndex.new(
44
+ name: short_name,
45
+ columns: index.columns,
46
+ unique: index.unique
47
+ )
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsDevtools
4
+ class GemSearchForm
5
+ include ActiveModel::Model
6
+
7
+ GemInfo = Data.define(
8
+ :name,
9
+ :required_version,
10
+ :actual_version,
11
+ :homepage,
12
+ :summary,
13
+ :source_code,
14
+ :documentation,
15
+ :groups,
16
+ :date,
17
+ :latest_version,
18
+ :changelog
19
+ ) do
20
+ def outdated?
21
+ return false if latest_version.nil?
22
+
23
+ actual_version < latest_version.version
24
+ end
25
+ end
26
+
27
+ def initialize(search: "")
28
+ @search = search.downcase
29
+ end
30
+
31
+ def results
32
+ specs = ask_bundler_for_specs
33
+ gems_list = specs.map { |gem_spec| GemInfo.new(**gem_spec) }
34
+
35
+ return order(gems_list) if @search.empty?
36
+
37
+ order(
38
+ gems_list.select { |gem| gem.name.include?(@search) }
39
+ )
40
+ end
41
+
42
+ private
43
+
44
+ GROUP_PRIORITY = {
45
+ "default" => 0,
46
+ "production" => 1,
47
+ "development" => 2,
48
+ "development-test" => 3,
49
+ "test" => 4
50
+ }.freeze
51
+
52
+ def order(gems)
53
+ gems.sort_by do |item|
54
+ [GROUP_PRIORITY.fetch(item.groups.join("-"), 5), item.name]
55
+ end
56
+ end
57
+
58
+ LatestSpec = Data.define(:version, :date)
59
+
60
+ def ask_bundler_for_specs
61
+ bundle = Bundler.load
62
+
63
+ dependencies = bundle.dependencies.map { |dep| [dep.name, dep.groups] }.to_h
64
+ specs = bundle.specs.select do |spec|
65
+ dependencies.keys.include?(spec.name)
66
+ end
67
+
68
+ specs.map do |spec|
69
+ latest_spec = Gem.latest_spec_for(spec.name)
70
+ {
71
+ name: spec.name,
72
+ latest_version: latest_spec ? LatestSpec.new(version: latest_spec.version, date: latest_spec.date) : nil,
73
+ date: spec.date,
74
+ required_version: spec.requirements.to_s,
75
+ actual_version: spec.version.to_s,
76
+ homepage: spec.homepage,
77
+ summary: spec.summary,
78
+ source_code: spec.metadata["source_code_uri"],
79
+ documentation: spec.metadata["documentation_uri"],
80
+ changelog: spec.metadata["changelog_uri"],
81
+ groups: dependencies[spec.name]
82
+ }
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsDevtools
4
+ class ImageSearchForm
5
+ include ActiveModel::Model
6
+
7
+ def initialize(search: "")
8
+ @search = search
9
+ end
10
+
11
+ def results
12
+ folders = RailsDevtools.asset_config.paths
13
+
14
+ images_by_folder = Hash.new { |hash, key| hash[key] = [] }
15
+ extensions = ImageAssets::ImageInfo::IMAGE_EXTENSIONS.map { |ext| ext.delete_prefix(".") }.join(",")
16
+
17
+ folders.each do |dir|
18
+ Dir.glob("#{dir}/**/*{#{@search.upcase}, #{@search.downcase}}*.{#{extensions}}").each do |path|
19
+ image_info = ImageAssets::ImageInfo.new(path)
20
+ next unless image_info.valid?
21
+
22
+ dir = File.dirname(path).gsub(Rails.root.to_s, "")
23
+ images_by_folder[dir] << image_info
24
+ end
25
+ end
26
+
27
+ images_by_folder
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsDevtools
4
+ class RouteSearchForm
5
+ include ActiveModel::Model
6
+
7
+ def initialize(search: "")
8
+ @search = search.downcase
9
+ end
10
+
11
+ def results
12
+ Routes::Collection.all
13
+ .select { |route| route.name.downcase.include?(@search) }
14
+ .group_by { |route| route.engine_info.name }
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,4 @@
1
+ module RailsDevtools
2
+ module ApplicationHelper
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ import "@hotwired/turbo-rails"
2
+ import "controllers"
3
+
4
+ console.log("Hello from application.js")
@@ -0,0 +1,10 @@
1
+ import { Application } from "@hotwired/stimulus"
2
+
3
+ const application = Application.start()
4
+
5
+ // Configure Stimulus development experience
6
+ application.debug = true
7
+ window.Stimulus = application
8
+
9
+ console.log("Hello from controllers/application.js")
10
+ export { application }
@@ -0,0 +1,9 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+
3
+ export default class extends Controller {
4
+ static targets = ["checkbox"]
5
+
6
+ toggle() {
7
+ this.checkboxTarget.checked = !this.checkboxTarget.checked
8
+ }
9
+ }
@@ -0,0 +1,11 @@
1
+ import { application } from "controllers/application";
2
+ import RevealController from '@stimulus-components/reveal'
3
+ import Clipboard from '@stimulus-components/clipboard'
4
+ import Notification from '@stimulus-components/notification'
5
+ import { eagerLoadControllersFrom } from "@hotwired/stimulus-loading"
6
+
7
+ application.register('reveal', RevealController)
8
+ application.register('clipboard', Clipboard)
9
+ application.register('notification', Notification)
10
+
11
+ eagerLoadControllersFrom("controllers", application)
@@ -0,0 +1,7 @@
1
+ import { Controller } from '@hotwired/stimulus'
2
+
3
+ export default class extends Controller {
4
+ reset() {
5
+ this.dispatch("search.reset")
6
+ }
7
+ }
@@ -0,0 +1,9 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+
3
+ export default class extends Controller {
4
+ static targets = ["form"]
5
+
6
+ submit() {
7
+ this.formTarget.requestSubmit()
8
+ }
9
+ }
@@ -0,0 +1,4 @@
1
+ module RailsDevtools
2
+ class ApplicationJob < ActiveJob::Base
3
+ end
4
+ end
@@ -0,0 +1,6 @@
1
+ module RailsDevtools
2
+ class ApplicationMailer < ActionMailer::Base
3
+ default from: "from@example.com"
4
+ layout "mailer"
5
+ end
6
+ end
@@ -0,0 +1,5 @@
1
+ module RailsDevtools
2
+ class ApplicationRecord < ActiveRecord::Base
3
+ self.abstract_class = true
4
+ end
5
+ end