notey 0.4.0 → 0.5.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 +4 -4
- data/README.md +36 -0
- data/app/controllers/notey/notifications_controller.rb +1 -2
- data/app/delivery_methods/notey/in_app.rb +1 -0
- data/app/models/notey/mark_read.rb +7 -2
- data/app/views/notey/_inbox.html.erb +5 -14
- data/app/views/notey/_live_stream.html.erb +1 -0
- data/app/views/notey/_notification.html.erb +14 -0
- data/app/views/notey/_unread_count.html.erb +1 -0
- data/app/views/notey/notifications/index.html.erb +7 -13
- data/lib/notey/live_inbox.rb +60 -0
- data/lib/notey/version.rb +1 -1
- data/lib/notey.rb +18 -1
- metadata +5 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2ace1eb52d62353acc618570451eade8a1736dd225b8ce899c68eec551c51355
|
|
4
|
+
data.tar.gz: 4752a3d42bab1851769adaa9bf11fdfb730ceb1ce80f0371a7835af6c837761e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2422c9b8fbe31ee6ac5907eb6f61a4f85ad46404c6c8fba15207923db5069e0886bb6ecf8c0fa52c65f2491cc506cda42f59f3964d7bf56b2be988d9b36b0332
|
|
7
|
+
data.tar.gz: fbccb4c605399312f12a45f0e15cf512f9542e794aa2fd582c45e6c731fb851d52a770ca7d194274ff1fde173ed62f475e1a13b767dc7bfdae0888357bc53ffd
|
data/README.md
CHANGED
|
@@ -207,6 +207,42 @@ from anywhere else does nothing.
|
|
|
207
207
|
and `values:`, and answer with an object responding to `ok?` and `message`. The
|
|
208
208
|
engine's own pages call the same two actions.
|
|
209
209
|
|
|
210
|
+
## Live updates
|
|
211
|
+
|
|
212
|
+
An open inbox can show a new notification the moment it is delivered, without a
|
|
213
|
+
reload. It is off until you turn it on, because it needs Turbo and a running
|
|
214
|
+
Action Cable server in production.
|
|
215
|
+
|
|
216
|
+
```ruby
|
|
217
|
+
# config/initializers/notey.rb
|
|
218
|
+
Notey.live_updates = true
|
|
219
|
+
Notey.mark_read_url = ->(notification) { Rails.application.routes.url_helpers.notifications_path }
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
`mark_read_url` is the url a pushed row's Mark read button posts to. A push is
|
|
223
|
+
rendered in a background job, which has no request to read that url from, so
|
|
224
|
+
you name it here. It is usually the same url you pass the inbox as `submit_url`.
|
|
225
|
+
|
|
226
|
+
With it on, the inbox and the engine's notifications page subscribe to one
|
|
227
|
+
stream per person per account, and:
|
|
228
|
+
|
|
229
|
+
- a notification delivered in-app appears at the top of that person's open
|
|
230
|
+
inbox in that account,
|
|
231
|
+
- marking one read shows it as read in the person's other open tabs,
|
|
232
|
+
- the unread count changes in every open tab of that person in that account.
|
|
233
|
+
|
|
234
|
+
Show the unread count anywhere on your page, and a push keeps it current:
|
|
235
|
+
|
|
236
|
+
```erb
|
|
237
|
+
<%= render "notey/unread_count", person: current_user, account: current_account.id %>
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
Notey does not install Turbo for you. Add `turbo-rails` to your Gemfile and load
|
|
241
|
+
its JavaScript. With live updates on and Turbo or `mark_read_url` missing, the
|
|
242
|
+
app refuses to boot and names what is missing. A push that fails, such as when
|
|
243
|
+
the cable server is down, is logged, and the read or delivery it came from still
|
|
244
|
+
goes through.
|
|
245
|
+
|
|
210
246
|
## Sending digests
|
|
211
247
|
|
|
212
248
|
A type set to daily or weekly sends nothing when it happens. Run the window on a
|
|
@@ -6,13 +6,12 @@ module Notey
|
|
|
6
6
|
|
|
7
7
|
def index
|
|
8
8
|
@notifications = inbox.includes(:event).order(created_at: :desc).limit(PER_PAGE)
|
|
9
|
-
@unread_count = inbox.unread.count
|
|
10
9
|
|
|
11
10
|
Noticed::Notification.where(id: @notifications.map(&:id)).unseen.mark_as_seen
|
|
12
11
|
end
|
|
13
12
|
|
|
14
13
|
def update
|
|
15
|
-
|
|
14
|
+
MarkRead.new(person: Current.member, account: Current.account_id, values: { read: params[:id] }).call
|
|
16
15
|
|
|
17
16
|
redirect_to notifications_path
|
|
18
17
|
end
|
|
@@ -9,15 +9,20 @@ module Notey
|
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
def call
|
|
12
|
-
notification
|
|
12
|
+
mark(notification) if notification
|
|
13
13
|
|
|
14
14
|
Kept.new
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
private
|
|
18
18
|
|
|
19
|
+
def mark(notification)
|
|
20
|
+
notification.mark_as_read!
|
|
21
|
+
LiveInbox.read(notification) if Notey.live_updates
|
|
22
|
+
end
|
|
23
|
+
|
|
19
24
|
def notification
|
|
20
|
-
Inbox.for(@person, account_id: @account_id).find_by(id: @values[:read])
|
|
25
|
+
@notification ||= Inbox.for(@person, account_id: @account_id).find_by(id: @values[:read])
|
|
21
26
|
end
|
|
22
27
|
end
|
|
23
28
|
end
|
|
@@ -1,16 +1,7 @@
|
|
|
1
1
|
<% notifications = Notey::Inbox.for(person, account_id: account).includes(:event).order(created_at: :desc) %>
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
<% unless notification.read? %>
|
|
9
|
-
<%= ui_form(action: submit_url, method: :patch) do %>
|
|
10
|
-
<%= hidden_field_tag "read", notification.id, id: nil %>
|
|
11
|
-
<%= ui_button(label: "Mark read") %>
|
|
12
|
-
<% end %>
|
|
13
|
-
<% end %>
|
|
14
|
-
</div>
|
|
15
|
-
<% end %>
|
|
16
|
-
<% end %>
|
|
3
|
+
<%= render "notey/live_stream", person: person, account: account %>
|
|
4
|
+
|
|
5
|
+
<div id="notey_inbox">
|
|
6
|
+
<%= render partial: "notey/notification", collection: notifications, locals: { submit_url: submit_url } %>
|
|
7
|
+
</div>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<%= turbo_stream_from(*Notey::LiveInbox.stream(person, account)) if Notey.live_updates && account.present? %>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<div id="notey_notification_<%= notification.id %>">
|
|
2
|
+
<%= ui_panel do %>
|
|
3
|
+
<div data-notification-id="<%= notification.id %>">
|
|
4
|
+
<%= notification.event.title %>
|
|
5
|
+
<%= ui_badge(label: notification.read? ? "Read" : "Unread") %>
|
|
6
|
+
<% unless notification.read? %>
|
|
7
|
+
<%= ui_form(action: submit_url, method: :patch) do %>
|
|
8
|
+
<%= hidden_field_tag "read", notification.id, id: nil %>
|
|
9
|
+
<%= ui_button(label: "Mark read") %>
|
|
10
|
+
<% end %>
|
|
11
|
+
<% end %>
|
|
12
|
+
</div>
|
|
13
|
+
<% end %>
|
|
14
|
+
</div>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<span id="notey_unread_count"><%= Notey::Inbox.for(person, account_id: account).unread.count %></span>
|
|
@@ -1,17 +1,11 @@
|
|
|
1
|
+
<%= render "notey/live_stream", person: Notey::Current.member, account: Notey::Current.account_id %>
|
|
2
|
+
|
|
1
3
|
<%= ui_page(max_width: :lg) do %>
|
|
2
|
-
<%= ui_section(title: "Notifications", subtitle: "
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
<%= notification.event.class.name %>
|
|
7
|
-
<%= ui_badge(label: notification.read? ? "Read" : "Unread") %>
|
|
8
|
-
<% unless notification.read? %>
|
|
9
|
-
<%= ui_form(action: notification_path(notification), method: :patch) do %>
|
|
10
|
-
<%= ui_button(label: "Mark read") %>
|
|
11
|
-
<% end %>
|
|
12
|
-
<% end %>
|
|
13
|
-
</div>
|
|
4
|
+
<%= ui_section(title: "Notifications", subtitle: safe_join([ render("notey/unread_count", person: Notey::Current.member, account: Notey::Current.account_id), " unread" ])) do %>
|
|
5
|
+
<div id="notey_inbox">
|
|
6
|
+
<% @notifications.each do |notification| %>
|
|
7
|
+
<%= render "notey/notification", notification: notification, submit_url: notification_path(notification) %>
|
|
14
8
|
<% end %>
|
|
15
|
-
|
|
9
|
+
</div>
|
|
16
10
|
<% end %>
|
|
17
11
|
<% end %>
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Notey
|
|
4
|
+
class LiveInbox
|
|
5
|
+
def self.stream(person, account_id)
|
|
6
|
+
[ person, :notey_inbox, account_id ]
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def self.deliver(notification)
|
|
10
|
+
return if notification.account_id.blank?
|
|
11
|
+
|
|
12
|
+
pushing(notification) do
|
|
13
|
+
Turbo::StreamsChannel.broadcast_prepend_to(
|
|
14
|
+
*stream_of(notification), target: "notey_inbox", html: row(notification)
|
|
15
|
+
)
|
|
16
|
+
push_unread_count(notification)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def self.read(notification)
|
|
21
|
+
pushing(notification) do
|
|
22
|
+
Turbo::StreamsChannel.broadcast_replace_to(
|
|
23
|
+
*stream_of(notification), target: "notey_notification_#{notification.id}", html: row(notification)
|
|
24
|
+
)
|
|
25
|
+
push_unread_count(notification)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def self.pushing(notification)
|
|
30
|
+
yield
|
|
31
|
+
rescue StandardError => error
|
|
32
|
+
Rails.logger.error("notey could not push notification #{notification.id}: #{error.message}")
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def self.push_unread_count(notification)
|
|
36
|
+
Turbo::StreamsChannel.broadcast_replace_to(
|
|
37
|
+
*stream_of(notification), target: "notey_unread_count", html: unread_count(notification)
|
|
38
|
+
)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def self.stream_of(notification)
|
|
42
|
+
stream(notification.recipient, notification.account_id)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def self.row(notification)
|
|
46
|
+
Notey::ApplicationController.render(
|
|
47
|
+
partial: "notey/notification",
|
|
48
|
+
locals: { notification: notification, submit_url: Notey.mark_read_url.call(notification) }
|
|
49
|
+
)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def self.unread_count(notification)
|
|
53
|
+
Notey::ApplicationController.render(
|
|
54
|
+
partial: "notey/unread_count",
|
|
55
|
+
locals: { person: notification.recipient, account: notification.account_id }
|
|
56
|
+
)
|
|
57
|
+
end
|
|
58
|
+
private_class_method :pushing, :push_unread_count, :stream_of, :row, :unread_count
|
|
59
|
+
end
|
|
60
|
+
end
|
data/lib/notey/version.rb
CHANGED
data/lib/notey.rb
CHANGED
|
@@ -3,6 +3,7 @@ require "notey/engine"
|
|
|
3
3
|
require "notey/channels"
|
|
4
4
|
require "notey/destinations"
|
|
5
5
|
require "notey/inbox"
|
|
6
|
+
require "notey/live_inbox"
|
|
6
7
|
require "notey/digest_run"
|
|
7
8
|
require "notey/records_attempt"
|
|
8
9
|
|
|
@@ -20,10 +21,12 @@ module Notey
|
|
|
20
21
|
class UnsendableChannel < StandardError; end
|
|
21
22
|
class UnsendableAttempt < StandardError; end
|
|
22
23
|
class MissingRetention < StandardError; end
|
|
24
|
+
class MissingMarkReadUrl < StandardError; end
|
|
25
|
+
class MissingTurbo < StandardError; end
|
|
23
26
|
|
|
24
27
|
class << self
|
|
25
28
|
attr_writer :notification_url, :mailer_sender
|
|
26
|
-
attr_accessor :attempt_retention
|
|
29
|
+
attr_accessor :attempt_retention, :live_updates, :mark_read_url
|
|
27
30
|
end
|
|
28
31
|
|
|
29
32
|
def self.mailer_sender
|
|
@@ -87,6 +90,7 @@ module Notey
|
|
|
87
90
|
def self.check!
|
|
88
91
|
registered_channels.each { |channel| check_channel!(channel) }
|
|
89
92
|
check_sender!
|
|
93
|
+
check_live_updates! if live_updates
|
|
90
94
|
end
|
|
91
95
|
|
|
92
96
|
def self.check_channel!(channel)
|
|
@@ -116,6 +120,17 @@ module Notey
|
|
|
116
120
|
raise MissingSender, "notey sends digests by email and no mailer_sender is set"
|
|
117
121
|
end
|
|
118
122
|
|
|
123
|
+
def self.check_live_updates!
|
|
124
|
+
raise MissingTurbo, "notey pushes live updates with turbo-rails, which is not loaded" unless turbo_loaded?
|
|
125
|
+
return if mark_read_url
|
|
126
|
+
|
|
127
|
+
raise MissingMarkReadUrl, "notey pushes rows with a Mark read button and no mark_read_url is set"
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def self.turbo_loaded?
|
|
131
|
+
defined?(::Turbo::StreamsChannel).present?
|
|
132
|
+
end
|
|
133
|
+
|
|
119
134
|
def self.sends(notification_type, on:, addressed: false, via: nil)
|
|
120
135
|
lambda do
|
|
121
136
|
decision = Channels.decision_for(recipient, notification_type, account_id: event.account_id)
|
|
@@ -130,6 +145,8 @@ module Notey
|
|
|
130
145
|
|
|
131
146
|
def self.reset!
|
|
132
147
|
@host_channels = nil
|
|
148
|
+
@live_updates = nil
|
|
149
|
+
@mark_read_url = nil
|
|
133
150
|
forget_notifiers
|
|
134
151
|
end
|
|
135
152
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: notey
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- tylercschneider
|
|
@@ -101,8 +101,11 @@ files:
|
|
|
101
101
|
- app/models/notey/save_preferences.rb
|
|
102
102
|
- app/views/notey/_destinations.html.erb
|
|
103
103
|
- app/views/notey/_inbox.html.erb
|
|
104
|
+
- app/views/notey/_live_stream.html.erb
|
|
104
105
|
- app/views/notey/_my_destinations.html.erb
|
|
106
|
+
- app/views/notey/_notification.html.erb
|
|
105
107
|
- app/views/notey/_preferences.html.erb
|
|
108
|
+
- app/views/notey/_unread_count.html.erb
|
|
106
109
|
- app/views/notey/destinations/show.html.erb
|
|
107
110
|
- app/views/notey/digest_mailer/digest.html.erb
|
|
108
111
|
- app/views/notey/notification_mailer/notification.html.erb
|
|
@@ -122,6 +125,7 @@ files:
|
|
|
122
125
|
- lib/notey/digest_run.rb
|
|
123
126
|
- lib/notey/engine.rb
|
|
124
127
|
- lib/notey/inbox.rb
|
|
128
|
+
- lib/notey/live_inbox.rb
|
|
125
129
|
- lib/notey/records_attempt.rb
|
|
126
130
|
- lib/notey/version.rb
|
|
127
131
|
- lib/tasks/notey_tasks.rake
|