rails_nexus 2.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.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +430 -0
- data/Rakefile +6 -0
- data/app/assets/config/rails_nexus_manifest.js +2 -0
- data/app/assets/javascripts/rails_nexus/controllers.js +603 -0
- data/app/assets/stylesheets/rails_nexus/application.css +1964 -0
- data/app/controllers/rails_nexus/analytics_controller.rb +361 -0
- data/app/controllers/rails_nexus/application_controller.rb +15 -0
- data/app/controllers/rails_nexus/backup_controller.rb +91 -0
- data/app/controllers/rails_nexus/cron_jobs_controller.rb +64 -0
- data/app/controllers/rails_nexus/database_health_controller.rb +128 -0
- data/app/controllers/rails_nexus/logged_exceptions_controller.rb +227 -0
- data/app/controllers/rails_nexus/n1_patterns_controller.rb +10 -0
- data/app/controllers/rails_nexus/settings_controller.rb +100 -0
- data/app/controllers/rails_nexus/source_code_controller.rb +39 -0
- data/app/controllers/rails_nexus/stats_controller.rb +494 -0
- data/app/controllers/rails_nexus/workflow_controller.rb +96 -0
- data/app/helpers/rails_nexus/application_helper.rb +5 -0
- data/app/helpers/rails_nexus/logged_exceptions_helper.rb +254 -0
- data/app/helpers/rails_nexus/source_code_helper.rb +107 -0
- data/app/javascript/controllers/rails_nexus_controller.js +380 -0
- data/app/javascript/controllers/rails_nexus_detail_controller.js +165 -0
- data/app/javascript/controllers/rails_nexus_sidebar_controller.js +15 -0
- data/app/javascript/controllers/rails_nexus_theme_controller.js +31 -0
- data/app/javascript/rails_nexus/application.js +17 -0
- data/app/jobs/rails_nexus/application_job.rb +4 -0
- data/app/mailers/rails_nexus/application_mailer.rb +6 -0
- data/app/models/rails_nexus/application_record.rb +5 -0
- data/app/models/rails_nexus/backup.rb +107 -0
- data/app/models/rails_nexus/base_record.rb +26 -0
- data/app/models/rails_nexus/comment.rb +13 -0
- data/app/models/rails_nexus/cron_job.rb +72 -0
- data/app/models/rails_nexus/database_stat.rb +128 -0
- data/app/models/rails_nexus/event.rb +101 -0
- data/app/models/rails_nexus/logged_exception.rb +864 -0
- data/app/models/rails_nexus/logged_exception_n1.rb +87 -0
- data/app/models/rails_nexus/metric.rb +107 -0
- data/app/models/rails_nexus/nginx_metric.rb +112 -0
- data/app/models/rails_nexus/server_metric.rb +168 -0
- data/app/models/rails_nexus/webhook_delivery.rb +64 -0
- data/app/services/rails_nexus/backup_service.rb +275 -0
- data/app/views/layouts/rails_nexus/application.html.erb +185 -0
- data/app/views/rails_nexus/analytics/index.html.erb +363 -0
- data/app/views/rails_nexus/backup/files.html.erb +53 -0
- data/app/views/rails_nexus/backup/index.html.erb +211 -0
- data/app/views/rails_nexus/backup/settings.html.erb +158 -0
- data/app/views/rails_nexus/cron_jobs/index.html.erb +141 -0
- data/app/views/rails_nexus/database_health/index.html.erb +139 -0
- data/app/views/rails_nexus/logged_exceptions/_comments_list.html.erb +50 -0
- data/app/views/rails_nexus/logged_exceptions/_exceptions.html.erb +190 -0
- data/app/views/rails_nexus/logged_exceptions/_feed.html.erb +3 -0
- data/app/views/rails_nexus/logged_exceptions/_filter_group.html.erb +10 -0
- data/app/views/rails_nexus/logged_exceptions/_show.html.erb +554 -0
- data/app/views/rails_nexus/logged_exceptions/_workflow_panel.html.erb +118 -0
- data/app/views/rails_nexus/logged_exceptions/clear.turbo_stream.erb +6 -0
- data/app/views/rails_nexus/logged_exceptions/destroy.turbo_stream.erb +2 -0
- data/app/views/rails_nexus/logged_exceptions/destroy_all.turbo_stream.erb +6 -0
- data/app/views/rails_nexus/logged_exceptions/feed.rss.builder +20 -0
- data/app/views/rails_nexus/logged_exceptions/index.html.erb +323 -0
- data/app/views/rails_nexus/logged_exceptions/query.html.erb +3 -0
- data/app/views/rails_nexus/logged_exceptions/query.turbo_stream.erb +6 -0
- data/app/views/rails_nexus/logged_exceptions/show.html.erb +3 -0
- data/app/views/rails_nexus/logged_exceptions/show.turbo_stream.erb +5 -0
- data/app/views/rails_nexus/n1_patterns/index.html.erb +153 -0
- data/app/views/rails_nexus/settings/index.html.erb +140 -0
- data/app/views/rails_nexus/stats/index.html.erb +569 -0
- data/config/importmap.rb +15 -0
- data/config/initializers/date_formats.rb +5 -0
- data/config/initializers/rails_nexus.rb +18 -0
- data/config/locales/en.yml +47 -0
- data/config/routes.rb +58 -0
- data/db/migrate/20240330122311_create_rails_nexus_logged_exceptions.rb +22 -0
- data/lib/generators/rails_nexus/backup_generator.rb +70 -0
- data/lib/generators/rails_nexus/customize_generator.rb +159 -0
- data/lib/generators/rails_nexus/install_generator.rb +61 -0
- data/lib/generators/rails_nexus/templates/INSTALL.md +9 -0
- data/lib/generators/rails_nexus/templates/backup/backup_helper.sh +152 -0
- data/lib/generators/rails_nexus/templates/backup/config.rb +27 -0
- data/lib/generators/rails_nexus/templates/backup/models/daily_backup.rb +24 -0
- data/lib/generators/rails_nexus/templates/backup/models/full_backup.rb +35 -0
- data/lib/generators/rails_nexus/templates/backup/models/sync_backup.rb +43 -0
- data/lib/generators/rails_nexus/templates/backup/mysql-config/db_config.cnf +15 -0
- data/lib/generators/rails_nexus/templates/backup/schedule.rb +28 -0
- data/lib/generators/rails_nexus/templates/javascript/controllers/rails_nexus_controller.js +310 -0
- data/lib/generators/rails_nexus/templates/javascript/controllers/rails_nexus_detail_controller.js +98 -0
- data/lib/generators/rails_nexus/templates/javascript/controllers/rails_nexus_sidebar_controller.js +15 -0
- data/lib/generators/rails_nexus/templates/javascript/controllers/rails_nexus_theme_controller.js +30 -0
- data/lib/generators/rails_nexus/templates/migration.rb +24 -0
- data/lib/generators/rails_nexus/templates/migration_advanced_features.rb +30 -0
- data/lib/generators/rails_nexus/templates/migration_cron_jobs.rb +22 -0
- data/lib/generators/rails_nexus/templates/migration_new_schema.rb +120 -0
- data/lib/generators/rails_nexus/templates/migration_platform_detection.rb +11 -0
- data/lib/generators/rails_nexus/templates/migration_webhook_deliveries.rb +21 -0
- data/lib/generators/rails_nexus/templates/migration_workflow.rb +29 -0
- data/lib/generators/rails_nexus/templates/rails_nexus.rb +96 -0
- data/lib/generators/rails_nexus/templates/views/layouts/rails_nexus/application.html.erb +129 -0
- data/lib/generators/rails_nexus/templates/views/rails_nexus/logged_exceptions/_exceptions.html.erb +123 -0
- data/lib/generators/rails_nexus/templates/views/rails_nexus/logged_exceptions/_show.html.erb +297 -0
- data/lib/generators/rails_nexus/templates/views/rails_nexus/logged_exceptions/index.html.erb +113 -0
- data/lib/rails_nexus/breadcrumbs.rb +161 -0
- data/lib/rails_nexus/cleanup.rb +32 -0
- data/lib/rails_nexus/configuration.rb +319 -0
- data/lib/rails_nexus/engine.rb +135 -0
- data/lib/rails_nexus/logger.rb +188 -0
- data/lib/rails_nexus/notifications.rb +105 -0
- data/lib/rails_nexus/ransack_config.rb +4 -0
- data/lib/rails_nexus/storm_protection.rb +124 -0
- data/lib/rails_nexus/version.rb +3 -0
- data/lib/rails_nexus.rb +133 -0
- data/lib/tasks/rails_nexus.rake +230 -0
- data/lib/tasks/rails_nexus_tasks.rake +37 -0
- data/rails_nexus.gemspec +36 -0
- metadata +252 -0
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class CreateRailsNexusMetricsTables < ActiveRecord::Migration[8.0]
|
|
4
|
+
def change
|
|
5
|
+
# ─── rails_nexus_metrics ─────────────────────────────────────────
|
|
6
|
+
create_table :rails_nexus_metrics do |t|
|
|
7
|
+
t.string :metric_type, null: false
|
|
8
|
+
t.float :value, null: false
|
|
9
|
+
t.string :unit
|
|
10
|
+
t.json :metadata
|
|
11
|
+
t.datetime :recorded_at, null: false
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
add_index :rails_nexus_metrics, [:metric_type, :recorded_at]
|
|
15
|
+
add_index :rails_nexus_metrics, :recorded_at
|
|
16
|
+
|
|
17
|
+
# ─── rails_nexus_database_stats ──────────────────────────────────
|
|
18
|
+
create_table :rails_nexus_database_stats do |t|
|
|
19
|
+
t.integer :pool_size
|
|
20
|
+
t.integer :busy
|
|
21
|
+
t.integer :idle
|
|
22
|
+
t.integer :dead
|
|
23
|
+
t.integer :waiting
|
|
24
|
+
t.float :utilization
|
|
25
|
+
t.string :table_name
|
|
26
|
+
t.bigint :table_rows
|
|
27
|
+
t.string :table_size
|
|
28
|
+
t.string :index_size
|
|
29
|
+
t.string :data_free
|
|
30
|
+
t.json :n1_patterns
|
|
31
|
+
t.json :slow_queries
|
|
32
|
+
t.datetime :recorded_at, null: false
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
add_index :rails_nexus_database_stats, :recorded_at
|
|
36
|
+
add_index :rails_nexus_database_stats, :table_name
|
|
37
|
+
|
|
38
|
+
# ─── rails_nexus_backups ─────────────────────────────────────────
|
|
39
|
+
create_table :rails_nexus_backups do |t|
|
|
40
|
+
t.string :model_name, null: false
|
|
41
|
+
t.string :status, null: false
|
|
42
|
+
t.text :file_path
|
|
43
|
+
t.bigint :file_size
|
|
44
|
+
t.float :duration
|
|
45
|
+
t.text :error_message
|
|
46
|
+
t.string :triggered_by
|
|
47
|
+
t.datetime :started_at, null: false
|
|
48
|
+
t.datetime :completed_at
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
add_index :rails_nexus_backups, [:model_name, :started_at]
|
|
52
|
+
add_index :rails_nexus_backups, :status
|
|
53
|
+
add_index :rails_nexus_backups, :started_at
|
|
54
|
+
|
|
55
|
+
# ─── rails_nexus_server_metrics ──────────────────────────────────
|
|
56
|
+
create_table :rails_nexus_server_metrics do |t|
|
|
57
|
+
t.string :hostname
|
|
58
|
+
t.string :ruby_version
|
|
59
|
+
t.string :rails_version
|
|
60
|
+
t.string :os_info
|
|
61
|
+
t.float :cpu_usage
|
|
62
|
+
t.integer :cpu_cores
|
|
63
|
+
t.float :load_avg_1m
|
|
64
|
+
t.float :load_avg_5m
|
|
65
|
+
t.float :load_avg_15m
|
|
66
|
+
t.bigint :memory_total
|
|
67
|
+
t.bigint :memory_used
|
|
68
|
+
t.bigint :memory_free
|
|
69
|
+
t.bigint :swap_total
|
|
70
|
+
t.bigint :swap_used
|
|
71
|
+
t.bigint :disk_total
|
|
72
|
+
t.bigint :disk_used
|
|
73
|
+
t.float :disk_usage_percent
|
|
74
|
+
t.integer :puma_workers
|
|
75
|
+
t.integer :puma_threads
|
|
76
|
+
t.integer :sidekiq_workers
|
|
77
|
+
t.integer :sidekiq_processed
|
|
78
|
+
t.integer :sidekiq_failed
|
|
79
|
+
t.integer :sidekiq_enqueued
|
|
80
|
+
t.float :uptime_seconds
|
|
81
|
+
t.datetime :recorded_at, null: false
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
add_index :rails_nexus_server_metrics, :recorded_at
|
|
85
|
+
|
|
86
|
+
# ─── rails_nexus_nginx_metrics ───────────────────────────────────
|
|
87
|
+
create_table :rails_nexus_nginx_metrics do |t|
|
|
88
|
+
t.integer :status_code, null: false
|
|
89
|
+
t.string :request_method
|
|
90
|
+
t.string :request_path
|
|
91
|
+
t.float :response_time
|
|
92
|
+
t.float :upstream_time
|
|
93
|
+
t.string :remote_addr
|
|
94
|
+
t.string :user_agent
|
|
95
|
+
t.string :referer
|
|
96
|
+
t.text :request_body
|
|
97
|
+
t.json :metadata
|
|
98
|
+
t.datetime :recorded_at, null: false
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
add_index :rails_nexus_nginx_metrics, [:status_code, :recorded_at]
|
|
102
|
+
add_index :rails_nexus_nginx_metrics, :recorded_at
|
|
103
|
+
add_index :rails_nexus_nginx_metrics, :request_path
|
|
104
|
+
|
|
105
|
+
# ─── rails_nexus_events ──────────────────────────────────────────
|
|
106
|
+
create_table :rails_nexus_events do |t|
|
|
107
|
+
t.string :event_type, null: false
|
|
108
|
+
t.string :eventable_type
|
|
109
|
+
t.bigint :eventable_id
|
|
110
|
+
t.json :metadata
|
|
111
|
+
t.string :author
|
|
112
|
+
t.text :message
|
|
113
|
+
t.datetime :created_at, null: false
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
add_index :rails_nexus_events, [:eventable_type, :eventable_id]
|
|
117
|
+
add_index :rails_nexus_events, :event_type
|
|
118
|
+
add_index :rails_nexus_events, :created_at
|
|
119
|
+
end
|
|
120
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
class AddPlatformToRailsNexusLoggedExceptions < ActiveRecord::Migration[8.0]
|
|
2
|
+
def change
|
|
3
|
+
add_column :rails_nexus_exceptions, :platform, :string, default: "web"
|
|
4
|
+
add_column :rails_nexus_exceptions, :platform_version, :string
|
|
5
|
+
add_column :rails_nexus_exceptions, :device_type, :string
|
|
6
|
+
add_column :rails_nexus_exceptions, :app_version, :string
|
|
7
|
+
|
|
8
|
+
add_index :rails_nexus_exceptions, :platform
|
|
9
|
+
add_index :rails_nexus_exceptions, [:platform, :exception_class]
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
class CreateRailsNexusWebhookDeliveries < ActiveRecord::Migration[8.0]
|
|
2
|
+
def change
|
|
3
|
+
create_table :rails_nexus_webhook_deliveries do |t|
|
|
4
|
+
t.string :url, null: false
|
|
5
|
+
t.string :status, null: false, default: "pending"
|
|
6
|
+
t.integer :response_code
|
|
7
|
+
t.text :request_body
|
|
8
|
+
t.text :response_body
|
|
9
|
+
t.float :duration
|
|
10
|
+
t.text :error_message
|
|
11
|
+
t.string :event_type
|
|
12
|
+
t.json :metadata
|
|
13
|
+
|
|
14
|
+
t.timestamps
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
add_index :rails_nexus_webhook_deliveries, :status
|
|
18
|
+
add_index :rails_nexus_webhook_deliveries, :created_at
|
|
19
|
+
add_index :rails_nexus_webhook_deliveries, :url
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Migration for RailsNexus workflow management
|
|
2
|
+
# Adds priority, assignment, snooze, mute columns and comments table
|
|
3
|
+
class AddWorkflowToRailsNexus < ActiveRecord::Migration[8.0]
|
|
4
|
+
def change
|
|
5
|
+
# Workflow columns on logged_exceptions
|
|
6
|
+
add_column :rails_nexus_exceptions, :priority, :string, default: nil
|
|
7
|
+
add_column :rails_nexus_exceptions, :assigned_to, :string, default: nil
|
|
8
|
+
add_column :rails_nexus_exceptions, :assigned_at, :datetime, default: nil
|
|
9
|
+
add_column :rails_nexus_exceptions, :snoozed_until, :datetime, default: nil
|
|
10
|
+
add_column :rails_nexus_exceptions, :muted, :boolean, default: false
|
|
11
|
+
add_column :rails_nexus_exceptions, :muted_at, :datetime, default: nil
|
|
12
|
+
add_column :rails_nexus_exceptions, :comments_count, :integer, default: 0
|
|
13
|
+
|
|
14
|
+
add_index :rails_nexus_exceptions, :priority
|
|
15
|
+
add_index :rails_nexus_exceptions, :assigned_to
|
|
16
|
+
add_index :rails_nexus_exceptions, :muted
|
|
17
|
+
|
|
18
|
+
# Comments table
|
|
19
|
+
create_table :rails_nexus_comments do |t|
|
|
20
|
+
t.references :logged_exception, null: false, foreign_key: { to_table: :rails_nexus_exceptions }
|
|
21
|
+
t.string :author, null: false
|
|
22
|
+
t.text :body, null: false
|
|
23
|
+
t.string :comment_type, default: "comment" # comment, status_change, assignment, note
|
|
24
|
+
t.timestamps
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
add_index :rails_nexus_comments, [:logged_exception_id, :created_at]
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
Rails.application.config.to_prepare do
|
|
4
|
+
RailsNexus.configure do |config|
|
|
5
|
+
# ─── General ─────────────────────────────────────────────
|
|
6
|
+
# Dashboard title
|
|
7
|
+
# config.application_name = "My App"
|
|
8
|
+
|
|
9
|
+
# Number of exceptions per page
|
|
10
|
+
# config.per_page = 30
|
|
11
|
+
|
|
12
|
+
# ─── Authentication ──────────────────────────────────────
|
|
13
|
+
# Protect the dashboard — only authorized users can access
|
|
14
|
+
# config.auth_block = lambda do |controller|
|
|
15
|
+
# controller.current_user&.admin?
|
|
16
|
+
# end
|
|
17
|
+
|
|
18
|
+
# ─── Exception Data ──────────────────────────────────────
|
|
19
|
+
# Attach additional data to each exception record
|
|
20
|
+
# config.exception_data = lambda do |controller|
|
|
21
|
+
# {
|
|
22
|
+
# user_id: controller.current_user&.id,
|
|
23
|
+
# request_id: controller.request.request_id
|
|
24
|
+
# }
|
|
25
|
+
# end
|
|
26
|
+
|
|
27
|
+
# ─── Notifications ───────────────────────────────────────
|
|
28
|
+
# Custom callback after exception is created
|
|
29
|
+
# config.after_create = lambda do |exception|
|
|
30
|
+
# SlackNotifier.alert(exception)
|
|
31
|
+
# end
|
|
32
|
+
|
|
33
|
+
# Webhook URLs for POST notifications
|
|
34
|
+
# config.webhooks = ["https://hooks.slack.com/services/xxx"]
|
|
35
|
+
# config.webhook_timeout = 5
|
|
36
|
+
# config.webhook_headers = { "Authorization" => "Bearer token" }
|
|
37
|
+
|
|
38
|
+
# ─── Cleanup ─────────────────────────────────────────────
|
|
39
|
+
# Auto-delete exceptions older than N days
|
|
40
|
+
# config.retention_days = 90
|
|
41
|
+
|
|
42
|
+
# ─── Appearance ──────────────────────────────────────────
|
|
43
|
+
# Theme: "light", "dark", or "auto"
|
|
44
|
+
# config.theme = "auto"
|
|
45
|
+
|
|
46
|
+
# Body CSS class
|
|
47
|
+
# config.body_class = ""
|
|
48
|
+
|
|
49
|
+
# ─── Advanced UI ─────────────────────────────────────────
|
|
50
|
+
|
|
51
|
+
# Show stats overview cards on the index page
|
|
52
|
+
# config.show_stats = true
|
|
53
|
+
|
|
54
|
+
# Enable keyboard shortcuts (/, j/k, t, ?, Esc, etc.)
|
|
55
|
+
# config.keyboard_shortcuts = true
|
|
56
|
+
|
|
57
|
+
# Show prev/next navigation in detail view
|
|
58
|
+
# config.enable_navigation = true
|
|
59
|
+
|
|
60
|
+
# Number of backtrace frames before collapsing
|
|
61
|
+
# config.backtrace_limit = 30
|
|
62
|
+
|
|
63
|
+
# Show metadata grid in detail view
|
|
64
|
+
# config.show_metadata = true
|
|
65
|
+
|
|
66
|
+
# Show environment variables in detail view
|
|
67
|
+
# config.show_environment = false
|
|
68
|
+
|
|
69
|
+
# Show request params in detail view
|
|
70
|
+
# config.show_request = true
|
|
71
|
+
|
|
72
|
+
# Page size options for the selector
|
|
73
|
+
# config.page_size_options = [25, 50, 100]
|
|
74
|
+
|
|
75
|
+
# ─── Sidebar Links ───────────────────────────────────────
|
|
76
|
+
# Custom links in the sidebar
|
|
77
|
+
# config.sidebar_links = [
|
|
78
|
+
# { label: "GitHub", url: "https://github.com/myorg/myapp" },
|
|
79
|
+
# { label: "Docs", url: "/docs" }
|
|
80
|
+
# ]
|
|
81
|
+
# ─── Database ───────────────────────────────────────────
|
|
82
|
+
# Use a separate database for RailsNexus tables.
|
|
83
|
+
#
|
|
84
|
+
# Option 1: Connection URL
|
|
85
|
+
# config.database_url = "mysql2://user:pass@localhost/rails_nexus"
|
|
86
|
+
#
|
|
87
|
+
# Option 2: Named database (uses config/database.yml entry)
|
|
88
|
+
# config.database_name = "rails_nexus"
|
|
89
|
+
#
|
|
90
|
+
# Option 3: Separate YAML file
|
|
91
|
+
# config.database_yml = "config/rails_nexus_database.yml"
|
|
92
|
+
#
|
|
93
|
+
# Option 4: Table prefix (default: "rails_nexus_")
|
|
94
|
+
# config.table_prefix = "ops_"
|
|
95
|
+
end
|
|
96
|
+
end
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en" class="h-full" data-controller="rails_nexus-theme" data-rails_nexus-theme-theme-value="<%= RailsNexus.configuration.theme %>">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
+
<meta name="color-scheme" content="light dark">
|
|
7
|
+
<title><%= content_for?(:title) ? yield(:title) : RailsNexus.configuration.application_name || "RailsNexus" %></title>
|
|
8
|
+
|
|
9
|
+
<%= stylesheet_link_tag "rails_nexus/application", "data-turbo-track": "reload" %>
|
|
10
|
+
<%= javascript_importmap_tags "rails_nexus/application" %>
|
|
11
|
+
|
|
12
|
+
<% if respond_to?(:turbo_refreshes_with) %>
|
|
13
|
+
<%= turbo_refreshes_with method: :morph, scroll: :preserve %>
|
|
14
|
+
<% end %>
|
|
15
|
+
<%= csrf_meta_tags %>
|
|
16
|
+
<%= csp_meta_tag %>
|
|
17
|
+
</head>
|
|
18
|
+
<body class="h-full <%= RailsNexus.configuration.body_class %>">
|
|
19
|
+
<div class="min-h-full flex">
|
|
20
|
+
|
|
21
|
+
<%# Sidebar %>
|
|
22
|
+
<aside class="rn-sidebar">
|
|
23
|
+
<div class="rn-sidebar-logo">
|
|
24
|
+
<%= link_to root_path, class: "flex items-center gap-2.5" do %>
|
|
25
|
+
<div class="rn-logo-icon">⚡</div>
|
|
26
|
+
<span class="rn-logo-text"><%= RailsNexus.configuration.application_name || "RailsNexus" %></span>
|
|
27
|
+
<% end %>
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
<nav class="rn-sidebar-nav">
|
|
31
|
+
<%= link_to root_path,
|
|
32
|
+
class: "rn-nav-item #{request.path == rails_nexus.root_path ? 'active' : ''}" do %>
|
|
33
|
+
<svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6A2.25 2.25 0 016 3.75h2.25A2.25 2.25 0 0110.5 6v2.25a2.25 2.25 0 01-2.25 2.25H6a2.25 2.25 0 01-2.25-2.25V6zM3.75 15.75A2.25 2.25 0 016 13.5h2.25a2.25 2.25 0 012.25 2.25V18a2.25 2.25 0 01-2.25 2.25H6A2.25 2.25 0 013.75 18v-2.25zM13.5 6a2.25 2.25 0 012.25-2.25H18A2.25 2.25 0 0120.25 6v2.25A2.25 2.25 0 0118 10.5h-2.25a2.25 2.25 0 01-2.25-2.25V6zM13.5 15.75a2.25 2.25 0 012.25-2.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-2.25A2.25 2.25 0 0113.5 18v-2.25z" /></svg>
|
|
34
|
+
Dashboard
|
|
35
|
+
<% end %>
|
|
36
|
+
|
|
37
|
+
<%= link_to feed_logged_exceptions_path(format: :rss),
|
|
38
|
+
class: "rn-nav-item" do %>
|
|
39
|
+
<svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M12.75 19.5v-.75a7.5 7.5 0 00-7.5-7.5H4.5m0-6.75h.75c7.87 0 14.25 6.38 14.25 14.25v.75M6 18.75a.375.375 0 11-.75 0 .375.375 0 01.75 0z" /></svg>
|
|
40
|
+
RSS Feed
|
|
41
|
+
<% end %>
|
|
42
|
+
|
|
43
|
+
<% RailsNexus.configuration.sidebar_links.each do |link| %>
|
|
44
|
+
<%= link_to link[:url],
|
|
45
|
+
class: "rn-nav-item",
|
|
46
|
+
target: link[:target] || "_self" do %>
|
|
47
|
+
<svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M13.5 6H5.25A2.25 2.25 0 003 8.25v10.5A2.25 2.25 0 005.25 21h10.5A2.25 2.25 0 0018 18.75V10.5m-10.5 6L21 3m0 0h-5.25M21 3v5.25" /></svg>
|
|
48
|
+
<%= link[:label] %>
|
|
49
|
+
<% end %>
|
|
50
|
+
<% end %>
|
|
51
|
+
</nav>
|
|
52
|
+
|
|
53
|
+
<div class="rn-sidebar-footer">
|
|
54
|
+
v<%= RailsNexus::VERSION %> · <%= RailsNexus::LoggedException.count %> exceptions
|
|
55
|
+
</div>
|
|
56
|
+
</aside>
|
|
57
|
+
|
|
58
|
+
<%# Main Content %>
|
|
59
|
+
<div class="flex-1 flex flex-col min-w-0">
|
|
60
|
+
<header class="rn-topbar">
|
|
61
|
+
<div class="flex items-center gap-3">
|
|
62
|
+
<button type="button" class="lg:hidden rn-icon-btn" data-action="click->rails_nexus-sidebar#toggle">
|
|
63
|
+
<svg class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5" /></svg>
|
|
64
|
+
</button>
|
|
65
|
+
<span class="text-sm font-semibold lg:hidden"><%= RailsNexus.configuration.application_name || "RailsNexus" %></span>
|
|
66
|
+
</div>
|
|
67
|
+
|
|
68
|
+
<div class="flex items-center gap-1.5">
|
|
69
|
+
<button type="button"
|
|
70
|
+
class="rn-icon-btn"
|
|
71
|
+
data-action="click->rails_nexus-theme#toggle"
|
|
72
|
+
title="Toggle theme">
|
|
73
|
+
<svg class="w-4 h-4 block dark:hidden" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M21.752 15.002A9.718 9.718 0 0118 15.75c-5.385 0-9.75-4.365-9.75-9.75 0-1.33.266-2.597.748-3.752A9.753 9.753 0 003 11.25C3 16.635 7.365 21 12.75 21a9.753 9.753 0 009.002-5.998z" /></svg>
|
|
74
|
+
<svg class="w-4 h-4 hidden dark:block" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M12 3v2.25m6.364.386l-1.591 1.591M21 12h-2.25m-.386 6.364l-1.591-1.591M12 18.75V21m-4.773-4.227l-1.591 1.591M5.25 12H3m4.227-4.773L5.636 5.636M15.75 12a3.75 3.75 0 11-7.5 0 3.75 3.75 0 017.5 0z" /></svg>
|
|
75
|
+
</button>
|
|
76
|
+
|
|
77
|
+
<% if main_app.respond_to?(:root_path) %>
|
|
78
|
+
<%= link_to main_app.root_path,
|
|
79
|
+
class: "rn-icon-btn",
|
|
80
|
+
title: "Back to app" do %>
|
|
81
|
+
<svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M13.5 6H5.25A2.25 2.25 0 003 8.25v10.5A2.25 2.25 0 005.25 21h10.5A2.25 2.25 0 0018 18.75V10.5m-10.5 6L21 3m0 0h-5.25M21 3v5.25" /></svg>
|
|
82
|
+
<% end %>
|
|
83
|
+
<% end %>
|
|
84
|
+
</div>
|
|
85
|
+
</header>
|
|
86
|
+
|
|
87
|
+
<% if notice.present? %>
|
|
88
|
+
<div class="mx-4 sm:mx-6 mt-4">
|
|
89
|
+
<div class="rn-alert rn-alert-success">
|
|
90
|
+
<svg class="w-5 h-5 shrink-0" viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd" /></svg>
|
|
91
|
+
<p class="text-sm font-medium"><%= notice %></p>
|
|
92
|
+
</div>
|
|
93
|
+
</div>
|
|
94
|
+
<% end %>
|
|
95
|
+
|
|
96
|
+
<% if alert.present? %>
|
|
97
|
+
<div class="mx-4 sm:mx-6 mt-4">
|
|
98
|
+
<div class="rn-alert rn-alert-error">
|
|
99
|
+
<svg class="w-5 h-5 shrink-0" viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clip-rule="evenodd" /></svg>
|
|
100
|
+
<p class="text-sm font-medium"><%= alert %></p>
|
|
101
|
+
</div>
|
|
102
|
+
</div>
|
|
103
|
+
<% end %>
|
|
104
|
+
|
|
105
|
+
<main class="flex-1 overflow-y-auto p-4 sm:p-6">
|
|
106
|
+
<%= yield %>
|
|
107
|
+
</main>
|
|
108
|
+
</div>
|
|
109
|
+
</div>
|
|
110
|
+
|
|
111
|
+
<div class="rn-overlay" data-rails_nexus-sidebar-target="overlay" data-action="click->rails_nexus-sidebar#close"></div>
|
|
112
|
+
<div class="rn-mobile-sidebar" data-rails_nexus-sidebar-target="drawer">
|
|
113
|
+
<div class="rn-sidebar-logo">
|
|
114
|
+
<span class="rn-logo-text"><%= RailsNexus.configuration.application_name || "RailsNexus" %></span>
|
|
115
|
+
<button type="button" class="rn-icon-btn" data-action="click->rails_nexus-sidebar#close">
|
|
116
|
+
<svg class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" /></svg>
|
|
117
|
+
</button>
|
|
118
|
+
</div>
|
|
119
|
+
<nav class="rn-sidebar-nav">
|
|
120
|
+
<%= link_to root_path, class: "rn-nav-item" do %>
|
|
121
|
+
<svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6A2.25 2.25 0 016 3.75h2.25A2.25 2.25 0 0110.5 6v2.25a2.25 2.25 0 01-2.25 2.25H6a2.25 2.25 0 01-2.25-2.25V6z" /></svg>
|
|
122
|
+
Dashboard
|
|
123
|
+
<% end %>
|
|
124
|
+
</nav>
|
|
125
|
+
</div>
|
|
126
|
+
|
|
127
|
+
<%= turbo_frame_tag :remote_modal, target: :_top %>
|
|
128
|
+
</body>
|
|
129
|
+
</html>
|
data/lib/generators/rails_nexus/templates/views/rails_nexus/logged_exceptions/_exceptions.html.erb
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
<div id="exceptions-content" class="bg-white rounded-xl border border-gray-200/60 shadow-sm overflow-hidden">
|
|
2
|
+
<% if @exceptions.empty? %>
|
|
3
|
+
<div class="px-6 py-16 text-center">
|
|
4
|
+
<div class="w-10 h-10 rounded-full bg-emerald-50 flex items-center justify-center mx-auto border border-emerald-100">
|
|
5
|
+
<svg class="w-5 h-5 text-emerald-500" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
|
6
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M9 12.75L11.25 15 15 9.75M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
|
7
|
+
</svg>
|
|
8
|
+
</div>
|
|
9
|
+
<p class="mt-3 text-sm font-medium text-gray-600"><%= t(".empty") %></p>
|
|
10
|
+
<p class="mt-1 text-xs text-gray-400">No exceptions match your filters.</p>
|
|
11
|
+
</div>
|
|
12
|
+
<% else %>
|
|
13
|
+
<%# Table header with count and bulk actions %>
|
|
14
|
+
<div class="px-4 py-2.5 border-b border-gray-100 flex items-center justify-between bg-gray-50/50">
|
|
15
|
+
<div class="flex items-center gap-3">
|
|
16
|
+
<span class="text-xs font-medium text-gray-500">
|
|
17
|
+
<span class="font-semibold text-gray-700"><%= @pagy.count %></span> exceptions
|
|
18
|
+
<% if filtered? %>
|
|
19
|
+
<span class="text-gray-400">(filtered)</span>
|
|
20
|
+
<% end %>
|
|
21
|
+
</span>
|
|
22
|
+
</div>
|
|
23
|
+
<div class="flex items-center gap-2">
|
|
24
|
+
<%= link_to destroy_all_logged_exceptions_path(params_filters),
|
|
25
|
+
class: "inline-flex items-center gap-1 px-2 py-1 text-[11px] font-medium text-red-600 bg-red-50 border border-red-100 rounded-md hover:bg-red-100 transition-colors",
|
|
26
|
+
data: { turbo_method: :post, turbo_confirm: t(".confirm_delete_visible"), turbo_stream: true } do %>
|
|
27
|
+
<svg class="w-3 h-3" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0" /></svg>
|
|
28
|
+
Delete all
|
|
29
|
+
<% end %>
|
|
30
|
+
</div>
|
|
31
|
+
</div>
|
|
32
|
+
|
|
33
|
+
<div class="overflow-x-auto">
|
|
34
|
+
<table class="min-w-full">
|
|
35
|
+
<thead>
|
|
36
|
+
<tr class="border-b border-gray-100">
|
|
37
|
+
<th class="px-4 py-2 text-left text-[11px] font-semibold text-gray-400 uppercase tracking-wider bg-gray-50/30">
|
|
38
|
+
<%= sort_link @q, :exception_class, "Type", data: { turbo_frame: "exceptions" } %>
|
|
39
|
+
</th>
|
|
40
|
+
<th class="px-4 py-2 text-left text-[11px] font-semibold text-gray-400 uppercase tracking-wider bg-gray-50/30">
|
|
41
|
+
<%= sort_link @q, :controller_name, "Source", data: { turbo_frame: "exceptions" } %>
|
|
42
|
+
</th>
|
|
43
|
+
<th class="px-4 py-2 text-left text-[11px] font-semibold text-gray-400 uppercase tracking-wider bg-gray-50/30">
|
|
44
|
+
<%= sort_link @q, :action_name, "Action", data: { turbo_frame: "exceptions" } %>
|
|
45
|
+
</th>
|
|
46
|
+
<th class="px-4 py-2 text-left text-[11px] font-semibold text-gray-400 uppercase tracking-wider bg-gray-50/30">
|
|
47
|
+
Message
|
|
48
|
+
</th>
|
|
49
|
+
<th class="px-4 py-2 text-left text-[11px] font-semibold text-gray-400 uppercase tracking-wider bg-gray-50/30">
|
|
50
|
+
<%= sort_link @q, :created_at, "Time", data: { turbo_frame: "exceptions" } %>
|
|
51
|
+
</th>
|
|
52
|
+
<th class="px-4 py-2 text-right text-[11px] font-semibold text-gray-400 uppercase tracking-wider bg-gray-50/30">
|
|
53
|
+
<span class="sr-only">Actions</span>
|
|
54
|
+
</th>
|
|
55
|
+
</tr>
|
|
56
|
+
</thead>
|
|
57
|
+
<tbody class="divide-y divide-gray-50">
|
|
58
|
+
<% @exceptions.each do |exception| %>
|
|
59
|
+
<tr id="<%= dom_id(exception) %>" class="group hover:bg-indigo-50/30 transition-colors cursor-pointer"
|
|
60
|
+
data-action="click->rails_nexus#selectRow"
|
|
61
|
+
data-url="<%= logged_exception_path(exception) %>">
|
|
62
|
+
<%# Type badge %>
|
|
63
|
+
<td class="px-4 py-2.5 whitespace-nowrap">
|
|
64
|
+
<span class="inline-flex items-center px-2 py-0.5 rounded text-[11px] font-semibold bg-red-50 text-red-700 border border-red-100/80">
|
|
65
|
+
<%= exception.exception_class %>
|
|
66
|
+
</span>
|
|
67
|
+
</td>
|
|
68
|
+
|
|
69
|
+
<%# Source (controller) %>
|
|
70
|
+
<td class="px-4 py-2.5 whitespace-nowrap">
|
|
71
|
+
<div class="flex items-center gap-1.5">
|
|
72
|
+
<span class="w-1.5 h-1.5 rounded-full bg-gray-300 shrink-0"></span>
|
|
73
|
+
<span class="text-xs font-mono text-gray-600"><%= exception.controller_name %></span>
|
|
74
|
+
</div>
|
|
75
|
+
</td>
|
|
76
|
+
|
|
77
|
+
<%# Action %>
|
|
78
|
+
<td class="px-4 py-2.5 whitespace-nowrap text-xs font-mono text-gray-400">
|
|
79
|
+
<%= exception.action_name %>
|
|
80
|
+
</td>
|
|
81
|
+
|
|
82
|
+
<%# Message %>
|
|
83
|
+
<td class="px-4 py-2.5 text-xs text-gray-500 truncate" style="width: 16rem; max-width: 16rem" title="<%= exception.message %>">
|
|
84
|
+
<%= link_to exception.message, logged_exception_path(exception),
|
|
85
|
+
class: "hover:text-indigo-600 transition-colors",
|
|
86
|
+
data: { turbo_frame: "exception-details" } %>
|
|
87
|
+
</td>
|
|
88
|
+
|
|
89
|
+
<%# Time %>
|
|
90
|
+
<td class="px-4 py-2.5 whitespace-nowrap text-[11px] text-gray-400">
|
|
91
|
+
<%= pretty_exception_date(exception) %>
|
|
92
|
+
</td>
|
|
93
|
+
|
|
94
|
+
<%# Actions %>
|
|
95
|
+
<td class="px-4 py-2.5 whitespace-nowrap text-right">
|
|
96
|
+
<%= link_to logged_exception_path(exception),
|
|
97
|
+
class: "opacity-0 group-hover:opacity-100 text-gray-300 hover:text-red-500 transition-all",
|
|
98
|
+
title: "Delete",
|
|
99
|
+
data: { turbo_method: :delete, turbo_confirm: t(".confirm_delete"), turbo_stream: true, action: "click->rails_nexus#stopPropagation" } do %>
|
|
100
|
+
<svg class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0" /></svg>
|
|
101
|
+
<% end %>
|
|
102
|
+
</td>
|
|
103
|
+
</tr>
|
|
104
|
+
<% end %>
|
|
105
|
+
</tbody>
|
|
106
|
+
</table>
|
|
107
|
+
</div>
|
|
108
|
+
|
|
109
|
+
<%# Pagination %>
|
|
110
|
+
<% if @pagy.pages > 1 %>
|
|
111
|
+
<div class="px-4 py-2.5 border-t border-gray-100 flex items-center justify-between bg-gray-50/30">
|
|
112
|
+
<p class="text-[11px] text-gray-400">
|
|
113
|
+
Showing <span class="font-medium text-gray-600"><%= @pagy.from %></span>
|
|
114
|
+
to <span class="font-medium text-gray-600"><%= @pagy.to %></span>
|
|
115
|
+
of <span class="font-medium text-gray-600"><%= @pagy.count %></span>
|
|
116
|
+
</p>
|
|
117
|
+
<div>
|
|
118
|
+
<%== pagy_nav(@pagy) %>
|
|
119
|
+
</div>
|
|
120
|
+
</div>
|
|
121
|
+
<% end %>
|
|
122
|
+
<% end %>
|
|
123
|
+
</div>
|