recycle_bin 1.1.1 → 1.2.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.
@@ -1,35 +1,84 @@
1
1
  <% content_for :title, "Deleted Items" %>
2
- <%= render 'recycle_bin/trash/stats',
3
- total_count: @total_count,
4
- model_types: @model_types,
5
- filtered_items: @filtered_items,
6
- current_page: @current_page,
7
- per_page: @per_page,
2
+
3
+ <!-- Page Header -->
4
+ <div class="page-header">
5
+ <div class="page-title-section">
6
+ <h1 class="page-title">🗂️ All Items</h1>
7
+ <p class="page-subtitle">Browse and manage all deleted items with advanced filtering and search</p>
8
+ </div>
9
+ <div class="page-actions">
10
+ <%= link_to "← Back to Dashboard", recycle_bin.root_path, class: "btn btn-outline" %>
11
+ </div>
12
+ </div>
13
+
14
+ <!-- Search Results Summary -->
15
+ <% if params[:search].present? %>
16
+ <div class="search-summary">
17
+ <div class="search-summary-content">
18
+ <h3>🔍 <%= search_result_summary(@total_count, params[:search]) %></h3>
19
+ <% if @total_count > 0 %>
20
+ <p class="search-tip">💡 Tip: Use advanced filters to narrow down your results further</p>
21
+ <% end %>
22
+ </div>
23
+ </div>
24
+ <% end %>
25
+
26
+ <!-- Filter Breadcrumb -->
27
+ <% if any_filters_active? %>
28
+ <div class="filter-breadcrumb">
29
+ <span class="breadcrumb-label">📋 Active Filters:</span>
30
+ <span class="breadcrumb-content"><%= filter_breadcrumb %></span>
31
+ <span class="filter-count-badge"><%= active_filter_count %></span>
32
+ </div>
33
+ <% end %>
34
+
35
+ <%= render 'recycle_bin/trash/stats',
36
+ total_count: @total_count,
37
+ model_types: @model_types,
38
+ filtered_items: @filtered_items,
39
+ current_page: @current_page,
40
+ per_page: @per_page,
8
41
  total_pages: @total_pages %>
42
+
9
43
  <%= render 'recycle_bin/trash/filters', model_types: @model_types %>
44
+
10
45
  <% if @deleted_items.any? %>
11
46
  <div class="main-card">
12
47
  <div class="card-header">
13
- <h3 class="card-title">Deleted Items (<%= number_with_delimiter(@total_count) %>)</h3>
48
+ <h3 class="card-title">
49
+ Deleted Items
50
+ <% if params[:search].present? %>
51
+ <span class="search-highlight">for "<%= params[:search] %>"</span>
52
+ <% end %>
53
+ (<%= number_with_delimiter(@total_count) %>)
54
+ </h3>
14
55
  <div class="card-actions">
15
- <%# <label class="btn btn-outline btn-sm">
16
- <input type="checkbox" id="auto-refresh"> Auto-refresh
17
- </label> %>
56
+ <!-- Export buttons -->
57
+ <div class="export-buttons">
58
+ <%= link_to "📊 CSV Export", recycle_bin.trash_index_path(format: :csv, **request.query_parameters),
59
+ class: "btn btn-outline btn-sm",
60
+ title: "Export current results to CSV" %>
61
+ <%= link_to "📄 JSON Export", recycle_bin.trash_index_path(format: :json, **request.query_parameters),
62
+ class: "btn btn-outline btn-sm",
63
+ title: "Export current results to JSON" %>
64
+ </div>
18
65
  </div>
19
66
  </div>
67
+
20
68
  <div id="bulk-actions" class="bulk-actions">
21
69
  <span id="bulk-count">0 items selected</span>
22
70
  <div class="card-actions">
23
- <%= form_with url: recycle_bin.bulk_restore_trash_index_path, method: :patch, local: true do |form| %>
71
+ <%= form_with url: bulk_restore_trash_index_path, method: :patch, local: true do |form| %>
24
72
  <input type="hidden" id="bulk-restore-items" name="selected_items" value="">
25
73
  <%= form.submit "↶ Restore Selected", class: "btn btn-success btn-sm", onclick: "return handleBulkAction('restore')" %>
26
74
  <% end %>
27
- <%= form_with url: recycle_bin.bulk_destroy_trash_index_path, method: :delete, local: true do |form| %>
75
+ <%= form_with url: bulk_destroy_trash_index_path, method: :delete, local: true do |form| %>
28
76
  <input type="hidden" id="bulk-destroy-items" name="selected_items" value="">
29
77
  <%= form.submit "🗑️ Delete Selected", class: "btn btn-danger btn-sm", onclick: "return handleBulkAction('destroy')" %>
30
78
  <% end %>
31
79
  </div>
32
80
  </div>
81
+
33
82
  <div class="table-container">
34
83
  <table class="table">
35
84
  <thead>
@@ -38,6 +87,7 @@
38
87
  <th>Type</th>
39
88
  <th>Item</th>
40
89
  <th>Deleted At</th>
90
+ <th>Size</th>
41
91
  <th>Actions</th>
42
92
  </tr>
43
93
  </thead>
@@ -47,14 +97,193 @@
47
97
  </table>
48
98
  </div>
49
99
  </div>
100
+
50
101
  <%= render 'recycle_bin/trash/pagination', current_page: @current_page, total_pages: @total_pages, total_count: @total_count, per_page: @per_page %>
102
+
51
103
  <% else %>
52
104
  <div class="main-card">
53
105
  <div class="empty-state">
54
- <div class="empty-icon">🎉</div>
55
- <h4 class="empty-title">No items match your filters!</h4>
56
- <p class="empty-subtitle">Try adjusting your filters or check back later for deleted items.</p>
57
- <%= link_to "Clear Filters", recycle_bin.root_path, class: "btn btn-primary" %>
106
+ <% if params[:search].present? %>
107
+ <div class="empty-icon">🔍</div>
108
+ <h4 class="empty-title">No search results found!</h4>
109
+ <p class="empty-subtitle">
110
+ No items match your search "<strong><%= params[:search] %></strong>".
111
+ Try adjusting your search terms or filters.
112
+ </p>
113
+ <div class="empty-actions">
114
+ <%= link_to "Clear Search", recycle_bin.trash_index_path, class: "btn btn-primary" %>
115
+ <%= link_to "View All Items", recycle_bin.trash_index_path, class: "btn btn-outline" %>
116
+ </div>
117
+ <% elsif any_filters_active? %>
118
+ <div class="empty-icon">📊</div>
119
+ <h4 class="empty-title">No items match your filters!</h4>
120
+ <p class="empty-subtitle">
121
+ Try adjusting your filter criteria or <%= link_to "clear all filters", recycle_bin.trash_index_path %>.
122
+ </p>
123
+ <% else %>
124
+ <div class="empty-icon">🎉</div>
125
+ <h4 class="empty-title">No items match your filters!</h4>
126
+ <p class="empty-subtitle">Try adjusting your filters or check back later for deleted items.</p>
127
+ <%= link_to "Clear Filters", recycle_bin.trash_index_path, class: "btn btn-primary" %>
128
+ <% end %>
58
129
  </div>
59
130
  </div>
60
- <% end %>
131
+ <% end %>
132
+
133
+ <style>
134
+ .page-header {
135
+ display: flex;
136
+ justify-content: space-between;
137
+ align-items: center;
138
+ margin-bottom: 24px;
139
+ padding: 20px 0;
140
+ border-bottom: 1px solid #e9ecef;
141
+ }
142
+
143
+ .page-title-section {
144
+ flex: 1;
145
+ }
146
+
147
+ .page-title {
148
+ font-size: 28px;
149
+ font-weight: 700;
150
+ color: #495057;
151
+ margin: 0 0 8px 0;
152
+ display: flex;
153
+ align-items: center;
154
+ gap: 12px;
155
+ }
156
+
157
+ .page-subtitle {
158
+ font-size: 16px;
159
+ color: #6c757d;
160
+ margin: 0;
161
+ line-height: 1.4;
162
+ }
163
+
164
+ .page-actions {
165
+ display: flex;
166
+ gap: 12px;
167
+ }
168
+
169
+ @media (max-width: 768px) {
170
+ .page-header {
171
+ flex-direction: column;
172
+ align-items: flex-start;
173
+ gap: 16px;
174
+ }
175
+
176
+ .page-actions {
177
+ width: 100%;
178
+ justify-content: flex-start;
179
+ }
180
+
181
+ .page-title {
182
+ font-size: 24px;
183
+ }
184
+
185
+ .page-subtitle {
186
+ font-size: 14px;
187
+ }
188
+ }
189
+
190
+ .search-summary {
191
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
192
+ color: white;
193
+ padding: 20px;
194
+ border-radius: 8px;
195
+ margin-bottom: 20px;
196
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
197
+ }
198
+
199
+ .search-summary-content h3 {
200
+ margin: 0 0 10px 0;
201
+ font-size: 1.5rem;
202
+ }
203
+
204
+ .search-tip {
205
+ margin: 0;
206
+ opacity: 0.9;
207
+ font-size: 0.9rem;
208
+ }
209
+
210
+ .filter-breadcrumb {
211
+ background: #e3f2fd;
212
+ border: 1px solid #bbdefb;
213
+ border-radius: 6px;
214
+ padding: 12px 16px;
215
+ margin-bottom: 20px;
216
+ display: flex;
217
+ align-items: center;
218
+ gap: 10px;
219
+ flex-wrap: wrap;
220
+ }
221
+
222
+ .breadcrumb-label {
223
+ font-weight: 600;
224
+ color: #1976d2;
225
+ font-size: 14px;
226
+ }
227
+
228
+ .breadcrumb-content {
229
+ color: #1565c0;
230
+ font-size: 14px;
231
+ }
232
+
233
+ .filter-count-badge {
234
+ background: #1976d2;
235
+ color: white;
236
+ padding: 2px 8px;
237
+ border-radius: 12px;
238
+ font-size: 12px;
239
+ font-weight: 600;
240
+ margin-left: auto;
241
+ }
242
+
243
+ .search-highlight {
244
+ background: #fff3cd;
245
+ color: #856404;
246
+ padding: 2px 8px;
247
+ border-radius: 4px;
248
+ font-size: 0.9rem;
249
+ font-weight: normal;
250
+ }
251
+
252
+ .export-buttons {
253
+ display: flex;
254
+ gap: 8px;
255
+ }
256
+
257
+ .empty-actions {
258
+ display: flex;
259
+ gap: 10px;
260
+ margin-top: 15px;
261
+ justify-content: center;
262
+ }
263
+
264
+ .empty-actions .btn {
265
+ min-width: 120px;
266
+ }
267
+
268
+ @media (max-width: 768px) {
269
+ .search-summary-content h3 {
270
+ font-size: 1.2rem;
271
+ }
272
+
273
+ .filter-breadcrumb {
274
+ flex-direction: column;
275
+ align-items: flex-start;
276
+ gap: 8px;
277
+ }
278
+
279
+ .filter-count-badge {
280
+ margin-left: 0;
281
+ align-self: flex-start;
282
+ }
283
+
284
+ .empty-actions {
285
+ flex-direction: column;
286
+ align-items: center;
287
+ }
288
+ }
289
+ </style>
data/config/routes.rb CHANGED
@@ -1,14 +1,21 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  RecycleBin::Engine.routes.draw do
4
- root 'trash#index'
4
+ # Dashboard as root
5
+ root 'trash#dashboard'
5
6
 
6
- # Standard resource routes
7
+ # Dashboard route
8
+ get 'dashboard', to: 'trash#dashboard', as: 'dashboard'
9
+
10
+ # Standard resource routes with format support
7
11
  resources :trash, only: [:index] do
8
12
  collection do
9
13
  patch :bulk_restore
10
14
  delete :bulk_destroy
11
15
  delete :cleanup_large_items
16
+ # Export routes
17
+ get :export_csv, defaults: { format: :csv }
18
+ get :export_json, defaults: { format: :json }
12
19
  end
13
20
  end
14
21
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RecycleBin
4
- VERSION = '1.1.1'
4
+ VERSION = '1.2.0'
5
5
  end
data/lib/recycle_bin.rb CHANGED
@@ -165,15 +165,52 @@ module RecycleBin
165
165
  # Configuration class for RecycleBin
166
166
  class Configuration
167
167
  attr_accessor :enable_web_interface, :items_per_page, :ui_theme,
168
- :auto_cleanup_after, :current_user_method, :max_items_per_page
168
+ :auto_cleanup_after, :current_user_method, :max_items_per_page,
169
+ :search_settings, :export_settings, :error_logging_service,
170
+ :enable_advanced_filters, :enable_search_highlighting,
171
+ :max_search_results, :enable_export,
172
+ :export_formats, :export_max_items, :enable_audit_logging
169
173
 
170
174
  def initialize
175
+ # Basic settings
171
176
  @enable_web_interface = true
172
177
  @items_per_page = 25
173
178
  @max_items_per_page = 1000
174
179
  @ui_theme = 'default'
175
180
  @auto_cleanup_after = nil
176
181
  @current_user_method = :current_user
182
+
183
+ # Search settings
184
+ @search_settings = {
185
+ enable_full_text_search: true,
186
+ searchable_fields: %w[title name email content body description],
187
+ max_search_length: 100,
188
+ search_timeout: 30.seconds,
189
+ enable_fuzzy_search: false,
190
+ min_search_length: 2
191
+ }
192
+
193
+ # Export settings
194
+ @export_settings = {
195
+ enable_csv_export: true,
196
+ enable_json_export: true,
197
+ max_export_items: 10_000,
198
+ export_timeout: 5.minutes,
199
+ include_metadata: true,
200
+ compress_large_exports: true
201
+ }
202
+
203
+ # Advanced features
204
+ @enable_advanced_filters = true
205
+ @enable_search_highlighting = true
206
+ @max_search_results = 10_000
207
+ @enable_export = true
208
+ @export_formats = %w[csv json]
209
+ @export_max_items = 10_000
210
+ @enable_audit_logging = false
211
+
212
+ # Error logging service (can be set to external service like Sentry)
213
+ @error_logging_service = nil
177
214
  end
178
215
 
179
216
  def authorize_with(&block)
@@ -183,5 +220,78 @@ module RecycleBin
183
220
  def authorization_method
184
221
  @authorization_method || proc { true }
185
222
  end
223
+
224
+ # Search configuration methods
225
+ def search_config
226
+ @search_settings
227
+ end
228
+
229
+ def enable_full_text_search=(value)
230
+ @search_settings[:enable_full_text_search] = value
231
+ end
232
+
233
+ def searchable_fields=(fields)
234
+ @search_settings[:searchable_fields] = Array(fields)
235
+ end
236
+
237
+ def max_search_length=(length)
238
+ @search_settings[:max_search_length] = length
239
+ end
240
+
241
+ def search_timeout=(timeout)
242
+ @search_settings[:search_timeout] = timeout
243
+ end
244
+
245
+ # Export configuration methods
246
+ def export_config
247
+ @export_settings
248
+ end
249
+
250
+ def enable_csv_export=(value)
251
+ @export_settings[:enable_csv_export] = value
252
+ end
253
+
254
+ def enable_json_export=(value)
255
+ @export_settings[:enable_json_export] = value
256
+ end
257
+
258
+ def max_export_items=(count)
259
+ @export_settings[:max_export_items] = count
260
+ end
261
+
262
+ def export_timeout=(timeout)
263
+ @export_settings[:export_timeout] = timeout
264
+ end
265
+
266
+ # Validation methods
267
+ def valid?
268
+ validate_configuration
269
+ end
270
+
271
+ def validate_configuration
272
+ errors = []
273
+
274
+ # Validate search settings
275
+ errors << 'min_search_length cannot be greater than max_search_length' if @search_settings[:min_search_length] > @search_settings[:max_search_length]
276
+
277
+ errors << 'search_timeout must be positive' if @search_settings[:search_timeout] <= 0
278
+
279
+ # Validate export settings
280
+ errors << 'max_export_items must be positive' if @export_settings[:max_export_items] <= 0
281
+
282
+ errors << 'export_timeout must be positive' if @export_settings[:export_timeout] <= 0
283
+
284
+ # Validate basic settings
285
+ errors << 'items_per_page must be positive' if @items_per_page <= 0
286
+
287
+ errors << 'max_items_per_page cannot be less than items_per_page' if @max_items_per_page < @items_per_page
288
+
289
+ errors.empty?
290
+ end
291
+
292
+ def errors
293
+ validate_configuration
294
+ []
295
+ end
186
296
  end
187
297
  end
metadata CHANGED
@@ -1,15 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: recycle_bin
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.1
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rishi Somani
8
8
  - Shobhit Jain
9
9
  - Raghav Agrawal
10
+ autorequire:
10
11
  bindir: bin
11
12
  cert_chain: []
12
- date: 2025-05-26 00:00:00.000000000 Z
13
+ date: 2025-09-08 00:00:00.000000000 Z
13
14
  dependencies:
14
15
  - !ruby/object:Gem::Dependency
15
16
  name: rails
@@ -101,6 +102,7 @@ files:
101
102
  - app/views/recycle_bin/trash/_item.html.erb
102
103
  - app/views/recycle_bin/trash/_pagination.html.erb
103
104
  - app/views/recycle_bin/trash/_stats.html.erb
105
+ - app/views/recycle_bin/trash/dashboard.html.erb
104
106
  - app/views/recycle_bin/trash/index.html.erb
105
107
  - app/views/recycle_bin/trash/show.html.erb
106
108
  - config/routes.rb
@@ -115,7 +117,6 @@ files:
115
117
  - lib/recycle_bin/install/templates/recycle_bin.rb
116
118
  - lib/recycle_bin/soft_deletable.rb
117
119
  - lib/recycle_bin/version.rb
118
- - recycle_bin.gemspec
119
120
  - sig/recycle_bin.rbs
120
121
  homepage: https://github.com/R95-del/recycle_bin
121
122
  licenses:
@@ -128,6 +129,7 @@ metadata:
128
129
  bug_tracker_uri: https://github.com/R95-del/recycle_bin/issues
129
130
  documentation_uri: https://github.com/R95-del/recycle_bin/blob/main/README.md
130
131
  wiki_uri: https://github.com/R95-del/recycle_bin/wiki
132
+ post_install_message:
131
133
  rdoc_options: []
132
134
  require_paths:
133
135
  - lib
@@ -142,7 +144,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
142
144
  - !ruby/object:Gem::Version
143
145
  version: '0'
144
146
  requirements: []
145
- rubygems_version: 3.6.6
147
+ rubygems_version: 3.5.18
148
+ signing_key:
146
149
  specification_version: 4
147
150
  summary: Soft delete and trash management for Ruby on Rails applications
148
151
  test_files: []
data/recycle_bin.gemspec DELETED
@@ -1,47 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'lib/recycle_bin/version'
4
-
5
- Gem::Specification.new do |spec|
6
- spec.name = 'recycle_bin'
7
- spec.version = RecycleBin::VERSION
8
- spec.authors = ['Rishi Somani', 'Shobhit Jain', 'Raghav Agrawal']
9
- spec.email = ['somani.rishi81@gmail.com', 'shobhjain09@gmail.com', 'raghavagrawal019@gmail.com']
10
-
11
- spec.summary = 'Soft delete and trash management for Ruby on Rails applications'
12
- spec.description = 'RecycleBin provides soft delete functionality with a user-friendly trash/recycle bin interface for any Rails application. Easily restore deleted records with a simple web interface.'
13
- spec.homepage = 'https://github.com/R95-del/recycle_bin'
14
- spec.license = 'MIT'
15
- spec.required_ruby_version = '>= 2.7.0'
16
-
17
- # Specify which files should be added to the gem when it is released.
18
- spec.files = Dir.chdir(__dir__) do
19
- `git ls-files -z`.split("\x0").reject do |f|
20
- # Exclude the gemspec file itself and development files
21
- (File.expand_path(f) == __FILE__) ||
22
- f.start_with?(*%w[bin/ test/ spec/ features/ .git .github]) ||
23
- f.match?(/\A\./) || # Exclude dotfiles
24
- f.end_with?('.gem') || # Exclude any .gem files
25
- f.include?('Gemfile.lock') # Exclude Gemfile.lock
26
- end
27
- end
28
-
29
- spec.require_paths = ['lib']
30
-
31
- # Runtime dependencies - Use pessimistic version constraints
32
- spec.add_dependency 'rails', '>= 6.0', '< 9.0'
33
-
34
- # Development dependencies - FIXED to match Gemfile
35
- spec.add_development_dependency 'factory_bot_rails', '~> 6.2'
36
- spec.add_development_dependency 'rspec-rails', '>= 6.0' # Changed from '~> 6.0'
37
- spec.add_development_dependency 'sqlite3', '~> 2.0' # Changed from '~> 2.1'
38
-
39
- # Gem metadata with distinct URIs
40
- spec.metadata['rubygems_mfa_required'] = 'true'
41
- spec.metadata['homepage_uri'] = spec.homepage
42
- spec.metadata['source_code_uri'] = 'https://github.com/R95-del/recycle_bin'
43
- spec.metadata['changelog_uri'] = 'https://github.com/R95-del/recycle_bin/blob/main/CHANGELOG.md'
44
- spec.metadata['bug_tracker_uri'] = 'https://github.com/R95-del/recycle_bin/issues'
45
- spec.metadata['documentation_uri'] = 'https://github.com/R95-del/recycle_bin/blob/main/README.md'
46
- spec.metadata['wiki_uri'] = 'https://github.com/R95-del/recycle_bin/wiki'
47
- end