turbo_chat 0.1.4 → 0.1.5
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 +9 -0
- data/README.md +22 -5
- data/app/assets/stylesheets/turbo_chat/application.css +7 -0
- data/app/controllers/turbo_chat/chat_messages_controller.rb +7 -2
- data/app/models/turbo_chat/chat_message/signals.rb +20 -7
- data/app/models/turbo_chat/chat_message.rb +18 -1
- data/app/views/turbo_chat/chat_messages/_signal.html.erb +5 -1
- data/app/views/turbo_chat/chat_messages/_signals.html.erb +7 -3
- data/lib/turbo_chat/signals.rb +20 -5
- data/lib/turbo_chat/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c4776a0d821cdcfb6907270b5bdb1c6ffe742026e8e2aa2b3f2bea1bcd7b8859
|
|
4
|
+
data.tar.gz: 8f0fccb6be759bb46534fd69296e610ee7bc80e9b659805d7bbb75db68841ec3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1ea9fd52941fdd7754f89c89ecf73cc47851abe5285fa8d2a05bb14da94746876d44cc414e8d835501f72b745586fbb2030b1ef5b0ceaaff34730534b774cc71
|
|
7
|
+
data.tar.gz: 9e056689af5f5c4a709f320c722f9cb6f324d52e4d3aba5ca22f50e6a999d3e0c435b087583140cc572b43be1a8eb185f4f383986beafbba24080334055e64de
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `turbo_chat` will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [0.1.5] - 2026-02-22
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- Custom signal text support via `signal_type: :custom` and `signal_text`.
|
|
9
|
+
- `TurboChat::Signals.custom!` helper for explicit custom status updates.
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
- Signal rendering now shows custom signal text in the live signals rail.
|
|
13
|
+
|
|
5
14
|
## [0.1.4] - 2026-02-22
|
|
6
15
|
|
|
7
16
|
### Added
|
data/README.md
CHANGED
|
@@ -35,7 +35,19 @@ Mount the engine:
|
|
|
35
35
|
mount TurboChat::Engine => "/", as: "turbo_chat"
|
|
36
36
|
```
|
|
37
37
|
|
|
38
|
-
This
|
|
38
|
+
This mounts TurboChat at your app root.
|
|
39
|
+
|
|
40
|
+
Because the engine defines `root` as `chats#index`, both of these resolve to chat index:
|
|
41
|
+
|
|
42
|
+
- `/`
|
|
43
|
+
- `/chats`
|
|
44
|
+
|
|
45
|
+
Route helpers:
|
|
46
|
+
|
|
47
|
+
- `turbo_chat.root_path` -> `/`
|
|
48
|
+
- `turbo_chat.chats_path` -> `/chats`
|
|
49
|
+
- `turbo_chat.chat_path(chat)` -> `/chats/:id`
|
|
50
|
+
- `turbo_chat_path` -> the mount point (`/`)
|
|
39
51
|
|
|
40
52
|
## Host App Requirements
|
|
41
53
|
|
|
@@ -49,7 +61,8 @@ end
|
|
|
49
61
|
|
|
50
62
|
### 2. Resolve the current participant
|
|
51
63
|
|
|
52
|
-
|
|
64
|
+
You can define `current_chat_participant` in your host `ApplicationController`.
|
|
65
|
+
If you already expose `current_user` and it returns a model using `acts_as_chat_participant`, TurboChat works without adding this method.
|
|
53
66
|
|
|
54
67
|
Recommended hook:
|
|
55
68
|
|
|
@@ -61,10 +74,12 @@ class ApplicationController < ActionController::Base
|
|
|
61
74
|
end
|
|
62
75
|
```
|
|
63
76
|
|
|
64
|
-
|
|
77
|
+
Resolution order:
|
|
65
78
|
|
|
66
|
-
1. `
|
|
67
|
-
2. `
|
|
79
|
+
1. Host `ApplicationController#current_chat_participant` (if defined)
|
|
80
|
+
2. `config.current_participant_resolver` (if configured)
|
|
81
|
+
3. `current_user` (if available)
|
|
82
|
+
4. Raise `NotImplementedError`
|
|
68
83
|
|
|
69
84
|
Optional resolver for non-`current_user` auth:
|
|
70
85
|
|
|
@@ -164,6 +179,8 @@ Raises:
|
|
|
164
179
|
|
|
165
180
|
```ruby
|
|
166
181
|
TurboChat::Signals.start!(chat: chat, participant: current_user, signal_type: :typing)
|
|
182
|
+
TurboChat::Signals.start!(chat: chat, participant: current_user, signal_type: :custom, signal_text: "Hello")
|
|
183
|
+
TurboChat::Signals.custom!(chat: chat, participant: current_user, signal_text: "Reviewing your request")
|
|
167
184
|
TurboChat::Signals.clear!(chat: chat, participant: current_user)
|
|
168
185
|
```
|
|
169
186
|
|
|
@@ -41,10 +41,15 @@ module TurboChat
|
|
|
41
41
|
end
|
|
42
42
|
|
|
43
43
|
def chat_message_params
|
|
44
|
-
permitted = params.require(:chat_message).permit(:body, :kind, :signal_type)
|
|
44
|
+
permitted = params.require(:chat_message).permit(:body, :kind, :signal_type, :signal_text)
|
|
45
45
|
normalized_kind = normalize_submittable_message_kind(permitted[:kind])
|
|
46
46
|
permitted[:kind] = normalized_kind
|
|
47
|
-
|
|
47
|
+
signal_text = permitted.delete(:signal_text)
|
|
48
|
+
if normalized_kind == "signal"
|
|
49
|
+
permitted[:body] = signal_text unless signal_text.nil?
|
|
50
|
+
else
|
|
51
|
+
permitted[:signal_type] = nil
|
|
52
|
+
end
|
|
48
53
|
permitted
|
|
49
54
|
end
|
|
50
55
|
|
|
@@ -4,13 +4,19 @@ module TurboChat
|
|
|
4
4
|
extend ActiveSupport::Concern
|
|
5
5
|
|
|
6
6
|
class_methods do
|
|
7
|
-
def start_signal!(chat:, participant:, signal_type: :typing)
|
|
8
|
-
create!(
|
|
7
|
+
def start_signal!(chat:, participant:, signal_type: :typing, signal_text: nil)
|
|
8
|
+
create!(
|
|
9
|
+
chat: chat,
|
|
10
|
+
participant: participant,
|
|
11
|
+
kind: :signal,
|
|
12
|
+
signal_type: signal_type,
|
|
13
|
+
body: signal_text
|
|
14
|
+
)
|
|
9
15
|
end
|
|
10
16
|
|
|
11
|
-
def replace_signal!(chat:, participant:, signal_type: :typing)
|
|
17
|
+
def replace_signal!(chat:, participant:, signal_type: :typing, signal_text: nil)
|
|
12
18
|
clear_signals!(chat: chat, participant: participant)
|
|
13
|
-
start_signal!(chat: chat, participant: participant, signal_type: signal_type)
|
|
19
|
+
start_signal!(chat: chat, participant: participant, signal_type: signal_type, signal_text: signal_text)
|
|
14
20
|
end
|
|
15
21
|
|
|
16
22
|
def clear_signals!(chat:, participant:)
|
|
@@ -19,8 +25,13 @@ module TurboChat
|
|
|
19
25
|
true
|
|
20
26
|
end
|
|
21
27
|
|
|
22
|
-
def with_signal(chat:, participant:, signal_type: :typing)
|
|
23
|
-
replace_signal!(
|
|
28
|
+
def with_signal(chat:, participant:, signal_type: :typing, signal_text: nil)
|
|
29
|
+
replace_signal!(
|
|
30
|
+
chat: chat,
|
|
31
|
+
participant: participant,
|
|
32
|
+
signal_type: signal_type,
|
|
33
|
+
signal_text: signal_text
|
|
34
|
+
)
|
|
24
35
|
yield
|
|
25
36
|
ensure
|
|
26
37
|
clear_signals!(chat: chat, participant: participant)
|
|
@@ -42,7 +53,9 @@ module TurboChat
|
|
|
42
53
|
|
|
43
54
|
def normalize_signal_fields
|
|
44
55
|
self.signal_type = nil if message? || system?
|
|
45
|
-
|
|
56
|
+
return unless signal?
|
|
57
|
+
|
|
58
|
+
self.body = signal_type_custom? ? body.to_s.strip : ""
|
|
46
59
|
end
|
|
47
60
|
|
|
48
61
|
def replace_participant_signals_on_submit
|
|
@@ -19,7 +19,7 @@ module TurboChat
|
|
|
19
19
|
belongs_to :participant, polymorphic: true
|
|
20
20
|
|
|
21
21
|
enum :kind, { message: 0, signal: 1, system: 2 }, default: :message
|
|
22
|
-
enum :signal_type, { typing: 0, thinking: 1, planning: 2 }, prefix: true
|
|
22
|
+
enum :signal_type, { typing: 0, thinking: 1, planning: 2, custom: 3 }, prefix: true
|
|
23
23
|
|
|
24
24
|
scope :ordered, -> { order(created_at: :asc, id: :asc) }
|
|
25
25
|
scope :messages_only, -> { where(kind: kinds[:message]) }
|
|
@@ -28,6 +28,7 @@ module TurboChat
|
|
|
28
28
|
validates :participant_type, :participant_id, presence: true
|
|
29
29
|
validates :body, presence: true, if: -> { message? || system? }
|
|
30
30
|
validates :signal_type, presence: true, if: :signal?
|
|
31
|
+
validates :signal_text, presence: true, if: :custom_signal?
|
|
31
32
|
validate :body_within_max_length, if: :message?
|
|
32
33
|
validate :mentions_allowed_for_participant, if: :message?
|
|
33
34
|
validate :apply_blocked_words_moderation, if: :message?
|
|
@@ -39,6 +40,16 @@ module TurboChat
|
|
|
39
40
|
after_update_commit :broadcast_update
|
|
40
41
|
after_destroy_commit :broadcast_destroy
|
|
41
42
|
|
|
43
|
+
def signal_text
|
|
44
|
+
return nil unless signal?
|
|
45
|
+
|
|
46
|
+
body.presence
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def signal_text=(value)
|
|
50
|
+
self.body = value
|
|
51
|
+
end
|
|
52
|
+
|
|
42
53
|
class << self
|
|
43
54
|
def create_membership_system_message!(chat:, actor:, event:, subject: nil)
|
|
44
55
|
return nil unless system_messages_enabled?
|
|
@@ -117,5 +128,11 @@ module TurboChat
|
|
|
117
128
|
participant.to_s
|
|
118
129
|
end
|
|
119
130
|
end
|
|
131
|
+
|
|
132
|
+
private
|
|
133
|
+
|
|
134
|
+
def custom_signal?
|
|
135
|
+
signal? && signal_type_custom?
|
|
136
|
+
end
|
|
120
137
|
end
|
|
121
138
|
end
|
|
@@ -1,3 +1,7 @@
|
|
|
1
1
|
<article id="<%= dom_id(chat_message) %>" class="chat-signal-entry">
|
|
2
|
-
|
|
2
|
+
<% if chat_message.signal_type_custom? && chat_message.signal_text.present? %>
|
|
3
|
+
<span><%= chat_message.participant_display_name %>: <%= chat_message.signal_text %></span>
|
|
4
|
+
<% else %>
|
|
5
|
+
<span><%= chat_message.participant_display_name %> is <%= chat_message.signal_type %>...</span>
|
|
6
|
+
<% end %>
|
|
3
7
|
</article>
|
|
@@ -17,8 +17,12 @@
|
|
|
17
17
|
data-chat-signal-participant-type="<%= signal_message.participant_type %>"
|
|
18
18
|
data-chat-signal-participant-id="<%= signal_message.participant_id %>">
|
|
19
19
|
<strong><%= signal_message.participant_display_name %></strong>
|
|
20
|
-
|
|
21
|
-
<
|
|
22
|
-
|
|
20
|
+
<% if signal_message.signal_type_custom? && signal_message.signal_text.present? %>
|
|
21
|
+
<span class="chat-signal-text"><%= signal_message.signal_text %></span>
|
|
22
|
+
<% else %>
|
|
23
|
+
<span class="chat-dots">
|
|
24
|
+
<i></i><i></i><i></i>
|
|
25
|
+
</span>
|
|
26
|
+
<% end %>
|
|
23
27
|
</div>
|
|
24
28
|
<% end %>
|
data/lib/turbo_chat/signals.rb
CHANGED
|
@@ -2,23 +2,38 @@ module TurboChat
|
|
|
2
2
|
module Signals
|
|
3
3
|
module_function
|
|
4
4
|
|
|
5
|
-
def start!(chat:, participant:, signal_type: :typing)
|
|
6
|
-
TurboChat::ChatMessage.replace_signal!(
|
|
5
|
+
def start!(chat:, participant:, signal_type: :typing, signal_text: nil)
|
|
6
|
+
TurboChat::ChatMessage.replace_signal!(
|
|
7
|
+
chat: chat,
|
|
8
|
+
participant: participant,
|
|
9
|
+
signal_type: signal_type,
|
|
10
|
+
signal_text: signal_text
|
|
11
|
+
)
|
|
7
12
|
end
|
|
8
13
|
|
|
9
|
-
def replace!(chat:, participant:, signal_type: :typing)
|
|
10
|
-
TurboChat::ChatMessage.replace_signal!(
|
|
14
|
+
def replace!(chat:, participant:, signal_type: :typing, signal_text: nil)
|
|
15
|
+
TurboChat::ChatMessage.replace_signal!(
|
|
16
|
+
chat: chat,
|
|
17
|
+
participant: participant,
|
|
18
|
+
signal_type: signal_type,
|
|
19
|
+
signal_text: signal_text
|
|
20
|
+
)
|
|
11
21
|
end
|
|
12
22
|
|
|
13
23
|
def clear!(chat:, participant:)
|
|
14
24
|
TurboChat::ChatMessage.clear_signals!(chat: chat, participant: participant)
|
|
15
25
|
end
|
|
16
26
|
|
|
17
|
-
def
|
|
27
|
+
def custom!(chat:, participant:, signal_text:)
|
|
28
|
+
start!(chat: chat, participant: participant, signal_type: :custom, signal_text: signal_text)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def with(chat:, participant:, signal_type: :typing, signal_text: nil, &block)
|
|
18
32
|
TurboChat::ChatMessage.with_signal(
|
|
19
33
|
chat: chat,
|
|
20
34
|
participant: participant,
|
|
21
35
|
signal_type: signal_type,
|
|
36
|
+
signal_text: signal_text,
|
|
22
37
|
&block
|
|
23
38
|
)
|
|
24
39
|
end
|
data/lib/turbo_chat/version.rb
CHANGED