rails_nexus 2.0.3 → 2.1.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.
@@ -0,0 +1,113 @@
1
+ <nav class="rn-sidebar-nav" aria-label="RailsNexus navigation">
2
+ <details class="rn-nav-section" data-action="toggle->rails_nexus-sidebar#closeOtherMenus" <%= "open" if monitor_menu_active %>>
3
+ <summary class="rn-nav-section-toggle">
4
+ <span class="rn-nav-section-title">
5
+ <span class="rn-nav-section-icon"><svg width="15" height="15" fill="none" viewBox="0 0 24 24" stroke-width="1.75" stroke="currentColor" aria-hidden="true"><path stroke-linecap="round" stroke-linejoin="round" d="M3 12h3l2.25-6 4.5 12 2.25-6H21" /></svg></span>
6
+ <span>Monitor</span>
7
+ </span>
8
+ <svg class="rn-nav-section-chevron" width="14" height="14" fill="none" viewBox="0 0 24 24" stroke-width="1.75" stroke="currentColor" aria-hidden="true"><path stroke-linecap="round" stroke-linejoin="round" d="M8.25 4.5l7.5 7.5-7.5 7.5" /></svg>
9
+ </summary>
10
+ <div class="rn-nav-section-items">
11
+
12
+ <%= link_to root_path,
13
+ class: "rn-nav-item #{request.path == rails_nexus.root_path ? 'active' : ''}" do %>
14
+ <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 9v3.75m9-3.75v6.75A2.25 2.25 0 0118.75 18H5.25A2.25 2.25 0 013 15.75V9m18 0l-9-6-9 6m18 0l-9 6-9-6" /></svg>
15
+ Exceptions
16
+ <% if exception_count > 0 %>
17
+ <span class="rn-nav-badge"><%= number_with_delimiter(exception_count) %></span>
18
+ <% end %>
19
+ <% end %>
20
+
21
+ <%= link_to database_health_path,
22
+ class: "rn-nav-item #{request.path == rails_nexus.database_health_path ? 'active' : ''}" do %>
23
+ <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="M20.25 6.375c0 2.278-3.694 4.125-8.25 4.125S3.75 8.653 3.75 6.375m16.5 0c0-2.278-3.694-4.125-8.25-4.125S3.75 4.097 3.75 6.375m16.5 0v11.25c0 2.278-3.694 4.125-8.25 4.125s-8.25-1.847-8.25-4.125V6.375m16.5 0v3.75m-16.5-3.75v3.75m16.5 0v3.75C20.25 16.153 16.556 18 12 18s-8.25-1.847-8.25-4.125v-3.75m16.5 0c0 2.278-3.694 4.125-8.25 4.125s-8.25-1.847-8.25-4.125" /></svg>
24
+ Database Health
25
+ <% end %>
26
+
27
+ <%= link_to n1_patterns_path,
28
+ class: "rn-nav-item #{request.path == rails_nexus.n1_patterns_path ? 'active' : ''}" do %>
29
+ <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 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z" /></svg>
30
+ N+1 Queries
31
+ <% end %>
32
+
33
+ <%= link_to analytics_path,
34
+ class: "rn-nav-item #{request.path == rails_nexus.analytics_path ? 'active' : ''}" do %>
35
+ <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 3v11.25A2.25 2.25 0 006 16.5h2.25M3.75 3h-1.5m1.5 0h16.5m0 0h1.5m-1.5 0v11.25A2.25 2.25 0 0118 16.5h-2.25m-7.5 0h7.5m-7.5 0l-1 3m8.5-3l1 3m0 0l.5 1.5m-.5-1.5h-9.5m0 0l-.5 1.5" /></svg>
36
+ Analytics
37
+ <% end %>
38
+
39
+ <%= link_to stats_path,
40
+ class: "rn-nav-item #{request.path == rails_nexus.stats_path ? 'active' : ''}" do %>
41
+ <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 13.125C3 12.504 3.504 12 4.125 12h2.25c.621 0 1.125.504 1.125 1.125v6.75C7.5 20.496 6.996 21 6.375 21h-2.25A1.125 1.125 0 013 19.875v-6.75zM9.75 8.625c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125v11.25c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 01-1.125-1.125V8.625zM16.5 4.125c0-.621.504-1.125 1.125-1.125h2.25C20.496 3 21 3.504 21 4.125v15.75c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 01-1.125-1.125V4.125z" /></svg>
42
+ Statistics
43
+ <% end %>
44
+ </div>
45
+ </details>
46
+
47
+ <details class="rn-nav-section" data-action="toggle->rails_nexus-sidebar#closeOtherMenus" <%= "open" if operations_menu_active %>>
48
+ <summary class="rn-nav-section-toggle">
49
+ <span class="rn-nav-section-title">
50
+ <span class="rn-nav-section-icon"><svg width="15" height="15" fill="none" viewBox="0 0 24 24" stroke-width="1.75" stroke="currentColor" aria-hidden="true"><path stroke-linecap="round" stroke-linejoin="round" d="M4.5 6.75h15M7.5 12h9m-6 5.25h3" /></svg></span>
51
+ <span>Operations</span>
52
+ </span>
53
+ <svg class="rn-nav-section-chevron" width="14" height="14" fill="none" viewBox="0 0 24 24" stroke-width="1.75" stroke="currentColor" aria-hidden="true"><path stroke-linecap="round" stroke-linejoin="round" d="M8.25 4.5l7.5 7.5-7.5 7.5" /></svg>
54
+ </summary>
55
+ <div class="rn-nav-section-items">
56
+
57
+ <%= link_to cron_jobs_path,
58
+ class: "rn-nav-item #{request.path.start_with?(rails_nexus.cron_jobs_path) ? 'active' : ''}" do %>
59
+ <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 6v6h4.5m4.5 0a9 9 0 11-18 0 9 9 0 0118 0z" /></svg>
60
+ Cron Jobs
61
+ <% end %>
62
+
63
+ <%= link_to backup_path,
64
+ class: "rn-nav-item #{controller_path == 'rails_nexus/backup' && !%w[all_history history].include?(action_name) ? 'active' : ''}" do %>
65
+ <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="M20.25 6.375c0 2.278-3.694 4.125-8.25 4.125S3.75 8.653 3.75 6.375m16.5 0c0-2.278-3.694-4.125-8.25-4.125S3.75 4.097 3.75 6.375m16.5 0v11.25c0 2.278-3.694 4.125-8.25 4.125s-8.25-1.847-8.25-4.125V6.375m16.5 0v3.75m-16.5-3.75v3.75m16.5 0v3.75C20.25 16.153 16.556 18 12 18s-8.25-1.847-8.25-4.125v-3.75m16.5 0c0 2.278-3.694 4.125-8.25 4.125s-8.25-1.847-8.25-4.125" /></svg>
66
+ Backups
67
+ <% end %>
68
+
69
+ <%= link_to backup_history_path,
70
+ class: "rn-nav-item #{controller_path == 'rails_nexus/backup' && %w[all_history history].include?(action_name) ? 'active' : ''}" do %>
71
+ <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 6v6h4.5m4.5 0a9 9 0 11-18 0 9 9 0 0118 0z" /></svg>
72
+ Backup History
73
+ <% end %>
74
+
75
+ <%= link_to settings_path,
76
+ class: "rn-nav-item #{request.path == rails_nexus.settings_path ? 'active' : ''}" do %>
77
+ <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="M9.594 3.94c.09-.542.56-.94 1.11-.94h2.593c.55 0 1.02.398 1.11.94l.213 1.281c.063.374.313.686.645.87.074.04.147.083.22.127.324.196.72.257 1.075.124l1.217-.456a1.125 1.125 0 011.37.49l1.296 2.247a1.125 1.125 0 01-.26 1.431l-1.003.827c-.293.24-.438.613-.431.992a6.759 6.759 0 010 .255c-.007.378.138.75.43.99l1.005.828c.424.35.534.954.26 1.43l-1.298 2.247a1.125 1.125 0 01-1.369.491l-1.217-.456c-.355-.133-.75-.072-1.076.124a6.57 6.57 0 01-.22.128c-.331.183-.581.495-.644.869l-.213 1.28c-.09.543-.56.941-1.11.941h-2.594c-.55 0-1.02-.398-1.11-.94l-.213-1.281c-.062-.374-.312-.686-.644-.87a6.52 6.52 0 01-.22-.127c-.325-.196-.72-.257-1.076-.124l-1.217.456a1.125 1.125 0 01-1.369-.49l-1.297-2.247a1.125 1.125 0 01.26-1.431l1.004-.827c.292-.24.437-.613.43-.992a6.932 6.932 0 010-.255c.007-.378-.138-.75-.43-.99l-1.004-.828a1.125 1.125 0 01-.26-1.43l1.297-2.247a1.125 1.125 0 011.37-.491l1.216.456c.356.133.751.072 1.076-.124.072-.044.146-.087.22-.128.332-.183.582-.495.644-.869l.214-1.281z" /><path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" /></svg>
78
+ Settings
79
+ <% end %>
80
+ </div>
81
+ </details>
82
+
83
+ <details class="rn-nav-section" data-action="toggle->rails_nexus-sidebar#closeOtherMenus" <%= "open" if resources_menu_active %>>
84
+ <summary class="rn-nav-section-toggle">
85
+ <span class="rn-nav-section-title">
86
+ <span class="rn-nav-section-icon"><svg width="15" height="15" fill="none" viewBox="0 0 24 24" stroke-width="1.75" stroke="currentColor" aria-hidden="true"><path stroke-linecap="round" stroke-linejoin="round" d="M10.5 6H6.75A3.75 3.75 0 003 9.75v7.5A3.75 3.75 0 006.75 21h7.5A3.75 3.75 0 0018 17.25V13.5m-6-1.5L21 3m0 0h-5.25M21 3v5.25" /></svg></span>
87
+ <span>Resources</span>
88
+ </span>
89
+ <svg class="rn-nav-section-chevron" width="14" height="14" fill="none" viewBox="0 0 24 24" stroke-width="1.75" stroke="currentColor" aria-hidden="true"><path stroke-linecap="round" stroke-linejoin="round" d="M8.25 4.5l7.5 7.5-7.5 7.5" /></svg>
90
+ </summary>
91
+ <div class="rn-nav-section-items">
92
+
93
+ <% if main_app.respond_to?(:root_path) %>
94
+ <%= link_to main_app.root_path, class: "rn-nav-item rn-nav-item--muted" do %>
95
+ <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>
96
+ Back to App
97
+ <% end %>
98
+ <% end %>
99
+
100
+ <%= link_to feed_logged_exceptions_path(format: :rss), class: "rn-nav-item rn-nav-item--muted" do %>
101
+ <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>
102
+ RSS Feed
103
+ <% end %>
104
+
105
+ <% RailsNexus.configuration.sidebar_links.each do |link| %>
106
+ <%= link_to link[:url], class: "rn-nav-item", target: link[:target] || "_self" do %>
107
+ <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>
108
+ <%= link[:label] %>
109
+ <% end %>
110
+ <% end %>
111
+ </div>
112
+ </details>
113
+ </nav>
@@ -4,6 +4,7 @@
4
4
  <meta charset="utf-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1">
6
6
  <meta name="color-scheme" content="light dark">
7
+ <meta name="turbo-prefetch" content="false">
7
8
  <title><%= content_for?(:title) ? yield(:title) : RailsNexus.configuration.application_name || "RailsNexus" %></title>
8
9
 
9
10
  <%= stylesheet_link_tag "rails_nexus/application", "data-turbo-track": "reload" %>
@@ -16,25 +17,53 @@
16
17
  <%= csrf_meta_tags %>
17
18
  <%= csp_meta_tag %>
18
19
  </head>
19
- <body class="h-full <%= RailsNexus.configuration.body_class %>">
20
+ <%
21
+ exception_count = RailsNexus::LoggedException.count
22
+ monitor_menu_active = %w[
23
+ rails_nexus/logged_exceptions rails_nexus/database_health rails_nexus/n1_patterns
24
+ rails_nexus/analytics rails_nexus/stats
25
+ ].include?(controller_path)
26
+ operations_menu_active = %w[
27
+ rails_nexus/cron_jobs rails_nexus/backup rails_nexus/settings
28
+ ].include?(controller_path)
29
+ resources_menu_active = RailsNexus.configuration.sidebar_links.any? do |link|
30
+ link[:url].to_s == request.path
31
+ end
32
+ %>
33
+ <body class="h-full <%= RailsNexus.configuration.body_class %>" data-controller="rails_nexus-sidebar">
20
34
  <div class="min-h-full flex">
21
35
 
22
36
  <%# Sidebar %>
23
- <aside class="rn-sidebar">
37
+ <aside id="rn-desktop-sidebar" class="rn-sidebar" data-rails_nexus-sidebar-target="sidebar">
24
38
  <%# Logo %>
25
39
  <div class="rn-sidebar-logo">
26
40
  <%= link_to root_path, class: "flex items-center gap-2.5" do %>
27
41
  <div class="rn-logo-icon">⚡</div>
28
- <span class="rn-logo-text"><%= RailsNexus.configuration.application_name || "RailsNexus" %></span>
42
+ <span class="rn-logo-copy">
43
+ <span class="rn-logo-text"><%= RailsNexus.configuration.application_name || "RailsNexus" %></span>
44
+ <span class="rn-logo-subtitle">Rails operations</span>
45
+ </span>
29
46
  <% end %>
30
47
  </div>
31
48
 
32
49
  <%# Navigation %>
33
- <nav class="rn-sidebar-nav">
50
+ <nav class="rn-sidebar-nav" aria-label="RailsNexus navigation">
51
+ <details class="rn-nav-section" data-action="toggle->rails_nexus-sidebar#closeOtherMenus" <%= "open" if monitor_menu_active %>>
52
+ <summary class="rn-nav-section-toggle">
53
+ <span class="rn-nav-section-title">
54
+ <span class="rn-nav-section-icon"><svg width="15" height="15" fill="none" viewBox="0 0 24 24" stroke-width="1.75" stroke="currentColor" aria-hidden="true"><path stroke-linecap="round" stroke-linejoin="round" d="M3 12h3l2.25-6 4.5 12 2.25-6H21" /></svg></span>
55
+ <span>Monitor</span>
56
+ </span>
57
+ <svg class="rn-nav-section-chevron" width="14" height="14" fill="none" viewBox="0 0 24 24" stroke-width="1.75" stroke="currentColor" aria-hidden="true"><path stroke-linecap="round" stroke-linejoin="round" d="M8.25 4.5l7.5 7.5-7.5 7.5" /></svg>
58
+ </summary>
59
+ <div class="rn-nav-section-items">
34
60
  <%= link_to root_path,
35
61
  class: "rn-nav-item #{request.path == rails_nexus.root_path ? 'active' : ''}" do %>
36
62
  <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>
37
- Dashboard
63
+ Exceptions
64
+ <% if exception_count > 0 %>
65
+ <span class="rn-nav-badge"><%= number_with_delimiter(exception_count) %></span>
66
+ <% end %>
38
67
  <% end %>
39
68
 
40
69
  <%= link_to database_health_path,
@@ -61,6 +90,19 @@
61
90
  Statistics
62
91
  <% end %>
63
92
 
93
+ </div>
94
+ </details>
95
+
96
+ <details class="rn-nav-section" data-action="toggle->rails_nexus-sidebar#closeOtherMenus" <%= "open" if operations_menu_active %>>
97
+ <summary class="rn-nav-section-toggle">
98
+ <span class="rn-nav-section-title">
99
+ <span class="rn-nav-section-icon"><svg width="15" height="15" fill="none" viewBox="0 0 24 24" stroke-width="1.75" stroke="currentColor" aria-hidden="true"><path stroke-linecap="round" stroke-linejoin="round" d="M4.5 6.75h15M7.5 12h9m-6 5.25h3" /></svg></span>
100
+ <span>Operations</span>
101
+ </span>
102
+ <svg class="rn-nav-section-chevron" width="14" height="14" fill="none" viewBox="0 0 24 24" stroke-width="1.75" stroke="currentColor" aria-hidden="true"><path stroke-linecap="round" stroke-linejoin="round" d="M8.25 4.5l7.5 7.5-7.5 7.5" /></svg>
103
+ </summary>
104
+ <div class="rn-nav-section-items">
105
+
64
106
  <%= link_to cron_jobs_path,
65
107
  class: "rn-nav-item #{request.path.start_with?(rails_nexus.cron_jobs_path) ? 'active' : ''}" do %>
66
108
  <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 6v6h4.5m4.5 0a9 9 0 11-18 0 9 9 0 0118 0z" /></svg>
@@ -68,19 +110,35 @@
68
110
  <% end %>
69
111
 
70
112
  <%= link_to backup_path,
71
- class: "rn-nav-item #{request.path.start_with?(rails_nexus.backup_path) ? 'active' : ''}" do %>
113
+ class: "rn-nav-item #{controller_path == 'rails_nexus/backup' && !%w[all_history history].include?(action_name) ? 'active' : ''}" do %>
72
114
  <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="M20.25 6.375c0 2.278-3.694 4.125-8.25 4.125S3.75 8.653 3.75 6.375m16.5 0c0-2.278-3.694-4.125-8.25-4.125S3.75 4.097 3.75 6.375m16.5 0v11.25c0 2.278-3.694 4.125-8.25 4.125s-8.25-1.847-8.25-4.125V6.375m16.5 0v3.75m-16.5-3.75v3.75m16.5 0v3.75C20.25 16.153 16.556 18 12 18s-8.25-1.847-8.25-4.125v-3.75m16.5 0c0 2.278-3.694 4.125-8.25 4.125s-8.25-1.847-8.25-4.125" /></svg>
73
115
  Backups
74
116
  <% end %>
75
117
 
118
+ <%= link_to backup_history_path,
119
+ class: "rn-nav-item #{controller_path == 'rails_nexus/backup' && %w[all_history history].include?(action_name) ? 'active' : ''}" do %>
120
+ <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 6v6h4.5m4.5 0a9 9 0 11-18 0 9 9 0 0118 0z" /></svg>
121
+ Backup History
122
+ <% end %>
123
+
76
124
  <%= link_to settings_path,
77
125
  class: "rn-nav-item #{request.path == rails_nexus.settings_path ? 'active' : ''}" do %>
78
126
  <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="M9.594 3.94c.09-.542.56-.94 1.11-.94h2.593c.55 0 1.02.398 1.11.94l.213 1.281c.063.374.313.686.645.87.074.04.147.083.22.127.324.196.72.257 1.075.124l1.217-.456a1.125 1.125 0 011.37.49l1.296 2.247a1.125 1.125 0 01-.26 1.431l-1.003.827c-.293.24-.438.613-.431.992a6.759 6.759 0 010 .255c-.007.378.138.75.43.99l1.005.828c.424.35.534.954.26 1.43l-1.298 2.247a1.125 1.125 0 01-1.369.491l-1.217-.456c-.355-.133-.75-.072-1.076.124a6.57 6.57 0 01-.22.128c-.331.183-.581.495-.644.869l-.213 1.28c-.09.543-.56.941-1.11.941h-2.594c-.55 0-1.02-.398-1.11-.94l-.213-1.281c-.062-.374-.312-.686-.644-.87a6.52 6.52 0 01-.22-.127c-.325-.196-.72-.257-1.076-.124l-1.217.456a1.125 1.125 0 01-1.369-.49l-1.297-2.247a1.125 1.125 0 01.26-1.431l1.004-.827c.292-.24.437-.613.43-.992a6.932 6.932 0 010-.255c.007-.378-.138-.75-.43-.99l-1.004-.828a1.125 1.125 0 01-.26-1.43l1.297-2.247a1.125 1.125 0 011.37-.491l1.216.456c.356.133.751.072 1.076-.124.072-.044.146-.087.22-.128.332-.183.582-.495.644-.869l.214-1.281z" /><path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" /></svg>
79
127
  Settings
80
128
  <% end %>
81
129
 
82
- <%# ─── Tools section ──────────────────────────────────────── %>
83
- <div class="rn-sidebar-section-divider"></div>
130
+ </div>
131
+ </details>
132
+
133
+ <details class="rn-nav-section" data-action="toggle->rails_nexus-sidebar#closeOtherMenus" <%= "open" if resources_menu_active %>>
134
+ <summary class="rn-nav-section-toggle">
135
+ <span class="rn-nav-section-title">
136
+ <span class="rn-nav-section-icon"><svg width="15" height="15" fill="none" viewBox="0 0 24 24" stroke-width="1.75" stroke="currentColor" aria-hidden="true"><path stroke-linecap="round" stroke-linejoin="round" d="M10.5 6H6.75A3.75 3.75 0 003 9.75v7.5A3.75 3.75 0 006.75 21h7.5A3.75 3.75 0 0018 17.25V13.5m-6-1.5L21 3m0 0h-5.25M21 3v5.25" /></svg></span>
137
+ <span>Resources</span>
138
+ </span>
139
+ <svg class="rn-nav-section-chevron" width="14" height="14" fill="none" viewBox="0 0 24 24" stroke-width="1.75" stroke="currentColor" aria-hidden="true"><path stroke-linecap="round" stroke-linejoin="round" d="M8.25 4.5l7.5 7.5-7.5 7.5" /></svg>
140
+ </summary>
141
+ <div class="rn-nav-section-items">
84
142
 
85
143
  <% if main_app.respond_to?(:root_path) %>
86
144
  <%= link_to main_app.root_path,
@@ -104,11 +162,14 @@
104
162
  <%= link[:label] %>
105
163
  <% end %>
106
164
  <% end %>
165
+ </div>
166
+ </details>
107
167
  </nav>
108
168
 
109
169
  <%# Footer %>
110
170
  <div class="rn-sidebar-footer">
111
- v<%= RailsNexus::VERSION %> · <%= RailsNexus::LoggedException.count %> exceptions
171
+ <span class="rn-sidebar-status"><span class="rn-status-dot"></span>Operational</span>
172
+ <span>v<%= RailsNexus::VERSION %></span>
112
173
  </div>
113
174
  </aside>
114
175
 
@@ -116,19 +177,42 @@
116
177
  <div class="flex-1 flex flex-col min-w-0">
117
178
  <%# Top Bar %>
118
179
  <header class="rn-topbar">
119
- <span class="text-sm font-semibold"><%= RailsNexus.configuration.application_name || "RailsNexus" %></span>
180
+ <div class="rn-topbar-title">
181
+ <button type="button"
182
+ class="rn-icon-btn rn-sidebar-toggle"
183
+ data-action="click->rails_nexus-sidebar#toggle"
184
+ data-rails_nexus-sidebar-target="toggleButton"
185
+ title="Toggle navigation"
186
+ aria-label="Hide navigation"
187
+ aria-controls="rn-desktop-sidebar rn-mobile-sidebar"
188
+ aria-expanded="true">
189
+ <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>
190
+ </button>
191
+ <div>
192
+ <span class="rn-topbar-heading"><%= RailsNexus.configuration.application_name || "RailsNexus" %></span>
193
+ <span class="rn-topbar-subtitle">Operations console</span>
194
+ </div>
195
+ </div>
120
196
 
121
- <div class="flex items-center gap-1.5">
122
- <% if RailsNexus.configuration.keyboard_shortcuts %>
123
- <span class="text-xs flex items-center gap-1" style="color: var(--rn-text-muted)">
124
- <span class="rn-kbd">?</span>
125
- </span>
197
+ <div class="rn-topbar-actions">
198
+ <% if RailsNexus.configuration.keyboard_shortcuts && controller_path == "rails_nexus/logged_exceptions" && action_name == "index" %>
199
+ <button type="button"
200
+ id="rn-shortcuts-button"
201
+ class="rn-icon-btn"
202
+ data-action="click->rails_nexus-sidebar#toggleShortcuts"
203
+ title="Keyboard shortcuts"
204
+ aria-label="Open keyboard shortcuts"
205
+ aria-haspopup="dialog"
206
+ aria-expanded="false">
207
+ <span class="rn-kbd" aria-hidden="true">?</span>
208
+ </button>
126
209
  <% end %>
127
210
 
128
211
  <button type="button"
129
212
  class="rn-icon-btn"
130
213
  data-action="click->rails_nexus-theme#toggle"
131
- title="Toggle theme (t)">
214
+ title="Toggle theme (t)"
215
+ aria-label="Toggle color theme">
132
216
  <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>
133
217
  <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>
134
218
  </button>
@@ -163,9 +247,22 @@
163
247
  <% end %>
164
248
 
165
249
  <%# Main Content %>
166
- <main class="flex-1 overflow-y-auto p-4 sm:p-6">
250
+ <main class="rn-main flex-1 p-4 sm:p-6">
167
251
  <%= yield %>
168
252
  </main>
253
+
254
+ <footer class="rn-footer">
255
+ <span>RailsNexus <span class="rn-footer-version">v<%= RailsNexus::VERSION %></span></span>
256
+ <span class="rn-footer-credit">
257
+ Built by
258
+ <a href="https://github.com/tamiru" target="_blank" rel="noopener noreferrer">Tamiru Hailu</a>
259
+ <span aria-hidden="true">·</span>
260
+ <a href="https://github.com/tamiru/rails_nexus" target="_blank" rel="noopener noreferrer" class="rn-footer-github">
261
+ <svg class="w-4 h-4" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M12 .7A11.3 11.3 0 00.7 12c0 5 3.2 9.2 7.7 10.7.6.1.8-.3.8-.6v-2.2c-3.1.7-3.8-1.3-3.8-1.3-.5-1.3-1.3-1.7-1.3-1.7-1-.7.1-.7.1-.7 1.1.1 1.7 1.2 1.7 1.2 1 1.7 2.6 1.2 3.3.9.1-.7.4-1.2.7-1.5-2.5-.3-5.1-1.3-5.1-5.6 0-1.2.4-2.3 1.2-3.1-.1-.3-.5-1.5.1-3.1 0 0 1-.3 3.1 1.2A10.8 10.8 0 0112 6.5c1 0 1.9.1 2.8.4 2.2-1.5 3.1-1.2 3.1-1.2.6 1.6.2 2.8.1 3.1.7.8 1.2 1.9 1.2 3.1 0 4.3-2.6 5.3-5.1 5.6.4.4.8 1.1.8 2.1v2.5c0 .4.2.7.8.6A11.3 11.3 0 0023.3 12 11.3 11.3 0 0012 .7z" /></svg>
262
+ GitHub
263
+ </a>
264
+ </span>
265
+ </footer>
169
266
  </div>
170
267
  </div>
171
268
 
@@ -173,19 +270,28 @@
173
270
  <div class="rn-overlay" data-rails_nexus-sidebar-target="overlay" data-action="click->rails_nexus-sidebar#close"></div>
174
271
 
175
272
  <%# Mobile sidebar drawer %>
176
- <div class="rn-mobile-sidebar" data-rails_nexus-sidebar-target="drawer">
273
+ <div id="rn-mobile-sidebar" class="rn-mobile-sidebar" data-rails_nexus-sidebar-target="drawer">
177
274
  <div class="rn-sidebar-logo">
178
- <span class="rn-logo-text"><%= RailsNexus.configuration.application_name || "RailsNexus" %></span>
179
- <button type="button" class="rn-icon-btn" data-action="click->rails_nexus-sidebar#close">
275
+ <%= link_to root_path, class: "flex items-center gap-2.5" do %>
276
+ <div class="rn-logo-icon">⚡</div>
277
+ <span class="rn-logo-copy">
278
+ <span class="rn-logo-text"><%= RailsNexus.configuration.application_name || "RailsNexus" %></span>
279
+ <span class="rn-logo-subtitle">Rails operations</span>
280
+ </span>
281
+ <% end %>
282
+ <button type="button" class="rn-icon-btn" data-action="click->rails_nexus-sidebar#close" aria-label="Close navigation">
180
283
  <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>
181
284
  </button>
182
285
  </div>
183
- <nav class="rn-sidebar-nav">
184
- <%= link_to root_path, class: "rn-nav-item" do %>
185
- <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>
186
- Dashboard
187
- <% end %>
188
- </nav>
286
+ <%= render "layouts/rails_nexus/sidebar_navigation",
287
+ exception_count: exception_count,
288
+ monitor_menu_active: monitor_menu_active,
289
+ operations_menu_active: operations_menu_active,
290
+ resources_menu_active: resources_menu_active %>
291
+ <div class="rn-sidebar-footer">
292
+ <span class="rn-sidebar-status"><span class="rn-status-dot"></span>Operational</span>
293
+ <span>v<%= RailsNexus::VERSION %></span>
294
+ </div>
189
295
  </div>
190
296
 
191
297
  <%= turbo_frame_tag :remote_modal, target: :_top %>