solidstats 2.0.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (135) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +12 -63
  3. data/README.md +27 -0
  4. data/Rakefile +3 -3
  5. data/app/assets/javascripts/solidstats/dashboard.js +0 -46
  6. data/app/assets/stylesheets/solidstats/dashboard.css +48 -0
  7. data/app/controllers/solidstats/dashboard_controller.rb +73 -61
  8. data/app/controllers/solidstats/logs_controller.rb +72 -0
  9. data/app/controllers/solidstats/performance_controller.rb +25 -0
  10. data/app/controllers/solidstats/productivity_controller.rb +39 -0
  11. data/app/controllers/solidstats/quality_controller.rb +152 -0
  12. data/app/controllers/solidstats/securities_controller.rb +30 -0
  13. data/app/helpers/solidstats/application_helper.rb +124 -11
  14. data/app/helpers/solidstats/performance_helper.rb +87 -0
  15. data/app/helpers/solidstats/productivity_helper.rb +38 -0
  16. data/app/services/solidstats/bundler_audit_service.rb +206 -0
  17. data/app/services/solidstats/coverage_compass_service.rb +335 -0
  18. data/app/services/solidstats/load_lens_service.rb +474 -0
  19. data/app/services/solidstats/log_size_monitor_service.rb +197 -66
  20. data/app/services/solidstats/my_todo_service.rb +242 -0
  21. data/app/services/solidstats/style_patrol_service.rb +319 -0
  22. data/app/views/layouts/solidstats/application.html.erb +8 -2
  23. data/app/views/layouts/solidstats/dashboard.html.erb +84 -0
  24. data/app/views/solidstats/dashboard/dashboard.html.erb +39 -0
  25. data/app/views/solidstats/logs/logs_size.html.erb +409 -0
  26. data/app/views/solidstats/performance/load_lens.html.erb +158 -0
  27. data/app/views/solidstats/productivity/_todo_list.html.erb +49 -0
  28. data/app/views/solidstats/productivity/my_todos.html.erb +84 -0
  29. data/app/views/solidstats/quality/coverage_compass.html.erb +420 -0
  30. data/app/views/solidstats/quality/style_patrol.html.erb +463 -0
  31. data/app/views/solidstats/securities/bundler_audit.html.erb +345 -0
  32. data/app/views/solidstats/shared/_dashboard_card.html.erb +160 -0
  33. data/app/views/solidstats/shared/_quick_actions.html.erb +26 -0
  34. data/config/routes.rb +31 -6
  35. data/lib/generators/solidstats/clean/clean_generator.rb +24 -0
  36. data/lib/generators/solidstats/clean/templates/README +8 -0
  37. data/lib/generators/solidstats/install/install_generator.rb +51 -10
  38. data/lib/generators/solidstats/install/templates/README +7 -0
  39. data/lib/solidstats/engine.rb +6 -71
  40. data/lib/solidstats/version.rb +1 -1
  41. data/lib/solidstats.rb +19 -303
  42. data/lib/tasks/solidstats.rake +67 -0
  43. data/lib/tasks/solidstats_performance.rake +61 -0
  44. data/lib/tasks/solidstats_tasks.rake +16 -4
  45. metadata +33 -95
  46. data/app/assets/javascripts/solidstats/gem_metadata.js +0 -554
  47. data/app/assets/stylesheets/solidstats/components/action_button.css +0 -99
  48. data/app/assets/stylesheets/solidstats/components/dashboard.css +0 -151
  49. data/app/assets/stylesheets/solidstats/components/dashboard_header.css +0 -93
  50. data/app/assets/stylesheets/solidstats/components/dashboard_layout.css +0 -97
  51. data/app/assets/stylesheets/solidstats/components/gem_metadata.css +0 -1403
  52. data/app/assets/stylesheets/solidstats/components/navigation.css +0 -80
  53. data/app/assets/stylesheets/solidstats/components/quick_navigation.css +0 -54
  54. data/app/assets/stylesheets/solidstats/components/security.css +0 -332
  55. data/app/assets/stylesheets/solidstats/components/status_badge.css +0 -58
  56. data/app/assets/stylesheets/solidstats/components/summary_card.css +0 -66
  57. data/app/assets/stylesheets/solidstats/components/tab_navigation.css +0 -95
  58. data/app/components/solidstats/base_component.rb +0 -88
  59. data/app/components/solidstats/code_quality/code_quality_section_component.html.erb +0 -0
  60. data/app/components/solidstats/code_quality/code_quality_section_component.rb +0 -0
  61. data/app/components/solidstats/code_quality/section_component.html.erb +0 -45
  62. data/app/components/solidstats/code_quality/section_component.rb +0 -34
  63. data/app/components/solidstats/dashboard_header_component.html.erb +0 -39
  64. data/app/components/solidstats/dashboard_header_component.rb +0 -33
  65. data/app/components/solidstats/previews/action_button_component_preview/button_vs_link.html.erb +0 -6
  66. data/app/components/solidstats/previews/action_button_component_preview/sizes.html.erb +0 -6
  67. data/app/components/solidstats/previews/action_button_component_preview/variants.html.erb +0 -6
  68. data/app/components/solidstats/previews/action_button_component_preview/with_icons.html.erb +0 -6
  69. data/app/components/solidstats/previews/action_button_component_preview.rb +0 -64
  70. data/app/components/solidstats/previews/navigation_component_preview.rb +0 -74
  71. data/app/components/solidstats/previews/stats_overview_component_preview.rb +0 -100
  72. data/app/components/solidstats/previews/status_badge_component_preview/sizes.html.erb +0 -6
  73. data/app/components/solidstats/previews/status_badge_component_preview/statuses.html.erb +0 -6
  74. data/app/components/solidstats/previews/status_badge_component_preview/with_icons.html.erb +0 -6
  75. data/app/components/solidstats/previews/status_badge_component_preview.rb +0 -49
  76. data/app/components/solidstats/previews/summary_card_component_preview/clickable.html.erb +0 -9
  77. data/app/components/solidstats/previews/summary_card_component_preview/dashboard_layout.html.erb +0 -9
  78. data/app/components/solidstats/previews/summary_card_component_preview/statuses.html.erb +0 -6
  79. data/app/components/solidstats/previews/summary_card_component_preview/value_formats.html.erb +0 -6
  80. data/app/components/solidstats/previews/summary_card_component_preview.rb +0 -67
  81. data/app/components/solidstats/quick_navigation_component.html.erb +0 -8
  82. data/app/components/solidstats/quick_navigation_component.rb +0 -21
  83. data/app/components/solidstats/security/gem_impact_analysis_component.html.erb +0 -44
  84. data/app/components/solidstats/security/gem_impact_analysis_component.rb +0 -45
  85. data/app/components/solidstats/security/overview_component.html.erb +0 -21
  86. data/app/components/solidstats/security/overview_component.rb +0 -104
  87. data/app/components/solidstats/security/section_component.html.erb +0 -26
  88. data/app/components/solidstats/security/section_component.rb +0 -52
  89. data/app/components/solidstats/security/timeline_component.html.erb +0 -39
  90. data/app/components/solidstats/security/timeline_component.rb +0 -43
  91. data/app/components/solidstats/tasks_section_component.html.erb +0 -17
  92. data/app/components/solidstats/tasks_section_component.rb +0 -22
  93. data/app/components/solidstats/ui/action_button_component.html.erb +0 -6
  94. data/app/components/solidstats/ui/action_button_component.rb +0 -71
  95. data/app/components/solidstats/ui/dashboard_layout_component.html.erb +0 -19
  96. data/app/components/solidstats/ui/dashboard_layout_component.rb +0 -85
  97. data/app/components/solidstats/ui/navigation_component.html.erb +0 -34
  98. data/app/components/solidstats/ui/navigation_component.rb +0 -72
  99. data/app/components/solidstats/ui/stats_overview_component.html.erb +0 -14
  100. data/app/components/solidstats/ui/stats_overview_component.rb +0 -78
  101. data/app/components/solidstats/ui/status_badge_component.html.erb +0 -6
  102. data/app/components/solidstats/ui/status_badge_component.rb +0 -42
  103. data/app/components/solidstats/ui/summary_card_component.html.erb +0 -12
  104. data/app/components/solidstats/ui/summary_card_component.rb +0 -63
  105. data/app/components/solidstats/ui/tab_navigation_component.html.erb +0 -22
  106. data/app/components/solidstats/ui/tab_navigation_component.rb +0 -79
  107. data/app/services/solidstats/audit_service.rb +0 -56
  108. data/app/services/solidstats/data_collector_service.rb +0 -83
  109. data/app/services/solidstats/gem_metadata/fetcher_service.rb +0 -136
  110. data/app/services/solidstats/todo_service.rb +0 -114
  111. data/app/views/solidstats/dashboard/_log_monitor.html.erb +0 -759
  112. data/app/views/solidstats/dashboard/_todos.html.erb +0 -151
  113. data/app/views/solidstats/dashboard/audit/_additional_styles.css +0 -22
  114. data/app/views/solidstats/dashboard/audit/_audit_badge.html.erb +0 -5
  115. data/app/views/solidstats/dashboard/audit/_audit_details.html.erb +0 -495
  116. data/app/views/solidstats/dashboard/audit/_audit_summary.html.erb +0 -26
  117. data/app/views/solidstats/dashboard/audit/_no_vulnerabilities.html.erb +0 -3
  118. data/app/views/solidstats/dashboard/audit/_security_audit.html.erb +0 -14
  119. data/app/views/solidstats/dashboard/audit/_vulnerabilities_table.html.erb +0 -1120
  120. data/app/views/solidstats/dashboard/audit/_vulnerability_details.html.erb +0 -63
  121. data/app/views/solidstats/dashboard/index.html.erb +0 -81
  122. data/app/views/solidstats/gem_metadata/_panel.html.erb +0 -419
  123. data/lib/generators/solidstats/feature/feature_generator.rb +0 -170
  124. data/lib/generators/solidstats/feature/templates/component.html.erb +0 -84
  125. data/lib/generators/solidstats/feature/templates/component.rb.erb +0 -103
  126. data/lib/generators/solidstats/feature/templates/component.scss +0 -243
  127. data/lib/generators/solidstats/feature/templates/component_test.rb.erb +0 -183
  128. data/lib/generators/solidstats/feature/templates/controller.rb.erb +0 -44
  129. data/lib/generators/solidstats/feature/templates/controller_test.rb.erb +0 -111
  130. data/lib/generators/solidstats/feature/templates/detail_view.html.erb +0 -755
  131. data/lib/generators/solidstats/feature/templates/preview.rb.erb +0 -107
  132. data/lib/generators/solidstats/feature/templates/service.rb.erb +0 -132
  133. data/lib/generators/solidstats/feature/templates/service_test.rb.erb +0 -109
  134. data/lib/generators/solidstats/install_generator.rb +0 -109
  135. data/lib/tasks/solidstats_install.rake +0 -133
@@ -1,136 +0,0 @@
1
- require "net/http"
2
-
3
- module Solidstats
4
- module GemMetadata
5
- class FetcherService
6
- GemMeta = Struct.new(:name, :version, :current_version, :released, :info, :runtime, keyword_init: true)
7
-
8
- def self.call(gem_names = nil, force_refresh = false)
9
- new.call(gem_names, force_refresh)
10
- end
11
-
12
- def call(gem_names = nil, force_refresh = false)
13
- gem_names = get_gem_names(gem_names)
14
- fetch_metadata(gem_names, force_refresh)
15
- end
16
-
17
- private
18
-
19
- def get_gem_names(gem_names)
20
- return gem_names if gem_names.present?
21
-
22
- gemfile_lock = Rails.root.join("Gemfile.lock")
23
- return [] unless File.exist?(gemfile_lock)
24
-
25
- lockfile = File.read(gemfile_lock)
26
- parser = Bundler::LockfileParser.new(lockfile)
27
- parser.specs.map(&:name)
28
- end
29
-
30
- def get_current_versions
31
- gemfile_lock = Rails.root.join("Gemfile.lock")
32
- return {} unless File.exist?(gemfile_lock)
33
-
34
- lockfile = File.read(gemfile_lock)
35
- parser = Bundler::LockfileParser.new(lockfile)
36
-
37
- parser.specs.each_with_object({}) do |spec, versions|
38
- versions[spec.name] = spec.version.to_s
39
- end
40
- end
41
-
42
- def fetch_metadata(gem_names, force_refresh)
43
- current_versions = get_current_versions
44
-
45
- gem_names.map do |name|
46
- fetch_gem_data(name, current_versions[name], force_refresh)
47
- end
48
- end
49
-
50
- def fetch_gem_data(name, current_version, force_refresh)
51
- cached_data = fetch_from_cache(name) unless force_refresh
52
-
53
- if cached_data
54
- # Update current version if it changed since caching
55
- if current_version && cached_data.current_version != current_version
56
- cached_data.current_version = current_version
57
- cache_data(name, cached_data)
58
- end
59
- return cached_data
60
- end
61
-
62
- begin
63
- data = fetch_from_api(name)
64
- meta = GemMeta.new(
65
- name: data["name"],
66
- version: data["version"],
67
- current_version: current_version,
68
- released: data["version_created_at"] ? Time.parse(data["version_created_at"]) : nil,
69
- info: data["info"],
70
- runtime: data["dependencies"] && data["dependencies"]["runtime"] || []
71
- )
72
- cache_data(name, meta)
73
- meta
74
- rescue => e
75
- Rails.logger.error("Failed to fetch gem metadata for #{name}: #{e.message}")
76
- GemMeta.new(name: name, current_version: current_version, info: "(API unavailable)")
77
- end
78
- end
79
-
80
- def fetch_from_api(name)
81
- uri = URI.parse("https://rubygems.org/api/v1/gems/#{name}.json")
82
- http = Net::HTTP.new(uri.host, uri.port)
83
- http.use_ssl = true
84
- http.open_timeout = 5
85
- http.read_timeout = 5
86
-
87
- response = http.get(uri.request_uri)
88
-
89
- if response.code == "200"
90
- JSON.parse(response.body)
91
- else
92
- raise "API request failed with status #{response.code}"
93
- end
94
- end
95
-
96
- def fetch_from_cache(name)
97
- cache_file = cache_path(name)
98
- return nil unless File.exist?(cache_file)
99
-
100
- data = JSON.parse(File.read(cache_file))
101
- cache_time = File.mtime(cache_file)
102
-
103
- # Return nil if cache is older than 24 hours
104
- return nil if Time.now - cache_time > 24.hours
105
-
106
- GemMeta.new(
107
- name: data["name"],
108
- version: data["version"],
109
- current_version: data["current_version"],
110
- released: data["released"] ? Time.parse(data["released"]) : nil,
111
- info: data["info"],
112
- runtime: data["runtime"] || []
113
- )
114
- end
115
-
116
- def cache_data(name, meta)
117
- FileUtils.mkdir_p(File.dirname(cache_path(name)))
118
-
119
- data = {
120
- "name" => meta.name,
121
- "version" => meta.version,
122
- "current_version" => meta.current_version,
123
- "released" => meta.released&.iso8601,
124
- "info" => meta.info,
125
- "runtime" => meta.runtime
126
- }
127
-
128
- File.write(cache_path(name), data.to_json)
129
- end
130
-
131
- def cache_path(name)
132
- Rails.root.join("tmp", "cache", "gem_metadata", "#{name}.json")
133
- end
134
- end
135
- end
136
- end
@@ -1,114 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Solidstats
4
- # Service to collect and process TODO items from codebase
5
- class TodoService < DataCollectorService
6
- # Initialize with default cache settings for TODO items
7
- def initialize
8
- super(Rails.root.join("tmp", "solidstats_todos.json"))
9
- end
10
-
11
- # Generate a summary for the dashboard display
12
- # @return [Hash] Summary information with counts and status
13
- def summary
14
- todos = fetch
15
- return { count: 0, status: "success", message: "No TODO items found" } if todos.nil? || todos.empty?
16
-
17
- stats = calculate_stats(todos)
18
-
19
- {
20
- count: todos.count,
21
- status: determine_status(todos),
22
- message: generate_message(todos.count),
23
- by_type: stats[:by_type],
24
- hotspots: stats[:hotspots]
25
- }
26
- end
27
-
28
- private
29
-
30
- # Calculate statistics for the TODO items
31
- # @param todos [Array] List of TODO items
32
- # @return [Hash] Statistics about the TODO items
33
- def calculate_stats(todos)
34
- stats = {
35
- by_type: {
36
- "TODO" => todos.count { |t| (t[:type] || t["type"]) == "TODO" },
37
- "FIXME" => todos.count { |t| (t[:type] || t["type"]) == "FIXME" },
38
- "HACK" => todos.count { |t| (t[:type] || t["type"]) == "HACK" }
39
- },
40
- by_file: {}
41
- }
42
-
43
- # Group by file path
44
- todos.each do |todo|
45
- file_path = todo[:file] || todo["file"]
46
- stats[:by_file][file_path] ||= 0
47
- stats[:by_file][file_path] += 1
48
- end
49
-
50
- # Find files with most TODOs (top 5)
51
- stats[:hotspots] = stats[:by_file].sort_by { |_, count| -count }
52
- .first(5)
53
- .to_h
54
-
55
- stats
56
- end
57
-
58
- # Determine the status indicator based on TODO items
59
- # @param todos [Array] List of TODO items
60
- # @return [String] Status indicator (success, warning, or danger)
61
- def determine_status(todos)
62
- fixme_count = todos.count { |t| t[:type] == "FIXME" }
63
- hack_count = todos.count { |t| t[:type] == "HACK" }
64
-
65
- if hack_count > 0
66
- "danger"
67
- elsif fixme_count > 0
68
- "warning"
69
- elsif todos.count > 10
70
- "warning"
71
- else
72
- "success"
73
- end
74
- end
75
-
76
- # Generate a status message based on TODO count
77
- # @param count [Integer] Number of TODOs
78
- # @return [String] Human-readable status message
79
- def generate_message(count)
80
- "#{count} #{count == 1 ? 'item' : 'items'} found"
81
- end
82
-
83
- # Collect fresh TODO data by scanning the codebase
84
- # @return [Array] List of TODO items found
85
- def collect_data
86
- todos = []
87
- raw_output = `grep -r -n -E "(TODO|FIXME|HACK|todo|fixme|hack)" app lib`.split("\n")
88
-
89
- raw_output.each do |line|
90
- if line =~ /^(.+):(\d+):(.+)$/
91
- file = $1
92
- line_num = $2
93
- content = $3
94
-
95
- # Match only exact lowercase or uppercase variants
96
- type_match = content.match(/(TODO|FIXME|HACK|todo|fixme|hack)/)
97
- if type_match
98
- # Convert to uppercase for consistency
99
- type = type_match.to_s.upcase
100
-
101
- todos << {
102
- file: file,
103
- line: line_num.to_i,
104
- content: content.strip,
105
- type: type
106
- }
107
- end
108
- end
109
- end
110
-
111
- todos
112
- end
113
- end
114
- end