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.
@@ -14,10 +14,11 @@
14
14
  </div>
15
15
  <% else %>
16
16
  <%# ─── Table Header Bar ───────────────────────────────────── %>
17
- <div class="px-4 py-2.5 flex items-center justify-between" style="background: var(--rn-bg-secondary); border-bottom: 1px solid var(--rn-border-light)">
18
- <div class="flex items-center gap-3">
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> exceptions
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="flex items-center gap-2">
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
- style="cursor: pointer; position: relative"
83
- data-action="click->rails_nexus#selectRow"
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-count-indicator rn-badge-<%= severity_for(exception) %>"
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-badge rn-badge-<%= severity_for(exception) %> rn-exception-name" title="<%= exception.exception_class %>"><%= exception.exception_class %></span>
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"><%= exception.fingerprint.first(10) %></span>
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-badge rn-badge-muted"><%= number_with_delimiter(exception_occurrence_count(exception)) %></span>
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="flex items-center justify-end gap-1 opacity-0 group-hover:opacity-100 transition-opacity">
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
@@ -1,3 +1,3 @@
1
1
  module RailsNexus
2
- VERSION = "2.0.2"
2
+ VERSION = "2.0.6"
3
3
  end
@@ -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.2
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