active_storage_dashboard 0.1.1

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,42 @@
1
+ <h1 class="page-title">Active Storage Variant Records</h1>
2
+
3
+ <div class="card">
4
+ <div class="card-body">
5
+ <% if defined?(ActiveStorage::VariantRecord) %>
6
+ <% if @variant_records.any? %>
7
+ <table>
8
+ <thead>
9
+ <tr>
10
+ <th>ID</th>
11
+ <th>Blob ID</th>
12
+ <th>Variation Digest</th>
13
+ <th>Actions</th>
14
+ </tr>
15
+ </thead>
16
+ <tbody>
17
+ <% @variant_records.each do |variant_record| %>
18
+ <tr>
19
+ <td><%= variant_record.id %></td>
20
+ <td><%= variant_record.blob_id %></td>
21
+ <td><%= variant_record.variation_digest %></td>
22
+ <td>
23
+ <a href="<%= variant_record_path(variant_record) %>">View Details</a>
24
+ </td>
25
+ </tr>
26
+ <% end %>
27
+ </tbody>
28
+ </table>
29
+
30
+ <%= pagination_links(@total_count) %>
31
+ <% else %>
32
+ <p>No variant records found.</p>
33
+ <% end %>
34
+ <% else %>
35
+ <div class="alert">
36
+ <p>
37
+ Variant Records are only available in Rails 6.1+. Your current Rails version does not support this feature.
38
+ </p>
39
+ </div>
40
+ <% end %>
41
+ </div>
42
+ </div>
@@ -0,0 +1,59 @@
1
+ <h1 class="page-title">Variant Record Details</h1>
2
+
3
+ <div class="card">
4
+ <div class="card-header">Variant Record Information</div>
5
+ <div class="card-body">
6
+ <table>
7
+ <tr>
8
+ <th>ID</th>
9
+ <td><%= @variant_record.id %></td>
10
+ </tr>
11
+ <tr>
12
+ <th>Blob ID</th>
13
+ <td><%= @variant_record.blob_id %></td>
14
+ </tr>
15
+ <tr>
16
+ <th>Variation Digest</th>
17
+ <td><%= @variant_record.variation_digest %></td>
18
+ </tr>
19
+ </table>
20
+ </div>
21
+ </div>
22
+
23
+ <div class="card">
24
+ <div class="card-header">Associated Blob</div>
25
+ <div class="card-body">
26
+ <table>
27
+ <tr>
28
+ <th>ID</th>
29
+ <td><%= @blob.id %></td>
30
+ </tr>
31
+ <tr>
32
+ <th>Filename</th>
33
+ <td><%= @blob.filename %></td>
34
+ </tr>
35
+ <tr>
36
+ <th>Content Type</th>
37
+ <td><%= @blob.content_type || 'Unknown' %></td>
38
+ </tr>
39
+ <tr>
40
+ <th>Size</th>
41
+ <td><%= format_bytes(@blob.byte_size) %></td>
42
+ </tr>
43
+ <tr>
44
+ <th>Created At</th>
45
+ <td><%= @blob.created_at.strftime('%Y-%m-%d %H:%M:%S') %></td>
46
+ </tr>
47
+ <tr>
48
+ <th>Actions</th>
49
+ <td>
50
+ <a href="<%= blob_path(@blob) %>">View Blob Details</a>
51
+ </td>
52
+ </tr>
53
+ </table>
54
+ </div>
55
+ </div>
56
+
57
+ <div class="card-body">
58
+ <a href="<%= variant_records_path %>" class="back-link">← Back to Variant Records</a>
59
+ </div>
@@ -0,0 +1,302 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Active Storage Dashboard</title>
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <style>
7
+ :root {
8
+ --primary-color: #4a6bef;
9
+ --secondary-color: #6c757d;
10
+ --success-color: #28a745;
11
+ --info-color: #17a2b8;
12
+ --warning-color: #ffc107;
13
+ --danger-color: #dc3545;
14
+ --light-color: #f8f9fa;
15
+ --dark-color: #343a40;
16
+ --body-bg: #f7f9fc;
17
+ --sidebar-bg: #ffffff;
18
+ --card-bg: #ffffff;
19
+ --text-color: #212529;
20
+ --border-color: #dee2e6;
21
+ }
22
+
23
+ * {
24
+ box-sizing: border-box;
25
+ margin: 0;
26
+ padding: 0;
27
+ }
28
+
29
+ body {
30
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
31
+ font-size: 1rem;
32
+ line-height: 1.5;
33
+ color: var(--text-color);
34
+ background-color: var(--body-bg);
35
+ }
36
+
37
+ a {
38
+ color: var(--primary-color);
39
+ text-decoration: none;
40
+ }
41
+
42
+ a:hover {
43
+ text-decoration: underline;
44
+ }
45
+
46
+ .container {
47
+ display: flex;
48
+ min-height: 100vh;
49
+ }
50
+
51
+ .sidebar {
52
+ width: 250px;
53
+ background-color: var(--sidebar-bg);
54
+ border-right: 1px solid var(--border-color);
55
+ padding: 1.5rem;
56
+ }
57
+
58
+ .content {
59
+ flex: 1;
60
+ padding: 1.5rem;
61
+ }
62
+
63
+ .sidebar-heading {
64
+ font-size: 1.25rem;
65
+ font-weight: 600;
66
+ margin-bottom: 1.5rem;
67
+ border-bottom: 1px solid var(--border-color);
68
+ padding-bottom: 0.5rem;
69
+ }
70
+
71
+ .sidebar-menu {
72
+ list-style: none;
73
+ }
74
+
75
+ .sidebar-menu li {
76
+ margin-bottom: 0.5rem;
77
+ }
78
+
79
+ .sidebar-menu a {
80
+ display: block;
81
+ padding: 0.5rem 0;
82
+ color: var(--dark-color);
83
+ }
84
+
85
+ .sidebar-menu a:hover,
86
+ .sidebar-menu a.active {
87
+ color: var(--primary-color);
88
+ }
89
+
90
+ .page-title {
91
+ margin-bottom: 1.5rem;
92
+ font-size: 1.75rem;
93
+ font-weight: 500;
94
+ }
95
+
96
+ .card {
97
+ background-color: var(--card-bg);
98
+ border-radius: 0.25rem;
99
+ box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
100
+ margin-bottom: 1.5rem;
101
+ }
102
+
103
+ .card-header {
104
+ padding: 0.75rem 1.25rem;
105
+ margin-bottom: 0;
106
+ background-color: rgba(0, 0, 0, 0.03);
107
+ border-bottom: 1px solid var(--border-color);
108
+ font-weight: 500;
109
+ }
110
+
111
+ .card-body {
112
+ padding: 1.25rem;
113
+ }
114
+
115
+ .stats-grid {
116
+ display: grid;
117
+ grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
118
+ gap: 1.5rem;
119
+ }
120
+
121
+ .stat-card {
122
+ padding: 1.25rem;
123
+ text-align: center;
124
+ background-color: var(--card-bg);
125
+ border-radius: 0.25rem;
126
+ box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
127
+ }
128
+
129
+ .stat-card-value {
130
+ font-size: 2rem;
131
+ font-weight: 500;
132
+ color: var(--primary-color);
133
+ }
134
+
135
+ .stat-card-label {
136
+ color: var(--secondary-color);
137
+ font-size: 0.875rem;
138
+ text-transform: uppercase;
139
+ letter-spacing: 0.05em;
140
+ }
141
+
142
+ table {
143
+ width: 100%;
144
+ border-collapse: collapse;
145
+ }
146
+
147
+ th, td {
148
+ padding: 0.75rem;
149
+ text-align: left;
150
+ border-bottom: 1px solid var(--border-color);
151
+ }
152
+
153
+ th {
154
+ background-color: rgba(0, 0, 0, 0.03);
155
+ font-weight: 500;
156
+ }
157
+
158
+ tbody tr:hover {
159
+ background-color: rgba(0, 0, 0, 0.03);
160
+ }
161
+
162
+ .pagination {
163
+ display: flex;
164
+ justify-content: center;
165
+ align-items: center;
166
+ margin-top: 1.5rem;
167
+ }
168
+
169
+ .pagination-link {
170
+ display: inline-block;
171
+ padding: 0.375rem 0.75rem;
172
+ margin: 0 0.25rem;
173
+ border-radius: 0.25rem;
174
+ background-color: var(--light-color);
175
+ color: var(--dark-color);
176
+ text-decoration: none;
177
+ }
178
+
179
+ .pagination-link:hover {
180
+ background-color: var(--primary-color);
181
+ color: white;
182
+ text-decoration: none;
183
+ }
184
+
185
+ .pagination-link.current {
186
+ background-color: var(--primary-color);
187
+ color: white;
188
+ }
189
+
190
+ .pagination-link.disabled {
191
+ color: var(--secondary-color);
192
+ pointer-events: none;
193
+ }
194
+
195
+ .pagination-ellipsis {
196
+ padding: 0.375rem 0.5rem;
197
+ }
198
+
199
+ .badge {
200
+ display: inline-block;
201
+ padding: 0.25em 0.4em;
202
+ font-size: 0.75em;
203
+ font-weight: 500;
204
+ line-height: 1;
205
+ text-align: center;
206
+ white-space: nowrap;
207
+ vertical-align: baseline;
208
+ border-radius: 0.25rem;
209
+ }
210
+
211
+ .badge-primary {
212
+ background-color: var(--primary-color);
213
+ color: white;
214
+ }
215
+
216
+ .badge-secondary {
217
+ background-color: var(--secondary-color);
218
+ color: white;
219
+ }
220
+
221
+ .badge-success {
222
+ background-color: var(--success-color);
223
+ color: white;
224
+ }
225
+
226
+ .badge-info {
227
+ background-color: var(--info-color);
228
+ color: white;
229
+ }
230
+
231
+ .flash {
232
+ padding: 0.75rem 1.25rem;
233
+ margin-bottom: 1rem;
234
+ border-radius: 0.25rem;
235
+ }
236
+
237
+ .flash-alert {
238
+ background-color: #f8d7da;
239
+ border: 1px solid #f5c6cb;
240
+ color: #721c24;
241
+ }
242
+
243
+ .flash-notice {
244
+ background-color: #d1ecf1;
245
+ border: 1px solid #bee5eb;
246
+ color: #0c5460;
247
+ }
248
+
249
+ .back-link {
250
+ margin-right: 10px;
251
+ }
252
+
253
+ .download-btn {
254
+ display: inline-block;
255
+ padding: 6px 12px;
256
+ background-color: var(--success-color);
257
+ color: white;
258
+ text-decoration: none;
259
+ border-radius: 4px;
260
+ font-size: 0.9rem;
261
+ }
262
+
263
+ .download-btn:hover {
264
+ text-decoration: none;
265
+ opacity: 0.9;
266
+ color: white;
267
+ }
268
+ </style>
269
+ </head>
270
+ <body>
271
+ <div class="container">
272
+ <div class="sidebar">
273
+ <h1 class="sidebar-heading">Active Storage Dashboard</h1>
274
+ <ul class="sidebar-menu">
275
+ <li><a href="<%= active_storage_dashboard.root_path %>" class="<%= controller_name == 'dashboard' ? 'active' : '' %>">Dashboard</a></li>
276
+ <li><a href="<%= active_storage_dashboard.blobs_path %>" class="<%= controller_name == 'blobs' ? 'active' : '' %>">Blobs</a></li>
277
+ <li><a href="<%= active_storage_dashboard.attachments_path %>" class="<%= controller_name == 'attachments' ? 'active' : '' %>">Attachments</a></li>
278
+ <li><a href="<%= active_storage_dashboard.variant_records_path %>" class="<%= controller_name == 'variant_records' ? 'active' : '' %>">Variant Records</a></li>
279
+ </ul>
280
+ </div>
281
+
282
+ <div class="content">
283
+ <% if flash[:alert] %>
284
+ <div class="flash flash-alert"><%= flash[:alert] %></div>
285
+ <% end %>
286
+
287
+ <% if flash[:notice] %>
288
+ <div class="flash flash-notice"><%= flash[:notice] %></div>
289
+ <% end %>
290
+
291
+ <%= yield %>
292
+ </div>
293
+ </div>
294
+
295
+ <script>
296
+ // Simple vanilla JS for any interactive elements
297
+ document.addEventListener('DOMContentLoaded', function() {
298
+ // Add any JavaScript functionality here if needed
299
+ });
300
+ </script>
301
+ </body>
302
+ </html>
data/config/routes.rb ADDED
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ ActiveStorageDashboard::Engine.routes.draw do
4
+ root to: 'dashboard#index'
5
+
6
+ resources :blobs, only: [:index, :show], path: 'blobs' do
7
+ member do
8
+ get 'download(/:disposition)', action: :download, as: :download
9
+ end
10
+ end
11
+
12
+ resources :attachments, only: [:index, :show], path: 'attachments' do
13
+ member do
14
+ get 'download(/:disposition)', action: :download, as: :download
15
+ end
16
+ end
17
+
18
+ resources :variant_records, only: [:index, :show], path: 'variant_records'
19
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveStorageDashboard
4
+ class Engine < ::Rails::Engine
5
+ isolate_namespace ActiveStorageDashboard
6
+
7
+ # Ensure URLs are generated correctly by setting defaults
8
+ initializer "active_storage_dashboard.url_options" do |app|
9
+ ActiveStorageDashboard::Engine.routes.default_url_options = app.routes.default_url_options
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveStorageDashboard
4
+ VERSION = "0.1.0"
5
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_storage_dashboard/version"
4
+ require "active_storage_dashboard/engine"
5
+
6
+ module ActiveStorageDashboard
7
+ # Your code goes here...
8
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ # desc "Explaining what the task does"
4
+ # task :active_storage_dashboard do
5
+ # # Task goes here
6
+ # end
metadata ADDED
@@ -0,0 +1,79 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: active_storage_dashboard
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Giovanni Panasiti
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 2025-05-16 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: rails
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: 5.2.0
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: 5.2.0
26
+ description: A mountable Rails engine that provides a dashboard to view Active Storage
27
+ data
28
+ email:
29
+ - giova.panasiti@gmail.com
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - README.md
35
+ - Rakefile
36
+ - app/controllers/active_storage_dashboard/application_controller.rb
37
+ - app/controllers/active_storage_dashboard/attachments_controller.rb
38
+ - app/controllers/active_storage_dashboard/blobs_controller.rb
39
+ - app/controllers/active_storage_dashboard/dashboard_controller.rb
40
+ - app/controllers/active_storage_dashboard/variant_records_controller.rb
41
+ - app/helpers/active_storage_dashboard/application_helper.rb
42
+ - app/views/active_storage_dashboard/attachments/index.html.erb
43
+ - app/views/active_storage_dashboard/attachments/show.html.erb
44
+ - app/views/active_storage_dashboard/blobs/index.html.erb
45
+ - app/views/active_storage_dashboard/blobs/show.html.erb
46
+ - app/views/active_storage_dashboard/dashboard/index.html.erb
47
+ - app/views/active_storage_dashboard/variant_records/index.html.erb
48
+ - app/views/active_storage_dashboard/variant_records/show.html.erb
49
+ - app/views/layouts/active_storage_dashboard/application.html.erb
50
+ - config/routes.rb
51
+ - lib/active_storage_dashboard.rb
52
+ - lib/active_storage_dashboard/engine.rb
53
+ - lib/active_storage_dashboard/version.rb
54
+ - lib/tasks/active_storage_dashboard_tasks.rake
55
+ homepage: https://github.com/giovapanasiti/active_storage_dashboard
56
+ licenses:
57
+ - MIT
58
+ metadata:
59
+ homepage_uri: https://github.com/giovapanasiti/active_storage_dashboard
60
+ source_code_uri: https://github.com/giovapanasiti/active_storage_dashboard
61
+ changelog_uri: https://github.com/giovapanasiti/active_storage_dashboard/blob/master/CHANGELOG.md
62
+ rdoc_options: []
63
+ require_paths:
64
+ - lib
65
+ required_ruby_version: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: 2.5.0
70
+ required_rubygems_version: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ requirements: []
76
+ rubygems_version: 3.6.2
77
+ specification_version: 4
78
+ summary: A dashboard for Active Storage in Rails applications
79
+ test_files: []