mysql_genius 0.1.0 → 0.3.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.
- checksums.yaml +4 -4
- data/.github/FUNDING.yml +5 -0
- data/.github/workflows/ci.yml +30 -7
- data/.gitignore +3 -0
- data/.rubocop.yml +24 -0
- data/CHANGELOG.md +32 -0
- data/Gemfile +7 -2
- data/README.md +50 -38
- data/Rakefile +3 -1
- data/app/controllers/concerns/mysql_genius/ai_features.rb +90 -52
- data/app/controllers/concerns/mysql_genius/database_analysis.rb +73 -45
- data/app/controllers/concerns/mysql_genius/query_execution.rb +18 -16
- data/app/controllers/mysql_genius/base_controller.rb +3 -1
- data/app/controllers/mysql_genius/queries_controller.rb +19 -12
- data/app/services/mysql_genius/ai_client.rb +10 -3
- data/app/services/mysql_genius/ai_optimization_service.rb +8 -4
- data/app/services/mysql_genius/ai_suggestion_service.rb +6 -3
- data/app/views/layouts/mysql_genius/application.html.erb +141 -5
- data/app/views/mysql_genius/queries/_tab_dashboard.html.erb +95 -0
- data/app/views/mysql_genius/queries/_tab_duplicate_indexes.html.erb +11 -0
- data/app/views/mysql_genius/queries/_tab_query_explorer.html.erb +110 -0
- data/app/views/mysql_genius/queries/_tab_table_sizes.html.erb +6 -4
- data/app/views/mysql_genius/queries/_tab_unused_indexes.html.erb +11 -0
- data/app/views/mysql_genius/queries/index.html.erb +377 -52
- data/bin/console +1 -0
- data/config/routes.rb +2 -0
- data/docs/screenshots/dashboard.png +0 -0
- data/docs/screenshots/query_explore.png +0 -0
- data/docs/superpowers/plans/2026-04-08-dashboard-first-redesign.md +741 -0
- data/docs/superpowers/specs/2026-04-08-dashboard-first-redesign.md +87 -0
- data/lib/generators/mysql_genius/install/install_generator.rb +19 -0
- data/lib/generators/mysql_genius/install/templates/initializer.rb +56 -0
- data/lib/mysql_genius/configuration.rb +8 -6
- data/lib/mysql_genius/engine.rb +2 -0
- data/lib/mysql_genius/slow_query_monitor.rb +30 -25
- data/lib/mysql_genius/sql_validator.rb +6 -4
- data/lib/mysql_genius/version.rb +3 -1
- data/lib/mysql_genius.rb +2 -0
- data/mysql_genius.gemspec +9 -8
- metadata +31 -15
- data/app/views/mysql_genius/queries/_tab_sql_query.html.erb +0 -40
- data/app/views/mysql_genius/queries/_tab_visual_builder.html.erb +0 -61
- data/docs/screenshots/sql_query.png +0 -0
- data/docs/screenshots/visual_builder.png +0 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# Dashboard-First Redesign
|
|
2
|
+
|
|
3
|
+
Redesign the default landing experience to lead with PgHero-style monitoring instead of the SQL query builder. Based on Reddit feedback that the current Visual Builder default makes the engine look like "another DB GUI" rather than a MySQL performance dashboard.
|
|
4
|
+
|
|
5
|
+
## Changes
|
|
6
|
+
|
|
7
|
+
### 1. New Dashboard Tab (default)
|
|
8
|
+
|
|
9
|
+
A new tab that becomes the active tab on page load. Loads all data immediately via parallel AJAX calls to existing endpoints. Four stacked sections:
|
|
10
|
+
|
|
11
|
+
**Server Summary** (reuses `server_overview` endpoint)
|
|
12
|
+
- Four cards in a responsive grid: Server (version, uptime), Connections (used/max progress bar), InnoDB Buffer Pool (hit rate progress bar), Query Activity (questions/sec, slow queries count)
|
|
13
|
+
|
|
14
|
+
**Top 5 Slow Queries** (reuses `slow_queries` endpoint)
|
|
15
|
+
- Compact table: duration, timestamp, truncated SQL
|
|
16
|
+
- "View all" link switches to Slow Queries tab
|
|
17
|
+
- If Redis not configured: muted placeholder "Configure `redis_url` to monitor slow queries."
|
|
18
|
+
|
|
19
|
+
**Top 5 Expensive Queries** (reuses `query_stats` endpoint with new `limit` param)
|
|
20
|
+
- Compact table: query digest, calls, total time, avg time
|
|
21
|
+
- Sorted by total time descending
|
|
22
|
+
- "View all" link switches to Query Stats tab
|
|
23
|
+
- If `performance_schema` unavailable: muted placeholder
|
|
24
|
+
|
|
25
|
+
**Index Alerts** (reuses `duplicate_indexes` and `unused_indexes` endpoints)
|
|
26
|
+
- Two badge cards showing counts: "X duplicate indexes", "X unused indexes"
|
|
27
|
+
- Green checkmark if count is zero
|
|
28
|
+
- Each badge is clickable, switches to the corresponding tab
|
|
29
|
+
|
|
30
|
+
### 2. Query Explorer Tab (merged Visual Builder + SQL Query)
|
|
31
|
+
|
|
32
|
+
The two existing query tabs merge into one "Query Explorer" tab with a mode toggle:
|
|
33
|
+
|
|
34
|
+
- **Visual mode** -- existing visual builder UI (table selector, columns, filters, ordering)
|
|
35
|
+
- **SQL mode** -- existing raw SQL textarea with AI suggestion panel
|
|
36
|
+
- Small toggle buttons at top of tab to switch modes
|
|
37
|
+
- Default mode: Visual
|
|
38
|
+
- SQL generated by visual builder carries over when switching to SQL mode (existing behavior preserved)
|
|
39
|
+
- Shared results area unchanged
|
|
40
|
+
|
|
41
|
+
### 3. Tab Reorder
|
|
42
|
+
|
|
43
|
+
New order:
|
|
44
|
+
1. Dashboard (new, default active)
|
|
45
|
+
2. Slow Queries
|
|
46
|
+
3. Query Stats
|
|
47
|
+
4. Server
|
|
48
|
+
5. Table Sizes
|
|
49
|
+
6. Unused Indexes
|
|
50
|
+
7. Duplicate Indexes
|
|
51
|
+
8. Query Explorer (merged)
|
|
52
|
+
9. AI Tools (conditional on `@ai_enabled`)
|
|
53
|
+
|
|
54
|
+
### 4. Backend Change
|
|
55
|
+
|
|
56
|
+
Add `limit` parameter support to the `query_stats` action. When present, cap the result set to the given limit. The dashboard passes `limit=5`; the Query Stats tab continues to omit it for the full list.
|
|
57
|
+
|
|
58
|
+
### 5. Gemspec Description Update
|
|
59
|
+
|
|
60
|
+
Change description to lead with monitoring:
|
|
61
|
+
> "MysqlGenius gives Rails apps a mountable performance dashboard for MySQL databases. Monitor slow queries, analyze query statistics from performance_schema, detect unused and duplicate indexes, and explore your database with optional AI-powered optimization."
|
|
62
|
+
|
|
63
|
+
### 6. README Updates
|
|
64
|
+
|
|
65
|
+
- Reorder screenshots section to lead with Dashboard
|
|
66
|
+
- Update "Usage" section to reflect new tab order and dashboard-first experience
|
|
67
|
+
- Add Dashboard screenshot placeholder
|
|
68
|
+
|
|
69
|
+
## Not Changing
|
|
70
|
+
|
|
71
|
+
- No new routes -- dashboard reuses existing endpoints
|
|
72
|
+
- No new controller actions -- only a `limit` param added to `query_stats`
|
|
73
|
+
- All existing tab partials remain intact, just reordered in the view
|
|
74
|
+
- Shared results area unchanged
|
|
75
|
+
- AI features unchanged
|
|
76
|
+
- Authentication unchanged
|
|
77
|
+
|
|
78
|
+
## Files Affected
|
|
79
|
+
|
|
80
|
+
- `app/views/mysql_genius/queries/index.html.erb` -- tab bar reorder, new dashboard partial render, merge visual/sql tabs, JS changes for dashboard auto-load and query explorer toggle
|
|
81
|
+
- `app/views/mysql_genius/queries/_tab_dashboard.html.erb` -- new partial
|
|
82
|
+
- `app/views/mysql_genius/queries/_tab_query_explorer.html.erb` -- new partial combining visual builder and sql query content
|
|
83
|
+
- `app/views/mysql_genius/queries/_tab_visual_builder.html.erb` -- removed (content moves to query explorer)
|
|
84
|
+
- `app/views/mysql_genius/queries/_tab_sql_query.html.erb` -- removed (content moves to query explorer)
|
|
85
|
+
- `app/controllers/concerns/mysql_genius/database_analysis.rb` -- add `limit` param to `query_stats`
|
|
86
|
+
- `mysql_genius.gemspec` -- updated description
|
|
87
|
+
- `README.md` -- updated screenshots order, usage section
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MysqlGenius
|
|
4
|
+
module Generators
|
|
5
|
+
class InstallGenerator < Rails::Generators::Base
|
|
6
|
+
source_root File.expand_path("templates", __dir__)
|
|
7
|
+
|
|
8
|
+
desc "Creates a MysqlGenius initializer and mounts the engine in routes."
|
|
9
|
+
|
|
10
|
+
def copy_initializer
|
|
11
|
+
template("initializer.rb", "config/initializers/mysql_genius.rb")
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def mount_engine
|
|
15
|
+
route('mount MysqlGenius::Engine, at: "/mysql_genius"')
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
MysqlGenius.configure do |config|
|
|
4
|
+
# --- Authentication ---
|
|
5
|
+
# Lambda that receives the controller instance. Return true to allow access.
|
|
6
|
+
# Default: allows everyone. Use route constraints for most cases.
|
|
7
|
+
# config.authenticate = ->(controller) { controller.current_user&.admin? }
|
|
8
|
+
|
|
9
|
+
# To use current_user or other app helpers, inherit from ApplicationController:
|
|
10
|
+
# config.base_controller = "ApplicationController"
|
|
11
|
+
|
|
12
|
+
# --- Tables ---
|
|
13
|
+
# Tables featured at the top of the visual builder dropdown (optional).
|
|
14
|
+
# config.featured_tables = %w[users posts comments]
|
|
15
|
+
|
|
16
|
+
# Tables blocked from querying (defaults: sessions, schema_migrations, ar_internal_metadata).
|
|
17
|
+
# config.blocked_tables += %w[oauth_tokens api_keys]
|
|
18
|
+
|
|
19
|
+
# Column patterns to redact with [REDACTED] in results (case-insensitive substring match).
|
|
20
|
+
# config.masked_column_patterns = %w[password secret digest token ssn]
|
|
21
|
+
|
|
22
|
+
# Default columns checked in the visual builder per table (optional).
|
|
23
|
+
# config.default_columns = {
|
|
24
|
+
# "users" => %w[id name email created_at],
|
|
25
|
+
# "posts" => %w[id title user_id published_at]
|
|
26
|
+
# }
|
|
27
|
+
|
|
28
|
+
# --- Query Safety ---
|
|
29
|
+
# config.max_row_limit = 1000 # Hard cap on rows returned
|
|
30
|
+
# config.default_row_limit = 25 # Default when no limit specified
|
|
31
|
+
# config.query_timeout_ms = 30_000 # 30 second timeout
|
|
32
|
+
|
|
33
|
+
# --- Slow Query Monitoring ---
|
|
34
|
+
# Requires Redis. Set to nil to disable.
|
|
35
|
+
# config.redis_url = ENV["REDIS_URL"]
|
|
36
|
+
# config.slow_query_threshold_ms = 250
|
|
37
|
+
|
|
38
|
+
# --- Audit Logging ---
|
|
39
|
+
# Set to nil to disable. Logs query executions, rejections, and errors.
|
|
40
|
+
# config.audit_logger = Logger.new(Rails.root.join("log", "mysql_genius.log"))
|
|
41
|
+
|
|
42
|
+
# --- AI Features (optional) ---
|
|
43
|
+
# Supports any OpenAI-compatible API: OpenAI, Azure OpenAI, Ollama, or a custom client.
|
|
44
|
+
# config.ai_endpoint = "https://api.openai.com/v1/chat/completions"
|
|
45
|
+
# config.ai_api_key = ENV["OPENAI_API_KEY"]
|
|
46
|
+
# config.ai_model = "gpt-4o"
|
|
47
|
+
# config.ai_auth_style = :bearer # :bearer for OpenAI/Ollama, :api_key for Azure
|
|
48
|
+
|
|
49
|
+
# Domain context helps the AI understand your schema and generate better queries.
|
|
50
|
+
# config.ai_system_context = <<~CONTEXT
|
|
51
|
+
# This is an e-commerce database.
|
|
52
|
+
# - `users` stores customer accounts.
|
|
53
|
+
# - `orders` tracks purchases, linked to users via `user_id`.
|
|
54
|
+
# - Soft-deleted records have `deleted_at IS NOT NULL`.
|
|
55
|
+
# CONTEXT
|
|
56
|
+
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module MysqlGenius
|
|
2
4
|
class Configuration
|
|
3
5
|
# Tables to feature in the visual builder dropdown (array of strings).
|
|
@@ -66,17 +68,17 @@ module MysqlGenius
|
|
|
66
68
|
|
|
67
69
|
def initialize
|
|
68
70
|
@featured_tables = []
|
|
69
|
-
@blocked_tables =
|
|
70
|
-
sessions
|
|
71
|
-
ar_internal_metadata
|
|
72
|
-
schema_migrations
|
|
71
|
+
@blocked_tables = [
|
|
72
|
+
"sessions",
|
|
73
|
+
"ar_internal_metadata",
|
|
74
|
+
"schema_migrations",
|
|
73
75
|
]
|
|
74
|
-
@masked_column_patterns =
|
|
76
|
+
@masked_column_patterns = ["password", "secret", "digest", "token"]
|
|
75
77
|
@default_columns = {}
|
|
76
78
|
@max_row_limit = 1000
|
|
77
79
|
@default_row_limit = 25
|
|
78
80
|
@query_timeout_ms = 30_000
|
|
79
|
-
@authenticate = ->(
|
|
81
|
+
@authenticate = ->(_controller) { true }
|
|
80
82
|
@ai_client = nil
|
|
81
83
|
@ai_endpoint = nil
|
|
82
84
|
@ai_api_key = nil
|
data/lib/mysql_genius/engine.rb
CHANGED
|
@@ -1,36 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require "json"
|
|
4
|
+
require "time"
|
|
2
5
|
|
|
3
6
|
module MysqlGenius
|
|
4
7
|
class SlowQueryMonitor
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
+
class << self
|
|
9
|
+
def redis_key
|
|
10
|
+
"mysql_genius:slow_queries"
|
|
11
|
+
end
|
|
8
12
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
13
|
+
def subscribe!
|
|
14
|
+
ActiveSupport::Notifications.subscribe("sql.active_record") do |_name, start, finish, _id, payload|
|
|
15
|
+
duration_ms = ((finish - start) * 1000).round(1)
|
|
16
|
+
sql = payload[:sql].to_s
|
|
17
|
+
threshold = MysqlGenius.configuration.slow_query_threshold_ms
|
|
14
18
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
19
|
+
next if duration_ms < threshold
|
|
20
|
+
next unless sql.match?(/\ASELECT\b/i)
|
|
21
|
+
next if sql.include?("SCHEMA")
|
|
22
|
+
next if sql.include?("EXPLAIN")
|
|
23
|
+
next if payload[:name] == "SCHEMA"
|
|
20
24
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
begin
|
|
26
|
+
redis = Redis.new(url: MysqlGenius.configuration.redis_url)
|
|
27
|
+
entry = {
|
|
28
|
+
sql: sql.length > 10_000 ? sql[0, 10_000] : sql,
|
|
29
|
+
duration_ms: duration_ms,
|
|
30
|
+
timestamp: Time.now.iso8601,
|
|
31
|
+
name: payload[:name],
|
|
32
|
+
}.to_json
|
|
29
33
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
+
redis.lpush(redis_key, entry)
|
|
35
|
+
redis.ltrim(redis_key, 0, 199)
|
|
36
|
+
rescue => e
|
|
37
|
+
Rails.logger.debug("[mysql_genius] Slow query logger error: #{e.message}") if defined?(Rails)
|
|
38
|
+
end
|
|
34
39
|
end
|
|
35
40
|
end
|
|
36
41
|
end
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module MysqlGenius
|
|
2
4
|
module SqlValidator
|
|
3
|
-
FORBIDDEN_KEYWORDS =
|
|
5
|
+
FORBIDDEN_KEYWORDS = ["INSERT", "UPDATE", "DELETE", "DROP", "ALTER", "CREATE", "TRUNCATE", "GRANT", "REVOKE"].freeze
|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
extend self
|
|
6
8
|
|
|
7
9
|
def validate(sql, blocked_tables:, connection:)
|
|
8
10
|
return "Please enter a query." if sql.nil? || sql.strip.empty?
|
|
@@ -22,7 +24,7 @@ module MysqlGenius
|
|
|
22
24
|
tables_in_query = extract_table_references(normalized, connection)
|
|
23
25
|
blocked = tables_in_query & blocked_tables
|
|
24
26
|
if blocked.any?
|
|
25
|
-
return "Access denied for table(s): #{blocked.join(
|
|
27
|
+
return "Access denied for table(s): #{blocked.join(", ")}."
|
|
26
28
|
end
|
|
27
29
|
|
|
28
30
|
nil
|
|
@@ -44,7 +46,7 @@ module MysqlGenius
|
|
|
44
46
|
elsif sql.match?(/\bLIMIT\s+\d+/i)
|
|
45
47
|
sql.gsub(/\bLIMIT\s+(\d+)/i) { "LIMIT #{[::Regexp.last_match(1).to_i, limit].min}" }
|
|
46
48
|
else
|
|
47
|
-
"#{sql.gsub(/;\s*\z/,
|
|
49
|
+
"#{sql.gsub(/;\s*\z/, "")} LIMIT #{limit}"
|
|
48
50
|
end
|
|
49
51
|
end
|
|
50
52
|
|
data/lib/mysql_genius/version.rb
CHANGED
data/lib/mysql_genius.rb
CHANGED
data/mysql_genius.gemspec
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
lib = File.expand_path("../lib", __FILE__)
|
|
2
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
3
5
|
require "mysql_genius/version"
|
|
@@ -9,9 +11,9 @@ Gem::Specification.new do |spec|
|
|
|
9
11
|
spec.email = ["antarr.t.byrd@uth.tmc.edu"]
|
|
10
12
|
|
|
11
13
|
spec.summary = "A MySQL performance dashboard and query explorer for Rails — like PgHero, but for MySQL."
|
|
12
|
-
spec.description = "MysqlGenius gives Rails apps a mountable
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
spec.description = "MysqlGenius gives Rails apps a mountable performance dashboard for MySQL databases. " \
|
|
15
|
+
"Monitor slow queries, analyze query statistics from performance_schema, detect unused and duplicate indexes, " \
|
|
16
|
+
"and explore your database with optional AI-powered optimization."
|
|
15
17
|
spec.homepage = "https://github.com/antarr/mysql_genius"
|
|
16
18
|
spec.license = "MIT"
|
|
17
19
|
|
|
@@ -21,14 +23,13 @@ Gem::Specification.new do |spec|
|
|
|
21
23
|
spec.metadata["source_code_uri"] = spec.homepage
|
|
22
24
|
spec.metadata["changelog_uri"] = "#{spec.homepage}/blob/main/CHANGELOG.md"
|
|
23
25
|
|
|
24
|
-
spec.files = Dir.chdir(File.expand_path(
|
|
25
|
-
|
|
26
|
+
spec.files = Dir.chdir(File.expand_path("..", __FILE__)) do
|
|
27
|
+
%x(git ls-files -z).split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
|
26
28
|
end
|
|
27
29
|
spec.bindir = "exe"
|
|
28
30
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
29
31
|
spec.require_paths = ["lib"]
|
|
30
32
|
|
|
31
|
-
spec.add_dependency
|
|
32
|
-
spec.add_dependency
|
|
33
|
-
|
|
33
|
+
spec.add_dependency("activerecord", ">= 5.2", "< 9")
|
|
34
|
+
spec.add_dependency("railties", ">= 5.2", "< 9")
|
|
34
35
|
end
|
metadata
CHANGED
|
@@ -1,22 +1,24 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: mysql_genius
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Antarr Byrd
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: exe
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
|
-
name:
|
|
13
|
+
name: activerecord
|
|
15
14
|
requirement: !ruby/object:Gem::Requirement
|
|
16
15
|
requirements:
|
|
17
16
|
- - ">="
|
|
18
17
|
- !ruby/object:Gem::Version
|
|
19
18
|
version: '5.2'
|
|
19
|
+
- - "<"
|
|
20
|
+
- !ruby/object:Gem::Version
|
|
21
|
+
version: '9'
|
|
20
22
|
type: :runtime
|
|
21
23
|
prerelease: false
|
|
22
24
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -24,13 +26,19 @@ dependencies:
|
|
|
24
26
|
- - ">="
|
|
25
27
|
- !ruby/object:Gem::Version
|
|
26
28
|
version: '5.2'
|
|
29
|
+
- - "<"
|
|
30
|
+
- !ruby/object:Gem::Version
|
|
31
|
+
version: '9'
|
|
27
32
|
- !ruby/object:Gem::Dependency
|
|
28
|
-
name:
|
|
33
|
+
name: railties
|
|
29
34
|
requirement: !ruby/object:Gem::Requirement
|
|
30
35
|
requirements:
|
|
31
36
|
- - ">="
|
|
32
37
|
- !ruby/object:Gem::Version
|
|
33
38
|
version: '5.2'
|
|
39
|
+
- - "<"
|
|
40
|
+
- !ruby/object:Gem::Version
|
|
41
|
+
version: '9'
|
|
34
42
|
type: :runtime
|
|
35
43
|
prerelease: false
|
|
36
44
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -38,18 +46,24 @@ dependencies:
|
|
|
38
46
|
- - ">="
|
|
39
47
|
- !ruby/object:Gem::Version
|
|
40
48
|
version: '5.2'
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
49
|
+
- - "<"
|
|
50
|
+
- !ruby/object:Gem::Version
|
|
51
|
+
version: '9'
|
|
52
|
+
description: MysqlGenius gives Rails apps a mountable performance dashboard for MySQL
|
|
53
|
+
databases. Monitor slow queries, analyze query statistics from performance_schema,
|
|
54
|
+
detect unused and duplicate indexes, and explore your database with optional AI-powered
|
|
55
|
+
optimization.
|
|
44
56
|
email:
|
|
45
57
|
- antarr.t.byrd@uth.tmc.edu
|
|
46
58
|
executables: []
|
|
47
59
|
extensions: []
|
|
48
60
|
extra_rdoc_files: []
|
|
49
61
|
files:
|
|
62
|
+
- ".github/FUNDING.yml"
|
|
50
63
|
- ".github/workflows/ci.yml"
|
|
51
64
|
- ".gitignore"
|
|
52
65
|
- ".rspec"
|
|
66
|
+
- ".rubocop.yml"
|
|
53
67
|
- CHANGELOG.md
|
|
54
68
|
- Gemfile
|
|
55
69
|
- LICENSE.txt
|
|
@@ -66,25 +80,29 @@ files:
|
|
|
66
80
|
- app/views/layouts/mysql_genius/application.html.erb
|
|
67
81
|
- app/views/mysql_genius/queries/_shared_results.html.erb
|
|
68
82
|
- app/views/mysql_genius/queries/_tab_ai_tools.html.erb
|
|
83
|
+
- app/views/mysql_genius/queries/_tab_dashboard.html.erb
|
|
69
84
|
- app/views/mysql_genius/queries/_tab_duplicate_indexes.html.erb
|
|
85
|
+
- app/views/mysql_genius/queries/_tab_query_explorer.html.erb
|
|
70
86
|
- app/views/mysql_genius/queries/_tab_query_stats.html.erb
|
|
71
87
|
- app/views/mysql_genius/queries/_tab_server.html.erb
|
|
72
88
|
- app/views/mysql_genius/queries/_tab_slow_queries.html.erb
|
|
73
|
-
- app/views/mysql_genius/queries/_tab_sql_query.html.erb
|
|
74
89
|
- app/views/mysql_genius/queries/_tab_table_sizes.html.erb
|
|
75
90
|
- app/views/mysql_genius/queries/_tab_unused_indexes.html.erb
|
|
76
|
-
- app/views/mysql_genius/queries/_tab_visual_builder.html.erb
|
|
77
91
|
- app/views/mysql_genius/queries/index.html.erb
|
|
78
92
|
- bin/console
|
|
79
93
|
- bin/setup
|
|
80
94
|
- config/routes.rb
|
|
81
95
|
- docs/screenshots/ai_tools.png
|
|
96
|
+
- docs/screenshots/dashboard.png
|
|
82
97
|
- docs/screenshots/duplicate_indexes.png
|
|
98
|
+
- docs/screenshots/query_explore.png
|
|
83
99
|
- docs/screenshots/query_stats.png
|
|
84
100
|
- docs/screenshots/server.png
|
|
85
|
-
- docs/screenshots/sql_query.png
|
|
86
101
|
- docs/screenshots/table_sizes.png
|
|
87
|
-
- docs/
|
|
102
|
+
- docs/superpowers/plans/2026-04-08-dashboard-first-redesign.md
|
|
103
|
+
- docs/superpowers/specs/2026-04-08-dashboard-first-redesign.md
|
|
104
|
+
- lib/generators/mysql_genius/install/install_generator.rb
|
|
105
|
+
- lib/generators/mysql_genius/install/templates/initializer.rb
|
|
88
106
|
- lib/mysql_genius.rb
|
|
89
107
|
- lib/mysql_genius/configuration.rb
|
|
90
108
|
- lib/mysql_genius/engine.rb
|
|
@@ -99,7 +117,6 @@ metadata:
|
|
|
99
117
|
homepage_uri: https://github.com/antarr/mysql_genius
|
|
100
118
|
source_code_uri: https://github.com/antarr/mysql_genius
|
|
101
119
|
changelog_uri: https://github.com/antarr/mysql_genius/blob/main/CHANGELOG.md
|
|
102
|
-
post_install_message:
|
|
103
120
|
rdoc_options: []
|
|
104
121
|
require_paths:
|
|
105
122
|
- lib
|
|
@@ -114,8 +131,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
114
131
|
- !ruby/object:Gem::Version
|
|
115
132
|
version: '0'
|
|
116
133
|
requirements: []
|
|
117
|
-
rubygems_version:
|
|
118
|
-
signing_key:
|
|
134
|
+
rubygems_version: 4.0.4
|
|
119
135
|
specification_version: 4
|
|
120
136
|
summary: A MySQL performance dashboard and query explorer for Rails — like PgHero,
|
|
121
137
|
but for MySQL.
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
<!-- SQL Query Tab -->
|
|
2
|
-
<div class="mg-tab-content" id="tab-sql">
|
|
3
|
-
<% if @ai_enabled %>
|
|
4
|
-
<div class="mg-card mg-mb">
|
|
5
|
-
<div class="mg-card-header">
|
|
6
|
-
<span class="mg-card-toggle" id="ai-toggle">⚡ AI Assistant <span class="mg-text-muted">- Describe what you want in plain English</span></span>
|
|
7
|
-
</div>
|
|
8
|
-
<div class="mg-card-body mg-hidden" id="ai-panel">
|
|
9
|
-
<div class="mg-field">
|
|
10
|
-
<textarea id="ai-prompt" rows="2" placeholder="e.g. Show me all users created in the last 30 days"></textarea>
|
|
11
|
-
<div class="mg-text-muted" style="margin-top:2px;">Only table names and column names are sent to the AI. No row data leaves the system.</div>
|
|
12
|
-
</div>
|
|
13
|
-
<button id="ai-suggest" class="mg-btn mg-btn-primary mg-btn-sm mg-mb">⚡ Suggest Query</button>
|
|
14
|
-
<div id="ai-result" class="mg-hidden">
|
|
15
|
-
<div id="ai-explanation" class="mg-alert mg-alert-info"></div>
|
|
16
|
-
</div>
|
|
17
|
-
</div>
|
|
18
|
-
</div>
|
|
19
|
-
<% end %>
|
|
20
|
-
|
|
21
|
-
<div class="mg-field">
|
|
22
|
-
<label for="sql-input">SQL Query</label>
|
|
23
|
-
<textarea id="sql-input" rows="5" placeholder="SELECT * FROM users LIMIT 10"></textarea>
|
|
24
|
-
</div>
|
|
25
|
-
<div class="mg-row">
|
|
26
|
-
<div class="mg-col-2 mg-field">
|
|
27
|
-
<label for="sql-row-limit">Row Limit</label>
|
|
28
|
-
<input type="number" id="sql-row-limit" value="25" min="1" max="<%= MysqlGenius.configuration.max_row_limit %>">
|
|
29
|
-
</div>
|
|
30
|
-
<div class="mg-field">
|
|
31
|
-
<label> </label>
|
|
32
|
-
<button id="sql-run" class="mg-btn mg-btn-primary">▶ Run Query</button>
|
|
33
|
-
<button id="sql-explain" class="mg-btn mg-btn-outline">🔎 Explain</button>
|
|
34
|
-
<% if @ai_enabled %>
|
|
35
|
-
<button id="sql-describe" class="mg-btn mg-btn-outline mg-btn-sm" style="margin-left:8px;">⚡ Describe</button>
|
|
36
|
-
<button id="sql-rewrite" class="mg-btn mg-btn-outline mg-btn-sm">⚡ Rewrite</button>
|
|
37
|
-
<% end %>
|
|
38
|
-
</div>
|
|
39
|
-
</div>
|
|
40
|
-
</div>
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
<!-- Visual Builder Tab -->
|
|
2
|
-
<div class="mg-tab-content active" id="tab-visual">
|
|
3
|
-
<div class="mg-row mg-mb">
|
|
4
|
-
<div class="mg-col-4 mg-field">
|
|
5
|
-
<label for="vb-table">Table</label>
|
|
6
|
-
<select id="vb-table">
|
|
7
|
-
<option value="">-- Select a table --</option>
|
|
8
|
-
<% if @featured_tables != @all_tables %>
|
|
9
|
-
<optgroup label="Featured">
|
|
10
|
-
<% @featured_tables.each do |table| %>
|
|
11
|
-
<option value="<%= table %>"><%= table %></option>
|
|
12
|
-
<% end %>
|
|
13
|
-
</optgroup>
|
|
14
|
-
<optgroup label="All Tables">
|
|
15
|
-
<% (@all_tables - @featured_tables).each do |table| %>
|
|
16
|
-
<option value="<%= table %>"><%= table %></option>
|
|
17
|
-
<% end %>
|
|
18
|
-
</optgroup>
|
|
19
|
-
<% else %>
|
|
20
|
-
<% @all_tables.each do |table| %>
|
|
21
|
-
<option value="<%= table %>"><%= table %></option>
|
|
22
|
-
<% end %>
|
|
23
|
-
<% end %>
|
|
24
|
-
</select>
|
|
25
|
-
</div>
|
|
26
|
-
<div class="mg-col-2 mg-field">
|
|
27
|
-
<label for="vb-row-limit">Row Limit</label>
|
|
28
|
-
<input type="number" id="vb-row-limit" value="25" min="1" max="<%= MysqlGenius.configuration.max_row_limit %>">
|
|
29
|
-
</div>
|
|
30
|
-
<div class="mg-field">
|
|
31
|
-
<label> </label>
|
|
32
|
-
<button id="vb-run" class="mg-btn mg-btn-primary" disabled>▶ Run Query</button>
|
|
33
|
-
<button id="vb-explain" class="mg-btn mg-btn-outline" disabled>🔎 Explain</button>
|
|
34
|
-
</div>
|
|
35
|
-
</div>
|
|
36
|
-
|
|
37
|
-
<div id="vb-columns-section" class="mg-mb mg-hidden">
|
|
38
|
-
<label>Columns
|
|
39
|
-
<span id="vb-toggle-all" class="mg-link">Toggle All</span>
|
|
40
|
-
<span id="vb-show-defaults" class="mg-link">Reset Defaults</span>
|
|
41
|
-
</label>
|
|
42
|
-
<div id="vb-columns" class="mg-checks"></div>
|
|
43
|
-
</div>
|
|
44
|
-
|
|
45
|
-
<div id="vb-filters-section" class="mg-mb mg-hidden">
|
|
46
|
-
<label>Filters</label>
|
|
47
|
-
<div id="vb-filters"></div>
|
|
48
|
-
<button id="vb-add-filter" class="mg-btn mg-btn-outline-secondary mg-btn-sm" style="margin-top:4px;">+ Add Filter</button>
|
|
49
|
-
</div>
|
|
50
|
-
|
|
51
|
-
<div id="vb-order-section" class="mg-mb mg-hidden">
|
|
52
|
-
<label>Order By</label>
|
|
53
|
-
<div id="vb-orders"></div>
|
|
54
|
-
<button id="vb-add-order" class="mg-btn mg-btn-outline-secondary mg-btn-sm" style="margin-top:4px;">+ Add Sort</button>
|
|
55
|
-
</div>
|
|
56
|
-
|
|
57
|
-
<div id="vb-generated-sql" class="mg-mb mg-hidden">
|
|
58
|
-
<label>Generated SQL</label>
|
|
59
|
-
<textarea id="vb-sql-preview" rows="2" readonly></textarea>
|
|
60
|
-
</div>
|
|
61
|
-
</div>
|
|
Binary file
|
|
Binary file
|