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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 87e5b68d4722dd1f28ae30a9926da8445184f2c3116b66f55c8f948e15e923f8
4
- data.tar.gz: 4654ef43284576a86f56c64c24d93bf3f6a15da709a81720af9fe38f331f5d6c
3
+ metadata.gz: c4776a0d821cdcfb6907270b5bdb1c6ffe742026e8e2aa2b3f2bea1bcd7b8859
4
+ data.tar.gz: 8f0fccb6be759bb46534fd69296e610ee7bc80e9b659805d7bbb75db68841ec3
5
5
  SHA512:
6
- metadata.gz: 1cfa9becf70f4e79fb3d5907dacefd722e87849b8f0cb3cbc75a6b7baa82680bdee3dc82b9d600bf4ddaee56ceaddbb278611a70b462bf8ff1604947f536e951
7
- data.tar.gz: b5e6106acb66c2e01447ef4a2b104d28da4206a712bf42a3076f5b981e3165d388e787b2307d70793d89ff550cfefdf73dceaea9e100b7ee50489d3284c8eda0
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 gives you chat routes like `/` (chat index), `/chats`, and `/chats/:id`.
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
- Define `current_chat_participant` in your host `ApplicationController`.
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
- Fallback behavior (only if you do not define `current_chat_participant`):
77
+ Resolution order:
65
78
 
66
- 1. `config.current_participant_resolver`
67
- 2. `current_user`
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
 
@@ -627,6 +627,13 @@ body {
627
627
  gap: 3px;
628
628
  }
629
629
 
630
+ .chat-signal-text {
631
+ max-width: 320px;
632
+ overflow: hidden;
633
+ text-overflow: ellipsis;
634
+ white-space: nowrap;
635
+ }
636
+
630
637
  .chat-dots i {
631
638
  width: 6px;
632
639
  height: 6px;
@@ -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
- permitted[:signal_type] = nil unless normalized_kind == "signal"
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!(chat: chat, participant: participant, kind: :signal, signal_type: signal_type)
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!(chat: chat, participant: participant, signal_type: signal_type)
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
- self.body = "" if signal?
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
- <span><%= chat_message.participant_display_name %> is <%= chat_message.signal_type %>...</span>
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
- <span class="chat-dots">
21
- <i></i><i></i><i></i>
22
- </span>
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 %>
@@ -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!(chat: chat, participant: participant, signal_type: signal_type)
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!(chat: chat, participant: participant, signal_type: signal_type)
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 with(chat:, participant:, signal_type: :typing, &block)
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
@@ -1,3 +1,3 @@
1
1
  module TurboChat
2
- VERSION = "0.1.4"
2
+ VERSION = "0.1.5"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: turbo_chat
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.1.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexander Haumer