rails_mail 0.10.6 → 0.12.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8d490206541f350f1c96e83e22233dc0829d3ef4e1102c7d9ef0aba2c2af6fc6
4
- data.tar.gz: 84510c52a082d8d8abdec666c0634c55c092c4b10e7d9c25319aa9b8e2a26c00
3
+ metadata.gz: af2921494ffeba97ba5924b637e2629f63038c848c1e23bc884b5989e20ace82
4
+ data.tar.gz: f6db844c277f6cbbd5d21032b21b36d8d53582742f8e70221121840347033f08
5
5
  SHA512:
6
- metadata.gz: 7c2fa09fbe238b7fa0c52e997dd7055922b8a8738e7e52270a1882e844ed877f4be6e6b0fc799e45c6ee525c3f5d3091aefa30df91edad2378a2af4fc08a5e15
7
- data.tar.gz: 8f989621de7be287c283899ae8f73a4dfa1e088e57de32c1012c2173f812b15b585a8a8ecca8523d24650fcdc822ea8e64bc7f6b2f3096df18be8b09eda821b0
6
+ metadata.gz: d8705cb7c5616c3e7b1f147b763bd29369196e83bdc30a14513413aa158bf7c6e931377d25bab927c1a45b65477e6a65e5f7f1a2bfcc365ca1b92b0816cfdbea
7
+ data.tar.gz: a33272cdb0993a9fc264869c4f037f16a25ae1e00e0e7d5c7d5123b12113c462ae434b1e561b08caa8ab17720d6a22a0015bebf64cfb7e165d9b6a435dab9000
data/README.md CHANGED
@@ -12,6 +12,7 @@ RailsMail saves all outgoing emails to your database instead of actually sending
12
12
  * Implements delivery_method for ActionMailer to catch emails and store them in the database
13
13
  * Real-time updates using Turbo and ActionCable
14
14
  * Search functionality across email fields (subject, from, to, cc, bcc)
15
+ * Infinite scrolling with customizable per-page count
15
16
  * Clean, responsive UI for viewing email contents
16
17
  * Optional authentication support
17
18
  * Trimming emails older than a specified duration or a maximum number of emails
@@ -111,6 +112,9 @@ RailsMail.configure do |config|
111
112
 
112
113
  # Control whether trimming runs synchronously (:now) or asynchronously (:later)
113
114
  config.sync_via = :later
115
+
116
+ # Per-page count for infinite scroll
117
+ config.per_page = 20
114
118
  end
115
119
  ```
116
120
 
@@ -256,8 +260,6 @@ RailsMail uses Turbo, TurboStreams, and ActionCable to provide real-time updates
256
260
  - Implement introspection of application notifiers and allow manual delivery/inspection of emails
257
261
  - Need to introspect the arguments of the notifier and see if the arguments can be paired with active record models or to allow a mapping of argument type to sample data / fixtures.
258
262
  - Implement read/unread functionality
259
- - Implement individual email delete
260
- - Implement multi-part (text/html) email support
261
263
  - Allow clients to add additional acceptable HTML tags to render
262
264
 
263
265
  ## Contributing
@@ -2,20 +2,27 @@ module RailsMail
2
2
  class EmailsController < BaseController
3
3
  # GET /emails
4
4
  def index
5
- @emails = Email.all
5
+ @emails = Email.order(created_at: :desc)
6
6
  @emails = @emails.search(params[:q]) if params[:q].present?
7
- @emails = @emails.order(created_at: :desc)
8
- @email = params[:id] ? Email.find(params[:id]) : Email.last
7
+ paginated = paginate_with_next_page(@emails, page: params[:page].to_i)
8
+ @emails, @next_page = paginated.items, paginated.next_page
9
+ @email = params[:id] ? Email.find(params[:id]) : @emails.last
10
+ # we're not paginating, so it means we're either the initial index page
11
+ # load or we're searching. In which case run an "update" turbo stream
12
+ # to replace all the results.
13
+ @turbo_stream_action = paginating? ? "append" : "update"
9
14
 
10
15
  respond_to do |format|
11
16
  format.html
12
- format.turbo_stream if params.key?(:q)
17
+ format.turbo_stream if params[:q].present? || params[:page].present?
13
18
  end
14
19
  end
15
20
 
16
21
  # GET /emails/1
17
22
  def show
18
23
  @emails = Email.order(created_at: :desc)
24
+ paginated = paginate_with_next_page(@emails, page: params[:page].to_i)
25
+ @emails, @next_page = paginated.items, paginated.next_page
19
26
  @email = Email.find(params[:id])
20
27
  session[:current_email_id] = @email.id
21
28
 
@@ -40,5 +47,20 @@ module RailsMail
40
47
  format.turbo_stream
41
48
  end
42
49
  end
50
+
51
+ private
52
+
53
+ def paginating?
54
+ params.key?(:page) && params[:page].to_i >= 1
55
+ end
56
+
57
+ def paginate_with_next_page(relation, page: nil)
58
+ per_page = RailsMail.configuration.per_page || 20
59
+ current_page = (page || params[:page] || 0).to_i
60
+ total_count = relation.count
61
+ items = relation.offset(current_page * per_page).limit(per_page)
62
+ next_page = total_count > per_page * (current_page + 1) ? current_page + 1 : nil
63
+ Struct.new(:items, :next_page).new(items, next_page)
64
+ end
43
65
  end
44
66
  end
@@ -8,7 +8,7 @@ module RailsMail
8
8
  a.set_attribute("data-turbo", "false")
9
9
  end
10
10
  sanitize(doc.to_html,
11
- tags: ActionView::Base.sanitized_allowed_tags + [ "table", "tbody", "tr", "td" ],
11
+ tags: ActionView::Base.sanitized_allowed_tags + [ "table", "tbody", "tr", "td", "th", "thead", "tfoot" ],
12
12
  attributes: ActionView::Base.sanitized_allowed_attributes + [ "style", "target", "data-turbo" ])
13
13
  end
14
14
  end
@@ -24,7 +24,7 @@
24
24
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
25
25
  </svg>
26
26
  </label>
27
-
27
+
28
28
  <!-- Title (centered) -->
29
29
  <%= link_to root_path, class: "text-gray-900" do %>
30
30
  <%= render "layouts/rails_mail/title" %>
@@ -32,7 +32,7 @@
32
32
 
33
33
  <!-- Clear All button (or empty div for spacing when button is hidden) -->
34
34
  <% if instance_eval(&RailsMail.show_clear_all_button_callback) %>
35
- <%= button_to destroy_all_emails_path,
35
+ <%= button_to destroy_all_emails_path,
36
36
  class: "text-sm text-gray-600 hover:text-gray-900",
37
37
  form: { data: { turbo_confirm: "Are you sure you want to clear all emails?" } },
38
38
  method: :delete do %>
@@ -50,12 +50,12 @@
50
50
  </div>
51
51
 
52
52
  <div id="search-form" class="flex-none px-2 pb-2">
53
- <%= form_with url: rails_mail.emails_path, method: :get, data: { turbo_stream: true, turbo_frame: "emails_list",controller: 'auto-submit' } do |f| %>
54
- <%= f.search_field :q,
55
- value: params[:q],
56
- class: "w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-1 focus:ring-blue-500 focus:border-blue-500",
57
- placeholder: "Search emails...",
58
- data: { action: 'keyup->auto-submit#submit search->auto-submit#submit' } %>
53
+ <%= form_with url: rails_mail.emails_path, method: :get, data: { turbo_stream: true, turbo_frame: "emails_list", controller: 'auto-submit' } do |f| %>
54
+ <%= f.search_field :q,
55
+ value: params[:q],
56
+ class: "w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-1 focus:ring-blue-500 focus:border-blue-500",
57
+ placeholder: "Search emails...",
58
+ data: { action: 'keyup->auto-submit#submit search->auto-submit#submit' } %>
59
59
  <% end %>
60
60
  </div>
61
61
 
@@ -72,4 +72,4 @@
72
72
  </div>
73
73
  </div>
74
74
  </body>
75
- </html>
75
+ </html>
@@ -1,7 +1,16 @@
1
- <turbo-stream action="update" target="email-sidebar">
1
+ <turbo-stream action="<%= @turbo_stream_action %>" target="email-list-wrapper">
2
2
  <template>
3
3
  <% @emails&.each do |email| %>
4
4
  <%= render partial: "rails_mail/shared/email", locals: {email: email, email_path: email_path(email) }, formats: [:html] %>
5
5
  <% end %>
6
6
  </template>
7
7
  </turbo-stream>
8
+ <turbo-stream action="replace" target="email-pagination">
9
+ <template>
10
+ <% if @next_page %>
11
+ <% path_opts = { format: "turbo_stream", page: @next_page.next } %>
12
+ <% path_opts[:q] = params[:q] if params[:q].present? %>
13
+ <%= turbo_frame_tag "email-pagination", src: emails_path(path_opts), loading: "lazy" %>
14
+ <% end %>
15
+ </template>
16
+ </turbo-stream>
@@ -16,7 +16,7 @@
16
16
  <div class="min-w-0">
17
17
  <div class="text-sm font-medium text-gray-900 truncate"><%= email.subject %></div>
18
18
  <div class="text-xs text-gray-500">
19
- <span class="truncate"><%= email.to.join(', ') %></span>
19
+ <span class="truncate"><%= email.from %></span>
20
20
  <time
21
21
  data-controller="timeago"
22
22
  data-timeago-datetime-value="<%= email.created_at.iso8601 %>"
@@ -3,7 +3,14 @@
3
3
  <% end %>
4
4
 
5
5
  <div id="email-sidebar" data-controller="email-highlight">
6
- <% @emails&.each do |email| %>
7
- <%= render "rails_mail/shared/email", email: email, email_path: email_path(email) %>
6
+ <div id="email-list-wrapper">
7
+ <% @emails&.each do |email| %>
8
+ <%= render "rails_mail/shared/email", email: email, email_path: email_path(email) %>
9
+ <% end %>
10
+ </div>
11
+ <% if @next_page %>
12
+ <% path_opts = { format: "turbo_stream", page: @next_page } %>
13
+ <% path_opts[:q] = params[:q] if params[:q].present? %>
14
+ <%= turbo_frame_tag "email-pagination", src: emails_path(path_opts), loading: "lazy", style: "display: block; height: 50px;" %>
8
15
  <% end %>
9
- </div>
16
+ </div>
@@ -4,7 +4,7 @@ module RailsMail
4
4
  class Configuration
5
5
  attr_accessor :authentication_callback, :show_clear_all_button_callback,
6
6
  :trim_emails_older_than, :trim_emails_max_count,
7
- :enqueue_trim_job
7
+ :enqueue_trim_job, :per_page
8
8
 
9
9
  def initialize
10
10
  @authentication_callback = nil
@@ -12,6 +12,7 @@ module RailsMail
12
12
  @trim_emails_older_than = nil
13
13
  @trim_emails_max_count = nil
14
14
  @enqueue_trim_job = ->(email) { RailsMail::TrimEmailsJob.perform_later }
15
+ @per_page = nil
15
16
  register_default_renderers
16
17
  end
17
18
 
@@ -2,8 +2,7 @@ module RailsMail
2
2
  module Renderer
3
3
  class HtmlRenderer < Base
4
4
  def self.handles?(email)
5
- email.content_type&.include?("text/html") ||
6
- email.content_type&.include?("multipart/alternative")
5
+ email.html_part.present?
7
6
  end
8
7
 
9
8
  def self.partial_name
@@ -2,8 +2,7 @@ module RailsMail
2
2
  module Renderer
3
3
  class TextRenderer < Base
4
4
  def self.handles?(email)
5
- email.content_type&.include?("text/plain") ||
6
- email.content_type&.include?("multipart/alternative")
5
+ email.text_part.present?
7
6
  end
8
7
 
9
8
  def self.partial_name
@@ -1,3 +1,3 @@
1
1
  module RailsMail
2
- VERSION = "0.10.6"
2
+ VERSION = "0.12.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails_mail
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.6
4
+ version: 0.12.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter Philips
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-04-25 00:00:00.000000000 Z
11
+ date: 2025-11-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails