rails_nexus 2.0.2 → 2.0.6
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/app/assets/javascripts/rails_nexus/controllers.js +21 -1
- data/app/assets/stylesheets/rails_nexus/application.css +295 -29
- data/app/controllers/rails_nexus/backup_controller.rb +6 -2
- data/app/javascript/controllers/rails_nexus_controller.js +2 -0
- data/app/javascript/controllers/rails_nexus_sidebar_controller.js +13 -0
- data/app/models/rails_nexus/backup_config.rb +77 -14
- data/app/services/rails_nexus/backup_service.rb +416 -97
- data/app/views/layouts/rails_nexus/_sidebar_navigation.html.erb +83 -0
- data/app/views/layouts/rails_nexus/application.html.erb +70 -22
- data/app/views/rails_nexus/backup/_form.html.erb +183 -37
- data/app/views/rails_nexus/logged_exceptions/_exceptions.html.erb +16 -15
- data/app/views/rails_nexus/logged_exceptions/index.html.erb +3 -3
- data/db/seeds/backup_configs.rb +139 -0
- data/lib/generators/rails_nexus/templates/migration.rb +59 -0
- data/lib/rails_nexus/version.rb +1 -1
- data/lib/tasks/rails_nexus.rake +10 -0
- metadata +3 -1
|
@@ -14,10 +14,11 @@
|
|
|
14
14
|
</div>
|
|
15
15
|
<% else %>
|
|
16
16
|
<%# ─── Table Header Bar ───────────────────────────────────── %>
|
|
17
|
-
<div class="
|
|
18
|
-
<div class="
|
|
17
|
+
<div class="rn-exceptions-toolbar" style="background: var(--rn-bg-secondary); border-bottom: 1px solid var(--rn-border-light)">
|
|
18
|
+
<div class="rn-exceptions-toolbar-summary">
|
|
19
19
|
<span class="text-xs font-medium" style="color: var(--rn-text-secondary)">
|
|
20
|
-
<span class="font-semibold" style="color: var(--rn-text)"><%= number_with_delimiter(@pagy.count) %></span>
|
|
20
|
+
<span class="font-semibold" style="color: var(--rn-text)"><%= number_with_delimiter(@pagy.count) %></span>
|
|
21
|
+
<%= "exception".pluralize(@pagy.count) %>
|
|
21
22
|
<% if filtered? %>
|
|
22
23
|
<span style="color: var(--rn-text-muted)">(filtered)</span>
|
|
23
24
|
<% end %>
|
|
@@ -35,7 +36,7 @@
|
|
|
35
36
|
</div>
|
|
36
37
|
</div>
|
|
37
38
|
|
|
38
|
-
<div class="
|
|
39
|
+
<div class="rn-exceptions-toolbar-actions">
|
|
39
40
|
<%# Keyboard hint %>
|
|
40
41
|
<span class="text-xs flex items-center gap-1" style="color: var(--rn-text-muted)">
|
|
41
42
|
<span class="rn-kbd">?</span> shortcuts
|
|
@@ -54,6 +55,7 @@
|
|
|
54
55
|
<%# ─── Exception Table ────────────────────────────────────── %>
|
|
55
56
|
<div class="rn-table-wrap">
|
|
56
57
|
<table class="rn-table rn-exceptions-table">
|
|
58
|
+
<caption class="sr-only">Logged application exceptions</caption>
|
|
57
59
|
<thead>
|
|
58
60
|
<tr>
|
|
59
61
|
<th class="rn-col-severity"><span class="sr-only">Severity</span></th>
|
|
@@ -79,24 +81,23 @@
|
|
|
79
81
|
<% @exceptions.each_with_index do |exception, index| %>
|
|
80
82
|
<tr id="<%= dom_id(exception) %>"
|
|
81
83
|
class="group"
|
|
82
|
-
|
|
83
|
-
|
|
84
|
+
tabindex="0"
|
|
85
|
+
aria-label="View <%= exception.exception_class %>: <%= exception.message.presence || 'No message' %>"
|
|
86
|
+
data-action="click->rails_nexus#selectRow keydown.enter->rails_nexus#selectRow keydown.space->rails_nexus#selectRow"
|
|
84
87
|
data-url="<%= logged_exception_path(exception) %>"
|
|
85
88
|
data-index="<%= index %>"
|
|
86
89
|
data-rails_nexus-index-param="<%= index %>">
|
|
87
90
|
|
|
88
91
|
<%# Severity indicator dot %>
|
|
89
|
-
<td>
|
|
90
|
-
<span class="rn-
|
|
91
|
-
style="background: var(--rn-<%= severity_for(exception) %>-light); color: var(--rn-<%= severity_for(exception) %>); width: 0.5rem; height: 0.5rem; min-width: 0; padding: 0; border-radius: 50%">
|
|
92
|
-
</span>
|
|
92
|
+
<td class="rn-col-severity">
|
|
93
|
+
<span class="rn-severity-dot rn-severity-<%= severity_for(exception) %>" aria-hidden="true"></span>
|
|
93
94
|
</td>
|
|
94
95
|
|
|
95
96
|
<%# Exception class with severity badge %>
|
|
96
97
|
<td class="rn-col-exception">
|
|
97
|
-
<span class="rn-
|
|
98
|
+
<span class="rn-exception-name" title="<%= exception.exception_class %>"><%= exception.exception_class %></span>
|
|
98
99
|
<% if exception.respond_to?(:fingerprint) && exception.fingerprint.present? %>
|
|
99
|
-
<span class="rn-row-meta rn-mono" title="Fingerprint"
|
|
100
|
+
<span class="rn-row-meta rn-mono" title="Fingerprint <%= exception.fingerprint %>">#<%= exception.fingerprint.first(10) %></span>
|
|
100
101
|
<% end %>
|
|
101
102
|
</td>
|
|
102
103
|
|
|
@@ -128,7 +129,7 @@
|
|
|
128
129
|
|
|
129
130
|
<%# Occurrence count %>
|
|
130
131
|
<td class="rn-col-count">
|
|
131
|
-
<span class="rn-
|
|
132
|
+
<span class="rn-occurrence-count" title="<%= pluralize(exception_occurrence_count(exception), 'occurrence') %>"><%= number_with_delimiter(exception_occurrence_count(exception)) %></span>
|
|
132
133
|
</td>
|
|
133
134
|
|
|
134
135
|
<%# Workflow indicators %>
|
|
@@ -148,11 +149,11 @@
|
|
|
148
149
|
</td>
|
|
149
150
|
|
|
150
151
|
<%# Time (relative) %>
|
|
151
|
-
<td class="rn-date"><%= pretty_exception_date(exception) %></td>
|
|
152
|
+
<td class="rn-col-time rn-date"><%= pretty_exception_date(exception) %></td>
|
|
152
153
|
|
|
153
154
|
<%# Actions (delete on hover) %>
|
|
154
155
|
<td class="rn-col-actions" style="text-align: right">
|
|
155
|
-
<div class="
|
|
156
|
+
<div class="rn-row-actions">
|
|
156
157
|
<%= link_to logged_exception_path(exception),
|
|
157
158
|
class: "rn-icon-btn",
|
|
158
159
|
style: "color: var(--rn-text-muted)",
|
|
@@ -272,11 +272,11 @@
|
|
|
272
272
|
|
|
273
273
|
<%# ─── Keyboard Shortcuts Dialog ───────────────────────────── %>
|
|
274
274
|
<% if RailsNexus.configuration.keyboard_shortcuts %>
|
|
275
|
-
<div class="rn-shortcuts-overlay" data-rails_nexus-target="shortcutsDialog">
|
|
275
|
+
<div class="rn-shortcuts-overlay" data-rails_nexus-target="shortcutsDialog" role="dialog" aria-modal="true" aria-labelledby="rn-shortcuts-title">
|
|
276
276
|
<div class="rn-shortcuts">
|
|
277
277
|
<div class="flex items-center justify-between mb-4">
|
|
278
|
-
<h3>Keyboard Shortcuts</h3>
|
|
279
|
-
<button type="button" class="rn-icon-btn" data-action="click->rails_nexus#closeShortcuts">
|
|
278
|
+
<h3 id="rn-shortcuts-title">Keyboard Shortcuts</h3>
|
|
279
|
+
<button type="button" class="rn-icon-btn" data-action="click->rails_nexus#closeShortcuts" aria-label="Close keyboard shortcuts">
|
|
280
280
|
<svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" /></svg>
|
|
281
281
|
</button>
|
|
282
282
|
</div>
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# ════════════════════════════════════════════════════════════════════
|
|
4
|
+
# Backup Config Seed — Migrated from ~/Backup gem models
|
|
5
|
+
#
|
|
6
|
+
# Run with:
|
|
7
|
+
# rails runner db/seeds/backup_configs.rb
|
|
8
|
+
#
|
|
9
|
+
# Or from the engine:
|
|
10
|
+
# rails_nexus:seed_backups rake task
|
|
11
|
+
# ════════════════════════════════════════════════════════════════════
|
|
12
|
+
|
|
13
|
+
configs = [
|
|
14
|
+
{
|
|
15
|
+
name: "tti_daily_backup",
|
|
16
|
+
description: "TTI Daily MySQL Backup — skip sessions, versions, logged_exceptions",
|
|
17
|
+
adapter: "mysql",
|
|
18
|
+
database_name: "tti_erp",
|
|
19
|
+
host: "localhost",
|
|
20
|
+
port: 3306,
|
|
21
|
+
username: "root",
|
|
22
|
+
# password: "36B042D8948C4086F37FA@root", # stored in mysql-config/cnf — set via env or UI
|
|
23
|
+
skip_tables: "tti_erp.logged_exceptions,tti_erp.sessions,tti_erp.versions",
|
|
24
|
+
|
|
25
|
+
storage_path: "~/dumps",
|
|
26
|
+
keep_count: 365,
|
|
27
|
+
|
|
28
|
+
compress: true,
|
|
29
|
+
bzip2_compress: false,
|
|
30
|
+
encrypted: true,
|
|
31
|
+
encryption_password: "12upo12e064a3",
|
|
32
|
+
gpg_enabled: false,
|
|
33
|
+
|
|
34
|
+
rsync_enabled: true,
|
|
35
|
+
rsync_host: "172.16.1.232",
|
|
36
|
+
rsync_port: 22,
|
|
37
|
+
rsync_user: "estudent",
|
|
38
|
+
rsync_path: "tti_backups",
|
|
39
|
+
rsync_mirror: false,
|
|
40
|
+
|
|
41
|
+
s3_enabled: false,
|
|
42
|
+
|
|
43
|
+
archive_enabled: false,
|
|
44
|
+
|
|
45
|
+
notify_command: "bk-send",
|
|
46
|
+
notify_on_success: true,
|
|
47
|
+
notify_on_failure: true,
|
|
48
|
+
email_notify: false,
|
|
49
|
+
|
|
50
|
+
schedule_cron: "0 2 * * *", # daily at 2am
|
|
51
|
+
enabled: true
|
|
52
|
+
},
|
|
53
|
+
|
|
54
|
+
{
|
|
55
|
+
name: "tti_full_backup",
|
|
56
|
+
description: "TTI Full MySQL Backup — all tables, no skip",
|
|
57
|
+
adapter: "mysql",
|
|
58
|
+
database_name: "tti_erp",
|
|
59
|
+
host: "localhost",
|
|
60
|
+
port: 3306,
|
|
61
|
+
username: "root",
|
|
62
|
+
skip_tables: "",
|
|
63
|
+
|
|
64
|
+
storage_path: "~/dumps",
|
|
65
|
+
keep_count: 10,
|
|
66
|
+
|
|
67
|
+
compress: true,
|
|
68
|
+
bzip2_compress: false,
|
|
69
|
+
encrypted: true,
|
|
70
|
+
encryption_password: "12upo12e064a3",
|
|
71
|
+
gpg_enabled: false,
|
|
72
|
+
|
|
73
|
+
rsync_enabled: false,
|
|
74
|
+
|
|
75
|
+
s3_enabled: false,
|
|
76
|
+
|
|
77
|
+
archive_enabled: false,
|
|
78
|
+
|
|
79
|
+
notify_command: "bk-send",
|
|
80
|
+
notify_on_success: true,
|
|
81
|
+
notify_on_failure: true,
|
|
82
|
+
email_notify: false,
|
|
83
|
+
|
|
84
|
+
schedule_cron: "0 0 * * 0", # weekly Sunday at midnight
|
|
85
|
+
enabled: true
|
|
86
|
+
},
|
|
87
|
+
|
|
88
|
+
{
|
|
89
|
+
name: "tti_sync_backup",
|
|
90
|
+
description: "TTI Sync — MySQL dump + RSync push to remote server",
|
|
91
|
+
adapter: "mysql",
|
|
92
|
+
database_name: "tti_erp",
|
|
93
|
+
host: "localhost",
|
|
94
|
+
port: 3306,
|
|
95
|
+
username: "root",
|
|
96
|
+
skip_tables: "tti_erp.logged_exceptions,tti_erp.sessions,tti_erp.versions",
|
|
97
|
+
|
|
98
|
+
storage_path: "~/dumps/sync",
|
|
99
|
+
keep_count: 1,
|
|
100
|
+
|
|
101
|
+
compress: true,
|
|
102
|
+
bzip2_compress: false,
|
|
103
|
+
encrypted: false,
|
|
104
|
+
|
|
105
|
+
rsync_enabled: true,
|
|
106
|
+
rsync_host: "198.199.121.213",
|
|
107
|
+
rsync_port: 22,
|
|
108
|
+
rsync_user: "winner2",
|
|
109
|
+
rsync_path: "dumps/tti",
|
|
110
|
+
rsync_mirror: false,
|
|
111
|
+
|
|
112
|
+
s3_enabled: false,
|
|
113
|
+
|
|
114
|
+
archive_enabled: false,
|
|
115
|
+
|
|
116
|
+
notify_command: "bk-send",
|
|
117
|
+
notify_on_success: true,
|
|
118
|
+
notify_on_failure: true,
|
|
119
|
+
email_notify: false,
|
|
120
|
+
|
|
121
|
+
schedule_cron: "0 3 * * *", # daily at 3am
|
|
122
|
+
enabled: true
|
|
123
|
+
}
|
|
124
|
+
]
|
|
125
|
+
|
|
126
|
+
puts "Seeding #{configs.size} backup configs..."
|
|
127
|
+
|
|
128
|
+
configs.each do |attrs|
|
|
129
|
+
config = RailsNexus::BackupConfig.find_or_initialize_by(name: attrs[:name])
|
|
130
|
+
config.assign_attributes(attrs)
|
|
131
|
+
|
|
132
|
+
if config.save
|
|
133
|
+
puts " ✓ #{config.name} (#{config.adapter}/#{config.database_name})"
|
|
134
|
+
else
|
|
135
|
+
puts " ✗ #{config.name}: #{config.errors.full_messages.join(', ')}"
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
puts "Done. #{RailsNexus::BackupConfig.count} configs total."
|
|
@@ -128,5 +128,64 @@ class CreateRailsNexusTables < ActiveRecord::Migration[<%= "[#{ActiveRecord::Mig
|
|
|
128
128
|
add_index :rails_nexus_backups, [:model_name, :started_at]
|
|
129
129
|
add_index :rails_nexus_backups, :status
|
|
130
130
|
add_index :rails_nexus_backups, :started_at
|
|
131
|
+
|
|
132
|
+
# ─── rails_nexus_backup_configs ────────────────────────────────
|
|
133
|
+
create_table :rails_nexus_backup_configs do |t|
|
|
134
|
+
t.string :name, null: false
|
|
135
|
+
t.string :description
|
|
136
|
+
t.string :database_name, null: false
|
|
137
|
+
t.string :adapter, null: false, default: "mysql"
|
|
138
|
+
t.string :host, default: "localhost"
|
|
139
|
+
t.integer :port
|
|
140
|
+
t.string :username
|
|
141
|
+
t.string :password
|
|
142
|
+
t.string :skip_tables
|
|
143
|
+
|
|
144
|
+
t.string :storage_path, null: false
|
|
145
|
+
t.integer :keep_count, default: 30
|
|
146
|
+
|
|
147
|
+
t.boolean :compress, default: true
|
|
148
|
+
t.boolean :bzip2_compress, default: false
|
|
149
|
+
t.boolean :encrypted, default: false
|
|
150
|
+
t.string :encryption_password
|
|
151
|
+
t.boolean :gpg_enabled, default: false
|
|
152
|
+
t.string :gpg_password
|
|
153
|
+
|
|
154
|
+
t.boolean :rsync_enabled, default: false
|
|
155
|
+
t.string :rsync_host
|
|
156
|
+
t.integer :rsync_port, default: 22
|
|
157
|
+
t.string :rsync_user
|
|
158
|
+
t.string :rsync_path
|
|
159
|
+
t.boolean :rsync_mirror, default: false
|
|
160
|
+
|
|
161
|
+
# S3 storage
|
|
162
|
+
t.boolean :s3_enabled, default: false
|
|
163
|
+
t.string :s3_access_key
|
|
164
|
+
t.string :s3_secret_key
|
|
165
|
+
t.string :s3_bucket
|
|
166
|
+
t.string :s3_region, default: "us-east-1"
|
|
167
|
+
t.string :s3_prefix
|
|
168
|
+
|
|
169
|
+
# Archives (file/dir backup)
|
|
170
|
+
t.boolean :archive_enabled, default: false
|
|
171
|
+
t.string :archive_paths
|
|
172
|
+
t.string :archive_excludes
|
|
173
|
+
t.boolean :split_chunks, default: false
|
|
174
|
+
|
|
175
|
+
# Notifications
|
|
176
|
+
t.string :notify_command
|
|
177
|
+
t.boolean :notify_on_success, default: true
|
|
178
|
+
t.boolean :notify_on_failure, default: true
|
|
179
|
+
t.boolean :email_notify, default: false
|
|
180
|
+
t.string :email_to
|
|
181
|
+
|
|
182
|
+
t.string :schedule_cron
|
|
183
|
+
t.boolean :enabled, default: true
|
|
184
|
+
|
|
185
|
+
t.timestamps
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
add_index :rails_nexus_backup_configs, :name, unique: true
|
|
189
|
+
add_index :rails_nexus_backup_configs, :enabled
|
|
131
190
|
end
|
|
132
191
|
end
|
data/lib/rails_nexus/version.rb
CHANGED
data/lib/tasks/rails_nexus.rake
CHANGED
|
@@ -298,4 +298,14 @@ namespace :rails_nexus do
|
|
|
298
298
|
end
|
|
299
299
|
end
|
|
300
300
|
end
|
|
301
|
+
|
|
302
|
+
desc "Seed backup configs from ~/Backup gem models"
|
|
303
|
+
task seed_backups: :environment do
|
|
304
|
+
seed_file = File.join(RailsNexus::Engine.root, "db", "seeds", "backup_configs.rb")
|
|
305
|
+
if File.exist?(seed_file)
|
|
306
|
+
load seed_file
|
|
307
|
+
else
|
|
308
|
+
puts "Seed file not found: #{seed_file}"
|
|
309
|
+
end
|
|
310
|
+
end
|
|
301
311
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rails_nexus
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.0.
|
|
4
|
+
version: 2.0.6
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Tamiru Hailu
|
|
@@ -148,6 +148,7 @@ files:
|
|
|
148
148
|
- app/models/rails_nexus/webhook_delivery.rb
|
|
149
149
|
- app/services/rails_nexus/backup_runner.rb
|
|
150
150
|
- app/services/rails_nexus/backup_service.rb
|
|
151
|
+
- app/views/layouts/rails_nexus/_sidebar_navigation.html.erb
|
|
151
152
|
- app/views/layouts/rails_nexus/application.html.erb
|
|
152
153
|
- app/views/rails_nexus/analytics/index.html.erb
|
|
153
154
|
- app/views/rails_nexus/backup/_form.html.erb
|
|
@@ -180,6 +181,7 @@ files:
|
|
|
180
181
|
- config/initializers/date_formats.rb
|
|
181
182
|
- config/locales/en.yml
|
|
182
183
|
- config/routes.rb
|
|
184
|
+
- db/seeds/backup_configs.rb
|
|
183
185
|
- lib/generators/rails_nexus/backup_generator.rb
|
|
184
186
|
- lib/generators/rails_nexus/customize_generator.rb
|
|
185
187
|
- lib/generators/rails_nexus/install_generator.rb
|