tramway 3.0.3.3 → 3.0.4
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 +46 -3
- data/app/components/tramway/chat_component.html.haml +12 -2
- data/app/components/tramway/chat_component.rb +1 -0
- data/app/components/tramway/containers/main_component.html.haml +1 -1
- data/app/components/tramway/containers/main_component.rb +5 -1
- data/app/components/tramway/containers/narrow_component.html.haml +1 -1
- data/app/components/tramway/containers/narrow_component.rb +3 -1
- data/app/views/tramway/chats/_message.html.haml +1 -4
- data/app/views/tramway/chats/_messages.html.haml +2 -0
- data/lib/generators/tramway/install/install_generator.rb +1 -1
- data/lib/tramway/chats/broadcast.rb +37 -0
- data/lib/tramway/version.rb +1 -1
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8f1294b704f5b6bc2779d6eae4168a9c63508af6b485dfe267fa70a1b2ca786e
|
|
4
|
+
data.tar.gz: 662bf3c75f819a46229a55cce0804b11a70511ade1ecbc08e8aa50a09d246381
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 90eb4ab0b7d5e871f904d320a42469ea92d35a83ebad3c014b167fe7b5294e7c046c1c0ebc41f64a09693794995e82641d69b3cb9d59d3e5183f5108ace44745
|
|
7
|
+
data.tar.gz: 53bc0d610787669587ed26f4c6bbadce0c0e476ae34b8f4ea49128ad7e20265080d09abdf3726fea93aea1014a2a935b12077b6049c47fd46c199c044ad6872f
|
data/README.md
CHANGED
|
@@ -925,17 +925,17 @@ When set to `false`, the text field is disabled and the waiting placeholder is s
|
|
|
925
925
|
If you do not want to render the message form, pass `message_form: nil`. When the form is present, `send_message_path` is
|
|
926
926
|
required and the helper will generate the correct POST form.
|
|
927
927
|
|
|
928
|
-
To append
|
|
928
|
+
To append a message to an already-rendered `tramway_chat` stream, use `tramway_chat_append_message`.
|
|
929
929
|
The method is mixed into controllers and ActiveRecord models by Tramway and expects:
|
|
930
930
|
- `chat_id:` — the same value used in `tramway_chat chat_id:`
|
|
931
|
-
- `
|
|
931
|
+
- `type:` — only `:sent` or `:received` (raises `ArgumentError` otherwise)
|
|
932
932
|
- `text:` — message content
|
|
933
933
|
- `sent_at:` — message timestamp
|
|
934
934
|
|
|
935
935
|
```ruby
|
|
936
936
|
tramway_chat_append_message(
|
|
937
937
|
chat_id: 'support-chat',
|
|
938
|
-
|
|
938
|
+
type: :received,
|
|
939
939
|
text: 'We got your request',
|
|
940
940
|
sent_at: Time.current
|
|
941
941
|
)
|
|
@@ -943,6 +943,49 @@ tramway_chat_append_message(
|
|
|
943
943
|
|
|
944
944
|
It broadcasts with `target: 'messages'` and renders the `tramway/chats/message` partial so the message appears in the live chat.
|
|
945
945
|
|
|
946
|
+
To prepend a message to the same stream, use `tramway_chat_prepend_message`. It accepts the same arguments and validation rules,
|
|
947
|
+
but inserts the rendered `tramway/chats/message` partial at the beginning of the `messages` target instead of the end.
|
|
948
|
+
|
|
949
|
+
```ruby
|
|
950
|
+
tramway_chat_prepend_message(
|
|
951
|
+
chat_id: 'support-chat',
|
|
952
|
+
type: :received,
|
|
953
|
+
text: 'Earlier message from history',
|
|
954
|
+
sent_at: 5.minutes.ago
|
|
955
|
+
)
|
|
956
|
+
```
|
|
957
|
+
|
|
958
|
+
To append multiple messages at once, use `tramway_chat_append_messages`. The method expects:
|
|
959
|
+
- `chat_id:` — the same value used in `tramway_chat chat_id:`
|
|
960
|
+
- `messages:` — an array of hashes, where each hash includes `type:`, `text:`, and `sent_at:`
|
|
961
|
+
|
|
962
|
+
Each message `type:` must be `:sent` or `:received` or the helper raises `ArgumentError`. It broadcasts with `target:
|
|
963
|
+
'messages'` and renders the `tramway/chats/messages` partial so the full collection appears in the live chat.
|
|
964
|
+
|
|
965
|
+
```ruby
|
|
966
|
+
tramway_chat_append_messages(
|
|
967
|
+
chat_id: 'support-chat',
|
|
968
|
+
messages: [
|
|
969
|
+
{ type: :received, text: 'First update', sent_at: 2.minutes.ago },
|
|
970
|
+
{ type: :sent, text: 'Thanks, checking now', sent_at: 1.minute.ago }
|
|
971
|
+
]
|
|
972
|
+
)
|
|
973
|
+
```
|
|
974
|
+
|
|
975
|
+
To prepend multiple messages, use `tramway_chat_prepend_messages`. It accepts the same `chat_id:` and `messages:` arguments
|
|
976
|
+
as `tramway_chat_append_messages`, validates each `type:`, and prepends the rendered `tramway/chats/messages` partial to the
|
|
977
|
+
beginning of the `messages` target.
|
|
978
|
+
|
|
979
|
+
```ruby
|
|
980
|
+
tramway_chat_prepend_messages(
|
|
981
|
+
chat_id: 'support-chat',
|
|
982
|
+
messages: [
|
|
983
|
+
{ type: :received, text: 'Older history item', sent_at: 10.minutes.ago },
|
|
984
|
+
{ type: :sent, text: 'Reply from earlier', sent_at: 9.minutes.ago }
|
|
985
|
+
]
|
|
986
|
+
)
|
|
987
|
+
```
|
|
988
|
+
|
|
946
989
|
### Tramway Table Component
|
|
947
990
|
|
|
948
991
|
Tramway provides a responsive, tailwind-styled table with light and dark themes. Use the `tramway_table`, `tramway_row`, and
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
= helpers.turbo_stream_from chat_id, 'messages'
|
|
2
2
|
|
|
3
3
|
#chat.flex.flex-1.h-full.w-full.min-h-0.min-w-0.flex-col
|
|
4
|
-
#messages.flex.flex-col.flex-1.min-h-0.overflow-y-auto.overflow-x-hidden.p-2.md:p-6.space-y-2.md:space-y-4.md:rounded-xl.rounded-t-xl{ class: 'text-gray-100 bg-gray-800/60' }
|
|
4
|
+
#messages.flex.flex-col.flex-1.min-h-0.overflow-y-auto.overflow-x-hidden.p-2.md:p-6.space-y-2.md:space-y-4.md:rounded-xl.rounded-t-xl{ class: 'text-gray-100 bg-gray-800/60', data: { scroll_to_bottom_on_update: scroll_to_bottom_on_update } }
|
|
5
5
|
- messages.each do |message|
|
|
6
6
|
= component "tramway/chats/message", **message
|
|
7
7
|
- if disabled?
|
|
@@ -31,13 +31,23 @@
|
|
|
31
31
|
const messages = document.getElementById('messages');
|
|
32
32
|
if (!messages || messages.dataset.chatScrollInitialized === 'true') return;
|
|
33
33
|
|
|
34
|
+
const shouldScrollToBottomOnUpdate = () => {
|
|
35
|
+
return messages.dataset.scrollToBottomOnUpdate !== 'false' &&
|
|
36
|
+
messages.dataset.preserveScroll !== 'true';
|
|
37
|
+
};
|
|
38
|
+
|
|
34
39
|
const scrollToBottom = () => {
|
|
35
40
|
messages.scrollTop = messages.scrollHeight;
|
|
36
41
|
};
|
|
37
42
|
|
|
43
|
+
// Always scroll to bottom on initial page load.
|
|
38
44
|
scrollToBottom();
|
|
39
45
|
|
|
40
|
-
const observer = new MutationObserver(
|
|
46
|
+
const observer = new MutationObserver(() => {
|
|
47
|
+
if (!shouldScrollToBottomOnUpdate()) return;
|
|
48
|
+
scrollToBottom();
|
|
49
|
+
});
|
|
50
|
+
|
|
41
51
|
observer.observe(messages, { childList: true });
|
|
42
52
|
|
|
43
53
|
messages.dataset.chatScrollInitialized = 'true';
|
|
@@ -9,6 +9,7 @@ module Tramway
|
|
|
9
9
|
option :options, optional: true, default: -> { {} }
|
|
10
10
|
option :send_message_path
|
|
11
11
|
option :send_messages_enabled, optional: true, default: -> { true }
|
|
12
|
+
option :scroll_to_bottom_on_update, optional: true, default: -> { true }
|
|
12
13
|
|
|
13
14
|
def disabled?
|
|
14
15
|
options[:disabled]
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
%main.w-full.min-h-dvh{ class: container_classes }
|
|
1
|
+
%main.w-full.min-h-dvh{ class: container_classes, **options.except(:class) }
|
|
2
2
|
= content
|
|
@@ -4,9 +4,13 @@ module Tramway
|
|
|
4
4
|
module Containers
|
|
5
5
|
# Main container for tailwind-styled layout
|
|
6
6
|
class MainComponent < Tramway::BaseComponent
|
|
7
|
+
option :options, optional: true, default: proc { {} }
|
|
8
|
+
|
|
7
9
|
def container_classes
|
|
10
|
+
options_classes = options[:class] || ''
|
|
11
|
+
|
|
8
12
|
theme_classes(
|
|
9
|
-
classic:
|
|
13
|
+
classic: "bg-gray-900 text-gray-100 shadow-inner#{options_classes}"
|
|
10
14
|
)
|
|
11
15
|
end
|
|
12
16
|
end
|
|
@@ -8,9 +8,11 @@ module Tramway
|
|
|
8
8
|
option :options, optional: true, default: proc { {} }
|
|
9
9
|
|
|
10
10
|
def container_classes
|
|
11
|
+
options_classes = options[:class] || ''
|
|
12
|
+
|
|
11
13
|
theme_classes(
|
|
12
14
|
classic: 'container p-4 flex align-center justify-center w-full mx-auto bg-gray-100 text-gray-700 ' \
|
|
13
|
-
'shadow-inner rounded-xl bg-gray-900 text-gray-100'
|
|
15
|
+
'shadow-inner rounded-xl bg-gray-900 text-gray-100' + options_classes
|
|
14
16
|
)
|
|
15
17
|
end
|
|
16
18
|
end
|
|
@@ -91,7 +91,7 @@ module Tramway
|
|
|
91
91
|
end
|
|
92
92
|
|
|
93
93
|
def agents_template_url
|
|
94
|
-
'https://
|
|
94
|
+
'https://raw.githubusercontent.com/Purple-Magic/tramway-skill/refs/heads/main/skills/tramway-skill/agents/tramway.md'
|
|
95
95
|
end
|
|
96
96
|
|
|
97
97
|
def agents_template_body
|
|
@@ -14,6 +14,43 @@ module Tramway
|
|
|
14
14
|
partial: 'tramway/chats/message',
|
|
15
15
|
locals: { type:, text:, sent_at: }
|
|
16
16
|
end
|
|
17
|
+
|
|
18
|
+
def tramway_chat_prepend_message(chat_id:, type:, text:, sent_at:)
|
|
19
|
+
raise ArgumentError, 'message_type must be :sent or :received' unless MESSAGE_TYPES.include?(type.to_sym)
|
|
20
|
+
|
|
21
|
+
Turbo::StreamsChannel.broadcast_prepend_to [chat_id, 'messages'],
|
|
22
|
+
target: 'messages',
|
|
23
|
+
partial: 'tramway/chats/message',
|
|
24
|
+
locals: { type:, text:, sent_at: }
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def tramway_chat_append_messages(chat_id:, messages:)
|
|
28
|
+
messages.each do |message|
|
|
29
|
+
unless MESSAGE_TYPES.include?(message[:type].to_sym)
|
|
30
|
+
raise ArgumentError,
|
|
31
|
+
'Each message must have :id and :type keys'
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
Turbo::StreamsChannel.broadcast_append_to [chat_id, 'messages'],
|
|
36
|
+
target: 'messages',
|
|
37
|
+
partial: 'tramway/chats/messages',
|
|
38
|
+
locals: { messages: }
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def tramway_chat_prepend_messages(chat_id:, messages:)
|
|
42
|
+
messages.each do |message|
|
|
43
|
+
unless MESSAGE_TYPES.include?(message[:type].to_sym)
|
|
44
|
+
raise ArgumentError,
|
|
45
|
+
'Each message must have :id and :type keys'
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
Turbo::StreamsChannel.broadcast_prepend_to [chat_id, 'messages'],
|
|
50
|
+
target: 'messages',
|
|
51
|
+
partial: 'tramway/chats/messages',
|
|
52
|
+
locals: { messages: }
|
|
53
|
+
end
|
|
17
54
|
end
|
|
18
55
|
end
|
|
19
56
|
end
|
data/lib/tramway/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: tramway
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.0.
|
|
4
|
+
version: 3.0.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- kalashnikovisme
|
|
@@ -250,6 +250,7 @@ files:
|
|
|
250
250
|
- app/views/kaminari/_paginator.html.haml
|
|
251
251
|
- app/views/kaminari/_prev_page.html.haml
|
|
252
252
|
- app/views/tramway/chats/_message.html.haml
|
|
253
|
+
- app/views/tramway/chats/_messages.html.haml
|
|
253
254
|
- app/views/tramway/entities/_form.html.haml
|
|
254
255
|
- app/views/tramway/entities/_list.html.haml
|
|
255
256
|
- app/views/tramway/entities/edit.html.haml
|