recycle_bin 1.0.0 → 1.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +55 -2
- data/Gemfile +3 -3
- data/README.md +95 -9
- data/app/controllers/recycle_bin/trash_controller.rb +120 -24
- data/app/views/{layouts/recycle_bin/application.html.erb → recycle_bin/layouts/recycle_bin.html.erb} +849 -609
- data/app/views/recycle_bin/shared/_error_messages.html.erb +10 -0
- data/app/views/recycle_bin/shared/_flash_messages.html.erb +6 -0
- data/app/views/recycle_bin/trash/_action_history.html.erb +71 -0
- data/app/views/recycle_bin/trash/_associations.html.erb +46 -0
- data/app/views/recycle_bin/trash/_filters.html.erb +17 -0
- data/app/views/recycle_bin/trash/_item.html.erb +24 -0
- data/app/views/recycle_bin/trash/_pagination.html.erb +75 -0
- data/app/views/recycle_bin/trash/_stats.html.erb +32 -0
- data/app/views/recycle_bin/trash/index.html.erb +48 -217
- data/app/views/recycle_bin/trash/show.html.erb +60 -215
- data/docs/index.html +928 -0
- data/docs/logo.svg +71 -0
- data/lib/recycle_bin/version.rb +1 -1
- data/lib/recycle_bin.rb +69 -3
- data/recycle_bin.gemspec +4 -4
- metadata +18 -14
- data/app/views/layouts/recycle_bin/recycle_bin/application.html.erb +0 -266
- data/app/views/layouts/recycle_bin/recycle_bin/trash/index.html.erb +0 -133
- data/app/views/layouts/recycle_bin/recycle_bin/trash/show.html.erb +0 -175
@@ -1,15 +1,12 @@
|
|
1
|
-
|
2
|
-
<div
|
3
|
-
|
4
|
-
|
5
|
-
</div>
|
6
|
-
|
7
|
-
<!-- Item Header Card -->
|
8
|
-
<div class="main-card" style="margin-bottom: 2rem;">
|
1
|
+
<% content_for :title, "#{@item.class.name} Details" %>
|
2
|
+
<div class="main-card">
|
3
|
+
<div class="back-link">
|
4
|
+
<%= link_to "← Back to Dashboard", recycle_bin.root_path, class: "btn btn-outline" %>
|
5
|
+
</div>
|
9
6
|
<div class="card-header">
|
10
7
|
<div>
|
11
|
-
<h1 class="card-title"
|
12
|
-
<span class="model-badge"
|
8
|
+
<h1 class="card-title">
|
9
|
+
<span class="model-badge"><%= @item.class.name %></span>
|
13
10
|
<%= @item.recyclable_title %>
|
14
11
|
</h1>
|
15
12
|
<div class="timestamp">
|
@@ -17,77 +14,53 @@
|
|
17
14
|
<%= @item.deleted_at.strftime('%B %d, %Y at %l:%M %p') %>
|
18
15
|
</div>
|
19
16
|
</div>
|
20
|
-
|
21
17
|
<div class="card-actions">
|
22
|
-
<%= link_to recycle_bin.restore_trash_path(@item.class.name, @item),
|
23
|
-
method: :patch,
|
24
|
-
|
25
|
-
data: { confirm: "
|
26
|
-
↶ Restore Item
|
27
|
-
<% end %>
|
28
|
-
<%= link_to recycle_bin.destroy_trash_path(@item.class.name, @item),
|
29
|
-
method: :delete,
|
30
|
-
class: "btn btn-danger",
|
31
|
-
data: { confirm: "Permanently delete this #{@item.class.name.downcase}? This cannot be undone!" } do %>
|
32
|
-
🗑️ Delete Forever
|
33
|
-
<% end %>
|
18
|
+
<%= link_to "↶ Restore Item", recycle_bin.restore_trash_path(@item.class.name, @item),
|
19
|
+
method: :patch, class: "btn btn-success", data: { confirm: "Restore this #{@item.class.name.downcase}?" } %>
|
20
|
+
<%= link_to "🗑️ Delete Forever", recycle_bin.destroy_trash_path(@item.class.name, @item),
|
21
|
+
method: :delete, class: "btn btn-danger", data: { confirm: "Permanently delete this #{@item.class.name.downcase}? This cannot be undone!" } %>
|
34
22
|
</div>
|
35
23
|
</div>
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
</span>
|
43
|
-
<span class="timestamp">
|
44
|
-
Size: <%= number_to_human_size(@item_memory_size) %> •
|
45
|
-
ID: <%= @item.id %>
|
46
|
-
</span>
|
47
|
-
</div>
|
24
|
+
<div class="bulk-actions show">
|
25
|
+
<span class="timestamp">
|
26
|
+
🗑️ This item is in the recycle bin •
|
27
|
+
Size: <%= number_to_human_size(@item_memory_size) %> •
|
28
|
+
ID: <%= @item.id %>
|
29
|
+
</span>
|
48
30
|
</div>
|
49
31
|
</div>
|
50
|
-
|
51
|
-
<!-- Original Data -->
|
52
32
|
<div class="main-card">
|
53
33
|
<div class="card-header">
|
54
34
|
<h3 class="card-title">Original Data</h3>
|
55
35
|
<div class="card-actions">
|
56
|
-
<button class="btn btn-sm btn-outline" onclick="toggleRawData()">
|
57
|
-
📋 Toggle Raw View
|
58
|
-
</button>
|
36
|
+
<button class="btn btn-sm btn-outline" onclick="toggleRawData()">📋 Toggle Raw View</button>
|
59
37
|
</div>
|
60
38
|
</div>
|
61
|
-
|
62
|
-
<div style="padding: 1.5rem;">
|
39
|
+
<div class="card-body">
|
63
40
|
<% if @original_attributes.any? %>
|
64
41
|
<div class="table-container">
|
65
42
|
<table class="table">
|
66
43
|
<thead>
|
67
44
|
<tr>
|
68
|
-
<th
|
45
|
+
<th class="field-column">Field</th>
|
69
46
|
<th>Value</th>
|
70
|
-
<th
|
47
|
+
<th class="type-column">Type</th>
|
71
48
|
</tr>
|
72
49
|
</thead>
|
73
50
|
<tbody>
|
74
51
|
<% @original_attributes.each do |key, value| %>
|
75
52
|
<tr>
|
76
|
-
<td>
|
77
|
-
<strong><%= key.humanize %></strong>
|
78
|
-
</td>
|
53
|
+
<td><strong><%= key.humanize %></strong></td>
|
79
54
|
<td>
|
80
55
|
<% if value.nil? %>
|
81
|
-
<em
|
56
|
+
<em class="timestamp">nil</em>
|
82
57
|
<% elsif value.is_a?(String) && value.length > 100 %>
|
83
58
|
<div>
|
84
59
|
<div><%= truncate(value, length: 100) %></div>
|
85
|
-
<details
|
86
|
-
<summary
|
87
|
-
|
88
|
-
|
89
|
-
<div style="margin-top: 0.5rem; padding: 1rem; background: #f8f9fa; border-radius: 4px; white-space: pre-wrap; font-family: monospace; font-size: 0.85rem;">
|
90
|
-
<%= value %>
|
60
|
+
<details>
|
61
|
+
<summary class="btn btn-outline btn-sm">Show full content (<%= value.length %> characters)</summary>
|
62
|
+
<div class="card">
|
63
|
+
<pre class="pre-wrap"><%= value %></pre>
|
91
64
|
</div>
|
92
65
|
</details>
|
93
66
|
</div>
|
@@ -99,34 +72,27 @@
|
|
99
72
|
<% elsif value.is_a?(Date) %>
|
100
73
|
<%= value.strftime('%B %d, %Y') %>
|
101
74
|
<% elsif value == true %>
|
102
|
-
<span
|
75
|
+
<span class="boolean-true">✓ True</span>
|
103
76
|
<% elsif value == false %>
|
104
|
-
<span
|
77
|
+
<span class="boolean-false">✗ False</span>
|
105
78
|
<% elsif value.is_a?(Numeric) %>
|
106
|
-
<span
|
79
|
+
<span class="numeric"><%= number_with_delimiter(value) %></span>
|
107
80
|
<% else %>
|
108
81
|
<%= value %>
|
109
82
|
<% end %>
|
110
83
|
</td>
|
111
|
-
<td>
|
112
|
-
<span class="timestamp">
|
113
|
-
<%= value.class.name.downcase %>
|
114
|
-
</span>
|
115
|
-
</td>
|
84
|
+
<td><span class="timestamp"><%= value.class.name.downcase %></span></td>
|
116
85
|
</tr>
|
117
86
|
<% end %>
|
118
87
|
</tbody>
|
119
88
|
</table>
|
120
89
|
</div>
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
<h4 style="margin-bottom: 1rem; color: #495057;">Raw JSON Data</h4>
|
126
|
-
<pre style="background: #2d3748; color: #e2e8f0; padding: 1rem; border-radius: 4px; overflow-x: auto; font-size: 0.85rem; line-height: 1.4;"><%= JSON.pretty_generate(@original_attributes) %></pre>
|
90
|
+
<div id="raw-data" class="hidden">
|
91
|
+
<div class="card">
|
92
|
+
<h4>Raw JSON Data</h4>
|
93
|
+
<pre class="pre-wrap"><%= JSON.pretty_generate(@original_attributes) %></pre>
|
127
94
|
</div>
|
128
95
|
</div>
|
129
|
-
|
130
96
|
<% else %>
|
131
97
|
<div class="empty-state">
|
132
98
|
<div class="empty-icon">📄</div>
|
@@ -136,153 +102,32 @@
|
|
136
102
|
<% end %>
|
137
103
|
</div>
|
138
104
|
</div>
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
<div class="
|
143
|
-
<
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
<% @associations.each do |association_name, items| %>
|
152
|
-
<div style="margin-bottom: 2rem;">
|
153
|
-
<h4 style="color: #495057; margin-bottom: 1rem; padding-bottom: 0.5rem; border-bottom: 1px solid #dee2e6;">
|
154
|
-
<%= association_name.humanize %>
|
155
|
-
<span class="timestamp">(<%= items.count %> items)</span>
|
156
|
-
</h4>
|
157
|
-
|
158
|
-
<% if items.any? %>
|
159
|
-
<div style="display: grid; gap: 1rem;">
|
160
|
-
<% items.each do |item| %>
|
161
|
-
<div style="display: flex; align-items: center; padding: 1rem; background: #f8f9fa; border-radius: 6px; border-left: 3px solid #667eea;">
|
162
|
-
<div style="flex: 1;">
|
163
|
-
<div style="font-weight: 500; color: #495057;">
|
164
|
-
<%= item.class.name %> -
|
165
|
-
<%= item.respond_to?(:title) ? item.title :
|
166
|
-
item.respond_to?(:name) ? item.name :
|
167
|
-
"ID: #{item.id}" %>
|
168
|
-
</div>
|
169
|
-
<div class="timestamp">
|
170
|
-
Created <%= time_ago_in_words(item.created_at) %> ago
|
171
|
-
<% if item.respond_to?(:deleted_at) && item.deleted_at %>
|
172
|
-
• <span style="color: #dc3545;">Also deleted</span>
|
173
|
-
<% end %>
|
174
|
-
</div>
|
175
|
-
</div>
|
176
|
-
|
177
|
-
<% if item.respond_to?(:deleted_at) && item.deleted_at %>
|
178
|
-
<span class="model-badge" style="background: #dc3545;">Deleted</span>
|
179
|
-
<% else %>
|
180
|
-
<span class="model-badge" style="background: #28a745;">Active</span>
|
181
|
-
<% end %>
|
182
|
-
</div>
|
183
|
-
<% end %>
|
184
|
-
</div>
|
185
|
-
<% else %>
|
186
|
-
<div class="empty-state" style="padding: 2rem;">
|
187
|
-
<p style="color: #6c757d; font-style: italic;">No related items found.</p>
|
188
|
-
</div>
|
189
|
-
<% end %>
|
190
|
-
</div>
|
191
|
-
<% end %>
|
192
|
-
</div>
|
193
|
-
</div>
|
194
|
-
<% end %>
|
195
|
-
|
196
|
-
<!-- Action History -->
|
197
|
-
<div class="main-card" style="margin-top: 2rem;">
|
198
|
-
<div class="card-header">
|
199
|
-
<h3 class="card-title">Action History</h3>
|
200
|
-
</div>
|
201
|
-
|
202
|
-
<div style="padding: 1.5rem;">
|
203
|
-
<div style="display: grid; gap: 1rem;">
|
204
|
-
<!-- Deletion Event -->
|
205
|
-
<div style="display: flex; align-items: start; gap: 1rem; padding: 1rem; border-left: 3px solid #dc3545; background: #fff5f5;">
|
206
|
-
<div style="font-size: 1.5rem;">🗑️</div>
|
207
|
-
<div style="flex: 1;">
|
208
|
-
<div style="font-weight: 500; color: #495057;">Item Deleted</div>
|
209
|
-
<div class="timestamp">
|
210
|
-
<%= @item.deleted_at.strftime('%B %d, %Y at %l:%M %p') %>
|
211
|
-
(<%= time_ago_in_words(@item.deleted_at) %> ago)
|
212
|
-
</div>
|
213
|
-
<% if @item.respond_to?(:deleted_by) && @item.deleted_by %>
|
214
|
-
<div class="timestamp">by <%= @item.deleted_by %></div>
|
215
|
-
<% end %>
|
216
|
-
</div>
|
217
|
-
</div>
|
218
|
-
|
219
|
-
<!-- Creation Event -->
|
220
|
-
<div style="display: flex; align-items: start; gap: 1rem; padding: 1rem; border-left: 3px solid #28a745; background: #f0fff4;">
|
221
|
-
<div style="font-size: 1.5rem;">✨</div>
|
222
|
-
<div style="flex: 1;">
|
223
|
-
<div style="font-weight: 500; color: #495057;">Item Created</div>
|
224
|
-
<div class="timestamp">
|
225
|
-
<%= @item.created_at.strftime('%B %d, %Y at %l:%M %p') %>
|
226
|
-
(<%= time_ago_in_words(@item.created_at) %> ago)
|
227
|
-
</div>
|
228
|
-
</div>
|
229
|
-
</div>
|
105
|
+
<%= render 'recycle_bin/trash/associations', associations: @associations if @associations&.any? %>
|
106
|
+
<%= render 'recycle_bin/trash/action_history', item: @item %>
|
107
|
+
<div class="main-card">
|
108
|
+
<div class="center-content">
|
109
|
+
<h4>Quick Actions</h4>
|
110
|
+
<div class="card-actions">
|
111
|
+
<%= link_to "↶ Restore to Application", recycle_bin.restore_trash_path(@item.class.name, @item),
|
112
|
+
method: :patch, class: "btn btn-success", data: { confirm: "Restore this #{@item.class.name.downcase}?" } %>
|
113
|
+
<%= link_to "🗑️ Delete Permanently", recycle_bin.destroy_trash_path(@item.class.name, @item),
|
114
|
+
method: :delete, class: "btn btn-danger", data: { confirm: "Permanently delete this #{@item.class.name.downcase}? This cannot be undone!" } %>
|
115
|
+
<%= link_to "📋 Back to Dashboard", recycle_bin.root_path, class: "btn btn-outline" %>
|
116
|
+
<button class="btn btn-outline" onclick="window.print()">🖨️ Print Details</button>
|
230
117
|
</div>
|
231
118
|
</div>
|
232
119
|
</div>
|
233
|
-
|
234
|
-
|
235
|
-
<
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
<% end %>
|
246
|
-
|
247
|
-
<%= link_to recycle_bin.destroy_trash_path(@item.class.name, @item),
|
248
|
-
method: :delete,
|
249
|
-
class: "btn btn-danger",
|
250
|
-
data: { confirm: "Permanently delete this #{@item.class.name.downcase}? This cannot be undone!" } do %>
|
251
|
-
🗑️ Delete Permanently
|
252
|
-
<% end %>
|
253
|
-
|
254
|
-
<%= link_to recycle_bin.root_path, class: "btn btn-outline" do %>
|
255
|
-
📋 Back to Dashboard
|
256
|
-
<% end %>
|
257
|
-
|
258
|
-
<button class="btn btn-outline" onclick="window.print()">
|
259
|
-
🖨️ Print Details
|
260
|
-
</button>
|
261
|
-
</div>
|
120
|
+
<% if Rails.env.development? %>
|
121
|
+
<div class="main-card">
|
122
|
+
<details>
|
123
|
+
<summary>🔍 Debug Info (Development Only)</summary>
|
124
|
+
<div class="card">
|
125
|
+
<p><strong>Class:</strong> <%= @item.class.name %></p>
|
126
|
+
<p><strong>ID:</strong> <%= @item.id %></p>
|
127
|
+
<p><strong>Deleted At:</strong> <%= @item.deleted_at %></p>
|
128
|
+
<p><strong>Attributes:</strong></p>
|
129
|
+
<pre class="pre-wrap"><%= @item.attributes.to_yaml %></pre>
|
130
|
+
</div>
|
131
|
+
</details>
|
262
132
|
</div>
|
263
|
-
|
264
|
-
|
265
|
-
<!-- JavaScript for interactions -->
|
266
|
-
<script>
|
267
|
-
function toggleRawData() {
|
268
|
-
const rawData = document.getElementById('raw-data');
|
269
|
-
if (rawData.style.display === 'none') {
|
270
|
-
rawData.style.display = 'block';
|
271
|
-
} else {
|
272
|
-
rawData.style.display = 'none';
|
273
|
-
}
|
274
|
-
}
|
275
|
-
|
276
|
-
// Auto-copy functionality for technical details
|
277
|
-
document.addEventListener('click', function(e) {
|
278
|
-
if (e.target.matches('[data-copy]')) {
|
279
|
-
const text = e.target.dataset.copy;
|
280
|
-
navigator.clipboard.writeText(text).then(() => {
|
281
|
-
e.target.textContent = '✓ Copied!';
|
282
|
-
setTimeout(() => {
|
283
|
-
e.target.textContent = text;
|
284
|
-
}, 2000);
|
285
|
-
});
|
286
|
-
}
|
287
|
-
});
|
288
|
-
</script>
|
133
|
+
<% end %>
|