rails_spotlight 0.2.5 → 0.3.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 +4 -4
- data/README.md +58 -5
- data/chrome_ext_private_policy.md +7 -3
- data/lib/rails_spotlight/app_notifications.rb +3 -1
- data/lib/rails_spotlight/channels/handlers/live_console_handler.rb +64 -0
- data/lib/rails_spotlight/channels/handlers/logs_handler.rb +38 -0
- data/lib/rails_spotlight/channels/handlers.rb +29 -0
- data/lib/rails_spotlight/channels/silence_action_cable_broadcaster_logging.rb +26 -0
- data/lib/rails_spotlight/channels/spotlight_channel.rb +71 -0
- data/lib/rails_spotlight/channels.rb +2 -2
- data/lib/rails_spotlight/configuration.rb +21 -4
- data/lib/rails_spotlight/event.rb +2 -1
- data/lib/rails_spotlight/log_interceptor.rb +37 -29
- data/lib/rails_spotlight/middlewares/handlers/base_action_handler.rb +34 -2
- data/lib/rails_spotlight/middlewares/handlers/code_analysis_action_handler.rb +89 -0
- data/lib/rails_spotlight/middlewares/handlers/console_action_handler.rb +5 -23
- data/lib/rails_spotlight/middlewares/handlers/directory_index_action_handler.rb +112 -0
- data/lib/rails_spotlight/middlewares/handlers/file_action_handler.rb +18 -4
- data/lib/rails_spotlight/middlewares/handlers/meta_action_handler.rb +0 -1
- data/lib/rails_spotlight/middlewares/handlers/sql_action_handler.rb +6 -15
- data/lib/rails_spotlight/middlewares/handlers/verify_action_handler.rb +6 -2
- data/lib/rails_spotlight/middlewares/request_completed.rb +14 -10
- data/lib/rails_spotlight/middlewares/request_handler.rb +5 -1
- data/lib/rails_spotlight/railtie.rb +12 -4
- data/lib/rails_spotlight/render_view_reporter.rb +3 -1
- data/lib/rails_spotlight/utils.rb +2 -0
- data/lib/rails_spotlight/version.rb +1 -1
- data/lib/tasks/init.rake +75 -6
- metadata +9 -4
- data/lib/rails_spotlight/channels/live_console_channel.rb +0 -62
- data/lib/rails_spotlight/channels/request_completed_channel.rb +0 -15
@@ -0,0 +1,89 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'tempfile'
|
5
|
+
|
6
|
+
module RailsSpotlight
|
7
|
+
module Middlewares
|
8
|
+
module Handlers
|
9
|
+
class CodeAnalysisActionHandler < BaseActionHandler
|
10
|
+
def skip_project_validation?
|
11
|
+
true
|
12
|
+
end
|
13
|
+
|
14
|
+
def execute
|
15
|
+
raise UnprocessableEntity, 'Please add rubocop to your project' unless rubocop_installed?
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def rubocop_installed?
|
21
|
+
Gem::Specification.find_all_by_name('rubocop').any?
|
22
|
+
rescue Gem::LoadError
|
23
|
+
false
|
24
|
+
end
|
25
|
+
|
26
|
+
def json_response_body # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
27
|
+
require 'rubocop'
|
28
|
+
|
29
|
+
# Create a temporary file to hold the source code
|
30
|
+
tempfile = Tempfile.new(['source', '.rb'])
|
31
|
+
tempfile.write(source)
|
32
|
+
tempfile.rewind
|
33
|
+
|
34
|
+
# Create a temporary file to capture the RuboCop output
|
35
|
+
output_file = Tempfile.new(['rubocop_output', '.json'])
|
36
|
+
|
37
|
+
# Define RuboCop options
|
38
|
+
options = {
|
39
|
+
formatters: [['json', output_file.path]],
|
40
|
+
cache: false,
|
41
|
+
safe: true
|
42
|
+
}
|
43
|
+
|
44
|
+
options[:autocorrect] = variant == :autofix
|
45
|
+
|
46
|
+
# Check for custom .rubocop.yml configuration
|
47
|
+
config_file = ::RailsSpotlight.config.rubocop_config_path || File.join(RailsSpotlight::Configuration.rails_root, '.rubocop.yml')
|
48
|
+
|
49
|
+
# Run RuboCop with appropriate options
|
50
|
+
config_store = RuboCop::ConfigStore.new
|
51
|
+
config_store.options_config = config_file if File.exist?(config_file)
|
52
|
+
runner = RuboCop::Runner.new(options, config_store)
|
53
|
+
|
54
|
+
begin
|
55
|
+
runner.run([tempfile.path])
|
56
|
+
|
57
|
+
# Read the corrected source
|
58
|
+
tempfile.rewind
|
59
|
+
corrected_source = File.read(tempfile.path)
|
60
|
+
|
61
|
+
# Read the RuboCop analysis result from the output file
|
62
|
+
output_file.rewind
|
63
|
+
analysis_result = JSON.parse(output_file.read)
|
64
|
+
|
65
|
+
{
|
66
|
+
source: variant == :autofix ? corrected_source : source,
|
67
|
+
analysis_result: analysis_result,
|
68
|
+
variant: variant
|
69
|
+
}
|
70
|
+
ensure
|
71
|
+
# Close and unlink the tempfile
|
72
|
+
tempfile.close
|
73
|
+
tempfile.unlink
|
74
|
+
output_file.close
|
75
|
+
output_file.unlink
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def source
|
80
|
+
@source ||= body_fetch('source')
|
81
|
+
end
|
82
|
+
|
83
|
+
def variant
|
84
|
+
@variant ||= body_fetch('variant', 'check').to_sym
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -6,46 +6,28 @@ module RailsSpotlight
|
|
6
6
|
module Handlers
|
7
7
|
class ConsoleActionHandler < BaseActionHandler
|
8
8
|
def execute
|
9
|
-
validate_project!
|
10
|
-
|
11
9
|
RailsSpotlight.config.logger && RailsSpotlight.config.logger.info("Executing command: #{command}") # rubocop:disable Style/SafeNavigation
|
12
10
|
executor.execute(command)
|
13
11
|
end
|
14
12
|
|
15
13
|
private
|
16
14
|
|
17
|
-
def validate_project!
|
18
|
-
return if for_project.blank?
|
19
|
-
return if for_project.include?(::RailsSpotlight.config.project_name)
|
20
|
-
|
21
|
-
raise UnprocessableEntity, "Check your connection settings the current command is not allowed to be executed on the #{::RailsSpotlight.config.project_name} project"
|
22
|
-
end
|
23
|
-
|
24
15
|
def executor
|
25
16
|
@executor ||= ::RailsSpotlight::RailsCommandExecutor.new
|
26
17
|
end
|
27
18
|
|
28
19
|
def inspect_types
|
29
|
-
@inspect_types ||=
|
20
|
+
@inspect_types ||= body_fetch('inspect_types')
|
30
21
|
end
|
31
22
|
|
32
23
|
def command
|
33
|
-
@command ||=
|
34
|
-
end
|
35
|
-
|
36
|
-
def for_project
|
37
|
-
@for_project ||= json_request_body['project']
|
24
|
+
@command ||= body_fetch('command')
|
38
25
|
end
|
39
26
|
|
40
27
|
def json_response_body
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
project: ::RailsSpotlight.config.project_name
|
45
|
-
}
|
46
|
-
else
|
47
|
-
executor.result_as_json.merge(project: ::RailsSpotlight.config.project_name)
|
48
|
-
end
|
28
|
+
return executor.result_as_json unless executor.execution_successful?
|
29
|
+
|
30
|
+
{ result: executor.result_as_json(inspect_types: inspect_types) }
|
49
31
|
end
|
50
32
|
end
|
51
33
|
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'find'
|
5
|
+
require 'pathname'
|
6
|
+
|
7
|
+
module RailsSpotlight
|
8
|
+
module Middlewares
|
9
|
+
module Handlers
|
10
|
+
class DirectoryIndexActionHandler < BaseActionHandler
|
11
|
+
def execute
|
12
|
+
@result = directory_to_json(::RailsSpotlight.config.rails_root)
|
13
|
+
rescue => e # rubocop:disable Style/RescueStandardError
|
14
|
+
raise UnprocessableEntity, e.message
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
attr_reader :result
|
20
|
+
|
21
|
+
def directory_to_json(path) # rubocop:disable Metrics/CyclomaticComplexity
|
22
|
+
relative_path = Pathname.new(path).relative_path_from(::RailsSpotlight.config.rails_root).to_s
|
23
|
+
return nil if ignored?(relative_path)
|
24
|
+
|
25
|
+
entry = {
|
26
|
+
name: File.basename(path),
|
27
|
+
path: relative_path,
|
28
|
+
dir: File.directory?(path),
|
29
|
+
children: []
|
30
|
+
}
|
31
|
+
|
32
|
+
if entry[:dir]
|
33
|
+
children = sort_children(Dir.children(path), path)
|
34
|
+
children.each do |child|
|
35
|
+
child_path = File.join(path, child)
|
36
|
+
child_entry = directory_to_json(child_path)
|
37
|
+
entry[:children] << child_entry if child_entry
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
return entry unless entry[:dir]
|
42
|
+
return entry unless entry[:children].empty?
|
43
|
+
|
44
|
+
show_empty_directories ? entry : nil
|
45
|
+
end
|
46
|
+
|
47
|
+
def sort_children(children, parent_path)
|
48
|
+
if sort_folders_first
|
49
|
+
children.sort_by do |child|
|
50
|
+
child_path = File.join(parent_path, child)
|
51
|
+
[File.directory?(child_path) ? 0 : 1, child.downcase]
|
52
|
+
end
|
53
|
+
else
|
54
|
+
children.sort_by(&:downcase)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def ignore
|
59
|
+
@ignore ||= body_fetch('ignore', [])
|
60
|
+
end
|
61
|
+
|
62
|
+
def sort_folders_first
|
63
|
+
@sort_folders_first ||= body_fetch('sort_folders_first', true)
|
64
|
+
end
|
65
|
+
|
66
|
+
def omnit_gitignore
|
67
|
+
@omnit_gitignore ||= body_fetch('omnit_gitignore', false)
|
68
|
+
end
|
69
|
+
|
70
|
+
def ignore_patterns
|
71
|
+
@ignore_patterns ||= ignore + ::RailsSpotlight.config.directory_index_ignore + (omnit_gitignore ? [] : gitignore_patterns)
|
72
|
+
end
|
73
|
+
|
74
|
+
def gitignore_file
|
75
|
+
@gitignore_file ||= File.join(::RailsSpotlight.config.rails_root, '.gitignore')
|
76
|
+
end
|
77
|
+
|
78
|
+
def show_empty_directories
|
79
|
+
@show_empty_directories ||= body_fetch('show_empty_directories', false)
|
80
|
+
end
|
81
|
+
|
82
|
+
def gitignore_patterns
|
83
|
+
@gitignore_patterns ||= if File.exist?(gitignore_file)
|
84
|
+
File.readlines(gitignore_file).map do |line|
|
85
|
+
line.strip!
|
86
|
+
next if line.empty? || line.start_with?('#') || line.start_with?('!')
|
87
|
+
|
88
|
+
line
|
89
|
+
end.compact
|
90
|
+
else
|
91
|
+
[]
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def ignored?(path)
|
96
|
+
return false if path == '.'
|
97
|
+
|
98
|
+
ignore_patterns.any? do |pattern|
|
99
|
+
File.fnmatch?(pattern, "/#{path}", File::FNM_PATHNAME | File::FNM_DOTMATCH)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def json_response_body
|
104
|
+
{
|
105
|
+
root_path: ::RailsSpotlight.config.rails_root,
|
106
|
+
result: result
|
107
|
+
}
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -23,14 +23,16 @@ module RailsSpotlight
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def new_content
|
26
|
-
|
26
|
+
body_fetch('content')
|
27
27
|
end
|
28
28
|
|
29
29
|
def json_response_body
|
30
30
|
{
|
31
31
|
source: text_response_body,
|
32
32
|
changed: write_mode?,
|
33
|
-
|
33
|
+
in_project: file_in_project?,
|
34
|
+
relative_path: Pathname.new(file_path).relative_path_from(::RailsSpotlight.config.rails_root).to_s,
|
35
|
+
root_path: ::RailsSpotlight.config.rails_root
|
34
36
|
}.merge(write_mode? ? { new_content: new_content } : {})
|
35
37
|
end
|
36
38
|
|
@@ -55,7 +57,7 @@ module RailsSpotlight
|
|
55
57
|
end
|
56
58
|
|
57
59
|
def request_mode
|
58
|
-
@request_mode ||=
|
60
|
+
@request_mode ||= body_fetch('mode', 'read')
|
59
61
|
end
|
60
62
|
|
61
63
|
def path_valid?
|
@@ -67,13 +69,17 @@ module RailsSpotlight
|
|
67
69
|
original_file_path
|
68
70
|
elsif file_in_project?
|
69
71
|
File.join(::RailsSpotlight.config.rails_root, original_file_path)
|
72
|
+
elsif file_in_project_app_dir?
|
73
|
+
File.join(::RailsSpotlight.config.rails_root, 'app', original_file_path)
|
74
|
+
elsif file_in_project_views_dir?
|
75
|
+
File.join(::RailsSpotlight.config.rails_root, 'app', 'views', original_file_path)
|
70
76
|
else # rubocop:disable Lint/DuplicateBranch
|
71
77
|
original_file_path
|
72
78
|
end
|
73
79
|
end
|
74
80
|
|
75
81
|
def original_file_path
|
76
|
-
@original_file_path ||=
|
82
|
+
@original_file_path ||= body_fetch('file')
|
77
83
|
end
|
78
84
|
|
79
85
|
def path_file_in_project?
|
@@ -84,6 +90,14 @@ module RailsSpotlight
|
|
84
90
|
File.exist?(File.join(::RailsSpotlight.config.rails_root, original_file_path))
|
85
91
|
end
|
86
92
|
|
93
|
+
def file_in_project_app_dir?
|
94
|
+
File.exist?(File.join(::RailsSpotlight.config.rails_root, 'app', original_file_path))
|
95
|
+
end
|
96
|
+
|
97
|
+
def file_in_project_views_dir?
|
98
|
+
File.exist?(File.join(::RailsSpotlight.config.rails_root, 'app', 'views', original_file_path))
|
99
|
+
end
|
100
|
+
|
87
101
|
def file_outside_project?
|
88
102
|
!file_in_project? && File.exist?(original_file_path)
|
89
103
|
end
|
@@ -5,7 +5,6 @@ module RailsSpotlight
|
|
5
5
|
module Handlers
|
6
6
|
class SqlActionHandler < BaseActionHandler
|
7
7
|
def execute
|
8
|
-
validate_project!
|
9
8
|
return transaction unless ActiveSupport.const_defined?('ExecutionContext')
|
10
9
|
|
11
10
|
ActiveSupport::ExecutionContext.set(rails_spotlight: request_id) do
|
@@ -15,13 +14,6 @@ module RailsSpotlight
|
|
15
14
|
|
16
15
|
private
|
17
16
|
|
18
|
-
def validate_project!
|
19
|
-
return if required_projects.blank?
|
20
|
-
return if required_projects.include?(::RailsSpotlight.config.project_name)
|
21
|
-
|
22
|
-
raise UnprocessableEntity, "Check your connection settings the current query is not allowed to be executed on the #{::RailsSpotlight.config.project_name} project"
|
23
|
-
end
|
24
|
-
|
25
17
|
def transaction
|
26
18
|
ActiveRecord::Base.transaction do
|
27
19
|
begin # rubocop:disable Style/RedundantBegin
|
@@ -56,8 +48,7 @@ module RailsSpotlight
|
|
56
48
|
result: result,
|
57
49
|
logs: logs,
|
58
50
|
error: error.present? ? error.inspect : nil,
|
59
|
-
|
60
|
-
project: ::RailsSpotlight.config.project_name
|
51
|
+
query_mode: force_execution? ? 'force' : 'default'
|
61
52
|
}
|
62
53
|
end
|
63
54
|
|
@@ -72,15 +63,15 @@ module RailsSpotlight
|
|
72
63
|
end
|
73
64
|
|
74
65
|
def query
|
75
|
-
@query ||=
|
66
|
+
@query ||= body_fetch('query')
|
76
67
|
end
|
77
68
|
|
78
69
|
def raw_options
|
79
|
-
@raw_options ||=
|
70
|
+
@raw_options ||= body_fetch('options', {}) || {}
|
80
71
|
end
|
81
72
|
|
82
|
-
def
|
83
|
-
@
|
73
|
+
def mode
|
74
|
+
@mode ||= body_fetch('mode', 'default')
|
84
75
|
end
|
85
76
|
|
86
77
|
def use
|
@@ -95,7 +86,7 @@ module RailsSpotlight
|
|
95
86
|
end
|
96
87
|
|
97
88
|
def force_execution?
|
98
|
-
@force_execution ||=
|
89
|
+
@force_execution ||= mode == 'force'
|
99
90
|
end
|
100
91
|
end
|
101
92
|
end
|
@@ -12,15 +12,19 @@ module RailsSpotlight
|
|
12
12
|
"Rails Spotlight is working!\nRails version: #{Rails.version}\nRails environment: #{Rails.env}"
|
13
13
|
end
|
14
14
|
|
15
|
+
def skip_project_validation?
|
16
|
+
true
|
17
|
+
end
|
18
|
+
|
15
19
|
def json_response_body
|
16
20
|
{
|
17
21
|
params: request.params,
|
18
22
|
body: request.body.read,
|
19
23
|
content_type: request.content_type,
|
20
24
|
request_method: request.request_method,
|
21
|
-
version:
|
25
|
+
version: request_spotlight_version,
|
26
|
+
for_projects: request_for_projects,
|
22
27
|
current_gem_version: ::RailsSpotlight::VERSION,
|
23
|
-
project: ::RailsSpotlight.config.project_name,
|
24
28
|
action_cable_path: defined?(ActionCable) ? ActionCable&.server&.config&.mount_path : nil
|
25
29
|
}
|
26
30
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative 'concerns/skip_request_paths'
|
4
|
+
require_relative '../channels/spotlight_channel'
|
4
5
|
|
5
6
|
module RailsSpotlight
|
6
7
|
module Middlewares
|
@@ -13,6 +14,8 @@ module RailsSpotlight
|
|
13
14
|
end
|
14
15
|
|
15
16
|
def call(env)
|
17
|
+
return app.call(env) unless ::RailsSpotlight.config.request_completed_broadcast_enabled?
|
18
|
+
|
16
19
|
if skip?(env['PATH_INFO']) || (env['HTTP_CONNECTION'] == 'Upgrade' && env['HTTP_UPGRADE'] == 'websocket')
|
17
20
|
app.call(env)
|
18
21
|
else
|
@@ -40,17 +43,18 @@ module RailsSpotlight
|
|
40
43
|
request = ActionDispatch::Request.new(env)
|
41
44
|
|
42
45
|
host, url = host_and_url(env)
|
43
|
-
|
44
|
-
'rails_spotlight_request_completed_channel',
|
46
|
+
RailsSpotlight::Channels::SpotlightChannel.broadcast(
|
45
47
|
{
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
48
|
+
type: 'request_completed',
|
49
|
+
payload: {
|
50
|
+
id: rails_spotlight_request_id,
|
51
|
+
http_method: env['REQUEST_METHOD'],
|
52
|
+
host: host,
|
53
|
+
url: url,
|
54
|
+
format: request.format.symbol,
|
55
|
+
controller: request.path_parameters[:controller],
|
56
|
+
action: request.path_parameters[:action]
|
57
|
+
}
|
54
58
|
}
|
55
59
|
)
|
56
60
|
end
|
@@ -2,11 +2,13 @@
|
|
2
2
|
|
3
3
|
require_relative 'handlers/base_action_handler'
|
4
4
|
require_relative 'handlers/file_action_handler'
|
5
|
+
require_relative 'handlers/directory_index_action_handler'
|
5
6
|
require_relative 'handlers/sql_action_handler'
|
6
7
|
require_relative 'handlers/verify_action_handler'
|
7
8
|
require_relative 'handlers/not_found_action_handler'
|
8
9
|
require_relative 'handlers/meta_action_handler'
|
9
10
|
require_relative 'handlers/console_action_handler'
|
11
|
+
require_relative 'handlers/code_analysis_action_handler'
|
10
12
|
|
11
13
|
module RailsSpotlight
|
12
14
|
module Middlewares
|
@@ -27,14 +29,16 @@ module RailsSpotlight
|
|
27
29
|
|
28
30
|
attr_reader :app
|
29
31
|
|
30
|
-
def handle(request, action, content_type = :json)
|
32
|
+
def handle(request, action, content_type = :json) # rubocop:disable Metrics/CyclomaticComplexity
|
31
33
|
args = [SecureRandom.uuid, request, content_type]
|
32
34
|
case action
|
33
35
|
when 'file' then Handlers::FileActionHandler.new(*args).call
|
36
|
+
when 'directory_index' then Handlers::DirectoryIndexActionHandler.new(*args).call
|
34
37
|
when 'sql' then Handlers::SqlActionHandler.new(*args).call
|
35
38
|
when 'verify' then Handlers::VerifyActionHandler.new(*args).call
|
36
39
|
when 'meta' then Handlers::MetaActionHandler.new(*args).call
|
37
40
|
when 'console' then Handlers::ConsoleActionHandler.new(*args).call
|
41
|
+
when 'code_analysis' then Handlers::CodeAnalysisActionHandler.new(*args).call
|
38
42
|
else
|
39
43
|
Handlers::NotFoundActionHandler.new(*args).call
|
40
44
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'rails/railtie'
|
4
|
+
require_relative 'log_interceptor'
|
4
5
|
|
5
6
|
module RailsSpotlight
|
6
7
|
class Railtie < ::Rails::Railtie
|
@@ -9,7 +10,10 @@ module RailsSpotlight
|
|
9
10
|
end
|
10
11
|
|
11
12
|
initializer 'rails_spotlight.log_interceptor' do
|
12
|
-
|
13
|
+
unless Rails.env.production?
|
14
|
+
Rails.logger&.extend(LogInterceptor)
|
15
|
+
defined?(Sidekiq::Logger) && Sidekiq.logger&.extend(LogInterceptor)
|
16
|
+
end
|
13
17
|
end
|
14
18
|
|
15
19
|
initializer 'rails_spotlight.subscribe_to_notifications' do
|
@@ -26,8 +30,7 @@ module RailsSpotlight
|
|
26
30
|
app.config.after_initialize do
|
27
31
|
update_actioncable_allowed_request_origins!
|
28
32
|
|
29
|
-
require 'rails_spotlight/channels/
|
30
|
-
require 'rails_spotlight/channels/live_console_channel' if ::RailsSpotlight.config.live_console_enabled?
|
33
|
+
require 'rails_spotlight/channels/spotlight_channel' if ::RailsSpotlight.config.request_completed_broadcast_enabled?
|
31
34
|
|
32
35
|
app.routes.draw { mount ActionCable.server => '/cable' } if ::RailsSpotlight.config.auto_mount_action_cable?
|
33
36
|
end
|
@@ -51,7 +54,12 @@ module RailsSpotlight
|
|
51
54
|
|
52
55
|
return unless ::RailsSpotlight.config.request_completed_broadcast_enabled?
|
53
56
|
|
54
|
-
app.middleware.insert_after ::RailsSpotlight::Middlewares::HeaderMarker, RailsSpotlight::Middlewares::RequestCompleted, app.config
|
57
|
+
# app.middleware.insert_after ::RailsSpotlight::Middlewares::HeaderMarker, RailsSpotlight::Middlewares::RequestCompleted, app.config
|
58
|
+
if defined? ActionDispatch::Executor
|
59
|
+
app.middleware.insert_after ActionDispatch::Executor, ::RailsSpotlight::Middlewares::RequestCompleted, app.config
|
60
|
+
else
|
61
|
+
app.middleware.use ::RailsSpotlight::Middlewares::RequestCompleted
|
62
|
+
end
|
55
63
|
end
|
56
64
|
|
57
65
|
def app
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module RailsSpotlight
|
2
4
|
class RenderViewReporter
|
3
5
|
def self.report_rendered_view_locals(view, locals: nil, params: nil, show_devise: false, skip_vars: [], metadata: {})
|
@@ -12,7 +14,7 @@ module RailsSpotlight
|
|
12
14
|
|
13
15
|
def self.serialize_as_json(value)
|
14
16
|
value.respond_to?(:as_json) ? value.as_json : nil
|
15
|
-
rescue => e
|
17
|
+
rescue => e # rubocop:disable Style/RescueStandardError
|
16
18
|
{
|
17
19
|
__serialization_error: e.message,
|
18
20
|
__source: value.inspect
|
data/lib/tasks/init.rake
CHANGED
@@ -4,7 +4,7 @@ require 'rake'
|
|
4
4
|
|
5
5
|
namespace :rails_spotlight do # rubocop:disable Metrics/BlockLength
|
6
6
|
desc 'Generate rails_spotlight configuration file'
|
7
|
-
task generate_config: :environment do
|
7
|
+
task generate_config: :environment do # rubocop:disable Metrics/BlockLength
|
8
8
|
require 'fileutils'
|
9
9
|
|
10
10
|
config_path = Rails.root.join('config', 'rails_spotlight.yml')
|
@@ -19,15 +19,21 @@ namespace :rails_spotlight do # rubocop:disable Metrics/BlockLength
|
|
19
19
|
MIDDLEWARE_SKIPPED_PATHS: []
|
20
20
|
NOT_ENCODABLE_EVENT_VALUES:
|
21
21
|
SKIP_RENDERED_IVARS: []
|
22
|
+
BLOCK_EDITING_FILES: false
|
23
|
+
BLOCK_EDITING_FILES_OUTSIDE_OF_THE_PROJECT: true
|
24
|
+
DIRECTORY_INDEX_IGNORE: ['/.git', '**/*.lock', '**/.DS_Store', '/app/assets/images/**', '/app/assets/fonts/**', '/app/assets/builds/**']
|
25
|
+
RUBOCOP_CONFIG_PATH: '.rubocop.yml'
|
22
26
|
# Rest of the configuration is required for ActionCable. It will be disabled automatically in when ActionCable is not available.
|
23
|
-
|
27
|
+
AUTO_MOUNT_ACTION_CABLE: false
|
28
|
+
ACTION_CABLE_MOUNT_PATH: /cable
|
29
|
+
# Required for all action cable features
|
30
|
+
USE_ACTION_CABLE: false
|
24
31
|
LIVE_CONSOLE_ENABLED: false
|
25
32
|
# Experimental feature.
|
26
33
|
REQUEST_COMPLETED_BROADCAST_ENABLED: false
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
BLOCK_EDITING_FILES_OUTSIDE_OF_THE_PROJECT: true
|
34
|
+
LIVE_LOGS_ENABLED: false
|
35
|
+
DEFAULT_RS_SRC: default
|
36
|
+
FORM_JS_EXECUTION_TOKEN: <%= Digest::MD5.hexdigest(Rails.application.class.respond_to?(:module_parent_name) ? Rails.application.class.module_parent_name : Rails.application.class.parent_name)%>
|
31
37
|
YAML
|
32
38
|
|
33
39
|
if File.exist?(config_path)
|
@@ -38,4 +44,67 @@ namespace :rails_spotlight do # rubocop:disable Metrics/BlockLength
|
|
38
44
|
puts 'Created config file: config/rails_spotlight.yml'
|
39
45
|
end
|
40
46
|
end
|
47
|
+
|
48
|
+
desc "Generate rails_spotlight JavaScript ERB partial for application layout to allow injecting JS code from the extension"
|
49
|
+
task inject_js_partial: :environment do
|
50
|
+
# Define the partial name and path
|
51
|
+
partial_name = "_rails_spotlight_extension_js.html.erb"
|
52
|
+
partial_path = "app/views/layouts/#{partial_name}"
|
53
|
+
|
54
|
+
# Define the JavaScript code
|
55
|
+
js_code = <<~JS
|
56
|
+
<script>
|
57
|
+
try {
|
58
|
+
function executeScriptFromMessage(msg) {
|
59
|
+
if (msg.token === "<%=::RailsSpotlight.config.form_js_execution_token%>") {
|
60
|
+
try {
|
61
|
+
const func = new Function(msg.code);
|
62
|
+
func();
|
63
|
+
return {status: 'Executed'};
|
64
|
+
} catch (e) {
|
65
|
+
return {status: 'Error', error: e};
|
66
|
+
}
|
67
|
+
} else {
|
68
|
+
return {status: 'Error', error: 'Invalid token provided, script execution aborted.'};
|
69
|
+
}
|
70
|
+
}
|
71
|
+
|
72
|
+
window.addEventListener('message', (event) => {
|
73
|
+
if (event.data && event.data.type === 'RAILS_SPOTLIGHT_EXTENSION_JS_EXECUTION') {
|
74
|
+
var result = executeScriptFromMessage(event.data);
|
75
|
+
if (event.data.debug) {
|
76
|
+
console.log('Script execution result:', result);
|
77
|
+
}
|
78
|
+
}
|
79
|
+
});
|
80
|
+
} catch (e) {
|
81
|
+
console.error('Error initializing the RAILS_SPOTLIGHT_EXTENSION_JS_EXECUTION script listener:', e);
|
82
|
+
}
|
83
|
+
</script>
|
84
|
+
JS
|
85
|
+
|
86
|
+
# Generate the ERB partial
|
87
|
+
File.write(partial_path, js_code)
|
88
|
+
puts "Partial created: #{partial_path}"
|
89
|
+
|
90
|
+
layout_file = Dir.glob('app/views/layouts/application.html.{erb,slim,haml}').first
|
91
|
+
layout_format = layout_file ? layout_file.split('.').last : 'erb'
|
92
|
+
|
93
|
+
if layout_file
|
94
|
+
puts "Detected layout file: #{layout_file}"
|
95
|
+
puts 'Please add the following line to your layout file at the appropriate place:'
|
96
|
+
else
|
97
|
+
puts 'No application layout file detected.'
|
98
|
+
puts 'Please manually add the following line to your application layout file:'
|
99
|
+
end
|
100
|
+
|
101
|
+
case layout_format
|
102
|
+
when 'slim'
|
103
|
+
puts "- if Rails.env.development?\n = render 'layouts/#{partial_name.split('.').first}'"
|
104
|
+
when 'haml'
|
105
|
+
puts "- if Rails.env.development?\n = render 'layouts/#{partial_name.split('.').first}'"
|
106
|
+
else
|
107
|
+
puts "<% if Rails.env.development? %>\n <%= render 'layouts/#{partial_name.split('.').first}' %>\n<% end %>"
|
108
|
+
end
|
109
|
+
end
|
41
110
|
end
|